Index: head/contrib/mdocml/man_macro.c =================================================================== --- head/contrib/mdocml/man_macro.c (revision 338825) +++ head/contrib/mdocml/man_macro.c (nonexistent) @@ -1,422 +0,0 @@ -/* $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, 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)) { - 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; -} Property changes on: head/contrib/mdocml/man_macro.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/dbm_map.c =================================================================== --- head/contrib/mdocml/dbm_map.c (revision 338825) +++ head/contrib/mdocml/dbm_map.c (nonexistent) @@ -1,194 +0,0 @@ -/* $Id: dbm_map.c,v 1.8 2017/02/17 14:43:54 schwarze Exp $ */ -/* - * Copyright (c) 2016 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. - * - * Low-level routines for the map-based version - * of the mandoc database, for read-only access. - * The interface is defined in "dbm_map.h". - */ -#include "config.h" - -#include -#include -#include - -#if HAVE_ENDIAN -#include -#elif HAVE_SYS_ENDIAN -#include -#elif HAVE_NTOHL -#include -#endif -#if HAVE_ERR -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "mansearch.h" -#include "dbm_map.h" -#include "dbm.h" - -static struct stat st; -static char *dbm_base; -static int ifd; -static int32_t max_offset; - -/* - * Open a disk-based database for read-only access. - * Validate the file format as far as it is not mandoc-specific. - * Return 0 on success. Return -1 and set errno on failure. - */ -int -dbm_map(const char *fname) -{ - int save_errno; - const int32_t *magic; - - if ((ifd = open(fname, O_RDONLY)) == -1) - return -1; - if (fstat(ifd, &st) == -1) - goto fail; - if (st.st_size < 5) { - warnx("dbm_map(%s): File too short", fname); - errno = EFTYPE; - goto fail; - } - if (st.st_size > INT32_MAX) { - errno = EFBIG; - goto fail; - } - if ((dbm_base = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, - ifd, 0)) == MAP_FAILED) - goto fail; - magic = dbm_getint(0); - if (be32toh(*magic) != MANDOCDB_MAGIC) { - if (strncmp(dbm_base, "SQLite format 3", 15)) - warnx("dbm_map(%s): " - "Bad initial magic %x (expected %x)", - fname, be32toh(*magic), MANDOCDB_MAGIC); - else - warnx("dbm_map(%s): " - "Obsolete format based on SQLite 3", - fname); - errno = EFTYPE; - goto fail; - } - magic = dbm_getint(1); - if (be32toh(*magic) != MANDOCDB_VERSION) { - warnx("dbm_map(%s): Bad version number %d (expected %d)", - fname, be32toh(*magic), MANDOCDB_VERSION); - errno = EFTYPE; - goto fail; - } - max_offset = be32toh(*dbm_getint(3)) + sizeof(int32_t); - if (st.st_size != max_offset) { - warnx("dbm_map(%s): Inconsistent file size %lld (expected %d)", - fname, (long long)st.st_size, max_offset); - errno = EFTYPE; - goto fail; - } - if ((magic = dbm_get(*dbm_getint(3))) == NULL) { - errno = EFTYPE; - goto fail; - } - if (be32toh(*magic) != MANDOCDB_MAGIC) { - warnx("dbm_map(%s): Bad final magic %x (expected %x)", - fname, be32toh(*magic), MANDOCDB_MAGIC); - errno = EFTYPE; - goto fail; - } - return 0; - -fail: - save_errno = errno; - close(ifd); - errno = save_errno; - return -1; -} - -void -dbm_unmap(void) -{ - if (munmap(dbm_base, st.st_size) == -1) - warn("dbm_unmap: munmap"); - if (close(ifd) == -1) - warn("dbm_unmap: close"); - dbm_base = (char *)-1; -} - -/* - * Take a raw integer as it was read from the database. - * Interpret it as an offset into the database file - * and return a pointer to that place in the file. - */ -void * -dbm_get(int32_t offset) -{ - offset = be32toh(offset); - if (offset < 0) { - warnx("dbm_get: Database corrupt: offset %d", offset); - return NULL; - } - if (offset >= max_offset) { - warnx("dbm_get: Database corrupt: offset %d > %d", - offset, max_offset); - return NULL; - } - return dbm_base + offset; -} - -/* - * Assume the database starts with some integers. - * Assume they are numbered starting from 0, increasing. - * Get a pointer to one with the number "offset". - */ -int32_t * -dbm_getint(int32_t offset) -{ - return (int32_t *)dbm_base + offset; -} - -/* - * The reverse of dbm_get(). - * Take pointer into the database file - * and convert it to the raw integer - * that would be used to refer to that place in the file. - */ -int32_t -dbm_addr(const void *p) -{ - return htobe32((const char *)p - dbm_base); -} - -int -dbm_match(const struct dbm_match *match, const char *str) -{ - switch (match->type) { - case DBM_EXACT: - return strcmp(str, match->str) == 0; - case DBM_SUB: - return strcasestr(str, match->str) != NULL; - case DBM_REGEX: - return regexec(match->re, str, 0, NULL, 0) == 0; - default: - abort(); - } -} Property changes on: head/contrib/mdocml/dbm_map.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mdoc_argv.c =================================================================== --- head/contrib/mdocml/mdoc_argv.c (revision 338825) +++ head/contrib/mdocml/mdoc_argv.c (nonexistent) @@ -1,678 +0,0 @@ -/* $Id: mdoc_argv.c,v 1.115 2017/05/30 16:22:03 schwarze Exp $ */ -/* - * Copyright (c) 2008, 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 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_aux.h" -#include "mandoc.h" -#include "roff.h" -#include "mdoc.h" -#include "libmandoc.h" -#include "roff_int.h" -#include "libmdoc.h" - -#define MULTI_STEP 5 /* pre-allocate argument values */ -#define DELIMSZ 6 /* max possible size of a delimiter */ - -enum argsflag { - ARGSFL_NONE = 0, - ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */ - ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */ -}; - -enum argvflag { - ARGV_NONE, /* no args to flag (e.g., -split) */ - ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */ - ARGV_MULTI /* multiple args (e.g., -column xxx yyy) */ -}; - -struct mdocarg { - enum argsflag flags; - const enum mdocargt *argvs; -}; - -static void argn_free(struct mdoc_arg *, int); -static enum margserr args(struct roff_man *, int, int *, - char *, enum argsflag, char **); -static int args_checkpunct(const char *, int); -static void argv_multi(struct roff_man *, int, - struct mdoc_argv *, int *, char *); -static void argv_single(struct roff_man *, int, - struct mdoc_argv *, int *, char *); - -static const enum argvflag argvflags[MDOC_ARG_MAX] = { - ARGV_NONE, /* MDOC_Split */ - ARGV_NONE, /* MDOC_Nosplit */ - ARGV_NONE, /* MDOC_Ragged */ - ARGV_NONE, /* MDOC_Unfilled */ - ARGV_NONE, /* MDOC_Literal */ - ARGV_SINGLE, /* MDOC_File */ - ARGV_SINGLE, /* MDOC_Offset */ - ARGV_NONE, /* MDOC_Bullet */ - ARGV_NONE, /* MDOC_Dash */ - ARGV_NONE, /* MDOC_Hyphen */ - ARGV_NONE, /* MDOC_Item */ - ARGV_NONE, /* MDOC_Enum */ - ARGV_NONE, /* MDOC_Tag */ - ARGV_NONE, /* MDOC_Diag */ - ARGV_NONE, /* MDOC_Hang */ - ARGV_NONE, /* MDOC_Ohang */ - ARGV_NONE, /* MDOC_Inset */ - ARGV_MULTI, /* MDOC_Column */ - ARGV_SINGLE, /* MDOC_Width */ - ARGV_NONE, /* MDOC_Compact */ - ARGV_NONE, /* MDOC_Std */ - ARGV_NONE, /* MDOC_Filled */ - ARGV_NONE, /* MDOC_Words */ - ARGV_NONE, /* MDOC_Emphasis */ - ARGV_NONE, /* MDOC_Symbolic */ - ARGV_NONE /* MDOC_Symbolic */ -}; - -static const enum mdocargt args_Ex[] = { - MDOC_Std, - MDOC_ARG_MAX -}; - -static const enum mdocargt args_An[] = { - MDOC_Split, - MDOC_Nosplit, - MDOC_ARG_MAX -}; - -static const enum mdocargt args_Bd[] = { - MDOC_Ragged, - MDOC_Unfilled, - MDOC_Filled, - MDOC_Literal, - MDOC_File, - MDOC_Offset, - MDOC_Compact, - MDOC_Centred, - MDOC_ARG_MAX -}; - -static const enum mdocargt args_Bf[] = { - MDOC_Emphasis, - MDOC_Literal, - MDOC_Symbolic, - MDOC_ARG_MAX -}; - -static const enum mdocargt args_Bk[] = { - MDOC_Words, - MDOC_ARG_MAX -}; - -static const enum mdocargt args_Bl[] = { - MDOC_Bullet, - MDOC_Dash, - MDOC_Hyphen, - MDOC_Item, - MDOC_Enum, - MDOC_Tag, - MDOC_Diag, - MDOC_Hang, - MDOC_Ohang, - MDOC_Inset, - MDOC_Column, - MDOC_Width, - MDOC_Offset, - MDOC_Compact, - MDOC_Nested, - MDOC_ARG_MAX -}; - -static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = { - { ARGSFL_NONE, NULL }, /* Dd */ - { ARGSFL_NONE, NULL }, /* Dt */ - { ARGSFL_NONE, NULL }, /* Os */ - { ARGSFL_NONE, NULL }, /* Sh */ - { ARGSFL_NONE, NULL }, /* Ss */ - { ARGSFL_NONE, NULL }, /* Pp */ - { ARGSFL_DELIM, NULL }, /* D1 */ - { ARGSFL_DELIM, NULL }, /* Dl */ - { ARGSFL_NONE, args_Bd }, /* Bd */ - { ARGSFL_NONE, NULL }, /* Ed */ - { ARGSFL_NONE, args_Bl }, /* Bl */ - { ARGSFL_NONE, NULL }, /* El */ - { ARGSFL_NONE, NULL }, /* It */ - { ARGSFL_DELIM, NULL }, /* Ad */ - { ARGSFL_DELIM, args_An }, /* An */ - { ARGSFL_DELIM, NULL }, /* Ap */ - { ARGSFL_DELIM, NULL }, /* Ar */ - { ARGSFL_DELIM, NULL }, /* Cd */ - { ARGSFL_DELIM, NULL }, /* Cm */ - { ARGSFL_DELIM, NULL }, /* Dv */ - { ARGSFL_DELIM, NULL }, /* Er */ - { ARGSFL_DELIM, NULL }, /* Ev */ - { ARGSFL_NONE, args_Ex }, /* Ex */ - { ARGSFL_DELIM, NULL }, /* Fa */ - { ARGSFL_NONE, NULL }, /* Fd */ - { ARGSFL_DELIM, NULL }, /* Fl */ - { ARGSFL_DELIM, NULL }, /* Fn */ - { ARGSFL_DELIM, NULL }, /* Ft */ - { ARGSFL_DELIM, NULL }, /* Ic */ - { ARGSFL_DELIM, NULL }, /* In */ - { ARGSFL_DELIM, NULL }, /* Li */ - { ARGSFL_NONE, NULL }, /* Nd */ - { ARGSFL_DELIM, NULL }, /* Nm */ - { ARGSFL_DELIM, NULL }, /* Op */ - { ARGSFL_DELIM, NULL }, /* Ot */ - { ARGSFL_DELIM, NULL }, /* Pa */ - { ARGSFL_NONE, args_Ex }, /* Rv */ - { ARGSFL_DELIM, NULL }, /* St */ - { ARGSFL_DELIM, NULL }, /* Va */ - { ARGSFL_DELIM, NULL }, /* Vt */ - { ARGSFL_DELIM, NULL }, /* Xr */ - { ARGSFL_NONE, NULL }, /* %A */ - { ARGSFL_NONE, NULL }, /* %B */ - { ARGSFL_NONE, NULL }, /* %D */ - { ARGSFL_NONE, NULL }, /* %I */ - { ARGSFL_NONE, NULL }, /* %J */ - { ARGSFL_NONE, NULL }, /* %N */ - { ARGSFL_NONE, NULL }, /* %O */ - { ARGSFL_NONE, NULL }, /* %P */ - { ARGSFL_NONE, NULL }, /* %R */ - { ARGSFL_NONE, NULL }, /* %T */ - { ARGSFL_NONE, NULL }, /* %V */ - { ARGSFL_DELIM, NULL }, /* Ac */ - { ARGSFL_NONE, NULL }, /* Ao */ - { ARGSFL_DELIM, NULL }, /* Aq */ - { ARGSFL_DELIM, NULL }, /* At */ - { ARGSFL_DELIM, NULL }, /* Bc */ - { ARGSFL_NONE, args_Bf }, /* Bf */ - { ARGSFL_NONE, NULL }, /* Bo */ - { ARGSFL_DELIM, NULL }, /* Bq */ - { ARGSFL_DELIM, NULL }, /* Bsx */ - { ARGSFL_DELIM, NULL }, /* Bx */ - { ARGSFL_NONE, NULL }, /* Db */ - { ARGSFL_DELIM, NULL }, /* Dc */ - { ARGSFL_NONE, NULL }, /* Do */ - { ARGSFL_DELIM, NULL }, /* Dq */ - { ARGSFL_DELIM, NULL }, /* Ec */ - { ARGSFL_NONE, NULL }, /* Ef */ - { ARGSFL_DELIM, NULL }, /* Em */ - { ARGSFL_NONE, NULL }, /* Eo */ - { ARGSFL_DELIM, NULL }, /* Fx */ - { ARGSFL_DELIM, NULL }, /* Ms */ - { ARGSFL_DELIM, NULL }, /* No */ - { ARGSFL_DELIM, NULL }, /* Ns */ - { ARGSFL_DELIM, NULL }, /* Nx */ - { ARGSFL_DELIM, NULL }, /* Ox */ - { ARGSFL_DELIM, NULL }, /* Pc */ - { ARGSFL_DELIM, NULL }, /* Pf */ - { ARGSFL_NONE, NULL }, /* Po */ - { ARGSFL_DELIM, NULL }, /* Pq */ - { ARGSFL_DELIM, NULL }, /* Qc */ - { ARGSFL_DELIM, NULL }, /* Ql */ - { ARGSFL_NONE, NULL }, /* Qo */ - { ARGSFL_DELIM, NULL }, /* Qq */ - { ARGSFL_NONE, NULL }, /* Re */ - { ARGSFL_NONE, NULL }, /* Rs */ - { ARGSFL_DELIM, NULL }, /* Sc */ - { ARGSFL_NONE, NULL }, /* So */ - { ARGSFL_DELIM, NULL }, /* Sq */ - { ARGSFL_NONE, NULL }, /* Sm */ - { ARGSFL_DELIM, NULL }, /* Sx */ - { ARGSFL_DELIM, NULL }, /* Sy */ - { ARGSFL_DELIM, NULL }, /* Tn */ - { ARGSFL_DELIM, NULL }, /* Ux */ - { ARGSFL_DELIM, NULL }, /* Xc */ - { ARGSFL_NONE, NULL }, /* Xo */ - { ARGSFL_NONE, NULL }, /* Fo */ - { ARGSFL_DELIM, NULL }, /* Fc */ - { ARGSFL_NONE, NULL }, /* Oo */ - { ARGSFL_DELIM, NULL }, /* Oc */ - { ARGSFL_NONE, args_Bk }, /* Bk */ - { ARGSFL_NONE, NULL }, /* Ek */ - { ARGSFL_NONE, NULL }, /* Bt */ - { ARGSFL_NONE, NULL }, /* Hf */ - { ARGSFL_DELIM, NULL }, /* Fr */ - { ARGSFL_NONE, NULL }, /* Ud */ - { ARGSFL_DELIM, NULL }, /* Lb */ - { ARGSFL_NONE, NULL }, /* Lp */ - { ARGSFL_DELIM, NULL }, /* Lk */ - { ARGSFL_DELIM, NULL }, /* Mt */ - { ARGSFL_DELIM, NULL }, /* Brq */ - { ARGSFL_NONE, NULL }, /* Bro */ - { ARGSFL_DELIM, NULL }, /* Brc */ - { ARGSFL_NONE, NULL }, /* %C */ - { ARGSFL_NONE, NULL }, /* Es */ - { ARGSFL_DELIM, NULL }, /* En */ - { ARGSFL_DELIM, NULL }, /* Dx */ - { ARGSFL_NONE, NULL }, /* %Q */ - { ARGSFL_NONE, NULL }, /* %U */ - { ARGSFL_NONE, NULL }, /* Ta */ -}; -static const struct mdocarg *const mdocargs = __mdocargs - MDOC_Dd; - - -/* - * Parse flags and their arguments from the input line. - * These come in the form -flag [argument ...]. - * Some flags take no argument, some one, some multiple. - */ -void -mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok, - struct mdoc_arg **reta, int *pos, char *buf) -{ - struct mdoc_argv tmpv; - struct mdoc_argv **retv; - const enum mdocargt *argtable; - char *argname; - int ipos, retc; - char savechar; - - *reta = NULL; - - /* Which flags does this macro support? */ - - assert(tok >= MDOC_Dd && tok < MDOC_MAX); - argtable = mdocargs[tok].argvs; - if (argtable == NULL) - return; - - /* Loop over the flags on the input line. */ - - ipos = *pos; - while (buf[ipos] == '-') { - - /* Seek to the first unescaped space. */ - - for (argname = buf + ++ipos; buf[ipos] != '\0'; ipos++) - if (buf[ipos] == ' ' && buf[ipos - 1] != '\\') - break; - - /* - * We want to nil-terminate the word to look it up. - * But we may not have a flag, in which case we need - * to restore the line as-is. So keep around the - * stray byte, which we'll reset upon exiting. - */ - - if ((savechar = buf[ipos]) != '\0') - buf[ipos++] = '\0'; - - /* - * Now look up the word as a flag. Use temporary - * storage that we'll copy into the node's flags. - */ - - while ((tmpv.arg = *argtable++) != MDOC_ARG_MAX) - if ( ! strcmp(argname, mdoc_argnames[tmpv.arg])) - break; - - /* If it isn't a flag, restore the saved byte. */ - - if (tmpv.arg == MDOC_ARG_MAX) { - if (savechar != '\0') - buf[ipos - 1] = savechar; - break; - } - - /* Read to the next word (the first argument). */ - - while (buf[ipos] == ' ') - ipos++; - - /* Parse the arguments of the flag. */ - - tmpv.line = line; - tmpv.pos = *pos; - tmpv.sz = 0; - tmpv.value = NULL; - - switch (argvflags[tmpv.arg]) { - case ARGV_SINGLE: - argv_single(mdoc, line, &tmpv, &ipos, buf); - break; - case ARGV_MULTI: - argv_multi(mdoc, line, &tmpv, &ipos, buf); - break; - case ARGV_NONE: - break; - } - - /* Append to the return values. */ - - if (*reta == NULL) - *reta = mandoc_calloc(1, sizeof(**reta)); - - retc = ++(*reta)->argc; - retv = &(*reta)->argv; - *retv = mandoc_reallocarray(*retv, retc, sizeof(**retv)); - memcpy(*retv + retc - 1, &tmpv, sizeof(**retv)); - - /* Prepare for parsing the next flag. */ - - *pos = ipos; - argtable = mdocargs[tok].argvs; - } -} - -void -mdoc_argv_free(struct mdoc_arg *p) -{ - int i; - - if (NULL == p) - return; - - if (p->refcnt) { - --(p->refcnt); - if (p->refcnt) - return; - } - assert(p->argc); - - for (i = (int)p->argc - 1; i >= 0; i--) - argn_free(p, i); - - free(p->argv); - free(p); -} - -static void -argn_free(struct mdoc_arg *p, int iarg) -{ - struct mdoc_argv *arg; - int j; - - arg = &p->argv[iarg]; - - if (arg->sz && arg->value) { - for (j = (int)arg->sz - 1; j >= 0; j--) - free(arg->value[j]); - free(arg->value); - } - - for (--p->argc; iarg < (int)p->argc; iarg++) - p->argv[iarg] = p->argv[iarg+1]; -} - -enum margserr -mdoc_args(struct roff_man *mdoc, int line, int *pos, - char *buf, enum roff_tok tok, char **v) -{ - struct roff_node *n; - char *v_local; - enum argsflag fl; - - if (v == NULL) - v = &v_local; - fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok].flags; - - /* - * We know that we're in an `It', so it's reasonable to expect - * us to be sitting in a `Bl'. Someday this may not be the case - * (if we allow random `It's sitting out there), so provide a - * safe fall-back into the default behaviour. - */ - - if (tok == MDOC_It) { - for (n = mdoc->last; n != NULL; n = n->parent) { - if (n->tok != MDOC_Bl) - continue; - if (n->norm->Bl.type == LIST_column) - fl = ARGSFL_TABSEP; - break; - } - } - - return args(mdoc, line, pos, buf, fl, v); -} - -static enum margserr -args(struct roff_man *mdoc, int line, int *pos, - char *buf, enum argsflag fl, char **v) -{ - char *p; - int pairs; - - if (buf[*pos] == '\0') { - if (mdoc->flags & MDOC_PHRASELIT && - ! (mdoc->flags & MDOC_PHRASE)) { - mandoc_msg(MANDOCERR_ARG_QUOTE, - mdoc->parse, line, *pos, NULL); - mdoc->flags &= ~MDOC_PHRASELIT; - } - return ARGS_EOLN; - } - - *v = buf + *pos; - - if (fl == ARGSFL_DELIM && args_checkpunct(buf, *pos)) - return ARGS_PUNCT; - - /* - * Tabs in `It' lines in `Bl -column' can't be escaped. - * Phrases are reparsed for `Ta' and other macros later. - */ - - if (fl == ARGSFL_TABSEP) { - if ((p = strchr(*v, '\t')) != NULL) { - - /* - * Words right before and right after - * tab characters are not parsed, - * unless there is a blank in between. - */ - - if (p > buf && p[-1] != ' ') - mdoc->flags |= MDOC_PHRASEQL; - if (p[1] != ' ') - mdoc->flags |= MDOC_PHRASEQN; - - /* - * One or more blanks after a tab cause - * one leading blank in the next column. - * So skip all but one of them. - */ - - *pos += (int)(p - *v) + 1; - while (buf[*pos] == ' ' && buf[*pos + 1] == ' ') - (*pos)++; - - /* - * A tab at the end of an input line - * switches to the next column. - */ - - if (buf[*pos] == '\0' || buf[*pos + 1] == '\0') - mdoc->flags |= MDOC_PHRASEQN; - } else { - p = strchr(*v, '\0'); - if (p[-1] == ' ') - mandoc_msg(MANDOCERR_SPACE_EOL, - mdoc->parse, line, *pos, NULL); - *pos += (int)(p - *v); - } - - /* Skip any trailing blank characters. */ - while (p > *v && p[-1] == ' ' && - (p - 1 == *v || p[-2] != '\\')) - p--; - *p = '\0'; - - return ARGS_PHRASE; - } - - /* - * Process a quoted literal. A quote begins with a double-quote - * and ends with a double-quote NOT preceded by a double-quote. - * NUL-terminate the literal in place. - * Collapse pairs of quotes inside quoted literals. - * Whitespace is NOT involved in literal termination. - */ - - if (mdoc->flags & MDOC_PHRASELIT || buf[*pos] == '\"') { - if ( ! (mdoc->flags & MDOC_PHRASELIT)) - *v = &buf[++(*pos)]; - - if (mdoc->flags & MDOC_PHRASE) - mdoc->flags |= MDOC_PHRASELIT; - - pairs = 0; - for ( ; buf[*pos]; (*pos)++) { - /* Move following text left after quoted quotes. */ - if (pairs) - buf[*pos - pairs] = buf[*pos]; - if ('\"' != buf[*pos]) - continue; - /* Unquoted quotes end quoted args. */ - if ('\"' != buf[*pos + 1]) - break; - /* Quoted quotes collapse. */ - pairs++; - (*pos)++; - } - if (pairs) - buf[*pos - pairs] = '\0'; - - if (buf[*pos] == '\0') { - if ( ! (mdoc->flags & MDOC_PHRASE)) - mandoc_msg(MANDOCERR_ARG_QUOTE, - mdoc->parse, line, *pos, NULL); - return ARGS_WORD; - } - - mdoc->flags &= ~MDOC_PHRASELIT; - buf[(*pos)++] = '\0'; - - if ('\0' == buf[*pos]) - return ARGS_WORD; - - while (' ' == buf[*pos]) - (*pos)++; - - if ('\0' == buf[*pos]) - mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, - line, *pos, NULL); - - return ARGS_WORD; - } - - p = &buf[*pos]; - *v = mandoc_getarg(mdoc->parse, &p, line, pos); - - /* - * After parsing the last word in this phrase, - * tell lookup() whether or not to interpret it. - */ - - if (*p == '\0' && mdoc->flags & MDOC_PHRASEQL) { - mdoc->flags &= ~MDOC_PHRASEQL; - mdoc->flags |= MDOC_PHRASEQF; - } - return ARGS_WORD; -} - -/* - * Check if the string consists only of space-separated closing - * delimiters. This is a bit of a dance: the first must be a close - * delimiter, but it may be followed by middle delimiters. Arbitrary - * whitespace may separate these tokens. - */ -static int -args_checkpunct(const char *buf, int i) -{ - int j; - char dbuf[DELIMSZ]; - enum mdelim d; - - /* First token must be a close-delimiter. */ - - for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++) - dbuf[j] = buf[i]; - - if (DELIMSZ == j) - return 0; - - dbuf[j] = '\0'; - if (DELIM_CLOSE != mdoc_isdelim(dbuf)) - return 0; - - while (' ' == buf[i]) - i++; - - /* Remaining must NOT be open/none. */ - - while (buf[i]) { - j = 0; - while (buf[i] && ' ' != buf[i] && j < DELIMSZ) - dbuf[j++] = buf[i++]; - - if (DELIMSZ == j) - return 0; - - dbuf[j] = '\0'; - d = mdoc_isdelim(dbuf); - if (DELIM_NONE == d || DELIM_OPEN == d) - return 0; - - while (' ' == buf[i]) - i++; - } - - return '\0' == buf[i]; -} - -static void -argv_multi(struct roff_man *mdoc, int line, - struct mdoc_argv *v, int *pos, char *buf) -{ - enum margserr ac; - char *p; - - for (v->sz = 0; ; v->sz++) { - if (buf[*pos] == '-') - break; - ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); - if (ac == ARGS_EOLN) - break; - - if (v->sz % MULTI_STEP == 0) - v->value = mandoc_reallocarray(v->value, - v->sz + MULTI_STEP, sizeof(char *)); - - v->value[(int)v->sz] = mandoc_strdup(p); - } -} - -static void -argv_single(struct roff_man *mdoc, int line, - struct mdoc_argv *v, int *pos, char *buf) -{ - enum margserr ac; - char *p; - - ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); - if (ac == ARGS_EOLN) - return; - - v->sz = 1; - v->value = mandoc_malloc(sizeof(char *)); - v->value[0] = mandoc_strdup(p); -} Property changes on: head/contrib/mdocml/mdoc_argv.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-wchar.c =================================================================== --- head/contrib/mdocml/test-wchar.c (revision 338825) +++ head/contrib/mdocml/test-wchar.c (nonexistent) @@ -1,63 +0,0 @@ -/* $Id: test-wchar.c,v 1.4 2016/07/31 09:29:13 schwarze Exp $ */ -/* - * Copyright (c) 2014 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. - */ - -#if defined(__linux__) || defined(__MINT__) -#define _GNU_SOURCE /* wcwidth() */ -#endif - -#include -#include -#include -#include - -int -main(void) -{ - wchar_t wc; - int width; - - if (setlocale(LC_ALL, "") == NULL) { - fputs("setlocale(LC_ALL, \"\") failed\n", stderr); - return 1; - } - - if (setlocale(LC_CTYPE, UTF8_LOCALE) == NULL) { - fprintf(stderr, "setlocale(LC_CTYPE, \"%s\") failed\n", - UTF8_LOCALE); - return 1; - } - - if (sizeof(wchar_t) < 4) { - fprintf(stderr, "wchar_t is only %zu bytes\n", - sizeof(wchar_t)); - return 1; - } - - if ((width = wcwidth(L' ')) != 1) { - fprintf(stderr, "wcwidth(L' ') returned %d\n", width); - return 1; - } - - dup2(STDERR_FILENO, STDOUT_FILENO); - wc = L'*'; - if (putwchar(wc) != (wint_t)wc) { - fputs("bad putwchar return value\n", stderr); - return 1; - } - - return 0; -} Property changes on: head/contrib/mdocml/test-wchar.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-be32toh.c =================================================================== --- head/contrib/mdocml/test-be32toh.c (revision 338825) +++ head/contrib/mdocml/test-be32toh.c (nonexistent) @@ -1,11 +0,0 @@ -#ifdef SYS_ENDIAN -#include -#else -#include -#endif - -int -main(void) -{ - return htobe32(be32toh(0x3a7d0cdb)) != 0x3a7d0cdb; -} Property changes on: head/contrib/mdocml/test-be32toh.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/configure.local.example =================================================================== --- head/contrib/mdocml/configure.local.example (revision 338825) +++ head/contrib/mdocml/configure.local.example (nonexistent) @@ -1,312 +0,0 @@ -# $Id: configure.local.example,v 1.33 2017/07/20 16:24:53 schwarze Exp $ -# -# Copyright (c) 2014, 2015, 2016, 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. - -# For all settings documented in this file, there are reasonable -# defaults and/or the ./configure script attempts autodetection. -# Consequently, you only need to create a file ./configure.local -# and put any of these settings into it if ./configure autodetection -# fails or if you want to make different choices for other reasons. - -# If autodetection fails, please tell . - -# We recommend that you write ./configure.local from scratch and -# only put the lines there you need. This file contains examples. -# It is not intended as a template to be copied as a whole. - -# --- user settings relevant for all builds ---------------------------- - -# For -Tutf8 and -Tlocale operation, mandoc(1) requires -# providing setlocale(3) and providing wcwidth(3) and -# putwchar(3) with a wchar_t storing UCS-4 values. Theoretically, -# the latter should be tested with the __STDC_ISO_10646__ feature -# macro. In practice, many headers do not provide that -# macro even though they treat wchar_t as UCS-4. So the automatic -# test only checks that wchar_t is wide enough, that is, at least -# four bytes. - -# The following line forces multi-byte support. -# If your C library does not treat wchar_t as UCS-4, the UTF-8 output -# mode will print garbage. - -HAVE_WCHAR=1 - -# The following line disables multi-byte support. -# The output modes -Tutf8 and -Tlocale will be the same as -Tascii. - -HAVE_WCHAR=0 - -# For -Tutf8 mode, mandoc needs to set an arbitrary locale having -# a UTF-8 character set. If autodetection of a suitable locale -# fails or selects an undesirable locale, you can manually choose -# the locale for -Tutf8 mode: - -UTF8_LOCALE=en_US.UTF-8 - -# When man(1) or apropos(1) is called without -m and -M options, -# MANPATH is not set in the environment, and man.conf(5) is not -# available, manuals are searched for in the following directory -# trees by default. - -MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" - -# Validation of cross references with mandoc -Tlint only looks -# for manual pages in the following directories: - -MANPATH_BASE="/usr/share/man:/usr/X11R6/man" - -# In manual pages written in the mdoc(7) language, the operating system -# version is displayed in the page footer line. If an operating system -# is specified as an argument to the .Os macro, that is always used. -# If the .Os macro has no argument and an operation system is specified -# with the mandoc(1) -Ios= command line option, that is used. -# Otherwise, the uname(3) library function is called at runtime to find -# the name of the operating system. -# If you do not want uname(3) to be called but instead want a fixed -# string to be used, use the following line: - -OSNAME="OpenBSD 6.0" - -# The following installation directories are used. -# It is possible to set only one or a few of these variables, -# there is no need to copy the whole block. -# Even if you set PREFIX to something else, the other variables -# pick it up without copying them all over. - -PREFIX="/usr/local" -BINDIR="${PREFIX}/bin" -SBINDIR="${PREFIX}/sbin" -MANDIR="${PREFIX}/man" - -# If BINDIR and SBINDIR are not subdirectories of the same parent -# directory or if the basename(1) of BINDIR differs from "bin", -# the relative path from SBINDIR to BINDIR is also needed. -# The default is: - -BIN_FROM_SBIN="../bin" - -# Some distributions may want to avoid naming conflicts -# with the configuration files of other man(1) implementations. -# This changes the name of the installed section 5 manual page as well. -MANM_MANCONF="mandoc.conf" # default is "man.conf" - -# Some distributions may want to avoid naming conflicts among manuals. -# If you want to change the names of installed section 7 manual pages, -# the following alternative names are suggested. -# The suffix ".7" will automatically be appended. -# It is possible to set only one or a few of these variables, -# there is no need to copy the whole block. - -MANM_MAN="mandoc_man" # default is "man" -MANM_MDOC="mandoc_mdoc" # default is "mdoc" -MANM_ROFF="mandoc_roff" # default is "roff" -MANM_EQN="mandoc_eqn" # default is "eqn" -MANM_TBL="mandoc_tbl" # default is "tbl" - -# Some distributions may want to avoid naming conflicts with -# other man(1), apropos(1), makewhatis(8), or soelim(1) utilities. -# If you want to change the names of binary programs, -# the following alternative names are suggested. -# Using different names is possible as well. -# This changes the names of the installed section 1 and section 8 -# manual pages as well. -# It is possible to set only one or two of these variables, -# there is no need to copy the whole block. - -BINM_MAN=mman # default is "man" -BINM_APROPOS=mapropos # default is "apropos" -BINM_WHATIS=mwhatis # default is "whatis" -BINM_MAKEWHATIS=mandocdb # default is "makewhatis" -BINM_SOELIM=msoelim # default is "soelim" - -# Some distributions do not want hardlinks -# between installed binary programs. -# Set the following variable to use symbolic links instead. -# It is also used for links between manual pages. -# It is only used by the install* targets. -# When using this, DESTDIR must be empty or an absolute path. - -LN="ln -sf" # default is "ln -f" - -# Before falling back to the bundled version of the ohash(3) hashing -# library, autoconfiguration tries the following linker flag to -# link against your system version. If you do have ohash(3) on -# your system but it needs different linker flags, set the following -# variable to specify the required linker flags. - -LD_OHASH="-lutil" - -# When library autodetection decides to use -L/usr/local/lib, -# -I/usr/local/include is automatically added to CFLAGS. -# If you manually set LD_OHASH to something including -L/usr/local/lib, -# chances are you will also need the following line: - -CFLAGS="${CFLAGS} -I/usr/local/include" - -# Some platforms may need an additional linker flag for nanosleep(2). -# If none is needed or it is -lrt, it is autodetected. -# Otherwise, set the following variable. - -LD_NANOSLEEP="-lrt" - -# Some platforms may need an additional linker flag for recvmsg(2). -# If none is needed or it is -lsocket, it is autodetected. -# Otherwise, set the following variable. - -LD_RECVMSG="-lsocket" - -# Some platforms might need additional linker flags to link against -# libmandoc that are not autodetected, though no such cases are -# currently known. - -LDADD="-lm" - -# Some systems may want to set additional linker flags for all the -# binaries, not only for those using libmandoc, for example for -# hardening options. - -LDFLAGS="-Wl,-z,relro" - -# It is possible to change the utility program used for installation -# and the modes files are installed with. The defaults are: - -INSTALL="install" -INSTALL_PROGRAM="${INSTALL} -m 0555" -INSTALL_LIB="${INSTALL} -m 0444" -INSTALL_MAN="${INSTALL} -m 0444" -INSTALL_DATA="${INSTALL} -m 0444" - -# When using the "homebrew" package manager on Mac OS X, the actual -# manuals are located in a so-called "cellar" and only symlinked -# into the manual trees. To allow mandoc to follow such symlinks, -# you have to specify the physical location of the cellar as returned -# by realpath(3), for example: - -PREFIX="/usr/local" -HOMEBREWDIR="${PREFIX}/Cellar" - -# --- user settings for the mandoc(3) library -------------------------- - -# By default, libmandoc.a is not installed. It is almost never needed -# because there is almost no non-mandoc software out there using this -# library. The one notable exception is NetBSD apropos(1). -# So, when building for the NetBSD base system - but not for NetBSD -# ports nor for pkgsrc! - you may want the following: - -INSTALL_LIBMANDOC=1 - -# The following settings are only used when INSTALL_LIBMANDOC is set. - -INCLUDEDIR="${PREFIX}/include/mandoc" -LIBDIR="${PREFIX}/lib/mandoc" - -# --- user settings related to man.cgi --------------------------------- - -# By default, building man.cgi(8) is disabled. To enable it, copy -# cgi.h.example to cgi.h, edit it, and use the following line. - -BUILD_CGI=1 - -# The remaining settings in this section are only relevant if BUILD_CGI -# is enabled. Otherwise, they have no effect either way. - -# By default, man.cgi(8) is linked statically. -# Some systems do not support static linking, for example Mac OS X. -# In that case, use the following line: - -STATIC= - -# Some systems, for example Linux, require -pthread for static linking: - -STATIC="-static -pthread" - -# Some directories. -# This works just like PREFIX, see above. - -WWWPREFIX="/var/www" -HTDOCDIR="${WWWPREFIX}/htdocs" -CGIBINDIR="${WWWPREFIX}/cgi-bin" - -# --- user settings related to catman ---------------------------------- - -# By default, building mandocd(8) and catman(8) is disabled. -# To enable it, use the following line. -# It does not work on SunOS 5.10 because there is no mkdirat(2) -# nor on SunOS 5.9 which also lacks CMSG_LEN(3) and CMSG_SPACE(3). - -BUILD_CATMAN=1 - -# Install catman(8) with a different name. -# See BINM_MAN above for details of how this works. - -BINM_CATMAN=mcatman # default is "catman" - -# --- settings that rarely need to be touched -------------------------- - -# Do not set these variables unless you really need to. - -# You can manually override the compiler to be used. -# But that's rarely useful because ./configure asks your make(1) -# which compiler to use, and that answer will hardly be wrong. - -CC=cc - -# IBM AIX may need: - -CC=xlc - -# The default compiler flags are: - -CFLAGS="-g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings" - -# IBM AIX xlc does not support -W; in that case, please use: - -CFLAGS="-g" - -# In rare cases, it may be required to skip individual automatic tests. -# Each of the following variables can be set to 0 (test will not be run -# and will be regarded as failed) or 1 (test will not be run and will -# be regarded as successful). - -HAVE_DIRENT_NAMLEN=0 -HAVE_ENDIAN=0 -HAVE_EFTYPE=0 -HAVE_ERR=0 -HAVE_FTS=0 # Setting this implies HAVE_FTS_COMPARE_CONST=0. -HAVE_FTS_COMPARE_CONST=0 # Setting this implies HAVE_FTS=1. -HAVE_GETLINE=0 -HAVE_GETSUBOPT=0 -HAVE_ISBLANK=0 -HAVE_MKDTEMP=0 -HAVE_NTOHL=0 -HAVE_O_DIRECTORY=0 -HAVE_OHASH=0 -HAVE_PATH_MAX=0 -HAVE_PLEDGE=0 -HAVE_PROGNAME=0 -HAVE_REALLOCARRAY=0 -HAVE_RECALLOCARRAY=0 -HAVE_REWB_BSD=0 -HAVE_REWB_SYSV=0 -HAVE_STRCASESTR=0 -HAVE_STRINGLIST=0 -HAVE_STRLCAT=0 -HAVE_STRLCPY=0 -HAVE_STRPTIME=0 -HAVE_STRSEP=0 -HAVE_STRTONUM=0 -HAVE_SYS_ENDIAN=0 -HAVE_VASPRINTF=0 -HAVE_WCHAR=0 Index: head/contrib/mdocml/dbm_map.h =================================================================== --- head/contrib/mdocml/dbm_map.h (revision 338825) +++ head/contrib/mdocml/dbm_map.h (nonexistent) @@ -1,29 +0,0 @@ -/* $Id: dbm_map.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */ -/* - * Copyright (c) 2016 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. - * - * Private interface for low-level routines for the map-based version - * of the mandoc database, for read-only access. - * To be used by dbm*.c only. - */ - -struct dbm_match; - -int dbm_map(const char *); -void dbm_unmap(void); -void *dbm_get(int32_t); -int32_t *dbm_getint(int32_t); -int32_t dbm_addr(const void *); -int dbm_match(const struct dbm_match *, const char *); Property changes on: head/contrib/mdocml/dbm_map.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/libroff.h =================================================================== --- head/contrib/mdocml/libroff.h (revision 338825) +++ head/contrib/mdocml/libroff.h (nonexistent) @@ -1,80 +0,0 @@ -/* $Id: libroff.h,v 1.42 2017/07/08 17:52:49 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * 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 mparse *parse; /* main parser, for error reporting */ - struct roff_node *node; /* syntax tree of this equation */ - struct eqn_def *defs; /* array of definitions */ - char *data; /* source code of this equation */ - char *start; /* first byte of the current token */ - char *end; /* first byte of the next token */ - size_t defsz; /* number of definitions */ - size_t sz; /* length of the source code */ - size_t toksz; /* length of the current token */ - int gsize; /* default point size */ - int delim; /* in-line delimiters enabled */ - char odelim; /* in-line opening delimiter */ - char cdelim; /* in-line closing delimiter */ -}; - -struct eqn_def { - char *key; - size_t keysz; - char *val; - size_t valsz; -}; - - -struct tbl_node *tbl_alloc(int, int, struct mparse *); -void tbl_restart(int, int, struct tbl_node *); -void tbl_free(struct tbl_node *); -void tbl_reset(struct tbl_node *); -void tbl_read(struct tbl_node *, int, const char *, int); -void tbl_option(struct tbl_node *, int, const char *, int *); -void tbl_layout(struct tbl_node *, int, const char *, int); -void tbl_data(struct tbl_node *, int, const char *, int); -void tbl_cdata(struct tbl_node *, int, const char *, int); -const struct tbl_span *tbl_span(struct tbl_node *); -int tbl_end(struct tbl_node *); -struct eqn_node *eqn_alloc(struct mparse *); -void eqn_box_free(struct eqn_box *); -void eqn_free(struct eqn_node *); -void eqn_parse(struct eqn_node *); -void eqn_read(struct eqn_node *, const char *); -void eqn_reset(struct eqn_node *); Property changes on: head/contrib/mdocml/libroff.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-isblank.c =================================================================== --- head/contrib/mdocml/test-isblank.c (revision 338825) +++ head/contrib/mdocml/test-isblank.c (nonexistent) @@ -1,7 +0,0 @@ -#include - -int -main(void) -{ - return !isblank(' ') || !isblank('\t') || isblank('_'); -} Property changes on: head/contrib/mdocml/test-isblank.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-strlcpy.c =================================================================== --- head/contrib/mdocml/test-strlcpy.c (revision 338825) +++ head/contrib/mdocml/test-strlcpy.c (nonexistent) @@ -1,9 +0,0 @@ -#include - -int -main(void) -{ - char buf[2] = ""; - return ! (strlcpy(buf, "a", sizeof(buf)) == 1 && - buf[0] == 'a' && buf[1] == '\0'); -} Property changes on: head/contrib/mdocml/test-strlcpy.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/roff.7 =================================================================== --- head/contrib/mdocml/roff.7 (revision 338825) +++ head/contrib/mdocml/roff.7 (nonexistent) @@ -1,2188 +0,0 @@ -.\" $Id: roff.7,v 1.94 2017/07/05 12:25:17 schwarze Exp $ -.\" -.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons -.\" Copyright (c) 2010,2011,2013-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. -.\" -.Dd $Mdocdate: July 5 2017 $ -.Dt ROFF 7 -.Os -.Sh NAME -.Nm roff -.Nd roff language reference for mandoc -.Sh DESCRIPTION -The -.Nm roff -language is a general purpose text formatting language. -Since traditional implementations of the -.Xr mdoc 7 -and -.Xr man 7 -manual formatting languages are based on it, -many real-world manuals use small numbers of -.Nm -requests and escape sequences intermixed with their -.Xr mdoc 7 -or -.Xr man 7 -code. -To properly format such manuals, the -.Xr mandoc 1 -utility supports a tiny subset of -.Nm -requests and escapes. -Only these requests and escapes supported by -.Xr mandoc 1 -are documented in the present manual, -together with the basic language syntax shared by -.Nm , -.Xr mdoc 7 , -and -.Xr man 7 . -For complete -.Nm -manuals, consult the -.Sx SEE ALSO -section. -.Pp -Input lines beginning with the control character -.Sq \&. -are parsed for requests and macros. -Such lines are called -.Dq request lines -or -.Dq macro lines , -respectively. -Requests change the processing state and manipulate the formatting; -some macros also define the document structure and produce formatted -output. -The single quote -.Pq Qq \(aq -is accepted as an alternative control character, -treated by -.Xr mandoc 1 -just like -.Ql \&. -.Pp -Lines not beginning with control characters are called -.Dq text lines . -They provide free-form text to be printed; the formatting of the text -depends on the respective processing context. -.Sh LANGUAGE SYNTAX -.Nm -documents may contain only graphable 7-bit ASCII characters, the space -character, and, in certain circumstances, the tab character. -The backslash character -.Sq \e -indicates the start of an escape sequence, used for example for -.Sx Comments , -.Sx Special Characters , -.Sx Predefined Strings , -and -user-defined strings defined using the -.Sx ds -request. -For a listing of escape sequences, consult the -.Sx ESCAPE SEQUENCE REFERENCE -below. -.Ss Comments -Text following an escaped double-quote -.Sq \e\(dq , -whether in a request, macro, or text line, is ignored to the end of the line. -A request line beginning with a control character and comment escape -.Sq \&.\e\(dq -is also ignored. -Furthermore, request lines with only a control character and optional -trailing whitespace are stripped from input. -.Pp -Examples: -.Bd -literal -offset indent -compact -\&.\e\(dq This is a comment line. -\&.\e\(dq The next line is ignored: -\&. -\&.Sh EXAMPLES \e\(dq This is a comment, too. -\&example text \e\(dq And so is this. -.Ed -.Ss Special Characters -Special characters are used to encode special glyphs and are rendered -differently across output media. -They may occur in request, macro, and text lines. -Sequences begin with the escape character -.Sq \e -followed by either an open-parenthesis -.Sq \&( -for two-character sequences; an open-bracket -.Sq \&[ -for n-character sequences (terminated at a close-bracket -.Sq \&] ) ; -or a single one character sequence. -.Pp -Examples: -.Bl -tag -width Ds -offset indent -compact -.It Li \e(em -Two-letter em dash escape. -.It Li \ee -One-letter backslash escape. -.El -.Pp -See -.Xr mandoc_char 7 -for a complete list. -.Ss Text Decoration -Terms may be text-decorated using the -.Sq \ef -escape followed by an indicator: B (bold), I (italic), R (regular), or P -(revert to previous mode). -A numerical representation 3, 2, or 1 (bold, italic, and regular, -respectively) may be used instead. -The indicator or numerical representative may be preceded by C -(constant-width), which is ignored. -.Pp -The two-character indicator -.Sq BI -requests a font that is both bold and italic. -It may not be portable to old roff implementations. -.Pp -Examples: -.Bl -tag -width Ds -offset indent -compact -.It Li \efBbold\efR -Write in \fBbold\fP, then switch to regular font mode. -.It Li \efIitalic\efP -Write in \fIitalic\fP, then return to previous font mode. -.It Li \ef(BIbold italic\efP -Write in \f(BIbold italic\fP, then return to previous font mode. -.El -.Pp -Text decoration is -.Em not -recommended for -.Xr mdoc 7 , -which encourages semantic annotation. -.Ss Predefined Strings -Predefined strings, like -.Sx Special Characters , -mark special output glyphs. -Predefined strings are escaped with the slash-asterisk, -.Sq \e* : -single-character -.Sq \e*X , -two-character -.Sq \e*(XX , -and N-character -.Sq \e* Ns Bq N . -.Pp -Examples: -.Bl -tag -width Ds -offset indent -compact -.It Li \e*(Am -Two-letter ampersand predefined string. -.It Li \e*q -One-letter double-quote predefined string. -.El -.Pp -Predefined strings are not recommended for use, -as they differ across implementations. -Those supported by -.Xr mandoc 1 -are listed in -.Xr mandoc_char 7 . -Manuals using these predefined strings are almost certainly not portable. -.Ss Whitespace -Whitespace consists of the space character. -In text lines, whitespace is preserved within a line. -In request and macro lines, whitespace delimits arguments and is discarded. -.Pp -Unescaped trailing spaces are stripped from text line input unless in a -literal context. -In general, trailing whitespace on any input line is discouraged for -reasons of portability. -In the rare case that a blank character is needed at the end of an -input line, it may be forced by -.Sq \e\ \e& . -.Pp -Literal space characters can be produced in the output -using escape sequences. -In macro lines, they can also be included in arguments using quotation; see -.Sx MACRO SYNTAX -for details. -.Pp -Blank text lines, which may include whitespace, are only permitted -within literal contexts. -If the first character of a text line is a space, that line is printed -with a leading newline. -.Ss Scaling Widths -Many requests and macros support scaled widths for their arguments. -The syntax for a scaled width is -.Sq Li [+-]?[0-9]*.[0-9]*[:unit:] , -where a decimal must be preceded or followed by at least one digit. -Negative numbers, while accepted, are truncated to zero. -.Pp -The following scaling units are accepted: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It c -centimetre -.It i -inch -.It P -pica (~1/6 inch) -.It p -point (~1/72 inch) -.It f -scale -.Sq u -by 65536 -.It v -default vertical span -.It m -width of rendered -.Sq m -.Pq em -character -.It n -width of rendered -.Sq n -.Pq en -character -.It u -default horizontal span for the terminal -.It M -mini-em (~1/100 em) -.El -.Pp -Using anything other than -.Sq m , -.Sq n , -or -.Sq v -is necessarily non-portable across output media. -See -.Sx COMPATIBILITY . -.Pp -If a scaling unit is not provided, the numerical value is interpreted -under the default rules of -.Sq v -for vertical spaces and -.Sq u -for horizontal ones. -.Pp -Examples: -.Bl -tag -width ".Bl -tag -width 2i" -offset indent -compact -.It Li \&.Bl -tag -width 2i -two-inch tagged list indentation in -.Xr mdoc 7 -.It Li \&.HP 2i -two-inch tagged list indentation in -.Xr man 7 -.It Li \&.sp 2v -two vertical spaces -.El -.Ss Sentence Spacing -Each sentence should terminate at the end of an input line. -By doing this, a formatter will be able to apply the proper amount of -spacing after the end of sentence (unescaped) period, exclamation mark, -or question mark followed by zero or more non-sentence closing -delimiters -.Po -.Sq \&) , -.Sq \&] , -.Sq \&' , -.Sq \&" -.Pc . -.Pp -The proper spacing is also intelligently preserved if a sentence ends at -the boundary of a macro line. -.Pp -Examples: -.Bd -literal -offset indent -compact -Do not end sentences mid-line like this. Instead, -end a sentence like this. -A macro would end like this: -\&.Xr mandoc 1 \&. -.Ed -.Sh REQUEST SYNTAX -A request or macro line consists of: -.Pp -.Bl -enum -compact -.It -the control character -.Sq \&. -or -.Sq \(aq -at the beginning of the line, -.It -optionally an arbitrary amount of whitespace, -.It -the name of the request or the macro, which is one word of arbitrary -length, terminated by whitespace, -.It -and zero or more arguments delimited by whitespace. -.El -.Pp -Thus, the following request lines are all equivalent: -.Bd -literal -offset indent -\&.ig end -\&.ig end -\&. ig end -.Ed -.Sh MACRO SYNTAX -Macros are provided by the -.Xr mdoc 7 -and -.Xr man 7 -languages and can be defined by the -.Sx \&de -request. -When called, they follow the same syntax as requests, except that -macro arguments may optionally be quoted by enclosing them -in double quote characters -.Pq Sq \(dq . -Quoted text, even if it contains whitespace or would cause -a macro invocation when unquoted, is always considered literal text. -Inside quoted text, pairs of double quote characters -.Pq Sq Qq -resolve to single double quote characters. -.Pp -To be recognised as the beginning of a quoted argument, the opening -quote character must be preceded by a space character. -A quoted argument extends to the next double quote character that is not -part of a pair, or to the end of the input line, whichever comes earlier. -Leaving out the terminating double quote character at the end of the line -is discouraged. -For clarity, if more arguments follow on the same input line, -it is recommended to follow the terminating double quote character -by a space character; in case the next character after the terminating -double quote character is anything else, it is regarded as the beginning -of the next, unquoted argument. -.Pp -Both in quoted and unquoted arguments, pairs of backslashes -.Pq Sq \e\e -resolve to single backslashes. -In unquoted arguments, space characters can alternatively be included -by preceding them with a backslash -.Pq Sq \e\~ , -but quoting is usually better for clarity. -.Pp -Examples: -.Bl -tag -width Ds -offset indent -compact -.It Li .Fn strlen \(dqconst char *s\(dq -Group arguments -.Qq const char *s -into one function argument. -If unspecified, -.Qq const , -.Qq char , -and -.Qq *s -would be considered separate arguments. -.It Li .Op \(dqFl a\(dq -Consider -.Qq \&Fl a -as literal text instead of a flag macro. -.El -.Sh REQUEST REFERENCE -The -.Xr mandoc 1 -.Nm -parser recognises the following requests. -For requests marked as "ignored" or "unsupported", any arguments are -ignored, and the number of arguments is not checked. -.Bl -tag -width Ds -.It Ic \&ab Op Ar message -Abort processing. -Currently unsupported. -.It Ic \&ad Op Cm b | c | l | n | r -Set line adjustment mode for subsequent text. -Currently ignored. -.It Ic \&af Ar registername format -Assign an output format to a number register. -Currently ignored. -.It Ic \&aln Ar newname oldname -Create an alias for a number register. -Currently unsupported. -.It Ic \&als Ar newname oldname -Create an alias for a request, string, macro, or diversion. -.It Ic \&am Ar macroname Op Ar endmacro -Append to a macro definition. -The syntax of this request is the same as that of -.Ic \&de . -.It Ic \&am1 Ar macroname Op Ar endmacro -Append to a macro definition, switching roff compatibility mode off -during macro execution (groff extension). -The syntax of this request is the same as that of -.Ic \&de1 . -Since -.Xr mandoc 1 -does not implement -.Nm -compatibility mode at all, it handles this request as an alias for -.Ic \&am . -.It Ic \&ami Ar macrostring Op Ar endstring -Append to a macro definition, specifying the macro name indirectly -(groff extension). -The syntax of this request is the same as that of -.Ic \&dei . -.It Ic \&ami1 Ar macrostring Op Ar endstring -Append to a macro definition, specifying the macro name indirectly -and switching roff compatibility mode off during macro execution -(groff extension). -The syntax of this request is the same as that of -.Ic \&dei1 . -Since -.Xr mandoc 1 -does not implement -.Nm -compatibility mode at all, it handles this request as an alias for -.Ic \&ami . -.It Ic \&as Ar stringname Op Ar string -Append to a user-defined string. -The syntax of this request is the same as that of -.Sx \&ds . -If a user-defined string with the specified name does not yet exist, -it is set to the empty string before appending. -.It Ic \&as1 Ar stringname Op Ar string -Append to a user-defined string, switching roff compatibility mode off -during macro execution (groff extension). -The syntax of this request is the same as that of -.Ic \&ds1 . -Since -.Xr mandoc 1 -does not implement -.Nm -compatibility mode at all, it handles this request as an alias for -.Ic \&as . -.It Ic \&asciify Ar divname -Fully unformat a diversion. -Currently unsupported. -.It Ic \&backtrace -Print a backtrace of the input stack. -This is a groff extension and currently ignored. -.It Ic \&bd Ar font Oo Ar curfont Oc Op Ar offset -Artificially embolden by repeated printing with small shifts. -Currently ignored. -.It Ic \&bleedat Ar left top width height -Set the BleedBox page parameter for PDF generation. -This is a Heirloom extension and currently ignored. -.It Ic \&blm Ar macroname -Set a blank line trap. -Currently unsupported. -.It Ic \&box Ar divname -Begin a diversion without including a partially filled line. -Currently unsupported. -.It Ic \&boxa Ar divname -Add to a diversion without including a partially filled line. -Currently unsupported. -.It Ic \&bp Oo Cm + Ns | Ns Cm - Oc Ns Ar pagenumber -Begin a new page. -Currently ignored. -.It Ic \&BP Ar source height width position offset flags label -Define a frame and place a picture in it. -This is a Heirloom extension and currently unsupported. -.It Ic \&br -Break the output line. -.It Ic \&break -Break out of a -.Ic \&while -loop. -Currently unsupported. -.It Ic \&breakchar Ar char ... -Optional line break characters. -This is a Heirloom extension and currently ignored. -.It Ic \&brnl Ar N -Break output line after the next -.Ar N -input lines. -This is a Heirloom extension and currently ignored. -.It Ic \&brp -Break and spread output line. -Currently, this is implemented as an alias for -.Ic \&br . -.It Ic \&brpnl Ar N -Break and spread output line after the next -.Ar N -input lines. -This is a Heirloom extension and currently ignored. -.It Ic \&c2 Op Ar char -Change the no-break control character. -Currently unsupported. -.It Ic \&cc Op Ar char -Change the control character. -If -.Ar char -is not specified, the control character is reset to -.Sq \&. . -Trailing characters are ignored. -.It Ic \&ce Op Ar N -Center the next -.Ar N -input lines without filling. -.Ar N -defaults to 1. -An argument of 0 or less ends centering. -Currently, high level macros abort centering. -.It Ic \&cf Ar filename -Output the contents of a file. -Ignored because insecure. -.It Ic \&cflags Ar flags char ... -Set character flags. -This is a groff extension and currently ignored. -.It Ic \&ch Ar macroname Op Ar dist -Change a trap location. -Currently ignored. -.It Ic \&char Ar glyphname Op Ar string -Define a new glyph. -Currently unsupported. -.It Ic \&chop Ar stringname -Remove the last character from a macro, string, or diversion. -Currently unsupported. -.It Ic \&class Ar classname char ... -Define a character class. -This is a groff extension and currently ignored. -.It Ic \&close Ar streamname -Close an open file. -Ignored because insecure. -.It Ic \&CL Ar color text -Print text in color. -This is a Heirloom extension and currently unsupported. -.It Ic \&color Op Cm 1 | 0 -Activate or deactivate colors. -This is a groff extension and currently ignored. -.It Ic \&composite Ar from to -Define a name component for composite glyph names. -This is a groff extension and currently unsupported. -.It Ic \&continue -Immediately start the next iteration of a -.Ic \&while -loop. -Currently unsupported. -.It Ic \&cp Op Cm 1 | 0 -Switch -.Nm -compatibility mode on or off. -Currently ignored. -.It Ic \&cropat Ar left top width height -Set the CropBox page parameter for PDF generation. -This is a Heirloom extension and currently ignored. -.It Ic \&cs Ar font Op Ar width Op Ar emsize -Constant character spacing mode. -Currently ignored. -.It Ic \&cu Op Ar N -Underline next -.Ar N -input lines including whitespace. -Currently ignored. -.It Ic \&da Ar divname -Append to a diversion. -Currently unsupported. -.It Ic \&dch Ar macroname Op Ar dist -Change a trap location in the current diversion. -This is a Heirloom extension and currently unsupported. -.It Ic \&de Ar macroname Op Ar endmacro -Define a -.Nm -macro. -Its syntax can be either -.Bd -literal -offset indent -.Pf . Ic \&de Ar macroname -.Ar definition -\&.. -.Ed -.Pp -or -.Bd -literal -offset indent -.Pf . Ic \&de Ar macroname Ar endmacro -.Ar definition -.Pf . Ar endmacro -.Ed -.Pp -Both forms define or redefine the macro -.Ar macroname -to represent the -.Ar definition , -which may consist of one or more input lines, including the newline -characters terminating each line, optionally containing calls to -.Nm -requests, -.Nm -macros or high-level macros like -.Xr man 7 -or -.Xr mdoc 7 -macros, whichever applies to the document in question. -.Pp -Specifying a custom -.Ar endmacro -macro works in the same way as for -.Ic \&ig ; -namely, the call to -.Sq Pf . Ar endmacro -first ends the -.Ar definition , -and after that, it is also evaluated as a -.Nm -request or -.Nm -macro, but not as a high-level macro. -.Pp -The macro can be invoked later using the syntax -.Pp -.D1 Pf . Ar macroname Op Ar argument Op Ar argument ... -.Pp -Regarding argument parsing, see -.Sx MACRO SYNTAX -above. -.Pp -The line invoking the macro will be replaced -in the input stream by the -.Ar definition , -replacing all occurrences of -.No \e\e$ Ns Ar N , -where -.Ar N -is a digit, by the -.Ar N Ns th Ar argument . -For example, -.Bd -literal -offset indent -\&.de ZN -\efI\e^\e\e$1\e^\efP\e\e$2 -\&.. -\&.ZN XtFree . -.Ed -.Pp -produces -.Pp -.D1 \efI\e^XtFree\e^\efP. -.Pp -in the input stream, and thus in the output: \fI\^XtFree\^\fP. -Each occurrence of \e\e$* is replaced with all the arguments, -joined together with single blank characters. -.Pp -Since macros and user-defined strings share a common string table, -defining a macro -.Ar macroname -clobbers the user-defined string -.Ar macroname , -and the -.Ar definition -can also be printed using the -.Sq \e* -string interpolation syntax described below -.Ic ds , -but this is rarely useful because every macro definition contains at least -one explicit newline character. -.Pp -In order to prevent endless recursion, both groff and -.Xr mandoc 1 -limit the stack depth for expanding macros and strings -to a large, but finite number, and -.Xr mandoc 1 -also limits the length of the expanded input line. -Do not rely on the exact values of these limits. -.It Ic \&de1 Ar macroname Op Ar endmacro -Define a -.Nm -macro that will be executed with -.Nm -compatibility mode switched off during macro execution. -This is a groff extension. -Since -.Xr mandoc 1 -does not implement -.Nm -compatibility mode at all, it handles this request as an alias for -.Ic \&de . -.It Ic \&defcolor Ar newname scheme component ... -Define a color name. -This is a groff extension and currently ignored. -.It Ic \&dei Ar macrostring Op Ar endstring -Define a -.Nm -macro, specifying the macro name indirectly (groff extension). -The syntax of this request is the same as that of -.Ic \&de . -The effect is the same as: -.Pp -.D1 Pf . Cm \&de No \e* Ns Bo Ar macrostring Bc Op \e* Ns Bq Ar endstring -.It Ic \&dei1 Ar macrostring Op Ar endstring -Define a -.Nm -macro that will be executed with -.Nm -compatibility mode switched off during macro execution, -specifying the macro name indirectly (groff extension). -Since -.Xr mandoc 1 -does not implement -.Nm -compatibility mode at all, it handles this request as an alias for -.Ic \&dei . -.It Ic \&device Ar string ... -.It Ic \&devicem Ar stringname -These two requests only make sense with the groff-specific intermediate -output format and are unsupported. -.It Ic \&di Ar divname -Begin a diversion. -Currently unsupported. -.It Ic \&do Ar command Op Ar argument ... -Execute -.Nm -request or macro line with compatibility mode disabled. -Currently unsupported. -.It Ic \&ds Ar stringname Op Oo \(dq Oc Ns Ar string -Define a user-defined string. -The -.Ar stringname -and -.Ar string -arguments are space-separated. -If the -.Ar string -begins with a double-quote character, that character will not be part -of the string. -All remaining characters on the input line form the -.Ar string , -including whitespace and double-quote characters, even trailing ones. -.Pp -The -.Ar string -can be interpolated into subsequent text by using -.No \e* Ns Bq Ar stringname -for a -.Ar stringname -of arbitrary length, or \e*(NN or \e*N if the length of -.Ar stringname -is two or one characters, respectively. -Interpolation can be prevented by escaping the leading backslash; -that is, an asterisk preceded by an even number of backslashes -does not trigger string interpolation. -.Pp -Since user-defined strings and macros share a common string table, -defining a string -.Ar stringname -clobbers the macro -.Ar stringname , -and the -.Ar stringname -used for defining a string can also be invoked as a macro, -in which case the following input line will be appended to the -.Ar string , -forming a new input line passed to the -.Nm -parser. -For example, -.Bd -literal -offset indent -\&.ds badidea .S -\&.badidea -H SYNOPSIS -.Ed -.Pp -invokes the -.Ic SH -macro when used in a -.Xr man 7 -document. -Such abuse is of course strongly discouraged. -.It Ic \&ds1 Ar stringname Op Oo \(dq Oc Ns Ar string -Define a user-defined string that will be expanded with -.Nm -compatibility mode switched off during string expansion. -This is a groff extension. -Since -.Xr mandoc 1 -does not implement -.Nm -compatibility mode at all, it handles this request as an alias for -.Ic \&ds . -.It Ic \&dwh Ar dist macroname -Set a location trap in the current diversion. -This is a Heirloom extension and currently unsupported. -.It Ic \&dt Op Ar dist macroname -Set a trap within a diversion. -Currently unsupported. -.It Ic \&ec Op Ar char -Enable the escape mechanism and change the escape character. -The -.Ar char -argument defaults to the backslash -.Pq Sq \e . -.It Ic \&ecr -Restore the escape character. -Currently unsupported. -.It Ic \&ecs -Save the escape character. -Currently unsupported. -.It Ic \&el Ar body -The -.Dq else -half of an if/else conditional. -Pops a result off the stack of conditional evaluations pushed by -.Ic \&ie -and uses it as its conditional. -If no stack entries are present (e.g., due to no prior -.Ic \&ie -calls) -then false is assumed. -The syntax of this request is similar to -.Ic \&if -except that the conditional is missing. -.It Ic \&em Ar macroname -Set a trap at the end of input. -Currently unsupported. -.It Ic \&EN -End an equation block. -See -.Ic \&EQ . -.It Ic \&eo -Disable the escape mechanism completely. -.It Ic \&EP -End a picture started by -.Ic \&BP . -This is a Heirloom extension and currently unsupported. -.It Ic \&EQ -Begin an equation block. -See -.Xr eqn 7 -for a description of the equation language. -.It Ic \&errprint Ar message -Print a string like an error message. -This is a Heirloom extension and currently ignored. -.It Ic \&ev Op Ar envname -Switch to another environment. -Currently unsupported. -.It Ic \&evc Op Ar envname -Copy an environment into the current environment. -Currently unsupported. -.It Ic \&ex -Abort processing and exit. -Currently unsupported. -.It Ic \&fallback Ar curfont font ... -Select the fallback sequence for a font. -This is a Heirloom extension and currently ignored. -.It Ic \&fam Op Ar familyname -Change the font family. -This is a groff extension and currently ignored. -.It Ic \&fc Op Ar delimchar Op Ar padchar -Define a delimiting and a padding character for fields. -Currently unsupported. -.It Ic \&fchar Ar glyphname Op Ar string -Define a fallback glyph. -Currently unsupported. -.It Ic \&fcolor Ar colorname -Set the fill color for \eD objects. -This is a groff extension and currently ignored. -.It Ic \&fdeferlig Ar font string ... -Defer ligature building. -This is a Heirloom extension and currently ignored. -.It Ic \&feature Cm + Ns | Ns Cm - Ns Ar name -Enable or disable an OpenType feature. -This is a Heirloom extension and currently ignored. -.It Ic \&fi -Switch to fill mode. -See -.Xr man 7 . -Ignored in -.Xr mdoc 7 . -.It Ic \&fkern Ar font minkern -Control the use of kerning tables for a font. -This is a Heirloom extension and currently ignored. -.It Ic \&fl -Flush output. -Currently ignored. -.It Ic \&flig Ar font string char ... -Define ligatures. -This is a Heirloom extension and currently ignored. -.It Ic \&fp Ar position font Op Ar filename -Assign font position. -Currently ignored. -.It Ic \&fps Ar mapname ... -Mount a font with a special character map. -This is a Heirloom extension and currently ignored. -.It Ic \&fschar Ar font glyphname Op Ar string -Define a font-specific fallback glyph. -This is a groff extension and currently unsupported. -.It Ic \&fspacewidth Ar font Op Ar afmunits -Set a font-specific width for the space character. -This is a Heirloom extension and currently ignored. -.It Ic \&fspecial Ar curfont Op Ar font ... -Conditionally define a special font. -This is a groff extension and currently ignored. -.It Ic \&ft Op Ar font -Change the font. -The following -.Ar font -arguments are supported: -.Bl -tag -width 4n -offset indent -.It Cm B , BI , 3 , 4 -switches to -.Sy bold -font -.It Cm I , 2 -switches to -.Em underlined -font -.It Cm R , CW , 1 -switches to normal font -.It Cm P No "or no argument" -switches back to the previous font -.El -.Pp -This request takes effect only locally and may be overridden -by macros and escape sequences. -.It Ic \&ftr Ar newname Op Ar oldname -Translate font name. -This is a groff extension and currently ignored. -.It Ic \&fzoom Ar font Op Ar permille -Zoom font size. -Currently ignored. -.It Ic \&gcolor Op Ar colorname -Set glyph color. -This is a groff extension and currently ignored. -.It Ic \&hc Op Ar char -Set the hyphenation character. -Currently ignored. -.It Ic \&hcode Ar char code ... -Set hyphenation codes of characters. -Currently ignored. -.It Ic \&hidechar Ar font char ... -Hide characters in a font. -This is a Heirloom extension and currently ignored. -.It Ic \&hla Ar language -Set hyphenation language. -This is a groff extension and currently ignored. -.It Ic \&hlm Op Ar number -Set maximum number of consecutive hyphenated lines. -Currently ignored. -.It Ic \&hpf Ar filename -Load hyphenation pattern file. -This is a groff extension and currently ignored. -.It Ic \&hpfa Ar filename -Load hyphenation pattern file, appending to the current patterns. -This is a groff extension and currently ignored. -.It Ic \&hpfcode Ar code code ... -Define mapping values for character codes in hyphenation patterns. -This is a groff extension and currently ignored. -.It Ic \&hw Ar word ... -Specify hyphenation points in words. -Currently ignored. -.It Ic \&hy Op Ar mode -Set automatic hyphenation mode. -Currently ignored. -.It Ic \&hylang Ar language -Set hyphenation language. -This is a Heirloom extension and currently ignored. -.It Ic \&hylen Ar nchar -Minimum word length for hyphenation. -This is a Heirloom extension and currently ignored. -.It Ic \&hym Op Ar length -Set hyphenation margin. -This is a groff extension and currently ignored. -.It Ic \&hypp Ar penalty ... -Define hyphenation penalties. -This is a Heirloom extension and currently ignored. -.It Ic \&hys Op Ar length -Set hyphenation space. -This is a groff extension and currently ignored. -.It Ic \&ie Ar condition body -The -.Dq if -half of an if/else conditional. -The result of the conditional is pushed into a stack used by subsequent -invocations of -.Ic \&el , -which may be separated by any intervening input (or not exist at all). -Its syntax is equivalent to -.Ic \&if . -.It Ic \&if Ar condition body -Begin a conditional. -This request can also be written as follows: -.Bd -unfilled -offset indent -.Pf . Ic \&if Ar condition No \e{ Ns Ar body -.Ar body ... Ns \e} -.Ed -.Bd -unfilled -offset indent -.Pf . Ic \&if Ar condition No \e{\e -.Ar body ... -.Pf . No \e} -.Ed -.Pp -The -.Ar condition -is a boolean expression. -Currently, -.Xr mandoc 1 -supports the following subset of roff conditionals: -.Bl -bullet -.It -If -.Sq \&! -is prefixed to -.Ar condition , -it is logically inverted. -.It -If the first character of -.Ar condition -is -.Sq n -.Pq nroff mode -or -.Sq o -.Pq odd page , -it evaluates to true. -.It -If the first character of -.Ar condition -is -.Sq c -.Pq character available , -.Sq e -.Pq even page , -.Sq t -.Pq troff mode , -or -.Sq v -.Pq vroff mode , -it evaluates to false. -.It -If the first character of -.Ar condition -is -.Sq d , -it evaluates to true if the rest of -.Ar condition -is the name of an existing user defined macro or string; -otherwise, it evaluates to false. -.It -If the first character of -.Ar condition -is -.Sq r , -it evaluates to true if the rest of -.Ar condition -is the name of an existing number register; -otherwise, it evaluates to false. -.It -If the -.Ar condition -starts with a parenthesis or with an optionally signed -integer number, it is evaluated according to the rules of -.Sx Numerical expressions -explained below. -It evaluates to true if the result is positive, -or to false if the result is zero or negative. -.It -Otherwise, the first character of -.Ar condition -is regarded as a delimiter and it evaluates to true if the string -extending from its first to its second occurrence is equal to the -string extending from its second to its third occurrence. -.It -If -.Ar condition -cannot be parsed, it evaluates to false. -.El -.Pp -If a conditional is false, its children are not processed, but are -syntactically interpreted to preserve the integrity of the input -document. -Thus, -.Pp -.D1 \&.if t .ig -.Pp -will discard the -.Sq \&.ig , -which may lead to interesting results, but -.Pp -.D1 \&.if t .if t \e{\e -.Pp -will continue to syntactically interpret to the block close of the final -conditional. -Sub-conditionals, in this case, obviously inherit the truth value of -the parent. -.Pp -If the -.Ar body -section is begun by an escaped brace -.Sq \e{ , -scope continues until the end of the input line containing the -matching closing-brace escape sequence -.Sq \e} . -If the -.Ar body -is not enclosed in braces, scope continues until the end of the line. -If the -.Ar condition -is followed by a -.Ar body -on the same line, whether after a brace or not, then requests and macros -.Em must -begin with a control character. -It is generally more intuitive, in this case, to write -.Bd -unfilled -offset indent -.Pf . Ic \&if Ar condition No \e{\e -.Pf . Ar request -.Pf . No \e} -.Ed -.Pp -than having the request or macro follow as -.Pp -.D1 Pf . Ic \&if Ar condition Pf \e{. Ar request -.Pp -The scope of a conditional is always parsed, but only executed if the -conditional evaluates to true. -.Pp -Note that the -.Sq \e} -is converted into a zero-width escape sequence if not passed as a -standalone macro -.Sq \&.\e} . -For example, -.Pp -.D1 \&.Fl a \e} b -.Pp -will result in -.Sq \e} -being considered an argument of the -.Sq \&Fl -macro. -.It Ic \&ig Op Ar endmacro -Ignore input. -Its syntax can be either -.Bd -literal -offset indent -.Pf . Cm \&ig -.Ar ignored text -\&.. -.Ed -.Pp -or -.Bd -literal -offset indent -.Pf . Cm \&ig Ar endmacro -.Ar ignored text -.Pf . Ar endmacro -.Ed -.Pp -In the first case, input is ignored until a -.Sq \&.. -request is encountered on its own line. -In the second case, input is ignored until the specified -.Sq Pf . Ar endmacro -is encountered. -Do not use the escape character -.Sq \e -anywhere in the definition of -.Ar endmacro ; -it would cause very strange behaviour. -.Pp -When the -.Ar endmacro -is a roff request or a roff macro, like in -.Pp -.D1 \&.ig if -.Pp -the subsequent invocation of -.Ic \&if -will first terminate the -.Ar ignored text , -then be invoked as usual. -Otherwise, it only terminates the -.Ar ignored text , -and arguments following it or the -.Sq \&.. -request are discarded. -.It Ic \&in Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width -Change indentation. -See -.Xr man 7 . -Ignored in -.Xr mdoc 7 . -.It Ic \&index Ar register stringname substring -Find a substring in a string. -This is a Heirloom extension and currently unsupported. -.It Ic \&it Ar expression macro -Set an input line trap. -The named -.Ar macro -will be invoked after processing the number of input text lines -specified by the numerical -.Ar expression . -While evaluating the -.Ar expression , -the unit suffixes described below -.Sx Scaling Widths -are ignored. -.It Ic \&it Ar expression macro -Set an input line trap, not counting lines ending with \ec. -Currently unsupported. -.It Ic \&IX Ar class keystring -To support the generation of a table of contents, -.Xr pod2man 1 -emits this user-defined macro, usually without defining it. -To avoid reporting large numbers of spurious errors, -.Xr mandoc 1 -ignores it. -.It Ic \&kern Op Cm 1 | 0 -Switch kerning on or off. -Currently ignored. -.It Ic \&kernafter Ar font char ... afmunits ... -Increase kerning after some characters. -This is a Heirloom extension and currently ignored. -.It Ic \&kernbefore Ar font char ... afmunits ... -Increase kerning before some characters. -This is a Heirloom extension and currently ignored. -.It Ic \&kernpair Ar font char ... font char ... afmunits -Add a kerning pair to the kerning table. -This is a Heirloom extension and currently ignored. -.It Ic \&lc Op Ar glyph -Define a leader repetition character. -Currently unsupported. -.It Ic \&lc_ctype Ar localename -Set the -.Dv LC_CTYPE -locale. -This is a Heirloom extension and currently unsupported. -.It Ic \&lds Ar macroname string -Define a local string. -This is a Heirloom extension and currently unsupported. -.It Ic \&length Ar register string -Count the number of input characters in a string. -Currently unsupported. -.It Ic \&letadj Ar lspmin lshmin letss lspmax lshmax -Dynamic letter spacing and reshaping. -This is a Heirloom extension and currently ignored. -.It Ic \&lf Ar lineno Op Ar filename -Change the line number for error messages. -Ignored because insecure. -.It Ic \&lg Op Cm 1 | 0 -Switch the ligature mechanism on or off. -Currently ignored. -.It Ic \&lhang Ar font char ... afmunits -Hang characters at left margin. -This is a Heirloom extension and currently ignored. -.It Ic \&linetabs Op Cm 1 | 0 -Enable or disable line-tabs mode. -This is a groff extension and currently unsupported. -.It Ic \&ll Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width -Change the output line length. -If the -.Ar width -argument is omitted, the line length is reset to its previous value. -The default setting for terminal output is 78n. -If a sign is given, the line length is added to or subtracted from; -otherwise, it is set to the provided value. -Using this request in new manuals is discouraged for several reasons, -among others because it overrides the -.Xr mandoc 1 -.Fl O Cm width -command line option. -.It Ic \&lnr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar value Op Ar increment -Set local number register. -This is a Heirloom extension and currently unsupported. -.It Ic \&lnrf Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar value Op Ar increment -Set local floating-point register. -This is a Heirloom extension and currently unsupported. -.It Ic \&lpfx Ar string -Set a line prefix. -This is a Heirloom extension and currently unsupported. -.It Ic \&ls Op Ar factor -Set line spacing. -It takes one integer argument specifying the vertical distance of -subsequent output text lines measured in v units. -Currently ignored. -.It Ic \&lsm Ar macroname -Set a leading spaces trap. -This is a groff extension and currently unsupported. -.It Ic \< Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width -Set title line length. -Currently ignored. -.It Ic \&mc Ar glyph Op Ar dist -Print margin character in the right margin. -The -.Ar dist -is currently ignored; instead, 1n is used. -.It Ic \&mediasize Ar media -Set the device media size. -This is a Heirloom extension and currently ignored. -.It Ic \&minss Ar width -Set minimum word space. -This is a Heirloom extension and currently ignored. -.It Ic \&mk Op Ar register -Mark vertical position. -Currently ignored. -.It Ic \&mso Ar filename -Load a macro file using the search path. -Ignored because insecure. -.It Ic \&na -Disable adjusting without changing the adjustment mode. -Currently ignored. -.It Ic \&ne Op Ar height -Declare the need for the specified minimum vertical space -before the next trap or the bottom of the page. -Currently ignored. -.It Ic \&nf -Switch to no-fill mode. -See -.Xr man 7 . -Ignored by -.Xr mdoc 7 . -.It Ic \&nh -Turn off automatic hyphenation mode. -Currently ignored. -.It Ic \&nhychar Ar char ... -Define hyphenation-inhibiting characters. -This is a Heirloom extension and currently ignored. -.It Ic \&nm Op Ar start Op Ar inc Op Ar space Op Ar indent -Print line numbers. -Currently unsupported. -.It Ic \&nn Op Ar number -Temporarily turn off line numbering. -Currently unsupported. -.It Ic \&nop Ar body -Execute the rest of the input line as a request or macro line. -Currently unsupported. -.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression -Define or change a register. -A register is an arbitrary string value that defines some sort of state, -which influences parsing and/or formatting. -For the syntax of -.Ar expression , -see -.Sx Numerical expressions -below. -If it is prefixed by a sign, the register will be -incremented or decremented instead of assigned to. -.Pp -The following -.Ar register -is handled specially: -.Bl -tag -width Ds -.It Cm nS -If set to a positive integer value, certain -.Xr mdoc 7 -macros will behave in the same way as in the -.Em SYNOPSIS -section. -If set to 0, these macros will behave in the same way as outside the -.Em SYNOPSIS -section, even when called within the -.Em SYNOPSIS -section itself. -Note that starting a new -.Xr mdoc 7 -section with the -.Ic \&Sh -macro will reset this register. -.El -.It Xo -.Ic \&nrf Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression -.Op Ar increment -.Xc -Define or change a floating-point register. -This is a Heirloom extension and currently unsupported. -.It Ic \&nroff -Force nroff mode. -This is a groff extension and currently ignored. -.It Ic \&ns -Turn on no-space mode. -Currently ignored. -.It Ic \&nx Op Ar filename -Abort processing of the current input file and process another one. -Ignored because insecure. -.It Ic \&open Ar stream file -Open a file for writing. -Ignored because insecure. -.It Ic \&opena Ar stream file -Open a file for appending. -Ignored because insecure. -.It Ic \&os -Output saved vertical space. -Currently ignored. -.It Ic \&output Ar string -Output directly to intermediate output. -Not supported. -.It Ic \&padj Op Cm 1 | 0 -Globally control paragraph-at-once adjustment. -This is a Heirloom extension and currently ignored. -.It Ic \&papersize Ar media -Set the paper size. -This is a Heirloom extension and currently ignored. -.It Ic \&pc Op Ar char -Change the page number character. -Currently ignored. -.It Ic \&pev -Print environments. -This is a groff extension and currently ignored. -.It Ic \&pi Ar command -Pipe output to a shell command. -Ignored because insecure. -.It Ic \&PI -Low-level request used by -.Ic \&BP . -This is a Heirloom extension and currently unsupported. -.It Ic \&pl Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height -Change page length. -Currently ignored. -.It Ic \&pm -Print names and sizes of macros, strings, and diversions -to standard error output. -Currently ignored. -.It Ic \&pn Oo Cm + Ns | Ns Cm - Oc Ns Ar number -Change the page number of the next page. -Currently ignored. -.It Ic \&pnr -Print all number registers on standard error output. -Currently ignored. -.It Ic \&po Op Oo Cm + Ns | Ns Cm - Oc Ns Ar offset -Set a horizontal page offset. -If no argument is specified, the page offset is reverted to its -previous value. -If a sign is specified, the new page offset is calculated relative -to the current one; otherwise, it is absolute. -The argument follows the syntax of -.Sx Scaling Widths -and the default scaling unit is -.Cm m . -.It Ic \&ps Op Oo Cm + Ns | Ns Cm - Oc Ns size -Change point size. -Currently ignored. -.It Ic \&psbb Ar filename -Retrieve the bounding box of a PostScript file. -Currently unsupported. -.It Ic \&pshape Ar indent length ... -Set a special shape for the current paragraph. -This is a Heirloom extension and currently unsupported. -.It Ic \&pso Ar command -Include output of a shell command. -Ignored because insecure. -.It Ic \&ptr -Print the names and positions of all traps on standard error output. -This is a groff extension and currently ignored. -.It Ic \&pvs Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height -Change post-vertical spacing. -This is a groff extension and currently ignored. -.It Ic \&rchar Ar glyph ... -Remove glyph definitions. -Currently unsupported. -.It Ic \&rd Op Ar prompt Op Ar agument ... -Read from standard input. -Currently ignored. -.It Ic \&recursionlimit Ar maxrec maxtail -Set the maximum stack depth for recursive macros. -This is a Heirloom extension and currently ignored. -.It Ic \&return Op Ar twice -Exit a macro and return to the caller. -Currently unsupported. -.It Ic \&rfschar Ar font glyph ... -Remove font-specific fallback glyph definitions. -Currently unsupported. -.It Ic \&rhang Ar font char ... afmunits -Hang characters at right margin. -This is a Heirloom extension and currently ignored. -.It Ic \&rj Op Ar N -Justify the next -.Ar N -input lines to the right margin without filling. -.Ar N -defaults to 1. -An argument of 0 or less ends right adjustment. -.It Ic \&rm Ar macroname -Remove a request, macro or string. -.It Ic \&rn Ar oldname newname -Rename a request, macro, diversion, or string. -In -.Xr mandoc 1 , -user-defined macros, -.Xr mdoc 7 -and -.Xr man 7 -macros, and user-defined strings can be renamed, but renaming of -predefined strings and of -.Nm -requests is not supported, and diversions are not implemented at all. -.It Ic \&rnn Ar oldname newname -Rename a number register. -Currently unsupported. -.It Ic \&rr Ar register -Remove a register. -.It Ic \&rs -End no-space mode. -Currently ignored. -.It Ic \&rt Op Ar dist -Return to marked vertical position. -Currently ignored. -.It Ic \&schar Ar glyph Op Ar string -Define global fallback glyph. -This is a groff extension and currently unsupported. -.It Ic \&sentchar Ar char ... -Define sentence-ending characters. -This is a Heirloom extension and currently ignored. -.It Ic \&shc Op Ar glyph -Change the soft hyphen character. -Currently ignored. -.It Ic \&shift Op Ar number -Shift macro arguments. -Currently unsupported. -.It Ic \&sizes Ar size ... -Define permissible point sizes. -This is a groff extension and currently ignored. -.It Ic \&so Ar filename -Include a source file. -The file is read and its contents processed as input in place of the -.Ic \&so -request line. -To avoid inadvertent inclusion of unrelated files, -.Xr mandoc 1 -only accepts relative paths not containing the strings -.Qq ../ -and -.Qq /.. . -.Pp -This request requires -.Xr man 1 -to change to the right directory before calling -.Xr mandoc 1 , -per convention to the root of the manual tree. -Typical usage looks like: -.Pp -.Dl \&.so man3/Xcursor.3 -.Pp -As the whole concept is rather fragile, the use of -.Ic \&so -is discouraged. -Use -.Xr ln 1 -instead. -.It Ic \&sp Op Ar height -Break the output line and emit vertical space. -The argument follows the syntax of -.Sx Scaling Widths -and defaults to one blank line -.Pq Li 1v . -.It Ic \&spacewidth Op Cm 1 | 0 -Set the space width from the font metrics file. -This is a Heirloom extension and currently ignored. -.It Ic \&special Op Ar font ... -Define a special font. -This is a groff extension and currently ignored. -.It Ic \&spreadwarn Op Ar width -Warn about wide spacing between words. -Currently ignored. -.It Ic \&ss Ar wordspace Op Ar sentencespace -Set space character size. -Currently ignored. -.It Ic \&sty Ar position style -Associate style with a font position. -This is a groff extension and currently ignored. -.It Ic \&substring Ar stringname startpos Op Ar endpos -Replace a user-defined string with a substring. -Currently unsupported. -.It Ic \&sv Op Ar height -Save vertical space. -Currently ignored. -.It Ic \&sy Ar command -Execute shell command. -Ignored because insecure. -.It Ic \&T& -Re-start a table layout, retaining the options of the prior table -invocation. -See -.Sx \&TS . -.It Ic \&ta Op Ar width ... Op Cm T Ar width ... -Set tab stops. -Each -.Ar width -argument follows the syntax of -.Sx Scaling Widths . -If prefixed by a plus sign, it is relative to the previous tab stop. -The arguments after the -.Cm T -marker are used repeatedly as often as needed; for each reuse, -they are taken relative to the last previously established tab stop. -When -.Ic \&ta -is called without arguments, all tab stops are cleared. -.It Ic \&tc Op Ar glyph -Change tab repetition character. -Currently unsupported. -.It Ic \&TE -End a table context. -See -.Sx \&TS . -.It Ic \&ti Oo Cm + Ns | Ns Cm - Oc Ns Ar width -Break the output line and indent the next output line by -.Ar width . -If a sign is specified, the temporary indentation is calculated -relative to the current indentation; otherwise, it is absolute. -The argument follows the syntax of -.Sx Scaling Widths -and the default scaling unit is -.Cm m . -.It Ic \&tkf Ar font minps width1 maxps width2 -Enable track kerning for a font. -Currently ignored. -.It Ic \&tl No \& Ap Ar left Ap Ar center Ap Ar right Ap -Print a title line. -Currently unsupported. -.It Ic \&tm Ar string -Print to standard error output. -Currently ignored. -.It Ic \&tm1 Ar string -Print to standard error output, allowing leading blanks. -This is a groff extension and currently ignored. -.It Ic \&tmc Ar string -Print to standard error output without a trailing newline. -This is a groff extension and currently ignored. -.It Ic \&tr Ar glyph glyph ... -Output character translation. -The first glyph in each pair is replaced by the second one. -Character escapes can be used; for example, -.Pp -.Dl tr \e(xx\e(yy -.Pp -replaces all invocations of \e(xx with \e(yy. -.It Ic \&track Ar font minps width1 maxps width2 -Static letter space tracking. -This is a Heirloom extension and currently ignored. -.It Ic \&transchar Ar char ... -Define transparent characters for sentence-ending. -This is a Heirloom extension and currently ignored. -.It Ic \&trf Ar filename -Output the contents of a file, disallowing invalid characters. -This is a groff extension and ignored because insecure. -.It Ic \&trimat Ar left top width height -Set the TrimBox page parameter for PDF generation. -This is a Heirloom extension and currently ignored. -.It Ic \&trin Ar glyph glyph ... -Output character translation, ignored by -.Ic \&asciify . -Currently unsupported. -.It Ic \&trnt Ar glyph glyph ... -Output character translation, ignored by \e!. -Currently unsupported. -.It Ic \&troff -Force troff mode. -This is a groff extension and currently ignored. -.It Ic \&TS -Begin a table, which formats input in aligned rows and columns. -See -.Xr tbl 7 -for a description of the tbl language. -.It Ic \&uf Ar font -Globally set the underline font. -Currently ignored. -.It Ic \&ul Op Ar N -Underline next -.Ar N -input lines. -Currently ignored. -.It Ic \&unformat Ar divname -Unformat spaces and tabs in a diversion. -Currently unsupported. -.It Ic \&unwatch Ar macroname -Disable notification for string or macro. -This is a Heirloom extension and currently ignored. -.It Ic \&unwatchn Ar register -Disable notification for register. -This is a Heirloom extension and currently ignored. -.It Ic \&vpt Op Cm 1 | 0 -Enable or disable vertical position traps. -This is a groff extension and currently ignored. -.It Ic \&vs Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height -Change vertical spacing. -Currently ignored. -.It Ic \&warn Ar flags -Set warning level. -Currently ignored. -.It Ic \&warnscale Ar si -Set the scaling indicator used in warnings. -This is a groff extension and currently ignored. -.It Ic \&watch Ar macroname -Notify on change of string or macro. -This is a Heirloom extension and currently ignored. -.It Ic \&watchlength Ar maxlength -On change, report the contents of macros and strings -up to the specified length. -This is a Heirloom extension and currently ignored. -.It Ic \&watchn Ar register -Notify on change of register. -This is a Heirloom extension and currently ignored. -.It Ic \&wh Ar dist Op Ar macroname -Set a page location trap. -Currently unsupported. -.It Ic \&while Ar condition body -Repeated execution while a condition is true. -Currently unsupported. -.It Ic \&write Oo \(dq Oc Ns Ar string -Write to an open file. -Ignored because insecure. -.It Ic \&writec Oo \(dq Oc Ns Ar string -Write to an open file without appending a newline. -Ignored because insecure. -.It Ic \&writem Ar macroname -Write macro or string to an open file. -Ignored because insecure. -.It Ic \&xflag Ar level -Set the extension level. -This is a Heirloom extension and currently ignored. -.El -.Ss Numerical expressions -The -.Sx \&nr , -.Sx \&if , -and -.Sx \&ie -requests accept integer numerical expressions as arguments. -These are always evaluated using the C -.Vt int -type; integer overflow works the same way as in the C language. -Numbers consist of an arbitrary number of digits -.Sq 0 -to -.Sq 9 -prefixed by an optional sign -.Sq + -or -.Sq - . -Each number may be followed by one optional scaling unit described below -.Sx Scaling Widths . -The following equations hold: -.Bd -literal -offset indent -1i = 6v = 6P = 10m = 10n = 72p = 1000M = 240u = 240 -254c = 100i = 24000u = 24000 -1f = 65536u = 65536 -.Ed -.Pp -The following binary operators are implemented. -Unless otherwise stated, they behave as in the C language: -.Pp -.Bl -tag -width 2n -compact -.It Ic + -addition -.It Ic - -subtraction -.It Ic * -multiplication -.It Ic / -division -.It Ic % -remainder of division -.It Ic < -less than -.It Ic > -greater than -.It Ic == -equal to -.It Ic = -equal to, same effect as -.Ic == -(this differs from C) -.It Ic <= -less than or equal to -.It Ic >= -greater than or equal to -.It Ic <> -not equal to (corresponds to C -.Ic != ; -this one is of limited portability, it is supported by Heirloom roff, -but not by groff) -.It Ic & -logical and (corresponds to C -.Ic && ) -.It Ic \&: -logical or (corresponds to C -.Ic || ) -.It Ic ? -maximum (not available in C) -.El -.Pp -There is no concept of precedence; evaluation proceeds from left to right, -except when subexpressions are enclosed in parentheses. -Inside parentheses, whitespace is ignored. -.Sh ESCAPE SEQUENCE REFERENCE -The -.Xr mandoc 1 -.Nm -parser recognises the following escape sequences. -Note that the -.Nm -language defines more escape sequences not implemented in -.Xr mandoc 1 . -In -.Xr mdoc 7 -and -.Xr man 7 -documents, using escape sequences is discouraged except for those -described in the -.Sx LANGUAGE SYNTAX -section above. -.Pp -A backslash followed by any character not listed here -simply prints that character itself. -.Ss \e -A backslash at the end of an input line can be used to continue the -logical input line on the next physical input line, joining the text -on both lines together as if it were on a single input line. -.Ss \e -The escape sequence backslash-space -.Pq Sq \e\ \& -is an unpaddable space-sized non-breaking space character; see -.Sx Whitespace . -.Ss \e\(dq -The rest of the input line is treated as -.Sx Comments . -.Ss \e% -Hyphenation allowed at this point of the word; ignored by -.Xr mandoc 1 . -.Ss \e& -Non-printing zero-width character; see -.Sx Whitespace . -.Ss \e\(aq -Acute accent special character; use -.Sq \e(aa -instead. -.Ss \e( Ns Ar cc -.Sx Special Characters -with two-letter names, see -.Xr mandoc_char 7 . -.Ss \e* Ns Bq Ar name -Interpolate the string with the -.Ar name ; -see -.Sx Predefined Strings -and -.Sx ds . -For short names, there are variants -.No \e* Ns Ar c -and -.No \e*( Ns Ar cc . -.Ss \e, -Left italic correction (groff extension); ignored by -.Xr mandoc 1 . -.Ss \e- -Special character -.Dq mathematical minus sign . -.Ss \e/ -Right italic correction (groff extension); ignored by -.Xr mandoc 1 . -.Ss \e Ns Bq Ar name -.Sx Special Characters -with names of arbitrary length, see -.Xr mandoc_char 7 . -.Ss \e^ -One-twelfth em half-narrow space character, effectively zero-width in -.Xr mandoc 1 . -.Ss \e` -Grave accent special character; use -.Sq \e(ga -instead. -.Ss \e{ -Begin conditional input; see -.Sx if . -.Ss \e\(ba -One-sixth em narrow space character, effectively zero-width in -.Xr mandoc 1 . -.Ss \e} -End conditional input; see -.Sx if . -.Ss \e~ -Paddable non-breaking space character. -.Ss \e0 -Digit width space character. -.Ss \eA\(aq Ns Ar string Ns \(aq -Anchor definition; ignored by -.Xr mandoc 1 . -.Ss \eB\(aq Ns Ar string Ns \(aq -Interpolate -.Sq 1 -if -.Ar string -conforms to the syntax of -.Sx Numerical expressions -explained above and -.Sq 0 -otherwise. -.Ss \eb\(aq Ns Ar string Ns \(aq -Bracket building function; ignored by -.Xr mandoc 1 . -.Ss \eC\(aq Ns Ar name Ns \(aq -.Sx Special Characters -with names of arbitrary length. -.Ss \ec -When encountered at the end of an input text line, -the next input text line is considered to continue that line, -even if there are request or macro lines in between. -No whitespace is inserted. -.Ss \eD\(aq Ns Ar string Ns \(aq -Draw graphics function; ignored by -.Xr mandoc 1 . -.Ss \ed -Move down by half a line; ignored by -.Xr mandoc 1 . -.Ss \ee -Backslash special character. -.Ss \eF Ns Bq Ar name -Switch font family (groff extension); ignored by -.Xr mandoc 1 . -For short names, there are variants -.No \eF Ns Ar c -and -.No \eF( Ns Ar cc . -.Ss \ef Ns Bq Ar name -Switch to the font -.Ar name , -see -.Sx Text Decoration . -For short names, there are variants -.No \ef Ns Ar c -and -.No \ef( Ns Ar cc . -.Ss \eg Ns Bq Ar name -Interpolate the format of a number register; ignored by -.Xr mandoc 1 . -For short names, there are variants -.No \eg Ns Ar c -and -.No \eg( Ns Ar cc . -.Ss \eH\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq -Set the height of the current font; ignored by -.Xr mandoc 1 . -.Ss \eh\(aq Ns Oo Cm \&| Oc Ns Ar width Ns \(aq -Horizontal motion. -If the vertical bar is given, the motion is relative to the current -indentation. -Otherwise, it is relative to the current position. -The default scaling unit is -.Cm m . -.Ss \ek Ns Bq Ar name -Mark horizontal input place in register; ignored by -.Xr mandoc 1 . -For short names, there are variants -.No \ek Ns Ar c -and -.No \ek( Ns Ar cc . -.Ss \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns \(aq -Vertical line drawing function; ignored by -.Xr mandoc 1 . -.Ss \el\(aq Ns Ar width Ns Oo Ar c Oc Ns \(aq -Draw a horizontal line of -.Ar width -using the glyph -.Ar c . -.Ss \eM Ns Bq Ar name -Set fill (background) color (groff extension); ignored by -.Xr mandoc 1 . -For short names, there are variants -.No \eM Ns Ar c -and -.No \eM( Ns Ar cc . -.Ss \em Ns Bq Ar name -Set glyph drawing color (groff extension); ignored by -.Xr mandoc 1 . -For short names, there are variants -.No \em Ns Ar c -and -.No \em( Ns Ar cc . -.Ss \eN\(aq Ns Ar number Ns \(aq -Character -.Ar number -on the current font. -.Ss \en Ns Bq Ar name -Interpolate the number register -.Ar name . -For short names, there are variants -.No \en Ns Ar c -and -.No \en( Ns Ar cc . -.Ss \eo\(aq Ns Ar string Ns \(aq -Overstrike, writing all the characters contained in the -.Ar string -to the same output position. -In terminal and HTML output modes, -only the last one of the characters is visible. -.Ss \ep -Break the output line at the end of the current word. -.Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq -Set number register; ignored by -.Xr mandoc 1 . -.Ss \eS\(aq Ns Ar number Ns \(aq -Slant output; ignored by -.Xr mandoc 1 . -.Ss \es\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq -Change point size; ignored by -.Xr mandoc 1 . -Alternative forms -.No \es Ns Oo +|- Oc Ns Ar n , -.No \es Ns Oo +|- Oc Ns \(aq Ns Ar number Ns \(aq , -.No \es Ns Bq Oo +|- Oc Ns Ar number , -and -.No \es Ns Oo +|- Oc Ns Bq Ar number -are also parsed and ignored. -.Ss \et -Horizontal tab; ignored by -.Xr mandoc 1 . -.Ss \eu -Move up by half a line; ignored by -.Xr mandoc 1 . -.Ss \eV Ns Bq Ar name -Interpolate an environment variable; ignored by -.Xr mandoc 1 . -For short names, there are variants -.No \eV Ns Ar c -and -.No \eV( Ns Ar cc . -.Ss \ev\(aq Ns Ar number Ns \(aq -Vertical motion; ignored by -.Xr mandoc 1 . -.Ss \ew\(aq Ns Ar string Ns \(aq -Interpolate the width of the -.Ar string . -The -.Xr mandoc 1 -implementation assumes that after expansion of user-defined strings, the -.Ar string -only contains normal characters, no escape sequences, and that each -character has a width of 24 basic units. -.Ss \eX\(aq Ns Ar string Ns \(aq -Output -.Ar string -as device control function; ignored in nroff mode and by -.Xr mandoc 1 . -.Ss \ex\(aq Ns Ar number Ns \(aq -Extra line space function; ignored by -.Xr mandoc 1 . -.Ss \eY Ns Bq Ar name -Output a string as a device control function; ignored in nroff mode and by -.Xr mandoc 1 . -For short names, there are variants -.No \eY Ns Ar c -and -.No \eY( Ns Ar cc . -.Ss \eZ\(aq Ns Ar string Ns \(aq -Print -.Ar string -with zero width and height; ignored by -.Xr mandoc 1 . -.Ss \ez -Output the next character without advancing the cursor position. -.Sh COMPATIBILITY -The -.Xr mandoc 1 -implementation of the -.Nm -language is intentionally incomplete. -Unimplemented features include: -.Pp -.Bl -dash -compact -.It -For security reasons, -.Xr mandoc 1 -never reads or writes external files except via -.Sx \&so -requests with safe relative paths. -.It -There is no automatic hyphenation, no adjustment to the right margin, -and no centering; the output is always set flush-left. -.It -Support for setting tabulator positions -and tabulator and leader characters is missing, -and support for manually changing indentation is limited. -.It -The -.Sq u -scaling unit is the default terminal unit. -In traditional troff systems, this unit changes depending on the -output media. -.It -Width measurements are implemented in a crude way -and often yield wrong results. -Explicit movement requests and escapes are ignored. -.It -There is no concept of output pages, no support for floats, -graphics drawing, and picture inclusion; -terminal output is always continuous. -.It -Requests regarding color, font families, and glyph manipulation -are ignored. -Font support is very limited. -Kerning is not implemented, and no ligatures are produced. -.It -The -.Qq \(aq -macro control character does not suppress output line breaks. -.It -Diversions are not implemented, -and support for traps is very incomplete. -.It -While recursion is supported, -.Sx \&while -loops are not. -.El -.Pp -The special semantics of the -.Cm nS -number register is an idiosyncracy of -.Ox -manuals and not supported by other -.Xr mdoc 7 -implementations. -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr eqn 7 , -.Xr man 7 , -.Xr mandoc_char 7 , -.Xr mdoc 7 , -.Xr tbl 7 -.Rs -.%A Joseph F. Ossanna -.%A Brian W. Kernighan -.%I AT&T Bell Laboratories -.%T Troff User's Manual -.%R Computing Science Technical Report -.%N 54 -.%C Murray Hill, New Jersey -.%D 1976 and 1992 -.%U http://www.kohala.com/start/troff/cstr54.ps -.Re -.Rs -.%A Joseph F. Ossanna -.%A Brian W. Kernighan -.%A Gunnar Ritter -.%T Heirloom Documentation Tools Nroff/Troff User's Manual -.%D September 17, 2007 -.%U http://heirloom.sourceforge.net/doctools/troff.pdf -.Re -.Sh HISTORY -The RUNOFF typesetting system, whose input forms the basis for -.Nm , -was written in MAD and FAP for the CTSS operating system by Jerome E. -Saltzer in 1964. -Doug McIlroy rewrote it in BCPL in 1969, renaming it -.Nm . -Dennis M. Ritchie rewrote McIlroy's -.Nm -in PDP-11 assembly for -.At v1 , -Joseph F. Ossanna improved roff and renamed it nroff -for -.At v2 , -then ported nroff to C as troff, which Brian W. Kernighan released with -.At v7 . -In 1989, James Clarke re-implemented troff in C++, naming it groff. -.Sh AUTHORS -.An -nosplit -This -.Nm -reference was written by -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv -and -.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: head/contrib/mdocml/roff.7 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/st.c =================================================================== --- head/contrib/mdocml/st.c (revision 338825) +++ head/contrib/mdocml/st.c (nonexistent) @@ -1,38 +0,0 @@ -/* $Id: st.c,v 1.14 2017/06/24 14:38:33 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_a2st(const char *p) -{ - -#include "st.in" - - return NULL; -} Property changes on: head/contrib/mdocml/st.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc_escape.3 =================================================================== --- head/contrib/mdocml/mandoc_escape.3 (revision 338825) +++ head/contrib/mdocml/mandoc_escape.3 (nonexistent) @@ -1,367 +0,0 @@ -.\" $Id: mandoc_escape.3,v 1.4 2017/07/04 23:40:01 schwarze Exp $ -.\" -.\" Copyright (c) 2014 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: July 4 2017 $ -.Dt MANDOC_ESCAPE 3 -.Os -.Sh NAME -.Nm mandoc_escape -.Nd parse roff escape sequences -.Sh SYNOPSIS -.In sys/types.h -.In mandoc.h -.Ft "enum mandoc_esc" -.Fo mandoc_escape -.Fa "const char **end" -.Fa "const char **start" -.Fa "int *sz" -.Fc -.Sh DESCRIPTION -This function scans a -.Xr roff 7 -escape sequence. -.Pp -An escape sequence consists of -.Bl -dash -compact -width 2n -.It -an initial backslash character -.Pq Sq \e , -.It -a single ASCII character called the escape sequence identifier, -.It -and, with only a few exceptions, an argument. -.El -.Pp -Arguments can be given in the following forms; some escape sequence -identifiers only accept some of these forms as specified below. -The first three forms are called the standard forms. -.Bl -tag -width 2n -.It \&In brackets: Ic \&[ Ns Ar argument Ns Ic \&] -The argument starts after the initial -.Sq \&[ , -ends before the final -.Sq \&] , -and the escape sequence ends with the final -.Sq \&] . -.It Two-character argument short form: Ic \&( Ns Ar ar -This form can only be used for arguments -consisting of exactly two characters. -It has the same effect as -.Ic \&[ Ns Ar ar Ns Ic \&] . -.It One-character argument short form: Ar a -This form can only be used for arguments -consisting of exactly one character. -It has the same effect as -.Ic \&[ Ns Ar a Ns Ic \&] . -.It Delimited form: Ar C Ns Ar argument Ns Ar C -The argument starts after the initial delimiter character -.Ar C , -ends before the next occurrence of the delimiter character -.Ar C , -and the escape sequence ends with that second -.Ar C . -Some escape sequences allow arbitrary characters -.Ar C -as quoting characters, some restrict the range of characters -that can be used as quoting characters. -.El -.Pp -Upon function entry, -.Fa end -is expected to point to the escape sequence identifier. -The values passed in as -.Fa start -and -.Fa sz -are ignored and overwritten. -.Pp -By design, this function cannot handle those -.Xr roff 7 -escape sequences that require in-place expansion, in particular -user-defined strings -.Ic \e* , -number registers -.Ic \en , -width measurements -.Ic \ew , -and numerical expression control -.Ic \eB . -These are handled by -.Fn roff_res , -a private preprocessor function called from -.Fn roff_parseln , -see the file -.Pa roff.c . -.Pp -The function -.Fn mandoc_escape -is used -.Bl -dash -compact -width 2n -.It -recursively by itself, because some escape sequence arguments can -in turn contain other escape sequences, -.It -for error detection internally by the -.Xr roff 7 -parser part of the -.Xr mandoc 3 -library, see the file -.Pa roff.c , -.It -above all externally by the -.Xr mandoc 1 -formatting modules, in particular -.Fl Tascii -and -.Fl Thtml , -for formatting purposes, see the files -.Pa term.c -and -.Pa html.c , -.It -and rarely externally by high-level utilities using the mandoc library, -for example -.Xr makewhatis 8 , -to purge escape sequences from text. -.El -.Sh RETURN VALUES -Upon function return, the pointer -.Fa end -is set to the character after the end of the escape sequence, -such that the calling higher-level parser can easily continue. -.Pp -For escape sequences taking an argument, the pointer -.Fa start -is set to the beginning of the argument and -.Fa sz -is set to the length of the argument. -For escape sequences not taking an argument, -.Fa start -is set to the character after the end of the sequence and -.Fa sz -is set to 0. -Both -.Fa start -and -.Fa sz -may be -.Dv NULL ; -in that case, the argument and the length are not returned. -.Pp -For sequences taking an argument, the function -.Fn mandoc_escape -returns one of the following values: -.Bl -tag -width 2n -.It Dv ESCAPE_FONT -The escape sequence -.Ic \ef -taking an argument in standard form: -.Ic \ef[ , \ef( , \ef Ns Ar a . -Two-character arguments starting with the character -.Sq C -are reduced to one-character arguments by skipping the -.Sq C . -More specific values are returned for the most commonly used arguments: -.Bl -column "argument" "ESCAPE_FONTITALIC" -.It argument Ta return value -.It Cm R No or Cm 1 Ta Dv ESCAPE_FONTROMAN -.It Cm I No or Cm 2 Ta Dv ESCAPE_FONTITALIC -.It Cm B No or Cm 3 Ta Dv ESCAPE_FONTBOLD -.It Cm P Ta Dv ESCAPE_FONTPREV -.It Cm BI Ta Dv ESCAPE_FONTBI -.El -.It Dv ESCAPE_SPECIAL -The escape sequence -.Ic \eC -taking an argument delimited with the single quote character -and, as a special exception, the escape sequences -.Em not -having an identifier, that is, those where the argument, in standard -form, directly follows the initial backslash: -.Ic \eC' , \e[ , \e( , \e Ns Ar a . -Note that the one-character argument short form can only be used for -argument characters that do not clash with escape sequence identifiers. -.Pp -If the argument matches one of the forms described below under -.Dv ESCAPE_UNICODE , -that value is returned instead. -.Pp -The -.Dv ESCAPE_SPECIAL -special character escape sequences can be rendered using the functions -.Fn mchars_spec2cp -and -.Fn mchars_spec2str -described in the -.Xr mchars_alloc 3 -manual. -.It Dv ESCAPE_UNICODE -Escape sequences of the same format as described above under -.Dv ESCAPE_SPECIAL , -but with an argument of the forms -.Ic u Ns Ar XXXX , -.Ic u Ns Ar YXXXX , -or -.Ic u10 Ns Ar XXXX -where -.Ar X -and -.Ar Y -are hexadecimal digits and -.Ar Y -is not zero: -.Ic \eC'u , \e[u . -As a special exception, -.Fa start -is set to the character after the -.Ic u , -and the -.Fa sz -return value does not include the -.Ic u -either. -.Pp -Such Unicode character escape sequences can be rendered using the function -.Fn mchars_num2uc -described in the -.Xr mchars_alloc 3 -manual. -.It Dv ESCAPE_NUMBERED -The escape sequence -.Ic \eN -followed by a delimited argument. -The delimiter character is arbitrary except that digits cannot be used. -If a digit is encountered instead of the opening delimiter, that -digit is considered to be the argument and the end of the sequence, and -.Dv ESCAPE_IGNORE -is returned. -.Pp -Such ASCII character escape sequences can be rendered using the function -.Fn mchars_num2char -described in the -.Xr mchars_alloc 3 -manual. -.It Dv ESCAPE_OVERSTRIKE -The escape sequence -.Ic \eo -followed by an argument delimited by an arbitrary character. -.It Dv ESCAPE_IGNORE -.Bl -bullet -width 2n -.It -The escape sequence -.Ic \es -followed by an argument in standard form or by an argument delimited -by the single quote character: -.Ic \es' , \es[ , \es( , \es Ns Ar a . -As a special exception, an optional -.Sq + -or -.Sq \- -character is allowed after the -.Sq s -for all forms. -.It -The escape sequences -.Ic \eF , -.Ic \eg , -.Ic \ek , -.Ic \eM , -.Ic \em , -.Ic \en , -.Ic \eV , -and -.Ic \eY -followed by an argument in standard form. -.It -The escape sequences -.Ic \eA , -.Ic \eb , -.Ic \eD , -.Ic \eR , -.Ic \eX , -and -.Ic \eZ -followed by an argument delimited by an arbitrary character. -.It -The escape sequences -.Ic \eH , -.Ic \eh , -.Ic \eL , -.Ic \el , -.Ic \eS , -.Ic \ev , -and -.Ic \ex -followed by an argument delimited by a character that cannot occur -in numerical expressions. -However, if any character that can occur in numerical expressions -is found instead of a delimiter, the sequence is considered to end -with that character, and -.Dv ESCAPE_ERROR -is returned. -.El -.It Dv ESCAPE_ERROR -Escape sequences taking an argument but not matching any of the above patterns. -In particular, that happens if the end of the logical input line -is reached before the end of the argument. -.El -.Pp -For sequences that do not take an argument, the function -.Fn mandoc_escape -returns one of the following values: -.Bl -tag -width 2n -.It Dv ESCAPE_SKIPCHAR -The escape sequence -.Qq \ez . -.It Dv ESCAPE_NOSPACE -The escape sequence -.Qq \ec . -.It Dv ESCAPE_IGNORE -The escape sequences -.Qq \ed -and -.Qq \eu . -.El -.Sh FILES -This function is implemented in -.Pa mandoc.c . -.Sh SEE ALSO -.Xr mchars_alloc 3 , -.Xr mandoc_char 7 , -.Xr roff 7 -.Sh HISTORY -This function has been available since mandoc 1.11.2. -.Sh AUTHORS -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv -.An Ingo Schwarze Aq Mt schwarze@openbsd.org -.Sh BUGS -The function doesn't cleanly distinguish between sequences that are -valid and supported, valid and ignored, valid and unsupported, -syntactically invalid, or undefined. -For sequences that are ignored or unsupported, it doesn't tell -whether that deficiency is likely to cause major formatting problems -and/or loss of document content. -The function is already rather complicated and still parses some -sequences incorrectly. -. -.ig -For these sequences, the list given below specifies a starting string -and either the length of the argument or an ending character. -The argument starts after the starting string. -In the former case, the sequence ends with the end of the argument. -In the latter case, the argument ends before the ending character, -and the sequence ends with the ending character. -.. Property changes on: head/contrib/mdocml/mandoc_escape.3 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_recallocarray.c =================================================================== --- head/contrib/mdocml/compat_recallocarray.c (revision 338825) +++ head/contrib/mdocml/compat_recallocarray.c (nonexistent) @@ -1,108 +0,0 @@ -#include "config.h" - -#if HAVE_RECALLOCARRAY - -int dummy; - -#else - -/* $Id: compat_recallocarray.c,v 1.1 2017/06/12 19:05:47 schwarze Exp $ */ -/* $OpenBSD: malloc.c,v 1.225 2017/05/13 07:11:29 otto Exp $ */ -/* - * Copyright (c) 2017 Otto Moerbeek - * - * 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 -#include -#include -#include -#include - -/* - * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX - * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW - */ -#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) - -/* - * Even though specified in POSIX, the PAGESIZE and PAGE_SIZE - * macros have very poor portability. Since we only use this - * to avoid free() overhead for small shrinking, simply pick - * an arbitrary number. - */ -#define MALLOC_PAGESIZE (1UL << 12) - - -void * -recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) -{ - size_t oldsize, newsize; - void *newptr; - - if (ptr == NULL) - return calloc(newnmemb, size); - - if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - newnmemb > 0 && SIZE_MAX / newnmemb < size) { - errno = ENOMEM; - return NULL; - } - newsize = newnmemb * size; - - if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { - errno = EINVAL; - return NULL; - } - oldsize = oldnmemb * size; - - /* - * Don't bother too much if we're shrinking just a bit, - * we do not shrink for series of small steps, oh well. - */ - if (newsize <= oldsize) { - size_t d = oldsize - newsize; - - if (d < oldsize / 2 && d < MALLOC_PAGESIZE) { - memset((char *)ptr + newsize, 0, d); - return ptr; - } - } - - newptr = malloc(newsize); - if (newptr == NULL) - return NULL; - - if (newsize > oldsize) { - memcpy(newptr, ptr, oldsize); - memset((char *)newptr + oldsize, 0, newsize - oldsize); - } else - memcpy(newptr, ptr, newsize); - - /* - * At this point, the OpenBSD implementation calls - * explicit_bzero() on the old memory before it is - * freed. Since explicit_bzero() is hard to implement - * portably and we don't handle confidential data in - * mandoc in the first place, simply free the memory - * without clearing it. - */ - - free(ptr); - - return newptr; -} - -#endif /* !HAVE_RECALLOCARRAY */ Property changes on: head/contrib/mdocml/compat_recallocarray.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-PATH_MAX.c =================================================================== --- head/contrib/mdocml/test-PATH_MAX.c (revision 338825) +++ head/contrib/mdocml/test-PATH_MAX.c (nonexistent) @@ -1,30 +0,0 @@ -/* - * POSIX allows PATH_MAX to not be defined, see - * http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html; - * the GNU Hurd is an example of a system not having it. - * - * Arguably, it would be better to test sysconf(_SC_PATH_MAX), - * but since the individual *.c files include "config.h" before - * , overriding an excessive value of PATH_MAX from - * "config.h" is impossible anyway, so for now, the simplest - * fix is to provide a value only on systems not having any. - * So far, we encountered no system defining PATH_MAX to an - * impractically large value, even though POSIX explicitly - * allows that. - * - * The real fix would be to replace all static buffers of size - * PATH_MAX by dynamically allocated buffers. But that is - * somewhat intrusive because it touches several files and - * because it requires changing struct mlink in mandocdb.c. - * So i'm postponing that for now. - */ - -#include -#include - -int -main(void) -{ - printf("PATH_MAX is defined to be %ld\n", (long)PATH_MAX); - return 0; -} Property changes on: head/contrib/mdocml/test-PATH_MAX.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-ntohl.c =================================================================== --- head/contrib/mdocml/test-ntohl.c (revision 338825) +++ head/contrib/mdocml/test-ntohl.c (nonexistent) @@ -1,7 +0,0 @@ -#include - -int -main(void) -{ - return htonl(ntohl(0x3a7d0cdb)) != 0x3a7d0cdb; -} Property changes on: head/contrib/mdocml/test-ntohl.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_reallocarray.c =================================================================== --- head/contrib/mdocml/compat_reallocarray.c (revision 338825) +++ head/contrib/mdocml/compat_reallocarray.c (nonexistent) @@ -1,49 +0,0 @@ -#include "config.h" - -#if HAVE_REALLOCARRAY - -int dummy; - -#else - -/* $Id: compat_reallocarray.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $ */ -/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */ -/* - * Copyright (c) 2008 Otto Moerbeek - * - * 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 -#include -#include -#include - -/* - * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX - * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW - */ -#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) - -void * -reallocarray(void *optr, size_t nmemb, size_t size) -{ - if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - nmemb > 0 && SIZE_MAX / nmemb < size) { - errno = ENOMEM; - return NULL; - } - return realloc(optr, size * nmemb); -} - -#endif /*!HAVE_REALLOCARRAY*/ Property changes on: head/contrib/mdocml/compat_reallocarray.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/libman.h =================================================================== --- head/contrib/mdocml/libman.h (revision 338825) +++ head/contrib/mdocml/libman.h (nonexistent) @@ -1,40 +0,0 @@ -/* $Id: libman.h,v 1.81 2017/04/29 12:45:41 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2014, 2015 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 MACRO_PROT_ARGS struct roff_man *man, \ - enum roff_tok tok, \ - int line, \ - int ppos, \ - int *pos, \ - char *buf - -struct man_macro { - void (*fp)(MACRO_PROT_ARGS); - int flags; -#define MAN_SCOPED (1 << 0) /* Optional next-line scope. */ -#define MAN_NSCOPED (1 << 1) /* Allowed in next-line element scope. */ -#define MAN_BSCOPE (1 << 2) /* Break next-line block scope. */ -#define MAN_JOIN (1 << 3) /* Join arguments together. */ -}; - -extern const struct man_macro *const man_macros; - - -void man_node_validate(struct roff_man *); -void man_state(struct roff_man *, struct roff_node *); -void man_unscope(struct roff_man *, const struct roff_node *); Property changes on: head/contrib/mdocml/libman.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/catman.8 =================================================================== --- head/contrib/mdocml/catman.8 (revision 338825) +++ head/contrib/mdocml/catman.8 (nonexistent) @@ -1,186 +0,0 @@ -.\" $Id: catman.8,v 1.8 2017/03/18 19:56: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: March 18 2017 $ -.Dt CATMAN 8 -.Os -.Sh NAME -.Nm catman -.Nd format all manual pages below a directory -.Sh SYNOPSIS -.Nm catman -.Op Fl I Cm os Ns = Ns Ar name -.Op Fl T Ar output -.Ar srcdir dstdir -.Sh DESCRIPTION -The -.Nm -utility assumes that all files below -.Ar srcdir -are manual pages in -.Xr mdoc 7 -and -.Xr man 7 -format and formats all of them, storing the formatted versions in -the same relative paths below -.Ar dstdir . -Subdirectories of -.Ar dstdir -are created as needed. -Existing files are not explicitly deleted, but possibly overwritten. -.Pp -The options are as follows: -.Bl -tag -width Ds -.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. -.It Fl T Ar output -Output format. -The -.Ar output -argument can be -.Cm ascii , -.Cm utf8 , -or -.Cm html ; -see -.Xr mandoc 1 . -In -.Cm html -output mode, the -.Cm fragment -output option is implied. -Other output options are not supported. -.El -.Sh IMPLEMENTATION NOTES -Since this version avoids -.Xr fork 2 -and -.Xr exec 3 -overhead and uses the much faster -.Sy mandoc -parsers and formatters rather than -.Sy groff , -it may be about one order of magnitude faster than other -.Nm -implementations. -.Sh EXIT STATUS -.Ex -std -.Pp -Possible errors include: -.Bl -bullet -.It -missing, invalid, or excessive command line arguments -.It -failure to change the current working directory to -.Ar srcdir -.It -failure to open -.Ar dstdir -.It -communication failure with -.Xr mandocd 8 -.It -resource exhaustion, for example file descriptor, process table, -or memory exhaustion -.El -.Pp -Except for memory exhaustion and similar system-level failures, -failures while trying to open, read, parse, or format individual -manual pages, to save individual formatted files to the file system, -or even to create directories do not cause -.Nm -to return an error exit status. -In such cases, -.Nm -will simply continue with the next file or subdirectory. -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr mandocd 8 -.Sh HISTORY -A -.Nm -utility first appeared in -.Fx 1.0 . -Other, incompatible implementations appeared in -.Nx 1.0 -and in -.Sy man-db No 2.2 . -.Pp -This version appeared in version 1.14.1 of the -.Sy mandoc -toolkit. -.Sh AUTHORS -.An -nosplit -The first -.Nm -implementation was a short shell script by -.An Christoph Robitschko -in July 1993. -.Pp -The -.Nx -implementations were written by -.An J. T. Conklin Aq Mt jtc@netbsd.org -in 1993, -.An Christian E. Hopps Aq Mt chopps@netbsd.org -in 1994, -and -.An Dante Profeta Aq Mt dante@netbsd.org -in 1999; the -.Sy man-db -implementation by -.An Graeme W. Wilford -in 1994; and the -.Fx -implementations by -.An Wolfram Schneider Aq Mt wosch@freebsd.org -in 1995 and -.An John Rochester Aq Mt john@jrochester.org -in 2002. -.Pp -The concept of the present version was designed and implemented by -.An Michael Stapelberg Aq Mt stapelberg@debian.org -in 2017. -Option and argument handling and directory iteration was added by -.An Ingo Schwarze Aq Mt schwarze@openbsd.org . -.Sh CAVEATS -All versions of -.Nm -are incompatible with each other because each caters to the needs -of a specific operating system, for example regarding directory -structures and file naming conventions. -.Pp -This version is more flexible than the others in so far as it does -not assume any particular directory structure or naming convention. -That flexibility comes at the price of not being able to change the -names and relative paths of the source files when reusing them to -store the formatted files, of not supporting any configuration file -formats or environment variables, and of being unable to scan for -and remove junk files in -.Ar dstdir . -.Pp -Currently, -.Nm -always reformats each page, even if the formatted version is newer -than the source version. Property changes on: head/contrib/mdocml/catman.8 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-ohash.c =================================================================== --- head/contrib/mdocml/test-ohash.c (revision 338825) +++ head/contrib/mdocml/test-ohash.c (nonexistent) @@ -1,39 +0,0 @@ -#include -#include -#include -#include - -static void *xmalloc(size_t, void *); -static void *xcalloc(size_t, size_t, void *); -static void xfree(void *, void *); - - -static void * -xmalloc(size_t sz, void *arg) { - return calloc(1,sz); -} - -static void * -xcalloc(size_t nmemb, size_t sz, void *arg) -{ - return calloc(nmemb,sz); -} - -static void -xfree(void *p, void *arg) -{ - free(p); -} - -int -main(void) -{ - struct ohash h; - struct ohash_info i; - i.alloc = xmalloc; - i.calloc = xcalloc; - i.free = xfree; - ohash_init(&h, 2, &i); - ohash_delete(&h); - return 0; -} Property changes on: head/contrib/mdocml/test-ohash.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tbl_html.c =================================================================== --- head/contrib/mdocml/tbl_html.c (revision 338825) +++ head/contrib/mdocml/tbl_html.c (nonexistent) @@ -1,161 +0,0 @@ -/* $Id: tbl_html.c,v 1.23 2017/07/31 16:14:10 schwarze Exp $ */ -/* - * Copyright (c) 2011 Kristaps Dzonsons - * 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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include - -#include "mandoc.h" -#include "out.h" -#include "html.h" - -static void html_tblopen(struct html *, const struct tbl_span *); -static size_t html_tbl_len(size_t, void *); -static size_t html_tbl_strlen(const char *, void *); -static size_t html_tbl_sulen(const struct roffsu *, void *); - - -static size_t -html_tbl_len(size_t sz, void *arg) -{ - return sz; -} - -static size_t -html_tbl_strlen(const char *p, void *arg) -{ - return strlen(p); -} - -static size_t -html_tbl_sulen(const struct roffsu *su, void *arg) -{ - if (su->scale < 0.0) - return 0; - - switch (su->unit) { - case SCALE_FS: /* 2^16 basic units */ - return su->scale * 65536.0 / 24.0; - case SCALE_IN: /* 10 characters per inch */ - return su->scale * 10.0; - case SCALE_CM: /* 2.54 cm per inch */ - return su->scale * 10.0 / 2.54; - case SCALE_PC: /* 6 pica per inch */ - case SCALE_VS: - return su->scale * 10.0 / 6.0; - case SCALE_EN: - case SCALE_EM: - return su->scale; - case SCALE_PT: /* 12 points per pica */ - return su->scale * 10.0 / 6.0 / 12.0; - case SCALE_BU: /* 24 basic units per character */ - return su->scale / 24.0; - case SCALE_MM: /* 1/1000 inch */ - return su->scale / 100.0; - default: - abort(); - } -} - -static void -html_tblopen(struct html *h, const struct tbl_span *sp) -{ - struct tag *t; - int ic; - - if (h->tbl.cols == NULL) { - h->tbl.len = html_tbl_len; - h->tbl.slen = html_tbl_strlen; - h->tbl.sulen = html_tbl_sulen; - tblcalc(&h->tbl, sp, 0, 0); - } - - assert(NULL == h->tblt); - h->tblt = print_otag(h, TAG_TABLE, "c", "tbl"); - - t = print_otag(h, TAG_COLGROUP, ""); - for (ic = 0; ic < sp->opts->cols; ic++) - print_otag(h, TAG_COL, "shw", h->tbl.cols[ic].width); - print_tagq(h, t); -} - -void -print_tblclose(struct html *h) -{ - - assert(h->tblt); - print_tagq(h, h->tblt); - h->tblt = NULL; -} - -void -print_tbl(struct html *h, const struct tbl_span *sp) -{ - const struct tbl_dat *dp; - struct tag *tt; - int ic; - - /* Inhibit printing of spaces: we do padding ourselves. */ - - if (h->tblt == NULL) - html_tblopen(h, sp); - - assert(h->tblt); - - h->flags |= HTML_NONOSPACE; - h->flags |= HTML_NOSPACE; - - tt = print_otag(h, TAG_TR, ""); - - switch (sp->pos) { - case TBL_SPAN_HORIZ: - case TBL_SPAN_DHORIZ: - print_otag(h, TAG_TD, "?", "colspan", "0"); - break; - default: - dp = sp->first; - for (ic = 0; ic < sp->opts->cols; ic++) { - print_stagq(h, tt); - print_otag(h, TAG_TD, ""); - - if (dp == NULL || dp->layout->col > ic) - continue; - if (dp->layout->pos != TBL_CELL_DOWN) - if (dp->string != NULL) - print_text(h, dp->string); - dp = dp->next; - } - break; - } - - print_tagq(h, tt); - - h->flags &= ~HTML_NONOSPACE; - - if (sp->next == NULL) { - assert(h->tbl.cols); - free(h->tbl.cols); - h->tbl.cols = NULL; - print_tblclose(h); - } - -} Property changes on: head/contrib/mdocml/tbl_html.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/config.h =================================================================== --- head/contrib/mdocml/config.h (revision 338825) +++ head/contrib/mdocml/config.h (nonexistent) @@ -1,55 +0,0 @@ -#ifdef __cplusplus -#error "Do not use C++. See the INSTALL file." -#endif - -#if !defined(__GNUC__) || (__GNUC__ < 4) -#define __attribute__(x) -#endif - -#if defined(__linux__) || defined(__MINT__) -#define _GNU_SOURCE /* See test-*.c what needs this. */ -#endif - -#include - -#define MAN_CONF_FILE "/etc/man.conf" -#define MANPATH_BASE "/usr/share/man" -#define MANPATH_DEFAULT "/usr/share/man:/usr/local/man" -#define UTF8_LOCALE "en_US.UTF-8" -#define HAVE_CMSG_XPG42 0 -#define HAVE_DIRENT_NAMLEN 1 -#define HAVE_ENDIAN 0 -#define HAVE_ERR 1 -#define HAVE_FTS 1 -#define HAVE_FTS_COMPARE_CONST 1 -#define HAVE_GETLINE 1 -#define HAVE_GETSUBOPT 1 -#define HAVE_ISBLANK 1 -#define HAVE_MKDTEMP 1 -#define HAVE_NTOHL 1 -#define HAVE_PLEDGE 0 -#define HAVE_PROGNAME 1 -#define HAVE_REALLOCARRAY 1 -#define HAVE_RECALLOCARRAY 0 -#define HAVE_REWB_BSD 1 -#define HAVE_REWB_SYSV 1 -#define HAVE_SANDBOX_INIT 0 -#define HAVE_STRCASESTR 1 -#define HAVE_STRINGLIST 1 -#define HAVE_STRLCAT 1 -#define HAVE_STRLCPY 1 -#define HAVE_STRPTIME 1 -#define HAVE_STRSEP 1 -#define HAVE_STRTONUM 1 -#define HAVE_SYS_ENDIAN 1 -#define HAVE_VASPRINTF 1 -#define HAVE_WCHAR 1 -#define HAVE_OHASH 1 - -#define BINM_APROPOS "apropos" -#define BINM_MAKEWHATIS "makewhatis" -#define BINM_MAN "man" -#define BINM_SOELIM "soelim" -#define BINM_WHATIS "whatis" - -extern void *recallocarray(void *, size_t, size_t, size_t); Property changes on: head/contrib/mdocml/config.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_ohash.c =================================================================== --- head/contrib/mdocml/compat_ohash.c (revision 338825) +++ head/contrib/mdocml/compat_ohash.c (nonexistent) @@ -1,339 +0,0 @@ -#include "config.h" - -#if HAVE_OHASH - -int dummy; - -#else - -/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * 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 - -#include -#include -#include -#include -#include -#include "compat_ohash.h" - -struct _ohash_record { - uint32_t hv; - const char *p; -}; - -#define DELETED ((const char *)h) -#define NONE (h->size) - -/* Don't bother changing the hash table if the change is small enough. */ -#define MINSIZE (1UL << 4) -#define MINDELETED 4 - -static void ohash_resize(struct ohash *); - - -/* This handles the common case of variable length keys, where the - * key is stored at the end of the record. - */ -void * -ohash_create_entry(struct ohash_info *i, const char *start, const char **end) -{ - char *p; - - if (!*end) - *end = start + strlen(start); - p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); - if (p) { - memcpy(p+i->key_offset, start, *end-start); - p[i->key_offset + (*end - start)] = '\0'; - } - return (void *)p; -} - -/* hash_delete only frees the hash structure. Use hash_first/hash_next - * to free entries as well. */ -void -ohash_delete(struct ohash *h) -{ - (h->info.free)(h->t, h->info.data); -#ifndef NDEBUG - h->t = NULL; -#endif -} - -static void -ohash_resize(struct ohash *h) -{ - struct _ohash_record *n; - size_t ns; - unsigned int j; - unsigned int i, incr; - - if (4 * h->deleted < h->total) { - if (h->size >= (UINT_MAX >> 1U)) - ns = UINT_MAX; - else - ns = h->size << 1U; - } else if (3 * h->deleted > 2 * h->total) - ns = h->size >> 1U; - else - ns = h->size; - if (ns < MINSIZE) - ns = MINSIZE; -#ifdef STATS_HASH - STAT_HASH_EXPAND++; - STAT_HASH_SIZE += ns - h->size; -#endif - - n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data); - if (!n) - return; - - for (j = 0; j < h->size; j++) { - if (h->t[j].p != NULL && h->t[j].p != DELETED) { - i = h->t[j].hv % ns; - incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1; - while (n[i].p != NULL) { - i += incr; - if (i >= ns) - i -= ns; - } - n[i].hv = h->t[j].hv; - n[i].p = h->t[j].p; - } - } - (h->info.free)(h->t, h->info.data); - h->t = n; - h->size = ns; - h->total -= h->deleted; - h->deleted = 0; -} - -void * -ohash_remove(struct ohash *h, unsigned int i) -{ - void *result = (void *)h->t[i].p; - - if (result == NULL || result == DELETED) - return NULL; - -#ifdef STATS_HASH - STAT_HASH_ENTRIES--; -#endif - h->t[i].p = DELETED; - h->deleted++; - if (h->deleted >= MINDELETED && 4 * h->deleted > h->total) - ohash_resize(h); - return result; -} - -void * -ohash_find(struct ohash *h, unsigned int i) -{ - if (h->t[i].p == DELETED) - return NULL; - else - return (void *)h->t[i].p; -} - -void * -ohash_insert(struct ohash *h, unsigned int i, void *p) -{ -#ifdef STATS_HASH - STAT_HASH_ENTRIES++; -#endif - if (h->t[i].p == DELETED) { - h->deleted--; - h->t[i].p = p; - } else { - h->t[i].p = p; - /* Arbitrary resize boundary. Tweak if not efficient enough. */ - if (++h->total * 4 > h->size * 3) - ohash_resize(h); - } - return p; -} - -unsigned int -ohash_entries(struct ohash *h) -{ - return h->total - h->deleted; -} - -void * -ohash_first(struct ohash *h, unsigned int *pos) -{ - *pos = 0; - return ohash_next(h, pos); -} - -void * -ohash_next(struct ohash *h, unsigned int *pos) -{ - for (; *pos < h->size; (*pos)++) - if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) - return (void *)h->t[(*pos)++].p; - return NULL; -} - -void -ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) -{ - h->size = 1UL << size; - if (h->size < MINSIZE) - h->size = MINSIZE; -#ifdef STATS_HASH - STAT_HASH_CREATION++; - STAT_HASH_SIZE += h->size; -#endif - /* Copy info so that caller may free it. */ - h->info.key_offset = info->key_offset; - h->info.calloc = info->calloc; - h->info.free = info->free; - h->info.alloc = info->alloc; - h->info.data = info->data; - h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record), - h->info.data); - h->total = h->deleted = 0; -} - -uint32_t -ohash_interval(const char *s, const char **e) -{ - uint32_t k; - - if (!*e) - *e = s + strlen(s); - if (s == *e) - k = 0; - else - k = *s++; - while (s != *e) - k = ((k << 2) | (k >> 30)) ^ *s++; - return k; -} - -unsigned int -ohash_lookup_interval(struct ohash *h, const char *start, const char *end, - uint32_t hv) -{ - unsigned int i, incr; - unsigned int empty; - -#ifdef STATS_HASH - STAT_HASH_LOOKUP++; -#endif - empty = NONE; - i = hv % h->size; - incr = ((hv % (h->size-2)) & ~1) + 1; - while (h->t[i].p != NULL) { -#ifdef STATS_HASH - STAT_HASH_LENGTH++; -#endif - if (h->t[i].p == DELETED) { - if (empty == NONE) - empty = i; - } else if (h->t[i].hv == hv && - strncmp(h->t[i].p+h->info.key_offset, start, - end - start) == 0 && - (h->t[i].p+h->info.key_offset)[end-start] == '\0') { - if (empty != NONE) { - h->t[empty].hv = hv; - h->t[empty].p = h->t[i].p; - h->t[i].p = DELETED; - return empty; - } else { -#ifdef STATS_HASH - STAT_HASH_POSITIVE++; -#endif - return i; - } - } - i += incr; - if (i >= h->size) - i -= h->size; - } - - /* Found an empty position. */ - if (empty != NONE) - i = empty; - h->t[i].hv = hv; - return i; -} - -unsigned int -ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv) -{ - unsigned int i, incr; - unsigned int empty; - -#ifdef STATS_HASH - STAT_HASH_LOOKUP++; -#endif - empty = NONE; - i = hv % h->size; - incr = ((hv % (h->size-2)) & ~1) + 1; - while (h->t[i].p != NULL) { -#ifdef STATS_HASH - STAT_HASH_LENGTH++; -#endif - if (h->t[i].p == DELETED) { - if (empty == NONE) - empty = i; - } else if (h->t[i].hv == hv && - memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { - if (empty != NONE) { - h->t[empty].hv = hv; - h->t[empty].p = h->t[i].p; - h->t[i].p = DELETED; - return empty; - } else { -#ifdef STATS_HASH - STAT_HASH_POSITIVE++; -#endif - } return i; - } - i += incr; - if (i >= h->size) - i -= h->size; - } - - /* Found an empty position. */ - if (empty != NONE) - i = empty; - h->t[i].hv = hv; - return i; -} - -unsigned int -ohash_qlookup(struct ohash *h, const char *s) -{ - const char *e = NULL; - return ohash_qlookupi(h, s, &e); -} - -unsigned int -ohash_qlookupi(struct ohash *h, const char *s, const char **e) -{ - uint32_t hv; - - hv = ohash_interval(s, e); - return ohash_lookup_interval(h, s, *e, hv); -} - -#endif /*!HAVE_OHASH*/ Property changes on: head/contrib/mdocml/compat_ohash.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tbl.3 =================================================================== --- head/contrib/mdocml/tbl.3 (revision 338825) +++ head/contrib/mdocml/tbl.3 (nonexistent) @@ -1,354 +0,0 @@ -.\" $Id: tbl.3,v 1.2 2015/01/30 04:11:50 schwarze Exp $ -.\" -.\" Copyright (c) 2013 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: January 30 2015 $ -.Dt TBL 3 -.Os -.Sh NAME -.Nm tbl_alloc , -.Nm tbl_read , -.Nm tbl_restart , -.Nm tbl_span , -.Nm tbl_end , -.Nm tbl_free -.Nd roff table parser library for mandoc -.Sh SYNOPSIS -.In mandoc.h -.In libmandoc.h -.In libroff.h -.Ft struct tbl_node * -.Fo tbl_alloc -.Fa "int pos" -.Fa "int line" -.Fa "struct mparse *parse" -.Fc -.Ft enum rofferr -.Fo tbl_read -.Fa "struct tbl_node *tbl" -.Fa "int ln" -.Fa "const char *p" -.Fa "int offs" -.Fc -.Ft void -.Fo tbl_restart -.Fa "int line" -.Fa "int pos" -.Fa "struct tbl_node *tbl" -.Fc -.Ft const struct tbl_span * -.Fo tbl_span -.Fa "struct tbl_node *tbl" -.Fc -.Ft void -.Fo tbl_end -.Fa "struct tbl_node **tblp" -.Fc -.Ft void -.Fo tbl_free -.Fa "struct tbl_node *tbl" -.Fc -.Sh DESCRIPTION -This library is tightly integrated into the -.Xr mandoc 1 -utility and not designed for stand-alone use. -The present manual is intended as a reference for developers working on -.Xr mandoc 1 . -.Ss Data structures -Unless otherwise noted, all of the following data structures are defined in -.In mandoc.h -and are deleted in -.Fn tbl_free . -.Bl -tag -width Ds -.It Vt struct tbl_node -This structure describes a complete table. -It is defined in -.In libroff.h , -created in -.Fn tbl_alloc , -and stored in the members -.Fa first_tbl , -.Fa last_tbl , -and -.Fa tbl -of -.Vt struct roff Bq Pa roff.c . -.Pp -The -.Fa first_span , -.Fa current_span , -.Fa last_span , -and -.Fa next -members may be -.Dv NULL . -The -.Fa first_row -and -.Fa last_row -members may be -.Dv NULL , -but if there is a span, the function -.Fn tbl_layout -guarantees that these pointers are not -.Dv NULL . -The function -.Fn tbl_alloc -guarantees that the -.Fa parse -member is not -.Dv NULL . -.It Vt struct tbl_opts -This structure describes the options of one table. -It is used as a substructure of -.Vt struct tbl_node -and thus created and deleted together with it. -It is filled in -.Fn tbl_options . -.It Vt struct tbl_row -This structure describes one layout line in a table -by maintaining a list of all the cells in that line. -It is allocated and filled in -.Fn row Bq Pa tbl_layout.c -and referenced from the -.Fa layout -member of -.Vt struct tbl_node . -.Pp -The -.Fa next -member may be -.Dv NULL . -The function -.Fn tbl_layout -guarantees that the -.Fa first -and -.Fa last -members are not NULL. -.It Vt struct tbl_cell -This structure describes one layout cell in a table, -in particular its alignment, membership in spans, and -usage for lines. -It is allocated and filled in -.Fn cell_alloc Bq Pa tbl_layout.c -and referenced from the -.Fa first -and -.Fa last -members of -.Vt struct tbl_row . -.Pp -The -.Fa next -member may be -.Dv NULL . -.It Vt struct tbl_span -This structure describes one data line in a table -by maintaining a list of all data cells in that line -or by specifying that it is a horizontal line. -It is allocated and filled in -.Fn newspan Bq Pa tbl_data.c -which is called from -.Fn tbl_data -and referenced from the -.Fa first_span , -.Fa current_span , -and -.Fa last_span -members of -.Vt struct tbl_node , -and from the -.Fa span -members of -.Vt struct man_node -and -.Vt struct mdoc_node -from -.In man.h -and -.In mdoc.h . -.Pp -The -.Fa first , -.Fa last , -.Fa prev , -and -.Fa next -members may be -.Dv NULL . -The function -.Fn newspan Bq Pa tbl_data.c -guarantees that the -.Fa opts -and -.Fa layout -members are not -.Dv NULL . -.It Vt struct tbl_dat -This structure describes one data cell in a table by specifying -whether it contains a line or data, whether it spans additional -layout cells, and by storing the data. -It is allocated and filled in -.Fn tbl_data -and referenced from the -.Fa first -and -.Fa last -members of -.Vt struct tbl_span . -.Pp -The -.Fa string -and -.Fa next -members may be -.Dv NULL . -The function -.Fn getdata -guarantees that the -.Fa layout -member is not -.Dv NULL . -.El -.Ss Interface functions -The following functions are implemented in -.Pa tbl.c , -and all callers in -.Pa roff.c . -.Bl -tag -width Ds -.It Fn tbl_alloc -Allocates, initializes, and returns a new -.Vt struct tbl_node . -Called from -.Fn roff_TS . -.It Fn tbl_read -Dispatches to -.Fn tbl_option , -.Fn tbl_layout , -.Fn tbl_cdata , -and -.Fn tbl_data , -see below. -Called from -.Fn roff_parseln . -.It Fn tbl_restart -Resets the -.Fa part -member of -.Vt struct tbl_node -to -.Dv TBL_PART_LAYOUT . -Called from -.Fn roff_T_ . -.It Fn tbl_span -On the first call, return the first -.Vt struct tbl_span ; -for later calls, return the next one or -.Dv NULL . -Called from -.Fn roff_span . -.It Fn tbl_end -Flags the last span as -.Dv TBL_SPAN_LAST -and clears the pointer passed as an argment. -Called from -.Fn roff_TE -and -.Fn roff_endparse . -.It Fn tbl_free -Frees the specified -.Vt struct tbl_node -and all the tbl_row, tbl_cell, tbl_span, and tbl_dat structures -referenced from it. -Called from -.Fn roff_free -and -.Fn roff_reset . -.El -.Ss Private functions -.Bl -tag -width Ds -.It Ft int Fn tbl_options "struct tbl_node *tbl" "int ln" "const char *p" -Parses the options line into -.Vt struct tbl_opts . -Implemented in -.Pa tbl_opts.c , -called from -.Fn tbl_read . -.It Ft int Fn tbl_layout "struct tbl_node *tbl" "int ln" "const char *p" -Allocates and fills one -.Vt struct tbl_row -for each layout line and one -.Vt struct tbl_cell -for each layout cell. -Implemented in -.Pa tbl_layout.c , -called from -.Fn tbl_read . -.It Ft int Fn tbl_data "struct tbl_node *tbl" "int ln" "const char *p" -Allocates one -.Vt struct tbl_span -for each data line and calls -.Fn getdata -for each data cell. -Implemented in -.Pa tbl_data.c , -called from -.Fn tbl_read . -.It Ft int Fn tbl_cdata "struct tbl_node *tbl" "int ln" "const char *p" -Continues parsing a data line: -When finding -.Sq T} , -switches back to -.Dv TBL_PART_DATA -mode and calls -.Fn getdata -if there are more data cells on the line. -Otherwise, appends the data to the current data cell. -Implemented in -.Pa tbl_data.c , -called from -.Fn tbl_read . -.It Xo -.Ft int -.Fo getdata -.Fa "struct tbl_node *tbl" -.Fa "struct tbl_span *dp" -.Fa "int ln" -.Fa "const char *p" -.Fa "int *pos" -.Fc -.Xc -Parses one data cell into one -.Vt struct tbl_dat . -Implemented in -.Pa tbl_data.c , -called from -.Fn tbl_data -and -.Fn tbl_cdata . -.El -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr mandoc 3 , -.Xr tbl 7 -.Sh AUTHORS -.An -nosplit -The -.Nm tbl -library was written by -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv -with contributions from -.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: head/contrib/mdocml/tbl.3 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mandocd.8 =================================================================== --- head/contrib/mdocml/mandocd.8 (revision 338825) +++ head/contrib/mdocml/mandocd.8 (nonexistent) @@ -1,198 +0,0 @@ -.\" $Id: mandocd.8,v 1.2 2017/03/18 19:56: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: March 18 2017 $ -.Dt MANDOCD 8 -.Os -.Sh NAME -.Nm mandocd -.Nd server process to format manual pages in batch mode -.Sh SYNOPSIS -.Nm mandocd -.Op Fl I Cm os Ns = Ns Ar name -.Op Fl T Ar output -.Ar socket_fd -.Sh DESCRIPTION -The -.Nm -utility formats many manual pages without requiring -.Xr fork 2 -and -.Xr exec 3 -overhead in between. -It does not require listing all the manuals to be formatted on the -command line, and it supports writing each formatted manual to its -own file descriptor. -.Pp -This server requires that a connected UNIX domain -.Xr socket 2 -is already present at -.Xr exec 3 -time. -Consequently, it cannot be started from the -.Xr sh 1 -command line because the shell cannot supply such a socket. -Typically, the socket is created by the parent process using -.Xr socketpair 2 -before calling -.Xr fork 2 -and -.Xr exec 3 -on -.Nm . -The parent process will pass the file descriptor number as an argument to -.Xr exec 3 , -formatted as a decimal ASCII-encoded integer. -See -.Xr catman 8 -for a typical implementation of a parent process. -.Pp -.Nm -loops reading one-byte messages with -.Xr recvmsg 2 -from the file descriptor number -.Ar socket_fd . -It ignores the byte read and only uses the out-of-band auxiliary -.Vt struct cmsghdr -control data, typically supplied by the calling process using -.Xr CMSG_FIRSTHDR 3 . -The parent process is expected to pass three file descriptors -with each dummy byte. -The first one is used for -.Xr mdoc 7 -or -.Xr man 7 -input, the second one for formatted output, and the third one -for error output. -.Pp -The options are as follows: -.Bl -tag -width Ds -.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. -.It Fl T Ar output -Output format. -The -.Ar output -argument can be -.Cm ascii , -.Cm utf8 , -or -.Cm html ; -see -.Xr mandoc 1 . -In -.Cm html -output mode, the -.Cm fragment -output option is implied. -Other output options are not supported. -.El -.Pp -After exhausting one input file descriptor, all three file descriptors -are closed before reading the next dummy byte and control message. -.Pp -When a zero-byte message is read, when the -.Ar socket_fd -is closed by the parent process, -or when an error occurs, -.Nm -exits. -.Sh EXIT STATUS -.Ex -std -.Pp -A zero-byte message or a closed -.Ar socket_fd -is considered success. -Possible errors include: -.Bl -bullet -.It -missing, invalid, or excessive -.Xr exec 3 -arguments -.It -.Xr recvmsg 2 -failure, for example due to -.Er EMSGSIZE -.It -missing or unexpected control data, in particular a -.Fa cmsg_level -in the -.Vt struct cmsghdr -that differs from -.Dv SOL_SOCKET , -a -.Fa cmsg_type -that differs from -.Dv SCM_RIGHTS , -or a -.Fa cmsg_len -that is not three times the size of an -.Vt int -.It -invalid file descriptors passed in the -.Xr CMSG_DATA 3 -.It -resource exhaustion, in particular -.Xr dup 2 -or -.Xr malloc 3 -failure -.El -.Pp -Except for memory exhaustion and similar system-level failures, -parsing and formatting errors do not cause -.Nm -to return an error exit status. -Even after severe parsing errors, -.Nm -will simply accept and process the next input file descriptor. -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr mandoc 3 , -.Xr catman 8 -.Sh HISTORY -The -.Nm -utility appeared in version 1.14.1 or the -.Sy mandoc -toolkit. -.Sh AUTHORS -.An -nosplit -The concept was designed and implemented by -.An Michael Stapelberg Aq Mt stapelberg@debian.org . -The -.Xr mandoc 3 -glue needed to make it a stand-alone process was added by -.An Ingo Schwarze Aq Mt schwarze@openbsd.org . -.Sh CAVEATS -If the parsed manual pages contain -.Xr roff 7 -.Pf . Ic so -requests, -.Nm -needs to be started with the current working directory set to the -root of the manual page tree. -Avoid starting it in directories that contain secret files in any -subdirectories, in particular in the user starting it has read -access to these secret files. Property changes on: head/contrib/mdocml/mandocd.8 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/demandoc.1 =================================================================== --- head/contrib/mdocml/demandoc.1 (revision 338825) +++ head/contrib/mdocml/demandoc.1 (nonexistent) @@ -1,108 +0,0 @@ -.\" $Id: demandoc.1,v 1.8 2014/09/12 00:10:26 schwarze Exp $ -.\" -.\" 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 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: September 12 2014 $ -.Dt DEMANDOC 1 -.Os -.Sh NAME -.Nm demandoc -.Nd emit only text of UNIX manuals -.Sh SYNOPSIS -.Nm demandoc -.Op Fl w -.Op Ar -.Sh DESCRIPTION -The -.Nm -utility emits only the text portions of well-formed -.Xr mdoc 7 -and -.Xr man 7 -.Ux -manual files. -.Pp -By default, -.Nm -parses standard input and outputs only text nodes, preserving line -and column position. -Escape sequences are omitted from the output. -.Pp -Its arguments are as follows: -.Bl -tag -width Ds -.It Fl w -Output a word list. -This outputs each word of text on its own line. -A -.Qq word , -in this case, refers to whitespace-delimited terms beginning with at -least two letters and not consisting of any escape sequences. -Words have their leading and trailing punctuation -.Pq double-quotes, sentence punctuation, etc. -stripped. -.It Ar -The input files. -.El -.Pp -If a document is not well-formed, it is skipped. -.Pp -The -.Fl i , -.Fl k , -.Fl m , -and -.Fl p -flags are silently discarded for calling compatibility with the -historical deroff. -.Sh EXIT STATUS -The -.Nm -utility exits with one of the following values: -.Pp -.Bl -tag -width Ds -compact -.It 0 -No errors occurred. -.It 6 -An operating system error occurred, for example memory exhaustion or an -error accessing input files. -Such errors cause -.Nm -to exit at once, possibly in the middle of parsing or formatting a file. -The output databases are corrupt and should be removed . -.El -.Sh EXAMPLES -The traditional usage of -.Nm -is for spell-checking manuals on -.Bx . -This is accomplished as follows (assuming British spelling): -.Pp -.Dl $ demandoc -w file.1 | spell -b -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr man 7 , -.Xr mdoc 7 -.Sh HISTORY -.Nm -replaces the historical deroff utility for handling modern -.Xr man 7 -and -.Xr mdoc 7 -documents. -.Sh AUTHORS -The -.Nm -utility was written by -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . Property changes on: head/contrib/mdocml/demandoc.1 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/Makefile =================================================================== --- head/contrib/mdocml/Makefile (revision 338825) +++ head/contrib/mdocml/Makefile (nonexistent) @@ -1,573 +0,0 @@ -# $Id: Makefile,v 1.516 2017/07/20 16:24:53 schwarze Exp $ -# -# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons -# Copyright (c) 2011, 2013-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. - -VERSION = 1.14.3 - -# === LIST OF FILES ==================================================== - -TESTSRCS = test-be32toh.c \ - test-cmsg.c \ - test-dirent-namlen.c \ - test-EFTYPE.c \ - test-err.c \ - test-fts.c \ - test-getline.c \ - test-getsubopt.c \ - test-isblank.c \ - test-mkdtemp.c \ - test-nanosleep.c \ - test-ntohl.c \ - test-O_DIRECTORY.c \ - test-ohash.c \ - test-PATH_MAX.c \ - test-pledge.c \ - test-progname.c \ - test-recvmsg.c \ - test-reallocarray.c \ - test-recallocarray.c \ - test-rewb-bsd.c \ - test-rewb-sysv.c \ - test-sandbox_init.c \ - test-strcasestr.c \ - test-stringlist.c \ - test-strlcat.c \ - test-strlcpy.c \ - test-strptime.c \ - test-strsep.c \ - test-strtonum.c \ - test-vasprintf.c \ - test-wchar.c - -SRCS = att.c \ - catman.c \ - cgi.c \ - chars.c \ - compat_err.c \ - compat_fts.c \ - compat_getline.c \ - compat_getsubopt.c \ - compat_isblank.c \ - compat_mkdtemp.c \ - compat_ohash.c \ - compat_progname.c \ - compat_reallocarray.c \ - compat_recallocarray.c \ - compat_strcasestr.c \ - compat_stringlist.c \ - compat_strlcat.c \ - compat_strlcpy.c \ - compat_strsep.c \ - compat_strtonum.c \ - compat_vasprintf.c \ - dba.c \ - dba_array.c \ - dba_read.c \ - dba_write.c \ - dbm.c \ - dbm_map.c \ - demandoc.c \ - eqn.c \ - eqn_html.c \ - eqn_term.c \ - html.c \ - lib.c \ - main.c \ - man.c \ - man_html.c \ - man_macro.c \ - man_term.c \ - man_validate.c \ - mandoc.c \ - mandoc_aux.c \ - mandoc_ohash.c \ - mandoc_xr.c \ - mandocd.c \ - mandocdb.c \ - manpath.c \ - mansearch.c \ - mdoc.c \ - mdoc_argv.c \ - mdoc_html.c \ - mdoc_macro.c \ - mdoc_man.c \ - mdoc_markdown.c \ - mdoc_state.c \ - mdoc_term.c \ - mdoc_validate.c \ - msec.c \ - out.c \ - preconv.c \ - read.c \ - roff.c \ - roff_html.c \ - roff_term.c \ - roff_validate.c \ - soelim.c \ - st.c \ - tag.c \ - tbl.c \ - tbl_data.c \ - tbl_html.c \ - tbl_layout.c \ - tbl_opts.c \ - tbl_term.c \ - term.c \ - term_ascii.c \ - term_ps.c \ - term_tab.c \ - tree.c - -DISTFILES = INSTALL \ - LICENSE \ - Makefile \ - Makefile.depend \ - NEWS \ - TODO \ - apropos.1 \ - catman.8 \ - cgi.h.example \ - compat_fts.h \ - compat_ohash.h \ - compat_stringlist.h \ - configure \ - configure.local.example \ - dba.h \ - dba_array.h \ - dba_write.h \ - dbm.h \ - dbm_map.h \ - demandoc.1 \ - eqn.7 \ - gmdiff \ - html.h \ - lib.in \ - libman.h \ - libmandoc.h \ - libmdoc.h \ - libroff.h \ - main.h \ - makewhatis.8 \ - man.1 \ - man.7 \ - man.cgi.3 \ - man.cgi.8 \ - man.conf.5 \ - man.h \ - man.options.1 \ - manconf.h \ - mandoc.1 \ - mandoc.3 \ - mandoc.css \ - mandoc.db.5 \ - mandoc.h \ - mandoc_aux.h \ - mandoc_char.7 \ - mandoc_escape.3 \ - mandoc_headers.3 \ - mandoc_html.3 \ - mandoc_malloc.3 \ - mandoc_ohash.h \ - mandoc_xr.h \ - mandocd.8 \ - mansearch.3 \ - mansearch.h \ - mchars_alloc.3 \ - mdoc.7 \ - mdoc.h \ - msec.in \ - out.h \ - predefs.in \ - roff.7 \ - roff.h \ - roff_int.h \ - soelim.1 \ - st.in \ - tag.h \ - tbl.3 \ - tbl.7 \ - term.h \ - $(SRCS) \ - $(TESTSRCS) - -LIBMAN_OBJS = man.o \ - man_macro.o \ - man_validate.o - -LIBMDOC_OBJS = att.o \ - lib.o \ - mdoc.o \ - mdoc_argv.o \ - mdoc_macro.o \ - mdoc_state.o \ - mdoc_validate.o \ - st.o - -LIBROFF_OBJS = eqn.o \ - roff.o \ - roff_validate.o \ - tbl.o \ - tbl_data.o \ - tbl_layout.o \ - tbl_opts.o - -LIBMANDOC_OBJS = $(LIBMAN_OBJS) \ - $(LIBMDOC_OBJS) \ - $(LIBROFF_OBJS) \ - chars.o \ - mandoc.o \ - mandoc_aux.o \ - mandoc_ohash.o \ - mandoc_xr.o \ - msec.o \ - preconv.o \ - read.o - -COMPAT_OBJS = compat_err.o \ - compat_fts.o \ - compat_getline.o \ - compat_getsubopt.o \ - compat_isblank.o \ - compat_mkdtemp.o \ - compat_ohash.o \ - compat_progname.o \ - compat_reallocarray.o \ - compat_recallocarray.o \ - compat_strcasestr.o \ - compat_strlcat.o \ - compat_strlcpy.o \ - compat_strsep.o \ - compat_strtonum.o \ - compat_vasprintf.o - -MANDOC_HTML_OBJS = eqn_html.o \ - html.o \ - man_html.o \ - mdoc_html.o \ - roff_html.o \ - tbl_html.o - -MANDOC_TERM_OBJS = eqn_term.o \ - man_term.o \ - mdoc_term.o \ - roff_term.o \ - term.o \ - term_ascii.o \ - term_ps.o \ - term_tab.o \ - tbl_term.o - -DBM_OBJS = dbm.o \ - dbm_map.o \ - mansearch.o - -DBA_OBJS = dba.o \ - dba_array.o \ - dba_read.o \ - dba_write.o \ - mandocdb.o - -MAIN_OBJS = $(MANDOC_HTML_OBJS) \ - $(MANDOC_MAN_OBJS) \ - $(MANDOC_TERM_OBJS) \ - $(DBM_OBJS) \ - $(DBA_OBJS) \ - main.o \ - manpath.o \ - mdoc_man.o \ - mdoc_markdown.o \ - out.o \ - tag.o \ - tree.o - -CGI_OBJS = $(MANDOC_HTML_OBJS) \ - $(DBM_OBJS) \ - cgi.o \ - out.o - -MANDOCD_OBJS = $(MANDOC_HTML_OBJS) \ - $(MANDOC_TERM_OBJS) \ - mandocd.o \ - out.o \ - tag.o - -DEMANDOC_OBJS = demandoc.o - -SOELIM_OBJS = soelim.o \ - compat_err.o \ - compat_getline.o \ - compat_progname.o \ - compat_reallocarray.o \ - compat_stringlist.o - -WWW_MANS = apropos.1.html \ - demandoc.1.html \ - man.1.html \ - mandoc.1.html \ - soelim.1.html \ - man.cgi.3.html \ - mandoc.3.html \ - mandoc_escape.3.html \ - mandoc_headers.3.html \ - mandoc_html.3.html \ - mandoc_malloc.3.html \ - mansearch.3.html \ - mchars_alloc.3.html \ - tbl.3.html \ - man.conf.5.html \ - mandoc.db.5.html \ - eqn.7.html \ - man.7.html \ - mandoc_char.7.html \ - mandocd.8.html \ - mdoc.7.html \ - roff.7.html \ - tbl.7.html \ - catman.8.html \ - makewhatis.8.html \ - man.cgi.8.html \ - man.h.html \ - manconf.h.html \ - mandoc.h.html \ - mandoc_aux.h.html \ - mansearch.h.html \ - mdoc.h.html \ - roff.h.html - -# === USER CONFIGURATION =============================================== - -include Makefile.local - -# === DEPENDENCY HANDLING ============================================== - -all: mandoc demandoc soelim $(BUILD_TARGETS) Makefile.local - -install: base-install $(INSTALL_TARGETS) - -www: $(WWW_MANS) - -$(WWW_MANS): mandoc - -.PHONY: base-install cgi-install install www-install -.PHONY: clean distclean depend - -include Makefile.depend - -# === TARGETS CONTAINING SHELL COMMANDS ================================ - -distclean: clean - rm -f Makefile.local config.h config.h.old config.log config.log.old - -clean: - rm -f libmandoc.a $(LIBMANDOC_OBJS) $(COMPAT_OBJS) - rm -f mandoc $(MAIN_OBJS) - rm -f man.cgi $(CGI_OBJS) - rm -f mandocd catman catman.o $(MANDOCD_OBJS) - rm -f demandoc $(DEMANDOC_OBJS) - rm -f soelim $(SOELIM_OBJS) - rm -f $(WWW_MANS) mandoc.tar.gz mandoc.sha256 - rm -rf *.dSYM - -base-install: mandoc demandoc soelim - mkdir -p $(DESTDIR)$(BINDIR) - mkdir -p $(DESTDIR)$(SBINDIR) - mkdir -p $(DESTDIR)$(MANDIR)/man1 - mkdir -p $(DESTDIR)$(MANDIR)/man5 - mkdir -p $(DESTDIR)$(MANDIR)/man7 - mkdir -p $(DESTDIR)$(MANDIR)/man8 - $(INSTALL_PROGRAM) mandoc demandoc $(DESTDIR)$(BINDIR) - $(INSTALL_PROGRAM) soelim $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) - cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_MAN) - cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_APROPOS) - cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_WHATIS) - cd $(DESTDIR)$(SBINDIR) && \ - $(LN) ${BIN_FROM_SBIN}/mandoc $(BINM_MAKEWHATIS) - $(INSTALL_MAN) mandoc.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL_MAN) soelim.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 - $(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 - $(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 - cd $(DESTDIR)$(MANDIR)/man1 && $(LN) $(BINM_APROPOS).1 $(BINM_WHATIS).1 - $(INSTALL_MAN) man.conf.5 $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 - $(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5 - $(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 - $(INSTALL_MAN) mdoc.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MDOC).7 - $(INSTALL_MAN) roff.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_ROFF).7 - $(INSTALL_MAN) eqn.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_EQN).7 - $(INSTALL_MAN) tbl.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_TBL).7 - $(INSTALL_MAN) mandoc_char.7 $(DESTDIR)$(MANDIR)/man7 - $(INSTALL_MAN) makewhatis.8 \ - $(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8 - -lib-install: libmandoc.a - mkdir -p $(DESTDIR)$(LIBDIR) - mkdir -p $(DESTDIR)$(INCLUDEDIR) - mkdir -p $(DESTDIR)$(MANDIR)/man3 - $(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR) - $(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h roff.h \ - $(DESTDIR)$(INCLUDEDIR) - $(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \ - mansearch.3 mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3 - -cgi-install: man.cgi - mkdir -p $(DESTDIR)$(CGIBINDIR) - mkdir -p $(DESTDIR)$(HTDOCDIR) - $(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR) - $(INSTALL_DATA) mandoc.css $(DESTDIR)$(HTDOCDIR) - -catman-install: mandocd catman - mkdir -p $(DESTDIR)$(SBINDIR) - mkdir -p $(DESTDIR)$(MANDIR)/man8 - $(INSTALL_PROGRAM) mandocd $(DESTDIR)$(SBINDIR) - $(INSTALL_PROGRAM) catman $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN) - $(INSTALL_MAN) mandocd.8 $(DESTDIR)$(MANDIR)/man8 - $(INSTALL_MAN) catman.8 $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8 - -uninstall: - rm -f $(DESTDIR)$(BINDIR)/mandoc - rm -f $(DESTDIR)$(BINDIR)/demandoc - rm -f $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) - rm -f $(DESTDIR)$(BINDIR)/$(BINM_MAN) - rm -f $(DESTDIR)$(BINDIR)/$(BINM_APROPOS) - rm -f $(DESTDIR)$(BINDIR)/$(BINM_WHATIS) - rm -f $(DESTDIR)$(SBINDIR)/$(BINM_MAKEWHATIS) - rm -f $(DESTDIR)$(MANDIR)/man1/mandoc.1 - rm -f $(DESTDIR)$(MANDIR)/man1/demandoc.1 - rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 - rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 - rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 - rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_WHATIS).1 - rm -f $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 - rm -f $(DESTDIR)$(MANDIR)/man5/mandoc.db.5 - rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 - rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_MDOC).7 - rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_ROFF).7 - rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_EQN).7 - rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_TBL).7 - rm -f $(DESTDIR)$(MANDIR)/man7/mandoc_char.7 - rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8 - rm -f $(DESTDIR)$(CGIBINDIR)/man.cgi - rm -f $(DESTDIR)$(HTDOCDIR)/mandoc.css - rm -f $(DESTDIR)$(SBINDIR)/mandocd - rm -f $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN) - rm -f $(DESTDIR)$(MANDIR)/man8/mandocd.8 - rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8 - rm -f $(DESTDIR)$(LIBDIR)/libmandoc.a - rm -f $(DESTDIR)$(MANDIR)/man3/mandoc.3 - rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_escape.3 - rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_malloc.3 - rm -f $(DESTDIR)$(MANDIR)/man3/mansearch.3 - rm -f $(DESTDIR)$(MANDIR)/man3/mchars_alloc.3 - rm -f $(DESTDIR)$(MANDIR)/man3/tbl.3 - rm -f $(DESTDIR)$(INCLUDEDIR)/man.h - rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc.h - rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_aux.h - rm -f $(DESTDIR)$(INCLUDEDIR)/mdoc.h - rm -f $(DESTDIR)$(INCLUDEDIR)/roff.h - [ ! -e $(DESTDIR)$(INCLUDEDIR) ] || rmdir $(DESTDIR)$(INCLUDEDIR) - -regress: all - cd regress && ./regress.pl - -regress-clean: - cd regress && ./regress.pl . clean - -Makefile.local config.h: configure $(TESTSRCS) - @echo "$@ is out of date; please run ./configure" - @exit 1 - -libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS) - ar rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS) - -mandoc: $(MAIN_OBJS) libmandoc.a - $(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD) - -man.cgi: $(CGI_OBJS) libmandoc.a - $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD) - -mandocd: $(MANDOCD_OBJS) libmandoc.a - $(CC) -o $@ $(LDFLAGS) $(MANDOCD_OBJS) libmandoc.a $(LDADD) - -catman: catman.o libmandoc.a - $(CC) -o $@ $(LDFLAGS) catman.o libmandoc.a $(LDADD) - -demandoc: $(DEMANDOC_OBJS) libmandoc.a - $(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) libmandoc.a $(LDADD) - -soelim: $(SOELIM_OBJS) - $(CC) -o $@ $(LDFLAGS) $(SOELIM_OBJS) - -# --- maintainer targets --- - -www-install: www - $(INSTALL_DATA) $(WWW_MANS) mandoc.css $(HTDOCDIR) - -depend: config.h - mkdep -f Makefile.depend $(CFLAGS) $(SRCS) - perl -e 'undef $$/; $$_ = <>; s|/usr/include/\S+||g; \ - s|\\\n||g; s| +| |g; s| $$||mg; print;' \ - Makefile.depend > Makefile.tmp - mv Makefile.tmp Makefile.depend - -regress-distclean: - @find regress \ - -name '.#*' -o \ - -name '*.orig' -o \ - -name '*.rej' -o \ - -name '*.core' \ - -exec rm -i {} \; - -regress-distcheck: - @find regress ! -type d ! -type f - @find regress -type f \ - ! -path '*/CVS/*' \ - ! -name Makefile \ - ! -name Makefile.inc \ - ! -name '*.in' \ - ! -name '*.out_ascii' \ - ! -name '*.out_utf8' \ - ! -name '*.out_html' \ - ! -name '*.out_markdown' \ - ! -name '*.out_lint' \ - ! -path regress/regress.pl \ - ! -path regress/regress.pl.1 - -dist: mandoc.sha256 - -mandoc.sha256: mandoc.tar.gz - sha256 mandoc.tar.gz > $@ - -mandoc.tar.gz: $(DISTFILES) - ls regress/*/*/*.mandoc_* && exit 1 || true - mkdir -p .dist/mandoc-$(VERSION)/ - $(INSTALL) -m 0644 $(DISTFILES) .dist/mandoc-$(VERSION) - cp -pR regress .dist/mandoc-$(VERSION) - find .dist/mandoc-$(VERSION)/regress \ - -type d -name CVS -print0 | xargs -0 rm -rf - chmod 755 .dist/mandoc-$(VERSION)/configure - ( cd .dist/ && tar zcf ../$@ mandoc-$(VERSION) ) - rm -rf .dist/ - -# === SUFFIX RULES ===================================================== - -.SUFFIXES: .1 .3 .5 .7 .8 .h -.SUFFIXES: .1.html .3.html .5.html .7.html .8.html .h.html - -.h.h.html: - highlight -I $< > $@ - -.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc - ./mandoc -Thtml -Wall,stop \ - -Ostyle=mandoc.css,man=%N.%S.html,includes=%I.html $< > $@ Property changes on: head/contrib/mdocml/Makefile ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_ohash.h =================================================================== --- head/contrib/mdocml/compat_ohash.h (revision 338825) +++ head/contrib/mdocml/compat_ohash.h (nonexistent) @@ -1,72 +0,0 @@ -/* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * 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. - */ - -#ifndef OHASH_H -#define OHASH_H - -/* Open hashing support. - * Open hashing was chosen because it is much lighter than other hash - * techniques, and more efficient in most cases. - */ - -/* user-visible data structure */ -struct ohash_info { - ptrdiff_t key_offset; - void *data; /* user data */ - void *(*calloc)(size_t, size_t, void *); - void (*free)(void *, void *); - void *(*alloc)(size_t, void *); -}; - -struct _ohash_record; - -/* private structure. It's there just so you can do a sizeof */ -struct ohash { - struct _ohash_record *t; - struct ohash_info info; - unsigned int size; - unsigned int total; - unsigned int deleted; -}; - -/* For this to be tweakable, we use small primitives, and leave part of the - * logic to the client application. e.g., hashing is left to the client - * application. We also provide a simple table entry lookup that yields - * a hashing table index (opaque) to be used in find/insert/remove. - * The keys are stored at a known position in the client data. - */ -void ohash_init(struct ohash *, unsigned, struct ohash_info *); -void ohash_delete(struct ohash *); - -unsigned int ohash_lookup_interval(struct ohash *, const char *, - const char *, uint32_t); -unsigned int ohash_lookup_memory(struct ohash *, const char *, - size_t, uint32_t); -void *ohash_find(struct ohash *, unsigned int); -void *ohash_remove(struct ohash *, unsigned int); -void *ohash_insert(struct ohash *, unsigned int, void *); -void *ohash_first(struct ohash *, unsigned int *); -void *ohash_next(struct ohash *, unsigned int *); -unsigned int ohash_entries(struct ohash *); - -void *ohash_create_entry(struct ohash_info *, const char *, const char **); -uint32_t ohash_interval(const char *, const char **); - -unsigned int ohash_qlookupi(struct ohash *, const char *, const char **); -unsigned int ohash_qlookup(struct ohash *, const char *); - -#endif Property changes on: head/contrib/mdocml/compat_ohash.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tbl.7 =================================================================== --- head/contrib/mdocml/tbl.7 (revision 338825) +++ head/contrib/mdocml/tbl.7 (nonexistent) @@ -1,432 +0,0 @@ -.\" $Id: tbl.7,v 1.28 2017/06/28 00:59:57 schwarze Exp $ -.\" -.\" Copyright (c) 2010, 2011 Kristaps Dzonsons -.\" 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. -.\" -.Dd $Mdocdate: June 28 2017 $ -.Dt TBL 7 -.Os -.Sh NAME -.Nm tbl -.Nd tbl language reference for mandoc -.Sh DESCRIPTION -The -.Nm tbl -language formats tables. -It is used within -.Xr mdoc 7 -and -.Xr man 7 -pages. -This manual describes the subset of the -.Nm -language accepted by the -.Xr mandoc 1 -utility. -.Pp -Each table is started with a -.Xr roff 7 -.Ic \&TS -macro, consist of at most one line of -.Sx Options , -one or more -.Sx Layout -lines, one or more -.Sx Data -lines, and ends with a -.Ic \&TE -macro. -All input must be 7-bit ASCII. -.Ss Options -If the first input line of a table ends with a semicolon, it contains -case-insensitive options separated by spaces, tabs, or commas. -Otherwise, it is interpreted as the first -.Sx Layout -line. -.Pp -The following options are available. -Some of them require arguments enclosed in parentheses: -.Bl -tag -width Ds -.It Cm allbox -Draw a single-line box around each table cell. -.It Cm box -Draw a single-line box around the table. -For GNU compatibility, this may also be invoked with -.Cm frame . -.It Cm center -Center the table instead of left-adjusting it. -For GNU compatibility, this may also be invoked with -.Cm centre . -.It Cm decimalpoint -Use the single-character argument as the decimal point with the -.Cm n -layout key. -This is a GNU extension. -.It Cm delim -Use the two characters of the argument as -.Xr eqn 7 -delimiters. -Currently unsupported. -.It Cm doublebox -Draw a double-line box around the table. -For GNU compatibility, this may also be invoked with -.Cm doubleframe . -.It Cm expand -Increase the width of the table to the current line length. -Currently ignored. -.It Cm linesize -Draw lines with the point size given by the unsigned integer argument. -Currently ignored. -.It Cm nokeep -Allow page breaks within the table. -This is a GNU extension and currently ignored. -.It Cm nospaces -Ignore leading and trailing spaces in data cells. -This is a GNU extension and currently ignored. -.It Cm nowarn -Suppress warnings about tables exceeding the current line length. -This is a GNU extension and currently ignored. -.It Cm tab -Use the single-character argument as a delimiter between data cells. -By default, the horizontal tabulator character is used. -.El -.Ss Layout -The table layout follows an -.Sx Options -line or a -.Xr roff 7 -.Ic \&TS -or -.Ic \&T& -macro. -Each layout line specifies how one line of -.Sx Data -is formatted. -The last layout line ends with a full stop. -It also applies to all remaining data lines. -Multiple layout lines can be joined by commas on a single physical -input line. -.Pp -Each layout line consists of one or more layout cell specifications, -optionally separated by whitespace. -The following case-insensitive key characters start a new cell -specification: -.Bl -tag -width 2n -.It Cm c -Center the string in this cell. -.It Cm r -Right-justify the string in this cell. -.It Cm l -Left-justify the string in this cell. -.It Cm n -Justify a number around its last decimal point. -If no decimal point is found in the number, -it is assumed to trail the number. -.It Cm s -Horizontally span columns from the last -.Pf non- Cm s -layout cell. -It is an error if a column span follows a -.Cm _ -or -.Cm = -cell, or comes first on a layout line. -The combined cell as a whole consumes only one cell -of the corresponding data line. -.It Cm a -Left-justify a string and pad with one space. -.It Cm ^ -Vertically span rows from the last -.Pf non- Cm ^ -layout cell. -It is an error to invoke a vertical span on the first layout line. -Unlike a horizontal span, a vertical span consumes a data cell -and discards the content. -.It Cm _ -Draw a single horizontal line in this cell. -This consumes a data cell and discards the content. -It may also be invoked with -.Cm \- . -.It Cm = -Draw a double horizontal line in this cell. -This consumes a data cell and discards the content. -.El -.Pp -Each cell key may be followed by zero or more of the following -case-insensitive modifiers: -.Bl -tag -width 2n -.It Cm b -Use a bold font for the contents of this cell. -.It Cm d -Move content down to the last row of this vertical span. -Currently ignored. -.It Cm e -Make this column wider to match the maximum width -of any other column also having the -.Cm e -modifier. -.It Cm f -The next character selects the font to use for this cell. -See the -.Xr roff 7 -manual for supported one-character font names. -.It Cm i -Use an italic font for the contents of this cell. -.It Cm m -Specify a cell start macro. -This is a GNU extension and currently unsupported. -.It Cm p -Set the point size to the following unsigned argument, -or change it by the following signed argument. -Currently ignored. -.It Cm v -Set the vertical line spacing to the following unsigned argument, -or change it by the following signed argument. -Currently ignored. -.It Cm t -Do not vertically center content in this vertical span, -leave it in the top row. -Currently ignored. -.It Cm u -Move cell content up by half a table row. -Currently ignored. -.It Cm w -Specify a minimum column width. -.It Cm x -After determining the width of all other columns, distribute the -rest of the line length among all columns having the -.Cm x -modifier. -.It Cm z -Do not use this cell for determining the width of this column. -.It Cm \&| -Draw a single vertical line to the right of this cell. -.It Cm || -Draw a double vertical line to the right of this cell. -.El -.Pp -If a modifier consists of decimal digits, -it specifies a minimum spacing in units of -.Cm n -between this column and the next column to the right. -The default is 3. -If there is a vertical line, it is drawn inside the spacing. -.Ss Data -The data section follows the last -.Sx Layout -line. -Each data line consists of one or more data cells, delimited by -.Cm tab -characters. -.Pp -If a data cells contains only the single character -.Ql _ -or -.Ql = , -a single or double horizontal line is drawn across the cell, -joining its neighbours. -If a data cells contains only the two character sequence -.Ql \e_ -or -.Ql \e= , -a single or double horizontal line is drawn inside the cell, -not joining its neighbours. -If a data line contains nothing but the single character -.Ql _ -or -.Ql = , -a horizontal line across the whole table is inserted -without consuming a layout row. -.Pp -In place of any data cell, a text block can be used. -It starts with -.Ic \&T{ -at the end of a physical input line. -Input line breaks inside the text block -neither end the text block nor its data cell. -It only ends if -.Ic \&T} -occurs at the beginning of a physical input line and is followed -by an end-of-cell indicator. -If the -.Ic \&T} -is followed by the end of the physical input line, the text block, -the data cell, and the data line ends at this point. -If the -.Ic \&T} -is followed by the -.Cm tab -character, only the text block and the data cell end, -but the data line continues with the data cell following the -.Cm tab -character. -If -.Ic \&T} -is followed by any other character, it does not end the text block, -which instead continues to the following physical input line. -.Sh EXAMPLES -String justification and font selection: -.Bd -literal -offset indent -\&.TS -rb c lb -r ci l. -r center l -ri ce le -right c left -\&.TE -.Ed -.Bd -filled -offset indent -.TS -rb c lb -r ci l. -r center l -ri ce le -right c left -.TE -.Ed -.Pp -Some ports in -.Ox 6.1 -to show number alignment and line drawing: -.Bd -literal -offset indent -\&.TS -box tab(:); -r| l -r n. -software:version -_ -AFL:2.39b -Mutt:1.8.0 -Ruby:1.8.7.374 -TeX Live:2015 -\&.TE -.Ed -.Bd -filled -offset indent -.TS -box tab(:); -r| l -r n. -software:version -_ -AFL:2.39b -Mutt:1.8.0 -Ruby:1.8.7.374 -TeX Live:2015 -.TE -.Ed -.sp 2v -Spans and skipping width calculations: -.Bd -literal -offset indent -\&.TS -box tab(:); -lz s | rt -lt| cb| ^ -^ | rz s. -left:r -l:center: -:right -\&.TE -.Ed -.Bd -filled -offset indent -.TS -box tab(:); -lz s | rt -lt| cb| ^ -^ | rz s. -left:r -l:center: -:right -.TE -.Ed -.sp 2v -Text blocks, specifying spacings and specifying and equalizing -column widths, putting lines into individual cells, and overriding -.Cm allbox : -.Bd -literal -offset indent -\&.TS -allbox tab(:); -le le||7 lw10. -The fourth line:_:line 1 -of this column:=:line 2 -determines:\_:line 3 -the column width.:T{ -This text is too wide to fit into a column of width 17. -T}:line 4 -T{ -No break here. -T}::line 5 -\&.TE -.Ed -.Bd -filled -offset indent -.TS -allbox tab(:); -le le||7 lw10. -The fourth line:_:line 1 -of this column:=:line 2 -determines:\_:line 3 -the column width.:T{ -This text is too wide to fit into a column of width 17. -T}:line 4 -T{ -No break here. -T}::line 5 -.TE -.Ed -.sp 2v -These examples were constructed to demonstrate many -.Nm -features in a compact way. -In real manual pages, keep tables as simple as possible: -Like that, they usually look better, are less fragile, and more portable. -.Sh COMPATIBILITY -The -.Xr mandoc 1 -implementation of -.Nm -doesn't support -.Xr mdoc 7 -and -.Xr man 7 -macros and -.Xr eqn 7 -equations inside tables. -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr man 7 , -.Xr mandoc_char 7 , -.Xr mdoc 7 , -.Xr roff 7 -.Rs -.%A M. E. Lesk -.%T Tbl\(emA Program to Format Tables -.%D June 11, 1976 -.Re -.Sh HISTORY -The tbl utility, a preprocessor for troff, was originally written by M. -E. Lesk at Bell Labs in 1975. -The GNU reimplementation of tbl, part of the groff package, was released -in 1990 by James Clark. -A standalone tbl implementation was written by Kristaps Dzonsons in -2010. -This formed the basis of the implementation that is part of the -.Xr mandoc 1 -utility. -.Sh AUTHORS -This -.Nm -reference was written by -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv -and -.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: head/contrib/mdocml/tbl.7 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/roff_validate.c =================================================================== --- head/contrib/mdocml/roff_validate.c (revision 338825) +++ head/contrib/mdocml/roff_validate.c (nonexistent) @@ -1,97 +0,0 @@ -/* $Id: roff_validate.c,v 1.9 2017/06/14 22:51:25 schwarze Exp $ */ -/* - * 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. - */ -#include - -#include -#include - -#include "mandoc.h" -#include "roff.h" -#include "libmandoc.h" -#include "roff_int.h" - -#define ROFF_VALID_ARGS struct roff_man *man, struct roff_node *n - -typedef void (*roff_valid_fp)(ROFF_VALID_ARGS); - -static void roff_valid_ft(ROFF_VALID_ARGS); - -static const roff_valid_fp roff_valids[ROFF_MAX] = { - NULL, /* br */ - NULL, /* ce */ - roff_valid_ft, /* ft */ - NULL, /* ll */ - NULL, /* mc */ - NULL, /* po */ - NULL, /* rj */ - NULL, /* sp */ - NULL, /* ta */ - NULL, /* ti */ -}; - - -void -roff_validate(struct roff_man *man) -{ - struct roff_node *n; - - n = man->last; - assert(n->tok < ROFF_MAX); - if (roff_valids[n->tok] != NULL) - (*roff_valids[n->tok])(man, n); -} - -static void -roff_valid_ft(ROFF_VALID_ARGS) -{ - char *cp; - - if (n->child == NULL) { - man->next = ROFF_NEXT_CHILD; - roff_word_alloc(man, n->line, n->pos, "P"); - man->last = n; - return; - } - - cp = n->child->string; - switch (*cp) { - case '1': - case '2': - case '3': - case '4': - case 'I': - case 'P': - case 'R': - if (cp[1] == '\0') - return; - break; - case 'B': - if (cp[1] == '\0' || (cp[1] == 'I' && cp[2] == '\0')) - return; - break; - case 'C': - if (cp[1] == 'W' && cp[2] == '\0') - return; - break; - default: - break; - } - - mandoc_vmsg(MANDOCERR_FT_BAD, man->parse, - n->line, n->pos, "ft %s", cp); - roff_node_delete(man, n); -} Property changes on: head/contrib/mdocml/roff_validate.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/soelim.c =================================================================== --- head/contrib/mdocml/soelim.c (revision 338825) +++ head/contrib/mdocml/soelim.c (nonexistent) @@ -1,182 +0,0 @@ -/* $Id: soelim.c,v 1.5 2015/11/07 14:22:29 schwarze Exp $ */ -/* - * Copyright (c) 2014 Baptiste Daroussin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "config.h" - -#include - -#include -#if HAVE_ERR -#include -#endif -#include -#include -#include -#include -#if HAVE_STRINGLIST -#include -#else -#include "compat_stringlist.h" -#endif -#include - -#define C_OPTION 0x1 - -static StringList *includes; - -static void -usage(void) -{ - - fprintf(stderr, "usage: soelim [-Crtv] [-I dir] [files]\n"); - - exit(EXIT_FAILURE); -} - -static FILE * -soelim_fopen(const char *name) -{ - FILE *f; - char path[PATH_MAX]; - size_t i; - - if (strcmp(name, "-") == 0) - return (stdin); - - if ((f = fopen(name, "r")) != NULL) - return (f); - - if (*name == '/') { - warn("can't open '%s'", name); - return (NULL); - } - - for (i = 0; i < includes->sl_cur; i++) { - snprintf(path, sizeof(path), "%s/%s", includes->sl_str[i], - name); - if ((f = fopen(path, "r")) != NULL) - return (f); - } - - warn("can't open '%s'", name); - - return (f); -} - -static int -soelim_file(FILE *f, int flag) -{ - char *line = NULL; - char *walk, *cp; - size_t linecap = 0; - ssize_t linelen; - - if (f == NULL) - return (1); - - while ((linelen = getline(&line, &linecap, f)) > 0) { - if (strncmp(line, ".so", 3) != 0) { - printf("%s", line); - continue; - } - - walk = line + 3; - if (!isspace(*walk) && ((flag & C_OPTION) == 0)) { - printf("%s", line); - continue; - } - - while (isspace(*walk)) - walk++; - - cp = walk; - while (*cp != '\0' && !isspace(*cp)) - cp++; - *cp = 0; - if (cp < line + linelen) - cp++; - - if (*walk == '\0') { - printf("%s", line); - continue; - } - if (soelim_file(soelim_fopen(walk), flag) == 1) { - free(line); - return (1); - } - if (*cp != '\0') - printf("%s", cp); - } - - free(line); - fclose(f); - - return (0); -} - -int -main(int argc, char **argv) -{ - int ch, i; - int ret = 0; - int flags = 0; - - includes = sl_init(); - if (includes == NULL) - err(EXIT_FAILURE, "sl_init()"); - - while ((ch = getopt(argc, argv, "CrtvI:")) != -1) { - switch (ch) { - case 'C': - flags |= C_OPTION; - break; - case 'r': - case 'v': - case 't': - /* stub compatibility with groff's soelim */ - break; - case 'I': - sl_add(includes, optarg); - break; - default: - sl_free(includes, 0); - usage(); - } - } - - argc -= optind; - argv += optind; - - if (argc == 0) - ret = soelim_file(stdin, flags); - - for (i = 0; i < argc; i++) - ret = soelim_file(soelim_fopen(argv[i]), flags); - - sl_free(includes, 0); - - return (ret); -} Property changes on: head/contrib/mdocml/soelim.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/soelim.1 =================================================================== --- head/contrib/mdocml/soelim.1 (revision 338825) +++ head/contrib/mdocml/soelim.1 (nonexistent) @@ -1,86 +0,0 @@ -.\" $Id: soelim.1,v 1.5 2017/07/04 23:40:01 schwarze Exp $ -.\" -.\" Copyright (c) 2014 Baptiste Daroussin -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.Dd $Mdocdate: July 4 2017 $ -.Dt SOELIM 1 -.Os -.Sh NAME -.Nm soelim -.Nd interpret .so requests in manpages -.Sh SYNOPSIS -.Nm -.Op Fl Crtv -.Op Fl I Ar dir -.Op Ar files ... -.Sh DESCRIPTION -.Nm -reads -.Ar files -lines by lines. -.Pp -If a line starts by: -.Dq .so anotherfile -it replace the line by processing -.Dq anotherfile . -Otherwise the line is printed to stdout. -.Bl -tag -width "-I dir" -.It Fl C -Recognise -.Em .so -when not followed by a space character. -.It Fl r -Compatibility with GNU groff's -.Nm soelim -(does nothing). -.It Fl t -Compatibility with GNU groff's -.Nm soelim -(does nothing). -.It Fl v -Compatibility with GNU groff's -.Nm soelim -(does nothing). -.It Fl I Ar dir -This option specify directories where -.Nm -searches for files (both those on the command line and those named in -.Dq .so -directive.) -This options may be specified multiple times. -The directories will be searched in the order specified. -.El -.Pp -The files are always searched first in the current directory. -.Pp -A file specified with an absolute path will be opened directly without -performing a search. -.Sh SEE ALSO -.Xr mandoc 1 -.Sh AUTHORS -This version of the -.Nm -utility was written by -.An Baptiste Daroussin Aq Mt bapt@freebsd.org . Property changes on: head/contrib/mdocml/soelim.1 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/libmandoc.h =================================================================== --- head/contrib/mdocml/libmandoc.h (revision 338825) +++ head/contrib/mdocml/libmandoc.h (nonexistent) @@ -1,73 +0,0 @@ -/* $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, 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 */ -}; - -struct buf { - char *buf; - size_t sz; -}; - - -struct mparse; -struct roff; -struct roff_man; - -void mandoc_msg(enum mandocerr, struct mparse *, - int, int, const char *); -void mandoc_vmsg(enum mandocerr, struct mparse *, - int, int, const char *, ...) - __attribute__((__format__ (__printf__, 5, 6))); -char *mandoc_getarg(struct mparse *, char **, int, int *); -char *mandoc_normdate(struct roff_man *, char *, int, int); -int mandoc_eos(const char *, size_t); -int mandoc_strntoi(const char *, size_t, int); -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 *); Property changes on: head/contrib/mdocml/libmandoc.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc.h =================================================================== --- head/contrib/mdocml/mandoc.h (revision 338825) +++ head/contrib/mdocml/mandoc.h (nonexistent) @@ -1,469 +0,0 @@ -/* $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_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_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_LATE, /* late prologue macro: macro */ - 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_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_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_EOS, /* new sentence, new line */ - 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_TEXT, /* text (number, variable, whatever) */ - EQN_SUBEXPR, /* nested `eqn' subexpression */ - EQN_LIST, /* list (braces, etc.) */ - EQN_PILE, /* vertical pile */ - EQN_MATRIX /* pile of piles */ -}; - -enum eqn_fontt { - EQNFONT_NONE = 0, - EQNFONT_ROMAN, - EQNFONT_BOLD, - EQNFONT_FAT, - EQNFONT_ITALIC, - EQNFONT__MAX -}; - -enum eqn_post { - EQNPOS_NONE = 0, - EQNPOS_SUP, - EQNPOS_SUBSUP, - EQNPOS_SUB, - EQNPOS_TO, - EQNPOS_FROM, - EQNPOS_FROMTO, - EQNPOS_OVER, - EQNPOS_SQRT, - EQNPOS__MAX -}; - -enum eqn_pilet { - EQNPILE_NONE = 0, - EQNPILE_PILE, - EQNPILE_CPILE, - EQNPILE_RPILE, - EQNPILE_LPILE, - EQNPILE_COL, - EQNPILE_CCOL, - EQNPILE_RCOL, - EQNPILE_LCOL, - EQNPILE__MAX -}; - - /* - * A "box" is a parsed mathematical expression as defined by the eqn.7 - * grammar. - */ -struct eqn_box { - int size; /* font size of expression */ -#define EQN_DEFSIZE INT_MIN - enum eqn_boxt type; /* type of node */ - struct eqn_box *first; /* first child node */ - struct eqn_box *last; /* last child node */ - struct eqn_box *next; /* node sibling */ - struct eqn_box *prev; /* node sibling */ - struct eqn_box *parent; /* node sibling */ - char *text; /* text (or NULL) */ - char *left; /* fence left-hand */ - char *right; /* fence right-hand */ - char *top; /* expression over-symbol */ - char *bottom; /* expression under-symbol */ - size_t args; /* arguments in parent */ - size_t expectargs; /* max arguments in parent */ - enum eqn_post pos; /* position of next box */ - enum eqn_fontt font; /* font of box */ - enum eqn_pilet pile; /* equation piling */ -}; - -/* - * Parse options. - */ -#define MPARSE_MDOC 1 /* assume -mdoc */ -#define MPARSE_MAN 2 /* assume -man */ -#define MPARSE_SO 4 /* honour .so requests */ -#define MPARSE_QUICK 8 /* abort the parse early */ -#define MPARSE_UTF8 16 /* accept UTF-8 input */ -#define MPARSE_LATIN1 32 /* accept ISO-LATIN-1 input */ - -enum mandoc_os { - MANDOC_OS_OTHER = 0, - MANDOC_OS_NETBSD, - MANDOC_OS_OPENBSD -}; - -enum mandoc_esc { - ESCAPE_ERROR = 0, /* bail! unparsable escape */ - ESCAPE_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 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 *); Property changes on: head/contrib/mdocml/mandoc.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-nanosleep.c =================================================================== --- head/contrib/mdocml/test-nanosleep.c (revision 338825) +++ head/contrib/mdocml/test-nanosleep.c (nonexistent) @@ -1,17 +0,0 @@ -#include -#include - -int -main(void) -{ - struct timespec timeout; - - timeout.tv_sec = 0; - timeout.tv_nsec = 100000000; /* 0.1 seconds */ - - if (nanosleep(&timeout, NULL)) { - perror("nanosleep"); - return 1; - } - return 0; -} Property changes on: head/contrib/mdocml/test-nanosleep.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/out.c =================================================================== --- head/contrib/mdocml/out.c (revision 338825) +++ head/contrib/mdocml/out.c (nonexistent) @@ -1,369 +0,0 @@ -/* $Id: out.c,v 1.70 2017/06/27 18:25:02 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2011, 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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include -#include - -#include "mandoc_aux.h" -#include "mandoc.h" -#include "out.h" - -static void tblcalc_data(struct rofftbl *, struct roffcol *, - const struct tbl_opts *, const struct tbl_dat *, - size_t); -static void tblcalc_literal(struct rofftbl *, struct roffcol *, - const struct tbl_dat *, size_t); -static void tblcalc_number(struct rofftbl *, struct roffcol *, - const struct tbl_opts *, const struct tbl_dat *); - - -/* - * Parse the *src string and store a scaling unit into *dst. - * If the string doesn't specify the unit, use the default. - * If no default is specified, fail. - * Return a pointer to the byte after the last byte used, - * or NULL on total failure. - */ -const char * -a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) -{ - char *endptr; - - dst->unit = def == SCALE_MAX ? SCALE_BU : def; - dst->scale = strtod(src, &endptr); - if (endptr == src) - return NULL; - - switch (*endptr++) { - case 'c': - dst->unit = SCALE_CM; - break; - case 'i': - dst->unit = SCALE_IN; - break; - case 'f': - dst->unit = SCALE_FS; - break; - case 'M': - dst->unit = SCALE_MM; - break; - case 'm': - dst->unit = SCALE_EM; - break; - case 'n': - dst->unit = SCALE_EN; - break; - case 'P': - dst->unit = SCALE_PC; - break; - case 'p': - dst->unit = SCALE_PT; - break; - case 'u': - dst->unit = SCALE_BU; - break; - case 'v': - dst->unit = SCALE_VS; - break; - default: - endptr--; - if (SCALE_MAX == def) - return NULL; - dst->unit = def; - break; - } - return endptr; -} - -/* - * Calculate the abstract widths and decimal positions of columns in a - * table. This routine allocates the columns structures then runs over - * all rows and cells in the table. The function pointers in "tbl" are - * used for the actual width calculations. - */ -void -tblcalc(struct rofftbl *tbl, const struct tbl_span *sp, - size_t offset, size_t rmargin) -{ - struct roffsu su; - const struct tbl_opts *opts; - const struct tbl_dat *dp; - struct roffcol *col; - size_t ewidth, xwidth; - int spans; - int icol, maxcol, necol, nxcol, quirkcol; - - /* - * Allocate the master column specifiers. These will hold the - * widths and decimal positions for all cells in the column. It - * must be freed and nullified by the caller. - */ - - assert(NULL == tbl->cols); - tbl->cols = mandoc_calloc((size_t)sp->opts->cols, - sizeof(struct roffcol)); - opts = sp->opts; - - for (maxcol = -1; sp; sp = sp->next) { - if (TBL_SPAN_DATA != sp->pos) - continue; - spans = 1; - /* - * Account for the data cells in the layout, matching it - * to data cells in the data section. - */ - for (dp = sp->first; dp; dp = dp->next) { - /* Do not used spanned cells in the calculation. */ - if (0 < --spans) - continue; - spans = dp->spans; - if (1 < spans) - continue; - icol = dp->layout->col; - while (maxcol < icol) - tbl->cols[++maxcol].spacing = SIZE_MAX; - col = tbl->cols + icol; - col->flags |= dp->layout->flags; - if (dp->layout->flags & TBL_CELL_WIGN) - continue; - if (dp->layout->wstr != NULL && - dp->layout->width == 0 && - a2roffsu(dp->layout->wstr, &su, SCALE_EN) - != NULL) - dp->layout->width = - (*tbl->sulen)(&su, tbl->arg); - if (col->width < dp->layout->width) - col->width = dp->layout->width; - if (dp->layout->spacing != SIZE_MAX && - (col->spacing == SIZE_MAX || - col->spacing < dp->layout->spacing)) - col->spacing = dp->layout->spacing; - tblcalc_data(tbl, col, opts, dp, - dp->block == 0 ? 0 : - dp->layout->width ? dp->layout->width : - rmargin ? (rmargin + sp->opts->cols / 2) - / (sp->opts->cols + 1) : 0); - } - } - - /* - * Count columns to equalize and columns to maximize. - * Find maximum width of the columns to equalize. - * Find total width of the columns *not* to maximize. - */ - - necol = nxcol = 0; - ewidth = xwidth = 0; - for (icol = 0; icol <= maxcol; icol++) { - col = tbl->cols + icol; - if (col->spacing == SIZE_MAX || icol == maxcol) - col->spacing = 3; - if (col->flags & TBL_CELL_EQUAL) { - necol++; - if (ewidth < col->width) - ewidth = col->width; - } - if (col->flags & TBL_CELL_WMAX) - nxcol++; - else - xwidth += col->width; - } - - /* - * Equalize columns, if requested for any of them. - * Update total width of the columns not to maximize. - */ - - if (necol) { - for (icol = 0; icol <= maxcol; icol++) { - col = tbl->cols + icol; - if ( ! (col->flags & TBL_CELL_EQUAL)) - continue; - if (col->width == ewidth) - continue; - if (nxcol && rmargin) - xwidth += ewidth - col->width; - col->width = ewidth; - } - } - - /* - * If there are any columns to maximize, find the total - * available width, deducting 3n margins between columns. - * Distribute the available width evenly. - */ - - if (nxcol && rmargin) { - xwidth += 3*maxcol + - (opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ? - 2 : !!opts->lvert + !!opts->rvert); - if (rmargin <= offset + xwidth) - return; - xwidth = rmargin - offset - xwidth; - - /* - * Emulate a bug in GNU tbl width calculation that - * manifests itself for large numbers of x-columns. - * Emulating it for 5 x-columns gives identical - * behaviour for up to 6 x-columns. - */ - - if (nxcol == 5) { - quirkcol = xwidth % nxcol + 2; - if (quirkcol != 3 && quirkcol != 4) - quirkcol = -1; - } else - quirkcol = -1; - - necol = 0; - ewidth = 0; - for (icol = 0; icol <= maxcol; icol++) { - col = tbl->cols + icol; - if ( ! (col->flags & TBL_CELL_WMAX)) - continue; - col->width = (double)xwidth * ++necol / nxcol - - ewidth + 0.4995; - if (necol == quirkcol) - col->width--; - ewidth += col->width; - } - } -} - -static void -tblcalc_data(struct rofftbl *tbl, struct roffcol *col, - const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw) -{ - size_t sz; - - /* Branch down into data sub-types. */ - - switch (dp->layout->pos) { - case TBL_CELL_HORIZ: - case TBL_CELL_DHORIZ: - sz = (*tbl->len)(1, tbl->arg); - if (col->width < sz) - col->width = sz; - break; - case TBL_CELL_LONG: - case TBL_CELL_CENTRE: - case TBL_CELL_LEFT: - case TBL_CELL_RIGHT: - tblcalc_literal(tbl, col, dp, mw); - break; - case TBL_CELL_NUMBER: - tblcalc_number(tbl, col, opts, dp); - break; - case TBL_CELL_DOWN: - break; - default: - abort(); - } -} - -static void -tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, - const struct tbl_dat *dp, size_t mw) -{ - const char *str; /* Beginning of the first line. */ - const char *beg; /* Beginning of the current line. */ - char *end; /* End of the current line. */ - size_t lsz; /* Length of the current line. */ - size_t wsz; /* Length of the current word. */ - - if (dp->string == NULL || *dp->string == '\0') - return; - str = mw ? mandoc_strdup(dp->string) : dp->string; - lsz = 0; - for (beg = str; beg != NULL && *beg != '\0'; beg = end) { - end = mw ? strchr(beg, ' ') : NULL; - if (end != NULL) { - *end++ = '\0'; - while (*end == ' ') - end++; - } - wsz = (*tbl->slen)(beg, tbl->arg); - if (mw && lsz && lsz + 1 + wsz <= mw) - lsz += 1 + wsz; - else - lsz = wsz; - if (col->width < lsz) - col->width = lsz; - } - if (mw) - free((void *)str); -} - -static void -tblcalc_number(struct rofftbl *tbl, struct roffcol *col, - const struct tbl_opts *opts, const struct tbl_dat *dp) -{ - int i; - size_t sz, psz, ssz, d; - const char *str; - char *cp; - char buf[2]; - - /* - * First calculate number width and decimal place (last + 1 for - * non-decimal numbers). If the stored decimal is subsequent to - * ours, make our size longer by that difference - * (right-"shifting"); similarly, if ours is subsequent the - * stored, then extend the stored size by the difference. - * Finally, re-assign the stored values. - */ - - str = dp->string ? dp->string : ""; - sz = (*tbl->slen)(str, tbl->arg); - - /* FIXME: TBL_DATA_HORIZ et al.? */ - - buf[0] = opts->decimal; - buf[1] = '\0'; - - psz = (*tbl->slen)(buf, tbl->arg); - - if (NULL != (cp = strrchr(str, opts->decimal))) { - buf[1] = '\0'; - for (ssz = 0, i = 0; cp != &str[i]; i++) { - buf[0] = str[i]; - ssz += (*tbl->slen)(buf, tbl->arg); - } - d = ssz + psz; - } else - d = sz + psz; - - /* Adjust the settings for this column. */ - - if (col->decimal > d) { - sz += col->decimal - d; - d = col->decimal; - } else - col->width += d - col->decimal; - - if (sz > col->width) - col->width = sz; - if (d > col->decimal) - col->decimal = d; -} Property changes on: head/contrib/mdocml/out.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/msec.c =================================================================== --- head/contrib/mdocml/msec.c (revision 338825) +++ head/contrib/mdocml/msec.c (nonexistent) @@ -1,36 +0,0 @@ -/* $Id: msec.c,v 1.15 2015/10/06 18:32:19 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 "libmandoc.h" - -#define LINE(x, y) \ - if (0 == strcmp(p, x)) return(y); - -const char * -mandoc_a2msec(const char *p) -{ - -#include "msec.in" - - return NULL; -} Property changes on: head/contrib/mdocml/msec.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/out.h =================================================================== --- head/contrib/mdocml/out.h (revision 338825) +++ head/contrib/mdocml/out.h (nonexistent) @@ -1,72 +0,0 @@ -/* $Id: out.h,v 1.31 2017/06/27 18:25:02 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * 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. - */ - -enum roffscale { - SCALE_CM, /* centimeters (c) */ - SCALE_IN, /* inches (i) */ - SCALE_PC, /* pica (P) */ - SCALE_PT, /* points (p) */ - SCALE_EM, /* ems (m) */ - SCALE_MM, /* mini-ems (M) */ - SCALE_EN, /* ens (n) */ - SCALE_BU, /* default horizontal (u) */ - SCALE_VS, /* default vertical (v) */ - SCALE_FS, /* syn. for u (f) */ - SCALE_MAX -}; - -struct roffcol { - size_t width; /* width of cell */ - size_t decimal; /* decimal position in cell */ - size_t spacing; /* spacing after the column */ - int flags; /* layout flags, see tbl_cell */ -}; - -struct roffsu { - enum roffscale unit; - double scale; -}; - -typedef size_t (*tbl_sulen)(const struct roffsu *, void *); -typedef size_t (*tbl_strlen)(const char *, void *); -typedef size_t (*tbl_len)(size_t, void *); - -struct rofftbl { - tbl_sulen sulen; /* calculate scaling unit length */ - tbl_strlen slen; /* calculate string length */ - tbl_len len; /* produce width of empty space */ - struct roffcol *cols; /* master column specifiers */ - void *arg; /* passed to sulen, slen, and len */ -}; - -#define SCALE_VS_INIT(p, v) \ - do { (p)->unit = SCALE_VS; \ - (p)->scale = (v); } \ - while (/* CONSTCOND */ 0) - -#define SCALE_HS_INIT(p, v) \ - do { (p)->unit = SCALE_EN; \ - (p)->scale = (v); } \ - while (/* CONSTCOND */ 0) - - -struct tbl_span; - -const char *a2roffsu(const char *, struct roffsu *, enum roffscale); -void tblcalc(struct rofftbl *tbl, - const struct tbl_span *, size_t, size_t); Property changes on: head/contrib/mdocml/out.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_stringlist.c =================================================================== --- head/contrib/mdocml/compat_stringlist.c (revision 338825) +++ head/contrib/mdocml/compat_stringlist.c (nonexistent) @@ -1,119 +0,0 @@ -#include "config.h" - -#if HAVE_STRINGLIST - -int dummy; - -#else - -/* $Id: compat_stringlist.c,v 1.6 2015/11/07 14:22:29 schwarze Exp $ */ -/* - * Copyright (c) 1994 Christos Zoulas - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if HAVE_ERR -#include -#endif -#include -#include -#include "compat_stringlist.h" - -#define _SL_CHUNKSIZE 20 - -/* - * sl_init(): Initialize a string list - */ -StringList * -sl_init(void) -{ - StringList *sl; - - sl = malloc(sizeof(StringList)); - if (sl == NULL) - err(1, "stringlist"); - - sl->sl_cur = 0; - sl->sl_max = _SL_CHUNKSIZE; - sl->sl_str = reallocarray(NULL, sl->sl_max, sizeof(char *)); - if (sl->sl_str == NULL) - err(1, "stringlist"); - return sl; -} - - -/* - * sl_add(): Add an item to the string list - */ -int -sl_add(StringList *sl, char *name) -{ - if (sl->sl_cur == sl->sl_max - 1) { - sl->sl_max += _SL_CHUNKSIZE; - sl->sl_str = reallocarray(sl->sl_str, - sl->sl_max, sizeof(char *)); - if (sl->sl_str == NULL) - return (-1); - } - sl->sl_str[sl->sl_cur++] = name; - return (0); -} - - -/* - * sl_free(): Free a stringlist - */ -void -sl_free(StringList *sl, int all) -{ - size_t i; - - if (sl == NULL) - return; - if (sl->sl_str) { - if (all) - for (i = 0; i < sl->sl_cur; i++) - free(sl->sl_str[i]); - free(sl->sl_str); - } - free(sl); -} - - -/* - * sl_find(): Find a name in the string list - */ -char * -sl_find(StringList *sl, const char *name) -{ - size_t i; - - for (i = 0; i < sl->sl_cur; i++) - if (strcmp(sl->sl_str[i], name) == 0) - return sl->sl_str[i]; - - return NULL; -} - -#endif Property changes on: head/contrib/mdocml/compat_stringlist.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/main.c =================================================================== --- head/contrib/mdocml/main.c (revision 338825) +++ head/contrib/mdocml/main.c (nonexistent) @@ -1,1185 +0,0 @@ -/* $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; - 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 */ -}; - - -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 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 *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.mmin = MANDOCERR_MAX; - curp.outopts = &conf.output; - options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1; - 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 (curp.os_s != NULL) { - warnx("-I %s: Duplicate argument", optarg); - return (int)MANDOCLEVEL_BADARG; - } - 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.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. */ - (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(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) - 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 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); - - 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 1; - } else for (isec = 0; isec < nsec; isec++) - if (fs_lookup(paths, ipath, sections[isec], - cfg->arch, *argv, res, ressz) && - cfg->firstmatch) - return 1; - } - 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->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[11]; - - toks[0] = "stop"; - toks[1] = "all"; - 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->mmin = MANDOCERR_BASE; - break; - case 3: - curp->mmin = MANDOCERR_STYLE; - break; - case 4: - curp->mmin = MANDOCERR_WARNING; - break; - case 5: - curp->mmin = MANDOCERR_ERROR; - break; - case 6: - 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(mmsg_stream, "%s: %s:", getprogname(), - file == NULL ? "" : file); - - if (line) - fprintf(mmsg_stream, "%d:%d:", line, col + 1); - - fprintf(mmsg_stream, " %s", mparse_strlevel(lvl)); - - if ((mparse_msg = mparse_strerror(t)) != NULL) - fprintf(mmsg_stream, ": %s", mparse_msg); - - if (msg) - fprintf(mmsg_stream, ": %s", msg); - - fputc('\n', mmsg_stream); -} - -static pid_t -spawn_pager(struct tag_files *tag_files) -{ - 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 = "less -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]); -} Property changes on: head/contrib/mdocml/main.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-reallocarray.c =================================================================== --- head/contrib/mdocml/test-reallocarray.c (revision 338825) +++ head/contrib/mdocml/test-reallocarray.c (nonexistent) @@ -1,7 +0,0 @@ -#include - -int -main(void) -{ - return !reallocarray(NULL, 2, 2); -} Property changes on: head/contrib/mdocml/test-reallocarray.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_fts.c =================================================================== --- head/contrib/mdocml/compat_fts.c (revision 338825) +++ head/contrib/mdocml/compat_fts.c (nonexistent) @@ -1,701 +0,0 @@ -#include "config.h" - -#if HAVE_FTS - -int dummy; - -#else - -/* $Id: compat_fts.c,v 1.14 2017/02/18 12:24:24 schwarze Exp $ */ -/* $OpenBSD: fts.c,v 1.56 2016/09/21 04:38:56 guenther Exp $ */ - -/*- - * Copyright (c) 1990, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "compat_fts.h" - -#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) - -static FTSENT *fts_alloc(FTS *, const char *, size_t); -static FTSENT *fts_build(FTS *); -static void fts_lfree(FTSENT *); -static void fts_load(FTS *, FTSENT *); -static size_t fts_maxarglen(char * const *); -static void fts_padjust(FTS *, FTSENT *); -static int fts_palloc(FTS *, size_t); -static FTSENT *fts_sort(FTS *, FTSENT *, int); -static unsigned short fts_stat(FTS *, FTSENT *); - -#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -#define CLR(opt) (sp->fts_options &= ~(opt)) -#define ISSET(opt) (sp->fts_options & (opt)) -#define SET(opt) (sp->fts_options |= (opt)) - -FTS * -fts_open(char * const *argv, int options, - int (*compar)(const FTSENT **, const FTSENT **)) -{ - FTS *sp; - FTSENT *p, *root; - int nitems; - FTSENT *parent, *prev; - - /* Options check. */ - if (options & ~FTS_OPTIONMASK) { - errno = EINVAL; - return (NULL); - } - - /* At least one path must be specified. */ - if (*argv == NULL) { - errno = EINVAL; - return (NULL); - } - - /* Allocate/initialize the stream */ - if ((sp = calloc(1, sizeof(FTS))) == NULL) - return (NULL); - sp->fts_compar = compar; - sp->fts_options = options; - - /* - * Start out with 1K of path space, and enough, in any case, - * to hold the user's paths. - */ - if (fts_palloc(sp, MAXIMUM(fts_maxarglen(argv), PATH_MAX))) - goto mem1; - - /* Allocate/initialize root's parent. */ - if ((parent = fts_alloc(sp, "", 0)) == NULL) - goto mem2; - parent->fts_level = FTS_ROOTPARENTLEVEL; - - /* Allocate/initialize root(s). */ - for (root = prev = NULL, nitems = 0; *argv; ++argv, ++nitems) { - if ((p = fts_alloc(sp, *argv, strlen(*argv))) == NULL) - goto mem3; - p->fts_level = FTS_ROOTLEVEL; - p->fts_parent = parent; - p->fts_accpath = p->fts_name; - p->fts_info = fts_stat(sp, p); - - /* Command-line "." and ".." are real directories. */ - if (p->fts_info == FTS_DOT) - p->fts_info = FTS_D; - - /* - * If comparison routine supplied, traverse in sorted - * order; otherwise traverse in the order specified. - */ - if (compar) { - p->fts_link = root; - root = p; - } else { - p->fts_link = NULL; - if (root == NULL) - root = p; - else - prev->fts_link = p; - prev = p; - } - } - if (compar && nitems > 1) - root = fts_sort(sp, root, nitems); - - /* - * Allocate a dummy pointer and make fts_read think that we've just - * finished the node before the root(s); set p->fts_info to FTS_INIT - * so that everything about the "current" node is ignored. - */ - if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) - goto mem3; - sp->fts_cur->fts_link = root; - sp->fts_cur->fts_info = FTS_INIT; - - if (nitems == 0) - free(parent); - - return (sp); - -mem3: fts_lfree(root); - free(parent); -mem2: free(sp->fts_path); -mem1: free(sp); - return (NULL); -} - -static void -fts_load(FTS *sp, FTSENT *p) -{ - size_t len; - char *cp; - - /* - * Load the stream structure for the next traversal. Since we don't - * actually enter the directory until after the preorder visit, set - * the fts_accpath field specially so the chdir gets done to the right - * place and the user can access the first node. From fts_open it's - * known that the path will fit. - */ - len = p->fts_pathlen = p->fts_namelen; - memmove(sp->fts_path, p->fts_name, len + 1); - if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { - len = strlen(++cp); - memmove(p->fts_name, cp, len + 1); - p->fts_namelen = len; - } - p->fts_accpath = p->fts_path = sp->fts_path; - sp->fts_dev = p->fts_dev; -} - -int -fts_close(FTS *sp) -{ - FTSENT *freep, *p; - - /* - * This still works if we haven't read anything -- the dummy structure - * points to the root list, so we step through to the end of the root - * list which has a valid parent pointer. - */ - if (sp->fts_cur) { - for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { - freep = p; - p = p->fts_link ? p->fts_link : p->fts_parent; - free(freep); - } - free(p); - } - - /* Free up child linked list, sort array, path buffer, stream ptr.*/ - if (sp->fts_child) - fts_lfree(sp->fts_child); - free(sp->fts_array); - free(sp->fts_path); - free(sp); - - return (0); -} - -/* - * Special case of "/" at the end of the path so that slashes aren't - * appended which would cause paths to be written as "....//foo". - */ -#define NAPPEND(p) \ - (p->fts_path[p->fts_pathlen - 1] == '/' \ - ? p->fts_pathlen - 1 : p->fts_pathlen) - -FTSENT * -fts_read(FTS *sp) -{ - FTSENT *p, *tmp; - int instr; - char *t; - - /* If finished or unrecoverable error, return NULL. */ - if (sp->fts_cur == NULL || ISSET(FTS_STOP)) - return (NULL); - - /* Set current node pointer. */ - p = sp->fts_cur; - - /* Save and zero out user instructions. */ - instr = p->fts_instr; - p->fts_instr = FTS_NOINSTR; - - /* Directory in pre-order. */ - if (p->fts_info == FTS_D) { - /* If skipped or crossed mount point, do post-order visit. */ - if (instr == FTS_SKIP || - (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { - if (sp->fts_child) { - fts_lfree(sp->fts_child); - sp->fts_child = NULL; - } - p->fts_info = FTS_DP; - return (p); - } - - /* - * If haven't read do so. If the read fails, fts_build sets - * FTS_STOP or the fts_info field of the node. - */ - if (sp->fts_child) { - /* nothing */ - } else if ((sp->fts_child = fts_build(sp)) == NULL) { - if (ISSET(FTS_STOP)) - return (NULL); - return (p); - } - p = sp->fts_child; - sp->fts_child = NULL; - goto name; - } - - /* Move to the next node on this level. */ -next: tmp = p; - if ((p = p->fts_link)) { - free(tmp); - - /* - * If reached the top, return to the original directory (or - * the root of the tree), and load the paths for the next root. - */ - if (p->fts_level == FTS_ROOTLEVEL) { - fts_load(sp, p); - return (sp->fts_cur = p); - } - - /* - * User may have called fts_set on the node. If skipped, - * ignore. If followed, get a file descriptor so we can - * get back if necessary. - */ - if (p->fts_instr == FTS_SKIP) - goto next; - -name: t = sp->fts_path + NAPPEND(p->fts_parent); - *t++ = '/'; - memmove(t, p->fts_name, p->fts_namelen + 1); - return (sp->fts_cur = p); - } - - /* Move up to the parent node. */ - p = tmp->fts_parent; - free(tmp); - - if (p->fts_level == FTS_ROOTPARENTLEVEL) { - /* - * Done; free everything up and set errno to 0 so the user - * can distinguish between error and EOF. - */ - free(p); - errno = 0; - return (sp->fts_cur = NULL); - } - - /* NUL terminate the pathname. */ - sp->fts_path[p->fts_pathlen] = '\0'; - - p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; - return (sp->fts_cur = p); -} - -/* - * Fts_set takes the stream as an argument although it's not used in this - * implementation; it would be necessary if anyone wanted to add global - * semantics to fts using fts_set. An error return is allowed for similar - * reasons. - */ -int -fts_set(FTS *sp, FTSENT *p, int instr) -{ - if (instr && instr != FTS_NOINSTR && instr != FTS_SKIP) { - errno = EINVAL; - return (1); - } - p->fts_instr = instr; - return (0); -} - -/* - * This is the tricky part -- do not casually change *anything* in here. The - * idea is to build the linked list of entries that are used by fts_children - * and fts_read. There are lots of special cases. - * - * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is - * set and it's a physical walk (so that symbolic links can't be directories), - * we can do things quickly. First, if it's a 4.4BSD file system, the type - * of the file is in the directory entry. Otherwise, we assume that the number - * of subdirectories in a node is equal to the number of links to the parent. - * The former skips all stat calls. The latter skips stat calls in any leaf - * directories and for any files after the subdirectories in the directory have - * been found, cutting the stat calls by about 2/3. - */ -static FTSENT * -fts_build(FTS *sp) -{ - struct dirent *dp; - FTSENT *p, *head; - FTSENT *cur, *tail; - DIR *dirp; - void *oldaddr; - size_t dlen, len, maxlen; - int nitems, level, doadjust; - int saved_errno; - char *cp; - - /* Set current node pointer. */ - cur = sp->fts_cur; - - /* - * Open the directory for reading. If this fails, we're done. - * If being called from fts_read, set the fts_info field. - */ - if ((dirp = opendir(cur->fts_accpath)) == NULL) { - cur->fts_info = FTS_DNR; - cur->fts_errno = errno; - return (NULL); - } - - /* - * Figure out the max file name length that can be stored in the - * current path -- the inner loop allocates more path as necessary. - * We really wouldn't have to do the maxlen calculations here, we - * could do them in fts_read before returning the path, but it's a - * lot easier here since the length is part of the dirent structure. - * - * If not changing directories set a pointer so that can just append - * each new name into the path. - */ - len = NAPPEND(cur); - cp = sp->fts_path + len; - *cp++ = '/'; - len++; - maxlen = sp->fts_pathlen - len; - - /* - * fts_level is signed so we must prevent it from wrapping - * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL. - */ - level = cur->fts_level; - if (level < FTS_MAXLEVEL) - level++; - - /* Read the directory, attaching each entry to the `link' pointer. */ - doadjust = 0; - for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { - if (ISDOT(dp->d_name)) - continue; - -#if HAVE_DIRENT_NAMLEN - dlen = dp->d_namlen; -#else - dlen = strlen(dp->d_name); -#endif - - if (!(p = fts_alloc(sp, dp->d_name, dlen))) - goto mem1; - if (dlen >= maxlen) { /* include space for NUL */ - oldaddr = sp->fts_path; - if (fts_palloc(sp, dlen + len + 1)) { - /* - * No more memory for path or structures. Save - * errno, free up the current structure and the - * structures already allocated. - */ -mem1: saved_errno = errno; - free(p); - fts_lfree(head); - (void)closedir(dirp); - cur->fts_info = FTS_ERR; - SET(FTS_STOP); - errno = saved_errno; - return (NULL); - } - /* Did realloc() change the pointer? */ - if (oldaddr != sp->fts_path) { - doadjust = 1; - cp = sp->fts_path + len; - } - maxlen = sp->fts_pathlen - len; - } - - p->fts_level = level; - p->fts_parent = sp->fts_cur; - p->fts_pathlen = len + dlen; - if (p->fts_pathlen < len) { - /* - * If we wrap, free up the current structure and - * the structures already allocated, then error - * out with ENAMETOOLONG. - */ - free(p); - fts_lfree(head); - (void)closedir(dirp); - cur->fts_info = FTS_ERR; - SET(FTS_STOP); - errno = ENAMETOOLONG; - return (NULL); - } - - /* Build a file name for fts_stat to stat. */ - p->fts_accpath = p->fts_path; - memmove(cp, p->fts_name, p->fts_namelen + 1); - /* Stat it. */ - p->fts_info = fts_stat(sp, p); - - /* We walk in directory order so "ls -f" doesn't get upset. */ - p->fts_link = NULL; - if (head == NULL) - head = tail = p; - else { - tail->fts_link = p; - tail = p; - } - ++nitems; - } - if (dirp) - (void)closedir(dirp); - - /* - * If realloc() changed the address of the path, adjust the - * addresses for the rest of the tree and the dir list. - */ - if (doadjust) - fts_padjust(sp, head); - - /* - * If not changing directories, reset the path back to original - * state. - */ - if (len == sp->fts_pathlen || nitems == 0) - --cp; - *cp = '\0'; - - /* If didn't find anything, return NULL. */ - if (!nitems) { - cur->fts_info = FTS_DP; - return (NULL); - } - - /* Sort the entries. */ - if (sp->fts_compar && nitems > 1) - head = fts_sort(sp, head, nitems); - return (head); -} - -static unsigned short -fts_stat(FTS *sp, FTSENT *p) -{ - FTSENT *t; - dev_t dev; - ino_t ino; - struct stat *sbp; - - /* If user needs stat info, stat buffer already allocated. */ - sbp = p->fts_statp; - - if (lstat(p->fts_accpath, sbp)) { - p->fts_errno = errno; - memset(sbp, 0, sizeof(struct stat)); - return (FTS_NS); - } - - if (S_ISDIR(sbp->st_mode)) { - /* - * Set the device/inode. Used to find cycles and check for - * crossing mount points. Also remember the link count, used - * in fts_build to limit the number of stat calls. It is - * understood that these fields are only referenced if fts_info - * is set to FTS_D. - */ - dev = p->fts_dev = sbp->st_dev; - ino = p->fts_ino = sbp->st_ino; - p->fts_nlink = sbp->st_nlink; - - if (ISDOT(p->fts_name)) - return (FTS_DOT); - - /* - * Cycle detection is done by brute force when the directory - * is first encountered. If the tree gets deep enough or the - * number of symbolic links to directories is high enough, - * something faster might be worthwhile. - */ - for (t = p->fts_parent; - t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) - if (ino == t->fts_ino && dev == t->fts_dev) { - p->fts_cycle = t; - return (FTS_DC); - } - return (FTS_D); - } - if (S_ISLNK(sbp->st_mode)) - return (FTS_SL); - if (S_ISREG(sbp->st_mode)) - return (FTS_F); - return (FTS_DEFAULT); -} - -static FTSENT * -fts_sort(FTS *sp, FTSENT *head, int nitems) -{ - FTSENT **ap, *p; - - /* - * Construct an array of pointers to the structures and call qsort(3). - * Reassemble the array in the order returned by qsort. If unable to - * sort for memory reasons, return the directory entries in their - * current order. Allocate enough space for the current needs plus - * 40 so don't realloc one entry at a time. - */ - if (nitems > sp->fts_nitems) { - struct _ftsent **a; - - sp->fts_nitems = nitems + 40; - if ((a = reallocarray(sp->fts_array, - sp->fts_nitems, sizeof(FTSENT *))) == NULL) { - free(sp->fts_array); - sp->fts_array = NULL; - sp->fts_nitems = 0; - return (head); - } - sp->fts_array = a; - } - for (ap = sp->fts_array, p = head; p; p = p->fts_link) - *ap++ = p; - qsort(sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); - for (head = *(ap = sp->fts_array); --nitems; ++ap) - ap[0]->fts_link = ap[1]; - ap[0]->fts_link = NULL; - return (head); -} - -static FTSENT * -fts_alloc(FTS *sp, const char *name, size_t namelen) -{ - FTSENT *p; - size_t len; - - len = sizeof(FTSENT) + namelen; - if ((p = calloc(1, len)) == NULL) - return (NULL); - - p->fts_path = sp->fts_path; - p->fts_namelen = namelen; - p->fts_instr = FTS_NOINSTR; - p->fts_statp = malloc(sizeof(struct stat)); - if (p->fts_statp == NULL) { - free(p); - return (NULL); - } - memcpy(p->fts_name, name, namelen); - - return (p); -} - -static void -fts_lfree(FTSENT *head) -{ - FTSENT *p; - - /* Free a linked list of structures. */ - while ((p = head)) { - head = head->fts_link; - free(p); - } -} - -/* - * Allow essentially unlimited paths; find, rm, ls should all work on any tree. - * Most systems will allow creation of paths much longer than PATH_MAX, even - * though the kernel won't resolve them. Add the size (not just what's needed) - * plus 256 bytes so don't realloc the path 2 bytes at a time. - */ -static int -fts_palloc(FTS *sp, size_t more) -{ - char *p; - - /* - * Check for possible wraparound. - */ - more += 256; - if (sp->fts_pathlen + more < sp->fts_pathlen) { - free(sp->fts_path); - sp->fts_path = NULL; - errno = ENAMETOOLONG; - return (1); - } - sp->fts_pathlen += more; - p = realloc(sp->fts_path, sp->fts_pathlen); - if (p == NULL) { - free(sp->fts_path); - sp->fts_path = NULL; - return (1); - } - sp->fts_path = p; - return (0); -} - -/* - * When the path is realloc'd, have to fix all of the pointers in structures - * already returned. - */ -static void -fts_padjust(FTS *sp, FTSENT *head) -{ - FTSENT *p; - char *addr = sp->fts_path; - -#define ADJUST(p) { \ - if ((p)->fts_accpath != (p)->fts_name) { \ - (p)->fts_accpath = \ - (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ - } \ - (p)->fts_path = addr; \ -} - /* Adjust the current set of children. */ - for (p = sp->fts_child; p; p = p->fts_link) - ADJUST(p); - - /* Adjust the rest of the tree, including the current level. */ - for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { - ADJUST(p); - p = p->fts_link ? p->fts_link : p->fts_parent; - } -} - -static size_t -fts_maxarglen(char * const *argv) -{ - size_t len, max; - - for (max = 0; *argv; ++argv) - if ((len = strlen(*argv)) > max) - max = len; - return (max + 1); -} - -#endif Property changes on: head/contrib/mdocml/compat_fts.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/roff.c =================================================================== --- head/contrib/mdocml/roff.c (revision 338825) +++ head/contrib/mdocml/roff.c (nonexistent) @@ -1,3748 +0,0 @@ -/* $Id: roff.c,v 1.324 2017/07/14 17:16:16 schwarze Exp $ */ -/* - * Copyright (c) 2008-2012, 2014 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 -#include - -#include "mandoc.h" -#include "mandoc_aux.h" -#include "mandoc_ohash.h" -#include "roff.h" -#include "libmandoc.h" -#include "roff_int.h" -#include "libroff.h" - -/* Maximum number of string expansions per line, to break infinite loops. */ -#define EXPAND_LIMIT 1000 - -/* Types of definitions of macros and strings. */ -#define ROFFDEF_USER (1 << 1) /* User-defined. */ -#define ROFFDEF_PRE (1 << 2) /* Predefined. */ -#define ROFFDEF_REN (1 << 3) /* Renamed standard macro. */ -#define ROFFDEF_STD (1 << 4) /* mdoc(7) or man(7) macro. */ -#define ROFFDEF_ANY (ROFFDEF_USER | ROFFDEF_PRE | \ - ROFFDEF_REN | ROFFDEF_STD) - -/* --- data types --------------------------------------------------------- */ - -/* - * An incredibly-simple string buffer. - */ -struct roffstr { - char *p; /* nil-terminated buffer */ - size_t sz; /* saved strlen(p) */ -}; - -/* - * A key-value roffstr pair as part of a singly-linked list. - */ -struct roffkv { - struct roffstr key; - struct roffstr val; - struct roffkv *next; /* next in list */ -}; - -/* - * A single number register as part of a singly-linked list. - */ -struct roffreg { - struct roffstr key; - int val; - struct roffreg *next; -}; - -/* - * Association of request and macro names with token IDs. - */ -struct roffreq { - enum roff_tok tok; - char name[]; -}; - -struct roff { - struct mparse *parse; /* parse point */ - struct roff_man *man; /* mdoc or man parser */ - struct roffnode *last; /* leaf of stack */ - int *rstack; /* stack of inverted `ie' values */ - struct ohash *reqtab; /* request lookup table */ - struct roffreg *regtab; /* number registers */ - struct roffkv *strtab; /* user-defined strings & macros */ - struct roffkv *rentab; /* renamed strings & macros */ - struct roffkv *xmbtab; /* multi-byte trans table (`tr') */ - struct roffstr *xtab; /* single-byte trans table (`tr') */ - const char *current_string; /* value of last called user macro */ - struct tbl_node *first_tbl; /* first table parsed */ - struct tbl_node *last_tbl; /* last table parsed */ - struct tbl_node *tbl; /* current table being parsed */ - struct eqn_node *last_eqn; /* equation parser */ - struct eqn_node *eqn; /* active equation parser */ - int eqn_inline; /* current equation is inline */ - int options; /* parse options */ - int rstacksz; /* current size limit of rstack */ - int rstackpos; /* position in rstack */ - int format; /* current file in mdoc or man format */ - int argc; /* number of args of the last macro */ - char control; /* control character */ - char escape; /* escape character */ -}; - -struct roffnode { - enum roff_tok tok; /* type of node */ - struct roffnode *parent; /* up one in stack */ - int line; /* parse line */ - int col; /* parse col */ - char *name; /* node name, e.g. macro name */ - char *end; /* end-rules: custom token */ - int endspan; /* end-rules: next-line or infty */ - int rule; /* current evaluation rule */ -}; - -#define ROFF_ARGS struct roff *r, /* parse ctx */ \ - enum roff_tok tok, /* tok of macro */ \ - struct buf *buf, /* input buffer */ \ - int ln, /* parse line */ \ - int ppos, /* original pos in buffer */ \ - int pos, /* current pos in buffer */ \ - int *offs /* reset offset of buffer data */ - -typedef enum rofferr (*roffproc)(ROFF_ARGS); - -struct roffmac { - roffproc proc; /* process new macro */ - roffproc text; /* process as child text of macro */ - roffproc sub; /* process as child of macro */ - int flags; -#define ROFFMAC_STRUCT (1 << 0) /* always interpret */ -}; - -struct predef { - const char *name; /* predefined input name */ - const char *str; /* replacement symbol */ -}; - -#define PREDEF(__name, __str) \ - { (__name), (__str) }, - -/* --- function prototypes ------------------------------------------------ */ - -static void roffnode_cleanscope(struct roff *); -static void roffnode_pop(struct roff *); -static void roffnode_push(struct roff *, enum roff_tok, - const char *, int, int); -static void roff_addtbl(struct roff_man *, struct tbl_node *); -static enum rofferr roff_als(ROFF_ARGS); -static enum rofferr roff_block(ROFF_ARGS); -static enum rofferr roff_block_text(ROFF_ARGS); -static enum rofferr roff_block_sub(ROFF_ARGS); -static enum rofferr roff_br(ROFF_ARGS); -static enum rofferr roff_cblock(ROFF_ARGS); -static enum rofferr roff_cc(ROFF_ARGS); -static void roff_ccond(struct roff *, int, int); -static enum rofferr roff_cond(ROFF_ARGS); -static enum rofferr roff_cond_text(ROFF_ARGS); -static enum rofferr roff_cond_sub(ROFF_ARGS); -static enum rofferr roff_ds(ROFF_ARGS); -static enum rofferr roff_ec(ROFF_ARGS); -static enum rofferr roff_eo(ROFF_ARGS); -static enum rofferr roff_eqndelim(struct roff *, struct buf *, int); -static int roff_evalcond(struct roff *r, int, char *, int *); -static int roff_evalnum(struct roff *, int, - const char *, int *, int *, int); -static int roff_evalpar(struct roff *, int, - const char *, int *, int *, int); -static int roff_evalstrcond(const char *, int *); -static void roff_free1(struct roff *); -static void roff_freereg(struct roffreg *); -static void roff_freestr(struct roffkv *); -static size_t roff_getname(struct roff *, char **, int, int); -static int roff_getnum(const char *, int *, int *, int); -static int roff_getop(const char *, int *, char *); -static int roff_getregn(const struct roff *, - const char *, size_t); -static int roff_getregro(const struct roff *, - const char *name); -static const char *roff_getstrn(const struct roff *, - const char *, size_t, int *); -static int roff_hasregn(const struct roff *, - const char *, size_t); -static enum rofferr roff_insec(ROFF_ARGS); -static enum rofferr roff_it(ROFF_ARGS); -static enum rofferr roff_line_ignore(ROFF_ARGS); -static void roff_man_alloc1(struct roff_man *); -static void roff_man_free1(struct roff_man *); -static enum rofferr roff_manyarg(ROFF_ARGS); -static enum rofferr roff_nr(ROFF_ARGS); -static enum rofferr roff_onearg(ROFF_ARGS); -static enum roff_tok roff_parse(struct roff *, char *, int *, - int, int); -static enum rofferr roff_parsetext(struct roff *, struct buf *, - int, int *); -static enum rofferr roff_renamed(ROFF_ARGS); -static enum rofferr roff_res(struct roff *, struct buf *, int, int); -static enum rofferr roff_rm(ROFF_ARGS); -static enum rofferr roff_rn(ROFF_ARGS); -static enum rofferr roff_rr(ROFF_ARGS); -static void roff_setstr(struct roff *, - const char *, const char *, int); -static void roff_setstrn(struct roffkv **, const char *, - size_t, const char *, size_t, int); -static enum rofferr roff_so(ROFF_ARGS); -static enum rofferr roff_tr(ROFF_ARGS); -static enum rofferr roff_Dd(ROFF_ARGS); -static enum rofferr roff_TE(ROFF_ARGS); -static enum rofferr roff_TS(ROFF_ARGS); -static enum rofferr roff_EQ(ROFF_ARGS); -static enum rofferr roff_EN(ROFF_ARGS); -static enum rofferr roff_T_(ROFF_ARGS); -static enum rofferr roff_unsupp(ROFF_ARGS); -static enum rofferr roff_userdef(ROFF_ARGS); - -/* --- constant data ------------------------------------------------------ */ - -#define ROFFNUM_SCALE (1 << 0) /* Honour scaling in roff_getnum(). */ -#define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */ - -const char *__roff_name[MAN_MAX + 1] = { - "br", "ce", "ft", "ll", - "mc", "po", "rj", "sp", - "ta", "ti", NULL, - "ab", "ad", "af", "aln", - "als", "am", "am1", "ami", - "ami1", "as", "as1", "asciify", - "backtrace", "bd", "bleedat", "blm", - "box", "boxa", "bp", "BP", - "break", "breakchar", "brnl", "brp", - "brpnl", "c2", "cc", - "cf", "cflags", "ch", "char", - "chop", "class", "close", "CL", - "color", "composite", "continue", "cp", - "cropat", "cs", "cu", "da", - "dch", "Dd", "de", "de1", - "defcolor", "dei", "dei1", "device", - "devicem", "di", "do", "ds", - "ds1", "dwh", "dt", "ec", - "ecr", "ecs", "el", "em", - "EN", "eo", "EP", "EQ", - "errprint", "ev", "evc", "ex", - "fallback", "fam", "fc", "fchar", - "fcolor", "fdeferlig", "feature", "fkern", - "fl", "flig", "fp", "fps", - "fschar", "fspacewidth", "fspecial", "ftr", - "fzoom", "gcolor", "hc", "hcode", - "hidechar", "hla", "hlm", "hpf", - "hpfa", "hpfcode", "hw", "hy", - "hylang", "hylen", "hym", "hypp", - "hys", "ie", "if", "ig", - "index", "it", "itc", "IX", - "kern", "kernafter", "kernbefore", "kernpair", - "lc", "lc_ctype", "lds", "length", - "letadj", "lf", "lg", "lhang", - "linetabs", "lnr", "lnrf", "lpfx", - "ls", "lsm", "lt", - "mediasize", "minss", "mk", "mso", - "na", "ne", "nh", "nhychar", - "nm", "nn", "nop", "nr", - "nrf", "nroff", "ns", "nx", - "open", "opena", "os", "output", - "padj", "papersize", "pc", "pev", - "pi", "PI", "pl", "pm", - "pn", "pnr", "ps", - "psbb", "pshape", "pso", "ptr", - "pvs", "rchar", "rd", "recursionlimit", - "return", "rfschar", "rhang", - "rm", "rn", "rnn", "rr", - "rs", "rt", "schar", "sentchar", - "shc", "shift", "sizes", "so", - "spacewidth", "special", "spreadwarn", "ss", - "sty", "substring", "sv", "sy", - "T&", "tc", "TE", - "TH", "tkf", "tl", - "tm", "tm1", "tmc", "tr", - "track", "transchar", "trf", "trimat", - "trin", "trnt", "troff", "TS", - "uf", "ul", "unformat", "unwatch", - "unwatchn", "vpt", "vs", "warn", - "warnscale", "watch", "watchlength", "watchn", - "wh", "while", "write", "writec", - "writem", "xflag", ".", NULL, - NULL, "text", - "Dd", "Dt", "Os", "Sh", - "Ss", "Pp", "D1", "Dl", - "Bd", "Ed", "Bl", "El", - "It", "Ad", "An", "Ap", - "Ar", "Cd", "Cm", "Dv", - "Er", "Ev", "Ex", "Fa", - "Fd", "Fl", "Fn", "Ft", - "Ic", "In", "Li", "Nd", - "Nm", "Op", "Ot", "Pa", - "Rv", "St", "Va", "Vt", - "Xr", "%A", "%B", "%D", - "%I", "%J", "%N", "%O", - "%P", "%R", "%T", "%V", - "Ac", "Ao", "Aq", "At", - "Bc", "Bf", "Bo", "Bq", - "Bsx", "Bx", "Db", "Dc", - "Do", "Dq", "Ec", "Ef", - "Em", "Eo", "Fx", "Ms", - "No", "Ns", "Nx", "Ox", - "Pc", "Pf", "Po", "Pq", - "Qc", "Ql", "Qo", "Qq", - "Re", "Rs", "Sc", "So", - "Sq", "Sm", "Sx", "Sy", - "Tn", "Ux", "Xc", "Xo", - "Fo", "Fc", "Oo", "Oc", - "Bk", "Ek", "Bt", "Hf", - "Fr", "Ud", "Lb", "Lp", - "Lk", "Mt", "Brq", "Bro", - "Brc", "%C", "Es", "En", - "Dx", "%Q", "%U", "Ta", - NULL, - "TH", "SH", "SS", "TP", - "LP", "PP", "P", "IP", - "HP", "SM", "SB", "BI", - "IB", "BR", "RB", "R", - "B", "I", "IR", "RI", - "nf", "fi", - "RE", "RS", "DT", "UC", - "PD", "AT", "in", - "OP", "EX", "EE", "UR", - "UE", "MT", "ME", NULL -}; -const char *const *roff_name = __roff_name; - -static struct roffmac roffs[TOKEN_NONE] = { - { roff_br, NULL, NULL, 0 }, /* br */ - { roff_onearg, NULL, NULL, 0 }, /* ce */ - { roff_onearg, NULL, NULL, 0 }, /* ft */ - { roff_onearg, NULL, NULL, 0 }, /* ll */ - { roff_onearg, NULL, NULL, 0 }, /* mc */ - { roff_onearg, NULL, NULL, 0 }, /* po */ - { roff_onearg, NULL, NULL, 0 }, /* rj */ - { roff_onearg, NULL, NULL, 0 }, /* sp */ - { roff_manyarg, NULL, NULL, 0 }, /* ta */ - { roff_onearg, NULL, NULL, 0 }, /* ti */ - { NULL, NULL, NULL, 0 }, /* ROFF_MAX */ - { roff_unsupp, NULL, NULL, 0 }, /* ab */ - { roff_line_ignore, NULL, NULL, 0 }, /* ad */ - { roff_line_ignore, NULL, NULL, 0 }, /* af */ - { roff_unsupp, NULL, NULL, 0 }, /* aln */ - { roff_als, NULL, NULL, 0 }, /* als */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* am */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* am1 */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami1 */ - { roff_ds, NULL, NULL, 0 }, /* as */ - { roff_ds, NULL, NULL, 0 }, /* as1 */ - { roff_unsupp, NULL, NULL, 0 }, /* asciify */ - { roff_line_ignore, NULL, NULL, 0 }, /* backtrace */ - { roff_line_ignore, NULL, NULL, 0 }, /* bd */ - { roff_line_ignore, NULL, NULL, 0 }, /* bleedat */ - { roff_unsupp, NULL, NULL, 0 }, /* blm */ - { roff_unsupp, NULL, NULL, 0 }, /* box */ - { roff_unsupp, NULL, NULL, 0 }, /* boxa */ - { roff_line_ignore, NULL, NULL, 0 }, /* bp */ - { roff_unsupp, NULL, NULL, 0 }, /* BP */ - { roff_unsupp, NULL, NULL, 0 }, /* break */ - { roff_line_ignore, NULL, NULL, 0 }, /* breakchar */ - { roff_line_ignore, NULL, NULL, 0 }, /* brnl */ - { roff_br, NULL, NULL, 0 }, /* brp */ - { roff_line_ignore, NULL, NULL, 0 }, /* brpnl */ - { roff_unsupp, NULL, NULL, 0 }, /* c2 */ - { roff_cc, NULL, NULL, 0 }, /* cc */ - { roff_insec, NULL, NULL, 0 }, /* cf */ - { roff_line_ignore, NULL, NULL, 0 }, /* cflags */ - { roff_line_ignore, NULL, NULL, 0 }, /* ch */ - { roff_unsupp, NULL, NULL, 0 }, /* char */ - { roff_unsupp, NULL, NULL, 0 }, /* chop */ - { roff_line_ignore, NULL, NULL, 0 }, /* class */ - { roff_insec, NULL, NULL, 0 }, /* close */ - { roff_unsupp, NULL, NULL, 0 }, /* CL */ - { roff_line_ignore, NULL, NULL, 0 }, /* color */ - { roff_unsupp, NULL, NULL, 0 }, /* composite */ - { roff_unsupp, NULL, NULL, 0 }, /* continue */ - { roff_line_ignore, NULL, NULL, 0 }, /* cp */ - { roff_line_ignore, NULL, NULL, 0 }, /* cropat */ - { roff_line_ignore, NULL, NULL, 0 }, /* cs */ - { roff_line_ignore, NULL, NULL, 0 }, /* cu */ - { roff_unsupp, NULL, NULL, 0 }, /* da */ - { roff_unsupp, NULL, NULL, 0 }, /* dch */ - { roff_Dd, NULL, NULL, 0 }, /* Dd */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* de */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* de1 */ - { roff_line_ignore, NULL, NULL, 0 }, /* defcolor */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* dei */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* dei1 */ - { roff_unsupp, NULL, NULL, 0 }, /* device */ - { roff_unsupp, NULL, NULL, 0 }, /* devicem */ - { roff_unsupp, NULL, NULL, 0 }, /* di */ - { roff_unsupp, NULL, NULL, 0 }, /* do */ - { roff_ds, NULL, NULL, 0 }, /* ds */ - { roff_ds, NULL, NULL, 0 }, /* ds1 */ - { roff_unsupp, NULL, NULL, 0 }, /* dwh */ - { roff_unsupp, NULL, NULL, 0 }, /* dt */ - { roff_ec, NULL, NULL, 0 }, /* ec */ - { roff_unsupp, NULL, NULL, 0 }, /* ecr */ - { roff_unsupp, NULL, NULL, 0 }, /* ecs */ - { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* el */ - { roff_unsupp, NULL, NULL, 0 }, /* em */ - { roff_EN, NULL, NULL, 0 }, /* EN */ - { roff_eo, NULL, NULL, 0 }, /* eo */ - { roff_unsupp, NULL, NULL, 0 }, /* EP */ - { roff_EQ, NULL, NULL, 0 }, /* EQ */ - { roff_line_ignore, NULL, NULL, 0 }, /* errprint */ - { roff_unsupp, NULL, NULL, 0 }, /* ev */ - { roff_unsupp, NULL, NULL, 0 }, /* evc */ - { roff_unsupp, NULL, NULL, 0 }, /* ex */ - { roff_line_ignore, NULL, NULL, 0 }, /* fallback */ - { roff_line_ignore, NULL, NULL, 0 }, /* fam */ - { roff_unsupp, NULL, NULL, 0 }, /* fc */ - { roff_unsupp, NULL, NULL, 0 }, /* fchar */ - { roff_line_ignore, NULL, NULL, 0 }, /* fcolor */ - { roff_line_ignore, NULL, NULL, 0 }, /* fdeferlig */ - { roff_line_ignore, NULL, NULL, 0 }, /* feature */ - { roff_line_ignore, NULL, NULL, 0 }, /* fkern */ - { roff_line_ignore, NULL, NULL, 0 }, /* fl */ - { roff_line_ignore, NULL, NULL, 0 }, /* flig */ - { roff_line_ignore, NULL, NULL, 0 }, /* fp */ - { roff_line_ignore, NULL, NULL, 0 }, /* fps */ - { roff_unsupp, NULL, NULL, 0 }, /* fschar */ - { roff_line_ignore, NULL, NULL, 0 }, /* fspacewidth */ - { roff_line_ignore, NULL, NULL, 0 }, /* fspecial */ - { roff_line_ignore, NULL, NULL, 0 }, /* ftr */ - { roff_line_ignore, NULL, NULL, 0 }, /* fzoom */ - { roff_line_ignore, NULL, NULL, 0 }, /* gcolor */ - { roff_line_ignore, NULL, NULL, 0 }, /* hc */ - { roff_line_ignore, NULL, NULL, 0 }, /* hcode */ - { roff_line_ignore, NULL, NULL, 0 }, /* hidechar */ - { roff_line_ignore, NULL, NULL, 0 }, /* hla */ - { roff_line_ignore, NULL, NULL, 0 }, /* hlm */ - { roff_line_ignore, NULL, NULL, 0 }, /* hpf */ - { roff_line_ignore, NULL, NULL, 0 }, /* hpfa */ - { roff_line_ignore, NULL, NULL, 0 }, /* hpfcode */ - { roff_line_ignore, NULL, NULL, 0 }, /* hw */ - { roff_line_ignore, NULL, NULL, 0 }, /* hy */ - { roff_line_ignore, NULL, NULL, 0 }, /* hylang */ - { roff_line_ignore, NULL, NULL, 0 }, /* hylen */ - { roff_line_ignore, NULL, NULL, 0 }, /* hym */ - { roff_line_ignore, NULL, NULL, 0 }, /* hypp */ - { roff_line_ignore, NULL, NULL, 0 }, /* hys */ - { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* ie */ - { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* if */ - { roff_block, roff_block_text, roff_block_sub, 0 }, /* ig */ - { roff_unsupp, NULL, NULL, 0 }, /* index */ - { roff_it, NULL, NULL, 0 }, /* it */ - { roff_unsupp, NULL, NULL, 0 }, /* itc */ - { roff_line_ignore, NULL, NULL, 0 }, /* IX */ - { roff_line_ignore, NULL, NULL, 0 }, /* kern */ - { roff_line_ignore, NULL, NULL, 0 }, /* kernafter */ - { roff_line_ignore, NULL, NULL, 0 }, /* kernbefore */ - { roff_line_ignore, NULL, NULL, 0 }, /* kernpair */ - { roff_unsupp, NULL, NULL, 0 }, /* lc */ - { roff_unsupp, NULL, NULL, 0 }, /* lc_ctype */ - { roff_unsupp, NULL, NULL, 0 }, /* lds */ - { roff_unsupp, NULL, NULL, 0 }, /* length */ - { roff_line_ignore, NULL, NULL, 0 }, /* letadj */ - { roff_insec, NULL, NULL, 0 }, /* lf */ - { roff_line_ignore, NULL, NULL, 0 }, /* lg */ - { roff_line_ignore, NULL, NULL, 0 }, /* lhang */ - { roff_unsupp, NULL, NULL, 0 }, /* linetabs */ - { roff_unsupp, NULL, NULL, 0 }, /* lnr */ - { roff_unsupp, NULL, NULL, 0 }, /* lnrf */ - { roff_unsupp, NULL, NULL, 0 }, /* lpfx */ - { roff_line_ignore, NULL, NULL, 0 }, /* ls */ - { roff_unsupp, NULL, NULL, 0 }, /* lsm */ - { roff_line_ignore, NULL, NULL, 0 }, /* lt */ - { roff_line_ignore, NULL, NULL, 0 }, /* mediasize */ - { roff_line_ignore, NULL, NULL, 0 }, /* minss */ - { roff_line_ignore, NULL, NULL, 0 }, /* mk */ - { roff_insec, NULL, NULL, 0 }, /* mso */ - { roff_line_ignore, NULL, NULL, 0 }, /* na */ - { roff_line_ignore, NULL, NULL, 0 }, /* ne */ - { roff_line_ignore, NULL, NULL, 0 }, /* nh */ - { roff_line_ignore, NULL, NULL, 0 }, /* nhychar */ - { roff_unsupp, NULL, NULL, 0 }, /* nm */ - { roff_unsupp, NULL, NULL, 0 }, /* nn */ - { roff_unsupp, NULL, NULL, 0 }, /* nop */ - { roff_nr, NULL, NULL, 0 }, /* nr */ - { roff_unsupp, NULL, NULL, 0 }, /* nrf */ - { roff_line_ignore, NULL, NULL, 0 }, /* nroff */ - { roff_line_ignore, NULL, NULL, 0 }, /* ns */ - { roff_insec, NULL, NULL, 0 }, /* nx */ - { roff_insec, NULL, NULL, 0 }, /* open */ - { roff_insec, NULL, NULL, 0 }, /* opena */ - { roff_line_ignore, NULL, NULL, 0 }, /* os */ - { roff_unsupp, NULL, NULL, 0 }, /* output */ - { roff_line_ignore, NULL, NULL, 0 }, /* padj */ - { roff_line_ignore, NULL, NULL, 0 }, /* papersize */ - { roff_line_ignore, NULL, NULL, 0 }, /* pc */ - { roff_line_ignore, NULL, NULL, 0 }, /* pev */ - { roff_insec, NULL, NULL, 0 }, /* pi */ - { roff_unsupp, NULL, NULL, 0 }, /* PI */ - { roff_line_ignore, NULL, NULL, 0 }, /* pl */ - { roff_line_ignore, NULL, NULL, 0 }, /* pm */ - { roff_line_ignore, NULL, NULL, 0 }, /* pn */ - { roff_line_ignore, NULL, NULL, 0 }, /* pnr */ - { roff_line_ignore, NULL, NULL, 0 }, /* ps */ - { roff_unsupp, NULL, NULL, 0 }, /* psbb */ - { roff_unsupp, NULL, NULL, 0 }, /* pshape */ - { roff_insec, NULL, NULL, 0 }, /* pso */ - { roff_line_ignore, NULL, NULL, 0 }, /* ptr */ - { roff_line_ignore, NULL, NULL, 0 }, /* pvs */ - { roff_unsupp, NULL, NULL, 0 }, /* rchar */ - { roff_line_ignore, NULL, NULL, 0 }, /* rd */ - { roff_line_ignore, NULL, NULL, 0 }, /* recursionlimit */ - { roff_unsupp, NULL, NULL, 0 }, /* return */ - { roff_unsupp, NULL, NULL, 0 }, /* rfschar */ - { roff_line_ignore, NULL, NULL, 0 }, /* rhang */ - { roff_rm, NULL, NULL, 0 }, /* rm */ - { roff_rn, NULL, NULL, 0 }, /* rn */ - { roff_unsupp, NULL, NULL, 0 }, /* rnn */ - { roff_rr, NULL, NULL, 0 }, /* rr */ - { roff_line_ignore, NULL, NULL, 0 }, /* rs */ - { roff_line_ignore, NULL, NULL, 0 }, /* rt */ - { roff_unsupp, NULL, NULL, 0 }, /* schar */ - { roff_line_ignore, NULL, NULL, 0 }, /* sentchar */ - { roff_line_ignore, NULL, NULL, 0 }, /* shc */ - { roff_unsupp, NULL, NULL, 0 }, /* shift */ - { roff_line_ignore, NULL, NULL, 0 }, /* sizes */ - { roff_so, NULL, NULL, 0 }, /* so */ - { roff_line_ignore, NULL, NULL, 0 }, /* spacewidth */ - { roff_line_ignore, NULL, NULL, 0 }, /* special */ - { roff_line_ignore, NULL, NULL, 0 }, /* spreadwarn */ - { roff_line_ignore, NULL, NULL, 0 }, /* ss */ - { roff_line_ignore, NULL, NULL, 0 }, /* sty */ - { roff_unsupp, NULL, NULL, 0 }, /* substring */ - { roff_line_ignore, NULL, NULL, 0 }, /* sv */ - { roff_insec, NULL, NULL, 0 }, /* sy */ - { roff_T_, NULL, NULL, 0 }, /* T& */ - { roff_unsupp, NULL, NULL, 0 }, /* tc */ - { roff_TE, NULL, NULL, 0 }, /* TE */ - { roff_Dd, NULL, NULL, 0 }, /* TH */ - { roff_line_ignore, NULL, NULL, 0 }, /* tkf */ - { roff_unsupp, NULL, NULL, 0 }, /* tl */ - { roff_line_ignore, NULL, NULL, 0 }, /* tm */ - { roff_line_ignore, NULL, NULL, 0 }, /* tm1 */ - { roff_line_ignore, NULL, NULL, 0 }, /* tmc */ - { roff_tr, NULL, NULL, 0 }, /* tr */ - { roff_line_ignore, NULL, NULL, 0 }, /* track */ - { roff_line_ignore, NULL, NULL, 0 }, /* transchar */ - { roff_insec, NULL, NULL, 0 }, /* trf */ - { roff_line_ignore, NULL, NULL, 0 }, /* trimat */ - { roff_unsupp, NULL, NULL, 0 }, /* trin */ - { roff_unsupp, NULL, NULL, 0 }, /* trnt */ - { roff_line_ignore, NULL, NULL, 0 }, /* troff */ - { roff_TS, NULL, NULL, 0 }, /* TS */ - { roff_line_ignore, NULL, NULL, 0 }, /* uf */ - { roff_line_ignore, NULL, NULL, 0 }, /* ul */ - { roff_unsupp, NULL, NULL, 0 }, /* unformat */ - { roff_line_ignore, NULL, NULL, 0 }, /* unwatch */ - { roff_line_ignore, NULL, NULL, 0 }, /* unwatchn */ - { roff_line_ignore, NULL, NULL, 0 }, /* vpt */ - { roff_line_ignore, NULL, NULL, 0 }, /* vs */ - { roff_line_ignore, NULL, NULL, 0 }, /* warn */ - { roff_line_ignore, NULL, NULL, 0 }, /* warnscale */ - { roff_line_ignore, NULL, NULL, 0 }, /* watch */ - { roff_line_ignore, NULL, NULL, 0 }, /* watchlength */ - { roff_line_ignore, NULL, NULL, 0 }, /* watchn */ - { roff_unsupp, NULL, NULL, 0 }, /* wh */ - { roff_unsupp, NULL, NULL, 0 }, /* while */ - { roff_insec, NULL, NULL, 0 }, /* write */ - { roff_insec, NULL, NULL, 0 }, /* writec */ - { roff_insec, NULL, NULL, 0 }, /* writem */ - { roff_line_ignore, NULL, NULL, 0 }, /* xflag */ - { roff_cblock, NULL, NULL, 0 }, /* . */ - { roff_renamed, NULL, NULL, 0 }, - { roff_userdef, NULL, NULL, 0 } -}; - -/* Array of injected predefined strings. */ -#define PREDEFS_MAX 38 -static const struct predef predefs[PREDEFS_MAX] = { -#include "predefs.in" -}; - -static int roffce_lines; /* number of input lines to center */ -static struct roff_node *roffce_node; /* active request */ -static int roffit_lines; /* number of lines to delay */ -static char *roffit_macro; /* nil-terminated macro line */ - - -/* --- request table ------------------------------------------------------ */ - -struct ohash * -roffhash_alloc(enum roff_tok mintok, enum roff_tok maxtok) -{ - struct ohash *htab; - struct roffreq *req; - enum roff_tok tok; - size_t sz; - unsigned int slot; - - htab = mandoc_malloc(sizeof(*htab)); - mandoc_ohash_init(htab, 8, offsetof(struct roffreq, name)); - - for (tok = mintok; tok < maxtok; tok++) { - if (roff_name[tok] == NULL) - continue; - sz = strlen(roff_name[tok]); - req = mandoc_malloc(sizeof(*req) + sz + 1); - req->tok = tok; - memcpy(req->name, roff_name[tok], sz + 1); - slot = ohash_qlookup(htab, req->name); - ohash_insert(htab, slot, req); - } - return htab; -} - -void -roffhash_free(struct ohash *htab) -{ - struct roffreq *req; - unsigned int slot; - - if (htab == NULL) - return; - for (req = ohash_first(htab, &slot); req != NULL; - req = ohash_next(htab, &slot)) - free(req); - ohash_delete(htab); - free(htab); -} - -enum roff_tok -roffhash_find(struct ohash *htab, const char *name, size_t sz) -{ - struct roffreq *req; - const char *end; - - if (sz) { - end = name + sz; - req = ohash_find(htab, ohash_qlookupi(htab, name, &end)); - } else - req = ohash_find(htab, ohash_qlookup(htab, name)); - return req == NULL ? TOKEN_NONE : req->tok; -} - -/* --- stack of request blocks -------------------------------------------- */ - -/* - * Pop the current node off of the stack of roff instructions currently - * pending. - */ -static void -roffnode_pop(struct roff *r) -{ - struct roffnode *p; - - assert(r->last); - p = r->last; - - r->last = r->last->parent; - free(p->name); - free(p->end); - free(p); -} - -/* - * Push a roff node onto the instruction stack. This must later be - * removed with roffnode_pop(). - */ -static void -roffnode_push(struct roff *r, enum roff_tok tok, const char *name, - int line, int col) -{ - struct roffnode *p; - - p = mandoc_calloc(1, sizeof(struct roffnode)); - p->tok = tok; - if (name) - p->name = mandoc_strdup(name); - p->parent = r->last; - p->line = line; - p->col = col; - p->rule = p->parent ? p->parent->rule : 0; - - r->last = p; -} - -/* --- roff parser state data management ---------------------------------- */ - -static void -roff_free1(struct roff *r) -{ - struct tbl_node *tbl; - int i; - - while (NULL != (tbl = r->first_tbl)) { - r->first_tbl = tbl->next; - tbl_free(tbl); - } - r->first_tbl = r->last_tbl = r->tbl = NULL; - - if (r->last_eqn != NULL) - eqn_free(r->last_eqn); - r->last_eqn = r->eqn = NULL; - - while (r->last) - roffnode_pop(r); - - free (r->rstack); - r->rstack = NULL; - r->rstacksz = 0; - r->rstackpos = -1; - - roff_freereg(r->regtab); - r->regtab = NULL; - - roff_freestr(r->strtab); - roff_freestr(r->rentab); - roff_freestr(r->xmbtab); - r->strtab = r->rentab = r->xmbtab = NULL; - - if (r->xtab) - for (i = 0; i < 128; i++) - free(r->xtab[i].p); - free(r->xtab); - r->xtab = NULL; -} - -void -roff_reset(struct roff *r) -{ - roff_free1(r); - r->format = r->options & (MPARSE_MDOC | MPARSE_MAN); - r->control = '\0'; - r->escape = '\\'; - roffce_lines = 0; - roffce_node = NULL; - roffit_lines = 0; - roffit_macro = NULL; -} - -void -roff_free(struct roff *r) -{ - roff_free1(r); - roffhash_free(r->reqtab); - free(r); -} - -struct roff * -roff_alloc(struct mparse *parse, int options) -{ - struct roff *r; - - r = mandoc_calloc(1, sizeof(struct roff)); - r->parse = parse; - r->reqtab = roffhash_alloc(0, ROFF_USERDEF); - r->options = options; - r->format = options & (MPARSE_MDOC | MPARSE_MAN); - r->rstackpos = -1; - r->escape = '\\'; - return r; -} - -/* --- syntax tree state data management ---------------------------------- */ - -static void -roff_man_free1(struct roff_man *man) -{ - - if (man->first != NULL) - roff_node_delete(man, man->first); - free(man->meta.msec); - free(man->meta.vol); - free(man->meta.os); - free(man->meta.arch); - free(man->meta.title); - free(man->meta.name); - free(man->meta.date); -} - -static void -roff_man_alloc1(struct roff_man *man) -{ - - memset(&man->meta, 0, sizeof(man->meta)); - man->first = mandoc_calloc(1, sizeof(*man->first)); - man->first->type = ROFFT_ROOT; - man->last = man->first; - man->last_es = NULL; - man->flags = 0; - man->macroset = MACROSET_NONE; - man->lastsec = man->lastnamed = SEC_NONE; - man->next = ROFF_NEXT_CHILD; -} - -void -roff_man_reset(struct roff_man *man) -{ - - roff_man_free1(man); - roff_man_alloc1(man); -} - -void -roff_man_free(struct roff_man *man) -{ - - roff_man_free1(man); - free(man); -} - -struct roff_man * -roff_man_alloc(struct roff *roff, struct mparse *parse, - const char *os_s, int quick) -{ - struct roff_man *man; - - man = mandoc_calloc(1, sizeof(*man)); - man->parse = parse; - man->roff = roff; - man->os_s = os_s; - man->quick = quick; - roff_man_alloc1(man); - roff->man = man; - return man; -} - -/* --- syntax tree handling ----------------------------------------------- */ - -struct roff_node * -roff_node_alloc(struct roff_man *man, int line, int pos, - enum roff_type type, int tok) -{ - struct roff_node *n; - - n = mandoc_calloc(1, sizeof(*n)); - n->line = line; - n->pos = pos; - n->tok = tok; - n->type = type; - n->sec = man->lastsec; - - if (man->flags & MDOC_SYNOPSIS) - n->flags |= NODE_SYNPRETTY; - else - n->flags &= ~NODE_SYNPRETTY; - if (man->flags & MDOC_NEWLINE) - n->flags |= NODE_LINE; - man->flags &= ~MDOC_NEWLINE; - - return n; -} - -void -roff_node_append(struct roff_man *man, struct roff_node *n) -{ - - switch (man->next) { - case ROFF_NEXT_SIBLING: - if (man->last->next != NULL) { - n->next = man->last->next; - man->last->next->prev = n; - } else - man->last->parent->last = n; - man->last->next = n; - n->prev = man->last; - n->parent = man->last->parent; - break; - case ROFF_NEXT_CHILD: - if (man->last->child != NULL) { - n->next = man->last->child; - man->last->child->prev = n; - } else - man->last->last = n; - man->last->child = n; - n->parent = man->last; - break; - default: - abort(); - } - man->last = n; - - switch (n->type) { - case ROFFT_HEAD: - n->parent->head = n; - break; - case ROFFT_BODY: - if (n->end != ENDBODY_NOT) - return; - n->parent->body = n; - break; - case ROFFT_TAIL: - n->parent->tail = n; - break; - default: - return; - } - - /* - * Copy over the normalised-data pointer of our parent. Not - * everybody has one, but copying a null pointer is fine. - */ - - n->norm = n->parent->norm; - assert(n->parent->type == ROFFT_BLOCK); -} - -void -roff_word_alloc(struct roff_man *man, int line, int pos, const char *word) -{ - struct roff_node *n; - - n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE); - n->string = roff_strdup(man->roff, word); - roff_node_append(man, n); - n->flags |= NODE_VALID | NODE_ENDED; - man->next = ROFF_NEXT_SIBLING; -} - -void -roff_word_append(struct roff_man *man, const char *word) -{ - struct roff_node *n; - char *addstr, *newstr; - - n = man->last; - addstr = roff_strdup(man->roff, word); - mandoc_asprintf(&newstr, "%s %s", n->string, addstr); - free(addstr); - free(n->string); - n->string = newstr; - man->next = ROFF_NEXT_SIBLING; -} - -void -roff_elem_alloc(struct roff_man *man, int line, int pos, int tok) -{ - struct roff_node *n; - - n = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok); - roff_node_append(man, n); - man->next = ROFF_NEXT_CHILD; -} - -struct roff_node * -roff_block_alloc(struct roff_man *man, int line, int pos, int tok) -{ - struct roff_node *n; - - n = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok); - roff_node_append(man, n); - man->next = ROFF_NEXT_CHILD; - return n; -} - -struct roff_node * -roff_head_alloc(struct roff_man *man, int line, int pos, int tok) -{ - struct roff_node *n; - - n = roff_node_alloc(man, line, pos, ROFFT_HEAD, tok); - roff_node_append(man, n); - man->next = ROFF_NEXT_CHILD; - return n; -} - -struct roff_node * -roff_body_alloc(struct roff_man *man, int line, int pos, int tok) -{ - struct roff_node *n; - - n = roff_node_alloc(man, line, pos, ROFFT_BODY, tok); - roff_node_append(man, n); - man->next = ROFF_NEXT_CHILD; - return n; -} - -static void -roff_addtbl(struct roff_man *man, struct tbl_node *tbl) -{ - struct roff_node *n; - const struct tbl_span *span; - - if (man->macroset == MACROSET_MAN) - man_breakscope(man, ROFF_TS); - while ((span = tbl_span(tbl)) != NULL) { - n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE); - n->span = span; - roff_node_append(man, n); - n->flags |= NODE_VALID | NODE_ENDED; - man->next = ROFF_NEXT_SIBLING; - } -} - -void -roff_node_unlink(struct roff_man *man, struct roff_node *n) -{ - - /* Adjust siblings. */ - - if (n->prev) - n->prev->next = n->next; - if (n->next) - n->next->prev = n->prev; - - /* Adjust parent. */ - - if (n->parent != NULL) { - if (n->parent->child == n) - n->parent->child = n->next; - if (n->parent->last == n) - n->parent->last = n->prev; - } - - /* Adjust parse point. */ - - if (man == NULL) - return; - if (man->last == n) { - if (n->prev == NULL) { - man->last = n->parent; - man->next = ROFF_NEXT_CHILD; - } else { - man->last = n->prev; - man->next = ROFF_NEXT_SIBLING; - } - } - if (man->first == n) - man->first = NULL; -} - -void -roff_node_free(struct roff_node *n) -{ - - if (n->args != NULL) - mdoc_argv_free(n->args); - if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM) - free(n->norm); - if (n->eqn != NULL) - eqn_box_free(n->eqn); - free(n->string); - free(n); -} - -void -roff_node_delete(struct roff_man *man, struct roff_node *n) -{ - - while (n->child != NULL) - roff_node_delete(man, n->child); - roff_node_unlink(man, n); - roff_node_free(n); -} - -void -deroff(char **dest, const struct roff_node *n) -{ - char *cp; - size_t sz; - - if (n->type != ROFFT_TEXT) { - for (n = n->child; n != NULL; n = n->next) - deroff(dest, n); - return; - } - - /* Skip leading whitespace. */ - - for (cp = n->string; *cp != '\0'; cp++) { - if (cp[0] == '\\' && cp[1] != '\0' && - strchr(" %&0^|~", cp[1]) != NULL) - cp++; - else if ( ! isspace((unsigned char)*cp)) - break; - } - - /* Skip trailing backslash. */ - - sz = strlen(cp); - if (sz > 0 && cp[sz - 1] == '\\') - sz--; - - /* Skip trailing whitespace. */ - - for (; sz; sz--) - if ( ! isspace((unsigned char)cp[sz-1])) - break; - - /* Skip empty strings. */ - - if (sz == 0) - return; - - if (*dest == NULL) { - *dest = mandoc_strndup(cp, sz); - return; - } - - mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp); - free(*dest); - *dest = cp; -} - -/* --- main functions of the roff parser ---------------------------------- */ - -/* - * In the current line, expand escape sequences that tend to get - * used in numerical expressions and conditional requests. - * Also check the syntax of the remaining escape sequences. - */ -static enum rofferr -roff_res(struct roff *r, struct buf *buf, int ln, int pos) -{ - char ubuf[24]; /* buffer to print the number */ - const char *start; /* start of the string to process */ - char *stesc; /* start of an escape sequence ('\\') */ - const char *stnam; /* start of the name, after "[(*" */ - const char *cp; /* end of the name, e.g. before ']' */ - const char *res; /* the string to be substituted */ - char *nbuf; /* new buffer to copy buf->buf to */ - size_t maxl; /* expected length of the escape name */ - size_t naml; /* actual length of the escape name */ - enum mandoc_esc esc; /* type of the escape sequence */ - int inaml; /* length returned from mandoc_escape() */ - int expand_count; /* to avoid infinite loops */ - int npos; /* position in numeric expression */ - int arg_complete; /* argument not interrupted by eol */ - int done; /* no more input available */ - int deftype; /* type of definition to paste */ - int rcsid; /* kind of RCS id seen */ - char term; /* character terminating the escape */ - - /* Search forward for comments. */ - - done = 0; - start = buf->buf + pos; - for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) { - if (stesc[0] != r->escape || stesc[1] == '\0') - continue; - stesc++; - if (*stesc != '"' && *stesc != '#') - continue; - - /* Comment found, look for RCS id. */ - - rcsid = 0; - if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) { - rcsid = 1 << MANDOC_OS_OPENBSD; - cp += 8; - } else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) { - rcsid = 1 << MANDOC_OS_NETBSD; - cp += 7; - } - if (cp != NULL && - isalnum((unsigned char)*cp) == 0 && - strchr(cp, '$') != NULL) { - if (r->man->meta.rcsids & rcsid) - mandoc_msg(MANDOCERR_RCS_REP, r->parse, - ln, stesc + 1 - buf->buf, stesc + 1); - r->man->meta.rcsids |= rcsid; - } - - /* Handle trailing whitespace. */ - - cp = strchr(stesc--, '\0') - 1; - if (*cp == '\n') { - done = 1; - cp--; - } - if (*cp == ' ' || *cp == '\t') - mandoc_msg(MANDOCERR_SPACE_EOL, r->parse, - ln, cp - buf->buf, NULL); - while (stesc > start && stesc[-1] == ' ') - stesc--; - *stesc = '\0'; - break; - } - if (stesc == start) - return ROFF_CONT; - stesc--; - - /* Notice the end of the input. */ - - if (*stesc == '\n') { - *stesc-- = '\0'; - done = 1; - } - - expand_count = 0; - while (stesc >= start) { - - /* Search backwards for the next backslash. */ - - if (*stesc != r->escape) { - if (*stesc == '\\') { - *stesc = '\0'; - buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s", - buf->buf, stesc + 1) + 1; - start = nbuf + pos; - stesc = nbuf + (stesc - buf->buf); - free(buf->buf); - buf->buf = nbuf; - } - stesc--; - continue; - } - - /* If it is escaped, skip it. */ - - for (cp = stesc - 1; cp >= start; cp--) - if (*cp != r->escape) - break; - - if ((stesc - cp) % 2 == 0) { - while (stesc > cp) - *stesc-- = '\\'; - continue; - } else if (stesc[1] != '\0') { - *stesc = '\\'; - } else { - *stesc-- = '\0'; - if (done) - continue; - else - return ROFF_APPEND; - } - - /* Decide whether to expand or to check only. */ - - term = '\0'; - cp = stesc + 1; - switch (*cp) { - case '*': - res = NULL; - break; - case 'B': - case 'w': - term = cp[1]; - /* FALLTHROUGH */ - case 'n': - res = ubuf; - break; - default: - esc = mandoc_escape(&cp, &stnam, &inaml); - if (esc == ESCAPE_ERROR || - (esc == ESCAPE_SPECIAL && - mchars_spec2cp(stnam, inaml) < 0)) - mandoc_vmsg(MANDOCERR_ESC_BAD, - r->parse, ln, (int)(stesc - buf->buf), - "%.*s", (int)(cp - stesc), stesc); - stesc--; - continue; - } - - if (EXPAND_LIMIT < ++expand_count) { - mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, - ln, (int)(stesc - buf->buf), NULL); - return ROFF_IGN; - } - - /* - * The third character decides the length - * of the name of the string or register. - * Save a pointer to the name. - */ - - if (term == '\0') { - switch (*++cp) { - case '\0': - maxl = 0; - break; - case '(': - cp++; - maxl = 2; - break; - case '[': - cp++; - term = ']'; - maxl = 0; - break; - default: - maxl = 1; - break; - } - } else { - cp += 2; - maxl = 0; - } - stnam = cp; - - /* Advance to the end of the name. */ - - naml = 0; - arg_complete = 1; - while (maxl == 0 || naml < maxl) { - if (*cp == '\0') { - mandoc_msg(MANDOCERR_ESC_BAD, r->parse, - ln, (int)(stesc - buf->buf), stesc); - arg_complete = 0; - break; - } - if (maxl == 0 && *cp == term) { - cp++; - break; - } - if (*cp++ != '\\' || stesc[1] != 'w') { - naml++; - continue; - } - switch (mandoc_escape(&cp, NULL, NULL)) { - case ESCAPE_SPECIAL: - case ESCAPE_UNICODE: - case ESCAPE_NUMBERED: - case ESCAPE_OVERSTRIKE: - naml++; - break; - default: - break; - } - } - - /* - * Retrieve the replacement string; if it is - * undefined, resume searching for escapes. - */ - - switch (stesc[1]) { - case '*': - if (arg_complete) { - deftype = ROFFDEF_USER | ROFFDEF_PRE; - res = roff_getstrn(r, stnam, naml, &deftype); - } - break; - case 'B': - npos = 0; - ubuf[0] = arg_complete && - roff_evalnum(r, ln, stnam, &npos, - NULL, ROFFNUM_SCALE) && - stnam + npos + 1 == cp ? '1' : '0'; - ubuf[1] = '\0'; - break; - case 'n': - if (arg_complete) - (void)snprintf(ubuf, sizeof(ubuf), "%d", - roff_getregn(r, stnam, naml)); - else - ubuf[0] = '\0'; - break; - case 'w': - /* use even incomplete args */ - (void)snprintf(ubuf, sizeof(ubuf), "%d", - 24 * (int)naml); - break; - } - - if (res == NULL) { - mandoc_vmsg(MANDOCERR_STR_UNDEF, - r->parse, ln, (int)(stesc - buf->buf), - "%.*s", (int)naml, stnam); - res = ""; - } else if (buf->sz + strlen(res) > SHRT_MAX) { - mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, - ln, (int)(stesc - buf->buf), NULL); - return ROFF_IGN; - } - - /* Replace the escape sequence by the string. */ - - *stesc = '\0'; - buf->sz = mandoc_asprintf(&nbuf, "%s%s%s", - buf->buf, res, cp) + 1; - - /* Prepare for the next replacement. */ - - start = nbuf + pos; - stesc = nbuf + (stesc - buf->buf) + strlen(res); - free(buf->buf); - buf->buf = nbuf; - } - return ROFF_CONT; -} - -/* - * Process text streams. - */ -static enum rofferr -roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs) -{ - size_t sz; - const char *start; - char *p; - int isz; - enum mandoc_esc esc; - - /* Spring the input line trap. */ - - if (roffit_lines == 1) { - isz = mandoc_asprintf(&p, "%s\n.%s", buf->buf, roffit_macro); - free(buf->buf); - buf->buf = p; - buf->sz = isz + 1; - *offs = 0; - free(roffit_macro); - roffit_lines = 0; - return ROFF_REPARSE; - } else if (roffit_lines > 1) - --roffit_lines; - - if (roffce_node != NULL && buf->buf[pos] != '\0') { - if (roffce_lines < 1) { - r->man->last = roffce_node; - r->man->next = ROFF_NEXT_SIBLING; - roffce_lines = 0; - roffce_node = NULL; - } else - roffce_lines--; - } - - /* Convert all breakable hyphens into ASCII_HYPH. */ - - start = p = buf->buf + pos; - - while (*p != '\0') { - sz = strcspn(p, "-\\"); - p += sz; - - if (*p == '\0') - break; - - if (*p == '\\') { - /* Skip over escapes. */ - p++; - esc = mandoc_escape((const char **)&p, NULL, NULL); - if (esc == ESCAPE_ERROR) - break; - while (*p == '-') - p++; - continue; - } else if (p == start) { - p++; - continue; - } - - if (isalpha((unsigned char)p[-1]) && - isalpha((unsigned char)p[1])) - *p = ASCII_HYPH; - p++; - } - return ROFF_CONT; -} - -enum rofferr -roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) -{ - enum roff_tok t; - enum rofferr e; - int pos; /* parse point */ - int spos; /* saved parse point for messages */ - int ppos; /* original offset in buf->buf */ - int ctl; /* macro line (boolean) */ - - ppos = pos = *offs; - - /* Handle in-line equation delimiters. */ - - if (r->tbl == NULL && - r->last_eqn != NULL && r->last_eqn->delim && - (r->eqn == NULL || r->eqn_inline)) { - e = roff_eqndelim(r, buf, pos); - if (e == ROFF_REPARSE) - return e; - assert(e == ROFF_CONT); - } - - /* Expand some escape sequences. */ - - e = roff_res(r, buf, ln, pos); - if (e == ROFF_IGN || e == ROFF_APPEND) - return e; - assert(e == ROFF_CONT); - - ctl = roff_getcontrol(r, buf->buf, &pos); - - /* - * First, if a scope is open and we're not a macro, pass the - * text through the macro's filter. - * Equations process all content themselves. - * Tables process almost all content themselves, but we want - * to warn about macros before passing it there. - */ - - if (r->last != NULL && ! ctl) { - t = r->last->tok; - e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs); - if (e == ROFF_IGN) - return e; - assert(e == ROFF_CONT); - } - if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) { - eqn_read(r->eqn, buf->buf + ppos); - return ROFF_IGN; - } - if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) { - tbl_read(r->tbl, ln, buf->buf, ppos); - roff_addtbl(r->man, r->tbl); - return ROFF_IGN; - } - if ( ! ctl) - return roff_parsetext(r, buf, pos, offs); - - /* Skip empty request lines. */ - - if (buf->buf[pos] == '"') { - mandoc_msg(MANDOCERR_COMMENT_BAD, r->parse, - ln, pos, NULL); - return ROFF_IGN; - } else if (buf->buf[pos] == '\0') - return ROFF_IGN; - - /* - * If a scope is open, go to the child handler for that macro, - * as it may want to preprocess before doing anything with it. - * Don't do so if an equation is open. - */ - - if (r->last) { - t = r->last->tok; - return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs); - } - - /* No scope is open. This is a new request or macro. */ - - spos = pos; - t = roff_parse(r, buf->buf, &pos, ln, ppos); - - /* Tables ignore most macros. */ - - if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS || - t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) { - mandoc_msg(MANDOCERR_TBLMACRO, r->parse, - ln, pos, buf->buf + spos); - if (t != TOKEN_NONE) - return ROFF_IGN; - while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ') - pos++; - while (buf->buf[pos] == ' ') - pos++; - tbl_read(r->tbl, ln, buf->buf, pos); - roff_addtbl(r->man, r->tbl); - return ROFF_IGN; - } - - /* For now, let high level macros abort .ce mode. */ - - if (ctl && roffce_node != NULL && - (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ || - t == ROFF_TH || t == ROFF_TS)) { - r->man->last = roffce_node; - r->man->next = ROFF_NEXT_SIBLING; - roffce_lines = 0; - roffce_node = NULL; - } - - /* - * This is neither a roff request nor a user-defined macro. - * Let the standard macro set parsers handle it. - */ - - if (t == TOKEN_NONE) - return ROFF_CONT; - - /* Execute a roff request or a user defined macro. */ - - return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs); -} - -void -roff_endparse(struct roff *r) -{ - if (r->last != NULL) - mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, - r->last->line, r->last->col, - roff_name[r->last->tok]); - - if (r->eqn != NULL) { - mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, - r->eqn->node->line, r->eqn->node->pos, "EQ"); - eqn_parse(r->eqn); - r->eqn = NULL; - } - - if (r->tbl != NULL) { - mandoc_msg(MANDOCERR_BLK_NOEND, r->parse, - r->tbl->line, r->tbl->pos, "TS"); - tbl_end(r->tbl); - r->tbl = NULL; - } -} - -/* - * Parse a roff node's type from the input buffer. This must be in the - * form of ".foo xxx" in the usual way. - */ -static enum roff_tok -roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos) -{ - char *cp; - const char *mac; - size_t maclen; - int deftype; - enum roff_tok t; - - cp = buf + *pos; - - if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp) - return TOKEN_NONE; - - mac = cp; - maclen = roff_getname(r, &cp, ln, ppos); - - deftype = ROFFDEF_USER | ROFFDEF_REN; - r->current_string = roff_getstrn(r, mac, maclen, &deftype); - switch (deftype) { - case ROFFDEF_USER: - t = ROFF_USERDEF; - break; - case ROFFDEF_REN: - t = ROFF_RENAMED; - break; - default: - t = roffhash_find(r->reqtab, mac, maclen); - break; - } - if (t != TOKEN_NONE) - *pos = cp - buf; - return t; -} - -/* --- handling of request blocks ----------------------------------------- */ - -static enum rofferr -roff_cblock(ROFF_ARGS) -{ - - /* - * A block-close `..' should only be invoked as a child of an - * ignore macro, otherwise raise a warning and just ignore it. - */ - - if (r->last == NULL) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, ".."); - return ROFF_IGN; - } - - switch (r->last->tok) { - case ROFF_am: - /* ROFF_am1 is remapped to ROFF_am in roff_block(). */ - case ROFF_ami: - case ROFF_de: - /* ROFF_de1 is remapped to ROFF_de in roff_block(). */ - case ROFF_dei: - case ROFF_ig: - break; - default: - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, ".."); - return ROFF_IGN; - } - - if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, - ".. %s", buf->buf + pos); - - roffnode_pop(r); - roffnode_cleanscope(r); - return ROFF_IGN; - -} - -static void -roffnode_cleanscope(struct roff *r) -{ - - while (r->last) { - if (--r->last->endspan != 0) - break; - roffnode_pop(r); - } -} - -static void -roff_ccond(struct roff *r, int ln, int ppos) -{ - - if (NULL == r->last) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "\\}"); - return; - } - - switch (r->last->tok) { - case ROFF_el: - case ROFF_ie: - case ROFF_if: - break; - default: - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "\\}"); - return; - } - - if (r->last->endspan > -1) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "\\}"); - return; - } - - roffnode_pop(r); - roffnode_cleanscope(r); - return; -} - -static enum rofferr -roff_block(ROFF_ARGS) -{ - const char *name, *value; - char *call, *cp, *iname, *rname; - size_t csz, namesz, rsz; - int deftype; - - /* Ignore groff compatibility mode for now. */ - - if (tok == ROFF_de1) - tok = ROFF_de; - else if (tok == ROFF_dei1) - tok = ROFF_dei; - else if (tok == ROFF_am1) - tok = ROFF_am; - else if (tok == ROFF_ami1) - tok = ROFF_ami; - - /* Parse the macro name argument. */ - - cp = buf->buf + pos; - if (tok == ROFF_ig) { - iname = NULL; - namesz = 0; - } else { - iname = cp; - namesz = roff_getname(r, &cp, ln, ppos); - iname[namesz] = '\0'; - } - - /* Resolve the macro name argument if it is indirect. */ - - if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) { - deftype = ROFFDEF_USER; - name = roff_getstrn(r, iname, namesz, &deftype); - if (name == NULL) { - mandoc_vmsg(MANDOCERR_STR_UNDEF, - r->parse, ln, (int)(iname - buf->buf), - "%.*s", (int)namesz, iname); - namesz = 0; - } else - namesz = strlen(name); - } else - name = iname; - - if (namesz == 0 && tok != ROFF_ig) { - mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, - ln, ppos, roff_name[tok]); - return ROFF_IGN; - } - - roffnode_push(r, tok, name, ln, ppos); - - /* - * At the beginning of a `de' macro, clear the existing string - * with the same name, if there is one. New content will be - * appended from roff_block_text() in multiline mode. - */ - - if (tok == ROFF_de || tok == ROFF_dei) { - roff_setstrn(&r->strtab, name, namesz, "", 0, 0); - roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); - } else if (tok == ROFF_am || tok == ROFF_ami) { - deftype = ROFFDEF_ANY; - value = roff_getstrn(r, iname, namesz, &deftype); - switch (deftype) { /* Before appending, ... */ - case ROFFDEF_PRE: /* copy predefined to user-defined. */ - roff_setstrn(&r->strtab, name, namesz, - value, strlen(value), 0); - break; - case ROFFDEF_REN: /* call original standard macro. */ - csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n", - (int)strlen(value), value); - roff_setstrn(&r->strtab, name, namesz, call, csz, 0); - roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); - free(call); - break; - case ROFFDEF_STD: /* rename and call standard macro. */ - rsz = mandoc_asprintf(&rname, "__%s_renamed", name); - roff_setstrn(&r->rentab, rname, rsz, name, namesz, 0); - csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n", - (int)rsz, rname); - roff_setstrn(&r->strtab, name, namesz, call, csz, 0); - free(call); - free(rname); - break; - default: - break; - } - } - - if (*cp == '\0') - return ROFF_IGN; - - /* Get the custom end marker. */ - - iname = cp; - namesz = roff_getname(r, &cp, ln, ppos); - - /* Resolve the end marker if it is indirect. */ - - if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) { - deftype = ROFFDEF_USER; - name = roff_getstrn(r, iname, namesz, &deftype); - if (name == NULL) { - mandoc_vmsg(MANDOCERR_STR_UNDEF, - r->parse, ln, (int)(iname - buf->buf), - "%.*s", (int)namesz, iname); - namesz = 0; - } else - namesz = strlen(name); - } else - name = iname; - - if (namesz) - r->last->end = mandoc_strndup(name, namesz); - - if (*cp != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, - ln, pos, ".%s ... %s", roff_name[tok], cp); - - return ROFF_IGN; -} - -static enum rofferr -roff_block_sub(ROFF_ARGS) -{ - enum roff_tok t; - int i, j; - - /* - * First check whether a custom macro exists at this level. If - * it does, then check against it. This is some of groff's - * stranger behaviours. If we encountered a custom end-scope - * tag and that tag also happens to be a "real" macro, then we - * need to try interpreting it again as a real macro. If it's - * not, then return ignore. Else continue. - */ - - if (r->last->end) { - for (i = pos, j = 0; r->last->end[j]; j++, i++) - if (buf->buf[i] != r->last->end[j]) - break; - - if (r->last->end[j] == '\0' && - (buf->buf[i] == '\0' || - buf->buf[i] == ' ' || - buf->buf[i] == '\t')) { - roffnode_pop(r); - roffnode_cleanscope(r); - - while (buf->buf[i] == ' ' || buf->buf[i] == '\t') - i++; - - pos = i; - if (roff_parse(r, buf->buf, &pos, ln, ppos) != - TOKEN_NONE) - return ROFF_RERUN; - return ROFF_IGN; - } - } - - /* - * If we have no custom end-query or lookup failed, then try - * pulling it out of the hashtable. - */ - - t = roff_parse(r, buf->buf, &pos, ln, ppos); - - if (t != ROFF_cblock) { - if (tok != ROFF_ig) - roff_setstr(r, r->last->name, buf->buf + ppos, 2); - return ROFF_IGN; - } - - return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); -} - -static enum rofferr -roff_block_text(ROFF_ARGS) -{ - - if (tok != ROFF_ig) - roff_setstr(r, r->last->name, buf->buf + pos, 2); - - return ROFF_IGN; -} - -static enum rofferr -roff_cond_sub(ROFF_ARGS) -{ - enum roff_tok t; - char *ep; - int rr; - - rr = r->last->rule; - roffnode_cleanscope(r); - - /* - * If `\}' occurs on a macro line without a preceding macro, - * drop the line completely. - */ - - ep = buf->buf + pos; - if (ep[0] == '\\' && ep[1] == '}') - rr = 0; - - /* Always check for the closing delimiter `\}'. */ - - while ((ep = strchr(ep, '\\')) != NULL) { - switch (ep[1]) { - case '}': - memmove(ep, ep + 2, strlen(ep + 2) + 1); - roff_ccond(r, ln, ep - buf->buf); - break; - case '\0': - ++ep; - break; - default: - ep += 2; - break; - } - } - - /* - * Fully handle known macros when they are structurally - * required or when the conditional evaluated to true. - */ - - t = roff_parse(r, buf->buf, &pos, ln, ppos); - return t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) - ? (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : rr - ? ROFF_CONT : ROFF_IGN; -} - -static enum rofferr -roff_cond_text(ROFF_ARGS) -{ - char *ep; - int rr; - - rr = r->last->rule; - roffnode_cleanscope(r); - - ep = buf->buf + pos; - while ((ep = strchr(ep, '\\')) != NULL) { - if (*(++ep) == '}') { - *ep = '&'; - roff_ccond(r, ln, ep - buf->buf - 1); - } - if (*ep != '\0') - ++ep; - } - return rr ? ROFF_CONT : ROFF_IGN; -} - -/* --- handling of numeric and conditional expressions -------------------- */ - -/* - * Parse a single signed integer number. Stop at the first non-digit. - * If there is at least one digit, return success and advance the - * parse point, else return failure and let the parse point unchanged. - * Ignore overflows, treat them just like the C language. - */ -static int -roff_getnum(const char *v, int *pos, int *res, int flags) -{ - int myres, scaled, n, p; - - if (NULL == res) - res = &myres; - - p = *pos; - n = v[p] == '-'; - if (n || v[p] == '+') - p++; - - if (flags & ROFFNUM_WHITE) - while (isspace((unsigned char)v[p])) - p++; - - for (*res = 0; isdigit((unsigned char)v[p]); p++) - *res = 10 * *res + v[p] - '0'; - if (p == *pos + n) - return 0; - - if (n) - *res = -*res; - - /* Each number may be followed by one optional scaling unit. */ - - switch (v[p]) { - case 'f': - scaled = *res * 65536; - break; - case 'i': - scaled = *res * 240; - break; - case 'c': - scaled = *res * 240 / 2.54; - break; - case 'v': - case 'P': - scaled = *res * 40; - break; - case 'm': - case 'n': - scaled = *res * 24; - break; - case 'p': - scaled = *res * 10 / 3; - break; - case 'u': - scaled = *res; - break; - case 'M': - scaled = *res * 6 / 25; - break; - default: - scaled = *res; - p--; - break; - } - if (flags & ROFFNUM_SCALE) - *res = scaled; - - *pos = p + 1; - return 1; -} - -/* - * Evaluate a string comparison condition. - * The first character is the delimiter. - * Succeed if the string up to its second occurrence - * matches the string up to its third occurence. - * Advance the cursor after the third occurrence - * or lacking that, to the end of the line. - */ -static int -roff_evalstrcond(const char *v, int *pos) -{ - const char *s1, *s2, *s3; - int match; - - match = 0; - s1 = v + *pos; /* initial delimiter */ - s2 = s1 + 1; /* for scanning the first string */ - s3 = strchr(s2, *s1); /* for scanning the second string */ - - if (NULL == s3) /* found no middle delimiter */ - goto out; - - while ('\0' != *++s3) { - if (*s2 != *s3) { /* mismatch */ - s3 = strchr(s3, *s1); - break; - } - if (*s3 == *s1) { /* found the final delimiter */ - match = 1; - break; - } - s2++; - } - -out: - if (NULL == s3) - s3 = strchr(s2, '\0'); - else if (*s3 != '\0') - s3++; - *pos = s3 - v; - return match; -} - -/* - * Evaluate an optionally negated single character, numerical, - * or string condition. - */ -static int -roff_evalcond(struct roff *r, int ln, char *v, int *pos) -{ - char *cp, *name; - size_t sz; - int deftype, number, savepos, istrue, wanttrue; - - if ('!' == v[*pos]) { - wanttrue = 0; - (*pos)++; - } else - wanttrue = 1; - - switch (v[*pos]) { - case '\0': - return 0; - case 'n': - case 'o': - (*pos)++; - return wanttrue; - case 'c': - case 'e': - case 't': - case 'v': - (*pos)++; - return !wanttrue; - case 'd': - case 'r': - cp = v + *pos + 1; - while (*cp == ' ') - cp++; - name = cp; - sz = roff_getname(r, &cp, ln, cp - v); - if (sz == 0) - istrue = 0; - else if (v[*pos] == 'r') - istrue = roff_hasregn(r, name, sz); - else { - deftype = ROFFDEF_ANY; - roff_getstrn(r, name, sz, &deftype); - istrue = !!deftype; - } - *pos = cp - v; - return istrue == wanttrue; - default: - break; - } - - savepos = *pos; - if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE)) - return (number > 0) == wanttrue; - else if (*pos == savepos) - return roff_evalstrcond(v, pos) == wanttrue; - else - return 0; -} - -static enum rofferr -roff_line_ignore(ROFF_ARGS) -{ - - return ROFF_IGN; -} - -static enum rofferr -roff_insec(ROFF_ARGS) -{ - - mandoc_msg(MANDOCERR_REQ_INSEC, r->parse, - ln, ppos, roff_name[tok]); - return ROFF_IGN; -} - -static enum rofferr -roff_unsupp(ROFF_ARGS) -{ - - mandoc_msg(MANDOCERR_REQ_UNSUPP, r->parse, - ln, ppos, roff_name[tok]); - return ROFF_IGN; -} - -static enum rofferr -roff_cond(ROFF_ARGS) -{ - - roffnode_push(r, tok, NULL, ln, ppos); - - /* - * An `.el' has no conditional body: it will consume the value - * of the current rstack entry set in prior `ie' calls or - * defaults to DENY. - * - * If we're not an `el', however, then evaluate the conditional. - */ - - r->last->rule = tok == ROFF_el ? - (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) : - roff_evalcond(r, ln, buf->buf, &pos); - - /* - * An if-else will put the NEGATION of the current evaluated - * conditional into the stack of rules. - */ - - if (tok == ROFF_ie) { - if (r->rstackpos + 1 == r->rstacksz) { - r->rstacksz += 16; - r->rstack = mandoc_reallocarray(r->rstack, - r->rstacksz, sizeof(int)); - } - r->rstack[++r->rstackpos] = !r->last->rule; - } - - /* If the parent has false as its rule, then so do we. */ - - if (r->last->parent && !r->last->parent->rule) - r->last->rule = 0; - - /* - * Determine scope. - * If there is nothing on the line after the conditional, - * not even whitespace, use next-line scope. - */ - - if (buf->buf[pos] == '\0') { - r->last->endspan = 2; - goto out; - } - - while (buf->buf[pos] == ' ') - pos++; - - /* An opening brace requests multiline scope. */ - - if (buf->buf[pos] == '\\' && buf->buf[pos + 1] == '{') { - r->last->endspan = -1; - pos += 2; - while (buf->buf[pos] == ' ') - pos++; - goto out; - } - - /* - * Anything else following the conditional causes - * single-line scope. Warn if the scope contains - * nothing but trailing whitespace. - */ - - if (buf->buf[pos] == '\0') - mandoc_msg(MANDOCERR_COND_EMPTY, r->parse, - ln, ppos, roff_name[tok]); - - r->last->endspan = 1; - -out: - *offs = pos; - return ROFF_RERUN; -} - -static enum rofferr -roff_ds(ROFF_ARGS) -{ - char *string; - const char *name; - size_t namesz; - - /* Ignore groff compatibility mode for now. */ - - if (tok == ROFF_ds1) - tok = ROFF_ds; - else if (tok == ROFF_as1) - tok = ROFF_as; - - /* - * The first word is the name of the string. - * If it is empty or terminated by an escape sequence, - * abort the `ds' request without defining anything. - */ - - name = string = buf->buf + pos; - if (*name == '\0') - return ROFF_IGN; - - namesz = roff_getname(r, &string, ln, pos); - if (name[namesz] == '\\') - return ROFF_IGN; - - /* Read past the initial double-quote, if any. */ - if (*string == '"') - string++; - - /* The rest is the value. */ - roff_setstrn(&r->strtab, name, namesz, string, strlen(string), - ROFF_as == tok); - roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); - return ROFF_IGN; -} - -/* - * Parse a single operator, one or two characters long. - * If the operator is recognized, return success and advance the - * parse point, else return failure and let the parse point unchanged. - */ -static int -roff_getop(const char *v, int *pos, char *res) -{ - - *res = v[*pos]; - - switch (*res) { - case '+': - case '-': - case '*': - case '/': - case '%': - case '&': - case ':': - break; - case '<': - switch (v[*pos + 1]) { - case '=': - *res = 'l'; - (*pos)++; - break; - case '>': - *res = '!'; - (*pos)++; - break; - case '?': - *res = 'i'; - (*pos)++; - break; - default: - break; - } - break; - case '>': - switch (v[*pos + 1]) { - case '=': - *res = 'g'; - (*pos)++; - break; - case '?': - *res = 'a'; - (*pos)++; - break; - default: - break; - } - break; - case '=': - if ('=' == v[*pos + 1]) - (*pos)++; - break; - default: - return 0; - } - (*pos)++; - - return *res; -} - -/* - * Evaluate either a parenthesized numeric expression - * or a single signed integer number. - */ -static int -roff_evalpar(struct roff *r, int ln, - const char *v, int *pos, int *res, int flags) -{ - - if ('(' != v[*pos]) - return roff_getnum(v, pos, res, flags); - - (*pos)++; - if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE)) - return 0; - - /* - * Omission of the closing parenthesis - * is an error in validation mode, - * but ignored in evaluation mode. - */ - - if (')' == v[*pos]) - (*pos)++; - else if (NULL == res) - return 0; - - return 1; -} - -/* - * Evaluate a complete numeric expression. - * Proceed left to right, there is no concept of precedence. - */ -static int -roff_evalnum(struct roff *r, int ln, const char *v, - int *pos, int *res, int flags) -{ - int mypos, operand2; - char operator; - - if (NULL == pos) { - mypos = 0; - pos = &mypos; - } - - if (flags & ROFFNUM_WHITE) - while (isspace((unsigned char)v[*pos])) - (*pos)++; - - if ( ! roff_evalpar(r, ln, v, pos, res, flags)) - return 0; - - while (1) { - if (flags & ROFFNUM_WHITE) - while (isspace((unsigned char)v[*pos])) - (*pos)++; - - if ( ! roff_getop(v, pos, &operator)) - break; - - if (flags & ROFFNUM_WHITE) - while (isspace((unsigned char)v[*pos])) - (*pos)++; - - if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags)) - return 0; - - if (flags & ROFFNUM_WHITE) - while (isspace((unsigned char)v[*pos])) - (*pos)++; - - if (NULL == res) - continue; - - switch (operator) { - case '+': - *res += operand2; - break; - case '-': - *res -= operand2; - break; - case '*': - *res *= operand2; - break; - case '/': - if (operand2 == 0) { - mandoc_msg(MANDOCERR_DIVZERO, - r->parse, ln, *pos, v); - *res = 0; - break; - } - *res /= operand2; - break; - case '%': - if (operand2 == 0) { - mandoc_msg(MANDOCERR_DIVZERO, - r->parse, ln, *pos, v); - *res = 0; - break; - } - *res %= operand2; - break; - case '<': - *res = *res < operand2; - break; - case '>': - *res = *res > operand2; - break; - case 'l': - *res = *res <= operand2; - break; - case 'g': - *res = *res >= operand2; - break; - case '=': - *res = *res == operand2; - break; - case '!': - *res = *res != operand2; - break; - case '&': - *res = *res && operand2; - break; - case ':': - *res = *res || operand2; - break; - case 'i': - if (operand2 < *res) - *res = operand2; - break; - case 'a': - if (operand2 > *res) - *res = operand2; - break; - default: - abort(); - } - } - return 1; -} - -/* --- register management ------------------------------------------------ */ - -void -roff_setreg(struct roff *r, const char *name, int val, char sign) -{ - struct roffreg *reg; - - /* Search for an existing register with the same name. */ - reg = r->regtab; - - while (reg && strcmp(name, reg->key.p)) - reg = reg->next; - - if (NULL == reg) { - /* Create a new register. */ - reg = mandoc_malloc(sizeof(struct roffreg)); - reg->key.p = mandoc_strdup(name); - reg->key.sz = strlen(name); - reg->val = 0; - reg->next = r->regtab; - r->regtab = reg; - } - - if ('+' == sign) - reg->val += val; - else if ('-' == sign) - reg->val -= val; - else - reg->val = val; -} - -/* - * Handle some predefined read-only number registers. - * For now, return -1 if the requested register is not predefined; - * in case a predefined read-only register having the value -1 - * were to turn up, another special value would have to be chosen. - */ -static int -roff_getregro(const struct roff *r, const char *name) -{ - - switch (*name) { - case '$': /* Number of arguments of the last macro evaluated. */ - return r->argc; - case 'A': /* ASCII approximation mode is always off. */ - return 0; - case 'g': /* Groff compatibility mode is always on. */ - return 1; - case 'H': /* Fixed horizontal resolution. */ - return 24; - case 'j': /* Always adjust left margin only. */ - return 0; - case 'T': /* Some output device is always defined. */ - return 1; - case 'V': /* Fixed vertical resolution. */ - return 40; - default: - return -1; - } -} - -int -roff_getreg(const struct roff *r, const char *name) -{ - struct roffreg *reg; - int val; - - if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) { - val = roff_getregro(r, name + 1); - if (-1 != val) - return val; - } - - for (reg = r->regtab; reg; reg = reg->next) - if (0 == strcmp(name, reg->key.p)) - return reg->val; - - return 0; -} - -static int -roff_getregn(const struct roff *r, const char *name, size_t len) -{ - struct roffreg *reg; - int val; - - if ('.' == name[0] && 2 == len) { - val = roff_getregro(r, name + 1); - if (-1 != val) - return val; - } - - for (reg = r->regtab; reg; reg = reg->next) - if (len == reg->key.sz && - 0 == strncmp(name, reg->key.p, len)) - return reg->val; - - return 0; -} - -static int -roff_hasregn(const struct roff *r, const char *name, size_t len) -{ - struct roffreg *reg; - int val; - - if ('.' == name[0] && 2 == len) { - val = roff_getregro(r, name + 1); - if (-1 != val) - return 1; - } - - for (reg = r->regtab; reg; reg = reg->next) - if (len == reg->key.sz && - 0 == strncmp(name, reg->key.p, len)) - return 1; - - return 0; -} - -static void -roff_freereg(struct roffreg *reg) -{ - struct roffreg *old_reg; - - while (NULL != reg) { - free(reg->key.p); - old_reg = reg; - reg = reg->next; - free(old_reg); - } -} - -static enum rofferr -roff_nr(ROFF_ARGS) -{ - char *key, *val; - size_t keysz; - int iv; - char sign; - - key = val = buf->buf + pos; - if (*key == '\0') - return ROFF_IGN; - - keysz = roff_getname(r, &val, ln, pos); - if (key[keysz] == '\\') - return ROFF_IGN; - key[keysz] = '\0'; - - sign = *val; - if (sign == '+' || sign == '-') - val++; - - if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE)) - roff_setreg(r, key, iv, sign); - - return ROFF_IGN; -} - -static enum rofferr -roff_rr(ROFF_ARGS) -{ - struct roffreg *reg, **prev; - char *name, *cp; - size_t namesz; - - name = cp = buf->buf + pos; - if (*name == '\0') - return ROFF_IGN; - namesz = roff_getname(r, &cp, ln, pos); - name[namesz] = '\0'; - - prev = &r->regtab; - while (1) { - reg = *prev; - if (reg == NULL || !strcmp(name, reg->key.p)) - break; - prev = ®->next; - } - if (reg != NULL) { - *prev = reg->next; - free(reg->key.p); - free(reg); - } - return ROFF_IGN; -} - -/* --- handler functions for roff requests -------------------------------- */ - -static enum rofferr -roff_rm(ROFF_ARGS) -{ - const char *name; - char *cp; - size_t namesz; - - cp = buf->buf + pos; - while (*cp != '\0') { - name = cp; - namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf)); - roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0); - roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); - if (name[namesz] == '\\') - break; - } - return ROFF_IGN; -} - -static enum rofferr -roff_it(ROFF_ARGS) -{ - int iv; - - /* Parse the number of lines. */ - - if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) { - mandoc_msg(MANDOCERR_IT_NONUM, r->parse, - ln, ppos, buf->buf + 1); - return ROFF_IGN; - } - - while (isspace((unsigned char)buf->buf[pos])) - pos++; - - /* - * Arm the input line trap. - * Special-casing "an-trap" is an ugly workaround to cope - * with DocBook stupidly fiddling with man(7) internals. - */ - - roffit_lines = iv; - roffit_macro = mandoc_strdup(iv != 1 || - strcmp(buf->buf + pos, "an-trap") ? - buf->buf + pos : "br"); - return ROFF_IGN; -} - -static enum rofferr -roff_Dd(ROFF_ARGS) -{ - int mask; - enum roff_tok t, te; - - switch (tok) { - case ROFF_Dd: - tok = MDOC_Dd; - te = MDOC_MAX; - if (r->format == 0) - r->format = MPARSE_MDOC; - mask = MPARSE_MDOC | MPARSE_QUICK; - break; - case ROFF_TH: - tok = MAN_TH; - te = MAN_MAX; - if (r->format == 0) - r->format = MPARSE_MAN; - mask = MPARSE_QUICK; - break; - default: - abort(); - } - if ((r->options & mask) == 0) - for (t = tok; t < te; t++) - roff_setstr(r, roff_name[t], NULL, 0); - return ROFF_CONT; -} - -static enum rofferr -roff_TE(ROFF_ARGS) -{ - if (r->tbl == NULL) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "TE"); - return ROFF_IGN; - } - if (tbl_end(r->tbl) == 0) { - r->tbl = NULL; - free(buf->buf); - buf->buf = mandoc_strdup(".sp"); - buf->sz = 4; - return ROFF_REPARSE; - } - r->tbl = NULL; - return ROFF_IGN; -} - -static enum rofferr -roff_T_(ROFF_ARGS) -{ - - if (NULL == r->tbl) - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, - ln, ppos, "T&"); - else - tbl_restart(ln, ppos, r->tbl); - - return ROFF_IGN; -} - -/* - * Handle in-line equation delimiters. - */ -static enum rofferr -roff_eqndelim(struct roff *r, struct buf *buf, int pos) -{ - char *cp1, *cp2; - const char *bef_pr, *bef_nl, *mac, *aft_nl, *aft_pr; - - /* - * Outside equations, look for an opening delimiter. - * If we are inside an equation, we already know it is - * in-line, or this function wouldn't have been called; - * so look for a closing delimiter. - */ - - cp1 = buf->buf + pos; - cp2 = strchr(cp1, r->eqn == NULL ? - r->last_eqn->odelim : r->last_eqn->cdelim); - if (cp2 == NULL) - return ROFF_CONT; - - *cp2++ = '\0'; - bef_pr = bef_nl = aft_nl = aft_pr = ""; - - /* Handle preceding text, protecting whitespace. */ - - if (*buf->buf != '\0') { - if (r->eqn == NULL) - bef_pr = "\\&"; - bef_nl = "\n"; - } - - /* - * Prepare replacing the delimiter with an equation macro - * and drop leading white space from the equation. - */ - - if (r->eqn == NULL) { - while (*cp2 == ' ') - cp2++; - mac = ".EQ"; - } else - mac = ".EN"; - - /* Handle following text, protecting whitespace. */ - - if (*cp2 != '\0') { - aft_nl = "\n"; - if (r->eqn != NULL) - aft_pr = "\\&"; - } - - /* Do the actual replacement. */ - - buf->sz = mandoc_asprintf(&cp1, "%s%s%s%s%s%s%s", buf->buf, - bef_pr, bef_nl, mac, aft_nl, aft_pr, cp2) + 1; - free(buf->buf); - buf->buf = cp1; - - /* Toggle the in-line state of the eqn subsystem. */ - - r->eqn_inline = r->eqn == NULL; - return ROFF_REPARSE; -} - -static enum rofferr -roff_EQ(ROFF_ARGS) -{ - struct roff_node *n; - - if (r->man->macroset == MACROSET_MAN) - man_breakscope(r->man, ROFF_EQ); - n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE); - if (ln > r->man->last->line) - n->flags |= NODE_LINE; - n->eqn = mandoc_calloc(1, sizeof(*n->eqn)); - n->eqn->expectargs = UINT_MAX; - roff_node_append(r->man, n); - r->man->next = ROFF_NEXT_SIBLING; - - assert(r->eqn == NULL); - if (r->last_eqn == NULL) - r->last_eqn = eqn_alloc(r->parse); - else - eqn_reset(r->last_eqn); - r->eqn = r->last_eqn; - r->eqn->node = n; - - if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, - ".EQ %s", buf->buf + pos); - - return ROFF_IGN; -} - -static enum rofferr -roff_EN(ROFF_ARGS) -{ - if (r->eqn != NULL) { - eqn_parse(r->eqn); - r->eqn = NULL; - } else - mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN"); - if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, - "EN %s", buf->buf + pos); - return ROFF_IGN; -} - -static enum rofferr -roff_TS(ROFF_ARGS) -{ - if (r->tbl != NULL) { - mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse, - ln, ppos, "TS breaks TS"); - tbl_end(r->tbl); - } - r->tbl = tbl_alloc(ppos, ln, r->parse); - if (r->last_tbl) - r->last_tbl->next = r->tbl; - else - r->first_tbl = r->tbl; - r->last_tbl = r->tbl; - return ROFF_IGN; -} - -static enum rofferr -roff_onearg(ROFF_ARGS) -{ - struct roff_node *n; - char *cp; - int npos; - - if (r->man->flags & (MAN_BLINE | MAN_ELINE) && - (tok == ROFF_ce || tok == ROFF_rj || tok == ROFF_sp || - tok == ROFF_ti)) - man_breakscope(r->man, tok); - - if (roffce_node != NULL && (tok == ROFF_ce || tok == ROFF_rj)) { - r->man->last = roffce_node; - r->man->next = ROFF_NEXT_SIBLING; - } - - roff_elem_alloc(r->man, ln, ppos, tok); - n = r->man->last; - - cp = buf->buf + pos; - if (*cp != '\0') { - while (*cp != '\0' && *cp != ' ') - cp++; - while (*cp == ' ') - *cp++ = '\0'; - if (*cp != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, - r->parse, ln, cp - buf->buf, - "%s ... %s", roff_name[tok], cp); - roff_word_alloc(r->man, ln, pos, buf->buf + pos); - } - - if (tok == ROFF_ce || tok == ROFF_rj) { - if (r->man->last->type == ROFFT_ELEM) { - roff_word_alloc(r->man, ln, pos, "1"); - r->man->last->flags |= NODE_NOSRC; - } - npos = 0; - if (roff_evalnum(r, ln, r->man->last->string, &npos, - &roffce_lines, 0) == 0) { - mandoc_vmsg(MANDOCERR_CE_NONUM, - r->parse, ln, pos, "ce %s", buf->buf + pos); - roffce_lines = 1; - } - if (roffce_lines < 1) { - r->man->last = r->man->last->parent; - roffce_node = NULL; - roffce_lines = 0; - } else - roffce_node = r->man->last->parent; - } else { - n->flags |= NODE_VALID | NODE_ENDED; - r->man->last = n; - } - n->flags |= NODE_LINE; - r->man->next = ROFF_NEXT_SIBLING; - return ROFF_IGN; -} - -static enum rofferr -roff_manyarg(ROFF_ARGS) -{ - struct roff_node *n; - char *sp, *ep; - - roff_elem_alloc(r->man, ln, ppos, tok); - n = r->man->last; - - for (sp = ep = buf->buf + pos; *sp != '\0'; sp = ep) { - while (*ep != '\0' && *ep != ' ') - ep++; - while (*ep == ' ') - *ep++ = '\0'; - roff_word_alloc(r->man, ln, sp - buf->buf, sp); - } - - n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; - r->man->last = n; - r->man->next = ROFF_NEXT_SIBLING; - return ROFF_IGN; -} - -static enum rofferr -roff_als(ROFF_ARGS) -{ - char *oldn, *newn, *end, *value; - size_t oldsz, newsz, valsz; - - newn = oldn = buf->buf + pos; - if (*newn == '\0') - return ROFF_IGN; - - newsz = roff_getname(r, &oldn, ln, pos); - if (newn[newsz] == '\\' || *oldn == '\0') - return ROFF_IGN; - - end = oldn; - oldsz = roff_getname(r, &end, ln, oldn - buf->buf); - if (oldsz == 0) - return ROFF_IGN; - - valsz = mandoc_asprintf(&value, ".%.*s \\$*\\\"\n", - (int)oldsz, oldn); - roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0); - roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); - free(value); - return ROFF_IGN; -} - -static enum rofferr -roff_br(ROFF_ARGS) -{ - if (r->man->flags & (MAN_BLINE | MAN_ELINE)) - man_breakscope(r->man, ROFF_br); - roff_elem_alloc(r->man, ln, ppos, ROFF_br); - if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, - "%s %s", roff_name[tok], buf->buf + pos); - r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; - r->man->next = ROFF_NEXT_SIBLING; - return ROFF_IGN; -} - -static enum rofferr -roff_cc(ROFF_ARGS) -{ - const char *p; - - p = buf->buf + pos; - - if (*p == '\0' || (r->control = *p++) == '.') - r->control = '\0'; - - if (*p != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, - ln, p - buf->buf, "cc ... %s", p); - - return ROFF_IGN; -} - -static enum rofferr -roff_ec(ROFF_ARGS) -{ - const char *p; - - p = buf->buf + pos; - if (*p == '\0') - r->escape = '\\'; - else { - r->escape = *p; - if (*++p != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, - ln, p - buf->buf, "ec ... %s", p); - } - return ROFF_IGN; -} - -static enum rofferr -roff_eo(ROFF_ARGS) -{ - r->escape = '\0'; - if (buf->buf[pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, - ln, pos, "eo %s", buf->buf + pos); - return ROFF_IGN; -} - -static enum rofferr -roff_tr(ROFF_ARGS) -{ - const char *p, *first, *second; - size_t fsz, ssz; - enum mandoc_esc esc; - - p = buf->buf + pos; - - if (*p == '\0') { - mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, ln, ppos, "tr"); - return ROFF_IGN; - } - - while (*p != '\0') { - fsz = ssz = 1; - - first = p++; - if (*first == '\\') { - esc = mandoc_escape(&p, NULL, NULL); - if (esc == ESCAPE_ERROR) { - mandoc_msg(MANDOCERR_ESC_BAD, r->parse, - ln, (int)(p - buf->buf), first); - return ROFF_IGN; - } - fsz = (size_t)(p - first); - } - - second = p++; - if (*second == '\\') { - esc = mandoc_escape(&p, NULL, NULL); - if (esc == ESCAPE_ERROR) { - mandoc_msg(MANDOCERR_ESC_BAD, r->parse, - ln, (int)(p - buf->buf), second); - return ROFF_IGN; - } - ssz = (size_t)(p - second); - } else if (*second == '\0') { - mandoc_vmsg(MANDOCERR_TR_ODD, r->parse, - ln, first - buf->buf, "tr %s", first); - second = " "; - p--; - } - - if (fsz > 1) { - roff_setstrn(&r->xmbtab, first, fsz, - second, ssz, 0); - continue; - } - - if (r->xtab == NULL) - r->xtab = mandoc_calloc(128, - sizeof(struct roffstr)); - - free(r->xtab[(int)*first].p); - r->xtab[(int)*first].p = mandoc_strndup(second, ssz); - r->xtab[(int)*first].sz = ssz; - } - - return ROFF_IGN; -} - -static enum rofferr -roff_rn(ROFF_ARGS) -{ - const char *value; - char *oldn, *newn, *end; - size_t oldsz, newsz; - int deftype; - - oldn = newn = buf->buf + pos; - if (*oldn == '\0') - return ROFF_IGN; - - oldsz = roff_getname(r, &newn, ln, pos); - if (oldn[oldsz] == '\\' || *newn == '\0') - return ROFF_IGN; - - end = newn; - newsz = roff_getname(r, &end, ln, newn - buf->buf); - if (newsz == 0) - return ROFF_IGN; - - deftype = ROFFDEF_ANY; - value = roff_getstrn(r, oldn, oldsz, &deftype); - switch (deftype) { - case ROFFDEF_USER: - roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0); - roff_setstrn(&r->strtab, oldn, oldsz, NULL, 0, 0); - roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); - break; - case ROFFDEF_PRE: - roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0); - roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); - break; - case ROFFDEF_REN: - roff_setstrn(&r->rentab, newn, newsz, value, strlen(value), 0); - roff_setstrn(&r->rentab, oldn, oldsz, NULL, 0, 0); - roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); - break; - case ROFFDEF_STD: - roff_setstrn(&r->rentab, newn, newsz, oldn, oldsz, 0); - roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); - break; - default: - roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); - roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); - break; - } - return ROFF_IGN; -} - -static enum rofferr -roff_so(ROFF_ARGS) -{ - char *name, *cp; - - name = buf->buf + pos; - mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name); - - /* - * Handle `so'. Be EXTREMELY careful, as we shouldn't be - * opening anything that's not in our cwd or anything beneath - * it. Thus, explicitly disallow traversing up the file-system - * or using absolute paths. - */ - - if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) { - mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos, - ".so %s", name); - buf->sz = mandoc_asprintf(&cp, - ".sp\nSee the file %s.\n.sp", name) + 1; - free(buf->buf); - buf->buf = cp; - *offs = 0; - return ROFF_REPARSE; - } - - *offs = pos; - return ROFF_SO; -} - -/* --- user defined strings and macros ------------------------------------ */ - -static enum rofferr -roff_userdef(ROFF_ARGS) -{ - const char *arg[16], *ap; - char *cp, *n1, *n2; - int expand_count, i, ib, ie; - size_t asz, rsz; - - /* - * Collect pointers to macro argument strings - * and NUL-terminate them. - */ - - r->argc = 0; - cp = buf->buf + pos; - for (i = 0; i < 16; i++) { - if (*cp == '\0') - arg[i] = ""; - else { - arg[i] = mandoc_getarg(r->parse, &cp, ln, &pos); - r->argc = i + 1; - } - } - - /* - * Expand macro arguments. - */ - - buf->sz = strlen(r->current_string) + 1; - n1 = n2 = cp = mandoc_malloc(buf->sz); - memcpy(n1, r->current_string, buf->sz); - expand_count = 0; - while (*cp != '\0') { - - /* Scan ahead for the next argument invocation. */ - - if (*cp++ != '\\') - continue; - if (*cp++ != '$') - continue; - if (*cp == '*') { /* \\$* inserts all arguments */ - ib = 0; - ie = r->argc - 1; - } else { /* \\$1 .. \\$9 insert one argument */ - ib = ie = *cp - '1'; - if (ib < 0 || ib > 8) - continue; - } - cp -= 2; - - /* - * Prevent infinite recursion. - */ - - if (cp >= n2) - expand_count = 1; - else if (++expand_count > EXPAND_LIMIT) { - mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, - ln, (int)(cp - n1), NULL); - free(buf->buf); - buf->buf = n1; - return ROFF_IGN; - } - - /* - * Determine the size of the expanded argument, - * taking escaping of quotes into account. - */ - - asz = ie > ib ? ie - ib : 0; /* for blanks */ - for (i = ib; i <= ie; i++) { - for (ap = arg[i]; *ap != '\0'; ap++) { - asz++; - if (*ap == '"') - asz += 3; - } - } - if (asz != 3) { - - /* - * Determine the size of the rest of the - * unexpanded macro, including the NUL. - */ - - rsz = buf->sz - (cp - n1) - 3; - - /* - * When shrinking, move before - * releasing the storage. - */ - - if (asz < 3) - memmove(cp + asz, cp + 3, rsz); - - /* - * Resize the storage for the macro - * and readjust the parse pointer. - */ - - buf->sz += asz - 3; - n2 = mandoc_realloc(n1, buf->sz); - cp = n2 + (cp - n1); - n1 = n2; - - /* - * When growing, make room - * for the expanded argument. - */ - - if (asz > 3) - memmove(cp + asz, cp + 3, rsz); - } - - /* Copy the expanded argument, escaping quotes. */ - - n2 = cp; - for (i = ib; i <= ie; i++) { - for (ap = arg[i]; *ap != '\0'; ap++) { - if (*ap == '"') { - memcpy(n2, "\\(dq", 4); - n2 += 4; - } else - *n2++ = *ap; - } - if (i < ie) - *n2++ = ' '; - } - } - - /* - * Replace the macro invocation - * by the expanded macro. - */ - - free(buf->buf); - buf->buf = n1; - *offs = 0; - - return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ? - ROFF_REPARSE : ROFF_APPEND; -} - -/* - * Calling a high-level macro that was renamed with .rn. - * r->current_string has already been set up by roff_parse(). - */ -static enum rofferr -roff_renamed(ROFF_ARGS) -{ - char *nbuf; - - buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string, - buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1; - free(buf->buf); - buf->buf = nbuf; - return ROFF_CONT; -} - -static size_t -roff_getname(struct roff *r, char **cpp, int ln, int pos) -{ - char *name, *cp; - size_t namesz; - - name = *cpp; - if ('\0' == *name) - return 0; - - /* Read until end of name and terminate it with NUL. */ - for (cp = name; 1; cp++) { - if ('\0' == *cp || ' ' == *cp) { - namesz = cp - name; - break; - } - if ('\\' != *cp) - continue; - namesz = cp - name; - if ('{' == cp[1] || '}' == cp[1]) - break; - cp++; - if ('\\' == *cp) - continue; - mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos, - "%.*s", (int)(cp - name + 1), name); - mandoc_escape((const char **)&cp, NULL, NULL); - break; - } - - /* Read past spaces. */ - while (' ' == *cp) - cp++; - - *cpp = cp; - return namesz; -} - -/* - * Store *string into the user-defined string called *name. - * To clear an existing entry, call with (*r, *name, NULL, 0). - * append == 0: replace mode - * append == 1: single-line append mode - * append == 2: multiline append mode, append '\n' after each call - */ -static void -roff_setstr(struct roff *r, const char *name, const char *string, - int append) -{ - size_t namesz; - - namesz = strlen(name); - roff_setstrn(&r->strtab, name, namesz, string, - string ? strlen(string) : 0, append); - roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); -} - -static void -roff_setstrn(struct roffkv **r, const char *name, size_t namesz, - const char *string, size_t stringsz, int append) -{ - struct roffkv *n; - char *c; - int i; - size_t oldch, newch; - - /* Search for an existing string with the same name. */ - n = *r; - - while (n && (namesz != n->key.sz || - strncmp(n->key.p, name, namesz))) - n = n->next; - - if (NULL == n) { - /* Create a new string table entry. */ - n = mandoc_malloc(sizeof(struct roffkv)); - n->key.p = mandoc_strndup(name, namesz); - n->key.sz = namesz; - n->val.p = NULL; - n->val.sz = 0; - n->next = *r; - *r = n; - } else if (0 == append) { - free(n->val.p); - n->val.p = NULL; - n->val.sz = 0; - } - - if (NULL == string) - return; - - /* - * One additional byte for the '\n' in multiline mode, - * and one for the terminating '\0'. - */ - newch = stringsz + (1 < append ? 2u : 1u); - - if (NULL == n->val.p) { - n->val.p = mandoc_malloc(newch); - *n->val.p = '\0'; - oldch = 0; - } else { - oldch = n->val.sz; - n->val.p = mandoc_realloc(n->val.p, oldch + newch); - } - - /* Skip existing content in the destination buffer. */ - c = n->val.p + (int)oldch; - - /* Append new content to the destination buffer. */ - i = 0; - while (i < (int)stringsz) { - /* - * Rudimentary roff copy mode: - * Handle escaped backslashes. - */ - if ('\\' == string[i] && '\\' == string[i + 1]) - i++; - *c++ = string[i++]; - } - - /* Append terminating bytes. */ - if (1 < append) - *c++ = '\n'; - - *c = '\0'; - n->val.sz = (int)(c - n->val.p); -} - -static const char * -roff_getstrn(const struct roff *r, const char *name, size_t len, - int *deftype) -{ - const struct roffkv *n; - int i; - enum roff_tok tok; - - if (*deftype & ROFFDEF_USER) { - for (n = r->strtab; n != NULL; n = n->next) { - if (strncmp(name, n->key.p, len) == 0 && - n->key.p[len] == '\0' && - n->val.p != NULL) { - *deftype = ROFFDEF_USER; - return n->val.p; - } - } - } - if (*deftype & ROFFDEF_PRE) { - for (i = 0; i < PREDEFS_MAX; i++) { - if (strncmp(name, predefs[i].name, len) == 0 && - predefs[i].name[len] == '\0') { - *deftype = ROFFDEF_PRE; - return predefs[i].str; - } - } - } - if (*deftype & ROFFDEF_REN) { - for (n = r->rentab; n != NULL; n = n->next) { - if (strncmp(name, n->key.p, len) == 0 && - n->key.p[len] == '\0' && - n->val.p != NULL) { - *deftype = ROFFDEF_REN; - return n->val.p; - } - } - } - if (*deftype & ROFFDEF_STD) { - if (r->man->macroset != MACROSET_MAN) { - for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) { - if (strncmp(name, roff_name[tok], len) == 0 && - roff_name[tok][len] == '\0') { - *deftype = ROFFDEF_STD; - return NULL; - } - } - } - if (r->man->macroset != MACROSET_MDOC) { - for (tok = MAN_TH; tok < MAN_MAX; tok++) { - if (strncmp(name, roff_name[tok], len) == 0 && - roff_name[tok][len] == '\0') { - *deftype = ROFFDEF_STD; - return NULL; - } - } - } - } - *deftype = 0; - return NULL; -} - -static void -roff_freestr(struct roffkv *r) -{ - struct roffkv *n, *nn; - - for (n = r; n; n = nn) { - free(n->key.p); - free(n->val.p); - nn = n->next; - free(n); - } -} - -/* --- accessors and utility functions ------------------------------------ */ - -/* - * Duplicate an input string, making the appropriate character - * conversations (as stipulated by `tr') along the way. - * Returns a heap-allocated string with all the replacements made. - */ -char * -roff_strdup(const struct roff *r, const char *p) -{ - const struct roffkv *cp; - char *res; - const char *pp; - size_t ssz, sz; - enum mandoc_esc esc; - - if (NULL == r->xmbtab && NULL == r->xtab) - return mandoc_strdup(p); - else if ('\0' == *p) - return mandoc_strdup(""); - - /* - * Step through each character looking for term matches - * (remember that a `tr' can be invoked with an escape, which is - * a glyph but the escape is multi-character). - * We only do this if the character hash has been initialised - * and the string is >0 length. - */ - - res = NULL; - ssz = 0; - - while ('\0' != *p) { - assert((unsigned int)*p < 128); - if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) { - sz = r->xtab[(int)*p].sz; - res = mandoc_realloc(res, ssz + sz + 1); - memcpy(res + ssz, r->xtab[(int)*p].p, sz); - ssz += sz; - p++; - continue; - } else if ('\\' != *p) { - res = mandoc_realloc(res, ssz + 2); - res[ssz++] = *p++; - continue; - } - - /* Search for term matches. */ - for (cp = r->xmbtab; cp; cp = cp->next) - if (0 == strncmp(p, cp->key.p, cp->key.sz)) - break; - - if (NULL != cp) { - /* - * A match has been found. - * Append the match to the array and move - * forward by its keysize. - */ - res = mandoc_realloc(res, - ssz + cp->val.sz + 1); - memcpy(res + ssz, cp->val.p, cp->val.sz); - ssz += cp->val.sz; - p += (int)cp->key.sz; - continue; - } - - /* - * Handle escapes carefully: we need to copy - * over just the escape itself, or else we might - * do replacements within the escape itself. - * Make sure to pass along the bogus string. - */ - pp = p++; - esc = mandoc_escape(&p, NULL, NULL); - if (ESCAPE_ERROR == esc) { - sz = strlen(pp); - res = mandoc_realloc(res, ssz + sz + 1); - memcpy(res + ssz, pp, sz); - break; - } - /* - * We bail out on bad escapes. - * No need to warn: we already did so when - * roff_res() was called. - */ - sz = (int)(p - pp); - res = mandoc_realloc(res, ssz + sz + 1); - memcpy(res + ssz, pp, sz); - ssz += sz; - } - - res[(int)ssz] = '\0'; - return res; -} - -int -roff_getformat(const struct roff *r) -{ - - return r->format; -} - -/* - * Find out whether a line is a macro line or not. - * If it is, adjust the current position and return one; if it isn't, - * return zero and don't change the current position. - * If the control character has been set with `.cc', then let that grain - * precedence. - * This is slighly contrary to groff, where using the non-breaking - * control character when `cc' has been invoked will cause the - * non-breaking macro contents to be printed verbatim. - */ -int -roff_getcontrol(const struct roff *r, const char *cp, int *ppos) -{ - int pos; - - pos = *ppos; - - if (r->control != '\0' && cp[pos] == r->control) - pos++; - else if (r->control != '\0') - return 0; - else if ('\\' == cp[pos] && '.' == cp[pos + 1]) - pos += 2; - else if ('.' == cp[pos] || '\'' == cp[pos]) - pos++; - else - return 0; - - while (' ' == cp[pos] || '\t' == cp[pos]) - pos++; - - *ppos = pos; - return 1; -} Property changes on: head/contrib/mdocml/roff.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_stringlist.h =================================================================== --- head/contrib/mdocml/compat_stringlist.h (revision 338825) +++ head/contrib/mdocml/compat_stringlist.h (nonexistent) @@ -1,45 +0,0 @@ -/* $Id: compat_stringlist.h,v 1.4 2015/11/07 14:01:16 schwarze Exp $ */ -/* $NetBSD: stringlist.h,v 1.2 1997/01/17 06:11:36 lukem Exp $ */ - -/* - * Copyright (c) 1994 Christos Zoulas - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * Simple string list - */ -typedef struct _stringlist { - char **sl_str; - size_t sl_max; - size_t sl_cur; -} StringList; - - -StringList *sl_init(void); -int sl_add(StringList *, char *); -void sl_free(StringList *, int); -char *sl_find(StringList *, const char *); Property changes on: head/contrib/mdocml/compat_stringlist.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/predefs.in =================================================================== --- head/contrib/mdocml/predefs.in (revision 338825) +++ head/contrib/mdocml/predefs.in (nonexistent) @@ -1,65 +0,0 @@ -/* $Id: predefs.in,v 1.4 2012/07/18 10:39:19 schwarze Exp $ */ -/* - * 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 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. - */ - -/* - * The predefined-string translation tables. Each corresponds to a - * predefined strings from (e.g.) tmac/mdoc/doc-nroff. The left-hand - * side corresponds to the input sequence (\*x, \*(xx and so on). The - * right-hand side is what's produced by libroff. - * - * XXX - C-escape strings! - * XXX - update PREDEF_MAX in roff.c if adding more! - */ - -PREDEF("Am", "&") -PREDEF("Ba", "\\fR|\\fP") -PREDEF("Ge", "\\(>=") -PREDEF("Gt", ">") -PREDEF("If", "infinity") -PREDEF("Le", "\\(<=") -PREDEF("Lq", "\\(lq") -PREDEF("Lt", "<") -PREDEF("Na", "NaN") -PREDEF("Ne", "\\(!=") -PREDEF("Pi", "pi") -PREDEF("Pm", "\\(+-") -PREDEF("Rq", "\\(rq") -PREDEF("left-bracket", "[") -PREDEF("left-parenthesis", "(") -PREDEF("lp", "(") -PREDEF("left-singlequote", "\\(oq") -PREDEF("q", "\\(dq") -PREDEF("quote-left", "\\(oq") -PREDEF("quote-right", "\\(cq") -PREDEF("R", "\\(rg") -PREDEF("right-bracket", "]") -PREDEF("right-parenthesis", ")") -PREDEF("rp", ")") -PREDEF("right-singlequote", "\\(cq") -PREDEF("Tm", "(Tm)") -PREDEF("Px", "POSIX") -PREDEF("Ai", "ANSI") -PREDEF("\'", "\\\'") -PREDEF("aa", "\\(aa") -PREDEF("ga", "\\(ga") -PREDEF("`", "\\`") -PREDEF("lq", "\\(lq") -PREDEF("rq", "\\(rq") -PREDEF("ua", "\\(ua") -PREDEF("va", "\\(va") -PREDEF("<=", "\\(<=") -PREDEF(">=", "\\(>=") Property changes on: head/contrib/mdocml/predefs.in ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/chars.c =================================================================== --- head/contrib/mdocml/chars.c (revision 338825) +++ head/contrib/mdocml/chars.c (nonexistent) @@ -1,511 +0,0 @@ -/* $Id: chars.c,v 1.71 2017/06/14 20:57:07 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2011, 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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include "mandoc.h" -#include "mandoc_aux.h" -#include "mandoc_ohash.h" -#include "libmandoc.h" - -struct ln { - const char roffcode[16]; - const char *ascii; - int unicode; -}; - -/* Special break control characters. */ -static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' }; -static const char ascii_break[2] = { ASCII_BREAK, '\0' }; - -static struct ln lines[] = { - - /* Spacing. */ - { " ", ascii_nbrsp, 0x00a0 }, - { "~", ascii_nbrsp, 0x00a0 }, - { "0", " ", 0x2002 }, - { "|", "", 0 }, - { "^", "", 0 }, - { "&", "", 0 }, - { "%", "", 0 }, - { ":", ascii_break, 0 }, - /* XXX The following three do not really belong here. */ - { "t", "", 0 }, - { "c", "", 0 }, - { "}", "", 0 }, - - /* Lines. */ - { "ba", "|", 0x007c }, - { "br", "|", 0x2502 }, - { "ul", "_", 0x005f }, - { "ru", "_", 0x005f }, - { "rn", "-", 0x203e }, - { "bb", "|", 0x00a6 }, - { "sl", "/", 0x002f }, - { "rs", "\\", 0x005c }, - - /* Text markers. */ - { "ci", "O", 0x25cb }, - { "bu", "+\bo", 0x2022 }, - { "dd", "|\b=", 0x2021 }, - { "dg", "|\b-", 0x2020 }, - { "lz", "<>", 0x25ca }, - { "sq", "[]", 0x25a1 }, - { "ps", "", 0x00b6 }, - { "sc", "", 0x00a7 }, - { "lh", "<=", 0x261c }, - { "rh", "=>", 0x261e }, - { "at", "@", 0x0040 }, - { "sh", "#", 0x0023 }, - { "CR", "_|", 0x21b5 }, - { "OK", "\\/", 0x2713 }, - { "CL", "", 0x2663 }, - { "SP", "", 0x2660 }, - { "HE", "", 0x2665 }, - { "DI", "", 0x2666 }, - - /* Legal symbols. */ - { "co", "(C)", 0x00a9 }, - { "rg", "(R)", 0x00ae }, - { "tm", "tm", 0x2122 }, - - /* Punctuation. */ - { "em", "--", 0x2014 }, - { "en", "-", 0x2013 }, - { "hy", "-", 0x2010 }, - { "e", "\\", 0x005c }, - { ".", ".", 0x002e }, - { "r!", "!", 0x00a1 }, - { "r?", "?", 0x00bf }, - - /* Quotes. */ - { "Bq", ",,", 0x201e }, - { "bq", ",", 0x201a }, - { "lq", "\"", 0x201c }, - { "rq", "\"", 0x201d }, - { "Lq", "\"", 0x201c }, - { "Rq", "\"", 0x201d }, - { "oq", "`", 0x2018 }, - { "cq", "\'", 0x2019 }, - { "aq", "\'", 0x0027 }, - { "dq", "\"", 0x0022 }, - { "Fo", "<<", 0x00ab }, - { "Fc", ">>", 0x00bb }, - { "fo", "<", 0x2039 }, - { "fc", ">", 0x203a }, - - /* Brackets. */ - { "lB", "[", 0x005b }, - { "rB", "]", 0x005d }, - { "lC", "{", 0x007b }, - { "rC", "}", 0x007d }, - { "la", "<", 0x27e8 }, - { "ra", ">", 0x27e9 }, - { "bv", "|", 0x23aa }, - { "braceex", "|", 0x23aa }, - { "bracketlefttp", "|", 0x23a1 }, - { "bracketleftbt", "|", 0x23a3 }, - { "bracketleftex", "|", 0x23a2 }, - { "bracketrighttp", "|", 0x23a4 }, - { "bracketrightbt", "|", 0x23a6 }, - { "bracketrightex", "|", 0x23a5 }, - { "lt", ",-", 0x23a7 }, - { "bracelefttp", ",-", 0x23a7 }, - { "lk", "{", 0x23a8 }, - { "braceleftmid", "{", 0x23a8 }, - { "lb", "`-", 0x23a9 }, - { "braceleftbt", "`-", 0x23a9 }, - { "braceleftex", "|", 0x23aa }, - { "rt", "-.", 0x23ab }, - { "bracerighttp", "-.", 0x23ab }, - { "rk", "}", 0x23ac }, - { "bracerightmid", "}", 0x23ac }, - { "rb", "-\'", 0x23ad }, - { "bracerightbt", "-\'", 0x23ad }, - { "bracerightex", "|", 0x23aa }, - { "parenlefttp", "/", 0x239b }, - { "parenleftbt", "\\", 0x239d }, - { "parenleftex", "|", 0x239c }, - { "parenrighttp", "\\", 0x239e }, - { "parenrightbt", "/", 0x23a0 }, - { "parenrightex", "|", 0x239f }, - - /* Arrows and lines. */ - { "<-", "<-", 0x2190 }, - { "->", "->", 0x2192 }, - { "<>", "<->", 0x2194 }, - { "da", "|\bv", 0x2193 }, - { "ua", "|\b^", 0x2191 }, - { "va", "^v", 0x2195 }, - { "lA", "<=", 0x21d0 }, - { "rA", "=>", 0x21d2 }, - { "hA", "<=>", 0x21d4 }, - { "uA", "=\b^", 0x21d1 }, - { "dA", "=\bv", 0x21d3 }, - { "vA", "^=v", 0x21d5 }, - { "an", "-", 0x23af }, - - /* Logic. */ - { "AN", "^", 0x2227 }, - { "OR", "v", 0x2228 }, - { "no", "~", 0x00ac }, - { "tno", "~", 0x00ac }, - { "te", "3", 0x2203 }, - { "fa", "-\bV", 0x2200 }, - { "st", "-)", 0x220b }, - { "tf", ".:.", 0x2234 }, - { "3d", ".:.", 0x2234 }, - { "or", "|", 0x007c }, - - /* Mathematicals. */ - { "pl", "+", 0x002b }, - { "mi", "-", 0x2212 }, - { "-", "-", 0x002d }, - { "-+", "-+", 0x2213 }, - { "+-", "+-", 0x00b1 }, - { "t+-", "+-", 0x00b1 }, - { "pc", ".", 0x00b7 }, - { "md", ".", 0x22c5 }, - { "mu", "x", 0x00d7 }, - { "tmu", "x", 0x00d7 }, - { "c*", "O\bx", 0x2297 }, - { "c+", "O\b+", 0x2295 }, - { "di", "-:-", 0x00f7 }, - { "tdi", "-:-", 0x00f7 }, - { "f/", "/", 0x2044 }, - { "**", "*", 0x2217 }, - { "<=", "<=", 0x2264 }, - { ">=", ">=", 0x2265 }, - { "<<", "<<", 0x226a }, - { ">>", ">>", 0x226b }, - { "eq", "=", 0x003d }, - { "!=", "!=", 0x2260 }, - { "==", "==", 0x2261 }, - { "ne", "!==", 0x2262 }, - { "ap", "~", 0x223c }, - { "|=", "-~", 0x2243 }, - { "=~", "=~", 0x2245 }, - { "~~", "~~", 0x2248 }, - { "~=", "~=", 0x2248 }, - { "pt", "oc", 0x221d }, - { "es", "{}", 0x2205 }, - { "mo", "E", 0x2208 }, - { "nm", "!E", 0x2209 }, - { "sb", "(=", 0x2282 }, - { "nb", "(!=", 0x2284 }, - { "sp", "=)", 0x2283 }, - { "nc", "!=)", 0x2285 }, - { "ib", "(=\b_", 0x2286 }, - { "ip", "=\b_)", 0x2287 }, - { "ca", "(^)", 0x2229 }, - { "cu", "U", 0x222a }, - { "/_", "_\b/", 0x2220 }, - { "pp", "_\b|", 0x22a5 }, - { "is", "'\b,\bI", 0x222b }, - { "integral", "'\b,\bI", 0x222b }, - { "sum", "E", 0x2211 }, - { "product", "TT", 0x220f }, - { "coproduct", "U", 0x2210 }, - { "gr", "V", 0x2207 }, - { "sr", "\\/", 0x221a }, - { "sqrt", "\\/", 0x221a }, - { "lc", "|~", 0x2308 }, - { "rc", "~|", 0x2309 }, - { "lf", "|_", 0x230a }, - { "rf", "_|", 0x230b }, - { "if", "oo", 0x221e }, - { "Ah", "N", 0x2135 }, - { "Im", "I", 0x2111 }, - { "Re", "R", 0x211c }, - { "wp", "P", 0x2118 }, - { "pd", "a", 0x2202 }, - { "-h", "/h", 0x210f }, - { "hbar", "/h", 0x210f }, - { "12", "1/2", 0x00bd }, - { "14", "1/4", 0x00bc }, - { "34", "3/4", 0x00be }, - { "18", "1/8", 0x215B }, - { "38", "3/8", 0x215C }, - { "58", "5/8", 0x215D }, - { "78", "7/8", 0x215E }, - { "S1", "1", 0x00B9 }, - { "S2", "2", 0x00B2 }, - { "S3", "3", 0x00B3 }, - - /* Ligatures. */ - { "ff", "ff", 0xfb00 }, - { "fi", "fi", 0xfb01 }, - { "fl", "fl", 0xfb02 }, - { "Fi", "ffi", 0xfb03 }, - { "Fl", "ffl", 0xfb04 }, - { "AE", "AE", 0x00c6 }, - { "ae", "ae", 0x00e6 }, - { "OE", "OE", 0x0152 }, - { "oe", "oe", 0x0153 }, - { "ss", "ss", 0x00df }, - { "IJ", "IJ", 0x0132 }, - { "ij", "ij", 0x0133 }, - - /* Accents. */ - { "a\"", "\"", 0x02dd }, - { "a-", "-", 0x00af }, - { "a.", ".", 0x02d9 }, - { "a^", "^", 0x005e }, - { "aa", "\'", 0x00b4 }, - { "\'", "\'", 0x00b4 }, - { "ga", "`", 0x0060 }, - { "`", "`", 0x0060 }, - { "ab", "'\b`", 0x02d8 }, - { "ac", ",", 0x00b8 }, - { "ad", "\"", 0x00a8 }, - { "ah", "v", 0x02c7 }, - { "ao", "o", 0x02da }, - { "a~", "~", 0x007e }, - { "ho", ",", 0x02db }, - { "ha", "^", 0x005e }, - { "ti", "~", 0x007e }, - - /* Accented letters. */ - { "'A", "'\bA", 0x00c1 }, - { "'E", "'\bE", 0x00c9 }, - { "'I", "'\bI", 0x00cd }, - { "'O", "'\bO", 0x00d3 }, - { "'U", "'\bU", 0x00da }, - { "'a", "'\ba", 0x00e1 }, - { "'e", "'\be", 0x00e9 }, - { "'i", "'\bi", 0x00ed }, - { "'o", "'\bo", 0x00f3 }, - { "'u", "'\bu", 0x00fa }, - { "`A", "`\bA", 0x00c0 }, - { "`E", "`\bE", 0x00c8 }, - { "`I", "`\bI", 0x00cc }, - { "`O", "`\bO", 0x00d2 }, - { "`U", "`\bU", 0x00d9 }, - { "`a", "`\ba", 0x00e0 }, - { "`e", "`\be", 0x00e8 }, - { "`i", "`\bi", 0x00ec }, - { "`o", "`\bo", 0x00f2 }, - { "`u", "`\bu", 0x00f9 }, - { "~A", "~\bA", 0x00c3 }, - { "~N", "~\bN", 0x00d1 }, - { "~O", "~\bO", 0x00d5 }, - { "~a", "~\ba", 0x00e3 }, - { "~n", "~\bn", 0x00f1 }, - { "~o", "~\bo", 0x00f5 }, - { ":A", "\"\bA", 0x00c4 }, - { ":E", "\"\bE", 0x00cb }, - { ":I", "\"\bI", 0x00cf }, - { ":O", "\"\bO", 0x00d6 }, - { ":U", "\"\bU", 0x00dc }, - { ":a", "\"\ba", 0x00e4 }, - { ":e", "\"\be", 0x00eb }, - { ":i", "\"\bi", 0x00ef }, - { ":o", "\"\bo", 0x00f6 }, - { ":u", "\"\bu", 0x00fc }, - { ":y", "\"\by", 0x00ff }, - { "^A", "^\bA", 0x00c2 }, - { "^E", "^\bE", 0x00ca }, - { "^I", "^\bI", 0x00ce }, - { "^O", "^\bO", 0x00d4 }, - { "^U", "^\bU", 0x00db }, - { "^a", "^\ba", 0x00e2 }, - { "^e", "^\be", 0x00ea }, - { "^i", "^\bi", 0x00ee }, - { "^o", "^\bo", 0x00f4 }, - { "^u", "^\bu", 0x00fb }, - { ",C", ",\bC", 0x00c7 }, - { ",c", ",\bc", 0x00e7 }, - { "/L", "/\bL", 0x0141 }, - { "/l", "/\bl", 0x0142 }, - { "/O", "/\bO", 0x00d8 }, - { "/o", "/\bo", 0x00f8 }, - { "oA", "o\bA", 0x00c5 }, - { "oa", "o\ba", 0x00e5 }, - - /* Special letters. */ - { "-D", "-\bD", 0x00d0 }, - { "Sd", "d", 0x00f0 }, - { "TP", "Th", 0x00de }, - { "Tp", "th", 0x00fe }, - { ".i", "i", 0x0131 }, - { ".j", "j", 0x0237 }, - - /* Currency. */ - { "Do", "$", 0x0024 }, - { "ct", "/\bc", 0x00a2 }, - { "Eu", "EUR", 0x20ac }, - { "eu", "EUR", 0x20ac }, - { "Ye", "=\bY", 0x00a5 }, - { "Po", "GBP", 0x00a3 }, - { "Cs", "o\bx", 0x00a4 }, - { "Fn", ",\bf", 0x0192 }, - - /* Units. */ - { "de", "", 0x00b0 }, - { "%0", "%o", 0x2030 }, - { "fm", "\'", 0x2032 }, - { "sd", "''", 0x2033 }, - { "mc", ",\bu", 0x00b5 }, - { "Of", "_\ba", 0x00aa }, - { "Om", "_\bo", 0x00ba }, - - /* Greek characters. */ - { "*A", "A", 0x0391 }, - { "*B", "B", 0x0392 }, - { "*G", "G", 0x0393 }, - { "*D", "_\b/_\b\\", 0x0394 }, - { "*E", "E", 0x0395 }, - { "*Z", "Z", 0x0396 }, - { "*Y", "H", 0x0397 }, - { "*H", "-\bO", 0x0398 }, - { "*I", "I", 0x0399 }, - { "*K", "K", 0x039a }, - { "*L", "/\\", 0x039b }, - { "*M", "M", 0x039c }, - { "*N", "N", 0x039d }, - { "*C", "_\bH", 0x039e }, - { "*O", "O", 0x039f }, - { "*P", "TT", 0x03a0 }, - { "*R", "P", 0x03a1 }, - { "*S", "S", 0x03a3 }, - { "*T", "T", 0x03a4 }, - { "*U", "Y", 0x03a5 }, - { "*F", "I\bO", 0x03a6 }, - { "*X", "X", 0x03a7 }, - { "*Q", "I\bY", 0x03a8 }, - { "*W", "_\bO", 0x03a9 }, - { "*a", "a", 0x03b1 }, - { "*b", "B", 0x03b2 }, - { "*g", "y", 0x03b3 }, - { "*d", "d", 0x03b4 }, - { "*e", "e", 0x03b5 }, - { "*z", ",\bC", 0x03b6 }, - { "*y", "n", 0x03b7 }, - { "*h", "-\b0", 0x03b8 }, - { "*i", "i", 0x03b9 }, - { "*k", "k", 0x03ba }, - { "*l", ">\b\\", 0x03bb }, - { "*m", ",\bu", 0x03bc }, - { "*n", "v", 0x03bd }, - { "*c", ",\bE", 0x03be }, - { "*o", "o", 0x03bf }, - { "*p", "-\bn", 0x03c0 }, - { "*r", "p", 0x03c1 }, - { "*s", "-\bo", 0x03c3 }, - { "*t", "~\bt", 0x03c4 }, - { "*u", "u", 0x03c5 }, - { "*f", "|\bo", 0x03d5 }, - { "*x", "x", 0x03c7 }, - { "*q", "|\bu", 0x03c8 }, - { "*w", "w", 0x03c9 }, - { "+h", "-\b0", 0x03d1 }, - { "+f", "|\bo", 0x03c6 }, - { "+p", "-\bw", 0x03d6 }, - { "+e", "e", 0x03f5 }, - { "ts", "s", 0x03c2 }, -}; - -static struct ohash mchars; - - -void -mchars_free(void) -{ - - ohash_delete(&mchars); -} - -void -mchars_alloc(void) -{ - size_t i; - unsigned int slot; - - mandoc_ohash_init(&mchars, 9, offsetof(struct ln, roffcode)); - for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++) { - slot = ohash_qlookup(&mchars, lines[i].roffcode); - assert(ohash_find(&mchars, slot) == NULL); - ohash_insert(&mchars, slot, lines + i); - } -} - -int -mchars_spec2cp(const char *p, size_t sz) -{ - const struct ln *ln; - const char *end; - - end = p + sz; - ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end)); - return ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1; -} - -int -mchars_num2char(const char *p, size_t sz) -{ - int i; - - i = mandoc_strntoi(p, sz, 10); - return i >= 0 && i < 256 ? i : -1; -} - -int -mchars_num2uc(const char *p, size_t sz) -{ - int i; - - i = mandoc_strntoi(p, sz, 16); - assert(i >= 0 && i <= 0x10FFFF); - return i; -} - -const char * -mchars_spec2str(const char *p, size_t sz, size_t *rsz) -{ - const struct ln *ln; - const char *end; - - end = p + sz; - ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end)); - if (ln == NULL) { - *rsz = 1; - return sz == 1 ? p : NULL; - } - - *rsz = strlen(ln->ascii); - return ln->ascii; -} - -const char * -mchars_uc2str(int uc) -{ - size_t i; - - for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++) - if (uc == lines[i].unicode) - return lines[i].ascii; - return ""; -} Property changes on: head/contrib/mdocml/chars.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/main.h =================================================================== --- head/contrib/mdocml/main.h (revision 338825) +++ head/contrib/mdocml/main.h (nonexistent) @@ -1,53 +0,0 @@ -/* $Id: main.h,v 1.27 2017/03/03 14:23:23 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2014, 2015 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. - */ - -struct roff_man; -struct manoutput; - -/* - * Definitions for main.c-visible output device functions, e.g., -Thtml - * and -Tascii. Note that ascii_alloc() is named as such in - * anticipation of latin1_alloc() and so on, all of which map into the - * terminal output routines with different character settings. - */ - -void *html_alloc(const struct manoutput *); -void html_mdoc(void *, const struct roff_man *); -void html_man(void *, const struct roff_man *); -void html_free(void *); - -void tree_mdoc(void *, const struct roff_man *); -void tree_man(void *, const struct roff_man *); - -void man_mdoc(void *, const struct roff_man *); -void man_man(void *, const struct roff_man *); - -void *locale_alloc(const struct manoutput *); -void *utf8_alloc(const struct manoutput *); -void *ascii_alloc(const struct manoutput *); -void ascii_free(void *); - -void *pdf_alloc(const struct manoutput *); -void *ps_alloc(const struct manoutput *); -void pspdf_free(void *); - -void terminal_mdoc(void *, const struct roff_man *); -void terminal_man(void *, const struct roff_man *); -void terminal_sepline(void *); - -void markdown_mdoc(void *, const struct roff_man *); Property changes on: head/contrib/mdocml/main.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/roff_html.c =================================================================== --- head/contrib/mdocml/roff_html.c (revision 338825) +++ head/contrib/mdocml/roff_html.c (nonexistent) @@ -1,96 +0,0 @@ -/* $Id: roff_html.c,v 1.11 2017/06/24 14:38:33 schwarze Exp $ */ -/* - * Copyright (c) 2010 Kristaps Dzonsons - * 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. - */ -#include - -#include -#include - -#include "mandoc.h" -#include "roff.h" -#include "out.h" -#include "html.h" - -#define ROFF_HTML_ARGS struct html *h, const struct roff_node *n - -typedef void (*roff_html_pre_fp)(ROFF_HTML_ARGS); - -static void roff_html_pre_br(ROFF_HTML_ARGS); -static void roff_html_pre_ce(ROFF_HTML_ARGS); -static void roff_html_pre_sp(ROFF_HTML_ARGS); - -static const roff_html_pre_fp roff_html_pre_acts[ROFF_MAX] = { - roff_html_pre_br, /* br */ - roff_html_pre_ce, /* ce */ - NULL, /* ft */ - NULL, /* ll */ - NULL, /* mc */ - NULL, /* po */ - roff_html_pre_ce, /* rj */ - roff_html_pre_sp, /* sp */ - NULL, /* ta */ - NULL, /* ti */ -}; - - -void -roff_html_pre(struct html *h, const struct roff_node *n) -{ - assert(n->tok < ROFF_MAX); - if (roff_html_pre_acts[n->tok] != NULL) - (*roff_html_pre_acts[n->tok])(h, n); -} - -static void -roff_html_pre_br(ROFF_HTML_ARGS) -{ - struct tag *t; - - t = print_otag(h, TAG_DIV, ""); - print_text(h, "\\~"); /* So the div isn't empty. */ - print_tagq(h, t); -} - -static void -roff_html_pre_ce(ROFF_HTML_ARGS) -{ - for (n = n->child->next; n != NULL; n = n->next) { - if (n->type == ROFFT_TEXT) { - if (n->flags & NODE_LINE) - roff_html_pre_br(h, n); - print_text(h, n->string); - } else - roff_html_pre(h, n); - } - roff_html_pre_br(h, n); -} - -static void -roff_html_pre_sp(ROFF_HTML_ARGS) -{ - struct roffsu su; - - SCALE_VS_INIT(&su, 1); - if ((n = n->child) != NULL) { - if (a2roffsu(n->string, &su, SCALE_VS) == NULL) - su.scale = 1.0; - else if (su.scale < 0.0) - su.scale = 0.0; - } - print_otag(h, TAG_DIV, "suh", &su); - print_text(h, "\\~"); /* So the div isn't empty. */ -} Property changes on: head/contrib/mdocml/roff_html.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/roff.h =================================================================== --- head/contrib/mdocml/roff.h (revision 338825) +++ head/contrib/mdocml/roff.h (nonexistent) @@ -1,579 +0,0 @@ -/* $Id: roff.h,v 1.58 2017/07/08 14:51:05 schwarze Exp $ */ -/* - * Copyright (c) 2008, 2009, 2010, 2011 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. - */ - -struct ohash; -struct mdoc_arg; -union mdoc_data; - -enum roff_macroset { - MACROSET_NONE = 0, - MACROSET_MDOC, - MACROSET_MAN -}; - -enum roff_sec { - SEC_NONE = 0, - SEC_NAME, - SEC_LIBRARY, - SEC_SYNOPSIS, - SEC_DESCRIPTION, - SEC_CONTEXT, - SEC_IMPLEMENTATION, /* IMPLEMENTATION NOTES */ - SEC_RETURN_VALUES, - SEC_ENVIRONMENT, - SEC_FILES, - SEC_EXIT_STATUS, - SEC_EXAMPLES, - SEC_DIAGNOSTICS, - SEC_COMPATIBILITY, - SEC_ERRORS, - SEC_SEE_ALSO, - SEC_STANDARDS, - SEC_HISTORY, - SEC_AUTHORS, - SEC_CAVEATS, - SEC_BUGS, - SEC_SECURITY, - SEC_CUSTOM, - SEC__MAX -}; - -enum roff_type { - ROFFT_ROOT, - ROFFT_BLOCK, - ROFFT_HEAD, - ROFFT_BODY, - ROFFT_TAIL, - ROFFT_ELEM, - ROFFT_TEXT, - ROFFT_TBL, - ROFFT_EQN -}; - -enum roff_tok { - ROFF_br = 0, - ROFF_ce, - ROFF_ft, - ROFF_ll, - ROFF_mc, - ROFF_po, - ROFF_rj, - ROFF_sp, - ROFF_ta, - ROFF_ti, - ROFF_MAX, - ROFF_ab, - ROFF_ad, - ROFF_af, - ROFF_aln, - ROFF_als, - ROFF_am, - ROFF_am1, - ROFF_ami, - ROFF_ami1, - ROFF_as, - ROFF_as1, - ROFF_asciify, - ROFF_backtrace, - ROFF_bd, - ROFF_bleedat, - ROFF_blm, - ROFF_box, - ROFF_boxa, - ROFF_bp, - ROFF_BP, - ROFF_break, - ROFF_breakchar, - ROFF_brnl, - ROFF_brp, - ROFF_brpnl, - ROFF_c2, - ROFF_cc, - ROFF_cf, - ROFF_cflags, - ROFF_ch, - ROFF_char, - ROFF_chop, - ROFF_class, - ROFF_close, - ROFF_CL, - ROFF_color, - ROFF_composite, - ROFF_continue, - ROFF_cp, - ROFF_cropat, - ROFF_cs, - ROFF_cu, - ROFF_da, - ROFF_dch, - ROFF_Dd, - ROFF_de, - ROFF_de1, - ROFF_defcolor, - ROFF_dei, - ROFF_dei1, - ROFF_device, - ROFF_devicem, - ROFF_di, - ROFF_do, - ROFF_ds, - ROFF_ds1, - ROFF_dwh, - ROFF_dt, - ROFF_ec, - ROFF_ecr, - ROFF_ecs, - ROFF_el, - ROFF_em, - ROFF_EN, - ROFF_eo, - ROFF_EP, - ROFF_EQ, - ROFF_errprint, - ROFF_ev, - ROFF_evc, - ROFF_ex, - ROFF_fallback, - ROFF_fam, - ROFF_fc, - ROFF_fchar, - ROFF_fcolor, - ROFF_fdeferlig, - ROFF_feature, - /* MAN_fi; ignored in mdoc(7) */ - ROFF_fkern, - ROFF_fl, - ROFF_flig, - ROFF_fp, - ROFF_fps, - ROFF_fschar, - ROFF_fspacewidth, - ROFF_fspecial, - ROFF_ftr, - ROFF_fzoom, - ROFF_gcolor, - ROFF_hc, - ROFF_hcode, - ROFF_hidechar, - ROFF_hla, - ROFF_hlm, - ROFF_hpf, - ROFF_hpfa, - ROFF_hpfcode, - ROFF_hw, - ROFF_hy, - ROFF_hylang, - ROFF_hylen, - ROFF_hym, - ROFF_hypp, - ROFF_hys, - ROFF_ie, - ROFF_if, - ROFF_ig, - /* MAN_in; ignored in mdoc(7) */ - ROFF_index, - ROFF_it, - ROFF_itc, - ROFF_IX, - ROFF_kern, - ROFF_kernafter, - ROFF_kernbefore, - ROFF_kernpair, - ROFF_lc, - ROFF_lc_ctype, - ROFF_lds, - ROFF_length, - ROFF_letadj, - ROFF_lf, - ROFF_lg, - ROFF_lhang, - ROFF_linetabs, - ROFF_lnr, - ROFF_lnrf, - ROFF_lpfx, - ROFF_ls, - ROFF_lsm, - ROFF_lt, - ROFF_mediasize, - ROFF_minss, - ROFF_mk, - ROFF_mso, - ROFF_na, - ROFF_ne, - /* MAN_nf; ignored in mdoc(7) */ - ROFF_nh, - ROFF_nhychar, - ROFF_nm, - ROFF_nn, - ROFF_nop, - ROFF_nr, - ROFF_nrf, - ROFF_nroff, - ROFF_ns, - ROFF_nx, - ROFF_open, - ROFF_opena, - ROFF_os, - ROFF_output, - ROFF_padj, - ROFF_papersize, - ROFF_pc, - ROFF_pev, - ROFF_pi, - ROFF_PI, - ROFF_pl, - ROFF_pm, - ROFF_pn, - ROFF_pnr, - ROFF_ps, - ROFF_psbb, - ROFF_pshape, - ROFF_pso, - ROFF_ptr, - ROFF_pvs, - ROFF_rchar, - ROFF_rd, - ROFF_recursionlimit, - ROFF_return, - ROFF_rfschar, - ROFF_rhang, - ROFF_rm, - ROFF_rn, - ROFF_rnn, - ROFF_rr, - ROFF_rs, - ROFF_rt, - ROFF_schar, - ROFF_sentchar, - ROFF_shc, - ROFF_shift, - ROFF_sizes, - ROFF_so, - ROFF_spacewidth, - ROFF_special, - ROFF_spreadwarn, - ROFF_ss, - ROFF_sty, - ROFF_substring, - ROFF_sv, - ROFF_sy, - ROFF_T_, - ROFF_tc, - ROFF_TE, - ROFF_TH, - ROFF_tkf, - ROFF_tl, - ROFF_tm, - ROFF_tm1, - ROFF_tmc, - ROFF_tr, - ROFF_track, - ROFF_transchar, - ROFF_trf, - ROFF_trimat, - ROFF_trin, - ROFF_trnt, - ROFF_troff, - ROFF_TS, - ROFF_uf, - ROFF_ul, - ROFF_unformat, - ROFF_unwatch, - ROFF_unwatchn, - ROFF_vpt, - ROFF_vs, - ROFF_warn, - ROFF_warnscale, - ROFF_watch, - ROFF_watchlength, - ROFF_watchn, - ROFF_wh, - ROFF_while, - ROFF_write, - ROFF_writec, - ROFF_writem, - ROFF_xflag, - ROFF_cblock, - ROFF_RENAMED, - ROFF_USERDEF, - TOKEN_NONE, - MDOC_Dd, - MDOC_Dt, - MDOC_Os, - MDOC_Sh, - MDOC_Ss, - MDOC_Pp, - MDOC_D1, - MDOC_Dl, - MDOC_Bd, - MDOC_Ed, - MDOC_Bl, - MDOC_El, - MDOC_It, - MDOC_Ad, - MDOC_An, - MDOC_Ap, - MDOC_Ar, - MDOC_Cd, - MDOC_Cm, - MDOC_Dv, - MDOC_Er, - MDOC_Ev, - MDOC_Ex, - MDOC_Fa, - MDOC_Fd, - MDOC_Fl, - MDOC_Fn, - MDOC_Ft, - MDOC_Ic, - MDOC_In, - MDOC_Li, - MDOC_Nd, - MDOC_Nm, - MDOC_Op, - MDOC_Ot, - MDOC_Pa, - MDOC_Rv, - MDOC_St, - MDOC_Va, - MDOC_Vt, - MDOC_Xr, - MDOC__A, - MDOC__B, - MDOC__D, - MDOC__I, - MDOC__J, - MDOC__N, - MDOC__O, - MDOC__P, - MDOC__R, - MDOC__T, - MDOC__V, - MDOC_Ac, - MDOC_Ao, - MDOC_Aq, - MDOC_At, - MDOC_Bc, - MDOC_Bf, - MDOC_Bo, - MDOC_Bq, - MDOC_Bsx, - MDOC_Bx, - MDOC_Db, - MDOC_Dc, - MDOC_Do, - MDOC_Dq, - MDOC_Ec, - MDOC_Ef, - MDOC_Em, - MDOC_Eo, - MDOC_Fx, - MDOC_Ms, - MDOC_No, - MDOC_Ns, - MDOC_Nx, - MDOC_Ox, - MDOC_Pc, - MDOC_Pf, - MDOC_Po, - MDOC_Pq, - MDOC_Qc, - MDOC_Ql, - MDOC_Qo, - MDOC_Qq, - MDOC_Re, - MDOC_Rs, - MDOC_Sc, - MDOC_So, - MDOC_Sq, - MDOC_Sm, - MDOC_Sx, - MDOC_Sy, - MDOC_Tn, - MDOC_Ux, - MDOC_Xc, - MDOC_Xo, - MDOC_Fo, - MDOC_Fc, - MDOC_Oo, - MDOC_Oc, - MDOC_Bk, - MDOC_Ek, - MDOC_Bt, - MDOC_Hf, - MDOC_Fr, - MDOC_Ud, - MDOC_Lb, - MDOC_Lp, - MDOC_Lk, - MDOC_Mt, - MDOC_Brq, - MDOC_Bro, - MDOC_Brc, - MDOC__C, - MDOC_Es, - MDOC_En, - MDOC_Dx, - MDOC__Q, - MDOC__U, - MDOC_Ta, - MDOC_MAX, - MAN_TH, - MAN_SH, - MAN_SS, - MAN_TP, - MAN_LP, - MAN_PP, - MAN_P, - MAN_IP, - MAN_HP, - MAN_SM, - MAN_SB, - MAN_BI, - MAN_IB, - MAN_BR, - MAN_RB, - MAN_R, - MAN_B, - MAN_I, - MAN_IR, - MAN_RI, - MAN_nf, - MAN_fi, - MAN_RE, - MAN_RS, - MAN_DT, - MAN_UC, - MAN_PD, - MAN_AT, - MAN_in, - MAN_OP, - MAN_EX, - MAN_EE, - MAN_UR, - MAN_UE, - MAN_MT, - MAN_ME, - MAN_MAX -}; - -enum roff_next { - ROFF_NEXT_SIBLING = 0, - ROFF_NEXT_CHILD -}; - -/* - * Indicates that a BODY's formatting has ended, but - * the scope is still open. Used for badly nested blocks. - */ -enum mdoc_endbody { - ENDBODY_NOT = 0, - ENDBODY_SPACE /* Is broken: append a space. */ -}; - -struct roff_node { - struct roff_node *parent; /* Parent AST node. */ - struct roff_node *child; /* First child AST node. */ - struct roff_node *last; /* Last child AST node. */ - struct roff_node *next; /* Sibling AST node. */ - struct roff_node *prev; /* Prior sibling AST node. */ - struct roff_node *head; /* BLOCK */ - struct roff_node *body; /* BLOCK/ENDBODY */ - struct roff_node *tail; /* BLOCK */ - struct mdoc_arg *args; /* BLOCK/ELEM */ - union mdoc_data *norm; /* Normalized arguments. */ - char *string; /* TEXT */ - const struct tbl_span *span; /* TBL */ - struct eqn_box *eqn; /* EQN */ - int line; /* Input file line number. */ - int pos; /* Input file column number. */ - int flags; -#define NODE_VALID (1 << 0) /* Has been validated. */ -#define NODE_ENDED (1 << 1) /* Gone past body end mark. */ -#define NODE_EOS (1 << 2) /* At sentence boundary. */ -#define NODE_LINE (1 << 3) /* First macro/text on line. */ -#define NODE_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting. */ -#define NODE_BROKEN (1 << 5) /* Must validate parent when ending. */ -#define NODE_DELIMO (1 << 6) -#define NODE_DELIMC (1 << 7) -#define NODE_NOSRC (1 << 8) /* Generated node, not in input file. */ -#define NODE_NOPRT (1 << 9) /* Shall not print anything. */ - int prev_font; /* Before entering this node. */ - int aux; /* Decoded node data, type-dependent. */ - enum roff_tok tok; /* Request or macro ID. */ - enum roff_type type; /* AST node type. */ - enum roff_sec sec; /* Current named section. */ - enum mdoc_endbody end; /* BODY */ -}; - -struct roff_meta { - char *msec; /* Manual section, usually a digit. */ - char *vol; /* Manual volume title. */ - char *os; /* Operating system. */ - char *arch; /* Machine architecture. */ - char *title; /* Manual title, usually CAPS. */ - char *name; /* Leading manual name. */ - char *date; /* Normalized date. */ - int hasbody; /* Document is not empty. */ - int rcsids; /* Bits indexed by enum mandoc_os. */ - enum mandoc_os os_e; /* Operating system. */ -}; - -struct roff_man { - struct roff_meta meta; /* Document meta-data. */ - struct mparse *parse; /* Parse pointer. */ - struct roff *roff; /* Roff parser state data. */ - struct ohash *mdocmac; /* Mdoc macro lookup table. */ - struct ohash *manmac; /* Man macro lookup table. */ - const char *os_s; /* Default operating system. */ - struct roff_node *first; /* The first node parsed. */ - struct roff_node *last; /* The last node parsed. */ - struct roff_node *last_es; /* The most recent Es node. */ - int quick; /* Abort parse early. */ - int flags; /* Parse flags. */ -#define MDOC_LITERAL (1 << 1) /* In a literal scope. */ -#define MDOC_PBODY (1 << 2) /* In the document body. */ -#define MDOC_NEWLINE (1 << 3) /* First macro/text in a line. */ -#define MDOC_PHRASE (1 << 4) /* In a Bl -column phrase. */ -#define MDOC_PHRASELIT (1 << 5) /* Literal within a phrase. */ -#define MDOC_FREECOL (1 << 6) /* `It' invocation should close. */ -#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting. */ -#define MDOC_KEEP (1 << 8) /* In a word keep. */ -#define MDOC_SMOFF (1 << 9) /* Spacing is off. */ -#define MDOC_NODELIMC (1 << 10) /* Disable closing delimiter handling. */ -#define MAN_ELINE (1 << 11) /* Next-line element scope. */ -#define MAN_BLINE (1 << 12) /* Next-line block scope. */ -#define MDOC_PHRASEQF (1 << 13) /* Quote first word encountered. */ -#define MDOC_PHRASEQL (1 << 14) /* Quote last word of this phrase. */ -#define MDOC_PHRASEQN (1 << 15) /* Quote first word of the next phrase. */ -#define MAN_LITERAL MDOC_LITERAL -#define MAN_NEWLINE MDOC_NEWLINE - enum roff_macroset macroset; /* Kind of high-level macros used. */ - enum roff_sec lastsec; /* Last section seen. */ - enum roff_sec lastnamed; /* Last standard section seen. */ - enum roff_next next; /* Where to put the next node. */ -}; - -extern const char *const *roff_name; - - -void deroff(char **, const struct roff_node *); -struct ohash *roffhash_alloc(enum roff_tok, enum roff_tok); -enum roff_tok roffhash_find(struct ohash *, const char *, size_t); -void roffhash_free(struct ohash *); -void roff_validate(struct roff_man *); Property changes on: head/contrib/mdocml/roff.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/dbm.c =================================================================== --- head/contrib/mdocml/dbm.c (revision 338825) +++ head/contrib/mdocml/dbm.c (nonexistent) @@ -1,480 +0,0 @@ -/* $Id: dbm.c,v 1.5 2016/10/18 22:27:25 schwarze Exp $ */ -/* - * Copyright (c) 2016 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. - * - * Map-based version of the mandoc database, for read-only access. - * The interface is defined in "dbm.h". - */ -#include "config.h" - -#include -#if HAVE_ENDIAN -#include -#elif HAVE_SYS_ENDIAN -#include -#elif HAVE_NTOHL -#include -#endif -#if HAVE_ERR -#include -#endif -#include -#include -#include -#include -#include -#include - -#include "mansearch.h" -#include "dbm_map.h" -#include "dbm.h" - -struct macro { - int32_t value; - int32_t pages; -}; - -struct page { - int32_t name; - int32_t sect; - int32_t arch; - int32_t desc; - int32_t file; -}; - -enum iter { - ITER_NONE = 0, - ITER_NAME, - ITER_SECT, - ITER_ARCH, - ITER_DESC, - ITER_MACRO -}; - -static struct macro *macros[MACRO_MAX]; -static int32_t nvals[MACRO_MAX]; -static struct page *pages; -static int32_t npages; -static enum iter iteration; - -static struct dbm_res page_bytitle(enum iter, const struct dbm_match *); -static struct dbm_res page_byarch(const struct dbm_match *); -static struct dbm_res page_bymacro(int32_t, const struct dbm_match *); -static char *macro_bypage(int32_t, int32_t); - - -/*** top level functions **********************************************/ - -/* - * Open a disk-based mandoc database for read-only access. - * Map the pages and macros[] arrays. - * Return 0 on success. Return -1 and set errno on failure. - */ -int -dbm_open(const char *fname) -{ - const int32_t *mp, *ep; - int32_t im; - - if (dbm_map(fname) == -1) - return -1; - - if ((npages = be32toh(*dbm_getint(4))) < 0) { - warnx("dbm_open(%s): Invalid number of pages: %d", - fname, npages); - goto fail; - } - pages = (struct page *)dbm_getint(5); - - if ((mp = dbm_get(*dbm_getint(2))) == NULL) { - warnx("dbm_open(%s): Invalid offset of macros array", fname); - goto fail; - } - if (be32toh(*mp) != MACRO_MAX) { - warnx("dbm_open(%s): Invalid number of macros: %d", - fname, be32toh(*mp)); - goto fail; - } - for (im = 0; im < MACRO_MAX; im++) { - if ((ep = dbm_get(*++mp)) == NULL) { - warnx("dbm_open(%s): Invalid offset of macro %d", - fname, im); - goto fail; - } - nvals[im] = be32toh(*ep); - macros[im] = (struct macro *)++ep; - } - return 0; - -fail: - dbm_unmap(); - errno = EFTYPE; - return -1; -} - -void -dbm_close(void) -{ - dbm_unmap(); -} - - -/*** functions for handling pages *************************************/ - -int32_t -dbm_page_count(void) -{ - return npages; -} - -/* - * Give the caller pointers to the data for one manual page. - */ -struct dbm_page * -dbm_page_get(int32_t ip) -{ - static struct dbm_page res; - - assert(ip >= 0); - assert(ip < npages); - res.name = dbm_get(pages[ip].name); - if (res.name == NULL) - res.name = "(NULL)"; - res.sect = dbm_get(pages[ip].sect); - if (res.sect == NULL) - res.sect = "(NULL)"; - res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL; - res.desc = dbm_get(pages[ip].desc); - if (res.desc == NULL) - res.desc = "(NULL)"; - res.file = dbm_get(pages[ip].file); - if (res.file == NULL) - res.file = " (NULL)"; - res.addr = dbm_addr(pages + ip); - return &res; -} - -/* - * Functions to start filtered iterations over manual pages. - */ -void -dbm_page_byname(const struct dbm_match *match) -{ - assert(match != NULL); - page_bytitle(ITER_NAME, match); -} - -void -dbm_page_bysect(const struct dbm_match *match) -{ - assert(match != NULL); - page_bytitle(ITER_SECT, match); -} - -void -dbm_page_byarch(const struct dbm_match *match) -{ - assert(match != NULL); - page_byarch(match); -} - -void -dbm_page_bydesc(const struct dbm_match *match) -{ - assert(match != NULL); - page_bytitle(ITER_DESC, match); -} - -void -dbm_page_bymacro(int32_t im, const struct dbm_match *match) -{ - assert(im >= 0); - assert(im < MACRO_MAX); - assert(match != NULL); - page_bymacro(im, match); -} - -/* - * Return the number of the next manual page in the current iteration. - */ -struct dbm_res -dbm_page_next(void) -{ - struct dbm_res res = {-1, 0}; - - switch(iteration) { - case ITER_NONE: - return res; - case ITER_ARCH: - return page_byarch(NULL); - case ITER_MACRO: - return page_bymacro(0, NULL); - default: - return page_bytitle(iteration, NULL); - } -} - -/* - * Functions implementing the iteration over manual pages. - */ -static struct dbm_res -page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match) -{ - static const struct dbm_match *match; - static const char *cp; - static int32_t ip; - struct dbm_res res = {-1, 0}; - - assert(arg_iter == ITER_NAME || arg_iter == ITER_DESC || - arg_iter == ITER_SECT); - - /* Initialize for a new iteration. */ - - if (arg_match != NULL) { - iteration = arg_iter; - match = arg_match; - switch (iteration) { - case ITER_NAME: - cp = dbm_get(pages[0].name); - break; - case ITER_SECT: - cp = dbm_get(pages[0].sect); - break; - case ITER_DESC: - cp = dbm_get(pages[0].desc); - break; - default: - abort(); - } - if (cp == NULL) { - iteration = ITER_NONE; - match = NULL; - cp = NULL; - ip = npages; - } else - ip = 0; - return res; - } - - /* Search for a name. */ - - while (ip < npages) { - if (iteration == ITER_NAME) - cp++; - if (dbm_match(match, cp)) - break; - cp = strchr(cp, '\0') + 1; - if (iteration == ITER_DESC) - ip++; - else if (*cp == '\0') { - cp++; - ip++; - } - } - - /* Reached the end without a match. */ - - if (ip == npages) { - iteration = ITER_NONE; - match = NULL; - cp = NULL; - return res; - } - - /* Found a match; save the quality for later retrieval. */ - - res.page = ip; - res.bits = iteration == ITER_NAME ? cp[-1] : 0; - - /* Skip the remaining names of this page. */ - - if (++ip < npages) { - do { - cp++; - } while (cp[-1] != '\0' || - (iteration != ITER_DESC && cp[-2] != '\0')); - } - return res; -} - -static struct dbm_res -page_byarch(const struct dbm_match *arg_match) -{ - static const struct dbm_match *match; - struct dbm_res res = {-1, 0}; - static int32_t ip; - const char *cp; - - /* Initialize for a new iteration. */ - - if (arg_match != NULL) { - iteration = ITER_ARCH; - match = arg_match; - ip = 0; - return res; - } - - /* Search for an architecture. */ - - for ( ; ip < npages; ip++) - if (pages[ip].arch) - for (cp = dbm_get(pages[ip].arch); - *cp != '\0'; - cp = strchr(cp, '\0') + 1) - if (dbm_match(match, cp)) { - res.page = ip++; - return res; - } - - /* Reached the end without a match. */ - - iteration = ITER_NONE; - match = NULL; - return res; -} - -static struct dbm_res -page_bymacro(int32_t arg_im, const struct dbm_match *arg_match) -{ - static const struct dbm_match *match; - static const int32_t *pp; - static const char *cp; - static int32_t im, iv; - struct dbm_res res = {-1, 0}; - - assert(im >= 0); - assert(im < MACRO_MAX); - - /* Initialize for a new iteration. */ - - if (arg_match != NULL) { - iteration = ITER_MACRO; - match = arg_match; - im = arg_im; - cp = nvals[im] ? dbm_get(macros[im]->value) : NULL; - pp = NULL; - iv = -1; - return res; - } - if (iteration != ITER_MACRO) - return res; - - /* Find the next matching macro value. */ - - while (pp == NULL || *pp == 0) { - if (++iv == nvals[im]) { - iteration = ITER_NONE; - return res; - } - if (iv) - cp = strchr(cp, '\0') + 1; - if (dbm_match(match, cp)) - pp = dbm_get(macros[im][iv].pages); - } - - /* Found a matching page. */ - - res.page = (struct page *)dbm_get(*pp++) - pages; - return res; -} - - -/*** functions for handling macros ************************************/ - -int32_t -dbm_macro_count(int32_t im) -{ - assert(im >= 0); - assert(im < MACRO_MAX); - return nvals[im]; -} - -struct dbm_macro * -dbm_macro_get(int32_t im, int32_t iv) -{ - static struct dbm_macro macro; - - assert(im >= 0); - assert(im < MACRO_MAX); - assert(iv >= 0); - assert(iv < nvals[im]); - macro.value = dbm_get(macros[im][iv].value); - macro.pp = dbm_get(macros[im][iv].pages); - return ¯o; -} - -/* - * Filtered iteration over macro entries. - */ -void -dbm_macro_bypage(int32_t im, int32_t ip) -{ - assert(im >= 0); - assert(im < MACRO_MAX); - assert(ip != 0); - macro_bypage(im, ip); -} - -char * -dbm_macro_next(void) -{ - return macro_bypage(MACRO_MAX, 0); -} - -static char * -macro_bypage(int32_t arg_im, int32_t arg_ip) -{ - static const int32_t *pp; - static int32_t im, ip, iv; - - /* Initialize for a new iteration. */ - - if (arg_im < MACRO_MAX && arg_ip != 0) { - im = arg_im; - ip = arg_ip; - pp = dbm_get(macros[im]->pages); - iv = 0; - return NULL; - } - if (im >= MACRO_MAX) - return NULL; - - /* Search for the next value. */ - - while (iv < nvals[im]) { - if (*pp == ip) - break; - if (*pp == 0) - iv++; - pp++; - } - - /* Reached the end without a match. */ - - if (iv == nvals[im]) { - im = MACRO_MAX; - ip = 0; - pp = NULL; - return NULL; - } - - /* Found a match; skip the remaining pages of this entry. */ - - if (++iv < nvals[im]) - while (*pp++ != 0) - continue; - - return dbm_get(macros[im][iv - 1].value); -} Property changes on: head/contrib/mdocml/dbm.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/man_validate.c =================================================================== --- head/contrib/mdocml/man_validate.c (revision 338825) +++ head/contrib/mdocml/man_validate.c (nonexistent) @@ -1,494 +0,0 @@ -/* $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_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 */ - 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, 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_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, 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->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; - } -} Property changes on: head/contrib/mdocml/man_validate.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-strcasestr.c =================================================================== --- head/contrib/mdocml/test-strcasestr.c (revision 338825) +++ head/contrib/mdocml/test-strcasestr.c (nonexistent) @@ -1,13 +0,0 @@ -#if defined(__linux__) || defined(__MINT__) -# define _GNU_SOURCE /* strcasestr() */ -#endif - -#include - -int -main(void) -{ - const char *big = "BigString"; - char *cp = strcasestr(big, "Gst"); - return cp != big + 2; -} Property changes on: head/contrib/mdocml/test-strcasestr.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mdoc_validate.c =================================================================== --- head/contrib/mdocml/mdoc_validate.c (revision 338825) +++ head/contrib/mdocml/mdoc_validate.c (nonexistent) @@ -1,2906 +0,0 @@ -/* $Id: mdoc_validate.c,v 1.352 2017/08/02 13:29:04 schwarze Exp $ */ -/* - * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010-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 -#ifndef OSNAME -#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 "libmandoc.h" -#include "roff_int.h" -#include "libmdoc.h" - -/* FIXME: .Bl -diag can't have non-text children in HEAD. */ - -#define POST_ARGS struct roff_man *mdoc - -enum check_ineq { - CHECK_LT, - CHECK_GT, - CHECK_EQ -}; - -typedef void (*v_post)(POST_ARGS); - -static int build_list(struct roff_man *, int); -static void check_text(struct roff_man *, int, int, char *); -static void check_argv(struct roff_man *, - struct roff_node *, struct mdoc_argv *); -static void check_args(struct roff_man *, struct roff_node *); -static void check_toptext(struct roff_man *, int, int, const char *); -static int child_an(const struct roff_node *); -static size_t macro2len(enum roff_tok); -static void rewrite_macro2len(struct roff_man *, char **); -static int similar(const char *, const char *); - -static void post_an(POST_ARGS); -static void post_an_norm(POST_ARGS); -static void post_at(POST_ARGS); -static void post_bd(POST_ARGS); -static void post_bf(POST_ARGS); -static void post_bk(POST_ARGS); -static void post_bl(POST_ARGS); -static void post_bl_block(POST_ARGS); -static void post_bl_head(POST_ARGS); -static void post_bl_norm(POST_ARGS); -static void post_bx(POST_ARGS); -static void post_defaults(POST_ARGS); -static void post_display(POST_ARGS); -static void post_dd(POST_ARGS); -static void post_delim(POST_ARGS); -static void post_delim_nb(POST_ARGS); -static void post_dt(POST_ARGS); -static void post_en(POST_ARGS); -static void post_es(POST_ARGS); -static void post_eoln(POST_ARGS); -static void post_ex(POST_ARGS); -static void post_fa(POST_ARGS); -static void post_fn(POST_ARGS); -static void post_fname(POST_ARGS); -static void post_fo(POST_ARGS); -static void post_hyph(POST_ARGS); -static void post_ignpar(POST_ARGS); -static void post_it(POST_ARGS); -static void post_lb(POST_ARGS); -static void post_nd(POST_ARGS); -static void post_nm(POST_ARGS); -static void post_ns(POST_ARGS); -static void post_obsolete(POST_ARGS); -static void post_os(POST_ARGS); -static void post_par(POST_ARGS); -static void post_prevpar(POST_ARGS); -static void post_root(POST_ARGS); -static void post_rs(POST_ARGS); -static void post_rv(POST_ARGS); -static void post_sh(POST_ARGS); -static void post_sh_head(POST_ARGS); -static void post_sh_name(POST_ARGS); -static void post_sh_see_also(POST_ARGS); -static void post_sh_authors(POST_ARGS); -static void post_sm(POST_ARGS); -static void post_st(POST_ARGS); -static void post_std(POST_ARGS); -static void post_sx(POST_ARGS); -static void post_useless(POST_ARGS); -static void post_xr(POST_ARGS); -static void post_xx(POST_ARGS); - -static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = { - post_dd, /* Dd */ - post_dt, /* Dt */ - post_os, /* Os */ - post_sh, /* Sh */ - post_ignpar, /* Ss */ - post_par, /* Pp */ - post_display, /* D1 */ - post_display, /* Dl */ - post_display, /* Bd */ - NULL, /* Ed */ - post_bl, /* Bl */ - NULL, /* El */ - post_it, /* It */ - post_delim_nb, /* Ad */ - post_an, /* An */ - NULL, /* Ap */ - post_defaults, /* Ar */ - NULL, /* Cd */ - post_delim_nb, /* Cm */ - post_delim_nb, /* Dv */ - post_delim_nb, /* Er */ - post_delim_nb, /* Ev */ - post_ex, /* Ex */ - post_fa, /* Fa */ - NULL, /* Fd */ - post_delim_nb, /* Fl */ - post_fn, /* Fn */ - post_delim_nb, /* Ft */ - post_delim_nb, /* Ic */ - post_delim_nb, /* In */ - post_defaults, /* Li */ - post_nd, /* Nd */ - post_nm, /* Nm */ - post_delim_nb, /* Op */ - post_obsolete, /* Ot */ - post_defaults, /* Pa */ - post_rv, /* Rv */ - post_st, /* St */ - post_delim_nb, /* Va */ - post_delim_nb, /* Vt */ - post_xr, /* Xr */ - NULL, /* %A */ - post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ - NULL, /* %D */ - NULL, /* %I */ - NULL, /* %J */ - post_hyph, /* %N */ - post_hyph, /* %O */ - NULL, /* %P */ - post_hyph, /* %R */ - post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ - NULL, /* %V */ - NULL, /* Ac */ - post_delim_nb, /* Ao */ - post_delim_nb, /* Aq */ - post_at, /* At */ - NULL, /* Bc */ - post_bf, /* Bf */ - post_delim_nb, /* Bo */ - NULL, /* Bq */ - post_xx, /* Bsx */ - post_bx, /* Bx */ - post_obsolete, /* Db */ - NULL, /* Dc */ - NULL, /* Do */ - NULL, /* Dq */ - NULL, /* Ec */ - NULL, /* Ef */ - post_delim_nb, /* Em */ - NULL, /* Eo */ - post_xx, /* Fx */ - post_delim_nb, /* Ms */ - NULL, /* No */ - post_ns, /* Ns */ - post_xx, /* Nx */ - post_xx, /* Ox */ - NULL, /* Pc */ - NULL, /* Pf */ - post_delim_nb, /* Po */ - post_delim_nb, /* Pq */ - NULL, /* Qc */ - post_delim_nb, /* Ql */ - post_delim_nb, /* Qo */ - post_delim_nb, /* Qq */ - NULL, /* Re */ - post_rs, /* Rs */ - NULL, /* Sc */ - post_delim_nb, /* So */ - post_delim_nb, /* Sq */ - post_sm, /* Sm */ - post_sx, /* Sx */ - post_delim_nb, /* Sy */ - post_useless, /* Tn */ - post_xx, /* Ux */ - NULL, /* Xc */ - NULL, /* Xo */ - post_fo, /* Fo */ - NULL, /* Fc */ - post_delim_nb, /* Oo */ - NULL, /* Oc */ - post_bk, /* Bk */ - NULL, /* Ek */ - post_eoln, /* Bt */ - post_obsolete, /* Hf */ - post_obsolete, /* Fr */ - post_eoln, /* Ud */ - post_lb, /* Lb */ - post_par, /* Lp */ - post_delim_nb, /* Lk */ - post_defaults, /* Mt */ - post_delim_nb, /* Brq */ - post_delim_nb, /* Bro */ - NULL, /* Brc */ - NULL, /* %C */ - post_es, /* Es */ - post_en, /* En */ - post_xx, /* Dx */ - NULL, /* %Q */ - NULL, /* %U */ - NULL, /* Ta */ -}; -static const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd; - -#define RSORD_MAX 14 /* Number of `Rs' blocks. */ - -static const enum roff_tok rsord[RSORD_MAX] = { - MDOC__A, - MDOC__T, - MDOC__B, - MDOC__I, - MDOC__J, - MDOC__R, - MDOC__N, - MDOC__V, - MDOC__U, - MDOC__P, - MDOC__Q, - MDOC__C, - MDOC__D, - MDOC__O -}; - -static const char * const secnames[SEC__MAX] = { - NULL, - "NAME", - "LIBRARY", - "SYNOPSIS", - "DESCRIPTION", - "CONTEXT", - "IMPLEMENTATION NOTES", - "RETURN VALUES", - "ENVIRONMENT", - "FILES", - "EXIT STATUS", - "EXAMPLES", - "DIAGNOSTICS", - "COMPATIBILITY", - "ERRORS", - "SEE ALSO", - "STANDARDS", - "HISTORY", - "AUTHORS", - "CAVEATS", - "BUGS", - "SECURITY CONSIDERATIONS", - NULL -}; - - -void -mdoc_node_validate(struct roff_man *mdoc) -{ - struct roff_node *n; - const v_post *p; - - n = mdoc->last; - mdoc->last = mdoc->last->child; - while (mdoc->last != NULL) { - mdoc_node_validate(mdoc); - if (mdoc->last == n) - mdoc->last = mdoc->last->child; - else - mdoc->last = mdoc->last->next; - } - - mdoc->last = n; - mdoc->next = ROFF_NEXT_SIBLING; - switch (n->type) { - case ROFFT_TEXT: - if (n->sec != SEC_SYNOPSIS || - (n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd)) - check_text(mdoc, n->line, n->pos, n->string); - if (n->parent->tok == MDOC_It || - (n->parent->type == ROFFT_BODY && - (n->parent->tok == MDOC_Sh || - n->parent->tok == MDOC_Ss))) - check_toptext(mdoc, n->line, n->pos, n->string); - break; - case ROFFT_EQN: - case ROFFT_TBL: - break; - case ROFFT_ROOT: - post_root(mdoc); - break; - default: - check_args(mdoc, mdoc->last); - - /* - * Closing delimiters are not special at the - * beginning of a block, opening delimiters - * are not special at the end. - */ - - if (n->child != NULL) - n->child->flags &= ~NODE_DELIMC; - if (n->last != NULL) - n->last->flags &= ~NODE_DELIMO; - - /* Call the macro's postprocessor. */ - - if (n->tok < ROFF_MAX) { - switch(n->tok) { - case ROFF_br: - case ROFF_sp: - post_par(mdoc); - break; - default: - roff_validate(mdoc); - break; - } - break; - } - - assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); - p = mdoc_valids + n->tok; - if (*p) - (*p)(mdoc); - if (mdoc->last == n) - mdoc_state(mdoc, n); - break; - } -} - -static void -check_args(struct roff_man *mdoc, struct roff_node *n) -{ - int i; - - if (NULL == n->args) - return; - - assert(n->args->argc); - for (i = 0; i < (int)n->args->argc; i++) - check_argv(mdoc, n, &n->args->argv[i]); -} - -static void -check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v) -{ - int i; - - for (i = 0; i < (int)v->sz; i++) - check_text(mdoc, v->line, v->pos, v->value[i]); -} - -static void -check_text(struct roff_man *mdoc, int ln, int pos, char *p) -{ - char *cp; - - if (MDOC_LITERAL & mdoc->flags) - return; - - for (cp = p; NULL != (p = strchr(p, '\t')); p++) - mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse, - ln, pos + (int)(p - cp), NULL); -} - -static void -check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) -{ - const char *cp, *cpr; - - if (*p == '\0') - return; - - if ((cp = strstr(p, "OpenBSD")) != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - ln, pos + (cp - p), "Ox"); - if ((cp = strstr(p, "NetBSD")) != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - ln, pos + (cp - p), "Nx"); - if ((cp = strstr(p, "FreeBSD")) != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - ln, pos + (cp - p), "Fx"); - if ((cp = strstr(p, "DragonFly")) != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - ln, pos + (cp - p), "Dx"); - - cp = p; - while ((cp = strstr(cp + 1, "()")) != NULL) { - for (cpr = cp - 1; cpr >= p; cpr--) - if (*cpr != '_' && !isalnum((unsigned char)*cpr)) - break; - if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) { - cpr++; - mandoc_vmsg(MANDOCERR_FUNC, mdoc->parse, - ln, pos + (cpr - p), - "%.*s()", (int)(cp - cpr), cpr); - } - } -} - -static void -post_delim(POST_ARGS) -{ - const struct roff_node *nch; - const char *lc; - enum mdelim delim; - enum roff_tok tok; - - tok = mdoc->last->tok; - nch = mdoc->last->last; - if (nch == NULL || nch->type != ROFFT_TEXT) - return; - lc = strchr(nch->string, '\0') - 1; - if (lc < nch->string) - return; - delim = mdoc_isdelim(lc); - if (delim == DELIM_NONE || delim == DELIM_OPEN) - return; - if (*lc == ')' && (tok == MDOC_Nd || tok == MDOC_Sh || - tok == MDOC_Ss || tok == MDOC_Fo)) - return; - - mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse, - nch->line, nch->pos + (lc - nch->string), - "%s%s %s", roff_name[tok], - nch == mdoc->last->child ? "" : " ...", nch->string); -} - -static void -post_delim_nb(POST_ARGS) -{ - const struct roff_node *nch; - const char *lc, *cp; - int nw; - enum mdelim delim; - enum roff_tok tok; - - /* - * Find candidates: at least two bytes, - * the last one a closing or middle delimiter. - */ - - tok = mdoc->last->tok; - nch = mdoc->last->last; - if (nch == NULL || nch->type != ROFFT_TEXT) - return; - lc = strchr(nch->string, '\0') - 1; - if (lc <= nch->string) - return; - delim = mdoc_isdelim(lc); - if (delim == DELIM_NONE || delim == DELIM_OPEN) - return; - - /* - * Reduce false positives by allowing various cases. - */ - - /* Escaped delimiters. */ - if (lc > nch->string + 1 && lc[-2] == '\\' && - (lc[-1] == '&' || lc[-1] == 'e')) - return; - - /* Specific byte sequences. */ - switch (*lc) { - case ')': - for (cp = lc; cp >= nch->string; cp--) - if (*cp == '(') - return; - break; - case '.': - if (lc > nch->string + 1 && lc[-2] == '.' && lc[-1] == '.') - return; - if (lc[-1] == '.') - return; - break; - case ';': - if (tok == MDOC_Vt) - return; - break; - case '?': - if (lc[-1] == '?') - return; - break; - case ']': - for (cp = lc; cp >= nch->string; cp--) - if (*cp == '[') - return; - break; - case '|': - if (lc == nch->string + 1 && lc[-1] == '|') - return; - default: - break; - } - - /* Exactly two non-alphanumeric bytes. */ - if (lc == nch->string + 1 && !isalnum((unsigned char)lc[-1])) - return; - - /* At least three alphabetic words with a sentence ending. */ - if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em || - tok == MDOC_Li || tok == MDOC_Po || tok == MDOC_Pq || - tok == MDOC_Sy)) { - nw = 0; - for (cp = lc - 1; cp >= nch->string; cp--) { - if (*cp == ' ') { - nw++; - if (cp > nch->string && cp[-1] == ',') - cp--; - } else if (isalpha((unsigned int)*cp)) { - if (nw > 1) - return; - } else - break; - } - } - - mandoc_vmsg(MANDOCERR_DELIM_NB, mdoc->parse, - nch->line, nch->pos + (lc - nch->string), - "%s%s %s", roff_name[tok], - nch == mdoc->last->child ? "" : " ...", nch->string); -} - -static void -post_bl_norm(POST_ARGS) -{ - struct roff_node *n; - struct mdoc_argv *argv, *wa; - int i; - enum mdocargt mdoclt; - enum mdoc_list lt; - - n = mdoc->last->parent; - n->norm->Bl.type = LIST__NONE; - - /* - * First figure out which kind of list to use: bind ourselves to - * the first mentioned list type and warn about any remaining - * ones. If we find no list type, we default to LIST_item. - */ - - wa = (n->args == NULL) ? NULL : n->args->argv; - mdoclt = MDOC_ARG_MAX; - for (i = 0; n->args && i < (int)n->args->argc; i++) { - argv = n->args->argv + i; - lt = LIST__NONE; - switch (argv->arg) { - /* Set list types. */ - case MDOC_Bullet: - lt = LIST_bullet; - break; - case MDOC_Dash: - lt = LIST_dash; - break; - case MDOC_Enum: - lt = LIST_enum; - break; - case MDOC_Hyphen: - lt = LIST_hyphen; - break; - case MDOC_Item: - lt = LIST_item; - break; - case MDOC_Tag: - lt = LIST_tag; - break; - case MDOC_Diag: - lt = LIST_diag; - break; - case MDOC_Hang: - lt = LIST_hang; - break; - case MDOC_Ohang: - lt = LIST_ohang; - break; - case MDOC_Inset: - lt = LIST_inset; - break; - case MDOC_Column: - lt = LIST_column; - break; - /* Set list arguments. */ - case MDOC_Compact: - if (n->norm->Bl.comp) - mandoc_msg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bl -compact"); - n->norm->Bl.comp = 1; - break; - case MDOC_Width: - wa = argv; - if (0 == argv->sz) { - mandoc_msg(MANDOCERR_ARG_EMPTY, - mdoc->parse, argv->line, - argv->pos, "Bl -width"); - n->norm->Bl.width = "0n"; - break; - } - if (NULL != n->norm->Bl.width) - mandoc_vmsg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bl -width %s", - argv->value[0]); - rewrite_macro2len(mdoc, argv->value); - n->norm->Bl.width = argv->value[0]; - break; - case MDOC_Offset: - if (0 == argv->sz) { - mandoc_msg(MANDOCERR_ARG_EMPTY, - mdoc->parse, argv->line, - argv->pos, "Bl -offset"); - break; - } - if (NULL != n->norm->Bl.offs) - mandoc_vmsg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bl -offset %s", - argv->value[0]); - rewrite_macro2len(mdoc, argv->value); - n->norm->Bl.offs = argv->value[0]; - break; - default: - continue; - } - if (LIST__NONE == lt) - continue; - mdoclt = argv->arg; - - /* Check: multiple list types. */ - - if (LIST__NONE != n->norm->Bl.type) { - mandoc_vmsg(MANDOCERR_BL_REP, - mdoc->parse, n->line, n->pos, - "Bl -%s", mdoc_argnames[argv->arg]); - continue; - } - - /* The list type should come first. */ - - if (n->norm->Bl.width || - n->norm->Bl.offs || - n->norm->Bl.comp) - mandoc_vmsg(MANDOCERR_BL_LATETYPE, - mdoc->parse, n->line, n->pos, "Bl -%s", - mdoc_argnames[n->args->argv[0].arg]); - - n->norm->Bl.type = lt; - if (LIST_column == lt) { - n->norm->Bl.ncols = argv->sz; - n->norm->Bl.cols = (void *)argv->value; - } - } - - /* Allow lists to default to LIST_item. */ - - if (LIST__NONE == n->norm->Bl.type) { - mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse, - n->line, n->pos, "Bl"); - n->norm->Bl.type = LIST_item; - mdoclt = MDOC_Item; - } - - /* - * Validate the width field. Some list types don't need width - * types and should be warned about them. Others should have it - * and must also be warned. Yet others have a default and need - * no warning. - */ - - switch (n->norm->Bl.type) { - case LIST_tag: - if (n->norm->Bl.width == NULL) - mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, - n->line, n->pos, "Bl -tag"); - break; - case LIST_column: - case LIST_diag: - case LIST_ohang: - case LIST_inset: - case LIST_item: - if (n->norm->Bl.width != NULL) - mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, - wa->line, wa->pos, "Bl -%s", - mdoc_argnames[mdoclt]); - n->norm->Bl.width = NULL; - break; - case LIST_bullet: - case LIST_dash: - case LIST_hyphen: - if (n->norm->Bl.width == NULL) - n->norm->Bl.width = "2n"; - break; - case LIST_enum: - if (n->norm->Bl.width == NULL) - n->norm->Bl.width = "3n"; - break; - default: - break; - } -} - -static void -post_bd(POST_ARGS) -{ - struct roff_node *n; - struct mdoc_argv *argv; - int i; - enum mdoc_disp dt; - - n = mdoc->last; - for (i = 0; n->args && i < (int)n->args->argc; i++) { - argv = n->args->argv + i; - dt = DISP__NONE; - - switch (argv->arg) { - case MDOC_Centred: - dt = DISP_centered; - break; - case MDOC_Ragged: - dt = DISP_ragged; - break; - case MDOC_Unfilled: - dt = DISP_unfilled; - break; - case MDOC_Filled: - dt = DISP_filled; - break; - case MDOC_Literal: - dt = DISP_literal; - break; - case MDOC_File: - mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse, - n->line, n->pos, NULL); - break; - case MDOC_Offset: - if (0 == argv->sz) { - mandoc_msg(MANDOCERR_ARG_EMPTY, - mdoc->parse, argv->line, - argv->pos, "Bd -offset"); - break; - } - if (NULL != n->norm->Bd.offs) - mandoc_vmsg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bd -offset %s", - argv->value[0]); - rewrite_macro2len(mdoc, argv->value); - n->norm->Bd.offs = argv->value[0]; - break; - case MDOC_Compact: - if (n->norm->Bd.comp) - mandoc_msg(MANDOCERR_ARG_REP, - mdoc->parse, argv->line, - argv->pos, "Bd -compact"); - n->norm->Bd.comp = 1; - break; - default: - abort(); - } - if (DISP__NONE == dt) - continue; - - if (DISP__NONE == n->norm->Bd.type) - n->norm->Bd.type = dt; - else - mandoc_vmsg(MANDOCERR_BD_REP, - mdoc->parse, n->line, n->pos, - "Bd -%s", mdoc_argnames[argv->arg]); - } - - if (DISP__NONE == n->norm->Bd.type) { - mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse, - n->line, n->pos, "Bd"); - n->norm->Bd.type = DISP_ragged; - } -} - -/* - * Stand-alone line macros. - */ - -static void -post_an_norm(POST_ARGS) -{ - struct roff_node *n; - struct mdoc_argv *argv; - size_t i; - - n = mdoc->last; - if (n->args == NULL) - return; - - for (i = 1; i < n->args->argc; i++) { - argv = n->args->argv + i; - mandoc_vmsg(MANDOCERR_AN_REP, - mdoc->parse, argv->line, argv->pos, - "An -%s", mdoc_argnames[argv->arg]); - } - - argv = n->args->argv; - if (argv->arg == MDOC_Split) - n->norm->An.auth = AUTH_split; - else if (argv->arg == MDOC_Nosplit) - n->norm->An.auth = AUTH_nosplit; - else - abort(); -} - -static void -post_eoln(POST_ARGS) -{ - struct roff_node *n; - - post_useless(mdoc); - n = mdoc->last; - if (n->child != NULL) - mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line, - n->pos, "%s %s", roff_name[n->tok], n->child->string); - - while (n->child != NULL) - roff_node_delete(mdoc, n->child); - - roff_word_alloc(mdoc, n->line, n->pos, n->tok == MDOC_Bt ? - "is currently in beta test." : "currently under development."); - mdoc->last->flags |= NODE_EOS | NODE_NOSRC; - mdoc->last = n; -} - -static int -build_list(struct roff_man *mdoc, int tok) -{ - struct roff_node *n; - int ic; - - n = mdoc->last->next; - for (ic = 1;; ic++) { - roff_elem_alloc(mdoc, n->line, n->pos, tok); - mdoc->last->flags |= NODE_NOSRC; - mdoc_node_relink(mdoc, n); - n = mdoc->last = mdoc->last->parent; - mdoc->next = ROFF_NEXT_SIBLING; - if (n->next == NULL) - return ic; - if (ic > 1 || n->next->next != NULL) { - roff_word_alloc(mdoc, n->line, n->pos, ","); - mdoc->last->flags |= NODE_DELIMC | NODE_NOSRC; - } - n = mdoc->last->next; - if (n->next == NULL) { - roff_word_alloc(mdoc, n->line, n->pos, "and"); - mdoc->last->flags |= NODE_NOSRC; - } - } -} - -static void -post_ex(POST_ARGS) -{ - struct roff_node *n; - int ic; - - post_std(mdoc); - - n = mdoc->last; - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, n->line, n->pos, "The"); - mdoc->last->flags |= NODE_NOSRC; - - if (mdoc->last->next != NULL) - ic = build_list(mdoc, MDOC_Nm); - else if (mdoc->meta.name != NULL) { - roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Nm); - mdoc->last->flags |= NODE_NOSRC; - roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); - mdoc->last->flags |= NODE_NOSRC; - mdoc->last = mdoc->last->parent; - mdoc->next = ROFF_NEXT_SIBLING; - ic = 1; - } else { - mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse, - n->line, n->pos, "Ex"); - ic = 0; - } - - roff_word_alloc(mdoc, n->line, n->pos, - ic > 1 ? "utilities exit\\~0" : "utility exits\\~0"); - mdoc->last->flags |= NODE_NOSRC; - roff_word_alloc(mdoc, n->line, n->pos, - "on success, and\\~>0 if an error occurs."); - mdoc->last->flags |= NODE_EOS | NODE_NOSRC; - mdoc->last = n; -} - -static void -post_lb(POST_ARGS) -{ - struct roff_node *n; - const char *p; - - post_delim_nb(mdoc); - - n = mdoc->last; - assert(n->child->type == ROFFT_TEXT); - mdoc->next = ROFF_NEXT_CHILD; - - if ((p = mdoc_a2lib(n->child->string)) != NULL) { - n->child->flags |= NODE_NOPRT; - roff_word_alloc(mdoc, n->line, n->pos, p); - mdoc->last->flags = NODE_NOSRC; - mdoc->last = n; - return; - } - - mandoc_vmsg(MANDOCERR_LB_BAD, mdoc->parse, n->child->line, - n->child->pos, "Lb %s", n->child->string); - - roff_word_alloc(mdoc, n->line, n->pos, "library"); - mdoc->last->flags = NODE_NOSRC; - roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq"); - mdoc->last->flags = NODE_DELIMO | NODE_NOSRC; - mdoc->last = mdoc->last->next; - roff_word_alloc(mdoc, n->line, n->pos, "\\(Rq"); - mdoc->last->flags = NODE_DELIMC | NODE_NOSRC; - mdoc->last = n; -} - -static void -post_rv(POST_ARGS) -{ - struct roff_node *n; - int ic; - - post_std(mdoc); - - n = mdoc->last; - mdoc->next = ROFF_NEXT_CHILD; - if (n->child != NULL) { - roff_word_alloc(mdoc, n->line, n->pos, "The"); - mdoc->last->flags |= NODE_NOSRC; - ic = build_list(mdoc, MDOC_Fn); - roff_word_alloc(mdoc, n->line, n->pos, - ic > 1 ? "functions return" : "function returns"); - mdoc->last->flags |= NODE_NOSRC; - roff_word_alloc(mdoc, n->line, n->pos, - "the value\\~0 if successful;"); - } else - roff_word_alloc(mdoc, n->line, n->pos, "Upon successful " - "completion, the value\\~0 is returned;"); - mdoc->last->flags |= NODE_NOSRC; - - roff_word_alloc(mdoc, n->line, n->pos, "otherwise " - "the value\\~\\-1 is returned and the global variable"); - mdoc->last->flags |= NODE_NOSRC; - roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Va); - mdoc->last->flags |= NODE_NOSRC; - roff_word_alloc(mdoc, n->line, n->pos, "errno"); - mdoc->last->flags |= NODE_NOSRC; - mdoc->last = mdoc->last->parent; - mdoc->next = ROFF_NEXT_SIBLING; - roff_word_alloc(mdoc, n->line, n->pos, - "is set to indicate the error."); - mdoc->last->flags |= NODE_EOS | NODE_NOSRC; - mdoc->last = n; -} - -static void -post_std(POST_ARGS) -{ - struct roff_node *n; - - post_delim(mdoc); - - n = mdoc->last; - if (n->args && n->args->argc == 1) - if (n->args->argv[0].arg == MDOC_Std) - return; - - mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); -} - -static void -post_st(POST_ARGS) -{ - struct roff_node *n, *nch; - const char *p; - - n = mdoc->last; - nch = n->child; - assert(nch->type == ROFFT_TEXT); - - if ((p = mdoc_a2st(nch->string)) == NULL) { - mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, - nch->line, nch->pos, "St %s", nch->string); - roff_node_delete(mdoc, n); - return; - } - - nch->flags |= NODE_NOPRT; - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, nch->line, nch->pos, p); - mdoc->last->flags |= NODE_NOSRC; - mdoc->last= n; -} - -static void -post_obsolete(POST_ARGS) -{ - struct roff_node *n; - - n = mdoc->last; - if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) - mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); -} - -static void -post_useless(POST_ARGS) -{ - struct roff_node *n; - - n = mdoc->last; - mandoc_msg(MANDOCERR_MACRO_USELESS, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); -} - -/* - * Block macros. - */ - -static void -post_bf(POST_ARGS) -{ - struct roff_node *np, *nch; - - /* - * Unlike other data pointers, these are "housed" by the HEAD - * element, which contains the goods. - */ - - np = mdoc->last; - if (np->type != ROFFT_HEAD) - return; - - assert(np->parent->type == ROFFT_BLOCK); - assert(np->parent->tok == MDOC_Bf); - - /* Check the number of arguments. */ - - nch = np->child; - if (np->parent->args == NULL) { - if (nch == NULL) { - mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse, - np->line, np->pos, "Bf"); - return; - } - nch = nch->next; - } - if (nch != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, - nch->line, nch->pos, "Bf ... %s", nch->string); - - /* Extract argument into data. */ - - if (np->parent->args != NULL) { - switch (np->parent->args->argv[0].arg) { - case MDOC_Emphasis: - np->norm->Bf.font = FONT_Em; - break; - case MDOC_Literal: - np->norm->Bf.font = FONT_Li; - break; - case MDOC_Symbolic: - np->norm->Bf.font = FONT_Sy; - break; - default: - abort(); - } - return; - } - - /* Extract parameter into data. */ - - if ( ! strcmp(np->child->string, "Em")) - np->norm->Bf.font = FONT_Em; - else if ( ! strcmp(np->child->string, "Li")) - np->norm->Bf.font = FONT_Li; - else if ( ! strcmp(np->child->string, "Sy")) - np->norm->Bf.font = FONT_Sy; - else - mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, - np->child->line, np->child->pos, - "Bf %s", np->child->string); -} - -static void -post_fname(POST_ARGS) -{ - const struct roff_node *n; - const char *cp; - size_t pos; - - n = mdoc->last->child; - pos = strcspn(n->string, "()"); - cp = n->string + pos; - if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) - mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, - n->line, n->pos + pos, n->string); -} - -static void -post_fn(POST_ARGS) -{ - - post_fname(mdoc); - post_fa(mdoc); -} - -static void -post_fo(POST_ARGS) -{ - const struct roff_node *n; - - n = mdoc->last; - - if (n->type != ROFFT_HEAD) - return; - - if (n->child == NULL) { - mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse, - n->line, n->pos, "Fo"); - return; - } - if (n->child != n->last) { - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, - n->child->next->line, n->child->next->pos, - "Fo ... %s", n->child->next->string); - while (n->child != n->last) - roff_node_delete(mdoc, n->last); - } else - post_delim(mdoc); - - post_fname(mdoc); -} - -static void -post_fa(POST_ARGS) -{ - const struct roff_node *n; - const char *cp; - - for (n = mdoc->last->child; n != NULL; n = n->next) { - for (cp = n->string; *cp != '\0'; cp++) { - /* Ignore callbacks and alterations. */ - if (*cp == '(' || *cp == '{') - break; - if (*cp != ',') - continue; - mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse, - n->line, n->pos + (cp - n->string), - n->string); - break; - } - } - post_delim_nb(mdoc); -} - -static void -post_nm(POST_ARGS) -{ - struct roff_node *n; - - n = mdoc->last; - - if (n->sec == SEC_NAME && n->child != NULL && - n->child->type == ROFFT_TEXT && mdoc->meta.msec != NULL) - mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1); - - if (n->last != NULL && - (n->last->tok == MDOC_Pp || - n->last->tok == MDOC_Lp)) - mdoc_node_relink(mdoc, n->last); - - if (mdoc->meta.name == NULL) - deroff(&mdoc->meta.name, n); - - if (mdoc->meta.name == NULL || - (mdoc->lastsec == SEC_NAME && n->child == NULL)) - mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, - n->line, n->pos, "Nm"); - - switch (n->type) { - case ROFFT_ELEM: - post_delim_nb(mdoc); - break; - case ROFFT_HEAD: - post_delim(mdoc); - break; - default: - return; - } - - if ((n->child != NULL && n->child->type == ROFFT_TEXT) || - mdoc->meta.name == NULL) - return; - - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); - mdoc->last->flags |= NODE_NOSRC; - mdoc->last = n; -} - -static void -post_nd(POST_ARGS) -{ - struct roff_node *n; - - n = mdoc->last; - - if (n->type != ROFFT_BODY) - return; - - if (n->sec != SEC_NAME) - mandoc_msg(MANDOCERR_ND_LATE, mdoc->parse, - n->line, n->pos, "Nd"); - - if (n->child == NULL) - mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, - n->line, n->pos, "Nd"); - else - post_delim(mdoc); - - post_hyph(mdoc); -} - -static void -post_display(POST_ARGS) -{ - struct roff_node *n, *np; - - n = mdoc->last; - switch (n->type) { - case ROFFT_BODY: - if (n->end != ENDBODY_NOT) { - if (n->tok == MDOC_Bd && - n->body->parent->args == NULL) - roff_node_delete(mdoc, n); - } else if (n->child == NULL) - mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); - else if (n->tok == MDOC_D1) - post_hyph(mdoc); - break; - case ROFFT_BLOCK: - if (n->tok == MDOC_Bd) { - if (n->args == NULL) { - mandoc_msg(MANDOCERR_BD_NOARG, - mdoc->parse, n->line, n->pos, "Bd"); - mdoc->next = ROFF_NEXT_SIBLING; - while (n->body->child != NULL) - mdoc_node_relink(mdoc, - n->body->child); - roff_node_delete(mdoc, n); - break; - } - post_bd(mdoc); - post_prevpar(mdoc); - } - for (np = n->parent; np != NULL; np = np->parent) { - if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) { - mandoc_vmsg(MANDOCERR_BD_NEST, - mdoc->parse, n->line, n->pos, - "%s in Bd", roff_name[n->tok]); - break; - } - } - break; - default: - break; - } -} - -static void -post_defaults(POST_ARGS) -{ - struct roff_node *nn; - - if (mdoc->last->child != NULL) { - post_delim_nb(mdoc); - return; - } - - /* - * The `Ar' defaults to "file ..." if no value is provided as an - * argument; the `Mt' and `Pa' macros use "~"; the `Li' just - * gets an empty string. - */ - - nn = mdoc->last; - switch (nn->tok) { - case MDOC_Ar: - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, nn->line, nn->pos, "file"); - mdoc->last->flags |= NODE_NOSRC; - roff_word_alloc(mdoc, nn->line, nn->pos, "..."); - mdoc->last->flags |= NODE_NOSRC; - break; - case MDOC_Pa: - case MDOC_Mt: - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, nn->line, nn->pos, "~"); - mdoc->last->flags |= NODE_NOSRC; - break; - default: - abort(); - } - mdoc->last = nn; -} - -static void -post_at(POST_ARGS) -{ - struct roff_node *n, *nch; - const char *att; - - n = mdoc->last; - nch = n->child; - - /* - * If we have a child, look it up in the standard keys. If a - * key exist, use that instead of the child; if it doesn't, - * prefix "AT&T UNIX " to the existing data. - */ - - att = NULL; - if (nch != NULL && ((att = mdoc_a2att(nch->string)) == NULL)) - mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, - nch->line, nch->pos, "At %s", nch->string); - - mdoc->next = ROFF_NEXT_CHILD; - if (att != NULL) { - roff_word_alloc(mdoc, nch->line, nch->pos, att); - nch->flags |= NODE_NOPRT; - } else - roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); - mdoc->last->flags |= NODE_NOSRC; - mdoc->last = n; -} - -static void -post_an(POST_ARGS) -{ - struct roff_node *np, *nch; - - post_an_norm(mdoc); - - np = mdoc->last; - nch = np->child; - if (np->norm->An.auth == AUTH__NONE) { - if (nch == NULL) - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - np->line, np->pos, "An"); - else - post_delim_nb(mdoc); - } else if (nch != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, - nch->line, nch->pos, "An ... %s", nch->string); -} - -static void -post_en(POST_ARGS) -{ - - post_obsolete(mdoc); - if (mdoc->last->type == ROFFT_BLOCK) - mdoc->last->norm->Es = mdoc->last_es; -} - -static void -post_es(POST_ARGS) -{ - - post_obsolete(mdoc); - mdoc->last_es = mdoc->last; -} - -static void -post_xx(POST_ARGS) -{ - struct roff_node *n; - const char *os; - char *v; - - post_delim_nb(mdoc); - - n = mdoc->last; - switch (n->tok) { - case MDOC_Bsx: - os = "BSD/OS"; - break; - case MDOC_Dx: - os = "DragonFly"; - break; - case MDOC_Fx: - os = "FreeBSD"; - break; - case MDOC_Nx: - os = "NetBSD"; - if (n->child == NULL) - break; - v = n->child->string; - if ((v[0] != '0' && v[0] != '1') || v[1] != '.' || - v[2] < '0' || v[2] > '9' || - v[3] < 'a' || v[3] > 'z' || v[4] != '\0') - break; - n->child->flags |= NODE_NOPRT; - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, n->child->line, n->child->pos, v); - v = mdoc->last->string; - v[3] = toupper((unsigned char)v[3]); - mdoc->last->flags |= NODE_NOSRC; - mdoc->last = n; - break; - case MDOC_Ox: - os = "OpenBSD"; - break; - case MDOC_Ux: - os = "UNIX"; - break; - default: - abort(); - } - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, n->line, n->pos, os); - mdoc->last->flags |= NODE_NOSRC; - mdoc->last = n; -} - -static void -post_it(POST_ARGS) -{ - struct roff_node *nbl, *nit, *nch; - int i, cols; - enum mdoc_list lt; - - post_prevpar(mdoc); - - nit = mdoc->last; - if (nit->type != ROFFT_BLOCK) - return; - - nbl = nit->parent->parent; - lt = nbl->norm->Bl.type; - - switch (lt) { - case LIST_tag: - case LIST_hang: - case LIST_ohang: - case LIST_inset: - case LIST_diag: - if (nit->head->child == NULL) - mandoc_vmsg(MANDOCERR_IT_NOHEAD, - mdoc->parse, nit->line, nit->pos, - "Bl -%s It", - mdoc_argnames[nbl->args->argv[0].arg]); - break; - case LIST_bullet: - case LIST_dash: - case LIST_enum: - case LIST_hyphen: - if (nit->body == NULL || nit->body->child == NULL) - mandoc_vmsg(MANDOCERR_IT_NOBODY, - mdoc->parse, nit->line, nit->pos, - "Bl -%s It", - mdoc_argnames[nbl->args->argv[0].arg]); - /* FALLTHROUGH */ - case LIST_item: - if ((nch = nit->head->child) != NULL) - mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, - nit->line, nit->pos, "It %s", - nch->string == NULL ? roff_name[nch->tok] : - nch->string); - break; - case LIST_column: - cols = (int)nbl->norm->Bl.ncols; - - assert(nit->head->child == NULL); - - if (nit->head->next->child == NULL && - nit->head->next->next == NULL) { - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - nit->line, nit->pos, "It"); - roff_node_delete(mdoc, nit); - break; - } - - i = 0; - for (nch = nit->child; nch != NULL; nch = nch->next) { - if (nch->type != ROFFT_BODY) - continue; - if (i++ && nch->flags & NODE_LINE) - mandoc_msg(MANDOCERR_TA_LINE, mdoc->parse, - nch->line, nch->pos, "Ta"); - } - if (i < cols || i > cols + 1) - mandoc_vmsg(MANDOCERR_BL_COL, - mdoc->parse, nit->line, nit->pos, - "%d columns, %d cells", cols, i); - else if (nit->head->next->child != NULL && - nit->head->next->child->line > nit->line) - mandoc_msg(MANDOCERR_IT_NOARG, mdoc->parse, - nit->line, nit->pos, "Bl -column It"); - break; - default: - abort(); - } -} - -static void -post_bl_block(POST_ARGS) -{ - struct roff_node *n, *ni, *nc; - - post_prevpar(mdoc); - - n = mdoc->last; - for (ni = n->body->child; ni != NULL; ni = ni->next) { - if (ni->body == NULL) - continue; - nc = ni->body->last; - while (nc != NULL) { - switch (nc->tok) { - case MDOC_Pp: - case MDOC_Lp: - case ROFF_br: - break; - default: - nc = NULL; - continue; - } - if (ni->next == NULL) { - mandoc_msg(MANDOCERR_PAR_MOVE, - mdoc->parse, nc->line, nc->pos, - roff_name[nc->tok]); - mdoc_node_relink(mdoc, nc); - } else if (n->norm->Bl.comp == 0 && - n->norm->Bl.type != LIST_column) { - mandoc_vmsg(MANDOCERR_PAR_SKIP, - mdoc->parse, nc->line, nc->pos, - "%s before It", roff_name[nc->tok]); - roff_node_delete(mdoc, nc); - } else - break; - nc = ni->body->last; - } - } -} - -/* - * If the argument of -offset or -width is a macro, - * replace it with the associated default width. - */ -static void -rewrite_macro2len(struct roff_man *mdoc, char **arg) -{ - size_t width; - enum roff_tok tok; - - if (*arg == NULL) - return; - else if ( ! strcmp(*arg, "Ds")) - width = 6; - else if ((tok = roffhash_find(mdoc->mdocmac, *arg, 0)) == TOKEN_NONE) - return; - else - width = macro2len(tok); - - free(*arg); - mandoc_asprintf(arg, "%zun", width); -} - -static void -post_bl_head(POST_ARGS) -{ - struct roff_node *nbl, *nh, *nch, *nnext; - struct mdoc_argv *argv; - int i, j; - - post_bl_norm(mdoc); - - nh = mdoc->last; - if (nh->norm->Bl.type != LIST_column) { - if ((nch = nh->child) == NULL) - return; - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, - nch->line, nch->pos, "Bl ... %s", nch->string); - while (nch != NULL) { - roff_node_delete(mdoc, nch); - nch = nh->child; - } - return; - } - - /* - * Append old-style lists, where the column width specifiers - * trail as macro parameters, to the new-style ("normal-form") - * lists where they're argument values following -column. - */ - - if (nh->child == NULL) - return; - - nbl = nh->parent; - for (j = 0; j < (int)nbl->args->argc; j++) - if (nbl->args->argv[j].arg == MDOC_Column) - break; - - assert(j < (int)nbl->args->argc); - - /* - * Accommodate for new-style groff column syntax. Shuffle the - * child nodes, all of which must be TEXT, as arguments for the - * column field. Then, delete the head children. - */ - - argv = nbl->args->argv + j; - i = argv->sz; - for (nch = nh->child; nch != NULL; nch = nch->next) - argv->sz++; - argv->value = mandoc_reallocarray(argv->value, - argv->sz, sizeof(char *)); - - nh->norm->Bl.ncols = argv->sz; - nh->norm->Bl.cols = (void *)argv->value; - - for (nch = nh->child; nch != NULL; nch = nnext) { - argv->value[i++] = nch->string; - nch->string = NULL; - nnext = nch->next; - roff_node_delete(NULL, nch); - } - nh->child = NULL; -} - -static void -post_bl(POST_ARGS) -{ - struct roff_node *nparent, *nprev; /* of the Bl block */ - struct roff_node *nblock, *nbody; /* of the Bl */ - struct roff_node *nchild, *nnext; /* of the Bl body */ - const char *prev_Er; - int order; - - nbody = mdoc->last; - switch (nbody->type) { - case ROFFT_BLOCK: - post_bl_block(mdoc); - return; - case ROFFT_HEAD: - post_bl_head(mdoc); - return; - case ROFFT_BODY: - break; - default: - return; - } - if (nbody->end != ENDBODY_NOT) - return; - - nchild = nbody->child; - if (nchild == NULL) { - mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, - nbody->line, nbody->pos, "Bl"); - return; - } - while (nchild != NULL) { - nnext = nchild->next; - if (nchild->tok == MDOC_It || - (nchild->tok == MDOC_Sm && - nnext != NULL && nnext->tok == MDOC_It)) { - nchild = nnext; - continue; - } - - /* - * In .Bl -column, the first rows may be implicit, - * that is, they may not start with .It macros. - * Such rows may be followed by nodes generated on the - * roff level, for example .TS, which cannot be moved - * out of the list. In that case, wrap such roff nodes - * into an implicit row. - */ - - if (nchild->prev != NULL) { - mdoc->last = nchild; - mdoc->next = ROFF_NEXT_SIBLING; - roff_block_alloc(mdoc, nchild->line, - nchild->pos, MDOC_It); - roff_head_alloc(mdoc, nchild->line, - nchild->pos, MDOC_It); - mdoc->next = ROFF_NEXT_SIBLING; - roff_body_alloc(mdoc, nchild->line, - nchild->pos, MDOC_It); - while (nchild->tok != MDOC_It) { - mdoc_node_relink(mdoc, nchild); - if ((nchild = nnext) == NULL) - break; - nnext = nchild->next; - mdoc->next = ROFF_NEXT_SIBLING; - } - mdoc->last = nbody; - continue; - } - - mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, - nchild->line, nchild->pos, roff_name[nchild->tok]); - - /* - * Move the node out of the Bl block. - * First, collect all required node pointers. - */ - - nblock = nbody->parent; - nprev = nblock->prev; - nparent = nblock->parent; - - /* - * Unlink this child. - */ - - nbody->child = nnext; - if (nnext == NULL) - nbody->last = NULL; - else - nnext->prev = NULL; - - /* - * Relink this child. - */ - - nchild->parent = nparent; - nchild->prev = nprev; - nchild->next = nblock; - - nblock->prev = nchild; - if (nprev == NULL) - nparent->child = nchild; - else - nprev->next = nchild; - - nchild = nnext; - } - - if (mdoc->meta.os_e != MANDOC_OS_NETBSD) - return; - - prev_Er = NULL; - for (nchild = nbody->child; nchild != NULL; nchild = nchild->next) { - if (nchild->tok != MDOC_It) - continue; - if ((nnext = nchild->head->child) == NULL) - continue; - if (nnext->type == ROFFT_BLOCK) - nnext = nnext->body->child; - if (nnext == NULL || nnext->tok != MDOC_Er) - continue; - nnext = nnext->child; - if (prev_Er != NULL) { - order = strcmp(prev_Er, nnext->string); - if (order > 0) - mandoc_vmsg(MANDOCERR_ER_ORDER, - mdoc->parse, nnext->line, nnext->pos, - "Er %s %s (NetBSD)", - prev_Er, nnext->string); - else if (order == 0) - mandoc_vmsg(MANDOCERR_ER_REP, - mdoc->parse, nnext->line, nnext->pos, - "Er %s (NetBSD)", prev_Er); - } - prev_Er = nnext->string; - } -} - -static void -post_bk(POST_ARGS) -{ - struct roff_node *n; - - n = mdoc->last; - - if (n->type == ROFFT_BLOCK && n->body->child == NULL) { - mandoc_msg(MANDOCERR_BLK_EMPTY, - mdoc->parse, n->line, n->pos, "Bk"); - roff_node_delete(mdoc, n); - } -} - -static void -post_sm(POST_ARGS) -{ - struct roff_node *nch; - - nch = mdoc->last->child; - - if (nch == NULL) { - mdoc->flags ^= MDOC_SMOFF; - return; - } - - assert(nch->type == ROFFT_TEXT); - - if ( ! strcmp(nch->string, "on")) { - mdoc->flags &= ~MDOC_SMOFF; - return; - } - if ( ! strcmp(nch->string, "off")) { - mdoc->flags |= MDOC_SMOFF; - return; - } - - mandoc_vmsg(MANDOCERR_SM_BAD, - mdoc->parse, nch->line, nch->pos, - "%s %s", roff_name[mdoc->last->tok], nch->string); - mdoc_node_relink(mdoc, nch); - return; -} - -static void -post_root(POST_ARGS) -{ - const char *openbsd_arch[] = { - "alpha", "amd64", "arm64", "armv7", "hppa", "i386", - "landisk", "loongson", "luna88k", "macppc", "mips64", - "octeon", "sgi", "socppc", "sparc64", NULL - }; - const char *netbsd_arch[] = { - "acorn26", "acorn32", "algor", "alpha", "amiga", - "arc", "atari", - "bebox", "cats", "cesfic", "cobalt", "dreamcast", - "emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5", - "hp300", "hpcarm", "hpcmips", "hpcsh", "hppa", - "i386", "ibmnws", "luna68k", - "mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc", - "netwinder", "news68k", "newsmips", "next68k", - "pc532", "playstation2", "pmax", "pmppc", "prep", - "sandpoint", "sbmips", "sgimips", "shark", - "sparc", "sparc64", "sun2", "sun3", - "vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL - }; - const char **arches[] = { NULL, netbsd_arch, openbsd_arch }; - - struct roff_node *n; - const char **arch; - - /* Add missing prologue data. */ - - if (mdoc->meta.date == NULL) - mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : - mandoc_normdate(mdoc, NULL, 0, 0); - - if (mdoc->meta.title == NULL) { - mandoc_msg(MANDOCERR_DT_NOTITLE, - mdoc->parse, 0, 0, "EOF"); - mdoc->meta.title = mandoc_strdup("UNTITLED"); - } - - if (mdoc->meta.vol == NULL) - mdoc->meta.vol = mandoc_strdup("LOCAL"); - - if (mdoc->meta.os == NULL) { - mandoc_msg(MANDOCERR_OS_MISSING, - mdoc->parse, 0, 0, NULL); - mdoc->meta.os = mandoc_strdup(""); - } else if (mdoc->meta.os_e && - (mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0) - mandoc_msg(MANDOCERR_RCS_MISSING, mdoc->parse, 0, 0, - mdoc->meta.os_e == MANDOC_OS_OPENBSD ? - "(OpenBSD)" : "(NetBSD)"); - - if (mdoc->meta.arch != NULL && - (arch = arches[mdoc->meta.os_e]) != NULL) { - while (*arch != NULL && strcmp(*arch, mdoc->meta.arch)) - arch++; - if (*arch == NULL) { - n = mdoc->first->child; - while (n->tok != MDOC_Dt) - n = n->next; - n = n->child->next->next; - mandoc_vmsg(MANDOCERR_ARCH_BAD, - mdoc->parse, n->line, n->pos, - "Dt ... %s %s", mdoc->meta.arch, - mdoc->meta.os_e == MANDOC_OS_OPENBSD ? - "(OpenBSD)" : "(NetBSD)"); - } - } - - /* Check that we begin with a proper `Sh'. */ - - n = mdoc->first->child; - while (n != NULL && n->tok >= MDOC_Dd && - mdoc_macros[n->tok].flags & MDOC_PROLOGUE) - n = n->next; - - if (n == NULL) - mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); - else if (n->tok != MDOC_Sh) - mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); -} - -static void -post_rs(POST_ARGS) -{ - struct roff_node *np, *nch, *next, *prev; - int i, j; - - np = mdoc->last; - - if (np->type != ROFFT_BODY) - return; - - if (np->child == NULL) { - mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse, - np->line, np->pos, "Rs"); - return; - } - - /* - * The full `Rs' block needs special handling to order the - * sub-elements according to `rsord'. Pick through each element - * and correctly order it. This is an insertion sort. - */ - - next = NULL; - for (nch = np->child->next; nch != NULL; nch = next) { - /* Determine order number of this child. */ - for (i = 0; i < RSORD_MAX; i++) - if (rsord[i] == nch->tok) - break; - - if (i == RSORD_MAX) { - mandoc_msg(MANDOCERR_RS_BAD, mdoc->parse, - nch->line, nch->pos, roff_name[nch->tok]); - i = -1; - } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) - np->norm->Rs.quote_T++; - - /* - * Remove this child from the chain. This somewhat - * repeats roff_node_unlink(), but since we're - * just re-ordering, there's no need for the - * full unlink process. - */ - - if ((next = nch->next) != NULL) - next->prev = nch->prev; - - if ((prev = nch->prev) != NULL) - prev->next = nch->next; - - nch->prev = nch->next = NULL; - - /* - * Scan back until we reach a node that's - * to be ordered before this child. - */ - - for ( ; prev ; prev = prev->prev) { - /* Determine order of `prev'. */ - for (j = 0; j < RSORD_MAX; j++) - if (rsord[j] == prev->tok) - break; - if (j == RSORD_MAX) - j = -1; - - if (j <= i) - break; - } - - /* - * Set this child back into its correct place - * in front of the `prev' node. - */ - - nch->prev = prev; - - if (prev == NULL) { - np->child->prev = nch; - nch->next = np->child; - np->child = nch; - } else { - if (prev->next) - prev->next->prev = nch; - nch->next = prev->next; - prev->next = nch; - } - } -} - -/* - * For some arguments of some macros, - * convert all breakable hyphens into ASCII_HYPH. - */ -static void -post_hyph(POST_ARGS) -{ - struct roff_node *nch; - char *cp; - - for (nch = mdoc->last->child; nch != NULL; nch = nch->next) { - if (nch->type != ROFFT_TEXT) - continue; - cp = nch->string; - if (*cp == '\0') - continue; - while (*(++cp) != '\0') - if (*cp == '-' && - isalpha((unsigned char)cp[-1]) && - isalpha((unsigned char)cp[1])) - *cp = ASCII_HYPH; - } -} - -static void -post_ns(POST_ARGS) -{ - struct roff_node *n; - - n = mdoc->last; - if (n->flags & NODE_LINE || - (n->next != NULL && n->next->flags & NODE_DELIMC)) - mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, - n->line, n->pos, NULL); -} - -static void -post_sx(POST_ARGS) -{ - post_delim(mdoc); - post_hyph(mdoc); -} - -static void -post_sh(POST_ARGS) -{ - - post_ignpar(mdoc); - - switch (mdoc->last->type) { - case ROFFT_HEAD: - post_sh_head(mdoc); - break; - case ROFFT_BODY: - switch (mdoc->lastsec) { - case SEC_NAME: - post_sh_name(mdoc); - break; - case SEC_SEE_ALSO: - post_sh_see_also(mdoc); - break; - case SEC_AUTHORS: - post_sh_authors(mdoc); - break; - default: - break; - } - break; - default: - break; - } -} - -static void -post_sh_name(POST_ARGS) -{ - struct roff_node *n; - int hasnm, hasnd; - - hasnm = hasnd = 0; - - for (n = mdoc->last->child; n != NULL; n = n->next) { - switch (n->tok) { - case MDOC_Nm: - if (hasnm && n->child != NULL) - mandoc_vmsg(MANDOCERR_NAMESEC_PUNCT, - mdoc->parse, n->line, n->pos, - "Nm %s", n->child->string); - hasnm = 1; - continue; - case MDOC_Nd: - hasnd = 1; - if (n->next != NULL) - mandoc_msg(MANDOCERR_NAMESEC_ND, - mdoc->parse, n->line, n->pos, NULL); - break; - case TOKEN_NONE: - if (n->type == ROFFT_TEXT && - n->string[0] == ',' && n->string[1] == '\0' && - n->next != NULL && n->next->tok == MDOC_Nm) { - n = n->next; - continue; - } - /* FALLTHROUGH */ - default: - mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, - n->line, n->pos, roff_name[n->tok]); - continue; - } - break; - } - - if ( ! hasnm) - mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse, - mdoc->last->line, mdoc->last->pos, NULL); - if ( ! hasnd) - mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse, - mdoc->last->line, mdoc->last->pos, NULL); -} - -static void -post_sh_see_also(POST_ARGS) -{ - const struct roff_node *n; - const char *name, *sec; - const char *lastname, *lastsec, *lastpunct; - int cmp; - - n = mdoc->last->child; - lastname = lastsec = lastpunct = NULL; - while (n != NULL) { - if (n->tok != MDOC_Xr || - n->child == NULL || - n->child->next == NULL) - break; - - /* Process one .Xr node. */ - - name = n->child->string; - sec = n->child->next->string; - if (lastsec != NULL) { - if (lastpunct[0] != ',' || lastpunct[1] != '\0') - mandoc_vmsg(MANDOCERR_XR_PUNCT, - mdoc->parse, n->line, n->pos, - "%s before %s(%s)", lastpunct, - name, sec); - cmp = strcmp(lastsec, sec); - if (cmp > 0) - mandoc_vmsg(MANDOCERR_XR_ORDER, - mdoc->parse, n->line, n->pos, - "%s(%s) after %s(%s)", name, - sec, lastname, lastsec); - else if (cmp == 0 && - strcasecmp(lastname, name) > 0) - mandoc_vmsg(MANDOCERR_XR_ORDER, - mdoc->parse, n->line, n->pos, - "%s after %s", name, lastname); - } - lastname = name; - lastsec = sec; - - /* Process the following node. */ - - n = n->next; - if (n == NULL) - break; - if (n->tok == MDOC_Xr) { - lastpunct = "none"; - continue; - } - if (n->type != ROFFT_TEXT) - break; - for (name = n->string; *name != '\0'; name++) - if (isalpha((const unsigned char)*name)) - return; - lastpunct = n->string; - if (n->next == NULL || n->next->tok == MDOC_Rs) - mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, - n->line, n->pos, "%s after %s(%s)", - lastpunct, lastname, lastsec); - n = n->next; - } -} - -static int -child_an(const struct roff_node *n) -{ - - for (n = n->child; n != NULL; n = n->next) - if ((n->tok == MDOC_An && n->child != NULL) || child_an(n)) - return 1; - return 0; -} - -static void -post_sh_authors(POST_ARGS) -{ - - if ( ! child_an(mdoc->last)) - mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse, - mdoc->last->line, mdoc->last->pos, NULL); -} - -/* - * Return an upper bound for the string distance (allowing - * transpositions). Not a full Levenshtein implementation - * because Levenshtein is quadratic in the string length - * and this function is called for every standard name, - * so the check for each custom name would be cubic. - * The following crude heuristics is linear, resulting - * in quadratic behaviour for checking one custom name, - * which does not cause measurable slowdown. - */ -static int -similar(const char *s1, const char *s2) -{ - const int maxdist = 3; - int dist = 0; - - while (s1[0] != '\0' && s2[0] != '\0') { - if (s1[0] == s2[0]) { - s1++; - s2++; - continue; - } - if (++dist > maxdist) - return INT_MAX; - if (s1[1] == s2[1]) { /* replacement */ - s1++; - s2++; - } else if (s1[0] == s2[1] && s1[1] == s2[0]) { - s1 += 2; /* transposition */ - s2 += 2; - } else if (s1[0] == s2[1]) /* insertion */ - s2++; - else if (s1[1] == s2[0]) /* deletion */ - s1++; - else - return INT_MAX; - } - dist += strlen(s1) + strlen(s2); - return dist > maxdist ? INT_MAX : dist; -} - -static void -post_sh_head(POST_ARGS) -{ - struct roff_node *nch; - const char *goodsec; - const char *const *testsec; - int dist, mindist; - enum roff_sec sec; - - /* - * Process a new section. Sections are either "named" or - * "custom". Custom sections are user-defined, while named ones - * follow a conventional order and may only appear in certain - * manual sections. - */ - - sec = mdoc->last->sec; - - /* The NAME should be first. */ - - if (sec != SEC_NAME && mdoc->lastnamed == SEC_NONE) - mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, - mdoc->last->line, mdoc->last->pos, "Sh %s", - sec != SEC_CUSTOM ? secnames[sec] : - (nch = mdoc->last->child) == NULL ? "" : - nch->type == ROFFT_TEXT ? nch->string : - roff_name[nch->tok]); - - /* The SYNOPSIS gets special attention in other areas. */ - - if (sec == SEC_SYNOPSIS) { - roff_setreg(mdoc->roff, "nS", 1, '='); - mdoc->flags |= MDOC_SYNOPSIS; - } else { - roff_setreg(mdoc->roff, "nS", 0, '='); - mdoc->flags &= ~MDOC_SYNOPSIS; - } - - /* Mark our last section. */ - - mdoc->lastsec = sec; - - /* We don't care about custom sections after this. */ - - if (sec == SEC_CUSTOM) { - if ((nch = mdoc->last->child) == NULL || - nch->type != ROFFT_TEXT || nch->next != NULL) - return; - goodsec = NULL; - mindist = INT_MAX; - for (testsec = secnames + 1; *testsec != NULL; testsec++) { - dist = similar(nch->string, *testsec); - if (dist < mindist) { - goodsec = *testsec; - mindist = dist; - } - } - if (goodsec != NULL) - mandoc_vmsg(MANDOCERR_SEC_TYPO, mdoc->parse, - nch->line, nch->pos, "Sh %s instead of %s", - nch->string, goodsec); - return; - } - - /* - * Check whether our non-custom section is being repeated or is - * out of order. - */ - - if (sec == mdoc->lastnamed) - mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse, - mdoc->last->line, mdoc->last->pos, - "Sh %s", secnames[sec]); - - if (sec < mdoc->lastnamed) - mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse, - mdoc->last->line, mdoc->last->pos, - "Sh %s", secnames[sec]); - - /* Mark the last named section. */ - - mdoc->lastnamed = sec; - - /* Check particular section/manual conventions. */ - - if (mdoc->meta.msec == NULL) - return; - - goodsec = NULL; - switch (sec) { - case SEC_ERRORS: - if (*mdoc->meta.msec == '4') - break; - goodsec = "2, 3, 4, 9"; - /* FALLTHROUGH */ - case SEC_RETURN_VALUES: - case SEC_LIBRARY: - if (*mdoc->meta.msec == '2') - break; - if (*mdoc->meta.msec == '3') - break; - if (NULL == goodsec) - goodsec = "2, 3, 9"; - /* FALLTHROUGH */ - case SEC_CONTEXT: - if (*mdoc->meta.msec == '9') - break; - if (NULL == goodsec) - goodsec = "9"; - mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, - mdoc->last->line, mdoc->last->pos, - "Sh %s for %s only", secnames[sec], goodsec); - break; - default: - break; - } -} - -static void -post_xr(POST_ARGS) -{ - struct roff_node *n, *nch; - - n = mdoc->last; - nch = n->child; - if (nch->next == NULL) { - mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, - n->line, n->pos, "Xr %s", nch->string); - } else { - assert(nch->next == n->last); - if(mandoc_xr_add(nch->next->string, nch->string, - nch->line, nch->pos)) - mandoc_vmsg(MANDOCERR_XR_SELF, mdoc->parse, - nch->line, nch->pos, "Xr %s %s", - nch->string, nch->next->string); - } - post_delim_nb(mdoc); -} - -static void -post_ignpar(POST_ARGS) -{ - struct roff_node *np; - - switch (mdoc->last->type) { - case ROFFT_BLOCK: - post_prevpar(mdoc); - return; - case ROFFT_HEAD: - post_delim(mdoc); - post_hyph(mdoc); - return; - case ROFFT_BODY: - break; - default: - return; - } - - if ((np = mdoc->last->child) != NULL) - if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { - mandoc_vmsg(MANDOCERR_PAR_SKIP, - mdoc->parse, np->line, np->pos, - "%s after %s", roff_name[np->tok], - roff_name[mdoc->last->tok]); - roff_node_delete(mdoc, np); - } - - if ((np = mdoc->last->last) != NULL) - if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { - mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, - np->line, np->pos, "%s at the end of %s", - roff_name[np->tok], - roff_name[mdoc->last->tok]); - roff_node_delete(mdoc, np); - } -} - -static void -post_prevpar(POST_ARGS) -{ - struct roff_node *n; - - n = mdoc->last; - if (NULL == n->prev) - return; - if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) - return; - - /* - * Don't allow prior `Lp' or `Pp' prior to a paragraph-type - * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. - */ - - if (n->prev->tok != MDOC_Pp && - n->prev->tok != MDOC_Lp && - n->prev->tok != ROFF_br) - return; - if (n->tok == MDOC_Bl && n->norm->Bl.comp) - return; - if (n->tok == MDOC_Bd && n->norm->Bd.comp) - return; - if (n->tok == MDOC_It && n->parent->norm->Bl.comp) - return; - - mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, - n->prev->line, n->prev->pos, "%s before %s", - roff_name[n->prev->tok], roff_name[n->tok]); - roff_node_delete(mdoc, n->prev); -} - -static void -post_par(POST_ARGS) -{ - struct roff_node *np; - - np = mdoc->last; - if (np->tok != ROFF_br && np->tok != ROFF_sp) - post_prevpar(mdoc); - - if (np->tok == ROFF_sp) { - if (np->child != NULL && np->child->next != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, - np->child->next->line, np->child->next->pos, - "sp ... %s", np->child->next->string); - } else if (np->child != NULL) - mandoc_vmsg(MANDOCERR_ARG_SKIP, - mdoc->parse, np->line, np->pos, "%s %s", - roff_name[np->tok], np->child->string); - - if ((np = mdoc->last->prev) == NULL) { - np = mdoc->last->parent; - if (np->tok != MDOC_Sh && np->tok != MDOC_Ss) - return; - } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp && - (mdoc->last->tok != ROFF_br || - (np->tok != ROFF_sp && np->tok != ROFF_br))) - return; - - mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, - mdoc->last->line, mdoc->last->pos, "%s after %s", - roff_name[mdoc->last->tok], roff_name[np->tok]); - roff_node_delete(mdoc, mdoc->last); -} - -static void -post_dd(POST_ARGS) -{ - struct roff_node *n; - char *datestr; - - n = mdoc->last; - n->flags |= NODE_NOPRT; - - if (mdoc->meta.date != NULL) { - mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, - n->line, n->pos, "Dd"); - free(mdoc->meta.date); - } else if (mdoc->flags & MDOC_PBODY) - mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, - n->line, n->pos, "Dd"); - else if (mdoc->meta.title != NULL) - mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, - n->line, n->pos, "Dd after Dt"); - else if (mdoc->meta.os != NULL) - mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, - n->line, n->pos, "Dd after Os"); - - if (n->child == NULL || n->child->string[0] == '\0') { - mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : - mandoc_normdate(mdoc, NULL, n->line, n->pos); - return; - } - - datestr = NULL; - deroff(&datestr, n); - if (mdoc->quick) - mdoc->meta.date = datestr; - else { - mdoc->meta.date = mandoc_normdate(mdoc, - datestr, n->line, n->pos); - free(datestr); - } -} - -static void -post_dt(POST_ARGS) -{ - struct roff_node *nn, *n; - const char *cp; - char *p; - - n = mdoc->last; - n->flags |= NODE_NOPRT; - - if (mdoc->flags & MDOC_PBODY) { - mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse, - n->line, n->pos, "Dt"); - return; - } - - if (mdoc->meta.title != NULL) - mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, - n->line, n->pos, "Dt"); - else if (mdoc->meta.os != NULL) - mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, - n->line, n->pos, "Dt after Os"); - - free(mdoc->meta.title); - free(mdoc->meta.msec); - free(mdoc->meta.vol); - free(mdoc->meta.arch); - - mdoc->meta.title = NULL; - mdoc->meta.msec = NULL; - mdoc->meta.vol = NULL; - mdoc->meta.arch = NULL; - - /* Mandatory first argument: title. */ - - nn = n->child; - if (nn == NULL || *nn->string == '\0') { - mandoc_msg(MANDOCERR_DT_NOTITLE, - mdoc->parse, n->line, n->pos, "Dt"); - mdoc->meta.title = mandoc_strdup("UNTITLED"); - } else { - mdoc->meta.title = mandoc_strdup(nn->string); - - /* Check that all characters are uppercase. */ - - for (p = nn->string; *p != '\0'; p++) - if (islower((unsigned char)*p)) { - mandoc_vmsg(MANDOCERR_TITLE_CASE, - mdoc->parse, nn->line, - nn->pos + (p - nn->string), - "Dt %s", nn->string); - break; - } - } - - /* Mandatory second argument: section. */ - - if (nn != NULL) - nn = nn->next; - - if (nn == NULL) { - mandoc_vmsg(MANDOCERR_MSEC_MISSING, - mdoc->parse, n->line, n->pos, - "Dt %s", mdoc->meta.title); - mdoc->meta.vol = mandoc_strdup("LOCAL"); - return; /* msec and arch remain NULL. */ - } - - mdoc->meta.msec = mandoc_strdup(nn->string); - - /* Infer volume title from section number. */ - - cp = mandoc_a2msec(nn->string); - if (cp == NULL) { - mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, - nn->line, nn->pos, "Dt ... %s", nn->string); - mdoc->meta.vol = mandoc_strdup(nn->string); - } else - mdoc->meta.vol = mandoc_strdup(cp); - - /* Optional third argument: architecture. */ - - if ((nn = nn->next) == NULL) - return; - - for (p = nn->string; *p != '\0'; p++) - *p = tolower((unsigned char)*p); - mdoc->meta.arch = mandoc_strdup(nn->string); - - /* Ignore fourth and later arguments. */ - - if ((nn = nn->next) != NULL) - mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, - nn->line, nn->pos, "Dt ... %s", nn->string); -} - -static void -post_bx(POST_ARGS) -{ - struct roff_node *n, *nch; - const char *macro; - - post_delim_nb(mdoc); - - n = mdoc->last; - nch = n->child; - - if (nch != NULL) { - macro = !strcmp(nch->string, "Open") ? "Ox" : - !strcmp(nch->string, "Net") ? "Nx" : - !strcmp(nch->string, "Free") ? "Fx" : - !strcmp(nch->string, "DragonFly") ? "Dx" : NULL; - if (macro != NULL) - mandoc_msg(MANDOCERR_BX, mdoc->parse, - n->line, n->pos, macro); - mdoc->last = nch; - nch = nch->next; - mdoc->next = ROFF_NEXT_SIBLING; - roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); - mdoc->last->flags |= NODE_NOSRC; - mdoc->next = ROFF_NEXT_SIBLING; - } else - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, n->line, n->pos, "BSD"); - mdoc->last->flags |= NODE_NOSRC; - - if (nch == NULL) { - mdoc->last = n; - return; - } - - roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); - mdoc->last->flags |= NODE_NOSRC; - mdoc->next = ROFF_NEXT_SIBLING; - roff_word_alloc(mdoc, n->line, n->pos, "-"); - mdoc->last->flags |= NODE_NOSRC; - roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); - mdoc->last->flags |= NODE_NOSRC; - mdoc->last = n; - - /* - * Make `Bx's second argument always start with an uppercase - * letter. Groff checks if it's an "accepted" term, but we just - * uppercase blindly. - */ - - *nch->string = (char)toupper((unsigned char)*nch->string); -} - -static void -post_os(POST_ARGS) -{ -#ifndef OSNAME - struct utsname utsname; - static char *defbuf; -#endif - struct roff_node *n; - - n = mdoc->last; - n->flags |= NODE_NOPRT; - - if (mdoc->meta.os != NULL) - mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, - n->line, n->pos, "Os"); - else if (mdoc->flags & MDOC_PBODY) - mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, - n->line, n->pos, "Os"); - - post_delim(mdoc); - - /* - * Set the operating system by way of the `Os' macro. - * The order of precedence is: - * 1. the argument of the `Os' macro, unless empty - * 2. the -Ios=foo command line argument, if provided - * 3. -DOSNAME="\"foo\"", if provided during compilation - * 4. "sysname release" from uname(3) - */ - - free(mdoc->meta.os); - mdoc->meta.os = NULL; - deroff(&mdoc->meta.os, n); - if (mdoc->meta.os) - goto out; - - if (mdoc->os_s != NULL) { - mdoc->meta.os = mandoc_strdup(mdoc->os_s); - goto out; - } - -#ifdef OSNAME - mdoc->meta.os = mandoc_strdup(OSNAME); -#else /*!OSNAME */ - if (defbuf == NULL) { - if (uname(&utsname) == -1) { - mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, - n->line, n->pos, "Os"); - defbuf = mandoc_strdup("UNKNOWN"); - } else - mandoc_asprintf(&defbuf, "%s %s", - utsname.sysname, utsname.release); - } - mdoc->meta.os = mandoc_strdup(defbuf); -#endif /*!OSNAME*/ - -out: - if (mdoc->meta.os_e == MANDOC_OS_OTHER) { - if (strstr(mdoc->meta.os, "OpenBSD") != NULL) - mdoc->meta.os_e = MANDOC_OS_OPENBSD; - else if (strstr(mdoc->meta.os, "NetBSD") != NULL) - mdoc->meta.os_e = MANDOC_OS_NETBSD; - } - - /* - * This is the earliest point where we can check - * Mdocdate conventions because we don't know - * the operating system earlier. - */ - - if (n->child != NULL) - mandoc_vmsg(MANDOCERR_OS_ARG, mdoc->parse, - n->child->line, n->child->pos, - "Os %s (%s)", n->child->string, - mdoc->meta.os_e == MANDOC_OS_OPENBSD ? - "OpenBSD" : "NetBSD"); - - while (n->tok != MDOC_Dd) - if ((n = n->prev) == NULL) - return; - if ((n = n->child) == NULL) - return; - if (strncmp(n->string, "$" "Mdocdate", 9)) { - if (mdoc->meta.os_e == MANDOC_OS_OPENBSD) - mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING, - mdoc->parse, n->line, n->pos, - "Dd %s (OpenBSD)", n->string); - } else { - if (mdoc->meta.os_e == MANDOC_OS_NETBSD) - mandoc_vmsg(MANDOCERR_MDOCDATE, - mdoc->parse, n->line, n->pos, - "Dd %s (NetBSD)", n->string); - } -} - -enum roff_sec -mdoc_a2sec(const char *p) -{ - int i; - - for (i = 0; i < (int)SEC__MAX; i++) - if (secnames[i] && 0 == strcmp(p, secnames[i])) - return (enum roff_sec)i; - - return SEC_CUSTOM; -} - -static size_t -macro2len(enum roff_tok macro) -{ - - switch (macro) { - case MDOC_Ad: - return 12; - case MDOC_Ao: - return 12; - case MDOC_An: - return 12; - case MDOC_Aq: - return 12; - case MDOC_Ar: - return 12; - case MDOC_Bo: - return 12; - case MDOC_Bq: - return 12; - case MDOC_Cd: - return 12; - case MDOC_Cm: - return 10; - case MDOC_Do: - return 10; - case MDOC_Dq: - return 12; - case MDOC_Dv: - return 12; - case MDOC_Eo: - return 12; - case MDOC_Em: - return 10; - case MDOC_Er: - return 17; - case MDOC_Ev: - return 15; - case MDOC_Fa: - return 12; - case MDOC_Fl: - return 10; - case MDOC_Fo: - return 16; - case MDOC_Fn: - return 16; - case MDOC_Ic: - return 10; - case MDOC_Li: - return 16; - case MDOC_Ms: - return 6; - case MDOC_Nm: - return 10; - case MDOC_No: - return 12; - case MDOC_Oo: - return 10; - case MDOC_Op: - return 14; - case MDOC_Pa: - return 32; - case MDOC_Pf: - return 12; - case MDOC_Po: - return 12; - case MDOC_Pq: - return 12; - case MDOC_Ql: - return 16; - case MDOC_Qo: - return 12; - case MDOC_So: - return 12; - case MDOC_Sq: - return 12; - case MDOC_Sy: - return 6; - case MDOC_Sx: - return 16; - case MDOC_Tn: - return 10; - case MDOC_Va: - return 12; - case MDOC_Vt: - return 12; - case MDOC_Xr: - return 10; - default: - break; - }; - return 0; -} Property changes on: head/contrib/mdocml/mdoc_validate.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/configure =================================================================== --- head/contrib/mdocml/configure (revision 338825) +++ head/contrib/mdocml/configure (nonexistent) @@ -1,537 +0,0 @@ -#!/bin/sh -# -# $Id: configure,v 1.64 2017/07/01 09:47:30 schwarze Exp $ -# -# Copyright (c) 2014, 2015, 2016, 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. - -set -e - -[ -w config.log ] && mv config.log config.log.old -[ -w config.h ] && mv config.h config.h.old - -# Output file descriptor usage: -# 1 (stdout): config.h, Makefile.local -# 2 (stderr): original stderr, usually to the console -# 3: config.log - -exec 3> config.log -echo "config.log: writing..." - -# --- default settings ------------------------------------------------- -# Initialize all variables here, -# such that nothing can leak in from the environment. - -SOURCEDIR=`dirname "$0"` - -MANPATH_BASE="/usr/share/man:/usr/X11R6/man" -MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" -OSNAME= -UTF8_LOCALE= - -CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | env -i make -sf -` -CFLAGS="-g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings" -CFLAGS="${CFLAGS} -Wno-unused-parameter" -LDADD= -LDFLAGS= -LD_NANOSLEEP= -LD_OHASH= -LD_RECVMSG= -STATIC="-static" - -BUILD_CGI=0 -BUILD_CATMAN=0 -INSTALL_LIBMANDOC=0 - -HAVE_CMSG= -HAVE_CMSG_XPG42=0 -HAVE_DIRENT_NAMLEN= -HAVE_EFTYPE= -HAVE_ENDIAN= -HAVE_ERR= -HAVE_FTS= -HAVE_FTS_COMPARE_CONST= -HAVE_GETLINE= -HAVE_GETSUBOPT= -HAVE_ISBLANK= -HAVE_MKDTEMP= -HAVE_NANOSLEEP= -HAVE_NTOHL= -HAVE_O_DIRECTORY= -HAVE_OHASH= -HAVE_PATH_MAX= -HAVE_PLEDGE= -HAVE_PROGNAME= -HAVE_REALLOCARRAY= -HAVE_RECALLOCARRAY= -HAVE_RECVMSG= -HAVE_REWB_BSD= -HAVE_REWB_SYSV= -HAVE_SANDBOX_INIT= -HAVE_STRCASESTR= -HAVE_STRINGLIST= -HAVE_STRLCAT= -HAVE_STRLCPY= -HAVE_STRPTIME= -HAVE_STRSEP= -HAVE_STRTONUM= -HAVE_SYS_ENDIAN= -HAVE_VASPRINTF= -HAVE_WCHAR= - -PREFIX="/usr/local" -BINDIR= -SBINDIR= -BIN_FROM_SBIN= -INCLUDEDIR= -LIBDIR= -MANDIR= -HOMEBREWDIR= - -WWWPREFIX="/var/www" -HTDOCDIR= -CGIBINDIR= - -BINM_APROPOS="apropos" -BINM_CATMAN="catman" -BINM_MAKEWHATIS="makewhatis" -BINM_MAN="man" -BINM_SOELIM="soelim" -BINM_WHATIS="whatis" -MANM_MAN="man" -MANM_MANCONF="man.conf" -MANM_MDOC="mdoc" -MANM_ROFF="roff" -MANM_EQN="eqn" -MANM_TBL="tbl" - -INSTALL="install" -INSTALL_PROGRAM= -INSTALL_LIB= -INSTALL_MAN= -INSTALL_DATA= -LN="ln -f" - -# --- manual settings from configure.local ----------------------------- - -if [ -r ./configure.local ]; then - echo "configure.local: reading..." 1>&2 - echo "configure.local: reading..." 1>&3 - cat ./configure.local 1>&3 - . ./configure.local -else - echo "configure.local: no (fully automatic configuration)" 1>&2 - echo "configure.local: no (fully automatic configuration)" 1>&3 -fi -echo 1>&3 - -# --- tests for config.h ---------------------------------------------- - -COMP="${CC} ${CFLAGS} -Wno-unused -Werror" - -# Check whether this HAVE_ setting is manually overridden. -# If yes, use the override, if no, do not decide anything yet. -# Arguments: lower-case test name, manual value -ismanual() { - [ -z "${3}" ] && return 1 - echo "${1}: manual (HAVE_${2}=${3})" 1>&2 - echo "${1}: manual (HAVE_${2}=${3})" 1>&3 - echo 1>&3 - return 0 -} - -# Run a single autoconfiguration test. -# In case of success, enable the feature. -# In case of failure, do not decide anything yet. -# Arguments: lower-case test name, upper-case test name, additional CFLAGS -singletest() { - cat 1>&3 << __HEREDOC__ -${1}${3}: testing... -${COMP} -o test-${1} test-${1}.c ${3} -__HEREDOC__ - - if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} 1>&3 2>&3 - then - echo "${1}${3}: ${CC} succeeded" 1>&3 - else - echo "${1}${3}: ${CC} failed with $?" 1>&3 - echo 1>&3 - return 1 - fi - - if ./test-${1} 1>&3 2>&3; then - echo "${1}${3}: yes" 1>&2 - echo "${1}${3}: yes" 1>&3 - echo 1>&3 - eval HAVE_${2}=1 - rm "test-${1}" - return 0 - else - echo "${1}${3}: execution failed with $?" 1>&3 - echo 1>&3 - rm "test-${1}" - return 1 - fi -} - -# Run a complete autoconfiguration test, including the check for -# a manual override and disabling the feature on failure. -# Arguments: lower case name, upper case name, additional CFLAGS -runtest() { - eval _manual=\${HAVE_${2}} - ismanual "${1}" "${2}" "${_manual}" && return 0 - singletest "${1}" "${2}" "${3}" && return 0 - echo "${1}${3}: no" 1>&2 - eval HAVE_${2}=0 - return 1 -} - -# Select a UTF-8 locale. -get_locale() { - [ -n "${HAVE_WCHAR}" ] && [ "${HAVE_WCHAR}" -eq 0 ] && return 0 - ismanual UTF8_LOCALE UTF8_LOCALE "$UTF8_LOCALE" && return 0 - echo "UTF8_LOCALE: testing..." 1>&3 - UTF8_LOCALE=`locale -a | grep -i '^en_US\.UTF-*8$' | head -n 1` - if [ -z "${UTF8_LOCALE}" ]; then - UTF8_LOCALE=`locale -a | grep -i '\.UTF-*8' | head -n 1` - [ -n "${UTF8_LOCALE}" ] || return 1 - fi - echo "UTF8_LOCALE=${UTF8_LOCALE}" 1>&2 - echo "UTF8_LOCALE=${UTF8_LOCALE}" 1>&3 - echo 1>&3 - return 0; -} - - -# --- library functions --- -runtest dirent-namlen DIRENT_NAMLEN || true -runtest be32toh ENDIAN || true -runtest be32toh SYS_ENDIAN -DSYS_ENDIAN || true -runtest EFTYPE EFTYPE || true -runtest err ERR || true -runtest getline GETLINE || true -runtest getsubopt GETSUBOPT || true -runtest isblank ISBLANK || true -runtest mkdtemp MKDTEMP || true -runtest ntohl NTOHL || true -runtest O_DIRECTORY O_DIRECTORY || true -runtest PATH_MAX PATH_MAX || true -runtest pledge PLEDGE || true -runtest sandbox_init SANDBOX_INIT || true -runtest progname PROGNAME || true -runtest reallocarray REALLOCARRAY || true -runtest recallocarray RECALLOCARRAY || true -runtest rewb-bsd REWB_BSD || true -runtest rewb-sysv REWB_SYSV || true -runtest strcasestr STRCASESTR || true -runtest stringlist STRINGLIST || true -runtest strlcat STRLCAT || true -runtest strlcpy STRLCPY || true -runtest strptime STRPTIME || true -runtest strsep STRSEP || true -runtest strtonum STRTONUM || true -runtest vasprintf VASPRINTF || true - -if [ ${HAVE_ENDIAN} -eq 0 -a \ - ${HAVE_SYS_ENDIAN} -eq 0 -a \ - ${HAVE_NTOHL} -eq 0 ]; then - echo "FATAL: no endian conversion functions found" 1>&2 - echo "FATAL: no endian conversion functions found" 1>&3 - exit 1 -fi - -if ismanual fts FTS ${HAVE_FTS}; then - HAVE_FTS_COMPARE_CONST=0 -elif runtest fts FTS_COMPARE_CONST -DFTS_COMPARE_CONST; then - HAVE_FTS=1 -else - runtest fts FTS || true -fi - -# --- wide character and locale support --- -if get_locale; then - runtest wchar WCHAR -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || true -else - HAVE_WCHAR=0 - echo "wchar: no (no UTF8_LOCALE)" 1>&2 - echo "wchar: no (no UTF8_LOCALE)" 1>&3 -fi - -# --- nanosleep --- -if [ -n "${LD_NANOSLEEP}" ]; then - runtest nanosleep NANOSLEEP "${LD_NANOSLEEP}" || true -elif singletest nanosleep NANOSLEEP; then - : -elif runtest nanosleep NANOSLEEP "-lrt"; then - LD_NANOSLEEP="-lrt" -fi -if [ "${HAVE_NANOSLEEP}" -eq 0 ]; then - echo "FATAL: nanosleep: no" 1>&2 - echo "FATAL: nanosleep: no" 1>&3 - exit 1 -fi - -if [ ${BUILD_CATMAN} -gt 0 ]; then - # --- recvmsg --- - if [ -n "${LD_RECVMSG}" ]; then - runtest recvmsg RECVMSG "${LD_RECVMSG}" || true - elif singletest recvmsg RECVMSG; then - : - elif runtest recvmsg RECVMSG "-lsocket"; then - LD_RECVMSG="-lsocket" - fi - if [ "${HAVE_RECVMSG}" -eq 0 ]; then - echo "FATAL: recvmsg: no" 1>&2 - echo "FATAL: recvmsg: no" 1>&3 - echo "Without recvmsg(2), you cannot BUILD_CATMAN." 1>&2 - exit 1 - fi - - # --- cmsg --- - if singletest cmsg CMSG; then - : - elif runtest cmsg CMSG "-D_XPG4_2"; then - HAVE_CMSG_XPG42=1 - fi - if [ "${HAVE_CMSG}" -eq 0 ]; then - echo "FATAL: cmsg: no" 1>&2 - echo "FATAL: cmsg: no" 1>&3 - echo "Without CMSG_FIRSTHDR(3), you cannot BUILD_CATMAN." 1>&2 - exit 1 - fi -fi - -# --- ohash --- -if ismanual ohash OHASH "${HAVE_OHASH}"; then - : -elif [ -n "${LD_OHASH}" ]; then - runtest ohash OHASH "${LD_OHASH}" || true -elif singletest ohash OHASH; then - : -elif runtest ohash OHASH "-lutil"; then - LD_OHASH="-lutil" -fi -if [ "${HAVE_OHASH}" -eq 0 ]; then - LD_OHASH= -fi - -# --- LDADD --- -LDADD="${LDADD} ${LD_NANOSLEEP} ${LD_RECVMSG} ${LD_OHASH} -lz" -echo "LDADD=\"${LDADD}\"" 1>&2 -echo "LDADD=\"${LDADD}\"" 1>&3 -echo 1>&3 - -# --- write config.h --- - -exec > config.h - -cat << __HEREDOC__ -#ifdef __cplusplus -#error "Do not use C++. See the INSTALL file." -#endif - -#if !defined(__GNUC__) || (__GNUC__ < 4) -#define __attribute__(x) -#endif - -#if defined(__linux__) || defined(__MINT__) -#define _GNU_SOURCE /* See test-*.c what needs this. */ -#endif - -__HEREDOC__ - -[ ${HAVE_GETLINE} -eq 0 -o \ - ${HAVE_REALLOCARRAY} -eq 0 -o ${HAVE_RECALLOCARRAY} -eq 0 -o \ - ${HAVE_STRLCAT} -eq 0 -o ${HAVE_STRLCPY} -eq 0 ] \ - && echo "#include " -[ ${HAVE_VASPRINTF} -eq 0 ] && echo "#include " -[ ${HAVE_GETLINE} -eq 0 ] && echo "#include " - -echo -echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\"" -echo "#define MANPATH_BASE \"${MANPATH_BASE}\"" -echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\"" -[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\"" -[ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\"" -[ -n "${HOMEBREWDIR}" ] && echo "#define HOMEBREWDIR \"${HOMEBREWDIR}\"" -[ ${HAVE_EFTYPE} -eq 0 ] && echo "#define EFTYPE EINVAL" -[ ${HAVE_O_DIRECTORY} -eq 0 ] && echo "#define O_DIRECTORY 0" -[ ${HAVE_PATH_MAX} -eq 0 ] && echo "#define PATH_MAX 4096" -if [ ${HAVE_ENDIAN} -eq 0 -a ${HAVE_SYS_ENDIAN} -eq 0 ]; then - echo "#define be32toh ntohl" - echo "#define htobe32 htonl" -fi - -cat << __HEREDOC__ -#define HAVE_CMSG_XPG42 ${HAVE_CMSG_XPG42} -#define HAVE_DIRENT_NAMLEN ${HAVE_DIRENT_NAMLEN} -#define HAVE_ENDIAN ${HAVE_ENDIAN} -#define HAVE_ERR ${HAVE_ERR} -#define HAVE_FTS ${HAVE_FTS} -#define HAVE_FTS_COMPARE_CONST ${HAVE_FTS_COMPARE_CONST} -#define HAVE_GETLINE ${HAVE_GETLINE} -#define HAVE_GETSUBOPT ${HAVE_GETSUBOPT} -#define HAVE_ISBLANK ${HAVE_ISBLANK} -#define HAVE_MKDTEMP ${HAVE_MKDTEMP} -#define HAVE_NTOHL ${HAVE_NTOHL} -#define HAVE_PLEDGE ${HAVE_PLEDGE} -#define HAVE_PROGNAME ${HAVE_PROGNAME} -#define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY} -#define HAVE_RECALLOCARRAY ${HAVE_RECALLOCARRAY} -#define HAVE_REWB_BSD ${HAVE_REWB_BSD} -#define HAVE_REWB_SYSV ${HAVE_REWB_SYSV} -#define HAVE_SANDBOX_INIT ${HAVE_SANDBOX_INIT} -#define HAVE_STRCASESTR ${HAVE_STRCASESTR} -#define HAVE_STRINGLIST ${HAVE_STRINGLIST} -#define HAVE_STRLCAT ${HAVE_STRLCAT} -#define HAVE_STRLCPY ${HAVE_STRLCPY} -#define HAVE_STRPTIME ${HAVE_STRPTIME} -#define HAVE_STRSEP ${HAVE_STRSEP} -#define HAVE_STRTONUM ${HAVE_STRTONUM} -#define HAVE_SYS_ENDIAN ${HAVE_SYS_ENDIAN} -#define HAVE_VASPRINTF ${HAVE_VASPRINTF} -#define HAVE_WCHAR ${HAVE_WCHAR} -#define HAVE_OHASH ${HAVE_OHASH} - -#define BINM_APROPOS "${BINM_APROPOS}" -#define BINM_CATMAN "${BINM_CATMAN}" -#define BINM_MAKEWHATIS "${BINM_MAKEWHATIS}" -#define BINM_MAN "${BINM_MAN}" -#define BINM_SOELIM "${BINM_SOELIM}" -#define BINM_WHATIS "${BINM_WHATIS}" - -__HEREDOC__ - -if [ ${HAVE_ERR} -eq 0 ]; then - echo "extern void err(int, const char *, ...);" - echo "extern void errx(int, const char *, ...);" - echo "extern void warn(const char *, ...);" - echo "extern void warnx(const char *, ...);" -fi - -[ ${HAVE_GETLINE} -eq 0 ] && \ - echo "extern ssize_t getline(char **, size_t *, FILE *);" - -[ ${HAVE_GETSUBOPT} -eq 0 ] && \ - echo "extern int getsubopt(char **, char * const *, char **);" - -[ ${HAVE_ISBLANK} -eq 0 ] && \ - echo "extern int isblank(int);" - -[ ${HAVE_MKDTEMP} -eq 0 ] && \ - echo "extern char *mkdtemp(char *);" - -if [ ${HAVE_PROGNAME} -eq 0 ]; then - echo "extern const char *getprogname(void);" - echo "extern void setprogname(const char *);" -fi - -[ ${HAVE_REALLOCARRAY} -eq 0 ] && \ - echo "extern void *reallocarray(void *, size_t, size_t);" - -[ ${HAVE_RECALLOCARRAY} -eq 0 ] && \ - echo "extern void *recallocarray(void *, size_t, size_t, size_t);" - -[ ${HAVE_STRCASESTR} -eq 0 ] && \ - echo "extern char *strcasestr(const char *, const char *);" - -[ ${HAVE_STRLCAT} -eq 0 ] && \ - echo "extern size_t strlcat(char *, const char *, size_t);" - -[ ${HAVE_STRLCPY} -eq 0 ] && \ - echo "extern size_t strlcpy(char *, const char *, size_t);" - -[ ${HAVE_STRSEP} -eq 0 ] && \ - echo "extern char *strsep(char **, const char *);" - -[ ${HAVE_STRTONUM} -eq 0 ] && \ - echo "extern long long strtonum(const char *, long long, long long, const char **);" - -[ ${HAVE_VASPRINTF} -eq 0 ] && \ - echo "extern int vasprintf(char **, const char *, va_list);" - -echo "config.h: written" 1>&2 -echo "config.h: written" 1>&3 - -# --- tests for Makefile.local ----------------------------------------- - -exec > Makefile.local - -[ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin" -[ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin" -[ -z "${BIN_FROM_SBIN}" ] && BIN_FROM_SBIN="../bin" -[ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include/mandoc" -[ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib/mandoc" -[ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man" - -[ -z "${HTDOCDIR}" ] && HTDOCDIR="${WWWPREFIX}/htdocs" -[ -z "${CGIBINDIR}" ] && CGIBINDIR="${WWWPREFIX}/cgi-bin" - -[ -z "${INSTALL_PROGRAM}" ] && INSTALL_PROGRAM="${INSTALL} -m 0555" -[ -z "${INSTALL_LIB}" ] && INSTALL_LIB="${INSTALL} -m 0444" -[ -z "${INSTALL_MAN}" ] && INSTALL_MAN="${INSTALL} -m 0444" -[ -z "${INSTALL_DATA}" ] && INSTALL_DATA="${INSTALL} -m 0444" - -BUILD_TARGETS= -[ ${BUILD_CGI} -gt 0 ] && BUILD_TARGETS="man.cgi" -[ ${BUILD_CATMAN} -gt 0 ] && \ - BUILD_TARGETS="${BUILD_TARGETS} mandocd catman" -INSTALL_TARGETS= -[ ${INSTALL_LIBMANDOC} -gt 0 ] && INSTALL_TARGETS="lib-install" -[ ${BUILD_CGI} -gt 0 ] && INSTALL_TARGETS="${INSTALL_TARGETS} cgi-install" -[ ${BUILD_CATMAN} -gt 0 ] && \ - INSTALL_TARGETS="${INSTALL_TARGETS} catman-install" - -cat << __HEREDOC__ -BUILD_TARGETS = ${BUILD_TARGETS} -INSTALL_TARGETS = ${INSTALL_TARGETS} -CC = ${CC} -CFLAGS = ${CFLAGS} -LDADD = ${LDADD} -LDFLAGS = ${LDFLAGS} -STATIC = ${STATIC} -PREFIX = ${PREFIX} -BINDIR = ${BINDIR} -SBINDIR = ${SBINDIR} -BIN_FROM_SBIN = ${BIN_FROM_SBIN} -INCLUDEDIR = ${INCLUDEDIR} -LIBDIR = ${LIBDIR} -MANDIR = ${MANDIR} -WWWPREFIX = ${WWWPREFIX} -HTDOCDIR = ${HTDOCDIR} -CGIBINDIR = ${CGIBINDIR} -BINM_APROPOS = ${BINM_APROPOS} -BINM_CATMAN = ${BINM_CATMAN} -BINM_MAKEWHATIS = ${BINM_MAKEWHATIS} -BINM_MAN = ${BINM_MAN} -BINM_SOELIM = ${BINM_SOELIM} -BINM_WHATIS = ${BINM_WHATIS} -MANM_MAN = ${MANM_MAN} -MANM_MANCONF = ${MANM_MANCONF} -MANM_MDOC = ${MANM_MDOC} -MANM_ROFF = ${MANM_ROFF} -MANM_EQN = ${MANM_EQN} -MANM_TBL = ${MANM_TBL} -INSTALL = ${INSTALL} -INSTALL_PROGRAM = ${INSTALL_PROGRAM} -INSTALL_LIB = ${INSTALL_LIB} -INSTALL_MAN = ${INSTALL_MAN} -INSTALL_DATA = ${INSTALL_DATA} -LN = ${LN} -__HEREDOC__ - -echo "Makefile.local: written" 1>&2 -echo "Makefile.local: written" 1>&3 - -exit 0 Property changes on: head/contrib/mdocml/configure ___________________________________________________________________ Deleted: svn:executable ## -1 +0,0 ## -* \ No newline at end of property Index: head/contrib/mdocml/dbm.h =================================================================== --- head/contrib/mdocml/dbm.h (revision 338825) +++ head/contrib/mdocml/dbm.h (nonexistent) @@ -1,68 +0,0 @@ -/* $Id: dbm.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */ -/* - * Copyright (c) 2016 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. - * - * Public interface for the map-based version - * of the mandoc database, for read-only access. - * To be used by dbm*.c, dba_read.c, and man(1) and apropos(1). - */ - -enum dbm_mtype { - DBM_EXACT = 0, - DBM_SUB, - DBM_REGEX -}; - -struct dbm_match { - regex_t *re; - const char *str; - enum dbm_mtype type; -}; - -struct dbm_res { - int32_t page; - int32_t bits; -}; - -struct dbm_page { - const char *name; - const char *sect; - const char *arch; - const char *desc; - const char *file; - int32_t addr; -}; - -struct dbm_macro { - const char *value; - const int32_t *pp; -}; - -int dbm_open(const char *); -void dbm_close(void); - -int32_t dbm_page_count(void); -struct dbm_page *dbm_page_get(int32_t); -void dbm_page_byname(const struct dbm_match *); -void dbm_page_bysect(const struct dbm_match *); -void dbm_page_byarch(const struct dbm_match *); -void dbm_page_bydesc(const struct dbm_match *); -void dbm_page_bymacro(int32_t, const struct dbm_match *); -struct dbm_res dbm_page_next(void); - -int32_t dbm_macro_count(int32_t); -struct dbm_macro *dbm_macro_get(int32_t, int32_t); -void dbm_macro_bypage(int32_t, int32_t); -char *dbm_macro_next(void); Property changes on: head/contrib/mdocml/dbm.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/man-cgi.css =================================================================== --- head/contrib/mdocml/man-cgi.css (revision 338825) +++ head/contrib/mdocml/man-cgi.css (nonexistent) @@ -1,13 +0,0 @@ -body { font-family: Helvetica, Arial, sans-serif; } -body > div { padding-left: 2em; - padding-top: 1em; } -body > div#mancgi { padding-left: 0em; - padding-top: 0em; } -body > div.results { font-size: smaller; } -#mancgi fieldset { text-align: center; - border: thin solid silver; - border-radius: 1em; - font-size: small; } -#mancgi input[name=expr] { width: 25%; } -.results td.title { vertical-align: top; - padding-right: 1em; } Property changes on: head/contrib/mdocml/man-cgi.css ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/css \ No newline at end of property Index: head/contrib/mdocml/mandoc_xr.c =================================================================== --- head/contrib/mdocml/mandoc_xr.c (revision 338825) +++ head/contrib/mdocml/mandoc_xr.c (nonexistent) @@ -1,121 +0,0 @@ -/* $Id: mandoc_xr.c,v 1.3 2017/07/02 21:18:29 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. - */ -#include - -#include -#include -#include -#include -#include - -#include "mandoc_aux.h" -#include "mandoc_ohash.h" -#include "mandoc_xr.h" - -static struct ohash *xr_hash = NULL; -static struct mandoc_xr *xr_first = NULL; -static struct mandoc_xr *xr_last = NULL; - -static void mandoc_xr_clear(void); - - -static void -mandoc_xr_clear(void) -{ - struct mandoc_xr *xr; - unsigned int slot; - - if (xr_hash == NULL) - return; - for (xr = ohash_first(xr_hash, &slot); xr != NULL; - xr = ohash_next(xr_hash, &slot)) - free(xr); - ohash_delete(xr_hash); -} - -void -mandoc_xr_reset(void) -{ - if (xr_hash == NULL) - xr_hash = mandoc_malloc(sizeof(*xr_hash)); - else - mandoc_xr_clear(); - mandoc_ohash_init(xr_hash, 5, - offsetof(struct mandoc_xr, hashkey)); - xr_first = xr_last = NULL; -} - -int -mandoc_xr_add(const char *sec, const char *name, int line, int pos) -{ - struct mandoc_xr *xr, *oxr; - const char *pend; - size_t ssz, nsz, tsz; - unsigned int slot; - int ret; - uint32_t hv; - - if (xr_hash == NULL) - return 0; - - ssz = strlen(sec) + 1; - nsz = strlen(name) + 1; - tsz = ssz + nsz; - xr = mandoc_malloc(sizeof(*xr) + tsz); - xr->next = NULL; - xr->sec = xr->hashkey; - xr->name = xr->hashkey + ssz; - xr->line = line; - xr->pos = pos; - xr->count = 1; - memcpy(xr->sec, sec, ssz); - memcpy(xr->name, name, nsz); - - pend = xr->hashkey + tsz; - hv = ohash_interval(xr->hashkey, &pend); - slot = ohash_lookup_memory(xr_hash, xr->hashkey, tsz, hv); - if ((oxr = ohash_find(xr_hash, slot)) == NULL) { - ohash_insert(xr_hash, slot, xr); - if (xr_first == NULL) - xr_first = xr; - else - xr_last->next = xr; - xr_last = xr; - return 0; - } - - oxr->count++; - ret = (oxr->line == -1) ^ (xr->line == -1); - if (xr->line == -1) - oxr->line = -1; - free(xr); - return ret; -} - -struct mandoc_xr * -mandoc_xr_get(void) -{ - return xr_first; -} - -void -mandoc_xr_free(void) -{ - mandoc_xr_clear(); - free(xr_hash); - xr_hash = NULL; -} Property changes on: head/contrib/mdocml/mandoc_xr.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/term_ascii.c =================================================================== --- head/contrib/mdocml/term_ascii.c (revision 338825) +++ head/contrib/mdocml/term_ascii.c (nonexistent) @@ -1,387 +0,0 @@ -/* $Id: term_ascii.c,v 1.58 2017/06/14 14:24:20 schwarze Exp $ */ -/* - * Copyright (c) 2010, 2011 Kristaps Dzonsons - * 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 - -#include -#if HAVE_WCHAR -#include -#endif -#include -#include -#include -#include -#if HAVE_WCHAR -#include -#endif - -#include "mandoc.h" -#include "mandoc_aux.h" -#include "out.h" -#include "term.h" -#include "manconf.h" -#include "main.h" - -static struct termp *ascii_init(enum termenc, const struct manoutput *); -static int ascii_hspan(const struct termp *, - const struct roffsu *); -static size_t ascii_width(const struct termp *, int); -static void ascii_advance(struct termp *, size_t); -static void ascii_begin(struct termp *); -static void ascii_end(struct termp *); -static void ascii_endline(struct termp *); -static void ascii_letter(struct termp *, int); -static void ascii_setwidth(struct termp *, int, int); - -#if HAVE_WCHAR -static void locale_advance(struct termp *, size_t); -static void locale_endline(struct termp *); -static void locale_letter(struct termp *, int); -static size_t locale_width(const struct termp *, int); -#endif - - -static struct termp * -ascii_init(enum termenc enc, const struct manoutput *outopts) -{ -#if HAVE_WCHAR - char *v; -#endif - struct termp *p; - - p = mandoc_calloc(1, sizeof(*p)); - p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol)); - p->maxtcol = 1; - - p->line = 1; - p->defrmargin = p->lastrmargin = 78; - p->fontq = mandoc_reallocarray(NULL, - (p->fontsz = 8), sizeof(*p->fontq)); - p->fontq[0] = p->fontl = TERMFONT_NONE; - - p->begin = ascii_begin; - p->end = ascii_end; - p->hspan = ascii_hspan; - p->type = TERMTYPE_CHAR; - - p->enc = TERMENC_ASCII; - p->advance = ascii_advance; - p->endline = ascii_endline; - p->letter = ascii_letter; - p->setwidth = ascii_setwidth; - p->width = ascii_width; - -#if HAVE_WCHAR - if (TERMENC_ASCII != enc) { - - /* - * Do not change any of this to LC_ALL. It might break - * the formatting by subtly changing the behaviour of - * various functions, for example strftime(3). As a - * worst case, it might even cause buffer overflows. - */ - - v = TERMENC_LOCALE == enc ? - setlocale(LC_CTYPE, "") : - setlocale(LC_CTYPE, UTF8_LOCALE); - if (NULL != v && MB_CUR_MAX > 1) { - p->enc = enc; - p->advance = locale_advance; - p->endline = locale_endline; - p->letter = locale_letter; - p->width = locale_width; - } - } -#endif - - if (outopts->mdoc) { - p->mdocstyle = 1; - p->defindent = 5; - } - if (outopts->indent) - p->defindent = outopts->indent; - if (outopts->width) - p->defrmargin = outopts->width; - if (outopts->synopsisonly) - p->synopsisonly = 1; - - return p; -} - -void * -ascii_alloc(const struct manoutput *outopts) -{ - - return ascii_init(TERMENC_ASCII, outopts); -} - -void * -utf8_alloc(const struct manoutput *outopts) -{ - - return ascii_init(TERMENC_UTF8, outopts); -} - -void * -locale_alloc(const struct manoutput *outopts) -{ - - return ascii_init(TERMENC_LOCALE, outopts); -} - -static void -ascii_setwidth(struct termp *p, int iop, int width) -{ - - width /= 24; - p->tcol->rmargin = p->defrmargin; - if (iop > 0) - p->defrmargin += width; - else if (iop == 0) - p->defrmargin = width ? (size_t)width : p->lastrmargin; - else if (p->defrmargin > (size_t)width) - p->defrmargin -= width; - else - p->defrmargin = 0; - p->lastrmargin = p->tcol->rmargin; - p->tcol->rmargin = p->maxrmargin = p->defrmargin; -} - -void -terminal_sepline(void *arg) -{ - struct termp *p; - size_t i; - - p = (struct termp *)arg; - (*p->endline)(p); - for (i = 0; i < p->defrmargin; i++) - (*p->letter)(p, '-'); - (*p->endline)(p); - (*p->endline)(p); -} - -static size_t -ascii_width(const struct termp *p, int c) -{ - - return 1; -} - -void -ascii_free(void *arg) -{ - - term_free((struct termp *)arg); -} - -static void -ascii_letter(struct termp *p, int c) -{ - - putchar(c); -} - -static void -ascii_begin(struct termp *p) -{ - - (*p->headf)(p, p->argf); -} - -static void -ascii_end(struct termp *p) -{ - - (*p->footf)(p, p->argf); -} - -static void -ascii_endline(struct termp *p) -{ - - p->line++; - p->tcol->offset -= p->ti; - p->ti = 0; - putchar('\n'); -} - -static void -ascii_advance(struct termp *p, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) - putchar(' '); -} - -static int -ascii_hspan(const struct termp *p, const struct roffsu *su) -{ - double r; - - switch (su->unit) { - case SCALE_BU: - r = su->scale; - break; - case SCALE_CM: - r = su->scale * 240.0 / 2.54; - break; - case SCALE_FS: - r = su->scale * 65536.0; - break; - case SCALE_IN: - r = su->scale * 240.0; - break; - case SCALE_MM: - r = su->scale * 0.24; - break; - case SCALE_VS: - case SCALE_PC: - r = su->scale * 40.0; - break; - case SCALE_PT: - r = su->scale * 10.0 / 3.0; - break; - case SCALE_EN: - case SCALE_EM: - r = su->scale * 24.0; - break; - default: - abort(); - } - return r > 0.0 ? r + 0.01 : r - 0.01; -} - -const char * -ascii_uc2str(int uc) -{ - static const char nbrsp[2] = { ASCII_NBRSP, '\0' }; - static const char *tab[] = { - "","","","","","","","", - "", "\t", "", "", "", "", "", "", - "","","","","","","","", - "","", "","","", "", "", "", - " ", "!", "\"", "#", "$", "%", "&", "'", - "(", ")", "*", "+", ",", "-", ".", "/", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", ":", ";", "<", "=", ">", "?", - "@", "A", "B", "C", "D", "E", "F", "G", - "H", "I", "J", "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", "U", "V", "W", - "X", "Y", "Z", "[", "\\", "]", "^", "_", - "`", "a", "b", "c", "d", "e", "f", "g", - "h", "i", "j", "k", "l", "m", "n", "o", - "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "{", "|", "}", "~", "", - "<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>", - "<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>", - "<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>", - "<98>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>", - nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "", - "\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-", - "","+-", "2", "3", "'", ",\bu", "",".", - ",", "1", "_\bo", ">>", "1/4", "1/2", "3/4", "?", - "`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC", - "`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI", - "-\bD", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x", - "/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss", - "`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc", - "`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi", - "d", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","-:-", - "/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by", - "A", "a", "A", "a", "A", "a", "'\bC", "'\bc", - "^\bC", "^\bc", "C", "c", "C", "c", "D", "d", - "/\bD", "/\bd", "E", "e", "E", "e", "E", "e", - "E", "e", "E", "e", "^\bG", "^\bg", "G", "g", - "G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh", - "~\bI", "~\bi", "I", "i", "I", "i", "I", "i", - "I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk", - "q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L", - "l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N", - "n", "'n", "Ng", "ng", "O", "o", "O", "o", - "O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br", - "R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs", - "S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt", - "~\bU", "~\bu", "U", "u", "U", "u", "U", "u", - "U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by", - "\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s", - "b", "B", "B", "b", "6", "6", "O", "C", - "c", "D", "D", "D", "d", "d", "3", "@", - "E", "F", ",\bf", "G", "G", "hv", "I", "/\bI", - "K", "k", "/\bl", "l", "W", "N", "n", "~\bO", - "O", "o", "OI", "oi", "P", "p", "YR", "2", - "2", "SH", "sh", "t", "T", "t", "T", "U", - "u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH", - "ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w", - "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ", - "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I", - "i", "O", "o", "U", "u", "U", "u", "U", - "u", "U", "u", "U", "u", "@", "A", "a", - "A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g", - "K", "k", "O", "o", "O", "o", "ZH", "zh", - "j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W", - "`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"}; - - assert(uc >= 0); - if ((size_t)uc < sizeof(tab)/sizeof(tab[0])) - return tab[uc]; - return mchars_uc2str(uc); -} - -#if HAVE_WCHAR -static size_t -locale_width(const struct termp *p, int c) -{ - int rc; - - if (c == ASCII_NBRSP) - c = ' '; - rc = wcwidth(c); - if (rc < 0) - rc = 0; - return rc; -} - -static void -locale_advance(struct termp *p, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) - putwchar(L' '); -} - -static void -locale_endline(struct termp *p) -{ - - p->line++; - p->tcol->offset -= p->ti; - p->ti = 0; - putwchar(L'\n'); -} - -static void -locale_letter(struct termp *p, int c) -{ - - putwchar(c); -} -#endif Property changes on: head/contrib/mdocml/term_ascii.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mchars_alloc.3 =================================================================== --- head/contrib/mdocml/mchars_alloc.3 (revision 338825) +++ head/contrib/mdocml/mchars_alloc.3 (nonexistent) @@ -1,227 +0,0 @@ -.\" $Id: mchars_alloc.3,v 1.4 2016/07/07 19:19:01 schwarze Exp $ -.\" -.\" Copyright (c) 2014 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: July 7 2016 $ -.Dt MCHARS_ALLOC 3 -.Os -.Sh NAME -.Nm mchars_alloc , -.Nm mchars_free , -.Nm mchars_num2char , -.Nm mchars_num2uc , -.Nm mchars_spec2cp , -.Nm mchars_spec2str , -.Nm mchars_uc2str -.Nd character table for mandoc -.Sh SYNOPSIS -.In sys/types.h -.In mandoc.h -.Ft void -.Fn mchars_alloc void -.Ft void -.Fn mchars_free void -.Ft char -.Fo mchars_num2char -.Fa "const char *decimal" -.Fa "size_t sz" -.Fc -.Ft int -.Fo mchars_num2uc -.Fa "const char *hexadecimal" -.Fa "size_t sz" -.Fc -.Ft int -.Fo mchars_spec2cp -.Fa "const char *name" -.Fa "size_t sz" -.Fc -.Ft "const char *" -.Fo mchars_spec2str -.Fa "const char *name" -.Fa "size_t sz" -.Fa "size_t *rsz" -.Fc -.Ft "const char *" -.Fn mchars_uc2str "int codepoint" -.Sh DESCRIPTION -These functions translate Unicode character numbers and -.Xr roff 7 -character names into glyphs. -See -.Xr mandoc_char 7 -for a list of -.Xr roff 7 -special characters. -These functions are intended for external use by programs formatting -.Xr mdoc 7 -and -.Xr man 7 -pages for output, for example the -.Xr mandoc 1 -output formatter modules and -.Xr makewhatis 8 . -The -.Fa decimal , -.Fa hexadecimal , -.Fa name , -and -.Fa size -input arguments are usually obtained from the -.Xr mandoc_escape 3 -parser function. -.Pp -The function -.Fn mchars_num2char -converts a -.Fa decimal -string representation of a character number consisting of -.Fa sz -digits into a printable ASCII character. -If the input string is non-numeric or does not represent a printable -ASCII character, the NUL character -.Pq Sq \e0 -is returned. -For example, the -.Xr mandoc 1 -.Fl Tascii , -.Fl Tutf8 , -and -.Fl Thtml -output modules use this function to render -.Xr roff 7 -.Ic \eN -escape sequences. -.Pp -The function -.Fn mchars_num2uc -converts a -.Fa hexadecimal -string representation of a Unicode codepoint consisting of -.Fa sz -digits into an integer representation. -If the input string is non-numeric or represents an ASCII character, -the NUL character -.Pq Sq \e0 -is returned. -For example, the -.Xr mandoc 1 -.Fl Tutf8 -and -.Fl Thtml -output modules use this function to render -.Xr roff 7 -.Ic \e[u Ns Ar XXXX Ns Ic \&] -and -.Ic \eC\(aqu Ns Ar XXXX Ns Ic \(aq -escape sequences. -.Pp -The function -.Fn mchars_alloc -initializes a static -.Vt "struct ohash" -object for subsequent use by the following two lookup functions. -When no longer needed, this object can be destroyed with -.Fn mchars_free . -.Pp -The function -.Fn mchars_spec2cp -looks up a -.Xr roff 7 -special character -.Fa name -consisting of -.Fa sz -characters and returns the corresponding Unicode codepoint. -If the -.Ar name -is not recognized, \-1 is returned. -For example, the -.Xr mandoc 1 -.Fl Tutf8 -and -.Fl Thtml -output modules use this function to render -.Xr roff 7 -.Ic \e[ Ns Ar name Ns Ic \&] -and -.Ic \eC\(aq Ns Ar name Ns Ic \(aq -escape sequences. -.Pp -The function -.Fn mchars_spec2str -looks up a -.Xr roff 7 -special character -.Fa name -consisting of -.Fa sz -characters and returns an ASCII string representation. -The length of the representation is returned in -.Fa rsz . -In many cases, the meaning of such ASCII representations -is not quite obvious, so using -.Xr roff 7 -special characters in documents intended for ASCII rendering -is usually a bad idea. -If the -.Ar name -is not recognized, -.Dv NULL -is returned. -For example, -.Xr makewhatis 8 -and the -.Xr mandoc 1 -.Fl Tascii -output module use this function to render -.Xr roff 7 -.Ic \e[ Ns Ar name Ns Ic \&] -and -.Ic \eC\(aq Ns Ar name Ns Ic \(aq -escape sequences. -.Pp -The function -.Fn mchars_uc2str -performs a reverse lookup of the Unicode -.Fa codepoint -and returns an ASCII string representation, or the string -.Qq -if none is available. -.Sh FILES -These funtions are implemented in the file -.Pa chars.c . -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr mandoc_escape 3 , -.Xr ohash_init 3 , -.Xr mandoc_char 7 , -.Xr roff 7 -.Sh HISTORY -These functions and their predecessors have been available since the -following mandoc versions: -.Bl -column "mchars_num2char()" "1.11.3" "chars_num2char()" "1.10.10" -.It Sy function Ta since Ta Sy predecessor Ta since -.It Fn mchars_alloc Ta 1.11.3 Ta Fn ascii2htab Ta 1.5.3 -.It Fn mchars_free Ta 1.11.2 Ta Fn asciifree Ta 1.6.0 -.It Fn mchars_num2char Ta 1.11.2 Ta Fn chars_num2char Ta 1.10.10 -.It Fn mchars_num2uc Ta 1.11.3 Ta \(em Ta \(em -.It Fn mchars_spec2cp Ta 1.11.2 Ta Fn chars_spec2cp Ta 1.10.5 -.It Fn mchars_spec2str Ta 1.11.2 Ta Fn a2ascii Ta 1.5.3 -.It Fn mchars_uc2str Ta 1.13.2 Ta \(em Ta \(em -.El -.Sh AUTHORS -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv -.An Ingo Schwarze Aq Mt schwarze@openbsd.org Property changes on: head/contrib/mdocml/mchars_alloc.3 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mandocd.c =================================================================== --- head/contrib/mdocml/mandocd.c (revision 338825) +++ head/contrib/mdocml/mandocd.c (nonexistent) @@ -1,285 +0,0 @@ -/* $Id: mandocd.c,v 1.6 2017/06/24 14:38:32 schwarze Exp $ */ -/* - * Copyright (c) 2017 Michael Stapelberg - * 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 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" - -#if HAVE_CMSG_XPG42 -#define _XPG4_2 -#endif - -#include -#include - -#if HAVE_ERR -#include -#endif -#include -#include -#include -#include -#include -#include - -#include "mandoc.h" -#include "roff.h" -#include "mdoc.h" -#include "man.h" -#include "main.h" -#include "manconf.h" - -enum outt { - OUTT_ASCII = 0, - OUTT_UTF8, - OUTT_HTML -}; - -static void process(struct mparse *, enum outt, void *); -static int read_fds(int, int *); -static void usage(void) __attribute__((__noreturn__)); - - -#define NUM_FDS 3 -static int -read_fds(int clientfd, int *fds) -{ - struct msghdr msg; - struct iovec iov[1]; - unsigned char dummy[1]; - struct cmsghdr *cmsg; - int *walk; - int cnt; - - /* Union used for alignment. */ - union { - uint8_t controlbuf[CMSG_SPACE(NUM_FDS * sizeof(int))]; - struct cmsghdr align; - } u; - - memset(&msg, '\0', sizeof(msg)); - msg.msg_control = u.controlbuf; - msg.msg_controllen = sizeof(u.controlbuf); - - /* - * Read a dummy byte - sendmsg cannot send an empty message, - * even if we are only interested in the OOB data. - */ - - iov[0].iov_base = dummy; - iov[0].iov_len = sizeof(dummy); - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - switch (recvmsg(clientfd, &msg, 0)) { - case -1: - warn("recvmsg"); - return -1; - case 0: - return 0; - default: - break; - } - - if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) { - warnx("CMSG_FIRSTHDR: missing control message"); - return -1; - } - - if (cmsg->cmsg_level != SOL_SOCKET || - cmsg->cmsg_type != SCM_RIGHTS || - cmsg->cmsg_len != CMSG_LEN(NUM_FDS * sizeof(int))) { - warnx("CMSG_FIRSTHDR: invalid control message"); - return -1; - } - - walk = (int *)CMSG_DATA(cmsg); - for (cnt = 0; cnt < NUM_FDS; cnt++) - fds[cnt] = *walk++; - - return 1; -} - -int -main(int argc, char *argv[]) -{ - struct manoutput options; - struct mparse *parser; - void *formatter; - const char *defos; - const char *errstr; - int clientfd; - int old_stdin; - int old_stdout; - int old_stderr; - int fds[3]; - int state, opt; - enum outt outtype; - - defos = NULL; - outtype = OUTT_ASCII; - while ((opt = getopt(argc, argv, "I:T:")) != -1) { - switch (opt) { - case 'I': - if (strncmp(optarg, "os=", 3) == 0) - defos = optarg + 3; - else { - warnx("-I %s: Bad argument", optarg); - usage(); - } - break; - case 'T': - if (strcmp(optarg, "ascii") == 0) - outtype = OUTT_ASCII; - else if (strcmp(optarg, "utf8") == 0) - outtype = OUTT_UTF8; - else if (strcmp(optarg, "html") == 0) - outtype = OUTT_HTML; - else { - warnx("-T %s: Bad argument", optarg); - usage(); - } - break; - default: - usage(); - } - } - - if (argc > 0) { - argc -= optind; - argv += optind; - } - if (argc != 1) - usage(); - - errstr = NULL; - clientfd = strtonum(argv[0], 3, INT_MAX, &errstr); - if (errstr) - errx(1, "file descriptor %s %s", argv[1], errstr); - - mchars_alloc(); - parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1, - MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, defos); - - memset(&options, 0, sizeof(options)); - switch (outtype) { - case OUTT_ASCII: - formatter = ascii_alloc(&options); - break; - case OUTT_UTF8: - formatter = utf8_alloc(&options); - break; - case OUTT_HTML: - options.fragment = 1; - formatter = html_alloc(&options); - break; - } - - state = 1; /* work to do */ - fflush(stdout); - fflush(stderr); - if ((old_stdin = dup(STDIN_FILENO)) == -1 || - (old_stdout = dup(STDOUT_FILENO)) == -1 || - (old_stderr = dup(STDERR_FILENO)) == -1) { - warn("dup"); - state = -1; /* error */ - } - - while (state == 1 && (state = read_fds(clientfd, fds)) == 1) { - if (dup2(fds[0], STDIN_FILENO) == -1 || - dup2(fds[1], STDOUT_FILENO) == -1 || - dup2(fds[2], STDERR_FILENO) == -1) { - warn("dup2"); - state = -1; - break; - } - - close(fds[0]); - close(fds[1]); - close(fds[2]); - - process(parser, outtype, formatter); - mparse_reset(parser); - - fflush(stdout); - fflush(stderr); - /* Close file descriptors by restoring the old ones. */ - if (dup2(old_stderr, STDERR_FILENO) == -1 || - dup2(old_stdout, STDOUT_FILENO) == -1 || - dup2(old_stdin, STDIN_FILENO) == -1) { - warn("dup2"); - state = -1; - break; - } - } - - close(clientfd); - switch (outtype) { - case OUTT_ASCII: - case OUTT_UTF8: - ascii_free(formatter); - break; - case OUTT_HTML: - html_free(formatter); - break; - } - mparse_free(parser); - mchars_free(); - return state == -1 ? 1 : 0; -} - -static void -process(struct mparse *parser, enum outt outtype, void *formatter) -{ - struct roff_man *man; - - mparse_readfd(parser, STDIN_FILENO, ""); - mparse_result(parser, &man, NULL); - - if (man == NULL) - return; - - if (man->macroset == MACROSET_MDOC) { - mdoc_validate(man); - switch (outtype) { - case OUTT_ASCII: - case OUTT_UTF8: - terminal_mdoc(formatter, man); - break; - case OUTT_HTML: - html_mdoc(formatter, man); - break; - } - } - if (man->macroset == MACROSET_MAN) { - man_validate(man); - switch (outtype) { - case OUTT_ASCII: - case OUTT_UTF8: - terminal_man(formatter, man); - break; - case OUTT_HTML: - html_man(formatter, man); - break; - } - } -} - -void -usage(void) -{ - fprintf(stderr, "usage: mandocd [-I os=name] [-T output] socket_fd\n"); - exit(1); -} Property changes on: head/contrib/mdocml/mandocd.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/term_ps.c =================================================================== --- head/contrib/mdocml/term_ps.c (revision 338825) +++ head/contrib/mdocml/term_ps.c (nonexistent) @@ -1,1331 +0,0 @@ -/* $Id: term_ps.c,v 1.85 2017/06/07 17:38:26 schwarze Exp $ */ -/* - * Copyright (c) 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2014, 2015, 2016, 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 -#if HAVE_ERR -#include -#endif -#include -#include -#include -#include -#include -#include - -#include "mandoc_aux.h" -#include "out.h" -#include "term.h" -#include "manconf.h" -#include "main.h" - -/* These work the buffer used by the header and footer. */ -#define PS_BUFSLOP 128 - -/* Convert PostScript point "x" to an AFM unit. */ -#define PNT2AFM(p, x) \ - (size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale)) - -/* Convert an AFM unit "x" to a PostScript points */ -#define AFM2PNT(p, x) \ - ((double)(x) / (1000.0 / (double)(p)->ps->scale)) - -struct glyph { - unsigned short wx; /* WX in AFM */ -}; - -struct font { - const char *name; /* FontName in AFM */ -#define MAXCHAR 95 /* total characters we can handle */ - struct glyph gly[MAXCHAR]; /* glyph metrics */ -}; - -struct termp_ps { - int flags; -#define PS_INLINE (1 << 0) /* we're in a word */ -#define PS_MARGINS (1 << 1) /* we're in the margins */ -#define PS_NEWPAGE (1 << 2) /* new page, no words yet */ -#define PS_BACKSP (1 << 3) /* last character was backspace */ - size_t pscol; /* visible column (AFM units) */ - size_t pscolnext; /* used for overstrike */ - size_t psrow; /* visible row (AFM units) */ - char *psmarg; /* margin buf */ - size_t psmargsz; /* margin buf size */ - size_t psmargcur; /* cur index in margin buf */ - char last; /* last non-backspace seen */ - enum termfont lastf; /* last set font */ - enum termfont nextf; /* building next font here */ - size_t scale; /* font scaling factor */ - size_t pages; /* number of pages shown */ - size_t lineheight; /* line height (AFM units) */ - size_t top; /* body top (AFM units) */ - size_t bottom; /* body bottom (AFM units) */ - size_t height; /* page height (AFM units */ - size_t width; /* page width (AFM units) */ - size_t lastwidth; /* page width before last ll */ - size_t left; /* body left (AFM units) */ - size_t header; /* header pos (AFM units) */ - size_t footer; /* footer pos (AFM units) */ - size_t pdfbytes; /* current output byte */ - size_t pdflastpg; /* byte of last page mark */ - size_t pdfbody; /* start of body object */ - size_t *pdfobjs; /* table of object offsets */ - size_t pdfobjsz; /* size of pdfobjs */ -}; - -static int ps_hspan(const struct termp *, - const struct roffsu *); -static size_t ps_width(const struct termp *, int); -static void ps_advance(struct termp *, size_t); -static void ps_begin(struct termp *); -static void ps_closepage(struct termp *); -static void ps_end(struct termp *); -static void ps_endline(struct termp *); -static void ps_growbuf(struct termp *, size_t); -static void ps_letter(struct termp *, int); -static void ps_pclose(struct termp *); -static void ps_plast(struct termp *); -static void ps_pletter(struct termp *, int); -static void ps_printf(struct termp *, const char *, ...) - __attribute__((__format__ (__printf__, 2, 3))); -static void ps_putchar(struct termp *, char); -static void ps_setfont(struct termp *, enum termfont); -static void ps_setwidth(struct termp *, int, int); -static struct termp *pspdf_alloc(const struct manoutput *); -static void pdf_obj(struct termp *, size_t); - -/* - * We define, for the time being, three fonts: bold, oblique/italic, and - * normal (roman). The following table hard-codes the font metrics for - * ASCII, i.e., 32--127. - */ - -static const struct font fonts[TERMFONT__MAX] = { - { "Times-Roman", { - { 250 }, - { 333 }, - { 408 }, - { 500 }, - { 500 }, - { 833 }, - { 778 }, - { 333 }, - { 333 }, - { 333 }, - { 500 }, - { 564 }, - { 250 }, - { 333 }, - { 250 }, - { 278 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 278 }, - { 278 }, - { 564 }, - { 564 }, - { 564 }, - { 444 }, - { 921 }, - { 722 }, - { 667 }, - { 667 }, - { 722 }, - { 611 }, - { 556 }, - { 722 }, - { 722 }, - { 333 }, - { 389 }, - { 722 }, - { 611 }, - { 889 }, - { 722 }, - { 722 }, - { 556 }, - { 722 }, - { 667 }, - { 556 }, - { 611 }, - { 722 }, - { 722 }, - { 944 }, - { 722 }, - { 722 }, - { 611 }, - { 333 }, - { 278 }, - { 333 }, - { 469 }, - { 500 }, - { 333 }, - { 444 }, - { 500 }, - { 444 }, - { 500}, - { 444}, - { 333}, - { 500}, - { 500}, - { 278}, - { 278}, - { 500}, - { 278}, - { 778}, - { 500}, - { 500}, - { 500}, - { 500}, - { 333}, - { 389}, - { 278}, - { 500}, - { 500}, - { 722}, - { 500}, - { 500}, - { 444}, - { 480}, - { 200}, - { 480}, - { 541}, - } }, - { "Times-Bold", { - { 250 }, - { 333 }, - { 555 }, - { 500 }, - { 500 }, - { 1000 }, - { 833 }, - { 333 }, - { 333 }, - { 333 }, - { 500 }, - { 570 }, - { 250 }, - { 333 }, - { 250 }, - { 278 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 333 }, - { 333 }, - { 570 }, - { 570 }, - { 570 }, - { 500 }, - { 930 }, - { 722 }, - { 667 }, - { 722 }, - { 722 }, - { 667 }, - { 611 }, - { 778 }, - { 778 }, - { 389 }, - { 500 }, - { 778 }, - { 667 }, - { 944 }, - { 722 }, - { 778 }, - { 611 }, - { 778 }, - { 722 }, - { 556 }, - { 667 }, - { 722 }, - { 722 }, - { 1000 }, - { 722 }, - { 722 }, - { 667 }, - { 333 }, - { 278 }, - { 333 }, - { 581 }, - { 500 }, - { 333 }, - { 500 }, - { 556 }, - { 444 }, - { 556 }, - { 444 }, - { 333 }, - { 500 }, - { 556 }, - { 278 }, - { 333 }, - { 556 }, - { 278 }, - { 833 }, - { 556 }, - { 500 }, - { 556 }, - { 556 }, - { 444 }, - { 389 }, - { 333 }, - { 556 }, - { 500 }, - { 722 }, - { 500 }, - { 500 }, - { 444 }, - { 394 }, - { 220 }, - { 394 }, - { 520 }, - } }, - { "Times-Italic", { - { 250 }, - { 333 }, - { 420 }, - { 500 }, - { 500 }, - { 833 }, - { 778 }, - { 333 }, - { 333 }, - { 333 }, - { 500 }, - { 675 }, - { 250 }, - { 333 }, - { 250 }, - { 278 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 333 }, - { 333 }, - { 675 }, - { 675 }, - { 675 }, - { 500 }, - { 920 }, - { 611 }, - { 611 }, - { 667 }, - { 722 }, - { 611 }, - { 611 }, - { 722 }, - { 722 }, - { 333 }, - { 444 }, - { 667 }, - { 556 }, - { 833 }, - { 667 }, - { 722 }, - { 611 }, - { 722 }, - { 611 }, - { 500 }, - { 556 }, - { 722 }, - { 611 }, - { 833 }, - { 611 }, - { 556 }, - { 556 }, - { 389 }, - { 278 }, - { 389 }, - { 422 }, - { 500 }, - { 333 }, - { 500 }, - { 500 }, - { 444 }, - { 500 }, - { 444 }, - { 278 }, - { 500 }, - { 500 }, - { 278 }, - { 278 }, - { 444 }, - { 278 }, - { 722 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 389 }, - { 389 }, - { 278 }, - { 500 }, - { 444 }, - { 667 }, - { 444 }, - { 444 }, - { 389 }, - { 400 }, - { 275 }, - { 400 }, - { 541 }, - } }, - { "Times-BoldItalic", { - { 250 }, - { 389 }, - { 555 }, - { 500 }, - { 500 }, - { 833 }, - { 778 }, - { 333 }, - { 333 }, - { 333 }, - { 500 }, - { 570 }, - { 250 }, - { 333 }, - { 250 }, - { 278 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 500 }, - { 333 }, - { 333 }, - { 570 }, - { 570 }, - { 570 }, - { 500 }, - { 832 }, - { 667 }, - { 667 }, - { 667 }, - { 722 }, - { 667 }, - { 667 }, - { 722 }, - { 778 }, - { 389 }, - { 500 }, - { 667 }, - { 611 }, - { 889 }, - { 722 }, - { 722 }, - { 611 }, - { 722 }, - { 667 }, - { 556 }, - { 611 }, - { 722 }, - { 667 }, - { 889 }, - { 667 }, - { 611 }, - { 611 }, - { 333 }, - { 278 }, - { 333 }, - { 570 }, - { 500 }, - { 333 }, - { 500 }, - { 500 }, - { 444 }, - { 500 }, - { 444 }, - { 333 }, - { 500 }, - { 556 }, - { 278 }, - { 278 }, - { 500 }, - { 278 }, - { 778 }, - { 556 }, - { 500 }, - { 500 }, - { 500 }, - { 389 }, - { 389 }, - { 278 }, - { 556 }, - { 444 }, - { 667 }, - { 500 }, - { 444 }, - { 389 }, - { 348 }, - { 220 }, - { 348 }, - { 570 }, - } }, -}; - -void * -pdf_alloc(const struct manoutput *outopts) -{ - struct termp *p; - - if (NULL != (p = pspdf_alloc(outopts))) - p->type = TERMTYPE_PDF; - - return p; -} - -void * -ps_alloc(const struct manoutput *outopts) -{ - struct termp *p; - - if (NULL != (p = pspdf_alloc(outopts))) - p->type = TERMTYPE_PS; - - return p; -} - -static struct termp * -pspdf_alloc(const struct manoutput *outopts) -{ - struct termp *p; - unsigned int pagex, pagey; - size_t marginx, marginy, lineheight; - const char *pp; - - p = mandoc_calloc(1, sizeof(*p)); - p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol)); - p->maxtcol = 1; - - p->enc = TERMENC_ASCII; - p->fontq = mandoc_reallocarray(NULL, - (p->fontsz = 8), sizeof(*p->fontq)); - p->fontq[0] = p->fontl = TERMFONT_NONE; - p->ps = mandoc_calloc(1, sizeof(*p->ps)); - - p->advance = ps_advance; - p->begin = ps_begin; - p->end = ps_end; - p->endline = ps_endline; - p->hspan = ps_hspan; - p->letter = ps_letter; - p->setwidth = ps_setwidth; - p->width = ps_width; - - /* Default to US letter (millimetres). */ - - pagex = 216; - pagey = 279; - - /* - * The ISO-269 paper sizes can be calculated automatically, but - * it would require bringing in -lm for pow() and I'd rather not - * do that. So just do it the easy way for now. Since this - * only happens once, I'm not terribly concerned. - */ - - pp = outopts->paper; - if (pp && strcasecmp(pp, "letter")) { - if (0 == strcasecmp(pp, "a3")) { - pagex = 297; - pagey = 420; - } else if (0 == strcasecmp(pp, "a4")) { - pagex = 210; - pagey = 297; - } else if (0 == strcasecmp(pp, "a5")) { - pagex = 148; - pagey = 210; - } else if (0 == strcasecmp(pp, "legal")) { - pagex = 216; - pagey = 356; - } else if (2 != sscanf(pp, "%ux%u", &pagex, &pagey)) - warnx("%s: Unknown paper", pp); - } - - /* - * This MUST be defined before any PNT2AFM or AFM2PNT - * calculations occur. - */ - - p->ps->scale = 11; - - /* Remember millimetres -> AFM units. */ - - pagex = PNT2AFM(p, ((double)pagex * 2.834)); - pagey = PNT2AFM(p, ((double)pagey * 2.834)); - - /* Margins are 1/9 the page x and y. */ - - marginx = (size_t)((double)pagex / 9.0); - marginy = (size_t)((double)pagey / 9.0); - - /* Line-height is 1.4em. */ - - lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4)); - - p->ps->width = p->ps->lastwidth = (size_t)pagex; - p->ps->height = (size_t)pagey; - p->ps->header = pagey - (marginy / 2) - (lineheight / 2); - p->ps->top = pagey - marginy; - p->ps->footer = (marginy / 2) - (lineheight / 2); - p->ps->bottom = marginy; - p->ps->left = marginx; - p->ps->lineheight = lineheight; - - p->defrmargin = pagex - (marginx * 2); - return p; -} - -static void -ps_setwidth(struct termp *p, int iop, int width) -{ - size_t lastwidth; - - lastwidth = p->ps->width; - if (iop > 0) - p->ps->width += width; - else if (iop == 0) - p->ps->width = width ? (size_t)width : p->ps->lastwidth; - else if (p->ps->width > (size_t)width) - p->ps->width -= width; - else - p->ps->width = 0; - p->ps->lastwidth = lastwidth; -} - -void -pspdf_free(void *arg) -{ - struct termp *p; - - p = (struct termp *)arg; - - free(p->ps->psmarg); - free(p->ps->pdfobjs); - - free(p->ps); - term_free(p); -} - -static void -ps_printf(struct termp *p, const char *fmt, ...) -{ - va_list ap; - int pos, len; - - va_start(ap, fmt); - - /* - * If we're running in regular mode, then pipe directly into - * vprintf(). If we're processing margins, then push the data - * into our growable margin buffer. - */ - - if ( ! (PS_MARGINS & p->ps->flags)) { - len = vprintf(fmt, ap); - va_end(ap); - p->ps->pdfbytes += len < 0 ? 0 : (size_t)len; - return; - } - - /* - * XXX: I assume that the in-margin print won't exceed - * PS_BUFSLOP (128 bytes), which is reasonable but still an - * assumption that will cause pukeage if it's not the case. - */ - - ps_growbuf(p, PS_BUFSLOP); - - pos = (int)p->ps->psmargcur; - vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap); - - va_end(ap); - - p->ps->psmargcur = strlen(p->ps->psmarg); -} - -static void -ps_putchar(struct termp *p, char c) -{ - int pos; - - /* See ps_printf(). */ - - if ( ! (PS_MARGINS & p->ps->flags)) { - putchar(c); - p->ps->pdfbytes++; - return; - } - - ps_growbuf(p, 2); - - pos = (int)p->ps->psmargcur++; - p->ps->psmarg[pos++] = c; - p->ps->psmarg[pos] = '\0'; -} - -static void -pdf_obj(struct termp *p, size_t obj) -{ - - assert(obj > 0); - - if ((obj - 1) >= p->ps->pdfobjsz) { - p->ps->pdfobjsz = obj + 128; - p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs, - p->ps->pdfobjsz, sizeof(size_t)); - } - - p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes; - ps_printf(p, "%zu 0 obj\n", obj); -} - -static void -ps_closepage(struct termp *p) -{ - int i; - size_t len, base; - - /* - * Close out a page that we've already flushed to output. In - * PostScript, we simply note that the page must be showed. In - * PDF, we must now create the Length, Resource, and Page node - * for the page contents. - */ - - assert(p->ps->psmarg && p->ps->psmarg[0]); - ps_printf(p, "%s", p->ps->psmarg); - - if (TERMTYPE_PS != p->type) { - ps_printf(p, "ET\n"); - - len = p->ps->pdfbytes - p->ps->pdflastpg; - base = p->ps->pages * 4 + p->ps->pdfbody; - - ps_printf(p, "endstream\nendobj\n"); - - /* Length of content. */ - pdf_obj(p, base + 1); - ps_printf(p, "%zu\nendobj\n", len); - - /* Resource for content. */ - pdf_obj(p, base + 2); - ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n"); - ps_printf(p, "/Font <<\n"); - for (i = 0; i < (int)TERMFONT__MAX; i++) - ps_printf(p, "/F%d %d 0 R\n", i, 3 + i); - ps_printf(p, ">>\n>>\n"); - - /* Page node. */ - pdf_obj(p, base + 3); - ps_printf(p, "<<\n"); - ps_printf(p, "/Type /Page\n"); - ps_printf(p, "/Parent 2 0 R\n"); - ps_printf(p, "/Resources %zu 0 R\n", base + 2); - ps_printf(p, "/Contents %zu 0 R\n", base); - ps_printf(p, ">>\nendobj\n"); - } else - ps_printf(p, "showpage\n"); - - p->ps->pages++; - p->ps->psrow = p->ps->top; - assert( ! (PS_NEWPAGE & p->ps->flags)); - p->ps->flags |= PS_NEWPAGE; -} - -static void -ps_end(struct termp *p) -{ - size_t i, xref, base; - - ps_plast(p); - ps_pclose(p); - - /* - * At the end of the file, do one last showpage. This is the - * same behaviour as groff(1) and works for multiple pages as - * well as just one. - */ - - if ( ! (PS_NEWPAGE & p->ps->flags)) { - assert(0 == p->ps->flags); - assert('\0' == p->ps->last); - ps_closepage(p); - } - - if (TERMTYPE_PS == p->type) { - ps_printf(p, "%%%%Trailer\n"); - ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages); - ps_printf(p, "%%%%EOF\n"); - return; - } - - pdf_obj(p, 2); - ps_printf(p, "<<\n/Type /Pages\n"); - ps_printf(p, "/MediaBox [0 0 %zu %zu]\n", - (size_t)AFM2PNT(p, p->ps->width), - (size_t)AFM2PNT(p, p->ps->height)); - - ps_printf(p, "/Count %zu\n", p->ps->pages); - ps_printf(p, "/Kids ["); - - for (i = 0; i < p->ps->pages; i++) - ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3); - - base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4; - - ps_printf(p, "]\n>>\nendobj\n"); - pdf_obj(p, base); - ps_printf(p, "<<\n"); - ps_printf(p, "/Type /Catalog\n"); - ps_printf(p, "/Pages 2 0 R\n"); - ps_printf(p, ">>\n"); - xref = p->ps->pdfbytes; - ps_printf(p, "xref\n"); - ps_printf(p, "0 %zu\n", base + 1); - ps_printf(p, "0000000000 65535 f \n"); - - for (i = 0; i < base; i++) - ps_printf(p, "%.10zu 00000 n \n", - p->ps->pdfobjs[(int)i]); - - ps_printf(p, "trailer\n"); - ps_printf(p, "<<\n"); - ps_printf(p, "/Size %zu\n", base + 1); - ps_printf(p, "/Root %zu 0 R\n", base); - ps_printf(p, "/Info 1 0 R\n"); - ps_printf(p, ">>\n"); - ps_printf(p, "startxref\n"); - ps_printf(p, "%zu\n", xref); - ps_printf(p, "%%%%EOF\n"); -} - -static void -ps_begin(struct termp *p) -{ - int i; - - /* - * Print margins into margin buffer. Nothing gets output to the - * screen yet, so we don't need to initialise the primary state. - */ - - if (p->ps->psmarg) { - assert(p->ps->psmargsz); - p->ps->psmarg[0] = '\0'; - } - - /*p->ps->pdfbytes = 0;*/ - p->ps->psmargcur = 0; - p->ps->flags = PS_MARGINS; - p->ps->pscol = p->ps->left; - p->ps->psrow = p->ps->header; - - ps_setfont(p, TERMFONT_NONE); - - (*p->headf)(p, p->argf); - (*p->endline)(p); - - p->ps->pscol = p->ps->left; - p->ps->psrow = p->ps->footer; - - (*p->footf)(p, p->argf); - (*p->endline)(p); - - p->ps->flags &= ~PS_MARGINS; - - assert(0 == p->ps->flags); - assert(p->ps->psmarg); - assert('\0' != p->ps->psmarg[0]); - - /* - * Print header and initialise page state. Following this, - * stuff gets printed to the screen, so make sure we're sane. - */ - - if (TERMTYPE_PS == p->type) { - ps_printf(p, "%%!PS-Adobe-3.0\n"); - ps_printf(p, "%%%%DocumentData: Clean7Bit\n"); - ps_printf(p, "%%%%Orientation: Portrait\n"); - ps_printf(p, "%%%%Pages: (atend)\n"); - ps_printf(p, "%%%%PageOrder: Ascend\n"); - ps_printf(p, "%%%%DocumentMedia: " - "Default %zu %zu 0 () ()\n", - (size_t)AFM2PNT(p, p->ps->width), - (size_t)AFM2PNT(p, p->ps->height)); - ps_printf(p, "%%%%DocumentNeededResources: font"); - - for (i = 0; i < (int)TERMFONT__MAX; i++) - ps_printf(p, " %s", fonts[i].name); - - ps_printf(p, "\n%%%%EndComments\n"); - } else { - ps_printf(p, "%%PDF-1.1\n"); - pdf_obj(p, 1); - ps_printf(p, "<<\n"); - ps_printf(p, ">>\n"); - ps_printf(p, "endobj\n"); - - for (i = 0; i < (int)TERMFONT__MAX; i++) { - pdf_obj(p, (size_t)i + 3); - ps_printf(p, "<<\n"); - ps_printf(p, "/Type /Font\n"); - ps_printf(p, "/Subtype /Type1\n"); - ps_printf(p, "/Name /F%d\n", i); - ps_printf(p, "/BaseFont /%s\n", fonts[i].name); - ps_printf(p, ">>\n"); - } - } - - p->ps->pdfbody = (size_t)TERMFONT__MAX + 3; - p->ps->pscol = p->ps->left; - p->ps->psrow = p->ps->top; - p->ps->flags |= PS_NEWPAGE; - ps_setfont(p, TERMFONT_NONE); -} - -static void -ps_pletter(struct termp *p, int c) -{ - int f; - - /* - * If we haven't opened a page context, then output that we're - * in a new page and make sure the font is correctly set. - */ - - if (PS_NEWPAGE & p->ps->flags) { - if (TERMTYPE_PS == p->type) { - ps_printf(p, "%%%%Page: %zu %zu\n", - p->ps->pages + 1, p->ps->pages + 1); - ps_printf(p, "/%s %zu selectfont\n", - fonts[(int)p->ps->lastf].name, - p->ps->scale); - } else { - pdf_obj(p, p->ps->pdfbody + - p->ps->pages * 4); - ps_printf(p, "<<\n"); - ps_printf(p, "/Length %zu 0 R\n", - p->ps->pdfbody + 1 + p->ps->pages * 4); - ps_printf(p, ">>\nstream\n"); - } - p->ps->pdflastpg = p->ps->pdfbytes; - p->ps->flags &= ~PS_NEWPAGE; - } - - /* - * If we're not in a PostScript "word" context, then open one - * now at the current cursor. - */ - - if ( ! (PS_INLINE & p->ps->flags)) { - if (TERMTYPE_PS != p->type) { - ps_printf(p, "BT\n/F%d %zu Tf\n", - (int)p->ps->lastf, p->ps->scale); - ps_printf(p, "%.3f %.3f Td\n(", - AFM2PNT(p, p->ps->pscol), - AFM2PNT(p, p->ps->psrow)); - } else - ps_printf(p, "%.3f %.3f moveto\n(", - AFM2PNT(p, p->ps->pscol), - AFM2PNT(p, p->ps->psrow)); - p->ps->flags |= PS_INLINE; - } - - assert( ! (PS_NEWPAGE & p->ps->flags)); - - /* - * We need to escape these characters as per the PostScript - * specification. We would also escape non-graphable characters - * (like tabs), but none of them would get to this point and - * it's superfluous to abort() on them. - */ - - switch (c) { - case '(': - case ')': - case '\\': - ps_putchar(p, '\\'); - break; - default: - break; - } - - /* Write the character and adjust where we are on the page. */ - - f = (int)p->ps->lastf; - - if (c <= 32 || c - 32 >= MAXCHAR) - c = 32; - - ps_putchar(p, (char)c); - c -= 32; - p->ps->pscol += (size_t)fonts[f].gly[c].wx; -} - -static void -ps_pclose(struct termp *p) -{ - - /* - * Spit out that we're exiting a word context (this is a - * "partial close" because we don't check the last-char buffer - * or anything). - */ - - if ( ! (PS_INLINE & p->ps->flags)) - return; - - if (TERMTYPE_PS != p->type) { - ps_printf(p, ") Tj\nET\n"); - } else - ps_printf(p, ") show\n"); - - p->ps->flags &= ~PS_INLINE; -} - -/* If we have a `last' char that wasn't printed yet, print it now. */ -static void -ps_plast(struct termp *p) -{ - size_t wx; - - if (p->ps->last == '\0') - return; - - /* Check the font mode; open a new scope if it doesn't match. */ - - if (p->ps->nextf != p->ps->lastf) { - ps_pclose(p); - ps_setfont(p, p->ps->nextf); - } - p->ps->nextf = TERMFONT_NONE; - - /* - * For an overstrike, if a previous character - * was wider, advance to center the new one. - */ - - if (p->ps->pscolnext) { - wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx; - if (p->ps->pscol + wx < p->ps->pscolnext) - p->ps->pscol = (p->ps->pscol + - p->ps->pscolnext - wx) / 2; - } - - ps_pletter(p, p->ps->last); - p->ps->last = '\0'; - - /* - * For an overstrike, if a previous character - * was wider, advance to the end of the old one. - */ - - if (p->ps->pscol < p->ps->pscolnext) { - ps_pclose(p); - p->ps->pscol = p->ps->pscolnext; - } -} - -static void -ps_letter(struct termp *p, int arg) -{ - size_t savecol; - char c; - - c = arg >= 128 || arg <= 0 ? '?' : arg; - - /* - * When receiving a backspace, merely flag it. - * We don't know yet whether it is - * a font instruction or an overstrike. - */ - - if (c == '\b') { - assert(p->ps->last != '\0'); - assert( ! (p->ps->flags & PS_BACKSP)); - p->ps->flags |= PS_BACKSP; - return; - } - - /* - * Decode font instructions. - */ - - if (p->ps->flags & PS_BACKSP) { - if (p->ps->last == '_') { - switch (p->ps->nextf) { - case TERMFONT_BI: - break; - case TERMFONT_BOLD: - p->ps->nextf = TERMFONT_BI; - break; - default: - p->ps->nextf = TERMFONT_UNDER; - } - p->ps->last = c; - p->ps->flags &= ~PS_BACKSP; - return; - } - if (p->ps->last == c) { - switch (p->ps->nextf) { - case TERMFONT_BI: - break; - case TERMFONT_UNDER: - p->ps->nextf = TERMFONT_BI; - break; - default: - p->ps->nextf = TERMFONT_BOLD; - } - p->ps->flags &= ~PS_BACKSP; - return; - } - - /* - * This is not a font instruction, but rather - * the next character. Prepare for overstrike. - */ - - savecol = p->ps->pscol; - } else - savecol = SIZE_MAX; - - /* - * We found the next character, so the font instructions - * for the previous one are complete. - * Use them and print it. - */ - - ps_plast(p); - - /* - * Do not print the current character yet because font - * instructions might follow; only remember the character. - * It will get printed later from ps_plast(). - */ - - p->ps->last = c; - - /* - * For an overstrike, back up to the previous position. - * If the previous character is wider than any it overstrikes, - * remember the current position, because it might also be - * wider than all that will overstrike it. - */ - - if (savecol != SIZE_MAX) { - if (p->ps->pscolnext < p->ps->pscol) - p->ps->pscolnext = p->ps->pscol; - ps_pclose(p); - p->ps->pscol = savecol; - p->ps->flags &= ~PS_BACKSP; - } else - p->ps->pscolnext = 0; -} - -static void -ps_advance(struct termp *p, size_t len) -{ - - /* - * Advance some spaces. This can probably be made smarter, - * i.e., to have multiple space-separated words in the same - * scope, but this is easier: just close out the current scope - * and readjust our column settings. - */ - - ps_plast(p); - ps_pclose(p); - p->ps->pscol += len; -} - -static void -ps_endline(struct termp *p) -{ - - /* Close out any scopes we have open: we're at eoln. */ - - ps_plast(p); - ps_pclose(p); - - /* - * If we're in the margin, don't try to recalculate our current - * row. XXX: if the column tries to be fancy with multiple - * lines, we'll do nasty stuff. - */ - - if (PS_MARGINS & p->ps->flags) - return; - - /* Left-justify. */ - - p->ps->pscol = p->ps->left; - - /* If we haven't printed anything, return. */ - - if (PS_NEWPAGE & p->ps->flags) - return; - - /* - * Put us down a line. If we're at the page bottom, spit out a - * showpage and restart our row. - */ - - if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) { - p->ps->psrow -= p->ps->lineheight; - return; - } - - ps_closepage(p); - - p->tcol->offset -= p->ti; - p->ti = 0; -} - -static void -ps_setfont(struct termp *p, enum termfont f) -{ - - assert(f < TERMFONT__MAX); - p->ps->lastf = f; - - /* - * If we're still at the top of the page, let the font-setting - * be delayed until we actually have stuff to print. - */ - - if (PS_NEWPAGE & p->ps->flags) - return; - - if (TERMTYPE_PS == p->type) - ps_printf(p, "/%s %zu selectfont\n", - fonts[(int)f].name, p->ps->scale); - else - ps_printf(p, "/F%d %zu Tf\n", - (int)f, p->ps->scale); -} - -static size_t -ps_width(const struct termp *p, int c) -{ - - if (c <= 32 || c - 32 >= MAXCHAR) - c = 0; - else - c -= 32; - - return (size_t)fonts[(int)TERMFONT_NONE].gly[c].wx; -} - -static int -ps_hspan(const struct termp *p, const struct roffsu *su) -{ - double r; - - /* - * All of these measurements are derived by converting from the - * native measurement to AFM units. - */ - switch (su->unit) { - case SCALE_BU: - /* - * Traditionally, the default unit is fixed to the - * output media. So this would refer to the point. In - * mandoc(1), however, we stick to the default terminal - * scaling unit so that output is the same regardless - * the media. - */ - r = PNT2AFM(p, su->scale * 72.0 / 240.0); - break; - case SCALE_CM: - r = PNT2AFM(p, su->scale * 72.0 / 2.54); - break; - case SCALE_EM: - r = su->scale * - fonts[(int)TERMFONT_NONE].gly[109 - 32].wx; - break; - case SCALE_EN: - r = su->scale * - fonts[(int)TERMFONT_NONE].gly[110 - 32].wx; - break; - case SCALE_IN: - r = PNT2AFM(p, su->scale * 72.0); - break; - case SCALE_MM: - r = su->scale * - fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0; - break; - case SCALE_PC: - r = PNT2AFM(p, su->scale * 12.0); - break; - case SCALE_PT: - r = PNT2AFM(p, su->scale * 1.0); - break; - case SCALE_VS: - r = su->scale * p->ps->lineheight; - break; - default: - r = su->scale; - break; - } - - return r * 24.0; -} - -static void -ps_growbuf(struct termp *p, size_t sz) -{ - if (p->ps->psmargcur + sz <= p->ps->psmargsz) - return; - - if (sz < PS_BUFSLOP) - sz = PS_BUFSLOP; - - p->ps->psmargsz += sz; - p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz); -} Property changes on: head/contrib/mdocml/term_ps.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mdoc.7 =================================================================== --- head/contrib/mdocml/mdoc.7 (revision 338825) +++ head/contrib/mdocml/mdoc.7 (nonexistent) @@ -1,3231 +0,0 @@ -.\" $Id: mdoc.7,v 1.269 2017/07/20 16:24:53 schwarze Exp $ -.\" -.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons -.\" Copyright (c) 2010, 2011, 2013-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: December 5 2017 $ -.Dt MDOC 7 -.Os -.Sh NAME -.Nm mdoc -.Nd semantic markup language for formatting manual pages -.Sh DESCRIPTION -The -.Nm mdoc -language supports authoring of manual pages for the -.Xr man 1 -utility by allowing semantic annotations of words, phrases, -page sections and complete manual pages. -Such annotations are used by formatting tools to achieve a uniform -presentation across all manuals written in -.Nm , -and to support hyperlinking if supported by the output medium. -.Pp -This reference document describes the structure of manual pages -and the syntax and usage of the -.Nm -language. -The reference implementation of a parsing and formatting tool is -.Xr mandoc 1 ; -the -.Sx COMPATIBILITY -section describes compatibility with other implementations. -.Pp -In an -.Nm -document, lines beginning with the control character -.Sq \&. -are called -.Dq macro lines . -The first word is the macro name. -It consists of two or three letters. -Most macro names begin with a capital letter. -For a list of available macros, see -.Sx MACRO OVERVIEW . -The words following the macro name are arguments to the macro, optionally -including the names of other, callable macros; see -.Sx MACRO SYNTAX -for details. -.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. -However, using -.Xr roff 7 -requests in -.Nm -documents is discouraged; -.Xr mandoc 1 -supports some of them merely for backward compatibility. -.Sh MANUAL STRUCTURE -A well-formed -.Nm -document consists of a document prologue followed by one or more -sections. -.Pp -The prologue, which consists of the -.Sx \&Dd , -.Sx \&Dt , -and -.Sx \&Os -macros in that order, is required for every document. -.Pp -The first section (sections are denoted by -.Sx \&Sh ) -must be the NAME section, consisting of at least one -.Sx \&Nm -followed by -.Sx \&Nd . -.Pp -Following that, convention dictates specifying at least the -.Em SYNOPSIS -and -.Em DESCRIPTION -sections, although this varies between manual sections. -.Pp -The following is a well-formed skeleton -.Nm -file for a utility -.Qq progname : -.Bd -literal -offset indent -\&.Dd $\&Mdocdate$ -\&.Dt PROGNAME section -\&.Os -\&.Sh NAME -\&.Nm progname -\&.Nd 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 -\&.Nm progname -\&.Op Fl options -\&.Ar -\&.Sh DESCRIPTION -The -\&.Nm -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 .Xr 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 an -.Nm -document are conventionally ordered as they appear above. -Sections should be composed as follows: -.Bl -ohang -offset Ds -.It Em NAME -The name(s) and a one line description of the documented material. -The syntax for this as follows: -.Bd -literal -offset indent -\&.Nm name0 , -\&.Nm name1 , -\&.Nm name2 -\&.Nd a one line description -.Ed -.Pp -Multiple -.Sq \&Nm -names should be separated by commas. -.Pp -The -.Sx \&Nm -macro(s) must precede the -.Sx \&Nd -macro. -.Pp -See -.Sx \&Nm -and -.Sx \&Nd . -.It Em LIBRARY -The name of the library containing the documented material, which is -assumed to be a function in a section 2, 3, or 9 manual. -The syntax for this is as follows: -.Bd -literal -offset indent -\&.Lb libarm -.Ed -.Pp -See -.Sx \&Lb . -.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: -.Bd -literal -offset indent -\&.Nm bar -\&.Op Fl v -\&.Op Fl o Ar file -\&.Op Ar -\&.Nm foo -\&.Op Fl v -\&.Op Fl o Ar file -\&.Op Ar -.Ed -.Pp -Commands should be ordered alphabetically. -.Pp -For the second, function calls (sections 2, 3, 9): -.Bd -literal -offset indent -\&.In header.h -\&.Vt extern const char *global; -\&.Ft "char *" -\&.Fn foo "const char *src" -\&.Ft "char *" -\&.Fn bar "const char *src" -.Ed -.Pp -Ordering of -.Sx \&In , -.Sx \&Vt , -.Sx \&Fn , -and -.Sx \&Fo -macros should follow C header-file conventions. -.Pp -And for the third, configurations (section 4): -.Bd -literal -offset indent -\&.Cd \(dqit* at isa? port 0x2e\(dq -\&.Cd \(dqit* at isa? port 0x4e\(dq -.Ed -.Pp -Manuals not in these sections generally don't need a -.Em SYNOPSIS . -.Pp -Some macros are displayed differently in the -.Em SYNOPSIS -section, particularly -.Sx \&Nm , -.Sx \&Cd , -.Sx \&Fd , -.Sx \&Fn , -.Sx \&Fo , -.Sx \&In , -.Sx \&Vt , -and -.Sx \&Ft . -All of these macros are output on their own line. -If two such dissimilar macros are pairwise invoked (except for -.Sx \&Ft -before -.Sx \&Fo -or -.Sx \&Fn ) , -they are separated by a vertical space, unless in the case of -.Sx \&Fo , -.Sx \&Fn , -and -.Sx \&Ft , -which are always separated by vertical space. -.Pp -When text and macros following an -.Sx \&Nm -macro starting an input line span multiple output lines, -all output lines but the first will be indented to align -with the text immediately following the -.Sx \&Nm -macro, up to the next -.Sx \&Nm , -.Sx \&Sh , -or -.Sx \&Ss -macro or the end of an enclosing block, whichever comes first. -.It Em DESCRIPTION -This begins with an expansion of the brief, one line description in -.Em NAME : -.Bd -literal -offset indent -The -\&.Nm -utility does this, that, and the other. -.Ed -.Pp -It usually follows with a breakdown of the options (if documenting a -command), such as: -.Bd -literal -offset indent -The arguments are as follows: -\&.Bl \-tag \-width Ds -\&.It Fl v -Print verbose information. -\&.El -.Ed -.Pp -List the options in alphabetical order, -uppercase before lowercase for each letter and -with no regard to whether an option takes an argument. -Put digits in ascending order before all letter options. -.Pp -Manuals not documenting a command won't include the above fragment. -.Pp -Since the -.Em DESCRIPTION -section usually contains most of the text of a manual, longer manuals -often use the -.Sx \&Ss -macro to form subsections. -In very long manuals, the -.Em DESCRIPTION -may be split into multiple sections, each started by an -.Sx \&Sh -macro followed by a non-standard section name, and each having -several subsections, like in the present -.Nm -manual. -.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. -.Pp -See -.Sx \&Rv . -.It Em ENVIRONMENT -Lists the environment variables used by the utility, -and explains the syntax and semantics of their values. -The -.Xr environ 7 -manual provides examples of typical content and formatting. -.Pp -See -.Sx \&Ev . -.It Em FILES -Documents files used. -It's helpful to document both the file name and a short description of how -the file is used (created, modified, etc.). -.Pp -See -.Sx \&Pa . -.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. -.Pp -See -.Sx \&Ex . -.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 messages. -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. -.Pp -See -.Sx \&Bl -.Fl diag . -.It Em ERRORS -Documents -.Xr errno 2 -settings in sections 2, 3, 4, and 9. -.Pp -See -.Sx \&Er . -.It Em SEE ALSO -References other manuals with related topics. -This section should exist for most manuals. -Cross-references should conventionally be ordered first by section, then -alphabetically (ignoring case). -.Pp -References to other documentation concerning the topic of the manual page, -for example authoritative books or journal articles, may also be -provided in this section. -.Pp -See -.Sx \&Rs -and -.Sx \&Xr . -.It Em STANDARDS -References any standards implemented or used. -If not adhering to any standards, the -.Em HISTORY -section should be used instead. -.Pp -See -.Sx \&St . -.It Em HISTORY -A brief history of the subject, including where it was first implemented, -and when it was ported to or reimplemented for the operating system at hand. -.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. -.Pp -See -.Sx \&An . -.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 below -in the alphabetical -.Sx MACRO REFERENCE . -.Ss Document preamble and NAME section macros -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Dd Ta document date: Cm $\&Mdocdate$ | Ar month day , year -.It Sx \&Dt Ta document title: Ar TITLE section Op Ar arch -.It Sx \&Os Ta operating system version: Op Ar system Op Ar version -.It Sx \&Nm Ta document name (one argument) -.It Sx \&Nd Ta document description (one line) -.El -.Ss Sections and cross references -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Sh Ta section header (one line) -.It Sx \&Ss Ta subsection header (one line) -.It Sx \&Sx Ta internal cross reference to a section or subsection -.It Sx \&Xr Ta cross reference to another manual page: Ar name section -.It Sx \&Pp , \&Lp Ta start a text paragraph (no arguments) -.El -.Ss Displays and lists -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Bd , \&Ed Ta display block: -.Fl Ar type -.Op Fl offset Ar width -.Op Fl compact -.It Sx \&D1 Ta indented display (one line) -.It Sx \&Dl Ta indented literal display (one line) -.It Sx \&Ql Ta in-line literal display: Ql text -.It Sx \&Bl , \&El Ta list block: -.Fl Ar type -.Op Fl width Ar val -.Op Fl offset Ar val -.Op Fl compact -.It Sx \&It Ta list item (syntax depends on Fl Ar type ) -.It Sx \&Ta Ta table cell separator in Sx \&Bl Fl column No lists -.It Sx \&Rs , \&%* , \&Re Ta bibliographic block (references) -.El -.Ss Spacing control -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Pf Ta prefix, no following horizontal space (one argument) -.It Sx \&Ns Ta roman font, no preceding horizontal space (no arguments) -.It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments) -.It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off -.It Sx \&Bk , \&Ek Ta keep block: Fl words -.El -.Ss Semantic markup for command line utilities -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Nm Ta start a SYNOPSIS block with the name of a utility -.It Sx \&Fl Ta command line options (flags) (>=0 arguments) -.It Sx \&Cm Ta command modifier (>0 arguments) -.It Sx \&Ar Ta command arguments (>=0 arguments) -.It Sx \&Op , \&Oo , \&Oc Ta optional syntax elements (enclosure) -.It Sx \&Ic Ta internal or interactive command (>0 arguments) -.It Sx \&Ev Ta environmental variable (>0 arguments) -.It Sx \&Pa Ta file system path (>=0 arguments) -.El -.Ss Semantic markup for function libraries -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Lb Ta function library (one argument) -.It Sx \&In Ta include file (one argument) -.It Sx \&Fd Ta other preprocessor directive (>0 arguments) -.It Sx \&Ft Ta function type (>0 arguments) -.It Sx \&Fo , \&Fc Ta function block: Ar funcname -.It Sx \&Fn Ta function name: -.Op Ar functype -.Ar funcname -.Oo -.Op Ar argtype -.Ar argname -.Oc -.It Sx \&Fa Ta function argument (>0 arguments) -.It Sx \&Vt Ta variable type (>0 arguments) -.It Sx \&Va Ta variable name (>0 arguments) -.It Sx \&Dv Ta defined variable or preprocessor constant (>0 arguments) -.It Sx \&Er Ta error constant (>0 arguments) -.It Sx \&Ev Ta environmental variable (>0 arguments) -.El -.Ss Various semantic markup -.Bl -column "Brq, Bro, Brc" description -.It Sx \&An Ta author name (>0 arguments) -.It Sx \&Lk Ta hyperlink: Ar uri Op Ar name -.It Sx \&Mt Ta Do mailto Dc hyperlink: Ar address -.It Sx \&Cd Ta kernel configuration declaration (>0 arguments) -.It Sx \&Ad Ta memory address (>0 arguments) -.It Sx \&Ms Ta mathematical symbol (>0 arguments) -.El -.Ss Physical markup -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Em Ta italic font or underline (emphasis) (>0 arguments) -.It Sx \&Sy Ta boldface font (symbolic) (>0 arguments) -.It Sx \&Li Ta typewriter font (literal) (>0 arguments) -.It Sx \&No Ta return to roman font (normal) (no arguments) -.It Sx \&Bf , \&Ef Ta font block: -.Op Fl Ar type | Cm \&Em | \&Li | \&Sy -.El -.Ss Physical enclosures -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Dq , \&Do , \&Dc Ta enclose in typographic double quotes: Dq text -.It Sx \&Qq , \&Qo , \&Qc Ta enclose in typewriter double quotes: Qq text -.It Sx \&Sq , \&So , \&Sc Ta enclose in single quotes: Sq text -.It Sx \&Pq , \&Po , \&Pc Ta enclose in parentheses: Pq text -.It Sx \&Bq , \&Bo , \&Bc Ta enclose in square brackets: Bq text -.It Sx \&Brq , \&Bro , \&Brc Ta enclose in curly braces: Brq text -.It Sx \&Aq , \&Ao , \&Ac Ta enclose in angle brackets: Aq text -.It Sx \&Eo , \&Ec Ta generic enclosure -.El -.Ss Text production -.Bl -column "Brq, Bro, Brc" description -.It Sx \&Ex Fl std Ta standard command exit values: Op Ar utility ... -.It Sx \&Rv Fl std Ta standard function return values: Op Ar function ... -.It Sx \&St Ta reference to a standards document (one argument) -.It Sx \&At Ta At -.It Sx \&Bx Ta Bx -.It Sx \&Bsx Ta Bsx -.It Sx \&Nx Ta Nx -.It Sx \&Fx Ta Fx -.It Sx \&Ox Ta Ox -.It Sx \&Dx Ta Dx -.El -.Sh MACRO REFERENCE -This section is a canonical reference of all macros, arranged -alphabetically. -For the scoping of individual macros, see -.Sx MACRO SYNTAX . -.Ss \&%A -Author name of an -.Sx \&Rs -block. -Multiple authors should each be accorded their own -.Sx \%%A -line. -Author names should be ordered with full or abbreviated forename(s) -first, then full surname. -.Ss \&%B -Book title of an -.Sx \&Rs -block. -This macro may also be used in a non-bibliographic context when -referring to book titles. -.Ss \&%C -Publication city or location of an -.Sx \&Rs -block. -.Ss \&%D -Publication date of an -.Sx \&Rs -block. -Recommended formats of arguments are -.Ar month day , year -or just -.Ar year . -.Ss \&%I -Publisher or issuer name of an -.Sx \&Rs -block. -.Ss \&%J -Journal name of an -.Sx \&Rs -block. -.Ss \&%N -Issue number (usually for journals) of an -.Sx \&Rs -block. -.Ss \&%O -Optional information of an -.Sx \&Rs -block. -.Ss \&%P -Book or journal page number of an -.Sx \&Rs -block. -.Ss \&%Q -Institutional author (school, government, etc.) of an -.Sx \&Rs -block. -Multiple institutional authors should each be accorded their own -.Sx \&%Q -line. -.Ss \&%R -Technical report name of an -.Sx \&Rs -block. -.Ss \&%T -Article title of an -.Sx \&Rs -block. -This macro may also be used in a non-bibliographical context when -referring to article titles. -.Ss \&%U -URI of reference document. -.Ss \&%V -Volume number of an -.Sx \&Rs -block. -.Ss \&Ac -Close an -.Sx \&Ao -block. -Does not have any tail arguments. -.Ss \&Ad -Memory address. -Do not use this for postal addresses. -.Pp -Examples: -.Dl \&.Ad [0,$] -.Dl \&.Ad 0x00000000 -.Ss \&An -Author name. -Can be used both for the authors of the program, function, or driver -documented in the manual, or for the authors of the manual itself. -Requires either the name of an author or one of the following arguments: -.Pp -.Bl -tag -width "-nosplitX" -offset indent -compact -.It Fl split -Start a new output line before each subsequent invocation of -.Sx \&An . -.It Fl nosplit -The opposite of -.Fl split . -.El -.Pp -The default is -.Fl nosplit . -The effect of selecting either of the -.Fl split -modes ends at the beginning of the -.Em AUTHORS -section. -In the -.Em AUTHORS -section, the default is -.Fl nosplit -for the first author listing and -.Fl split -for all other author listings. -.Pp -Examples: -.Dl \&.An -nosplit -.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv -.Ss \&Ao -Begin a block enclosed by angle brackets. -Does not have any head arguments. -.Pp -Examples: -.Dl \&.Fl -key= \&Ns \&Ao \&Ar val \&Ac -.Pp -See also -.Sx \&Aq . -.Ss \&Ap -Inserts an apostrophe without any surrounding whitespace. -This is generally used as a grammatical device when referring to the verb -form of a function. -.Pp -Examples: -.Dl \&.Fn execve \&Ap d -.Ss \&Aq -Encloses its arguments in angle brackets. -.Pp -Examples: -.Dl \&.Fl -key= \&Ns \&Aq \&Ar val -.Pp -.Em Remarks : -this macro is often abused for rendering URIs, which should instead use -.Sx \&Lk -or -.Sx \&Mt , -or to note pre-processor -.Dq Li #include -statements, which should use -.Sx \&In . -.Pp -See also -.Sx \&Ao . -.Ss \&Ar -Command arguments. -If an argument is not provided, the string -.Dq file ...\& -is used as a default. -.Pp -Examples: -.Dl ".Fl o Ar file" -.Dl ".Ar" -.Dl ".Ar arg1 , arg2 ." -.Pp -The arguments to the -.Sx \&Ar -macro are names and placeholders for command arguments; -for fixed strings to be passed verbatim as arguments, use -.Sx \&Fl -or -.Sx \&Cm . -.Ss \&At -Formats an -.At -version. -Accepts one optional argument: -.Pp -.Bl -tag -width "v[1-7] | 32vX" -offset indent -compact -.It Cm v[1-7] | 32v -A version of -.At . -.It Cm III -.At III . -.It Cm V | V.[1-4] -A version of -.At V . -.El -.Pp -Note that these arguments do not begin with a hyphen. -.Pp -Examples: -.Dl \&.At -.Dl \&.At III -.Dl \&.At V.1 -.Pp -See also -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Fx , -.Sx \&Nx , -and -.Sx \&Ox . -.Ss \&Bc -Close a -.Sx \&Bo -block. -Does not have any tail arguments. -.Ss \&Bd -Begin a display block. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Bd -.Fl Ns Ar type -.Op Fl offset Ar width -.Op Fl compact -.Ed -.Pp -Display blocks are used to select a different indentation and -justification than the one used by the surrounding text. -They may contain both macro lines and text lines. -By default, a display block is preceded by a vertical space. -.Pp -The -.Ar type -must be one of the following: -.Bl -tag -width 13n -offset indent -.It Fl centered -Produce one output line from each input line, and center-justify each line. -Using this display type is not recommended; many -.Nm -implementations render it poorly. -.It Fl filled -Change the positions of line breaks to fill each line, and left- and -right-justify the resulting block. -.It Fl literal -Produce one output line from each input line, -and do not justify the block at all. -Preserve white space as it appears in the input. -Always use a constant-width font. -Use this for displaying source code. -.It Fl ragged -Change the positions of line breaks to fill each line, and left-justify -the resulting block. -.It Fl unfilled -The same as -.Fl literal , -but using the same font as for normal text, which is a variable width font -if supported by the output device. -.El -.Pp -The -.Ar type -must be provided first. -Additional arguments may follow: -.Bl -tag -width 13n -offset indent -.It Fl offset Ar width -Indent the display by the -.Ar width , -which may be one of the following: -.Bl -item -.It -One of the pre-defined strings -.Cm indent , -the width of a standard indentation (six constant width characters); -.Cm indent-two , -twice -.Cm indent ; -.Cm left , -which has no effect; -.Cm right , -which justifies to the right margin; or -.Cm center , -which aligns around an imagined center axis. -.It -A macro invocation, which selects a predefined width -associated with that macro. -The most popular is the imaginary macro -.Ar \&Ds , -which resolves to -.Sy 6n . -.It -A scaling width as described in -.Xr roff 7 . -.It -An arbitrary string, which indents by the length of this string. -.El -.Pp -When the argument is missing, -.Fl offset -is ignored. -.It Fl compact -Do not assert vertical space before the display. -.El -.Pp -Examples: -.Bd -literal -offset indent -\&.Bd \-literal \-offset indent \-compact - Hello world. -\&.Ed -.Ed -.Pp -See also -.Sx \&D1 -and -.Sx \&Dl . -.Ss \&Bf -Change the font mode for a scoped block of text. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Bf -.Oo -.Fl emphasis | literal | symbolic | -.Cm \&Em | \&Li | \&Sy -.Oc -.Ed -.Pp -The -.Fl emphasis -and -.Cm \&Em -argument are equivalent, as are -.Fl symbolic -and -.Cm \&Sy , -and -.Fl literal -and -.Cm \&Li . -Without an argument, this macro does nothing. -The font mode continues until broken by a new font mode in a nested -scope or -.Sx \&Ef -is encountered. -.Pp -See also -.Sx \&Li , -.Sx \&Ef , -.Sx \&Em , -and -.Sx \&Sy . -.Ss \&Bk -For each macro, keep its output together on the same output line, -until the end of the macro or the end of the input line is reached, -whichever comes first. -Line breaks in text lines are unaffected. -The syntax is as follows: -.Pp -.D1 Pf \. Sx \&Bk Fl words -.Pp -The -.Fl words -argument is required; additional arguments are ignored. -.Pp -The following example will not break within each -.Sx \&Op -macro line: -.Bd -literal -offset indent -\&.Bk \-words -\&.Op Fl f Ar flags -\&.Op Fl o Ar output -\&.Ek -.Ed -.Pp -Be careful in using over-long lines within a keep block! -Doing so will clobber the right margin. -.Ss \&Bl -Begin a list. -Lists consist of items specified using the -.Sx \&It -macro, containing a head or a body or both. -The list syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Bl -.Fl Ns Ar type -.Op Fl width Ar val -.Op Fl offset Ar val -.Op Fl compact -.Op HEAD ... -.Ed -.Pp -The list -.Ar type -is mandatory and must be specified first. -The -.Fl width -and -.Fl offset -arguments accept macro names as described for -.Sx \&Bd -.Fl offset , -scaling widths as described in -.Xr roff 7 , -or use the length of the given string. -The -.Fl offset -is a global indentation for the whole list, affecting both item heads -and bodies. -For those list types supporting it, the -.Fl width -argument requests an additional indentation of item bodies, -to be added to the -.Fl offset . -Unless the -.Fl compact -argument is specified, list entries are separated by vertical space. -.Pp -A list must specify one of the following list types: -.Bl -tag -width 12n -offset indent -.It Fl bullet -No item heads can be specified, but a bullet will be printed at the head -of each item. -Item bodies start on the same output line as the bullet -and are indented according to the -.Fl width -argument. -.It Fl column -A columnated list. -The -.Fl width -argument has no effect; instead, the string length of each argument -specifies the width of one column. -If the first line of the body of a -.Fl column -list is not an -.Sx \&It -macro line, -.Sx \&It -contexts spanning one input line each are implied until an -.Sx \&It -macro line is encountered, at which point items start being interpreted as -described in the -.Sx \&It -documentation. -.It Fl dash -Like -.Fl bullet , -except that dashes are used in place of bullets. -.It Fl diag -Like -.Fl inset , -except that item heads are not parsed for macro invocations. -Most often used in the -.Em DIAGNOSTICS -section with error constants in the item heads. -.It Fl enum -A numbered list. -No item heads can be specified. -Formatted like -.Fl bullet , -except that cardinal numbers are used in place of bullets, -starting at 1. -.It Fl hang -Like -.Fl tag , -except that the first lines of item bodies are not indented, but follow -the item heads like in -.Fl inset -lists. -.It Fl hyphen -Synonym for -.Fl dash . -.It Fl inset -Item bodies follow items heads on the same line, using normal inter-word -spacing. -Bodies are not indented, and the -.Fl width -argument is ignored. -.It Fl item -No item heads can be specified, and none are printed. -Bodies are not indented, and the -.Fl width -argument is ignored. -.It Fl ohang -Item bodies start on the line following item heads and are not indented. -The -.Fl width -argument is ignored. -.It Fl tag -Item bodies are indented according to the -.Fl width -argument. -When an item head fits inside the indentation, the item body follows -this head on the same output line. -Otherwise, the body starts on the output line following the head. -.El -.Pp -Lists may be nested within lists and displays. -Nesting of -.Fl column -and -.Fl enum -lists may not be portable. -.Pp -See also -.Sx \&El -and -.Sx \&It . -.Ss \&Bo -Begin a block enclosed by square brackets. -Does not have any head arguments. -.Pp -Examples: -.Bd -literal -offset indent -compact -\&.Bo 1 , -\&.Dv BUFSIZ \&Bc -.Ed -.Pp -See also -.Sx \&Bq . -.Ss \&Bq -Encloses its arguments in square brackets. -.Pp -Examples: -.Dl \&.Bq 1 , \&Dv BUFSIZ -.Pp -.Em Remarks : -this macro is sometimes abused to emulate optional arguments for -commands; the correct macros to use for this purpose are -.Sx \&Op , -.Sx \&Oo , -and -.Sx \&Oc . -.Pp -See also -.Sx \&Bo . -.Ss \&Brc -Close a -.Sx \&Bro -block. -Does not have any tail arguments. -.Ss \&Bro -Begin a block enclosed by curly braces. -Does not have any head arguments. -.Pp -Examples: -.Bd -literal -offset indent -compact -\&.Bro 1 , ... , -\&.Va n \&Brc -.Ed -.Pp -See also -.Sx \&Brq . -.Ss \&Brq -Encloses its arguments in curly braces. -.Pp -Examples: -.Dl \&.Brq 1 , ... , \&Va n -.Pp -See also -.Sx \&Bro . -.Ss \&Bsx -Format the -.Bsx -version provided as an argument, or a default value if -no argument is provided. -.Pp -Examples: -.Dl \&.Bsx 1.0 -.Dl \&.Bsx -.Pp -See also -.Sx \&At , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Fx , -.Sx \&Nx , -and -.Sx \&Ox . -.Ss \&Bt -Supported only for compatibility, do not use this in new manuals. -Prints -.Dq is currently in beta test. -.Ss \&Bx -Format the -.Bx -version provided as an argument, or a default value if no -argument is provided. -.Pp -Examples: -.Dl \&.Bx 4.3 Tahoe -.Dl \&.Bx 4.4 -.Dl \&.Bx -.Pp -See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Dx , -.Sx \&Fx , -.Sx \&Nx , -and -.Sx \&Ox . -.Ss \&Cd -Kernel configuration declaration. -This denotes strings accepted by -.Xr config 8 . -It is most often used in section 4 manual pages. -.Pp -Examples: -.Dl \&.Cd device le0 at scode? -.Pp -.Em Remarks : -this macro is commonly abused by using quoted literals to retain -whitespace and align consecutive -.Sx \&Cd -declarations. -This practise is discouraged. -.Ss \&Cm -Command modifiers. -Typically used for fixed strings passed as arguments, unless -.Sx \&Fl -is more appropriate. -Also useful when specifying configuration options or keys. -.Pp -Examples: -.Dl ".Nm mt Fl f Ar device Cm rewind" -.Dl ".Nm ps Fl o Cm pid , Ns Cm command" -.Dl ".Nm dd Cm if= Ns Ar file1 Cm of= Ns Ar file2" -.Dl ".Cm IdentityFile Pa ~/.ssh/id_rsa" -.Dl ".Cm LogLevel Dv DEBUG" -.Ss \&D1 -One-line indented display. -This is formatted by the default rules and is useful for simple indented -statements. -It is followed by a newline. -.Pp -Examples: -.Dl \&.D1 \&Fl abcdefgh -.Pp -See also -.Sx \&Bd -and -.Sx \&Dl . -.Ss \&Db -This macro is obsolete. -No replacement is needed. -It is ignored by -.Xr mandoc 1 -and groff including its arguments. -It was formerly used to toggle a debugging mode. -.Ss \&Dc -Close a -.Sx \&Do -block. -Does not have any tail arguments. -.Ss \&Dd -Document date for display in the page footer. -This is the mandatory first macro of any -.Nm -manual. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Dd Ar month day , year -.Pp -The -.Ar month -is the full English month name, the -.Ar day -is an optionally zero-padded numeral, and the -.Ar year -is the full four-digit year. -.Pp -Other arguments are not portable; the -.Xr mandoc 1 -utility handles them as follows: -.Bl -dash -offset 3n -compact -.It -To have the date automatically filled in by the -.Ox -version of -.Xr cvs 1 , -the special string -.Dq $\&Mdocdate$ -can be given as an argument. -.It -The traditional, purely numeric -.Xr man 7 -format -.Ar year Ns \(en Ns Ar month Ns \(en Ns Ar day -is accepted, too. -.It -If a date string cannot be parsed, it is used verbatim. -.It -If no date string is given, the current date is used. -.El -.Pp -Examples: -.Dl \&.Dd $\&Mdocdate$ -.Dl \&.Dd $\&Mdocdate: July 21 2007$ -.Dl \&.Dd July 21, 2007 -.Pp -See also -.Sx \&Dt -and -.Sx \&Os . -.Ss \&Dl -One-line indented display. -This is formatted as literal text and is useful for commands and -invocations. -It is followed by a newline. -.Pp -Examples: -.Dl \&.Dl % mandoc mdoc.7 \e(ba less -.Pp -See also -.Sx \&Ql , -.Sx \&Bd -.Fl literal , -and -.Sx \&D1 . -.Ss \&Do -Begin a block enclosed by double quotes. -Does not have any head arguments. -.Pp -Examples: -.Bd -literal -offset indent -compact -\&.Do -April is the cruellest month -\&.Dc -\e(em T.S. Eliot -.Ed -.Pp -See also -.Sx \&Dq . -.Ss \&Dq -Encloses its arguments in -.Dq typographic -double-quotes. -.Pp -Examples: -.Bd -literal -offset indent -compact -\&.Dq April is the cruellest month -\e(em T.S. Eliot -.Ed -.Pp -See also -.Sx \&Qq , -.Sx \&Sq , -and -.Sx \&Do . -.Ss \&Dt -Document title for display in the page header. -This is the mandatory second macro of any -.Nm -file. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Dt -.Ar TITLE -.Ar section -.Op Ar arch -.Ed -.Pp -Its arguments are as follows: -.Bl -tag -width section -offset 2n -.It Ar TITLE -The document's title (name), defaulting to -.Dq UNTITLED -if unspecified. -To achieve a uniform appearance of page header lines, -it should by convention be all caps. -.It Ar section -The manual section. -This may be one of -.Cm 1 -.Pq General Commands , -.Cm 2 -.Pq System Calls , -.Cm 3 -.Pq Library Functions , -.Cm 3p -.Pq Perl Library , -.Cm 4 -.Pq Device Drivers , -.Cm 5 -.Pq File Formats , -.Cm 6 -.Pq Games , -.Cm 7 -.Pq Miscellaneous Information , -.Cm 8 -.Pq System Manager's Manual , -or -.Cm 9 -.Pq Kernel Developer's Manual . -It should correspond to the manual's filename suffix and defaults to -the empty string if unspecified. -.It Ar arch -This specifies the machine architecture a manual page applies to, -where relevant, for example -.Cm alpha , -.Cm amd64 , -.Cm i386 , -or -.Cm sparc64 . -The list of valid architectures varies by operating system. -.El -.Pp -Examples: -.Dl \&.Dt FOO 1 -.Dl \&.Dt FOO 9 i386 -.Pp -See also -.Sx \&Dd -and -.Sx \&Os . -.Ss \&Dv -Defined variables such as preprocessor constants, constant symbols, -enumeration values, and so on. -.Pp -Examples: -.Dl \&.Dv NULL -.Dl \&.Dv BUFSIZ -.Dl \&.Dv STDOUT_FILENO -.Pp -See also -.Sx \&Er -and -.Sx \&Ev -for special-purpose constants, -.Sx \&Va -for variable symbols, and -.Sx \&Fd -for listing preprocessor variable definitions in the -.Em SYNOPSIS . -.Ss \&Dx -Format the -.Dx -version provided as an argument, or a default -value if no argument is provided. -.Pp -Examples: -.Dl \&.Dx 2.4.1 -.Dl \&.Dx -.Pp -See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Fx , -.Sx \&Nx , -and -.Sx \&Ox . -.Ss \&Ec -Close a scope started by -.Sx \&Eo . -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Ec Op Ar TERM -.Pp -The -.Ar TERM -argument is used as the enclosure tail, for example, specifying \e(rq -will emulate -.Sx \&Dc . -.Ss \&Ed -End a display context started by -.Sx \&Bd . -.Ss \&Ef -End a font mode context started by -.Sx \&Bf . -.Ss \&Ek -End a keep context started by -.Sx \&Bk . -.Ss \&El -End a list context started by -.Sx \&Bl . -.Pp -See also -.Sx \&Bl -and -.Sx \&It . -.Ss \&Em -Request an italic font. -If the output device does not provide that, underline. -.Pp -This is most often used for stress emphasis (not to be confused with -importance, see -.Sx \&Sy ) . -In the rare cases where none of the semantic markup macros fit, -it can also be used for technical terms and placeholders, except -that for syntax elements, -.Sx \&Sy -and -.Sx \&Ar -are preferred, respectively. -.Pp -Examples: -.Bd -literal -compact -offset indent -Selected lines are those -\&.Em not -matching any of the specified patterns. -Some of the functions use a -\&.Em hold space -to save the pattern space for subsequent retrieval. -.Ed -.Pp -See also -.Sx \&Bf , -.Sx \&Li , -.Sx \&No , -and -.Sx \&Sy . -.Ss \&En -This macro is obsolete. -Use -.Sx \&Eo -or any of the other enclosure macros. -.Pp -It encloses its argument in the delimiters specified by the last -.Sx \&Es -macro. -.Ss \&Eo -An arbitrary enclosure. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Eo Op Ar TERM -.Pp -The -.Ar TERM -argument is used as the enclosure head, for example, specifying \e(lq -will emulate -.Sx \&Do . -.Ss \&Er -Error constants for definitions of the -.Va errno -libc global variable. -This is most often used in section 2 and 3 manual pages. -.Pp -Examples: -.Dl \&.Er EPERM -.Dl \&.Er ENOENT -.Pp -See also -.Sx \&Dv -for general constants. -.Ss \&Es -This macro is obsolete. -Use -.Sx \&Eo -or any of the other enclosure macros. -.Pp -It takes two arguments, defining the delimiters to be used by subsequent -.Sx \&En -macros. -.Ss \&Ev -Environmental variables such as those specified in -.Xr environ 7 . -.Pp -Examples: -.Dl \&.Ev DISPLAY -.Dl \&.Ev PATH -.Pp -See also -.Sx \&Dv -for general constants. -.Ss \&Ex -Insert a standard sentence regarding command exit values of 0 on success -and >0 on failure. -This is most often used in section 1, 6, and 8 manual pages. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Ex Fl std Op Ar utility ... -.Pp -If -.Ar utility -is not specified, the document's name set by -.Sx \&Nm -is used. -Multiple -.Ar utility -arguments are treated as separate utilities. -.Pp -See also -.Sx \&Rv . -.Ss \&Fa -Function argument or parameter. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Fa -.Qo -.Op Ar argtype -.Op Ar argname -.Qc Ar \&... -.Ed -.Pp -Each argument may be a name and a type (recommended for the -.Em SYNOPSIS -section), a name alone (for function invocations), -or a type alone (for function prototypes). -If both a type and a name are given or if the type consists of multiple -words, all words belonging to the same function argument have to be -given in a single argument to the -.Sx \&Fa -macro. -.Pp -This macro is also used to specify the field name of a structure. -.Pp -Most often, the -.Sx \&Fa -macro is used in the -.Em SYNOPSIS -within -.Sx \&Fo -blocks when documenting multi-line function prototypes. -If invoked with multiple arguments, the arguments are separated by a -comma. -Furthermore, if the following macro is another -.Sx \&Fa , -the last argument will also have a trailing comma. -.Pp -Examples: -.Dl \&.Fa \(dqconst char *p\(dq -.Dl \&.Fa \(dqint a\(dq \(dqint b\(dq \(dqint c\(dq -.Dl \&.Fa \(dqchar *\(dq size_t -.Pp -See also -.Sx \&Fo . -.Ss \&Fc -End a function context started by -.Sx \&Fo . -.Ss \&Fd -Preprocessor directive, in particular for listing it in the -.Em SYNOPSIS . -Historically, it was also used to document include files. -The latter usage has been deprecated in favour of -.Sx \&In . -.Pp -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf \. Sx \&Fd -.Li # Ns Ar directive -.Op Ar argument ... -.Ed -.Pp -Examples: -.Dl \&.Fd #define sa_handler __sigaction_u.__sa_handler -.Dl \&.Fd #define SIO_MAXNFDS -.Dl \&.Fd #ifdef FS_DEBUG -.Dl \&.Ft void -.Dl \&.Fn dbg_open \(dqconst char *\(dq -.Dl \&.Fd #endif -.Pp -See also -.Sx MANUAL STRUCTURE , -.Sx \&In , -and -.Sx \&Dv . -.Ss \&Fl -Command-line flag or option. -Used when listing arguments to command-line utilities. -Prints a fixed-width hyphen -.Sq \- -directly followed by each argument. -If no arguments are provided, a hyphen is printed followed by a space. -If the argument is a macro, a hyphen is prefixed to the subsequent macro -output. -.Pp -Examples: -.Dl ".Fl R Op Fl H | L | P" -.Dl ".Op Fl 1AaCcdFfgHhikLlmnopqRrSsTtux" -.Dl ".Fl type Cm d Fl name Pa CVS" -.Dl ".Fl Ar signal_number" -.Dl ".Fl o Fl" -.Pp -See also -.Sx \&Cm . -.Ss \&Fn -A function name. -Its syntax is as follows: -.Bd -ragged -offset indent -.Pf . Sx \&Fn -.Op Ar functype -.Ar funcname -.Op Oo Ar argtype Oc Ar argname -.Ed -.Pp -Function arguments are surrounded in parenthesis and -are delimited by commas. -If no arguments are specified, blank parenthesis are output. -In the -.Em SYNOPSIS -section, this macro starts a new output line, -and a blank line is automatically inserted between function definitions. -.Pp -Examples: -.Dl \&.Fn \(dqint funcname\(dq \(dqint arg0\(dq \(dqint arg1\(dq -.Dl \&.Fn funcname \(dqint arg0\(dq -.Dl \&.Fn funcname arg0 -.Pp -.Bd -literal -offset indent -compact -\&.Ft functype -\&.Fn funcname -.Ed -.Pp -When referring to a function documented in another manual page, use -.Sx \&Xr -instead. -See also -.Sx MANUAL STRUCTURE , -.Sx \&Fo , -and -.Sx \&Ft . -.Ss \&Fo -Begin a function block. -This is a multi-line version of -.Sx \&Fn . -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Fo Ar funcname -.Pp -Invocations usually occur in the following context: -.Bd -ragged -offset indent -.Pf \. Sx \&Ft Ar functype -.br -.Pf \. Sx \&Fo Ar funcname -.br -.Pf \. Sx \&Fa Qq Ar argtype Ar argname -.br -\&.\.\. -.br -.Pf \. Sx \&Fc -.Ed -.Pp -A -.Sx \&Fo -scope is closed by -.Sx \&Fc . -.Pp -See also -.Sx MANUAL STRUCTURE , -.Sx \&Fa , -.Sx \&Fc , -and -.Sx \&Ft . -.Ss \&Fr -This macro is obsolete. -No replacement markup is needed. -.Pp -It was used to show numerical function return values in an italic font. -.Ss \&Ft -A function type. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Ft Ar functype -.Pp -In the -.Em SYNOPSIS -section, a new output line is started after this macro. -.Pp -Examples: -.Dl \&.Ft int -.Bd -literal -offset indent -compact -\&.Ft functype -\&.Fn funcname -.Ed -.Pp -See also -.Sx MANUAL STRUCTURE , -.Sx \&Fn , -and -.Sx \&Fo . -.Ss \&Fx -Format the -.Fx -version provided as an argument, or a default value -if no argument is provided. -.Pp -Examples: -.Dl \&.Fx 7.1 -.Dl \&.Fx -.Pp -See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Nx , -and -.Sx \&Ox . -.Ss \&Hf -This macro is not implemented in -.Xr mandoc 1 . -.Pp -It was used to include the contents of a (header) file literally. -The syntax was: -.Pp -.Dl Pf . Sx \&Hf Ar filename -.Ss \&Ic -Designate an internal or interactive command. -This is similar to -.Sx \&Cm -but used for instructions rather than values. -.Pp -Examples: -.Dl \&.Ic :wq -.Dl \&.Ic hash -.Dl \&.Ic alias -.Pp -Note that using -.Sx \&Bd Fl literal -or -.Sx \&D1 -is preferred for displaying code; the -.Sx \&Ic -macro is used when referring to specific instructions. -.Ss \&In -The name of an include file. -This macro is most often used in section 2, 3, and 9 manual pages. -.Pp -When invoked as the first macro on an input line in the -.Em SYNOPSIS -section, the argument is displayed in angle brackets -and preceded by -.Qq #include , -and a blank line is inserted in front if there is a preceding -function declaration. -In other sections, it only encloses its argument in angle brackets -and causes no line break. -.Pp -Examples: -.Dl \&.In sys/types.h -.Pp -See also -.Sx MANUAL STRUCTURE . -.Ss \&It -A list item. -The syntax of this macro depends on the list type. -.Pp -Lists -of type -.Fl hang , -.Fl ohang , -.Fl inset , -and -.Fl diag -have the following syntax: -.Pp -.D1 Pf \. Sx \&It Ar args -.Pp -Lists of type -.Fl bullet , -.Fl dash , -.Fl enum , -.Fl hyphen -and -.Fl item -have the following syntax: -.Pp -.D1 Pf \. Sx \&It -.Pp -with subsequent lines interpreted within the scope of the -.Sx \&It -until either a closing -.Sx \&El -or another -.Sx \&It . -.Pp -The -.Fl tag -list has the following syntax: -.Pp -.D1 Pf \. Sx \&It Op Cm args -.Pp -Subsequent lines are interpreted as with -.Fl bullet -and family. -The line arguments correspond to the list's left-hand side; body -arguments correspond to the list's contents. -.Pp -The -.Fl column -list is the most complicated. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&It Ar cell Op Sx \&Ta Ar cell ... -.D1 Pf \. Sx \&It Ar cell Op Ar cell ... -.Pp -The arguments consist of one or more lines of text and macros -representing a complete table line. -Cells within the line are delimited by the special -.Sx \&Ta -block macro or by literal tab characters. -.Pp -Using literal tabs is strongly discouraged because they are very -hard to use correctly and -.Nm -code using them is very hard to read. -In particular, a blank character is syntactically significant -before and after the literal tab character. -If a word precedes or follows the tab without an intervening blank, -that word is never interpreted as a macro call, but always output -literally. -.Pp -The tab cell delimiter may only be used within the -.Sx \&It -line itself; on following lines, only the -.Sx \&Ta -macro can be used to delimit cells, and portability requires that -.Sx \&Ta -is called by other macros: some parsers do not recognize it when -it appears as the first macro on a line. -.Pp -Note that quoted strings may span tab-delimited cells on an -.Sx \&It -line. -For example, -.Pp -.Dl .It \(dqcol1 ,\& col2 ,\(dq \&; -.Pp -will preserve the whitespace before both commas, -but not the whitespace before the semicolon. -.Pp -See also -.Sx \&Bl . -.Ss \&Lb -Specify a library. -The syntax is as follows: -.Pp -.D1 Pf \. Sx \&Lb Ar library -.Pp -The -.Ar library -parameter may be a system library, such as -.Cm libz -or -.Cm libpam , -in which case a small library description is printed next to the linker -invocation; or a custom library, in which case the library name is -printed in quotes. -This is most commonly used in the -.Em SYNOPSIS -section as described in -.Sx MANUAL STRUCTURE . -.Pp -Examples: -.Dl \&.Lb libz -.Dl \&.Lb libmandoc -.Ss \&Li -Denotes text that should be in a -.Li literal -font mode. -Note that this is a presentation term and should not be used for -stylistically decorating technical terms. -.Pp -On terminal output devices, this is often indistinguishable from -normal text. -.Pp -See also -.Sx \&Bf , -.Sx \&Em , -.Sx \&No , -and -.Sx \&Sy . -.Ss \&Lk -Format a hyperlink. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Lk Ar uri Op Ar name -.Pp -Examples: -.Dl \&.Lk http://bsd.lv \(dqThe BSD.lv Project\(dq -.Dl \&.Lk http://bsd.lv -.Pp -See also -.Sx \&Mt . -.Ss \&Lp -Synonym for -.Sx \&Pp . -.Ss \&Ms -Display a mathematical symbol. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Ms Ar symbol -.Pp -Examples: -.Dl \&.Ms sigma -.Dl \&.Ms aleph -.Ss \&Mt -Format a -.Dq mailto: -hyperlink. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Mt Ar address -.Pp -Examples: -.Dl \&.Mt discuss@manpages.bsd.lv -.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv -.Ss \&Nd -A one line description of the manual's content. -This is the mandatory last macro of the -.Em NAME -section and not appropriate for other sections. -.Pp -Examples: -.Dl Pf . Sx \&Nd mdoc language reference -.Dl Pf . Sx \&Nd format and display UNIX manuals -.Pp -The -.Sx \&Nd -macro technically accepts child macros and terminates with a subsequent -.Sx \&Sh -invocation. -Do not assume this behaviour: some -.Xr whatis 1 -database generators are not smart enough to parse more than the line -arguments and will display macros verbatim. -.Pp -See also -.Sx \&Nm . -.Ss \&Nm -The name of the manual page, or \(em in particular in section 1, 6, -and 8 pages \(em of an additional command or feature documented in -the manual page. -When first invoked, the -.Sx \&Nm -macro expects a single argument, the name of the manual page. -Usually, the first invocation happens in the -.Em NAME -section of the page. -The specified name will be remembered and used whenever the macro is -called again without arguments later in the page. -The -.Sx \&Nm -macro uses -.Sx Block full-implicit -semantics when invoked as the first macro on an input line in the -.Em SYNOPSIS -section; otherwise, it uses ordinary -.Sx In-line -semantics. -.Pp -Examples: -.Bd -literal -offset indent -\&.Sh SYNOPSIS -\&.Nm cat -\&.Op Fl benstuv -\&.Op Ar -.Ed -.Pp -In the -.Em SYNOPSIS -of section 2, 3 and 9 manual pages, use the -.Sx \&Fn -macro rather than -.Sx \&Nm -to mark up the name of the manual page. -.Ss \&No -Normal text. -Closes the scope of any preceding in-line macro. -When used after physical formatting macros like -.Sx \&Em -or -.Sx \&Sy , -switches back to the standard font face and weight. -Can also be used to embed plain text strings in macro lines -using semantic annotation macros. -.Pp -Examples: -.Dl ".Em italic , Sy bold , No and roman" -.Pp -.Bd -literal -offset indent -compact -\&.Sm off -\&.Cm :C No / Ar pattern No / Ar replacement No / -\&.Sm on -.Ed -.Pp -See also -.Sx \&Em , -.Sx \&Li , -and -.Sx \&Sy . -.Ss \&Ns -Suppress a space between the output of the preceding macro -and the following text or macro. -Following invocation, input is interpreted as normal text -just like after an -.Sx \&No -macro. -.Pp -This has no effect when invoked at the start of a macro line. -.Pp -Examples: -.Dl ".Ar name Ns = Ns Ar value" -.Dl ".Cm :M Ns Ar pattern" -.Dl ".Fl o Ns Ar output" -.Pp -See also -.Sx \&No -and -.Sx \&Sm . -.Ss \&Nx -Format the -.Nx -version provided as an argument, or a default value if -no argument is provided. -.Pp -Examples: -.Dl \&.Nx 5.01 -.Dl \&.Nx -.Pp -See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Fx , -and -.Sx \&Ox . -.Ss \&Oc -Close multi-line -.Sx \&Oo -context. -.Ss \&Oo -Multi-line version of -.Sx \&Op . -.Pp -Examples: -.Bd -literal -offset indent -compact -\&.Oo -\&.Op Fl flag Ns Ar value -\&.Oc -.Ed -.Ss \&Op -Optional part of a command line. -Prints the argument(s) in brackets. -This is most often used in the -.Em SYNOPSIS -section of section 1 and 8 manual pages. -.Pp -Examples: -.Dl \&.Op \&Fl a \&Ar b -.Dl \&.Op \&Ar a | b -.Pp -See also -.Sx \&Oo . -.Ss \&Os -Operating system version for display in the page footer. -This is the mandatory third macro of -any -.Nm -file. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Os Op Ar system Op Ar version -.Pp -The optional -.Ar system -parameter specifies the relevant operating system or environment. -It is suggested to leave it unspecified, in which case -.Xr mandoc 1 -uses its -.Fl Ios -argument or, if that isn't specified either, -.Fa sysname -and -.Fa release -as returned by -.Xr uname 3 . -.Pp -Examples: -.Dl \&.Os -.Dl \&.Os KTH/CSC/TCS -.Dl \&.Os BSD 4.3 -.Pp -See also -.Sx \&Dd -and -.Sx \&Dt . -.Ss \&Ot -This macro is obsolete. -Use -.Sx \&Ft -instead; with -.Xr mandoc 1 , -both have the same effect. -.Pp -Historical -.Nm -packages described it as -.Dq "old function type (FORTRAN)" . -.Ss \&Ox -Format the -.Ox -version provided as an argument, or a default value -if no argument is provided. -.Pp -Examples: -.Dl \&.Ox 4.5 -.Dl \&.Ox -.Pp -See also -.Sx \&At , -.Sx \&Bsx , -.Sx \&Bx , -.Sx \&Dx , -.Sx \&Fx , -and -.Sx \&Nx . -.Ss \&Pa -An absolute or relative file system path, or a file or directory name. -If an argument is not provided, the character -.Sq \(ti -is used as a default. -.Pp -Examples: -.Dl \&.Pa /usr/bin/mandoc -.Dl \&.Pa /usr/share/man/man7/mdoc.7 -.Pp -See also -.Sx \&Lk . -.Ss \&Pc -Close parenthesised context opened by -.Sx \&Po . -.Ss \&Pf -Removes the space between its argument and the following macro. -Its syntax is as follows: -.Pp -.D1 .Pf Ar prefix macro arguments ... -.Pp -This is equivalent to: -.Pp -.D1 .No \e& Ns Ar prefix No \&Ns Ar macro arguments ... -.Pp -The -.Ar prefix -argument is not parsed for macro names or delimiters, -but used verbatim as if it were escaped. -.Pp -Examples: -.Dl ".Pf $ Ar variable_name" -.Dl ".Pf . Ar macro_name" -.Dl ".Pf 0x Ar hex_digits" -.Pp -See also -.Sx \&Ns -and -.Sx \&Sm . -.Ss \&Po -Multi-line version of -.Sx \&Pq . -.Ss \&Pp -Break a paragraph. -This will assert vertical space between prior and subsequent macros -and/or text. -.Pp -Paragraph breaks are not needed before or after -.Sx \&Sh -or -.Sx \&Ss -macros or before displays -.Pq Sx \&Bd -or lists -.Pq Sx \&Bl -unless the -.Fl compact -flag is given. -.Ss \&Pq -Parenthesised enclosure. -.Pp -See also -.Sx \&Po . -.Ss \&Qc -Close quoted context opened by -.Sx \&Qo . -.Ss \&Ql -In-line literal display. -This can for example be used for complete command invocations and -for multi-word code fragments when more specific markup is not -appropriate and an indented display is not desired. -While -.Xr mandoc 1 -always encloses the arguments in single quotes, other formatters -usually omit the quotes on non-terminal output devices when the -arguments have three or more characters. -.Pp -See also -.Sx \&Dl -and -.Sx \&Bd -.Fl literal . -.Ss \&Qo -Multi-line version of -.Sx \&Qq . -.Ss \&Qq -Encloses its arguments in -.Qq typewriter -double-quotes. -Consider using -.Sx \&Dq . -.Pp -See also -.Sx \&Dq , -.Sx \&Sq , -and -.Sx \&Qo . -.Ss \&Re -Close an -.Sx \&Rs -block. -Does not have any tail arguments. -.Ss \&Rs -Begin a bibliographic -.Pq Dq reference -block. -Does not have any head arguments. -The block macro may only contain -.Sx \&%A , -.Sx \&%B , -.Sx \&%C , -.Sx \&%D , -.Sx \&%I , -.Sx \&%J , -.Sx \&%N , -.Sx \&%O , -.Sx \&%P , -.Sx \&%Q , -.Sx \&%R , -.Sx \&%T , -.Sx \&%U , -and -.Sx \&%V -child macros (at least one must be specified). -.Pp -Examples: -.Bd -literal -offset indent -compact -\&.Rs -\&.%A J. E. Hopcroft -\&.%A J. D. Ullman -\&.%B Introduction to Automata Theory, Languages, and Computation -\&.%I Addison-Wesley -\&.%C Reading, Massachusetts -\&.%D 1979 -\&.Re -.Ed -.Pp -If an -.Sx \&Rs -block is used within a SEE ALSO section, a vertical space is asserted -before the rendered output, else the block continues on the current -line. -.Ss \&Rv -Insert a standard sentence regarding a function call's return value of 0 -on success and \-1 on error, with the -.Va errno -libc global variable set on error. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Rv Fl std Op Ar function ... -.Pp -If -.Ar function -is not specified, the document's name set by -.Sx \&Nm -is used. -Multiple -.Ar function -arguments are treated as separate functions. -.Pp -See also -.Sx \&Ex . -.Ss \&Sc -Close single-quoted context opened by -.Sx \&So . -.Ss \&Sh -Begin a new section. -For a list of conventional manual sections, see -.Sx MANUAL STRUCTURE . -These sections should be used unless it's absolutely necessary that -custom sections be used. -.Pp -Section names should be unique so that they may be keyed by -.Sx \&Sx . -Although this macro is parsed, it should not consist of child node or it -may not be linked with -.Sx \&Sx . -.Pp -See also -.Sx \&Pp , -.Sx \&Ss , -and -.Sx \&Sx . -.Ss \&Sm -Switches the spacing mode for output generated from macros. -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Sm Op Cm on | off -.Pp -By default, spacing is -.Cm on . -When switched -.Cm off , -no white space is inserted between macro arguments and between the -output generated from adjacent macros, but text lines -still get normal spacing between words and sentences. -.Pp -When called without an argument, the -.Sx \&Sm -macro toggles the spacing mode. -Using this is not recommended because it makes the code harder to read. -.Ss \&So -Multi-line version of -.Sx \&Sq . -.Ss \&Sq -Encloses its arguments in -.Sq typewriter -single-quotes. -.Pp -See also -.Sx \&Dq , -.Sx \&Qq , -and -.Sx \&So . -.Ss \&Ss -Begin a new subsection. -Unlike with -.Sx \&Sh , -there is no convention for the naming of subsections. -Except -.Em DESCRIPTION , -the conventional sections described in -.Sx MANUAL STRUCTURE -rarely have subsections. -.Pp -Sub-section names should be unique so that they may be keyed by -.Sx \&Sx . -Although this macro is parsed, it should not consist of child node or it -may not be linked with -.Sx \&Sx . -.Pp -See also -.Sx \&Pp , -.Sx \&Sh , -and -.Sx \&Sx . -.Ss \&St -Replace an abbreviation for a standard with the full form. -The following standards are recognised. -Where multiple lines are given without a blank line in between, -they all refer to the same standard, and using the first form -is recommended. -.Bl -tag -width 1n -.It C language standards -.Pp -.Bl -tag -width "-p1003.1g-2000" -compact -.It \-ansiC -.St -ansiC -.It \-ansiC-89 -.St -ansiC-89 -.It \-isoC -.St -isoC -.It \-isoC-90 -.St -isoC-90 -.br -The original C standard. -.Pp -.It \-isoC-amd1 -.St -isoC-amd1 -.Pp -.It \-isoC-tcor1 -.St -isoC-tcor1 -.Pp -.It \-isoC-tcor2 -.St -isoC-tcor2 -.Pp -.It \-isoC-99 -.St -isoC-99 -.br -The second major version of the C language standard. -.Pp -.It \-isoC-2011 -.St -isoC-2011 -.br -The third major version of the C language standard. -.El -.It POSIX.1 before the Single UNIX Specification -.Pp -.Bl -tag -width "-p1003.1g-2000" -compact -.It \-p1003.1-88 -.St -p1003.1-88 -.It \-p1003.1 -.St -p1003.1 -.br -The original POSIX standard, based on ANSI C. -.Pp -.It \-p1003.1-90 -.St -p1003.1-90 -.It \-iso9945-1-90 -.St -iso9945-1-90 -.br -The first update of POSIX.1. -.Pp -.It \-p1003.1b-93 -.St -p1003.1b-93 -.It \-p1003.1b -.St -p1003.1b -.br -Real-time extensions. -.Pp -.It \-p1003.1c-95 -.St -p1003.1c-95 -.br -POSIX thread interfaces. -.Pp -.It \-p1003.1i-95 -.St -p1003.1i-95 -.br -Technical Corrigendum. -.Pp -.It \-p1003.1-96 -.St -p1003.1-96 -.It \-iso9945-1-96 -.St -iso9945-1-96 -.br -Includes POSIX.1-1990, 1b, 1c, and 1i. -.El -.It X/Open Portability Guide version 4 and related standards -.Pp -.Bl -tag -width "-p1003.1g-2000" -compact -.It \-xpg3 -.St -xpg3 -.br -An XPG4 precursor, published in 1989. -.Pp -.It \-p1003.2 -.St -p1003.2 -.It \-p1003.2-92 -.St -p1003.2-92 -.It \-iso9945-2-93 -.St -iso9945-2-93 -.br -An XCU4 precursor. -.Pp -.It \-p1003.2a-92 -.St -p1003.2a-92 -.br -Updates to POSIX.2. -.Pp -.It \-xpg4 -.St -xpg4 -.br -Based on POSIX.1 and POSIX.2, published in 1992. -.El -.It Single UNIX Specification version 1 and related standards -.Pp -.Bl -tag -width "-p1003.1g-2000" -compact -.It \-susv1 -.St -susv1 -.It \-xpg4.2 -.St -xpg4.2 -.br -This standard was published in 1994. -It was used as the basis for UNIX 95 certification. -The following three refer to parts of it. -.Pp -.It \-xsh4.2 -.St -xsh4.2 -.Pp -.It \-xcurses4.2 -.St -xcurses4.2 -.Pp -.It \-p1003.1g-2000 -.St -p1003.1g-2000 -.br -Networking APIs, including sockets. -.Pp -.It \-svid4 -.St -svid4 , -.br -Published in 1995. -.El -.It Single UNIX Specification version 2 and related standards -.Pp -.Bl -tag -width "-p1003.1g-2000" -compact -.It \-susv2 -.St -susv2 -This Standard was published in 1997 -and is also called X/Open Portability Guide version 5. -It was used as the basis for UNIX 98 certification. -The following refer to parts of it. -.Pp -.It \-xbd5 -.St -xbd5 -.Pp -.It \-xsh5 -.St -xsh5 -.Pp -.It \-xcu5 -.St -xcu5 -.Pp -.It \-xns5 -.St -xns5 -.It \-xns5.2 -.St -xns5.2 -.El -.It Single UNIX Specification version 3 -.Pp -.Bl -tag -width "-p1003.1-2001" -compact -.It \-p1003.1-2001 -.St -p1003.1-2001 -.It \-susv3 -.St -susv3 -.br -This standard is based on C99, SUSv2, POSIX.1-1996, 1d, and 1j. -It is also called X/Open Portability Guide version 6. -It is used as the basis for UNIX 03 certification. -.Pp -.It \-p1003.1-2004 -.St -p1003.1-2004 -.br -The second and last Technical Corrigendum. -.El -.It Single UNIX Specification version 4 -.Pp -.Bl -tag -width "-p1003.1g-2000" -compact -.It \-p1003.1-2008 -.St -p1003.1-2008 -.It \-susv4 -.St -susv4 -.br -This standard is also called -X/Open Portability Guide version 7. -.Pp -.It \-p1003.1-2013 -.St -p1003.1-2013 -.br -The 2013 edition incorporates Technical Corrigendum 1. -.Pp -.It \-p1003.1-2016 -.St -p1003.1-2016 -.br -The 2016 edition incorporates Technical Corrigendum 1 and -Technical Corrigendum 2. -.El -.It Other standards -.Pp -.Bl -tag -width "-p1003.1g-2000" -compact -.It \-ieee754 -.St -ieee754 -.br -Floating-point arithmetic. -.Pp -.It \-iso8601 -.St -iso8601 -.br -Representation of dates and times, published in 1988. -.Pp -.It \-iso8802-3 -.St -iso8802-3 -.br -Ethernet local area networks. -.Pp -.It \-ieee1275-94 -.St -ieee1275-94 -.El -.El -.Ss \&Sx -Reference a section or subsection in the same manual page. -The referenced section or subsection name must be identical to the -enclosed argument, including whitespace. -.Pp -Examples: -.Dl \&.Sx MANUAL STRUCTURE -.Pp -See also -.Sx \&Sh -and -.Sx \&Ss . -.Ss \&Sy -Request a boldface font. -.Pp -This is most often used to indicate importance or seriousness (not to be -confused with stress emphasis, see -.Sx \&Em ) . -When none of the semantic macros fit, it is also adequate for syntax -elements that have to be given or that appear verbatim. -.Pp -Examples: -.Bd -literal -compact -offset indent -\&.Sy Warning : -If -\&.Sy s -appears in the owner permissions, set-user-ID mode is set. -This utility replaces the former -\&.Sy dumpdir -program. -.Ed -.Pp -See also -.Sx \&Bf , -.Sx \&Em , -.Sx \&Li , -and -.Sx \&No . -.Ss \&Ta -Table cell separator in -.Sx \&Bl Fl column -lists; can only be used below -.Sx \&It . -.Ss \&Tn -Supported only for compatibility, do not use this in new manuals. -Even though the macro name -.Pq Dq tradename -suggests a semantic function, historic usage is inconsistent, mostly -using it as a presentation-level macro to request a small caps font. -.Ss \&Ud -Supported only for compatibility, do not use this in new manuals. -Prints out -.Dq currently under development. -.Ss \&Ux -Supported only for compatibility, do not use this in new manuals. -Prints out -.Dq Ux . -.Ss \&Va -A variable name. -.Pp -Examples: -.Dl \&.Va foo -.Dl \&.Va const char *bar ; -.Pp -For function arguments and parameters, use -.Sx \&Fa -instead. -For declarations of global variables in the -.Em SYNOPSIS -section, use -.Sx \&Vt . -.Ss \&Vt -A variable type. -.Pp -This is also used for indicating global variables in the -.Em SYNOPSIS -section, in which case a variable name is also specified. -Note that it accepts -.Sx Block partial-implicit -syntax when invoked as the first macro on an input line in the -.Em SYNOPSIS -section, else it accepts ordinary -.Sx In-line -syntax. -In the former case, this macro starts a new output line, -and a blank line is inserted in front if there is a preceding -function definition or include directive. -.Pp -Examples: -.Dl \&.Vt unsigned char -.Dl \&.Vt extern const char * const sys_signame[] \&; -.Pp -For parameters in function prototypes, use -.Sx \&Fa -instead, for function return types -.Sx \&Ft , -and for variable names outside the -.Em SYNOPSIS -section -.Sx \&Va , -even when including a type with the name. -See also -.Sx MANUAL STRUCTURE . -.Ss \&Xc -Close a scope opened by -.Sx \&Xo . -.Ss \&Xo -Extend the header of an -.Sx \&It -macro or the body of a partial-implicit block macro -beyond the end of the input line. -This macro originally existed to work around the 9-argument limit -of historic -.Xr roff 7 . -.Ss \&Xr -Link to another manual -.Pq Qq cross-reference . -Its syntax is as follows: -.Pp -.D1 Pf \. Sx \&Xr Ar name section -.Pp -Cross reference the -.Ar name -and -.Ar section -number of another man page. -.Pp -Examples: -.Dl \&.Xr mandoc 1 -.Dl \&.Xr mandoc 1 \&; -.Dl \&.Xr mandoc 1 \&Ns s behaviour -.Sh MACRO SYNTAX -The syntax of a macro depends on its classification. -In this section, -.Sq \-arg -refers to macro arguments, which may be followed by zero or more -.Sq parm -parameters; -.Sq \&Yo -opens the scope of a macro; and if specified, -.Sq \&Yc -closes it out. -.Pp -The -.Em Callable -column indicates that the macro may also be called by passing its name -as an argument to another macro. -For example, -.Sq \&.Op \&Fl O \&Ar file -produces -.Sq Op Fl O Ar file . -To prevent a macro call and render the macro name literally, -escape it by prepending a zero-width space, -.Sq \e& . -For example, -.Sq \&Op \e&Fl O -produces -.Sq Op \&Fl O . -If a macro is not callable but its name appears as an argument -to another macro, it is interpreted as opaque text. -For example, -.Sq \&.Fl \&Sh -produces -.Sq Fl \&Sh . -.Pp -The -.Em Parsed -column indicates whether the macro may call other macros by receiving -their names as arguments. -If a macro is not parsed but the name of another macro appears -as an argument, it is interpreted as opaque text. -.Pp -The -.Em Scope -column, if applicable, describes closure rules. -.Ss Block full-explicit -Multi-line scope closed by an explicit closing macro. -All macros contains bodies; only -.Sx \&Bf -and -.Pq optionally -.Sx \&Bl -contain a head. -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB -\(lBbody...\(rB -\&.Yc -.Ed -.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXX" -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&Bd Ta \&No Ta \&No Ta closed by Sx \&Ed -.It Sx \&Bf Ta \&No Ta \&No Ta closed by Sx \&Ef -.It Sx \&Bk Ta \&No Ta \&No Ta closed by Sx \&Ek -.It Sx \&Bl Ta \&No Ta \&No Ta closed by Sx \&El -.It Sx \&Ed Ta \&No Ta \&No Ta opened by Sx \&Bd -.It Sx \&Ef Ta \&No Ta \&No Ta opened by Sx \&Bf -.It Sx \&Ek Ta \&No Ta \&No Ta opened by Sx \&Bk -.It Sx \&El Ta \&No Ta \&No Ta opened by Sx \&Bl -.El -.Ss Block full-implicit -Multi-line scope closed by end-of-file or implicitly by another macro. -All macros have bodies; some -.Po -.Sx \&It Fl bullet , -.Fl hyphen , -.Fl dash , -.Fl enum , -.Fl item -.Pc -don't have heads; only one -.Po -.Sx \&It -in -.Sx \&Bl Fl column -.Pc -has multiple heads. -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead... \(lBTa head...\(rB\(rB -\(lBbody...\(rB -.Ed -.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXXXXXXXXX" -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&It Ta \&No Ta Yes Ta closed by Sx \&It , Sx \&El -.It Sx \&Nd Ta \&No Ta \&No Ta closed by Sx \&Sh -.It Sx \&Nm Ta \&No Ta Yes Ta closed by Sx \&Nm , Sx \&Sh , Sx \&Ss -.It Sx \&Sh Ta \&No Ta Yes Ta closed by Sx \&Sh -.It Sx \&Ss Ta \&No Ta Yes Ta closed by Sx \&Sh , Sx \&Ss -.El -.Pp -Note that the -.Sx \&Nm -macro is a -.Sx Block full-implicit -macro only when invoked as the first macro -in a -.Em SYNOPSIS -section line, else it is -.Sx In-line . -.Ss Block partial-explicit -Like block full-explicit, but also with single-line scope. -Each has at least a body and, in limited circumstances, a head -.Po -.Sx \&Fo , -.Sx \&Eo -.Pc -and/or tail -.Pq Sx \&Ec . -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB -\(lBbody...\(rB -\&.Yc \(lBtail...\(rB - -\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB \ -\(lBbody...\(rB \&Yc \(lBtail...\(rB -.Ed -.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&Ac Ta Yes Ta Yes Ta opened by Sx \&Ao -.It Sx \&Ao Ta Yes Ta Yes Ta closed by Sx \&Ac -.It Sx \&Bc Ta Yes Ta Yes Ta closed by Sx \&Bo -.It Sx \&Bo Ta Yes Ta Yes Ta opened by Sx \&Bc -.It Sx \&Brc Ta Yes Ta Yes Ta opened by Sx \&Bro -.It Sx \&Bro Ta Yes Ta Yes Ta closed by Sx \&Brc -.It Sx \&Dc Ta Yes Ta Yes Ta opened by Sx \&Do -.It Sx \&Do Ta Yes Ta Yes Ta closed by Sx \&Dc -.It Sx \&Ec Ta Yes Ta Yes Ta opened by Sx \&Eo -.It Sx \&Eo Ta Yes Ta Yes Ta closed by Sx \&Ec -.It Sx \&Fc Ta Yes Ta Yes Ta opened by Sx \&Fo -.It Sx \&Fo Ta \&No Ta \&No Ta closed by Sx \&Fc -.It Sx \&Oc Ta Yes Ta Yes Ta closed by Sx \&Oo -.It Sx \&Oo Ta Yes Ta Yes Ta opened by Sx \&Oc -.It Sx \&Pc Ta Yes Ta Yes Ta closed by Sx \&Po -.It Sx \&Po Ta Yes Ta Yes Ta opened by Sx \&Pc -.It Sx \&Qc Ta Yes Ta Yes Ta opened by Sx \&Oo -.It Sx \&Qo Ta Yes Ta Yes Ta closed by Sx \&Oc -.It Sx \&Re Ta \&No Ta \&No Ta opened by Sx \&Rs -.It Sx \&Rs Ta \&No Ta \&No Ta closed by Sx \&Re -.It Sx \&Sc Ta Yes Ta Yes Ta opened by Sx \&So -.It Sx \&So Ta Yes Ta Yes Ta closed by Sx \&Sc -.It Sx \&Xc Ta Yes Ta Yes Ta opened by Sx \&Xo -.It Sx \&Xo Ta Yes Ta Yes Ta closed by Sx \&Xc -.El -.Ss Block partial-implicit -Like block full-implicit, but with single-line scope closed by the -end of the line. -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBbody...\(rB \(lBres...\(rB -.Ed -.Bl -column "MacroX" "CallableX" "ParsedX" -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed -.It Sx \&Aq Ta Yes Ta Yes -.It Sx \&Bq Ta Yes Ta Yes -.It Sx \&Brq Ta Yes Ta Yes -.It Sx \&D1 Ta \&No Ta \&Yes -.It Sx \&Dl Ta \&No Ta Yes -.It Sx \&Dq Ta Yes Ta Yes -.It Sx \&En Ta Yes Ta Yes -.It Sx \&Op Ta Yes Ta Yes -.It Sx \&Pq Ta Yes Ta Yes -.It Sx \&Ql Ta Yes Ta Yes -.It Sx \&Qq Ta Yes Ta Yes -.It Sx \&Sq Ta Yes Ta Yes -.It Sx \&Vt Ta Yes Ta Yes -.El -.Pp -Note that the -.Sx \&Vt -macro is a -.Sx Block partial-implicit -only when invoked as the first macro -in a -.Em SYNOPSIS -section line, else it is -.Sx In-line . -.Ss Special block macro -The -.Sx \&Ta -macro can only be used below -.Sx \&It -in -.Sx \&Bl Fl column -lists. -It delimits blocks representing table cells; -these blocks have bodies, but no heads. -.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&Ta Ta Yes Ta Yes Ta closed by Sx \&Ta , Sx \&It -.El -.Ss In-line -Closed by the end of the line, fixed argument lengths, -and/or subsequent macros. -In-line macros have only text children. -If a number (or inequality) of arguments is -.Pq n , -then the macro accepts an arbitrary number of arguments. -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB \(lBres...\(rB - -\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB Yc... - -\&.Yo \(lB\-arg \(lBval...\(rB\(rB arg0 arg1 argN -.Ed -.Bl -column "MacroX" "CallableX" "ParsedX" "Arguments" -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Arguments -.It Sx \&%A Ta \&No Ta \&No Ta >0 -.It Sx \&%B Ta \&No Ta \&No Ta >0 -.It Sx \&%C Ta \&No Ta \&No Ta >0 -.It Sx \&%D Ta \&No Ta \&No Ta >0 -.It Sx \&%I Ta \&No Ta \&No Ta >0 -.It Sx \&%J Ta \&No Ta \&No Ta >0 -.It Sx \&%N Ta \&No Ta \&No Ta >0 -.It Sx \&%O Ta \&No Ta \&No Ta >0 -.It Sx \&%P Ta \&No Ta \&No Ta >0 -.It Sx \&%Q Ta \&No Ta \&No Ta >0 -.It Sx \&%R Ta \&No Ta \&No Ta >0 -.It Sx \&%T Ta \&No Ta \&No Ta >0 -.It Sx \&%U Ta \&No Ta \&No Ta >0 -.It Sx \&%V Ta \&No Ta \&No Ta >0 -.It Sx \&Ad Ta Yes Ta Yes Ta >0 -.It Sx \&An Ta Yes Ta Yes Ta >0 -.It Sx \&Ap Ta Yes Ta Yes Ta 0 -.It Sx \&Ar Ta Yes Ta Yes Ta n -.It Sx \&At Ta Yes Ta Yes Ta 1 -.It Sx \&Bsx Ta Yes Ta Yes Ta n -.It Sx \&Bt Ta \&No Ta \&No Ta 0 -.It Sx \&Bx Ta Yes Ta Yes Ta n -.It Sx \&Cd Ta Yes Ta Yes Ta >0 -.It Sx \&Cm Ta Yes Ta Yes Ta >0 -.It Sx \&Db Ta \&No Ta \&No Ta 1 -.It Sx \&Dd Ta \&No Ta \&No Ta n -.It Sx \&Dt Ta \&No Ta \&No Ta n -.It Sx \&Dv Ta Yes Ta Yes Ta >0 -.It Sx \&Dx Ta Yes Ta Yes Ta n -.It Sx \&Em Ta Yes Ta Yes Ta >0 -.It Sx \&Er Ta Yes Ta Yes Ta >0 -.It Sx \&Es Ta Yes Ta Yes Ta 2 -.It Sx \&Ev Ta Yes Ta Yes Ta >0 -.It Sx \&Ex Ta \&No Ta \&No Ta n -.It Sx \&Fa Ta Yes Ta Yes Ta >0 -.It Sx \&Fd Ta \&No Ta \&No Ta >0 -.It Sx \&Fl Ta Yes Ta Yes Ta n -.It Sx \&Fn Ta Yes Ta Yes Ta >0 -.It Sx \&Fr Ta Yes Ta Yes Ta >0 -.It Sx \&Ft Ta Yes Ta Yes Ta >0 -.It Sx \&Fx Ta Yes Ta Yes Ta n -.It Sx \&Hf Ta \&No Ta \&No Ta n -.It Sx \&Ic Ta Yes Ta Yes Ta >0 -.It Sx \&In Ta \&No Ta \&No Ta 1 -.It Sx \&Lb Ta \&No Ta \&No Ta 1 -.It Sx \&Li Ta Yes Ta Yes Ta >0 -.It Sx \&Lk Ta Yes Ta Yes Ta >0 -.It Sx \&Lp Ta \&No Ta \&No Ta 0 -.It Sx \&Ms Ta Yes Ta Yes Ta >0 -.It Sx \&Mt Ta Yes Ta Yes Ta >0 -.It Sx \&Nm Ta Yes Ta Yes Ta n -.It Sx \&No Ta Yes Ta Yes Ta 0 -.It Sx \&Ns Ta Yes Ta Yes Ta 0 -.It Sx \&Nx Ta Yes Ta Yes Ta n -.It Sx \&Os Ta \&No Ta \&No Ta n -.It Sx \&Ot Ta Yes Ta Yes Ta >0 -.It Sx \&Ox Ta Yes Ta Yes Ta n -.It Sx \&Pa Ta Yes Ta Yes Ta n -.It Sx \&Pf Ta Yes Ta Yes Ta 1 -.It Sx \&Pp Ta \&No Ta \&No Ta 0 -.It Sx \&Rv Ta \&No Ta \&No Ta n -.It Sx \&Sm Ta \&No Ta \&No Ta <2 -.It Sx \&St Ta \&No Ta Yes Ta 1 -.It Sx \&Sx Ta Yes Ta Yes Ta >0 -.It Sx \&Sy Ta Yes Ta Yes Ta >0 -.It Sx \&Tn Ta Yes Ta Yes Ta >0 -.It Sx \&Ud Ta \&No Ta \&No Ta 0 -.It Sx \&Ux Ta Yes Ta Yes Ta n -.It Sx \&Va Ta Yes Ta Yes Ta n -.It Sx \&Vt Ta Yes Ta Yes Ta >0 -.It Sx \&Xr Ta Yes Ta Yes Ta 2 -.El -.Ss Delimiters -When a macro argument consists of one single input character -considered as a delimiter, the argument gets special handling. -This does not apply when delimiters appear in arguments containing -more than one character. -Consequently, to prevent special handling and just handle it -like any other argument, a delimiter can be escaped by prepending -a zero-width space -.Pq Sq \e& . -In text lines, delimiters never need escaping, but may be used -as normal punctuation. -.Pp -For many macros, when the leading arguments are opening delimiters, -these delimiters are put before the macro scope, -and when the trailing arguments are closing delimiters, -these delimiters are put after the macro scope. -Spacing is suppressed after opening delimiters -and before closing delimiters. -For example, -.Pp -.D1 Pf \. \&Aq "( [ word ] ) ." -.Pp -renders as: -.Pp -.D1 Aq ( [ word ] ) . -.Pp -Opening delimiters are: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It \&( -left parenthesis -.It \&[ -left bracket -.El -.Pp -Closing delimiters are: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It \&. -period -.It \&, -comma -.It \&: -colon -.It \&; -semicolon -.It \&) -right parenthesis -.It \&] -right bracket -.It \&? -question mark -.It \&! -exclamation mark -.El -.Pp -Note that even a period preceded by a backslash -.Pq Sq \e.\& -gets this special handling; use -.Sq \e&. -to prevent that. -.Pp -Many in-line macros interrupt their scope when they encounter -delimiters, and resume their scope when more arguments follow that -are not delimiters. -For example, -.Pp -.D1 Pf \. \&Fl "a ( b | c \e*(Ba d ) e" -.Pp -renders as: -.Pp -.D1 Fl a ( b | c \*(Ba d ) e -.Pp -This applies to both opening and closing delimiters, -and also to the middle delimiter, which does not suppress spacing: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It \&| -vertical bar -.El -.Pp -As a special case, the predefined string \e*(Ba is handled and rendered -in the same way as a plain -.Sq \&| -character. -Using this predefined string is not recommended in new manuals. -.Ss Font handling -In -.Nm -documents, usage of semantic markup is recommended in order to have -proper fonts automatically selected; only when no fitting semantic markup -is available, consider falling back to -.Sx Physical markup -macros. -Whenever any -.Nm -macro switches the -.Xr roff 7 -font mode, it will automatically restore the previous font when exiting -its scope. -Manually switching the font using the -.Xr roff 7 -.Ql \ef -font escape sequences is never required. -.Sh COMPATIBILITY -This section provides an incomplete list of compatibility issues -between mandoc and GNU troff -.Pq Qq groff . -.Pp -The following problematic behaviour is found in groff: -.Pp -.Bl -dash -compact -.It -.Sx \&Dd -with non-standard arguments behaves very strangely. -When there are three arguments, they are printed verbatim. -Any other number of arguments is replaced by the current date, -but without any arguments the string -.Dq Epoch -is printed. -.It -.Sx \&Lk -only accepts a single link-name argument; the remainder is misformatted. -.It -.Sx \&Pa -does not format its arguments when used in the FILES section under -certain list types. -.It -.Sx \&Ta -can only be called by other macros, but not at the beginning of a line. -.It -.Sx \&%C -is not implemented (up to and including groff-1.22.2). -.It -.Sq \ef -.Pq font face -and -.Sq \eF -.Pq font family face -.Sx Text Decoration -escapes behave irregularly when specified within line-macro scopes. -.It -Negative scaling units return to prior lines. -Instead, mandoc truncates them to zero. -.El -.Pp -The following features are unimplemented in mandoc: -.Pp -.Bl -dash -compact -.It -.Sx \&Bd -.Fl file Ar file -is unsupported for security reasons. -.It -.Sx \&Bd -.Fl filled -does not adjust the right margin, but is an alias for -.Sx \&Bd -.Fl ragged . -.It -.Sx \&Bd -.Fl literal -does not use a literal font, but is an alias for -.Sx \&Bd -.Fl unfilled . -.It -.Sx \&Bd -.Fl offset Cm center -and -.Fl offset Cm right -don't work. -Groff does not implement centered and flush-right rendering either, -but produces large indentations. -.El -.Sh SEE ALSO -.Xr man 1 , -.Xr mandoc 1 , -.Xr eqn 7 , -.Xr man 7 , -.Xr mandoc_char 7 , -.Xr roff 7 , -.Xr tbl 7 -.Pp -The web page -.Lk http://mandoc.bsd.lv/mdoc/ "extended documentation for the mdoc language" -provides a few tutorial-style pages for beginners, an extensive style -guide for advanced authors, and an alphabetic index helping to choose -the best macros for various kinds of content. -.Sh HISTORY -The -.Nm -language first appeared as a troff macro package in -.Bx 4.4 . -It was later significantly updated by Werner Lemberg and Ruslan Ermilov -in groff-1.17. -The standalone implementation that is part of the -.Xr mandoc 1 -utility written by Kristaps Dzonsons appeared in -.Ox 4.6 . -.Sh AUTHORS -The -.Nm -reference was written by -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . Property changes on: head/contrib/mdocml/mdoc.7 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc_xr.h =================================================================== --- head/contrib/mdocml/mandoc_xr.h (revision 338825) +++ head/contrib/mdocml/mandoc_xr.h (nonexistent) @@ -1,31 +0,0 @@ -/* $Id: mandoc_xr.h,v 1.3 2017/07/02 21:18:29 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. - */ - -struct mandoc_xr { - struct mandoc_xr *next; - char *sec; - char *name; - int line; /* Or -1 for this page's own names. */ - int pos; - int count; - char hashkey[]; -}; - -void mandoc_xr_reset(void); -int mandoc_xr_add(const char *, const char *, int, int); -struct mandoc_xr *mandoc_xr_get(void); -void mandoc_xr_free(void); Property changes on: head/contrib/mdocml/mandoc_xr.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-mkdtemp.c =================================================================== --- head/contrib/mdocml/test-mkdtemp.c (revision 338825) +++ head/contrib/mdocml/test-mkdtemp.c (nonexistent) @@ -1,12 +0,0 @@ -#include -#include - -int -main(void) -{ - char dirname[] = "/tmp/temp.XXXXXX"; - - if (mkdtemp(dirname) != dirname) - return 1; - return rmdir(dirname) == -1; -} Property changes on: head/contrib/mdocml/test-mkdtemp.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_strlcat.c =================================================================== --- head/contrib/mdocml/compat_strlcat.c (revision 338825) +++ head/contrib/mdocml/compat_strlcat.c (nonexistent) @@ -1,65 +0,0 @@ -#include "config.h" - -#if HAVE_STRLCAT - -int dummy; - -#else - -/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * 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 -#include - -/* - * Appends src to string dst of size siz (unlike strncat, siz is the - * full size of dst, not space left). At most siz-1 characters - * will be copied. Always NUL terminates (unless siz <= strlen(dst)). - * Returns strlen(src) + MIN(siz, strlen(initial dst)). - * If retval >= siz, truncation occurred. - */ -size_t -strlcat(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen + (s - src)); /* count does not include NUL */ -} - -#endif Property changes on: head/contrib/mdocml/compat_strlcat.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-recvmsg.c =================================================================== --- head/contrib/mdocml/test-recvmsg.c (revision 338825) +++ head/contrib/mdocml/test-recvmsg.c (nonexistent) @@ -1,8 +0,0 @@ -#include -#include - -int -main(void) -{ - return recvmsg(-1, NULL, 0) != -1; -} Property changes on: head/contrib/mdocml/test-recvmsg.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-dirent-namlen.c =================================================================== --- head/contrib/mdocml/test-dirent-namlen.c (revision 338825) +++ head/contrib/mdocml/test-dirent-namlen.c (nonexistent) @@ -1,10 +0,0 @@ -#include -#include - -int -main(void) -{ - struct dirent entry; - - return sizeof(entry.d_namlen) == 0; -} Property changes on: head/contrib/mdocml/test-dirent-namlen.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tbl.c =================================================================== --- head/contrib/mdocml/tbl.c (revision 338825) +++ head/contrib/mdocml/tbl.c (nonexistent) @@ -1,179 +0,0 @@ -/* $Id: tbl.c,v 1.42 2017/07/08 17:52:50 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2011, 2015 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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include -#include - -#include "mandoc.h" -#include "mandoc_aux.h" -#include "libmandoc.h" -#include "libroff.h" - - -void -tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos) -{ - const char *cp; - int active; - - /* - * In the options section, proceed to the layout section - * after a semicolon, or right away if there is no semicolon. - * Ignore semicolons in arguments. - */ - - if (tbl->part == TBL_PART_OPTS) { - tbl->part = TBL_PART_LAYOUT; - active = 1; - for (cp = p + pos; *cp != '\0'; cp++) { - switch (*cp) { - case '(': - active = 0; - continue; - case ')': - active = 1; - continue; - case ';': - if (active) - break; - continue; - default: - continue; - } - break; - } - if (*cp == ';') { - tbl_option(tbl, ln, p, &pos); - if (p[pos] == '\0') - return; - } - } - - /* Process the other section types. */ - - switch (tbl->part) { - case TBL_PART_LAYOUT: - tbl_layout(tbl, ln, p, pos); - break; - case TBL_PART_CDATA: - tbl_cdata(tbl, ln, p, pos); - break; - default: - tbl_data(tbl, ln, p, pos); - break; - } -} - -struct tbl_node * -tbl_alloc(int pos, int line, struct mparse *parse) -{ - struct tbl_node *tbl; - - tbl = mandoc_calloc(1, sizeof(*tbl)); - tbl->line = line; - tbl->pos = pos; - tbl->parse = parse; - tbl->part = TBL_PART_OPTS; - tbl->opts.tab = '\t'; - tbl->opts.decimal = '.'; - return tbl; -} - -void -tbl_free(struct tbl_node *tbl) -{ - struct tbl_row *rp; - struct tbl_cell *cp; - struct tbl_span *sp; - struct tbl_dat *dp; - - while ((rp = tbl->first_row) != NULL) { - tbl->first_row = rp->next; - while (rp->first != NULL) { - cp = rp->first; - rp->first = cp->next; - free(cp->wstr); - free(cp); - } - free(rp); - } - - while ((sp = tbl->first_span) != NULL) { - tbl->first_span = sp->next; - while (sp->first != NULL) { - dp = sp->first; - sp->first = dp->next; - free(dp->string); - free(dp); - } - free(sp); - } - - free(tbl); -} - -void -tbl_restart(int line, int pos, struct tbl_node *tbl) -{ - if (tbl->part == TBL_PART_CDATA) - mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse, - line, pos, "T&"); - - tbl->part = TBL_PART_LAYOUT; - tbl->line = line; - tbl->pos = pos; -} - -const struct tbl_span * -tbl_span(struct tbl_node *tbl) -{ - struct tbl_span *span; - - assert(tbl); - span = tbl->current_span ? tbl->current_span->next - : tbl->first_span; - if (span) - tbl->current_span = span; - return span; -} - -int -tbl_end(struct tbl_node *tbl) -{ - struct tbl_span *sp; - - if (tbl->part == TBL_PART_CDATA) - mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse, - tbl->line, tbl->pos, "TE"); - - sp = tbl->first_span; - while (sp != NULL && sp->first == NULL) - sp = sp->next; - if (sp == NULL) { - mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->parse, - tbl->line, tbl->pos, NULL); - return 0; - } - return 1; -} Property changes on: head/contrib/mdocml/tbl.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc_aux.h =================================================================== --- head/contrib/mdocml/mandoc_aux.h (revision 338825) +++ head/contrib/mdocml/mandoc_aux.h (nonexistent) @@ -1,27 +0,0 @@ -/* $Id: mandoc_aux.h,v 1.7 2017/06/12 19:05:47 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2011 Kristaps Dzonsons - * 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); Property changes on: head/contrib/mdocml/mandoc_aux.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/demandoc.c =================================================================== --- head/contrib/mdocml/demandoc.c (revision 338825) +++ head/contrib/mdocml/demandoc.c (nonexistent) @@ -1,264 +0,0 @@ -/* $Id: demandoc.c,v 1.29 2017/06/24 14:38:32 schwarze Exp $ */ -/* - * 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 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 -#include -#include -#include -#include - -#include "mandoc.h" -#include "roff.h" -#include "man.h" -#include "mdoc.h" - -static void pline(int, int *, int *, int); -static void pman(const struct roff_node *, int *, int *, int); -static void pmandoc(struct mparse *, int, const char *, int); -static void pmdoc(const struct roff_node *, int *, int *, int); -static void pstring(const char *, int, int *, int); -static void usage(void); - -static const char *progname; - -int -main(int argc, char *argv[]) -{ - struct mparse *mp; - int ch, fd, i, list; - extern int optind; - - if (argc < 1) - progname = "demandoc"; - else if ((progname = strrchr(argv[0], '/')) == NULL) - progname = argv[0]; - else - ++progname; - - mp = NULL; - list = 0; - - while (-1 != (ch = getopt(argc, argv, "ikm:pw"))) - switch (ch) { - case ('i'): - /* FALLTHROUGH */ - case ('k'): - /* FALLTHROUGH */ - case ('m'): - /* FALLTHROUGH */ - case ('p'): - break; - case ('w'): - list = 1; - break; - default: - usage(); - return (int)MANDOCLEVEL_BADARG; - } - - argc -= optind; - argv += optind; - - mchars_alloc(); - mp = mparse_alloc(MPARSE_SO, MANDOCERR_MAX, NULL, - MANDOC_OS_OTHER, NULL); - assert(mp); - - if (argc < 1) - pmandoc(mp, STDIN_FILENO, "", list); - - for (i = 0; i < argc; i++) { - mparse_reset(mp); - if ((fd = mparse_open(mp, argv[i])) == -1) { - perror(argv[i]); - continue; - } - pmandoc(mp, fd, argv[i], list); - } - - mparse_free(mp); - mchars_free(); - return (int)MANDOCLEVEL_OK; -} - -static void -usage(void) -{ - - fprintf(stderr, "usage: %s [-w] [files...]\n", progname); -} - -static void -pmandoc(struct mparse *mp, int fd, const char *fn, int list) -{ - struct roff_man *man; - int line, col; - - mparse_readfd(mp, fd, fn); - close(fd); - mparse_result(mp, &man, NULL); - line = 1; - col = 0; - - if (man == NULL) - return; - if (man->macroset == MACROSET_MDOC) { - mdoc_validate(man); - pmdoc(man->first->child, &line, &col, list); - } else { - man_validate(man); - pman(man->first->child, &line, &col, list); - } - - if ( ! list) - putchar('\n'); -} - -/* - * Strip the escapes out of a string, emitting the results. - */ -static void -pstring(const char *p, int col, int *colp, int list) -{ - enum mandoc_esc esc; - const char *start, *end; - int emit; - - /* - * Print as many column spaces til we achieve parity with the - * input document. - */ - -again: - if (list && '\0' != *p) { - while (isspace((unsigned char)*p)) - p++; - - while ('\'' == *p || '(' == *p || '"' == *p) - p++; - - emit = isalpha((unsigned char)p[0]) && - isalpha((unsigned char)p[1]); - - for (start = p; '\0' != *p; p++) - if ('\\' == *p) { - p++; - esc = mandoc_escape(&p, NULL, NULL); - if (ESCAPE_ERROR == esc) - return; - emit = 0; - } else if (isspace((unsigned char)*p)) - break; - - end = p - 1; - - while (end > start) - if ('.' == *end || ',' == *end || - '\'' == *end || '"' == *end || - ')' == *end || '!' == *end || - '?' == *end || ':' == *end || - ';' == *end) - end--; - else - break; - - if (emit && end - start >= 1) { - for ( ; start <= end; start++) - if (ASCII_HYPH == *start) - putchar('-'); - else - putchar((unsigned char)*start); - putchar('\n'); - } - - if (isspace((unsigned char)*p)) - goto again; - - return; - } - - while (*colp < col) { - putchar(' '); - (*colp)++; - } - - /* - * Print the input word, skipping any special characters. - */ - while ('\0' != *p) - if ('\\' == *p) { - p++; - esc = mandoc_escape(&p, NULL, NULL); - if (ESCAPE_ERROR == esc) - break; - } else { - putchar((unsigned char )*p++); - (*colp)++; - } -} - -static void -pline(int line, int *linep, int *col, int list) -{ - - if (list) - return; - - /* - * Print out as many lines as needed to reach parity with the - * original input. - */ - - while (*linep < line) { - putchar('\n'); - (*linep)++; - } - - *col = 0; -} - -static void -pmdoc(const struct roff_node *p, int *line, int *col, int list) -{ - - for ( ; p; p = p->next) { - if (NODE_LINE & p->flags) - pline(p->line, line, col, list); - if (ROFFT_TEXT == p->type) - pstring(p->string, p->pos, col, list); - if (p->child) - pmdoc(p->child, line, col, list); - } -} - -static void -pman(const struct roff_node *p, int *line, int *col, int list) -{ - - for ( ; p; p = p->next) { - if (NODE_LINE & p->flags) - pline(p->line, line, col, list); - if (ROFFT_TEXT == p->type) - pstring(p->string, p->pos, col, list); - if (p->child) - pman(p->child, line, col, list); - } -} Property changes on: head/contrib/mdocml/demandoc.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/eqn.7 =================================================================== --- head/contrib/mdocml/eqn.7 (revision 338825) +++ head/contrib/mdocml/eqn.7 (nonexistent) @@ -1,500 +0,0 @@ -.\" $Id: eqn.7,v 1.36 2017/07/20 11:07:27 schwarze Exp $ -.\" -.\" Copyright (c) 2011 Kristaps Dzonsons -.\" Copyright (c) 2014 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: July 20 2017 $ -.Dt EQN 7 -.Os -.Sh NAME -.Nm eqn -.Nd eqn language reference for mandoc -.Sh DESCRIPTION -The -.Nm eqn -language is an equation-formatting language. -It is used within -.Xr mdoc 7 -and -.Xr man 7 -.Ux -manual pages. -It describes the -.Em structure -of an equation, not its mathematical meaning. -This manual describes the -.Nm -language accepted by the -.Xr mandoc 1 -utility, which corresponds to the Second Edition -.Nm -specification (see -.Sx SEE ALSO -for references). -.Pp -Equations within -.Xr mdoc 7 -or -.Xr man 7 -documents are enclosed by the standalone -.Sq \&.EQ -and -.Sq \&.EN -tags. -Equations are multi-line blocks consisting of formulas and control -statements. -.Sh EQUATION STRUCTURE -Each equation is bracketed by -.Sq \&.EQ -and -.Sq \&.EN -strings. -.Em Note : -these are not the same as -.Xr roff 7 -macros, and may only be invoked as -.Sq \&.EQ . -.Pp -The equation grammar is as follows, where quoted strings are -case-sensitive literals in the input: -.Bd -literal -offset indent -eqn : box | eqn box -box : text - | \(dq{\(dq eqn \(dq}\(dq - | \(dqdefine\(dq text text - | \(dqndefine\(dq text text - | \(dqtdefine\(dq text text - | \(dqgfont\(dq text - | \(dqgsize\(dq text - | \(dqset\(dq text text - | \(dqundef\(dq text - | \(dqsqrt\(dq box - | box pos box - | box mark - | \(dqmatrix\(dq \(dq{\(dq [col \(dq{\(dq list \(dq}\(dq ]* - | pile \(dq{\(dq list \(dq}\(dq - | font box - | \(dqsize\(dq text box - | \(dqleft\(dq text eqn [\(dqright\(dq text] -col : \(dqlcol\(dq | \(dqrcol\(dq | \(dqccol\(dq | \(dqcol\(dq -text : [^space\e\(dq]+ | \e\(dq.*\e\(dq -pile : \(dqlpile\(dq | \(dqcpile\(dq | \(dqrpile\(dq | \(dqpile\(dq -pos : \(dqover\(dq | \(dqsup\(dq | \(dqsub\(dq | \(dqto\(dq | \(dqfrom\(dq -mark : \(dqdot\(dq | \(dqdotdot\(dq | \(dqhat\(dq | \(dqtilde\(dq | \(dqvec\(dq - | \(dqdyad\(dq | \(dqbar\(dq | \(dqunder\(dq -font : \(dqroman\(dq | \(dqitalic\(dq | \(dqbold\(dq | \(dqfat\(dq -list : eqn - | list \(dqabove\(dq eqn -space : [\e^~ \et] -.Ed -.Pp -White-space consists of the space, tab, circumflex, and tilde -characters. -It is required to delimit tokens consisting of alphabetic characters -and it is ignored at other places. -Braces and quotes also delimit tokens. -If within a quoted string, these space characters are retained. -Quoted strings are also not scanned for keywords, glyph names, -and expansion of definitions. -To print a literal quote character, it can be prepended with a -backslash or expressed with the \e(dq escape sequence. -.Pp -Subequations can be enclosed in braces to pass them as arguments -to operation keywords, overriding standard operation precedence. -Braces can be nested. -To set a brace verbatim, it needs to be enclosed in quotes. -.Pp -The following text terms are translated into a rendered glyph, if -available: alpha, beta, chi, delta, epsilon, eta, gamma, iota, kappa, -lambda, mu, nu, omega, omicron, phi, pi, psi, rho, sigma, tau, theta, -upsilon, xi, zeta, DELTA, GAMMA, LAMBDA, OMEGA, PHI, PI, PSI, SIGMA, -THETA, UPSILON, XI, inter (intersection), union (union), prod (product), -int (integral), sum (summation), grad (gradient), del (vector -differential), times (multiply), cdot (center-dot), nothing (zero-width -space), approx (approximately equals), prime (prime), half (one-half), -partial (partial differential), inf (infinity), >> (much greater), << -(much less), <\- (left arrow), \-> (right arrow), +\- (plus-minus), != -(not equal), == (equivalence), <= (less-than-equal), and >= -(more-than-equal). -The character escape sequences documented in -.Xr mandoc_char 7 -can be used, too. -.Pp -The following control statements are available: -.Bl -tag -width Ds -.It Cm define -Replace all occurrences of a key with a value. -Its syntax is as follows: -.Pp -.D1 Cm define Ar key cvalc -.Pp -The first character of the value string, -.Ar c , -is used as the delimiter for the value -.Ar val . -This allows for arbitrary enclosure of terms (not just quotes), such as -.Pp -.D1 Cm define Ar foo \(aqbar baz\(aq -.D1 Cm define Ar foo cbar bazc -.Pp -It is an error to have an empty -.Ar key -or -.Ar val . -Note that a quoted -.Ar key -causes errors in some -.Nm -implementations and should not be considered portable. -It is not expanded for replacements. -Definitions may refer to other definitions; these are evaluated -recursively when text replacement occurs and not when the definition is -created. -.Pp -Definitions can create arbitrary strings, for example, the following is -a legal construction. -.Bd -literal -offset indent -define foo \(aqdefine\(aq -foo bar \(aqbaz\(aq -.Ed -.Pp -Self-referencing definitions will raise an error. -The -.Cm ndefine -statement is a synonym for -.Cm define , -while -.Cm tdefine -is discarded. -.It Cm gfont -Set the default font of subsequent output. -Its syntax is as follows: -.Pp -.D1 Cm gfont Ar font -.Pp -In mandoc, this value is discarded. -.It Cm gsize -Set the default size of subsequent output. -Its syntax is as follows: -.Pp -.D1 Cm gsize Oo +|\- Oc Ns Ar size -.Pp -The -.Ar size -value should be an integer. -If prepended by a sign, -the font size is changed relative to the current size. -.It Cm set -Set an equation mode. -In mandoc, both arguments are thrown away. -Its syntax is as follows: -.Pp -.D1 Cm set Ar key val -.Pp -The -.Ar key -and -.Ar val -are not expanded for replacements. -This statement is a GNU extension. -.It Cm undef -Unset a previously-defined key. -Its syntax is as follows: -.Pp -.D1 Cm define Ar key -.Pp -Once invoked, the definition for -.Ar key -is discarded. -The -.Ar key -is not expanded for replacements. -This statement is a GNU extension. -.El -.Pp -Operation keywords have the following semantics: -.Bl -tag -width Ds -.It Cm above -See -.Cm pile . -.It Cm bar -Draw a line over the preceding box. -.It Cm bold -Set the following box using bold font. -.It Cm ccol -Like -.Cm cpile , -but for use in -.Cm matrix . -.It Cm cpile -Like -.Cm pile , -but with slightly increased vertical spacing. -.It Cm dot -Set a single dot over the preceding box. -.It Cm dotdot -Set two dots (dieresis) over the preceding box. -.It Cm dyad -Set a dyad symbol (left-right arrow) over the preceding box. -.It Cm fat -A synonym for -.Cm bold . -.It Cm font -Set the second argument using the font specified by the first argument; -currently not recognized by the -.Xr mandoc 1 -.Nm -parser. -.It Cm from -Set the following box below the preceding box, -using a slightly smaller font. -Used for sums, integrals, limits, and the like. -.It Cm hat -Set a hat (circumflex) over the preceding box. -.It Cm italic -Set the following box using italic font. -.It Cm lcol -Like -.Cm lpile , -but for use in -.Cm matrix . -.It Cm left -Set the first argument as a big left delimiter before the second argument. -As an optional third argument, -.Cm right -can follow. -In that case, the fourth argument is set as a big right delimiter after -the second argument. -.It Cm lpile -Like -.Cm cpile , -but subequations are left-justified. -.It Cm matrix -Followed by a list of columns enclosed in braces. -All columns need to have the same number of subequations. -The columns are set as a matrix. -The difference compared to multiple subsequent -.Cm pile -operators is that in a -.Cm matrix , -corresponding subequations in all columns line up horizontally, -while each -.Cm pile -does vertical spacing independently. -.It Cm over -Set a fraction. -The preceding box is the numerator, the following box is the denominator. -.It Cm pile -Followed by a list of subequations enclosed in braces, -the subequations being separated by -.Cm above -keywords. -Sets the subequations one above the other, each of them centered. -Typically used to represent vectors in coordinate representation. -.It Cm rcol -Like -.Cm rpile , -but for use in -.Cm matrix . -.It Cm right -See -.Cm left ; -.Cm right -cannot be used without -.Cm left . -To set a big right delimiter without a big left delimiter, the following -construction can be used: -.Pp -.D1 Cm left No \(dq\(dq Ar box Cm right Ar delimiter -.It Cm roman -Set the following box using the default font. -.It Cm rpile -Like -.Cm cpile , -but subequations are right-justified. -.It Cm size -Set the second argument with the font size specified by the first -argument; currently ignored by -.Xr mandoc 1 . -By prepending a plus or minus sign to the first argument, -the font size can be selected relative to the current size. -.It Cm sqrt -Set the square root of the following box. -.It Cm sub -Set the following box as a subscript to the preceding box. -.It Cm sup -Set the following box as a superscript to the preceding box. -As a special case, if a -.Cm sup -clause immediately follows a -.Cm sub -clause as in -.Pp -.D1 Ar mainbox Cm sub Ar subbox Cm sup Ar supbox -.Pp -both are set with respect to the same -.Ar mainbox , -that is, -.Ar supbox -is set above -.Ar subbox . -.It Cm tilde -Set a tilde over the preceding box. -.It Cm to -Set the following box above the preceding box, -using a slightly smaller font. -Used for sums and integrals and the like. -As a special case, if a -.Cm to -clause immediately follows a -.Cm from -clause as in -.Pp -.D1 Ar mainbox Cm from Ar frombox Cm to Ar tobox -.Pp -both are set below and above the same -.Ar mainbox . -.It Cm under -Underline the preceding box. -.It Cm vec -Set a vector symbol (right arrow) over the preceding box. -.El -.Pp -The binary operations -.Cm from , -.Cm to , -.Cm sub , -and -.Cm sup -group to the right, that is, -.Pp -.D1 Ar mainbox Cm sup Ar supbox Cm sub Ar subbox -.Pp -is the same as -.Pp -.D1 Ar mainbox Cm sup Brq Ar supbox Cm sub Ar subbox -.Pp -and different from -.Pp -.D1 Bro Ar mainbox Cm sup Ar supbox Brc Cm sub Ar subbox . -.Pp -By contrast, -.Cm over -groups to the left. -.Pp -In the following list, earlier operations bind more tightly than -later operations: -.Pp -.Bl -enum -compact -.It -.Cm dyad , -.Cm vec , -.Cm under , -.Cm bar , -.Cm tilde , -.Cm hat , -.Cm dot , -.Cm dotdot -.It -.Cm fat , -.Cm roman , -.Cm italic , -.Cm bold , -.Cm size -.It -.Cm sub , -.Cm sup -.It -.Cm sqrt -.It -.Cm over -.It -.Cm from , -.Cm to -.El -.Sh COMPATIBILITY -This section documents the compatibility of mandoc -.Nm -and the troff -.Nm -implementation (including GNU troff). -.Pp -.Bl -dash -compact -.It -The text string -.Sq \e\(dq -is interpreted as a literal quote in troff. -In mandoc, this is interpreted as a comment. -.It -In troff, The circumflex and tilde white-space symbols map to -fixed-width spaces. -In mandoc, these characters are synonyms for the space character. -.It -The troff implementation of -.Nm -allows for equation alignment with the -.Cm mark -and -.Cm lineup -tokens. -mandoc discards these tokens. -The -.Cm back Ar n , -.Cm fwd Ar n , -.Cm up Ar n , -and -.Cm down Ar n -commands are also ignored. -.El -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr man 7 , -.Xr mandoc_char 7 , -.Xr mdoc 7 , -.Xr roff 7 -.Rs -.%A Brian W. Kernighan -.%A Lorinda L. Cherry -.%T System for Typesetting Mathematics -.%J Communications of the ACM -.%V 18 -.%P 151\(en157 -.%D March, 1975 -.Re -.Rs -.%A Brian W. Kernighan -.%A Lorinda L. Cherry -.%T Typesetting Mathematics, User's Guide -.%D 1976 -.Re -.Rs -.%A Brian W. Kernighan -.%A Lorinda L. Cherry -.%T Typesetting Mathematics, User's Guide (Second Edition) -.%D 1978 -.Re -.Sh HISTORY -The eqn utility, a preprocessor for troff, was originally written by -Brian W. Kernighan and Lorinda L. Cherry in 1975. -The GNU reimplementation of eqn, part of the GNU troff package, was -released in 1989 by James Clark. -The eqn component of -.Xr mandoc 1 -was added in 2011. -.Sh AUTHORS -This -.Nm -reference was written by -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . Property changes on: head/contrib/mdocml/eqn.7 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/apropos.1 =================================================================== --- head/contrib/mdocml/apropos.1 (revision 338825) +++ head/contrib/mdocml/apropos.1 (nonexistent) @@ -1,486 +0,0 @@ -.\" $Id: apropos.1,v 1.46 2017/07/04 23:40:01 schwarze Exp $ -.\" -.\" Copyright (c) 2011, 2012 Kristaps Dzonsons -.\" Copyright (c) 2011, 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: August 8 2018 $ -.Dt APROPOS 1 -.Os -.Sh NAME -.Nm apropos , -.Nm whatis -.Nd search manual page databases -.Sh SYNOPSIS -.Nm -.Op Fl afk -.Op Fl C Ar file -.Op Fl M Ar path -.Op Fl m Ar path -.Op Fl O Ar outkey -.Op Fl S Ar arch -.Op Fl s Ar section -.Ar expression ... -.Sh DESCRIPTION -The -.Nm apropos -and -.Nm whatis -utilities query manual page databases generated by -.Xr makewhatis 8 , -evaluating -.Ar expression -for each file in each database. -By default, they display the names, section numbers, and description lines -of all matching manuals. -.Pp -By default, -.Nm -searches for -.Xr makewhatis 8 -databases in the default paths stipulated by -.Xr man 1 -and uses case-insensitive substring matching -.Pq the Cm = No operator -over manual names and descriptions -.Pq the Li \&Nm No and Li \&Nd No macro keys . -Multiple terms imply pairwise -.Fl o . -.Pp -.Nm whatis -is a synonym for -.Nm -.Fl f . -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl a -Instead of showing only the title lines, show the complete manual pages, -just like -.Xr man 1 -.Fl a -would. -If the standard output is a terminal device and -.Fl c -is not specified, use -.Xr less 1 -to paginate them. -In -.Fl a -mode, the options -.Fl IKOTW -described in the -.Xr mandoc 1 -manual are also available. -.It Fl C Ar file -Specify an alternative configuration -.Ar file -in -.Xr man.conf 5 -format. -.It Fl f -Search for all words in -.Ar expression -in manual page names only. -The search is case insensitive and matches whole words only. -In this mode, macro keys, comparison operators, and logical operators -are not available. -.It Fl k -Support the full -.Ar expression -syntax. -It is the default for -.Nm . -.It Fl M Ar path -Use the colon-separated path instead of the default list of paths -searched for -.Xr makewhatis 8 -databases. -Invalid paths, or paths without manual databases, are ignored. -.It Fl m Ar path -Prepend the colon-separated paths to the list of paths searched -for -.Xr makewhatis 8 -databases. -Invalid paths, or paths without manual databases, are ignored. -.It Fl O Ar outkey -Show the values associated with the key -.Ar outkey -instead of the manual descriptions. -.It Fl S Ar arch -Restrict the search to pages for the specified -.Xr machine 1 -architecture. -.Ar arch -is case insensitive. -By default, pages for all architectures are shown. -.It Fl s Ar section -Restrict the search to the specified section of the manual. -By default, pages from all sections are shown. -See -.Xr man 1 -for a listing of sections. -.El -.Pp -The options -.Fl chlw -are also supported and are documented in -.Xr man 1 . -The options -.Fl fkl -are mutually exclusive and override each other. -.Pp -An -.Ar expression -consists of search terms joined by logical operators -.Fl a -.Pq and -and -.Fl o -.Pq or . -The -.Fl a -operator has precedence over -.Fl o -and both are evaluated left-to-right. -.Bl -tag -width Ds -.It \&( Ar expr No \&) -True if the subexpression -.Ar expr -is true. -.It Ar expr1 Fl a Ar expr2 -True if both -.Ar expr1 -and -.Ar expr2 -are true (logical -.Sq and ) . -.It Ar expr1 Oo Fl o Oc Ar expr2 -True if -.Ar expr1 -and/or -.Ar expr2 -evaluate to true (logical -.Sq or ) . -.It Ar term -True if -.Ar term -is satisfied. -This has syntax -.Sm off -.Oo -.Op Ar key Op , Ar key ... -.Pq Cm = | \(ti -.Oc -.Ar val , -.Sm on -where -.Ar key -is an -.Xr mdoc 7 -macro to query and -.Ar val -is its value. -See -.Sx Macro Keys -for a list of available keys. -Operator -.Cm = -evaluates a substring, while -.Cm \(ti -evaluates a regular expression. -.It Fl i Ar term -If -.Ar term -is a regular expression, it -is evaluated case-insensitively. -Has no effect on substring terms. -.El -.Pp -Results are sorted according to the following criteria: -.Bl -enum -.It -The manpath directory tree the page is found in, according to the -order specified with -.Fl M , -.Fl m , -the -.Ev MANPATH -environment variable, the -.Xr man.conf 5 -configuration file, or the default documented in -.Xr man.conf 5 . -.It -The section number in ascending numerical order. -.It -The page name in ascending -.Xr ascii 7 -alphabetical order, case-insensitive. -.El -.Pp -Each output line is formatted as -.Pp -.D1 name[, name...](sec) \- description -.Pp -Where -.Dq name -is the manual's name, -.Dq sec -is the manual section, and -.Dq description -is the manual's short description. -If an architecture is specified for the manual, it is displayed as -.Pp -.D1 name(sec/arch) \- description -.Pp -Resulting manuals may be accessed as -.Pp -.Dl $ man \-s sec name -.Pp -If an architecture is specified in the output, use -.Pp -.Dl $ man \-s sec \-S arch name -.Ss Macro Keys -Queries evaluate over a subset of -.Xr mdoc 7 -macros indexed by -.Xr makewhatis 8 . -In addition to the macro keys listed below, the special key -.Cm any -may be used to match any available macro key. -.Pp -Names and description: -.Bl -column "xLix" description -offset indent -compact -.It Li \&Nm Ta manual name -.It Li \&Nd Ta one-line manual description -.It Li arch Ta machine architecture (case-insensitive) -.It Li sec Ta manual section number -.El -.Pp -Sections and cross references: -.Bl -column "xLix" description -offset indent -compact -.It Li \&Sh Ta section header (excluding standard sections) -.It Li \&Ss Ta subsection header -.It Li \&Xr Ta cross reference to another manual page -.It Li \&Rs Ta bibliographic reference -.El -.Pp -Semantic markup for command line utilities: -.Bl -column "xLix" description -offset indent -compact -.It Li \&Fl Ta command line options (flags) -.It Li \&Cm Ta command modifier -.It Li \&Ar Ta command argument -.It Li \&Ic Ta internal or interactive command -.It Li \&Ev Ta environmental variable -.It Li \&Pa Ta file system path -.El -.Pp -Semantic markup for function libraries: -.Bl -column "xLix" description -offset indent -compact -.It Li \&Lb Ta function library name -.It Li \&In Ta include file -.It Li \&Ft Ta function return type -.It Li \&Fn Ta function name -.It Li \&Fa Ta function argument type and name -.It Li \&Vt Ta variable type -.It Li \&Va Ta variable name -.It Li \&Dv Ta defined variable or preprocessor constant -.It Li \&Er Ta error constant -.It Li \&Ev Ta environmental variable -.El -.Pp -Various semantic markup: -.Bl -column "xLix" description -offset indent -compact -.It Li \&An Ta author name -.It Li \&Lk Ta hyperlink -.It Li \&Mt Ta Do mailto Dc hyperlink -.It Li \&Cd Ta kernel configuration declaration -.It Li \&Ms Ta mathematical symbol -.It Li \&Tn Ta tradename -.El -.Pp -Physical markup: -.Bl -column "xLix" description -offset indent -compact -.It Li \&Em Ta italic font or underline -.It Li \&Sy Ta boldface font -.It Li \&Li Ta typewriter font -.El -.Pp -Text production: -.Bl -column "xLix" description -offset indent -compact -.It Li \&St Ta reference to a standards document -.It Li \&At Ta At No version reference -.It Li \&Bx Ta Bx No version reference -.It Li \&Bsx Ta Bsx No version reference -.It Li \&Nx Ta Nx No version reference -.It Li \&Fx Ta Fx No version reference -.It Li \&Ox Ta Ox No version reference -.It Li \&Dx Ta Dx No version reference -.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 less 1 ; -see -.Xr man 1 -for details. -Only used if -.Fl a -or -.Fl l -is specified. -.It Ev MANPATH -A colon-separated list of directories to search for manual pages; see -.Xr man 1 -for details. -Overridden by -.Fl M , -ignored if -.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 less 1 -.Fl s -is used. -Only used if -.Fl a -or -.Fl l -is specified. -.El -.Sh FILES -.Bl -tag -width "/etc/man.conf" -compact -.It Pa mandoc.db -name of the -.Xr makewhatis 8 -keyword database -.It Pa /etc/man.conf -default -.Xr man 1 -configuration file -.El -.Sh EXIT STATUS -.Ex -std -.Sh EXAMPLES -Search for -.Qq .cf -as a substring of manual names and descriptions: -.Pp -.Dl $ apropos .cf -.Pp -Include matches for -.Qq .cnf -and -.Qq .conf -as well: -.Pp -.Dl $ apropos .cf .cnf .conf -.Pp -Search in names and descriptions using a regular expression: -.Pp -.Dl $ apropos \(aq\(tiset.?[ug]id\(aq -.Pp -Search for manuals in the library section mentioning both the -.Qq optind -and the -.Qq optarg -variables: -.Pp -.Dl $ apropos \-s 3 Va=optind \-a Va=optarg -.Pp -Do exactly the same as calling -.Nm whatis -with the argument -.Qq ssh : -.Pp -.Dl $ apropos \-\- \-i \(aqNm\(ti[[:<:]]ssh[[:>:]]\(aq -.Pp -The following two invocations are equivalent: -.Pp -.D1 Li $ apropos -S Ar arch Li -s Ar section expression -.Bd -ragged -offset indent -.Li $ apropos \e( Ar expression Li \e) -.Li -a arch\(ti^( Ns Ar arch Ns Li |any)$ -.Li -a sec\(ti^ Ns Ar section Ns Li $ -.Ed -.Sh SEE ALSO -.Xr man 1 , -.Xr re_format 7 , -.Xr makewhatis 8 -.Sh HISTORY -Part of the functionality of -.Nm whatis -was already provided by the former -.Nm manwhere -utility in -.Bx 1 . -The -.Nm -and -.Nm whatis -utilities first appeared in -.Bx 2 . -They were rewritten from scratch for -.Ox 5.6 . -.Pp -The -.Fl M -option and the -.Ev MANPATH -variable first appeared in -.Bx 4.3 ; -.Fl m -in -.Bx 4.3 Reno ; -.Fl C -in -.Bx 4.4 Lite1 ; -and -.Fl S -and -.Fl s -in -.Ox 4.5 -for -.Nm -and in -.Ox 5.6 -for -.Nm whatis . -The options -.Fl acfhIKklOTWw -appeared in -.Ox 5.7 . -.Sh AUTHORS -.An -nosplit -.An Bill Joy -wrote -.Nm manwhere -in 1977 and the original -.Bx -.Nm -and -.Nm whatis -in February 1979. -The current version was written by -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv -and -.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: head/contrib/mdocml/apropos.1 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/dba_write.c =================================================================== --- head/contrib/mdocml/dba_write.c (revision 338825) +++ head/contrib/mdocml/dba_write.c (nonexistent) @@ -1,127 +0,0 @@ -/* $Id: dba_write.c,v 1.3 2016/08/05 23:15:08 schwarze Exp $ */ -/* - * Copyright (c) 2016 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. - * - * Low-level functions for serializing allocation-based data to disk. - * The interface is defined in "dba_write.h". - */ -#include "config.h" - -#include -#if HAVE_ENDIAN -#include -#elif HAVE_SYS_ENDIAN -#include -#elif HAVE_NTOHL -#include -#endif -#if HAVE_ERR -#include -#endif -#include -#include -#include -#include - -#include "dba_write.h" - -static FILE *ofp; - - -int -dba_open(const char *fname) -{ - ofp = fopen(fname, "w"); - return ofp == NULL ? -1 : 0; -} - -int -dba_close(void) -{ - return fclose(ofp) == EOF ? -1 : 0; -} - -int32_t -dba_tell(void) -{ - long pos; - - if ((pos = ftell(ofp)) == -1) - err(1, "ftell"); - if (pos >= INT32_MAX) { - errno = EOVERFLOW; - err(1, "ftell = %ld", pos); - } - return pos; -} - -void -dba_seek(int32_t pos) -{ - if (fseek(ofp, pos, SEEK_SET) == -1) - err(1, "fseek(%d)", pos); -} - -int32_t -dba_align(void) -{ - int32_t pos; - - pos = dba_tell(); - while (pos & 3) { - dba_char_write('\0'); - pos++; - } - return pos; -} - -int32_t -dba_skip(int32_t nmemb, int32_t sz) -{ - const int32_t out[5] = {0, 0, 0, 0, 0}; - int32_t i, pos; - - assert(sz >= 0); - assert(nmemb > 0); - assert(nmemb <= 5); - pos = dba_tell(); - for (i = 0; i < sz; i++) - if (nmemb - fwrite(&out, sizeof(out[0]), nmemb, ofp)) - err(1, "fwrite"); - return pos; -} - -void -dba_char_write(int c) -{ - if (putc(c, ofp) == EOF) - err(1, "fputc"); -} - -void -dba_str_write(const char *str) -{ - if (fputs(str, ofp) == EOF) - err(1, "fputs"); - dba_char_write('\0'); -} - -void -dba_int_write(int32_t i) -{ - i = htobe32(i); - if (fwrite(&i, sizeof(i), 1, ofp) != 1) - err(1, "fwrite"); -} Property changes on: head/contrib/mdocml/dba_write.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/man.1 =================================================================== --- head/contrib/mdocml/man.1 (revision 338825) +++ head/contrib/mdocml/man.1 (nonexistent) @@ -1,384 +0,0 @@ -.\" $Id: man.1,v 1.29 2017/05/17 23:23:00 schwarze Exp $ -.\" -.\" Copyright (c) 1989, 1990, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre -.\" Copyright (c) 2010, 2011, 2014-2017 Ingo Schwarze -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)man.1 8.2 (Berkeley) 1/2/94 -.\" -.Dd $Mdocdate: August 8 2018 $ -.Dt MAN 1 -.Os -.Sh NAME -.Nm man -.Nd display manual pages -.Sh SYNOPSIS -.Nm man -.Op Fl acfhklw -.Op Fl C Ar file -.Op Fl M Ar path -.Op Fl m Ar path -.Op Fl S Ar subsection -.Op Oo Fl s Oc Ar section -.Ar name ... -.Sh DESCRIPTION -The -.Nm -utility -displays the -manual pages entitled -.Ar name . -Pages may be selected according to -a specific category -.Pq Ar section -or -machine architecture -.Pq Ar subsection . -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl a -Display all matching manual pages. -Normally, only the first page found is displayed. -.It Fl C Ar file -Use the specified -.Ar file -instead of the default configuration file. -This permits users to configure their own manual environment. -See -.Xr man.conf 5 -for a description of the contents of this file. -.It Fl c -Copy the manual page to the standard output instead of using -.Xr less 1 -to paginate it. -This is done by default if the standard output is not a terminal device. -.It Fl f -A synonym for -.Xr whatis 1 . -It searches for -.Ar name -in manual page names and displays the header lines from all matching pages. -The search is case insensitive and matches whole words only. -.It Fl h -Display only the SYNOPSIS lines of the requested manual pages. -Implies -.Fl a -and -.Fl c . -.It Fl k -A synonym for -.Xr apropos 1 . -Instead of -.Ar name , -an expression can be provided using the syntax described in the -.Xr apropos 1 -manual. -By default, it displays the header lines of all matching pages. -.It Fl l -A synonym for -.Xr mandoc 1 -.Fl a . -The -.Ar name -arguments are interpreted as filenames. -No search is done and -.Ar file , -.Ar path , -.Ar section , -.Ar subsection , -and -.Fl w -are ignored. -.It Fl M Ar path -Override the list of standard directories which -.Nm -searches for manual pages. -The supplied -.Ar path -must be a colon -.Pq Ql \&: -separated list of directories. -This search path may also be set using the environment variable -.Ev MANPATH . -.It Fl m Ar path -Augment the list of standard directories which -.Nm -searches for manual pages. -The supplied -.Ar path -must be a colon -.Pq Ql \&: -separated list of directories. -These directories will be searched before the standard directories or -the directories specified using the -.Fl M -option or the -.Ev MANPATH -environment variable. -.It Fl S Ar subsection -Only show pages for the specified -.Xr machine 1 -architecture. -.Ar subsection -is case insensitive. -.Pp -By default manual pages for all architectures are installed. -Therefore this option can be used to view pages for one -architecture whilst using another. -.Pp -This option overrides the -.Ev MACHINE -environment variable. -.It Oo Fl s Oc Ar section -Only select manuals from the specified -.Ar section . -The currently available sections are: -.Pp -.Bl -tag -width "localXXX" -offset indent -compact -.It 1 -General commands -.Pq tools and utilities . -.It 2 -System calls and error numbers. -.It 3 -Library functions. -.It 3p -.Xr perl 1 -programmer's reference guide. -.It 4 -Device drivers. -.It 5 -File formats. -.It 6 -Games. -.It 7 -Miscellaneous information. -.It 8 -System maintenance and operation commands. -.It 9 -Kernel internals. -.El -.Pp -If not specified and a match is found in more than one section, -the first match is selected from the following list: -1, 8, 6, 2, 3, 5, 7, 4, 9, 3p. -.It Fl w -List the pathnames of all matching manual pages instead of displaying -any of them. -.El -.Pp -The options -.Fl IKOTW -are also supported and are documented in -.Xr mandoc 1 . -The options -.Fl fkl -are mutually exclusive and override each other. -.Pp -Guidelines for writing -man pages can be found in -.Xr mdoc 7 . -.Pp -If both a formatted and an unformatted version of the same manual page, -for example -.Pa cat1/foo.0 -and -.Pa man1/foo.1 , -exist in the same directory, only the unformatted version is used. -.Sh ENVIRONMENT -.Bl -tag -width MANPATHX -.It Ev MACHINE -As some manual pages are intended only for specific architectures, -.Nm -searches any subdirectories, -with the same name as the current architecture, -in every directory which it searches. -Machine specific areas are checked before general areas. -The current machine type may be overridden by setting the environment -variable -.Ev MACHINE -to the name of a specific architecture, -or with the -.Fl S -option. -.Ev MACHINE -is case insensitive. -.It Ev MANPAGER -Any non-empty value of the environment variable -.Ev MANPAGER -is used instead of the standard pagination program, -.Xr less 1 . -If -.Xr less 1 -is used, the interactive -.Ic :t -command can be used to go to the definitions of various terms, for -example command line options, command modifiers, internal commands, -environment variables, function names, preprocessor macros, -.Xr errno 2 -values, and some other emphasized words. -Some terms may have defining text at more than one place. -In that case, the -.Xr less 1 -interactive commands -.Ic t -and -.Ic T -can be used to move to the next and to the previous place providing -information about the term last searched for with -.Ic :t . -.It Ev MANPATH -The standard search path used by -.Nm -may be changed by specifying a path in the -.Ev MANPATH -environment variable. -The format of the path is a colon -.Pq Ql \&: -separated list of directories. -Invalid paths are ignored. -Overridden by -.Fl M , -ignored if -.Fl l -is specified. -.Pp -If -.Ev MANPATH -begins with a colon, it is appended to the default list; -if it ends with a colon, it is prepended to the default list; -or if it contains two adjacent colons, -the standard search path is inserted between the colons. -If none of these conditions are met, it overrides the -standard search path. -.It Ev PAGER -Specifies the pagination program to use when -.Ev MANPAGER -is not defined. -If neither PAGER nor MANPAGER is defined, -.Xr less 1 -.Fl s -is used. -Only used if -.Fl a -or -.Fl l -is specified. -.El -.Sh FILES -.Bl -tag -width /etc/man.conf -compact -.It Pa /etc/man.conf -default man configuration file -.El -.Sh EXIT STATUS -.Ex -std man -See -.Xr mandoc 1 -for details. -.Sh SEE ALSO -.Xr apropos 1 , -.Xr intro 1 , -.Xr whereis 1 , -.Xr intro 2 , -.Xr intro 3 , -.Xr intro 4 , -.Xr intro 5 , -.Xr man.conf 5 , -.Xr intro 6 , -.Xr intro 7 , -.Xr mdoc 7 , -.Xr intro 8 , -.Xr intro 9 -.Sh STANDARDS -The -.Nm -utility is compliant with the -.St -p1003.1-2008 -specification. -.Pp -The flags -.Op Fl aCcfhIKlMmOSsTWw , -as well as the environment variables -.Ev MACHINE , -.Ev MANPAGER , -and -.Ev MANPATH , -are extensions to that specification. -.Sh HISTORY -A -.Nm -command first appeared in -.At v3 . -.Pp -The -.Fl w -option first appeared in -.At v7 ; -.Fl f -and -.Fl k -in -.Bx 4 ; -.Fl M -in -.Bx 4.3 ; -.Fl a -in -.Bx 4.3 Tahoe ; -.Fl c -and -.Fl m -in -.Bx 4.3 Reno ; -.Fl h -in -.Bx 4.3 Net/2 ; -.Fl C -in -.Nx 1.0 ; -.Fl s -and -.Fl S -in -.Ox 2.3 ; -and -.Fl I , -.Fl K , -.Fl l , -.Fl O , -and -.Fl W -in -.Ox 5.7 . -The -.Fl T -option first appeared in -.At III -and was also added in -.Ox 5.7 . Property changes on: head/contrib/mdocml/man.1 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/dba_write.h =================================================================== --- head/contrib/mdocml/dba_write.h (revision 338825) +++ head/contrib/mdocml/dba_write.h (nonexistent) @@ -1,30 +0,0 @@ -/* $Id: dba_write.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */ -/* - * Copyright (c) 2016 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. - * - * Internal interface to low-level functions - * for serializing allocation-based data to disk. - * For use by dba_array.c and dba.c only. - */ - -int dba_open(const char *); -int dba_close(void); -int32_t dba_tell(void); -void dba_seek(int32_t); -int32_t dba_align(void); -int32_t dba_skip(int32_t, int32_t); -void dba_char_write(int); -void dba_str_write(const char *); -void dba_int_write(int32_t); Property changes on: head/contrib/mdocml/dba_write.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_strlcpy.c =================================================================== --- head/contrib/mdocml/compat_strlcpy.c (revision 338825) +++ head/contrib/mdocml/compat_strlcpy.c (nonexistent) @@ -1,61 +0,0 @@ -#include "config.h" - -#if HAVE_STRLCPY - -int dummy; - -#else - -/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * 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 -#include - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t -strlcpy(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = *s++) == '\0') - break; - } - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} - -#endif Property changes on: head/contrib/mdocml/compat_strlcpy.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/man.7 =================================================================== --- head/contrib/mdocml/man.7 (revision 338825) +++ head/contrib/mdocml/man.7 (nonexistent) @@ -1,915 +0,0 @@ -.\" $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: 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. Property changes on: head/contrib/mdocml/man.7 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-strtonum.c =================================================================== --- head/contrib/mdocml/test-strtonum.c (revision 338825) +++ head/contrib/mdocml/test-strtonum.c (nonexistent) @@ -1,42 +0,0 @@ -/* $Id: test-strtonum.c,v 1.2 2015/10/06 18:32:20 schwarze Exp $ */ -/* - * Copyright (c) 2015 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. - */ - -#include - -int -main(void) -{ - const char *errstr; - - if (strtonum("1", 0, 2, &errstr) != 1) - return 1; - if (errstr != NULL) - return 2; - if (strtonum("1x", 0, 2, &errstr) != 0) - return 3; - if (errstr == NULL) - return 4; - if (strtonum("2", 0, 1, &errstr) != 0) - return 5; - if (errstr == NULL) - return 6; - if (strtonum("0", 1, 2, &errstr) != 0) - return 7; - if (errstr == NULL) - return 8; - return 0; -} Property changes on: head/contrib/mdocml/test-strtonum.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tbl_layout.c =================================================================== --- head/contrib/mdocml/tbl_layout.c (revision 338825) +++ head/contrib/mdocml/tbl_layout.c (nonexistent) @@ -1,375 +0,0 @@ -/* $Id: tbl_layout.c,v 1.44 2017/06/27 18:25:02 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2012, 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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include -#include - -#include "mandoc.h" -#include "mandoc_aux.h" -#include "libmandoc.h" -#include "libroff.h" - -struct tbl_phrase { - char name; - enum tbl_cellt key; -}; - -static const struct tbl_phrase keys[] = { - { 'c', TBL_CELL_CENTRE }, - { 'r', TBL_CELL_RIGHT }, - { 'l', TBL_CELL_LEFT }, - { 'n', TBL_CELL_NUMBER }, - { 's', TBL_CELL_SPAN }, - { 'a', TBL_CELL_LONG }, - { '^', TBL_CELL_DOWN }, - { '-', TBL_CELL_HORIZ }, - { '_', TBL_CELL_HORIZ }, - { '=', TBL_CELL_DHORIZ } -}; - -#define KEYS_MAX ((int)(sizeof(keys)/sizeof(keys[0]))) - -static void mods(struct tbl_node *, struct tbl_cell *, - int, const char *, int *); -static void cell(struct tbl_node *, struct tbl_row *, - int, const char *, int *); -static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *, - enum tbl_cellt); - - -static void -mods(struct tbl_node *tbl, struct tbl_cell *cp, - int ln, const char *p, int *pos) -{ - char *endptr; - size_t sz; - -mod: - while (p[*pos] == ' ' || p[*pos] == '\t') - (*pos)++; - - /* Row delimiters and cell specifiers end modifier lists. */ - - if (strchr(".,-=^_ACLNRSaclnrs", p[*pos]) != NULL) - return; - - /* Throw away parenthesised expression. */ - - if ('(' == p[*pos]) { - (*pos)++; - while (p[*pos] && ')' != p[*pos]) - (*pos)++; - if (')' == p[*pos]) { - (*pos)++; - goto mod; - } - mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse, - ln, *pos, NULL); - return; - } - - /* Parse numerical spacing from modifier string. */ - - if (isdigit((unsigned char)p[*pos])) { - cp->spacing = strtoull(p + *pos, &endptr, 10); - *pos = endptr - p; - goto mod; - } - - switch (tolower((unsigned char)p[(*pos)++])) { - case 'b': - cp->flags |= TBL_CELL_BOLD; - goto mod; - case 'd': - cp->flags |= TBL_CELL_BALIGN; - goto mod; - case 'e': - cp->flags |= TBL_CELL_EQUAL; - goto mod; - case 'f': - break; - case 'i': - cp->flags |= TBL_CELL_ITALIC; - goto mod; - case 'm': - mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse, - ln, *pos, "m"); - goto mod; - case 'p': - case 'v': - if (p[*pos] == '-' || p[*pos] == '+') - (*pos)++; - while (isdigit((unsigned char)p[*pos])) - (*pos)++; - goto mod; - case 't': - cp->flags |= TBL_CELL_TALIGN; - goto mod; - case 'u': - cp->flags |= TBL_CELL_UP; - goto mod; - case 'w': - sz = 0; - if (p[*pos] == '(') { - (*pos)++; - while (p[*pos + sz] != '\0' && p[*pos + sz] != ')') - sz++; - } else - while (isdigit((unsigned char)p[*pos + sz])) - sz++; - if (sz) { - free(cp->wstr); - cp->wstr = mandoc_strndup(p + *pos, sz); - *pos += sz; - if (p[*pos] == ')') - (*pos)++; - } - goto mod; - case 'x': - cp->flags |= TBL_CELL_WMAX; - goto mod; - case 'z': - cp->flags |= TBL_CELL_WIGN; - goto mod; - case '|': - if (cp->vert < 2) - cp->vert++; - else - mandoc_msg(MANDOCERR_TBLLAYOUT_VERT, - tbl->parse, ln, *pos - 1, NULL); - goto mod; - default: - mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse, - ln, *pos - 1, "%c", p[*pos - 1]); - goto mod; - } - - /* Ignore parenthised font names for now. */ - - if (p[*pos] == '(') - goto mod; - - /* Support only one-character font-names for now. */ - - if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) { - mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse, - ln, *pos, "TS %s", p + *pos - 1); - if (p[*pos] != '\0') - (*pos)++; - if (p[*pos] != '\0') - (*pos)++; - goto mod; - } - - switch (p[(*pos)++]) { - case '3': - case 'B': - cp->flags |= TBL_CELL_BOLD; - goto mod; - case '2': - case 'I': - cp->flags |= TBL_CELL_ITALIC; - goto mod; - case '1': - case 'R': - goto mod; - default: - mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse, - ln, *pos - 1, "TS f%c", p[*pos - 1]); - goto mod; - } -} - -static void -cell(struct tbl_node *tbl, struct tbl_row *rp, - int ln, const char *p, int *pos) -{ - int i; - enum tbl_cellt c; - - /* Handle leading vertical lines */ - - while (p[*pos] == ' ' || p[*pos] == '\t' || p[*pos] == '|') { - if (p[*pos] == '|') { - if (rp->vert < 2) - rp->vert++; - else - mandoc_msg(MANDOCERR_TBLLAYOUT_VERT, - tbl->parse, ln, *pos, NULL); - } - (*pos)++; - } - -again: - while (p[*pos] == ' ' || p[*pos] == '\t') - (*pos)++; - - if (p[*pos] == '.' || p[*pos] == '\0') - return; - - /* Parse the column position (`c', `l', `r', ...). */ - - for (i = 0; i < KEYS_MAX; i++) - if (tolower((unsigned char)p[*pos]) == keys[i].name) - break; - - if (i == KEYS_MAX) { - mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse, - ln, *pos, "%c", p[*pos]); - (*pos)++; - goto again; - } - c = keys[i].key; - - /* Special cases of spanners. */ - - if (c == TBL_CELL_SPAN) { - if (rp->last == NULL) - mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, - tbl->parse, ln, *pos, NULL); - else if (rp->last->pos == TBL_CELL_HORIZ || - rp->last->pos == TBL_CELL_DHORIZ) - c = rp->last->pos; - } else if (c == TBL_CELL_DOWN && rp == tbl->first_row) - mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, - tbl->parse, ln, *pos, NULL); - - (*pos)++; - - /* Allocate cell then parse its modifiers. */ - - mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos); -} - -void -tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos) -{ - struct tbl_row *rp; - - rp = NULL; - for (;;) { - /* Skip whitespace before and after each cell. */ - - while (p[pos] == ' ' || p[pos] == '\t') - pos++; - - switch (p[pos]) { - case ',': /* Next row on this input line. */ - pos++; - rp = NULL; - continue; - case '\0': /* Next row on next input line. */ - return; - case '.': /* End of layout. */ - pos++; - tbl->part = TBL_PART_DATA; - - /* - * When the layout is completely empty, - * default to one left-justified column. - */ - - if (tbl->first_row == NULL) { - tbl->first_row = tbl->last_row = - mandoc_calloc(1, sizeof(*rp)); - } - if (tbl->first_row->first == NULL) { - mandoc_msg(MANDOCERR_TBLLAYOUT_NONE, - tbl->parse, ln, pos, NULL); - cell_alloc(tbl, tbl->first_row, - TBL_CELL_LEFT); - if (tbl->opts.lvert < tbl->first_row->vert) - tbl->opts.lvert = tbl->first_row->vert; - return; - } - - /* - * Search for the widest line - * along the left and right margins. - */ - - for (rp = tbl->first_row; rp; rp = rp->next) { - if (tbl->opts.lvert < rp->vert) - tbl->opts.lvert = rp->vert; - if (rp->last != NULL && - rp->last->col + 1 == tbl->opts.cols && - tbl->opts.rvert < rp->last->vert) - tbl->opts.rvert = rp->last->vert; - - /* If the last line is empty, drop it. */ - - if (rp->next != NULL && - rp->next->first == NULL) { - free(rp->next); - rp->next = NULL; - tbl->last_row = rp; - } - } - return; - default: /* Cell. */ - break; - } - - /* - * If the last line had at least one cell, - * start a new one; otherwise, continue it. - */ - - if (rp == NULL) { - if (tbl->last_row == NULL || - tbl->last_row->first != NULL) { - rp = mandoc_calloc(1, sizeof(*rp)); - if (tbl->last_row) - tbl->last_row->next = rp; - else - tbl->first_row = rp; - tbl->last_row = rp; - } else - rp = tbl->last_row; - } - cell(tbl, rp, ln, p, &pos); - } -} - -static struct tbl_cell * -cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) -{ - struct tbl_cell *p, *pp; - - p = mandoc_calloc(1, sizeof(*p)); - p->spacing = SIZE_MAX; - p->pos = pos; - - if ((pp = rp->last) != NULL) { - pp->next = p; - p->col = pp->col + 1; - } else - rp->first = p; - rp->last = p; - - if (tbl->opts.cols <= p->col) - tbl->opts.cols = p->col + 1; - - return p; -} Property changes on: head/contrib/mdocml/tbl_layout.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/att.c =================================================================== --- head/contrib/mdocml/att.c (revision 338825) +++ head/contrib/mdocml/att.c (nonexistent) @@ -1,51 +0,0 @@ -/* $Id: att.c,v 1.16 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_a2att(const char *p) -{ - - LINE("v1", "Version\\~1 AT&T UNIX"); - LINE("v2", "Version\\~2 AT&T UNIX"); - LINE("v3", "Version\\~3 AT&T UNIX"); - LINE("v4", "Version\\~4 AT&T UNIX"); - LINE("v5", "Version\\~5 AT&T UNIX"); - LINE("v6", "Version\\~6 AT&T UNIX"); - LINE("v7", "Version\\~7 AT&T UNIX"); - LINE("32v", "Version\\~32V AT&T UNIX"); - LINE("III", "AT&T System\\~III UNIX"); - LINE("V", "AT&T System\\~V UNIX"); - LINE("V.1", "AT&T System\\~V Release\\~1 UNIX"); - LINE("V.2", "AT&T System\\~V Release\\~2 UNIX"); - LINE("V.3", "AT&T System\\~V Release\\~3 UNIX"); - LINE("V.4", "AT&T System\\~V Release\\~4 UNIX"); - - return NULL; -} Property changes on: head/contrib/mdocml/att.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-progname.c =================================================================== --- head/contrib/mdocml/test-progname.c (revision 338825) +++ head/contrib/mdocml/test-progname.c (nonexistent) @@ -1,10 +0,0 @@ -#include - -int -main(void) -{ - const char * progname; - - progname = getprogname(); - return progname == NULL; -} Property changes on: head/contrib/mdocml/test-progname.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tbl_opts.c =================================================================== --- head/contrib/mdocml/tbl_opts.c (revision 338825) +++ head/contrib/mdocml/tbl_opts.c (nonexistent) @@ -1,173 +0,0 @@ -/* $Id: tbl_opts.c,v 1.21 2015/09/26 00:54:04 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2015 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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include - -#include "mandoc.h" -#include "libmandoc.h" -#include "libroff.h" - -#define KEY_DPOINT 0 -#define KEY_DELIM 1 -#define KEY_LINESIZE 2 -#define KEY_TAB 3 - -struct tbl_phrase { - const char *name; - int key; -}; - -static const struct tbl_phrase keys[] = { - {"decimalpoint", 0}, - {"delim", 0}, - {"linesize", 0}, - {"tab", 0}, - {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX}, - {"box", TBL_OPT_BOX}, - {"frame", TBL_OPT_BOX}, - {"center", TBL_OPT_CENTRE}, - {"centre", TBL_OPT_CENTRE}, - {"doublebox", TBL_OPT_DBOX}, - {"doubleframe", TBL_OPT_DBOX}, - {"expand", TBL_OPT_EXPAND}, - {"nokeep", TBL_OPT_NOKEEP}, - {"nospaces", TBL_OPT_NOSPACE}, - {"nowarn", TBL_OPT_NOWARN}, -}; - -#define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0]))) - -static void arg(struct tbl_node *, int, const char *, int *, int); - - -static void -arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) -{ - int len, want; - - while (p[*pos] == ' ' || p[*pos] == '\t') - (*pos)++; - - /* Arguments are enclosed in parentheses. */ - - len = 0; - if (p[*pos] == '(') { - (*pos)++; - while (p[*pos + len] != ')') - len++; - } - - switch (key) { - case KEY_DELIM: - mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse, - ln, *pos, "%.*s", len, p + *pos); - want = 2; - break; - case KEY_TAB: - want = 1; - if (len == want) - tbl->opts.tab = p[*pos]; - break; - case KEY_LINESIZE: - want = 0; - break; - case KEY_DPOINT: - want = 1; - if (len == want) - tbl->opts.decimal = p[*pos]; - break; - default: - abort(); - } - - if (len == 0) - mandoc_msg(MANDOCERR_TBLOPT_NOARG, - tbl->parse, ln, *pos, keys[key].name); - else if (want && len != want) - mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, - tbl->parse, ln, *pos, "%s want %d have %d", - keys[key].name, want, len); - - *pos += len; - if (p[*pos] == ')') - (*pos)++; -} - -/* - * Parse one line of options up to the semicolon. - * Each option can be preceded by blanks and/or commas, - * and some options are followed by arguments. - */ -void -tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) -{ - int i, pos, len; - - pos = *offs; - for (;;) { - while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',') - pos++; - - if (p[pos] == ';') { - *offs = pos + 1; - return; - } - - /* Parse one option name. */ - - len = 0; - while (isalpha((unsigned char)p[pos + len])) - len++; - - if (len == 0) { - mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA, - tbl->parse, ln, pos, "%c", p[pos]); - pos++; - continue; - } - - /* Look up the option name. */ - - i = 0; - while (i < KEY_MAXKEYS && - (strncasecmp(p + pos, keys[i].name, len) || - keys[i].name[len] != '\0')) - i++; - - if (i == KEY_MAXKEYS) { - mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse, - ln, pos, "%.*s", len, p + pos); - pos += len; - continue; - } - - /* Handle the option. */ - - pos += len; - if (keys[i].key) - tbl->opts.opts |= keys[i].key; - else - arg(tbl, ln, p, &pos, i); - } -} Property changes on: head/contrib/mdocml/tbl_opts.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/msec.in =================================================================== --- head/contrib/mdocml/msec.in (revision 338825) +++ head/contrib/mdocml/msec.in (nonexistent) @@ -1,34 +0,0 @@ -/* $Id: msec.in,v 1.6 2010/06/19 20:46:28 kristaps 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. - */ - -/* - * These are all possible manual-section macros and what they correspond - * to when rendered as the volume title. - * - * Be sure to escape strings. - */ - -LINE("1", "FreeBSD General Commands Manual") -LINE("2", "FreeBSD System Calls Manual") -LINE("3", "FreeBSD Library Functions Manual") -LINE("3p", "Perl Library Functions Manual") -LINE("4", "FreeBSD Kernel Interfaces Manual") -LINE("5", "FreeBSD File Formats Manual") -LINE("6", "FreeBSD Games Manual") -LINE("7", "FreeBSD Miscellaneous Information Manual") -LINE("8", "FreeBSD System Manager\'s Manual") -LINE("9", "FreeBSD Kernel Developer\'s Manual") Property changes on: head/contrib/mdocml/msec.in ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-fts.c =================================================================== --- head/contrib/mdocml/test-fts.c (revision 338825) +++ head/contrib/mdocml/test-fts.c (nonexistent) @@ -1,59 +0,0 @@ -#include -#include -#include -#include -#include - -#ifdef FTS_COMPARE_CONST -int fts_compare(const FTSENT *const *, const FTSENT *const *); -#else -int fts_compare(const FTSENT **, const FTSENT **); -#endif - -int -main(void) -{ - const char *argv[2]; - FTS *ftsp; - FTSENT *entry; - - argv[0] = "."; - argv[1] = (char *)NULL; - - ftsp = fts_open((char * const *)argv, - FTS_PHYSICAL | FTS_NOCHDIR, fts_compare); - - if (ftsp == NULL) { - perror("fts_open"); - return 1; - } - - entry = fts_read(ftsp); - - if (entry == NULL) { - perror("fts_read"); - return 1; - } - - if (fts_set(ftsp, entry, FTS_SKIP) != 0) { - perror("fts_set"); - return 1; - } - - if (fts_close(ftsp) != 0) { - perror("fts_close"); - return 1; - } - - return 0; -} - -int -#ifdef FTS_COMPARE_CONST -fts_compare(const FTSENT *const *a, const FTSENT *const *b) -#else -fts_compare(const FTSENT **a, const FTSENT **b) -#endif -{ - return strcmp((*a)->fts_name, (*b)->fts_name); -} Property changes on: head/contrib/mdocml/test-fts.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tbl_term.c =================================================================== --- head/contrib/mdocml/tbl_term.c (revision 338825) +++ head/contrib/mdocml/tbl_term.c (nonexistent) @@ -1,676 +0,0 @@ -/* $Id: tbl_term.c,v 1.57 2017/07/31 16:14:10 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2011 Kristaps Dzonsons - * Copyright (c) 2011,2012,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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include - -#include "mandoc.h" -#include "out.h" -#include "term.h" - -#define IS_HORIZ(cp) ((cp)->pos == TBL_CELL_HORIZ || \ - (cp)->pos == TBL_CELL_DHORIZ) - -static size_t term_tbl_len(size_t, void *); -static size_t term_tbl_strlen(const char *, void *); -static size_t term_tbl_sulen(const struct roffsu *, void *); -static void tbl_char(struct termp *, char, size_t); -static void tbl_data(struct termp *, const struct tbl_opts *, - const struct tbl_cell *, - const struct tbl_dat *, - const struct roffcol *); -static void tbl_literal(struct termp *, const struct tbl_dat *, - const struct roffcol *); -static void tbl_number(struct termp *, const struct tbl_opts *, - const struct tbl_dat *, - const struct roffcol *); -static void tbl_hrule(struct termp *, const struct tbl_span *, int); -static void tbl_word(struct termp *, const struct tbl_dat *); - - -static size_t -term_tbl_sulen(const struct roffsu *su, void *arg) -{ - int i; - - i = term_hen((const struct termp *)arg, su); - return i > 0 ? i : 0; -} - -static size_t -term_tbl_strlen(const char *p, void *arg) -{ - return term_strlen((const struct termp *)arg, p); -} - -static size_t -term_tbl_len(size_t sz, void *arg) -{ - return term_len((const struct termp *)arg, sz); -} - -void -term_tbl(struct termp *tp, const struct tbl_span *sp) -{ - const struct tbl_cell *cp, *cpn, *cpp; - const struct tbl_dat *dp; - static size_t offset; - size_t coloff, tsz; - int ic, horiz, spans, vert, more; - char fc; - - /* Inhibit printing of spaces: we do padding ourselves. */ - - tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE; - - /* - * The first time we're invoked for a given table block, - * calculate the table widths and decimal positions. - */ - - if (tp->tbl.cols == NULL) { - tp->tbl.len = term_tbl_len; - tp->tbl.slen = term_tbl_strlen; - tp->tbl.sulen = term_tbl_sulen; - tp->tbl.arg = tp; - - tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin); - - /* Tables leak .ta settings to subsequent text. */ - - term_tab_set(tp, NULL); - coloff = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) || - sp->opts->lvert; - for (ic = 0; ic < sp->opts->cols; ic++) { - coloff += tp->tbl.cols[ic].width; - term_tab_iset(coloff); - coloff += tp->tbl.cols[ic].spacing; - } - - /* Center the table as a whole. */ - - offset = tp->tcol->offset; - if (sp->opts->opts & TBL_OPT_CENTRE) { - tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) - ? 2 : !!sp->opts->lvert + !!sp->opts->rvert; - for (ic = 0; ic + 1 < sp->opts->cols; ic++) - tsz += tp->tbl.cols[ic].width + - tp->tbl.cols[ic].spacing; - if (sp->opts->cols) - tsz += tp->tbl.cols[sp->opts->cols - 1].width; - if (offset + tsz > tp->tcol->rmargin) - tsz -= 1; - tp->tcol->offset = offset + tp->tcol->rmargin > tsz ? - (offset + tp->tcol->rmargin - tsz) / 2 : 0; - } - - /* Horizontal frame at the start of boxed tables. */ - - if (sp->opts->opts & TBL_OPT_DBOX) - tbl_hrule(tp, sp, 3); - if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) - tbl_hrule(tp, sp, 2); - } - - /* Set up the columns. */ - - tp->flags |= TERMP_MULTICOL; - horiz = 0; - switch (sp->pos) { - case TBL_SPAN_HORIZ: - case TBL_SPAN_DHORIZ: - horiz = 1; - term_setcol(tp, 1); - break; - case TBL_SPAN_DATA: - term_setcol(tp, sp->opts->cols + 2); - coloff = tp->tcol->offset; - - /* Set up a column for a left vertical frame. */ - - if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) || - sp->opts->lvert) - coloff++; - tp->tcol->rmargin = coloff; - - /* Set up the data columns. */ - - dp = sp->first; - spans = 0; - for (ic = 0; ic < sp->opts->cols; ic++) { - if (spans == 0) { - tp->tcol++; - tp->tcol->offset = coloff; - } - coloff += tp->tbl.cols[ic].width; - tp->tcol->rmargin = coloff; - if (ic + 1 < sp->opts->cols) - coloff += tp->tbl.cols[ic].spacing; - if (spans) { - spans--; - continue; - } - if (dp == NULL) - continue; - spans = dp->spans; - if (ic || sp->layout->first->pos != TBL_CELL_SPAN) - dp = dp->next; - } - - /* Set up a column for a right vertical frame. */ - - tp->tcol++; - tp->tcol->offset = coloff + 1; - tp->tcol->rmargin = tp->maxrmargin; - - /* Spans may have reduced the number of columns. */ - - tp->lasttcol = tp->tcol - tp->tcols; - - /* Fill the buffers for all data columns. */ - - tp->tcol = tp->tcols; - cp = cpn = sp->layout->first; - dp = sp->first; - spans = 0; - for (ic = 0; ic < sp->opts->cols; ic++) { - if (cpn != NULL) { - cp = cpn; - cpn = cpn->next; - } - if (spans) { - spans--; - continue; - } - tp->tcol++; - tp->col = 0; - tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic); - if (dp == NULL) - continue; - spans = dp->spans; - if (cp->pos != TBL_CELL_SPAN) - dp = dp->next; - } - break; - } - - do { - /* Print the vertical frame at the start of each row. */ - - tp->tcol = tp->tcols; - fc = '\0'; - if (sp->layout->vert || - (sp->next != NULL && sp->next->layout->vert && - sp->next->pos == TBL_SPAN_DATA) || - (sp->prev != NULL && sp->prev->layout->vert && - (horiz || (IS_HORIZ(sp->layout->first) && - !IS_HORIZ(sp->prev->layout->first)))) || - sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)) - fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|'; - else if (horiz && sp->opts->lvert) - fc = '-'; - if (fc != '\0') { - (*tp->advance)(tp, tp->tcols->offset); - (*tp->letter)(tp, fc); - tp->viscol = tp->tcol->offset + 1; - } - - /* Print the data cells. */ - - more = 0; - if (horiz) { - tbl_hrule(tp, sp, 0); - term_flushln(tp); - } else { - cp = sp->layout->first; - cpn = sp->next == NULL ? NULL : - sp->next->layout->first; - cpp = sp->prev == NULL ? NULL : - sp->prev->layout->first; - dp = sp->first; - spans = 0; - for (ic = 0; ic < sp->opts->cols; ic++) { - - /* - * Figure out whether to print a - * vertical line after this cell - * and advance to next layout cell. - */ - - if (cp != NULL) { - vert = cp->vert; - switch (cp->pos) { - case TBL_CELL_HORIZ: - fc = '-'; - break; - case TBL_CELL_DHORIZ: - fc = '='; - break; - default: - fc = ' '; - break; - } - } else { - vert = 0; - fc = ' '; - } - if (cpp != NULL) { - if (vert == 0 && - cp != NULL && - ((IS_HORIZ(cp) && - !IS_HORIZ(cpp)) || - (cp->next != NULL && - cpp->next != NULL && - IS_HORIZ(cp->next) && - !IS_HORIZ(cpp->next)))) - vert = cpp->vert; - cpp = cpp->next; - } - if (vert == 0 && - sp->opts->opts & TBL_OPT_ALLBOX) - vert = 1; - if (cpn != NULL) { - if (vert == 0) - vert = cpn->vert; - cpn = cpn->next; - } - if (cp != NULL) - cp = cp->next; - - /* - * Skip later cells in a span, - * figure out whether to start a span, - * and advance to next data cell. - */ - - if (spans) { - spans--; - continue; - } - if (dp != NULL) { - spans = dp->spans; - if (ic || sp->layout->first->pos - != TBL_CELL_SPAN) - dp = dp->next; - } - - /* - * Print one line of text in the cell - * and remember whether there is more. - */ - - tp->tcol++; - if (tp->tcol->col < tp->tcol->lastcol) - term_flushln(tp); - if (tp->tcol->col < tp->tcol->lastcol) - more = 1; - - /* - * Vertical frames between data cells, - * but not after the last column. - */ - - if (fc == ' ' && ((vert == 0 && - (cp == NULL || !IS_HORIZ(cp))) || - tp->tcol + 1 == tp->tcols + tp->lasttcol)) - continue; - - if (tp->viscol < tp->tcol->rmargin) { - (*tp->advance)(tp, tp->tcol->rmargin - - tp->viscol); - tp->viscol = tp->tcol->rmargin; - } - while (tp->viscol < tp->tcol->rmargin + - tp->tbl.cols[ic].spacing / 2) { - (*tp->letter)(tp, fc); - tp->viscol++; - } - - if (tp->tcol + 1 == tp->tcols + tp->lasttcol) - continue; - - if (fc == ' ' && cp != NULL) { - switch (cp->pos) { - case TBL_CELL_HORIZ: - fc = '-'; - break; - case TBL_CELL_DHORIZ: - fc = '='; - break; - default: - break; - } - } - if (tp->tbl.cols[ic].spacing) { - (*tp->letter)(tp, fc == ' ' ? '|' : - vert ? '+' : fc); - tp->viscol++; - } - - if (fc != ' ') { - if (cp != NULL && - cp->pos == TBL_CELL_HORIZ) - fc = '-'; - else if (cp != NULL && - cp->pos == TBL_CELL_DHORIZ) - fc = '='; - else - fc = ' '; - } - if (tp->tbl.cols[ic].spacing > 2 && - (vert > 1 || fc != ' ')) { - (*tp->letter)(tp, fc == ' ' ? '|' : - vert > 1 ? '+' : fc); - tp->viscol++; - } - } - } - - /* Print the vertical frame at the end of each row. */ - - fc = '\0'; - if ((sp->layout->last->vert && - sp->layout->last->col + 1 == sp->opts->cols) || - (sp->next != NULL && - sp->next->layout->last->vert && - sp->next->layout->last->col + 1 == sp->opts->cols) || - (sp->prev != NULL && - sp->prev->layout->last->vert && - sp->prev->layout->last->col + 1 == sp->opts->cols && - (horiz || (IS_HORIZ(sp->layout->last) && - !IS_HORIZ(sp->prev->layout->last)))) || - (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))) - fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|'; - else if (horiz && sp->opts->rvert) - fc = '-'; - if (fc != '\0') { - if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 || - sp->layout->last->col + 1 < sp->opts->cols)) { - tp->tcol++; - (*tp->advance)(tp, - tp->tcol->offset > tp->viscol ? - tp->tcol->offset - tp->viscol : 1); - } - (*tp->letter)(tp, fc); - } - (*tp->endline)(tp); - tp->viscol = 0; - } while (more); - - /* - * Clean up after this row. If it is the last line - * of the table, print the box line and clean up - * column data; otherwise, print the allbox line. - */ - - term_setcol(tp, 1); - tp->flags &= ~TERMP_MULTICOL; - tp->tcol->rmargin = tp->maxrmargin; - if (sp->next == NULL) { - if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) { - tbl_hrule(tp, sp, 2); - tp->skipvsp = 1; - } - if (sp->opts->opts & TBL_OPT_DBOX) { - tbl_hrule(tp, sp, 3); - tp->skipvsp = 2; - } - assert(tp->tbl.cols); - free(tp->tbl.cols); - tp->tbl.cols = NULL; - tp->tcol->offset = offset; - } else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX && - (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA || - sp->next->next != NULL)) - tbl_hrule(tp, sp, 1); - - tp->flags &= ~TERMP_NONOSPACE; -} - -/* - * Kinds of horizontal rulers: - * 0: inside the table (single or double line with crossings) - * 1: inside the table (single or double line with crossings and ends) - * 2: inner frame (single line with crossings and ends) - * 3: outer frame (single line without crossings with ends) - */ -static void -tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind) -{ - const struct tbl_cell *cp, *cpn, *cpp; - const struct roffcol *col; - int vert; - char line, cross; - - line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-'; - cross = (kind < 3) ? '+' : '-'; - - if (kind) - term_word(tp, "+"); - cp = sp->layout->first; - cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first; - if (cpp == cp) - cpp = NULL; - cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first; - if (cpn == cp) - cpn = NULL; - for (;;) { - col = tp->tbl.cols + cp->col; - tbl_char(tp, line, col->width + col->spacing / 2); - vert = cp->vert; - if ((cp = cp->next) == NULL) - break; - if (cpp != NULL) { - if (vert < cpp->vert) - vert = cpp->vert; - cpp = cpp->next; - } - if (cpn != NULL) { - if (vert < cpn->vert) - vert = cpn->vert; - cpn = cpn->next; - } - if (sp->opts->opts & TBL_OPT_ALLBOX && !vert) - vert = 1; - if (col->spacing) - tbl_char(tp, vert ? cross : line, 1); - if (col->spacing > 2) - tbl_char(tp, vert > 1 ? cross : line, 1); - if (col->spacing > 4) - tbl_char(tp, line, (col->spacing - 3) / 2); - } - if (kind) { - term_word(tp, "+"); - term_flushln(tp); - } -} - -static void -tbl_data(struct termp *tp, const struct tbl_opts *opts, - const struct tbl_cell *cp, const struct tbl_dat *dp, - const struct roffcol *col) -{ - switch (cp->pos) { - case TBL_CELL_HORIZ: - tbl_char(tp, '-', col->width); - return; - case TBL_CELL_DHORIZ: - tbl_char(tp, '=', col->width); - return; - default: - break; - } - - if (dp == NULL) - return; - - switch (dp->pos) { - case TBL_DATA_NONE: - return; - case TBL_DATA_HORIZ: - case TBL_DATA_NHORIZ: - tbl_char(tp, '-', col->width); - return; - case TBL_DATA_NDHORIZ: - case TBL_DATA_DHORIZ: - tbl_char(tp, '=', col->width); - return; - default: - break; - } - - switch (cp->pos) { - case TBL_CELL_LONG: - case TBL_CELL_CENTRE: - case TBL_CELL_LEFT: - case TBL_CELL_RIGHT: - tbl_literal(tp, dp, col); - break; - case TBL_CELL_NUMBER: - tbl_number(tp, opts, dp, col); - break; - case TBL_CELL_DOWN: - case TBL_CELL_SPAN: - break; - default: - abort(); - } -} - -static void -tbl_char(struct termp *tp, char c, size_t len) -{ - size_t i, sz; - char cp[2]; - - cp[0] = c; - cp[1] = '\0'; - - sz = term_strlen(tp, cp); - - for (i = 0; i < len; i += sz) - term_word(tp, cp); -} - -static void -tbl_literal(struct termp *tp, const struct tbl_dat *dp, - const struct roffcol *col) -{ - size_t len, padl, padr, width; - int ic, spans; - - assert(dp->string); - len = term_strlen(tp, dp->string); - width = col->width; - ic = dp->layout->col; - spans = dp->spans; - while (spans--) - width += tp->tbl.cols[++ic].width + 3; - - padr = width > len ? width - len : 0; - padl = 0; - - switch (dp->layout->pos) { - case TBL_CELL_LONG: - padl = term_len(tp, 1); - padr = padr > padl ? padr - padl : 0; - break; - case TBL_CELL_CENTRE: - if (2 > padr) - break; - padl = padr / 2; - padr -= padl; - break; - case TBL_CELL_RIGHT: - padl = padr; - padr = 0; - break; - default: - break; - } - - tbl_char(tp, ASCII_NBRSP, padl); - tbl_word(tp, dp); - tbl_char(tp, ASCII_NBRSP, padr); -} - -static void -tbl_number(struct termp *tp, const struct tbl_opts *opts, - const struct tbl_dat *dp, - const struct roffcol *col) -{ - char *cp; - char buf[2]; - size_t sz, psz, ssz, d, padl; - int i; - - /* - * See calc_data_number(). Left-pad by taking the offset of our - * and the maximum decimal; right-pad by the remaining amount. - */ - - assert(dp->string); - - sz = term_strlen(tp, dp->string); - - buf[0] = opts->decimal; - buf[1] = '\0'; - - psz = term_strlen(tp, buf); - - if ((cp = strrchr(dp->string, opts->decimal)) != NULL) { - for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { - buf[0] = dp->string[i]; - ssz += term_strlen(tp, buf); - } - d = ssz + psz; - } else - d = sz + psz; - - if (col->decimal > d && col->width > sz) { - padl = col->decimal - d; - if (padl + sz > col->width) - padl = col->width - sz; - tbl_char(tp, ASCII_NBRSP, padl); - } else - padl = 0; - tbl_word(tp, dp); - if (col->width > sz + padl) - tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); -} - -static void -tbl_word(struct termp *tp, const struct tbl_dat *dp) -{ - int prev_font; - - prev_font = tp->fonti; - if (dp->layout->flags & TBL_CELL_BOLD) - term_fontpush(tp, TERMFONT_BOLD); - else if (dp->layout->flags & TBL_CELL_ITALIC) - term_fontpush(tp, TERMFONT_UNDER); - - term_word(tp, dp->string); - - term_fontpopq(tp, prev_font); -} Property changes on: head/contrib/mdocml/tbl_term.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/html.c =================================================================== --- head/contrib/mdocml/html.c (revision 338825) +++ head/contrib/mdocml/html.c (nonexistent) @@ -1,979 +0,0 @@ -/* $Id: html.c,v 1.219 2017/07/15 17:57:51 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_aux.h" -#include "mandoc.h" -#include "roff.h" -#include "out.h" -#include "html.h" -#include "manconf.h" -#include "main.h" - -struct htmldata { - const char *name; - int flags; -#define HTML_NOSTACK (1 << 0) -#define HTML_AUTOCLOSE (1 << 1) -#define HTML_NLBEFORE (1 << 2) -#define HTML_NLBEGIN (1 << 3) -#define HTML_NLEND (1 << 4) -#define HTML_NLAFTER (1 << 5) -#define HTML_NLAROUND (HTML_NLBEFORE | HTML_NLAFTER) -#define HTML_NLINSIDE (HTML_NLBEGIN | HTML_NLEND) -#define HTML_NLALL (HTML_NLAROUND | HTML_NLINSIDE) -#define HTML_INDENT (1 << 6) -#define HTML_NOINDENT (1 << 7) -}; - -static const struct htmldata htmltags[TAG_MAX] = { - {"html", HTML_NLALL}, - {"head", HTML_NLALL | HTML_INDENT}, - {"body", HTML_NLALL}, - {"meta", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, - {"title", HTML_NLAROUND}, - {"div", HTML_NLAROUND}, - {"h1", HTML_NLAROUND}, - {"h2", HTML_NLAROUND}, - {"span", 0}, - {"link", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, - {"br", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, - {"a", 0}, - {"table", HTML_NLALL | HTML_INDENT}, - {"colgroup", HTML_NLALL | HTML_INDENT}, - {"col", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, - {"tr", HTML_NLALL | HTML_INDENT}, - {"td", HTML_NLAROUND}, - {"li", HTML_NLAROUND | HTML_INDENT}, - {"ul", HTML_NLALL | HTML_INDENT}, - {"ol", HTML_NLALL | HTML_INDENT}, - {"dl", HTML_NLALL | HTML_INDENT}, - {"dt", HTML_NLAROUND}, - {"dd", HTML_NLAROUND | HTML_INDENT}, - {"pre", HTML_NLALL | HTML_NOINDENT}, - {"var", 0}, - {"cite", 0}, - {"b", 0}, - {"i", 0}, - {"code", 0}, - {"small", 0}, - {"style", HTML_NLALL | HTML_INDENT}, - {"math", HTML_NLALL | HTML_INDENT}, - {"mrow", 0}, - {"mi", 0}, - {"mn", 0}, - {"mo", 0}, - {"msup", 0}, - {"msub", 0}, - {"msubsup", 0}, - {"mfrac", 0}, - {"msqrt", 0}, - {"mfenced", 0}, - {"mtable", 0}, - {"mtr", 0}, - {"mtd", 0}, - {"munderover", 0}, - {"munder", 0}, - {"mover", 0}, -}; - -static const char *const roffscales[SCALE_MAX] = { - "cm", /* SCALE_CM */ - "in", /* SCALE_IN */ - "pc", /* SCALE_PC */ - "pt", /* SCALE_PT */ - "em", /* SCALE_EM */ - "em", /* SCALE_MM */ - "ex", /* SCALE_EN */ - "ex", /* SCALE_BU */ - "em", /* SCALE_VS */ - "ex", /* SCALE_FS */ -}; - -static void a2width(const char *, struct roffsu *); -static void print_byte(struct html *, char); -static void print_endword(struct html *); -static void print_indent(struct html *); -static void print_word(struct html *, const char *); - -static void print_ctag(struct html *, struct tag *); -static int print_escape(struct html *, char); -static int print_encode(struct html *, const char *, const char *, int); -static void print_href(struct html *, const char *, const char *, int); -static void print_metaf(struct html *, enum mandoc_esc); - - -void * -html_alloc(const struct manoutput *outopts) -{ - struct html *h; - - h = mandoc_calloc(1, sizeof(struct html)); - - h->tag = NULL; - h->style = outopts->style; - h->base_man = outopts->man; - h->base_includes = outopts->includes; - if (outopts->fragment) - h->oflags |= HTML_FRAGMENT; - - return h; -} - -void -html_free(void *p) -{ - struct tag *tag; - struct html *h; - - h = (struct html *)p; - - while ((tag = h->tag) != NULL) { - h->tag = tag->next; - free(tag); - } - - free(h); -} - -void -print_gen_head(struct html *h) -{ - struct tag *t; - - print_otag(h, TAG_META, "?", "charset", "utf-8"); - - /* - * Print a default style-sheet. - */ - - t = print_otag(h, TAG_STYLE, ""); - print_text(h, "table.head, table.foot { width: 100%; }"); - print_endline(h); - print_text(h, "td.head-rtitle, td.foot-os { text-align: right; }"); - print_endline(h); - print_text(h, "td.head-vol { text-align: center; }"); - print_endline(h); - print_text(h, "div.Pp { margin: 1ex 0ex; }"); - print_tagq(h, t); - - if (h->style) - print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet", - h->style, "type", "text/css", "media", "all"); -} - -static void -print_metaf(struct html *h, enum mandoc_esc deco) -{ - enum htmlfont font; - - switch (deco) { - case ESCAPE_FONTPREV: - font = h->metal; - break; - case ESCAPE_FONTITALIC: - font = HTMLFONT_ITALIC; - break; - case ESCAPE_FONTBOLD: - font = HTMLFONT_BOLD; - break; - case ESCAPE_FONTBI: - font = HTMLFONT_BI; - break; - case ESCAPE_FONT: - case ESCAPE_FONTROMAN: - font = HTMLFONT_NONE; - break; - default: - abort(); - } - - if (h->metaf) { - print_tagq(h, h->metaf); - h->metaf = NULL; - } - - h->metal = h->metac; - h->metac = font; - - switch (font) { - case HTMLFONT_ITALIC: - h->metaf = print_otag(h, TAG_I, ""); - break; - case HTMLFONT_BOLD: - h->metaf = print_otag(h, TAG_B, ""); - break; - case HTMLFONT_BI: - h->metaf = print_otag(h, TAG_B, ""); - print_otag(h, TAG_I, ""); - break; - default: - break; - } -} - -char * -html_make_id(const struct roff_node *n) -{ - const struct roff_node *nch; - char *buf, *cp; - - for (nch = n->child; nch != NULL; nch = nch->next) - if (nch->type != ROFFT_TEXT) - return NULL; - - buf = NULL; - deroff(&buf, n); - - /* http://www.w3.org/TR/html5/dom.html#the-id-attribute */ - - for (cp = buf; *cp != '\0'; cp++) - if (*cp == ' ') - *cp = '_'; - - return buf; -} - -int -html_strlen(const char *cp) -{ - size_t rsz; - int skip, sz; - - /* - * Account for escaped sequences within string length - * calculations. This follows the logic in term_strlen() as we - * must calculate the width of produced strings. - * Assume that characters are always width of "1". This is - * hacky, but it gets the job done for approximation of widths. - */ - - sz = 0; - skip = 0; - while (1) { - rsz = strcspn(cp, "\\"); - if (rsz) { - cp += rsz; - if (skip) { - skip = 0; - rsz--; - } - sz += rsz; - } - if ('\0' == *cp) - break; - cp++; - switch (mandoc_escape(&cp, NULL, NULL)) { - case ESCAPE_ERROR: - return sz; - case ESCAPE_UNICODE: - case ESCAPE_NUMBERED: - case ESCAPE_SPECIAL: - case ESCAPE_OVERSTRIKE: - if (skip) - skip = 0; - else - sz++; - break; - case ESCAPE_SKIPCHAR: - skip = 1; - break; - default: - break; - } - } - return sz; -} - -static int -print_escape(struct html *h, char c) -{ - - switch (c) { - case '<': - print_word(h, "<"); - break; - case '>': - print_word(h, ">"); - break; - case '&': - print_word(h, "&"); - break; - case '"': - print_word(h, """); - break; - case ASCII_NBRSP: - print_word(h, " "); - break; - case ASCII_HYPH: - print_byte(h, '-'); - break; - case ASCII_BREAK: - break; - default: - return 0; - } - return 1; -} - -static int -print_encode(struct html *h, const char *p, const char *pend, int norecurse) -{ - char numbuf[16]; - struct tag *t; - const char *seq; - size_t sz; - int c, len, breakline, nospace; - enum mandoc_esc esc; - static const char rejs[10] = { ' ', '\\', '<', '>', '&', '"', - ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' }; - - if (pend == NULL) - pend = strchr(p, '\0'); - - breakline = 0; - nospace = 0; - - while (p < pend) { - if (HTML_SKIPCHAR & h->flags && '\\' != *p) { - h->flags &= ~HTML_SKIPCHAR; - p++; - continue; - } - - for (sz = strcspn(p, rejs); sz-- && p < pend; p++) - print_byte(h, *p); - - if (breakline && - (p >= pend || *p == ' ' || *p == ASCII_NBRSP)) { - t = print_otag(h, TAG_DIV, ""); - print_text(h, "\\~"); - print_tagq(h, t); - breakline = 0; - while (p < pend && (*p == ' ' || *p == ASCII_NBRSP)) - p++; - continue; - } - - if (p >= pend) - break; - - if (*p == ' ') { - print_endword(h); - p++; - continue; - } - - if (print_escape(h, *p++)) - continue; - - esc = mandoc_escape(&p, &seq, &len); - if (ESCAPE_ERROR == esc) - break; - - switch (esc) { - case ESCAPE_FONT: - case ESCAPE_FONTPREV: - case ESCAPE_FONTBOLD: - case ESCAPE_FONTITALIC: - case ESCAPE_FONTBI: - case ESCAPE_FONTROMAN: - if (0 == norecurse) - print_metaf(h, esc); - continue; - case ESCAPE_SKIPCHAR: - h->flags |= HTML_SKIPCHAR; - continue; - default: - break; - } - - if (h->flags & HTML_SKIPCHAR) { - h->flags &= ~HTML_SKIPCHAR; - continue; - } - - switch (esc) { - case ESCAPE_UNICODE: - /* Skip past "u" header. */ - c = mchars_num2uc(seq + 1, len - 1); - break; - case ESCAPE_NUMBERED: - c = mchars_num2char(seq, len); - if (c < 0) - continue; - break; - case ESCAPE_SPECIAL: - c = mchars_spec2cp(seq, len); - if (c <= 0) - continue; - break; - case ESCAPE_BREAK: - breakline = 1; - continue; - case ESCAPE_NOSPACE: - if ('\0' == *p) - nospace = 1; - continue; - case ESCAPE_OVERSTRIKE: - if (len == 0) - continue; - c = seq[len - 1]; - break; - default: - continue; - } - if ((c < 0x20 && c != 0x09) || - (c > 0x7E && c < 0xA0)) - c = 0xFFFD; - if (c > 0x7E) { - (void)snprintf(numbuf, sizeof(numbuf), "&#x%.4X;", c); - print_word(h, numbuf); - } else if (print_escape(h, c) == 0) - print_byte(h, c); - } - - return nospace; -} - -static void -print_href(struct html *h, const char *name, const char *sec, int man) -{ - const char *p, *pp; - - pp = man ? h->base_man : h->base_includes; - while ((p = strchr(pp, '%')) != NULL) { - print_encode(h, pp, p, 1); - if (man && p[1] == 'S') { - if (sec == NULL) - print_byte(h, '1'); - else - print_encode(h, sec, NULL, 1); - } else if ((man && p[1] == 'N') || - (man == 0 && p[1] == 'I')) - print_encode(h, name, NULL, 1); - else - print_encode(h, p, p + 2, 1); - pp = p + 2; - } - if (*pp != '\0') - print_encode(h, pp, NULL, 1); -} - -struct tag * -print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) -{ - va_list ap; - struct roffsu mysu, *su; - char numbuf[16]; - struct tag *t; - const char *attr; - char *arg1, *arg2; - double v; - int i, have_style, tflags; - - tflags = htmltags[tag].flags; - - /* Push this tag onto the stack of open scopes. */ - - if ((tflags & HTML_NOSTACK) == 0) { - t = mandoc_malloc(sizeof(struct tag)); - t->tag = tag; - t->next = h->tag; - h->tag = t; - } else - t = NULL; - - if (tflags & HTML_NLBEFORE) - print_endline(h); - if (h->col == 0) - print_indent(h); - else if ((h->flags & HTML_NOSPACE) == 0) { - if (h->flags & HTML_KEEP) - print_word(h, " "); - else { - if (h->flags & HTML_PREKEEP) - h->flags |= HTML_KEEP; - print_endword(h); - } - } - - if ( ! (h->flags & HTML_NONOSPACE)) - h->flags &= ~HTML_NOSPACE; - else - h->flags |= HTML_NOSPACE; - - /* Print out the tag name and attributes. */ - - print_byte(h, '<'); - print_word(h, htmltags[tag].name); - - va_start(ap, fmt); - - have_style = 0; - while (*fmt != '\0') { - if (*fmt == 's') { - have_style = 1; - fmt++; - break; - } - - /* Parse a non-style attribute and its arguments. */ - - arg1 = va_arg(ap, char *); - switch (*fmt++) { - case 'c': - attr = "class"; - break; - case 'h': - attr = "href"; - break; - case 'i': - attr = "id"; - break; - case '?': - attr = arg1; - arg1 = va_arg(ap, char *); - break; - default: - abort(); - } - arg2 = NULL; - if (*fmt == 'M') - arg2 = va_arg(ap, char *); - if (arg1 == NULL) - continue; - - /* Print the non-style attributes. */ - - print_byte(h, ' '); - print_word(h, attr); - print_byte(h, '='); - print_byte(h, '"'); - switch (*fmt) { - case 'I': - print_href(h, arg1, NULL, 0); - fmt++; - break; - case 'M': - print_href(h, arg1, arg2, 1); - fmt++; - break; - case 'R': - print_byte(h, '#'); - print_encode(h, arg1, NULL, 1); - fmt++; - break; - case 'T': - print_encode(h, arg1, NULL, 1); - print_word(h, "\" title=\""); - print_encode(h, arg1, NULL, 1); - fmt++; - break; - default: - print_encode(h, arg1, NULL, 1); - break; - } - print_byte(h, '"'); - } - - /* Print out styles. */ - - while (*fmt != '\0') { - arg1 = NULL; - su = NULL; - - /* First letter: input argument type. */ - - switch (*fmt++) { - case 'h': - i = va_arg(ap, int); - su = &mysu; - SCALE_HS_INIT(su, i); - break; - case 's': - arg1 = va_arg(ap, char *); - break; - case 'u': - su = va_arg(ap, struct roffsu *); - break; - case 'w': - if ((arg2 = va_arg(ap, char *)) != NULL) { - su = &mysu; - a2width(arg2, su); - } - if (*fmt == '*') { - if (su != NULL && su->unit == SCALE_EN && - su->scale > 5.9 && su->scale < 6.1) - su = NULL; - fmt++; - } - if (*fmt == '+') { - if (su != NULL) { - /* Make even bold text fit. */ - su->scale *= 1.2; - /* Add padding. */ - su->scale += 3.0; - } - fmt++; - } - if (*fmt == '-') { - if (su != NULL) - su->scale *= -1.0; - fmt++; - } - break; - default: - abort(); - } - - /* Second letter: style name. */ - - switch (*fmt++) { - case 'h': - attr = "height"; - break; - case 'i': - attr = "text-indent"; - break; - case 'l': - attr = "margin-left"; - break; - case 'w': - attr = "width"; - break; - case 'W': - attr = "min-width"; - break; - case '?': - attr = arg1; - arg1 = va_arg(ap, char *); - break; - default: - abort(); - } - if (su == NULL && arg1 == NULL) - continue; - - if (have_style == 1) - print_word(h, " style=\""); - else - print_byte(h, ' '); - print_word(h, attr); - print_byte(h, ':'); - print_byte(h, ' '); - if (su != NULL) { - v = su->scale; - if (su->unit == SCALE_MM && (v /= 100.0) == 0.0) - v = 1.0; - else if (su->unit == SCALE_BU) - v /= 24.0; - (void)snprintf(numbuf, sizeof(numbuf), "%.2f", v); - print_word(h, numbuf); - print_word(h, roffscales[su->unit]); - } else - print_word(h, arg1); - print_byte(h, ';'); - have_style = 2; - } - if (have_style == 2) - print_byte(h, '"'); - - va_end(ap); - - /* Accommodate for "well-formed" singleton escaping. */ - - if (HTML_AUTOCLOSE & htmltags[tag].flags) - print_byte(h, '/'); - - print_byte(h, '>'); - - if (tflags & HTML_NLBEGIN) - print_endline(h); - else - h->flags |= HTML_NOSPACE; - - if (tflags & HTML_INDENT) - h->indent++; - if (tflags & HTML_NOINDENT) - h->noindent++; - - return t; -} - -static void -print_ctag(struct html *h, struct tag *tag) -{ - int tflags; - - /* - * Remember to close out and nullify the current - * meta-font and table, if applicable. - */ - if (tag == h->metaf) - h->metaf = NULL; - if (tag == h->tblt) - h->tblt = NULL; - - tflags = htmltags[tag->tag].flags; - - if (tflags & HTML_INDENT) - h->indent--; - if (tflags & HTML_NOINDENT) - h->noindent--; - if (tflags & HTML_NLEND) - print_endline(h); - print_indent(h); - print_byte(h, '<'); - print_byte(h, '/'); - print_word(h, htmltags[tag->tag].name); - print_byte(h, '>'); - if (tflags & HTML_NLAFTER) - print_endline(h); - - h->tag = tag->next; - free(tag); -} - -void -print_gen_decls(struct html *h) -{ - print_word(h, ""); - print_endline(h); -} - -void -print_text(struct html *h, const char *word) -{ - if (h->col && (h->flags & HTML_NOSPACE) == 0) { - if ( ! (HTML_KEEP & h->flags)) { - if (HTML_PREKEEP & h->flags) - h->flags |= HTML_KEEP; - print_endword(h); - } else - print_word(h, " "); - } - - assert(NULL == h->metaf); - switch (h->metac) { - case HTMLFONT_ITALIC: - h->metaf = print_otag(h, TAG_I, ""); - break; - case HTMLFONT_BOLD: - h->metaf = print_otag(h, TAG_B, ""); - break; - case HTMLFONT_BI: - h->metaf = print_otag(h, TAG_B, ""); - print_otag(h, TAG_I, ""); - break; - default: - print_indent(h); - break; - } - - assert(word); - if ( ! print_encode(h, word, NULL, 0)) { - if ( ! (h->flags & HTML_NONOSPACE)) - h->flags &= ~HTML_NOSPACE; - h->flags &= ~HTML_NONEWLINE; - } else - h->flags |= HTML_NOSPACE | HTML_NONEWLINE; - - if (h->metaf) { - print_tagq(h, h->metaf); - h->metaf = NULL; - } - - h->flags &= ~HTML_IGNDELIM; -} - -void -print_tagq(struct html *h, const struct tag *until) -{ - struct tag *tag; - - while ((tag = h->tag) != NULL) { - print_ctag(h, tag); - if (until && tag == until) - return; - } -} - -void -print_stagq(struct html *h, const struct tag *suntil) -{ - struct tag *tag; - - while ((tag = h->tag) != NULL) { - if (suntil && tag == suntil) - return; - print_ctag(h, tag); - } -} - -void -print_paragraph(struct html *h) -{ - struct tag *t; - - t = print_otag(h, TAG_DIV, "c", "Pp"); - print_tagq(h, t); -} - - -/*********************************************************************** - * Low level output functions. - * They implement line breaking using a short static buffer. - ***********************************************************************/ - -/* - * Buffer one HTML output byte. - * If the buffer is full, flush and deactivate it and start a new line. - * If the buffer is inactive, print directly. - */ -static void -print_byte(struct html *h, char c) -{ - if ((h->flags & HTML_BUFFER) == 0) { - putchar(c); - h->col++; - return; - } - - if (h->col + h->bufcol < sizeof(h->buf)) { - h->buf[h->bufcol++] = c; - return; - } - - putchar('\n'); - h->col = 0; - print_indent(h); - putchar(' '); - putchar(' '); - fwrite(h->buf, h->bufcol, 1, stdout); - putchar(c); - h->col = (h->indent + 1) * 2 + h->bufcol + 1; - h->bufcol = 0; - h->flags &= ~HTML_BUFFER; -} - -/* - * If something was printed on the current output line, end it. - * Not to be called right after print_indent(). - */ -void -print_endline(struct html *h) -{ - if (h->col == 0) - return; - - if (h->bufcol) { - putchar(' '); - fwrite(h->buf, h->bufcol, 1, stdout); - h->bufcol = 0; - } - putchar('\n'); - h->col = 0; - h->flags |= HTML_NOSPACE; - h->flags &= ~HTML_BUFFER; -} - -/* - * Flush the HTML output buffer. - * If it is inactive, activate it. - */ -static void -print_endword(struct html *h) -{ - if (h->noindent) { - print_byte(h, ' '); - return; - } - - if ((h->flags & HTML_BUFFER) == 0) { - h->col++; - h->flags |= HTML_BUFFER; - } else if (h->bufcol) { - putchar(' '); - fwrite(h->buf, h->bufcol, 1, stdout); - h->col += h->bufcol + 1; - } - h->bufcol = 0; -} - -/* - * If at the beginning of a new output line, - * perform indentation and mark the line as containing output. - * Make sure to really produce some output right afterwards, - * but do not use print_otag() for producing it. - */ -static void -print_indent(struct html *h) -{ - size_t i; - - if (h->col) - return; - - if (h->noindent == 0) { - h->col = h->indent * 2; - for (i = 0; i < h->col; i++) - putchar(' '); - } - h->flags &= ~HTML_NOSPACE; -} - -/* - * Print or buffer some characters - * depending on the current HTML output buffer state. - */ -static void -print_word(struct html *h, const char *cp) -{ - while (*cp != '\0') - print_byte(h, *cp++); -} - -/* - * Calculate the scaling unit passed in a `-width' argument. This uses - * either a native scaling unit (e.g., 1i, 2m) or the string length of - * the value. - */ -static void -a2width(const char *p, struct roffsu *su) -{ - const char *end; - - end = a2roffsu(p, su, SCALE_MAX); - if (end == NULL || *end != '\0') { - su->unit = SCALE_EN; - su->scale = html_strlen(p); - } else if (su->scale < 0.0) - su->scale = 0.0; -} Property changes on: head/contrib/mdocml/html.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/cgi.h.example =================================================================== --- head/contrib/mdocml/cgi.h.example (revision 338825) +++ head/contrib/mdocml/cgi.h.example (nonexistent) @@ -1,7 +0,0 @@ -/* Example compile-time configuration file for man.cgi(8). */ - -#define SCRIPT_NAME "cgi-bin/man.cgi" -#define MAN_DIR "/man" -#define CSS_DIR "" -#define CUSTOMIZE_TITLE "Manual pages with mandoc" -#define COMPAT_OLDURI Yes Index: head/contrib/mdocml/mandoc.css =================================================================== --- head/contrib/mdocml/mandoc.css (revision 338825) +++ head/contrib/mdocml/mandoc.css (nonexistent) @@ -1,203 +0,0 @@ -/* $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 { margin-left: 0ex; } -b.It-diag { font-style: normal; } -dl.Bl-hang { } -dt.It-hang { } -dd.It-hang { margin-left: 10.2ex; } -dl.Bl-inset { } -dt.It-inset { } -dd.It-inset { margin-left: 0ex; } -dl.Bl-ohang { } -dt.It-ohang { } -dd.It-ohang { margin-left: 0ex; } -dl.Bl-tag { margin-left: 10.2ex; } -dt.It-tag { float: left; - margin-top: 0ex; - margin-left: -10.2ex; - padding-right: 2ex; - vertical-align: top; } -dd.It-tag { clear: right; - width: 100%; - margin-top: 0ex; - margin-left: 0ex; - vertical-align: top; - overflow: auto; } -dl.Bl-compact > dt { - margin-top: 0ex; } - -table.Bl-column { } -tr.It-column { } -td.It-column { margin-top: 1em; } -table.Bl-compact > tbody > tr > td { - margin-top: 0ex; } - -cite.Rs { font-style: normal; - font-weight: normal; } -span.RsA { } -i.RsB { font-weight: normal; } -span.RsC { } -span.RsD { } -i.RsI { font-weight: normal; } -i.RsJ { font-weight: normal; } -span.RsN { } -span.RsO { } -span.RsP { } -span.RsQ { } -span.RsR { } -span.RsT { text-decoration: underline; } -a.RsU { } -span.RsV { } - -span.eqn { } -table.tbl { } - -/* 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; } Property changes on: head/contrib/mdocml/mandoc.css ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/css \ No newline at end of property Index: head/contrib/mdocml/compat_getsubopt.c =================================================================== --- head/contrib/mdocml/compat_getsubopt.c (revision 338825) +++ head/contrib/mdocml/compat_getsubopt.c (nonexistent) @@ -1,96 +0,0 @@ -#include "config.h" - -#if HAVE_GETSUBOPT - -int dummy; - -#else - -/* $Id: compat_getsubopt.c,v 1.5 2014/08/17 20:53:50 schwarze Exp $ */ -/* $OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $ */ - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include - -int -getsubopt(char **optionp, char * const *tokens, char **valuep) -{ - int cnt; - char *suboptarg; - char *p; - - suboptarg = *valuep = NULL; - - if (!optionp || !*optionp) - return(-1); - - /* skip leading white-space, commas */ - for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); - - if (!*p) { - *optionp = p; - return(-1); - } - - /* save the start of the token, and skip the rest of the token. */ - for (suboptarg = p; - *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';); - - if (*p) { - /* - * If there's an equals sign, set the value pointer, and - * skip over the value part of the token. Terminate the - * token. - */ - if (*p == '=') { - *p = '\0'; - for (*valuep = ++p; - *p && *p != ',' && *p != ' ' && *p != '\t'; ++p); - if (*p) - *p++ = '\0'; - } else - *p++ = '\0'; - /* Skip any whitespace or commas after this token. */ - for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); - } - - /* set optionp for next round. */ - *optionp = p; - - for (cnt = 0; *tokens; ++tokens, ++cnt) - if (!strcmp(suboptarg, *tokens)) - return(cnt); - return(-1); -} - -#endif Property changes on: head/contrib/mdocml/compat_getsubopt.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/read.c =================================================================== --- head/contrib/mdocml/read.c (revision 338825) +++ head/contrib/mdocml/read.c (nonexistent) @@ -1,901 +0,0 @@ -/* $Id: read.c,v 1.192 2017/07/20 14:36:36 schwarze Exp $ */ -/* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2010-2017 Ingo Schwarze - * Copyright (c) 2010, 2012 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 -#include -#include -#include -#include -#include - -#include "mandoc_aux.h" -#include "mandoc.h" -#include "roff.h" -#include "mdoc.h" -#include "man.h" -#include "libmandoc.h" - -#define REPARSE_LIMIT 1000 - -struct mparse { - struct roff *roff; /* roff parser (!NULL) */ - struct roff_man *man; /* man parser */ - char *sodest; /* filename pointed to by .so */ - const char *file; /* filename of current input file */ - struct buf *primary; /* buffer currently being parsed */ - struct buf *secondary; /* preprocessed copy of input */ - const char *os_s; /* default operating system */ - mandocmsg mmsg; /* warning/error message handler */ - enum mandoclevel file_status; /* status of current parse */ - enum mandocerr mmin; /* ignore messages below this */ - int options; /* parser options */ - int gzip; /* current input file is gzipped */ - int filenc; /* encoding of the current file */ - int reparse_count; /* finite interp. stack */ - int line; /* line number in the file */ -}; - -static void choose_parser(struct mparse *); -static void resize_buf(struct buf *, size_t); -static int mparse_buf_r(struct mparse *, struct buf, size_t, int); -static int read_whole_file(struct mparse *, const char *, int, - struct buf *, int *); -static void mparse_end(struct mparse *); -static void mparse_parse_buffer(struct mparse *, struct buf, - const char *); - -static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { - MANDOCERR_OK, - MANDOCERR_OK, - MANDOCERR_WARNING, - MANDOCERR_ERROR, - MANDOCERR_UNSUPP, - MANDOCERR_MAX, - MANDOCERR_MAX -}; - -static const char * const mandocerrs[MANDOCERR_MAX] = { - "ok", - - "base system convention", - - "Mdocdate found", - "Mdocdate missing", - "unknown architecture", - "operating system explicitly specified", - "RCS id missing", - "referenced manual not found", - - "generic style suggestion", - - "legacy man(7) date format", - "lower case character in document title", - "duplicate RCS id", - "typo in section name", - "unterminated quoted argument", - "useless macro", - "consider using OS macro", - "errnos out of order", - "duplicate errno", - "trailing delimiter", - "no blank before trailing delimiter", - "fill mode already enabled, skipping", - "fill mode already disabled, skipping", - "function name without markup", - "whitespace at end of input line", - "bad comment style", - - "generic warning", - - /* related to the prologue */ - "missing manual title, using UNTITLED", - "missing manual title, using \"\"", - "missing manual section, using \"\"", - "unknown manual section", - "missing date, using today's date", - "cannot parse date, using it verbatim", - "date in the future, using it anyway", - "missing Os macro, using \"\"", - "late prologue macro", - "prologue macros out of order", - - /* related to document structure */ - ".so is fragile, better use ln(1)", - "no document body", - "content before first section header", - "first section is not \"NAME\"", - "NAME section without Nm before Nd", - "NAME section without description", - "description not at the end of NAME", - "bad NAME section content", - "missing comma before name", - "missing description line, using \"\"", - "description line outside NAME section", - "sections out of conventional order", - "duplicate section title", - "unexpected section", - "cross reference to self", - "unusual Xr order", - "unusual Xr punctuation", - "AUTHORS section without An macro", - - /* related to macros and nesting */ - "obsolete macro", - "macro neither callable nor escaped", - "skipping paragraph macro", - "moving paragraph macro out of list", - "skipping no-space macro", - "blocks badly nested", - "nested displays are not portable", - "moving content out of list", - "first macro on line", - "line scope broken", - "skipping blank line in line scope", - - /* related to missing macro arguments */ - "skipping empty request", - "conditional request controls empty scope", - "skipping empty macro", - "empty block", - "empty argument, using 0n", - "missing display type, using -ragged", - "list type is not the first argument", - "missing -width in -tag list, using 6n", - "missing utility name, using \"\"", - "missing function name, using \"\"", - "empty head in list item", - "empty list item", - "missing argument, using next line", - "missing font type, using \\fR", - "unknown font type, using \\fR", - "nothing follows prefix", - "empty reference block", - "missing section argument", - "missing -std argument, adding it", - "missing option string, using \"\"", - "missing resource identifier, using \"\"", - "missing eqn box, using \"\"", - - /* related to bad macro arguments */ - "duplicate argument", - "skipping duplicate argument", - "skipping duplicate display type", - "skipping duplicate list type", - "skipping -width argument", - "wrong number of cells", - "unknown AT&T UNIX version", - "comma in function argument", - "parenthesis in function name", - "unknown library name", - "invalid content in Rs block", - "invalid Boolean argument", - "unknown font, skipping request", - "odd number of characters in request", - - /* related to plain text */ - "blank line in fill mode, using .sp", - "tab in filled text", - "new sentence, new line", - "invalid escape sequence", - "undefined string, using \"\"", - - /* related to tables */ - "tbl line starts with span", - "tbl column starts with span", - "skipping vertical bar in tbl layout", - - "generic error", - - /* related to tables */ - "non-alphabetic character in tbl options", - "skipping unknown tbl option", - "missing tbl option argument", - "wrong tbl option argument size", - "empty tbl layout", - "invalid character in tbl layout", - "unmatched parenthesis in tbl layout", - "tbl without any data cells", - "ignoring data in spanned tbl cell", - "ignoring extra tbl data cells", - "data block open at end of tbl", - - /* related to document structure and macros */ - NULL, - "duplicate prologue macro", - "skipping late title macro", - "input stack limit exceeded, infinite loop?", - "skipping bad character", - "skipping unknown macro", - "skipping insecure request", - "skipping item outside list", - "skipping column outside column list", - "skipping end of block that is not open", - "fewer RS blocks open, skipping", - "inserting missing end of block", - "appending missing end of block", - - /* related to request and macro arguments */ - "escaped character not allowed in a name", - "NOT IMPLEMENTED: Bd -file", - "skipping display without arguments", - "missing list type, using -item", - "argument is not numeric, using 1", - "missing manual name, using \"\"", - "uname(3) system call failed, using UNKNOWN", - "unknown standard specifier", - "skipping request without numeric argument", - "NOT IMPLEMENTED: .so with absolute path or \"..\"", - ".so request failed", - "skipping all arguments", - "skipping excess arguments", - "divide by zero", - - "unsupported feature", - "input too large", - "unsupported control character", - "unsupported roff request", - "eqn delim option in tbl", - "unsupported tbl layout modifier", - "ignoring macro in table", -}; - -static const char * const mandoclevels[MANDOCLEVEL_MAX] = { - "SUCCESS", - "STYLE", - "WARNING", - "ERROR", - "UNSUPP", - "BADARG", - "SYSERR" -}; - - -static void -resize_buf(struct buf *buf, size_t initial) -{ - - buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial; - buf->buf = mandoc_realloc(buf->buf, buf->sz); -} - -static void -choose_parser(struct mparse *curp) -{ - char *cp, *ep; - int format; - - /* - * If neither command line arguments -mdoc or -man select - * a parser nor the roff parser found a .Dd or .TH macro - * yet, look ahead in the main input buffer. - */ - - if ((format = roff_getformat(curp->roff)) == 0) { - cp = curp->primary->buf; - ep = cp + curp->primary->sz; - while (cp < ep) { - if (*cp == '.' || *cp == '\'') { - cp++; - if (cp[0] == 'D' && cp[1] == 'd') { - format = MPARSE_MDOC; - break; - } - if (cp[0] == 'T' && cp[1] == 'H') { - format = MPARSE_MAN; - break; - } - } - cp = memchr(cp, '\n', ep - cp); - if (cp == NULL) - break; - cp++; - } - } - - if (format == MPARSE_MDOC) { - curp->man->macroset = MACROSET_MDOC; - if (curp->man->mdocmac == NULL) - curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX); - } else { - curp->man->macroset = MACROSET_MAN; - if (curp->man->manmac == NULL) - curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX); - } - curp->man->first->tok = TOKEN_NONE; -} - -/* - * Main parse routine for a buffer. - * It assumes encoding and line numbering are already set up. - * It can recurse directly (for invocations of user-defined - * macros, inline equations, and input line traps) - * and indirectly (for .so file inclusion). - */ -static int -mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) -{ - struct buf ln; - const char *save_file; - char *cp; - size_t pos; /* byte number in the ln buffer */ - enum rofferr rr; - int of; - int lnn; /* line number in the real file */ - int fd; - unsigned char c; - - memset(&ln, 0, sizeof(ln)); - - lnn = curp->line; - pos = 0; - - while (i < blk.sz) { - if (0 == pos && '\0' == blk.buf[i]) - break; - - if (start) { - curp->line = lnn; - curp->reparse_count = 0; - - if (lnn < 3 && - curp->filenc & MPARSE_UTF8 && - curp->filenc & MPARSE_LATIN1) - curp->filenc = preconv_cue(&blk, i); - } - - while (i < blk.sz && (start || blk.buf[i] != '\0')) { - - /* - * When finding an unescaped newline character, - * leave the character loop to process the line. - * Skip a preceding carriage return, if any. - */ - - if ('\r' == blk.buf[i] && i + 1 < blk.sz && - '\n' == blk.buf[i + 1]) - ++i; - if ('\n' == blk.buf[i]) { - ++i; - ++lnn; - break; - } - - /* - * Make sure we have space for the worst - * case of 11 bytes: "\\[u10ffff]\0" - */ - - if (pos + 11 > ln.sz) - resize_buf(&ln, 256); - - /* - * Encode 8-bit input. - */ - - c = blk.buf[i]; - if (c & 0x80) { - if ( ! (curp->filenc && preconv_encode( - &blk, &i, &ln, &pos, &curp->filenc))) { - mandoc_vmsg(MANDOCERR_CHAR_BAD, curp, - curp->line, pos, "0x%x", c); - ln.buf[pos++] = '?'; - i++; - } - continue; - } - - /* - * Exclude control characters. - */ - - if (c == 0x7f || (c < 0x20 && c != 0x09)) { - mandoc_vmsg(c == 0x00 || c == 0x04 || - c > 0x0a ? MANDOCERR_CHAR_BAD : - MANDOCERR_CHAR_UNSUPP, - curp, curp->line, pos, "0x%x", c); - i++; - if (c != '\r') - ln.buf[pos++] = '?'; - continue; - } - - ln.buf[pos++] = blk.buf[i++]; - } - - if (pos + 1 >= ln.sz) - resize_buf(&ln, 256); - - if (i == blk.sz || blk.buf[i] == '\0') - ln.buf[pos++] = '\n'; - ln.buf[pos] = '\0'; - - /* - * A significant amount of complexity is contained by - * the roff preprocessor. It's line-oriented but can be - * expressed on one line, so we need at times to - * readjust our starting point and re-run it. The roff - * preprocessor can also readjust the buffers with new - * data, so we pass them in wholesale. - */ - - of = 0; - - /* - * Maintain a lookaside buffer of all parsed lines. We - * only do this if mparse_keep() has been invoked (the - * buffer may be accessed with mparse_getkeep()). - */ - - if (curp->secondary) { - curp->secondary->buf = mandoc_realloc( - curp->secondary->buf, - curp->secondary->sz + pos + 2); - memcpy(curp->secondary->buf + - curp->secondary->sz, - ln.buf, pos); - curp->secondary->sz += pos; - curp->secondary->buf - [curp->secondary->sz] = '\n'; - curp->secondary->sz++; - curp->secondary->buf - [curp->secondary->sz] = '\0'; - } -rerun: - rr = roff_parseln(curp->roff, curp->line, &ln, &of); - - switch (rr) { - case ROFF_REPARSE: - if (++curp->reparse_count > REPARSE_LIMIT) - mandoc_msg(MANDOCERR_ROFFLOOP, curp, - curp->line, pos, NULL); - else if (mparse_buf_r(curp, ln, of, 0) == 1 || - start == 1) { - pos = 0; - continue; - } - free(ln.buf); - return 0; - case ROFF_APPEND: - pos = strlen(ln.buf); - continue; - case ROFF_RERUN: - goto rerun; - case ROFF_IGN: - pos = 0; - continue; - case ROFF_SO: - if ( ! (curp->options & MPARSE_SO) && - (i >= blk.sz || blk.buf[i] == '\0')) { - curp->sodest = mandoc_strdup(ln.buf + of); - free(ln.buf); - return 1; - } - /* - * We remove `so' clauses from our lookaside - * buffer because we're going to descend into - * the file recursively. - */ - if (curp->secondary) - curp->secondary->sz -= pos + 1; - save_file = curp->file; - if ((fd = mparse_open(curp, ln.buf + of)) != -1) { - mparse_readfd(curp, fd, ln.buf + of); - close(fd); - curp->file = save_file; - } else { - curp->file = save_file; - mandoc_vmsg(MANDOCERR_SO_FAIL, - curp, curp->line, pos, - ".so %s", ln.buf + of); - ln.sz = mandoc_asprintf(&cp, - ".sp\nSee the file %s.\n.sp", - ln.buf + of); - free(ln.buf); - ln.buf = cp; - of = 0; - mparse_buf_r(curp, ln, of, 0); - } - pos = 0; - continue; - default: - break; - } - - if (curp->man->macroset == MACROSET_NONE) - choose_parser(curp); - - if ((curp->man->macroset == MACROSET_MDOC ? - mdoc_parseln(curp->man, curp->line, ln.buf, of) : - man_parseln(curp->man, curp->line, ln.buf, of)) == 2) - break; - - /* Temporary buffers typically are not full. */ - - if (0 == start && '\0' == blk.buf[i]) - break; - - /* Start the next input line. */ - - pos = 0; - } - - free(ln.buf); - return 1; -} - -static int -read_whole_file(struct mparse *curp, const char *file, int fd, - struct buf *fb, int *with_mmap) -{ - struct stat st; - gzFile gz; - size_t off; - ssize_t ssz; - - if (fstat(fd, &st) == -1) { - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, - "fstat: %s", strerror(errno)); - return 0; - } - - /* - * If we're a regular file, try just reading in the whole entry - * via mmap(). This is faster than reading it into blocks, and - * since each file is only a few bytes to begin with, I'm not - * concerned that this is going to tank any machines. - */ - - if (curp->gzip == 0 && S_ISREG(st.st_mode)) { - if (st.st_size > 0x7fffffff) { - mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL); - return 0; - } - *with_mmap = 1; - fb->sz = (size_t)st.st_size; - fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0); - if (fb->buf != MAP_FAILED) - return 1; - } - - if (curp->gzip) { - if ((gz = gzdopen(fd, "rb")) == NULL) { - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, - "gzdopen: %s", strerror(errno)); - return 0; - } - } else - gz = NULL; - - /* - * If this isn't a regular file (like, say, stdin), then we must - * go the old way and just read things in bit by bit. - */ - - *with_mmap = 0; - off = 0; - fb->sz = 0; - fb->buf = NULL; - for (;;) { - if (off == fb->sz) { - if (fb->sz == (1U << 31)) { - mandoc_msg(MANDOCERR_TOOLARGE, curp, - 0, 0, NULL); - break; - } - resize_buf(fb, 65536); - } - ssz = curp->gzip ? - gzread(gz, fb->buf + (int)off, fb->sz - off) : - read(fd, fb->buf + (int)off, fb->sz - off); - if (ssz == 0) { - fb->sz = off; - return 1; - } - if (ssz == -1) { - mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, - "read: %s", strerror(errno)); - break; - } - off += (size_t)ssz; - } - - free(fb->buf); - fb->buf = NULL; - return 0; -} - -static void -mparse_end(struct mparse *curp) -{ - if (curp->man->macroset == MACROSET_NONE) - curp->man->macroset = MACROSET_MAN; - if (curp->man->macroset == MACROSET_MDOC) - mdoc_endparse(curp->man); - else - man_endparse(curp->man); - roff_endparse(curp->roff); -} - -static void -mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file) -{ - struct buf *svprimary; - const char *svfile; - size_t offset; - static int recursion_depth; - - if (64 < recursion_depth) { - mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL); - return; - } - - /* Line number is per-file. */ - svfile = curp->file; - curp->file = file; - svprimary = curp->primary; - curp->primary = &blk; - curp->line = 1; - recursion_depth++; - - /* Skip an UTF-8 byte order mark. */ - if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 && - (unsigned char)blk.buf[0] == 0xef && - (unsigned char)blk.buf[1] == 0xbb && - (unsigned char)blk.buf[2] == 0xbf) { - offset = 3; - curp->filenc &= ~MPARSE_LATIN1; - } else - offset = 0; - - mparse_buf_r(curp, blk, offset, 1); - - if (--recursion_depth == 0) - mparse_end(curp); - - curp->primary = svprimary; - curp->file = svfile; -} - -enum mandoclevel -mparse_readmem(struct mparse *curp, void *buf, size_t len, - const char *file) -{ - struct buf blk; - - blk.buf = buf; - blk.sz = len; - - mparse_parse_buffer(curp, blk, file); - return curp->file_status; -} - -/* - * Read the whole file into memory and call the parsers. - * Called recursively when an .so request is encountered. - */ -enum mandoclevel -mparse_readfd(struct mparse *curp, int fd, const char *file) -{ - struct buf blk; - int with_mmap; - int save_filenc; - - if (read_whole_file(curp, file, fd, &blk, &with_mmap)) { - save_filenc = curp->filenc; - curp->filenc = curp->options & - (MPARSE_UTF8 | MPARSE_LATIN1); - mparse_parse_buffer(curp, blk, file); - curp->filenc = save_filenc; - if (with_mmap) - munmap(blk.buf, blk.sz); - else - free(blk.buf); - } - return curp->file_status; -} - -int -mparse_open(struct mparse *curp, const char *file) -{ - char *cp; - int fd; - - curp->file = file; - cp = strrchr(file, '.'); - curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz")); - - /* First try to use the filename as it is. */ - - if ((fd = open(file, O_RDONLY)) != -1) - return fd; - - /* - * If that doesn't work and the filename doesn't - * already end in .gz, try appending .gz. - */ - - if ( ! curp->gzip) { - mandoc_asprintf(&cp, "%s.gz", file); - fd = open(cp, O_RDONLY); - free(cp); - if (fd != -1) { - curp->gzip = 1; - return fd; - } - } - - /* Neither worked, give up. */ - - mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno)); - return -1; -} - -struct mparse * -mparse_alloc(int options, enum mandocerr mmin, mandocmsg mmsg, - enum mandoc_os os_e, const char *os_s) -{ - struct mparse *curp; - - curp = mandoc_calloc(1, sizeof(struct mparse)); - - curp->options = options; - curp->mmin = mmin; - curp->mmsg = mmsg; - curp->os_s = os_s; - - curp->roff = roff_alloc(curp, options); - curp->man = roff_man_alloc(curp->roff, curp, curp->os_s, - curp->options & MPARSE_QUICK ? 1 : 0); - if (curp->options & MPARSE_MDOC) { - curp->man->macroset = MACROSET_MDOC; - if (curp->man->mdocmac == NULL) - curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX); - } else if (curp->options & MPARSE_MAN) { - curp->man->macroset = MACROSET_MAN; - if (curp->man->manmac == NULL) - curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX); - } - curp->man->first->tok = TOKEN_NONE; - curp->man->meta.os_e = os_e; - return curp; -} - -void -mparse_reset(struct mparse *curp) -{ - roff_reset(curp->roff); - roff_man_reset(curp->man); - - free(curp->sodest); - curp->sodest = NULL; - - if (curp->secondary) - curp->secondary->sz = 0; - - curp->file_status = MANDOCLEVEL_OK; - curp->gzip = 0; -} - -void -mparse_free(struct mparse *curp) -{ - - roffhash_free(curp->man->mdocmac); - roffhash_free(curp->man->manmac); - roff_man_free(curp->man); - roff_free(curp->roff); - if (curp->secondary) - free(curp->secondary->buf); - - free(curp->secondary); - free(curp->sodest); - free(curp); -} - -void -mparse_result(struct mparse *curp, struct roff_man **man, - char **sodest) -{ - - if (sodest && NULL != (*sodest = curp->sodest)) { - *man = NULL; - return; - } - if (man) - *man = curp->man; -} - -void -mparse_updaterc(struct mparse *curp, enum mandoclevel *rc) -{ - if (curp->file_status > *rc) - *rc = curp->file_status; -} - -void -mandoc_vmsg(enum mandocerr t, struct mparse *m, - int ln, int pos, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - mandoc_msg(t, m, ln, pos, buf); -} - -void -mandoc_msg(enum mandocerr er, struct mparse *m, - int ln, int col, const char *msg) -{ - enum mandoclevel level; - - if (er < m->mmin && er != MANDOCERR_FILE) - return; - - level = MANDOCLEVEL_UNSUPP; - while (er < mandoclimits[level]) - level--; - - if (m->mmsg) - (*m->mmsg)(er, level, m->file, ln, col, msg); - - if (m->file_status < level) - m->file_status = level; -} - -const char * -mparse_strerror(enum mandocerr er) -{ - - return mandocerrs[er]; -} - -const char * -mparse_strlevel(enum mandoclevel lvl) -{ - return mandoclevels[lvl]; -} - -void -mparse_keep(struct mparse *p) -{ - - assert(NULL == p->secondary); - p->secondary = mandoc_calloc(1, sizeof(struct buf)); -} - -const char * -mparse_getkeep(const struct mparse *p) -{ - - assert(p->secondary); - return p->secondary->sz ? p->secondary->buf : NULL; -} Property changes on: head/contrib/mdocml/read.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-rewb-bsd.c =================================================================== --- head/contrib/mdocml/test-rewb-bsd.c (revision 338825) +++ head/contrib/mdocml/test-rewb-bsd.c (nonexistent) @@ -1,27 +0,0 @@ -#include -#include -#include - -int -main(void) -{ - regex_t re; - - if (regcomp(&re, "[[:<:]]word[[:>:]]", REG_EXTENDED | REG_NOSUB)) - return 1; - if (regexec(&re, "the word is here", 0, NULL, 0)) - return 2; - if (regexec(&re, "same word", 0, NULL, 0)) - return 3; - if (regexec(&re, "word again", 0, NULL, 0)) - return 4; - if (regexec(&re, "word", 0, NULL, 0)) - return 5; - if (regexec(&re, "wordy", 0, NULL, 0) != REG_NOMATCH) - return 6; - if (regexec(&re, "sword", 0, NULL, 0) != REG_NOMATCH) - return 7; - if (regexec(&re, "reworded", 0, NULL, 0) != REG_NOMATCH) - return 8; - return 0; -} Property changes on: head/contrib/mdocml/test-rewb-bsd.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/html.h =================================================================== --- head/contrib/mdocml/html.h (revision 338825) +++ head/contrib/mdocml/html.h (nonexistent) @@ -1,135 +0,0 @@ -/* $Id: html.h,v 1.87 2017/07/08 14:51:04 schwarze Exp $ */ -/* - * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons - * 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. - */ - -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_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_box *);
-void		  print_paragraph(struct html *);
-void		  print_endline(struct html *);
-
-char		 *html_make_id(const struct roff_node *);
-int		  html_strlen(const char *);

Property changes on: head/contrib/mdocml/html.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mandoc_ohash.c
===================================================================
--- head/contrib/mdocml/mandoc_ohash.c	(revision 338825)
+++ head/contrib/mdocml/mandoc_ohash.c	(nonexistent)
@@ -1,63 +0,0 @@
-/*	$Id: mandoc_ohash.c,v 1.2 2015/10/19 18:58:47 schwarze Exp $	*/
-/*
- * Copyright (c) 2014, 2015 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 
-#include 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "mandoc_ohash.h"
-
-static	void	 *hash_alloc(size_t, void *);
-static	void	 *hash_calloc(size_t, size_t, void *);
-static	void	  hash_free(void *, void *);
-
-
-void
-mandoc_ohash_init(struct ohash *h, unsigned int sz, ptrdiff_t ko)
-{
-	struct ohash_info info;
-
-	info.alloc = hash_alloc;
-	info.calloc = hash_calloc;
-	info.free = hash_free;
-	info.data = NULL;
-	info.key_offset = ko;
-
-	ohash_init(h, sz, &info);
-}
-
-static void *
-hash_alloc(size_t sz, void *arg)
-{
-
-	return mandoc_malloc(sz);
-}
-
-static void *
-hash_calloc(size_t n, size_t sz, void *arg)
-{
-
-	return mandoc_calloc(n, sz);
-}
-
-static void
-hash_free(void *p, void *arg)
-{
-
-	free(p);
-}

Property changes on: head/contrib/mdocml/mandoc_ohash.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mdoc_markdown.c
===================================================================
--- head/contrib/mdocml/mdoc_markdown.c	(revision 338825)
+++ head/contrib/mdocml/mdoc_markdown.c	(nonexistent)
@@ -1,1569 +0,0 @@
-/*	$Id: mdoc_markdown.c,v 1.23 2017/06/14 01:31:26 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 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 
-
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "main.h"
-
-struct	md_act {
-	int		(*cond)(struct roff_node *n);
-	int		(*pre)(struct roff_node *n);
-	void		(*post)(struct roff_node *n);
-	const char	 *prefix; /* pre-node string constant */
-	const char	 *suffix; /* post-node string constant */
-};
-
-static	void	 md_nodelist(struct roff_node *);
-static	void	 md_node(struct roff_node *);
-static	const char *md_stack(char c);
-static	void	 md_preword(void);
-static	void	 md_rawword(const char *);
-static	void	 md_word(const char *);
-static	void	 md_named(const char *);
-static	void	 md_char(unsigned char);
-static	void	 md_uri(const char *);
-
-static	int	 md_cond_head(struct roff_node *);
-static	int	 md_cond_body(struct roff_node *);
-
-static	int	 md_pre_raw(struct roff_node *);
-static	int	 md_pre_word(struct roff_node *);
-static	int	 md_pre_skip(struct roff_node *);
-static	void	 md_pre_syn(struct roff_node *);
-static	int	 md_pre_An(struct roff_node *);
-static	int	 md_pre_Ap(struct roff_node *);
-static	int	 md_pre_Bd(struct roff_node *);
-static	int	 md_pre_Bk(struct roff_node *);
-static	int	 md_pre_Bl(struct roff_node *);
-static	int	 md_pre_D1(struct roff_node *);
-static	int	 md_pre_Dl(struct roff_node *);
-static	int	 md_pre_En(struct roff_node *);
-static	int	 md_pre_Eo(struct roff_node *);
-static	int	 md_pre_Fa(struct roff_node *);
-static	int	 md_pre_Fd(struct roff_node *);
-static	int	 md_pre_Fn(struct roff_node *);
-static	int	 md_pre_Fo(struct roff_node *);
-static	int	 md_pre_In(struct roff_node *);
-static	int	 md_pre_It(struct roff_node *);
-static	int	 md_pre_Lk(struct roff_node *);
-static	int	 md_pre_Mt(struct roff_node *);
-static	int	 md_pre_Nd(struct roff_node *);
-static	int	 md_pre_Nm(struct roff_node *);
-static	int	 md_pre_No(struct roff_node *);
-static	int	 md_pre_Ns(struct roff_node *);
-static	int	 md_pre_Pp(struct roff_node *);
-static	int	 md_pre_Rs(struct roff_node *);
-static	int	 md_pre_Sh(struct roff_node *);
-static	int	 md_pre_Sm(struct roff_node *);
-static	int	 md_pre_Vt(struct roff_node *);
-static	int	 md_pre_Xr(struct roff_node *);
-static	int	 md_pre__T(struct roff_node *);
-static	int	 md_pre_br(struct roff_node *);
-
-static	void	 md_post_raw(struct roff_node *);
-static	void	 md_post_word(struct roff_node *);
-static	void	 md_post_pc(struct roff_node *);
-static	void	 md_post_Bk(struct roff_node *);
-static	void	 md_post_Bl(struct roff_node *);
-static	void	 md_post_D1(struct roff_node *);
-static	void	 md_post_En(struct roff_node *);
-static	void	 md_post_Eo(struct roff_node *);
-static	void	 md_post_Fa(struct roff_node *);
-static	void	 md_post_Fd(struct roff_node *);
-static	void	 md_post_Fl(struct roff_node *);
-static	void	 md_post_Fn(struct roff_node *);
-static	void	 md_post_Fo(struct roff_node *);
-static	void	 md_post_In(struct roff_node *);
-static	void	 md_post_It(struct roff_node *);
-static	void	 md_post_Lb(struct roff_node *);
-static	void	 md_post_Nm(struct roff_node *);
-static	void	 md_post_Pf(struct roff_node *);
-static	void	 md_post_Vt(struct roff_node *);
-static	void	 md_post__T(struct roff_node *);
-
-static	const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
-	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
-	{ NULL, md_pre_Sh, NULL, NULL, NULL }, /* Sh */
-	{ NULL, md_pre_Sh, NULL, NULL, NULL }, /* Ss */
-	{ NULL, md_pre_Pp, NULL, NULL, NULL }, /* Pp */
-	{ md_cond_body, md_pre_D1, md_post_D1, NULL, NULL }, /* D1 */
-	{ md_cond_body, md_pre_Dl, md_post_D1, NULL, NULL }, /* Dl */
-	{ md_cond_body, md_pre_Bd, md_post_D1, NULL, NULL }, /* Bd */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
-	{ md_cond_body, md_pre_Bl, md_post_Bl, NULL, NULL }, /* Bl */
-	{ NULL, NULL, NULL, NULL, NULL }, /* El */
-	{ NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */
-	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */
-	{ NULL, md_pre_An, NULL, NULL, NULL }, /* An */
-	{ NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */
-	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ar */
-	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */
-	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */
-	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Dv */
-	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Er */
-	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Ev */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ex */
-	{ NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */
-	{ NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */
-	{ NULL, md_pre_raw, md_post_Fl, "**-", "**" }, /* Fl */
-	{ NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */
-	{ NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */
-	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */
-	{ NULL, md_pre_In, md_post_In, NULL, NULL }, /* In */
-	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */
-	{ md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
-	{ NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
-	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */
-	{ NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ot */
-	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Rv */
-	{ NULL, NULL, NULL, NULL, NULL }, /* St */
-	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Va */
-	{ NULL, md_pre_Vt, md_post_Vt, "*", "*" }, /* Vt */
-	{ NULL, md_pre_Xr, NULL, NULL, NULL }, /* Xr */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %A */
-	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %B */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %D */
-	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %I */
-	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %J */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %N */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %O */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %P */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %R */
-	{ NULL, md_pre__T, md_post__T, NULL, NULL }, /* %T */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %V */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
-	{ md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Ao */
-	{ md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Aq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* At */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Bf XXX not implemented */
-	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bo */
-	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Bsx */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Bx */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Db */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
-	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Do */
-	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Dq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
-	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Em */
-	{ md_cond_body, md_pre_Eo, md_post_Eo, NULL, NULL }, /* Eo */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Fx */
-	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ms */
-	{ NULL, md_pre_No, NULL, NULL, NULL }, /* No */
-	{ NULL, md_pre_Ns, NULL, NULL, NULL }, /* Ns */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Nx */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ox */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
-	{ NULL, NULL, md_post_Pf, NULL, NULL }, /* Pf */
-	{ md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Po */
-	{ md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Pq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
-	{ md_cond_body, md_pre_raw, md_post_raw, "'`", "`'" }, /* Ql */
-	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qo */
-	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
-	{ md_cond_body, md_pre_Rs, NULL, NULL, NULL }, /* Rs */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
-	{ md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* So */
-	{ md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* Sq */
-	{ NULL, md_pre_Sm, NULL, NULL, NULL }, /* Sm */
-	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Sx */
-	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Sy */
-	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Tn */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ux */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Xc */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Xo */
-	{ NULL, md_pre_Fo, md_post_Fo, "**", "**" }, /* Fo */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Fc */
-	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Oo */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
-	{ NULL, md_pre_Bk, md_post_Bk, NULL, NULL }, /* Bk */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Bt */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
-	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
-	{ NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */
-	{ NULL, md_pre_Pp, NULL, NULL, NULL }, /* Lp */
-	{ NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */
-	{ NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */
-	{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */
-	{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %C */
-	{ NULL, md_pre_skip, NULL, NULL, NULL }, /* Es */
-	{ md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Dx */
-	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */
-	{ NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
-};
-static	const struct md_act *const md_acts = __md_acts - MDOC_Dd;
-
-static	int	 outflags;
-#define	MD_spc		 (1 << 0)  /* Blank character before next word. */
-#define	MD_spc_force	 (1 << 1)  /* Even before trailing punctuation. */
-#define	MD_nonl		 (1 << 2)  /* Prevent linebreak in markdown code. */
-#define	MD_nl		 (1 << 3)  /* Break markdown code line. */
-#define	MD_br		 (1 << 4)  /* Insert an output line break. */
-#define	MD_sp		 (1 << 5)  /* Insert a paragraph break. */
-#define	MD_Sm		 (1 << 6)  /* Horizontal spacing mode. */
-#define	MD_Bk		 (1 << 7)  /* Word keep mode. */
-#define	MD_An_split	 (1 << 8)  /* Author mode is "split". */
-#define	MD_An_nosplit	 (1 << 9)  /* Author mode is "nosplit". */
-
-static	int	 escflags; /* Escape in generated markdown code: */
-#define	ESC_BOL	 (1 << 0)  /* "#*+-" near the beginning of a line. */
-#define	ESC_NUM	 (1 << 1)  /* "." after a leading number. */
-#define	ESC_HYP	 (1 << 2)  /* "(" immediately after "]". */
-#define	ESC_SQU	 (1 << 4)  /* "]" when "[" is open. */
-#define	ESC_FON	 (1 << 5)  /* "*" immediately after unrelated "*". */
-#define	ESC_EOL	 (1 << 6)  /* " " at the and of a line. */
-
-static	int	 code_blocks, quote_blocks, list_blocks;
-static	int	 outcount;
-
-void
-markdown_mdoc(void *arg, const struct roff_man *mdoc)
-{
-	outflags = MD_Sm;
-	md_word(mdoc->meta.title);
-	if (mdoc->meta.msec != NULL) {
-		outflags &= ~MD_spc;
-		md_word("(");
-		md_word(mdoc->meta.msec);
-		md_word(")");
-	}
-	md_word("-");
-	md_word(mdoc->meta.vol);
-	if (mdoc->meta.arch != NULL) {
-		md_word("(");
-		md_word(mdoc->meta.arch);
-		md_word(")");
-	}
-	outflags |= MD_sp;
-
-	md_nodelist(mdoc->first->child);
-
-	outflags |= MD_sp;
-	md_word(mdoc->meta.os);
-	md_word("-");
-	md_word(mdoc->meta.date);
-	putchar('\n');
-}
-
-static void
-md_nodelist(struct roff_node *n)
-{
-	while (n != NULL) {
-		md_node(n);
-		n = n->next;
-	}
-}
-
-static void
-md_node(struct roff_node *n)
-{
-	const struct md_act	*act;
-	int			 cond, process_children;
-
-	if (n->flags & NODE_NOPRT)
-		return;
-
-	if (outflags & MD_nonl)
-		outflags &= ~(MD_nl | MD_sp);
-	else if (outflags & MD_spc && n->flags & NODE_LINE)
-		outflags |= MD_nl;
-
-	act = NULL;
-	cond = 0;
-	process_children = 1;
-	n->flags &= ~NODE_ENDED;
-
-	if (n->type == ROFFT_TEXT) {
-		if (n->flags & NODE_DELIMC)
-			outflags &= ~(MD_spc | MD_spc_force);
-		else if (outflags & MD_Sm)
-			outflags |= MD_spc_force;
-		md_word(n->string);
-		if (n->flags & NODE_DELIMO)
-			outflags &= ~(MD_spc | MD_spc_force);
-		else if (outflags & MD_Sm)
-			outflags |= MD_spc;
-	} else if (n->tok < ROFF_MAX) {
-		switch (n->tok) {
-		case ROFF_br:
-			process_children = md_pre_br(n);
-			break;
-		case ROFF_sp:
-			process_children = md_pre_Pp(n);
-			break;
-		default:
-			process_children = 0;
-			break;
-		}
-	} else {
-		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
-		act = md_acts + n->tok;
-		cond = act->cond == NULL || (*act->cond)(n);
-		if (cond && act->pre != NULL &&
-		    (n->end == ENDBODY_NOT || n->child != NULL))
-			process_children = (*act->pre)(n);
-	}
-
-	if (process_children && n->child != NULL)
-		md_nodelist(n->child);
-
-	if (n->flags & NODE_ENDED)
-		return;
-
-	if (cond && act->post != NULL)
-		(*act->post)(n);
-
-	if (n->end != ENDBODY_NOT)
-		n->body->flags |= NODE_ENDED;
-}
-
-static const char *
-md_stack(char c)
-{
-	static char	*stack;
-	static size_t	 sz;
-	static size_t	 cur;
-
-	switch (c) {
-	case '\0':
-		break;
-	case (char)-1:
-		assert(cur);
-		stack[--cur] = '\0';
-		break;
-	default:
-		if (cur + 1 >= sz) {
-			sz += 8;
-			stack = mandoc_realloc(stack, sz);
-		}
-		stack[cur] = c;
-		stack[++cur] = '\0';
-		break;
-	}
-	return stack == NULL ? "" : stack;
-}
-
-/*
- * Handle vertical and horizontal spacing.
- */
-static void
-md_preword(void)
-{
-	const char	*cp;
-
-	/*
-	 * If a list block is nested inside a code block or a blockquote,
-	 * blank lines for paragraph breaks no longer work; instead,
-	 * they terminate the list.  Work around this markdown issue
-	 * by using mere line breaks instead.
-	 */
-
-	if (list_blocks && outflags & MD_sp) {
-		outflags &= ~MD_sp;
-		outflags |= MD_br;
-	}
-
-	/*
-	 * End the old line if requested.
-	 * Escape whitespace at the end of the markdown line
-	 * such that it won't look like an output line break.
-	 */
-
-	if (outflags & MD_sp)
-		putchar('\n');
-	else if (outflags & MD_br) {
-		putchar(' ');
-		putchar(' ');
-	} else if (outflags & MD_nl && escflags & ESC_EOL)
-		md_named("zwnj");
-
-	/* Start a new line if necessary. */
-
-	if (outflags & (MD_nl | MD_br | MD_sp)) {
-		putchar('\n');
-		for (cp = md_stack('\0'); *cp != '\0'; cp++) {
-			putchar(*cp);
-			if (*cp == '>')
-				putchar(' ');
-		}
-		outflags &= ~(MD_nl | MD_br | MD_sp);
-		escflags = ESC_BOL;
-		outcount = 0;
-
-	/* Handle horizontal spacing. */
-
-	} else if (outflags & MD_spc) {
-		if (outflags & MD_Bk)
-			fputs(" ", stdout);
-		else
-			putchar(' ');
-		escflags &= ~ESC_FON;
-		outcount++;
-	}
-
-	outflags &= ~(MD_spc_force | MD_nonl);
-	if (outflags & MD_Sm)
-		outflags |= MD_spc;
-	else
-		outflags &= ~MD_spc;
-}
-
-/*
- * Print markdown syntax elements.
- * Can also be used for constant strings when neither escaping
- * nor delimiter handling is required.
- */
-static void
-md_rawword(const char *s)
-{
-	md_preword();
-
-	if (*s == '\0')
-		return;
-
-	if (escflags & ESC_FON) {
-		escflags &= ~ESC_FON;
-		if (*s == '*' && !code_blocks)
-			fputs("‌", stdout);
-	}
-
-	while (*s != '\0') {
-		switch(*s) {
-		case '*':
-			if (s[1] == '\0')
-				escflags |= ESC_FON;
-			break;
-		case '[':
-			escflags |= ESC_SQU;
-			break;
-		case ']':
-			escflags |= ESC_HYP;
-			escflags &= ~ESC_SQU;
-			break;
-		default:
-			break;
-		}
-		md_char(*s++);
-	}
-	if (s[-1] == ' ')
-		escflags |= ESC_EOL;
-	else
-		escflags &= ~ESC_EOL;
-}
-
-/*
- * Print text and mdoc(7) syntax elements.
- */
-static void
-md_word(const char *s)
-{
-	const char	*seq, *prevfont, *currfont, *nextfont;
-	char		 c;
-	int		 bs, sz, uc, breakline;
-
-	/* No spacing before closing delimiters. */
-	if (s[0] != '\0' && s[1] == '\0' &&
-	    strchr("!),.:;?]", s[0]) != NULL &&
-	    (outflags & MD_spc_force) == 0)
-		outflags &= ~MD_spc;
-
-	md_preword();
-
-	if (*s == '\0')
-		return;
-
-	/* No spacing after opening delimiters. */
-	if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
-		outflags &= ~MD_spc;
-
-	breakline = 0;
-	prevfont = currfont = "";
-	while ((c = *s++) != '\0') {
-		bs = 0;
-		switch(c) {
-		case ASCII_NBRSP:
-			if (code_blocks)
-				c = ' ';
-			else {
-				md_named("nbsp");
-				c = '\0';
-			}
-			break;
-		case ASCII_HYPH:
-			bs = escflags & ESC_BOL && !code_blocks;
-			c = '-';
-			break;
-		case ASCII_BREAK:
-			continue;
-		case '#':
-		case '+':
-		case '-':
-			bs = escflags & ESC_BOL && !code_blocks;
-			break;
-		case '(':
-			bs = escflags & ESC_HYP && !code_blocks;
-			break;
-		case ')':
-			bs = escflags & ESC_NUM && !code_blocks;
-			break;
-		case '*':
-		case '[':
-		case '_':
-		case '`':
-			bs = !code_blocks;
-			break;
-		case '.':
-			bs = escflags & ESC_NUM && !code_blocks;
-			break;
-		case '<':
-			if (code_blocks == 0) {
-				md_named("lt");
-				c = '\0';
-			}
-			break;
-		case '=':
-			if (escflags & ESC_BOL && !code_blocks) {
-				md_named("equals");
-				c = '\0';
-			}
-			break;
-		case '>':
-			if (code_blocks == 0) {
-				md_named("gt");
-				c = '\0';
-			}
-			break;
-		case '\\':
-			uc = 0;
-			nextfont = NULL;
-			switch (mandoc_escape(&s, &seq, &sz)) {
-			case ESCAPE_UNICODE:
-				uc = mchars_num2uc(seq + 1, sz - 1);
-				break;
-			case ESCAPE_NUMBERED:
-				uc = mchars_num2char(seq, sz);
-				break;
-			case ESCAPE_SPECIAL:
-				uc = mchars_spec2cp(seq, sz);
-				break;
-			case ESCAPE_FONTBOLD:
-				nextfont = "**";
-				break;
-			case ESCAPE_FONTITALIC:
-				nextfont = "*";
-				break;
-			case ESCAPE_FONTBI:
-				nextfont = "***";
-				break;
-			case ESCAPE_FONT:
-			case ESCAPE_FONTROMAN:
-				nextfont = "";
-				break;
-			case ESCAPE_FONTPREV:
-				nextfont = prevfont;
-				break;
-			case ESCAPE_BREAK:
-				breakline = 1;
-				break;
-			case ESCAPE_NOSPACE:
-			case ESCAPE_SKIPCHAR:
-			case ESCAPE_OVERSTRIKE:
-				/* XXX not implemented */
-				/* FALLTHROUGH */
-			case ESCAPE_ERROR:
-			default:
-				break;
-			}
-			if (nextfont != NULL && !code_blocks) {
-				if (*currfont != '\0') {
-					outflags &= ~MD_spc;
-					md_rawword(currfont);
-				}
-				prevfont = currfont;
-				currfont = nextfont;
-				if (*currfont != '\0') {
-					outflags &= ~MD_spc;
-					md_rawword(currfont);
-				}
-			}
-			if (uc) {
-				if ((uc < 0x20 && uc != 0x09) ||
-				    (uc > 0x7E && uc < 0xA0))
-					uc = 0xFFFD;
-				if (code_blocks) {
-					seq = mchars_uc2str(uc);
-					fputs(seq, stdout);
-					outcount += strlen(seq);
-				} else {
-					printf("&#%d;", uc);
-					outcount++;
-				}
-				escflags &= ~ESC_FON;
-			}
-			c = '\0';
-			break;
-		case ']':
-			bs = escflags & ESC_SQU && !code_blocks;
-			escflags |= ESC_HYP;
-			break;
-		default:
-			break;
-		}
-		if (bs)
-			putchar('\\');
-		md_char(c);
-		if (breakline &&
-		    (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) {
-			printf("  \n");
-			breakline = 0;
-			while (*s == ' ' || *s == ASCII_NBRSP)
-				s++;
-		}
-	}
-	if (*currfont != '\0') {
-		outflags &= ~MD_spc;
-		md_rawword(currfont);
-	} else if (s[-2] == ' ')
-		escflags |= ESC_EOL;
-	else
-		escflags &= ~ESC_EOL;
-}
-
-/*
- * Print a single HTML named character reference.
- */
-static void
-md_named(const char *s)
-{
-	printf("&%s;", s);
-	escflags &= ~(ESC_FON | ESC_EOL);
-	outcount++;
-}
-
-/*
- * Print a single raw character and maintain certain escape flags.
- */
-static void
-md_char(unsigned char c)
-{
-	if (c != '\0') {
-		putchar(c);
-		if (c == '*')
-			escflags |= ESC_FON;
-		else
-			escflags &= ~ESC_FON;
-		outcount++;
-	}
-	if (c != ']')
-		escflags &= ~ESC_HYP;
-	if (c == ' ' || c == '\t' || c == '>')
-		return;
-	if (isdigit(c) == 0)
-		escflags &= ~ESC_NUM;
-	else if (escflags & ESC_BOL)
-		escflags |= ESC_NUM;
-	escflags &= ~ESC_BOL;
-}
-
-static int
-md_cond_head(struct roff_node *n)
-{
-	return n->type == ROFFT_HEAD;
-}
-
-static int
-md_cond_body(struct roff_node *n)
-{
-	return n->type == ROFFT_BODY;
-}
-
-static int
-md_pre_raw(struct roff_node *n)
-{
-	const char	*prefix;
-
-	if ((prefix = md_acts[n->tok].prefix) != NULL) {
-		md_rawword(prefix);
-		outflags &= ~MD_spc;
-		if (*prefix == '`')
-			code_blocks++;
-	}
-	return 1;
-}
-
-static void
-md_post_raw(struct roff_node *n)
-{
-	const char	*suffix;
-
-	if ((suffix = md_acts[n->tok].suffix) != NULL) {
-		outflags &= ~(MD_spc | MD_nl);
-		md_rawword(suffix);
-		if (*suffix == '`')
-			code_blocks--;
-	}
-}
-
-static int
-md_pre_word(struct roff_node *n)
-{
-	const char	*prefix;
-
-	if ((prefix = md_acts[n->tok].prefix) != NULL) {
-		md_word(prefix);
-		outflags &= ~MD_spc;
-	}
-	return 1;
-}
-
-static void
-md_post_word(struct roff_node *n)
-{
-	const char	*suffix;
-
-	if ((suffix = md_acts[n->tok].suffix) != NULL) {
-		outflags &= ~(MD_spc | MD_nl);
-		md_word(suffix);
-	}
-}
-
-static void
-md_post_pc(struct roff_node *n)
-{
-	md_post_raw(n);
-	if (n->parent->tok != MDOC_Rs)
-		return;
-	if (n->next != NULL) {
-		md_word(",");
-		if (n->prev != NULL &&
-		    n->prev->tok == n->tok &&
-		    n->next->tok == n->tok)
-			md_word("and");
-	} else {
-		md_word(".");
-		outflags |= MD_nl;
-	}
-}
-
-static int
-md_pre_skip(struct roff_node *n)
-{
-	return 0;
-}
-
-static void
-md_pre_syn(struct roff_node *n)
-{
-	if (n->prev == NULL || ! (n->flags & NODE_SYNPRETTY))
-		return;
-
-	if (n->prev->tok == n->tok &&
-	    n->tok != MDOC_Ft &&
-	    n->tok != MDOC_Fo &&
-	    n->tok != MDOC_Fn) {
-		outflags |= MD_br;
-		return;
-	}
-
-	switch (n->prev->tok) {
-	case MDOC_Fd:
-	case MDOC_Fn:
-	case MDOC_Fo:
-	case MDOC_In:
-	case MDOC_Vt:
-		outflags |= MD_sp;
-		break;
-	case MDOC_Ft:
-		if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
-			outflags |= MD_sp;
-			break;
-		}
-		/* FALLTHROUGH */
-	default:
-		outflags |= MD_br;
-		break;
-	}
-}
-
-static int
-md_pre_An(struct roff_node *n)
-{
-	switch (n->norm->An.auth) {
-	case AUTH_split:
-		outflags &= ~MD_An_nosplit;
-		outflags |= MD_An_split;
-		return 0;
-	case AUTH_nosplit:
-		outflags &= ~MD_An_split;
-		outflags |= MD_An_nosplit;
-		return 0;
-	default:
-		if (outflags & MD_An_split)
-			outflags |= MD_br;
-		else if (n->sec == SEC_AUTHORS &&
-		    ! (outflags & MD_An_nosplit))
-			outflags |= MD_An_split;
-		return 1;
-	}
-}
-
-static int
-md_pre_Ap(struct roff_node *n)
-{
-	outflags &= ~MD_spc;
-	md_word("'");
-	outflags &= ~MD_spc;
-	return 0;
-}
-
-static int
-md_pre_Bd(struct roff_node *n)
-{
-	switch (n->norm->Bd.type) {
-	case DISP_unfilled:
-	case DISP_literal:
-		return md_pre_Dl(n);
-	default:
-		return md_pre_D1(n);
-	}
-}
-
-static int
-md_pre_Bk(struct roff_node *n)
-{
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		return 1;
-	case ROFFT_BODY:
-		outflags |= MD_Bk;
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-static void
-md_post_Bk(struct roff_node *n)
-{
-	if (n->type == ROFFT_BODY)
-		outflags &= ~MD_Bk;
-}
-
-static int
-md_pre_Bl(struct roff_node *n)
-{
-	n->norm->Bl.count = 0;
-	if (n->norm->Bl.type == LIST_column)
-		md_pre_Dl(n);
-	outflags |= MD_sp;
-	return 1;
-}
-
-static void
-md_post_Bl(struct roff_node *n)
-{
-	n->norm->Bl.count = 0;
-	if (n->norm->Bl.type == LIST_column)
-		md_post_D1(n);
-	outflags |= MD_sp;
-}
-
-static int
-md_pre_D1(struct roff_node *n)
-{
-	/*
-	 * Markdown blockquote syntax does not work inside code blocks.
-	 * The best we can do is fall back to another nested code block.
-	 */
-	if (code_blocks) {
-		md_stack('\t');
-		code_blocks++;
-	} else {
-		md_stack('>');
-		quote_blocks++;
-	}
-	outflags |= MD_sp;
-	return 1;
-}
-
-static void
-md_post_D1(struct roff_node *n)
-{
-	md_stack((char)-1);
-	if (code_blocks)
-		code_blocks--;
-	else
-		quote_blocks--;
-	outflags |= MD_sp;
-}
-
-static int
-md_pre_Dl(struct roff_node *n)
-{
-	/*
-	 * Markdown code block syntax does not work inside blockquotes.
-	 * The best we can do is fall back to another nested blockquote.
-	 */
-	if (quote_blocks) {
-		md_stack('>');
-		quote_blocks++;
-	} else {
-		md_stack('\t');
-		code_blocks++;
-	}
-	outflags |= MD_sp;
-	return 1;
-}
-
-static int
-md_pre_En(struct roff_node *n)
-{
-	if (n->norm->Es == NULL ||
-	    n->norm->Es->child == NULL)
-		return 1;
-
-	md_word(n->norm->Es->child->string);
-	outflags &= ~MD_spc;
-	return 1;
-}
-
-static void
-md_post_En(struct roff_node *n)
-{
-	if (n->norm->Es == NULL ||
-	    n->norm->Es->child == NULL ||
-	    n->norm->Es->child->next == NULL)
-		return;
-
-	outflags &= ~MD_spc;
-	md_word(n->norm->Es->child->next->string);
-}
-
-static int
-md_pre_Eo(struct roff_node *n)
-{
-	if (n->end == ENDBODY_NOT &&
-	    n->parent->head->child == NULL &&
-	    n->child != NULL &&
-	    n->child->end != ENDBODY_NOT)
-		md_preword();
-	else if (n->end != ENDBODY_NOT ? n->child != NULL :
-	    n->parent->head->child != NULL && (n->child != NULL ||
-	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
-		outflags &= ~(MD_spc | MD_nl);
-	return 1;
-}
-
-static void
-md_post_Eo(struct roff_node *n)
-{
-	if (n->end != ENDBODY_NOT) {
-		outflags |= MD_spc;
-		return;
-	}
-
-	if (n->child == NULL && n->parent->head->child == NULL)
-		return;
-
-	if (n->parent->tail != NULL && n->parent->tail->child != NULL)
-		outflags &= ~MD_spc;
-        else
-		outflags |= MD_spc;
-}
-
-static int
-md_pre_Fa(struct roff_node *n)
-{
-	int	 am_Fa;
-
-	am_Fa = n->tok == MDOC_Fa;
-
-	if (am_Fa)
-		n = n->child;
-
-	while (n != NULL) {
-		md_rawword("*");
-		outflags &= ~MD_spc;
-		md_node(n);
-		outflags &= ~MD_spc;
-		md_rawword("*");
-		if ((n = n->next) != NULL)
-			md_word(",");
-	}
-	return 0;
-}
-
-static void
-md_post_Fa(struct roff_node *n)
-{
-	if (n->next != NULL && n->next->tok == MDOC_Fa)
-		md_word(",");
-}
-
-static int
-md_pre_Fd(struct roff_node *n)
-{
-	md_pre_syn(n);
-	md_pre_raw(n);
-	return 1;
-}
-
-static void
-md_post_Fd(struct roff_node *n)
-{
-	md_post_raw(n);
-	outflags |= MD_br;
-}
-
-static void
-md_post_Fl(struct roff_node *n)
-{
-	md_post_raw(n);
-	if (n->child == NULL && n->next != NULL &&
-	    n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE))
-		outflags &= ~MD_spc;
-}
-
-static int
-md_pre_Fn(struct roff_node *n)
-{
-	md_pre_syn(n);
-
-	if ((n = n->child) == NULL)
-		return 0;
-
-	md_rawword("**");
-	outflags &= ~MD_spc;
-	md_node(n);
-	outflags &= ~MD_spc;
-	md_rawword("**");
-	outflags &= ~MD_spc;
-	md_word("(");
-
-	if ((n = n->next) != NULL)
-		md_pre_Fa(n);
-	return 0;
-}
-
-static void
-md_post_Fn(struct roff_node *n)
-{
-	md_word(")");
-	if (n->flags & NODE_SYNPRETTY) {
-		md_word(";");
-		outflags |= MD_sp;
-	}
-}
-
-static int
-md_pre_Fo(struct roff_node *n)
-{
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		md_pre_syn(n);
-		break;
-	case ROFFT_HEAD:
-		if (n->child == NULL)
-			return 0;
-		md_pre_raw(n);
-		break;
-	case ROFFT_BODY:
-		outflags &= ~(MD_spc | MD_nl);
-		md_word("(");
-		break;
-	default:
-		break;
-	}
-	return 1;
-}
-
-static void
-md_post_Fo(struct roff_node *n)
-{
-	switch (n->type) {
-	case ROFFT_HEAD:
-		if (n->child != NULL)
-			md_post_raw(n);
-		break;
-	case ROFFT_BODY:
-		md_post_Fn(n);
-		break;
-	default:
-		break;
-	}
-}
-
-static int
-md_pre_In(struct roff_node *n)
-{
-	if (n->flags & NODE_SYNPRETTY) {
-		md_pre_syn(n);
-		md_rawword("**");
-		outflags &= ~MD_spc;
-		md_word("#include <");
-	} else {
-		md_word("<");
-		outflags &= ~MD_spc;
-		md_rawword("*");
-	}
-	outflags &= ~MD_spc;
-	return 1;
-}
-
-static void
-md_post_In(struct roff_node *n)
-{
-	if (n->flags & NODE_SYNPRETTY) {
-		outflags &= ~MD_spc;
-		md_rawword(">**");
-		outflags |= MD_nl;
-	} else {
-		outflags &= ~MD_spc;
-		md_rawword("*>");
-	}
-}
-
-static int
-md_pre_It(struct roff_node *n)
-{
-	struct roff_node	*bln;
-
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		return 1;
-
-	case ROFFT_HEAD:
-		bln = n->parent->parent;
-		if (bln->norm->Bl.comp == 0 &&
-		    bln->norm->Bl.type != LIST_column)
-			outflags |= MD_sp;
-		outflags |= MD_nl;
-
-		switch (bln->norm->Bl.type) {
-		case LIST_item:
-			outflags |= MD_br;
-			return 0;
-		case LIST_inset:
-		case LIST_diag:
-		case LIST_ohang:
-			outflags |= MD_br;
-			return 1;
-		case LIST_tag:
-		case LIST_hang:
-			outflags |= MD_sp;
-			return 1;
-		case LIST_bullet:
-			md_rawword("*\t");
-			break;
-		case LIST_dash:
-		case LIST_hyphen:
-			md_rawword("-\t");
-			break;
-		case LIST_enum:
-			md_preword();
-			if (bln->norm->Bl.count < 99)
-				bln->norm->Bl.count++;
-			printf("%d.\t", bln->norm->Bl.count);
-			escflags &= ~ESC_FON;
-			break;
-		case LIST_column:
-			outflags |= MD_br;
-			return 0;
-		default:
-			return 0;
-		}
-		outflags &= ~MD_spc;
-		outflags |= MD_nonl;
-		outcount = 0;
-		md_stack('\t');
-		if (code_blocks || quote_blocks)
-			list_blocks++;
-		return 0;
-
-	case ROFFT_BODY:
-		bln = n->parent->parent;
-		switch (bln->norm->Bl.type) {
-		case LIST_ohang:
-			outflags |= MD_br;
-			break;
-		case LIST_tag:
-		case LIST_hang:
-			md_pre_D1(n);
-			break;
-		default:
-			break;
-		}
-		return 1;
-
-	default:
-		return 0;
-	}
-}
-
-static void
-md_post_It(struct roff_node *n)
-{
-	struct roff_node	*bln;
-	int			 i, nc;
-
-	if (n->type != ROFFT_BODY)
-		return;
-
-	bln = n->parent->parent;
-	switch (bln->norm->Bl.type) {
-	case LIST_bullet:
-	case LIST_dash:
-	case LIST_hyphen:
-	case LIST_enum:
-		md_stack((char)-1);
-		if (code_blocks || quote_blocks)
-			list_blocks--;
-		break;
-	case LIST_tag:
-	case LIST_hang:
-		md_post_D1(n);
-		break;
-
-	case LIST_column:
-		if (n->next == NULL)
-			break;
-
-		/* Calculate the array index of the current column. */
-
-		i = 0;
-		while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)
-			i++;
-
-		/* 
-		 * If a width was specified for this column,
-		 * subtract what printed, and
-		 * add the same spacing as in mdoc_term.c.
-		 */
-
-		nc = bln->norm->Bl.ncols;
-		i = i < nc ? strlen(bln->norm->Bl.cols[i]) - outcount +
-		    (nc < 5 ? 4 : nc == 5 ? 3 : 1) : 1;
-		if (i < 1)
-			i = 1;
-		while (i-- > 0)
-			putchar(' ');
-
-		outflags &= ~MD_spc;
-		escflags &= ~ESC_FON;
-		outcount = 0;
-		break;
-
-	default:
-		break;
-	}
-}
-
-static void
-md_post_Lb(struct roff_node *n)
-{
-	if (n->sec == SEC_LIBRARY)
-		outflags |= MD_br;
-}
-
-static void
-md_uri(const char *s)
-{
-	while (*s != '\0') {
-		if (strchr("%()<>", *s) != NULL) {
-			printf("%%%2.2hhX", *s);
-			outcount += 3;
-		} else {
-			putchar(*s);
-			outcount++;
-		}
-		s++;
-	}
-}
-
-static int
-md_pre_Lk(struct roff_node *n)
-{
-	const struct roff_node *link, *descr, *punct;
-
-	if ((link = n->child) == NULL)
-		return 0;
-
-	/* Find beginning of trailing punctuation. */
-	punct = n->last;
-	while (punct != link && punct->flags & NODE_DELIMC)
-		punct = punct->prev;
-	punct = punct->next;
-
-	/* Link text. */
-	descr = link->next;
-	if (descr == punct)
-		descr = link;  /* no text */
-	md_rawword("[");
-	outflags &= ~MD_spc;
-	do {
-		md_word(descr->string);
-		descr = descr->next;
-	} while (descr != punct);
-	outflags &= ~MD_spc;
-
-	/* Link target. */
-	md_rawword("](");
-	md_uri(link->string);
-	outflags &= ~MD_spc;
-	md_rawword(")");
-
-	/* Trailing punctuation. */
-	while (punct != NULL) {
-		md_word(punct->string);
-		punct = punct->next;
-	}
-	return 0;
-}
-
-static int
-md_pre_Mt(struct roff_node *n)
-{
-	const struct roff_node *nch;
-
-	md_rawword("[");
-	outflags &= ~MD_spc;
-	for (nch = n->child; nch != NULL; nch = nch->next)
-		md_word(nch->string);
-	outflags &= ~MD_spc;
-	md_rawword("](mailto:");
-	for (nch = n->child; nch != NULL; nch = nch->next) {
-		md_uri(nch->string);
-		if (nch->next != NULL) {
-			putchar(' ');
-			outcount++;
-		}
-	}
-	outflags &= ~MD_spc;
-	md_rawword(")");
-	return 0;
-}
-
-static int
-md_pre_Nd(struct roff_node *n)
-{
-	outflags &= ~MD_nl;
-	outflags |= MD_spc;
-	md_word("-");
-	return 1;
-}
-
-static int
-md_pre_Nm(struct roff_node *n)
-{
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		outflags |= MD_Bk;
-		md_pre_syn(n);
-		break;
-	case ROFFT_HEAD:
-	case ROFFT_ELEM:
-		md_pre_raw(n);
-		break;
-	default:
-		break;
-	}
-	return 1;
-}
-
-static void
-md_post_Nm(struct roff_node *n)
-{
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		outflags &= ~MD_Bk;
-		break;
-	case ROFFT_HEAD:
-	case ROFFT_ELEM:
-		md_post_raw(n);
-		break;
-	default:
-		break;
-	}
-}
-
-static int
-md_pre_No(struct roff_node *n)
-{
-	outflags |= MD_spc_force;
-	return 1;
-}
-
-static int
-md_pre_Ns(struct roff_node *n)
-{
-	outflags &= ~MD_spc;
-	return 0;
-}
-
-static void
-md_post_Pf(struct roff_node *n)
-{
-	if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
-		outflags &= ~MD_spc;
-}
-
-static int
-md_pre_Pp(struct roff_node *n)
-{
-	outflags |= MD_sp;
-	return 0;
-}
-
-static int
-md_pre_Rs(struct roff_node *n)
-{
-	if (n->sec == SEC_SEE_ALSO)
-		outflags |= MD_sp;
-	return 1;
-}
-
-static int
-md_pre_Sh(struct roff_node *n)
-{
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		if (n->sec == SEC_AUTHORS)
-			outflags &= ~(MD_An_split | MD_An_nosplit);
-		break;
-	case ROFFT_HEAD:
-		outflags |= MD_sp;
-		md_rawword(n->tok == MDOC_Sh ? "#" : "##");
-		break;
-	case ROFFT_BODY:
-		outflags |= MD_sp;
-		break;
-	default:
-		break;
-	}
-	return 1;
-}
-
-static int
-md_pre_Sm(struct roff_node *n)
-{
-	if (n->child == NULL)
-		outflags ^= MD_Sm;
-	else if (strcmp("on", n->child->string) == 0)
-		outflags |= MD_Sm;
-	else
-		outflags &= ~MD_Sm;
-
-	if (outflags & MD_Sm)
-		outflags |= MD_spc;
-
-	return 0;
-}
-
-static int
-md_pre_Vt(struct roff_node *n)
-{
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		md_pre_syn(n);
-		return 1;
-	case ROFFT_BODY:
-	case ROFFT_ELEM:
-		md_pre_raw(n);
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-static void
-md_post_Vt(struct roff_node *n)
-{
-	switch (n->type) {
-	case ROFFT_BODY:
-	case ROFFT_ELEM:
-		md_post_raw(n);
-		break;
-	default:
-		break;
-	}
-}
-
-static int
-md_pre_Xr(struct roff_node *n)
-{
-	n = n->child;
-	if (n == NULL)
-		return 0;
-	md_node(n);
-	n = n->next;
-	if (n == NULL)
-		return 0;
-	outflags &= ~MD_spc;
-	md_word("(");
-	md_node(n);
-	md_word(")");
-	return 0;
-}
-
-static int
-md_pre__T(struct roff_node *n)
-{
-	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
-		md_word("\"");
-	else
-		md_rawword("*");
-	outflags &= ~MD_spc;
-	return 1;
-}
-
-static void
-md_post__T(struct roff_node *n)
-{
-	outflags &= ~MD_spc;
-	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
-		md_word("\"");
-	else
-		md_rawword("*");
-	md_post_pc(n);
-}
-
-static int
-md_pre_br(struct roff_node *n)
-{
-	outflags |= MD_br;
-	return 0;
-}

Property changes on: head/contrib/mdocml/mdoc_markdown.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mdoc.c
===================================================================
--- head/contrib/mdocml/mdoc.c	(revision 338825)
+++ head/contrib/mdocml/mdoc.c	(nonexistent)
@@ -1,459 +0,0 @@
-/*	$Id: mdoc.c,v 1.267 2017/06/17 13:06:16 schwarze Exp $ */
-/*
- * 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 "mandoc_aux.h"
-#include "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "libmandoc.h"
-#include "roff_int.h"
-#include "libmdoc.h"
-
-const	char *const __mdoc_argnames[MDOC_ARG_MAX] = {
-	"split",		"nosplit",		"ragged",
-	"unfilled",		"literal",		"file",
-	"offset",		"bullet",		"dash",
-	"hyphen",		"item",			"enum",
-	"tag",			"diag",			"hang",
-	"ohang",		"inset",		"column",
-	"width",		"compact",		"std",
-	"filled",		"words",		"emphasis",
-	"symbolic",		"nested",		"centered"
-};
-const	char * const *mdoc_argnames = __mdoc_argnames;
-
-static	int		  mdoc_ptext(struct roff_man *, int, char *, int);
-static	int		  mdoc_pmacro(struct roff_man *, int, char *, int);
-
-
-/*
- * Main parse routine.  Parses a single line -- really just hands off to
- * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
- */
-int
-mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs)
-{
-
-	if (mdoc->last->type != ROFFT_EQN || ln > mdoc->last->line)
-		mdoc->flags |= MDOC_NEWLINE;
-
-	/*
-	 * Let the roff nS register switch SYNOPSIS mode early,
-	 * such that the parser knows at all times
-	 * whether this mode is on or off.
-	 * Note that this mode is also switched by the Sh macro.
-	 */
-	if (roff_getreg(mdoc->roff, "nS"))
-		mdoc->flags |= MDOC_SYNOPSIS;
-	else
-		mdoc->flags &= ~MDOC_SYNOPSIS;
-
-	return roff_getcontrol(mdoc->roff, buf, &offs) ?
-	    mdoc_pmacro(mdoc, ln, buf, offs) :
-	    mdoc_ptext(mdoc, ln, buf, offs);
-}
-
-void
-mdoc_macro(MACRO_PROT_ARGS)
-{
-	assert(tok >= MDOC_Dd && tok < MDOC_MAX);
-	(*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
-}
-
-void
-mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, enum roff_tok tok)
-{
-	struct roff_node *p;
-
-	p = roff_node_alloc(mdoc, line, pos, ROFFT_TAIL, tok);
-	roff_node_append(mdoc, p);
-	mdoc->next = ROFF_NEXT_CHILD;
-}
-
-struct roff_node *
-mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos,
-    enum roff_tok tok, struct roff_node *body)
-{
-	struct roff_node *p;
-
-	body->flags |= NODE_ENDED;
-	body->parent->flags |= NODE_ENDED;
-	p = roff_node_alloc(mdoc, line, pos, ROFFT_BODY, tok);
-	p->body = body;
-	p->norm = body->norm;
-	p->end = ENDBODY_SPACE;
-	roff_node_append(mdoc, p);
-	mdoc->next = ROFF_NEXT_SIBLING;
-	return p;
-}
-
-struct roff_node *
-mdoc_block_alloc(struct roff_man *mdoc, int line, int pos,
-    enum roff_tok tok, struct mdoc_arg *args)
-{
-	struct roff_node *p;
-
-	p = roff_node_alloc(mdoc, line, pos, ROFFT_BLOCK, tok);
-	p->args = args;
-	if (p->args)
-		(args->refcnt)++;
-
-	switch (tok) {
-	case MDOC_Bd:
-	case MDOC_Bf:
-	case MDOC_Bl:
-	case MDOC_En:
-	case MDOC_Rs:
-		p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
-		break;
-	default:
-		break;
-	}
-	roff_node_append(mdoc, p);
-	mdoc->next = ROFF_NEXT_CHILD;
-	return p;
-}
-
-void
-mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos,
-     enum roff_tok tok, struct mdoc_arg *args)
-{
-	struct roff_node *p;
-
-	p = roff_node_alloc(mdoc, line, pos, ROFFT_ELEM, tok);
-	p->args = args;
-	if (p->args)
-		(args->refcnt)++;
-
-	switch (tok) {
-	case MDOC_An:
-		p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
-		break;
-	default:
-		break;
-	}
-	roff_node_append(mdoc, p);
-	mdoc->next = ROFF_NEXT_CHILD;
-}
-
-void
-mdoc_node_relink(struct roff_man *mdoc, struct roff_node *p)
-{
-
-	roff_node_unlink(mdoc, p);
-	p->prev = p->next = NULL;
-	roff_node_append(mdoc, p);
-}
-
-/*
- * Parse free-form text, that is, a line that does not begin with the
- * control character.
- */
-static int
-mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
-{
-	struct roff_node *n;
-	const char	 *cp, *sp;
-	char		 *c, *ws, *end;
-
-	n = mdoc->last;
-
-	/*
-	 * If a column list contains plain text, assume an implicit item
-	 * macro.  This can happen one or more times at the beginning
-	 * of such a list, intermixed with non-It mdoc macros and with
-	 * nodes generated on the roff level, for example by tbl.
-	 */
-
-	if ((n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
-	     n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) ||
-	    (n->parent != NULL && n->parent->tok == MDOC_Bl &&
-	     n->parent->norm->Bl.type == LIST_column)) {
-		mdoc->flags |= MDOC_FREECOL;
-		mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
-		return 1;
-	}
-
-	/*
-	 * Search for the beginning of unescaped trailing whitespace (ws)
-	 * and for the first character not to be output (end).
-	 */
-
-	/* FIXME: replace with strcspn(). */
-	ws = NULL;
-	for (c = end = buf + offs; *c; c++) {
-		switch (*c) {
-		case ' ':
-			if (NULL == ws)
-				ws = c;
-			continue;
-		case '\t':
-			/*
-			 * Always warn about trailing tabs,
-			 * even outside literal context,
-			 * where they should be put on the next line.
-			 */
-			if (NULL == ws)
-				ws = c;
-			/*
-			 * Strip trailing tabs in literal context only;
-			 * outside, they affect the next line.
-			 */
-			if (MDOC_LITERAL & mdoc->flags)
-				continue;
-			break;
-		case '\\':
-			/* Skip the escaped character, too, if any. */
-			if (c[1])
-				c++;
-			/* FALLTHROUGH */
-		default:
-			ws = NULL;
-			break;
-		}
-		end = c + 1;
-	}
-	*end = '\0';
-
-	if (ws)
-		mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
-		    line, (int)(ws-buf), NULL);
-
-	/*
-	 * Blank lines are allowed in no-fill mode
-	 * and cancel preceding \c,
-	 * but add a single vertical space elsewhere.
-	 */
-
-	if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
-		switch (mdoc->last->type) {
-		case ROFFT_TEXT:
-			sp = mdoc->last->string;
-			cp = end = strchr(sp, '\0') - 2;
-			if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
-				break;
-			while (cp > sp && cp[-1] == '\\')
-				cp--;
-			if ((end - cp) % 2)
-				break;
-			*end = '\0';
-			return 1;
-		default:
-			break;
-		}
-		mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
-		    line, (int)(c - buf), NULL);
-		roff_elem_alloc(mdoc, line, offs, ROFF_sp);
-		mdoc->last->flags |= NODE_VALID | NODE_ENDED;
-		mdoc->next = ROFF_NEXT_SIBLING;
-		return 1;
-	}
-
-	roff_word_alloc(mdoc, line, offs, buf+offs);
-
-	if (mdoc->flags & MDOC_LITERAL)
-		return 1;
-
-	/*
-	 * 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(buf < end);
-
-	if (mandoc_eos(buf+offs, (size_t)(end-buf-offs)))
-		mdoc->last->flags |= NODE_EOS;
-
-	for (c = buf + offs; c != NULL; c = strchr(c + 1, '.')) {
-		if (c - buf < offs + 2)
-			continue;
-		if (end - c < 3)
-			break;
-		if (c[1] != ' ' ||
-		    isalpha((unsigned char)c[-2]) == 0 ||
-		    isalpha((unsigned char)c[-1]) == 0 ||
-		    (c[-2] == 'n' && c[-1] == 'c') ||
-		    (c[-2] == 'v' && c[-1] == 's'))
-			continue;
-		c += 2;
-		if (*c == ' ')
-			c++;
-		if (*c == ' ')
-			c++;
-		if (isupper((unsigned char)(*c)))
-			mandoc_msg(MANDOCERR_EOS, mdoc->parse,
-			    line, (int)(c - buf), NULL);
-	}
-
-	return 1;
-}
-
-/*
- * Parse a macro line, that is, a line beginning with the control
- * character.
- */
-static int
-mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
-{
-	struct roff_node *n;
-	const char	 *cp;
-	size_t		  sz;
-	enum roff_tok	  tok;
-	int		  sv;
-
-	/* Determine the line macro. */
-
-	sv = offs;
-	tok = TOKEN_NONE;
-	for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
-		offs++;
-	if (sz == 2 || sz == 3)
-		tok = roffhash_find(mdoc->mdocmac, buf + sv, sz);
-	if (tok == TOKEN_NONE) {
-		mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
-		    ln, sv, buf + sv - 1);
-		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 ('\0' == buf[offs] && ' ' == buf[offs - 1])
-		mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
-		    ln, offs - 1, NULL);
-
-	/*
-	 * If an initial macro or a list invocation, divert directly
-	 * into macro processing.
-	 */
-
-	n = mdoc->last;
-	if (n == NULL || tok == MDOC_It || tok == MDOC_El) {
-		mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
-		return 1;
-	}
-
-	/*
-	 * If a column list contains a non-It macro, assume an implicit
-	 * item macro.  This can happen one or more times at the
-	 * beginning of such a list, intermixed with text lines and
-	 * with nodes generated on the roff level, for example by tbl.
-	 */
-
-	if ((n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
-	     n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) ||
-	    (n->parent != NULL && n->parent->tok == MDOC_Bl &&
-	     n->parent->norm->Bl.type == LIST_column)) {
-		mdoc->flags |= MDOC_FREECOL;
-		mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
-		return 1;
-	}
-
-	/* Normal processing of a macro. */
-
-	mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
-
-	/* In quick mode (for mandocdb), abort after the NAME section. */
-
-	if (mdoc->quick && MDOC_Sh == tok &&
-	    SEC_NAME != mdoc->last->sec)
-		return 2;
-
-	return 1;
-}
-
-enum mdelim
-mdoc_isdelim(const char *p)
-{
-
-	if ('\0' == p[0])
-		return DELIM_NONE;
-
-	if ('\0' == p[1])
-		switch (p[0]) {
-		case '(':
-		case '[':
-			return DELIM_OPEN;
-		case '|':
-			return DELIM_MIDDLE;
-		case '.':
-		case ',':
-		case ';':
-		case ':':
-		case '?':
-		case '!':
-		case ')':
-		case ']':
-			return DELIM_CLOSE;
-		default:
-			return DELIM_NONE;
-		}
-
-	if ('\\' != p[0])
-		return DELIM_NONE;
-
-	if (0 == strcmp(p + 1, "."))
-		return DELIM_CLOSE;
-	if (0 == strcmp(p + 1, "fR|\\fP"))
-		return DELIM_MIDDLE;
-
-	return DELIM_NONE;
-}
-
-void
-mdoc_validate(struct roff_man *mdoc)
-{
-
-	mdoc->last = mdoc->first;
-	mdoc_node_validate(mdoc);
-	mdoc_state_reset(mdoc);
-}

Property changes on: head/contrib/mdocml/mdoc.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/dba.c
===================================================================
--- head/contrib/mdocml/dba.c	(revision 338825)
+++ head/contrib/mdocml/dba.c	(nonexistent)
@@ -1,508 +0,0 @@
-/*	$Id: dba.c,v 1.10 2017/02/17 14:43:54 schwarze Exp $ */
-/*
- * Copyright (c) 2016, 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.
- *
- * Allocation-based version of the mandoc database, for read-write access.
- * The interface is defined in "dba.h".
- */
-#include "config.h"
-
-#include 
-#if HAVE_ENDIAN
-#include 
-#elif HAVE_SYS_ENDIAN
-#include 
-#elif HAVE_NTOHL
-#include 
-#endif
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "mandoc_ohash.h"
-#include "mansearch.h"
-#include "dba_write.h"
-#include "dba_array.h"
-#include "dba.h"
-
-struct macro_entry {
-	struct dba_array	*pages;
-	char			 value[];
-};
-
-static void	*prepend(const char *, char);
-static void	 dba_pages_write(struct dba_array *);
-static int	 compare_names(const void *, const void *);
-static int	 compare_strings(const void *, const void *);
-
-static struct macro_entry
-		*get_macro_entry(struct ohash *, const char *, int32_t);
-static void	 dba_macros_write(struct dba_array *);
-static void	 dba_macro_write(struct ohash *);
-static int	 compare_entries(const void *, const void *);
-
-
-/*** top-level functions **********************************************/
-
-struct dba *
-dba_new(int32_t npages)
-{
-	struct dba	*dba;
-	struct ohash	*macro;
-	int32_t		 im;
-
-	dba = mandoc_malloc(sizeof(*dba));
-	dba->pages = dba_array_new(npages, DBA_GROW);
-	dba->macros = dba_array_new(MACRO_MAX, 0);
-	for (im = 0; im < MACRO_MAX; im++) {
-		macro = mandoc_malloc(sizeof(*macro));
-		mandoc_ohash_init(macro, 4,
-		    offsetof(struct macro_entry, value));
-		dba_array_set(dba->macros, im, macro);
-	}
-	return dba;
-}
-
-void
-dba_free(struct dba *dba)
-{
-	struct dba_array	*page;
-	struct ohash		*macro;
-	struct macro_entry	*entry;
-	unsigned int		 slot;
-
-	dba_array_FOREACH(dba->macros, macro) {
-		for (entry = ohash_first(macro, &slot); entry != NULL;
-		     entry = ohash_next(macro, &slot)) {
-			dba_array_free(entry->pages);
-			free(entry);
-		}
-		ohash_delete(macro);
-		free(macro);
-	}
-	dba_array_free(dba->macros);
-
-	dba_array_undel(dba->pages);
-	dba_array_FOREACH(dba->pages, page) {
-		dba_array_free(dba_array_get(page, DBP_NAME));
-		dba_array_free(dba_array_get(page, DBP_SECT));
-		dba_array_free(dba_array_get(page, DBP_ARCH));
-		free(dba_array_get(page, DBP_DESC));
-		dba_array_free(dba_array_get(page, DBP_FILE));
-		dba_array_free(page);
-	}
-	dba_array_free(dba->pages);
-
-	free(dba);
-}
-
-/*
- * Write the complete mandoc database to disk; the format is:
- * - One integer each for magic and version.
- * - One pointer each to the macros table and to the final magic.
- * - The pages table.
- * - The macros table.
- * - And at the very end, the magic integer again.
- */
-int
-dba_write(const char *fname, struct dba *dba)
-{
-	int	 save_errno;
-	int32_t	 pos_end, pos_macros, pos_macros_ptr;
-
-	if (dba_open(fname) == -1)
-		return -1;
-	dba_int_write(MANDOCDB_MAGIC);
-	dba_int_write(MANDOCDB_VERSION);
-	pos_macros_ptr = dba_skip(1, 2);
-	dba_pages_write(dba->pages);
-	pos_macros = dba_tell();
-	dba_macros_write(dba->macros);
-	pos_end = dba_tell();
-	dba_int_write(MANDOCDB_MAGIC);
-	dba_seek(pos_macros_ptr);
-	dba_int_write(pos_macros);
-	dba_int_write(pos_end);
-	if (dba_close() == -1) {
-		save_errno = errno;
-		unlink(fname);
-		errno = save_errno;
-		return -1;
-	}
-	return 0;
-}
-
-
-/*** functions for handling pages *************************************/
-
-/*
- * Create a new page and append it to the pages table.
- */
-struct dba_array *
-dba_page_new(struct dba_array *pages, const char *arch,
-    const char *desc, const char *file, enum form form)
-{
-	struct dba_array *page, *entry;
-
-	page = dba_array_new(DBP_MAX, 0);
-	entry = dba_array_new(1, DBA_STR | DBA_GROW);
-	dba_array_add(page, entry);
-	entry = dba_array_new(1, DBA_STR | DBA_GROW);
-	dba_array_add(page, entry);
-	if (arch != NULL && *arch != '\0') {
-		entry = dba_array_new(1, DBA_STR | DBA_GROW);
-		dba_array_add(entry, (void *)arch);
-	} else
-		entry = NULL;
-	dba_array_add(page, entry);
-	dba_array_add(page, mandoc_strdup(desc));
-	entry = dba_array_new(1, DBA_STR | DBA_GROW);
-	dba_array_add(entry, prepend(file, form));
-	dba_array_add(page, entry);
-	dba_array_add(pages, page);
-	return page;
-}
-
-/*
- * Add a section, architecture, or file name to an existing page.
- * Passing the NULL pointer for the architecture makes the page MI.
- * In that case, any earlier or later architectures are ignored.
- */
-void
-dba_page_add(struct dba_array *page, int32_t ie, const char *str)
-{
-	struct dba_array	*entries;
-	char			*entry;
-
-	entries = dba_array_get(page, ie);
-	if (ie == DBP_ARCH) {
-		if (entries == NULL)
-			return;
-		if (str == NULL || *str == '\0') {
-			dba_array_free(entries);
-			dba_array_set(page, DBP_ARCH, NULL);
-			return;
-		}
-	}
-	if (*str == '\0')
-		return;
-	dba_array_FOREACH(entries, entry) {
-		if (ie == DBP_FILE && *entry < ' ')
-			entry++;
-		if (strcmp(entry, str) == 0)
-			return;
-	}
-	dba_array_add(entries, (void *)str);
-}
-
-/*
- * Add an additional name to an existing page.
- */
-void
-dba_page_alias(struct dba_array *page, const char *name, uint64_t mask)
-{
-	struct dba_array	*entries;
-	char			*entry;
-	char			 maskbyte;
-
-	if (*name == '\0')
-		return;
-	maskbyte = mask & NAME_MASK;
-	entries = dba_array_get(page, DBP_NAME);
-	dba_array_FOREACH(entries, entry) {
-		if (strcmp(entry + 1, name) == 0) {
-			*entry |= maskbyte;
-			return;
-		}
-	}
-	dba_array_add(entries, prepend(name, maskbyte));
-}
-
-/*
- * Return a pointer to a temporary copy of instr with inbyte prepended.
- */
-static void *
-prepend(const char *instr, char inbyte)
-{
-	static char	*outstr = NULL;
-	static size_t	 outlen = 0;
-	size_t		 newlen;
-
-	newlen = strlen(instr) + 1;
-	if (newlen > outlen) {
-		outstr = mandoc_realloc(outstr, newlen + 1);
-		outlen = newlen;
-	}
-	*outstr = inbyte;
-	memcpy(outstr + 1, instr, newlen);
-	return outstr;
-}
-
-/*
- * Write the pages table to disk; the format is:
- * - One integer containing the number of pages.
- * - For each page, five pointers to the names, sections,
- *   architectures, description, and file names of the page.
- *   MI pages write 0 instead of the architecture pointer.
- * - One list each for names, sections, architectures, descriptions and
- *   file names.  The description for each page ends with a NUL byte.
- *   For all the other lists, each string ends with a NUL byte,
- *   and the last string for a page ends with two NUL bytes.
- * - To assure alignment of following integers,
- *   the end is padded with NUL bytes up to a multiple of four bytes.
- */
-static void
-dba_pages_write(struct dba_array *pages)
-{
-	struct dba_array	*page, *entry;
-	int32_t			 pos_pages, pos_end;
-
-	pos_pages = dba_array_writelen(pages, 5);
-	dba_array_FOREACH(pages, page) {
-		dba_array_setpos(page, DBP_NAME, dba_tell());
-		entry = dba_array_get(page, DBP_NAME);
-		dba_array_sort(entry, compare_names);
-		dba_array_writelst(entry);
-	}
-	dba_array_FOREACH(pages, page) {
-		dba_array_setpos(page, DBP_SECT, dba_tell());
-		entry = dba_array_get(page, DBP_SECT);
-		dba_array_sort(entry, compare_strings);
-		dba_array_writelst(entry);
-	}
-	dba_array_FOREACH(pages, page) {
-		if ((entry = dba_array_get(page, DBP_ARCH)) != NULL) {
-			dba_array_setpos(page, DBP_ARCH, dba_tell());
-			dba_array_sort(entry, compare_strings);
-			dba_array_writelst(entry);
-		} else
-			dba_array_setpos(page, DBP_ARCH, 0);
-	}
-	dba_array_FOREACH(pages, page) {
-		dba_array_setpos(page, DBP_DESC, dba_tell());
-		dba_str_write(dba_array_get(page, DBP_DESC));
-	}
-	dba_array_FOREACH(pages, page) {
-		dba_array_setpos(page, DBP_FILE, dba_tell());
-		dba_array_writelst(dba_array_get(page, DBP_FILE));
-	}
-	pos_end = dba_align();
-	dba_seek(pos_pages);
-	dba_array_FOREACH(pages, page)
-		dba_array_writepos(page);
-	dba_seek(pos_end);
-}
-
-static int
-compare_names(const void *vp1, const void *vp2)
-{
-	const char	*cp1, *cp2;
-	int		 diff;
-
-	cp1 = *(const char * const *)vp1;
-	cp2 = *(const char * const *)vp2;
-	return (diff = *cp2 - *cp1) ? diff :
-	    strcasecmp(cp1 + 1, cp2 + 1);
-}
-
-static int
-compare_strings(const void *vp1, const void *vp2)
-{
-	const char	*cp1, *cp2;
-
-	cp1 = *(const char * const *)vp1;
-	cp2 = *(const char * const *)vp2;
-	return strcmp(cp1, cp2);
-}
-
-/*** functions for handling macros ************************************/
-
-/*
- * In the hash table for a single macro, look up an entry by
- * the macro value or add an empty one if it doesn't exist yet.
- */
-static struct macro_entry *
-get_macro_entry(struct ohash *macro, const char *value, int32_t np)
-{
-	struct macro_entry	*entry;
-	size_t			 len;
-	unsigned int		 slot;
-
-	slot = ohash_qlookup(macro, value);
-	if ((entry = ohash_find(macro, slot)) == NULL) {
-		len = strlen(value) + 1;
-		entry = mandoc_malloc(sizeof(*entry) + len);
-		memcpy(&entry->value, value, len);
-		entry->pages = dba_array_new(np, DBA_GROW);
-		ohash_insert(macro, slot, entry);
-	}
-	return entry;
-}
-
-/*
- * In addition to get_macro_entry(), add multiple page references,
- * converting them from the on-disk format (byte offsets in the file)
- * to page pointers in memory.
- */
-void
-dba_macro_new(struct dba *dba, int32_t im, const char *value,
-    const int32_t *pp)
-{
-	struct macro_entry	*entry;
-	const int32_t		*ip;
-	int32_t			 np;
-
-	np = 0;
-	for (ip = pp; *ip; ip++)
-		np++;
-
-	entry = get_macro_entry(dba_array_get(dba->macros, im), value, np);
-	for (ip = pp; *ip; ip++)
-		dba_array_add(entry->pages, dba_array_get(dba->pages,
-		    be32toh(*ip) / 5 / sizeof(*ip) - 1));
-}
-
-/*
- * In addition to get_macro_entry(), add one page reference,
- * directly taking the in-memory page pointer as an argument.
- */
-void
-dba_macro_add(struct dba_array *macros, int32_t im, const char *value,
-    struct dba_array *page)
-{
-	struct macro_entry	*entry;
-
-	if (*value == '\0')
-		return;
-	entry = get_macro_entry(dba_array_get(macros, im), value, 1);
-	dba_array_add(entry->pages, page);
-}
-
-/*
- * Write the macros table to disk; the format is:
- * - The number of macro tables (actually, MACRO_MAX).
- * - That number of pointers to the individual macro tables.
- * - The individual macro tables.
- */
-static void
-dba_macros_write(struct dba_array *macros)
-{
-	struct ohash		*macro;
-	int32_t			 im, pos_macros, pos_end;
-
-	pos_macros = dba_array_writelen(macros, 1);
-	im = 0;
-	dba_array_FOREACH(macros, macro) {
-		dba_array_setpos(macros, im++, dba_tell());
-		dba_macro_write(macro);
-	}
-	pos_end = dba_tell();
-	dba_seek(pos_macros);
-	dba_array_writepos(macros);
-	dba_seek(pos_end);
-}
-
-/*
- * Write one individual macro table to disk; the format is:
- * - The number of entries in the table.
- * - For each entry, two pointers, the first one to the value
- *   and the second one to the list of pages.
- * - A list of values, each ending in a NUL byte.
- * - To assure alignment of following integers,
- *   padding with NUL bytes up to a multiple of four bytes.
- * - A list of pointers to pages, each list ending in a 0 integer.
- */
-static void
-dba_macro_write(struct ohash *macro)
-{
-	struct macro_entry	**entries, *entry;
-	struct dba_array	 *page;
-	int32_t			 *kpos, *dpos;
-	unsigned int		  ie, ne, slot;
-	int			  use;
-	int32_t			  addr, pos_macro, pos_end;
-
-	/* Temporary storage for filtering and sorting. */
-
-	ne = ohash_entries(macro);
-	entries = mandoc_reallocarray(NULL, ne, sizeof(*entries));
-	kpos = mandoc_reallocarray(NULL, ne, sizeof(*kpos));
-	dpos = mandoc_reallocarray(NULL, ne, sizeof(*dpos));
-
-	/* Build a list of non-empty entries and sort it. */
-
-	ne = 0;
-	for (entry = ohash_first(macro, &slot); entry != NULL;
-	     entry = ohash_next(macro, &slot)) {
-		use = 0;
-		dba_array_FOREACH(entry->pages, page)
-			if (dba_array_getpos(page))
-				use = 1;
-		if (use)
-			entries[ne++] = entry;
-	}
-	qsort(entries, ne, sizeof(*entries), compare_entries);
-
-	/* Number of entries, and space for the pointer pairs. */
-
-	dba_int_write(ne);
-	pos_macro = dba_skip(2, ne);
-
-	/* String table. */
-
-	for (ie = 0; ie < ne; ie++) {
-		kpos[ie] = dba_tell();
-		dba_str_write(entries[ie]->value);
-	}
-	dba_align();
-
-	/* Pages table. */
-
-	for (ie = 0; ie < ne; ie++) {
-		dpos[ie] = dba_tell();
-		dba_array_FOREACH(entries[ie]->pages, page)
-			if ((addr = dba_array_getpos(page)))
-				dba_int_write(addr);
-		dba_int_write(0);
-	}
-	pos_end = dba_tell();
-
-	/* Fill in the pointer pairs. */
-
-	dba_seek(pos_macro);
-	for (ie = 0; ie < ne; ie++) {
-		dba_int_write(kpos[ie]);
-		dba_int_write(dpos[ie]);
-	}
-	dba_seek(pos_end);
-
-	free(entries);
-	free(kpos);
-	free(dpos);
-}
-
-static int
-compare_entries(const void *vp1, const void *vp2)
-{
-	const struct macro_entry *ep1, *ep2;
-
-	ep1 = *(const struct macro_entry * const *)vp1;
-	ep2 = *(const struct macro_entry * const *)vp2;
-	return strcmp(ep1->value, ep2->value);
-}

Property changes on: head/contrib/mdocml/dba.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/dba_array.c
===================================================================
--- head/contrib/mdocml/dba_array.c	(revision 338825)
+++ head/contrib/mdocml/dba_array.c	(nonexistent)
@@ -1,188 +0,0 @@
-/*	$Id: dba_array.c,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
-/*
- * Copyright (c) 2016 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.
- *
- * Allocation-based arrays for the mandoc database, for read-write access.
- * The interface is defined in "dba_array.h".
- */
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "dba_write.h"
-#include "dba_array.h"
-
-struct dba_array {
-	void	**ep;	/* Array of entries. */
-	int32_t	 *em;	/* Array of map positions. */
-	int	  flags;
-	int32_t	  ea;	/* Entries allocated. */
-	int32_t	  eu;	/* Entries used (including deleted). */
-	int32_t	  ed;	/* Entries deleted. */
-	int32_t	  ec;	/* Currently active entry. */
-	int32_t	  pos;  /* Map position of this array. */
-};
-
-
-struct dba_array *
-dba_array_new(int32_t ea, int flags)
-{
-	struct dba_array	*array;
-
-	assert(ea > 0);
-	array = mandoc_malloc(sizeof(*array));
-	array->ep = mandoc_reallocarray(NULL, ea, sizeof(*array->ep));
-	array->em = mandoc_reallocarray(NULL, ea, sizeof(*array->em));
-	array->ea = ea;
-	array->eu = 0;
-	array->ed = 0;
-	array->ec = 0;
-	array->flags = flags;
-	array->pos = 0;
-	return array;
-}
-
-void
-dba_array_free(struct dba_array *array)
-{
-	int32_t	 ie;
-
-	if (array == NULL)
-		return;
-	if (array->flags & DBA_STR)
-		for (ie = 0; ie < array->eu; ie++)
-			free(array->ep[ie]);
-	free(array->ep);
-	free(array->em);
-	free(array);
-}
-
-void
-dba_array_set(struct dba_array *array, int32_t ie, void *entry)
-{
-	assert(ie >= 0);
-	assert(ie < array->ea);
-	assert(ie <= array->eu);
-	if (ie == array->eu)
-		array->eu++;
-	if (array->flags & DBA_STR)
-		entry = mandoc_strdup(entry);
-	array->ep[ie] = entry;
-	array->em[ie] = 0;
-}
-
-void
-dba_array_add(struct dba_array *array, void *entry)
-{
-	if (array->eu == array->ea) {
-		assert(array->flags & DBA_GROW);
-		array->ep = mandoc_reallocarray(array->ep,
-		    2, sizeof(*array->ep) * array->ea);
-		array->em = mandoc_reallocarray(array->em,
-		    2, sizeof(*array->em) * array->ea);
-		array->ea *= 2;
-	}
-	dba_array_set(array, array->eu, entry);
-}
-
-void *
-dba_array_get(struct dba_array *array, int32_t ie)
-{
-	if (ie < 0 || ie >= array->eu || array->em[ie] == -1)
-		return NULL;
-	return array->ep[ie];
-}
-
-void
-dba_array_start(struct dba_array *array)
-{
-	array->ec = array->eu;
-}
-
-void *
-dba_array_next(struct dba_array *array)
-{
-	if (array->ec < array->eu)
-		array->ec++;
-	else
-		array->ec = 0;
-	while (array->ec < array->eu && array->em[array->ec] == -1)
-		array->ec++;
-	return array->ec < array->eu ? array->ep[array->ec] : NULL;
-}
-
-void
-dba_array_del(struct dba_array *array)
-{
-	if (array->ec < array->eu && array->em[array->ec] != -1) {
-		array->em[array->ec] = -1;
-		array->ed++;
-	}
-}
-
-void
-dba_array_undel(struct dba_array *array)
-{
-	memset(array->em, 0, sizeof(*array->em) * array->eu);
-}
-
-void
-dba_array_setpos(struct dba_array *array, int32_t ie, int32_t pos)
-{
-	array->em[ie] = pos;
-}
-
-int32_t
-dba_array_getpos(struct dba_array *array)
-{
-	return array->pos;
-}
-
-void
-dba_array_sort(struct dba_array *array, dba_compare_func func)
-{
-	assert(array->ed == 0);
-	qsort(array->ep, array->eu, sizeof(*array->ep), func);
-}
-
-int32_t
-dba_array_writelen(struct dba_array *array, int32_t nmemb)
-{
-	dba_int_write(array->eu - array->ed);
-	return dba_skip(nmemb, array->eu - array->ed);
-}
-
-void
-dba_array_writepos(struct dba_array *array)
-{
-	int32_t	 ie;
-
-	array->pos = dba_tell();
-	for (ie = 0; ie < array->eu; ie++)
-		if (array->em[ie] != -1)
-			dba_int_write(array->em[ie]);
-}
-
-void
-dba_array_writelst(struct dba_array *array)
-{
-	const char	*str;
-
-	dba_array_FOREACH(array, str)
-		dba_str_write(str);
-	dba_char_write('\0');
-}

Property changes on: head/contrib/mdocml/dba_array.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mandoc_ohash.h
===================================================================
--- head/contrib/mdocml/mandoc_ohash.h	(revision 338825)
+++ head/contrib/mdocml/mandoc_ohash.h	(nonexistent)
@@ -1,23 +0,0 @@
-/*	$Id: mandoc_ohash.h,v 1.2 2015/11/07 14:01:16 schwarze Exp $	*/
-/*
- * Copyright (c) 2015 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.
- */
-#if HAVE_OHASH
-#include 
-#else
-#include "compat_ohash.h"
-#endif
-
-void		  mandoc_ohash_init(struct ohash *, unsigned int, ptrdiff_t);

Property changes on: head/contrib/mdocml/mandoc_ohash.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mdoc.h
===================================================================
--- head/contrib/mdocml/mdoc.h	(revision 338825)
+++ head/contrib/mdocml/mdoc.h	(nonexistent)
@@ -1,155 +0,0 @@
-/*	$Id: mdoc.h,v 1.145 2017/04/24 23:06:18 schwarze Exp $ */
-/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
- * Copyright (c) 2014, 2015 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	mdocargt {
-	MDOC_Split, /* -split */
-	MDOC_Nosplit, /* -nospli */
-	MDOC_Ragged, /* -ragged */
-	MDOC_Unfilled, /* -unfilled */
-	MDOC_Literal, /* -literal */
-	MDOC_File, /* -file */
-	MDOC_Offset, /* -offset */
-	MDOC_Bullet, /* -bullet */
-	MDOC_Dash, /* -dash */
-	MDOC_Hyphen, /* -hyphen */
-	MDOC_Item, /* -item */
-	MDOC_Enum, /* -enum */
-	MDOC_Tag, /* -tag */
-	MDOC_Diag, /* -diag */
-	MDOC_Hang, /* -hang */
-	MDOC_Ohang, /* -ohang */
-	MDOC_Inset, /* -inset */
-	MDOC_Column, /* -column */
-	MDOC_Width, /* -width */
-	MDOC_Compact, /* -compact */
-	MDOC_Std, /* -std */
-	MDOC_Filled, /* -filled */
-	MDOC_Words, /* -words */
-	MDOC_Emphasis, /* -emphasis */
-	MDOC_Symbolic, /* -symbolic */
-	MDOC_Nested, /* -nested */
-	MDOC_Centred, /* -centered */
-	MDOC_ARG_MAX
-};
-
-/*
- * An argument to a macro (multiple values = `-column xxx yyy').
- */
-struct	mdoc_argv {
-	enum mdocargt	  arg; /* type of argument */
-	int		  line;
-	int		  pos;
-	size_t		  sz; /* elements in "value" */
-	char		**value; /* argument strings */
-};
-
-/*
- * Reference-counted macro arguments.  These are refcounted because
- * blocks have multiple instances of the same arguments spread across
- * the HEAD, BODY, TAIL, and BLOCK node types.
- */
-struct	mdoc_arg {
-	size_t		  argc;
-	struct mdoc_argv *argv;
-	unsigned int	  refcnt;
-};
-
-enum	mdoc_list {
-	LIST__NONE = 0,
-	LIST_bullet, /* -bullet */
-	LIST_column, /* -column */
-	LIST_dash, /* -dash */
-	LIST_diag, /* -diag */
-	LIST_enum, /* -enum */
-	LIST_hang, /* -hang */
-	LIST_hyphen, /* -hyphen */
-	LIST_inset, /* -inset */
-	LIST_item, /* -item */
-	LIST_ohang, /* -ohang */
-	LIST_tag, /* -tag */
-	LIST_MAX
-};
-
-enum	mdoc_disp {
-	DISP__NONE = 0,
-	DISP_centered, /* -centered */
-	DISP_ragged, /* -ragged */
-	DISP_unfilled, /* -unfilled */
-	DISP_filled, /* -filled */
-	DISP_literal /* -literal */
-};
-
-enum	mdoc_auth {
-	AUTH__NONE = 0,
-	AUTH_split, /* -split */
-	AUTH_nosplit /* -nosplit */
-};
-
-enum	mdoc_font {
-	FONT__NONE = 0,
-	FONT_Em, /* Em, -emphasis */
-	FONT_Li, /* Li, -literal */
-	FONT_Sy /* Sy, -symbolic */
-};
-
-struct	mdoc_bd {
-	const char	 *offs; /* -offset */
-	enum mdoc_disp	  type; /* -ragged, etc. */
-	int		  comp; /* -compact */
-};
-
-struct	mdoc_bl {
-	const char	 *width; /* -width */
-	const char	 *offs; /* -offset */
-	enum mdoc_list	  type; /* -tag, -enum, etc. */
-	int		  comp; /* -compact */
-	size_t		  ncols; /* -column arg count */
-	const char	**cols; /* -column val ptr */
-	int		  count; /* -enum counter */
-};
-
-struct	mdoc_bf {
-	enum mdoc_font	  font; /* font */
-};
-
-struct	mdoc_an {
-	enum mdoc_auth	  auth; /* -split, etc. */
-};
-
-struct	mdoc_rs {
-	int		  quote_T; /* whether to quote %T */
-};
-
-/*
- * Consists of normalised node arguments.  These should be used instead
- * of iterating through the mdoc_arg pointers of a node: defaults are
- * provided, etc.
- */
-union	mdoc_data {
-	struct mdoc_an	  An;
-	struct mdoc_bd	  Bd;
-	struct mdoc_bf	  Bf;
-	struct mdoc_bl	  Bl;
-	struct roff_node *Es;
-	struct mdoc_rs	  Rs;
-};
-
-/* Names of macro args.  Index is enum mdocargt. */
-extern	const char *const *mdoc_argnames;
-
-void		 mdoc_validate(struct roff_man *);

Property changes on: head/contrib/mdocml/mdoc.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/dba.h
===================================================================
--- head/contrib/mdocml/dba.h	(revision 338825)
+++ head/contrib/mdocml/dba.h	(nonexistent)
@@ -1,50 +0,0 @@
-/*	$Id: dba.h,v 1.2 2016/08/17 20:46:56 schwarze Exp $ */
-/*
- * Copyright (c) 2016 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.
- *
- * Public interface of the allocation-based version
- * of the mandoc database, for read-write access.
- * To be used by dba.c, dba_read.c, and makewhatis(8).
- */
-
-#define	DBP_NAME	0
-#define	DBP_SECT	1
-#define	DBP_ARCH	2
-#define	DBP_DESC	3
-#define	DBP_FILE	4
-#define	DBP_MAX		5
-
-struct dba_array;
-
-struct dba {
-	struct dba_array	*pages;
-	struct dba_array	*macros;
-};
-
-
-struct dba	*dba_new(int32_t);
-void		 dba_free(struct dba *);
-struct dba	*dba_read(const char *);
-int		 dba_write(const char *, struct dba *);
-
-struct dba_array *dba_page_new(struct dba_array *, const char *,
-			const char *, const char *, enum form);
-void		 dba_page_add(struct dba_array *, int32_t, const char *);
-void		 dba_page_alias(struct dba_array *, const char *, uint64_t);
-
-void		 dba_macro_new(struct dba *, int32_t,
-			const char *, const int32_t *);
-void		 dba_macro_add(struct dba_array *, int32_t,
-			const char *, struct dba_array *);

Property changes on: head/contrib/mdocml/dba.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/dba_array.h
===================================================================
--- head/contrib/mdocml/dba_array.h	(revision 338825)
+++ head/contrib/mdocml/dba_array.h	(nonexistent)
@@ -1,47 +0,0 @@
-/*	$Id: dba_array.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
-/*
- * Copyright (c) 2016 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.
- *
- * Public interface for allocation-based arrays
- * for the mandoc database, for read-write access.
- * To be used by dba*.c and by makewhatis(8).
- */
-
-struct dba_array;
-
-#define	DBA_STR		0x01	/* Map contains strings, not pointers. */
-#define	DBA_GROW	0x02	/* Allow the array to grow. */
-
-#define	dba_array_FOREACH(a, e) \
-	dba_array_start(a); \
-	while (((e) = dba_array_next(a)) != NULL)
-
-typedef int dba_compare_func(const void *, const void *);
-
-struct dba_array *dba_array_new(int32_t, int);
-void		 dba_array_free(struct dba_array *);
-void		 dba_array_set(struct dba_array *, int32_t, void *);
-void		 dba_array_add(struct dba_array *, void *);
-void		*dba_array_get(struct dba_array *, int32_t);
-void		 dba_array_start(struct dba_array *);
-void		*dba_array_next(struct dba_array *);
-void		 dba_array_del(struct dba_array *);
-void		 dba_array_undel(struct dba_array *);
-void		 dba_array_setpos(struct dba_array *, int32_t, int32_t);
-int32_t		 dba_array_getpos(struct dba_array *);
-void		 dba_array_sort(struct dba_array *, dba_compare_func);
-int32_t		 dba_array_writelen(struct dba_array *, int32_t);
-void		 dba_array_writepos(struct dba_array *);
-void		 dba_array_writelst(struct dba_array *);

Property changes on: head/contrib/mdocml/dba_array.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/compat_strcasestr.c
===================================================================
--- head/contrib/mdocml/compat_strcasestr.c	(revision 338825)
+++ head/contrib/mdocml/compat_strcasestr.c	(nonexistent)
@@ -1,73 +0,0 @@
-#include "config.h"
-
-#if HAVE_STRCASESTR
-
-int dummy;
-
-#else
-
-/*	$Id: compat_strcasestr.c,v 1.4 2014/12/11 09:19:32 schwarze Exp $	*/
-/*	$NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $	*/
-
-/*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include 
-#include 
-#include 
-
-#define	__UNCONST(a)	((void *)(unsigned long)(const void *)(a))
-
-/*
- * Find the first occurrence of find in s, ignore case.
- */
-char *
-strcasestr(const char *s, const char *find)
-{
-	char c, sc;
-	size_t len;
-
-	if ((c = *find++) != 0) {
-		c = tolower((unsigned char)c);
-		len = strlen(find);
-		do {
-			do {
-				if ((sc = *s++) == 0)
-					return (NULL);
-			} while ((char)tolower((unsigned char)sc) != c);
-		} while (strncasecmp(s, find, len) != 0);
-		s--;
-	}
-	return __UNCONST(s);
-}
-
-#endif

Property changes on: head/contrib/mdocml/compat_strcasestr.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mandoc_malloc.3
===================================================================
--- head/contrib/mdocml/mandoc_malloc.3	(revision 338825)
+++ head/contrib/mdocml/mandoc_malloc.3	(nonexistent)
@@ -1,191 +0,0 @@
-.\"	$Id: mandoc_malloc.3,v 1.2 2016/07/07 19:19:01 schwarze Exp $
-.\"
-.\" Copyright (c) 2014 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: July 7 2016 $
-.Dt MANDOC_MALLOC 3
-.Os
-.Sh NAME
-.Nm mandoc_malloc ,
-.Nm mandoc_realloc ,
-.Nm mandoc_reallocarray ,
-.Nm mandoc_calloc ,
-.Nm mandoc_strdup ,
-.Nm mandoc_strndup ,
-.Nm mandoc_asprintf
-.Nd memory allocation function wrappers used in the mandoc library
-.Sh SYNOPSIS
-.In sys/types.h
-.In mandoc_aux.h
-.Ft "void *"
-.Fo mandoc_malloc
-.Fa "size_t size"
-.Fc
-.Ft "void *"
-.Fo mandoc_realloc
-.Fa "void *ptr"
-.Fa "size_t size"
-.Fc
-.Ft "void *"
-.Fo mandoc_reallocarray
-.Fa "void *ptr"
-.Fa "size_t nmemb"
-.Fa "size_t size"
-.Fc
-.Ft "void *"
-.Fo mandoc_calloc
-.Fa "size_t nmemb"
-.Fa "size_t size"
-.Fc
-.Ft "char *"
-.Fo mandoc_strdup
-.Fa "const char *s"
-.Fc
-.Ft "char *"
-.Fo mandoc_strndup
-.Fa "const char *s"
-.Fa "size_t maxlen"
-.Fc
-.Ft int
-.Fo mandoc_asprintf
-.Fa "char **ret"
-.Fa "const char *format"
-.Fa "..."
-.Fc
-.Sh DESCRIPTION
-These functions call the libc functions of the same names, passing
-through their return values when successful.
-In case of failure, they do not return, but instead call
-.Xr err 3 .
-They can be used both internally by any code in the mandoc libraries
-and externally by programs using that library, for example
-.Xr mandoc 1 ,
-.Xr man 1 ,
-.Xr apropos 1 ,
-.Xr makewhatis 8 ,
-and
-.Xr man.cgi 8 .
-.Pp
-The function
-.Fn mandoc_malloc
-allocates one new object, leaving the memory uninitialized.
-The functions
-.Fn mandoc_realloc
-and
-.Fn mandoc_reallocarray
-change the size of an existing object or array, possibly moving it.
-When shrinking the size, existing data is truncated; when growing,
-the additional memory is not initialized.
-The function
-.Fn mandoc_calloc
-allocates a new array, initializing it to zero.
-.Pp
-The argument
-.Fa size
-is the size of each object.
-The argument
-.Fa nmemb
-is the new number of objects in the array.
-The argument
-.Fa ptr
-is a pointer to the existing object or array to be resized; if it is
-.Dv NULL ,
-a new object or array is allocated.
-.Pp
-The functions
-.Fn mandoc_strdup
-and
-.Fn mandoc_strndup
-copy a string into newly allocated memory.
-For
-.Fn mandoc_strdup ,
-the string pointed to by
-.Fa s
-needs to be NUL-terminated.
-For
-.Fn mandoc_strndup ,
-at most
-.Fa maxlen
-bytes are copied.
-The function
-.Fn mandoc_asprintf
-writes output formatted according to
-.Fa format
-into newly allocated memory and returns a pointer to the result in
-.Fa ret .
-For all three string functions, the result is always NUL-terminated.
-.Pp
-When the objects and strings are no longer needed,
-the pointers returned by these functions can be passed to
-.Xr free 3 .
-.Sh RETURN VALUES
-The function
-.Fn mandoc_asprintf
-always returns the number of characters written, excluding the
-final NUL byte.
-It never returns -1.
-.Pp
-The other functions always return a valid pointer; they never return
-.Dv NULL .
-.Sh FILES
-These functions are implemented in
-.Pa mandoc_aux.c .
-.Sh SEE ALSO
-.Xr asprintf 3 ,
-.Xr err 3 ,
-.Xr malloc 3 ,
-.Xr strdup 3
-.Sh STANDARDS
-The functions
-.Fn malloc ,
-.Fn realloc ,
-and
-.Fn calloc
-are required by
-.St -ansiC .
-The functions
-.Fn strdup
-and
-.Fn strndup
-are required by
-.St -p1003.1-2008 .
-The function
-.Fn asprintf
-is a widespread extension that first appeared in the GNU C library.
-.Pp
-The function
-.Fn reallocarray
-is an extension that first appeared in
-.Ox 5.6 .
-If it is not provided by the operating system, the mandoc build system
-uses a bundled portable implementation.
-.Sh HISTORY
-The functions
-.Fn mandoc_malloc ,
-.Fn mandoc_realloc ,
-.Fn mandoc_calloc ,
-and
-.Fn mandoc_strdup
-have been available since mandoc 1.9.12,
-.Fn mandoc_strndup
-since 1.11.5,
-and
-.Fn mandoc_asprintf
-and
-.Fn mandoc_reallocarray
-since 1.12.4 and 1.13.0.
-.Sh AUTHORS
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
-.An Ingo Schwarze Aq Mt schwarze@openbsd.org

Property changes on: head/contrib/mdocml/mandoc_malloc.3
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/eqn.c
===================================================================
--- head/contrib/mdocml/eqn.c	(revision 338825)
+++ head/contrib/mdocml/eqn.c	(nonexistent)
@@ -1,1103 +0,0 @@
-/*	$Id: eqn.c,v 1.78 2017/07/15 16:26:17 schwarze Exp $ */
-/*
- * Copyright (c) 2011, 2014 Kristaps Dzonsons 
- * 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.
- */
-#include "config.h"
-
-#include 
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "mandoc.h"
-#include "roff.h"
-#include "libmandoc.h"
-#include "libroff.h"
-
-#define	EQN_NEST_MAX	 128 /* maximum nesting of defines */
-#define	STRNEQ(p1, sz1, p2, sz2) \
-	((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
-
-enum	eqn_tok {
-	EQN_TOK_DYAD = 0,
-	EQN_TOK_VEC,
-	EQN_TOK_UNDER,
-	EQN_TOK_BAR,
-	EQN_TOK_TILDE,
-	EQN_TOK_HAT,
-	EQN_TOK_DOT,
-	EQN_TOK_DOTDOT,
-	EQN_TOK_FWD,
-	EQN_TOK_BACK,
-	EQN_TOK_DOWN,
-	EQN_TOK_UP,
-	EQN_TOK_FAT,
-	EQN_TOK_ROMAN,
-	EQN_TOK_ITALIC,
-	EQN_TOK_BOLD,
-	EQN_TOK_SIZE,
-	EQN_TOK_SUB,
-	EQN_TOK_SUP,
-	EQN_TOK_SQRT,
-	EQN_TOK_OVER,
-	EQN_TOK_FROM,
-	EQN_TOK_TO,
-	EQN_TOK_BRACE_OPEN,
-	EQN_TOK_BRACE_CLOSE,
-	EQN_TOK_GSIZE,
-	EQN_TOK_GFONT,
-	EQN_TOK_MARK,
-	EQN_TOK_LINEUP,
-	EQN_TOK_LEFT,
-	EQN_TOK_RIGHT,
-	EQN_TOK_PILE,
-	EQN_TOK_LPILE,
-	EQN_TOK_RPILE,
-	EQN_TOK_CPILE,
-	EQN_TOK_MATRIX,
-	EQN_TOK_CCOL,
-	EQN_TOK_LCOL,
-	EQN_TOK_RCOL,
-	EQN_TOK_DELIM,
-	EQN_TOK_DEFINE,
-	EQN_TOK_TDEFINE,
-	EQN_TOK_NDEFINE,
-	EQN_TOK_UNDEF,
-	EQN_TOK_ABOVE,
-	EQN_TOK__MAX,
-	EQN_TOK_FUNC,
-	EQN_TOK_QUOTED,
-	EQN_TOK_SYM,
-	EQN_TOK_EOF
-};
-
-static	const char *eqn_toks[EQN_TOK__MAX] = {
-	"dyad", /* EQN_TOK_DYAD */
-	"vec", /* EQN_TOK_VEC */
-	"under", /* EQN_TOK_UNDER */
-	"bar", /* EQN_TOK_BAR */
-	"tilde", /* EQN_TOK_TILDE */
-	"hat", /* EQN_TOK_HAT */
-	"dot", /* EQN_TOK_DOT */
-	"dotdot", /* EQN_TOK_DOTDOT */
-	"fwd", /* EQN_TOK_FWD * */
-	"back", /* EQN_TOK_BACK */
-	"down", /* EQN_TOK_DOWN */
-	"up", /* EQN_TOK_UP */
-	"fat", /* EQN_TOK_FAT */
-	"roman", /* EQN_TOK_ROMAN */
-	"italic", /* EQN_TOK_ITALIC */
-	"bold", /* EQN_TOK_BOLD */
-	"size", /* EQN_TOK_SIZE */
-	"sub", /* EQN_TOK_SUB */
-	"sup", /* EQN_TOK_SUP */
-	"sqrt", /* EQN_TOK_SQRT */
-	"over", /* EQN_TOK_OVER */
-	"from", /* EQN_TOK_FROM */
-	"to", /* EQN_TOK_TO */
-	"{", /* EQN_TOK_BRACE_OPEN */
-	"}", /* EQN_TOK_BRACE_CLOSE */
-	"gsize", /* EQN_TOK_GSIZE */
-	"gfont", /* EQN_TOK_GFONT */
-	"mark", /* EQN_TOK_MARK */
-	"lineup", /* EQN_TOK_LINEUP */
-	"left", /* EQN_TOK_LEFT */
-	"right", /* EQN_TOK_RIGHT */
-	"pile", /* EQN_TOK_PILE */
-	"lpile", /* EQN_TOK_LPILE */
-	"rpile", /* EQN_TOK_RPILE */
-	"cpile", /* EQN_TOK_CPILE */
-	"matrix", /* EQN_TOK_MATRIX */
-	"ccol", /* EQN_TOK_CCOL */
-	"lcol", /* EQN_TOK_LCOL */
-	"rcol", /* EQN_TOK_RCOL */
-	"delim", /* EQN_TOK_DELIM */
-	"define", /* EQN_TOK_DEFINE */
-	"tdefine", /* EQN_TOK_TDEFINE */
-	"ndefine", /* EQN_TOK_NDEFINE */
-	"undef", /* EQN_TOK_UNDEF */
-	"above", /* EQN_TOK_ABOVE */
-};
-
-static	const char *const eqn_func[] = {
-	"acos",	"acsc",	"and",	"arc",	"asec",	"asin", "atan",
-	"cos",	"cosh", "coth",	"csc",	"det",	"exp",	"for",
-	"if",	"lim",	"ln",	"log",	"max",	"min",
-	"sec",	"sin",	"sinh",	"tan",	"tanh",	"Im",	"Re",
-};
-
-enum	eqn_symt {
-	EQNSYM_alpha = 0,
-	EQNSYM_beta,
-	EQNSYM_chi,
-	EQNSYM_delta,
-	EQNSYM_epsilon,
-	EQNSYM_eta,
-	EQNSYM_gamma,
-	EQNSYM_iota,
-	EQNSYM_kappa,
-	EQNSYM_lambda,
-	EQNSYM_mu,
-	EQNSYM_nu,
-	EQNSYM_omega,
-	EQNSYM_omicron,
-	EQNSYM_phi,
-	EQNSYM_pi,
-	EQNSYM_ps,
-	EQNSYM_rho,
-	EQNSYM_sigma,
-	EQNSYM_tau,
-	EQNSYM_theta,
-	EQNSYM_upsilon,
-	EQNSYM_xi,
-	EQNSYM_zeta,
-	EQNSYM_DELTA,
-	EQNSYM_GAMMA,
-	EQNSYM_LAMBDA,
-	EQNSYM_OMEGA,
-	EQNSYM_PHI,
-	EQNSYM_PI,
-	EQNSYM_PSI,
-	EQNSYM_SIGMA,
-	EQNSYM_THETA,
-	EQNSYM_UPSILON,
-	EQNSYM_XI,
-	EQNSYM_inter,
-	EQNSYM_union,
-	EQNSYM_prod,
-	EQNSYM_int,
-	EQNSYM_sum,
-	EQNSYM_grad,
-	EQNSYM_del,
-	EQNSYM_times,
-	EQNSYM_cdot,
-	EQNSYM_nothing,
-	EQNSYM_approx,
-	EQNSYM_prime,
-	EQNSYM_half,
-	EQNSYM_partial,
-	EQNSYM_inf,
-	EQNSYM_muchgreat,
-	EQNSYM_muchless,
-	EQNSYM_larrow,
-	EQNSYM_rarrow,
-	EQNSYM_pm,
-	EQNSYM_nequal,
-	EQNSYM_equiv,
-	EQNSYM_lessequal,
-	EQNSYM_moreequal,
-	EQNSYM_minus,
-	EQNSYM__MAX
-};
-
-struct	eqnsym {
-	const char	*str;
-	const char	*sym;
-};
-
-static	const struct eqnsym eqnsyms[EQNSYM__MAX] = {
-	{ "alpha", "*a" }, /* EQNSYM_alpha */
-	{ "beta", "*b" }, /* EQNSYM_beta */
-	{ "chi", "*x" }, /* EQNSYM_chi */
-	{ "delta", "*d" }, /* EQNSYM_delta */
-	{ "epsilon", "*e" }, /* EQNSYM_epsilon */
-	{ "eta", "*y" }, /* EQNSYM_eta */
-	{ "gamma", "*g" }, /* EQNSYM_gamma */
-	{ "iota", "*i" }, /* EQNSYM_iota */
-	{ "kappa", "*k" }, /* EQNSYM_kappa */
-	{ "lambda", "*l" }, /* EQNSYM_lambda */
-	{ "mu", "*m" }, /* EQNSYM_mu */
-	{ "nu", "*n" }, /* EQNSYM_nu */
-	{ "omega", "*w" }, /* EQNSYM_omega */
-	{ "omicron", "*o" }, /* EQNSYM_omicron */
-	{ "phi", "*f" }, /* EQNSYM_phi */
-	{ "pi", "*p" }, /* EQNSYM_pi */
-	{ "psi", "*q" }, /* EQNSYM_psi */
-	{ "rho", "*r" }, /* EQNSYM_rho */
-	{ "sigma", "*s" }, /* EQNSYM_sigma */
-	{ "tau", "*t" }, /* EQNSYM_tau */
-	{ "theta", "*h" }, /* EQNSYM_theta */
-	{ "upsilon", "*u" }, /* EQNSYM_upsilon */
-	{ "xi", "*c" }, /* EQNSYM_xi */
-	{ "zeta", "*z" }, /* EQNSYM_zeta */
-	{ "DELTA", "*D" }, /* EQNSYM_DELTA */
-	{ "GAMMA", "*G" }, /* EQNSYM_GAMMA */
-	{ "LAMBDA", "*L" }, /* EQNSYM_LAMBDA */
-	{ "OMEGA", "*W" }, /* EQNSYM_OMEGA */
-	{ "PHI", "*F" }, /* EQNSYM_PHI */
-	{ "PI", "*P" }, /* EQNSYM_PI */
-	{ "PSI", "*Q" }, /* EQNSYM_PSI */
-	{ "SIGMA", "*S" }, /* EQNSYM_SIGMA */
-	{ "THETA", "*H" }, /* EQNSYM_THETA */
-	{ "UPSILON", "*U" }, /* EQNSYM_UPSILON */
-	{ "XI", "*C" }, /* EQNSYM_XI */
-	{ "inter", "ca" }, /* EQNSYM_inter */
-	{ "union", "cu" }, /* EQNSYM_union */
-	{ "prod", "product" }, /* EQNSYM_prod */
-	{ "int", "integral" }, /* EQNSYM_int */
-	{ "sum", "sum" }, /* EQNSYM_sum */
-	{ "grad", "gr" }, /* EQNSYM_grad */
-	{ "del", "gr" }, /* EQNSYM_del */
-	{ "times", "mu" }, /* EQNSYM_times */
-	{ "cdot", "pc" }, /* EQNSYM_cdot */
-	{ "nothing", "&" }, /* EQNSYM_nothing */
-	{ "approx", "~~" }, /* EQNSYM_approx */
-	{ "prime", "fm" }, /* EQNSYM_prime */
-	{ "half", "12" }, /* EQNSYM_half */
-	{ "partial", "pd" }, /* EQNSYM_partial */
-	{ "inf", "if" }, /* EQNSYM_inf */
-	{ ">>", ">>" }, /* EQNSYM_muchgreat */
-	{ "<<", "<<" }, /* EQNSYM_muchless */
-	{ "<-", "<-" }, /* EQNSYM_larrow */
-	{ "->", "->" }, /* EQNSYM_rarrow */
-	{ "+-", "+-" }, /* EQNSYM_pm */
-	{ "!=", "!=" }, /* EQNSYM_nequal */
-	{ "==", "==" }, /* EQNSYM_equiv */
-	{ "<=", "<=" }, /* EQNSYM_lessequal */
-	{ ">=", ">=" }, /* EQNSYM_moreequal */
-	{ "-", "mi" }, /* EQNSYM_minus */
-};
-
-enum	parse_mode {
-	MODE_QUOTED,
-	MODE_NOSUB,
-	MODE_SUB,
-	MODE_TOK
-};
-
-static	struct eqn_box	*eqn_box_alloc(struct eqn_node *, struct eqn_box *);
-static	struct eqn_box	*eqn_box_makebinary(struct eqn_node *,
-				struct eqn_box *);
-static	void		 eqn_def(struct eqn_node *);
-static	struct eqn_def	*eqn_def_find(struct eqn_node *);
-static	void		 eqn_delim(struct eqn_node *);
-static	enum eqn_tok	 eqn_next(struct eqn_node *, enum parse_mode);
-static	void		 eqn_undef(struct eqn_node *);
-
-
-struct eqn_node *
-eqn_alloc(struct mparse *parse)
-{
-	struct eqn_node *ep;
-
-	ep = mandoc_calloc(1, sizeof(*ep));
-	ep->parse = parse;
-	ep->gsize = EQN_DEFSIZE;
-	return ep;
-}
-
-void
-eqn_reset(struct eqn_node *ep)
-{
-	free(ep->data);
-	ep->data = ep->start = ep->end = NULL;
-	ep->sz = ep->toksz = 0;
-}
-
-void
-eqn_read(struct eqn_node *ep, const char *p)
-{
-	char		*cp;
-
-	if (ep->data == NULL) {
-		ep->sz = strlen(p);
-		ep->data = mandoc_strdup(p);
-	} else {
-		ep->sz = mandoc_asprintf(&cp, "%s %s", ep->data, p);
-		free(ep->data);
-		ep->data = cp;
-	}
-	ep->sz += 1;
-}
-
-/*
- * Find the key "key" of the give size within our eqn-defined values.
- */
-static struct eqn_def *
-eqn_def_find(struct eqn_node *ep)
-{
-	int		 i;
-
-	for (i = 0; i < (int)ep->defsz; i++)
-		if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
-		    ep->defs[i].keysz, ep->start, ep->toksz))
-			return &ep->defs[i];
-
-	return NULL;
-}
-
-/*
- * Parse a token from the input text.  The modes are:
- * MODE_QUOTED: Use *ep->start as the delimiter; the token ends
- *   before its next occurence.  Do not interpret the token in any
- *   way and return EQN_TOK_QUOTED.  All other modes behave like
- *   MODE_QUOTED when *ep->start is '"'.
- * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it;
- *   otherwise, it ends before the next whitespace or brace.
- *   Do not interpret the token and return EQN_TOK__MAX.
- * MODE_SUB: Like MODE_NOSUB, but try to interpret the token as an
- *   alias created with define.  If it is an alias, replace it with
- *   its string value and reparse.
- * MODE_TOK: Like MODE_SUB, but also check the token against the list
- *   of tokens, and if there is a match, return that token.  Otherwise,
- *   if the token matches a symbol, return EQN_TOK_SYM; if it matches
- *   a function name, EQN_TOK_FUNC, or else EQN_TOK__MAX.  Except for
- *   a token match, *ep->start is set to an allocated string that the
- *   caller is expected to free.
- * All modes skip whitespace following the end of the token.
- */
-static enum eqn_tok
-eqn_next(struct eqn_node *ep, enum parse_mode mode)
-{
-	static int	 last_len, lim;
-
-	struct eqn_def	*def;
-	size_t		 start;
-	int		 diff, i, quoted;
-	enum eqn_tok	 tok;
-
-	/*
-	 * Reset the recursion counter after advancing
-	 * beyond the end of the previous substitution.
-	 */
-	if (ep->end - ep->data >= last_len)
-		lim = 0;
-
-	ep->start = ep->end;
-	quoted = mode == MODE_QUOTED;
-	for (;;) {
-		switch (*ep->start) {
-		case '\0':
-			ep->toksz = 0;
-			return EQN_TOK_EOF;
-		case '"':
-			quoted = 1;
-			break;
-		default:
-			break;
-		}
-		if (quoted) {
-			ep->end = strchr(ep->start + 1, *ep->start);
-			ep->start++;  /* Skip opening quote. */
-			if (ep->end == NULL) {
-				mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
-				    ep->node->line, ep->node->pos, NULL);
-				ep->end = strchr(ep->start, '\0');
-			}
-		} else {
-			ep->end = ep->start + 1;
-			if (*ep->start != '{' && *ep->start != '}')
-				ep->end += strcspn(ep->end, " ^~\"{}\t");
-		}
-		ep->toksz = ep->end - ep->start;
-		if (quoted && *ep->end != '\0')
-			ep->end++;  /* Skip closing quote. */
-		while (*ep->end != '\0' && strchr(" \t^~", *ep->end) != NULL)
-			ep->end++;
-		if (quoted)  /* Cannot return, may have to strndup. */
-			break;
-		if (mode == MODE_NOSUB)
-			return EQN_TOK__MAX;
-		if ((def = eqn_def_find(ep)) == NULL)
-			break;
-		if (++lim > EQN_NEST_MAX) {
-			mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
-			    ep->node->line, ep->node->pos, NULL);
-			return EQN_TOK_EOF;
-		}
-
-		/* Replace a defined name with its string value. */
-		if ((diff = def->valsz - ep->toksz) > 0) {
-			start = ep->start - ep->data;
-			ep->sz += diff;
-			ep->data = mandoc_realloc(ep->data, ep->sz + 1);
-			ep->start = ep->data + start;
-		}
-		if (diff)
-			memmove(ep->start + def->valsz, ep->start + ep->toksz,
-			    strlen(ep->start + ep->toksz) + 1);
-		memcpy(ep->start, def->val, def->valsz);
-		last_len = ep->start - ep->data + def->valsz;
-	}
-	if (mode != MODE_TOK)
-		return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX;
-	if (quoted) {
-		ep->start = mandoc_strndup(ep->start, ep->toksz);
-		return EQN_TOK_QUOTED;
-	}
-	for (tok = 0; tok < EQN_TOK__MAX; tok++)
-		if (STRNEQ(ep->start, ep->toksz,
-		    eqn_toks[tok], strlen(eqn_toks[tok])))
-			return tok;
-
-	for (i = 0; i < EQNSYM__MAX; i++) {
-		if (STRNEQ(ep->start, ep->toksz,
-		    eqnsyms[i].str, strlen(eqnsyms[i].str))) {
-			mandoc_asprintf(&ep->start,
-			    "\\[%s]", eqnsyms[i].sym);
-			return EQN_TOK_SYM;
-		}
-	}
-	ep->start = mandoc_strndup(ep->start, ep->toksz);
-	for (i = 0; i < (int)(sizeof(eqn_func)/sizeof(*eqn_func)); i++)
-		if (STRNEQ(ep->start, ep->toksz,
-		    eqn_func[i], strlen(eqn_func[i])))
-			return EQN_TOK_FUNC;
-	return EQN_TOK__MAX;
-}
-
-void
-eqn_box_free(struct eqn_box *bp)
-{
-
-	if (bp->first)
-		eqn_box_free(bp->first);
-	if (bp->next)
-		eqn_box_free(bp->next);
-
-	free(bp->text);
-	free(bp->left);
-	free(bp->right);
-	free(bp->top);
-	free(bp->bottom);
-	free(bp);
-}
-
-/*
- * Allocate a box as the last child of the parent node.
- */
-static struct eqn_box *
-eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
-{
-	struct eqn_box	*bp;
-
-	bp = mandoc_calloc(1, sizeof(struct eqn_box));
-	bp->parent = parent;
-	bp->parent->args++;
-	bp->expectargs = UINT_MAX;
-	bp->font = bp->parent->font;
-	bp->size = ep->gsize;
-
-	if (NULL != parent->first) {
-		parent->last->next = bp;
-		bp->prev = parent->last;
-	} else
-		parent->first = bp;
-
-	parent->last = bp;
-	return bp;
-}
-
-/*
- * Reparent the current last node (of the current parent) under a new
- * EQN_SUBEXPR as the first element.
- * Then return the new parent.
- * The new EQN_SUBEXPR will have a two-child limit.
- */
-static struct eqn_box *
-eqn_box_makebinary(struct eqn_node *ep, struct eqn_box *parent)
-{
-	struct eqn_box	*b, *newb;
-
-	assert(NULL != parent->last);
-	b = parent->last;
-	if (parent->last == parent->first)
-		parent->first = NULL;
-	parent->args--;
-	parent->last = b->prev;
-	b->prev = NULL;
-	newb = eqn_box_alloc(ep, parent);
-	newb->type = EQN_SUBEXPR;
-	newb->expectargs = 2;
-	newb->args = 1;
-	newb->first = newb->last = b;
-	newb->first->next = NULL;
-	b->parent = newb;
-	return newb;
-}
-
-/*
- * Parse the "delim" control statement.
- */
-static void
-eqn_delim(struct eqn_node *ep)
-{
-	if (ep->end[0] == '\0' || ep->end[1] == '\0') {
-		mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-		    ep->node->line, ep->node->pos, "delim");
-		if (ep->end[0] != '\0')
-			ep->end++;
-	} else if (strncmp(ep->end, "off", 3) == 0) {
-		ep->delim = 0;
-		ep->end += 3;
-	} else if (strncmp(ep->end, "on", 2) == 0) {
-		if (ep->odelim && ep->cdelim)
-			ep->delim = 1;
-		ep->end += 2;
-	} else {
-		ep->odelim = *ep->end++;
-		ep->cdelim = *ep->end++;
-		ep->delim = 1;
-	}
-}
-
-/*
- * Undefine a previously-defined string.
- */
-static void
-eqn_undef(struct eqn_node *ep)
-{
-	struct eqn_def	*def;
-
-	if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
-		mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-		    ep->node->line, ep->node->pos, "undef");
-		return;
-	}
-	if ((def = eqn_def_find(ep)) == NULL)
-		return;
-	free(def->key);
-	free(def->val);
-	def->key = def->val = NULL;
-	def->keysz = def->valsz = 0;
-}
-
-static void
-eqn_def(struct eqn_node *ep)
-{
-	struct eqn_def	*def;
-	int		 i;
-
-	if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
-		mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-		    ep->node->line, ep->node->pos, "define");
-		return;
-	}
-
-	/*
-	 * Search for a key that already exists.
-	 * Create a new key if none is found.
-	 */
-	if ((def = eqn_def_find(ep)) == NULL) {
-		/* Find holes in string array. */
-		for (i = 0; i < (int)ep->defsz; i++)
-			if (0 == ep->defs[i].keysz)
-				break;
-
-		if (i == (int)ep->defsz) {
-			ep->defsz++;
-			ep->defs = mandoc_reallocarray(ep->defs,
-			    ep->defsz, sizeof(struct eqn_def));
-			ep->defs[i].key = ep->defs[i].val = NULL;
-		}
-
-		def = ep->defs + i;
-		free(def->key);
-		def->key = mandoc_strndup(ep->start, ep->toksz);
-		def->keysz = ep->toksz;
-	}
-
-	if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
-		mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
-		    ep->node->line, ep->node->pos, "define %s", def->key);
-		free(def->key);
-		free(def->val);
-		def->key = def->val = NULL;
-		def->keysz = def->valsz = 0;
-		return;
-	}
-	free(def->val);
-	def->val = mandoc_strndup(ep->start, ep->toksz);
-	def->valsz = ep->toksz;
-}
-
-void
-eqn_parse(struct eqn_node *ep)
-{
-	struct eqn_box	*cur, *nbox, *parent, *split;
-	const char	*cp, *cpn;
-	char		*p;
-	enum eqn_tok	 tok;
-	enum { CCL_LET, CCL_DIG, CCL_PUN } ccl, ccln;
-	int		 size;
-
-	parent = ep->node->eqn;
-	assert(parent != NULL);
-
-	/*
-	 * Empty equation.
-	 * Do not add it to the high-level syntax tree.
-	 */
-
-	if (ep->data == NULL)
-		return;
-
-	ep->start = ep->end = ep->data + strspn(ep->data, " ^~");
-
-next_tok:
-	tok = eqn_next(ep, MODE_TOK);
-	switch (tok) {
-	case EQN_TOK_UNDEF:
-		eqn_undef(ep);
-		break;
-	case EQN_TOK_NDEFINE:
-	case EQN_TOK_DEFINE:
-		eqn_def(ep);
-		break;
-	case EQN_TOK_TDEFINE:
-		if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
-		    eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)
-			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-			    ep->node->line, ep->node->pos, "tdefine");
-		break;
-	case EQN_TOK_DELIM:
-		eqn_delim(ep);
-		break;
-	case EQN_TOK_GFONT:
-		if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
-			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-		break;
-	case EQN_TOK_MARK:
-	case EQN_TOK_LINEUP:
-		/* Ignore these. */
-		break;
-	case EQN_TOK_DYAD:
-	case EQN_TOK_VEC:
-	case EQN_TOK_UNDER:
-	case EQN_TOK_BAR:
-	case EQN_TOK_TILDE:
-	case EQN_TOK_HAT:
-	case EQN_TOK_DOT:
-	case EQN_TOK_DOTDOT:
-		if (parent->last == NULL) {
-			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-			cur = eqn_box_alloc(ep, parent);
-			cur->type = EQN_TEXT;
-			cur->text = mandoc_strdup("");
-		}
-		parent = eqn_box_makebinary(ep, parent);
-		parent->type = EQN_LIST;
-		parent->expectargs = 1;
-		parent->font = EQNFONT_ROMAN;
-		switch (tok) {
-		case EQN_TOK_DOTDOT:
-			parent->top = mandoc_strdup("\\[ad]");
-			break;
-		case EQN_TOK_VEC:
-			parent->top = mandoc_strdup("\\[->]");
-			break;
-		case EQN_TOK_DYAD:
-			parent->top = mandoc_strdup("\\[<>]");
-			break;
-		case EQN_TOK_TILDE:
-			parent->top = mandoc_strdup("\\[a~]");
-			break;
-		case EQN_TOK_UNDER:
-			parent->bottom = mandoc_strdup("\\[ul]");
-			break;
-		case EQN_TOK_BAR:
-			parent->top = mandoc_strdup("\\[rn]");
-			break;
-		case EQN_TOK_DOT:
-			parent->top = mandoc_strdup("\\[a.]");
-			break;
-		case EQN_TOK_HAT:
-			parent->top = mandoc_strdup("\\[ha]");
-			break;
-		default:
-			abort();
-		}
-		parent = parent->parent;
-		break;
-	case EQN_TOK_FWD:
-	case EQN_TOK_BACK:
-	case EQN_TOK_DOWN:
-	case EQN_TOK_UP:
-		if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
-			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-		break;
-	case EQN_TOK_FAT:
-	case EQN_TOK_ROMAN:
-	case EQN_TOK_ITALIC:
-	case EQN_TOK_BOLD:
-		while (parent->args == parent->expectargs)
-			parent = parent->parent;
-		/*
-		 * These values apply to the next word or sequence of
-		 * words; thus, we mark that we'll have a child with
-		 * exactly one of those.
-		 */
-		parent = eqn_box_alloc(ep, parent);
-		parent->type = EQN_LIST;
-		parent->expectargs = 1;
-		switch (tok) {
-		case EQN_TOK_FAT:
-			parent->font = EQNFONT_FAT;
-			break;
-		case EQN_TOK_ROMAN:
-			parent->font = EQNFONT_ROMAN;
-			break;
-		case EQN_TOK_ITALIC:
-			parent->font = EQNFONT_ITALIC;
-			break;
-		case EQN_TOK_BOLD:
-			parent->font = EQNFONT_BOLD;
-			break;
-		default:
-			abort();
-		}
-		break;
-	case EQN_TOK_SIZE:
-	case EQN_TOK_GSIZE:
-		/* Accept two values: integral size and a single. */
-		if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
-			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-			break;
-		}
-		size = mandoc_strntoi(ep->start, ep->toksz, 10);
-		if (-1 == size) {
-			mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-			break;
-		}
-		if (EQN_TOK_GSIZE == tok) {
-			ep->gsize = size;
-			break;
-		}
-		while (parent->args == parent->expectargs)
-			parent = parent->parent;
-		parent = eqn_box_alloc(ep, parent);
-		parent->type = EQN_LIST;
-		parent->expectargs = 1;
-		parent->size = size;
-		break;
-	case EQN_TOK_FROM:
-	case EQN_TOK_TO:
-	case EQN_TOK_SUB:
-	case EQN_TOK_SUP:
-		/*
-		 * We have a left-right-associative expression.
-		 * Repivot under a positional node, open a child scope
-		 * and keep on reading.
-		 */
-		if (parent->last == NULL) {
-			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-			cur = eqn_box_alloc(ep, parent);
-			cur->type = EQN_TEXT;
-			cur->text = mandoc_strdup("");
-		}
-		while (parent->expectargs == 1 && parent->args == 1)
-			parent = parent->parent;
-		if (tok == EQN_TOK_FROM || tok == EQN_TOK_TO)  {
-			for (cur = parent; cur != NULL; cur = cur->parent)
-				if (cur->pos == EQNPOS_SUB ||
-				    cur->pos == EQNPOS_SUP ||
-				    cur->pos == EQNPOS_SUBSUP ||
-				    cur->pos == EQNPOS_SQRT ||
-				    cur->pos == EQNPOS_OVER)
-					break;
-			if (cur != NULL)
-				parent = cur->parent;
-		}
-		if (tok == EQN_TOK_SUP && parent->pos == EQNPOS_SUB) {
-			parent->expectargs = 3;
-			parent->pos = EQNPOS_SUBSUP;
-			break;
-		}
-		if (tok == EQN_TOK_TO && parent->pos == EQNPOS_FROM) {
-			parent->expectargs = 3;
-			parent->pos = EQNPOS_FROMTO;
-			break;
-		}
-		parent = eqn_box_makebinary(ep, parent);
-		switch (tok) {
-		case EQN_TOK_FROM:
-			parent->pos = EQNPOS_FROM;
-			break;
-		case EQN_TOK_TO:
-			parent->pos = EQNPOS_TO;
-			break;
-		case EQN_TOK_SUP:
-			parent->pos = EQNPOS_SUP;
-			break;
-		case EQN_TOK_SUB:
-			parent->pos = EQNPOS_SUB;
-			break;
-		default:
-			abort();
-		}
-		break;
-	case EQN_TOK_SQRT:
-		while (parent->args == parent->expectargs)
-			parent = parent->parent;
-		/*
-		 * Accept a left-right-associative set of arguments just
-		 * like sub and sup and friends but without rebalancing
-		 * under a pivot.
-		 */
-		parent = eqn_box_alloc(ep, parent);
-		parent->type = EQN_SUBEXPR;
-		parent->pos = EQNPOS_SQRT;
-		parent->expectargs = 1;
-		break;
-	case EQN_TOK_OVER:
-		/*
-		 * We have a right-left-associative fraction.
-		 * Close out anything that's currently open, then
-		 * rebalance and continue reading.
-		 */
-		if (parent->last == NULL) {
-			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-			cur = eqn_box_alloc(ep, parent);
-			cur->type = EQN_TEXT;
-			cur->text = mandoc_strdup("");
-		}
-		while (parent->args == parent->expectargs)
-			parent = parent->parent;
-		while (EQN_SUBEXPR == parent->type)
-			parent = parent->parent;
-		parent = eqn_box_makebinary(ep, parent);
-		parent->pos = EQNPOS_OVER;
-		break;
-	case EQN_TOK_RIGHT:
-	case EQN_TOK_BRACE_CLOSE:
-		/*
-		 * Close out the existing brace.
-		 * FIXME: this is a shitty sentinel: we should really
-		 * have a native EQN_BRACE type or whatnot.
-		 */
-		for (cur = parent; cur != NULL; cur = cur->parent)
-			if (cur->type == EQN_LIST &&
-			    cur->expectargs > 1 &&
-			    (tok == EQN_TOK_BRACE_CLOSE ||
-			     cur->left != NULL))
-				break;
-		if (cur == NULL) {
-			mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-			break;
-		}
-		parent = cur;
-		if (EQN_TOK_RIGHT == tok) {
-			if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
-				mandoc_msg(MANDOCERR_REQ_EMPTY,
-				    ep->parse, ep->node->line,
-				    ep->node->pos, eqn_toks[tok]);
-				break;
-			}
-			/* Handling depends on right/left. */
-			if (STRNEQ(ep->start, ep->toksz, "ceiling", 7))
-				parent->right = mandoc_strdup("\\[rc]");
-			else if (STRNEQ(ep->start, ep->toksz, "floor", 5))
-				parent->right = mandoc_strdup("\\[rf]");
-			else
-				parent->right =
-				    mandoc_strndup(ep->start, ep->toksz);
-		}
-		parent = parent->parent;
-		if (tok == EQN_TOK_BRACE_CLOSE &&
-		    (parent->type == EQN_PILE ||
-		     parent->type == EQN_MATRIX))
-			parent = parent->parent;
-		/* Close out any "singleton" lists. */
-		while (parent->type == EQN_LIST &&
-		    parent->expectargs == 1 &&
-		    parent->args == 1)
-			parent = parent->parent;
-		break;
-	case EQN_TOK_BRACE_OPEN:
-	case EQN_TOK_LEFT:
-		/*
-		 * If we already have something in the stack and we're
-		 * in an expression, then rewind til we're not any more
-		 * (just like with the text node).
-		 */
-		while (parent->args == parent->expectargs)
-			parent = parent->parent;
-		if (EQN_TOK_LEFT == tok &&
-		    eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
-			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-			break;
-		}
-		parent = eqn_box_alloc(ep, parent);
-		parent->type = EQN_LIST;
-		if (EQN_TOK_LEFT == tok) {
-			if (STRNEQ(ep->start, ep->toksz, "ceiling", 7))
-				parent->left = mandoc_strdup("\\[lc]");
-			else if (STRNEQ(ep->start, ep->toksz, "floor", 5))
-				parent->left = mandoc_strdup("\\[lf]");
-			else
-				parent->left =
-				    mandoc_strndup(ep->start, ep->toksz);
-		}
-		break;
-	case EQN_TOK_PILE:
-	case EQN_TOK_LPILE:
-	case EQN_TOK_RPILE:
-	case EQN_TOK_CPILE:
-	case EQN_TOK_CCOL:
-	case EQN_TOK_LCOL:
-	case EQN_TOK_RCOL:
-		while (parent->args == parent->expectargs)
-			parent = parent->parent;
-		parent = eqn_box_alloc(ep, parent);
-		parent->type = EQN_PILE;
-		parent->expectargs = 1;
-		break;
-	case EQN_TOK_ABOVE:
-		for (cur = parent; cur != NULL; cur = cur->parent)
-			if (cur->type == EQN_PILE)
-				break;
-		if (cur == NULL) {
-			mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
-			    ep->node->line, ep->node->pos, eqn_toks[tok]);
-			break;
-		}
-		parent = eqn_box_alloc(ep, cur);
-		parent->type = EQN_LIST;
-		break;
-	case EQN_TOK_MATRIX:
-		while (parent->args == parent->expectargs)
-			parent = parent->parent;
-		parent = eqn_box_alloc(ep, parent);
-		parent->type = EQN_MATRIX;
-		parent->expectargs = 1;
-		break;
-	case EQN_TOK_EOF:
-		return;
-	case EQN_TOK__MAX:
-	case EQN_TOK_FUNC:
-	case EQN_TOK_QUOTED:
-	case EQN_TOK_SYM:
-		p = ep->start;
-		assert(p != NULL);
-		/*
-		 * If we already have something in the stack and we're
-		 * in an expression, then rewind til we're not any more.
-		 */
-		while (parent->args == parent->expectargs)
-			parent = parent->parent;
-		cur = eqn_box_alloc(ep, parent);
-		cur->type = EQN_TEXT;
-		cur->text = p;
-		switch (tok) {
-		case EQN_TOK_FUNC:
-			cur->font = EQNFONT_ROMAN;
-			break;
-		case EQN_TOK_QUOTED:
-			if (cur->font == EQNFONT_NONE)
-				cur->font = EQNFONT_ITALIC;
-			break;
-		case EQN_TOK_SYM:
-			break;
-		default:
-			if (cur->font != EQNFONT_NONE || *p == '\0')
-				break;
-			cpn = p - 1;
-			ccln = CCL_LET;
-			split = NULL;
-			for (;;) {
-				/* Advance to next character. */
-				cp = cpn++;
-				ccl = ccln;
-				ccln = isalpha((unsigned char)*cpn) ? CCL_LET :
-				    isdigit((unsigned char)*cpn) ||
-				    (*cpn == '.' && (ccl == CCL_DIG ||
-				     isdigit((unsigned char)cpn[1]))) ?
-				    CCL_DIG : CCL_PUN;
-				/* No boundary before first character. */
-				if (cp < p)
-					continue;
-				cur->font = ccl == CCL_LET ?
-				    EQNFONT_ITALIC : EQNFONT_ROMAN;
-				if (*cp == '\\')
-					mandoc_escape(&cpn, NULL, NULL);
-				/* No boundary after last character. */
-				if (*cpn == '\0')
-					break;
-				if (ccln == ccl && *cp != ',' && *cpn != ',')
-					continue;
-				/* Boundary found, split the text. */
-				if (parent->args == parent->expectargs) {
-					/* Remove the text from the tree. */
-					if (cur->prev == NULL)
-						parent->first = cur->next;
-					else
-						cur->prev->next = NULL;
-					parent->last = cur->prev;
-					parent->args--;
-					/* Set up a list instead. */
-					split = eqn_box_alloc(ep, parent);
-					split->type = EQN_LIST;
-					/* Insert the word into the list. */
-					split->first = split->last = cur;
-					cur->parent = split;
-					cur->prev = NULL;
-					parent = split;
-				}
-				/* Append a new text box. */
-				nbox = eqn_box_alloc(ep, parent);
-				nbox->type = EQN_TEXT;
-				nbox->text = mandoc_strdup(cpn);
-				/* Truncate the old box. */
-				p = mandoc_strndup(cur->text,
-				    cpn - cur->text);
-				free(cur->text);
-				cur->text = p;
-				/* Setup to process the new box. */
-				cur = nbox;
-				p = nbox->text;
-				cpn = p - 1;
-				ccln = CCL_LET;
-			}
-			if (split != NULL)
-				parent = split->parent;
-			break;
-		}
-		break;
-	default:
-		abort();
-	}
-	goto next_tok;
-}
-
-void
-eqn_free(struct eqn_node *p)
-{
-	int		 i;
-
-	for (i = 0; i < (int)p->defsz; i++) {
-		free(p->defs[i].key);
-		free(p->defs[i].val);
-	}
-
-	free(p->data);
-	free(p->defs);
-	free(p);
-}

Property changes on: head/contrib/mdocml/eqn.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-strlcat.c
===================================================================
--- head/contrib/mdocml/test-strlcat.c	(revision 338825)
+++ head/contrib/mdocml/test-strlcat.c	(nonexistent)
@@ -1,9 +0,0 @@
-#include 
-
-int
-main(void)
-{
-	char buf[3] = "a";
-	return ! (strlcat(buf, "b", sizeof(buf)) == 2 &&
-	    buf[0] == 'a' && buf[1] == 'b' && buf[2] == '\0');
-}

Property changes on: head/contrib/mdocml/test-strlcat.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-strsep.c
===================================================================
--- head/contrib/mdocml/test-strsep.c	(revision 338825)
+++ head/contrib/mdocml/test-strsep.c	(nonexistent)
@@ -1,10 +0,0 @@
-#include 
-
-int
-main(void)
-{
-	char buf[6] = "aybxc";
-	char *workp = buf;
-	char *retp = strsep(&workp, "xy");
-	return ! (retp == buf && buf[1] == '\0' && workp == buf + 2);
-}

Property changes on: head/contrib/mdocml/test-strsep.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-O_DIRECTORY.c
===================================================================
--- head/contrib/mdocml/test-O_DIRECTORY.c	(revision 338825)
+++ head/contrib/mdocml/test-O_DIRECTORY.c	(nonexistent)
@@ -1,7 +0,0 @@
-#include 
-
-int
-main(void)
-{
-	return open(".", O_RDONLY | O_DIRECTORY) == -1;
-}

Property changes on: head/contrib/mdocml/test-O_DIRECTORY.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/dba_read.c
===================================================================
--- head/contrib/mdocml/dba_read.c	(revision 338825)
+++ head/contrib/mdocml/dba_read.c	(nonexistent)
@@ -1,72 +0,0 @@
-/*	$Id: dba_read.c,v 1.4 2016/08/17 20:46:56 schwarze Exp $ */
-/*
- * Copyright (c) 2016 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.
- *
- * Function to read the mandoc database from disk into RAM,
- * such that data can be added or removed.
- * The interface is defined in "dba.h".
- * This file is seperate from dba.c because this also uses "dbm.h".
- */
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "mansearch.h"
-#include "dba_array.h"
-#include "dba.h"
-#include "dbm.h"
-
-
-struct dba *
-dba_read(const char *fname)
-{
-	struct dba		*dba;
-	struct dba_array	*page;
-	struct dbm_page		*pdata;
-	struct dbm_macro	*mdata;
-	const char		*cp;
-	int32_t			 im, ip, iv, npages;
-
-	if (dbm_open(fname) == -1)
-		return NULL;
-	npages = dbm_page_count();
-	dba = dba_new(npages < 128 ? 128 : npages);
-	for (ip = 0; ip < npages; ip++) {
-		pdata = dbm_page_get(ip);
-		page = dba_page_new(dba->pages, pdata->arch,
-		    pdata->desc, pdata->file + 1, *pdata->file);
-		for (cp = pdata->name; *cp != '\0'; cp = strchr(cp, '\0') + 1)
-			dba_page_add(page, DBP_NAME, cp);
-		for (cp = pdata->sect; *cp != '\0'; cp = strchr(cp, '\0') + 1)
-			dba_page_add(page, DBP_SECT, cp);
-		if ((cp = pdata->arch) != NULL)
-			while (*(cp = strchr(cp, '\0') + 1) != '\0')
-				dba_page_add(page, DBP_ARCH, cp);
-		cp = pdata->file;
-		while (*(cp = strchr(cp, '\0') + 1) != '\0')
-			dba_page_add(page, DBP_FILE, cp);
-	}
-	for (im = 0; im < MACRO_MAX; im++) {
-		for (iv = 0; iv < dbm_macro_count(im); iv++) {
-			mdata = dbm_macro_get(im, iv);
-			dba_macro_new(dba, im, mdata->value, mdata->pp);
-		}
-	}
-	dbm_close();
-	return dba;
-}

Property changes on: head/contrib/mdocml/dba_read.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/man.c
===================================================================
--- head/contrib/mdocml/man.c	(revision 338825)
+++ head/contrib/mdocml/man.c	(nonexistent)
@@ -1,383 +0,0 @@
-/*	$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 and cancel preceding \c,
-	 * but add a single vertical space elsewhere.
-	 */
-
-	if (buf[i] == '\0') {
-		if (man->flags & (MAN_ELINE | MAN_BLINE)) {
-			mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
-			    line, 0, NULL);
-			return 1;
-		}
-		if (man->last->tok == MAN_SH || man->last->tok == MAN_SS)
-			return 1;
-		switch (man->last->type) {
-		case ROFFT_TEXT:
-			sp = man->last->string;
-			cp = ep = strchr(sp, '\0') - 2;
-			if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
-				break;
-			while (cp > sp && cp[-1] == '\\')
-				cp--;
-			if ((ep - cp) % 2)
-				break;
-			*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;
-		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 (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;
-}

Property changes on: head/contrib/mdocml/man.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-cmsg.c
===================================================================
--- head/contrib/mdocml/test-cmsg.c	(revision 338825)
+++ head/contrib/mdocml/test-cmsg.c	(nonexistent)
@@ -1,13 +0,0 @@
-#include 
-#include 
-
-int
-main(void)
-{
-	struct msghdr	 msg;
-
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-
-	return CMSG_FIRSTHDR(&msg) != NULL;
-}

Property changes on: head/contrib/mdocml/test-cmsg.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/eqn_html.c
===================================================================
--- head/contrib/mdocml/eqn_html.c	(revision 338825)
+++ head/contrib/mdocml/eqn_html.c	(nonexistent)
@@ -1,244 +0,0 @@
-/*	$Id: eqn_html.c,v 1.17 2017/07/14 13:32:35 schwarze Exp $ */
-/*
- * Copyright (c) 2011, 2014 Kristaps Dzonsons 
- * 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.
- */
-#include "config.h"
-
-#include 
-
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc.h"
-#include "out.h"
-#include "html.h"
-
-static void
-eqn_box(struct html *p, const struct eqn_box *bp)
-{
-	struct tag	*post, *row, *cell, *t;
-	const struct eqn_box *child, *parent;
-	const char	*cp;
-	size_t		 i, j, rows;
-	enum htmltag	 tag;
-	enum eqn_fontt	 font;
-
-	if (NULL == bp)
-		return;
-
-	post = NULL;
-
-	/*
-	 * Special handling for a matrix, which is presented to us in
-	 * column order, but must be printed in row-order.
-	 */
-	if (EQN_MATRIX == bp->type) {
-		if (NULL == bp->first)
-			goto out;
-		if (bp->first->type != EQN_LIST ||
-		    bp->first->expectargs == 1) {
-			eqn_box(p, bp->first);
-			goto out;
-		}
-		if (NULL == (parent = bp->first->first))
-			goto out;
-		/* Estimate the number of rows, first. */
-		if (NULL == (child = parent->first))
-			goto out;
-		for (rows = 0; NULL != child; rows++)
-			child = child->next;
-		/* Print row-by-row. */
-		post = print_otag(p, TAG_MTABLE, "");
-		for (i = 0; i < rows; i++) {
-			parent = bp->first->first;
-			row = print_otag(p, TAG_MTR, "");
-			while (NULL != parent) {
-				child = parent->first;
-				for (j = 0; j < i; j++) {
-					if (NULL == child)
-						break;
-					child = child->next;
-				}
-				cell = print_otag(p, TAG_MTD, "");
-				/*
-				 * If we have no data for this
-				 * particular cell, then print a
-				 * placeholder and continue--don't puke.
-				 */
-				if (NULL != child)
-					eqn_box(p, child->first);
-				print_tagq(p, cell);
-				parent = parent->next;
-			}
-			print_tagq(p, row);
-		}
-		goto out;
-	}
-
-	switch (bp->pos) {
-	case EQNPOS_TO:
-		post = print_otag(p, TAG_MOVER, "");
-		break;
-	case EQNPOS_SUP:
-		post = print_otag(p, TAG_MSUP, "");
-		break;
-	case EQNPOS_FROM:
-		post = print_otag(p, TAG_MUNDER, "");
-		break;
-	case EQNPOS_SUB:
-		post = print_otag(p, TAG_MSUB, "");
-		break;
-	case EQNPOS_OVER:
-		post = print_otag(p, TAG_MFRAC, "");
-		break;
-	case EQNPOS_FROMTO:
-		post = print_otag(p, TAG_MUNDEROVER, "");
-		break;
-	case EQNPOS_SUBSUP:
-		post = print_otag(p, TAG_MSUBSUP, "");
-		break;
-	case EQNPOS_SQRT:
-		post = print_otag(p, TAG_MSQRT, "");
-		break;
-	default:
-		break;
-	}
-
-	if (bp->top || bp->bottom) {
-		assert(NULL == post);
-		if (bp->top && NULL == bp->bottom)
-			post = print_otag(p, TAG_MOVER, "");
-		else if (bp->top && bp->bottom)
-			post = print_otag(p, TAG_MUNDEROVER, "");
-		else if (bp->bottom)
-			post = print_otag(p, TAG_MUNDER, "");
-	}
-
-	if (EQN_PILE == bp->type) {
-		assert(NULL == post);
-		if (bp->first != NULL &&
-		    bp->first->type == EQN_LIST &&
-		    bp->first->expectargs > 1)
-			post = print_otag(p, TAG_MTABLE, "");
-	} else if (bp->type == EQN_LIST && bp->expectargs > 1 &&
-	    bp->parent && bp->parent->type == EQN_PILE) {
-		assert(NULL == post);
-		post = print_otag(p, TAG_MTR, "");
-		print_otag(p, TAG_MTD, "");
-	}
-
-	if (bp->text != NULL) {
-		assert(post == NULL);
-		tag = TAG_MI;
-		cp = bp->text;
-		if (isdigit((unsigned char)cp[0]) ||
-		    (cp[0] == '.' && isdigit((unsigned char)cp[1]))) {
-			tag = TAG_MN;
-			while (*++cp != '\0') {
-				if (*cp != '.' &&
-				    isdigit((unsigned char)*cp) == 0) {
-					tag = TAG_MI;
-					break;
-				}
-			}
-		} else if (*cp != '\0' && isalpha((unsigned char)*cp) == 0) {
-			tag = TAG_MO;
-			while (*cp != '\0') {
-				if (cp[0] == '\\' && cp[1] != '\0') {
-					cp++;
-					mandoc_escape(&cp, NULL, NULL);
-				} else if (isalnum((unsigned char)*cp)) {
-					tag = TAG_MI;
-					break;
-				} else
-					cp++;
-			}
-		}
-		font = bp->font;
-		if (bp->text[0] != '\0' &&
-		    (((tag == TAG_MN || tag == TAG_MO) &&
-		      font == EQNFONT_ROMAN) ||
-		     (tag == TAG_MI && font == (bp->text[1] == '\0' ?
-		      EQNFONT_ITALIC : EQNFONT_ROMAN))))
-			font = EQNFONT_NONE;
-		switch (font) {
-		case EQNFONT_NONE:
-			post = print_otag(p, tag, "");
-			break;
-		case EQNFONT_ROMAN:
-			post = print_otag(p, tag, "?", "fontstyle", "normal");
-			break;
-		case EQNFONT_BOLD:
-		case EQNFONT_FAT:
-			post = print_otag(p, tag, "?", "fontweight", "bold");
-			break;
-		case EQNFONT_ITALIC:
-			post = print_otag(p, tag, "?", "fontstyle", "italic");
-			break;
-		default:
-			abort();
-		}
-		print_text(p, bp->text);
-	} else if (NULL == post) {
-		if (NULL != bp->left || NULL != bp->right)
-			post = print_otag(p, TAG_MFENCED, "??",
-			    "open", bp->left == NULL ? "" : bp->left,
-			    "close", bp->right == NULL ? "" : bp->right);
-		if (NULL == post)
-			post = print_otag(p, TAG_MROW, "");
-		else
-			print_otag(p, TAG_MROW, "");
-	}
-
-	eqn_box(p, bp->first);
-
-out:
-	if (NULL != bp->bottom) {
-		t = print_otag(p, TAG_MO, "");
-		print_text(p, bp->bottom);
-		print_tagq(p, t);
-	}
-	if (NULL != bp->top) {
-		t = print_otag(p, TAG_MO, "");
-		print_text(p, bp->top);
-		print_tagq(p, t);
-	}
-
-	if (NULL != post)
-		print_tagq(p, post);
-
-	eqn_box(p, bp->next);
-}
-
-void
-print_eqn(struct html *p, const struct eqn_box *bp)
-{
-	struct tag	*t;
-
-	if (bp->first == NULL)
-		return;
-
-	t = print_otag(p, TAG_MATH, "c", "eqn");
-
-	p->flags |= HTML_NONOSPACE;
-	eqn_box(p, bp);
-	p->flags &= ~HTML_NONOSPACE;
-
-	print_tagq(p, t);
-}

Property changes on: head/contrib/mdocml/eqn_html.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mansearch.3
===================================================================
--- head/contrib/mdocml/mansearch.3	(revision 338825)
+++ head/contrib/mdocml/mansearch.3	(nonexistent)
@@ -1,120 +0,0 @@
-.\"	$Id: mansearch.3,v 1.5 2017/03/30 22:22:05 schwarze Exp $
-.\"
-.\" Copyright (c) 2014 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: March 30 2017 $
-.Dt MANSEARCH 3
-.Os
-.Sh NAME
-.Nm mansearch
-.Nd search manual page databases
-.Sh SYNOPSIS
-.In stdint.h
-.In manconf.h
-.In mansearch.h
-.Ft int
-.Fo mansearch
-.Fa "const struct mansearch *search"
-.Fa "const struct manpaths *paths"
-.Fa "int argc"
-.Fa "char *argv[]"
-.Fa "struct manpage **res"
-.Fa "size_t *sz"
-.Fc
-.Sh DESCRIPTION
-The
-.Fn mansearch
-function returns information about manuals matching a search query from a
-.Xr mandoc.db 5
-database.
-.Pp
-The query arguments are as follows:
-.Bl -tag -width Ds
-.It Fa "const struct mansearch *search"
-Search options, defined in
-.In mansearch.h .
-.It Fa "const struct manpaths *paths"
-Directories to be searched, defined in
-.In manconf.h .
-.It Fa "int argc" , "char *argv[]"
-Search criteria, usually taken from the command line.
-.El
-.Pp
-The output arguments are as follows:
-.Bl -tag -width Ds
-.It Fa "struct manpage **res"
-Returns a pointer to an array of result structures defined in
-.In mansearch.h .
-The user is expected to call
-.Xr free 3
-on the
-.Va file ,
-.Va names ,
-and
-.Va output
-fields of all structures, as well as the
-.Fa res
-array itself.
-.It Fa "size_t *sz"
-Returns the number of result structures contained in
-.Fa res .
-.El
-.Sh IMPLEMENTATION NOTES
-For each manual page tree, the search is done in two steps.
-In the first step, a list of pages matching the search criteria is built.
-In the second step, the requested information about these pages is
-retrieved from the database and assembled into the
-.Fa res
-array.
-.Pp
-All function mentioned here are defined in the file
-.Pa mansearch.c .
-.Ss Finding matches
-Command line parsing is done by the function
-.Fn exprcomp
-building a singly linked list of
-.Vt expr
-structures, using the helper functions
-.Fn expr_and
-and
-.Fn exprterm .
-.Ss Assembling the results
-The names, sections, and architectures of the manuals found
-are assembled into the
-.Va names
-field of the result structure by the function
-.Fn buildnames .
-.Sh FILES
-.Bl -tag -width mandoc.db -compact
-.It Pa mandoc.db
-The manual page database.
-.El
-.Sh SEE ALSO
-.Xr apropos 1 ,
-.Xr mandoc.db 5 ,
-.Xr makewhatis 8
-.Sh HISTORY
-The
-.Fn mansearch
-subsystem first appeared in
-.Ox 5.6 .
-.Sh AUTHORS
-.An -nosplit
-A module to search manual page databases was first written by
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
-in 2011, at first using the Berkeley DB;
-he rewrote it for SQLite3 in 2012, and
-.An Ingo Schwarze Aq Mt schwarze@openbsd.org
-removed the dependency on SQLite3 in 2016.

Property changes on: head/contrib/mdocml/mansearch.3
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/man.h
===================================================================
--- head/contrib/mdocml/man.h	(revision 338825)
+++ head/contrib/mdocml/man.h	(nonexistent)
@@ -1,22 +0,0 @@
-/*	$Id: man.h,v 1.78 2017/04/24 23:06:18 schwarze Exp $ */
-/*
- * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
- * Copyright (c) 2014, 2015 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.
- */
-
-struct	roff_man;
-
-const struct mparse	*man_mparse(const struct roff_man *);
-void			 man_validate(struct roff_man *);

Property changes on: head/contrib/mdocml/man.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/term_tab.c
===================================================================
--- head/contrib/mdocml/term_tab.c	(revision 338825)
+++ head/contrib/mdocml/term_tab.c	(nonexistent)
@@ -1,128 +0,0 @@
-/*	$OpenBSD: term.c,v 1.119 2017/01/08 18:08:44 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.
- */
-#include 
-
-#include 
-
-#include "mandoc_aux.h"
-#include "out.h"
-#include "term.h"
-
-struct tablist {
-	size_t	*t;	/* Allocated array of tab positions. */
-	size_t	 s;	/* Allocated number of positions. */
-	size_t	 n;	/* Currently used number of positions. */
-};
-
-static struct {
-	struct tablist	 a;	/* All tab positions for lookup. */
-	struct tablist	 p;	/* Periodic tab positions to add. */
-	size_t		 d;	/* Default tab width in units of n. */
-} tabs;
-
-
-void
-term_tab_set(const struct termp *p, const char *arg)
-{
-	static int	 recording_period;
-
-	struct roffsu	 su;
-	struct tablist	*tl;
-	size_t		 pos;
-	int		 add;
-
-	/* Special arguments: clear all tabs or switch lists. */
-
-	if (arg == NULL) {
-		tabs.a.n = tabs.p.n = 0;
-		recording_period = 0;
-		if (tabs.d == 0) {
-			a2roffsu(".8i", &su, SCALE_IN);
-			tabs.d = term_hen(p, &su);
-		}
-		return;
-	}
-	if (arg[0] == 'T' && arg[1] == '\0') {
-		recording_period = 1;
-		return;
-	}
-
-	/* Parse the sign, the number, and the unit. */
-
-	if (*arg == '+') {
-		add = 1;
-		arg++;
-	} else
-		add = 0;
-	if (a2roffsu(arg, &su, SCALE_EM) == NULL)
-		return;
-
-	/* Select the list, and extend it if it is full. */
-
-	tl = recording_period ? &tabs.p : &tabs.a;
-	if (tl->n >= tl->s) {
-		tl->s += 8;
-		tl->t = mandoc_reallocarray(tl->t, tl->s, sizeof(*tl->t));
-	}
-
-	/* Append the new position. */
-
-	pos = term_hen(p, &su);
-	tl->t[tl->n] = pos;
-	if (add && tl->n)
-		tl->t[tl->n] += tl->t[tl->n - 1];
-	tl->n++;
-}
-
-/*
- * Simplified version without a parser,
- * never incremental, never periodic, for use by tbl(7).
- */
-void
-term_tab_iset(size_t inc)
-{
-	if (tabs.a.n >= tabs.a.s) {
-		tabs.a.s += 8;
-		tabs.a.t = mandoc_reallocarray(tabs.a.t, tabs.a.s,
-		    sizeof(*tabs.a.t));
-	}
-	tabs.a.t[tabs.a.n++] = inc;
-}
-
-size_t
-term_tab_next(size_t prev)
-{
-	size_t	 i, j;
-
-	for (i = 0;; i++) {
-		if (i == tabs.a.n) {
-			if (tabs.p.n == 0)
-				return prev;
-			tabs.a.n += tabs.p.n;
-			if (tabs.a.s < tabs.a.n) {
-				tabs.a.s = tabs.a.n;
-				tabs.a.t = mandoc_reallocarray(tabs.a.t,
-				    tabs.a.s, sizeof(*tabs.a.t));
-			}
-			for (j = 0; j < tabs.p.n; j++)
-				tabs.a.t[i + j] = tabs.p.t[j] +
-				    (i ? tabs.a.t[i - 1] : 0);
-		}
-		if (prev < tabs.a.t[i])
-			return tabs.a.t[i];
-	}
-}

Property changes on: head/contrib/mdocml/term_tab.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/LICENSE
===================================================================
--- head/contrib/mdocml/LICENSE	(revision 338825)
+++ head/contrib/mdocml/LICENSE	(nonexistent)
@@ -1,54 +0,0 @@
-$Id: LICENSE,v 1.17 2017/06/23 15:58:14 schwarze Exp $
-
-With the exceptions noted below, all code and documentation
-contained in the mandoc toolkit is protected by the Copyright
-of the following developers:
-
-Copyright (c) 2008-2012, 2014 Kristaps Dzonsons 
-Copyright (c) 2010-2017 Ingo Schwarze 
-Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger 
-Copyright (c) 2013 Franco Fichtner 
-Copyright (c) 2014 Baptiste Daroussin 
-Copyright (c) 2016 Ed Maste 
-Copyright (c) 2017 Michael Stapelberg 
-Copyright (c) 1999, 2004 Marc Espie 
-Copyright (c) 1998, 2004, 2010 Todd C. Miller 
-Copyright (c) 2008, 2017 Otto Moerbeek 
-Copyright (c) 2004 Ted Unangst 
-Copyright (c) 1994 Christos Zoulas 
-Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre 
-
-See the individual source files for information about who contributed
-to which file during which years.
-
-
-The mandoc distribution as a whole is distributed by its developers
-under the following license:
-
-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.
-
-
-The following files included from outside sources are protected by
-other people's Copyright and are distributed under various 2-clause
-and 3-clause BSD licenses; see these individual files for details.
-
-soelim.c, soelim.1:
-Copyright (c) 2014 Baptiste Daroussin 
-
-compat_err.c, compat_fts.c, compat_fts.h,
-compat_getsubopt.c, compat_strcasestr.c, compat_strsep.c,
-man.1:
-Copyright (c) 1989,1990,1993,1994 The Regents of the University of California
-
-compat_stringlist.c, compat_stringlist.h:
-Copyright (c) 1994 Christos Zoulas 
Index: head/contrib/mdocml/man_html.c
===================================================================
--- head/contrib/mdocml/man_html.c	(revision 338825)
+++ head/contrib/mdocml/man_html.c	(nonexistent)
@@ -1,670 +0,0 @@
-/*	$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);
-		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;
-}

Property changes on: head/contrib/mdocml/man_html.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mdoc_term.c
===================================================================
--- head/contrib/mdocml/mdoc_term.c	(revision 338825)
+++ head/contrib/mdocml/mdoc_term.c	(nonexistent)
@@ -1,2103 +0,0 @@
-/*	$Id: mdoc_term.c,v 1.364 2017/06/14 17:51:15 schwarze Exp $ */
-/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
- * Copyright (c) 2010, 2012-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 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "out.h"
-#include "term.h"
-#include "tag.h"
-#include "main.h"
-
-struct	termpair {
-	struct termpair	 *ppair;
-	int		  count;
-};
-
-#define	DECL_ARGS struct termp *p, \
-		  struct termpair *pair, \
-		  const struct roff_meta *meta, \
-		  struct roff_node *n
-
-struct	termact {
-	int	(*pre)(DECL_ARGS);
-	void	(*post)(DECL_ARGS);
-};
-
-static	int	  a2width(const struct termp *, const char *);
-
-static	void	  print_bvspace(struct termp *,
-			const struct roff_node *,
-			const struct roff_node *);
-static	void	  print_mdoc_node(DECL_ARGS);
-static	void	  print_mdoc_nodelist(DECL_ARGS);
-static	void	  print_mdoc_head(struct termp *, const struct roff_meta *);
-static	void	  print_mdoc_foot(struct termp *, const struct roff_meta *);
-static	void	  synopsis_pre(struct termp *,
-			const struct roff_node *);
-
-static	void	  termp____post(DECL_ARGS);
-static	void	  termp__t_post(DECL_ARGS);
-static	void	  termp_bd_post(DECL_ARGS);
-static	void	  termp_bk_post(DECL_ARGS);
-static	void	  termp_bl_post(DECL_ARGS);
-static	void	  termp_eo_post(DECL_ARGS);
-static	void	  termp_fd_post(DECL_ARGS);
-static	void	  termp_fo_post(DECL_ARGS);
-static	void	  termp_in_post(DECL_ARGS);
-static	void	  termp_it_post(DECL_ARGS);
-static	void	  termp_lb_post(DECL_ARGS);
-static	void	  termp_nm_post(DECL_ARGS);
-static	void	  termp_pf_post(DECL_ARGS);
-static	void	  termp_quote_post(DECL_ARGS);
-static	void	  termp_sh_post(DECL_ARGS);
-static	void	  termp_ss_post(DECL_ARGS);
-static	void	  termp_xx_post(DECL_ARGS);
-
-static	int	  termp__a_pre(DECL_ARGS);
-static	int	  termp__t_pre(DECL_ARGS);
-static	int	  termp_an_pre(DECL_ARGS);
-static	int	  termp_ap_pre(DECL_ARGS);
-static	int	  termp_bd_pre(DECL_ARGS);
-static	int	  termp_bf_pre(DECL_ARGS);
-static	int	  termp_bk_pre(DECL_ARGS);
-static	int	  termp_bl_pre(DECL_ARGS);
-static	int	  termp_bold_pre(DECL_ARGS);
-static	int	  termp_cd_pre(DECL_ARGS);
-static	int	  termp_d1_pre(DECL_ARGS);
-static	int	  termp_eo_pre(DECL_ARGS);
-static	int	  termp_em_pre(DECL_ARGS);
-static	int	  termp_er_pre(DECL_ARGS);
-static	int	  termp_ex_pre(DECL_ARGS);
-static	int	  termp_fa_pre(DECL_ARGS);
-static	int	  termp_fd_pre(DECL_ARGS);
-static	int	  termp_fl_pre(DECL_ARGS);
-static	int	  termp_fn_pre(DECL_ARGS);
-static	int	  termp_fo_pre(DECL_ARGS);
-static	int	  termp_ft_pre(DECL_ARGS);
-static	int	  termp_in_pre(DECL_ARGS);
-static	int	  termp_it_pre(DECL_ARGS);
-static	int	  termp_li_pre(DECL_ARGS);
-static	int	  termp_lk_pre(DECL_ARGS);
-static	int	  termp_nd_pre(DECL_ARGS);
-static	int	  termp_nm_pre(DECL_ARGS);
-static	int	  termp_ns_pre(DECL_ARGS);
-static	int	  termp_quote_pre(DECL_ARGS);
-static	int	  termp_rs_pre(DECL_ARGS);
-static	int	  termp_sh_pre(DECL_ARGS);
-static	int	  termp_skip_pre(DECL_ARGS);
-static	int	  termp_sm_pre(DECL_ARGS);
-static	int	  termp_pp_pre(DECL_ARGS);
-static	int	  termp_ss_pre(DECL_ARGS);
-static	int	  termp_sy_pre(DECL_ARGS);
-static	int	  termp_tag_pre(DECL_ARGS);
-static	int	  termp_under_pre(DECL_ARGS);
-static	int	  termp_vt_pre(DECL_ARGS);
-static	int	  termp_xr_pre(DECL_ARGS);
-static	int	  termp_xx_pre(DECL_ARGS);
-
-static	const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
-	{ NULL, NULL }, /* Dd */
-	{ NULL, NULL }, /* Dt */
-	{ NULL, NULL }, /* Os */
-	{ termp_sh_pre, termp_sh_post }, /* Sh */
-	{ termp_ss_pre, termp_ss_post }, /* Ss */
-	{ termp_pp_pre, NULL }, /* Pp */
-	{ termp_d1_pre, termp_bl_post }, /* D1 */
-	{ termp_d1_pre, termp_bl_post }, /* Dl */
-	{ termp_bd_pre, termp_bd_post }, /* Bd */
-	{ NULL, NULL }, /* Ed */
-	{ termp_bl_pre, termp_bl_post }, /* Bl */
-	{ NULL, NULL }, /* El */
-	{ termp_it_pre, termp_it_post }, /* It */
-	{ termp_under_pre, NULL }, /* Ad */
-	{ termp_an_pre, NULL }, /* An */
-	{ termp_ap_pre, NULL }, /* Ap */
-	{ termp_under_pre, NULL }, /* Ar */
-	{ termp_cd_pre, NULL }, /* Cd */
-	{ termp_bold_pre, NULL }, /* Cm */
-	{ termp_li_pre, NULL }, /* Dv */
-	{ termp_er_pre, NULL }, /* Er */
-	{ termp_tag_pre, NULL }, /* Ev */
-	{ termp_ex_pre, NULL }, /* Ex */
-	{ termp_fa_pre, NULL }, /* Fa */
-	{ termp_fd_pre, termp_fd_post }, /* Fd */
-	{ termp_fl_pre, NULL }, /* Fl */
-	{ termp_fn_pre, NULL }, /* Fn */
-	{ termp_ft_pre, NULL }, /* Ft */
-	{ termp_bold_pre, NULL }, /* Ic */
-	{ termp_in_pre, termp_in_post }, /* In */
-	{ termp_li_pre, NULL }, /* Li */
-	{ termp_nd_pre, NULL }, /* Nd */
-	{ termp_nm_pre, termp_nm_post }, /* Nm */
-	{ termp_quote_pre, termp_quote_post }, /* Op */
-	{ termp_ft_pre, NULL }, /* Ot */
-	{ termp_under_pre, NULL }, /* Pa */
-	{ termp_ex_pre, NULL }, /* Rv */
-	{ NULL, NULL }, /* St */
-	{ termp_under_pre, NULL }, /* Va */
-	{ termp_vt_pre, NULL }, /* Vt */
-	{ termp_xr_pre, NULL }, /* Xr */
-	{ termp__a_pre, termp____post }, /* %A */
-	{ termp_under_pre, termp____post }, /* %B */
-	{ NULL, termp____post }, /* %D */
-	{ termp_under_pre, termp____post }, /* %I */
-	{ termp_under_pre, termp____post }, /* %J */
-	{ NULL, termp____post }, /* %N */
-	{ NULL, termp____post }, /* %O */
-	{ NULL, termp____post }, /* %P */
-	{ NULL, termp____post }, /* %R */
-	{ termp__t_pre, termp__t_post }, /* %T */
-	{ NULL, termp____post }, /* %V */
-	{ NULL, NULL }, /* Ac */
-	{ termp_quote_pre, termp_quote_post }, /* Ao */
-	{ termp_quote_pre, termp_quote_post }, /* Aq */
-	{ NULL, NULL }, /* At */
-	{ NULL, NULL }, /* Bc */
-	{ termp_bf_pre, NULL }, /* Bf */
-	{ termp_quote_pre, termp_quote_post }, /* Bo */
-	{ termp_quote_pre, termp_quote_post }, /* Bq */
-	{ termp_xx_pre, termp_xx_post }, /* Bsx */
-	{ NULL, NULL }, /* Bx */
-	{ termp_skip_pre, NULL }, /* Db */
-	{ NULL, NULL }, /* Dc */
-	{ termp_quote_pre, termp_quote_post }, /* Do */
-	{ termp_quote_pre, termp_quote_post }, /* Dq */
-	{ NULL, NULL }, /* Ec */ /* FIXME: no space */
-	{ NULL, NULL }, /* Ef */
-	{ termp_em_pre, NULL }, /* Em */
-	{ termp_eo_pre, termp_eo_post }, /* Eo */
-	{ termp_xx_pre, termp_xx_post }, /* Fx */
-	{ termp_bold_pre, NULL }, /* Ms */
-	{ termp_li_pre, NULL }, /* No */
-	{ termp_ns_pre, NULL }, /* Ns */
-	{ termp_xx_pre, termp_xx_post }, /* Nx */
-	{ termp_xx_pre, termp_xx_post }, /* Ox */
-	{ NULL, NULL }, /* Pc */
-	{ NULL, termp_pf_post }, /* Pf */
-	{ termp_quote_pre, termp_quote_post }, /* Po */
-	{ termp_quote_pre, termp_quote_post }, /* Pq */
-	{ NULL, NULL }, /* Qc */
-	{ termp_quote_pre, termp_quote_post }, /* Ql */
-	{ termp_quote_pre, termp_quote_post }, /* Qo */
-	{ termp_quote_pre, termp_quote_post }, /* Qq */
-	{ NULL, NULL }, /* Re */
-	{ termp_rs_pre, NULL }, /* Rs */
-	{ NULL, NULL }, /* Sc */
-	{ termp_quote_pre, termp_quote_post }, /* So */
-	{ termp_quote_pre, termp_quote_post }, /* Sq */
-	{ termp_sm_pre, NULL }, /* Sm */
-	{ termp_under_pre, NULL }, /* Sx */
-	{ termp_sy_pre, NULL }, /* Sy */
-	{ NULL, NULL }, /* Tn */
-	{ termp_xx_pre, termp_xx_post }, /* Ux */
-	{ NULL, NULL }, /* Xc */
-	{ NULL, NULL }, /* Xo */
-	{ termp_fo_pre, termp_fo_post }, /* Fo */
-	{ NULL, NULL }, /* Fc */
-	{ termp_quote_pre, termp_quote_post }, /* Oo */
-	{ NULL, NULL }, /* Oc */
-	{ termp_bk_pre, termp_bk_post }, /* Bk */
-	{ NULL, NULL }, /* Ek */
-	{ NULL, NULL }, /* Bt */
-	{ NULL, NULL }, /* Hf */
-	{ termp_under_pre, NULL }, /* Fr */
-	{ NULL, NULL }, /* Ud */
-	{ NULL, termp_lb_post }, /* Lb */
-	{ termp_pp_pre, NULL }, /* Lp */
-	{ termp_lk_pre, NULL }, /* Lk */
-	{ termp_under_pre, NULL }, /* Mt */
-	{ termp_quote_pre, termp_quote_post }, /* Brq */
-	{ termp_quote_pre, termp_quote_post }, /* Bro */
-	{ NULL, NULL }, /* Brc */
-	{ NULL, termp____post }, /* %C */
-	{ termp_skip_pre, NULL }, /* Es */
-	{ termp_quote_pre, termp_quote_post }, /* En */
-	{ termp_xx_pre, termp_xx_post }, /* Dx */
-	{ NULL, termp____post }, /* %Q */
-	{ NULL, termp____post }, /* %U */
-	{ NULL, NULL }, /* Ta */
-};
-static	const struct termact *const termacts = __termacts - MDOC_Dd;
-
-static	int	 fn_prio;
-
-
-void
-terminal_mdoc(void *arg, const struct roff_man *mdoc)
-{
-	struct roff_node	*n;
-	struct termp		*p;
-	size_t			 save_defindent;
-
-	p = (struct termp *)arg;
-	p->tcol->rmargin = p->maxrmargin = p->defrmargin;
-	term_tab_set(p, NULL);
-	term_tab_set(p, "T");
-	term_tab_set(p, ".5i");
-
-	n = mdoc->first->child;
-	if (p->synopsisonly) {
-		while (n != NULL) {
-			if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
-				if (n->child->next->child != NULL)
-					print_mdoc_nodelist(p, NULL,
-					    &mdoc->meta,
-					    n->child->next->child);
-				term_newln(p);
-				break;
-			}
-			n = n->next;
-		}
-	} else {
-		save_defindent = p->defindent;
-		if (p->defindent == 0)
-			p->defindent = 5;
-		term_begin(p, print_mdoc_head, print_mdoc_foot,
-		    &mdoc->meta);
-		while (n != NULL && n->flags & NODE_NOPRT)
-			n = n->next;
-		if (n != NULL) {
-			if (n->tok != MDOC_Sh)
-				term_vspace(p);
-			print_mdoc_nodelist(p, NULL, &mdoc->meta, n);
-		}
-		term_end(p);
-		p->defindent = save_defindent;
-	}
-}
-
-static void
-print_mdoc_nodelist(DECL_ARGS)
-{
-
-	while (n != NULL) {
-		print_mdoc_node(p, pair, meta, n);
-		n = n->next;
-	}
-}
-
-static void
-print_mdoc_node(DECL_ARGS)
-{
-	int		 chld;
-	struct termpair	 npair;
-	size_t		 offset, rmargin;
-
-	if (n->flags & NODE_NOPRT)
-		return;
-
-	chld = 1;
-	offset = p->tcol->offset;
-	rmargin = p->tcol->rmargin;
-	n->flags &= ~NODE_ENDED;
-	n->prev_font = p->fonti;
-
-	memset(&npair, 0, sizeof(struct termpair));
-	npair.ppair = pair;
-
-	/*
-	 * Keeps only work until the end of a line.  If a keep was
-	 * invoked in a prior line, revert it to PREKEEP.
-	 */
-
-	if (p->flags & TERMP_KEEP && n->flags & NODE_LINE) {
-		p->flags &= ~TERMP_KEEP;
-		p->flags |= TERMP_PREKEEP;
-	}
-
-	/*
-	 * After the keep flags have been set up, we may now
-	 * produce output.  Note that some pre-handlers do so.
-	 */
-
-	switch (n->type) {
-	case ROFFT_TEXT:
-		if (*n->string == ' ' && n->flags & NODE_LINE &&
-		    (p->flags & TERMP_NONEWLINE) == 0)
-			term_newln(p);
-		if (NODE_DELIMC & n->flags)
-			p->flags |= TERMP_NOSPACE;
-		term_word(p, n->string);
-		if (NODE_DELIMO & n->flags)
-			p->flags |= TERMP_NOSPACE;
-		break;
-	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;
-		break;
-	case ROFFT_TBL:
-		if (p->tbl.cols == NULL)
-			term_newln(p);
-		term_tbl(p, n->span);
-		break;
-	default:
-		if (n->tok < ROFF_MAX) {
-			roff_term_pre(p, n);
-			return;
-		}
-		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
-		if (termacts[n->tok].pre != NULL &&
-		    (n->end == ENDBODY_NOT || n->child != NULL))
-			chld = (*termacts[n->tok].pre)
-				(p, &npair, meta, n);
-		break;
-	}
-
-	if (chld && n->child)
-		print_mdoc_nodelist(p, &npair, meta, n->child);
-
-	term_fontpopq(p,
-	    (ENDBODY_NOT == n->end ? n : n->body)->prev_font);
-
-	switch (n->type) {
-	case ROFFT_TEXT:
-		break;
-	case ROFFT_TBL:
-		break;
-	case ROFFT_EQN:
-		break;
-	default:
-		if (termacts[n->tok].post == NULL || n->flags & NODE_ENDED)
-			break;
-		(void)(*termacts[n->tok].post)(p, &npair, meta, n);
-
-		/*
-		 * Explicit end tokens not only call the post
-		 * handler, but also tell the respective block
-		 * that it must not call the post handler again.
-		 */
-		if (ENDBODY_NOT != n->end)
-			n->body->flags |= NODE_ENDED;
-		break;
-	}
-
-	if (NODE_EOS & n->flags)
-		p->flags |= TERMP_SENTENCE;
-
-	if (n->type != ROFFT_TEXT)
-		p->tcol->offset = offset;
-	p->tcol->rmargin = rmargin;
-}
-
-static void
-print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
-{
-	size_t sz;
-
-	term_fontrepl(p, TERMFONT_NONE);
-
-	/*
-	 * Output the footer in new-groff style, that is, three columns
-	 * with the middle being the manual date and flanking columns
-	 * being the operating system:
-	 *
-	 * SYSTEM                  DATE                    SYSTEM
-	 */
-
-	term_vspace(p);
-
-	p->tcol->offset = 0;
-	sz = term_strlen(p, meta->date);
-	p->tcol->rmargin = p->maxrmargin > sz ?
-	    (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
-	p->trailspace = 1;
-	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
-
-	term_word(p, meta->os);
-	term_flushln(p);
-
-	p->tcol->offset = p->tcol->rmargin;
-	sz = term_strlen(p, meta->os);
-	p->tcol->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
-	p->flags |= TERMP_NOSPACE;
-
-	term_word(p, meta->date);
-	term_flushln(p);
-
-	p->tcol->offset = p->tcol->rmargin;
-	p->tcol->rmargin = p->maxrmargin;
-	p->trailspace = 0;
-	p->flags &= ~TERMP_NOBREAK;
-	p->flags |= TERMP_NOSPACE;
-
-	term_word(p, meta->os);
-	term_flushln(p);
-
-	p->tcol->offset = 0;
-	p->tcol->rmargin = p->maxrmargin;
-	p->flags = 0;
-}
-
-static void
-print_mdoc_head(struct termp *p, const struct roff_meta *meta)
-{
-	char			*volume, *title;
-	size_t			 vollen, titlen;
-
-	/*
-	 * The header is strange.  It has three components, which are
-	 * really two with the first duplicated.  It goes like this:
-	 *
-	 * IDENTIFIER              TITLE                   IDENTIFIER
-	 *
-	 * The IDENTIFIER is NAME(SECTION), which is the command-name
-	 * (if given, or "unknown" if not) followed by the manual page
-	 * section.  These are given in `Dt'.  The TITLE is a free-form
-	 * string depending on the manual volume.  If not specified, it
-	 * switches on the manual section.
-	 */
-
-	assert(meta->vol);
-	if (NULL == meta->arch)
-		volume = mandoc_strdup(meta->vol);
-	else
-		mandoc_asprintf(&volume, "%s (%s)",
-		    meta->vol, meta->arch);
-	vollen = term_strlen(p, volume);
-
-	if (NULL == meta->msec)
-		title = mandoc_strdup(meta->title);
-	else
-		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);
-
-	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);
-
-	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;
-	free(title);
-	free(volume);
-}
-
-static int
-a2width(const struct termp *p, const char *v)
-{
-	struct roffsu	 su;
-	const char	*end;
-
-	end = a2roffsu(v, &su, SCALE_MAX);
-	if (end == NULL || *end != '\0') {
-		SCALE_HS_INIT(&su, term_strlen(p, v));
-		su.scale /= term_strlen(p, "0");
-	}
-	return term_hen(p, &su);
-}
-
-/*
- * Determine how much space to print out before block elements of `It'
- * (and thus `Bl') and `Bd'.  And then go ahead and print that space,
- * too.
- */
-static void
-print_bvspace(struct termp *p,
-	const struct roff_node *bl,
-	const struct roff_node *n)
-{
-	const struct roff_node	*nn;
-
-	assert(n);
-
-	term_newln(p);
-
-	if (MDOC_Bd == bl->tok && bl->norm->Bd.comp)
-		return;
-	if (MDOC_Bl == bl->tok && bl->norm->Bl.comp)
-		return;
-
-	/* Do not vspace directly after Ss/Sh. */
-
-	nn = n;
-	while (nn->prev != NULL && nn->prev->flags & NODE_NOPRT)
-		nn = nn->prev;
-	while (nn->prev == NULL) {
-		do {
-			nn = nn->parent;
-			if (nn->type == ROFFT_ROOT)
-				return;
-		} while (nn->type != ROFFT_BLOCK);
-		if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
-			return;
-		if (nn->tok == MDOC_It &&
-		    nn->parent->parent->norm->Bl.type != LIST_item)
-			break;
-	}
-
-	/* A `-column' does not assert vspace within the list. */
-
-	if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type)
-		if (n->prev && MDOC_It == n->prev->tok)
-			return;
-
-	/* A `-diag' without body does not vspace. */
-
-	if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type)
-		if (n->prev && MDOC_It == n->prev->tok) {
-			assert(n->prev->body);
-			if (NULL == n->prev->body->child)
-				return;
-		}
-
-	term_vspace(p);
-}
-
-
-static int
-termp_it_pre(DECL_ARGS)
-{
-	struct roffsu		su;
-	char			buf[24];
-	const struct roff_node *bl, *nn;
-	size_t			ncols, dcol;
-	int			i, offset, width;
-	enum mdoc_list		type;
-
-	if (n->type == ROFFT_BLOCK) {
-		print_bvspace(p, n->parent->parent, n);
-		return 1;
-	}
-
-	bl = n->parent->parent->parent;
-	type = bl->norm->Bl.type;
-
-	/*
-	 * Defaults for specific list types.
-	 */
-
-	switch (type) {
-	case LIST_bullet:
-	case LIST_dash:
-	case LIST_hyphen:
-	case LIST_enum:
-		width = term_len(p, 2);
-		break;
-	case LIST_hang:
-	case LIST_tag:
-		width = term_len(p, 8);
-		break;
-	case LIST_column:
-		width = term_len(p, 10);
-		break;
-	default:
-		width = 0;
-		break;
-	}
-	offset = 0;
-
-	/*
-	 * First calculate width and offset.  This is pretty easy unless
-	 * we're a -column list, in which case all prior columns must
-	 * be accounted for.
-	 */
-
-	if (bl->norm->Bl.offs != NULL) {
-		offset = a2width(p, bl->norm->Bl.offs);
-		if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
-			offset = -p->tcol->offset;
-		else if (offset > SHRT_MAX)
-			offset = 0;
-	}
-
-	switch (type) {
-	case LIST_column:
-		if (n->type == ROFFT_HEAD)
-			break;
-
-		/*
-		 * Imitate groff's column handling:
-		 * - For each earlier column, add its width.
-		 * - For less than 5 columns, add four more blanks per
-		 *   column.
-		 * - For exactly 5 columns, add three more blank per
-		 *   column.
-		 * - For more than 5 columns, add only one column.
-		 */
-		ncols = bl->norm->Bl.ncols;
-		dcol = ncols < 5 ? term_len(p, 4) :
-		    ncols == 5 ? term_len(p, 3) : term_len(p, 1);
-
-		/*
-		 * Calculate the offset by applying all prior ROFFT_BODY,
-		 * so we stop at the ROFFT_HEAD (nn->prev == NULL).
-		 */
-
-		for (i = 0, nn = n->prev;
-		    nn->prev && i < (int)ncols;
-		    nn = nn->prev, i++) {
-			SCALE_HS_INIT(&su,
-			    term_strlen(p, bl->norm->Bl.cols[i]));
-			su.scale /= term_strlen(p, "0");
-			offset += term_hen(p, &su) + dcol;
-		}
-
-		/*
-		 * When exceeding the declared number of columns, leave
-		 * the remaining widths at 0.  This will later be
-		 * adjusted to the default width of 10, or, for the last
-		 * column, stretched to the right margin.
-		 */
-		if (i >= (int)ncols)
-			break;
-
-		/*
-		 * Use the declared column widths, extended as explained
-		 * in the preceding paragraph.
-		 */
-		SCALE_HS_INIT(&su, term_strlen(p, bl->norm->Bl.cols[i]));
-		su.scale /= term_strlen(p, "0");
-		width = term_hen(p, &su) + dcol;
-		break;
-	default:
-		if (NULL == bl->norm->Bl.width)
-			break;
-
-		/*
-		 * Note: buffer the width by 2, which is groff's magic
-		 * number for buffering single arguments.  See the above
-		 * handling for column for how this changes.
-		 */
-		width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
-		if (width < 0 && (size_t)(-width) > p->tcol->offset)
-			width = -p->tcol->offset;
-		else if (width > SHRT_MAX)
-			width = 0;
-		break;
-	}
-
-	/*
-	 * Whitespace control.  Inset bodies need an initial space,
-	 * while diagonal bodies need two.
-	 */
-
-	p->flags |= TERMP_NOSPACE;
-
-	switch (type) {
-	case LIST_diag:
-		if (n->type == ROFFT_BODY)
-			term_word(p, "\\ \\ ");
-		break;
-	case LIST_inset:
-		if (n->type == ROFFT_BODY && n->parent->head->child != NULL)
-			term_word(p, "\\ ");
-		break;
-	default:
-		break;
-	}
-
-	p->flags |= TERMP_NOSPACE;
-
-	switch (type) {
-	case LIST_diag:
-		if (n->type == ROFFT_HEAD)
-			term_fontpush(p, TERMFONT_BOLD);
-		break;
-	default:
-		break;
-	}
-
-	/*
-	 * Pad and break control.  This is the tricky part.  These flags
-	 * are documented in term_flushln() in term.c.  Note that we're
-	 * going to unset all of these flags in termp_it_post() when we
-	 * exit.
-	 */
-
-	switch (type) {
-	case LIST_enum:
-	case LIST_bullet:
-	case LIST_dash:
-	case LIST_hyphen:
-		if (n->type == ROFFT_HEAD) {
-			p->flags |= TERMP_NOBREAK | TERMP_HANG;
-			p->trailspace = 1;
-		} else if (width <= (int)term_len(p, 2))
-			p->flags |= TERMP_NOPAD;
-		break;
-	case LIST_hang:
-		if (n->type != ROFFT_HEAD)
-			break;
-		p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
-		p->trailspace = 1;
-		break;
-	case LIST_tag:
-		if (n->type != ROFFT_HEAD)
-			break;
-
-		p->flags |= TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND;
-		p->trailspace = 2;
-
-		if (NULL == n->next || NULL == n->next->child)
-			p->flags |= TERMP_HANG;
-		break;
-	case LIST_column:
-		if (n->type == ROFFT_HEAD)
-			break;
-
-		if (NULL == n->next) {
-			p->flags &= ~TERMP_NOBREAK;
-			p->trailspace = 0;
-		} else {
-			p->flags |= TERMP_NOBREAK;
-			p->trailspace = 1;
-		}
-
-		break;
-	case LIST_diag:
-		if (n->type != ROFFT_HEAD)
-			break;
-		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
-		p->trailspace = 1;
-		break;
-	default:
-		break;
-	}
-
-	/*
-	 * Margin control.  Set-head-width lists have their right
-	 * margins shortened.  The body for these lists has the offset
-	 * necessarily lengthened.  Everybody gets the offset.
-	 */
-
-	p->tcol->offset += offset;
-
-	switch (type) {
-	case LIST_bullet:
-	case LIST_dash:
-	case LIST_enum:
-	case LIST_hyphen:
-	case LIST_hang:
-	case LIST_tag:
-		if (n->type == ROFFT_HEAD)
-			p->tcol->rmargin = p->tcol->offset + width;
-		else
-			p->tcol->offset += width;
-		break;
-	case LIST_column:
-		assert(width);
-		p->tcol->rmargin = p->tcol->offset + width;
-		/*
-		 * XXX - this behaviour is not documented: the
-		 * right-most column is filled to the right margin.
-		 */
-		if (n->type == ROFFT_HEAD)
-			break;
-		if (n->next == NULL && p->tcol->rmargin < p->maxrmargin)
-			p->tcol->rmargin = p->maxrmargin;
-		break;
-	default:
-		break;
-	}
-
-	/*
-	 * The dash, hyphen, bullet and enum lists all have a special
-	 * HEAD character (temporarily bold, in some cases).
-	 */
-
-	if (n->type == ROFFT_HEAD)
-		switch (type) {
-		case LIST_bullet:
-			term_fontpush(p, TERMFONT_BOLD);
-			term_word(p, "\\[bu]");
-			term_fontpop(p);
-			break;
-		case LIST_dash:
-		case LIST_hyphen:
-			term_fontpush(p, TERMFONT_BOLD);
-			term_word(p, "-");
-			term_fontpop(p);
-			break;
-		case LIST_enum:
-			(pair->ppair->ppair->count)++;
-			(void)snprintf(buf, sizeof(buf), "%d.",
-			    pair->ppair->ppair->count);
-			term_word(p, buf);
-			break;
-		default:
-			break;
-		}
-
-	/*
-	 * If we're not going to process our children, indicate so here.
-	 */
-
-	switch (type) {
-	case LIST_bullet:
-	case LIST_item:
-	case LIST_dash:
-	case LIST_hyphen:
-	case LIST_enum:
-		if (n->type == ROFFT_HEAD)
-			return 0;
-		break;
-	case LIST_column:
-		if (n->type == ROFFT_HEAD)
-			return 0;
-		p->minbl = 0;
-		break;
-	default:
-		break;
-	}
-
-	return 1;
-}
-
-static void
-termp_it_post(DECL_ARGS)
-{
-	enum mdoc_list	   type;
-
-	if (n->type == ROFFT_BLOCK)
-		return;
-
-	type = n->parent->parent->parent->norm->Bl.type;
-
-	switch (type) {
-	case LIST_item:
-	case LIST_diag:
-	case LIST_inset:
-		if (n->type == ROFFT_BODY)
-			term_newln(p);
-		break;
-	case LIST_column:
-		if (n->type == ROFFT_BODY)
-			term_flushln(p);
-		break;
-	default:
-		term_newln(p);
-		break;
-	}
-
-	/*
-	 * Now that our output is flushed, we can reset our tags.  Since
-	 * only `It' sets these flags, we're free to assume that nobody
-	 * has munged them in the meanwhile.
-	 */
-
-	p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND | TERMP_HANG);
-	p->trailspace = 0;
-}
-
-static int
-termp_nm_pre(DECL_ARGS)
-{
-	const char	*cp;
-
-	if (n->type == ROFFT_BLOCK) {
-		p->flags |= TERMP_PREKEEP;
-		return 1;
-	}
-
-	if (n->type == ROFFT_BODY) {
-		if (n->child == NULL)
-			return 0;
-		p->flags |= TERMP_NOSPACE;
-		cp = NULL;
-		if (n->prev->child != NULL)
-		    cp = n->prev->child->string;
-		if (cp == NULL)
-			cp = meta->name;
-		if (cp == NULL)
-			p->tcol->offset += term_len(p, 6);
-		else
-			p->tcol->offset += term_len(p, 1) +
-			    term_strlen(p, cp);
-		return 1;
-	}
-
-	if (n->child == NULL)
-		return 0;
-
-	if (n->type == ROFFT_HEAD)
-		synopsis_pre(p, n->parent);
-
-	if (n->type == ROFFT_HEAD &&
-	    n->next != NULL && n->next->child != NULL) {
-		p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
-		p->trailspace = 1;
-		p->tcol->rmargin = p->tcol->offset + term_len(p, 1);
-		if (n->child == NULL)
-			p->tcol->rmargin += term_strlen(p, meta->name);
-		else if (n->child->type == ROFFT_TEXT) {
-			p->tcol->rmargin += term_strlen(p, n->child->string);
-			if (n->child->next != NULL)
-				p->flags |= TERMP_HANG;
-		} else {
-			p->tcol->rmargin += term_len(p, 5);
-			p->flags |= TERMP_HANG;
-		}
-	}
-
-	term_fontpush(p, TERMFONT_BOLD);
-	return 1;
-}
-
-static void
-termp_nm_post(DECL_ARGS)
-{
-
-	if (n->type == ROFFT_BLOCK) {
-		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
-	} else if (n->type == ROFFT_HEAD &&
-	    NULL != n->next && NULL != n->next->child) {
-		term_flushln(p);
-		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
-		p->trailspace = 0;
-	} else if (n->type == ROFFT_BODY && n->child != NULL)
-		term_flushln(p);
-}
-
-static int
-termp_fl_pre(DECL_ARGS)
-{
-
-	termp_tag_pre(p, pair, meta, n);
-	term_fontpush(p, TERMFONT_BOLD);
-	term_word(p, "\\-");
-
-	if (!(n->child == NULL &&
-	    (n->next == NULL ||
-	     n->next->type == ROFFT_TEXT ||
-	     n->next->flags & NODE_LINE)))
-		p->flags |= TERMP_NOSPACE;
-
-	return 1;
-}
-
-static int
-termp__a_pre(DECL_ARGS)
-{
-
-	if (n->prev && MDOC__A == n->prev->tok)
-		if (NULL == n->next || MDOC__A != n->next->tok)
-			term_word(p, "and");
-
-	return 1;
-}
-
-static int
-termp_an_pre(DECL_ARGS)
-{
-
-	if (n->norm->An.auth == AUTH_split) {
-		p->flags &= ~TERMP_NOSPLIT;
-		p->flags |= TERMP_SPLIT;
-		return 0;
-	}
-	if (n->norm->An.auth == AUTH_nosplit) {
-		p->flags &= ~TERMP_SPLIT;
-		p->flags |= TERMP_NOSPLIT;
-		return 0;
-	}
-
-	if (p->flags & TERMP_SPLIT)
-		term_newln(p);
-
-	if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT))
-		p->flags |= TERMP_SPLIT;
-
-	return 1;
-}
-
-static int
-termp_ns_pre(DECL_ARGS)
-{
-
-	if ( ! (NODE_LINE & n->flags))
-		p->flags |= TERMP_NOSPACE;
-	return 1;
-}
-
-static int
-termp_rs_pre(DECL_ARGS)
-{
-
-	if (SEC_SEE_ALSO != n->sec)
-		return 1;
-	if (n->type == ROFFT_BLOCK && n->prev != NULL)
-		term_vspace(p);
-	return 1;
-}
-
-static int
-termp_ex_pre(DECL_ARGS)
-{
-	term_newln(p);
-	return 1;
-}
-
-static int
-termp_nd_pre(DECL_ARGS)
-{
-
-	if (n->type == ROFFT_BODY)
-		term_word(p, "\\(en");
-	return 1;
-}
-
-static int
-termp_bl_pre(DECL_ARGS)
-{
-
-	return n->type != ROFFT_HEAD;
-}
-
-static void
-termp_bl_post(DECL_ARGS)
-{
-
-	if (n->type != ROFFT_BLOCK)
-		return;
-	term_newln(p);
-	if (n->tok != MDOC_Bl || n->norm->Bl.type != LIST_column)
-		return;
-	term_tab_set(p, NULL);
-	term_tab_set(p, "T");
-	term_tab_set(p, ".5i");
-}
-
-static int
-termp_xr_pre(DECL_ARGS)
-{
-
-	if (NULL == (n = n->child))
-		return 0;
-
-	assert(n->type == ROFFT_TEXT);
-	term_word(p, n->string);
-
-	if (NULL == (n = n->next))
-		return 0;
-
-	p->flags |= TERMP_NOSPACE;
-	term_word(p, "(");
-	p->flags |= TERMP_NOSPACE;
-
-	assert(n->type == ROFFT_TEXT);
-	term_word(p, n->string);
-
-	p->flags |= TERMP_NOSPACE;
-	term_word(p, ")");
-
-	return 0;
-}
-
-/*
- * This decides how to assert whitespace before any of the SYNOPSIS set
- * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain
- * macro combos).
- */
-static void
-synopsis_pre(struct termp *p, const struct roff_node *n)
-{
-	/*
-	 * Obviously, if we're not in a SYNOPSIS or no prior macros
-	 * exist, do nothing.
-	 */
-	if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
-		return;
-
-	/*
-	 * If we're the second in a pair of like elements, emit our
-	 * newline and return.  UNLESS we're `Fo', `Fn', `Fn', in which
-	 * case we soldier on.
-	 */
-	if (n->prev->tok == n->tok &&
-	    MDOC_Ft != n->tok &&
-	    MDOC_Fo != n->tok &&
-	    MDOC_Fn != n->tok) {
-		term_newln(p);
-		return;
-	}
-
-	/*
-	 * If we're one of the SYNOPSIS set and non-like pair-wise after
-	 * another (or Fn/Fo, which we've let slip through) then assert
-	 * vertical space, else only newline and move on.
-	 */
-	switch (n->prev->tok) {
-	case MDOC_Fd:
-	case MDOC_Fn:
-	case MDOC_Fo:
-	case MDOC_In:
-	case MDOC_Vt:
-		term_vspace(p);
-		break;
-	case MDOC_Ft:
-		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
-			term_vspace(p);
-			break;
-		}
-		/* FALLTHROUGH */
-	default:
-		term_newln(p);
-		break;
-	}
-}
-
-static int
-termp_vt_pre(DECL_ARGS)
-{
-
-	if (n->type == ROFFT_ELEM) {
-		synopsis_pre(p, n);
-		return termp_under_pre(p, pair, meta, n);
-	} else if (n->type == ROFFT_BLOCK) {
-		synopsis_pre(p, n);
-		return 1;
-	} else if (n->type == ROFFT_HEAD)
-		return 0;
-
-	return termp_under_pre(p, pair, meta, n);
-}
-
-static int
-termp_bold_pre(DECL_ARGS)
-{
-
-	termp_tag_pre(p, pair, meta, n);
-	term_fontpush(p, TERMFONT_BOLD);
-	return 1;
-}
-
-static int
-termp_fd_pre(DECL_ARGS)
-{
-
-	synopsis_pre(p, n);
-	return termp_bold_pre(p, pair, meta, n);
-}
-
-static void
-termp_fd_post(DECL_ARGS)
-{
-
-	term_newln(p);
-}
-
-static int
-termp_sh_pre(DECL_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		/*
-		 * Vertical space before sections, except
-		 * when the previous section was empty.
-		 */
-		if (n->prev == NULL ||
-		    n->prev->tok != MDOC_Sh ||
-		    (n->prev->body != NULL &&
-		     n->prev->body->child != NULL))
-			term_vspace(p);
-		break;
-	case ROFFT_HEAD:
-		term_fontpush(p, TERMFONT_BOLD);
-		break;
-	case ROFFT_BODY:
-		p->tcol->offset = term_len(p, p->defindent);
-		term_tab_set(p, NULL);
-		term_tab_set(p, "T");
-		term_tab_set(p, ".5i");
-		switch (n->sec) {
-		case SEC_DESCRIPTION:
-			fn_prio = 0;
-			break;
-		case SEC_AUTHORS:
-			p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
-			break;
-		default:
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-	return 1;
-}
-
-static void
-termp_sh_post(DECL_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_HEAD:
-		term_newln(p);
-		break;
-	case ROFFT_BODY:
-		term_newln(p);
-		p->tcol->offset = 0;
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-termp_lb_post(DECL_ARGS)
-{
-
-	if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags)
-		term_newln(p);
-}
-
-static int
-termp_d1_pre(DECL_ARGS)
-{
-
-	if (n->type != ROFFT_BLOCK)
-		return 1;
-	term_newln(p);
-	p->tcol->offset += term_len(p, p->defindent + 1);
-	term_tab_set(p, NULL);
-	term_tab_set(p, "T");
-	term_tab_set(p, ".5i");
-	return 1;
-}
-
-static int
-termp_ft_pre(DECL_ARGS)
-{
-
-	/* NB: NODE_LINE does not effect this! */
-	synopsis_pre(p, n);
-	term_fontpush(p, TERMFONT_UNDER);
-	return 1;
-}
-
-static int
-termp_fn_pre(DECL_ARGS)
-{
-	size_t		 rmargin = 0;
-	int		 pretty;
-
-	pretty = NODE_SYNPRETTY & n->flags;
-
-	synopsis_pre(p, n);
-
-	if (NULL == (n = n->child))
-		return 0;
-
-	if (pretty) {
-		rmargin = p->tcol->rmargin;
-		p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
-		p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
-	}
-
-	assert(n->type == ROFFT_TEXT);
-	term_fontpush(p, TERMFONT_BOLD);
-	term_word(p, n->string);
-	term_fontpop(p);
-
-	if (n->sec == SEC_DESCRIPTION || n->sec == SEC_CUSTOM)
-		tag_put(n->string, ++fn_prio, p->line);
-
-	if (pretty) {
-		term_flushln(p);
-		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
-		p->flags |= TERMP_NOPAD;
-		p->tcol->offset = p->tcol->rmargin;
-		p->tcol->rmargin = rmargin;
-	}
-
-	p->flags |= TERMP_NOSPACE;
-	term_word(p, "(");
-	p->flags |= TERMP_NOSPACE;
-
-	for (n = n->next; n; n = n->next) {
-		assert(n->type == ROFFT_TEXT);
-		term_fontpush(p, TERMFONT_UNDER);
-		if (pretty)
-			p->flags |= TERMP_NBRWORD;
-		term_word(p, n->string);
-		term_fontpop(p);
-
-		if (n->next) {
-			p->flags |= TERMP_NOSPACE;
-			term_word(p, ",");
-		}
-	}
-
-	p->flags |= TERMP_NOSPACE;
-	term_word(p, ")");
-
-	if (pretty) {
-		p->flags |= TERMP_NOSPACE;
-		term_word(p, ";");
-		term_flushln(p);
-	}
-
-	return 0;
-}
-
-static int
-termp_fa_pre(DECL_ARGS)
-{
-	const struct roff_node	*nn;
-
-	if (n->parent->tok != MDOC_Fo) {
-		term_fontpush(p, TERMFONT_UNDER);
-		return 1;
-	}
-
-	for (nn = n->child; nn; nn = nn->next) {
-		term_fontpush(p, TERMFONT_UNDER);
-		p->flags |= TERMP_NBRWORD;
-		term_word(p, nn->string);
-		term_fontpop(p);
-
-		if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
-			p->flags |= TERMP_NOSPACE;
-			term_word(p, ",");
-		}
-	}
-
-	return 0;
-}
-
-static int
-termp_bd_pre(DECL_ARGS)
-{
-	size_t			 lm, len;
-	struct roff_node	*nn;
-	int			 offset;
-
-	if (n->type == ROFFT_BLOCK) {
-		print_bvspace(p, n, n);
-		return 1;
-	} else if (n->type == ROFFT_HEAD)
-		return 0;
-
-	/* Handle the -offset argument. */
-
-	if (n->norm->Bd.offs == NULL ||
-	    ! strcmp(n->norm->Bd.offs, "left"))
-		/* nothing */;
-	else if ( ! strcmp(n->norm->Bd.offs, "indent"))
-		p->tcol->offset += term_len(p, p->defindent + 1);
-	else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
-		p->tcol->offset += term_len(p, (p->defindent + 1) * 2);
-	else {
-		offset = a2width(p, n->norm->Bd.offs);
-		if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
-			p->tcol->offset = 0;
-		else if (offset < SHRT_MAX)
-			p->tcol->offset += offset;
-	}
-
-	/*
-	 * If -ragged or -filled are specified, the block does nothing
-	 * but change the indentation.  If -unfilled or -literal are
-	 * specified, text is printed exactly as entered in the display:
-	 * for macro lines, a newline is appended to the line.  Blank
-	 * lines are allowed.
-	 */
-
-	if (n->norm->Bd.type != DISP_literal &&
-	    n->norm->Bd.type != DISP_unfilled &&
-	    n->norm->Bd.type != DISP_centered)
-		return 1;
-
-	if (n->norm->Bd.type == DISP_literal) {
-		term_tab_set(p, NULL);
-		term_tab_set(p, "T");
-		term_tab_set(p, "8n");
-	}
-
-	lm = p->tcol->offset;
-	p->flags |= TERMP_BRNEVER;
-	for (nn = n->child; nn != NULL; nn = nn->next) {
-		if (n->norm->Bd.type == DISP_centered) {
-			if (nn->type == ROFFT_TEXT) {
-				len = term_strlen(p, nn->string);
-				p->tcol->offset = len >= p->tcol->rmargin ?
-				    0 : lm + len >= p->tcol->rmargin ?
-				    p->tcol->rmargin - len :
-				    (lm + p->tcol->rmargin - len) / 2;
-			} else
-				p->tcol->offset = lm;
-		}
-		print_mdoc_node(p, pair, meta, nn);
-		/*
-		 * If the printed node flushes its own line, then we
-		 * needn't do it here as well.  This is hacky, but the
-		 * notion of selective eoln whitespace is pretty dumb
-		 * anyway, so don't sweat it.
-		 */
-		if (nn->tok < ROFF_MAX)
-			continue;
-		switch (nn->tok) {
-		case MDOC_Sm:
-		case MDOC_Bl:
-		case MDOC_D1:
-		case MDOC_Dl:
-		case MDOC_Lp:
-		case MDOC_Pp:
-			continue;
-		default:
-			break;
-		}
-		if (p->flags & TERMP_NONEWLINE ||
-		    (nn->next && ! (nn->next->flags & NODE_LINE)))
-			continue;
-		term_flushln(p);
-		p->flags |= TERMP_NOSPACE;
-	}
-	p->flags &= ~TERMP_BRNEVER;
-	return 0;
-}
-
-static void
-termp_bd_post(DECL_ARGS)
-{
-	if (n->type != ROFFT_BODY)
-		return;
-	if (DISP_literal == n->norm->Bd.type ||
-	    DISP_unfilled == n->norm->Bd.type)
-		p->flags |= TERMP_BRNEVER;
-	p->flags |= TERMP_NOSPACE;
-	term_newln(p);
-	p->flags &= ~TERMP_BRNEVER;
-}
-
-static int
-termp_xx_pre(DECL_ARGS)
-{
-	if ((n->aux = p->flags & TERMP_PREKEEP) == 0)
-		p->flags |= TERMP_PREKEEP;
-	return 1;
-}
-
-static void
-termp_xx_post(DECL_ARGS)
-{
-	if (n->aux == 0)
-		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
-}
-
-static void
-termp_pf_post(DECL_ARGS)
-{
-
-	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
-		p->flags |= TERMP_NOSPACE;
-}
-
-static int
-termp_ss_pre(DECL_ARGS)
-{
-	struct roff_node *nn;
-
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		term_newln(p);
-		for (nn = n->prev; nn != NULL; nn = nn->prev)
-			if ((nn->flags & NODE_NOPRT) == 0)
-				break;
-		if (nn != NULL)
-			term_vspace(p);
-		break;
-	case ROFFT_HEAD:
-		term_fontpush(p, TERMFONT_BOLD);
-		p->tcol->offset = term_len(p, (p->defindent+1)/2);
-		break;
-	case ROFFT_BODY:
-		p->tcol->offset = term_len(p, p->defindent);
-		term_tab_set(p, NULL);
-		term_tab_set(p, "T");
-		term_tab_set(p, ".5i");
-		break;
-	default:
-		break;
-	}
-
-	return 1;
-}
-
-static void
-termp_ss_post(DECL_ARGS)
-{
-
-	if (n->type == ROFFT_HEAD || n->type == ROFFT_BODY)
-		term_newln(p);
-}
-
-static int
-termp_cd_pre(DECL_ARGS)
-{
-
-	synopsis_pre(p, n);
-	term_fontpush(p, TERMFONT_BOLD);
-	return 1;
-}
-
-static int
-termp_in_pre(DECL_ARGS)
-{
-
-	synopsis_pre(p, n);
-
-	if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags) {
-		term_fontpush(p, TERMFONT_BOLD);
-		term_word(p, "#include");
-		term_word(p, "<");
-	} else {
-		term_word(p, "<");
-		term_fontpush(p, TERMFONT_UNDER);
-	}
-
-	p->flags |= TERMP_NOSPACE;
-	return 1;
-}
-
-static void
-termp_in_post(DECL_ARGS)
-{
-
-	if (NODE_SYNPRETTY & n->flags)
-		term_fontpush(p, TERMFONT_BOLD);
-
-	p->flags |= TERMP_NOSPACE;
-	term_word(p, ">");
-
-	if (NODE_SYNPRETTY & n->flags)
-		term_fontpop(p);
-}
-
-static int
-termp_pp_pre(DECL_ARGS)
-{
-	fn_prio = 0;
-	term_vspace(p);
-	return 0;
-}
-
-static int
-termp_skip_pre(DECL_ARGS)
-{
-
-	return 0;
-}
-
-static int
-termp_quote_pre(DECL_ARGS)
-{
-
-	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
-		return 1;
-
-	switch (n->tok) {
-	case MDOC_Ao:
-	case MDOC_Aq:
-		term_word(p, n->child != NULL && n->child->next == NULL &&
-		    n->child->tok == MDOC_Mt ? "<" : "\\(la");
-		break;
-	case MDOC_Bro:
-	case MDOC_Brq:
-		term_word(p, "{");
-		break;
-	case MDOC_Oo:
-	case MDOC_Op:
-	case MDOC_Bo:
-	case MDOC_Bq:
-		term_word(p, "[");
-		break;
-	case MDOC__T:
-		/* FALLTHROUGH */
-	case MDOC_Do:
-	case MDOC_Dq:
-		term_word(p, "\\(Lq");
-		break;
-	case MDOC_En:
-		if (NULL == n->norm->Es ||
-		    NULL == n->norm->Es->child)
-			return 1;
-		term_word(p, n->norm->Es->child->string);
-		break;
-	case MDOC_Po:
-	case MDOC_Pq:
-		term_word(p, "(");
-		break;
-	case MDOC_Qo:
-	case MDOC_Qq:
-		term_word(p, "\"");
-		break;
-	case MDOC_Ql:
-	case MDOC_So:
-	case MDOC_Sq:
-		term_word(p, "\\(oq");
-		break;
-	default:
-		abort();
-	}
-
-	p->flags |= TERMP_NOSPACE;
-	return 1;
-}
-
-static void
-termp_quote_post(DECL_ARGS)
-{
-
-	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
-		return;
-
-	p->flags |= TERMP_NOSPACE;
-
-	switch (n->tok) {
-	case MDOC_Ao:
-	case MDOC_Aq:
-		term_word(p, n->child != NULL && n->child->next == NULL &&
-		    n->child->tok == MDOC_Mt ? ">" : "\\(ra");
-		break;
-	case MDOC_Bro:
-	case MDOC_Brq:
-		term_word(p, "}");
-		break;
-	case MDOC_Oo:
-	case MDOC_Op:
-	case MDOC_Bo:
-	case MDOC_Bq:
-		term_word(p, "]");
-		break;
-	case MDOC__T:
-		/* FALLTHROUGH */
-	case MDOC_Do:
-	case MDOC_Dq:
-		term_word(p, "\\(Rq");
-		break;
-	case MDOC_En:
-		if (n->norm->Es == NULL ||
-		    n->norm->Es->child == NULL ||
-		    n->norm->Es->child->next == NULL)
-			p->flags &= ~TERMP_NOSPACE;
-		else
-			term_word(p, n->norm->Es->child->next->string);
-		break;
-	case MDOC_Po:
-	case MDOC_Pq:
-		term_word(p, ")");
-		break;
-	case MDOC_Qo:
-	case MDOC_Qq:
-		term_word(p, "\"");
-		break;
-	case MDOC_Ql:
-	case MDOC_So:
-	case MDOC_Sq:
-		term_word(p, "\\(cq");
-		break;
-	default:
-		abort();
-	}
-}
-
-static int
-termp_eo_pre(DECL_ARGS)
-{
-
-	if (n->type != ROFFT_BODY)
-		return 1;
-
-	if (n->end == ENDBODY_NOT &&
-	    n->parent->head->child == NULL &&
-	    n->child != NULL &&
-	    n->child->end != ENDBODY_NOT)
-		term_word(p, "\\&");
-	else if (n->end != ENDBODY_NOT ? n->child != NULL :
-	     n->parent->head->child != NULL && (n->child != NULL ||
-	     (n->parent->tail != NULL && n->parent->tail->child != NULL)))
-		p->flags |= TERMP_NOSPACE;
-
-	return 1;
-}
-
-static void
-termp_eo_post(DECL_ARGS)
-{
-	int	 body, tail;
-
-	if (n->type != ROFFT_BODY)
-		return;
-
-	if (n->end != ENDBODY_NOT) {
-		p->flags &= ~TERMP_NOSPACE;
-		return;
-	}
-
-	body = n->child != NULL || n->parent->head->child != NULL;
-	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
-
-	if (body && tail)
-		p->flags |= TERMP_NOSPACE;
-	else if ( ! (body || tail))
-		term_word(p, "\\&");
-	else if ( ! tail)
-		p->flags &= ~TERMP_NOSPACE;
-}
-
-static int
-termp_fo_pre(DECL_ARGS)
-{
-	size_t		 rmargin = 0;
-	int		 pretty;
-
-	pretty = NODE_SYNPRETTY & n->flags;
-
-	if (n->type == ROFFT_BLOCK) {
-		synopsis_pre(p, n);
-		return 1;
-	} else if (n->type == ROFFT_BODY) {
-		if (pretty) {
-			rmargin = p->tcol->rmargin;
-			p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
-			p->flags |= TERMP_NOBREAK | TERMP_BRIND |
-					TERMP_HANG;
-		}
-		p->flags |= TERMP_NOSPACE;
-		term_word(p, "(");
-		p->flags |= TERMP_NOSPACE;
-		if (pretty) {
-			term_flushln(p);
-			p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
-					TERMP_HANG);
-			p->flags |= TERMP_NOPAD;
-			p->tcol->offset = p->tcol->rmargin;
-			p->tcol->rmargin = rmargin;
-		}
-		return 1;
-	}
-
-	if (NULL == n->child)
-		return 0;
-
-	/* XXX: we drop non-initial arguments as per groff. */
-
-	assert(n->child->string);
-	term_fontpush(p, TERMFONT_BOLD);
-	term_word(p, n->child->string);
-	return 0;
-}
-
-static void
-termp_fo_post(DECL_ARGS)
-{
-
-	if (n->type != ROFFT_BODY)
-		return;
-
-	p->flags |= TERMP_NOSPACE;
-	term_word(p, ")");
-
-	if (NODE_SYNPRETTY & n->flags) {
-		p->flags |= TERMP_NOSPACE;
-		term_word(p, ";");
-		term_flushln(p);
-	}
-}
-
-static int
-termp_bf_pre(DECL_ARGS)
-{
-
-	if (n->type == ROFFT_HEAD)
-		return 0;
-	else if (n->type != ROFFT_BODY)
-		return 1;
-
-	if (FONT_Em == n->norm->Bf.font)
-		term_fontpush(p, TERMFONT_UNDER);
-	else if (FONT_Sy == n->norm->Bf.font)
-		term_fontpush(p, TERMFONT_BOLD);
-	else
-		term_fontpush(p, TERMFONT_NONE);
-
-	return 1;
-}
-
-static int
-termp_sm_pre(DECL_ARGS)
-{
-
-	if (NULL == n->child)
-		p->flags ^= TERMP_NONOSPACE;
-	else if (0 == strcmp("on", n->child->string))
-		p->flags &= ~TERMP_NONOSPACE;
-	else
-		p->flags |= TERMP_NONOSPACE;
-
-	if (p->col && ! (TERMP_NONOSPACE & p->flags))
-		p->flags &= ~TERMP_NOSPACE;
-
-	return 0;
-}
-
-static int
-termp_ap_pre(DECL_ARGS)
-{
-
-	p->flags |= TERMP_NOSPACE;
-	term_word(p, "'");
-	p->flags |= TERMP_NOSPACE;
-	return 1;
-}
-
-static void
-termp____post(DECL_ARGS)
-{
-
-	/*
-	 * Handle lists of authors.  In general, print each followed by
-	 * a comma.  Don't print the comma if there are only two
-	 * authors.
-	 */
-	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
-		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
-			if (NULL == n->prev || MDOC__A != n->prev->tok)
-				return;
-
-	/* TODO: %U. */
-
-	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
-		return;
-
-	p->flags |= TERMP_NOSPACE;
-	if (NULL == n->next) {
-		term_word(p, ".");
-		p->flags |= TERMP_SENTENCE;
-	} else
-		term_word(p, ",");
-}
-
-static int
-termp_li_pre(DECL_ARGS)
-{
-
-	termp_tag_pre(p, pair, meta, n);
-	term_fontpush(p, TERMFONT_NONE);
-	return 1;
-}
-
-static int
-termp_lk_pre(DECL_ARGS)
-{
-	const struct roff_node *link, *descr, *punct;
-	int display;
-
-	if ((link = n->child) == NULL)
-		return 0;
-
-	/* Find beginning of trailing punctuation. */
-	punct = n->last;
-	while (punct != link && punct->flags & NODE_DELIMC)
-		punct = punct->prev;
-	punct = punct->next;
-
-	/* Link text. */
-	if ((descr = link->next) != NULL && descr != punct) {
-		term_fontpush(p, TERMFONT_UNDER);
-		while (descr != punct) {
-			if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
-				p->flags |= TERMP_NOSPACE;
-			term_word(p, descr->string);
-			descr = descr->next;
-		}
-		term_fontpop(p);
-		p->flags |= TERMP_NOSPACE;
-		term_word(p, ":");
-	}
-
-	/* Link target. */
-	display = term_strlen(p, link->string) >= 26;
-	if (display) {
-		term_newln(p);
-		p->tcol->offset += term_len(p, p->defindent + 1);
-	}
-	term_fontpush(p, TERMFONT_BOLD);
-	term_word(p, link->string);
-	term_fontpop(p);
-
-	/* Trailing punctuation. */
-	while (punct != NULL) {
-		p->flags |= TERMP_NOSPACE;
-		term_word(p, punct->string);
-		punct = punct->next;
-	}
-	if (display)
-		term_newln(p);
-	return 0;
-}
-
-static int
-termp_bk_pre(DECL_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		break;
-	case ROFFT_HEAD:
-		return 0;
-	case ROFFT_BODY:
-		if (n->parent->args != NULL || n->prev->child == NULL)
-			p->flags |= TERMP_PREKEEP;
-		break;
-	default:
-		abort();
-	}
-
-	return 1;
-}
-
-static void
-termp_bk_post(DECL_ARGS)
-{
-
-	if (n->type == ROFFT_BODY)
-		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
-}
-
-static void
-termp__t_post(DECL_ARGS)
-{
-
-	/*
-	 * If we're in an `Rs' and there's a journal present, then quote
-	 * us instead of underlining us (for disambiguation).
-	 */
-	if (n->parent && MDOC_Rs == n->parent->tok &&
-	    n->parent->norm->Rs.quote_T)
-		termp_quote_post(p, pair, meta, n);
-
-	termp____post(p, pair, meta, n);
-}
-
-static int
-termp__t_pre(DECL_ARGS)
-{
-
-	/*
-	 * If we're in an `Rs' and there's a journal present, then quote
-	 * us instead of underlining us (for disambiguation).
-	 */
-	if (n->parent && MDOC_Rs == n->parent->tok &&
-	    n->parent->norm->Rs.quote_T)
-		return termp_quote_pre(p, pair, meta, n);
-
-	term_fontpush(p, TERMFONT_UNDER);
-	return 1;
-}
-
-static int
-termp_under_pre(DECL_ARGS)
-{
-
-	term_fontpush(p, TERMFONT_UNDER);
-	return 1;
-}
-
-static int
-termp_em_pre(DECL_ARGS)
-{
-	if (n->child != NULL &&
-	    n->child->type == ROFFT_TEXT)
-		tag_put(n->child->string, 0, p->line);
-	term_fontpush(p, TERMFONT_UNDER);
-	return 1;
-}
-
-static int
-termp_sy_pre(DECL_ARGS)
-{
-	if (n->child != NULL &&
-	    n->child->type == ROFFT_TEXT)
-		tag_put(n->child->string, 0, p->line);
-	term_fontpush(p, TERMFONT_BOLD);
-	return 1;
-}
-
-static int
-termp_er_pre(DECL_ARGS)
-{
-
-	if (n->sec == SEC_ERRORS &&
-	    (n->parent->tok == MDOC_It ||
-	     (n->parent->tok == MDOC_Bq &&
-	      n->parent->parent->parent->tok == MDOC_It)))
-		tag_put(n->child->string, 1, p->line);
-	return 1;
-}
-
-static int
-termp_tag_pre(DECL_ARGS)
-{
-
-	if (n->child != NULL &&
-	    n->child->type == ROFFT_TEXT &&
-	    (n->prev == NULL ||
-	     (n->prev->type == ROFFT_TEXT &&
-	      strcmp(n->prev->string, "|") == 0)) &&
-	    (n->parent->tok == MDOC_It ||
-	     (n->parent->tok == MDOC_Xo &&
-	      n->parent->parent->prev == NULL &&
-	      n->parent->parent->parent->tok == MDOC_It)))
-		tag_put(n->child->string, 1, p->line);
-	return 1;
-}

Property changes on: head/contrib/mdocml/mdoc_term.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/catman.c
===================================================================
--- head/contrib/mdocml/catman.c	(revision 338825)
+++ head/contrib/mdocml/catman.c	(nonexistent)
@@ -1,260 +0,0 @@
-/*	$Id: catman.c,v 1.21 2017/02/18 12:24:24 schwarze Exp $ */
-/*
- * Copyright (c) 2017 Michael Stapelberg 
- * 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 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"
-
-#if HAVE_CMSG_XPG42
-#define _XPG4_2
-#endif
-
-#include 
-#include 
-#include 
-
-#if HAVE_ERR
-#include 
-#endif
-#include 
-#include 
-#if HAVE_FTS
-#include 
-#else
-#include "compat_fts.h"
-#endif
-#include 
-#include 
-#include 
-#include 
-#include 
-
-int	 process_manpage(int, int, const char *);
-int	 process_tree(int, int);
-void	 run_mandocd(int, const char *, const char *)
-		__attribute__((__noreturn__));
-ssize_t	 sock_fd_write(int, int, int, int);
-void	 usage(void) __attribute__((__noreturn__));
-
-
-void
-run_mandocd(int sockfd, const char *outtype, const char* defos)
-{
-	char	 sockfdstr[10];
-
-	if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1)
-		err(1, "snprintf");
-	if (defos == NULL)
-		execlp("mandocd", "mandocd", "-T", outtype,
-		    sockfdstr, (char *)NULL);
-	else
-		execlp("mandocd", "mandocd", "-T", outtype,
-		    "-I", defos, sockfdstr, (char *)NULL);
-	err(1, "exec");
-}
-
-ssize_t
-sock_fd_write(int fd, int fd0, int fd1, int fd2)
-{
-	const struct timespec timeout = { 0, 10000000 };  /* 0.01 s */
-	struct msghdr	 msg;
-	struct iovec	 iov;
-	union {
-		struct cmsghdr	 cmsghdr;
-		char		 control[CMSG_SPACE(3 * sizeof(int))];
-	} cmsgu;
-	struct cmsghdr	*cmsg;
-	int		*walk;
-	ssize_t		 sz;
-	unsigned char	 dummy[1] = {'\0'};
-
-	iov.iov_base = dummy;
-	iov.iov_len = sizeof(dummy);
-
-	msg.msg_name = NULL;
-	msg.msg_namelen = 0;
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-
-	msg.msg_control = cmsgu.control;
-	msg.msg_controllen = sizeof(cmsgu.control);
-
-	cmsg = CMSG_FIRSTHDR(&msg);
-	cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int));
-	cmsg->cmsg_level = SOL_SOCKET;
-	cmsg->cmsg_type = SCM_RIGHTS;
-
-	walk = (int *)CMSG_DATA(cmsg);
-	*(walk++) = fd0;
-	*(walk++) = fd1;
-	*(walk++) = fd2;
-
-	/*
-	 * It appears that on some systems, sendmsg(3)
-	 * may return EAGAIN even in blocking mode.
-	 * Seen for example on Oracle Solaris 11.2.
-	 * The sleeping time was chosen by experimentation,
-	 * to neither cause more than a handful of retries
-	 * in normal operation nor unnecessary delays.
-	 */
-	for (;;) {
-		if ((sz = sendmsg(fd, &msg, 0)) != -1 ||
-		    errno != EAGAIN)
-			break;
-		nanosleep(&timeout, NULL);
-	}
-	return sz;
-}
-
-int
-process_manpage(int srv_fd, int dstdir_fd, const char *path)
-{
-	int	 in_fd, out_fd;
-	int	 irc;
-
-	if ((in_fd = open(path, O_RDONLY)) == -1) {
-		warn("open(%s)", path);
-		return 0;
-	}
-
-	if ((out_fd = openat(dstdir_fd, path,
-	    O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC,
-	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
-		warn("openat(%s)", path);
-		close(in_fd);
-		return 0;
-	}
-
-	irc = sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO);
-
-	close(in_fd);
-	close(out_fd);
-
-	if (irc < 0) {
-		warn("sendmsg");
-		return -1;
-	}
-	return 0;
-}
-
-int
-process_tree(int srv_fd, int dstdir_fd)
-{
-	FTS		*ftsp;
-	FTSENT		*entry;
-	const char	*argv[2];
-	const char	*path;
-
-	argv[0] = ".";
-	argv[1] = (char *)NULL;
-
-	if ((ftsp = fts_open((char * const *)argv,
-	    FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
-		warn("fts_open");
-		return -1;
-	}
-
-	while ((entry = fts_read(ftsp)) != NULL) {
-		path = entry->fts_path + 2;
-		switch (entry->fts_info) {
-		case FTS_F:
-			if (process_manpage(srv_fd, dstdir_fd, path) == -1) {
-				fts_close(ftsp);
-				return -1;
-			}
-			break;
-		case FTS_D:
-			if (*path != '\0' &&
-			    mkdirat(dstdir_fd, path, S_IRWXU | S_IRGRP |
-			      S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
-			    errno != EEXIST) {
-				warn("mkdirat(%s)", path);
-				(void)fts_set(ftsp, entry, FTS_SKIP);
-			}
-			break;
-		case FTS_DP:
-			break;
-		default:
-			warnx("%s: not a regular file", path);
-			break;
-		}
-	}
-
-	fts_close(ftsp);
-	return 0;
-}
-
-int
-main(int argc, char **argv)
-{
-	const char	*defos, *outtype;
-	int		 srv_fds[2];
-	int		 dstdir_fd;
-	int		 opt;
-	pid_t		 pid;
-
-	defos = NULL;
-	outtype = "ascii";
-	while ((opt = getopt(argc, argv, "I:T:")) != -1) {
-		switch (opt) {
-		case 'I':
-			defos = optarg;
-			break;
-		case 'T':
-			outtype = optarg;
-			break;
-		default:
-			usage();
-		}
-	}
-
-	if (argc > 0) {
-		argc -= optind;
-		argv += optind;
-	}
-	if (argc != 2)
-		usage();
-
-	if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1)
-		err(1, "socketpair");
-
-	pid = fork();
-	switch (pid) {
-	case -1:
-		err(1, "fork");
-	case 0:
-		close(srv_fds[0]);
-		run_mandocd(srv_fds[1], outtype, defos);
-	default:
-		break;
-	}
-	close(srv_fds[1]);
-
-	if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1)
-		err(1, "open(%s)", argv[1]);
-
-	if (chdir(argv[0]) == -1)
-		err(1, "chdir(%s)", argv[0]);
-
-	return process_tree(srv_fds[0], dstdir_fd) == -1 ? 1 : 0;
-}
-
-void
-usage(void)
-{
-	fprintf(stderr, "usage: %s [-I os=name] [-T output] "
-	    "srcdir dstdir\n", BINM_CATMAN);
-	exit(1);
-}

Property changes on: head/contrib/mdocml/catman.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-stringlist.c
===================================================================
--- head/contrib/mdocml/test-stringlist.c	(revision 338825)
+++ head/contrib/mdocml/test-stringlist.c	(nonexistent)
@@ -1,37 +0,0 @@
-/*	$Id: test-stringlist.c,v 1.2 2015/10/06 18:32:20 schwarze Exp $	*/
-/*
- * Copyright (c) 2015 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.
- */
-
-#include 
-
-int
-main(void)
-{
-	StringList	*sl;
-	char		 teststr[] = "test";
-
-	if ((sl = sl_init()) == NULL)
-		return 1;
-	if (sl_add(sl, teststr))
-		return 2;
-	if (sl->sl_cur != 1)
-		return 3;
-	if (sl->sl_str[0] != teststr)
-		return 4;
-
-	sl_free(sl, 0);
-	return 0;
-}

Property changes on: head/contrib/mdocml/test-stringlist.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/tbl_data.c
===================================================================
--- head/contrib/mdocml/tbl_data.c	(revision 338825)
+++ head/contrib/mdocml/tbl_data.c	(nonexistent)
@@ -1,241 +0,0 @@
-/*	$Id: tbl_data.c,v 1.45 2017/07/08 17:52:50 schwarze Exp $ */
-/*
- * Copyright (c) 2009, 2010, 2011 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 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 
-#include 
-#include 
-#include 
-
-#include "mandoc.h"
-#include "mandoc_aux.h"
-#include "libmandoc.h"
-#include "libroff.h"
-
-static	void		 getdata(struct tbl_node *, struct tbl_span *,
-				int, const char *, int *);
-static	struct tbl_span	*newspan(struct tbl_node *, int,
-				struct tbl_row *);
-
-
-static void
-getdata(struct tbl_node *tbl, struct tbl_span *dp,
-		int ln, const char *p, int *pos)
-{
-	struct tbl_dat	*dat;
-	struct tbl_cell	*cp;
-	int		 sv;
-
-	/* Advance to the next layout cell, skipping spanners. */
-
-	cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
-	while (cp != NULL && cp->pos == TBL_CELL_SPAN)
-		cp = cp->next;
-
-	/*
-	 * If the current layout row is out of cells, allocate
-	 * a new cell if another row of the table has at least
-	 * this number of columns, or discard the input if we
-	 * are beyond the last column of the table as a whole.
-	 */
-
-	if (cp == NULL) {
-		if (dp->layout->last->col + 1 < dp->opts->cols) {
-			cp = mandoc_calloc(1, sizeof(*cp));
-			cp->pos = TBL_CELL_LEFT;
-			dp->layout->last->next = cp;
-			cp->col = dp->layout->last->col + 1;
-			dp->layout->last = cp;
-		} else {
-			mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
-			    ln, *pos, p + *pos);
-			while (p[*pos])
-				(*pos)++;
-			return;
-		}
-	}
-
-	dat = mandoc_calloc(1, sizeof(*dat));
-	dat->layout = cp;
-	dat->pos = TBL_DATA_NONE;
-	dat->spans = 0;
-	for (cp = cp->next; cp != NULL; cp = cp->next)
-		if (cp->pos == TBL_CELL_SPAN)
-			dat->spans++;
-		else
-			break;
-
-	if (dp->last == NULL)
-		dp->first = dat;
-	else
-		dp->last->next = dat;
-	dp->last = dat;
-
-	sv = *pos;
-	while (p[*pos] && p[*pos] != tbl->opts.tab)
-		(*pos)++;
-
-	/*
-	 * Check for a continued-data scope opening.  This consists of a
-	 * trailing `T{' at the end of the line.  Subsequent lines,
-	 * until a standalone `T}', are included in our cell.
-	 */
-
-	if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
-		tbl->part = TBL_PART_CDATA;
-		return;
-	}
-
-	dat->string = mandoc_strndup(p + sv, *pos - sv);
-
-	if (p[*pos])
-		(*pos)++;
-
-	if ( ! strcmp(dat->string, "_"))
-		dat->pos = TBL_DATA_HORIZ;
-	else if ( ! strcmp(dat->string, "="))
-		dat->pos = TBL_DATA_DHORIZ;
-	else if ( ! strcmp(dat->string, "\\_"))
-		dat->pos = TBL_DATA_NHORIZ;
-	else if ( ! strcmp(dat->string, "\\="))
-		dat->pos = TBL_DATA_NDHORIZ;
-	else
-		dat->pos = TBL_DATA_DATA;
-
-	if ((dat->layout->pos == TBL_CELL_HORIZ ||
-	    dat->layout->pos == TBL_CELL_DHORIZ ||
-	    dat->layout->pos == TBL_CELL_DOWN) &&
-	    dat->pos == TBL_DATA_DATA && *dat->string != '\0')
-		mandoc_msg(MANDOCERR_TBLDATA_SPAN,
-		    tbl->parse, ln, sv, dat->string);
-}
-
-void
-tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
-{
-	struct tbl_dat	*dat;
-	size_t		 sz;
-
-	dat = tbl->last_span->last;
-
-	if (p[pos] == 'T' && p[pos + 1] == '}') {
-		pos += 2;
-		if (p[pos] == tbl->opts.tab) {
-			tbl->part = TBL_PART_DATA;
-			pos++;
-			while (p[pos] != '\0')
-				getdata(tbl, tbl->last_span, ln, p, &pos);
-			return;
-		} else if (p[pos] == '\0') {
-			tbl->part = TBL_PART_DATA;
-			return;
-		}
-
-		/* Fallthrough: T} is part of a word. */
-	}
-
-	dat->pos = TBL_DATA_DATA;
-	dat->block = 1;
-
-	if (dat->string != NULL) {
-		sz = strlen(p + pos) + strlen(dat->string) + 2;
-		dat->string = mandoc_realloc(dat->string, sz);
-		(void)strlcat(dat->string, " ", sz);
-		(void)strlcat(dat->string, p + pos, sz);
-	} else
-		dat->string = mandoc_strdup(p + pos);
-
-	if (dat->layout->pos == TBL_CELL_DOWN)
-		mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
-		    ln, pos, dat->string);
-}
-
-static struct tbl_span *
-newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
-{
-	struct tbl_span	*dp;
-
-	dp = mandoc_calloc(1, sizeof(*dp));
-	dp->line = line;
-	dp->opts = &tbl->opts;
-	dp->layout = rp;
-	dp->prev = tbl->last_span;
-
-	if (dp->prev == NULL) {
-		tbl->first_span = dp;
-		tbl->current_span = NULL;
-	} else
-		dp->prev->next = dp;
-	tbl->last_span = dp;
-
-	return dp;
-}
-
-void
-tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
-{
-	struct tbl_row	*rp;
-	struct tbl_cell	*cp;
-	struct tbl_span	*sp;
-
-	rp = (sp = tbl->last_span) == NULL ? tbl->first_row :
-	    sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ?
-	    sp->layout->next : sp->layout;
-
-	assert(rp != NULL);
-
-	if ( ! strcmp(p, "_")) {
-		sp = newspan(tbl, ln, rp);
-		sp->pos = TBL_SPAN_HORIZ;
-		return;
-	} else if ( ! strcmp(p, "=")) {
-		sp = newspan(tbl, ln, rp);
-		sp->pos = TBL_SPAN_DHORIZ;
-		return;
-	}
-
-	/*
-	 * If the layout row contains nothing but horizontal lines,
-	 * allocate an empty span for it and assign the current span
-	 * to the next layout row accepting data.
-	 */
-
-	while (rp->next != NULL) {
-		if (rp->last->col + 1 < tbl->opts.cols)
-			break;
-		for (cp = rp->first; cp != NULL; cp = cp->next)
-			if (cp->pos != TBL_CELL_HORIZ &&
-			    cp->pos != TBL_CELL_DHORIZ)
-				break;
-		if (cp != NULL)
-			break;
-		sp = newspan(tbl, ln, rp);
-		sp->pos = TBL_SPAN_DATA;
-		rp = rp->next;
-	}
-
-	/* Process a real data row. */
-
-	sp = newspan(tbl, ln, rp);
-	sp->pos = TBL_SPAN_DATA;
-	while (p[pos] != '\0')
-		getdata(tbl, sp, ln, p, &pos);
-}

Property changes on: head/contrib/mdocml/tbl_data.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-fgetln.c
===================================================================
--- head/contrib/mdocml/test-fgetln.c	(revision 338825)
+++ head/contrib/mdocml/test-fgetln.c	(nonexistent)
@@ -1,11 +0,0 @@
-#include 
-#include 
-#include 
-
-int
-main(void)
-{
-	size_t sz;
-	fclose(stdin);
-	return(NULL != fgetln(stdin, &sz));
-}

Property changes on: head/contrib/mdocml/test-fgetln.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mandoc_html.3
===================================================================
--- head/contrib/mdocml/mandoc_html.3	(revision 338825)
+++ head/contrib/mdocml/mandoc_html.3	(nonexistent)
@@ -1,385 +0,0 @@
-.\"	$Id: mandoc_html.3,v 1.10 2017/07/15 17:57:51 schwarze Exp $
-.\"
-.\" 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.
-.\"
-.Dd $Mdocdate: July 15 2017 $
-.Dt MANDOC_HTML 3
-.Os
-.Sh NAME
-.Nm mandoc_html
-.Nd internals of the mandoc HTML formatter
-.Sh SYNOPSIS
-.In "html.h"
-.Ft void
-.Fn print_gen_decls "struct html *h"
-.Ft void
-.Fn print_gen_head "struct html *h"
-.Ft struct tag *
-.Fo print_otag
-.Fa "struct html *h"
-.Fa "enum htmltag tag"
-.Fa "const char *fmt"
-.Fa ...
-.Fc
-.Ft void
-.Fo print_tagq
-.Fa "struct html *h"
-.Fa "const struct tag *until"
-.Fc
-.Ft void
-.Fo print_stagq
-.Fa "struct html *h"
-.Fa "const struct tag *suntil"
-.Fc
-.Ft void
-.Fo print_text
-.Fa "struct html *h"
-.Fa "const char *word"
-.Fc
-.Ft char *
-.Fo html_make_id
-.Fa "const struct roff_node *n"
-.Fc
-.Ft int
-.Fo html_strlen
-.Fa "const char *cp"
-.Fc
-.Sh DESCRIPTION
-The mandoc HTML formatter is not a formal library.
-However, as it is compiled into more than one program, in particular
-.Xr mandoc 1
-and
-.Xr man.cgi 8 ,
-and because it may be security-critical in some contexts,
-some documentation is useful to help to use it correctly and
-to prevent XSS vulnerabilities.
-.Pp
-The formatter produces HTML output on the standard output.
-Since proper escaping is usually required and best taken care of
-at one central place, the language-specific formatters
-.Po
-.Pa *_html.c ,
-see
-.Sx FILES
-.Pc
-are not supposed to print directly to
-.Dv stdout
-using functions like
-.Xr printf 3 ,
-.Xr putc 3 ,
-.Xr puts 3 ,
-or
-.Xr write 2 .
-Instead, they are expected to use the output functions declared in
-.Pa html.h
-and implemented as part of the main HTML formatting engine in
-.Pa html.c .
-.Ss Data structures
-These structures are declared in
-.Pa html.h .
-.Bl -tag -width Ds
-.It Vt struct html
-Internal state of the HTML formatter.
-.It Vt struct tag
-One entry for the LIFO stack of HTML elements.
-Members are
-.Fa "enum htmltag tag"
-and
-.Fa "struct tag *next" .
-.El
-.Ss Private interface functions
-The function
-.Fn print_gen_decls
-prints the opening
-.Ao Pf \&? Ic xml ? Ac
-and
-.Aq Pf \&! Ic DOCTYPE
-declarations required for the current document type.
-.Pp
-The function
-.Fn print_gen_head
-prints the opening
-.Aq Ic META
-and
-.Aq Ic LINK
-elements for the document
-.Aq Ic HEAD ,
-using the
-.Fa style
-member of
-.Fa h
-unless that is
-.Dv NULL .
-It uses
-.Fn print_otag
-which takes care of properly encoding attributes,
-which is relevant for the
-.Fa style
-link in particular.
-.Pp
-The function
-.Fn print_otag
-prints the start tag of an HTML element with the name
-.Fa tag ,
-optionally including the attributes specified by
-.Fa fmt .
-If
-.Fa fmt
-is the empty string, no attributes are written.
-Each letter of
-.Fa fmt
-specifies one attribute to write.
-Most attributes require one
-.Va char *
-argument which becomes the value of the attribute.
-The arguments have to be given in the same order as the attribute letters.
-If an argument is
-.Dv NULL ,
-the respective attribute is not written.
-.Bl -tag -width 1n -offset indent
-.It Cm c
-Print a
-.Cm class
-attribute.
-This attribute letter can optionally be followed by the modifier letter
-.Cm T .
-In that case, a
-.Cm title
-attribute with the same value is also printed.
-.It Cm h
-Print a
-.Cm href
-attribute.
-This attribute letter can optionally be followed by a modifier letter.
-If followed by
-.Cm R ,
-it formats the link as a local one by prefixing a
-.Sq #
-character.
-If followed by
-.Cm I ,
-it interpretes the argument as a header file name
-and generates a link using the
-.Xr mandoc 1
-.Fl O Cm includes
-option.
-If followed by
-.Cm M ,
-it takes two arguments instead of one, a manual page name and
-section, and formats them as a link to a manual page using the
-.Xr mandoc 1
-.Fl O Cm man
-option.
-.It Cm i
-Print an
-.Cm id
-attribute.
-.It Cm \&?
-Print an arbitrary attribute.
-This format letter requires two
-.Vt char *
-arguments, the attribute name and the value.
-The name must not be
-.Dv NULL .
-.It Cm s
-Print a
-.Cm style
-attribute.
-If present, it must be the last format letter.
-In contrast to the other format letters, this one does not yet
-print the value and does not take an argument.
-Instead, the rest of the format string consists of pairs of
-argument type letters and style name letters.
-.El
-.Pp
-Argument type letters each require one argument as follows:
-.Bl -tag -width 1n -offset indent
-.It Cm h
-Requires one
-.Vt int
-argument, interpreted as a horizontal length in units of
-.Dv SCALE_EN .
-.It Cm s
-Requires one
-.Vt char *
-argument, used as a style value.
-.It Cm u
-Requires one
-.Vt struct roffsu *
-argument, used as a length.
-.It Cm w
-Requires one
-.Vt char *
-argument, interpreted as an
-.Xr mdoc 7 Ns -style
-width specifier.
-If the argument is
-.Dv NULL ,
-nothing is printed for this pair.
-.Pp
-The
-.Cm w
-argument type letter can optionally be followed by one, two, or three
-modifier letters.
-The modifier
-.Cm *
-suppresses printing of the pair if the argument matches 6n.
-The modifier
-.Cm +
-increases the width by 20% to make even bold text fit
-and adds three units for padding between columns.
-The modifier
-.Cm \-
-makes the width negative by multiplying it with \-1.
-.El
-.Pp
-Style name letters decide what to do with the preceding argument:
-.Bl -tag -width 1n -offset indent
-.It Cm h
-Set
-.Cm height
-to the given length.
-.It Cm i
-Set
-.Cm text-indent
-to the given length.
-.It Cm l
-Set
-.Cm margin-left
-to the given length.
-.It Cm w
-Set
-.Cm width
-to the given length.
-.It Cm W
-Set
-.Cm min-width
-to the given length.
-.It Cm \&?
-The special pair
-.Cm s?
-requires two
-.Vt char *
-arguments.
-The first is the style name, the second its value.
-The style name must not be
-.Dv NULL .
-.El
-.Pp
-.Fn print_otag
-uses the private function
-.Fn print_encode
-to take care of HTML encoding.
-If required by the element type, it remembers in
-.Fa h
-that the element is open.
-The function
-.Fn print_tagq
-is used to close out all open elements up to and including
-.Fa until ;
-.Fn print_stagq
-is a variant to close out all open elements up to but excluding
-.Fa suntil .
-.Pp
-The function
-.Fn print_text
-prints HTML element content.
-It uses the private function
-.Fn print_encode
-to take care of HTML encoding.
-If the document has requested a non-standard font, for example using a
-.Xr roff 7
-.Ic \ef
-font escape sequence,
-.Fn print_text
-wraps
-.Fa word
-in an HTML font selection element using the
-.Fn print_otag
-and
-.Fn print_tagq
-functions.
-.Pp
-The function
-.Fn html_make_id
-takes a node containing one or more text children
-and returns a newly allocated string containing the concatenation
-of the child strings, with blanks replaced by underscores.
-If the node
-.Fa n
-contains any non-text child node,
-.Fn html_make_id
-returns
-.Dv NULL
-instead.
-The caller is responsible for freeing the returned string.
-.Pp
-The function
-.Fn html_strlen
-counts the number of characters in
-.Fa cp .
-It is used as a crude estimate of the width needed to display a string.
-.Pp
-The functions
-.Fn print_eqn ,
-.Fn print_tbl ,
-and
-.Fn print_tblclose
-are not yet documented.
-.Sh FILES
-.Bl -tag -width mandoc_aux.c -compact
-.It Pa main.h
-declarations of public functions for use by the main program,
-not yet documented
-.It Pa html.h
-declarations of data types and private functions
-for use by language-specific HTML formatters
-.It Pa html.c
-main HTML formatting engine and utility functions
-.It Pa mdoc_html.c
-.Xr mdoc 7
-HTML formatter
-.It Pa man_html.c
-.Xr man 7
-HTML formatter
-.It Pa tbl_html.c
-.Xr tbl 7
-HTML formatter
-.It Pa eqn_html.c
-.Xr eqn 7
-HTML formatter
-.It Pa out.h
-declarations of data types and private functions
-for shared use by all mandoc formatters,
-not yet documented
-.It Pa out.c
-private functions for shared use by all mandoc formatters
-.It Pa mandoc_aux.h
-declarations of common mandoc utility functions, see
-.Xr mandoc 3
-.It Pa mandoc_aux.c
-implementation of common mandoc utility functions
-.El
-.Sh SEE ALSO
-.Xr mandoc 1 ,
-.Xr mandoc 3 ,
-.Xr man.cgi 8
-.Sh AUTHORS
-.An -nosplit
-The mandoc HTML formatter was written by
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
-It is maintained by
-.An Ingo Schwarze Aq Mt schwarze@openbsd.org ,
-who also wrote this manual.

Property changes on: head/contrib/mdocml/mandoc_html.3
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-sandbox_init.c
===================================================================
--- head/contrib/mdocml/test-sandbox_init.c	(revision 338825)
+++ head/contrib/mdocml/test-sandbox_init.c	(nonexistent)
@@ -1,13 +0,0 @@
-#include 
-
-int
-main(void)
-{
-	char	*ep;
-	int	 rc;
-
-	rc = sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, &ep);
-	if (-1 == rc)
-		sandbox_free_error(ep);
-	return(-1 == rc);
-}

Property changes on: head/contrib/mdocml/test-sandbox_init.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/lib.c
===================================================================
--- head/contrib/mdocml/lib.c	(revision 338825)
+++ head/contrib/mdocml/lib.c	(nonexistent)
@@ -1,38 +0,0 @@
-/*	$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;
-}

Property changes on: head/contrib/mdocml/lib.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-err.c
===================================================================
--- head/contrib/mdocml/test-err.c	(revision 338825)
+++ head/contrib/mdocml/test-err.c	(nonexistent)
@@ -1,28 +0,0 @@
-/*	$Id: test-err.c,v 1.1 2015/10/11 21:12:55 schwarze Exp $	*/
-/*
- * Copyright (c) 2015 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.
- */
-
-#include 
-
-int
-main(void)
-{
-	warnx("%d. warnx", 1);
-	warn("%d. warn", 2);
-	err(0, "%d. err", 3);
-	/* NOTREACHED */
-	return 1;
-}

Property changes on: head/contrib/mdocml/test-err.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mandoc.1
===================================================================
--- head/contrib/mdocml/mandoc.1	(revision 338825)
+++ head/contrib/mdocml/mandoc.1	(nonexistent)
@@ -1,2140 +0,0 @@
-.\"	$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: August 8 2018 $
-.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 less 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 less 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.
-.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 .
-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 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 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 .
-.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 less 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 less 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 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 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 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 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
-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
-Indicates a risk of information loss or severe misformatting,
-in most cases caused by serious syntax errors.
-.It Cm warning
-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.
-.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 "trailing delimiter"
-.Pq mdoc
-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 "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 "late prologue macro"
-.Pq mdoc
-A
-.Ic \&Dd
-or
-.Ic \&Os
-macro occurs after some non-prologue macro, but still takes effect.
-.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, 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 "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 "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 "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 "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 \&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 \&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 .

Property changes on: head/contrib/mdocml/mandoc.1
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mandoc.3
===================================================================
--- head/contrib/mdocml/mandoc.3	(revision 338825)
+++ head/contrib/mdocml/mandoc.3	(nonexistent)
@@ -1,713 +0,0 @@
-.\"	$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: 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
-.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 mandocerr mmin"
-.Fa "mandocmsg mmsg"
-.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 mmin
-Can be set to
-.Dv MANDOCERR_BASE ,
-.Dv MANDOCERR_STYLE ,
-.Dv MANDOCERR_WARNING ,
-.Dv MANDOCERR_ERROR ,
-.Dv MANDOCERR_UNSUPP ,
-or
-.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 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
-.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
-.Ic \&Ao
-block extends from TEXT ao to TEXT ac,
-while the formatting of the
-.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 .

Property changes on: head/contrib/mdocml/mandoc.3
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mandoc.c
===================================================================
--- head/contrib/mdocml/mandoc.c	(revision 338825)
+++ head/contrib/mdocml/mandoc.c	(nonexistent)
@@ -1,630 +0,0 @@
-/*	$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_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 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, 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)) {
-		cp = time2a(t);
-		if (t > time(NULL) + 86400)
-			mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse,
-			    ln, pos, cp);
-		return cp;
-	}
-
-	/* In man(7), do not warn about the legacy format. */
-
-	if (a2time(&t, "%Y-%m-%d", in) == 0)
-		mandoc_msg(MANDOCERR_DATE_BAD, man->parse, ln, pos, in);
-	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;
-}

Property changes on: head/contrib/mdocml/mandoc.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-strptime.c
===================================================================
--- head/contrib/mdocml/test-strptime.c	(revision 338825)
+++ head/contrib/mdocml/test-strptime.c	(nonexistent)
@@ -1,14 +0,0 @@
-#if defined(__linux__) || defined(__MINT__)
-# define _GNU_SOURCE /* strptime() */
-#endif
-
-#include 
-
-int
-main(void)
-{
-	struct tm tm;
-	const char input[] = "2014-01-04";
-	return ! (strptime(input, "%Y-%m-%d", &tm) == input + 10 &&
-	    tm.tm_year == 114 && tm.tm_mon == 0 && tm.tm_mday == 4);
-}

Property changes on: head/contrib/mdocml/test-strptime.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/preconv.c
===================================================================
--- head/contrib/mdocml/preconv.c	(revision 338825)
+++ head/contrib/mdocml/preconv.c	(nonexistent)
@@ -1,176 +0,0 @@
-/*	$Id: preconv.c,v 1.16 2017/02/18 13:43:52 schwarze Exp $ */
-/*
- * Copyright (c) 2011 Kristaps Dzonsons 
- * Copyright (c) 2014 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.
- */
-#include "config.h"
-
-#include 
-
-#include 
-#include 
-#include 
-#include "mandoc.h"
-#include "libmandoc.h"
-
-int
-preconv_encode(const struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
-    int *filenc)
-{
-	const unsigned char	*cu;
-	int			 nby;
-	unsigned int		 accum;
-
-	cu = (const unsigned char *)ib->buf + *ii;
-	assert(*cu & 0x80);
-
-	if ( ! (*filenc & MPARSE_UTF8))
-		goto latin;
-
-	nby = 1;
-	while (nby < 5 && *cu & (1 << (7 - nby)))
-		nby++;
-
-	switch (nby) {
-	case 2:
-		accum = *cu & 0x1f;
-		if (accum < 0x02)  /* Obfuscated ASCII. */
-			goto latin;
-		break;
-	case 3:
-		accum = *cu & 0x0f;
-		break;
-	case 4:
-		accum = *cu & 0x07;
-		if (accum > 0x04) /* Beyond Unicode. */
-			goto latin;
-		break;
-	default:  /* Bad sequence header. */
-		goto latin;
-	}
-
-	cu++;
-	switch (nby) {
-	case 3:
-		if ((accum == 0x00 && ! (*cu & 0x20)) ||  /* Use 2-byte. */
-		    (accum == 0x0d && *cu & 0x20))  /* Surrogates. */
-			goto latin;
-		break;
-	case 4:
-		if ((accum == 0x00 && ! (*cu & 0x30)) ||  /* Use 3-byte. */
-		    (accum == 0x04 && *cu & 0x30))  /* Beyond Unicode. */
-			goto latin;
-		break;
-	default:
-		break;
-	}
-
-	while (--nby) {
-		if ((*cu & 0xc0) != 0x80)  /* Invalid continuation. */
-			goto latin;
-		accum <<= 6;
-		accum += *cu & 0x3f;
-		cu++;
-	}
-
-	assert(accum > 0x7f);
-	assert(accum < 0x110000);
-	assert(accum < 0xd800 || accum > 0xdfff);
-
-	*oi += snprintf(ob->buf + *oi, 11, "\\[u%.4X]", accum);
-	*ii = (const char *)cu - ib->buf;
-	*filenc &= ~MPARSE_LATIN1;
-	return 1;
-
-latin:
-	if ( ! (*filenc & MPARSE_LATIN1))
-		return 0;
-
-	*oi += snprintf(ob->buf + *oi, 11,
-	    "\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
-
-	*filenc &= ~MPARSE_UTF8;
-	return 1;
-}
-
-int
-preconv_cue(const struct buf *b, size_t offset)
-{
-	const char	*ln, *eoln, *eoph;
-	size_t		 sz, phsz;
-
-	ln = b->buf + offset;
-	sz = b->sz - offset;
-
-	/* Look for the end-of-line. */
-
-	if (NULL == (eoln = memchr(ln, '\n', sz)))
-		eoln = ln + sz;
-
-	/* Check if we have the correct header/trailer. */
-
-	if ((sz = (size_t)(eoln - ln)) < 10 ||
-	    memcmp(ln, ".\\\" -*-", 7) || memcmp(eoln - 3, "-*-", 3))
-		return MPARSE_UTF8 | MPARSE_LATIN1;
-
-	/* Move after the header and adjust for the trailer. */
-
-	ln += 7;
-	sz -= 10;
-
-	while (sz > 0) {
-		while (sz > 0 && ' ' == *ln) {
-			ln++;
-			sz--;
-		}
-		if (0 == sz)
-			break;
-
-		/* Find the end-of-phrase marker (or eoln). */
-
-		if (NULL == (eoph = memchr(ln, ';', sz)))
-			eoph = eoln - 3;
-		else
-			eoph++;
-
-		/* Only account for the "coding" phrase. */
-
-		if ((phsz = eoph - ln) < 7 ||
-		    strncasecmp(ln, "coding:", 7)) {
-			sz -= phsz;
-			ln += phsz;
-			continue;
-		}
-
-		sz -= 7;
-		ln += 7;
-
-		while (sz > 0 && ' ' == *ln) {
-			ln++;
-			sz--;
-		}
-		if (0 == sz)
-			return 0;
-
-		/* Check us against known encodings. */
-
-		if (phsz > 4 && !strncasecmp(ln, "utf-8", 5))
-			return MPARSE_UTF8;
-		if (phsz > 10 && !strncasecmp(ln, "iso-latin-1", 11))
-			return MPARSE_LATIN1;
-		return 0;
-	}
-	return MPARSE_UTF8 | MPARSE_LATIN1;
-}

Property changes on: head/contrib/mdocml/preconv.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-rewb-sysv.c
===================================================================
--- head/contrib/mdocml/test-rewb-sysv.c	(revision 338825)
+++ head/contrib/mdocml/test-rewb-sysv.c	(nonexistent)
@@ -1,27 +0,0 @@
-#include 
-#include 
-#include 
-
-int
-main(void)
-{
-	regex_t	 re;
-
-	if (regcomp(&re, "\\", REG_EXTENDED | REG_NOSUB))
-		return 1;
-	if (regexec(&re, "the word is here", 0, NULL, 0))
-		return 2;
-	if (regexec(&re, "same word", 0, NULL, 0))
-		return 3;
-	if (regexec(&re, "word again", 0, NULL, 0))
-		return 4;
-	if (regexec(&re, "word", 0, NULL, 0))
-		return 5;
-	if (regexec(&re, "wordy", 0, NULL, 0) != REG_NOMATCH)
-		return 6;
-	if (regexec(&re, "sword", 0, NULL, 0) != REG_NOMATCH)
-		return 7;
-	if (regexec(&re, "reworded", 0, NULL, 0) != REG_NOMATCH)
-		return 8;
-	return 0;
-}

Property changes on: head/contrib/mdocml/test-rewb-sysv.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/compat_err.c
===================================================================
--- head/contrib/mdocml/compat_err.c	(revision 338825)
+++ head/contrib/mdocml/compat_err.c	(nonexistent)
@@ -1,112 +0,0 @@
-#include "config.h"
-
-#if HAVE_ERR
-
-int dummy;
-
-#else
-
-/* $Id: compat_err.c,v 1.4 2015/11/26 07:42:11 schwarze Exp $ */
-/*
- * Copyright (c) 1993
- *      The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include 
-#include 
-#include 
-#include 
-#include 
-
-static void vwarni(const char *, va_list);
-static void vwarnxi(const char *, va_list);
-
-static void
-vwarnxi(const char *fmt, va_list ap)
-{
-	fprintf(stderr, "%s: ", getprogname());
-	if (fmt != NULL)
-		vfprintf(stderr, fmt, ap);
-}
-
-static void
-vwarni(const char *fmt, va_list ap)
-{
-	int sverrno;
-
-	sverrno = errno;
-	vwarnxi(fmt, ap);
-	if (fmt != NULL)
-		fputs(": ", stderr);
-	fprintf(stderr, "%s\n", strerror(sverrno));
-}
-
-void
-err(int eval, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarni(fmt, ap);
-	va_end(ap);
-	exit(eval);
-}
-
-void
-errx(int eval, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarnxi(fmt, ap);
-	va_end(ap);
-	fputc('\n', stderr);
-	exit(eval);
-}
-
-void
-warn(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarni(fmt, ap);
-	va_end(ap);
-}
-
-void
-warnx(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarnxi(fmt, ap);
-	va_end(ap);
-	fputc('\n', stderr);
-}
-
-#endif

Property changes on: head/contrib/mdocml/compat_err.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/compat_fts.h
===================================================================
--- head/contrib/mdocml/compat_fts.h	(revision 338825)
+++ head/contrib/mdocml/compat_fts.h	(nonexistent)
@@ -1,105 +0,0 @@
-/*	$OpenBSD: fts.h,v 1.14 2012/12/05 23:19:57 deraadt Exp $	*/
-/*	$NetBSD: fts.h,v 1.7 2012/03/01 16:18:51 hans Exp $	*/
-
-/*
- * Copyright (c) 1989, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)fts.h	8.3 (Berkeley) 8/14/94
- */
-
-#ifndef	_FTS_H_
-#define	_FTS_H_
-
-typedef struct {
-	struct _ftsent *fts_cur;	/* current node */
-	struct _ftsent *fts_child;	/* linked list of children */
-	struct _ftsent **fts_array;	/* sort array */
-	dev_t fts_dev;			/* starting device # */
-	char *fts_path;			/* path for this descent */
-	size_t fts_pathlen;		/* sizeof(path) */
-	int fts_nitems;			/* elements in the sort array */
-	int (*fts_compar)();		/* compare function */
-
-#define	FTS_NOCHDIR	0x0004		/* don't change directories */
-#define	FTS_PHYSICAL	0x0010		/* physical walk */
-#define	FTS_XDEV	0x0040		/* don't cross devices */
-#define	FTS_OPTIONMASK	0x0054		/* valid user option mask */
-
-#define	FTS_STOP	0x2000		/* (private) unrecoverable error */
-	int fts_options;		/* fts_open options, global flags */
-} FTS;
-
-typedef struct _ftsent {
-	struct _ftsent *fts_cycle;	/* cycle node */
-	struct _ftsent *fts_parent;	/* parent directory */
-	struct _ftsent *fts_link;	/* next file in directory */
-	char *fts_accpath;		/* access path */
-	char *fts_path;			/* root path */
-	int fts_errno;			/* errno for this node */
-	size_t fts_pathlen;		/* strlen(fts_path) */
-	size_t fts_namelen;		/* strlen(fts_name) */
-
-	ino_t fts_ino;			/* inode */
-	dev_t fts_dev;			/* device */
-	nlink_t fts_nlink;		/* link count */
-
-#define	FTS_ROOTPARENTLEVEL	-1
-#define	FTS_ROOTLEVEL		 0
-#define	FTS_MAXLEVEL		 0x7fffffff
-	int fts_level;		/* depth (-1 to N) */
-
-#define	FTS_D		 1		/* preorder directory */
-#define	FTS_DC		 2		/* directory that causes cycles */
-#define	FTS_DEFAULT	 3		/* none of the above */
-#define	FTS_DNR		 4		/* unreadable directory */
-#define	FTS_DOT		 5		/* dot or dot-dot */
-#define	FTS_DP		 6		/* postorder directory */
-#define	FTS_ERR		 7		/* error; errno is set */
-#define	FTS_F		 8		/* regular file */
-#define	FTS_INIT	 9		/* initialized only */
-#define	FTS_NS		10		/* stat(2) failed */
-#define	FTS_NSOK	11		/* no stat(2) requested */
-#define	FTS_SL		12		/* symbolic link */
-	unsigned short fts_info;	/* user flags for FTSENT structure */
-
-#define	FTS_NOINSTR	 3		/* no instructions */
-#define	FTS_SKIP	 4		/* discard node */
-	unsigned short fts_instr;	/* fts_set() instructions */
-
-	struct stat *fts_statp;		/* stat(2) information */
-	char fts_name[1];		/* file name */
-} FTSENT;
-
-
-int	 fts_close(FTS *);
-FTS	*fts_open(char * const *, int,
-	    int (*)(const FTSENT **, const FTSENT **));
-FTSENT	*fts_read(FTS *);
-int	 fts_set(FTS *, FTSENT *, int);
-
-#endif /* !_FTS_H_ */

Property changes on: head/contrib/mdocml/compat_fts.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-getsubopt.c
===================================================================
--- head/contrib/mdocml/test-getsubopt.c	(revision 338825)
+++ head/contrib/mdocml/test-getsubopt.c	(nonexistent)
@@ -1,34 +0,0 @@
-/*	$Id: test-getsubopt.c,v 1.4 2015/10/06 18:32:20 schwarze Exp $	*/
-/*
- * 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 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.
- */
-
-#if defined(__linux__) || defined(__MINT__)
-#define _GNU_SOURCE /* getsubopt() */
-#endif
-
-#include 
-
-int
-main(void)
-{
-	char buf[] = "k=v";
-	char *options = buf;
-	char token0[] = "k";
-	char *const tokens[] = { token0, NULL };
-	char *value = NULL;
-	return ! (getsubopt(&options, tokens, &value) == 0
-	    && value == buf+2 && options == buf+3);
-}

Property changes on: head/contrib/mdocml/test-getsubopt.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-recallocarray.c
===================================================================
--- head/contrib/mdocml/test-recallocarray.c	(revision 338825)
+++ head/contrib/mdocml/test-recallocarray.c	(nonexistent)
@@ -1,11 +0,0 @@
-#include 
-
-int
-main(void)
-{
-	void	*p;
-
-	if ((p = calloc(2, 2)) == NULL)
-		return 1;
-	return !recallocarray(p, 2, 3, 2);
-}

Property changes on: head/contrib/mdocml/test-recallocarray.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/st.in
===================================================================
--- head/contrib/mdocml/st.in	(revision 338825)
+++ head/contrib/mdocml/st.in	(nonexistent)
@@ -1,78 +0,0 @@
-/*	$Id: st.in,v 1.29 2017/06/24 13:49:29 schwarze Exp $ */
-/*
- * Copyright (c) 2009, 2010 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.
- */
-
-/*
- * This file defines the .St macro arguments.  If you add a new
- * standard, make sure that the left-and side corresponds to the .St
- * argument (like .St -p1003.1) and the right-hand side corresponds to
- * the formatted output string.
- *
- * Be sure to escape strings.
- * The non-breaking blanks prevent ending an output line right before
- * a number.  Groff prevent line breaks at the same places.
- *
- * REMEMBER TO ADD NEW STANDARDS TO MDOC.7!
- */
-
-LINE("-p1003.1-88",	"IEEE Std 1003.1-1988 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-90",	"IEEE Std 1003.1-1990 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-96",	"ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-2001",	"IEEE Std 1003.1-2001 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-2004",	"IEEE Std 1003.1-2004 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-2008",	"IEEE Std 1003.1-2008 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-2013",	"IEEE Std 1003.1-2008, 2013 Edition (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1-2016",	"IEEE Std 1003.1-2008, 2016 Edition (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1",	"IEEE Std 1003.1 (\\(LqPOSIX.1\\(Rq)")
-LINE("-p1003.1b",	"IEEE Std 1003.1b (\\(LqPOSIX.1b\\(Rq)")
-LINE("-p1003.1b-93",	"IEEE Std 1003.1b-1993 (\\(LqPOSIX.1b\\(Rq)")
-LINE("-p1003.1c-95",	"IEEE Std 1003.1c-1995 (\\(LqPOSIX.1c\\(Rq)")
-LINE("-p1003.1g-2000",	"IEEE Std 1003.1g-2000 (\\(LqPOSIX.1g\\(Rq)")
-LINE("-p1003.1i-95",	"IEEE Std 1003.1i-1995 (\\(LqPOSIX.1i\\(Rq)")
-LINE("-p1003.2",	"IEEE Std 1003.2 (\\(LqPOSIX.2\\(Rq)")
-LINE("-p1003.2-92",	"IEEE Std 1003.2-1992 (\\(LqPOSIX.2\\(Rq)")
-LINE("-p1003.2a-92",	"IEEE Std 1003.2a-1992 (\\(LqPOSIX.2\\(Rq)")
-LINE("-isoC",		"ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
-LINE("-isoC-90",	"ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
-LINE("-isoC-amd1",	"ISO/IEC 9899/AMD1:1995 (\\(LqISO\\~C90, Amendment 1\\(Rq)")
-LINE("-isoC-tcor1",	"ISO/IEC 9899/TCOR1:1994 (\\(LqISO\\~C90, Technical Corrigendum 1\\(Rq)")
-LINE("-isoC-tcor2",	"ISO/IEC 9899/TCOR2:1995 (\\(LqISO\\~C90, Technical Corrigendum 2\\(Rq)")
-LINE("-isoC-99",	"ISO/IEC 9899:1999 (\\(LqISO\\~C99\\(Rq)")
-LINE("-isoC-2011",	"ISO/IEC 9899:2011 (\\(LqISO\\~C11\\(Rq)")
-LINE("-iso9945-1-90",	"ISO/IEC 9945-1:1990 (\\(LqPOSIX.1\\(Rq)")
-LINE("-iso9945-1-96",	"ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
-LINE("-iso9945-2-93",	"ISO/IEC 9945-2:1993 (\\(LqPOSIX.2\\(Rq)")
-LINE("-ansiC",		"ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
-LINE("-ansiC-89",	"ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
-LINE("-ieee754",	"IEEE Std 754-1985")
-LINE("-iso8802-3",	"ISO 8802-3: 1989")
-LINE("-iso8601",	"ISO 8601")
-LINE("-ieee1275-94",	"IEEE Std 1275-1994 (\\(LqOpen Firmware\\(Rq)")
-LINE("-xpg3",		"X/Open Portability Guide Issue\\~3 (\\(LqXPG3\\(Rq)")
-LINE("-xpg4",		"X/Open Portability Guide Issue\\~4 (\\(LqXPG4\\(Rq)")
-LINE("-xpg4.2",		"X/Open Portability Guide Issue\\~4, Version\\~2 (\\(LqXPG4.2\\(Rq)")
-LINE("-xbd5",		"X/Open Base Definitions Issue\\~5 (\\(LqXBD5\\(Rq)")
-LINE("-xcu5",		"X/Open Commands and Utilities Issue\\~5 (\\(LqXCU5\\(Rq)")
-LINE("-xsh4.2",		"X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(LqXSH4.2\\(Rq)")
-LINE("-xsh5",		"X/Open System Interfaces and Headers Issue\\~5 (\\(LqXSH5\\(Rq)")
-LINE("-xns5",		"X/Open Networking Services Issue\\~5 (\\(LqXNS5\\(Rq)")
-LINE("-xns5.2",		"X/Open Networking Services Issue\\~5.2 (\\(LqXNS5.2\\(Rq)")
-LINE("-xcurses4.2",	"X/Open Curses Issue\\~4, Version\\~2 (\\(LqXCURSES4.2\\(Rq)")
-LINE("-susv1",		"Version\\~1 of the Single UNIX Specification (\\(LqSUSv1\\(Rq)")
-LINE("-susv2",		"Version\\~2 of the Single UNIX Specification (\\(LqSUSv2\\(Rq)")
-LINE("-susv3",		"Version\\~3 of the Single UNIX Specification (\\(LqSUSv3\\(Rq)")
-LINE("-susv4",		"Version\\~4 of the Single UNIX Specification (\\(LqSUSv4\\(Rq)")
-LINE("-svid4",		"System\\~V Interface Definition, Fourth Edition (\\(LqSVID4\\(Rq)")

Property changes on: head/contrib/mdocml/st.in
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-vasprintf.c
===================================================================
--- head/contrib/mdocml/test-vasprintf.c	(revision 338825)
+++ head/contrib/mdocml/test-vasprintf.c	(nonexistent)
@@ -1,52 +0,0 @@
-/*	$Id: test-vasprintf.c,v 1.4 2016/07/18 18:35:05 schwarze Exp $	*/
-/*
- * Copyright (c) 2015 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.
- */
-
-#if defined(__linux__) || defined(__MINT__)
-#define _GNU_SOURCE /* vasprintf() */
-#endif
-
-#include 
-#include 
-#include 
-
-static int	 testfunc(char **, const char *, ...);
-
-
-static int
-testfunc(char **ret, const char *format, ...)
-{
-	va_list	 ap;
-	int	 irc;
-
-	va_start(ap, format);
-	irc = vasprintf(ret, format, ap);
-	va_end(ap);
-
-	return irc;
-}
-
-int
-main(void)
-{
-	char	*ret;
-
-	if (testfunc(&ret, "%s.", "Text") != 5)
-		return 1;
-	if (strcmp(ret, "Text."))
-		return 2;
-	return 0;
-}

Property changes on: head/contrib/mdocml/test-vasprintf.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mansearch.c
===================================================================
--- head/contrib/mdocml/mansearch.c	(revision 338825)
+++ head/contrib/mdocml/mansearch.c	(nonexistent)
@@ -1,841 +0,0 @@
-/*	$Id: mansearch.c,v 1.76 2017/08/02 13:29:04 schwarze Exp $ */
-/*
- * Copyright (c) 2012 Kristaps Dzonsons 
- * Copyright (c) 2013-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 
-#if HAVE_ERR
-#include 
-#endif
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc.h"
-#include "mandoc_aux.h"
-#include "mandoc_ohash.h"
-#include "manconf.h"
-#include "mansearch.h"
-#include "dbm.h"
-
-struct	expr {
-	/* Used for terms: */
-	struct dbm_match match;   /* Match type and expression. */
-	uint64_t	 bits;    /* Type mask. */
-	/* Used for OR and AND groups: */
-	struct expr	*next;    /* Next child in the parent group. */
-	struct expr	*child;   /* First child in this group. */
-	enum { EXPR_TERM, EXPR_OR, EXPR_AND } type;
-};
-
-const char *const mansearch_keynames[KEY_MAX] = {
-	"arch",	"sec",	"Xr",	"Ar",	"Fa",	"Fl",	"Dv",	"Fn",
-	"Ic",	"Pa",	"Cm",	"Li",	"Em",	"Cd",	"Va",	"Ft",
-	"Tn",	"Er",	"Ev",	"Sy",	"Sh",	"In",	"Ss",	"Ox",
-	"An",	"Mt",	"St",	"Bx",	"At",	"Nx",	"Fx",	"Lk",
-	"Ms",	"Bsx",	"Dx",	"Rs",	"Vt",	"Lb",	"Nm",	"Nd"
-};
-
-
-static	struct ohash	*manmerge(struct expr *, struct ohash *);
-static	struct ohash	*manmerge_term(struct expr *, struct ohash *);
-static	struct ohash	*manmerge_or(struct expr *, struct ohash *);
-static	struct ohash	*manmerge_and(struct expr *, struct ohash *);
-static	char		*buildnames(const struct dbm_page *);
-static	char		*buildoutput(size_t, struct dbm_page *);
-static	size_t		 lstlen(const char *, size_t);
-static	void		 lstcat(char *, size_t *, const char *, const char *);
-static	int		 lstmatch(const char *, const char *);
-static	struct expr	*exprcomp(const struct mansearch *,
-				int, char *[], int *);
-static	struct expr	*expr_and(const struct mansearch *,
-				int, char *[], int *);
-static	struct expr	*exprterm(const struct mansearch *,
-				int, char *[], int *);
-static	void		 exprfree(struct expr *);
-static	int		 manpage_compare(const void *, const void *);
-
-
-int
-mansearch(const struct mansearch *search,
-		const struct manpaths *paths,
-		int argc, char *argv[],
-		struct manpage **res, size_t *sz)
-{
-	char		 buf[PATH_MAX];
-	struct dbm_res	*rp;
-	struct expr	*e;
-	struct dbm_page	*page;
-	struct manpage	*mpage;
-	struct ohash	*htab;
-	size_t		 cur, i, maxres, outkey;
-	unsigned int	 slot;
-	int		 argi, chdir_status, getcwd_status, im;
-
-	argi = 0;
-	if ((e = exprcomp(search, argc, argv, &argi)) == NULL) {
-		*sz = 0;
-		return 0;
-	}
-
-	cur = maxres = 0;
-	if (res != NULL)
-		*res = NULL;
-
-	outkey = KEY_Nd;
-	if (search->outkey != NULL)
-		for (im = 0; im < KEY_MAX; im++)
-			if (0 == strcasecmp(search->outkey,
-			    mansearch_keynames[im])) {
-				outkey = im;
-				break;
-			}
-
-	/*
-	 * Remember the original working directory, if possible.
-	 * This will be needed if the second or a later directory
-	 * is given as a relative path.
-	 * Do not error out if the current directory is not
-	 * searchable: Maybe it won't be needed after all.
-	 */
-
-	if (getcwd(buf, PATH_MAX) == NULL) {
-		getcwd_status = 0;
-		(void)strlcpy(buf, strerror(errno), sizeof(buf));
-	} else
-		getcwd_status = 1;
-
-	/*
-	 * Loop over the directories (containing databases) for us to
-	 * search.
-	 * Don't let missing/bad databases/directories phase us.
-	 * In each, try to open the resident database and, if it opens,
-	 * scan it for our match expression.
-	 */
-
-	chdir_status = 0;
-	for (i = 0; i < paths->sz; i++) {
-		if (chdir_status && paths->paths[i][0] != '/') {
-			if ( ! getcwd_status) {
-				warnx("%s: getcwd: %s", paths->paths[i], buf);
-				continue;
-			} else if (chdir(buf) == -1) {
-				warn("%s", buf);
-				continue;
-			}
-		}
-		if (chdir(paths->paths[i]) == -1) {
-			warn("%s", paths->paths[i]);
-			continue;
-		}
-		chdir_status = 1;
-
-		if (dbm_open(MANDOC_DB) == -1) {
-			if (errno != ENOENT)
-				warn("%s/%s", paths->paths[i], MANDOC_DB);
-			continue;
-		}
-
-		if ((htab = manmerge(e, NULL)) == NULL) {
-			dbm_close();
-			continue;
-		}
-
-		for (rp = ohash_first(htab, &slot); rp != NULL;
-		    rp = ohash_next(htab, &slot)) {
-			page = dbm_page_get(rp->page);
-
-			if (lstmatch(search->sec, page->sect) == 0 ||
-			    lstmatch(search->arch, page->arch) == 0 ||
-			    (search->argmode == ARG_NAME &&
-			     rp->bits <= (int32_t)(NAME_SYN & NAME_MASK)))
-				continue;
-
-			if (res == NULL) {
-				cur = 1;
-				break;
-			}
-			if (cur + 1 > maxres) {
-				maxres += 1024;
-				*res = mandoc_reallocarray(*res,
-				    maxres, sizeof(**res));
-			}
-			mpage = *res + cur;
-			mandoc_asprintf(&mpage->file, "%s/%s",
-			    paths->paths[i], page->file + 1);
-			mpage->names = buildnames(page);
-			mpage->output = buildoutput(outkey, page);
-			mpage->ipath = i;
-			mpage->bits = rp->bits;
-			mpage->sec = *page->sect - '0';
-			if (mpage->sec < 0 || mpage->sec > 9)
-				mpage->sec = 10;
-			mpage->form = *page->file;
-			free(rp);
-			cur++;
-		}
-		ohash_delete(htab);
-		free(htab);
-		dbm_close();
-
-		/*
-		 * In man(1) mode, prefer matches in earlier trees
-		 * over matches in later trees.
-		 */
-
-		if (cur && search->firstmatch)
-			break;
-	}
-	if (res != NULL)
-		qsort(*res, cur, sizeof(struct manpage), manpage_compare);
-	if (chdir_status && getcwd_status && chdir(buf) == -1)
-		warn("%s", buf);
-	exprfree(e);
-	*sz = cur;
-	return res != NULL || cur;
-}
-
-/*
- * Merge the results for the expression tree rooted at e
- * into the the result list htab.
- */
-static struct ohash *
-manmerge(struct expr *e, struct ohash *htab)
-{
-	switch (e->type) {
-	case EXPR_TERM:
-		return manmerge_term(e, htab);
-	case EXPR_OR:
-		return manmerge_or(e->child, htab);
-	case EXPR_AND:
-		return manmerge_and(e->child, htab);
-	default:
-		abort();
-	}
-}
-
-static struct ohash *
-manmerge_term(struct expr *e, struct ohash *htab)
-{
-	struct dbm_res	 res, *rp;
-	uint64_t	 ib;
-	unsigned int	 slot;
-	int		 im;
-
-	if (htab == NULL) {
-		htab = mandoc_malloc(sizeof(*htab));
-		mandoc_ohash_init(htab, 4, offsetof(struct dbm_res, page));
-	}
-
-	for (im = 0, ib = 1; im < KEY_MAX; im++, ib <<= 1) {
-		if ((e->bits & ib) == 0)
-			continue;
-
-		switch (ib) {
-		case TYPE_arch:
-			dbm_page_byarch(&e->match);
-			break;
-		case TYPE_sec:
-			dbm_page_bysect(&e->match);
-			break;
-		case TYPE_Nm:
-			dbm_page_byname(&e->match);
-			break;
-		case TYPE_Nd:
-			dbm_page_bydesc(&e->match);
-			break;
-		default:
-			dbm_page_bymacro(im - 2, &e->match);
-			break;
-		}
-
-		/*
-		 * When hashing for deduplication, use the unique
-		 * page ID itself instead of a hash function;
-		 * that is quite efficient.
-		 */
-
-		for (;;) {
-			res = dbm_page_next();
-			if (res.page == -1)
-				break;
-			slot = ohash_lookup_memory(htab,
-			    (char *)&res, sizeof(res.page), res.page);
-			if ((rp = ohash_find(htab, slot)) != NULL) {
-				rp->bits |= res.bits;
-				continue;
-			}
-			rp = mandoc_malloc(sizeof(*rp));
-			*rp = res;
-			ohash_insert(htab, slot, rp);
-		}
-	}
-	return htab;
-}
-
-static struct ohash *
-manmerge_or(struct expr *e, struct ohash *htab)
-{
-	while (e != NULL) {
-		htab = manmerge(e, htab);
-		e = e->next;
-	}
-	return htab;
-}
-
-static struct ohash *
-manmerge_and(struct expr *e, struct ohash *htab)
-{
-	struct ohash	*hand, *h1, *h2;
-	struct dbm_res	*res;
-	unsigned int	 slot1, slot2;
-
-	/* Evaluate the first term of the AND clause. */
-
-	hand = manmerge(e, NULL);
-
-	while ((e = e->next) != NULL) {
-
-		/* Evaluate the next term and prepare for ANDing. */
-
-		h2 = manmerge(e, NULL);
-		if (ohash_entries(h2) < ohash_entries(hand)) {
-			h1 = h2;
-			h2 = hand;
-		} else
-			h1 = hand;
-		hand = mandoc_malloc(sizeof(*hand));
-		mandoc_ohash_init(hand, 4, offsetof(struct dbm_res, page));
-
-		/* Keep all pages that are in both result sets. */
-
-		for (res = ohash_first(h1, &slot1); res != NULL;
-		    res = ohash_next(h1, &slot1)) {
-			if (ohash_find(h2, ohash_lookup_memory(h2,
-			    (char *)res, sizeof(res->page),
-			    res->page)) == NULL)
-				free(res);
-			else
-				ohash_insert(hand, ohash_lookup_memory(hand,
-				    (char *)res, sizeof(res->page),
-				    res->page), res);
-		}
-
-		/* Discard the merged results. */
-
-		for (res = ohash_first(h2, &slot2); res != NULL;
-		    res = ohash_next(h2, &slot2))
-			free(res);
-		ohash_delete(h2);
-		free(h2);
-		ohash_delete(h1);
-		free(h1);
-	}
-
-	/* Merge the result of the AND into htab. */
-
-	if (htab == NULL)
-		return hand;
-
-	for (res = ohash_first(hand, &slot1); res != NULL;
-	    res = ohash_next(hand, &slot1)) {
-		slot2 = ohash_lookup_memory(htab,
-		    (char *)res, sizeof(res->page), res->page);
-		if (ohash_find(htab, slot2) == NULL)
-			ohash_insert(htab, slot2, res);
-		else
-			free(res);
-	}
-
-	/* Discard the merged result. */
-
-	ohash_delete(hand);
-	free(hand);
-	return htab;
-}
-
-void
-mansearch_free(struct manpage *res, size_t sz)
-{
-	size_t	 i;
-
-	for (i = 0; i < sz; i++) {
-		free(res[i].file);
-		free(res[i].names);
-		free(res[i].output);
-	}
-	free(res);
-}
-
-static int
-manpage_compare(const void *vp1, const void *vp2)
-{
-	const struct manpage	*mp1, *mp2;
-	const char		*cp1, *cp2;
-	size_t			 sz1, sz2;
-	int			 diff;
-
-	mp1 = vp1;
-	mp2 = vp2;
-	if ((diff = mp2->bits - mp1->bits) ||
-	    (diff = mp1->sec - mp2->sec))
-		return diff;
-
-	/* Fall back to alphabetic ordering of names. */
-	sz1 = strcspn(mp1->names, "(");
-	sz2 = strcspn(mp2->names, "(");
-	if (sz1 < sz2)
-		sz1 = sz2;
-	if ((diff = strncasecmp(mp1->names, mp2->names, sz1)))
-		return diff;
-
-	/* For identical names and sections, prefer arch-dependent. */
-	cp1 = strchr(mp1->names + sz1, '/');
-	cp2 = strchr(mp2->names + sz2, '/');
-	return cp1 != NULL && cp2 != NULL ? strcasecmp(cp1, cp2) :
-	    cp1 != NULL ? -1 : cp2 != NULL ? 1 : 0;
-}
-
-static char *
-buildnames(const struct dbm_page *page)
-{
-	char	*buf;
-	size_t	 i, sz;
-
-	sz = lstlen(page->name, 2) + 1 + lstlen(page->sect, 2) +
-	    (page->arch == NULL ? 0 : 1 + lstlen(page->arch, 2)) + 2;
-	buf = mandoc_malloc(sz);
-	i = 0;
-	lstcat(buf, &i, page->name, ", ");
-	buf[i++] = '(';
-	lstcat(buf, &i, page->sect, ", ");
-	if (page->arch != NULL) {
-		buf[i++] = '/';
-		lstcat(buf, &i, page->arch, ", ");
-	}
-	buf[i++] = ')';
-	buf[i++] = '\0';
-	assert(i == sz);
-	return buf;
-}
-
-/*
- * Count the buffer space needed to print the NUL-terminated
- * list of NUL-terminated strings, when printing sep separator
- * characters between strings.
- */
-static size_t
-lstlen(const char *cp, size_t sep)
-{
-	size_t	 sz;
-
-	for (sz = 0; *cp != '\0'; cp++) {
-
-		/* Skip names appearing only in the SYNOPSIS. */
-		if (*cp <= (char)(NAME_SYN & NAME_MASK)) {
-			while (*cp != '\0')
-				cp++;
-			continue;
-		}
-
-		/* Skip name class markers. */
-		if (*cp < ' ')
-			cp++;
-
-		/* Print a separator before each but the first string. */
-		if (sz)
-			sz += sep;
-
-		/* Copy one string. */
-		while (*cp != '\0') {
-			sz++;
-			cp++;
-		}
-	}
-	return sz;
-}
-
-/*
- * Print the NUL-terminated list of NUL-terminated strings
- * into the buffer, seperating strings with sep.
- */
-static void
-lstcat(char *buf, size_t *i, const char *cp, const char *sep)
-{
-	const char	*s;
-	size_t		 i_start;
-
-	for (i_start = *i; *cp != '\0'; cp++) {
-
-		/* Skip names appearing only in the SYNOPSIS. */
-		if (*cp <= (char)(NAME_SYN & NAME_MASK)) {
-			while (*cp != '\0')
-				cp++;
-			continue;
-		}
-
-		/* Skip name class markers. */
-		if (*cp < ' ')
-			cp++;
-
-		/* Print a separator before each but the first string. */
-		if (*i > i_start) {
-			s = sep;
-			while (*s != '\0')
-				buf[(*i)++] = *s++;
-		}
-
-		/* Copy one string. */
-		while (*cp != '\0')
-			buf[(*i)++] = *cp++;
-	}
-
-}
-
-/*
- * Return 1 if the string *want occurs in any of the strings
- * in the NUL-terminated string list *have, or 0 otherwise.
- * If either argument is NULL or empty, assume no filtering
- * is desired and return 1.
- */
-static int
-lstmatch(const char *want, const char *have)
-{
-        if (want == NULL || have == NULL || *have == '\0')
-                return 1;
-        while (*have != '\0') {
-                if (strcasestr(have, want) != NULL)
-                        return 1;
-                have = strchr(have, '\0') + 1;
-        }
-        return 0;
-}
-
-/*
- * Build a list of values taken by the macro im in the manual page.
- */
-static char *
-buildoutput(size_t im, struct dbm_page *page)
-{
-	const char	*oldoutput, *sep, *input;
-	char		*output, *newoutput, *value;
-	size_t		 sz, i;
-
-	switch (im) {
-	case KEY_Nd:
-		return mandoc_strdup(page->desc);
-	case KEY_Nm:
-		input = page->name;
-		break;
-	case KEY_sec:
-		input = page->sect;
-		break;
-	case KEY_arch:
-		input = page->arch;
-		if (input == NULL)
-			input = "all\0";
-		break;
-	default:
-		input = NULL;
-		break;
-	}
-
-	if (input != NULL) {
-		sz = lstlen(input, 3) + 1;
-		output = mandoc_malloc(sz);
-		i = 0;
-		lstcat(output, &i, input, " # ");
-		output[i++] = '\0';
-		assert(i == sz);
-		return output;
-	}
-
-	output = NULL;
-	dbm_macro_bypage(im - 2, page->addr);
-	while ((value = dbm_macro_next()) != NULL) {
-		if (output == NULL) {
-			oldoutput = "";
-			sep = "";
-		} else {
-			oldoutput = output;
-			sep = " # ";
-		}
-		mandoc_asprintf(&newoutput, "%s%s%s", oldoutput, sep, value);
-		free(output);
-		output = newoutput;
-	}
-	return output;
-}
-
-/*
- * Compile a set of string tokens into an expression.
- * Tokens in "argv" are assumed to be individual expression atoms (e.g.,
- * "(", "foo=bar", etc.).
- */
-static struct expr *
-exprcomp(const struct mansearch *search, int argc, char *argv[], int *argi)
-{
-	struct expr	*parent, *child;
-	int		 needterm, nested;
-
-	if ((nested = *argi) == argc)
-		return NULL;
-	needterm = 1;
-	parent = child = NULL;
-	while (*argi < argc) {
-		if (strcmp(")", argv[*argi]) == 0) {
-			if (needterm)
-				warnx("missing term "
-				    "before closing parenthesis");
-			needterm = 0;
-			if (nested)
-				break;
-			warnx("ignoring unmatched right parenthesis");
-			++*argi;
-			continue;
-		}
-		if (strcmp("-o", argv[*argi]) == 0) {
-			if (needterm) {
-				if (*argi > 0)
-					warnx("ignoring -o after %s",
-					    argv[*argi - 1]);
-				else
-					warnx("ignoring initial -o");
-			}
-			needterm = 1;
-			++*argi;
-			continue;
-		}
-		needterm = 0;
-		if (child == NULL) {
-			child = expr_and(search, argc, argv, argi);
-			continue;
-		}
-		if (parent == NULL) {
-			parent = mandoc_calloc(1, sizeof(*parent));
-			parent->type = EXPR_OR;
-			parent->next = NULL;
-			parent->child = child;
-		}
-		child->next = expr_and(search, argc, argv, argi);
-		child = child->next;
-	}
-	if (needterm && *argi)
-		warnx("ignoring trailing %s", argv[*argi - 1]);
-	return parent == NULL ? child : parent;
-}
-
-static struct expr *
-expr_and(const struct mansearch *search, int argc, char *argv[], int *argi)
-{
-	struct expr	*parent, *child;
-	int		 needterm;
-
-	needterm = 1;
-	parent = child = NULL;
-	while (*argi < argc) {
-		if (strcmp(")", argv[*argi]) == 0) {
-			if (needterm)
-				warnx("missing term "
-				    "before closing parenthesis");
-			needterm = 0;
-			break;
-		}
-		if (strcmp("-o", argv[*argi]) == 0)
-			break;
-		if (strcmp("-a", argv[*argi]) == 0) {
-			if (needterm) {
-				if (*argi > 0)
-					warnx("ignoring -a after %s",
-					    argv[*argi - 1]);
-				else
-					warnx("ignoring initial -a");
-			}
-			needterm = 1;
-			++*argi;
-			continue;
-		}
-		if (needterm == 0)
-			break;
-		if (child == NULL) {
-			child = exprterm(search, argc, argv, argi);
-			if (child != NULL)
-				needterm = 0;
-			continue;
-		}
-		needterm = 0;
-		if (parent == NULL) {
-			parent = mandoc_calloc(1, sizeof(*parent));
-			parent->type = EXPR_AND;
-			parent->next = NULL;
-			parent->child = child;
-		}
-		child->next = exprterm(search, argc, argv, argi);
-		if (child->next != NULL) {
-			child = child->next;
-			needterm = 0;
-		}
-	}
-	if (needterm && *argi)
-		warnx("ignoring trailing %s", argv[*argi - 1]);
-	return parent == NULL ? child : parent;
-}
-
-static struct expr *
-exprterm(const struct mansearch *search, int argc, char *argv[], int *argi)
-{
-	char		 errbuf[BUFSIZ];
-	struct expr	*e;
-	char		*key, *val;
-	uint64_t	 iterbit;
-	int		 cs, i, irc;
-
-	if (strcmp("(", argv[*argi]) == 0) {
-		++*argi;
-		e = exprcomp(search, argc, argv, argi);
-		if (*argi < argc) {
-			assert(strcmp(")", argv[*argi]) == 0);
-			++*argi;
-		} else
-			warnx("unclosed parenthesis");
-		return e;
-	}
-
-	if (strcmp("-i", argv[*argi]) == 0 && *argi + 1 < argc) {
-		cs = 0;
-		++*argi;
-	} else
-		cs = 1;
-
-	e = mandoc_calloc(1, sizeof(*e));
-	e->type = EXPR_TERM;
-	e->bits = 0;
-	e->next = NULL;
-	e->child = NULL;
-
-	if (search->argmode == ARG_NAME) {
-		e->bits = TYPE_Nm;
-		e->match.type = DBM_EXACT;
-		e->match.str = argv[(*argi)++];
-		return e;
-	}
-
-	/*
-	 * Separate macro keys from search string.
-	 * If needed, request regular expression handling.
-	 */
-
-	if (search->argmode == ARG_WORD) {
-		e->bits = TYPE_Nm;
-		e->match.type = DBM_REGEX;
-#if HAVE_REWB_BSD
-		mandoc_asprintf(&val, "[[:<:]]%s[[:>:]]", argv[*argi]);
-#elif HAVE_REWB_SYSV
-		mandoc_asprintf(&val, "\\<%s\\>", argv[*argi]);
-#else
-		mandoc_asprintf(&val,
-		    "(^|[^a-zA-Z01-9_])%s([^a-zA-Z01-9_]|$)", argv[*argi]);
-#endif
-		cs = 0;
-	} else if ((val = strpbrk(argv[*argi], "=~")) == NULL) {
-		e->bits = TYPE_Nm | TYPE_Nd;
-		e->match.type = DBM_SUB;
-		e->match.str = argv[*argi];
-	} else {
-		if (val == argv[*argi])
-			e->bits = TYPE_Nm | TYPE_Nd;
-		if (*val == '=') {
-			e->match.type = DBM_SUB;
-			e->match.str = val + 1;
-		} else
-			e->match.type = DBM_REGEX;
-		*val++ = '\0';
-		if (strstr(argv[*argi], "arch") != NULL)
-			cs = 0;
-	}
-
-	/* Compile regular expressions. */
-
-	if (e->match.type == DBM_REGEX) {
-		e->match.re = mandoc_malloc(sizeof(*e->match.re));
-		irc = regcomp(e->match.re, val,
-		    REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE));
-		if (irc) {
-			regerror(irc, e->match.re, errbuf, sizeof(errbuf));
-			warnx("regcomp /%s/: %s", val, errbuf);
-		}
-		if (search->argmode == ARG_WORD)
-			free(val);
-		if (irc) {
-			free(e->match.re);
-			free(e);
-			++*argi;
-			return NULL;
-		}
-	}
-
-	if (e->bits) {
-		++*argi;
-		return e;
-	}
-
-	/*
-	 * Parse out all possible fields.
-	 * If the field doesn't resolve, bail.
-	 */
-
-	while (NULL != (key = strsep(&argv[*argi], ","))) {
-		if ('\0' == *key)
-			continue;
-		for (i = 0, iterbit = 1; i < KEY_MAX; i++, iterbit <<= 1) {
-			if (0 == strcasecmp(key, mansearch_keynames[i])) {
-				e->bits |= iterbit;
-				break;
-			}
-		}
-		if (i == KEY_MAX) {
-			if (strcasecmp(key, "any"))
-				warnx("treating unknown key "
-				    "\"%s\" as \"any\"", key);
-			e->bits |= ~0ULL;
-		}
-	}
-
-	++*argi;
-	return e;
-}
-
-static void
-exprfree(struct expr *e)
-{
-	if (e->next != NULL)
-		exprfree(e->next);
-	if (e->child != NULL)
-		exprfree(e->child);
-	free(e);
-}

Property changes on: head/contrib/mdocml/mansearch.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mdoc_macro.c
===================================================================
--- head/contrib/mdocml/mdoc_macro.c	(revision 338825)
+++ head/contrib/mdocml/mdoc_macro.c	(nonexistent)
@@ -1,1505 +0,0 @@
-/*	$Id: mdoc_macro.c,v 1.224 2017/05/30 16:22:03 schwarze Exp $ */
-/*
- * Copyright (c) 2008-2012 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 "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "libmandoc.h"
-#include "roff_int.h"
-#include "libmdoc.h"
-
-static	void		blk_full(MACRO_PROT_ARGS);
-static	void		blk_exp_close(MACRO_PROT_ARGS);
-static	void		blk_part_exp(MACRO_PROT_ARGS);
-static	void		blk_part_imp(MACRO_PROT_ARGS);
-static	void		ctx_synopsis(MACRO_PROT_ARGS);
-static	void		in_line_eoln(MACRO_PROT_ARGS);
-static	void		in_line_argn(MACRO_PROT_ARGS);
-static	void		in_line(MACRO_PROT_ARGS);
-static	void		phrase_ta(MACRO_PROT_ARGS);
-
-static	void		append_delims(struct roff_man *, int, int *, char *);
-static	void		dword(struct roff_man *, int, int, const char *,
-				enum mdelim, int);
-static	int		find_pending(struct roff_man *, enum roff_tok,
-				int, int, struct roff_node *);
-static	int		lookup(struct roff_man *, int, int, int, const char *);
-static	int		macro_or_word(MACRO_PROT_ARGS, int);
-static	void		break_intermediate(struct roff_node *,
-				struct roff_node *);
-static	int		parse_rest(struct roff_man *, enum roff_tok,
-				int, int *, char *);
-static	enum roff_tok	rew_alt(enum roff_tok);
-static	void		rew_elem(struct roff_man *, enum roff_tok);
-static	void		rew_last(struct roff_man *, const struct roff_node *);
-static	void		rew_pending(struct roff_man *,
-				const struct roff_node *);
-
-const	struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = {
-	{ in_line_eoln, MDOC_PROLOGUE }, /* Dd */
-	{ in_line_eoln, MDOC_PROLOGUE }, /* Dt */
-	{ in_line_eoln, MDOC_PROLOGUE }, /* Os */
-	{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* Sh */
-	{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* Ss */
-	{ in_line_eoln, 0 }, /* Pp */
-	{ blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* D1 */
-	{ blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* Dl */
-	{ blk_full, MDOC_EXPLICIT }, /* Bd */
-	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ed */
-	{ blk_full, MDOC_EXPLICIT }, /* Bl */
-	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* El */
-	{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_IGNDELIM | MDOC_JOIN }, /* Ap */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
-	{ in_line_eoln, 0 }, /* Ex */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
-	{ in_line_eoln, 0 }, /* Fd */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ic */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Li */
-	{ blk_full, MDOC_JOIN }, /* Nd */
-	{ ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ot */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
-	{ in_line_eoln, 0 }, /* Rv */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
-	{ ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
-	{ in_line_eoln, MDOC_JOIN }, /* %A */
-	{ in_line_eoln, MDOC_JOIN }, /* %B */
-	{ in_line_eoln, MDOC_JOIN }, /* %D */
-	{ in_line_eoln, MDOC_JOIN }, /* %I */
-	{ in_line_eoln, MDOC_JOIN }, /* %J */
-	{ in_line_eoln, 0 }, /* %N */
-	{ in_line_eoln, MDOC_JOIN }, /* %O */
-	{ in_line_eoln, 0 }, /* %P */
-	{ in_line_eoln, MDOC_JOIN }, /* %R */
-	{ in_line_eoln, MDOC_JOIN }, /* %T */
-	{ in_line_eoln, 0 }, /* %V */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Ac */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_EXPLICIT | MDOC_JOIN }, /* Ao */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Aq */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Bc */
-	{ blk_full, MDOC_EXPLICIT }, /* Bf */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_EXPLICIT | MDOC_JOIN }, /* Bo */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Bq */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
-	{ in_line_eoln, 0 }, /* Db */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Dc */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_EXPLICIT | MDOC_JOIN }, /* Do */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Dq */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ec */
-	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ef */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Em */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* No */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Pc */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_EXPLICIT | MDOC_JOIN }, /* Po */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Pq */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Qc */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ql */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_EXPLICIT | MDOC_JOIN }, /* Qo */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Qq */
-	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Re */
-	{ blk_full, MDOC_EXPLICIT }, /* Rs */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Sc */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_EXPLICIT | MDOC_JOIN }, /* So */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */
-	{ in_line_argn, 0 }, /* Sm */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ux */
-	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
-	{ blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Fc */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_EXPLICIT | MDOC_JOIN }, /* Oo */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Oc */
-	{ blk_full, MDOC_EXPLICIT }, /* Bk */
-	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */
-	{ in_line_eoln, 0 }, /* Bt */
-	{ in_line_eoln, 0 }, /* Hf */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fr */
-	{ in_line_eoln, 0 }, /* Ud */
-	{ in_line, 0 }, /* Lb */
-	{ in_line_eoln, 0 }, /* Lp */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
-	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Brq */
-	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
-			MDOC_EXPLICIT | MDOC_JOIN }, /* Bro */
-	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
-			 MDOC_EXPLICIT | MDOC_JOIN }, /* Brc */
-	{ in_line_eoln, MDOC_JOIN }, /* %C */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Es */
-	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* En */
-	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
-	{ in_line_eoln, MDOC_JOIN }, /* %Q */
-	{ in_line_eoln, 0 }, /* %U */
-	{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
-};
-const	struct mdoc_macro *const mdoc_macros = __mdoc_macros - MDOC_Dd;
-
-
-/*
- * This is called at the end of parsing.  It must traverse up the tree,
- * closing out open [implicit] scopes.  Obviously, open explicit scopes
- * are errors.
- */
-void
-mdoc_endparse(struct roff_man *mdoc)
-{
-	struct roff_node *n;
-
-	/* Scan for open explicit scopes. */
-
-	n = mdoc->last->flags & NODE_VALID ?
-	    mdoc->last->parent : mdoc->last;
-
-	for ( ; n; n = n->parent)
-		if (n->type == ROFFT_BLOCK &&
-		    mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
-			mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
-			    n->line, n->pos, roff_name[n->tok]);
-
-	/* Rewind to the first. */
-
-	rew_last(mdoc, mdoc->first);
-	mdoc_state_reset(mdoc);
-}
-
-/*
- * Look up the macro at *p called by "from",
- * or as a line macro if from == TOKEN_NONE.
- */
-static int
-lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p)
-{
-	enum roff_tok	 res;
-
-	if (mdoc->flags & MDOC_PHRASEQF) {
-		mdoc->flags &= ~MDOC_PHRASEQF;
-		return TOKEN_NONE;
-	}
-	if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) {
-		res = roffhash_find(mdoc->mdocmac, p, 0);
-		if (res != TOKEN_NONE) {
-			if (mdoc_macros[res].flags & MDOC_CALLABLE)
-				return res;
-			mandoc_msg(MANDOCERR_MACRO_CALL,
-			    mdoc->parse, line, ppos, p);
-		}
-	}
-	return TOKEN_NONE;
-}
-
-/*
- * Rewind up to and including a specific node.
- */
-static void
-rew_last(struct roff_man *mdoc, const struct roff_node *to)
-{
-
-	if (to->flags & NODE_VALID)
-		return;
-
-	while (mdoc->last != to) {
-		mdoc_state(mdoc, mdoc->last);
-		mdoc->last->flags |= NODE_VALID | NODE_ENDED;
-		mdoc->last = mdoc->last->parent;
-	}
-	mdoc_state(mdoc, mdoc->last);
-	mdoc->last->flags |= NODE_VALID | NODE_ENDED;
-	mdoc->next = ROFF_NEXT_SIBLING;
-}
-
-/*
- * Rewind up to a specific block, including all blocks that broke it.
- */
-static void
-rew_pending(struct roff_man *mdoc, const struct roff_node *n)
-{
-
-	for (;;) {
-		rew_last(mdoc, n);
-
-		if (mdoc->last == n) {
-			switch (n->type) {
-			case ROFFT_HEAD:
-				roff_body_alloc(mdoc, n->line, n->pos,
-				    n->tok);
-				break;
-			case ROFFT_BLOCK:
-				break;
-			default:
-				return;
-			}
-			if ( ! (n->flags & NODE_BROKEN))
-				return;
-		} else
-			n = mdoc->last;
-
-		for (;;) {
-			if ((n = n->parent) == NULL)
-				return;
-
-			if (n->type == ROFFT_BLOCK ||
-			    n->type == ROFFT_HEAD) {
-				if (n->flags & NODE_ENDED)
-					break;
-				else
-					return;
-			}
-		}
-	}
-}
-
-/*
- * For a block closing macro, return the corresponding opening one.
- * Otherwise, return the macro itself.
- */
-static enum roff_tok
-rew_alt(enum roff_tok tok)
-{
-	switch (tok) {
-	case MDOC_Ac:
-		return MDOC_Ao;
-	case MDOC_Bc:
-		return MDOC_Bo;
-	case MDOC_Brc:
-		return MDOC_Bro;
-	case MDOC_Dc:
-		return MDOC_Do;
-	case MDOC_Ec:
-		return MDOC_Eo;
-	case MDOC_Ed:
-		return MDOC_Bd;
-	case MDOC_Ef:
-		return MDOC_Bf;
-	case MDOC_Ek:
-		return MDOC_Bk;
-	case MDOC_El:
-		return MDOC_Bl;
-	case MDOC_Fc:
-		return MDOC_Fo;
-	case MDOC_Oc:
-		return MDOC_Oo;
-	case MDOC_Pc:
-		return MDOC_Po;
-	case MDOC_Qc:
-		return MDOC_Qo;
-	case MDOC_Re:
-		return MDOC_Rs;
-	case MDOC_Sc:
-		return MDOC_So;
-	case MDOC_Xc:
-		return MDOC_Xo;
-	default:
-		return tok;
-	}
-}
-
-static void
-rew_elem(struct roff_man *mdoc, enum roff_tok tok)
-{
-	struct roff_node *n;
-
-	n = mdoc->last;
-	if (n->type != ROFFT_ELEM)
-		n = n->parent;
-	assert(n->type == ROFFT_ELEM);
-	assert(tok == n->tok);
-	rew_last(mdoc, n);
-}
-
-static void
-break_intermediate(struct roff_node *n, struct roff_node *breaker)
-{
-	if (n != breaker &&
-	    n->type != ROFFT_BLOCK && n->type != ROFFT_HEAD &&
-	    (n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
-		n = n->parent;
-	while (n != breaker) {
-		if ( ! (n->flags & NODE_VALID))
-			n->flags |= NODE_BROKEN;
-		n = n->parent;
-	}
-}
-
-/*
- * If there is an open sub-block of the target requiring
- * explicit close-out, postpone closing out the target until
- * the rew_pending() call closing out the sub-block.
- */
-static int
-find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos,
-	struct roff_node *target)
-{
-	struct roff_node	*n;
-	int			 irc;
-
-	if (target->flags & NODE_VALID)
-		return 0;
-
-	irc = 0;
-	for (n = mdoc->last; n != NULL && n != target; n = n->parent) {
-		if (n->flags & NODE_ENDED)
-			continue;
-		if (n->type == ROFFT_BLOCK &&
-		    mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
-			irc = 1;
-			break_intermediate(mdoc->last, target);
-			if (target->type == ROFFT_HEAD)
-				target->flags |= NODE_ENDED;
-			else if ( ! (target->flags & NODE_ENDED)) {
-				mandoc_vmsg(MANDOCERR_BLK_NEST,
-				    mdoc->parse, line, ppos,
-				    "%s breaks %s", roff_name[tok],
-				    roff_name[n->tok]);
-				mdoc_endbody_alloc(mdoc, line, ppos,
-				    tok, target);
-			}
-		}
-	}
-	return irc;
-}
-
-/*
- * Allocate a word and check whether it's punctuation or not.
- * Punctuation consists of those tokens found in mdoc_isdelim().
- */
-static void
-dword(struct roff_man *mdoc, int line, int col, const char *p,
-		enum mdelim d, int may_append)
-{
-
-	if (d == DELIM_MAX)
-		d = mdoc_isdelim(p);
-
-	if (may_append &&
-	    ! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) &&
-	    d == DELIM_NONE && mdoc->last->type == ROFFT_TEXT &&
-	    mdoc_isdelim(mdoc->last->string) == DELIM_NONE) {
-		roff_word_append(mdoc, p);
-		return;
-	}
-
-	roff_word_alloc(mdoc, line, col, p);
-
-	/*
-	 * If the word consists of a bare delimiter,
-	 * flag the new node accordingly,
-	 * unless doing so was vetoed by the invoking macro.
-	 * Always clear the veto, it is only valid for one word.
-	 */
-
-	if (d == DELIM_OPEN)
-		mdoc->last->flags |= NODE_DELIMO;
-	else if (d == DELIM_CLOSE &&
-	    ! (mdoc->flags & MDOC_NODELIMC) &&
-	    mdoc->last->parent->tok != MDOC_Fd)
-		mdoc->last->flags |= NODE_DELIMC;
-	mdoc->flags &= ~MDOC_NODELIMC;
-}
-
-static void
-append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
-{
-	char		*p;
-	int		 la;
-
-	if (buf[*pos] == '\0')
-		return;
-
-	for (;;) {
-		la = *pos;
-		if (mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p) ==
-		    ARGS_EOLN)
-			break;
-		dword(mdoc, line, la, p, DELIM_MAX, 1);
-
-		/*
-		 * If we encounter end-of-sentence symbols, then trigger
-		 * the double-space.
-		 *
-		 * XXX: it's easy to allow this to propagate outward to
-		 * the last symbol, such that `. )' will cause the
-		 * correct double-spacing.  However, (1) groff isn't
-		 * smart enough to do this and (2) it would require
-		 * knowing which symbols break this behaviour, for
-		 * example, `.  ;' shouldn't propagate the double-space.
-		 */
-
-		if (mandoc_eos(p, strlen(p)))
-			mdoc->last->flags |= NODE_EOS;
-	}
-}
-
-/*
- * Parse one word.
- * If it is a macro, call it and return 1.
- * Otherwise, allocate it and return 0.
- */
-static int
-macro_or_word(MACRO_PROT_ARGS, int parsed)
-{
-	char		*p;
-	int		 ntok;
-
-	p = buf + ppos;
-	ntok = TOKEN_NONE;
-	if (*p == '"')
-		p++;
-	else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
-		ntok = lookup(mdoc, tok, line, ppos, p);
-
-	if (ntok == TOKEN_NONE) {
-		dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE ||
-		    mdoc_macros[tok].flags & MDOC_JOIN);
-		return 0;
-	} else {
-		if (tok != TOKEN_NONE &&
-		    mdoc_macros[tok].fp == in_line_eoln)
-			rew_elem(mdoc, tok);
-		mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
-		if (tok == TOKEN_NONE)
-			append_delims(mdoc, line, pos, buf);
-		return 1;
-	}
-}
-
-/*
- * Close out block partial/full explicit.
- */
-static void
-blk_exp_close(MACRO_PROT_ARGS)
-{
-	struct roff_node *body;		/* Our own body. */
-	struct roff_node *endbody;	/* Our own end marker. */
-	struct roff_node *itblk;	/* An It block starting later. */
-	struct roff_node *later;	/* A sub-block starting later. */
-	struct roff_node *n;		/* Search back to our block. */
-	struct roff_node *target;	/* For find_pending(). */
-
-	int		 j, lastarg, maxargs, nl, pending;
-	enum margserr	 ac;
-	enum roff_tok	 atok, ntok;
-	char		*p;
-
-	nl = MDOC_NEWLINE & mdoc->flags;
-
-	switch (tok) {
-	case MDOC_Ec:
-		maxargs = 1;
-		break;
-	case MDOC_Ek:
-		mdoc->flags &= ~MDOC_KEEP;
-		/* FALLTHROUGH */
-	default:
-		maxargs = 0;
-		break;
-	}
-
-	/* Search backwards for the beginning of our own body. */
-
-	atok = rew_alt(tok);
-	body = NULL;
-	for (n = mdoc->last; n; n = n->parent) {
-		if (n->flags & NODE_ENDED || n->tok != atok ||
-		    n->type != ROFFT_BODY || n->end != ENDBODY_NOT)
-			continue;
-		body = n;
-		break;
-	}
-
-	/*
-	 * Search backwards for beginnings of blocks,
-	 * both of our own and of pending sub-blocks.
-	 */
-
-	endbody = itblk = later = NULL;
-	for (n = mdoc->last; n; n = n->parent) {
-		if (n->flags & NODE_ENDED)
-			continue;
-
-		/*
-		 * Mismatching end macros can never break anything
-		 * and we only care about the breaking of BLOCKs.
-		 */
-
-		if (body == NULL || n->type != ROFFT_BLOCK)
-			continue;
-
-		/*
-		 * SYNOPSIS name blocks can not be broken themselves,
-		 * but they do get broken together with a broken child.
-		 */
-
-		if (n->tok == MDOC_Nm) {
-			if (later != NULL)
-				n->flags |= NODE_BROKEN | NODE_ENDED;
-			continue;
-		}
-
-		if (n->tok == MDOC_It) {
-			itblk = n;
-			continue;
-		}
-
-		if (atok == n->tok) {
-
-			/*
-			 * Found the start of our own block.
-			 * When there is no pending sub block,
-			 * just proceed to closing out.
-			 */
-
-			if (later == NULL ||
-			    (tok == MDOC_El && itblk == NULL))
-				break;
-
-			/*
-			 * When there is a pending sub block, postpone
-			 * closing out the current block until the
-			 * rew_pending() closing out the sub-block.
-			 * Mark the place where the formatting - but not
-			 * the scope - of the current block ends.
-			 */
-
-			mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse,
-			    line, ppos, "%s breaks %s",
-			    roff_name[atok], roff_name[later->tok]);
-
-			endbody = mdoc_endbody_alloc(mdoc, line, ppos,
-			    atok, body);
-
-			if (tok == MDOC_El)
-				itblk->flags |= NODE_ENDED | NODE_BROKEN;
-
-			/*
-			 * If a block closing macro taking arguments
-			 * breaks another block, put the arguments
-			 * into the end marker.
-			 */
-
-			if (maxargs)
-				mdoc->next = ROFF_NEXT_CHILD;
-			break;
-		}
-
-		/*
-		 * Explicit blocks close out description lines, but
-		 * even those can get broken together with a child.
-		 */
-
-		if (n->tok == MDOC_Nd) {
-			if (later != NULL)
-				n->flags |= NODE_BROKEN | NODE_ENDED;
-			else
-				rew_last(mdoc, n);
-			continue;
-		}
-
-		/* Breaking an open sub block. */
-
-		break_intermediate(mdoc->last, body);
-		n->flags |= NODE_BROKEN;
-		if (later == NULL)
-			later = n;
-	}
-
-	if (body == NULL) {
-		mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
-		    line, ppos, roff_name[tok]);
-		if (maxargs && endbody == NULL) {
-			/*
-			 * Stray .Ec without previous .Eo:
-			 * Break the output line, keep the arguments.
-			 */
-			roff_elem_alloc(mdoc, line, ppos, ROFF_br);
-			rew_elem(mdoc, ROFF_br);
-		}
-	} else if (endbody == NULL) {
-		rew_last(mdoc, body);
-		if (maxargs)
-			mdoc_tail_alloc(mdoc, line, ppos, atok);
-	}
-
-	if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
-		if (buf[*pos] != '\0')
-			mandoc_vmsg(MANDOCERR_ARG_SKIP,
-			    mdoc->parse, line, ppos,
-			    "%s %s", roff_name[tok],
-			    buf + *pos);
-		if (endbody == NULL && n != NULL)
-			rew_pending(mdoc, n);
-		return;
-	}
-
-	if (endbody != NULL)
-		n = endbody;
-
-	ntok = TOKEN_NONE;
-	for (j = 0; ; j++) {
-		lastarg = *pos;
-
-		if (j == maxargs && n != NULL)
-			rew_last(mdoc, n);
-
-		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-		if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
-			break;
-
-		ntok = lookup(mdoc, tok, line, lastarg, p);
-
-		if (ntok == TOKEN_NONE) {
-			dword(mdoc, line, lastarg, p, DELIM_MAX,
-			    MDOC_JOIN & mdoc_macros[tok].flags);
-			continue;
-		}
-
-		if (n != NULL)
-			rew_last(mdoc, n);
-		mdoc->flags &= ~MDOC_NEWLINE;
-		mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
-		break;
-	}
-
-	if (n != NULL) {
-		pending = 0;
-		if (ntok != TOKEN_NONE && n->flags & NODE_BROKEN) {
-			target = n;
-			do
-				target = target->parent;
-			while ( ! (target->flags & NODE_ENDED));
-			pending = find_pending(mdoc, ntok, line, ppos, target);
-		}
-		if ( ! pending)
-			rew_pending(mdoc, n);
-	}
-	if (nl)
-		append_delims(mdoc, line, pos, buf);
-}
-
-static void
-in_line(MACRO_PROT_ARGS)
-{
-	int		 la, scope, cnt, firstarg, mayopen, nc, nl;
-	enum roff_tok	 ntok;
-	enum margserr	 ac;
-	enum mdelim	 d;
-	struct mdoc_arg	*arg;
-	char		*p;
-
-	nl = MDOC_NEWLINE & mdoc->flags;
-
-	/*
-	 * Whether we allow ignored elements (those without content,
-	 * usually because of reserved words) to squeak by.
-	 */
-
-	switch (tok) {
-	case MDOC_An:
-	case MDOC_Ar:
-	case MDOC_Fl:
-	case MDOC_Mt:
-	case MDOC_Nm:
-	case MDOC_Pa:
-		nc = 1;
-		break;
-	default:
-		nc = 0;
-		break;
-	}
-
-	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
-	d = DELIM_NONE;
-	firstarg = 1;
-	mayopen = 1;
-	for (cnt = scope = 0;; ) {
-		la = *pos;
-		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
-		/*
-		 * At the end of a macro line,
-		 * opening delimiters do not suppress spacing.
-		 */
-
-		if (ac == ARGS_EOLN) {
-			if (d == DELIM_OPEN)
-				mdoc->last->flags &= ~NODE_DELIMO;
-			break;
-		}
-
-		/*
-		 * The rest of the macro line is only punctuation,
-		 * to be handled by append_delims().
-		 * If there were no other arguments,
-		 * do not allow the first one to suppress spacing,
-		 * even if it turns out to be a closing one.
-		 */
-
-		if (ac == ARGS_PUNCT) {
-			if (cnt == 0 && (nc == 0 || tok == MDOC_An))
-				mdoc->flags |= MDOC_NODELIMC;
-			break;
-		}
-
-		ntok = (tok == MDOC_Fn && !cnt) ?
-		    TOKEN_NONE : lookup(mdoc, tok, line, la, p);
-
-		/*
-		 * In this case, we've located a submacro and must
-		 * execute it.  Close out scope, if open.  If no
-		 * elements have been generated, either create one (nc)
-		 * or raise a warning.
-		 */
-
-		if (ntok != TOKEN_NONE) {
-			if (scope)
-				rew_elem(mdoc, tok);
-			if (nc && ! cnt) {
-				mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-				rew_last(mdoc, mdoc->last);
-			} else if ( ! nc && ! cnt) {
-				mdoc_argv_free(arg);
-				mandoc_msg(MANDOCERR_MACRO_EMPTY,
-				    mdoc->parse, line, ppos,
-				    roff_name[tok]);
-			}
-			mdoc_macro(mdoc, ntok, line, la, pos, buf);
-			if (nl)
-				append_delims(mdoc, line, pos, buf);
-			return;
-		}
-
-		/*
-		 * Handle punctuation.  Set up our scope, if a word;
-		 * rewind the scope, if a delimiter; then append the word.
-		 */
-
-		if ((d = mdoc_isdelim(p)) != DELIM_NONE) {
-			/*
-			 * If we encounter closing punctuation, no word
-			 * has been emitted, no scope is open, and we're
-			 * allowed to have an empty element, then start
-			 * a new scope.
-			 */
-			if ((d == DELIM_CLOSE ||
-			     (d == DELIM_MIDDLE && tok == MDOC_Fl)) &&
-			    !cnt && !scope && nc && mayopen) {
-				mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-				scope = 1;
-				cnt++;
-				if (tok == MDOC_Nm)
-					mayopen = 0;
-			}
-			/*
-			 * Close out our scope, if one is open, before
-			 * any punctuation.
-			 */
-			if (scope && tok != MDOC_Lk) {
-				rew_elem(mdoc, tok);
-				scope = 0;
-				if (tok == MDOC_Fn)
-					mayopen = 0;
-			}
-		} else if (mayopen && !scope) {
-			mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-			scope = 1;
-			cnt++;
-		}
-
-		dword(mdoc, line, la, p, d,
-		    mdoc_macros[tok].flags & MDOC_JOIN);
-
-		/*
-		 * If the first argument is a closing delimiter,
-		 * do not suppress spacing before it.
-		 */
-
-		if (firstarg && d == DELIM_CLOSE && !nc)
-			mdoc->last->flags &= ~NODE_DELIMC;
-		firstarg = 0;
-
-		/*
-		 * `Fl' macros have their scope re-opened with each new
-		 * word so that the `-' can be added to each one without
-		 * having to parse out spaces.
-		 */
-		if (scope && tok == MDOC_Fl) {
-			rew_elem(mdoc, tok);
-			scope = 0;
-		}
-	}
-
-	if (scope && tok != MDOC_Lk) {
-		rew_elem(mdoc, tok);
-		scope = 0;
-	}
-
-	/*
-	 * If no elements have been collected and we're allowed to have
-	 * empties (nc), open a scope and close it out.  Otherwise,
-	 * raise a warning.
-	 */
-
-	if ( ! cnt) {
-		if (nc) {
-			mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-			rew_last(mdoc, mdoc->last);
-		} else {
-			mdoc_argv_free(arg);
-			mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
-			    line, ppos, roff_name[tok]);
-		}
-	}
-	if (nl)
-		append_delims(mdoc, line, pos, buf);
-	if (scope)
-		rew_elem(mdoc, tok);
-}
-
-static void
-blk_full(MACRO_PROT_ARGS)
-{
-	int		  la, nl, parsed;
-	struct mdoc_arg	 *arg;
-	struct roff_node *blk; /* Our own or a broken block. */
-	struct roff_node *head; /* Our own head. */
-	struct roff_node *body; /* Our own body. */
-	struct roff_node *n;
-	enum margserr	  ac, lac;
-	char		 *p;
-
-	nl = MDOC_NEWLINE & mdoc->flags;
-
-	if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
-		mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
-		    line, ppos, roff_name[tok]);
-		return;
-	}
-
-	if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
-
-		/* Here, tok is one of Sh Ss Nm Nd It. */
-
-		blk = NULL;
-		for (n = mdoc->last; n != NULL; n = n->parent) {
-			if (n->flags & NODE_ENDED) {
-				if ( ! (n->flags & NODE_VALID))
-					n->flags |= NODE_BROKEN;
-				continue;
-			}
-			if (n->type != ROFFT_BLOCK)
-				continue;
-
-			if (tok == MDOC_It && n->tok == MDOC_Bl) {
-				if (blk != NULL) {
-					mandoc_vmsg(MANDOCERR_BLK_BROKEN,
-					    mdoc->parse, line, ppos,
-					    "It breaks %s",
-					    roff_name[blk->tok]);
-					rew_pending(mdoc, blk);
-				}
-				break;
-			}
-
-			if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
-				switch (tok) {
-				case MDOC_Sh:
-				case MDOC_Ss:
-					mandoc_vmsg(MANDOCERR_BLK_BROKEN,
-					    mdoc->parse, line, ppos,
-					    "%s breaks %s", roff_name[tok],
-					    roff_name[n->tok]);
-					rew_pending(mdoc, n);
-					n = mdoc->last;
-					continue;
-				case MDOC_It:
-					/* Delay in case it's astray. */
-					blk = n;
-					continue;
-				default:
-					break;
-				}
-				break;
-			}
-
-			/* Here, n is one of Sh Ss Nm Nd It. */
-
-			if (tok != MDOC_Sh && (n->tok == MDOC_Sh ||
-			    (tok != MDOC_Ss && (n->tok == MDOC_Ss ||
-			     (tok != MDOC_It && n->tok == MDOC_It)))))
-				break;
-
-			/* Item breaking an explicit block. */
-
-			if (blk != NULL) {
-				mandoc_vmsg(MANDOCERR_BLK_BROKEN,
-				    mdoc->parse, line, ppos,
-				    "It breaks %s", roff_name[blk->tok]);
-				rew_pending(mdoc, blk);
-				blk = NULL;
-			}
-
-			/* Close out prior implicit scopes. */
-
-			rew_pending(mdoc, n);
-		}
-
-		/* Skip items outside lists. */
-
-		if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
-			mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
-			    line, ppos, "It %s", buf + *pos);
-			roff_elem_alloc(mdoc, line, ppos, ROFF_br);
-			rew_elem(mdoc, ROFF_br);
-			return;
-		}
-	}
-
-	/*
-	 * This routine accommodates implicitly- and explicitly-scoped
-	 * macro openings.  Implicit ones first close out prior scope
-	 * (seen above).  Delay opening the head until necessary to
-	 * allow leading punctuation to print.  Special consideration
-	 * for `It -column', which has phrase-part syntax instead of
-	 * regular child nodes.
-	 */
-
-	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-	blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg);
-	head = body = NULL;
-
-	/*
-	 * Exception: Heads of `It' macros in `-diag' lists are not
-	 * parsed, even though `It' macros in general are parsed.
-	 */
-
-	parsed = tok != MDOC_It ||
-	    mdoc->last->parent->tok != MDOC_Bl ||
-	    mdoc->last->parent->norm->Bl.type != LIST_diag;
-
-	/*
-	 * The `Nd' macro has all arguments in its body: it's a hybrid
-	 * of block partial-explicit and full-implicit.  Stupid.
-	 */
-
-	if (tok == MDOC_Nd) {
-		head = roff_head_alloc(mdoc, line, ppos, tok);
-		rew_last(mdoc, head);
-		body = roff_body_alloc(mdoc, line, ppos, tok);
-	}
-
-	if (tok == MDOC_Bk)
-		mdoc->flags |= MDOC_KEEP;
-
-	ac = ARGS_EOLN;
-	for (;;) {
-
-		/*
-		 * If we are right after a tab character,
-		 * do not parse the first word for macros.
-		 */
-
-		if (mdoc->flags & MDOC_PHRASEQN) {
-			mdoc->flags &= ~MDOC_PHRASEQN;
-			mdoc->flags |= MDOC_PHRASEQF;
-		}
-
-		la = *pos;
-		lac = ac;
-		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-		if (ac == ARGS_EOLN) {
-			if (lac != ARGS_PHRASE ||
-			    ! (mdoc->flags & MDOC_PHRASEQF))
-				break;
-
-			/*
-			 * This line ends in a tab; start the next
-			 * column now, with a leading blank.
-			 */
-
-			if (body != NULL)
-				rew_last(mdoc, body);
-			body = roff_body_alloc(mdoc, line, ppos, tok);
-			roff_word_alloc(mdoc, line, ppos, "\\&");
-			break;
-		}
-
-		if (tok == MDOC_Bd || tok == MDOC_Bk) {
-			mandoc_vmsg(MANDOCERR_ARG_EXCESS,
-			    mdoc->parse, line, la, "%s ... %s",
-			    roff_name[tok], buf + la);
-			break;
-		}
-		if (tok == MDOC_Rs) {
-			mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
-			    line, la, "Rs %s", buf + la);
-			break;
-		}
-		if (ac == ARGS_PUNCT)
-			break;
-
-		/*
-		 * Emit leading punctuation (i.e., punctuation before
-		 * the ROFFT_HEAD) for non-phrase types.
-		 */
-
-		if (head == NULL &&
-		    ac != ARGS_PHRASE &&
-		    mdoc_isdelim(p) == DELIM_OPEN) {
-			dword(mdoc, line, la, p, DELIM_OPEN, 0);
-			continue;
-		}
-
-		/* Open a head if one hasn't been opened. */
-
-		if (head == NULL)
-			head = roff_head_alloc(mdoc, line, ppos, tok);
-
-		if (ac == ARGS_PHRASE) {
-
-			/*
-			 * If we haven't opened a body yet, rewind the
-			 * head; if we have, rewind that instead.
-			 */
-
-			rew_last(mdoc, body == NULL ? head : body);
-			body = roff_body_alloc(mdoc, line, ppos, tok);
-
-			/* Process to the tab or to the end of the line. */
-
-			mdoc->flags |= MDOC_PHRASE;
-			parse_rest(mdoc, TOKEN_NONE, line, &la, buf);
-			mdoc->flags &= ~MDOC_PHRASE;
-
-			/* There may have been `Ta' macros. */
-
-			while (body->next != NULL)
-				body = body->next;
-			continue;
-		}
-
-		if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
-			break;
-	}
-
-	if (blk->flags & NODE_VALID)
-		return;
-	if (head == NULL)
-		head = roff_head_alloc(mdoc, line, ppos, tok);
-	if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs)
-		append_delims(mdoc, line, pos, buf);
-	if (body != NULL)
-		goto out;
-	if (find_pending(mdoc, tok, line, ppos, head))
-		return;
-
-	/* Close out scopes to remain in a consistent state. */
-
-	rew_last(mdoc, head);
-	body = roff_body_alloc(mdoc, line, ppos, tok);
-out:
-	if (mdoc->flags & MDOC_FREECOL) {
-		rew_last(mdoc, body);
-		rew_last(mdoc, blk);
-		mdoc->flags &= ~MDOC_FREECOL;
-	}
-}
-
-static void
-blk_part_imp(MACRO_PROT_ARGS)
-{
-	int		  la, nl;
-	enum margserr	  ac;
-	char		 *p;
-	struct roff_node *blk; /* saved block context */
-	struct roff_node *body; /* saved body context */
-	struct roff_node *n;
-
-	nl = MDOC_NEWLINE & mdoc->flags;
-
-	/*
-	 * A macro that spans to the end of the line.  This is generally
-	 * (but not necessarily) called as the first macro.  The block
-	 * has a head as the immediate child, which is always empty,
-	 * followed by zero or more opening punctuation nodes, then the
-	 * body (which may be empty, depending on the macro), then zero
-	 * or more closing punctuation nodes.
-	 */
-
-	blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
-	rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
-
-	/*
-	 * Open the body scope "on-demand", that is, after we've
-	 * processed all our the leading delimiters (open parenthesis,
-	 * etc.).
-	 */
-
-	for (body = NULL; ; ) {
-		la = *pos;
-		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-		if (ac == ARGS_EOLN || ac == ARGS_PUNCT)
-			break;
-
-		if (body == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
-			dword(mdoc, line, la, p, DELIM_OPEN, 0);
-			continue;
-		}
-
-		if (body == NULL)
-			body = roff_body_alloc(mdoc, line, ppos, tok);
-
-		if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
-			break;
-	}
-	if (body == NULL)
-		body = roff_body_alloc(mdoc, line, ppos, tok);
-
-	if (find_pending(mdoc, tok, line, ppos, body))
-		return;
-
-	rew_last(mdoc, body);
-	if (nl)
-		append_delims(mdoc, line, pos, buf);
-	rew_pending(mdoc, blk);
-
-	/* Move trailing .Ns out of scope. */
-
-	for (n = body->child; n && n->next; n = n->next)
-		/* Do nothing. */ ;
-	if (n && n->tok == MDOC_Ns)
-		mdoc_node_relink(mdoc, n);
-}
-
-static void
-blk_part_exp(MACRO_PROT_ARGS)
-{
-	int		  la, nl;
-	enum margserr	  ac;
-	struct roff_node *head; /* keep track of head */
-	char		 *p;
-
-	nl = MDOC_NEWLINE & mdoc->flags;
-
-	/*
-	 * The opening of an explicit macro having zero or more leading
-	 * punctuation nodes; a head with optional single element (the
-	 * case of `Eo'); and a body that may be empty.
-	 */
-
-	roff_block_alloc(mdoc, line, ppos, tok);
-	head = NULL;
-	for (;;) {
-		la = *pos;
-		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-		if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
-			break;
-
-		/* Flush out leading punctuation. */
-
-		if (head == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
-			dword(mdoc, line, la, p, DELIM_OPEN, 0);
-			continue;
-		}
-
-		if (head == NULL) {
-			head = roff_head_alloc(mdoc, line, ppos, tok);
-			if (tok == MDOC_Eo)  /* Not parsed. */
-				dword(mdoc, line, la, p, DELIM_MAX, 0);
-			rew_last(mdoc, head);
-			roff_body_alloc(mdoc, line, ppos, tok);
-			if (tok == MDOC_Eo)
-				continue;
-		}
-
-		if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
-			break;
-	}
-
-	/* Clean-up to leave in a consistent state. */
-
-	if (head == NULL) {
-		rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
-		roff_body_alloc(mdoc, line, ppos, tok);
-	}
-	if (nl)
-		append_delims(mdoc, line, pos, buf);
-}
-
-static void
-in_line_argn(MACRO_PROT_ARGS)
-{
-	struct mdoc_arg	*arg;
-	char		*p;
-	enum margserr	 ac;
-	enum roff_tok	 ntok;
-	int		 state; /* arg#; -1: not yet open; -2: closed */
-	int		 la, maxargs, nl;
-
-	nl = mdoc->flags & MDOC_NEWLINE;
-
-	/*
-	 * A line macro that has a fixed number of arguments (maxargs).
-	 * Only open the scope once the first non-leading-punctuation is
-	 * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
-	 * keep it open until the maximum number of arguments are
-	 * exhausted.
-	 */
-
-	switch (tok) {
-	case MDOC_Ap:
-	case MDOC_Ns:
-	case MDOC_Ux:
-		maxargs = 0;
-		break;
-	case MDOC_Bx:
-	case MDOC_Es:
-	case MDOC_Xr:
-		maxargs = 2;
-		break;
-	default:
-		maxargs = 1;
-		break;
-	}
-
-	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
-	state = -1;
-	p = NULL;
-	for (;;) {
-		la = *pos;
-		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
-		if (ac == ARGS_WORD && state == -1 &&
-		    ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
-		    mdoc_isdelim(p) == DELIM_OPEN) {
-			dword(mdoc, line, la, p, DELIM_OPEN, 0);
-			continue;
-		}
-
-		if (state == -1 && tok != MDOC_In &&
-		    tok != MDOC_St && tok != MDOC_Xr) {
-			mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-			state = 0;
-		}
-
-		if (ac == ARGS_PUNCT || ac == ARGS_EOLN) {
-			if (abs(state) < 2 && tok == MDOC_Pf)
-				mandoc_vmsg(MANDOCERR_PF_SKIP,
-				    mdoc->parse, line, ppos, "Pf %s",
-				    p == NULL ? "at eol" : p);
-			break;
-		}
-
-		if (state == maxargs) {
-			rew_elem(mdoc, tok);
-			state = -2;
-		}
-
-		ntok = (tok == MDOC_Pf && state == 0) ?
-		    TOKEN_NONE : lookup(mdoc, tok, line, la, p);
-
-		if (ntok != TOKEN_NONE) {
-			if (state >= 0) {
-				rew_elem(mdoc, tok);
-				state = -2;
-			}
-			mdoc_macro(mdoc, ntok, line, la, pos, buf);
-			break;
-		}
-
-		if (mdoc_macros[tok].flags & MDOC_IGNDELIM ||
-		    mdoc_isdelim(p) == DELIM_NONE) {
-			if (state == -1) {
-				mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-				state = 1;
-			} else if (state >= 0)
-				state++;
-		} else if (state >= 0) {
-			rew_elem(mdoc, tok);
-			state = -2;
-		}
-
-		dword(mdoc, line, la, p, DELIM_MAX,
-		    mdoc_macros[tok].flags & MDOC_JOIN);
-	}
-
-	if (state == -1) {
-		mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
-		    line, ppos, roff_name[tok]);
-		return;
-	}
-
-	if (state == 0 && tok == MDOC_Pf)
-		append_delims(mdoc, line, pos, buf);
-	if (state >= 0)
-		rew_elem(mdoc, tok);
-	if (nl)
-		append_delims(mdoc, line, pos, buf);
-}
-
-static void
-in_line_eoln(MACRO_PROT_ARGS)
-{
-	struct roff_node	*n;
-	struct mdoc_arg		*arg;
-
-	if ((tok == MDOC_Pp || tok == MDOC_Lp) &&
-	    ! (mdoc->flags & MDOC_SYNOPSIS)) {
-		n = mdoc->last;
-		if (mdoc->next == ROFF_NEXT_SIBLING)
-			n = n->parent;
-		if (n->tok == MDOC_Nm)
-			rew_last(mdoc, n->parent);
-	}
-
-	if (buf[*pos] == '\0' &&
-	    (tok == MDOC_Fd || *roff_name[tok] == '%')) {
-		mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
-		    line, ppos, roff_name[tok]);
-		return;
-	}
-
-	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-	mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-	if (parse_rest(mdoc, tok, line, pos, buf))
-		return;
-	rew_elem(mdoc, tok);
-}
-
-/*
- * The simplest argument parser available: Parse the remaining
- * words until the end of the phrase or line and return 0
- * or until the next macro, call that macro, and return 1.
- */
-static int
-parse_rest(struct roff_man *mdoc, enum roff_tok tok,
-    int line, int *pos, char *buf)
-{
-	int		 la;
-
-	for (;;) {
-		la = *pos;
-		if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
-			return 0;
-		if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
-			return 1;
-	}
-}
-
-static void
-ctx_synopsis(MACRO_PROT_ARGS)
-{
-
-	if (~mdoc->flags & (MDOC_SYNOPSIS | MDOC_NEWLINE))
-		in_line(mdoc, tok, line, ppos, pos, buf);
-	else if (tok == MDOC_Nm)
-		blk_full(mdoc, tok, line, ppos, pos, buf);
-	else {
-		assert(tok == MDOC_Vt);
-		blk_part_imp(mdoc, tok, line, ppos, pos, buf);
-	}
-}
-
-/*
- * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
- * They're unusual because they're basically free-form text until a
- * macro is encountered.
- */
-static void
-phrase_ta(MACRO_PROT_ARGS)
-{
-	struct roff_node *body, *n;
-
-	/* Make sure we are in a column list or ignore this macro. */
-
-	body = NULL;
-	for (n = mdoc->last; n != NULL; n = n->parent) {
-		if (n->flags & NODE_ENDED)
-			continue;
-		if (n->tok == MDOC_It && n->type == ROFFT_BODY)
-			body = n;
-		if (n->tok == MDOC_Bl && n->end == ENDBODY_NOT)
-			break;
-	}
-
-	if (n == NULL || n->norm->Bl.type != LIST_column) {
-		mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
-		    line, ppos, "Ta");
-		return;
-	}
-
-	/* Advance to the next column. */
-
-	rew_last(mdoc, body);
-	roff_body_alloc(mdoc, line, ppos, MDOC_It);
-	parse_rest(mdoc, TOKEN_NONE, line, pos, buf);
-}

Property changes on: head/contrib/mdocml/mdoc_macro.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/manpath.c
===================================================================
--- head/contrib/mdocml/manpath.c	(revision 338825)
+++ head/contrib/mdocml/manpath.c	(nonexistent)
@@ -1,333 +0,0 @@
-/*	$Id: manpath.c,v 1.35 2017/07/01 09:47:30 schwarze Exp $ */
-/*
- * Copyright (c) 2011, 2014, 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.
- */
-#include "config.h"
-
-#include 
-#include 
-
-#include 
-#if HAVE_ERR
-#include 
-#endif
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "manconf.h"
-
-static	void	 manconf_file(struct manconf *, const char *);
-static	void	 manpath_add(struct manpaths *, const char *, int);
-static	void	 manpath_parseline(struct manpaths *, char *, int);
-
-
-void
-manconf_parse(struct manconf *conf, const char *file,
-		char *defp, char *auxp)
-{
-	char		*insert;
-
-	/* Always prepend -m. */
-	manpath_parseline(&conf->manpath, auxp, 1);
-
-	/* If -M is given, it overrides everything else. */
-	if (NULL != defp) {
-		manpath_parseline(&conf->manpath, defp, 1);
-		return;
-	}
-
-	/* MANPATH and man.conf(5) cooperate. */
-	defp = getenv("MANPATH");
-	if (NULL == file)
-		file = MAN_CONF_FILE;
-
-	/* No MANPATH; use man.conf(5) only. */
-	if (NULL == defp || '\0' == defp[0]) {
-		manconf_file(conf, file);
-		return;
-	}
-
-	/* Prepend man.conf(5) to MANPATH. */
-	if (':' == defp[0]) {
-		manconf_file(conf, file);
-		manpath_parseline(&conf->manpath, defp, 0);
-		return;
-	}
-
-	/* Append man.conf(5) to MANPATH. */
-	if (':' == defp[strlen(defp) - 1]) {
-		manpath_parseline(&conf->manpath, defp, 0);
-		manconf_file(conf, file);
-		return;
-	}
-
-	/* Insert man.conf(5) into MANPATH. */
-	insert = strstr(defp, "::");
-	if (NULL != insert) {
-		*insert++ = '\0';
-		manpath_parseline(&conf->manpath, defp, 0);
-		manconf_file(conf, file);
-		manpath_parseline(&conf->manpath, insert + 1, 0);
-		return;
-	}
-
-	/* MANPATH overrides man.conf(5) completely. */
-	manpath_parseline(&conf->manpath, defp, 0);
-}
-
-void
-manpath_base(struct manpaths *dirs)
-{
-	char path_base[] = MANPATH_BASE;
-	manpath_parseline(dirs, path_base, 0);
-}
-
-/*
- * Parse a FULL pathname from a colon-separated list of arrays.
- */
-static void
-manpath_parseline(struct manpaths *dirs, char *path, int complain)
-{
-	char	*dir;
-
-	if (NULL == path)
-		return;
-
-	for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
-		manpath_add(dirs, dir, complain);
-}
-
-/*
- * Add a directory to the array, ignoring bad directories.
- * Grow the array one-by-one for simplicity's sake.
- */
-static void
-manpath_add(struct manpaths *dirs, const char *dir, int complain)
-{
-	char		 buf[PATH_MAX];
-	struct stat	 sb;
-	char		*cp;
-	size_t		 i;
-
-	if (NULL == (cp = realpath(dir, buf))) {
-		if (complain)
-			warn("manpath: %s", dir);
-		return;
-	}
-
-	for (i = 0; i < dirs->sz; i++)
-		if (0 == strcmp(dirs->paths[i], dir))
-			return;
-
-	if (stat(cp, &sb) == -1) {
-		if (complain)
-			warn("manpath: %s", dir);
-		return;
-	}
-
-	dirs->paths = mandoc_reallocarray(dirs->paths,
-	    dirs->sz + 1, sizeof(char *));
-
-	dirs->paths[dirs->sz++] = mandoc_strdup(cp);
-}
-
-void
-manconf_free(struct manconf *conf)
-{
-	size_t		 i;
-
-	for (i = 0; i < conf->manpath.sz; i++)
-		free(conf->manpath.paths[i]);
-
-	free(conf->manpath.paths);
-	free(conf->output.includes);
-	free(conf->output.man);
-	free(conf->output.paper);
-	free(conf->output.style);
-}
-
-static void
-manconf_file(struct manconf *conf, const char *file)
-{
-	const char *const toks[] = { "manpath", "output", "_whatdb" };
-	char manpath_default[] = MANPATH_DEFAULT;
-
-	FILE		*stream;
-	char		*line, *cp, *ep;
-	size_t		 linesz, tok, toklen;
-	ssize_t		 linelen;
-
-	if ((stream = fopen(file, "r")) == NULL)
-		goto out;
-
-	line = NULL;
-	linesz = 0;
-
-	while ((linelen = getline(&line, &linesz, stream)) != -1) {
-		cp = line;
-		ep = cp + linelen - 1;
-		while (ep > cp && isspace((unsigned char)*ep))
-			*ep-- = '\0';
-		while (isspace((unsigned char)*cp))
-			cp++;
-		if (cp == ep || *cp == '#')
-			continue;
-
-		for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
-			toklen = strlen(toks[tok]);
-			if (cp + toklen < ep &&
-			    isspace((unsigned char)cp[toklen]) &&
-			    strncmp(cp, toks[tok], toklen) == 0) {
-				cp += toklen;
-				while (isspace((unsigned char)*cp))
-					cp++;
-				break;
-			}
-		}
-
-		switch (tok) {
-		case 2:  /* _whatdb */
-			while (ep > cp && ep[-1] != '/')
-				ep--;
-			if (ep == cp)
-				continue;
-			*ep = '\0';
-			/* FALLTHROUGH */
-		case 0:  /* manpath */
-			manpath_add(&conf->manpath, cp, 0);
-			*manpath_default = '\0';
-			break;
-		case 1:  /* output */
-			manconf_output(&conf->output, cp, 1);
-			break;
-		default:
-			break;
-		}
-	}
-	free(line);
-	fclose(stream);
-
-out:
-	if (*manpath_default != '\0')
-		manpath_parseline(&conf->manpath, manpath_default, 0);
-}
-
-int
-manconf_output(struct manoutput *conf, const char *cp, int fromfile)
-{
-	const char *const toks[] = {
-	    "includes", "man", "paper", "style",
-	    "indent", "width", "fragment", "mdoc", "noval"
-	};
-
-	const char	*errstr;
-	char		*oldval;
-	size_t		 len, tok;
-
-	for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
-		len = strlen(toks[tok]);
-		if ( ! strncmp(cp, toks[tok], len) &&
-		    strchr(" =	", cp[len]) != NULL) {
-			cp += len;
-			if (*cp == '=')
-				cp++;
-			while (isspace((unsigned char)*cp))
-				cp++;
-			break;
-		}
-	}
-
-	if (tok < 6 && *cp == '\0') {
-		warnx("-O %s=?: Missing argument value", toks[tok]);
-		return -1;
-	}
-	if ((tok == 6 || tok == 7) && *cp != '\0') {
-		warnx("-O %s: Does not take a value: %s", toks[tok], cp);
-		return -1;
-	}
-
-	switch (tok) {
-	case 0:
-		if (conf->includes != NULL) {
-			oldval = mandoc_strdup(conf->includes);
-			break;
-		}
-		conf->includes = mandoc_strdup(cp);
-		return 0;
-	case 1:
-		if (conf->man != NULL) {
-			oldval = mandoc_strdup(conf->man);
-			break;
-		}
-		conf->man = mandoc_strdup(cp);
-		return 0;
-	case 2:
-		if (conf->paper != NULL) {
-			oldval = mandoc_strdup(conf->paper);
-			break;
-		}
-		conf->paper = mandoc_strdup(cp);
-		return 0;
-	case 3:
-		if (conf->style != NULL) {
-			oldval = mandoc_strdup(conf->style);
-			break;
-		}
-		conf->style = mandoc_strdup(cp);
-		return 0;
-	case 4:
-		if (conf->indent) {
-			mandoc_asprintf(&oldval, "%zu", conf->indent);
-			break;
-		}
-		conf->indent = strtonum(cp, 0, 1000, &errstr);
-		if (errstr == NULL)
-			return 0;
-		warnx("-O indent=%s is %s", cp, errstr);
-		return -1;
-	case 5:
-		if (conf->width) {
-			mandoc_asprintf(&oldval, "%zu", conf->width);
-			break;
-		}
-		conf->width = strtonum(cp, 1, 1000, &errstr);
-		if (errstr == NULL)
-			return 0;
-		warnx("-O width=%s is %s", cp, errstr);
-		return -1;
-	case 6:
-		conf->fragment = 1;
-		return 0;
-	case 7:
-		conf->mdoc = 1;
-		return 0;
-	case 8:
-		conf->noval = 1;
-		return 0;
-	default:
-		if (fromfile)
-			warnx("-O %s: Bad argument", cp);
-		return -1;
-	}
-	if (fromfile == 0)
-		warnx("-O %s=%s: Option already set to %s",
-		    toks[tok], cp, oldval);
-	free(oldval);
-	return -1;
-}

Property changes on: head/contrib/mdocml/manpath.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/compat_strtonum.c
===================================================================
--- head/contrib/mdocml/compat_strtonum.c	(revision 338825)
+++ head/contrib/mdocml/compat_strtonum.c	(nonexistent)
@@ -1,76 +0,0 @@
-#include "config.h"
-
-#if HAVE_STRTONUM
-
-int dummy;
-
-#else
-
-/*	$Id: compat_strtonum.c,v 1.1 2015/02/16 14:56:22 schwarze Exp $	*/
-/*	$OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $	*/
-
-/*
- * Copyright (c) 2004 Ted Unangst and Todd Miller
- * All rights reserved.
- *
- * 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 
-#include 
-#include 
-
-#define	INVALID		1
-#define	TOOSMALL	2
-#define	TOOLARGE	3
-
-long long
-strtonum(const char *numstr, long long minval, long long maxval,
-    const char **errstrp)
-{
-	long long ll = 0;
-	int error = 0;
-	char *ep;
-	struct errval {
-		const char *errstr;
-		int err;
-	} ev[4] = {
-		{ NULL,		0 },
-		{ "invalid",	EINVAL },
-		{ "too small",	ERANGE },
-		{ "too large",	ERANGE },
-	};
-
-	ev[0].err = errno;
-	errno = 0;
-	if (minval > maxval) {
-		error = INVALID;
-	} else {
-		ll = strtoll(numstr, &ep, 10);
-		if (numstr == ep || *ep != '\0')
-			error = INVALID;
-		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
-			error = TOOSMALL;
-		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
-			error = TOOLARGE;
-	}
-	if (errstrp != NULL)
-		*errstrp = ev[error].errstr;
-	errno = ev[error].err;
-	if (error)
-		ll = 0;
-
-	return (ll);
-}
-
-#endif /* !HAVE_STRTONUM */

Property changes on: head/contrib/mdocml/compat_strtonum.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/term.c
===================================================================
--- head/contrib/mdocml/term.c	(revision 338825)
+++ head/contrib/mdocml/term.c	(nonexistent)
@@ -1,995 +0,0 @@
-/*	$Id: term.c,v 1.274 2017/07/28 14:25:48 schwarze Exp $ */
-/*
- * Copyright (c) 2008, 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 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.h"
-#include "mandoc_aux.h"
-#include "out.h"
-#include "term.h"
-#include "main.h"
-
-static	size_t		 cond_width(const struct termp *, int, int *);
-static	void		 adjbuf(struct termp_col *, size_t);
-static	void		 bufferc(struct termp *, char);
-static	void		 encode(struct termp *, const char *, size_t);
-static	void		 encode1(struct termp *, int);
-static	void		 endline(struct termp *);
-
-
-void
-term_setcol(struct termp *p, size_t maxtcol)
-{
-	if (maxtcol > p->maxtcol) {
-		p->tcols = mandoc_recallocarray(p->tcols,
-		    p->maxtcol, maxtcol, sizeof(*p->tcols));
-		p->maxtcol = maxtcol;
-	}
-	p->lasttcol = maxtcol - 1;
-	p->tcol = p->tcols;
-}
-
-void
-term_free(struct termp *p)
-{
-	for (p->tcol = p->tcols; p->tcol < p->tcols + p->maxtcol; p->tcol++)
-		free(p->tcol->buf);
-	free(p->tcols);
-	free(p->fontq);
-	free(p);
-}
-
-void
-term_begin(struct termp *p, term_margin head,
-		term_margin foot, const struct roff_meta *arg)
-{
-
-	p->headf = head;
-	p->footf = foot;
-	p->argf = arg;
-	(*p->begin)(p);
-}
-
-void
-term_end(struct termp *p)
-{
-
-	(*p->end)(p);
-}
-
-/*
- * Flush a chunk of text.  By default, break the output line each time
- * the right margin is reached, and continue output on the next line
- * at the same offset as the chunk itself.  By default, also break the
- * output line at the end of the chunk.
- * The following flags may be specified:
- *
- *  - TERMP_NOBREAK: Do not break the output line at the right margin,
- *    but only at the max right margin.  Also, do not break the output
- *    line at the end of the chunk, such that the next call can pad to
- *    the next column.  However, if less than p->trailspace blanks,
- *    which can be 0, 1, or 2, remain to the right margin, the line
- *    will be broken.
- *  - TERMP_BRTRSP: Consider trailing whitespace significant
- *    when deciding whether the chunk fits or not.
- *  - TERMP_BRIND: If the chunk does not fit and the output line has
- *    to be broken, start the next line at the right margin instead
- *    of at the offset.  Used together with TERMP_NOBREAK for the tags
- *    in various kinds of tagged lists.
- *  - TERMP_HANG: Do not break the output line at the right margin,
- *    append the next chunk after it even if this one is too long.
- *    To be used together with TERMP_NOBREAK.
- *  - TERMP_NOPAD: Start writing at the current position,
- *    do not pad with blank characters up to the offset.
- */
-void
-term_flushln(struct termp *p)
-{
-	size_t		 vis;   /* current visual position on output */
-	size_t		 vbl;   /* number of blanks to prepend to output */
-	size_t		 vend;	/* end of word visual position on output */
-	size_t		 bp;    /* visual right border position */
-	size_t		 dv;    /* temporary for visual pos calculations */
-	size_t		 j;     /* temporary loop index for p->tcol->buf */
-	size_t		 jhy;	/* last hyph before overflow w/r/t j */
-	size_t		 maxvis; /* output position of visible boundary */
-	int		 ntab;	/* number of tabs to prepend */
-	int		 breakline; /* after this word */
-
-	vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
-	    0 : p->tcol->offset - p->viscol;
-	if (p->minbl && vbl < p->minbl)
-		vbl = p->minbl;
-	maxvis = p->tcol->rmargin > p->viscol + vbl ?
-	    p->tcol->rmargin - p->viscol - vbl : 0;
-	bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
-	    p->maxrmargin > p->viscol + vbl ?
-	    p->maxrmargin - p->viscol - vbl : 0;
-	vis = vend = 0;
-
-	if ((p->flags & TERMP_MULTICOL) == 0)
-		p->tcol->col = 0;
-	while (p->tcol->col < p->tcol->lastcol) {
-
-		/*
-		 * Handle literal tab characters: collapse all
-		 * subsequent tabs into a single huge set of spaces.
-		 */
-
-		ntab = 0;
-		while (p->tcol->col < p->tcol->lastcol &&
-		    p->tcol->buf[p->tcol->col] == '\t') {
-			vend = term_tab_next(vis);
-			vbl += vend - vis;
-			vis = vend;
-			ntab++;
-			p->tcol->col++;
-		}
-
-		/*
-		 * Count up visible word characters.  Control sequences
-		 * (starting with the CSI) aren't counted.  A space
-		 * generates a non-printing word, which is valid (the
-		 * space is printed according to regular spacing rules).
-		 */
-
-		jhy = 0;
-		breakline = 0;
-		for (j = p->tcol->col; j < p->tcol->lastcol; j++) {
-			if (p->tcol->buf[j] == '\n') {
-				if ((p->flags & TERMP_BRIND) == 0)
-					breakline = 1;
-				continue;
-			}
-			if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t')
-				break;
-
-			/* Back over the last printed character. */
-			if (p->tcol->buf[j] == '\b') {
-				assert(j);
-				vend -= (*p->width)(p, p->tcol->buf[j - 1]);
-				continue;
-			}
-
-			/* Regular word. */
-			/* Break at the hyphen point if we overrun. */
-			if (vend > vis && vend < bp &&
-			    (p->tcol->buf[j] == ASCII_HYPH||
-			     p->tcol->buf[j] == ASCII_BREAK))
-				jhy = j;
-
-			/*
-			 * Hyphenation now decided, put back a real
-			 * hyphen such that we get the correct width.
-			 */
-			if (p->tcol->buf[j] == ASCII_HYPH)
-				p->tcol->buf[j] = '-';
-
-			vend += (*p->width)(p, p->tcol->buf[j]);
-		}
-
-		/*
-		 * Find out whether we would exceed the right margin.
-		 * If so, break to the next line.
-		 */
-
-		if (vend > bp && jhy == 0 && vis > 0 &&
-		    (p->flags & TERMP_BRNEVER) == 0) {
-			if (p->flags & TERMP_MULTICOL)
-				return;
-
-			endline(p);
-			vend -= vis;
-
-			/* Use pending tabs on the new line. */
-
-			vbl = 0;
-			while (ntab--)
-				vbl = term_tab_next(vbl);
-
-			/* Re-establish indentation. */
-
-			if (p->flags & TERMP_BRIND)
-				vbl += p->tcol->rmargin;
-			else
-				vbl += p->tcol->offset;
-			maxvis = p->tcol->rmargin > vbl ?
-			    p->tcol->rmargin - vbl : 0;
-			bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
-			    p->maxrmargin > vbl ?  p->maxrmargin - vbl : 0;
-		}
-
-		/*
-		 * Write out the rest of the word.
-		 */
-
-		for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) {
-			if (vend > bp && jhy > 0 && p->tcol->col > jhy)
-				break;
-			if (p->tcol->buf[p->tcol->col] == '\n')
-				continue;
-			if (p->tcol->buf[p->tcol->col] == '\t')
-				break;
-			if (p->tcol->buf[p->tcol->col] == ' ') {
-				j = p->tcol->col;
-				while (p->tcol->col < p->tcol->lastcol &&
-				    p->tcol->buf[p->tcol->col] == ' ')
-					p->tcol->col++;
-				dv = (p->tcol->col - j) * (*p->width)(p, ' ');
-				vbl += dv;
-				vend += dv;
-				break;
-			}
-			if (p->tcol->buf[p->tcol->col] == ASCII_NBRSP) {
-				vbl += (*p->width)(p, ' ');
-				continue;
-			}
-			if (p->tcol->buf[p->tcol->col] == ASCII_BREAK)
-				continue;
-
-			/*
-			 * Now we definitely know there will be
-			 * printable characters to output,
-			 * so write preceding white space now.
-			 */
-			if (vbl) {
-				(*p->advance)(p, vbl);
-				p->viscol += vbl;
-				vbl = 0;
-			}
-
-			(*p->letter)(p, p->tcol->buf[p->tcol->col]);
-			if (p->tcol->buf[p->tcol->col] == '\b')
-				p->viscol -= (*p->width)(p,
-				    p->tcol->buf[p->tcol->col - 1]);
-			else
-				p->viscol += (*p->width)(p,
-				    p->tcol->buf[p->tcol->col]);
-		}
-		vis = vend;
-
-		if (breakline == 0)
-			continue;
-
-		/* Explicitly requested output line break. */
-
-		if (p->flags & TERMP_MULTICOL)
-			return;
-
-		endline(p);
-		breakline = 0;
-		vis = vend = 0;
-
-		/* Re-establish indentation. */
-
-		vbl = p->tcol->offset;
-		maxvis = p->tcol->rmargin > vbl ?
-		    p->tcol->rmargin - vbl : 0;
-		bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
-		    p->maxrmargin > vbl ?  p->maxrmargin - vbl : 0;
-	}
-
-	/*
-	 * If there was trailing white space, it was not printed;
-	 * so reset the cursor position accordingly.
-	 */
-
-	if (vis > vbl)
-		vis -= vbl;
-	else
-		vis = 0;
-
-	p->col = p->tcol->col = p->tcol->lastcol = 0;
-	p->minbl = p->trailspace;
-	p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD);
-
-	if (p->flags & TERMP_MULTICOL)
-		return;
-
-	/* Trailing whitespace is significant in some columns. */
-
-	if (vis && vbl && (TERMP_BRTRSP & p->flags))
-		vis += vbl;
-
-	/* If the column was overrun, break the line. */
-	if ((p->flags & TERMP_NOBREAK) == 0 ||
-	    ((p->flags & TERMP_HANG) == 0 &&
-	     vis + p->trailspace * (*p->width)(p, ' ') > maxvis))
-		endline(p);
-}
-
-static void
-endline(struct termp *p)
-{
-	if ((p->flags & (TERMP_NEWMC | TERMP_ENDMC)) == TERMP_ENDMC) {
-		p->mc = NULL;
-		p->flags &= ~TERMP_ENDMC;
-	}
-	if (p->mc != NULL) {
-		if (p->viscol && p->maxrmargin >= p->viscol)
-			(*p->advance)(p, p->maxrmargin - p->viscol + 1);
-		p->flags |= TERMP_NOBUF | TERMP_NOSPACE;
-		term_word(p, p->mc);
-		p->flags &= ~(TERMP_NOBUF | TERMP_NEWMC);
-	}
-	p->viscol = 0;
-	p->minbl = 0;
-	(*p->endline)(p);
-}
-
-/*
- * A newline only breaks an existing line; it won't assert vertical
- * space.  All data in the output buffer is flushed prior to the newline
- * assertion.
- */
-void
-term_newln(struct termp *p)
-{
-
-	p->flags |= TERMP_NOSPACE;
-	if (p->tcol->lastcol || p->viscol)
-		term_flushln(p);
-}
-
-/*
- * Asserts a vertical space (a full, empty line-break between lines).
- * Note that if used twice, this will cause two blank spaces and so on.
- * All data in the output buffer is flushed prior to the newline
- * assertion.
- */
-void
-term_vspace(struct termp *p)
-{
-
-	term_newln(p);
-	p->viscol = 0;
-	p->minbl = 0;
-	if (0 < p->skipvsp)
-		p->skipvsp--;
-	else
-		(*p->endline)(p);
-}
-
-/* Swap current and previous font; for \fP and .ft P */
-void
-term_fontlast(struct termp *p)
-{
-	enum termfont	 f;
-
-	f = p->fontl;
-	p->fontl = p->fontq[p->fonti];
-	p->fontq[p->fonti] = f;
-}
-
-/* Set font, save current, discard previous; for \f, .ft, .B etc. */
-void
-term_fontrepl(struct termp *p, enum termfont f)
-{
-
-	p->fontl = p->fontq[p->fonti];
-	p->fontq[p->fonti] = f;
-}
-
-/* Set font, save previous. */
-void
-term_fontpush(struct termp *p, enum termfont f)
-{
-
-	p->fontl = p->fontq[p->fonti];
-	if (++p->fonti == p->fontsz) {
-		p->fontsz += 8;
-		p->fontq = mandoc_reallocarray(p->fontq,
-		    p->fontsz, sizeof(*p->fontq));
-	}
-	p->fontq[p->fonti] = f;
-}
-
-/* Flush to make the saved pointer current again. */
-void
-term_fontpopq(struct termp *p, int i)
-{
-
-	assert(i >= 0);
-	if (p->fonti > i)
-		p->fonti = i;
-}
-
-/* Pop one font off the stack. */
-void
-term_fontpop(struct termp *p)
-{
-
-	assert(p->fonti);
-	p->fonti--;
-}
-
-/*
- * Handle pwords, partial words, which may be either a single word or a
- * phrase that cannot be broken down (such as a literal string).  This
- * handles word styling.
- */
-void
-term_word(struct termp *p, const char *word)
-{
-	struct roffsu	 su;
-	const char	 nbrsp[2] = { ASCII_NBRSP, 0 };
-	const char	*seq, *cp;
-	int		 sz, uc;
-	size_t		 csz, lsz, ssz;
-	enum mandoc_esc	 esc;
-
-	if ((p->flags & TERMP_NOBUF) == 0) {
-		if ((p->flags & TERMP_NOSPACE) == 0) {
-			if ((p->flags & TERMP_KEEP) == 0) {
-				bufferc(p, ' ');
-				if (p->flags & TERMP_SENTENCE)
-					bufferc(p, ' ');
-			} else
-				bufferc(p, ASCII_NBRSP);
-		}
-		if (p->flags & TERMP_PREKEEP)
-			p->flags |= TERMP_KEEP;
-		if (p->flags & TERMP_NONOSPACE)
-			p->flags |= TERMP_NOSPACE;
-		else
-			p->flags &= ~TERMP_NOSPACE;
-		p->flags &= ~(TERMP_SENTENCE | TERMP_NONEWLINE);
-		p->skipvsp = 0;
-	}
-
-	while ('\0' != *word) {
-		if ('\\' != *word) {
-			if (TERMP_NBRWORD & p->flags) {
-				if (' ' == *word) {
-					encode(p, nbrsp, 1);
-					word++;
-					continue;
-				}
-				ssz = strcspn(word, "\\ ");
-			} else
-				ssz = strcspn(word, "\\");
-			encode(p, word, ssz);
-			word += (int)ssz;
-			continue;
-		}
-
-		word++;
-		esc = mandoc_escape(&word, &seq, &sz);
-		if (ESCAPE_ERROR == esc)
-			continue;
-
-		switch (esc) {
-		case ESCAPE_UNICODE:
-			uc = mchars_num2uc(seq + 1, sz - 1);
-			break;
-		case ESCAPE_NUMBERED:
-			uc = mchars_num2char(seq, sz);
-			if (uc < 0)
-				continue;
-			break;
-		case ESCAPE_SPECIAL:
-			if (p->enc == TERMENC_ASCII) {
-				cp = mchars_spec2str(seq, sz, &ssz);
-				if (cp != NULL)
-					encode(p, cp, ssz);
-			} else {
-				uc = mchars_spec2cp(seq, sz);
-				if (uc > 0)
-					encode1(p, uc);
-			}
-			continue;
-		case ESCAPE_FONTBOLD:
-			term_fontrepl(p, TERMFONT_BOLD);
-			continue;
-		case ESCAPE_FONTITALIC:
-			term_fontrepl(p, TERMFONT_UNDER);
-			continue;
-		case ESCAPE_FONTBI:
-			term_fontrepl(p, TERMFONT_BI);
-			continue;
-		case ESCAPE_FONT:
-		case ESCAPE_FONTROMAN:
-			term_fontrepl(p, TERMFONT_NONE);
-			continue;
-		case ESCAPE_FONTPREV:
-			term_fontlast(p);
-			continue;
-		case ESCAPE_BREAK:
-			bufferc(p, '\n');
-			continue;
-		case ESCAPE_NOSPACE:
-			if (p->flags & TERMP_BACKAFTER)
-				p->flags &= ~TERMP_BACKAFTER;
-			else if (*word == '\0')
-				p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE);
-			continue;
-		case ESCAPE_HORIZ:
-			if (*seq == '|') {
-				seq++;
-				uc = -p->col;
-			} else
-				uc = 0;
-			if (a2roffsu(seq, &su, SCALE_EM) == NULL)
-				continue;
-			uc += term_hen(p, &su);
-			if (uc > 0)
-				while (uc-- > 0)
-					bufferc(p, ASCII_NBRSP);
-			else if (p->col > (size_t)(-uc))
-				p->col += uc;
-			else {
-				uc += p->col;
-				p->col = 0;
-				if (p->tcol->offset > (size_t)(-uc)) {
-					p->ti += uc;
-					p->tcol->offset += uc;
-				} else {
-					p->ti -= p->tcol->offset;
-					p->tcol->offset = 0;
-				}
-			}
-			continue;
-		case ESCAPE_HLINE:
-			if ((cp = a2roffsu(seq, &su, SCALE_EM)) == NULL)
-				continue;
-			uc = term_hen(p, &su);
-			if (uc <= 0) {
-				if (p->tcol->rmargin <= p->tcol->offset)
-					continue;
-				lsz = p->tcol->rmargin - p->tcol->offset;
-			} else
-				lsz = uc;
-			if (*cp == seq[-1])
-				uc = -1;
-			else if (*cp == '\\') {
-				seq = cp + 1;
-				esc = mandoc_escape(&seq, &cp, &sz);
-				switch (esc) {
-				case ESCAPE_UNICODE:
-					uc = mchars_num2uc(cp + 1, sz - 1);
-					break;
-				case ESCAPE_NUMBERED:
-					uc = mchars_num2char(cp, sz);
-					break;
-				case ESCAPE_SPECIAL:
-					uc = mchars_spec2cp(cp, sz);
-					break;
-				default:
-					uc = -1;
-					break;
-				}
-			} else
-				uc = *cp;
-			if (uc < 0x20 || (uc > 0x7E && uc < 0xA0))
-				uc = '_';
-			if (p->enc == TERMENC_ASCII) {
-				cp = ascii_uc2str(uc);
-				csz = term_strlen(p, cp);
-				ssz = strlen(cp);
-			} else
-				csz = (*p->width)(p, uc);
-			while (lsz >= csz) {
-				if (p->enc == TERMENC_ASCII)
-					encode(p, cp, ssz);
-				else
-					encode1(p, uc);
-				lsz -= csz;
-			}
-			continue;
-		case ESCAPE_SKIPCHAR:
-			p->flags |= TERMP_BACKAFTER;
-			continue;
-		case ESCAPE_OVERSTRIKE:
-			cp = seq + sz;
-			while (seq < cp) {
-				if (*seq == '\\') {
-					mandoc_escape(&seq, NULL, NULL);
-					continue;
-				}
-				encode1(p, *seq++);
-				if (seq < cp) {
-					if (p->flags & TERMP_BACKBEFORE)
-						p->flags |= TERMP_BACKAFTER;
-					else
-						p->flags |= TERMP_BACKBEFORE;
-				}
-			}
-			/* Trim trailing backspace/blank pair. */
-			if (p->tcol->lastcol > 2 &&
-			    (p->tcol->buf[p->tcol->lastcol - 1] == ' ' ||
-			     p->tcol->buf[p->tcol->lastcol - 1] == '\t'))
-				p->tcol->lastcol -= 2;
-			if (p->col > p->tcol->lastcol)
-				p->col = p->tcol->lastcol;
-			continue;
-		default:
-			continue;
-		}
-
-		/*
-		 * Common handling for Unicode and numbered
-		 * character escape sequences.
-		 */
-
-		if (p->enc == TERMENC_ASCII) {
-			cp = ascii_uc2str(uc);
-			encode(p, cp, strlen(cp));
-		} else {
-			if ((uc < 0x20 && uc != 0x09) ||
-			    (uc > 0x7E && uc < 0xA0))
-				uc = 0xFFFD;
-			encode1(p, uc);
-		}
-	}
-	p->flags &= ~TERMP_NBRWORD;
-}
-
-static void
-adjbuf(struct termp_col *c, size_t sz)
-{
-	if (c->maxcols == 0)
-		c->maxcols = 1024;
-	while (c->maxcols <= sz)
-		c->maxcols <<= 2;
-	c->buf = mandoc_reallocarray(c->buf, c->maxcols, sizeof(*c->buf));
-}
-
-static void
-bufferc(struct termp *p, char c)
-{
-	if (p->flags & TERMP_NOBUF) {
-		(*p->letter)(p, c);
-		return;
-	}
-	if (p->col + 1 >= p->tcol->maxcols)
-		adjbuf(p->tcol, p->col + 1);
-	if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
-		p->tcol->buf[p->col] = c;
-	if (p->tcol->lastcol < ++p->col)
-		p->tcol->lastcol = p->col;
-}
-
-/*
- * See encode().
- * Do this for a single (probably unicode) value.
- * Does not check for non-decorated glyphs.
- */
-static void
-encode1(struct termp *p, int c)
-{
-	enum termfont	  f;
-
-	if (p->flags & TERMP_NOBUF) {
-		(*p->letter)(p, c);
-		return;
-	}
-
-	if (p->col + 7 >= p->tcol->maxcols)
-		adjbuf(p->tcol, p->col + 7);
-
-	f = (c == ASCII_HYPH || c > 127 || isgraph(c)) ?
-	    p->fontq[p->fonti] : TERMFONT_NONE;
-
-	if (p->flags & TERMP_BACKBEFORE) {
-		if (p->tcol->buf[p->col - 1] == ' ' ||
-		    p->tcol->buf[p->col - 1] == '\t')
-			p->col--;
-		else
-			p->tcol->buf[p->col++] = '\b';
-		p->flags &= ~TERMP_BACKBEFORE;
-	}
-	if (f == TERMFONT_UNDER || f == TERMFONT_BI) {
-		p->tcol->buf[p->col++] = '_';
-		p->tcol->buf[p->col++] = '\b';
-	}
-	if (f == TERMFONT_BOLD || f == TERMFONT_BI) {
-		if (c == ASCII_HYPH)
-			p->tcol->buf[p->col++] = '-';
-		else
-			p->tcol->buf[p->col++] = c;
-		p->tcol->buf[p->col++] = '\b';
-	}
-	if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
-		p->tcol->buf[p->col] = c;
-	if (p->tcol->lastcol < ++p->col)
-		p->tcol->lastcol = p->col;
-	if (p->flags & TERMP_BACKAFTER) {
-		p->flags |= TERMP_BACKBEFORE;
-		p->flags &= ~TERMP_BACKAFTER;
-	}
-}
-
-static void
-encode(struct termp *p, const char *word, size_t sz)
-{
-	size_t		  i;
-
-	if (p->flags & TERMP_NOBUF) {
-		for (i = 0; i < sz; i++)
-			(*p->letter)(p, word[i]);
-		return;
-	}
-
-	if (p->col + 2 + (sz * 5) >= p->tcol->maxcols)
-		adjbuf(p->tcol, p->col + 2 + (sz * 5));
-
-	for (i = 0; i < sz; i++) {
-		if (ASCII_HYPH == word[i] ||
-		    isgraph((unsigned char)word[i]))
-			encode1(p, word[i]);
-		else {
-			if (p->tcol->lastcol <= p->col ||
-			    (word[i] != ' ' && word[i] != ASCII_NBRSP))
-				p->tcol->buf[p->col] = word[i];
-			p->col++;
-
-			/*
-			 * Postpone the effect of \z while handling
-			 * an overstrike sequence from ascii_uc2str().
-			 */
-
-			if (word[i] == '\b' &&
-			    (p->flags & TERMP_BACKBEFORE)) {
-				p->flags &= ~TERMP_BACKBEFORE;
-				p->flags |= TERMP_BACKAFTER;
-			}
-		}
-	}
-	if (p->tcol->lastcol < p->col)
-		p->tcol->lastcol = p->col;
-}
-
-void
-term_setwidth(struct termp *p, const char *wstr)
-{
-	struct roffsu	 su;
-	int		 iop, width;
-
-	iop = 0;
-	width = 0;
-	if (NULL != wstr) {
-		switch (*wstr) {
-		case '+':
-			iop = 1;
-			wstr++;
-			break;
-		case '-':
-			iop = -1;
-			wstr++;
-			break;
-		default:
-			break;
-		}
-		if (a2roffsu(wstr, &su, SCALE_MAX) != NULL)
-			width = term_hspan(p, &su);
-		else
-			iop = 0;
-	}
-	(*p->setwidth)(p, iop, width);
-}
-
-size_t
-term_len(const struct termp *p, size_t sz)
-{
-
-	return (*p->width)(p, ' ') * sz;
-}
-
-static size_t
-cond_width(const struct termp *p, int c, int *skip)
-{
-
-	if (*skip) {
-		(*skip) = 0;
-		return 0;
-	} else
-		return (*p->width)(p, c);
-}
-
-size_t
-term_strlen(const struct termp *p, const char *cp)
-{
-	size_t		 sz, rsz, i;
-	int		 ssz, skip, uc;
-	const char	*seq, *rhs;
-	enum mandoc_esc	 esc;
-	static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH,
-			ASCII_BREAK, '\0' };
-
-	/*
-	 * Account for escaped sequences within string length
-	 * calculations.  This follows the logic in term_word() as we
-	 * must calculate the width of produced strings.
-	 */
-
-	sz = 0;
-	skip = 0;
-	while ('\0' != *cp) {
-		rsz = strcspn(cp, rej);
-		for (i = 0; i < rsz; i++)
-			sz += cond_width(p, *cp++, &skip);
-
-		switch (*cp) {
-		case '\\':
-			cp++;
-			esc = mandoc_escape(&cp, &seq, &ssz);
-			if (ESCAPE_ERROR == esc)
-				continue;
-
-			rhs = NULL;
-
-			switch (esc) {
-			case ESCAPE_UNICODE:
-				uc = mchars_num2uc(seq + 1, ssz - 1);
-				break;
-			case ESCAPE_NUMBERED:
-				uc = mchars_num2char(seq, ssz);
-				if (uc < 0)
-					continue;
-				break;
-			case ESCAPE_SPECIAL:
-				if (p->enc == TERMENC_ASCII) {
-					rhs = mchars_spec2str(seq, ssz, &rsz);
-					if (rhs != NULL)
-						break;
-				} else {
-					uc = mchars_spec2cp(seq, ssz);
-					if (uc > 0)
-						sz += cond_width(p, uc, &skip);
-				}
-				continue;
-			case ESCAPE_SKIPCHAR:
-				skip = 1;
-				continue;
-			case ESCAPE_OVERSTRIKE:
-				rsz = 0;
-				rhs = seq + ssz;
-				while (seq < rhs) {
-					if (*seq == '\\') {
-						mandoc_escape(&seq, NULL, NULL);
-						continue;
-					}
-					i = (*p->width)(p, *seq++);
-					if (rsz < i)
-						rsz = i;
-				}
-				sz += rsz;
-				continue;
-			default:
-				continue;
-			}
-
-			/*
-			 * Common handling for Unicode and numbered
-			 * character escape sequences.
-			 */
-
-			if (rhs == NULL) {
-				if (p->enc == TERMENC_ASCII) {
-					rhs = ascii_uc2str(uc);
-					rsz = strlen(rhs);
-				} else {
-					if ((uc < 0x20 && uc != 0x09) ||
-					    (uc > 0x7E && uc < 0xA0))
-						uc = 0xFFFD;
-					sz += cond_width(p, uc, &skip);
-					continue;
-				}
-			}
-
-			if (skip) {
-				skip = 0;
-				break;
-			}
-
-			/*
-			 * Common handling for all escape sequences
-			 * printing more than one character.
-			 */
-
-			for (i = 0; i < rsz; i++)
-				sz += (*p->width)(p, *rhs++);
-			break;
-		case ASCII_NBRSP:
-			sz += cond_width(p, ' ', &skip);
-			cp++;
-			break;
-		case ASCII_HYPH:
-			sz += cond_width(p, '-', &skip);
-			cp++;
-			break;
-		default:
-			break;
-		}
-	}
-
-	return sz;
-}
-
-int
-term_vspan(const struct termp *p, const struct roffsu *su)
-{
-	double		 r;
-	int		 ri;
-
-	switch (su->unit) {
-	case SCALE_BU:
-		r = su->scale / 40.0;
-		break;
-	case SCALE_CM:
-		r = su->scale * 6.0 / 2.54;
-		break;
-	case SCALE_FS:
-		r = su->scale * 65536.0 / 40.0;
-		break;
-	case SCALE_IN:
-		r = su->scale * 6.0;
-		break;
-	case SCALE_MM:
-		r = su->scale * 0.006;
-		break;
-	case SCALE_PC:
-		r = su->scale;
-		break;
-	case SCALE_PT:
-		r = su->scale / 12.0;
-		break;
-	case SCALE_EN:
-	case SCALE_EM:
-		r = su->scale * 0.6;
-		break;
-	case SCALE_VS:
-		r = su->scale;
-		break;
-	default:
-		abort();
-	}
-	ri = r > 0.0 ? r + 0.4995 : r - 0.4995;
-	return ri < 66 ? ri : 1;
-}
-
-/*
- * Convert a scaling width to basic units, rounding towards 0.
- */
-int
-term_hspan(const struct termp *p, const struct roffsu *su)
-{
-
-	return (*p->hspan)(p, su);
-}
-
-/*
- * Convert a scaling width to basic units, rounding to closest.
- */
-int
-term_hen(const struct termp *p, const struct roffsu *su)
-{
-	int bu;
-
-	if ((bu = (*p->hspan)(p, su)) >= 0)
-		return (bu + 11) / 24;
-	else
-		return -((-bu + 11) / 24);
-}

Property changes on: head/contrib/mdocml/term.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mansearch.h
===================================================================
--- head/contrib/mdocml/mansearch.h	(revision 338825)
+++ head/contrib/mdocml/mansearch.h	(nonexistent)
@@ -1,118 +0,0 @@
-/*	$Id: mansearch.h,v 1.28 2017/04/17 20:05:08 schwarze Exp $ */
-/*
- * Copyright (c) 2012 Kristaps Dzonsons 
- * Copyright (c) 2013, 2014, 2016, 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.
- */
-
-#define	MANDOC_DB	 "mandoc.db"
-#define	MANDOCDB_MAGIC	 0x3a7d0cdb
-#define	MANDOCDB_VERSION 1
-
-#define	MACRO_MAX	 36
-#define	KEY_arch	 0
-#define	KEY_sec		 1
-#define	KEY_Nm		 38
-#define	KEY_Nd		 39
-#define	KEY_MAX		 40
-
-#define	TYPE_arch	 0x0000000000000001ULL
-#define	TYPE_sec	 0x0000000000000002ULL
-#define	TYPE_Xr		 0x0000000000000004ULL
-#define	TYPE_Ar		 0x0000000000000008ULL
-#define	TYPE_Fa		 0x0000000000000010ULL
-#define	TYPE_Fl		 0x0000000000000020ULL
-#define	TYPE_Dv		 0x0000000000000040ULL
-#define	TYPE_Fn		 0x0000000000000080ULL
-#define	TYPE_Ic		 0x0000000000000100ULL
-#define	TYPE_Pa		 0x0000000000000200ULL
-#define	TYPE_Cm		 0x0000000000000400ULL
-#define	TYPE_Li		 0x0000000000000800ULL
-#define	TYPE_Em		 0x0000000000001000ULL
-#define	TYPE_Cd		 0x0000000000002000ULL
-#define	TYPE_Va		 0x0000000000004000ULL
-#define	TYPE_Ft		 0x0000000000008000ULL
-#define	TYPE_Tn		 0x0000000000010000ULL
-#define	TYPE_Er		 0x0000000000020000ULL
-#define	TYPE_Ev		 0x0000000000040000ULL
-#define	TYPE_Sy		 0x0000000000080000ULL
-#define	TYPE_Sh		 0x0000000000100000ULL
-#define	TYPE_In		 0x0000000000200000ULL
-#define	TYPE_Ss		 0x0000000000400000ULL
-#define	TYPE_Ox		 0x0000000000800000ULL
-#define	TYPE_An		 0x0000000001000000ULL
-#define	TYPE_Mt		 0x0000000002000000ULL
-#define	TYPE_St		 0x0000000004000000ULL
-#define	TYPE_Bx		 0x0000000008000000ULL
-#define	TYPE_At		 0x0000000010000000ULL
-#define	TYPE_Nx		 0x0000000020000000ULL
-#define	TYPE_Fx		 0x0000000040000000ULL
-#define	TYPE_Lk		 0x0000000080000000ULL
-#define	TYPE_Ms		 0x0000000100000000ULL
-#define	TYPE_Bsx	 0x0000000200000000ULL
-#define	TYPE_Dx		 0x0000000400000000ULL
-#define	TYPE_Rs		 0x0000000800000000ULL
-#define	TYPE_Vt		 0x0000001000000000ULL
-#define	TYPE_Lb		 0x0000002000000000ULL
-#define	TYPE_Nm		 0x0000004000000000ULL
-#define	TYPE_Nd		 0x0000008000000000ULL
-
-#define	NAME_SYN	 0x0000004000000001ULL
-#define	NAME_FIRST	 0x0000004000000004ULL
-#define	NAME_TITLE	 0x0000004000000006ULL
-#define	NAME_HEAD	 0x0000004000000008ULL
-#define	NAME_FILE	 0x0000004000000010ULL
-#define	NAME_MASK	 0x000000000000001fULL
-
-enum	form {
-	FORM_SRC = 1,	/* Format is mdoc(7) or man(7). */
-	FORM_CAT,	/* Manual page is preformatted. */
-	FORM_NONE	/* Format is unknown. */
-};
-
-enum	argmode {
-	ARG_FILE = 0,
-	ARG_NAME,
-	ARG_WORD,
-	ARG_EXPR
-};
-
-struct	manpage {
-	char		*file; /* to be prefixed by manpath */
-	char		*names; /* a list of names with sections */
-	char		*output; /* user-defined additional output */
-	size_t		 ipath; /* number of the manpath */
-	uint64_t	 bits; /* name type mask */
-	int		 sec; /* section number, 10 means invalid */
-	enum form	 form;
-};
-
-struct	mansearch {
-	const char	*arch; /* architecture/NULL */
-	const char	*sec; /* mansection/NULL */
-	const char	*outkey; /* show content of this macro */
-	enum argmode	 argmode; /* interpretation of arguments */
-	int		 firstmatch; /* first matching database only */
-};
-
-
-struct	manpaths;
-
-int	mansearch(const struct mansearch *cfg, /* options */
-		const struct manpaths *paths, /* manpaths */
-		int argc, /* size of argv */
-		char *argv[],  /* search terms */
-		struct manpage **res, /* results */
-		size_t *ressz); /* results returned */
-void	mansearch_free(struct manpage *, size_t);

Property changes on: head/contrib/mdocml/mansearch.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-getline.c
===================================================================
--- head/contrib/mdocml/test-getline.c	(revision 338825)
+++ head/contrib/mdocml/test-getline.c	(nonexistent)
@@ -1,13 +0,0 @@
-#include 
-#include 
-#include 
-
-int
-main(void)
-{
-	char	*line = NULL;
-	size_t	 linesz = 0;
-
-	fclose(stdin);
-	return getline(&line, &linesz, stdin) != -1;
-}

Property changes on: head/contrib/mdocml/test-getline.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/manpath.h
===================================================================
--- head/contrib/mdocml/manpath.h	(revision 338825)
+++ head/contrib/mdocml/manpath.h	(nonexistent)
@@ -1,34 +0,0 @@
-/*	$Id: manpath.h,v 1.7 2014/12/01 04:05:32 schwarze Exp $ */
-/*
- * Copyright (c) 2011 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 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.
- */
-
-/*
- * Unsorted list of unique, absolute paths to be searched for manual
- * databases.
- */
-struct	manpaths {
-	size_t	  sz;
-	char	**paths;
-};
-
-__BEGIN_DECLS
-
-void	 manpath_manconf(struct manpaths *, const char *);
-void	 manpath_parse(struct manpaths *, const char *, char *, char *);
-void	 manpath_free(struct manpaths *);
-
-__END_DECLS

Property changes on: head/contrib/mdocml/manpath.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/term.h
===================================================================
--- head/contrib/mdocml/term.h	(revision 338825)
+++ head/contrib/mdocml/term.h	(nonexistent)
@@ -1,156 +0,0 @@
-/*	$Id: term.h,v 1.130 2017/07/08 14:51:05 schwarze Exp $ */
-/*
- * Copyright (c) 2008, 2009, 2010, 2011 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.
- */
-
-enum	termenc {
-	TERMENC_ASCII,
-	TERMENC_LOCALE,
-	TERMENC_UTF8
-};
-
-enum	termtype {
-	TERMTYPE_CHAR,
-	TERMTYPE_PS,
-	TERMTYPE_PDF
-};
-
-enum	termfont {
-	TERMFONT_NONE = 0,
-	TERMFONT_BOLD,
-	TERMFONT_UNDER,
-	TERMFONT_BI,
-	TERMFONT__MAX
-};
-
-struct	eqn_box;
-struct	roff_meta;
-struct	roff_node;
-struct	tbl_span;
-struct	termp;
-
-typedef void	(*term_margin)(struct termp *, const struct roff_meta *);
-
-struct	termp_tbl {
-	int		  width;	/* width in fixed chars */
-	int		  decimal;	/* decimal point position */
-};
-
-struct	termp_col {
-	int		 *buf;		/* Output buffer. */
-	size_t		  maxcols;	/* Allocated bytes in buf. */
-	size_t		  lastcol;	/* Last byte in buf. */
-	size_t		  col;		/* Byte in buf to be written. */
-	size_t		  rmargin;	/* Current right margin. */
-	size_t		  offset;	/* Current left margin. */
-};
-
-struct	termp {
-	struct rofftbl	  tbl;		/* Table configuration. */
-	struct termp_col *tcols;	/* Array of table columns. */
-	struct termp_col *tcol;		/* Current table column. */
-	size_t		  maxtcol;	/* Allocated table columns. */
-	size_t		  lasttcol;	/* Last column currently used. */
-	size_t		  line;		/* Current output line number. */
-	size_t		  defindent;	/* Default indent for text. */
-	size_t		  defrmargin;	/* Right margin of the device. */
-	size_t		  lastrmargin;	/* Right margin before the last ll. */
-	size_t		  maxrmargin;	/* Max right margin. */
-	size_t		  col;		/* Byte position in buf. */
-	size_t		  viscol;	/* Chars on current line. */
-	size_t		  trailspace;	/* See term_flushln(). */
-	size_t		  minbl;	/* Minimum blanks before next field. */
-	int		  synopsisonly; /* Print the synopsis only. */
-	int		  mdocstyle;	/* Imitate mdoc(7) output. */
-	int		  ti;		/* Temporary indent for one line. */
-	int		  skipvsp;	/* Vertical space to skip. */
-	int		  flags;
-#define	TERMP_SENTENCE	 (1 << 0)	/* Space before a sentence. */
-#define	TERMP_NOSPACE	 (1 << 1)	/* No space before words. */
-#define	TERMP_NONOSPACE	 (1 << 2)	/* No space (no autounset). */
-#define	TERMP_NBRWORD	 (1 << 3)	/* Make next word nonbreaking. */
-#define	TERMP_KEEP	 (1 << 4)	/* Keep words together. */
-#define	TERMP_PREKEEP	 (1 << 5)	/* ...starting with the next one. */
-#define	TERMP_BACKAFTER	 (1 << 6)	/* Back up after next character. */
-#define	TERMP_BACKBEFORE (1 << 7)	/* Back up before next character. */
-#define	TERMP_NOBREAK	 (1 << 8)	/* See term_flushln(). */
-#define	TERMP_BRTRSP	 (1 << 9)	/* See term_flushln(). */
-#define	TERMP_BRIND	 (1 << 10)	/* See term_flushln(). */
-#define	TERMP_HANG	 (1 << 11)	/* See term_flushln(). */
-#define	TERMP_NOPAD	 (1 << 12)	/* See term_flushln(). */
-#define	TERMP_NOSPLIT	 (1 << 13)	/* Do not break line before .An. */
-#define	TERMP_SPLIT	 (1 << 14)	/* Break line before .An. */
-#define	TERMP_NONEWLINE	 (1 << 15)	/* No line break in nofill mode. */
-#define	TERMP_BRNEVER	 (1 << 16)	/* Don't even break at maxrmargin. */
-#define	TERMP_NOBUF	 (1 << 17)	/* Bypass output buffer. */
-#define	TERMP_NEWMC	 (1 << 18)	/* No .mc printed yet. */
-#define	TERMP_ENDMC	 (1 << 19)	/* Next break ends .mc mode. */
-#define	TERMP_MULTICOL	 (1 << 20)	/* Multiple column mode. */
-	enum termtype	  type;		/* Terminal, PS, or PDF. */
-	enum termenc	  enc;		/* Type of encoding. */
-	enum termfont	  fontl;	/* Last font set. */
-	enum termfont	 *fontq;	/* Symmetric fonts. */
-	int		  fontsz;	/* Allocated size of font stack */
-	int		  fonti;	/* Index of font stack. */
-	term_margin	  headf;	/* invoked to print head */
-	term_margin	  footf;	/* invoked to print foot */
-	void		(*letter)(struct termp *, int);
-	void		(*begin)(struct termp *);
-	void		(*end)(struct termp *);
-	void		(*endline)(struct termp *);
-	void		(*advance)(struct termp *, size_t);
-	void		(*setwidth)(struct termp *, int, int);
-	size_t		(*width)(const struct termp *, int);
-	int		(*hspan)(const struct termp *,
-				const struct roffsu *);
-	const void	 *argf;		/* arg for headf/footf */
-	const char	 *mc;		/* Margin character. */
-	struct termp_ps	 *ps;
-};
-
-
-const char	 *ascii_uc2str(int);
-
-void		  roff_term_pre(struct termp *, const struct roff_node *);
-
-void		  term_eqn(struct termp *, const struct eqn_box *);
-void		  term_tbl(struct termp *, const struct tbl_span *);
-void		  term_free(struct termp *);
-void		  term_setcol(struct termp *, size_t);
-void		  term_newln(struct termp *);
-void		  term_vspace(struct termp *);
-void		  term_word(struct termp *, const char *);
-void		  term_flushln(struct termp *);
-void		  term_begin(struct termp *, term_margin,
-			term_margin, const struct roff_meta *);
-void		  term_end(struct termp *);
-
-void		  term_setwidth(struct termp *, const char *);
-int		  term_hspan(const struct termp *, const struct roffsu *);
-int		  term_hen(const struct termp *, const struct roffsu *);
-int		  term_vspan(const struct termp *, const struct roffsu *);
-size_t		  term_strlen(const struct termp *, const char *);
-size_t		  term_len(const struct termp *, size_t);
-
-void		  term_tab_set(const struct termp *, const char *);
-void		  term_tab_iset(size_t);
-size_t		  term_tab_next(size_t);
-
-void		  term_fontpush(struct termp *, enum termfont);
-void		  term_fontpop(struct termp *);
-void		  term_fontpopq(struct termp *, int);
-void		  term_fontrepl(struct termp *, enum termfont);
-void		  term_fontlast(struct termp *);

Property changes on: head/contrib/mdocml/term.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mdoc_man.c
===================================================================
--- head/contrib/mdocml/mdoc_man.c	(revision 338825)
+++ head/contrib/mdocml/mdoc_man.c	(nonexistent)
@@ -1,1804 +0,0 @@
-/*	$Id: mdoc_man.c,v 1.122 2017/06/14 22:51:25 schwarze Exp $ */
-/*
- * Copyright (c) 2011-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.
- */
-#include "config.h"
-
-#include 
-
-#include 
-#include 
-#include 
-#include 
-
-#include "mandoc_aux.h"
-#include "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "man.h"
-#include "out.h"
-#include "main.h"
-
-#define	DECL_ARGS const struct roff_meta *meta, struct roff_node *n
-
-typedef	int	(*int_fp)(DECL_ARGS);
-typedef	void	(*void_fp)(DECL_ARGS);
-
-struct	manact {
-	int_fp		  cond; /* DON'T run actions */
-	int_fp		  pre; /* pre-node action */
-	void_fp		  post; /* post-node action */
-	const char	 *prefix; /* pre-node string constant */
-	const char	 *suffix; /* post-node string constant */
-};
-
-static	int	  cond_body(DECL_ARGS);
-static	int	  cond_head(DECL_ARGS);
-static  void	  font_push(char);
-static	void	  font_pop(void);
-static	int	  man_strlen(const char *);
-static	void	  mid_it(void);
-static	void	  post__t(DECL_ARGS);
-static	void	  post_aq(DECL_ARGS);
-static	void	  post_bd(DECL_ARGS);
-static	void	  post_bf(DECL_ARGS);
-static	void	  post_bk(DECL_ARGS);
-static	void	  post_bl(DECL_ARGS);
-static	void	  post_dl(DECL_ARGS);
-static	void	  post_en(DECL_ARGS);
-static	void	  post_enc(DECL_ARGS);
-static	void	  post_eo(DECL_ARGS);
-static	void	  post_fa(DECL_ARGS);
-static	void	  post_fd(DECL_ARGS);
-static	void	  post_fl(DECL_ARGS);
-static	void	  post_fn(DECL_ARGS);
-static	void	  post_fo(DECL_ARGS);
-static	void	  post_font(DECL_ARGS);
-static	void	  post_in(DECL_ARGS);
-static	void	  post_it(DECL_ARGS);
-static	void	  post_lb(DECL_ARGS);
-static	void	  post_nm(DECL_ARGS);
-static	void	  post_percent(DECL_ARGS);
-static	void	  post_pf(DECL_ARGS);
-static	void	  post_sect(DECL_ARGS);
-static	void	  post_vt(DECL_ARGS);
-static	int	  pre__t(DECL_ARGS);
-static	int	  pre_an(DECL_ARGS);
-static	int	  pre_ap(DECL_ARGS);
-static	int	  pre_aq(DECL_ARGS);
-static	int	  pre_bd(DECL_ARGS);
-static	int	  pre_bf(DECL_ARGS);
-static	int	  pre_bk(DECL_ARGS);
-static	int	  pre_bl(DECL_ARGS);
-static	void	  pre_br(DECL_ARGS);
-static	int	  pre_dl(DECL_ARGS);
-static	int	  pre_en(DECL_ARGS);
-static	int	  pre_enc(DECL_ARGS);
-static	int	  pre_em(DECL_ARGS);
-static	int	  pre_skip(DECL_ARGS);
-static	int	  pre_eo(DECL_ARGS);
-static	int	  pre_ex(DECL_ARGS);
-static	int	  pre_fa(DECL_ARGS);
-static	int	  pre_fd(DECL_ARGS);
-static	int	  pre_fl(DECL_ARGS);
-static	int	  pre_fn(DECL_ARGS);
-static	int	  pre_fo(DECL_ARGS);
-static	void	  pre_ft(DECL_ARGS);
-static	int	  pre_Ft(DECL_ARGS);
-static	int	  pre_in(DECL_ARGS);
-static	int	  pre_it(DECL_ARGS);
-static	int	  pre_lk(DECL_ARGS);
-static	int	  pre_li(DECL_ARGS);
-static	int	  pre_nm(DECL_ARGS);
-static	int	  pre_no(DECL_ARGS);
-static	int	  pre_ns(DECL_ARGS);
-static	void	  pre_onearg(DECL_ARGS);
-static	int	  pre_pp(DECL_ARGS);
-static	int	  pre_rs(DECL_ARGS);
-static	int	  pre_sm(DECL_ARGS);
-static	void	  pre_sp(DECL_ARGS);
-static	int	  pre_sect(DECL_ARGS);
-static	int	  pre_sy(DECL_ARGS);
-static	void	  pre_syn(const struct roff_node *);
-static	void	  pre_ta(DECL_ARGS);
-static	int	  pre_vt(DECL_ARGS);
-static	int	  pre_xr(DECL_ARGS);
-static	void	  print_word(const char *);
-static	void	  print_line(const char *, int);
-static	void	  print_block(const char *, int);
-static	void	  print_offs(const char *, int);
-static	void	  print_width(const struct mdoc_bl *,
-			const struct roff_node *);
-static	void	  print_count(int *);
-static	void	  print_node(DECL_ARGS);
-
-static	const void_fp roff_manacts[ROFF_MAX] = {
-	pre_br,		/* br */
-	pre_onearg,	/* ce */
-	pre_ft,		/* ft */
-	pre_onearg,	/* ll */
-	pre_onearg,	/* mc */
-	pre_onearg,	/* po */
-	pre_onearg,	/* rj */
-	pre_sp,		/* sp */
-	pre_ta,		/* ta */
-	pre_onearg,	/* ti */
-};
-
-static	const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
-	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
-	{ NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
-	{ NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
-	{ NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
-	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
-	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
-	{ cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
-	{ cond_body, pre_bl, post_bl, NULL, NULL }, /* Bl */
-	{ NULL, NULL, NULL, NULL, NULL }, /* El */
-	{ NULL, pre_it, post_it, NULL, NULL }, /* It */
-	{ NULL, pre_em, post_font, NULL, NULL }, /* Ad */
-	{ NULL, pre_an, NULL, NULL, NULL }, /* An */
-	{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
-	{ NULL, pre_em, post_font, NULL, NULL }, /* Ar */
-	{ NULL, pre_sy, post_font, NULL, NULL }, /* Cd */
-	{ NULL, pre_sy, post_font, NULL, NULL }, /* Cm */
-	{ NULL, pre_li, post_font, NULL, NULL }, /* Dv */
-	{ NULL, pre_li, post_font, NULL, NULL }, /* Er */
-	{ NULL, pre_li, post_font, NULL, NULL }, /* Ev */
-	{ NULL, pre_ex, NULL, NULL, NULL }, /* Ex */
-	{ NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */
-	{ NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */
-	{ NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */
-	{ NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */
-	{ NULL, pre_Ft, post_font, NULL, NULL }, /* Ft */
-	{ NULL, pre_sy, post_font, NULL, NULL }, /* Ic */
-	{ NULL, pre_in, post_in, NULL, NULL }, /* In */
-	{ NULL, pre_li, post_font, NULL, NULL }, /* Li */
-	{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
-	{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
-	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
-	{ NULL, pre_Ft, post_font, NULL, NULL }, /* Ot */
-	{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
-	{ NULL, pre_ex, NULL, NULL, NULL }, /* Rv */
-	{ NULL, NULL, NULL, NULL, NULL }, /* St */
-	{ NULL, pre_em, post_font, NULL, NULL }, /* Va */
-	{ NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */
-	{ NULL, pre_xr, NULL, NULL, NULL }, /* Xr */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %A */
-	{ NULL, pre_em, post_percent, NULL, NULL }, /* %B */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %D */
-	{ NULL, pre_em, post_percent, NULL, NULL }, /* %I */
-	{ NULL, pre_em, post_percent, NULL, NULL }, /* %J */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %N */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %O */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %P */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %R */
-	{ NULL, pre__t, post__t, NULL, NULL }, /* %T */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %V */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
-	{ cond_body, pre_aq, post_aq, NULL, NULL }, /* Ao */
-	{ cond_body, pre_aq, post_aq, NULL, NULL }, /* Aq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* At */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
-	{ NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */
-	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
-	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
-	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bsx */
-	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bx */
-	{ NULL, pre_skip, NULL, NULL, NULL }, /* Db */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
-	{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Do */
-	{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Dq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
-	{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
-	{ cond_body, pre_eo, post_eo, NULL, NULL }, /* Eo */
-	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Fx */
-	{ NULL, pre_sy, post_font, NULL, NULL }, /* Ms */
-	{ NULL, pre_no, NULL, NULL, NULL }, /* No */
-	{ NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
-	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Nx */
-	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Ox */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
-	{ NULL, NULL, post_pf, NULL, NULL }, /* Pf */
-	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
-	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
-	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Ql */
-	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */
-	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
-	{ cond_body, pre_rs, NULL, NULL, NULL }, /* Rs */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
-	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* So */
-	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Sq */
-	{ NULL, pre_sm, NULL, NULL, NULL }, /* Sm */
-	{ NULL, pre_em, post_font, NULL, NULL }, /* Sx */
-	{ NULL, pre_sy, post_font, NULL, NULL }, /* Sy */
-	{ NULL, pre_li, post_font, NULL, NULL }, /* Tn */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ux */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Xc */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Xo */
-	{ NULL, pre_fo, post_fo, NULL, NULL }, /* Fo */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Fc */
-	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
-	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bk */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Bt */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
-	{ NULL, pre_em, post_font, NULL, NULL }, /* Fr */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
-	{ NULL, NULL, post_lb, NULL, NULL }, /* Lb */
-	{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
-	{ NULL, pre_lk, NULL, NULL, NULL }, /* Lk */
-	{ NULL, pre_em, post_font, NULL, NULL }, /* Mt */
-	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
-	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %C */
-	{ NULL, pre_skip, NULL, NULL, NULL }, /* Es */
-	{ cond_body, pre_en, post_en, NULL, NULL }, /* En */
-	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Dx */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %Q */
-	{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
-	{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
-};
-static	const struct manact *const manacts = __manacts - MDOC_Dd;
-
-static	int		outflags;
-#define	MMAN_spc	(1 << 0)  /* blank character before next word */
-#define	MMAN_spc_force	(1 << 1)  /* even before trailing punctuation */
-#define	MMAN_nl		(1 << 2)  /* break man(7) code line */
-#define	MMAN_br		(1 << 3)  /* break output line */
-#define	MMAN_sp		(1 << 4)  /* insert a blank output line */
-#define	MMAN_PP		(1 << 5)  /* reset indentation etc. */
-#define	MMAN_Sm		(1 << 6)  /* horizontal spacing mode */
-#define	MMAN_Bk		(1 << 7)  /* word keep mode */
-#define	MMAN_Bk_susp	(1 << 8)  /* suspend this (after a macro) */
-#define	MMAN_An_split	(1 << 9)  /* author mode is "split" */
-#define	MMAN_An_nosplit	(1 << 10) /* author mode is "nosplit" */
-#define	MMAN_PD		(1 << 11) /* inter-paragraph spacing disabled */
-#define	MMAN_nbrword	(1 << 12) /* do not break the next word */
-
-#define	BL_STACK_MAX	32
-
-static	int		Bl_stack[BL_STACK_MAX];  /* offsets [chars] */
-static	int		Bl_stack_post[BL_STACK_MAX];  /* add final .RE */
-static	int		Bl_stack_len;  /* number of nested Bl blocks */
-static	int		TPremain;  /* characters before tag is full */
-
-static	struct {
-	char	*head;
-	char	*tail;
-	size_t	 size;
-}	fontqueue;
-
-
-static int
-man_strlen(const char *cp)
-{
-	size_t	 rsz;
-	int	 skip, sz;
-
-	sz = 0;
-	skip = 0;
-	for (;;) {
-		rsz = strcspn(cp, "\\");
-		if (rsz) {
-			cp += rsz;
-			if (skip) {
-				skip = 0;
-				rsz--;
-			}
-			sz += rsz;
-		}
-		if ('\0' == *cp)
-			break;
-		cp++;
-		switch (mandoc_escape(&cp, NULL, NULL)) {
-		case ESCAPE_ERROR:
-			return sz;
-		case ESCAPE_UNICODE:
-		case ESCAPE_NUMBERED:
-		case ESCAPE_SPECIAL:
-		case ESCAPE_OVERSTRIKE:
-			if (skip)
-				skip = 0;
-			else
-				sz++;
-			break;
-		case ESCAPE_SKIPCHAR:
-			skip = 1;
-			break;
-		default:
-			break;
-		}
-	}
-	return sz;
-}
-
-static void
-font_push(char newfont)
-{
-
-	if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) {
-		fontqueue.size += 8;
-		fontqueue.head = mandoc_realloc(fontqueue.head,
-		    fontqueue.size);
-	}
-	*fontqueue.tail = newfont;
-	print_word("");
-	printf("\\f");
-	putchar(newfont);
-	outflags &= ~MMAN_spc;
-}
-
-static void
-font_pop(void)
-{
-
-	if (fontqueue.tail > fontqueue.head)
-		fontqueue.tail--;
-	outflags &= ~MMAN_spc;
-	print_word("");
-	printf("\\f");
-	putchar(*fontqueue.tail);
-}
-
-static void
-print_word(const char *s)
-{
-
-	if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) {
-		/*
-		 * If we need a newline, print it now and start afresh.
-		 */
-		if (MMAN_PP & outflags) {
-			if (MMAN_sp & outflags) {
-				if (MMAN_PD & outflags) {
-					printf("\n.PD");
-					outflags &= ~MMAN_PD;
-				}
-			} else if ( ! (MMAN_PD & outflags)) {
-				printf("\n.PD 0");
-				outflags |= MMAN_PD;
-			}
-			printf("\n.PP\n");
-		} else if (MMAN_sp & outflags)
-			printf("\n.sp\n");
-		else if (MMAN_br & outflags)
-			printf("\n.br\n");
-		else if (MMAN_nl & outflags)
-			putchar('\n');
-		outflags &= ~(MMAN_PP|MMAN_sp|MMAN_br|MMAN_nl|MMAN_spc);
-		if (1 == TPremain)
-			printf(".br\n");
-		TPremain = 0;
-	} else if (MMAN_spc & outflags) {
-		/*
-		 * If we need a space, only print it if
-		 * (1) it is forced by `No' or
-		 * (2) what follows is not terminating punctuation or
-		 * (3) what follows is longer than one character.
-		 */
-		if (MMAN_spc_force & outflags || '\0' == s[0] ||
-		    NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) {
-			if (MMAN_Bk & outflags &&
-			    ! (MMAN_Bk_susp & outflags))
-				putchar('\\');
-			putchar(' ');
-			if (TPremain)
-				TPremain--;
-		}
-	}
-
-	/*
-	 * Reassign needing space if we're not following opening
-	 * punctuation.
-	 */
-	if (MMAN_Sm & outflags && ('\0' == s[0] ||
-	    (('(' != s[0] && '[' != s[0]) || '\0' != s[1])))
-		outflags |= MMAN_spc;
-	else
-		outflags &= ~MMAN_spc;
-	outflags &= ~(MMAN_spc_force | MMAN_Bk_susp);
-
-	for ( ; *s; s++) {
-		switch (*s) {
-		case ASCII_NBRSP:
-			printf("\\ ");
-			break;
-		case ASCII_HYPH:
-			putchar('-');
-			break;
-		case ASCII_BREAK:
-			printf("\\:");
-			break;
-		case ' ':
-			if (MMAN_nbrword & outflags) {
-				printf("\\ ");
-				break;
-			}
-			/* FALLTHROUGH */
-		default:
-			putchar((unsigned char)*s);
-			break;
-		}
-		if (TPremain)
-			TPremain--;
-	}
-	outflags &= ~MMAN_nbrword;
-}
-
-static void
-print_line(const char *s, int newflags)
-{
-
-	outflags |= MMAN_nl;
-	print_word(s);
-	outflags |= newflags;
-}
-
-static void
-print_block(const char *s, int newflags)
-{
-
-	outflags &= ~MMAN_PP;
-	if (MMAN_sp & outflags) {
-		outflags &= ~(MMAN_sp | MMAN_br);
-		if (MMAN_PD & outflags) {
-			print_line(".PD", 0);
-			outflags &= ~MMAN_PD;
-		}
-	} else if (! (MMAN_PD & outflags))
-		print_line(".PD 0", MMAN_PD);
-	outflags |= MMAN_nl;
-	print_word(s);
-	outflags |= MMAN_Bk_susp | newflags;
-}
-
-static void
-print_offs(const char *v, int keywords)
-{
-	char		  buf[24];
-	struct roffsu	  su;
-	const char	 *end;
-	int		  sz;
-
-	print_line(".RS", MMAN_Bk_susp);
-
-	/* Convert v into a number (of characters). */
-	if (NULL == v || '\0' == *v || (keywords && !strcmp(v, "left")))
-		sz = 0;
-	else if (keywords && !strcmp(v, "indent"))
-		sz = 6;
-	else if (keywords && !strcmp(v, "indent-two"))
-		sz = 12;
-	else {
-		end = a2roffsu(v, &su, SCALE_EN);
-		if (end == NULL || *end != '\0')
-			sz = man_strlen(v);
-		else if (SCALE_EN == su.unit)
-			sz = su.scale;
-		else {
-			/*
-			 * XXX
-			 * If we are inside an enclosing list,
-			 * there is no easy way to add the two
-			 * indentations because they are provided
-			 * in terms of different units.
-			 */
-			print_word(v);
-			outflags |= MMAN_nl;
-			return;
-		}
-	}
-
-	/*
-	 * We are inside an enclosing list.
-	 * Add the two indentations.
-	 */
-	if (Bl_stack_len)
-		sz += Bl_stack[Bl_stack_len - 1];
-
-	(void)snprintf(buf, sizeof(buf), "%dn", sz);
-	print_word(buf);
-	outflags |= MMAN_nl;
-}
-
-/*
- * Set up the indentation for a list item; used from pre_it().
- */
-static void
-print_width(const struct mdoc_bl *bl, const struct roff_node *child)
-{
-	char		  buf[24];
-	struct roffsu	  su;
-	const char	 *end;
-	int		  numeric, remain, sz, chsz;
-
-	numeric = 1;
-	remain = 0;
-
-	/* Convert the width into a number (of characters). */
-	if (bl->width == NULL)
-		sz = (bl->type == LIST_hang) ? 6 : 0;
-	else {
-		end = a2roffsu(bl->width, &su, SCALE_MAX);
-		if (end == NULL || *end != '\0')
-			sz = man_strlen(bl->width);
-		else if (SCALE_EN == su.unit)
-			sz = su.scale;
-		else {
-			sz = 0;
-			numeric = 0;
-		}
-	}
-
-	/* XXX Rough estimation, might have multiple parts. */
-	if (bl->type == LIST_enum)
-		chsz = (bl->count > 8) + 1;
-	else if (child != NULL && child->type == ROFFT_TEXT)
-		chsz = man_strlen(child->string);
-	else
-		chsz = 0;
-
-	/* Maybe we are inside an enclosing list? */
-	mid_it();
-
-	/*
-	 * Save our own indentation,
-	 * such that child lists can use it.
-	 */
-	Bl_stack[Bl_stack_len++] = sz + 2;
-
-	/* Set up the current list. */
-	if (chsz > sz && bl->type != LIST_tag)
-		print_block(".HP", 0);
-	else {
-		print_block(".TP", 0);
-		remain = sz + 2;
-	}
-	if (numeric) {
-		(void)snprintf(buf, sizeof(buf), "%dn", sz + 2);
-		print_word(buf);
-	} else
-		print_word(bl->width);
-	TPremain = remain;
-}
-
-static void
-print_count(int *count)
-{
-	char		  buf[24];
-
-	(void)snprintf(buf, sizeof(buf), "%d.\\&", ++*count);
-	print_word(buf);
-}
-
-void
-man_man(void *arg, const struct roff_man *man)
-{
-
-	/*
-	 * Dump the keep buffer.
-	 * We're guaranteed by now that this exists (is non-NULL).
-	 * Flush stdout afterward, just in case.
-	 */
-	fputs(mparse_getkeep(man_mparse(man)), stdout);
-	fflush(stdout);
-}
-
-void
-man_mdoc(void *arg, const struct roff_man *mdoc)
-{
-	struct roff_node *n;
-
-	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
-	    mdoc->meta.title,
-	    (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
-	    mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);
-
-	/* Disable hyphenation and if nroff, disable justification. */
-	printf(".nh\n.if n .ad l");
-
-	outflags = MMAN_nl | MMAN_Sm;
-	if (0 == fontqueue.size) {
-		fontqueue.size = 8;
-		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
-		*fontqueue.tail = 'R';
-	}
-	for (n = mdoc->first->child; n != NULL; n = n->next)
-		print_node(&mdoc->meta, n);
-	putchar('\n');
-}
-
-static void
-print_node(DECL_ARGS)
-{
-	const struct manact	*act;
-	struct roff_node	*sub;
-	int			 cond, do_sub;
-
-	if (n->flags & NODE_NOPRT)
-		return;
-
-	/*
-	 * Break the line if we were parsed subsequent the current node.
-	 * This makes the page structure be more consistent.
-	 */
-	if (MMAN_spc & outflags && NODE_LINE & n->flags)
-		outflags |= MMAN_nl;
-
-	act = NULL;
-	cond = 0;
-	do_sub = 1;
-	n->flags &= ~NODE_ENDED;
-
-	if (n->type == ROFFT_TEXT) {
-		/*
-		 * Make sure that we don't happen to start with a
-		 * control character at the start of a line.
-		 */
-		if (MMAN_nl & outflags &&
-		    ('.' == *n->string || '\'' == *n->string)) {
-			print_word("");
-			printf("\\&");
-			outflags &= ~MMAN_spc;
-		}
-		if (n->flags & NODE_DELIMC)
-			outflags &= ~(MMAN_spc | MMAN_spc_force);
-		else if (outflags & MMAN_Sm)
-			outflags |= MMAN_spc_force;
-		print_word(n->string);
-		if (n->flags & NODE_DELIMO)
-			outflags &= ~(MMAN_spc | MMAN_spc_force);
-		else if (outflags & MMAN_Sm)
-			outflags |= MMAN_spc;
-	} else if (n->tok < ROFF_MAX) {
-		(*roff_manacts[n->tok])(meta, n);
-		return;
-	} else {
-		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
-		/*
-		 * Conditionally run the pre-node action handler for a
-		 * node.
-		 */
-		act = manacts + n->tok;
-		cond = act->cond == NULL || (*act->cond)(meta, n);
-		if (cond && act->pre != NULL &&
-		    (n->end == ENDBODY_NOT || n->child != NULL))
-			do_sub = (*act->pre)(meta, n);
-	}
-
-	/*
-	 * Conditionally run all child nodes.
-	 * Note that this iterates over children instead of using
-	 * recursion.  This prevents unnecessary depth in the stack.
-	 */
-	if (do_sub)
-		for (sub = n->child; sub; sub = sub->next)
-			print_node(meta, sub);
-
-	/*
-	 * Lastly, conditionally run the post-node handler.
-	 */
-	if (NODE_ENDED & n->flags)
-		return;
-
-	if (cond && act->post)
-		(*act->post)(meta, n);
-
-	if (ENDBODY_NOT != n->end)
-		n->body->flags |= NODE_ENDED;
-}
-
-static int
-cond_head(DECL_ARGS)
-{
-
-	return n->type == ROFFT_HEAD;
-}
-
-static int
-cond_body(DECL_ARGS)
-{
-
-	return n->type == ROFFT_BODY;
-}
-
-static int
-pre_enc(DECL_ARGS)
-{
-	const char	*prefix;
-
-	prefix = manacts[n->tok].prefix;
-	if (NULL == prefix)
-		return 1;
-	print_word(prefix);
-	outflags &= ~MMAN_spc;
-	return 1;
-}
-
-static void
-post_enc(DECL_ARGS)
-{
-	const char *suffix;
-
-	suffix = manacts[n->tok].suffix;
-	if (NULL == suffix)
-		return;
-	outflags &= ~(MMAN_spc | MMAN_nl);
-	print_word(suffix);
-}
-
-static int
-pre_ex(DECL_ARGS)
-{
-	outflags |= MMAN_br | MMAN_nl;
-	return 1;
-}
-
-static void
-post_font(DECL_ARGS)
-{
-
-	font_pop();
-}
-
-static void
-post_percent(DECL_ARGS)
-{
-
-	if (pre_em == manacts[n->tok].pre)
-		font_pop();
-	if (n->next) {
-		print_word(",");
-		if (n->prev &&	n->prev->tok == n->tok &&
-				n->next->tok == n->tok)
-			print_word("and");
-	} else {
-		print_word(".");
-		outflags |= MMAN_nl;
-	}
-}
-
-static int
-pre__t(DECL_ARGS)
-{
-
-	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) {
-		print_word("\\(lq");
-		outflags &= ~MMAN_spc;
-	} else
-		font_push('I');
-	return 1;
-}
-
-static void
-post__t(DECL_ARGS)
-{
-
-	if (n->parent->tok  == MDOC_Rs && n->parent->norm->Rs.quote_T) {
-		outflags &= ~MMAN_spc;
-		print_word("\\(rq");
-	} else
-		font_pop();
-	post_percent(meta, n);
-}
-
-/*
- * Print before a section header.
- */
-static int
-pre_sect(DECL_ARGS)
-{
-
-	if (n->type == ROFFT_HEAD) {
-		outflags |= MMAN_sp;
-		print_block(manacts[n->tok].prefix, 0);
-		print_word("");
-		putchar('\"');
-		outflags &= ~MMAN_spc;
-	}
-	return 1;
-}
-
-/*
- * Print subsequent a section header.
- */
-static void
-post_sect(DECL_ARGS)
-{
-
-	if (n->type != ROFFT_HEAD)
-		return;
-	outflags &= ~MMAN_spc;
-	print_word("");
-	putchar('\"');
-	outflags |= MMAN_nl;
-	if (MDOC_Sh == n->tok && SEC_AUTHORS == n->sec)
-		outflags &= ~(MMAN_An_split | MMAN_An_nosplit);
-}
-
-/* See mdoc_term.c, synopsis_pre() for comments. */
-static void
-pre_syn(const struct roff_node *n)
-{
-
-	if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
-		return;
-
-	if (n->prev->tok == n->tok &&
-	    MDOC_Ft != n->tok &&
-	    MDOC_Fo != n->tok &&
-	    MDOC_Fn != n->tok) {
-		outflags |= MMAN_br;
-		return;
-	}
-
-	switch (n->prev->tok) {
-	case MDOC_Fd:
-	case MDOC_Fn:
-	case MDOC_Fo:
-	case MDOC_In:
-	case MDOC_Vt:
-		outflags |= MMAN_sp;
-		break;
-	case MDOC_Ft:
-		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
-			outflags |= MMAN_sp;
-			break;
-		}
-		/* FALLTHROUGH */
-	default:
-		outflags |= MMAN_br;
-		break;
-	}
-}
-
-static int
-pre_an(DECL_ARGS)
-{
-
-	switch (n->norm->An.auth) {
-	case AUTH_split:
-		outflags &= ~MMAN_An_nosplit;
-		outflags |= MMAN_An_split;
-		return 0;
-	case AUTH_nosplit:
-		outflags &= ~MMAN_An_split;
-		outflags |= MMAN_An_nosplit;
-		return 0;
-	default:
-		if (MMAN_An_split & outflags)
-			outflags |= MMAN_br;
-		else if (SEC_AUTHORS == n->sec &&
-		    ! (MMAN_An_nosplit & outflags))
-			outflags |= MMAN_An_split;
-		return 1;
-	}
-}
-
-static int
-pre_ap(DECL_ARGS)
-{
-
-	outflags &= ~MMAN_spc;
-	print_word("'");
-	outflags &= ~MMAN_spc;
-	return 0;
-}
-
-static int
-pre_aq(DECL_ARGS)
-{
-
-	print_word(n->child != NULL && n->child->next == NULL &&
-	    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
-	outflags &= ~MMAN_spc;
-	return 1;
-}
-
-static void
-post_aq(DECL_ARGS)
-{
-
-	outflags &= ~(MMAN_spc | MMAN_nl);
-	print_word(n->child != NULL && n->child->next == NULL &&
-	    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
-}
-
-static int
-pre_bd(DECL_ARGS)
-{
-
-	outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br);
-
-	if (DISP_unfilled == n->norm->Bd.type ||
-	    DISP_literal  == n->norm->Bd.type)
-		print_line(".nf", 0);
-	if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
-		outflags |= MMAN_sp;
-	print_offs(n->norm->Bd.offs, 1);
-	return 1;
-}
-
-static void
-post_bd(DECL_ARGS)
-{
-
-	/* Close out this display. */
-	print_line(".RE", MMAN_nl);
-	if (DISP_unfilled == n->norm->Bd.type ||
-	    DISP_literal  == n->norm->Bd.type)
-		print_line(".fi", MMAN_nl);
-
-	/* Maybe we are inside an enclosing list? */
-	if (NULL != n->parent->next)
-		mid_it();
-}
-
-static int
-pre_bf(DECL_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		return 1;
-	case ROFFT_BODY:
-		break;
-	default:
-		return 0;
-	}
-	switch (n->norm->Bf.font) {
-	case FONT_Em:
-		font_push('I');
-		break;
-	case FONT_Sy:
-		font_push('B');
-		break;
-	default:
-		font_push('R');
-		break;
-	}
-	return 1;
-}
-
-static void
-post_bf(DECL_ARGS)
-{
-
-	if (n->type == ROFFT_BODY)
-		font_pop();
-}
-
-static int
-pre_bk(DECL_ARGS)
-{
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		return 1;
-	case ROFFT_BODY:
-	case ROFFT_ELEM:
-		outflags |= MMAN_Bk;
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-static void
-post_bk(DECL_ARGS)
-{
-	switch (n->type) {
-	case ROFFT_ELEM:
-		while ((n = n->parent) != NULL)
-			 if (n->tok == MDOC_Bk)
-				return;
-		/* FALLTHROUGH */
-	case ROFFT_BODY:
-		outflags &= ~MMAN_Bk;
-		break;
-	default:
-		break;
-	}
-}
-
-static int
-pre_bl(DECL_ARGS)
-{
-	size_t		 icol;
-
-	/*
-	 * print_offs() will increase the -offset to account for
-	 * a possible enclosing .It, but any enclosed .It blocks
-	 * just nest and do not add up their indentation.
-	 */
-	if (n->norm->Bl.offs) {
-		print_offs(n->norm->Bl.offs, 0);
-		Bl_stack[Bl_stack_len++] = 0;
-	}
-
-	switch (n->norm->Bl.type) {
-	case LIST_enum:
-		n->norm->Bl.count = 0;
-		return 1;
-	case LIST_column:
-		break;
-	default:
-		return 1;
-	}
-
-	if (n->child != NULL) {
-		print_line(".TS", MMAN_nl);
-		for (icol = 0; icol < n->norm->Bl.ncols; icol++)
-			print_word("l");
-		print_word(".");
-	}
-	outflags |= MMAN_nl;
-	return 1;
-}
-
-static void
-post_bl(DECL_ARGS)
-{
-
-	switch (n->norm->Bl.type) {
-	case LIST_column:
-		if (n->child != NULL)
-			print_line(".TE", 0);
-		break;
-	case LIST_enum:
-		n->norm->Bl.count = 0;
-		break;
-	default:
-		break;
-	}
-
-	if (n->norm->Bl.offs) {
-		print_line(".RE", MMAN_nl);
-		assert(Bl_stack_len);
-		Bl_stack_len--;
-		assert(0 == Bl_stack[Bl_stack_len]);
-	} else {
-		outflags |= MMAN_PP | MMAN_nl;
-		outflags &= ~(MMAN_sp | MMAN_br);
-	}
-
-	/* Maybe we are inside an enclosing list? */
-	if (NULL != n->parent->next)
-		mid_it();
-
-}
-
-static void
-pre_br(DECL_ARGS)
-{
-	outflags |= MMAN_br;
-}
-
-static int
-pre_dl(DECL_ARGS)
-{
-
-	print_offs("6n", 0);
-	return 1;
-}
-
-static void
-post_dl(DECL_ARGS)
-{
-
-	print_line(".RE", MMAN_nl);
-
-	/* Maybe we are inside an enclosing list? */
-	if (NULL != n->parent->next)
-		mid_it();
-}
-
-static int
-pre_em(DECL_ARGS)
-{
-
-	font_push('I');
-	return 1;
-}
-
-static int
-pre_en(DECL_ARGS)
-{
-
-	if (NULL == n->norm->Es ||
-	    NULL == n->norm->Es->child)
-		return 1;
-
-	print_word(n->norm->Es->child->string);
-	outflags &= ~MMAN_spc;
-	return 1;
-}
-
-static void
-post_en(DECL_ARGS)
-{
-
-	if (NULL == n->norm->Es ||
-	    NULL == n->norm->Es->child ||
-	    NULL == n->norm->Es->child->next)
-		return;
-
-	outflags &= ~MMAN_spc;
-	print_word(n->norm->Es->child->next->string);
-	return;
-}
-
-static int
-pre_eo(DECL_ARGS)
-{
-
-	if (n->end == ENDBODY_NOT &&
-	    n->parent->head->child == NULL &&
-	    n->child != NULL &&
-	    n->child->end != ENDBODY_NOT)
-		print_word("\\&");
-	else if (n->end != ENDBODY_NOT ? n->child != NULL :
-	    n->parent->head->child != NULL && (n->child != NULL ||
-	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
-		outflags &= ~(MMAN_spc | MMAN_nl);
-	return 1;
-}
-
-static void
-post_eo(DECL_ARGS)
-{
-	int	 body, tail;
-
-	if (n->end != ENDBODY_NOT) {
-		outflags |= MMAN_spc;
-		return;
-	}
-
-	body = n->child != NULL || n->parent->head->child != NULL;
-	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
-
-	if (body && tail)
-		outflags &= ~MMAN_spc;
-	else if ( ! (body || tail))
-		print_word("\\&");
-	else if ( ! tail)
-		outflags |= MMAN_spc;
-}
-
-static int
-pre_fa(DECL_ARGS)
-{
-	int	 am_Fa;
-
-	am_Fa = MDOC_Fa == n->tok;
-
-	if (am_Fa)
-		n = n->child;
-
-	while (NULL != n) {
-		font_push('I');
-		if (am_Fa || NODE_SYNPRETTY & n->flags)
-			outflags |= MMAN_nbrword;
-		print_node(meta, n);
-		font_pop();
-		if (NULL != (n = n->next))
-			print_word(",");
-	}
-	return 0;
-}
-
-static void
-post_fa(DECL_ARGS)
-{
-
-	if (NULL != n->next && MDOC_Fa == n->next->tok)
-		print_word(",");
-}
-
-static int
-pre_fd(DECL_ARGS)
-{
-
-	pre_syn(n);
-	font_push('B');
-	return 1;
-}
-
-static void
-post_fd(DECL_ARGS)
-{
-
-	font_pop();
-	outflags |= MMAN_br;
-}
-
-static int
-pre_fl(DECL_ARGS)
-{
-
-	font_push('B');
-	print_word("\\-");
-	if (n->child != NULL)
-		outflags &= ~MMAN_spc;
-	return 1;
-}
-
-static void
-post_fl(DECL_ARGS)
-{
-
-	font_pop();
-	if (!(n->child != NULL ||
-	    n->next == NULL ||
-	    n->next->type == ROFFT_TEXT ||
-	    n->next->flags & NODE_LINE))
-		outflags &= ~MMAN_spc;
-}
-
-static int
-pre_fn(DECL_ARGS)
-{
-
-	pre_syn(n);
-
-	n = n->child;
-	if (NULL == n)
-		return 0;
-
-	if (NODE_SYNPRETTY & n->flags)
-		print_block(".HP 4n", MMAN_nl);
-
-	font_push('B');
-	print_node(meta, n);
-	font_pop();
-	outflags &= ~MMAN_spc;
-	print_word("(");
-	outflags &= ~MMAN_spc;
-
-	n = n->next;
-	if (NULL != n)
-		pre_fa(meta, n);
-	return 0;
-}
-
-static void
-post_fn(DECL_ARGS)
-{
-
-	print_word(")");
-	if (NODE_SYNPRETTY & n->flags) {
-		print_word(";");
-		outflags |= MMAN_PP;
-	}
-}
-
-static int
-pre_fo(DECL_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		pre_syn(n);
-		break;
-	case ROFFT_HEAD:
-		if (n->child == NULL)
-			return 0;
-		if (NODE_SYNPRETTY & n->flags)
-			print_block(".HP 4n", MMAN_nl);
-		font_push('B');
-		break;
-	case ROFFT_BODY:
-		outflags &= ~(MMAN_spc | MMAN_nl);
-		print_word("(");
-		outflags &= ~MMAN_spc;
-		break;
-	default:
-		break;
-	}
-	return 1;
-}
-
-static void
-post_fo(DECL_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_HEAD:
-		if (n->child != NULL)
-			font_pop();
-		break;
-	case ROFFT_BODY:
-		post_fn(meta, n);
-		break;
-	default:
-		break;
-	}
-}
-
-static int
-pre_Ft(DECL_ARGS)
-{
-
-	pre_syn(n);
-	font_push('I');
-	return 1;
-}
-
-static void
-pre_ft(DECL_ARGS)
-{
-	print_line(".ft", 0);
-	print_word(n->child->string);
-	outflags |= MMAN_nl;
-}
-
-static int
-pre_in(DECL_ARGS)
-{
-
-	if (NODE_SYNPRETTY & n->flags) {
-		pre_syn(n);
-		font_push('B');
-		print_word("#include <");
-		outflags &= ~MMAN_spc;
-	} else {
-		print_word("<");
-		outflags &= ~MMAN_spc;
-		font_push('I');
-	}
-	return 1;
-}
-
-static void
-post_in(DECL_ARGS)
-{
-
-	if (NODE_SYNPRETTY & n->flags) {
-		outflags &= ~MMAN_spc;
-		print_word(">");
-		font_pop();
-		outflags |= MMAN_br;
-	} else {
-		font_pop();
-		outflags &= ~MMAN_spc;
-		print_word(">");
-	}
-}
-
-static int
-pre_it(DECL_ARGS)
-{
-	const struct roff_node *bln;
-
-	switch (n->type) {
-	case ROFFT_HEAD:
-		outflags |= MMAN_PP | MMAN_nl;
-		bln = n->parent->parent;
-		if (0 == bln->norm->Bl.comp ||
-		    (NULL == n->parent->prev &&
-		     NULL == bln->parent->prev))
-			outflags |= MMAN_sp;
-		outflags &= ~MMAN_br;
-		switch (bln->norm->Bl.type) {
-		case LIST_item:
-			return 0;
-		case LIST_inset:
-		case LIST_diag:
-		case LIST_ohang:
-			if (bln->norm->Bl.type == LIST_diag)
-				print_line(".B \"", 0);
-			else
-				print_line(".R \"", 0);
-			outflags &= ~MMAN_spc;
-			return 1;
-		case LIST_bullet:
-		case LIST_dash:
-		case LIST_hyphen:
-			print_width(&bln->norm->Bl, NULL);
-			TPremain = 0;
-			outflags |= MMAN_nl;
-			font_push('B');
-			if (LIST_bullet == bln->norm->Bl.type)
-				print_word("\\(bu");
-			else
-				print_word("-");
-			font_pop();
-			outflags |= MMAN_nl;
-			return 0;
-		case LIST_enum:
-			print_width(&bln->norm->Bl, NULL);
-			TPremain = 0;
-			outflags |= MMAN_nl;
-			print_count(&bln->norm->Bl.count);
-			outflags |= MMAN_nl;
-			return 0;
-		case LIST_hang:
-			print_width(&bln->norm->Bl, n->child);
-			TPremain = 0;
-			outflags |= MMAN_nl;
-			return 1;
-		case LIST_tag:
-			print_width(&bln->norm->Bl, n->child);
-			putchar('\n');
-			outflags &= ~MMAN_spc;
-			return 1;
-		default:
-			return 1;
-		}
-	default:
-		break;
-	}
-	return 1;
-}
-
-/*
- * This function is called after closing out an indented block.
- * If we are inside an enclosing list, restore its indentation.
- */
-static void
-mid_it(void)
-{
-	char		 buf[24];
-
-	/* Nothing to do outside a list. */
-	if (0 == Bl_stack_len || 0 == Bl_stack[Bl_stack_len - 1])
-		return;
-
-	/* The indentation has already been set up. */
-	if (Bl_stack_post[Bl_stack_len - 1])
-		return;
-
-	/* Restore the indentation of the enclosing list. */
-	print_line(".RS", MMAN_Bk_susp);
-	(void)snprintf(buf, sizeof(buf), "%dn",
-	    Bl_stack[Bl_stack_len - 1]);
-	print_word(buf);
-
-	/* Remeber to close out this .RS block later. */
-	Bl_stack_post[Bl_stack_len - 1] = 1;
-}
-
-static void
-post_it(DECL_ARGS)
-{
-	const struct roff_node *bln;
-
-	bln = n->parent->parent;
-
-	switch (n->type) {
-	case ROFFT_HEAD:
-		switch (bln->norm->Bl.type) {
-		case LIST_diag:
-			outflags &= ~MMAN_spc;
-			print_word("\\ ");
-			break;
-		case LIST_ohang:
-			outflags |= MMAN_br;
-			break;
-		default:
-			break;
-		}
-		break;
-	case ROFFT_BODY:
-		switch (bln->norm->Bl.type) {
-		case LIST_bullet:
-		case LIST_dash:
-		case LIST_hyphen:
-		case LIST_enum:
-		case LIST_hang:
-		case LIST_tag:
-			assert(Bl_stack_len);
-			Bl_stack[--Bl_stack_len] = 0;
-
-			/*
-			 * Our indentation had to be restored
-			 * after a child display or child list.
-			 * Close out that indentation block now.
-			 */
-			if (Bl_stack_post[Bl_stack_len]) {
-				print_line(".RE", MMAN_nl);
-				Bl_stack_post[Bl_stack_len] = 0;
-			}
-			break;
-		case LIST_column:
-			if (NULL != n->next) {
-				putchar('\t');
-				outflags &= ~MMAN_spc;
-			}
-			break;
-		default:
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-post_lb(DECL_ARGS)
-{
-
-	if (SEC_LIBRARY == n->sec)
-		outflags |= MMAN_br;
-}
-
-static int
-pre_lk(DECL_ARGS)
-{
-	const struct roff_node *link, *descr, *punct;
-	int display;
-
-	if ((link = n->child) == NULL)
-		return 0;
-
-	/* Find beginning of trailing punctuation. */
-	punct = n->last;
-	while (punct != link && punct->flags & NODE_DELIMC)
-		punct = punct->prev;
-	punct = punct->next;
-
-	/* Link text. */
-	if ((descr = link->next) != NULL && descr != punct) {
-		font_push('I');
-		while (descr != punct) {
-			print_word(descr->string);
-			descr = descr->next;
-		}
-		font_pop();
-		print_word(":");
-	}
-
-	/* Link target. */
-	display = man_strlen(link->string) >= 26;
-	if (display) {
-		print_line(".RS", MMAN_Bk_susp);
-		print_word("6n");
-		outflags |= MMAN_nl;
-	}
-	font_push('B');
-	print_word(link->string);
-	font_pop();
-
-	/* Trailing punctuation. */
-	while (punct != NULL) {
-		print_word(punct->string);
-		punct = punct->next;
-	}
-	if (display)
-		print_line(".RE", MMAN_nl);
-	return 0;
-}
-
-static void
-pre_onearg(DECL_ARGS)
-{
-	outflags |= MMAN_nl;
-	print_word(".");
-	outflags &= ~MMAN_spc;
-	print_word(roff_name[n->tok]);
-	if (n->child != NULL)
-		print_word(n->child->string);
-	outflags |= MMAN_nl;
-	if (n->tok == ROFF_ce)
-		for (n = n->child->next; n != NULL; n = n->next)
-			print_node(meta, n);
-}
-
-static int
-pre_li(DECL_ARGS)
-{
-
-	font_push('R');
-	return 1;
-}
-
-static int
-pre_nm(DECL_ARGS)
-{
-	char	*name;
-
-	if (n->type == ROFFT_BLOCK) {
-		outflags |= MMAN_Bk;
-		pre_syn(n);
-	}
-	if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD)
-		return 1;
-	name = n->child == NULL ? NULL : n->child->string;
-	if (NULL == name)
-		return 0;
-	if (n->type == ROFFT_HEAD) {
-		if (NULL == n->parent->prev)
-			outflags |= MMAN_sp;
-		print_block(".HP", 0);
-		printf(" %dn", man_strlen(name) + 1);
-		outflags |= MMAN_nl;
-	}
-	font_push('B');
-	return 1;
-}
-
-static void
-post_nm(DECL_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		outflags &= ~MMAN_Bk;
-		break;
-	case ROFFT_HEAD:
-	case ROFFT_ELEM:
-		if (n->child != NULL && n->child->string != NULL)
-			font_pop();
-		break;
-	default:
-		break;
-	}
-}
-
-static int
-pre_no(DECL_ARGS)
-{
-
-	outflags |= MMAN_spc_force;
-	return 1;
-}
-
-static int
-pre_ns(DECL_ARGS)
-{
-
-	outflags &= ~MMAN_spc;
-	return 0;
-}
-
-static void
-post_pf(DECL_ARGS)
-{
-
-	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
-		outflags &= ~MMAN_spc;
-}
-
-static int
-pre_pp(DECL_ARGS)
-{
-
-	if (MDOC_It != n->parent->tok)
-		outflags |= MMAN_PP;
-	outflags |= MMAN_sp | MMAN_nl;
-	outflags &= ~MMAN_br;
-	return 0;
-}
-
-static int
-pre_rs(DECL_ARGS)
-{
-
-	if (SEC_SEE_ALSO == n->sec) {
-		outflags |= MMAN_PP | MMAN_sp | MMAN_nl;
-		outflags &= ~MMAN_br;
-	}
-	return 1;
-}
-
-static int
-pre_skip(DECL_ARGS)
-{
-
-	return 0;
-}
-
-static int
-pre_sm(DECL_ARGS)
-{
-
-	if (NULL == n->child)
-		outflags ^= MMAN_Sm;
-	else if (0 == strcmp("on", n->child->string))
-		outflags |= MMAN_Sm;
-	else
-		outflags &= ~MMAN_Sm;
-
-	if (MMAN_Sm & outflags)
-		outflags |= MMAN_spc;
-
-	return 0;
-}
-
-static void
-pre_sp(DECL_ARGS)
-{
-	if (outflags & MMAN_PP) {
-		outflags &= ~MMAN_PP;
-		print_line(".PP", 0);
-	} else {
-		print_line(".sp", 0);
-		if (n->child != NULL)
-			print_word(n->child->string);
-	}
-	outflags |= MMAN_nl;
-}
-
-static int
-pre_sy(DECL_ARGS)
-{
-
-	font_push('B');
-	return 1;
-}
-
-static void
-pre_ta(DECL_ARGS)
-{
-	print_line(".ta", 0);
-	for (n = n->child; n != NULL; n = n->next)
-		print_word(n->string);
-	outflags |= MMAN_nl;
-}
-
-static int
-pre_vt(DECL_ARGS)
-{
-
-	if (NODE_SYNPRETTY & n->flags) {
-		switch (n->type) {
-		case ROFFT_BLOCK:
-			pre_syn(n);
-			return 1;
-		case ROFFT_BODY:
-			break;
-		default:
-			return 0;
-		}
-	}
-	font_push('I');
-	return 1;
-}
-
-static void
-post_vt(DECL_ARGS)
-{
-
-	if (n->flags & NODE_SYNPRETTY && n->type != ROFFT_BODY)
-		return;
-	font_pop();
-}
-
-static int
-pre_xr(DECL_ARGS)
-{
-
-	n = n->child;
-	if (NULL == n)
-		return 0;
-	print_node(meta, n);
-	n = n->next;
-	if (NULL == n)
-		return 0;
-	outflags &= ~MMAN_spc;
-	print_word("(");
-	print_node(meta, n);
-	print_word(")");
-	return 0;
-}

Property changes on: head/contrib/mdocml/mdoc_man.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/man.options.1
===================================================================
--- head/contrib/mdocml/man.options.1	(revision 338825)
+++ head/contrib/mdocml/man.options.1	(nonexistent)
@@ -1,1332 +0,0 @@
-.\"	$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: 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
-.Fx
-SVN repository
-.It
-the
-.Ox
-CVS repository
-.It
-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

Property changes on: head/contrib/mdocml/man.options.1
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mdoc_state.c
===================================================================
--- head/contrib/mdocml/mdoc_state.c	(revision 338825)
+++ head/contrib/mdocml/mdoc_state.c	(nonexistent)
@@ -1,292 +0,0 @@
-/*	$Id: mdoc_state.c,v 1.8 2017/05/05 15:17:32 schwarze Exp $ */
-/*
- * 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.
- */
-#include 
-
-#include 
-#include 
-#include 
-
-#include "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "libmandoc.h"
-#include "libmdoc.h"
-
-#define STATE_ARGS  struct roff_man *mdoc, struct roff_node *n
-
-typedef	void	(*state_handler)(STATE_ARGS);
-
-static	void	 state_bd(STATE_ARGS);
-static	void	 state_bl(STATE_ARGS);
-static	void	 state_dl(STATE_ARGS);
-static	void	 state_sh(STATE_ARGS);
-static	void	 state_sm(STATE_ARGS);
-
-static	const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
-	NULL,		/* Dd */
-	NULL,		/* Dt */
-	NULL,		/* Os */
-	state_sh,	/* Sh */
-	NULL,		/* Ss */
-	NULL,		/* Pp */
-	NULL,		/* D1 */
-	state_dl,	/* Dl */
-	state_bd,	/* Bd */
-	NULL,		/* Ed */
-	state_bl,	/* Bl */
-	NULL,		/* El */
-	NULL,		/* It */
-	NULL,		/* Ad */
-	NULL,		/* An */
-	NULL,		/* Ap */
-	NULL,		/* Ar */
-	NULL,		/* Cd */
-	NULL,		/* Cm */
-	NULL,		/* Dv */
-	NULL,		/* Er */
-	NULL,		/* Ev */
-	NULL,		/* Ex */
-	NULL,		/* Fa */
-	NULL,		/* Fd */
-	NULL,		/* Fl */
-	NULL,		/* Fn */
-	NULL,		/* Ft */
-	NULL,		/* Ic */
-	NULL,		/* In */
-	NULL,		/* Li */
-	NULL,		/* Nd */
-	NULL,		/* Nm */
-	NULL,		/* Op */
-	NULL,		/* Ot */
-	NULL,		/* Pa */
-	NULL,		/* Rv */
-	NULL,		/* St */
-	NULL,		/* Va */
-	NULL,		/* Vt */
-	NULL,		/* Xr */
-	NULL,		/* %A */
-	NULL,		/* %B */
-	NULL,		/* %D */
-	NULL,		/* %I */
-	NULL,		/* %J */
-	NULL,		/* %N */
-	NULL,		/* %O */
-	NULL,		/* %P */
-	NULL,		/* %R */
-	NULL,		/* %T */
-	NULL,		/* %V */
-	NULL,		/* Ac */
-	NULL,		/* Ao */
-	NULL,		/* Aq */
-	NULL,		/* At */
-	NULL,		/* Bc */
-	NULL,		/* Bf */
-	NULL,		/* Bo */
-	NULL,		/* Bq */
-	NULL,		/* Bsx */
-	NULL,		/* Bx */
-	NULL,		/* Db */
-	NULL,		/* Dc */
-	NULL,		/* Do */
-	NULL,		/* Dq */
-	NULL,		/* Ec */
-	NULL,		/* Ef */
-	NULL,		/* Em */
-	NULL,		/* Eo */
-	NULL,		/* Fx */
-	NULL,		/* Ms */
-	NULL,		/* No */
-	NULL,		/* Ns */
-	NULL,		/* Nx */
-	NULL,		/* Ox */
-	NULL,		/* Pc */
-	NULL,		/* Pf */
-	NULL,		/* Po */
-	NULL,		/* Pq */
-	NULL,		/* Qc */
-	NULL,		/* Ql */
-	NULL,		/* Qo */
-	NULL,		/* Qq */
-	NULL,		/* Re */
-	NULL,		/* Rs */
-	NULL,		/* Sc */
-	NULL,		/* So */
-	NULL,		/* Sq */
-	state_sm,	/* Sm */
-	NULL,		/* Sx */
-	NULL,		/* Sy */
-	NULL,		/* Tn */
-	NULL,		/* Ux */
-	NULL,		/* Xc */
-	NULL,		/* Xo */
-	NULL,		/* Fo */
-	NULL,		/* Fc */
-	NULL,		/* Oo */
-	NULL,		/* Oc */
-	NULL,		/* Bk */
-	NULL,		/* Ek */
-	NULL,		/* Bt */
-	NULL,		/* Hf */
-	NULL,		/* Fr */
-	NULL,		/* Ud */
-	NULL,		/* Lb */
-	NULL,		/* Lp */
-	NULL,		/* Lk */
-	NULL,		/* Mt */
-	NULL,		/* Brq */
-	NULL,		/* Bro */
-	NULL,		/* Brc */
-	NULL,		/* %C */
-	NULL,		/* Es */
-	NULL,		/* En */
-	NULL,		/* Dx */
-	NULL,		/* %Q */
-	NULL,		/* %U */
-	NULL,		/* Ta */
-};
-static const state_handler *const state_handlers = __state_handlers - MDOC_Dd;
-
-
-void
-mdoc_state(struct roff_man *mdoc, struct roff_node *n)
-{
-	state_handler handler;
-
-	if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
-		return;
-
-	assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
-	if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
-		mdoc->flags |= MDOC_PBODY;
-
-	handler = state_handlers[n->tok];
-	if (*handler)
-		(*handler)(mdoc, n);
-}
-
-void
-mdoc_state_reset(struct roff_man *mdoc)
-{
-
-	roff_setreg(mdoc->roff, "nS", 0, '=');
-	mdoc->flags = 0;
-}
-
-static void
-state_bd(STATE_ARGS)
-{
-	enum mdocargt arg;
-
-	if (n->type != ROFFT_HEAD &&
-	    (n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
-		return;
-
-	if (n->parent->args == NULL)
-		return;
-
-	arg = n->parent->args->argv[0].arg;
-	if (arg != MDOC_Literal && arg != MDOC_Unfilled)
-		return;
-
-	state_dl(mdoc, n);
-}
-
-static void
-state_bl(STATE_ARGS)
-{
-
-	if (n->type != ROFFT_HEAD || n->parent->args == NULL)
-		return;
-
-	switch(n->parent->args->argv[0].arg) {
-	case MDOC_Diag:
-		n->norm->Bl.type = LIST_diag;
-		break;
-	case MDOC_Column:
-		n->norm->Bl.type = LIST_column;
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-state_dl(STATE_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_HEAD:
-		mdoc->flags |= MDOC_LITERAL;
-		break;
-	case ROFFT_BODY:
-		mdoc->flags &= ~MDOC_LITERAL;
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-state_sh(STATE_ARGS)
-{
-	struct roff_node *nch;
-	char		 *secname;
-
-	if (n->type != ROFFT_HEAD)
-		return;
-
-	if ( ! (n->flags & NODE_VALID)) {
-		secname = NULL;
-		deroff(&secname, n);
-
-		/*
-		 * Set the section attribute for the BLOCK, HEAD,
-		 * and HEAD children; the latter can only be TEXT
-		 * nodes, so no recursion is needed.  For other
-		 * nodes, including the .Sh BODY, this is done
-		 * when allocating the node data structures, but
-		 * for .Sh BLOCK and HEAD, the section is still
-		 * unknown at that time.
-		 */
-
-		n->sec = n->parent->sec = secname == NULL ?
-		    SEC_CUSTOM : mdoc_a2sec(secname);
-		for (nch = n->child; nch != NULL; nch = nch->next)
-			nch->sec = n->sec;
-		free(secname);
-	}
-
-	if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) {
-		roff_setreg(mdoc->roff, "nS", 1, '=');
-		mdoc->flags |= MDOC_SYNOPSIS;
-	} else {
-		roff_setreg(mdoc->roff, "nS", 0, '=');
-		mdoc->flags &= ~MDOC_SYNOPSIS;
-	}
-}
-
-static void
-state_sm(STATE_ARGS)
-{
-
-	if (n->child == NULL)
-		mdoc->flags ^= MDOC_SMOFF;
-	else if ( ! strcmp(n->child->string, "on"))
-		mdoc->flags &= ~MDOC_SMOFF;
-	else if ( ! strcmp(n->child->string, "off"))
-		mdoc->flags |= MDOC_SMOFF;
-}

Property changes on: head/contrib/mdocml/mdoc_state.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/makewhatis.8
===================================================================
--- head/contrib/mdocml/makewhatis.8	(revision 338825)
+++ head/contrib/mdocml/makewhatis.8	(nonexistent)
@@ -1,228 +0,0 @@
-.\"	$Id: makewhatis.8,v 1.6 2017/05/17 22:27:12 schwarze Exp $
-.\"
-.\" Copyright (c) 2011, 2012 Kristaps Dzonsons 
-.\" Copyright (c) 2011, 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: May 17 2017 $
-.Dt MAKEWHATIS 8
-.Os
-.Sh NAME
-.Nm makewhatis
-.Nd index UNIX manuals
-.Sh SYNOPSIS
-.Nm
-.Op Fl aDnpQ
-.Op Fl T Cm utf8
-.Op Fl C Ar file
-.Nm
-.Op Fl aDnpQ
-.Op Fl T Cm utf8
-.Ar dir ...
-.Nm
-.Op Fl DnpQ
-.Op Fl T Cm utf8
-.Fl d Ar dir
-.Op Ar
-.Nm
-.Op Fl Dnp
-.Op Fl T Cm utf8
-.Fl u Ar dir
-.Op Ar
-.Nm
-.Op Fl DQ
-.Fl t Ar
-.Sh DESCRIPTION
-The
-.Nm
-utility extracts keywords from
-.Ux
-manuals and indexes them in a database for fast retrieval by
-.Xr apropos 1 ,
-.Xr whatis 1 ,
-and
-.Xr man 1 Ns 's
-.Fl k
-option.
-.Pp
-By default,
-.Nm
-creates a database in each
-.Ar dir
-using the files
-.Sm off
-.Sy man Ar section Li /
-.Op Ar arch Li /
-.Ar title . section
-.Sm on
-and
-.Sm off
-.Sy cat Ar section Li /
-.Op Ar arch Li /
-.Ar title . Sy 0
-.Sm on
-in that directory.
-Existing databases are replaced.
-If a directory contains no manual pages, no database is created in that
-directory.
-If
-.Ar dir
-is not provided,
-.Nm
-uses the default paths stipulated by
-.Xr man.conf 5 .
-.Pp
-The arguments are as follows:
-.Bl -tag -width "-C file"
-.It Fl a
-Use all directories and files found below
-.Ar dir ... .
-.It Fl C Ar file
-Specify an alternative configuration
-.Ar file
-in
-.Xr man.conf 5
-format.
-.It Fl D
-Display all files added or removed to the index.
-With a second
-.Fl D ,
-also show all keywords added for each file.
-.It Fl d Ar dir
-Merge (remove and re-add)
-.Ar
-to the database in
-.Ar dir .
-.It Fl n
-Do not create or modify any database; scan and parse only,
-and print manual page names and descriptions to standard output.
-.It Fl p
-Print warnings about potential problems with manual pages
-to the standard error output.
-.It Fl Q
-Quickly build reduced-size databases
-by reading only the NAME sections of manuals.
-The resulting databases will usually contain names and descriptions only.
-.It Fl T Cm utf8
-Use UTF-8 encoding instead of ASCII for strings stored in the databases.
-.It Fl t Ar
-Check the given
-.Ar files
-for potential problems.
-Implies
-.Fl a ,
-.Fl n ,
-and
-.Fl p .
-All diagnostic messages are printed to the standard output;
-the standard error output is not used.
-.It Fl u Ar dir
-Remove
-.Ar
-from the database in
-.Ar dir .
-If that causes the database to become empty, also delete the database file.
-.El
-.Pp
-If fatal parse errors are encountered while parsing, the offending file
-is printed to stderr, omitted from the index, and the parse continues
-with the next input file.
-.Sh ENVIRONMENT
-.Bl -tag -width MANPATH
-.It Ev MANPATH
-A colon-separated list of directories to create databases in.
-Ignored if a
-.Ar dir
-argument or the
-.Fl t
-option is specified.
-.El
-.Sh FILES
-.Bl -tag -width Ds
-.It Pa mandoc.db
-A database of manpages relative to the directory of the file.
-This file is portable across architectures and systems, so long as the
-manpage hierarchy it indexes does not change.
-.It Pa /etc/man.conf
-The default
-.Xr man 1
-configuration file.
-.El
-.Sh EXIT STATUS
-The
-.Nm
-utility exits with one of the following values:
-.Pp
-.Bl -tag -width Ds -compact
-.It 0
-No errors occurred.
-.It 5
-Invalid command line arguments were specified.
-No input files have been read.
-.It 6
-An operating system error occurred, for example memory exhaustion or an
-error accessing input files.
-Such errors cause
-.Nm
-to exit at once, possibly in the middle of parsing or formatting a file.
-The output databases are corrupt and should be removed.
-.El
-.Sh SEE ALSO
-.Xr apropos 1 ,
-.Xr man 1 ,
-.Xr whatis 1 ,
-.Xr man.conf 5
-.Sh HISTORY
-A
-.Nm
-utility first appeared in
-.Bx 2 .
-It was rewritten in
-.Xr perl 1
-for
-.Ox 2.7
-and in C for
-.Ox 5.6 .
-.Pp
-The
-.Ar dir
-argument first appeared in
-.Nx 1.0 ;
-the options
-.Fl dpt
-in
-.Ox 2.7 ;
-the option
-.Fl u
-in
-.Ox 3.4 ;
-and the options
-.Fl aCDnQT
-in
-.Ox 5.6 .
-.Sh AUTHORS
-.An -nosplit
-.An Bill Joy
-wrote the original
-.Bx
-.Nm
-in February 1979,
-.An Marc Espie
-started the Perl version in 2000,
-and the current version of
-.Nm
-was written by
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
-and
-.An Ingo Schwarze Aq Mt schwarze@openbsd.org .

Property changes on: head/contrib/mdocml/makewhatis.8
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/compat_getline.c
===================================================================
--- head/contrib/mdocml/compat_getline.c	(revision 338825)
+++ head/contrib/mdocml/compat_getline.c	(nonexistent)
@@ -1,68 +0,0 @@
-#include "config.h"
-
-#if HAVE_GETLINE
-
-int dummy;
-
-#else
-
-/*	$Id: compat_getline.c,v 1.1 2015/11/07 20:52:52 schwarze Exp $ */
-/*
- * Copyright (c) 2015 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.
- */
-
-#include 
-#include 
-#include 
-#include 
-
-ssize_t
-getline(char **buf, size_t *bufsz, FILE *fp)
-{
-	char	*nbuf;
-	size_t	 nbufsz, pos;
-	int	 c;
-
-	if (buf == NULL || bufsz == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	if (*buf == NULL)
-		*bufsz = 0;
-	else
-		**buf = '\0';
-
-	pos = 0;
-	for (;;) {
-		if (pos + 1 >= *bufsz) {
-			nbufsz = *bufsz ? *bufsz * 2 : BUFSIZ;
-			if ((nbuf = realloc(*buf, nbufsz)) == NULL)
-				return -1;
-			*buf = nbuf;
-			*bufsz = nbufsz;
-		}
-		if ((c = fgetc(fp)) == EOF) {
-			(*buf)[pos] = '\0';
-			return pos > 0 && feof(fp) ? (ssize_t)pos : -1;
-		}
-		(*buf)[pos++] = c;
-		(*buf)[pos] = '\0';
-		if (c == '\n')
-			return pos;
-	}
-}
-
-#endif

Property changes on: head/contrib/mdocml/compat_getline.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/test-pledge.c
===================================================================
--- head/contrib/mdocml/test-pledge.c	(revision 338825)
+++ head/contrib/mdocml/test-pledge.c	(nonexistent)
@@ -1,7 +0,0 @@
-#include 
-
-int
-main(void)
-{
-	return !!pledge("stdio", NULL);
-}

Property changes on: head/contrib/mdocml/test-pledge.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/INSTALL
===================================================================
--- head/contrib/mdocml/INSTALL	(revision 338825)
+++ head/contrib/mdocml/INSTALL	(nonexistent)
@@ -1,159 +0,0 @@
-$Id: INSTALL,v 1.20 2017/07/28 14:57:56 schwarze Exp $
-
-About the portable mandoc distribution
---------------------------------------
-The mandoc manpage compiler toolset (formerly called "mdocml")
-is a suite of tools compiling mdoc(7), the roff(7) macro language
-of choice for BSD manual pages, and man(7), the predominant
-historical language for UNIX manuals.
-
-It includes a man(1) manual viewer and additional tools.
-For general information, see .
-
-In case you have questions or want to provide feedback, read
-.  Consider subscribing to the
-discuss@ mailing list mentioned on that page.  If you intend to
-help with the development of mandoc, consider subscribing to the
-tech@ mailing list, too.
-
-Enjoy using the mandoc toolset!
-
-Ingo Schwarze, Karlsruhe, July 2017
-
-
-Installation
-------------
-Before manually installing mandoc on your system, please check
-whether the newest version of mandoc is already installed by default
-or available via a binary package or a ports system.  A list of the
-latest bundled and ported versions of mandoc for various operating
-systems is maintained at .
-
-Regarding how packages and ports are maintained for your operating
-system, please consult your operating system documentation.
-To install mandoc manually, the following steps are needed:
-
-1. If you want to build the CGI program, man.cgi(8), too,
-run the command "echo BUILD_CGI=1 >> configure.local".
-Then run "cp cgi.h.example cgi.h" and edit cgi.h as desired.
-
-2. If you also want to build the catman(8) utility, run the
-command "echo BUILD_CATMAN=1 >> configure.local".  Note that it
-is unlikely to be a drop-in replacement providing the same
-functionality as your system's "catman", if your operating
-system contains one.
-
-3. Define MANPATH_DEFAULT in configure.local
-if /usr/share/man:/usr/X11R6/man:/usr/local/man is not appropriate
-for your operating system.
-
-4. Run "./configure".
-This script attempts autoconfiguration of mandoc for your system.
-Read both its standard output and the file "Makefile.local" it
-generates.  If anything looks wrong or different from what you
-wish, read the file "configure.local.example", create and edit
-a file "configure.local", and re-run "./configure" until the
-result seems right to you.
-On Solaris 10 and earlier, you may have to run "ksh ./configure"
-because the native /bin/sh lacks some POSIX features.
-
-5. Run "make".
-Any POSIX-compatible make, in particular both BSD make and GNU make,
-should work.  If the build fails, look at "configure.local.example"
-and go back to step 2.
-
-6. Run "make -n install" and check whether everything will be
-installed to the intended places.  Otherwise, put some *DIR or *NM*
-variables into "configure.local" and go back to step 4.
-
-7. Optionally run the regression suite.
-Basically, that amounts to "cd regress && ./regress.pl".
-But you should probably look at "./mandoc -l regress/regress.pl.1"
-first.
-
-8. Run "sudo make install".  If you intend to build a binary
-package using some kind of fake root mechanism, you may need a
-command like "make DESTDIR=... install".  Read the *-install targets
-in the "Makefile" to understand how DESTDIR is used.
-
-9. Run the command "sudo makewhatis" to build mandoc.db(5) databases
-in all the directory trees configured in step 3.  Whenever installing
-new manual pages, re-run makewhatis(8) to update the databases, or
-apropos(1) will not find the new pages.
-
-10. To set up a man.cgi(8) server, read its manual page.
-
-Note that some man(7) pages may contain low-level roff(7) markup
-that mandoc does not yet understand.  On some BSD systems using
-mandoc, third-party software is vetted on whether it may be formatted
-with mandoc.  If not, groff(1) is pulled in as a dependency and
-used to install a pre-formatted "catpage" instead of directly as
-manual page source.
-
-
-Understanding mandoc dependencies
----------------------------------
-The following libraries are required:
-
-1. zlib for decompressing gzipped manual pages.
-
-2. The fts(3) directory traversion functions.
-If your system does not have them, the bundled compatibility version
-will be used, so you need not worry in that case.  But be careful: old
-glibc versions of fts(3) were known to be broken on 32bit platforms,
-see .
-That was presumably fixed in glibc-2.23.
-If you run into that problem, set "HAVE_FTS=0" in configure.local.
-
-3. Marc Espie's ohash(3) library.
-If your system does not have it, the bundled compatibility version
-will be used, so you probably need not worry about it.
-
-One of the chief design goals of the mandoc toolbox is to make
-sure that nothing related to documentation requires C++.
-Consequently, linking mandoc against any kind of C++ program
-would defeat the purpose and is not supported.
-
-
-Checking autoconfiguration quality
-----------------------------------
-If you want to check whether automatic configuration works well
-on your platform, consider the following:
-
-The mandoc package intentionally does not use GNU autoconf because
-we consider that toolset a blatant example of overengineering that
-is obsolete nowadays, since all modern operating systems are now
-reasonably close to POSIX and do not need arcane shell magic any
-longer.  If your system does need such magic, consider upgrading
-to reasonably modern POSIX-compliant tools rather than asking for
-autoconf-style workarounds.
-
-As far as mandoc is using any features not mandated by ANSI X3.159-1989
-("ANSI C") or IEEE Std 1003.1-2008 ("POSIX") that some modern systems
-do not have, we intend to provide autoconfiguration tests and
-compat_*.c implementations.  Please report any that turn out to be
-missing.  Note that while we do strive to produce portable code,
-we do not slavishly restrict ourselves to POSIX-only interfaces.
-For improved security and readability, we do use well-designed,
-modern interfaces like reallocarray(3) even if they are still rather
-uncommon, of course bundling compat_*.c implementations as needed.
-
-Where mandoc is using ANSI C or POSIX features that some systems
-still lack and that compat_*.c implementations can be provided for
-without too much hassle, we will consider adding them, too, so
-please report whatever is missing on your platform.
-
-The following steps can be used to manually check the automatic
-configuration on your platform:
-
-1. Run "make distclean".
-
-2. Run "./configure"
-
-3. Read the file "config.log".  It shows the compiler commands used
-to test the libraries installed on your system and the standard
-output and standard error output these commands produce.  Watch out
-for unexpected failures.  Those are most likely to happen if headers
-or libraries are installed in unusual places or interfaces defined
-in unusual headers.  You can also look at the file "config.h" and
-check that no "#define HAVE_*" differ from your expectations.
Index: head/contrib/mdocml/mandoc_aux.c
===================================================================
--- head/contrib/mdocml/mandoc_aux.c	(revision 338825)
+++ head/contrib/mdocml/mandoc_aux.c	(nonexistent)
@@ -1,118 +0,0 @@
-/*	$Id: mandoc_aux.c,v 1.10 2017/06/12 19:05:47 schwarze Exp $ */
-/*
- * Copyright (c) 2009, 2011 Kristaps Dzonsons 
- * 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;
-}

Property changes on: head/contrib/mdocml/mandoc_aux.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/man.cgi.3
===================================================================
--- head/contrib/mdocml/man.cgi.3	(revision 338825)
+++ head/contrib/mdocml/man.cgi.3	(nonexistent)
@@ -1,310 +0,0 @@
-.\"	$Id: man.cgi.3,v 1.4 2017/03/15 13:18:53 schwarze Exp $
-.\"
-.\" Copyright (c) 2016, 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: March 15 2017 $
-.Dt MAN.CGI 3
-.Os
-.Sh NAME
-.Nm man.cgi
-.Nd internals of the CGI program to search and display manual pages
-.Sh DESCRIPTION
-The source code of
-.Xr man.cgi 8
-is organized in four levels:
-.Pp
-.Bl -enum -compact
-.It
-.Sx Top level
-.It
-.Sx Page generators
-.It
-.Sx Result generators
-.It
-.Sx Utility routines
-.El
-.Ss Top level
-The top level of
-.Xr man.cgi 8
-consists of the
-.Fn main
-program and a few parser routines.
-.Bl -tag -width 1n
-.It Ft int Fn main void
-The main program
-.Bl -dash -compact
-.It
-limits execution time;
-.It
-changes to
-.Dv MAN_DIR ,
-the data directory containing all the manual trees;
-.It
-calls
-.Fn parse_manpath_conf ;
-.It
-if
-.Ev PATH_INFO
-is empty, calls
-.Fn parse_query_string ;
-otherwise,
-calls
-.Fn parse_path_info ;
-.It
-validates the manpath and the architecture;
-.It
-calls the appropriate one among the
-.Sx Page generators .
-.El
-.It Ft void Fn parse_manpath_conf "struct req *req"
-Parses and validates
-.Pa manpath.conf
-and fills
-.Va req->p
-and
-.Va req->psz .
-.It Ft void Fn parse_path_info "struct req *req" "const char *path"
-Parses and validates
-.Ev PATH_INFO ,
-clears
-.Va req->isquery ,
-and fills
-.Va req->q .
-.It Ft void Fn parse_query_string "struct req *req" "const char *qs"
-Parses and validates
-.Ev QUERY_STRING ,
-sets
-.Va req->isquery ,
-and fills
-.Va req->q .
-This function is the only user of the utility functions
-.Fn http_decode
-and
-.Fn set_query_attr .
-.El
-.Ss Page generators
-The purpose of each page generator is to print a complete HTML page,
-starting with the HTTP headers and continuing to the page footer.
-Before starting HTML output with
-.Fn resp_begin_html ,
-some page generators do some preparatory work, for example to decide
-which page to show.
-Each page generator ends with a call to
-.Fn resp_end_html .
-.Bl -tag -width 1n
-.It Ft void Fn pg_show "struct req *req" "const char *fullpath"
-This page generator is used when
-.Ev PATH_INFO
-contains the complete path to a manual page including manpath,
-section directory, optional architecture subdirectory, manual name
-and section number suffix.
-It validates the manpath, changes into it, validate the filename,
-and then calls
-.Fn resp_begin_html ,
-.Fn resp_searchform ,
-.Fn resp_show ,
-and
-.Fn resp_end_html
-in that order.
-.It Ft void Fn pg_search "const struct req *req"
-This page generator is used when
-.Ev PATH_INFO
-contains a search query in short format or when
-.Ev PATH_INFO
-is empty and a
-.Ev QUERY_STRING
-is provided.
-If possible, requests using
-.Ev QUERY_STRING
-are redirected to URIs using
-.Ev PATH_INFO
-by calling
-.Fn pg_redirect .
-Otherwise, it changes into the manpath and calls
-.Xr mansearch 3 .
-Depending on the result, it calls either
-.Fn pg_noresult
-or
-.Fn pg_searchres .
-.It Ft void Fn pg_redirect "const struct req *req" "const char *name"
-This function is special in so far as it does not print an HTML page,
-but only an HTTP 303 response with a Location: of the form:
-.Sm off
-.No http://
-.Ar host Ns /
-.Op Ar scriptname Ns /
-.Op Ar manpath Ns /
-.Op Ar arch Ns /
-.Fa name
-.Op Pf . Ar sec
-.Sm on
-.It Ft void Fn pg_noresult "const struct req *req" "const char *msg"
-This function calls
-.Fn resp_begin_html ,
-.Fn resp_searchform ,
-prints the
-.Fa msg
-passed to it, and calls
-.Fn resp_end_html .
-.It Ft void Fn pg_searchres "const struct req *req" "struct manpage *r"\
- "size_t sz"
-This function first validates the filenames found.
-If
-.Ev QUERY_STRING
-was used and there is exactly one result,
-it writes an HTTP redirect to that result.
-Otherwise, it writes an HTML result page beginning with
-.Fn resp_begin_html
-and
-.Fn resp_searchform .
-If there is more than one result, it writes a list of links
-to all the results.
-If it was a
-.Xr man 1
-rather than an
-.Xr apropos 1
-query or if there is only one single result, it calls
-.Fn resp_show .
-Finally, it calls
-.Fn resp_end_html .
-.It Ft void Fn pg_index "const struct req *req"
-This page generator is used when
-.Ev PATH_INFO
-and
-.Ev QUERY_STRING
-are both empty.
-It calls
-.Fn resp_begin_html
-and
-.Fn resp_searchform ,
-writes links to help pages, and calls
-.Fn resp_end_html .
-.It Ft void Fn pg_error_badrequest "const char *msg"
-This page generator is used when
-.Fn main
-or
-.Fn pg_show
-detect an invalid URI.
-It calls
-.Fn resp_begin_html ,
-prints the
-.Fa msg
-provided, and calls
-.Fn resp_end_html .
-.It Ft void Fn pg_error_internal void
-This page generator is used by various functions when errors are
-detected in the
-.Pa manpath.conf
-configuration file, in
-.Xr mandoc.db 5
-databases, in the
-.Xr mandoc 3
-parser, in file system permissions, or when setting up timeouts.
-It calls
-.Fn resp_begin_html ,
-prints
-.Qq "Internal Server Error" ,
-and calls
-.Fn resp_end_html .
-Before calling
-.Fn pg_error_internal ,
-call
-.Xr warn 3
-or
-.Xr warnx 3
-to log the reason of the error to the
-.Xr httpd 8
-server log file.
-.El
-.Ss Result generators
-The purpose of result generators is to print a chunk of HTML code.
-When they print untrusted strings or characters,
-.Fn html_print
-and
-.Fn html_putchar
-are used.
-The highest level result generators are:
-.Bl -tag -width 1n
-.It Ft void Fn resp_begin_html "int code" "const char *msg" "const char *file"
-This generator calls
-.Fn resp_begin_http
-to print the HTTP headers, then prints the HTML header up to the
-opening tag of the  element, then copies the file
-.Pa header.html
-to the output, if it exists and is readable.
-If
-.Fa file
-is not
-.Dv NULL ,
-it is used for the  element.
-.It Ft void Fn resp_searchform "const struct req *req" "enum focus focus"
-This generator prints a search form, filling it with data
-from the provided request object.
-If the
-.Fa focus
-argument is
-.Dv FOCUS_QUERY ,
-it sets the document's autofocus to the query input box.
-.It Ft void Fn resp_show "const struct req *req" "const char *file"
-This wrapper dispatches to either
-.Fn resp_catman
-or
-.Fn resp_format ,
-depending on whether
-.Ar file
-starts with
-.Pa cat
-or
-.Pa man ,
-respectively.
-.It Ft void Fn resp_catman "const struct req *req" "const char *file"
-This generator translates a preformatted, backspace-encoded manual
-page to HTML and prints it to the output.
-.It Ft void Fn resp_format "const struct req *req" "const char *file"
-This generator formats a manual page on the standard output,
-using the functions documented in
-.Xr mchars_alloc 3
-and
-.Xr mandoc 3 .
-.It Ft void Fn resp_end_html void
-This generator copies the file
-.Pa footer.html
-to the output, if it exists and is readable,
-and closes the <body> and <html> elements.
-.El
-.Ss Utility routines
-These functions take a string and return 1 if it is valid, or 0 otherwise.
-.Bl -tag -width 1n
-.It Ft int Fn validate_urifrag "const char *frag"
-Checks that the string only contains alphanumeric ASCII characters,
-dashes, dots, slashes, and underscores.
-.It Ft int Fn validate_manpath "const struct req *req" "const char* manpath"
-Checks that the string is either
-.Qq mandoc
-or one of the manpaths configured in
-.Pa manpath.conf .
-.It Ft int Fn validate_filename "const char *file"
-Checks that the string starts with
-.Qq man
-or
-.Qq cat
-and does not ascend to parent directories.
-.El
-.Sh SEE ALSO
-.Xr mandoc 3 ,
-.Xr mansearch 3 ,
-.Xr mchars_alloc 3 ,
-.Xr mandoc.db 5 ,
-.Xr man.cgi 8

Property changes on: head/contrib/mdocml/man.cgi.3
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/roff_int.h
===================================================================
--- head/contrib/mdocml/roff_int.h	(revision 338825)
+++ head/contrib/mdocml/roff_int.h	(nonexistent)
@@ -1,39 +0,0 @@
-/*	$Id: roff_int.h,v 1.9 2017/07/08 17:52:50 schwarze Exp $	*/
-/*
- * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-struct roff_node *roff_node_alloc(struct roff_man *, int, int,
-			enum roff_type, int);
-void		  roff_node_append(struct roff_man *, struct roff_node *);
-void		  roff_word_alloc(struct roff_man *, int, int, const char *);
-void		  roff_word_append(struct roff_man *, const char *);
-void		  roff_elem_alloc(struct roff_man *, int, int, int);
-struct roff_node *roff_block_alloc(struct roff_man *, int, int, int);
-struct roff_node *roff_head_alloc(struct roff_man *, int, int, int);
-struct roff_node *roff_body_alloc(struct roff_man *, int, int, int);
-void		  roff_node_unlink(struct roff_man *, struct roff_node *);
-void		  roff_node_free(struct roff_node *);
-void		  roff_node_delete(struct roff_man *, struct roff_node *);
-
-/*
- * Functions called from roff.c need to be declared here,
- * not in libmdoc.h or libman.h, even if they are specific
- * to either the mdoc(7) or the man(7) parser.
- */
-
-void		  man_breakscope(struct roff_man *, int);
-void		  mdoc_argv_free(struct mdoc_arg *);

Property changes on: head/contrib/mdocml/roff_int.h
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/compat_mkdtemp.c
===================================================================
--- head/contrib/mdocml/compat_mkdtemp.c	(revision 338825)
+++ head/contrib/mdocml/compat_mkdtemp.c	(nonexistent)
@@ -1,61 +0,0 @@
-#include "config.h"
-
-#if HAVE_MKDTEMP
-
-int dummy;
-
-#else
-
-/*	$Id: compat_mkdtemp.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $	*/
-/*
- * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * The algorithm of this function is inspired by OpenBSD mkdtemp(3)
- * by Theo de Raadt and Todd Miller, but the code differs.
- */
-
-#include <sys/stat.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
-char *
-mkdtemp(char *path)
-{
-	char		*start, *cp;
-	unsigned	 int tries;
-
-	start = strchr(path, '\0');
-	while (start > path && start[-1] == 'X')
-		start--;
-
-	for (tries = INT_MAX; tries; tries--) {
-		if (mktemp(path) == NULL) {
-			errno = EEXIST;
-			return NULL;
-		}
-		if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) == 0)
-			return path;
-		if (errno != EEXIST)
-			return NULL;
-		for (cp = start; *cp != '\0'; cp++)
-			*cp = 'X';
-	}
-	errno = EEXIST;
-	return NULL;
-}
-
-#endif

Property changes on: head/contrib/mdocml/compat_mkdtemp.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/man.cgi.8
===================================================================
--- head/contrib/mdocml/man.cgi.8	(revision 338825)
+++ head/contrib/mdocml/man.cgi.8	(nonexistent)
@@ -1,421 +0,0 @@
-.\"	$Id: man.cgi.8,v 1.22 2017/03/18 16:48:24 schwarze Exp $
-.\"
-.\" Copyright (c) 2014, 2015, 2016 Ingo Schwarze <schwarze@openbsd.org>
-.\"
-.\" Permission to use, copy, modify, and distribute this software for any
-.\" purpose with or without fee is hereby granted, provided that the above
-.\" copyright notice and this permission notice appear in all copies.
-.\"
-.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.Dd $Mdocdate: March 18 2017 $
-.Dt MAN.CGI 8
-.Os
-.Sh NAME
-.Nm man.cgi
-.Nd CGI program to search and display manual pages
-.Sh DESCRIPTION
-The
-.Nm
-CGI program searches for manual pages on a WWW server
-and displays them to HTTP clients,
-providing functionality equivalent to the
-.Xr man 1
-and
-.Xr apropos 1
-utilities.
-It can use multiple manual trees in parallel.
-.Ss HTML search interface
-At the top of each generated HTML page,
-.Nm
-displays a search form containing these elements:
-.Bl -enum
-.It
-An input box for search queries, expecting
-either a name of a manual page or an
-.Ar expression
-using the syntax described in the
-.Xr apropos 1
-manual; filling this in is required for each search.
-.Pp
-The expression is broken into words at whitespace.
-Whitespace characters and backslashes can be escaped
-by prepending a backslash.
-The effect of prepending a backslash to another character is undefined;
-in the current implementation, it has no effect.
-.It
-A
-.Xr man 1
-submit button.
-The string in the input box is interpreted as the name of a manual page.
-.It
-An
-.Xr apropos 1
-submit button.
-The string in the input box is interpreted as a search
-.Ar expression .
-.It
-A dropdown menu to optionally select a manual section.
-If one is provided, it has the same effect as the
-.Xr man 1
-and
-.Xr apropos 1
-.Fl s
-option.
-Otherwise, pages from all sections are shown.
-.It
-A dropdown menu to optionally select an architecture.
-If one is provided, it has the same effect as the
-.Xr man 1
-and
-.Xr apropos 1
-.Fl S
-option.
-By default, pages for all architectures are shown.
-.It
-A dropdown menu to select a manual tree.
-If the configuration file
-.Pa /var/www/man/manpath.conf
-contains only one manpath, the dropdown menu is not shown.
-By default, the first manpath given in the file is used.
-.El
-.Ss Program output
-The
-.Nm
-program generates five kinds of output pages:
-.Bl -tag -width Ds
-.It The index page.
-This is returned when calling
-.Nm
-without
-.Ev PATH_INFO
-and without a
-.Ev QUERY_STRING .
-It serves as a starting point for using the program
-and shows the search form only.
-.It A list page.
-Lists are returned when searches match more than one manual page.
-The first column shows the names and section numbers of manuals
-as clickable links.
-The second column shows the one-line descriptions of the manuals.
-.It A manual page.
-This output format is used when a search matches exactly one
-manual page, or when a link on a list page or an
-.Ic \&Xr
-link on another manual page is followed.
-.It A no-result page.
-This is shown when a search request returns no results -
-eiher because it violates the query syntax, or because
-the search does not match any manual pages.
-.It \&An error page.
-This cannot happen by merely clicking the
-.Dq Search
-button, but only by manually entering an invalid URI.
-It does not show the search form, but only an error message
-and a link back to the index page.
-.El
-.Ss Setup
-For each manual tree, create one first-level subdirectory below
-.Pa /var/www/man .
-The name of one of these directories is called a
-.Dq manpath
-in the context of
-.Nm .
-Create a single ASCII text file
-.Pa /var/www/man/manpath.conf
-containing the names of these directories, one per line.
-The directory given first is used as the default manpath.
-.Pp
-Inside each of these directories, use the same directory and file
-structure as found below
-.Pa /usr/share/man ,
-that is, second-level subdirectories
-.Pa /var/www/man/*/man1 , /var/www/man/*/man2
-etc. containing source
-.Xr mdoc 7
-and
-.Xr man 7
-manuals with file name extensions matching the section numbers,
-second-level subdirectories
-.Pa /var/www/man/*/cat1 , /var/www/man/*/cat2
-etc. containing preformatted manuals with the file name extension
-.Sq 0 ,
-and optional third-level subdirectories for architectures.
-Use
-.Xr makewhatis 8
-to create a
-.Xr mandoc.db 5
-database inside each manpath.
-.Pp
-Configure your web server to execute CGI programs located in
-.Pa /cgi-bin .
-When using
-.Ox
-.Xr httpd 8 ,
-the
-.Xr slowcgi 8
-proxy daemon is needed to translate FastCGI requests to plain old CGI.
-.Pp
-To compile
-.Nm ,
-first copy
-.Pa cgi.h.example
-to
-.Pa cgi.h
-and edit it according to your needs.
-It contains the following compile-time definitions:
-.Bl -tag -width Ds
-.It Ev COMPAT_OLDURI
-Only useful for running on www.openbsd.org to deal with old URIs containing
-.Qq "manpath=OpenBSD "
-where the blank character has to be translated to a hyphen.
-When compiling for other sites, this definition can be deleted.
-.It Dv CSS_DIR
-An optional file system path to the directory containing the file
-.Pa mandoc.css ,
-to be specified relative to the server's document root,
-and to be specified without a trailing slash.
-When empty, the CSS file is assumed to be in the document root.
-Otherwise, a leading slash is needed.
-This is used in generated HTML code.
-.It Dv CUSTOMIZE_TITLE
-An ASCII string to be used for the HTML <TITLE> element.
-.It Dv MAN_DIR
-A file system path to the
-.Nm
-data directory relative to the web server
-.Xr chroot 2
-directory, to be specified with a leading slash and without a trailing slash.
-It needs to have at least one component; the root directory cannot be used
-for this purpose.
-The files
-.Pa manpath.conf ,
-.Pa header.html ,
-and
-.Pa footer.html
-are looked up in this directory.
-It is also prepended to the manpath when opening
-.Xr mandoc.db 5
-and manual page files.
-.It Dv SCRIPT_NAME
-The initial component of URIs, to be specified without leading
-and trailing slashes.
-It can be empty.
-.El
-.Pp
-After editing
-.Pa cgi.h ,
-run
-.Pp
-.Dl make man.cgi
-.Pp
-and copy the resulting binary to the proper location,
-for example using the command:
-.Pp
-.Dl make installcgi
-.Pp
-In addition to that, make sure the default manpath contains the files
-.Pa man1/apropos.1
-and
-.Pa man8/man.cgi.8 ,
-or the documentation links at the bottom of the index page will not work.
-.Ss URI interface
-.Nm
-uniform resource identifiers are not needed for interactive use,
-but can be useful for deep linking.
-They consist of:
-.Bl -enum
-.It
-The
-.Cm http://
-protocol specifier.
-.It
-The host name.
-.It
-The
-.Dv SCRIPT_NAME ,
-preceded by a slash unless empty.
-.It
-To show a single page, a slash, the manpath, another slash,
-and the name of the requested file, for example
-.Pa /OpenBSD-current/man1/mandoc.1 .
-This can be abbreviated according to the following syntax:
-.Sm off
-.Op / Ar manpath
-.Op / Cm man Ar sec
-.Op / Ar arch
-.Pf / Ar name Op \&. Ar sec
-.Sm on
-.It
-For searches, a query string starting with a question mark
-and consisting of
-.Ar key Ns = Ns Ar value
-pairs, separated by ampersands, for example
-.Pa ?manpath=OpenBSD-current&query=mandoc .
-Supported keys are
-.Cm manpath ,
-.Cm query ,
-.Cm sec ,
-.Cm arch ,
-corresponding to
-.Xr apropos 1
-.Fl M ,
-.Ar expression ,
-.Fl s ,
-.Fl S ,
-respectively, and
-.Cm apropos ,
-which is a boolean parameter to select or deselect the
-.Xr apropos 1
-query mode.
-For backward compatibility with the traditional
-.Nm ,
-.Cm sektion
-is supported as an alias for
-.Cm sec .
-.El
-.Ss Restricted character set
-For security reasons, in particular to prevent cross site scripting
-attacks, some strings used by
-.Nm
-can only contain the following characters:
-.Pp
-.Bl -dash -compact -offset indent
-.It
-lower case and upper case ASCII letters
-.It
-the ten decimal digits
-.It
-the dash
-.Pq Sq -
-.It
-the dot
-.Pq Sq \&.
-.It
-the slash
-.Pq Sq /
-.It
-the underscore
-.Pq Sq _
-.El
-.Pp
-In particular, this applies to all manpaths and architecture names.
-.Sh ENVIRONMENT
-The web server may pass the following CGI variables to
-.Nm :
-.Bl -tag -width Ds
-.It Ev SCRIPT_NAME
-The initial part of the URI passed from the client to the server,
-starting after the server's host name and ending before
-.Ev PATH_INFO .
-This is ignored by
-.Nm .
-When constructing URIs for links and redirections, the
-.Dv SCRIPT_NAME
-preprocessor constant is used instead.
-.It Ev PATH_INFO
-The final part of the URI path passed from the client to the server,
-starting after the
-.Ev SCRIPT_NAME
-and ending before the
-.Ev QUERY_STRING .
-It is used by the
-.Cm show
-page to acquire the manpath and filename it needs.
-.It Ev QUERY_STRING
-The HTTP query string passed from the client to the server.
-It is the final part of the URI, after the question mark.
-It is used by the
-.Cm search
-page to acquire the named parameters it needs.
-.El
-.Sh FILES
-.Bl -tag -width Ds
-.It Pa /var/www
-Default web server
-.Xr chroot 2
-directory.
-All the following paths are specified relative to this directory.
-.It Pa /cgi-bin/man.cgi
-The usual file system path to the
-.Nm
-program inside the web server
-.Xr chroot 2
-directory.
-A different name can be chosen, but in any case, it needs to be configured in
-.Xr httpd.conf 5 .
-.It Pa /htdocs
-The file system path to the server document root directory
-relative to the server
-.Xr chroot 2
-directory.
-This is part of the web server configuration and not specific to
-.Nm .
-.It Pa /htdocs/mandoc.css
-A style sheet for
-.Xr mandoc 1
-HTML styling, referenced from each generated HTML page.
-.It Pa /man
-Default
-.Nm
-data directory containing all the manual trees.
-Can be overridden by
-.Dv MAN_DIR .
-.It Pa /man/manpath.conf
-The list of available manpaths, one per line.
-If any of the lines in this file contains a slash
-.Pq Sq /
-or any character not contained in the
-.Sx Restricted character set ,
-.Nm
-reports an internal server error and exits without doing anything.
-.It Pa /man/header.html
-An optional file containing static HTML code to be inserted right
-after opening the <BODY> element.
-.It Pa /man/footer.html
-An optional file containing static HTML code to be inserted right
-before closing the <BODY> element.
-.It Pa /man/OpenBSD-current/man1/mandoc.1
-An example
-.Xr mdoc 7
-source file located below the
-.Dq OpenBSD-current
-manpath.
-.El
-.Sh COMPATIBILITY
-The
-.Nm
-CGI program is call-compatible with queries from the traditional
-.Pa man.cgi
-script by Wolfram Schneider.
-However, the output may not be quite the same.
-.Sh SEE ALSO
-.Xr apropos 1 ,
-.Xr mandoc.db 5 ,
-.Xr makewhatis 8 ,
-.Xr slowcgi 8
-.Sh HISTORY
-A version of
-.Nm
-based on
-.Xr mandoc 1
-first appeared in mdocml-1.12.1 (March 2012).
-The current
-.Xr mandoc.db 5
-database format first appeared in
-.Ox 6.1 .
-.Sh AUTHORS
-.An -nosplit
-The
-.Nm
-program was written by
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
-and is maintained by
-.An Ingo Schwarze Aq Mt schwarze@openbsd.org ,
-who also designed and implemented the database format.

Property changes on: head/contrib/mdocml/man.cgi.8
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/lib.in
===================================================================
--- head/contrib/mdocml/lib.in	(revision 338825)
+++ head/contrib/mdocml/lib.in	(nonexistent)
@@ -1,133 +0,0 @@
-/*	$Id: lib.in,v 1.19 2016/11/23 20:22:13 schwarze Exp $ */
-/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2009, 2012 Joerg Sonnenberger <joerg@netbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * These are all possible .Lb strings.  When a new library is added, add
- * its short-string to the left-hand side and formatted string to the
- * right-hand side.
- *
- * Be sure to escape strings.
- */
-
-LINE("lib80211",	"802.11 Wireless Network Management Library (lib80211, \\-l80211)")
-LINE("libarchive",	"Streaming Archive Library (libarchive, \\-larchive)")
-LINE("libarm",		"ARM Architecture Library (libarm, \\-larm)")
-LINE("libarm32",	"ARM32 Architecture Library (libarm32, \\-larm32)")
-LINE("libbe",		"Boot Environment Library (libbe, \\-lbe)")
-LINE("libbluetooth",	"Bluetooth Library (libbluetooth, \\-lbluetooth)")
-LINE("libbsm",		"Basic Security Module Library (libbsm, \\-lbsm)")
-LINE("libc",		"Standard C\\~Library (libc, \\-lc)")
-LINE("libc_r",		"Reentrant C\\~Library (libc_r, \\-lc_r)")
-LINE("libcalendar",	"Calendar Arithmetic Library (libcalendar, \\-lcalendar)")
-LINE("libcam",		"Common Access Method User Library (libcam, \\-lcam)")
-LINE("libcasper",	"Casper Library (libcasper, \\-lcasper)")
-LINE("libcdk",		"Curses Development Kit Library (libcdk, \\-lcdk)")
-LINE("libcipher",	"FreeSec Crypt Library (libcipher, \\-lcipher)")
-LINE("libcompat",	"Compatibility Library (libcompat, \\-lcompat)")
-LINE("libcrypt",	"Crypt Library (libcrypt, \\-lcrypt)")
-LINE("libcurses",	"Curses Library (libcurses, \\-lcurses)")
-LINE("libcuse", 	"Userland Character Device Library (libcuse, \\-lcuse)")
-LINE("libdevattr",	"Device attribute and event library (libdevattr, \\-ldevattr)")
-LINE("libdevctl",	"Device Control Library (libdevctl, \\-ldevctl)")
-LINE("libdevinfo",	"Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)")
-LINE("libdevstat",	"Device Statistics Library (libdevstat, \\-ldevstat)")
-LINE("libdisk",		"Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)")
-LINE("libdl",		"Dynamic Linker Services Filter (libdl, \\-ldl)")
-LINE("libdm",		"Device Mapper Library (libdm, \\-ldm)")
-LINE("libdwarf",	"DWARF Access Library (libdwarf, \\-ldwarf)")
-LINE("libedit",		"Command Line Editor Library (libedit, \\-ledit)")
-LINE("libefi",		"EFI Runtime Services Library (libefi, \\-lefi)")
-LINE("libelf",		"ELF Access Library (libelf, \\-lelf)")
-LINE("libevent",	"Event Notification Library (libevent, \\-levent)")
-LINE("libexecinfo",	"Backtrace Information Library (libexecinfo, \\-lexecinfo)")
-LINE("libfetch",	"File Transfer Library (libfetch, \\-lfetch)")
-LINE("libfsid",		"Filesystem Identification Library (libfsid, \\-lfsid)")
-LINE("libftpio",	"FTP Connection Management Library (libftpio, \\-lftpio)")
-LINE("libform",		"Curses Form Library (libform, \\-lform)")
-LINE("libgeom",		"Userland API Library for Kernel GEOM subsystem (libgeom, \\-lgeom)")
-LINE("libgpio",		"General-Purpose Input Output (GPIO) library (libgpio, \\-lgpio)")
-LINE("libhammer",	"HAMMER Filesystem Userland Library (libhammer, \\-lhammer)")
-LINE("libi386",		"i386 Architecture Library (libi386, \\-li386)")
-LINE("libintl",		"Internationalized Message Handling Library (libintl, \\-lintl)")
-LINE("libipsec",	"IPsec Policy Control Library (libipsec, \\-lipsec)")
-LINE("libiscsi",	"iSCSI protocol library (libiscsi, \\-liscsi)")
-LINE("libisns",		"Internet Storage Name Service Library (libisns, \\-lisns)")
-LINE("libjail",		"Jail Library (libjail, \\-ljail)")
-LINE("libkcore",	"Kernel Memory Core Access Library (libkcore, \\-lkcore)")
-LINE("libkiconv",	"Kernel-side iconv Library (libkiconv, \\-lkiconv)")
-LINE("libkse",		"N:M Threading Library (libkse, \\-lkse)")
-LINE("libkvm",		"Kernel Data Access Library (libkvm, \\-lkvm)")
-LINE("libm",		"Math Library (libm, \\-lm)")
-LINE("libm68k",		"m68k Architecture Library (libm68k, \\-lm68k)")
-LINE("libmagic",	"Magic Number Recognition Library (libmagic, \\-lmagic)")
-LINE("libmandoc",	"Mandoc Macro Compiler Library (libmandoc, \\-lmandoc)")
-LINE("libmd",		"Message Digest (MD4, MD5, etc.) Support Library (libmd, \\-lmd)")
-LINE("libmemstat",	"Kernel Memory Allocator Statistics Library (libmemstat, \\-lmemstat)")
-LINE("libmenu",		"Curses Menu Library (libmenu, \\-lmenu)")
-LINE("libmj",		"Minimalist JSON library (libmj, \\-lmj)")
-LINE("libnetgraph",	"Netgraph User Library (libnetgraph, \\-lnetgraph)")
-LINE("libnetpgp",	"Netpgp Signing, Verification, Encryption and Decryption (libnetpgp, \\-lnetpgp)")
-LINE("libnetpgpverify",	"Netpgp Verification (libnetpgpverify, \\-lnetpgpverify)")
-LINE("libnpf",		"NPF Packet Filter Library (libnpf, \\-lnpf)")
-LINE("libnv",		"Name/value pairs library (libnv, \\-lnv)")
-LINE("libossaudio",	"OSS Audio Emulation Library (libossaudio, \\-lossaudio)")
-LINE("libpam",		"Pluggable Authentication Module Library (libpam, \\-lpam)")
-LINE("libpanel",	"Z-order for curses windows (libpanel, \\-lpanel)")
-LINE("libpcap",		"Packet capture Library (libpcap, \\-lpcap)")
-LINE("libpci",		"PCI Bus Access Library (libpci, \\-lpci)")
-LINE("libpmc",		"Performance Counters Library (libpmc, \\-lpmc)")
-LINE("libppath",	"Property-List Paths Library (libppath, \\-lppath)")
-LINE("libposix",	"POSIX Compatibility Library (libposix, \\-lposix)")
-LINE("libposix1e",	"POSIX.1e Security API Library (libposix1e, \\-lposix1e)")
-LINE("libppath",	"Property-List Paths Library (libppath, \\-lppath)")
-LINE("libproc",		"Processor Monitoring and Analysis Library (libproc, \\-lproc)")
-LINE("libprocstat",	"Process and Files Information Retrieval (libprocstat, \\-lprocstat)")
-LINE("libprop",		"Property Container Object Library (libprop, \\-lprop)")
-LINE("libpthread",	"POSIX Threads Library (libpthread, \\-lpthread)")
-LINE("libpthread_dbg",	"POSIX Debug Threads Library (libpthread_dbg, \\-lpthread_dbg)")
-LINE("libpuffs",	"puffs Convenience Library (libpuffs, \\-lpuffs)")
-LINE("libquota",	"Disk Quota Access and Control Library (libquota, \\-lquota)")
-LINE("libradius",	"RADIUS Client Library (libradius, \\-lradius)")
-LINE("librefuse",	"File System in Userspace Convenience Library (librefuse, \\-lrefuse)")
-LINE("libresolv",	"DNS Resolver Library (libresolv, \\-lresolv)")
-LINE("librpcsec_gss",	"RPC GSS-API Authentication Library (librpcsec_gss, \\-lrpcsec_gss)")
-LINE("librpcsvc",	"RPC Service Library (librpcsvc, \\-lrpcsvc)")
-LINE("librt",		"POSIX Real\\-time Library (librt, \\-lrt)")
-LINE("librtld_db",	"Debugging interface to the runtime linker Library (librtld_db, \\-lrtld_db)")
-LINE("librumpclient",	"Clientside Stubs for rump Kernel Remote Protocols (librumpclient, \\-lrumpclient)")
-LINE("libsaslc",	"Simple Authentication and Security Layer client library (libsaslc, \\-lsaslc)")
-LINE("libsbuf",		"Safe String Composition Library (libsbuf, \\-lsbuf)")
-LINE("libsdp",		"Bluetooth Service Discovery Protocol User Library (libsdp, \\-lsdp)")
-LINE("libssp",		"Buffer Overflow Protection Library (libssp, \\-lssp)")
-LINE("libstdthreads",	"C11 Threads Library (libstdthreads, \\-lstdthreads)")
-LINE("libSystem",	"System Library (libSystem, \\-lSystem)")
-LINE("libsysdecode",	"System Argument Decoding Library (libsysdecode, \\-lsysdecode)")
-LINE("libtacplus",	"TACACS+ Client Library (libtacplus, \\-ltacplus)")
-LINE("libtcplay",	"TrueCrypt-compatible API library (libtcplay, \\-ltcplay)")
-LINE("libtermcap",	"Termcap Access Library (libtermcap, \\-ltermcap)")
-LINE("libterminfo",	"Terminal Information Library (libterminfo, \\-lterminfo)")
-LINE("libthr",		"1:1 Threading Library (libthr, \\-lthr)")
-LINE("libufs",		"UFS File System Access Library (libufs, \\-lufs)")
-LINE("libugidfw",	"File System Firewall Interface Library (libugidfw, \\-lugidfw)")
-LINE("libulog",		"User Login Record Library (libulog, \\-lulog)")
-LINE("libusbhid",	"USB Human Interface Devices Library (libusbhid, \\-lusbhid)")
-LINE("libutil",		"System Utilities Library (libutil, \\-lutil)")
-LINE("libvgl",		"Video Graphics Library (libvgl, \\-lvgl)")
-LINE("libx86_64",	"x86_64 Architecture Library (libx86_64, \\-lx86_64)")
-LINE("libxo",		"Text, XML, JSON, and HTML Output Emission Library (libxo, \\-lxo)")
-LINE("libz",		"Compression Library (libz, \\-lz)")

Property changes on: head/contrib/mdocml/lib.in
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mandocdb.c
===================================================================
--- head/contrib/mdocml/mandocdb.c	(revision 338825)
+++ head/contrib/mdocml/mandocdb.c	(nonexistent)
@@ -1,2338 +0,0 @@
-/*	$Id: mandocdb.c,v 1.253 2017/07/28 14:48:25 schwarze Exp $ */
-/*
- * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
- * Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <assert.h>
-#include <ctype.h>
-#if HAVE_ERR
-#include <err.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#if HAVE_FTS
-#include <fts.h>
-#else
-#include "compat_fts.h"
-#endif
-#include <limits.h>
-#if HAVE_SANDBOX_INIT
-#include <sandbox.h>
-#endif
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "mandoc_aux.h"
-#include "mandoc_ohash.h"
-#include "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "man.h"
-#include "manconf.h"
-#include "mansearch.h"
-#include "dba_array.h"
-#include "dba.h"
-
-extern const char *const mansearch_keynames[];
-
-enum	op {
-	OP_DEFAULT = 0, /* new dbs from dir list or default config */
-	OP_CONFFILE, /* new databases from custom config file */
-	OP_UPDATE, /* delete/add entries in existing database */
-	OP_DELETE, /* delete entries from existing database */
-	OP_TEST /* change no databases, report potential problems */
-};
-
-struct	str {
-	const struct mpage *mpage; /* if set, the owning parse */
-	uint64_t	 mask; /* bitmask in sequence */
-	char		 key[]; /* rendered text */
-};
-
-struct	inodev {
-	ino_t		 st_ino;
-	dev_t		 st_dev;
-};
-
-struct	mpage {
-	struct inodev	 inodev;  /* used for hashing routine */
-	struct dba_array *dba;
-	char		*sec;     /* section from file content */
-	char		*arch;    /* architecture from file content */
-	char		*title;   /* title from file content */
-	char		*desc;    /* description from file content */
-	struct mpage	*next;    /* singly linked list */
-	struct mlink	*mlinks;  /* singly linked list */
-	int		 name_head_done;
-	enum form	 form;    /* format from file content */
-};
-
-struct	mlink {
-	char		 file[PATH_MAX]; /* filename rel. to manpath */
-	char		*dsec;    /* section from directory */
-	char		*arch;    /* architecture from directory */
-	char		*name;    /* name from file name (not empty) */
-	char		*fsec;    /* section from file name suffix */
-	struct mlink	*next;    /* singly linked list */
-	struct mpage	*mpage;   /* parent */
-	int		 gzip;	  /* filename has a .gz suffix */
-	enum form	 dform;   /* format from directory */
-	enum form	 fform;   /* format from file name suffix */
-};
-
-typedef	int (*mdoc_fp)(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-
-struct	mdoc_handler {
-	mdoc_fp		 fp; /* optional handler */
-	uint64_t	 mask;  /* set unless handler returns 0 */
-	int		 taboo;  /* node flags that must not be set */
-};
-
-
-int		 mandocdb(int, char *[]);
-
-static	void	 dbadd(struct dba *, struct mpage *);
-static	void	 dbadd_mlink(const struct mlink *mlink);
-static	void	 dbprune(struct dba *);
-static	void	 dbwrite(struct dba *);
-static	void	 filescan(const char *);
-#if HAVE_FTS_COMPARE_CONST
-static	int	 fts_compare(const FTSENT *const *, const FTSENT *const *);
-#else
-static	int	 fts_compare(const FTSENT **, const FTSENT **);
-#endif
-static	void	 mlink_add(struct mlink *, const struct stat *);
-static	void	 mlink_check(struct mpage *, struct mlink *);
-static	void	 mlink_free(struct mlink *);
-static	void	 mlinks_undupe(struct mpage *);
-static	void	 mpages_free(void);
-static	void	 mpages_merge(struct dba *, struct mparse *);
-static	void	 parse_cat(struct mpage *, int);
-static	void	 parse_man(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	void	 parse_mdoc(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	int	 parse_mdoc_head(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	int	 parse_mdoc_Fd(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	void	 parse_mdoc_fname(struct mpage *, const struct roff_node *);
-static	int	 parse_mdoc_Fn(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	int	 parse_mdoc_Fo(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	int	 parse_mdoc_Nd(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	int	 parse_mdoc_Nm(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	int	 parse_mdoc_Sh(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	int	 parse_mdoc_Va(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	int	 parse_mdoc_Xr(struct mpage *, const struct roff_meta *,
-			const struct roff_node *);
-static	void	 putkey(const struct mpage *, char *, uint64_t);
-static	void	 putkeys(const struct mpage *, char *, size_t, uint64_t);
-static	void	 putmdockey(const struct mpage *,
-			const struct roff_node *, uint64_t, int);
-static	int	 render_string(char **, size_t *);
-static	void	 say(const char *, const char *, ...)
-			__attribute__((__format__ (__printf__, 2, 3)));
-static	int	 set_basedir(const char *, int);
-static	int	 treescan(void);
-static	size_t	 utf8(unsigned int, char [7]);
-
-static	int		 nodb; /* no database changes */
-static	int		 mparse_options; /* abort the parse early */
-static	int		 use_all; /* use all found files */
-static	int		 debug; /* print what we're doing */
-static	int		 warnings; /* warn about crap */
-static	int		 write_utf8; /* write UTF-8 output; else ASCII */
-static	int		 exitcode; /* to be returned by main */
-static	enum op		 op; /* operational mode */
-static	char		 basedir[PATH_MAX]; /* current base directory */
-static	struct mpage	*mpage_head; /* list of distinct manual pages */
-static	struct ohash	 mpages; /* table of distinct manual pages */
-static	struct ohash	 mlinks; /* table of directory entries */
-static	struct ohash	 names; /* table of all names */
-static	struct ohash	 strings; /* table of all strings */
-static	uint64_t	 name_mask;
-
-static	const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
-	{ NULL, 0, NODE_NOPRT },  /* Dd */
-	{ NULL, 0, NODE_NOPRT },  /* Dt */
-	{ NULL, 0, NODE_NOPRT },  /* Os */
-	{ parse_mdoc_Sh, TYPE_Sh, 0 }, /* Sh */
-	{ parse_mdoc_head, TYPE_Ss, 0 }, /* Ss */
-	{ NULL, 0, 0 },  /* Pp */
-	{ NULL, 0, 0 },  /* D1 */
-	{ NULL, 0, 0 },  /* Dl */
-	{ NULL, 0, 0 },  /* Bd */
-	{ NULL, 0, 0 },  /* Ed */
-	{ NULL, 0, 0 },  /* Bl */
-	{ NULL, 0, 0 },  /* El */
-	{ NULL, 0, 0 },  /* It */
-	{ NULL, 0, 0 },  /* Ad */
-	{ NULL, TYPE_An, 0 },  /* An */
-	{ NULL, 0, 0 },  /* Ap */
-	{ NULL, TYPE_Ar, 0 },  /* Ar */
-	{ NULL, TYPE_Cd, 0 },  /* Cd */
-	{ NULL, TYPE_Cm, 0 },  /* Cm */
-	{ NULL, TYPE_Dv, 0 },  /* Dv */
-	{ NULL, TYPE_Er, 0 },  /* Er */
-	{ NULL, TYPE_Ev, 0 },  /* Ev */
-	{ NULL, 0, 0 },  /* Ex */
-	{ NULL, TYPE_Fa, 0 },  /* Fa */
-	{ parse_mdoc_Fd, 0, 0 },  /* Fd */
-	{ NULL, TYPE_Fl, 0 },  /* Fl */
-	{ parse_mdoc_Fn, 0, 0 },  /* Fn */
-	{ NULL, TYPE_Ft, 0 },  /* Ft */
-	{ NULL, TYPE_Ic, 0 },  /* Ic */
-	{ NULL, TYPE_In, 0 },  /* In */
-	{ NULL, TYPE_Li, 0 },  /* Li */
-	{ parse_mdoc_Nd, 0, 0 },  /* Nd */
-	{ parse_mdoc_Nm, 0, 0 },  /* Nm */
-	{ NULL, 0, 0 },  /* Op */
-	{ NULL, 0, 0 },  /* Ot */
-	{ NULL, TYPE_Pa, NODE_NOSRC },  /* Pa */
-	{ NULL, 0, 0 },  /* Rv */
-	{ NULL, TYPE_St, 0 },  /* St */
-	{ parse_mdoc_Va, TYPE_Va, 0 },  /* Va */
-	{ parse_mdoc_Va, TYPE_Vt, 0 },  /* Vt */
-	{ parse_mdoc_Xr, 0, 0 },  /* Xr */
-	{ NULL, 0, 0 },  /* %A */
-	{ NULL, 0, 0 },  /* %B */
-	{ NULL, 0, 0 },  /* %D */
-	{ NULL, 0, 0 },  /* %I */
-	{ NULL, 0, 0 },  /* %J */
-	{ NULL, 0, 0 },  /* %N */
-	{ NULL, 0, 0 },  /* %O */
-	{ NULL, 0, 0 },  /* %P */
-	{ NULL, 0, 0 },  /* %R */
-	{ NULL, 0, 0 },  /* %T */
-	{ NULL, 0, 0 },  /* %V */
-	{ NULL, 0, 0 },  /* Ac */
-	{ NULL, 0, 0 },  /* Ao */
-	{ NULL, 0, 0 },  /* Aq */
-	{ NULL, TYPE_At, 0 },  /* At */
-	{ NULL, 0, 0 },  /* Bc */
-	{ NULL, 0, 0 },  /* Bf */
-	{ NULL, 0, 0 },  /* Bo */
-	{ NULL, 0, 0 },  /* Bq */
-	{ NULL, TYPE_Bsx, NODE_NOSRC },  /* Bsx */
-	{ NULL, TYPE_Bx, NODE_NOSRC },  /* Bx */
-	{ NULL, 0, 0 },  /* Db */
-	{ NULL, 0, 0 },  /* Dc */
-	{ NULL, 0, 0 },  /* Do */
-	{ NULL, 0, 0 },  /* Dq */
-	{ NULL, 0, 0 },  /* Ec */
-	{ NULL, 0, 0 },  /* Ef */
-	{ NULL, TYPE_Em, 0 },  /* Em */
-	{ NULL, 0, 0 },  /* Eo */
-	{ NULL, TYPE_Fx, NODE_NOSRC },  /* Fx */
-	{ NULL, TYPE_Ms, 0 },  /* Ms */
-	{ NULL, 0, 0 },  /* No */
-	{ NULL, 0, 0 },  /* Ns */
-	{ NULL, TYPE_Nx, NODE_NOSRC },  /* Nx */
-	{ NULL, TYPE_Ox, NODE_NOSRC },  /* Ox */
-	{ NULL, 0, 0 },  /* Pc */
-	{ NULL, 0, 0 },  /* Pf */
-	{ NULL, 0, 0 },  /* Po */
-	{ NULL, 0, 0 },  /* Pq */
-	{ NULL, 0, 0 },  /* Qc */
-	{ NULL, 0, 0 },  /* Ql */
-	{ NULL, 0, 0 },  /* Qo */
-	{ NULL, 0, 0 },  /* Qq */
-	{ NULL, 0, 0 },  /* Re */
-	{ NULL, 0, 0 },  /* Rs */
-	{ NULL, 0, 0 },  /* Sc */
-	{ NULL, 0, 0 },  /* So */
-	{ NULL, 0, 0 },  /* Sq */
-	{ NULL, 0, 0 },  /* Sm */
-	{ NULL, 0, 0 },  /* Sx */
-	{ NULL, TYPE_Sy, 0 },  /* Sy */
-	{ NULL, TYPE_Tn, 0 },  /* Tn */
-	{ NULL, 0, NODE_NOSRC },  /* Ux */
-	{ NULL, 0, 0 },  /* Xc */
-	{ NULL, 0, 0 },  /* Xo */
-	{ parse_mdoc_Fo, 0, 0 },  /* Fo */
-	{ NULL, 0, 0 },  /* Fc */
-	{ NULL, 0, 0 },  /* Oo */
-	{ NULL, 0, 0 },  /* Oc */
-	{ NULL, 0, 0 },  /* Bk */
-	{ NULL, 0, 0 },  /* Ek */
-	{ NULL, 0, 0 },  /* Bt */
-	{ NULL, 0, 0 },  /* Hf */
-	{ NULL, 0, 0 },  /* Fr */
-	{ NULL, 0, 0 },  /* Ud */
-	{ NULL, TYPE_Lb, NODE_NOSRC },  /* Lb */
-	{ NULL, 0, 0 },  /* Lp */
-	{ NULL, TYPE_Lk, 0 },  /* Lk */
-	{ NULL, TYPE_Mt, NODE_NOSRC },  /* Mt */
-	{ NULL, 0, 0 },  /* Brq */
-	{ NULL, 0, 0 },  /* Bro */
-	{ NULL, 0, 0 },  /* Brc */
-	{ NULL, 0, 0 },  /* %C */
-	{ NULL, 0, 0 },  /* Es */
-	{ NULL, 0, 0 },  /* En */
-	{ NULL, TYPE_Dx, NODE_NOSRC },  /* Dx */
-	{ NULL, 0, 0 },  /* %Q */
-	{ NULL, 0, 0 },  /* %U */
-	{ NULL, 0, 0 },  /* Ta */
-};
-static	const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd;
-
-
-int
-mandocdb(int argc, char *argv[])
-{
-	struct manconf	  conf;
-	struct mparse	 *mp;
-	struct dba	 *dba;
-	const char	 *path_arg, *progname;
-	size_t		  j, sz;
-	int		  ch, i;
-
-#if HAVE_PLEDGE
-	if (pledge("stdio rpath wpath cpath fattr flock proc exec", NULL) == -1) {
-		warn("pledge");
-		return (int)MANDOCLEVEL_SYSERR;
-	}
-#endif
-
-#if HAVE_SANDBOX_INIT
-	if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) {
-		warnx("sandbox_init");
-		return (int)MANDOCLEVEL_SYSERR;
-	}
-#endif
-
-	memset(&conf, 0, sizeof(conf));
-
-	/*
-	 * We accept a few different invocations.
-	 * The CHECKOP macro makes sure that invocation styles don't
-	 * clobber each other.
-	 */
-#define	CHECKOP(_op, _ch) do \
-	if (OP_DEFAULT != (_op)) { \
-		warnx("-%c: Conflicting option", (_ch)); \
-		goto usage; \
-	} while (/*CONSTCOND*/0)
-
-	path_arg = NULL;
-	op = OP_DEFAULT;
-
-	while (-1 != (ch = getopt(argc, argv, "aC:Dd:npQT:tu:v")))
-		switch (ch) {
-		case 'a':
-			use_all = 1;
-			break;
-		case 'C':
-			CHECKOP(op, ch);
-			path_arg = optarg;
-			op = OP_CONFFILE;
-			break;
-		case 'D':
-			debug++;
-			break;
-		case 'd':
-			CHECKOP(op, ch);
-			path_arg = optarg;
-			op = OP_UPDATE;
-			break;
-		case 'n':
-			nodb = 1;
-			break;
-		case 'p':
-			warnings = 1;
-			break;
-		case 'Q':
-			mparse_options |= MPARSE_QUICK;
-			break;
-		case 'T':
-			if (strcmp(optarg, "utf8")) {
-				warnx("-T%s: Unsupported output format",
-				    optarg);
-				goto usage;
-			}
-			write_utf8 = 1;
-			break;
-		case 't':
-			CHECKOP(op, ch);
-			dup2(STDOUT_FILENO, STDERR_FILENO);
-			op = OP_TEST;
-			nodb = warnings = 1;
-			break;
-		case 'u':
-			CHECKOP(op, ch);
-			path_arg = optarg;
-			op = OP_DELETE;
-			break;
-		case 'v':
-			/* Compatibility with espie@'s makewhatis. */
-			break;
-		default:
-			goto usage;
-		}
-
-	argc -= optind;
-	argv += optind;
-
-#if HAVE_PLEDGE
-	if (nodb) {
-		if (pledge("stdio rpath", NULL) == -1) {
-			warn("pledge");
-			return (int)MANDOCLEVEL_SYSERR;
-		}
-	}
-#endif
-
-	if (OP_CONFFILE == op && argc > 0) {
-		warnx("-C: Too many arguments");
-		goto usage;
-	}
-
-	exitcode = (int)MANDOCLEVEL_OK;
-	mchars_alloc();
-	mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL,
-	    MANDOC_OS_OTHER, NULL);
-	mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
-	mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
-
-	if (OP_UPDATE == op || OP_DELETE == op || OP_TEST == op) {
-
-		/*
-		 * Most of these deal with a specific directory.
-		 * Jump into that directory first.
-		 */
-		if (OP_TEST != op && 0 == set_basedir(path_arg, 1))
-			goto out;
-
-		dba = nodb ? dba_new(128) : dba_read(MANDOC_DB);
-		if (dba != NULL) {
-			/*
-			 * The existing database is usable.  Process
-			 * all files specified on the command-line.
-			 */
-#if HAVE_PLEDGE
-			if (!nodb) {
-				if (pledge("stdio rpath wpath cpath fattr flock", NULL) == -1) {
-					warn("pledge");
-					exitcode = (int)MANDOCLEVEL_SYSERR;
-					goto out;
-				}
-			}
-#endif
-			use_all = 1;
-			for (i = 0; i < argc; i++)
-				filescan(argv[i]);
-			if (nodb == 0)
-				dbprune(dba);
-		} else {
-			/* Database missing or corrupt. */
-			if (op != OP_UPDATE || errno != ENOENT)
-				say(MANDOC_DB, "%s: Automatically recreating"
-				    " from scratch", strerror(errno));
-			exitcode = (int)MANDOCLEVEL_OK;
-			op = OP_DEFAULT;
-			if (0 == treescan())
-				goto out;
-			dba = dba_new(128);
-		}
-		if (OP_DELETE != op)
-			mpages_merge(dba, mp);
-		if (nodb == 0)
-			dbwrite(dba);
-		dba_free(dba);
-	} else {
-		/*
-		 * If we have arguments, use them as our manpaths.
-		 * If we don't, use man.conf(5).
-		 */
-		if (argc > 0) {
-			conf.manpath.paths = mandoc_reallocarray(NULL,
-			    argc, sizeof(char *));
-			conf.manpath.sz = (size_t)argc;
-			for (i = 0; i < argc; i++)
-				conf.manpath.paths[i] = mandoc_strdup(argv[i]);
-		} else
-			manconf_parse(&conf, path_arg, NULL, NULL);
-
-		if (conf.manpath.sz == 0) {
-			exitcode = (int)MANDOCLEVEL_BADARG;
-			say("", "Empty manpath");
-		}
-
-		/*
-		 * First scan the tree rooted at a base directory, then
-		 * build a new database and finally move it into place.
-		 * Ignore zero-length directories and strip trailing
-		 * slashes.
-		 */
-		for (j = 0; j < conf.manpath.sz; j++) {
-			sz = strlen(conf.manpath.paths[j]);
-			if (sz && conf.manpath.paths[j][sz - 1] == '/')
-				conf.manpath.paths[j][--sz] = '\0';
-			if (0 == sz)
-				continue;
-
-			if (j) {
-				mandoc_ohash_init(&mpages, 6,
-				    offsetof(struct mpage, inodev));
-				mandoc_ohash_init(&mlinks, 6,
-				    offsetof(struct mlink, file));
-			}
-
-			if ( ! set_basedir(conf.manpath.paths[j], argc > 0))
-				continue;
-			if (0 == treescan())
-				continue;
-			dba = dba_new(128);
-			mpages_merge(dba, mp);
-			if (nodb == 0)
-				dbwrite(dba);
-			dba_free(dba);
-
-			if (j + 1 < conf.manpath.sz) {
-				mpages_free();
-				ohash_delete(&mpages);
-				ohash_delete(&mlinks);
-			}
-		}
-	}
-out:
-	manconf_free(&conf);
-	mparse_free(mp);
-	mchars_free();
-	mpages_free();
-	ohash_delete(&mpages);
-	ohash_delete(&mlinks);
-	return exitcode;
-usage:
-	progname = getprogname();
-	fprintf(stderr, "usage: %s [-aDnpQ] [-C file] [-Tutf8]\n"
-			"       %s [-aDnpQ] [-Tutf8] dir ...\n"
-			"       %s [-DnpQ] [-Tutf8] -d dir [file ...]\n"
-			"       %s [-Dnp] -u dir [file ...]\n"
-			"       %s [-Q] -t file ...\n",
-		        progname, progname, progname, progname, progname);
-
-	return (int)MANDOCLEVEL_BADARG;
-}
-
-/*
- * To get a singly linked list in alpha order while inserting entries
- * at the beginning, process directory entries in reverse alpha order.
- */
-static int
-#if HAVE_FTS_COMPARE_CONST
-fts_compare(const FTSENT *const *a, const FTSENT *const *b)
-#else
-fts_compare(const FTSENT **a, const FTSENT **b)
-#endif
-{
-	return -strcmp((*a)->fts_name, (*b)->fts_name);
-}
-
-/*
- * Scan a directory tree rooted at "basedir" for manpages.
- * We use fts(), scanning directory parts along the way for clues to our
- * section and architecture.
- *
- * If use_all has been specified, grok all files.
- * If not, sanitise paths to the following:
- *
- *   [./]man*[/<arch>]/<name>.<section>
- *   or
- *   [./]cat<section>[/<arch>]/<name>.0
- *
- * TODO: accommodate for multi-language directories.
- */
-static int
-treescan(void)
-{
-	char		 buf[PATH_MAX];
-	FTS		*f;
-	FTSENT		*ff;
-	struct mlink	*mlink;
-	int		 gzip;
-	enum form	 dform;
-	char		*dsec, *arch, *fsec, *cp;
-	const char	*path;
-	const char	*argv[2];
-
-	argv[0] = ".";
-	argv[1] = NULL;
-
-	f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR,
-	    fts_compare);
-	if (f == NULL) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "&fts_open");
-		return 0;
-	}
-
-	dsec = arch = NULL;
-	dform = FORM_NONE;
-
-	while ((ff = fts_read(f)) != NULL) {
-		path = ff->fts_path + 2;
-		switch (ff->fts_info) {
-
-		/*
-		 * Symbolic links require various sanity checks,
-		 * then get handled just like regular files.
-		 */
-		case FTS_SL:
-			if (realpath(path, buf) == NULL) {
-				if (warnings)
-					say(path, "&realpath");
-				continue;
-			}
-			if (strstr(buf, basedir) != buf
-#ifdef HOMEBREWDIR
-			    && strstr(buf, HOMEBREWDIR) != buf
-#endif
-			) {
-				if (warnings) say("",
-				    "%s: outside base directory", buf);
-				continue;
-			}
-			/* Use logical inode to avoid mpages dupe. */
-			if (stat(path, ff->fts_statp) == -1) {
-				if (warnings)
-					say(path, "&stat");
-				continue;
-			}
-			/* FALLTHROUGH */
-
-		/*
-		 * If we're a regular file, add an mlink by using the
-		 * stored directory data and handling the filename.
-		 */
-		case FTS_F:
-			if ( ! strcmp(path, MANDOC_DB))
-				continue;
-			if ( ! use_all && ff->fts_level < 2) {
-				if (warnings)
-					say(path, "Extraneous file");
-				continue;
-			}
-			gzip = 0;
-			fsec = NULL;
-			while (fsec == NULL) {
-				fsec = strrchr(ff->fts_name, '.');
-				if (fsec == NULL || strcmp(fsec+1, "gz"))
-					break;
-				gzip = 1;
-				*fsec = '\0';
-				fsec = NULL;
-			}
-			if (fsec == NULL) {
-				if ( ! use_all) {
-					if (warnings)
-						say(path,
-						    "No filename suffix");
-					continue;
-				}
-			} else if ( ! strcmp(++fsec, "html")) {
-				if (warnings)
-					say(path, "Skip html");
-				continue;
-			} else if ( ! strcmp(fsec, "ps")) {
-				if (warnings)
-					say(path, "Skip ps");
-				continue;
-			} else if ( ! strcmp(fsec, "pdf")) {
-				if (warnings)
-					say(path, "Skip pdf");
-				continue;
-			} else if ( ! use_all &&
-			    ((dform == FORM_SRC &&
-			      strncmp(fsec, dsec, strlen(dsec))) ||
-			     (dform == FORM_CAT && strcmp(fsec, "0")))) {
-				if (warnings)
-					say(path, "Wrong filename suffix");
-				continue;
-			} else
-				fsec[-1] = '\0';
-
-			mlink = mandoc_calloc(1, sizeof(struct mlink));
-			if (strlcpy(mlink->file, path,
-			    sizeof(mlink->file)) >=
-			    sizeof(mlink->file)) {
-				say(path, "Filename too long");
-				free(mlink);
-				continue;
-			}
-			mlink->dform = dform;
-			mlink->dsec = dsec;
-			mlink->arch = arch;
-			mlink->name = ff->fts_name;
-			mlink->fsec = fsec;
-			mlink->gzip = gzip;
-			mlink_add(mlink, ff->fts_statp);
-			continue;
-
-		case FTS_D:
-		case FTS_DP:
-			break;
-
-		default:
-			if (warnings)
-				say(path, "Not a regular file");
-			continue;
-		}
-
-		switch (ff->fts_level) {
-		case 0:
-			/* Ignore the root directory. */
-			break;
-		case 1:
-			/*
-			 * This might contain manX/ or catX/.
-			 * Try to infer this from the name.
-			 * If we're not in use_all, enforce it.
-			 */
-			cp = ff->fts_name;
-			if (ff->fts_info == FTS_DP) {
-				dform = FORM_NONE;
-				dsec = NULL;
-				break;
-			}
-
-			if ( ! strncmp(cp, "man", 3)) {
-				dform = FORM_SRC;
-				dsec = cp + 3;
-			} else if ( ! strncmp(cp, "cat", 3)) {
-				dform = FORM_CAT;
-				dsec = cp + 3;
-			} else {
-				dform = FORM_NONE;
-				dsec = NULL;
-			}
-
-			if (dsec != NULL || use_all)
-				break;
-
-			if (warnings)
-				say(path, "Unknown directory part");
-			fts_set(f, ff, FTS_SKIP);
-			break;
-		case 2:
-			/*
-			 * Possibly our architecture.
-			 * If we're descending, keep tabs on it.
-			 */
-			if (ff->fts_info != FTS_DP && dsec != NULL)
-				arch = ff->fts_name;
-			else
-				arch = NULL;
-			break;
-		default:
-			if (ff->fts_info == FTS_DP || use_all)
-				break;
-			if (warnings)
-				say(path, "Extraneous directory part");
-			fts_set(f, ff, FTS_SKIP);
-			break;
-		}
-	}
-
-	fts_close(f);
-	return 1;
-}
-
-/*
- * Add a file to the mlinks table.
- * Do not verify that it's a "valid" looking manpage (we'll do that
- * later).
- *
- * Try to infer the manual section, architecture, and page name from the
- * path, assuming it looks like
- *
- *   [./]man*[/<arch>]/<name>.<section>
- *   or
- *   [./]cat<section>[/<arch>]/<name>.0
- *
- * See treescan() for the fts(3) version of this.
- */
-static void
-filescan(const char *file)
-{
-	char		 buf[PATH_MAX];
-	struct stat	 st;
-	struct mlink	*mlink;
-	char		*p, *start;
-
-	assert(use_all);
-
-	if (0 == strncmp(file, "./", 2))
-		file += 2;
-
-	/*
-	 * We have to do lstat(2) before realpath(3) loses
-	 * the information whether this is a symbolic link.
-	 * We need to know that because for symbolic links,
-	 * we want to use the orginal file name, while for
-	 * regular files, we want to use the real path.
-	 */
-	if (-1 == lstat(file, &st)) {
-		exitcode = (int)MANDOCLEVEL_BADARG;
-		say(file, "&lstat");
-		return;
-	} else if (0 == ((S_IFREG | S_IFLNK) & st.st_mode)) {
-		exitcode = (int)MANDOCLEVEL_BADARG;
-		say(file, "Not a regular file");
-		return;
-	}
-
-	/*
-	 * We have to resolve the file name to the real path
-	 * in any case for the base directory check.
-	 */
-	if (NULL == realpath(file, buf)) {
-		exitcode = (int)MANDOCLEVEL_BADARG;
-		say(file, "&realpath");
-		return;
-	}
-
-	if (OP_TEST == op)
-		start = buf;
-	else if (strstr(buf, basedir) == buf)
-		start = buf + strlen(basedir);
-#ifdef HOMEBREWDIR
-	else if (strstr(buf, HOMEBREWDIR) == buf)
-		start = buf;
-#endif
-	else {
-		exitcode = (int)MANDOCLEVEL_BADARG;
-		say("", "%s: outside base directory", buf);
-		return;
-	}
-
-	/*
-	 * Now we are sure the file is inside our tree.
-	 * If it is a symbolic link, ignore the real path
-	 * and use the original name.
-	 * This implies passing stuff like "cat1/../man1/foo.1"
-	 * on the command line won't work.  So don't do that.
-	 * Note the stat(2) can still fail if the link target
-	 * doesn't exist.
-	 */
-	if (S_IFLNK & st.st_mode) {
-		if (-1 == stat(buf, &st)) {
-			exitcode = (int)MANDOCLEVEL_BADARG;
-			say(file, "&stat");
-			return;
-		}
-		if (strlcpy(buf, file, sizeof(buf)) >= sizeof(buf)) {
-			say(file, "Filename too long");
-			return;
-		}
-		start = buf;
-		if (OP_TEST != op && strstr(buf, basedir) == buf)
-			start += strlen(basedir);
-	}
-
-	mlink = mandoc_calloc(1, sizeof(struct mlink));
-	mlink->dform = FORM_NONE;
-	if (strlcpy(mlink->file, start, sizeof(mlink->file)) >=
-	    sizeof(mlink->file)) {
-		say(start, "Filename too long");
-		free(mlink);
-		return;
-	}
-
-	/*
-	 * In test mode or when the original name is absolute
-	 * but outside our tree, guess the base directory.
-	 */
-
-	if (op == OP_TEST || (start == buf && *start == '/')) {
-		if (strncmp(buf, "man/", 4) == 0)
-			start = buf + 4;
-		else if ((start = strstr(buf, "/man/")) != NULL)
-			start += 5;
-		else
-			start = buf;
-	}
-
-	/*
-	 * First try to guess our directory structure.
-	 * If we find a separator, try to look for man* or cat*.
-	 * If we find one of these and what's underneath is a directory,
-	 * assume it's an architecture.
-	 */
-	if (NULL != (p = strchr(start, '/'))) {
-		*p++ = '\0';
-		if (0 == strncmp(start, "man", 3)) {
-			mlink->dform = FORM_SRC;
-			mlink->dsec = start + 3;
-		} else if (0 == strncmp(start, "cat", 3)) {
-			mlink->dform = FORM_CAT;
-			mlink->dsec = start + 3;
-		}
-
-		start = p;
-		if (NULL != mlink->dsec && NULL != (p = strchr(start, '/'))) {
-			*p++ = '\0';
-			mlink->arch = start;
-			start = p;
-		}
-	}
-
-	/*
-	 * Now check the file suffix.
-	 * Suffix of `.0' indicates a catpage, `.1-9' is a manpage.
-	 */
-	p = strrchr(start, '\0');
-	while (p-- > start && '/' != *p && '.' != *p)
-		/* Loop. */ ;
-
-	if ('.' == *p) {
-		*p++ = '\0';
-		mlink->fsec = p;
-	}
-
-	/*
-	 * Now try to parse the name.
-	 * Use the filename portion of the path.
-	 */
-	mlink->name = start;
-	if (NULL != (p = strrchr(start, '/'))) {
-		mlink->name = p + 1;
-		*p = '\0';
-	}
-	mlink_add(mlink, &st);
-}
-
-static void
-mlink_add(struct mlink *mlink, const struct stat *st)
-{
-	struct inodev	 inodev;
-	struct mpage	*mpage;
-	unsigned int	 slot;
-
-	assert(NULL != mlink->file);
-
-	mlink->dsec = mandoc_strdup(mlink->dsec ? mlink->dsec : "");
-	mlink->arch = mandoc_strdup(mlink->arch ? mlink->arch : "");
-	mlink->name = mandoc_strdup(mlink->name ? mlink->name : "");
-	mlink->fsec = mandoc_strdup(mlink->fsec ? mlink->fsec : "");
-
-	if ('0' == *mlink->fsec) {
-		free(mlink->fsec);
-		mlink->fsec = mandoc_strdup(mlink->dsec);
-		mlink->fform = FORM_CAT;
-	} else if ('1' <= *mlink->fsec && '9' >= *mlink->fsec)
-		mlink->fform = FORM_SRC;
-	else
-		mlink->fform = FORM_NONE;
-
-	slot = ohash_qlookup(&mlinks, mlink->file);
-	assert(NULL == ohash_find(&mlinks, slot));
-	ohash_insert(&mlinks, slot, mlink);
-
-	memset(&inodev, 0, sizeof(inodev));  /* Clear padding. */
-	inodev.st_ino = st->st_ino;
-	inodev.st_dev = st->st_dev;
-	slot = ohash_lookup_memory(&mpages, (char *)&inodev,
-	    sizeof(struct inodev), inodev.st_ino);
-	mpage = ohash_find(&mpages, slot);
-	if (NULL == mpage) {
-		mpage = mandoc_calloc(1, sizeof(struct mpage));
-		mpage->inodev.st_ino = inodev.st_ino;
-		mpage->inodev.st_dev = inodev.st_dev;
-		mpage->form = FORM_NONE;
-		mpage->next = mpage_head;
-		mpage_head = mpage;
-		ohash_insert(&mpages, slot, mpage);
-	} else
-		mlink->next = mpage->mlinks;
-	mpage->mlinks = mlink;
-	mlink->mpage = mpage;
-}
-
-static void
-mlink_free(struct mlink *mlink)
-{
-
-	free(mlink->dsec);
-	free(mlink->arch);
-	free(mlink->name);
-	free(mlink->fsec);
-	free(mlink);
-}
-
-static void
-mpages_free(void)
-{
-	struct mpage	*mpage;
-	struct mlink	*mlink;
-
-	while ((mpage = mpage_head) != NULL) {
-		while ((mlink = mpage->mlinks) != NULL) {
-			mpage->mlinks = mlink->next;
-			mlink_free(mlink);
-		}
-		mpage_head = mpage->next;
-		free(mpage->sec);
-		free(mpage->arch);
-		free(mpage->title);
-		free(mpage->desc);
-		free(mpage);
-	}
-}
-
-/*
- * For each mlink to the mpage, check whether the path looks like
- * it is formatted, and if it does, check whether a source manual
- * exists by the same name, ignoring the suffix.
- * If both conditions hold, drop the mlink.
- */
-static void
-mlinks_undupe(struct mpage *mpage)
-{
-	char		  buf[PATH_MAX];
-	struct mlink	**prev;
-	struct mlink	 *mlink;
-	char		 *bufp;
-
-	mpage->form = FORM_CAT;
-	prev = &mpage->mlinks;
-	while (NULL != (mlink = *prev)) {
-		if (FORM_CAT != mlink->dform) {
-			mpage->form = FORM_NONE;
-			goto nextlink;
-		}
-		(void)strlcpy(buf, mlink->file, sizeof(buf));
-		bufp = strstr(buf, "cat");
-		assert(NULL != bufp);
-		memcpy(bufp, "man", 3);
-		if (NULL != (bufp = strrchr(buf, '.')))
-			*++bufp = '\0';
-		(void)strlcat(buf, mlink->dsec, sizeof(buf));
-		if (NULL == ohash_find(&mlinks,
-		    ohash_qlookup(&mlinks, buf)))
-			goto nextlink;
-		if (warnings)
-			say(mlink->file, "Man source exists: %s", buf);
-		if (use_all)
-			goto nextlink;
-		*prev = mlink->next;
-		mlink_free(mlink);
-		continue;
-nextlink:
-		prev = &(*prev)->next;
-	}
-}
-
-static void
-mlink_check(struct mpage *mpage, struct mlink *mlink)
-{
-	struct str	*str;
-	unsigned int	 slot;
-
-	/*
-	 * Check whether the manual section given in a file
-	 * agrees with the directory where the file is located.
-	 * Some manuals have suffixes like (3p) on their
-	 * section number either inside the file or in the
-	 * directory name, some are linked into more than one
-	 * section, like encrypt(1) = makekey(8).
-	 */
-
-	if (FORM_SRC == mpage->form &&
-	    strcasecmp(mpage->sec, mlink->dsec))
-		say(mlink->file, "Section \"%s\" manual in %s directory",
-		    mpage->sec, mlink->dsec);
-
-	/*
-	 * Manual page directories exist for each kernel
-	 * architecture as returned by machine(1).
-	 * However, many manuals only depend on the
-	 * application architecture as returned by arch(1).
-	 * For example, some (2/ARM) manuals are shared
-	 * across the "armish" and "zaurus" kernel
-	 * architectures.
-	 * A few manuals are even shared across completely
-	 * different architectures, for example fdformat(1)
-	 * on amd64, i386, and sparc64.
-	 */
-
-	if (strcasecmp(mpage->arch, mlink->arch))
-		say(mlink->file, "Architecture \"%s\" manual in "
-		    "\"%s\" directory", mpage->arch, mlink->arch);
-
-	/*
-	 * XXX
-	 * parse_cat() doesn't set NAME_TITLE yet.
-	 */
-
-	if (FORM_CAT == mpage->form)
-		return;
-
-	/*
-	 * Check whether this mlink
-	 * appears as a name in the NAME section.
-	 */
-
-	slot = ohash_qlookup(&names, mlink->name);
-	str = ohash_find(&names, slot);
-	assert(NULL != str);
-	if ( ! (NAME_TITLE & str->mask))
-		say(mlink->file, "Name missing in NAME section");
-}
-
-/*
- * Run through the files in the global vector "mpages"
- * and add them to the database specified in "basedir".
- *
- * This handles the parsing scheme itself, using the cues of directory
- * and filename to determine whether the file is parsable or not.
- */
-static void
-mpages_merge(struct dba *dba, struct mparse *mp)
-{
-	struct mpage		*mpage, *mpage_dest;
-	struct mlink		*mlink, *mlink_dest;
-	struct roff_man		*man;
-	char			*sodest;
-	char			*cp;
-	int			 fd;
-
-	for (mpage = mpage_head; mpage != NULL; mpage = mpage->next) {
-		mlinks_undupe(mpage);
-		if ((mlink = mpage->mlinks) == NULL)
-			continue;
-
-		name_mask = NAME_MASK;
-		mandoc_ohash_init(&names, 4, offsetof(struct str, key));
-		mandoc_ohash_init(&strings, 6, offsetof(struct str, key));
-		mparse_reset(mp);
-		man = NULL;
-		sodest = NULL;
-
-		if ((fd = mparse_open(mp, mlink->file)) == -1) {
-			say(mlink->file, "&open");
-			goto nextpage;
-		}
-
-		/*
-		 * Interpret the file as mdoc(7) or man(7) source
-		 * code, unless it is known to be formatted.
-		 */
-		if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) {
-			mparse_readfd(mp, fd, mlink->file);
-			close(fd);
-			fd = -1;
-			mparse_result(mp, &man, &sodest);
-		}
-
-		if (sodest != NULL) {
-			mlink_dest = ohash_find(&mlinks,
-			    ohash_qlookup(&mlinks, sodest));
-			if (mlink_dest == NULL) {
-				mandoc_asprintf(&cp, "%s.gz", sodest);
-				mlink_dest = ohash_find(&mlinks,
-				    ohash_qlookup(&mlinks, cp));
-				free(cp);
-			}
-			if (mlink_dest != NULL) {
-
-				/* The .so target exists. */
-
-				mpage_dest = mlink_dest->mpage;
-				while (1) {
-					mlink->mpage = mpage_dest;
-
-					/*
-					 * If the target was already
-					 * processed, add the links
-					 * to the database now.
-					 * Otherwise, this will
-					 * happen when we come
-					 * to the target.
-					 */
-
-					if (mpage_dest->dba != NULL)
-						dbadd_mlink(mlink);
-
-					if (mlink->next == NULL)
-						break;
-					mlink = mlink->next;
-				}
-
-				/* Move all links to the target. */
-
-				mlink->next = mlink_dest->next;
-				mlink_dest->next = mpage->mlinks;
-				mpage->mlinks = NULL;
-			}
-			goto nextpage;
-		} else if (man != NULL && man->macroset == MACROSET_MDOC) {
-			mdoc_validate(man);
-			mpage->form = FORM_SRC;
-			mpage->sec = man->meta.msec;
-			mpage->sec = mandoc_strdup(
-			    mpage->sec == NULL ? "" : mpage->sec);
-			mpage->arch = man->meta.arch;
-			mpage->arch = mandoc_strdup(
-			    mpage->arch == NULL ? "" : mpage->arch);
-			mpage->title = mandoc_strdup(man->meta.title);
-		} else if (man != NULL && man->macroset == MACROSET_MAN) {
-			man_validate(man);
-			if (*man->meta.msec != '\0' ||
-			    *man->meta.title != '\0') {
-				mpage->form = FORM_SRC;
-				mpage->sec = mandoc_strdup(man->meta.msec);
-				mpage->arch = mandoc_strdup(mlink->arch);
-				mpage->title = mandoc_strdup(man->meta.title);
-			} else
-				man = NULL;
-		}
-
-		assert(mpage->desc == NULL);
-		if (man == NULL) {
-			mpage->form = FORM_CAT;
-			mpage->sec = mandoc_strdup(mlink->dsec);
-			mpage->arch = mandoc_strdup(mlink->arch);
-			mpage->title = mandoc_strdup(mlink->name);
-			parse_cat(mpage, fd);
-		} else if (man->macroset == MACROSET_MDOC)
-			parse_mdoc(mpage, &man->meta, man->first);
-		else
-			parse_man(mpage, &man->meta, man->first);
-		if (mpage->desc == NULL) {
-			mpage->desc = mandoc_strdup(mlink->name);
-			if (warnings)
-				say(mlink->file, "No one-line description, "
-				    "using filename \"%s\"", mlink->name);
-		}
-
-		for (mlink = mpage->mlinks;
-		     mlink != NULL;
-		     mlink = mlink->next) {
-			putkey(mpage, mlink->name, NAME_FILE);
-			if (warnings && !use_all)
-				mlink_check(mpage, mlink);
-		}
-
-		dbadd(dba, mpage);
-
-nextpage:
-		ohash_delete(&strings);
-		ohash_delete(&names);
-	}
-}
-
-static void
-parse_cat(struct mpage *mpage, int fd)
-{
-	FILE		*stream;
-	struct mlink	*mlink;
-	char		*line, *p, *title, *sec;
-	size_t		 linesz, plen, titlesz;
-	ssize_t		 len;
-	int		 offs;
-
-	mlink = mpage->mlinks;
-	stream = fd == -1 ? fopen(mlink->file, "r") : fdopen(fd, "r");
-	if (stream == NULL) {
-		if (fd != -1)
-			close(fd);
-		if (warnings)
-			say(mlink->file, "&fopen");
-		return;
-	}
-
-	line = NULL;
-	linesz = 0;
-
-	/* Parse the section number from the header line. */
-
-	while (getline(&line, &linesz, stream) != -1) {
-		if (*line == '\n')
-			continue;
-		if ((sec = strchr(line, '(')) == NULL)
-			break;
-		if ((p = strchr(++sec, ')')) == NULL)
-			break;
-		free(mpage->sec);
-		mpage->sec = mandoc_strndup(sec, p - sec);
-		if (warnings && *mlink->dsec != '\0' &&
-		    strcasecmp(mpage->sec, mlink->dsec))
-			say(mlink->file,
-			    "Section \"%s\" manual in %s directory",
-			    mpage->sec, mlink->dsec);
-		break;
-	}
-
-	/* Skip to first blank line. */
-
-	while (line == NULL || *line != '\n')
-		if (getline(&line, &linesz, stream) == -1)
-			break;
-
-	/*
-	 * Assume the first line that is not indented
-	 * is the first section header.  Skip to it.
-	 */
-
-	while (getline(&line, &linesz, stream) != -1)
-		if (*line != '\n' && *line != ' ')
-			break;
-
-	/*
-	 * Read up until the next section into a buffer.
-	 * Strip the leading and trailing newline from each read line,
-	 * appending a trailing space.
-	 * Ignore empty (whitespace-only) lines.
-	 */
-
-	titlesz = 0;
-	title = NULL;
-
-	while ((len = getline(&line, &linesz, stream)) != -1) {
-		if (*line != ' ')
-			break;
-		offs = 0;
-		while (isspace((unsigned char)line[offs]))
-			offs++;
-		if (line[offs] == '\0')
-			continue;
-		title = mandoc_realloc(title, titlesz + len - offs);
-		memcpy(title + titlesz, line + offs, len - offs);
-		titlesz += len - offs;
-		title[titlesz - 1] = ' ';
-	}
-	free(line);
-
-	/*
-	 * If no page content can be found, or the input line
-	 * is already the next section header, or there is no
-	 * trailing newline, reuse the page title as the page
-	 * description.
-	 */
-
-	if (NULL == title || '\0' == *title) {
-		if (warnings)
-			say(mlink->file, "Cannot find NAME section");
-		fclose(stream);
-		free(title);
-		return;
-	}
-
-	title[titlesz - 1] = '\0';
-
-	/*
-	 * Skip to the first dash.
-	 * Use the remaining line as the description (no more than 70
-	 * bytes).
-	 */
-
-	if (NULL != (p = strstr(title, "- "))) {
-		for (p += 2; ' ' == *p || '\b' == *p; p++)
-			/* Skip to next word. */ ;
-	} else {
-		if (warnings)
-			say(mlink->file, "No dash in title line, "
-			    "reusing \"%s\" as one-line description", title);
-		p = title;
-	}
-
-	plen = strlen(p);
-
-	/* Strip backspace-encoding from line. */
-
-	while (NULL != (line = memchr(p, '\b', plen))) {
-		len = line - p;
-		if (0 == len) {
-			memmove(line, line + 1, plen--);
-			continue;
-		}
-		memmove(line - 1, line + 1, plen - len);
-		plen -= 2;
-	}
-
-	mpage->desc = mandoc_strdup(p);
-	fclose(stream);
-	free(title);
-}
-
-/*
- * Put a type/word pair into the word database for this particular file.
- */
-static void
-putkey(const struct mpage *mpage, char *value, uint64_t type)
-{
-	putkeys(mpage, value, strlen(value), type);
-}
-
-/*
- * Grok all nodes at or below a certain mdoc node into putkey().
- */
-static void
-putmdockey(const struct mpage *mpage,
-	const struct roff_node *n, uint64_t m, int taboo)
-{
-
-	for ( ; NULL != n; n = n->next) {
-		if (n->flags & taboo)
-			continue;
-		if (NULL != n->child)
-			putmdockey(mpage, n->child, m, taboo);
-		if (n->type == ROFFT_TEXT)
-			putkey(mpage, n->string, m);
-	}
-}
-
-static void
-parse_man(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-	const struct roff_node *head, *body;
-	char		*start, *title;
-	char		 byte;
-	size_t		 sz;
-
-	if (n == NULL)
-		return;
-
-	/*
-	 * We're only searching for one thing: the first text child in
-	 * the BODY of a NAME section.  Since we don't keep track of
-	 * sections in -man, run some hoops to find out whether we're in
-	 * the correct section or not.
-	 */
-
-	if (n->type == ROFFT_BODY && n->tok == MAN_SH) {
-		body = n;
-		if ((head = body->parent->head) != NULL &&
-		    (head = head->child) != NULL &&
-		    head->next == NULL &&
-		    head->type == ROFFT_TEXT &&
-		    strcmp(head->string, "NAME") == 0 &&
-		    body->child != NULL) {
-
-			/*
-			 * Suck the entire NAME section into memory.
-			 * Yes, we might run away.
-			 * But too many manuals have big, spread-out
-			 * NAME sections over many lines.
-			 */
-
-			title = NULL;
-			deroff(&title, body);
-			if (NULL == title)
-				return;
-
-			/*
-			 * Go through a special heuristic dance here.
-			 * Conventionally, one or more manual names are
-			 * comma-specified prior to a whitespace, then a
-			 * dash, then a description.  Try to puzzle out
-			 * the name parts here.
-			 */
-
-			start = title;
-			for ( ;; ) {
-				sz = strcspn(start, " ,");
-				if ('\0' == start[sz])
-					break;
-
-				byte = start[sz];
-				start[sz] = '\0';
-
-				/*
-				 * Assume a stray trailing comma in the
-				 * name list if a name begins with a dash.
-				 */
-
-				if ('-' == start[0] ||
-				    ('\\' == start[0] && '-' == start[1]))
-					break;
-
-				putkey(mpage, start, NAME_TITLE);
-				if ( ! (mpage->name_head_done ||
-				    strcasecmp(start, meta->title))) {
-					putkey(mpage, start, NAME_HEAD);
-					mpage->name_head_done = 1;
-				}
-
-				if (' ' == byte) {
-					start += sz + 1;
-					break;
-				}
-
-				assert(',' == byte);
-				start += sz + 1;
-				while (' ' == *start)
-					start++;
-			}
-
-			if (start == title) {
-				putkey(mpage, start, NAME_TITLE);
-				if ( ! (mpage->name_head_done ||
-				    strcasecmp(start, meta->title))) {
-					putkey(mpage, start, NAME_HEAD);
-					mpage->name_head_done = 1;
-				}
-				free(title);
-				return;
-			}
-
-			while (isspace((unsigned char)*start))
-				start++;
-
-			if (0 == strncmp(start, "-", 1))
-				start += 1;
-			else if (0 == strncmp(start, "\\-\\-", 4))
-				start += 4;
-			else if (0 == strncmp(start, "\\-", 2))
-				start += 2;
-			else if (0 == strncmp(start, "\\(en", 4))
-				start += 4;
-			else if (0 == strncmp(start, "\\(em", 4))
-				start += 4;
-
-			while (' ' == *start)
-				start++;
-
-			mpage->desc = mandoc_strdup(start);
-			free(title);
-			return;
-		}
-	}
-
-	for (n = n->child; n; n = n->next) {
-		if (NULL != mpage->desc)
-			break;
-		parse_man(mpage, meta, n);
-	}
-}
-
-static void
-parse_mdoc(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-
-	for (n = n->child; n != NULL; n = n->next) {
-		if (n->tok == TOKEN_NONE ||
-		    n->tok < ROFF_MAX ||
-		    n->flags & mdocs[n->tok].taboo)
-			continue;
-		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
-		switch (n->type) {
-		case ROFFT_ELEM:
-		case ROFFT_BLOCK:
-		case ROFFT_HEAD:
-		case ROFFT_BODY:
-		case ROFFT_TAIL:
-			if (mdocs[n->tok].fp != NULL &&
-			    (*mdocs[n->tok].fp)(mpage, meta, n) == 0)
-				break;
-			if (mdocs[n->tok].mask)
-				putmdockey(mpage, n->child,
-				    mdocs[n->tok].mask, mdocs[n->tok].taboo);
-			break;
-		default:
-			continue;
-		}
-		if (NULL != n->child)
-			parse_mdoc(mpage, meta, n);
-	}
-}
-
-static int
-parse_mdoc_Fd(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-	char		*start, *end;
-	size_t		 sz;
-
-	if (SEC_SYNOPSIS != n->sec ||
-	    NULL == (n = n->child) ||
-	    n->type != ROFFT_TEXT)
-		return 0;
-
-	/*
-	 * Only consider those `Fd' macro fields that begin with an
-	 * "inclusion" token (versus, e.g., #define).
-	 */
-
-	if (strcmp("#include", n->string))
-		return 0;
-
-	if ((n = n->next) == NULL || n->type != ROFFT_TEXT)
-		return 0;
-
-	/*
-	 * Strip away the enclosing angle brackets and make sure we're
-	 * not zero-length.
-	 */
-
-	start = n->string;
-	if ('<' == *start || '"' == *start)
-		start++;
-
-	if (0 == (sz = strlen(start)))
-		return 0;
-
-	end = &start[(int)sz - 1];
-	if ('>' == *end || '"' == *end)
-		end--;
-
-	if (end > start)
-		putkeys(mpage, start, end - start + 1, TYPE_In);
-	return 0;
-}
-
-static void
-parse_mdoc_fname(struct mpage *mpage, const struct roff_node *n)
-{
-	char	*cp;
-	size_t	 sz;
-
-	if (n->type != ROFFT_TEXT)
-		return;
-
-	/* Skip function pointer punctuation. */
-
-	cp = n->string;
-	while (*cp == '(' || *cp == '*')
-		cp++;
-	sz = strcspn(cp, "()");
-
-	putkeys(mpage, cp, sz, TYPE_Fn);
-	if (n->sec == SEC_SYNOPSIS)
-		putkeys(mpage, cp, sz, NAME_SYN);
-}
-
-static int
-parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-
-	if (n->child == NULL)
-		return 0;
-
-	parse_mdoc_fname(mpage, n->child);
-
-	for (n = n->child->next; n != NULL; n = n->next)
-		if (n->type == ROFFT_TEXT)
-			putkey(mpage, n->string, TYPE_Fa);
-
-	return 0;
-}
-
-static int
-parse_mdoc_Fo(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-
-	if (n->type != ROFFT_HEAD)
-		return 1;
-
-	if (n->child != NULL)
-		parse_mdoc_fname(mpage, n->child);
-
-	return 0;
-}
-
-static int
-parse_mdoc_Va(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-	char *cp;
-
-	if (n->type != ROFFT_ELEM && n->type != ROFFT_BODY)
-		return 0;
-
-	if (n->child != NULL &&
-	    n->child->next == NULL &&
-	    n->child->type == ROFFT_TEXT)
-		return 1;
-
-	cp = NULL;
-	deroff(&cp, n);
-	if (cp != NULL) {
-		putkey(mpage, cp, TYPE_Vt | (n->tok == MDOC_Va ||
-		    n->type == ROFFT_BODY ? TYPE_Va : 0));
-		free(cp);
-	}
-
-	return 0;
-}
-
-static int
-parse_mdoc_Xr(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-	char	*cp;
-
-	if (NULL == (n = n->child))
-		return 0;
-
-	if (NULL == n->next) {
-		putkey(mpage, n->string, TYPE_Xr);
-		return 0;
-	}
-
-	mandoc_asprintf(&cp, "%s(%s)", n->string, n->next->string);
-	putkey(mpage, cp, TYPE_Xr);
-	free(cp);
-	return 0;
-}
-
-static int
-parse_mdoc_Nd(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-
-	if (n->type == ROFFT_BODY)
-		deroff(&mpage->desc, n);
-	return 0;
-}
-
-static int
-parse_mdoc_Nm(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-
-	if (SEC_NAME == n->sec)
-		putmdockey(mpage, n->child, NAME_TITLE, 0);
-	else if (n->sec == SEC_SYNOPSIS && n->type == ROFFT_HEAD) {
-		if (n->child == NULL)
-			putkey(mpage, meta->name, NAME_SYN);
-		else
-			putmdockey(mpage, n->child, NAME_SYN, 0);
-	}
-	if ( ! (mpage->name_head_done ||
-	    n->child == NULL || n->child->string == NULL ||
-	    strcasecmp(n->child->string, meta->title))) {
-		putkey(mpage, n->child->string, NAME_HEAD);
-		mpage->name_head_done = 1;
-	}
-	return 0;
-}
-
-static int
-parse_mdoc_Sh(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-
-	return n->sec == SEC_CUSTOM && n->type == ROFFT_HEAD;
-}
-
-static int
-parse_mdoc_head(struct mpage *mpage, const struct roff_meta *meta,
-	const struct roff_node *n)
-{
-
-	return n->type == ROFFT_HEAD;
-}
-
-/*
- * Add a string to the hash table for the current manual.
- * Each string has a bitmask telling which macros it belongs to.
- * When we finish the manual, we'll dump the table.
- */
-static void
-putkeys(const struct mpage *mpage, char *cp, size_t sz, uint64_t v)
-{
-	struct ohash	*htab;
-	struct str	*s;
-	const char	*end;
-	unsigned int	 slot;
-	int		 i, mustfree;
-
-	if (0 == sz)
-		return;
-
-	mustfree = render_string(&cp, &sz);
-
-	if (TYPE_Nm & v) {
-		htab = &names;
-		v &= name_mask;
-		if (v & NAME_FIRST)
-			name_mask &= ~NAME_FIRST;
-		if (debug > 1)
-			say(mpage->mlinks->file,
-			    "Adding name %*s, bits=0x%llx", (int)sz, cp,
-			    (unsigned long long)v);
-	} else {
-		htab = &strings;
-		if (debug > 1)
-		    for (i = 0; i < KEY_MAX; i++)
-			if ((uint64_t)1 << i & v)
-			    say(mpage->mlinks->file,
-				"Adding key %s=%*s",
-				mansearch_keynames[i], (int)sz, cp);
-	}
-
-	end = cp + sz;
-	slot = ohash_qlookupi(htab, cp, &end);
-	s = ohash_find(htab, slot);
-
-	if (NULL != s && mpage == s->mpage) {
-		s->mask |= v;
-		return;
-	} else if (NULL == s) {
-		s = mandoc_calloc(1, sizeof(struct str) + sz + 1);
-		memcpy(s->key, cp, sz);
-		ohash_insert(htab, slot, s);
-	}
-	s->mpage = mpage;
-	s->mask = v;
-
-	if (mustfree)
-		free(cp);
-}
-
-/*
- * Take a Unicode codepoint and produce its UTF-8 encoding.
- * This isn't the best way to do this, but it works.
- * The magic numbers are from the UTF-8 packaging.
- * They're not as scary as they seem: read the UTF-8 spec for details.
- */
-static size_t
-utf8(unsigned int cp, char out[7])
-{
-	size_t		 rc;
-
-	rc = 0;
-	if (cp <= 0x0000007F) {
-		rc = 1;
-		out[0] = (char)cp;
-	} else if (cp <= 0x000007FF) {
-		rc = 2;
-		out[0] = (cp >> 6  & 31) | 192;
-		out[1] = (cp       & 63) | 128;
-	} else if (cp <= 0x0000FFFF) {
-		rc = 3;
-		out[0] = (cp >> 12 & 15) | 224;
-		out[1] = (cp >> 6  & 63) | 128;
-		out[2] = (cp       & 63) | 128;
-	} else if (cp <= 0x001FFFFF) {
-		rc = 4;
-		out[0] = (cp >> 18 &  7) | 240;
-		out[1] = (cp >> 12 & 63) | 128;
-		out[2] = (cp >> 6  & 63) | 128;
-		out[3] = (cp       & 63) | 128;
-	} else if (cp <= 0x03FFFFFF) {
-		rc = 5;
-		out[0] = (cp >> 24 &  3) | 248;
-		out[1] = (cp >> 18 & 63) | 128;
-		out[2] = (cp >> 12 & 63) | 128;
-		out[3] = (cp >> 6  & 63) | 128;
-		out[4] = (cp       & 63) | 128;
-	} else if (cp <= 0x7FFFFFFF) {
-		rc = 6;
-		out[0] = (cp >> 30 &  1) | 252;
-		out[1] = (cp >> 24 & 63) | 128;
-		out[2] = (cp >> 18 & 63) | 128;
-		out[3] = (cp >> 12 & 63) | 128;
-		out[4] = (cp >> 6  & 63) | 128;
-		out[5] = (cp       & 63) | 128;
-	} else
-		return 0;
-
-	out[rc] = '\0';
-	return rc;
-}
-
-/*
- * If the string contains escape sequences,
- * replace it with an allocated rendering and return 1,
- * such that the caller can free it after use.
- * Otherwise, do nothing and return 0.
- */
-static int
-render_string(char **public, size_t *psz)
-{
-	const char	*src, *scp, *addcp, *seq;
-	char		*dst;
-	size_t		 ssz, dsz, addsz;
-	char		 utfbuf[7], res[6];
-	int		 seqlen, unicode;
-
-	res[0] = '\\';
-	res[1] = '\t';
-	res[2] = ASCII_NBRSP;
-	res[3] = ASCII_HYPH;
-	res[4] = ASCII_BREAK;
-	res[5] = '\0';
-
-	src = scp = *public;
-	ssz = *psz;
-	dst = NULL;
-	dsz = 0;
-
-	while (scp < src + *psz) {
-
-		/* Leave normal characters unchanged. */
-
-		if (strchr(res, *scp) == NULL) {
-			if (dst != NULL)
-				dst[dsz++] = *scp;
-			scp++;
-			continue;
-		}
-
-		/*
-		 * Found something that requires replacing,
-		 * make sure we have a destination buffer.
-		 */
-
-		if (dst == NULL) {
-			dst = mandoc_malloc(ssz + 1);
-			dsz = scp - src;
-			memcpy(dst, src, dsz);
-		}
-
-		/* Handle single-char special characters. */
-
-		switch (*scp) {
-		case '\\':
-			break;
-		case '\t':
-		case ASCII_NBRSP:
-			dst[dsz++] = ' ';
-			scp++;
-			continue;
-		case ASCII_HYPH:
-			dst[dsz++] = '-';
-			/* FALLTHROUGH */
-		case ASCII_BREAK:
-			scp++;
-			continue;
-		default:
-			abort();
-		}
-
-		/*
-		 * Found an escape sequence.
-		 * Read past the slash, then parse it.
-		 * Ignore everything except characters.
-		 */
-
-		scp++;
-		if (mandoc_escape(&scp, &seq, &seqlen) != ESCAPE_SPECIAL)
-			continue;
-
-		/*
-		 * Render the special character
-		 * as either UTF-8 or ASCII.
-		 */
-
-		if (write_utf8) {
-			unicode = mchars_spec2cp(seq, seqlen);
-			if (unicode <= 0)
-				continue;
-			addsz = utf8(unicode, utfbuf);
-			if (addsz == 0)
-				continue;
-			addcp = utfbuf;
-		} else {
-			addcp = mchars_spec2str(seq, seqlen, &addsz);
-			if (addcp == NULL)
-				continue;
-			if (*addcp == ASCII_NBRSP) {
-				addcp = " ";
-				addsz = 1;
-			}
-		}
-
-		/* Copy the rendered glyph into the stream. */
-
-		ssz += addsz;
-		dst = mandoc_realloc(dst, ssz + 1);
-		memcpy(dst + dsz, addcp, addsz);
-		dsz += addsz;
-	}
-	if (dst != NULL) {
-		*public = dst;
-		*psz = dsz;
-	}
-
-	/* Trim trailing whitespace and NUL-terminate. */
-
-	while (*psz > 0 && (*public)[*psz - 1] == ' ')
-		--*psz;
-	if (dst != NULL) {
-		(*public)[*psz] = '\0';
-		return 1;
-	} else
-		return 0;
-}
-
-static void
-dbadd_mlink(const struct mlink *mlink)
-{
-	dba_page_alias(mlink->mpage->dba, mlink->name, NAME_FILE);
-	dba_page_add(mlink->mpage->dba, DBP_SECT, mlink->dsec);
-	dba_page_add(mlink->mpage->dba, DBP_SECT, mlink->fsec);
-	dba_page_add(mlink->mpage->dba, DBP_ARCH, mlink->arch);
-	dba_page_add(mlink->mpage->dba, DBP_FILE, mlink->file);
-}
-
-/*
- * Flush the current page's terms (and their bits) into the database.
- * Also, handle escape sequences at the last possible moment.
- */
-static void
-dbadd(struct dba *dba, struct mpage *mpage)
-{
-	struct mlink	*mlink;
-	struct str	*key;
-	char		*cp;
-	uint64_t	 mask;
-	size_t		 i;
-	unsigned int	 slot;
-	int		 mustfree;
-
-	mlink = mpage->mlinks;
-
-	if (nodb) {
-		for (key = ohash_first(&names, &slot); NULL != key;
-		     key = ohash_next(&names, &slot))
-			free(key);
-		for (key = ohash_first(&strings, &slot); NULL != key;
-		     key = ohash_next(&strings, &slot))
-			free(key);
-		if (0 == debug)
-			return;
-		while (NULL != mlink) {
-			fputs(mlink->name, stdout);
-			if (NULL == mlink->next ||
-			    strcmp(mlink->dsec, mlink->next->dsec) ||
-			    strcmp(mlink->fsec, mlink->next->fsec) ||
-			    strcmp(mlink->arch, mlink->next->arch)) {
-				putchar('(');
-				if ('\0' == *mlink->dsec)
-					fputs(mlink->fsec, stdout);
-				else
-					fputs(mlink->dsec, stdout);
-				if ('\0' != *mlink->arch)
-					printf("/%s", mlink->arch);
-				putchar(')');
-			}
-			mlink = mlink->next;
-			if (NULL != mlink)
-				fputs(", ", stdout);
-		}
-		printf(" - %s\n", mpage->desc);
-		return;
-	}
-
-	if (debug)
-		say(mlink->file, "Adding to database");
-
-	cp = mpage->desc;
-	i = strlen(cp);
-	mustfree = render_string(&cp, &i);
-	mpage->dba = dba_page_new(dba->pages,
-	    *mpage->arch == '\0' ? mlink->arch : mpage->arch,
-	    cp, mlink->file, mpage->form);
-	if (mustfree)
-		free(cp);
-	dba_page_add(mpage->dba, DBP_SECT, mpage->sec);
-
-	while (mlink != NULL) {
-		dbadd_mlink(mlink);
-		mlink = mlink->next;
-	}
-
-	for (key = ohash_first(&names, &slot); NULL != key;
-	     key = ohash_next(&names, &slot)) {
-		assert(key->mpage == mpage);
-		dba_page_alias(mpage->dba, key->key, key->mask);
-		free(key);
-	}
-	for (key = ohash_first(&strings, &slot); NULL != key;
-	     key = ohash_next(&strings, &slot)) {
-		assert(key->mpage == mpage);
-		i = 0;
-		for (mask = TYPE_Xr; mask <= TYPE_Lb; mask *= 2) {
-			if (key->mask & mask)
-				dba_macro_add(dba->macros, i,
-				    key->key, mpage->dba);
-			i++;
-		}
-		free(key);
-	}
-}
-
-static void
-dbprune(struct dba *dba)
-{
-	struct dba_array	*page, *files;
-	char			*file;
-
-	dba_array_FOREACH(dba->pages, page) {
-		files = dba_array_get(page, DBP_FILE);
-		dba_array_FOREACH(files, file) {
-			if (*file < ' ')
-				file++;
-			if (ohash_find(&mlinks, ohash_qlookup(&mlinks,
-			    file)) != NULL) {
-				if (debug)
-					say(file, "Deleting from database");
-				dba_array_del(dba->pages);
-				break;
-			}
-		}
-	}
-}
-
-/*
- * Write the database from memory to disk.
- */
-static void
-dbwrite(struct dba *dba)
-{
-	char		 tfn[32];
-	int		 status;
-	pid_t		 child;
-
-	/*
-	 * Do not write empty databases, and delete existing ones
-	 * when makewhatis -u causes them to become empty.
-	 */
-
-	dba_array_start(dba->pages);
-	if (dba_array_next(dba->pages) == NULL) {
-		if (unlink(MANDOC_DB) == -1 && errno != ENOENT)
-			say(MANDOC_DB, "&unlink");
-		return;
-	}
-
-	/*
-	 * Build the database in a temporary file,
-	 * then atomically move it into place.
-	 */
-
-	if (dba_write(MANDOC_DB "~", dba) != -1) {
-		if (rename(MANDOC_DB "~", MANDOC_DB) == -1) {
-			exitcode = (int)MANDOCLEVEL_SYSERR;
-			say(MANDOC_DB, "&rename");
-			unlink(MANDOC_DB "~");
-		}
-		return;
-	}
-
-	/*
-	 * We lack write permission and cannot replace the database
-	 * file, but let's at least check whether the data changed.
-	 */
-
-	(void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn));
-	if (mkdtemp(tfn) == NULL) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "&%s", tfn);
-		return;
-	}
-
-	(void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn));
-	if (dba_write(tfn, dba) == -1) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say(tfn, "&dba_write");
-		goto out;
-	}
-
-	switch (child = fork()) {
-	case -1:
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "&fork cmp");
-		return;
-	case 0:
-		execlp("cmp", "cmp", "-s", tfn, MANDOC_DB, (char *)NULL);
-		say("", "&exec cmp");
-		exit(0);
-	default:
-		break;
-	}
-	if (waitpid(child, &status, 0) == -1) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "&wait cmp");
-	} else if (WIFSIGNALED(status)) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "cmp died from signal %d", WTERMSIG(status));
-	} else if (WEXITSTATUS(status)) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say(MANDOC_DB,
-		    "Data changed, but cannot replace database");
-	}
-
-out:
-	*strrchr(tfn, '/') = '\0';
-	switch (child = fork()) {
-	case -1:
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "&fork rm");
-		return;
-	case 0:
-		execlp("rm", "rm", "-rf", tfn, (char *)NULL);
-		say("", "&exec rm");
-		exit((int)MANDOCLEVEL_SYSERR);
-	default:
-		break;
-	}
-	if (waitpid(child, &status, 0) == -1) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "&wait rm");
-	} else if (WIFSIGNALED(status) || WEXITSTATUS(status)) {
-		exitcode = (int)MANDOCLEVEL_SYSERR;
-		say("", "%s: Cannot remove temporary directory", tfn);
-	}
-}
-
-static int
-set_basedir(const char *targetdir, int report_baddir)
-{
-	static char	 startdir[PATH_MAX];
-	static int	 getcwd_status;  /* 1 = ok, 2 = failure */
-	static int	 chdir_status;  /* 1 = changed directory */
-	char		*cp;
-
-	/*
-	 * Remember the original working directory, if possible.
-	 * This will be needed if the second or a later directory
-	 * on the command line is given as a relative path.
-	 * Do not error out if the current directory is not
-	 * searchable: Maybe it won't be needed after all.
-	 */
-	if (0 == getcwd_status) {
-		if (NULL == getcwd(startdir, sizeof(startdir))) {
-			getcwd_status = 2;
-			(void)strlcpy(startdir, strerror(errno),
-			    sizeof(startdir));
-		} else
-			getcwd_status = 1;
-	}
-
-	/*
-	 * We are leaving the old base directory.
-	 * Do not use it any longer, not even for messages.
-	 */
-	*basedir = '\0';
-
-	/*
-	 * If and only if the directory was changed earlier and
-	 * the next directory to process is given as a relative path,
-	 * first go back, or bail out if that is impossible.
-	 */
-	if (chdir_status && '/' != *targetdir) {
-		if (2 == getcwd_status) {
-			exitcode = (int)MANDOCLEVEL_SYSERR;
-			say("", "getcwd: %s", startdir);
-			return 0;
-		}
-		if (-1 == chdir(startdir)) {
-			exitcode = (int)MANDOCLEVEL_SYSERR;
-			say("", "&chdir %s", startdir);
-			return 0;
-		}
-	}
-
-	/*
-	 * Always resolve basedir to the canonicalized absolute
-	 * pathname and append a trailing slash, such that
-	 * we can reliably check whether files are inside.
-	 */
-	if (NULL == realpath(targetdir, basedir)) {
-		if (report_baddir || errno != ENOENT) {
-			exitcode = (int)MANDOCLEVEL_BADARG;
-			say("", "&%s: realpath", targetdir);
-		}
-		return 0;
-	} else if (-1 == chdir(basedir)) {
-		if (report_baddir || errno != ENOENT) {
-			exitcode = (int)MANDOCLEVEL_BADARG;
-			say("", "&chdir");
-		}
-		return 0;
-	}
-	chdir_status = 1;
-	cp = strchr(basedir, '\0');
-	if ('/' != cp[-1]) {
-		if (cp - basedir >= PATH_MAX - 1) {
-			exitcode = (int)MANDOCLEVEL_SYSERR;
-			say("", "Filename too long");
-			return 0;
-		}
-		*cp++ = '/';
-		*cp = '\0';
-	}
-	return 1;
-}
-
-static void
-say(const char *file, const char *format, ...)
-{
-	va_list		 ap;
-	int		 use_errno;
-
-	if ('\0' != *basedir)
-		fprintf(stderr, "%s", basedir);
-	if ('\0' != *basedir && '\0' != *file)
-		fputc('/', stderr);
-	if ('\0' != *file)
-		fprintf(stderr, "%s", file);
-
-	use_errno = 1;
-	if (NULL != format) {
-		switch (*format) {
-		case '&':
-			format++;
-			break;
-		case '\0':
-			format = NULL;
-			break;
-		default:
-			use_errno = 0;
-			break;
-		}
-	}
-	if (NULL != format) {
-		if ('\0' != *basedir || '\0' != *file)
-			fputs(": ", stderr);
-		va_start(ap, format);
-		vfprintf(stderr, format, ap);
-		va_end(ap);
-	}
-	if (use_errno) {
-		if ('\0' != *basedir || '\0' != *file || NULL != format)
-			fputs(": ", stderr);
-		perror(NULL);
-	} else
-		fputc('\n', stderr);
-}

Property changes on: head/contrib/mdocml/mandocdb.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/compat_strsep.c
===================================================================
--- head/contrib/mdocml/compat_strsep.c	(revision 338825)
+++ head/contrib/mdocml/compat_strsep.c	(nonexistent)
@@ -1,79 +0,0 @@
-#include "config.h"
-
-#if HAVE_STRSEP
-
-int dummy;
-
-#else
-
-/*	$Id: compat_strsep.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $	*/
-/*	$OpenBSD: strsep.c,v 1.7 2014/02/05 20:42:32 stsp Exp $	*/
-
-/*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Get next token from string *stringp, where tokens are possibly-empty
- * strings separated by characters from delim.  
- *
- * Writes NULs into the string at *stringp to end tokens.
- * delim need not remain constant from call to call.
- * On return, *stringp points past the last NUL written (if there might
- * be further tokens), or is NULL (if there are definitely no more tokens).
- *
- * If *stringp is NULL, strsep returns NULL.
- */
-char *
-strsep(char **stringp, const char *delim)
-{
-	char *s;
-	const char *spanp;
-	int c, sc;
-	char *tok;
-
-	if ((s = *stringp) == NULL)
-		return (NULL);
-	for (tok = s;;) {
-		c = *s++;
-		spanp = delim;
-		do {
-			if ((sc = *spanp++) == c) {
-				if (c == 0)
-					s = NULL;
-				else
-					s[-1] = 0;
-				*stringp = s;
-				return (tok);
-			}
-		} while (sc != 0);
-	}
-	/* NOTREACHED */
-}
-
-#endif

Property changes on: head/contrib/mdocml/compat_strsep.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/compat_isblank.c
===================================================================
--- head/contrib/mdocml/compat_isblank.c	(revision 338825)
+++ head/contrib/mdocml/compat_isblank.c	(nonexistent)
@@ -1,33 +0,0 @@
-#include "config.h"
-
-#if HAVE_ISBLANK
-
-int dummy;
-
-#else
-
-/*	$Id: compat_isblank.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $	*/
-/*
- * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-int
-isblank(int c)
-{
-
-	return c == ' ' || c == '\t';
-}
-
-#endif

Property changes on: head/contrib/mdocml/compat_isblank.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/mdoc_html.c
===================================================================
--- head/contrib/mdocml/mdoc_html.c	(revision 338825)
+++ head/contrib/mdocml/mdoc_html.c	(nonexistent)
@@ -1,1842 +0,0 @@
-/*	$Id: mdoc_html.c,v 1.294 2017/07/15 17:57:51 schwarze Exp $ */
-/*
- * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include "config.h"
-
-#include <sys/types.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "mandoc_aux.h"
-#include "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "out.h"
-#include "html.h"
-#include "main.h"
-
-#define	INDENT		 5
-
-#define	MDOC_ARGS	  const struct roff_meta *meta, \
-			  struct roff_node *n, \
-			  struct html *h
-
-#ifndef MIN
-#define	MIN(a,b)	((/*CONSTCOND*/(a)<(b))?(a):(b))
-#endif
-
-struct	htmlmdoc {
-	int		(*pre)(MDOC_ARGS);
-	void		(*post)(MDOC_ARGS);
-};
-
-static	char		 *cond_id(const struct roff_node *);
-static	void		  print_mdoc_head(MDOC_ARGS);
-static	void		  print_mdoc_node(MDOC_ARGS);
-static	void		  print_mdoc_nodelist(MDOC_ARGS);
-static	void		  synopsis_pre(struct html *,
-				const struct roff_node *);
-
-static	void		  mdoc_root_post(MDOC_ARGS);
-static	int		  mdoc_root_pre(MDOC_ARGS);
-
-static	void		  mdoc__x_post(MDOC_ARGS);
-static	int		  mdoc__x_pre(MDOC_ARGS);
-static	int		  mdoc_ad_pre(MDOC_ARGS);
-static	int		  mdoc_an_pre(MDOC_ARGS);
-static	int		  mdoc_ap_pre(MDOC_ARGS);
-static	int		  mdoc_ar_pre(MDOC_ARGS);
-static	int		  mdoc_bd_pre(MDOC_ARGS);
-static	int		  mdoc_bf_pre(MDOC_ARGS);
-static	void		  mdoc_bk_post(MDOC_ARGS);
-static	int		  mdoc_bk_pre(MDOC_ARGS);
-static	int		  mdoc_bl_pre(MDOC_ARGS);
-static	int		  mdoc_cd_pre(MDOC_ARGS);
-static	int		  mdoc_cm_pre(MDOC_ARGS);
-static	int		  mdoc_d1_pre(MDOC_ARGS);
-static	int		  mdoc_dv_pre(MDOC_ARGS);
-static	int		  mdoc_fa_pre(MDOC_ARGS);
-static	int		  mdoc_fd_pre(MDOC_ARGS);
-static	int		  mdoc_fl_pre(MDOC_ARGS);
-static	int		  mdoc_fn_pre(MDOC_ARGS);
-static	int		  mdoc_ft_pre(MDOC_ARGS);
-static	int		  mdoc_em_pre(MDOC_ARGS);
-static	void		  mdoc_eo_post(MDOC_ARGS);
-static	int		  mdoc_eo_pre(MDOC_ARGS);
-static	int		  mdoc_er_pre(MDOC_ARGS);
-static	int		  mdoc_ev_pre(MDOC_ARGS);
-static	int		  mdoc_ex_pre(MDOC_ARGS);
-static	void		  mdoc_fo_post(MDOC_ARGS);
-static	int		  mdoc_fo_pre(MDOC_ARGS);
-static	int		  mdoc_ic_pre(MDOC_ARGS);
-static	int		  mdoc_igndelim_pre(MDOC_ARGS);
-static	int		  mdoc_in_pre(MDOC_ARGS);
-static	int		  mdoc_it_pre(MDOC_ARGS);
-static	int		  mdoc_lb_pre(MDOC_ARGS);
-static	int		  mdoc_li_pre(MDOC_ARGS);
-static	int		  mdoc_lk_pre(MDOC_ARGS);
-static	int		  mdoc_mt_pre(MDOC_ARGS);
-static	int		  mdoc_ms_pre(MDOC_ARGS);
-static	int		  mdoc_nd_pre(MDOC_ARGS);
-static	int		  mdoc_nm_pre(MDOC_ARGS);
-static	int		  mdoc_no_pre(MDOC_ARGS);
-static	int		  mdoc_ns_pre(MDOC_ARGS);
-static	int		  mdoc_pa_pre(MDOC_ARGS);
-static	void		  mdoc_pf_post(MDOC_ARGS);
-static	int		  mdoc_pp_pre(MDOC_ARGS);
-static	void		  mdoc_quote_post(MDOC_ARGS);
-static	int		  mdoc_quote_pre(MDOC_ARGS);
-static	int		  mdoc_rs_pre(MDOC_ARGS);
-static	int		  mdoc_sh_pre(MDOC_ARGS);
-static	int		  mdoc_skip_pre(MDOC_ARGS);
-static	int		  mdoc_sm_pre(MDOC_ARGS);
-static	int		  mdoc_ss_pre(MDOC_ARGS);
-static	int		  mdoc_st_pre(MDOC_ARGS);
-static	int		  mdoc_sx_pre(MDOC_ARGS);
-static	int		  mdoc_sy_pre(MDOC_ARGS);
-static	int		  mdoc_va_pre(MDOC_ARGS);
-static	int		  mdoc_vt_pre(MDOC_ARGS);
-static	int		  mdoc_xr_pre(MDOC_ARGS);
-static	int		  mdoc_xx_pre(MDOC_ARGS);
-
-static	const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
-	{NULL, NULL}, /* Dd */
-	{NULL, NULL}, /* Dt */
-	{NULL, NULL}, /* Os */
-	{mdoc_sh_pre, NULL }, /* Sh */
-	{mdoc_ss_pre, NULL }, /* Ss */
-	{mdoc_pp_pre, NULL}, /* Pp */
-	{mdoc_d1_pre, NULL}, /* D1 */
-	{mdoc_d1_pre, NULL}, /* Dl */
-	{mdoc_bd_pre, NULL}, /* Bd */
-	{NULL, NULL}, /* Ed */
-	{mdoc_bl_pre, NULL}, /* Bl */
-	{NULL, NULL}, /* El */
-	{mdoc_it_pre, NULL}, /* It */
-	{mdoc_ad_pre, NULL}, /* Ad */
-	{mdoc_an_pre, NULL}, /* An */
-	{mdoc_ap_pre, NULL}, /* Ap */
-	{mdoc_ar_pre, NULL}, /* Ar */
-	{mdoc_cd_pre, NULL}, /* Cd */
-	{mdoc_cm_pre, NULL}, /* Cm */
-	{mdoc_dv_pre, NULL}, /* Dv */
-	{mdoc_er_pre, NULL}, /* Er */
-	{mdoc_ev_pre, NULL}, /* Ev */
-	{mdoc_ex_pre, NULL}, /* Ex */
-	{mdoc_fa_pre, NULL}, /* Fa */
-	{mdoc_fd_pre, NULL}, /* Fd */
-	{mdoc_fl_pre, NULL}, /* Fl */
-	{mdoc_fn_pre, NULL}, /* Fn */
-	{mdoc_ft_pre, NULL}, /* Ft */
-	{mdoc_ic_pre, NULL}, /* Ic */
-	{mdoc_in_pre, NULL}, /* In */
-	{mdoc_li_pre, NULL}, /* Li */
-	{mdoc_nd_pre, NULL}, /* Nd */
-	{mdoc_nm_pre, NULL}, /* Nm */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Op */
-	{mdoc_ft_pre, NULL}, /* Ot */
-	{mdoc_pa_pre, NULL}, /* Pa */
-	{mdoc_ex_pre, NULL}, /* Rv */
-	{mdoc_st_pre, NULL}, /* St */
-	{mdoc_va_pre, NULL}, /* Va */
-	{mdoc_vt_pre, NULL}, /* Vt */
-	{mdoc_xr_pre, NULL}, /* Xr */
-	{mdoc__x_pre, mdoc__x_post}, /* %A */
-	{mdoc__x_pre, mdoc__x_post}, /* %B */
-	{mdoc__x_pre, mdoc__x_post}, /* %D */
-	{mdoc__x_pre, mdoc__x_post}, /* %I */
-	{mdoc__x_pre, mdoc__x_post}, /* %J */
-	{mdoc__x_pre, mdoc__x_post}, /* %N */
-	{mdoc__x_pre, mdoc__x_post}, /* %O */
-	{mdoc__x_pre, mdoc__x_post}, /* %P */
-	{mdoc__x_pre, mdoc__x_post}, /* %R */
-	{mdoc__x_pre, mdoc__x_post}, /* %T */
-	{mdoc__x_pre, mdoc__x_post}, /* %V */
-	{NULL, NULL}, /* Ac */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Ao */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Aq */
-	{mdoc_xx_pre, NULL}, /* At */
-	{NULL, NULL}, /* Bc */
-	{mdoc_bf_pre, NULL}, /* Bf */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Bo */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
-	{mdoc_xx_pre, NULL}, /* Bsx */
-	{mdoc_xx_pre, NULL}, /* Bx */
-	{mdoc_skip_pre, NULL}, /* Db */
-	{NULL, NULL}, /* Dc */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Do */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
-	{NULL, NULL}, /* Ec */ /* FIXME: no space */
-	{NULL, NULL}, /* Ef */
-	{mdoc_em_pre, NULL}, /* Em */
-	{mdoc_eo_pre, mdoc_eo_post}, /* Eo */
-	{mdoc_xx_pre, NULL}, /* Fx */
-	{mdoc_ms_pre, NULL}, /* Ms */
-	{mdoc_no_pre, NULL}, /* No */
-	{mdoc_ns_pre, NULL}, /* Ns */
-	{mdoc_xx_pre, NULL}, /* Nx */
-	{mdoc_xx_pre, NULL}, /* Ox */
-	{NULL, NULL}, /* Pc */
-	{mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Po */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Pq */
-	{NULL, NULL}, /* Qc */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Ql */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Qo */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Qq */
-	{NULL, NULL}, /* Re */
-	{mdoc_rs_pre, NULL}, /* Rs */
-	{NULL, NULL}, /* Sc */
-	{mdoc_quote_pre, mdoc_quote_post}, /* So */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Sq */
-	{mdoc_sm_pre, NULL}, /* Sm */
-	{mdoc_sx_pre, NULL}, /* Sx */
-	{mdoc_sy_pre, NULL}, /* Sy */
-	{NULL, NULL}, /* Tn */
-	{mdoc_xx_pre, NULL}, /* Ux */
-	{NULL, NULL}, /* Xc */
-	{NULL, NULL}, /* Xo */
-	{mdoc_fo_pre, mdoc_fo_post}, /* Fo */
-	{NULL, NULL}, /* Fc */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Oo */
-	{NULL, NULL}, /* Oc */
-	{mdoc_bk_pre, mdoc_bk_post}, /* Bk */
-	{NULL, NULL}, /* Ek */
-	{NULL, NULL}, /* Bt */
-	{NULL, NULL}, /* Hf */
-	{mdoc_em_pre, NULL}, /* Fr */
-	{NULL, NULL}, /* Ud */
-	{mdoc_lb_pre, NULL}, /* Lb */
-	{mdoc_pp_pre, NULL}, /* Lp */
-	{mdoc_lk_pre, NULL}, /* Lk */
-	{mdoc_mt_pre, NULL}, /* Mt */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
-	{mdoc_quote_pre, mdoc_quote_post}, /* Bro */
-	{NULL, NULL}, /* Brc */
-	{mdoc__x_pre, mdoc__x_post}, /* %C */
-	{mdoc_skip_pre, NULL}, /* Es */
-	{mdoc_quote_pre, mdoc_quote_post}, /* En */
-	{mdoc_xx_pre, NULL}, /* Dx */
-	{mdoc__x_pre, mdoc__x_post}, /* %Q */
-	{mdoc__x_pre, mdoc__x_post}, /* %U */
-	{NULL, NULL}, /* Ta */
-};
-static	const struct htmlmdoc *const mdocs = __mdocs - MDOC_Dd;
-
-
-/*
- * See the same function in mdoc_term.c for documentation.
- */
-static void
-synopsis_pre(struct html *h, const struct roff_node *n)
-{
-
-	if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
-		return;
-
-	if (n->prev->tok == n->tok &&
-	    MDOC_Fo != n->tok &&
-	    MDOC_Ft != n->tok &&
-	    MDOC_Fn != n->tok) {
-		print_otag(h, TAG_BR, "");
-		return;
-	}
-
-	switch (n->prev->tok) {
-	case MDOC_Fd:
-	case MDOC_Fn:
-	case MDOC_Fo:
-	case MDOC_In:
-	case MDOC_Vt:
-		print_paragraph(h);
-		break;
-	case MDOC_Ft:
-		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
-			print_paragraph(h);
-			break;
-		}
-		/* FALLTHROUGH */
-	default:
-		print_otag(h, TAG_BR, "");
-		break;
-	}
-}
-
-void
-html_mdoc(void *arg, const struct roff_man *mdoc)
-{
-	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_mdoc_head(&mdoc->meta, mdoc->first->child, h);
-		print_tagq(h, t);
-		print_otag(h, TAG_BODY, "");
-	}
-
-	mdoc_root_pre(&mdoc->meta, mdoc->first->child, h);
-	t = print_otag(h, TAG_DIV, "c", "manual-text");
-	print_mdoc_nodelist(&mdoc->meta, mdoc->first->child, h);
-	print_tagq(h, t);
-	mdoc_root_post(&mdoc->meta, mdoc->first->child, h);
-	print_tagq(h, NULL);
-}
-
-static void
-print_mdoc_head(MDOC_ARGS)
-{
-	char	*cp;
-
-	print_gen_head(h);
-
-	if (meta->arch != NULL && meta->msec != NULL)
-		mandoc_asprintf(&cp, "%s(%s) (%s)", meta->title,
-		    meta->msec, meta->arch);
-	else if (meta->msec != NULL)
-		mandoc_asprintf(&cp, "%s(%s)", meta->title, meta->msec);
-	else if (meta->arch != NULL)
-		mandoc_asprintf(&cp, "%s (%s)", meta->title, meta->arch);
-	else
-		cp = mandoc_strdup(meta->title);
-
-	print_otag(h, TAG_TITLE, "");
-	print_text(h, cp);
-	free(cp);
-}
-
-static void
-print_mdoc_nodelist(MDOC_ARGS)
-{
-
-	while (n != NULL) {
-		print_mdoc_node(meta, n, h);
-		n = n->next;
-	}
-}
-
-static void
-print_mdoc_node(MDOC_ARGS)
-{
-	int		 child;
-	struct tag	*t;
-
-	if (n->flags & NODE_NOPRT)
-		return;
-
-	child = 1;
-	t = h->tag;
-	n->flags &= ~NODE_ENDED;
-
-	switch (n->type) {
-	case ROFFT_TEXT:
-		/* No tables in this mode... */
-		assert(NULL == h->tblt);
-
-		/*
-		 * Make sure that if we're in a literal mode already
-		 * (i.e., within a <PRE>) don't print the newline.
-		 */
-		if (*n->string == ' ' && n->flags & NODE_LINE &&
-		    (h->flags & (HTML_LITERAL | HTML_NONEWLINE)) == 0)
-			print_otag(h, TAG_BR, "");
-		if (NODE_DELIMC & n->flags)
-			h->flags |= HTML_NOSPACE;
-		print_text(h, n->string);
-		if (NODE_DELIMO & n->flags)
-			h->flags |= HTML_NOSPACE;
-		return;
-	case ROFFT_EQN:
-		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 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 != NULL) {
-			print_tblclose(h);
-			t = h->tag;
-		}
-		assert(h->tblt == NULL);
-		if (n->tok < ROFF_MAX) {
-			roff_html_pre(h, n);
-			child = 0;
-			break;
-		}
-		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
-		if (mdocs[n->tok].pre != NULL &&
-		    (n->end == ENDBODY_NOT || n->child != NULL))
-			child = (*mdocs[n->tok].pre)(meta, n, h);
-		break;
-	}
-
-	if (h->flags & HTML_KEEP && n->flags & NODE_LINE) {
-		h->flags &= ~HTML_KEEP;
-		h->flags |= HTML_PREKEEP;
-	}
-
-	if (child && n->child)
-		print_mdoc_nodelist(meta, n->child, h);
-
-	print_stagq(h, t);
-
-	switch (n->type) {
-	case ROFFT_EQN:
-		break;
-	default:
-		if (n->tok < ROFF_MAX ||
-		    mdocs[n->tok].post == NULL ||
-		    n->flags & NODE_ENDED)
-			break;
-		(*mdocs[n->tok].post)(meta, n, h);
-		if (n->end != ENDBODY_NOT)
-			n->body->flags |= NODE_ENDED;
-		break;
-	}
-}
-
-static void
-mdoc_root_post(MDOC_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, meta->date);
-	print_stagq(h, tt);
-
-	print_otag(h, TAG_TD, "c", "foot-os");
-	print_text(h, meta->os);
-	print_tagq(h, t);
-}
-
-static int
-mdoc_root_pre(MDOC_ARGS)
-{
-	struct tag	*t, *tt;
-	char		*volume, *title;
-
-	if (NULL == meta->arch)
-		volume = mandoc_strdup(meta->vol);
-	else
-		mandoc_asprintf(&volume, "%s (%s)",
-		    meta->vol, meta->arch);
-
-	if (NULL == meta->msec)
-		title = mandoc_strdup(meta->title);
-	else
-		mandoc_asprintf(&title, "%s(%s)",
-		    meta->title, meta->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");
-	print_text(h, volume);
-	print_stagq(h, tt);
-
-	print_otag(h, TAG_TD, "c", "head-rtitle");
-	print_text(h, title);
-	print_tagq(h, t);
-
-	free(title);
-	free(volume);
-	return 1;
-}
-
-static char *
-cond_id(const struct roff_node *n)
-{
-	if (n->child != NULL &&
-	    n->child->type == ROFFT_TEXT &&
-	    (n->prev == NULL ||
-	     (n->prev->type == ROFFT_TEXT &&
-	      strcmp(n->prev->string, "|") == 0)) &&
-	    (n->parent->tok == MDOC_It ||
-	     (n->parent->tok == MDOC_Xo &&
-	      n->parent->parent->prev == NULL &&
-	      n->parent->parent->parent->tok == MDOC_It)))
-		return html_make_id(n);
-	return NULL;
-}
-
-static int
-mdoc_sh_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	switch (n->type) {
-	case 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);
-		break;
-	case ROFFT_BODY:
-		if (n->sec == SEC_AUTHORS)
-			h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
-		break;
-	default:
-		break;
-	}
-	return 1;
-}
-
-static int
-mdoc_ss_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	if (n->type != ROFFT_HEAD)
-		return 1;
-
-	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
-mdoc_fl_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_B, "cTi", "Fl", id);
-	free(id);
-
-	print_text(h, "\\-");
-	if (!(n->child == NULL &&
-	    (n->next == NULL ||
-	     n->next->type == ROFFT_TEXT ||
-	     n->next->flags & NODE_LINE)))
-		h->flags |= HTML_NOSPACE;
-
-	return 1;
-}
-
-static int
-mdoc_cm_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_B, "cTi", "Cm", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_nd_pre(MDOC_ARGS)
-{
-	if (n->type != ROFFT_BODY)
-		return 1;
-
-	/* XXX: this tag in theory can contain block elements. */
-
-	print_text(h, "\\(em");
-	print_otag(h, TAG_SPAN, "cT", "Nd");
-	return 1;
-}
-
-static int
-mdoc_nm_pre(MDOC_ARGS)
-{
-	switch (n->type) {
-	case ROFFT_HEAD:
-		print_otag(h, TAG_TD, "");
-		/* FALLTHROUGH */
-	case ROFFT_ELEM:
-		print_otag(h, TAG_B, "cT", "Nm");
-		return 1;
-	case ROFFT_BODY:
-		print_otag(h, TAG_TD, "");
-		return 1;
-	default:
-		break;
-	}
-	synopsis_pre(h, n);
-	print_otag(h, TAG_TABLE, "c", "Nm");
-	print_otag(h, TAG_TR, "");
-	return 1;
-}
-
-static int
-mdoc_xr_pre(MDOC_ARGS)
-{
-	if (NULL == n->child)
-		return 0;
-
-	if (h->base_man)
-		print_otag(h, TAG_A, "cThM", "Xr",
-		    n->child->string, n->child->next == NULL ?
-		    NULL : n->child->next->string);
-	else
-		print_otag(h, TAG_A, "cT", "Xr");
-
-	n = n->child;
-	print_text(h, n->string);
-
-	if (NULL == (n = n->next))
-		return 0;
-
-	h->flags |= HTML_NOSPACE;
-	print_text(h, "(");
-	h->flags |= HTML_NOSPACE;
-	print_text(h, n->string);
-	h->flags |= HTML_NOSPACE;
-	print_text(h, ")");
-	return 0;
-}
-
-static int
-mdoc_ns_pre(MDOC_ARGS)
-{
-
-	if ( ! (NODE_LINE & n->flags))
-		h->flags |= HTML_NOSPACE;
-	return 1;
-}
-
-static int
-mdoc_ar_pre(MDOC_ARGS)
-{
-	print_otag(h, TAG_VAR, "cT", "Ar");
-	return 1;
-}
-
-static int
-mdoc_xx_pre(MDOC_ARGS)
-{
-	print_otag(h, TAG_SPAN, "c", "Ux");
-	return 1;
-}
-
-static int
-mdoc_it_pre(MDOC_ARGS)
-{
-	const struct roff_node	*bl;
-	struct tag		*t;
-	const char		*cattr;
-	enum mdoc_list		 type;
-
-	bl = n->parent;
-	while (bl->tok != MDOC_Bl)
-		bl = bl->parent;
-	type = bl->norm->Bl.type;
-
-	switch (type) {
-	case LIST_bullet:
-		cattr = "It-bullet";
-		break;
-	case LIST_dash:
-	case LIST_hyphen:
-		cattr = "It-dash";
-		break;
-	case LIST_item:
-		cattr = "It-item";
-		break;
-	case LIST_enum:
-		cattr = "It-enum";
-		break;
-	case LIST_diag:
-		cattr = "It-diag";
-		break;
-	case LIST_hang:
-		cattr = "It-hang";
-		break;
-	case LIST_inset:
-		cattr = "It-inset";
-		break;
-	case LIST_ohang:
-		cattr = "It-ohang";
-		break;
-	case LIST_tag:
-		cattr = "It-tag";
-		break;
-	case LIST_column:
-		cattr = "It-column";
-		break;
-	default:
-		break;
-	}
-
-	switch (type) {
-	case LIST_bullet:
-	case LIST_dash:
-	case LIST_hyphen:
-	case LIST_item:
-	case LIST_enum:
-		switch (n->type) {
-		case ROFFT_HEAD:
-			return 0;
-		case ROFFT_BODY:
-			print_otag(h, TAG_LI, "c", cattr);
-			break;
-		default:
-			break;
-		}
-		break;
-	case LIST_diag:
-	case LIST_hang:
-	case LIST_inset:
-	case LIST_ohang:
-		switch (n->type) {
-		case ROFFT_HEAD:
-			print_otag(h, TAG_DT, "c", cattr);
-			if (type == LIST_diag)
-				print_otag(h, TAG_B, "c", cattr);
-			break;
-		case ROFFT_BODY:
-			print_otag(h, TAG_DD, "csw*+l", cattr,
-			    bl->norm->Bl.width);
-			break;
-		default:
-			break;
-		}
-		break;
-	case LIST_tag:
-		switch (n->type) {
-		case ROFFT_HEAD:
-			if (h->style != NULL && !bl->norm->Bl.comp &&
-			    (n->parent->prev == NULL ||
-			     n->parent->prev->body == NULL ||
-			     n->parent->prev->body->child != NULL)) {
-				t = print_otag(h, TAG_DT, "csw*+-l",
-				    cattr, bl->norm->Bl.width);
-				print_text(h, "\\ ");
-				print_tagq(h, t);
-				t = print_otag(h, TAG_DD, "c", cattr);
-				print_text(h, "\\ ");
-				print_tagq(h, t);
-			}
-			print_otag(h, TAG_DT, "csw*+-l", cattr,
-			    bl->norm->Bl.width);
-			break;
-		case ROFFT_BODY:
-			if (n->child == NULL) {
-				print_otag(h, TAG_DD, "css?", cattr,
-				    "width", "auto");
-				print_text(h, "\\ ");
-			} else
-				print_otag(h, TAG_DD, "c", cattr);
-			break;
-		default:
-			break;
-		}
-		break;
-	case LIST_column:
-		switch (n->type) {
-		case ROFFT_HEAD:
-			break;
-		case ROFFT_BODY:
-			print_otag(h, TAG_TD, "c", cattr);
-			break;
-		default:
-			print_otag(h, TAG_TR, "c", cattr);
-		}
-	default:
-		break;
-	}
-
-	return 1;
-}
-
-static int
-mdoc_bl_pre(MDOC_ARGS)
-{
-	char		 cattr[21];
-	struct tag	*t;
-	struct mdoc_bl	*bl;
-	size_t		 i;
-	enum htmltag	 elemtype;
-
-	bl = &n->norm->Bl;
-
-	switch (n->type) {
-	case ROFFT_BODY:
-		return 1;
-
-	case ROFFT_HEAD:
-		if (bl->type != LIST_column || bl->ncols == 0)
-			return 0;
-
-		/*
-		 * For each column, print out the <COL> tag with our
-		 * suggested width.  The last column gets min-width, as
-		 * in terminal mode it auto-sizes to the width of the
-		 * screen and we want to preserve that behaviour.
-		 */
-
-		t = print_otag(h, TAG_COLGROUP, "");
-		for (i = 0; i < bl->ncols - 1; i++)
-			print_otag(h, TAG_COL, "sw+w", bl->cols[i]);
-		print_otag(h, TAG_COL, "swW", bl->cols[i]);
-		print_tagq(h, t);
-		return 0;
-
-	default:
-		break;
-	}
-
-	switch (bl->type) {
-	case LIST_bullet:
-		elemtype = TAG_UL;
-		(void)strlcpy(cattr, "Bl-bullet", sizeof(cattr));
-		break;
-	case LIST_dash:
-	case LIST_hyphen:
-		elemtype = TAG_UL;
-		(void)strlcpy(cattr, "Bl-dash", sizeof(cattr));
-		break;
-	case LIST_item:
-		elemtype = TAG_UL;
-		(void)strlcpy(cattr, "Bl-item", sizeof(cattr));
-		break;
-	case LIST_enum:
-		elemtype = TAG_OL;
-		(void)strlcpy(cattr, "Bl-enum", sizeof(cattr));
-		break;
-	case LIST_diag:
-		elemtype = TAG_DL;
-		(void)strlcpy(cattr, "Bl-diag", sizeof(cattr));
-		break;
-	case LIST_hang:
-		elemtype = TAG_DL;
-		(void)strlcpy(cattr, "Bl-hang", sizeof(cattr));
-		break;
-	case LIST_inset:
-		elemtype = TAG_DL;
-		(void)strlcpy(cattr, "Bl-inset", sizeof(cattr));
-		break;
-	case LIST_ohang:
-		elemtype = TAG_DL;
-		(void)strlcpy(cattr, "Bl-ohang", sizeof(cattr));
-		break;
-	case LIST_tag:
-		if (bl->offs)
-			print_otag(h, TAG_DIV, "cswl", "Bl-tag", bl->offs);
-		print_otag(h, TAG_DL, "csw*+l", bl->comp ?
-		    "Bl-tag Bl-compact" : "Bl-tag", bl->width);
-		return 1;
-	case LIST_column:
-		elemtype = TAG_TABLE;
-		(void)strlcpy(cattr, "Bl-column", sizeof(cattr));
-		break;
-	default:
-		abort();
-	}
-	if (bl->comp)
-		(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
-	print_otag(h, elemtype, "cswl", cattr, bl->offs);
-	return 1;
-}
-
-static int
-mdoc_ex_pre(MDOC_ARGS)
-{
-	if (n->prev)
-		print_otag(h, TAG_BR, "");
-	return 1;
-}
-
-static int
-mdoc_st_pre(MDOC_ARGS)
-{
-	print_otag(h, TAG_SPAN, "cT", "St");
-	return 1;
-}
-
-static int
-mdoc_em_pre(MDOC_ARGS)
-{
-	print_otag(h, TAG_I, "cT", "Em");
-	return 1;
-}
-
-static int
-mdoc_d1_pre(MDOC_ARGS)
-{
-	if (n->type != ROFFT_BLOCK)
-		return 1;
-
-	print_otag(h, TAG_DIV, "c", "D1");
-
-	if (n->tok == MDOC_Dl)
-		print_otag(h, TAG_CODE, "c", "Li");
-
-	return 1;
-}
-
-static int
-mdoc_sx_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	id = html_make_id(n);
-	print_otag(h, TAG_A, "cThR", "Sx", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_bd_pre(MDOC_ARGS)
-{
-	int			 comp, offs, sv;
-	struct roff_node	*nn;
-
-	if (n->type == ROFFT_HEAD)
-		return 0;
-
-	if (n->type == ROFFT_BLOCK) {
-		comp = n->norm->Bd.comp;
-		for (nn = n; nn && ! comp; nn = nn->parent) {
-			if (nn->type != ROFFT_BLOCK)
-				continue;
-			if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok)
-				comp = 1;
-			if (nn->prev)
-				break;
-		}
-		if ( ! comp)
-			print_paragraph(h);
-		return 1;
-	}
-
-	/* Handle the -offset argument. */
-
-	if (n->norm->Bd.offs == NULL ||
-	    ! strcmp(n->norm->Bd.offs, "left"))
-		offs = 0;
-	else if ( ! strcmp(n->norm->Bd.offs, "indent"))
-		offs = INDENT;
-	else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
-		offs = INDENT * 2;
-	else
-		offs = -1;
-
-	if (offs == -1)
-		print_otag(h, TAG_DIV, "cswl", "Bd", n->norm->Bd.offs);
-	else
-		print_otag(h, TAG_DIV, "cshl", "Bd", offs);
-
-	if (n->norm->Bd.type != DISP_unfilled &&
-	    n->norm->Bd.type != DISP_literal)
-		return 1;
-
-	print_otag(h, TAG_PRE, "c", "Li");
-
-	/* This can be recursive: save & set our literal state. */
-
-	sv = h->flags & HTML_LITERAL;
-	h->flags |= HTML_LITERAL;
-
-	for (nn = n->child; nn; nn = nn->next) {
-		print_mdoc_node(meta, nn, h);
-		/*
-		 * If the printed node flushes its own line, then we
-		 * needn't do it here as well.  This is hacky, but the
-		 * notion of selective eoln whitespace is pretty dumb
-		 * anyway, so don't sweat it.
-		 */
-		switch (nn->tok) {
-		case ROFF_br:
-		case ROFF_sp:
-		case MDOC_Sm:
-		case MDOC_Bl:
-		case MDOC_D1:
-		case MDOC_Dl:
-		case MDOC_Lp:
-		case MDOC_Pp:
-			continue;
-		default:
-			break;
-		}
-		if (h->flags & HTML_NONEWLINE ||
-		    (nn->next && ! (nn->next->flags & NODE_LINE)))
-			continue;
-		else if (nn->next)
-			print_text(h, "\n");
-
-		h->flags |= HTML_NOSPACE;
-	}
-
-	if (0 == sv)
-		h->flags &= ~HTML_LITERAL;
-
-	return 0;
-}
-
-static int
-mdoc_pa_pre(MDOC_ARGS)
-{
-	print_otag(h, TAG_I, "cT", "Pa");
-	return 1;
-}
-
-static int
-mdoc_ad_pre(MDOC_ARGS)
-{
-	print_otag(h, TAG_I, "c", "Ad");
-	return 1;
-}
-
-static int
-mdoc_an_pre(MDOC_ARGS)
-{
-	if (n->norm->An.auth == AUTH_split) {
-		h->flags &= ~HTML_NOSPLIT;
-		h->flags |= HTML_SPLIT;
-		return 0;
-	}
-	if (n->norm->An.auth == AUTH_nosplit) {
-		h->flags &= ~HTML_SPLIT;
-		h->flags |= HTML_NOSPLIT;
-		return 0;
-	}
-
-	if (h->flags & HTML_SPLIT)
-		print_otag(h, TAG_BR, "");
-
-	if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
-		h->flags |= HTML_SPLIT;
-
-	print_otag(h, TAG_SPAN, "cT", "An");
-	return 1;
-}
-
-static int
-mdoc_cd_pre(MDOC_ARGS)
-{
-	synopsis_pre(h, n);
-	print_otag(h, TAG_B, "cT", "Cd");
-	return 1;
-}
-
-static int
-mdoc_dv_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_CODE, "cTi", "Dv", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_ev_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_CODE, "cTi", "Ev", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_er_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	id = n->sec == SEC_ERRORS &&
-	    (n->parent->tok == MDOC_It ||
-	     (n->parent->tok == MDOC_Bq &&
-	      n->parent->parent->parent->tok == MDOC_It)) ?
-	    html_make_id(n) : NULL;
-
-	if (id != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_CODE, "cTi", "Er", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_fa_pre(MDOC_ARGS)
-{
-	const struct roff_node	*nn;
-	struct tag		*t;
-
-	if (n->parent->tok != MDOC_Fo) {
-		print_otag(h, TAG_VAR, "cT", "Fa");
-		return 1;
-	}
-
-	for (nn = n->child; nn; nn = nn->next) {
-		t = print_otag(h, TAG_VAR, "cT", "Fa");
-		print_text(h, nn->string);
-		print_tagq(h, t);
-		if (nn->next) {
-			h->flags |= HTML_NOSPACE;
-			print_text(h, ",");
-		}
-	}
-
-	if (n->child && n->next && n->next->tok == MDOC_Fa) {
-		h->flags |= HTML_NOSPACE;
-		print_text(h, ",");
-	}
-
-	return 0;
-}
-
-static int
-mdoc_fd_pre(MDOC_ARGS)
-{
-	struct tag	*t;
-	char		*buf, *cp;
-
-	synopsis_pre(h, n);
-
-	if (NULL == (n = n->child))
-		return 0;
-
-	assert(n->type == ROFFT_TEXT);
-
-	if (strcmp(n->string, "#include")) {
-		print_otag(h, TAG_B, "cT", "Fd");
-		return 1;
-	}
-
-	print_otag(h, TAG_B, "cT", "In");
-	print_text(h, n->string);
-
-	if (NULL != (n = n->next)) {
-		assert(n->type == ROFFT_TEXT);
-
-		if (h->base_includes) {
-			cp = n->string;
-			if (*cp == '<' || *cp == '"')
-				cp++;
-			buf = mandoc_strdup(cp);
-			cp = strchr(buf, '\0') - 1;
-			if (cp >= buf && (*cp == '>' || *cp == '"'))
-				*cp = '\0';
-			t = print_otag(h, TAG_A, "cThI", "In", buf);
-			free(buf);
-		} else
-			t = print_otag(h, TAG_A, "cT", "In");
-
-		print_text(h, n->string);
-		print_tagq(h, t);
-
-		n = n->next;
-	}
-
-	for ( ; n; n = n->next) {
-		assert(n->type == ROFFT_TEXT);
-		print_text(h, n->string);
-	}
-
-	return 0;
-}
-
-static int
-mdoc_vt_pre(MDOC_ARGS)
-{
-	if (n->type == ROFFT_BLOCK) {
-		synopsis_pre(h, n);
-		return 1;
-	} else if (n->type == ROFFT_ELEM) {
-		synopsis_pre(h, n);
-	} else if (n->type == ROFFT_HEAD)
-		return 0;
-
-	print_otag(h, TAG_VAR, "cT", "Vt");
-	return 1;
-}
-
-static int
-mdoc_ft_pre(MDOC_ARGS)
-{
-	synopsis_pre(h, n);
-	print_otag(h, TAG_VAR, "cT", "Ft");
-	return 1;
-}
-
-static int
-mdoc_fn_pre(MDOC_ARGS)
-{
-	struct tag	*t;
-	char		 nbuf[BUFSIZ];
-	const char	*sp, *ep;
-	int		 sz, pretty;
-
-	pretty = NODE_SYNPRETTY & n->flags;
-	synopsis_pre(h, n);
-
-	/* Split apart into type and name. */
-	assert(n->child->string);
-	sp = n->child->string;
-
-	ep = strchr(sp, ' ');
-	if (NULL != ep) {
-		t = print_otag(h, TAG_VAR, "cT", "Ft");
-
-		while (ep) {
-			sz = MIN((int)(ep - sp), BUFSIZ - 1);
-			(void)memcpy(nbuf, sp, (size_t)sz);
-			nbuf[sz] = '\0';
-			print_text(h, nbuf);
-			sp = ++ep;
-			ep = strchr(sp, ' ');
-		}
-		print_tagq(h, t);
-	}
-
-	t = print_otag(h, TAG_B, "cT", "Fn");
-
-	if (sp)
-		print_text(h, sp);
-
-	print_tagq(h, t);
-
-	h->flags |= HTML_NOSPACE;
-	print_text(h, "(");
-	h->flags |= HTML_NOSPACE;
-
-	for (n = n->child->next; n; n = n->next) {
-		if (NODE_SYNPRETTY & n->flags)
-			t = print_otag(h, TAG_VAR, "cTss?", "Fa",
-			    "white-space", "nowrap");
-		else
-			t = print_otag(h, TAG_VAR, "cT", "Fa");
-		print_text(h, n->string);
-		print_tagq(h, t);
-		if (n->next) {
-			h->flags |= HTML_NOSPACE;
-			print_text(h, ",");
-		}
-	}
-
-	h->flags |= HTML_NOSPACE;
-	print_text(h, ")");
-
-	if (pretty) {
-		h->flags |= HTML_NOSPACE;
-		print_text(h, ";");
-	}
-
-	return 0;
-}
-
-static int
-mdoc_sm_pre(MDOC_ARGS)
-{
-
-	if (NULL == n->child)
-		h->flags ^= HTML_NONOSPACE;
-	else if (0 == strcmp("on", n->child->string))
-		h->flags &= ~HTML_NONOSPACE;
-	else
-		h->flags |= HTML_NONOSPACE;
-
-	if ( ! (HTML_NONOSPACE & h->flags))
-		h->flags &= ~HTML_NOSPACE;
-
-	return 0;
-}
-
-static int
-mdoc_skip_pre(MDOC_ARGS)
-{
-
-	return 0;
-}
-
-static int
-mdoc_pp_pre(MDOC_ARGS)
-{
-
-	print_paragraph(h);
-	return 0;
-}
-
-static int
-mdoc_lk_pre(MDOC_ARGS)
-{
-	const struct roff_node *link, *descr, *punct;
-	struct tag	*t;
-
-	if ((link = n->child) == NULL)
-		return 0;
-
-	/* Find beginning of trailing punctuation. */
-	punct = n->last;
-	while (punct != link && punct->flags & NODE_DELIMC)
-		punct = punct->prev;
-	punct = punct->next;
-
-	/* Link target and link text. */
-	descr = link->next;
-	if (descr == punct)
-		descr = link;  /* no text */
-	t = print_otag(h, TAG_A, "cTh", "Lk", link->string);
-	do {
-		if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
-			h->flags |= HTML_NOSPACE;
-		print_text(h, descr->string);
-		descr = descr->next;
-	} while (descr != punct);
-	print_tagq(h, t);
-
-	/* Trailing punctuation. */
-	while (punct != NULL) {
-		h->flags |= HTML_NOSPACE;
-		print_text(h, punct->string);
-		punct = punct->next;
-	}
-	return 0;
-}
-
-static int
-mdoc_mt_pre(MDOC_ARGS)
-{
-	struct tag	*t;
-	char		*cp;
-
-	for (n = n->child; n; n = n->next) {
-		assert(n->type == ROFFT_TEXT);
-
-		mandoc_asprintf(&cp, "mailto:%s", n->string);
-		t = print_otag(h, TAG_A, "cTh", "Mt", cp);
-		print_text(h, n->string);
-		print_tagq(h, t);
-		free(cp);
-	}
-
-	return 0;
-}
-
-static int
-mdoc_fo_pre(MDOC_ARGS)
-{
-	struct tag	*t;
-
-	if (n->type == ROFFT_BODY) {
-		h->flags |= HTML_NOSPACE;
-		print_text(h, "(");
-		h->flags |= HTML_NOSPACE;
-		return 1;
-	} else if (n->type == ROFFT_BLOCK) {
-		synopsis_pre(h, n);
-		return 1;
-	}
-
-	if (n->child == NULL)
-		return 0;
-
-	assert(n->child->string);
-	t = print_otag(h, TAG_B, "cT", "Fn");
-	print_text(h, n->child->string);
-	print_tagq(h, t);
-	return 0;
-}
-
-static void
-mdoc_fo_post(MDOC_ARGS)
-{
-
-	if (n->type != ROFFT_BODY)
-		return;
-	h->flags |= HTML_NOSPACE;
-	print_text(h, ")");
-	h->flags |= HTML_NOSPACE;
-	print_text(h, ";");
-}
-
-static int
-mdoc_in_pre(MDOC_ARGS)
-{
-	struct tag	*t;
-
-	synopsis_pre(h, n);
-	print_otag(h, TAG_B, "cT", "In");
-
-	/*
-	 * The first argument of the `In' gets special treatment as
-	 * being a linked value.  Subsequent values are printed
-	 * afterward.  groff does similarly.  This also handles the case
-	 * of no children.
-	 */
-
-	if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags)
-		print_text(h, "#include");
-
-	print_text(h, "<");
-	h->flags |= HTML_NOSPACE;
-
-	if (NULL != (n = n->child)) {
-		assert(n->type == ROFFT_TEXT);
-
-		if (h->base_includes)
-			t = print_otag(h, TAG_A, "cThI", "In", n->string);
-		else
-			t = print_otag(h, TAG_A, "cT", "In");
-		print_text(h, n->string);
-		print_tagq(h, t);
-
-		n = n->next;
-	}
-
-	h->flags |= HTML_NOSPACE;
-	print_text(h, ">");
-
-	for ( ; n; n = n->next) {
-		assert(n->type == ROFFT_TEXT);
-		print_text(h, n->string);
-	}
-
-	return 0;
-}
-
-static int
-mdoc_ic_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_B, "cTi", "Ic", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_va_pre(MDOC_ARGS)
-{
-	print_otag(h, TAG_VAR, "cT", "Va");
-	return 1;
-}
-
-static int
-mdoc_ap_pre(MDOC_ARGS)
-{
-
-	h->flags |= HTML_NOSPACE;
-	print_text(h, "\\(aq");
-	h->flags |= HTML_NOSPACE;
-	return 1;
-}
-
-static int
-mdoc_bf_pre(MDOC_ARGS)
-{
-	const char	*cattr;
-
-	if (n->type == ROFFT_HEAD)
-		return 0;
-	else if (n->type != ROFFT_BODY)
-		return 1;
-
-	if (FONT_Em == n->norm->Bf.font)
-		cattr = "Em";
-	else if (FONT_Sy == n->norm->Bf.font)
-		cattr = "Sy";
-	else if (FONT_Li == n->norm->Bf.font)
-		cattr = "Li";
-	else
-		cattr = "No";
-
-	/*
-	 * We want this to be inline-formatted, but needs to be div to
-	 * accept block children.
-	 */
-
-	print_otag(h, TAG_DIV, "css?hl", cattr, "display", "inline", 1);
-	return 1;
-}
-
-static int
-mdoc_ms_pre(MDOC_ARGS)
-{
-	char *id;
-
-	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_B, "cTi", "Ms", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_igndelim_pre(MDOC_ARGS)
-{
-
-	h->flags |= HTML_IGNDELIM;
-	return 1;
-}
-
-static void
-mdoc_pf_post(MDOC_ARGS)
-{
-
-	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
-		h->flags |= HTML_NOSPACE;
-}
-
-static int
-mdoc_rs_pre(MDOC_ARGS)
-{
-	if (n->type != ROFFT_BLOCK)
-		return 1;
-
-	if (n->prev && SEC_SEE_ALSO == n->sec)
-		print_paragraph(h);
-
-	print_otag(h, TAG_CITE, "cT", "Rs");
-	return 1;
-}
-
-static int
-mdoc_no_pre(MDOC_ARGS)
-{
-	char *id;
-
-	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_SPAN, "ci", "No", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_li_pre(MDOC_ARGS)
-{
-	char	*id;
-
-	if ((id = cond_id(n)) != NULL)
-		print_otag(h, TAG_A, "chR", "selflink", id);
-	print_otag(h, TAG_CODE, "ci", "Li", id);
-	free(id);
-	return 1;
-}
-
-static int
-mdoc_sy_pre(MDOC_ARGS)
-{
-	print_otag(h, TAG_B, "cT", "Sy");
-	return 1;
-}
-
-static int
-mdoc_lb_pre(MDOC_ARGS)
-{
-	if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
-		print_otag(h, TAG_BR, "");
-
-	print_otag(h, TAG_SPAN, "cT", "Lb");
-	return 1;
-}
-
-static int
-mdoc__x_pre(MDOC_ARGS)
-{
-	const char	*cattr;
-	enum htmltag	 t;
-
-	t = TAG_SPAN;
-
-	switch (n->tok) {
-	case MDOC__A:
-		cattr = "RsA";
-		if (n->prev && MDOC__A == n->prev->tok)
-			if (NULL == n->next || MDOC__A != n->next->tok)
-				print_text(h, "and");
-		break;
-	case MDOC__B:
-		t = TAG_I;
-		cattr = "RsB";
-		break;
-	case MDOC__C:
-		cattr = "RsC";
-		break;
-	case MDOC__D:
-		cattr = "RsD";
-		break;
-	case MDOC__I:
-		t = TAG_I;
-		cattr = "RsI";
-		break;
-	case MDOC__J:
-		t = TAG_I;
-		cattr = "RsJ";
-		break;
-	case MDOC__N:
-		cattr = "RsN";
-		break;
-	case MDOC__O:
-		cattr = "RsO";
-		break;
-	case MDOC__P:
-		cattr = "RsP";
-		break;
-	case MDOC__Q:
-		cattr = "RsQ";
-		break;
-	case MDOC__R:
-		cattr = "RsR";
-		break;
-	case MDOC__T:
-		cattr = "RsT";
-		break;
-	case MDOC__U:
-		print_otag(h, TAG_A, "ch", "RsU", n->child->string);
-		return 1;
-	case MDOC__V:
-		cattr = "RsV";
-		break;
-	default:
-		abort();
-	}
-
-	print_otag(h, t, "c", cattr);
-	return 1;
-}
-
-static void
-mdoc__x_post(MDOC_ARGS)
-{
-
-	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
-		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
-			if (NULL == n->prev || MDOC__A != n->prev->tok)
-				return;
-
-	/* TODO: %U */
-
-	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
-		return;
-
-	h->flags |= HTML_NOSPACE;
-	print_text(h, n->next ? "," : ".");
-}
-
-static int
-mdoc_bk_pre(MDOC_ARGS)
-{
-
-	switch (n->type) {
-	case ROFFT_BLOCK:
-		break;
-	case ROFFT_HEAD:
-		return 0;
-	case ROFFT_BODY:
-		if (n->parent->args != NULL || n->prev->child == NULL)
-			h->flags |= HTML_PREKEEP;
-		break;
-	default:
-		abort();
-	}
-
-	return 1;
-}
-
-static void
-mdoc_bk_post(MDOC_ARGS)
-{
-
-	if (n->type == ROFFT_BODY)
-		h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
-}
-
-static int
-mdoc_quote_pre(MDOC_ARGS)
-{
-	if (n->type != ROFFT_BODY)
-		return 1;
-
-	switch (n->tok) {
-	case MDOC_Ao:
-	case MDOC_Aq:
-		print_text(h, n->child != NULL && n->child->next == NULL &&
-		    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
-		break;
-	case MDOC_Bro:
-	case MDOC_Brq:
-		print_text(h, "\\(lC");
-		break;
-	case MDOC_Bo:
-	case MDOC_Bq:
-		print_text(h, "\\(lB");
-		break;
-	case MDOC_Oo:
-	case MDOC_Op:
-		print_text(h, "\\(lB");
-		h->flags |= HTML_NOSPACE;
-		print_otag(h, TAG_SPAN, "c", "Op");
-		break;
-	case MDOC_En:
-		if (NULL == n->norm->Es ||
-		    NULL == n->norm->Es->child)
-			return 1;
-		print_text(h, n->norm->Es->child->string);
-		break;
-	case MDOC_Do:
-	case MDOC_Dq:
-	case MDOC_Qo:
-	case MDOC_Qq:
-		print_text(h, "\\(lq");
-		break;
-	case MDOC_Po:
-	case MDOC_Pq:
-		print_text(h, "(");
-		break;
-	case MDOC_Ql:
-		print_text(h, "\\(oq");
-		h->flags |= HTML_NOSPACE;
-		print_otag(h, TAG_CODE, "c", "Li");
-		break;
-	case MDOC_So:
-	case MDOC_Sq:
-		print_text(h, "\\(oq");
-		break;
-	default:
-		abort();
-	}
-
-	h->flags |= HTML_NOSPACE;
-	return 1;
-}
-
-static void
-mdoc_quote_post(MDOC_ARGS)
-{
-
-	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
-		return;
-
-	h->flags |= HTML_NOSPACE;
-
-	switch (n->tok) {
-	case MDOC_Ao:
-	case MDOC_Aq:
-		print_text(h, n->child != NULL && n->child->next == NULL &&
-		    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
-		break;
-	case MDOC_Bro:
-	case MDOC_Brq:
-		print_text(h, "\\(rC");
-		break;
-	case MDOC_Oo:
-	case MDOC_Op:
-	case MDOC_Bo:
-	case MDOC_Bq:
-		print_text(h, "\\(rB");
-		break;
-	case MDOC_En:
-		if (n->norm->Es == NULL ||
-		    n->norm->Es->child == NULL ||
-		    n->norm->Es->child->next == NULL)
-			h->flags &= ~HTML_NOSPACE;
-		else
-			print_text(h, n->norm->Es->child->next->string);
-		break;
-	case MDOC_Qo:
-	case MDOC_Qq:
-	case MDOC_Do:
-	case MDOC_Dq:
-		print_text(h, "\\(rq");
-		break;
-	case MDOC_Po:
-	case MDOC_Pq:
-		print_text(h, ")");
-		break;
-	case MDOC_Ql:
-	case MDOC_So:
-	case MDOC_Sq:
-		print_text(h, "\\(cq");
-		break;
-	default:
-		abort();
-	}
-}
-
-static int
-mdoc_eo_pre(MDOC_ARGS)
-{
-
-	if (n->type != ROFFT_BODY)
-		return 1;
-
-	if (n->end == ENDBODY_NOT &&
-	    n->parent->head->child == NULL &&
-	    n->child != NULL &&
-	    n->child->end != ENDBODY_NOT)
-		print_text(h, "\\&");
-	else if (n->end != ENDBODY_NOT ? n->child != NULL :
-	    n->parent->head->child != NULL && (n->child != NULL ||
-	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
-		h->flags |= HTML_NOSPACE;
-	return 1;
-}
-
-static void
-mdoc_eo_post(MDOC_ARGS)
-{
-	int	 body, tail;
-
-	if (n->type != ROFFT_BODY)
-		return;
-
-	if (n->end != ENDBODY_NOT) {
-		h->flags &= ~HTML_NOSPACE;
-		return;
-	}
-
-	body = n->child != NULL || n->parent->head->child != NULL;
-	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
-
-	if (body && tail)
-		h->flags |= HTML_NOSPACE;
-	else if ( ! tail)
-		h->flags &= ~HTML_NOSPACE;
-}

Property changes on: head/contrib/mdocml/mdoc_html.c
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: head/contrib/mdocml/cgi.c
===================================================================
--- head/contrib/mdocml/cgi.c	(revision 338825)
+++ head/contrib/mdocml/cgi.c	(nonexistent)
@@ -1,1242 +0,0 @@
-/*	$Id: cgi.c,v 1.156 2017/06/24 14:38:32 schwarze Exp $ */
-/*
- * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@usta.de>
- *
- * 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 <sys/types.h>
-#include <sys/time.h>
-
-#include <ctype.h>
-#if HAVE_ERR
-#include <err.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "mandoc_aux.h"
-#include "mandoc.h"
-#include "roff.h"
-#include "mdoc.h"
-#include "man.h"
-#include "main.h"
-#include "manconf.h"
-#include "mansearch.h"
-#include "cgi.h"
-
-/*
- * A query as passed to the search function.
- */
-struct	query {
-	char		*manpath; /* desired manual directory */
-	char		*arch; /* architecture */
-	char		*sec; /* manual section */
-	char		*query; /* unparsed query expression */
-	int		 equal; /* match whole names, not substrings */
-};
-
-struct	req {
-	struct query	  q;
-	char		**p; /* array of available manpaths */
-	size_t		  psz; /* number of available manpaths */
-	int		  isquery; /* QUERY_STRING used, not PATH_INFO */
-};
-
-enum	focus {
-	FOCUS_NONE = 0,
-	FOCUS_QUERY
-};
-
-static	void		 html_print(const char *);
-static	void		 html_putchar(char);
-static	int		 http_decode(char *);
-static	void		 parse_manpath_conf(struct req *);
-static	void		 parse_path_info(struct req *req, const char *path);
-static	void		 parse_query_string(struct req *, const char *);
-static	void		 pg_error_badrequest(const char *);
-static	void		 pg_error_internal(void);
-static	void		 pg_index(const struct req *);
-static	void		 pg_noresult(const struct req *, const char *);
-static	void		 pg_redirect(const struct req *, const char *);
-static	void		 pg_search(const struct req *);
-static	void		 pg_searchres(const struct req *,
-				struct manpage *, size_t);
-static	void		 pg_show(struct req *, const char *);
-static	void		 resp_begin_html(int, const char *, const char *);
-static	void		 resp_begin_http(int, const char *);
-static	void		 resp_catman(const struct req *, const char *);
-static	void		 resp_copy(const char *);
-static	void		 resp_end_html(void);
-static	void		 resp_format(const struct req *, const char *);
-static	void		 resp_searchform(const struct req *, enum focus);
-static	void		 resp_show(const struct req *, const char *);
-static	void		 set_query_attr(char **, char **);
-static	int		 validate_filename(const char *);
-static	int		 validate_manpath(const struct req *, const char *);
-static	int		 validate_urifrag(const char *);
-
-static	const char	 *scriptname = SCRIPT_NAME;
-
-static	const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
-static	const char *const sec_numbers[] = {
-    "0", "1", "2", "3", "3p", "4", "5", "6", "7", "8", "9"
-};
-static	const char *const sec_names[] = {
-    "All Sections",
-    "1 - General Commands",
-    "2 - System Calls",
-    "3 - Library Functions",
-    "3p - Perl Library",
-    "4 - Device Drivers",
-    "5 - File Formats",
-    "6 - Games",
-    "7 - Miscellaneous Information",
-    "8 - System Manager\'s Manual",
-    "9 - Kernel Developer\'s Manual"
-};
-static	const int sec_MAX = sizeof(sec_names) / sizeof(char *);
-
-static	const char *const arch_names[] = {
-    "amd64",       "alpha",       "armv7",	"arm64",
-    "hppa",        "i386",        "landisk",
-    "loongson",    "luna88k",     "macppc",      "mips64",
-    "octeon",      "sgi",         "socppc",      "sparc64",
-    "amiga",       "arc",         "armish",      "arm32",
-    "atari",       "aviion",      "beagle",      "cats",
-    "hppa64",      "hp300",
-    "ia64",        "mac68k",      "mvme68k",     "mvme88k",
-    "mvmeppc",     "palm",        "pc532",       "pegasos",
-    "pmax",        "powerpc",     "solbourne",   "sparc",
-    "sun3",        "vax",         "wgrisc",      "x68k",
-    "zaurus"
-};
-static	const int arch_MAX = sizeof(arch_names) / sizeof(char *);
-
-/*
- * Print a character, escaping HTML along the way.
- * This will pass non-ASCII straight to output: be warned!
- */
-static void
-html_putchar(char c)
-{
-
-	switch (c) {
-	case '"':
-		printf(""");
-		break;
-	case '&':
-		printf("&");
-		break;
-	case '>':
-		printf(">");
-		break;
-	case '<':
-		printf("<");
-		break;
-	default:
-		putchar((unsigned char)c);
-		break;
-	}
-}
-
-/*
- * Call through to html_putchar().
- * Accepts NULL strings.
- */
-static void
-html_print(const char *p)
-{
-
-	if (NULL == p)
-		return;
-	while ('\0' != *p)
-		html_putchar(*p++);
-}
-
-/*
- * Transfer the responsibility for the allocated string *val
- * to the query structure.
- */
-static void
-set_query_attr(char **attr, char **val)
-{
-
-	free(*attr);
-	if (**val == '\0') {
-		*attr = NULL;
-		free(*val);
-	} else
-		*attr = *val;
-	*val = NULL;
-}
-
-/*
- * Parse the QUERY_STRING for key-value pairs
- * and store the values into the query structure.
- */
-static void
-parse_query_string(struct req *req, const char *qs)
-{
-	char		*key, *val;
-	size_t		 keysz, valsz;
-
-	req->isquery	= 1;
-	req->q.manpath	= NULL;
-	req->q.arch	= NULL;
-	req->q.sec	= NULL;
-	req->q.query	= NULL;
-	req->q.equal	= 1;
-
-	key = val = NULL;
-	while (*qs != '\0') {
-
-		/* Parse one key. */
-
-		keysz = strcspn(qs, "=;&");
-		key = mandoc_strndup(qs, keysz);
-		qs += keysz;
-		if (*qs != '=')
-			goto next;
-
-		/* Parse one value. */
-
-		valsz = strcspn(++qs, ";&");
-		val = mandoc_strndup(qs, valsz);
-		qs += valsz;
-
-		/* Decode and catch encoding errors. */
-
-		if ( ! (http_decode(key) && http_decode(val)))
-			goto next;
-
-		/* Handle key-value pairs. */
-
-		if ( ! strcmp(key, "query"))
-			set_query_attr(&req->q.query, &val);
-
-		else if ( ! strcmp(key, "apropos"))
-			req->q.equal = !strcmp(val, "0");
-
-		else if ( ! strcmp(key, "manpath")) {
-#ifdef COMPAT_OLDURI
-			if ( ! strncmp(val, "OpenBSD ", 8)) {
-				val[7] = '-';
-				if ('C' == val[8])
-					val[8] = 'c';
-			}
-#endif
-			set_query_attr(&req->q.manpath, &val);
-		}
-
-		else if ( ! (strcmp(key, "sec")
-#ifdef COMPAT_OLDURI
-		    && strcmp(key, "sektion")
-#endif
-		    )) {
-			if ( ! strcmp(val, "0"))
-				*val = '\0';
-			set_query_attr(&req->q.sec, &val);
-		}
-
-		else if ( ! strcmp(key, "arch")) {
-			if ( ! strcmp(val, "default"))
-				*val = '\0';
-			set_query_attr(&req->q.arch, &val);
-		}
-
-		/*
-		 * The key must be freed in any case.
-		 * The val may have been handed over to the query
-		 * structure, in which case it is now NULL.
-		 */
-next:
-		free(key);
-		key = NULL;
-		free(val);
-		val = NULL;
-
-		if (*qs != '\0')
-			qs++;
-	}
-}
-
-/*
- * HTTP-decode a string.  The standard explanation is that this turns
- * "%4e+foo" into "n foo" in the regular way.  This is done in-place
- * over the allocated string.
- */
-static int
-http_decode(char *p)
-{
-	char             hex[3];
-	char		*q;
-	int              c;
-
-	hex[2] = '\0';
-
-	q = p;
-	for ( ; '\0' != *p; p++, q++) {
-		if ('%' == *p) {
-			if ('\0' == (hex[0] = *(p + 1)))
-				return 0;
-			if ('\0' == (hex[1] = *(p + 2)))
-				return 0;
-			if (1 != sscanf(hex, "%x", &c))
-				return 0;
-			if ('\0' == c)
-				return 0;
-
-			*q = (char)c;
-			p += 2;
-		} else
-			*q = '+' == *p ? ' ' : *p;
-	}
-
-	*q = '\0';
-	return 1;
-}
-
-static void
-resp_begin_http(int code, const char *msg)
-{
-
-	if (200 != code)
-		printf("Status: %d %s\r\n", code, msg);
-
-	printf("Content-Type: text/html; charset=utf-8\r\n"
-	     "Cache-Control: no-cache\r\n"
-	     "Pragma: no-cache\r\n"
-	     "\r\n");
-
-	fflush(stdout);
-}
-
-static void
-resp_copy(const char *filename)
-{
-	char	 buf[4096];
-	ssize_t	 sz;
-	int	 fd;
-
-	if ((fd = open(filename, O_RDONLY)) != -1) {
-		fflush(stdout);
-		while ((sz = read(fd, buf, sizeof(buf))) > 0)
-			write(STDOUT_FILENO, buf, sz);
-		close(fd);
-	}
-}
-
-static void
-resp_begin_html(int code, const char *msg, const char *file)
-{
-	char	*cp;
-
-	resp_begin_http(code, msg);
-
-	printf("<!DOCTYPE html>\n"
-	       "<html>\n"
-	       "<head>\n"
-	       "  <meta charset=\"UTF-8\"/>\n"
-	       "  <link rel=\"stylesheet\" href=\"%s/mandoc.css\""
-	       " type=\"text/css\" media=\"all\">\n"
-	       "  <title>",
-	       CSS_DIR);
-	if (file != NULL) {
-		if ((cp = strrchr(file, '/')) != NULL)
-			file = cp + 1;
-		if ((cp = strrchr(file, '.')) != NULL) {
-			printf("%.*s(%s) - ", (int)(cp - file), file, cp + 1);
-		} else
-			printf("%s - ", file);
-	}
-	printf("%s\n"
-	       "\n"
-	       "\n",
-	       CUSTOMIZE_TITLE);
-
-	resp_copy(MAN_DIR "/header.html");
-}
-
-static void
-resp_end_html(void)
-{
-
-	resp_copy(MAN_DIR "/footer.html");
-
-	puts("\n"
-	     "");
-}
-
-static void
-resp_searchform(const struct req *req, enum focus focus)
-{
-	int		 i;
-
-	printf("
\n" - "
\n" - " Manual Page Search Parameters\n", - scriptname); - - /* Write query input box. */ - - printf(" q.query != NULL) - html_print(req->q.query); - printf( "\" size=\"40\""); - if (focus == FOCUS_QUERY) - printf(" autofocus"); - puts(">"); - - /* Write submission buttons. */ - - printf( " \n" - " \n" - "
\n"); - - /* Write section selector. */ - - puts(" "); - - /* Write architecture selector. */ - - printf( " "); - - /* Write manpath selector. */ - - if (req->psz > 1) { - puts(" "); - } - - puts("
\n" - "
"); -} - -static int -validate_urifrag(const char *frag) -{ - - while ('\0' != *frag) { - if ( ! (isalnum((unsigned char)*frag) || - '-' == *frag || '.' == *frag || - '/' == *frag || '_' == *frag)) - return 0; - frag++; - } - return 1; -} - -static int -validate_manpath(const struct req *req, const char* manpath) -{ - size_t i; - - for (i = 0; i < req->psz; i++) - if ( ! strcmp(manpath, req->p[i])) - return 1; - - return 0; -} - -static int -validate_filename(const char *file) -{ - - if ('.' == file[0] && '/' == file[1]) - file += 2; - - return ! (strstr(file, "../") || strstr(file, "/..") || - (strncmp(file, "man", 3) && strncmp(file, "cat", 3))); -} - -static void -pg_index(const struct req *req) -{ - - resp_begin_html(200, NULL, NULL); - resp_searchform(req, FOCUS_QUERY); - printf("

\n" - "This web interface is documented in the\n" - "man.cgi(8)\n" - "manual, and the\n" - "apropos(1)\n" - "manual explains the query syntax.\n" - "

\n", - scriptname, *scriptname == '\0' ? "" : "/", - scriptname, *scriptname == '\0' ? "" : "/"); - resp_end_html(); -} - -static void -pg_noresult(const struct req *req, const char *msg) -{ - resp_begin_html(200, NULL, NULL); - resp_searchform(req, FOCUS_QUERY); - puts("

"); - puts(msg); - puts("

"); - resp_end_html(); -} - -static void -pg_error_badrequest(const char *msg) -{ - - resp_begin_html(400, "Bad Request", NULL); - puts("

Bad Request

\n" - "

\n"); - puts(msg); - printf("Try again from the\n" - "main page.\n" - "

", scriptname); - resp_end_html(); -} - -static void -pg_error_internal(void) -{ - resp_begin_html(500, "Internal Server Error", NULL); - puts("

Internal Server Error

"); - resp_end_html(); -} - -static void -pg_redirect(const struct req *req, const char *name) -{ - printf("Status: 303 See Other\r\n" - "Location: /"); - if (*scriptname != '\0') - printf("%s/", scriptname); - if (strcmp(req->q.manpath, req->p[0])) - printf("%s/", req->q.manpath); - if (req->q.arch != NULL) - printf("%s/", req->q.arch); - printf("%s", name); - if (req->q.sec != NULL) - printf(".%s", req->q.sec); - printf("\r\nContent-Type: text/html; charset=utf-8\r\n\r\n"); -} - -static void -pg_searchres(const struct req *req, struct manpage *r, size_t sz) -{ - char *arch, *archend; - const char *sec; - size_t i, iuse; - int archprio, archpriouse; - int prio, priouse; - - for (i = 0; i < sz; i++) { - if (validate_filename(r[i].file)) - continue; - warnx("invalid filename %s in %s database", - r[i].file, req->q.manpath); - pg_error_internal(); - return; - } - - if (req->isquery && sz == 1) { - /* - * If we have just one result, then jump there now - * without any delay. - */ - printf("Status: 303 See Other\r\n" - "Location: /"); - if (*scriptname != '\0') - printf("%s/", scriptname); - if (strcmp(req->q.manpath, req->p[0])) - printf("%s/", req->q.manpath); - printf("%s\r\n" - "Content-Type: text/html; charset=utf-8\r\n\r\n", - r[0].file); - return; - } - - /* - * In man(1) mode, show one of the pages - * even if more than one is found. - */ - - iuse = 0; - if (req->q.equal || sz == 1) { - priouse = 20; - archpriouse = 3; - for (i = 0; i < sz; i++) { - sec = r[i].file; - sec += strcspn(sec, "123456789"); - if (sec[0] == '\0') - continue; - prio = sec_prios[sec[0] - '1']; - if (sec[1] != '/') - prio += 10; - if (req->q.arch == NULL) { - archprio = - ((arch = strchr(sec + 1, '/')) - == NULL) ? 3 : - ((archend = strchr(arch + 1, '/')) - == NULL) ? 0 : - strncmp(arch, "amd64/", - archend - arch) ? 2 : 1; - if (archprio < archpriouse) { - archpriouse = archprio; - priouse = prio; - iuse = i; - continue; - } - if (archprio > archpriouse) - continue; - } - if (prio >= priouse) - continue; - priouse = prio; - iuse = i; - } - resp_begin_html(200, NULL, r[iuse].file); - } else - resp_begin_html(200, NULL, NULL); - - resp_searchform(req, - req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY); - - if (sz > 1) { - puts(""); - for (i = 0; i < sz; i++) { - printf(" \n" - " \n" - " \n" - " "); - } - puts("
" - "q.manpath, req->p[0])) - printf("%s/", req->q.manpath); - printf("%s\">", r[i].file); - html_print(r[i].names); - printf(""); - html_print(r[i].output); - puts("
"); - } - - if (req->q.equal || sz == 1) { - puts("
"); - resp_show(req, r[iuse].file); - } - - resp_end_html(); -} - -static void -resp_catman(const struct req *req, const char *file) -{ - FILE *f; - char *p; - size_t sz; - ssize_t len; - int i; - int italic, bold; - - if ((f = fopen(file, "r")) == NULL) { - puts("

You specified an invalid manual file.

"); - return; - } - - puts("
\n" - "
");
-
-	p = NULL;
-	sz = 0;
-
-	while ((len = getline(&p, &sz, f)) != -1) {
-		bold = italic = 0;
-		for (i = 0; i < len - 1; i++) {
-			/*
-			 * This means that the catpage is out of state.
-			 * Ignore it and keep going (although the
-			 * catpage is bogus).
-			 */
-
-			if ('\b' == p[i] || '\n' == p[i])
-				continue;
-
-			/*
-			 * Print a regular character.
-			 * Close out any bold/italic scopes.
-			 * If we're in back-space mode, make sure we'll
-			 * have something to enter when we backspace.
-			 */
-
-			if ('\b' != p[i + 1]) {
-				if (italic)
-					printf("");
-				if (bold)
-					printf("");
-				italic = bold = 0;
-				html_putchar(p[i]);
-				continue;
-			} else if (i + 2 >= len)
-				continue;
-
-			/* Italic mode. */
-
-			if ('_' == p[i]) {
-				if (bold)
-					printf("");
-				if ( ! italic)
-					printf("");
-				bold = 0;
-				italic = 1;
-				i += 2;
-				html_putchar(p[i]);
-				continue;
-			}
-
-			/*
-			 * Handle funny behaviour troff-isms.
-			 * These grok'd from the original man2html.c.
-			 */
-
-			if (('+' == p[i] && 'o' == p[i + 2]) ||
-					('o' == p[i] && '+' == p[i + 2]) ||
-					('|' == p[i] && '=' == p[i + 2]) ||
-					('=' == p[i] && '|' == p[i + 2]) ||
-					('*' == p[i] && '=' == p[i + 2]) ||
-					('=' == p[i] && '*' == p[i + 2]) ||
-					('*' == p[i] && '|' == p[i + 2]) ||
-					('|' == p[i] && '*' == p[i + 2]))  {
-				if (italic)
-					printf("");
-				if (bold)
-					printf("");
-				italic = bold = 0;
-				putchar('*');
-				i += 2;
-				continue;
-			} else if (('|' == p[i] && '-' == p[i + 2]) ||
-					('-' == p[i] && '|' == p[i + 1]) ||
-					('+' == p[i] && '-' == p[i + 1]) ||
-					('-' == p[i] && '+' == p[i + 1]) ||
-					('+' == p[i] && '|' == p[i + 1]) ||
-					('|' == p[i] && '+' == p[i + 1]))  {
-				if (italic)
-					printf("");
-				if (bold)
-					printf("");
-				italic = bold = 0;
-				putchar('+');
-				i += 2;
-				continue;
-			}
-
-			/* Bold mode. */
-
-			if (italic)
-				printf("");
-			if ( ! bold)
-				printf("");
-			bold = 1;
-			italic = 0;
-			i += 2;
-			html_putchar(p[i]);
-		}
-
-		/*
-		 * Clean up the last character.
-		 * We can get to a newline; don't print that.
-		 */
-
-		if (italic)
-			printf("");
-		if (bold)
-			printf("");
-
-		if (i == len - 1 && p[i] != '\n')
-			html_putchar(p[i]);
-
-		putchar('\n');
-	}
-	free(p);
-
-	puts("
\n" - "
"); - - fclose(f); -} - -static void -resp_format(const struct req *req, const char *file) -{ - struct manoutput conf; - struct mparse *mp; - struct roff_man *man; - void *vp; - int fd; - int usepath; - - if (-1 == (fd = open(file, O_RDONLY, 0))) { - puts("

You specified an invalid manual file.

"); - return; - } - - mchars_alloc(); - mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1, - MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, req->q.manpath); - mparse_readfd(mp, fd, file); - close(fd); - - memset(&conf, 0, sizeof(conf)); - conf.fragment = 1; - conf.style = mandoc_strdup(CSS_DIR "/mandoc.css"); - usepath = strcmp(req->q.manpath, req->p[0]); - mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S", - scriptname, *scriptname == '\0' ? "" : "/", - usepath ? req->q.manpath : "", usepath ? "/" : ""); - - mparse_result(mp, &man, NULL); - if (man == NULL) { - warnx("fatal mandoc error: %s/%s", req->q.manpath, file); - pg_error_internal(); - mparse_free(mp); - mchars_free(); - return; - } - - vp = html_alloc(&conf); - - if (man->macroset == MACROSET_MDOC) { - mdoc_validate(man); - html_mdoc(vp, man); - } else { - man_validate(man); - html_man(vp, man); - } - - html_free(vp); - mparse_free(mp); - mchars_free(); - free(conf.man); - free(conf.style); -} - -static void -resp_show(const struct req *req, const char *file) -{ - - if ('.' == file[0] && '/' == file[1]) - file += 2; - - if ('c' == *file) - resp_catman(req, file); - else - resp_format(req, file); -} - -static void -pg_show(struct req *req, const char *fullpath) -{ - char *manpath; - const char *file; - - if ((file = strchr(fullpath, '/')) == NULL) { - pg_error_badrequest( - "You did not specify a page to show."); - return; - } - manpath = mandoc_strndup(fullpath, file - fullpath); - file++; - - if ( ! validate_manpath(req, manpath)) { - pg_error_badrequest( - "You specified an invalid manpath."); - free(manpath); - return; - } - - /* - * Begin by chdir()ing into the manpath. - * This way we can pick up the database files, which are - * relative to the manpath root. - */ - - if (chdir(manpath) == -1) { - warn("chdir %s", manpath); - pg_error_internal(); - free(manpath); - return; - } - free(manpath); - - if ( ! validate_filename(file)) { - pg_error_badrequest( - "You specified an invalid manual file."); - return; - } - - resp_begin_html(200, NULL, file); - resp_searchform(req, FOCUS_NONE); - resp_show(req, file); - resp_end_html(); -} - -static void -pg_search(const struct req *req) -{ - struct mansearch search; - struct manpaths paths; - struct manpage *res; - char **argv; - char *query, *rp, *wp; - size_t ressz; - int argc; - - /* - * Begin by chdir()ing into the root of the manpath. - * This way we can pick up the database files, which are - * relative to the manpath root. - */ - - if (chdir(req->q.manpath) == -1) { - warn("chdir %s", req->q.manpath); - pg_error_internal(); - return; - } - - search.arch = req->q.arch; - search.sec = req->q.sec; - search.outkey = "Nd"; - search.argmode = req->q.equal ? ARG_NAME : ARG_EXPR; - search.firstmatch = 1; - - paths.sz = 1; - paths.paths = mandoc_malloc(sizeof(char *)); - paths.paths[0] = mandoc_strdup("."); - - /* - * Break apart at spaces with backslash-escaping. - */ - - argc = 0; - argv = NULL; - rp = query = mandoc_strdup(req->q.query); - for (;;) { - while (isspace((unsigned char)*rp)) - rp++; - if (*rp == '\0') - break; - argv = mandoc_reallocarray(argv, argc + 1, sizeof(char *)); - argv[argc++] = wp = rp; - for (;;) { - if (isspace((unsigned char)*rp)) { - *wp = '\0'; - rp++; - break; - } - if (rp[0] == '\\' && rp[1] != '\0') - rp++; - if (wp != rp) - *wp = *rp; - if (*rp == '\0') - break; - wp++; - rp++; - } - } - - res = NULL; - ressz = 0; - if (req->isquery && req->q.equal && argc == 1) - pg_redirect(req, argv[0]); - else if (mansearch(&search, &paths, argc, argv, &res, &ressz) == 0) - pg_noresult(req, "You entered an invalid query."); - else if (ressz == 0) - pg_noresult(req, "No results found."); - else - pg_searchres(req, res, ressz); - - free(query); - mansearch_free(res, ressz); - free(paths.paths[0]); - free(paths.paths); -} - -int -main(void) -{ - struct req req; - struct itimerval itimer; - const char *path; - const char *querystring; - int i; - -#if HAVE_PLEDGE - /* - * The "rpath" pledge could be revoked after mparse_readfd() - * if the file desciptor to "/footer.html" would be opened - * up front, but it's probably not worth the complication - * of the code it would cause: it would require scattering - * pledge() calls in multiple low-level resp_*() functions. - */ - - if (pledge("stdio rpath", NULL) == -1) { - warn("pledge"); - pg_error_internal(); - return EXIT_FAILURE; - } -#endif - - /* Poor man's ReDoS mitigation. */ - - itimer.it_value.tv_sec = 2; - itimer.it_value.tv_usec = 0; - itimer.it_interval.tv_sec = 2; - itimer.it_interval.tv_usec = 0; - if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) == -1) { - warn("setitimer"); - pg_error_internal(); - return EXIT_FAILURE; - } - - /* - * First we change directory into the MAN_DIR so that - * subsequent scanning for manpath directories is rooted - * relative to the same position. - */ - - if (chdir(MAN_DIR) == -1) { - warn("MAN_DIR: %s", MAN_DIR); - pg_error_internal(); - return EXIT_FAILURE; - } - - memset(&req, 0, sizeof(struct req)); - req.q.equal = 1; - parse_manpath_conf(&req); - - /* Parse the path info and the query string. */ - - if ((path = getenv("PATH_INFO")) == NULL) - path = ""; - else if (*path == '/') - path++; - - if (*path != '\0') { - parse_path_info(&req, path); - if (req.q.manpath == NULL || req.q.sec == NULL || - *req.q.query == '\0' || access(path, F_OK) == -1) - path = ""; - } else if ((querystring = getenv("QUERY_STRING")) != NULL) - parse_query_string(&req, querystring); - - /* Validate parsed data and add defaults. */ - - if (req.q.manpath == NULL) - req.q.manpath = mandoc_strdup(req.p[0]); - else if ( ! validate_manpath(&req, req.q.manpath)) { - pg_error_badrequest( - "You specified an invalid manpath."); - return EXIT_FAILURE; - } - - if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) { - pg_error_badrequest( - "You specified an invalid architecture."); - return EXIT_FAILURE; - } - - /* Dispatch to the three different pages. */ - - if ('\0' != *path) - pg_show(&req, path); - else if (NULL != req.q.query) - pg_search(&req); - else - pg_index(&req); - - free(req.q.manpath); - free(req.q.arch); - free(req.q.sec); - free(req.q.query); - for (i = 0; i < (int)req.psz; i++) - free(req.p[i]); - free(req.p); - return EXIT_SUCCESS; -} - -/* - * If PATH_INFO is not a file name, translate it to a query. - */ -static void -parse_path_info(struct req *req, const char *path) -{ - char *dir[4]; - int i; - - req->isquery = 0; - req->q.equal = 1; - req->q.manpath = mandoc_strdup(path); - req->q.arch = NULL; - - /* Mandatory manual page name. */ - if ((req->q.query = strrchr(req->q.manpath, '/')) == NULL) { - req->q.query = req->q.manpath; - req->q.manpath = NULL; - } else - *req->q.query++ = '\0'; - - /* Optional trailing section. */ - if ((req->q.sec = strrchr(req->q.query, '.')) != NULL) { - if(isdigit((unsigned char)req->q.sec[1])) { - *req->q.sec++ = '\0'; - req->q.sec = mandoc_strdup(req->q.sec); - } else - req->q.sec = NULL; - } - - /* Handle the case of name[.section] only. */ - if (req->q.manpath == NULL) - return; - req->q.query = mandoc_strdup(req->q.query); - - /* Split directory components. */ - dir[i = 0] = req->q.manpath; - while ((dir[i + 1] = strchr(dir[i], '/')) != NULL) { - if (++i == 3) { - pg_error_badrequest( - "You specified too many directory components."); - exit(EXIT_FAILURE); - } - *dir[i]++ = '\0'; - } - - /* Optional manpath. */ - if ((i = validate_manpath(req, req->q.manpath)) == 0) - req->q.manpath = NULL; - else if (dir[1] == NULL) - return; - - /* Optional section. */ - if (strncmp(dir[i], "man", 3) == 0) { - free(req->q.sec); - req->q.sec = mandoc_strdup(dir[i++] + 3); - } - if (dir[i] == NULL) { - if (req->q.manpath == NULL) - free(dir[0]); - return; - } - if (dir[i + 1] != NULL) { - pg_error_badrequest( - "You specified an invalid directory component."); - exit(EXIT_FAILURE); - } - - /* Optional architecture. */ - if (i) { - req->q.arch = mandoc_strdup(dir[i]); - if (req->q.manpath == NULL) - free(dir[0]); - } else - req->q.arch = dir[0]; -} - -/* - * Scan for indexable paths. - */ -static void -parse_manpath_conf(struct req *req) -{ - FILE *fp; - char *dp; - size_t dpsz; - ssize_t len; - - if ((fp = fopen("manpath.conf", "r")) == NULL) { - warn("%s/manpath.conf", MAN_DIR); - pg_error_internal(); - exit(EXIT_FAILURE); - } - - dp = NULL; - dpsz = 0; - - while ((len = getline(&dp, &dpsz, fp)) != -1) { - if (dp[len - 1] == '\n') - dp[--len] = '\0'; - req->p = mandoc_realloc(req->p, - (req->psz + 1) * sizeof(char *)); - if ( ! validate_urifrag(dp)) { - warnx("%s/manpath.conf contains " - "unsafe path \"%s\"", MAN_DIR, dp); - pg_error_internal(); - exit(EXIT_FAILURE); - } - if (strchr(dp, '/') != NULL) { - warnx("%s/manpath.conf contains " - "path with slash \"%s\"", MAN_DIR, dp); - pg_error_internal(); - exit(EXIT_FAILURE); - } - req->p[req->psz++] = dp; - dp = NULL; - dpsz = 0; - } - free(dp); - - if (req->p == NULL) { - warnx("%s/manpath.conf is empty", MAN_DIR); - pg_error_internal(); - exit(EXIT_FAILURE); - } -} Property changes on: head/contrib/mdocml/cgi.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/eqn_term.c =================================================================== --- head/contrib/mdocml/eqn_term.c (revision 338825) +++ head/contrib/mdocml/eqn_term.c (nonexistent) @@ -1,154 +0,0 @@ -/* $Id: eqn_term.c,v 1.13 2017/07/08 14:51:04 schwarze Exp $ */ -/* - * Copyright (c) 2011 Kristaps Dzonsons - * 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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include - -#include "mandoc.h" -#include "out.h" -#include "term.h" - -static const enum termfont fontmap[EQNFONT__MAX] = { - TERMFONT_NONE, /* EQNFONT_NONE */ - TERMFONT_NONE, /* EQNFONT_ROMAN */ - TERMFONT_BOLD, /* EQNFONT_BOLD */ - TERMFONT_BOLD, /* EQNFONT_FAT */ - TERMFONT_UNDER /* EQNFONT_ITALIC */ -}; - -static void eqn_box(struct termp *, const struct eqn_box *); - - -void -term_eqn(struct termp *p, const struct eqn_box *bp) -{ - - eqn_box(p, bp); - p->flags &= ~TERMP_NOSPACE; -} - -static void -eqn_box(struct termp *p, const struct eqn_box *bp) -{ - const struct eqn_box *child; - int delim; - - /* Delimiters around this box? */ - - if ((bp->type == EQN_LIST && bp->expectargs > 1) || - (bp->type == EQN_PILE && (bp->prev || bp->next)) || - (bp->parent != NULL && (bp->parent->pos == EQNPOS_SQRT || - /* Diacritic followed by ^ or _. */ - ((bp->top != NULL || bp->bottom != NULL) && - bp->parent->type == EQN_SUBEXPR && - bp->parent->pos != EQNPOS_OVER && bp->next != NULL) || - /* Nested over, sub, sup, from, to. */ - (bp->type == EQN_SUBEXPR && bp->pos != EQNPOS_SQRT && - ((bp->parent->type == EQN_LIST && bp->expectargs == 1) || - (bp->parent->type == EQN_SUBEXPR && - bp->pos != EQNPOS_SQRT)))))) { - if (bp->parent->type == EQN_SUBEXPR && bp->prev != NULL) - p->flags |= TERMP_NOSPACE; - term_word(p, bp->left != NULL ? bp->left : "("); - p->flags |= TERMP_NOSPACE; - delim = 1; - } else - delim = 0; - - /* Handle Fonts and text. */ - - if (bp->font != EQNFONT_NONE) - term_fontpush(p, fontmap[(int)bp->font]); - - if (bp->text != NULL) - term_word(p, bp->text); - - /* Special box types. */ - - if (bp->pos == EQNPOS_SQRT) { - term_word(p, "sqrt"); - if (bp->first != NULL) { - p->flags |= TERMP_NOSPACE; - eqn_box(p, bp->first); - } - } else if (bp->type == EQN_SUBEXPR) { - child = bp->first; - eqn_box(p, child); - p->flags |= TERMP_NOSPACE; - term_word(p, bp->pos == EQNPOS_OVER ? "/" : - (bp->pos == EQNPOS_SUP || - bp->pos == EQNPOS_TO) ? "^" : "_"); - p->flags |= TERMP_NOSPACE; - child = child->next; - if (child != NULL) { - eqn_box(p, child); - if (bp->pos == EQNPOS_FROMTO || - bp->pos == EQNPOS_SUBSUP) { - p->flags |= TERMP_NOSPACE; - term_word(p, "^"); - p->flags |= TERMP_NOSPACE; - child = child->next; - if (child != NULL) - eqn_box(p, child); - } - } - } else { - child = bp->first; - if (bp->type == EQN_MATRIX && - child != NULL && - child->type == EQN_LIST && - child->expectargs > 1) - child = child->first; - while (child != NULL) { - eqn_box(p, - bp->type == EQN_PILE && - child->type == EQN_LIST && - child->expectargs > 1 && - child->args == 1 ? - child->first : child); - child = child->next; - } - } - - /* Handle Fonts and diacritics. */ - - if (bp->font != EQNFONT_NONE) - term_fontpop(p); - if (bp->top != NULL) { - p->flags |= TERMP_NOSPACE; - term_word(p, bp->top); - } - if (bp->bottom != NULL) { - p->flags |= TERMP_NOSPACE; - term_word(p, "_"); - } - - /* Right delimiter after this box? */ - - if (delim) { - p->flags |= TERMP_NOSPACE; - term_word(p, bp->right != NULL ? bp->right : ")"); - if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL) - p->flags |= TERMP_NOSPACE; - } -} Property changes on: head/contrib/mdocml/eqn_term.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/libmdoc.h =================================================================== --- head/contrib/mdocml/libmdoc.h (revision 338825) +++ head/contrib/mdocml/libmdoc.h (nonexistent) @@ -1,87 +0,0 @@ -/* $Id: libmdoc.h,v 1.112 2017/05/30 16:22:03 schwarze Exp $ */ -/* - * Copyright (c) 2008, 2009, 2010, 2011 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. - */ - -#define MACRO_PROT_ARGS struct roff_man *mdoc, \ - enum roff_tok tok, \ - int line, \ - int ppos, \ - int *pos, \ - char *buf - -struct mdoc_macro { - void (*fp)(MACRO_PROT_ARGS); - int flags; -#define MDOC_CALLABLE (1 << 0) -#define MDOC_PARSED (1 << 1) -#define MDOC_EXPLICIT (1 << 2) -#define MDOC_PROLOGUE (1 << 3) -#define MDOC_IGNDELIM (1 << 4) -#define MDOC_JOIN (1 << 5) -}; - -enum margserr { - ARGS_ERROR, - ARGS_EOLN, /* end-of-line */ - ARGS_WORD, /* normal word */ - ARGS_PUNCT, /* series of punctuation */ - ARGS_PHRASE /* Bl -column phrase */ -}; - -/* - * A punctuation delimiter is opening, closing, or "middle mark" - * punctuation. These govern spacing. - * Opening punctuation (e.g., the opening parenthesis) suppresses the - * following space; closing punctuation (e.g., the closing parenthesis) - * suppresses the leading space; middle punctuation (e.g., the vertical - * bar) can do either. The middle punctuation delimiter bends the rules - * depending on usage. - */ -enum mdelim { - DELIM_NONE = 0, - DELIM_OPEN, - DELIM_MIDDLE, - DELIM_CLOSE, - DELIM_MAX -}; - -extern const struct mdoc_macro *const mdoc_macros; - - -void mdoc_macro(MACRO_PROT_ARGS); -void mdoc_elem_alloc(struct roff_man *, int, int, - enum roff_tok, struct mdoc_arg *); -struct roff_node *mdoc_block_alloc(struct roff_man *, int, int, - enum roff_tok, struct mdoc_arg *); -void mdoc_tail_alloc(struct roff_man *, int, int, - enum roff_tok); -struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int, - enum roff_tok, struct roff_node *); -void mdoc_node_relink(struct roff_man *, struct roff_node *); -void mdoc_node_validate(struct roff_man *); -void mdoc_state(struct roff_man *, struct roff_node *); -void mdoc_state_reset(struct roff_man *); -const char *mdoc_a2arch(const char *); -const char *mdoc_a2att(const char *); -const char *mdoc_a2lib(const char *); -enum roff_sec mdoc_a2sec(const char *); -const char *mdoc_a2st(const char *); -void mdoc_argv(struct roff_man *, int, enum roff_tok, - struct mdoc_arg **, int *, char *); -enum margserr mdoc_args(struct roff_man *, int, - int *, char *, enum roff_tok, char **); -enum mdelim mdoc_isdelim(const char *); Property changes on: head/contrib/mdocml/libmdoc.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/test-EFTYPE.c =================================================================== --- head/contrib/mdocml/test-EFTYPE.c (revision 338825) +++ head/contrib/mdocml/test-EFTYPE.c (nonexistent) @@ -1,7 +0,0 @@ -#include - -int -main(void) -{ - return !EFTYPE; -} Property changes on: head/contrib/mdocml/test-EFTYPE.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/man.conf.5 =================================================================== --- head/contrib/mdocml/man.conf.5 (revision 338825) +++ head/contrib/mdocml/man.conf.5 (nonexistent) @@ -1,131 +0,0 @@ -.\" $Id: man.conf.5,v 1.4 2016/12/28 22:52:17 schwarze Exp $ -.\" -.\" Copyright (c) 2015 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: December 28 2016 $ -.Dt MAN.CONF 5 -.Os -.Sh NAME -.Nm man.conf -.Nd configuration file for man -.Sh DESCRIPTION -This is the configuration file -for the -.Xr man 1 , -.Xr apropos 1 , -and -.Xr makewhatis 8 -utilities. -Its presence, and all directives, are optional. -.Pp -This file is an ASCII text file. -Leading whitespace on lines, lines starting with -.Sq # , -and blank lines are ignored. -Words are separated by whitespace. -The first word on each line is the name of a configuration directive. -.Pp -The following directives are supported: -.Bl -tag -width Ds -.It Ic manpath Ar path -Override the default search -.Ar path -for -.Xr man 1 , -.Xr apropos 1 , -and -.Xr makewhatis 8 . -It can be used multiple times to specify multiple paths, -with the order determining the manual page search order. -.Pp -Each path is a tree containing subdirectories -whose names consist of the strings -.Sq man -and/or -.Sq cat -followed by the names of sections, usually single digits. -The former are supposed to contain unformatted manual pages in -.Xr mdoc 7 -and/or -.Xr man 7 -format; file names should end with the name of the section -preceded by a dot. -The latter should contain preformatted manual pages; -file names should end with -.Ql .0 . -.Pp -Creating a -.Xr mandoc.db 5 -database with -.Xr makewhatis 8 -in each directory configured with -.Ic manpath -is recommended and necessary for -.Xr apropos 1 -to work, but not strictly required for -.Xr man 1 . -.It Ic output Ar option Op Ar value -Configure the default value of an output option. -These directives are overridden by the -.Fl O -command line options of the same names. -For details, see the -.Xr mandoc 1 -manual. -.Pp -.Bl -column fragment integer "ascii, utf8" -compact -.It Ar option Ta Ar value Ta used by Fl T Ta purpose -.It Ta Ta Ta -.It Ic fragment Ta none Ta Cm html Ta print only body -.It Ic includes Ta string Ta Cm html Ta path to header files -.It Ic indent Ta integer Ta Cm ascii , utf8 Ta left margin -.It Ic man Ta string Ta Cm html Ta path for \&Xr links -.It Ic paper Ta string Ta Cm ps , pdf Ta paper size -.It Ic style Ta string Ta Cm html Ta CSS file -.It Ic width Ta integer Ta Cm ascii , utf8 Ta right margin -.El -.It Ic _whatdb Ar path Ns Cm /whatis.db -This directive provides the same functionality as -.Ic manpath , -but using a historic and misleading syntax. -It is kept for backward compatibility for now, -but will eventually be removed. -.El -.Sh FILES -.Pa /etc/man.conf -.Sh EXAMPLES -The following configuration file reproduces the defaults: -installing it is equivalent to not having a -.Nm -file at all. -.Bd -literal -offset indent -manpath /usr/share/man -manpath /usr/X11R6/man -manpath /usr/local/man -.Ed -.Sh SEE ALSO -.Xr apropos 1 , -.Xr man 1 , -.Xr makewhatis 8 -.Sh HISTORY -A relatively complicated -.Nm -file format first appeared in -.Bx 4.3 Reno . -For -.Ox 5.8 , -it was redesigned from scratch, aiming for simplicity. -.Sh AUTHORS -.An Ingo Schwarze Aq Mt schwarze@openbsd.org Property changes on: head/contrib/mdocml/man.conf.5 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc_headers.3 =================================================================== --- head/contrib/mdocml/mandoc_headers.3 (revision 338825) +++ head/contrib/mdocml/mandoc_headers.3 (nonexistent) @@ -1,570 +0,0 @@ -.Dd $Mdocdate: July 8 2017 $ -.Dt MANDOC_HEADERS 3 -.Os -.Sh NAME -.Nm mandoc_headers -.Nd ordering of mandoc include files -.Sh DESCRIPTION -To support a cleaner coding style, the mandoc header files do not -contain any include directives and do not guard against multiple -inclusion. -The application developer has to make sure that the headers are -included in a proper order, and that no header is included more -than once. -.Pp -The headers and functions form three major groups: -.Sx Parser interface , -.Sx Parser internals , -and -.Sx Formatter interface . -.Pp -Various rules are given below prohibiting the inclusion of certain -combinations of headers into the same file. -The intention is to keep the following functional components -separate from each other: -.Pp -.Bl -dash -offset indent -compact -.It -.Xr mdoc 7 -parser -.It -.Xr man 7 -parser -.It -.Xr roff 7 -parser -.It -.Xr tbl 7 -parser -.It -.Xr eqn 7 -parser -.It -terminal formatters -.It -HTML formatters -.It -search tools -.El -.Pp -Note that mere usage of an opaque struct type does -.Em not -require inclusion of the header where that type is defined. -.Ss Parser interface -Each of the following headers can be included without including -any other mandoc header. -These headers should be included before any other mandoc headers. -.Bl -tag -width Ds -.It Qq Pa mandoc_aux.h -Requires -.In sys/types.h -for -.Vt size_t . -.Pp -Provides the utility functions documented in -.Xr mandoc_malloc 3 . -.It Qq Pa mandoc_ohash.h -Requires -.In stddef.h -for -.Vt ptrdiff_t -and -.In stdint.h -for -.Vt uint32_t . -.Pp -Includes -.In ohash.h -and provides -.Fn mandoc_ohash_init . -.It Qq Pa mandoc.h -Requires -.In sys/types.h -for -.Vt size_t . -.Pp -Provides -.Vt enum mandoc_esc , -.Vt enum mandocerr , -.Vt enum mandoclevel , -.Vt enum mandoc_os , -.Vt enum tbl_cellt , -.Vt enum tbl_datt , -.Vt enum tbl_spant , -.Vt enum eqn_boxt , -.Vt enum eqn_fontt , -.Vt enum eqn_pilet , -.Vt enum eqn_post , -.Vt struct tbl_opts , -.Vt struct tbl_cell , -.Vt struct tbl_row , -.Vt struct tbl_dat , -.Vt struct tbl_span , -.Vt struct eqn_box , -the function prototype typedef -.Fn mandocmsg , -the function -.Xr mandoc_escape 3 , -the functions described in -.Xr mchars_alloc 3 , -and the functions -.Fn mparse_* -described in -.Xr mandoc 3 . -.Pp -Uses the opaque type -.Vt struct mparse -from -.Pa read.c -for function prototypes. -Uses the type -.Vt struct roff_man -from -.Pa roff.h -as an opaque type for function prototypes. -.It Qq Pa mandoc_xr.h -Provides -.Vt struct mandoc_xr -and the functions -.Fn mandoc_xr_reset , -.Fn mandoc_xr_add , -.Fn mandoc_xr_get , -and -.Fn mandoc_xr_free . -.It Qq Pa roff.h -Requires -.Qq Pa mandoc_ohash.h -for -.Vt struct ohash -and -.Qq Pa mandoc.h -for -.Vt enum mandoc_os . -.Pp -Provides -.Vt enum mdoc_endbody , -.Vt enum roff_macroset , -.Vt enum roff_next , -.Vt enum roff_sec , -.Vt enum roff_tok , -.Vt enum roff_type , -.Vt struct roff_man , -.Vt struct roff_meta , -.Vt struct roff_node , -the constant array -.Va roff_name -and the functions -.Fn deroff , -.Fn roffhash_alloc , -.Fn roffhash_find , -.Fn roffhash_free , -and -.Fn roff_validate . -.Pp -Uses pointers to the types -.Vt struct mdoc_arg -and -.Vt union mdoc_data -from -.Pa mdoc.h -as opaque struct members. -.El -.Pp -The following two require -.Qq Pa roff.h -but no other mandoc headers. -Afterwards, any other mandoc headers can be included as needed. -.Bl -tag -width Ds -.It Qq Pa mdoc.h -Requires -.In sys/types.h -for -.Vt size_t . -.Pp -Provides -.Vt enum mdocargt , -.Vt enum mdoc_auth , -.Vt enum mdoc_disp , -.Vt enum mdoc_font , -.Vt enum mdoc_list , -.Vt struct mdoc_argv , -.Vt struct mdoc_arg , -.Vt struct mdoc_an , -.Vt struct mdoc_bd , -.Vt struct mdoc_bf , -.Vt struct mdoc_bl , -.Vt struct mdoc_rs , -.Vt union mdoc_data , -and the functions -.Fn mdoc_* -described in -.Xr mandoc 3 . -.Pp -Uses the type -.Vt struct roff_man -from -.Pa roff.h -as an opaque type for function prototypes. -.Pp -When this header is included, the same file should not include -.Pa libman.h -or -.Pa libroff.h . -.It Qq Pa man.h -Provides the functions -.Fn man_* -described in -.Xr mandoc 3 . -.Pp -Uses the opaque type -.Vt struct mparse -from -.Pa read.c -for function prototypes. -Uses the type -.Vt struct roff_man -from -.Pa roff.h -as an opaque type for function prototypes. -.Pp -When this header is included, the same file should not include -.Pa libmdoc.h -or -.Pa libroff.h . -.El -.Ss Parser internals -The following headers require inclusion of a parser interface header -before they can be included. -All parser interface headers should precede all parser internal headers. -When any parser internal headers are included, the same file should -not include any formatter headers. -.Bl -tag -width Ds -.It Qq Pa libmandoc.h -Requires -.In sys/types.h -for -.Vt size_t -and -.Qq Pa mandoc.h -for -.Vt enum mandocerr . -.Pp -Provides -.Vt enum rofferr , -.Vt struct buf , -utility functions needed by multiple parsers, -and the top-level functions to call the parsers. -.Pp -Uses the opaque types -.Vt struct mparse -from -.Pa read.c -and -.Vt struct roff -from -.Pa roff.c -for function prototypes. -Uses the type -.Vt struct roff_man -from -.Pa roff.h -as an opaque type for function prototypes. -.It Qq Pa roff_int.h -Requires -.Qq Pa roff.h -for -.Vt enum roff_type . -.Pp -Provides functions named -.Fn roff_* -to handle roff nodes and the two special functions -.Fn man_breakscope -and -.Fn mdoc_argv_free -because the latter two are needed by -.Qq Pa roff.c . -.Pp -Uses the types -.Vt struct roff_man -and -.Vt struct roff_node -from -.Pa roff.h -and -.Vt struct mdoc_arg -from -.Pa mdoc.h -as opaque types for function prototypes. -.It Qq Pa libmdoc.h -Requires -.Qq Pa roff.h -for -.Vt enum roff_tok -and -.Qq Pa mdoc.h -for -.Vt enum mdoc_* -and -.Vt struct mdoc_* . -.Pp -Provides -.Vt enum margserr , -.Vt enum mdelim , -.Vt struct mdoc_macro , -and many functions internal to the -.Xr mdoc 7 -parser. -.Pp -Uses the opaque type -.Vt struct mparse -from -.Pa read.c . -Uses the types -.Vt struct roff_man -and -.Vt struct roff_node -from -.Pa roff.h -as opaque types for function prototypes. -.Pp -When this header is included, the same file should not include -.Pa man.h , -.Pa libman.h , -or -.Pa libroff.h . -.It Qq Pa libman.h -Requires -.Qq Pa roff.h -for -.Vt enum roff_tok . -.Pp -Provides -.Vt struct man_macro -and some functions internal to the -.Xr man 7 -parser. -.Pp -Uses the types -.Vt struct roff_man -and -.Vt struct roff_node -from -.Pa roff.h -as opaque types for function prototypes. -.Pp -When this header is included, the same file should not include -.Pa mdoc.h , -.Pa libmdoc.h , -or -.Pa libroff.h . -.It Qq Pa libroff.h -Requires -.In sys/types.h -for -.Vt size_t -and -.Qq Pa mandoc.h -for -.Vt struct tbl_* -and -.Vt struct eqn_box . -.Pp -Provides -.Vt enum tbl_part , -.Vt struct tbl_node , -.Vt struct eqn_def , -.Vt struct eqn_node , -and many functions internal to the -.Xr tbl 7 -and -.Xr eqn 7 -parsers. -.Pp -Uses the opaque type -.Vt struct mparse -from -.Pa read.c . -.Pp -When this header is included, the same file should not include -.Pa man.h , -.Pa mdoc.h , -.Pa libman.h , -or -.Pa libmdoc.h . -.El -.Ss Formatter interface -These headers should be included after any parser interface headers. -No parser internal headers should be included by the same file. -.Bl -tag -width Ds -.It Qq Pa out.h -Requires -.In sys/types.h -for -.Vt size_t . -.Pp -Provides -.Vt enum roffscale , -.Vt struct roffcol , -.Vt struct roffsu , -.Vt struct rofftbl , -.Fn a2roffsu , -and -.Fn tblcalc . -.Pp -Uses -.Vt struct tbl_span -from -.Pa mandoc.h -as an opaque type for function prototypes. -.Pp -When this header is included, the same file should not include -.Pa mansearch.h . -.It Qq Pa term.h -Requires -.In sys/types.h -for -.Vt size_t -and -.Qq Pa out.h -for -.Vt struct roffsu -and -.Vt struct rofftbl . -.Pp -Provides -.Vt enum termenc , -.Vt enum termfont , -.Vt enum termtype , -.Vt struct termp_tbl , -.Vt struct termp , -.Fn roff_term_pre , -and many terminal formatting functions. -.Pp -Uses the opaque type -.Vt struct termp_ps -from -.Pa term_ps.c . -Uses -.Vt struct tbl_span -and -.Vt struct eqn_box -from -.Pa mandoc.h -and -.Vt struct roff_meta -and -.Vt struct roff_node -from -.Pa roff.h -as opaque types for function prototypes. -.Pp -When this header is included, the same file should not include -.Pa html.h -or -.Pa mansearch.h . -.It Qq Pa html.h -Requires -.In sys/types.h -for -.Vt size_t -and -.Qq Pa out.h -for -.Vt struct roffsu -and -.Vt struct rofftbl . -.Pp -Provides -.Vt enum htmltag , -.Vt enum htmlattr , -.Vt enum htmlfont , -.Vt struct tag , -.Vt struct tagq , -.Vt struct htmlpair , -.Vt struct html , -.Fn roff_html_pre , -and many HTML formatting functions. -.Pp -Uses -.Vt struct tbl_span -and -.Vt struct eqn_box -from -.Pa mandoc.h -and -.Vt struct roff_node -from -.Pa roff.h -as opaque types for function prototypes. -.Pp -When this header is included, the same file should not include -.Pa term.h -or -.Pa mansearch.h . -.It Qq Pa tag.h -Requires -.In sys/types.h -for -.Vt size_t . -.Pp -Provides an interface to generate -.Xr ctags 1 -files for the -.Ic :t -functionality mentioned in -.Xr man 1 . -.It Qq Pa main.h -Provides the top level steering functions for all formatters. -.Pp -Uses the type -.Vt struct roff_man -from -.Pa roff.h -as an opaque type for function prototypes. -.It Qq Pa manconf.h -Requires -.In sys/types.h -for -.Vt size_t . -.Pp -Provides -.Vt struct manconf , -.Vt struct manpaths , -.Vt struct manoutput , -and the functions -.Fn manconf_parse , -.Fn manconf_output , -.Fn manconf_free , -and -.Fn manpath_base . -.It Qq Pa mansearch.h -Requires -.In sys/types.h -for -.Vt size_t -and -.In stdint.h -for -.Vt uint64_t . -.Pp -Provides -.Vt enum argmode , -.Vt struct manpage , -.Vt struct mansearch , -and the functions -.Fn mansearch -and -.Fn mansearch_free . -.Pp -Uses -.Vt struct manpaths -from -.Pa manconf.h -as an opaque type for function prototypes. -.Pp -When this header is included, the same file should not include -.Pa out.h , -.Pa term.h , -or -.Pa html.h . -.El Property changes on: head/contrib/mdocml/mandoc_headers.3 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/man_term.c =================================================================== --- head/contrib/mdocml/man_term.c (revision 338825) +++ head/contrib/mdocml/man_term.c (nonexistent) @@ -1,1101 +0,0 @@ -/* $Id: man_term.c,v 1.209 2017/07/31 15:19:06 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 { - 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; -} - -/* - * 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_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_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_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_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 >= MAN_TH && - 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 >= MAN_TH && - 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_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') { - 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); -} Property changes on: head/contrib/mdocml/man_term.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/compat_progname.c =================================================================== --- head/contrib/mdocml/compat_progname.c (revision 338825) +++ head/contrib/mdocml/compat_progname.c (nonexistent) @@ -1,42 +0,0 @@ -#include "config.h" - -#if HAVE_PROGNAME - -int dummy; - -#else - -/* $Id: compat_progname.c,v 1.1 2015/11/06 16:30:33 schwarze Exp $ */ -/* - * Copyright (c) 2015 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. - */ - -static const char *progname; - -void -setprogname(const char *name) -{ - - progname = name; -} - -const char * -getprogname(void) -{ - - return progname; -} - -#endif Property changes on: head/contrib/mdocml/compat_progname.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/gmdiff =================================================================== --- head/contrib/mdocml/gmdiff (revision 338825) +++ head/contrib/mdocml/gmdiff (nonexistent) @@ -1,54 +0,0 @@ -#!/bin/sh -# Copyright (c) 2013, 2014 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. - -if [ `id -u` -eq 0 ]; then - echo "$0: do not run me as root" - exit 1 -fi - -if [ $# -eq 0 ]; then - echo "usage: $0 [-h] manual_source_file ..." - exit 1 -fi - -if [ "X$1" = "X-h" ]; then - shift - export PATH="/usr/local/heirloom-doctools/bin:$PATH" - EQN="neqn" - ROFF="nroff" - MOPT="-Omdoc $MOPT" -elif [ "X$1" = "X-u" ]; then - shift - ROFF="groff -ket -ww -Tutf8 -P -c" - MOPT="-Werror -Tutf8 $MOPT" -else - ROFF="groff -et -ww -Tascii -P -c" - MOPT="-Werror -Tascii $MOPT" -fi - -while [ -n "$1" ]; do - file=$1 - shift - echo " ========== $file ========== " - $ROFF -mandoc $file 2> /tmp/roff.err > /tmp/roff.out - ${MANDOC:=mandoc} -Ios=OpenBSD $MOPT $file \ - 2> /tmp/mandoc.err > /tmp/mandoc.out - for i in roff mandoc; do - [ -s /tmp/$i.err ] && echo "$i errors:" && cat /tmp/$i.err - done - diff -au /tmp/roff.out /tmp/mandoc.out 2>&1 -done - -exit 0 Index: head/contrib/mdocml/tag.c =================================================================== --- head/contrib/mdocml/tag.c (revision 338825) +++ head/contrib/mdocml/tag.c (nonexistent) @@ -1,249 +0,0 @@ -/* $Id: tag.c,v 1.18 2017/02/17 14:31:52 schwarze Exp $ */ -/* - * Copyright (c) 2015, 2016 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. - */ -#include "config.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "mandoc_aux.h" -#include "mandoc_ohash.h" -#include "tag.h" - -struct tag_entry { - size_t *lines; - size_t maxlines; - size_t nlines; - int prio; - char s[]; -}; - -static void tag_signal(int) __attribute__((__noreturn__)); - -static struct ohash tag_data; -static struct tag_files tag_files; - - -/* - * Prepare for using a pager. - * Not all pagers are capable of using a tag file, - * but for simplicity, create it anyway. - */ -struct tag_files * -tag_init(void) -{ - struct sigaction sa; - int ofd; - - ofd = -1; - tag_files.tfd = -1; - tag_files.tcpgid = -1; - - /* Clean up when dying from a signal. */ - - memset(&sa, 0, sizeof(sa)); - sigfillset(&sa.sa_mask); - sa.sa_handler = tag_signal; - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - - /* - * POSIX requires that a process calling tcsetpgrp(3) - * from the background gets a SIGTTOU signal. - * In that case, do not stop. - */ - - sa.sa_handler = SIG_IGN; - sigaction(SIGTTOU, &sa, NULL); - - /* Save the original standard output for use by the pager. */ - - if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) - goto fail; - - /* Create both temporary output files. */ - - (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX", - sizeof(tag_files.ofn)); - (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX", - sizeof(tag_files.tfn)); - if ((ofd = mkstemp(tag_files.ofn)) == -1) - goto fail; - if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) - goto fail; - if (dup2(ofd, STDOUT_FILENO) == -1) - goto fail; - close(ofd); - - /* - * Set up the ohash table to collect output line numbers - * where various marked-up terms are documented. - */ - - mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s)); - return &tag_files; - -fail: - tag_unlink(); - if (ofd != -1) - close(ofd); - if (tag_files.ofd != -1) - close(tag_files.ofd); - if (tag_files.tfd != -1) - close(tag_files.tfd); - *tag_files.ofn = '\0'; - *tag_files.tfn = '\0'; - tag_files.ofd = -1; - tag_files.tfd = -1; - return NULL; -} - -/* - * Set the line number where a term is defined, - * unless it is already defined at a higher priority. - */ -void -tag_put(const char *s, int prio, size_t line) -{ - struct tag_entry *entry; - size_t len; - unsigned int slot; - - /* Sanity checks. */ - - if (tag_files.tfd <= 0) - return; - if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e')) - s += 2; - if (*s == '\0' || strchr(s, ' ') != NULL) - return; - - slot = ohash_qlookup(&tag_data, s); - entry = ohash_find(&tag_data, slot); - - if (entry == NULL) { - - /* Build a new entry. */ - - len = strlen(s) + 1; - entry = mandoc_malloc(sizeof(*entry) + len); - memcpy(entry->s, s, len); - entry->lines = NULL; - entry->maxlines = entry->nlines = 0; - ohash_insert(&tag_data, slot, entry); - - } else { - - /* Handle priority 0 entries. */ - - if (prio == 0) { - if (entry->prio == 0) - entry->prio = -1; - return; - } - - /* A better entry is already present, ignore the new one. */ - - if (entry->prio > 0 && entry->prio < prio) - return; - - /* The existing entry is worse, clear it. */ - - if (entry->prio < 1 || entry->prio > prio) - entry->nlines = 0; - } - - /* Remember the new line. */ - - if (entry->maxlines == entry->nlines) { - entry->maxlines += 4; - entry->lines = mandoc_reallocarray(entry->lines, - entry->maxlines, sizeof(*entry->lines)); - } - entry->lines[entry->nlines++] = line; - entry->prio = prio; -} - -/* - * Write out the tags file using the previously collected - * information and clear the ohash table while going along. - */ -void -tag_write(void) -{ - FILE *stream; - struct tag_entry *entry; - size_t i; - unsigned int slot; - - if (tag_files.tfd <= 0) - return; - stream = fdopen(tag_files.tfd, "w"); - entry = ohash_first(&tag_data, &slot); - while (entry != NULL) { - if (stream != NULL && entry->prio >= 0) - for (i = 0; i < entry->nlines; i++) - fprintf(stream, "%s %s %zu\n", - entry->s, tag_files.ofn, entry->lines[i]); - free(entry->lines); - free(entry); - entry = ohash_next(&tag_data, &slot); - } - ohash_delete(&tag_data); - if (stream != NULL) - fclose(stream); -} - -void -tag_unlink(void) -{ - pid_t tc_pgid; - - if (tag_files.tcpgid != -1) { - tc_pgid = tcgetpgrp(tag_files.ofd); - if (tc_pgid == tag_files.pager_pid || - tc_pgid == getpgid(0) || - getpgid(tc_pgid) == -1) - (void)tcsetpgrp(tag_files.ofd, tag_files.tcpgid); - } - if (*tag_files.ofn != '\0') - unlink(tag_files.ofn); - if (*tag_files.tfn != '\0') - unlink(tag_files.tfn); -} - -static void -tag_signal(int signum) -{ - struct sigaction sa; - - tag_unlink(); - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_handler = SIG_DFL; - sigaction(signum, &sa, NULL); - kill(getpid(), signum); - /* NOTREACHED */ - _exit(1); -} Property changes on: head/contrib/mdocml/tag.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/manconf.h =================================================================== --- head/contrib/mdocml/manconf.h (revision 338825) +++ head/contrib/mdocml/manconf.h (nonexistent) @@ -1,50 +0,0 @@ -/* $Id: manconf.h,v 1.5 2017/07/01 09:47:30 schwarze Exp $ */ -/* - * 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 *); Property changes on: head/contrib/mdocml/manconf.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc.db.5 =================================================================== --- head/contrib/mdocml/mandoc.db.5 (revision 338825) +++ head/contrib/mdocml/mandoc.db.5 (nonexistent) @@ -1,228 +0,0 @@ -.\" $Id: mandoc.db.5,v 1.5 2016/08/01 12:27:15 schwarze Exp $ -.\" -.\" Copyright (c) 2014, 2016 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: August 1 2016 $ -.Dt MANDOC.DB 5 -.Os -.Sh NAME -.Nm mandoc.db -.Nd manual page database -.Sh DESCRIPTION -The -.Nm -file format is used to store information about installed manual -pages to facilitate semantic searching for manuals. -Each manual page tree contains its own -.Nm -file; see -.Sx FILES -for examples. -.Pp -Such database files are generated by -.Xr makewhatis 8 -and used by -.Xr man 1 , -.Xr apropos 1 -and -.Xr whatis 1 . -.Pp -The file format uses three datatypes: -.Pp -.Bl -dash -compact -offset 2n -width 1n -.It -32-bit signed integer numbers in big endian (network) byte ordering -.It -NUL-terminated strings -.It -lists of NUL-terminated strings, terminated by a second NUL character -.El -.Pp -Numbers are aligned to four-byte boundaries; where they follow -strings or lists of strings, padding with additional NUL characters -occurs. -Some, but not all, numbers point to positions in the file. -These pointers are measured in bytes, and the first byte of the -file is considered to be byte 0. -.Pp -Each file consists of: -.Pp -.Bl -dash -compact -offset 2n -width 1n -.It -One magic number, 0x3a7d0cdb. -.It -One version number, currently 1. -.It -One pointer to the macros table. -.It -One pointer to the final magic number. -.It -The pages table (variable length). -.It -The macros table (variable length). -.It -The magic number once again, 0x3a7d0cdb. -.El -.Pp -The pages table contains one entry for each physical manual page -file, no matter how many hard and soft links it may have in the -file system. -The pages table consists of: -.Pp -.Bl -dash -compact -offset 2n -width 1n -.It -The number of pages in the database. -.It -For each page: -.Bl -dash -compact -offset 2n -width 1n -.It -One pointer to the list of names. -.It -One pointer to the list of sections. -.It -One pointer to the list of architectures -or 0 if the page is machine-independent. -.It -One pointer to the one-line description string. -.It -One pointer to the list of filenames. -.El -.It -For each page, the list of names. -Each name is preceded by a single byte indicating the sources of the name. -The meaning of the bits is: -.Bl -dash -compact -offset 2n -width 1n -.It -0x10: The name appears in a filename. -.It -0x08: The name appears in a header line, i.e. in a .Dt or .TH macro. -.It -0x04: The name is the first one in the title line, i.e. it appears -in the first .Nm macro in the NAME section. -.It -0x02: The name appears in any .Nm macro in the NAME section. -.It -0x01: The name appears in an .Nm block in the SYNOPSIS section. -.El -.It -For each page, the list of sections. -Each section is given as a string, not as a number. -.It -For each architecture-dependent page, the list of architectures. -.It -For each page, the one-line description string taken from the .Nd macro. -.It -For each page, the list of filenames relative to the root of the -respective manpath. -This list includes hard links, soft links, and links simulated -with .so -.Xr roff 7 -requests. -The first filename is preceded by a single byte -having the following significance: -.Bl -dash -compact -offset 2n -width 1n -.It -.Dv FORM_SRC No = 0x01 : -The file format is -.Xr mdoc 7 -or -.Xr man 7 . -.It -.Dv FORM_CAT No = 0x02 : -The manual page is preformatted. -.El -.It -Zero to three NUL bytes for padding. -.El -.Pp -The macros table consists of: -.Pp -.Bl -dash -compact -offset 2n -width 1n -.It -The number of different macro keys, currently 36. -The ordering of macros is defined in -.In mansearch.h -and the significance of the macro keys is documented in -.Xr apropos 1 . -.It -For each macro key, one pointer to the respective macro table. -.It -For each macro key, the macro table (variable length). -.El -.Pp -Each macro table consists of: -.Pp -.Bl -dash -compact -offset 2n -width 1n -.It -The number of entries in the table. -.It -For each entry: -.Bl -dash -compact -offset 2n -width 1n -.It -One pointer to the value of the macro key. -Each value is a string of text taken from some macro invocation. -.It -One pointer to the list of pages. -.El -.It -For each entry, the value of the macro key. -.It -Zero to three NUL bytes for padding. -.It -For each entry, one or more pointers to pages in the pages table, -pointing to the pointer to the list of names, -followed by the number 0. -.El -.Sh FILES -.Bl -tag -width /usr/share/man/mandoc.db -compact -.It Pa /usr/share/man/mandoc.db -The manual page database for the base system. -.It Pa /usr/X11R6/man/mandoc.db -The same for the -.Xr X 7 -Window System. -.It Pa /usr/local/man/mandoc.db -The same for -.Xr packages 7 . -.El -.Pp -A program to dump -.Nm -files in a human-readable format suitable for -.Xr diff 1 -is provided in the directory -.Pa /usr/src/regress/usr.bin/mandoc/db/dbm_dump/ . -.Sh SEE ALSO -.Xr apropos 1 , -.Xr man 1 , -.Xr whatis 1 , -.Xr makewhatis 8 -.Sh HISTORY -A manual page database -.Pa /usr/lib/whatis -first appeared in -.Bx 2 . -The present format first appeared in -.Ox 6.1 . -.Sh AUTHORS -.An -nosplit -The original version of -.Xr makewhatis 8 -was written by -.An Bill Joy -in 1979. -The present database format was designed by -.An Ingo Schwarze Aq Mt schwarze@openbsd.org -in 2016. Property changes on: head/contrib/mdocml/mandoc.db.5 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tag.h =================================================================== --- head/contrib/mdocml/tag.h (revision 338825) +++ head/contrib/mdocml/tag.h (nonexistent) @@ -1,31 +0,0 @@ -/* $Id: tag.h,v 1.7 2015/11/20 21:59:54 schwarze Exp $ */ -/* - * Copyright (c) 2015 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. - */ - -struct tag_files { - char ofn[20]; - char tfn[20]; - int ofd; - int tfd; - pid_t tcpgid; - pid_t pager_pid; -}; - - -struct tag_files *tag_init(void); -void tag_put(const char *, int, size_t); -void tag_write(void); -void tag_unlink(void); Property changes on: head/contrib/mdocml/tag.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/roff_term.c =================================================================== --- head/contrib/mdocml/roff_term.c (revision 338825) +++ head/contrib/mdocml/roff_term.c (nonexistent) @@ -1,248 +0,0 @@ -/* $Id: roff_term.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */ -/* - * Copyright (c) 2010, 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. - */ -#include - -#include -#include - -#include "mandoc.h" -#include "roff.h" -#include "out.h" -#include "term.h" - -#define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n - -typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS); - -static void roff_term_pre_br(ROFF_TERM_ARGS); -static void roff_term_pre_ce(ROFF_TERM_ARGS); -static void roff_term_pre_ft(ROFF_TERM_ARGS); -static void roff_term_pre_ll(ROFF_TERM_ARGS); -static void roff_term_pre_mc(ROFF_TERM_ARGS); -static void roff_term_pre_po(ROFF_TERM_ARGS); -static void roff_term_pre_sp(ROFF_TERM_ARGS); -static void roff_term_pre_ta(ROFF_TERM_ARGS); -static void roff_term_pre_ti(ROFF_TERM_ARGS); - -static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = { - roff_term_pre_br, /* br */ - roff_term_pre_ce, /* ce */ - roff_term_pre_ft, /* ft */ - roff_term_pre_ll, /* ll */ - roff_term_pre_mc, /* mc */ - roff_term_pre_po, /* po */ - roff_term_pre_ce, /* rj */ - roff_term_pre_sp, /* sp */ - roff_term_pre_ta, /* ta */ - roff_term_pre_ti, /* ti */ -}; - - -void -roff_term_pre(struct termp *p, const struct roff_node *n) -{ - assert(n->tok < ROFF_MAX); - (*roff_term_pre_acts[n->tok])(p, n); -} - -static void -roff_term_pre_br(ROFF_TERM_ARGS) -{ - term_newln(p); - if (p->flags & TERMP_BRIND) { - p->tcol->offset = p->tcol->rmargin; - p->tcol->rmargin = p->maxrmargin; - p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); - } -} - -static void -roff_term_pre_ce(ROFF_TERM_ARGS) -{ - const struct roff_node *nc1, *nc2; - size_t len, lm; - - roff_term_pre_br(p, n); - lm = p->tcol->offset; - nc1 = n->child->next; - while (nc1 != NULL) { - nc2 = nc1; - len = 0; - do { - if (nc2->type == ROFFT_TEXT) { - if (len) - len++; - len += term_strlen(p, nc2->string); - } - nc2 = nc2->next; - } while (nc2 != NULL && (nc2->type != ROFFT_TEXT || - (nc2->flags & NODE_LINE) == 0)); - p->tcol->offset = len >= p->tcol->rmargin ? 0 : - lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len : - n->tok == ROFF_rj ? p->tcol->rmargin - len : - (lm + p->tcol->rmargin - len) / 2; - while (nc1 != nc2) { - if (nc1->type == ROFFT_TEXT) - term_word(p, nc1->string); - else - roff_term_pre(p, nc1); - nc1 = nc1->next; - } - p->flags |= TERMP_NOSPACE; - term_flushln(p); - } - p->tcol->offset = lm; -} - -static void -roff_term_pre_ft(ROFF_TERM_ARGS) -{ - switch (*n->child->string) { - case '4': - case '3': - case 'B': - term_fontrepl(p, TERMFONT_BOLD); - break; - case '2': - case 'I': - term_fontrepl(p, TERMFONT_UNDER); - break; - case 'P': - term_fontlast(p); - break; - case '1': - case 'C': - case 'R': - term_fontrepl(p, TERMFONT_NONE); - break; - default: - break; - } -} - -static void -roff_term_pre_ll(ROFF_TERM_ARGS) -{ - term_setwidth(p, n->child != NULL ? n->child->string : NULL); -} - -static void -roff_term_pre_mc(ROFF_TERM_ARGS) -{ - if (p->col) { - p->flags |= TERMP_NOBREAK; - term_flushln(p); - p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE); - } - if (n->child != NULL) { - p->mc = n->child->string; - p->flags |= TERMP_NEWMC; - } else - p->flags |= TERMP_ENDMC; -} - -static void -roff_term_pre_po(ROFF_TERM_ARGS) -{ - struct roffsu su; - static int po, polast; - int ponew; - - if (n->child != NULL && - a2roffsu(n->child->string, &su, SCALE_EM) != NULL) { - ponew = term_hen(p, &su); - if (*n->child->string == '+' || - *n->child->string == '-') - ponew += po; - } else - ponew = polast; - polast = po; - po = ponew; - - ponew = po - polast + (int)p->tcol->offset; - p->tcol->offset = ponew > 0 ? ponew : 0; -} - -static void -roff_term_pre_sp(ROFF_TERM_ARGS) -{ - struct roffsu su; - int len; - - if (n->child != NULL) { - if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL) - su.scale = 1.0; - len = term_vspan(p, &su); - } else - len = 1; - - if (len < 0) - p->skipvsp -= len; - else - while (len--) - term_vspace(p); - - roff_term_pre_br(p, n); -} - -static void -roff_term_pre_ta(ROFF_TERM_ARGS) -{ - term_tab_set(p, NULL); - for (n = n->child; n != NULL; n = n->next) - term_tab_set(p, n->string); -} - -static void -roff_term_pre_ti(ROFF_TERM_ARGS) -{ - struct roffsu su; - const char *cp; - int len, sign; - - roff_term_pre_br(p, n); - - if (n->child == NULL) - return; - cp = n->child->string; - if (*cp == '+') { - sign = 1; - cp++; - } else if (*cp == '-') { - sign = -1; - cp++; - } else - sign = 0; - - if (a2roffsu(cp, &su, SCALE_EM) == NULL) - return; - len = term_hen(p, &su); - - if (sign == 0) { - p->ti = len - p->tcol->offset; - p->tcol->offset = len; - } else if (sign == 1) { - p->ti = len; - p->tcol->offset += len; - } else if ((size_t)len < p->tcol->offset) { - p->ti = -len; - p->tcol->offset -= len; - } else { - p->ti = -p->tcol->offset; - p->tcol->offset = 0; - } -} Property changes on: head/contrib/mdocml/roff_term.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/Makefile.depend =================================================================== --- head/contrib/mdocml/Makefile.depend (revision 338825) +++ head/contrib/mdocml/Makefile.depend (nonexistent) @@ -1,78 +0,0 @@ -att.o: att.c config.h mandoc.h roff.h mdoc.h libmdoc.h -catman.o: catman.c config.h compat_fts.h -cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mansearch.h cgi.h -chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h -compat_err.o: compat_err.c config.h -compat_fts.o: compat_fts.c config.h compat_fts.h -compat_getline.o: compat_getline.c config.h -compat_getsubopt.o: compat_getsubopt.c config.h -compat_isblank.o: compat_isblank.c config.h -compat_mkdtemp.o: compat_mkdtemp.c config.h -compat_ohash.o: compat_ohash.c config.h compat_ohash.h -compat_progname.o: compat_progname.c config.h -compat_reallocarray.o: compat_reallocarray.c config.h -compat_recallocarray.o: compat_recallocarray.c config.h -compat_strcasestr.o: compat_strcasestr.c config.h -compat_stringlist.o: compat_stringlist.c config.h compat_stringlist.h -compat_strlcat.o: compat_strlcat.c config.h -compat_strlcpy.o: compat_strlcpy.c config.h -compat_strsep.o: compat_strsep.c config.h -compat_strtonum.o: compat_strtonum.c config.h -compat_vasprintf.o: compat_vasprintf.c config.h -dba.o: dba.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mansearch.h dba_write.h dba_array.h dba.h -dba_array.o: dba_array.c mandoc_aux.h dba_write.h dba_array.h -dba_read.o: dba_read.c mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h -dba_write.o: dba_write.c config.h dba_write.h -dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h -dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.h -demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h -eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h libroff.h -eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h -eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h -html.o: html.c config.h mandoc_aux.h mandoc.h roff.h out.h html.h manconf.h main.h -lib.o: lib.c config.h mandoc.h roff.h mdoc.h libmdoc.h lib.in -main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h tag.h main.h manconf.h mansearch.h -man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h -man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h main.h -man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h -mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h -mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h -mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h -mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h main.h manconf.h -mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h manconf.h mansearch.h dba_array.h dba.h -manpath.o: manpath.c config.h mandoc_aux.h manconf.h -mansearch.o: mansearch.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h -mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h html.h main.h -mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h -mdoc_markdown.o: mdoc_markdown.c mandoc_aux.h mandoc.h roff.h mdoc.h main.h -mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h libmdoc.h -mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h term.h tag.h main.h -mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -msec.o: msec.c config.h mandoc.h libmandoc.h msec.in -out.o: out.c config.h mandoc_aux.h mandoc.h out.h -preconv.o: preconv.c config.h mandoc.h libmandoc.h -read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h -roff.o: roff.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h libmandoc.h roff_int.h libroff.h predefs.in -roff_html.o: roff_html.c mandoc.h roff.h out.h html.h -roff_term.o: roff_term.c mandoc.h roff.h out.h term.h -roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h -soelim.o: soelim.c config.h compat_stringlist.h -st.o: st.c config.h mandoc.h roff.h mdoc.h libmdoc.h st.in -tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h -tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h -tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h -tbl_html.o: tbl_html.c config.h mandoc.h out.h html.h -tbl_layout.o: tbl_layout.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h -tbl_opts.o: tbl_opts.c config.h mandoc.h libmandoc.h libroff.h -tbl_term.o: tbl_term.c config.h mandoc.h out.h term.h -term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h -term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h manconf.h main.h -term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h manconf.h main.h -term_tab.o: term_tab.c mandoc_aux.h out.h term.h -tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h main.h Property changes on: head/contrib/mdocml/Makefile.depend ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/TODO =================================================================== --- head/contrib/mdocml/TODO (revision 338825) +++ head/contrib/mdocml/TODO (nonexistent) @@ -1,582 +0,0 @@ -************************************************************************ -* Official mandoc TODO. -* $Id: TODO,v 1.246 2017/07/24 11:15:12 schwarze Exp $ -************************************************************************ - -Many issues are annotated for difficulty as follows: - - - loc = locality of the issue - * single file issue, affects file only, or very few - ** single module issue, affects several files of one module - *** cross-module issue, significantly impacts multiple modules - and may require substantial changes to internal interfaces - - exist = difficulty of the existing code in this area - * affected code is straightforward and easy to read and change - ** affected code is somewhat complex, but once you understand - the design, not particularly difficult to understand - *** affected code uses a special, exceptionally tricky design - - algo = difficulty of the new algorithm to be written - * the required logic and code is straightforward - ** the required logic is somewhat complex and needs a careful design - *** the required logic is exceptionally tricky, - maybe an approach to solve that is not even known yet - - size = the amount of code to be written or changed - * a small number of lines (at most 100, usually much less) - ** a considerable amount of code (several dozen to a few hundred) - *** a large amount of code (many hundreds, maybe thousands) - - imp = importance of the issue - * mostly for completeness - ** would be nice to have - *** issue causes considerable inconvenience - -Obviously, as the issues have not been solved yet, these annotations -are mere guesses, and some may be wrong. - -************************************************************************ -* missing features -************************************************************************ - ---- missing roff features ---------------------------------------------- - -- .ad (adjust margins) - .ad l -- adjust left margin only (flush left) - .ad r -- adjust right margin only (flush right) - .ad c -- center text on line - .ad b -- adjust both margins (alias: .ad n) - .na -- temporarily disable adjustment without changing the mode - .ad -- re-enable adjustment without changing the mode - Adjustment mode is ignored while in no-fill mode (.nf). - loc *** exist *** algo ** size ** imp ** (parser reorg would help) - -- .fc (field control) - found by naddy@ in xloadimage(1) - loc ** exist *** algo * size * imp * - -- .nr third argument (auto-increment step size, requires \n+) - found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700 - loc * exist * algo * size * imp ** - -- .ns (no-space mode) occurs in xine-config(1) - when implementing this, also let .TH set it - reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500 - loc *** exist *** algo *** size ** imp * - -- .while and .shift - found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200 - loc * exist ** algo ** size ** imp ** - -- \n+ and \n- numerical register increment and decrement - found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700 - loc * exist * algo * size * imp ** - -- \w'' improve width measurements - would not be very useful without an expression parser, see below - needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100 - loc ** exist *** algo *** size * imp *** - -- \\ in high-level macro arguments - Currently, \\ is expanded in two situations: - 1) macro and string definition (roff.c setstrn()) - 2) macro argument parsing (mandoc.c mandoc_getarg()) - For user defined macros, the second happens in time because of ROFF_REPARSE. - But for standard high-level macros, it only happens after entering the - high level parsers, which is too late because the code doesn't get - back to roff.c roff_res() from that point. Because this requires - distinguishing requests, user-defined macros and standard macros - on the roff_res() level, it is hard to solve without the parser reorg. - Found by naddy@ in devel/cutils cobfusc(1) Mon, 16 Feb 2015 19:10:52 +0100 - loc *** exist *** algo *** size ** imp * - -- using undefined strings or macros defines them to be empty - wl@ Mon, 14 Nov 2011 14:37:01 +0000 - loc * exist * algo * size * imp * - ---- missing mdoc features ---------------------------------------------- - -- .Bl -column .Xo support is missing - ultimate goal: - restore .Xr and .Dv to - lib/libc/compat-43/sigvec.3 - lib/libc/gen/signal.3 - lib/libc/sys/sigaction.2 - loc * exist *** algo *** size * imp ** - -- edge case: decide how to deal with blk_full bad nesting, e.g. - .Sh .Nm .Bk .Nm .Ek .Sh found by jmc@ in ssh-keygen(1) - from jmc@ Wed, 14 Jul 2010 18:10:32 +0100 - loc * exist *** algo *** size ** imp ** - -- .Bd -centered implies -filled, not -unfilled, which is not - easy to implement; it requires code similar to .ce, which - we don't have either. - Besides, groff has bug causing text right *before* .Bd -centered - to be centered as well. - loc *** exist *** algo ** size ** imp ** (parser reorg would help) - -- .Bd -filled should not be the same as .Bd -ragged, but align both - the left and right margin. In groff, it is implemented in terms - of .ad b, which we don't have either. Found in cksum(1). - loc *** exist *** algo ** size ** imp ** (parser reorg would help) - -- implement blank `Bl -column', such as - .Bl -column - .It foo Ta bar - .El - loc * exist *** algo *** size * imp * - -- explicitly disallow nested `Bl -column', which would clobber internal - flags defined for struct mdoc_macro - loc * exist * algo * size * imp ** - -- In .Bl -column .It, the end of the line probably has to be regarded - as an implicit .Ta, if there could be one, see the following mildly - ugly code from login.conf(5): - .Bl -column minpasswordlen program xetcxmotd - .It path Ta path Ta value of Dv _PATH_DEFPATH - .br - Default search path. - reported by Michal Mazurek - via jmc@ Thu, 7 Apr 2011 16:00:53 +0059 - loc * exist *** algo ** size * imp ** - -- inside `.Bl -column' phrases, punctuation is handled like normal - text, e.g. `.Bl -column .It Fl x . Ta ...' should give "-x -." - -- inside `.Bl -column' phrases, TERMP_IGNDELIM handling by `Pf' - is not safe, e.g. `.Bl -column .It Pf a b .' gives "ab." - but should give "ab ." - -- check whether it is correct that `D1' uses INDENT+1; - does it need its own constant? - loc * exist ** algo ** size * imp ** - -- prohibit `Nm' from having non-text HEAD children - (e.g., NetBSD mDNSShared/dns-sd.1) - (mdoc_html.c and mdoc_term.c `Nm' handlers can be slightly simplified) - -- support translated section names - e.g. x11/scrotwm scrotwm_es.1:21:2: error: NAME section must be first - that one uses NOMBRE because it is spanish... - deraadt tends to think that section-dependent macro behaviour - is a bad idea in the first place, so this may be irrelevant - loc ** exist ** algo ** size * imp ** - -- When there is free text in the SYNOPSIS and that free text contains - the .Nm macro, groff somehow understands to treat the .Nm as an in-line - macro, while mandoc treats it as a block macro and breaks the line. - No idea how the logic for distinguishing in-line and block instances - should be, needs investigation. - uqs@ Thu, 2 Jun 2011 11:03:51 +0200 - uqs@ Thu, 2 Jun 2011 11:33:35 +0200 - loc * exist ** algo *** size * imp ** - ---- missing tbl features ----------------------------------------------- - -- the "s" layout column specifier is used for placement of data - into columns, but ignored during column width calculations - synaptics(4) found by tedu@ Mon, 17 Aug 2015 21:17:42 -0400 - loc * exist ** algo *** size * imp ** - -- support mdoc(7) and man(7) macros inside tbl(7) code; - probably requires the parser reorg and letting tbl(7) - use roff_node such that macro sets can mix; - informed by bapt@ that FreeBSD needs this: 3 Jan 2015 23:32:23 +0100 - loc *** exist ** algo *** size ** imp *** - -- look at the POSIX manuals in the books/man-pages-posix port, - they use some unsupported tbl(7) features. - loc * exist ** algo ** size ** imp *** - -- look what Joerg Schilling manual pages use - Thu, 19 Mar 2015 18:31:48 +0100 - -- use Unicode U+2500 to U+256C for table borders - in tbl(7) -Tutf-8 output - suggested by bentley@ Tue, 14 Oct 2014 04:10:55 -0600 - loc * exist ** algo * size * imp ** - ---- missing eqn features ----------------------------------------------- - -- In a matrix, break the output line after each matrix line. - Found in the discussion at CDBUG 2015. - Suggested by Avi Weinstock. - loc * exist * algo * size * imp ** - -- The "size" keyword is parsed, but ignored by the formatter. - loc * exist * algo * size * imp * - -- The spacing characters `~', `^', and tab are currently ignored, - see User's Guide (Second Edition) page 2 section 4. - loc * exist * algo ** size * imp ** - -- Mark and lineup are parsed and ignored, - see User's Guide (Second Edition) page 5 section 15. - loc ** exist ** algo ** size ** imp ** - -- GNU eqn converts some operators to special characters, for example, - input HYPHEN-MINUS becomes output \(mi, unless it is part of a - quoted word. mandoc(1) only does this when the operator is - surrounded by blanks, not when it is part of an unquoted word. - Also, check whether there are more such cases (e.g., +?). - reported by bentley@ 20 Jun 2017 02:04:29 -0600 - -- Primes, opprime, and ' - bentley@ Thu, 13 Jul 2017 23:14:20 -0600 - ---- missing misc features ---------------------------------------------- - -- italic correction (\/) in PostScript mode - Werner LEMBERG on groff at gnu dot org Sun, 10 Nov 2013 12:47:46 - loc ** exist ** algo * size * imp * - -- change the default PAGER to more -Es and use the pager - even for apropos title line output; req by bapt@ - loc * exist * algo * size * imp *** - -- clean up escape sequence handling, creating three classes: - (1) fully implemented, or parsed and ignored without loss of content - (2) unimplemented, potentially causing loss of content - or serious mangling of formatting (e.g. \n) -> ERROR - see textproc/mgdiff(1) for nice examples - (3) undefined, just output the character -> perhaps WARNING - loc *** exist ** algo ** size ** imp *** (parser reorg helps) - -- kettenis wants base roff, ms, and me Fri, 1 Jan 2010 22:13:15 +0100 (CET) - loc ** exist ** algo ** size *** imp * - ---- compatibility checks ----------------------------------------------- - -- is .Bk implemented correctly in modern groff? - sobrado@ Tue, 19 Apr 2011 22:12:55 +0200 - -- compare output to Heirloom roff, Solaris roff, and - http://repo.or.cz/w/neatroff.git http://litcave.rudi.ir/ - -- look at AT&T DWB http://www2.research.att.com/sw/download - Carsten Kunze has patches - Mon, 4 Aug 2014 17:01:28 +0200 - ported version: https://github.com/n-t-roff/DWB3.3 - Carsten Kunze Wed, 22 Apr 2015 11:21:43 +0200 - -- look at pages generated from reStructeredText, e.g. devel/mercurial hg(1) - These are a weird mixture of man(7) and custom autogenerated low-level - roff stuff. Figure out to what extent we can cope. - For details, see http://docutils.sourceforge.net/rst.html - noted by stsp@ Sat, 24 Apr 2010 09:17:55 +0200 - reminded by nicm@ Mon, 3 May 2010 09:52:41 +0100 - -- look at pages generated from ronn(1) github.com/rtomayko/ronn - (based on markdown) - -- look at pages generated from Texinfo source by yat2m, e.g. security/gnupg - First impression is not that bad. - -- look at pages generated by pandoc; see - https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/Writers/Man.hs - porting planned by kili@ Thu, 19 Jun 2014 19:46:28 +0200 - -- check compatibility with Plan9: - http://swtch.com/usr/local/plan9/tmac/tmac.an - http://swtch.com/plan9port/man/man7/man.html - "Anthony J. Bentley" 28 Dec 2010 21:58:40 -0700 - -- check compatibility with COHERENT troff: - http://www.nesssoftware.com/home/mwc/source.php - -- check compatibility with the man(7) formatter - https://raw.githubusercontent.com/rofl0r/hardcore-utils/master/man.c - -- check compatibility with - http://ikiwiki.info/plugins/contrib/mandoc/ - https://github.com/schmonz/ikiwiki/compare/mandoc - Amitai Schlair Mon, 19 May 2014 14:05:53 -0400 - -- check features of the Slackware man.conf(5) format - Carsten Kunze Wed, 11 Mar 2015 17:57:24 +0100 - -************************************************************************ -* formatting issues: ugly output -************************************************************************ - -- revisit empty in-line macros - look at the difference between "Em x Em ." and "Sq x Em ." - Carsten Kunze Fri, 12 Dec 2014 00:15:41 +0100 - loc *** exist *** algo *** size * imp ** - -- a column list with blank `Ta' cells triggers a spurious - start-with-whitespace printing of a newline - -- In .Bl -column, .It a"bc" - shows the quotes in groff, but not in mandoc - loc * exist *** algo ** size * imp ** - -- In .Bl -column, - .It Em AuthenticationKey Length - ought to render "Key Length" with emphasis, too, - see OpenBSD iked.conf(5). - reported again Nicolas Joly via wiz@ Wed, 12 Oct 2011 00:20:00 +0200 - loc * exist *** algo *** size ** imp *** - -- empty phrases in .Bl column produce too few blanks - try e.g. .Bl -column It Ta Ta - reported by millert Fri, 02 Apr 2010 16:13:46 -0400 - loc * exist *** algo *** size * imp ** - -- .%T can have trailing punctuation. Currently, it puts the trailing - punctuation into a trailing MDOC_TEXT element inside its own scope. - That element should rather be outside its scope, such that the - punctuation does not get underlines. This is not trivial to - implement because .%T then needs some features of in_line_eoln() - - slurp all arguments into one single text element - and one feature - of in_line() - put trailing punctuation out of scope. - Found in mount_nfs(8) and exports(5), search for "Appendix". - loc ** exist ** algo *** size * imp ** - -- Trailing punctuation after .%T triggers EOS spacing, at least - outside .Rs (eek!). Simply setting ARGSFL_DELIM for .%T is not - the right solution, it sends mandoc into an endless loop. - reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100 - loc * exist ** algo ** size * imp ** - -- global variables in the SYNOPSIS of section 3 pages - .Vt vs .Vt/.Va vs .Ft/.Va vs .Ft/.Fa ... - from kristaps@ Tue, 08 Jun 2010 11:13:32 +0200 - -- implicit whitespace around inline equations - example code: where '$times$' denotes matrix multiplication - must not have an HTML line break, nor a blank, before - partial solution: html.c {"math", HTML_NLINSIDE | HTML_INDENT}, - bentley@ Thu, 13 Jul 2017 19:00:59 -0600 - -- in enclosures, mandoc sometimes fancies a bogus end of sentence - reminded by jmc@ Thu, 23 Sep 2010 18:13:39 +0059 - loc * exist ** algo *** size * imp *** - -- a line starting with "\fB something" counts as starting with whitespace - and triggers a line break; found in audio/normalize-mp3(1) - loc ** exist * algo ** size * imp ** - -- formatting /usr/local/man/man1/latex2man.1 with groff and mandoc - reveals lots of bugs both in groff and mandoc... - reported by bentley@ Wed, 22 May 2013 23:49:30 -0600 - ---- PostScript and PDF issues ------------------------------------------ - -- PDF output doesn't use a monospaced font for .Bd -literal - Example: "mandoc -Tpdf afterboot.8 > output.pdf && pdfviewer output.pdf". - Search the text "Routing tables". - Also check what PostScript mode does when fixing this. - reported by juanfra@ Wed, 04 Jun 2014 21:44:58 +0200 - instructions from juanfra@ Wed, 11 Jun 2014 02:21:01 +0200 - add a new <> block to the PDF files with /BaseFont /Courier - and change the /Name from /F0 to the new font (/F5 (?)). - re-reported by tb@ Mon, 16 Mar 2015 16:47:21 +0100 - loc * exist ** algo ** size * imp ** - ---- HTML issues -------------------------------------------------------- - -- .Bf at the beginning of a paragraph inserts a bogus 1ex horizontal - space, see for example random(3). Introduced in - http://mdocml.bsd.lv/cgi-bin/cvsweb/mdoc_html.c.diff?r1=1.91&r2=1.92 - reported by deraadt@ Mon, 28 Sep 2015 20:14:13 -0600 (MDT) - loc ** exist ** algo ** size * imp * - -- jsg on icb, Nov 3, 2014: - try to guess Xr in man(7) for hyperlinking - and render them with - https://github.com/Debian/debiman/issues/15 - loc * exist * algo ** size ** imp ** - -- The tables used to render the three-part page headers actually force - the width of the to the max-width given for . - Not yet sure how to fix that... - Observed by an Anonymous Coward on undeadly.org: - http://undeadly.org/cgi?action=article&sid=20140925064244&pid=1 - loc * exist * algo ** size * imp *** - -- generate tags in HTML - idea from florian@ Tue, 7 Apr 2015 00:26:28 +0000 - may be possible to implement with .Lk img://something.png alt_text - -- check https://github.com/trentm/mdocml - -************************************************************************ -* formatting issues: gratuitous differences -************************************************************************ - -- .Fn reopens a new scope after punctuation in mandoc, - but closes its scope for good in groff. - Do we want to change mandoc or groff? - Steffen Nurpmeso Sat, 08 Nov 2014 13:34:59 +0100 - loc * exist ** algo ** size * imp ** - -- In .Bl -enum -width 0n, groff continues one the same line after - the number, mandoc breaks the line. - mail to kristaps@ Mon, 20 Jul 2009 02:21:39 +0200 - loc * exist ** algo ** size * imp ** - -- .Pp between two .It in .Bl -column should produce one, - not two blank lines, see e.g. login.conf(5). - reported by jmc@ Sun, 17 Apr 2011 14:04:58 +0059 - reported again by sthen@ Wed, 18 Jan 2012 02:09:39 +0000 (UTC) - loc * exist *** algo ** size * imp ** - -- If the *first* line after .It is .Pp, break the line right after - the tag, do not pad with space characters before breaking. - See the description of the a, c, and i commands in sed(1). - loc * exist ** algo ** size * imp ** - -- If the first line after .It is .D1, do not assert a blank line - in between, see for example tmux(1). - reported by nicm@ 13 Jan 2011 00:18:57 +0000 - loc * exist ** algo ** size * imp ** - -- Trailing punctuation after .It should trigger EOS spacing. - reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100 - Probably, this should be fixed somewhere in termp_it_pre(), not sure. - loc * exist ** algo ** size * imp ** - -- When the -width string contains macros, the macros must be rendered - before measuring the width, for example - .Bl -tag -width ".Dv message" - in magic(5), located in src/usr.bin/file, is the same - as -width 7n, not -width 11n. - The same applies to .Bl -column column widths; - reported again by Nicolas Joly Thu, 1 Mar 2012 13:41:26 +0100 via wiz@ 5 Mar - reported again by Franco Fichtner Fri, 27 Sep 2013 21:02:28 +0200 - reported again by Bruce Evans Fri, 17 Feb 2017 21:22:44 +0100 via bapt@ - loc *** exist *** algo *** size ** imp *** - An easy partial fix would be to just skip the first word if it starts - with a dot, including any following white space, when measuring. - loc * exist * algo * size * imp *** - -- The \& zero-width character counts as output. - That is, when it is alone on a line between two .Pp, - we want three blank lines, not two as in mandoc. - loc ** exist ** algo ** size * imp ** - -- Sequences of multiple man(7) paragraphs (.PP, .IP) interspersed - with .ps and .nf/.fi produce execessive blank lines, see libJudy - and graphics/dcmtk. The parser reorg may help with this. - -- trailing whitespace must be ignored even when followed by a font escape, - see for example - makes - \fBdig \fR - operate in batch mode - in dig(1). - loc ** exist ** algo ** size * imp ** - -************************************************************************ -* warning issues -************************************************************************ - -- style message about macros inside .Bd -literal and .Dl, in particular - font changing macros like .Cm, .Ar, .Fa (from the mdoclint TODO) - -- style message about mismatches between the section number in the - file name (if it is known) and the section number in .Dt - (from the mdoclint TODO) - -- style message about NULL without .Dv (from the mdoclint TODO) - -- style message about error constants without .Er (from the mdoclint TODO) - -- warn when .Sh or .Ss contain other macros - Steffen Nurpmeso, savannah.gnu.org/bugs/index.php?45034 - loc * exist * algo * size * imp ** - -- style message about violations of the convention - .An name Aq Mt localpart@domain in AUTHORS (from the mdoclint TODO) - -- warn about attempts to call non-callable macros - Steffen Nurpmeso Tue, 11 Nov 2014 22:55:16 +0100 - Note that formatting is inconsistent in groff. - .Fn Po prints "Po()", .Ar Sh prints "file ..." and no "Sh". - Relatively hard because the relevant code is scattered - all over mdoc_macro.c and all subtly different. - loc ** exist ** algo ** size ** imp ** - -- style message about suspicious uses of - vs. \- vs. \(mi - e.g. -1 is likely wrong (from the mdoclint TODO) - -- warn about punctuation - e.g. ',' and ';' - at the beginning - of a text line, if it is likely intended to follow the preceding - output without intervening whitespace, in particular after a - macro line (from the mdoclint TODO) - -- mandoc_special does not really check the escape sequence, - but just the overall format - loc ** exist ** algo *** size ** imp ** - -************************************************************************ -* documentation issues -************************************************************************ - -- dashes, hyphens, and minus signs in manual pages - jmc@ Fri, 28 Mar 2014 07:19:27 +0000 - -- mark macros as: page structure domain, manual domain, general text domain - is this useful? - -- mention /usr/share/misc/mdoc.template in mdoc(7)? - -- Is all the content from http://www.std.com/obi/BSD/doc/usd/28.tbl/tbl - covered in tbl(7)? - -************************************************************************ -* performance issues -************************************************************************ - -- the PDF file is HUGE: this can be reduced by using relative offsets - -************************************************************************ -* structural issues -************************************************************************ - -- POSIX says in the documentation of sysconf(3) that PATH_MAX - is allowed to be so large that it is a bad idea to use it - for sizing static buffers. So use dynamic buffers throughout. - See the file test-PATH_MAX.c for details. - Found by Aaron M. Ucko in the GNU Hurd via Bdale Garbee, - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=829624 - -- We use the input line number at several places to distinguish - same-line from different-line input. That plainly doesn't work - with user-defined macros, leading to random breakage. - -- Is it possible to further simplify ENDBODY_SPACE? - -- Find better ways to prevent endless loops - in roff(7) macro and string expansion. - -- make buffers for parsing functions const - christos@ via wiz@ Fri, 18 Dec 2015 17:10:01 +0100 - -- struct mparse refactoring - Steffen Nurpmeso Thu, 04 Sep 2014 12:50:00 +0200 - -************************************************************************ -* CGI issues -************************************************************************ - - - Enable HTTP compression by detecting gzip encoding and filtering - output through libz. - - Sandbox (see OpenSSH). - - Enable caching support via HTTP 304 and If-Modified-Since. - - Have Mac OSX systems automatically disable -static compilation of the - CGI: -static isn't supported. - -************************************************************************ -* to improve in the groff_mdoc(7) macros -************************************************************************ - -- use uname(1) to set doc-default-operating-system at install time - tobimensch Mon, 1 Dec 2014 00:25:07 +0100 - -- apostrophe (39), circumflex (94), grave (96), tilde (126) - in manuals: \(aq, \(ha, \`, \(ti - Re: [Groff] ASCII Minus Sign in man Pages. - bentley@ 26 Apr 2017 10:02:06 -0600 - Do we need to fix existing manuals? - Do we need to fix the definition of the mdoc(7) language? Index: head/contrib/mdocml/compat_vasprintf.c =================================================================== --- head/contrib/mdocml/compat_vasprintf.c (revision 338825) +++ head/contrib/mdocml/compat_vasprintf.c (nonexistent) @@ -1,56 +0,0 @@ -#include "config.h" - -#if HAVE_VASPRINTF - -int dummy; - -#else - -/* $Id: compat_vasprintf.c,v 1.3 2015/10/06 18:32:19 schwarze Exp $ */ -/* - * Copyright (c) 2015 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. - * - * This fallback implementation is not efficient: - * It does the formatting twice. - * Short of fiddling with the unknown internals of the system's - * printf(3) or completely reimplementing printf(3), i can't think - * of another portable solution. - */ - -#include -#include -#include - -int -vasprintf(char **ret, const char *format, va_list ap) -{ - char buf[2]; - va_list ap2; - int sz; - - va_copy(ap2, ap); - sz = vsnprintf(buf, sizeof(buf), format, ap2); - va_end(ap2); - - if (sz != -1 && (*ret = malloc(sz + 1)) != NULL) { - if (vsnprintf(*ret, sz + 1, format, ap) == sz) - return sz; - free(*ret); - } - *ret = NULL; - return -1; -} - -#endif Property changes on: head/contrib/mdocml/compat_vasprintf.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/tree.c =================================================================== --- head/contrib/mdocml/tree.c (revision 338825) +++ head/contrib/mdocml/tree.c (nonexistent) @@ -1,403 +0,0 @@ -/* $Id: tree.c,v 1.77 2017/07/08 14:51:05 schwarze Exp $ */ -/* - * Copyright (c) 2008, 2009, 2011, 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.h" -#include "roff.h" -#include "mdoc.h" -#include "man.h" -#include "main.h" - -static void print_box(const struct eqn_box *, int); -static void print_man(const struct roff_node *, int); -static void print_meta(const struct roff_meta *); -static void print_mdoc(const struct roff_node *, int); -static void print_span(const struct tbl_span *, int); - - -void -tree_mdoc(void *arg, const struct roff_man *mdoc) -{ - print_meta(&mdoc->meta); - putchar('\n'); - print_mdoc(mdoc->first->child, 0); -} - -void -tree_man(void *arg, const struct roff_man *man) -{ - print_meta(&man->meta); - if (man->meta.hasbody == 0) - puts("body = empty"); - putchar('\n'); - print_man(man->first->child, 0); -} - -static void -print_meta(const struct roff_meta *meta) -{ - if (meta->title != NULL) - printf("title = \"%s\"\n", meta->title); - if (meta->name != NULL) - printf("name = \"%s\"\n", meta->name); - if (meta->msec != NULL) - printf("sec = \"%s\"\n", meta->msec); - if (meta->vol != NULL) - printf("vol = \"%s\"\n", meta->vol); - if (meta->arch != NULL) - printf("arch = \"%s\"\n", meta->arch); - if (meta->os != NULL) - printf("os = \"%s\"\n", meta->os); - if (meta->date != NULL) - printf("date = \"%s\"\n", meta->date); -} - -static void -print_mdoc(const struct roff_node *n, int indent) -{ - const char *p, *t; - int i, j; - size_t argc; - struct mdoc_argv *argv; - - if (n == NULL) - return; - - argv = NULL; - argc = 0; - t = p = NULL; - - switch (n->type) { - case ROFFT_ROOT: - t = "root"; - break; - case ROFFT_BLOCK: - t = "block"; - break; - case ROFFT_HEAD: - t = "head"; - break; - case ROFFT_BODY: - if (n->end) - t = "body-end"; - else - t = "body"; - break; - case ROFFT_TAIL: - t = "tail"; - break; - case ROFFT_ELEM: - t = "elem"; - break; - case ROFFT_TEXT: - t = "text"; - break; - case ROFFT_TBL: - break; - case ROFFT_EQN: - t = "eqn"; - break; - default: - abort(); - } - - switch (n->type) { - case ROFFT_TEXT: - p = n->string; - break; - case ROFFT_BODY: - p = roff_name[n->tok]; - break; - case ROFFT_HEAD: - p = roff_name[n->tok]; - break; - case ROFFT_TAIL: - p = roff_name[n->tok]; - break; - case ROFFT_ELEM: - p = roff_name[n->tok]; - if (n->args) { - argv = n->args->argv; - argc = n->args->argc; - } - break; - case ROFFT_BLOCK: - p = roff_name[n->tok]; - if (n->args) { - argv = n->args->argv; - argc = n->args->argc; - } - break; - case ROFFT_TBL: - break; - case ROFFT_EQN: - p = "EQ"; - break; - case ROFFT_ROOT: - p = "root"; - break; - default: - abort(); - } - - if (n->span) { - assert(NULL == p && NULL == t); - print_span(n->span, indent); - } else { - for (i = 0; i < indent; i++) - putchar(' '); - - printf("%s (%s)", p, t); - - for (i = 0; i < (int)argc; i++) { - printf(" -%s", mdoc_argnames[argv[i].arg]); - if (argv[i].sz > 0) - printf(" ["); - for (j = 0; j < (int)argv[i].sz; j++) - printf(" [%s]", argv[i].value[j]); - if (argv[i].sz > 0) - printf(" ]"); - } - - putchar(' '); - if (NODE_DELIMO & n->flags) - putchar('('); - if (NODE_LINE & n->flags) - putchar('*'); - printf("%d:%d", n->line, n->pos + 1); - if (NODE_DELIMC & n->flags) - putchar(')'); - if (NODE_EOS & n->flags) - putchar('.'); - if (NODE_BROKEN & n->flags) - printf(" BROKEN"); - if (NODE_NOSRC & n->flags) - printf(" NOSRC"); - if (NODE_NOPRT & n->flags) - printf(" NOPRT"); - putchar('\n'); - } - - if (n->eqn) - print_box(n->eqn->first, indent + 4); - if (n->child) - print_mdoc(n->child, indent + - (n->type == ROFFT_BLOCK ? 2 : 4)); - if (n->next) - print_mdoc(n->next, indent); -} - -static void -print_man(const struct roff_node *n, int indent) -{ - const char *p, *t; - int i; - - if (n == NULL) - return; - - t = p = NULL; - - switch (n->type) { - case ROFFT_ROOT: - t = "root"; - break; - case ROFFT_ELEM: - t = "elem"; - break; - case ROFFT_TEXT: - t = "text"; - break; - case ROFFT_BLOCK: - t = "block"; - break; - case ROFFT_HEAD: - t = "head"; - break; - case ROFFT_BODY: - t = "body"; - break; - case ROFFT_TBL: - break; - case ROFFT_EQN: - t = "eqn"; - break; - default: - abort(); - } - - switch (n->type) { - case ROFFT_TEXT: - p = n->string; - break; - case ROFFT_ELEM: - case ROFFT_BLOCK: - case ROFFT_HEAD: - case ROFFT_BODY: - p = roff_name[n->tok]; - break; - case ROFFT_ROOT: - p = "root"; - break; - case ROFFT_TBL: - break; - case ROFFT_EQN: - p = "EQ"; - break; - default: - abort(); - } - - if (n->span) { - assert(NULL == p && NULL == t); - print_span(n->span, indent); - } else { - for (i = 0; i < indent; i++) - putchar(' '); - printf("%s (%s) ", p, t); - if (NODE_LINE & n->flags) - putchar('*'); - printf("%d:%d", n->line, n->pos + 1); - if (NODE_EOS & n->flags) - putchar('.'); - putchar('\n'); - } - - if (n->eqn) - print_box(n->eqn->first, indent + 4); - if (n->child) - print_man(n->child, indent + - (n->type == ROFFT_BLOCK ? 2 : 4)); - if (n->next) - print_man(n->next, indent); -} - -static void -print_box(const struct eqn_box *ep, int indent) -{ - int i; - const char *t; - - static const char *posnames[] = { - NULL, "sup", "subsup", "sub", - "to", "from", "fromto", - "over", "sqrt", NULL }; - - if (NULL == ep) - return; - for (i = 0; i < indent; i++) - putchar(' '); - - t = NULL; - switch (ep->type) { - case EQN_LIST: - t = "eqn-list"; - break; - case EQN_SUBEXPR: - t = "eqn-expr"; - break; - case EQN_TEXT: - t = "eqn-text"; - break; - case EQN_PILE: - t = "eqn-pile"; - break; - case EQN_MATRIX: - t = "eqn-matrix"; - break; - } - - fputs(t, stdout); - if (ep->pos) - printf(" pos=%s", posnames[ep->pos]); - if (ep->left) - printf(" left=\"%s\"", ep->left); - if (ep->right) - printf(" right=\"%s\"", ep->right); - if (ep->top) - printf(" top=\"%s\"", ep->top); - if (ep->bottom) - printf(" bottom=\"%s\"", ep->bottom); - if (ep->text) - printf(" text=\"%s\"", ep->text); - if (ep->font) - printf(" font=%d", ep->font); - if (ep->size != EQN_DEFSIZE) - printf(" size=%d", ep->size); - if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args) - printf(" badargs=%zu(%zu)", ep->args, ep->expectargs); - else if (ep->args) - printf(" args=%zu", ep->args); - putchar('\n'); - - print_box(ep->first, indent + 4); - print_box(ep->next, indent); -} - -static void -print_span(const struct tbl_span *sp, int indent) -{ - const struct tbl_dat *dp; - int i; - - for (i = 0; i < indent; i++) - putchar(' '); - - switch (sp->pos) { - case TBL_SPAN_HORIZ: - putchar('-'); - return; - case TBL_SPAN_DHORIZ: - putchar('='); - return; - default: - break; - } - - for (dp = sp->first; dp; dp = dp->next) { - switch (dp->pos) { - case TBL_DATA_HORIZ: - case TBL_DATA_NHORIZ: - putchar('-'); - continue; - case TBL_DATA_DHORIZ: - case TBL_DATA_NDHORIZ: - putchar('='); - continue; - default: - break; - } - printf("[\"%s\"", dp->string ? dp->string : ""); - if (dp->spans) - printf("(%d)", dp->spans); - if (NULL == dp->layout) - putchar('*'); - putchar(']'); - putchar(' '); - } - - printf("(tbl) %d:1\n", sp->line); -} Property changes on: head/contrib/mdocml/tree.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml/NEWS =================================================================== --- head/contrib/mdocml/NEWS (revision 338825) +++ head/contrib/mdocml/NEWS (nonexistent) @@ -1,993 +0,0 @@ -$Id: NEWS,v 1.26 2017/07/28 14:57:56 schwarze Exp $ - -This file lists the most important changes in the mandoc.bsd.lv distribution. - -Changes in version 1.14.3, released on August 5, 2017 - - --- BUG FIXES --- - * man(7): Do not crash with out-of-bounds read access to a constant - array if .sp or a blank line immediately precedes .SS or .SH. - * mdoc(7): Do not crash with out-of-bounds read access to a constant - array if .sp or a blank line precede the first .Sh macro. - * tbl(7): Ignore explicitly specified negative column widths rather than - wrapping around to huge numbers and risking memory exhaustion. - * man(1): No longer use names that only occur in the SYNOPSIS section. - Gets rid of some surprising behaviour and bogus warnings. - --- THANKS TO --- - Leah Neukirchen (Void Linux), Markus Waldeck (Debian), - Peter Bui (nd.edu), and Yuri Pankov (illumos) for bug reports. - -Changes in version 1.14.2, released on July 28, 2017 - - --- MAJOR NEW FEATURES --- - * New mdoc(7) -Tmarkdown output mode. - * For -Thtml, implement internal hyperlinks pointing to authoritative - definitions of various syntax elements, similar to the ctags(1)-like - less(1) :t internal searching in terminal mode. - * Provide a superset of the functionality of the former mdoclint(1) - utility and a new -Wstyle message level with several new messages, - including validity checking of .Xr cross references. - * tbl(7): Implement automatic line breaking inside individual table - cells, and several other formatting improvements. - * eqn(7): Complete rewrite of the lexer, resulting in several bugfixes. - * Continue parser unification, in particular allowing generation - of syntax tree nodes on the roff(7) level, allowing implementation - of many additional roff requests. - --- REMOVED FUNCTIONALITY --- - * Delete the manpage(1) utility. It was never enabled in any release. - * Delete the -Txhtml command line option. It has been an obsolete - alias for the -Thtml output mode for more than two years. - --- MINOR NEW FEATURES --- - * -Tlint now puts parser messages on stdout instead of stderr, - making commands like "man -l -Tlint *.1" useful. - * mdoc(7): Various .Lk formatting improvements. - * mdoc(7) -Thtml: Better CSS for .Bl lists. - * man(7): Implement the .MT/.ME block macro (mailto hyperlink). - * man(7): Implement the .DT macro (restore default tab positions). - * man(7): Improved support for manuals generated with reStructuredText - by partial support for the \n[an-margin] number register. - * man(7) -Thtml: Support deep linking to .SH and .SS headers. - * tbl(7): Implement the "allbox" table option. - * tbl(7): Implement the column spacing and the 'w' (minimum column - width) layout modifiers. - * tbl(7): Significant improvements of the manual page. - * eqn(7): Much improved font selection, including recognition of - well-known function names, and a few other formatting improvements. - * eqn(7) -Thtml: Use and in addition to . - * roff(7): Implement the .ce (centering), .mc (margin character), - .rj (right justify), .ta (define tab stops), .ti (temporary indent), - .als (macro alias), .ec and .eo (escape character control), - .po (page offset), and .rn (macro rename) requests. - * roff(7) .am: Implement appending to mdoc(7) and man(7) macros. - * roff(7): implement the \h (horizontol motion), \l (horizontal - line drawing), and \p (break output line) escape sequences, - and also several additional character escape sequences. - * roff(7): Implement the 'd' conditional (macro or string defined). - * man.cgi(8) now uses pledge(2), too. - * regress.pl(1): simpler user interface, better summary output, - simpler code, and no more recursion. - --- THANKS TO --- - * Anthony Bentley (OpenBSD) for the implementation of .MT/.ME, - reports of many bugs and missing features, and suggestions - for a number of feature and documentation improvements. - * Sebastien Marie (OpenBSD) for two source code patches and - for some useful discussions. - * Florian Obser (OpenBSD) for a bugfix patch and a bug report. - * Jonathan Gray (OpenBSD) for several bug reports from afl(1) - and several more from static analysis tools. - * Theo Buehler (OpenBSD) for several bug reports, most from afl(1). - * Jason McIntyre (OpenBSD) for many useful discussions about a - wide variety of topics, lots of continuous testing, a number of - bug reports, and some suggestions for messages and documentation. - * Thomas Klausner (NetBSD) for lots of help while migrating - mdoclint(1) functionality to mandoc -Tlint, for suggesting - several useful new messages, and for release testing. - * Reyk Floeter (OpenBSD) and Vsevolod Stakhov (FreeBSD) for - suggesting a markdown output mode. - * Thomas Guettler for suggesting -Thtml internal hyperlinks. - * Yuri Pankov (Illumos) for inspiring new warning messages and - for extensive release testing. - * Anton Lindqvist and TJ Townsend (both OpenBSD) and Jan Stary - for multiple bug reports. - * Leah Neukirchen (Void Linux) for bug reports and release testing. - * Michael Stapelberg (Debian) for suggesting feature improvements - and for release testing. - * Martin Natano and Theo de Raadt (both OpenBSD), Andreas Voegele, - Gabriel Guzman, Gonzalo Tornaria, Markus Waldeck, and Raf Czlonka - for bug reports. - * Antoine Jacoutot (OpenBSD) and Steffen Nurpmeso for suggesting - feature improvements. - * Dag-Erling Smoergrav (FreeBSD) for inspiring new warning messages. - * Ted Unangst and Marc Espie (OpenBSD) for providing useful ideas. - * Svyatoslav Mishyn (Crux Linux) for release testing. - * Carsten Kunze (Heirloom roff) for help keeping mandoc and groff - compatible and for committing some of my patches to groff. - -Changes in version 1.14.1, released on February 21, 2017 - - --- MAJOR NEW FEATURES --- - * apropos(1): Reimplement complete semantic search functionality - without the dependency on SQLite3, using only POSIX APIs. - This comes with a completely new mandoc.db(5) file format. - * man(1): Support more than one tag entry for the same search term, - plus some minor improvements to the less(1) :t support. - * -Thtml: Use real macro names for CSS classes. - Systematic cleanup of and many improvements to mandoc.css. - * -Thtml: Produce human readable HTML code by using indentation - and better line breaks. Improve various HTML elements, - and trim several useless ones. - * New catman(8) utility, still somewhat experimental. - * Now includes a portable version of the OpenBSD mandoc regression - suite, see regress/regress.pl.1 for details. - --- REMOVED FUNCTIONALITY --- - * Operating systems that don't provide mmap(3) are no longer supported. - * Drop support for manpath(1). Even if your system has manpath(1), - it is simpler to use MANPATH_DEFAULT in configure.local for - operating system defaults, man.conf(5) for machine-specific - modifications, and ${MANPATH}, -m, and -M for user preferences - than to bother with the complexity of manpath(1). - * makewhatis(8) -p: No longer warn about missing MLINKS since these - are no longer needed for anything. - --- MINOR NEW FEATURES --- - * mdoc(7): Warn about invalid punctuation and content below NAME. - * mdoc(7): Warn about .Xr lacking the second argument (section). - * mdoc(7): Warn about violations of the rule "new sentence, new line". - * roff(7): Warn about trailing whitespace at the end of comments. - * mdoc(7): Improve rendering of double quotes. - * mdoc(7): Always do text production in the validator, never in the - formatters. Cleaner, simpler, shorter, helps NetBSD apropos(1) - and also makes -Ttree output more useful. - * -Ttree: Show metadata and some additional node flags. - New -Onoval output option to show the unvalidated tree. - --- RELIABILITY BUGFIXES --- - * man(1): Make "man -l" work with standard input from a pipe or file, - as long as standard output is a terminal. - * man(7): Fix out of bounds read access if a text node immediately - preceded the first .SH header. - * mdoc(7): Fix out of bounds read access for .Bl without a type - but with a width. - * mdoc(7): Fix out of bounds read access for .Bl -column starting - with a tab character instead of a child .It macro. - * mdoc(7): Fix syntax tree corruption leading to segfaults caused - by stray block end macros in nested blocks of mismatching type. - * man(1): Fix NULL dereference when the first of multiple pages - shown was preformatted. - * mdoc(7): Fix syntax tree corruption leading to NULL dereference - caused by partial implicit macros inside .Bl -column table cells. - * mdoc(7): Fix syntax tree corruption leading to NULL dereference - for macro sequences like .Bl .Bl .It Bo .El .It. - * mdoc(7): Fix syntax tree corruption leading to NULL dereference - caused by .Ta following a nested .Bl -column breaking another block. - * mdoc(7): Fix syntax tree corruption sometimes leading to NULL - dereference caused by indirectly broken .Nd or .Nm blocks. - * mdoc(7) -Thtml: Fix a NULL dereference for .Bl -column with 0 columns. - * mdoc(7): Fix NULL dereference in some specific cases of a - block-end macro calling another block-end macro. - * mdoc(7): Fix NULL dereference if the only child of the head - of the first .Sh was an empty in-line macro. - * eqn(7): Fix NULL dereference in the terminal formatter - for empty matrices and empty square roots. - * mdoc(7): Fix an assertion failure for a .Bd without a type that - breaks another block. - * mdoc(7): Fix an assertion failure that happened for some .Bl -column - lists containing a column width of "-4n", "-3n", or "-2n". - * mdoc(7): Fix an assertion failure caused by .Bl -column without .It - but containing eqn(7) or tbl(7) code. - * roff(7): Fix an assertion failure caused by \z\[u00FF] with -Tps/-Tpdf. - * roff(7): Fix an assertion failures caused by whitespace inside \o'' - (overstrike) sequences. - * -Thtml: Fix an assertion failure caused by -Oman or -Oincludes of - excessive length. - --- PORTABILITY IMPROVEMENTS --- - * man(1): Do not mix stdio narrow and wide stream orientation - on stdout, which could cause output corruption on glibc. - * mandoc(1): Autodetect a suitable locale for -Tutf8 mode. - * ./configure: Autodetect whether PATH_MAX and O_DIRECTORY are defined. - * ./configure: Autodetect if nanosleep(3) needs -lrt. - * ./configure: Provide an ${LN} configuration variable. - * ./configure: Put compiler arguments that may contain -l at the end. - --- MINOR BUGFIXES --- - * mdoc(7): Fix SYNOPSIS output if the first child of .Nm is a macro. - * mdoc(7) -Thtml: Improve formatting of .Bl -tag with short tags. - * man(7) -Thtml: Preserve whitespace in .nf (nofill) mode. - * mandoc(1): Error out on invalid output options on the command line. - --- STRUCTURAL CHANGES, no functional change --- - * Redesign part of the mandoc_html(3) interfaces, making them much - easier to use and reducing the amount of code by a few hundred lines. - --- THANKS TO --- - * Michael Stapelberg (Debian) for designing the new mandocd(8) - and parts of the new catman(8), for release testing, and for a - number of patches and bug reports. - * Baptiste Daroussin (FreeBSD) for profiling the new makewhatis(8) - implementation and suggesting an algorithmic improvement which - more than doubled performance, and for a few bug reports. - * Ed Maste (FreeBSD) for an important patch improving reproducibility - of builds in makewhatis(8), and for a few bug reports. - * Theo Buehler (OpenBSD) for almost twenty important bug reports, - most of them found by systematic afl(1) fuzzing. - * Benny Lofgren, David Dahlberg, and in particular Vadim Zhukov - for crucial help in getting .Bl -tag CSS formatting fixed. - * Svyatoslav Mishyn (Crux Linux) for an initial version of the - patch to autodetect a suitable locale for -Tutf8 mode - and for release testing. - * Jason McIntyre (OpenBSD) for multiple useful discussions - and a number of bug reports. - * Sevan Janiyan (NetBSD) for extensive release testing and multiple - bug reports. - * Thomas Klausner and Christos Zoulas (NetBSD), Yuri Pankov (illumos), - and Leah Neukirchen (Void Linux) for release testing and bug reports. - * Ulrich Spoerlein (FreeBSD) for release testing. - * Alexander Bluhm, Andrew Fresh, Antoine Jacoutot, Antony Bentley, - Christian Weisgerber, Jonathan Gray, Marc Espie, Martijn van Duren, - Stuart Henderson, Ted Unangst, Theo de Raadt (OpenBSD), Abhinav - Upadhyay, Kamil Rytarowski (NetBSD), Aaron M. Ucko, Bdale Garbee, - Reiner Herrmann, Shane Kerr (Debian), Daniel Sabogal (Alpine Linux), - Carsten Kunze (Heirloom roff), Kristaps Dzonsons (bsd.lv), - Anton Lindqvist, Jan Stary, Jeremy A. Mates, Mark Patruck, - Pavan Maddamsetti, Sean Levy , and - Tiago Silva for bug reports. - * Brent Cook, Marc Espie, Philip Guenther, Todd Miller (OpenBSD) - and Markus Waldeck for useful discussions. - * And as usual, OpenCSW for providing me with a Solaris 9/10/11 - testing environment. - -Changes in version 1.13.4, released on July 14, 2016 - - --- MAJOR NEW FEATURES --- - * man.conf(5): Design and implement a simpler configuration file format. - * man(1): Leverage less(1) -T and :t in a way resembling ctags(1) - to jump to the definitions of various terms inside manual pages. - * soelim(1): New implementation by Baptiste Daroussin. - * privilege limitation: Use OpenBSD pledge(2) or OS X sandbox_init(3) - when available. - * man.cgi(8): Support short URIs like http://man.openbsd.org/mdoc . - * mandoc.css: Use one unified stylesheet rather than three different ones. - --- MAJOR FUNCTIONALLY RELEVANT BUGFIXES --- - * mdoc(7): Fix multiple aspects of SYNOPSIS .Nm formatting. - * man(1): Fix process group handling, avoiding unclean shutdowns. - --- PORTABILITY IMPROVEMENTS --- - * Correctly use the ohash(3) compatibility implementation - even when building without SQLite support. - * Add compat glue for building on Solaris 9 and 10. - * Let ./configure select a supported RE syntax for word boundaries. - * Support LDFLAGS, to be used for example for hardening options. - * Avoid mixing putchar(3) and putwchar(3) on the same file descriptor, - it resulted in output corruption on some platforms. - * Avoid reusing va_lists, use va_copy(3) for better portability. - * Do not hardcode the path to the more(1) program. - --- MINOR NEW FEATURES --- - * roff(7): Implement \n(.$ (number of macro arguments). - * roff(7): Fully implement \z (do not advance cursor). - * roff(7): Implement the `r' conditional (register exists). - * roff(7): Implement \\$* (interpolate all arguments). - * roff(7): Parse and ignore \, and \/ (italic corrections). - * When there is no -m, no -M, no MANPATH and no /etc/man.conf, - fall back to /usr/share/man:/usr/X11R6/man:/usr/local/man. - * man(1): Give manuals in purely numerical sections priority over - manuals of the same name in sections with an alphabetical suffix. - * man.cgi(8): Support "header.html" and "footer.html". - * man.cgi(8): Set the "autofocus" attribute on the query text box. - * man.cgi(8): Simplify the search form, drop two useless buttons. - * man.cgi(8): Delete the pseudo-manpath "mandoc", assume that - apropos(1) and man.cgi(8) are installed in the default manpath. - --- RELIABILITY BUGFIXES --- - * mdoc(7): Avoid a use after free and an assertion failure when nodes - are deleted during validation. - * mdoc(7): Avoid a NULL pointer access when .Bd has no arguments. - * mdoc(7): Avoid a NULL pointer access triggered by mismatching end macros. - * mdoc(7): Avoid an assertion when .Fo has no argument. - * mdoc(7): Avoid an assertion when .Ta occurs in .Bl -column. - * mdoc(7): Avoid an assertion when a body gets broken and has a tail. - * roff(7): Avoid an assertion caused by blanks inside \o. - * roff(7): Make .so links to gziped manuals work without mandoc.db(5). - * tbl(7): Avoid a use after free when the last line of a layout is empty. - * eqn(7): Avoid an infinite loop caused by recursive "define". - * makewhatis(8): Avoid a segfault caused by unusual directory structures. - * Fix handling of leading, trailing, and double colons in MANPATH and -m. - --- MINOR BUGFIXES --- - * mdoc(7): Put arguments to end macros of broken partial explicit blocks - inside the breaking block. - * mdoc(7): Let .Dv force normal font. - * mdoc(7): Make trailing whitespace significant in .Bl -tag widths. - * mdoc(7): Fix macro interpretation around tabs in .Bl -column. - * man(7): Use the default width for .RS without arguments. - * man(7): On a new RS nesting level, the saved width starts from - the default width, not from the saved width of the previous level. - * man(7): Allow .PD in next-line scope. - * man(7): Improve handling of empty .HP. - * man(7): Improve formatting of .br and .sp inside .HP. - * man(7): Do not mistreat empty arguments to font alternating - macros as vertical spacing requests. - * man(7): Allow fill mode changes in tagged paragraph next-line scope. - * man(7): Fix minor bugs in block rewinding and simplify the related code. - * man(7): Add missing line breaks before subsection headers. - * man(7): Give section and subsection headers hanging indentation. - * man(7): Make trailing whitespace significant in .TP widths. - * roff(7): Don't allow breaking the output line after hyphens - that immediately follow escape sequences. - * roff(7): Ignore blank characters at the beginning of conditional blocks. - * roff(7): Escape breakable hyphens only after handling input line traps. - * roff(7): Reject \[uD800] to \[uDFFF] (surrogates) in the parser. - * tbl(7): Allow more than one data field after T} on the same input line. - * terminal output: Apply bold and italic to non-ASCII Unicode codepoints. - * terminal output: Improve rounding rules for horizontal scaling widths. - * HTML output: Render ASCII_NBRSP as " ", not "-". - * man(1): Do not match the first part of a name if it continues with a dot. - * man(1): Keep working even if the current directory is unusable. - * man(1): Better error message when $PAGER is invalid. - * makewhatis(8): Improve handling of .Va and .Vt macros. - * apropos(1): Print "nothing appropriate" to stderr when appropriate. - * apropos(1): Abort with a useful error message when elementary - database operations like preparing queries or binding variables fail. - --- STRUCTURAL CHANGES, no functional change --- - * mdoc(7) and man(7): Unified data structures struct roff_node etc. - * mdoc(7) and man(7): Unified node handling library in roff.c. - * mdoc(7) and man(7): Seperate validation phase from parsing. - * roff(7): Major character table cleanup. - * Link with libz rather than forking gunzip(1). - --- THANKS TO --- - * Baptiste Daroussin (FreeBSD) for the new soelim(1) - and for release testing. - * Anthony Bentley (OpenBSD) for unifying mandoc.css, two nice - patches for man.cgi(8), some documentation patches, some bug - reports, and various useful discussions. - * Todd Miller (OpenBSD) for lots of help with process group and - signal handling, a few patches, some bug reports and some useful - discussions. - * Jonathan Gray (OpenBSD) for yet more testing with afl(1) - again resulting in more than half a dozen important bug reports. - * Svyatoslav Mishyn (Crux Linux) for some patches, several bug - reports, and extensive release testing. - * Leah Neukirchen (Void Linux) for a number of compatibility - patches and suggestions and several bug reports. - * Christos Zoulas (NetBSD) for a bug fix patch and some useful - suggestions for cleanup. - * Florian Obser (OpenBSD) for a bugfix patch and some bug reports. - * Sevan Janiyan for help with Solaris compatibility and release - testing on many platforms. - * Jan Holzhueter and OpenCSW in general for help with Solaris - compatibility, and for providing me with a Solaris 9/10/11 testing - environment. - * Michael McConville (OpenBSD) for some simple cleanup patches. - * Thomas Klausner (NetBSD) for some bug reports and release testing. - * Christian Weisgerber, Dmitrij Czarkoff, Igor Sobrado, - Ken Westerback, Marc Espie, Mike Belopuhov, Rafael Neves, - Ted Unangst, Tim van der Molen, Theo Buehler, Theo de Raadt - (OpenBSD), Kurt Jaeger, Dag Erling Smoergrav (FreeBSD), - Joerg Sonnenberger (NetBSD), Carsten Kunze (Heirloom troff), - Daniel Levai, Fabian Raetz, Jan Stary, Jean-Yves Migeon, - Lorenzo Beretta, Markus Waldeck, Maxim Belooussov, Michael Reed, - Peter Bray, and Serguey Parkhomovsky for bug reports and feature - suggestions. - * Alexander Hall, Andrew Fresh, Antoine Jacoutot, Doug Hogan, - Jason McIntyre, Jasper Lievisse Adriaanse, Kent Spillner, - Nicholas Marriott, Peter Hessler, Sebastien Marie, Stefan Sperling, - and Theo de Raadt (OpenBSD) for helpful discussions and feedback. - -Changes in version 1.13.3, released on March 13, 2015 - - --- MAJOR NEW FEATURES --- - * When a manual is missing from an outdated database, let man(1) - show it anyway, using a KISS file system lookup as a fallback. - * Use this to always provide man(1), even without database support. - * Fatal errors no longer exist. If a file can be opened, mandoc - will produce some output; at worst, the output may be almost empty. - * New -Wunsupp message level. - --- POTENTIONALLY SECURITY RELEVANT BUGFIXES --- - * Fix a potential write buffer overrun on incomplete string conditionals. - http://mandoc.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.241 - * Fix a potential write buffer overrun on backslash at EOF in a conditional. - http://mandoc.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.247 - * Fix a use after free sometimes hit when validation deletes a block. - http://mandoc.bsd.lv/cgi-bin/cvsweb/mdoc_macro.c#rev1.180 - --- MAJOR FUNCTIONALLY RELEVANT BUGFIXES --- - * Let man(1) show manuals for the current architecture by default, - and support the MACHINE environment variable. - * Fix the man(1) and apropos(1) -m option, it didn't work at all. - * Do not spawn a pager when there is no output. - * In makewhatis(8), fix detection of hardlinked manuals on platforms - having padding in struct inodev (typically 64bit platforms). - --- PORTABILITY IMPROVEMENTS --- - * Ignore O_CLOEXEC when the operating system doesn't provide it. - * Avoid forward reference to enum type which violates ISO C99. - * Support homebrew-style linking on Mac OS X. - --- MINOR NEW FEATURES --- - * lookup: Accept digit+letter and "n" as section names in man(1), - and consistently handle digit+letter in file name extensions. - * lookup: Speed up -s/-S by using the "mlinks" rather than the "keys" table. - * output: Insert horizontal lines between formatted manual pages. - * input: New stricter and more resilient UTF-8 parser. - * mdoc(7): Refactor block rewinding for simpler and more robust parsing. - * man(7): Use the -Ios option when .TH has less than four arguments. - * tbl(7): Implement the "center" option. - * tbl(7): New option and format parsers, improved in many respects. - * roff(7): Basic implementation of the \o escape sequence (overstrike), - and improved rendering of overstrikes in PostScript and PDF output. - * Message improvements, in particular for, but not restricted to, - eqn(7), tbl(7), and wrong numbers of arguments in mdoc(7) and man(7), - in various cases also improving output generated by invalid input. - * Delete the -V option. It serves no purpose but keeps confusing people. - * gmdiff: Minimal support for Heirloom roff. - --- RELIABILITY BUGFIXES --- - * tbl(7): Fix a read buffer overrun on 'f' at EOL in a layout. - * roff(7): Fix a read buffer overrun on incomplete numerical conditions. - * mdoc(7): Fix a NULL pointer access on .Nd followed by an explicit block. - * mdoc(7): Fix a NULL pointer access on .It Xo without .Xc. - * mdoc(7): Fix a NULL pointer access on .Eo without a tail. - * mdoc(7): Fix a NULL pointer access in the validation of empty .St macros. - * man(7)/tbl(7): Fix a NULL pointer access on .TS right after .TP. - * tbl(7): Fix a NULL pointer access on layout lines without any cells. - * eqn(7): Fix NULL pointer accesses in the terminal formatter. - * roff(7): Fix a NULL pointer access on trailing \s-/\s+ without an argument. - * gz: Fix a potential NULL pointer access after waitpid() failure. - * roff(7): Don't let the modulo operator divide by zero. - * input: Fix an assertion failure on certain invalid UTF-8 input. - * terminal output: Allow arbitrary depth of the font stack (assertion fix). - * mdoc(7): Fix assertion failures and endless loops on invalid block closing. - * mdoc(7): Fix an assertion failure on .Bl .Sm not followed by .It. - * mdoc(7): Fix an assertion failure on .Bl -column ... .El .Ta. - * tbl(7): Fix assertion failures by macros inside table data, - but do not throw away the macro arguments. - * Prevent certain kinds of unreasonable input from producing excessive - output, in one case caused by unsigned integer underflow. - * Fix a potential memory leak in makewhatis(8) on very long filenames. - --- MINOR BUGFIXES --- - * mdoc(7): Fix parsing of badly nested blocks with multiple identical blocks. - * mdoc(7): Support negative indentations for displays and lists. - * mdoc(7): Don't mistreat negative .sp arguments as large positive ones. - * mdoc(7): Some spacing fixes for .Eo/.Ec. - * man(7): Support negative horizontal widths. - * man(7): Do not print out invalid .IP arguments. - * man(7): Correctly handle scaling units after .PD. - * man(7): Support .RE with an argument. - * man(7): Fix restoring indentation after .RS with large negative arguments. - * tbl(7): Prevent tables from breaking the filling of preceding text. - * tbl(7): Fix vertical spacing at the beginning of tables. - * tbl(7): Parser and formatter fixes for line drawing and font modifiers. - * tbl(7): Correct handling of blank data lines. - * eqn(7): Add sometimes missing whitespace before equation output. - * roff(7): Fix vertical scaling, most of it was wrong. - * roff(7): Slightly improve \w width measurements. - * roff(7): Accept the historic aliases \s10 to \s39 for \s(10 to \s(39. - * roff(7): Correctly escape quotes when expanding macro arguments. - * roff(7): Correctly handle scaling units in numerical expressions, - and some other improvements to the parsing of numerical expressions. - * roff(7): Three minor fixes with respect to evaluation of conditionals. - * roff(7): Let .it accept numerical expressions, not just constants. - * mandoc_char(7): Correct some character names and renderings. - * If earlier files set a non-zero exit status, never reset it to zero. - --- THANKS TO --- - * Jonathan Gray (OpenBSD) for yet more testing with afl (the American - Fuzzy Lop security fuzzer), again resulting in many bug reports. - * Theo de Raadt (OpenBSD) for suggesting the main new feature (man(1) file - system lookup) and for reporting an important bug (pager without output). - * Theo Buehler for an important bug report (-s/-S slowness) - and for proposing a nice new feature (lines between pages). - * Jason McIntyre for an important bug report (hardlink detection) - and multiple documentation patches. - * Pascal Stumpf (OpenBSD) and Alessandro de Laurenzis for - important bug reports (architecture and man -m, respectively). - * Thomas Klausner (NetBSD) for proposing a new feature (man(7) -Ios), - a bug report, and release testing. - * Anthony Bentley, Daniel Dickman, Ted Unangst (OpenBSD) and - Kristaps Dzonsons (bsd.lv) for source code patches and bug reports. - * Christian Weisgerber (OpenBSD) for more than half a dozen bug reports. - * Carsten Kunze (Heirloom troff) for bug reports and release testing. - * Antoine Jacoutot (OpenBSD) for release testing. - * Alexis Hildebrandt (Homebrew), Baptiste Daroussin (FreeBSD), - Jonathan Perkin (SmartOS), Pedro Giffuni (FreeBSD), Svyatoslav - Mishyn (Crux Linux), Ulrich Spoerlein (FreeBSD), Jan Stary, Patrick - Keshishian, Sebastien Marie, and Steffen Nurpmeso for bug reports. - -Changes in version 1.13.2, released on December 13, 2014 - - --- MAJOR NEW FEATURES --- - * Include an implementation of man(1), the manual page viewer. - * Unified set of command line option, each one supported by all - command names, including new options -a (format all), -c (no - pager), -h (synopsis only), and -w (list filenames). - * Support the MANPAGER and PAGER environment variables. - * Support gzip'ed manuals by the whole toolset, even as .so targets. - * Support UTF-8 and Latin-1 input by the whole toolset, delete preconv(1). - * Switch the default output mode from -Tascii to -Tlocale. - * Improve -Tascii output for Unicode escape sequences. - * Let the -Thtml output mode produce polyglot HTML5. - * Many improvements for eqn(7), in particular in-line equations, - MathML output in -Thtml mode, and much improved terminal formatting. - --- PORTABILITY IMPROVEMENTS --- - * Change the build sequence to the usual ./configure; make; make install. - * Support ./configure.local for build customizations. - * Autodetect wchar, sqlite3, and manpath support. - * Provide a fallback version of fts(3) for systems lacking it. - * Support choosing alternative binary and manual names. - --- MINOR NEW FEATURES --- - * Rudimentary implementation of the e, x, and z tbl(7) layout - modifiers to equalize, maximize, and ignore the width of columns. - * Implement font modifiers in tbl(7) layouts. - * Allow comma-separated options in the tbl(7) options line. - * Parse and ignore the .pl (page length) roff(7) request. - * Implement .An -[no]split for the mdoc(7) -Thtml output mode. - * Support bold italic font in PostScript and PDF output. - * Warn about commas in function arguments and parentheses in function names. - * Warn about botched .Xr ordering and punctuation below SEE ALSO. - * Warn about AUTHORS sections without .An macros. - * Warn about attempts to call non-callable macros. - * New developer documentation manual page mandoc_headers(3). - --- BUGFIXES --- - * Fix read buffer overrun sometimes triggered by trailing whitespace. - * Fix read buffer overrun triggered by certain invalid \H sequences. - * Fix NULL pointer access triggered by .Bl without any arguments. - * Fix NULL pointer access triggered by .It Nm Fo without .Fc. - * Fix NULL pointer access triggered by .Sh Xo .Sh without .Xc. - * Fix NULL pointer access triggered by missing .Nm. - * Fix an assertion triggered by .It right after .El. - * Fix an assertion triggered by .Ec without preceding .Eo. - * Fix an assertion triggered by .Sm or .Db with multiple arguments. - * Fix assertion failures triggered by very large width arguments. - * Fix a division by zero in the roff(7) parser. - * Prevent negative arguments to .ll from causing integer underflow. - * Correctly autodetect source format even when .Dd is preceded by .ll. - * Multiple fixes with respect to .Bd and .Bl -offset and -width. - * Many bugfixes with respect to scaling units. - * Multiple fixes with respect to delimiter handling by in-line macros. - * Multiple fixes with respect to .Pf. - * Make \c work properly in no-fill mode. - * Stricter syntax checking of Unicode character names. - --- THANKS TO --- - * Kristaps Dzonsons for rewriting the eqn(7) parser, implementing - HTML5 and MathML output, and various other code contributions. - * Jonathan Gray (OpenBSD) for extensive testing with afl (the - American Fuzzy Lop security fuzzer) resulting in many bug reports. - * Anthony Bentley (OpenBSD), Baptiste Daroussin (FreeBSD), Daniel - Dickman, Doug Hogan, Jason McIntyre, Theo de Raadt (OpenBSD), - and Martin Natano for source code patches. - * Carsten Kunze (Heirloom troff), Daniel Levai (Slackware), - Garrett D'Amore (illumos), Giovanni Becchis, Matthew Dempsky, - Stuart Henderson, Ted Unangst, Todd Miller (OpenBSD), Thomas - Klausner (NetBSD), Ulrich Spoerlein (FreeBSD), Justin Haynes, - Marcus Merighi, Sebastien Marie, Steffen Nurpmeso and Theo Buehler - for bug reports. - -Changes in version 1.13.1, released on August 10, 2014 - - --- MAJOR NEW FEATURES --- - * A complete apropos(1)/makewhatis(8)/man.cgi(8) suite - based on SQLite3 is now included. - * The roff(7) parser now provides an almost complete implementation - of numerical expressions. - * Warning and error messages have been improved in many ways. - Almost all fatal errors were downgraded to normal errors and some - even to warnings. Almost all messages now mention the macro where - the issue is detected and many indicate the workaround employed. - The mandoc(1) manual now includes a list explaining all messages. - --- MINOR NEW FEATURES --- - * The roff(7) parser now supports the .ami (append to macro with - indirectly specified name), .as (append to user-defined - string), .dei (define macro with indirectly specified name), - .ll (line length), and .rr (remove register) requests. - * The roff(7) parser now supports string comparison and numerical - conditionals in the .if and .ie requests. - * The roff parser now fully supports the \B (validate numerical - expression) and partially supports the \w (measure text width) - escape sequences. - * The terminal formatter now supports the \: (optional line break) - escape sequence. - * The roff parser now supports expansion of user-defined strings - involving indirect references. - * The roff(7) parser now handles some pre-defined read-only - number registers that occur in the pod2man(1) preamble. - * For backward compatibility, the mdoc(7) parser and formatters - now support the obsolete macros .En, .Es, .Fr, and .Ot. - * The mdoc(7) formatter non partially supports .Bd -centered. - * tbl(7) now handles leading and trailing vertical lines. - * The build system now provides fallback versions of strcasestr(3) - and strsep(3) for systems lacking them. - * The mdoc(7) manual now explains how various standards - supported by the .St macro are related to each other. - --- BUGFIXES --- - * In the roff(7) parser, several bugs were fixed with respect - to closing conditional blocks on macro lines. - * Parsing of roff(7) identifiers and escape sequences was improved - in multiple respects. - * In the mdoc(7) parser, the handling of defective document - prologues was improved in multiple ways. - * The mdoc(7) parser no longer skips content before the first section - header, and it no longer deletes non-.% content from .Rs blocks. - * In the mdoc(7) parser, a crash was fixed related to weird .Sh headers. - * In the mdoc(7) parser, handling of .Sm with missing or invalid - arguments was corrected. - * In the mdoc(7) parser, trailing punctuation at the end of partial - implicit macros no longer triggers end-of-sentence spacing. - * In the terminal formatter, two crashes were fixed: one triggered by - excessive indentation and another by excessively long .Nm arguments. - * In the terminal formatter, a floating point rounding bug was - fixed that sometimes caused an off-by-one error in indentation. - * In the UTF-8 formatter, rendering of accents, breakable hyphens, - and non-breakable spaces was corrected. - * In the HTML formatter, encoding of special characters was - corrected in multiple respects. - * In the mdoc(7) formatter, rendering of .Ex and .Rv was - improved for various edge cases. - * In the mdoc(7) formatter, handling of empty .Bl -inset item - heads was improved. - * In the man(7) formatter, some bugs were fixed with respect - to same-line detection in the context of .TP and .nf macros, - and the indentation of .IP and .TP blocks was improved. - * The mandoc(3) library no longer prints to stderr. - --- THANKS TO --- - Abhinav Upadhyay (NetBSD), Andreas Voegele, Anthony Bentley (OpenBSD), - Christian Weisgerber (OpenBSD), Havard Eidnes (NetBSD), Jan Stary, - Jason McIntyre (OpenBSD), Jeremie Courreges-Anglas (OpenBSD), - Joerg Sonnenberger (NetBSD), Juan Francisco Cantero Hurtado (OpenBSD), - Marc Espie (OpenBSD), Matthias Scheler (NetBSD), Pascal Stumpf (OpenBSD), - Paul Onyschuk (Alpine Linux), Sebastien Marie, Steffen Nurpmeso, - Stuart Henderson (OpenBSD), Ted Unangst (OpenBSD), Theo de Raadt (OpenBSD), - Thomas Klausner (NetBSD), and Ulrich Spoerlein (FreeBSD) - for reporting bugs and missing features. - -Changes in version 1.12.3, released on December 31, 2013 - - * In the mdoc(7) SYNOPSIS, line breaks and hanging indentation - now work correctly for .Fo/.Fa/.Fc and .Fn blocks. - Thanks to Franco Fichtner for doing part of the work. - * The mdoc(7) .Bk macro got some addititonal bugfixes. - * In mdoc(7) macro arguments, double quotes can now be quoted - by doubling them, just like in man(7). - Thanks to Tsugutomo ENAMI for the patch. - * At the end of man(7) macro lines, end-of-sentence spacing - now works. Thanks to Franco Fichtner for the patch. - * For backward compatibility, the man(7) parser now supports the - man-ext .UR/.UE (uniform resource identifier) block macros. - * The man(7) parser now handles closing blocks that are not open - more gracefully. - * The man(7) parser now ignores blank lines right after .SH and .SS. - * In the man(7) formatter, reset indentation when leaving a block, - not just when entering the next one. - * The roff(7) .nr request now supports incrementing and decrementing - number registers and stops parsing the number right before the - first non-digit character. - * The roff(7) parser now supports the alternative escape sequence - syntax \C'uXXXX' for Unicode characters. - * The roff(7) parser now parses and ignores the .fam (font family) - and .hw (hyphenation points) requests and the \d and \u escape - sequences. - * The roff(7) manual got a new ESCAPE SEQUENCE REFERENCE. - -Changes in version 1.12.2, released on Oktober 5, 2013 - - * The mdoc(7) to man(7) converter, to be called as mandoc -Tman, - is now fully functional. - * The mandoc(1) utility now supports the -Ios (default operating system) - input option, and the -Tutf8 output mode now actually works. - * The mandocdb(8) utility no longer truncates existing databases when - starting to build new ones, but only replaces them when the build - actually succeeds. - * The man(7) parser now supports the PD macro (paragraph distance), - and (for GNU man-ext compatibility only) EX (example block) and EE - (example end). Plus several bugfixes regarding indentation, line - breaks, and vertical spacing, and regarding RS following TP. - * The roff(7) parser now supports the \f(BI (bold+italic) font escape, - the \z (zero cursor advance) escape and the cc (change control - character) and it (input line trap) requests. Plus bugfixes regarding - the \t (tab) escape, nested escape sequences, and conditional requests. - * In mdoc(7), several bugs were fixed related to UTF-8 output of quoting - enclosures, delimiter handling, list indentation and horizontal and - vertical spacing, formatting of the Lk, %U, and %C macros, plus some - bugfixes related to the handling of syntax errors like badly nested - font blocks, stray Ta macros outside column lists, unterminated It Xo - blocks, and non-text children of Nm blocks. - * In tbl(7), the width of horizontal spans and the vertical spacing - around tables was corrected, and in man(7) files, a crash was fixed - that was triggered by some particular unclosed T{ macros. - * For mandoc developers, we now provide a tbl(3) library manual and - gmdiff, a very small, very simplistic groff-versus-mandoc output - comparison tool. - * Provide this NEWS file. - -Changes in version 1.12.1, released on March 23, 2012 - - * Significant work on apropos(1) and mandocdb(8). These tools are now - much more robust. A whatis(1) implementation is now handled as an - apropos(1) mode. These tools are also able to minimally handle - pre-formatted pages, that is, those already formatted by another - utility such as GNU troff. - * The man.cgi(7) script is also now available for wider testing. - It interfaces with mandocdb(8) manuals cached by catman(8). - HTML output is generated on-the-fly by libmandoc or internal - methods to convert pre-formatted pages. - * The mailing list archive for the discuss and tech lists are being - hosted by Gmane at gmane.comp.tools.mdocml.user and - gmane.comp.tools.mdocml.devel, respectively. - -Changes in version 1.12.0, released on October 8, 2011 - - * This version features a new, work-in-progress mandoc(1) output mode: - -Tman. This mode allows a system maintainer to distribute man(7) - media for older systems that may not natively support mdoc(7), such - as old Solaris systems. - * The -Ofragment option was added to mandoc(1)'s -Thtml and -Txhtml modes. - * While adding features, an apropos(1) utility has been merged from the - mandoc-tools sandbox. This interfaces with mandocdb(8) for semantic - search of manual content. apropos(1) is different from the traditional - apropos primarily in allowing keyword search (such as for functions, - utilities, etc.) and regular expressions. Note that the calling - syntax for apropos is likely to change as it settles down. - * In documentation news, the mdoc(7) and man(7) manuals have been - made considerably more readable by adding MACRO OVERVIEW sections, by - moving the gory details of the LANGUAGE SYNTAX to the roff(7) manual, - and by moving the very technical MACRO SYNTAX sections down to the - bottom of the page. - * Furthermore, for tbl(7), the -Tascii mode horizontal spacing of tables - was rewritten completely. It is now compatible with groff(1), both - with and without frames and rulers. - * Nesting of indented blocks is now supported in man(7), and several - bugs were fixed regarding indentation and alignment. - * The page headers in mdoc(7) are now nicer for very long titles. - -Changes in version 1.11.7, released on September 2, 2011 - - * Added demandoc(1) utility for stripping away macros and escapes. - This replaces the historical deroff(1) utility. - * Also improved the mdoc(7) and man(7) manuals. - -Changes in version 1.11.6, released on August 16, 2011 - - * Handling of tr macro in roff(7) implemented. This makes Perl - documentation much more readable. Hyphenation is also now enabled in - man(7) format documents. Many other general improvements have been - implemented. - -Changes in version 1.11.5, released on July 24, 2011 - - * Significant eqn(7) improvements. mdocml can now parse arbitrary eqn - input (although few GNU extensions are accepted, nor is mixing - low-level roff with eqn). See the eqn(7) manual for details. - For the time being, equations are rendered as simple in-line text. - The equation parser satisfies the language specified in the - Second Edition User's Guide: - http://www.kohala.com/start/troff/v7man/eqn/eqn2e.ps - -Changes in version 1.11.4, released on July 12, 2011 - - * Bug-fixes and clean-ups across all systems, especially in mandocdb(8) - and the man(7) parser. This release was significantly assisted by - participants in OpenBSD's c2k11. Thanks! - -Changes in version 1.11.3, released on May 26, 2011 - - * Introduce locale-encoding of output with the -Tlocale output option and - Unicode escaped-character input. See mandoc(1) and mandoc_char(7), - respectively, for details. This allows for non-ASCII characters (e.g., - \[u5000]) to be rendered in the locale's encoding, if said environment - supports wide-character encoding (if it does not, -Tascii is used - instead). Locale support can be turned off at compile time by removing - -DUSE_WCHAR in the Makefile, in which case -Tlocale is always a synonym - for -Tascii. - * Furthermore, multibyte-encoded documents, such as those in UTF-8, may - be on-the-fly recoded into mandoc(1) input by using the newly-added - preconv(1) utility. Note: in the future, this feature may be - integrated into mandoc(1). - -Changes in version 1.11.2, released on May 12, 2011 - - * Corrected some installation issues in version 1.11.1. - * Further migration to libmandoc. - * Initial public release (this utility is very much under development) - of mandocdb(8). This utility produces keyword databases of manual - content, which features semantic querying of manual content. - -Changes in version 1.11.1, released on April 4, 2011 - - * The earlier libroff, libmdoc, and libman soup have been merged into - a single library, libmandoc, which manages all aspects of parsing - real manuals, from line-handling to tbl(7) parsing. - * As usual, many general fixes and improvements have also occurred. - In particular, a great deal of redundancy and superfluous code has - been removed with the merging of the backend libraries. - * see also the changes in 1.10.10 - -Changes in version 1.10.10, March 20, 2011, NOT released - - * Initial eqn(7) functionality is in place. For the time being, - this is limited to the recognition of equation blocks; - future version of mdocml will expand upon this framework. - -Changes in version 1.10.9, released on January 7, 2011 - - * Many back-end fixes have been implemented: argument handling (quoting), - man(7) improvements, error/warning classes, and many more. - * Initial tbl(7) functionality (see the "TS", "TE", and "T&" macros in - the roff(7) manual) has been merged from tbl.bsd.lv. Output is still - minimal, especially for -Thtml and -Txhtml, but manages to at least - display data. This means that mandoc(1) now has built-in support - for two troff preprocessors via libroff: soelim(1) and tbl(1). - -Changes in version 1.10.8, released on December 24, 2010 - - * Overhauled the -Thtml and -Txhtml output modes. They now display - readable output in arbitrary browsers, including text-based ones like - lynx(1). See HTML and XHTML manuals in the DOCUMENTATION section - for examples. Attention: available style-sheet classes have been - considerably changed! See the example.style.css file for details. - Lastly, libmdoc and libman have been cleaned up and reduced in size - and complexity. - * see also the changes in 1.10.7 - -Changes in version 1.10.7, December 6, 2010, NOT released - - Significant improvements merged from OpenBSD downstream, including: - * many new roff(7) components, - * in-line implementation of troff's soelim(1), - * broken-block handling, - * overhauled error classifications, and - * cleaned up handling of error conditions. - -Changes in version 1.10.6, released on September 27, 2010 - - * Calling conventions for mandoc(1) have changed: -W improved and -f - deprecated. - * Non-ASCII characters are also now uniformly discarded. - * Lots of documentation improvements. - * Many incremental fixes accomodating for groff's more interesting - productions. - * Lastly, pod2man(1) preambles are now fully accepted after some - considerable roff(7) and special character support. - -Changes in version 1.10.5, released on July 27, 2010 - - * Primarily a bug-fix and polish release, but including -Tpdf support - in mandoc(1) by way of "Summer of Code". Highlights: - * fix "Sm" and "Bd" handling - * fix end-of-sentence handling for embedded sentences - * polish man(7) documentation - * document all mdoc(7) macros - * polish mandoc(1) -Tps output - * lots of internal clean-ups in character escapes - * un-break literal contexts in man(7) documents - * improve -Thtml output for -man - * add mandoc(1) -Tpdf support - -Changes in version 1.10.4, released on July 12, 2010 - - * Lots of features developed during both "Summer of Code" and the - OpenBSD c2k10 hackathon: - * minimal "ds" roff(7) symbols are supported - * beautified SYNOPSIS section output - * acceptance of scope-block breakage in mdoc(7) - * clarify error message status - * many minor bug-fixes and formatting issues resolved - * see also changes in 1.10.3 - -Changes in version 1.10.3, June 29, 2010, NOT released - - * variable font-width and paper-size support in mandoc(1) -Tps output - * "Bk" mdoc(7) support - -Changes in version 1.10.2, released on June 19, 2010 - - * Small release featuring text-decoration in -Tps output, - a few minor relaxations of errors, and some optimisations. - -Changes in version 1.10.1, released on June 7, 2010 - - * This primarily focusses on the "Bl" and "It" macros described in - mdoc(7). Multi-line column support is now fully compatible with groff, - as are implicit list entries for columns. - * Removed manuals(7) in favour of http://manpages.bsd.lv. - * The way we handle the SYNOPSIS section (see the SYNOPSIS documentation - in MANUAL STRUCTURE) has also been considerably simplified compared - to groff's method. - * Furthermore, the -Owidth=width output option has been added to -Tascii, - see mandoc(1). - * Lastly, initial PostScript output has been added with the -Tps option - to mandoc(1). It's brutally simple at the moment: fixed-font, with no - font decorations. - -Changes in version 1.10.0, released on May 29, 2010 - - * Release consisting of the results from the m2k10 hackathon and up-merge - from OpenBSD. This requires a significant note of thanks to Ingo - Schwarze (OpenBSD) and Joerg Sonnenberger (NetBSD) for their hard work, - and again to Joerg for hosting m2k10. Highlights (mostly cribbed from - Ingo's m2k10 report) follow in no particular order: - * a libroff preprocessor in front of libmdoc and libman stripping out - roff(7) instructions; - * end-of-sentence (EOS) detection in free-form and macro lines; - * correct handling of tab-separated columnar lists in mdoc(7); - * improved main calling routines to optionally use mmap(3) for better - performance; - * cleaned up exiting when invoked as -Tlint or over multiple files - with -fign-errors; - * error and warning message handling re-written to be unified for - libroff, libmdoc, and libman; - * handling of badly-nested explicit-scoped macros; - * improved free-form text parsing in libman and libmdoc; - * significant GNU troff compatibility improvements in -Tascii, - largely in terms of spacing; - * a regression framework for making sure the many fragilities of GNU - troff aren't trampled in subsequent work; - * support for -Tascii breaking at hyphens encountered in free-form text; - * and many more minor fixes and improvements - -Changes in version 1.9.25, released on May 13, 2010 - - * Fixed handling of "\*(Ba" escape. - * Backed out -fno-ign-chars (pointless complexity). - * Fixed erroneous breaking of literal lines. - * Fixed SYNOPSIS breaking lines before non-initial macros. - * Changed default section ordering. - * Most importantly, the framework for end-of-sentence double-spacing is - in place, now implemented for the "end-of-sentence, end-of-line" rule. - * This is a stable roll-back point before the mandoc hackathon in Rostock! - -Changes in version 1.9.24, released on May 9, 2010 - - * Rolled back break-at-hyphen. - * -DUGLY is now the default (no feature splits!). - * Free-form text is not de-chunked any more: lines are passed - whole-sale into the front-end, including whitespace. - * Added mailing lists. - -Changes in version 1.9.23, released on April 7, 2010 - - * mdocml has been linked to the OpenBSD build. - * This version incorporates many small changes, mostly from patches - by OpenBSD, allowing crufty manuals to slip by with warnings instead - of erroring-out. - * Some subtle semantic issues, such as punctuation scope, have also - been fixed. - * Lastly, some issues with -Thtml have been fixed, which prompted an - update to the online manual pages style layout. - -Changes in version 1.9.22, released on March 31, 2010 - - * Adjusted merge of the significant work by Ingo Schwarze - in getting "Xo" blocks (block full implicit, e.g., "It" - for non-columnar lists) to work properly. This isn't - enabled by default: you must specify -DUGLY as a compiler - flag (see the Makefile for details). - -Changes in version 1.9.20, released on March 30, 2010 - - * More efforts to get roff instructions in man(7) documents under - control. Note that roff instructions embedded in line-scoped, - next-line macros (e.g. "B") are not supported. - * Leading punctuation for mdoc(7) macros, such as "Fl ( ( a", - are now correctly handled. - -Changes in version 1.9.18, released on March 27, 2010 - - * Many fixes (largely pertaining to scope) - and improvements (e.g., handling of apostrophe-control macros, - which fixes the strange "BR" seen in some macro output) - to handling roff instructions in man(7) documents. - -Changes in version 1.9.17, released on March 25, 2010 - - * Accept perlpod(1) standard preamble. - * Also accept (and discard) "de", "dei", "am", "ami", and "ig" - roff macro blocks. - -Changes in version 1.9.16, released on March 22, 2010 - - * Inspired by patches and bug reports by Ingo Schwarze, - allowed man(7) to accept non-printing elements to be nested - within next-line scopes, such as "br" within "B" or "TH", - which is valid roff. - * Longsoon architecture also noted and Makefile cleaned up. - -Changes in version 1.9.15, released on February 18, 2010 - - * Moved to our new BSD.lv home. - * XHTML is now an acceptable output mode for mandoc(1); - * "Xr" made more compatible with groff; - * "Vt" fixed when invoked in SYNOPSIS; - * "\\" escape removed; - * end-of-line white-space detected for all lines; - * subtle bug fixed in list display for some modes; - * compatibility layer checked in for compilation in diverse - UNIX systems; - * and column lengths handled correctly. - -For older releases, see the ChangeLog files -in http://mandoc.bsd.lv/snapshots/ . Index: head/contrib/mdocml/mandoc_char.7 =================================================================== --- head/contrib/mdocml/mandoc_char.7 (revision 338825) +++ head/contrib/mdocml/mandoc_char.7 (nonexistent) @@ -1,808 +0,0 @@ -.\" $Id: mandoc_char.7,v 1.67 2017/06/14 20:57:07 schwarze Exp $ -.\" -.\" Copyright (c) 2003 Jason McIntyre -.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons -.\" Copyright (c) 2011, 2013, 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. -.\" -.Dd $Mdocdate: June 14 2017 $ -.Dt MANDOC_CHAR 7 -.Os -.Sh NAME -.Nm mandoc_char -.Nd mandoc special characters -.Sh DESCRIPTION -This page documents the -.Xr roff 7 -escape sequences accepted by -.Xr mandoc 1 -to represent special characters in -.Xr mdoc 7 -and -.Xr man 7 -documents. -.Pp -The rendering depends on the -.Xr mandoc 1 -output mode; in ASCII output, most characters are completely -unintelligible. -For that reason, using any of the special characters documented here, -except those discussed in the -.Sx DESCRIPTION , -is strongly discouraged; they are supported merely for backwards -compatibility with existing documents. -.Pp -In particular, in English manual pages, do not use special-character -escape sequences to represent national language characters in author -names; instead, provide ASCII transcriptions of the names. -.Ss Dashes and Hyphens -In typography there are different types of dashes of various width: -the hyphen (-), -the minus sign (\(mi), -the en-dash (\(en), -and the em-dash (\(em). -.Pp -Hyphens are used for adjectives; -to separate the two parts of a compound word; -or to separate a word across two successive lines of text. -The hyphen does not need to be escaped: -.Bd -unfilled -offset indent -blue-eyed -lorry-driver -.Ed -.Pp -If a word on a text input line contains a hyphen, a formatter may decide -to insert an output line break after the hyphen if that helps filling -the current output line, but the whole word would overflow the line. -If it is important that the word is not broken across lines in this -way, a zero-width space -.Pq Sq \e& -can be inserted before or after the hyphen. -While -.Xr mandoc 1 -never breaks the output line after hyphens adjacent to a zero-width -space, after any of the other dash- or hyphen-like characters -represented by escape sequences, or after hyphens inside words in -macro arguments, other software may not respect these rules and may -break the line even in such cases. -.Pp -Some -.Xr roff 7 -implementations contains dictionaries allowing to break the line -at syllable boundaries even inside words that contain no hyphens. -Such automatic hyphenation is not supported by -.Xr mandoc 1 , -which only breaks the line at whitespace, and inside words only -after existing hyphens. -.Pp -The mathematical minus sign is used for negative numbers or subtraction. -It should be written as -.Sq \e(mi : -.Bd -unfilled -offset indent -a = 3 \e(mi 1; -b = \e(mi2; -.Ed -.Pp -The en-dash is used to separate the two elements of a range, -or can be used the same way as an em-dash. -It should be written as -.Sq \e(en : -.Bd -unfilled -offset indent -pp. 95\e(en97. -Go away \e(en or else! -.Ed -.Pp -The em-dash can be used to show an interruption -or can be used the same way as colons, semi-colons, or parentheses. -It should be written as -.Sq \e(em : -.Bd -unfilled -offset indent -Three things \e(em apples, oranges, and bananas. -This is not that \e(em rather, this is that. -.Ed -.Pp -Note: -hyphens, minus signs, and en-dashes look identical under normal ASCII output. -Other formats, such as PostScript, render them correctly, -with differing widths. -.Ss Spaces -To separate words in normal text, for indenting and alignment -in literal context, and when none of the following special cases apply, -just use the normal space character -.Pq Sq \ . -.Pp -When filling text, output lines may be broken between words, i.e. at space -characters. -To prevent a line break between two particular words, -use the unpaddable non-breaking space escape sequence -.Pq Sq \e\ \& -instead of the normal space character. -For example, the input string -.Dq number\e\ 1 -will be kept together as -.Dq number\ 1 -on the same output line. -.Pp -On request and macro lines, the normal space character serves as an -argument delimiter. -To include whitespace into arguments, quoting is usually the best choice; -see the MACRO SYNTAX section in -.Xr roff 7 . -In some cases, using the non-breaking space escape sequence -.Pq Sq \e\ \& -may be preferable. -.Pp -To escape macro names and to protect whitespace at the end -of input lines, the zero-width space -.Pq Sq \e& -is often useful. -For example, in -.Xr mdoc 7 , -a normal space character can be displayed in single quotes in either -of the following ways: -.Pp -.Dl .Sq \(dq \(dq -.Dl .Sq \e \e& -.Ss Quotes -On request and macro lines, the double-quote character -.Pq Sq \(dq -is handled specially to allow quoting. -One way to prevent this special handling is by using the -.Sq \e(dq -escape sequence. -.Pp -Note that on text lines, literal double-quote characters can be used -verbatim. -All other quote-like characters can be used verbatim as well, -even on request and macro lines. -.Ss Accents -In output modes supporting such special output characters, for example -.Fl T Cm pdf , -and sometimes less consistently in -.Fl T Cm utf8 , -some -.Xr roff 7 -formatters convert the following ASCII input characters to the -following Unicode special output characters: -.Bl -column x(ga U+2018 -offset indent -.It \(ga Ta U+2018 Ta left single quotation mark -.It \(aq Ta U+2019 Ta right single quotation mark -.It \(ti Ta U+02DC Ta small tilde -.It \(ha Ta U+02C6 Ta modifier letter circumflex -.El -.Pp -In prose, this automatic substitution is often desirable; -but when these characters have to be displayed as plain ASCII -characters, for example in source code samples, they require -escaping to render as follows: -.Bl -column x(ga U+2018 -offset indent -.It \e(ga Ta U+0060 Ta grave accent -.It \e(aq Ta U+0027 Ta apostrophe -.It \e(ti Ta U+007E Ta tilde -.It \e(ha Ta U+005E Ta circumflex accent -.El -.Ss Periods -The period -.Pq Sq \&. -is handled specially at the beginning of an input line, -where it introduces a -.Xr roff 7 -request or a macro, and when appearing alone as a macro argument in -.Xr mdoc 7 . -In such situations, prepend a zero-width space -.Pq Sq \e&. -to make it behave like normal text. -.Pp -Do not use the -.Sq \e. -escape sequence. -It does not prevent special handling of the period. -.Ss Backslashes -To include a literal backslash -.Pq Sq \e -into the output, use the -.Pq Sq \ee -escape sequence. -.Pp -Note that doubling it -.Pq Sq \e\e -is not the right way to output a backslash. -Because -.Xr mandoc 1 -does not implement full -.Xr roff 7 -functionality, it may work with -.Xr mandoc 1 , -but it may have weird effects on complete -.Xr roff 7 -implementations. -.Sh SPECIAL CHARACTERS -Special characters are encoded as -.Sq \eX -.Pq for a one-character escape , -.Sq \e(XX -.Pq two-character , -and -.Sq \e[N] -.Pq N-character . -For details, see the -.Em Special Characters -subsection of the -.Xr roff 7 -manual. -.Pp -Spacing: -.Bl -column "Input" "Description" -offset indent -compact -.It Em Input Ta Em Description -.It Sq \e\ \& Ta unpaddable non-breaking space -.It \e\(ti Ta paddable non-breaking space -.It \e0 Ta unpaddable, breaking digit-width space -.It \e| Ta one-sixth \e(em narrow space, zero width in nroff mode -.It \e^ Ta one-twelfth \e(em half-narrow space, zero width in nroff -.It \e& Ta zero-width space -.It \e% Ta zero-width space allowing hyphenation -.El -.Pp -Lines: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(ba Ta \(ba Ta bar -.It \e(br Ta \(br Ta box rule -.It \e(ul Ta \(ul Ta underscore -.It \e(ru Ta \(ru Ta underscore (width 0.5m) -.It \e(rn Ta \(rn Ta overline -.It \e(bb Ta \(bb Ta broken bar -.It \e(sl Ta \(sl Ta forward slash -.It \e(rs Ta \(rs Ta backward slash -.El -.Pp -Text markers: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(ci Ta \(ci Ta circle -.It \e(bu Ta \(bu Ta bullet -.It \e(dd Ta \(dd Ta double dagger -.It \e(dg Ta \(dg Ta dagger -.It \e(lz Ta \(lz Ta lozenge -.It \e(sq Ta \(sq Ta white square -.It \e(ps Ta \(ps Ta paragraph -.It \e(sc Ta \(sc Ta section -.It \e(lh Ta \(lh Ta left hand -.It \e(rh Ta \(rh Ta right hand -.It \e(at Ta \(at Ta at -.It \e(sh Ta \(sh Ta hash (pound) -.It \e(CR Ta \(CR Ta carriage return -.It \e(OK Ta \(OK Ta check mark -.It \e(CL Ta \(CL Ta club suit -.It \e(SP Ta \(SP Ta spade suit -.It \e(HE Ta \(HE Ta heart suit -.It \e(DI Ta \(DI Ta diamond suit -.El -.Pp -Legal symbols: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(co Ta \(co Ta copyright -.It \e(rg Ta \(rg Ta registered -.It \e(tm Ta \(tm Ta trademarked -.El -.Pp -Punctuation: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(em Ta \(em Ta em-dash -.It \e(en Ta \(en Ta en-dash -.It \e(hy Ta \(hy Ta hyphen -.It \ee Ta \e Ta back-slash -.It \e. Ta \. Ta period -.It \e(r! Ta \(r! Ta upside-down exclamation -.It \e(r? Ta \(r? Ta upside-down question -.El -.Pp -Quotes: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(Bq Ta \(Bq Ta right low double-quote -.It \e(bq Ta \(bq Ta right low single-quote -.It \e(lq Ta \(lq Ta left double-quote -.It \e(rq Ta \(rq Ta right double-quote -.It \e(oq Ta \(oq Ta left single-quote -.It \e(cq Ta \(cq Ta right single-quote -.It \e(aq Ta \(aq Ta apostrophe quote (text) -.It \e(dq Ta \(dq Ta double quote (text) -.It \e(Fo Ta \(Fo Ta left guillemet -.It \e(Fc Ta \(Fc Ta right guillemet -.It \e(fo Ta \(fo Ta left single guillemet -.It \e(fc Ta \(fc Ta right single guillemet -.El -.Pp -Brackets: -.Bl -column "xxbracketrightbtx" Rendered Description -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(lB Ta \(lB Ta left bracket -.It \e(rB Ta \(rB Ta right bracket -.It \e(lC Ta \(lC Ta left brace -.It \e(rC Ta \(rC Ta right brace -.It \e(la Ta \(la Ta left angle -.It \e(ra Ta \(ra Ta right angle -.It \e(bv Ta \(bv Ta brace extension -.It \e[braceex] Ta \[braceex] Ta brace extension -.It \e[bracketlefttp] Ta \[bracketlefttp] Ta top-left hooked bracket -.It \e[bracketleftbt] Ta \[bracketleftbt] Ta bottom-left hooked bracket -.It \e[bracketleftex] Ta \[bracketleftex] Ta left hooked bracket extension -.It \e[bracketrighttp] Ta \[bracketrighttp] Ta top-right hooked bracket -.It \e[bracketrightbt] Ta \[bracketrightbt] Ta bottom-right hooked bracket -.It \e[bracketrightex] Ta \[bracketrightex] Ta right hooked bracket extension -.It \e(lt Ta \(lt Ta top-left hooked brace -.It \e[bracelefttp] Ta \[bracelefttp] Ta top-left hooked brace -.It \e(lk Ta \(lk Ta mid-left hooked brace -.It \e[braceleftmid] Ta \[braceleftmid] Ta mid-left hooked brace -.It \e(lb Ta \(lb Ta bottom-left hooked brace -.It \e[braceleftbt] Ta \[braceleftbt] Ta bottom-left hooked brace -.It \e[braceleftex] Ta \[braceleftex] Ta left hooked brace extension -.It \e(rt Ta \(rt Ta top-left hooked brace -.It \e[bracerighttp] Ta \[bracerighttp] Ta top-right hooked brace -.It \e(rk Ta \(rk Ta mid-right hooked brace -.It \e[bracerightmid] Ta \[bracerightmid] Ta mid-right hooked brace -.It \e(rb Ta \(rb Ta bottom-right hooked brace -.It \e[bracerightbt] Ta \[bracerightbt] Ta bottom-right hooked brace -.It \e[bracerightex] Ta \[bracerightex] Ta right hooked brace extension -.It \e[parenlefttp] Ta \[parenlefttp] Ta top-left hooked parenthesis -.It \e[parenleftbt] Ta \[parenleftbt] Ta bottom-left hooked parenthesis -.It \e[parenleftex] Ta \[parenleftex] Ta left hooked parenthesis extension -.It \e[parenrighttp] Ta \[parenrighttp] Ta top-right hooked parenthesis -.It \e[parenrightbt] Ta \[parenrightbt] Ta bottom-right hooked parenthesis -.It \e[parenrightex] Ta \[parenrightex] Ta right hooked parenthesis extension -.El -.Pp -Arrows: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(<- Ta \(<- Ta left arrow -.It \e(-> Ta \(-> Ta right arrow -.It \e(<> Ta \(<> Ta left-right arrow -.It \e(da Ta \(da Ta down arrow -.It \e(ua Ta \(ua Ta up arrow -.It \e(va Ta \(va Ta up-down arrow -.It \e(lA Ta \(lA Ta left double-arrow -.It \e(rA Ta \(rA Ta right double-arrow -.It \e(hA Ta \(hA Ta left-right double-arrow -.It \e(uA Ta \(uA Ta up double-arrow -.It \e(dA Ta \(dA Ta down double-arrow -.It \e(vA Ta \(vA Ta up-down double-arrow -.It \e(an Ta \(an Ta horizontal arrow extension -.El -.Pp -Logical: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(AN Ta \(AN Ta logical and -.It \e(OR Ta \(OR Ta logical or -.It \e(no Ta \(no Ta logical not -.It \e[tno] Ta \[tno] Ta logical not (text) -.It \e(te Ta \(te Ta existential quantifier -.It \e(fa Ta \(fa Ta universal quantifier -.It \e(st Ta \(st Ta such that -.It \e(tf Ta \(tf Ta therefore -.It \e(3d Ta \(3d Ta therefore -.It \e(or Ta \(or Ta bitwise or -.El -.Pp -Mathematical: -.Bl -column "xxcoproductxx" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(pl Ta \(pl Ta plus -.It \e(mi Ta \(mi Ta minus -.It \e- Ta \- Ta minus (text) -.It \e(-+ Ta \(-+ Ta minus-plus -.It \e(+- Ta \(+- Ta plus-minus -.It \e[t+-] Ta \[t+-] Ta plus-minus (text) -.It \e(pc Ta \(pc Ta center-dot -.It \e(mu Ta \(mu Ta multiply -.It \e[tmu] Ta \[tmu] Ta multiply (text) -.It \e(c* Ta \(c* Ta circle-multiply -.It \e(c+ Ta \(c+ Ta circle-plus -.It \e(di Ta \(di Ta divide -.It \e[tdi] Ta \[tdi] Ta divide (text) -.It \e(f/ Ta \(f/ Ta fraction -.It \e(** Ta \(** Ta asterisk -.It \e(<= Ta \(<= Ta less-than-equal -.It \e(>= Ta \(>= Ta greater-than-equal -.It \e(<< Ta \(<< Ta much less -.It \e(>> Ta \(>> Ta much greater -.It \e(eq Ta \(eq Ta equal -.It \e(!= Ta \(!= Ta not equal -.It \e(== Ta \(== Ta equivalent -.It \e(ne Ta \(ne Ta not equivalent -.It \e(ap Ta \(ap Ta tilde operator -.It \e(|= Ta \(|= Ta asymptotically equal -.It \e(=\(ti Ta \(=~ Ta approximately equal -.It \e(\(ti\(ti Ta \(~~ Ta almost equal -.It \e(\(ti= Ta \(~= Ta almost equal -.It \e(pt Ta \(pt Ta proportionate -.It \e(es Ta \(es Ta empty set -.It \e(mo Ta \(mo Ta element -.It \e(nm Ta \(nm Ta not element -.It \e(sb Ta \(sb Ta proper subset -.It \e(nb Ta \(nb Ta not subset -.It \e(sp Ta \(sp Ta proper superset -.It \e(nc Ta \(nc Ta not superset -.It \e(ib Ta \(ib Ta reflexive subset -.It \e(ip Ta \(ip Ta reflexive superset -.It \e(ca Ta \(ca Ta intersection -.It \e(cu Ta \(cu Ta union -.It \e(/_ Ta \(/_ Ta angle -.It \e(pp Ta \(pp Ta perpendicular -.It \e(is Ta \(is Ta integral -.It \e[integral] Ta \[integral] Ta integral -.It \e[sum] Ta \[sum] Ta summation -.It \e[product] Ta \[product] Ta product -.It \e[coproduct] Ta \[coproduct] Ta coproduct -.It \e(gr Ta \(gr Ta gradient -.It \e(sr Ta \(sr Ta square root -.It \e[sqrt] Ta \[sqrt] Ta square root -.It \e(lc Ta \(lc Ta left-ceiling -.It \e(rc Ta \(rc Ta right-ceiling -.It \e(lf Ta \(lf Ta left-floor -.It \e(rf Ta \(rf Ta right-floor -.It \e(if Ta \(if Ta infinity -.It \e(Ah Ta \(Ah Ta aleph -.It \e(Im Ta \(Im Ta imaginary -.It \e(Re Ta \(Re Ta real -.It \e(wp Ta \(wp Ta Weierstrass p -.It \e(pd Ta \(pd Ta partial differential -.It \e(-h Ta \(-h Ta Planck constant over 2\(*p -.It \e[hbar] Ta \[hbar] Ta Planck constant over 2\(*p -.It \e(12 Ta \(12 Ta one-half -.It \e(14 Ta \(14 Ta one-fourth -.It \e(34 Ta \(34 Ta three-fourths -.It \e(18 Ta \(18 Ta one-eighth -.It \e(38 Ta \(38 Ta three-eighths -.It \e(58 Ta \(58 Ta five-eighths -.It \e(78 Ta \(78 Ta seven-eighths -.It \e(S1 Ta \(S1 Ta superscript 1 -.It \e(S2 Ta \(S2 Ta superscript 2 -.It \e(S3 Ta \(S3 Ta superscript 3 -.El -.Pp -Ligatures: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(ff Ta \(ff Ta ff ligature -.It \e(fi Ta \(fi Ta fi ligature -.It \e(fl Ta \(fl Ta fl ligature -.It \e(Fi Ta \(Fi Ta ffi ligature -.It \e(Fl Ta \(Fl Ta ffl ligature -.It \e(AE Ta \(AE Ta AE -.It \e(ae Ta \(ae Ta ae -.It \e(OE Ta \(OE Ta OE -.It \e(oe Ta \(oe Ta oe -.It \e(ss Ta \(ss Ta German eszett -.It \e(IJ Ta \(IJ Ta IJ ligature -.It \e(ij Ta \(ij Ta ij ligature -.El -.Pp -Accents: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(a" Ta \(a" Ta Hungarian umlaut -.It \e(a- Ta \(a- Ta macron -.It \e(a. Ta \(a. Ta dotted -.It \e(a^ Ta \(a^ Ta circumflex -.It \e(aa Ta \(aa Ta acute -.It \e\(aq Ta \' Ta acute -.It \e(ga Ta \(ga Ta grave -.It \e\(ga Ta \` Ta grave -.It \e(ab Ta \(ab Ta breve -.It \e(ac Ta \(ac Ta cedilla -.It \e(ad Ta \(ad Ta dieresis -.It \e(ah Ta \(ah Ta caron -.It \e(ao Ta \(ao Ta ring -.It \e(a\(ti Ta \(a~ Ta tilde -.It \e(ho Ta \(ho Ta ogonek -.It \e(ha Ta \(ha Ta hat (text) -.It \e(ti Ta \(ti Ta tilde (text) -.El -.Pp -Accented letters: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(\(aqA Ta \('A Ta acute A -.It \e(\(aqE Ta \('E Ta acute E -.It \e(\(aqI Ta \('I Ta acute I -.It \e(\(aqO Ta \('O Ta acute O -.It \e(\(aqU Ta \('U Ta acute U -.It \e(\(aqa Ta \('a Ta acute a -.It \e(\(aqe Ta \('e Ta acute e -.It \e(\(aqi Ta \('i Ta acute i -.It \e(\(aqo Ta \('o Ta acute o -.It \e(\(aqu Ta \('u Ta acute u -.It \e(\(gaA Ta \(`A Ta grave A -.It \e(\(gaE Ta \(`E Ta grave E -.It \e(\(gaI Ta \(`I Ta grave I -.It \e(\(gaO Ta \(`O Ta grave O -.It \e(\(gaU Ta \(`U Ta grave U -.It \e(\(gaa Ta \(`a Ta grave a -.It \e(\(gae Ta \(`e Ta grave e -.It \e(\(gai Ta \(`i Ta grave i -.It \e(\(gao Ta \(`i Ta grave o -.It \e(\(gau Ta \(`u Ta grave u -.It \e(\(tiA Ta \(~A Ta tilde A -.It \e(\(tiN Ta \(~N Ta tilde N -.It \e(\(tiO Ta \(~O Ta tilde O -.It \e(\(tia Ta \(~a Ta tilde a -.It \e(\(tin Ta \(~n Ta tilde n -.It \e(\(tio Ta \(~o Ta tilde o -.It \e(:A Ta \(:A Ta dieresis A -.It \e(:E Ta \(:E Ta dieresis E -.It \e(:I Ta \(:I Ta dieresis I -.It \e(:O Ta \(:O Ta dieresis O -.It \e(:U Ta \(:U Ta dieresis U -.It \e(:a Ta \(:a Ta dieresis a -.It \e(:e Ta \(:e Ta dieresis e -.It \e(:i Ta \(:i Ta dieresis i -.It \e(:o Ta \(:o Ta dieresis o -.It \e(:u Ta \(:u Ta dieresis u -.It \e(:y Ta \(:y Ta dieresis y -.It \e(^A Ta \(^A Ta circumflex A -.It \e(^E Ta \(^E Ta circumflex E -.It \e(^I Ta \(^I Ta circumflex I -.It \e(^O Ta \(^O Ta circumflex O -.It \e(^U Ta \(^U Ta circumflex U -.It \e(^a Ta \(^a Ta circumflex a -.It \e(^e Ta \(^e Ta circumflex e -.It \e(^i Ta \(^i Ta circumflex i -.It \e(^o Ta \(^o Ta circumflex o -.It \e(^u Ta \(^u Ta circumflex u -.It \e(,C Ta \(,C Ta cedilla C -.It \e(,c Ta \(,c Ta cedilla c -.It \e(/L Ta \(/L Ta stroke L -.It \e(/l Ta \(/l Ta stroke l -.It \e(/O Ta \(/O Ta stroke O -.It \e(/o Ta \(/o Ta stroke o -.It \e(oA Ta \(oA Ta ring A -.It \e(oa Ta \(oa Ta ring a -.El -.Pp -Special letters: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(-D Ta \(-D Ta Eth -.It \e(Sd Ta \(Sd Ta eth -.It \e(TP Ta \(TP Ta Thorn -.It \e(Tp Ta \(Tp Ta thorn -.It \e(.i Ta \(.i Ta dotless i -.It \e(.j Ta \(.j Ta dotless j -.El -.Pp -Currency: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(Do Ta \(Do Ta dollar -.It \e(ct Ta \(ct Ta cent -.It \e(Eu Ta \(Eu Ta Euro symbol -.It \e(eu Ta \(eu Ta Euro symbol -.It \e(Ye Ta \(Ye Ta yen -.It \e(Po Ta \(Po Ta pound -.It \e(Cs Ta \(Cs Ta Scandinavian -.It \e(Fn Ta \(Fn Ta florin -.El -.Pp -Units: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(de Ta \(de Ta degree -.It \e(%0 Ta \(%0 Ta per-thousand -.It \e(fm Ta \(fm Ta minute -.It \e(sd Ta \(sd Ta second -.It \e(mc Ta \(mc Ta micro -.It \e(Of Ta \(Of Ta Spanish female ordinal -.It \e(Om Ta \(Om Ta Spanish masculine ordinal -.El -.Pp -Greek letters: -.Bl -column "Input" "Rendered" "Description" -offset indent -compact -.It Em Input Ta Em Rendered Ta Em Description -.It \e(*A Ta \(*A Ta Alpha -.It \e(*B Ta \(*B Ta Beta -.It \e(*G Ta \(*G Ta Gamma -.It \e(*D Ta \(*D Ta Delta -.It \e(*E Ta \(*E Ta Epsilon -.It \e(*Z Ta \(*Z Ta Zeta -.It \e(*Y Ta \(*Y Ta Eta -.It \e(*H Ta \(*H Ta Theta -.It \e(*I Ta \(*I Ta Iota -.It \e(*K Ta \(*K Ta Kappa -.It \e(*L Ta \(*L Ta Lambda -.It \e(*M Ta \(*M Ta Mu -.It \e(*N Ta \(*N Ta Nu -.It \e(*C Ta \(*C Ta Xi -.It \e(*O Ta \(*O Ta Omicron -.It \e(*P Ta \(*P Ta Pi -.It \e(*R Ta \(*R Ta Rho -.It \e(*S Ta \(*S Ta Sigma -.It \e(*T Ta \(*T Ta Tau -.It \e(*U Ta \(*U Ta Upsilon -.It \e(*F Ta \(*F Ta Phi -.It \e(*X Ta \(*X Ta Chi -.It \e(*Q Ta \(*Q Ta Psi -.It \e(*W Ta \(*W Ta Omega -.It \e(*a Ta \(*a Ta alpha -.It \e(*b Ta \(*b Ta beta -.It \e(*g Ta \(*g Ta gamma -.It \e(*d Ta \(*d Ta delta -.It \e(*e Ta \(*e Ta epsilon -.It \e(*z Ta \(*z Ta zeta -.It \e(*y Ta \(*y Ta eta -.It \e(*h Ta \(*h Ta theta -.It \e(*i Ta \(*i Ta iota -.It \e(*k Ta \(*k Ta kappa -.It \e(*l Ta \(*l Ta lambda -.It \e(*m Ta \(*m Ta mu -.It \e(*n Ta \(*n Ta nu -.It \e(*c Ta \(*c Ta xi -.It \e(*o Ta \(*o Ta omicron -.It \e(*p Ta \(*p Ta pi -.It \e(*r Ta \(*r Ta rho -.It \e(*s Ta \(*s Ta sigma -.It \e(*t Ta \(*t Ta tau -.It \e(*u Ta \(*u Ta upsilon -.It \e(*f Ta \(*f Ta phi -.It \e(*x Ta \(*x Ta chi -.It \e(*q Ta \(*q Ta psi -.It \e(*w Ta \(*w Ta omega -.It \e(+h Ta \(+h Ta theta variant -.It \e(+f Ta \(+f Ta phi variant -.It \e(+p Ta \(+p Ta pi variant -.It \e(+e Ta \(+e Ta epsilon variant -.It \e(ts Ta \(ts Ta sigma terminal -.El -.Sh PREDEFINED STRINGS -Predefined strings are inherited from the macro packages of historical -troff implementations. -They are -.Em not recommended -for use, as they differ across implementations. -Manuals using these predefined strings are almost certainly not -portable. -.Pp -Their syntax is similar to special characters, using -.Sq \e*X -.Pq for a one-character escape , -.Sq \e*(XX -.Pq two-character , -and -.Sq \e*[N] -.Pq N-character . -For details, see the -.Em Predefined Strings -subsection of the -.Xr roff 7 -manual. -.Bl -column "Input" "Rendered" "Description" -offset indent -.It Em Input Ta Em Rendered Ta Em Description -.It \e*(Ba Ta \*(Ba Ta vertical bar -.It \e*(Ne Ta \*(Ne Ta not equal -.It \e*(Ge Ta \*(Ge Ta greater-than-equal -.It \e*(Le Ta \*(Le Ta less-than-equal -.It \e*(Gt Ta \*(Gt Ta greater-than -.It \e*(Lt Ta \*(Lt Ta less-than -.It \e*(Pm Ta \*(Pm Ta plus-minus -.It \e*(If Ta \*(If Ta infinity -.It \e*(Pi Ta \*(Pi Ta pi -.It \e*(Na Ta \*(Na Ta NaN -.It \e*(Am Ta \*(Am Ta ampersand -.It \e*R Ta \*R Ta restricted mark -.It \e*(Tm Ta \*(Tm Ta trade mark -.It \e*q Ta \*q Ta double-quote -.It \e*(Rq Ta \*(Rq Ta right-double-quote -.It \e*(Lq Ta \*(Lq Ta left-double-quote -.It \e*(lp Ta \*(lp Ta right-parenthesis -.It \e*(rp Ta \*(rp Ta left-parenthesis -.It \e*(lq Ta \*(lq Ta left double-quote -.It \e*(rq Ta \*(rq Ta right double-quote -.It \e*(ua Ta \*(ua Ta up arrow -.It \e*(va Ta \*(va Ta up-down arrow -.It \e*(<= Ta \*(<= Ta less-than-equal -.It \e*(>= Ta \*(>= Ta greater-than-equal -.It \e*(aa Ta \*(aa Ta acute -.It \e*(ga Ta \*(ga Ta grave -.It \e*(Px Ta \*(Px Ta POSIX standard name -.It \e*(Ai Ta \*(Ai Ta ANSI standard name -.El -.Sh UNICODE CHARACTERS -The escape sequences -.Pp -.Dl \e[uXXXX] and \eC\(aquXXXX\(aq -.Pp -are interpreted as Unicode codepoints. -The codepoint must be in the range above U+0080 and less than U+10FFFF. -For compatibility, the hexadecimal digits -.Sq A -to -.Sq F -must be given as uppercase characters, -and points must be zero-padded to four characters; if -greater than four characters, no zero padding is allowed. -Unicode surrogates are not allowed. -.Sh NUMBERED CHARACTERS -For backward compatibility with existing manuals, -.Xr mandoc 1 -also supports the -.Pp -.Dl \eN\(aq Ns Ar number Ns \(aq -.Pp -escape sequence, inserting the character -.Ar number -from the current character set into the output. -Of course, this is inherently non-portable and is already marked -as deprecated in the Heirloom roff manual. -For example, do not use \eN\(aq34\(aq, use \e(dq, or even the plain -.Sq \(dq -character where possible. -.Sh COMPATIBILITY -This section documents compatibility between mandoc and other -troff implementations, at this time limited to GNU troff -.Pq Qq groff . -.Pp -.Bl -dash -compact -.It -The \eN\(aq\(aq escape sequence is limited to printable characters; in -groff, it accepts arbitrary character numbers. -.It -In -.Fl T Ns Cm ascii , -the -\e(ss, \e(nm, \e(nb, \e(nc, \e(ib, \e(ip, \e(pp, \e[sum], \e[product], -\e[coproduct], \e(gr, \e(-h, and \e(a. special characters render -differently between mandoc and groff. -.It -In -.Fl T Ns Cm html , -the \e(\(ti=, \e(nb, and \e(nc special characters render differently -between mandoc and groff. -.It -The -.Fl T Ns Cm ps -and -.Fl T Ns Cm pdf -modes format like -.Fl T Ns Cm ascii -instead of rendering glyphs as in groff. -.It -The \e[radicalex], \e[sqrtex], and \e(ru special characters have been omitted -from mandoc either because they are poorly documented or they have no -known representation. -.El -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr man 7 , -.Xr mdoc 7 , -.Xr roff 7 -.Sh AUTHORS -The -.Nm -manual page was written by -.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . -.Sh CAVEATS -The predefined string -.Sq \e*(Ba -mimics the behaviour of the -.Sq \&| -character in -.Xr mdoc 7 ; -thus, if you wish to render a vertical bar with no side effects, use -the -.Sq \e(ba -escape. Property changes on: head/contrib/mdocml/mandoc_char.7 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/mdocml =================================================================== --- head/contrib/mdocml (revision 338825) +++ head/contrib/mdocml (nonexistent) Property changes on: head/contrib/mdocml ___________________________________________________________________ Deleted: svn:mergeinfo ## -0,13 +0,0 ## Reverse-merged /projects/bsd_rdma_4_9/contrib/mdocml:r319973-326168 Reverse-merged /projects/clang350-import/contrib/mdocml:r274961-276476 Reverse-merged /projects/clang360-import/contrib/mdocml:r277327-280030 Reverse-merged /projects/clang370-import/contrib/mdocml:r287506-288928 Reverse-merged /projects/clang380-import/contrib/mdocml:r292913-296412 Reverse-merged /vendor/mdocml/dist:r241676-324361 Reverse-merged /projects/clang390-import/contrib/mdocml:r303250-309123 Reverse-merged /projects/clang-trunk/contrib/mdocml:r283596-287505 Reverse-merged /projects/bectl/contrib/mdocml:r336666-337662 Reverse-merged /projects/mpsutil/contrib/mdocml:r286179-290100 Reverse-merged /projects/collation/contrib/mdocml:r286424-290491 Reverse-merged /projects/clang400-import/contrib/mdocml:r311132-314524 Reverse-merged /projects/clang500-import/contrib/mdocml:r316992-321352 Index: head/contrib/mandoc/INSTALL =================================================================== --- head/contrib/mandoc/INSTALL (nonexistent) +++ head/contrib/mandoc/INSTALL (revision 338826) @@ -0,0 +1,159 @@ +$Id: INSTALL,v 1.22 2018/07/31 15:34:00 schwarze Exp $ + +About the portable mandoc distribution +-------------------------------------- +The mandoc manpage compiler toolset (formerly called "mdocml") +is a suite of tools compiling mdoc(7), the roff(7) macro language +of choice for BSD manual pages, and man(7), the predominant +historical language for UNIX manuals. + +It includes a man(1) manual viewer and additional tools. +For general information, see . + +In case you have questions or want to provide feedback, read +. Consider subscribing to the +discuss@ mailing list mentioned on that page. If you intend to +help with the development of mandoc, consider subscribing to the +tech@ mailing list, too. + +Enjoy using the mandoc toolset! + +Ingo Schwarze, Karlsruhe, August 2018 + + +Installation +------------ +Before manually installing mandoc on your system, please check +whether the newest version of mandoc is already installed by default +or available via a binary package or a ports system. A list of the +latest bundled and ported versions of mandoc for various operating +systems is maintained at . + +Regarding how packages and ports are maintained for your operating +system, please consult your operating system documentation. +To install mandoc manually, the following steps are needed: + +1. If you want to build the CGI program, man.cgi(8), too, +run the command "echo BUILD_CGI=1 >> configure.local". +Then run "cp cgi.h.example cgi.h" and edit cgi.h as desired. + +2. If you also want to build the catman(8) utility, run the +command "echo BUILD_CATMAN=1 >> configure.local". Note that it +is unlikely to be a drop-in replacement providing the same +functionality as your system's "catman", if your operating +system contains one. + +3. Define MANPATH_DEFAULT in configure.local +if /usr/share/man:/usr/X11R6/man:/usr/local/man is not appropriate +for your operating system. + +4. Run "./configure". +This script attempts autoconfiguration of mandoc for your system. +Read both its standard output and the file "Makefile.local" it +generates. If anything looks wrong or different from what you +wish, read the file "configure.local.example", create and edit +a file "configure.local", and re-run "./configure" until the +result seems right to you. + +5. Run "make". +Any POSIX-compatible make, in particular both BSD make and GNU make, +should work. If the build fails, look at "configure.local.example" +and go back to step 2. + +6. Run "make -n install" and check whether everything will be +installed to the intended places. Otherwise, put some *DIR or *NM* +variables into "configure.local" and go back to step 4. + +7. Optionally run the regression suite. +Basically, that amounts to "cd regress && ./regress.pl". +But you should probably look at "./mandoc -l regress/regress.pl.1" +first. + +8. Run "sudo make install". If you intend to build a binary +package using some kind of fake root mechanism, you may need a +command like "make DESTDIR=... install". Read the *-install targets +in the "Makefile" to understand how DESTDIR is used. + +9. Run the command "sudo makewhatis" to build mandoc.db(5) databases +in all the directory trees configured in step 3. Whenever installing +new manual pages, re-run makewhatis(8) to update the databases, or +apropos(1) will not find the new pages. + +10. To set up a man.cgi(8) server, read its manual page. + +Note that a very small number of man(7) pages contain low-level +roff(7) markup that mandoc does not yet understand. On some BSD +systems using mandoc, third-party software is vetted on whether it +may be formatted with mandoc. If not, groff(1) is pulled in as a +dependency and used to install pre-formatted "catpages" instead of +manual page sources. This mechanism is used much less frequently +than in the past. On OpenBSD, only 25 out of about 10000 ports +still require formatting with groff(1). + + +Understanding mandoc dependencies +--------------------------------- +The following libraries are required: + +1. zlib for decompressing gzipped manual pages. + +2. The fts(3) directory traversion functions. +If your system does not have them, the bundled compatibility version +will be used, so you need not worry in that case. But be careful: old +glibc versions of fts(3) were known to be broken on 32bit platforms, +see . +That was presumably fixed in glibc-2.23. +If you run into that problem, set "HAVE_FTS=0" in configure.local. + +3. Marc Espie's ohash(3) library. +If your system does not have it, the bundled compatibility version +will be used, so you probably need not worry about it. + +One of the chief design goals of the mandoc toolbox is to make +sure that nothing related to documentation requires C++. +Consequently, linking mandoc against any kind of C++ program +would defeat the purpose and is not supported. + + +Checking autoconfiguration quality +---------------------------------- +If you want to check whether automatic configuration works well +on your platform, consider the following: + +The mandoc package intentionally does not use GNU autoconf because +we consider that toolset a blatant example of overengineering that +is obsolete nowadays, since all modern operating systems are now +reasonably close to POSIX and do not need arcane shell magic any +longer. If your system does need such magic, consider upgrading +to reasonably modern POSIX-compliant tools rather than asking for +autoconf-style workarounds. + +As far as mandoc is using any features not mandated by ANSI X3.159-1989 +("ANSI C") or IEEE Std 1003.1-2008 ("POSIX") that some modern systems +do not have, we intend to provide autoconfiguration tests and +compat_*.c implementations. Please report any that turn out to be +missing. Note that while we do strive to produce portable code, +we do not slavishly restrict ourselves to POSIX-only interfaces. +For improved security and readability, we do use well-designed, +modern interfaces like reallocarray(3) even if they are still rather +uncommon, of course bundling compat_*.c implementations as needed. + +Where mandoc is using ANSI C or POSIX features that some systems +still lack and that compat_*.c implementations can be provided for +without too much hassle, we will consider adding them, too, so +please report whatever is missing on your platform. + +The following steps can be used to manually check the automatic +configuration on your platform: + +1. Run "make distclean". + +2. Run "./configure" + +3. Read the file "config.log". It shows the compiler commands used +to test the libraries installed on your system and the standard +output and standard error output these commands produce. Watch out +for unexpected failures. Those are most likely to happen if headers +or libraries are installed in unusual places or interfaces defined +in unusual headers. You can also look at the file "config.h" and +check that no "#define HAVE_*" differ from your expectations. Index: head/contrib/mandoc/LICENSE =================================================================== --- head/contrib/mandoc/LICENSE (nonexistent) +++ head/contrib/mandoc/LICENSE (revision 338826) @@ -0,0 +1,54 @@ +$Id: LICENSE,v 1.19 2018/07/31 10:18:15 schwarze Exp $ + +With the exceptions noted below, all code and documentation +contained in the mandoc toolkit is protected by the Copyright +of the following developers: + +Copyright (c) 2008-2012, 2014 Kristaps Dzonsons +Copyright (c) 2010-2018 Ingo Schwarze +Copyright (c) 1999, 2004, 2017 Marc Espie +Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger +Copyright (c) 2013 Franco Fichtner +Copyright (c) 2014 Baptiste Daroussin +Copyright (c) 2016 Ed Maste +Copyright (c) 2017 Michael Stapelberg +Copyright (c) 1998, 2004, 2010 Todd C. Miller +Copyright (c) 2008, 2017 Otto Moerbeek +Copyright (c) 2004 Ted Unangst +Copyright (c) 1994 Christos Zoulas +Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre + +See the individual source files for information about who contributed +to which file during which years. + + +The mandoc distribution as a whole is distributed by its developers +under the following license: + +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. + + +The following files included from outside sources are protected by +other people's Copyright and are distributed under various 2-clause +and 3-clause BSD licenses; see these individual files for details. + +soelim.c, soelim.1: +Copyright (c) 2014 Baptiste Daroussin + +compat_err.c, compat_fts.c, compat_fts.h, +compat_getsubopt.c, compat_strcasestr.c, compat_strsep.c, +man.1: +Copyright (c) 1989,1990,1993,1994 The Regents of the University of California + +compat_stringlist.c, compat_stringlist.h: +Copyright (c) 1994 Christos Zoulas Index: head/contrib/mandoc/Makefile =================================================================== --- head/contrib/mandoc/Makefile (nonexistent) +++ head/contrib/mandoc/Makefile (revision 338826) @@ -0,0 +1,577 @@ +# $Id: Makefile,v 1.519 2018/07/31 15:34:00 schwarze Exp $ +# +# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons +# Copyright (c) 2011, 2013-2018 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. + +VERSION = 1.14.4 + +# === LIST OF FILES ==================================================== + +TESTSRCS = test-be32toh.c \ + test-cmsg.c \ + test-dirent-namlen.c \ + test-EFTYPE.c \ + test-err.c \ + test-fts.c \ + test-getline.c \ + test-getsubopt.c \ + test-isblank.c \ + test-mkdtemp.c \ + test-nanosleep.c \ + test-noop.c \ + test-ntohl.c \ + test-O_DIRECTORY.c \ + test-ohash.c \ + test-PATH_MAX.c \ + test-pledge.c \ + test-progname.c \ + test-recvmsg.c \ + test-reallocarray.c \ + test-recallocarray.c \ + test-rewb-bsd.c \ + test-rewb-sysv.c \ + test-sandbox_init.c \ + test-strcasestr.c \ + test-stringlist.c \ + test-strlcat.c \ + test-strlcpy.c \ + test-strndup.c \ + test-strptime.c \ + test-strsep.c \ + test-strtonum.c \ + test-vasprintf.c \ + test-wchar.c + +SRCS = att.c \ + catman.c \ + cgi.c \ + chars.c \ + compat_err.c \ + compat_fts.c \ + compat_getline.c \ + compat_getsubopt.c \ + compat_isblank.c \ + compat_mkdtemp.c \ + compat_ohash.c \ + compat_progname.c \ + compat_reallocarray.c \ + compat_recallocarray.c \ + compat_strcasestr.c \ + compat_stringlist.c \ + compat_strlcat.c \ + compat_strlcpy.c \ + compat_strndup.c \ + compat_strsep.c \ + compat_strtonum.c \ + compat_vasprintf.c \ + dba.c \ + dba_array.c \ + dba_read.c \ + dba_write.c \ + dbm.c \ + dbm_map.c \ + demandoc.c \ + eqn.c \ + eqn_html.c \ + eqn_term.c \ + html.c \ + lib.c \ + main.c \ + man.c \ + man_html.c \ + man_macro.c \ + man_term.c \ + man_validate.c \ + mandoc.c \ + mandoc_aux.c \ + mandoc_ohash.c \ + mandoc_xr.c \ + mandocd.c \ + mandocdb.c \ + manpath.c \ + mansearch.c \ + mdoc.c \ + mdoc_argv.c \ + mdoc_html.c \ + mdoc_macro.c \ + mdoc_man.c \ + mdoc_markdown.c \ + mdoc_state.c \ + mdoc_term.c \ + mdoc_validate.c \ + msec.c \ + out.c \ + preconv.c \ + read.c \ + roff.c \ + roff_html.c \ + roff_term.c \ + roff_validate.c \ + soelim.c \ + st.c \ + tag.c \ + tbl.c \ + tbl_data.c \ + tbl_html.c \ + tbl_layout.c \ + tbl_opts.c \ + tbl_term.c \ + term.c \ + term_ascii.c \ + term_ps.c \ + term_tab.c \ + tree.c + +DISTFILES = INSTALL \ + LICENSE \ + Makefile \ + Makefile.depend \ + NEWS \ + TODO \ + apropos.1 \ + catman.8 \ + cgi.h.example \ + compat_fts.h \ + compat_ohash.h \ + compat_stringlist.h \ + configure \ + configure.local.example \ + dba.h \ + dba_array.h \ + dba_write.h \ + dbm.h \ + dbm_map.h \ + demandoc.1 \ + eqn.7 \ + gmdiff \ + html.h \ + lib.in \ + libman.h \ + libmandoc.h \ + libmdoc.h \ + libroff.h \ + main.h \ + makewhatis.8 \ + man.1 \ + man.7 \ + man.cgi.3 \ + man.cgi.8 \ + man.conf.5 \ + man.h \ + man.options.1 \ + manconf.h \ + mandoc.1 \ + mandoc.3 \ + mandoc.css \ + mandoc.db.5 \ + mandoc.h \ + mandoc_aux.h \ + mandoc_char.7 \ + mandoc_escape.3 \ + mandoc_headers.3 \ + mandoc_html.3 \ + mandoc_malloc.3 \ + mandoc_ohash.h \ + mandoc_xr.h \ + mandocd.8 \ + mansearch.3 \ + mansearch.h \ + mchars_alloc.3 \ + mdoc.7 \ + mdoc.h \ + msec.in \ + out.h \ + predefs.in \ + roff.7 \ + roff.h \ + roff_int.h \ + soelim.1 \ + st.in \ + tag.h \ + tbl.3 \ + tbl.7 \ + term.h \ + $(SRCS) \ + $(TESTSRCS) + +LIBMAN_OBJS = man.o \ + man_macro.o \ + man_validate.o + +LIBMDOC_OBJS = att.o \ + lib.o \ + mdoc.o \ + mdoc_argv.o \ + mdoc_macro.o \ + mdoc_state.o \ + mdoc_validate.o \ + st.o + +LIBROFF_OBJS = eqn.o \ + roff.o \ + roff_validate.o \ + tbl.o \ + tbl_data.o \ + tbl_layout.o \ + tbl_opts.o + +LIBMANDOC_OBJS = $(LIBMAN_OBJS) \ + $(LIBMDOC_OBJS) \ + $(LIBROFF_OBJS) \ + chars.o \ + mandoc.o \ + mandoc_aux.o \ + mandoc_ohash.o \ + mandoc_xr.o \ + msec.o \ + preconv.o \ + read.o + +COMPAT_OBJS = compat_err.o \ + compat_fts.o \ + compat_getline.o \ + compat_getsubopt.o \ + compat_isblank.o \ + compat_mkdtemp.o \ + compat_ohash.o \ + compat_progname.o \ + compat_reallocarray.o \ + compat_recallocarray.o \ + compat_strcasestr.o \ + compat_strlcat.o \ + compat_strlcpy.o \ + compat_strndup.o \ + compat_strsep.o \ + compat_strtonum.o \ + compat_vasprintf.o + +MANDOC_HTML_OBJS = eqn_html.o \ + html.o \ + man_html.o \ + mdoc_html.o \ + roff_html.o \ + tbl_html.o + +MANDOC_TERM_OBJS = eqn_term.o \ + man_term.o \ + mdoc_term.o \ + roff_term.o \ + term.o \ + term_ascii.o \ + term_ps.o \ + term_tab.o \ + tbl_term.o + +DBM_OBJS = dbm.o \ + dbm_map.o \ + mansearch.o + +DBA_OBJS = dba.o \ + dba_array.o \ + dba_read.o \ + dba_write.o \ + mandocdb.o + +MAIN_OBJS = $(MANDOC_HTML_OBJS) \ + $(MANDOC_MAN_OBJS) \ + $(MANDOC_TERM_OBJS) \ + $(DBM_OBJS) \ + $(DBA_OBJS) \ + main.o \ + manpath.o \ + mdoc_man.o \ + mdoc_markdown.o \ + out.o \ + tag.o \ + tree.o + +CGI_OBJS = $(MANDOC_HTML_OBJS) \ + $(DBM_OBJS) \ + cgi.o \ + out.o + +MANDOCD_OBJS = $(MANDOC_HTML_OBJS) \ + $(MANDOC_TERM_OBJS) \ + mandocd.o \ + out.o \ + tag.o + +DEMANDOC_OBJS = demandoc.o + +SOELIM_OBJS = soelim.o \ + compat_err.o \ + compat_getline.o \ + compat_progname.o \ + compat_reallocarray.o \ + compat_stringlist.o + +WWW_MANS = apropos.1.html \ + demandoc.1.html \ + man.1.html \ + mandoc.1.html \ + soelim.1.html \ + man.cgi.3.html \ + mandoc.3.html \ + mandoc_escape.3.html \ + mandoc_headers.3.html \ + mandoc_html.3.html \ + mandoc_malloc.3.html \ + mansearch.3.html \ + mchars_alloc.3.html \ + tbl.3.html \ + man.conf.5.html \ + mandoc.db.5.html \ + eqn.7.html \ + man.7.html \ + mandoc_char.7.html \ + mandocd.8.html \ + mdoc.7.html \ + roff.7.html \ + tbl.7.html \ + catman.8.html \ + makewhatis.8.html \ + man.cgi.8.html \ + man.h.html \ + manconf.h.html \ + mandoc.h.html \ + mandoc_aux.h.html \ + mansearch.h.html \ + mdoc.h.html \ + roff.h.html + +# === USER CONFIGURATION =============================================== + +include Makefile.local + +# === DEPENDENCY HANDLING ============================================== + +all: mandoc demandoc soelim $(BUILD_TARGETS) Makefile.local + +install: base-install $(INSTALL_TARGETS) + +www: $(WWW_MANS) + +$(WWW_MANS): mandoc + +.PHONY: base-install cgi-install install www-install +.PHONY: clean distclean depend + +include Makefile.depend + +# === TARGETS CONTAINING SHELL COMMANDS ================================ + +distclean: clean + rm -f Makefile.local config.h config.h.old config.log config.log.old + +clean: + rm -f libmandoc.a $(LIBMANDOC_OBJS) $(COMPAT_OBJS) + rm -f mandoc $(MAIN_OBJS) + rm -f man.cgi $(CGI_OBJS) + rm -f mandocd catman catman.o $(MANDOCD_OBJS) + rm -f demandoc $(DEMANDOC_OBJS) + rm -f soelim $(SOELIM_OBJS) + rm -f $(WWW_MANS) mandoc.tar.gz mandoc.sha256 + rm -rf *.dSYM + +base-install: mandoc demandoc soelim + mkdir -p $(DESTDIR)$(BINDIR) + mkdir -p $(DESTDIR)$(SBINDIR) + mkdir -p $(DESTDIR)$(MANDIR)/man1 + mkdir -p $(DESTDIR)$(MANDIR)/man5 + mkdir -p $(DESTDIR)$(MANDIR)/man7 + mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_PROGRAM) mandoc demandoc $(DESTDIR)$(BINDIR) + $(INSTALL_PROGRAM) soelim $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) + cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_MAN) + cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_APROPOS) + cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_WHATIS) + cd $(DESTDIR)$(SBINDIR) && \ + $(LN) ${BIN_FROM_SBIN}/mandoc $(BINM_MAKEWHATIS) + $(INSTALL_MAN) mandoc.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1 + $(INSTALL_MAN) soelim.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 + $(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 + $(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 + cd $(DESTDIR)$(MANDIR)/man1 && $(LN) $(BINM_APROPOS).1 $(BINM_WHATIS).1 + $(INSTALL_MAN) man.conf.5 $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 + $(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5 + $(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 + $(INSTALL_MAN) mdoc.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MDOC).7 + $(INSTALL_MAN) roff.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_ROFF).7 + $(INSTALL_MAN) eqn.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_EQN).7 + $(INSTALL_MAN) tbl.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_TBL).7 + $(INSTALL_MAN) mandoc_char.7 $(DESTDIR)$(MANDIR)/man7 + $(INSTALL_MAN) makewhatis.8 \ + $(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8 + +lib-install: libmandoc.a + mkdir -p $(DESTDIR)$(LIBDIR) + mkdir -p $(DESTDIR)$(INCLUDEDIR) + mkdir -p $(DESTDIR)$(MANDIR)/man3 + $(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR) + $(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h roff.h \ + $(DESTDIR)$(INCLUDEDIR) + $(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \ + mansearch.3 mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3 + +cgi-install: man.cgi + mkdir -p $(DESTDIR)$(CGIBINDIR) + mkdir -p $(DESTDIR)$(HTDOCDIR) + $(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR) + $(INSTALL_DATA) mandoc.css $(DESTDIR)$(HTDOCDIR) + +catman-install: mandocd catman + mkdir -p $(DESTDIR)$(SBINDIR) + mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_PROGRAM) mandocd $(DESTDIR)$(SBINDIR) + $(INSTALL_PROGRAM) catman $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN) + $(INSTALL_MAN) mandocd.8 $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_MAN) catman.8 $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8 + +uninstall: + rm -f $(DESTDIR)$(BINDIR)/mandoc + rm -f $(DESTDIR)$(BINDIR)/demandoc + rm -f $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_MAN) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_APROPOS) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_WHATIS) + rm -f $(DESTDIR)$(SBINDIR)/$(BINM_MAKEWHATIS) + rm -f $(DESTDIR)$(MANDIR)/man1/mandoc.1 + rm -f $(DESTDIR)$(MANDIR)/man1/demandoc.1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_WHATIS).1 + rm -f $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 + rm -f $(DESTDIR)$(MANDIR)/man5/mandoc.db.5 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_MDOC).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_ROFF).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_EQN).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_TBL).7 + rm -f $(DESTDIR)$(MANDIR)/man7/mandoc_char.7 + rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8 + rm -f $(DESTDIR)$(CGIBINDIR)/man.cgi + rm -f $(DESTDIR)$(HTDOCDIR)/mandoc.css + rm -f $(DESTDIR)$(SBINDIR)/mandocd + rm -f $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN) + rm -f $(DESTDIR)$(MANDIR)/man8/mandocd.8 + rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8 + rm -f $(DESTDIR)$(LIBDIR)/libmandoc.a + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_escape.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_malloc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mansearch.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mchars_alloc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/tbl.3 + rm -f $(DESTDIR)$(INCLUDEDIR)/man.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_aux.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mdoc.h + rm -f $(DESTDIR)$(INCLUDEDIR)/roff.h + [ ! -e $(DESTDIR)$(INCLUDEDIR) ] || rmdir $(DESTDIR)$(INCLUDEDIR) + +regress: all + cd regress && ./regress.pl + +regress-clean: + cd regress && ./regress.pl . clean + +Makefile.local config.h: configure $(TESTSRCS) + @echo "$@ is out of date; please run ./configure" + @exit 1 + +libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS) + ar rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS) + +mandoc: $(MAIN_OBJS) libmandoc.a + $(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD) + +man.cgi: $(CGI_OBJS) libmandoc.a + $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD) + +mandocd: $(MANDOCD_OBJS) libmandoc.a + $(CC) -o $@ $(LDFLAGS) $(MANDOCD_OBJS) libmandoc.a $(LDADD) + +catman: catman.o libmandoc.a + $(CC) -o $@ $(LDFLAGS) catman.o libmandoc.a $(LDADD) + +demandoc: $(DEMANDOC_OBJS) libmandoc.a + $(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) libmandoc.a $(LDADD) + +soelim: $(SOELIM_OBJS) + $(CC) -o $@ $(LDFLAGS) $(SOELIM_OBJS) + +# --- maintainer targets --- + +www-install: www + $(INSTALL_DATA) $(WWW_MANS) mandoc.css $(HTDOCDIR) + +depend: config.h + mkdep -f Makefile.depend $(CFLAGS) $(SRCS) + perl -e 'undef $$/; $$_ = <>; s|/usr/include/\S+||g; \ + s|\\\n||g; s| +| |g; s| $$||mg; print;' \ + Makefile.depend > Makefile.tmp + mv Makefile.tmp Makefile.depend + +regress-distclean: + @find regress \ + -name '.#*' -o \ + -name '*.orig' -o \ + -name '*.rej' -o \ + -name '*.core' \ + -exec rm -i {} \; + +regress-distcheck: + @find regress ! -type d ! -type f + @find regress -type f \ + ! -path '*/CVS/*' \ + ! -name Makefile \ + ! -name Makefile.inc \ + ! -name '*.in' \ + ! -name '*.out_ascii' \ + ! -name '*.out_utf8' \ + ! -name '*.out_html' \ + ! -name '*.out_markdown' \ + ! -name '*.out_lint' \ + ! -path regress/regress.pl \ + ! -path regress/regress.pl.1 + +dist: mandoc-$(VERSION).sha256 + +mandoc-$(VERSION).sha256: mandoc-$(VERSION).tar.gz + sha256 mandoc-$(VERSION).tar.gz > $@ + +mandoc-$(VERSION).tar.gz: $(DISTFILES) + ls regress/*/*/*.mandoc_* && exit 1 || true + mkdir -p .dist/mandoc-$(VERSION)/ + $(INSTALL) -m 0644 $(DISTFILES) .dist/mandoc-$(VERSION) + cp -pR regress .dist/mandoc-$(VERSION) + find .dist/mandoc-$(VERSION)/regress \ + -type d -name CVS -print0 | xargs -0 rm -rf + chmod 755 .dist/mandoc-$(VERSION)/configure + ( cd .dist/ && tar zcf ../$@ mandoc-$(VERSION) ) + rm -rf .dist/ + +# === SUFFIX RULES ===================================================== + +.SUFFIXES: .1 .3 .5 .7 .8 .h +.SUFFIXES: .1.html .3.html .5.html .7.html .8.html .h.html + +.h.h.html: + highlight -I $< > $@ + +.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc + ./mandoc -Thtml -Wall,stop \ + -Ostyle=mandoc.css,man=%N.%S.html,includes=%I.html $< > $@ Property changes on: head/contrib/mandoc/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/Makefile.depend =================================================================== --- head/contrib/mandoc/Makefile.depend (nonexistent) +++ head/contrib/mandoc/Makefile.depend (revision 338826) @@ -0,0 +1,79 @@ +att.o: att.c config.h mandoc.h roff.h mdoc.h libmdoc.h +catman.o: catman.c config.h compat_fts.h +cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mansearch.h cgi.h +chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h +compat_err.o: compat_err.c config.h +compat_fts.o: compat_fts.c config.h compat_fts.h +compat_getline.o: compat_getline.c config.h +compat_getsubopt.o: compat_getsubopt.c config.h +compat_isblank.o: compat_isblank.c config.h +compat_mkdtemp.o: compat_mkdtemp.c config.h +compat_ohash.o: compat_ohash.c config.h compat_ohash.h +compat_progname.o: compat_progname.c config.h +compat_reallocarray.o: compat_reallocarray.c config.h +compat_recallocarray.o: compat_recallocarray.c config.h +compat_strcasestr.o: compat_strcasestr.c config.h +compat_stringlist.o: compat_stringlist.c config.h compat_stringlist.h +compat_strlcat.o: compat_strlcat.c config.h +compat_strlcpy.o: compat_strlcpy.c config.h +compat_strndup.o: compat_strndup.c config.h +compat_strsep.o: compat_strsep.c config.h +compat_strtonum.o: compat_strtonum.c config.h +compat_vasprintf.o: compat_vasprintf.c config.h +dba.o: dba.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mansearch.h dba_write.h dba_array.h dba.h +dba_array.o: dba_array.c mandoc_aux.h dba_write.h dba_array.h +dba_read.o: dba_read.c mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h +dba_write.o: dba_write.c config.h dba_write.h +dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h +dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.h +demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h +eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h libroff.h +eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h +eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h +html.o: html.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h out.h html.h manconf.h main.h +lib.o: lib.c config.h mandoc.h roff.h mdoc.h libmdoc.h lib.in +main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h tag.h main.h manconf.h mansearch.h +man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h +man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h main.h +man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h +mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h +mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h +mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h +mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h main.h manconf.h +mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h manconf.h mansearch.h dba_array.h dba.h +manpath.o: manpath.c config.h mandoc_aux.h manconf.h +mansearch.o: mansearch.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h +mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h html.h main.h +mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h +mdoc_markdown.o: mdoc_markdown.c mandoc_aux.h mandoc.h roff.h mdoc.h main.h +mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h libmdoc.h +mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h term.h tag.h main.h +mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +msec.o: msec.c config.h mandoc.h libmandoc.h msec.in +out.o: out.c config.h mandoc_aux.h mandoc.h out.h +preconv.o: preconv.c config.h mandoc.h libmandoc.h +read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h +roff.o: roff.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h libmandoc.h roff_int.h libroff.h predefs.in +roff_html.o: roff_html.c mandoc.h roff.h out.h html.h +roff_term.o: roff_term.c mandoc.h roff.h out.h term.h +roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h +soelim.o: soelim.c config.h compat_stringlist.h +st.o: st.c config.h mandoc.h roff.h mdoc.h libmdoc.h st.in +tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h +tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h +tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h +tbl_html.o: tbl_html.c config.h mandoc.h out.h html.h +tbl_layout.o: tbl_layout.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h +tbl_opts.o: tbl_opts.c config.h mandoc.h libmandoc.h libroff.h +tbl_term.o: tbl_term.c config.h mandoc.h out.h term.h +term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h +term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h manconf.h main.h +term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h manconf.h main.h +term_tab.o: term_tab.c mandoc_aux.h out.h term.h +tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h main.h Property changes on: head/contrib/mandoc/Makefile.depend ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/NEWS =================================================================== --- head/contrib/mandoc/NEWS (nonexistent) +++ head/contrib/mandoc/NEWS (revision 338826) @@ -0,0 +1,1070 @@ +$Id: NEWS,v 1.32 2018/08/08 14:47:38 schwarze Exp $ + +This file lists the most important changes in the mandoc.bsd.lv distribution. + +Changes in version 1.14.4, released on August 8, 2018 + + --- MAJOR NEW FEATURES --- + * In ASCII output, render mathematical symbols and greek letters + as transliterations conveying the characters' meanings rather + than trying to imitate their shape. Consequently, such characters + can now be used in portable manual pages. All the same, please + limit their use to contexts where they really matter, for example + when showing complicated mathematical formulae. + * First steps towards better support for small screens in HTML + output (responsive design): avoid most style= attributes, in + particular all hard-coded indentations and column widths, and + provide a better mandoc.css style sheet with a @media query, + using em units throughout, and avoiding redundancy in selectors. + * Better HTML output with some more fitting HTML elements, eliminating + needless class= attributes, and avoiding various HTML syntax errors + (element nesting, URL-fragment syntax, duplicate id= attributes). + --- MINOR NEW FEATURES --- + * When a man(1) argument contains a slash, imply -l like in man-db. + * Use TIOCGWINSZ to reduce the default -Owidth and -Oindent during + interactive use on terminals narrower than 79 columns. + * Generated PostScript files are now more than 50% smaller. + * Terminal rendering of eqn(7) is improved in several respects. + * Simplified and nicer output from the mdoc(7) .Lk macro, formatting + all links in-line, even long ones. + * roff(7) \n+ and \n- numerical register auto-increment and -decrement + * roff(7) .nr optional third argument (auto-increment step size) + * Autodetect in ./configure whether the compiler can use -W and -static, + allowing to build on Solaris 10 and 11 without any configure.local. + --- RELIABILITY BUGFIXES --- + * Only activate UTF-8 output when the user really selected UTF-8, + not some other multibyte character encoding. + * Prevent excessive .ll arguments from generating infinite output. + * Fix out of bounds accesses to parse buffers that could happen when + using renamed or user defined macros after roff(7) conditionals. + * Avoid an assertion failure in certain .Bl -column lists. + * Avoid a NULL pointer access on deroff() failure after '.SS ""'. + * Fix a segfault that could be triggered by two invalid .Dt macros. + * Fix two syntax errors in generated PDF files. + * Properly state the page size in generated PostScript files. + * Close a memory leak caused by missing gzclose(3). + * Fix misformatting of man(7) documents lacking .SH macros + in PostScript and PDF output. + * And many minor bugfixes. + --- THANKS TO --- + * Marc Espie (OpenBSD) for implementing the size reduction of + PostScript files, one additional patch for code simplification, + and two bug reports. + * Theo Buehler (OpenBSD) for a bugfix patch, + and Theo de Raadt (OpenBSD) for checking it. + * John Gardner for more than a dozen suggestions regarding HTML output. + * Mike Williams for teaching me how to use %%DocumentMedia and + setpagedevice in PostScript files. + * Werner Lemberg (groff) for feedback on mdoc(7) language changes. + * Colin Watson (man-db) for feedback on man-db semantics. + * Jason McIntyre (OpenBSD) for lots of feedback and suggestions + on diagnostic messages and on the documentation. + * Thomas Klausner (NetBSD) for suggesting two new style messages + and one new feature, for two bug reports, and for release testing. + * Leah Neukirchen (Void Linux) for suggesting a new style message, + five bug reports, and release testing. + * Anthony Bentley (OpenBSD) for reporting multiple bugs and missing + features. + * Paul Irofti (OpenBSD) and Nate Bargmann for suggesting new features. + * Michael Stapelberg (Debian) for bug reports and release testing. + * Christian Weisgerber, Jonathan Gray, Stuart Henderson, + Ted Unangst (OpenBSD), Takeshi Nakayama (NetBSD), + Anton Lazarov, Jakub Klinkovsky, Jan Stary, Jesper Wallin, + Will Backmam, and Wolfgang Mueller for bug reports. + * Sevan Janiyan (NetBSD) for additions to lib.in. + * George Brown for suggesting code simplifications. + * David Coppa, Igor Sobrado (OpenBSD), and Alexander Kuleshov + for documentation improvements. + * Laura Morales and Raf Czlonka for questions resulting in better + documentation. + * Yuri Pankov (illumos) for release testing. + +Changes in version 1.14.3, released on August 5, 2017 + + --- BUG FIXES --- + * man(7): Do not crash with out-of-bounds read access to a constant + array if .sp or a blank line immediately precedes .SS or .SH. + * mdoc(7): Do not crash with out-of-bounds read access to a constant + array if .sp or a blank line precede the first .Sh macro. + * tbl(7): Ignore explicitly specified negative column widths rather than + wrapping around to huge numbers and risking memory exhaustion. + * man(1): No longer use names that only occur in the SYNOPSIS section. + Gets rid of some surprising behaviour and bogus warnings. + --- THANKS TO --- + Leah Neukirchen (Void Linux), Markus Waldeck (Debian), + Peter Bui (nd.edu), and Yuri Pankov (illumos) for bug reports. + +Changes in version 1.14.2, released on July 28, 2017 + + --- MAJOR NEW FEATURES --- + * New mdoc(7) -Tmarkdown output mode. + * For -Thtml, implement internal hyperlinks pointing to authoritative + definitions of various syntax elements, similar to the ctags(1)-like + less(1) :t internal searching in terminal mode. + * Provide a superset of the functionality of the former mdoclint(1) + utility and a new -Wstyle message level with several new messages, + including validity checking of .Xr cross references. + * tbl(7): Implement automatic line breaking inside individual table + cells, and several other formatting improvements. + * eqn(7): Complete rewrite of the lexer, resulting in several bugfixes. + * Continue parser unification, in particular allowing generation + of syntax tree nodes on the roff(7) level, allowing implementation + of many additional roff requests. + --- REMOVED FUNCTIONALITY --- + * Delete the manpage(1) utility. It was never enabled in any release. + * Delete the -Txhtml command line option. It has been an obsolete + alias for the -Thtml output mode for more than two years. + --- MINOR NEW FEATURES --- + * -Tlint now puts parser messages on stdout instead of stderr, + making commands like "man -l -Tlint *.1" useful. + * mdoc(7): Various .Lk formatting improvements. + * mdoc(7) -Thtml: Better CSS for .Bl lists. + * man(7): Implement the .MT/.ME block macro (mailto hyperlink). + * man(7): Implement the .DT macro (restore default tab positions). + * man(7): Improved support for manuals generated with reStructuredText + by partial support for the \n[an-margin] number register. + * man(7) -Thtml: Support deep linking to .SH and .SS headers. + * tbl(7): Implement the "allbox" table option. + * tbl(7): Implement the column spacing and the 'w' (minimum column + width) layout modifiers. + * tbl(7): Significant improvements of the manual page. + * eqn(7): Much improved font selection, including recognition of + well-known function names, and a few other formatting improvements. + * eqn(7) -Thtml: Use and in addition to . + * roff(7): Implement the .ce (centering), .mc (margin character), + .rj (right justify), .ta (define tab stops), .ti (temporary indent), + .als (macro alias), .ec and .eo (escape character control), + .po (page offset), and .rn (macro rename) requests. + * roff(7) .am: Implement appending to mdoc(7) and man(7) macros. + * roff(7): implement the \h (horizontol motion), \l (horizontal + line drawing), and \p (break output line) escape sequences, + and also several additional character escape sequences. + * roff(7): Implement the 'd' conditional (macro or string defined). + * man.cgi(8) now uses pledge(2), too. + * regress.pl(1): simpler user interface, better summary output, + simpler code, and no more recursion. + --- THANKS TO --- + * Anthony Bentley (OpenBSD) for the implementation of .MT/.ME, + reports of many bugs and missing features, and suggestions + for a number of feature and documentation improvements. + * Sebastien Marie (OpenBSD) for two source code patches and + for some useful discussions. + * Florian Obser (OpenBSD) for a bugfix patch and a bug report. + * Jonathan Gray (OpenBSD) for several bug reports from afl(1) + and several more from static analysis tools. + * Theo Buehler (OpenBSD) for several bug reports, most from afl(1). + * Jason McIntyre (OpenBSD) for many useful discussions about a + wide variety of topics, lots of continuous testing, a number of + bug reports, and some suggestions for messages and documentation. + * Thomas Klausner (NetBSD) for lots of help while migrating + mdoclint(1) functionality to mandoc -Tlint, for suggesting + several useful new messages, and for release testing. + * Reyk Floeter (OpenBSD) and Vsevolod Stakhov (FreeBSD) for + suggesting a markdown output mode. + * Thomas Guettler for suggesting -Thtml internal hyperlinks. + * Yuri Pankov (Illumos) for inspiring new warning messages and + for extensive release testing. + * Anton Lindqvist and TJ Townsend (both OpenBSD) and Jan Stary + for multiple bug reports. + * Leah Neukirchen (Void Linux) for bug reports and release testing. + * Michael Stapelberg (Debian) for suggesting feature improvements + and for release testing. + * Martin Natano and Theo de Raadt (both OpenBSD), Andreas Voegele, + Gabriel Guzman, Gonzalo Tornaria, Markus Waldeck, and Raf Czlonka + for bug reports. + * Antoine Jacoutot (OpenBSD) and Steffen Nurpmeso for suggesting + feature improvements. + * Dag-Erling Smoergrav (FreeBSD) for inspiring new warning messages. + * Ted Unangst and Marc Espie (OpenBSD) for providing useful ideas. + * Svyatoslav Mishyn (Crux Linux) for release testing. + * Carsten Kunze (Heirloom roff) for help keeping mandoc and groff + compatible and for committing some of my patches to groff. + +Changes in version 1.14.1, released on February 21, 2017 + + --- MAJOR NEW FEATURES --- + * apropos(1): Reimplement complete semantic search functionality + without the dependency on SQLite3, using only POSIX APIs. + This comes with a completely new mandoc.db(5) file format. + * man(1): Support more than one tag entry for the same search term, + plus some minor improvements to the less(1) :t support. + * -Thtml: Use real macro names for CSS classes. + Systematic cleanup of and many improvements to mandoc.css. + * -Thtml: Produce human readable HTML code by using indentation + and better line breaks. Improve various HTML elements, + and trim several useless ones. + * New catman(8) utility, still somewhat experimental. + * Now includes a portable version of the OpenBSD mandoc regression + suite, see regress/regress.pl.1 for details. + --- REMOVED FUNCTIONALITY --- + * Operating systems that don't provide mmap(3) are no longer supported. + * Drop support for manpath(1). Even if your system has manpath(1), + it is simpler to use MANPATH_DEFAULT in configure.local for + operating system defaults, man.conf(5) for machine-specific + modifications, and ${MANPATH}, -m, and -M for user preferences + than to bother with the complexity of manpath(1). + * makewhatis(8) -p: No longer warn about missing MLINKS since these + are no longer needed for anything. + --- MINOR NEW FEATURES --- + * mdoc(7): Warn about invalid punctuation and content below NAME. + * mdoc(7): Warn about .Xr lacking the second argument (section). + * mdoc(7): Warn about violations of the rule "new sentence, new line". + * roff(7): Warn about trailing whitespace at the end of comments. + * mdoc(7): Improve rendering of double quotes. + * mdoc(7): Always do text production in the validator, never in the + formatters. Cleaner, simpler, shorter, helps NetBSD apropos(1) + and also makes -Ttree output more useful. + * -Ttree: Show metadata and some additional node flags. + New -Onoval output option to show the unvalidated tree. + --- RELIABILITY BUGFIXES --- + * man(1): Make "man -l" work with standard input from a pipe or file, + as long as standard output is a terminal. + * man(7): Fix out of bounds read access if a text node immediately + preceded the first .SH header. + * mdoc(7): Fix out of bounds read access for .Bl without a type + but with a width. + * mdoc(7): Fix out of bounds read access for .Bl -column starting + with a tab character instead of a child .It macro. + * mdoc(7): Fix syntax tree corruption leading to segfaults caused + by stray block end macros in nested blocks of mismatching type. + * man(1): Fix NULL dereference when the first of multiple pages + shown was preformatted. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + caused by partial implicit macros inside .Bl -column table cells. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + for macro sequences like .Bl .Bl .It Bo .El .It. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + caused by .Ta following a nested .Bl -column breaking another block. + * mdoc(7): Fix syntax tree corruption sometimes leading to NULL + dereference caused by indirectly broken .Nd or .Nm blocks. + * mdoc(7) -Thtml: Fix a NULL dereference for .Bl -column with 0 columns. + * mdoc(7): Fix NULL dereference in some specific cases of a + block-end macro calling another block-end macro. + * mdoc(7): Fix NULL dereference if the only child of the head + of the first .Sh was an empty in-line macro. + * eqn(7): Fix NULL dereference in the terminal formatter + for empty matrices and empty square roots. + * mdoc(7): Fix an assertion failure for a .Bd without a type that + breaks another block. + * mdoc(7): Fix an assertion failure that happened for some .Bl -column + lists containing a column width of "-4n", "-3n", or "-2n". + * mdoc(7): Fix an assertion failure caused by .Bl -column without .It + but containing eqn(7) or tbl(7) code. + * roff(7): Fix an assertion failure caused by \z\[u00FF] with -Tps/-Tpdf. + * roff(7): Fix an assertion failures caused by whitespace inside \o'' + (overstrike) sequences. + * -Thtml: Fix an assertion failure caused by -Oman or -Oincludes of + excessive length. + --- PORTABILITY IMPROVEMENTS --- + * man(1): Do not mix stdio narrow and wide stream orientation + on stdout, which could cause output corruption on glibc. + * mandoc(1): Autodetect a suitable locale for -Tutf8 mode. + * ./configure: Autodetect whether PATH_MAX and O_DIRECTORY are defined. + * ./configure: Autodetect if nanosleep(3) needs -lrt. + * ./configure: Provide an ${LN} configuration variable. + * ./configure: Put compiler arguments that may contain -l at the end. + --- MINOR BUGFIXES --- + * mdoc(7): Fix SYNOPSIS output if the first child of .Nm is a macro. + * mdoc(7) -Thtml: Improve formatting of .Bl -tag with short tags. + * man(7) -Thtml: Preserve whitespace in .nf (nofill) mode. + * mandoc(1): Error out on invalid output options on the command line. + --- STRUCTURAL CHANGES, no functional change --- + * Redesign part of the mandoc_html(3) interfaces, making them much + easier to use and reducing the amount of code by a few hundred lines. + --- THANKS TO --- + * Michael Stapelberg (Debian) for designing the new mandocd(8) + and parts of the new catman(8), for release testing, and for a + number of patches and bug reports. + * Baptiste Daroussin (FreeBSD) for profiling the new makewhatis(8) + implementation and suggesting an algorithmic improvement which + more than doubled performance, and for a few bug reports. + * Ed Maste (FreeBSD) for an important patch improving reproducibility + of builds in makewhatis(8), and for a few bug reports. + * Theo Buehler (OpenBSD) for almost twenty important bug reports, + most of them found by systematic afl(1) fuzzing. + * Benny Lofgren, David Dahlberg, and in particular Vadim Zhukov + for crucial help in getting .Bl -tag CSS formatting fixed. + * Svyatoslav Mishyn (Crux Linux) for an initial version of the + patch to autodetect a suitable locale for -Tutf8 mode + and for release testing. + * Jason McIntyre (OpenBSD) for multiple useful discussions + and a number of bug reports. + * Sevan Janiyan (NetBSD) for extensive release testing and multiple + bug reports. + * Thomas Klausner and Christos Zoulas (NetBSD), Yuri Pankov (illumos), + and Leah Neukirchen (Void Linux) for release testing and bug reports. + * Ulrich Spoerlein (FreeBSD) for release testing. + * Alexander Bluhm, Andrew Fresh, Antoine Jacoutot, Antony Bentley, + Christian Weisgerber, Jonathan Gray, Marc Espie, Martijn van Duren, + Stuart Henderson, Ted Unangst, Theo de Raadt (OpenBSD), Abhinav + Upadhyay, Kamil Rytarowski (NetBSD), Aaron M. Ucko, Bdale Garbee, + Reiner Herrmann, Shane Kerr (Debian), Daniel Sabogal (Alpine Linux), + Carsten Kunze (Heirloom roff), Kristaps Dzonsons (bsd.lv), + Anton Lindqvist, Jan Stary, Jeremy A. Mates, Mark Patruck, + Pavan Maddamsetti, Sean Levy , and + Tiago Silva for bug reports. + * Brent Cook, Marc Espie, Philip Guenther, Todd Miller (OpenBSD) + and Markus Waldeck for useful discussions. + * And as usual, OpenCSW for providing me with a Solaris 9/10/11 + testing environment. + +Changes in version 1.13.4, released on July 14, 2016 + + --- MAJOR NEW FEATURES --- + * man.conf(5): Design and implement a simpler configuration file format. + * man(1): Leverage less(1) -T and :t in a way resembling ctags(1) + to jump to the definitions of various terms inside manual pages. + * soelim(1): New implementation by Baptiste Daroussin. + * privilege limitation: Use OpenBSD pledge(2) or OS X sandbox_init(3) + when available. + * man.cgi(8): Support short URIs like http://man.openbsd.org/mdoc . + * mandoc.css: Use one unified stylesheet rather than three different ones. + --- MAJOR FUNCTIONALLY RELEVANT BUGFIXES --- + * mdoc(7): Fix multiple aspects of SYNOPSIS .Nm formatting. + * man(1): Fix process group handling, avoiding unclean shutdowns. + --- PORTABILITY IMPROVEMENTS --- + * Correctly use the ohash(3) compatibility implementation + even when building without SQLite support. + * Add compat glue for building on Solaris 9 and 10. + * Let ./configure select a supported RE syntax for word boundaries. + * Support LDFLAGS, to be used for example for hardening options. + * Avoid mixing putchar(3) and putwchar(3) on the same file descriptor, + it resulted in output corruption on some platforms. + * Avoid reusing va_lists, use va_copy(3) for better portability. + * Do not hardcode the path to the more(1) program. + --- MINOR NEW FEATURES --- + * roff(7): Implement \n(.$ (number of macro arguments). + * roff(7): Fully implement \z (do not advance cursor). + * roff(7): Implement the `r' conditional (register exists). + * roff(7): Implement \\$* (interpolate all arguments). + * roff(7): Parse and ignore \, and \/ (italic corrections). + * When there is no -m, no -M, no MANPATH and no /etc/man.conf, + fall back to /usr/share/man:/usr/X11R6/man:/usr/local/man. + * man(1): Give manuals in purely numerical sections priority over + manuals of the same name in sections with an alphabetical suffix. + * man.cgi(8): Support "header.html" and "footer.html". + * man.cgi(8): Set the "autofocus" attribute on the query text box. + * man.cgi(8): Simplify the search form, drop two useless buttons. + * man.cgi(8): Delete the pseudo-manpath "mandoc", assume that + apropos(1) and man.cgi(8) are installed in the default manpath. + --- RELIABILITY BUGFIXES --- + * mdoc(7): Avoid a use after free and an assertion failure when nodes + are deleted during validation. + * mdoc(7): Avoid a NULL pointer access when .Bd has no arguments. + * mdoc(7): Avoid a NULL pointer access triggered by mismatching end macros. + * mdoc(7): Avoid an assertion when .Fo has no argument. + * mdoc(7): Avoid an assertion when .Ta occurs in .Bl -column. + * mdoc(7): Avoid an assertion when a body gets broken and has a tail. + * roff(7): Avoid an assertion caused by blanks inside \o. + * roff(7): Make .so links to gziped manuals work without mandoc.db(5). + * tbl(7): Avoid a use after free when the last line of a layout is empty. + * eqn(7): Avoid an infinite loop caused by recursive "define". + * makewhatis(8): Avoid a segfault caused by unusual directory structures. + * Fix handling of leading, trailing, and double colons in MANPATH and -m. + --- MINOR BUGFIXES --- + * mdoc(7): Put arguments to end macros of broken partial explicit blocks + inside the breaking block. + * mdoc(7): Let .Dv force normal font. + * mdoc(7): Make trailing whitespace significant in .Bl -tag widths. + * mdoc(7): Fix macro interpretation around tabs in .Bl -column. + * man(7): Use the default width for .RS without arguments. + * man(7): On a new RS nesting level, the saved width starts from + the default width, not from the saved width of the previous level. + * man(7): Allow .PD in next-line scope. + * man(7): Improve handling of empty .HP. + * man(7): Improve formatting of .br and .sp inside .HP. + * man(7): Do not mistreat empty arguments to font alternating + macros as vertical spacing requests. + * man(7): Allow fill mode changes in tagged paragraph next-line scope. + * man(7): Fix minor bugs in block rewinding and simplify the related code. + * man(7): Add missing line breaks before subsection headers. + * man(7): Give section and subsection headers hanging indentation. + * man(7): Make trailing whitespace significant in .TP widths. + * roff(7): Don't allow breaking the output line after hyphens + that immediately follow escape sequences. + * roff(7): Ignore blank characters at the beginning of conditional blocks. + * roff(7): Escape breakable hyphens only after handling input line traps. + * roff(7): Reject \[uD800] to \[uDFFF] (surrogates) in the parser. + * tbl(7): Allow more than one data field after T} on the same input line. + * terminal output: Apply bold and italic to non-ASCII Unicode codepoints. + * terminal output: Improve rounding rules for horizontal scaling widths. + * HTML output: Render ASCII_NBRSP as " ", not "-". + * man(1): Do not match the first part of a name if it continues with a dot. + * man(1): Keep working even if the current directory is unusable. + * man(1): Better error message when $PAGER is invalid. + * makewhatis(8): Improve handling of .Va and .Vt macros. + * apropos(1): Print "nothing appropriate" to stderr when appropriate. + * apropos(1): Abort with a useful error message when elementary + database operations like preparing queries or binding variables fail. + --- STRUCTURAL CHANGES, no functional change --- + * mdoc(7) and man(7): Unified data structures struct roff_node etc. + * mdoc(7) and man(7): Unified node handling library in roff.c. + * mdoc(7) and man(7): Seperate validation phase from parsing. + * roff(7): Major character table cleanup. + * Link with libz rather than forking gunzip(1). + --- THANKS TO --- + * Baptiste Daroussin (FreeBSD) for the new soelim(1) + and for release testing. + * Anthony Bentley (OpenBSD) for unifying mandoc.css, two nice + patches for man.cgi(8), some documentation patches, some bug + reports, and various useful discussions. + * Todd Miller (OpenBSD) for lots of help with process group and + signal handling, a few patches, some bug reports and some useful + discussions. + * Jonathan Gray (OpenBSD) for yet more testing with afl(1) + again resulting in more than half a dozen important bug reports. + * Svyatoslav Mishyn (Crux Linux) for some patches, several bug + reports, and extensive release testing. + * Leah Neukirchen (Void Linux) for a number of compatibility + patches and suggestions and several bug reports. + * Christos Zoulas (NetBSD) for a bug fix patch and some useful + suggestions for cleanup. + * Florian Obser (OpenBSD) for a bugfix patch and some bug reports. + * Sevan Janiyan for help with Solaris compatibility and release + testing on many platforms. + * Jan Holzhueter and OpenCSW in general for help with Solaris + compatibility, and for providing me with a Solaris 9/10/11 testing + environment. + * Michael McConville (OpenBSD) for some simple cleanup patches. + * Thomas Klausner (NetBSD) for some bug reports and release testing. + * Christian Weisgerber, Dmitrij Czarkoff, Igor Sobrado, + Ken Westerback, Marc Espie, Mike Belopuhov, Rafael Neves, + Ted Unangst, Tim van der Molen, Theo Buehler, Theo de Raadt + (OpenBSD), Kurt Jaeger, Dag Erling Smoergrav (FreeBSD), + Joerg Sonnenberger (NetBSD), Carsten Kunze (Heirloom troff), + Daniel Levai, Fabian Raetz, Jan Stary, Jean-Yves Migeon, + Lorenzo Beretta, Markus Waldeck, Maxim Belooussov, Michael Reed, + Peter Bray, and Serguey Parkhomovsky for bug reports and feature + suggestions. + * Alexander Hall, Andrew Fresh, Antoine Jacoutot, Doug Hogan, + Jason McIntyre, Jasper Lievisse Adriaanse, Kent Spillner, + Nicholas Marriott, Peter Hessler, Sebastien Marie, Stefan Sperling, + and Theo de Raadt (OpenBSD) for helpful discussions and feedback. + +Changes in version 1.13.3, released on March 13, 2015 + + --- MAJOR NEW FEATURES --- + * When a manual is missing from an outdated database, let man(1) + show it anyway, using a KISS file system lookup as a fallback. + * Use this to always provide man(1), even without database support. + * Fatal errors no longer exist. If a file can be opened, mandoc + will produce some output; at worst, the output may be almost empty. + * New -Wunsupp message level. + --- POTENTIONALLY SECURITY RELEVANT BUGFIXES --- + * Fix a potential write buffer overrun on incomplete string conditionals. + http://mandoc.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.241 + * Fix a potential write buffer overrun on backslash at EOF in a conditional. + http://mandoc.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.247 + * Fix a use after free sometimes hit when validation deletes a block. + http://mandoc.bsd.lv/cgi-bin/cvsweb/mdoc_macro.c#rev1.180 + --- MAJOR FUNCTIONALLY RELEVANT BUGFIXES --- + * Let man(1) show manuals for the current architecture by default, + and support the MACHINE environment variable. + * Fix the man(1) and apropos(1) -m option, it didn't work at all. + * Do not spawn a pager when there is no output. + * In makewhatis(8), fix detection of hardlinked manuals on platforms + having padding in struct inodev (typically 64bit platforms). + --- PORTABILITY IMPROVEMENTS --- + * Ignore O_CLOEXEC when the operating system doesn't provide it. + * Avoid forward reference to enum type which violates ISO C99. + * Support homebrew-style linking on Mac OS X. + --- MINOR NEW FEATURES --- + * lookup: Accept digit+letter and "n" as section names in man(1), + and consistently handle digit+letter in file name extensions. + * lookup: Speed up -s/-S by using the "mlinks" rather than the "keys" table. + * output: Insert horizontal lines between formatted manual pages. + * input: New stricter and more resilient UTF-8 parser. + * mdoc(7): Refactor block rewinding for simpler and more robust parsing. + * man(7): Use the -Ios option when .TH has less than four arguments. + * tbl(7): Implement the "center" option. + * tbl(7): New option and format parsers, improved in many respects. + * roff(7): Basic implementation of the \o escape sequence (overstrike), + and improved rendering of overstrikes in PostScript and PDF output. + * Message improvements, in particular for, but not restricted to, + eqn(7), tbl(7), and wrong numbers of arguments in mdoc(7) and man(7), + in various cases also improving output generated by invalid input. + * Delete the -V option. It serves no purpose but keeps confusing people. + * gmdiff: Minimal support for Heirloom roff. + --- RELIABILITY BUGFIXES --- + * tbl(7): Fix a read buffer overrun on 'f' at EOL in a layout. + * roff(7): Fix a read buffer overrun on incomplete numerical conditions. + * mdoc(7): Fix a NULL pointer access on .Nd followed by an explicit block. + * mdoc(7): Fix a NULL pointer access on .It Xo without .Xc. + * mdoc(7): Fix a NULL pointer access on .Eo without a tail. + * mdoc(7): Fix a NULL pointer access in the validation of empty .St macros. + * man(7)/tbl(7): Fix a NULL pointer access on .TS right after .TP. + * tbl(7): Fix a NULL pointer access on layout lines without any cells. + * eqn(7): Fix NULL pointer accesses in the terminal formatter. + * roff(7): Fix a NULL pointer access on trailing \s-/\s+ without an argument. + * gz: Fix a potential NULL pointer access after waitpid() failure. + * roff(7): Don't let the modulo operator divide by zero. + * input: Fix an assertion failure on certain invalid UTF-8 input. + * terminal output: Allow arbitrary depth of the font stack (assertion fix). + * mdoc(7): Fix assertion failures and endless loops on invalid block closing. + * mdoc(7): Fix an assertion failure on .Bl .Sm not followed by .It. + * mdoc(7): Fix an assertion failure on .Bl -column ... .El .Ta. + * tbl(7): Fix assertion failures by macros inside table data, + but do not throw away the macro arguments. + * Prevent certain kinds of unreasonable input from producing excessive + output, in one case caused by unsigned integer underflow. + * Fix a potential memory leak in makewhatis(8) on very long filenames. + --- MINOR BUGFIXES --- + * mdoc(7): Fix parsing of badly nested blocks with multiple identical blocks. + * mdoc(7): Support negative indentations for displays and lists. + * mdoc(7): Don't mistreat negative .sp arguments as large positive ones. + * mdoc(7): Some spacing fixes for .Eo/.Ec. + * man(7): Support negative horizontal widths. + * man(7): Do not print out invalid .IP arguments. + * man(7): Correctly handle scaling units after .PD. + * man(7): Support .RE with an argument. + * man(7): Fix restoring indentation after .RS with large negative arguments. + * tbl(7): Prevent tables from breaking the filling of preceding text. + * tbl(7): Fix vertical spacing at the beginning of tables. + * tbl(7): Parser and formatter fixes for line drawing and font modifiers. + * tbl(7): Correct handling of blank data lines. + * eqn(7): Add sometimes missing whitespace before equation output. + * roff(7): Fix vertical scaling, most of it was wrong. + * roff(7): Slightly improve \w width measurements. + * roff(7): Accept the historic aliases \s10 to \s39 for \s(10 to \s(39. + * roff(7): Correctly escape quotes when expanding macro arguments. + * roff(7): Correctly handle scaling units in numerical expressions, + and some other improvements to the parsing of numerical expressions. + * roff(7): Three minor fixes with respect to evaluation of conditionals. + * roff(7): Let .it accept numerical expressions, not just constants. + * mandoc_char(7): Correct some character names and renderings. + * If earlier files set a non-zero exit status, never reset it to zero. + --- THANKS TO --- + * Jonathan Gray (OpenBSD) for yet more testing with afl (the American + Fuzzy Lop security fuzzer), again resulting in many bug reports. + * Theo de Raadt (OpenBSD) for suggesting the main new feature (man(1) file + system lookup) and for reporting an important bug (pager without output). + * Theo Buehler for an important bug report (-s/-S slowness) + and for proposing a nice new feature (lines between pages). + * Jason McIntyre for an important bug report (hardlink detection) + and multiple documentation patches. + * Pascal Stumpf (OpenBSD) and Alessandro de Laurenzis for + important bug reports (architecture and man -m, respectively). + * Thomas Klausner (NetBSD) for proposing a new feature (man(7) -Ios), + a bug report, and release testing. + * Anthony Bentley, Daniel Dickman, Ted Unangst (OpenBSD) and + Kristaps Dzonsons (bsd.lv) for source code patches and bug reports. + * Christian Weisgerber (OpenBSD) for more than half a dozen bug reports. + * Carsten Kunze (Heirloom troff) for bug reports and release testing. + * Antoine Jacoutot (OpenBSD) for release testing. + * Alexis Hildebrandt (Homebrew), Baptiste Daroussin (FreeBSD), + Jonathan Perkin (SmartOS), Pedro Giffuni (FreeBSD), Svyatoslav + Mishyn (Crux Linux), Ulrich Spoerlein (FreeBSD), Jan Stary, Patrick + Keshishian, Sebastien Marie, and Steffen Nurpmeso for bug reports. + +Changes in version 1.13.2, released on December 13, 2014 + + --- MAJOR NEW FEATURES --- + * Include an implementation of man(1), the manual page viewer. + * Unified set of command line option, each one supported by all + command names, including new options -a (format all), -c (no + pager), -h (synopsis only), and -w (list filenames). + * Support the MANPAGER and PAGER environment variables. + * Support gzip'ed manuals by the whole toolset, even as .so targets. + * Support UTF-8 and Latin-1 input by the whole toolset, delete preconv(1). + * Switch the default output mode from -Tascii to -Tlocale. + * Improve -Tascii output for Unicode escape sequences. + * Let the -Thtml output mode produce polyglot HTML5. + * Many improvements for eqn(7), in particular in-line equations, + MathML output in -Thtml mode, and much improved terminal formatting. + --- PORTABILITY IMPROVEMENTS --- + * Change the build sequence to the usual ./configure; make; make install. + * Support ./configure.local for build customizations. + * Autodetect wchar, sqlite3, and manpath support. + * Provide a fallback version of fts(3) for systems lacking it. + * Support choosing alternative binary and manual names. + --- MINOR NEW FEATURES --- + * Rudimentary implementation of the e, x, and z tbl(7) layout + modifiers to equalize, maximize, and ignore the width of columns. + * Implement font modifiers in tbl(7) layouts. + * Allow comma-separated options in the tbl(7) options line. + * Parse and ignore the .pl (page length) roff(7) request. + * Implement .An -[no]split for the mdoc(7) -Thtml output mode. + * Support bold italic font in PostScript and PDF output. + * Warn about commas in function arguments and parentheses in function names. + * Warn about botched .Xr ordering and punctuation below SEE ALSO. + * Warn about AUTHORS sections without .An macros. + * Warn about attempts to call non-callable macros. + * New developer documentation manual page mandoc_headers(3). + --- BUGFIXES --- + * Fix read buffer overrun sometimes triggered by trailing whitespace. + * Fix read buffer overrun triggered by certain invalid \H sequences. + * Fix NULL pointer access triggered by .Bl without any arguments. + * Fix NULL pointer access triggered by .It Nm Fo without .Fc. + * Fix NULL pointer access triggered by .Sh Xo .Sh without .Xc. + * Fix NULL pointer access triggered by missing .Nm. + * Fix an assertion triggered by .It right after .El. + * Fix an assertion triggered by .Ec without preceding .Eo. + * Fix an assertion triggered by .Sm or .Db with multiple arguments. + * Fix assertion failures triggered by very large width arguments. + * Fix a division by zero in the roff(7) parser. + * Prevent negative arguments to .ll from causing integer underflow. + * Correctly autodetect source format even when .Dd is preceded by .ll. + * Multiple fixes with respect to .Bd and .Bl -offset and -width. + * Many bugfixes with respect to scaling units. + * Multiple fixes with respect to delimiter handling by in-line macros. + * Multiple fixes with respect to .Pf. + * Make \c work properly in no-fill mode. + * Stricter syntax checking of Unicode character names. + --- THANKS TO --- + * Kristaps Dzonsons for rewriting the eqn(7) parser, implementing + HTML5 and MathML output, and various other code contributions. + * Jonathan Gray (OpenBSD) for extensive testing with afl (the + American Fuzzy Lop security fuzzer) resulting in many bug reports. + * Anthony Bentley (OpenBSD), Baptiste Daroussin (FreeBSD), Daniel + Dickman, Doug Hogan, Jason McIntyre, Theo de Raadt (OpenBSD), + and Martin Natano for source code patches. + * Carsten Kunze (Heirloom troff), Daniel Levai (Slackware), + Garrett D'Amore (illumos), Giovanni Becchis, Matthew Dempsky, + Stuart Henderson, Ted Unangst, Todd Miller (OpenBSD), Thomas + Klausner (NetBSD), Ulrich Spoerlein (FreeBSD), Justin Haynes, + Marcus Merighi, Sebastien Marie, Steffen Nurpmeso and Theo Buehler + for bug reports. + +Changes in version 1.13.1, released on August 10, 2014 + + --- MAJOR NEW FEATURES --- + * A complete apropos(1)/makewhatis(8)/man.cgi(8) suite + based on SQLite3 is now included. + * The roff(7) parser now provides an almost complete implementation + of numerical expressions. + * Warning and error messages have been improved in many ways. + Almost all fatal errors were downgraded to normal errors and some + even to warnings. Almost all messages now mention the macro where + the issue is detected and many indicate the workaround employed. + The mandoc(1) manual now includes a list explaining all messages. + --- MINOR NEW FEATURES --- + * The roff(7) parser now supports the .ami (append to macro with + indirectly specified name), .as (append to user-defined + string), .dei (define macro with indirectly specified name), + .ll (line length), and .rr (remove register) requests. + * The roff(7) parser now supports string comparison and numerical + conditionals in the .if and .ie requests. + * The roff parser now fully supports the \B (validate numerical + expression) and partially supports the \w (measure text width) + escape sequences. + * The terminal formatter now supports the \: (optional line break) + escape sequence. + * The roff parser now supports expansion of user-defined strings + involving indirect references. + * The roff(7) parser now handles some pre-defined read-only + number registers that occur in the pod2man(1) preamble. + * For backward compatibility, the mdoc(7) parser and formatters + now support the obsolete macros .En, .Es, .Fr, and .Ot. + * The mdoc(7) formatter non partially supports .Bd -centered. + * tbl(7) now handles leading and trailing vertical lines. + * The build system now provides fallback versions of strcasestr(3) + and strsep(3) for systems lacking them. + * The mdoc(7) manual now explains how various standards + supported by the .St macro are related to each other. + --- BUGFIXES --- + * In the roff(7) parser, several bugs were fixed with respect + to closing conditional blocks on macro lines. + * Parsing of roff(7) identifiers and escape sequences was improved + in multiple respects. + * In the mdoc(7) parser, the handling of defective document + prologues was improved in multiple ways. + * The mdoc(7) parser no longer skips content before the first section + header, and it no longer deletes non-.% content from .Rs blocks. + * In the mdoc(7) parser, a crash was fixed related to weird .Sh headers. + * In the mdoc(7) parser, handling of .Sm with missing or invalid + arguments was corrected. + * In the mdoc(7) parser, trailing punctuation at the end of partial + implicit macros no longer triggers end-of-sentence spacing. + * In the terminal formatter, two crashes were fixed: one triggered by + excessive indentation and another by excessively long .Nm arguments. + * In the terminal formatter, a floating point rounding bug was + fixed that sometimes caused an off-by-one error in indentation. + * In the UTF-8 formatter, rendering of accents, breakable hyphens, + and non-breakable spaces was corrected. + * In the HTML formatter, encoding of special characters was + corrected in multiple respects. + * In the mdoc(7) formatter, rendering of .Ex and .Rv was + improved for various edge cases. + * In the mdoc(7) formatter, handling of empty .Bl -inset item + heads was improved. + * In the man(7) formatter, some bugs were fixed with respect + to same-line detection in the context of .TP and .nf macros, + and the indentation of .IP and .TP blocks was improved. + * The mandoc(3) library no longer prints to stderr. + --- THANKS TO --- + Abhinav Upadhyay (NetBSD), Andreas Voegele, Anthony Bentley (OpenBSD), + Christian Weisgerber (OpenBSD), Havard Eidnes (NetBSD), Jan Stary, + Jason McIntyre (OpenBSD), Jeremie Courreges-Anglas (OpenBSD), + Joerg Sonnenberger (NetBSD), Juan Francisco Cantero Hurtado (OpenBSD), + Marc Espie (OpenBSD), Matthias Scheler (NetBSD), Pascal Stumpf (OpenBSD), + Paul Onyschuk (Alpine Linux), Sebastien Marie, Steffen Nurpmeso, + Stuart Henderson (OpenBSD), Ted Unangst (OpenBSD), Theo de Raadt (OpenBSD), + Thomas Klausner (NetBSD), and Ulrich Spoerlein (FreeBSD) + for reporting bugs and missing features. + +Changes in version 1.12.3, released on December 31, 2013 + + * In the mdoc(7) SYNOPSIS, line breaks and hanging indentation + now work correctly for .Fo/.Fa/.Fc and .Fn blocks. + Thanks to Franco Fichtner for doing part of the work. + * The mdoc(7) .Bk macro got some addititonal bugfixes. + * In mdoc(7) macro arguments, double quotes can now be quoted + by doubling them, just like in man(7). + Thanks to Tsugutomo ENAMI for the patch. + * At the end of man(7) macro lines, end-of-sentence spacing + now works. Thanks to Franco Fichtner for the patch. + * For backward compatibility, the man(7) parser now supports the + man-ext .UR/.UE (uniform resource identifier) block macros. + * The man(7) parser now handles closing blocks that are not open + more gracefully. + * The man(7) parser now ignores blank lines right after .SH and .SS. + * In the man(7) formatter, reset indentation when leaving a block, + not just when entering the next one. + * The roff(7) .nr request now supports incrementing and decrementing + number registers and stops parsing the number right before the + first non-digit character. + * The roff(7) parser now supports the alternative escape sequence + syntax \C'uXXXX' for Unicode characters. + * The roff(7) parser now parses and ignores the .fam (font family) + and .hw (hyphenation points) requests and the \d and \u escape + sequences. + * The roff(7) manual got a new ESCAPE SEQUENCE REFERENCE. + +Changes in version 1.12.2, released on Oktober 5, 2013 + + * The mdoc(7) to man(7) converter, to be called as mandoc -Tman, + is now fully functional. + * The mandoc(1) utility now supports the -Ios (default operating system) + input option, and the -Tutf8 output mode now actually works. + * The mandocdb(8) utility no longer truncates existing databases when + starting to build new ones, but only replaces them when the build + actually succeeds. + * The man(7) parser now supports the PD macro (paragraph distance), + and (for GNU man-ext compatibility only) EX (example block) and EE + (example end). Plus several bugfixes regarding indentation, line + breaks, and vertical spacing, and regarding RS following TP. + * The roff(7) parser now supports the \f(BI (bold+italic) font escape, + the \z (zero cursor advance) escape and the cc (change control + character) and it (input line trap) requests. Plus bugfixes regarding + the \t (tab) escape, nested escape sequences, and conditional requests. + * In mdoc(7), several bugs were fixed related to UTF-8 output of quoting + enclosures, delimiter handling, list indentation and horizontal and + vertical spacing, formatting of the Lk, %U, and %C macros, plus some + bugfixes related to the handling of syntax errors like badly nested + font blocks, stray Ta macros outside column lists, unterminated It Xo + blocks, and non-text children of Nm blocks. + * In tbl(7), the width of horizontal spans and the vertical spacing + around tables was corrected, and in man(7) files, a crash was fixed + that was triggered by some particular unclosed T{ macros. + * For mandoc developers, we now provide a tbl(3) library manual and + gmdiff, a very small, very simplistic groff-versus-mandoc output + comparison tool. + * Provide this NEWS file. + +Changes in version 1.12.1, released on March 23, 2012 + + * Significant work on apropos(1) and mandocdb(8). These tools are now + much more robust. A whatis(1) implementation is now handled as an + apropos(1) mode. These tools are also able to minimally handle + pre-formatted pages, that is, those already formatted by another + utility such as GNU troff. + * The man.cgi(7) script is also now available for wider testing. + It interfaces with mandocdb(8) manuals cached by catman(8). + HTML output is generated on-the-fly by libmandoc or internal + methods to convert pre-formatted pages. + * The mailing list archive for the discuss and tech lists are being + hosted by Gmane at gmane.comp.tools.mdocml.user and + gmane.comp.tools.mdocml.devel, respectively. + +Changes in version 1.12.0, released on October 8, 2011 + + * This version features a new, work-in-progress mandoc(1) output mode: + -Tman. This mode allows a system maintainer to distribute man(7) + media for older systems that may not natively support mdoc(7), such + as old Solaris systems. + * The -Ofragment option was added to mandoc(1)'s -Thtml and -Txhtml modes. + * While adding features, an apropos(1) utility has been merged from the + mandoc-tools sandbox. This interfaces with mandocdb(8) for semantic + search of manual content. apropos(1) is different from the traditional + apropos primarily in allowing keyword search (such as for functions, + utilities, etc.) and regular expressions. Note that the calling + syntax for apropos is likely to change as it settles down. + * In documentation news, the mdoc(7) and man(7) manuals have been + made considerably more readable by adding MACRO OVERVIEW sections, by + moving the gory details of the LANGUAGE SYNTAX to the roff(7) manual, + and by moving the very technical MACRO SYNTAX sections down to the + bottom of the page. + * Furthermore, for tbl(7), the -Tascii mode horizontal spacing of tables + was rewritten completely. It is now compatible with groff(1), both + with and without frames and rulers. + * Nesting of indented blocks is now supported in man(7), and several + bugs were fixed regarding indentation and alignment. + * The page headers in mdoc(7) are now nicer for very long titles. + +Changes in version 1.11.7, released on September 2, 2011 + + * Added demandoc(1) utility for stripping away macros and escapes. + This replaces the historical deroff(1) utility. + * Also improved the mdoc(7) and man(7) manuals. + +Changes in version 1.11.6, released on August 16, 2011 + + * Handling of tr macro in roff(7) implemented. This makes Perl + documentation much more readable. Hyphenation is also now enabled in + man(7) format documents. Many other general improvements have been + implemented. + +Changes in version 1.11.5, released on July 24, 2011 + + * Significant eqn(7) improvements. mdocml can now parse arbitrary eqn + input (although few GNU extensions are accepted, nor is mixing + low-level roff with eqn). See the eqn(7) manual for details. + For the time being, equations are rendered as simple in-line text. + The equation parser satisfies the language specified in the + Second Edition User's Guide: + http://www.kohala.com/start/troff/v7man/eqn/eqn2e.ps + +Changes in version 1.11.4, released on July 12, 2011 + + * Bug-fixes and clean-ups across all systems, especially in mandocdb(8) + and the man(7) parser. This release was significantly assisted by + participants in OpenBSD's c2k11. Thanks! + +Changes in version 1.11.3, released on May 26, 2011 + + * Introduce locale-encoding of output with the -Tlocale output option and + Unicode escaped-character input. See mandoc(1) and mandoc_char(7), + respectively, for details. This allows for non-ASCII characters (e.g., + \[u5000]) to be rendered in the locale's encoding, if said environment + supports wide-character encoding (if it does not, -Tascii is used + instead). Locale support can be turned off at compile time by removing + -DUSE_WCHAR in the Makefile, in which case -Tlocale is always a synonym + for -Tascii. + * Furthermore, multibyte-encoded documents, such as those in UTF-8, may + be on-the-fly recoded into mandoc(1) input by using the newly-added + preconv(1) utility. Note: in the future, this feature may be + integrated into mandoc(1). + +Changes in version 1.11.2, released on May 12, 2011 + + * Corrected some installation issues in version 1.11.1. + * Further migration to libmandoc. + * Initial public release (this utility is very much under development) + of mandocdb(8). This utility produces keyword databases of manual + content, which features semantic querying of manual content. + +Changes in version 1.11.1, released on April 4, 2011 + + * The earlier libroff, libmdoc, and libman soup have been merged into + a single library, libmandoc, which manages all aspects of parsing + real manuals, from line-handling to tbl(7) parsing. + * As usual, many general fixes and improvements have also occurred. + In particular, a great deal of redundancy and superfluous code has + been removed with the merging of the backend libraries. + * see also the changes in 1.10.10 + +Changes in version 1.10.10, March 20, 2011, NOT released + + * Initial eqn(7) functionality is in place. For the time being, + this is limited to the recognition of equation blocks; + future version of mdocml will expand upon this framework. + +Changes in version 1.10.9, released on January 7, 2011 + + * Many back-end fixes have been implemented: argument handling (quoting), + man(7) improvements, error/warning classes, and many more. + * Initial tbl(7) functionality (see the "TS", "TE", and "T&" macros in + the roff(7) manual) has been merged from tbl.bsd.lv. Output is still + minimal, especially for -Thtml and -Txhtml, but manages to at least + display data. This means that mandoc(1) now has built-in support + for two troff preprocessors via libroff: soelim(1) and tbl(1). + +Changes in version 1.10.8, released on December 24, 2010 + + * Overhauled the -Thtml and -Txhtml output modes. They now display + readable output in arbitrary browsers, including text-based ones like + lynx(1). See HTML and XHTML manuals in the DOCUMENTATION section + for examples. Attention: available style-sheet classes have been + considerably changed! See the example.style.css file for details. + Lastly, libmdoc and libman have been cleaned up and reduced in size + and complexity. + * see also the changes in 1.10.7 + +Changes in version 1.10.7, December 6, 2010, NOT released + + Significant improvements merged from OpenBSD downstream, including: + * many new roff(7) components, + * in-line implementation of troff's soelim(1), + * broken-block handling, + * overhauled error classifications, and + * cleaned up handling of error conditions. + +Changes in version 1.10.6, released on September 27, 2010 + + * Calling conventions for mandoc(1) have changed: -W improved and -f + deprecated. + * Non-ASCII characters are also now uniformly discarded. + * Lots of documentation improvements. + * Many incremental fixes accomodating for groff's more interesting + productions. + * Lastly, pod2man(1) preambles are now fully accepted after some + considerable roff(7) and special character support. + +Changes in version 1.10.5, released on July 27, 2010 + + * Primarily a bug-fix and polish release, but including -Tpdf support + in mandoc(1) by way of "Summer of Code". Highlights: + * fix "Sm" and "Bd" handling + * fix end-of-sentence handling for embedded sentences + * polish man(7) documentation + * document all mdoc(7) macros + * polish mandoc(1) -Tps output + * lots of internal clean-ups in character escapes + * un-break literal contexts in man(7) documents + * improve -Thtml output for -man + * add mandoc(1) -Tpdf support + +Changes in version 1.10.4, released on July 12, 2010 + + * Lots of features developed during both "Summer of Code" and the + OpenBSD c2k10 hackathon: + * minimal "ds" roff(7) symbols are supported + * beautified SYNOPSIS section output + * acceptance of scope-block breakage in mdoc(7) + * clarify error message status + * many minor bug-fixes and formatting issues resolved + * see also changes in 1.10.3 + +Changes in version 1.10.3, June 29, 2010, NOT released + + * variable font-width and paper-size support in mandoc(1) -Tps output + * "Bk" mdoc(7) support + +Changes in version 1.10.2, released on June 19, 2010 + + * Small release featuring text-decoration in -Tps output, + a few minor relaxations of errors, and some optimisations. + +Changes in version 1.10.1, released on June 7, 2010 + + * This primarily focusses on the "Bl" and "It" macros described in + mdoc(7). Multi-line column support is now fully compatible with groff, + as are implicit list entries for columns. + * Removed manuals(7) in favour of http://manpages.bsd.lv. + * The way we handle the SYNOPSIS section (see the SYNOPSIS documentation + in MANUAL STRUCTURE) has also been considerably simplified compared + to groff's method. + * Furthermore, the -Owidth=width output option has been added to -Tascii, + see mandoc(1). + * Lastly, initial PostScript output has been added with the -Tps option + to mandoc(1). It's brutally simple at the moment: fixed-font, with no + font decorations. + +Changes in version 1.10.0, released on May 29, 2010 + + * Release consisting of the results from the m2k10 hackathon and up-merge + from OpenBSD. This requires a significant note of thanks to Ingo + Schwarze (OpenBSD) and Joerg Sonnenberger (NetBSD) for their hard work, + and again to Joerg for hosting m2k10. Highlights (mostly cribbed from + Ingo's m2k10 report) follow in no particular order: + * a libroff preprocessor in front of libmdoc and libman stripping out + roff(7) instructions; + * end-of-sentence (EOS) detection in free-form and macro lines; + * correct handling of tab-separated columnar lists in mdoc(7); + * improved main calling routines to optionally use mmap(3) for better + performance; + * cleaned up exiting when invoked as -Tlint or over multiple files + with -fign-errors; + * error and warning message handling re-written to be unified for + libroff, libmdoc, and libman; + * handling of badly-nested explicit-scoped macros; + * improved free-form text parsing in libman and libmdoc; + * significant GNU troff compatibility improvements in -Tascii, + largely in terms of spacing; + * a regression framework for making sure the many fragilities of GNU + troff aren't trampled in subsequent work; + * support for -Tascii breaking at hyphens encountered in free-form text; + * and many more minor fixes and improvements + +Changes in version 1.9.25, released on May 13, 2010 + + * Fixed handling of "\*(Ba" escape. + * Backed out -fno-ign-chars (pointless complexity). + * Fixed erroneous breaking of literal lines. + * Fixed SYNOPSIS breaking lines before non-initial macros. + * Changed default section ordering. + * Most importantly, the framework for end-of-sentence double-spacing is + in place, now implemented for the "end-of-sentence, end-of-line" rule. + * This is a stable roll-back point before the mandoc hackathon in Rostock! + +Changes in version 1.9.24, released on May 9, 2010 + + * Rolled back break-at-hyphen. + * -DUGLY is now the default (no feature splits!). + * Free-form text is not de-chunked any more: lines are passed + whole-sale into the front-end, including whitespace. + * Added mailing lists. + +Changes in version 1.9.23, released on April 7, 2010 + + * mdocml has been linked to the OpenBSD build. + * This version incorporates many small changes, mostly from patches + by OpenBSD, allowing crufty manuals to slip by with warnings instead + of erroring-out. + * Some subtle semantic issues, such as punctuation scope, have also + been fixed. + * Lastly, some issues with -Thtml have been fixed, which prompted an + update to the online manual pages style layout. + +Changes in version 1.9.22, released on March 31, 2010 + + * Adjusted merge of the significant work by Ingo Schwarze + in getting "Xo" blocks (block full implicit, e.g., "It" + for non-columnar lists) to work properly. This isn't + enabled by default: you must specify -DUGLY as a compiler + flag (see the Makefile for details). + +Changes in version 1.9.20, released on March 30, 2010 + + * More efforts to get roff instructions in man(7) documents under + control. Note that roff instructions embedded in line-scoped, + next-line macros (e.g. "B") are not supported. + * Leading punctuation for mdoc(7) macros, such as "Fl ( ( a", + are now correctly handled. + +Changes in version 1.9.18, released on March 27, 2010 + + * Many fixes (largely pertaining to scope) + and improvements (e.g., handling of apostrophe-control macros, + which fixes the strange "BR" seen in some macro output) + to handling roff instructions in man(7) documents. + +Changes in version 1.9.17, released on March 25, 2010 + + * Accept perlpod(1) standard preamble. + * Also accept (and discard) "de", "dei", "am", "ami", and "ig" + roff macro blocks. + +Changes in version 1.9.16, released on March 22, 2010 + + * Inspired by patches and bug reports by Ingo Schwarze, + allowed man(7) to accept non-printing elements to be nested + within next-line scopes, such as "br" within "B" or "TH", + which is valid roff. + * Longsoon architecture also noted and Makefile cleaned up. + +Changes in version 1.9.15, released on February 18, 2010 + + * Moved to our new BSD.lv home. + * XHTML is now an acceptable output mode for mandoc(1); + * "Xr" made more compatible with groff; + * "Vt" fixed when invoked in SYNOPSIS; + * "\\" escape removed; + * end-of-line white-space detected for all lines; + * subtle bug fixed in list display for some modes; + * compatibility layer checked in for compilation in diverse + UNIX systems; + * and column lengths handled correctly. + +For older releases, see the ChangeLog files +in http://mandoc.bsd.lv/snapshots/ . Index: head/contrib/mandoc/TODO =================================================================== --- head/contrib/mandoc/TODO (nonexistent) +++ head/contrib/mandoc/TODO (revision 338826) @@ -0,0 +1,657 @@ +************************************************************************ +* Official mandoc TODO. +* $Id: TODO,v 1.258 2018/08/06 14:16:30 schwarze Exp $ +************************************************************************ + +Many issues are annotated for difficulty as follows: + + - loc = locality of the issue + * single file issue, affects file only, or very few + ** single module issue, affects several files of one module + *** cross-module issue, significantly impacts multiple modules + and may require substantial changes to internal interfaces + - exist = difficulty of the existing code in this area + * affected code is straightforward and easy to read and change + ** affected code is somewhat complex, but once you understand + the design, not particularly difficult to understand + *** affected code uses a special, exceptionally tricky design + - algo = difficulty of the new algorithm to be written + * the required logic and code is straightforward + ** the required logic is somewhat complex and needs a careful design + *** the required logic is exceptionally tricky, + maybe an approach to solve that is not even known yet + - size = the amount of code to be written or changed + * a small number of lines (at most 100, usually much less) + ** a considerable amount of code (several dozen to a few hundred) + *** a large amount of code (many hundreds, maybe thousands) + - imp = importance of the issue + * mostly for completeness + ** would be nice to have + *** issue causes considerable inconvenience + +Obviously, as the issues have not been solved yet, these annotations +are mere guesses, and some may be wrong. + +************************************************************************ +* missing features +************************************************************************ + +--- missing roff features ---------------------------------------------- + +- .nop prints its arguments as text, + see groff(7) for an example + +- .ft CB selects constant-width bold font + see groff_out(7) for examples + +- \*(.T prints the device being used, + see groff_char(7) for an example + +- \[charNN], \[charNNN] prints a single-byte codepoint + see groff_char(7) for examples + +- .ad (adjust margins) + .ad l -- adjust left margin only (flush left) + .ad r -- adjust right margin only (flush right) + .ad c -- center text on line + .ad b -- adjust both margins (alias: .ad n) + .na -- temporarily disable adjustment without changing the mode + .ad -- re-enable adjustment without changing the mode + Adjustment mode is ignored while in no-fill mode (.nf). + loc *** exist *** algo ** size ** imp ** (parser reorg would help) + +- .fc (field control) + found by naddy@ in xloadimage(1) + loc ** exist *** algo * size * imp * + +- .ns (no-space mode) occurs in xine-config(1) + when implementing this, also let .TH set it + reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500 + loc *** exist *** algo *** size ** imp * + +- .while and .shift + found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200 + loc * exist ** algo ** size ** imp ** + +- \w'' improve width measurements + would not be very useful without an expression parser, see below + needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100 + loc ** exist *** algo *** size * imp *** + +- \\ in high-level macro arguments + Currently, \\ is expanded in two situations: + 1) macro and string definition (roff.c setstrn()) + 2) macro argument parsing (mandoc.c mandoc_getarg()) + For user defined macros, the second happens in time because of ROFF_REPARSE. + But for standard high-level macros, it only happens after entering the + high level parsers, which is too late because the code doesn't get + back to roff.c roff_res() from that point. Because this requires + distinguishing requests, user-defined macros and standard macros + on the roff_res() level, it is hard to solve without the parser reorg. + Found by naddy@ in devel/cutils cobfusc(1) Mon, 16 Feb 2015 19:10:52 +0100 + loc *** exist *** algo *** size ** imp * + +- check for missing roff escape sequences, implement those that are + trivial even if not usually appearing in manual pages, gracefully + ignore the non-trivial ones, document what they are supposed to do + and what mandoc does instead + loc * exist ** algo * size * imp * + +--- missing mdoc features ---------------------------------------------- + +- .Bl -column .Xo support is missing + ultimate goal: + restore .Xr and .Dv to + lib/libc/compat-43/sigvec.3 + lib/libc/gen/signal.3 + lib/libc/sys/sigaction.2 + loc * exist *** algo *** size * imp ** + +- edge case: decide how to deal with blk_full bad nesting, e.g. + .Sh .Nm .Bk .Nm .Ek .Sh found by jmc@ in ssh-keygen(1) + from jmc@ Wed, 14 Jul 2010 18:10:32 +0100 + loc * exist *** algo *** size ** imp ** + +- .Bd -centered implies -filled, not -unfilled, which is not + easy to implement; it requires code similar to .ce, which + we don't have either. + Besides, groff has bug causing text right *before* .Bd -centered + to be centered as well. + loc *** exist *** algo ** size ** imp ** (parser reorg would help) + +- .Bd -filled should not be the same as .Bd -ragged, but align both + the left and right margin. In groff, it is implemented in terms + of .ad b, which we don't have either. Found in cksum(1). + loc *** exist *** algo ** size ** imp ** (parser reorg would help) + +- implement blank `Bl -column', such as + .Bl -column + .It foo Ta bar + .El + loc * exist *** algo *** size * imp * + +- explicitly disallow nested `Bl -column', which would clobber internal + flags defined for struct mdoc_macro + loc * exist * algo * size * imp ** + +- In .Bl -column .It, the end of the line probably has to be regarded + as an implicit .Ta, if there could be one, see the following mildly + ugly code from login.conf(5): + .Bl -column minpasswordlen program xetcxmotd + .It path Ta path Ta value of Dv _PATH_DEFPATH + .br + Default search path. + reported by Michal Mazurek + via jmc@ Thu, 7 Apr 2011 16:00:53 +0059 + loc * exist *** algo ** size * imp ** + +- inside `.Bl -column' phrases, punctuation is handled like normal + text, e.g. `.Bl -column .It Fl x . Ta ...' should give "-x -." + +- inside `.Bl -column' phrases, TERMP_IGNDELIM handling by `Pf' + is not safe, e.g. `.Bl -column .It Pf a b .' gives "ab." + but should give "ab ." + +- prohibit `Nm' from having non-text HEAD children + (e.g., NetBSD mDNSShared/dns-sd.1) + (mdoc_html.c and mdoc_term.c `Nm' handlers can be slightly simplified) + +- support translated section names + e.g. x11/scrotwm scrotwm_es.1:21:2: error: NAME section must be first + that one uses NOMBRE because it is spanish... + deraadt tends to think that section-dependent macro behaviour + is a bad idea in the first place, so this may be irrelevant + loc ** exist ** algo ** size * imp ** + +- When there is free text in the SYNOPSIS and that free text contains + the .Nm macro, groff somehow understands to treat the .Nm as an in-line + macro, while mandoc treats it as a block macro and breaks the line. + No idea how the logic for distinguishing in-line and block instances + should be, needs investigation. + uqs@ Thu, 2 Jun 2011 11:03:51 +0200 + uqs@ Thu, 2 Jun 2011 11:33:35 +0200 + loc * exist ** algo *** size * imp ** + +--- missing man features ----------------------------------------------- + +- .SY and .YS, + used by many groff manual pages + +- preserve punctuation following .ME, + see ditroff(7) for an example + +- .TQ tagged paragraph continuation, + see groff_diff(7) for examples + +- groff_www(7) .MTO and .URL + These macros were used by the GNU grep(1) man page. + The groff_www(7) manual page itself uses them, too. + We should probably *not* add them to mandoc. + Just mentioning this here to keep track of the abuse. + Laura Morales 20 Apr 2018 07:33:02 +0200 + loc ** exist * algo * size ** imp * + +--- missing tbl features ----------------------------------------------- + +- the "s" layout column specifier is used for placement of data + into columns, but ignored during column width calculations + synaptics(4) found by tedu@ Mon, 17 Aug 2015 21:17:42 -0400 + loc * exist ** algo *** size * imp ** + +- vertical centering in cells vertically spanned with ^ + pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200 + loc * exist *** algo *** size ** imp * + +- support .ds requests inside tbl(7) code, + see tbl(1) for an example + +- support mdoc(7) and man(7) macros inside tbl(7) code; + probably requires the parser reorg and letting tbl(7) + use roff_node such that macro sets can mix; + informed by bapt@ that FreeBSD needs this: 3 Jan 2015 23:32:23 +0100 + loc *** exist ** algo *** size ** imp *** + +- look at the POSIX manuals in the books/man-pages-posix port, + they use some unsupported tbl(7) features. + loc * exist ** algo ** size ** imp *** + +- look what Joerg Schilling manual pages use + Thu, 19 Mar 2015 18:31:48 +0100 + +- use Unicode U+2500 to U+256C for table borders + in tbl(7) -Tutf-8 output + suggested by bentley@ Tue, 14 Oct 2014 04:10:55 -0600 + loc * exist ** algo * size * imp ** + +- implement horizontal and vertical alignment in HTML output + pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200 + loc * exist * algo * size * imp *** + +- implement cell spanning in HTML output + pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200 + loc * exist * algo ** size ** imp ** + +- implement table borders in HTML output + pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200 + loc * exist * algo ** size ** imp ** + +--- missing eqn features ----------------------------------------------- + +- In a matrix, break the output line after each matrix line. + Found in the discussion at CDBUG 2015. + Suggested by Avi Weinstock. + loc * exist * algo * size * imp ** + +- The "size" keyword is parsed, but ignored by the formatter. + loc * exist * algo * size * imp * + +- The spacing characters `~', `^', and tab are currently ignored, + see User's Guide (Second Edition) page 2 section 4. + loc * exist * algo ** size * imp ** + +- Mark and lineup are parsed and ignored, + see User's Guide (Second Edition) page 5 section 15. + loc ** exist ** algo ** size ** imp ** + +- GNU eqn converts some operators to special characters, for example, + input HYPHEN-MINUS becomes output \(mi, unless it is part of a + quoted word. mandoc(1) only does this when the operator is + surrounded by blanks, not when it is part of an unquoted word. + Also, check whether there are more such cases (e.g., +?). + reported by bentley@ 20 Jun 2017 02:04:29 -0600 + loc * exist ** algo ** size * imp * + +- Primes, opprime, and ' + bentley@ Thu, 13 Jul 2017 23:14:20 -0600 + +--- missing misc features ---------------------------------------------- + +- man -ks 1,8 route; kn@ Jul 13, 2018 orally + +- italic correction (\/) in PostScript mode + Werner LEMBERG on groff at gnu dot org Sun, 10 Nov 2013 12:47:46 + loc ** exist ** algo * size * imp * + +- change the default PAGER to more -Es and use the pager + even for apropos title line output; req by bapt@ + loc * exist * algo * size * imp *** + +- clean up escape sequence handling, creating three classes: + (1) fully implemented, or parsed and ignored without loss of content + (2) unimplemented, potentially causing loss of content + or serious mangling of formatting (e.g. \n) -> ERROR + see textproc/mgdiff(1) for nice examples + (3) undefined, just output the character -> perhaps WARNING + loc *** exist ** algo ** size ** imp *** (parser reorg helps) + +- kettenis wants base roff, ms, and me Fri, 1 Jan 2010 22:13:15 +0100 (CET) + loc ** exist ** algo ** size *** imp * + +--- compatibility checks ----------------------------------------------- + +- is .Bk implemented correctly in modern groff? + sobrado@ Tue, 19 Apr 2011 22:12:55 +0200 + +- compare output to Heirloom roff, Solaris roff, and + http://repo.or.cz/w/neatroff.git http://litcave.rudi.ir/ + +- look at AT&T DWB http://www2.research.att.com/sw/download + Carsten Kunze has patches + Mon, 4 Aug 2014 17:01:28 +0200 + ported version: https://github.com/n-t-roff/DWB3.3 + Carsten Kunze Wed, 22 Apr 2015 11:21:43 +0200 + +- look at pages generated from reStructeredText, e.g. devel/mercurial hg(1) + These are a weird mixture of man(7) and custom autogenerated low-level + roff stuff. Figure out to what extent we can cope. + For details, see http://docutils.sourceforge.net/rst.html + noted by stsp@ Sat, 24 Apr 2010 09:17:55 +0200 + reminded by nicm@ Mon, 3 May 2010 09:52:41 +0100 + +- look at pages generated from ronn(1) github.com/rtomayko/ronn + (based on markdown) + +- look at pages generated from Texinfo source by yat2m, e.g. security/gnupg + First impression is not that bad. + +- look at pages generated by pandoc; see + https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/Writers/Man.hs + porting planned by kili@ Thu, 19 Jun 2014 19:46:28 +0200 + +- check compatibility with Plan9: + http://swtch.com/usr/local/plan9/tmac/tmac.an + http://swtch.com/plan9port/man/man7/man.html + "Anthony J. Bentley" 28 Dec 2010 21:58:40 -0700 + +- check compatibility with COHERENT troff: + http://www.nesssoftware.com/home/mwc/source.php + +- check compatibility with the man(7) formatter + https://raw.githubusercontent.com/rofl0r/hardcore-utils/master/man.c + +- check compatibility with + http://ikiwiki.info/plugins/contrib/mandoc/ + https://github.com/schmonz/ikiwiki/compare/mandoc + Amitai Schlair Mon, 19 May 2014 14:05:53 -0400 + +- check features of the Slackware man.conf(5) format + Carsten Kunze Wed, 11 Mar 2015 17:57:24 +0100 + +************************************************************************ +* formatting issues: ugly output +************************************************************************ + +- .UR can nest inside .TP, + see roff(7) for examples + +- revisit empty in-line macros + look at the difference between "Em x Em ." and "Sq x Em ." + Carsten Kunze Fri, 12 Dec 2014 00:15:41 +0100 + loc *** exist *** algo *** size * imp ** + +- a column list with blank `Ta' cells triggers a spurious + start-with-whitespace printing of a newline + +- In .Bl -column, .It a"bc" + shows the quotes in groff, but not in mandoc + loc * exist *** algo ** size * imp ** + +- In .Bl -column, + .It Em AuthenticationKey Length + ought to render "Key Length" with emphasis, too, + see OpenBSD iked.conf(5). + reported again Nicolas Joly via wiz@ Wed, 12 Oct 2011 00:20:00 +0200 + loc * exist *** algo *** size ** imp *** + +- empty phrases in .Bl column produce too few blanks + try e.g. .Bl -column It Ta Ta + reported by millert Fri, 02 Apr 2010 16:13:46 -0400 + loc * exist *** algo *** size * imp ** + +- .%T can have trailing punctuation. Currently, it puts the trailing + punctuation into a trailing MDOC_TEXT element inside its own scope. + That element should rather be outside its scope, such that the + punctuation does not get underlines. This is not trivial to + implement because .%T then needs some features of in_line_eoln() - + slurp all arguments into one single text element - and one feature + of in_line() - put trailing punctuation out of scope. + Found in mount_nfs(8) and exports(5), search for "Appendix". + loc ** exist ** algo *** size * imp ** + +- Trailing punctuation after .%T triggers EOS spacing, at least + outside .Rs (eek!). Simply setting ARGSFL_DELIM for .%T is not + the right solution, it sends mandoc into an endless loop. + reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100 + loc * exist ** algo ** size * imp ** + +- global variables in the SYNOPSIS of section 3 pages + .Vt vs .Vt/.Va vs .Ft/.Va vs .Ft/.Fa ... + from kristaps@ Tue, 08 Jun 2010 11:13:32 +0200 + +- implicit whitespace around inline equations + example code: where '$times$' denotes matrix multiplication + must not have an HTML line break, nor a blank, before + partial solution: html.c {"math", HTML_NLINSIDE | HTML_INDENT}, + bentley@ Thu, 13 Jul 2017 19:00:59 -0600 + +- in enclosures, mandoc sometimes fancies a bogus end of sentence + reminded by jmc@ Thu, 23 Sep 2010 18:13:39 +0059 + loc * exist ** algo *** size * imp *** + +- a line starting with "\fB something" counts as starting with whitespace + and triggers a line break; found in audio/normalize-mp3(1) + loc ** exist * algo ** size * imp ** + +- formatting /usr/local/man/man1/latex2man.1 with groff and mandoc + reveals lots of bugs both in groff and mandoc... + reported by bentley@ Wed, 22 May 2013 23:49:30 -0600 + +--- PostScript and PDF issues ------------------------------------------ + +- PDF output doesn't use a monospaced font for .Bd -literal + Example: "mandoc -Tpdf afterboot.8 > output.pdf && pdfviewer output.pdf". + Search the text "Routing tables". + Also check what PostScript mode does when fixing this. + reported by juanfra@ Wed, 04 Jun 2014 21:44:58 +0200 + instructions from juanfra@ Wed, 11 Jun 2014 02:21:01 +0200 + add a new <> block to the PDF files with /BaseFont /Courier + and change the /Name from /F0 to the new font (/F5 (?)). + re-reported by tb@ Mon, 16 Mar 2015 16:47:21 +0100 + loc * exist ** algo ** size * imp ** + +--- HTML issues -------------------------------------------------------- + +- wrap Sh and Ss content into
+ Laura Morales 21 Apr 2018 18:10:48 +0200 + (Evaluate whether this is really useful and has no adverse + side effects before implementing; if it is possible, + it does seem cleaner.) + loc ** exist ** algo * size * imp *** + +- format ".IP *" etc. as
    rather than
    + https://github.com/Debian/debiman/issues/67 + loc ** exist ** algo ** size * imp *** + +- .Bf at the beginning of a paragraph inserts a bogus 1ex horizontal + space, see for example random(3). Introduced in + http://mdocml.bsd.lv/cgi-bin/cvsweb/mdoc_html.c.diff?r1=1.91&r2=1.92 + reported by deraadt@ Mon, 28 Sep 2015 20:14:13 -0600 (MDT) + loc ** exist ** algo ** size * imp * + +- jsg on icb, Nov 3, 2014: + try to guess Xr in man(7) for hyperlinking + and render them with + https://github.com/Debian/debiman/issues/15 + loc * exist * algo ** size ** imp ** + +- The tables used to render the three-part page headers actually force + the width of the to the max-width given for . + Not yet sure how to fix that... + Observed by an Anonymous Coward on undeadly.org: + http://undeadly.org/cgi?action=article&sid=20140925064244&pid=1 + loc * exist * algo ** size * imp *** + +- generate tags in HTML + idea from florian@ Tue, 7 Apr 2015 00:26:28 +0000 + may be possible to implement with .Lk img://something.png alt_text + +- check https://github.com/trentm/mdocml + +************************************************************************ +* formatting issues: gratuitous differences +************************************************************************ + +- .Fn reopens a new scope after punctuation in mandoc, + but closes its scope for good in groff. + Do we want to change mandoc or groff? + Steffen Nurpmeso Sat, 08 Nov 2014 13:34:59 +0100 + loc * exist ** algo ** size * imp ** + +- In .Bl -enum -width 0n, groff continues one the same line after + the number, mandoc breaks the line. + mail to kristaps@ Mon, 20 Jul 2009 02:21:39 +0200 + loc * exist ** algo ** size * imp ** + +- .Pp between two .It in .Bl -column should produce one, + not two blank lines, see e.g. login.conf(5). + reported by jmc@ Sun, 17 Apr 2011 14:04:58 +0059 + reported again by sthen@ Wed, 18 Jan 2012 02:09:39 +0000 (UTC) + loc * exist *** algo ** size * imp ** + +- If the *first* line after .It is .Pp, break the line right after + the tag, do not pad with space characters before breaking. + See the description of the a, c, and i commands in sed(1). + loc * exist ** algo ** size * imp ** + +- If the first line after .It is .D1, do not assert a blank line + in between, see for example tmux(1). + reported by nicm@ 13 Jan 2011 00:18:57 +0000 + loc * exist ** algo ** size * imp ** + +- Trailing punctuation after .It should trigger EOS spacing. + reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100 + Probably, this should be fixed somewhere in termp_it_pre(), not sure. + loc * exist ** algo ** size * imp ** + +- When the -width string contains macros, the macros must be rendered + before measuring the width, for example + .Bl -tag -width ".Dv message" + in magic(5), located in src/usr.bin/file, is the same + as -width 7n, not -width 11n. + The same applies to .Bl -column column widths; + reported again by Nicolas Joly Thu, 1 Mar 2012 13:41:26 +0100 via wiz@ 5 Mar + reported again by Franco Fichtner Fri, 27 Sep 2013 21:02:28 +0200 + reported again by Bruce Evans Fri, 17 Feb 2017 21:22:44 +0100 via bapt@ + loc *** exist *** algo *** size ** imp *** + An easy partial fix would be to just skip the first word if it starts + with a dot, including any following white space, when measuring. + loc * exist * algo * size * imp *** + +- The \& zero-width character counts as output. + That is, when it is alone on a line between two .Pp, + we want three blank lines, not two as in mandoc. + loc ** exist ** algo ** size * imp ** + +- Sequences of multiple man(7) paragraphs (.PP, .IP) interspersed + with .ps and .nf/.fi produce execessive blank lines, see libJudy + and graphics/dcmtk. The parser reorg may help with this. + +- trailing whitespace must be ignored even when followed by a font escape, + see for example + makes + \fBdig \fR + operate in batch mode + in dig(1). + loc ** exist ** algo ** size * imp ** + +************************************************************************ +* warning issues +************************************************************************ + +- warn about duplicate .Sh/.Ss heads + gre(4): Rename duplicate sections 20 Apr 2018 15:27:33 +0200 + loc * exist * algo * size * imp ** + +- style message about macros inside .Bd -literal and .Dl, in particular + font changing macros like .Cm, .Ar, .Fa (from the mdoclint TODO) + +- style message about mismatches between the section number in the + file name (if it is known) and the section number in .Dt + (from the mdoclint TODO) + +- style message about NULL without .Dv (from the mdoclint TODO) + +- style message about error constants without .Er (from the mdoclint TODO) + +- warn when .Sh or .Ss contain other macros + Steffen Nurpmeso, savannah.gnu.org/bugs/index.php?45034 + loc * exist * algo * size * imp ** + +- style message about violations of the convention + .An name Aq Mt localpart@domain in AUTHORS (from the mdoclint TODO) + +- warn about attempts to call non-callable macros + Steffen Nurpmeso Tue, 11 Nov 2014 22:55:16 +0100 + Note that formatting is inconsistent in groff. + .Fn Po prints "Po()", .Ar Sh prints "file ..." and no "Sh". + Relatively hard because the relevant code is scattered + all over mdoc_macro.c and all subtly different. + loc ** exist ** algo ** size ** imp ** + +- style message about suspicious uses of - vs. \- vs. \(mi + e.g. -1 is likely wrong (from the mdoclint TODO) + +- warn about punctuation - e.g. ',' and ';' - at the beginning + of a text line, if it is likely intended to follow the preceding + output without intervening whitespace, in particular after a + macro line (from the mdoclint TODO) + +- mandoc_special does not really check the escape sequence, + but just the overall format + loc ** exist ** algo *** size ** imp ** + +- makewhatis -p complains about language subdirectories: + /usr/local/man//ru: Unknown directory part + + +************************************************************************ +* documentation issues +************************************************************************ + +- dashes, hyphens, and minus signs in manual pages + jmc@ Fri, 28 Mar 2014 07:19:27 +0000 + +- mark macros as: page structure domain, manual domain, general text domain + is this useful? + +- mention /usr/share/misc/mdoc.template in mdoc(7)? + +- Is all the content from http://www.std.com/obi/BSD/doc/usd/28.tbl/tbl + covered in tbl(7)? + +************************************************************************ +* performance issues +************************************************************************ + +- the PDF file is HUGE: this can be reduced by using relative offsets + +************************************************************************ +* structural issues +************************************************************************ + +- POSIX says in the documentation of sysconf(3) that PATH_MAX + is allowed to be so large that it is a bad idea to use it + for sizing static buffers. So use dynamic buffers throughout. + See the file test-PATH_MAX.c for details. + Found by Aaron M. Ucko in the GNU Hurd via Bdale Garbee, + https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=829624 + +- We use the input line number at several places to distinguish + same-line from different-line input. That plainly doesn't work + with user-defined macros, leading to random breakage. + +- Is it possible to further simplify ENDBODY_SPACE? + +- Find better ways to prevent endless loops + in roff(7) macro and string expansion. + +- make buffers for parsing functions const + christos@ via wiz@ Fri, 18 Dec 2015 17:10:01 +0100 + +- struct mparse refactoring + Steffen Nurpmeso Thu, 04 Sep 2014 12:50:00 +0200 + +************************************************************************ +* CGI issues +************************************************************************ + + - Enable HTTP compression by detecting gzip encoding and filtering + output through libz. + - Privilege separation (see OpenSSH). + - Enable caching support via HTTP 304 and If-Modified-Since. + - Have Mac OSX systems automatically disable -static compilation of the + CGI: -static isn't supported. + +************************************************************************ +* to improve in the groff_mdoc(7) macros +************************************************************************ + +- .Cd # arch1, arch2 in section 4 pages: + find better way to indicate multiple architectures, maybe: + allow .Dt vgafb 4 "macppc sparc64" + already shown as "Device Drivers Manual (macppc sparc64)" + for apropos, make that "vgafb(4) - macppc # sparc64" instead of "- all" + groff can be made to show multiple arches, too, but it is + tedious to do the string parsing in roff code... + jmc@ 23 Apr 2018 07:24:52 +0100 [man for vgafb(4)...] + loc ** exist ** algo * size * imp *** + +- use uname(1) to set doc-default-operating-system at install time + tobimensch Mon, 1 Dec 2014 00:25:07 +0100 + +- apostrophe (39), circumflex (94), grave (96), tilde (126) + in manuals: \(aq, \(ha, \`, \(ti + Re: [Groff] ASCII Minus Sign in man Pages. + bentley@ 26 Apr 2017 10:02:06 -0600 + Do we need to fix existing manuals? + Do we need to fix the definition of the mdoc(7) language? Index: head/contrib/mandoc/apropos.1 =================================================================== --- head/contrib/mandoc/apropos.1 (nonexistent) +++ head/contrib/mandoc/apropos.1 (revision 338826) @@ -0,0 +1,509 @@ +.\" $Id: apropos.1,v 1.47 2018/02/23 18:54:02 schwarze Exp $ +.\" +.\" Copyright (c) 2011, 2012 Kristaps Dzonsons +.\" Copyright (c) 2011, 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: February 23 2018 $ +.Dt APROPOS 1 +.Os +.Sh NAME +.Nm apropos , +.Nm whatis +.Nd search manual page databases +.Sh SYNOPSIS +.Nm +.Op Fl afk +.Op Fl C Ar file +.Op Fl M Ar path +.Op Fl m Ar path +.Op Fl O Ar outkey +.Op Fl S Ar arch +.Op Fl s Ar section +.Ar expression ... +.Sh DESCRIPTION +The +.Nm apropos +and +.Nm whatis +utilities query manual page databases generated by +.Xr makewhatis 8 , +evaluating +.Ar expression +for each file in each database. +By default, they display the names, section numbers, and description lines +of all matching manuals. +.Pp +By default, +.Nm +searches for +.Xr makewhatis 8 +databases in the default paths stipulated by +.Xr man 1 +and uses case-insensitive substring matching +.Pq the Cm = No operator +over manual names and descriptions +.Pq the Li \&Nm No and Li \&Nd No macro keys . +Multiple terms imply pairwise +.Fl o . +.Pp +.Nm whatis +is a synonym for +.Nm +.Fl f . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +Instead of showing only the title lines, show the complete manual pages, +just like +.Xr man 1 +.Fl a +would. +If the standard output is a terminal device and +.Fl c +is not specified, use +.Xr more 1 +to paginate them. +In +.Fl a +mode, the options +.Fl IKOTW +described in the +.Xr mandoc 1 +manual are also available. +.It Fl C Ar file +Specify an alternative configuration +.Ar file +in +.Xr man.conf 5 +format. +.It Fl f +Search for all words in +.Ar expression +in manual page names only. +The search is case insensitive and matches whole words only. +In this mode, macro keys, comparison operators, and logical operators +are not available. +.It Fl k +Support the full +.Ar expression +syntax. +It is the default for +.Nm . +.It Fl M Ar path +Use the colon-separated path instead of the default list of paths +searched for +.Xr makewhatis 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl m Ar path +Prepend the colon-separated paths to the list of paths searched +for +.Xr makewhatis 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl O Ar outkey +Show the values associated with the key +.Ar outkey +instead of the manual descriptions. +.It Fl S Ar arch +Restrict the search to pages for the specified +.Xr machine 1 +architecture. +.Ar arch +is case insensitive. +By default, pages for all architectures are shown. +.It Fl s Ar section +Restrict the search to the specified section of the manual. +By default, pages from all sections are shown. +See +.Xr man 1 +for a listing of sections. +.El +.Pp +The options +.Fl chlw +are also supported and are documented in +.Xr man 1 . +The options +.Fl fkl +are mutually exclusive and override each other. +.Pp +An +.Ar expression +consists of search terms joined by logical operators +.Fl a +.Pq and +and +.Fl o +.Pq or . +The +.Fl a +operator has precedence over +.Fl o +and both are evaluated left-to-right. +.Bl -tag -width Ds +.It \&( Ar expr No \&) +True if the subexpression +.Ar expr +is true. +.It Ar expr1 Fl a Ar expr2 +True if both +.Ar expr1 +and +.Ar expr2 +are true (logical +.Sq and ) . +.It Ar expr1 Oo Fl o Oc Ar expr2 +True if +.Ar expr1 +and/or +.Ar expr2 +evaluate to true (logical +.Sq or ) . +.It Ar term +True if +.Ar term +is satisfied. +This has syntax +.Sm off +.Oo +.Op Ar key Op , Ar key ... +.Pq Cm = | \(ti +.Oc +.Ar val , +.Sm on +where +.Ar key +is an +.Xr mdoc 7 +macro to query and +.Ar val +is its value. +See +.Sx Macro Keys +for a list of available keys. +Operator +.Cm = +evaluates a substring, while +.Cm \(ti +evaluates a regular expression. +.It Fl i Ar term +If +.Ar term +is a regular expression, it +is evaluated case-insensitively. +Has no effect on substring terms. +.El +.Pp +Results are sorted according to the following criteria: +.Bl -enum +.It +The manpath directory tree the page is found in, according to the +order specified with +.Fl M , +.Fl m , +the +.Ev MANPATH +environment variable, the +.Xr man.conf 5 +configuration file, or the default documented in +.Xr man.conf 5 . +.It +The section number in ascending numerical order. +.It +The page name in ascending +.Xr ascii 7 +alphabetical order, case-insensitive. +.El +.Pp +Each output line is formatted as +.Pp +.D1 name[, name...](sec) \- description +.Pp +Where +.Dq name +is the manual's name, +.Dq sec +is the manual section, and +.Dq description +is the manual's short description. +If an architecture is specified for the manual, it is displayed as +.Pp +.D1 name(sec/arch) \- description +.Pp +Resulting manuals may be accessed as +.Pp +.Dl $ man \-s sec name +.Pp +If an architecture is specified in the output, use +.Pp +.Dl $ man \-s sec \-S arch name +.Ss Macro Keys +Queries evaluate over a subset of +.Xr mdoc 7 +macros indexed by +.Xr makewhatis 8 . +In addition to the macro keys listed below, the special key +.Cm any +may be used to match any available macro key. +.Pp +Names and description: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Nm Ta manual name +.It Li \&Nd Ta one-line manual description +.It Li arch Ta machine architecture (case-insensitive) +.It Li sec Ta manual section number +.El +.Pp +Sections and cross references: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Sh Ta section header (excluding standard sections) +.It Li \&Ss Ta subsection header +.It Li \&Xr Ta cross reference to another manual page +.It Li \&Rs Ta bibliographic reference +.El +.Pp +Semantic markup for command line utilities: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Fl Ta command line options (flags) +.It Li \&Cm Ta command modifier +.It Li \&Ar Ta command argument +.It Li \&Ic Ta internal or interactive command +.It Li \&Ev Ta environmental variable +.It Li \&Pa Ta file system path +.El +.Pp +Semantic markup for function libraries: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Lb Ta function library name +.It Li \&In Ta include file +.It Li \&Ft Ta function return type +.It Li \&Fn Ta function name +.It Li \&Fa Ta function argument type and name +.It Li \&Vt Ta variable type +.It Li \&Va Ta variable name +.It Li \&Dv Ta defined variable or preprocessor constant +.It Li \&Er Ta error constant +.It Li \&Ev Ta environmental variable +.El +.Pp +Various semantic markup: +.Bl -column "xLix" description -offset indent -compact +.It Li \&An Ta author name +.It Li \&Lk Ta hyperlink +.It Li \&Mt Ta Do mailto Dc hyperlink +.It Li \&Cd Ta kernel configuration declaration +.It Li \&Ms Ta mathematical symbol +.It Li \&Tn Ta tradename +.El +.Pp +Physical markup: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Em Ta italic font or underline +.It Li \&Sy Ta boldface font +.It Li \&Li Ta typewriter font +.El +.Pp +Text production: +.Bl -column "xLix" description -offset indent -compact +.It Li \&St Ta reference to a standards document +.It Li \&At Ta At No version reference +.It Li \&Bx Ta Bx No version reference +.It Li \&Bsx Ta Bsx No version reference +.It Li \&Nx Ta Nx No version reference +.It Li \&Fx Ta Fx No version reference +.It Li \&Ox Ta Ox No version reference +.It Li \&Dx Ta Dx No version reference +.El +.Pp +In general, macro keys are supposed to yield complete results without +expecting the user to consider actual macro usage. +For example, results include: +.Pp +.Bl -tag -width 3n -offset 3n -compact +.It Li \&Fa +function arguments appearing on +.Ic \&Fn +lines +.It Li \&Fn +fuction names marked up with +.Ic \&Fo +macros +.It Li \&In +include file names marked up with +.Ic \&Fd +macros +.It Li \&Vt +types appearing as function return types and +.It \& +types appearing in function arguments in the SYNOPSIS +.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 MANPATH +A colon-separated list of directories to search for manual pages; see +.Xr man 1 +for details. +Overridden by +.Fl M , +ignored if +.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 FILES +.Bl -tag -width "/etc/man.conf" -compact +.It Pa mandoc.db +name of the +.Xr makewhatis 8 +keyword database +.It Pa /etc/man.conf +default +.Xr man 1 +configuration file +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Search for +.Qq .cf +as a substring of manual names and descriptions: +.Pp +.Dl $ apropos .cf +.Pp +Include matches for +.Qq .cnf +and +.Qq .conf +as well: +.Pp +.Dl $ apropos .cf .cnf .conf +.Pp +Search in names and descriptions using a regular expression: +.Pp +.Dl $ apropos \(aq\(tiset.?[ug]id\(aq +.Pp +Search for manuals in the library section mentioning both the +.Qq optind +and the +.Qq optarg +variables: +.Pp +.Dl $ apropos \-s 3 Va=optind \-a Va=optarg +.Pp +Do exactly the same as calling +.Nm whatis +with the argument +.Qq ssh : +.Pp +.Dl $ apropos \-\- \-i \(aqNm\(ti[[:<:]]ssh[[:>:]]\(aq +.Pp +The following two invocations are equivalent: +.Pp +.D1 Li $ apropos -S Ar arch Li -s Ar section expression +.Bd -ragged -offset indent +.Li $ apropos \e( Ar expression Li \e) +.Li -a arch\(ti^( Ns Ar arch Ns Li |any)$ +.Li -a sec\(ti^ Ns Ar section Ns Li $ +.Ed +.Sh SEE ALSO +.Xr man 1 , +.Xr re_format 7 , +.Xr makewhatis 8 +.Sh HISTORY +Part of the functionality of +.Nm whatis +was already provided by the former +.Nm manwhere +utility in +.Bx 1 . +The +.Nm +and +.Nm whatis +utilities first appeared in +.Bx 2 . +They were rewritten from scratch for +.Ox 5.6 . +.Pp +The +.Fl M +option and the +.Ev MANPATH +variable first appeared in +.Bx 4.3 ; +.Fl m +in +.Bx 4.3 Reno ; +.Fl C +in +.Bx 4.4 Lite1 ; +and +.Fl S +and +.Fl s +in +.Ox 4.5 +for +.Nm +and in +.Ox 5.6 +for +.Nm whatis . +The options +.Fl acfhIKklOTWw +appeared in +.Ox 5.7 . +.Sh AUTHORS +.An -nosplit +.An Bill Joy +wrote +.Nm manwhere +in 1977 and the original +.Bx +.Nm +and +.Nm whatis +in February 1979. +The current version was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +and +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: head/contrib/mandoc/apropos.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/cgi.c =================================================================== --- head/contrib/mandoc/cgi.c (nonexistent) +++ head/contrib/mandoc/cgi.c (revision 338826) @@ -0,0 +1,1242 @@ +/* $Id: cgi.c,v 1.158 2018/05/29 20:32:45 schwarze Exp $ */ +/* + * Copyright (c) 2011, 2012 Kristaps Dzonsons + * Copyright (c) 2014, 2015, 2016, 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 +#if HAVE_ERR +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "man.h" +#include "main.h" +#include "manconf.h" +#include "mansearch.h" +#include "cgi.h" + +/* + * A query as passed to the search function. + */ +struct query { + char *manpath; /* desired manual directory */ + char *arch; /* architecture */ + char *sec; /* manual section */ + char *query; /* unparsed query expression */ + int equal; /* match whole names, not substrings */ +}; + +struct req { + struct query q; + char **p; /* array of available manpaths */ + size_t psz; /* number of available manpaths */ + int isquery; /* QUERY_STRING used, not PATH_INFO */ +}; + +enum focus { + FOCUS_NONE = 0, + FOCUS_QUERY +}; + +static void html_print(const char *); +static void html_putchar(char); +static int http_decode(char *); +static void parse_manpath_conf(struct req *); +static void parse_path_info(struct req *req, const char *path); +static void parse_query_string(struct req *, const char *); +static void pg_error_badrequest(const char *); +static void pg_error_internal(void); +static void pg_index(const struct req *); +static void pg_noresult(const struct req *, const char *); +static void pg_redirect(const struct req *, const char *); +static void pg_search(const struct req *); +static void pg_searchres(const struct req *, + struct manpage *, size_t); +static void pg_show(struct req *, const char *); +static void resp_begin_html(int, const char *, const char *); +static void resp_begin_http(int, const char *); +static void resp_catman(const struct req *, const char *); +static void resp_copy(const char *); +static void resp_end_html(void); +static void resp_format(const struct req *, const char *); +static void resp_searchform(const struct req *, enum focus); +static void resp_show(const struct req *, const char *); +static void set_query_attr(char **, char **); +static int validate_filename(const char *); +static int validate_manpath(const struct req *, const char *); +static int validate_urifrag(const char *); + +static const char *scriptname = SCRIPT_NAME; + +static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9}; +static const char *const sec_numbers[] = { + "0", "1", "2", "3", "3p", "4", "5", "6", "7", "8", "9" +}; +static const char *const sec_names[] = { + "All Sections", + "1 - General Commands", + "2 - System Calls", + "3 - Library Functions", + "3p - Perl Library", + "4 - Device Drivers", + "5 - File Formats", + "6 - Games", + "7 - Miscellaneous Information", + "8 - System Manager\'s Manual", + "9 - Kernel Developer\'s Manual" +}; +static const int sec_MAX = sizeof(sec_names) / sizeof(char *); + +static const char *const arch_names[] = { + "amd64", "alpha", "armv7", "arm64", + "hppa", "i386", "landisk", + "loongson", "luna88k", "macppc", "mips64", + "octeon", "sgi", "socppc", "sparc64", + "amiga", "arc", "armish", "arm32", + "atari", "aviion", "beagle", "cats", + "hppa64", "hp300", + "ia64", "mac68k", "mvme68k", "mvme88k", + "mvmeppc", "palm", "pc532", "pegasos", + "pmax", "powerpc", "solbourne", "sparc", + "sun3", "vax", "wgrisc", "x68k", + "zaurus" +}; +static const int arch_MAX = sizeof(arch_names) / sizeof(char *); + +/* + * Print a character, escaping HTML along the way. + * This will pass non-ASCII straight to output: be warned! + */ +static void +html_putchar(char c) +{ + + switch (c) { + case '"': + printf("""); + break; + case '&': + printf("&"); + break; + case '>': + printf(">"); + break; + case '<': + printf("<"); + break; + default: + putchar((unsigned char)c); + break; + } +} + +/* + * Call through to html_putchar(). + * Accepts NULL strings. + */ +static void +html_print(const char *p) +{ + + if (NULL == p) + return; + while ('\0' != *p) + html_putchar(*p++); +} + +/* + * Transfer the responsibility for the allocated string *val + * to the query structure. + */ +static void +set_query_attr(char **attr, char **val) +{ + + free(*attr); + if (**val == '\0') { + *attr = NULL; + free(*val); + } else + *attr = *val; + *val = NULL; +} + +/* + * Parse the QUERY_STRING for key-value pairs + * and store the values into the query structure. + */ +static void +parse_query_string(struct req *req, const char *qs) +{ + char *key, *val; + size_t keysz, valsz; + + req->isquery = 1; + req->q.manpath = NULL; + req->q.arch = NULL; + req->q.sec = NULL; + req->q.query = NULL; + req->q.equal = 1; + + key = val = NULL; + while (*qs != '\0') { + + /* Parse one key. */ + + keysz = strcspn(qs, "=;&"); + key = mandoc_strndup(qs, keysz); + qs += keysz; + if (*qs != '=') + goto next; + + /* Parse one value. */ + + valsz = strcspn(++qs, ";&"); + val = mandoc_strndup(qs, valsz); + qs += valsz; + + /* Decode and catch encoding errors. */ + + if ( ! (http_decode(key) && http_decode(val))) + goto next; + + /* Handle key-value pairs. */ + + if ( ! strcmp(key, "query")) + set_query_attr(&req->q.query, &val); + + else if ( ! strcmp(key, "apropos")) + req->q.equal = !strcmp(val, "0"); + + else if ( ! strcmp(key, "manpath")) { +#ifdef COMPAT_OLDURI + if ( ! strncmp(val, "OpenBSD ", 8)) { + val[7] = '-'; + if ('C' == val[8]) + val[8] = 'c'; + } +#endif + set_query_attr(&req->q.manpath, &val); + } + + else if ( ! (strcmp(key, "sec") +#ifdef COMPAT_OLDURI + && strcmp(key, "sektion") +#endif + )) { + if ( ! strcmp(val, "0")) + *val = '\0'; + set_query_attr(&req->q.sec, &val); + } + + else if ( ! strcmp(key, "arch")) { + if ( ! strcmp(val, "default")) + *val = '\0'; + set_query_attr(&req->q.arch, &val); + } + + /* + * The key must be freed in any case. + * The val may have been handed over to the query + * structure, in which case it is now NULL. + */ +next: + free(key); + key = NULL; + free(val); + val = NULL; + + if (*qs != '\0') + qs++; + } +} + +/* + * HTTP-decode a string. The standard explanation is that this turns + * "%4e+foo" into "n foo" in the regular way. This is done in-place + * over the allocated string. + */ +static int +http_decode(char *p) +{ + char hex[3]; + char *q; + int c; + + hex[2] = '\0'; + + q = p; + for ( ; '\0' != *p; p++, q++) { + if ('%' == *p) { + if ('\0' == (hex[0] = *(p + 1))) + return 0; + if ('\0' == (hex[1] = *(p + 2))) + return 0; + if (1 != sscanf(hex, "%x", &c)) + return 0; + if ('\0' == c) + return 0; + + *q = (char)c; + p += 2; + } else + *q = '+' == *p ? ' ' : *p; + } + + *q = '\0'; + return 1; +} + +static void +resp_begin_http(int code, const char *msg) +{ + + if (200 != code) + printf("Status: %d %s\r\n", code, msg); + + printf("Content-Type: text/html; charset=utf-8\r\n" + "Cache-Control: no-cache\r\n" + "Pragma: no-cache\r\n" + "\r\n"); + + fflush(stdout); +} + +static void +resp_copy(const char *filename) +{ + char buf[4096]; + ssize_t sz; + int fd; + + if ((fd = open(filename, O_RDONLY)) != -1) { + fflush(stdout); + while ((sz = read(fd, buf, sizeof(buf))) > 0) + write(STDOUT_FILENO, buf, sz); + close(fd); + } +} + +static void +resp_begin_html(int code, const char *msg, const char *file) +{ + char *cp; + + resp_begin_http(code, msg); + + printf("\n" + "\n" + "\n" + " \n" + " \n" + " \n" + " ", + CSS_DIR); + if (file != NULL) { + if ((cp = strrchr(file, '/')) != NULL) + file = cp + 1; + if ((cp = strrchr(file, '.')) != NULL) { + printf("%.*s(%s) - ", (int)(cp - file), file, cp + 1); + } else + printf("%s - ", file); + } + printf("%s\n" + "\n" + "\n", + CUSTOMIZE_TITLE); + + resp_copy(MAN_DIR "/header.html"); +} + +static void +resp_end_html(void) +{ + + resp_copy(MAN_DIR "/footer.html"); + + puts("\n" + ""); +} + +static void +resp_searchform(const struct req *req, enum focus focus) +{ + int i; + + printf("
    \n" + "
    \n" + " Manual Page Search Parameters\n", + scriptname); + + /* Write query input box. */ + + printf(" q.query != NULL) + html_print(req->q.query); + printf( "\" size=\"40\""); + if (focus == FOCUS_QUERY) + printf(" autofocus"); + puts(">"); + + /* Write submission buttons. */ + + printf( " \n" + " \n" + "
    \n"); + + /* Write section selector. */ + + puts(" "); + + /* Write architecture selector. */ + + printf( " "); + + /* Write manpath selector. */ + + if (req->psz > 1) { + puts(" "); + } + + puts("
    \n" + "
    "); +} + +static int +validate_urifrag(const char *frag) +{ + + while ('\0' != *frag) { + if ( ! (isalnum((unsigned char)*frag) || + '-' == *frag || '.' == *frag || + '/' == *frag || '_' == *frag)) + return 0; + frag++; + } + return 1; +} + +static int +validate_manpath(const struct req *req, const char* manpath) +{ + size_t i; + + for (i = 0; i < req->psz; i++) + if ( ! strcmp(manpath, req->p[i])) + return 1; + + return 0; +} + +static int +validate_filename(const char *file) +{ + + if ('.' == file[0] && '/' == file[1]) + file += 2; + + return ! (strstr(file, "../") || strstr(file, "/..") || + (strncmp(file, "man", 3) && strncmp(file, "cat", 3))); +} + +static void +pg_index(const struct req *req) +{ + + resp_begin_html(200, NULL, NULL); + resp_searchform(req, FOCUS_QUERY); + printf("

    \n" + "This web interface is documented in the\n" + "man.cgi(8)\n" + "manual, and the\n" + "apropos(1)\n" + "manual explains the query syntax.\n" + "

    \n", + scriptname, *scriptname == '\0' ? "" : "/", + scriptname, *scriptname == '\0' ? "" : "/"); + resp_end_html(); +} + +static void +pg_noresult(const struct req *req, const char *msg) +{ + resp_begin_html(200, NULL, NULL); + resp_searchform(req, FOCUS_QUERY); + puts("

    "); + puts(msg); + puts("

    "); + resp_end_html(); +} + +static void +pg_error_badrequest(const char *msg) +{ + + resp_begin_html(400, "Bad Request", NULL); + puts("

    Bad Request

    \n" + "

    \n"); + puts(msg); + printf("Try again from the\n" + "main page.\n" + "

    ", scriptname); + resp_end_html(); +} + +static void +pg_error_internal(void) +{ + resp_begin_html(500, "Internal Server Error", NULL); + puts("

    Internal Server Error

    "); + resp_end_html(); +} + +static void +pg_redirect(const struct req *req, const char *name) +{ + printf("Status: 303 See Other\r\n" + "Location: /"); + if (*scriptname != '\0') + printf("%s/", scriptname); + if (strcmp(req->q.manpath, req->p[0])) + printf("%s/", req->q.manpath); + if (req->q.arch != NULL) + printf("%s/", req->q.arch); + printf("%s", name); + if (req->q.sec != NULL) + printf(".%s", req->q.sec); + printf("\r\nContent-Type: text/html; charset=utf-8\r\n\r\n"); +} + +static void +pg_searchres(const struct req *req, struct manpage *r, size_t sz) +{ + char *arch, *archend; + const char *sec; + size_t i, iuse; + int archprio, archpriouse; + int prio, priouse; + + for (i = 0; i < sz; i++) { + if (validate_filename(r[i].file)) + continue; + warnx("invalid filename %s in %s database", + r[i].file, req->q.manpath); + pg_error_internal(); + return; + } + + if (req->isquery && sz == 1) { + /* + * If we have just one result, then jump there now + * without any delay. + */ + printf("Status: 303 See Other\r\n" + "Location: /"); + if (*scriptname != '\0') + printf("%s/", scriptname); + if (strcmp(req->q.manpath, req->p[0])) + printf("%s/", req->q.manpath); + printf("%s\r\n" + "Content-Type: text/html; charset=utf-8\r\n\r\n", + r[0].file); + return; + } + + /* + * In man(1) mode, show one of the pages + * even if more than one is found. + */ + + iuse = 0; + if (req->q.equal || sz == 1) { + priouse = 20; + archpriouse = 3; + for (i = 0; i < sz; i++) { + sec = r[i].file; + sec += strcspn(sec, "123456789"); + if (sec[0] == '\0') + continue; + prio = sec_prios[sec[0] - '1']; + if (sec[1] != '/') + prio += 10; + if (req->q.arch == NULL) { + archprio = + ((arch = strchr(sec + 1, '/')) + == NULL) ? 3 : + ((archend = strchr(arch + 1, '/')) + == NULL) ? 0 : + strncmp(arch, "amd64/", + archend - arch) ? 2 : 1; + if (archprio < archpriouse) { + archpriouse = archprio; + priouse = prio; + iuse = i; + continue; + } + if (archprio > archpriouse) + continue; + } + if (prio >= priouse) + continue; + priouse = prio; + iuse = i; + } + resp_begin_html(200, NULL, r[iuse].file); + } else + resp_begin_html(200, NULL, NULL); + + resp_searchform(req, + req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY); + + if (sz > 1) { + puts(""); + for (i = 0; i < sz; i++) { + printf(" \n" + " \n" + " \n" + " "); + } + puts("
    " + "q.manpath, req->p[0])) + printf("%s/", req->q.manpath); + printf("%s\">", r[i].file); + html_print(r[i].names); + printf(""); + html_print(r[i].output); + puts("
    "); + } + + if (req->q.equal || sz == 1) { + puts("
    "); + resp_show(req, r[iuse].file); + } + + resp_end_html(); +} + +static void +resp_catman(const struct req *req, const char *file) +{ + FILE *f; + char *p; + size_t sz; + ssize_t len; + int i; + int italic, bold; + + if ((f = fopen(file, "r")) == NULL) { + puts("

    You specified an invalid manual file.

    "); + return; + } + + puts("
    \n" + "
    ");
    +
    +	p = NULL;
    +	sz = 0;
    +
    +	while ((len = getline(&p, &sz, f)) != -1) {
    +		bold = italic = 0;
    +		for (i = 0; i < len - 1; i++) {
    +			/*
    +			 * This means that the catpage is out of state.
    +			 * Ignore it and keep going (although the
    +			 * catpage is bogus).
    +			 */
    +
    +			if ('\b' == p[i] || '\n' == p[i])
    +				continue;
    +
    +			/*
    +			 * Print a regular character.
    +			 * Close out any bold/italic scopes.
    +			 * If we're in back-space mode, make sure we'll
    +			 * have something to enter when we backspace.
    +			 */
    +
    +			if ('\b' != p[i + 1]) {
    +				if (italic)
    +					printf("");
    +				if (bold)
    +					printf("");
    +				italic = bold = 0;
    +				html_putchar(p[i]);
    +				continue;
    +			} else if (i + 2 >= len)
    +				continue;
    +
    +			/* Italic mode. */
    +
    +			if ('_' == p[i]) {
    +				if (bold)
    +					printf("");
    +				if ( ! italic)
    +					printf("");
    +				bold = 0;
    +				italic = 1;
    +				i += 2;
    +				html_putchar(p[i]);
    +				continue;
    +			}
    +
    +			/*
    +			 * Handle funny behaviour troff-isms.
    +			 * These grok'd from the original man2html.c.
    +			 */
    +
    +			if (('+' == p[i] && 'o' == p[i + 2]) ||
    +					('o' == p[i] && '+' == p[i + 2]) ||
    +					('|' == p[i] && '=' == p[i + 2]) ||
    +					('=' == p[i] && '|' == p[i + 2]) ||
    +					('*' == p[i] && '=' == p[i + 2]) ||
    +					('=' == p[i] && '*' == p[i + 2]) ||
    +					('*' == p[i] && '|' == p[i + 2]) ||
    +					('|' == p[i] && '*' == p[i + 2]))  {
    +				if (italic)
    +					printf("");
    +				if (bold)
    +					printf("");
    +				italic = bold = 0;
    +				putchar('*');
    +				i += 2;
    +				continue;
    +			} else if (('|' == p[i] && '-' == p[i + 2]) ||
    +					('-' == p[i] && '|' == p[i + 1]) ||
    +					('+' == p[i] && '-' == p[i + 1]) ||
    +					('-' == p[i] && '+' == p[i + 1]) ||
    +					('+' == p[i] && '|' == p[i + 1]) ||
    +					('|' == p[i] && '+' == p[i + 1]))  {
    +				if (italic)
    +					printf("");
    +				if (bold)
    +					printf("");
    +				italic = bold = 0;
    +				putchar('+');
    +				i += 2;
    +				continue;
    +			}
    +
    +			/* Bold mode. */
    +
    +			if (italic)
    +				printf("");
    +			if ( ! bold)
    +				printf("");
    +			bold = 1;
    +			italic = 0;
    +			i += 2;
    +			html_putchar(p[i]);
    +		}
    +
    +		/*
    +		 * Clean up the last character.
    +		 * We can get to a newline; don't print that.
    +		 */
    +
    +		if (italic)
    +			printf("");
    +		if (bold)
    +			printf("");
    +
    +		if (i == len - 1 && p[i] != '\n')
    +			html_putchar(p[i]);
    +
    +		putchar('\n');
    +	}
    +	free(p);
    +
    +	puts("
    \n" + "
    "); + + fclose(f); +} + +static void +resp_format(const struct req *req, const char *file) +{ + struct manoutput conf; + struct mparse *mp; + struct roff_man *man; + void *vp; + int fd; + int usepath; + + if (-1 == (fd = open(file, O_RDONLY, 0))) { + puts("

    You specified an invalid manual file.

    "); + return; + } + + mchars_alloc(); + mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1, + MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, req->q.manpath); + mparse_readfd(mp, fd, file); + close(fd); + + memset(&conf, 0, sizeof(conf)); + conf.fragment = 1; + conf.style = mandoc_strdup(CSS_DIR "/mandoc.css"); + usepath = strcmp(req->q.manpath, req->p[0]); + mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S", + scriptname, *scriptname == '\0' ? "" : "/", + usepath ? req->q.manpath : "", usepath ? "/" : ""); + + mparse_result(mp, &man, NULL); + if (man == NULL) { + warnx("fatal mandoc error: %s/%s", req->q.manpath, file); + pg_error_internal(); + mparse_free(mp); + mchars_free(); + return; + } + + vp = html_alloc(&conf); + + if (man->macroset == MACROSET_MDOC) { + mdoc_validate(man); + html_mdoc(vp, man); + } else { + man_validate(man); + html_man(vp, man); + } + + html_free(vp); + mparse_free(mp); + mchars_free(); + free(conf.man); + free(conf.style); +} + +static void +resp_show(const struct req *req, const char *file) +{ + + if ('.' == file[0] && '/' == file[1]) + file += 2; + + if ('c' == *file) + resp_catman(req, file); + else + resp_format(req, file); +} + +static void +pg_show(struct req *req, const char *fullpath) +{ + char *manpath; + const char *file; + + if ((file = strchr(fullpath, '/')) == NULL) { + pg_error_badrequest( + "You did not specify a page to show."); + return; + } + manpath = mandoc_strndup(fullpath, file - fullpath); + file++; + + if ( ! validate_manpath(req, manpath)) { + pg_error_badrequest( + "You specified an invalid manpath."); + free(manpath); + return; + } + + /* + * Begin by chdir()ing into the manpath. + * This way we can pick up the database files, which are + * relative to the manpath root. + */ + + if (chdir(manpath) == -1) { + warn("chdir %s", manpath); + pg_error_internal(); + free(manpath); + return; + } + free(manpath); + + if ( ! validate_filename(file)) { + pg_error_badrequest( + "You specified an invalid manual file."); + return; + } + + resp_begin_html(200, NULL, file); + resp_searchform(req, FOCUS_NONE); + resp_show(req, file); + resp_end_html(); +} + +static void +pg_search(const struct req *req) +{ + struct mansearch search; + struct manpaths paths; + struct manpage *res; + char **argv; + char *query, *rp, *wp; + size_t ressz; + int argc; + + /* + * Begin by chdir()ing into the root of the manpath. + * This way we can pick up the database files, which are + * relative to the manpath root. + */ + + if (chdir(req->q.manpath) == -1) { + warn("chdir %s", req->q.manpath); + pg_error_internal(); + return; + } + + search.arch = req->q.arch; + search.sec = req->q.sec; + search.outkey = "Nd"; + search.argmode = req->q.equal ? ARG_NAME : ARG_EXPR; + search.firstmatch = 1; + + paths.sz = 1; + paths.paths = mandoc_malloc(sizeof(char *)); + paths.paths[0] = mandoc_strdup("."); + + /* + * Break apart at spaces with backslash-escaping. + */ + + argc = 0; + argv = NULL; + rp = query = mandoc_strdup(req->q.query); + for (;;) { + while (isspace((unsigned char)*rp)) + rp++; + if (*rp == '\0') + break; + argv = mandoc_reallocarray(argv, argc + 1, sizeof(char *)); + argv[argc++] = wp = rp; + for (;;) { + if (isspace((unsigned char)*rp)) { + *wp = '\0'; + rp++; + break; + } + if (rp[0] == '\\' && rp[1] != '\0') + rp++; + if (wp != rp) + *wp = *rp; + if (*rp == '\0') + break; + wp++; + rp++; + } + } + + res = NULL; + ressz = 0; + if (req->isquery && req->q.equal && argc == 1) + pg_redirect(req, argv[0]); + else if (mansearch(&search, &paths, argc, argv, &res, &ressz) == 0) + pg_noresult(req, "You entered an invalid query."); + else if (ressz == 0) + pg_noresult(req, "No results found."); + else + pg_searchres(req, res, ressz); + + free(query); + mansearch_free(res, ressz); + free(paths.paths[0]); + free(paths.paths); +} + +int +main(void) +{ + struct req req; + struct itimerval itimer; + const char *path; + const char *querystring; + int i; + +#if HAVE_PLEDGE + /* + * The "rpath" pledge could be revoked after mparse_readfd() + * if the file desciptor to "/footer.html" would be opened + * up front, but it's probably not worth the complication + * of the code it would cause: it would require scattering + * pledge() calls in multiple low-level resp_*() functions. + */ + + if (pledge("stdio rpath", NULL) == -1) { + warn("pledge"); + pg_error_internal(); + return EXIT_FAILURE; + } +#endif + + /* Poor man's ReDoS mitigation. */ + + itimer.it_value.tv_sec = 2; + itimer.it_value.tv_usec = 0; + itimer.it_interval.tv_sec = 2; + itimer.it_interval.tv_usec = 0; + if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) == -1) { + warn("setitimer"); + pg_error_internal(); + return EXIT_FAILURE; + } + + /* + * First we change directory into the MAN_DIR so that + * subsequent scanning for manpath directories is rooted + * relative to the same position. + */ + + if (chdir(MAN_DIR) == -1) { + warn("MAN_DIR: %s", MAN_DIR); + pg_error_internal(); + return EXIT_FAILURE; + } + + memset(&req, 0, sizeof(struct req)); + req.q.equal = 1; + parse_manpath_conf(&req); + + /* Parse the path info and the query string. */ + + if ((path = getenv("PATH_INFO")) == NULL) + path = ""; + else if (*path == '/') + path++; + + if (*path != '\0') { + parse_path_info(&req, path); + if (req.q.manpath == NULL || req.q.sec == NULL || + *req.q.query == '\0' || access(path, F_OK) == -1) + path = ""; + } else if ((querystring = getenv("QUERY_STRING")) != NULL) + parse_query_string(&req, querystring); + + /* Validate parsed data and add defaults. */ + + if (req.q.manpath == NULL) + req.q.manpath = mandoc_strdup(req.p[0]); + else if ( ! validate_manpath(&req, req.q.manpath)) { + pg_error_badrequest( + "You specified an invalid manpath."); + return EXIT_FAILURE; + } + + if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) { + pg_error_badrequest( + "You specified an invalid architecture."); + return EXIT_FAILURE; + } + + /* Dispatch to the three different pages. */ + + if ('\0' != *path) + pg_show(&req, path); + else if (NULL != req.q.query) + pg_search(&req); + else + pg_index(&req); + + free(req.q.manpath); + free(req.q.arch); + free(req.q.sec); + free(req.q.query); + for (i = 0; i < (int)req.psz; i++) + free(req.p[i]); + free(req.p); + return EXIT_SUCCESS; +} + +/* + * If PATH_INFO is not a file name, translate it to a query. + */ +static void +parse_path_info(struct req *req, const char *path) +{ + char *dir[4]; + int i; + + req->isquery = 0; + req->q.equal = 1; + req->q.manpath = mandoc_strdup(path); + req->q.arch = NULL; + + /* Mandatory manual page name. */ + if ((req->q.query = strrchr(req->q.manpath, '/')) == NULL) { + req->q.query = req->q.manpath; + req->q.manpath = NULL; + } else + *req->q.query++ = '\0'; + + /* Optional trailing section. */ + if ((req->q.sec = strrchr(req->q.query, '.')) != NULL) { + if(isdigit((unsigned char)req->q.sec[1])) { + *req->q.sec++ = '\0'; + req->q.sec = mandoc_strdup(req->q.sec); + } else + req->q.sec = NULL; + } + + /* Handle the case of name[.section] only. */ + if (req->q.manpath == NULL) + return; + req->q.query = mandoc_strdup(req->q.query); + + /* Split directory components. */ + dir[i = 0] = req->q.manpath; + while ((dir[i + 1] = strchr(dir[i], '/')) != NULL) { + if (++i == 3) { + pg_error_badrequest( + "You specified too many directory components."); + exit(EXIT_FAILURE); + } + *dir[i]++ = '\0'; + } + + /* Optional manpath. */ + if ((i = validate_manpath(req, req->q.manpath)) == 0) + req->q.manpath = NULL; + else if (dir[1] == NULL) + return; + + /* Optional section. */ + if (strncmp(dir[i], "man", 3) == 0) { + free(req->q.sec); + req->q.sec = mandoc_strdup(dir[i++] + 3); + } + if (dir[i] == NULL) { + if (req->q.manpath == NULL) + free(dir[0]); + return; + } + if (dir[i + 1] != NULL) { + pg_error_badrequest( + "You specified an invalid directory component."); + exit(EXIT_FAILURE); + } + + /* Optional architecture. */ + if (i) { + req->q.arch = mandoc_strdup(dir[i]); + if (req->q.manpath == NULL) + free(dir[0]); + } else + req->q.arch = dir[0]; +} + +/* + * Scan for indexable paths. + */ +static void +parse_manpath_conf(struct req *req) +{ + FILE *fp; + char *dp; + size_t dpsz; + ssize_t len; + + if ((fp = fopen("manpath.conf", "r")) == NULL) { + warn("%s/manpath.conf", MAN_DIR); + pg_error_internal(); + exit(EXIT_FAILURE); + } + + dp = NULL; + dpsz = 0; + + while ((len = getline(&dp, &dpsz, fp)) != -1) { + if (dp[len - 1] == '\n') + dp[--len] = '\0'; + req->p = mandoc_realloc(req->p, + (req->psz + 1) * sizeof(char *)); + if ( ! validate_urifrag(dp)) { + warnx("%s/manpath.conf contains " + "unsafe path \"%s\"", MAN_DIR, dp); + pg_error_internal(); + exit(EXIT_FAILURE); + } + if (strchr(dp, '/') != NULL) { + warnx("%s/manpath.conf contains " + "path with slash \"%s\"", MAN_DIR, dp); + pg_error_internal(); + exit(EXIT_FAILURE); + } + req->p[req->psz++] = dp; + dp = NULL; + dpsz = 0; + } + free(dp); + + if (req->p == NULL) { + warnx("%s/manpath.conf is empty", MAN_DIR); + pg_error_internal(); + exit(EXIT_FAILURE); + } +} Property changes on: head/contrib/mandoc/cgi.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/chars.c =================================================================== --- head/contrib/mandoc/chars.c (nonexistent) +++ head/contrib/mandoc/chars.c (revision 338826) @@ -0,0 +1,511 @@ +/* $Id: chars.c,v 1.73 2017/08/23 13:01:29 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2011, 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. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "libmandoc.h" + +struct ln { + const char roffcode[16]; + const char *ascii; + int unicode; +}; + +/* Special break control characters. */ +static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' }; +static const char ascii_break[2] = { ASCII_BREAK, '\0' }; + +static struct ln lines[] = { + + /* Spacing. */ + { " ", ascii_nbrsp, 0x00a0 }, + { "~", ascii_nbrsp, 0x00a0 }, + { "0", " ", 0x2002 }, + { "|", "", 0 }, + { "^", "", 0 }, + { "&", "", 0 }, + { "%", "", 0 }, + { ":", ascii_break, 0 }, + /* XXX The following three do not really belong here. */ + { "t", "", 0 }, + { "c", "", 0 }, + { "}", "", 0 }, + + /* Lines. */ + { "ba", "|", 0x007c }, + { "br", "|", 0x2502 }, + { "ul", "_", 0x005f }, + { "ru", "_", 0x005f }, + { "rn", "-", 0x203e }, + { "bb", "|", 0x00a6 }, + { "sl", "/", 0x002f }, + { "rs", "\\", 0x005c }, + + /* Text markers. */ + { "ci", "O", 0x25cb }, + { "bu", "+\bo", 0x2022 }, + { "dd", "<**>", 0x2021 }, + { "dg", "<*>", 0x2020 }, + { "lz", "<>", 0x25ca }, + { "sq", "[]", 0x25a1 }, + { "ps", "", 0x00b6 }, + { "sc", "
    ", 0x00a7 }, + { "lh", "<=", 0x261c }, + { "rh", "=>", 0x261e }, + { "at", "@", 0x0040 }, + { "sh", "#", 0x0023 }, + { "CR", "", 0x21b5 }, + { "OK", "\\/", 0x2713 }, + { "CL", "", 0x2663 }, + { "SP", "", 0x2660 }, + { "HE", "", 0x2665 }, + { "DI", "", 0x2666 }, + + /* Legal symbols. */ + { "co", "(C)", 0x00a9 }, + { "rg", "(R)", 0x00ae }, + { "tm", "tm", 0x2122 }, + + /* Punctuation. */ + { "em", "--", 0x2014 }, + { "en", "-", 0x2013 }, + { "hy", "-", 0x2010 }, + { "e", "\\", 0x005c }, + { ".", ".", 0x002e }, + { "r!", "!", 0x00a1 }, + { "r?", "?", 0x00bf }, + + /* Quotes. */ + { "Bq", ",,", 0x201e }, + { "bq", ",", 0x201a }, + { "lq", "\"", 0x201c }, + { "rq", "\"", 0x201d }, + { "Lq", "\"", 0x201c }, + { "Rq", "\"", 0x201d }, + { "oq", "`", 0x2018 }, + { "cq", "\'", 0x2019 }, + { "aq", "\'", 0x0027 }, + { "dq", "\"", 0x0022 }, + { "Fo", "<<", 0x00ab }, + { "Fc", ">>", 0x00bb }, + { "fo", "<", 0x2039 }, + { "fc", ">", 0x203a }, + + /* Brackets. */ + { "lB", "[", 0x005b }, + { "rB", "]", 0x005d }, + { "lC", "{", 0x007b }, + { "rC", "}", 0x007d }, + { "la", "<", 0x27e8 }, + { "ra", ">", 0x27e9 }, + { "bv", "|", 0x23aa }, + { "braceex", "|", 0x23aa }, + { "bracketlefttp", "|", 0x23a1 }, + { "bracketleftbt", "|", 0x23a3 }, + { "bracketleftex", "|", 0x23a2 }, + { "bracketrighttp", "|", 0x23a4 }, + { "bracketrightbt", "|", 0x23a6 }, + { "bracketrightex", "|", 0x23a5 }, + { "lt", ",-", 0x23a7 }, + { "bracelefttp", ",-", 0x23a7 }, + { "lk", "{", 0x23a8 }, + { "braceleftmid", "{", 0x23a8 }, + { "lb", "`-", 0x23a9 }, + { "braceleftbt", "`-", 0x23a9 }, + { "braceleftex", "|", 0x23aa }, + { "rt", "-.", 0x23ab }, + { "bracerighttp", "-.", 0x23ab }, + { "rk", "}", 0x23ac }, + { "bracerightmid", "}", 0x23ac }, + { "rb", "-\'", 0x23ad }, + { "bracerightbt", "-\'", 0x23ad }, + { "bracerightex", "|", 0x23aa }, + { "parenlefttp", "/", 0x239b }, + { "parenleftbt", "\\", 0x239d }, + { "parenleftex", "|", 0x239c }, + { "parenrighttp", "\\", 0x239e }, + { "parenrightbt", "/", 0x23a0 }, + { "parenrightex", "|", 0x239f }, + + /* Arrows and lines. */ + { "<-", "<-", 0x2190 }, + { "->", "->", 0x2192 }, + { "<>", "<->", 0x2194 }, + { "da", "|\bv", 0x2193 }, + { "ua", "|\b^", 0x2191 }, + { "va", "^v", 0x2195 }, + { "lA", "<=", 0x21d0 }, + { "rA", "=>", 0x21d2 }, + { "hA", "<=>", 0x21d4 }, + { "uA", "=\b^", 0x21d1 }, + { "dA", "=\bv", 0x21d3 }, + { "vA", "^=v", 0x21d5 }, + { "an", "-", 0x23af }, + + /* Logic. */ + { "AN", "^", 0x2227 }, + { "OR", "v", 0x2228 }, + { "no", "~", 0x00ac }, + { "tno", "~", 0x00ac }, + { "te", "", 0x2203 }, + { "fa", "", 0x2200 }, + { "st", "", 0x220b }, + { "tf", "", 0x2234 }, + { "3d", "", 0x2234 }, + { "or", "|", 0x007c }, + + /* Mathematicals. */ + { "pl", "+", 0x002b }, + { "mi", "-", 0x2212 }, + { "-", "-", 0x002d }, + { "-+", "-+", 0x2213 }, + { "+-", "+-", 0x00b1 }, + { "t+-", "+-", 0x00b1 }, + { "pc", ".", 0x00b7 }, + { "md", ".", 0x22c5 }, + { "mu", "x", 0x00d7 }, + { "tmu", "x", 0x00d7 }, + { "c*", "O\bx", 0x2297 }, + { "c+", "O\b+", 0x2295 }, + { "di", "/", 0x00f7 }, + { "tdi", "/", 0x00f7 }, + { "f/", "/", 0x2044 }, + { "**", "*", 0x2217 }, + { "<=", "<=", 0x2264 }, + { ">=", ">=", 0x2265 }, + { "<<", "<<", 0x226a }, + { ">>", ">>", 0x226b }, + { "eq", "=", 0x003d }, + { "!=", "!=", 0x2260 }, + { "==", "==", 0x2261 }, + { "ne", "!==", 0x2262 }, + { "ap", "~", 0x223c }, + { "|=", "-~", 0x2243 }, + { "=~", "=~", 0x2245 }, + { "~~", "~~", 0x2248 }, + { "~=", "~=", 0x2248 }, + { "pt", "", 0x221d }, + { "es", "{}", 0x2205 }, + { "mo", "", 0x2208 }, + { "nm", "", 0x2209 }, + { "sb", "", 0x2282 }, + { "nb", "", 0x2284 }, + { "sp", "", 0x2283 }, + { "nc", "", 0x2285 }, + { "ib", "", 0x2286 }, + { "ip", "", 0x2287 }, + { "ca", "", 0x2229 }, + { "cu", "", 0x222a }, + { "/_", "", 0x2220 }, + { "pp", "", 0x22a5 }, + { "is", "", 0x222b }, + { "integral", "", 0x222b }, + { "sum", "", 0x2211 }, + { "product", "", 0x220f }, + { "coproduct", "", 0x2210 }, + { "gr", "", 0x2207 }, + { "sr", "", 0x221a }, + { "sqrt", "", 0x221a }, + { "lc", "|~", 0x2308 }, + { "rc", "~|", 0x2309 }, + { "lf", "|_", 0x230a }, + { "rf", "_|", 0x230b }, + { "if", "", 0x221e }, + { "Ah", "", 0x2135 }, + { "Im", "", 0x2111 }, + { "Re", "", 0x211c }, + { "wp", "P", 0x2118 }, + { "pd", "", 0x2202 }, + { "-h", "/h", 0x210f }, + { "hbar", "/h", 0x210f }, + { "12", "1/2", 0x00bd }, + { "14", "1/4", 0x00bc }, + { "34", "3/4", 0x00be }, + { "18", "1/8", 0x215B }, + { "38", "3/8", 0x215C }, + { "58", "5/8", 0x215D }, + { "78", "7/8", 0x215E }, + { "S1", "^1", 0x00B9 }, + { "S2", "^2", 0x00B2 }, + { "S3", "^3", 0x00B3 }, + + /* Ligatures. */ + { "ff", "ff", 0xfb00 }, + { "fi", "fi", 0xfb01 }, + { "fl", "fl", 0xfb02 }, + { "Fi", "ffi", 0xfb03 }, + { "Fl", "ffl", 0xfb04 }, + { "AE", "AE", 0x00c6 }, + { "ae", "ae", 0x00e6 }, + { "OE", "OE", 0x0152 }, + { "oe", "oe", 0x0153 }, + { "ss", "ss", 0x00df }, + { "IJ", "IJ", 0x0132 }, + { "ij", "ij", 0x0133 }, + + /* Accents. */ + { "a\"", "\"", 0x02dd }, + { "a-", "-", 0x00af }, + { "a.", ".", 0x02d9 }, + { "a^", "^", 0x005e }, + { "aa", "\'", 0x00b4 }, + { "\'", "\'", 0x00b4 }, + { "ga", "`", 0x0060 }, + { "`", "`", 0x0060 }, + { "ab", "'\b`", 0x02d8 }, + { "ac", ",", 0x00b8 }, + { "ad", "\"", 0x00a8 }, + { "ah", "v", 0x02c7 }, + { "ao", "o", 0x02da }, + { "a~", "~", 0x007e }, + { "ho", ",", 0x02db }, + { "ha", "^", 0x005e }, + { "ti", "~", 0x007e }, + + /* Accented letters. */ + { "'A", "'\bA", 0x00c1 }, + { "'E", "'\bE", 0x00c9 }, + { "'I", "'\bI", 0x00cd }, + { "'O", "'\bO", 0x00d3 }, + { "'U", "'\bU", 0x00da }, + { "'a", "'\ba", 0x00e1 }, + { "'e", "'\be", 0x00e9 }, + { "'i", "'\bi", 0x00ed }, + { "'o", "'\bo", 0x00f3 }, + { "'u", "'\bu", 0x00fa }, + { "`A", "`\bA", 0x00c0 }, + { "`E", "`\bE", 0x00c8 }, + { "`I", "`\bI", 0x00cc }, + { "`O", "`\bO", 0x00d2 }, + { "`U", "`\bU", 0x00d9 }, + { "`a", "`\ba", 0x00e0 }, + { "`e", "`\be", 0x00e8 }, + { "`i", "`\bi", 0x00ec }, + { "`o", "`\bo", 0x00f2 }, + { "`u", "`\bu", 0x00f9 }, + { "~A", "~\bA", 0x00c3 }, + { "~N", "~\bN", 0x00d1 }, + { "~O", "~\bO", 0x00d5 }, + { "~a", "~\ba", 0x00e3 }, + { "~n", "~\bn", 0x00f1 }, + { "~o", "~\bo", 0x00f5 }, + { ":A", "\"\bA", 0x00c4 }, + { ":E", "\"\bE", 0x00cb }, + { ":I", "\"\bI", 0x00cf }, + { ":O", "\"\bO", 0x00d6 }, + { ":U", "\"\bU", 0x00dc }, + { ":a", "\"\ba", 0x00e4 }, + { ":e", "\"\be", 0x00eb }, + { ":i", "\"\bi", 0x00ef }, + { ":o", "\"\bo", 0x00f6 }, + { ":u", "\"\bu", 0x00fc }, + { ":y", "\"\by", 0x00ff }, + { "^A", "^\bA", 0x00c2 }, + { "^E", "^\bE", 0x00ca }, + { "^I", "^\bI", 0x00ce }, + { "^O", "^\bO", 0x00d4 }, + { "^U", "^\bU", 0x00db }, + { "^a", "^\ba", 0x00e2 }, + { "^e", "^\be", 0x00ea }, + { "^i", "^\bi", 0x00ee }, + { "^o", "^\bo", 0x00f4 }, + { "^u", "^\bu", 0x00fb }, + { ",C", ",\bC", 0x00c7 }, + { ",c", ",\bc", 0x00e7 }, + { "/L", "/\bL", 0x0141 }, + { "/l", "/\bl", 0x0142 }, + { "/O", "/\bO", 0x00d8 }, + { "/o", "/\bo", 0x00f8 }, + { "oA", "o\bA", 0x00c5 }, + { "oa", "o\ba", 0x00e5 }, + + /* Special letters. */ + { "-D", "Dh", 0x00d0 }, + { "Sd", "dh", 0x00f0 }, + { "TP", "Th", 0x00de }, + { "Tp", "th", 0x00fe }, + { ".i", "i", 0x0131 }, + { ".j", "j", 0x0237 }, + + /* Currency. */ + { "Do", "$", 0x0024 }, + { "ct", "/\bc", 0x00a2 }, + { "Eu", "EUR", 0x20ac }, + { "eu", "EUR", 0x20ac }, + { "Ye", "=\bY", 0x00a5 }, + { "Po", "GBP", 0x00a3 }, + { "Cs", "o\bx", 0x00a4 }, + { "Fn", ",\bf", 0x0192 }, + + /* Units. */ + { "de", "", 0x00b0 }, + { "%0", "", 0x2030 }, + { "fm", "\'", 0x2032 }, + { "sd", "''", 0x2033 }, + { "mc", "", 0x00b5 }, + { "Of", "_\ba", 0x00aa }, + { "Om", "_\bo", 0x00ba }, + + /* Greek characters. */ + { "*A", "A", 0x0391 }, + { "*B", "B", 0x0392 }, + { "*G", "", 0x0393 }, + { "*D", "", 0x0394 }, + { "*E", "E", 0x0395 }, + { "*Z", "Z", 0x0396 }, + { "*Y", "H", 0x0397 }, + { "*H", "", 0x0398 }, + { "*I", "I", 0x0399 }, + { "*K", "K", 0x039a }, + { "*L", "", 0x039b }, + { "*M", "M", 0x039c }, + { "*N", "N", 0x039d }, + { "*C", "", 0x039e }, + { "*O", "O", 0x039f }, + { "*P", "", 0x03a0 }, + { "*R", "P", 0x03a1 }, + { "*S", "", 0x03a3 }, + { "*T", "T", 0x03a4 }, + { "*U", "Y", 0x03a5 }, + { "*F", "", 0x03a6 }, + { "*X", "X", 0x03a7 }, + { "*Q", "", 0x03a8 }, + { "*W", "", 0x03a9 }, + { "*a", "", 0x03b1 }, + { "*b", "", 0x03b2 }, + { "*g", "", 0x03b3 }, + { "*d", "", 0x03b4 }, + { "*e", "", 0x03b5 }, + { "*z", "", 0x03b6 }, + { "*y", "", 0x03b7 }, + { "*h", "", 0x03b8 }, + { "*i", "", 0x03b9 }, + { "*k", "", 0x03ba }, + { "*l", "", 0x03bb }, + { "*m", "", 0x03bc }, + { "*n", "", 0x03bd }, + { "*c", "", 0x03be }, + { "*o", "o", 0x03bf }, + { "*p", "", 0x03c0 }, + { "*r", "", 0x03c1 }, + { "*s", "", 0x03c3 }, + { "*t", "", 0x03c4 }, + { "*u", "", 0x03c5 }, + { "*f", "", 0x03d5 }, + { "*x", "", 0x03c7 }, + { "*q", "", 0x03c8 }, + { "*w", "", 0x03c9 }, + { "+h", "", 0x03d1 }, + { "+f", "", 0x03c6 }, + { "+p", "", 0x03d6 }, + { "+e", "", 0x03f5 }, + { "ts", "", 0x03c2 }, +}; + +static struct ohash mchars; + + +void +mchars_free(void) +{ + + ohash_delete(&mchars); +} + +void +mchars_alloc(void) +{ + size_t i; + unsigned int slot; + + mandoc_ohash_init(&mchars, 9, offsetof(struct ln, roffcode)); + for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++) { + slot = ohash_qlookup(&mchars, lines[i].roffcode); + assert(ohash_find(&mchars, slot) == NULL); + ohash_insert(&mchars, slot, lines + i); + } +} + +int +mchars_spec2cp(const char *p, size_t sz) +{ + const struct ln *ln; + const char *end; + + end = p + sz; + ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end)); + return ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1; +} + +int +mchars_num2char(const char *p, size_t sz) +{ + int i; + + i = mandoc_strntoi(p, sz, 10); + return i >= 0 && i < 256 ? i : -1; +} + +int +mchars_num2uc(const char *p, size_t sz) +{ + int i; + + i = mandoc_strntoi(p, sz, 16); + assert(i >= 0 && i <= 0x10FFFF); + return i; +} + +const char * +mchars_spec2str(const char *p, size_t sz, size_t *rsz) +{ + const struct ln *ln; + const char *end; + + end = p + sz; + ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end)); + if (ln == NULL) { + *rsz = 1; + return sz == 1 ? p : NULL; + } + + *rsz = strlen(ln->ascii); + return ln->ascii; +} + +const char * +mchars_uc2str(int uc) +{ + size_t i; + + for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++) + if (uc == lines[i].unicode) + return lines[i].ascii; + return ""; +} Property changes on: head/contrib/mandoc/chars.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/compat_strndup.c =================================================================== --- head/contrib/mandoc/compat_strndup.c (nonexistent) +++ head/contrib/mandoc/compat_strndup.c (revision 338826) @@ -0,0 +1,50 @@ +#include "config.h" + +#if HAVE_STRNDUP + +int dummy; + +#else + +/* $Id: compat_strndup.c,v 1.1 2018/02/27 11:16:23 schwarze Exp $ */ +/* OpenBSD: strndup.c,v 1.2 2015/08/31 02:53:57 guenther Exp */ +/* + * Copyright (c) 2010 Todd C. Miller + * + * 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 + +#include +#include + +char * +strndup(const char *str, size_t maxlen) +{ + char *copy; + size_t len; + + for (len = 0; len < maxlen && str[len] != '\0'; len++) + continue; + + copy = malloc(len + 1); + if (copy != NULL) { + (void)memcpy(copy, str, len); + copy[len] = '\0'; + } + + return copy; +} + +#endif Property changes on: head/contrib/mandoc/compat_strndup.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/config.h =================================================================== --- head/contrib/mandoc/config.h (nonexistent) +++ head/contrib/mandoc/config.h (revision 338826) @@ -0,0 +1,57 @@ +#ifdef __cplusplus +#error "Do not use C++. See the INSTALL file." +#endif + +#if !defined(__GNUC__) || (__GNUC__ < 4) +#define __attribute__(x) +#endif + +#if defined(__linux__) || defined(__MINT__) +#define _GNU_SOURCE /* See test-*.c what needs this. */ +#endif + +#include + +#define MAN_CONF_FILE "/etc/man.conf" +#define MANPATH_BASE "/usr/share/man" +#define MANPATH_DEFAULT "/usr/share/man:/usr/local/man" +#define UTF8_LOCALE "en_US.UTF-8" +#define HAVE_CMSG_XPG42 0 +#define HAVE_DIRENT_NAMLEN 1 +#define HAVE_ENDIAN 0 +#define HAVE_ERR 1 +#define HAVE_FTS 1 +#define HAVE_FTS_COMPARE_CONST 1 +#define HAVE_GETLINE 1 +#define HAVE_GETSUBOPT 1 +#define HAVE_ISBLANK 1 +#define HAVE_MKDTEMP 1 +#define HAVE_NTOHL 1 +#define HAVE_PLEDGE 0 +#define HAVE_PROGNAME 1 +#define HAVE_REALLOCARRAY 1 +#define HAVE_RECALLOCARRAY 0 +#define HAVE_REWB_BSD 1 +#define HAVE_REWB_SYSV 1 +#define HAVE_SANDBOX_INIT 0 +#define HAVE_STRCASESTR 1 +#define HAVE_STRINGLIST 1 +#define HAVE_STRLCAT 1 +#define HAVE_STRLCPY 1 +#define HAVE_STRNDUP 1 +#define HAVE_STRPTIME 1 +#define HAVE_STRSEP 1 +#define HAVE_STRTONUM 1 +#define HAVE_SYS_ENDIAN 1 +#define HAVE_VASPRINTF 1 +#define HAVE_WCHAR 1 +#define HAVE_OHASH 1 + +#define BINM_APROPOS "apropos" +#define BINM_CATMAN "catman" +#define BINM_MAKEWHATIS "makewhatis" +#define BINM_MAN "man" +#define BINM_SOELIM "soelim" +#define BINM_WHATIS "whatis" + +extern void *recallocarray(void *, size_t, size_t, size_t); Property changes on: head/contrib/mandoc/config.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/configure =================================================================== --- head/contrib/mandoc/configure (nonexistent) +++ head/contrib/mandoc/configure (revision 338826) @@ -0,0 +1,580 @@ +#!/bin/sh +# +# $Id: configure,v 1.66 2018/07/31 15:34:00 schwarze Exp $ +# +# Copyright (c) 2014,2015,2016,2017,2018 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. + +set -e + +[ -w config.log ] && mv config.log config.log.old +[ -w config.h ] && mv config.h config.h.old + +# Output file descriptor usage: +# 1 (stdout): config.h, Makefile.local +# 2 (stderr): original stderr, usually to the console +# 3: config.log + +exec 3> config.log +echo "file config.log: writing..." + +# --- default settings ------------------------------------------------- +# Initialize all variables here, +# such that nothing can leak in from the environment. + +SOURCEDIR=`dirname "$0"` + +MANPATH_BASE="/usr/share/man:/usr/X11R6/man" +MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" +OSNAME= +UTF8_LOCALE= + +CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | env -i make -sf -` +CFLAGS= +LDADD= +LDFLAGS= +LD_NANOSLEEP= +LD_OHASH= +LD_RECVMSG= +STATIC= + +BUILD_CGI=0 +BUILD_CATMAN=0 +INSTALL_LIBMANDOC=0 + +HAVE_CMSG= +HAVE_CMSG_XPG42=0 +HAVE_DIRENT_NAMLEN= +HAVE_EFTYPE= +HAVE_ENDIAN= +HAVE_ERR= +HAVE_FTS= +HAVE_FTS_COMPARE_CONST= +HAVE_GETLINE= +HAVE_GETSUBOPT= +HAVE_ISBLANK= +HAVE_MKDTEMP= +HAVE_NANOSLEEP= +HAVE_NTOHL= +HAVE_O_DIRECTORY= +HAVE_OHASH= +HAVE_PATH_MAX= +HAVE_PLEDGE= +HAVE_PROGNAME= +HAVE_REALLOCARRAY= +HAVE_RECALLOCARRAY= +HAVE_RECVMSG= +HAVE_REWB_BSD= +HAVE_REWB_SYSV= +HAVE_SANDBOX_INIT= +HAVE_STRCASESTR= +HAVE_STRINGLIST= +HAVE_STRLCAT= +HAVE_STRLCPY= +HAVE_STRNDUP= +HAVE_STRPTIME= +HAVE_STRSEP= +HAVE_STRTONUM= +HAVE_SYS_ENDIAN= +HAVE_VASPRINTF= +HAVE_WCHAR= + +PREFIX="/usr/local" +BINDIR= +SBINDIR= +BIN_FROM_SBIN= +INCLUDEDIR= +LIBDIR= +MANDIR= +HOMEBREWDIR= + +WWWPREFIX="/var/www" +HTDOCDIR= +CGIBINDIR= + +BINM_APROPOS="apropos" +BINM_CATMAN="catman" +BINM_MAKEWHATIS="makewhatis" +BINM_MAN="man" +BINM_SOELIM="soelim" +BINM_WHATIS="whatis" +MANM_MAN="man" +MANM_MANCONF="man.conf" +MANM_MDOC="mdoc" +MANM_ROFF="roff" +MANM_EQN="eqn" +MANM_TBL="tbl" + +INSTALL="install" +INSTALL_PROGRAM= +INSTALL_LIB= +INSTALL_MAN= +INSTALL_DATA= +LN="ln -f" + +# --- manual settings from configure.local ----------------------------- + +if [ -r ./configure.local ]; then + echo "file configure.local: reading..." 1>&2 + echo "file configure.local: reading..." 1>&3 + cat ./configure.local 1>&3 + . ./configure.local +else + echo "file configure.local: no (fully automatic configuration)" 1>&2 + echo "file configure.local: no (fully automatic configuration)" 1>&3 +fi +echo 1>&3 + +# --- tests functions -------------------------------------------------- + +# Check whether this HAVE_ setting is manually overridden. +# If yes, use the override, if no, do not decide anything yet. +# Arguments: test file name, test var name, manual value +ismanual() { + [ -z "${3}" ] && return 1 + echo "tested ${1}: HAVE_${2}=${3} (manual)" 1>&2 + echo "tested ${1}: HAVE_${2}=${3} (manual)" 1>&3 + echo 1>&3 + return 0 +} + +# Run a single autoconfiguration test. +# In case of success, enable the feature. +# In case of failure, do not decide anything yet. +# Arguments: test file name, test var name, additional CFLAGS +singletest() { + cat 1>&3 << __HEREDOC__ +testing ${1}${3} ... +${COMP} -o test-${1} test-${1}.c ${3} +__HEREDOC__ + + if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} 1>&3 2>&3 + then + echo "partial result of ${1}${3}: ${CC} succeeded" 1>&3 + else + echo "result of ${1}${3}: ${CC} failed with exit status $?" 1>&3 + echo "result of compiling ${1}${3}: no" 1>&3 + echo 1>&3 + return 1 + fi + + if ./test-${1} 1>&3 2>&3; then + echo "tested ${1}${3}: yes" 1>&2 + echo "result of running ${1}${3}: yes" 1>&3 + echo 1>&3 + eval HAVE_${2}=1 + rm "test-${1}" + return 0 + else + echo "result of ${1}${3}: execution failed with exit status $?" 1>&3 + echo "result of running ${1}${3}: no" 1>&3 + echo 1>&3 + rm "test-${1}" + return 1 + fi +} + +# Run a complete autoconfiguration test, including the check for +# a manual override and disabling the feature on failure. +# Arguments: test file name, test var name, additional CFLAGS +runtest() { + eval _manual=\${HAVE_${2}} + ismanual "${1}" "${2}" "${_manual}" && return 0 + singletest "${1}" "${2}" "${3}" && return 0 + echo "tested ${1}${3}: no" 1>&2 + eval HAVE_${2}=0 + return 1 +} + +# Select a UTF-8 locale. +get_locale() { + [ -n "${HAVE_WCHAR}" ] && [ "${HAVE_WCHAR}" -eq 0 ] && return 0 + ismanual UTF8_LOCALE UTF8_LOCALE "$UTF8_LOCALE" && return 0 + echo "testing UTF8_LOCALE ..." 1>&3 + UTF8_LOCALE=`locale -a | grep -i '^en_US\.UTF-*8$' | head -n 1` + if [ -z "${UTF8_LOCALE}" ]; then + UTF8_LOCALE=`locale -a | grep -i '\.UTF-*8' | head -n 1` + [ -n "${UTF8_LOCALE}" ] || return 1 + fi + echo "selected UTF8_LOCALE=${UTF8_LOCALE}" 1>&2 + echo "selected UTF8_LOCALE=${UTF8_LOCALE}" 1>&3 + echo 1>&3 + return 0; +} + +# --- compiler options ------------------------------------------------- + +if [ -n "${CFLAGS}" ]; then + COMP="${CC} ${CFLAGS}" + echo "selected CFLAGS=\"${CFLAGS}\" (manual)" 1>&2 + echo "selected CFLAGS=\"${CFLAGS}\" (manual)" 1>&3 + echo 1>&3 +else + CFLAGS="-g -W -Wall -Wmissing-prototypes -Wstrict-prototypes" + CFLAGS="${CFLAGS} -Wwrite-strings -Wno-unused-parameter" + COMP="${CC} ${CFLAGS} -Wno-unused -Werror" + echo -n "tested ${CC} -W: " 1>&2 + echo -n "testing ${CC} -W: " 1>&3 + runtest noop WFLAG || true + if [ "${HAVE_WFLAG}" -eq 0 ]; then + CFLAGS="-g" + COMP="${CC} ${CFLAGS}" + fi + echo "selected CFLAGS=\"${CFLAGS}\"" 1>&2 + echo "selected CFLAGS=\"${CFLAGS}\"" 1>&3 + echo 1>&3 +fi + +if [ -n "${STATIC}" ]; then + echo "selected STATIC=\"${STATIC}\" (manual)" 1>&2 + echo "selected STATIC=\"${STATIC}\" (manual)" 1>&3 + echo 1>&3 +else + runtest noop STATIC -static || true + [ ${HAVE_STATIC} -eq 0 ] || STATIC="-static" + echo "selected STATIC=\"${STATIC}\"" 1>&2 + echo "selected STATIC=\"${STATIC}\"" 1>&3 + echo 1>&3 +fi + +# --- tests for config.h ---------------------------------------------- + +# --- library functions --- +runtest dirent-namlen DIRENT_NAMLEN || true +runtest be32toh ENDIAN || true +runtest be32toh SYS_ENDIAN -DSYS_ENDIAN || true +runtest EFTYPE EFTYPE || true +runtest err ERR || true +runtest getline GETLINE || true +runtest getsubopt GETSUBOPT || true +runtest isblank ISBLANK || true +runtest mkdtemp MKDTEMP || true +runtest ntohl NTOHL || true +runtest O_DIRECTORY O_DIRECTORY || true +runtest PATH_MAX PATH_MAX || true +runtest pledge PLEDGE || true +runtest sandbox_init SANDBOX_INIT || true +runtest progname PROGNAME || true +runtest reallocarray REALLOCARRAY || true +runtest recallocarray RECALLOCARRAY || true +runtest rewb-bsd REWB_BSD || true +runtest rewb-sysv REWB_SYSV || true +runtest strcasestr STRCASESTR || true +runtest stringlist STRINGLIST || true +runtest strlcat STRLCAT || true +runtest strlcpy STRLCPY || true +runtest strndup STRNDUP || true +runtest strptime STRPTIME || true +runtest strsep STRSEP || true +runtest strtonum STRTONUM || true +runtest vasprintf VASPRINTF || true + +if [ ${HAVE_ENDIAN} -eq 0 -a \ + ${HAVE_SYS_ENDIAN} -eq 0 -a \ + ${HAVE_NTOHL} -eq 0 ]; then + echo "FATAL: no endian conversion functions found" 1>&2 + echo "FATAL: no endian conversion functions found" 1>&3 + exit 1 +fi + +if ismanual fts FTS ${HAVE_FTS}; then + HAVE_FTS_COMPARE_CONST=0 +elif runtest fts FTS_COMPARE_CONST -DFTS_COMPARE_CONST; then + HAVE_FTS=1 +else + runtest fts FTS || true +fi + +# --- wide character and locale support --- +if get_locale; then + runtest wchar WCHAR -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || true +else + HAVE_WCHAR=0 + echo "tested wchar: no (no UTF8_LOCALE)" 1>&2 + echo "tested wchar: no (no UTF8_LOCALE)" 1>&3 + echo 1>&3 +fi + +# --- nanosleep --- +if [ -n "${LD_NANOSLEEP}" ]; then + runtest nanosleep NANOSLEEP "${LD_NANOSLEEP}" || true +elif singletest nanosleep NANOSLEEP; then + : +elif runtest nanosleep NANOSLEEP "-lrt"; then + LD_NANOSLEEP="-lrt" +fi +if [ "${HAVE_NANOSLEEP}" -eq 0 ]; then + echo "FATAL: nanosleep: no" 1>&2 + echo "FATAL: nanosleep: no" 1>&3 + exit 1 +fi + +if [ ${BUILD_CATMAN} -gt 0 ]; then + # --- recvmsg --- + if [ -n "${LD_RECVMSG}" ]; then + runtest recvmsg RECVMSG "${LD_RECVMSG}" || true + elif singletest recvmsg RECVMSG; then + : + elif runtest recvmsg RECVMSG "-lsocket"; then + LD_RECVMSG="-lsocket" + fi + if [ "${HAVE_RECVMSG}" -eq 0 ]; then + echo "FATAL: recvmsg: no" 1>&2 + echo "FATAL: recvmsg: no" 1>&3 + echo "Without recvmsg(2), you cannot BUILD_CATMAN." 1>&2 + exit 1 + fi + + # --- cmsg --- + if singletest cmsg CMSG; then + : + elif runtest cmsg CMSG "-D_XPG4_2"; then + HAVE_CMSG_XPG42=1 + fi + if [ "${HAVE_CMSG}" -eq 0 ]; then + echo "FATAL: cmsg: no" 1>&2 + echo "FATAL: cmsg: no" 1>&3 + echo "Without CMSG_FIRSTHDR(3), you cannot BUILD_CATMAN." 1>&2 + exit 1 + fi +fi + +# --- ohash --- +if ismanual ohash OHASH "${HAVE_OHASH}"; then + : +elif [ -n "${LD_OHASH}" ]; then + runtest ohash OHASH "${LD_OHASH}" || true +elif singletest ohash OHASH; then + : +elif runtest ohash OHASH "-lutil"; then + LD_OHASH="-lutil" +fi +if [ "${HAVE_OHASH}" -eq 0 ]; then + LD_OHASH= +fi + +# --- LDADD --- +LDADD="${LDADD} ${LD_NANOSLEEP} ${LD_RECVMSG} ${LD_OHASH} -lz" +echo "selected LDADD=\"${LDADD}\"" 1>&2 +echo "selected LDADD=\"${LDADD}\"" 1>&3 +echo 1>&3 + +# --- write config.h --- + +exec > config.h + +cat << __HEREDOC__ +#ifdef __cplusplus +#error "Do not use C++. See the INSTALL file." +#endif + +#if !defined(__GNUC__) || (__GNUC__ < 4) +#define __attribute__(x) +#endif + +#if defined(__linux__) || defined(__MINT__) +#define _GNU_SOURCE /* See test-*.c what needs this. */ +#endif + +__HEREDOC__ + +[ ${HAVE_GETLINE} -eq 0 -o \ + ${HAVE_REALLOCARRAY} -eq 0 -o ${HAVE_RECALLOCARRAY} -eq 0 -o \ + ${HAVE_STRLCAT} -eq 0 -o ${HAVE_STRLCPY} -eq 0 -o \ + ${HAVE_STRNDUP} -eq 0 ] \ + && echo "#include " +[ ${HAVE_VASPRINTF} -eq 0 ] && echo "#include " +[ ${HAVE_GETLINE} -eq 0 ] && echo "#include " + +echo +echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\"" +echo "#define MANPATH_BASE \"${MANPATH_BASE}\"" +echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\"" +[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\"" +[ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\"" +[ -n "${HOMEBREWDIR}" ] && echo "#define HOMEBREWDIR \"${HOMEBREWDIR}\"" +[ ${HAVE_EFTYPE} -eq 0 ] && echo "#define EFTYPE EINVAL" +[ ${HAVE_O_DIRECTORY} -eq 0 ] && echo "#define O_DIRECTORY 0" +[ ${HAVE_PATH_MAX} -eq 0 ] && echo "#define PATH_MAX 4096" +if [ ${HAVE_ENDIAN} -eq 0 -a ${HAVE_SYS_ENDIAN} -eq 0 ]; then + echo "#define be32toh ntohl" + echo "#define htobe32 htonl" +fi + +cat << __HEREDOC__ +#define HAVE_CMSG_XPG42 ${HAVE_CMSG_XPG42} +#define HAVE_DIRENT_NAMLEN ${HAVE_DIRENT_NAMLEN} +#define HAVE_ENDIAN ${HAVE_ENDIAN} +#define HAVE_ERR ${HAVE_ERR} +#define HAVE_FTS ${HAVE_FTS} +#define HAVE_FTS_COMPARE_CONST ${HAVE_FTS_COMPARE_CONST} +#define HAVE_GETLINE ${HAVE_GETLINE} +#define HAVE_GETSUBOPT ${HAVE_GETSUBOPT} +#define HAVE_ISBLANK ${HAVE_ISBLANK} +#define HAVE_MKDTEMP ${HAVE_MKDTEMP} +#define HAVE_NTOHL ${HAVE_NTOHL} +#define HAVE_PLEDGE ${HAVE_PLEDGE} +#define HAVE_PROGNAME ${HAVE_PROGNAME} +#define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY} +#define HAVE_RECALLOCARRAY ${HAVE_RECALLOCARRAY} +#define HAVE_REWB_BSD ${HAVE_REWB_BSD} +#define HAVE_REWB_SYSV ${HAVE_REWB_SYSV} +#define HAVE_SANDBOX_INIT ${HAVE_SANDBOX_INIT} +#define HAVE_STRCASESTR ${HAVE_STRCASESTR} +#define HAVE_STRINGLIST ${HAVE_STRINGLIST} +#define HAVE_STRLCAT ${HAVE_STRLCAT} +#define HAVE_STRLCPY ${HAVE_STRLCPY} +#define HAVE_STRNDUP ${HAVE_STRNDUP} +#define HAVE_STRPTIME ${HAVE_STRPTIME} +#define HAVE_STRSEP ${HAVE_STRSEP} +#define HAVE_STRTONUM ${HAVE_STRTONUM} +#define HAVE_SYS_ENDIAN ${HAVE_SYS_ENDIAN} +#define HAVE_VASPRINTF ${HAVE_VASPRINTF} +#define HAVE_WCHAR ${HAVE_WCHAR} +#define HAVE_OHASH ${HAVE_OHASH} + +#define BINM_APROPOS "${BINM_APROPOS}" +#define BINM_CATMAN "${BINM_CATMAN}" +#define BINM_MAKEWHATIS "${BINM_MAKEWHATIS}" +#define BINM_MAN "${BINM_MAN}" +#define BINM_SOELIM "${BINM_SOELIM}" +#define BINM_WHATIS "${BINM_WHATIS}" + +__HEREDOC__ + +if [ ${HAVE_ERR} -eq 0 ]; then + echo "extern void err(int, const char *, ...);" + echo "extern void errx(int, const char *, ...);" + echo "extern void warn(const char *, ...);" + echo "extern void warnx(const char *, ...);" +fi + +[ ${HAVE_GETLINE} -eq 0 ] && \ + echo "extern ssize_t getline(char **, size_t *, FILE *);" + +[ ${HAVE_GETSUBOPT} -eq 0 ] && \ + echo "extern int getsubopt(char **, char * const *, char **);" + +[ ${HAVE_ISBLANK} -eq 0 ] && \ + echo "extern int isblank(int);" + +[ ${HAVE_MKDTEMP} -eq 0 ] && \ + echo "extern char *mkdtemp(char *);" + +if [ ${HAVE_PROGNAME} -eq 0 ]; then + echo "extern const char *getprogname(void);" + echo "extern void setprogname(const char *);" +fi + +[ ${HAVE_REALLOCARRAY} -eq 0 ] && \ + echo "extern void *reallocarray(void *, size_t, size_t);" + +[ ${HAVE_RECALLOCARRAY} -eq 0 ] && \ + echo "extern void *recallocarray(void *, size_t, size_t, size_t);" + +[ ${HAVE_STRCASESTR} -eq 0 ] && \ + echo "extern char *strcasestr(const char *, const char *);" + +[ ${HAVE_STRLCAT} -eq 0 ] && \ + echo "extern size_t strlcat(char *, const char *, size_t);" + +[ ${HAVE_STRLCPY} -eq 0 ] && \ + echo "extern size_t strlcpy(char *, const char *, size_t);" + +[ ${HAVE_STRNDUP} -eq 0 ] && \ + echo "extern char *strndup(const char *, size_t);" + +[ ${HAVE_STRSEP} -eq 0 ] && \ + echo "extern char *strsep(char **, const char *);" + +[ ${HAVE_STRTONUM} -eq 0 ] && \ + echo "extern long long strtonum(const char *, long long, long long, const char **);" + +[ ${HAVE_VASPRINTF} -eq 0 ] && \ + echo "extern int vasprintf(char **, const char *, va_list);" + +echo "file config.h: written" 1>&2 +echo "file config.h: written" 1>&3 + +# --- tests for Makefile.local ----------------------------------------- + +exec > Makefile.local + +[ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin" +[ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin" +[ -z "${BIN_FROM_SBIN}" ] && BIN_FROM_SBIN="../bin" +[ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include/mandoc" +[ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib/mandoc" +[ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man" + +[ -z "${HTDOCDIR}" ] && HTDOCDIR="${WWWPREFIX}/htdocs" +[ -z "${CGIBINDIR}" ] && CGIBINDIR="${WWWPREFIX}/cgi-bin" + +[ -z "${INSTALL_PROGRAM}" ] && INSTALL_PROGRAM="${INSTALL} -m 0555" +[ -z "${INSTALL_LIB}" ] && INSTALL_LIB="${INSTALL} -m 0444" +[ -z "${INSTALL_MAN}" ] && INSTALL_MAN="${INSTALL} -m 0444" +[ -z "${INSTALL_DATA}" ] && INSTALL_DATA="${INSTALL} -m 0444" + +BUILD_TARGETS= +[ ${BUILD_CGI} -gt 0 ] && BUILD_TARGETS="man.cgi" +[ ${BUILD_CATMAN} -gt 0 ] && \ + BUILD_TARGETS="${BUILD_TARGETS} mandocd catman" +INSTALL_TARGETS= +[ ${INSTALL_LIBMANDOC} -gt 0 ] && INSTALL_TARGETS="lib-install" +[ ${BUILD_CGI} -gt 0 ] && INSTALL_TARGETS="${INSTALL_TARGETS} cgi-install" +[ ${BUILD_CATMAN} -gt 0 ] && \ + INSTALL_TARGETS="${INSTALL_TARGETS} catman-install" + +cat << __HEREDOC__ +BUILD_TARGETS = ${BUILD_TARGETS} +INSTALL_TARGETS = ${INSTALL_TARGETS} +CC = ${CC} +CFLAGS = ${CFLAGS} +LDADD = ${LDADD} +LDFLAGS = ${LDFLAGS} +STATIC = ${STATIC} +PREFIX = ${PREFIX} +BINDIR = ${BINDIR} +SBINDIR = ${SBINDIR} +BIN_FROM_SBIN = ${BIN_FROM_SBIN} +INCLUDEDIR = ${INCLUDEDIR} +LIBDIR = ${LIBDIR} +MANDIR = ${MANDIR} +WWWPREFIX = ${WWWPREFIX} +HTDOCDIR = ${HTDOCDIR} +CGIBINDIR = ${CGIBINDIR} +BINM_APROPOS = ${BINM_APROPOS} +BINM_CATMAN = ${BINM_CATMAN} +BINM_MAKEWHATIS = ${BINM_MAKEWHATIS} +BINM_MAN = ${BINM_MAN} +BINM_SOELIM = ${BINM_SOELIM} +BINM_WHATIS = ${BINM_WHATIS} +MANM_MAN = ${MANM_MAN} +MANM_MANCONF = ${MANM_MANCONF} +MANM_MDOC = ${MANM_MDOC} +MANM_ROFF = ${MANM_ROFF} +MANM_EQN = ${MANM_EQN} +MANM_TBL = ${MANM_TBL} +INSTALL = ${INSTALL} +INSTALL_PROGRAM = ${INSTALL_PROGRAM} +INSTALL_LIB = ${INSTALL_LIB} +INSTALL_MAN = ${INSTALL_MAN} +INSTALL_DATA = ${INSTALL_DATA} +LN = ${LN} +__HEREDOC__ + +echo "file Makefile.local: written" 1>&2 +echo "file Makefile.local: written" 1>&3 + +exit 0 Property changes on: head/contrib/mandoc/configure ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: head/contrib/mandoc/configure.local.example =================================================================== --- head/contrib/mandoc/configure.local.example (nonexistent) +++ head/contrib/mandoc/configure.local.example (revision 338826) @@ -0,0 +1,316 @@ +# $Id: configure.local.example,v 1.34 2018/07/31 15:34:00 schwarze Exp $ +# +# Copyright (c) 2014,2015,2016,2017,2018 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. + +# For all settings documented in this file, there are reasonable +# defaults and/or the ./configure script attempts autodetection. +# Consequently, you only need to create a file ./configure.local +# and put any of these settings into it if ./configure autodetection +# fails or if you want to make different choices for other reasons. + +# If autodetection fails, please tell . + +# We recommend that you write ./configure.local from scratch and +# only put the lines there you need. This file contains examples. +# It is not intended as a template to be copied as a whole. + +# --- user settings relevant for all builds ---------------------------- + +# For -Tutf8 and -Tlocale operation, mandoc(1) requires +# providing setlocale(3) and providing wcwidth(3) and +# putwchar(3) with a wchar_t storing UCS-4 values. Theoretically, +# the latter should be tested with the __STDC_ISO_10646__ feature +# macro. In practice, many headers do not provide that +# macro even though they treat wchar_t as UCS-4. So the automatic +# test only checks that wchar_t is wide enough, that is, at least +# four bytes. + +# The following line forces multi-byte support. +# If your C library does not treat wchar_t as UCS-4, the UTF-8 output +# mode will print garbage. + +HAVE_WCHAR=1 + +# The following line disables multi-byte support. +# The output modes -Tutf8 and -Tlocale will be the same as -Tascii. + +HAVE_WCHAR=0 + +# For -Tutf8 mode, mandoc needs to set an arbitrary locale having +# a UTF-8 character set. If autodetection of a suitable locale +# fails or selects an undesirable locale, you can manually choose +# the locale for -Tutf8 mode: + +UTF8_LOCALE=en_US.UTF-8 + +# When man(1) or apropos(1) is called without -m and -M options, +# MANPATH is not set in the environment, and man.conf(5) is not +# available, manuals are searched for in the following directory +# trees by default. + +MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" + +# Validation of cross references with mandoc -Tlint only looks +# for manual pages in the following directories: + +MANPATH_BASE="/usr/share/man:/usr/X11R6/man" + +# In manual pages written in the mdoc(7) language, the operating system +# version is displayed in the page footer line. If an operating system +# is specified as an argument to the .Os macro, that is always used. +# If the .Os macro has no argument and an operation system is specified +# with the mandoc(1) -Ios= command line option, that is used. +# Otherwise, the uname(3) library function is called at runtime to find +# the name of the operating system. +# If you do not want uname(3) to be called but instead want a fixed +# string to be used, use the following line: + +OSNAME="OpenBSD 6.3" + +# The following installation directories are used. +# It is possible to set only one or a few of these variables, +# there is no need to copy the whole block. +# Even if you set PREFIX to something else, the other variables +# pick it up without copying them all over. + +PREFIX="/usr/local" +BINDIR="${PREFIX}/bin" +SBINDIR="${PREFIX}/sbin" +MANDIR="${PREFIX}/man" + +# If BINDIR and SBINDIR are not subdirectories of the same parent +# directory or if the basename(1) of BINDIR differs from "bin", +# the relative path from SBINDIR to BINDIR is also needed. +# The default is: + +BIN_FROM_SBIN="../bin" + +# Some distributions may want to avoid naming conflicts +# with the configuration files of other man(1) implementations. +# This changes the name of the installed section 5 manual page as well. + +MANM_MANCONF="mandoc.conf" # default is "man.conf" + +# Some distributions may want to avoid naming conflicts among manuals. +# If you want to change the names of installed section 7 manual pages, +# the following alternative names are suggested. +# The suffix ".7" will automatically be appended. +# It is possible to set only one or a few of these variables, +# there is no need to copy the whole block. + +MANM_MAN="mandoc_man" # default is "man" +MANM_MDOC="mandoc_mdoc" # default is "mdoc" +MANM_ROFF="mandoc_roff" # default is "roff" +MANM_EQN="mandoc_eqn" # default is "eqn" +MANM_TBL="mandoc_tbl" # default is "tbl" + +# Some distributions may want to avoid naming conflicts with +# other man(1), apropos(1), makewhatis(8), or soelim(1) utilities. +# If you want to change the names of binary programs, +# the following alternative names are suggested. +# Using different names is possible as well. +# This changes the names of the installed section 1 and section 8 +# manual pages as well. +# It is possible to set only one or two of these variables, +# there is no need to copy the whole block. + +BINM_MAN=mman # default is "man" +BINM_APROPOS=mapropos # default is "apropos" +BINM_WHATIS=mwhatis # default is "whatis" +BINM_MAKEWHATIS=mandocdb # default is "makewhatis" +BINM_SOELIM=msoelim # default is "soelim" + +# Some distributions do not want hardlinks +# between installed binary programs. +# Set the following variable to use symbolic links instead. +# It is also used for links between manual pages. +# It is only used by the install* targets. +# When using this, DESTDIR must be empty or an absolute path. + +LN="ln -sf" # default is "ln -f" + +# Before falling back to the bundled version of the ohash(3) hashing +# library, autoconfiguration tries the following linker flag to +# link against your system version. If you do have ohash(3) on +# your system but it needs different linker flags, set the following +# variable to specify the required linker flags. + +LD_OHASH="-lutil" + +# Some platforms may need an additional linker flag for nanosleep(2). +# If none is needed or it is -lrt, it is autodetected. +# Otherwise, set the following variable. + +LD_NANOSLEEP="-lrt" + +# Some platforms may need an additional linker flag for recvmsg(2). +# If none is needed or it is -lsocket, it is autodetected. +# Otherwise, set the following variable. + +LD_RECVMSG="-lsocket" + +# Some platforms might need additional linker flags to link against +# libmandoc that are not autodetected, though no such cases are +# currently known. + +LDADD="-lm" + +# Some systems may want to set additional linker flags for all the +# binaries, not only for those using libmandoc, for example for +# hardening options. + +LDFLAGS="-Wl,-z,relro" + +# It is possible to change the utility program used for installation +# and the modes files are installed with. The defaults are: + +INSTALL="install" +INSTALL_PROGRAM="${INSTALL} -m 0555" +INSTALL_LIB="${INSTALL} -m 0444" +INSTALL_MAN="${INSTALL} -m 0444" +INSTALL_DATA="${INSTALL} -m 0444" + +# When using the "homebrew" package manager on Mac OS X, the actual +# manuals are located in a so-called "cellar" and only symlinked +# into the manual trees. To allow mandoc to follow such symlinks, +# you have to specify the physical location of the cellar as returned +# by realpath(3), for example: + +PREFIX="/usr/local" +HOMEBREWDIR="${PREFIX}/Cellar" + +# --- user settings for the mandoc(3) library -------------------------- + +# By default, libmandoc.a is not installed. It is almost never needed +# because there is almost no non-mandoc software out there using this +# library. The one notable exception is NetBSD apropos(1). +# So, when building for the NetBSD base system - but not for NetBSD +# ports nor for pkgsrc! - you may want the following: + +INSTALL_LIBMANDOC=1 + +# The following settings are only used when INSTALL_LIBMANDOC is set. + +INCLUDEDIR="${PREFIX}/include/mandoc" +LIBDIR="${PREFIX}/lib/mandoc" + +# --- user settings related to man.cgi --------------------------------- + +# By default, building man.cgi(8) is disabled. To enable it, copy +# cgi.h.example to cgi.h, edit it, and use the following line. + +BUILD_CGI=1 + +# The remaining settings in this section are only relevant if BUILD_CGI +# is enabled. Otherwise, they have no effect either way. + +# By default, man.cgi(8) is linked statically if the compiler supports +# the -static option. If automatic detection fails, you can force +# static linking of man.cgi(8). + +STATIC="-static" + +# Some systems may require -pthread for static linking: + +STATIC="-static -pthread" + +# If static linking works in general but not with additional libraries +# like -lrt or -lz, you can force dynamic linking. This may for +# example be required on SunOS 5.9. + +STATIC=" " + +# Some directories. +# This works just like PREFIX, see above. + +WWWPREFIX="/var/www" +HTDOCDIR="${WWWPREFIX}/htdocs" +CGIBINDIR="${WWWPREFIX}/cgi-bin" + +# --- user settings related to catman ---------------------------------- + +# By default, building mandocd(8) and catman(8) is disabled. +# To enable it, use the following line. +# It does not work on SunOS 5.10 because there is no mkdirat(2) +# nor on SunOS 5.9 which also lacks CMSG_LEN(3) and CMSG_SPACE(3). + +BUILD_CATMAN=1 + +# Install catman(8) with a different name. +# See BINM_MAN above for details of how this works. + +BINM_CATMAN=mcatman # default is "catman" + +# --- settings that rarely need to be touched -------------------------- + +# Do not set these variables unless you really need to. + +# You can manually override the compiler to be used. +# But that's rarely useful because ./configure asks your make(1) +# which compiler to use, and that answer will hardly be wrong. + +CC=cc + +# Because the system compiler may not provide , +# SunOS 5.9 may need: + +CC=gcc + +# IBM AIX may need: + +CC=xlc + +# Normally, leave CFLAGS unset. In that case, -g will automatically +# be used, and various -W options will be added if the compiler +# supports them. If you define CFLAGS manually, it will be used +# unchanged, and nothing will be added. + +CFLAGS="-g" + +# In rare cases, it may be required to skip individual automatic tests. +# Each of the following variables can be set to 0 (test will not be run +# and will be regarded as failed) or 1 (test will not be run and will +# be regarded as successful). + +HAVE_DIRENT_NAMLEN=0 +HAVE_ENDIAN=0 +HAVE_EFTYPE=0 +HAVE_ERR=0 +HAVE_FTS=0 # Setting this implies HAVE_FTS_COMPARE_CONST=0. +HAVE_FTS_COMPARE_CONST=0 # Setting this implies HAVE_FTS=1. +HAVE_GETLINE=0 +HAVE_GETSUBOPT=0 +HAVE_ISBLANK=0 +HAVE_MKDTEMP=0 +HAVE_NTOHL=0 +HAVE_O_DIRECTORY=0 +HAVE_OHASH=0 +HAVE_PATH_MAX=0 +HAVE_PLEDGE=0 +HAVE_PROGNAME=0 +HAVE_REALLOCARRAY=0 +HAVE_RECALLOCARRAY=0 +HAVE_REWB_BSD=0 +HAVE_REWB_SYSV=0 +HAVE_STRCASESTR=0 +HAVE_STRINGLIST=0 +HAVE_STRLCAT=0 +HAVE_STRLCPY=0 +HAVE_STRPTIME=0 +HAVE_STRSEP=0 +HAVE_STRTONUM=0 +HAVE_SYS_ENDIAN=0 +HAVE_VASPRINTF=0 +HAVE_WCHAR=0 Index: head/contrib/mandoc/eqn.7 =================================================================== --- head/contrib/mandoc/eqn.7 (nonexistent) +++ head/contrib/mandoc/eqn.7 (revision 338826) @@ -0,0 +1,500 @@ +.\" $Id: eqn.7,v 1.37 2017/09/04 10:35:27 schwarze Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons +.\" Copyright (c) 2014 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: September 4 2017 $ +.Dt EQN 7 +.Os +.Sh NAME +.Nm eqn +.Nd eqn language reference for mandoc +.Sh DESCRIPTION +The +.Nm eqn +language is an equation-formatting language. +It is used within +.Xr mdoc 7 +and +.Xr man 7 +.Ux +manual pages. +It describes the +.Em structure +of an equation, not its mathematical meaning. +This manual describes the +.Nm +language accepted by the +.Xr mandoc 1 +utility, which corresponds to the Second Edition +.Nm +specification (see +.Sx SEE ALSO +for references). +.Pp +Equations within +.Xr mdoc 7 +or +.Xr man 7 +documents are enclosed by the standalone +.Sq \&.EQ +and +.Sq \&.EN +tags. +Equations are multi-line blocks consisting of formulas and control +statements. +.Sh EQUATION STRUCTURE +Each equation is bracketed by +.Sq \&.EQ +and +.Sq \&.EN +strings. +.Em Note : +these are not the same as +.Xr roff 7 +macros, and may only be invoked as +.Sq \&.EQ . +.Pp +The equation grammar is as follows, where quoted strings are +case-sensitive literals in the input: +.Bd -literal -offset indent +eqn : box | eqn box +box : text + | \(dq{\(dq eqn \(dq}\(dq + | \(dqdefine\(dq text text + | \(dqndefine\(dq text text + | \(dqtdefine\(dq text text + | \(dqgfont\(dq text + | \(dqgsize\(dq text + | \(dqset\(dq text text + | \(dqundef\(dq text + | \(dqsqrt\(dq box + | box pos box + | box mark + | \(dqmatrix\(dq \(dq{\(dq [col \(dq{\(dq list \(dq}\(dq]* \(dq}\(dq + | pile \(dq{\(dq list \(dq}\(dq + | font box + | \(dqsize\(dq text box + | \(dqleft\(dq text eqn [\(dqright\(dq text] +col : \(dqlcol\(dq | \(dqrcol\(dq | \(dqccol\(dq | \(dqcol\(dq +text : [^space\e\(dq]+ | \e\(dq.*\e\(dq +pile : \(dqlpile\(dq | \(dqcpile\(dq | \(dqrpile\(dq | \(dqpile\(dq +pos : \(dqover\(dq | \(dqsup\(dq | \(dqsub\(dq | \(dqto\(dq | \(dqfrom\(dq +mark : \(dqdot\(dq | \(dqdotdot\(dq | \(dqhat\(dq | \(dqtilde\(dq | \(dqvec\(dq + | \(dqdyad\(dq | \(dqbar\(dq | \(dqunder\(dq +font : \(dqroman\(dq | \(dqitalic\(dq | \(dqbold\(dq | \(dqfat\(dq +list : eqn + | list \(dqabove\(dq eqn +space : [\e^~ \et] +.Ed +.Pp +White-space consists of the space, tab, circumflex, and tilde +characters. +It is required to delimit tokens consisting of alphabetic characters +and it is ignored at other places. +Braces and quotes also delimit tokens. +If within a quoted string, these space characters are retained. +Quoted strings are also not scanned for keywords, glyph names, +and expansion of definitions. +To print a literal quote character, it can be prepended with a +backslash or expressed with the \e(dq escape sequence. +.Pp +Subequations can be enclosed in braces to pass them as arguments +to operation keywords, overriding standard operation precedence. +Braces can be nested. +To set a brace verbatim, it needs to be enclosed in quotes. +.Pp +The following text terms are translated into a rendered glyph, if +available: alpha, beta, chi, delta, epsilon, eta, gamma, iota, kappa, +lambda, mu, nu, omega, omicron, phi, pi, psi, rho, sigma, tau, theta, +upsilon, xi, zeta, DELTA, GAMMA, LAMBDA, OMEGA, PHI, PI, PSI, SIGMA, +THETA, UPSILON, XI, inter (intersection), union (union), prod (product), +int (integral), sum (summation), grad (gradient), del (vector +differential), times (multiply), cdot (center-dot), nothing (zero-width +space), approx (approximately equals), prime (prime), half (one-half), +partial (partial differential), inf (infinity), >> (much greater), << +(much less), <\- (left arrow), \-> (right arrow), +\- (plus-minus), != +(not equal), == (equivalence), <= (less-than-equal), and >= +(more-than-equal). +The character escape sequences documented in +.Xr mandoc_char 7 +can be used, too. +.Pp +The following control statements are available: +.Bl -tag -width Ds +.It Cm define +Replace all occurrences of a key with a value. +Its syntax is as follows: +.Pp +.D1 Cm define Ar key cvalc +.Pp +The first character of the value string, +.Ar c , +is used as the delimiter for the value +.Ar val . +This allows for arbitrary enclosure of terms (not just quotes), such as +.Pp +.D1 Cm define Ar foo \(aqbar baz\(aq +.D1 Cm define Ar foo cbar bazc +.Pp +It is an error to have an empty +.Ar key +or +.Ar val . +Note that a quoted +.Ar key +causes errors in some +.Nm +implementations and should not be considered portable. +It is not expanded for replacements. +Definitions may refer to other definitions; these are evaluated +recursively when text replacement occurs and not when the definition is +created. +.Pp +Definitions can create arbitrary strings, for example, the following is +a legal construction. +.Bd -literal -offset indent +define foo \(aqdefine\(aq +foo bar \(aqbaz\(aq +.Ed +.Pp +Self-referencing definitions will raise an error. +The +.Cm ndefine +statement is a synonym for +.Cm define , +while +.Cm tdefine +is discarded. +.It Cm gfont +Set the default font of subsequent output. +Its syntax is as follows: +.Pp +.D1 Cm gfont Ar font +.Pp +In mandoc, this value is discarded. +.It Cm gsize +Set the default size of subsequent output. +Its syntax is as follows: +.Pp +.D1 Cm gsize Oo +|\- Oc Ns Ar size +.Pp +The +.Ar size +value should be an integer. +If prepended by a sign, +the font size is changed relative to the current size. +.It Cm set +Set an equation mode. +In mandoc, both arguments are thrown away. +Its syntax is as follows: +.Pp +.D1 Cm set Ar key val +.Pp +The +.Ar key +and +.Ar val +are not expanded for replacements. +This statement is a GNU extension. +.It Cm undef +Unset a previously-defined key. +Its syntax is as follows: +.Pp +.D1 Cm define Ar key +.Pp +Once invoked, the definition for +.Ar key +is discarded. +The +.Ar key +is not expanded for replacements. +This statement is a GNU extension. +.El +.Pp +Operation keywords have the following semantics: +.Bl -tag -width Ds +.It Cm above +See +.Cm pile . +.It Cm bar +Draw a line over the preceding box. +.It Cm bold +Set the following box using bold font. +.It Cm ccol +Like +.Cm cpile , +but for use in +.Cm matrix . +.It Cm cpile +Like +.Cm pile , +but with slightly increased vertical spacing. +.It Cm dot +Set a single dot over the preceding box. +.It Cm dotdot +Set two dots (dieresis) over the preceding box. +.It Cm dyad +Set a dyad symbol (left-right arrow) over the preceding box. +.It Cm fat +A synonym for +.Cm bold . +.It Cm font +Set the second argument using the font specified by the first argument; +currently not recognized by the +.Xr mandoc 1 +.Nm +parser. +.It Cm from +Set the following box below the preceding box, +using a slightly smaller font. +Used for sums, integrals, limits, and the like. +.It Cm hat +Set a hat (circumflex) over the preceding box. +.It Cm italic +Set the following box using italic font. +.It Cm lcol +Like +.Cm lpile , +but for use in +.Cm matrix . +.It Cm left +Set the first argument as a big left delimiter before the second argument. +As an optional third argument, +.Cm right +can follow. +In that case, the fourth argument is set as a big right delimiter after +the second argument. +.It Cm lpile +Like +.Cm cpile , +but subequations are left-justified. +.It Cm matrix +Followed by a list of columns enclosed in braces. +All columns need to have the same number of subequations. +The columns are set as a matrix. +The difference compared to multiple subsequent +.Cm pile +operators is that in a +.Cm matrix , +corresponding subequations in all columns line up horizontally, +while each +.Cm pile +does vertical spacing independently. +.It Cm over +Set a fraction. +The preceding box is the numerator, the following box is the denominator. +.It Cm pile +Followed by a list of subequations enclosed in braces, +the subequations being separated by +.Cm above +keywords. +Sets the subequations one above the other, each of them centered. +Typically used to represent vectors in coordinate representation. +.It Cm rcol +Like +.Cm rpile , +but for use in +.Cm matrix . +.It Cm right +See +.Cm left ; +.Cm right +cannot be used without +.Cm left . +To set a big right delimiter without a big left delimiter, the following +construction can be used: +.Pp +.D1 Cm left No \(dq\(dq Ar box Cm right Ar delimiter +.It Cm roman +Set the following box using the default font. +.It Cm rpile +Like +.Cm cpile , +but subequations are right-justified. +.It Cm size +Set the second argument with the font size specified by the first +argument; currently ignored by +.Xr mandoc 1 . +By prepending a plus or minus sign to the first argument, +the font size can be selected relative to the current size. +.It Cm sqrt +Set the square root of the following box. +.It Cm sub +Set the following box as a subscript to the preceding box. +.It Cm sup +Set the following box as a superscript to the preceding box. +As a special case, if a +.Cm sup +clause immediately follows a +.Cm sub +clause as in +.Pp +.D1 Ar mainbox Cm sub Ar subbox Cm sup Ar supbox +.Pp +both are set with respect to the same +.Ar mainbox , +that is, +.Ar supbox +is set above +.Ar subbox . +.It Cm tilde +Set a tilde over the preceding box. +.It Cm to +Set the following box above the preceding box, +using a slightly smaller font. +Used for sums and integrals and the like. +As a special case, if a +.Cm to +clause immediately follows a +.Cm from +clause as in +.Pp +.D1 Ar mainbox Cm from Ar frombox Cm to Ar tobox +.Pp +both are set below and above the same +.Ar mainbox . +.It Cm under +Underline the preceding box. +.It Cm vec +Set a vector symbol (right arrow) over the preceding box. +.El +.Pp +The binary operations +.Cm from , +.Cm to , +.Cm sub , +and +.Cm sup +group to the right, that is, +.Pp +.D1 Ar mainbox Cm sup Ar supbox Cm sub Ar subbox +.Pp +is the same as +.Pp +.D1 Ar mainbox Cm sup Brq Ar supbox Cm sub Ar subbox +.Pp +and different from +.Pp +.D1 Bro Ar mainbox Cm sup Ar supbox Brc Cm sub Ar subbox . +.Pp +By contrast, +.Cm over +groups to the left. +.Pp +In the following list, earlier operations bind more tightly than +later operations: +.Pp +.Bl -enum -compact +.It +.Cm dyad , +.Cm vec , +.Cm under , +.Cm bar , +.Cm tilde , +.Cm hat , +.Cm dot , +.Cm dotdot +.It +.Cm fat , +.Cm roman , +.Cm italic , +.Cm bold , +.Cm size +.It +.Cm sub , +.Cm sup +.It +.Cm sqrt +.It +.Cm over +.It +.Cm from , +.Cm to +.El +.Sh COMPATIBILITY +This section documents the compatibility of mandoc +.Nm +and the troff +.Nm +implementation (including GNU troff). +.Pp +.Bl -dash -compact +.It +The text string +.Sq \e\(dq +is interpreted as a literal quote in troff. +In mandoc, this is interpreted as a comment. +.It +In troff, The circumflex and tilde white-space symbols map to +fixed-width spaces. +In mandoc, these characters are synonyms for the space character. +.It +The troff implementation of +.Nm +allows for equation alignment with the +.Cm mark +and +.Cm lineup +tokens. +mandoc discards these tokens. +The +.Cm back Ar n , +.Cm fwd Ar n , +.Cm up Ar n , +and +.Cm down Ar n +commands are also ignored. +.El +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr man 7 , +.Xr mandoc_char 7 , +.Xr mdoc 7 , +.Xr roff 7 +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T System for Typesetting Mathematics +.%J Communications of the ACM +.%V 18 +.%P 151\(en157 +.%D March, 1975 +.Re +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T Typesetting Mathematics, User's Guide +.%D 1976 +.Re +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T Typesetting Mathematics, User's Guide (Second Edition) +.%D 1978 +.Re +.Sh HISTORY +The eqn utility, a preprocessor for troff, was originally written by +Brian W. Kernighan and Lorinda L. Cherry in 1975. +The GNU reimplementation of eqn, part of the GNU troff package, was +released in 1989 by James Clark. +The eqn component of +.Xr mandoc 1 +was added in 2011. +.Sh AUTHORS +This +.Nm +reference was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . Property changes on: head/contrib/mandoc/eqn.7 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/eqn_term.c =================================================================== --- head/contrib/mandoc/eqn_term.c (nonexistent) +++ head/contrib/mandoc/eqn_term.c (revision 338826) @@ -0,0 +1,174 @@ +/* $Id: eqn_term.c,v 1.17 2017/08/23 21:56:20 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * 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. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "out.h" +#include "term.h" + +static const enum termfont fontmap[EQNFONT__MAX] = { + TERMFONT_NONE, /* EQNFONT_NONE */ + TERMFONT_NONE, /* EQNFONT_ROMAN */ + TERMFONT_BOLD, /* EQNFONT_BOLD */ + TERMFONT_BOLD, /* EQNFONT_FAT */ + TERMFONT_UNDER /* EQNFONT_ITALIC */ +}; + +static void eqn_box(struct termp *, const struct eqn_box *); + + +void +term_eqn(struct termp *p, const struct eqn_box *bp) +{ + + eqn_box(p, bp); + p->flags &= ~TERMP_NOSPACE; +} + +static void +eqn_box(struct termp *p, const struct eqn_box *bp) +{ + const struct eqn_box *child; + const char *cp; + int delim; + + /* Delimiters around this box? */ + + if ((bp->type == EQN_LIST && bp->expectargs > 1) || + (bp->type == EQN_PILE && (bp->prev || bp->next)) || + (bp->parent != NULL && (bp->parent->pos == EQNPOS_SQRT || + /* Diacritic followed by ^ or _. */ + ((bp->top != NULL || bp->bottom != NULL) && + bp->parent->type == EQN_SUBEXPR && + bp->parent->pos != EQNPOS_OVER && bp->next != NULL) || + /* Nested over, sub, sup, from, to. */ + (bp->type == EQN_SUBEXPR && bp->pos != EQNPOS_SQRT && + ((bp->parent->type == EQN_LIST && bp->expectargs == 1) || + (bp->parent->type == EQN_SUBEXPR && + bp->pos != EQNPOS_SQRT)))))) { + if ((bp->parent->type == EQN_SUBEXPR && bp->prev != NULL) || + (bp->type == EQN_LIST && + bp->first != NULL && + bp->first->type != EQN_PILE && + bp->first->type != EQN_MATRIX && + bp->prev != NULL && + (bp->prev->type == EQN_LIST || + (bp->prev->type == EQN_TEXT && + (*bp->prev->text == '\\' || + isalpha((unsigned char)*bp->prev->text)))))) + p->flags |= TERMP_NOSPACE; + term_word(p, bp->left != NULL ? bp->left : "("); + p->flags |= TERMP_NOSPACE; + delim = 1; + } else + delim = 0; + + /* Handle Fonts and text. */ + + if (bp->font != EQNFONT_NONE) + term_fontpush(p, fontmap[(int)bp->font]); + + if (bp->text != NULL) { + if (strchr("!\"'),.:;?]}", *bp->text) != NULL) + p->flags |= TERMP_NOSPACE; + term_word(p, bp->text); + if ((cp = strchr(bp->text, '\0')) > bp->text && + (strchr("\"'([{", cp[-1]) != NULL || + (bp->prev == NULL && (cp[-1] == '-' || + (cp >= bp->text + 5 && + strcmp(cp - 5, "\\[mi]") == 0))))) + p->flags |= TERMP_NOSPACE; + } + + /* Special box types. */ + + if (bp->pos == EQNPOS_SQRT) { + term_word(p, "sqrt"); + if (bp->first != NULL) { + p->flags |= TERMP_NOSPACE; + eqn_box(p, bp->first); + } + } else if (bp->type == EQN_SUBEXPR) { + child = bp->first; + eqn_box(p, child); + p->flags |= TERMP_NOSPACE; + term_word(p, bp->pos == EQNPOS_OVER ? "/" : + (bp->pos == EQNPOS_SUP || + bp->pos == EQNPOS_TO) ? "^" : "_"); + child = child->next; + if (child != NULL) { + p->flags |= TERMP_NOSPACE; + eqn_box(p, child); + if (bp->pos == EQNPOS_FROMTO || + bp->pos == EQNPOS_SUBSUP) { + p->flags |= TERMP_NOSPACE; + term_word(p, "^"); + p->flags |= TERMP_NOSPACE; + child = child->next; + if (child != NULL) + eqn_box(p, child); + } + } + } else { + child = bp->first; + if (bp->type == EQN_MATRIX && + child != NULL && + child->type == EQN_LIST && + child->expectargs > 1) + child = child->first; + while (child != NULL) { + eqn_box(p, + bp->type == EQN_PILE && + child->type == EQN_LIST && + child->expectargs > 1 && + child->args == 1 ? + child->first : child); + child = child->next; + } + } + + /* Handle Fonts and diacritics. */ + + if (bp->font != EQNFONT_NONE) + term_fontpop(p); + if (bp->top != NULL) { + p->flags |= TERMP_NOSPACE; + term_word(p, bp->top); + } + if (bp->bottom != NULL) { + p->flags |= TERMP_NOSPACE; + term_word(p, "_"); + } + + /* Right delimiter after this box? */ + + if (delim) { + p->flags |= TERMP_NOSPACE; + term_word(p, bp->right != NULL ? bp->right : ")"); + if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL) + p->flags |= TERMP_NOSPACE; + } +} Property changes on: head/contrib/mandoc/eqn_term.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/gmdiff =================================================================== --- head/contrib/mandoc/gmdiff (nonexistent) +++ head/contrib/mandoc/gmdiff (revision 338826) @@ -0,0 +1,57 @@ +#!/bin/sh +# Copyright (c) 2013,2014,2015,2017,2018 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. + +if [ `id -u` -eq 0 ]; then + echo "$0: do not run me as root" + exit 1 +fi + +if [ $# -eq 0 ]; then + echo "usage: $0 [-h|-u] manual_source_file ..." + exit 1 +fi + +if [ "X$1" = "X-h" ]; then + shift + export PATH="/usr/local/heirloom-doctools/bin:$PATH" + EQN="neqn" + ROFF="nroff" + MOPT="-Ios=BSD -Tascii $MOPT" + COLPIPE="col -b" +elif [ "X$1" = "X-u" ]; then + shift + ROFF="groff -ket -ww -Tutf8 -P -c" + MOPT="-Ios=OpenBSD -Wall -Tutf8 $MOPT" + COLPIPE="cat" +else + ROFF="groff -et -ww -mtty-char -Tascii -P -c" + MOPT="-Ios=OpenBSD -Wall -Tascii $MOPT" + COLPIPE="cat" +fi + +while [ -n "$1" ]; do + file=$1 + shift + echo " ========== $file ========== " + $ROFF -mandoc $file | $COLPIPE 2> /tmp/roff.err > /tmp/roff.out + ${MANDOC:=mandoc} $MOPT $file | $COLPIPE \ + 2> /tmp/mandoc.err > /tmp/mandoc.out + for i in roff mandoc; do + [ -s /tmp/$i.err ] && echo "$i errors:" && cat /tmp/$i.err + done + diff -au /tmp/roff.out /tmp/mandoc.out 2>&1 +done + +exit 0 Index: head/contrib/mandoc/html.c =================================================================== --- head/contrib/mandoc/html.c (nonexistent) +++ head/contrib/mandoc/html.c (revision 338826) @@ -0,0 +1,886 @@ +/* $Id: html.c,v 1.238 2018/06/25 16:54:59 schwarze Exp $ */ +/* + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons + * Copyright (c) 2011-2015, 2017, 2018 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 + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "mandoc.h" +#include "roff.h" +#include "out.h" +#include "html.h" +#include "manconf.h" +#include "main.h" + +struct htmldata { + const char *name; + int flags; +#define HTML_NOSTACK (1 << 0) +#define HTML_AUTOCLOSE (1 << 1) +#define HTML_NLBEFORE (1 << 2) +#define HTML_NLBEGIN (1 << 3) +#define HTML_NLEND (1 << 4) +#define HTML_NLAFTER (1 << 5) +#define HTML_NLAROUND (HTML_NLBEFORE | HTML_NLAFTER) +#define HTML_NLINSIDE (HTML_NLBEGIN | HTML_NLEND) +#define HTML_NLALL (HTML_NLAROUND | HTML_NLINSIDE) +#define HTML_INDENT (1 << 6) +#define HTML_NOINDENT (1 << 7) +}; + +static const struct htmldata htmltags[TAG_MAX] = { + {"html", HTML_NLALL}, + {"head", HTML_NLALL | HTML_INDENT}, + {"body", HTML_NLALL}, + {"meta", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, + {"title", HTML_NLAROUND}, + {"div", HTML_NLAROUND}, + {"div", 0}, + {"h1", HTML_NLAROUND}, + {"h2", HTML_NLAROUND}, + {"span", 0}, + {"link", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, + {"br", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, + {"a", 0}, + {"table", HTML_NLALL | HTML_INDENT}, + {"tr", HTML_NLALL | HTML_INDENT}, + {"td", HTML_NLAROUND}, + {"li", HTML_NLAROUND | HTML_INDENT}, + {"ul", HTML_NLALL | HTML_INDENT}, + {"ol", HTML_NLALL | HTML_INDENT}, + {"dl", HTML_NLALL | HTML_INDENT}, + {"dt", HTML_NLAROUND}, + {"dd", HTML_NLAROUND | HTML_INDENT}, + {"pre", HTML_NLALL | HTML_NOINDENT}, + {"var", 0}, + {"cite", 0}, + {"b", 0}, + {"i", 0}, + {"code", 0}, + {"small", 0}, + {"style", HTML_NLALL | HTML_INDENT}, + {"math", HTML_NLALL | HTML_INDENT}, + {"mrow", 0}, + {"mi", 0}, + {"mn", 0}, + {"mo", 0}, + {"msup", 0}, + {"msub", 0}, + {"msubsup", 0}, + {"mfrac", 0}, + {"msqrt", 0}, + {"mfenced", 0}, + {"mtable", 0}, + {"mtr", 0}, + {"mtd", 0}, + {"munderover", 0}, + {"munder", 0}, + {"mover", 0}, +}; + +/* Avoid duplicate HTML id= attributes. */ +static struct ohash id_unique; + +static void print_byte(struct html *, char); +static void print_endword(struct html *); +static void print_indent(struct html *); +static void print_word(struct html *, const char *); + +static void print_ctag(struct html *, struct tag *); +static int print_escape(struct html *, char); +static int print_encode(struct html *, const char *, const char *, int); +static void print_href(struct html *, const char *, const char *, int); +static void print_metaf(struct html *, enum mandoc_esc); + + +void * +html_alloc(const struct manoutput *outopts) +{ + struct html *h; + + h = mandoc_calloc(1, sizeof(struct html)); + + h->tag = NULL; + h->style = outopts->style; + h->base_man = outopts->man; + h->base_includes = outopts->includes; + if (outopts->fragment) + h->oflags |= HTML_FRAGMENT; + + mandoc_ohash_init(&id_unique, 4, 0); + + return h; +} + +void +html_free(void *p) +{ + struct tag *tag; + struct html *h; + char *cp; + unsigned int slot; + + h = (struct html *)p; + while ((tag = h->tag) != NULL) { + h->tag = tag->next; + free(tag); + } + free(h); + + cp = ohash_first(&id_unique, &slot); + while (cp != NULL) { + free(cp); + cp = ohash_next(&id_unique, &slot); + } + ohash_delete(&id_unique); +} + +void +print_gen_head(struct html *h) +{ + struct tag *t; + + print_otag(h, TAG_META, "?", "charset", "utf-8"); + if (h->style != NULL) { + print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet", + h->style, "type", "text/css", "media", "all"); + return; + } + + /* + * Print a minimal embedded style sheet. + */ + + t = print_otag(h, TAG_STYLE, ""); + print_text(h, "table.head, table.foot { width: 100%; }"); + print_endline(h); + print_text(h, "td.head-rtitle, td.foot-os { text-align: right; }"); + print_endline(h); + print_text(h, "td.head-vol { text-align: center; }"); + print_endline(h); + print_text(h, "div.Pp { margin: 1ex 0ex; }"); + print_endline(h); + print_text(h, "div.Nd, div.Bf, div.Op { display: inline; }"); + print_endline(h); + print_text(h, "span.Pa, span.Ad { font-style: italic; }"); + print_endline(h); + print_text(h, "span.Ms { font-weight: bold; }"); + print_endline(h); + print_text(h, "dl.Bl-diag "); + print_byte(h, '>'); + print_text(h, " dt { font-weight: bold; }"); + print_endline(h); + print_text(h, "code.Nm, code.Fl, code.Cm, code.Ic, " + "code.In, code.Fd, code.Fn,"); + print_endline(h); + print_text(h, "code.Cd { font-weight: bold; " + "font-family: inherit; }"); + print_tagq(h, t); +} + +static void +print_metaf(struct html *h, enum mandoc_esc deco) +{ + enum htmlfont font; + + switch (deco) { + case ESCAPE_FONTPREV: + font = h->metal; + break; + case ESCAPE_FONTITALIC: + font = HTMLFONT_ITALIC; + break; + case ESCAPE_FONTBOLD: + font = HTMLFONT_BOLD; + break; + case ESCAPE_FONTBI: + font = HTMLFONT_BI; + break; + case ESCAPE_FONT: + case ESCAPE_FONTROMAN: + font = HTMLFONT_NONE; + break; + default: + abort(); + } + + if (h->metaf) { + print_tagq(h, h->metaf); + h->metaf = NULL; + } + + h->metal = h->metac; + h->metac = font; + + switch (font) { + case HTMLFONT_ITALIC: + h->metaf = print_otag(h, TAG_I, ""); + break; + case HTMLFONT_BOLD: + h->metaf = print_otag(h, TAG_B, ""); + break; + case HTMLFONT_BI: + h->metaf = print_otag(h, TAG_B, ""); + print_otag(h, TAG_I, ""); + break; + default: + break; + } +} + +char * +html_make_id(const struct roff_node *n, int unique) +{ + const struct roff_node *nch; + char *buf, *bufs, *cp; + unsigned int slot; + int suffix; + + for (nch = n->child; nch != NULL; nch = nch->next) + if (nch->type != ROFFT_TEXT) + return NULL; + + buf = NULL; + deroff(&buf, n); + if (buf == NULL) + return NULL; + + /* + * In ID attributes, only use ASCII characters that are + * permitted in URL-fragment strings according to the + * explicit list at: + * https://url.spec.whatwg.org/#url-fragment-string + */ + + for (cp = buf; *cp != '\0'; cp++) + if (isalnum((unsigned char)*cp) == 0 && + strchr("!$&'()*+,-./:;=?@_~", *cp) == NULL) + *cp = '_'; + + if (unique == 0) + return buf; + + /* Avoid duplicate HTML id= attributes. */ + + bufs = NULL; + suffix = 1; + slot = ohash_qlookup(&id_unique, buf); + cp = ohash_find(&id_unique, slot); + if (cp != NULL) { + while (cp != NULL) { + free(bufs); + if (++suffix > 127) { + free(buf); + return NULL; + } + mandoc_asprintf(&bufs, "%s_%d", buf, suffix); + slot = ohash_qlookup(&id_unique, bufs); + cp = ohash_find(&id_unique, slot); + } + free(buf); + buf = bufs; + } + ohash_insert(&id_unique, slot, buf); + return buf; +} + +static int +print_escape(struct html *h, char c) +{ + + switch (c) { + case '<': + print_word(h, "<"); + break; + case '>': + print_word(h, ">"); + break; + case '&': + print_word(h, "&"); + break; + case '"': + print_word(h, """); + break; + case ASCII_NBRSP: + print_word(h, " "); + break; + case ASCII_HYPH: + print_byte(h, '-'); + break; + case ASCII_BREAK: + break; + default: + return 0; + } + return 1; +} + +static int +print_encode(struct html *h, const char *p, const char *pend, int norecurse) +{ + char numbuf[16]; + struct tag *t; + const char *seq; + size_t sz; + int c, len, breakline, nospace; + enum mandoc_esc esc; + static const char rejs[10] = { ' ', '\\', '<', '>', '&', '"', + ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' }; + + if (pend == NULL) + pend = strchr(p, '\0'); + + breakline = 0; + nospace = 0; + + while (p < pend) { + if (HTML_SKIPCHAR & h->flags && '\\' != *p) { + h->flags &= ~HTML_SKIPCHAR; + p++; + continue; + } + + for (sz = strcspn(p, rejs); sz-- && p < pend; p++) + print_byte(h, *p); + + if (breakline && + (p >= pend || *p == ' ' || *p == ASCII_NBRSP)) { + t = print_otag(h, TAG_DIV, ""); + print_text(h, "\\~"); + print_tagq(h, t); + breakline = 0; + while (p < pend && (*p == ' ' || *p == ASCII_NBRSP)) + p++; + continue; + } + + if (p >= pend) + break; + + if (*p == ' ') { + print_endword(h); + p++; + continue; + } + + if (print_escape(h, *p++)) + continue; + + esc = mandoc_escape(&p, &seq, &len); + if (ESCAPE_ERROR == esc) + break; + + switch (esc) { + case ESCAPE_FONT: + case ESCAPE_FONTPREV: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBI: + case ESCAPE_FONTROMAN: + if (0 == norecurse) + print_metaf(h, esc); + continue; + case ESCAPE_SKIPCHAR: + h->flags |= HTML_SKIPCHAR; + continue; + default: + break; + } + + if (h->flags & HTML_SKIPCHAR) { + h->flags &= ~HTML_SKIPCHAR; + continue; + } + + switch (esc) { + case ESCAPE_UNICODE: + /* Skip past "u" header. */ + c = mchars_num2uc(seq + 1, len - 1); + break; + case ESCAPE_NUMBERED: + c = mchars_num2char(seq, len); + if (c < 0) + continue; + break; + case ESCAPE_SPECIAL: + c = mchars_spec2cp(seq, len); + if (c <= 0) + continue; + break; + case ESCAPE_BREAK: + breakline = 1; + continue; + case ESCAPE_NOSPACE: + if ('\0' == *p) + nospace = 1; + continue; + case ESCAPE_OVERSTRIKE: + if (len == 0) + continue; + c = seq[len - 1]; + break; + default: + continue; + } + if ((c < 0x20 && c != 0x09) || + (c > 0x7E && c < 0xA0)) + c = 0xFFFD; + if (c > 0x7E) { + (void)snprintf(numbuf, sizeof(numbuf), "&#x%.4X;", c); + print_word(h, numbuf); + } else if (print_escape(h, c) == 0) + print_byte(h, c); + } + + return nospace; +} + +static void +print_href(struct html *h, const char *name, const char *sec, int man) +{ + const char *p, *pp; + + pp = man ? h->base_man : h->base_includes; + while ((p = strchr(pp, '%')) != NULL) { + print_encode(h, pp, p, 1); + if (man && p[1] == 'S') { + if (sec == NULL) + print_byte(h, '1'); + else + print_encode(h, sec, NULL, 1); + } else if ((man && p[1] == 'N') || + (man == 0 && p[1] == 'I')) + print_encode(h, name, NULL, 1); + else + print_encode(h, p, p + 2, 1); + pp = p + 2; + } + if (*pp != '\0') + print_encode(h, pp, NULL, 1); +} + +struct tag * +print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) +{ + va_list ap; + struct tag *t; + const char *attr; + char *arg1, *arg2; + int tflags; + + tflags = htmltags[tag].flags; + + /* Push this tag onto the stack of open scopes. */ + + if ((tflags & HTML_NOSTACK) == 0) { + t = mandoc_malloc(sizeof(struct tag)); + t->tag = tag; + t->next = h->tag; + h->tag = t; + } else + t = NULL; + + if (tflags & HTML_NLBEFORE) + print_endline(h); + if (h->col == 0) + print_indent(h); + else if ((h->flags & HTML_NOSPACE) == 0) { + if (h->flags & HTML_KEEP) + print_word(h, " "); + else { + if (h->flags & HTML_PREKEEP) + h->flags |= HTML_KEEP; + print_endword(h); + } + } + + if ( ! (h->flags & HTML_NONOSPACE)) + h->flags &= ~HTML_NOSPACE; + else + h->flags |= HTML_NOSPACE; + + /* Print out the tag name and attributes. */ + + print_byte(h, '<'); + print_word(h, htmltags[tag].name); + + va_start(ap, fmt); + + while (*fmt != '\0') { + + /* Parse attributes and arguments. */ + + arg1 = va_arg(ap, char *); + arg2 = NULL; + switch (*fmt++) { + case 'c': + attr = "class"; + break; + case 'h': + attr = "href"; + break; + case 'i': + attr = "id"; + break; + case 's': + attr = "style"; + arg2 = va_arg(ap, char *); + break; + case '?': + attr = arg1; + arg1 = va_arg(ap, char *); + break; + default: + abort(); + } + if (*fmt == 'M') + arg2 = va_arg(ap, char *); + if (arg1 == NULL) + continue; + + /* Print the attributes. */ + + print_byte(h, ' '); + print_word(h, attr); + print_byte(h, '='); + print_byte(h, '"'); + switch (*fmt) { + case 'I': + print_href(h, arg1, NULL, 0); + fmt++; + break; + case 'M': + print_href(h, arg1, arg2, 1); + fmt++; + break; + case 'R': + print_byte(h, '#'); + print_encode(h, arg1, NULL, 1); + fmt++; + break; + case 'T': + print_encode(h, arg1, NULL, 1); + print_word(h, "\" title=\""); + print_encode(h, arg1, NULL, 1); + fmt++; + break; + default: + if (arg2 == NULL) + print_encode(h, arg1, NULL, 1); + else { + print_word(h, arg1); + print_byte(h, ':'); + print_byte(h, ' '); + print_word(h, arg2); + print_byte(h, ';'); + } + break; + } + print_byte(h, '"'); + } + va_end(ap); + + /* Accommodate for "well-formed" singleton escaping. */ + + if (HTML_AUTOCLOSE & htmltags[tag].flags) + print_byte(h, '/'); + + print_byte(h, '>'); + + if (tflags & HTML_NLBEGIN) + print_endline(h); + else + h->flags |= HTML_NOSPACE; + + if (tflags & HTML_INDENT) + h->indent++; + if (tflags & HTML_NOINDENT) + h->noindent++; + + return t; +} + +static void +print_ctag(struct html *h, struct tag *tag) +{ + int tflags; + + /* + * Remember to close out and nullify the current + * meta-font and table, if applicable. + */ + if (tag == h->metaf) + h->metaf = NULL; + if (tag == h->tblt) + h->tblt = NULL; + + tflags = htmltags[tag->tag].flags; + + if (tflags & HTML_INDENT) + h->indent--; + if (tflags & HTML_NOINDENT) + h->noindent--; + if (tflags & HTML_NLEND) + print_endline(h); + print_indent(h); + print_byte(h, '<'); + print_byte(h, '/'); + print_word(h, htmltags[tag->tag].name); + print_byte(h, '>'); + if (tflags & HTML_NLAFTER) + print_endline(h); + + h->tag = tag->next; + free(tag); +} + +void +print_gen_decls(struct html *h) +{ + print_word(h, ""); + print_endline(h); +} + +void +print_gen_comment(struct html *h, struct roff_node *n) +{ + int wantblank; + + print_word(h, "") == NULL && + (wantblank || *n->string != '\0')) { + print_endline(h); + print_indent(h); + print_word(h, n->string); + wantblank = *n->string != '\0'; + } + n = n->next; + } + if (wantblank) + print_endline(h); + print_word(h, " -->"); + print_endline(h); + h->indent = 0; +} + +void +print_text(struct html *h, const char *word) +{ + if (h->col && (h->flags & HTML_NOSPACE) == 0) { + if ( ! (HTML_KEEP & h->flags)) { + if (HTML_PREKEEP & h->flags) + h->flags |= HTML_KEEP; + print_endword(h); + } else + print_word(h, " "); + } + + assert(NULL == h->metaf); + switch (h->metac) { + case HTMLFONT_ITALIC: + h->metaf = print_otag(h, TAG_I, ""); + break; + case HTMLFONT_BOLD: + h->metaf = print_otag(h, TAG_B, ""); + break; + case HTMLFONT_BI: + h->metaf = print_otag(h, TAG_B, ""); + print_otag(h, TAG_I, ""); + break; + default: + print_indent(h); + break; + } + + assert(word); + if ( ! print_encode(h, word, NULL, 0)) { + if ( ! (h->flags & HTML_NONOSPACE)) + h->flags &= ~HTML_NOSPACE; + h->flags &= ~HTML_NONEWLINE; + } else + h->flags |= HTML_NOSPACE | HTML_NONEWLINE; + + if (h->metaf) { + print_tagq(h, h->metaf); + h->metaf = NULL; + } + + h->flags &= ~HTML_IGNDELIM; +} + +void +print_tagq(struct html *h, const struct tag *until) +{ + struct tag *tag; + + while ((tag = h->tag) != NULL) { + print_ctag(h, tag); + if (until && tag == until) + return; + } +} + +void +print_stagq(struct html *h, const struct tag *suntil) +{ + struct tag *tag; + + while ((tag = h->tag) != NULL) { + if (suntil && tag == suntil) + return; + print_ctag(h, tag); + } +} + +void +print_paragraph(struct html *h) +{ + struct tag *t; + + t = print_otag(h, TAG_DIV, "c", "Pp"); + print_tagq(h, t); +} + + +/*********************************************************************** + * Low level output functions. + * They implement line breaking using a short static buffer. + ***********************************************************************/ + +/* + * Buffer one HTML output byte. + * If the buffer is full, flush and deactivate it and start a new line. + * If the buffer is inactive, print directly. + */ +static void +print_byte(struct html *h, char c) +{ + if ((h->flags & HTML_BUFFER) == 0) { + putchar(c); + h->col++; + return; + } + + if (h->col + h->bufcol < sizeof(h->buf)) { + h->buf[h->bufcol++] = c; + return; + } + + putchar('\n'); + h->col = 0; + print_indent(h); + putchar(' '); + putchar(' '); + fwrite(h->buf, h->bufcol, 1, stdout); + putchar(c); + h->col = (h->indent + 1) * 2 + h->bufcol + 1; + h->bufcol = 0; + h->flags &= ~HTML_BUFFER; +} + +/* + * If something was printed on the current output line, end it. + * Not to be called right after print_indent(). + */ +void +print_endline(struct html *h) +{ + if (h->col == 0) + return; + + if (h->bufcol) { + putchar(' '); + fwrite(h->buf, h->bufcol, 1, stdout); + h->bufcol = 0; + } + putchar('\n'); + h->col = 0; + h->flags |= HTML_NOSPACE; + h->flags &= ~HTML_BUFFER; +} + +/* + * Flush the HTML output buffer. + * If it is inactive, activate it. + */ +static void +print_endword(struct html *h) +{ + if (h->noindent) { + print_byte(h, ' '); + return; + } + + if ((h->flags & HTML_BUFFER) == 0) { + h->col++; + h->flags |= HTML_BUFFER; + } else if (h->bufcol) { + putchar(' '); + fwrite(h->buf, h->bufcol, 1, stdout); + h->col += h->bufcol + 1; + } + h->bufcol = 0; +} + +/* + * If at the beginning of a new output line, + * perform indentation and mark the line as containing output. + * Make sure to really produce some output right afterwards, + * but do not use print_otag() for producing it. + */ +static void +print_indent(struct html *h) +{ + size_t i; + + if (h->col) + return; + + if (h->noindent == 0) { + h->col = h->indent * 2; + for (i = 0; i < h->col; i++) + putchar(' '); + } + h->flags &= ~HTML_NOSPACE; +} + +/* + * Print or buffer some characters + * depending on the current HTML output buffer state. + */ +static void +print_word(struct html *h, const char *cp) +{ + while (*cp != '\0') + print_byte(h, *cp++); +} Property changes on: head/contrib/mandoc/html.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mandoc/html.h =================================================================== --- head/contrib/mandoc/html.h (nonexistent) +++ head/contrib/mandoc/html.h (revision 338826) @@ -0,0 +1,134 @@ +/* $Id: html.h,v 1.92 2018/06/25 16:54:59 schwarze Exp $ */ +/* + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons + * Copyright (c) 2017, 2018 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 htmltag { + TAG_HTML, + TAG_HEAD, + TAG_BODY, + TAG_META, + TAG_TITLE, + TAG_DIV, + TAG_IDIV, + TAG_H1, + TAG_H2, + TAG_SPAN, + TAG_LINK, + TAG_BR, + TAG_A, + TAG_TABLE, + 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_box;
    +
    +void		  roff_html_pre(struct html *, const struct roff_node *);
    +
    +void		  print_gen_comment(struct html *, struct roff_node *);
    +void		  print_gen_decls(struct html *);
    +void		  print_gen_head(struct html *);
    +struct tag	 *print_otag(struct html *, enum htmltag, const char *, ...);
    +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_box *);
    +void		  print_paragraph(struct html *);
    +void		  print_endline(struct html *);
    +
    +char		 *html_make_id(const struct roff_node *, int);
    
    Property changes on: head/contrib/mandoc/html.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/lib.in
    ===================================================================
    --- head/contrib/mandoc/lib.in	(nonexistent)
    +++ head/contrib/mandoc/lib.in	(revision 338826)
    @@ -0,0 +1,136 @@
    +/*	$Id: lib.in,v 1.20 2017/08/20 02:30:27 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009 Kristaps Dzonsons 
    + * Copyright (c) 2009, 2012 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.
    + */
    +
    +/*
    + * These are all possible .Lb strings.  When a new library is added, add
    + * its short-string to the left-hand side and formatted string to the
    + * right-hand side.
    + *
    + * Be sure to escape strings.
    + */
    +
    +LINE("lib80211",	"802.11 Wireless Network Management Library (lib80211, \\-l80211)")
    +LINE("libalias",	"Packet Aliasing Library (libalias, \\-lalias)")
    +LINE("libarchive",	"Streaming Archive Library (libarchive, \\-larchive)")
    +LINE("libarm",		"ARM Architecture Library (libarm, \\-larm)")
    +LINE("libarm32",	"ARM32 Architecture Library (libarm32, \\-larm32)")
    +LINE("libbe",		"Boot Environment Library (libbe, \\-lbe)")
    +LINE("libbluetooth",	"Bluetooth Library (libbluetooth, \\-lbluetooth)")
    +LINE("libbsdxml",	"eXpat XML parser library (libbsdxml, \\-lbsdxml)")
    +LINE("libbsm",		"Basic Security Module Library (libbsm, \\-lbsm)")
    +LINE("libc",		"Standard C\\~Library (libc, \\-lc)")
    +LINE("libc_r",		"Reentrant C\\~Library (libc_r, \\-lc_r)")
    +LINE("libcalendar",	"Calendar Arithmetic Library (libcalendar, \\-lcalendar)")
    +LINE("libcam",		"Common Access Method User Library (libcam, \\-lcam)")
    +LINE("libcasper",	"Casper Library (libcasper, \\-lcasper)")
    +LINE("libcdk",		"Curses Development Kit Library (libcdk, \\-lcdk)")
    +LINE("libcipher",	"FreeSec Crypt Library (libcipher, \\-lcipher)")
    +LINE("libcompat",	"Compatibility Library (libcompat, \\-lcompat)")
    +LINE("libcrypt",	"Crypt Library (libcrypt, \\-lcrypt)")
    +LINE("libcurses",	"Curses Library (libcurses, \\-lcurses)")
    +LINE("libcuse", 	"Userland Character Device Library (libcuse, \\-lcuse)")
    +LINE("libdevattr",	"Device attribute and event library (libdevattr, \\-ldevattr)")
    +LINE("libdevctl",	"Device Control Library (libdevctl, \\-ldevctl)")
    +LINE("libdevinfo",	"Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)")
    +LINE("libdevstat",	"Device Statistics Library (libdevstat, \\-ldevstat)")
    +LINE("libdisk",		"Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)")
    +LINE("libdl",		"Dynamic Linker Services Filter (libdl, \\-ldl)")
    +LINE("libdm",		"Device Mapper Library (libdm, \\-ldm)")
    +LINE("libdwarf",	"DWARF Access Library (libdwarf, \\-ldwarf)")
    +LINE("libedit",		"Command Line Editor Library (libedit, \\-ledit)")
    +LINE("libefi",		"EFI Runtime Services Library (libefi, \\-lefi)")
    +LINE("libelf",		"ELF Access Library (libelf, \\-lelf)")
    +LINE("libevent",	"Event Notification Library (libevent, \\-levent)")
    +LINE("libexecinfo",	"Backtrace Information Library (libexecinfo, \\-lexecinfo)")
    +LINE("libfetch",	"File Transfer Library (libfetch, \\-lfetch)")
    +LINE("libfsid",		"Filesystem Identification Library (libfsid, \\-lfsid)")
    +LINE("libftpio",	"FTP Connection Management Library (libftpio, \\-lftpio)")
    +LINE("libform",		"Curses Form Library (libform, \\-lform)")
    +LINE("libgeom",		"Userland API Library for Kernel GEOM subsystem (libgeom, \\-lgeom)")
    +LINE("libgpio",		"General-Purpose Input Output (GPIO) library (libgpio, \\-lgpio)")
    +LINE("libhammer",	"HAMMER Filesystem Userland Library (libhammer, \\-lhammer)")
    +LINE("libi386",		"i386 Architecture Library (libi386, \\-li386)")
    +LINE("libintl",		"Internationalized Message Handling Library (libintl, \\-lintl)")
    +LINE("libipsec",	"IPsec Policy Control Library (libipsec, \\-lipsec)")
    +LINE("libiscsi",	"iSCSI protocol library (libiscsi, \\-liscsi)")
    +LINE("libisns",		"Internet Storage Name Service Library (libisns, \\-lisns)")
    +LINE("libjail",		"Jail Library (libjail, \\-ljail)")
    +LINE("libkcore",	"Kernel Memory Core Access Library (libkcore, \\-lkcore)")
    +LINE("libkiconv",	"Kernel-side iconv Library (libkiconv, \\-lkiconv)")
    +LINE("libkse",		"N:M Threading Library (libkse, \\-lkse)")
    +LINE("libkvm",		"Kernel Data Access Library (libkvm, \\-lkvm)")
    +LINE("libm",		"Math Library (libm, \\-lm)")
    +LINE("libm68k",		"m68k Architecture Library (libm68k, \\-lm68k)")
    +LINE("libmagic",	"Magic Number Recognition Library (libmagic, \\-lmagic)")
    +LINE("libmandoc",	"Mandoc Macro Compiler Library (libmandoc, \\-lmandoc)")
    +LINE("libmd",		"Message Digest (MD4, MD5, etc.) Support Library (libmd, \\-lmd)")
    +LINE("libmemstat",	"Kernel Memory Allocator Statistics Library (libmemstat, \\-lmemstat)")
    +LINE("libmenu",		"Curses Menu Library (libmenu, \\-lmenu)")
    +LINE("libmj",		"Minimalist JSON library (libmj, \\-lmj)")
    +LINE("libnetgraph",	"Netgraph User Library (libnetgraph, \\-lnetgraph)")
    +LINE("libnetpgp",	"Netpgp Signing, Verification, Encryption and Decryption (libnetpgp, \\-lnetpgp)")
    +LINE("libnetpgpverify",	"Netpgp Verification (libnetpgpverify, \\-lnetpgpverify)")
    +LINE("libnpf",		"NPF Packet Filter Library (libnpf, \\-lnpf)")
    +LINE("libnv",		"Name/value pairs library (libnv, \\-lnv)")
    +LINE("libossaudio",	"OSS Audio Emulation Library (libossaudio, \\-lossaudio)")
    +LINE("libpam",		"Pluggable Authentication Module Library (libpam, \\-lpam)")
    +LINE("libpanel",	"Z-order for curses windows (libpanel, \\-lpanel)")
    +LINE("libpcap",		"Packet capture Library (libpcap, \\-lpcap)")
    +LINE("libpci",		"PCI Bus Access Library (libpci, \\-lpci)")
    +LINE("libpmc",		"Performance Counters Library (libpmc, \\-lpmc)")
    +LINE("libppath",	"Property-List Paths Library (libppath, \\-lppath)")
    +LINE("libposix",	"POSIX Compatibility Library (libposix, \\-lposix)")
    +LINE("libposix1e",	"POSIX.1e Security API Library (libposix1e, \\-lposix1e)")
    +LINE("libppath",	"Property-List Paths Library (libppath, \\-lppath)")
    +LINE("libproc",		"Processor Monitoring and Analysis Library (libproc, \\-lproc)")
    +LINE("libprocstat",	"Process and Files Information Retrieval (libprocstat, \\-lprocstat)")
    +LINE("libprop",		"Property Container Object Library (libprop, \\-lprop)")
    +LINE("libpthread",	"POSIX Threads Library (libpthread, \\-lpthread)")
    +LINE("libpthread_dbg",	"POSIX Debug Threads Library (libpthread_dbg, \\-lpthread_dbg)")
    +LINE("libpuffs",	"puffs Convenience Library (libpuffs, \\-lpuffs)")
    +LINE("libquota",	"Disk Quota Access and Control Library (libquota, \\-lquota)")
    +LINE("libradius",	"RADIUS Client Library (libradius, \\-lradius)")
    +LINE("librefuse",	"File System in Userspace Convenience Library (librefuse, \\-lrefuse)")
    +LINE("libresolv",	"DNS Resolver Library (libresolv, \\-lresolv)")
    +LINE("librpcsec_gss",	"RPC GSS-API Authentication Library (librpcsec_gss, \\-lrpcsec_gss)")
    +LINE("librpcsvc",	"RPC Service Library (librpcsvc, \\-lrpcsvc)")
    +LINE("librt",		"POSIX Real\\-time Library (librt, \\-lrt)")
    +LINE("librtld_db",	"Debugging interface to the runtime linker Library (librtld_db, \\-lrtld_db)")
    +LINE("librumpclient",	"Clientside Stubs for rump Kernel Remote Protocols (librumpclient, \\-lrumpclient)")
    +LINE("libsaslc",	"Simple Authentication and Security Layer client library (libsaslc, \\-lsaslc)")
    +LINE("libsbuf",		"Safe String Composition Library (libsbuf, \\-lsbuf)")
    +LINE("libsdp",		"Bluetooth Service Discovery Protocol User Library (libsdp, \\-lsdp)")
    +LINE("libssp",		"Buffer Overflow Protection Library (libssp, \\-lssp)")
    +LINE("libstdthreads",	"C11 Threads Library (libstdthreads, \\-lstdthreads)")
    +LINE("libstdthreads",	"C11 Threads Library (libstdthreads, \\-lstdthreads)")
    +LINE("libSystem",	"System Library (libSystem, \\-lSystem)")
    +LINE("libsysdecode",	"System Argument Decoding Library (libsysdecode, \\-lsysdecode)")
    +LINE("libtacplus",	"TACACS+ Client Library (libtacplus, \\-ltacplus)")
    +LINE("libtcplay",	"TrueCrypt-compatible API library (libtcplay, \\-ltcplay)")
    +LINE("libtermcap",	"Termcap Access Library (libtermcap, \\-ltermcap)")
    +LINE("libterminfo",	"Terminal Information Library (libterminfo, \\-lterminfo)")
    +LINE("libthr",		"1:1 Threading Library (libthr, \\-lthr)")
    +LINE("libufs",		"UFS File System Access Library (libufs, \\-lufs)")
    +LINE("libugidfw",	"File System Firewall Interface Library (libugidfw, \\-lugidfw)")
    +LINE("libulog",		"User Login Record Library (libulog, \\-lulog)")
    +LINE("libusbhid",	"USB Human Interface Devices Library (libusbhid, \\-lusbhid)")
    +LINE("libutil",		"System Utilities Library (libutil, \\-lutil)")
    +LINE("libvgl",		"Video Graphics Library (libvgl, \\-lvgl)")
    +LINE("libx86_64",	"x86_64 Architecture Library (libx86_64, \\-lx86_64)")
    +LINE("libxo",		"Text, XML, JSON, and HTML Output Emission Library (libxo, \\-lxo)")
    +LINE("libz",		"Compression Library (libz, \\-lz)")
    
    Property changes on: head/contrib/mandoc/lib.in
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/libmandoc.h
    ===================================================================
    --- head/contrib/mandoc/libmandoc.h	(nonexistent)
    +++ head/contrib/mandoc/libmandoc.h	(revision 338826)
    @@ -0,0 +1,73 @@
    +/*	$Id: libmandoc.h,v 1.71 2018/04/09 22:27:04 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011, 2012 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.
    + */
    +
    +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 */
    +};
    +
    +struct	buf {
    +	char	*buf;
    +	size_t	 sz;
    +};
    +
    +
    +struct	mparse;
    +struct	roff;
    +struct	roff_man;
    +
    +void		 mandoc_msg(enum mandocerr, struct mparse *,
    +			int, int, const char *);
    +void		 mandoc_vmsg(enum mandocerr, struct mparse *,
    +			int, int, const char *, ...)
    +			__attribute__((__format__ (__printf__, 5, 6)));
    +char		*mandoc_getarg(struct mparse *, char **, int, int *);
    +char		*mandoc_normdate(struct roff_man *, char *, int, int);
    +int		 mandoc_eos(const char *, size_t);
    +int		 mandoc_strntoi(const char *, size_t, int);
    +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(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 *);
    
    Property changes on: head/contrib/mandoc/libmandoc.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/main.c
    ===================================================================
    --- head/contrib/mandoc/main.c	(nonexistent)
    +++ head/contrib/mandoc/main.c	(revision 338826)
    @@ -0,0 +1,1253 @@
    +/*	$Id: main.c,v 1.306 2018/05/14 14:10:23 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008-2012 Kristaps Dzonsons 
    + * Copyright (c) 2010-2012, 2014-2018 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 
    +#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 
    +
    +#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;
    +	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 */
    +};
    +
    +
    +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	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 winsize	 ws;
    +	struct tag_files *tag_files;
    +	struct manpage	*res, *resp;
    +	const char	*progname, *sec, *thisarg;
    +	char		*conf_file, *defpaths, *auxpaths;
    +	char		*oarg;
    +	unsigned char	*uc;
    +	size_t		 i, sz;
    +	int		 prio, best_prio;
    +	enum outmode	 outmode;
    +	int		 fd, startdir;
    +	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.mmin = MANDOCERR_MAX;
    +	curp.outopts = &conf.output;
    +	options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
    +	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 (curp.os_s != NULL) {
    +				warnx("-I %s: Duplicate argument", optarg);
    +				return (int)MANDOCLEVEL_BADARG;
    +			}
    +			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 (use_pager &&
    +	    (conf.output.width == 0 || conf.output.indent == 0) &&
    +	    ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 &&
    +	    ws.ws_col > 1) {
    +		if (conf.output.width == 0 && ws.ws_col < 79)
    +			conf.output.width = ws.ws_col - 1;
    +		if (conf.output.indent == 0 && ws.ws_col < 66)
    +			conf.output.indent = 3;
    +	}
    +
    +#if HAVE_PLEDGE
    +	if (!use_pager)
    +		if (pledge("stdio rpath", NULL) == -1)
    +			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 && search.argmode == ARG_NAME)
    +			fs_search(&search, &conf.manpath,
    +			    argc, argv, &res, &sz);
    +
    +		if (search.argmode == ARG_NAME) {
    +			for (c = 0; c < argc; c++) {
    +				if (strchr(argv[c], '/') == NULL)
    +					continue;
    +				if (access(argv[c], R_OK) == -1) {
    +					warn("%s", argv[c]);
    +					continue;
    +				}
    +				res = mandoc_reallocarray(res,
    +				    sz + 1, sizeof(*res));
    +				res[sz].file = mandoc_strdup(argv[c]);
    +				res[sz].names = NULL;
    +				res[sz].output = NULL;
    +				res[sz].ipath = SIZE_MAX;
    +				res[sz].bits = 0;
    +				res[sz].sec = 10;
    +				res[sz].form = FORM_SRC;
    +				sz++;
    +			}
    +		}
    +
    +		if (sz == 0) {
    +			if (search.argmode != ARG_NAME)
    +				warnx("nothing appropriate");
    +			rc = MANDOCLEVEL_BADARG;
    +			goto out;
    +		}
    +
    +		/*
    +		 * 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.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, "");
    +	}
    +
    +	/*
    +	 * Remember the original working directory, if possible.
    +	 * This will be needed if some names on the command line
    +	 * are page names and some are relative file names.
    +	 * Do not error out if the current directory is not
    +	 * readable: Maybe it won't be needed after all.
    +	 */
    +	startdir = open(".", O_RDONLY | O_DIRECTORY);
    +
    +	while (argc > 0) {
    +
    +		/*
    +		 * Changing directories is not needed in ARG_FILE mode.
    +		 * Do it on a best-effort basis.  Even in case of
    +		 * failure, some functionality may still work.
    +		 */
    +		if (resp != NULL) {
    +			if (resp->ipath != SIZE_MAX)
    +				(void)chdir(conf.manpath.paths[resp->ipath]);
    +			else if (startdir != -1)
    +				(void)fchdir(startdir);
    +		}
    +
    +		fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
    +		if (fd != -1) {
    +			if (use_pager) {
    +				tag_files = tag_init();
    +				use_pager = 0;
    +			}
    +
    +			if (resp == NULL)
    +				parse(&curp, fd, *argv);
    +			else if (resp->form == FORM_SRC)
    +				parse(&curp, fd, resp->file);
    +			else
    +				passthrough(resp->file, fd,
    +				    conf.output.synopsisonly);
    +
    +			if (ferror(stdout)) {
    +				if (tag_files != NULL) {
    +					warn("%s", tag_files->ofn);
    +					tag_unlink();
    +					tag_files = NULL;
    +				} else
    +					warn("stdout");
    +				rc = MANDOCLEVEL_SYSERR;
    +				break;
    +			}
    +
    +			if (argc > 1 && curp.outtype <= OUTT_UTF8) {
    +				if (curp.outdata == NULL)
    +					outdata_alloc(&curp);
    +				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 (startdir != -1) {
    +		(void)fchdir(startdir);
    +		close(startdir);
    +	}
    +
    +	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(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)
    +		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 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);
    +
    +	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 1;
    +			} else for (isec = 0; isec < nsec; isec++)
    +				if (fs_lookup(paths, ipath, sections[isec],
    +				    cfg->arch, *argv, res, ressz) &&
    +				    cfg->firstmatch)
    +					return 1;
    +		}
    +		if (res != NULL && *ressz == lastsz &&
    +		    strchr(*argv, '/') == NULL)
    +			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->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[11];
    +
    +	toks[0] = "stop";
    +	toks[1] = "all";
    +	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->mmin = MANDOCERR_BASE;
    +			break;
    +		case 3:
    +			curp->mmin = MANDOCERR_STYLE;
    +			break;
    +		case 4:
    +			curp->mmin = MANDOCERR_WARNING;
    +			break;
    +		case 5:
    +			curp->mmin = MANDOCERR_ERROR;
    +			break;
    +		case 6:
    +			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(mmsg_stream, "%s: %s:", getprogname(),
    +	    file == NULL ? "" : file);
    +
    +	if (line)
    +		fprintf(mmsg_stream, "%d:%d:", line, col + 1);
    +
    +	fprintf(mmsg_stream, " %s", mparse_strlevel(lvl));
    +
    +	if ((mparse_msg = mparse_strerror(t)) != NULL)
    +		fprintf(mmsg_stream, ": %s", mparse_msg);
    +
    +	if (msg)
    +		fprintf(mmsg_stream, ": %s", msg);
    +
    +	fputc('\n', mmsg_stream);
    +}
    +
    +static pid_t
    +spawn_pager(struct tag_files *tag_files)
    +{
    +	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 = "less -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);
    +	assert(tag_files->tfd == -1);
    +
    +	/* 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]);
    +}
    
    Property changes on: head/contrib/mandoc/main.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man.1
    ===================================================================
    --- head/contrib/mandoc/man.1	(nonexistent)
    +++ head/contrib/mandoc/man.1	(revision 338826)
    @@ -0,0 +1,396 @@
    +.\"	$Id: man.1,v 1.33 2018/04/19 23:41:16 schwarze Exp $
    +.\"
    +.\" Copyright (c) 1989, 1990, 1993
    +.\"	The Regents of the University of California.  All rights reserved.
    +.\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre 
    +.\" Copyright (c) 2010, 2011, 2014-2017 Ingo Schwarze 
    +.\"
    +.\" Redistribution and use in source and binary forms, with or without
    +.\" modification, are permitted provided that the following conditions
    +.\" are met:
    +.\" 1. Redistributions of source code must retain the above copyright
    +.\"    notice, this list of conditions and the following disclaimer.
    +.\" 2. Redistributions in binary form must reproduce the above copyright
    +.\"    notice, this list of conditions and the following disclaimer in the
    +.\"    documentation and/or other materials provided with the distribution.
    +.\" 3. Neither the name of the University nor the names of its contributors
    +.\"    may be used to endorse or promote products derived from this software
    +.\"    without specific prior written permission.
    +.\"
    +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    +.\" SUCH DAMAGE.
    +.\"
    +.\"     @(#)man.1	8.2 (Berkeley) 1/2/94
    +.\"
    +.Dd $Mdocdate: April 19 2018 $
    +.Dt MAN 1
    +.Os
    +.Sh NAME
    +.Nm man
    +.Nd display manual pages
    +.Sh SYNOPSIS
    +.Nm man
    +.Op Fl acfhklw
    +.Op Fl C Ar file
    +.Op Fl M Ar path
    +.Op Fl m Ar path
    +.Op Fl S Ar subsection
    +.Op Oo Fl s Oc Ar section
    +.Ar name ...
    +.Sh DESCRIPTION
    +The
    +.Nm
    +utility
    +displays the
    +manual pages entitled
    +.Ar name .
    +Pages may be selected according to
    +a specific category
    +.Pq Ar section
    +or
    +machine architecture
    +.Pq Ar subsection .
    +.Pp
    +The options are as follows:
    +.Bl -tag -width Ds
    +.It Fl a
    +Display all matching manual pages.
    +Normally, only the first page found is displayed.
    +.It Fl C Ar file
    +Use the specified
    +.Ar file
    +instead of the default configuration file.
    +This permits users to configure their own manual environment.
    +See
    +.Xr man.conf 5
    +for a description of the contents of this file.
    +.It Fl c
    +Copy the manual page to the standard output instead of using
    +.Xr more 1
    +to paginate it.
    +This is done by default if the standard output is not a terminal device.
    +.Pp
    +When using
    +.Fl c ,
    +most terminal devices are unable to show the markup.
    +To print the output of
    +.Nm
    +to the terminal with markup but without using a pager, pipe it to
    +.Xr ul 1 .
    +To remove the markup, pipe the output to
    +.Xr col 1
    +.Fl b
    +instead.
    +.It Fl f
    +A synonym for
    +.Xr whatis 1 .
    +It searches for
    +.Ar name
    +in manual page names and displays the header lines from all matching pages.
    +The search is case insensitive and matches whole words only.
    +.It Fl h
    +Display only the SYNOPSIS lines of the requested manual pages.
    +Implies
    +.Fl a
    +and
    +.Fl c .
    +.It Fl k
    +A synonym for
    +.Xr apropos 1 .
    +Instead of
    +.Ar name ,
    +an expression can be provided using the syntax described in the
    +.Xr apropos 1
    +manual.
    +By default, it displays the header lines of all matching pages.
    +.It Fl l
    +A synonym for
    +.Xr mandoc 1 .
    +The
    +.Ar name
    +arguments are interpreted as filenames.
    +No search is done and
    +.Ar file ,
    +.Ar path ,
    +.Ar section ,
    +.Ar subsection ,
    +and
    +.Fl w
    +are ignored.
    +This option implies
    +.Fl a .
    +.It Fl M Ar path
    +Override the list of standard directories which
    +.Nm
    +searches for manual pages.
    +The supplied
    +.Ar path
    +must be a colon
    +.Pq Ql \&:
    +separated list of directories.
    +This search path may also be set using the environment variable
    +.Ev MANPATH .
    +.It Fl m Ar path
    +Augment the list of standard directories which
    +.Nm
    +searches for manual pages.
    +The supplied
    +.Ar path
    +must be a colon
    +.Pq Ql \&:
    +separated list of directories.
    +These directories will be searched before the standard directories or
    +the directories specified using the
    +.Fl M
    +option or the
    +.Ev MANPATH
    +environment variable.
    +.It Fl S Ar subsection
    +Only show pages for the specified
    +.Xr machine 1
    +architecture.
    +.Ar subsection
    +is case insensitive.
    +.Pp
    +By default manual pages for all architectures are installed.
    +Therefore this option can be used to view pages for one
    +architecture whilst using another.
    +.Pp
    +This option overrides the
    +.Ev MACHINE
    +environment variable.
    +.It Oo Fl s Oc Ar section
    +Only select manuals from the specified
    +.Ar section .
    +The currently available sections are:
    +.Pp
    +.Bl -tag -width "localXXX" -offset indent -compact
    +.It 1
    +General commands
    +.Pq tools and utilities .
    +.It 2
    +System calls and error numbers.
    +.It 3
    +Library functions.
    +.It 3p
    +.Xr perl 1
    +programmer's reference guide.
    +.It 4
    +Device drivers.
    +.It 5
    +File formats.
    +.It 6
    +Games.
    +.It 7
    +Miscellaneous information.
    +.It 8
    +System maintenance and operation commands.
    +.It 9
    +Kernel internals.
    +.El
    +.Pp
    +If not specified and a match is found in more than one section,
    +the first match is selected from the following list:
    +1, 8, 6, 2, 3, 5, 7, 4, 9, 3p.
    +.It Fl w
    +List the pathnames of all matching manual pages instead of displaying
    +any of them.
    +.El
    +.Pp
    +The options
    +.Fl IKOTW
    +are also supported and are documented in
    +.Xr mandoc 1 .
    +The options
    +.Fl fkl
    +are mutually exclusive and override each other.
    +.Pp
    +Guidelines for writing
    +man pages can be found in
    +.Xr mdoc 7 .
    +.Pp
    +If both a formatted and an unformatted version of the same manual page,
    +for example
    +.Pa cat1/foo.0
    +and
    +.Pa man1/foo.1 ,
    +exist in the same directory, only the unformatted version is used.
    +.Sh ENVIRONMENT
    +.Bl -tag -width MANPATHX
    +.It Ev MACHINE
    +As some manual pages are intended only for specific architectures,
    +.Nm
    +searches any subdirectories,
    +with the same name as the current architecture,
    +in every directory which it searches.
    +Machine specific areas are checked before general areas.
    +The current machine type may be overridden by setting the environment
    +variable
    +.Ev MACHINE
    +to the name of a specific architecture,
    +or with the
    +.Fl S
    +option.
    +.Ev MACHINE
    +is case insensitive.
    +.It Ev MANPAGER
    +Any non-empty value of the environment variable
    +.Ev MANPAGER
    +is used instead of the standard pagination program,
    +.Xr more 1 .
    +If
    +.Xr less 1
    +is used, the interactive
    +.Ic :t
    +command can be used to go to the definitions of various terms, for
    +example command line options, command modifiers, internal commands,
    +environment variables, function names, preprocessor macros,
    +.Xr errno 2
    +values, and some other emphasized words.
    +Some terms may have defining text at more than one place.
    +In that case, the
    +.Xr less 1
    +interactive commands
    +.Ic t
    +and
    +.Ic T
    +can be used to move to the next and to the previous place providing
    +information about the term last searched for with
    +.Ic :t .
    +.It Ev MANPATH
    +The standard search path used by
    +.Nm
    +may be changed by specifying a path in the
    +.Ev MANPATH
    +environment variable.
    +The format of the path is a colon
    +.Pq Ql \&:
    +separated list of directories.
    +Invalid paths are ignored.
    +Overridden by
    +.Fl M ,
    +ignored if
    +.Fl l
    +is specified.
    +.Pp
    +If
    +.Ev MANPATH
    +begins with a colon, it is appended to the default list;
    +if it ends with a colon, it is prepended to the default list;
    +or if it contains two adjacent colons,
    +the standard search path is inserted between the colons.
    +If none of these conditions are met, it overrides the
    +standard search path.
    +.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.
    +.El
    +.Sh FILES
    +.Bl -tag -width /etc/man.conf -compact
    +.It Pa /etc/man.conf
    +default man configuration file
    +.El
    +.Sh EXIT STATUS
    +.Ex -std man
    +See
    +.Xr mandoc 1
    +for details.
    +.Sh EXAMPLES
    +Format a page for pasting extracts into an email message \(em
    +avoid printing any UTF-8 characters, reduce the width to ease
    +quoting in replies, and remove markup:
    +.Pp
    +.Dl $ man -T ascii -O width=65 pledge | col -b
    +.Pp
    +Read a typeset page in a PDF viewer:
    +.Pp
    +.Dl $ MANPAGER=mupdf man -T pdf lpd
    +.Sh SEE ALSO
    +.Xr apropos 1 ,
    +.Xr col 1 ,
    +.Xr mandoc 1 ,
    +.Xr ul 1 ,
    +.Xr whereis 1 ,
    +.Xr man.conf 5 ,
    +.Xr mdoc 7
    +.Sh STANDARDS
    +The
    +.Nm
    +utility is compliant with the
    +.St -p1003.1-2008
    +specification.
    +.Pp
    +The flags
    +.Op Fl aCcfhIKlMmOSsTWw ,
    +as well as the environment variables
    +.Ev MACHINE ,
    +.Ev MANPAGER ,
    +and
    +.Ev MANPATH ,
    +are extensions to that specification.
    +.Sh HISTORY
    +A
    +.Nm
    +command first appeared in
    +.At v3 .
    +.Pp
    +The
    +.Fl w
    +option first appeared in
    +.At v7 ;
    +.Fl f
    +and
    +.Fl k
    +in
    +.Bx 4 ;
    +.Fl M
    +in
    +.Bx 4.3 ;
    +.Fl a
    +in
    +.Bx 4.3 Tahoe ;
    +.Fl c
    +and
    +.Fl m
    +in
    +.Bx 4.3 Reno ;
    +.Fl h
    +in
    +.Bx 4.3 Net/2 ;
    +.Fl C
    +in
    +.Nx 1.0 ;
    +.Fl s
    +and
    +.Fl S
    +in
    +.Ox 2.3 ;
    +and
    +.Fl I ,
    +.Fl K ,
    +.Fl l ,
    +.Fl O ,
    +and
    +.Fl W
    +in
    +.Ox 5.7 .
    +The
    +.Fl T
    +option first appeared in
    +.At III
    +and was also added in
    +.Ox 5.7 .
    
    Property changes on: head/contrib/mandoc/man.1
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man.7
    ===================================================================
    --- head/contrib/mandoc/man.7	(nonexistent)
    +++ head/contrib/mandoc/man.7	(revision 338826)
    @@ -0,0 +1,902 @@
    +.\"	$Id: man.7,v 1.137 2018/04/05 22:12:33 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: April 5 2018 $
    +.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 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 .
    +.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 .
    +.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 \&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 \&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.
    
    Property changes on: head/contrib/mandoc/man.7
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man.cgi.8
    ===================================================================
    --- head/contrib/mandoc/man.cgi.8	(nonexistent)
    +++ head/contrib/mandoc/man.cgi.8	(revision 338826)
    @@ -0,0 +1,426 @@
    +.\"	$Id: man.cgi.8,v 1.23 2018/05/20 21:48:44 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2014, 2015, 2016 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 20 2018 $
    +.Dt MAN.CGI 8
    +.Os
    +.Sh NAME
    +.Nm man.cgi
    +.Nd CGI program to search and display manual pages
    +.Sh DESCRIPTION
    +The
    +.Nm
    +CGI program searches for manual pages on a WWW server
    +and displays them to HTTP clients,
    +providing functionality equivalent to the
    +.Xr man 1
    +and
    +.Xr apropos 1
    +utilities.
    +It can use multiple manual trees in parallel.
    +.Ss HTML search interface
    +At the top of each generated HTML page,
    +.Nm
    +displays a search form containing these elements:
    +.Bl -enum
    +.It
    +An input box for search queries, expecting
    +either a name of a manual page or an
    +.Ar expression
    +using the syntax described in the
    +.Xr apropos 1
    +manual; filling this in is required for each search.
    +.Pp
    +The expression is broken into words at whitespace.
    +Whitespace characters and backslashes can be escaped
    +by prepending a backslash.
    +The effect of prepending a backslash to another character is undefined;
    +in the current implementation, it has no effect.
    +.It
    +A
    +.Xr man 1
    +submit button.
    +The string in the input box is interpreted as the name of a manual page.
    +.It
    +An
    +.Xr apropos 1
    +submit button.
    +The string in the input box is interpreted as a search
    +.Ar expression .
    +.It
    +A dropdown menu to optionally select a manual section.
    +If one is provided, it has the same effect as the
    +.Xr man 1
    +and
    +.Xr apropos 1
    +.Fl s
    +option.
    +Otherwise, pages from all sections are shown.
    +.It
    +A dropdown menu to optionally select an architecture.
    +If one is provided, it has the same effect as the
    +.Xr man 1
    +and
    +.Xr apropos 1
    +.Fl S
    +option.
    +By default, pages for all architectures are shown.
    +.It
    +A dropdown menu to select a manual tree.
    +If the configuration file
    +.Pa /var/www/man/manpath.conf
    +contains only one manpath, the dropdown menu is not shown.
    +By default, the first manpath given in the file is used.
    +.El
    +.Ss Program output
    +The
    +.Nm
    +program generates five kinds of output pages:
    +.Bl -tag -width Ds
    +.It The index page.
    +This is returned when calling
    +.Nm
    +without
    +.Ev PATH_INFO
    +and without a
    +.Ev QUERY_STRING .
    +It serves as a starting point for using the program
    +and shows the search form only.
    +.It A list page.
    +Lists are returned when searches match more than one manual page.
    +The first column shows the names and section numbers of manuals
    +as clickable links.
    +The second column shows the one-line descriptions of the manuals.
    +For
    +.Xr man 1
    +style searches, the content of the first manual page follows the list.
    +.It A manual page.
    +This output format is used when a search matches exactly one
    +manual page, or when a link on a list page or an
    +.Ic \&Xr
    +link on another manual page is followed.
    +.It A no-result page.
    +This is shown when a search request returns no results -
    +either because it violates the query syntax, or because
    +the search does not match any manual pages.
    +.It \&An error page.
    +This cannot happen by merely clicking the
    +.Dq Search
    +button, but only by manually entering an invalid URI.
    +It does not show the search form, but only an error message
    +and a link back to the index page.
    +.El
    +.Ss Setup
    +For each manual tree, create one first-level subdirectory below
    +.Pa /var/www/man .
    +The name of one of these directories is called a
    +.Dq manpath
    +in the context of
    +.Nm .
    +Create a single ASCII text file
    +.Pa /var/www/man/manpath.conf
    +containing the names of these directories, one per line.
    +The directory given first is used as the default manpath.
    +.Pp
    +Inside each of these directories, use the same directory and file
    +structure as found below
    +.Pa /usr/share/man ,
    +that is, second-level subdirectories
    +.Pa /var/www/man/*/man1 , /var/www/man/*/man2
    +etc. containing source
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +manuals with file name extensions matching the section numbers,
    +second-level subdirectories
    +.Pa /var/www/man/*/cat1 , /var/www/man/*/cat2
    +etc. containing preformatted manuals with the file name extension
    +.Sq 0 ,
    +and optional third-level subdirectories for architectures.
    +Use
    +.Xr makewhatis 8
    +to create a
    +.Xr mandoc.db 5
    +database inside each manpath.
    +.Pp
    +Configure your web server to execute CGI programs located in
    +.Pa /cgi-bin .
    +When using
    +.Ox
    +.Xr httpd 8 ,
    +the
    +.Xr slowcgi 8
    +proxy daemon is needed to translate FastCGI requests to plain old CGI.
    +.Pp
    +To compile
    +.Nm ,
    +first copy
    +.Pa cgi.h.example
    +to
    +.Pa cgi.h
    +and edit it according to your needs.
    +It contains the following compile-time definitions:
    +.Bl -tag -width Ds
    +.It Ev COMPAT_OLDURI
    +Only useful for running on www.openbsd.org to deal with old URIs containing
    +.Qq "manpath=OpenBSD "
    +where the blank character has to be translated to a hyphen.
    +When compiling for other sites, this definition can be deleted.
    +.It Dv CSS_DIR
    +An optional file system path to the directory containing the file
    +.Pa mandoc.css ,
    +to be specified relative to the server's document root,
    +and to be specified without a trailing slash.
    +When empty, the CSS file is assumed to be in the document root.
    +Otherwise, a leading slash is needed.
    +This is used in generated HTML code.
    +.It Dv CUSTOMIZE_TITLE
    +An ASCII string to be used for the HTML  element.
    +.It Dv MAN_DIR
    +A file system path to the
    +.Nm
    +data directory relative to the web server
    +.Xr chroot 2
    +directory, to be specified with a leading slash and without a trailing slash.
    +It needs to have at least one component; the root directory cannot be used
    +for this purpose.
    +The files
    +.Pa manpath.conf ,
    +.Pa header.html ,
    +and
    +.Pa footer.html
    +are looked up in this directory.
    +It is also prepended to the manpath when opening
    +.Xr mandoc.db 5
    +and manual page files.
    +.It Dv SCRIPT_NAME
    +The initial component of URIs, to be specified without leading
    +and trailing slashes.
    +It can be empty.
    +.El
    +.Pp
    +After editing
    +.Pa cgi.h ,
    +run
    +.Pp
    +.Dl make man.cgi
    +.Pp
    +and copy the resulting binary to the proper location,
    +for example using the command:
    +.Pp
    +.Dl make installcgi
    +.Pp
    +In addition to that, make sure the default manpath contains the files
    +.Pa man1/apropos.1
    +and
    +.Pa man8/man.cgi.8 ,
    +or the documentation links at the bottom of the index page will not work.
    +.Ss URI interface
    +.Nm
    +uniform resource identifiers are not needed for interactive use,
    +but can be useful for deep linking.
    +They consist of:
    +.Bl -enum
    +.It
    +The
    +.Cm http://
    +or
    +.Cm https://
    +protocol specifier.
    +.It
    +The host name.
    +.It
    +The
    +.Dv SCRIPT_NAME ,
    +preceded by a slash unless empty.
    +.It
    +To show a single page, a slash, the manpath, another slash,
    +and the name of the requested file, for example
    +.Pa /OpenBSD-current/man1/mandoc.1 .
    +This can be abbreviated according to the following syntax:
    +.Sm off
    +.Op / Ar manpath
    +.Op / Cm man Ar sec
    +.Op / Ar arch
    +.Pf / Ar name Op \&. Ar sec
    +.Sm on
    +.It
    +For searches, a query string starting with a question mark
    +and consisting of
    +.Ar key Ns = Ns Ar value
    +pairs, separated by ampersands, for example
    +.Pa ?manpath=OpenBSD-current&query=mandoc .
    +Supported keys are
    +.Cm manpath ,
    +.Cm query ,
    +.Cm sec ,
    +.Cm arch ,
    +corresponding to
    +.Xr apropos 1
    +.Fl M ,
    +.Ar expression ,
    +.Fl s ,
    +.Fl S ,
    +respectively, and
    +.Cm apropos ,
    +which is a boolean parameter to select or deselect the
    +.Xr apropos 1
    +query mode.
    +For backward compatibility with the traditional
    +.Nm ,
    +.Cm sektion
    +is supported as an alias for
    +.Cm sec .
    +.El
    +.Ss Restricted character set
    +For security reasons, in particular to prevent cross site scripting
    +attacks, some strings used by
    +.Nm
    +can only contain the following characters:
    +.Pp
    +.Bl -dash -compact -offset indent
    +.It
    +lower case and upper case ASCII letters
    +.It
    +the ten decimal digits
    +.It
    +the dash
    +.Pq Sq -
    +.It
    +the dot
    +.Pq Sq \&.
    +.It
    +the slash
    +.Pq Sq /
    +.It
    +the underscore
    +.Pq Sq _
    +.El
    +.Pp
    +In particular, this applies to all manpaths and architecture names.
    +.Sh ENVIRONMENT
    +The web server may pass the following CGI variables to
    +.Nm :
    +.Bl -tag -width Ds
    +.It Ev SCRIPT_NAME
    +The initial part of the URI passed from the client to the server,
    +starting after the server's host name and ending before
    +.Ev PATH_INFO .
    +This is ignored by
    +.Nm .
    +When constructing URIs for links and redirections, the
    +.Dv SCRIPT_NAME
    +preprocessor constant is used instead.
    +.It Ev PATH_INFO
    +The final part of the URI path passed from the client to the server,
    +starting after the
    +.Ev SCRIPT_NAME
    +and ending before the
    +.Ev QUERY_STRING .
    +It is used by the
    +.Cm show
    +page to acquire the manpath and filename it needs.
    +.It Ev QUERY_STRING
    +The HTTP query string passed from the client to the server.
    +It is the final part of the URI, after the question mark.
    +It is used by the
    +.Cm search
    +page to acquire the named parameters it needs.
    +.El
    +.Sh FILES
    +.Bl -tag -width Ds
    +.It Pa /var/www
    +Default web server
    +.Xr chroot 2
    +directory.
    +All the following paths are specified relative to this directory.
    +.It Pa /cgi-bin/man.cgi
    +The usual file system path to the
    +.Nm
    +program inside the web server
    +.Xr chroot 2
    +directory.
    +A different name can be chosen, but in any case, it needs to be configured in
    +.Xr httpd.conf 5 .
    +.It Pa /htdocs
    +The file system path to the server document root directory
    +relative to the server
    +.Xr chroot 2
    +directory.
    +This is part of the web server configuration and not specific to
    +.Nm .
    +.It Pa /htdocs/mandoc.css
    +A style sheet for
    +.Xr mandoc 1
    +HTML styling, referenced from each generated HTML page.
    +.It Pa /man
    +Default
    +.Nm
    +data directory containing all the manual trees.
    +Can be overridden by
    +.Dv MAN_DIR .
    +.It Pa /man/manpath.conf
    +The list of available manpaths, one per line.
    +If any of the lines in this file contains a slash
    +.Pq Sq /
    +or any character not contained in the
    +.Sx Restricted character set ,
    +.Nm
    +reports an internal server error and exits without doing anything.
    +.It Pa /man/header.html
    +An optional file containing static HTML code to be inserted right
    +after opening the <BODY> element.
    +.It Pa /man/footer.html
    +An optional file containing static HTML code to be inserted right
    +before closing the <BODY> element.
    +.It Pa /man/OpenBSD-current/man1/mandoc.1
    +An example
    +.Xr mdoc 7
    +source file located below the
    +.Dq OpenBSD-current
    +manpath.
    +.El
    +.Sh COMPATIBILITY
    +The
    +.Nm
    +CGI program is call-compatible with queries from the traditional
    +.Pa man.cgi
    +script by Wolfram Schneider.
    +However, the output looks quite different.
    +.Sh SEE ALSO
    +.Xr apropos 1 ,
    +.Xr mandoc.db 5 ,
    +.Xr makewhatis 8 ,
    +.Xr slowcgi 8
    +.Sh HISTORY
    +A version of
    +.Nm
    +based on
    +.Xr mandoc 1
    +first appeared in mdocml-1.12.1 (March 2012).
    +The current
    +.Xr mandoc.db 5
    +database format first appeared in
    +.Ox 6.1 .
    +.Sh AUTHORS
    +.An -nosplit
    +The
    +.Nm
    +program was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +and is maintained by
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org ,
    +who also designed and implemented the database format.
    
    Property changes on: head/contrib/mandoc/man.cgi.8
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man.conf.5
    ===================================================================
    --- head/contrib/mandoc/man.conf.5	(nonexistent)
    +++ head/contrib/mandoc/man.conf.5	(revision 338826)
    @@ -0,0 +1,135 @@
    +.\"	$Id: man.conf.5,v 1.5 2017/08/22 18:17:52 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: August 22 2017 $
    +.Dt MAN.CONF 5
    +.Os
    +.Sh NAME
    +.Nm man.conf
    +.Nd configuration file for man
    +.Sh DESCRIPTION
    +This is the configuration file
    +for the
    +.Xr man 1 ,
    +.Xr apropos 1 ,
    +and
    +.Xr makewhatis 8
    +utilities.
    +Its presence, and all directives, are optional.
    +.Pp
    +This file is an ASCII text file.
    +Leading whitespace on lines, lines starting with
    +.Sq # ,
    +and blank lines are ignored.
    +Words are separated by whitespace.
    +The first word on each line is the name of a configuration directive.
    +.Pp
    +The following directives are supported:
    +.Bl -tag -width Ds
    +.It Ic manpath Ar path
    +Override the default search
    +.Ar path
    +for
    +.Xr man 1 ,
    +.Xr apropos 1 ,
    +and
    +.Xr makewhatis 8 .
    +It can be used multiple times to specify multiple paths,
    +with the order determining the manual page search order.
    +.Pp
    +Each path is a tree containing subdirectories
    +whose names consist of the strings
    +.Sq man
    +and/or
    +.Sq cat
    +followed by the names of sections, usually single digits.
    +The former are supposed to contain unformatted manual pages in
    +.Xr mdoc 7
    +and/or
    +.Xr man 7
    +format; file names should end with the name of the section
    +preceded by a dot.
    +The latter should contain preformatted manual pages;
    +file names should end with
    +.Ql .0 .
    +.Pp
    +Creating a
    +.Xr mandoc.db 5
    +database with
    +.Xr makewhatis 8
    +in each directory configured with
    +.Ic manpath
    +is recommended and necessary for
    +.Xr apropos 1
    +to work, and also for
    +.Xr man 1
    +on operating systems like
    +.Ox
    +that install each manual page with only one file name in the file system,
    +even if it documents multiple utilities or functions.
    +.It Ic output Ar option Op Ar value
    +Configure the default value of an output option.
    +These directives are overridden by the
    +.Fl O
    +command line options of the same names.
    +For details, see the
    +.Xr mandoc 1
    +manual.
    +.Pp
    +.Bl -column fragment integer "ascii, utf8" -compact
    +.It Ar option   Ta Ar value Ta used by Fl T Ta purpose
    +.It Ta Ta Ta
    +.It Ic fragment Ta none     Ta Cm html Ta print only body
    +.It Ic includes Ta string   Ta Cm html Ta path to header files
    +.It Ic indent   Ta integer  Ta Cm ascii , utf8 Ta left margin
    +.It Ic man      Ta string   Ta Cm html Ta path for \&Xr links
    +.It Ic paper    Ta string   Ta Cm ps , pdf Ta paper size
    +.It Ic style    Ta string   Ta Cm html Ta CSS file
    +.It Ic width    Ta integer  Ta Cm ascii , utf8 Ta right margin
    +.El
    +.It Ic _whatdb Ar path Ns Cm /whatis.db
    +This directive provides the same functionality as
    +.Ic manpath ,
    +but using a historic and misleading syntax.
    +It is kept for backward compatibility for now,
    +but will eventually be removed.
    +.El
    +.Sh FILES
    +.Pa /etc/man.conf
    +.Sh EXAMPLES
    +The following configuration file reproduces the defaults:
    +installing it is equivalent to not having a
    +.Nm
    +file at all.
    +.Bd -literal -offset indent
    +manpath /usr/share/man
    +manpath /usr/X11R6/man
    +manpath /usr/local/man
    +.Ed
    +.Sh SEE ALSO
    +.Xr apropos 1 ,
    +.Xr man 1 ,
    +.Xr makewhatis 8
    +.Sh HISTORY
    +A relatively complicated
    +.Nm
    +file format first appeared in
    +.Bx 4.3 Reno .
    +For
    +.Ox 5.8 ,
    +it was redesigned from scratch, aiming for simplicity.
    +.Sh AUTHORS
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org
    
    Property changes on: head/contrib/mandoc/man.conf.5
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man_html.c
    ===================================================================
    --- head/contrib/mandoc/man_html.c	(nonexistent)
    +++ head/contrib/mandoc/man_html.c	(revision 338826)
    @@ -0,0 +1,646 @@
    +/*	$Id: man_html.c,v 1.153 2018/07/27 17:49:31 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#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	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(const struct roff_meta *,
    +				struct html *);
    +static	void		  print_man_nodelist(MAN_ARGS);
    +static	void		  print_man_node(MAN_ARGS);
    +static	int		  fillmode(struct html *, int);
    +static	int		  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(const struct roff_meta *,
    +				struct html *);
    +static	void		  man_root_pre(const struct roff_meta *,
    +				struct html *);
    +
    +static	const struct htmlman __mans[MAN_MAX - MAN_TH] = {
    +	{ NULL, NULL }, /* TH */
    +	{ 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 roff_node	*n;
    +	struct tag		*t;
    +
    +	h = (struct html *)arg;
    +	n = man->first->child;
    +
    +	if ((h->oflags & HTML_FRAGMENT) == 0) {
    +		print_gen_decls(h);
    +		print_otag(h, TAG_HTML, "");
    +		if (n->type == ROFFT_COMMENT)
    +			print_gen_comment(h, n);
    +		t = print_otag(h, TAG_HEAD, "");
    +		print_man_head(&man->meta, h);
    +		print_tagq(h, t);
    +		print_otag(h, TAG_BODY, "");
    +	}
    +
    +	man_root_pre(&man->meta, h);
    +	t = print_otag(h, TAG_DIV, "c", "manual-text");
    +	print_man_nodelist(&man->meta, n, h);
    +	print_tagq(h, t);
    +	man_root_post(&man->meta, h);
    +	print_tagq(h, NULL);
    +}
    +
    +static void
    +print_man_head(const struct roff_meta *man, struct html *h)
    +{
    +	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;
    +	case ROFFT_COMMENT:
    +		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 void
    +man_root_pre(const struct roff_meta *man, struct html *h)
    +{
    +	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(const struct roff_meta *man, struct html *h)
    +{
    +	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, 1);
    +		print_otag(h, TAG_H1, "cTi", "Sh", id);
    +		if (id != NULL)
    +			print_otag(h, TAG_A, "chR", "permalink", 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, 1);
    +		print_otag(h, TAG_H2, "cTi", "Ss", id);
    +		if (id != NULL)
    +			print_otag(h, TAG_A, "chR", "permalink", 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, "");
    +		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, "");
    +
    +	/* 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)
    +{
    +	if (n->type == ROFFT_HEAD)
    +		return 0;
    +
    +	if (n->type == ROFFT_BLOCK) {
    +		print_bvspace(h, n);
    +		print_otag(h, TAG_DIV, "c", "HP");
    +	}
    +	return 1;
    +}
    +
    +static int
    +man_OP_pre(MAN_ARGS)
    +{
    +	struct tag	*tt;
    +
    +	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)
    +{
    +	if (n->type == ROFFT_HEAD)
    +		return 0;
    +	if (n->type == ROFFT_BLOCK)
    +		print_otag(h, TAG_DIV, "c", "Bd-indent");
    +	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);
    +		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;
    +}
    
    Property changes on: head/contrib/mandoc/man_html.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man_term.c
    ===================================================================
    --- head/contrib/mandoc/man_term.c	(nonexistent)
    +++ head/contrib/mandoc/man_term.c	(revision 338826)
    @@ -0,0 +1,1116 @@
    +/*	$Id: man_term.c,v 1.211 2018/06/10 15:12:35 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#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 {
    +		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;
    +}
    +
    +/*
    + * 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_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_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_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_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 >= MAN_TH &&
    +		    termacts[n->tok].flags & MAN_NOTEXT);
    +		if (n == NULL || n->type == ROFFT_COMMENT ||
    +		    (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 >= MAN_TH &&
    +		    termacts[n->tok].flags & MAN_NOTEXT);
    +		if (n == NULL || n->type == ROFFT_COMMENT ||
    +		    (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_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') {
    +			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_COMMENT:
    +		return;
    +	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);
    +
    +	/*
    +	 * Reset the terminal state for more output after the footer:
    +	 * Some output modes, in particular PostScript and PDF, print
    +	 * the header and the footer into a buffer such that it can be
    +	 * reused for multiple output pages, then go on to format the
    +	 * main text.
    +	 */
    +
    +        p->tcol->offset = 0;
    +        p->flags = 0;
    +
    +	free(title);
    +}
    +
    +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);
    +}
    
    Property changes on: head/contrib/mandoc/man_term.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man_validate.c
    ===================================================================
    --- head/contrib/mandoc/man_validate.c	(nonexistent)
    +++ head/contrib/mandoc/man_validate.c	(revision 338826)
    @@ -0,0 +1,494 @@
    +/*	$OpenBSD$ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <errno.h>
    +#include <limits.h>
    +#include <stdarg.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#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_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 */
    +	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_COMMENT:
    +	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 (n->last == NULL || n->last->type == ROFFT_COMMENT)
    +		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, 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_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, 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->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;
    +	}
    +}
    
    Property changes on: head/contrib/mandoc/man_validate.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc.1
    ===================================================================
    --- head/contrib/mandoc/mandoc.1	(nonexistent)
    +++ head/contrib/mandoc/mandoc.1	(revision 338826)
    @@ -0,0 +1,2160 @@
    +.\"	$Id: mandoc.1,v 1.226 2018/07/28 18:34:15 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    +.\" Copyright (c) 2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE 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: July 28 2018 $
    +.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 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.
    +.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 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.
    +See the descriptions of the individual output formats for supported
    +.Ar options .
    +.It Fl T Ar output
    +Select the output format.
    +Supported values for the
    +.Ar output
    +argument are
    +.Cm ascii ,
    +.Cm html ,
    +the default of
    +.Cm locale ,
    +.Cm man ,
    +.Cm markdown ,
    +.Cm pdf ,
    +.Cm ps ,
    +.Cm tree ,
    +and
    +.Cm utf8 .
    +.Pp
    +The special
    +.Fl T Cm lint
    +mode only parses the input and produces no output.
    +It implies
    +.Fl W Cm all
    +and redirects parser messages, which usually appear on standard
    +error output, to standard output.
    +.It Fl W Ar level
    +Specify the minimum message
    +.Ar level
    +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 .
    +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 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 from the given input file.
    +If multiple files are specified, they are processed in the given order.
    +If unspecified,
    +.Nm
    +reads from standard input.
    +.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 ASCII Output
    +Use
    +.Fl T Cm ascii
    +to force text output in 7-bit ASCII character encoding documented in the
    +.Xr ascii 7
    +manual page, ignoring the
    +.Xr locale 1
    +set in the environment.
    +.Pp
    +Font styles are applied by using back-spaced encoding such that an
    +underlined character
    +.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
    +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.
    +When output is to a pager on a terminal that is less than 66 columns
    +wide, the default is reduced to three columns.
    +.It Cm mdoc
    +Format
    +.Xr man 7
    +input files in
    +.Xr mdoc 7
    +output style.
    +Specifically, this suppresses the two additional blank lines near the
    +top and the bottom of each page, and it implies
    +.Fl O Cm indent Ns =5 .
    +One useful application is for checking that
    +.Fl T Cm man
    +output formats in the same way as the
    +.Xr mdoc 7
    +source it was generated from.
    +.It Cm width Ns = Ns Ar width
    +The output width is set to
    +.Ar width
    +instead of the default of 78.
    +When output is to a pager on a terminal that is less than 79 columns
    +wide, the default is reduced to one less than the terminal width.
    +In any case, lines that are output in literal mode are never wrapped
    +and may exceed the output width.
    +.El
    +.Ss HTML Output
    +Output produced by
    +.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
    +Non-ASCII characters are rendered
    +as hexadecimal Unicode character references.
    +.Pp
    +The following
    +.Fl O
    +arguments are accepted:
    +.Bl -tag -width Ds
    +.It Cm fragment
    +Omit the <!DOCTYPE> declaration and the <html>, <head>, and <body>
    +elements and only emit the subtree below the <body> 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
    +By default,
    +.Nm
    +automatically selects UTF-8 or ASCII output according to the current
    +.Xr locale 1 .
    +If any of the environment variables
    +.Ev LC_ALL ,
    +.Ev LC_CTYPE ,
    +or
    +.Ev LANG
    +are set and the first one that is set
    +selects the UTF-8 character encoding, it produces
    +.Sx UTF-8 Output ;
    +otherwise, it falls back to
    +.Sx ASCII Output .
    +This output mode can also be selected explicitly with
    +.Fl T Cm locale .
    +.Ss Man Output
    +Use
    +.Fl T Cm man
    +to translate
    +.Xr mdoc 7
    +input into
    +.Xr man 7
    +output format.
    +This is useful for distributing manual sources to legacy systems
    +lacking
    +.Xr mdoc 7
    +formatters.
    +.Pp
    +If the input format of a file 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
    +Use
    +.Fl T Cm markdown
    +to translate
    +.Xr mdoc 7
    +input to the markdown format conforming to
    +.Lk http://daringfireball.net/projects/markdown/syntax.text\
    + "John Gruber's 2004 specification" .
    +The output also almost conforms to the
    +.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 text output in UTF-8 multi-byte character encoding,
    +ignoring the
    +.Xr locale 1
    +settings in the environment.
    +See
    +.Sx ASCII Output
    +regarding font styles and
    +.Fl O
    +arguments.
    +.Pp
    +On operating systems lacking locale or wide character support, and
    +on those where the internal character representation is not UCS-4,
    +.Nm
    +always falls back to
    +.Sx ASCII Output .
    +.Ss Syntax tree output
    +Use
    +.Fl T Cm tree
    +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 LC_CTYPE
    +The character encoding
    +.Xr locale 1 .
    +When
    +.Sx Locale Output
    +is selected, it decides whether to use ASCII or UTF-8 output format.
    +It never affects the interpretation of input files.
    +.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 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 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 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 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
    +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
    +Indicates a risk of information loss or severe misformatting,
    +in most cases caused by serious syntax errors.
    +.It Cm warning
    +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 convention used in the base system of a specific operating system
    +is not adhered to.
    +These are not markup mistakes, and neither the quality of formatting
    +nor portability are in danger.
    +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.
    +.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 "normalizing date format to" : No ...
    +.Pq mdoc , man
    +The
    +.Ic \&Dd
    +or
    +.Ic \&TH
    +macro provides an abbreviated month name or a day number with a
    +leading zero.
    +In the formatted output, the month name is written out in full
    +and the leading zero is omitted.
    +.It Sy "lower case character in document title"
    +.Pq mdoc , man
    +The title is still used as given in the
    +.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 "possible 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 "trailing delimiter"
    +.Pq mdoc
    +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 "verbatim \(dq--\(dq, maybe consider using \e(em"
    +.Pq mdoc
    +Even though the ASCII output device renders an em-dash as
    +.Qq \-\- ,
    +that is not a good way to write it in an input file
    +because it renders poorly on all other output devices.
    +.It Sy "function name without markup"
    +.Pq mdoc
    +A word followed by an empty pair of parentheses occurs on a text line.
    +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 "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 "late prologue macro"
    +.Pq mdoc
    +A
    +.Ic \&Dd
    +or
    +.Ic \&Os
    +macro occurs after some non-prologue macro, but still takes effect.
    +.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, 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 "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 "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 "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 "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 \&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 \&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 .
    
    Property changes on: head/contrib/mandoc/mandoc.1
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc.c
    ===================================================================
    --- head/contrib/mandoc/mandoc.c	(nonexistent)
    +++ head/contrib/mandoc/mandoc.c	(revision 338826)
    @@ -0,0 +1,633 @@
    +/*	$Id: mandoc.c,v 1.104 2018/07/28 18:34:15 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <errno.h>
    +#include <limits.h>
    +#include <stdlib.h>
    +#include <stdio.h>
    +#include <string.h>
    +#include <time.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 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, 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)) {
    +		cp = time2a(t);
    +		if (t > time(NULL) + 86400)
    +			mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse,
    +			    ln, pos, cp);
    +		else if (*in != '$' && strcmp(in, cp) != 0)
    +			mandoc_msg(MANDOCERR_DATE_NORM, man->parse,
    +			    ln, pos, cp);
    +		return cp;
    +	}
    +
    +	/* In man(7), do not warn about the legacy format. */
    +
    +	if (a2time(&t, "%Y-%m-%d", in) == 0)
    +		mandoc_msg(MANDOCERR_DATE_BAD, man->parse, ln, pos, in);
    +	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;
    +}
    
    Property changes on: head/contrib/mandoc/mandoc.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc.css
    ===================================================================
    --- head/contrib/mandoc/mandoc.css	(nonexistent)
    +++ head/contrib/mandoc/mandoc.css	(revision 338826)
    @@ -0,0 +1,253 @@
    +/* $Id: mandoc.css,v 1.36 2018/07/23 22:51:26 schwarze Exp $ */
    +/*
    + * Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
    + */
    +
    +/* Global defaults. */
    +
    +html {		max-width: 65em; }
    +body {		font-family: Helvetica,Arial,sans-serif; }
    +table {		margin-top: 0em;
    +		margin-bottom: 0em; }
    +td {		vertical-align: top; }
    +ul, ol, dl {	margin-top: 0em;
    +		margin-bottom: 0em; }
    +li, dt {	margin-top: 1em; }
    +
    +.permalink {	border-bottom: thin dotted;
    +		color: inherit;
    +		font: inherit;
    +		text-decoration: inherit; }
    +* {		clear: both }
    +
    +/* Search form and search results. */
    +
    +fieldset {	border: thin solid silver;
    +		border-radius: 1em;
    +		text-align: center; }
    +input[name=expr] {
    +		width: 25%; }
    +
    +table.results {	margin-top: 1em;
    +		margin-left: 2em;
    +		font-size: smaller; }
    +
    +/* Header and footer lines. */
    +
    +table.head {	width: 100%;
    +		border-bottom: 1px dotted #808080;
    +		margin-bottom: 1em;
    +		font-size: smaller; }
    +td.head-vol {	text-align: center; }
    +td.head-rtitle {
    +		text-align: right; }
    +
    +table.foot {	width: 100%;
    +		border-top: 1px dotted #808080;
    +		margin-top: 1em;
    +		font-size: smaller; }
    +td.foot-os {	text-align: right; }
    +
    +/* Sections and paragraphs. */
    +
    +.manual-text {
    +		margin-left: 3.8em; }
    +.Nd {		display: inline; }
    +.Sh {		margin-top: 1.2em;
    +		margin-bottom: 0.6em;
    +		margin-left: -3.2em;
    +		font-size: 110%; }
    +.Ss {		margin-top: 1.2em;
    +		margin-bottom: 0.6em;
    +		margin-left: -1.2em;
    +		font-size: 105%; }
    +.Pp {		margin: 0.6em 0em; }
    +.Sx { }
    +.Xr { }
    +
    +/* Displays and lists. */
    +
    +.Bd { }
    +.Bd-indent {	margin-left: 3.8em; }
    +
    +.Bl-bullet {	list-style-type: disc;
    +		padding-left: 1em; }
    +.Bl-bullet > li { }
    +.Bl-dash {	list-style-type: none;
    +		padding-left: 0em; }
    +.Bl-dash > li:before {
    +		content: "\2014  "; }
    +.Bl-item {	list-style-type: none;
    +		padding-left: 0em; }
    +.Bl-item > li { }
    +.Bl-compact > li {
    +		margin-top: 0em; }
    +
    +.Bl-enum {	padding-left: 2em; }
    +.Bl-enum > li { }
    +.Bl-compact > li {
    +		margin-top: 0em; }
    +
    +.Bl-diag { }
    +.Bl-diag > dt {
    +		font-style: normal;
    +		font-weight: bold; }
    +.Bl-diag > dd {
    +		margin-left: 0em; }
    +.Bl-hang { }
    +.Bl-hang > dt { }
    +.Bl-hang > dd {
    +		margin-left: 5.5em; }
    +.Bl-inset { }
    +.Bl-inset > dt { }
    +.Bl-inset > dd {
    +		margin-left: 0em; }
    +.Bl-ohang { }
    +.Bl-ohang > dt { }
    +.Bl-ohang > dd {
    +		margin-left: 0em; }
    +.Bl-tag {	margin-left: 5.5em; }
    +.Bl-tag > dt {
    +		float: left;
    +		margin-top: 0em;
    +		margin-left: -5.5em;
    +		padding-right: 1.2em;
    +		vertical-align: top; }
    +.Bl-tag > dd {
    +		clear: right;
    +		width: 100%;
    +		margin-top: 0em;
    +		margin-left: 0em;
    +		vertical-align: top;
    +		overflow: auto; }
    +.Bl-compact > dt {
    +		margin-top: 0em; }
    +
    +.Bl-column { }
    +.Bl-column > tbody > tr { }
    +.Bl-column > tbody > tr > td {
    +		margin-top: 1em; }
    +.Bl-compact > tbody > tr > td {
    +		margin-top: 0em; }
    +
    +.Rs {		font-style: normal;
    +		font-weight: normal; }
    +.RsA { }
    +.RsB {		font-style: italic;
    +		font-weight: normal; }
    +.RsC { }
    +.RsD { }
    +.RsI {		font-style: italic;
    +		font-weight: normal; }
    +.RsJ {		font-style: italic;
    +		font-weight: normal; }
    +.RsN { }
    +.RsO { }
    +.RsP { }
    +.RsQ { }
    +.RsR { }
    +.RsT {		text-decoration: underline; }
    +.RsU { }
    +.RsV { }
    +
    +.eqn { }
    +.tbl { }
    +
    +.HP {		margin-left: 3.8em;
    +		text-indent: -3.8em; }
    +
    +/* Semantic markup for command line utilities. */
    +
    +table.Nm { }
    +code.Nm {	font-style: normal;
    +		font-weight: bold;
    +		font-family: inherit; }
    +.Fl {		font-style: normal;
    +		font-weight: bold;
    +		font-family: inherit; }
    +.Cm {		font-style: normal;
    +		font-weight: bold;
    +		font-family: inherit; }
    +.Ar {		font-style: italic;
    +		font-weight: normal; }
    +.Op {		display: inline; }
    +.Ic {		font-style: normal;
    +		font-weight: bold;
    +		font-family: inherit; }
    +.Ev {		font-style: normal;
    +		font-weight: normal;
    +		font-family: monospace; }
    +.Pa {		font-style: italic;
    +		font-weight: normal; }
    +
    +/* Semantic markup for function libraries. */
    +
    +.Lb { }
    +code.In {	font-style: normal;
    +		font-weight: bold;
    +		font-family: inherit; }
    +a.In { }
    +.Fd {		font-style: normal;
    +		font-weight: bold;
    +		font-family: inherit; }
    +.Ft {		font-style: italic;
    +		font-weight: normal; }
    +.Fn {		font-style: normal;
    +		font-weight: bold;
    +		font-family: inherit; }
    +.Fa {		font-style: italic;
    +		font-weight: normal; }
    +.Vt {		font-style: italic;
    +		font-weight: normal; }
    +.Va {		font-style: italic;
    +		font-weight: normal; }
    +.Dv {		font-style: normal;
    +		font-weight: normal;
    +		font-family: monospace; }
    +.Er {		font-style: normal;
    +		font-weight: normal;
    +		font-family: monospace; }
    +
    +/* Various semantic markup. */
    +
    +.An { }
    +.Lk { }
    +.Mt { }
    +.Cd {		font-style: normal;
    +		font-weight: bold;
    +		font-family: inherit; }
    +.Ad {		font-style: italic;
    +		font-weight: normal; }
    +.Ms {		font-style: normal;
    +		font-weight: bold; }
    +.St { }
    +.Ux { }
    +
    +/* Physical markup. */
    +
    +.Bf {		display: inline; }
    +.No {		font-style: normal;
    +		font-weight: normal; }
    +.Em {		font-style: italic;
    +		font-weight: normal; }
    +.Sy {		font-style: normal;
    +		font-weight: bold; }
    +.Li {		font-style: normal;
    +		font-weight: normal;
    +		font-family: monospace; }
    +
    +/* Overrides to avoid excessive margins on small devices. */
    +
    +@media (max-width: 37.5em) {
    +.manual-text {
    +		margin-left: 0.5em; }
    +.Sh, .Ss {	margin-left: 0em; }
    +.Bd-indent {	margin-left: 2em; }
    +.Bl-hang > dd {
    +		margin-left: 2em; }
    +.Bl-tag {	margin-left: 2em; }
    +.Bl-tag > dt {
    +		margin-left: -2em; }
    +.HP {		margin-left: 2em;
    +		text-indent: -2em; }
    +}
    
    Property changes on: head/contrib/mandoc/mandoc.css
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/css
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc.h
    ===================================================================
    --- head/contrib/mandoc/mandoc.h	(nonexistent)
    +++ head/contrib/mandoc/mandoc.h	(revision 338826)
    @@ -0,0 +1,471 @@
    +/*	$Id: mandoc.h,v 1.248 2018/07/28 18:34:15 schwarze Exp $ */
    +/*
    + * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#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_DATE_NORM, /* normalizing date format to: ... */
    +	MANDOCERR_TITLE_CASE, /* lower case character in document title */
    +	MANDOCERR_RCS_REP, /* duplicate RCS id: ... */
    +	MANDOCERR_SEC_TYPO,  /* possible typo in section name: Sh ... */
    +	MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
    +	MANDOCERR_MACRO_USELESS, /* useless macro: macro */
    +	MANDOCERR_BX, /* consider using OS macro: macro */
    +	MANDOCERR_ER_ORDER, /* errnos out of order: Er ... */
    +	MANDOCERR_ER_REP, /* duplicate errno: Er ... */
    +	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_DASHDASH, /* verbatim "--", maybe consider using \(em */
    +	MANDOCERR_FUNC, /* function name without markup: name() */
    +	MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
    +	MANDOCERR_COMMENT_BAD, /* bad comment style */
    +
    +	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_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_LATE, /* late prologue macro: macro */
    +	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_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_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_EOS, /* new sentence, new line */
    +	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_TEXT, /* text (number, variable, whatever) */
    +	EQN_SUBEXPR, /* nested `eqn' subexpression */
    +	EQN_LIST, /* list (braces, etc.) */
    +	EQN_PILE, /* vertical pile */
    +	EQN_MATRIX /* pile of piles */
    +};
    +
    +enum	eqn_fontt {
    +	EQNFONT_NONE = 0,
    +	EQNFONT_ROMAN,
    +	EQNFONT_BOLD,
    +	EQNFONT_FAT,
    +	EQNFONT_ITALIC,
    +	EQNFONT__MAX
    +};
    +
    +enum	eqn_post {
    +	EQNPOS_NONE = 0,
    +	EQNPOS_SUP,
    +	EQNPOS_SUBSUP,
    +	EQNPOS_SUB,
    +	EQNPOS_TO,
    +	EQNPOS_FROM,
    +	EQNPOS_FROMTO,
    +	EQNPOS_OVER,
    +	EQNPOS_SQRT,
    +	EQNPOS__MAX
    +};
    +
    +enum	eqn_pilet {
    +	EQNPILE_NONE = 0,
    +	EQNPILE_PILE,
    +	EQNPILE_CPILE,
    +	EQNPILE_RPILE,
    +	EQNPILE_LPILE,
    +	EQNPILE_COL,
    +	EQNPILE_CCOL,
    +	EQNPILE_RCOL,
    +	EQNPILE_LCOL,
    +	EQNPILE__MAX
    +};
    +
    + /*
    + * A "box" is a parsed mathematical expression as defined by the eqn.7
    + * grammar.
    + */
    +struct	eqn_box {
    +	int		  size; /* font size of expression */
    +#define	EQN_DEFSIZE	  INT_MIN
    +	enum eqn_boxt	  type; /* type of node */
    +	struct eqn_box	 *first; /* first child node */
    +	struct eqn_box	 *last; /* last child node */
    +	struct eqn_box	 *next; /* node sibling */
    +	struct eqn_box	 *prev; /* node sibling */
    +	struct eqn_box	 *parent; /* node sibling */
    +	char		 *text; /* text (or NULL) */
    +	char		 *left; /* fence left-hand */
    +	char		 *right; /* fence right-hand */
    +	char		 *top; /* expression over-symbol */
    +	char		 *bottom; /* expression under-symbol */
    +	size_t		  args; /* arguments in parent */
    +	size_t		  expectargs; /* max arguments in parent */
    +	enum eqn_post	  pos; /* position of next box */
    +	enum eqn_fontt	  font; /* font of box */
    +	enum eqn_pilet	  pile; /* equation piling */
    +};
    +
    +/*
    + * Parse options.
    + */
    +#define	MPARSE_MDOC	1  /* assume -mdoc */
    +#define	MPARSE_MAN	2  /* assume -man */
    +#define	MPARSE_SO	4  /* honour .so requests */
    +#define	MPARSE_QUICK	8  /* abort the parse early */
    +#define	MPARSE_UTF8	16 /* accept UTF-8 input */
    +#define	MPARSE_LATIN1	32 /* accept ISO-LATIN-1 input */
    +
    +enum	mandoc_os {
    +	MANDOC_OS_OTHER = 0,
    +	MANDOC_OS_NETBSD,
    +	MANDOC_OS_OPENBSD
    +};
    +
    +enum	mandoc_esc {
    +	ESCAPE_ERROR = 0, /* bail! unparsable escape */
    +	ESCAPE_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 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 *);
    
    Property changes on: head/contrib/mandoc/mandoc.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_aux.c
    ===================================================================
    --- head/contrib/mandoc/mandoc_aux.c	(nonexistent)
    +++ head/contrib/mandoc/mandoc_aux.c	(revision 338826)
    @@ -0,0 +1,118 @@
    +/*	$Id: mandoc_aux.c,v 1.11 2018/02/07 20:04:57 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * 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 <sys/types.h>
    +
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <stdarg.h>
    +#include <stdlib.h>
    +#include <stdio.h>
    +#include <string.h>
    +
    +#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 = strndup(ptr, sz);
    +	if (p == NULL)
    +		err((int)MANDOCLEVEL_SYSERR, NULL);
    +	return p;
    +}
    
    Property changes on: head/contrib/mandoc/mandoc_aux.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_char.7
    ===================================================================
    --- head/contrib/mandoc/mandoc_char.7	(nonexistent)
    +++ head/contrib/mandoc/mandoc_char.7	(revision 338826)
    @@ -0,0 +1,828 @@
    +.\"	$Id: mandoc_char.7,v 1.72 2018/08/08 14:30:48 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
    +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    +.\" Copyright (c) 2011, 2013, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: August 8 2018 $
    +.Dt MANDOC_CHAR 7
    +.Os
    +.Sh NAME
    +.Nm mandoc_char
    +.Nd mandoc special characters
    +.Sh DESCRIPTION
    +This page documents the
    +.Xr roff 7
    +escape sequences accepted by
    +.Xr mandoc 1
    +to represent special characters in
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +documents.
    +.Pp
    +The rendering depends on the
    +.Xr mandoc 1
    +output mode; it can be inspected by calling
    +.Xr man 1
    +on the
    +.Nm
    +manual page with different
    +.Fl T
    +arguments.
    +In ASCII output, the rendering of some characters may be hard
    +to interpret for the reader.
    +Many are rendered as descriptive strings like
    +.Qq <integral> ,
    +.Qq <degree> ,
    +or
    +.Qq <Gamma> ,
    +which may look ugly, and many are replaced by similar ASCII characters.
    +In particular, accented characters are usually shown without the accent.
    +For that reason, try to avoid using any of the special characters
    +documented here except those discussed in the
    +.Sx DESCRIPTION ,
    +unless they are essential for explaining the subject matter at hand,
    +for example when documenting complicated mathematical functions.
    +.Pp
    +In particular, in English manual pages, do not use special-character
    +escape sequences to represent national language characters in author
    +names; instead, provide ASCII transcriptions of the names.
    +.Ss Dashes and Hyphens
    +In typography there are different types of dashes of various width:
    +the hyphen (\(hy),
    +the en-dash (\(en),
    +the em-dash (\(em),
    +and the mathematical minus sign (\(mi).
    +.Pp
    +Hyphens are used for adjectives;
    +to separate the two parts of a compound word;
    +or to separate a word across two successive lines of text.
    +The hyphen does not need to be escaped:
    +.Bd -unfilled -offset indent
    +blue-eyed
    +lorry-driver
    +.Ed
    +.Pp
    +The en-dash is used to separate the two elements of a range,
    +or can be used the same way as an em-dash.
    +It should be written as
    +.Sq \e(en :
    +.Bd -unfilled -offset indent
    +pp. 95\e(en97.
    +Go away \e(en or else!
    +.Ed
    +.Pp
    +The em-dash can be used to show an interruption
    +or can be used the same way as colons, semi-colons, or parentheses.
    +It should be written as
    +.Sq \e(em :
    +.Bd -unfilled -offset indent
    +Three things \e(em apples, oranges, and bananas.
    +This is not that \e(em rather, this is that.
    +.Ed
    +.Pp
    +In
    +.Xr roff 7
    +documents, the minus sign is normally written as
    +.Sq \e- .
    +In manual pages, some style guides recommend to also use
    +.Sq \e-
    +if an ASCII 0x2d
    +.Dq hyphen-minus
    +output glyph that can be copied and pasted is desired in output modes
    +supporting it, for example in
    +.Fl T Cm utf8
    +and
    +.Fl T Cm html .
    +But currently, no practically relevant manual page formatter actually
    +requires that subtlety, so in manual pages just write plain
    +.Sq -
    +to represent hyphen, minus, and hyphen-minus.
    +.Pp
    +If a word on a text input line contains a hyphen, a formatter may decide
    +to insert an output line break after the hyphen if that helps filling
    +the current output line, but the whole word would overflow the line.
    +If it is important that the word is not broken across lines in this
    +way, a zero-width space
    +.Pq Sq \e&
    +can be inserted before or after the hyphen.
    +While
    +.Xr mandoc 1
    +never breaks the output line after hyphens adjacent to a zero-width
    +space, after any of the other dash- or hyphen-like characters
    +represented by escape sequences, or after hyphens inside words in
    +macro arguments, other software may not respect these rules and may
    +break the line even in such cases.
    +.Pp
    +Some
    +.Xr roff 7
    +implementations contains dictionaries allowing to break the line
    +at syllable boundaries even inside words that contain no hyphens.
    +Such automatic hyphenation is not supported by
    +.Xr mandoc 1 ,
    +which only breaks the line at whitespace, and inside words only
    +after existing hyphens.
    +.Ss Spaces
    +To separate words in normal text, for indenting and alignment
    +in literal context, and when none of the following special cases apply,
    +just use the normal space character
    +.Pq Sq \  .
    +.Pp
    +When filling text, output lines may be broken between words, i.e. at space
    +characters.
    +To prevent a line break between two particular words,
    +use the unpaddable non-breaking space escape sequence
    +.Pq Sq \e\ \&
    +instead of the normal space character.
    +For example, the input string
    +.Dq number\e\ 1
    +will be kept together as
    +.Dq number\ 1
    +on the same output line.
    +.Pp
    +On request and macro lines, the normal space character serves as an
    +argument delimiter.
    +To include whitespace into arguments, quoting is usually the best choice;
    +see the MACRO SYNTAX section in
    +.Xr roff 7 .
    +In some cases, using the non-breaking space escape sequence
    +.Pq Sq \e\ \&
    +may be preferable.
    +.Pp
    +To escape macro names and to protect whitespace at the end
    +of input lines, the zero-width space
    +.Pq Sq \e&
    +is often useful.
    +For example, in
    +.Xr mdoc 7 ,
    +a normal space character can be displayed in single quotes in either
    +of the following ways:
    +.Pp
    +.Dl .Sq \(dq \(dq
    +.Dl .Sq \e \e&
    +.Ss Quotes
    +On request and macro lines, the double-quote character
    +.Pq Sq \(dq
    +is handled specially to allow quoting.
    +One way to prevent this special handling is by using the
    +.Sq \e(dq
    +escape sequence.
    +.Pp
    +Note that on text lines, literal double-quote characters can be used
    +verbatim.
    +All other quote-like characters can be used verbatim as well,
    +even on request and macro lines.
    +.Ss Accents
    +In output modes supporting such special output characters, for example
    +.Fl T Cm pdf ,
    +and sometimes less consistently in
    +.Fl T Cm utf8 ,
    +some
    +.Xr roff 7
    +formatters convert the following ASCII input characters to the
    +following Unicode special output characters:
    +.Bl -column x(ga U+2018 -offset indent
    +.It \(ga Ta U+2018 Ta left single quotation mark
    +.It \(aq Ta U+2019 Ta right single quotation mark
    +.It \(ti Ta U+02DC Ta small tilde
    +.It \(ha Ta U+02C6 Ta modifier letter circumflex
    +.El
    +.Pp
    +In prose, this automatic substitution is often desirable;
    +but when these characters have to be displayed as plain ASCII
    +characters, for example in source code samples, they require
    +escaping to render as follows:
    +.Bl -column x(ga U+2018 -offset indent
    +.It \e(ga Ta U+0060 Ta grave accent
    +.It \e(aq Ta U+0027 Ta apostrophe
    +.It \e(ti Ta U+007E Ta tilde
    +.It \e(ha Ta U+005E Ta circumflex accent
    +.El
    +.Ss Periods
    +The period
    +.Pq Sq \&.
    +is handled specially at the beginning of an input line,
    +where it introduces a
    +.Xr roff 7
    +request or a macro, and when appearing alone as a macro argument in
    +.Xr mdoc 7 .
    +In such situations, prepend a zero-width space
    +.Pq Sq \e&.
    +to make it behave like normal text.
    +.Pp
    +Do not use the
    +.Sq \e.
    +escape sequence.
    +It does not prevent special handling of the period.
    +.Ss Backslashes
    +To include a literal backslash
    +.Pq Sq \e
    +into the output, use the
    +.Pq Sq \ee
    +escape sequence.
    +.Pp
    +Note that doubling it
    +.Pq Sq \e\e
    +is not the right way to output a backslash.
    +Because
    +.Xr mandoc 1
    +does not implement full
    +.Xr roff 7
    +functionality, it may work with
    +.Xr mandoc 1 ,
    +but it may have weird effects on complete
    +.Xr roff 7
    +implementations.
    +.Sh SPECIAL CHARACTERS
    +Special characters are encoded as
    +.Sq \eX
    +.Pq for a one-character escape ,
    +.Sq \e(XX
    +.Pq two-character ,
    +and
    +.Sq \e[N]
    +.Pq N-character .
    +For details, see the
    +.Em Special Characters
    +subsection of the
    +.Xr roff 7
    +manual.
    +.Pp
    +Spacing:
    +.Bl -column "Input" "Description" -offset indent -compact
    +.It Em Input Ta Em Description
    +.It Sq \e\ \& Ta unpaddable non-breaking space
    +.It \e\(ti   Ta paddable non-breaking space
    +.It \e0      Ta unpaddable, breaking digit-width space
    +.It \e|      Ta one-sixth \e(em narrow space, zero width in nroff mode
    +.It \e^      Ta one-twelfth \e(em half-narrow space, zero width in nroff
    +.It \e&      Ta zero-width space
    +.It \e%      Ta zero-width space allowing hyphenation
    +.El
    +.Pp
    +Lines:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(ba    Ta \(ba        Ta bar
    +.It \e(br    Ta \(br        Ta box rule
    +.It \e(ul    Ta \(ul        Ta underscore
    +.It \e(ru    Ta \(ru        Ta underscore (width 0.5m)
    +.It \e(rn    Ta \(rn        Ta overline
    +.It \e(bb    Ta \(bb        Ta broken bar
    +.It \e(sl    Ta \(sl        Ta forward slash
    +.It \e(rs    Ta \(rs        Ta backward slash
    +.El
    +.Pp
    +Text markers:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(ci    Ta \(ci        Ta circle
    +.It \e(bu    Ta \(bu        Ta bullet
    +.It \e(dd    Ta \(dd        Ta double dagger
    +.It \e(dg    Ta \(dg        Ta dagger
    +.It \e(lz    Ta \(lz        Ta lozenge
    +.It \e(sq    Ta \(sq        Ta white square
    +.It \e(ps    Ta \(ps        Ta paragraph
    +.It \e(sc    Ta \(sc        Ta section
    +.It \e(lh    Ta \(lh        Ta left hand
    +.It \e(rh    Ta \(rh        Ta right hand
    +.It \e(at    Ta \(at        Ta at
    +.It \e(sh    Ta \(sh        Ta hash (pound)
    +.It \e(CR    Ta \(CR        Ta carriage return
    +.It \e(OK    Ta \(OK        Ta check mark
    +.It \e(CL    Ta \(CL        Ta club suit
    +.It \e(SP    Ta \(SP        Ta spade suit
    +.It \e(HE    Ta \(HE        Ta heart suit
    +.It \e(DI    Ta \(DI        Ta diamond suit
    +.El
    +.Pp
    +Legal symbols:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(co    Ta \(co        Ta copyright
    +.It \e(rg    Ta \(rg        Ta registered
    +.It \e(tm    Ta \(tm        Ta trademarked
    +.El
    +.Pp
    +Punctuation:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(em    Ta \(em        Ta em-dash
    +.It \e(en    Ta \(en        Ta en-dash
    +.It \e(hy    Ta \(hy        Ta hyphen
    +.It \ee      Ta \e          Ta back-slash
    +.It \e.      Ta \.          Ta period
    +.It \e(r!    Ta \(r!        Ta upside-down exclamation
    +.It \e(r?    Ta \(r?        Ta upside-down question
    +.El
    +.Pp
    +Quotes:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(Bq    Ta \(Bq        Ta right low double-quote
    +.It \e(bq    Ta \(bq        Ta right low single-quote
    +.It \e(lq    Ta \(lq        Ta left double-quote
    +.It \e(rq    Ta \(rq        Ta right double-quote
    +.It \e(oq    Ta \(oq        Ta left single-quote
    +.It \e(cq    Ta \(cq        Ta right single-quote
    +.It \e(aq    Ta \(aq        Ta apostrophe quote (ASCII character)
    +.It \e(dq    Ta \(dq        Ta double quote (ASCII character)
    +.It \e(Fo    Ta \(Fo        Ta left guillemet
    +.It \e(Fc    Ta \(Fc        Ta right guillemet
    +.It \e(fo    Ta \(fo        Ta left single guillemet
    +.It \e(fc    Ta \(fc        Ta right single guillemet
    +.El
    +.Pp
    +Brackets:
    +.Bl -column "xxbracketrightbtx" Rendered Description -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(lB    Ta \(lB        Ta left bracket
    +.It \e(rB    Ta \(rB        Ta right bracket
    +.It \e(lC    Ta \(lC        Ta left brace
    +.It \e(rC    Ta \(rC        Ta right brace
    +.It \e(la    Ta \(la        Ta left angle
    +.It \e(ra    Ta \(ra        Ta right angle
    +.It \e(bv    Ta \(bv        Ta brace extension (special font)
    +.It \e[braceex] Ta \[braceex] Ta brace extension
    +.It \e[bracketlefttp] Ta \[bracketlefttp] Ta top-left hooked bracket
    +.It \e[bracketleftbt] Ta \[bracketleftbt] Ta bottom-left hooked bracket
    +.It \e[bracketleftex] Ta \[bracketleftex] Ta left hooked bracket extension
    +.It \e[bracketrighttp] Ta \[bracketrighttp] Ta top-right hooked bracket
    +.It \e[bracketrightbt] Ta \[bracketrightbt] Ta bottom-right hooked bracket
    +.It \e[bracketrightex] Ta \[bracketrightex] Ta right hooked bracket extension
    +.It \e(lt    Ta \(lt        Ta top-left hooked brace
    +.It \e[bracelefttp] Ta \[bracelefttp] Ta top-left hooked brace
    +.It \e(lk    Ta \(lk        Ta mid-left hooked brace
    +.It \e[braceleftmid] Ta \[braceleftmid] Ta mid-left hooked brace
    +.It \e(lb    Ta \(lb        Ta bottom-left hooked brace
    +.It \e[braceleftbt] Ta \[braceleftbt] Ta bottom-left hooked brace
    +.It \e[braceleftex] Ta \[braceleftex] Ta left hooked brace extension
    +.It \e(rt    Ta \(rt        Ta top-left hooked brace
    +.It \e[bracerighttp] Ta \[bracerighttp] Ta top-right hooked brace
    +.It \e(rk    Ta \(rk        Ta mid-right hooked brace
    +.It \e[bracerightmid] Ta \[bracerightmid] Ta mid-right hooked brace
    +.It \e(rb    Ta \(rb        Ta bottom-right hooked brace
    +.It \e[bracerightbt] Ta \[bracerightbt] Ta bottom-right hooked brace
    +.It \e[bracerightex] Ta \[bracerightex] Ta right hooked brace extension
    +.It \e[parenlefttp] Ta \[parenlefttp] Ta top-left hooked parenthesis
    +.It \e[parenleftbt] Ta \[parenleftbt] Ta bottom-left hooked parenthesis
    +.It \e[parenleftex] Ta \[parenleftex] Ta left hooked parenthesis extension
    +.It \e[parenrighttp] Ta \[parenrighttp] Ta top-right hooked parenthesis
    +.It \e[parenrightbt] Ta \[parenrightbt] Ta bottom-right hooked parenthesis
    +.It \e[parenrightex] Ta \[parenrightex] Ta right hooked parenthesis extension
    +.El
    +.Pp
    +Arrows:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(<-    Ta \(<-        Ta left arrow
    +.It \e(->    Ta \(->        Ta right arrow
    +.It \e(<>    Ta \(<>        Ta left-right arrow
    +.It \e(da    Ta \(da        Ta down arrow
    +.It \e(ua    Ta \(ua        Ta up arrow
    +.It \e(va    Ta \(va        Ta up-down arrow
    +.It \e(lA    Ta \(lA        Ta left double-arrow
    +.It \e(rA    Ta \(rA        Ta right double-arrow
    +.It \e(hA    Ta \(hA        Ta left-right double-arrow
    +.It \e(uA    Ta \(uA        Ta up double-arrow
    +.It \e(dA    Ta \(dA        Ta down double-arrow
    +.It \e(vA    Ta \(vA        Ta up-down double-arrow
    +.It \e(an    Ta \(an        Ta horizontal arrow extension
    +.El
    +.Pp
    +Logical:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(AN    Ta \(AN        Ta logical and
    +.It \e(OR    Ta \(OR        Ta logical or
    +.It \e[tno]  Ta \[tno]      Ta logical not (text font)
    +.It \e(no    Ta \(no        Ta logical not (special font)
    +.It \e(te    Ta \(te        Ta existential quantifier
    +.It \e(fa    Ta \(fa        Ta universal quantifier
    +.It \e(st    Ta \(st        Ta such that
    +.It \e(tf    Ta \(tf        Ta therefore
    +.It \e(3d    Ta \(3d        Ta therefore
    +.It \e(or    Ta \(or        Ta bitwise or
    +.El
    +.Pp
    +Mathematical:
    +.Bl -column "xxcoproductxx" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e-      Ta \-          Ta minus (text font)
    +.It \e(mi    Ta \(mi        Ta minus (special font)
    +.It +        Ta +           Ta plus (text font)
    +.It \e(pl    Ta \(pl        Ta plus (special font)
    +.It \e(-+    Ta \(-+        Ta minus-plus
    +.It \e[t+-]  Ta \[t+-]      Ta plus-minus (text font)
    +.It \e(+-    Ta \(+-        Ta plus-minus (special font)
    +.It \e(pc    Ta \(pc        Ta center-dot
    +.It \e[tmu]  Ta \[tmu]      Ta multiply (text font)
    +.It \e(mu    Ta \(mu        Ta multiply (special font)
    +.It \e(c*    Ta \(c*        Ta circle-multiply
    +.It \e(c+    Ta \(c+        Ta circle-plus
    +.It \e[tdi]  Ta \[tdi]      Ta divide (text font)
    +.It \e(di    Ta \(di        Ta divide (special font)
    +.It \e(f/    Ta \(f/        Ta fraction
    +.It \e(**    Ta \(**        Ta asterisk
    +.It \e(<=    Ta \(<=        Ta less-than-equal
    +.It \e(>=    Ta \(>=        Ta greater-than-equal
    +.It \e(<<    Ta \(<<        Ta much less
    +.It \e(>>    Ta \(>>        Ta much greater
    +.It \e(eq    Ta \(eq        Ta equal
    +.It \e(!=    Ta \(!=        Ta not equal
    +.It \e(==    Ta \(==        Ta equivalent
    +.It \e(ne    Ta \(ne        Ta not equivalent
    +.It \e(ap    Ta \(ap        Ta tilde operator
    +.It \e(|=    Ta \(|=        Ta asymptotically equal
    +.It \e(=\(ti Ta \(=~        Ta approximately equal
    +.It \e(\(ti\(ti Ta \(~~        Ta almost equal
    +.It \e(\(ti= Ta \(~=        Ta almost equal
    +.It \e(pt    Ta \(pt        Ta proportionate
    +.It \e(es    Ta \(es        Ta empty set
    +.It \e(mo    Ta \(mo        Ta element
    +.It \e(nm    Ta \(nm        Ta not element
    +.It \e(sb    Ta \(sb        Ta proper subset
    +.It \e(nb    Ta \(nb        Ta not subset
    +.It \e(sp    Ta \(sp        Ta proper superset
    +.It \e(nc    Ta \(nc        Ta not superset
    +.It \e(ib    Ta \(ib        Ta reflexive subset
    +.It \e(ip    Ta \(ip        Ta reflexive superset
    +.It \e(ca    Ta \(ca        Ta intersection
    +.It \e(cu    Ta \(cu        Ta union
    +.It \e(/_    Ta \(/_        Ta angle
    +.It \e(pp    Ta \(pp        Ta perpendicular
    +.It \e(is    Ta \(is        Ta integral
    +.It \e[integral] Ta \[integral] Ta integral
    +.It \e[sum]    Ta \[sum]   Ta summation
    +.It \e[product] Ta \[product] Ta product
    +.It \e[coproduct] Ta \[coproduct] Ta coproduct
    +.It \e(gr    Ta \(gr        Ta gradient
    +.It \e(sr    Ta \(sr        Ta square root
    +.It \e[sqrt] Ta \[sqrt]     Ta square root
    +.It \e(lc    Ta \(lc        Ta left-ceiling
    +.It \e(rc    Ta \(rc        Ta right-ceiling
    +.It \e(lf    Ta \(lf        Ta left-floor
    +.It \e(rf    Ta \(rf        Ta right-floor
    +.It \e(if    Ta \(if        Ta infinity
    +.It \e(Ah    Ta \(Ah        Ta aleph
    +.It \e(Im    Ta \(Im        Ta imaginary
    +.It \e(Re    Ta \(Re        Ta real
    +.It \e(wp    Ta \(wp        Ta Weierstrass p
    +.It \e(pd    Ta \(pd        Ta partial differential
    +.It \e(-h    Ta \(-h        Ta Planck constant over 2\(*p
    +.It \e[hbar] Ta \[hbar]     Ta Planck constant over 2\(*p
    +.It \e(12    Ta \(12        Ta one-half
    +.It \e(14    Ta \(14        Ta one-fourth
    +.It \e(34    Ta \(34        Ta three-fourths
    +.It \e(18    Ta \(18        Ta one-eighth
    +.It \e(38    Ta \(38        Ta three-eighths
    +.It \e(58    Ta \(58        Ta five-eighths
    +.It \e(78    Ta \(78        Ta seven-eighths
    +.It \e(S1    Ta \(S1        Ta superscript 1
    +.It \e(S2    Ta \(S2        Ta superscript 2
    +.It \e(S3    Ta \(S3        Ta superscript 3
    +.El
    +.Pp
    +Ligatures:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(ff    Ta \(ff        Ta ff ligature
    +.It \e(fi    Ta \(fi        Ta fi ligature
    +.It \e(fl    Ta \(fl        Ta fl ligature
    +.It \e(Fi    Ta \(Fi        Ta ffi ligature
    +.It \e(Fl    Ta \(Fl        Ta ffl ligature
    +.It \e(AE    Ta \(AE        Ta AE
    +.It \e(ae    Ta \(ae        Ta ae
    +.It \e(OE    Ta \(OE        Ta OE
    +.It \e(oe    Ta \(oe        Ta oe
    +.It \e(ss    Ta \(ss        Ta German eszett
    +.It \e(IJ    Ta \(IJ        Ta IJ ligature
    +.It \e(ij    Ta \(ij        Ta ij ligature
    +.El
    +.Pp
    +Accents:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(a"    Ta \(a"        Ta Hungarian umlaut
    +.It \e(a-    Ta \(a-        Ta macron
    +.It \e(a.    Ta \(a.        Ta dotted
    +.It \e(a^    Ta \(a^        Ta circumflex
    +.It \e(aa    Ta \(aa        Ta acute
    +.It \e\(aq   Ta \'          Ta acute
    +.It \e(ga    Ta \(ga        Ta grave
    +.It \e\(ga   Ta \`          Ta grave
    +.It \e(ab    Ta \(ab        Ta breve
    +.It \e(ac    Ta \(ac        Ta cedilla
    +.It \e(ad    Ta \(ad        Ta dieresis
    +.It \e(ah    Ta \(ah        Ta caron
    +.It \e(ao    Ta \(ao        Ta ring
    +.It \e(a\(ti Ta \(a~        Ta tilde
    +.It \e(ho    Ta \(ho        Ta ogonek
    +.It \e(ha    Ta \(ha        Ta hat (ASCII character)
    +.It \e(ti    Ta \(ti        Ta tilde (ASCII character)
    +.El
    +.Pp
    +Accented letters:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(\(aqA Ta \('A        Ta acute A
    +.It \e(\(aqE Ta \('E        Ta acute E
    +.It \e(\(aqI Ta \('I        Ta acute I
    +.It \e(\(aqO Ta \('O        Ta acute O
    +.It \e(\(aqU Ta \('U        Ta acute U
    +.It \e(\(aqa Ta \('a        Ta acute a
    +.It \e(\(aqe Ta \('e        Ta acute e
    +.It \e(\(aqi Ta \('i        Ta acute i
    +.It \e(\(aqo Ta \('o        Ta acute o
    +.It \e(\(aqu Ta \('u        Ta acute u
    +.It \e(\(gaA Ta \(`A        Ta grave A
    +.It \e(\(gaE Ta \(`E        Ta grave E
    +.It \e(\(gaI Ta \(`I        Ta grave I
    +.It \e(\(gaO Ta \(`O        Ta grave O
    +.It \e(\(gaU Ta \(`U        Ta grave U
    +.It \e(\(gaa Ta \(`a        Ta grave a
    +.It \e(\(gae Ta \(`e        Ta grave e
    +.It \e(\(gai Ta \(`i        Ta grave i
    +.It \e(\(gao Ta \(`i        Ta grave o
    +.It \e(\(gau Ta \(`u        Ta grave u
    +.It \e(\(tiA Ta \(~A        Ta tilde A
    +.It \e(\(tiN Ta \(~N        Ta tilde N
    +.It \e(\(tiO Ta \(~O        Ta tilde O
    +.It \e(\(tia Ta \(~a        Ta tilde a
    +.It \e(\(tin Ta \(~n        Ta tilde n
    +.It \e(\(tio Ta \(~o        Ta tilde o
    +.It \e(:A    Ta \(:A        Ta dieresis A
    +.It \e(:E    Ta \(:E        Ta dieresis E
    +.It \e(:I    Ta \(:I        Ta dieresis I
    +.It \e(:O    Ta \(:O        Ta dieresis O
    +.It \e(:U    Ta \(:U        Ta dieresis U
    +.It \e(:a    Ta \(:a        Ta dieresis a
    +.It \e(:e    Ta \(:e        Ta dieresis e
    +.It \e(:i    Ta \(:i        Ta dieresis i
    +.It \e(:o    Ta \(:o        Ta dieresis o
    +.It \e(:u    Ta \(:u        Ta dieresis u
    +.It \e(:y    Ta \(:y        Ta dieresis y
    +.It \e(^A    Ta \(^A        Ta circumflex A
    +.It \e(^E    Ta \(^E        Ta circumflex E
    +.It \e(^I    Ta \(^I        Ta circumflex I
    +.It \e(^O    Ta \(^O        Ta circumflex O
    +.It \e(^U    Ta \(^U        Ta circumflex U
    +.It \e(^a    Ta \(^a        Ta circumflex a
    +.It \e(^e    Ta \(^e        Ta circumflex e
    +.It \e(^i    Ta \(^i        Ta circumflex i
    +.It \e(^o    Ta \(^o        Ta circumflex o
    +.It \e(^u    Ta \(^u        Ta circumflex u
    +.It \e(,C    Ta \(,C        Ta cedilla C
    +.It \e(,c    Ta \(,c        Ta cedilla c
    +.It \e(/L    Ta \(/L        Ta stroke L
    +.It \e(/l    Ta \(/l        Ta stroke l
    +.It \e(/O    Ta \(/O        Ta stroke O
    +.It \e(/o    Ta \(/o        Ta stroke o
    +.It \e(oA    Ta \(oA        Ta ring A
    +.It \e(oa    Ta \(oa        Ta ring a
    +.El
    +.Pp
    +Special letters:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(-D    Ta \(-D        Ta Eth
    +.It \e(Sd    Ta \(Sd        Ta eth
    +.It \e(TP    Ta \(TP        Ta Thorn
    +.It \e(Tp    Ta \(Tp        Ta thorn
    +.It \e(.i    Ta \(.i        Ta dotless i
    +.It \e(.j    Ta \(.j        Ta dotless j
    +.El
    +.Pp
    +Currency:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(Do    Ta \(Do        Ta dollar
    +.It \e(ct    Ta \(ct        Ta cent
    +.It \e(Eu    Ta \(Eu        Ta Euro symbol
    +.It \e(eu    Ta \(eu        Ta Euro symbol
    +.It \e(Ye    Ta \(Ye        Ta yen
    +.It \e(Po    Ta \(Po        Ta pound
    +.It \e(Cs    Ta \(Cs        Ta Scandinavian
    +.It \e(Fn    Ta \(Fn        Ta florin
    +.El
    +.Pp
    +Units:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(de    Ta \(de        Ta degree
    +.It \e(%0    Ta \(%0        Ta per-thousand
    +.It \e(fm    Ta \(fm        Ta minute
    +.It \e(sd    Ta \(sd        Ta second
    +.It \e(mc    Ta \(mc        Ta micro
    +.It \e(Of    Ta \(Of        Ta Spanish female ordinal
    +.It \e(Om    Ta \(Om        Ta Spanish masculine ordinal
    +.El
    +.Pp
    +Greek letters:
    +.Bl -column "Input" "Rendered" "Description" -offset indent -compact
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e(*A    Ta \(*A        Ta Alpha
    +.It \e(*B    Ta \(*B        Ta Beta
    +.It \e(*G    Ta \(*G        Ta Gamma
    +.It \e(*D    Ta \(*D        Ta Delta
    +.It \e(*E    Ta \(*E        Ta Epsilon
    +.It \e(*Z    Ta \(*Z        Ta Zeta
    +.It \e(*Y    Ta \(*Y        Ta Eta
    +.It \e(*H    Ta \(*H        Ta Theta
    +.It \e(*I    Ta \(*I        Ta Iota
    +.It \e(*K    Ta \(*K        Ta Kappa
    +.It \e(*L    Ta \(*L        Ta Lambda
    +.It \e(*M    Ta \(*M        Ta Mu
    +.It \e(*N    Ta \(*N        Ta Nu
    +.It \e(*C    Ta \(*C        Ta Xi
    +.It \e(*O    Ta \(*O        Ta Omicron
    +.It \e(*P    Ta \(*P        Ta Pi
    +.It \e(*R    Ta \(*R        Ta Rho
    +.It \e(*S    Ta \(*S        Ta Sigma
    +.It \e(*T    Ta \(*T        Ta Tau
    +.It \e(*U    Ta \(*U        Ta Upsilon
    +.It \e(*F    Ta \(*F        Ta Phi
    +.It \e(*X    Ta \(*X        Ta Chi
    +.It \e(*Q    Ta \(*Q        Ta Psi
    +.It \e(*W    Ta \(*W        Ta Omega
    +.It \e(*a    Ta \(*a        Ta alpha
    +.It \e(*b    Ta \(*b        Ta beta
    +.It \e(*g    Ta \(*g        Ta gamma
    +.It \e(*d    Ta \(*d        Ta delta
    +.It \e(*e    Ta \(*e        Ta epsilon
    +.It \e(*z    Ta \(*z        Ta zeta
    +.It \e(*y    Ta \(*y        Ta eta
    +.It \e(*h    Ta \(*h        Ta theta
    +.It \e(*i    Ta \(*i        Ta iota
    +.It \e(*k    Ta \(*k        Ta kappa
    +.It \e(*l    Ta \(*l        Ta lambda
    +.It \e(*m    Ta \(*m        Ta mu
    +.It \e(*n    Ta \(*n        Ta nu
    +.It \e(*c    Ta \(*c        Ta xi
    +.It \e(*o    Ta \(*o        Ta omicron
    +.It \e(*p    Ta \(*p        Ta pi
    +.It \e(*r    Ta \(*r        Ta rho
    +.It \e(*s    Ta \(*s        Ta sigma
    +.It \e(*t    Ta \(*t        Ta tau
    +.It \e(*u    Ta \(*u        Ta upsilon
    +.It \e(*f    Ta \(*f        Ta phi
    +.It \e(*x    Ta \(*x        Ta chi
    +.It \e(*q    Ta \(*q        Ta psi
    +.It \e(*w    Ta \(*w        Ta omega
    +.It \e(+h    Ta \(+h        Ta theta variant
    +.It \e(+f    Ta \(+f        Ta phi variant
    +.It \e(+p    Ta \(+p        Ta pi variant
    +.It \e(+e    Ta \(+e        Ta epsilon variant
    +.It \e(ts    Ta \(ts        Ta sigma terminal
    +.El
    +.Sh PREDEFINED STRINGS
    +Predefined strings are inherited from the macro packages of historical
    +troff implementations.
    +They are
    +.Em not recommended
    +for use, as they differ across implementations.
    +Manuals using these predefined strings are almost certainly not
    +portable.
    +.Pp
    +Their syntax is similar to special characters, using
    +.Sq \e*X
    +.Pq for a one-character escape ,
    +.Sq \e*(XX
    +.Pq two-character ,
    +and
    +.Sq \e*[N]
    +.Pq N-character .
    +For details, see the
    +.Em Predefined Strings
    +subsection of the
    +.Xr roff 7
    +manual.
    +.Bl -column "Input" "Rendered" "Description" -offset indent
    +.It Em Input Ta Em Rendered Ta Em Description
    +.It \e*(Ba   Ta \*(Ba       Ta vertical bar
    +.It \e*(Ne   Ta \*(Ne       Ta not equal
    +.It \e*(Ge   Ta \*(Ge       Ta greater-than-equal
    +.It \e*(Le   Ta \*(Le       Ta less-than-equal
    +.It \e*(Gt   Ta \*(Gt       Ta greater-than
    +.It \e*(Lt   Ta \*(Lt       Ta less-than
    +.It \e*(Pm   Ta \*(Pm       Ta plus-minus
    +.It \e*(If   Ta \*(If       Ta infinity
    +.It \e*(Pi   Ta \*(Pi       Ta pi
    +.It \e*(Na   Ta \*(Na       Ta NaN
    +.It \e*(Am   Ta \*(Am       Ta ampersand
    +.It \e*R     Ta \*R         Ta restricted mark
    +.It \e*(Tm   Ta \*(Tm       Ta trade mark
    +.It \e*q     Ta \*q         Ta double-quote
    +.It \e*(Rq   Ta \*(Rq       Ta right-double-quote
    +.It \e*(Lq   Ta \*(Lq       Ta left-double-quote
    +.It \e*(lp   Ta \*(lp       Ta right-parenthesis
    +.It \e*(rp   Ta \*(rp       Ta left-parenthesis
    +.It \e*(lq   Ta \*(lq       Ta left double-quote
    +.It \e*(rq   Ta \*(rq       Ta right double-quote
    +.It \e*(ua   Ta \*(ua       Ta up arrow
    +.It \e*(va   Ta \*(va       Ta up-down arrow
    +.It \e*(<=   Ta \*(<=       Ta less-than-equal
    +.It \e*(>=   Ta \*(>=       Ta greater-than-equal
    +.It \e*(aa   Ta \*(aa       Ta acute
    +.It \e*(ga   Ta \*(ga       Ta grave
    +.It \e*(Px   Ta \*(Px       Ta POSIX standard name
    +.It \e*(Ai   Ta \*(Ai       Ta ANSI standard name
    +.El
    +.Sh UNICODE CHARACTERS
    +The escape sequences
    +.Pp
    +.Dl \e[uXXXX] and \eC\(aquXXXX\(aq
    +.Pp
    +are interpreted as Unicode codepoints.
    +The codepoint must be in the range above U+0080 and less than U+10FFFF.
    +For compatibility, the hexadecimal digits
    +.Sq A
    +to
    +.Sq F
    +must be given as uppercase characters,
    +and points must be zero-padded to four characters; if
    +greater than four characters, no zero padding is allowed.
    +Unicode surrogates are not allowed.
    +.Sh NUMBERED CHARACTERS
    +For backward compatibility with existing manuals,
    +.Xr mandoc 1
    +also supports the
    +.Pp
    +.Dl \eN\(aq Ns Ar number Ns \(aq
    +.Pp
    +escape sequence, inserting the character
    +.Ar number
    +from the current character set into the output.
    +Of course, this is inherently non-portable and is already marked
    +as deprecated in the Heirloom roff manual.
    +For example, do not use \eN\(aq34\(aq, use \e(dq, or even the plain
    +.Sq \(dq
    +character where possible.
    +.Sh COMPATIBILITY
    +This section documents compatibility between mandoc and other
    +troff implementations, at this time limited to GNU troff
    +.Pq Qq groff .
    +.Pp
    +.Bl -dash -compact
    +.It
    +The \eN\(aq\(aq escape sequence is limited to printable characters; in
    +groff, it accepts arbitrary character numbers.
    +.It
    +In
    +.Fl T Ns Cm ascii ,
    +the
    +\e(ss, \e(nm, \e(nb, \e(nc, \e(ib, \e(ip, \e(pp, \e[sum], \e[product],
    +\e[coproduct], \e(gr, \e(-h, and \e(a. special characters render
    +differently between mandoc and groff.
    +.It
    +In
    +.Fl T Ns Cm html ,
    +the \e(\(ti=, \e(nb, and \e(nc special characters render differently
    +between mandoc and groff.
    +.It
    +The
    +.Fl T Ns Cm ps
    +and
    +.Fl T Ns Cm pdf
    +modes format like
    +.Fl T Ns Cm ascii
    +instead of rendering glyphs as in groff.
    +.It
    +The \e[radicalex], \e[sqrtex], and \e(ru special characters have been omitted
    +from mandoc either because they are poorly documented or they have no
    +known representation.
    +.El
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr man 7 ,
    +.Xr mdoc 7 ,
    +.Xr roff 7
    +.Sh AUTHORS
    +The
    +.Nm
    +manual page was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
    +.Sh CAVEATS
    +The predefined string
    +.Sq \e*(Ba
    +mimics the behaviour of the
    +.Sq \&|
    +character in
    +.Xr mdoc 7 ;
    +thus, if you wish to render a vertical bar with no side effects, use
    +the
    +.Sq \e(ba
    +escape.
    
    Property changes on: head/contrib/mandoc/mandoc_char.7
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_html.3
    ===================================================================
    --- head/contrib/mandoc/mandoc_html.3	(nonexistent)
    +++ head/contrib/mandoc/mandoc_html.3	(revision 338826)
    @@ -0,0 +1,325 @@
    +.\"	$Id: mandoc_html.3,v 1.17 2018/06/25 16:54:59 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE 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 25 2018 $
    +.Dt MANDOC_HTML 3
    +.Os
    +.Sh NAME
    +.Nm mandoc_html
    +.Nd internals of the mandoc HTML formatter
    +.Sh SYNOPSIS
    +.In "html.h"
    +.Ft void
    +.Fn print_gen_decls "struct html *h"
    +.Ft void
    +.Fn print_gen_comment "struct html *h" "struct roff_node *n"
    +.Ft void
    +.Fn print_gen_head "struct html *h"
    +.Ft struct tag *
    +.Fo print_otag
    +.Fa "struct html *h"
    +.Fa "enum htmltag tag"
    +.Fa "const char *fmt"
    +.Fa ...
    +.Fc
    +.Ft void
    +.Fo print_tagq
    +.Fa "struct html *h"
    +.Fa "const struct tag *until"
    +.Fc
    +.Ft void
    +.Fo print_stagq
    +.Fa "struct html *h"
    +.Fa "const struct tag *suntil"
    +.Fc
    +.Ft void
    +.Fo print_text
    +.Fa "struct html *h"
    +.Fa "const char *word"
    +.Fc
    +.Ft char *
    +.Fo html_make_id
    +.Fa "const struct roff_node *n"
    +.Fc
    +.Ft int
    +.Fo html_strlen
    +.Fa "const char *cp"
    +.Fc
    +.Sh DESCRIPTION
    +The mandoc HTML formatter is not a formal library.
    +However, as it is compiled into more than one program, in particular
    +.Xr mandoc 1
    +and
    +.Xr man.cgi 8 ,
    +and because it may be security-critical in some contexts,
    +some documentation is useful to help to use it correctly and
    +to prevent XSS vulnerabilities.
    +.Pp
    +The formatter produces HTML output on the standard output.
    +Since proper escaping is usually required and best taken care of
    +at one central place, the language-specific formatters
    +.Po
    +.Pa *_html.c ,
    +see
    +.Sx FILES
    +.Pc
    +are not supposed to print directly to
    +.Dv stdout
    +using functions like
    +.Xr printf 3 ,
    +.Xr putc 3 ,
    +.Xr puts 3 ,
    +or
    +.Xr write 2 .
    +Instead, they are expected to use the output functions declared in
    +.Pa html.h
    +and implemented as part of the main HTML formatting engine in
    +.Pa html.c .
    +.Ss Data structures
    +These structures are declared in
    +.Pa html.h .
    +.Bl -tag -width Ds
    +.It Vt struct html
    +Internal state of the HTML formatter.
    +.It Vt struct tag
    +One entry for the LIFO stack of HTML elements.
    +Members are
    +.Fa "enum htmltag tag"
    +and
    +.Fa "struct tag *next" .
    +.El
    +.Ss Private interface functions
    +The function
    +.Fn print_gen_decls
    +prints the opening
    +.Ao Pf \&? Ic xml ? Ac
    +and
    +.Aq Pf \&! Ic DOCTYPE
    +declarations required for the current document type.
    +.Pp
    +The function
    +.Fn print_gen_comment
    +prints the leading comments, usually containing a Copyright notice
    +and license, as an HTML comment.
    +It is intended to be called right after opening the
    +.Aq Ic HTML
    +element.
    +Pass the first
    +.Dv ROFFT_COMMENT
    +node in
    +.Fa n .
    +.Pp
    +The function
    +.Fn print_gen_head
    +prints the opening
    +.Aq Ic META
    +and
    +.Aq Ic LINK
    +elements for the document
    +.Aq Ic HEAD ,
    +using the
    +.Fa style
    +member of
    +.Fa h
    +unless that is
    +.Dv NULL .
    +It uses
    +.Fn print_otag
    +which takes care of properly encoding attributes,
    +which is relevant for the
    +.Fa style
    +link in particular.
    +.Pp
    +The function
    +.Fn print_otag
    +prints the start tag of an HTML element with the name
    +.Fa tag ,
    +optionally including the attributes specified by
    +.Fa fmt .
    +If
    +.Fa fmt
    +is the empty string, no attributes are written.
    +Each letter of
    +.Fa fmt
    +specifies one attribute to write.
    +Most attributes require one
    +.Va char *
    +argument which becomes the value of the attribute.
    +The arguments have to be given in the same order as the attribute letters.
    +If an argument is
    +.Dv NULL ,
    +the respective attribute is not written.
    +.Bl -tag -width 1n -offset indent
    +.It Cm c
    +Print a
    +.Cm class
    +attribute.
    +This attribute letter can optionally be followed by the modifier letter
    +.Cm T .
    +In that case, a
    +.Cm title
    +attribute with the same value is also printed.
    +.It Cm h
    +Print a
    +.Cm href
    +attribute.
    +This attribute letter can optionally be followed by a modifier letter.
    +If followed by
    +.Cm R ,
    +it formats the link as a local one by prefixing a
    +.Sq #
    +character.
    +If followed by
    +.Cm I ,
    +it interpretes the argument as a header file name
    +and generates a link using the
    +.Xr mandoc 1
    +.Fl O Cm includes
    +option.
    +If followed by
    +.Cm M ,
    +it takes two arguments instead of one, a manual page name and
    +section, and formats them as a link to a manual page using the
    +.Xr mandoc 1
    +.Fl O Cm man
    +option.
    +.It Cm i
    +Print an
    +.Cm id
    +attribute.
    +.It Cm \&?
    +Print an arbitrary attribute.
    +This format letter requires two
    +.Vt char *
    +arguments, the attribute name and the value.
    +The name must not be
    +.Dv NULL .
    +.It Cm s
    +Print a
    +.Cm style
    +attribute.
    +If present, it must be the last format letter.
    +It requires two
    +.Va char *
    +arguments.
    +The first is the name of the style property, the second its value.
    +.El
    +.Pp
    +.Fn print_otag
    +uses the private function
    +.Fn print_encode
    +to take care of HTML encoding.
    +If required by the element type, it remembers in
    +.Fa h
    +that the element is open.
    +The function
    +.Fn print_tagq
    +is used to close out all open elements up to and including
    +.Fa until ;
    +.Fn print_stagq
    +is a variant to close out all open elements up to but excluding
    +.Fa suntil .
    +.Pp
    +The function
    +.Fn print_text
    +prints HTML element content.
    +It uses the private function
    +.Fn print_encode
    +to take care of HTML encoding.
    +If the document has requested a non-standard font, for example using a
    +.Xr roff 7
    +.Ic \ef
    +font escape sequence,
    +.Fn print_text
    +wraps
    +.Fa word
    +in an HTML font selection element using the
    +.Fn print_otag
    +and
    +.Fn print_tagq
    +functions.
    +.Pp
    +The function
    +.Fn html_make_id
    +takes a node containing one or more text children
    +and returns a newly allocated string containing the concatenation
    +of the child strings, with blanks replaced by underscores.
    +If the node
    +.Fa n
    +contains any non-text child node,
    +.Fn html_make_id
    +returns
    +.Dv NULL
    +instead.
    +The caller is responsible for freeing the returned string.
    +.Pp
    +The function
    +.Fn html_strlen
    +counts the number of characters in
    +.Fa cp .
    +It is used as a crude estimate of the width needed to display a string.
    +.Pp
    +The functions
    +.Fn print_eqn ,
    +.Fn print_tbl ,
    +and
    +.Fn print_tblclose
    +are not yet documented.
    +.Sh FILES
    +.Bl -tag -width mandoc_aux.c -compact
    +.It Pa main.h
    +declarations of public functions for use by the main program,
    +not yet documented
    +.It Pa html.h
    +declarations of data types and private functions
    +for use by language-specific HTML formatters
    +.It Pa html.c
    +main HTML formatting engine and utility functions
    +.It Pa mdoc_html.c
    +.Xr mdoc 7
    +HTML formatter
    +.It Pa man_html.c
    +.Xr man 7
    +HTML formatter
    +.It Pa tbl_html.c
    +.Xr tbl 7
    +HTML formatter
    +.It Pa eqn_html.c
    +.Xr eqn 7
    +HTML formatter
    +.It Pa out.h
    +declarations of data types and private functions
    +for shared use by all mandoc formatters,
    +not yet documented
    +.It Pa out.c
    +private functions for shared use by all mandoc formatters
    +.It Pa mandoc_aux.h
    +declarations of common mandoc utility functions, see
    +.Xr mandoc 3
    +.It Pa mandoc_aux.c
    +implementation of common mandoc utility functions
    +.El
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr mandoc 3 ,
    +.Xr man.cgi 8
    +.Sh AUTHORS
    +.An -nosplit
    +The mandoc HTML formatter was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
    +It is maintained by
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org ,
    +who also wrote this manual.
    
    Property changes on: head/contrib/mandoc/mandoc_html.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandocdb.c
    ===================================================================
    --- head/contrib/mandoc/mandocdb.c	(nonexistent)
    +++ head/contrib/mandoc/mandocdb.c	(revision 338826)
    @@ -0,0 +1,2364 @@
    +/*	$Id: mandocdb.c,v 1.258 2018/02/23 18:25:57 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +#include <sys/mman.h>
    +#include <sys/stat.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <errno.h>
    +#include <fcntl.h>
    +#if HAVE_FTS
    +#include <fts.h>
    +#else
    +#include "compat_fts.h"
    +#endif
    +#include <limits.h>
    +#if HAVE_SANDBOX_INIT
    +#include <sandbox.h>
    +#endif
    +#include <stdarg.h>
    +#include <stddef.h>
    +#include <stdio.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc_ohash.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "man.h"
    +#include "manconf.h"
    +#include "mansearch.h"
    +#include "dba_array.h"
    +#include "dba.h"
    +
    +extern const char *const mansearch_keynames[];
    +
    +enum	op {
    +	OP_DEFAULT = 0, /* new dbs from dir list or default config */
    +	OP_CONFFILE, /* new databases from custom config file */
    +	OP_UPDATE, /* delete/add entries in existing database */
    +	OP_DELETE, /* delete entries from existing database */
    +	OP_TEST /* change no databases, report potential problems */
    +};
    +
    +struct	str {
    +	const struct mpage *mpage; /* if set, the owning parse */
    +	uint64_t	 mask; /* bitmask in sequence */
    +	char		 key[]; /* rendered text */
    +};
    +
    +struct	inodev {
    +	ino_t		 st_ino;
    +	dev_t		 st_dev;
    +};
    +
    +struct	mpage {
    +	struct inodev	 inodev;  /* used for hashing routine */
    +	struct dba_array *dba;
    +	char		*sec;     /* section from file content */
    +	char		*arch;    /* architecture from file content */
    +	char		*title;   /* title from file content */
    +	char		*desc;    /* description from file content */
    +	struct mpage	*next;    /* singly linked list */
    +	struct mlink	*mlinks;  /* singly linked list */
    +	int		 name_head_done;
    +	enum form	 form;    /* format from file content */
    +};
    +
    +struct	mlink {
    +	char		 file[PATH_MAX]; /* filename rel. to manpath */
    +	char		*dsec;    /* section from directory */
    +	char		*arch;    /* architecture from directory */
    +	char		*name;    /* name from file name (not empty) */
    +	char		*fsec;    /* section from file name suffix */
    +	struct mlink	*next;    /* singly linked list */
    +	struct mpage	*mpage;   /* parent */
    +	int		 gzip;	  /* filename has a .gz suffix */
    +	enum form	 dform;   /* format from directory */
    +	enum form	 fform;   /* format from file name suffix */
    +};
    +
    +typedef	int (*mdoc_fp)(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +
    +struct	mdoc_handler {
    +	mdoc_fp		 fp; /* optional handler */
    +	uint64_t	 mask;  /* set unless handler returns 0 */
    +	int		 taboo;  /* node flags that must not be set */
    +};
    +
    +
    +int		 mandocdb(int, char *[]);
    +
    +static	void	 dbadd(struct dba *, struct mpage *);
    +static	void	 dbadd_mlink(const struct mlink *mlink);
    +static	void	 dbprune(struct dba *);
    +static	void	 dbwrite(struct dba *);
    +static	void	 filescan(const char *);
    +#if HAVE_FTS_COMPARE_CONST
    +static	int	 fts_compare(const FTSENT *const *, const FTSENT *const *);
    +#else
    +static	int	 fts_compare(const FTSENT **, const FTSENT **);
    +#endif
    +static	void	 mlink_add(struct mlink *, const struct stat *);
    +static	void	 mlink_check(struct mpage *, struct mlink *);
    +static	void	 mlink_free(struct mlink *);
    +static	void	 mlinks_undupe(struct mpage *);
    +static	void	 mpages_free(void);
    +static	void	 mpages_merge(struct dba *, struct mparse *);
    +static	void	 parse_cat(struct mpage *, int);
    +static	void	 parse_man(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	void	 parse_mdoc(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_head(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_Fa(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_Fd(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	void	 parse_mdoc_fname(struct mpage *, const struct roff_node *);
    +static	int	 parse_mdoc_Fn(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_Fo(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_Nd(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_Nm(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_Sh(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_Va(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	int	 parse_mdoc_Xr(struct mpage *, const struct roff_meta *,
    +			const struct roff_node *);
    +static	void	 putkey(const struct mpage *, char *, uint64_t);
    +static	void	 putkeys(const struct mpage *, char *, size_t, uint64_t);
    +static	void	 putmdockey(const struct mpage *,
    +			const struct roff_node *, uint64_t, int);
    +static	int	 render_string(char **, size_t *);
    +static	void	 say(const char *, const char *, ...)
    +			__attribute__((__format__ (__printf__, 2, 3)));
    +static	int	 set_basedir(const char *, int);
    +static	int	 treescan(void);
    +static	size_t	 utf8(unsigned int, char [7]);
    +
    +static	int		 nodb; /* no database changes */
    +static	int		 mparse_options; /* abort the parse early */
    +static	int		 use_all; /* use all found files */
    +static	int		 debug; /* print what we're doing */
    +static	int		 warnings; /* warn about crap */
    +static	int		 write_utf8; /* write UTF-8 output; else ASCII */
    +static	int		 exitcode; /* to be returned by main */
    +static	enum op		 op; /* operational mode */
    +static	char		 basedir[PATH_MAX]; /* current base directory */
    +static	struct mpage	*mpage_head; /* list of distinct manual pages */
    +static	struct ohash	 mpages; /* table of distinct manual pages */
    +static	struct ohash	 mlinks; /* table of directory entries */
    +static	struct ohash	 names; /* table of all names */
    +static	struct ohash	 strings; /* table of all strings */
    +static	uint64_t	 name_mask;
    +
    +static	const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
    +	{ NULL, 0, NODE_NOPRT },  /* Dd */
    +	{ NULL, 0, NODE_NOPRT },  /* Dt */
    +	{ NULL, 0, NODE_NOPRT },  /* Os */
    +	{ parse_mdoc_Sh, TYPE_Sh, 0 }, /* Sh */
    +	{ parse_mdoc_head, TYPE_Ss, 0 }, /* Ss */
    +	{ NULL, 0, 0 },  /* Pp */
    +	{ NULL, 0, 0 },  /* D1 */
    +	{ NULL, 0, 0 },  /* Dl */
    +	{ NULL, 0, 0 },  /* Bd */
    +	{ NULL, 0, 0 },  /* Ed */
    +	{ NULL, 0, 0 },  /* Bl */
    +	{ NULL, 0, 0 },  /* El */
    +	{ NULL, 0, 0 },  /* It */
    +	{ NULL, 0, 0 },  /* Ad */
    +	{ NULL, TYPE_An, 0 },  /* An */
    +	{ NULL, 0, 0 },  /* Ap */
    +	{ NULL, TYPE_Ar, 0 },  /* Ar */
    +	{ NULL, TYPE_Cd, 0 },  /* Cd */
    +	{ NULL, TYPE_Cm, 0 },  /* Cm */
    +	{ NULL, TYPE_Dv, 0 },  /* Dv */
    +	{ NULL, TYPE_Er, 0 },  /* Er */
    +	{ NULL, TYPE_Ev, 0 },  /* Ev */
    +	{ NULL, 0, 0 },  /* Ex */
    +	{ parse_mdoc_Fa, 0, 0 },  /* Fa */
    +	{ parse_mdoc_Fd, 0, 0 },  /* Fd */
    +	{ NULL, TYPE_Fl, 0 },  /* Fl */
    +	{ parse_mdoc_Fn, 0, 0 },  /* Fn */
    +	{ NULL, TYPE_Ft | TYPE_Vt, 0 },  /* Ft */
    +	{ NULL, TYPE_Ic, 0 },  /* Ic */
    +	{ NULL, TYPE_In, 0 },  /* In */
    +	{ NULL, TYPE_Li, 0 },  /* Li */
    +	{ parse_mdoc_Nd, 0, 0 },  /* Nd */
    +	{ parse_mdoc_Nm, 0, 0 },  /* Nm */
    +	{ NULL, 0, 0 },  /* Op */
    +	{ NULL, 0, 0 },  /* Ot */
    +	{ NULL, TYPE_Pa, NODE_NOSRC },  /* Pa */
    +	{ NULL, 0, 0 },  /* Rv */
    +	{ NULL, TYPE_St, 0 },  /* St */
    +	{ parse_mdoc_Va, TYPE_Va, 0 },  /* Va */
    +	{ parse_mdoc_Va, TYPE_Vt, 0 },  /* Vt */
    +	{ parse_mdoc_Xr, 0, 0 },  /* Xr */
    +	{ NULL, 0, 0 },  /* %A */
    +	{ NULL, 0, 0 },  /* %B */
    +	{ NULL, 0, 0 },  /* %D */
    +	{ NULL, 0, 0 },  /* %I */
    +	{ NULL, 0, 0 },  /* %J */
    +	{ NULL, 0, 0 },  /* %N */
    +	{ NULL, 0, 0 },  /* %O */
    +	{ NULL, 0, 0 },  /* %P */
    +	{ NULL, 0, 0 },  /* %R */
    +	{ NULL, 0, 0 },  /* %T */
    +	{ NULL, 0, 0 },  /* %V */
    +	{ NULL, 0, 0 },  /* Ac */
    +	{ NULL, 0, 0 },  /* Ao */
    +	{ NULL, 0, 0 },  /* Aq */
    +	{ NULL, TYPE_At, 0 },  /* At */
    +	{ NULL, 0, 0 },  /* Bc */
    +	{ NULL, 0, 0 },  /* Bf */
    +	{ NULL, 0, 0 },  /* Bo */
    +	{ NULL, 0, 0 },  /* Bq */
    +	{ NULL, TYPE_Bsx, NODE_NOSRC },  /* Bsx */
    +	{ NULL, TYPE_Bx, NODE_NOSRC },  /* Bx */
    +	{ NULL, 0, 0 },  /* Db */
    +	{ NULL, 0, 0 },  /* Dc */
    +	{ NULL, 0, 0 },  /* Do */
    +	{ NULL, 0, 0 },  /* Dq */
    +	{ NULL, 0, 0 },  /* Ec */
    +	{ NULL, 0, 0 },  /* Ef */
    +	{ NULL, TYPE_Em, 0 },  /* Em */
    +	{ NULL, 0, 0 },  /* Eo */
    +	{ NULL, TYPE_Fx, NODE_NOSRC },  /* Fx */
    +	{ NULL, TYPE_Ms, 0 },  /* Ms */
    +	{ NULL, 0, 0 },  /* No */
    +	{ NULL, 0, 0 },  /* Ns */
    +	{ NULL, TYPE_Nx, NODE_NOSRC },  /* Nx */
    +	{ NULL, TYPE_Ox, NODE_NOSRC },  /* Ox */
    +	{ NULL, 0, 0 },  /* Pc */
    +	{ NULL, 0, 0 },  /* Pf */
    +	{ NULL, 0, 0 },  /* Po */
    +	{ NULL, 0, 0 },  /* Pq */
    +	{ NULL, 0, 0 },  /* Qc */
    +	{ NULL, 0, 0 },  /* Ql */
    +	{ NULL, 0, 0 },  /* Qo */
    +	{ NULL, 0, 0 },  /* Qq */
    +	{ NULL, 0, 0 },  /* Re */
    +	{ NULL, 0, 0 },  /* Rs */
    +	{ NULL, 0, 0 },  /* Sc */
    +	{ NULL, 0, 0 },  /* So */
    +	{ NULL, 0, 0 },  /* Sq */
    +	{ NULL, 0, 0 },  /* Sm */
    +	{ NULL, 0, 0 },  /* Sx */
    +	{ NULL, TYPE_Sy, 0 },  /* Sy */
    +	{ NULL, TYPE_Tn, 0 },  /* Tn */
    +	{ NULL, 0, NODE_NOSRC },  /* Ux */
    +	{ NULL, 0, 0 },  /* Xc */
    +	{ NULL, 0, 0 },  /* Xo */
    +	{ parse_mdoc_Fo, 0, 0 },  /* Fo */
    +	{ NULL, 0, 0 },  /* Fc */
    +	{ NULL, 0, 0 },  /* Oo */
    +	{ NULL, 0, 0 },  /* Oc */
    +	{ NULL, 0, 0 },  /* Bk */
    +	{ NULL, 0, 0 },  /* Ek */
    +	{ NULL, 0, 0 },  /* Bt */
    +	{ NULL, 0, 0 },  /* Hf */
    +	{ NULL, 0, 0 },  /* Fr */
    +	{ NULL, 0, 0 },  /* Ud */
    +	{ NULL, TYPE_Lb, NODE_NOSRC },  /* Lb */
    +	{ NULL, 0, 0 },  /* Lp */
    +	{ NULL, TYPE_Lk, 0 },  /* Lk */
    +	{ NULL, TYPE_Mt, NODE_NOSRC },  /* Mt */
    +	{ NULL, 0, 0 },  /* Brq */
    +	{ NULL, 0, 0 },  /* Bro */
    +	{ NULL, 0, 0 },  /* Brc */
    +	{ NULL, 0, 0 },  /* %C */
    +	{ NULL, 0, 0 },  /* Es */
    +	{ NULL, 0, 0 },  /* En */
    +	{ NULL, TYPE_Dx, NODE_NOSRC },  /* Dx */
    +	{ NULL, 0, 0 },  /* %Q */
    +	{ NULL, 0, 0 },  /* %U */
    +	{ NULL, 0, 0 },  /* Ta */
    +};
    +static	const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd;
    +
    +
    +int
    +mandocdb(int argc, char *argv[])
    +{
    +	struct manconf	  conf;
    +	struct mparse	 *mp;
    +	struct dba	 *dba;
    +	const char	 *path_arg, *progname;
    +	size_t		  j, sz;
    +	int		  ch, i;
    +
    +#if HAVE_PLEDGE
    +	if (pledge("stdio rpath wpath cpath", NULL) == -1) {
    +		warn("pledge");
    +		return (int)MANDOCLEVEL_SYSERR;
    +	}
    +#endif
    +
    +#if HAVE_SANDBOX_INIT
    +	if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) {
    +		warnx("sandbox_init");
    +		return (int)MANDOCLEVEL_SYSERR;
    +	}
    +#endif
    +
    +	memset(&conf, 0, sizeof(conf));
    +
    +	/*
    +	 * We accept a few different invocations.
    +	 * The CHECKOP macro makes sure that invocation styles don't
    +	 * clobber each other.
    +	 */
    +#define	CHECKOP(_op, _ch) do \
    +	if (OP_DEFAULT != (_op)) { \
    +		warnx("-%c: Conflicting option", (_ch)); \
    +		goto usage; \
    +	} while (/*CONSTCOND*/0)
    +
    +	path_arg = NULL;
    +	op = OP_DEFAULT;
    +
    +	while (-1 != (ch = getopt(argc, argv, "aC:Dd:npQT:tu:v")))
    +		switch (ch) {
    +		case 'a':
    +			use_all = 1;
    +			break;
    +		case 'C':
    +			CHECKOP(op, ch);
    +			path_arg = optarg;
    +			op = OP_CONFFILE;
    +			break;
    +		case 'D':
    +			debug++;
    +			break;
    +		case 'd':
    +			CHECKOP(op, ch);
    +			path_arg = optarg;
    +			op = OP_UPDATE;
    +			break;
    +		case 'n':
    +			nodb = 1;
    +			break;
    +		case 'p':
    +			warnings = 1;
    +			break;
    +		case 'Q':
    +			mparse_options |= MPARSE_QUICK;
    +			break;
    +		case 'T':
    +			if (strcmp(optarg, "utf8")) {
    +				warnx("-T%s: Unsupported output format",
    +				    optarg);
    +				goto usage;
    +			}
    +			write_utf8 = 1;
    +			break;
    +		case 't':
    +			CHECKOP(op, ch);
    +			dup2(STDOUT_FILENO, STDERR_FILENO);
    +			op = OP_TEST;
    +			nodb = warnings = 1;
    +			break;
    +		case 'u':
    +			CHECKOP(op, ch);
    +			path_arg = optarg;
    +			op = OP_DELETE;
    +			break;
    +		case 'v':
    +			/* Compatibility with espie@'s makewhatis. */
    +			break;
    +		default:
    +			goto usage;
    +		}
    +
    +	argc -= optind;
    +	argv += optind;
    +
    +#if HAVE_PLEDGE
    +	if (nodb) {
    +		if (pledge("stdio rpath", NULL) == -1) {
    +			warn("pledge");
    +			return (int)MANDOCLEVEL_SYSERR;
    +		}
    +	}
    +#endif
    +
    +	if (OP_CONFFILE == op && argc > 0) {
    +		warnx("-C: Too many arguments");
    +		goto usage;
    +	}
    +
    +	exitcode = (int)MANDOCLEVEL_OK;
    +	mchars_alloc();
    +	mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL,
    +	    MANDOC_OS_OTHER, NULL);
    +	mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
    +	mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
    +
    +	if (OP_UPDATE == op || OP_DELETE == op || OP_TEST == op) {
    +
    +		/*
    +		 * Most of these deal with a specific directory.
    +		 * Jump into that directory first.
    +		 */
    +		if (OP_TEST != op && 0 == set_basedir(path_arg, 1))
    +			goto out;
    +
    +		dba = nodb ? dba_new(128) : dba_read(MANDOC_DB);
    +		if (dba != NULL) {
    +			/*
    +			 * The existing database is usable.  Process
    +			 * all files specified on the command-line.
    +			 */
    +			use_all = 1;
    +			for (i = 0; i < argc; i++)
    +				filescan(argv[i]);
    +			if (nodb == 0)
    +				dbprune(dba);
    +		} else {
    +			/* Database missing or corrupt. */
    +			if (op != OP_UPDATE || errno != ENOENT)
    +				say(MANDOC_DB, "%s: Automatically recreating"
    +				    " from scratch", strerror(errno));
    +			exitcode = (int)MANDOCLEVEL_OK;
    +			op = OP_DEFAULT;
    +			if (0 == treescan())
    +				goto out;
    +			dba = dba_new(128);
    +		}
    +		if (OP_DELETE != op)
    +			mpages_merge(dba, mp);
    +		if (nodb == 0)
    +			dbwrite(dba);
    +		dba_free(dba);
    +	} else {
    +		/*
    +		 * If we have arguments, use them as our manpaths.
    +		 * If we don't, use man.conf(5).
    +		 */
    +		if (argc > 0) {
    +			conf.manpath.paths = mandoc_reallocarray(NULL,
    +			    argc, sizeof(char *));
    +			conf.manpath.sz = (size_t)argc;
    +			for (i = 0; i < argc; i++)
    +				conf.manpath.paths[i] = mandoc_strdup(argv[i]);
    +		} else
    +			manconf_parse(&conf, path_arg, NULL, NULL);
    +
    +		if (conf.manpath.sz == 0) {
    +			exitcode = (int)MANDOCLEVEL_BADARG;
    +			say("", "Empty manpath");
    +		}
    +
    +		/*
    +		 * First scan the tree rooted at a base directory, then
    +		 * build a new database and finally move it into place.
    +		 * Ignore zero-length directories and strip trailing
    +		 * slashes.
    +		 */
    +		for (j = 0; j < conf.manpath.sz; j++) {
    +			sz = strlen(conf.manpath.paths[j]);
    +			if (sz && conf.manpath.paths[j][sz - 1] == '/')
    +				conf.manpath.paths[j][--sz] = '\0';
    +			if (0 == sz)
    +				continue;
    +
    +			if (j) {
    +				mandoc_ohash_init(&mpages, 6,
    +				    offsetof(struct mpage, inodev));
    +				mandoc_ohash_init(&mlinks, 6,
    +				    offsetof(struct mlink, file));
    +			}
    +
    +			if ( ! set_basedir(conf.manpath.paths[j], argc > 0))
    +				continue;
    +			if (0 == treescan())
    +				continue;
    +			dba = dba_new(128);
    +			mpages_merge(dba, mp);
    +			if (nodb == 0)
    +				dbwrite(dba);
    +			dba_free(dba);
    +
    +			if (j + 1 < conf.manpath.sz) {
    +				mpages_free();
    +				ohash_delete(&mpages);
    +				ohash_delete(&mlinks);
    +			}
    +		}
    +	}
    +out:
    +	manconf_free(&conf);
    +	mparse_free(mp);
    +	mchars_free();
    +	mpages_free();
    +	ohash_delete(&mpages);
    +	ohash_delete(&mlinks);
    +	return exitcode;
    +usage:
    +	progname = getprogname();
    +	fprintf(stderr, "usage: %s [-aDnpQ] [-C file] [-Tutf8]\n"
    +			"       %s [-aDnpQ] [-Tutf8] dir ...\n"
    +			"       %s [-DnpQ] [-Tutf8] -d dir [file ...]\n"
    +			"       %s [-Dnp] -u dir [file ...]\n"
    +			"       %s [-Q] -t file ...\n",
    +		        progname, progname, progname, progname, progname);
    +
    +	return (int)MANDOCLEVEL_BADARG;
    +}
    +
    +/*
    + * To get a singly linked list in alpha order while inserting entries
    + * at the beginning, process directory entries in reverse alpha order.
    + */
    +static int
    +#if HAVE_FTS_COMPARE_CONST
    +fts_compare(const FTSENT *const *a, const FTSENT *const *b)
    +#else
    +fts_compare(const FTSENT **a, const FTSENT **b)
    +#endif
    +{
    +	return -strcmp((*a)->fts_name, (*b)->fts_name);
    +}
    +
    +/*
    + * Scan a directory tree rooted at "basedir" for manpages.
    + * We use fts(), scanning directory parts along the way for clues to our
    + * section and architecture.
    + *
    + * If use_all has been specified, grok all files.
    + * If not, sanitise paths to the following:
    + *
    + *   [./]man*[/<arch>]/<name>.<section>
    + *   or
    + *   [./]cat<section>[/<arch>]/<name>.0
    + *
    + * TODO: accommodate for multi-language directories.
    + */
    +static int
    +treescan(void)
    +{
    +	char		 buf[PATH_MAX];
    +	FTS		*f;
    +	FTSENT		*ff;
    +	struct mlink	*mlink;
    +	int		 gzip;
    +	enum form	 dform;
    +	char		*dsec, *arch, *fsec, *cp;
    +	const char	*path;
    +	const char	*argv[2];
    +
    +	argv[0] = ".";
    +	argv[1] = NULL;
    +
    +	f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR,
    +	    fts_compare);
    +	if (f == NULL) {
    +		exitcode = (int)MANDOCLEVEL_SYSERR;
    +		say("", "&fts_open");
    +		return 0;
    +	}
    +
    +	dsec = arch = NULL;
    +	dform = FORM_NONE;
    +
    +	while ((ff = fts_read(f)) != NULL) {
    +		path = ff->fts_path + 2;
    +		switch (ff->fts_info) {
    +
    +		/*
    +		 * Symbolic links require various sanity checks,
    +		 * then get handled just like regular files.
    +		 */
    +		case FTS_SL:
    +			if (realpath(path, buf) == NULL) {
    +				if (warnings)
    +					say(path, "&realpath");
    +				continue;
    +			}
    +			if (strstr(buf, basedir) != buf
    +#ifdef HOMEBREWDIR
    +			    && strstr(buf, HOMEBREWDIR) != buf
    +#endif
    +			) {
    +				if (warnings) say("",
    +				    "%s: outside base directory", buf);
    +				continue;
    +			}
    +			/* Use logical inode to avoid mpages dupe. */
    +			if (stat(path, ff->fts_statp) == -1) {
    +				if (warnings)
    +					say(path, "&stat");
    +				continue;
    +			}
    +			/* FALLTHROUGH */
    +
    +		/*
    +		 * If we're a regular file, add an mlink by using the
    +		 * stored directory data and handling the filename.
    +		 */
    +		case FTS_F:
    +			if ( ! strcmp(path, MANDOC_DB))
    +				continue;
    +			if ( ! use_all && ff->fts_level < 2) {
    +				if (warnings)
    +					say(path, "Extraneous file");
    +				continue;
    +			}
    +			gzip = 0;
    +			fsec = NULL;
    +			while (fsec == NULL) {
    +				fsec = strrchr(ff->fts_name, '.');
    +				if (fsec == NULL || strcmp(fsec+1, "gz"))
    +					break;
    +				gzip = 1;
    +				*fsec = '\0';
    +				fsec = NULL;
    +			}
    +			if (fsec == NULL) {
    +				if ( ! use_all) {
    +					if (warnings)
    +						say(path,
    +						    "No filename suffix");
    +					continue;
    +				}
    +			} else if ( ! strcmp(++fsec, "html")) {
    +				if (warnings)
    +					say(path, "Skip html");
    +				continue;
    +			} else if ( ! strcmp(fsec, "ps")) {
    +				if (warnings)
    +					say(path, "Skip ps");
    +				continue;
    +			} else if ( ! strcmp(fsec, "pdf")) {
    +				if (warnings)
    +					say(path, "Skip pdf");
    +				continue;
    +			} else if ( ! use_all &&
    +			    ((dform == FORM_SRC &&
    +			      strncmp(fsec, dsec, strlen(dsec))) ||
    +			     (dform == FORM_CAT && strcmp(fsec, "0")))) {
    +				if (warnings)
    +					say(path, "Wrong filename suffix");
    +				continue;
    +			} else
    +				fsec[-1] = '\0';
    +
    +			mlink = mandoc_calloc(1, sizeof(struct mlink));
    +			if (strlcpy(mlink->file, path,
    +			    sizeof(mlink->file)) >=
    +			    sizeof(mlink->file)) {
    +				say(path, "Filename too long");
    +				free(mlink);
    +				continue;
    +			}
    +			mlink->dform = dform;
    +			mlink->dsec = dsec;
    +			mlink->arch = arch;
    +			mlink->name = ff->fts_name;
    +			mlink->fsec = fsec;
    +			mlink->gzip = gzip;
    +			mlink_add(mlink, ff->fts_statp);
    +			continue;
    +
    +		case FTS_D:
    +		case FTS_DP:
    +			break;
    +
    +		default:
    +			if (warnings)
    +				say(path, "Not a regular file");
    +			continue;
    +		}
    +
    +		switch (ff->fts_level) {
    +		case 0:
    +			/* Ignore the root directory. */
    +			break;
    +		case 1:
    +			/*
    +			 * This might contain manX/ or catX/.
    +			 * Try to infer this from the name.
    +			 * If we're not in use_all, enforce it.
    +			 */
    +			cp = ff->fts_name;
    +			if (ff->fts_info == FTS_DP) {
    +				dform = FORM_NONE;
    +				dsec = NULL;
    +				break;
    +			}
    +
    +			if ( ! strncmp(cp, "man", 3)) {
    +				dform = FORM_SRC;
    +				dsec = cp + 3;
    +			} else if ( ! strncmp(cp, "cat", 3)) {
    +				dform = FORM_CAT;
    +				dsec = cp + 3;
    +			} else {
    +				dform = FORM_NONE;
    +				dsec = NULL;
    +			}
    +
    +			if (dsec != NULL || use_all)
    +				break;
    +
    +			if (warnings)
    +				say(path, "Unknown directory part");
    +			fts_set(f, ff, FTS_SKIP);
    +			break;
    +		case 2:
    +			/*
    +			 * Possibly our architecture.
    +			 * If we're descending, keep tabs on it.
    +			 */
    +			if (ff->fts_info != FTS_DP && dsec != NULL)
    +				arch = ff->fts_name;
    +			else
    +				arch = NULL;
    +			break;
    +		default:
    +			if (ff->fts_info == FTS_DP || use_all)
    +				break;
    +			if (warnings)
    +				say(path, "Extraneous directory part");
    +			fts_set(f, ff, FTS_SKIP);
    +			break;
    +		}
    +	}
    +
    +	fts_close(f);
    +	return 1;
    +}
    +
    +/*
    + * Add a file to the mlinks table.
    + * Do not verify that it's a "valid" looking manpage (we'll do that
    + * later).
    + *
    + * Try to infer the manual section, architecture, and page name from the
    + * path, assuming it looks like
    + *
    + *   [./]man*[/<arch>]/<name>.<section>
    + *   or
    + *   [./]cat<section>[/<arch>]/<name>.0
    + *
    + * See treescan() for the fts(3) version of this.
    + */
    +static void
    +filescan(const char *file)
    +{
    +	char		 buf[PATH_MAX];
    +	struct stat	 st;
    +	struct mlink	*mlink;
    +	char		*p, *start;
    +
    +	assert(use_all);
    +
    +	if (0 == strncmp(file, "./", 2))
    +		file += 2;
    +
    +	/*
    +	 * We have to do lstat(2) before realpath(3) loses
    +	 * the information whether this is a symbolic link.
    +	 * We need to know that because for symbolic links,
    +	 * we want to use the orginal file name, while for
    +	 * regular files, we want to use the real path.
    +	 */
    +	if (-1 == lstat(file, &st)) {
    +		exitcode = (int)MANDOCLEVEL_BADARG;
    +		say(file, "&lstat");
    +		return;
    +	} else if (0 == ((S_IFREG | S_IFLNK) & st.st_mode)) {
    +		exitcode = (int)MANDOCLEVEL_BADARG;
    +		say(file, "Not a regular file");
    +		return;
    +	}
    +
    +	/*
    +	 * We have to resolve the file name to the real path
    +	 * in any case for the base directory check.
    +	 */
    +	if (NULL == realpath(file, buf)) {
    +		exitcode = (int)MANDOCLEVEL_BADARG;
    +		say(file, "&realpath");
    +		return;
    +	}
    +
    +	if (OP_TEST == op)
    +		start = buf;
    +	else if (strstr(buf, basedir) == buf)
    +		start = buf + strlen(basedir);
    +#ifdef HOMEBREWDIR
    +	else if (strstr(buf, HOMEBREWDIR) == buf)
    +		start = buf;
    +#endif
    +	else {
    +		exitcode = (int)MANDOCLEVEL_BADARG;
    +		say("", "%s: outside base directory", buf);
    +		return;
    +	}
    +
    +	/*
    +	 * Now we are sure the file is inside our tree.
    +	 * If it is a symbolic link, ignore the real path
    +	 * and use the original name.
    +	 * This implies passing stuff like "cat1/../man1/foo.1"
    +	 * on the command line won't work.  So don't do that.
    +	 * Note the stat(2) can still fail if the link target
    +	 * doesn't exist.
    +	 */
    +	if (S_IFLNK & st.st_mode) {
    +		if (-1 == stat(buf, &st)) {
    +			exitcode = (int)MANDOCLEVEL_BADARG;
    +			say(file, "&stat");
    +			return;
    +		}
    +		if (strlcpy(buf, file, sizeof(buf)) >= sizeof(buf)) {
    +			say(file, "Filename too long");
    +			return;
    +		}
    +		start = buf;
    +		if (OP_TEST != op && strstr(buf, basedir) == buf)
    +			start += strlen(basedir);
    +	}
    +
    +	mlink = mandoc_calloc(1, sizeof(struct mlink));
    +	mlink->dform = FORM_NONE;
    +	if (strlcpy(mlink->file, start, sizeof(mlink->file)) >=
    +	    sizeof(mlink->file)) {
    +		say(start, "Filename too long");
    +		free(mlink);
    +		return;
    +	}
    +
    +	/*
    +	 * In test mode or when the original name is absolute
    +	 * but outside our tree, guess the base directory.
    +	 */
    +
    +	if (op == OP_TEST || (start == buf && *start == '/')) {
    +		if (strncmp(buf, "man/", 4) == 0)
    +			start = buf + 4;
    +		else if ((start = strstr(buf, "/man/")) != NULL)
    +			start += 5;
    +		else
    +			start = buf;
    +	}
    +
    +	/*
    +	 * First try to guess our directory structure.
    +	 * If we find a separator, try to look for man* or cat*.
    +	 * If we find one of these and what's underneath is a directory,
    +	 * assume it's an architecture.
    +	 */
    +	if (NULL != (p = strchr(start, '/'))) {
    +		*p++ = '\0';
    +		if (0 == strncmp(start, "man", 3)) {
    +			mlink->dform = FORM_SRC;
    +			mlink->dsec = start + 3;
    +		} else if (0 == strncmp(start, "cat", 3)) {
    +			mlink->dform = FORM_CAT;
    +			mlink->dsec = start + 3;
    +		}
    +
    +		start = p;
    +		if (NULL != mlink->dsec && NULL != (p = strchr(start, '/'))) {
    +			*p++ = '\0';
    +			mlink->arch = start;
    +			start = p;
    +		}
    +	}
    +
    +	/*
    +	 * Now check the file suffix.
    +	 * Suffix of `.0' indicates a catpage, `.1-9' is a manpage.
    +	 */
    +	p = strrchr(start, '\0');
    +	while (p-- > start && '/' != *p && '.' != *p)
    +		/* Loop. */ ;
    +
    +	if ('.' == *p) {
    +		*p++ = '\0';
    +		mlink->fsec = p;
    +	}
    +
    +	/*
    +	 * Now try to parse the name.
    +	 * Use the filename portion of the path.
    +	 */
    +	mlink->name = start;
    +	if (NULL != (p = strrchr(start, '/'))) {
    +		mlink->name = p + 1;
    +		*p = '\0';
    +	}
    +	mlink_add(mlink, &st);
    +}
    +
    +static void
    +mlink_add(struct mlink *mlink, const struct stat *st)
    +{
    +	struct inodev	 inodev;
    +	struct mpage	*mpage;
    +	unsigned int	 slot;
    +
    +	assert(NULL != mlink->file);
    +
    +	mlink->dsec = mandoc_strdup(mlink->dsec ? mlink->dsec : "");
    +	mlink->arch = mandoc_strdup(mlink->arch ? mlink->arch : "");
    +	mlink->name = mandoc_strdup(mlink->name ? mlink->name : "");
    +	mlink->fsec = mandoc_strdup(mlink->fsec ? mlink->fsec : "");
    +
    +	if ('0' == *mlink->fsec) {
    +		free(mlink->fsec);
    +		mlink->fsec = mandoc_strdup(mlink->dsec);
    +		mlink->fform = FORM_CAT;
    +	} else if ('1' <= *mlink->fsec && '9' >= *mlink->fsec)
    +		mlink->fform = FORM_SRC;
    +	else
    +		mlink->fform = FORM_NONE;
    +
    +	slot = ohash_qlookup(&mlinks, mlink->file);
    +	assert(NULL == ohash_find(&mlinks, slot));
    +	ohash_insert(&mlinks, slot, mlink);
    +
    +	memset(&inodev, 0, sizeof(inodev));  /* Clear padding. */
    +	inodev.st_ino = st->st_ino;
    +	inodev.st_dev = st->st_dev;
    +	slot = ohash_lookup_memory(&mpages, (char *)&inodev,
    +	    sizeof(struct inodev), inodev.st_ino);
    +	mpage = ohash_find(&mpages, slot);
    +	if (NULL == mpage) {
    +		mpage = mandoc_calloc(1, sizeof(struct mpage));
    +		mpage->inodev.st_ino = inodev.st_ino;
    +		mpage->inodev.st_dev = inodev.st_dev;
    +		mpage->form = FORM_NONE;
    +		mpage->next = mpage_head;
    +		mpage_head = mpage;
    +		ohash_insert(&mpages, slot, mpage);
    +	} else
    +		mlink->next = mpage->mlinks;
    +	mpage->mlinks = mlink;
    +	mlink->mpage = mpage;
    +}
    +
    +static void
    +mlink_free(struct mlink *mlink)
    +{
    +
    +	free(mlink->dsec);
    +	free(mlink->arch);
    +	free(mlink->name);
    +	free(mlink->fsec);
    +	free(mlink);
    +}
    +
    +static void
    +mpages_free(void)
    +{
    +	struct mpage	*mpage;
    +	struct mlink	*mlink;
    +
    +	while ((mpage = mpage_head) != NULL) {
    +		while ((mlink = mpage->mlinks) != NULL) {
    +			mpage->mlinks = mlink->next;
    +			mlink_free(mlink);
    +		}
    +		mpage_head = mpage->next;
    +		free(mpage->sec);
    +		free(mpage->arch);
    +		free(mpage->title);
    +		free(mpage->desc);
    +		free(mpage);
    +	}
    +}
    +
    +/*
    + * For each mlink to the mpage, check whether the path looks like
    + * it is formatted, and if it does, check whether a source manual
    + * exists by the same name, ignoring the suffix.
    + * If both conditions hold, drop the mlink.
    + */
    +static void
    +mlinks_undupe(struct mpage *mpage)
    +{
    +	char		  buf[PATH_MAX];
    +	struct mlink	**prev;
    +	struct mlink	 *mlink;
    +	char		 *bufp;
    +
    +	mpage->form = FORM_CAT;
    +	prev = &mpage->mlinks;
    +	while (NULL != (mlink = *prev)) {
    +		if (FORM_CAT != mlink->dform) {
    +			mpage->form = FORM_NONE;
    +			goto nextlink;
    +		}
    +		(void)strlcpy(buf, mlink->file, sizeof(buf));
    +		bufp = strstr(buf, "cat");
    +		assert(NULL != bufp);
    +		memcpy(bufp, "man", 3);
    +		if (NULL != (bufp = strrchr(buf, '.')))
    +			*++bufp = '\0';
    +		(void)strlcat(buf, mlink->dsec, sizeof(buf));
    +		if (NULL == ohash_find(&mlinks,
    +		    ohash_qlookup(&mlinks, buf)))
    +			goto nextlink;
    +		if (warnings)
    +			say(mlink->file, "Man source exists: %s", buf);
    +		if (use_all)
    +			goto nextlink;
    +		*prev = mlink->next;
    +		mlink_free(mlink);
    +		continue;
    +nextlink:
    +		prev = &(*prev)->next;
    +	}
    +}
    +
    +static void
    +mlink_check(struct mpage *mpage, struct mlink *mlink)
    +{
    +	struct str	*str;
    +	unsigned int	 slot;
    +
    +	/*
    +	 * Check whether the manual section given in a file
    +	 * agrees with the directory where the file is located.
    +	 * Some manuals have suffixes like (3p) on their
    +	 * section number either inside the file or in the
    +	 * directory name, some are linked into more than one
    +	 * section, like encrypt(1) = makekey(8).
    +	 */
    +
    +	if (FORM_SRC == mpage->form &&
    +	    strcasecmp(mpage->sec, mlink->dsec))
    +		say(mlink->file, "Section \"%s\" manual in %s directory",
    +		    mpage->sec, mlink->dsec);
    +
    +	/*
    +	 * Manual page directories exist for each kernel
    +	 * architecture as returned by machine(1).
    +	 * However, many manuals only depend on the
    +	 * application architecture as returned by arch(1).
    +	 * For example, some (2/ARM) manuals are shared
    +	 * across the "armish" and "zaurus" kernel
    +	 * architectures.
    +	 * A few manuals are even shared across completely
    +	 * different architectures, for example fdformat(1)
    +	 * on amd64, i386, and sparc64.
    +	 */
    +
    +	if (strcasecmp(mpage->arch, mlink->arch))
    +		say(mlink->file, "Architecture \"%s\" manual in "
    +		    "\"%s\" directory", mpage->arch, mlink->arch);
    +
    +	/*
    +	 * XXX
    +	 * parse_cat() doesn't set NAME_TITLE yet.
    +	 */
    +
    +	if (FORM_CAT == mpage->form)
    +		return;
    +
    +	/*
    +	 * Check whether this mlink
    +	 * appears as a name in the NAME section.
    +	 */
    +
    +	slot = ohash_qlookup(&names, mlink->name);
    +	str = ohash_find(&names, slot);
    +	assert(NULL != str);
    +	if ( ! (NAME_TITLE & str->mask))
    +		say(mlink->file, "Name missing in NAME section");
    +}
    +
    +/*
    + * Run through the files in the global vector "mpages"
    + * and add them to the database specified in "basedir".
    + *
    + * This handles the parsing scheme itself, using the cues of directory
    + * and filename to determine whether the file is parsable or not.
    + */
    +static void
    +mpages_merge(struct dba *dba, struct mparse *mp)
    +{
    +	struct mpage		*mpage, *mpage_dest;
    +	struct mlink		*mlink, *mlink_dest;
    +	struct roff_man		*man;
    +	char			*sodest;
    +	char			*cp;
    +	int			 fd;
    +
    +	for (mpage = mpage_head; mpage != NULL; mpage = mpage->next) {
    +		mlinks_undupe(mpage);
    +		if ((mlink = mpage->mlinks) == NULL)
    +			continue;
    +
    +		name_mask = NAME_MASK;
    +		mandoc_ohash_init(&names, 4, offsetof(struct str, key));
    +		mandoc_ohash_init(&strings, 6, offsetof(struct str, key));
    +		mparse_reset(mp);
    +		man = NULL;
    +		sodest = NULL;
    +
    +		if ((fd = mparse_open(mp, mlink->file)) == -1) {
    +			say(mlink->file, "&open");
    +			goto nextpage;
    +		}
    +
    +		/*
    +		 * Interpret the file as mdoc(7) or man(7) source
    +		 * code, unless it is known to be formatted.
    +		 */
    +		if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) {
    +			mparse_readfd(mp, fd, mlink->file);
    +			close(fd);
    +			fd = -1;
    +			mparse_result(mp, &man, &sodest);
    +		}
    +
    +		if (sodest != NULL) {
    +			mlink_dest = ohash_find(&mlinks,
    +			    ohash_qlookup(&mlinks, sodest));
    +			if (mlink_dest == NULL) {
    +				mandoc_asprintf(&cp, "%s.gz", sodest);
    +				mlink_dest = ohash_find(&mlinks,
    +				    ohash_qlookup(&mlinks, cp));
    +				free(cp);
    +			}
    +			if (mlink_dest != NULL) {
    +
    +				/* The .so target exists. */
    +
    +				mpage_dest = mlink_dest->mpage;
    +				while (1) {
    +					mlink->mpage = mpage_dest;
    +
    +					/*
    +					 * If the target was already
    +					 * processed, add the links
    +					 * to the database now.
    +					 * Otherwise, this will
    +					 * happen when we come
    +					 * to the target.
    +					 */
    +
    +					if (mpage_dest->dba != NULL)
    +						dbadd_mlink(mlink);
    +
    +					if (mlink->next == NULL)
    +						break;
    +					mlink = mlink->next;
    +				}
    +
    +				/* Move all links to the target. */
    +
    +				mlink->next = mlink_dest->next;
    +				mlink_dest->next = mpage->mlinks;
    +				mpage->mlinks = NULL;
    +			}
    +			goto nextpage;
    +		} else if (man != NULL && man->macroset == MACROSET_MDOC) {
    +			mdoc_validate(man);
    +			mpage->form = FORM_SRC;
    +			mpage->sec = man->meta.msec;
    +			mpage->sec = mandoc_strdup(
    +			    mpage->sec == NULL ? "" : mpage->sec);
    +			mpage->arch = man->meta.arch;
    +			mpage->arch = mandoc_strdup(
    +			    mpage->arch == NULL ? "" : mpage->arch);
    +			mpage->title = mandoc_strdup(man->meta.title);
    +		} else if (man != NULL && man->macroset == MACROSET_MAN) {
    +			man_validate(man);
    +			if (*man->meta.msec != '\0' ||
    +			    *man->meta.title != '\0') {
    +				mpage->form = FORM_SRC;
    +				mpage->sec = mandoc_strdup(man->meta.msec);
    +				mpage->arch = mandoc_strdup(mlink->arch);
    +				mpage->title = mandoc_strdup(man->meta.title);
    +			} else
    +				man = NULL;
    +		}
    +
    +		assert(mpage->desc == NULL);
    +		if (man == NULL) {
    +			mpage->form = FORM_CAT;
    +			mpage->sec = mandoc_strdup(mlink->dsec);
    +			mpage->arch = mandoc_strdup(mlink->arch);
    +			mpage->title = mandoc_strdup(mlink->name);
    +			parse_cat(mpage, fd);
    +		} else if (man->macroset == MACROSET_MDOC)
    +			parse_mdoc(mpage, &man->meta, man->first);
    +		else
    +			parse_man(mpage, &man->meta, man->first);
    +		if (mpage->desc == NULL) {
    +			mpage->desc = mandoc_strdup(mlink->name);
    +			if (warnings)
    +				say(mlink->file, "No one-line description, "
    +				    "using filename \"%s\"", mlink->name);
    +		}
    +
    +		for (mlink = mpage->mlinks;
    +		     mlink != NULL;
    +		     mlink = mlink->next) {
    +			putkey(mpage, mlink->name, NAME_FILE);
    +			if (warnings && !use_all)
    +				mlink_check(mpage, mlink);
    +		}
    +
    +		dbadd(dba, mpage);
    +
    +nextpage:
    +		ohash_delete(&strings);
    +		ohash_delete(&names);
    +	}
    +}
    +
    +static void
    +parse_cat(struct mpage *mpage, int fd)
    +{
    +	FILE		*stream;
    +	struct mlink	*mlink;
    +	char		*line, *p, *title, *sec;
    +	size_t		 linesz, plen, titlesz;
    +	ssize_t		 len;
    +	int		 offs;
    +
    +	mlink = mpage->mlinks;
    +	stream = fd == -1 ? fopen(mlink->file, "r") : fdopen(fd, "r");
    +	if (stream == NULL) {
    +		if (fd != -1)
    +			close(fd);
    +		if (warnings)
    +			say(mlink->file, "&fopen");
    +		return;
    +	}
    +
    +	line = NULL;
    +	linesz = 0;
    +
    +	/* Parse the section number from the header line. */
    +
    +	while (getline(&line, &linesz, stream) != -1) {
    +		if (*line == '\n')
    +			continue;
    +		if ((sec = strchr(line, '(')) == NULL)
    +			break;
    +		if ((p = strchr(++sec, ')')) == NULL)
    +			break;
    +		free(mpage->sec);
    +		mpage->sec = mandoc_strndup(sec, p - sec);
    +		if (warnings && *mlink->dsec != '\0' &&
    +		    strcasecmp(mpage->sec, mlink->dsec))
    +			say(mlink->file,
    +			    "Section \"%s\" manual in %s directory",
    +			    mpage->sec, mlink->dsec);
    +		break;
    +	}
    +
    +	/* Skip to first blank line. */
    +
    +	while (line == NULL || *line != '\n')
    +		if (getline(&line, &linesz, stream) == -1)
    +			break;
    +
    +	/*
    +	 * Assume the first line that is not indented
    +	 * is the first section header.  Skip to it.
    +	 */
    +
    +	while (getline(&line, &linesz, stream) != -1)
    +		if (*line != '\n' && *line != ' ')
    +			break;
    +
    +	/*
    +	 * Read up until the next section into a buffer.
    +	 * Strip the leading and trailing newline from each read line,
    +	 * appending a trailing space.
    +	 * Ignore empty (whitespace-only) lines.
    +	 */
    +
    +	titlesz = 0;
    +	title = NULL;
    +
    +	while ((len = getline(&line, &linesz, stream)) != -1) {
    +		if (*line != ' ')
    +			break;
    +		offs = 0;
    +		while (isspace((unsigned char)line[offs]))
    +			offs++;
    +		if (line[offs] == '\0')
    +			continue;
    +		title = mandoc_realloc(title, titlesz + len - offs);
    +		memcpy(title + titlesz, line + offs, len - offs);
    +		titlesz += len - offs;
    +		title[titlesz - 1] = ' ';
    +	}
    +	free(line);
    +
    +	/*
    +	 * If no page content can be found, or the input line
    +	 * is already the next section header, or there is no
    +	 * trailing newline, reuse the page title as the page
    +	 * description.
    +	 */
    +
    +	if (NULL == title || '\0' == *title) {
    +		if (warnings)
    +			say(mlink->file, "Cannot find NAME section");
    +		fclose(stream);
    +		free(title);
    +		return;
    +	}
    +
    +	title[titlesz - 1] = '\0';
    +
    +	/*
    +	 * Skip to the first dash.
    +	 * Use the remaining line as the description (no more than 70
    +	 * bytes).
    +	 */
    +
    +	if (NULL != (p = strstr(title, "- "))) {
    +		for (p += 2; ' ' == *p || '\b' == *p; p++)
    +			/* Skip to next word. */ ;
    +	} else {
    +		if (warnings)
    +			say(mlink->file, "No dash in title line, "
    +			    "reusing \"%s\" as one-line description", title);
    +		p = title;
    +	}
    +
    +	plen = strlen(p);
    +
    +	/* Strip backspace-encoding from line. */
    +
    +	while (NULL != (line = memchr(p, '\b', plen))) {
    +		len = line - p;
    +		if (0 == len) {
    +			memmove(line, line + 1, plen--);
    +			continue;
    +		}
    +		memmove(line - 1, line + 1, plen - len);
    +		plen -= 2;
    +	}
    +
    +	/*
    +	 * Cut off excessive one-line descriptions.
    +	 * Bad pages are not worth better heuristics.
    +	 */
    +
    +	mpage->desc = mandoc_strndup(p, 150);
    +	fclose(stream);
    +	free(title);
    +}
    +
    +/*
    + * Put a type/word pair into the word database for this particular file.
    + */
    +static void
    +putkey(const struct mpage *mpage, char *value, uint64_t type)
    +{
    +	putkeys(mpage, value, strlen(value), type);
    +}
    +
    +/*
    + * Grok all nodes at or below a certain mdoc node into putkey().
    + */
    +static void
    +putmdockey(const struct mpage *mpage,
    +	const struct roff_node *n, uint64_t m, int taboo)
    +{
    +
    +	for ( ; NULL != n; n = n->next) {
    +		if (n->flags & taboo)
    +			continue;
    +		if (NULL != n->child)
    +			putmdockey(mpage, n->child, m, taboo);
    +		if (n->type == ROFFT_TEXT)
    +			putkey(mpage, n->string, m);
    +	}
    +}
    +
    +static void
    +parse_man(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +	const struct roff_node *head, *body;
    +	char		*start, *title;
    +	char		 byte;
    +	size_t		 sz;
    +
    +	if (n == NULL)
    +		return;
    +
    +	/*
    +	 * We're only searching for one thing: the first text child in
    +	 * the BODY of a NAME section.  Since we don't keep track of
    +	 * sections in -man, run some hoops to find out whether we're in
    +	 * the correct section or not.
    +	 */
    +
    +	if (n->type == ROFFT_BODY && n->tok == MAN_SH) {
    +		body = n;
    +		if ((head = body->parent->head) != NULL &&
    +		    (head = head->child) != NULL &&
    +		    head->next == NULL &&
    +		    head->type == ROFFT_TEXT &&
    +		    strcmp(head->string, "NAME") == 0 &&
    +		    body->child != NULL) {
    +
    +			/*
    +			 * Suck the entire NAME section into memory.
    +			 * Yes, we might run away.
    +			 * But too many manuals have big, spread-out
    +			 * NAME sections over many lines.
    +			 */
    +
    +			title = NULL;
    +			deroff(&title, body);
    +			if (NULL == title)
    +				return;
    +
    +			/*
    +			 * Go through a special heuristic dance here.
    +			 * Conventionally, one or more manual names are
    +			 * comma-specified prior to a whitespace, then a
    +			 * dash, then a description.  Try to puzzle out
    +			 * the name parts here.
    +			 */
    +
    +			start = title;
    +			for ( ;; ) {
    +				sz = strcspn(start, " ,");
    +				if ('\0' == start[sz])
    +					break;
    +
    +				byte = start[sz];
    +				start[sz] = '\0';
    +
    +				/*
    +				 * Assume a stray trailing comma in the
    +				 * name list if a name begins with a dash.
    +				 */
    +
    +				if ('-' == start[0] ||
    +				    ('\\' == start[0] && '-' == start[1]))
    +					break;
    +
    +				putkey(mpage, start, NAME_TITLE);
    +				if ( ! (mpage->name_head_done ||
    +				    strcasecmp(start, meta->title))) {
    +					putkey(mpage, start, NAME_HEAD);
    +					mpage->name_head_done = 1;
    +				}
    +
    +				if (' ' == byte) {
    +					start += sz + 1;
    +					break;
    +				}
    +
    +				assert(',' == byte);
    +				start += sz + 1;
    +				while (' ' == *start)
    +					start++;
    +			}
    +
    +			if (start == title) {
    +				putkey(mpage, start, NAME_TITLE);
    +				if ( ! (mpage->name_head_done ||
    +				    strcasecmp(start, meta->title))) {
    +					putkey(mpage, start, NAME_HEAD);
    +					mpage->name_head_done = 1;
    +				}
    +				free(title);
    +				return;
    +			}
    +
    +			while (isspace((unsigned char)*start))
    +				start++;
    +
    +			if (0 == strncmp(start, "-", 1))
    +				start += 1;
    +			else if (0 == strncmp(start, "\\-\\-", 4))
    +				start += 4;
    +			else if (0 == strncmp(start, "\\-", 2))
    +				start += 2;
    +			else if (0 == strncmp(start, "\\(en", 4))
    +				start += 4;
    +			else if (0 == strncmp(start, "\\(em", 4))
    +				start += 4;
    +
    +			while (' ' == *start)
    +				start++;
    +
    +			/*
    +			 * Cut off excessive one-line descriptions.
    +			 * Bad pages are not worth better heuristics.
    +			 */
    +
    +			mpage->desc = mandoc_strndup(start, 150);
    +			free(title);
    +			return;
    +		}
    +	}
    +
    +	for (n = n->child; n; n = n->next) {
    +		if (NULL != mpage->desc)
    +			break;
    +		parse_man(mpage, meta, n);
    +	}
    +}
    +
    +static void
    +parse_mdoc(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +
    +	for (n = n->child; n != NULL; n = n->next) {
    +		if (n->tok == TOKEN_NONE ||
    +		    n->tok < ROFF_MAX ||
    +		    n->flags & mdocs[n->tok].taboo)
    +			continue;
    +		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
    +		switch (n->type) {
    +		case ROFFT_ELEM:
    +		case ROFFT_BLOCK:
    +		case ROFFT_HEAD:
    +		case ROFFT_BODY:
    +		case ROFFT_TAIL:
    +			if (mdocs[n->tok].fp != NULL &&
    +			    (*mdocs[n->tok].fp)(mpage, meta, n) == 0)
    +				break;
    +			if (mdocs[n->tok].mask)
    +				putmdockey(mpage, n->child,
    +				    mdocs[n->tok].mask, mdocs[n->tok].taboo);
    +			break;
    +		default:
    +			continue;
    +		}
    +		if (NULL != n->child)
    +			parse_mdoc(mpage, meta, n);
    +	}
    +}
    +
    +static int
    +parse_mdoc_Fa(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +	uint64_t mask;
    +
    +	mask = TYPE_Fa;
    +	if (n->sec == SEC_SYNOPSIS)
    +		mask |= TYPE_Vt;
    +
    +	putmdockey(mpage, n->child, mask, 0);
    +	return 0;
    +}
    +
    +static int
    +parse_mdoc_Fd(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +	char		*start, *end;
    +	size_t		 sz;
    +
    +	if (SEC_SYNOPSIS != n->sec ||
    +	    NULL == (n = n->child) ||
    +	    n->type != ROFFT_TEXT)
    +		return 0;
    +
    +	/*
    +	 * Only consider those `Fd' macro fields that begin with an
    +	 * "inclusion" token (versus, e.g., #define).
    +	 */
    +
    +	if (strcmp("#include", n->string))
    +		return 0;
    +
    +	if ((n = n->next) == NULL || n->type != ROFFT_TEXT)
    +		return 0;
    +
    +	/*
    +	 * Strip away the enclosing angle brackets and make sure we're
    +	 * not zero-length.
    +	 */
    +
    +	start = n->string;
    +	if ('<' == *start || '"' == *start)
    +		start++;
    +
    +	if (0 == (sz = strlen(start)))
    +		return 0;
    +
    +	end = &start[(int)sz - 1];
    +	if ('>' == *end || '"' == *end)
    +		end--;
    +
    +	if (end > start)
    +		putkeys(mpage, start, end - start + 1, TYPE_In);
    +	return 0;
    +}
    +
    +static void
    +parse_mdoc_fname(struct mpage *mpage, const struct roff_node *n)
    +{
    +	char	*cp;
    +	size_t	 sz;
    +
    +	if (n->type != ROFFT_TEXT)
    +		return;
    +
    +	/* Skip function pointer punctuation. */
    +
    +	cp = n->string;
    +	while (*cp == '(' || *cp == '*')
    +		cp++;
    +	sz = strcspn(cp, "()");
    +
    +	putkeys(mpage, cp, sz, TYPE_Fn);
    +	if (n->sec == SEC_SYNOPSIS)
    +		putkeys(mpage, cp, sz, NAME_SYN);
    +}
    +
    +static int
    +parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +	uint64_t mask;
    +
    +	if (n->child == NULL)
    +		return 0;
    +
    +	parse_mdoc_fname(mpage, n->child);
    +
    +	n = n->child->next;
    +	if (n != NULL && n->type == ROFFT_TEXT) {
    +		mask = TYPE_Fa;
    +		if (n->sec == SEC_SYNOPSIS)
    +			mask |= TYPE_Vt;
    +		putmdockey(mpage, n, mask, 0);
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +parse_mdoc_Fo(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +
    +	if (n->type != ROFFT_HEAD)
    +		return 1;
    +
    +	if (n->child != NULL)
    +		parse_mdoc_fname(mpage, n->child);
    +
    +	return 0;
    +}
    +
    +static int
    +parse_mdoc_Va(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +	char *cp;
    +
    +	if (n->type != ROFFT_ELEM && n->type != ROFFT_BODY)
    +		return 0;
    +
    +	if (n->child != NULL &&
    +	    n->child->next == NULL &&
    +	    n->child->type == ROFFT_TEXT)
    +		return 1;
    +
    +	cp = NULL;
    +	deroff(&cp, n);
    +	if (cp != NULL) {
    +		putkey(mpage, cp, TYPE_Vt | (n->tok == MDOC_Va ||
    +		    n->type == ROFFT_BODY ? TYPE_Va : 0));
    +		free(cp);
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +parse_mdoc_Xr(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +	char	*cp;
    +
    +	if (NULL == (n = n->child))
    +		return 0;
    +
    +	if (NULL == n->next) {
    +		putkey(mpage, n->string, TYPE_Xr);
    +		return 0;
    +	}
    +
    +	mandoc_asprintf(&cp, "%s(%s)", n->string, n->next->string);
    +	putkey(mpage, cp, TYPE_Xr);
    +	free(cp);
    +	return 0;
    +}
    +
    +static int
    +parse_mdoc_Nd(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +
    +	if (n->type == ROFFT_BODY)
    +		deroff(&mpage->desc, n);
    +	return 0;
    +}
    +
    +static int
    +parse_mdoc_Nm(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +
    +	if (SEC_NAME == n->sec)
    +		putmdockey(mpage, n->child, NAME_TITLE, 0);
    +	else if (n->sec == SEC_SYNOPSIS && n->type == ROFFT_HEAD) {
    +		if (n->child == NULL)
    +			putkey(mpage, meta->name, NAME_SYN);
    +		else
    +			putmdockey(mpage, n->child, NAME_SYN, 0);
    +	}
    +	if ( ! (mpage->name_head_done ||
    +	    n->child == NULL || n->child->string == NULL ||
    +	    strcasecmp(n->child->string, meta->title))) {
    +		putkey(mpage, n->child->string, NAME_HEAD);
    +		mpage->name_head_done = 1;
    +	}
    +	return 0;
    +}
    +
    +static int
    +parse_mdoc_Sh(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +
    +	return n->sec == SEC_CUSTOM && n->type == ROFFT_HEAD;
    +}
    +
    +static int
    +parse_mdoc_head(struct mpage *mpage, const struct roff_meta *meta,
    +	const struct roff_node *n)
    +{
    +
    +	return n->type == ROFFT_HEAD;
    +}
    +
    +/*
    + * Add a string to the hash table for the current manual.
    + * Each string has a bitmask telling which macros it belongs to.
    + * When we finish the manual, we'll dump the table.
    + */
    +static void
    +putkeys(const struct mpage *mpage, char *cp, size_t sz, uint64_t v)
    +{
    +	struct ohash	*htab;
    +	struct str	*s;
    +	const char	*end;
    +	unsigned int	 slot;
    +	int		 i, mustfree;
    +
    +	if (0 == sz)
    +		return;
    +
    +	mustfree = render_string(&cp, &sz);
    +
    +	if (TYPE_Nm & v) {
    +		htab = &names;
    +		v &= name_mask;
    +		if (v & NAME_FIRST)
    +			name_mask &= ~NAME_FIRST;
    +		if (debug > 1)
    +			say(mpage->mlinks->file,
    +			    "Adding name %*s, bits=0x%llx", (int)sz, cp,
    +			    (unsigned long long)v);
    +	} else {
    +		htab = &strings;
    +		if (debug > 1)
    +		    for (i = 0; i < KEY_MAX; i++)
    +			if ((uint64_t)1 << i & v)
    +			    say(mpage->mlinks->file,
    +				"Adding key %s=%*s",
    +				mansearch_keynames[i], (int)sz, cp);
    +	}
    +
    +	end = cp + sz;
    +	slot = ohash_qlookupi(htab, cp, &end);
    +	s = ohash_find(htab, slot);
    +
    +	if (NULL != s && mpage == s->mpage) {
    +		s->mask |= v;
    +		return;
    +	} else if (NULL == s) {
    +		s = mandoc_calloc(1, sizeof(struct str) + sz + 1);
    +		memcpy(s->key, cp, sz);
    +		ohash_insert(htab, slot, s);
    +	}
    +	s->mpage = mpage;
    +	s->mask = v;
    +
    +	if (mustfree)
    +		free(cp);
    +}
    +
    +/*
    + * Take a Unicode codepoint and produce its UTF-8 encoding.
    + * This isn't the best way to do this, but it works.
    + * The magic numbers are from the UTF-8 packaging.
    + * They're not as scary as they seem: read the UTF-8 spec for details.
    + */
    +static size_t
    +utf8(unsigned int cp, char out[7])
    +{
    +	size_t		 rc;
    +
    +	rc = 0;
    +	if (cp <= 0x0000007F) {
    +		rc = 1;
    +		out[0] = (char)cp;
    +	} else if (cp <= 0x000007FF) {
    +		rc = 2;
    +		out[0] = (cp >> 6  & 31) | 192;
    +		out[1] = (cp       & 63) | 128;
    +	} else if (cp <= 0x0000FFFF) {
    +		rc = 3;
    +		out[0] = (cp >> 12 & 15) | 224;
    +		out[1] = (cp >> 6  & 63) | 128;
    +		out[2] = (cp       & 63) | 128;
    +	} else if (cp <= 0x001FFFFF) {
    +		rc = 4;
    +		out[0] = (cp >> 18 &  7) | 240;
    +		out[1] = (cp >> 12 & 63) | 128;
    +		out[2] = (cp >> 6  & 63) | 128;
    +		out[3] = (cp       & 63) | 128;
    +	} else if (cp <= 0x03FFFFFF) {
    +		rc = 5;
    +		out[0] = (cp >> 24 &  3) | 248;
    +		out[1] = (cp >> 18 & 63) | 128;
    +		out[2] = (cp >> 12 & 63) | 128;
    +		out[3] = (cp >> 6  & 63) | 128;
    +		out[4] = (cp       & 63) | 128;
    +	} else if (cp <= 0x7FFFFFFF) {
    +		rc = 6;
    +		out[0] = (cp >> 30 &  1) | 252;
    +		out[1] = (cp >> 24 & 63) | 128;
    +		out[2] = (cp >> 18 & 63) | 128;
    +		out[3] = (cp >> 12 & 63) | 128;
    +		out[4] = (cp >> 6  & 63) | 128;
    +		out[5] = (cp       & 63) | 128;
    +	} else
    +		return 0;
    +
    +	out[rc] = '\0';
    +	return rc;
    +}
    +
    +/*
    + * If the string contains escape sequences,
    + * replace it with an allocated rendering and return 1,
    + * such that the caller can free it after use.
    + * Otherwise, do nothing and return 0.
    + */
    +static int
    +render_string(char **public, size_t *psz)
    +{
    +	const char	*src, *scp, *addcp, *seq;
    +	char		*dst;
    +	size_t		 ssz, dsz, addsz;
    +	char		 utfbuf[7], res[6];
    +	int		 seqlen, unicode;
    +
    +	res[0] = '\\';
    +	res[1] = '\t';
    +	res[2] = ASCII_NBRSP;
    +	res[3] = ASCII_HYPH;
    +	res[4] = ASCII_BREAK;
    +	res[5] = '\0';
    +
    +	src = scp = *public;
    +	ssz = *psz;
    +	dst = NULL;
    +	dsz = 0;
    +
    +	while (scp < src + *psz) {
    +
    +		/* Leave normal characters unchanged. */
    +
    +		if (strchr(res, *scp) == NULL) {
    +			if (dst != NULL)
    +				dst[dsz++] = *scp;
    +			scp++;
    +			continue;
    +		}
    +
    +		/*
    +		 * Found something that requires replacing,
    +		 * make sure we have a destination buffer.
    +		 */
    +
    +		if (dst == NULL) {
    +			dst = mandoc_malloc(ssz + 1);
    +			dsz = scp - src;
    +			memcpy(dst, src, dsz);
    +		}
    +
    +		/* Handle single-char special characters. */
    +
    +		switch (*scp) {
    +		case '\\':
    +			break;
    +		case '\t':
    +		case ASCII_NBRSP:
    +			dst[dsz++] = ' ';
    +			scp++;
    +			continue;
    +		case ASCII_HYPH:
    +			dst[dsz++] = '-';
    +			/* FALLTHROUGH */
    +		case ASCII_BREAK:
    +			scp++;
    +			continue;
    +		default:
    +			abort();
    +		}
    +
    +		/*
    +		 * Found an escape sequence.
    +		 * Read past the slash, then parse it.
    +		 * Ignore everything except characters.
    +		 */
    +
    +		scp++;
    +		if (mandoc_escape(&scp, &seq, &seqlen) != ESCAPE_SPECIAL)
    +			continue;
    +
    +		/*
    +		 * Render the special character
    +		 * as either UTF-8 or ASCII.
    +		 */
    +
    +		if (write_utf8) {
    +			unicode = mchars_spec2cp(seq, seqlen);
    +			if (unicode <= 0)
    +				continue;
    +			addsz = utf8(unicode, utfbuf);
    +			if (addsz == 0)
    +				continue;
    +			addcp = utfbuf;
    +		} else {
    +			addcp = mchars_spec2str(seq, seqlen, &addsz);
    +			if (addcp == NULL)
    +				continue;
    +			if (*addcp == ASCII_NBRSP) {
    +				addcp = " ";
    +				addsz = 1;
    +			}
    +		}
    +
    +		/* Copy the rendered glyph into the stream. */
    +
    +		ssz += addsz;
    +		dst = mandoc_realloc(dst, ssz + 1);
    +		memcpy(dst + dsz, addcp, addsz);
    +		dsz += addsz;
    +	}
    +	if (dst != NULL) {
    +		*public = dst;
    +		*psz = dsz;
    +	}
    +
    +	/* Trim trailing whitespace and NUL-terminate. */
    +
    +	while (*psz > 0 && (*public)[*psz - 1] == ' ')
    +		--*psz;
    +	if (dst != NULL) {
    +		(*public)[*psz] = '\0';
    +		return 1;
    +	} else
    +		return 0;
    +}
    +
    +static void
    +dbadd_mlink(const struct mlink *mlink)
    +{
    +	dba_page_alias(mlink->mpage->dba, mlink->name, NAME_FILE);
    +	dba_page_add(mlink->mpage->dba, DBP_SECT, mlink->dsec);
    +	dba_page_add(mlink->mpage->dba, DBP_SECT, mlink->fsec);
    +	dba_page_add(mlink->mpage->dba, DBP_ARCH, mlink->arch);
    +	dba_page_add(mlink->mpage->dba, DBP_FILE, mlink->file);
    +}
    +
    +/*
    + * Flush the current page's terms (and their bits) into the database.
    + * Also, handle escape sequences at the last possible moment.
    + */
    +static void
    +dbadd(struct dba *dba, struct mpage *mpage)
    +{
    +	struct mlink	*mlink;
    +	struct str	*key;
    +	char		*cp;
    +	uint64_t	 mask;
    +	size_t		 i;
    +	unsigned int	 slot;
    +	int		 mustfree;
    +
    +	mlink = mpage->mlinks;
    +
    +	if (nodb) {
    +		for (key = ohash_first(&names, &slot); NULL != key;
    +		     key = ohash_next(&names, &slot))
    +			free(key);
    +		for (key = ohash_first(&strings, &slot); NULL != key;
    +		     key = ohash_next(&strings, &slot))
    +			free(key);
    +		if (0 == debug)
    +			return;
    +		while (NULL != mlink) {
    +			fputs(mlink->name, stdout);
    +			if (NULL == mlink->next ||
    +			    strcmp(mlink->dsec, mlink->next->dsec) ||
    +			    strcmp(mlink->fsec, mlink->next->fsec) ||
    +			    strcmp(mlink->arch, mlink->next->arch)) {
    +				putchar('(');
    +				if ('\0' == *mlink->dsec)
    +					fputs(mlink->fsec, stdout);
    +				else
    +					fputs(mlink->dsec, stdout);
    +				if ('\0' != *mlink->arch)
    +					printf("/%s", mlink->arch);
    +				putchar(')');
    +			}
    +			mlink = mlink->next;
    +			if (NULL != mlink)
    +				fputs(", ", stdout);
    +		}
    +		printf(" - %s\n", mpage->desc);
    +		return;
    +	}
    +
    +	if (debug)
    +		say(mlink->file, "Adding to database");
    +
    +	cp = mpage->desc;
    +	i = strlen(cp);
    +	mustfree = render_string(&cp, &i);
    +	mpage->dba = dba_page_new(dba->pages,
    +	    *mpage->arch == '\0' ? mlink->arch : mpage->arch,
    +	    cp, mlink->file, mpage->form);
    +	if (mustfree)
    +		free(cp);
    +	dba_page_add(mpage->dba, DBP_SECT, mpage->sec);
    +
    +	while (mlink != NULL) {
    +		dbadd_mlink(mlink);
    +		mlink = mlink->next;
    +	}
    +
    +	for (key = ohash_first(&names, &slot); NULL != key;
    +	     key = ohash_next(&names, &slot)) {
    +		assert(key->mpage == mpage);
    +		dba_page_alias(mpage->dba, key->key, key->mask);
    +		free(key);
    +	}
    +	for (key = ohash_first(&strings, &slot); NULL != key;
    +	     key = ohash_next(&strings, &slot)) {
    +		assert(key->mpage == mpage);
    +		i = 0;
    +		for (mask = TYPE_Xr; mask <= TYPE_Lb; mask *= 2) {
    +			if (key->mask & mask)
    +				dba_macro_add(dba->macros, i,
    +				    key->key, mpage->dba);
    +			i++;
    +		}
    +		free(key);
    +	}
    +}
    +
    +static void
    +dbprune(struct dba *dba)
    +{
    +	struct dba_array	*page, *files;
    +	char			*file;
    +
    +	dba_array_FOREACH(dba->pages, page) {
    +		files = dba_array_get(page, DBP_FILE);
    +		dba_array_FOREACH(files, file) {
    +			if (*file < ' ')
    +				file++;
    +			if (ohash_find(&mlinks, ohash_qlookup(&mlinks,
    +			    file)) != NULL) {
    +				if (debug)
    +					say(file, "Deleting from database");
    +				dba_array_del(dba->pages);
    +				break;
    +			}
    +		}
    +	}
    +}
    +
    +/*
    + * Write the database from memory to disk.
    + */
    +static void
    +dbwrite(struct dba *dba)
    +{
    +	struct stat	 sb1, sb2;
    +	char		 tfn[33], *cp1, *cp2;
    +	off_t		 i;
    +	int		 fd1, fd2;
    +
    +	/*
    +	 * Do not write empty databases, and delete existing ones
    +	 * when makewhatis -u causes them to become empty.
    +	 */
    +
    +	dba_array_start(dba->pages);
    +	if (dba_array_next(dba->pages) == NULL) {
    +		if (unlink(MANDOC_DB) == -1 && errno != ENOENT)
    +			say(MANDOC_DB, "&unlink");
    +		return;
    +	}
    +
    +	/*
    +	 * Build the database in a temporary file,
    +	 * then atomically move it into place.
    +	 */
    +
    +	if (dba_write(MANDOC_DB "~", dba) != -1) {
    +		if (rename(MANDOC_DB "~", MANDOC_DB) == -1) {
    +			exitcode = (int)MANDOCLEVEL_SYSERR;
    +			say(MANDOC_DB, "&rename");
    +			unlink(MANDOC_DB "~");
    +		}
    +		return;
    +	}
    +
    +	/*
    +	 * We lack write permission and cannot replace the database
    +	 * file, but let's at least check whether the data changed.
    +	 */
    +
    +	(void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn));
    +	if (mkdtemp(tfn) == NULL) {
    +		exitcode = (int)MANDOCLEVEL_SYSERR;
    +		say("", "&%s", tfn);
    +		return;
    +	}
    +	cp1 = cp2 = MAP_FAILED;
    +	fd1 = fd2 = -1;
    +	(void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn));
    +	if (dba_write(tfn, dba) == -1) {
    +		say(tfn, "&dba_write");
    +		goto err;
    +	}
    +	if ((fd1 = open(MANDOC_DB, O_RDONLY, 0)) == -1) {
    +		say(MANDOC_DB, "&open");
    +		goto err;
    +	}
    +	if ((fd2 = open(tfn, O_RDONLY, 0)) == -1) {
    +		say(tfn, "&open");
    +		goto err;
    +	}
    +	if (fstat(fd1, &sb1) == -1) {
    +		say(MANDOC_DB, "&fstat");
    +		goto err;
    +	}
    +	if (fstat(fd2, &sb2) == -1) {
    +		say(tfn, "&fstat");
    +		goto err;
    +	}
    +	if (sb1.st_size != sb2.st_size)
    +		goto err;
    +	if ((cp1 = mmap(NULL, sb1.st_size, PROT_READ, MAP_PRIVATE,
    +	    fd1, 0)) == MAP_FAILED) {
    +		say(MANDOC_DB, "&mmap");
    +		goto err;
    +	}
    +	if ((cp2 = mmap(NULL, sb2.st_size, PROT_READ, MAP_PRIVATE,
    +	    fd2, 0)) == MAP_FAILED) {
    +		say(tfn, "&mmap");
    +		goto err;
    +	}
    +	for (i = 0; i < sb1.st_size; i++)
    +		if (cp1[i] != cp2[i])
    +			goto err;
    +	goto out;
    +
    +err:
    +	exitcode = (int)MANDOCLEVEL_SYSERR;
    +	say(MANDOC_DB, "Data changed, but cannot replace database");
    +
    +out:
    +	if (cp1 != MAP_FAILED)
    +		munmap(cp1, sb1.st_size);
    +	if (cp2 != MAP_FAILED)
    +		munmap(cp2, sb2.st_size);
    +	if (fd1 != -1)
    +		close(fd1);
    +	if (fd2 != -1)
    +		close(fd2);
    +	unlink(tfn);
    +	*strrchr(tfn, '/') = '\0';
    +	rmdir(tfn);
    +}
    +
    +static int
    +set_basedir(const char *targetdir, int report_baddir)
    +{
    +	static char	 startdir[PATH_MAX];
    +	static int	 getcwd_status;  /* 1 = ok, 2 = failure */
    +	static int	 chdir_status;  /* 1 = changed directory */
    +	char		*cp;
    +
    +	/*
    +	 * Remember the original working directory, if possible.
    +	 * This will be needed if the second or a later directory
    +	 * on the command line is given as a relative path.
    +	 * Do not error out if the current directory is not
    +	 * searchable: Maybe it won't be needed after all.
    +	 */
    +	if (0 == getcwd_status) {
    +		if (NULL == getcwd(startdir, sizeof(startdir))) {
    +			getcwd_status = 2;
    +			(void)strlcpy(startdir, strerror(errno),
    +			    sizeof(startdir));
    +		} else
    +			getcwd_status = 1;
    +	}
    +
    +	/*
    +	 * We are leaving the old base directory.
    +	 * Do not use it any longer, not even for messages.
    +	 */
    +	*basedir = '\0';
    +
    +	/*
    +	 * If and only if the directory was changed earlier and
    +	 * the next directory to process is given as a relative path,
    +	 * first go back, or bail out if that is impossible.
    +	 */
    +	if (chdir_status && '/' != *targetdir) {
    +		if (2 == getcwd_status) {
    +			exitcode = (int)MANDOCLEVEL_SYSERR;
    +			say("", "getcwd: %s", startdir);
    +			return 0;
    +		}
    +		if (-1 == chdir(startdir)) {
    +			exitcode = (int)MANDOCLEVEL_SYSERR;
    +			say("", "&chdir %s", startdir);
    +			return 0;
    +		}
    +	}
    +
    +	/*
    +	 * Always resolve basedir to the canonicalized absolute
    +	 * pathname and append a trailing slash, such that
    +	 * we can reliably check whether files are inside.
    +	 */
    +	if (NULL == realpath(targetdir, basedir)) {
    +		if (report_baddir || errno != ENOENT) {
    +			exitcode = (int)MANDOCLEVEL_BADARG;
    +			say("", "&%s: realpath", targetdir);
    +		}
    +		return 0;
    +	} else if (-1 == chdir(basedir)) {
    +		if (report_baddir || errno != ENOENT) {
    +			exitcode = (int)MANDOCLEVEL_BADARG;
    +			say("", "&chdir");
    +		}
    +		return 0;
    +	}
    +	chdir_status = 1;
    +	cp = strchr(basedir, '\0');
    +	if ('/' != cp[-1]) {
    +		if (cp - basedir >= PATH_MAX - 1) {
    +			exitcode = (int)MANDOCLEVEL_SYSERR;
    +			say("", "Filename too long");
    +			return 0;
    +		}
    +		*cp++ = '/';
    +		*cp = '\0';
    +	}
    +	return 1;
    +}
    +
    +static void
    +say(const char *file, const char *format, ...)
    +{
    +	va_list		 ap;
    +	int		 use_errno;
    +
    +	if ('\0' != *basedir)
    +		fprintf(stderr, "%s", basedir);
    +	if ('\0' != *basedir && '\0' != *file)
    +		fputc('/', stderr);
    +	if ('\0' != *file)
    +		fprintf(stderr, "%s", file);
    +
    +	use_errno = 1;
    +	if (NULL != format) {
    +		switch (*format) {
    +		case '&':
    +			format++;
    +			break;
    +		case '\0':
    +			format = NULL;
    +			break;
    +		default:
    +			use_errno = 0;
    +			break;
    +		}
    +	}
    +	if (NULL != format) {
    +		if ('\0' != *basedir || '\0' != *file)
    +			fputs(": ", stderr);
    +		va_start(ap, format);
    +		vfprintf(stderr, format, ap);
    +		va_end(ap);
    +	}
    +	if (use_errno) {
    +		if ('\0' != *basedir || '\0' != *file || NULL != format)
    +			fputs(": ", stderr);
    +		perror(NULL);
    +	} else
    +		fputc('\n', stderr);
    +}
    
    Property changes on: head/contrib/mandoc/mandocdb.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mansearch.c
    ===================================================================
    --- head/contrib/mandoc/mansearch.c	(nonexistent)
    +++ head/contrib/mandoc/mansearch.c	(revision 338826)
    @@ -0,0 +1,851 @@
    +/*	$Id: mansearch.c,v 1.77 2017/08/22 17:50:11 schwarze Exp $ */
    +/*
    + * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * 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 <sys/mman.h>
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <glob.h>
    +#include <limits.h>
    +#include <regex.h>
    +#include <stdio.h>
    +#include <stdint.h>
    +#include <stddef.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mandoc.h"
    +#include "mandoc_aux.h"
    +#include "mandoc_ohash.h"
    +#include "manconf.h"
    +#include "mansearch.h"
    +#include "dbm.h"
    +
    +struct	expr {
    +	/* Used for terms: */
    +	struct dbm_match match;   /* Match type and expression. */
    +	uint64_t	 bits;    /* Type mask. */
    +	/* Used for OR and AND groups: */
    +	struct expr	*next;    /* Next child in the parent group. */
    +	struct expr	*child;   /* First child in this group. */
    +	enum { EXPR_TERM, EXPR_OR, EXPR_AND } type;
    +};
    +
    +const char *const mansearch_keynames[KEY_MAX] = {
    +	"arch",	"sec",	"Xr",	"Ar",	"Fa",	"Fl",	"Dv",	"Fn",
    +	"Ic",	"Pa",	"Cm",	"Li",	"Em",	"Cd",	"Va",	"Ft",
    +	"Tn",	"Er",	"Ev",	"Sy",	"Sh",	"In",	"Ss",	"Ox",
    +	"An",	"Mt",	"St",	"Bx",	"At",	"Nx",	"Fx",	"Lk",
    +	"Ms",	"Bsx",	"Dx",	"Rs",	"Vt",	"Lb",	"Nm",	"Nd"
    +};
    +
    +
    +static	struct ohash	*manmerge(struct expr *, struct ohash *);
    +static	struct ohash	*manmerge_term(struct expr *, struct ohash *);
    +static	struct ohash	*manmerge_or(struct expr *, struct ohash *);
    +static	struct ohash	*manmerge_and(struct expr *, struct ohash *);
    +static	char		*buildnames(const struct dbm_page *);
    +static	char		*buildoutput(size_t, struct dbm_page *);
    +static	size_t		 lstlen(const char *, size_t);
    +static	void		 lstcat(char *, size_t *, const char *, const char *);
    +static	int		 lstmatch(const char *, const char *);
    +static	struct expr	*exprcomp(const struct mansearch *,
    +				int, char *[], int *);
    +static	struct expr	*expr_and(const struct mansearch *,
    +				int, char *[], int *);
    +static	struct expr	*exprterm(const struct mansearch *,
    +				int, char *[], int *);
    +static	void		 exprfree(struct expr *);
    +static	int		 manpage_compare(const void *, const void *);
    +
    +
    +int
    +mansearch(const struct mansearch *search,
    +		const struct manpaths *paths,
    +		int argc, char *argv[],
    +		struct manpage **res, size_t *sz)
    +{
    +	char		 buf[PATH_MAX];
    +	struct dbm_res	*rp;
    +	struct expr	*e;
    +	struct dbm_page	*page;
    +	struct manpage	*mpage;
    +	struct ohash	*htab;
    +	size_t		 cur, i, maxres, outkey;
    +	unsigned int	 slot;
    +	int		 argi, chdir_status, getcwd_status, im;
    +
    +	argi = 0;
    +	if ((e = exprcomp(search, argc, argv, &argi)) == NULL) {
    +		*sz = 0;
    +		return 0;
    +	}
    +
    +	cur = maxres = 0;
    +	if (res != NULL)
    +		*res = NULL;
    +
    +	outkey = KEY_Nd;
    +	if (search->outkey != NULL)
    +		for (im = 0; im < KEY_MAX; im++)
    +			if (0 == strcasecmp(search->outkey,
    +			    mansearch_keynames[im])) {
    +				outkey = im;
    +				break;
    +			}
    +
    +	/*
    +	 * Remember the original working directory, if possible.
    +	 * This will be needed if the second or a later directory
    +	 * is given as a relative path.
    +	 * Do not error out if the current directory is not
    +	 * searchable: Maybe it won't be needed after all.
    +	 */
    +
    +	if (getcwd(buf, PATH_MAX) == NULL) {
    +		getcwd_status = 0;
    +		(void)strlcpy(buf, strerror(errno), sizeof(buf));
    +	} else
    +		getcwd_status = 1;
    +
    +	/*
    +	 * Loop over the directories (containing databases) for us to
    +	 * search.
    +	 * Don't let missing/bad databases/directories phase us.
    +	 * In each, try to open the resident database and, if it opens,
    +	 * scan it for our match expression.
    +	 */
    +
    +	chdir_status = 0;
    +	for (i = 0; i < paths->sz; i++) {
    +		if (chdir_status && paths->paths[i][0] != '/') {
    +			if ( ! getcwd_status) {
    +				warnx("%s: getcwd: %s", paths->paths[i], buf);
    +				continue;
    +			} else if (chdir(buf) == -1) {
    +				warn("%s", buf);
    +				continue;
    +			}
    +		}
    +		if (chdir(paths->paths[i]) == -1) {
    +			warn("%s", paths->paths[i]);
    +			continue;
    +		}
    +		chdir_status = 1;
    +
    +		if (dbm_open(MANDOC_DB) == -1) {
    +			if (errno != ENOENT)
    +				warn("%s/%s", paths->paths[i], MANDOC_DB);
    +			continue;
    +		}
    +
    +		if ((htab = manmerge(e, NULL)) == NULL) {
    +			dbm_close();
    +			continue;
    +		}
    +
    +		for (rp = ohash_first(htab, &slot); rp != NULL;
    +		    rp = ohash_next(htab, &slot)) {
    +			page = dbm_page_get(rp->page);
    +
    +			if (lstmatch(search->sec, page->sect) == 0 ||
    +			    lstmatch(search->arch, page->arch) == 0 ||
    +			    (search->argmode == ARG_NAME &&
    +			     rp->bits <= (int32_t)(NAME_SYN & NAME_MASK)))
    +				continue;
    +
    +			if (res == NULL) {
    +				cur = 1;
    +				break;
    +			}
    +			if (cur + 1 > maxres) {
    +				maxres += 1024;
    +				*res = mandoc_reallocarray(*res,
    +				    maxres, sizeof(**res));
    +			}
    +			mpage = *res + cur;
    +			mandoc_asprintf(&mpage->file, "%s/%s",
    +			    paths->paths[i], page->file + 1);
    +			if (access(chdir_status ? page->file + 1 :
    +			    mpage->file, R_OK) == -1) {
    +				warn("%s", mpage->file);
    +				warnx("outdated mandoc.db contains "
    +				    "bogus %s entry, run makewhatis %s", 
    +				    page->file + 1, paths->paths[i]);
    +				free(mpage->file);
    +				free(rp);
    +				continue;
    +			}
    +			mpage->names = buildnames(page);
    +			mpage->output = buildoutput(outkey, page);
    +			mpage->ipath = i;
    +			mpage->bits = rp->bits;
    +			mpage->sec = *page->sect - '0';
    +			if (mpage->sec < 0 || mpage->sec > 9)
    +				mpage->sec = 10;
    +			mpage->form = *page->file;
    +			free(rp);
    +			cur++;
    +		}
    +		ohash_delete(htab);
    +		free(htab);
    +		dbm_close();
    +
    +		/*
    +		 * In man(1) mode, prefer matches in earlier trees
    +		 * over matches in later trees.
    +		 */
    +
    +		if (cur && search->firstmatch)
    +			break;
    +	}
    +	if (res != NULL)
    +		qsort(*res, cur, sizeof(struct manpage), manpage_compare);
    +	if (chdir_status && getcwd_status && chdir(buf) == -1)
    +		warn("%s", buf);
    +	exprfree(e);
    +	*sz = cur;
    +	return res != NULL || cur;
    +}
    +
    +/*
    + * Merge the results for the expression tree rooted at e
    + * into the the result list htab.
    + */
    +static struct ohash *
    +manmerge(struct expr *e, struct ohash *htab)
    +{
    +	switch (e->type) {
    +	case EXPR_TERM:
    +		return manmerge_term(e, htab);
    +	case EXPR_OR:
    +		return manmerge_or(e->child, htab);
    +	case EXPR_AND:
    +		return manmerge_and(e->child, htab);
    +	default:
    +		abort();
    +	}
    +}
    +
    +static struct ohash *
    +manmerge_term(struct expr *e, struct ohash *htab)
    +{
    +	struct dbm_res	 res, *rp;
    +	uint64_t	 ib;
    +	unsigned int	 slot;
    +	int		 im;
    +
    +	if (htab == NULL) {
    +		htab = mandoc_malloc(sizeof(*htab));
    +		mandoc_ohash_init(htab, 4, offsetof(struct dbm_res, page));
    +	}
    +
    +	for (im = 0, ib = 1; im < KEY_MAX; im++, ib <<= 1) {
    +		if ((e->bits & ib) == 0)
    +			continue;
    +
    +		switch (ib) {
    +		case TYPE_arch:
    +			dbm_page_byarch(&e->match);
    +			break;
    +		case TYPE_sec:
    +			dbm_page_bysect(&e->match);
    +			break;
    +		case TYPE_Nm:
    +			dbm_page_byname(&e->match);
    +			break;
    +		case TYPE_Nd:
    +			dbm_page_bydesc(&e->match);
    +			break;
    +		default:
    +			dbm_page_bymacro(im - 2, &e->match);
    +			break;
    +		}
    +
    +		/*
    +		 * When hashing for deduplication, use the unique
    +		 * page ID itself instead of a hash function;
    +		 * that is quite efficient.
    +		 */
    +
    +		for (;;) {
    +			res = dbm_page_next();
    +			if (res.page == -1)
    +				break;
    +			slot = ohash_lookup_memory(htab,
    +			    (char *)&res, sizeof(res.page), res.page);
    +			if ((rp = ohash_find(htab, slot)) != NULL) {
    +				rp->bits |= res.bits;
    +				continue;
    +			}
    +			rp = mandoc_malloc(sizeof(*rp));
    +			*rp = res;
    +			ohash_insert(htab, slot, rp);
    +		}
    +	}
    +	return htab;
    +}
    +
    +static struct ohash *
    +manmerge_or(struct expr *e, struct ohash *htab)
    +{
    +	while (e != NULL) {
    +		htab = manmerge(e, htab);
    +		e = e->next;
    +	}
    +	return htab;
    +}
    +
    +static struct ohash *
    +manmerge_and(struct expr *e, struct ohash *htab)
    +{
    +	struct ohash	*hand, *h1, *h2;
    +	struct dbm_res	*res;
    +	unsigned int	 slot1, slot2;
    +
    +	/* Evaluate the first term of the AND clause. */
    +
    +	hand = manmerge(e, NULL);
    +
    +	while ((e = e->next) != NULL) {
    +
    +		/* Evaluate the next term and prepare for ANDing. */
    +
    +		h2 = manmerge(e, NULL);
    +		if (ohash_entries(h2) < ohash_entries(hand)) {
    +			h1 = h2;
    +			h2 = hand;
    +		} else
    +			h1 = hand;
    +		hand = mandoc_malloc(sizeof(*hand));
    +		mandoc_ohash_init(hand, 4, offsetof(struct dbm_res, page));
    +
    +		/* Keep all pages that are in both result sets. */
    +
    +		for (res = ohash_first(h1, &slot1); res != NULL;
    +		    res = ohash_next(h1, &slot1)) {
    +			if (ohash_find(h2, ohash_lookup_memory(h2,
    +			    (char *)res, sizeof(res->page),
    +			    res->page)) == NULL)
    +				free(res);
    +			else
    +				ohash_insert(hand, ohash_lookup_memory(hand,
    +				    (char *)res, sizeof(res->page),
    +				    res->page), res);
    +		}
    +
    +		/* Discard the merged results. */
    +
    +		for (res = ohash_first(h2, &slot2); res != NULL;
    +		    res = ohash_next(h2, &slot2))
    +			free(res);
    +		ohash_delete(h2);
    +		free(h2);
    +		ohash_delete(h1);
    +		free(h1);
    +	}
    +
    +	/* Merge the result of the AND into htab. */
    +
    +	if (htab == NULL)
    +		return hand;
    +
    +	for (res = ohash_first(hand, &slot1); res != NULL;
    +	    res = ohash_next(hand, &slot1)) {
    +		slot2 = ohash_lookup_memory(htab,
    +		    (char *)res, sizeof(res->page), res->page);
    +		if (ohash_find(htab, slot2) == NULL)
    +			ohash_insert(htab, slot2, res);
    +		else
    +			free(res);
    +	}
    +
    +	/* Discard the merged result. */
    +
    +	ohash_delete(hand);
    +	free(hand);
    +	return htab;
    +}
    +
    +void
    +mansearch_free(struct manpage *res, size_t sz)
    +{
    +	size_t	 i;
    +
    +	for (i = 0; i < sz; i++) {
    +		free(res[i].file);
    +		free(res[i].names);
    +		free(res[i].output);
    +	}
    +	free(res);
    +}
    +
    +static int
    +manpage_compare(const void *vp1, const void *vp2)
    +{
    +	const struct manpage	*mp1, *mp2;
    +	const char		*cp1, *cp2;
    +	size_t			 sz1, sz2;
    +	int			 diff;
    +
    +	mp1 = vp1;
    +	mp2 = vp2;
    +	if ((diff = mp2->bits - mp1->bits) ||
    +	    (diff = mp1->sec - mp2->sec))
    +		return diff;
    +
    +	/* Fall back to alphabetic ordering of names. */
    +	sz1 = strcspn(mp1->names, "(");
    +	sz2 = strcspn(mp2->names, "(");
    +	if (sz1 < sz2)
    +		sz1 = sz2;
    +	if ((diff = strncasecmp(mp1->names, mp2->names, sz1)))
    +		return diff;
    +
    +	/* For identical names and sections, prefer arch-dependent. */
    +	cp1 = strchr(mp1->names + sz1, '/');
    +	cp2 = strchr(mp2->names + sz2, '/');
    +	return cp1 != NULL && cp2 != NULL ? strcasecmp(cp1, cp2) :
    +	    cp1 != NULL ? -1 : cp2 != NULL ? 1 : 0;
    +}
    +
    +static char *
    +buildnames(const struct dbm_page *page)
    +{
    +	char	*buf;
    +	size_t	 i, sz;
    +
    +	sz = lstlen(page->name, 2) + 1 + lstlen(page->sect, 2) +
    +	    (page->arch == NULL ? 0 : 1 + lstlen(page->arch, 2)) + 2;
    +	buf = mandoc_malloc(sz);
    +	i = 0;
    +	lstcat(buf, &i, page->name, ", ");
    +	buf[i++] = '(';
    +	lstcat(buf, &i, page->sect, ", ");
    +	if (page->arch != NULL) {
    +		buf[i++] = '/';
    +		lstcat(buf, &i, page->arch, ", ");
    +	}
    +	buf[i++] = ')';
    +	buf[i++] = '\0';
    +	assert(i == sz);
    +	return buf;
    +}
    +
    +/*
    + * Count the buffer space needed to print the NUL-terminated
    + * list of NUL-terminated strings, when printing sep separator
    + * characters between strings.
    + */
    +static size_t
    +lstlen(const char *cp, size_t sep)
    +{
    +	size_t	 sz;
    +
    +	for (sz = 0; *cp != '\0'; cp++) {
    +
    +		/* Skip names appearing only in the SYNOPSIS. */
    +		if (*cp <= (char)(NAME_SYN & NAME_MASK)) {
    +			while (*cp != '\0')
    +				cp++;
    +			continue;
    +		}
    +
    +		/* Skip name class markers. */
    +		if (*cp < ' ')
    +			cp++;
    +
    +		/* Print a separator before each but the first string. */
    +		if (sz)
    +			sz += sep;
    +
    +		/* Copy one string. */
    +		while (*cp != '\0') {
    +			sz++;
    +			cp++;
    +		}
    +	}
    +	return sz;
    +}
    +
    +/*
    + * Print the NUL-terminated list of NUL-terminated strings
    + * into the buffer, seperating strings with sep.
    + */
    +static void
    +lstcat(char *buf, size_t *i, const char *cp, const char *sep)
    +{
    +	const char	*s;
    +	size_t		 i_start;
    +
    +	for (i_start = *i; *cp != '\0'; cp++) {
    +
    +		/* Skip names appearing only in the SYNOPSIS. */
    +		if (*cp <= (char)(NAME_SYN & NAME_MASK)) {
    +			while (*cp != '\0')
    +				cp++;
    +			continue;
    +		}
    +
    +		/* Skip name class markers. */
    +		if (*cp < ' ')
    +			cp++;
    +
    +		/* Print a separator before each but the first string. */
    +		if (*i > i_start) {
    +			s = sep;
    +			while (*s != '\0')
    +				buf[(*i)++] = *s++;
    +		}
    +
    +		/* Copy one string. */
    +		while (*cp != '\0')
    +			buf[(*i)++] = *cp++;
    +	}
    +
    +}
    +
    +/*
    + * Return 1 if the string *want occurs in any of the strings
    + * in the NUL-terminated string list *have, or 0 otherwise.
    + * If either argument is NULL or empty, assume no filtering
    + * is desired and return 1.
    + */
    +static int
    +lstmatch(const char *want, const char *have)
    +{
    +        if (want == NULL || have == NULL || *have == '\0')
    +                return 1;
    +        while (*have != '\0') {
    +                if (strcasestr(have, want) != NULL)
    +                        return 1;
    +                have = strchr(have, '\0') + 1;
    +        }
    +        return 0;
    +}
    +
    +/*
    + * Build a list of values taken by the macro im in the manual page.
    + */
    +static char *
    +buildoutput(size_t im, struct dbm_page *page)
    +{
    +	const char	*oldoutput, *sep, *input;
    +	char		*output, *newoutput, *value;
    +	size_t		 sz, i;
    +
    +	switch (im) {
    +	case KEY_Nd:
    +		return mandoc_strdup(page->desc);
    +	case KEY_Nm:
    +		input = page->name;
    +		break;
    +	case KEY_sec:
    +		input = page->sect;
    +		break;
    +	case KEY_arch:
    +		input = page->arch;
    +		if (input == NULL)
    +			input = "all\0";
    +		break;
    +	default:
    +		input = NULL;
    +		break;
    +	}
    +
    +	if (input != NULL) {
    +		sz = lstlen(input, 3) + 1;
    +		output = mandoc_malloc(sz);
    +		i = 0;
    +		lstcat(output, &i, input, " # ");
    +		output[i++] = '\0';
    +		assert(i == sz);
    +		return output;
    +	}
    +
    +	output = NULL;
    +	dbm_macro_bypage(im - 2, page->addr);
    +	while ((value = dbm_macro_next()) != NULL) {
    +		if (output == NULL) {
    +			oldoutput = "";
    +			sep = "";
    +		} else {
    +			oldoutput = output;
    +			sep = " # ";
    +		}
    +		mandoc_asprintf(&newoutput, "%s%s%s", oldoutput, sep, value);
    +		free(output);
    +		output = newoutput;
    +	}
    +	return output;
    +}
    +
    +/*
    + * Compile a set of string tokens into an expression.
    + * Tokens in "argv" are assumed to be individual expression atoms (e.g.,
    + * "(", "foo=bar", etc.).
    + */
    +static struct expr *
    +exprcomp(const struct mansearch *search, int argc, char *argv[], int *argi)
    +{
    +	struct expr	*parent, *child;
    +	int		 needterm, nested;
    +
    +	if ((nested = *argi) == argc)
    +		return NULL;
    +	needterm = 1;
    +	parent = child = NULL;
    +	while (*argi < argc) {
    +		if (strcmp(")", argv[*argi]) == 0) {
    +			if (needterm)
    +				warnx("missing term "
    +				    "before closing parenthesis");
    +			needterm = 0;
    +			if (nested)
    +				break;
    +			warnx("ignoring unmatched right parenthesis");
    +			++*argi;
    +			continue;
    +		}
    +		if (strcmp("-o", argv[*argi]) == 0) {
    +			if (needterm) {
    +				if (*argi > 0)
    +					warnx("ignoring -o after %s",
    +					    argv[*argi - 1]);
    +				else
    +					warnx("ignoring initial -o");
    +			}
    +			needterm = 1;
    +			++*argi;
    +			continue;
    +		}
    +		needterm = 0;
    +		if (child == NULL) {
    +			child = expr_and(search, argc, argv, argi);
    +			continue;
    +		}
    +		if (parent == NULL) {
    +			parent = mandoc_calloc(1, sizeof(*parent));
    +			parent->type = EXPR_OR;
    +			parent->next = NULL;
    +			parent->child = child;
    +		}
    +		child->next = expr_and(search, argc, argv, argi);
    +		child = child->next;
    +	}
    +	if (needterm && *argi)
    +		warnx("ignoring trailing %s", argv[*argi - 1]);
    +	return parent == NULL ? child : parent;
    +}
    +
    +static struct expr *
    +expr_and(const struct mansearch *search, int argc, char *argv[], int *argi)
    +{
    +	struct expr	*parent, *child;
    +	int		 needterm;
    +
    +	needterm = 1;
    +	parent = child = NULL;
    +	while (*argi < argc) {
    +		if (strcmp(")", argv[*argi]) == 0) {
    +			if (needterm)
    +				warnx("missing term "
    +				    "before closing parenthesis");
    +			needterm = 0;
    +			break;
    +		}
    +		if (strcmp("-o", argv[*argi]) == 0)
    +			break;
    +		if (strcmp("-a", argv[*argi]) == 0) {
    +			if (needterm) {
    +				if (*argi > 0)
    +					warnx("ignoring -a after %s",
    +					    argv[*argi - 1]);
    +				else
    +					warnx("ignoring initial -a");
    +			}
    +			needterm = 1;
    +			++*argi;
    +			continue;
    +		}
    +		if (needterm == 0)
    +			break;
    +		if (child == NULL) {
    +			child = exprterm(search, argc, argv, argi);
    +			if (child != NULL)
    +				needterm = 0;
    +			continue;
    +		}
    +		needterm = 0;
    +		if (parent == NULL) {
    +			parent = mandoc_calloc(1, sizeof(*parent));
    +			parent->type = EXPR_AND;
    +			parent->next = NULL;
    +			parent->child = child;
    +		}
    +		child->next = exprterm(search, argc, argv, argi);
    +		if (child->next != NULL) {
    +			child = child->next;
    +			needterm = 0;
    +		}
    +	}
    +	if (needterm && *argi)
    +		warnx("ignoring trailing %s", argv[*argi - 1]);
    +	return parent == NULL ? child : parent;
    +}
    +
    +static struct expr *
    +exprterm(const struct mansearch *search, int argc, char *argv[], int *argi)
    +{
    +	char		 errbuf[BUFSIZ];
    +	struct expr	*e;
    +	char		*key, *val;
    +	uint64_t	 iterbit;
    +	int		 cs, i, irc;
    +
    +	if (strcmp("(", argv[*argi]) == 0) {
    +		++*argi;
    +		e = exprcomp(search, argc, argv, argi);
    +		if (*argi < argc) {
    +			assert(strcmp(")", argv[*argi]) == 0);
    +			++*argi;
    +		} else
    +			warnx("unclosed parenthesis");
    +		return e;
    +	}
    +
    +	if (strcmp("-i", argv[*argi]) == 0 && *argi + 1 < argc) {
    +		cs = 0;
    +		++*argi;
    +	} else
    +		cs = 1;
    +
    +	e = mandoc_calloc(1, sizeof(*e));
    +	e->type = EXPR_TERM;
    +	e->bits = 0;
    +	e->next = NULL;
    +	e->child = NULL;
    +
    +	if (search->argmode == ARG_NAME) {
    +		e->bits = TYPE_Nm;
    +		e->match.type = DBM_EXACT;
    +		e->match.str = argv[(*argi)++];
    +		return e;
    +	}
    +
    +	/*
    +	 * Separate macro keys from search string.
    +	 * If needed, request regular expression handling.
    +	 */
    +
    +	if (search->argmode == ARG_WORD) {
    +		e->bits = TYPE_Nm;
    +		e->match.type = DBM_REGEX;
    +#if HAVE_REWB_BSD
    +		mandoc_asprintf(&val, "[[:<:]]%s[[:>:]]", argv[*argi]);
    +#elif HAVE_REWB_SYSV
    +		mandoc_asprintf(&val, "\\<%s\\>", argv[*argi]);
    +#else
    +		mandoc_asprintf(&val,
    +		    "(^|[^a-zA-Z01-9_])%s([^a-zA-Z01-9_]|$)", argv[*argi]);
    +#endif
    +		cs = 0;
    +	} else if ((val = strpbrk(argv[*argi], "=~")) == NULL) {
    +		e->bits = TYPE_Nm | TYPE_Nd;
    +		e->match.type = DBM_SUB;
    +		e->match.str = argv[*argi];
    +	} else {
    +		if (val == argv[*argi])
    +			e->bits = TYPE_Nm | TYPE_Nd;
    +		if (*val == '=') {
    +			e->match.type = DBM_SUB;
    +			e->match.str = val + 1;
    +		} else
    +			e->match.type = DBM_REGEX;
    +		*val++ = '\0';
    +		if (strstr(argv[*argi], "arch") != NULL)
    +			cs = 0;
    +	}
    +
    +	/* Compile regular expressions. */
    +
    +	if (e->match.type == DBM_REGEX) {
    +		e->match.re = mandoc_malloc(sizeof(*e->match.re));
    +		irc = regcomp(e->match.re, val,
    +		    REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE));
    +		if (irc) {
    +			regerror(irc, e->match.re, errbuf, sizeof(errbuf));
    +			warnx("regcomp /%s/: %s", val, errbuf);
    +		}
    +		if (search->argmode == ARG_WORD)
    +			free(val);
    +		if (irc) {
    +			free(e->match.re);
    +			free(e);
    +			++*argi;
    +			return NULL;
    +		}
    +	}
    +
    +	if (e->bits) {
    +		++*argi;
    +		return e;
    +	}
    +
    +	/*
    +	 * Parse out all possible fields.
    +	 * If the field doesn't resolve, bail.
    +	 */
    +
    +	while (NULL != (key = strsep(&argv[*argi], ","))) {
    +		if ('\0' == *key)
    +			continue;
    +		for (i = 0, iterbit = 1; i < KEY_MAX; i++, iterbit <<= 1) {
    +			if (0 == strcasecmp(key, mansearch_keynames[i])) {
    +				e->bits |= iterbit;
    +				break;
    +			}
    +		}
    +		if (i == KEY_MAX) {
    +			if (strcasecmp(key, "any"))
    +				warnx("treating unknown key "
    +				    "\"%s\" as \"any\"", key);
    +			e->bits |= ~0ULL;
    +		}
    +	}
    +
    +	++*argi;
    +	return e;
    +}
    +
    +static void
    +exprfree(struct expr *e)
    +{
    +	if (e->next != NULL)
    +		exprfree(e->next);
    +	if (e->child != NULL)
    +		exprfree(e->child);
    +	free(e);
    +}
    
    Property changes on: head/contrib/mandoc/mansearch.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc.7
    ===================================================================
    --- head/contrib/mandoc/mdoc.7	(nonexistent)
    +++ head/contrib/mandoc/mdoc.7	(revision 338826)
    @@ -0,0 +1,3244 @@
    +.\"	$Id: mdoc.7,v 1.271 2018/07/28 18:34:15 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    +.\" Copyright (c) 2010, 2011, 2013-2018 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE 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: July 28 2018 $
    +.Dt MDOC 7
    +.Os
    +.Sh NAME
    +.Nm mdoc
    +.Nd semantic markup language for formatting manual pages
    +.Sh DESCRIPTION
    +The
    +.Nm mdoc
    +language supports authoring of manual pages for the
    +.Xr man 1
    +utility by allowing semantic annotations of words, phrases,
    +page sections and complete manual pages.
    +Such annotations are used by formatting tools to achieve a uniform
    +presentation across all manuals written in
    +.Nm ,
    +and to support hyperlinking if supported by the output medium.
    +.Pp
    +This reference document describes the structure of manual pages
    +and the syntax and usage of the
    +.Nm
    +language.
    +The reference implementation of a parsing and formatting tool is
    +.Xr mandoc 1 ;
    +the
    +.Sx COMPATIBILITY
    +section describes compatibility with other implementations.
    +.Pp
    +In an
    +.Nm
    +document, lines beginning with the control character
    +.Sq \&.
    +are called
    +.Dq macro lines .
    +The first word is the macro name.
    +It consists of two or three letters.
    +Most macro names begin with a capital letter.
    +For a list of available macros, see
    +.Sx MACRO OVERVIEW .
    +The words following the macro name are arguments to the macro, optionally
    +including the names of other, callable macros; see
    +.Sx MACRO SYNTAX
    +for details.
    +.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.
    +However, using
    +.Xr roff 7
    +requests in
    +.Nm
    +documents is discouraged;
    +.Xr mandoc 1
    +supports some of them merely for backward compatibility.
    +.Sh MANUAL STRUCTURE
    +A well-formed
    +.Nm
    +document consists of a document prologue followed by one or more
    +sections.
    +.Pp
    +The prologue, which consists of the
    +.Sx \&Dd ,
    +.Sx \&Dt ,
    +and
    +.Sx \&Os
    +macros in that order, is required for every document.
    +.Pp
    +The first section (sections are denoted by
    +.Sx \&Sh )
    +must be the NAME section, consisting of at least one
    +.Sx \&Nm
    +followed by
    +.Sx \&Nd .
    +.Pp
    +Following that, convention dictates specifying at least the
    +.Em SYNOPSIS
    +and
    +.Em DESCRIPTION
    +sections, although this varies between manual sections.
    +.Pp
    +The following is a well-formed skeleton
    +.Nm
    +file for a utility
    +.Qq progname :
    +.Bd -literal -offset indent
    +\&.Dd $\&Mdocdate$
    +\&.Dt PROGNAME section
    +\&.Os
    +\&.Sh NAME
    +\&.Nm progname
    +\&.Nd 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
    +\&.Nm progname
    +\&.Op Fl options
    +\&.Ar
    +\&.Sh DESCRIPTION
    +The
    +\&.Nm
    +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 .Xr 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 an
    +.Nm
    +document are conventionally ordered as they appear above.
    +Sections should be composed as follows:
    +.Bl -ohang -offset Ds
    +.It Em NAME
    +The name(s) and a one line description of the documented material.
    +The syntax for this as follows:
    +.Bd -literal -offset indent
    +\&.Nm name0 ,
    +\&.Nm name1 ,
    +\&.Nm name2
    +\&.Nd a one line description
    +.Ed
    +.Pp
    +Multiple
    +.Sq \&Nm
    +names should be separated by commas.
    +.Pp
    +The
    +.Sx \&Nm
    +macro(s) must precede the
    +.Sx \&Nd
    +macro.
    +.Pp
    +See
    +.Sx \&Nm
    +and
    +.Sx \&Nd .
    +.It Em LIBRARY
    +The name of the library containing the documented material, which is
    +assumed to be a function in a section 2, 3, or 9 manual.
    +The syntax for this is as follows:
    +.Bd -literal -offset indent
    +\&.Lb libarm
    +.Ed
    +.Pp
    +See
    +.Sx \&Lb .
    +.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:
    +.Bd -literal -offset indent
    +\&.Nm bar
    +\&.Op Fl v
    +\&.Op Fl o Ar file
    +\&.Op Ar
    +\&.Nm foo
    +\&.Op Fl v
    +\&.Op Fl o Ar file
    +\&.Op Ar
    +.Ed
    +.Pp
    +Commands should be ordered alphabetically.
    +.Pp
    +For the second, function calls (sections 2, 3, 9):
    +.Bd -literal -offset indent
    +\&.In header.h
    +\&.Vt extern const char *global;
    +\&.Ft "char *"
    +\&.Fn foo "const char *src"
    +\&.Ft "char *"
    +\&.Fn bar "const char *src"
    +.Ed
    +.Pp
    +Ordering of
    +.Sx \&In ,
    +.Sx \&Vt ,
    +.Sx \&Fn ,
    +and
    +.Sx \&Fo
    +macros should follow C header-file conventions.
    +.Pp
    +And for the third, configurations (section 4):
    +.Bd -literal -offset indent
    +\&.Cd \(dqit* at isa? port 0x2e\(dq
    +\&.Cd \(dqit* at isa? port 0x4e\(dq
    +.Ed
    +.Pp
    +Manuals not in these sections generally don't need a
    +.Em SYNOPSIS .
    +.Pp
    +Some macros are displayed differently in the
    +.Em SYNOPSIS
    +section, particularly
    +.Sx \&Nm ,
    +.Sx \&Cd ,
    +.Sx \&Fd ,
    +.Sx \&Fn ,
    +.Sx \&Fo ,
    +.Sx \&In ,
    +.Sx \&Vt ,
    +and
    +.Sx \&Ft .
    +All of these macros are output on their own line.
    +If two such dissimilar macros are pairwise invoked (except for
    +.Sx \&Ft
    +before
    +.Sx \&Fo
    +or
    +.Sx \&Fn ) ,
    +they are separated by a vertical space, unless in the case of
    +.Sx \&Fo ,
    +.Sx \&Fn ,
    +and
    +.Sx \&Ft ,
    +which are always separated by vertical space.
    +.Pp
    +When text and macros following an
    +.Sx \&Nm
    +macro starting an input line span multiple output lines,
    +all output lines but the first will be indented to align
    +with the text immediately following the
    +.Sx \&Nm
    +macro, up to the next
    +.Sx \&Nm ,
    +.Sx \&Sh ,
    +or
    +.Sx \&Ss
    +macro or the end of an enclosing block, whichever comes first.
    +.It Em DESCRIPTION
    +This begins with an expansion of the brief, one line description in
    +.Em NAME :
    +.Bd -literal -offset indent
    +The
    +\&.Nm
    +utility does this, that, and the other.
    +.Ed
    +.Pp
    +It usually follows with a breakdown of the options (if documenting a
    +command), such as:
    +.Bd -literal -offset indent
    +The arguments are as follows:
    +\&.Bl \-tag \-width Ds
    +\&.It Fl v
    +Print verbose information.
    +\&.El
    +.Ed
    +.Pp
    +List the options in alphabetical order,
    +uppercase before lowercase for each letter and
    +with no regard to whether an option takes an argument.
    +Put digits in ascending order before all letter options.
    +.Pp
    +Manuals not documenting a command won't include the above fragment.
    +.Pp
    +Since the
    +.Em DESCRIPTION
    +section usually contains most of the text of a manual, longer manuals
    +often use the
    +.Sx \&Ss
    +macro to form subsections.
    +In very long manuals, the
    +.Em DESCRIPTION
    +may be split into multiple sections, each started by an
    +.Sx \&Sh
    +macro followed by a non-standard section name, and each having
    +several subsections, like in the present
    +.Nm
    +manual.
    +.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.
    +.Pp
    +See
    +.Sx \&Rv .
    +.It Em ENVIRONMENT
    +Lists the environment variables used by the utility,
    +and explains the syntax and semantics of their values.
    +The
    +.Xr environ 7
    +manual provides examples of typical content and formatting.
    +.Pp
    +See
    +.Sx \&Ev .
    +.It Em FILES
    +Documents files used.
    +It's helpful to document both the file name and a short description of how
    +the file is used (created, modified, etc.).
    +.Pp
    +See
    +.Sx \&Pa .
    +.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.
    +.Pp
    +See
    +.Sx \&Ex .
    +.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 messages.
    +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.
    +.Pp
    +See
    +.Sx \&Bl
    +.Fl diag .
    +.It Em ERRORS
    +Documents
    +.Xr errno 2
    +settings in sections 2, 3, 4, and 9.
    +.Pp
    +See
    +.Sx \&Er .
    +.It Em SEE ALSO
    +References other manuals with related topics.
    +This section should exist for most manuals.
    +Cross-references should conventionally be ordered first by section, then
    +alphabetically (ignoring case).
    +.Pp
    +References to other documentation concerning the topic of the manual page,
    +for example authoritative books or journal articles, may also be
    +provided in this section.
    +.Pp
    +See
    +.Sx \&Rs
    +and
    +.Sx \&Xr .
    +.It Em STANDARDS
    +References any standards implemented or used.
    +If not adhering to any standards, the
    +.Em HISTORY
    +section should be used instead.
    +.Pp
    +See
    +.Sx \&St .
    +.It Em HISTORY
    +A brief history of the subject, including where it was first implemented,
    +and when it was ported to or reimplemented for the operating system at hand.
    +.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.
    +.Pp
    +See
    +.Sx \&An .
    +.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 below
    +in the alphabetical
    +.Sx MACRO REFERENCE .
    +.Ss Document preamble and NAME section macros
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Dd Ta document date: Cm $\&Mdocdate$ | Ar month day , year
    +.It Sx \&Dt Ta document title: Ar TITLE section Op Ar arch
    +.It Sx \&Os Ta operating system version: Op Ar system Op Ar version
    +.It Sx \&Nm Ta document name (one argument)
    +.It Sx \&Nd Ta document description (one line)
    +.El
    +.Ss Sections and cross references
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Sh Ta section header (one line)
    +.It Sx \&Ss Ta subsection header (one line)
    +.It Sx \&Sx Ta internal cross reference to a section or subsection
    +.It Sx \&Xr Ta cross reference to another manual page: Ar name section
    +.It Sx \&Pp , \&Lp Ta start a text paragraph (no arguments)
    +.El
    +.Ss Displays and lists
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Bd , \&Ed Ta display block:
    +.Fl Ar type
    +.Op Fl offset Ar width
    +.Op Fl compact
    +.It Sx \&D1 Ta indented display (one line)
    +.It Sx \&Dl Ta indented literal display (one line)
    +.It Sx \&Ql Ta in-line literal display: Ql text
    +.It Sx \&Bl , \&El Ta list block:
    +.Fl Ar type
    +.Op Fl width Ar val
    +.Op Fl offset Ar val
    +.Op Fl compact
    +.It Sx \&It Ta list item (syntax depends on Fl Ar type )
    +.It Sx \&Ta Ta table cell separator in Sx \&Bl Fl column No lists
    +.It Sx \&Rs , \&%* , \&Re Ta bibliographic block (references)
    +.El
    +.Ss Spacing control
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Pf Ta prefix, no following horizontal space (one argument)
    +.It Sx \&Ns Ta roman font, no preceding horizontal space (no arguments)
    +.It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments)
    +.It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off
    +.It Sx \&Bk , \&Ek Ta keep block: Fl words
    +.El
    +.Ss Semantic markup for command line utilities
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Nm Ta start a SYNOPSIS block with the name of a utility
    +.It Sx \&Fl Ta command line options (flags) (>=0 arguments)
    +.It Sx \&Cm Ta command modifier (>0 arguments)
    +.It Sx \&Ar Ta command arguments (>=0 arguments)
    +.It Sx \&Op , \&Oo , \&Oc Ta optional syntax elements (enclosure)
    +.It Sx \&Ic Ta internal or interactive command (>0 arguments)
    +.It Sx \&Ev Ta environmental variable (>0 arguments)
    +.It Sx \&Pa Ta file system path (>=0 arguments)
    +.El
    +.Ss Semantic markup for function libraries
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Lb Ta function library (one argument)
    +.It Sx \&In Ta include file (one argument)
    +.It Sx \&Fd Ta other preprocessor directive (>0 arguments)
    +.It Sx \&Ft Ta function type (>0 arguments)
    +.It Sx \&Fo , \&Fc Ta function block: Ar funcname
    +.It Sx \&Fn Ta function name:
    +.Op Ar functype
    +.Ar funcname
    +.Oo
    +.Op Ar argtype
    +.Ar argname
    +.Oc
    +.It Sx \&Fa Ta function argument (>0 arguments)
    +.It Sx \&Vt Ta variable type (>0 arguments)
    +.It Sx \&Va Ta variable name (>0 arguments)
    +.It Sx \&Dv Ta defined variable or preprocessor constant (>0 arguments)
    +.It Sx \&Er Ta error constant (>0 arguments)
    +.It Sx \&Ev Ta environmental variable (>0 arguments)
    +.El
    +.Ss Various semantic markup
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&An Ta author name (>0 arguments)
    +.It Sx \&Lk Ta hyperlink: Ar uri Op Ar name
    +.It Sx \&Mt Ta Do mailto Dc hyperlink: Ar address
    +.It Sx \&Cd Ta kernel configuration declaration (>0 arguments)
    +.It Sx \&Ad Ta memory address (>0 arguments)
    +.It Sx \&Ms Ta mathematical symbol (>0 arguments)
    +.El
    +.Ss Physical markup
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Em Ta italic font or underline (emphasis) (>0 arguments)
    +.It Sx \&Sy Ta boldface font (symbolic) (>0 arguments)
    +.It Sx \&Li Ta typewriter font (literal) (>0 arguments)
    +.It Sx \&No Ta return to roman font (normal) (no arguments)
    +.It Sx \&Bf , \&Ef Ta font block:
    +.Op Fl Ar type | Cm \&Em | \&Li | \&Sy
    +.El
    +.Ss Physical enclosures
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Dq , \&Do , \&Dc Ta enclose in typographic double quotes: Dq text
    +.It Sx \&Qq , \&Qo , \&Qc Ta enclose in typewriter double quotes: Qq text
    +.It Sx \&Sq , \&So , \&Sc Ta enclose in single quotes: Sq text
    +.It Sx \&Pq , \&Po , \&Pc Ta enclose in parentheses: Pq text
    +.It Sx \&Bq , \&Bo , \&Bc Ta enclose in square brackets: Bq text
    +.It Sx \&Brq , \&Bro , \&Brc Ta enclose in curly braces: Brq text
    +.It Sx \&Aq , \&Ao , \&Ac Ta enclose in angle brackets: Aq text
    +.It Sx \&Eo , \&Ec Ta generic enclosure
    +.El
    +.Ss Text production
    +.Bl -column "Brq, Bro, Brc" description
    +.It Sx \&Ex Fl std Ta standard command exit values: Op Ar utility ...
    +.It Sx \&Rv Fl std Ta standard function return values: Op Ar function ...
    +.It Sx \&St Ta reference to a standards document (one argument)
    +.It Sx \&At Ta At
    +.It Sx \&Bx Ta Bx
    +.It Sx \&Bsx Ta Bsx
    +.It Sx \&Nx Ta Nx
    +.It Sx \&Fx Ta Fx
    +.It Sx \&Ox Ta Ox
    +.It Sx \&Dx Ta Dx
    +.El
    +.Sh MACRO REFERENCE
    +This section is a canonical reference of all macros, arranged
    +alphabetically.
    +For the scoping of individual macros, see
    +.Sx MACRO SYNTAX .
    +.Ss \&%A
    +Author name of an
    +.Sx \&Rs
    +block.
    +Multiple authors should each be accorded their own
    +.Sx \%%A
    +line.
    +Author names should be ordered with full or abbreviated forename(s)
    +first, then full surname.
    +.Ss \&%B
    +Book title of an
    +.Sx \&Rs
    +block.
    +This macro may also be used in a non-bibliographic context when
    +referring to book titles.
    +.Ss \&%C
    +Publication city or location of an
    +.Sx \&Rs
    +block.
    +.Ss \&%D
    +Publication date of an
    +.Sx \&Rs
    +block.
    +Recommended formats of arguments are
    +.Ar month day , year
    +or just
    +.Ar year .
    +.Ss \&%I
    +Publisher or issuer name of an
    +.Sx \&Rs
    +block.
    +.Ss \&%J
    +Journal name of an
    +.Sx \&Rs
    +block.
    +.Ss \&%N
    +Issue number (usually for journals) of an
    +.Sx \&Rs
    +block.
    +.Ss \&%O
    +Optional information of an
    +.Sx \&Rs
    +block.
    +.Ss \&%P
    +Book or journal page number of an
    +.Sx \&Rs
    +block.
    +.Ss \&%Q
    +Institutional author (school, government, etc.) of an
    +.Sx \&Rs
    +block.
    +Multiple institutional authors should each be accorded their own
    +.Sx \&%Q
    +line.
    +.Ss \&%R
    +Technical report name of an
    +.Sx \&Rs
    +block.
    +.Ss \&%T
    +Article title of an
    +.Sx \&Rs
    +block.
    +This macro may also be used in a non-bibliographical context when
    +referring to article titles.
    +.Ss \&%U
    +URI of reference document.
    +.Ss \&%V
    +Volume number of an
    +.Sx \&Rs
    +block.
    +.Ss \&Ac
    +Close an
    +.Sx \&Ao
    +block.
    +Does not have any tail arguments.
    +.Ss \&Ad
    +Memory address.
    +Do not use this for postal addresses.
    +.Pp
    +Examples:
    +.Dl \&.Ad [0,$]
    +.Dl \&.Ad 0x00000000
    +.Ss \&An
    +Author name.
    +Can be used both for the authors of the program, function, or driver
    +documented in the manual, or for the authors of the manual itself.
    +Requires either the name of an author or one of the following arguments:
    +.Pp
    +.Bl -tag -width "-nosplitX" -offset indent -compact
    +.It Fl split
    +Start a new output line before each subsequent invocation of
    +.Sx \&An .
    +.It Fl nosplit
    +The opposite of
    +.Fl split .
    +.El
    +.Pp
    +The default is
    +.Fl nosplit .
    +The effect of selecting either of the
    +.Fl split
    +modes ends at the beginning of the
    +.Em AUTHORS
    +section.
    +In the
    +.Em AUTHORS
    +section, the default is
    +.Fl nosplit
    +for the first author listing and
    +.Fl split
    +for all other author listings.
    +.Pp
    +Examples:
    +.Dl \&.An -nosplit
    +.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv
    +.Ss \&Ao
    +Begin a block enclosed by angle brackets.
    +Does not have any head arguments.
    +This macro is almost never useful.
    +See
    +.Sx \&Aq
    +for more details.
    +.Ss \&Ap
    +Inserts an apostrophe without any surrounding whitespace.
    +This is generally used as a grammatical device when referring to the verb
    +form of a function.
    +.Pp
    +Examples:
    +.Dl \&.Fn execve \&Ap d
    +.Ss \&Aq
    +Encloses its arguments in angle brackets.
    +The only important use case is for email addresses.
    +See
    +.Sx \&Mt
    +for an example.
    +.Pp
    +Occasionally, it is used for names of characters and keys, for example:
    +.Bd -literal -offset indent
    +Press the
    +\&.Aq escape
    +key to ...
    +.Ed
    +.Pp
    +For URIs, use
    +.Sx \&Lk
    +instead, and
    +.Sx \&In
    +for
    +.Dq #include
    +directives.
    +Never wrap
    +.Sx \&Ar
    +in
    +.Sx \&Aq .
    +.Pp
    +Since
    +.Sx \&Aq
    +usually renders with non-ASCII characters in non-ASCII output modes,
    +do not use it where the ASCII characters
    +.Sq <
    +and
    +.Sq >
    +are required as syntax elements.
    +Instead, use these characters directly in such cases, combining them
    +with the macros
    +.Sx \&Pf ,
    +.Sx \&Ns ,
    +or
    +.Sx \&Eo
    +as needed.
    +.Pp
    +See also
    +.Sx \&Ao .
    +.Ss \&Ar
    +Command arguments.
    +If an argument is not provided, the string
    +.Dq file ...\&
    +is used as a default.
    +.Pp
    +Examples:
    +.Dl ".Fl o Ar file"
    +.Dl ".Ar"
    +.Dl ".Ar arg1 , arg2 ."
    +.Pp
    +The arguments to the
    +.Sx \&Ar
    +macro are names and placeholders for command arguments;
    +for fixed strings to be passed verbatim as arguments, use
    +.Sx \&Fl
    +or
    +.Sx \&Cm .
    +.Ss \&At
    +Formats an
    +.At
    +version.
    +Accepts one optional argument:
    +.Pp
    +.Bl -tag -width "v[1-7] | 32vX" -offset indent -compact
    +.It Cm v[1-7] | 32v
    +A version of
    +.At .
    +.It Cm III
    +.At III .
    +.It Cm V | V.[1-4]
    +A version of
    +.At V .
    +.El
    +.Pp
    +Note that these arguments do not begin with a hyphen.
    +.Pp
    +Examples:
    +.Dl \&.At
    +.Dl \&.At III
    +.Dl \&.At V.1
    +.Pp
    +See also
    +.Sx \&Bsx ,
    +.Sx \&Bx ,
    +.Sx \&Dx ,
    +.Sx \&Fx ,
    +.Sx \&Nx ,
    +and
    +.Sx \&Ox .
    +.Ss \&Bc
    +Close a
    +.Sx \&Bo
    +block.
    +Does not have any tail arguments.
    +.Ss \&Bd
    +Begin a display block.
    +Its syntax is as follows:
    +.Bd -ragged -offset indent
    +.Pf \. Sx \&Bd
    +.Fl Ns Ar type
    +.Op Fl offset Ar width
    +.Op Fl compact
    +.Ed
    +.Pp
    +Display blocks are used to select a different indentation and
    +justification than the one used by the surrounding text.
    +They may contain both macro lines and text lines.
    +By default, a display block is preceded by a vertical space.
    +.Pp
    +The
    +.Ar type
    +must be one of the following:
    +.Bl -tag -width 13n -offset indent
    +.It Fl centered
    +Produce one output line from each input line, and center-justify each line.
    +Using this display type is not recommended; many
    +.Nm
    +implementations render it poorly.
    +.It Fl filled
    +Change the positions of line breaks to fill each line, and left- and
    +right-justify the resulting block.
    +.It Fl literal
    +Produce one output line from each input line,
    +and do not justify the block at all.
    +Preserve white space as it appears in the input.
    +Always use a constant-width font.
    +Use this for displaying source code.
    +.It Fl ragged
    +Change the positions of line breaks to fill each line, and left-justify
    +the resulting block.
    +.It Fl unfilled
    +The same as
    +.Fl literal ,
    +but using the same font as for normal text, which is a variable width font
    +if supported by the output device.
    +.El
    +.Pp
    +The
    +.Ar type
    +must be provided first.
    +Additional arguments may follow:
    +.Bl -tag -width 13n -offset indent
    +.It Fl offset Ar width
    +Indent the display by the
    +.Ar width ,
    +which may be one of the following:
    +.Bl -item
    +.It
    +One of the pre-defined strings
    +.Cm indent ,
    +the width of a standard indentation (six constant width characters);
    +.Cm indent-two ,
    +twice
    +.Cm indent ;
    +.Cm left ,
    +which has no effect;
    +.Cm right ,
    +which justifies to the right margin; or
    +.Cm center ,
    +which aligns around an imagined center axis.
    +.It
    +A macro invocation, which selects a predefined width
    +associated with that macro.
    +The most popular is the imaginary macro
    +.Ar \&Ds ,
    +which resolves to
    +.Sy 6n .
    +.It
    +A scaling width as described in
    +.Xr roff 7 .
    +.It
    +An arbitrary string, which indents by the length of this string.
    +.El
    +.Pp
    +When the argument is missing,
    +.Fl offset
    +is ignored.
    +.It Fl compact
    +Do not assert vertical space before the display.
    +.El
    +.Pp
    +Examples:
    +.Bd -literal -offset indent
    +\&.Bd \-literal \-offset indent \-compact
    +   Hello       world.
    +\&.Ed
    +.Ed
    +.Pp
    +See also
    +.Sx \&D1
    +and
    +.Sx \&Dl .
    +.Ss \&Bf
    +Change the font mode for a scoped block of text.
    +Its syntax is as follows:
    +.Bd -ragged -offset indent
    +.Pf \. Sx \&Bf
    +.Oo
    +.Fl emphasis | literal | symbolic |
    +.Cm \&Em | \&Li | \&Sy
    +.Oc
    +.Ed
    +.Pp
    +The
    +.Fl emphasis
    +and
    +.Cm \&Em
    +argument are equivalent, as are
    +.Fl symbolic
    +and
    +.Cm \&Sy ,
    +and
    +.Fl literal
    +and
    +.Cm \&Li .
    +Without an argument, this macro does nothing.
    +The font mode continues until broken by a new font mode in a nested
    +scope or
    +.Sx \&Ef
    +is encountered.
    +.Pp
    +See also
    +.Sx \&Li ,
    +.Sx \&Ef ,
    +.Sx \&Em ,
    +and
    +.Sx \&Sy .
    +.Ss \&Bk
    +For each macro, keep its output together on the same output line,
    +until the end of the macro or the end of the input line is reached,
    +whichever comes first.
    +Line breaks in text lines are unaffected.
    +The syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Bk Fl words
    +.Pp
    +The
    +.Fl words
    +argument is required; additional arguments are ignored.
    +.Pp
    +The following example will not break within each
    +.Sx \&Op
    +macro line:
    +.Bd -literal -offset indent
    +\&.Bk \-words
    +\&.Op Fl f Ar flags
    +\&.Op Fl o Ar output
    +\&.Ek
    +.Ed
    +.Pp
    +Be careful in using over-long lines within a keep block!
    +Doing so will clobber the right margin.
    +.Ss \&Bl
    +Begin a list.
    +Lists consist of items specified using the
    +.Sx \&It
    +macro, containing a head or a body or both.
    +The list syntax is as follows:
    +.Bd -ragged -offset indent
    +.Pf \. Sx \&Bl
    +.Fl Ns Ar type
    +.Op Fl width Ar val
    +.Op Fl offset Ar val
    +.Op Fl compact
    +.Op HEAD ...
    +.Ed
    +.Pp
    +The list
    +.Ar type
    +is mandatory and must be specified first.
    +The
    +.Fl width
    +and
    +.Fl offset
    +arguments accept macro names as described for
    +.Sx \&Bd
    +.Fl offset ,
    +scaling widths as described in
    +.Xr roff 7 ,
    +or use the length of the given string.
    +The
    +.Fl offset
    +is a global indentation for the whole list, affecting both item heads
    +and bodies.
    +For those list types supporting it, the
    +.Fl width
    +argument requests an additional indentation of item bodies,
    +to be added to the
    +.Fl offset .
    +Unless the
    +.Fl compact
    +argument is specified, list entries are separated by vertical space.
    +.Pp
    +A list must specify one of the following list types:
    +.Bl -tag -width 12n -offset indent
    +.It Fl bullet
    +No item heads can be specified, but a bullet will be printed at the head
    +of each item.
    +Item bodies start on the same output line as the bullet
    +and are indented according to the
    +.Fl width
    +argument.
    +.It Fl column
    +A columnated list.
    +The
    +.Fl width
    +argument has no effect; instead, the string length of each argument
    +specifies the width of one column.
    +If the first line of the body of a
    +.Fl column
    +list is not an
    +.Sx \&It
    +macro line,
    +.Sx \&It
    +contexts spanning one input line each are implied until an
    +.Sx \&It
    +macro line is encountered, at which point items start being interpreted as
    +described in the
    +.Sx \&It
    +documentation.
    +.It Fl dash
    +Like
    +.Fl bullet ,
    +except that dashes are used in place of bullets.
    +.It Fl diag
    +Like
    +.Fl inset ,
    +except that item heads are not parsed for macro invocations.
    +Most often used in the
    +.Em DIAGNOSTICS
    +section with error constants in the item heads.
    +.It Fl enum
    +A numbered list.
    +No item heads can be specified.
    +Formatted like
    +.Fl bullet ,
    +except that cardinal numbers are used in place of bullets,
    +starting at 1.
    +.It Fl hang
    +Like
    +.Fl tag ,
    +except that the first lines of item bodies are not indented, but follow
    +the item heads like in
    +.Fl inset
    +lists.
    +.It Fl hyphen
    +Synonym for
    +.Fl dash .
    +.It Fl inset
    +Item bodies follow items heads on the same line, using normal inter-word
    +spacing.
    +Bodies are not indented, and the
    +.Fl width
    +argument is ignored.
    +.It Fl item
    +No item heads can be specified, and none are printed.
    +Bodies are not indented, and the
    +.Fl width
    +argument is ignored.
    +.It Fl ohang
    +Item bodies start on the line following item heads and are not indented.
    +The
    +.Fl width
    +argument is ignored.
    +.It Fl tag
    +Item bodies are indented according to the
    +.Fl width
    +argument.
    +When an item head fits inside the indentation, the item body follows
    +this head on the same output line.
    +Otherwise, the body starts on the output line following the head.
    +.El
    +.Pp
    +Lists may be nested within lists and displays.
    +Nesting of
    +.Fl column
    +and
    +.Fl enum
    +lists may not be portable.
    +.Pp
    +See also
    +.Sx \&El
    +and
    +.Sx \&It .
    +.Ss \&Bo
    +Begin a block enclosed by square brackets.
    +Does not have any head arguments.
    +.Pp
    +Examples:
    +.Bd -literal -offset indent -compact
    +\&.Bo 1 ,
    +\&.Dv BUFSIZ \&Bc
    +.Ed
    +.Pp
    +See also
    +.Sx \&Bq .
    +.Ss \&Bq
    +Encloses its arguments in square brackets.
    +.Pp
    +Examples:
    +.Dl \&.Bq 1 , \&Dv BUFSIZ
    +.Pp
    +.Em Remarks :
    +this macro is sometimes abused to emulate optional arguments for
    +commands; the correct macros to use for this purpose are
    +.Sx \&Op ,
    +.Sx \&Oo ,
    +and
    +.Sx \&Oc .
    +.Pp
    +See also
    +.Sx \&Bo .
    +.Ss \&Brc
    +Close a
    +.Sx \&Bro
    +block.
    +Does not have any tail arguments.
    +.Ss \&Bro
    +Begin a block enclosed by curly braces.
    +Does not have any head arguments.
    +.Pp
    +Examples:
    +.Bd -literal -offset indent -compact
    +\&.Bro 1 , ... ,
    +\&.Va n \&Brc
    +.Ed
    +.Pp
    +See also
    +.Sx \&Brq .
    +.Ss \&Brq
    +Encloses its arguments in curly braces.
    +.Pp
    +Examples:
    +.Dl \&.Brq 1 , ... , \&Va n
    +.Pp
    +See also
    +.Sx \&Bro .
    +.Ss \&Bsx
    +Format the
    +.Bsx
    +version provided as an argument, or a default value if
    +no argument is provided.
    +.Pp
    +Examples:
    +.Dl \&.Bsx 1.0
    +.Dl \&.Bsx
    +.Pp
    +See also
    +.Sx \&At ,
    +.Sx \&Bx ,
    +.Sx \&Dx ,
    +.Sx \&Fx ,
    +.Sx \&Nx ,
    +and
    +.Sx \&Ox .
    +.Ss \&Bt
    +Supported only for compatibility, do not use this in new manuals.
    +Prints
    +.Dq is currently in beta test.
    +.Ss \&Bx
    +Format the
    +.Bx
    +version provided as an argument, or a default value if no
    +argument is provided.
    +.Pp
    +Examples:
    +.Dl \&.Bx 4.3 Tahoe
    +.Dl \&.Bx 4.4
    +.Dl \&.Bx
    +.Pp
    +See also
    +.Sx \&At ,
    +.Sx \&Bsx ,
    +.Sx \&Dx ,
    +.Sx \&Fx ,
    +.Sx \&Nx ,
    +and
    +.Sx \&Ox .
    +.Ss \&Cd
    +Kernel configuration declaration.
    +This denotes strings accepted by
    +.Xr config 8 .
    +It is most often used in section 4 manual pages.
    +.Pp
    +Examples:
    +.Dl \&.Cd device le0 at scode?
    +.Pp
    +.Em Remarks :
    +this macro is commonly abused by using quoted literals to retain
    +whitespace and align consecutive
    +.Sx \&Cd
    +declarations.
    +This practise is discouraged.
    +.Ss \&Cm
    +Command modifiers.
    +Typically used for fixed strings passed as arguments, unless
    +.Sx \&Fl
    +is more appropriate.
    +Also useful when specifying configuration options or keys.
    +.Pp
    +Examples:
    +.Dl ".Nm mt Fl f Ar device Cm rewind"
    +.Dl ".Nm ps Fl o Cm pid , Ns Cm command"
    +.Dl ".Nm dd Cm if= Ns Ar file1 Cm of= Ns Ar file2"
    +.Dl ".Cm IdentityFile Pa ~/.ssh/id_rsa"
    +.Dl ".Cm LogLevel Dv DEBUG"
    +.Ss \&D1
    +One-line indented display.
    +This is formatted by the default rules and is useful for simple indented
    +statements.
    +It is followed by a newline.
    +.Pp
    +Examples:
    +.Dl \&.D1 \&Fl abcdefgh
    +.Pp
    +See also
    +.Sx \&Bd
    +and
    +.Sx \&Dl .
    +.Ss \&Db
    +This macro is obsolete.
    +No replacement is needed.
    +It is ignored by
    +.Xr mandoc 1
    +and groff including its arguments.
    +It was formerly used to toggle a debugging mode.
    +.Ss \&Dc
    +Close a
    +.Sx \&Do
    +block.
    +Does not have any tail arguments.
    +.Ss \&Dd
    +Document date for display in the page footer.
    +This is the mandatory first macro of any
    +.Nm
    +manual.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Dd Ar month day , year
    +.Pp
    +The
    +.Ar month
    +is the full English month name, the
    +.Ar day
    +is an integer number, and the
    +.Ar year
    +is the full four-digit year.
    +.Pp
    +Other arguments are not portable; the
    +.Xr mandoc 1
    +utility handles them as follows:
    +.Bl -dash -offset 3n -compact
    +.It
    +To have the date automatically filled in by the
    +.Ox
    +version of
    +.Xr cvs 1 ,
    +the special string
    +.Dq $\&Mdocdate$
    +can be given as an argument.
    +.It
    +The traditional, purely numeric
    +.Xr man 7
    +format
    +.Ar year Ns \(en Ns Ar month Ns \(en Ns Ar day
    +is accepted, too.
    +.It
    +If a date string cannot be parsed, it is used verbatim.
    +.It
    +If no date string is given, the current date is used.
    +.El
    +.Pp
    +Examples:
    +.Dl \&.Dd $\&Mdocdate$
    +.Dl \&.Dd $\&Mdocdate: July 2 2018$
    +.Dl \&.Dd July 2, 2018
    +.Pp
    +See also
    +.Sx \&Dt
    +and
    +.Sx \&Os .
    +.Ss \&Dl
    +One-line indented display.
    +This is formatted as literal text and is useful for commands and
    +invocations.
    +It is followed by a newline.
    +.Pp
    +Examples:
    +.Dl \&.Dl % mandoc mdoc.7 \e(ba less
    +.Pp
    +See also
    +.Sx \&Ql ,
    +.Sx \&Bd
    +.Fl literal ,
    +and
    +.Sx \&D1 .
    +.Ss \&Do
    +Begin a block enclosed by double quotes.
    +Does not have any head arguments.
    +.Pp
    +Examples:
    +.Bd -literal -offset indent -compact
    +\&.Do
    +April is the cruellest month
    +\&.Dc
    +\e(em T.S. Eliot
    +.Ed
    +.Pp
    +See also
    +.Sx \&Dq .
    +.Ss \&Dq
    +Encloses its arguments in
    +.Dq typographic
    +double-quotes.
    +.Pp
    +Examples:
    +.Bd -literal -offset indent -compact
    +\&.Dq April is the cruellest month
    +\e(em T.S. Eliot
    +.Ed
    +.Pp
    +See also
    +.Sx \&Qq ,
    +.Sx \&Sq ,
    +and
    +.Sx \&Do .
    +.Ss \&Dt
    +Document title for display in the page header.
    +This is the mandatory second macro of any
    +.Nm
    +file.
    +Its syntax is as follows:
    +.Bd -ragged -offset indent
    +.Pf \. Sx \&Dt
    +.Ar TITLE
    +.Ar section
    +.Op Ar arch
    +.Ed
    +.Pp
    +Its arguments are as follows:
    +.Bl -tag -width section -offset 2n
    +.It Ar TITLE
    +The document's title (name), defaulting to
    +.Dq UNTITLED
    +if unspecified.
    +To achieve a uniform appearance of page header lines,
    +it should by convention be all caps.
    +.It Ar section
    +The manual section.
    +This may be one of
    +.Cm 1
    +.Pq General Commands ,
    +.Cm 2
    +.Pq System Calls ,
    +.Cm 3
    +.Pq Library Functions ,
    +.Cm 3p
    +.Pq Perl Library ,
    +.Cm 4
    +.Pq Device Drivers ,
    +.Cm 5
    +.Pq File Formats ,
    +.Cm 6
    +.Pq Games ,
    +.Cm 7
    +.Pq Miscellaneous Information ,
    +.Cm 8
    +.Pq System Manager's Manual ,
    +or
    +.Cm 9
    +.Pq Kernel Developer's Manual .
    +It should correspond to the manual's filename suffix and defaults to
    +the empty string if unspecified.
    +.It Ar arch
    +This specifies the machine architecture a manual page applies to,
    +where relevant, for example
    +.Cm alpha ,
    +.Cm amd64 ,
    +.Cm i386 ,
    +or
    +.Cm sparc64 .
    +The list of valid architectures varies by operating system.
    +.El
    +.Pp
    +Examples:
    +.Dl \&.Dt FOO 1
    +.Dl \&.Dt FOO 9 i386
    +.Pp
    +See also
    +.Sx \&Dd
    +and
    +.Sx \&Os .
    +.Ss \&Dv
    +Defined variables such as preprocessor constants, constant symbols,
    +enumeration values, and so on.
    +.Pp
    +Examples:
    +.Dl \&.Dv NULL
    +.Dl \&.Dv BUFSIZ
    +.Dl \&.Dv STDOUT_FILENO
    +.Pp
    +See also
    +.Sx \&Er
    +and
    +.Sx \&Ev
    +for special-purpose constants,
    +.Sx \&Va
    +for variable symbols, and
    +.Sx \&Fd
    +for listing preprocessor variable definitions in the
    +.Em SYNOPSIS .
    +.Ss \&Dx
    +Format the
    +.Dx
    +version provided as an argument, or a default
    +value if no argument is provided.
    +.Pp
    +Examples:
    +.Dl \&.Dx 2.4.1
    +.Dl \&.Dx
    +.Pp
    +See also
    +.Sx \&At ,
    +.Sx \&Bsx ,
    +.Sx \&Bx ,
    +.Sx \&Fx ,
    +.Sx \&Nx ,
    +and
    +.Sx \&Ox .
    +.Ss \&Ec
    +Close a scope started by
    +.Sx \&Eo .
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Ec Op Ar TERM
    +.Pp
    +The
    +.Ar TERM
    +argument is used as the enclosure tail, for example, specifying \e(rq
    +will emulate
    +.Sx \&Dc .
    +.Ss \&Ed
    +End a display context started by
    +.Sx \&Bd .
    +.Ss \&Ef
    +End a font mode context started by
    +.Sx \&Bf .
    +.Ss \&Ek
    +End a keep context started by
    +.Sx \&Bk .
    +.Ss \&El
    +End a list context started by
    +.Sx \&Bl .
    +.Pp
    +See also
    +.Sx \&Bl
    +and
    +.Sx \&It .
    +.Ss \&Em
    +Request an italic font.
    +If the output device does not provide that, underline.
    +.Pp
    +This is most often used for stress emphasis (not to be confused with
    +importance, see
    +.Sx \&Sy ) .
    +In the rare cases where none of the semantic markup macros fit,
    +it can also be used for technical terms and placeholders, except
    +that for syntax elements,
    +.Sx \&Sy
    +and
    +.Sx \&Ar
    +are preferred, respectively.
    +.Pp
    +Examples:
    +.Bd -literal -compact -offset indent
    +Selected lines are those
    +\&.Em not
    +matching any of the specified patterns.
    +Some of the functions use a
    +\&.Em hold space
    +to save the pattern space for subsequent retrieval.
    +.Ed
    +.Pp
    +See also
    +.Sx \&Bf ,
    +.Sx \&Li ,
    +.Sx \&No ,
    +and
    +.Sx \&Sy .
    +.Ss \&En
    +This macro is obsolete.
    +Use
    +.Sx \&Eo
    +or any of the other enclosure macros.
    +.Pp
    +It encloses its argument in the delimiters specified by the last
    +.Sx \&Es
    +macro.
    +.Ss \&Eo
    +An arbitrary enclosure.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Eo Op Ar TERM
    +.Pp
    +The
    +.Ar TERM
    +argument is used as the enclosure head, for example, specifying \e(lq
    +will emulate
    +.Sx \&Do .
    +.Ss \&Er
    +Error constants for definitions of the
    +.Va errno
    +libc global variable.
    +This is most often used in section 2 and 3 manual pages.
    +.Pp
    +Examples:
    +.Dl \&.Er EPERM
    +.Dl \&.Er ENOENT
    +.Pp
    +See also
    +.Sx \&Dv
    +for general constants.
    +.Ss \&Es
    +This macro is obsolete.
    +Use
    +.Sx \&Eo
    +or any of the other enclosure macros.
    +.Pp
    +It takes two arguments, defining the delimiters to be used by subsequent
    +.Sx \&En
    +macros.
    +.Ss \&Ev
    +Environmental variables such as those specified in
    +.Xr environ 7 .
    +.Pp
    +Examples:
    +.Dl \&.Ev DISPLAY
    +.Dl \&.Ev PATH
    +.Pp
    +See also
    +.Sx \&Dv
    +for general constants.
    +.Ss \&Ex
    +Insert a standard sentence regarding command exit values of 0 on success
    +and >0 on failure.
    +This is most often used in section 1, 6, and 8 manual pages.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Ex Fl std Op Ar utility ...
    +.Pp
    +If
    +.Ar utility
    +is not specified, the document's name set by
    +.Sx \&Nm
    +is used.
    +Multiple
    +.Ar utility
    +arguments are treated as separate utilities.
    +.Pp
    +See also
    +.Sx \&Rv .
    +.Ss \&Fa
    +Function argument or parameter.
    +Its syntax is as follows:
    +.Bd -ragged -offset indent
    +.Pf \. Sx \&Fa
    +.Qo
    +.Op Ar argtype
    +.Op Ar argname
    +.Qc Ar \&...
    +.Ed
    +.Pp
    +Each argument may be a name and a type (recommended for the
    +.Em SYNOPSIS
    +section), a name alone (for function invocations),
    +or a type alone (for function prototypes).
    +If both a type and a name are given or if the type consists of multiple
    +words, all words belonging to the same function argument have to be
    +given in a single argument to the
    +.Sx \&Fa
    +macro.
    +.Pp
    +This macro is also used to specify the field name of a structure.
    +.Pp
    +Most often, the
    +.Sx \&Fa
    +macro is used in the
    +.Em SYNOPSIS
    +within
    +.Sx \&Fo
    +blocks when documenting multi-line function prototypes.
    +If invoked with multiple arguments, the arguments are separated by a
    +comma.
    +Furthermore, if the following macro is another
    +.Sx \&Fa ,
    +the last argument will also have a trailing comma.
    +.Pp
    +Examples:
    +.Dl \&.Fa \(dqconst char *p\(dq
    +.Dl \&.Fa \(dqint a\(dq \(dqint b\(dq \(dqint c\(dq
    +.Dl \&.Fa \(dqchar *\(dq size_t
    +.Pp
    +See also
    +.Sx \&Fo .
    +.Ss \&Fc
    +End a function context started by
    +.Sx \&Fo .
    +.Ss \&Fd
    +Preprocessor directive, in particular for listing it in the
    +.Em SYNOPSIS .
    +Historically, it was also used to document include files.
    +The latter usage has been deprecated in favour of
    +.Sx \&In .
    +.Pp
    +Its syntax is as follows:
    +.Bd -ragged -offset indent
    +.Pf \. Sx \&Fd
    +.Li # Ns Ar directive
    +.Op Ar argument ...
    +.Ed
    +.Pp
    +Examples:
    +.Dl \&.Fd #define sa_handler __sigaction_u.__sa_handler
    +.Dl \&.Fd #define SIO_MAXNFDS
    +.Dl \&.Fd #ifdef FS_DEBUG
    +.Dl \&.Ft void
    +.Dl \&.Fn dbg_open \(dqconst char *\(dq
    +.Dl \&.Fd #endif
    +.Pp
    +See also
    +.Sx MANUAL STRUCTURE ,
    +.Sx \&In ,
    +and
    +.Sx \&Dv .
    +.Ss \&Fl
    +Command-line flag or option.
    +Used when listing arguments to command-line utilities.
    +Prints a fixed-width hyphen
    +.Sq \-
    +directly followed by each argument.
    +If no arguments are provided, a hyphen is printed followed by a space.
    +If the argument is a macro, a hyphen is prefixed to the subsequent macro
    +output.
    +.Pp
    +Examples:
    +.Dl ".Fl R Op Fl H | L | P"
    +.Dl ".Op Fl 1AaCcdFfgHhikLlmnopqRrSsTtux"
    +.Dl ".Fl type Cm d Fl name Pa CVS"
    +.Dl ".Fl Ar signal_number"
    +.Dl ".Fl o Fl"
    +.Pp
    +See also
    +.Sx \&Cm .
    +.Ss \&Fn
    +A function name.
    +Its syntax is as follows:
    +.Bd -ragged -offset indent
    +.Pf . Sx \&Fn
    +.Op Ar functype
    +.Ar funcname
    +.Op Oo Ar argtype Oc Ar argname
    +.Ed
    +.Pp
    +Function arguments are surrounded in parenthesis and
    +are delimited by commas.
    +If no arguments are specified, blank parenthesis are output.
    +In the
    +.Em SYNOPSIS
    +section, this macro starts a new output line,
    +and a blank line is automatically inserted between function definitions.
    +.Pp
    +Examples:
    +.Dl \&.Fn \(dqint funcname\(dq \(dqint arg0\(dq \(dqint arg1\(dq
    +.Dl \&.Fn funcname \(dqint arg0\(dq
    +.Dl \&.Fn funcname arg0
    +.Pp
    +.Bd -literal -offset indent -compact
    +\&.Ft functype
    +\&.Fn funcname
    +.Ed
    +.Pp
    +When referring to a function documented in another manual page, use
    +.Sx \&Xr
    +instead.
    +See also
    +.Sx MANUAL STRUCTURE ,
    +.Sx \&Fo ,
    +and
    +.Sx \&Ft .
    +.Ss \&Fo
    +Begin a function block.
    +This is a multi-line version of
    +.Sx \&Fn .
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Fo Ar funcname
    +.Pp
    +Invocations usually occur in the following context:
    +.Bd -ragged -offset indent
    +.Pf \. Sx \&Ft Ar functype
    +.br
    +.Pf \. Sx \&Fo Ar funcname
    +.br
    +.Pf \. Sx \&Fa Qq Ar argtype Ar argname
    +.br
    +\&.\.\.
    +.br
    +.Pf \. Sx \&Fc
    +.Ed
    +.Pp
    +A
    +.Sx \&Fo
    +scope is closed by
    +.Sx \&Fc .
    +.Pp
    +See also
    +.Sx MANUAL STRUCTURE ,
    +.Sx \&Fa ,
    +.Sx \&Fc ,
    +and
    +.Sx \&Ft .
    +.Ss \&Fr
    +This macro is obsolete.
    +No replacement markup is needed.
    +.Pp
    +It was used to show numerical function return values in an italic font.
    +.Ss \&Ft
    +A function type.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Ft Ar functype
    +.Pp
    +In the
    +.Em SYNOPSIS
    +section, a new output line is started after this macro.
    +.Pp
    +Examples:
    +.Dl \&.Ft int
    +.Bd -literal -offset indent -compact
    +\&.Ft functype
    +\&.Fn funcname
    +.Ed
    +.Pp
    +See also
    +.Sx MANUAL STRUCTURE ,
    +.Sx \&Fn ,
    +and
    +.Sx \&Fo .
    +.Ss \&Fx
    +Format the
    +.Fx
    +version provided as an argument, or a default value
    +if no argument is provided.
    +.Pp
    +Examples:
    +.Dl \&.Fx 7.1
    +.Dl \&.Fx
    +.Pp
    +See also
    +.Sx \&At ,
    +.Sx \&Bsx ,
    +.Sx \&Bx ,
    +.Sx \&Dx ,
    +.Sx \&Nx ,
    +and
    +.Sx \&Ox .
    +.Ss \&Hf
    +This macro is not implemented in
    +.Xr mandoc 1 .
    +.Pp
    +It was used to include the contents of a (header) file literally.
    +The syntax was:
    +.Pp
    +.Dl Pf . Sx \&Hf Ar filename
    +.Ss \&Ic
    +Designate an internal or interactive command.
    +This is similar to
    +.Sx \&Cm
    +but used for instructions rather than values.
    +.Pp
    +Examples:
    +.Dl \&.Ic :wq
    +.Dl \&.Ic hash
    +.Dl \&.Ic alias
    +.Pp
    +Note that using
    +.Sx \&Bd Fl literal
    +or
    +.Sx \&D1
    +is preferred for displaying code; the
    +.Sx \&Ic
    +macro is used when referring to specific instructions.
    +.Ss \&In
    +The name of an include file.
    +This macro is most often used in section 2, 3, and 9 manual pages.
    +.Pp
    +When invoked as the first macro on an input line in the
    +.Em SYNOPSIS
    +section, the argument is displayed in angle brackets
    +and preceded by
    +.Qq #include ,
    +and a blank line is inserted in front if there is a preceding
    +function declaration.
    +In other sections, it only encloses its argument in angle brackets
    +and causes no line break.
    +.Pp
    +Examples:
    +.Dl \&.In sys/types.h
    +.Pp
    +See also
    +.Sx MANUAL STRUCTURE .
    +.Ss \&It
    +A list item.
    +The syntax of this macro depends on the list type.
    +.Pp
    +Lists
    +of type
    +.Fl hang ,
    +.Fl ohang ,
    +.Fl inset ,
    +and
    +.Fl diag
    +have the following syntax:
    +.Pp
    +.D1 Pf \. Sx \&It Ar args
    +.Pp
    +Lists of type
    +.Fl bullet ,
    +.Fl dash ,
    +.Fl enum ,
    +.Fl hyphen
    +and
    +.Fl item
    +have the following syntax:
    +.Pp
    +.D1 Pf \. Sx \&It
    +.Pp
    +with subsequent lines interpreted within the scope of the
    +.Sx \&It
    +until either a closing
    +.Sx \&El
    +or another
    +.Sx \&It .
    +.Pp
    +The
    +.Fl tag
    +list has the following syntax:
    +.Pp
    +.D1 Pf \. Sx \&It Op Cm args
    +.Pp
    +Subsequent lines are interpreted as with
    +.Fl bullet
    +and family.
    +The line arguments correspond to the list's left-hand side; body
    +arguments correspond to the list's contents.
    +.Pp
    +The
    +.Fl column
    +list is the most complicated.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&It Ar cell Op Sx \&Ta Ar cell ...
    +.D1 Pf \. Sx \&It Ar cell Op <TAB> Ar cell ...
    +.Pp
    +The arguments consist of one or more lines of text and macros
    +representing a complete table line.
    +Cells within the line are delimited by the special
    +.Sx \&Ta
    +block macro or by literal tab characters.
    +.Pp
    +Using literal tabs is strongly discouraged because they are very
    +hard to use correctly and
    +.Nm
    +code using them is very hard to read.
    +In particular, a blank character is syntactically significant
    +before and after the literal tab character.
    +If a word precedes or follows the tab without an intervening blank,
    +that word is never interpreted as a macro call, but always output
    +literally.
    +.Pp
    +The tab cell delimiter may only be used within the
    +.Sx \&It
    +line itself; on following lines, only the
    +.Sx \&Ta
    +macro can be used to delimit cells, and portability requires that
    +.Sx \&Ta
    +is called by other macros: some parsers do not recognize it when
    +it appears as the first macro on a line.
    +.Pp
    +Note that quoted strings may span tab-delimited cells on an
    +.Sx \&It
    +line.
    +For example,
    +.Pp
    +.Dl .It \(dqcol1 ,\& <TAB> col2 ,\(dq \&;
    +.Pp
    +will preserve the whitespace before both commas,
    +but not the whitespace before the semicolon.
    +.Pp
    +See also
    +.Sx \&Bl .
    +.Ss \&Lb
    +Specify a library.
    +The syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Lb Ar library
    +.Pp
    +The
    +.Ar library
    +parameter may be a system library, such as
    +.Cm libz
    +or
    +.Cm libpam ,
    +in which case a small library description is printed next to the linker
    +invocation; or a custom library, in which case the library name is
    +printed in quotes.
    +This is most commonly used in the
    +.Em SYNOPSIS
    +section as described in
    +.Sx MANUAL STRUCTURE .
    +.Pp
    +Examples:
    +.Dl \&.Lb libz
    +.Dl \&.Lb libmandoc
    +.Ss \&Li
    +Denotes text that should be in a
    +.Li literal
    +font mode.
    +Note that this is a presentation term and should not be used for
    +stylistically decorating technical terms.
    +.Pp
    +On terminal output devices, this is often indistinguishable from
    +normal text.
    +.Pp
    +See also
    +.Sx \&Bf ,
    +.Sx \&Em ,
    +.Sx \&No ,
    +and
    +.Sx \&Sy .
    +.Ss \&Lk
    +Format a hyperlink.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Lk Ar uri Op Ar name
    +.Pp
    +Examples:
    +.Dl \&.Lk http://bsd.lv \(dqThe BSD.lv Project\(dq
    +.Dl \&.Lk http://bsd.lv
    +.Pp
    +See also
    +.Sx \&Mt .
    +.Ss \&Lp
    +Synonym for
    +.Sx \&Pp .
    +.Ss \&Ms
    +Display a mathematical symbol.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Ms Ar symbol
    +.Pp
    +Examples:
    +.Dl \&.Ms sigma
    +.Dl \&.Ms aleph
    +.Ss \&Mt
    +Format a
    +.Dq mailto:
    +hyperlink.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Mt Ar address
    +.Pp
    +Examples:
    +.Dl \&.Mt discuss@manpages.bsd.lv
    +.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv
    +.Ss \&Nd
    +A one line description of the manual's content.
    +This is the mandatory last macro of the
    +.Em NAME
    +section and not appropriate for other sections.
    +.Pp
    +Examples:
    +.Dl Pf . Sx \&Nd mdoc language reference
    +.Dl Pf . Sx \&Nd format and display UNIX manuals
    +.Pp
    +The
    +.Sx \&Nd
    +macro technically accepts child macros and terminates with a subsequent
    +.Sx \&Sh
    +invocation.
    +Do not assume this behaviour: some
    +.Xr whatis 1
    +database generators are not smart enough to parse more than the line
    +arguments and will display macros verbatim.
    +.Pp
    +See also
    +.Sx \&Nm .
    +.Ss \&Nm
    +The name of the manual page, or \(em in particular in section 1, 6,
    +and 8 pages \(em of an additional command or feature documented in
    +the manual page.
    +When first invoked, the
    +.Sx \&Nm
    +macro expects a single argument, the name of the manual page.
    +Usually, the first invocation happens in the
    +.Em NAME
    +section of the page.
    +The specified name will be remembered and used whenever the macro is
    +called again without arguments later in the page.
    +The
    +.Sx \&Nm
    +macro uses
    +.Sx Block full-implicit
    +semantics when invoked as the first macro on an input line in the
    +.Em SYNOPSIS
    +section; otherwise, it uses ordinary
    +.Sx In-line
    +semantics.
    +.Pp
    +Examples:
    +.Bd -literal -offset indent
    +\&.Sh SYNOPSIS
    +\&.Nm cat
    +\&.Op Fl benstuv
    +\&.Op Ar
    +.Ed
    +.Pp
    +In the
    +.Em SYNOPSIS
    +of section 2, 3 and 9 manual pages, use the
    +.Sx \&Fn
    +macro rather than
    +.Sx \&Nm
    +to mark up the name of the manual page.
    +.Ss \&No
    +Normal text.
    +Closes the scope of any preceding in-line macro.
    +When used after physical formatting macros like
    +.Sx \&Em
    +or
    +.Sx \&Sy ,
    +switches back to the standard font face and weight.
    +Can also be used to embed plain text strings in macro lines
    +using semantic annotation macros.
    +.Pp
    +Examples:
    +.Dl ".Em italic , Sy bold , No and roman"
    +.Pp
    +.Bd -literal -offset indent -compact
    +\&.Sm off
    +\&.Cm :C No / Ar pattern No / Ar replacement No /
    +\&.Sm on
    +.Ed
    +.Pp
    +See also
    +.Sx \&Em ,
    +.Sx \&Li ,
    +and
    +.Sx \&Sy .
    +.Ss \&Ns
    +Suppress a space between the output of the preceding macro
    +and the following text or macro.
    +Following invocation, input is interpreted as normal text
    +just like after an
    +.Sx \&No
    +macro.
    +.Pp
    +This has no effect when invoked at the start of a macro line.
    +.Pp
    +Examples:
    +.Dl ".Ar name Ns = Ns Ar value"
    +.Dl ".Cm :M Ns Ar pattern"
    +.Dl ".Fl o Ns Ar output"
    +.Pp
    +See also
    +.Sx \&No
    +and
    +.Sx \&Sm .
    +.Ss \&Nx
    +Format the
    +.Nx
    +version provided as an argument, or a default value if
    +no argument is provided.
    +.Pp
    +Examples:
    +.Dl \&.Nx 5.01
    +.Dl \&.Nx
    +.Pp
    +See also
    +.Sx \&At ,
    +.Sx \&Bsx ,
    +.Sx \&Bx ,
    +.Sx \&Dx ,
    +.Sx \&Fx ,
    +and
    +.Sx \&Ox .
    +.Ss \&Oc
    +Close multi-line
    +.Sx \&Oo
    +context.
    +.Ss \&Oo
    +Multi-line version of
    +.Sx \&Op .
    +.Pp
    +Examples:
    +.Bd -literal -offset indent -compact
    +\&.Oo
    +\&.Op Fl flag Ns Ar value
    +\&.Oc
    +.Ed
    +.Ss \&Op
    +Optional part of a command line.
    +Prints the argument(s) in brackets.
    +This is most often used in the
    +.Em SYNOPSIS
    +section of section 1 and 8 manual pages.
    +.Pp
    +Examples:
    +.Dl \&.Op \&Fl a \&Ar b
    +.Dl \&.Op \&Ar a | b
    +.Pp
    +See also
    +.Sx \&Oo .
    +.Ss \&Os
    +Operating system version for display in the page footer.
    +This is the mandatory third macro of
    +any
    +.Nm
    +file.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Os Op Ar system Op Ar version
    +.Pp
    +The optional
    +.Ar system
    +parameter specifies the relevant operating system or environment.
    +It is suggested to leave it unspecified, in which case
    +.Xr mandoc 1
    +uses its
    +.Fl Ios
    +argument or, if that isn't specified either,
    +.Fa sysname
    +and
    +.Fa release
    +as returned by
    +.Xr uname 3 .
    +.Pp
    +Examples:
    +.Dl \&.Os
    +.Dl \&.Os KTH/CSC/TCS
    +.Dl \&.Os BSD 4.3
    +.Pp
    +See also
    +.Sx \&Dd
    +and
    +.Sx \&Dt .
    +.Ss \&Ot
    +This macro is obsolete.
    +Use
    +.Sx \&Ft
    +instead; with
    +.Xr mandoc 1 ,
    +both have the same effect.
    +.Pp
    +Historical
    +.Nm
    +packages described it as
    +.Dq "old function type (FORTRAN)" .
    +.Ss \&Ox
    +Format the
    +.Ox
    +version provided as an argument, or a default value
    +if no argument is provided.
    +.Pp
    +Examples:
    +.Dl \&.Ox 4.5
    +.Dl \&.Ox
    +.Pp
    +See also
    +.Sx \&At ,
    +.Sx \&Bsx ,
    +.Sx \&Bx ,
    +.Sx \&Dx ,
    +.Sx \&Fx ,
    +and
    +.Sx \&Nx .
    +.Ss \&Pa
    +An absolute or relative file system path, or a file or directory name.
    +If an argument is not provided, the character
    +.Sq \(ti
    +is used as a default.
    +.Pp
    +Examples:
    +.Dl \&.Pa /usr/bin/mandoc
    +.Dl \&.Pa /usr/share/man/man7/mdoc.7
    +.Pp
    +See also
    +.Sx \&Lk .
    +.Ss \&Pc
    +Close parenthesised context opened by
    +.Sx \&Po .
    +.Ss \&Pf
    +Removes the space between its argument and the following macro.
    +Its syntax is as follows:
    +.Pp
    +.D1 .Pf Ar prefix macro arguments ...
    +.Pp
    +This is equivalent to:
    +.Pp
    +.D1 .No \e& Ns Ar prefix No \&Ns Ar macro arguments ...
    +.Pp
    +The
    +.Ar prefix
    +argument is not parsed for macro names or delimiters,
    +but used verbatim as if it were escaped.
    +.Pp
    +Examples:
    +.Dl ".Pf $ Ar variable_name"
    +.Dl ".Pf . Ar macro_name"
    +.Dl ".Pf 0x Ar hex_digits"
    +.Pp
    +See also
    +.Sx \&Ns
    +and
    +.Sx \&Sm .
    +.Ss \&Po
    +Multi-line version of
    +.Sx \&Pq .
    +.Ss \&Pp
    +Break a paragraph.
    +This will assert vertical space between prior and subsequent macros
    +and/or text.
    +.Pp
    +Paragraph breaks are not needed before or after
    +.Sx \&Sh
    +or
    +.Sx \&Ss
    +macros or before displays
    +.Pq Sx \&Bd
    +or lists
    +.Pq Sx \&Bl
    +unless the
    +.Fl compact
    +flag is given.
    +.Ss \&Pq
    +Parenthesised enclosure.
    +.Pp
    +See also
    +.Sx \&Po .
    +.Ss \&Qc
    +Close quoted context opened by
    +.Sx \&Qo .
    +.Ss \&Ql
    +In-line literal display.
    +This can for example be used for complete command invocations and
    +for multi-word code fragments when more specific markup is not
    +appropriate and an indented display is not desired.
    +While
    +.Xr mandoc 1
    +always encloses the arguments in single quotes, other formatters
    +usually omit the quotes on non-terminal output devices when the
    +arguments have three or more characters.
    +.Pp
    +See also
    +.Sx \&Dl
    +and
    +.Sx \&Bd
    +.Fl literal .
    +.Ss \&Qo
    +Multi-line version of
    +.Sx \&Qq .
    +.Ss \&Qq
    +Encloses its arguments in
    +.Qq typewriter
    +double-quotes.
    +Consider using
    +.Sx \&Dq .
    +.Pp
    +See also
    +.Sx \&Dq ,
    +.Sx \&Sq ,
    +and
    +.Sx \&Qo .
    +.Ss \&Re
    +Close an
    +.Sx \&Rs
    +block.
    +Does not have any tail arguments.
    +.Ss \&Rs
    +Begin a bibliographic
    +.Pq Dq reference
    +block.
    +Does not have any head arguments.
    +The block macro may only contain
    +.Sx \&%A ,
    +.Sx \&%B ,
    +.Sx \&%C ,
    +.Sx \&%D ,
    +.Sx \&%I ,
    +.Sx \&%J ,
    +.Sx \&%N ,
    +.Sx \&%O ,
    +.Sx \&%P ,
    +.Sx \&%Q ,
    +.Sx \&%R ,
    +.Sx \&%T ,
    +.Sx \&%U ,
    +and
    +.Sx \&%V
    +child macros (at least one must be specified).
    +.Pp
    +Examples:
    +.Bd -literal -offset indent -compact
    +\&.Rs
    +\&.%A J. E. Hopcroft
    +\&.%A J. D. Ullman
    +\&.%B Introduction to Automata Theory, Languages, and Computation
    +\&.%I Addison-Wesley
    +\&.%C Reading, Massachusetts
    +\&.%D 1979
    +\&.Re
    +.Ed
    +.Pp
    +If an
    +.Sx \&Rs
    +block is used within a SEE ALSO section, a vertical space is asserted
    +before the rendered output, else the block continues on the current
    +line.
    +.Ss \&Rv
    +Insert a standard sentence regarding a function call's return value of 0
    +on success and \-1 on error, with the
    +.Va errno
    +libc global variable set on error.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Rv Fl std Op Ar function ...
    +.Pp
    +If
    +.Ar function
    +is not specified, the document's name set by
    +.Sx \&Nm
    +is used.
    +Multiple
    +.Ar function
    +arguments are treated as separate functions.
    +.Pp
    +See also
    +.Sx \&Ex .
    +.Ss \&Sc
    +Close single-quoted context opened by
    +.Sx \&So .
    +.Ss \&Sh
    +Begin a new section.
    +For a list of conventional manual sections, see
    +.Sx MANUAL STRUCTURE .
    +These sections should be used unless it's absolutely necessary that
    +custom sections be used.
    +.Pp
    +Section names should be unique so that they may be keyed by
    +.Sx \&Sx .
    +Although this macro is parsed, it should not consist of child node or it
    +may not be linked with
    +.Sx \&Sx .
    +.Pp
    +See also
    +.Sx \&Pp ,
    +.Sx \&Ss ,
    +and
    +.Sx \&Sx .
    +.Ss \&Sm
    +Switches the spacing mode for output generated from macros.
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Sm Op Cm on | off
    +.Pp
    +By default, spacing is
    +.Cm on .
    +When switched
    +.Cm off ,
    +no white space is inserted between macro arguments and between the
    +output generated from adjacent macros, but text lines
    +still get normal spacing between words and sentences.
    +.Pp
    +When called without an argument, the
    +.Sx \&Sm
    +macro toggles the spacing mode.
    +Using this is not recommended because it makes the code harder to read.
    +.Ss \&So
    +Multi-line version of
    +.Sx \&Sq .
    +.Ss \&Sq
    +Encloses its arguments in
    +.Sq typewriter
    +single-quotes.
    +.Pp
    +See also
    +.Sx \&Dq ,
    +.Sx \&Qq ,
    +and
    +.Sx \&So .
    +.Ss \&Ss
    +Begin a new subsection.
    +Unlike with
    +.Sx \&Sh ,
    +there is no convention for the naming of subsections.
    +Except
    +.Em DESCRIPTION ,
    +the conventional sections described in
    +.Sx MANUAL STRUCTURE
    +rarely have subsections.
    +.Pp
    +Sub-section names should be unique so that they may be keyed by
    +.Sx \&Sx .
    +Although this macro is parsed, it should not consist of child node or it
    +may not be linked with
    +.Sx \&Sx .
    +.Pp
    +See also
    +.Sx \&Pp ,
    +.Sx \&Sh ,
    +and
    +.Sx \&Sx .
    +.Ss \&St
    +Replace an abbreviation for a standard with the full form.
    +The following standards are recognised.
    +Where multiple lines are given without a blank line in between,
    +they all refer to the same standard, and using the first form
    +is recommended.
    +.Bl -tag -width 1n
    +.It C language standards
    +.Pp
    +.Bl -tag -width "-p1003.1g-2000" -compact
    +.It \-ansiC
    +.St -ansiC
    +.It \-ansiC-89
    +.St -ansiC-89
    +.It \-isoC
    +.St -isoC
    +.It \-isoC-90
    +.St -isoC-90
    +.br
    +The original C standard.
    +.Pp
    +.It \-isoC-amd1
    +.St -isoC-amd1
    +.Pp
    +.It \-isoC-tcor1
    +.St -isoC-tcor1
    +.Pp
    +.It \-isoC-tcor2
    +.St -isoC-tcor2
    +.Pp
    +.It \-isoC-99
    +.St -isoC-99
    +.br
    +The second major version of the C language standard.
    +.Pp
    +.It \-isoC-2011
    +.St -isoC-2011
    +.br
    +The third major version of the C language standard.
    +.El
    +.It POSIX.1 before the Single UNIX Specification
    +.Pp
    +.Bl -tag -width "-p1003.1g-2000" -compact
    +.It \-p1003.1-88
    +.St -p1003.1-88
    +.It \-p1003.1
    +.St -p1003.1
    +.br
    +The original POSIX standard, based on ANSI C.
    +.Pp
    +.It \-p1003.1-90
    +.St -p1003.1-90
    +.It \-iso9945-1-90
    +.St -iso9945-1-90
    +.br
    +The first update of POSIX.1.
    +.Pp
    +.It \-p1003.1b-93
    +.St -p1003.1b-93
    +.It \-p1003.1b
    +.St -p1003.1b
    +.br
    +Real-time extensions.
    +.Pp
    +.It \-p1003.1c-95
    +.St -p1003.1c-95
    +.br
    +POSIX thread interfaces.
    +.Pp
    +.It \-p1003.1i-95
    +.St -p1003.1i-95
    +.br
    +Technical Corrigendum.
    +.Pp
    +.It \-p1003.1-96
    +.St -p1003.1-96
    +.It \-iso9945-1-96
    +.St -iso9945-1-96
    +.br
    +Includes POSIX.1-1990, 1b, 1c, and 1i.
    +.El
    +.It X/Open Portability Guide version 4 and related standards
    +.Pp
    +.Bl -tag -width "-p1003.1g-2000" -compact
    +.It \-xpg3
    +.St -xpg3
    +.br
    +An XPG4 precursor, published in 1989.
    +.Pp
    +.It \-p1003.2
    +.St -p1003.2
    +.It \-p1003.2-92
    +.St -p1003.2-92
    +.It \-iso9945-2-93
    +.St -iso9945-2-93
    +.br
    +An XCU4 precursor.
    +.Pp
    +.It \-p1003.2a-92
    +.St -p1003.2a-92
    +.br
    +Updates to POSIX.2.
    +.Pp
    +.It \-xpg4
    +.St -xpg4
    +.br
    +Based on POSIX.1 and POSIX.2, published in 1992.
    +.El
    +.It Single UNIX Specification version 1 and related standards
    +.Pp
    +.Bl -tag -width "-p1003.1g-2000" -compact
    +.It \-susv1
    +.St -susv1
    +.It \-xpg4.2
    +.St -xpg4.2
    +.br
    +This standard was published in 1994.
    +It was used as the basis for UNIX 95 certification.
    +The following three refer to parts of it.
    +.Pp
    +.It \-xsh4.2
    +.St -xsh4.2
    +.Pp
    +.It \-xcurses4.2
    +.St -xcurses4.2
    +.Pp
    +.It \-p1003.1g-2000
    +.St -p1003.1g-2000
    +.br
    +Networking APIs, including sockets.
    +.Pp
    +.It \-svid4
    +.St -svid4 ,
    +.br
    +Published in 1995.
    +.El
    +.It Single UNIX Specification version 2 and related standards
    +.Pp
    +.Bl -tag -width "-p1003.1g-2000" -compact
    +.It \-susv2
    +.St -susv2
    +This Standard was published in 1997
    +and is also called X/Open Portability Guide version 5.
    +It was used as the basis for UNIX 98 certification.
    +The following refer to parts of it.
    +.Pp
    +.It \-xbd5
    +.St -xbd5
    +.Pp
    +.It \-xsh5
    +.St -xsh5
    +.Pp
    +.It \-xcu5
    +.St -xcu5
    +.Pp
    +.It \-xns5
    +.St -xns5
    +.It \-xns5.2
    +.St -xns5.2
    +.El
    +.It Single UNIX Specification version 3
    +.Pp
    +.Bl -tag -width "-p1003.1-2001" -compact
    +.It \-p1003.1-2001
    +.St -p1003.1-2001
    +.It \-susv3
    +.St -susv3
    +.br
    +This standard is based on C99, SUSv2, POSIX.1-1996, 1d, and 1j.
    +It is also called X/Open Portability Guide version 6.
    +It is used as the basis for UNIX 03 certification.
    +.Pp
    +.It \-p1003.1-2004
    +.St -p1003.1-2004
    +.br
    +The second and last Technical Corrigendum.
    +.El
    +.It Single UNIX Specification version 4
    +.Pp
    +.Bl -tag -width "-p1003.1g-2000" -compact
    +.It \-p1003.1-2008
    +.St -p1003.1-2008
    +.It \-susv4
    +.St -susv4
    +.br
    +This standard is also called
    +X/Open Portability Guide version 7.
    +.El
    +.It Other standards
    +.Pp
    +.Bl -tag -width "-p1003.1g-2000" -compact
    +.It \-ieee754
    +.St -ieee754
    +.br
    +Floating-point arithmetic.
    +.Pp
    +.It \-iso8601
    +.St -iso8601
    +.br
    +Representation of dates and times, published in 1988.
    +.Pp
    +.It \-iso8802-3
    +.St -iso8802-3
    +.br
    +Ethernet local area networks.
    +.Pp
    +.It \-ieee1275-94
    +.St -ieee1275-94
    +.El
    +.El
    +.Ss \&Sx
    +Reference a section or subsection in the same manual page.
    +The referenced section or subsection name must be identical to the
    +enclosed argument, including whitespace.
    +.Pp
    +Examples:
    +.Dl \&.Sx MANUAL STRUCTURE
    +.Pp
    +See also
    +.Sx \&Sh
    +and
    +.Sx \&Ss .
    +.Ss \&Sy
    +Request a boldface font.
    +.Pp
    +This is most often used to indicate importance or seriousness (not to be
    +confused with stress emphasis, see
    +.Sx \&Em ) .
    +When none of the semantic macros fit, it is also adequate for syntax
    +elements that have to be given or that appear verbatim.
    +.Pp
    +Examples:
    +.Bd -literal -compact -offset indent
    +\&.Sy Warning :
    +If
    +\&.Sy s
    +appears in the owner permissions, set-user-ID mode is set.
    +This utility replaces the former
    +\&.Sy dumpdir
    +program.
    +.Ed
    +.Pp
    +See also
    +.Sx \&Bf ,
    +.Sx \&Em ,
    +.Sx \&Li ,
    +and
    +.Sx \&No .
    +.Ss \&Ta
    +Table cell separator in
    +.Sx \&Bl Fl column
    +lists; can only be used below
    +.Sx \&It .
    +.Ss \&Tn
    +Supported only for compatibility, do not use this in new manuals.
    +Even though the macro name
    +.Pq Dq tradename
    +suggests a semantic function, historic usage is inconsistent, mostly
    +using it as a presentation-level macro to request a small caps font.
    +.Ss \&Ud
    +Supported only for compatibility, do not use this in new manuals.
    +Prints out
    +.Dq currently under development.
    +.Ss \&Ux
    +Supported only for compatibility, do not use this in new manuals.
    +Prints out
    +.Dq Ux .
    +.Ss \&Va
    +A variable name.
    +.Pp
    +Examples:
    +.Dl \&.Va foo
    +.Dl \&.Va const char *bar ;
    +.Pp
    +For function arguments and parameters, use
    +.Sx \&Fa
    +instead.
    +For declarations of global variables in the
    +.Em SYNOPSIS
    +section, use
    +.Sx \&Vt .
    +.Ss \&Vt
    +A variable type.
    +.Pp
    +This is also used for indicating global variables in the
    +.Em SYNOPSIS
    +section, in which case a variable name is also specified.
    +Note that it accepts
    +.Sx Block partial-implicit
    +syntax when invoked as the first macro on an input line in the
    +.Em SYNOPSIS
    +section, else it accepts ordinary
    +.Sx In-line
    +syntax.
    +In the former case, this macro starts a new output line,
    +and a blank line is inserted in front if there is a preceding
    +function definition or include directive.
    +.Pp
    +Examples:
    +.Dl \&.Vt unsigned char
    +.Dl \&.Vt extern const char * const sys_signame[] \&;
    +.Pp
    +For parameters in function prototypes, use
    +.Sx \&Fa
    +instead, for function return types
    +.Sx \&Ft ,
    +and for variable names outside the
    +.Em SYNOPSIS
    +section
    +.Sx \&Va ,
    +even when including a type with the name.
    +See also
    +.Sx MANUAL STRUCTURE .
    +.Ss \&Xc
    +Close a scope opened by
    +.Sx \&Xo .
    +.Ss \&Xo
    +Extend the header of an
    +.Sx \&It
    +macro or the body of a partial-implicit block macro
    +beyond the end of the input line.
    +This macro originally existed to work around the 9-argument limit
    +of historic
    +.Xr roff 7 .
    +.Ss \&Xr
    +Link to another manual
    +.Pq Qq cross-reference .
    +Its syntax is as follows:
    +.Pp
    +.D1 Pf \. Sx \&Xr Ar name section
    +.Pp
    +Cross reference the
    +.Ar name
    +and
    +.Ar section
    +number of another man page.
    +.Pp
    +Examples:
    +.Dl \&.Xr mandoc 1
    +.Dl \&.Xr mandoc 1 \&;
    +.Dl \&.Xr mandoc 1 \&Ns s behaviour
    +.Sh MACRO SYNTAX
    +The syntax of a macro depends on its classification.
    +In this section,
    +.Sq \-arg
    +refers to macro arguments, which may be followed by zero or more
    +.Sq parm
    +parameters;
    +.Sq \&Yo
    +opens the scope of a macro; and if specified,
    +.Sq \&Yc
    +closes it out.
    +.Pp
    +The
    +.Em Callable
    +column indicates that the macro may also be called by passing its name
    +as an argument to another macro.
    +For example,
    +.Sq \&.Op \&Fl O \&Ar file
    +produces
    +.Sq Op Fl O Ar file .
    +To prevent a macro call and render the macro name literally,
    +escape it by prepending a zero-width space,
    +.Sq \e& .
    +For example,
    +.Sq \&Op \e&Fl O
    +produces
    +.Sq Op \&Fl O .
    +If a macro is not callable but its name appears as an argument
    +to another macro, it is interpreted as opaque text.
    +For example,
    +.Sq \&.Fl \&Sh
    +produces
    +.Sq Fl \&Sh .
    +.Pp
    +The
    +.Em Parsed
    +column indicates whether the macro may call other macros by receiving
    +their names as arguments.
    +If a macro is not parsed but the name of another macro appears
    +as an argument, it is interpreted as opaque text.
    +.Pp
    +The
    +.Em Scope
    +column, if applicable, describes closure rules.
    +.Ss Block full-explicit
    +Multi-line scope closed by an explicit closing macro.
    +All macros contains bodies; only
    +.Sx \&Bf
    +and
    +.Pq optionally
    +.Sx \&Bl
    +contain a head.
    +.Bd -literal -offset indent
    +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB
    +\(lBbody...\(rB
    +\&.Yc
    +.Ed
    +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXX" -offset indent
    +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope
    +.It Sx \&Bd  Ta    \&No     Ta    \&No     Ta    closed by Sx \&Ed
    +.It Sx \&Bf  Ta    \&No     Ta    \&No     Ta    closed by Sx \&Ef
    +.It Sx \&Bk  Ta    \&No     Ta    \&No     Ta    closed by Sx \&Ek
    +.It Sx \&Bl  Ta    \&No     Ta    \&No     Ta    closed by Sx \&El
    +.It Sx \&Ed  Ta    \&No     Ta    \&No     Ta    opened by Sx \&Bd
    +.It Sx \&Ef  Ta    \&No     Ta    \&No     Ta    opened by Sx \&Bf
    +.It Sx \&Ek  Ta    \&No     Ta    \&No     Ta    opened by Sx \&Bk
    +.It Sx \&El  Ta    \&No     Ta    \&No     Ta    opened by Sx \&Bl
    +.El
    +.Ss Block full-implicit
    +Multi-line scope closed by end-of-file or implicitly by another macro.
    +All macros have bodies; some
    +.Po
    +.Sx \&It Fl bullet ,
    +.Fl hyphen ,
    +.Fl dash ,
    +.Fl enum ,
    +.Fl item
    +.Pc
    +don't have heads; only one
    +.Po
    +.Sx \&It
    +in
    +.Sx \&Bl Fl column
    +.Pc
    +has multiple heads.
    +.Bd -literal -offset indent
    +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead... \(lBTa head...\(rB\(rB
    +\(lBbody...\(rB
    +.Ed
    +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXXXXXXXXX" -offset indent
    +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope
    +.It Sx \&It Ta \&No Ta Yes  Ta closed by Sx \&It , Sx \&El
    +.It Sx \&Nd Ta \&No Ta \&No Ta closed by Sx \&Sh
    +.It Sx \&Nm Ta \&No Ta Yes  Ta closed by Sx \&Nm , Sx \&Sh , Sx \&Ss
    +.It Sx \&Sh Ta \&No Ta Yes  Ta closed by Sx \&Sh
    +.It Sx \&Ss Ta \&No Ta Yes  Ta closed by Sx \&Sh , Sx \&Ss
    +.El
    +.Pp
    +Note that the
    +.Sx \&Nm
    +macro is a
    +.Sx Block full-implicit
    +macro only when invoked as the first macro
    +in a
    +.Em SYNOPSIS
    +section line, else it is
    +.Sx In-line .
    +.Ss Block partial-explicit
    +Like block full-explicit, but also with single-line scope.
    +Each has at least a body and, in limited circumstances, a head
    +.Po
    +.Sx \&Fo ,
    +.Sx \&Eo
    +.Pc
    +and/or tail
    +.Pq Sx \&Ec .
    +.Bd -literal -offset indent
    +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB
    +\(lBbody...\(rB
    +\&.Yc \(lBtail...\(rB
    +
    +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB \
    +\(lBbody...\(rB \&Yc \(lBtail...\(rB
    +.Ed
    +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent
    +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope
    +.It Sx \&Ac  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Ao
    +.It Sx \&Ao  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Ac
    +.It Sx \&Bc  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Bo
    +.It Sx \&Bo  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Bc
    +.It Sx \&Brc Ta    Yes      Ta    Yes      Ta    opened by Sx \&Bro
    +.It Sx \&Bro Ta    Yes      Ta    Yes      Ta    closed by Sx \&Brc
    +.It Sx \&Dc  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Do
    +.It Sx \&Do  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Dc
    +.It Sx \&Ec  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Eo
    +.It Sx \&Eo  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Ec
    +.It Sx \&Fc  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Fo
    +.It Sx \&Fo  Ta    \&No     Ta    \&No     Ta    closed by Sx \&Fc
    +.It Sx \&Oc  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Oo
    +.It Sx \&Oo  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Oc
    +.It Sx \&Pc  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Po
    +.It Sx \&Po  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Pc
    +.It Sx \&Qc  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Oo
    +.It Sx \&Qo  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Oc
    +.It Sx \&Re  Ta    \&No     Ta    \&No     Ta    opened by Sx \&Rs
    +.It Sx \&Rs  Ta    \&No     Ta    \&No     Ta    closed by Sx \&Re
    +.It Sx \&Sc  Ta    Yes      Ta    Yes      Ta    opened by Sx \&So
    +.It Sx \&So  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Sc
    +.It Sx \&Xc  Ta    Yes      Ta    Yes      Ta    opened by Sx \&Xo
    +.It Sx \&Xo  Ta    Yes      Ta    Yes      Ta    closed by Sx \&Xc
    +.El
    +.Ss Block partial-implicit
    +Like block full-implicit, but with single-line scope closed by the
    +end of the line.
    +.Bd -literal -offset indent
    +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBbody...\(rB \(lBres...\(rB
    +.Ed
    +.Bl -column "MacroX" "CallableX" "ParsedX" -offset indent
    +.It Em Macro Ta Em Callable Ta Em Parsed
    +.It Sx \&Aq  Ta    Yes      Ta    Yes
    +.It Sx \&Bq  Ta    Yes      Ta    Yes
    +.It Sx \&Brq Ta    Yes      Ta    Yes
    +.It Sx \&D1  Ta    \&No     Ta    \&Yes
    +.It Sx \&Dl  Ta    \&No     Ta    Yes
    +.It Sx \&Dq  Ta    Yes      Ta    Yes
    +.It Sx \&En  Ta    Yes      Ta    Yes
    +.It Sx \&Op  Ta    Yes      Ta    Yes
    +.It Sx \&Pq  Ta    Yes      Ta    Yes
    +.It Sx \&Ql  Ta    Yes      Ta    Yes
    +.It Sx \&Qq  Ta    Yes      Ta    Yes
    +.It Sx \&Sq  Ta    Yes      Ta    Yes
    +.It Sx \&Vt  Ta    Yes      Ta    Yes
    +.El
    +.Pp
    +Note that the
    +.Sx \&Vt
    +macro is a
    +.Sx Block partial-implicit
    +only when invoked as the first macro
    +in a
    +.Em SYNOPSIS
    +section line, else it is
    +.Sx In-line .
    +.Ss Special block macro
    +The
    +.Sx \&Ta
    +macro can only be used below
    +.Sx \&It
    +in
    +.Sx \&Bl Fl column
    +lists.
    +It delimits blocks representing table cells;
    +these blocks have bodies, but no heads.
    +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent
    +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope
    +.It Sx \&Ta  Ta    Yes      Ta    Yes    Ta closed by Sx \&Ta , Sx \&It
    +.El
    +.Ss In-line
    +Closed by the end of the line, fixed argument lengths,
    +and/or subsequent macros.
    +In-line macros have only text children.
    +If a number (or inequality) of arguments is
    +.Pq n ,
    +then the macro accepts an arbitrary number of arguments.
    +.Bd -literal -offset indent
    +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB \(lBres...\(rB
    +
    +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB Yc...
    +
    +\&.Yo \(lB\-arg \(lBval...\(rB\(rB arg0 arg1 argN
    +.Ed
    +.Bl -column "MacroX" "CallableX" "ParsedX" "Arguments" -offset indent
    +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Arguments
    +.It Sx \&%A  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%B  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%C  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%D  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%I  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%J  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%N  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%O  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%P  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%Q  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%R  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%T  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%U  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&%V  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&Ad  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&An  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Ap  Ta    Yes      Ta    Yes      Ta    0
    +.It Sx \&Ar  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&At  Ta    Yes      Ta    Yes      Ta    1
    +.It Sx \&Bsx Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Bt  Ta    \&No     Ta    \&No     Ta    0
    +.It Sx \&Bx  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Cd  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Cm  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Db  Ta    \&No     Ta    \&No     Ta    1
    +.It Sx \&Dd  Ta    \&No     Ta    \&No     Ta    n
    +.It Sx \&Dt  Ta    \&No     Ta    \&No     Ta    n
    +.It Sx \&Dv  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Dx  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Em  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Er  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Es  Ta    Yes      Ta    Yes      Ta    2
    +.It Sx \&Ev  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Ex  Ta    \&No     Ta    \&No     Ta    n
    +.It Sx \&Fa  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Fd  Ta    \&No     Ta    \&No     Ta    >0
    +.It Sx \&Fl  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Fn  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Fr  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Ft  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Fx  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Hf  Ta    \&No     Ta    \&No     Ta    n
    +.It Sx \&Ic  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&In  Ta    \&No     Ta    \&No     Ta    1
    +.It Sx \&Lb  Ta    \&No     Ta    \&No     Ta    1
    +.It Sx \&Li  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Lk  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Lp  Ta    \&No     Ta    \&No     Ta    0
    +.It Sx \&Ms  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Mt  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Nm  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&No  Ta    Yes      Ta    Yes      Ta    0
    +.It Sx \&Ns  Ta    Yes      Ta    Yes      Ta    0
    +.It Sx \&Nx  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Os  Ta    \&No     Ta    \&No     Ta    n
    +.It Sx \&Ot  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Ox  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Pa  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Pf  Ta    Yes      Ta    Yes      Ta    1
    +.It Sx \&Pp  Ta    \&No     Ta    \&No     Ta    0
    +.It Sx \&Rv  Ta    \&No     Ta    \&No     Ta    n
    +.It Sx \&Sm  Ta    \&No     Ta    \&No     Ta    <2
    +.It Sx \&St  Ta    \&No     Ta    Yes      Ta    1
    +.It Sx \&Sx  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Sy  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Tn  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Ud  Ta    \&No     Ta    \&No     Ta    0
    +.It Sx \&Ux  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Va  Ta    Yes      Ta    Yes      Ta    n
    +.It Sx \&Vt  Ta    Yes      Ta    Yes      Ta    >0
    +.It Sx \&Xr  Ta    Yes      Ta    Yes      Ta    2
    +.El
    +.Ss Delimiters
    +When a macro argument consists of one single input character
    +considered as a delimiter, the argument gets special handling.
    +This does not apply when delimiters appear in arguments containing
    +more than one character.
    +Consequently, to prevent special handling and just handle it
    +like any other argument, a delimiter can be escaped by prepending
    +a zero-width space
    +.Pq Sq \e& .
    +In text lines, delimiters never need escaping, but may be used
    +as normal punctuation.
    +.Pp
    +For many macros, when the leading arguments are opening delimiters,
    +these delimiters are put before the macro scope,
    +and when the trailing arguments are closing delimiters,
    +these delimiters are put after the macro scope.
    +Spacing is suppressed after opening delimiters
    +and before closing delimiters.
    +For example,
    +.Pp
    +.D1 Pf \. \&Aq "( [ word ] ) ."
    +.Pp
    +renders as:
    +.Pp
    +.D1 Aq ( [ word ] ) .
    +.Pp
    +Opening delimiters are:
    +.Pp
    +.Bl -tag -width Ds -offset indent -compact
    +.It \&(
    +left parenthesis
    +.It \&[
    +left bracket
    +.El
    +.Pp
    +Closing delimiters are:
    +.Pp
    +.Bl -tag -width Ds -offset indent -compact
    +.It \&.
    +period
    +.It \&,
    +comma
    +.It \&:
    +colon
    +.It \&;
    +semicolon
    +.It \&)
    +right parenthesis
    +.It \&]
    +right bracket
    +.It \&?
    +question mark
    +.It \&!
    +exclamation mark
    +.El
    +.Pp
    +Note that even a period preceded by a backslash
    +.Pq Sq \e.\&
    +gets this special handling; use
    +.Sq \e&.
    +to prevent that.
    +.Pp
    +Many in-line macros interrupt their scope when they encounter
    +delimiters, and resume their scope when more arguments follow that
    +are not delimiters.
    +For example,
    +.Pp
    +.D1 Pf \. \&Fl "a ( b | c \e*(Ba d ) e"
    +.Pp
    +renders as:
    +.Pp
    +.D1 Fl a ( b | c \*(Ba d ) e
    +.Pp
    +This applies to both opening and closing delimiters,
    +and also to the middle delimiter, which does not suppress spacing:
    +.Pp
    +.Bl -tag -width Ds -offset indent -compact
    +.It \&|
    +vertical bar
    +.El
    +.Pp
    +As a special case, the predefined string \e*(Ba is handled and rendered
    +in the same way as a plain
    +.Sq \&|
    +character.
    +Using this predefined string is not recommended in new manuals.
    +.Ss Font handling
    +In
    +.Nm
    +documents, usage of semantic markup is recommended in order to have
    +proper fonts automatically selected; only when no fitting semantic markup
    +is available, consider falling back to
    +.Sx Physical markup
    +macros.
    +Whenever any
    +.Nm
    +macro switches the
    +.Xr roff 7
    +font mode, it will automatically restore the previous font when exiting
    +its scope.
    +Manually switching the font using the
    +.Xr roff 7
    +.Ql \ef
    +font escape sequences is never required.
    +.Sh COMPATIBILITY
    +This section provides an incomplete list of compatibility issues
    +between mandoc and GNU troff
    +.Pq Qq groff .
    +.Pp
    +The following problematic behaviour is found in groff:
    +.Pp
    +.Bl -dash -compact
    +.It
    +.Sx \&Dd
    +with non-standard arguments behaves very strangely.
    +When there are three arguments, they are printed verbatim.
    +Any other number of arguments is replaced by the current date,
    +but without any arguments the string
    +.Dq Epoch
    +is printed.
    +.It
    +.Sx \&Lk
    +only accepts a single link-name argument; the remainder is misformatted.
    +.It
    +.Sx \&Pa
    +does not format its arguments when used in the FILES section under
    +certain list types.
    +.It
    +.Sx \&Ta
    +can only be called by other macros, but not at the beginning of a line.
    +.It
    +.Sx \&%C
    +is not implemented (up to and including groff-1.22.2).
    +.It
    +.Sq \ef
    +.Pq font face
    +and
    +.Sq \eF
    +.Pq font family face
    +.Sx Text Decoration
    +escapes behave irregularly when specified within line-macro scopes.
    +.It
    +Negative scaling units return to prior lines.
    +Instead, mandoc truncates them to zero.
    +.El
    +.Pp
    +The following features are unimplemented in mandoc:
    +.Pp
    +.Bl -dash -compact
    +.It
    +.Sx \&Bd
    +.Fl file Ar file
    +is unsupported for security reasons.
    +.It
    +.Sx \&Bd
    +.Fl filled
    +does not adjust the right margin, but is an alias for
    +.Sx \&Bd
    +.Fl ragged .
    +.It
    +.Sx \&Bd
    +.Fl literal
    +does not use a literal font, but is an alias for
    +.Sx \&Bd
    +.Fl unfilled .
    +.It
    +.Sx \&Bd
    +.Fl offset Cm center
    +and
    +.Fl offset Cm right
    +don't work.
    +Groff does not implement centered and flush-right rendering either,
    +but produces large indentations.
    +.El
    +.Sh SEE ALSO
    +.Xr man 1 ,
    +.Xr mandoc 1 ,
    +.Xr eqn 7 ,
    +.Xr man 7 ,
    +.Xr mandoc_char 7 ,
    +.Xr roff 7 ,
    +.Xr tbl 7
    +.Pp
    +The web page
    +.Lk http://mandoc.bsd.lv/mdoc/ "extended documentation for the mdoc language"
    +provides a few tutorial-style pages for beginners, an extensive style
    +guide for advanced authors, and an alphabetic index helping to choose
    +the best macros for various kinds of content.
    +.Sh HISTORY
    +The
    +.Nm
    +language first appeared as a troff macro package in
    +.Bx 4.4 .
    +It was later significantly updated by Werner Lemberg and Ruslan Ermilov
    +in groff-1.17.
    +The standalone implementation that is part of the
    +.Xr mandoc 1
    +utility written by Kristaps Dzonsons appeared in
    +.Ox 4.6 .
    +.Sh AUTHORS
    +The
    +.Nm
    +reference was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
    
    Property changes on: head/contrib/mandoc/mdoc.7
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc.c
    ===================================================================
    --- head/contrib/mandoc/mdoc.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc.c	(revision 338826)
    @@ -0,0 +1,459 @@
    +/*	$Id: mdoc.c,v 1.268 2017/08/11 16:56:21 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdarg.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "libmandoc.h"
    +#include "roff_int.h"
    +#include "libmdoc.h"
    +
    +const	char *const __mdoc_argnames[MDOC_ARG_MAX] = {
    +	"split",		"nosplit",		"ragged",
    +	"unfilled",		"literal",		"file",
    +	"offset",		"bullet",		"dash",
    +	"hyphen",		"item",			"enum",
    +	"tag",			"diag",			"hang",
    +	"ohang",		"inset",		"column",
    +	"width",		"compact",		"std",
    +	"filled",		"words",		"emphasis",
    +	"symbolic",		"nested",		"centered"
    +};
    +const	char * const *mdoc_argnames = __mdoc_argnames;
    +
    +static	int		  mdoc_ptext(struct roff_man *, int, char *, int);
    +static	int		  mdoc_pmacro(struct roff_man *, int, char *, int);
    +
    +
    +/*
    + * Main parse routine.  Parses a single line -- really just hands off to
    + * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
    + */
    +int
    +mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs)
    +{
    +
    +	if (mdoc->last->type != ROFFT_EQN || ln > mdoc->last->line)
    +		mdoc->flags |= MDOC_NEWLINE;
    +
    +	/*
    +	 * Let the roff nS register switch SYNOPSIS mode early,
    +	 * such that the parser knows at all times
    +	 * whether this mode is on or off.
    +	 * Note that this mode is also switched by the Sh macro.
    +	 */
    +	if (roff_getreg(mdoc->roff, "nS"))
    +		mdoc->flags |= MDOC_SYNOPSIS;
    +	else
    +		mdoc->flags &= ~MDOC_SYNOPSIS;
    +
    +	return roff_getcontrol(mdoc->roff, buf, &offs) ?
    +	    mdoc_pmacro(mdoc, ln, buf, offs) :
    +	    mdoc_ptext(mdoc, ln, buf, offs);
    +}
    +
    +void
    +mdoc_macro(MACRO_PROT_ARGS)
    +{
    +	assert(tok >= MDOC_Dd && tok < MDOC_MAX);
    +	(*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
    +}
    +
    +void
    +mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, enum roff_tok tok)
    +{
    +	struct roff_node *p;
    +
    +	p = roff_node_alloc(mdoc, line, pos, ROFFT_TAIL, tok);
    +	roff_node_append(mdoc, p);
    +	mdoc->next = ROFF_NEXT_CHILD;
    +}
    +
    +struct roff_node *
    +mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos,
    +    enum roff_tok tok, struct roff_node *body)
    +{
    +	struct roff_node *p;
    +
    +	body->flags |= NODE_ENDED;
    +	body->parent->flags |= NODE_ENDED;
    +	p = roff_node_alloc(mdoc, line, pos, ROFFT_BODY, tok);
    +	p->body = body;
    +	p->norm = body->norm;
    +	p->end = ENDBODY_SPACE;
    +	roff_node_append(mdoc, p);
    +	mdoc->next = ROFF_NEXT_SIBLING;
    +	return p;
    +}
    +
    +struct roff_node *
    +mdoc_block_alloc(struct roff_man *mdoc, int line, int pos,
    +    enum roff_tok tok, struct mdoc_arg *args)
    +{
    +	struct roff_node *p;
    +
    +	p = roff_node_alloc(mdoc, line, pos, ROFFT_BLOCK, tok);
    +	p->args = args;
    +	if (p->args)
    +		(args->refcnt)++;
    +
    +	switch (tok) {
    +	case MDOC_Bd:
    +	case MDOC_Bf:
    +	case MDOC_Bl:
    +	case MDOC_En:
    +	case MDOC_Rs:
    +		p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
    +		break;
    +	default:
    +		break;
    +	}
    +	roff_node_append(mdoc, p);
    +	mdoc->next = ROFF_NEXT_CHILD;
    +	return p;
    +}
    +
    +void
    +mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos,
    +     enum roff_tok tok, struct mdoc_arg *args)
    +{
    +	struct roff_node *p;
    +
    +	p = roff_node_alloc(mdoc, line, pos, ROFFT_ELEM, tok);
    +	p->args = args;
    +	if (p->args)
    +		(args->refcnt)++;
    +
    +	switch (tok) {
    +	case MDOC_An:
    +		p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
    +		break;
    +	default:
    +		break;
    +	}
    +	roff_node_append(mdoc, p);
    +	mdoc->next = ROFF_NEXT_CHILD;
    +}
    +
    +void
    +mdoc_node_relink(struct roff_man *mdoc, struct roff_node *p)
    +{
    +
    +	roff_node_unlink(mdoc, p);
    +	p->prev = p->next = NULL;
    +	roff_node_append(mdoc, p);
    +}
    +
    +/*
    + * Parse free-form text, that is, a line that does not begin with the
    + * control character.
    + */
    +static int
    +mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
    +{
    +	struct roff_node *n;
    +	const char	 *cp, *sp;
    +	char		 *c, *ws, *end;
    +
    +	n = mdoc->last;
    +
    +	/*
    +	 * If a column list contains plain text, assume an implicit item
    +	 * macro.  This can happen one or more times at the beginning
    +	 * of such a list, intermixed with non-It mdoc macros and with
    +	 * nodes generated on the roff level, for example by tbl.
    +	 */
    +
    +	if ((n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
    +	     n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) ||
    +	    (n->parent != NULL && n->parent->tok == MDOC_Bl &&
    +	     n->parent->norm->Bl.type == LIST_column)) {
    +		mdoc->flags |= MDOC_FREECOL;
    +		mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
    +		return 1;
    +	}
    +
    +	/*
    +	 * Search for the beginning of unescaped trailing whitespace (ws)
    +	 * and for the first character not to be output (end).
    +	 */
    +
    +	/* FIXME: replace with strcspn(). */
    +	ws = NULL;
    +	for (c = end = buf + offs; *c; c++) {
    +		switch (*c) {
    +		case ' ':
    +			if (NULL == ws)
    +				ws = c;
    +			continue;
    +		case '\t':
    +			/*
    +			 * Always warn about trailing tabs,
    +			 * even outside literal context,
    +			 * where they should be put on the next line.
    +			 */
    +			if (NULL == ws)
    +				ws = c;
    +			/*
    +			 * Strip trailing tabs in literal context only;
    +			 * outside, they affect the next line.
    +			 */
    +			if (MDOC_LITERAL & mdoc->flags)
    +				continue;
    +			break;
    +		case '\\':
    +			/* Skip the escaped character, too, if any. */
    +			if (c[1])
    +				c++;
    +			/* FALLTHROUGH */
    +		default:
    +			ws = NULL;
    +			break;
    +		}
    +		end = c + 1;
    +	}
    +	*end = '\0';
    +
    +	if (ws)
    +		mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
    +		    line, (int)(ws-buf), NULL);
    +
    +	/*
    +	 * Blank lines are allowed in no-fill mode
    +	 * and cancel preceding \c,
    +	 * but add a single vertical space elsewhere.
    +	 */
    +
    +	if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
    +		switch (mdoc->last->type) {
    +		case ROFFT_TEXT:
    +			sp = mdoc->last->string;
    +			cp = end = strchr(sp, '\0') - 2;
    +			if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
    +				break;
    +			while (cp > sp && cp[-1] == '\\')
    +				cp--;
    +			if ((end - cp) % 2)
    +				break;
    +			*end = '\0';
    +			return 1;
    +		default:
    +			break;
    +		}
    +		mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
    +		    line, (int)(c - buf), NULL);
    +		roff_elem_alloc(mdoc, line, offs, ROFF_sp);
    +		mdoc->last->flags |= NODE_VALID | NODE_ENDED;
    +		mdoc->next = ROFF_NEXT_SIBLING;
    +		return 1;
    +	}
    +
    +	roff_word_alloc(mdoc, line, offs, buf+offs);
    +
    +	if (mdoc->flags & MDOC_LITERAL)
    +		return 1;
    +
    +	/*
    +	 * 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(buf < end);
    +
    +	if (mandoc_eos(buf+offs, (size_t)(end-buf-offs)))
    +		mdoc->last->flags |= NODE_EOS;
    +
    +	for (c = buf + offs; c != NULL; c = strchr(c + 1, '.')) {
    +		if (c - buf < offs + 2)
    +			continue;
    +		if (end - c < 3)
    +			break;
    +		if (c[1] != ' ' ||
    +		    isalnum((unsigned char)c[-2]) == 0 ||
    +		    isalnum((unsigned char)c[-1]) == 0 ||
    +		    (c[-2] == 'n' && c[-1] == 'c') ||
    +		    (c[-2] == 'v' && c[-1] == 's'))
    +			continue;
    +		c += 2;
    +		if (*c == ' ')
    +			c++;
    +		if (*c == ' ')
    +			c++;
    +		if (isupper((unsigned char)(*c)))
    +			mandoc_msg(MANDOCERR_EOS, mdoc->parse,
    +			    line, (int)(c - buf), NULL);
    +	}
    +
    +	return 1;
    +}
    +
    +/*
    + * Parse a macro line, that is, a line beginning with the control
    + * character.
    + */
    +static int
    +mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
    +{
    +	struct roff_node *n;
    +	const char	 *cp;
    +	size_t		  sz;
    +	enum roff_tok	  tok;
    +	int		  sv;
    +
    +	/* Determine the line macro. */
    +
    +	sv = offs;
    +	tok = TOKEN_NONE;
    +	for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
    +		offs++;
    +	if (sz == 2 || sz == 3)
    +		tok = roffhash_find(mdoc->mdocmac, buf + sv, sz);
    +	if (tok == TOKEN_NONE) {
    +		mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
    +		    ln, sv, buf + sv - 1);
    +		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 ('\0' == buf[offs] && ' ' == buf[offs - 1])
    +		mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
    +		    ln, offs - 1, NULL);
    +
    +	/*
    +	 * If an initial macro or a list invocation, divert directly
    +	 * into macro processing.
    +	 */
    +
    +	n = mdoc->last;
    +	if (n == NULL || tok == MDOC_It || tok == MDOC_El) {
    +		mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
    +		return 1;
    +	}
    +
    +	/*
    +	 * If a column list contains a non-It macro, assume an implicit
    +	 * item macro.  This can happen one or more times at the
    +	 * beginning of such a list, intermixed with text lines and
    +	 * with nodes generated on the roff level, for example by tbl.
    +	 */
    +
    +	if ((n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
    +	     n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) ||
    +	    (n->parent != NULL && n->parent->tok == MDOC_Bl &&
    +	     n->parent->norm->Bl.type == LIST_column)) {
    +		mdoc->flags |= MDOC_FREECOL;
    +		mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
    +		return 1;
    +	}
    +
    +	/* Normal processing of a macro. */
    +
    +	mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
    +
    +	/* In quick mode (for mandocdb), abort after the NAME section. */
    +
    +	if (mdoc->quick && MDOC_Sh == tok &&
    +	    SEC_NAME != mdoc->last->sec)
    +		return 2;
    +
    +	return 1;
    +}
    +
    +enum mdelim
    +mdoc_isdelim(const char *p)
    +{
    +
    +	if ('\0' == p[0])
    +		return DELIM_NONE;
    +
    +	if ('\0' == p[1])
    +		switch (p[0]) {
    +		case '(':
    +		case '[':
    +			return DELIM_OPEN;
    +		case '|':
    +			return DELIM_MIDDLE;
    +		case '.':
    +		case ',':
    +		case ';':
    +		case ':':
    +		case '?':
    +		case '!':
    +		case ')':
    +		case ']':
    +			return DELIM_CLOSE;
    +		default:
    +			return DELIM_NONE;
    +		}
    +
    +	if ('\\' != p[0])
    +		return DELIM_NONE;
    +
    +	if (0 == strcmp(p + 1, "."))
    +		return DELIM_CLOSE;
    +	if (0 == strcmp(p + 1, "fR|\\fP"))
    +		return DELIM_MIDDLE;
    +
    +	return DELIM_NONE;
    +}
    +
    +void
    +mdoc_validate(struct roff_man *mdoc)
    +{
    +
    +	mdoc->last = mdoc->first;
    +	mdoc_node_validate(mdoc);
    +	mdoc_state_reset(mdoc);
    +}
    
    Property changes on: head/contrib/mandoc/mdoc.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc_html.c
    ===================================================================
    --- head/contrib/mandoc/mdoc_html.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc_html.c	(revision 338826)
    @@ -0,0 +1,1762 @@
    +/*	$Id: mdoc_html.c,v 1.310 2018/07/27 17:49:31 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "out.h"
    +#include "html.h"
    +#include "main.h"
    +
    +#define	MDOC_ARGS	  const struct roff_meta *meta, \
    +			  struct roff_node *n, \
    +			  struct html *h
    +
    +#ifndef MIN
    +#define	MIN(a,b)	((/*CONSTCOND*/(a)<(b))?(a):(b))
    +#endif
    +
    +struct	htmlmdoc {
    +	int		(*pre)(MDOC_ARGS);
    +	void		(*post)(MDOC_ARGS);
    +};
    +
    +static	char		 *cond_id(const struct roff_node *);
    +static	void		  print_mdoc_head(const struct roff_meta *,
    +				struct html *);
    +static	void		  print_mdoc_node(MDOC_ARGS);
    +static	void		  print_mdoc_nodelist(MDOC_ARGS);
    +static	void		  synopsis_pre(struct html *,
    +				const struct roff_node *);
    +
    +static	void		  mdoc_root_post(const struct roff_meta *,
    +				struct html *);
    +static	int		  mdoc_root_pre(const struct roff_meta *,
    +				struct html *);
    +
    +static	void		  mdoc__x_post(MDOC_ARGS);
    +static	int		  mdoc__x_pre(MDOC_ARGS);
    +static	int		  mdoc_ad_pre(MDOC_ARGS);
    +static	int		  mdoc_an_pre(MDOC_ARGS);
    +static	int		  mdoc_ap_pre(MDOC_ARGS);
    +static	int		  mdoc_ar_pre(MDOC_ARGS);
    +static	int		  mdoc_bd_pre(MDOC_ARGS);
    +static	int		  mdoc_bf_pre(MDOC_ARGS);
    +static	void		  mdoc_bk_post(MDOC_ARGS);
    +static	int		  mdoc_bk_pre(MDOC_ARGS);
    +static	int		  mdoc_bl_pre(MDOC_ARGS);
    +static	int		  mdoc_cd_pre(MDOC_ARGS);
    +static	int		  mdoc_cm_pre(MDOC_ARGS);
    +static	int		  mdoc_d1_pre(MDOC_ARGS);
    +static	int		  mdoc_dv_pre(MDOC_ARGS);
    +static	int		  mdoc_fa_pre(MDOC_ARGS);
    +static	int		  mdoc_fd_pre(MDOC_ARGS);
    +static	int		  mdoc_fl_pre(MDOC_ARGS);
    +static	int		  mdoc_fn_pre(MDOC_ARGS);
    +static	int		  mdoc_ft_pre(MDOC_ARGS);
    +static	int		  mdoc_em_pre(MDOC_ARGS);
    +static	void		  mdoc_eo_post(MDOC_ARGS);
    +static	int		  mdoc_eo_pre(MDOC_ARGS);
    +static	int		  mdoc_er_pre(MDOC_ARGS);
    +static	int		  mdoc_ev_pre(MDOC_ARGS);
    +static	int		  mdoc_ex_pre(MDOC_ARGS);
    +static	void		  mdoc_fo_post(MDOC_ARGS);
    +static	int		  mdoc_fo_pre(MDOC_ARGS);
    +static	int		  mdoc_ic_pre(MDOC_ARGS);
    +static	int		  mdoc_igndelim_pre(MDOC_ARGS);
    +static	int		  mdoc_in_pre(MDOC_ARGS);
    +static	int		  mdoc_it_pre(MDOC_ARGS);
    +static	int		  mdoc_lb_pre(MDOC_ARGS);
    +static	int		  mdoc_li_pre(MDOC_ARGS);
    +static	int		  mdoc_lk_pre(MDOC_ARGS);
    +static	int		  mdoc_mt_pre(MDOC_ARGS);
    +static	int		  mdoc_ms_pre(MDOC_ARGS);
    +static	int		  mdoc_nd_pre(MDOC_ARGS);
    +static	int		  mdoc_nm_pre(MDOC_ARGS);
    +static	int		  mdoc_no_pre(MDOC_ARGS);
    +static	int		  mdoc_ns_pre(MDOC_ARGS);
    +static	int		  mdoc_pa_pre(MDOC_ARGS);
    +static	void		  mdoc_pf_post(MDOC_ARGS);
    +static	int		  mdoc_pp_pre(MDOC_ARGS);
    +static	void		  mdoc_quote_post(MDOC_ARGS);
    +static	int		  mdoc_quote_pre(MDOC_ARGS);
    +static	int		  mdoc_rs_pre(MDOC_ARGS);
    +static	int		  mdoc_sh_pre(MDOC_ARGS);
    +static	int		  mdoc_skip_pre(MDOC_ARGS);
    +static	int		  mdoc_sm_pre(MDOC_ARGS);
    +static	int		  mdoc_ss_pre(MDOC_ARGS);
    +static	int		  mdoc_st_pre(MDOC_ARGS);
    +static	int		  mdoc_sx_pre(MDOC_ARGS);
    +static	int		  mdoc_sy_pre(MDOC_ARGS);
    +static	int		  mdoc_va_pre(MDOC_ARGS);
    +static	int		  mdoc_vt_pre(MDOC_ARGS);
    +static	int		  mdoc_xr_pre(MDOC_ARGS);
    +static	int		  mdoc_xx_pre(MDOC_ARGS);
    +
    +static	const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
    +	{NULL, NULL}, /* Dd */
    +	{NULL, NULL}, /* Dt */
    +	{NULL, NULL}, /* Os */
    +	{mdoc_sh_pre, NULL }, /* Sh */
    +	{mdoc_ss_pre, NULL }, /* Ss */
    +	{mdoc_pp_pre, NULL}, /* Pp */
    +	{mdoc_d1_pre, NULL}, /* D1 */
    +	{mdoc_d1_pre, NULL}, /* Dl */
    +	{mdoc_bd_pre, NULL}, /* Bd */
    +	{NULL, NULL}, /* Ed */
    +	{mdoc_bl_pre, NULL}, /* Bl */
    +	{NULL, NULL}, /* El */
    +	{mdoc_it_pre, NULL}, /* It */
    +	{mdoc_ad_pre, NULL}, /* Ad */
    +	{mdoc_an_pre, NULL}, /* An */
    +	{mdoc_ap_pre, NULL}, /* Ap */
    +	{mdoc_ar_pre, NULL}, /* Ar */
    +	{mdoc_cd_pre, NULL}, /* Cd */
    +	{mdoc_cm_pre, NULL}, /* Cm */
    +	{mdoc_dv_pre, NULL}, /* Dv */
    +	{mdoc_er_pre, NULL}, /* Er */
    +	{mdoc_ev_pre, NULL}, /* Ev */
    +	{mdoc_ex_pre, NULL}, /* Ex */
    +	{mdoc_fa_pre, NULL}, /* Fa */
    +	{mdoc_fd_pre, NULL}, /* Fd */
    +	{mdoc_fl_pre, NULL}, /* Fl */
    +	{mdoc_fn_pre, NULL}, /* Fn */
    +	{mdoc_ft_pre, NULL}, /* Ft */
    +	{mdoc_ic_pre, NULL}, /* Ic */
    +	{mdoc_in_pre, NULL}, /* In */
    +	{mdoc_li_pre, NULL}, /* Li */
    +	{mdoc_nd_pre, NULL}, /* Nd */
    +	{mdoc_nm_pre, NULL}, /* Nm */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Op */
    +	{mdoc_ft_pre, NULL}, /* Ot */
    +	{mdoc_pa_pre, NULL}, /* Pa */
    +	{mdoc_ex_pre, NULL}, /* Rv */
    +	{mdoc_st_pre, NULL}, /* St */
    +	{mdoc_va_pre, NULL}, /* Va */
    +	{mdoc_vt_pre, NULL}, /* Vt */
    +	{mdoc_xr_pre, NULL}, /* Xr */
    +	{mdoc__x_pre, mdoc__x_post}, /* %A */
    +	{mdoc__x_pre, mdoc__x_post}, /* %B */
    +	{mdoc__x_pre, mdoc__x_post}, /* %D */
    +	{mdoc__x_pre, mdoc__x_post}, /* %I */
    +	{mdoc__x_pre, mdoc__x_post}, /* %J */
    +	{mdoc__x_pre, mdoc__x_post}, /* %N */
    +	{mdoc__x_pre, mdoc__x_post}, /* %O */
    +	{mdoc__x_pre, mdoc__x_post}, /* %P */
    +	{mdoc__x_pre, mdoc__x_post}, /* %R */
    +	{mdoc__x_pre, mdoc__x_post}, /* %T */
    +	{mdoc__x_pre, mdoc__x_post}, /* %V */
    +	{NULL, NULL}, /* Ac */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Ao */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Aq */
    +	{mdoc_xx_pre, NULL}, /* At */
    +	{NULL, NULL}, /* Bc */
    +	{mdoc_bf_pre, NULL}, /* Bf */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Bo */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
    +	{mdoc_xx_pre, NULL}, /* Bsx */
    +	{mdoc_xx_pre, NULL}, /* Bx */
    +	{mdoc_skip_pre, NULL}, /* Db */
    +	{NULL, NULL}, /* Dc */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Do */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
    +	{NULL, NULL}, /* Ec */ /* FIXME: no space */
    +	{NULL, NULL}, /* Ef */
    +	{mdoc_em_pre, NULL}, /* Em */
    +	{mdoc_eo_pre, mdoc_eo_post}, /* Eo */
    +	{mdoc_xx_pre, NULL}, /* Fx */
    +	{mdoc_ms_pre, NULL}, /* Ms */
    +	{mdoc_no_pre, NULL}, /* No */
    +	{mdoc_ns_pre, NULL}, /* Ns */
    +	{mdoc_xx_pre, NULL}, /* Nx */
    +	{mdoc_xx_pre, NULL}, /* Ox */
    +	{NULL, NULL}, /* Pc */
    +	{mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Po */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Pq */
    +	{NULL, NULL}, /* Qc */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Ql */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Qo */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Qq */
    +	{NULL, NULL}, /* Re */
    +	{mdoc_rs_pre, NULL}, /* Rs */
    +	{NULL, NULL}, /* Sc */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* So */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Sq */
    +	{mdoc_sm_pre, NULL}, /* Sm */
    +	{mdoc_sx_pre, NULL}, /* Sx */
    +	{mdoc_sy_pre, NULL}, /* Sy */
    +	{NULL, NULL}, /* Tn */
    +	{mdoc_xx_pre, NULL}, /* Ux */
    +	{NULL, NULL}, /* Xc */
    +	{NULL, NULL}, /* Xo */
    +	{mdoc_fo_pre, mdoc_fo_post}, /* Fo */
    +	{NULL, NULL}, /* Fc */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Oo */
    +	{NULL, NULL}, /* Oc */
    +	{mdoc_bk_pre, mdoc_bk_post}, /* Bk */
    +	{NULL, NULL}, /* Ek */
    +	{NULL, NULL}, /* Bt */
    +	{NULL, NULL}, /* Hf */
    +	{mdoc_em_pre, NULL}, /* Fr */
    +	{NULL, NULL}, /* Ud */
    +	{mdoc_lb_pre, NULL}, /* Lb */
    +	{mdoc_pp_pre, NULL}, /* Lp */
    +	{mdoc_lk_pre, NULL}, /* Lk */
    +	{mdoc_mt_pre, NULL}, /* Mt */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* Bro */
    +	{NULL, NULL}, /* Brc */
    +	{mdoc__x_pre, mdoc__x_post}, /* %C */
    +	{mdoc_skip_pre, NULL}, /* Es */
    +	{mdoc_quote_pre, mdoc_quote_post}, /* En */
    +	{mdoc_xx_pre, NULL}, /* Dx */
    +	{mdoc__x_pre, mdoc__x_post}, /* %Q */
    +	{mdoc__x_pre, mdoc__x_post}, /* %U */
    +	{NULL, NULL}, /* Ta */
    +};
    +static	const struct htmlmdoc *const mdocs = __mdocs - MDOC_Dd;
    +
    +
    +/*
    + * See the same function in mdoc_term.c for documentation.
    + */
    +static void
    +synopsis_pre(struct html *h, const struct roff_node *n)
    +{
    +
    +	if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
    +		return;
    +
    +	if (n->prev->tok == n->tok &&
    +	    MDOC_Fo != n->tok &&
    +	    MDOC_Ft != n->tok &&
    +	    MDOC_Fn != n->tok) {
    +		print_otag(h, TAG_BR, "");
    +		return;
    +	}
    +
    +	switch (n->prev->tok) {
    +	case MDOC_Fd:
    +	case MDOC_Fn:
    +	case MDOC_Fo:
    +	case MDOC_In:
    +	case MDOC_Vt:
    +		print_paragraph(h);
    +		break;
    +	case MDOC_Ft:
    +		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
    +			print_paragraph(h);
    +			break;
    +		}
    +		/* FALLTHROUGH */
    +	default:
    +		print_otag(h, TAG_BR, "");
    +		break;
    +	}
    +}
    +
    +void
    +html_mdoc(void *arg, const struct roff_man *mdoc)
    +{
    +	struct html		*h;
    +	struct roff_node	*n;
    +	struct tag		*t;
    +
    +	h = (struct html *)arg;
    +	n = mdoc->first->child;
    +
    +	if ((h->oflags & HTML_FRAGMENT) == 0) {
    +		print_gen_decls(h);
    +		print_otag(h, TAG_HTML, "");
    +		if (n->type == ROFFT_COMMENT)
    +			print_gen_comment(h, n);
    +		t = print_otag(h, TAG_HEAD, "");
    +		print_mdoc_head(&mdoc->meta, h);
    +		print_tagq(h, t);
    +		print_otag(h, TAG_BODY, "");
    +	}
    +
    +	mdoc_root_pre(&mdoc->meta, h);
    +	t = print_otag(h, TAG_DIV, "c", "manual-text");
    +	print_mdoc_nodelist(&mdoc->meta, n, h);
    +	print_tagq(h, t);
    +	mdoc_root_post(&mdoc->meta, h);
    +	print_tagq(h, NULL);
    +}
    +
    +static void
    +print_mdoc_head(const struct roff_meta *meta, struct html *h)
    +{
    +	char	*cp;
    +
    +	print_gen_head(h);
    +
    +	if (meta->arch != NULL && meta->msec != NULL)
    +		mandoc_asprintf(&cp, "%s(%s) (%s)", meta->title,
    +		    meta->msec, meta->arch);
    +	else if (meta->msec != NULL)
    +		mandoc_asprintf(&cp, "%s(%s)", meta->title, meta->msec);
    +	else if (meta->arch != NULL)
    +		mandoc_asprintf(&cp, "%s (%s)", meta->title, meta->arch);
    +	else
    +		cp = mandoc_strdup(meta->title);
    +
    +	print_otag(h, TAG_TITLE, "");
    +	print_text(h, cp);
    +	free(cp);
    +}
    +
    +static void
    +print_mdoc_nodelist(MDOC_ARGS)
    +{
    +
    +	while (n != NULL) {
    +		print_mdoc_node(meta, n, h);
    +		n = n->next;
    +	}
    +}
    +
    +static void
    +print_mdoc_node(MDOC_ARGS)
    +{
    +	int		 child;
    +	struct tag	*t;
    +
    +	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
    +		return;
    +
    +	child = 1;
    +	t = h->tag;
    +	n->flags &= ~NODE_ENDED;
    +
    +	switch (n->type) {
    +	case ROFFT_TEXT:
    +		/* No tables in this mode... */
    +		assert(NULL == h->tblt);
    +
    +		/*
    +		 * Make sure that if we're in a literal mode already
    +		 * (i.e., within a <PRE>) don't print the newline.
    +		 */
    +		if (*n->string == ' ' && n->flags & NODE_LINE &&
    +		    (h->flags & (HTML_LITERAL | HTML_NONEWLINE)) == 0)
    +			print_otag(h, TAG_BR, "");
    +		if (NODE_DELIMC & n->flags)
    +			h->flags |= HTML_NOSPACE;
    +		print_text(h, n->string);
    +		if (NODE_DELIMO & n->flags)
    +			h->flags |= HTML_NOSPACE;
    +		return;
    +	case ROFFT_EQN:
    +		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 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 != NULL) {
    +			print_tblclose(h);
    +			t = h->tag;
    +		}
    +		assert(h->tblt == NULL);
    +		if (n->tok < ROFF_MAX) {
    +			roff_html_pre(h, n);
    +			child = 0;
    +			break;
    +		}
    +		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
    +		if (mdocs[n->tok].pre != NULL &&
    +		    (n->end == ENDBODY_NOT || n->child != NULL))
    +			child = (*mdocs[n->tok].pre)(meta, n, h);
    +		break;
    +	}
    +
    +	if (h->flags & HTML_KEEP && n->flags & NODE_LINE) {
    +		h->flags &= ~HTML_KEEP;
    +		h->flags |= HTML_PREKEEP;
    +	}
    +
    +	if (child && n->child)
    +		print_mdoc_nodelist(meta, n->child, h);
    +
    +	print_stagq(h, t);
    +
    +	switch (n->type) {
    +	case ROFFT_EQN:
    +		break;
    +	default:
    +		if (n->tok < ROFF_MAX ||
    +		    mdocs[n->tok].post == NULL ||
    +		    n->flags & NODE_ENDED)
    +			break;
    +		(*mdocs[n->tok].post)(meta, n, h);
    +		if (n->end != ENDBODY_NOT)
    +			n->body->flags |= NODE_ENDED;
    +		break;
    +	}
    +}
    +
    +static void
    +mdoc_root_post(const struct roff_meta *meta, struct html *h)
    +{
    +	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, meta->date);
    +	print_stagq(h, tt);
    +
    +	print_otag(h, TAG_TD, "c", "foot-os");
    +	print_text(h, meta->os);
    +	print_tagq(h, t);
    +}
    +
    +static int
    +mdoc_root_pre(const struct roff_meta *meta, struct html *h)
    +{
    +	struct tag	*t, *tt;
    +	char		*volume, *title;
    +
    +	if (NULL == meta->arch)
    +		volume = mandoc_strdup(meta->vol);
    +	else
    +		mandoc_asprintf(&volume, "%s (%s)",
    +		    meta->vol, meta->arch);
    +
    +	if (NULL == meta->msec)
    +		title = mandoc_strdup(meta->title);
    +	else
    +		mandoc_asprintf(&title, "%s(%s)",
    +		    meta->title, meta->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");
    +	print_text(h, volume);
    +	print_stagq(h, tt);
    +
    +	print_otag(h, TAG_TD, "c", "head-rtitle");
    +	print_text(h, title);
    +	print_tagq(h, t);
    +
    +	free(title);
    +	free(volume);
    +	return 1;
    +}
    +
    +static char *
    +cond_id(const struct roff_node *n)
    +{
    +	if (n->child != NULL &&
    +	    n->child->type == ROFFT_TEXT &&
    +	    (n->prev == NULL ||
    +	     (n->prev->type == ROFFT_TEXT &&
    +	      strcmp(n->prev->string, "|") == 0)) &&
    +	    (n->parent->tok == MDOC_It ||
    +	     (n->parent->tok == MDOC_Xo &&
    +	      n->parent->parent->prev == NULL &&
    +	      n->parent->parent->parent->tok == MDOC_It)))
    +		return html_make_id(n, 1);
    +	return NULL;
    +}
    +
    +static int
    +mdoc_sh_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		id = html_make_id(n, 1);
    +		print_otag(h, TAG_H1, "cTi", "Sh", id);
    +		if (id != NULL)
    +			print_otag(h, TAG_A, "chR", "permalink", id);
    +		break;
    +	case ROFFT_BODY:
    +		if (n->sec == SEC_AUTHORS)
    +			h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
    +		break;
    +	default:
    +		break;
    +	}
    +	return 1;
    +}
    +
    +static int
    +mdoc_ss_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	if (n->type != ROFFT_HEAD)
    +		return 1;
    +
    +	id = html_make_id(n, 1);
    +	print_otag(h, TAG_H2, "cTi", "Ss", id);
    +	if (id != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_fl_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	if ((id = cond_id(n)) != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_CODE, "cTi", "Fl", id);
    +
    +	print_text(h, "\\-");
    +	if (!(n->child == NULL &&
    +	    (n->next == NULL ||
    +	     n->next->type == ROFFT_TEXT ||
    +	     n->next->flags & NODE_LINE)))
    +		h->flags |= HTML_NOSPACE;
    +
    +	return 1;
    +}
    +
    +static int
    +mdoc_cm_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	if ((id = cond_id(n)) != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_CODE, "cTi", "Cm", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_nd_pre(MDOC_ARGS)
    +{
    +	if (n->type != ROFFT_BODY)
    +		return 1;
    +
    +	print_text(h, "\\(em");
    +	/* Cannot use TAG_SPAN because it may contain blocks. */
    +	print_otag(h, TAG_DIV, "cT", "Nd");
    +	return 1;
    +}
    +
    +static int
    +mdoc_nm_pre(MDOC_ARGS)
    +{
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		print_otag(h, TAG_TD, "");
    +		/* FALLTHROUGH */
    +	case ROFFT_ELEM:
    +		print_otag(h, TAG_CODE, "cT", "Nm");
    +		return 1;
    +	case ROFFT_BODY:
    +		print_otag(h, TAG_TD, "");
    +		return 1;
    +	default:
    +		break;
    +	}
    +	synopsis_pre(h, n);
    +	print_otag(h, TAG_TABLE, "c", "Nm");
    +	print_otag(h, TAG_TR, "");
    +	return 1;
    +}
    +
    +static int
    +mdoc_xr_pre(MDOC_ARGS)
    +{
    +	if (NULL == n->child)
    +		return 0;
    +
    +	if (h->base_man)
    +		print_otag(h, TAG_A, "cThM", "Xr",
    +		    n->child->string, n->child->next == NULL ?
    +		    NULL : n->child->next->string);
    +	else
    +		print_otag(h, TAG_A, "cT", "Xr");
    +
    +	n = n->child;
    +	print_text(h, n->string);
    +
    +	if (NULL == (n = n->next))
    +		return 0;
    +
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, "(");
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, n->string);
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, ")");
    +	return 0;
    +}
    +
    +static int
    +mdoc_ns_pre(MDOC_ARGS)
    +{
    +
    +	if ( ! (NODE_LINE & n->flags))
    +		h->flags |= HTML_NOSPACE;
    +	return 1;
    +}
    +
    +static int
    +mdoc_ar_pre(MDOC_ARGS)
    +{
    +	print_otag(h, TAG_VAR, "cT", "Ar");
    +	return 1;
    +}
    +
    +static int
    +mdoc_xx_pre(MDOC_ARGS)
    +{
    +	print_otag(h, TAG_SPAN, "c", "Ux");
    +	return 1;
    +}
    +
    +static int
    +mdoc_it_pre(MDOC_ARGS)
    +{
    +	const struct roff_node	*bl;
    +	struct tag		*t;
    +	enum mdoc_list		 type;
    +
    +	bl = n->parent;
    +	while (bl->tok != MDOC_Bl)
    +		bl = bl->parent;
    +	type = bl->norm->Bl.type;
    +
    +	switch (type) {
    +	case LIST_bullet:
    +	case LIST_dash:
    +	case LIST_hyphen:
    +	case LIST_item:
    +	case LIST_enum:
    +		switch (n->type) {
    +		case ROFFT_HEAD:
    +			return 0;
    +		case ROFFT_BODY:
    +			print_otag(h, TAG_LI, "");
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	case LIST_diag:
    +	case LIST_hang:
    +	case LIST_inset:
    +	case LIST_ohang:
    +		switch (n->type) {
    +		case ROFFT_HEAD:
    +			print_otag(h, TAG_DT, "");
    +			break;
    +		case ROFFT_BODY:
    +			print_otag(h, TAG_DD, "");
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	case LIST_tag:
    +		switch (n->type) {
    +		case ROFFT_HEAD:
    +			if (h->style != NULL && !bl->norm->Bl.comp &&
    +			    (n->parent->prev == NULL ||
    +			     n->parent->prev->body == NULL ||
    +			     n->parent->prev->body->child != NULL)) {
    +				t = print_otag(h, TAG_DT, "");
    +				print_text(h, "\\ ");
    +				print_tagq(h, t);
    +				t = print_otag(h, TAG_DD, "");
    +				print_text(h, "\\ ");
    +				print_tagq(h, t);
    +			}
    +			print_otag(h, TAG_DT, "");
    +			break;
    +		case ROFFT_BODY:
    +			if (n->child == NULL) {
    +				print_otag(h, TAG_DD, "s", "width", "auto");
    +				print_text(h, "\\ ");
    +			} else
    +				print_otag(h, TAG_DD, "");
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	case LIST_column:
    +		switch (n->type) {
    +		case ROFFT_HEAD:
    +			break;
    +		case ROFFT_BODY:
    +			print_otag(h, TAG_TD, "");
    +			break;
    +		default:
    +			print_otag(h, TAG_TR, "");
    +		}
    +	default:
    +		break;
    +	}
    +
    +	return 1;
    +}
    +
    +static int
    +mdoc_bl_pre(MDOC_ARGS)
    +{
    +	char		 cattr[28];
    +	struct mdoc_bl	*bl;
    +	enum htmltag	 elemtype;
    +
    +	switch (n->type) {
    +	case ROFFT_BODY:
    +		return 1;
    +	case ROFFT_HEAD:
    +		return 0;
    +	default:
    +		break;
    +	}
    +
    +	bl = &n->norm->Bl;
    +	switch (bl->type) {
    +	case LIST_bullet:
    +		elemtype = TAG_UL;
    +		(void)strlcpy(cattr, "Bl-bullet", sizeof(cattr));
    +		break;
    +	case LIST_dash:
    +	case LIST_hyphen:
    +		elemtype = TAG_UL;
    +		(void)strlcpy(cattr, "Bl-dash", sizeof(cattr));
    +		break;
    +	case LIST_item:
    +		elemtype = TAG_UL;
    +		(void)strlcpy(cattr, "Bl-item", sizeof(cattr));
    +		break;
    +	case LIST_enum:
    +		elemtype = TAG_OL;
    +		(void)strlcpy(cattr, "Bl-enum", sizeof(cattr));
    +		break;
    +	case LIST_diag:
    +		elemtype = TAG_DL;
    +		(void)strlcpy(cattr, "Bl-diag", sizeof(cattr));
    +		break;
    +	case LIST_hang:
    +		elemtype = TAG_DL;
    +		(void)strlcpy(cattr, "Bl-hang", sizeof(cattr));
    +		break;
    +	case LIST_inset:
    +		elemtype = TAG_DL;
    +		(void)strlcpy(cattr, "Bl-inset", sizeof(cattr));
    +		break;
    +	case LIST_ohang:
    +		elemtype = TAG_DL;
    +		(void)strlcpy(cattr, "Bl-ohang", sizeof(cattr));
    +		break;
    +	case LIST_tag:
    +		if (bl->offs)
    +			print_otag(h, TAG_DIV, "c", "Bd-indent");
    +		print_otag(h, TAG_DL, "c", bl->comp ?
    +		    "Bl-tag Bl-compact" : "Bl-tag");
    +		return 1;
    +	case LIST_column:
    +		elemtype = TAG_TABLE;
    +		(void)strlcpy(cattr, "Bl-column", sizeof(cattr));
    +		break;
    +	default:
    +		abort();
    +	}
    +	if (bl->offs != NULL)
    +		(void)strlcat(cattr, " Bd-indent", sizeof(cattr));
    +	if (bl->comp)
    +		(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
    +	print_otag(h, elemtype, "c", cattr);
    +	return 1;
    +}
    +
    +static int
    +mdoc_ex_pre(MDOC_ARGS)
    +{
    +	if (n->prev)
    +		print_otag(h, TAG_BR, "");
    +	return 1;
    +}
    +
    +static int
    +mdoc_st_pre(MDOC_ARGS)
    +{
    +	print_otag(h, TAG_SPAN, "cT", "St");
    +	return 1;
    +}
    +
    +static int
    +mdoc_em_pre(MDOC_ARGS)
    +{
    +	print_otag(h, TAG_I, "cT", "Em");
    +	return 1;
    +}
    +
    +static int
    +mdoc_d1_pre(MDOC_ARGS)
    +{
    +	if (n->type != ROFFT_BLOCK)
    +		return 1;
    +
    +	print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
    +
    +	if (n->tok == MDOC_Dl)
    +		print_otag(h, TAG_CODE, "c", "Li");
    +
    +	return 1;
    +}
    +
    +static int
    +mdoc_sx_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	id = html_make_id(n, 0);
    +	print_otag(h, TAG_A, "cThR", "Sx", id);
    +	free(id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_bd_pre(MDOC_ARGS)
    +{
    +	int			 comp, sv;
    +	struct roff_node	*nn;
    +
    +	if (n->type == ROFFT_HEAD)
    +		return 0;
    +
    +	if (n->type == ROFFT_BLOCK) {
    +		comp = n->norm->Bd.comp;
    +		for (nn = n; nn && ! comp; nn = nn->parent) {
    +			if (nn->type != ROFFT_BLOCK)
    +				continue;
    +			if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok)
    +				comp = 1;
    +			if (nn->prev)
    +				break;
    +		}
    +		if ( ! comp)
    +			print_paragraph(h);
    +		return 1;
    +	}
    +
    +	/* Handle the -offset argument. */
    +
    +	if (n->norm->Bd.offs == NULL ||
    +	    ! strcmp(n->norm->Bd.offs, "left"))
    +		print_otag(h, TAG_DIV, "c", "Bd");
    +	else
    +		print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
    +
    +	if (n->norm->Bd.type != DISP_unfilled &&
    +	    n->norm->Bd.type != DISP_literal)
    +		return 1;
    +
    +	print_otag(h, TAG_PRE, "c", "Li");
    +
    +	/* This can be recursive: save & set our literal state. */
    +
    +	sv = h->flags & HTML_LITERAL;
    +	h->flags |= HTML_LITERAL;
    +
    +	for (nn = n->child; nn; nn = nn->next) {
    +		print_mdoc_node(meta, nn, h);
    +		/*
    +		 * If the printed node flushes its own line, then we
    +		 * needn't do it here as well.  This is hacky, but the
    +		 * notion of selective eoln whitespace is pretty dumb
    +		 * anyway, so don't sweat it.
    +		 */
    +		switch (nn->tok) {
    +		case ROFF_br:
    +		case ROFF_sp:
    +		case MDOC_Sm:
    +		case MDOC_Bl:
    +		case MDOC_D1:
    +		case MDOC_Dl:
    +		case MDOC_Lp:
    +		case MDOC_Pp:
    +			continue;
    +		default:
    +			break;
    +		}
    +		if (h->flags & HTML_NONEWLINE ||
    +		    (nn->next && ! (nn->next->flags & NODE_LINE)))
    +			continue;
    +		else if (nn->next)
    +			print_text(h, "\n");
    +
    +		h->flags |= HTML_NOSPACE;
    +	}
    +
    +	if (0 == sv)
    +		h->flags &= ~HTML_LITERAL;
    +
    +	return 0;
    +}
    +
    +static int
    +mdoc_pa_pre(MDOC_ARGS)
    +{
    +	print_otag(h, TAG_SPAN, "cT", "Pa");
    +	return 1;
    +}
    +
    +static int
    +mdoc_ad_pre(MDOC_ARGS)
    +{
    +	print_otag(h, TAG_SPAN, "c", "Ad");
    +	return 1;
    +}
    +
    +static int
    +mdoc_an_pre(MDOC_ARGS)
    +{
    +	if (n->norm->An.auth == AUTH_split) {
    +		h->flags &= ~HTML_NOSPLIT;
    +		h->flags |= HTML_SPLIT;
    +		return 0;
    +	}
    +	if (n->norm->An.auth == AUTH_nosplit) {
    +		h->flags &= ~HTML_SPLIT;
    +		h->flags |= HTML_NOSPLIT;
    +		return 0;
    +	}
    +
    +	if (h->flags & HTML_SPLIT)
    +		print_otag(h, TAG_BR, "");
    +
    +	if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
    +		h->flags |= HTML_SPLIT;
    +
    +	print_otag(h, TAG_SPAN, "cT", "An");
    +	return 1;
    +}
    +
    +static int
    +mdoc_cd_pre(MDOC_ARGS)
    +{
    +	synopsis_pre(h, n);
    +	print_otag(h, TAG_CODE, "cT", "Cd");
    +	return 1;
    +}
    +
    +static int
    +mdoc_dv_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	if ((id = cond_id(n)) != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_CODE, "cTi", "Dv", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_ev_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	if ((id = cond_id(n)) != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_CODE, "cTi", "Ev", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_er_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	id = n->sec == SEC_ERRORS &&
    +	    (n->parent->tok == MDOC_It ||
    +	     (n->parent->tok == MDOC_Bq &&
    +	      n->parent->parent->parent->tok == MDOC_It)) ?
    +	    html_make_id(n, 1) : NULL;
    +
    +	if (id != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_CODE, "cTi", "Er", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_fa_pre(MDOC_ARGS)
    +{
    +	const struct roff_node	*nn;
    +	struct tag		*t;
    +
    +	if (n->parent->tok != MDOC_Fo) {
    +		print_otag(h, TAG_VAR, "cT", "Fa");
    +		return 1;
    +	}
    +
    +	for (nn = n->child; nn; nn = nn->next) {
    +		t = print_otag(h, TAG_VAR, "cT", "Fa");
    +		print_text(h, nn->string);
    +		print_tagq(h, t);
    +		if (nn->next) {
    +			h->flags |= HTML_NOSPACE;
    +			print_text(h, ",");
    +		}
    +	}
    +
    +	if (n->child && n->next && n->next->tok == MDOC_Fa) {
    +		h->flags |= HTML_NOSPACE;
    +		print_text(h, ",");
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +mdoc_fd_pre(MDOC_ARGS)
    +{
    +	struct tag	*t;
    +	char		*buf, *cp;
    +
    +	synopsis_pre(h, n);
    +
    +	if (NULL == (n = n->child))
    +		return 0;
    +
    +	assert(n->type == ROFFT_TEXT);
    +
    +	if (strcmp(n->string, "#include")) {
    +		print_otag(h, TAG_CODE, "cT", "Fd");
    +		return 1;
    +	}
    +
    +	print_otag(h, TAG_CODE, "cT", "In");
    +	print_text(h, n->string);
    +
    +	if (NULL != (n = n->next)) {
    +		assert(n->type == ROFFT_TEXT);
    +
    +		if (h->base_includes) {
    +			cp = n->string;
    +			if (*cp == '<' || *cp == '"')
    +				cp++;
    +			buf = mandoc_strdup(cp);
    +			cp = strchr(buf, '\0') - 1;
    +			if (cp >= buf && (*cp == '>' || *cp == '"'))
    +				*cp = '\0';
    +			t = print_otag(h, TAG_A, "cThI", "In", buf);
    +			free(buf);
    +		} else
    +			t = print_otag(h, TAG_A, "cT", "In");
    +
    +		print_text(h, n->string);
    +		print_tagq(h, t);
    +
    +		n = n->next;
    +	}
    +
    +	for ( ; n; n = n->next) {
    +		assert(n->type == ROFFT_TEXT);
    +		print_text(h, n->string);
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +mdoc_vt_pre(MDOC_ARGS)
    +{
    +	if (n->type == ROFFT_BLOCK) {
    +		synopsis_pre(h, n);
    +		return 1;
    +	} else if (n->type == ROFFT_ELEM) {
    +		synopsis_pre(h, n);
    +	} else if (n->type == ROFFT_HEAD)
    +		return 0;
    +
    +	print_otag(h, TAG_VAR, "cT", "Vt");
    +	return 1;
    +}
    +
    +static int
    +mdoc_ft_pre(MDOC_ARGS)
    +{
    +	synopsis_pre(h, n);
    +	print_otag(h, TAG_VAR, "cT", "Ft");
    +	return 1;
    +}
    +
    +static int
    +mdoc_fn_pre(MDOC_ARGS)
    +{
    +	struct tag	*t;
    +	char		 nbuf[BUFSIZ];
    +	const char	*sp, *ep;
    +	int		 sz, pretty;
    +
    +	pretty = NODE_SYNPRETTY & n->flags;
    +	synopsis_pre(h, n);
    +
    +	/* Split apart into type and name. */
    +	assert(n->child->string);
    +	sp = n->child->string;
    +
    +	ep = strchr(sp, ' ');
    +	if (NULL != ep) {
    +		t = print_otag(h, TAG_VAR, "cT", "Ft");
    +
    +		while (ep) {
    +			sz = MIN((int)(ep - sp), BUFSIZ - 1);
    +			(void)memcpy(nbuf, sp, (size_t)sz);
    +			nbuf[sz] = '\0';
    +			print_text(h, nbuf);
    +			sp = ++ep;
    +			ep = strchr(sp, ' ');
    +		}
    +		print_tagq(h, t);
    +	}
    +
    +	t = print_otag(h, TAG_CODE, "cT", "Fn");
    +
    +	if (sp)
    +		print_text(h, sp);
    +
    +	print_tagq(h, t);
    +
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, "(");
    +	h->flags |= HTML_NOSPACE;
    +
    +	for (n = n->child->next; n; n = n->next) {
    +		if (NODE_SYNPRETTY & n->flags)
    +			t = print_otag(h, TAG_VAR, "cTs", "Fa",
    +			    "white-space", "nowrap");
    +		else
    +			t = print_otag(h, TAG_VAR, "cT", "Fa");
    +		print_text(h, n->string);
    +		print_tagq(h, t);
    +		if (n->next) {
    +			h->flags |= HTML_NOSPACE;
    +			print_text(h, ",");
    +		}
    +	}
    +
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, ")");
    +
    +	if (pretty) {
    +		h->flags |= HTML_NOSPACE;
    +		print_text(h, ";");
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +mdoc_sm_pre(MDOC_ARGS)
    +{
    +
    +	if (NULL == n->child)
    +		h->flags ^= HTML_NONOSPACE;
    +	else if (0 == strcmp("on", n->child->string))
    +		h->flags &= ~HTML_NONOSPACE;
    +	else
    +		h->flags |= HTML_NONOSPACE;
    +
    +	if ( ! (HTML_NONOSPACE & h->flags))
    +		h->flags &= ~HTML_NOSPACE;
    +
    +	return 0;
    +}
    +
    +static int
    +mdoc_skip_pre(MDOC_ARGS)
    +{
    +
    +	return 0;
    +}
    +
    +static int
    +mdoc_pp_pre(MDOC_ARGS)
    +{
    +
    +	print_paragraph(h);
    +	return 0;
    +}
    +
    +static int
    +mdoc_lk_pre(MDOC_ARGS)
    +{
    +	const struct roff_node *link, *descr, *punct;
    +	struct tag	*t;
    +
    +	if ((link = n->child) == NULL)
    +		return 0;
    +
    +	/* Find beginning of trailing punctuation. */
    +	punct = n->last;
    +	while (punct != link && punct->flags & NODE_DELIMC)
    +		punct = punct->prev;
    +	punct = punct->next;
    +
    +	/* Link target and link text. */
    +	descr = link->next;
    +	if (descr == punct)
    +		descr = link;  /* no text */
    +	t = print_otag(h, TAG_A, "cTh", "Lk", link->string);
    +	do {
    +		if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
    +			h->flags |= HTML_NOSPACE;
    +		print_text(h, descr->string);
    +		descr = descr->next;
    +	} while (descr != punct);
    +	print_tagq(h, t);
    +
    +	/* Trailing punctuation. */
    +	while (punct != NULL) {
    +		h->flags |= HTML_NOSPACE;
    +		print_text(h, punct->string);
    +		punct = punct->next;
    +	}
    +	return 0;
    +}
    +
    +static int
    +mdoc_mt_pre(MDOC_ARGS)
    +{
    +	struct tag	*t;
    +	char		*cp;
    +
    +	for (n = n->child; n; n = n->next) {
    +		assert(n->type == ROFFT_TEXT);
    +
    +		mandoc_asprintf(&cp, "mailto:%s", n->string);
    +		t = print_otag(h, TAG_A, "cTh", "Mt", cp);
    +		print_text(h, n->string);
    +		print_tagq(h, t);
    +		free(cp);
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +mdoc_fo_pre(MDOC_ARGS)
    +{
    +	struct tag	*t;
    +
    +	if (n->type == ROFFT_BODY) {
    +		h->flags |= HTML_NOSPACE;
    +		print_text(h, "(");
    +		h->flags |= HTML_NOSPACE;
    +		return 1;
    +	} else if (n->type == ROFFT_BLOCK) {
    +		synopsis_pre(h, n);
    +		return 1;
    +	}
    +
    +	if (n->child == NULL)
    +		return 0;
    +
    +	assert(n->child->string);
    +	t = print_otag(h, TAG_CODE, "cT", "Fn");
    +	print_text(h, n->child->string);
    +	print_tagq(h, t);
    +	return 0;
    +}
    +
    +static void
    +mdoc_fo_post(MDOC_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BODY)
    +		return;
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, ")");
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, ";");
    +}
    +
    +static int
    +mdoc_in_pre(MDOC_ARGS)
    +{
    +	struct tag	*t;
    +
    +	synopsis_pre(h, n);
    +	print_otag(h, TAG_CODE, "cT", "In");
    +
    +	/*
    +	 * The first argument of the `In' gets special treatment as
    +	 * being a linked value.  Subsequent values are printed
    +	 * afterward.  groff does similarly.  This also handles the case
    +	 * of no children.
    +	 */
    +
    +	if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags)
    +		print_text(h, "#include");
    +
    +	print_text(h, "<");
    +	h->flags |= HTML_NOSPACE;
    +
    +	if (NULL != (n = n->child)) {
    +		assert(n->type == ROFFT_TEXT);
    +
    +		if (h->base_includes)
    +			t = print_otag(h, TAG_A, "cThI", "In", n->string);
    +		else
    +			t = print_otag(h, TAG_A, "cT", "In");
    +		print_text(h, n->string);
    +		print_tagq(h, t);
    +
    +		n = n->next;
    +	}
    +
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, ">");
    +
    +	for ( ; n; n = n->next) {
    +		assert(n->type == ROFFT_TEXT);
    +		print_text(h, n->string);
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +mdoc_ic_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	if ((id = cond_id(n)) != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_CODE, "cTi", "Ic", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_va_pre(MDOC_ARGS)
    +{
    +	print_otag(h, TAG_VAR, "cT", "Va");
    +	return 1;
    +}
    +
    +static int
    +mdoc_ap_pre(MDOC_ARGS)
    +{
    +
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, "\\(aq");
    +	h->flags |= HTML_NOSPACE;
    +	return 1;
    +}
    +
    +static int
    +mdoc_bf_pre(MDOC_ARGS)
    +{
    +	const char	*cattr;
    +
    +	if (n->type == ROFFT_HEAD)
    +		return 0;
    +	else if (n->type != ROFFT_BODY)
    +		return 1;
    +
    +	if (FONT_Em == n->norm->Bf.font)
    +		cattr = "Bf Em";
    +	else if (FONT_Sy == n->norm->Bf.font)
    +		cattr = "Bf Sy";
    +	else if (FONT_Li == n->norm->Bf.font)
    +		cattr = "Bf Li";
    +	else
    +		cattr = "Bf No";
    +
    +	/* Cannot use TAG_SPAN because it may contain blocks. */
    +	print_otag(h, TAG_DIV, "c", cattr);
    +	return 1;
    +}
    +
    +static int
    +mdoc_ms_pre(MDOC_ARGS)
    +{
    +	char *id;
    +
    +	if ((id = cond_id(n)) != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_SPAN, "cTi", "Ms", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_igndelim_pre(MDOC_ARGS)
    +{
    +
    +	h->flags |= HTML_IGNDELIM;
    +	return 1;
    +}
    +
    +static void
    +mdoc_pf_post(MDOC_ARGS)
    +{
    +
    +	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
    +		h->flags |= HTML_NOSPACE;
    +}
    +
    +static int
    +mdoc_rs_pre(MDOC_ARGS)
    +{
    +	if (n->type != ROFFT_BLOCK)
    +		return 1;
    +
    +	if (n->prev && SEC_SEE_ALSO == n->sec)
    +		print_paragraph(h);
    +
    +	print_otag(h, TAG_CITE, "cT", "Rs");
    +	return 1;
    +}
    +
    +static int
    +mdoc_no_pre(MDOC_ARGS)
    +{
    +	char *id;
    +
    +	if ((id = cond_id(n)) != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_SPAN, "ci", "No", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_li_pre(MDOC_ARGS)
    +{
    +	char	*id;
    +
    +	if ((id = cond_id(n)) != NULL)
    +		print_otag(h, TAG_A, "chR", "permalink", id);
    +	print_otag(h, TAG_CODE, "ci", "Li", id);
    +	return 1;
    +}
    +
    +static int
    +mdoc_sy_pre(MDOC_ARGS)
    +{
    +	print_otag(h, TAG_B, "cT", "Sy");
    +	return 1;
    +}
    +
    +static int
    +mdoc_lb_pre(MDOC_ARGS)
    +{
    +	if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
    +		print_otag(h, TAG_BR, "");
    +
    +	print_otag(h, TAG_SPAN, "cT", "Lb");
    +	return 1;
    +}
    +
    +static int
    +mdoc__x_pre(MDOC_ARGS)
    +{
    +	const char	*cattr;
    +	enum htmltag	 t;
    +
    +	t = TAG_SPAN;
    +
    +	switch (n->tok) {
    +	case MDOC__A:
    +		cattr = "RsA";
    +		if (n->prev && MDOC__A == n->prev->tok)
    +			if (NULL == n->next || MDOC__A != n->next->tok)
    +				print_text(h, "and");
    +		break;
    +	case MDOC__B:
    +		t = TAG_I;
    +		cattr = "RsB";
    +		break;
    +	case MDOC__C:
    +		cattr = "RsC";
    +		break;
    +	case MDOC__D:
    +		cattr = "RsD";
    +		break;
    +	case MDOC__I:
    +		t = TAG_I;
    +		cattr = "RsI";
    +		break;
    +	case MDOC__J:
    +		t = TAG_I;
    +		cattr = "RsJ";
    +		break;
    +	case MDOC__N:
    +		cattr = "RsN";
    +		break;
    +	case MDOC__O:
    +		cattr = "RsO";
    +		break;
    +	case MDOC__P:
    +		cattr = "RsP";
    +		break;
    +	case MDOC__Q:
    +		cattr = "RsQ";
    +		break;
    +	case MDOC__R:
    +		cattr = "RsR";
    +		break;
    +	case MDOC__T:
    +		cattr = "RsT";
    +		break;
    +	case MDOC__U:
    +		print_otag(h, TAG_A, "ch", "RsU", n->child->string);
    +		return 1;
    +	case MDOC__V:
    +		cattr = "RsV";
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	print_otag(h, t, "c", cattr);
    +	return 1;
    +}
    +
    +static void
    +mdoc__x_post(MDOC_ARGS)
    +{
    +
    +	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
    +		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
    +			if (NULL == n->prev || MDOC__A != n->prev->tok)
    +				return;
    +
    +	/* TODO: %U */
    +
    +	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
    +		return;
    +
    +	h->flags |= HTML_NOSPACE;
    +	print_text(h, n->next ? "," : ".");
    +}
    +
    +static int
    +mdoc_bk_pre(MDOC_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		break;
    +	case ROFFT_HEAD:
    +		return 0;
    +	case ROFFT_BODY:
    +		if (n->parent->args != NULL || n->prev->child == NULL)
    +			h->flags |= HTML_PREKEEP;
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	return 1;
    +}
    +
    +static void
    +mdoc_bk_post(MDOC_ARGS)
    +{
    +
    +	if (n->type == ROFFT_BODY)
    +		h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
    +}
    +
    +static int
    +mdoc_quote_pre(MDOC_ARGS)
    +{
    +	if (n->type != ROFFT_BODY)
    +		return 1;
    +
    +	switch (n->tok) {
    +	case MDOC_Ao:
    +	case MDOC_Aq:
    +		print_text(h, n->child != NULL && n->child->next == NULL &&
    +		    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
    +		break;
    +	case MDOC_Bro:
    +	case MDOC_Brq:
    +		print_text(h, "\\(lC");
    +		break;
    +	case MDOC_Bo:
    +	case MDOC_Bq:
    +		print_text(h, "\\(lB");
    +		break;
    +	case MDOC_Oo:
    +	case MDOC_Op:
    +		print_text(h, "\\(lB");
    +		h->flags |= HTML_NOSPACE;
    +		/* Cannot use TAG_SPAN because it may contain blocks. */
    +		print_otag(h, TAG_IDIV, "c", "Op");
    +		break;
    +	case MDOC_En:
    +		if (NULL == n->norm->Es ||
    +		    NULL == n->norm->Es->child)
    +			return 1;
    +		print_text(h, n->norm->Es->child->string);
    +		break;
    +	case MDOC_Do:
    +	case MDOC_Dq:
    +	case MDOC_Qo:
    +	case MDOC_Qq:
    +		print_text(h, "\\(lq");
    +		break;
    +	case MDOC_Po:
    +	case MDOC_Pq:
    +		print_text(h, "(");
    +		break;
    +	case MDOC_Ql:
    +		print_text(h, "\\(oq");
    +		h->flags |= HTML_NOSPACE;
    +		print_otag(h, TAG_CODE, "c", "Li");
    +		break;
    +	case MDOC_So:
    +	case MDOC_Sq:
    +		print_text(h, "\\(oq");
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	h->flags |= HTML_NOSPACE;
    +	return 1;
    +}
    +
    +static void
    +mdoc_quote_post(MDOC_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
    +		return;
    +
    +	h->flags |= HTML_NOSPACE;
    +
    +	switch (n->tok) {
    +	case MDOC_Ao:
    +	case MDOC_Aq:
    +		print_text(h, n->child != NULL && n->child->next == NULL &&
    +		    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
    +		break;
    +	case MDOC_Bro:
    +	case MDOC_Brq:
    +		print_text(h, "\\(rC");
    +		break;
    +	case MDOC_Oo:
    +	case MDOC_Op:
    +	case MDOC_Bo:
    +	case MDOC_Bq:
    +		print_text(h, "\\(rB");
    +		break;
    +	case MDOC_En:
    +		if (n->norm->Es == NULL ||
    +		    n->norm->Es->child == NULL ||
    +		    n->norm->Es->child->next == NULL)
    +			h->flags &= ~HTML_NOSPACE;
    +		else
    +			print_text(h, n->norm->Es->child->next->string);
    +		break;
    +	case MDOC_Qo:
    +	case MDOC_Qq:
    +	case MDOC_Do:
    +	case MDOC_Dq:
    +		print_text(h, "\\(rq");
    +		break;
    +	case MDOC_Po:
    +	case MDOC_Pq:
    +		print_text(h, ")");
    +		break;
    +	case MDOC_Ql:
    +	case MDOC_So:
    +	case MDOC_Sq:
    +		print_text(h, "\\(cq");
    +		break;
    +	default:
    +		abort();
    +	}
    +}
    +
    +static int
    +mdoc_eo_pre(MDOC_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BODY)
    +		return 1;
    +
    +	if (n->end == ENDBODY_NOT &&
    +	    n->parent->head->child == NULL &&
    +	    n->child != NULL &&
    +	    n->child->end != ENDBODY_NOT)
    +		print_text(h, "\\&");
    +	else if (n->end != ENDBODY_NOT ? n->child != NULL :
    +	    n->parent->head->child != NULL && (n->child != NULL ||
    +	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
    +		h->flags |= HTML_NOSPACE;
    +	return 1;
    +}
    +
    +static void
    +mdoc_eo_post(MDOC_ARGS)
    +{
    +	int	 body, tail;
    +
    +	if (n->type != ROFFT_BODY)
    +		return;
    +
    +	if (n->end != ENDBODY_NOT) {
    +		h->flags &= ~HTML_NOSPACE;
    +		return;
    +	}
    +
    +	body = n->child != NULL || n->parent->head->child != NULL;
    +	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
    +
    +	if (body && tail)
    +		h->flags |= HTML_NOSPACE;
    +	else if ( ! tail)
    +		h->flags &= ~HTML_NOSPACE;
    +}
    
    Property changes on: head/contrib/mandoc/mdoc_html.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc_man.c
    ===================================================================
    --- head/contrib/mandoc/mdoc_man.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc_man.c	(revision 338826)
    @@ -0,0 +1,1803 @@
    +/*	$Id: mdoc_man.c,v 1.126 2018/04/11 17:11:13 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "man.h"
    +#include "out.h"
    +#include "main.h"
    +
    +#define	DECL_ARGS const struct roff_meta *meta, struct roff_node *n
    +
    +typedef	int	(*int_fp)(DECL_ARGS);
    +typedef	void	(*void_fp)(DECL_ARGS);
    +
    +struct	manact {
    +	int_fp		  cond; /* DON'T run actions */
    +	int_fp		  pre; /* pre-node action */
    +	void_fp		  post; /* post-node action */
    +	const char	 *prefix; /* pre-node string constant */
    +	const char	 *suffix; /* post-node string constant */
    +};
    +
    +static	int	  cond_body(DECL_ARGS);
    +static	int	  cond_head(DECL_ARGS);
    +static  void	  font_push(char);
    +static	void	  font_pop(void);
    +static	int	  man_strlen(const char *);
    +static	void	  mid_it(void);
    +static	void	  post__t(DECL_ARGS);
    +static	void	  post_aq(DECL_ARGS);
    +static	void	  post_bd(DECL_ARGS);
    +static	void	  post_bf(DECL_ARGS);
    +static	void	  post_bk(DECL_ARGS);
    +static	void	  post_bl(DECL_ARGS);
    +static	void	  post_dl(DECL_ARGS);
    +static	void	  post_en(DECL_ARGS);
    +static	void	  post_enc(DECL_ARGS);
    +static	void	  post_eo(DECL_ARGS);
    +static	void	  post_fa(DECL_ARGS);
    +static	void	  post_fd(DECL_ARGS);
    +static	void	  post_fl(DECL_ARGS);
    +static	void	  post_fn(DECL_ARGS);
    +static	void	  post_fo(DECL_ARGS);
    +static	void	  post_font(DECL_ARGS);
    +static	void	  post_in(DECL_ARGS);
    +static	void	  post_it(DECL_ARGS);
    +static	void	  post_lb(DECL_ARGS);
    +static	void	  post_nm(DECL_ARGS);
    +static	void	  post_percent(DECL_ARGS);
    +static	void	  post_pf(DECL_ARGS);
    +static	void	  post_sect(DECL_ARGS);
    +static	void	  post_vt(DECL_ARGS);
    +static	int	  pre__t(DECL_ARGS);
    +static	int	  pre_an(DECL_ARGS);
    +static	int	  pre_ap(DECL_ARGS);
    +static	int	  pre_aq(DECL_ARGS);
    +static	int	  pre_bd(DECL_ARGS);
    +static	int	  pre_bf(DECL_ARGS);
    +static	int	  pre_bk(DECL_ARGS);
    +static	int	  pre_bl(DECL_ARGS);
    +static	void	  pre_br(DECL_ARGS);
    +static	int	  pre_dl(DECL_ARGS);
    +static	int	  pre_en(DECL_ARGS);
    +static	int	  pre_enc(DECL_ARGS);
    +static	int	  pre_em(DECL_ARGS);
    +static	int	  pre_skip(DECL_ARGS);
    +static	int	  pre_eo(DECL_ARGS);
    +static	int	  pre_ex(DECL_ARGS);
    +static	int	  pre_fa(DECL_ARGS);
    +static	int	  pre_fd(DECL_ARGS);
    +static	int	  pre_fl(DECL_ARGS);
    +static	int	  pre_fn(DECL_ARGS);
    +static	int	  pre_fo(DECL_ARGS);
    +static	void	  pre_ft(DECL_ARGS);
    +static	int	  pre_Ft(DECL_ARGS);
    +static	int	  pre_in(DECL_ARGS);
    +static	int	  pre_it(DECL_ARGS);
    +static	int	  pre_lk(DECL_ARGS);
    +static	int	  pre_li(DECL_ARGS);
    +static	int	  pre_nm(DECL_ARGS);
    +static	int	  pre_no(DECL_ARGS);
    +static	int	  pre_ns(DECL_ARGS);
    +static	void	  pre_onearg(DECL_ARGS);
    +static	int	  pre_pp(DECL_ARGS);
    +static	int	  pre_rs(DECL_ARGS);
    +static	int	  pre_sm(DECL_ARGS);
    +static	void	  pre_sp(DECL_ARGS);
    +static	int	  pre_sect(DECL_ARGS);
    +static	int	  pre_sy(DECL_ARGS);
    +static	void	  pre_syn(const struct roff_node *);
    +static	void	  pre_ta(DECL_ARGS);
    +static	int	  pre_vt(DECL_ARGS);
    +static	int	  pre_xr(DECL_ARGS);
    +static	void	  print_word(const char *);
    +static	void	  print_line(const char *, int);
    +static	void	  print_block(const char *, int);
    +static	void	  print_offs(const char *, int);
    +static	void	  print_width(const struct mdoc_bl *,
    +			const struct roff_node *);
    +static	void	  print_count(int *);
    +static	void	  print_node(DECL_ARGS);
    +
    +static	const void_fp roff_manacts[ROFF_MAX] = {
    +	pre_br,		/* br */
    +	pre_onearg,	/* ce */
    +	pre_ft,		/* ft */
    +	pre_onearg,	/* ll */
    +	pre_onearg,	/* mc */
    +	pre_onearg,	/* po */
    +	pre_onearg,	/* rj */
    +	pre_sp,		/* sp */
    +	pre_ta,		/* ta */
    +	pre_onearg,	/* ti */
    +};
    +
    +static	const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
    +	{ NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
    +	{ NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
    +	{ NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
    +	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
    +	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
    +	{ cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
    +	{ cond_body, pre_bl, post_bl, NULL, NULL }, /* Bl */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* El */
    +	{ NULL, pre_it, post_it, NULL, NULL }, /* It */
    +	{ NULL, pre_em, post_font, NULL, NULL }, /* Ad */
    +	{ NULL, pre_an, NULL, NULL, NULL }, /* An */
    +	{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
    +	{ NULL, pre_em, post_font, NULL, NULL }, /* Ar */
    +	{ NULL, pre_sy, post_font, NULL, NULL }, /* Cd */
    +	{ NULL, pre_sy, post_font, NULL, NULL }, /* Cm */
    +	{ NULL, pre_li, post_font, NULL, NULL }, /* Dv */
    +	{ NULL, pre_li, post_font, NULL, NULL }, /* Er */
    +	{ NULL, pre_li, post_font, NULL, NULL }, /* Ev */
    +	{ NULL, pre_ex, NULL, NULL, NULL }, /* Ex */
    +	{ NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */
    +	{ NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */
    +	{ NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */
    +	{ NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */
    +	{ NULL, pre_Ft, post_font, NULL, NULL }, /* Ft */
    +	{ NULL, pre_sy, post_font, NULL, NULL }, /* Ic */
    +	{ NULL, pre_in, post_in, NULL, NULL }, /* In */
    +	{ NULL, pre_li, post_font, NULL, NULL }, /* Li */
    +	{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
    +	{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
    +	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
    +	{ NULL, pre_Ft, post_font, NULL, NULL }, /* Ot */
    +	{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
    +	{ NULL, pre_ex, NULL, NULL, NULL }, /* Rv */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* St */
    +	{ NULL, pre_em, post_font, NULL, NULL }, /* Va */
    +	{ NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */
    +	{ NULL, pre_xr, NULL, NULL, NULL }, /* Xr */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %A */
    +	{ NULL, pre_em, post_percent, NULL, NULL }, /* %B */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %D */
    +	{ NULL, pre_em, post_percent, NULL, NULL }, /* %I */
    +	{ NULL, pre_em, post_percent, NULL, NULL }, /* %J */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %N */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %O */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %P */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %R */
    +	{ NULL, pre__t, post__t, NULL, NULL }, /* %T */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %V */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
    +	{ cond_body, pre_aq, post_aq, NULL, NULL }, /* Ao */
    +	{ cond_body, pre_aq, post_aq, NULL, NULL }, /* Aq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* At */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
    +	{ NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */
    +	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
    +	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
    +	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bsx */
    +	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bx */
    +	{ NULL, pre_skip, NULL, NULL, NULL }, /* Db */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
    +	{ cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Do */
    +	{ cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Dq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
    +	{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
    +	{ cond_body, pre_eo, post_eo, NULL, NULL }, /* Eo */
    +	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Fx */
    +	{ NULL, pre_sy, post_font, NULL, NULL }, /* Ms */
    +	{ NULL, pre_no, NULL, NULL, NULL }, /* No */
    +	{ NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
    +	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Nx */
    +	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Ox */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
    +	{ NULL, NULL, post_pf, NULL, NULL }, /* Pf */
    +	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
    +	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
    +	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Ql */
    +	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */
    +	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
    +	{ cond_body, pre_rs, NULL, NULL, NULL }, /* Rs */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
    +	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* So */
    +	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Sq */
    +	{ NULL, pre_sm, NULL, NULL, NULL }, /* Sm */
    +	{ NULL, pre_em, post_font, NULL, NULL }, /* Sx */
    +	{ NULL, pre_sy, post_font, NULL, NULL }, /* Sy */
    +	{ NULL, pre_li, post_font, NULL, NULL }, /* Tn */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ux */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Xc */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Xo */
    +	{ NULL, pre_fo, post_fo, NULL, NULL }, /* Fo */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Fc */
    +	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
    +	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bk */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Bt */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
    +	{ NULL, pre_em, post_font, NULL, NULL }, /* Fr */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
    +	{ NULL, NULL, post_lb, NULL, NULL }, /* Lb */
    +	{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
    +	{ NULL, pre_lk, NULL, NULL, NULL }, /* Lk */
    +	{ NULL, pre_em, post_font, NULL, NULL }, /* Mt */
    +	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
    +	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %C */
    +	{ NULL, pre_skip, NULL, NULL, NULL }, /* Es */
    +	{ cond_body, pre_en, post_en, NULL, NULL }, /* En */
    +	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Dx */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %Q */
    +	{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
    +};
    +static	const struct manact *const manacts = __manacts - MDOC_Dd;
    +
    +static	int		outflags;
    +#define	MMAN_spc	(1 << 0)  /* blank character before next word */
    +#define	MMAN_spc_force	(1 << 1)  /* even before trailing punctuation */
    +#define	MMAN_nl		(1 << 2)  /* break man(7) code line */
    +#define	MMAN_br		(1 << 3)  /* break output line */
    +#define	MMAN_sp		(1 << 4)  /* insert a blank output line */
    +#define	MMAN_PP		(1 << 5)  /* reset indentation etc. */
    +#define	MMAN_Sm		(1 << 6)  /* horizontal spacing mode */
    +#define	MMAN_Bk		(1 << 7)  /* word keep mode */
    +#define	MMAN_Bk_susp	(1 << 8)  /* suspend this (after a macro) */
    +#define	MMAN_An_split	(1 << 9)  /* author mode is "split" */
    +#define	MMAN_An_nosplit	(1 << 10) /* author mode is "nosplit" */
    +#define	MMAN_PD		(1 << 11) /* inter-paragraph spacing disabled */
    +#define	MMAN_nbrword	(1 << 12) /* do not break the next word */
    +
    +#define	BL_STACK_MAX	32
    +
    +static	int		Bl_stack[BL_STACK_MAX];  /* offsets [chars] */
    +static	int		Bl_stack_post[BL_STACK_MAX];  /* add final .RE */
    +static	int		Bl_stack_len;  /* number of nested Bl blocks */
    +static	int		TPremain;  /* characters before tag is full */
    +
    +static	struct {
    +	char	*head;
    +	char	*tail;
    +	size_t	 size;
    +}	fontqueue;
    +
    +
    +static int
    +man_strlen(const char *cp)
    +{
    +	size_t	 rsz;
    +	int	 skip, sz;
    +
    +	sz = 0;
    +	skip = 0;
    +	for (;;) {
    +		rsz = strcspn(cp, "\\");
    +		if (rsz) {
    +			cp += rsz;
    +			if (skip) {
    +				skip = 0;
    +				rsz--;
    +			}
    +			sz += rsz;
    +		}
    +		if ('\0' == *cp)
    +			break;
    +		cp++;
    +		switch (mandoc_escape(&cp, NULL, NULL)) {
    +		case ESCAPE_ERROR:
    +			return sz;
    +		case ESCAPE_UNICODE:
    +		case ESCAPE_NUMBERED:
    +		case ESCAPE_SPECIAL:
    +		case ESCAPE_OVERSTRIKE:
    +			if (skip)
    +				skip = 0;
    +			else
    +				sz++;
    +			break;
    +		case ESCAPE_SKIPCHAR:
    +			skip = 1;
    +			break;
    +		default:
    +			break;
    +		}
    +	}
    +	return sz;
    +}
    +
    +static void
    +font_push(char newfont)
    +{
    +
    +	if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) {
    +		fontqueue.size += 8;
    +		fontqueue.head = mandoc_realloc(fontqueue.head,
    +		    fontqueue.size);
    +	}
    +	*fontqueue.tail = newfont;
    +	print_word("");
    +	printf("\\f");
    +	putchar(newfont);
    +	outflags &= ~MMAN_spc;
    +}
    +
    +static void
    +font_pop(void)
    +{
    +
    +	if (fontqueue.tail > fontqueue.head)
    +		fontqueue.tail--;
    +	outflags &= ~MMAN_spc;
    +	print_word("");
    +	printf("\\f");
    +	putchar(*fontqueue.tail);
    +}
    +
    +static void
    +print_word(const char *s)
    +{
    +
    +	if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) {
    +		/*
    +		 * If we need a newline, print it now and start afresh.
    +		 */
    +		if (MMAN_PP & outflags) {
    +			if (MMAN_sp & outflags) {
    +				if (MMAN_PD & outflags) {
    +					printf("\n.PD");
    +					outflags &= ~MMAN_PD;
    +				}
    +			} else if ( ! (MMAN_PD & outflags)) {
    +				printf("\n.PD 0");
    +				outflags |= MMAN_PD;
    +			}
    +			printf("\n.PP\n");
    +		} else if (MMAN_sp & outflags)
    +			printf("\n.sp\n");
    +		else if (MMAN_br & outflags)
    +			printf("\n.br\n");
    +		else if (MMAN_nl & outflags)
    +			putchar('\n');
    +		outflags &= ~(MMAN_PP|MMAN_sp|MMAN_br|MMAN_nl|MMAN_spc);
    +		if (1 == TPremain)
    +			printf(".br\n");
    +		TPremain = 0;
    +	} else if (MMAN_spc & outflags) {
    +		/*
    +		 * If we need a space, only print it if
    +		 * (1) it is forced by `No' or
    +		 * (2) what follows is not terminating punctuation or
    +		 * (3) what follows is longer than one character.
    +		 */
    +		if (MMAN_spc_force & outflags || '\0' == s[0] ||
    +		    NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) {
    +			if (MMAN_Bk & outflags &&
    +			    ! (MMAN_Bk_susp & outflags))
    +				putchar('\\');
    +			putchar(' ');
    +			if (TPremain)
    +				TPremain--;
    +		}
    +	}
    +
    +	/*
    +	 * Reassign needing space if we're not following opening
    +	 * punctuation.
    +	 */
    +	if (MMAN_Sm & outflags && ('\0' == s[0] ||
    +	    (('(' != s[0] && '[' != s[0]) || '\0' != s[1])))
    +		outflags |= MMAN_spc;
    +	else
    +		outflags &= ~MMAN_spc;
    +	outflags &= ~(MMAN_spc_force | MMAN_Bk_susp);
    +
    +	for ( ; *s; s++) {
    +		switch (*s) {
    +		case ASCII_NBRSP:
    +			printf("\\ ");
    +			break;
    +		case ASCII_HYPH:
    +			putchar('-');
    +			break;
    +		case ASCII_BREAK:
    +			printf("\\:");
    +			break;
    +		case ' ':
    +			if (MMAN_nbrword & outflags) {
    +				printf("\\ ");
    +				break;
    +			}
    +			/* FALLTHROUGH */
    +		default:
    +			putchar((unsigned char)*s);
    +			break;
    +		}
    +		if (TPremain)
    +			TPremain--;
    +	}
    +	outflags &= ~MMAN_nbrword;
    +}
    +
    +static void
    +print_line(const char *s, int newflags)
    +{
    +
    +	outflags |= MMAN_nl;
    +	print_word(s);
    +	outflags |= newflags;
    +}
    +
    +static void
    +print_block(const char *s, int newflags)
    +{
    +
    +	outflags &= ~MMAN_PP;
    +	if (MMAN_sp & outflags) {
    +		outflags &= ~(MMAN_sp | MMAN_br);
    +		if (MMAN_PD & outflags) {
    +			print_line(".PD", 0);
    +			outflags &= ~MMAN_PD;
    +		}
    +	} else if (! (MMAN_PD & outflags))
    +		print_line(".PD 0", MMAN_PD);
    +	outflags |= MMAN_nl;
    +	print_word(s);
    +	outflags |= MMAN_Bk_susp | newflags;
    +}
    +
    +static void
    +print_offs(const char *v, int keywords)
    +{
    +	char		  buf[24];
    +	struct roffsu	  su;
    +	const char	 *end;
    +	int		  sz;
    +
    +	print_line(".RS", MMAN_Bk_susp);
    +
    +	/* Convert v into a number (of characters). */
    +	if (NULL == v || '\0' == *v || (keywords && !strcmp(v, "left")))
    +		sz = 0;
    +	else if (keywords && !strcmp(v, "indent"))
    +		sz = 6;
    +	else if (keywords && !strcmp(v, "indent-two"))
    +		sz = 12;
    +	else {
    +		end = a2roffsu(v, &su, SCALE_EN);
    +		if (end == NULL || *end != '\0')
    +			sz = man_strlen(v);
    +		else if (SCALE_EN == su.unit)
    +			sz = su.scale;
    +		else {
    +			/*
    +			 * XXX
    +			 * If we are inside an enclosing list,
    +			 * there is no easy way to add the two
    +			 * indentations because they are provided
    +			 * in terms of different units.
    +			 */
    +			print_word(v);
    +			outflags |= MMAN_nl;
    +			return;
    +		}
    +	}
    +
    +	/*
    +	 * We are inside an enclosing list.
    +	 * Add the two indentations.
    +	 */
    +	if (Bl_stack_len)
    +		sz += Bl_stack[Bl_stack_len - 1];
    +
    +	(void)snprintf(buf, sizeof(buf), "%dn", sz);
    +	print_word(buf);
    +	outflags |= MMAN_nl;
    +}
    +
    +/*
    + * Set up the indentation for a list item; used from pre_it().
    + */
    +static void
    +print_width(const struct mdoc_bl *bl, const struct roff_node *child)
    +{
    +	char		  buf[24];
    +	struct roffsu	  su;
    +	const char	 *end;
    +	int		  numeric, remain, sz, chsz;
    +
    +	numeric = 1;
    +	remain = 0;
    +
    +	/* Convert the width into a number (of characters). */
    +	if (bl->width == NULL)
    +		sz = (bl->type == LIST_hang) ? 6 : 0;
    +	else {
    +		end = a2roffsu(bl->width, &su, SCALE_MAX);
    +		if (end == NULL || *end != '\0')
    +			sz = man_strlen(bl->width);
    +		else if (SCALE_EN == su.unit)
    +			sz = su.scale;
    +		else {
    +			sz = 0;
    +			numeric = 0;
    +		}
    +	}
    +
    +	/* XXX Rough estimation, might have multiple parts. */
    +	if (bl->type == LIST_enum)
    +		chsz = (bl->count > 8) + 1;
    +	else if (child != NULL && child->type == ROFFT_TEXT)
    +		chsz = man_strlen(child->string);
    +	else
    +		chsz = 0;
    +
    +	/* Maybe we are inside an enclosing list? */
    +	mid_it();
    +
    +	/*
    +	 * Save our own indentation,
    +	 * such that child lists can use it.
    +	 */
    +	Bl_stack[Bl_stack_len++] = sz + 2;
    +
    +	/* Set up the current list. */
    +	if (chsz > sz && bl->type != LIST_tag)
    +		print_block(".HP", 0);
    +	else {
    +		print_block(".TP", 0);
    +		remain = sz + 2;
    +	}
    +	if (numeric) {
    +		(void)snprintf(buf, sizeof(buf), "%dn", sz + 2);
    +		print_word(buf);
    +	} else
    +		print_word(bl->width);
    +	TPremain = remain;
    +}
    +
    +static void
    +print_count(int *count)
    +{
    +	char		  buf[24];
    +
    +	(void)snprintf(buf, sizeof(buf), "%d.\\&", ++*count);
    +	print_word(buf);
    +}
    +
    +void
    +man_man(void *arg, const struct roff_man *man)
    +{
    +
    +	/*
    +	 * Dump the keep buffer.
    +	 * We're guaranteed by now that this exists (is non-NULL).
    +	 * Flush stdout afterward, just in case.
    +	 */
    +	fputs(mparse_getkeep(man_mparse(man)), stdout);
    +	fflush(stdout);
    +}
    +
    +void
    +man_mdoc(void *arg, const struct roff_man *mdoc)
    +{
    +	struct roff_node *n;
    +
    +	printf(".\\\" Automatically generated from an mdoc input file."
    +	    "  Do not edit.\n");
    +	for (n = mdoc->first->child; n != NULL; n = n->next) {
    +		if (n->type != ROFFT_COMMENT)
    +			break;
    +		printf(".\\\"%s\n", n->string);
    +	}
    +
    +	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
    +	    mdoc->meta.title,
    +	    (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
    +	    mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);
    +
    +	/* Disable hyphenation and if nroff, disable justification. */
    +	printf(".nh\n.if n .ad l");
    +
    +	outflags = MMAN_nl | MMAN_Sm;
    +	if (0 == fontqueue.size) {
    +		fontqueue.size = 8;
    +		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
    +		*fontqueue.tail = 'R';
    +	}
    +	for (; n != NULL; n = n->next)
    +		print_node(&mdoc->meta, n);
    +	putchar('\n');
    +}
    +
    +static void
    +print_node(DECL_ARGS)
    +{
    +	const struct manact	*act;
    +	struct roff_node	*sub;
    +	int			 cond, do_sub;
    +
    +	if (n->flags & NODE_NOPRT)
    +		return;
    +
    +	/*
    +	 * Break the line if we were parsed subsequent the current node.
    +	 * This makes the page structure be more consistent.
    +	 */
    +	if (MMAN_spc & outflags && NODE_LINE & n->flags)
    +		outflags |= MMAN_nl;
    +
    +	act = NULL;
    +	cond = 0;
    +	do_sub = 1;
    +	n->flags &= ~NODE_ENDED;
    +
    +	if (n->type == ROFFT_TEXT) {
    +		/*
    +		 * Make sure that we don't happen to start with a
    +		 * control character at the start of a line.
    +		 */
    +		if (MMAN_nl & outflags &&
    +		    ('.' == *n->string || '\'' == *n->string)) {
    +			print_word("");
    +			printf("\\&");
    +			outflags &= ~MMAN_spc;
    +		}
    +		if (n->flags & NODE_DELIMC)
    +			outflags &= ~(MMAN_spc | MMAN_spc_force);
    +		else if (outflags & MMAN_Sm)
    +			outflags |= MMAN_spc_force;
    +		print_word(n->string);
    +		if (n->flags & NODE_DELIMO)
    +			outflags &= ~(MMAN_spc | MMAN_spc_force);
    +		else if (outflags & MMAN_Sm)
    +			outflags |= MMAN_spc;
    +	} else if (n->tok < ROFF_MAX) {
    +		(*roff_manacts[n->tok])(meta, n);
    +		return;
    +	} else {
    +		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
    +		/*
    +		 * Conditionally run the pre-node action handler for a
    +		 * node.
    +		 */
    +		act = manacts + n->tok;
    +		cond = act->cond == NULL || (*act->cond)(meta, n);
    +		if (cond && act->pre != NULL &&
    +		    (n->end == ENDBODY_NOT || n->child != NULL))
    +			do_sub = (*act->pre)(meta, n);
    +	}
    +
    +	/*
    +	 * Conditionally run all child nodes.
    +	 * Note that this iterates over children instead of using
    +	 * recursion.  This prevents unnecessary depth in the stack.
    +	 */
    +	if (do_sub)
    +		for (sub = n->child; sub; sub = sub->next)
    +			print_node(meta, sub);
    +
    +	/*
    +	 * Lastly, conditionally run the post-node handler.
    +	 */
    +	if (NODE_ENDED & n->flags)
    +		return;
    +
    +	if (cond && act->post)
    +		(*act->post)(meta, n);
    +
    +	if (ENDBODY_NOT != n->end)
    +		n->body->flags |= NODE_ENDED;
    +}
    +
    +static int
    +cond_head(DECL_ARGS)
    +{
    +
    +	return n->type == ROFFT_HEAD;
    +}
    +
    +static int
    +cond_body(DECL_ARGS)
    +{
    +
    +	return n->type == ROFFT_BODY;
    +}
    +
    +static int
    +pre_enc(DECL_ARGS)
    +{
    +	const char	*prefix;
    +
    +	prefix = manacts[n->tok].prefix;
    +	if (NULL == prefix)
    +		return 1;
    +	print_word(prefix);
    +	outflags &= ~MMAN_spc;
    +	return 1;
    +}
    +
    +static void
    +post_enc(DECL_ARGS)
    +{
    +	const char *suffix;
    +
    +	suffix = manacts[n->tok].suffix;
    +	if (NULL == suffix)
    +		return;
    +	outflags &= ~(MMAN_spc | MMAN_nl);
    +	print_word(suffix);
    +}
    +
    +static int
    +pre_ex(DECL_ARGS)
    +{
    +	outflags |= MMAN_br | MMAN_nl;
    +	return 1;
    +}
    +
    +static void
    +post_font(DECL_ARGS)
    +{
    +
    +	font_pop();
    +}
    +
    +static void
    +post_percent(DECL_ARGS)
    +{
    +
    +	if (pre_em == manacts[n->tok].pre)
    +		font_pop();
    +	if (n->next) {
    +		print_word(",");
    +		if (n->prev &&	n->prev->tok == n->tok &&
    +				n->next->tok == n->tok)
    +			print_word("and");
    +	} else {
    +		print_word(".");
    +		outflags |= MMAN_nl;
    +	}
    +}
    +
    +static int
    +pre__t(DECL_ARGS)
    +{
    +
    +	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) {
    +		print_word("\\(lq");
    +		outflags &= ~MMAN_spc;
    +	} else
    +		font_push('I');
    +	return 1;
    +}
    +
    +static void
    +post__t(DECL_ARGS)
    +{
    +
    +	if (n->parent->tok  == MDOC_Rs && n->parent->norm->Rs.quote_T) {
    +		outflags &= ~MMAN_spc;
    +		print_word("\\(rq");
    +	} else
    +		font_pop();
    +	post_percent(meta, n);
    +}
    +
    +/*
    + * Print before a section header.
    + */
    +static int
    +pre_sect(DECL_ARGS)
    +{
    +
    +	if (n->type == ROFFT_HEAD) {
    +		outflags |= MMAN_sp;
    +		print_block(manacts[n->tok].prefix, 0);
    +		print_word("");
    +		putchar('\"');
    +		outflags &= ~MMAN_spc;
    +	}
    +	return 1;
    +}
    +
    +/*
    + * Print subsequent a section header.
    + */
    +static void
    +post_sect(DECL_ARGS)
    +{
    +
    +	if (n->type != ROFFT_HEAD)
    +		return;
    +	outflags &= ~MMAN_spc;
    +	print_word("");
    +	putchar('\"');
    +	outflags |= MMAN_nl;
    +	if (MDOC_Sh == n->tok && SEC_AUTHORS == n->sec)
    +		outflags &= ~(MMAN_An_split | MMAN_An_nosplit);
    +}
    +
    +/* See mdoc_term.c, synopsis_pre() for comments. */
    +static void
    +pre_syn(const struct roff_node *n)
    +{
    +
    +	if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
    +		return;
    +
    +	if (n->prev->tok == n->tok &&
    +	    MDOC_Ft != n->tok &&
    +	    MDOC_Fo != n->tok &&
    +	    MDOC_Fn != n->tok) {
    +		outflags |= MMAN_br;
    +		return;
    +	}
    +
    +	switch (n->prev->tok) {
    +	case MDOC_Fd:
    +	case MDOC_Fn:
    +	case MDOC_Fo:
    +	case MDOC_In:
    +	case MDOC_Vt:
    +		outflags |= MMAN_sp;
    +		break;
    +	case MDOC_Ft:
    +		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
    +			outflags |= MMAN_sp;
    +			break;
    +		}
    +		/* FALLTHROUGH */
    +	default:
    +		outflags |= MMAN_br;
    +		break;
    +	}
    +}
    +
    +static int
    +pre_an(DECL_ARGS)
    +{
    +
    +	switch (n->norm->An.auth) {
    +	case AUTH_split:
    +		outflags &= ~MMAN_An_nosplit;
    +		outflags |= MMAN_An_split;
    +		return 0;
    +	case AUTH_nosplit:
    +		outflags &= ~MMAN_An_split;
    +		outflags |= MMAN_An_nosplit;
    +		return 0;
    +	default:
    +		if (MMAN_An_split & outflags)
    +			outflags |= MMAN_br;
    +		else if (SEC_AUTHORS == n->sec &&
    +		    ! (MMAN_An_nosplit & outflags))
    +			outflags |= MMAN_An_split;
    +		return 1;
    +	}
    +}
    +
    +static int
    +pre_ap(DECL_ARGS)
    +{
    +
    +	outflags &= ~MMAN_spc;
    +	print_word("'");
    +	outflags &= ~MMAN_spc;
    +	return 0;
    +}
    +
    +static int
    +pre_aq(DECL_ARGS)
    +{
    +
    +	print_word(n->child != NULL && n->child->next == NULL &&
    +	    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
    +	outflags &= ~MMAN_spc;
    +	return 1;
    +}
    +
    +static void
    +post_aq(DECL_ARGS)
    +{
    +
    +	outflags &= ~(MMAN_spc | MMAN_nl);
    +	print_word(n->child != NULL && n->child->next == NULL &&
    +	    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
    +}
    +
    +static int
    +pre_bd(DECL_ARGS)
    +{
    +
    +	outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br);
    +
    +	if (DISP_unfilled == n->norm->Bd.type ||
    +	    DISP_literal  == n->norm->Bd.type)
    +		print_line(".nf", 0);
    +	if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
    +		outflags |= MMAN_sp;
    +	print_offs(n->norm->Bd.offs, 1);
    +	return 1;
    +}
    +
    +static void
    +post_bd(DECL_ARGS)
    +{
    +
    +	/* Close out this display. */
    +	print_line(".RE", MMAN_nl);
    +	if (DISP_unfilled == n->norm->Bd.type ||
    +	    DISP_literal  == n->norm->Bd.type)
    +		print_line(".fi", MMAN_nl);
    +
    +	/* Maybe we are inside an enclosing list? */
    +	if (NULL != n->parent->next)
    +		mid_it();
    +}
    +
    +static int
    +pre_bf(DECL_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		return 1;
    +	case ROFFT_BODY:
    +		break;
    +	default:
    +		return 0;
    +	}
    +	switch (n->norm->Bf.font) {
    +	case FONT_Em:
    +		font_push('I');
    +		break;
    +	case FONT_Sy:
    +		font_push('B');
    +		break;
    +	default:
    +		font_push('R');
    +		break;
    +	}
    +	return 1;
    +}
    +
    +static void
    +post_bf(DECL_ARGS)
    +{
    +
    +	if (n->type == ROFFT_BODY)
    +		font_pop();
    +}
    +
    +static int
    +pre_bk(DECL_ARGS)
    +{
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		return 1;
    +	case ROFFT_BODY:
    +	case ROFFT_ELEM:
    +		outflags |= MMAN_Bk;
    +		return 1;
    +	default:
    +		return 0;
    +	}
    +}
    +
    +static void
    +post_bk(DECL_ARGS)
    +{
    +	switch (n->type) {
    +	case ROFFT_ELEM:
    +		while ((n = n->parent) != NULL)
    +			 if (n->tok == MDOC_Bk)
    +				return;
    +		/* FALLTHROUGH */
    +	case ROFFT_BODY:
    +		outflags &= ~MMAN_Bk;
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static int
    +pre_bl(DECL_ARGS)
    +{
    +	size_t		 icol;
    +
    +	/*
    +	 * print_offs() will increase the -offset to account for
    +	 * a possible enclosing .It, but any enclosed .It blocks
    +	 * just nest and do not add up their indentation.
    +	 */
    +	if (n->norm->Bl.offs) {
    +		print_offs(n->norm->Bl.offs, 0);
    +		Bl_stack[Bl_stack_len++] = 0;
    +	}
    +
    +	switch (n->norm->Bl.type) {
    +	case LIST_enum:
    +		n->norm->Bl.count = 0;
    +		return 1;
    +	case LIST_column:
    +		break;
    +	default:
    +		return 1;
    +	}
    +
    +	if (n->child != NULL) {
    +		print_line(".TS", MMAN_nl);
    +		for (icol = 0; icol < n->norm->Bl.ncols; icol++)
    +			print_word("l");
    +		print_word(".");
    +	}
    +	outflags |= MMAN_nl;
    +	return 1;
    +}
    +
    +static void
    +post_bl(DECL_ARGS)
    +{
    +
    +	switch (n->norm->Bl.type) {
    +	case LIST_column:
    +		if (n->child != NULL)
    +			print_line(".TE", 0);
    +		break;
    +	case LIST_enum:
    +		n->norm->Bl.count = 0;
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	if (n->norm->Bl.offs) {
    +		print_line(".RE", MMAN_nl);
    +		assert(Bl_stack_len);
    +		Bl_stack_len--;
    +		assert(0 == Bl_stack[Bl_stack_len]);
    +	} else {
    +		outflags |= MMAN_PP | MMAN_nl;
    +		outflags &= ~(MMAN_sp | MMAN_br);
    +	}
    +
    +	/* Maybe we are inside an enclosing list? */
    +	if (NULL != n->parent->next)
    +		mid_it();
    +
    +}
    +
    +static void
    +pre_br(DECL_ARGS)
    +{
    +	outflags |= MMAN_br;
    +}
    +
    +static int
    +pre_dl(DECL_ARGS)
    +{
    +
    +	print_offs("6n", 0);
    +	return 1;
    +}
    +
    +static void
    +post_dl(DECL_ARGS)
    +{
    +
    +	print_line(".RE", MMAN_nl);
    +
    +	/* Maybe we are inside an enclosing list? */
    +	if (NULL != n->parent->next)
    +		mid_it();
    +}
    +
    +static int
    +pre_em(DECL_ARGS)
    +{
    +
    +	font_push('I');
    +	return 1;
    +}
    +
    +static int
    +pre_en(DECL_ARGS)
    +{
    +
    +	if (NULL == n->norm->Es ||
    +	    NULL == n->norm->Es->child)
    +		return 1;
    +
    +	print_word(n->norm->Es->child->string);
    +	outflags &= ~MMAN_spc;
    +	return 1;
    +}
    +
    +static void
    +post_en(DECL_ARGS)
    +{
    +
    +	if (NULL == n->norm->Es ||
    +	    NULL == n->norm->Es->child ||
    +	    NULL == n->norm->Es->child->next)
    +		return;
    +
    +	outflags &= ~MMAN_spc;
    +	print_word(n->norm->Es->child->next->string);
    +	return;
    +}
    +
    +static int
    +pre_eo(DECL_ARGS)
    +{
    +
    +	if (n->end == ENDBODY_NOT &&
    +	    n->parent->head->child == NULL &&
    +	    n->child != NULL &&
    +	    n->child->end != ENDBODY_NOT)
    +		print_word("\\&");
    +	else if (n->end != ENDBODY_NOT ? n->child != NULL :
    +	    n->parent->head->child != NULL && (n->child != NULL ||
    +	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
    +		outflags &= ~(MMAN_spc | MMAN_nl);
    +	return 1;
    +}
    +
    +static void
    +post_eo(DECL_ARGS)
    +{
    +	int	 body, tail;
    +
    +	if (n->end != ENDBODY_NOT) {
    +		outflags |= MMAN_spc;
    +		return;
    +	}
    +
    +	body = n->child != NULL || n->parent->head->child != NULL;
    +	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
    +
    +	if (body && tail)
    +		outflags &= ~MMAN_spc;
    +	else if ( ! (body || tail))
    +		print_word("\\&");
    +	else if ( ! tail)
    +		outflags |= MMAN_spc;
    +}
    +
    +static int
    +pre_fa(DECL_ARGS)
    +{
    +	int	 am_Fa;
    +
    +	am_Fa = MDOC_Fa == n->tok;
    +
    +	if (am_Fa)
    +		n = n->child;
    +
    +	while (NULL != n) {
    +		font_push('I');
    +		if (am_Fa || NODE_SYNPRETTY & n->flags)
    +			outflags |= MMAN_nbrword;
    +		print_node(meta, n);
    +		font_pop();
    +		if (NULL != (n = n->next))
    +			print_word(",");
    +	}
    +	return 0;
    +}
    +
    +static void
    +post_fa(DECL_ARGS)
    +{
    +
    +	if (NULL != n->next && MDOC_Fa == n->next->tok)
    +		print_word(",");
    +}
    +
    +static int
    +pre_fd(DECL_ARGS)
    +{
    +
    +	pre_syn(n);
    +	font_push('B');
    +	return 1;
    +}
    +
    +static void
    +post_fd(DECL_ARGS)
    +{
    +
    +	font_pop();
    +	outflags |= MMAN_br;
    +}
    +
    +static int
    +pre_fl(DECL_ARGS)
    +{
    +
    +	font_push('B');
    +	print_word("\\-");
    +	if (n->child != NULL)
    +		outflags &= ~MMAN_spc;
    +	return 1;
    +}
    +
    +static void
    +post_fl(DECL_ARGS)
    +{
    +
    +	font_pop();
    +	if (!(n->child != NULL ||
    +	    n->next == NULL ||
    +	    n->next->type == ROFFT_TEXT ||
    +	    n->next->flags & NODE_LINE))
    +		outflags &= ~MMAN_spc;
    +}
    +
    +static int
    +pre_fn(DECL_ARGS)
    +{
    +
    +	pre_syn(n);
    +
    +	n = n->child;
    +	if (NULL == n)
    +		return 0;
    +
    +	if (NODE_SYNPRETTY & n->flags)
    +		print_block(".HP 4n", MMAN_nl);
    +
    +	font_push('B');
    +	print_node(meta, n);
    +	font_pop();
    +	outflags &= ~MMAN_spc;
    +	print_word("(");
    +	outflags &= ~MMAN_spc;
    +
    +	n = n->next;
    +	if (NULL != n)
    +		pre_fa(meta, n);
    +	return 0;
    +}
    +
    +static void
    +post_fn(DECL_ARGS)
    +{
    +
    +	print_word(")");
    +	if (NODE_SYNPRETTY & n->flags) {
    +		print_word(";");
    +		outflags |= MMAN_PP;
    +	}
    +}
    +
    +static int
    +pre_fo(DECL_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		pre_syn(n);
    +		break;
    +	case ROFFT_HEAD:
    +		if (n->child == NULL)
    +			return 0;
    +		if (NODE_SYNPRETTY & n->flags)
    +			print_block(".HP 4n", MMAN_nl);
    +		font_push('B');
    +		break;
    +	case ROFFT_BODY:
    +		outflags &= ~(MMAN_spc | MMAN_nl);
    +		print_word("(");
    +		outflags &= ~MMAN_spc;
    +		break;
    +	default:
    +		break;
    +	}
    +	return 1;
    +}
    +
    +static void
    +post_fo(DECL_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		if (n->child != NULL)
    +			font_pop();
    +		break;
    +	case ROFFT_BODY:
    +		post_fn(meta, n);
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static int
    +pre_Ft(DECL_ARGS)
    +{
    +
    +	pre_syn(n);
    +	font_push('I');
    +	return 1;
    +}
    +
    +static void
    +pre_ft(DECL_ARGS)
    +{
    +	print_line(".ft", 0);
    +	print_word(n->child->string);
    +	outflags |= MMAN_nl;
    +}
    +
    +static int
    +pre_in(DECL_ARGS)
    +{
    +
    +	if (NODE_SYNPRETTY & n->flags) {
    +		pre_syn(n);
    +		font_push('B');
    +		print_word("#include <");
    +		outflags &= ~MMAN_spc;
    +	} else {
    +		print_word("<");
    +		outflags &= ~MMAN_spc;
    +		font_push('I');
    +	}
    +	return 1;
    +}
    +
    +static void
    +post_in(DECL_ARGS)
    +{
    +
    +	if (NODE_SYNPRETTY & n->flags) {
    +		outflags &= ~MMAN_spc;
    +		print_word(">");
    +		font_pop();
    +		outflags |= MMAN_br;
    +	} else {
    +		font_pop();
    +		outflags &= ~MMAN_spc;
    +		print_word(">");
    +	}
    +}
    +
    +static int
    +pre_it(DECL_ARGS)
    +{
    +	const struct roff_node *bln;
    +
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		outflags |= MMAN_PP | MMAN_nl;
    +		bln = n->parent->parent;
    +		if (0 == bln->norm->Bl.comp ||
    +		    (NULL == n->parent->prev &&
    +		     NULL == bln->parent->prev))
    +			outflags |= MMAN_sp;
    +		outflags &= ~MMAN_br;
    +		switch (bln->norm->Bl.type) {
    +		case LIST_item:
    +			return 0;
    +		case LIST_inset:
    +		case LIST_diag:
    +		case LIST_ohang:
    +			if (bln->norm->Bl.type == LIST_diag)
    +				print_line(".B \"", 0);
    +			else
    +				print_line(".BR \\& \"", 0);
    +			outflags &= ~MMAN_spc;
    +			return 1;
    +		case LIST_bullet:
    +		case LIST_dash:
    +		case LIST_hyphen:
    +			print_width(&bln->norm->Bl, NULL);
    +			TPremain = 0;
    +			outflags |= MMAN_nl;
    +			font_push('B');
    +			if (LIST_bullet == bln->norm->Bl.type)
    +				print_word("\\(bu");
    +			else
    +				print_word("-");
    +			font_pop();
    +			outflags |= MMAN_nl;
    +			return 0;
    +		case LIST_enum:
    +			print_width(&bln->norm->Bl, NULL);
    +			TPremain = 0;
    +			outflags |= MMAN_nl;
    +			print_count(&bln->norm->Bl.count);
    +			outflags |= MMAN_nl;
    +			return 0;
    +		case LIST_hang:
    +			print_width(&bln->norm->Bl, n->child);
    +			TPremain = 0;
    +			outflags |= MMAN_nl;
    +			return 1;
    +		case LIST_tag:
    +			print_width(&bln->norm->Bl, n->child);
    +			putchar('\n');
    +			outflags &= ~MMAN_spc;
    +			return 1;
    +		default:
    +			return 1;
    +		}
    +	default:
    +		break;
    +	}
    +	return 1;
    +}
    +
    +/*
    + * This function is called after closing out an indented block.
    + * If we are inside an enclosing list, restore its indentation.
    + */
    +static void
    +mid_it(void)
    +{
    +	char		 buf[24];
    +
    +	/* Nothing to do outside a list. */
    +	if (0 == Bl_stack_len || 0 == Bl_stack[Bl_stack_len - 1])
    +		return;
    +
    +	/* The indentation has already been set up. */
    +	if (Bl_stack_post[Bl_stack_len - 1])
    +		return;
    +
    +	/* Restore the indentation of the enclosing list. */
    +	print_line(".RS", MMAN_Bk_susp);
    +	(void)snprintf(buf, sizeof(buf), "%dn",
    +	    Bl_stack[Bl_stack_len - 1]);
    +	print_word(buf);
    +
    +	/* Remeber to close out this .RS block later. */
    +	Bl_stack_post[Bl_stack_len - 1] = 1;
    +}
    +
    +static void
    +post_it(DECL_ARGS)
    +{
    +	const struct roff_node *bln;
    +
    +	bln = n->parent->parent;
    +
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		switch (bln->norm->Bl.type) {
    +		case LIST_diag:
    +			outflags &= ~MMAN_spc;
    +			print_word("\\ ");
    +			break;
    +		case LIST_ohang:
    +			outflags |= MMAN_br;
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	case ROFFT_BODY:
    +		switch (bln->norm->Bl.type) {
    +		case LIST_bullet:
    +		case LIST_dash:
    +		case LIST_hyphen:
    +		case LIST_enum:
    +		case LIST_hang:
    +		case LIST_tag:
    +			assert(Bl_stack_len);
    +			Bl_stack[--Bl_stack_len] = 0;
    +
    +			/*
    +			 * Our indentation had to be restored
    +			 * after a child display or child list.
    +			 * Close out that indentation block now.
    +			 */
    +			if (Bl_stack_post[Bl_stack_len]) {
    +				print_line(".RE", MMAN_nl);
    +				Bl_stack_post[Bl_stack_len] = 0;
    +			}
    +			break;
    +		case LIST_column:
    +			if (NULL != n->next) {
    +				putchar('\t');
    +				outflags &= ~MMAN_spc;
    +			}
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +post_lb(DECL_ARGS)
    +{
    +
    +	if (SEC_LIBRARY == n->sec)
    +		outflags |= MMAN_br;
    +}
    +
    +static int
    +pre_lk(DECL_ARGS)
    +{
    +	const struct roff_node *link, *descr, *punct;
    +
    +	if ((link = n->child) == NULL)
    +		return 0;
    +
    +	/* Find beginning of trailing punctuation. */
    +	punct = n->last;
    +	while (punct != link && punct->flags & NODE_DELIMC)
    +		punct = punct->prev;
    +	punct = punct->next;
    +
    +	/* Link text. */
    +	if ((descr = link->next) != NULL && descr != punct) {
    +		font_push('I');
    +		while (descr != punct) {
    +			print_word(descr->string);
    +			descr = descr->next;
    +		}
    +		font_pop();
    +		print_word(":");
    +	}
    +
    +	/* Link target. */
    +	font_push('B');
    +	print_word(link->string);
    +	font_pop();
    +
    +	/* Trailing punctuation. */
    +	while (punct != NULL) {
    +		print_word(punct->string);
    +		punct = punct->next;
    +	}
    +	return 0;
    +}
    +
    +static void
    +pre_onearg(DECL_ARGS)
    +{
    +	outflags |= MMAN_nl;
    +	print_word(".");
    +	outflags &= ~MMAN_spc;
    +	print_word(roff_name[n->tok]);
    +	if (n->child != NULL)
    +		print_word(n->child->string);
    +	outflags |= MMAN_nl;
    +	if (n->tok == ROFF_ce)
    +		for (n = n->child->next; n != NULL; n = n->next)
    +			print_node(meta, n);
    +}
    +
    +static int
    +pre_li(DECL_ARGS)
    +{
    +
    +	font_push('R');
    +	return 1;
    +}
    +
    +static int
    +pre_nm(DECL_ARGS)
    +{
    +	char	*name;
    +
    +	if (n->type == ROFFT_BLOCK) {
    +		outflags |= MMAN_Bk;
    +		pre_syn(n);
    +	}
    +	if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD)
    +		return 1;
    +	name = n->child == NULL ? NULL : n->child->string;
    +	if (NULL == name)
    +		return 0;
    +	if (n->type == ROFFT_HEAD) {
    +		if (NULL == n->parent->prev)
    +			outflags |= MMAN_sp;
    +		print_block(".HP", 0);
    +		printf(" %dn", man_strlen(name) + 1);
    +		outflags |= MMAN_nl;
    +	}
    +	font_push('B');
    +	return 1;
    +}
    +
    +static void
    +post_nm(DECL_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		outflags &= ~MMAN_Bk;
    +		break;
    +	case ROFFT_HEAD:
    +	case ROFFT_ELEM:
    +		if (n->child != NULL && n->child->string != NULL)
    +			font_pop();
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static int
    +pre_no(DECL_ARGS)
    +{
    +
    +	outflags |= MMAN_spc_force;
    +	return 1;
    +}
    +
    +static int
    +pre_ns(DECL_ARGS)
    +{
    +
    +	outflags &= ~MMAN_spc;
    +	return 0;
    +}
    +
    +static void
    +post_pf(DECL_ARGS)
    +{
    +
    +	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
    +		outflags &= ~MMAN_spc;
    +}
    +
    +static int
    +pre_pp(DECL_ARGS)
    +{
    +
    +	if (MDOC_It != n->parent->tok)
    +		outflags |= MMAN_PP;
    +	outflags |= MMAN_sp | MMAN_nl;
    +	outflags &= ~MMAN_br;
    +	return 0;
    +}
    +
    +static int
    +pre_rs(DECL_ARGS)
    +{
    +
    +	if (SEC_SEE_ALSO == n->sec) {
    +		outflags |= MMAN_PP | MMAN_sp | MMAN_nl;
    +		outflags &= ~MMAN_br;
    +	}
    +	return 1;
    +}
    +
    +static int
    +pre_skip(DECL_ARGS)
    +{
    +
    +	return 0;
    +}
    +
    +static int
    +pre_sm(DECL_ARGS)
    +{
    +
    +	if (NULL == n->child)
    +		outflags ^= MMAN_Sm;
    +	else if (0 == strcmp("on", n->child->string))
    +		outflags |= MMAN_Sm;
    +	else
    +		outflags &= ~MMAN_Sm;
    +
    +	if (MMAN_Sm & outflags)
    +		outflags |= MMAN_spc;
    +
    +	return 0;
    +}
    +
    +static void
    +pre_sp(DECL_ARGS)
    +{
    +	if (outflags & MMAN_PP) {
    +		outflags &= ~MMAN_PP;
    +		print_line(".PP", 0);
    +	} else {
    +		print_line(".sp", 0);
    +		if (n->child != NULL)
    +			print_word(n->child->string);
    +	}
    +	outflags |= MMAN_nl;
    +}
    +
    +static int
    +pre_sy(DECL_ARGS)
    +{
    +
    +	font_push('B');
    +	return 1;
    +}
    +
    +static void
    +pre_ta(DECL_ARGS)
    +{
    +	print_line(".ta", 0);
    +	for (n = n->child; n != NULL; n = n->next)
    +		print_word(n->string);
    +	outflags |= MMAN_nl;
    +}
    +
    +static int
    +pre_vt(DECL_ARGS)
    +{
    +
    +	if (NODE_SYNPRETTY & n->flags) {
    +		switch (n->type) {
    +		case ROFFT_BLOCK:
    +			pre_syn(n);
    +			return 1;
    +		case ROFFT_BODY:
    +			break;
    +		default:
    +			return 0;
    +		}
    +	}
    +	font_push('I');
    +	return 1;
    +}
    +
    +static void
    +post_vt(DECL_ARGS)
    +{
    +
    +	if (n->flags & NODE_SYNPRETTY && n->type != ROFFT_BODY)
    +		return;
    +	font_pop();
    +}
    +
    +static int
    +pre_xr(DECL_ARGS)
    +{
    +
    +	n = n->child;
    +	if (NULL == n)
    +		return 0;
    +	print_node(meta, n);
    +	n = n->next;
    +	if (NULL == n)
    +		return 0;
    +	outflags &= ~MMAN_spc;
    +	print_word("(");
    +	print_node(meta, n);
    +	print_word(")");
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/mdoc_man.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc_markdown.c
    ===================================================================
    --- head/contrib/mandoc/mdoc_markdown.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc_markdown.c	(revision 338826)
    @@ -0,0 +1,1569 @@
    +/*	$Id: mdoc_markdown.c,v 1.24 2018/04/11 17:11:13 schwarze Exp $ */
    +/*
    + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdio.h>
    +#include <string.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "main.h"
    +
    +struct	md_act {
    +	int		(*cond)(struct roff_node *n);
    +	int		(*pre)(struct roff_node *n);
    +	void		(*post)(struct roff_node *n);
    +	const char	 *prefix; /* pre-node string constant */
    +	const char	 *suffix; /* post-node string constant */
    +};
    +
    +static	void	 md_nodelist(struct roff_node *);
    +static	void	 md_node(struct roff_node *);
    +static	const char *md_stack(char c);
    +static	void	 md_preword(void);
    +static	void	 md_rawword(const char *);
    +static	void	 md_word(const char *);
    +static	void	 md_named(const char *);
    +static	void	 md_char(unsigned char);
    +static	void	 md_uri(const char *);
    +
    +static	int	 md_cond_head(struct roff_node *);
    +static	int	 md_cond_body(struct roff_node *);
    +
    +static	int	 md_pre_raw(struct roff_node *);
    +static	int	 md_pre_word(struct roff_node *);
    +static	int	 md_pre_skip(struct roff_node *);
    +static	void	 md_pre_syn(struct roff_node *);
    +static	int	 md_pre_An(struct roff_node *);
    +static	int	 md_pre_Ap(struct roff_node *);
    +static	int	 md_pre_Bd(struct roff_node *);
    +static	int	 md_pre_Bk(struct roff_node *);
    +static	int	 md_pre_Bl(struct roff_node *);
    +static	int	 md_pre_D1(struct roff_node *);
    +static	int	 md_pre_Dl(struct roff_node *);
    +static	int	 md_pre_En(struct roff_node *);
    +static	int	 md_pre_Eo(struct roff_node *);
    +static	int	 md_pre_Fa(struct roff_node *);
    +static	int	 md_pre_Fd(struct roff_node *);
    +static	int	 md_pre_Fn(struct roff_node *);
    +static	int	 md_pre_Fo(struct roff_node *);
    +static	int	 md_pre_In(struct roff_node *);
    +static	int	 md_pre_It(struct roff_node *);
    +static	int	 md_pre_Lk(struct roff_node *);
    +static	int	 md_pre_Mt(struct roff_node *);
    +static	int	 md_pre_Nd(struct roff_node *);
    +static	int	 md_pre_Nm(struct roff_node *);
    +static	int	 md_pre_No(struct roff_node *);
    +static	int	 md_pre_Ns(struct roff_node *);
    +static	int	 md_pre_Pp(struct roff_node *);
    +static	int	 md_pre_Rs(struct roff_node *);
    +static	int	 md_pre_Sh(struct roff_node *);
    +static	int	 md_pre_Sm(struct roff_node *);
    +static	int	 md_pre_Vt(struct roff_node *);
    +static	int	 md_pre_Xr(struct roff_node *);
    +static	int	 md_pre__T(struct roff_node *);
    +static	int	 md_pre_br(struct roff_node *);
    +
    +static	void	 md_post_raw(struct roff_node *);
    +static	void	 md_post_word(struct roff_node *);
    +static	void	 md_post_pc(struct roff_node *);
    +static	void	 md_post_Bk(struct roff_node *);
    +static	void	 md_post_Bl(struct roff_node *);
    +static	void	 md_post_D1(struct roff_node *);
    +static	void	 md_post_En(struct roff_node *);
    +static	void	 md_post_Eo(struct roff_node *);
    +static	void	 md_post_Fa(struct roff_node *);
    +static	void	 md_post_Fd(struct roff_node *);
    +static	void	 md_post_Fl(struct roff_node *);
    +static	void	 md_post_Fn(struct roff_node *);
    +static	void	 md_post_Fo(struct roff_node *);
    +static	void	 md_post_In(struct roff_node *);
    +static	void	 md_post_It(struct roff_node *);
    +static	void	 md_post_Lb(struct roff_node *);
    +static	void	 md_post_Nm(struct roff_node *);
    +static	void	 md_post_Pf(struct roff_node *);
    +static	void	 md_post_Vt(struct roff_node *);
    +static	void	 md_post__T(struct roff_node *);
    +
    +static	const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
    +	{ NULL, md_pre_Sh, NULL, NULL, NULL }, /* Sh */
    +	{ NULL, md_pre_Sh, NULL, NULL, NULL }, /* Ss */
    +	{ NULL, md_pre_Pp, NULL, NULL, NULL }, /* Pp */
    +	{ md_cond_body, md_pre_D1, md_post_D1, NULL, NULL }, /* D1 */
    +	{ md_cond_body, md_pre_Dl, md_post_D1, NULL, NULL }, /* Dl */
    +	{ md_cond_body, md_pre_Bd, md_post_D1, NULL, NULL }, /* Bd */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
    +	{ md_cond_body, md_pre_Bl, md_post_Bl, NULL, NULL }, /* Bl */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* El */
    +	{ NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */
    +	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */
    +	{ NULL, md_pre_An, NULL, NULL, NULL }, /* An */
    +	{ NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */
    +	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ar */
    +	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */
    +	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */
    +	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Dv */
    +	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Er */
    +	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Ev */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ex */
    +	{ NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */
    +	{ NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */
    +	{ NULL, md_pre_raw, md_post_Fl, "**-", "**" }, /* Fl */
    +	{ NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */
    +	{ NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */
    +	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */
    +	{ NULL, md_pre_In, md_post_In, NULL, NULL }, /* In */
    +	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */
    +	{ md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
    +	{ NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
    +	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */
    +	{ NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ot */
    +	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Rv */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* St */
    +	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Va */
    +	{ NULL, md_pre_Vt, md_post_Vt, "*", "*" }, /* Vt */
    +	{ NULL, md_pre_Xr, NULL, NULL, NULL }, /* Xr */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %A */
    +	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %B */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %D */
    +	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %I */
    +	{ NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %J */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %N */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %O */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %P */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %R */
    +	{ NULL, md_pre__T, md_post__T, NULL, NULL }, /* %T */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %V */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
    +	{ md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Ao */
    +	{ md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Aq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* At */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Bf XXX not implemented */
    +	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bo */
    +	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Bsx */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Bx */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Db */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
    +	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Do */
    +	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Dq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
    +	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Em */
    +	{ md_cond_body, md_pre_Eo, md_post_Eo, NULL, NULL }, /* Eo */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Fx */
    +	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ms */
    +	{ NULL, md_pre_No, NULL, NULL, NULL }, /* No */
    +	{ NULL, md_pre_Ns, NULL, NULL, NULL }, /* Ns */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Nx */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ox */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
    +	{ NULL, NULL, md_post_Pf, NULL, NULL }, /* Pf */
    +	{ md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Po */
    +	{ md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Pq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
    +	{ md_cond_body, md_pre_raw, md_post_raw, "'`", "`'" }, /* Ql */
    +	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qo */
    +	{ md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qq */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
    +	{ md_cond_body, md_pre_Rs, NULL, NULL, NULL }, /* Rs */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
    +	{ md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* So */
    +	{ md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* Sq */
    +	{ NULL, md_pre_Sm, NULL, NULL, NULL }, /* Sm */
    +	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Sx */
    +	{ NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Sy */
    +	{ NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Tn */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ux */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Xc */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Xo */
    +	{ NULL, md_pre_Fo, md_post_Fo, "**", "**" }, /* Fo */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Fc */
    +	{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Oo */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
    +	{ NULL, md_pre_Bk, md_post_Bk, NULL, NULL }, /* Bk */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Bt */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
    +	{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
    +	{ NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */
    +	{ NULL, md_pre_Pp, NULL, NULL, NULL }, /* Lp */
    +	{ NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */
    +	{ NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */
    +	{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */
    +	{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %C */
    +	{ NULL, md_pre_skip, NULL, NULL, NULL }, /* Es */
    +	{ md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Dx */
    +	{ NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */
    +	{ NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
    +	{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
    +};
    +static	const struct md_act *const md_acts = __md_acts - MDOC_Dd;
    +
    +static	int	 outflags;
    +#define	MD_spc		 (1 << 0)  /* Blank character before next word. */
    +#define	MD_spc_force	 (1 << 1)  /* Even before trailing punctuation. */
    +#define	MD_nonl		 (1 << 2)  /* Prevent linebreak in markdown code. */
    +#define	MD_nl		 (1 << 3)  /* Break markdown code line. */
    +#define	MD_br		 (1 << 4)  /* Insert an output line break. */
    +#define	MD_sp		 (1 << 5)  /* Insert a paragraph break. */
    +#define	MD_Sm		 (1 << 6)  /* Horizontal spacing mode. */
    +#define	MD_Bk		 (1 << 7)  /* Word keep mode. */
    +#define	MD_An_split	 (1 << 8)  /* Author mode is "split". */
    +#define	MD_An_nosplit	 (1 << 9)  /* Author mode is "nosplit". */
    +
    +static	int	 escflags; /* Escape in generated markdown code: */
    +#define	ESC_BOL	 (1 << 0)  /* "#*+-" near the beginning of a line. */
    +#define	ESC_NUM	 (1 << 1)  /* "." after a leading number. */
    +#define	ESC_HYP	 (1 << 2)  /* "(" immediately after "]". */
    +#define	ESC_SQU	 (1 << 4)  /* "]" when "[" is open. */
    +#define	ESC_FON	 (1 << 5)  /* "*" immediately after unrelated "*". */
    +#define	ESC_EOL	 (1 << 6)  /* " " at the and of a line. */
    +
    +static	int	 code_blocks, quote_blocks, list_blocks;
    +static	int	 outcount;
    +
    +void
    +markdown_mdoc(void *arg, const struct roff_man *mdoc)
    +{
    +	outflags = MD_Sm;
    +	md_word(mdoc->meta.title);
    +	if (mdoc->meta.msec != NULL) {
    +		outflags &= ~MD_spc;
    +		md_word("(");
    +		md_word(mdoc->meta.msec);
    +		md_word(")");
    +	}
    +	md_word("-");
    +	md_word(mdoc->meta.vol);
    +	if (mdoc->meta.arch != NULL) {
    +		md_word("(");
    +		md_word(mdoc->meta.arch);
    +		md_word(")");
    +	}
    +	outflags |= MD_sp;
    +
    +	md_nodelist(mdoc->first->child);
    +
    +	outflags |= MD_sp;
    +	md_word(mdoc->meta.os);
    +	md_word("-");
    +	md_word(mdoc->meta.date);
    +	putchar('\n');
    +}
    +
    +static void
    +md_nodelist(struct roff_node *n)
    +{
    +	while (n != NULL) {
    +		md_node(n);
    +		n = n->next;
    +	}
    +}
    +
    +static void
    +md_node(struct roff_node *n)
    +{
    +	const struct md_act	*act;
    +	int			 cond, process_children;
    +
    +	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
    +		return;
    +
    +	if (outflags & MD_nonl)
    +		outflags &= ~(MD_nl | MD_sp);
    +	else if (outflags & MD_spc && n->flags & NODE_LINE)
    +		outflags |= MD_nl;
    +
    +	act = NULL;
    +	cond = 0;
    +	process_children = 1;
    +	n->flags &= ~NODE_ENDED;
    +
    +	if (n->type == ROFFT_TEXT) {
    +		if (n->flags & NODE_DELIMC)
    +			outflags &= ~(MD_spc | MD_spc_force);
    +		else if (outflags & MD_Sm)
    +			outflags |= MD_spc_force;
    +		md_word(n->string);
    +		if (n->flags & NODE_DELIMO)
    +			outflags &= ~(MD_spc | MD_spc_force);
    +		else if (outflags & MD_Sm)
    +			outflags |= MD_spc;
    +	} else if (n->tok < ROFF_MAX) {
    +		switch (n->tok) {
    +		case ROFF_br:
    +			process_children = md_pre_br(n);
    +			break;
    +		case ROFF_sp:
    +			process_children = md_pre_Pp(n);
    +			break;
    +		default:
    +			process_children = 0;
    +			break;
    +		}
    +	} else {
    +		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
    +		act = md_acts + n->tok;
    +		cond = act->cond == NULL || (*act->cond)(n);
    +		if (cond && act->pre != NULL &&
    +		    (n->end == ENDBODY_NOT || n->child != NULL))
    +			process_children = (*act->pre)(n);
    +	}
    +
    +	if (process_children && n->child != NULL)
    +		md_nodelist(n->child);
    +
    +	if (n->flags & NODE_ENDED)
    +		return;
    +
    +	if (cond && act->post != NULL)
    +		(*act->post)(n);
    +
    +	if (n->end != ENDBODY_NOT)
    +		n->body->flags |= NODE_ENDED;
    +}
    +
    +static const char *
    +md_stack(char c)
    +{
    +	static char	*stack;
    +	static size_t	 sz;
    +	static size_t	 cur;
    +
    +	switch (c) {
    +	case '\0':
    +		break;
    +	case (char)-1:
    +		assert(cur);
    +		stack[--cur] = '\0';
    +		break;
    +	default:
    +		if (cur + 1 >= sz) {
    +			sz += 8;
    +			stack = mandoc_realloc(stack, sz);
    +		}
    +		stack[cur] = c;
    +		stack[++cur] = '\0';
    +		break;
    +	}
    +	return stack == NULL ? "" : stack;
    +}
    +
    +/*
    + * Handle vertical and horizontal spacing.
    + */
    +static void
    +md_preword(void)
    +{
    +	const char	*cp;
    +
    +	/*
    +	 * If a list block is nested inside a code block or a blockquote,
    +	 * blank lines for paragraph breaks no longer work; instead,
    +	 * they terminate the list.  Work around this markdown issue
    +	 * by using mere line breaks instead.
    +	 */
    +
    +	if (list_blocks && outflags & MD_sp) {
    +		outflags &= ~MD_sp;
    +		outflags |= MD_br;
    +	}
    +
    +	/*
    +	 * End the old line if requested.
    +	 * Escape whitespace at the end of the markdown line
    +	 * such that it won't look like an output line break.
    +	 */
    +
    +	if (outflags & MD_sp)
    +		putchar('\n');
    +	else if (outflags & MD_br) {
    +		putchar(' ');
    +		putchar(' ');
    +	} else if (outflags & MD_nl && escflags & ESC_EOL)
    +		md_named("zwnj");
    +
    +	/* Start a new line if necessary. */
    +
    +	if (outflags & (MD_nl | MD_br | MD_sp)) {
    +		putchar('\n');
    +		for (cp = md_stack('\0'); *cp != '\0'; cp++) {
    +			putchar(*cp);
    +			if (*cp == '>')
    +				putchar(' ');
    +		}
    +		outflags &= ~(MD_nl | MD_br | MD_sp);
    +		escflags = ESC_BOL;
    +		outcount = 0;
    +
    +	/* Handle horizontal spacing. */
    +
    +	} else if (outflags & MD_spc) {
    +		if (outflags & MD_Bk)
    +			fputs(" ", stdout);
    +		else
    +			putchar(' ');
    +		escflags &= ~ESC_FON;
    +		outcount++;
    +	}
    +
    +	outflags &= ~(MD_spc_force | MD_nonl);
    +	if (outflags & MD_Sm)
    +		outflags |= MD_spc;
    +	else
    +		outflags &= ~MD_spc;
    +}
    +
    +/*
    + * Print markdown syntax elements.
    + * Can also be used for constant strings when neither escaping
    + * nor delimiter handling is required.
    + */
    +static void
    +md_rawword(const char *s)
    +{
    +	md_preword();
    +
    +	if (*s == '\0')
    +		return;
    +
    +	if (escflags & ESC_FON) {
    +		escflags &= ~ESC_FON;
    +		if (*s == '*' && !code_blocks)
    +			fputs("‌", stdout);
    +	}
    +
    +	while (*s != '\0') {
    +		switch(*s) {
    +		case '*':
    +			if (s[1] == '\0')
    +				escflags |= ESC_FON;
    +			break;
    +		case '[':
    +			escflags |= ESC_SQU;
    +			break;
    +		case ']':
    +			escflags |= ESC_HYP;
    +			escflags &= ~ESC_SQU;
    +			break;
    +		default:
    +			break;
    +		}
    +		md_char(*s++);
    +	}
    +	if (s[-1] == ' ')
    +		escflags |= ESC_EOL;
    +	else
    +		escflags &= ~ESC_EOL;
    +}
    +
    +/*
    + * Print text and mdoc(7) syntax elements.
    + */
    +static void
    +md_word(const char *s)
    +{
    +	const char	*seq, *prevfont, *currfont, *nextfont;
    +	char		 c;
    +	int		 bs, sz, uc, breakline;
    +
    +	/* No spacing before closing delimiters. */
    +	if (s[0] != '\0' && s[1] == '\0' &&
    +	    strchr("!),.:;?]", s[0]) != NULL &&
    +	    (outflags & MD_spc_force) == 0)
    +		outflags &= ~MD_spc;
    +
    +	md_preword();
    +
    +	if (*s == '\0')
    +		return;
    +
    +	/* No spacing after opening delimiters. */
    +	if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
    +		outflags &= ~MD_spc;
    +
    +	breakline = 0;
    +	prevfont = currfont = "";
    +	while ((c = *s++) != '\0') {
    +		bs = 0;
    +		switch(c) {
    +		case ASCII_NBRSP:
    +			if (code_blocks)
    +				c = ' ';
    +			else {
    +				md_named("nbsp");
    +				c = '\0';
    +			}
    +			break;
    +		case ASCII_HYPH:
    +			bs = escflags & ESC_BOL && !code_blocks;
    +			c = '-';
    +			break;
    +		case ASCII_BREAK:
    +			continue;
    +		case '#':
    +		case '+':
    +		case '-':
    +			bs = escflags & ESC_BOL && !code_blocks;
    +			break;
    +		case '(':
    +			bs = escflags & ESC_HYP && !code_blocks;
    +			break;
    +		case ')':
    +			bs = escflags & ESC_NUM && !code_blocks;
    +			break;
    +		case '*':
    +		case '[':
    +		case '_':
    +		case '`':
    +			bs = !code_blocks;
    +			break;
    +		case '.':
    +			bs = escflags & ESC_NUM && !code_blocks;
    +			break;
    +		case '<':
    +			if (code_blocks == 0) {
    +				md_named("lt");
    +				c = '\0';
    +			}
    +			break;
    +		case '=':
    +			if (escflags & ESC_BOL && !code_blocks) {
    +				md_named("equals");
    +				c = '\0';
    +			}
    +			break;
    +		case '>':
    +			if (code_blocks == 0) {
    +				md_named("gt");
    +				c = '\0';
    +			}
    +			break;
    +		case '\\':
    +			uc = 0;
    +			nextfont = NULL;
    +			switch (mandoc_escape(&s, &seq, &sz)) {
    +			case ESCAPE_UNICODE:
    +				uc = mchars_num2uc(seq + 1, sz - 1);
    +				break;
    +			case ESCAPE_NUMBERED:
    +				uc = mchars_num2char(seq, sz);
    +				break;
    +			case ESCAPE_SPECIAL:
    +				uc = mchars_spec2cp(seq, sz);
    +				break;
    +			case ESCAPE_FONTBOLD:
    +				nextfont = "**";
    +				break;
    +			case ESCAPE_FONTITALIC:
    +				nextfont = "*";
    +				break;
    +			case ESCAPE_FONTBI:
    +				nextfont = "***";
    +				break;
    +			case ESCAPE_FONT:
    +			case ESCAPE_FONTROMAN:
    +				nextfont = "";
    +				break;
    +			case ESCAPE_FONTPREV:
    +				nextfont = prevfont;
    +				break;
    +			case ESCAPE_BREAK:
    +				breakline = 1;
    +				break;
    +			case ESCAPE_NOSPACE:
    +			case ESCAPE_SKIPCHAR:
    +			case ESCAPE_OVERSTRIKE:
    +				/* XXX not implemented */
    +				/* FALLTHROUGH */
    +			case ESCAPE_ERROR:
    +			default:
    +				break;
    +			}
    +			if (nextfont != NULL && !code_blocks) {
    +				if (*currfont != '\0') {
    +					outflags &= ~MD_spc;
    +					md_rawword(currfont);
    +				}
    +				prevfont = currfont;
    +				currfont = nextfont;
    +				if (*currfont != '\0') {
    +					outflags &= ~MD_spc;
    +					md_rawword(currfont);
    +				}
    +			}
    +			if (uc) {
    +				if ((uc < 0x20 && uc != 0x09) ||
    +				    (uc > 0x7E && uc < 0xA0))
    +					uc = 0xFFFD;
    +				if (code_blocks) {
    +					seq = mchars_uc2str(uc);
    +					fputs(seq, stdout);
    +					outcount += strlen(seq);
    +				} else {
    +					printf("&#%d;", uc);
    +					outcount++;
    +				}
    +				escflags &= ~ESC_FON;
    +			}
    +			c = '\0';
    +			break;
    +		case ']':
    +			bs = escflags & ESC_SQU && !code_blocks;
    +			escflags |= ESC_HYP;
    +			break;
    +		default:
    +			break;
    +		}
    +		if (bs)
    +			putchar('\\');
    +		md_char(c);
    +		if (breakline &&
    +		    (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) {
    +			printf("  \n");
    +			breakline = 0;
    +			while (*s == ' ' || *s == ASCII_NBRSP)
    +				s++;
    +		}
    +	}
    +	if (*currfont != '\0') {
    +		outflags &= ~MD_spc;
    +		md_rawword(currfont);
    +	} else if (s[-2] == ' ')
    +		escflags |= ESC_EOL;
    +	else
    +		escflags &= ~ESC_EOL;
    +}
    +
    +/*
    + * Print a single HTML named character reference.
    + */
    +static void
    +md_named(const char *s)
    +{
    +	printf("&%s;", s);
    +	escflags &= ~(ESC_FON | ESC_EOL);
    +	outcount++;
    +}
    +
    +/*
    + * Print a single raw character and maintain certain escape flags.
    + */
    +static void
    +md_char(unsigned char c)
    +{
    +	if (c != '\0') {
    +		putchar(c);
    +		if (c == '*')
    +			escflags |= ESC_FON;
    +		else
    +			escflags &= ~ESC_FON;
    +		outcount++;
    +	}
    +	if (c != ']')
    +		escflags &= ~ESC_HYP;
    +	if (c == ' ' || c == '\t' || c == '>')
    +		return;
    +	if (isdigit(c) == 0)
    +		escflags &= ~ESC_NUM;
    +	else if (escflags & ESC_BOL)
    +		escflags |= ESC_NUM;
    +	escflags &= ~ESC_BOL;
    +}
    +
    +static int
    +md_cond_head(struct roff_node *n)
    +{
    +	return n->type == ROFFT_HEAD;
    +}
    +
    +static int
    +md_cond_body(struct roff_node *n)
    +{
    +	return n->type == ROFFT_BODY;
    +}
    +
    +static int
    +md_pre_raw(struct roff_node *n)
    +{
    +	const char	*prefix;
    +
    +	if ((prefix = md_acts[n->tok].prefix) != NULL) {
    +		md_rawword(prefix);
    +		outflags &= ~MD_spc;
    +		if (*prefix == '`')
    +			code_blocks++;
    +	}
    +	return 1;
    +}
    +
    +static void
    +md_post_raw(struct roff_node *n)
    +{
    +	const char	*suffix;
    +
    +	if ((suffix = md_acts[n->tok].suffix) != NULL) {
    +		outflags &= ~(MD_spc | MD_nl);
    +		md_rawword(suffix);
    +		if (*suffix == '`')
    +			code_blocks--;
    +	}
    +}
    +
    +static int
    +md_pre_word(struct roff_node *n)
    +{
    +	const char	*prefix;
    +
    +	if ((prefix = md_acts[n->tok].prefix) != NULL) {
    +		md_word(prefix);
    +		outflags &= ~MD_spc;
    +	}
    +	return 1;
    +}
    +
    +static void
    +md_post_word(struct roff_node *n)
    +{
    +	const char	*suffix;
    +
    +	if ((suffix = md_acts[n->tok].suffix) != NULL) {
    +		outflags &= ~(MD_spc | MD_nl);
    +		md_word(suffix);
    +	}
    +}
    +
    +static void
    +md_post_pc(struct roff_node *n)
    +{
    +	md_post_raw(n);
    +	if (n->parent->tok != MDOC_Rs)
    +		return;
    +	if (n->next != NULL) {
    +		md_word(",");
    +		if (n->prev != NULL &&
    +		    n->prev->tok == n->tok &&
    +		    n->next->tok == n->tok)
    +			md_word("and");
    +	} else {
    +		md_word(".");
    +		outflags |= MD_nl;
    +	}
    +}
    +
    +static int
    +md_pre_skip(struct roff_node *n)
    +{
    +	return 0;
    +}
    +
    +static void
    +md_pre_syn(struct roff_node *n)
    +{
    +	if (n->prev == NULL || ! (n->flags & NODE_SYNPRETTY))
    +		return;
    +
    +	if (n->prev->tok == n->tok &&
    +	    n->tok != MDOC_Ft &&
    +	    n->tok != MDOC_Fo &&
    +	    n->tok != MDOC_Fn) {
    +		outflags |= MD_br;
    +		return;
    +	}
    +
    +	switch (n->prev->tok) {
    +	case MDOC_Fd:
    +	case MDOC_Fn:
    +	case MDOC_Fo:
    +	case MDOC_In:
    +	case MDOC_Vt:
    +		outflags |= MD_sp;
    +		break;
    +	case MDOC_Ft:
    +		if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
    +			outflags |= MD_sp;
    +			break;
    +		}
    +		/* FALLTHROUGH */
    +	default:
    +		outflags |= MD_br;
    +		break;
    +	}
    +}
    +
    +static int
    +md_pre_An(struct roff_node *n)
    +{
    +	switch (n->norm->An.auth) {
    +	case AUTH_split:
    +		outflags &= ~MD_An_nosplit;
    +		outflags |= MD_An_split;
    +		return 0;
    +	case AUTH_nosplit:
    +		outflags &= ~MD_An_split;
    +		outflags |= MD_An_nosplit;
    +		return 0;
    +	default:
    +		if (outflags & MD_An_split)
    +			outflags |= MD_br;
    +		else if (n->sec == SEC_AUTHORS &&
    +		    ! (outflags & MD_An_nosplit))
    +			outflags |= MD_An_split;
    +		return 1;
    +	}
    +}
    +
    +static int
    +md_pre_Ap(struct roff_node *n)
    +{
    +	outflags &= ~MD_spc;
    +	md_word("'");
    +	outflags &= ~MD_spc;
    +	return 0;
    +}
    +
    +static int
    +md_pre_Bd(struct roff_node *n)
    +{
    +	switch (n->norm->Bd.type) {
    +	case DISP_unfilled:
    +	case DISP_literal:
    +		return md_pre_Dl(n);
    +	default:
    +		return md_pre_D1(n);
    +	}
    +}
    +
    +static int
    +md_pre_Bk(struct roff_node *n)
    +{
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		return 1;
    +	case ROFFT_BODY:
    +		outflags |= MD_Bk;
    +		return 1;
    +	default:
    +		return 0;
    +	}
    +}
    +
    +static void
    +md_post_Bk(struct roff_node *n)
    +{
    +	if (n->type == ROFFT_BODY)
    +		outflags &= ~MD_Bk;
    +}
    +
    +static int
    +md_pre_Bl(struct roff_node *n)
    +{
    +	n->norm->Bl.count = 0;
    +	if (n->norm->Bl.type == LIST_column)
    +		md_pre_Dl(n);
    +	outflags |= MD_sp;
    +	return 1;
    +}
    +
    +static void
    +md_post_Bl(struct roff_node *n)
    +{
    +	n->norm->Bl.count = 0;
    +	if (n->norm->Bl.type == LIST_column)
    +		md_post_D1(n);
    +	outflags |= MD_sp;
    +}
    +
    +static int
    +md_pre_D1(struct roff_node *n)
    +{
    +	/*
    +	 * Markdown blockquote syntax does not work inside code blocks.
    +	 * The best we can do is fall back to another nested code block.
    +	 */
    +	if (code_blocks) {
    +		md_stack('\t');
    +		code_blocks++;
    +	} else {
    +		md_stack('>');
    +		quote_blocks++;
    +	}
    +	outflags |= MD_sp;
    +	return 1;
    +}
    +
    +static void
    +md_post_D1(struct roff_node *n)
    +{
    +	md_stack((char)-1);
    +	if (code_blocks)
    +		code_blocks--;
    +	else
    +		quote_blocks--;
    +	outflags |= MD_sp;
    +}
    +
    +static int
    +md_pre_Dl(struct roff_node *n)
    +{
    +	/*
    +	 * Markdown code block syntax does not work inside blockquotes.
    +	 * The best we can do is fall back to another nested blockquote.
    +	 */
    +	if (quote_blocks) {
    +		md_stack('>');
    +		quote_blocks++;
    +	} else {
    +		md_stack('\t');
    +		code_blocks++;
    +	}
    +	outflags |= MD_sp;
    +	return 1;
    +}
    +
    +static int
    +md_pre_En(struct roff_node *n)
    +{
    +	if (n->norm->Es == NULL ||
    +	    n->norm->Es->child == NULL)
    +		return 1;
    +
    +	md_word(n->norm->Es->child->string);
    +	outflags &= ~MD_spc;
    +	return 1;
    +}
    +
    +static void
    +md_post_En(struct roff_node *n)
    +{
    +	if (n->norm->Es == NULL ||
    +	    n->norm->Es->child == NULL ||
    +	    n->norm->Es->child->next == NULL)
    +		return;
    +
    +	outflags &= ~MD_spc;
    +	md_word(n->norm->Es->child->next->string);
    +}
    +
    +static int
    +md_pre_Eo(struct roff_node *n)
    +{
    +	if (n->end == ENDBODY_NOT &&
    +	    n->parent->head->child == NULL &&
    +	    n->child != NULL &&
    +	    n->child->end != ENDBODY_NOT)
    +		md_preword();
    +	else if (n->end != ENDBODY_NOT ? n->child != NULL :
    +	    n->parent->head->child != NULL && (n->child != NULL ||
    +	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
    +		outflags &= ~(MD_spc | MD_nl);
    +	return 1;
    +}
    +
    +static void
    +md_post_Eo(struct roff_node *n)
    +{
    +	if (n->end != ENDBODY_NOT) {
    +		outflags |= MD_spc;
    +		return;
    +	}
    +
    +	if (n->child == NULL && n->parent->head->child == NULL)
    +		return;
    +
    +	if (n->parent->tail != NULL && n->parent->tail->child != NULL)
    +		outflags &= ~MD_spc;
    +        else
    +		outflags |= MD_spc;
    +}
    +
    +static int
    +md_pre_Fa(struct roff_node *n)
    +{
    +	int	 am_Fa;
    +
    +	am_Fa = n->tok == MDOC_Fa;
    +
    +	if (am_Fa)
    +		n = n->child;
    +
    +	while (n != NULL) {
    +		md_rawword("*");
    +		outflags &= ~MD_spc;
    +		md_node(n);
    +		outflags &= ~MD_spc;
    +		md_rawword("*");
    +		if ((n = n->next) != NULL)
    +			md_word(",");
    +	}
    +	return 0;
    +}
    +
    +static void
    +md_post_Fa(struct roff_node *n)
    +{
    +	if (n->next != NULL && n->next->tok == MDOC_Fa)
    +		md_word(",");
    +}
    +
    +static int
    +md_pre_Fd(struct roff_node *n)
    +{
    +	md_pre_syn(n);
    +	md_pre_raw(n);
    +	return 1;
    +}
    +
    +static void
    +md_post_Fd(struct roff_node *n)
    +{
    +	md_post_raw(n);
    +	outflags |= MD_br;
    +}
    +
    +static void
    +md_post_Fl(struct roff_node *n)
    +{
    +	md_post_raw(n);
    +	if (n->child == NULL && n->next != NULL &&
    +	    n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE))
    +		outflags &= ~MD_spc;
    +}
    +
    +static int
    +md_pre_Fn(struct roff_node *n)
    +{
    +	md_pre_syn(n);
    +
    +	if ((n = n->child) == NULL)
    +		return 0;
    +
    +	md_rawword("**");
    +	outflags &= ~MD_spc;
    +	md_node(n);
    +	outflags &= ~MD_spc;
    +	md_rawword("**");
    +	outflags &= ~MD_spc;
    +	md_word("(");
    +
    +	if ((n = n->next) != NULL)
    +		md_pre_Fa(n);
    +	return 0;
    +}
    +
    +static void
    +md_post_Fn(struct roff_node *n)
    +{
    +	md_word(")");
    +	if (n->flags & NODE_SYNPRETTY) {
    +		md_word(";");
    +		outflags |= MD_sp;
    +	}
    +}
    +
    +static int
    +md_pre_Fo(struct roff_node *n)
    +{
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		md_pre_syn(n);
    +		break;
    +	case ROFFT_HEAD:
    +		if (n->child == NULL)
    +			return 0;
    +		md_pre_raw(n);
    +		break;
    +	case ROFFT_BODY:
    +		outflags &= ~(MD_spc | MD_nl);
    +		md_word("(");
    +		break;
    +	default:
    +		break;
    +	}
    +	return 1;
    +}
    +
    +static void
    +md_post_Fo(struct roff_node *n)
    +{
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		if (n->child != NULL)
    +			md_post_raw(n);
    +		break;
    +	case ROFFT_BODY:
    +		md_post_Fn(n);
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static int
    +md_pre_In(struct roff_node *n)
    +{
    +	if (n->flags & NODE_SYNPRETTY) {
    +		md_pre_syn(n);
    +		md_rawword("**");
    +		outflags &= ~MD_spc;
    +		md_word("#include <");
    +	} else {
    +		md_word("<");
    +		outflags &= ~MD_spc;
    +		md_rawword("*");
    +	}
    +	outflags &= ~MD_spc;
    +	return 1;
    +}
    +
    +static void
    +md_post_In(struct roff_node *n)
    +{
    +	if (n->flags & NODE_SYNPRETTY) {
    +		outflags &= ~MD_spc;
    +		md_rawword(">**");
    +		outflags |= MD_nl;
    +	} else {
    +		outflags &= ~MD_spc;
    +		md_rawword("*>");
    +	}
    +}
    +
    +static int
    +md_pre_It(struct roff_node *n)
    +{
    +	struct roff_node	*bln;
    +
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		return 1;
    +
    +	case ROFFT_HEAD:
    +		bln = n->parent->parent;
    +		if (bln->norm->Bl.comp == 0 &&
    +		    bln->norm->Bl.type != LIST_column)
    +			outflags |= MD_sp;
    +		outflags |= MD_nl;
    +
    +		switch (bln->norm->Bl.type) {
    +		case LIST_item:
    +			outflags |= MD_br;
    +			return 0;
    +		case LIST_inset:
    +		case LIST_diag:
    +		case LIST_ohang:
    +			outflags |= MD_br;
    +			return 1;
    +		case LIST_tag:
    +		case LIST_hang:
    +			outflags |= MD_sp;
    +			return 1;
    +		case LIST_bullet:
    +			md_rawword("*\t");
    +			break;
    +		case LIST_dash:
    +		case LIST_hyphen:
    +			md_rawword("-\t");
    +			break;
    +		case LIST_enum:
    +			md_preword();
    +			if (bln->norm->Bl.count < 99)
    +				bln->norm->Bl.count++;
    +			printf("%d.\t", bln->norm->Bl.count);
    +			escflags &= ~ESC_FON;
    +			break;
    +		case LIST_column:
    +			outflags |= MD_br;
    +			return 0;
    +		default:
    +			return 0;
    +		}
    +		outflags &= ~MD_spc;
    +		outflags |= MD_nonl;
    +		outcount = 0;
    +		md_stack('\t');
    +		if (code_blocks || quote_blocks)
    +			list_blocks++;
    +		return 0;
    +
    +	case ROFFT_BODY:
    +		bln = n->parent->parent;
    +		switch (bln->norm->Bl.type) {
    +		case LIST_ohang:
    +			outflags |= MD_br;
    +			break;
    +		case LIST_tag:
    +		case LIST_hang:
    +			md_pre_D1(n);
    +			break;
    +		default:
    +			break;
    +		}
    +		return 1;
    +
    +	default:
    +		return 0;
    +	}
    +}
    +
    +static void
    +md_post_It(struct roff_node *n)
    +{
    +	struct roff_node	*bln;
    +	int			 i, nc;
    +
    +	if (n->type != ROFFT_BODY)
    +		return;
    +
    +	bln = n->parent->parent;
    +	switch (bln->norm->Bl.type) {
    +	case LIST_bullet:
    +	case LIST_dash:
    +	case LIST_hyphen:
    +	case LIST_enum:
    +		md_stack((char)-1);
    +		if (code_blocks || quote_blocks)
    +			list_blocks--;
    +		break;
    +	case LIST_tag:
    +	case LIST_hang:
    +		md_post_D1(n);
    +		break;
    +
    +	case LIST_column:
    +		if (n->next == NULL)
    +			break;
    +
    +		/* Calculate the array index of the current column. */
    +
    +		i = 0;
    +		while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)
    +			i++;
    +
    +		/* 
    +		 * If a width was specified for this column,
    +		 * subtract what printed, and
    +		 * add the same spacing as in mdoc_term.c.
    +		 */
    +
    +		nc = bln->norm->Bl.ncols;
    +		i = i < nc ? strlen(bln->norm->Bl.cols[i]) - outcount +
    +		    (nc < 5 ? 4 : nc == 5 ? 3 : 1) : 1;
    +		if (i < 1)
    +			i = 1;
    +		while (i-- > 0)
    +			putchar(' ');
    +
    +		outflags &= ~MD_spc;
    +		escflags &= ~ESC_FON;
    +		outcount = 0;
    +		break;
    +
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +md_post_Lb(struct roff_node *n)
    +{
    +	if (n->sec == SEC_LIBRARY)
    +		outflags |= MD_br;
    +}
    +
    +static void
    +md_uri(const char *s)
    +{
    +	while (*s != '\0') {
    +		if (strchr("%()<>", *s) != NULL) {
    +			printf("%%%2.2hhX", *s);
    +			outcount += 3;
    +		} else {
    +			putchar(*s);
    +			outcount++;
    +		}
    +		s++;
    +	}
    +}
    +
    +static int
    +md_pre_Lk(struct roff_node *n)
    +{
    +	const struct roff_node *link, *descr, *punct;
    +
    +	if ((link = n->child) == NULL)
    +		return 0;
    +
    +	/* Find beginning of trailing punctuation. */
    +	punct = n->last;
    +	while (punct != link && punct->flags & NODE_DELIMC)
    +		punct = punct->prev;
    +	punct = punct->next;
    +
    +	/* Link text. */
    +	descr = link->next;
    +	if (descr == punct)
    +		descr = link;  /* no text */
    +	md_rawword("[");
    +	outflags &= ~MD_spc;
    +	do {
    +		md_word(descr->string);
    +		descr = descr->next;
    +	} while (descr != punct);
    +	outflags &= ~MD_spc;
    +
    +	/* Link target. */
    +	md_rawword("](");
    +	md_uri(link->string);
    +	outflags &= ~MD_spc;
    +	md_rawword(")");
    +
    +	/* Trailing punctuation. */
    +	while (punct != NULL) {
    +		md_word(punct->string);
    +		punct = punct->next;
    +	}
    +	return 0;
    +}
    +
    +static int
    +md_pre_Mt(struct roff_node *n)
    +{
    +	const struct roff_node *nch;
    +
    +	md_rawword("[");
    +	outflags &= ~MD_spc;
    +	for (nch = n->child; nch != NULL; nch = nch->next)
    +		md_word(nch->string);
    +	outflags &= ~MD_spc;
    +	md_rawword("](mailto:");
    +	for (nch = n->child; nch != NULL; nch = nch->next) {
    +		md_uri(nch->string);
    +		if (nch->next != NULL) {
    +			putchar(' ');
    +			outcount++;
    +		}
    +	}
    +	outflags &= ~MD_spc;
    +	md_rawword(")");
    +	return 0;
    +}
    +
    +static int
    +md_pre_Nd(struct roff_node *n)
    +{
    +	outflags &= ~MD_nl;
    +	outflags |= MD_spc;
    +	md_word("-");
    +	return 1;
    +}
    +
    +static int
    +md_pre_Nm(struct roff_node *n)
    +{
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		outflags |= MD_Bk;
    +		md_pre_syn(n);
    +		break;
    +	case ROFFT_HEAD:
    +	case ROFFT_ELEM:
    +		md_pre_raw(n);
    +		break;
    +	default:
    +		break;
    +	}
    +	return 1;
    +}
    +
    +static void
    +md_post_Nm(struct roff_node *n)
    +{
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		outflags &= ~MD_Bk;
    +		break;
    +	case ROFFT_HEAD:
    +	case ROFFT_ELEM:
    +		md_post_raw(n);
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static int
    +md_pre_No(struct roff_node *n)
    +{
    +	outflags |= MD_spc_force;
    +	return 1;
    +}
    +
    +static int
    +md_pre_Ns(struct roff_node *n)
    +{
    +	outflags &= ~MD_spc;
    +	return 0;
    +}
    +
    +static void
    +md_post_Pf(struct roff_node *n)
    +{
    +	if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
    +		outflags &= ~MD_spc;
    +}
    +
    +static int
    +md_pre_Pp(struct roff_node *n)
    +{
    +	outflags |= MD_sp;
    +	return 0;
    +}
    +
    +static int
    +md_pre_Rs(struct roff_node *n)
    +{
    +	if (n->sec == SEC_SEE_ALSO)
    +		outflags |= MD_sp;
    +	return 1;
    +}
    +
    +static int
    +md_pre_Sh(struct roff_node *n)
    +{
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		if (n->sec == SEC_AUTHORS)
    +			outflags &= ~(MD_An_split | MD_An_nosplit);
    +		break;
    +	case ROFFT_HEAD:
    +		outflags |= MD_sp;
    +		md_rawword(n->tok == MDOC_Sh ? "#" : "##");
    +		break;
    +	case ROFFT_BODY:
    +		outflags |= MD_sp;
    +		break;
    +	default:
    +		break;
    +	}
    +	return 1;
    +}
    +
    +static int
    +md_pre_Sm(struct roff_node *n)
    +{
    +	if (n->child == NULL)
    +		outflags ^= MD_Sm;
    +	else if (strcmp("on", n->child->string) == 0)
    +		outflags |= MD_Sm;
    +	else
    +		outflags &= ~MD_Sm;
    +
    +	if (outflags & MD_Sm)
    +		outflags |= MD_spc;
    +
    +	return 0;
    +}
    +
    +static int
    +md_pre_Vt(struct roff_node *n)
    +{
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		md_pre_syn(n);
    +		return 1;
    +	case ROFFT_BODY:
    +	case ROFFT_ELEM:
    +		md_pre_raw(n);
    +		return 1;
    +	default:
    +		return 0;
    +	}
    +}
    +
    +static void
    +md_post_Vt(struct roff_node *n)
    +{
    +	switch (n->type) {
    +	case ROFFT_BODY:
    +	case ROFFT_ELEM:
    +		md_post_raw(n);
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static int
    +md_pre_Xr(struct roff_node *n)
    +{
    +	n = n->child;
    +	if (n == NULL)
    +		return 0;
    +	md_node(n);
    +	n = n->next;
    +	if (n == NULL)
    +		return 0;
    +	outflags &= ~MD_spc;
    +	md_word("(");
    +	md_node(n);
    +	md_word(")");
    +	return 0;
    +}
    +
    +static int
    +md_pre__T(struct roff_node *n)
    +{
    +	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
    +		md_word("\"");
    +	else
    +		md_rawword("*");
    +	outflags &= ~MD_spc;
    +	return 1;
    +}
    +
    +static void
    +md_post__T(struct roff_node *n)
    +{
    +	outflags &= ~MD_spc;
    +	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
    +		md_word("\"");
    +	else
    +		md_rawword("*");
    +	md_post_pc(n);
    +}
    +
    +static int
    +md_pre_br(struct roff_node *n)
    +{
    +	outflags |= MD_br;
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/mdoc_markdown.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc_state.c
    ===================================================================
    --- head/contrib/mandoc/mdoc_state.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc_state.c	(revision 338826)
    @@ -0,0 +1,297 @@
    +/*	$Id: mdoc_state.c,v 1.9 2017/11/29 20:05:33 schwarze Exp $ */
    +/*
    + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "libmandoc.h"
    +#include "libmdoc.h"
    +
    +#define STATE_ARGS  struct roff_man *mdoc, struct roff_node *n
    +
    +typedef	void	(*state_handler)(STATE_ARGS);
    +
    +static	void	 state_bd(STATE_ARGS);
    +static	void	 state_bl(STATE_ARGS);
    +static	void	 state_dl(STATE_ARGS);
    +static	void	 state_sh(STATE_ARGS);
    +static	void	 state_sm(STATE_ARGS);
    +
    +static	const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
    +	NULL,		/* Dd */
    +	NULL,		/* Dt */
    +	NULL,		/* Os */
    +	state_sh,	/* Sh */
    +	NULL,		/* Ss */
    +	NULL,		/* Pp */
    +	NULL,		/* D1 */
    +	state_dl,	/* Dl */
    +	state_bd,	/* Bd */
    +	NULL,		/* Ed */
    +	state_bl,	/* Bl */
    +	NULL,		/* El */
    +	NULL,		/* It */
    +	NULL,		/* Ad */
    +	NULL,		/* An */
    +	NULL,		/* Ap */
    +	NULL,		/* Ar */
    +	NULL,		/* Cd */
    +	NULL,		/* Cm */
    +	NULL,		/* Dv */
    +	NULL,		/* Er */
    +	NULL,		/* Ev */
    +	NULL,		/* Ex */
    +	NULL,		/* Fa */
    +	NULL,		/* Fd */
    +	NULL,		/* Fl */
    +	NULL,		/* Fn */
    +	NULL,		/* Ft */
    +	NULL,		/* Ic */
    +	NULL,		/* In */
    +	NULL,		/* Li */
    +	NULL,		/* Nd */
    +	NULL,		/* Nm */
    +	NULL,		/* Op */
    +	NULL,		/* Ot */
    +	NULL,		/* Pa */
    +	NULL,		/* Rv */
    +	NULL,		/* St */
    +	NULL,		/* Va */
    +	NULL,		/* Vt */
    +	NULL,		/* Xr */
    +	NULL,		/* %A */
    +	NULL,		/* %B */
    +	NULL,		/* %D */
    +	NULL,		/* %I */
    +	NULL,		/* %J */
    +	NULL,		/* %N */
    +	NULL,		/* %O */
    +	NULL,		/* %P */
    +	NULL,		/* %R */
    +	NULL,		/* %T */
    +	NULL,		/* %V */
    +	NULL,		/* Ac */
    +	NULL,		/* Ao */
    +	NULL,		/* Aq */
    +	NULL,		/* At */
    +	NULL,		/* Bc */
    +	NULL,		/* Bf */
    +	NULL,		/* Bo */
    +	NULL,		/* Bq */
    +	NULL,		/* Bsx */
    +	NULL,		/* Bx */
    +	NULL,		/* Db */
    +	NULL,		/* Dc */
    +	NULL,		/* Do */
    +	NULL,		/* Dq */
    +	NULL,		/* Ec */
    +	NULL,		/* Ef */
    +	NULL,		/* Em */
    +	NULL,		/* Eo */
    +	NULL,		/* Fx */
    +	NULL,		/* Ms */
    +	NULL,		/* No */
    +	NULL,		/* Ns */
    +	NULL,		/* Nx */
    +	NULL,		/* Ox */
    +	NULL,		/* Pc */
    +	NULL,		/* Pf */
    +	NULL,		/* Po */
    +	NULL,		/* Pq */
    +	NULL,		/* Qc */
    +	NULL,		/* Ql */
    +	NULL,		/* Qo */
    +	NULL,		/* Qq */
    +	NULL,		/* Re */
    +	NULL,		/* Rs */
    +	NULL,		/* Sc */
    +	NULL,		/* So */
    +	NULL,		/* Sq */
    +	state_sm,	/* Sm */
    +	NULL,		/* Sx */
    +	NULL,		/* Sy */
    +	NULL,		/* Tn */
    +	NULL,		/* Ux */
    +	NULL,		/* Xc */
    +	NULL,		/* Xo */
    +	NULL,		/* Fo */
    +	NULL,		/* Fc */
    +	NULL,		/* Oo */
    +	NULL,		/* Oc */
    +	NULL,		/* Bk */
    +	NULL,		/* Ek */
    +	NULL,		/* Bt */
    +	NULL,		/* Hf */
    +	NULL,		/* Fr */
    +	NULL,		/* Ud */
    +	NULL,		/* Lb */
    +	NULL,		/* Lp */
    +	NULL,		/* Lk */
    +	NULL,		/* Mt */
    +	NULL,		/* Brq */
    +	NULL,		/* Bro */
    +	NULL,		/* Brc */
    +	NULL,		/* %C */
    +	NULL,		/* Es */
    +	NULL,		/* En */
    +	NULL,		/* Dx */
    +	NULL,		/* %Q */
    +	NULL,		/* %U */
    +	NULL,		/* Ta */
    +};
    +static const state_handler *const state_handlers = __state_handlers - MDOC_Dd;
    +
    +
    +void
    +mdoc_state(struct roff_man *mdoc, struct roff_node *n)
    +{
    +	state_handler handler;
    +
    +	if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
    +		return;
    +
    +	assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
    +	if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
    +		mdoc->flags |= MDOC_PBODY;
    +
    +	handler = state_handlers[n->tok];
    +	if (*handler)
    +		(*handler)(mdoc, n);
    +}
    +
    +void
    +mdoc_state_reset(struct roff_man *mdoc)
    +{
    +
    +	roff_setreg(mdoc->roff, "nS", 0, '=');
    +	mdoc->flags = 0;
    +}
    +
    +static void
    +state_bd(STATE_ARGS)
    +{
    +	enum mdocargt arg;
    +
    +	if (n->type != ROFFT_HEAD &&
    +	    (n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
    +		return;
    +
    +	if (n->parent->args == NULL)
    +		return;
    +
    +	arg = n->parent->args->argv[0].arg;
    +	if (arg != MDOC_Literal && arg != MDOC_Unfilled)
    +		return;
    +
    +	state_dl(mdoc, n);
    +}
    +
    +static void
    +state_bl(STATE_ARGS)
    +{
    +	struct mdoc_arg	*args;
    +	size_t		 i;
    +
    +	if (n->type != ROFFT_HEAD || n->parent->args == NULL)
    +		return;
    +
    +	args = n->parent->args;
    +	for (i = 0; i < args->argc; i++) {
    +		switch(args->argv[i].arg) {
    +		case MDOC_Diag:
    +			n->norm->Bl.type = LIST_diag;
    +			return;
    +		case MDOC_Column:
    +			n->norm->Bl.type = LIST_column;
    +			return;
    +		default:
    +			break;
    +		}
    +	}
    +}
    +
    +static void
    +state_dl(STATE_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		mdoc->flags |= MDOC_LITERAL;
    +		break;
    +	case ROFFT_BODY:
    +		mdoc->flags &= ~MDOC_LITERAL;
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +state_sh(STATE_ARGS)
    +{
    +	struct roff_node *nch;
    +	char		 *secname;
    +
    +	if (n->type != ROFFT_HEAD)
    +		return;
    +
    +	if ( ! (n->flags & NODE_VALID)) {
    +		secname = NULL;
    +		deroff(&secname, n);
    +
    +		/*
    +		 * Set the section attribute for the BLOCK, HEAD,
    +		 * and HEAD children; the latter can only be TEXT
    +		 * nodes, so no recursion is needed.  For other
    +		 * nodes, including the .Sh BODY, this is done
    +		 * when allocating the node data structures, but
    +		 * for .Sh BLOCK and HEAD, the section is still
    +		 * unknown at that time.
    +		 */
    +
    +		n->sec = n->parent->sec = secname == NULL ?
    +		    SEC_CUSTOM : mdoc_a2sec(secname);
    +		for (nch = n->child; nch != NULL; nch = nch->next)
    +			nch->sec = n->sec;
    +		free(secname);
    +	}
    +
    +	if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) {
    +		roff_setreg(mdoc->roff, "nS", 1, '=');
    +		mdoc->flags |= MDOC_SYNOPSIS;
    +	} else {
    +		roff_setreg(mdoc->roff, "nS", 0, '=');
    +		mdoc->flags &= ~MDOC_SYNOPSIS;
    +	}
    +}
    +
    +static void
    +state_sm(STATE_ARGS)
    +{
    +
    +	if (n->child == NULL)
    +		mdoc->flags ^= MDOC_SMOFF;
    +	else if ( ! strcmp(n->child->string, "on"))
    +		mdoc->flags &= ~MDOC_SMOFF;
    +	else if ( ! strcmp(n->child->string, "off"))
    +		mdoc->flags |= MDOC_SMOFF;
    +}
    
    Property changes on: head/contrib/mandoc/mdoc_state.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc_term.c
    ===================================================================
    --- head/contrib/mandoc/mdoc_term.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc_term.c	(revision 338826)
    @@ -0,0 +1,2100 @@
    +/*	$Id: mdoc_term.c,v 1.367 2018/04/11 17:11:13 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <limits.h>
    +#include <stdint.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "out.h"
    +#include "term.h"
    +#include "tag.h"
    +#include "main.h"
    +
    +struct	termpair {
    +	struct termpair	 *ppair;
    +	int		  count;
    +};
    +
    +#define	DECL_ARGS struct termp *p, \
    +		  struct termpair *pair, \
    +		  const struct roff_meta *meta, \
    +		  struct roff_node *n
    +
    +struct	termact {
    +	int	(*pre)(DECL_ARGS);
    +	void	(*post)(DECL_ARGS);
    +};
    +
    +static	int	  a2width(const struct termp *, const char *);
    +
    +static	void	  print_bvspace(struct termp *,
    +			const struct roff_node *,
    +			const struct roff_node *);
    +static	void	  print_mdoc_node(DECL_ARGS);
    +static	void	  print_mdoc_nodelist(DECL_ARGS);
    +static	void	  print_mdoc_head(struct termp *, const struct roff_meta *);
    +static	void	  print_mdoc_foot(struct termp *, const struct roff_meta *);
    +static	void	  synopsis_pre(struct termp *,
    +			const struct roff_node *);
    +
    +static	void	  termp____post(DECL_ARGS);
    +static	void	  termp__t_post(DECL_ARGS);
    +static	void	  termp_bd_post(DECL_ARGS);
    +static	void	  termp_bk_post(DECL_ARGS);
    +static	void	  termp_bl_post(DECL_ARGS);
    +static	void	  termp_eo_post(DECL_ARGS);
    +static	void	  termp_fd_post(DECL_ARGS);
    +static	void	  termp_fo_post(DECL_ARGS);
    +static	void	  termp_in_post(DECL_ARGS);
    +static	void	  termp_it_post(DECL_ARGS);
    +static	void	  termp_lb_post(DECL_ARGS);
    +static	void	  termp_nm_post(DECL_ARGS);
    +static	void	  termp_pf_post(DECL_ARGS);
    +static	void	  termp_quote_post(DECL_ARGS);
    +static	void	  termp_sh_post(DECL_ARGS);
    +static	void	  termp_ss_post(DECL_ARGS);
    +static	void	  termp_xx_post(DECL_ARGS);
    +
    +static	int	  termp__a_pre(DECL_ARGS);
    +static	int	  termp__t_pre(DECL_ARGS);
    +static	int	  termp_an_pre(DECL_ARGS);
    +static	int	  termp_ap_pre(DECL_ARGS);
    +static	int	  termp_bd_pre(DECL_ARGS);
    +static	int	  termp_bf_pre(DECL_ARGS);
    +static	int	  termp_bk_pre(DECL_ARGS);
    +static	int	  termp_bl_pre(DECL_ARGS);
    +static	int	  termp_bold_pre(DECL_ARGS);
    +static	int	  termp_cd_pre(DECL_ARGS);
    +static	int	  termp_d1_pre(DECL_ARGS);
    +static	int	  termp_eo_pre(DECL_ARGS);
    +static	int	  termp_em_pre(DECL_ARGS);
    +static	int	  termp_er_pre(DECL_ARGS);
    +static	int	  termp_ex_pre(DECL_ARGS);
    +static	int	  termp_fa_pre(DECL_ARGS);
    +static	int	  termp_fd_pre(DECL_ARGS);
    +static	int	  termp_fl_pre(DECL_ARGS);
    +static	int	  termp_fn_pre(DECL_ARGS);
    +static	int	  termp_fo_pre(DECL_ARGS);
    +static	int	  termp_ft_pre(DECL_ARGS);
    +static	int	  termp_in_pre(DECL_ARGS);
    +static	int	  termp_it_pre(DECL_ARGS);
    +static	int	  termp_li_pre(DECL_ARGS);
    +static	int	  termp_lk_pre(DECL_ARGS);
    +static	int	  termp_nd_pre(DECL_ARGS);
    +static	int	  termp_nm_pre(DECL_ARGS);
    +static	int	  termp_ns_pre(DECL_ARGS);
    +static	int	  termp_quote_pre(DECL_ARGS);
    +static	int	  termp_rs_pre(DECL_ARGS);
    +static	int	  termp_sh_pre(DECL_ARGS);
    +static	int	  termp_skip_pre(DECL_ARGS);
    +static	int	  termp_sm_pre(DECL_ARGS);
    +static	int	  termp_pp_pre(DECL_ARGS);
    +static	int	  termp_ss_pre(DECL_ARGS);
    +static	int	  termp_sy_pre(DECL_ARGS);
    +static	int	  termp_tag_pre(DECL_ARGS);
    +static	int	  termp_under_pre(DECL_ARGS);
    +static	int	  termp_vt_pre(DECL_ARGS);
    +static	int	  termp_xr_pre(DECL_ARGS);
    +static	int	  termp_xx_pre(DECL_ARGS);
    +
    +static	const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
    +	{ NULL, NULL }, /* Dd */
    +	{ NULL, NULL }, /* Dt */
    +	{ NULL, NULL }, /* Os */
    +	{ termp_sh_pre, termp_sh_post }, /* Sh */
    +	{ termp_ss_pre, termp_ss_post }, /* Ss */
    +	{ termp_pp_pre, NULL }, /* Pp */
    +	{ termp_d1_pre, termp_bl_post }, /* D1 */
    +	{ termp_d1_pre, termp_bl_post }, /* Dl */
    +	{ termp_bd_pre, termp_bd_post }, /* Bd */
    +	{ NULL, NULL }, /* Ed */
    +	{ termp_bl_pre, termp_bl_post }, /* Bl */
    +	{ NULL, NULL }, /* El */
    +	{ termp_it_pre, termp_it_post }, /* It */
    +	{ termp_under_pre, NULL }, /* Ad */
    +	{ termp_an_pre, NULL }, /* An */
    +	{ termp_ap_pre, NULL }, /* Ap */
    +	{ termp_under_pre, NULL }, /* Ar */
    +	{ termp_cd_pre, NULL }, /* Cd */
    +	{ termp_bold_pre, NULL }, /* Cm */
    +	{ termp_li_pre, NULL }, /* Dv */
    +	{ termp_er_pre, NULL }, /* Er */
    +	{ termp_tag_pre, NULL }, /* Ev */
    +	{ termp_ex_pre, NULL }, /* Ex */
    +	{ termp_fa_pre, NULL }, /* Fa */
    +	{ termp_fd_pre, termp_fd_post }, /* Fd */
    +	{ termp_fl_pre, NULL }, /* Fl */
    +	{ termp_fn_pre, NULL }, /* Fn */
    +	{ termp_ft_pre, NULL }, /* Ft */
    +	{ termp_bold_pre, NULL }, /* Ic */
    +	{ termp_in_pre, termp_in_post }, /* In */
    +	{ termp_li_pre, NULL }, /* Li */
    +	{ termp_nd_pre, NULL }, /* Nd */
    +	{ termp_nm_pre, termp_nm_post }, /* Nm */
    +	{ termp_quote_pre, termp_quote_post }, /* Op */
    +	{ termp_ft_pre, NULL }, /* Ot */
    +	{ termp_under_pre, NULL }, /* Pa */
    +	{ termp_ex_pre, NULL }, /* Rv */
    +	{ NULL, NULL }, /* St */
    +	{ termp_under_pre, NULL }, /* Va */
    +	{ termp_vt_pre, NULL }, /* Vt */
    +	{ termp_xr_pre, NULL }, /* Xr */
    +	{ termp__a_pre, termp____post }, /* %A */
    +	{ termp_under_pre, termp____post }, /* %B */
    +	{ NULL, termp____post }, /* %D */
    +	{ termp_under_pre, termp____post }, /* %I */
    +	{ termp_under_pre, termp____post }, /* %J */
    +	{ NULL, termp____post }, /* %N */
    +	{ NULL, termp____post }, /* %O */
    +	{ NULL, termp____post }, /* %P */
    +	{ NULL, termp____post }, /* %R */
    +	{ termp__t_pre, termp__t_post }, /* %T */
    +	{ NULL, termp____post }, /* %V */
    +	{ NULL, NULL }, /* Ac */
    +	{ termp_quote_pre, termp_quote_post }, /* Ao */
    +	{ termp_quote_pre, termp_quote_post }, /* Aq */
    +	{ NULL, NULL }, /* At */
    +	{ NULL, NULL }, /* Bc */
    +	{ termp_bf_pre, NULL }, /* Bf */
    +	{ termp_quote_pre, termp_quote_post }, /* Bo */
    +	{ termp_quote_pre, termp_quote_post }, /* Bq */
    +	{ termp_xx_pre, termp_xx_post }, /* Bsx */
    +	{ NULL, NULL }, /* Bx */
    +	{ termp_skip_pre, NULL }, /* Db */
    +	{ NULL, NULL }, /* Dc */
    +	{ termp_quote_pre, termp_quote_post }, /* Do */
    +	{ termp_quote_pre, termp_quote_post }, /* Dq */
    +	{ NULL, NULL }, /* Ec */ /* FIXME: no space */
    +	{ NULL, NULL }, /* Ef */
    +	{ termp_em_pre, NULL }, /* Em */
    +	{ termp_eo_pre, termp_eo_post }, /* Eo */
    +	{ termp_xx_pre, termp_xx_post }, /* Fx */
    +	{ termp_bold_pre, NULL }, /* Ms */
    +	{ termp_li_pre, NULL }, /* No */
    +	{ termp_ns_pre, NULL }, /* Ns */
    +	{ termp_xx_pre, termp_xx_post }, /* Nx */
    +	{ termp_xx_pre, termp_xx_post }, /* Ox */
    +	{ NULL, NULL }, /* Pc */
    +	{ NULL, termp_pf_post }, /* Pf */
    +	{ termp_quote_pre, termp_quote_post }, /* Po */
    +	{ termp_quote_pre, termp_quote_post }, /* Pq */
    +	{ NULL, NULL }, /* Qc */
    +	{ termp_quote_pre, termp_quote_post }, /* Ql */
    +	{ termp_quote_pre, termp_quote_post }, /* Qo */
    +	{ termp_quote_pre, termp_quote_post }, /* Qq */
    +	{ NULL, NULL }, /* Re */
    +	{ termp_rs_pre, NULL }, /* Rs */
    +	{ NULL, NULL }, /* Sc */
    +	{ termp_quote_pre, termp_quote_post }, /* So */
    +	{ termp_quote_pre, termp_quote_post }, /* Sq */
    +	{ termp_sm_pre, NULL }, /* Sm */
    +	{ termp_under_pre, NULL }, /* Sx */
    +	{ termp_sy_pre, NULL }, /* Sy */
    +	{ NULL, NULL }, /* Tn */
    +	{ termp_xx_pre, termp_xx_post }, /* Ux */
    +	{ NULL, NULL }, /* Xc */
    +	{ NULL, NULL }, /* Xo */
    +	{ termp_fo_pre, termp_fo_post }, /* Fo */
    +	{ NULL, NULL }, /* Fc */
    +	{ termp_quote_pre, termp_quote_post }, /* Oo */
    +	{ NULL, NULL }, /* Oc */
    +	{ termp_bk_pre, termp_bk_post }, /* Bk */
    +	{ NULL, NULL }, /* Ek */
    +	{ NULL, NULL }, /* Bt */
    +	{ NULL, NULL }, /* Hf */
    +	{ termp_under_pre, NULL }, /* Fr */
    +	{ NULL, NULL }, /* Ud */
    +	{ NULL, termp_lb_post }, /* Lb */
    +	{ termp_pp_pre, NULL }, /* Lp */
    +	{ termp_lk_pre, NULL }, /* Lk */
    +	{ termp_under_pre, NULL }, /* Mt */
    +	{ termp_quote_pre, termp_quote_post }, /* Brq */
    +	{ termp_quote_pre, termp_quote_post }, /* Bro */
    +	{ NULL, NULL }, /* Brc */
    +	{ NULL, termp____post }, /* %C */
    +	{ termp_skip_pre, NULL }, /* Es */
    +	{ termp_quote_pre, termp_quote_post }, /* En */
    +	{ termp_xx_pre, termp_xx_post }, /* Dx */
    +	{ NULL, termp____post }, /* %Q */
    +	{ NULL, termp____post }, /* %U */
    +	{ NULL, NULL }, /* Ta */
    +};
    +static	const struct termact *const termacts = __termacts - MDOC_Dd;
    +
    +static	int	 fn_prio;
    +
    +
    +void
    +terminal_mdoc(void *arg, const struct roff_man *mdoc)
    +{
    +	struct roff_node	*n;
    +	struct termp		*p;
    +	size_t			 save_defindent;
    +
    +	p = (struct termp *)arg;
    +	p->tcol->rmargin = p->maxrmargin = p->defrmargin;
    +	term_tab_set(p, NULL);
    +	term_tab_set(p, "T");
    +	term_tab_set(p, ".5i");
    +
    +	n = mdoc->first->child;
    +	if (p->synopsisonly) {
    +		while (n != NULL) {
    +			if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
    +				if (n->child->next->child != NULL)
    +					print_mdoc_nodelist(p, NULL,
    +					    &mdoc->meta,
    +					    n->child->next->child);
    +				term_newln(p);
    +				break;
    +			}
    +			n = n->next;
    +		}
    +	} else {
    +		save_defindent = p->defindent;
    +		if (p->defindent == 0)
    +			p->defindent = 5;
    +		term_begin(p, print_mdoc_head, print_mdoc_foot,
    +		    &mdoc->meta);
    +		while (n != NULL &&
    +		    (n->type == ROFFT_COMMENT ||
    +		     n->flags & NODE_NOPRT))
    +			n = n->next;
    +		if (n != NULL) {
    +			if (n->tok != MDOC_Sh)
    +				term_vspace(p);
    +			print_mdoc_nodelist(p, NULL, &mdoc->meta, n);
    +		}
    +		term_end(p);
    +		p->defindent = save_defindent;
    +	}
    +}
    +
    +static void
    +print_mdoc_nodelist(DECL_ARGS)
    +{
    +
    +	while (n != NULL) {
    +		print_mdoc_node(p, pair, meta, n);
    +		n = n->next;
    +	}
    +}
    +
    +static void
    +print_mdoc_node(DECL_ARGS)
    +{
    +	int		 chld;
    +	struct termpair	 npair;
    +	size_t		 offset, rmargin;
    +
    +	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
    +		return;
    +
    +	chld = 1;
    +	offset = p->tcol->offset;
    +	rmargin = p->tcol->rmargin;
    +	n->flags &= ~NODE_ENDED;
    +	n->prev_font = p->fonti;
    +
    +	memset(&npair, 0, sizeof(struct termpair));
    +	npair.ppair = pair;
    +
    +	/*
    +	 * Keeps only work until the end of a line.  If a keep was
    +	 * invoked in a prior line, revert it to PREKEEP.
    +	 */
    +
    +	if (p->flags & TERMP_KEEP && n->flags & NODE_LINE) {
    +		p->flags &= ~TERMP_KEEP;
    +		p->flags |= TERMP_PREKEEP;
    +	}
    +
    +	/*
    +	 * After the keep flags have been set up, we may now
    +	 * produce output.  Note that some pre-handlers do so.
    +	 */
    +
    +	switch (n->type) {
    +	case ROFFT_TEXT:
    +		if (*n->string == ' ' && n->flags & NODE_LINE &&
    +		    (p->flags & TERMP_NONEWLINE) == 0)
    +			term_newln(p);
    +		if (NODE_DELIMC & n->flags)
    +			p->flags |= TERMP_NOSPACE;
    +		term_word(p, n->string);
    +		if (NODE_DELIMO & n->flags)
    +			p->flags |= TERMP_NOSPACE;
    +		break;
    +	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;
    +		break;
    +	case ROFFT_TBL:
    +		if (p->tbl.cols == NULL)
    +			term_newln(p);
    +		term_tbl(p, n->span);
    +		break;
    +	default:
    +		if (n->tok < ROFF_MAX) {
    +			roff_term_pre(p, n);
    +			return;
    +		}
    +		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
    +		if (termacts[n->tok].pre != NULL &&
    +		    (n->end == ENDBODY_NOT || n->child != NULL))
    +			chld = (*termacts[n->tok].pre)
    +				(p, &npair, meta, n);
    +		break;
    +	}
    +
    +	if (chld && n->child)
    +		print_mdoc_nodelist(p, &npair, meta, n->child);
    +
    +	term_fontpopq(p,
    +	    (ENDBODY_NOT == n->end ? n : n->body)->prev_font);
    +
    +	switch (n->type) {
    +	case ROFFT_TEXT:
    +		break;
    +	case ROFFT_TBL:
    +		break;
    +	case ROFFT_EQN:
    +		break;
    +	default:
    +		if (termacts[n->tok].post == NULL || n->flags & NODE_ENDED)
    +			break;
    +		(void)(*termacts[n->tok].post)(p, &npair, meta, n);
    +
    +		/*
    +		 * Explicit end tokens not only call the post
    +		 * handler, but also tell the respective block
    +		 * that it must not call the post handler again.
    +		 */
    +		if (ENDBODY_NOT != n->end)
    +			n->body->flags |= NODE_ENDED;
    +		break;
    +	}
    +
    +	if (NODE_EOS & n->flags)
    +		p->flags |= TERMP_SENTENCE;
    +
    +	if (n->type != ROFFT_TEXT)
    +		p->tcol->offset = offset;
    +	p->tcol->rmargin = rmargin;
    +}
    +
    +static void
    +print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
    +{
    +	size_t sz;
    +
    +	term_fontrepl(p, TERMFONT_NONE);
    +
    +	/*
    +	 * Output the footer in new-groff style, that is, three columns
    +	 * with the middle being the manual date and flanking columns
    +	 * being the operating system:
    +	 *
    +	 * SYSTEM                  DATE                    SYSTEM
    +	 */
    +
    +	term_vspace(p);
    +
    +	p->tcol->offset = 0;
    +	sz = term_strlen(p, meta->date);
    +	p->tcol->rmargin = p->maxrmargin > sz ?
    +	    (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
    +	p->trailspace = 1;
    +	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
    +
    +	term_word(p, meta->os);
    +	term_flushln(p);
    +
    +	p->tcol->offset = p->tcol->rmargin;
    +	sz = term_strlen(p, meta->os);
    +	p->tcol->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
    +	p->flags |= TERMP_NOSPACE;
    +
    +	term_word(p, meta->date);
    +	term_flushln(p);
    +
    +	p->tcol->offset = p->tcol->rmargin;
    +	p->tcol->rmargin = p->maxrmargin;
    +	p->trailspace = 0;
    +	p->flags &= ~TERMP_NOBREAK;
    +	p->flags |= TERMP_NOSPACE;
    +
    +	term_word(p, meta->os);
    +	term_flushln(p);
    +
    +	p->tcol->offset = 0;
    +	p->tcol->rmargin = p->maxrmargin;
    +	p->flags = 0;
    +}
    +
    +static void
    +print_mdoc_head(struct termp *p, const struct roff_meta *meta)
    +{
    +	char			*volume, *title;
    +	size_t			 vollen, titlen;
    +
    +	/*
    +	 * The header is strange.  It has three components, which are
    +	 * really two with the first duplicated.  It goes like this:
    +	 *
    +	 * IDENTIFIER              TITLE                   IDENTIFIER
    +	 *
    +	 * The IDENTIFIER is NAME(SECTION), which is the command-name
    +	 * (if given, or "unknown" if not) followed by the manual page
    +	 * section.  These are given in `Dt'.  The TITLE is a free-form
    +	 * string depending on the manual volume.  If not specified, it
    +	 * switches on the manual section.
    +	 */
    +
    +	assert(meta->vol);
    +	if (NULL == meta->arch)
    +		volume = mandoc_strdup(meta->vol);
    +	else
    +		mandoc_asprintf(&volume, "%s (%s)",
    +		    meta->vol, meta->arch);
    +	vollen = term_strlen(p, volume);
    +
    +	if (NULL == meta->msec)
    +		title = mandoc_strdup(meta->title);
    +	else
    +		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);
    +
    +	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);
    +
    +	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;
    +	free(title);
    +	free(volume);
    +}
    +
    +static int
    +a2width(const struct termp *p, const char *v)
    +{
    +	struct roffsu	 su;
    +	const char	*end;
    +
    +	end = a2roffsu(v, &su, SCALE_MAX);
    +	if (end == NULL || *end != '\0') {
    +		SCALE_HS_INIT(&su, term_strlen(p, v));
    +		su.scale /= term_strlen(p, "0");
    +	}
    +	return term_hen(p, &su);
    +}
    +
    +/*
    + * Determine how much space to print out before block elements of `It'
    + * (and thus `Bl') and `Bd'.  And then go ahead and print that space,
    + * too.
    + */
    +static void
    +print_bvspace(struct termp *p,
    +	const struct roff_node *bl,
    +	const struct roff_node *n)
    +{
    +	const struct roff_node	*nn;
    +
    +	assert(n);
    +
    +	term_newln(p);
    +
    +	if (MDOC_Bd == bl->tok && bl->norm->Bd.comp)
    +		return;
    +	if (MDOC_Bl == bl->tok && bl->norm->Bl.comp)
    +		return;
    +
    +	/* Do not vspace directly after Ss/Sh. */
    +
    +	nn = n;
    +	while (nn->prev != NULL &&
    +	    (nn->prev->type == ROFFT_COMMENT ||
    +	     nn->prev->flags & NODE_NOPRT))
    +		nn = nn->prev;
    +	while (nn->prev == NULL) {
    +		do {
    +			nn = nn->parent;
    +			if (nn->type == ROFFT_ROOT)
    +				return;
    +		} while (nn->type != ROFFT_BLOCK);
    +		if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
    +			return;
    +		if (nn->tok == MDOC_It &&
    +		    nn->parent->parent->norm->Bl.type != LIST_item)
    +			break;
    +	}
    +
    +	/* A `-column' does not assert vspace within the list. */
    +
    +	if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type)
    +		if (n->prev && MDOC_It == n->prev->tok)
    +			return;
    +
    +	/* A `-diag' without body does not vspace. */
    +
    +	if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type)
    +		if (n->prev && MDOC_It == n->prev->tok) {
    +			assert(n->prev->body);
    +			if (NULL == n->prev->body->child)
    +				return;
    +		}
    +
    +	term_vspace(p);
    +}
    +
    +
    +static int
    +termp_it_pre(DECL_ARGS)
    +{
    +	struct roffsu		su;
    +	char			buf[24];
    +	const struct roff_node *bl, *nn;
    +	size_t			ncols, dcol;
    +	int			i, offset, width;
    +	enum mdoc_list		type;
    +
    +	if (n->type == ROFFT_BLOCK) {
    +		print_bvspace(p, n->parent->parent, n);
    +		return 1;
    +	}
    +
    +	bl = n->parent->parent->parent;
    +	type = bl->norm->Bl.type;
    +
    +	/*
    +	 * Defaults for specific list types.
    +	 */
    +
    +	switch (type) {
    +	case LIST_bullet:
    +	case LIST_dash:
    +	case LIST_hyphen:
    +	case LIST_enum:
    +		width = term_len(p, 2);
    +		break;
    +	case LIST_hang:
    +	case LIST_tag:
    +		width = term_len(p, 8);
    +		break;
    +	case LIST_column:
    +		width = term_len(p, 10);
    +		break;
    +	default:
    +		width = 0;
    +		break;
    +	}
    +	offset = 0;
    +
    +	/*
    +	 * First calculate width and offset.  This is pretty easy unless
    +	 * we're a -column list, in which case all prior columns must
    +	 * be accounted for.
    +	 */
    +
    +	if (bl->norm->Bl.offs != NULL) {
    +		offset = a2width(p, bl->norm->Bl.offs);
    +		if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
    +			offset = -p->tcol->offset;
    +		else if (offset > SHRT_MAX)
    +			offset = 0;
    +	}
    +
    +	switch (type) {
    +	case LIST_column:
    +		if (n->type == ROFFT_HEAD)
    +			break;
    +
    +		/*
    +		 * Imitate groff's column handling:
    +		 * - For each earlier column, add its width.
    +		 * - For less than 5 columns, add four more blanks per
    +		 *   column.
    +		 * - For exactly 5 columns, add three more blank per
    +		 *   column.
    +		 * - For more than 5 columns, add only one column.
    +		 */
    +		ncols = bl->norm->Bl.ncols;
    +		dcol = ncols < 5 ? term_len(p, 4) :
    +		    ncols == 5 ? term_len(p, 3) : term_len(p, 1);
    +
    +		/*
    +		 * Calculate the offset by applying all prior ROFFT_BODY,
    +		 * so we stop at the ROFFT_HEAD (nn->prev == NULL).
    +		 */
    +
    +		for (i = 0, nn = n->prev;
    +		    nn->prev && i < (int)ncols;
    +		    nn = nn->prev, i++) {
    +			SCALE_HS_INIT(&su,
    +			    term_strlen(p, bl->norm->Bl.cols[i]));
    +			su.scale /= term_strlen(p, "0");
    +			offset += term_hen(p, &su) + dcol;
    +		}
    +
    +		/*
    +		 * When exceeding the declared number of columns, leave
    +		 * the remaining widths at 0.  This will later be
    +		 * adjusted to the default width of 10, or, for the last
    +		 * column, stretched to the right margin.
    +		 */
    +		if (i >= (int)ncols)
    +			break;
    +
    +		/*
    +		 * Use the declared column widths, extended as explained
    +		 * in the preceding paragraph.
    +		 */
    +		SCALE_HS_INIT(&su, term_strlen(p, bl->norm->Bl.cols[i]));
    +		su.scale /= term_strlen(p, "0");
    +		width = term_hen(p, &su) + dcol;
    +		break;
    +	default:
    +		if (NULL == bl->norm->Bl.width)
    +			break;
    +
    +		/*
    +		 * Note: buffer the width by 2, which is groff's magic
    +		 * number for buffering single arguments.  See the above
    +		 * handling for column for how this changes.
    +		 */
    +		width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
    +		if (width < 0 && (size_t)(-width) > p->tcol->offset)
    +			width = -p->tcol->offset;
    +		else if (width > SHRT_MAX)
    +			width = 0;
    +		break;
    +	}
    +
    +	/*
    +	 * Whitespace control.  Inset bodies need an initial space,
    +	 * while diagonal bodies need two.
    +	 */
    +
    +	p->flags |= TERMP_NOSPACE;
    +
    +	switch (type) {
    +	case LIST_diag:
    +		if (n->type == ROFFT_BODY)
    +			term_word(p, "\\ \\ ");
    +		break;
    +	case LIST_inset:
    +		if (n->type == ROFFT_BODY && n->parent->head->child != NULL)
    +			term_word(p, "\\ ");
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	p->flags |= TERMP_NOSPACE;
    +
    +	switch (type) {
    +	case LIST_diag:
    +		if (n->type == ROFFT_HEAD)
    +			term_fontpush(p, TERMFONT_BOLD);
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	/*
    +	 * Pad and break control.  This is the tricky part.  These flags
    +	 * are documented in term_flushln() in term.c.  Note that we're
    +	 * going to unset all of these flags in termp_it_post() when we
    +	 * exit.
    +	 */
    +
    +	switch (type) {
    +	case LIST_enum:
    +	case LIST_bullet:
    +	case LIST_dash:
    +	case LIST_hyphen:
    +		if (n->type == ROFFT_HEAD) {
    +			p->flags |= TERMP_NOBREAK | TERMP_HANG;
    +			p->trailspace = 1;
    +		} else if (width <= (int)term_len(p, 2))
    +			p->flags |= TERMP_NOPAD;
    +		break;
    +	case LIST_hang:
    +		if (n->type != ROFFT_HEAD)
    +			break;
    +		p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
    +		p->trailspace = 1;
    +		break;
    +	case LIST_tag:
    +		if (n->type != ROFFT_HEAD)
    +			break;
    +
    +		p->flags |= TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND;
    +		p->trailspace = 2;
    +
    +		if (NULL == n->next || NULL == n->next->child)
    +			p->flags |= TERMP_HANG;
    +		break;
    +	case LIST_column:
    +		if (n->type == ROFFT_HEAD)
    +			break;
    +
    +		if (NULL == n->next) {
    +			p->flags &= ~TERMP_NOBREAK;
    +			p->trailspace = 0;
    +		} else {
    +			p->flags |= TERMP_NOBREAK;
    +			p->trailspace = 1;
    +		}
    +
    +		break;
    +	case LIST_diag:
    +		if (n->type != ROFFT_HEAD)
    +			break;
    +		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
    +		p->trailspace = 1;
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	/*
    +	 * Margin control.  Set-head-width lists have their right
    +	 * margins shortened.  The body for these lists has the offset
    +	 * necessarily lengthened.  Everybody gets the offset.
    +	 */
    +
    +	p->tcol->offset += offset;
    +
    +	switch (type) {
    +	case LIST_bullet:
    +	case LIST_dash:
    +	case LIST_enum:
    +	case LIST_hyphen:
    +	case LIST_hang:
    +	case LIST_tag:
    +		if (n->type == ROFFT_HEAD)
    +			p->tcol->rmargin = p->tcol->offset + width;
    +		else
    +			p->tcol->offset += width;
    +		break;
    +	case LIST_column:
    +		assert(width);
    +		p->tcol->rmargin = p->tcol->offset + width;
    +		/*
    +		 * XXX - this behaviour is not documented: the
    +		 * right-most column is filled to the right margin.
    +		 */
    +		if (n->type == ROFFT_HEAD)
    +			break;
    +		if (n->next == NULL && p->tcol->rmargin < p->maxrmargin)
    +			p->tcol->rmargin = p->maxrmargin;
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	/*
    +	 * The dash, hyphen, bullet and enum lists all have a special
    +	 * HEAD character (temporarily bold, in some cases).
    +	 */
    +
    +	if (n->type == ROFFT_HEAD)
    +		switch (type) {
    +		case LIST_bullet:
    +			term_fontpush(p, TERMFONT_BOLD);
    +			term_word(p, "\\[bu]");
    +			term_fontpop(p);
    +			break;
    +		case LIST_dash:
    +		case LIST_hyphen:
    +			term_fontpush(p, TERMFONT_BOLD);
    +			term_word(p, "-");
    +			term_fontpop(p);
    +			break;
    +		case LIST_enum:
    +			(pair->ppair->ppair->count)++;
    +			(void)snprintf(buf, sizeof(buf), "%d.",
    +			    pair->ppair->ppair->count);
    +			term_word(p, buf);
    +			break;
    +		default:
    +			break;
    +		}
    +
    +	/*
    +	 * If we're not going to process our children, indicate so here.
    +	 */
    +
    +	switch (type) {
    +	case LIST_bullet:
    +	case LIST_item:
    +	case LIST_dash:
    +	case LIST_hyphen:
    +	case LIST_enum:
    +		if (n->type == ROFFT_HEAD)
    +			return 0;
    +		break;
    +	case LIST_column:
    +		if (n->type == ROFFT_HEAD)
    +			return 0;
    +		p->minbl = 0;
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	return 1;
    +}
    +
    +static void
    +termp_it_post(DECL_ARGS)
    +{
    +	enum mdoc_list	   type;
    +
    +	if (n->type == ROFFT_BLOCK)
    +		return;
    +
    +	type = n->parent->parent->parent->norm->Bl.type;
    +
    +	switch (type) {
    +	case LIST_item:
    +	case LIST_diag:
    +	case LIST_inset:
    +		if (n->type == ROFFT_BODY)
    +			term_newln(p);
    +		break;
    +	case LIST_column:
    +		if (n->type == ROFFT_BODY)
    +			term_flushln(p);
    +		break;
    +	default:
    +		term_newln(p);
    +		break;
    +	}
    +
    +	/*
    +	 * Now that our output is flushed, we can reset our tags.  Since
    +	 * only `It' sets these flags, we're free to assume that nobody
    +	 * has munged them in the meanwhile.
    +	 */
    +
    +	p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND | TERMP_HANG);
    +	p->trailspace = 0;
    +}
    +
    +static int
    +termp_nm_pre(DECL_ARGS)
    +{
    +	const char	*cp;
    +
    +	if (n->type == ROFFT_BLOCK) {
    +		p->flags |= TERMP_PREKEEP;
    +		return 1;
    +	}
    +
    +	if (n->type == ROFFT_BODY) {
    +		if (n->child == NULL)
    +			return 0;
    +		p->flags |= TERMP_NOSPACE;
    +		cp = NULL;
    +		if (n->prev->child != NULL)
    +		    cp = n->prev->child->string;
    +		if (cp == NULL)
    +			cp = meta->name;
    +		if (cp == NULL)
    +			p->tcol->offset += term_len(p, 6);
    +		else
    +			p->tcol->offset += term_len(p, 1) +
    +			    term_strlen(p, cp);
    +		return 1;
    +	}
    +
    +	if (n->child == NULL)
    +		return 0;
    +
    +	if (n->type == ROFFT_HEAD)
    +		synopsis_pre(p, n->parent);
    +
    +	if (n->type == ROFFT_HEAD &&
    +	    n->next != NULL && n->next->child != NULL) {
    +		p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
    +		p->trailspace = 1;
    +		p->tcol->rmargin = p->tcol->offset + term_len(p, 1);
    +		if (n->child == NULL)
    +			p->tcol->rmargin += term_strlen(p, meta->name);
    +		else if (n->child->type == ROFFT_TEXT) {
    +			p->tcol->rmargin += term_strlen(p, n->child->string);
    +			if (n->child->next != NULL)
    +				p->flags |= TERMP_HANG;
    +		} else {
    +			p->tcol->rmargin += term_len(p, 5);
    +			p->flags |= TERMP_HANG;
    +		}
    +	}
    +
    +	term_fontpush(p, TERMFONT_BOLD);
    +	return 1;
    +}
    +
    +static void
    +termp_nm_post(DECL_ARGS)
    +{
    +
    +	if (n->type == ROFFT_BLOCK) {
    +		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
    +	} else if (n->type == ROFFT_HEAD &&
    +	    NULL != n->next && NULL != n->next->child) {
    +		term_flushln(p);
    +		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
    +		p->trailspace = 0;
    +	} else if (n->type == ROFFT_BODY && n->child != NULL)
    +		term_flushln(p);
    +}
    +
    +static int
    +termp_fl_pre(DECL_ARGS)
    +{
    +
    +	termp_tag_pre(p, pair, meta, n);
    +	term_fontpush(p, TERMFONT_BOLD);
    +	term_word(p, "\\-");
    +
    +	if (!(n->child == NULL &&
    +	    (n->next == NULL ||
    +	     n->next->type == ROFFT_TEXT ||
    +	     n->next->flags & NODE_LINE)))
    +		p->flags |= TERMP_NOSPACE;
    +
    +	return 1;
    +}
    +
    +static int
    +termp__a_pre(DECL_ARGS)
    +{
    +
    +	if (n->prev && MDOC__A == n->prev->tok)
    +		if (NULL == n->next || MDOC__A != n->next->tok)
    +			term_word(p, "and");
    +
    +	return 1;
    +}
    +
    +static int
    +termp_an_pre(DECL_ARGS)
    +{
    +
    +	if (n->norm->An.auth == AUTH_split) {
    +		p->flags &= ~TERMP_NOSPLIT;
    +		p->flags |= TERMP_SPLIT;
    +		return 0;
    +	}
    +	if (n->norm->An.auth == AUTH_nosplit) {
    +		p->flags &= ~TERMP_SPLIT;
    +		p->flags |= TERMP_NOSPLIT;
    +		return 0;
    +	}
    +
    +	if (p->flags & TERMP_SPLIT)
    +		term_newln(p);
    +
    +	if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT))
    +		p->flags |= TERMP_SPLIT;
    +
    +	return 1;
    +}
    +
    +static int
    +termp_ns_pre(DECL_ARGS)
    +{
    +
    +	if ( ! (NODE_LINE & n->flags))
    +		p->flags |= TERMP_NOSPACE;
    +	return 1;
    +}
    +
    +static int
    +termp_rs_pre(DECL_ARGS)
    +{
    +
    +	if (SEC_SEE_ALSO != n->sec)
    +		return 1;
    +	if (n->type == ROFFT_BLOCK && n->prev != NULL)
    +		term_vspace(p);
    +	return 1;
    +}
    +
    +static int
    +termp_ex_pre(DECL_ARGS)
    +{
    +	term_newln(p);
    +	return 1;
    +}
    +
    +static int
    +termp_nd_pre(DECL_ARGS)
    +{
    +
    +	if (n->type == ROFFT_BODY)
    +		term_word(p, "\\(en");
    +	return 1;
    +}
    +
    +static int
    +termp_bl_pre(DECL_ARGS)
    +{
    +
    +	return n->type != ROFFT_HEAD;
    +}
    +
    +static void
    +termp_bl_post(DECL_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BLOCK)
    +		return;
    +	term_newln(p);
    +	if (n->tok != MDOC_Bl || n->norm->Bl.type != LIST_column)
    +		return;
    +	term_tab_set(p, NULL);
    +	term_tab_set(p, "T");
    +	term_tab_set(p, ".5i");
    +}
    +
    +static int
    +termp_xr_pre(DECL_ARGS)
    +{
    +
    +	if (NULL == (n = n->child))
    +		return 0;
    +
    +	assert(n->type == ROFFT_TEXT);
    +	term_word(p, n->string);
    +
    +	if (NULL == (n = n->next))
    +		return 0;
    +
    +	p->flags |= TERMP_NOSPACE;
    +	term_word(p, "(");
    +	p->flags |= TERMP_NOSPACE;
    +
    +	assert(n->type == ROFFT_TEXT);
    +	term_word(p, n->string);
    +
    +	p->flags |= TERMP_NOSPACE;
    +	term_word(p, ")");
    +
    +	return 0;
    +}
    +
    +/*
    + * This decides how to assert whitespace before any of the SYNOPSIS set
    + * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain
    + * macro combos).
    + */
    +static void
    +synopsis_pre(struct termp *p, const struct roff_node *n)
    +{
    +	/*
    +	 * Obviously, if we're not in a SYNOPSIS or no prior macros
    +	 * exist, do nothing.
    +	 */
    +	if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
    +		return;
    +
    +	/*
    +	 * If we're the second in a pair of like elements, emit our
    +	 * newline and return.  UNLESS we're `Fo', `Fn', `Fn', in which
    +	 * case we soldier on.
    +	 */
    +	if (n->prev->tok == n->tok &&
    +	    MDOC_Ft != n->tok &&
    +	    MDOC_Fo != n->tok &&
    +	    MDOC_Fn != n->tok) {
    +		term_newln(p);
    +		return;
    +	}
    +
    +	/*
    +	 * If we're one of the SYNOPSIS set and non-like pair-wise after
    +	 * another (or Fn/Fo, which we've let slip through) then assert
    +	 * vertical space, else only newline and move on.
    +	 */
    +	switch (n->prev->tok) {
    +	case MDOC_Fd:
    +	case MDOC_Fn:
    +	case MDOC_Fo:
    +	case MDOC_In:
    +	case MDOC_Vt:
    +		term_vspace(p);
    +		break;
    +	case MDOC_Ft:
    +		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
    +			term_vspace(p);
    +			break;
    +		}
    +		/* FALLTHROUGH */
    +	default:
    +		term_newln(p);
    +		break;
    +	}
    +}
    +
    +static int
    +termp_vt_pre(DECL_ARGS)
    +{
    +
    +	if (n->type == ROFFT_ELEM) {
    +		synopsis_pre(p, n);
    +		return termp_under_pre(p, pair, meta, n);
    +	} else if (n->type == ROFFT_BLOCK) {
    +		synopsis_pre(p, n);
    +		return 1;
    +	} else if (n->type == ROFFT_HEAD)
    +		return 0;
    +
    +	return termp_under_pre(p, pair, meta, n);
    +}
    +
    +static int
    +termp_bold_pre(DECL_ARGS)
    +{
    +
    +	termp_tag_pre(p, pair, meta, n);
    +	term_fontpush(p, TERMFONT_BOLD);
    +	return 1;
    +}
    +
    +static int
    +termp_fd_pre(DECL_ARGS)
    +{
    +
    +	synopsis_pre(p, n);
    +	return termp_bold_pre(p, pair, meta, n);
    +}
    +
    +static void
    +termp_fd_post(DECL_ARGS)
    +{
    +
    +	term_newln(p);
    +}
    +
    +static int
    +termp_sh_pre(DECL_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		/*
    +		 * Vertical space before sections, except
    +		 * when the previous section was empty.
    +		 */
    +		if (n->prev == NULL ||
    +		    n->prev->tok != MDOC_Sh ||
    +		    (n->prev->body != NULL &&
    +		     n->prev->body->child != NULL))
    +			term_vspace(p);
    +		break;
    +	case ROFFT_HEAD:
    +		term_fontpush(p, TERMFONT_BOLD);
    +		break;
    +	case ROFFT_BODY:
    +		p->tcol->offset = term_len(p, p->defindent);
    +		term_tab_set(p, NULL);
    +		term_tab_set(p, "T");
    +		term_tab_set(p, ".5i");
    +		switch (n->sec) {
    +		case SEC_DESCRIPTION:
    +			fn_prio = 0;
    +			break;
    +		case SEC_AUTHORS:
    +			p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	default:
    +		break;
    +	}
    +	return 1;
    +}
    +
    +static void
    +termp_sh_post(DECL_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		term_newln(p);
    +		break;
    +	case ROFFT_BODY:
    +		term_newln(p);
    +		p->tcol->offset = 0;
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +termp_lb_post(DECL_ARGS)
    +{
    +
    +	if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags)
    +		term_newln(p);
    +}
    +
    +static int
    +termp_d1_pre(DECL_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BLOCK)
    +		return 1;
    +	term_newln(p);
    +	p->tcol->offset += term_len(p, p->defindent + 1);
    +	term_tab_set(p, NULL);
    +	term_tab_set(p, "T");
    +	term_tab_set(p, ".5i");
    +	return 1;
    +}
    +
    +static int
    +termp_ft_pre(DECL_ARGS)
    +{
    +
    +	/* NB: NODE_LINE does not effect this! */
    +	synopsis_pre(p, n);
    +	term_fontpush(p, TERMFONT_UNDER);
    +	return 1;
    +}
    +
    +static int
    +termp_fn_pre(DECL_ARGS)
    +{
    +	size_t		 rmargin = 0;
    +	int		 pretty;
    +
    +	pretty = NODE_SYNPRETTY & n->flags;
    +
    +	synopsis_pre(p, n);
    +
    +	if (NULL == (n = n->child))
    +		return 0;
    +
    +	if (pretty) {
    +		rmargin = p->tcol->rmargin;
    +		p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
    +		p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
    +	}
    +
    +	assert(n->type == ROFFT_TEXT);
    +	term_fontpush(p, TERMFONT_BOLD);
    +	term_word(p, n->string);
    +	term_fontpop(p);
    +
    +	if (n->sec == SEC_DESCRIPTION || n->sec == SEC_CUSTOM)
    +		tag_put(n->string, ++fn_prio, p->line);
    +
    +	if (pretty) {
    +		term_flushln(p);
    +		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
    +		p->flags |= TERMP_NOPAD;
    +		p->tcol->offset = p->tcol->rmargin;
    +		p->tcol->rmargin = rmargin;
    +	}
    +
    +	p->flags |= TERMP_NOSPACE;
    +	term_word(p, "(");
    +	p->flags |= TERMP_NOSPACE;
    +
    +	for (n = n->next; n; n = n->next) {
    +		assert(n->type == ROFFT_TEXT);
    +		term_fontpush(p, TERMFONT_UNDER);
    +		if (pretty)
    +			p->flags |= TERMP_NBRWORD;
    +		term_word(p, n->string);
    +		term_fontpop(p);
    +
    +		if (n->next) {
    +			p->flags |= TERMP_NOSPACE;
    +			term_word(p, ",");
    +		}
    +	}
    +
    +	p->flags |= TERMP_NOSPACE;
    +	term_word(p, ")");
    +
    +	if (pretty) {
    +		p->flags |= TERMP_NOSPACE;
    +		term_word(p, ";");
    +		term_flushln(p);
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +termp_fa_pre(DECL_ARGS)
    +{
    +	const struct roff_node	*nn;
    +
    +	if (n->parent->tok != MDOC_Fo) {
    +		term_fontpush(p, TERMFONT_UNDER);
    +		return 1;
    +	}
    +
    +	for (nn = n->child; nn; nn = nn->next) {
    +		term_fontpush(p, TERMFONT_UNDER);
    +		p->flags |= TERMP_NBRWORD;
    +		term_word(p, nn->string);
    +		term_fontpop(p);
    +
    +		if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
    +			p->flags |= TERMP_NOSPACE;
    +			term_word(p, ",");
    +		}
    +	}
    +
    +	return 0;
    +}
    +
    +static int
    +termp_bd_pre(DECL_ARGS)
    +{
    +	size_t			 lm, len;
    +	struct roff_node	*nn;
    +	int			 offset;
    +
    +	if (n->type == ROFFT_BLOCK) {
    +		print_bvspace(p, n, n);
    +		return 1;
    +	} else if (n->type == ROFFT_HEAD)
    +		return 0;
    +
    +	/* Handle the -offset argument. */
    +
    +	if (n->norm->Bd.offs == NULL ||
    +	    ! strcmp(n->norm->Bd.offs, "left"))
    +		/* nothing */;
    +	else if ( ! strcmp(n->norm->Bd.offs, "indent"))
    +		p->tcol->offset += term_len(p, p->defindent + 1);
    +	else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
    +		p->tcol->offset += term_len(p, (p->defindent + 1) * 2);
    +	else {
    +		offset = a2width(p, n->norm->Bd.offs);
    +		if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
    +			p->tcol->offset = 0;
    +		else if (offset < SHRT_MAX)
    +			p->tcol->offset += offset;
    +	}
    +
    +	/*
    +	 * If -ragged or -filled are specified, the block does nothing
    +	 * but change the indentation.  If -unfilled or -literal are
    +	 * specified, text is printed exactly as entered in the display:
    +	 * for macro lines, a newline is appended to the line.  Blank
    +	 * lines are allowed.
    +	 */
    +
    +	if (n->norm->Bd.type != DISP_literal &&
    +	    n->norm->Bd.type != DISP_unfilled &&
    +	    n->norm->Bd.type != DISP_centered)
    +		return 1;
    +
    +	if (n->norm->Bd.type == DISP_literal) {
    +		term_tab_set(p, NULL);
    +		term_tab_set(p, "T");
    +		term_tab_set(p, "8n");
    +	}
    +
    +	lm = p->tcol->offset;
    +	p->flags |= TERMP_BRNEVER;
    +	for (nn = n->child; nn != NULL; nn = nn->next) {
    +		if (n->norm->Bd.type == DISP_centered) {
    +			if (nn->type == ROFFT_TEXT) {
    +				len = term_strlen(p, nn->string);
    +				p->tcol->offset = len >= p->tcol->rmargin ?
    +				    0 : lm + len >= p->tcol->rmargin ?
    +				    p->tcol->rmargin - len :
    +				    (lm + p->tcol->rmargin - len) / 2;
    +			} else
    +				p->tcol->offset = lm;
    +		}
    +		print_mdoc_node(p, pair, meta, nn);
    +		/*
    +		 * If the printed node flushes its own line, then we
    +		 * needn't do it here as well.  This is hacky, but the
    +		 * notion of selective eoln whitespace is pretty dumb
    +		 * anyway, so don't sweat it.
    +		 */
    +		if (nn->tok < ROFF_MAX)
    +			continue;
    +		switch (nn->tok) {
    +		case MDOC_Sm:
    +		case MDOC_Bl:
    +		case MDOC_D1:
    +		case MDOC_Dl:
    +		case MDOC_Lp:
    +		case MDOC_Pp:
    +			continue;
    +		default:
    +			break;
    +		}
    +		if (p->flags & TERMP_NONEWLINE ||
    +		    (nn->next && ! (nn->next->flags & NODE_LINE)))
    +			continue;
    +		term_flushln(p);
    +		p->flags |= TERMP_NOSPACE;
    +	}
    +	p->flags &= ~TERMP_BRNEVER;
    +	return 0;
    +}
    +
    +static void
    +termp_bd_post(DECL_ARGS)
    +{
    +	if (n->type != ROFFT_BODY)
    +		return;
    +	if (DISP_literal == n->norm->Bd.type ||
    +	    DISP_unfilled == n->norm->Bd.type)
    +		p->flags |= TERMP_BRNEVER;
    +	p->flags |= TERMP_NOSPACE;
    +	term_newln(p);
    +	p->flags &= ~TERMP_BRNEVER;
    +}
    +
    +static int
    +termp_xx_pre(DECL_ARGS)
    +{
    +	if ((n->aux = p->flags & TERMP_PREKEEP) == 0)
    +		p->flags |= TERMP_PREKEEP;
    +	return 1;
    +}
    +
    +static void
    +termp_xx_post(DECL_ARGS)
    +{
    +	if (n->aux == 0)
    +		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
    +}
    +
    +static void
    +termp_pf_post(DECL_ARGS)
    +{
    +
    +	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
    +		p->flags |= TERMP_NOSPACE;
    +}
    +
    +static int
    +termp_ss_pre(DECL_ARGS)
    +{
    +	struct roff_node *nn;
    +
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		term_newln(p);
    +		for (nn = n->prev; nn != NULL; nn = nn->prev)
    +			if (nn->type != ROFFT_COMMENT &&
    +			    (nn->flags & NODE_NOPRT) == 0)
    +				break;
    +		if (nn != NULL)
    +			term_vspace(p);
    +		break;
    +	case ROFFT_HEAD:
    +		term_fontpush(p, TERMFONT_BOLD);
    +		p->tcol->offset = term_len(p, (p->defindent+1)/2);
    +		break;
    +	case ROFFT_BODY:
    +		p->tcol->offset = term_len(p, p->defindent);
    +		term_tab_set(p, NULL);
    +		term_tab_set(p, "T");
    +		term_tab_set(p, ".5i");
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	return 1;
    +}
    +
    +static void
    +termp_ss_post(DECL_ARGS)
    +{
    +
    +	if (n->type == ROFFT_HEAD || n->type == ROFFT_BODY)
    +		term_newln(p);
    +}
    +
    +static int
    +termp_cd_pre(DECL_ARGS)
    +{
    +
    +	synopsis_pre(p, n);
    +	term_fontpush(p, TERMFONT_BOLD);
    +	return 1;
    +}
    +
    +static int
    +termp_in_pre(DECL_ARGS)
    +{
    +
    +	synopsis_pre(p, n);
    +
    +	if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags) {
    +		term_fontpush(p, TERMFONT_BOLD);
    +		term_word(p, "#include");
    +		term_word(p, "<");
    +	} else {
    +		term_word(p, "<");
    +		term_fontpush(p, TERMFONT_UNDER);
    +	}
    +
    +	p->flags |= TERMP_NOSPACE;
    +	return 1;
    +}
    +
    +static void
    +termp_in_post(DECL_ARGS)
    +{
    +
    +	if (NODE_SYNPRETTY & n->flags)
    +		term_fontpush(p, TERMFONT_BOLD);
    +
    +	p->flags |= TERMP_NOSPACE;
    +	term_word(p, ">");
    +
    +	if (NODE_SYNPRETTY & n->flags)
    +		term_fontpop(p);
    +}
    +
    +static int
    +termp_pp_pre(DECL_ARGS)
    +{
    +	fn_prio = 0;
    +	term_vspace(p);
    +	return 0;
    +}
    +
    +static int
    +termp_skip_pre(DECL_ARGS)
    +{
    +
    +	return 0;
    +}
    +
    +static int
    +termp_quote_pre(DECL_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
    +		return 1;
    +
    +	switch (n->tok) {
    +	case MDOC_Ao:
    +	case MDOC_Aq:
    +		term_word(p, n->child != NULL && n->child->next == NULL &&
    +		    n->child->tok == MDOC_Mt ? "<" : "\\(la");
    +		break;
    +	case MDOC_Bro:
    +	case MDOC_Brq:
    +		term_word(p, "{");
    +		break;
    +	case MDOC_Oo:
    +	case MDOC_Op:
    +	case MDOC_Bo:
    +	case MDOC_Bq:
    +		term_word(p, "[");
    +		break;
    +	case MDOC__T:
    +		/* FALLTHROUGH */
    +	case MDOC_Do:
    +	case MDOC_Dq:
    +		term_word(p, "\\(lq");
    +		break;
    +	case MDOC_En:
    +		if (NULL == n->norm->Es ||
    +		    NULL == n->norm->Es->child)
    +			return 1;
    +		term_word(p, n->norm->Es->child->string);
    +		break;
    +	case MDOC_Po:
    +	case MDOC_Pq:
    +		term_word(p, "(");
    +		break;
    +	case MDOC_Qo:
    +	case MDOC_Qq:
    +		term_word(p, "\"");
    +		break;
    +	case MDOC_Ql:
    +	case MDOC_So:
    +	case MDOC_Sq:
    +		term_word(p, "\\(oq");
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	p->flags |= TERMP_NOSPACE;
    +	return 1;
    +}
    +
    +static void
    +termp_quote_post(DECL_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
    +		return;
    +
    +	p->flags |= TERMP_NOSPACE;
    +
    +	switch (n->tok) {
    +	case MDOC_Ao:
    +	case MDOC_Aq:
    +		term_word(p, n->child != NULL && n->child->next == NULL &&
    +		    n->child->tok == MDOC_Mt ? ">" : "\\(ra");
    +		break;
    +	case MDOC_Bro:
    +	case MDOC_Brq:
    +		term_word(p, "}");
    +		break;
    +	case MDOC_Oo:
    +	case MDOC_Op:
    +	case MDOC_Bo:
    +	case MDOC_Bq:
    +		term_word(p, "]");
    +		break;
    +	case MDOC__T:
    +		/* FALLTHROUGH */
    +	case MDOC_Do:
    +	case MDOC_Dq:
    +		term_word(p, "\\(rq");
    +		break;
    +	case MDOC_En:
    +		if (n->norm->Es == NULL ||
    +		    n->norm->Es->child == NULL ||
    +		    n->norm->Es->child->next == NULL)
    +			p->flags &= ~TERMP_NOSPACE;
    +		else
    +			term_word(p, n->norm->Es->child->next->string);
    +		break;
    +	case MDOC_Po:
    +	case MDOC_Pq:
    +		term_word(p, ")");
    +		break;
    +	case MDOC_Qo:
    +	case MDOC_Qq:
    +		term_word(p, "\"");
    +		break;
    +	case MDOC_Ql:
    +	case MDOC_So:
    +	case MDOC_Sq:
    +		term_word(p, "\\(cq");
    +		break;
    +	default:
    +		abort();
    +	}
    +}
    +
    +static int
    +termp_eo_pre(DECL_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BODY)
    +		return 1;
    +
    +	if (n->end == ENDBODY_NOT &&
    +	    n->parent->head->child == NULL &&
    +	    n->child != NULL &&
    +	    n->child->end != ENDBODY_NOT)
    +		term_word(p, "\\&");
    +	else if (n->end != ENDBODY_NOT ? n->child != NULL :
    +	     n->parent->head->child != NULL && (n->child != NULL ||
    +	     (n->parent->tail != NULL && n->parent->tail->child != NULL)))
    +		p->flags |= TERMP_NOSPACE;
    +
    +	return 1;
    +}
    +
    +static void
    +termp_eo_post(DECL_ARGS)
    +{
    +	int	 body, tail;
    +
    +	if (n->type != ROFFT_BODY)
    +		return;
    +
    +	if (n->end != ENDBODY_NOT) {
    +		p->flags &= ~TERMP_NOSPACE;
    +		return;
    +	}
    +
    +	body = n->child != NULL || n->parent->head->child != NULL;
    +	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
    +
    +	if (body && tail)
    +		p->flags |= TERMP_NOSPACE;
    +	else if ( ! (body || tail))
    +		term_word(p, "\\&");
    +	else if ( ! tail)
    +		p->flags &= ~TERMP_NOSPACE;
    +}
    +
    +static int
    +termp_fo_pre(DECL_ARGS)
    +{
    +	size_t		 rmargin = 0;
    +	int		 pretty;
    +
    +	pretty = NODE_SYNPRETTY & n->flags;
    +
    +	if (n->type == ROFFT_BLOCK) {
    +		synopsis_pre(p, n);
    +		return 1;
    +	} else if (n->type == ROFFT_BODY) {
    +		if (pretty) {
    +			rmargin = p->tcol->rmargin;
    +			p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
    +			p->flags |= TERMP_NOBREAK | TERMP_BRIND |
    +					TERMP_HANG;
    +		}
    +		p->flags |= TERMP_NOSPACE;
    +		term_word(p, "(");
    +		p->flags |= TERMP_NOSPACE;
    +		if (pretty) {
    +			term_flushln(p);
    +			p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
    +					TERMP_HANG);
    +			p->flags |= TERMP_NOPAD;
    +			p->tcol->offset = p->tcol->rmargin;
    +			p->tcol->rmargin = rmargin;
    +		}
    +		return 1;
    +	}
    +
    +	if (NULL == n->child)
    +		return 0;
    +
    +	/* XXX: we drop non-initial arguments as per groff. */
    +
    +	assert(n->child->string);
    +	term_fontpush(p, TERMFONT_BOLD);
    +	term_word(p, n->child->string);
    +	return 0;
    +}
    +
    +static void
    +termp_fo_post(DECL_ARGS)
    +{
    +
    +	if (n->type != ROFFT_BODY)
    +		return;
    +
    +	p->flags |= TERMP_NOSPACE;
    +	term_word(p, ")");
    +
    +	if (NODE_SYNPRETTY & n->flags) {
    +		p->flags |= TERMP_NOSPACE;
    +		term_word(p, ";");
    +		term_flushln(p);
    +	}
    +}
    +
    +static int
    +termp_bf_pre(DECL_ARGS)
    +{
    +
    +	if (n->type == ROFFT_HEAD)
    +		return 0;
    +	else if (n->type != ROFFT_BODY)
    +		return 1;
    +
    +	if (FONT_Em == n->norm->Bf.font)
    +		term_fontpush(p, TERMFONT_UNDER);
    +	else if (FONT_Sy == n->norm->Bf.font)
    +		term_fontpush(p, TERMFONT_BOLD);
    +	else
    +		term_fontpush(p, TERMFONT_NONE);
    +
    +	return 1;
    +}
    +
    +static int
    +termp_sm_pre(DECL_ARGS)
    +{
    +
    +	if (NULL == n->child)
    +		p->flags ^= TERMP_NONOSPACE;
    +	else if (0 == strcmp("on", n->child->string))
    +		p->flags &= ~TERMP_NONOSPACE;
    +	else
    +		p->flags |= TERMP_NONOSPACE;
    +
    +	if (p->col && ! (TERMP_NONOSPACE & p->flags))
    +		p->flags &= ~TERMP_NOSPACE;
    +
    +	return 0;
    +}
    +
    +static int
    +termp_ap_pre(DECL_ARGS)
    +{
    +
    +	p->flags |= TERMP_NOSPACE;
    +	term_word(p, "'");
    +	p->flags |= TERMP_NOSPACE;
    +	return 1;
    +}
    +
    +static void
    +termp____post(DECL_ARGS)
    +{
    +
    +	/*
    +	 * Handle lists of authors.  In general, print each followed by
    +	 * a comma.  Don't print the comma if there are only two
    +	 * authors.
    +	 */
    +	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
    +		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
    +			if (NULL == n->prev || MDOC__A != n->prev->tok)
    +				return;
    +
    +	/* TODO: %U. */
    +
    +	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
    +		return;
    +
    +	p->flags |= TERMP_NOSPACE;
    +	if (NULL == n->next) {
    +		term_word(p, ".");
    +		p->flags |= TERMP_SENTENCE;
    +	} else
    +		term_word(p, ",");
    +}
    +
    +static int
    +termp_li_pre(DECL_ARGS)
    +{
    +
    +	termp_tag_pre(p, pair, meta, n);
    +	term_fontpush(p, TERMFONT_NONE);
    +	return 1;
    +}
    +
    +static int
    +termp_lk_pre(DECL_ARGS)
    +{
    +	const struct roff_node *link, *descr, *punct;
    +
    +	if ((link = n->child) == NULL)
    +		return 0;
    +
    +	/* Find beginning of trailing punctuation. */
    +	punct = n->last;
    +	while (punct != link && punct->flags & NODE_DELIMC)
    +		punct = punct->prev;
    +	punct = punct->next;
    +
    +	/* Link text. */
    +	if ((descr = link->next) != NULL && descr != punct) {
    +		term_fontpush(p, TERMFONT_UNDER);
    +		while (descr != punct) {
    +			if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
    +				p->flags |= TERMP_NOSPACE;
    +			term_word(p, descr->string);
    +			descr = descr->next;
    +		}
    +		term_fontpop(p);
    +		p->flags |= TERMP_NOSPACE;
    +		term_word(p, ":");
    +	}
    +
    +	/* Link target. */
    +	term_fontpush(p, TERMFONT_BOLD);
    +	term_word(p, link->string);
    +	term_fontpop(p);
    +
    +	/* Trailing punctuation. */
    +	while (punct != NULL) {
    +		p->flags |= TERMP_NOSPACE;
    +		term_word(p, punct->string);
    +		punct = punct->next;
    +	}
    +	return 0;
    +}
    +
    +static int
    +termp_bk_pre(DECL_ARGS)
    +{
    +
    +	switch (n->type) {
    +	case ROFFT_BLOCK:
    +		break;
    +	case ROFFT_HEAD:
    +		return 0;
    +	case ROFFT_BODY:
    +		if (n->parent->args != NULL || n->prev->child == NULL)
    +			p->flags |= TERMP_PREKEEP;
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	return 1;
    +}
    +
    +static void
    +termp_bk_post(DECL_ARGS)
    +{
    +
    +	if (n->type == ROFFT_BODY)
    +		p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
    +}
    +
    +static void
    +termp__t_post(DECL_ARGS)
    +{
    +
    +	/*
    +	 * If we're in an `Rs' and there's a journal present, then quote
    +	 * us instead of underlining us (for disambiguation).
    +	 */
    +	if (n->parent && MDOC_Rs == n->parent->tok &&
    +	    n->parent->norm->Rs.quote_T)
    +		termp_quote_post(p, pair, meta, n);
    +
    +	termp____post(p, pair, meta, n);
    +}
    +
    +static int
    +termp__t_pre(DECL_ARGS)
    +{
    +
    +	/*
    +	 * If we're in an `Rs' and there's a journal present, then quote
    +	 * us instead of underlining us (for disambiguation).
    +	 */
    +	if (n->parent && MDOC_Rs == n->parent->tok &&
    +	    n->parent->norm->Rs.quote_T)
    +		return termp_quote_pre(p, pair, meta, n);
    +
    +	term_fontpush(p, TERMFONT_UNDER);
    +	return 1;
    +}
    +
    +static int
    +termp_under_pre(DECL_ARGS)
    +{
    +
    +	term_fontpush(p, TERMFONT_UNDER);
    +	return 1;
    +}
    +
    +static int
    +termp_em_pre(DECL_ARGS)
    +{
    +	if (n->child != NULL &&
    +	    n->child->type == ROFFT_TEXT)
    +		tag_put(n->child->string, 0, p->line);
    +	term_fontpush(p, TERMFONT_UNDER);
    +	return 1;
    +}
    +
    +static int
    +termp_sy_pre(DECL_ARGS)
    +{
    +	if (n->child != NULL &&
    +	    n->child->type == ROFFT_TEXT)
    +		tag_put(n->child->string, 0, p->line);
    +	term_fontpush(p, TERMFONT_BOLD);
    +	return 1;
    +}
    +
    +static int
    +termp_er_pre(DECL_ARGS)
    +{
    +
    +	if (n->sec == SEC_ERRORS &&
    +	    (n->parent->tok == MDOC_It ||
    +	     (n->parent->tok == MDOC_Bq &&
    +	      n->parent->parent->parent->tok == MDOC_It)))
    +		tag_put(n->child->string, 1, p->line);
    +	return 1;
    +}
    +
    +static int
    +termp_tag_pre(DECL_ARGS)
    +{
    +
    +	if (n->child != NULL &&
    +	    n->child->type == ROFFT_TEXT &&
    +	    (n->prev == NULL ||
    +	     (n->prev->type == ROFFT_TEXT &&
    +	      strcmp(n->prev->string, "|") == 0)) &&
    +	    (n->parent->tok == MDOC_It ||
    +	     (n->parent->tok == MDOC_Xo &&
    +	      n->parent->parent->prev == NULL &&
    +	      n->parent->parent->parent->tok == MDOC_It)))
    +		tag_put(n->child->string, 1, p->line);
    +	return 1;
    +}
    
    Property changes on: head/contrib/mandoc/mdoc_term.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc_validate.c
    ===================================================================
    --- head/contrib/mandoc/mdoc_validate.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc_validate.c	(revision 338826)
    @@ -0,0 +1,2968 @@
    +/*	$Id: mdoc_validate.c,v 1.360 2018/08/01 16:00:58 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * 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 <sys/types.h>
    +#ifndef OSNAME
    +#include <sys/utsname.h>
    +#endif
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "mandoc_xr.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "libmandoc.h"
    +#include "roff_int.h"
    +#include "libmdoc.h"
    +
    +/* FIXME: .Bl -diag can't have non-text children in HEAD. */
    +
    +#define	POST_ARGS struct roff_man *mdoc
    +
    +enum	check_ineq {
    +	CHECK_LT,
    +	CHECK_GT,
    +	CHECK_EQ
    +};
    +
    +typedef	void	(*v_post)(POST_ARGS);
    +
    +static	int	 build_list(struct roff_man *, int);
    +static	void	 check_argv(struct roff_man *,
    +			struct roff_node *, struct mdoc_argv *);
    +static	void	 check_args(struct roff_man *, struct roff_node *);
    +static	void	 check_text(struct roff_man *, int, int, char *);
    +static	void	 check_text_em(struct roff_man *, int, int, char *);
    +static	void	 check_toptext(struct roff_man *, int, int, const char *);
    +static	int	 child_an(const struct roff_node *);
    +static	size_t		macro2len(enum roff_tok);
    +static	void	 rewrite_macro2len(struct roff_man *, char **);
    +static	int	 similar(const char *, const char *);
    +
    +static	void	 post_an(POST_ARGS);
    +static	void	 post_an_norm(POST_ARGS);
    +static	void	 post_at(POST_ARGS);
    +static	void	 post_bd(POST_ARGS);
    +static	void	 post_bf(POST_ARGS);
    +static	void	 post_bk(POST_ARGS);
    +static	void	 post_bl(POST_ARGS);
    +static	void	 post_bl_block(POST_ARGS);
    +static	void	 post_bl_head(POST_ARGS);
    +static	void	 post_bl_norm(POST_ARGS);
    +static	void	 post_bx(POST_ARGS);
    +static	void	 post_defaults(POST_ARGS);
    +static	void	 post_display(POST_ARGS);
    +static	void	 post_dd(POST_ARGS);
    +static	void	 post_delim(POST_ARGS);
    +static	void	 post_delim_nb(POST_ARGS);
    +static	void	 post_dt(POST_ARGS);
    +static	void	 post_en(POST_ARGS);
    +static	void	 post_es(POST_ARGS);
    +static	void	 post_eoln(POST_ARGS);
    +static	void	 post_ex(POST_ARGS);
    +static	void	 post_fa(POST_ARGS);
    +static	void	 post_fn(POST_ARGS);
    +static	void	 post_fname(POST_ARGS);
    +static	void	 post_fo(POST_ARGS);
    +static	void	 post_hyph(POST_ARGS);
    +static	void	 post_ignpar(POST_ARGS);
    +static	void	 post_it(POST_ARGS);
    +static	void	 post_lb(POST_ARGS);
    +static	void	 post_nd(POST_ARGS);
    +static	void	 post_nm(POST_ARGS);
    +static	void	 post_ns(POST_ARGS);
    +static	void	 post_obsolete(POST_ARGS);
    +static	void	 post_os(POST_ARGS);
    +static	void	 post_par(POST_ARGS);
    +static	void	 post_prevpar(POST_ARGS);
    +static	void	 post_root(POST_ARGS);
    +static	void	 post_rs(POST_ARGS);
    +static	void	 post_rv(POST_ARGS);
    +static	void	 post_sh(POST_ARGS);
    +static	void	 post_sh_head(POST_ARGS);
    +static	void	 post_sh_name(POST_ARGS);
    +static	void	 post_sh_see_also(POST_ARGS);
    +static	void	 post_sh_authors(POST_ARGS);
    +static	void	 post_sm(POST_ARGS);
    +static	void	 post_st(POST_ARGS);
    +static	void	 post_std(POST_ARGS);
    +static	void	 post_sx(POST_ARGS);
    +static	void	 post_useless(POST_ARGS);
    +static	void	 post_xr(POST_ARGS);
    +static	void	 post_xx(POST_ARGS);
    +
    +static	const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
    +	post_dd,	/* Dd */
    +	post_dt,	/* Dt */
    +	post_os,	/* Os */
    +	post_sh,	/* Sh */
    +	post_ignpar,	/* Ss */
    +	post_par,	/* Pp */
    +	post_display,	/* D1 */
    +	post_display,	/* Dl */
    +	post_display,	/* Bd */
    +	NULL,		/* Ed */
    +	post_bl,	/* Bl */
    +	NULL,		/* El */
    +	post_it,	/* It */
    +	post_delim_nb,	/* Ad */
    +	post_an,	/* An */
    +	NULL,		/* Ap */
    +	post_defaults,	/* Ar */
    +	NULL,		/* Cd */
    +	post_delim_nb,	/* Cm */
    +	post_delim_nb,	/* Dv */
    +	post_delim_nb,	/* Er */
    +	post_delim_nb,	/* Ev */
    +	post_ex,	/* Ex */
    +	post_fa,	/* Fa */
    +	NULL,		/* Fd */
    +	post_delim_nb,	/* Fl */
    +	post_fn,	/* Fn */
    +	post_delim_nb,	/* Ft */
    +	post_delim_nb,	/* Ic */
    +	post_delim_nb,	/* In */
    +	post_defaults,	/* Li */
    +	post_nd,	/* Nd */
    +	post_nm,	/* Nm */
    +	post_delim_nb,	/* Op */
    +	post_obsolete,	/* Ot */
    +	post_defaults,	/* Pa */
    +	post_rv,	/* Rv */
    +	post_st,	/* St */
    +	post_delim_nb,	/* Va */
    +	post_delim_nb,	/* Vt */
    +	post_xr,	/* Xr */
    +	NULL,		/* %A */
    +	post_hyph,	/* %B */ /* FIXME: can be used outside Rs/Re. */
    +	NULL,		/* %D */
    +	NULL,		/* %I */
    +	NULL,		/* %J */
    +	post_hyph,	/* %N */
    +	post_hyph,	/* %O */
    +	NULL,		/* %P */
    +	post_hyph,	/* %R */
    +	post_hyph,	/* %T */ /* FIXME: can be used outside Rs/Re. */
    +	NULL,		/* %V */
    +	NULL,		/* Ac */
    +	NULL,		/* Ao */
    +	post_delim_nb,	/* Aq */
    +	post_at,	/* At */
    +	NULL,		/* Bc */
    +	post_bf,	/* Bf */
    +	NULL,		/* Bo */
    +	NULL,		/* Bq */
    +	post_xx,	/* Bsx */
    +	post_bx,	/* Bx */
    +	post_obsolete,	/* Db */
    +	NULL,		/* Dc */
    +	NULL,		/* Do */
    +	NULL,		/* Dq */
    +	NULL,		/* Ec */
    +	NULL,		/* Ef */
    +	post_delim_nb,	/* Em */
    +	NULL,		/* Eo */
    +	post_xx,	/* Fx */
    +	post_delim_nb,	/* Ms */
    +	NULL,		/* No */
    +	post_ns,	/* Ns */
    +	post_xx,	/* Nx */
    +	post_xx,	/* Ox */
    +	NULL,		/* Pc */
    +	NULL,		/* Pf */
    +	NULL,		/* Po */
    +	post_delim_nb,	/* Pq */
    +	NULL,		/* Qc */
    +	post_delim_nb,	/* Ql */
    +	NULL,		/* Qo */
    +	post_delim_nb,	/* Qq */
    +	NULL,		/* Re */
    +	post_rs,	/* Rs */
    +	NULL,		/* Sc */
    +	NULL,		/* So */
    +	post_delim_nb,	/* Sq */
    +	post_sm,	/* Sm */
    +	post_sx,	/* Sx */
    +	post_delim_nb,	/* Sy */
    +	post_useless,	/* Tn */
    +	post_xx,	/* Ux */
    +	NULL,		/* Xc */
    +	NULL,		/* Xo */
    +	post_fo,	/* Fo */
    +	NULL,		/* Fc */
    +	NULL,		/* Oo */
    +	NULL,		/* Oc */
    +	post_bk,	/* Bk */
    +	NULL,		/* Ek */
    +	post_eoln,	/* Bt */
    +	post_obsolete,	/* Hf */
    +	post_obsolete,	/* Fr */
    +	post_eoln,	/* Ud */
    +	post_lb,	/* Lb */
    +	post_par,	/* Lp */
    +	post_delim_nb,	/* Lk */
    +	post_defaults,	/* Mt */
    +	post_delim_nb,	/* Brq */
    +	NULL,		/* Bro */
    +	NULL,		/* Brc */
    +	NULL,		/* %C */
    +	post_es,	/* Es */
    +	post_en,	/* En */
    +	post_xx,	/* Dx */
    +	NULL,		/* %Q */
    +	NULL,		/* %U */
    +	NULL,		/* Ta */
    +};
    +static	const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd;
    +
    +#define	RSORD_MAX 14 /* Number of `Rs' blocks. */
    +
    +static	const enum roff_tok rsord[RSORD_MAX] = {
    +	MDOC__A,
    +	MDOC__T,
    +	MDOC__B,
    +	MDOC__I,
    +	MDOC__J,
    +	MDOC__R,
    +	MDOC__N,
    +	MDOC__V,
    +	MDOC__U,
    +	MDOC__P,
    +	MDOC__Q,
    +	MDOC__C,
    +	MDOC__D,
    +	MDOC__O
    +};
    +
    +static	const char * const secnames[SEC__MAX] = {
    +	NULL,
    +	"NAME",
    +	"LIBRARY",
    +	"SYNOPSIS",
    +	"DESCRIPTION",
    +	"CONTEXT",
    +	"IMPLEMENTATION NOTES",
    +	"RETURN VALUES",
    +	"ENVIRONMENT",
    +	"FILES",
    +	"EXIT STATUS",
    +	"EXAMPLES",
    +	"DIAGNOSTICS",
    +	"COMPATIBILITY",
    +	"ERRORS",
    +	"SEE ALSO",
    +	"STANDARDS",
    +	"HISTORY",
    +	"AUTHORS",
    +	"CAVEATS",
    +	"BUGS",
    +	"SECURITY CONSIDERATIONS",
    +	NULL
    +};
    +
    +
    +void
    +mdoc_node_validate(struct roff_man *mdoc)
    +{
    +	struct roff_node *n, *np;
    +	const v_post *p;
    +
    +	n = mdoc->last;
    +	mdoc->last = mdoc->last->child;
    +	while (mdoc->last != NULL) {
    +		mdoc_node_validate(mdoc);
    +		if (mdoc->last == n)
    +			mdoc->last = mdoc->last->child;
    +		else
    +			mdoc->last = mdoc->last->next;
    +	}
    +
    +	mdoc->last = n;
    +	mdoc->next = ROFF_NEXT_SIBLING;
    +	switch (n->type) {
    +	case ROFFT_TEXT:
    +		np = n->parent;
    +		if (n->sec != SEC_SYNOPSIS ||
    +		    (np->tok != MDOC_Cd && np->tok != MDOC_Fd))
    +			check_text(mdoc, n->line, n->pos, n->string);
    +		if (np->tok != MDOC_Ql && np->tok != MDOC_Dl &&
    +		    (np->tok != MDOC_Bd ||
    +		     (mdoc->flags & MDOC_LITERAL) == 0) &&
    +		    (np->tok != MDOC_It || np->type != ROFFT_HEAD ||
    +		     np->parent->parent->norm->Bl.type != LIST_diag))
    +			check_text_em(mdoc, n->line, n->pos, n->string);
    +		if (np->tok == MDOC_It || (np->type == ROFFT_BODY &&
    +		    (np->tok == MDOC_Sh || np->tok == MDOC_Ss)))
    +			check_toptext(mdoc, n->line, n->pos, n->string);
    +		break;
    +	case ROFFT_COMMENT:
    +	case ROFFT_EQN:
    +	case ROFFT_TBL:
    +		break;
    +	case ROFFT_ROOT:
    +		post_root(mdoc);
    +		break;
    +	default:
    +		check_args(mdoc, mdoc->last);
    +
    +		/*
    +		 * Closing delimiters are not special at the
    +		 * beginning of a block, opening delimiters
    +		 * are not special at the end.
    +		 */
    +
    +		if (n->child != NULL)
    +			n->child->flags &= ~NODE_DELIMC;
    +		if (n->last != NULL)
    +			n->last->flags &= ~NODE_DELIMO;
    +
    +		/* Call the macro's postprocessor. */
    +
    +		if (n->tok < ROFF_MAX) {
    +			switch(n->tok) {
    +			case ROFF_br:
    +			case ROFF_sp:
    +				post_par(mdoc);
    +				break;
    +			default:
    +				roff_validate(mdoc);
    +				break;
    +			}
    +			break;
    +		}
    +
    +		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
    +		p = mdoc_valids + n->tok;
    +		if (*p)
    +			(*p)(mdoc);
    +		if (mdoc->last == n)
    +			mdoc_state(mdoc, n);
    +		break;
    +	}
    +}
    +
    +static void
    +check_args(struct roff_man *mdoc, struct roff_node *n)
    +{
    +	int		 i;
    +
    +	if (NULL == n->args)
    +		return;
    +
    +	assert(n->args->argc);
    +	for (i = 0; i < (int)n->args->argc; i++)
    +		check_argv(mdoc, n, &n->args->argv[i]);
    +}
    +
    +static void
    +check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v)
    +{
    +	int		 i;
    +
    +	for (i = 0; i < (int)v->sz; i++)
    +		check_text(mdoc, v->line, v->pos, v->value[i]);
    +}
    +
    +static void
    +check_text(struct roff_man *mdoc, int ln, int pos, char *p)
    +{
    +	char		*cp;
    +
    +	if (MDOC_LITERAL & mdoc->flags)
    +		return;
    +
    +	for (cp = p; NULL != (p = strchr(p, '\t')); p++)
    +		mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse,
    +		    ln, pos + (int)(p - cp), NULL);
    +}
    +
    +static void
    +check_text_em(struct roff_man *mdoc, int ln, int pos, char *p)
    +{
    +	const struct roff_node	*np, *nn;
    +	char			*cp;
    +
    +	np = mdoc->last->prev;
    +	nn = mdoc->last->next;
    +
    +	/* Look for em-dashes wrongly encoded as "--". */
    +
    +	for (cp = p; *cp != '\0'; cp++) {
    +		if (cp[0] != '-' || cp[1] != '-')
    +			continue;
    +		cp++;
    +
    +		/* Skip input sequences of more than two '-'. */
    +
    +		if (cp[1] == '-') {
    +			while (cp[1] == '-')
    +				cp++;
    +			continue;
    +		}
    +
    +		/* Skip "--" directly attached to something else. */
    +
    +		if ((cp - p > 1 && cp[-2] != ' ') ||
    +		    (cp[1] != '\0' && cp[1] != ' '))
    +			continue;
    +
    +		/* Require a letter right before or right afterwards. */
    +
    +		if ((cp - p > 2 ?
    +		     isalpha((unsigned char)cp[-3]) :
    +		     np != NULL &&
    +		     np->type == ROFFT_TEXT &&
    +		     *np->string != '\0' &&
    +		     isalpha((unsigned char)np->string[
    +		       strlen(np->string) - 1])) ||
    +		    (cp[1] != '\0' && cp[2] != '\0' ?
    +		     isalpha((unsigned char)cp[2]) :
    +		     nn != NULL &&
    +		     nn->type == ROFFT_TEXT &&
    +		     isalpha((unsigned char)*nn->string))) {
    +			mandoc_msg(MANDOCERR_DASHDASH, mdoc->parse,
    +			    ln, pos + (int)(cp - p) - 1, NULL);
    +			break;
    +		}
    +	}
    +}
    +
    +static void
    +check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p)
    +{
    +	const char	*cp, *cpr;
    +
    +	if (*p == '\0')
    +		return;
    +
    +	if ((cp = strstr(p, "OpenBSD")) != NULL)
    +		mandoc_msg(MANDOCERR_BX, mdoc->parse,
    +		    ln, pos + (cp - p), "Ox");
    +	if ((cp = strstr(p, "NetBSD")) != NULL)
    +		mandoc_msg(MANDOCERR_BX, mdoc->parse,
    +		    ln, pos + (cp - p), "Nx");
    +	if ((cp = strstr(p, "FreeBSD")) != NULL)
    +		mandoc_msg(MANDOCERR_BX, mdoc->parse,
    +		    ln, pos + (cp - p), "Fx");
    +	if ((cp = strstr(p, "DragonFly")) != NULL)
    +		mandoc_msg(MANDOCERR_BX, mdoc->parse,
    +		    ln, pos + (cp - p), "Dx");
    +
    +	cp = p;
    +	while ((cp = strstr(cp + 1, "()")) != NULL) {
    +		for (cpr = cp - 1; cpr >= p; cpr--)
    +			if (*cpr != '_' && !isalnum((unsigned char)*cpr))
    +				break;
    +		if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) {
    +			cpr++;
    +			mandoc_vmsg(MANDOCERR_FUNC, mdoc->parse,
    +			    ln, pos + (cpr - p),
    +			    "%.*s()", (int)(cp - cpr), cpr);
    +		}
    +	}
    +}
    +
    +static void
    +post_delim(POST_ARGS)
    +{
    +	const struct roff_node	*nch;
    +	const char		*lc;
    +	enum mdelim		 delim;
    +	enum roff_tok		 tok;
    +
    +	tok = mdoc->last->tok;
    +	nch = mdoc->last->last;
    +	if (nch == NULL || nch->type != ROFFT_TEXT)
    +		return;
    +	lc = strchr(nch->string, '\0') - 1;
    +	if (lc < nch->string)
    +		return;
    +	delim = mdoc_isdelim(lc);
    +	if (delim == DELIM_NONE || delim == DELIM_OPEN)
    +		return;
    +	if (*lc == ')' && (tok == MDOC_Nd || tok == MDOC_Sh ||
    +	    tok == MDOC_Ss || tok == MDOC_Fo))
    +		return;
    +
    +	mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse,
    +	    nch->line, nch->pos + (lc - nch->string),
    +	    "%s%s %s", roff_name[tok],
    +	    nch == mdoc->last->child ? "" : " ...", nch->string);
    +}
    +
    +static void
    +post_delim_nb(POST_ARGS)
    +{
    +	const struct roff_node	*nch;
    +	const char		*lc, *cp;
    +	int			 nw;
    +	enum mdelim		 delim;
    +	enum roff_tok		 tok;
    +
    +	/*
    +	 * Find candidates: at least two bytes,
    +	 * the last one a closing or middle delimiter.
    +	 */
    +
    +	tok = mdoc->last->tok;
    +	nch = mdoc->last->last;
    +	if (nch == NULL || nch->type != ROFFT_TEXT)
    +		return;
    +	lc = strchr(nch->string, '\0') - 1;
    +	if (lc <= nch->string)
    +		return;
    +	delim = mdoc_isdelim(lc);
    +	if (delim == DELIM_NONE || delim == DELIM_OPEN)
    +		return;
    +
    +	/*
    +	 * Reduce false positives by allowing various cases.
    +	 */
    +
    +	/* Escaped delimiters. */
    +	if (lc > nch->string + 1 && lc[-2] == '\\' &&
    +	    (lc[-1] == '&' || lc[-1] == 'e'))
    +		return;
    +
    +	/* Specific byte sequences. */
    +	switch (*lc) {
    +	case ')':
    +		for (cp = lc; cp >= nch->string; cp--)
    +			if (*cp == '(')
    +				return;
    +		break;
    +	case '.':
    +		if (lc > nch->string + 1 && lc[-2] == '.' && lc[-1] == '.')
    +			return;
    +		if (lc[-1] == '.')
    +			return;
    +		break;
    +	case ';':
    +		if (tok == MDOC_Vt)
    +			return;
    +		break;
    +	case '?':
    +		if (lc[-1] == '?')
    +			return;
    +		break;
    +	case ']':
    +		for (cp = lc; cp >= nch->string; cp--)
    +			if (*cp == '[')
    +				return;
    +		break;
    +	case '|':
    +		if (lc == nch->string + 1 && lc[-1] == '|')
    +			return;
    +	default:
    +		break;
    +	}
    +
    +	/* Exactly two non-alphanumeric bytes. */
    +	if (lc == nch->string + 1 && !isalnum((unsigned char)lc[-1]))
    +		return;
    +
    +	/* At least three alphabetic words with a sentence ending. */
    +	if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em ||
    +	    tok == MDOC_Li || tok == MDOC_Pq || tok == MDOC_Sy)) {
    +		nw = 0;
    +		for (cp = lc - 1; cp >= nch->string; cp--) {
    +			if (*cp == ' ') {
    +				nw++;
    +				if (cp > nch->string && cp[-1] == ',')
    +					cp--;
    +			} else if (isalpha((unsigned int)*cp)) {
    +				if (nw > 1)
    +					return;
    +			} else
    +				break;
    +		}
    +	}
    +
    +	mandoc_vmsg(MANDOCERR_DELIM_NB, mdoc->parse,
    +	    nch->line, nch->pos + (lc - nch->string),
    +	    "%s%s %s", roff_name[tok],
    +	    nch == mdoc->last->child ? "" : " ...", nch->string);
    +}
    +
    +static void
    +post_bl_norm(POST_ARGS)
    +{
    +	struct roff_node *n;
    +	struct mdoc_argv *argv, *wa;
    +	int		  i;
    +	enum mdocargt	  mdoclt;
    +	enum mdoc_list	  lt;
    +
    +	n = mdoc->last->parent;
    +	n->norm->Bl.type = LIST__NONE;
    +
    +	/*
    +	 * First figure out which kind of list to use: bind ourselves to
    +	 * the first mentioned list type and warn about any remaining
    +	 * ones.  If we find no list type, we default to LIST_item.
    +	 */
    +
    +	wa = (n->args == NULL) ? NULL : n->args->argv;
    +	mdoclt = MDOC_ARG_MAX;
    +	for (i = 0; n->args && i < (int)n->args->argc; i++) {
    +		argv = n->args->argv + i;
    +		lt = LIST__NONE;
    +		switch (argv->arg) {
    +		/* Set list types. */
    +		case MDOC_Bullet:
    +			lt = LIST_bullet;
    +			break;
    +		case MDOC_Dash:
    +			lt = LIST_dash;
    +			break;
    +		case MDOC_Enum:
    +			lt = LIST_enum;
    +			break;
    +		case MDOC_Hyphen:
    +			lt = LIST_hyphen;
    +			break;
    +		case MDOC_Item:
    +			lt = LIST_item;
    +			break;
    +		case MDOC_Tag:
    +			lt = LIST_tag;
    +			break;
    +		case MDOC_Diag:
    +			lt = LIST_diag;
    +			break;
    +		case MDOC_Hang:
    +			lt = LIST_hang;
    +			break;
    +		case MDOC_Ohang:
    +			lt = LIST_ohang;
    +			break;
    +		case MDOC_Inset:
    +			lt = LIST_inset;
    +			break;
    +		case MDOC_Column:
    +			lt = LIST_column;
    +			break;
    +		/* Set list arguments. */
    +		case MDOC_Compact:
    +			if (n->norm->Bl.comp)
    +				mandoc_msg(MANDOCERR_ARG_REP,
    +				    mdoc->parse, argv->line,
    +				    argv->pos, "Bl -compact");
    +			n->norm->Bl.comp = 1;
    +			break;
    +		case MDOC_Width:
    +			wa = argv;
    +			if (0 == argv->sz) {
    +				mandoc_msg(MANDOCERR_ARG_EMPTY,
    +				    mdoc->parse, argv->line,
    +				    argv->pos, "Bl -width");
    +				n->norm->Bl.width = "0n";
    +				break;
    +			}
    +			if (NULL != n->norm->Bl.width)
    +				mandoc_vmsg(MANDOCERR_ARG_REP,
    +				    mdoc->parse, argv->line,
    +				    argv->pos, "Bl -width %s",
    +				    argv->value[0]);
    +			rewrite_macro2len(mdoc, argv->value);
    +			n->norm->Bl.width = argv->value[0];
    +			break;
    +		case MDOC_Offset:
    +			if (0 == argv->sz) {
    +				mandoc_msg(MANDOCERR_ARG_EMPTY,
    +				    mdoc->parse, argv->line,
    +				    argv->pos, "Bl -offset");
    +				break;
    +			}
    +			if (NULL != n->norm->Bl.offs)
    +				mandoc_vmsg(MANDOCERR_ARG_REP,
    +				    mdoc->parse, argv->line,
    +				    argv->pos, "Bl -offset %s",
    +				    argv->value[0]);
    +			rewrite_macro2len(mdoc, argv->value);
    +			n->norm->Bl.offs = argv->value[0];
    +			break;
    +		default:
    +			continue;
    +		}
    +		if (LIST__NONE == lt)
    +			continue;
    +		mdoclt = argv->arg;
    +
    +		/* Check: multiple list types. */
    +
    +		if (LIST__NONE != n->norm->Bl.type) {
    +			mandoc_vmsg(MANDOCERR_BL_REP,
    +			    mdoc->parse, n->line, n->pos,
    +			    "Bl -%s", mdoc_argnames[argv->arg]);
    +			continue;
    +		}
    +
    +		/* The list type should come first. */
    +
    +		if (n->norm->Bl.width ||
    +		    n->norm->Bl.offs ||
    +		    n->norm->Bl.comp)
    +			mandoc_vmsg(MANDOCERR_BL_LATETYPE,
    +			    mdoc->parse, n->line, n->pos, "Bl -%s",
    +			    mdoc_argnames[n->args->argv[0].arg]);
    +
    +		n->norm->Bl.type = lt;
    +		if (LIST_column == lt) {
    +			n->norm->Bl.ncols = argv->sz;
    +			n->norm->Bl.cols = (void *)argv->value;
    +		}
    +	}
    +
    +	/* Allow lists to default to LIST_item. */
    +
    +	if (LIST__NONE == n->norm->Bl.type) {
    +		mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse,
    +		    n->line, n->pos, "Bl");
    +		n->norm->Bl.type = LIST_item;
    +		mdoclt = MDOC_Item;
    +	}
    +
    +	/*
    +	 * Validate the width field.  Some list types don't need width
    +	 * types and should be warned about them.  Others should have it
    +	 * and must also be warned.  Yet others have a default and need
    +	 * no warning.
    +	 */
    +
    +	switch (n->norm->Bl.type) {
    +	case LIST_tag:
    +		if (n->norm->Bl.width == NULL)
    +			mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse,
    +			    n->line, n->pos, "Bl -tag");
    +		break;
    +	case LIST_column:
    +	case LIST_diag:
    +	case LIST_ohang:
    +	case LIST_inset:
    +	case LIST_item:
    +		if (n->norm->Bl.width != NULL)
    +			mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse,
    +			    wa->line, wa->pos, "Bl -%s",
    +			    mdoc_argnames[mdoclt]);
    +		n->norm->Bl.width = NULL;
    +		break;
    +	case LIST_bullet:
    +	case LIST_dash:
    +	case LIST_hyphen:
    +		if (n->norm->Bl.width == NULL)
    +			n->norm->Bl.width = "2n";
    +		break;
    +	case LIST_enum:
    +		if (n->norm->Bl.width == NULL)
    +			n->norm->Bl.width = "3n";
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +post_bd(POST_ARGS)
    +{
    +	struct roff_node *n;
    +	struct mdoc_argv *argv;
    +	int		  i;
    +	enum mdoc_disp	  dt;
    +
    +	n = mdoc->last;
    +	for (i = 0; n->args && i < (int)n->args->argc; i++) {
    +		argv = n->args->argv + i;
    +		dt = DISP__NONE;
    +
    +		switch (argv->arg) {
    +		case MDOC_Centred:
    +			dt = DISP_centered;
    +			break;
    +		case MDOC_Ragged:
    +			dt = DISP_ragged;
    +			break;
    +		case MDOC_Unfilled:
    +			dt = DISP_unfilled;
    +			break;
    +		case MDOC_Filled:
    +			dt = DISP_filled;
    +			break;
    +		case MDOC_Literal:
    +			dt = DISP_literal;
    +			break;
    +		case MDOC_File:
    +			mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse,
    +			    n->line, n->pos, NULL);
    +			break;
    +		case MDOC_Offset:
    +			if (0 == argv->sz) {
    +				mandoc_msg(MANDOCERR_ARG_EMPTY,
    +				    mdoc->parse, argv->line,
    +				    argv->pos, "Bd -offset");
    +				break;
    +			}
    +			if (NULL != n->norm->Bd.offs)
    +				mandoc_vmsg(MANDOCERR_ARG_REP,
    +				    mdoc->parse, argv->line,
    +				    argv->pos, "Bd -offset %s",
    +				    argv->value[0]);
    +			rewrite_macro2len(mdoc, argv->value);
    +			n->norm->Bd.offs = argv->value[0];
    +			break;
    +		case MDOC_Compact:
    +			if (n->norm->Bd.comp)
    +				mandoc_msg(MANDOCERR_ARG_REP,
    +				    mdoc->parse, argv->line,
    +				    argv->pos, "Bd -compact");
    +			n->norm->Bd.comp = 1;
    +			break;
    +		default:
    +			abort();
    +		}
    +		if (DISP__NONE == dt)
    +			continue;
    +
    +		if (DISP__NONE == n->norm->Bd.type)
    +			n->norm->Bd.type = dt;
    +		else
    +			mandoc_vmsg(MANDOCERR_BD_REP,
    +			    mdoc->parse, n->line, n->pos,
    +			    "Bd -%s", mdoc_argnames[argv->arg]);
    +	}
    +
    +	if (DISP__NONE == n->norm->Bd.type) {
    +		mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse,
    +		    n->line, n->pos, "Bd");
    +		n->norm->Bd.type = DISP_ragged;
    +	}
    +}
    +
    +/*
    + * Stand-alone line macros.
    + */
    +
    +static void
    +post_an_norm(POST_ARGS)
    +{
    +	struct roff_node *n;
    +	struct mdoc_argv *argv;
    +	size_t	 i;
    +
    +	n = mdoc->last;
    +	if (n->args == NULL)
    +		return;
    +
    +	for (i = 1; i < n->args->argc; i++) {
    +		argv = n->args->argv + i;
    +		mandoc_vmsg(MANDOCERR_AN_REP,
    +		    mdoc->parse, argv->line, argv->pos,
    +		    "An -%s", mdoc_argnames[argv->arg]);
    +	}
    +
    +	argv = n->args->argv;
    +	if (argv->arg == MDOC_Split)
    +		n->norm->An.auth = AUTH_split;
    +	else if (argv->arg == MDOC_Nosplit)
    +		n->norm->An.auth = AUTH_nosplit;
    +	else
    +		abort();
    +}
    +
    +static void
    +post_eoln(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +
    +	post_useless(mdoc);
    +	n = mdoc->last;
    +	if (n->child != NULL)
    +		mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line,
    +		    n->pos, "%s %s", roff_name[n->tok], n->child->string);
    +
    +	while (n->child != NULL)
    +		roff_node_delete(mdoc, n->child);
    +
    +	roff_word_alloc(mdoc, n->line, n->pos, n->tok == MDOC_Bt ?
    +	    "is currently in beta test." : "currently under development.");
    +	mdoc->last->flags |= NODE_EOS | NODE_NOSRC;
    +	mdoc->last = n;
    +}
    +
    +static int
    +build_list(struct roff_man *mdoc, int tok)
    +{
    +	struct roff_node	*n;
    +	int			 ic;
    +
    +	n = mdoc->last->next;
    +	for (ic = 1;; ic++) {
    +		roff_elem_alloc(mdoc, n->line, n->pos, tok);
    +		mdoc->last->flags |= NODE_NOSRC;
    +		mdoc_node_relink(mdoc, n);
    +		n = mdoc->last = mdoc->last->parent;
    +		mdoc->next = ROFF_NEXT_SIBLING;
    +		if (n->next == NULL)
    +			return ic;
    +		if (ic > 1 || n->next->next != NULL) {
    +			roff_word_alloc(mdoc, n->line, n->pos, ",");
    +			mdoc->last->flags |= NODE_DELIMC | NODE_NOSRC;
    +		}
    +		n = mdoc->last->next;
    +		if (n->next == NULL) {
    +			roff_word_alloc(mdoc, n->line, n->pos, "and");
    +			mdoc->last->flags |= NODE_NOSRC;
    +		}
    +	}
    +}
    +
    +static void
    +post_ex(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +	int			 ic;
    +
    +	post_std(mdoc);
    +
    +	n = mdoc->last;
    +	mdoc->next = ROFF_NEXT_CHILD;
    +	roff_word_alloc(mdoc, n->line, n->pos, "The");
    +	mdoc->last->flags |= NODE_NOSRC;
    +
    +	if (mdoc->last->next != NULL)
    +		ic = build_list(mdoc, MDOC_Nm);
    +	else if (mdoc->meta.name != NULL) {
    +		roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Nm);
    +		mdoc->last->flags |= NODE_NOSRC;
    +		roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
    +		mdoc->last->flags |= NODE_NOSRC;
    +		mdoc->last = mdoc->last->parent;
    +		mdoc->next = ROFF_NEXT_SIBLING;
    +		ic = 1;
    +	} else {
    +		mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
    +		    n->line, n->pos, "Ex");
    +		ic = 0;
    +	}
    +
    +	roff_word_alloc(mdoc, n->line, n->pos,
    +	    ic > 1 ? "utilities exit\\~0" : "utility exits\\~0");
    +	mdoc->last->flags |= NODE_NOSRC;
    +	roff_word_alloc(mdoc, n->line, n->pos,
    +	    "on success, and\\~>0 if an error occurs.");
    +	mdoc->last->flags |= NODE_EOS | NODE_NOSRC;
    +	mdoc->last = n;
    +}
    +
    +static void
    +post_lb(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +	const char		*p;
    +
    +	post_delim_nb(mdoc);
    +
    +	n = mdoc->last;
    +	assert(n->child->type == ROFFT_TEXT);
    +	mdoc->next = ROFF_NEXT_CHILD;
    +
    +	if ((p = mdoc_a2lib(n->child->string)) != NULL) {
    +		n->child->flags |= NODE_NOPRT;
    +		roff_word_alloc(mdoc, n->line, n->pos, p);
    +		mdoc->last->flags = NODE_NOSRC;
    +		mdoc->last = n;
    +		return;
    +	}
    +
    +	mandoc_vmsg(MANDOCERR_LB_BAD, mdoc->parse, n->child->line,
    +	    n->child->pos, "Lb %s", n->child->string);
    +
    +	roff_word_alloc(mdoc, n->line, n->pos, "library");
    +	mdoc->last->flags = NODE_NOSRC;
    +	roff_word_alloc(mdoc, n->line, n->pos, "\\(lq");
    +	mdoc->last->flags = NODE_DELIMO | NODE_NOSRC;
    +	mdoc->last = mdoc->last->next;
    +	roff_word_alloc(mdoc, n->line, n->pos, "\\(rq");
    +	mdoc->last->flags = NODE_DELIMC | NODE_NOSRC;
    +	mdoc->last = n;
    +}
    +
    +static void
    +post_rv(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +	int			 ic;
    +
    +	post_std(mdoc);
    +
    +	n = mdoc->last;
    +	mdoc->next = ROFF_NEXT_CHILD;
    +	if (n->child != NULL) {
    +		roff_word_alloc(mdoc, n->line, n->pos, "The");
    +		mdoc->last->flags |= NODE_NOSRC;
    +		ic = build_list(mdoc, MDOC_Fn);
    +		roff_word_alloc(mdoc, n->line, n->pos,
    +		    ic > 1 ? "functions return" : "function returns");
    +		mdoc->last->flags |= NODE_NOSRC;
    +		roff_word_alloc(mdoc, n->line, n->pos,
    +		    "the value\\~0 if successful;");
    +	} else
    +		roff_word_alloc(mdoc, n->line, n->pos, "Upon successful "
    +		    "completion, the value\\~0 is returned;");
    +	mdoc->last->flags |= NODE_NOSRC;
    +
    +	roff_word_alloc(mdoc, n->line, n->pos, "otherwise "
    +	    "the value\\~\\-1 is returned and the global variable");
    +	mdoc->last->flags |= NODE_NOSRC;
    +	roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Va);
    +	mdoc->last->flags |= NODE_NOSRC;
    +	roff_word_alloc(mdoc, n->line, n->pos, "errno");
    +	mdoc->last->flags |= NODE_NOSRC;
    +	mdoc->last = mdoc->last->parent;
    +	mdoc->next = ROFF_NEXT_SIBLING;
    +	roff_word_alloc(mdoc, n->line, n->pos,
    +	    "is set to indicate the error.");
    +	mdoc->last->flags |= NODE_EOS | NODE_NOSRC;
    +	mdoc->last = n;
    +}
    +
    +static void
    +post_std(POST_ARGS)
    +{
    +	struct roff_node *n;
    +
    +	post_delim(mdoc);
    +
    +	n = mdoc->last;
    +	if (n->args && n->args->argc == 1)
    +		if (n->args->argv[0].arg == MDOC_Std)
    +			return;
    +
    +	mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
    +	    n->line, n->pos, roff_name[n->tok]);
    +}
    +
    +static void
    +post_st(POST_ARGS)
    +{
    +	struct roff_node	 *n, *nch;
    +	const char		 *p;
    +
    +	n = mdoc->last;
    +	nch = n->child;
    +	assert(nch->type == ROFFT_TEXT);
    +
    +	if ((p = mdoc_a2st(nch->string)) == NULL) {
    +		mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
    +		    nch->line, nch->pos, "St %s", nch->string);
    +		roff_node_delete(mdoc, n);
    +		return;
    +	}
    +
    +	nch->flags |= NODE_NOPRT;
    +	mdoc->next = ROFF_NEXT_CHILD;
    +	roff_word_alloc(mdoc, nch->line, nch->pos, p);
    +	mdoc->last->flags |= NODE_NOSRC;
    +	mdoc->last= n;
    +}
    +
    +static void
    +post_obsolete(POST_ARGS)
    +{
    +	struct roff_node *n;
    +
    +	n = mdoc->last;
    +	if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK)
    +		mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
    +		    n->line, n->pos, roff_name[n->tok]);
    +}
    +
    +static void
    +post_useless(POST_ARGS)
    +{
    +	struct roff_node *n;
    +
    +	n = mdoc->last;
    +	mandoc_msg(MANDOCERR_MACRO_USELESS, mdoc->parse,
    +	    n->line, n->pos, roff_name[n->tok]);
    +}
    +
    +/*
    + * Block macros.
    + */
    +
    +static void
    +post_bf(POST_ARGS)
    +{
    +	struct roff_node *np, *nch;
    +
    +	/*
    +	 * Unlike other data pointers, these are "housed" by the HEAD
    +	 * element, which contains the goods.
    +	 */
    +
    +	np = mdoc->last;
    +	if (np->type != ROFFT_HEAD)
    +		return;
    +
    +	assert(np->parent->type == ROFFT_BLOCK);
    +	assert(np->parent->tok == MDOC_Bf);
    +
    +	/* Check the number of arguments. */
    +
    +	nch = np->child;
    +	if (np->parent->args == NULL) {
    +		if (nch == NULL) {
    +			mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse,
    +			    np->line, np->pos, "Bf");
    +			return;
    +		}
    +		nch = nch->next;
    +	}
    +	if (nch != NULL)
    +		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
    +		    nch->line, nch->pos, "Bf ... %s", nch->string);
    +
    +	/* Extract argument into data. */
    +
    +	if (np->parent->args != NULL) {
    +		switch (np->parent->args->argv[0].arg) {
    +		case MDOC_Emphasis:
    +			np->norm->Bf.font = FONT_Em;
    +			break;
    +		case MDOC_Literal:
    +			np->norm->Bf.font = FONT_Li;
    +			break;
    +		case MDOC_Symbolic:
    +			np->norm->Bf.font = FONT_Sy;
    +			break;
    +		default:
    +			abort();
    +		}
    +		return;
    +	}
    +
    +	/* Extract parameter into data. */
    +
    +	if ( ! strcmp(np->child->string, "Em"))
    +		np->norm->Bf.font = FONT_Em;
    +	else if ( ! strcmp(np->child->string, "Li"))
    +		np->norm->Bf.font = FONT_Li;
    +	else if ( ! strcmp(np->child->string, "Sy"))
    +		np->norm->Bf.font = FONT_Sy;
    +	else
    +		mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse,
    +		    np->child->line, np->child->pos,
    +		    "Bf %s", np->child->string);
    +}
    +
    +static void
    +post_fname(POST_ARGS)
    +{
    +	const struct roff_node	*n;
    +	const char		*cp;
    +	size_t			 pos;
    +
    +	n = mdoc->last->child;
    +	pos = strcspn(n->string, "()");
    +	cp = n->string + pos;
    +	if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
    +		mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
    +		    n->line, n->pos + pos, n->string);
    +}
    +
    +static void
    +post_fn(POST_ARGS)
    +{
    +
    +	post_fname(mdoc);
    +	post_fa(mdoc);
    +}
    +
    +static void
    +post_fo(POST_ARGS)
    +{
    +	const struct roff_node	*n;
    +
    +	n = mdoc->last;
    +
    +	if (n->type != ROFFT_HEAD)
    +		return;
    +
    +	if (n->child == NULL) {
    +		mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse,
    +		    n->line, n->pos, "Fo");
    +		return;
    +	}
    +	if (n->child != n->last) {
    +		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
    +		    n->child->next->line, n->child->next->pos,
    +		    "Fo ... %s", n->child->next->string);
    +		while (n->child != n->last)
    +			roff_node_delete(mdoc, n->last);
    +	} else
    +		post_delim(mdoc);
    +
    +	post_fname(mdoc);
    +}
    +
    +static void
    +post_fa(POST_ARGS)
    +{
    +	const struct roff_node *n;
    +	const char *cp;
    +
    +	for (n = mdoc->last->child; n != NULL; n = n->next) {
    +		for (cp = n->string; *cp != '\0'; cp++) {
    +			/* Ignore callbacks and alterations. */
    +			if (*cp == '(' || *cp == '{')
    +				break;
    +			if (*cp != ',')
    +				continue;
    +			mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
    +			    n->line, n->pos + (cp - n->string),
    +			    n->string);
    +			break;
    +		}
    +	}
    +	post_delim_nb(mdoc);
    +}
    +
    +static void
    +post_nm(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +
    +	n = mdoc->last;
    +
    +	if (n->sec == SEC_NAME && n->child != NULL &&
    +	    n->child->type == ROFFT_TEXT && mdoc->meta.msec != NULL)
    +		mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1);
    +
    +	if (n->last != NULL &&
    +	    (n->last->tok == MDOC_Pp ||
    +	     n->last->tok == MDOC_Lp))
    +		mdoc_node_relink(mdoc, n->last);
    +
    +	if (mdoc->meta.name == NULL)
    +		deroff(&mdoc->meta.name, n);
    +
    +	if (mdoc->meta.name == NULL ||
    +	    (mdoc->lastsec == SEC_NAME && n->child == NULL))
    +		mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
    +		    n->line, n->pos, "Nm");
    +
    +	switch (n->type) {
    +	case ROFFT_ELEM:
    +		post_delim_nb(mdoc);
    +		break;
    +	case ROFFT_HEAD:
    +		post_delim(mdoc);
    +		break;
    +	default:
    +		return;
    +	}
    +
    +	if ((n->child != NULL && n->child->type == ROFFT_TEXT) ||
    +	    mdoc->meta.name == NULL)
    +		return;
    +
    +	mdoc->next = ROFF_NEXT_CHILD;
    +	roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
    +	mdoc->last->flags |= NODE_NOSRC;
    +	mdoc->last = n;
    +}
    +
    +static void
    +post_nd(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +
    +	n = mdoc->last;
    +
    +	if (n->type != ROFFT_BODY)
    +		return;
    +
    +	if (n->sec != SEC_NAME)
    +		mandoc_msg(MANDOCERR_ND_LATE, mdoc->parse,
    +		    n->line, n->pos, "Nd");
    +
    +	if (n->child == NULL)
    +		mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
    +		    n->line, n->pos, "Nd");
    +	else
    +		post_delim(mdoc);
    +
    +	post_hyph(mdoc);
    +}
    +
    +static void
    +post_display(POST_ARGS)
    +{
    +	struct roff_node *n, *np;
    +
    +	n = mdoc->last;
    +	switch (n->type) {
    +	case ROFFT_BODY:
    +		if (n->end != ENDBODY_NOT) {
    +			if (n->tok == MDOC_Bd &&
    +			    n->body->parent->args == NULL)
    +				roff_node_delete(mdoc, n);
    +		} else if (n->child == NULL)
    +			mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
    +			    n->line, n->pos, roff_name[n->tok]);
    +		else if (n->tok == MDOC_D1)
    +			post_hyph(mdoc);
    +		break;
    +	case ROFFT_BLOCK:
    +		if (n->tok == MDOC_Bd) {
    +			if (n->args == NULL) {
    +				mandoc_msg(MANDOCERR_BD_NOARG,
    +				    mdoc->parse, n->line, n->pos, "Bd");
    +				mdoc->next = ROFF_NEXT_SIBLING;
    +				while (n->body->child != NULL)
    +					mdoc_node_relink(mdoc,
    +					    n->body->child);
    +				roff_node_delete(mdoc, n);
    +				break;
    +			}
    +			post_bd(mdoc);
    +			post_prevpar(mdoc);
    +		}
    +		for (np = n->parent; np != NULL; np = np->parent) {
    +			if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) {
    +				mandoc_vmsg(MANDOCERR_BD_NEST,
    +				    mdoc->parse, n->line, n->pos,
    +				    "%s in Bd", roff_name[n->tok]);
    +				break;
    +			}
    +		}
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +post_defaults(POST_ARGS)
    +{
    +	struct roff_node *nn;
    +
    +	if (mdoc->last->child != NULL) {
    +		post_delim_nb(mdoc);
    +		return;
    +	}
    +
    +	/*
    +	 * The `Ar' defaults to "file ..." if no value is provided as an
    +	 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
    +	 * gets an empty string.
    +	 */
    +
    +	nn = mdoc->last;
    +	switch (nn->tok) {
    +	case MDOC_Ar:
    +		mdoc->next = ROFF_NEXT_CHILD;
    +		roff_word_alloc(mdoc, nn->line, nn->pos, "file");
    +		mdoc->last->flags |= NODE_NOSRC;
    +		roff_word_alloc(mdoc, nn->line, nn->pos, "...");
    +		mdoc->last->flags |= NODE_NOSRC;
    +		break;
    +	case MDOC_Pa:
    +	case MDOC_Mt:
    +		mdoc->next = ROFF_NEXT_CHILD;
    +		roff_word_alloc(mdoc, nn->line, nn->pos, "~");
    +		mdoc->last->flags |= NODE_NOSRC;
    +		break;
    +	default:
    +		abort();
    +	}
    +	mdoc->last = nn;
    +}
    +
    +static void
    +post_at(POST_ARGS)
    +{
    +	struct roff_node	*n, *nch;
    +	const char		*att;
    +
    +	n = mdoc->last;
    +	nch = n->child;
    +
    +	/*
    +	 * If we have a child, look it up in the standard keys.  If a
    +	 * key exist, use that instead of the child; if it doesn't,
    +	 * prefix "AT&T UNIX " to the existing data.
    +	 */
    +
    +	att = NULL;
    +	if (nch != NULL && ((att = mdoc_a2att(nch->string)) == NULL))
    +		mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
    +		    nch->line, nch->pos, "At %s", nch->string);
    +
    +	mdoc->next = ROFF_NEXT_CHILD;
    +	if (att != NULL) {
    +		roff_word_alloc(mdoc, nch->line, nch->pos, att);
    +		nch->flags |= NODE_NOPRT;
    +	} else
    +		roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX");
    +	mdoc->last->flags |= NODE_NOSRC;
    +	mdoc->last = n;
    +}
    +
    +static void
    +post_an(POST_ARGS)
    +{
    +	struct roff_node *np, *nch;
    +
    +	post_an_norm(mdoc);
    +
    +	np = mdoc->last;
    +	nch = np->child;
    +	if (np->norm->An.auth == AUTH__NONE) {
    +		if (nch == NULL)
    +			mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
    +			    np->line, np->pos, "An");
    +		else
    +			post_delim_nb(mdoc);
    +	} else if (nch != NULL)
    +		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
    +		    nch->line, nch->pos, "An ... %s", nch->string);
    +}
    +
    +static void
    +post_en(POST_ARGS)
    +{
    +
    +	post_obsolete(mdoc);
    +	if (mdoc->last->type == ROFFT_BLOCK)
    +		mdoc->last->norm->Es = mdoc->last_es;
    +}
    +
    +static void
    +post_es(POST_ARGS)
    +{
    +
    +	post_obsolete(mdoc);
    +	mdoc->last_es = mdoc->last;
    +}
    +
    +static void
    +post_xx(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +	const char		*os;
    +	char			*v;
    +
    +	post_delim_nb(mdoc);
    +
    +	n = mdoc->last;
    +	switch (n->tok) {
    +	case MDOC_Bsx:
    +		os = "BSD/OS";
    +		break;
    +	case MDOC_Dx:
    +		os = "DragonFly";
    +		break;
    +	case MDOC_Fx:
    +		os = "FreeBSD";
    +		break;
    +	case MDOC_Nx:
    +		os = "NetBSD";
    +		if (n->child == NULL)
    +			break;
    +		v = n->child->string;
    +		if ((v[0] != '0' && v[0] != '1') || v[1] != '.' ||
    +		    v[2] < '0' || v[2] > '9' ||
    +		    v[3] < 'a' || v[3] > 'z' || v[4] != '\0')
    +			break;
    +		n->child->flags |= NODE_NOPRT;
    +		mdoc->next = ROFF_NEXT_CHILD;
    +		roff_word_alloc(mdoc, n->child->line, n->child->pos, v);
    +		v = mdoc->last->string;
    +		v[3] = toupper((unsigned char)v[3]);
    +		mdoc->last->flags |= NODE_NOSRC;
    +		mdoc->last = n;
    +		break;
    +	case MDOC_Ox:
    +		os = "OpenBSD";
    +		break;
    +	case MDOC_Ux:
    +		os = "UNIX";
    +		break;
    +	default:
    +		abort();
    +	}
    +	mdoc->next = ROFF_NEXT_CHILD;
    +	roff_word_alloc(mdoc, n->line, n->pos, os);
    +	mdoc->last->flags |= NODE_NOSRC;
    +	mdoc->last = n;
    +}
    +
    +static void
    +post_it(POST_ARGS)
    +{
    +	struct roff_node *nbl, *nit, *nch;
    +	int		  i, cols;
    +	enum mdoc_list	  lt;
    +
    +	post_prevpar(mdoc);
    +
    +	nit = mdoc->last;
    +	if (nit->type != ROFFT_BLOCK)
    +		return;
    +
    +	nbl = nit->parent->parent;
    +	lt = nbl->norm->Bl.type;
    +
    +	switch (lt) {
    +	case LIST_tag:
    +	case LIST_hang:
    +	case LIST_ohang:
    +	case LIST_inset:
    +	case LIST_diag:
    +		if (nit->head->child == NULL)
    +			mandoc_vmsg(MANDOCERR_IT_NOHEAD,
    +			    mdoc->parse, nit->line, nit->pos,
    +			    "Bl -%s It",
    +			    mdoc_argnames[nbl->args->argv[0].arg]);
    +		break;
    +	case LIST_bullet:
    +	case LIST_dash:
    +	case LIST_enum:
    +	case LIST_hyphen:
    +		if (nit->body == NULL || nit->body->child == NULL)
    +			mandoc_vmsg(MANDOCERR_IT_NOBODY,
    +			    mdoc->parse, nit->line, nit->pos,
    +			    "Bl -%s It",
    +			    mdoc_argnames[nbl->args->argv[0].arg]);
    +		/* FALLTHROUGH */
    +	case LIST_item:
    +		if ((nch = nit->head->child) != NULL)
    +			mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
    +			    nit->line, nit->pos, "It %s",
    +			    nch->string == NULL ? roff_name[nch->tok] :
    +			    nch->string);
    +		break;
    +	case LIST_column:
    +		cols = (int)nbl->norm->Bl.ncols;
    +
    +		assert(nit->head->child == NULL);
    +
    +		if (nit->head->next->child == NULL &&
    +		    nit->head->next->next == NULL) {
    +			mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
    +			    nit->line, nit->pos, "It");
    +			roff_node_delete(mdoc, nit);
    +			break;
    +		}
    +
    +		i = 0;
    +		for (nch = nit->child; nch != NULL; nch = nch->next) {
    +			if (nch->type != ROFFT_BODY)
    +				continue;
    +			if (i++ && nch->flags & NODE_LINE)
    +				mandoc_msg(MANDOCERR_TA_LINE, mdoc->parse,
    +				    nch->line, nch->pos, "Ta");
    +		}
    +		if (i < cols || i > cols + 1)
    +			mandoc_vmsg(MANDOCERR_BL_COL,
    +			    mdoc->parse, nit->line, nit->pos,
    +			    "%d columns, %d cells", cols, i);
    +		else if (nit->head->next->child != NULL &&
    +		    nit->head->next->child->line > nit->line)
    +			mandoc_msg(MANDOCERR_IT_NOARG, mdoc->parse,
    +			    nit->line, nit->pos, "Bl -column It");
    +		break;
    +	default:
    +		abort();
    +	}
    +}
    +
    +static void
    +post_bl_block(POST_ARGS)
    +{
    +	struct roff_node *n, *ni, *nc;
    +
    +	post_prevpar(mdoc);
    +
    +	n = mdoc->last;
    +	for (ni = n->body->child; ni != NULL; ni = ni->next) {
    +		if (ni->body == NULL)
    +			continue;
    +		nc = ni->body->last;
    +		while (nc != NULL) {
    +			switch (nc->tok) {
    +			case MDOC_Pp:
    +			case MDOC_Lp:
    +			case ROFF_br:
    +				break;
    +			default:
    +				nc = NULL;
    +				continue;
    +			}
    +			if (ni->next == NULL) {
    +				mandoc_msg(MANDOCERR_PAR_MOVE,
    +				    mdoc->parse, nc->line, nc->pos,
    +				    roff_name[nc->tok]);
    +				mdoc_node_relink(mdoc, nc);
    +			} else if (n->norm->Bl.comp == 0 &&
    +			    n->norm->Bl.type != LIST_column) {
    +				mandoc_vmsg(MANDOCERR_PAR_SKIP,
    +				    mdoc->parse, nc->line, nc->pos,
    +				    "%s before It", roff_name[nc->tok]);
    +				roff_node_delete(mdoc, nc);
    +			} else
    +				break;
    +			nc = ni->body->last;
    +		}
    +	}
    +}
    +
    +/*
    + * If the argument of -offset or -width is a macro,
    + * replace it with the associated default width.
    + */
    +static void
    +rewrite_macro2len(struct roff_man *mdoc, char **arg)
    +{
    +	size_t		  width;
    +	enum roff_tok	  tok;
    +
    +	if (*arg == NULL)
    +		return;
    +	else if ( ! strcmp(*arg, "Ds"))
    +		width = 6;
    +	else if ((tok = roffhash_find(mdoc->mdocmac, *arg, 0)) == TOKEN_NONE)
    +		return;
    +	else
    +		width = macro2len(tok);
    +
    +	free(*arg);
    +	mandoc_asprintf(arg, "%zun", width);
    +}
    +
    +static void
    +post_bl_head(POST_ARGS)
    +{
    +	struct roff_node *nbl, *nh, *nch, *nnext;
    +	struct mdoc_argv *argv;
    +	int		  i, j;
    +
    +	post_bl_norm(mdoc);
    +
    +	nh = mdoc->last;
    +	if (nh->norm->Bl.type != LIST_column) {
    +		if ((nch = nh->child) == NULL)
    +			return;
    +		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
    +		    nch->line, nch->pos, "Bl ... %s", nch->string);
    +		while (nch != NULL) {
    +			roff_node_delete(mdoc, nch);
    +			nch = nh->child;
    +		}
    +		return;
    +	}
    +
    +	/*
    +	 * Append old-style lists, where the column width specifiers
    +	 * trail as macro parameters, to the new-style ("normal-form")
    +	 * lists where they're argument values following -column.
    +	 */
    +
    +	if (nh->child == NULL)
    +		return;
    +
    +	nbl = nh->parent;
    +	for (j = 0; j < (int)nbl->args->argc; j++)
    +		if (nbl->args->argv[j].arg == MDOC_Column)
    +			break;
    +
    +	assert(j < (int)nbl->args->argc);
    +
    +	/*
    +	 * Accommodate for new-style groff column syntax.  Shuffle the
    +	 * child nodes, all of which must be TEXT, as arguments for the
    +	 * column field.  Then, delete the head children.
    +	 */
    +
    +	argv = nbl->args->argv + j;
    +	i = argv->sz;
    +	for (nch = nh->child; nch != NULL; nch = nch->next)
    +		argv->sz++;
    +	argv->value = mandoc_reallocarray(argv->value,
    +	    argv->sz, sizeof(char *));
    +
    +	nh->norm->Bl.ncols = argv->sz;
    +	nh->norm->Bl.cols = (void *)argv->value;
    +
    +	for (nch = nh->child; nch != NULL; nch = nnext) {
    +		argv->value[i++] = nch->string;
    +		nch->string = NULL;
    +		nnext = nch->next;
    +		roff_node_delete(NULL, nch);
    +	}
    +	nh->child = NULL;
    +}
    +
    +static void
    +post_bl(POST_ARGS)
    +{
    +	struct roff_node	*nparent, *nprev; /* of the Bl block */
    +	struct roff_node	*nblock, *nbody;  /* of the Bl */
    +	struct roff_node	*nchild, *nnext;  /* of the Bl body */
    +	const char		*prev_Er;
    +	int			 order;
    +
    +	nbody = mdoc->last;
    +	switch (nbody->type) {
    +	case ROFFT_BLOCK:
    +		post_bl_block(mdoc);
    +		return;
    +	case ROFFT_HEAD:
    +		post_bl_head(mdoc);
    +		return;
    +	case ROFFT_BODY:
    +		break;
    +	default:
    +		return;
    +	}
    +	if (nbody->end != ENDBODY_NOT)
    +		return;
    +
    +	nchild = nbody->child;
    +	if (nchild == NULL) {
    +		mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
    +		    nbody->line, nbody->pos, "Bl");
    +		return;
    +	}
    +	while (nchild != NULL) {
    +		nnext = nchild->next;
    +		if (nchild->tok == MDOC_It ||
    +		    (nchild->tok == MDOC_Sm &&
    +		     nnext != NULL && nnext->tok == MDOC_It)) {
    +			nchild = nnext;
    +			continue;
    +		}
    +
    +		/*
    +		 * In .Bl -column, the first rows may be implicit,
    +		 * that is, they may not start with .It macros.
    +		 * Such rows may be followed by nodes generated on the
    +		 * roff level, for example .TS, which cannot be moved
    +		 * out of the list.  In that case, wrap such roff nodes
    +		 * into an implicit row.
    +		 */
    +
    +		if (nchild->prev != NULL) {
    +			mdoc->last = nchild;
    +			mdoc->next = ROFF_NEXT_SIBLING;
    +			roff_block_alloc(mdoc, nchild->line,
    +			    nchild->pos, MDOC_It);
    +			roff_head_alloc(mdoc, nchild->line,
    +			    nchild->pos, MDOC_It);
    +			mdoc->next = ROFF_NEXT_SIBLING;
    +			roff_body_alloc(mdoc, nchild->line,
    +			    nchild->pos, MDOC_It);
    +			while (nchild->tok != MDOC_It) {
    +				mdoc_node_relink(mdoc, nchild);
    +				if ((nchild = nnext) == NULL)
    +					break;
    +				nnext = nchild->next;
    +				mdoc->next = ROFF_NEXT_SIBLING;
    +			}
    +			mdoc->last = nbody;
    +			continue;
    +		}
    +
    +		mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
    +		    nchild->line, nchild->pos, roff_name[nchild->tok]);
    +
    +		/*
    +		 * Move the node out of the Bl block.
    +		 * First, collect all required node pointers.
    +		 */
    +
    +		nblock  = nbody->parent;
    +		nprev   = nblock->prev;
    +		nparent = nblock->parent;
    +
    +		/*
    +		 * Unlink this child.
    +		 */
    +
    +		nbody->child = nnext;
    +		if (nnext == NULL)
    +			nbody->last  = NULL;
    +		else
    +			nnext->prev = NULL;
    +
    +		/*
    +		 * Relink this child.
    +		 */
    +
    +		nchild->parent = nparent;
    +		nchild->prev   = nprev;
    +		nchild->next   = nblock;
    +
    +		nblock->prev = nchild;
    +		if (nprev == NULL)
    +			nparent->child = nchild;
    +		else
    +			nprev->next = nchild;
    +
    +		nchild = nnext;
    +	}
    +
    +	if (mdoc->meta.os_e != MANDOC_OS_NETBSD)
    +		return;
    +
    +	prev_Er = NULL;
    +	for (nchild = nbody->child; nchild != NULL; nchild = nchild->next) {
    +		if (nchild->tok != MDOC_It)
    +			continue;
    +		if ((nnext = nchild->head->child) == NULL)
    +			continue;
    +		if (nnext->type == ROFFT_BLOCK)
    +			nnext = nnext->body->child;
    +		if (nnext == NULL || nnext->tok != MDOC_Er)
    +			continue;
    +		nnext = nnext->child;
    +		if (prev_Er != NULL) {
    +			order = strcmp(prev_Er, nnext->string);
    +			if (order > 0)
    +				mandoc_vmsg(MANDOCERR_ER_ORDER,
    +				    mdoc->parse, nnext->line, nnext->pos,
    +				    "Er %s %s (NetBSD)",
    +				    prev_Er, nnext->string);
    +			else if (order == 0)
    +				mandoc_vmsg(MANDOCERR_ER_REP,
    +				    mdoc->parse, nnext->line, nnext->pos,
    +				    "Er %s (NetBSD)", prev_Er);
    +		}
    +		prev_Er = nnext->string;
    +	}
    +}
    +
    +static void
    +post_bk(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +
    +	n = mdoc->last;
    +
    +	if (n->type == ROFFT_BLOCK && n->body->child == NULL) {
    +		mandoc_msg(MANDOCERR_BLK_EMPTY,
    +		    mdoc->parse, n->line, n->pos, "Bk");
    +		roff_node_delete(mdoc, n);
    +	}
    +}
    +
    +static void
    +post_sm(POST_ARGS)
    +{
    +	struct roff_node	*nch;
    +
    +	nch = mdoc->last->child;
    +
    +	if (nch == NULL) {
    +		mdoc->flags ^= MDOC_SMOFF;
    +		return;
    +	}
    +
    +	assert(nch->type == ROFFT_TEXT);
    +
    +	if ( ! strcmp(nch->string, "on")) {
    +		mdoc->flags &= ~MDOC_SMOFF;
    +		return;
    +	}
    +	if ( ! strcmp(nch->string, "off")) {
    +		mdoc->flags |= MDOC_SMOFF;
    +		return;
    +	}
    +
    +	mandoc_vmsg(MANDOCERR_SM_BAD,
    +	    mdoc->parse, nch->line, nch->pos,
    +	    "%s %s", roff_name[mdoc->last->tok], nch->string);
    +	mdoc_node_relink(mdoc, nch);
    +	return;
    +}
    +
    +static void
    +post_root(POST_ARGS)
    +{
    +	const char *openbsd_arch[] = {
    +		"alpha", "amd64", "arm64", "armv7", "hppa", "i386",
    +		"landisk", "loongson", "luna88k", "macppc", "mips64",
    +		"octeon", "sgi", "socppc", "sparc64", NULL
    +	};
    +	const char *netbsd_arch[] = {
    +		"acorn26", "acorn32", "algor", "alpha", "amiga",
    +		"arc", "atari",
    +		"bebox", "cats", "cesfic", "cobalt", "dreamcast",
    +		"emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5",
    +		"hp300", "hpcarm", "hpcmips", "hpcsh", "hppa",
    +		"i386", "ibmnws", "luna68k",
    +		"mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc",
    +		"netwinder", "news68k", "newsmips", "next68k",
    +		"pc532", "playstation2", "pmax", "pmppc", "prep",
    +		"sandpoint", "sbmips", "sgimips", "shark",
    +		"sparc", "sparc64", "sun2", "sun3",
    +		"vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL
    +        };
    +	const char **arches[] = { NULL, netbsd_arch, openbsd_arch };
    +
    +	struct roff_node *n;
    +	const char **arch;
    +
    +	/* Add missing prologue data. */
    +
    +	if (mdoc->meta.date == NULL)
    +		mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
    +		    mandoc_normdate(mdoc, NULL, 0, 0);
    +
    +	if (mdoc->meta.title == NULL) {
    +		mandoc_msg(MANDOCERR_DT_NOTITLE,
    +		    mdoc->parse, 0, 0, "EOF");
    +		mdoc->meta.title = mandoc_strdup("UNTITLED");
    +	}
    +
    +	if (mdoc->meta.vol == NULL)
    +		mdoc->meta.vol = mandoc_strdup("LOCAL");
    +
    +	if (mdoc->meta.os == NULL) {
    +		mandoc_msg(MANDOCERR_OS_MISSING,
    +		    mdoc->parse, 0, 0, NULL);
    +		mdoc->meta.os = mandoc_strdup("");
    +	} else if (mdoc->meta.os_e &&
    +	    (mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0)
    +		mandoc_msg(MANDOCERR_RCS_MISSING, mdoc->parse, 0, 0,
    +		    mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
    +		    "(OpenBSD)" : "(NetBSD)");
    +
    +	if (mdoc->meta.arch != NULL &&
    +	    (arch = arches[mdoc->meta.os_e]) != NULL) {
    +		while (*arch != NULL && strcmp(*arch, mdoc->meta.arch))
    +			arch++;
    +		if (*arch == NULL) {
    +			n = mdoc->first->child;
    +			while (n->tok != MDOC_Dt ||
    +			    n->child == NULL ||
    +			    n->child->next == NULL ||
    +			    n->child->next->next == NULL)
    +				n = n->next;
    +			n = n->child->next->next;
    +			mandoc_vmsg(MANDOCERR_ARCH_BAD,
    +			    mdoc->parse, n->line, n->pos,
    +			    "Dt ... %s %s", mdoc->meta.arch,
    +			    mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
    +			    "(OpenBSD)" : "(NetBSD)");
    +		}
    +	}
    +
    +	/* Check that we begin with a proper `Sh'. */
    +
    +	n = mdoc->first->child;
    +	while (n != NULL &&
    +	    (n->type == ROFFT_COMMENT ||
    +	     (n->tok >= MDOC_Dd &&
    +	      mdoc_macros[n->tok].flags & MDOC_PROLOGUE)))
    +		n = n->next;
    +
    +	if (n == NULL)
    +		mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
    +	else if (n->tok != MDOC_Sh)
    +		mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
    +		    n->line, n->pos, roff_name[n->tok]);
    +}
    +
    +static void
    +post_rs(POST_ARGS)
    +{
    +	struct roff_node *np, *nch, *next, *prev;
    +	int		  i, j;
    +
    +	np = mdoc->last;
    +
    +	if (np->type != ROFFT_BODY)
    +		return;
    +
    +	if (np->child == NULL) {
    +		mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse,
    +		    np->line, np->pos, "Rs");
    +		return;
    +	}
    +
    +	/*
    +	 * The full `Rs' block needs special handling to order the
    +	 * sub-elements according to `rsord'.  Pick through each element
    +	 * and correctly order it.  This is an insertion sort.
    +	 */
    +
    +	next = NULL;
    +	for (nch = np->child->next; nch != NULL; nch = next) {
    +		/* Determine order number of this child. */
    +		for (i = 0; i < RSORD_MAX; i++)
    +			if (rsord[i] == nch->tok)
    +				break;
    +
    +		if (i == RSORD_MAX) {
    +			mandoc_msg(MANDOCERR_RS_BAD, mdoc->parse,
    +			    nch->line, nch->pos, roff_name[nch->tok]);
    +			i = -1;
    +		} else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
    +			np->norm->Rs.quote_T++;
    +
    +		/*
    +		 * Remove this child from the chain.  This somewhat
    +		 * repeats roff_node_unlink(), but since we're
    +		 * just re-ordering, there's no need for the
    +		 * full unlink process.
    +		 */
    +
    +		if ((next = nch->next) != NULL)
    +			next->prev = nch->prev;
    +
    +		if ((prev = nch->prev) != NULL)
    +			prev->next = nch->next;
    +
    +		nch->prev = nch->next = NULL;
    +
    +		/*
    +		 * Scan back until we reach a node that's
    +		 * to be ordered before this child.
    +		 */
    +
    +		for ( ; prev ; prev = prev->prev) {
    +			/* Determine order of `prev'. */
    +			for (j = 0; j < RSORD_MAX; j++)
    +				if (rsord[j] == prev->tok)
    +					break;
    +			if (j == RSORD_MAX)
    +				j = -1;
    +
    +			if (j <= i)
    +				break;
    +		}
    +
    +		/*
    +		 * Set this child back into its correct place
    +		 * in front of the `prev' node.
    +		 */
    +
    +		nch->prev = prev;
    +
    +		if (prev == NULL) {
    +			np->child->prev = nch;
    +			nch->next = np->child;
    +			np->child = nch;
    +		} else {
    +			if (prev->next)
    +				prev->next->prev = nch;
    +			nch->next = prev->next;
    +			prev->next = nch;
    +		}
    +	}
    +}
    +
    +/*
    + * For some arguments of some macros,
    + * convert all breakable hyphens into ASCII_HYPH.
    + */
    +static void
    +post_hyph(POST_ARGS)
    +{
    +	struct roff_node	*nch;
    +	char			*cp;
    +
    +	for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
    +		if (nch->type != ROFFT_TEXT)
    +			continue;
    +		cp = nch->string;
    +		if (*cp == '\0')
    +			continue;
    +		while (*(++cp) != '\0')
    +			if (*cp == '-' &&
    +			    isalpha((unsigned char)cp[-1]) &&
    +			    isalpha((unsigned char)cp[1]))
    +				*cp = ASCII_HYPH;
    +	}
    +}
    +
    +static void
    +post_ns(POST_ARGS)
    +{
    +	struct roff_node	*n;
    +
    +	n = mdoc->last;
    +	if (n->flags & NODE_LINE ||
    +	    (n->next != NULL && n->next->flags & NODE_DELIMC))
    +		mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
    +		    n->line, n->pos, NULL);
    +}
    +
    +static void
    +post_sx(POST_ARGS)
    +{
    +	post_delim(mdoc);
    +	post_hyph(mdoc);
    +}
    +
    +static void
    +post_sh(POST_ARGS)
    +{
    +
    +	post_ignpar(mdoc);
    +
    +	switch (mdoc->last->type) {
    +	case ROFFT_HEAD:
    +		post_sh_head(mdoc);
    +		break;
    +	case ROFFT_BODY:
    +		switch (mdoc->lastsec)  {
    +		case SEC_NAME:
    +			post_sh_name(mdoc);
    +			break;
    +		case SEC_SEE_ALSO:
    +			post_sh_see_also(mdoc);
    +			break;
    +		case SEC_AUTHORS:
    +			post_sh_authors(mdoc);
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +post_sh_name(POST_ARGS)
    +{
    +	struct roff_node *n;
    +	int hasnm, hasnd;
    +
    +	hasnm = hasnd = 0;
    +
    +	for (n = mdoc->last->child; n != NULL; n = n->next) {
    +		switch (n->tok) {
    +		case MDOC_Nm:
    +			if (hasnm && n->child != NULL)
    +				mandoc_vmsg(MANDOCERR_NAMESEC_PUNCT,
    +				    mdoc->parse, n->line, n->pos,
    +				    "Nm %s", n->child->string);
    +			hasnm = 1;
    +			continue;
    +		case MDOC_Nd:
    +			hasnd = 1;
    +			if (n->next != NULL)
    +				mandoc_msg(MANDOCERR_NAMESEC_ND,
    +				    mdoc->parse, n->line, n->pos, NULL);
    +			break;
    +		case TOKEN_NONE:
    +			if (n->type == ROFFT_TEXT &&
    +			    n->string[0] == ',' && n->string[1] == '\0' &&
    +			    n->next != NULL && n->next->tok == MDOC_Nm) {
    +				n = n->next;
    +				continue;
    +			}
    +			/* FALLTHROUGH */
    +		default:
    +			mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
    +			    n->line, n->pos, roff_name[n->tok]);
    +			continue;
    +		}
    +		break;
    +	}
    +
    +	if ( ! hasnm)
    +		mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
    +		    mdoc->last->line, mdoc->last->pos, NULL);
    +	if ( ! hasnd)
    +		mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
    +		    mdoc->last->line, mdoc->last->pos, NULL);
    +}
    +
    +static void
    +post_sh_see_also(POST_ARGS)
    +{
    +	const struct roff_node	*n;
    +	const char		*name, *sec;
    +	const char		*lastname, *lastsec, *lastpunct;
    +	int			 cmp;
    +
    +	n = mdoc->last->child;
    +	lastname = lastsec = lastpunct = NULL;
    +	while (n != NULL) {
    +		if (n->tok != MDOC_Xr ||
    +		    n->child == NULL ||
    +		    n->child->next == NULL)
    +			break;
    +
    +		/* Process one .Xr node. */
    +
    +		name = n->child->string;
    +		sec = n->child->next->string;
    +		if (lastsec != NULL) {
    +			if (lastpunct[0] != ',' || lastpunct[1] != '\0')
    +				mandoc_vmsg(MANDOCERR_XR_PUNCT,
    +				    mdoc->parse, n->line, n->pos,
    +				    "%s before %s(%s)", lastpunct,
    +				    name, sec);
    +			cmp = strcmp(lastsec, sec);
    +			if (cmp > 0)
    +				mandoc_vmsg(MANDOCERR_XR_ORDER,
    +				    mdoc->parse, n->line, n->pos,
    +				    "%s(%s) after %s(%s)", name,
    +				    sec, lastname, lastsec);
    +			else if (cmp == 0 &&
    +			    strcasecmp(lastname, name) > 0)
    +				mandoc_vmsg(MANDOCERR_XR_ORDER,
    +				    mdoc->parse, n->line, n->pos,
    +				    "%s after %s", name, lastname);
    +		}
    +		lastname = name;
    +		lastsec = sec;
    +
    +		/* Process the following node. */
    +
    +		n = n->next;
    +		if (n == NULL)
    +			break;
    +		if (n->tok == MDOC_Xr) {
    +			lastpunct = "none";
    +			continue;
    +		}
    +		if (n->type != ROFFT_TEXT)
    +			break;
    +		for (name = n->string; *name != '\0'; name++)
    +			if (isalpha((const unsigned char)*name))
    +				return;
    +		lastpunct = n->string;
    +		if (n->next == NULL || n->next->tok == MDOC_Rs)
    +			mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
    +			    n->line, n->pos, "%s after %s(%s)",
    +			    lastpunct, lastname, lastsec);
    +		n = n->next;
    +	}
    +}
    +
    +static int
    +child_an(const struct roff_node *n)
    +{
    +
    +	for (n = n->child; n != NULL; n = n->next)
    +		if ((n->tok == MDOC_An && n->child != NULL) || child_an(n))
    +			return 1;
    +	return 0;
    +}
    +
    +static void
    +post_sh_authors(POST_ARGS)
    +{
    +
    +	if ( ! child_an(mdoc->last))
    +		mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
    +		    mdoc->last->line, mdoc->last->pos, NULL);
    +}
    +
    +/*
    + * Return an upper bound for the string distance (allowing
    + * transpositions).  Not a full Levenshtein implementation
    + * because Levenshtein is quadratic in the string length
    + * and this function is called for every standard name,
    + * so the check for each custom name would be cubic.
    + * The following crude heuristics is linear, resulting
    + * in quadratic behaviour for checking one custom name,
    + * which does not cause measurable slowdown.
    + */
    +static int
    +similar(const char *s1, const char *s2)
    +{
    +	const int	maxdist = 3;
    +	int		dist = 0;
    +
    +	while (s1[0] != '\0' && s2[0] != '\0') {
    +		if (s1[0] == s2[0]) {
    +			s1++;
    +			s2++;
    +			continue;
    +		}
    +		if (++dist > maxdist)
    +			return INT_MAX;
    +		if (s1[1] == s2[1]) {  /* replacement */
    +			s1++;
    +			s2++;
    +		} else if (s1[0] == s2[1] && s1[1] == s2[0]) {
    +			s1 += 2;	/* transposition */
    +			s2 += 2;
    +		} else if (s1[0] == s2[1])  /* insertion */
    +			s2++;
    +		else if (s1[1] == s2[0])  /* deletion */
    +			s1++;
    +		else
    +			return INT_MAX;
    +	}
    +	dist += strlen(s1) + strlen(s2);
    +	return dist > maxdist ? INT_MAX : dist;
    +}
    +
    +static void
    +post_sh_head(POST_ARGS)
    +{
    +	struct roff_node	*nch;
    +	const char		*goodsec;
    +	const char *const	*testsec;
    +	int			 dist, mindist;
    +	enum roff_sec		 sec;
    +
    +	/*
    +	 * Process a new section.  Sections are either "named" or
    +	 * "custom".  Custom sections are user-defined, while named ones
    +	 * follow a conventional order and may only appear in certain
    +	 * manual sections.
    +	 */
    +
    +	sec = mdoc->last->sec;
    +
    +	/* The NAME should be first. */
    +
    +	if (sec != SEC_NAME && mdoc->lastnamed == SEC_NONE)
    +		mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
    +		    mdoc->last->line, mdoc->last->pos, "Sh %s",
    +		    sec != SEC_CUSTOM ? secnames[sec] :
    +		    (nch = mdoc->last->child) == NULL ? "" :
    +		    nch->type == ROFFT_TEXT ? nch->string :
    +		    roff_name[nch->tok]);
    +
    +	/* The SYNOPSIS gets special attention in other areas. */
    +
    +	if (sec == SEC_SYNOPSIS) {
    +		roff_setreg(mdoc->roff, "nS", 1, '=');
    +		mdoc->flags |= MDOC_SYNOPSIS;
    +	} else {
    +		roff_setreg(mdoc->roff, "nS", 0, '=');
    +		mdoc->flags &= ~MDOC_SYNOPSIS;
    +	}
    +
    +	/* Mark our last section. */
    +
    +	mdoc->lastsec = sec;
    +
    +	/* We don't care about custom sections after this. */
    +
    +	if (sec == SEC_CUSTOM) {
    +		if ((nch = mdoc->last->child) == NULL ||
    +		    nch->type != ROFFT_TEXT || nch->next != NULL)
    +			return;
    +		goodsec = NULL;
    +		mindist = INT_MAX;
    +		for (testsec = secnames + 1; *testsec != NULL; testsec++) {
    +			dist = similar(nch->string, *testsec);
    +			if (dist < mindist) {
    +				goodsec = *testsec;
    +				mindist = dist;
    +			}
    +		}
    +		if (goodsec != NULL)
    +			mandoc_vmsg(MANDOCERR_SEC_TYPO, mdoc->parse,
    +			    nch->line, nch->pos, "Sh %s instead of %s",
    +			    nch->string, goodsec);
    +		return;
    +	}
    +
    +	/*
    +	 * Check whether our non-custom section is being repeated or is
    +	 * out of order.
    +	 */
    +
    +	if (sec == mdoc->lastnamed)
    +		mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
    +		    mdoc->last->line, mdoc->last->pos,
    +		    "Sh %s", secnames[sec]);
    +
    +	if (sec < mdoc->lastnamed)
    +		mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
    +		    mdoc->last->line, mdoc->last->pos,
    +		    "Sh %s", secnames[sec]);
    +
    +	/* Mark the last named section. */
    +
    +	mdoc->lastnamed = sec;
    +
    +	/* Check particular section/manual conventions. */
    +
    +	if (mdoc->meta.msec == NULL)
    +		return;
    +
    +	goodsec = NULL;
    +	switch (sec) {
    +	case SEC_ERRORS:
    +		if (*mdoc->meta.msec == '4')
    +			break;
    +		goodsec = "2, 3, 4, 9";
    +		/* FALLTHROUGH */
    +	case SEC_RETURN_VALUES:
    +	case SEC_LIBRARY:
    +		if (*mdoc->meta.msec == '2')
    +			break;
    +		if (*mdoc->meta.msec == '3')
    +			break;
    +		if (NULL == goodsec)
    +			goodsec = "2, 3, 9";
    +		/* FALLTHROUGH */
    +	case SEC_CONTEXT:
    +		if (*mdoc->meta.msec == '9')
    +			break;
    +		if (NULL == goodsec)
    +			goodsec = "9";
    +		mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
    +		    mdoc->last->line, mdoc->last->pos,
    +		    "Sh %s for %s only", secnames[sec], goodsec);
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +post_xr(POST_ARGS)
    +{
    +	struct roff_node *n, *nch;
    +
    +	n = mdoc->last;
    +	nch = n->child;
    +	if (nch->next == NULL) {
    +		mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse,
    +		    n->line, n->pos, "Xr %s", nch->string);
    +	} else {
    +		assert(nch->next == n->last);
    +		if(mandoc_xr_add(nch->next->string, nch->string,
    +		    nch->line, nch->pos))
    +			mandoc_vmsg(MANDOCERR_XR_SELF, mdoc->parse,
    +			    nch->line, nch->pos, "Xr %s %s",
    +			    nch->string, nch->next->string);
    +	}
    +	post_delim_nb(mdoc);
    +}
    +
    +static void
    +post_ignpar(POST_ARGS)
    +{
    +	struct roff_node *np;
    +
    +	switch (mdoc->last->type) {
    +	case ROFFT_BLOCK:
    +		post_prevpar(mdoc);
    +		return;
    +	case ROFFT_HEAD:
    +		post_delim(mdoc);
    +		post_hyph(mdoc);
    +		return;
    +	case ROFFT_BODY:
    +		break;
    +	default:
    +		return;
    +	}
    +
    +	if ((np = mdoc->last->child) != NULL)
    +		if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
    +			mandoc_vmsg(MANDOCERR_PAR_SKIP,
    +			    mdoc->parse, np->line, np->pos,
    +			    "%s after %s", roff_name[np->tok],
    +			    roff_name[mdoc->last->tok]);
    +			roff_node_delete(mdoc, np);
    +		}
    +
    +	if ((np = mdoc->last->last) != NULL)
    +		if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
    +			mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
    +			    np->line, np->pos, "%s at the end of %s",
    +			    roff_name[np->tok],
    +			    roff_name[mdoc->last->tok]);
    +			roff_node_delete(mdoc, np);
    +		}
    +}
    +
    +static void
    +post_prevpar(POST_ARGS)
    +{
    +	struct roff_node *n;
    +
    +	n = mdoc->last;
    +	if (NULL == n->prev)
    +		return;
    +	if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK)
    +		return;
    +
    +	/*
    +	 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
    +	 * block:  `Lp', `Pp', or non-compact `Bd' or `Bl'.
    +	 */
    +
    +	if (n->prev->tok != MDOC_Pp &&
    +	    n->prev->tok != MDOC_Lp &&
    +	    n->prev->tok != ROFF_br)
    +		return;
    +	if (n->tok == MDOC_Bl && n->norm->Bl.comp)
    +		return;
    +	if (n->tok == MDOC_Bd && n->norm->Bd.comp)
    +		return;
    +	if (n->tok == MDOC_It && n->parent->norm->Bl.comp)
    +		return;
    +
    +	mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
    +	    n->prev->line, n->prev->pos, "%s before %s",
    +	    roff_name[n->prev->tok], roff_name[n->tok]);
    +	roff_node_delete(mdoc, n->prev);
    +}
    +
    +static void
    +post_par(POST_ARGS)
    +{
    +	struct roff_node *np;
    +
    +	np = mdoc->last;
    +	if (np->tok != ROFF_br && np->tok != ROFF_sp)
    +		post_prevpar(mdoc);
    +
    +	if (np->tok == ROFF_sp) {
    +		if (np->child != NULL && np->child->next != NULL)
    +			mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
    +			    np->child->next->line, np->child->next->pos,
    +			    "sp ... %s", np->child->next->string);
    +	} else if (np->child != NULL)
    +		mandoc_vmsg(MANDOCERR_ARG_SKIP,
    +		    mdoc->parse, np->line, np->pos, "%s %s",
    +		    roff_name[np->tok], np->child->string);
    +
    +	if ((np = mdoc->last->prev) == NULL) {
    +		np = mdoc->last->parent;
    +		if (np->tok != MDOC_Sh && np->tok != MDOC_Ss)
    +			return;
    +	} else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp &&
    +	    (mdoc->last->tok != ROFF_br ||
    +	     (np->tok != ROFF_sp && np->tok != ROFF_br)))
    +		return;
    +
    +	mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
    +	    mdoc->last->line, mdoc->last->pos, "%s after %s",
    +	    roff_name[mdoc->last->tok], roff_name[np->tok]);
    +	roff_node_delete(mdoc, mdoc->last);
    +}
    +
    +static void
    +post_dd(POST_ARGS)
    +{
    +	struct roff_node *n;
    +	char		 *datestr;
    +
    +	n = mdoc->last;
    +	n->flags |= NODE_NOPRT;
    +
    +	if (mdoc->meta.date != NULL) {
    +		mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
    +		    n->line, n->pos, "Dd");
    +		free(mdoc->meta.date);
    +	} else if (mdoc->flags & MDOC_PBODY)
    +		mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
    +		    n->line, n->pos, "Dd");
    +	else if (mdoc->meta.title != NULL)
    +		mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
    +		    n->line, n->pos, "Dd after Dt");
    +	else if (mdoc->meta.os != NULL)
    +		mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
    +		    n->line, n->pos, "Dd after Os");
    +
    +	if (n->child == NULL || n->child->string[0] == '\0') {
    +		mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
    +		    mandoc_normdate(mdoc, NULL, n->line, n->pos);
    +		return;
    +	}
    +
    +	datestr = NULL;
    +	deroff(&datestr, n);
    +	if (mdoc->quick)
    +		mdoc->meta.date = datestr;
    +	else {
    +		mdoc->meta.date = mandoc_normdate(mdoc,
    +		    datestr, n->line, n->pos);
    +		free(datestr);
    +	}
    +}
    +
    +static void
    +post_dt(POST_ARGS)
    +{
    +	struct roff_node *nn, *n;
    +	const char	 *cp;
    +	char		 *p;
    +
    +	n = mdoc->last;
    +	n->flags |= NODE_NOPRT;
    +
    +	if (mdoc->flags & MDOC_PBODY) {
    +		mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse,
    +		    n->line, n->pos, "Dt");
    +		return;
    +	}
    +
    +	if (mdoc->meta.title != NULL)
    +		mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
    +		    n->line, n->pos, "Dt");
    +	else if (mdoc->meta.os != NULL)
    +		mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
    +		    n->line, n->pos, "Dt after Os");
    +
    +	free(mdoc->meta.title);
    +	free(mdoc->meta.msec);
    +	free(mdoc->meta.vol);
    +	free(mdoc->meta.arch);
    +
    +	mdoc->meta.title = NULL;
    +	mdoc->meta.msec = NULL;
    +	mdoc->meta.vol = NULL;
    +	mdoc->meta.arch = NULL;
    +
    +	/* Mandatory first argument: title. */
    +
    +	nn = n->child;
    +	if (nn == NULL || *nn->string == '\0') {
    +		mandoc_msg(MANDOCERR_DT_NOTITLE,
    +		    mdoc->parse, n->line, n->pos, "Dt");
    +		mdoc->meta.title = mandoc_strdup("UNTITLED");
    +	} else {
    +		mdoc->meta.title = mandoc_strdup(nn->string);
    +
    +		/* Check that all characters are uppercase. */
    +
    +		for (p = nn->string; *p != '\0'; p++)
    +			if (islower((unsigned char)*p)) {
    +				mandoc_vmsg(MANDOCERR_TITLE_CASE,
    +				    mdoc->parse, nn->line,
    +				    nn->pos + (p - nn->string),
    +				    "Dt %s", nn->string);
    +				break;
    +			}
    +	}
    +
    +	/* Mandatory second argument: section. */
    +
    +	if (nn != NULL)
    +		nn = nn->next;
    +
    +	if (nn == NULL) {
    +		mandoc_vmsg(MANDOCERR_MSEC_MISSING,
    +		    mdoc->parse, n->line, n->pos,
    +		    "Dt %s", mdoc->meta.title);
    +		mdoc->meta.vol = mandoc_strdup("LOCAL");
    +		return;  /* msec and arch remain NULL. */
    +	}
    +
    +	mdoc->meta.msec = mandoc_strdup(nn->string);
    +
    +	/* Infer volume title from section number. */
    +
    +	cp = mandoc_a2msec(nn->string);
    +	if (cp == NULL) {
    +		mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
    +		    nn->line, nn->pos, "Dt ... %s", nn->string);
    +		mdoc->meta.vol = mandoc_strdup(nn->string);
    +	} else
    +		mdoc->meta.vol = mandoc_strdup(cp);
    +
    +	/* Optional third argument: architecture. */
    +
    +	if ((nn = nn->next) == NULL)
    +		return;
    +
    +	for (p = nn->string; *p != '\0'; p++)
    +		*p = tolower((unsigned char)*p);
    +	mdoc->meta.arch = mandoc_strdup(nn->string);
    +
    +	/* Ignore fourth and later arguments. */
    +
    +	if ((nn = nn->next) != NULL)
    +		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
    +		    nn->line, nn->pos, "Dt ... %s", nn->string);
    +}
    +
    +static void
    +post_bx(POST_ARGS)
    +{
    +	struct roff_node	*n, *nch;
    +	const char		*macro;
    +
    +	post_delim_nb(mdoc);
    +
    +	n = mdoc->last;
    +	nch = n->child;
    +
    +	if (nch != NULL) {
    +		macro = !strcmp(nch->string, "Open") ? "Ox" :
    +		    !strcmp(nch->string, "Net") ? "Nx" :
    +		    !strcmp(nch->string, "Free") ? "Fx" :
    +		    !strcmp(nch->string, "DragonFly") ? "Dx" : NULL;
    +		if (macro != NULL)
    +			mandoc_msg(MANDOCERR_BX, mdoc->parse,
    +			    n->line, n->pos, macro);
    +		mdoc->last = nch;
    +		nch = nch->next;
    +		mdoc->next = ROFF_NEXT_SIBLING;
    +		roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns);
    +		mdoc->last->flags |= NODE_NOSRC;
    +		mdoc->next = ROFF_NEXT_SIBLING;
    +	} else
    +		mdoc->next = ROFF_NEXT_CHILD;
    +	roff_word_alloc(mdoc, n->line, n->pos, "BSD");
    +	mdoc->last->flags |= NODE_NOSRC;
    +
    +	if (nch == NULL) {
    +		mdoc->last = n;
    +		return;
    +	}
    +
    +	roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns);
    +	mdoc->last->flags |= NODE_NOSRC;
    +	mdoc->next = ROFF_NEXT_SIBLING;
    +	roff_word_alloc(mdoc, n->line, n->pos, "-");
    +	mdoc->last->flags |= NODE_NOSRC;
    +	roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns);
    +	mdoc->last->flags |= NODE_NOSRC;
    +	mdoc->last = n;
    +
    +	/*
    +	 * Make `Bx's second argument always start with an uppercase
    +	 * letter.  Groff checks if it's an "accepted" term, but we just
    +	 * uppercase blindly.
    +	 */
    +
    +	*nch->string = (char)toupper((unsigned char)*nch->string);
    +}
    +
    +static void
    +post_os(POST_ARGS)
    +{
    +#ifndef OSNAME
    +	struct utsname	  utsname;
    +	static char	 *defbuf;
    +#endif
    +	struct roff_node *n;
    +
    +	n = mdoc->last;
    +	n->flags |= NODE_NOPRT;
    +
    +	if (mdoc->meta.os != NULL)
    +		mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
    +		    n->line, n->pos, "Os");
    +	else if (mdoc->flags & MDOC_PBODY)
    +		mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
    +		    n->line, n->pos, "Os");
    +
    +	post_delim(mdoc);
    +
    +	/*
    +	 * Set the operating system by way of the `Os' macro.
    +	 * The order of precedence is:
    +	 * 1. the argument of the `Os' macro, unless empty
    +	 * 2. the -Ios=foo command line argument, if provided
    +	 * 3. -DOSNAME="\"foo\"", if provided during compilation
    +	 * 4. "sysname release" from uname(3)
    +	 */
    +
    +	free(mdoc->meta.os);
    +	mdoc->meta.os = NULL;
    +	deroff(&mdoc->meta.os, n);
    +	if (mdoc->meta.os)
    +		goto out;
    +
    +	if (mdoc->os_s != NULL) {
    +		mdoc->meta.os = mandoc_strdup(mdoc->os_s);
    +		goto out;
    +	}
    +
    +#ifdef OSNAME
    +	mdoc->meta.os = mandoc_strdup(OSNAME);
    +#else /*!OSNAME */
    +	if (defbuf == NULL) {
    +		if (uname(&utsname) == -1) {
    +			mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
    +			    n->line, n->pos, "Os");
    +			defbuf = mandoc_strdup("UNKNOWN");
    +		} else
    +			mandoc_asprintf(&defbuf, "%s %s",
    +			    utsname.sysname, utsname.release);
    +	}
    +	mdoc->meta.os = mandoc_strdup(defbuf);
    +#endif /*!OSNAME*/
    +
    +out:
    +	if (mdoc->meta.os_e == MANDOC_OS_OTHER) {
    +		if (strstr(mdoc->meta.os, "OpenBSD") != NULL)
    +			mdoc->meta.os_e = MANDOC_OS_OPENBSD;
    +		else if (strstr(mdoc->meta.os, "NetBSD") != NULL)
    +			mdoc->meta.os_e = MANDOC_OS_NETBSD;
    +	}
    +
    +	/*
    +	 * This is the earliest point where we can check
    +	 * Mdocdate conventions because we don't know
    +	 * the operating system earlier.
    +	 */
    +
    +	if (n->child != NULL)
    +		mandoc_vmsg(MANDOCERR_OS_ARG, mdoc->parse,
    +		    n->child->line, n->child->pos,
    +		    "Os %s (%s)", n->child->string,
    +		    mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
    +		    "OpenBSD" : "NetBSD");
    +
    +	while (n->tok != MDOC_Dd)
    +		if ((n = n->prev) == NULL)
    +			return;
    +	if ((n = n->child) == NULL)
    +		return;
    +	if (strncmp(n->string, "$" "Mdocdate", 9)) {
    +		if (mdoc->meta.os_e == MANDOC_OS_OPENBSD)
    +			mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING,
    +			    mdoc->parse, n->line, n->pos,
    +			    "Dd %s (OpenBSD)", n->string);
    +	} else {
    +		if (mdoc->meta.os_e == MANDOC_OS_NETBSD)
    +			mandoc_vmsg(MANDOCERR_MDOCDATE,
    +			    mdoc->parse, n->line, n->pos,
    +			    "Dd %s (NetBSD)", n->string);
    +	}
    +}
    +
    +enum roff_sec
    +mdoc_a2sec(const char *p)
    +{
    +	int		 i;
    +
    +	for (i = 0; i < (int)SEC__MAX; i++)
    +		if (secnames[i] && 0 == strcmp(p, secnames[i]))
    +			return (enum roff_sec)i;
    +
    +	return SEC_CUSTOM;
    +}
    +
    +static size_t
    +macro2len(enum roff_tok macro)
    +{
    +
    +	switch (macro) {
    +	case MDOC_Ad:
    +		return 12;
    +	case MDOC_Ao:
    +		return 12;
    +	case MDOC_An:
    +		return 12;
    +	case MDOC_Aq:
    +		return 12;
    +	case MDOC_Ar:
    +		return 12;
    +	case MDOC_Bo:
    +		return 12;
    +	case MDOC_Bq:
    +		return 12;
    +	case MDOC_Cd:
    +		return 12;
    +	case MDOC_Cm:
    +		return 10;
    +	case MDOC_Do:
    +		return 10;
    +	case MDOC_Dq:
    +		return 12;
    +	case MDOC_Dv:
    +		return 12;
    +	case MDOC_Eo:
    +		return 12;
    +	case MDOC_Em:
    +		return 10;
    +	case MDOC_Er:
    +		return 17;
    +	case MDOC_Ev:
    +		return 15;
    +	case MDOC_Fa:
    +		return 12;
    +	case MDOC_Fl:
    +		return 10;
    +	case MDOC_Fo:
    +		return 16;
    +	case MDOC_Fn:
    +		return 16;
    +	case MDOC_Ic:
    +		return 10;
    +	case MDOC_Li:
    +		return 16;
    +	case MDOC_Ms:
    +		return 6;
    +	case MDOC_Nm:
    +		return 10;
    +	case MDOC_No:
    +		return 12;
    +	case MDOC_Oo:
    +		return 10;
    +	case MDOC_Op:
    +		return 14;
    +	case MDOC_Pa:
    +		return 32;
    +	case MDOC_Pf:
    +		return 12;
    +	case MDOC_Po:
    +		return 12;
    +	case MDOC_Pq:
    +		return 12;
    +	case MDOC_Ql:
    +		return 16;
    +	case MDOC_Qo:
    +		return 12;
    +	case MDOC_So:
    +		return 12;
    +	case MDOC_Sq:
    +		return 12;
    +	case MDOC_Sy:
    +		return 6;
    +	case MDOC_Sx:
    +		return 16;
    +	case MDOC_Tn:
    +		return 10;
    +	case MDOC_Va:
    +		return 12;
    +	case MDOC_Vt:
    +		return 12;
    +	case MDOC_Xr:
    +		return 10;
    +	default:
    +		break;
    +	};
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/mdoc_validate.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/out.h
    ===================================================================
    --- head/contrib/mandoc/out.h	(nonexistent)
    +++ head/contrib/mandoc/out.h	(revision 338826)
    @@ -0,0 +1,67 @@
    +/*	$Id: out.h,v 1.32 2018/06/25 16:54:59 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * 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	roffscale {
    +	SCALE_CM, /* centimeters (c) */
    +	SCALE_IN, /* inches (i) */
    +	SCALE_PC, /* pica (P) */
    +	SCALE_PT, /* points (p) */
    +	SCALE_EM, /* ems (m) */
    +	SCALE_MM, /* mini-ems (M) */
    +	SCALE_EN, /* ens (n) */
    +	SCALE_BU, /* default horizontal (u) */
    +	SCALE_VS, /* default vertical (v) */
    +	SCALE_FS, /* syn. for u (f) */
    +	SCALE_MAX
    +};
    +
    +struct	roffcol {
    +	size_t		 width; /* width of cell */
    +	size_t		 decimal; /* decimal position in cell */
    +	size_t		 spacing; /* spacing after the column */
    +	int		 flags; /* layout flags, see tbl_cell */
    +};
    +
    +struct	roffsu {
    +	enum roffscale	  unit;
    +	double		  scale;
    +};
    +
    +typedef	size_t	(*tbl_sulen)(const struct roffsu *, void *);
    +typedef	size_t	(*tbl_strlen)(const char *, void *);
    +typedef	size_t	(*tbl_len)(size_t, void *);
    +
    +struct	rofftbl {
    +	tbl_sulen	 sulen; /* calculate scaling unit length */
    +	tbl_strlen	 slen; /* calculate string length */
    +	tbl_len		 len; /* produce width of empty space */
    +	struct roffcol	*cols; /* master column specifiers */
    +	void		*arg; /* passed to sulen, slen, and len */
    +};
    +
    +#define	SCALE_HS_INIT(p, v) \
    +	do { (p)->unit = SCALE_EN; \
    +	     (p)->scale = (v); } \
    +	while (/* CONSTCOND */ 0)
    +
    +
    +struct	tbl_span;
    +
    +const char	 *a2roffsu(const char *, struct roffsu *, enum roffscale);
    +void		  tblcalc(struct rofftbl *tbl,
    +			const struct tbl_span *, size_t, size_t);
    
    Property changes on: head/contrib/mandoc/out.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/read.c
    ===================================================================
    --- head/contrib/mandoc/read.c	(nonexistent)
    +++ head/contrib/mandoc/read.c	(revision 338826)
    @@ -0,0 +1,928 @@
    +/*	$Id: read.c,v 1.196 2018/07/28 18:34:15 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * 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 <sys/types.h>
    +#include <sys/mman.h>
    +#include <sys/stat.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <stdarg.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +#include <zlib.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "man.h"
    +#include "libmandoc.h"
    +
    +#define	REPARSE_LIMIT	1000
    +
    +struct	mparse {
    +	struct roff	 *roff; /* roff parser (!NULL) */
    +	struct roff_man	 *man; /* man parser */
    +	char		 *sodest; /* filename pointed to by .so */
    +	const char	 *file; /* filename of current input file */
    +	struct buf	 *primary; /* buffer currently being parsed */
    +	struct buf	 *secondary; /* preprocessed copy of input */
    +	const char	 *os_s; /* default operating system */
    +	mandocmsg	  mmsg; /* warning/error message handler */
    +	enum mandoclevel  file_status; /* status of current parse */
    +	enum mandocerr	  mmin; /* ignore messages below this */
    +	int		  options; /* parser options */
    +	int		  gzip; /* current input file is gzipped */
    +	int		  filenc; /* encoding of the current file */
    +	int		  reparse_count; /* finite interp. stack */
    +	int		  line; /* line number in the file */
    +};
    +
    +static	void	  choose_parser(struct mparse *);
    +static	void	  resize_buf(struct buf *, size_t);
    +static	int	  mparse_buf_r(struct mparse *, struct buf, size_t, int);
    +static	int	  read_whole_file(struct mparse *, const char *, int,
    +				struct buf *, int *);
    +static	void	  mparse_end(struct mparse *);
    +static	void	  mparse_parse_buffer(struct mparse *, struct buf,
    +			const char *);
    +
    +static	const enum mandocerr	mandoclimits[MANDOCLEVEL_MAX] = {
    +	MANDOCERR_OK,
    +	MANDOCERR_OK,
    +	MANDOCERR_WARNING,
    +	MANDOCERR_ERROR,
    +	MANDOCERR_UNSUPP,
    +	MANDOCERR_MAX,
    +	MANDOCERR_MAX
    +};
    +
    +static	const char * const	mandocerrs[MANDOCERR_MAX] = {
    +	"ok",
    +
    +	"base system convention",
    +
    +	"Mdocdate found",
    +	"Mdocdate missing",
    +	"unknown architecture",
    +	"operating system explicitly specified",
    +	"RCS id missing",
    +	"referenced manual not found",
    +
    +	"generic style suggestion",
    +
    +	"legacy man(7) date format",
    +	"normalizing date format to",
    +	"lower case character in document title",
    +	"duplicate RCS id",
    +	"possible typo in section name",
    +	"unterminated quoted argument",
    +	"useless macro",
    +	"consider using OS macro",
    +	"errnos out of order",
    +	"duplicate errno",
    +	"trailing delimiter",
    +	"no blank before trailing delimiter",
    +	"fill mode already enabled, skipping",
    +	"fill mode already disabled, skipping",
    +	"verbatim \"--\", maybe consider using \\(em",
    +	"function name without markup",
    +	"whitespace at end of input line",
    +	"bad comment style",
    +
    +	"generic warning",
    +
    +	/* related to the prologue */
    +	"missing manual title, using UNTITLED",
    +	"missing manual title, using \"\"",
    +	"missing manual section, using \"\"",
    +	"unknown manual section",
    +	"missing date, using today's date",
    +	"cannot parse date, using it verbatim",
    +	"date in the future, using it anyway",
    +	"missing Os macro, using \"\"",
    +	"late prologue macro",
    +	"prologue macros out of order",
    +
    +	/* related to document structure */
    +	".so is fragile, better use ln(1)",
    +	"no document body",
    +	"content before first section header",
    +	"first section is not \"NAME\"",
    +	"NAME section without Nm before Nd",
    +	"NAME section without description",
    +	"description not at the end of NAME",
    +	"bad NAME section content",
    +	"missing comma before name",
    +	"missing description line, using \"\"",
    +	"description line outside NAME section",
    +	"sections out of conventional order",
    +	"duplicate section title",
    +	"unexpected section",
    +	"cross reference to self",
    +	"unusual Xr order",
    +	"unusual Xr punctuation",
    +	"AUTHORS section without An macro",
    +
    +	/* related to macros and nesting */
    +	"obsolete macro",
    +	"macro neither callable nor escaped",
    +	"skipping paragraph macro",
    +	"moving paragraph macro out of list",
    +	"skipping no-space macro",
    +	"blocks badly nested",
    +	"nested displays are not portable",
    +	"moving content out of list",
    +	"first macro on line",
    +	"line scope broken",
    +	"skipping blank line in line scope",
    +
    +	/* related to missing macro arguments */
    +	"skipping empty request",
    +	"conditional request controls empty scope",
    +	"skipping empty macro",
    +	"empty block",
    +	"empty argument, using 0n",
    +	"missing display type, using -ragged",
    +	"list type is not the first argument",
    +	"missing -width in -tag list, using 6n",
    +	"missing utility name, using \"\"",
    +	"missing function name, using \"\"",
    +	"empty head in list item",
    +	"empty list item",
    +	"missing argument, using next line",
    +	"missing font type, using \\fR",
    +	"unknown font type, using \\fR",
    +	"nothing follows prefix",
    +	"empty reference block",
    +	"missing section argument",
    +	"missing -std argument, adding it",
    +	"missing option string, using \"\"",
    +	"missing resource identifier, using \"\"",
    +	"missing eqn box, using \"\"",
    +
    +	/* related to bad macro arguments */
    +	"duplicate argument",
    +	"skipping duplicate argument",
    +	"skipping duplicate display type",
    +	"skipping duplicate list type",
    +	"skipping -width argument",
    +	"wrong number of cells",
    +	"unknown AT&T UNIX version",
    +	"comma in function argument",
    +	"parenthesis in function name",
    +	"unknown library name",
    +	"invalid content in Rs block",
    +	"invalid Boolean argument",
    +	"unknown font, skipping request",
    +	"odd number of characters in request",
    +
    +	/* related to plain text */
    +	"blank line in fill mode, using .sp",
    +	"tab in filled text",
    +	"new sentence, new line",
    +	"invalid escape sequence",
    +	"undefined string, using \"\"",
    +
    +	/* related to tables */
    +	"tbl line starts with span",
    +	"tbl column starts with span",
    +	"skipping vertical bar in tbl layout",
    +
    +	"generic error",
    +
    +	/* related to tables */
    +	"non-alphabetic character in tbl options",
    +	"skipping unknown tbl option",
    +	"missing tbl option argument",
    +	"wrong tbl option argument size",
    +	"empty tbl layout",
    +	"invalid character in tbl layout",
    +	"unmatched parenthesis in tbl layout",
    +	"tbl without any data cells",
    +	"ignoring data in spanned tbl cell",
    +	"ignoring extra tbl data cells",
    +	"data block open at end of tbl",
    +
    +	/* related to document structure and macros */
    +	NULL,
    +	"duplicate prologue macro",
    +	"skipping late title macro",
    +	"input stack limit exceeded, infinite loop?",
    +	"skipping bad character",
    +	"skipping unknown macro",
    +	"skipping insecure request",
    +	"skipping item outside list",
    +	"skipping column outside column list",
    +	"skipping end of block that is not open",
    +	"fewer RS blocks open, skipping",
    +	"inserting missing end of block",
    +	"appending missing end of block",
    +
    +	/* related to request and macro arguments */
    +	"escaped character not allowed in a name",
    +	"NOT IMPLEMENTED: Bd -file",
    +	"skipping display without arguments",
    +	"missing list type, using -item",
    +	"argument is not numeric, using 1",
    +	"missing manual name, using \"\"",
    +	"uname(3) system call failed, using UNKNOWN",
    +	"unknown standard specifier",
    +	"skipping request without numeric argument",
    +	"NOT IMPLEMENTED: .so with absolute path or \"..\"",
    +	".so request failed",
    +	"skipping all arguments",
    +	"skipping excess arguments",
    +	"divide by zero",
    +
    +	"unsupported feature",
    +	"input too large",
    +	"unsupported control character",
    +	"unsupported roff request",
    +	"eqn delim option in tbl",
    +	"unsupported tbl layout modifier",
    +	"ignoring macro in table",
    +};
    +
    +static	const char * const	mandoclevels[MANDOCLEVEL_MAX] = {
    +	"SUCCESS",
    +	"STYLE",
    +	"WARNING",
    +	"ERROR",
    +	"UNSUPP",
    +	"BADARG",
    +	"SYSERR"
    +};
    +
    +
    +static void
    +resize_buf(struct buf *buf, size_t initial)
    +{
    +
    +	buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
    +	buf->buf = mandoc_realloc(buf->buf, buf->sz);
    +}
    +
    +static void
    +choose_parser(struct mparse *curp)
    +{
    +	char		*cp, *ep;
    +	int		 format;
    +
    +	/*
    +	 * If neither command line arguments -mdoc or -man select
    +	 * a parser nor the roff parser found a .Dd or .TH macro
    +	 * yet, look ahead in the main input buffer.
    +	 */
    +
    +	if ((format = roff_getformat(curp->roff)) == 0) {
    +		cp = curp->primary->buf;
    +		ep = cp + curp->primary->sz;
    +		while (cp < ep) {
    +			if (*cp == '.' || *cp == '\'') {
    +				cp++;
    +				if (cp[0] == 'D' && cp[1] == 'd') {
    +					format = MPARSE_MDOC;
    +					break;
    +				}
    +				if (cp[0] == 'T' && cp[1] == 'H') {
    +					format = MPARSE_MAN;
    +					break;
    +				}
    +			}
    +			cp = memchr(cp, '\n', ep - cp);
    +			if (cp == NULL)
    +				break;
    +			cp++;
    +		}
    +	}
    +
    +	if (format == MPARSE_MDOC) {
    +		curp->man->macroset = MACROSET_MDOC;
    +		if (curp->man->mdocmac == NULL)
    +			curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
    +	} else {
    +		curp->man->macroset = MACROSET_MAN;
    +		if (curp->man->manmac == NULL)
    +			curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
    +	}
    +	curp->man->first->tok = TOKEN_NONE;
    +}
    +
    +/*
    + * Main parse routine for a buffer.
    + * It assumes encoding and line numbering are already set up.
    + * It can recurse directly (for invocations of user-defined
    + * macros, inline equations, and input line traps)
    + * and indirectly (for .so file inclusion).
    + */
    +static int
    +mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
    +{
    +	struct buf	 ln;
    +	const char	*save_file;
    +	char		*cp;
    +	size_t		 pos; /* byte number in the ln buffer */
    +	enum rofferr	 rr;
    +	int		 of;
    +	int		 lnn; /* line number in the real file */
    +	int		 fd;
    +	unsigned char	 c;
    +
    +	memset(&ln, 0, sizeof(ln));
    +
    +	lnn = curp->line;
    +	pos = 0;
    +
    +	while (i < blk.sz) {
    +		if (0 == pos && '\0' == blk.buf[i])
    +			break;
    +
    +		if (start) {
    +			curp->line = lnn;
    +			curp->reparse_count = 0;
    +
    +			if (lnn < 3 &&
    +			    curp->filenc & MPARSE_UTF8 &&
    +			    curp->filenc & MPARSE_LATIN1)
    +				curp->filenc = preconv_cue(&blk, i);
    +		}
    +
    +		while (i < blk.sz && (start || blk.buf[i] != '\0')) {
    +
    +			/*
    +			 * When finding an unescaped newline character,
    +			 * leave the character loop to process the line.
    +			 * Skip a preceding carriage return, if any.
    +			 */
    +
    +			if ('\r' == blk.buf[i] && i + 1 < blk.sz &&
    +			    '\n' == blk.buf[i + 1])
    +				++i;
    +			if ('\n' == blk.buf[i]) {
    +				++i;
    +				++lnn;
    +				break;
    +			}
    +
    +			/*
    +			 * Make sure we have space for the worst
    +			 * case of 11 bytes: "\\[u10ffff]\0"
    +			 */
    +
    +			if (pos + 11 > ln.sz)
    +				resize_buf(&ln, 256);
    +
    +			/*
    +			 * Encode 8-bit input.
    +			 */
    +
    +			c = blk.buf[i];
    +			if (c & 0x80) {
    +				if ( ! (curp->filenc && preconv_encode(
    +				    &blk, &i, &ln, &pos, &curp->filenc))) {
    +					mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
    +					    curp->line, pos, "0x%x", c);
    +					ln.buf[pos++] = '?';
    +					i++;
    +				}
    +				continue;
    +			}
    +
    +			/*
    +			 * Exclude control characters.
    +			 */
    +
    +			if (c == 0x7f || (c < 0x20 && c != 0x09)) {
    +				mandoc_vmsg(c == 0x00 || c == 0x04 ||
    +				    c > 0x0a ? MANDOCERR_CHAR_BAD :
    +				    MANDOCERR_CHAR_UNSUPP,
    +				    curp, curp->line, pos, "0x%x", c);
    +				i++;
    +				if (c != '\r')
    +					ln.buf[pos++] = '?';
    +				continue;
    +			}
    +
    +			ln.buf[pos++] = blk.buf[i++];
    +		}
    +
    +		if (pos + 1 >= ln.sz)
    +			resize_buf(&ln, 256);
    +
    +		if (i == blk.sz || blk.buf[i] == '\0')
    +			ln.buf[pos++] = '\n';
    +		ln.buf[pos] = '\0';
    +
    +		/*
    +		 * A significant amount of complexity is contained by
    +		 * the roff preprocessor.  It's line-oriented but can be
    +		 * expressed on one line, so we need at times to
    +		 * readjust our starting point and re-run it.  The roff
    +		 * preprocessor can also readjust the buffers with new
    +		 * data, so we pass them in wholesale.
    +		 */
    +
    +		of = 0;
    +
    +		/*
    +		 * Maintain a lookaside buffer of all parsed lines.  We
    +		 * only do this if mparse_keep() has been invoked (the
    +		 * buffer may be accessed with mparse_getkeep()).
    +		 */
    +
    +		if (curp->secondary) {
    +			curp->secondary->buf = mandoc_realloc(
    +			    curp->secondary->buf,
    +			    curp->secondary->sz + pos + 2);
    +			memcpy(curp->secondary->buf +
    +			    curp->secondary->sz,
    +			    ln.buf, pos);
    +			curp->secondary->sz += pos;
    +			curp->secondary->buf
    +				[curp->secondary->sz] = '\n';
    +			curp->secondary->sz++;
    +			curp->secondary->buf
    +				[curp->secondary->sz] = '\0';
    +		}
    +rerun:
    +		rr = roff_parseln(curp->roff, curp->line, &ln, &of);
    +
    +		switch (rr) {
    +		case ROFF_REPARSE:
    +			if (++curp->reparse_count > REPARSE_LIMIT)
    +				mandoc_msg(MANDOCERR_ROFFLOOP, curp,
    +				    curp->line, pos, NULL);
    +			else if (mparse_buf_r(curp, ln, of, 0) == 1 ||
    +			    start == 1) {
    +				pos = 0;
    +				continue;
    +			}
    +			free(ln.buf);
    +			return 0;
    +		case ROFF_APPEND:
    +			pos = strlen(ln.buf);
    +			continue;
    +		case ROFF_RERUN:
    +			goto rerun;
    +		case ROFF_IGN:
    +			pos = 0;
    +			continue;
    +		case ROFF_SO:
    +			if ( ! (curp->options & MPARSE_SO) &&
    +			    (i >= blk.sz || blk.buf[i] == '\0')) {
    +				curp->sodest = mandoc_strdup(ln.buf + of);
    +				free(ln.buf);
    +				return 1;
    +			}
    +			/*
    +			 * We remove `so' clauses from our lookaside
    +			 * buffer because we're going to descend into
    +			 * the file recursively.
    +			 */
    +			if (curp->secondary)
    +				curp->secondary->sz -= pos + 1;
    +			save_file = curp->file;
    +			if ((fd = mparse_open(curp, ln.buf + of)) != -1) {
    +				mparse_readfd(curp, fd, ln.buf + of);
    +				close(fd);
    +				curp->file = save_file;
    +			} else {
    +				curp->file = save_file;
    +				mandoc_vmsg(MANDOCERR_SO_FAIL,
    +				    curp, curp->line, pos,
    +				    ".so %s", ln.buf + of);
    +				ln.sz = mandoc_asprintf(&cp,
    +				    ".sp\nSee the file %s.\n.sp",
    +				    ln.buf + of);
    +				free(ln.buf);
    +				ln.buf = cp;
    +				of = 0;
    +				mparse_buf_r(curp, ln, of, 0);
    +			}
    +			pos = 0;
    +			continue;
    +		default:
    +			break;
    +		}
    +
    +		if (curp->man->macroset == MACROSET_NONE)
    +			choose_parser(curp);
    +
    +		if ((curp->man->macroset == MACROSET_MDOC ?
    +		    mdoc_parseln(curp->man, curp->line, ln.buf, of) :
    +		    man_parseln(curp->man, curp->line, ln.buf, of)) == 2)
    +				break;
    +
    +		/* Temporary buffers typically are not full. */
    +
    +		if (0 == start && '\0' == blk.buf[i])
    +			break;
    +
    +		/* Start the next input line. */
    +
    +		pos = 0;
    +	}
    +
    +	free(ln.buf);
    +	return 1;
    +}
    +
    +static int
    +read_whole_file(struct mparse *curp, const char *file, int fd,
    +		struct buf *fb, int *with_mmap)
    +{
    +	struct stat	 st;
    +	gzFile		 gz;
    +	size_t		 off;
    +	ssize_t		 ssz;
    +	int		 gzerrnum, retval;
    +
    +	if (fstat(fd, &st) == -1) {
    +		mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
    +		    "fstat: %s", strerror(errno));
    +		return 0;
    +	}
    +
    +	/*
    +	 * If we're a regular file, try just reading in the whole entry
    +	 * via mmap().  This is faster than reading it into blocks, and
    +	 * since each file is only a few bytes to begin with, I'm not
    +	 * concerned that this is going to tank any machines.
    +	 */
    +
    +	if (curp->gzip == 0 && S_ISREG(st.st_mode)) {
    +		if (st.st_size > 0x7fffffff) {
    +			mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
    +			return 0;
    +		}
    +		*with_mmap = 1;
    +		fb->sz = (size_t)st.st_size;
    +		fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
    +		if (fb->buf != MAP_FAILED)
    +			return 1;
    +	}
    +
    +	if (curp->gzip) {
    +		/*
    +		 * Duplicating the file descriptor is required
    +		 * because we will have to call gzclose(3)
    +		 * to free memory used internally by zlib,
    +		 * but that will also close the file descriptor,
    +		 * which this function must not do.
    +		 */
    +		if ((fd = dup(fd)) == -1) {
    +			mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
    +			    "dup: %s", strerror(errno));
    +			return 0;
    +		}
    +		if ((gz = gzdopen(fd, "rb")) == NULL) {
    +			mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
    +			    "gzdopen: %s", strerror(errno));
    +			close(fd);
    +			return 0;
    +		}
    +	} else
    +		gz = NULL;
    +
    +	/*
    +	 * If this isn't a regular file (like, say, stdin), then we must
    +	 * go the old way and just read things in bit by bit.
    +	 */
    +
    +	*with_mmap = 0;
    +	off = 0;
    +	retval = 0;
    +	fb->sz = 0;
    +	fb->buf = NULL;
    +	for (;;) {
    +		if (off == fb->sz) {
    +			if (fb->sz == (1U << 31)) {
    +				mandoc_msg(MANDOCERR_TOOLARGE, curp,
    +				    0, 0, NULL);
    +				break;
    +			}
    +			resize_buf(fb, 65536);
    +		}
    +		ssz = curp->gzip ?
    +		    gzread(gz, fb->buf + (int)off, fb->sz - off) :
    +		    read(fd, fb->buf + (int)off, fb->sz - off);
    +		if (ssz == 0) {
    +			fb->sz = off;
    +			retval = 1;
    +			break;
    +		}
    +		if (ssz == -1) {
    +			if (curp->gzip)
    +				(void)gzerror(gz, &gzerrnum);
    +			mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "read: %s",
    +			    curp->gzip && gzerrnum != Z_ERRNO ?
    +			    zError(gzerrnum) : strerror(errno));
    +			break;
    +		}
    +		off += (size_t)ssz;
    +	}
    +
    +	if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK)
    +		mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "gzclose: %s",
    +		    gzerrnum == Z_ERRNO ? strerror(errno) :
    +		    zError(gzerrnum));
    +	if (retval == 0) {
    +		free(fb->buf);
    +		fb->buf = NULL;
    +	}
    +	return retval;
    +}
    +
    +static void
    +mparse_end(struct mparse *curp)
    +{
    +	if (curp->man->macroset == MACROSET_NONE)
    +		curp->man->macroset = MACROSET_MAN;
    +	if (curp->man->macroset == MACROSET_MDOC)
    +		mdoc_endparse(curp->man);
    +	else
    +		man_endparse(curp->man);
    +	roff_endparse(curp->roff);
    +}
    +
    +static void
    +mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
    +{
    +	struct buf	*svprimary;
    +	const char	*svfile;
    +	size_t		 offset;
    +	static int	 recursion_depth;
    +
    +	if (64 < recursion_depth) {
    +		mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL);
    +		return;
    +	}
    +
    +	/* Line number is per-file. */
    +	svfile = curp->file;
    +	curp->file = file;
    +	svprimary = curp->primary;
    +	curp->primary = &blk;
    +	curp->line = 1;
    +	recursion_depth++;
    +
    +	/* Skip an UTF-8 byte order mark. */
    +	if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 &&
    +	    (unsigned char)blk.buf[0] == 0xef &&
    +	    (unsigned char)blk.buf[1] == 0xbb &&
    +	    (unsigned char)blk.buf[2] == 0xbf) {
    +		offset = 3;
    +		curp->filenc &= ~MPARSE_LATIN1;
    +	} else
    +		offset = 0;
    +
    +	mparse_buf_r(curp, blk, offset, 1);
    +
    +	if (--recursion_depth == 0)
    +		mparse_end(curp);
    +
    +	curp->primary = svprimary;
    +	curp->file = svfile;
    +}
    +
    +enum mandoclevel
    +mparse_readmem(struct mparse *curp, void *buf, size_t len,
    +		const char *file)
    +{
    +	struct buf blk;
    +
    +	blk.buf = buf;
    +	blk.sz = len;
    +
    +	mparse_parse_buffer(curp, blk, file);
    +	return curp->file_status;
    +}
    +
    +/*
    + * Read the whole file into memory and call the parsers.
    + * Called recursively when an .so request is encountered.
    + */
    +enum mandoclevel
    +mparse_readfd(struct mparse *curp, int fd, const char *file)
    +{
    +	struct buf	 blk;
    +	int		 with_mmap;
    +	int		 save_filenc;
    +
    +	if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
    +		save_filenc = curp->filenc;
    +		curp->filenc = curp->options &
    +		    (MPARSE_UTF8 | MPARSE_LATIN1);
    +		mparse_parse_buffer(curp, blk, file);
    +		curp->filenc = save_filenc;
    +		if (with_mmap)
    +			munmap(blk.buf, blk.sz);
    +		else
    +			free(blk.buf);
    +	}
    +	return curp->file_status;
    +}
    +
    +int
    +mparse_open(struct mparse *curp, const char *file)
    +{
    +	char		 *cp;
    +	int		  fd;
    +
    +	curp->file = file;
    +	cp = strrchr(file, '.');
    +	curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
    +
    +	/* First try to use the filename as it is. */
    +
    +	if ((fd = open(file, O_RDONLY)) != -1)
    +		return fd;
    +
    +	/*
    +	 * If that doesn't work and the filename doesn't
    +	 * already  end in .gz, try appending .gz.
    +	 */
    +
    +	if ( ! curp->gzip) {
    +		mandoc_asprintf(&cp, "%s.gz", file);
    +		fd = open(cp, O_RDONLY);
    +		free(cp);
    +		if (fd != -1) {
    +			curp->gzip = 1;
    +			return fd;
    +		}
    +	}
    +
    +	/* Neither worked, give up. */
    +
    +	mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
    +	return -1;
    +}
    +
    +struct mparse *
    +mparse_alloc(int options, enum mandocerr mmin, mandocmsg mmsg,
    +    enum mandoc_os os_e, const char *os_s)
    +{
    +	struct mparse	*curp;
    +
    +	curp = mandoc_calloc(1, sizeof(struct mparse));
    +
    +	curp->options = options;
    +	curp->mmin = mmin;
    +	curp->mmsg = mmsg;
    +	curp->os_s = os_s;
    +
    +	curp->roff = roff_alloc(curp, options);
    +	curp->man = roff_man_alloc(curp->roff, curp, curp->os_s,
    +		curp->options & MPARSE_QUICK ? 1 : 0);
    +	if (curp->options & MPARSE_MDOC) {
    +		curp->man->macroset = MACROSET_MDOC;
    +		if (curp->man->mdocmac == NULL)
    +			curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
    +	} else if (curp->options & MPARSE_MAN) {
    +		curp->man->macroset = MACROSET_MAN;
    +		if (curp->man->manmac == NULL)
    +			curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
    +	}
    +	curp->man->first->tok = TOKEN_NONE;
    +	curp->man->meta.os_e = os_e;
    +	return curp;
    +}
    +
    +void
    +mparse_reset(struct mparse *curp)
    +{
    +	roff_reset(curp->roff);
    +	roff_man_reset(curp->man);
    +
    +	free(curp->sodest);
    +	curp->sodest = NULL;
    +
    +	if (curp->secondary)
    +		curp->secondary->sz = 0;
    +
    +	curp->file_status = MANDOCLEVEL_OK;
    +	curp->gzip = 0;
    +}
    +
    +void
    +mparse_free(struct mparse *curp)
    +{
    +
    +	roffhash_free(curp->man->mdocmac);
    +	roffhash_free(curp->man->manmac);
    +	roff_man_free(curp->man);
    +	roff_free(curp->roff);
    +	if (curp->secondary)
    +		free(curp->secondary->buf);
    +
    +	free(curp->secondary);
    +	free(curp->sodest);
    +	free(curp);
    +}
    +
    +void
    +mparse_result(struct mparse *curp, struct roff_man **man,
    +	char **sodest)
    +{
    +
    +	if (sodest && NULL != (*sodest = curp->sodest)) {
    +		*man = NULL;
    +		return;
    +	}
    +	if (man)
    +		*man = curp->man;
    +}
    +
    +void
    +mparse_updaterc(struct mparse *curp, enum mandoclevel *rc)
    +{
    +	if (curp->file_status > *rc)
    +		*rc = curp->file_status;
    +}
    +
    +void
    +mandoc_vmsg(enum mandocerr t, struct mparse *m,
    +		int ln, int pos, const char *fmt, ...)
    +{
    +	char		 buf[256];
    +	va_list		 ap;
    +
    +	va_start(ap, fmt);
    +	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
    +	va_end(ap);
    +
    +	mandoc_msg(t, m, ln, pos, buf);
    +}
    +
    +void
    +mandoc_msg(enum mandocerr er, struct mparse *m,
    +		int ln, int col, const char *msg)
    +{
    +	enum mandoclevel level;
    +
    +	if (er < m->mmin && er != MANDOCERR_FILE)
    +		return;
    +
    +	level = MANDOCLEVEL_UNSUPP;
    +	while (er < mandoclimits[level])
    +		level--;
    +
    +	if (m->mmsg)
    +		(*m->mmsg)(er, level, m->file, ln, col, msg);
    +
    +	if (m->file_status < level)
    +		m->file_status = level;
    +}
    +
    +const char *
    +mparse_strerror(enum mandocerr er)
    +{
    +
    +	return mandocerrs[er];
    +}
    +
    +const char *
    +mparse_strlevel(enum mandoclevel lvl)
    +{
    +	return mandoclevels[lvl];
    +}
    +
    +void
    +mparse_keep(struct mparse *p)
    +{
    +
    +	assert(NULL == p->secondary);
    +	p->secondary = mandoc_calloc(1, sizeof(struct buf));
    +}
    +
    +const char *
    +mparse_getkeep(const struct mparse *p)
    +{
    +
    +	assert(p->secondary);
    +	return p->secondary->sz ? p->secondary->buf : NULL;
    +}
    
    Property changes on: head/contrib/mandoc/read.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/roff.7
    ===================================================================
    --- head/contrib/mandoc/roff.7	(nonexistent)
    +++ head/contrib/mandoc/roff.7	(revision 338826)
    @@ -0,0 +1,2202 @@
    +.\"	$Id: roff.7,v 1.96 2018/04/10 00:52:30 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
    +.\" Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE 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: April 10 2018 $
    +.Dt ROFF 7
    +.Os
    +.Sh NAME
    +.Nm roff
    +.Nd roff language reference for mandoc
    +.Sh DESCRIPTION
    +The
    +.Nm roff
    +language is a general purpose text formatting language.
    +Since traditional implementations of the
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +manual formatting languages are based on it,
    +many real-world manuals use small numbers of
    +.Nm
    +requests and escape sequences intermixed with their
    +.Xr mdoc 7
    +or
    +.Xr man 7
    +code.
    +To properly format such manuals, the
    +.Xr mandoc 1
    +utility supports a tiny subset of
    +.Nm
    +requests and escapes.
    +Only these requests and escapes supported by
    +.Xr mandoc 1
    +are documented in the present manual,
    +together with the basic language syntax shared by
    +.Nm ,
    +.Xr mdoc 7 ,
    +and
    +.Xr man 7 .
    +For complete
    +.Nm
    +manuals, consult the
    +.Sx SEE ALSO
    +section.
    +.Pp
    +Input lines beginning with the control character
    +.Sq \&.
    +are parsed for requests and macros.
    +Such lines are called
    +.Dq request lines
    +or
    +.Dq macro lines ,
    +respectively.
    +Requests change the processing state and manipulate the formatting;
    +some macros also define the document structure and produce formatted
    +output.
    +The single quote
    +.Pq Qq \(aq
    +is accepted as an alternative control character,
    +treated by
    +.Xr mandoc 1
    +just like
    +.Ql \&.
    +.Pp
    +Lines not beginning with control characters are called
    +.Dq text lines .
    +They provide free-form text to be printed; the formatting of the text
    +depends on the respective processing context.
    +.Sh LANGUAGE SYNTAX
    +.Nm
    +documents may contain only graphable 7-bit ASCII characters, the space
    +character, and, in certain circumstances, the tab character.
    +The backslash character
    +.Sq \e
    +indicates the start of an escape sequence, used for example for
    +.Sx Comments ,
    +.Sx Special Characters ,
    +.Sx Predefined Strings ,
    +and
    +user-defined strings defined using the
    +.Sx ds
    +request.
    +For a listing of escape sequences, consult the
    +.Sx ESCAPE SEQUENCE REFERENCE
    +below.
    +.Ss Comments
    +Text following an escaped double-quote
    +.Sq \e\(dq ,
    +whether in a request, macro, or text line, is ignored to the end of the line.
    +A request line beginning with a control character and comment escape
    +.Sq \&.\e\(dq
    +is also ignored.
    +Furthermore, request lines with only a control character and optional
    +trailing whitespace are stripped from input.
    +.Pp
    +Examples:
    +.Bd -literal -offset indent -compact
    +\&.\e\(dq This is a comment line.
    +\&.\e\(dq The next line is ignored:
    +\&.
    +\&.Sh EXAMPLES \e\(dq This is a comment, too.
    +\&example text \e\(dq And so is this.
    +.Ed
    +.Ss Special Characters
    +Special characters are used to encode special glyphs and are rendered
    +differently across output media.
    +They may occur in request, macro, and text lines.
    +Sequences begin with the escape character
    +.Sq \e
    +followed by either an open-parenthesis
    +.Sq \&(
    +for two-character sequences; an open-bracket
    +.Sq \&[
    +for n-character sequences (terminated at a close-bracket
    +.Sq \&] ) ;
    +or a single one character sequence.
    +.Pp
    +Examples:
    +.Bl -tag -width Ds -offset indent -compact
    +.It Li \e(em
    +Two-letter em dash escape.
    +.It Li \ee
    +One-letter backslash escape.
    +.El
    +.Pp
    +See
    +.Xr mandoc_char 7
    +for a complete list.
    +.Ss Text Decoration
    +Terms may be text-decorated using the
    +.Sq \ef
    +escape followed by an indicator: B (bold), I (italic), R (regular), or P
    +(revert to previous mode).
    +A numerical representation 3, 2, or 1 (bold, italic, and regular,
    +respectively) may be used instead.
    +The indicator or numerical representative may be preceded by C
    +(constant-width), which is ignored.
    +.Pp
    +The two-character indicator
    +.Sq BI
    +requests a font that is both bold and italic.
    +It may not be portable to old roff implementations.
    +.Pp
    +Examples:
    +.Bl -tag -width Ds -offset indent -compact
    +.It Li \efBbold\efR
    +Write in \fBbold\fP, then switch to regular font mode.
    +.It Li \efIitalic\efP
    +Write in \fIitalic\fP, then return to previous font mode.
    +.It Li \ef(BIbold italic\efP
    +Write in \f(BIbold italic\fP, then return to previous font mode.
    +.El
    +.Pp
    +Text decoration is
    +.Em not
    +recommended for
    +.Xr mdoc 7 ,
    +which encourages semantic annotation.
    +.Ss Predefined Strings
    +Predefined strings, like
    +.Sx Special Characters ,
    +mark special output glyphs.
    +Predefined strings are escaped with the slash-asterisk,
    +.Sq \e* :
    +single-character
    +.Sq \e*X ,
    +two-character
    +.Sq \e*(XX ,
    +and N-character
    +.Sq \e* Ns Bq N .
    +.Pp
    +Examples:
    +.Bl -tag -width Ds -offset indent -compact
    +.It Li \e*(Am
    +Two-letter ampersand predefined string.
    +.It Li \e*q
    +One-letter double-quote predefined string.
    +.El
    +.Pp
    +Predefined strings are not recommended for use,
    +as they differ across implementations.
    +Those supported by
    +.Xr mandoc 1
    +are listed in
    +.Xr mandoc_char 7 .
    +Manuals using these predefined strings are almost certainly not portable.
    +.Ss Whitespace
    +Whitespace consists of the space character.
    +In text lines, whitespace is preserved within a line.
    +In request and macro lines, whitespace delimits arguments and is discarded.
    +.Pp
    +Unescaped trailing spaces are stripped from text line input unless in a
    +literal context.
    +In general, trailing whitespace on any input line is discouraged for
    +reasons of portability.
    +In the rare case that a blank character is needed at the end of an
    +input line, it may be forced by
    +.Sq \e\ \e& .
    +.Pp
    +Literal space characters can be produced in the output
    +using escape sequences.
    +In macro lines, they can also be included in arguments using quotation; see
    +.Sx MACRO SYNTAX
    +for details.
    +.Pp
    +Blank text lines, which may include whitespace, are only permitted
    +within literal contexts.
    +If the first character of a text line is a space, that line is printed
    +with a leading newline.
    +.Ss Scaling Widths
    +Many requests and macros support scaled widths for their arguments.
    +The syntax for a scaled width is
    +.Sq Li [+-]?[0-9]*.[0-9]*[:unit:] ,
    +where a decimal must be preceded or followed by at least one digit.
    +Negative numbers, while accepted, are truncated to zero.
    +.Pp
    +The following scaling units are accepted:
    +.Pp
    +.Bl -tag -width Ds -offset indent -compact
    +.It c
    +centimetre
    +.It i
    +inch
    +.It P
    +pica (~1/6 inch)
    +.It p
    +point (~1/72 inch)
    +.It f
    +scale
    +.Sq u
    +by 65536
    +.It v
    +default vertical span
    +.It m
    +width of rendered
    +.Sq m
    +.Pq em
    +character
    +.It n
    +width of rendered
    +.Sq n
    +.Pq en
    +character
    +.It u
    +default horizontal span for the terminal
    +.It M
    +mini-em (~1/100 em)
    +.El
    +.Pp
    +Using anything other than
    +.Sq m ,
    +.Sq n ,
    +or
    +.Sq v
    +is necessarily non-portable across output media.
    +See
    +.Sx COMPATIBILITY .
    +.Pp
    +If a scaling unit is not provided, the numerical value is interpreted
    +under the default rules of
    +.Sq v
    +for vertical spaces and
    +.Sq u
    +for horizontal ones.
    +.Pp
    +Examples:
    +.Bl -tag -width ".Bl -tag -width 2i" -offset indent -compact
    +.It Li \&.Bl -tag -width 2i
    +two-inch tagged list indentation in
    +.Xr mdoc 7
    +.It Li \&.HP 2i
    +two-inch tagged list indentation in
    +.Xr man 7
    +.It Li \&.sp 2v
    +two vertical spaces
    +.El
    +.Ss Sentence Spacing
    +Each sentence should terminate at the end of an input line.
    +By doing this, a formatter will be able to apply the proper amount of
    +spacing after the end of sentence (unescaped) period, exclamation mark,
    +or question mark followed by zero or more non-sentence closing
    +delimiters
    +.Po
    +.Sq \&) ,
    +.Sq \&] ,
    +.Sq \&' ,
    +.Sq \&"
    +.Pc .
    +.Pp
    +The proper spacing is also intelligently preserved if a sentence ends at
    +the boundary of a macro line.
    +.Pp
    +Examples:
    +.Bd -literal -offset indent -compact
    +Do not end sentences mid-line like this.  Instead,
    +end a sentence like this.
    +A macro would end like this:
    +\&.Xr mandoc 1 \&.
    +.Ed
    +.Sh REQUEST SYNTAX
    +A request or macro line consists of:
    +.Pp
    +.Bl -enum -compact
    +.It
    +the control character
    +.Sq \&.
    +or
    +.Sq \(aq
    +at the beginning of the line,
    +.It
    +optionally an arbitrary amount of whitespace,
    +.It
    +the name of the request or the macro, which is one word of arbitrary
    +length, terminated by whitespace,
    +.It
    +and zero or more arguments delimited by whitespace.
    +.El
    +.Pp
    +Thus, the following request lines are all equivalent:
    +.Bd -literal -offset indent
    +\&.ig end
    +\&.ig    end
    +\&.   ig end
    +.Ed
    +.Sh MACRO SYNTAX
    +Macros are provided by the
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +languages and can be defined by the
    +.Sx \&de
    +request.
    +When called, they follow the same syntax as requests, except that
    +macro arguments may optionally be quoted by enclosing them
    +in double quote characters
    +.Pq Sq \(dq .
    +Quoted text, even if it contains whitespace or would cause
    +a macro invocation when unquoted, is always considered literal text.
    +Inside quoted text, pairs of double quote characters
    +.Pq Sq Qq
    +resolve to single double quote characters.
    +.Pp
    +To be recognised as the beginning of a quoted argument, the opening
    +quote character must be preceded by a space character.
    +A quoted argument extends to the next double quote character that is not
    +part of a pair, or to the end of the input line, whichever comes earlier.
    +Leaving out the terminating double quote character at the end of the line
    +is discouraged.
    +For clarity, if more arguments follow on the same input line,
    +it is recommended to follow the terminating double quote character
    +by a space character; in case the next character after the terminating
    +double quote character is anything else, it is regarded as the beginning
    +of the next, unquoted argument.
    +.Pp
    +Both in quoted and unquoted arguments, pairs of backslashes
    +.Pq Sq \e\e
    +resolve to single backslashes.
    +In unquoted arguments, space characters can alternatively be included
    +by preceding them with a backslash
    +.Pq Sq \e\~ ,
    +but quoting is usually better for clarity.
    +.Pp
    +Examples:
    +.Bl -tag -width Ds -offset indent -compact
    +.It Li .Fn strlen \(dqconst char *s\(dq
    +Group arguments
    +.Qq const char *s
    +into one function argument.
    +If unspecified,
    +.Qq const ,
    +.Qq char ,
    +and
    +.Qq *s
    +would be considered separate arguments.
    +.It Li .Op \(dqFl a\(dq
    +Consider
    +.Qq \&Fl a
    +as literal text instead of a flag macro.
    +.El
    +.Sh REQUEST REFERENCE
    +The
    +.Xr mandoc 1
    +.Nm
    +parser recognises the following requests.
    +For requests marked as "ignored" or "unsupported", any arguments are
    +ignored, and the number of arguments is not checked.
    +.Bl -tag -width Ds
    +.It Ic \&ab Op Ar message
    +Abort processing.
    +Currently unsupported.
    +.It Ic \&ad Op Cm b | c | l | n | r
    +Set line adjustment mode for subsequent text.
    +Currently ignored.
    +.It Ic \&af Ar registername format
    +Assign an output format to a number register.
    +Currently ignored.
    +.It Ic \&aln Ar newname oldname
    +Create an alias for a number register.
    +Currently unsupported.
    +.It Ic \&als Ar newname oldname
    +Create an alias for a request, string, macro, or diversion.
    +.It Ic \&am Ar macroname Op Ar endmacro
    +Append to a macro definition.
    +The syntax of this request is the same as that of
    +.Ic \&de .
    +.It Ic \&am1 Ar macroname Op Ar endmacro
    +Append to a macro definition, switching roff compatibility mode off
    +during macro execution (groff extension).
    +The syntax of this request is the same as that of
    +.Ic \&de1 .
    +Since
    +.Xr mandoc 1
    +does not implement
    +.Nm
    +compatibility mode at all, it handles this request as an alias for
    +.Ic \&am .
    +.It Ic \&ami Ar macrostring Op Ar endstring
    +Append to a macro definition, specifying the macro name indirectly
    +(groff extension).
    +The syntax of this request is the same as that of
    +.Ic \&dei .
    +.It Ic \&ami1 Ar macrostring Op Ar endstring
    +Append to a macro definition, specifying the macro name indirectly
    +and switching roff compatibility mode off during macro execution
    +(groff extension).
    +The syntax of this request is the same as that of
    +.Ic \&dei1 .
    +Since
    +.Xr mandoc 1
    +does not implement
    +.Nm
    +compatibility mode at all, it handles this request as an alias for
    +.Ic \&ami .
    +.It Ic \&as Ar stringname Op Ar string
    +Append to a user-defined string.
    +The syntax of this request is the same as that of
    +.Sx \&ds .
    +If a user-defined string with the specified name does not yet exist,
    +it is set to the empty string before appending.
    +.It Ic \&as1 Ar stringname Op Ar string
    +Append to a user-defined string, switching roff compatibility mode off
    +during macro execution (groff extension).
    +The syntax of this request is the same as that of
    +.Ic \&ds1 .
    +Since
    +.Xr mandoc 1
    +does not implement
    +.Nm
    +compatibility mode at all, it handles this request as an alias for
    +.Ic \&as .
    +.It Ic \&asciify Ar divname
    +Fully unformat a diversion.
    +Currently unsupported.
    +.It Ic \&backtrace
    +Print a backtrace of the input stack.
    +This is a groff extension and currently ignored.
    +.It Ic \&bd Ar font Oo Ar curfont Oc Op Ar offset
    +Artificially embolden by repeated printing with small shifts.
    +Currently ignored.
    +.It Ic \&bleedat Ar left top width height
    +Set the BleedBox page parameter for PDF generation.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&blm Ar macroname
    +Set a blank line trap.
    +Currently unsupported.
    +.It Ic \&box Ar divname
    +Begin a diversion without including a partially filled line.
    +Currently unsupported.
    +.It Ic \&boxa Ar divname
    +Add to a diversion without including a partially filled line.
    +Currently unsupported.
    +.It Ic \&bp Oo Cm + Ns | Ns Cm - Oc Ns Ar pagenumber
    +Begin a new page.
    +Currently ignored.
    +.It Ic \&BP Ar source height width position offset flags label
    +Define a frame and place a picture in it.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&br
    +Break the output line.
    +.It Ic \&break
    +Break out of a
    +.Ic \&while
    +loop.
    +Currently unsupported.
    +.It Ic \&breakchar Ar char ...
    +Optional line break characters.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&brnl Ar N
    +Break output line after the next
    +.Ar N
    +input lines.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&brp
    +Break and spread output line.
    +Currently, this is implemented as an alias for
    +.Ic \&br .
    +.It Ic \&brpnl Ar N
    +Break and spread output line after the next
    +.Ar N
    +input lines.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&c2 Op Ar char
    +Change the no-break control character.
    +Currently unsupported.
    +.It Ic \&cc Op Ar char
    +Change the control character.
    +If
    +.Ar char
    +is not specified, the control character is reset to
    +.Sq \&. .
    +Trailing characters are ignored.
    +.It Ic \&ce Op Ar N
    +Center the next
    +.Ar N
    +input lines without filling.
    +.Ar N
    +defaults to 1.
    +An argument of 0 or less ends centering.
    +Currently, high level macros abort centering.
    +.It Ic \&cf Ar filename
    +Output the contents of a file.
    +Ignored because insecure.
    +.It Ic \&cflags Ar flags char ...
    +Set character flags.
    +This is a groff extension and currently ignored.
    +.It Ic \&ch Ar macroname Op Ar dist
    +Change a trap location.
    +Currently ignored.
    +.It Ic \&char Ar glyphname Op Ar string
    +Define a new glyph.
    +Currently unsupported.
    +.It Ic \&chop Ar stringname
    +Remove the last character from a macro, string, or diversion.
    +Currently unsupported.
    +.It Ic \&class Ar classname char ...
    +Define a character class.
    +This is a groff extension and currently ignored.
    +.It Ic \&close Ar streamname
    +Close an open file.
    +Ignored because insecure.
    +.It Ic \&CL Ar color text
    +Print text in color.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&color Op Cm 1 | 0
    +Activate or deactivate colors.
    +This is a groff extension and currently ignored.
    +.It Ic \&composite Ar from to
    +Define a name component for composite glyph names.
    +This is a groff extension and currently unsupported.
    +.It Ic \&continue
    +Immediately start the next iteration of a
    +.Ic \&while
    +loop.
    +Currently unsupported.
    +.It Ic \&cp Op Cm 1 | 0
    +Switch
    +.Nm
    +compatibility mode on or off.
    +Currently ignored.
    +.It Ic \&cropat Ar left top width height
    +Set the CropBox page parameter for PDF generation.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&cs Ar font Op Ar width Op Ar emsize
    +Constant character spacing mode.
    +Currently ignored.
    +.It Ic \&cu Op Ar N
    +Underline next
    +.Ar N
    +input lines including whitespace.
    +Currently ignored.
    +.It Ic \&da Ar divname
    +Append to a diversion.
    +Currently unsupported.
    +.It Ic \&dch Ar macroname Op Ar dist
    +Change a trap location in the current diversion.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&de Ar macroname Op Ar endmacro
    +Define a
    +.Nm
    +macro.
    +Its syntax can be either
    +.Bd -literal -offset indent
    +.Pf . Ic \&de Ar macroname
    +.Ar definition
    +\&..
    +.Ed
    +.Pp
    +or
    +.Bd -literal -offset indent
    +.Pf . Ic \&de Ar macroname Ar endmacro
    +.Ar definition
    +.Pf . Ar endmacro
    +.Ed
    +.Pp
    +Both forms define or redefine the macro
    +.Ar macroname
    +to represent the
    +.Ar definition ,
    +which may consist of one or more input lines, including the newline
    +characters terminating each line, optionally containing calls to
    +.Nm
    +requests,
    +.Nm
    +macros or high-level macros like
    +.Xr man 7
    +or
    +.Xr mdoc 7
    +macros, whichever applies to the document in question.
    +.Pp
    +Specifying a custom
    +.Ar endmacro
    +macro works in the same way as for
    +.Ic \&ig ;
    +namely, the call to
    +.Sq Pf . Ar endmacro
    +first ends the
    +.Ar definition ,
    +and after that, it is also evaluated as a
    +.Nm
    +request or
    +.Nm
    +macro, but not as a high-level macro.
    +.Pp
    +The macro can be invoked later using the syntax
    +.Pp
    +.D1 Pf . Ar macroname Op Ar argument Op Ar argument ...
    +.Pp
    +Regarding argument parsing, see
    +.Sx MACRO SYNTAX
    +above.
    +.Pp
    +The line invoking the macro will be replaced
    +in the input stream by the
    +.Ar definition ,
    +replacing all occurrences of
    +.No \e\e$ Ns Ar N ,
    +where
    +.Ar N
    +is a digit, by the
    +.Ar N Ns th Ar argument .
    +For example,
    +.Bd -literal -offset indent
    +\&.de ZN
    +\efI\e^\e\e$1\e^\efP\e\e$2
    +\&..
    +\&.ZN XtFree .
    +.Ed
    +.Pp
    +produces
    +.Pp
    +.D1 \efI\e^XtFree\e^\efP.
    +.Pp
    +in the input stream, and thus in the output: \fI\^XtFree\^\fP.
    +Each occurrence of \e\e$* is replaced with all the arguments,
    +joined together with single blank characters.
    +.Pp
    +Since macros and user-defined strings share a common string table,
    +defining a macro
    +.Ar macroname
    +clobbers the user-defined string
    +.Ar macroname ,
    +and the
    +.Ar definition
    +can also be printed using the
    +.Sq \e*
    +string interpolation syntax described below
    +.Ic ds ,
    +but this is rarely useful because every macro definition contains at least
    +one explicit newline character.
    +.Pp
    +In order to prevent endless recursion, both groff and
    +.Xr mandoc 1
    +limit the stack depth for expanding macros and strings
    +to a large, but finite number, and
    +.Xr mandoc 1
    +also limits the length of the expanded input line.
    +Do not rely on the exact values of these limits.
    +.It Ic \&de1 Ar macroname Op Ar endmacro
    +Define a
    +.Nm
    +macro that will be executed with
    +.Nm
    +compatibility mode switched off during macro execution.
    +This is a groff extension.
    +Since
    +.Xr mandoc 1
    +does not implement
    +.Nm
    +compatibility mode at all, it handles this request as an alias for
    +.Ic \&de .
    +.It Ic \&defcolor Ar newname scheme component ...
    +Define a color name.
    +This is a groff extension and currently ignored.
    +.It Ic \&dei Ar macrostring Op Ar endstring
    +Define a
    +.Nm
    +macro, specifying the macro name indirectly (groff extension).
    +The syntax of this request is the same as that of
    +.Ic \&de .
    +The effect is the same as:
    +.Pp
    +.D1 Pf . Cm \&de No \e* Ns Bo Ar macrostring Bc Op \e* Ns Bq Ar endstring
    +.It Ic \&dei1 Ar macrostring Op Ar endstring
    +Define a
    +.Nm
    +macro that will be executed with
    +.Nm
    +compatibility mode switched off during macro execution,
    +specifying the macro name indirectly (groff extension).
    +Since
    +.Xr mandoc 1
    +does not implement
    +.Nm
    +compatibility mode at all, it handles this request as an alias for
    +.Ic \&dei .
    +.It Ic \&device Ar string ...
    +.It Ic \&devicem Ar stringname
    +These two requests only make sense with the groff-specific intermediate
    +output format and are unsupported.
    +.It Ic \&di Ar divname
    +Begin a diversion.
    +Currently unsupported.
    +.It Ic \&do Ar command Op Ar argument ...
    +Execute
    +.Nm
    +request or macro line with compatibility mode disabled.
    +Currently unsupported.
    +.It Ic \&ds Ar stringname Op Oo \(dq Oc Ns Ar string
    +Define a user-defined string.
    +The
    +.Ar stringname
    +and
    +.Ar string
    +arguments are space-separated.
    +If the
    +.Ar string
    +begins with a double-quote character, that character will not be part
    +of the string.
    +All remaining characters on the input line form the
    +.Ar string ,
    +including whitespace and double-quote characters, even trailing ones.
    +.Pp
    +The
    +.Ar string
    +can be interpolated into subsequent text by using
    +.No \e* Ns Bq Ar stringname
    +for a
    +.Ar stringname
    +of arbitrary length, or \e*(NN or \e*N if the length of
    +.Ar stringname
    +is two or one characters, respectively.
    +Interpolation can be prevented by escaping the leading backslash;
    +that is, an asterisk preceded by an even number of backslashes
    +does not trigger string interpolation.
    +.Pp
    +Since user-defined strings and macros share a common string table,
    +defining a string
    +.Ar stringname
    +clobbers the macro
    +.Ar stringname ,
    +and the
    +.Ar stringname
    +used for defining a string can also be invoked as a macro,
    +in which case the following input line will be appended to the
    +.Ar string ,
    +forming a new input line passed to the
    +.Nm
    +parser.
    +For example,
    +.Bd -literal -offset indent
    +\&.ds badidea .S
    +\&.badidea
    +H SYNOPSIS
    +.Ed
    +.Pp
    +invokes the
    +.Ic SH
    +macro when used in a
    +.Xr man 7
    +document.
    +Such abuse is of course strongly discouraged.
    +.It Ic \&ds1 Ar stringname Op Oo \(dq Oc Ns Ar string
    +Define a user-defined string that will be expanded with
    +.Nm
    +compatibility mode switched off during string expansion.
    +This is a groff extension.
    +Since
    +.Xr mandoc 1
    +does not implement
    +.Nm
    +compatibility mode at all, it handles this request as an alias for
    +.Ic \&ds .
    +.It Ic \&dwh Ar dist macroname
    +Set a location trap in the current diversion.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&dt Op Ar dist macroname
    +Set a trap within a diversion.
    +Currently unsupported.
    +.It Ic \&ec Op Ar char
    +Enable the escape mechanism and change the escape character.
    +The
    +.Ar char
    +argument defaults to the backslash
    +.Pq Sq \e .
    +.It Ic \&ecr
    +Restore the escape character.
    +Currently unsupported.
    +.It Ic \&ecs
    +Save the escape character.
    +Currently unsupported.
    +.It Ic \&el Ar body
    +The
    +.Dq else
    +half of an if/else conditional.
    +Pops a result off the stack of conditional evaluations pushed by
    +.Ic \&ie
    +and uses it as its conditional.
    +If no stack entries are present (e.g., due to no prior
    +.Ic \&ie
    +calls)
    +then false is assumed.
    +The syntax of this request is similar to
    +.Ic \&if
    +except that the conditional is missing.
    +.It Ic \&em Ar macroname
    +Set a trap at the end of input.
    +Currently unsupported.
    +.It Ic \&EN
    +End an equation block.
    +See
    +.Ic \&EQ .
    +.It Ic \&eo
    +Disable the escape mechanism completely.
    +.It Ic \&EP
    +End a picture started by
    +.Ic \&BP .
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&EQ
    +Begin an equation block.
    +See
    +.Xr eqn 7
    +for a description of the equation language.
    +.It Ic \&errprint Ar message
    +Print a string like an error message.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&ev Op Ar envname
    +Switch to another environment.
    +Currently unsupported.
    +.It Ic \&evc Op Ar envname
    +Copy an environment into the current environment.
    +Currently unsupported.
    +.It Ic \&ex
    +Abort processing and exit.
    +Currently unsupported.
    +.It Ic \&fallback Ar curfont font ...
    +Select the fallback sequence for a font.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&fam Op Ar familyname
    +Change the font family.
    +This is a groff extension and currently ignored.
    +.It Ic \&fc Op Ar delimchar Op Ar padchar
    +Define a delimiting and a padding character for fields.
    +Currently unsupported.
    +.It Ic \&fchar Ar glyphname Op Ar string
    +Define a fallback glyph.
    +Currently unsupported.
    +.It Ic \&fcolor Ar colorname
    +Set the fill color for \eD objects.
    +This is a groff extension and currently ignored.
    +.It Ic \&fdeferlig Ar font string ...
    +Defer ligature building.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&feature Cm + Ns | Ns Cm - Ns Ar name
    +Enable or disable an OpenType feature.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&fi
    +Switch to fill mode.
    +See
    +.Xr man 7 .
    +Ignored in
    +.Xr mdoc 7 .
    +.It Ic \&fkern Ar font minkern
    +Control the use of kerning tables for a font.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&fl
    +Flush output.
    +Currently ignored.
    +.It Ic \&flig Ar font string char ...
    +Define ligatures.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&fp Ar position font Op Ar filename
    +Assign font position.
    +Currently ignored.
    +.It Ic \&fps Ar mapname ...
    +Mount a font with a special character map.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&fschar Ar font glyphname Op Ar string
    +Define a font-specific fallback glyph.
    +This is a groff extension and currently unsupported.
    +.It Ic \&fspacewidth Ar font Op Ar afmunits
    +Set a font-specific width for the space character.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&fspecial Ar curfont Op Ar font ...
    +Conditionally define a special font.
    +This is a groff extension and currently ignored.
    +.It Ic \&ft Op Ar font
    +Change the font.
    +The following
    +.Ar font
    +arguments are supported:
    +.Bl -tag -width 4n -offset indent
    +.It Cm B , BI , 3 , 4
    +switches to
    +.Sy bold
    +font
    +.It Cm I , 2
    +switches to
    +.Em underlined
    +font
    +.It Cm R , CW , 1
    +switches to normal font
    +.It Cm P No "or no argument"
    +switches back to the previous font
    +.El
    +.Pp
    +This request takes effect only locally and may be overridden
    +by macros and escape sequences.
    +.It Ic \&ftr Ar newname Op Ar oldname
    +Translate font name.
    +This is a groff extension and currently ignored.
    +.It Ic \&fzoom Ar font Op Ar permille
    +Zoom font size.
    +Currently ignored.
    +.It Ic \&gcolor Op Ar colorname
    +Set glyph color.
    +This is a groff extension and currently ignored.
    +.It Ic \&hc Op Ar char
    +Set the hyphenation character.
    +Currently ignored.
    +.It Ic \&hcode Ar char code ...
    +Set hyphenation codes of characters.
    +Currently ignored.
    +.It Ic \&hidechar Ar font char ...
    +Hide characters in a font.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&hla Ar language
    +Set hyphenation language.
    +This is a groff extension and currently ignored.
    +.It Ic \&hlm Op Ar number
    +Set maximum number of consecutive hyphenated lines.
    +Currently ignored.
    +.It Ic \&hpf Ar filename
    +Load hyphenation pattern file.
    +This is a groff extension and currently ignored.
    +.It Ic \&hpfa Ar filename
    +Load hyphenation pattern file, appending to the current patterns.
    +This is a groff extension and currently ignored.
    +.It Ic \&hpfcode Ar code code ...
    +Define mapping values for character codes in hyphenation patterns.
    +This is a groff extension and currently ignored.
    +.It Ic \&hw Ar word ...
    +Specify hyphenation points in words.
    +Currently ignored.
    +.It Ic \&hy Op Ar mode
    +Set automatic hyphenation mode.
    +Currently ignored.
    +.It Ic \&hylang Ar language
    +Set hyphenation language.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&hylen Ar nchar
    +Minimum word length for hyphenation.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&hym Op Ar length
    +Set hyphenation margin.
    +This is a groff extension and currently ignored.
    +.It Ic \&hypp Ar penalty ...
    +Define hyphenation penalties.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&hys Op Ar length
    +Set hyphenation space.
    +This is a groff extension and currently ignored.
    +.It Ic \&ie Ar condition body
    +The
    +.Dq if
    +half of an if/else conditional.
    +The result of the conditional is pushed into a stack used by subsequent
    +invocations of
    +.Ic \&el ,
    +which may be separated by any intervening input (or not exist at all).
    +Its syntax is equivalent to
    +.Ic \&if .
    +.It Ic \&if Ar condition body
    +Begin a conditional.
    +This request can also be written as follows:
    +.Bd -unfilled -offset indent
    +.Pf . Ic \&if Ar condition No \e{ Ns Ar body
    +.Ar body ... Ns \e}
    +.Ed
    +.Bd -unfilled -offset indent
    +.Pf . Ic \&if Ar condition No \e{\e
    +.Ar body ...
    +.Pf . No \e}
    +.Ed
    +.Pp
    +The
    +.Ar condition
    +is a boolean expression.
    +Currently,
    +.Xr mandoc 1
    +supports the following subset of roff conditionals:
    +.Bl -bullet
    +.It
    +If
    +.Sq \&!
    +is prefixed to
    +.Ar condition ,
    +it is logically inverted.
    +.It
    +If the first character of
    +.Ar condition
    +is
    +.Sq n
    +.Pq nroff mode
    +or
    +.Sq o
    +.Pq odd page ,
    +it evaluates to true.
    +.It
    +If the first character of
    +.Ar condition
    +is
    +.Sq c
    +.Pq character available ,
    +.Sq e
    +.Pq even page ,
    +.Sq t
    +.Pq troff mode ,
    +or
    +.Sq v
    +.Pq vroff mode ,
    +it evaluates to false.
    +.It
    +If the first character of
    +.Ar condition
    +is
    +.Sq d ,
    +it evaluates to true if the rest of
    +.Ar condition
    +is the name of an existing user defined macro or string;
    +otherwise, it evaluates to false.
    +.It
    +If the first character of
    +.Ar condition
    +is
    +.Sq r ,
    +it evaluates to true if the rest of
    +.Ar condition
    +is the name of an existing number register;
    +otherwise, it evaluates to false.
    +.It
    +If the
    +.Ar condition
    +starts with a parenthesis or with an optionally signed
    +integer number, it is evaluated according to the rules of
    +.Sx Numerical expressions
    +explained below.
    +It evaluates to true if the result is positive,
    +or to false if the result is zero or negative.
    +.It
    +Otherwise, the first character of
    +.Ar condition
    +is regarded as a delimiter and it evaluates to true if the string
    +extending from its first to its second occurrence is equal to the
    +string extending from its second to its third occurrence.
    +.It
    +If
    +.Ar condition
    +cannot be parsed, it evaluates to false.
    +.El
    +.Pp
    +If a conditional is false, its children are not processed, but are
    +syntactically interpreted to preserve the integrity of the input
    +document.
    +Thus,
    +.Pp
    +.D1 \&.if t .ig
    +.Pp
    +will discard the
    +.Sq \&.ig ,
    +which may lead to interesting results, but
    +.Pp
    +.D1 \&.if t .if t \e{\e
    +.Pp
    +will continue to syntactically interpret to the block close of the final
    +conditional.
    +Sub-conditionals, in this case, obviously inherit the truth value of
    +the parent.
    +.Pp
    +If the
    +.Ar body
    +section is begun by an escaped brace
    +.Sq \e{ ,
    +scope continues until the end of the input line containing the
    +matching closing-brace escape sequence
    +.Sq \e} .
    +If the
    +.Ar body
    +is not enclosed in braces, scope continues until the end of the line.
    +If the
    +.Ar condition
    +is followed by a
    +.Ar body
    +on the same line, whether after a brace or not, then requests and macros
    +.Em must
    +begin with a control character.
    +It is generally more intuitive, in this case, to write
    +.Bd -unfilled -offset indent
    +.Pf . Ic \&if Ar condition No \e{\e
    +.Pf . Ar request
    +.Pf . No \e}
    +.Ed
    +.Pp
    +than having the request or macro follow as
    +.Pp
    +.D1 Pf . Ic \&if Ar condition Pf \e{. Ar request
    +.Pp
    +The scope of a conditional is always parsed, but only executed if the
    +conditional evaluates to true.
    +.Pp
    +Note that the
    +.Sq \e}
    +is converted into a zero-width escape sequence if not passed as a
    +standalone macro
    +.Sq \&.\e} .
    +For example,
    +.Pp
    +.D1 \&.Fl a \e} b
    +.Pp
    +will result in
    +.Sq \e}
    +being considered an argument of the
    +.Sq \&Fl
    +macro.
    +.It Ic \&ig Op Ar endmacro
    +Ignore input.
    +Its syntax can be either
    +.Bd -literal -offset indent
    +.Pf . Cm \&ig
    +.Ar ignored text
    +\&..
    +.Ed
    +.Pp
    +or
    +.Bd -literal -offset indent
    +.Pf . Cm \&ig Ar endmacro
    +.Ar ignored text
    +.Pf . Ar endmacro
    +.Ed
    +.Pp
    +In the first case, input is ignored until a
    +.Sq \&..
    +request is encountered on its own line.
    +In the second case, input is ignored until the specified
    +.Sq Pf . Ar endmacro
    +is encountered.
    +Do not use the escape character
    +.Sq \e
    +anywhere in the definition of
    +.Ar endmacro ;
    +it would cause very strange behaviour.
    +.Pp
    +When the
    +.Ar endmacro
    +is a roff request or a roff macro, like in
    +.Pp
    +.D1 \&.ig if
    +.Pp
    +the subsequent invocation of
    +.Ic \&if
    +will first terminate the
    +.Ar ignored text ,
    +then be invoked as usual.
    +Otherwise, it only terminates the
    +.Ar ignored text ,
    +and arguments following it or the
    +.Sq \&..
    +request are discarded.
    +.It Ic \&in Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width
    +Change indentation.
    +See
    +.Xr man 7 .
    +Ignored in
    +.Xr mdoc 7 .
    +.It Ic \&index Ar register stringname substring
    +Find a substring in a string.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&it Ar expression macro
    +Set an input line trap.
    +The named
    +.Ar macro
    +will be invoked after processing the number of input text lines
    +specified by the numerical
    +.Ar expression .
    +While evaluating the
    +.Ar expression ,
    +the unit suffixes described below
    +.Sx Scaling Widths
    +are ignored.
    +.It Ic \&it Ar expression macro
    +Set an input line trap, not counting lines ending with \ec.
    +Currently unsupported.
    +.It Ic \&IX Ar class keystring
    +To support the generation of a table of contents,
    +.Xr pod2man 1
    +emits this user-defined macro, usually without defining it.
    +To avoid reporting large numbers of spurious errors,
    +.Xr mandoc 1
    +ignores it.
    +.It Ic \&kern Op Cm 1 | 0
    +Switch kerning on or off.
    +Currently ignored.
    +.It Ic \&kernafter Ar font char ... afmunits ...
    +Increase kerning after some characters.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&kernbefore Ar font char ... afmunits ...
    +Increase kerning before some characters.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&kernpair Ar font char ... font char ... afmunits
    +Add a kerning pair to the kerning table.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&lc Op Ar glyph
    +Define a leader repetition character.
    +Currently unsupported.
    +.It Ic \&lc_ctype Ar localename
    +Set the
    +.Dv LC_CTYPE
    +locale.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&lds Ar macroname string
    +Define a local string.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&length Ar register string
    +Count the number of input characters in a string.
    +Currently unsupported.
    +.It Ic \&letadj Ar lspmin lshmin letss lspmax lshmax
    +Dynamic letter spacing and reshaping.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&lf Ar lineno Op Ar filename
    +Change the line number for error messages.
    +Ignored because insecure.
    +.It Ic \&lg Op Cm 1 | 0
    +Switch the ligature mechanism on or off.
    +Currently ignored.
    +.It Ic \&lhang Ar font char ... afmunits
    +Hang characters at left margin.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&linetabs Op Cm 1 | 0
    +Enable or disable line-tabs mode.
    +This is a groff extension and currently unsupported.
    +.It Ic \&ll Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width
    +Change the output line length.
    +If the
    +.Ar width
    +argument is omitted, the line length is reset to its previous value.
    +The default setting for terminal output is 78n.
    +If a sign is given, the line length is added to or subtracted from;
    +otherwise, it is set to the provided value.
    +Using this request in new manuals is discouraged for several reasons,
    +among others because it overrides the
    +.Xr mandoc 1
    +.Fl O Cm width
    +command line option.
    +.It Ic \&lnr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar value Op Ar increment
    +Set local number register.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&lnrf Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar value Op Ar increment
    +Set local floating-point register.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&lpfx Ar string
    +Set a line prefix.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&ls Op Ar factor
    +Set line spacing.
    +It takes one integer argument specifying the vertical distance of
    +subsequent output text lines measured in v units.
    +Currently ignored.
    +.It Ic \&lsm Ar macroname
    +Set a leading spaces trap.
    +This is a groff extension and currently unsupported.
    +.It Ic \< Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width
    +Set title line length.
    +Currently ignored.
    +.It Ic \&mc Ar glyph Op Ar dist
    +Print margin character in the right margin.
    +The
    +.Ar dist
    +is currently ignored; instead, 1n is used.
    +.It Ic \&mediasize Ar media
    +Set the device media size.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&minss Ar width
    +Set minimum word space.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&mk Op Ar register
    +Mark vertical position.
    +Currently ignored.
    +.It Ic \&mso Ar filename
    +Load a macro file using the search path.
    +Ignored because insecure.
    +.It Ic \&na
    +Disable adjusting without changing the adjustment mode.
    +Currently ignored.
    +.It Ic \&ne Op Ar height
    +Declare the need for the specified minimum vertical space
    +before the next trap or the bottom of the page.
    +Currently ignored.
    +.It Ic \&nf
    +Switch to no-fill mode.
    +See
    +.Xr man 7 .
    +Ignored by
    +.Xr mdoc 7 .
    +.It Ic \&nh
    +Turn off automatic hyphenation mode.
    +Currently ignored.
    +.It Ic \&nhychar Ar char ...
    +Define hyphenation-inhibiting characters.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&nm Op Ar start Op Ar inc Op Ar space Op Ar indent
    +Print line numbers.
    +Currently unsupported.
    +.It Ic \&nn Op Ar number
    +Temporarily turn off line numbering.
    +Currently unsupported.
    +.It Ic \&nop Ar body
    +Execute the rest of the input line as a request or macro line.
    +Currently unsupported.
    +.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression Op Ar stepsize
    +Define or change a register.
    +A register is an arbitrary string value that defines some sort of state,
    +which influences parsing and/or formatting.
    +For the syntax of
    +.Ar expression ,
    +see
    +.Sx Numerical expressions
    +below.
    +If it is prefixed by a sign, the register will be
    +incremented or decremented instead of assigned to.
    +.Pp
    +The
    +.Ar stepsize
    +is used by the
    +.Ic \en+
    +auto-increment feature.
    +It remains unchanged when omitted while changing an existing register,
    +and it defaults to 0 when defining a new register.
    +.Pp
    +The following
    +.Ar register
    +is handled specially:
    +.Bl -tag -width Ds
    +.It Cm nS
    +If set to a positive integer value, certain
    +.Xr mdoc 7
    +macros will behave in the same way as in the
    +.Em SYNOPSIS
    +section.
    +If set to 0, these macros will behave in the same way as outside the
    +.Em SYNOPSIS
    +section, even when called within the
    +.Em SYNOPSIS
    +section itself.
    +Note that starting a new
    +.Xr mdoc 7
    +section with the
    +.Ic \&Sh
    +macro will reset this register.
    +.El
    +.It Xo
    +.Ic \&nrf Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression
    +.Op Ar increment
    +.Xc
    +Define or change a floating-point register.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&nroff
    +Force nroff mode.
    +This is a groff extension and currently ignored.
    +.It Ic \&ns
    +Turn on no-space mode.
    +Currently ignored.
    +.It Ic \&nx Op Ar filename
    +Abort processing of the current input file and process another one.
    +Ignored because insecure.
    +.It Ic \&open Ar stream file
    +Open a file for writing.
    +Ignored because insecure.
    +.It Ic \&opena Ar stream file
    +Open a file for appending.
    +Ignored because insecure.
    +.It Ic \&os
    +Output saved vertical space.
    +Currently ignored.
    +.It Ic \&output Ar string
    +Output directly to intermediate output.
    +Not supported.
    +.It Ic \&padj Op Cm 1 | 0
    +Globally control paragraph-at-once adjustment.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&papersize Ar media
    +Set the paper size.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&pc Op Ar char
    +Change the page number character.
    +Currently ignored.
    +.It Ic \&pev
    +Print environments.
    +This is a groff extension and currently ignored.
    +.It Ic \&pi Ar command
    +Pipe output to a shell command.
    +Ignored because insecure.
    +.It Ic \&PI
    +Low-level request used by
    +.Ic \&BP .
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&pl Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height
    +Change page length.
    +Currently ignored.
    +.It Ic \&pm
    +Print names and sizes of macros, strings, and diversions
    +to standard error output.
    +Currently ignored.
    +.It Ic \&pn Oo Cm + Ns | Ns Cm - Oc Ns Ar number
    +Change the page number of the next page.
    +Currently ignored.
    +.It Ic \&pnr
    +Print all number registers on standard error output.
    +Currently ignored.
    +.It Ic \&po Op Oo Cm + Ns | Ns Cm - Oc Ns Ar offset
    +Set a horizontal page offset.
    +If no argument is specified, the page offset is reverted to its
    +previous value.
    +If a sign is specified, the new page offset is calculated relative
    +to the current one; otherwise, it is absolute.
    +The argument follows the syntax of
    +.Sx Scaling Widths
    +and the default scaling unit is
    +.Cm m .
    +.It Ic \&ps Op Oo Cm + Ns | Ns Cm - Oc Ns size
    +Change point size.
    +Currently ignored.
    +.It Ic \&psbb Ar filename
    +Retrieve the bounding box of a PostScript file.
    +Currently unsupported.
    +.It Ic \&pshape Ar indent length ...
    +Set a special shape for the current paragraph.
    +This is a Heirloom extension and currently unsupported.
    +.It Ic \&pso Ar command
    +Include output of a shell command.
    +Ignored because insecure.
    +.It Ic \&ptr
    +Print the names and positions of all traps on standard error output.
    +This is a groff extension and currently ignored.
    +.It Ic \&pvs Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height
    +Change post-vertical spacing.
    +This is a groff extension and currently ignored.
    +.It Ic \&rchar Ar glyph ...
    +Remove glyph definitions.
    +Currently unsupported.
    +.It Ic \&rd Op Ar prompt Op Ar argument ...
    +Read from standard input.
    +Currently ignored.
    +.It Ic \&recursionlimit Ar maxrec maxtail
    +Set the maximum stack depth for recursive macros.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&return Op Ar twice
    +Exit a macro and return to the caller.
    +Currently unsupported.
    +.It Ic \&rfschar Ar font glyph ...
    +Remove font-specific fallback glyph definitions.
    +Currently unsupported.
    +.It Ic \&rhang Ar font char ... afmunits
    +Hang characters at right margin.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&rj Op Ar N
    +Justify the next
    +.Ar N
    +input lines to the right margin without filling.
    +.Ar N
    +defaults to 1.
    +An argument of 0 or less ends right adjustment.
    +.It Ic \&rm Ar macroname
    +Remove a request, macro or string.
    +.It Ic \&rn Ar oldname newname
    +Rename a request, macro, diversion, or string.
    +In
    +.Xr mandoc 1 ,
    +user-defined macros,
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +macros, and user-defined strings can be renamed, but renaming of
    +predefined strings and of
    +.Nm
    +requests is not supported, and diversions are not implemented at all.
    +.It Ic \&rnn Ar oldname newname
    +Rename a number register.
    +Currently unsupported.
    +.It Ic \&rr Ar register
    +Remove a register.
    +.It Ic \&rs
    +End no-space mode.
    +Currently ignored.
    +.It Ic \&rt Op Ar dist
    +Return to marked vertical position.
    +Currently ignored.
    +.It Ic \&schar Ar glyph Op Ar string
    +Define global fallback glyph.
    +This is a groff extension and currently unsupported.
    +.It Ic \&sentchar Ar char ...
    +Define sentence-ending characters.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&shc Op Ar glyph
    +Change the soft hyphen character.
    +Currently ignored.
    +.It Ic \&shift Op Ar number
    +Shift macro arguments.
    +Currently unsupported.
    +.It Ic \&sizes Ar size ...
    +Define permissible point sizes.
    +This is a groff extension and currently ignored.
    +.It Ic \&so Ar filename
    +Include a source file.
    +The file is read and its contents processed as input in place of the
    +.Ic \&so
    +request line.
    +To avoid inadvertent inclusion of unrelated files,
    +.Xr mandoc 1
    +only accepts relative paths not containing the strings
    +.Qq ../
    +and
    +.Qq /.. .
    +.Pp
    +This request requires
    +.Xr man 1
    +to change to the right directory before calling
    +.Xr mandoc 1 ,
    +per convention to the root of the manual tree.
    +Typical usage looks like:
    +.Pp
    +.Dl \&.so man3/Xcursor.3
    +.Pp
    +As the whole concept is rather fragile, the use of
    +.Ic \&so
    +is discouraged.
    +Use
    +.Xr ln 1
    +instead.
    +.It Ic \&sp Op Ar height
    +Break the output line and emit vertical space.
    +The argument follows the syntax of
    +.Sx Scaling Widths
    +and defaults to one blank line
    +.Pq Li 1v .
    +.It Ic \&spacewidth Op Cm 1 | 0
    +Set the space width from the font metrics file.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&special Op Ar font ...
    +Define a special font.
    +This is a groff extension and currently ignored.
    +.It Ic \&spreadwarn Op Ar width
    +Warn about wide spacing between words.
    +Currently ignored.
    +.It Ic \&ss Ar wordspace Op Ar sentencespace
    +Set space character size.
    +Currently ignored.
    +.It Ic \&sty Ar position style
    +Associate style with a font position.
    +This is a groff extension and currently ignored.
    +.It Ic \&substring Ar stringname startpos Op Ar endpos
    +Replace a user-defined string with a substring.
    +Currently unsupported.
    +.It Ic \&sv Op Ar height
    +Save vertical space.
    +Currently ignored.
    +.It Ic \&sy Ar command
    +Execute shell command.
    +Ignored because insecure.
    +.It Ic \&T&
    +Re-start a table layout, retaining the options of the prior table
    +invocation.
    +See
    +.Sx \&TS .
    +.It Ic \&ta Op Ar width ... Op Cm T Ar width ...
    +Set tab stops.
    +Each
    +.Ar width
    +argument follows the syntax of
    +.Sx Scaling Widths .
    +If prefixed by a plus sign, it is relative to the previous tab stop.
    +The arguments after the
    +.Cm T
    +marker are used repeatedly as often as needed; for each reuse,
    +they are taken relative to the last previously established tab stop.
    +When
    +.Ic \&ta
    +is called without arguments, all tab stops are cleared.
    +.It Ic \&tc Op Ar glyph
    +Change tab repetition character.
    +Currently unsupported.
    +.It Ic \&TE
    +End a table context.
    +See
    +.Sx \&TS .
    +.It Ic \&ti Oo Cm + Ns | Ns Cm - Oc Ns Ar width
    +Break the output line and indent the next output line by
    +.Ar width .
    +If a sign is specified, the temporary indentation is calculated
    +relative to the current indentation; otherwise, it is absolute.
    +The argument follows the syntax of
    +.Sx Scaling Widths
    +and the default scaling unit is
    +.Cm m .
    +.It Ic \&tkf Ar font minps width1 maxps width2
    +Enable track kerning for a font.
    +Currently ignored.
    +.It Ic \&tl No \& Ap Ar left Ap Ar center Ap Ar right Ap
    +Print a title line.
    +Currently unsupported.
    +.It Ic \&tm Ar string
    +Print to standard error output.
    +Currently ignored.
    +.It Ic \&tm1 Ar string
    +Print to standard error output, allowing leading blanks.
    +This is a groff extension and currently ignored.
    +.It Ic \&tmc Ar string
    +Print to standard error output without a trailing newline.
    +This is a groff extension and currently ignored.
    +.It Ic \&tr Ar glyph glyph ...
    +Output character translation.
    +The first glyph in each pair is replaced by the second one.
    +Character escapes can be used; for example,
    +.Pp
    +.Dl tr \e(xx\e(yy
    +.Pp
    +replaces all invocations of \e(xx with \e(yy.
    +.It Ic \&track Ar font minps width1 maxps width2
    +Static letter space tracking.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&transchar Ar char ...
    +Define transparent characters for sentence-ending.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&trf Ar filename
    +Output the contents of a file, disallowing invalid characters.
    +This is a groff extension and ignored because insecure.
    +.It Ic \&trimat Ar left top width height
    +Set the TrimBox page parameter for PDF generation.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&trin Ar glyph glyph ...
    +Output character translation, ignored by
    +.Ic \&asciify .
    +Currently unsupported.
    +.It Ic \&trnt Ar glyph glyph ...
    +Output character translation, ignored by \e!.
    +Currently unsupported.
    +.It Ic \&troff
    +Force troff mode.
    +This is a groff extension and currently ignored.
    +.It Ic \&TS
    +Begin a table, which formats input in aligned rows and columns.
    +See
    +.Xr tbl 7
    +for a description of the tbl language.
    +.It Ic \&uf Ar font
    +Globally set the underline font.
    +Currently ignored.
    +.It Ic \&ul Op Ar N
    +Underline next
    +.Ar N
    +input lines.
    +Currently ignored.
    +.It Ic \&unformat Ar divname
    +Unformat spaces and tabs in a diversion.
    +Currently unsupported.
    +.It Ic \&unwatch Ar macroname
    +Disable notification for string or macro.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&unwatchn Ar register
    +Disable notification for register.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&vpt Op Cm 1 | 0
    +Enable or disable vertical position traps.
    +This is a groff extension and currently ignored.
    +.It Ic \&vs Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height
    +Change vertical spacing.
    +Currently ignored.
    +.It Ic \&warn Ar flags
    +Set warning level.
    +Currently ignored.
    +.It Ic \&warnscale Ar si
    +Set the scaling indicator used in warnings.
    +This is a groff extension and currently ignored.
    +.It Ic \&watch Ar macroname
    +Notify on change of string or macro.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&watchlength Ar maxlength
    +On change, report the contents of macros and strings
    +up to the specified length.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&watchn Ar register
    +Notify on change of register.
    +This is a Heirloom extension and currently ignored.
    +.It Ic \&wh Ar dist Op Ar macroname
    +Set a page location trap.
    +Currently unsupported.
    +.It Ic \&while Ar condition body
    +Repeated execution while a condition is true.
    +Currently unsupported.
    +.It Ic \&write Oo \(dq Oc Ns Ar string
    +Write to an open file.
    +Ignored because insecure.
    +.It Ic \&writec Oo \(dq Oc Ns Ar string
    +Write to an open file without appending a newline.
    +Ignored because insecure.
    +.It Ic \&writem Ar macroname
    +Write macro or string to an open file.
    +Ignored because insecure.
    +.It Ic \&xflag Ar level
    +Set the extension level.
    +This is a Heirloom extension and currently ignored.
    +.El
    +.Ss Numerical expressions
    +The
    +.Sx \&nr ,
    +.Sx \&if ,
    +and
    +.Sx \&ie
    +requests accept integer numerical expressions as arguments.
    +These are always evaluated using the C
    +.Vt int
    +type; integer overflow works the same way as in the C language.
    +Numbers consist of an arbitrary number of digits
    +.Sq 0
    +to
    +.Sq 9
    +prefixed by an optional sign
    +.Sq +
    +or
    +.Sq - .
    +Each number may be followed by one optional scaling unit described below
    +.Sx Scaling Widths .
    +The following equations hold:
    +.Bd -literal -offset indent
    +1i = 6v = 6P = 10m = 10n = 72p = 1000M = 240u = 240
    +254c = 100i = 24000u = 24000
    +1f = 65536u = 65536
    +.Ed
    +.Pp
    +The following binary operators are implemented.
    +Unless otherwise stated, they behave as in the C language:
    +.Pp
    +.Bl -tag -width 2n -compact
    +.It Ic +
    +addition
    +.It Ic -
    +subtraction
    +.It Ic *
    +multiplication
    +.It Ic /
    +division
    +.It Ic %
    +remainder of division
    +.It Ic <
    +less than
    +.It Ic >
    +greater than
    +.It Ic ==
    +equal to
    +.It Ic =
    +equal to, same effect as
    +.Ic ==
    +(this differs from C)
    +.It Ic <=
    +less than or equal to
    +.It Ic >=
    +greater than or equal to
    +.It Ic <>
    +not equal to (corresponds to C
    +.Ic != ;
    +this one is of limited portability, it is supported by Heirloom roff,
    +but not by groff)
    +.It Ic &
    +logical and (corresponds to C
    +.Ic && )
    +.It Ic \&:
    +logical or (corresponds to C
    +.Ic || )
    +.It Ic <?
    +minimum (not available in C)
    +.It Ic >?
    +maximum (not available in C)
    +.El
    +.Pp
    +There is no concept of precedence; evaluation proceeds from left to right,
    +except when subexpressions are enclosed in parentheses.
    +Inside parentheses, whitespace is ignored.
    +.Sh ESCAPE SEQUENCE REFERENCE
    +The
    +.Xr mandoc 1
    +.Nm
    +parser recognises the following escape sequences.
    +Note that the
    +.Nm
    +language defines more escape sequences not implemented in
    +.Xr mandoc 1 .
    +In
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +documents, using escape sequences is discouraged except for those
    +described in the
    +.Sx LANGUAGE SYNTAX
    +section above.
    +.Pp
    +A backslash followed by any character not listed here
    +simply prints that character itself.
    +.Ss \e<newline>
    +A backslash at the end of an input line can be used to continue the
    +logical input line on the next physical input line, joining the text
    +on both lines together as if it were on a single input line.
    +.Ss \e<space>
    +The escape sequence backslash-space
    +.Pq Sq \e\ \&
    +is an unpaddable space-sized non-breaking space character; see
    +.Sx Whitespace .
    +.Ss \e\(dq
    +The rest of the input line is treated as
    +.Sx Comments .
    +.Ss \e%
    +Hyphenation allowed at this point of the word; ignored by
    +.Xr mandoc 1 .
    +.Ss \e&
    +Non-printing zero-width character; see
    +.Sx Whitespace .
    +.Ss \e\(aq
    +Acute accent special character; use
    +.Sq \e(aa
    +instead.
    +.Ss \e( Ns Ar cc
    +.Sx Special Characters
    +with two-letter names, see
    +.Xr mandoc_char 7 .
    +.Ss \e* Ns Bq Ar name
    +Interpolate the string with the
    +.Ar name ;
    +see
    +.Sx Predefined Strings
    +and
    +.Sx ds .
    +For short names, there are variants
    +.No \e* Ns Ar c
    +and
    +.No \e*( Ns Ar cc .
    +.Ss \e,
    +Left italic correction (groff extension); ignored by
    +.Xr mandoc 1 .
    +.Ss \e-
    +Special character
    +.Dq mathematical minus sign .
    +.Ss \e/
    +Right italic correction (groff extension); ignored by
    +.Xr mandoc 1 .
    +.Ss \e Ns Bq Ar name
    +.Sx Special Characters
    +with names of arbitrary length, see
    +.Xr mandoc_char 7 .
    +.Ss \e^
    +One-twelfth em half-narrow space character, effectively zero-width in
    +.Xr mandoc 1 .
    +.Ss \e`
    +Grave accent special character; use
    +.Sq \e(ga
    +instead.
    +.Ss \e{
    +Begin conditional input; see
    +.Sx if .
    +.Ss \e\(ba
    +One-sixth em narrow space character, effectively zero-width in
    +.Xr mandoc 1 .
    +.Ss \e}
    +End conditional input; see
    +.Sx if .
    +.Ss \e~
    +Paddable non-breaking space character.
    +.Ss \e0
    +Digit width space character.
    +.Ss \eA\(aq Ns Ar string Ns \(aq
    +Anchor definition; ignored by
    +.Xr mandoc 1 .
    +.Ss \eB\(aq Ns Ar string Ns \(aq
    +Interpolate
    +.Sq 1
    +if
    +.Ar string
    +conforms to the syntax of
    +.Sx Numerical expressions
    +explained above and
    +.Sq 0
    +otherwise.
    +.Ss \eb\(aq Ns Ar string Ns \(aq
    +Bracket building function; ignored by
    +.Xr mandoc 1 .
    +.Ss \eC\(aq Ns Ar name Ns \(aq
    +.Sx Special Characters
    +with names of arbitrary length.
    +.Ss \ec
    +When encountered at the end of an input text line,
    +the next input text line is considered to continue that line,
    +even if there are request or macro lines in between.
    +No whitespace is inserted.
    +.Ss \eD\(aq Ns Ar string Ns \(aq
    +Draw graphics function; ignored by
    +.Xr mandoc 1 .
    +.Ss \ed
    +Move down by half a line; ignored by
    +.Xr mandoc 1 .
    +.Ss \ee
    +Backslash special character.
    +.Ss \eF Ns Bq Ar name
    +Switch font family (groff extension); ignored by
    +.Xr mandoc 1 .
    +For short names, there are variants
    +.No \eF Ns Ar c
    +and
    +.No \eF( Ns Ar cc .
    +.Ss \ef Ns Bq Ar name
    +Switch to the font
    +.Ar name ,
    +see
    +.Sx Text Decoration .
    +For short names, there are variants
    +.No \ef Ns Ar c
    +and
    +.No \ef( Ns Ar cc .
    +.Ss \eg Ns Bq Ar name
    +Interpolate the format of a number register; ignored by
    +.Xr mandoc 1 .
    +For short names, there are variants
    +.No \eg Ns Ar c
    +and
    +.No \eg( Ns Ar cc .
    +.Ss \eH\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq
    +Set the height of the current font; ignored by
    +.Xr mandoc 1 .
    +.Ss \eh\(aq Ns Oo Cm \&| Oc Ns Ar width Ns \(aq
    +Horizontal motion.
    +If the vertical bar is given, the motion is relative to the current
    +indentation.
    +Otherwise, it is relative to the current position.
    +The default scaling unit is
    +.Cm m .
    +.Ss \ek Ns Bq Ar name
    +Mark horizontal input place in register; ignored by
    +.Xr mandoc 1 .
    +For short names, there are variants
    +.No \ek Ns Ar c
    +and
    +.No \ek( Ns Ar cc .
    +.Ss \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns \(aq
    +Vertical line drawing function; ignored by
    +.Xr mandoc 1 .
    +.Ss \el\(aq Ns Ar width Ns Oo Ar c Oc Ns \(aq
    +Draw a horizontal line of
    +.Ar width
    +using the glyph
    +.Ar c .
    +.Ss \eM Ns Bq Ar name
    +Set fill (background) color (groff extension); ignored by
    +.Xr mandoc 1 .
    +For short names, there are variants
    +.No \eM Ns Ar c
    +and
    +.No \eM( Ns Ar cc .
    +.Ss \em Ns Bq Ar name
    +Set glyph drawing color (groff extension); ignored by
    +.Xr mandoc 1 .
    +For short names, there are variants
    +.No \em Ns Ar c
    +and
    +.No \em( Ns Ar cc .
    +.Ss \eN\(aq Ns Ar number Ns \(aq
    +Character
    +.Ar number
    +on the current font.
    +.Ss \en Ns Oo +|- Oc Ns Bq Ar name
    +Interpolate the number register
    +.Ar name .
    +For short names, there are variants
    +.No \en Ns Ar c
    +and
    +.No \en( Ns Ar cc .
    +If the optional sign is specified,
    +the register is first incremented or decremented by the
    +.Ar stepsize
    +that was specified in the relevant
    +.Ic \&nr
    +request, and the changed value is interpolated.
    +.Ss \eo\(aq Ns Ar string Ns \(aq
    +Overstrike, writing all the characters contained in the
    +.Ar string
    +to the same output position.
    +In terminal and HTML output modes,
    +only the last one of the characters is visible.
    +.Ss \ep
    +Break the output line at the end of the current word.
    +.Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq
    +Set number register; ignored by
    +.Xr mandoc 1 .
    +.Ss \eS\(aq Ns Ar number Ns \(aq
    +Slant output; ignored by
    +.Xr mandoc 1 .
    +.Ss \es\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq
    +Change point size; ignored by
    +.Xr mandoc 1 .
    +Alternative forms
    +.No \es Ns Oo +|- Oc Ns Ar n ,
    +.No \es Ns Oo +|- Oc Ns \(aq Ns Ar number Ns \(aq ,
    +.No \es Ns Bq Oo +|- Oc Ns Ar number ,
    +and
    +.No \es Ns Oo +|- Oc Ns Bq Ar number
    +are also parsed and ignored.
    +.Ss \et
    +Horizontal tab; ignored by
    +.Xr mandoc 1 .
    +.Ss \eu
    +Move up by half a line; ignored by
    +.Xr mandoc 1 .
    +.Ss \eV Ns Bq Ar name
    +Interpolate an environment variable; ignored by
    +.Xr mandoc 1 .
    +For short names, there are variants
    +.No \eV Ns Ar c
    +and
    +.No \eV( Ns Ar cc .
    +.Ss \ev\(aq Ns Ar number Ns \(aq
    +Vertical motion; ignored by
    +.Xr mandoc 1 .
    +.Ss \ew\(aq Ns Ar string Ns \(aq
    +Interpolate the width of the
    +.Ar string .
    +The
    +.Xr mandoc 1
    +implementation assumes that after expansion of user-defined strings, the
    +.Ar string
    +only contains normal characters, no escape sequences, and that each
    +character has a width of 24 basic units.
    +.Ss \eX\(aq Ns Ar string Ns \(aq
    +Output
    +.Ar string
    +as device control function; ignored in nroff mode and by
    +.Xr mandoc 1 .
    +.Ss \ex\(aq Ns Ar number Ns \(aq
    +Extra line space function; ignored by
    +.Xr mandoc 1 .
    +.Ss \eY Ns Bq Ar name
    +Output a string as a device control function; ignored in nroff mode and by
    +.Xr mandoc 1 .
    +For short names, there are variants
    +.No \eY Ns Ar c
    +and
    +.No \eY( Ns Ar cc .
    +.Ss \eZ\(aq Ns Ar string Ns \(aq
    +Print
    +.Ar string
    +with zero width and height; ignored by
    +.Xr mandoc 1 .
    +.Ss \ez
    +Output the next character without advancing the cursor position.
    +.Sh COMPATIBILITY
    +The
    +.Xr mandoc 1
    +implementation of the
    +.Nm
    +language is intentionally incomplete.
    +Unimplemented features include:
    +.Pp
    +.Bl -dash -compact
    +.It
    +For security reasons,
    +.Xr mandoc 1
    +never reads or writes external files except via
    +.Sx \&so
    +requests with safe relative paths.
    +.It
    +There is no automatic hyphenation, no adjustment to the right margin,
    +and no centering; the output is always set flush-left.
    +.It
    +Support for setting tabulator positions
    +and tabulator and leader characters is missing,
    +and support for manually changing indentation is limited.
    +.It
    +The
    +.Sq u
    +scaling unit is the default terminal unit.
    +In traditional troff systems, this unit changes depending on the
    +output media.
    +.It
    +Width measurements are implemented in a crude way
    +and often yield wrong results.
    +Explicit movement requests and escapes are ignored.
    +.It
    +There is no concept of output pages, no support for floats,
    +graphics drawing, and picture inclusion;
    +terminal output is always continuous.
    +.It
    +Requests regarding color, font families, and glyph manipulation
    +are ignored.
    +Font support is very limited.
    +Kerning is not implemented, and no ligatures are produced.
    +.It
    +The
    +.Qq \(aq
    +macro control character does not suppress output line breaks.
    +.It
    +Diversions are not implemented,
    +and support for traps is very incomplete.
    +.It
    +While recursion is supported,
    +.Sx \&while
    +loops are not.
    +.El
    +.Pp
    +The special semantics of the
    +.Cm nS
    +number register is an idiosyncracy of
    +.Ox
    +manuals and not supported by other
    +.Xr mdoc 7
    +implementations.
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr eqn 7 ,
    +.Xr man 7 ,
    +.Xr mandoc_char 7 ,
    +.Xr mdoc 7 ,
    +.Xr tbl 7
    +.Rs
    +.%A Joseph F. Ossanna
    +.%A Brian W. Kernighan
    +.%I AT&T Bell Laboratories
    +.%T Troff User's Manual
    +.%R Computing Science Technical Report
    +.%N 54
    +.%C Murray Hill, New Jersey
    +.%D 1976 and 1992
    +.%U http://www.kohala.com/start/troff/cstr54.ps
    +.Re
    +.Rs
    +.%A Joseph F. Ossanna
    +.%A Brian W. Kernighan
    +.%A Gunnar Ritter
    +.%T Heirloom Documentation Tools Nroff/Troff User's Manual
    +.%D September 17, 2007
    +.%U http://heirloom.sourceforge.net/doctools/troff.pdf
    +.Re
    +.Sh HISTORY
    +The RUNOFF typesetting system, whose input forms the basis for
    +.Nm ,
    +was written in MAD and FAP for the CTSS operating system by Jerome E.
    +Saltzer in 1964.
    +Doug McIlroy rewrote it in BCPL in 1969, renaming it
    +.Nm .
    +Dennis M. Ritchie rewrote McIlroy's
    +.Nm
    +in PDP-11 assembly for
    +.At v1 ,
    +Joseph F. Ossanna improved roff and renamed it nroff
    +for
    +.At v2 ,
    +then ported nroff to C as troff, which Brian W. Kernighan released with
    +.At v7 .
    +In 1989, James Clarke re-implemented troff in C++, naming it groff.
    +.Sh AUTHORS
    +.An -nosplit
    +This
    +.Nm
    +reference was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +and
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
    
    Property changes on: head/contrib/mandoc/roff.7
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/roff.c
    ===================================================================
    --- head/contrib/mandoc/roff.c	(nonexistent)
    +++ head/contrib/mandoc/roff.c	(revision 338826)
    @@ -0,0 +1,3838 @@
    +/*	$Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <limits.h>
    +#include <stddef.h>
    +#include <stdint.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "mandoc_aux.h"
    +#include "mandoc_ohash.h"
    +#include "roff.h"
    +#include "libmandoc.h"
    +#include "roff_int.h"
    +#include "libroff.h"
    +
    +/* Maximum number of string expansions per line, to break infinite loops. */
    +#define	EXPAND_LIMIT	1000
    +
    +/* Types of definitions of macros and strings. */
    +#define	ROFFDEF_USER	(1 << 1)  /* User-defined. */
    +#define	ROFFDEF_PRE	(1 << 2)  /* Predefined. */
    +#define	ROFFDEF_REN	(1 << 3)  /* Renamed standard macro. */
    +#define	ROFFDEF_STD	(1 << 4)  /* mdoc(7) or man(7) macro. */
    +#define	ROFFDEF_ANY	(ROFFDEF_USER | ROFFDEF_PRE | \
    +			 ROFFDEF_REN | ROFFDEF_STD)
    +#define	ROFFDEF_UNDEF	(1 << 5)  /* Completely undefined. */
    +
    +/* --- data types --------------------------------------------------------- */
    +
    +/*
    + * An incredibly-simple string buffer.
    + */
    +struct	roffstr {
    +	char		*p; /* nil-terminated buffer */
    +	size_t		 sz; /* saved strlen(p) */
    +};
    +
    +/*
    + * A key-value roffstr pair as part of a singly-linked list.
    + */
    +struct	roffkv {
    +	struct roffstr	 key;
    +	struct roffstr	 val;
    +	struct roffkv	*next; /* next in list */
    +};
    +
    +/*
    + * A single number register as part of a singly-linked list.
    + */
    +struct	roffreg {
    +	struct roffstr	 key;
    +	int		 val;
    +	int		 step;
    +	struct roffreg	*next;
    +};
    +
    +/*
    + * Association of request and macro names with token IDs.
    + */
    +struct	roffreq {
    +	enum roff_tok	 tok;
    +	char		 name[];
    +};
    +
    +struct	roff {
    +	struct mparse	*parse; /* parse point */
    +	struct roff_man	*man; /* mdoc or man parser */
    +	struct roffnode	*last; /* leaf of stack */
    +	int		*rstack; /* stack of inverted `ie' values */
    +	struct ohash	*reqtab; /* request lookup table */
    +	struct roffreg	*regtab; /* number registers */
    +	struct roffkv	*strtab; /* user-defined strings & macros */
    +	struct roffkv	*rentab; /* renamed strings & macros */
    +	struct roffkv	*xmbtab; /* multi-byte trans table (`tr') */
    +	struct roffstr	*xtab; /* single-byte trans table (`tr') */
    +	const char	*current_string; /* value of last called user macro */
    +	struct tbl_node	*first_tbl; /* first table parsed */
    +	struct tbl_node	*last_tbl; /* last table parsed */
    +	struct tbl_node	*tbl; /* current table being parsed */
    +	struct eqn_node	*last_eqn; /* equation parser */
    +	struct eqn_node	*eqn; /* active equation parser */
    +	int		 eqn_inline; /* current equation is inline */
    +	int		 options; /* parse options */
    +	int		 rstacksz; /* current size limit of rstack */
    +	int		 rstackpos; /* position in rstack */
    +	int		 format; /* current file in mdoc or man format */
    +	int		 argc; /* number of args of the last macro */
    +	char		 control; /* control character */
    +	char		 escape; /* escape character */
    +};
    +
    +struct	roffnode {
    +	enum roff_tok	 tok; /* type of node */
    +	struct roffnode	*parent; /* up one in stack */
    +	int		 line; /* parse line */
    +	int		 col; /* parse col */
    +	char		*name; /* node name, e.g. macro name */
    +	char		*end; /* end-rules: custom token */
    +	int		 endspan; /* end-rules: next-line or infty */
    +	int		 rule; /* current evaluation rule */
    +};
    +
    +#define	ROFF_ARGS	 struct roff *r, /* parse ctx */ \
    +			 enum roff_tok tok, /* tok of macro */ \
    +			 struct buf *buf, /* input buffer */ \
    +			 int ln, /* parse line */ \
    +			 int ppos, /* original pos in buffer */ \
    +			 int pos, /* current pos in buffer */ \
    +			 int *offs /* reset offset of buffer data */
    +
    +typedef	enum rofferr (*roffproc)(ROFF_ARGS);
    +
    +struct	roffmac {
    +	roffproc	 proc; /* process new macro */
    +	roffproc	 text; /* process as child text of macro */
    +	roffproc	 sub; /* process as child of macro */
    +	int		 flags;
    +#define	ROFFMAC_STRUCT	(1 << 0) /* always interpret */
    +};
    +
    +struct	predef {
    +	const char	*name; /* predefined input name */
    +	const char	*str; /* replacement symbol */
    +};
    +
    +#define	PREDEF(__name, __str) \
    +	{ (__name), (__str) },
    +
    +/* --- function prototypes ------------------------------------------------ */
    +
    +static	void		 roffnode_cleanscope(struct roff *);
    +static	void		 roffnode_pop(struct roff *);
    +static	void		 roffnode_push(struct roff *, enum roff_tok,
    +				const char *, int, int);
    +static	void		 roff_addtbl(struct roff_man *, struct tbl_node *);
    +static	enum rofferr	 roff_als(ROFF_ARGS);
    +static	enum rofferr	 roff_block(ROFF_ARGS);
    +static	enum rofferr	 roff_block_text(ROFF_ARGS);
    +static	enum rofferr	 roff_block_sub(ROFF_ARGS);
    +static	enum rofferr	 roff_br(ROFF_ARGS);
    +static	enum rofferr	 roff_cblock(ROFF_ARGS);
    +static	enum rofferr	 roff_cc(ROFF_ARGS);
    +static	void		 roff_ccond(struct roff *, int, int);
    +static	enum rofferr	 roff_cond(ROFF_ARGS);
    +static	enum rofferr	 roff_cond_text(ROFF_ARGS);
    +static	enum rofferr	 roff_cond_sub(ROFF_ARGS);
    +static	enum rofferr	 roff_ds(ROFF_ARGS);
    +static	enum rofferr	 roff_ec(ROFF_ARGS);
    +static	enum rofferr	 roff_eo(ROFF_ARGS);
    +static	enum rofferr	 roff_eqndelim(struct roff *, struct buf *, int);
    +static	int		 roff_evalcond(struct roff *r, int, char *, int *);
    +static	int		 roff_evalnum(struct roff *, int,
    +				const char *, int *, int *, int);
    +static	int		 roff_evalpar(struct roff *, int,
    +				const char *, int *, int *, int);
    +static	int		 roff_evalstrcond(const char *, int *);
    +static	void		 roff_free1(struct roff *);
    +static	void		 roff_freereg(struct roffreg *);
    +static	void		 roff_freestr(struct roffkv *);
    +static	size_t		 roff_getname(struct roff *, char **, int, int);
    +static	int		 roff_getnum(const char *, int *, int *, int);
    +static	int		 roff_getop(const char *, int *, char *);
    +static	int		 roff_getregn(struct roff *,
    +				const char *, size_t, char);
    +static	int		 roff_getregro(const struct roff *,
    +				const char *name);
    +static	const char	*roff_getstrn(struct roff *,
    +				const char *, size_t, int *);
    +static	int		 roff_hasregn(const struct roff *,
    +				const char *, size_t);
    +static	enum rofferr	 roff_insec(ROFF_ARGS);
    +static	enum rofferr	 roff_it(ROFF_ARGS);
    +static	enum rofferr	 roff_line_ignore(ROFF_ARGS);
    +static	void		 roff_man_alloc1(struct roff_man *);
    +static	void		 roff_man_free1(struct roff_man *);
    +static	enum rofferr	 roff_manyarg(ROFF_ARGS);
    +static	enum rofferr	 roff_nr(ROFF_ARGS);
    +static	enum rofferr	 roff_onearg(ROFF_ARGS);
    +static	enum roff_tok	 roff_parse(struct roff *, char *, int *,
    +				int, int);
    +static	enum rofferr	 roff_parsetext(struct roff *, struct buf *,
    +				int, int *);
    +static	enum rofferr	 roff_renamed(ROFF_ARGS);
    +static	enum rofferr	 roff_res(struct roff *, struct buf *, int, int);
    +static	enum rofferr	 roff_rm(ROFF_ARGS);
    +static	enum rofferr	 roff_rn(ROFF_ARGS);
    +static	enum rofferr	 roff_rr(ROFF_ARGS);
    +static	void		 roff_setregn(struct roff *, const char *,
    +				size_t, int, char, int);
    +static	void		 roff_setstr(struct roff *,
    +				const char *, const char *, int);
    +static	void		 roff_setstrn(struct roffkv **, const char *,
    +				size_t, const char *, size_t, int);
    +static	enum rofferr	 roff_so(ROFF_ARGS);
    +static	enum rofferr	 roff_tr(ROFF_ARGS);
    +static	enum rofferr	 roff_Dd(ROFF_ARGS);
    +static	enum rofferr	 roff_TE(ROFF_ARGS);
    +static	enum rofferr	 roff_TS(ROFF_ARGS);
    +static	enum rofferr	 roff_EQ(ROFF_ARGS);
    +static	enum rofferr	 roff_EN(ROFF_ARGS);
    +static	enum rofferr	 roff_T_(ROFF_ARGS);
    +static	enum rofferr	 roff_unsupp(ROFF_ARGS);
    +static	enum rofferr	 roff_userdef(ROFF_ARGS);
    +
    +/* --- constant data ------------------------------------------------------ */
    +
    +#define	ROFFNUM_SCALE	(1 << 0)  /* Honour scaling in roff_getnum(). */
    +#define	ROFFNUM_WHITE	(1 << 1)  /* Skip whitespace in roff_evalnum(). */
    +
    +const char *__roff_name[MAN_MAX + 1] = {
    +	"br",		"ce",		"ft",		"ll",
    +	"mc",		"po",		"rj",		"sp",
    +	"ta",		"ti",		NULL,
    +	"ab",		"ad",		"af",		"aln",
    +	"als",		"am",		"am1",		"ami",
    +	"ami1",		"as",		"as1",		"asciify",
    +	"backtrace",	"bd",		"bleedat",	"blm",
    +        "box",		"boxa",		"bp",		"BP",
    +	"break",	"breakchar",	"brnl",		"brp",
    +	"brpnl",	"c2",		"cc",
    +	"cf",		"cflags",	"ch",		"char",
    +	"chop",		"class",	"close",	"CL",
    +	"color",	"composite",	"continue",	"cp",
    +	"cropat",	"cs",		"cu",		"da",
    +	"dch",		"Dd",		"de",		"de1",
    +	"defcolor",	"dei",		"dei1",		"device",
    +	"devicem",	"di",		"do",		"ds",
    +	"ds1",		"dwh",		"dt",		"ec",
    +	"ecr",		"ecs",		"el",		"em",
    +	"EN",		"eo",		"EP",		"EQ",
    +	"errprint",	"ev",		"evc",		"ex",
    +	"fallback",	"fam",		"fc",		"fchar",
    +	"fcolor",	"fdeferlig",	"feature",	"fkern",
    +	"fl",		"flig",		"fp",		"fps",
    +	"fschar",	"fspacewidth",	"fspecial",	"ftr",
    +	"fzoom",	"gcolor",	"hc",		"hcode",
    +	"hidechar",	"hla",		"hlm",		"hpf",
    +	"hpfa",		"hpfcode",	"hw",		"hy",
    +	"hylang",	"hylen",	"hym",		"hypp",
    +	"hys",		"ie",		"if",		"ig",
    +	"index",	"it",		"itc",		"IX",
    +	"kern",		"kernafter",	"kernbefore",	"kernpair",
    +	"lc",		"lc_ctype",	"lds",		"length",
    +	"letadj",	"lf",		"lg",		"lhang",
    +	"linetabs",	"lnr",		"lnrf",		"lpfx",
    +	"ls",		"lsm",		"lt",
    +	"mediasize",	"minss",	"mk",		"mso",
    +	"na",		"ne",		"nh",		"nhychar",
    +	"nm",		"nn",		"nop",		"nr",
    +	"nrf",		"nroff",	"ns",		"nx",
    +	"open",		"opena",	"os",		"output",
    +	"padj",		"papersize",	"pc",		"pev",
    +	"pi",		"PI",		"pl",		"pm",
    +	"pn",		"pnr",		"ps",
    +	"psbb",		"pshape",	"pso",		"ptr",
    +	"pvs",		"rchar",	"rd",		"recursionlimit",
    +	"return",	"rfschar",	"rhang",
    +	"rm",		"rn",		"rnn",		"rr",
    +	"rs",		"rt",		"schar",	"sentchar",
    +	"shc",		"shift",	"sizes",	"so",
    +	"spacewidth",	"special",	"spreadwarn",	"ss",
    +	"sty",		"substring",	"sv",		"sy",
    +	"T&",		"tc",		"TE",
    +	"TH",		"tkf",		"tl",
    +	"tm",		"tm1",		"tmc",		"tr",
    +	"track",	"transchar",	"trf",		"trimat",
    +	"trin",		"trnt",		"troff",	"TS",
    +	"uf",		"ul",		"unformat",	"unwatch",
    +	"unwatchn",	"vpt",		"vs",		"warn",
    +	"warnscale",	"watch",	"watchlength",	"watchn",
    +	"wh",		"while",	"write",	"writec",
    +	"writem",	"xflag",	".",		NULL,
    +	NULL,		"text",
    +	"Dd",		"Dt",		"Os",		"Sh",
    +	"Ss",		"Pp",		"D1",		"Dl",
    +	"Bd",		"Ed",		"Bl",		"El",
    +	"It",		"Ad",		"An",		"Ap",
    +	"Ar",		"Cd",		"Cm",		"Dv",
    +	"Er",		"Ev",		"Ex",		"Fa",
    +	"Fd",		"Fl",		"Fn",		"Ft",
    +	"Ic",		"In",		"Li",		"Nd",
    +	"Nm",		"Op",		"Ot",		"Pa",
    +	"Rv",		"St",		"Va",		"Vt",
    +	"Xr",		"%A",		"%B",		"%D",
    +	"%I",		"%J",		"%N",		"%O",
    +	"%P",		"%R",		"%T",		"%V",
    +	"Ac",		"Ao",		"Aq",		"At",
    +	"Bc",		"Bf",		"Bo",		"Bq",
    +	"Bsx",		"Bx",		"Db",		"Dc",
    +	"Do",		"Dq",		"Ec",		"Ef",
    +	"Em",		"Eo",		"Fx",		"Ms",
    +	"No",		"Ns",		"Nx",		"Ox",
    +	"Pc",		"Pf",		"Po",		"Pq",
    +	"Qc",		"Ql",		"Qo",		"Qq",
    +	"Re",		"Rs",		"Sc",		"So",
    +	"Sq",		"Sm",		"Sx",		"Sy",
    +	"Tn",		"Ux",		"Xc",		"Xo",
    +	"Fo",		"Fc",		"Oo",		"Oc",
    +	"Bk",		"Ek",		"Bt",		"Hf",
    +	"Fr",		"Ud",		"Lb",		"Lp",
    +	"Lk",		"Mt",		"Brq",		"Bro",
    +	"Brc",		"%C",		"Es",		"En",
    +	"Dx",		"%Q",		"%U",		"Ta",
    +	NULL,
    +	"TH",		"SH",		"SS",		"TP",
    +	"LP",		"PP",		"P",		"IP",
    +	"HP",		"SM",		"SB",		"BI",
    +	"IB",		"BR",		"RB",		"R",
    +	"B",		"I",		"IR",		"RI",
    +	"nf",		"fi",
    +	"RE",		"RS",		"DT",		"UC",
    +	"PD",		"AT",		"in",
    +	"OP",		"EX",		"EE",		"UR",
    +	"UE",		"MT",		"ME",		NULL
    +};
    +const	char *const *roff_name = __roff_name;
    +
    +static	struct roffmac	 roffs[TOKEN_NONE] = {
    +	{ roff_br, NULL, NULL, 0 },  /* br */
    +	{ roff_onearg, NULL, NULL, 0 },  /* ce */
    +	{ roff_onearg, NULL, NULL, 0 },  /* ft */
    +	{ roff_onearg, NULL, NULL, 0 },  /* ll */
    +	{ roff_onearg, NULL, NULL, 0 },  /* mc */
    +	{ roff_onearg, NULL, NULL, 0 },  /* po */
    +	{ roff_onearg, NULL, NULL, 0 },  /* rj */
    +	{ roff_onearg, NULL, NULL, 0 },  /* sp */
    +	{ roff_manyarg, NULL, NULL, 0 },  /* ta */
    +	{ roff_onearg, NULL, NULL, 0 },  /* ti */
    +	{ NULL, NULL, NULL, 0 },  /* ROFF_MAX */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* ab */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ad */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* af */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* aln */
    +	{ roff_als, NULL, NULL, 0 },  /* als */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* am */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* am1 */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* ami */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* ami1 */
    +	{ roff_ds, NULL, NULL, 0 },  /* as */
    +	{ roff_ds, NULL, NULL, 0 },  /* as1 */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* asciify */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* backtrace */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* bd */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* bleedat */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* blm */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* box */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* boxa */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* bp */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* BP */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* break */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* breakchar */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* brnl */
    +	{ roff_br, NULL, NULL, 0 },  /* brp */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* brpnl */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* c2 */
    +	{ roff_cc, NULL, NULL, 0 },  /* cc */
    +	{ roff_insec, NULL, NULL, 0 },  /* cf */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* cflags */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ch */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* char */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* chop */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* class */
    +	{ roff_insec, NULL, NULL, 0 },  /* close */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* CL */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* color */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* composite */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* continue */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* cp */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* cropat */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* cs */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* cu */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* da */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* dch */
    +	{ roff_Dd, NULL, NULL, 0 },  /* Dd */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* de */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* de1 */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* defcolor */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* dei */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* dei1 */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* device */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* devicem */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* di */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* do */
    +	{ roff_ds, NULL, NULL, 0 },  /* ds */
    +	{ roff_ds, NULL, NULL, 0 },  /* ds1 */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* dwh */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* dt */
    +	{ roff_ec, NULL, NULL, 0 },  /* ec */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* ecr */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* ecs */
    +	{ roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },  /* el */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* em */
    +	{ roff_EN, NULL, NULL, 0 },  /* EN */
    +	{ roff_eo, NULL, NULL, 0 },  /* eo */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* EP */
    +	{ roff_EQ, NULL, NULL, 0 },  /* EQ */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* errprint */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* ev */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* evc */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* ex */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fallback */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fam */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* fc */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* fchar */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fcolor */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fdeferlig */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* feature */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fkern */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fl */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* flig */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fp */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fps */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* fschar */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fspacewidth */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fspecial */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ftr */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* fzoom */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* gcolor */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hc */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hcode */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hidechar */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hla */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hlm */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hpf */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hpfa */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hpfcode */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hw */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hy */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hylang */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hylen */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hym */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hypp */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* hys */
    +	{ roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },  /* ie */
    +	{ roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },  /* if */
    +	{ roff_block, roff_block_text, roff_block_sub, 0 },  /* ig */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* index */
    +	{ roff_it, NULL, NULL, 0 },  /* it */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* itc */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* IX */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* kern */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* kernafter */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* kernbefore */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* kernpair */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* lc */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* lc_ctype */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* lds */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* length */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* letadj */
    +	{ roff_insec, NULL, NULL, 0 },  /* lf */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* lg */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* lhang */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* linetabs */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* lnr */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* lnrf */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* lpfx */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ls */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* lsm */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* lt */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* mediasize */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* minss */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* mk */
    +	{ roff_insec, NULL, NULL, 0 },  /* mso */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* na */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ne */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* nh */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* nhychar */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* nm */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* nn */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* nop */
    +	{ roff_nr, NULL, NULL, 0 },  /* nr */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* nrf */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* nroff */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ns */
    +	{ roff_insec, NULL, NULL, 0 },  /* nx */
    +	{ roff_insec, NULL, NULL, 0 },  /* open */
    +	{ roff_insec, NULL, NULL, 0 },  /* opena */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* os */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* output */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* padj */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* papersize */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* pc */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* pev */
    +	{ roff_insec, NULL, NULL, 0 },  /* pi */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* PI */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* pl */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* pm */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* pn */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* pnr */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ps */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* psbb */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* pshape */
    +	{ roff_insec, NULL, NULL, 0 },  /* pso */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ptr */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* pvs */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* rchar */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* rd */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* recursionlimit */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* return */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* rfschar */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* rhang */
    +	{ roff_rm, NULL, NULL, 0 },  /* rm */
    +	{ roff_rn, NULL, NULL, 0 },  /* rn */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* rnn */
    +	{ roff_rr, NULL, NULL, 0 },  /* rr */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* rs */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* rt */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* schar */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* sentchar */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* shc */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* shift */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* sizes */
    +	{ roff_so, NULL, NULL, 0 },  /* so */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* spacewidth */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* special */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* spreadwarn */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ss */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* sty */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* substring */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* sv */
    +	{ roff_insec, NULL, NULL, 0 },  /* sy */
    +	{ roff_T_, NULL, NULL, 0 },  /* T& */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* tc */
    +	{ roff_TE, NULL, NULL, 0 },  /* TE */
    +	{ roff_Dd, NULL, NULL, 0 },  /* TH */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* tkf */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* tl */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* tm */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* tm1 */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* tmc */
    +	{ roff_tr, NULL, NULL, 0 },  /* tr */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* track */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* transchar */
    +	{ roff_insec, NULL, NULL, 0 },  /* trf */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* trimat */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* trin */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* trnt */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* troff */
    +	{ roff_TS, NULL, NULL, 0 },  /* TS */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* uf */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* ul */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* unformat */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* unwatch */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* unwatchn */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* vpt */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* vs */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* warn */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* warnscale */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* watch */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* watchlength */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* watchn */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* wh */
    +	{ roff_unsupp, NULL, NULL, 0 },  /* while */
    +	{ roff_insec, NULL, NULL, 0 },  /* write */
    +	{ roff_insec, NULL, NULL, 0 },  /* writec */
    +	{ roff_insec, NULL, NULL, 0 },  /* writem */
    +	{ roff_line_ignore, NULL, NULL, 0 },  /* xflag */
    +	{ roff_cblock, NULL, NULL, 0 },  /* . */
    +	{ roff_renamed, NULL, NULL, 0 },
    +	{ roff_userdef, NULL, NULL, 0 }
    +};
    +
    +/* Array of injected predefined strings. */
    +#define	PREDEFS_MAX	 38
    +static	const struct predef predefs[PREDEFS_MAX] = {
    +#include "predefs.in"
    +};
    +
    +static	int	 roffce_lines;	/* number of input lines to center */
    +static	struct roff_node *roffce_node;  /* active request */
    +static	int	 roffit_lines;  /* number of lines to delay */
    +static	char	*roffit_macro;  /* nil-terminated macro line */
    +
    +
    +/* --- request table ------------------------------------------------------ */
    +
    +struct ohash *
    +roffhash_alloc(enum roff_tok mintok, enum roff_tok maxtok)
    +{
    +	struct ohash	*htab;
    +	struct roffreq	*req;
    +	enum roff_tok	 tok;
    +	size_t		 sz;
    +	unsigned int	 slot;
    +
    +	htab = mandoc_malloc(sizeof(*htab));
    +	mandoc_ohash_init(htab, 8, offsetof(struct roffreq, name));
    +
    +	for (tok = mintok; tok < maxtok; tok++) {
    +		if (roff_name[tok] == NULL)
    +			continue;
    +		sz = strlen(roff_name[tok]);
    +		req = mandoc_malloc(sizeof(*req) + sz + 1);
    +		req->tok = tok;
    +		memcpy(req->name, roff_name[tok], sz + 1);
    +		slot = ohash_qlookup(htab, req->name);
    +		ohash_insert(htab, slot, req);
    +	}
    +	return htab;
    +}
    +
    +void
    +roffhash_free(struct ohash *htab)
    +{
    +	struct roffreq	*req;
    +	unsigned int	 slot;
    +
    +	if (htab == NULL)
    +		return;
    +	for (req = ohash_first(htab, &slot); req != NULL;
    +	     req = ohash_next(htab, &slot))
    +		free(req);
    +	ohash_delete(htab);
    +	free(htab);
    +}
    +
    +enum roff_tok
    +roffhash_find(struct ohash *htab, const char *name, size_t sz)
    +{
    +	struct roffreq	*req;
    +	const char	*end;
    +
    +	if (sz) {
    +		end = name + sz;
    +		req = ohash_find(htab, ohash_qlookupi(htab, name, &end));
    +	} else
    +		req = ohash_find(htab, ohash_qlookup(htab, name));
    +	return req == NULL ? TOKEN_NONE : req->tok;
    +}
    +
    +/* --- stack of request blocks -------------------------------------------- */
    +
    +/*
    + * Pop the current node off of the stack of roff instructions currently
    + * pending.
    + */
    +static void
    +roffnode_pop(struct roff *r)
    +{
    +	struct roffnode	*p;
    +
    +	assert(r->last);
    +	p = r->last;
    +
    +	r->last = r->last->parent;
    +	free(p->name);
    +	free(p->end);
    +	free(p);
    +}
    +
    +/*
    + * Push a roff node onto the instruction stack.  This must later be
    + * removed with roffnode_pop().
    + */
    +static void
    +roffnode_push(struct roff *r, enum roff_tok tok, const char *name,
    +		int line, int col)
    +{
    +	struct roffnode	*p;
    +
    +	p = mandoc_calloc(1, sizeof(struct roffnode));
    +	p->tok = tok;
    +	if (name)
    +		p->name = mandoc_strdup(name);
    +	p->parent = r->last;
    +	p->line = line;
    +	p->col = col;
    +	p->rule = p->parent ? p->parent->rule : 0;
    +
    +	r->last = p;
    +}
    +
    +/* --- roff parser state data management ---------------------------------- */
    +
    +static void
    +roff_free1(struct roff *r)
    +{
    +	struct tbl_node	*tbl;
    +	int		 i;
    +
    +	while (NULL != (tbl = r->first_tbl)) {
    +		r->first_tbl = tbl->next;
    +		tbl_free(tbl);
    +	}
    +	r->first_tbl = r->last_tbl = r->tbl = NULL;
    +
    +	if (r->last_eqn != NULL)
    +		eqn_free(r->last_eqn);
    +	r->last_eqn = r->eqn = NULL;
    +
    +	while (r->last)
    +		roffnode_pop(r);
    +
    +	free (r->rstack);
    +	r->rstack = NULL;
    +	r->rstacksz = 0;
    +	r->rstackpos = -1;
    +
    +	roff_freereg(r->regtab);
    +	r->regtab = NULL;
    +
    +	roff_freestr(r->strtab);
    +	roff_freestr(r->rentab);
    +	roff_freestr(r->xmbtab);
    +	r->strtab = r->rentab = r->xmbtab = NULL;
    +
    +	if (r->xtab)
    +		for (i = 0; i < 128; i++)
    +			free(r->xtab[i].p);
    +	free(r->xtab);
    +	r->xtab = NULL;
    +}
    +
    +void
    +roff_reset(struct roff *r)
    +{
    +	roff_free1(r);
    +	r->format = r->options & (MPARSE_MDOC | MPARSE_MAN);
    +	r->control = '\0';
    +	r->escape = '\\';
    +	roffce_lines = 0;
    +	roffce_node = NULL;
    +	roffit_lines = 0;
    +	roffit_macro = NULL;
    +}
    +
    +void
    +roff_free(struct roff *r)
    +{
    +	roff_free1(r);
    +	roffhash_free(r->reqtab);
    +	free(r);
    +}
    +
    +struct roff *
    +roff_alloc(struct mparse *parse, int options)
    +{
    +	struct roff	*r;
    +
    +	r = mandoc_calloc(1, sizeof(struct roff));
    +	r->parse = parse;
    +	r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
    +	r->options = options;
    +	r->format = options & (MPARSE_MDOC | MPARSE_MAN);
    +	r->rstackpos = -1;
    +	r->escape = '\\';
    +	return r;
    +}
    +
    +/* --- syntax tree state data management ---------------------------------- */
    +
    +static void
    +roff_man_free1(struct roff_man *man)
    +{
    +
    +	if (man->first != NULL)
    +		roff_node_delete(man, man->first);
    +	free(man->meta.msec);
    +	free(man->meta.vol);
    +	free(man->meta.os);
    +	free(man->meta.arch);
    +	free(man->meta.title);
    +	free(man->meta.name);
    +	free(man->meta.date);
    +}
    +
    +static void
    +roff_man_alloc1(struct roff_man *man)
    +{
    +
    +	memset(&man->meta, 0, sizeof(man->meta));
    +	man->first = mandoc_calloc(1, sizeof(*man->first));
    +	man->first->type = ROFFT_ROOT;
    +	man->last = man->first;
    +	man->last_es = NULL;
    +	man->flags = 0;
    +	man->macroset = MACROSET_NONE;
    +	man->lastsec = man->lastnamed = SEC_NONE;
    +	man->next = ROFF_NEXT_CHILD;
    +}
    +
    +void
    +roff_man_reset(struct roff_man *man)
    +{
    +
    +	roff_man_free1(man);
    +	roff_man_alloc1(man);
    +}
    +
    +void
    +roff_man_free(struct roff_man *man)
    +{
    +
    +	roff_man_free1(man);
    +	free(man);
    +}
    +
    +struct roff_man *
    +roff_man_alloc(struct roff *roff, struct mparse *parse,
    +	const char *os_s, int quick)
    +{
    +	struct roff_man *man;
    +
    +	man = mandoc_calloc(1, sizeof(*man));
    +	man->parse = parse;
    +	man->roff = roff;
    +	man->os_s = os_s;
    +	man->quick = quick;
    +	roff_man_alloc1(man);
    +	roff->man = man;
    +	return man;
    +}
    +
    +/* --- syntax tree handling ----------------------------------------------- */
    +
    +struct roff_node *
    +roff_node_alloc(struct roff_man *man, int line, int pos,
    +	enum roff_type type, int tok)
    +{
    +	struct roff_node	*n;
    +
    +	n = mandoc_calloc(1, sizeof(*n));
    +	n->line = line;
    +	n->pos = pos;
    +	n->tok = tok;
    +	n->type = type;
    +	n->sec = man->lastsec;
    +
    +	if (man->flags & MDOC_SYNOPSIS)
    +		n->flags |= NODE_SYNPRETTY;
    +	else
    +		n->flags &= ~NODE_SYNPRETTY;
    +	if (man->flags & MDOC_NEWLINE)
    +		n->flags |= NODE_LINE;
    +	man->flags &= ~MDOC_NEWLINE;
    +
    +	return n;
    +}
    +
    +void
    +roff_node_append(struct roff_man *man, struct roff_node *n)
    +{
    +
    +	switch (man->next) {
    +	case ROFF_NEXT_SIBLING:
    +		if (man->last->next != NULL) {
    +			n->next = man->last->next;
    +			man->last->next->prev = n;
    +		} else
    +			man->last->parent->last = n;
    +		man->last->next = n;
    +		n->prev = man->last;
    +		n->parent = man->last->parent;
    +		break;
    +	case ROFF_NEXT_CHILD:
    +		if (man->last->child != NULL) {
    +			n->next = man->last->child;
    +			man->last->child->prev = n;
    +		} else
    +			man->last->last = n;
    +		man->last->child = n;
    +		n->parent = man->last;
    +		break;
    +	default:
    +		abort();
    +	}
    +	man->last = n;
    +
    +	switch (n->type) {
    +	case ROFFT_HEAD:
    +		n->parent->head = n;
    +		break;
    +	case ROFFT_BODY:
    +		if (n->end != ENDBODY_NOT)
    +			return;
    +		n->parent->body = n;
    +		break;
    +	case ROFFT_TAIL:
    +		n->parent->tail = n;
    +		break;
    +	default:
    +		return;
    +	}
    +
    +	/*
    +	 * Copy over the normalised-data pointer of our parent.  Not
    +	 * everybody has one, but copying a null pointer is fine.
    +	 */
    +
    +	n->norm = n->parent->norm;
    +	assert(n->parent->type == ROFFT_BLOCK);
    +}
    +
    +void
    +roff_word_alloc(struct roff_man *man, int line, int pos, const char *word)
    +{
    +	struct roff_node	*n;
    +
    +	n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE);
    +	n->string = roff_strdup(man->roff, word);
    +	roff_node_append(man, n);
    +	n->flags |= NODE_VALID | NODE_ENDED;
    +	man->next = ROFF_NEXT_SIBLING;
    +}
    +
    +void
    +roff_word_append(struct roff_man *man, const char *word)
    +{
    +	struct roff_node	*n;
    +	char			*addstr, *newstr;
    +
    +	n = man->last;
    +	addstr = roff_strdup(man->roff, word);
    +	mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
    +	free(addstr);
    +	free(n->string);
    +	n->string = newstr;
    +	man->next = ROFF_NEXT_SIBLING;
    +}
    +
    +void
    +roff_elem_alloc(struct roff_man *man, int line, int pos, int tok)
    +{
    +	struct roff_node	*n;
    +
    +	n = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok);
    +	roff_node_append(man, n);
    +	man->next = ROFF_NEXT_CHILD;
    +}
    +
    +struct roff_node *
    +roff_block_alloc(struct roff_man *man, int line, int pos, int tok)
    +{
    +	struct roff_node	*n;
    +
    +	n = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok);
    +	roff_node_append(man, n);
    +	man->next = ROFF_NEXT_CHILD;
    +	return n;
    +}
    +
    +struct roff_node *
    +roff_head_alloc(struct roff_man *man, int line, int pos, int tok)
    +{
    +	struct roff_node	*n;
    +
    +	n = roff_node_alloc(man, line, pos, ROFFT_HEAD, tok);
    +	roff_node_append(man, n);
    +	man->next = ROFF_NEXT_CHILD;
    +	return n;
    +}
    +
    +struct roff_node *
    +roff_body_alloc(struct roff_man *man, int line, int pos, int tok)
    +{
    +	struct roff_node	*n;
    +
    +	n = roff_node_alloc(man, line, pos, ROFFT_BODY, tok);
    +	roff_node_append(man, n);
    +	man->next = ROFF_NEXT_CHILD;
    +	return n;
    +}
    +
    +static void
    +roff_addtbl(struct roff_man *man, struct tbl_node *tbl)
    +{
    +	struct roff_node	*n;
    +	const struct tbl_span	*span;
    +
    +	if (man->macroset == MACROSET_MAN)
    +		man_breakscope(man, ROFF_TS);
    +	while ((span = tbl_span(tbl)) != NULL) {
    +		n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE);
    +		n->span = span;
    +		roff_node_append(man, n);
    +		n->flags |= NODE_VALID | NODE_ENDED;
    +		man->next = ROFF_NEXT_SIBLING;
    +	}
    +}
    +
    +void
    +roff_node_unlink(struct roff_man *man, struct roff_node *n)
    +{
    +
    +	/* Adjust siblings. */
    +
    +	if (n->prev)
    +		n->prev->next = n->next;
    +	if (n->next)
    +		n->next->prev = n->prev;
    +
    +	/* Adjust parent. */
    +
    +	if (n->parent != NULL) {
    +		if (n->parent->child == n)
    +			n->parent->child = n->next;
    +		if (n->parent->last == n)
    +			n->parent->last = n->prev;
    +	}
    +
    +	/* Adjust parse point. */
    +
    +	if (man == NULL)
    +		return;
    +	if (man->last == n) {
    +		if (n->prev == NULL) {
    +			man->last = n->parent;
    +			man->next = ROFF_NEXT_CHILD;
    +		} else {
    +			man->last = n->prev;
    +			man->next = ROFF_NEXT_SIBLING;
    +		}
    +	}
    +	if (man->first == n)
    +		man->first = NULL;
    +}
    +
    +void
    +roff_node_free(struct roff_node *n)
    +{
    +
    +	if (n->args != NULL)
    +		mdoc_argv_free(n->args);
    +	if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM)
    +		free(n->norm);
    +	if (n->eqn != NULL)
    +		eqn_box_free(n->eqn);
    +	free(n->string);
    +	free(n);
    +}
    +
    +void
    +roff_node_delete(struct roff_man *man, struct roff_node *n)
    +{
    +
    +	while (n->child != NULL)
    +		roff_node_delete(man, n->child);
    +	roff_node_unlink(man, n);
    +	roff_node_free(n);
    +}
    +
    +void
    +deroff(char **dest, const struct roff_node *n)
    +{
    +	char	*cp;
    +	size_t	 sz;
    +
    +	if (n->type != ROFFT_TEXT) {
    +		for (n = n->child; n != NULL; n = n->next)
    +			deroff(dest, n);
    +		return;
    +	}
    +
    +	/* Skip leading whitespace. */
    +
    +	for (cp = n->string; *cp != '\0'; cp++) {
    +		if (cp[0] == '\\' && cp[1] != '\0' &&
    +		    strchr(" %&0^|~", cp[1]) != NULL)
    +			cp++;
    +		else if ( ! isspace((unsigned char)*cp))
    +			break;
    +	}
    +
    +	/* Skip trailing backslash. */
    +
    +	sz = strlen(cp);
    +	if (sz > 0 && cp[sz - 1] == '\\')
    +		sz--;
    +
    +	/* Skip trailing whitespace. */
    +
    +	for (; sz; sz--)
    +		if ( ! isspace((unsigned char)cp[sz-1]))
    +			break;
    +
    +	/* Skip empty strings. */
    +
    +	if (sz == 0)
    +		return;
    +
    +	if (*dest == NULL) {
    +		*dest = mandoc_strndup(cp, sz);
    +		return;
    +	}
    +
    +	mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
    +	free(*dest);
    +	*dest = cp;
    +}
    +
    +/* --- main functions of the roff parser ---------------------------------- */
    +
    +/*
    + * In the current line, expand escape sequences that tend to get
    + * used in numerical expressions and conditional requests.
    + * Also check the syntax of the remaining escape sequences.
    + */
    +static enum rofferr
    +roff_res(struct roff *r, struct buf *buf, int ln, int pos)
    +{
    +	char		 ubuf[24]; /* buffer to print the number */
    +	struct roff_node *n;	/* used for header comments */
    +	const char	*start;	/* start of the string to process */
    +	char		*stesc;	/* start of an escape sequence ('\\') */
    +	char		*ep;	/* end of comment string */
    +	const char	*stnam;	/* start of the name, after "[(*" */
    +	const char	*cp;	/* end of the name, e.g. before ']' */
    +	const char	*res;	/* the string to be substituted */
    +	char		*nbuf;	/* new buffer to copy buf->buf to */
    +	size_t		 maxl;  /* expected length of the escape name */
    +	size_t		 naml;	/* actual length of the escape name */
    +	enum mandoc_esc	 esc;	/* type of the escape sequence */
    +	int		 inaml;	/* length returned from mandoc_escape() */
    +	int		 expand_count;	/* to avoid infinite loops */
    +	int		 npos;	/* position in numeric expression */
    +	int		 arg_complete; /* argument not interrupted by eol */
    +	int		 done;	/* no more input available */
    +	int		 deftype; /* type of definition to paste */
    +	int		 rcsid;	/* kind of RCS id seen */
    +	char		 sign;	/* increment number register */
    +	char		 term;	/* character terminating the escape */
    +
    +	/* Search forward for comments. */
    +
    +	done = 0;
    +	start = buf->buf + pos;
    +	for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) {
    +		if (stesc[0] != r->escape || stesc[1] == '\0')
    +			continue;
    +		stesc++;
    +		if (*stesc != '"' && *stesc != '#')
    +			continue;
    +
    +		/* Comment found, look for RCS id. */
    +
    +		rcsid = 0;
    +		if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) {
    +			rcsid = 1 << MANDOC_OS_OPENBSD;
    +			cp += 8;
    +		} else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) {
    +			rcsid = 1 << MANDOC_OS_NETBSD;
    +			cp += 7;
    +		}
    +		if (cp != NULL &&
    +		    isalnum((unsigned char)*cp) == 0 &&
    +		    strchr(cp, '$') != NULL) {
    +			if (r->man->meta.rcsids & rcsid)
    +				mandoc_msg(MANDOCERR_RCS_REP, r->parse,
    +				    ln, stesc + 1 - buf->buf, stesc + 1);
    +			r->man->meta.rcsids |= rcsid;
    +		}
    +
    +		/* Handle trailing whitespace. */
    +
    +		ep = strchr(stesc--, '\0') - 1;
    +		if (*ep == '\n') {
    +			done = 1;
    +			ep--;
    +		}
    +		if (*ep == ' ' || *ep == '\t')
    +			mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
    +			    ln, ep - buf->buf, NULL);
    +
    +		/*
    +		 * Save comments preceding the title macro
    +		 * in the syntax tree.
    +		 */
    +
    +		if (r->format == 0) {
    +			while (*ep == ' ' || *ep == '\t')
    +				ep--;
    +			ep[1] = '\0';
    +			n = roff_node_alloc(r->man,
    +			    ln, stesc + 1 - buf->buf,
    +			    ROFFT_COMMENT, TOKEN_NONE);
    +			n->string = mandoc_strdup(stesc + 2);
    +			roff_node_append(r->man, n);
    +			n->flags |= NODE_VALID | NODE_ENDED;
    +			r->man->next = ROFF_NEXT_SIBLING;
    +		}
    +
    +		/* Discard comments. */
    +
    +		while (stesc > start && stesc[-1] == ' ')
    +			stesc--;
    +		*stesc = '\0';
    +		break;
    +	}
    +	if (stesc == start)
    +		return ROFF_CONT;
    +	stesc--;
    +
    +	/* Notice the end of the input. */
    +
    +	if (*stesc == '\n') {
    +		*stesc-- = '\0';
    +		done = 1;
    +	}
    +
    +	expand_count = 0;
    +	while (stesc >= start) {
    +
    +		/* Search backwards for the next backslash. */
    +
    +		if (*stesc != r->escape) {
    +			if (*stesc == '\\') {
    +				*stesc = '\0';
    +				buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s",
    +				    buf->buf, stesc + 1) + 1;
    +				start = nbuf + pos;
    +				stesc = nbuf + (stesc - buf->buf);
    +				free(buf->buf);
    +				buf->buf = nbuf;
    +			}
    +			stesc--;
    +			continue;
    +		}
    +
    +		/* If it is escaped, skip it. */
    +
    +		for (cp = stesc - 1; cp >= start; cp--)
    +			if (*cp != r->escape)
    +				break;
    +
    +		if ((stesc - cp) % 2 == 0) {
    +			while (stesc > cp)
    +				*stesc-- = '\\';
    +			continue;
    +		} else if (stesc[1] != '\0') {
    +			*stesc = '\\';
    +		} else {
    +			*stesc-- = '\0';
    +			if (done)
    +				continue;
    +			else
    +				return ROFF_APPEND;
    +		}
    +
    +		/* Decide whether to expand or to check only. */
    +
    +		term = '\0';
    +		cp = stesc + 1;
    +		switch (*cp) {
    +		case '*':
    +			res = NULL;
    +			break;
    +		case 'B':
    +		case 'w':
    +			term = cp[1];
    +			/* FALLTHROUGH */
    +		case 'n':
    +			sign = cp[1];
    +			if (sign == '+' || sign == '-')
    +				cp++;
    +			res = ubuf;
    +			break;
    +		default:
    +			esc = mandoc_escape(&cp, &stnam, &inaml);
    +			if (esc == ESCAPE_ERROR ||
    +			    (esc == ESCAPE_SPECIAL &&
    +			     mchars_spec2cp(stnam, inaml) < 0))
    +				mandoc_vmsg(MANDOCERR_ESC_BAD,
    +				    r->parse, ln, (int)(stesc - buf->buf),
    +				    "%.*s", (int)(cp - stesc), stesc);
    +			stesc--;
    +			continue;
    +		}
    +
    +		if (EXPAND_LIMIT < ++expand_count) {
    +			mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
    +			    ln, (int)(stesc - buf->buf), NULL);
    +			return ROFF_IGN;
    +		}
    +
    +		/*
    +		 * The third character decides the length
    +		 * of the name of the string or register.
    +		 * Save a pointer to the name.
    +		 */
    +
    +		if (term == '\0') {
    +			switch (*++cp) {
    +			case '\0':
    +				maxl = 0;
    +				break;
    +			case '(':
    +				cp++;
    +				maxl = 2;
    +				break;
    +			case '[':
    +				cp++;
    +				term = ']';
    +				maxl = 0;
    +				break;
    +			default:
    +				maxl = 1;
    +				break;
    +			}
    +		} else {
    +			cp += 2;
    +			maxl = 0;
    +		}
    +		stnam = cp;
    +
    +		/* Advance to the end of the name. */
    +
    +		naml = 0;
    +		arg_complete = 1;
    +		while (maxl == 0 || naml < maxl) {
    +			if (*cp == '\0') {
    +				mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
    +				    ln, (int)(stesc - buf->buf), stesc);
    +				arg_complete = 0;
    +				break;
    +			}
    +			if (maxl == 0 && *cp == term) {
    +				cp++;
    +				break;
    +			}
    +			if (*cp++ != '\\' || stesc[1] != 'w') {
    +				naml++;
    +				continue;
    +			}
    +			switch (mandoc_escape(&cp, NULL, NULL)) {
    +			case ESCAPE_SPECIAL:
    +			case ESCAPE_UNICODE:
    +			case ESCAPE_NUMBERED:
    +			case ESCAPE_OVERSTRIKE:
    +				naml++;
    +				break;
    +			default:
    +				break;
    +			}
    +		}
    +
    +		/*
    +		 * Retrieve the replacement string; if it is
    +		 * undefined, resume searching for escapes.
    +		 */
    +
    +		switch (stesc[1]) {
    +		case '*':
    +			if (arg_complete) {
    +				deftype = ROFFDEF_USER | ROFFDEF_PRE;
    +				res = roff_getstrn(r, stnam, naml, &deftype);
    +			}
    +			break;
    +		case 'B':
    +			npos = 0;
    +			ubuf[0] = arg_complete &&
    +			    roff_evalnum(r, ln, stnam, &npos,
    +			      NULL, ROFFNUM_SCALE) &&
    +			    stnam + npos + 1 == cp ? '1' : '0';
    +			ubuf[1] = '\0';
    +			break;
    +		case 'n':
    +			if (arg_complete)
    +				(void)snprintf(ubuf, sizeof(ubuf), "%d",
    +				    roff_getregn(r, stnam, naml, sign));
    +			else
    +				ubuf[0] = '\0';
    +			break;
    +		case 'w':
    +			/* use even incomplete args */
    +			(void)snprintf(ubuf, sizeof(ubuf), "%d",
    +			    24 * (int)naml);
    +			break;
    +		}
    +
    +		if (res == NULL) {
    +			mandoc_vmsg(MANDOCERR_STR_UNDEF,
    +			    r->parse, ln, (int)(stesc - buf->buf),
    +			    "%.*s", (int)naml, stnam);
    +			res = "";
    +		} else if (buf->sz + strlen(res) > SHRT_MAX) {
    +			mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
    +			    ln, (int)(stesc - buf->buf), NULL);
    +			return ROFF_IGN;
    +		}
    +
    +		/* Replace the escape sequence by the string. */
    +
    +		*stesc = '\0';
    +		buf->sz = mandoc_asprintf(&nbuf, "%s%s%s",
    +		    buf->buf, res, cp) + 1;
    +
    +		/* Prepare for the next replacement. */
    +
    +		start = nbuf + pos;
    +		stesc = nbuf + (stesc - buf->buf) + strlen(res);
    +		free(buf->buf);
    +		buf->buf = nbuf;
    +	}
    +	return ROFF_CONT;
    +}
    +
    +/*
    + * Process text streams.
    + */
    +static enum rofferr
    +roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs)
    +{
    +	size_t		 sz;
    +	const char	*start;
    +	char		*p;
    +	int		 isz;
    +	enum mandoc_esc	 esc;
    +
    +	/* Spring the input line trap. */
    +
    +	if (roffit_lines == 1) {
    +		isz = mandoc_asprintf(&p, "%s\n.%s", buf->buf, roffit_macro);
    +		free(buf->buf);
    +		buf->buf = p;
    +		buf->sz = isz + 1;
    +		*offs = 0;
    +		free(roffit_macro);
    +		roffit_lines = 0;
    +		return ROFF_REPARSE;
    +	} else if (roffit_lines > 1)
    +		--roffit_lines;
    +
    +	if (roffce_node != NULL && buf->buf[pos] != '\0') {
    +		if (roffce_lines < 1) {
    +			r->man->last = roffce_node;
    +			r->man->next = ROFF_NEXT_SIBLING;
    +			roffce_lines = 0;
    +			roffce_node = NULL;
    +		} else
    +			roffce_lines--;
    +	}
    +
    +	/* Convert all breakable hyphens into ASCII_HYPH. */
    +
    +	start = p = buf->buf + pos;
    +
    +	while (*p != '\0') {
    +		sz = strcspn(p, "-\\");
    +		p += sz;
    +
    +		if (*p == '\0')
    +			break;
    +
    +		if (*p == '\\') {
    +			/* Skip over escapes. */
    +			p++;
    +			esc = mandoc_escape((const char **)&p, NULL, NULL);
    +			if (esc == ESCAPE_ERROR)
    +				break;
    +			while (*p == '-')
    +				p++;
    +			continue;
    +		} else if (p == start) {
    +			p++;
    +			continue;
    +		}
    +
    +		if (isalpha((unsigned char)p[-1]) &&
    +		    isalpha((unsigned char)p[1]))
    +			*p = ASCII_HYPH;
    +		p++;
    +	}
    +	return ROFF_CONT;
    +}
    +
    +enum rofferr
    +roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
    +{
    +	enum roff_tok	 t;
    +	enum rofferr	 e;
    +	int		 pos;	/* parse point */
    +	int		 spos;	/* saved parse point for messages */
    +	int		 ppos;	/* original offset in buf->buf */
    +	int		 ctl;	/* macro line (boolean) */
    +
    +	ppos = pos = *offs;
    +
    +	/* Handle in-line equation delimiters. */
    +
    +	if (r->tbl == NULL &&
    +	    r->last_eqn != NULL && r->last_eqn->delim &&
    +	    (r->eqn == NULL || r->eqn_inline)) {
    +		e = roff_eqndelim(r, buf, pos);
    +		if (e == ROFF_REPARSE)
    +			return e;
    +		assert(e == ROFF_CONT);
    +	}
    +
    +	/* Expand some escape sequences. */
    +
    +	e = roff_res(r, buf, ln, pos);
    +	if (e == ROFF_IGN || e == ROFF_APPEND)
    +		return e;
    +	assert(e == ROFF_CONT);
    +
    +	ctl = roff_getcontrol(r, buf->buf, &pos);
    +
    +	/*
    +	 * First, if a scope is open and we're not a macro, pass the
    +	 * text through the macro's filter.
    +	 * Equations process all content themselves.
    +	 * Tables process almost all content themselves, but we want
    +	 * to warn about macros before passing it there.
    +	 */
    +
    +	if (r->last != NULL && ! ctl) {
    +		t = r->last->tok;
    +		e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs);
    +		if (e == ROFF_IGN)
    +			return e;
    +		assert(e == ROFF_CONT);
    +	}
    +	if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) {
    +		eqn_read(r->eqn, buf->buf + ppos);
    +		return ROFF_IGN;
    +	}
    +	if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) {
    +		tbl_read(r->tbl, ln, buf->buf, ppos);
    +		roff_addtbl(r->man, r->tbl);
    +		return ROFF_IGN;
    +	}
    +	if ( ! ctl)
    +		return roff_parsetext(r, buf, pos, offs);
    +
    +	/* Skip empty request lines. */
    +
    +	if (buf->buf[pos] == '"') {
    +		mandoc_msg(MANDOCERR_COMMENT_BAD, r->parse,
    +		    ln, pos, NULL);
    +		return ROFF_IGN;
    +	} else if (buf->buf[pos] == '\0')
    +		return ROFF_IGN;
    +
    +	/*
    +	 * If a scope is open, go to the child handler for that macro,
    +	 * as it may want to preprocess before doing anything with it.
    +	 * Don't do so if an equation is open.
    +	 */
    +
    +	if (r->last) {
    +		t = r->last->tok;
    +		return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs);
    +	}
    +
    +	/* No scope is open.  This is a new request or macro. */
    +
    +	spos = pos;
    +	t = roff_parse(r, buf->buf, &pos, ln, ppos);
    +
    +	/* Tables ignore most macros. */
    +
    +	if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS ||
    +	    t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) {
    +		mandoc_msg(MANDOCERR_TBLMACRO, r->parse,
    +		    ln, pos, buf->buf + spos);
    +		if (t != TOKEN_NONE)
    +			return ROFF_IGN;
    +		while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
    +			pos++;
    +		while (buf->buf[pos] == ' ')
    +			pos++;
    +		tbl_read(r->tbl, ln, buf->buf, pos);
    +		roff_addtbl(r->man, r->tbl);
    +		return ROFF_IGN;
    +	}
    +
    +	/* For now, let high level macros abort .ce mode. */
    +
    +	if (ctl && roffce_node != NULL &&
    +	    (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ ||
    +	     t == ROFF_TH || t == ROFF_TS)) {
    +		r->man->last = roffce_node;
    +		r->man->next = ROFF_NEXT_SIBLING;
    +		roffce_lines = 0;
    +		roffce_node = NULL;
    +	}
    +
    +	/*
    +	 * This is neither a roff request nor a user-defined macro.
    +	 * Let the standard macro set parsers handle it.
    +	 */
    +
    +	if (t == TOKEN_NONE)
    +		return ROFF_CONT;
    +
    +	/* Execute a roff request or a user defined macro. */
    +
    +	return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs);
    +}
    +
    +void
    +roff_endparse(struct roff *r)
    +{
    +	if (r->last != NULL)
    +		mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
    +		    r->last->line, r->last->col,
    +		    roff_name[r->last->tok]);
    +
    +	if (r->eqn != NULL) {
    +		mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
    +		    r->eqn->node->line, r->eqn->node->pos, "EQ");
    +		eqn_parse(r->eqn);
    +		r->eqn = NULL;
    +	}
    +
    +	if (r->tbl != NULL) {
    +		mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
    +		    r->tbl->line, r->tbl->pos, "TS");
    +		tbl_end(r->tbl);
    +		r->tbl = NULL;
    +	}
    +}
    +
    +/*
    + * Parse a roff node's type from the input buffer.  This must be in the
    + * form of ".foo xxx" in the usual way.
    + */
    +static enum roff_tok
    +roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
    +{
    +	char		*cp;
    +	const char	*mac;
    +	size_t		 maclen;
    +	int		 deftype;
    +	enum roff_tok	 t;
    +
    +	cp = buf + *pos;
    +
    +	if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp)
    +		return TOKEN_NONE;
    +
    +	mac = cp;
    +	maclen = roff_getname(r, &cp, ln, ppos);
    +
    +	deftype = ROFFDEF_USER | ROFFDEF_REN;
    +	r->current_string = roff_getstrn(r, mac, maclen, &deftype);
    +	switch (deftype) {
    +	case ROFFDEF_USER:
    +		t = ROFF_USERDEF;
    +		break;
    +	case ROFFDEF_REN:
    +		t = ROFF_RENAMED;
    +		break;
    +	default:
    +		t = roffhash_find(r->reqtab, mac, maclen);
    +		break;
    +	}
    +	if (t != TOKEN_NONE)
    +		*pos = cp - buf;
    +	else if (deftype == ROFFDEF_UNDEF) {
    +		/* Using an undefined macro defines it to be empty. */
    +		roff_setstrn(&r->strtab, mac, maclen, "", 0, 0);
    +		roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0);
    +	}
    +	return t;
    +}
    +
    +/* --- handling of request blocks ----------------------------------------- */
    +
    +static enum rofferr
    +roff_cblock(ROFF_ARGS)
    +{
    +
    +	/*
    +	 * A block-close `..' should only be invoked as a child of an
    +	 * ignore macro, otherwise raise a warning and just ignore it.
    +	 */
    +
    +	if (r->last == NULL) {
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
    +		    ln, ppos, "..");
    +		return ROFF_IGN;
    +	}
    +
    +	switch (r->last->tok) {
    +	case ROFF_am:
    +		/* ROFF_am1 is remapped to ROFF_am in roff_block(). */
    +	case ROFF_ami:
    +	case ROFF_de:
    +		/* ROFF_de1 is remapped to ROFF_de in roff_block(). */
    +	case ROFF_dei:
    +	case ROFF_ig:
    +		break;
    +	default:
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
    +		    ln, ppos, "..");
    +		return ROFF_IGN;
    +	}
    +
    +	if (buf->buf[pos] != '\0')
    +		mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
    +		    ".. %s", buf->buf + pos);
    +
    +	roffnode_pop(r);
    +	roffnode_cleanscope(r);
    +	return ROFF_IGN;
    +
    +}
    +
    +static void
    +roffnode_cleanscope(struct roff *r)
    +{
    +
    +	while (r->last) {
    +		if (--r->last->endspan != 0)
    +			break;
    +		roffnode_pop(r);
    +	}
    +}
    +
    +static void
    +roff_ccond(struct roff *r, int ln, int ppos)
    +{
    +
    +	if (NULL == r->last) {
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
    +		    ln, ppos, "\\}");
    +		return;
    +	}
    +
    +	switch (r->last->tok) {
    +	case ROFF_el:
    +	case ROFF_ie:
    +	case ROFF_if:
    +		break;
    +	default:
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
    +		    ln, ppos, "\\}");
    +		return;
    +	}
    +
    +	if (r->last->endspan > -1) {
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
    +		    ln, ppos, "\\}");
    +		return;
    +	}
    +
    +	roffnode_pop(r);
    +	roffnode_cleanscope(r);
    +	return;
    +}
    +
    +static enum rofferr
    +roff_block(ROFF_ARGS)
    +{
    +	const char	*name, *value;
    +	char		*call, *cp, *iname, *rname;
    +	size_t		 csz, namesz, rsz;
    +	int		 deftype;
    +
    +	/* Ignore groff compatibility mode for now. */
    +
    +	if (tok == ROFF_de1)
    +		tok = ROFF_de;
    +	else if (tok == ROFF_dei1)
    +		tok = ROFF_dei;
    +	else if (tok == ROFF_am1)
    +		tok = ROFF_am;
    +	else if (tok == ROFF_ami1)
    +		tok = ROFF_ami;
    +
    +	/* Parse the macro name argument. */
    +
    +	cp = buf->buf + pos;
    +	if (tok == ROFF_ig) {
    +		iname = NULL;
    +		namesz = 0;
    +	} else {
    +		iname = cp;
    +		namesz = roff_getname(r, &cp, ln, ppos);
    +		iname[namesz] = '\0';
    +	}
    +
    +	/* Resolve the macro name argument if it is indirect. */
    +
    +	if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
    +		deftype = ROFFDEF_USER;
    +		name = roff_getstrn(r, iname, namesz, &deftype);
    +		if (name == NULL) {
    +			mandoc_vmsg(MANDOCERR_STR_UNDEF,
    +			    r->parse, ln, (int)(iname - buf->buf),
    +			    "%.*s", (int)namesz, iname);
    +			namesz = 0;
    +		} else
    +			namesz = strlen(name);
    +	} else
    +		name = iname;
    +
    +	if (namesz == 0 && tok != ROFF_ig) {
    +		mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse,
    +		    ln, ppos, roff_name[tok]);
    +		return ROFF_IGN;
    +	}
    +
    +	roffnode_push(r, tok, name, ln, ppos);
    +
    +	/*
    +	 * At the beginning of a `de' macro, clear the existing string
    +	 * with the same name, if there is one.  New content will be
    +	 * appended from roff_block_text() in multiline mode.
    +	 */
    +
    +	if (tok == ROFF_de || tok == ROFF_dei) {
    +		roff_setstrn(&r->strtab, name, namesz, "", 0, 0);
    +		roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
    +	} else if (tok == ROFF_am || tok == ROFF_ami) {
    +		deftype = ROFFDEF_ANY;
    +		value = roff_getstrn(r, iname, namesz, &deftype);
    +		switch (deftype) {  /* Before appending, ... */
    +		case ROFFDEF_PRE: /* copy predefined to user-defined. */
    +			roff_setstrn(&r->strtab, name, namesz,
    +			    value, strlen(value), 0);
    +			break;
    +		case ROFFDEF_REN: /* call original standard macro. */
    +			csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n",
    +			    (int)strlen(value), value);
    +			roff_setstrn(&r->strtab, name, namesz, call, csz, 0);
    +			roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
    +			free(call);
    +			break;
    +		case ROFFDEF_STD:  /* rename and call standard macro. */
    +			rsz = mandoc_asprintf(&rname, "__%s_renamed", name);
    +			roff_setstrn(&r->rentab, rname, rsz, name, namesz, 0);
    +			csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n",
    +			    (int)rsz, rname);
    +			roff_setstrn(&r->strtab, name, namesz, call, csz, 0);
    +			free(call);
    +			free(rname);
    +			break;
    +		default:
    +			break;
    +		}
    +	}
    +
    +	if (*cp == '\0')
    +		return ROFF_IGN;
    +
    +	/* Get the custom end marker. */
    +
    +	iname = cp;
    +	namesz = roff_getname(r, &cp, ln, ppos);
    +
    +	/* Resolve the end marker if it is indirect. */
    +
    +	if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
    +		deftype = ROFFDEF_USER;
    +		name = roff_getstrn(r, iname, namesz, &deftype);
    +		if (name == NULL) {
    +			mandoc_vmsg(MANDOCERR_STR_UNDEF,
    +			    r->parse, ln, (int)(iname - buf->buf),
    +			    "%.*s", (int)namesz, iname);
    +			namesz = 0;
    +		} else
    +			namesz = strlen(name);
    +	} else
    +		name = iname;
    +
    +	if (namesz)
    +		r->last->end = mandoc_strndup(name, namesz);
    +
    +	if (*cp != '\0')
    +		mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
    +		    ln, pos, ".%s ... %s", roff_name[tok], cp);
    +
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_block_sub(ROFF_ARGS)
    +{
    +	enum roff_tok	t;
    +	int		i, j;
    +
    +	/*
    +	 * First check whether a custom macro exists at this level.  If
    +	 * it does, then check against it.  This is some of groff's
    +	 * stranger behaviours.  If we encountered a custom end-scope
    +	 * tag and that tag also happens to be a "real" macro, then we
    +	 * need to try interpreting it again as a real macro.  If it's
    +	 * not, then return ignore.  Else continue.
    +	 */
    +
    +	if (r->last->end) {
    +		for (i = pos, j = 0; r->last->end[j]; j++, i++)
    +			if (buf->buf[i] != r->last->end[j])
    +				break;
    +
    +		if (r->last->end[j] == '\0' &&
    +		    (buf->buf[i] == '\0' ||
    +		     buf->buf[i] == ' ' ||
    +		     buf->buf[i] == '\t')) {
    +			roffnode_pop(r);
    +			roffnode_cleanscope(r);
    +
    +			while (buf->buf[i] == ' ' || buf->buf[i] == '\t')
    +				i++;
    +
    +			pos = i;
    +			if (roff_parse(r, buf->buf, &pos, ln, ppos) !=
    +			    TOKEN_NONE)
    +				return ROFF_RERUN;
    +			return ROFF_IGN;
    +		}
    +	}
    +
    +	/*
    +	 * If we have no custom end-query or lookup failed, then try
    +	 * pulling it out of the hashtable.
    +	 */
    +
    +	t = roff_parse(r, buf->buf, &pos, ln, ppos);
    +
    +	if (t != ROFF_cblock) {
    +		if (tok != ROFF_ig)
    +			roff_setstr(r, r->last->name, buf->buf + ppos, 2);
    +		return ROFF_IGN;
    +	}
    +
    +	return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
    +}
    +
    +static enum rofferr
    +roff_block_text(ROFF_ARGS)
    +{
    +
    +	if (tok != ROFF_ig)
    +		roff_setstr(r, r->last->name, buf->buf + pos, 2);
    +
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_cond_sub(ROFF_ARGS)
    +{
    +	enum roff_tok	 t;
    +	char		*ep;
    +	int		 rr;
    +
    +	rr = r->last->rule;
    +	roffnode_cleanscope(r);
    +
    +	/*
    +	 * If `\}' occurs on a macro line without a preceding macro,
    +	 * drop the line completely.
    +	 */
    +
    +	ep = buf->buf + pos;
    +	if (ep[0] == '\\' && ep[1] == '}')
    +		rr = 0;
    +
    +	/* Always check for the closing delimiter `\}'. */
    +
    +	while ((ep = strchr(ep, '\\')) != NULL) {
    +		switch (ep[1]) {
    +		case '}':
    +			memmove(ep, ep + 2, strlen(ep + 2) + 1);
    +			roff_ccond(r, ln, ep - buf->buf);
    +			break;
    +		case '\0':
    +			++ep;
    +			break;
    +		default:
    +			ep += 2;
    +			break;
    +		}
    +	}
    +
    +	/*
    +	 * Fully handle known macros when they are structurally
    +	 * required or when the conditional evaluated to true.
    +	 */
    +
    +	t = roff_parse(r, buf->buf, &pos, ln, ppos);
    +	return t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT)
    +	    ? (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : rr
    +	    ? ROFF_CONT : ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_cond_text(ROFF_ARGS)
    +{
    +	char		*ep;
    +	int		 rr;
    +
    +	rr = r->last->rule;
    +	roffnode_cleanscope(r);
    +
    +	ep = buf->buf + pos;
    +	while ((ep = strchr(ep, '\\')) != NULL) {
    +		if (*(++ep) == '}') {
    +			*ep = '&';
    +			roff_ccond(r, ln, ep - buf->buf - 1);
    +		}
    +		if (*ep != '\0')
    +			++ep;
    +	}
    +	return rr ? ROFF_CONT : ROFF_IGN;
    +}
    +
    +/* --- handling of numeric and conditional expressions -------------------- */
    +
    +/*
    + * Parse a single signed integer number.  Stop at the first non-digit.
    + * If there is at least one digit, return success and advance the
    + * parse point, else return failure and let the parse point unchanged.
    + * Ignore overflows, treat them just like the C language.
    + */
    +static int
    +roff_getnum(const char *v, int *pos, int *res, int flags)
    +{
    +	int	 myres, scaled, n, p;
    +
    +	if (NULL == res)
    +		res = &myres;
    +
    +	p = *pos;
    +	n = v[p] == '-';
    +	if (n || v[p] == '+')
    +		p++;
    +
    +	if (flags & ROFFNUM_WHITE)
    +		while (isspace((unsigned char)v[p]))
    +			p++;
    +
    +	for (*res = 0; isdigit((unsigned char)v[p]); p++)
    +		*res = 10 * *res + v[p] - '0';
    +	if (p == *pos + n)
    +		return 0;
    +
    +	if (n)
    +		*res = -*res;
    +
    +	/* Each number may be followed by one optional scaling unit. */
    +
    +	switch (v[p]) {
    +	case 'f':
    +		scaled = *res * 65536;
    +		break;
    +	case 'i':
    +		scaled = *res * 240;
    +		break;
    +	case 'c':
    +		scaled = *res * 240 / 2.54;
    +		break;
    +	case 'v':
    +	case 'P':
    +		scaled = *res * 40;
    +		break;
    +	case 'm':
    +	case 'n':
    +		scaled = *res * 24;
    +		break;
    +	case 'p':
    +		scaled = *res * 10 / 3;
    +		break;
    +	case 'u':
    +		scaled = *res;
    +		break;
    +	case 'M':
    +		scaled = *res * 6 / 25;
    +		break;
    +	default:
    +		scaled = *res;
    +		p--;
    +		break;
    +	}
    +	if (flags & ROFFNUM_SCALE)
    +		*res = scaled;
    +
    +	*pos = p + 1;
    +	return 1;
    +}
    +
    +/*
    + * Evaluate a string comparison condition.
    + * The first character is the delimiter.
    + * Succeed if the string up to its second occurrence
    + * matches the string up to its third occurence.
    + * Advance the cursor after the third occurrence
    + * or lacking that, to the end of the line.
    + */
    +static int
    +roff_evalstrcond(const char *v, int *pos)
    +{
    +	const char	*s1, *s2, *s3;
    +	int		 match;
    +
    +	match = 0;
    +	s1 = v + *pos;		/* initial delimiter */
    +	s2 = s1 + 1;		/* for scanning the first string */
    +	s3 = strchr(s2, *s1);	/* for scanning the second string */
    +
    +	if (NULL == s3)		/* found no middle delimiter */
    +		goto out;
    +
    +	while ('\0' != *++s3) {
    +		if (*s2 != *s3) {  /* mismatch */
    +			s3 = strchr(s3, *s1);
    +			break;
    +		}
    +		if (*s3 == *s1) {  /* found the final delimiter */
    +			match = 1;
    +			break;
    +		}
    +		s2++;
    +	}
    +
    +out:
    +	if (NULL == s3)
    +		s3 = strchr(s2, '\0');
    +	else if (*s3 != '\0')
    +		s3++;
    +	*pos = s3 - v;
    +	return match;
    +}
    +
    +/*
    + * Evaluate an optionally negated single character, numerical,
    + * or string condition.
    + */
    +static int
    +roff_evalcond(struct roff *r, int ln, char *v, int *pos)
    +{
    +	char	*cp, *name;
    +	size_t	 sz;
    +	int	 deftype, number, savepos, istrue, wanttrue;
    +
    +	if ('!' == v[*pos]) {
    +		wanttrue = 0;
    +		(*pos)++;
    +	} else
    +		wanttrue = 1;
    +
    +	switch (v[*pos]) {
    +	case '\0':
    +		return 0;
    +	case 'n':
    +	case 'o':
    +		(*pos)++;
    +		return wanttrue;
    +	case 'c':
    +	case 'e':
    +	case 't':
    +	case 'v':
    +		(*pos)++;
    +		return !wanttrue;
    +	case 'd':
    +	case 'r':
    +		cp = v + *pos + 1;
    +		while (*cp == ' ')
    +			cp++;
    +		name = cp;
    +		sz = roff_getname(r, &cp, ln, cp - v);
    +		if (sz == 0)
    +			istrue = 0;
    +		else if (v[*pos] == 'r')
    +			istrue = roff_hasregn(r, name, sz);
    +		else {
    +			deftype = ROFFDEF_ANY;
    +		        roff_getstrn(r, name, sz, &deftype);
    +			istrue = !!deftype;
    +		}
    +		*pos = cp - v;
    +		return istrue == wanttrue;
    +	default:
    +		break;
    +	}
    +
    +	savepos = *pos;
    +	if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE))
    +		return (number > 0) == wanttrue;
    +	else if (*pos == savepos)
    +		return roff_evalstrcond(v, pos) == wanttrue;
    +	else
    +		return 0;
    +}
    +
    +static enum rofferr
    +roff_line_ignore(ROFF_ARGS)
    +{
    +
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_insec(ROFF_ARGS)
    +{
    +
    +	mandoc_msg(MANDOCERR_REQ_INSEC, r->parse,
    +	    ln, ppos, roff_name[tok]);
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_unsupp(ROFF_ARGS)
    +{
    +
    +	mandoc_msg(MANDOCERR_REQ_UNSUPP, r->parse,
    +	    ln, ppos, roff_name[tok]);
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_cond(ROFF_ARGS)
    +{
    +
    +	roffnode_push(r, tok, NULL, ln, ppos);
    +
    +	/*
    +	 * An `.el' has no conditional body: it will consume the value
    +	 * of the current rstack entry set in prior `ie' calls or
    +	 * defaults to DENY.
    +	 *
    +	 * If we're not an `el', however, then evaluate the conditional.
    +	 */
    +
    +	r->last->rule = tok == ROFF_el ?
    +	    (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) :
    +	    roff_evalcond(r, ln, buf->buf, &pos);
    +
    +	/*
    +	 * An if-else will put the NEGATION of the current evaluated
    +	 * conditional into the stack of rules.
    +	 */
    +
    +	if (tok == ROFF_ie) {
    +		if (r->rstackpos + 1 == r->rstacksz) {
    +			r->rstacksz += 16;
    +			r->rstack = mandoc_reallocarray(r->rstack,
    +			    r->rstacksz, sizeof(int));
    +		}
    +		r->rstack[++r->rstackpos] = !r->last->rule;
    +	}
    +
    +	/* If the parent has false as its rule, then so do we. */
    +
    +	if (r->last->parent && !r->last->parent->rule)
    +		r->last->rule = 0;
    +
    +	/*
    +	 * Determine scope.
    +	 * If there is nothing on the line after the conditional,
    +	 * not even whitespace, use next-line scope.
    +	 */
    +
    +	if (buf->buf[pos] == '\0') {
    +		r->last->endspan = 2;
    +		goto out;
    +	}
    +
    +	while (buf->buf[pos] == ' ')
    +		pos++;
    +
    +	/* An opening brace requests multiline scope. */
    +
    +	if (buf->buf[pos] == '\\' && buf->buf[pos + 1] == '{') {
    +		r->last->endspan = -1;
    +		pos += 2;
    +		while (buf->buf[pos] == ' ')
    +			pos++;
    +		goto out;
    +	}
    +
    +	/*
    +	 * Anything else following the conditional causes
    +	 * single-line scope.  Warn if the scope contains
    +	 * nothing but trailing whitespace.
    +	 */
    +
    +	if (buf->buf[pos] == '\0')
    +		mandoc_msg(MANDOCERR_COND_EMPTY, r->parse,
    +		    ln, ppos, roff_name[tok]);
    +
    +	r->last->endspan = 1;
    +
    +out:
    +	*offs = pos;
    +	return ROFF_RERUN;
    +}
    +
    +static enum rofferr
    +roff_ds(ROFF_ARGS)
    +{
    +	char		*string;
    +	const char	*name;
    +	size_t		 namesz;
    +
    +	/* Ignore groff compatibility mode for now. */
    +
    +	if (tok == ROFF_ds1)
    +		tok = ROFF_ds;
    +	else if (tok == ROFF_as1)
    +		tok = ROFF_as;
    +
    +	/*
    +	 * The first word is the name of the string.
    +	 * If it is empty or terminated by an escape sequence,
    +	 * abort the `ds' request without defining anything.
    +	 */
    +
    +	name = string = buf->buf + pos;
    +	if (*name == '\0')
    +		return ROFF_IGN;
    +
    +	namesz = roff_getname(r, &string, ln, pos);
    +	if (name[namesz] == '\\')
    +		return ROFF_IGN;
    +
    +	/* Read past the initial double-quote, if any. */
    +	if (*string == '"')
    +		string++;
    +
    +	/* The rest is the value. */
    +	roff_setstrn(&r->strtab, name, namesz, string, strlen(string),
    +	    ROFF_as == tok);
    +	roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
    +	return ROFF_IGN;
    +}
    +
    +/*
    + * Parse a single operator, one or two characters long.
    + * If the operator is recognized, return success and advance the
    + * parse point, else return failure and let the parse point unchanged.
    + */
    +static int
    +roff_getop(const char *v, int *pos, char *res)
    +{
    +
    +	*res = v[*pos];
    +
    +	switch (*res) {
    +	case '+':
    +	case '-':
    +	case '*':
    +	case '/':
    +	case '%':
    +	case '&':
    +	case ':':
    +		break;
    +	case '<':
    +		switch (v[*pos + 1]) {
    +		case '=':
    +			*res = 'l';
    +			(*pos)++;
    +			break;
    +		case '>':
    +			*res = '!';
    +			(*pos)++;
    +			break;
    +		case '?':
    +			*res = 'i';
    +			(*pos)++;
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	case '>':
    +		switch (v[*pos + 1]) {
    +		case '=':
    +			*res = 'g';
    +			(*pos)++;
    +			break;
    +		case '?':
    +			*res = 'a';
    +			(*pos)++;
    +			break;
    +		default:
    +			break;
    +		}
    +		break;
    +	case '=':
    +		if ('=' == v[*pos + 1])
    +			(*pos)++;
    +		break;
    +	default:
    +		return 0;
    +	}
    +	(*pos)++;
    +
    +	return *res;
    +}
    +
    +/*
    + * Evaluate either a parenthesized numeric expression
    + * or a single signed integer number.
    + */
    +static int
    +roff_evalpar(struct roff *r, int ln,
    +	const char *v, int *pos, int *res, int flags)
    +{
    +
    +	if ('(' != v[*pos])
    +		return roff_getnum(v, pos, res, flags);
    +
    +	(*pos)++;
    +	if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE))
    +		return 0;
    +
    +	/*
    +	 * Omission of the closing parenthesis
    +	 * is an error in validation mode,
    +	 * but ignored in evaluation mode.
    +	 */
    +
    +	if (')' == v[*pos])
    +		(*pos)++;
    +	else if (NULL == res)
    +		return 0;
    +
    +	return 1;
    +}
    +
    +/*
    + * Evaluate a complete numeric expression.
    + * Proceed left to right, there is no concept of precedence.
    + */
    +static int
    +roff_evalnum(struct roff *r, int ln, const char *v,
    +	int *pos, int *res, int flags)
    +{
    +	int		 mypos, operand2;
    +	char		 operator;
    +
    +	if (NULL == pos) {
    +		mypos = 0;
    +		pos = &mypos;
    +	}
    +
    +	if (flags & ROFFNUM_WHITE)
    +		while (isspace((unsigned char)v[*pos]))
    +			(*pos)++;
    +
    +	if ( ! roff_evalpar(r, ln, v, pos, res, flags))
    +		return 0;
    +
    +	while (1) {
    +		if (flags & ROFFNUM_WHITE)
    +			while (isspace((unsigned char)v[*pos]))
    +				(*pos)++;
    +
    +		if ( ! roff_getop(v, pos, &operator))
    +			break;
    +
    +		if (flags & ROFFNUM_WHITE)
    +			while (isspace((unsigned char)v[*pos]))
    +				(*pos)++;
    +
    +		if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags))
    +			return 0;
    +
    +		if (flags & ROFFNUM_WHITE)
    +			while (isspace((unsigned char)v[*pos]))
    +				(*pos)++;
    +
    +		if (NULL == res)
    +			continue;
    +
    +		switch (operator) {
    +		case '+':
    +			*res += operand2;
    +			break;
    +		case '-':
    +			*res -= operand2;
    +			break;
    +		case '*':
    +			*res *= operand2;
    +			break;
    +		case '/':
    +			if (operand2 == 0) {
    +				mandoc_msg(MANDOCERR_DIVZERO,
    +					r->parse, ln, *pos, v);
    +				*res = 0;
    +				break;
    +			}
    +			*res /= operand2;
    +			break;
    +		case '%':
    +			if (operand2 == 0) {
    +				mandoc_msg(MANDOCERR_DIVZERO,
    +					r->parse, ln, *pos, v);
    +				*res = 0;
    +				break;
    +			}
    +			*res %= operand2;
    +			break;
    +		case '<':
    +			*res = *res < operand2;
    +			break;
    +		case '>':
    +			*res = *res > operand2;
    +			break;
    +		case 'l':
    +			*res = *res <= operand2;
    +			break;
    +		case 'g':
    +			*res = *res >= operand2;
    +			break;
    +		case '=':
    +			*res = *res == operand2;
    +			break;
    +		case '!':
    +			*res = *res != operand2;
    +			break;
    +		case '&':
    +			*res = *res && operand2;
    +			break;
    +		case ':':
    +			*res = *res || operand2;
    +			break;
    +		case 'i':
    +			if (operand2 < *res)
    +				*res = operand2;
    +			break;
    +		case 'a':
    +			if (operand2 > *res)
    +				*res = operand2;
    +			break;
    +		default:
    +			abort();
    +		}
    +	}
    +	return 1;
    +}
    +
    +/* --- register management ------------------------------------------------ */
    +
    +void
    +roff_setreg(struct roff *r, const char *name, int val, char sign)
    +{
    +	roff_setregn(r, name, strlen(name), val, sign, INT_MIN);
    +}
    +
    +static void
    +roff_setregn(struct roff *r, const char *name, size_t len,
    +    int val, char sign, int step)
    +{
    +	struct roffreg	*reg;
    +
    +	/* Search for an existing register with the same name. */
    +	reg = r->regtab;
    +
    +	while (reg != NULL && (reg->key.sz != len ||
    +	    strncmp(reg->key.p, name, len) != 0))
    +		reg = reg->next;
    +
    +	if (NULL == reg) {
    +		/* Create a new register. */
    +		reg = mandoc_malloc(sizeof(struct roffreg));
    +		reg->key.p = mandoc_strndup(name, len);
    +		reg->key.sz = len;
    +		reg->val = 0;
    +		reg->step = 0;
    +		reg->next = r->regtab;
    +		r->regtab = reg;
    +	}
    +
    +	if ('+' == sign)
    +		reg->val += val;
    +	else if ('-' == sign)
    +		reg->val -= val;
    +	else
    +		reg->val = val;
    +	if (step != INT_MIN)
    +		reg->step = step;
    +}
    +
    +/*
    + * Handle some predefined read-only number registers.
    + * For now, return -1 if the requested register is not predefined;
    + * in case a predefined read-only register having the value -1
    + * were to turn up, another special value would have to be chosen.
    + */
    +static int
    +roff_getregro(const struct roff *r, const char *name)
    +{
    +
    +	switch (*name) {
    +	case '$':  /* Number of arguments of the last macro evaluated. */
    +		return r->argc;
    +	case 'A':  /* ASCII approximation mode is always off. */
    +		return 0;
    +	case 'g':  /* Groff compatibility mode is always on. */
    +		return 1;
    +	case 'H':  /* Fixed horizontal resolution. */
    +		return 24;
    +	case 'j':  /* Always adjust left margin only. */
    +		return 0;
    +	case 'T':  /* Some output device is always defined. */
    +		return 1;
    +	case 'V':  /* Fixed vertical resolution. */
    +		return 40;
    +	default:
    +		return -1;
    +	}
    +}
    +
    +int
    +roff_getreg(struct roff *r, const char *name)
    +{
    +	return roff_getregn(r, name, strlen(name), '\0');
    +}
    +
    +static int
    +roff_getregn(struct roff *r, const char *name, size_t len, char sign)
    +{
    +	struct roffreg	*reg;
    +	int		 val;
    +
    +	if ('.' == name[0] && 2 == len) {
    +		val = roff_getregro(r, name + 1);
    +		if (-1 != val)
    +			return val;
    +	}
    +
    +	for (reg = r->regtab; reg; reg = reg->next) {
    +		if (len == reg->key.sz &&
    +		    0 == strncmp(name, reg->key.p, len)) {
    +			switch (sign) {
    +			case '+':
    +				reg->val += reg->step;
    +				break;
    +			case '-':
    +				reg->val -= reg->step;
    +				break;
    +			default:
    +				break;
    +			}
    +			return reg->val;
    +		}
    +	}
    +
    +	roff_setregn(r, name, len, 0, '\0', INT_MIN);
    +	return 0;
    +}
    +
    +static int
    +roff_hasregn(const struct roff *r, const char *name, size_t len)
    +{
    +	struct roffreg	*reg;
    +	int		 val;
    +
    +	if ('.' == name[0] && 2 == len) {
    +		val = roff_getregro(r, name + 1);
    +		if (-1 != val)
    +			return 1;
    +	}
    +
    +	for (reg = r->regtab; reg; reg = reg->next)
    +		if (len == reg->key.sz &&
    +		    0 == strncmp(name, reg->key.p, len))
    +			return 1;
    +
    +	return 0;
    +}
    +
    +static void
    +roff_freereg(struct roffreg *reg)
    +{
    +	struct roffreg	*old_reg;
    +
    +	while (NULL != reg) {
    +		free(reg->key.p);
    +		old_reg = reg;
    +		reg = reg->next;
    +		free(old_reg);
    +	}
    +}
    +
    +static enum rofferr
    +roff_nr(ROFF_ARGS)
    +{
    +	char		*key, *val, *step;
    +	size_t		 keysz;
    +	int		 iv, is, len;
    +	char		 sign;
    +
    +	key = val = buf->buf + pos;
    +	if (*key == '\0')
    +		return ROFF_IGN;
    +
    +	keysz = roff_getname(r, &val, ln, pos);
    +	if (key[keysz] == '\\')
    +		return ROFF_IGN;
    +
    +	sign = *val;
    +	if (sign == '+' || sign == '-')
    +		val++;
    +
    +	len = 0;
    +	if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
    +		return ROFF_IGN;
    +
    +	step = val + len;
    +	while (isspace((unsigned char)*step))
    +		step++;
    +	if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
    +		is = INT_MIN;
    +
    +	roff_setregn(r, key, keysz, iv, sign, is);
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_rr(ROFF_ARGS)
    +{
    +	struct roffreg	*reg, **prev;
    +	char		*name, *cp;
    +	size_t		 namesz;
    +
    +	name = cp = buf->buf + pos;
    +	if (*name == '\0')
    +		return ROFF_IGN;
    +	namesz = roff_getname(r, &cp, ln, pos);
    +	name[namesz] = '\0';
    +
    +	prev = &r->regtab;
    +	while (1) {
    +		reg = *prev;
    +		if (reg == NULL || !strcmp(name, reg->key.p))
    +			break;
    +		prev = ®->next;
    +	}
    +	if (reg != NULL) {
    +		*prev = reg->next;
    +		free(reg->key.p);
    +		free(reg);
    +	}
    +	return ROFF_IGN;
    +}
    +
    +/* --- handler functions for roff requests -------------------------------- */
    +
    +static enum rofferr
    +roff_rm(ROFF_ARGS)
    +{
    +	const char	 *name;
    +	char		 *cp;
    +	size_t		  namesz;
    +
    +	cp = buf->buf + pos;
    +	while (*cp != '\0') {
    +		name = cp;
    +		namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf));
    +		roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
    +		roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
    +		if (name[namesz] == '\\')
    +			break;
    +	}
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_it(ROFF_ARGS)
    +{
    +	int		 iv;
    +
    +	/* Parse the number of lines. */
    +
    +	if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
    +		mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
    +		    ln, ppos, buf->buf + 1);
    +		return ROFF_IGN;
    +	}
    +
    +	while (isspace((unsigned char)buf->buf[pos]))
    +		pos++;
    +
    +	/*
    +	 * Arm the input line trap.
    +	 * Special-casing "an-trap" is an ugly workaround to cope
    +	 * with DocBook stupidly fiddling with man(7) internals.
    +	 */
    +
    +	roffit_lines = iv;
    +	roffit_macro = mandoc_strdup(iv != 1 ||
    +	    strcmp(buf->buf + pos, "an-trap") ?
    +	    buf->buf + pos : "br");
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_Dd(ROFF_ARGS)
    +{
    +	int		 mask;
    +	enum roff_tok	 t, te;
    +
    +	switch (tok) {
    +	case ROFF_Dd:
    +		tok = MDOC_Dd;
    +		te = MDOC_MAX;
    +		if (r->format == 0)
    +			r->format = MPARSE_MDOC;
    +		mask = MPARSE_MDOC | MPARSE_QUICK;
    +		break;
    +	case ROFF_TH:
    +		tok = MAN_TH;
    +		te = MAN_MAX;
    +		if (r->format == 0)
    +			r->format = MPARSE_MAN;
    +		mask = MPARSE_QUICK;
    +		break;
    +	default:
    +		abort();
    +	}
    +	if ((r->options & mask) == 0)
    +		for (t = tok; t < te; t++)
    +			roff_setstr(r, roff_name[t], NULL, 0);
    +	return ROFF_CONT;
    +}
    +
    +static enum rofferr
    +roff_TE(ROFF_ARGS)
    +{
    +	if (r->tbl == NULL) {
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
    +		    ln, ppos, "TE");
    +		return ROFF_IGN;
    +	}
    +	if (tbl_end(r->tbl) == 0) {
    +		r->tbl = NULL;
    +		free(buf->buf);
    +		buf->buf = mandoc_strdup(".sp");
    +		buf->sz = 4;
    +		*offs = 0;
    +		return ROFF_REPARSE;
    +	}
    +	r->tbl = NULL;
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_T_(ROFF_ARGS)
    +{
    +
    +	if (NULL == r->tbl)
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
    +		    ln, ppos, "T&");
    +	else
    +		tbl_restart(ln, ppos, r->tbl);
    +
    +	return ROFF_IGN;
    +}
    +
    +/*
    + * Handle in-line equation delimiters.
    + */
    +static enum rofferr
    +roff_eqndelim(struct roff *r, struct buf *buf, int pos)
    +{
    +	char		*cp1, *cp2;
    +	const char	*bef_pr, *bef_nl, *mac, *aft_nl, *aft_pr;
    +
    +	/*
    +	 * Outside equations, look for an opening delimiter.
    +	 * If we are inside an equation, we already know it is
    +	 * in-line, or this function wouldn't have been called;
    +	 * so look for a closing delimiter.
    +	 */
    +
    +	cp1 = buf->buf + pos;
    +	cp2 = strchr(cp1, r->eqn == NULL ?
    +	    r->last_eqn->odelim : r->last_eqn->cdelim);
    +	if (cp2 == NULL)
    +		return ROFF_CONT;
    +
    +	*cp2++ = '\0';
    +	bef_pr = bef_nl = aft_nl = aft_pr = "";
    +
    +	/* Handle preceding text, protecting whitespace. */
    +
    +	if (*buf->buf != '\0') {
    +		if (r->eqn == NULL)
    +			bef_pr = "\\&";
    +		bef_nl = "\n";
    +	}
    +
    +	/*
    +	 * Prepare replacing the delimiter with an equation macro
    +	 * and drop leading white space from the equation.
    +	 */
    +
    +	if (r->eqn == NULL) {
    +		while (*cp2 == ' ')
    +			cp2++;
    +		mac = ".EQ";
    +	} else
    +		mac = ".EN";
    +
    +	/* Handle following text, protecting whitespace. */
    +
    +	if (*cp2 != '\0') {
    +		aft_nl = "\n";
    +		if (r->eqn != NULL)
    +			aft_pr = "\\&";
    +	}
    +
    +	/* Do the actual replacement. */
    +
    +	buf->sz = mandoc_asprintf(&cp1, "%s%s%s%s%s%s%s", buf->buf,
    +	    bef_pr, bef_nl, mac, aft_nl, aft_pr, cp2) + 1;
    +	free(buf->buf);
    +	buf->buf = cp1;
    +
    +	/* Toggle the in-line state of the eqn subsystem. */
    +
    +	r->eqn_inline = r->eqn == NULL;
    +	return ROFF_REPARSE;
    +}
    +
    +static enum rofferr
    +roff_EQ(ROFF_ARGS)
    +{
    +	struct roff_node	*n;
    +
    +	if (r->man->macroset == MACROSET_MAN)
    +		man_breakscope(r->man, ROFF_EQ);
    +	n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE);
    +	if (ln > r->man->last->line)
    +		n->flags |= NODE_LINE;
    +	n->eqn = mandoc_calloc(1, sizeof(*n->eqn));
    +	n->eqn->expectargs = UINT_MAX;
    +	roff_node_append(r->man, n);
    +	r->man->next = ROFF_NEXT_SIBLING;
    +
    +	assert(r->eqn == NULL);
    +	if (r->last_eqn == NULL)
    +		r->last_eqn = eqn_alloc(r->parse);
    +	else
    +		eqn_reset(r->last_eqn);
    +	r->eqn = r->last_eqn;
    +	r->eqn->node = n;
    +
    +	if (buf->buf[pos] != '\0')
    +		mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
    +		    ".EQ %s", buf->buf + pos);
    +
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_EN(ROFF_ARGS)
    +{
    +	if (r->eqn != NULL) {
    +		eqn_parse(r->eqn);
    +		r->eqn = NULL;
    +	} else
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN");
    +	if (buf->buf[pos] != '\0')
    +		mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
    +		    "EN %s", buf->buf + pos);
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_TS(ROFF_ARGS)
    +{
    +	if (r->tbl != NULL) {
    +		mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse,
    +		    ln, ppos, "TS breaks TS");
    +		tbl_end(r->tbl);
    +	}
    +	r->tbl = tbl_alloc(ppos, ln, r->parse);
    +	if (r->last_tbl)
    +		r->last_tbl->next = r->tbl;
    +	else
    +		r->first_tbl = r->tbl;
    +	r->last_tbl = r->tbl;
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_onearg(ROFF_ARGS)
    +{
    +	struct roff_node	*n;
    +	char			*cp;
    +	int			 npos;
    +
    +	if (r->man->flags & (MAN_BLINE | MAN_ELINE) &&
    +	    (tok == ROFF_ce || tok == ROFF_rj || tok == ROFF_sp ||
    +	     tok == ROFF_ti))
    +		man_breakscope(r->man, tok);
    +
    +	if (roffce_node != NULL && (tok == ROFF_ce || tok == ROFF_rj)) {
    +		r->man->last = roffce_node;
    +		r->man->next = ROFF_NEXT_SIBLING;
    +	}
    +
    +	roff_elem_alloc(r->man, ln, ppos, tok);
    +	n = r->man->last;
    +
    +	cp = buf->buf + pos;
    +	if (*cp != '\0') {
    +		while (*cp != '\0' && *cp != ' ')
    +			cp++;
    +		while (*cp == ' ')
    +			*cp++ = '\0';
    +		if (*cp != '\0')
    +			mandoc_vmsg(MANDOCERR_ARG_EXCESS,
    +			    r->parse, ln, cp - buf->buf,
    +			    "%s ... %s", roff_name[tok], cp);
    +		roff_word_alloc(r->man, ln, pos, buf->buf + pos);
    +	}
    +
    +	if (tok == ROFF_ce || tok == ROFF_rj) {
    +		if (r->man->last->type == ROFFT_ELEM) {
    +			roff_word_alloc(r->man, ln, pos, "1");
    +			r->man->last->flags |= NODE_NOSRC;
    +		}
    +		npos = 0;
    +		if (roff_evalnum(r, ln, r->man->last->string, &npos,
    +		    &roffce_lines, 0) == 0) {
    +			mandoc_vmsg(MANDOCERR_CE_NONUM,
    +			    r->parse, ln, pos, "ce %s", buf->buf + pos);
    +			roffce_lines = 1;
    +		}
    +		if (roffce_lines < 1) {
    +			r->man->last = r->man->last->parent;
    +			roffce_node = NULL;
    +			roffce_lines = 0;
    +		} else
    +			roffce_node = r->man->last->parent;
    +	} else {
    +		n->flags |= NODE_VALID | NODE_ENDED;
    +		r->man->last = n;
    +	}
    +	n->flags |= NODE_LINE;
    +	r->man->next = ROFF_NEXT_SIBLING;
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_manyarg(ROFF_ARGS)
    +{
    +	struct roff_node	*n;
    +	char			*sp, *ep;
    +
    +	roff_elem_alloc(r->man, ln, ppos, tok);
    +	n = r->man->last;
    +
    +	for (sp = ep = buf->buf + pos; *sp != '\0'; sp = ep) {
    +		while (*ep != '\0' && *ep != ' ')
    +			ep++;
    +		while (*ep == ' ')
    +			*ep++ = '\0';
    +		roff_word_alloc(r->man, ln, sp - buf->buf, sp);
    +	}
    +
    +	n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
    +	r->man->last = n;
    +	r->man->next = ROFF_NEXT_SIBLING;
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_als(ROFF_ARGS)
    +{
    +	char		*oldn, *newn, *end, *value;
    +	size_t		 oldsz, newsz, valsz;
    +
    +	newn = oldn = buf->buf + pos;
    +	if (*newn == '\0')
    +		return ROFF_IGN;
    +
    +	newsz = roff_getname(r, &oldn, ln, pos);
    +	if (newn[newsz] == '\\' || *oldn == '\0')
    +		return ROFF_IGN;
    +
    +	end = oldn;
    +	oldsz = roff_getname(r, &end, ln, oldn - buf->buf);
    +	if (oldsz == 0)
    +		return ROFF_IGN;
    +
    +	valsz = mandoc_asprintf(&value, ".%.*s \\$*\\\"\n",
    +	    (int)oldsz, oldn);
    +	roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0);
    +	roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
    +	free(value);
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_br(ROFF_ARGS)
    +{
    +	if (r->man->flags & (MAN_BLINE | MAN_ELINE))
    +		man_breakscope(r->man, ROFF_br);
    +	roff_elem_alloc(r->man, ln, ppos, ROFF_br);
    +	if (buf->buf[pos] != '\0')
    +		mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
    +		    "%s %s", roff_name[tok], buf->buf + pos);
    +	r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
    +	r->man->next = ROFF_NEXT_SIBLING;
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_cc(ROFF_ARGS)
    +{
    +	const char	*p;
    +
    +	p = buf->buf + pos;
    +
    +	if (*p == '\0' || (r->control = *p++) == '.')
    +		r->control = '\0';
    +
    +	if (*p != '\0')
    +		mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
    +		    ln, p - buf->buf, "cc ... %s", p);
    +
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_ec(ROFF_ARGS)
    +{
    +	const char	*p;
    +
    +	p = buf->buf + pos;
    +	if (*p == '\0')
    +		r->escape = '\\';
    +	else {
    +		r->escape = *p;
    +		if (*++p != '\0')
    +			mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
    +			    ln, p - buf->buf, "ec ... %s", p);
    +	}
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_eo(ROFF_ARGS)
    +{
    +	r->escape = '\0';
    +	if (buf->buf[pos] != '\0')
    +		mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse,
    +		    ln, pos, "eo %s", buf->buf + pos);
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_tr(ROFF_ARGS)
    +{
    +	const char	*p, *first, *second;
    +	size_t		 fsz, ssz;
    +	enum mandoc_esc	 esc;
    +
    +	p = buf->buf + pos;
    +
    +	if (*p == '\0') {
    +		mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, ln, ppos, "tr");
    +		return ROFF_IGN;
    +	}
    +
    +	while (*p != '\0') {
    +		fsz = ssz = 1;
    +
    +		first = p++;
    +		if (*first == '\\') {
    +			esc = mandoc_escape(&p, NULL, NULL);
    +			if (esc == ESCAPE_ERROR) {
    +				mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
    +				    ln, (int)(p - buf->buf), first);
    +				return ROFF_IGN;
    +			}
    +			fsz = (size_t)(p - first);
    +		}
    +
    +		second = p++;
    +		if (*second == '\\') {
    +			esc = mandoc_escape(&p, NULL, NULL);
    +			if (esc == ESCAPE_ERROR) {
    +				mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
    +				    ln, (int)(p - buf->buf), second);
    +				return ROFF_IGN;
    +			}
    +			ssz = (size_t)(p - second);
    +		} else if (*second == '\0') {
    +			mandoc_vmsg(MANDOCERR_TR_ODD, r->parse,
    +			    ln, first - buf->buf, "tr %s", first);
    +			second = " ";
    +			p--;
    +		}
    +
    +		if (fsz > 1) {
    +			roff_setstrn(&r->xmbtab, first, fsz,
    +			    second, ssz, 0);
    +			continue;
    +		}
    +
    +		if (r->xtab == NULL)
    +			r->xtab = mandoc_calloc(128,
    +			    sizeof(struct roffstr));
    +
    +		free(r->xtab[(int)*first].p);
    +		r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
    +		r->xtab[(int)*first].sz = ssz;
    +	}
    +
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_rn(ROFF_ARGS)
    +{
    +	const char	*value;
    +	char		*oldn, *newn, *end;
    +	size_t		 oldsz, newsz;
    +	int		 deftype;
    +
    +	oldn = newn = buf->buf + pos;
    +	if (*oldn == '\0')
    +		return ROFF_IGN;
    +
    +	oldsz = roff_getname(r, &newn, ln, pos);
    +	if (oldn[oldsz] == '\\' || *newn == '\0')
    +		return ROFF_IGN;
    +
    +	end = newn;
    +	newsz = roff_getname(r, &end, ln, newn - buf->buf);
    +	if (newsz == 0)
    +		return ROFF_IGN;
    +
    +	deftype = ROFFDEF_ANY;
    +	value = roff_getstrn(r, oldn, oldsz, &deftype);
    +	switch (deftype) {
    +	case ROFFDEF_USER:
    +		roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0);
    +		roff_setstrn(&r->strtab, oldn, oldsz, NULL, 0, 0);
    +		roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
    +		break;
    +	case ROFFDEF_PRE:
    +		roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0);
    +		roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
    +		break;
    +	case ROFFDEF_REN:
    +		roff_setstrn(&r->rentab, newn, newsz, value, strlen(value), 0);
    +		roff_setstrn(&r->rentab, oldn, oldsz, NULL, 0, 0);
    +		roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
    +		break;
    +	case ROFFDEF_STD:
    +		roff_setstrn(&r->rentab, newn, newsz, oldn, oldsz, 0);
    +		roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
    +		break;
    +	default:
    +		roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
    +		roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
    +		break;
    +	}
    +	return ROFF_IGN;
    +}
    +
    +static enum rofferr
    +roff_so(ROFF_ARGS)
    +{
    +	char *name, *cp;
    +
    +	name = buf->buf + pos;
    +	mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name);
    +
    +	/*
    +	 * Handle `so'.  Be EXTREMELY careful, as we shouldn't be
    +	 * opening anything that's not in our cwd or anything beneath
    +	 * it.  Thus, explicitly disallow traversing up the file-system
    +	 * or using absolute paths.
    +	 */
    +
    +	if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) {
    +		mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos,
    +		    ".so %s", name);
    +		buf->sz = mandoc_asprintf(&cp,
    +		    ".sp\nSee the file %s.\n.sp", name) + 1;
    +		free(buf->buf);
    +		buf->buf = cp;
    +		*offs = 0;
    +		return ROFF_REPARSE;
    +	}
    +
    +	*offs = pos;
    +	return ROFF_SO;
    +}
    +
    +/* --- user defined strings and macros ------------------------------------ */
    +
    +static enum rofferr
    +roff_userdef(ROFF_ARGS)
    +{
    +	const char	 *arg[16], *ap;
    +	char		 *cp, *n1, *n2;
    +	int		  expand_count, i, ib, ie;
    +	size_t		  asz, rsz;
    +
    +	/*
    +	 * Collect pointers to macro argument strings
    +	 * and NUL-terminate them.
    +	 */
    +
    +	r->argc = 0;
    +	cp = buf->buf + pos;
    +	for (i = 0; i < 16; i++) {
    +		if (*cp == '\0')
    +			arg[i] = "";
    +		else {
    +			arg[i] = mandoc_getarg(r->parse, &cp, ln, &pos);
    +			r->argc = i + 1;
    +		}
    +	}
    +
    +	/*
    +	 * Expand macro arguments.
    +	 */
    +
    +	buf->sz = strlen(r->current_string) + 1;
    +	n1 = n2 = cp = mandoc_malloc(buf->sz);
    +	memcpy(n1, r->current_string, buf->sz);
    +	expand_count = 0;
    +	while (*cp != '\0') {
    +
    +		/* Scan ahead for the next argument invocation. */
    +
    +		if (*cp++ != '\\')
    +			continue;
    +		if (*cp++ != '$')
    +			continue;
    +		if (*cp == '*') {  /* \\$* inserts all arguments */
    +			ib = 0;
    +			ie = r->argc - 1;
    +		} else {  /* \\$1 .. \\$9 insert one argument */
    +			ib = ie = *cp - '1';
    +			if (ib < 0 || ib > 8)
    +				continue;
    +		}
    +		cp -= 2;
    +
    +		/*
    +		 * Prevent infinite recursion.
    +		 */
    +
    +		if (cp >= n2)
    +			expand_count = 1;
    +		else if (++expand_count > EXPAND_LIMIT) {
    +			mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
    +			    ln, (int)(cp - n1), NULL);
    +			free(buf->buf);
    +			buf->buf = n1;
    +			*offs = 0;
    +			return ROFF_IGN;
    +		}
    +
    +		/*
    +		 * Determine the size of the expanded argument,
    +		 * taking escaping of quotes into account.
    +		 */
    +
    +		asz = ie > ib ? ie - ib : 0;  /* for blanks */
    +		for (i = ib; i <= ie; i++) {
    +			for (ap = arg[i]; *ap != '\0'; ap++) {
    +				asz++;
    +				if (*ap == '"')
    +					asz += 3;
    +			}
    +		}
    +		if (asz != 3) {
    +
    +			/*
    +			 * Determine the size of the rest of the
    +			 * unexpanded macro, including the NUL.
    +			 */
    +
    +			rsz = buf->sz - (cp - n1) - 3;
    +
    +			/*
    +			 * When shrinking, move before
    +			 * releasing the storage.
    +			 */
    +
    +			if (asz < 3)
    +				memmove(cp + asz, cp + 3, rsz);
    +
    +			/*
    +			 * Resize the storage for the macro
    +			 * and readjust the parse pointer.
    +			 */
    +
    +			buf->sz += asz - 3;
    +			n2 = mandoc_realloc(n1, buf->sz);
    +			cp = n2 + (cp - n1);
    +			n1 = n2;
    +
    +			/*
    +			 * When growing, make room
    +			 * for the expanded argument.
    +			 */
    +
    +			if (asz > 3)
    +				memmove(cp + asz, cp + 3, rsz);
    +		}
    +
    +		/* Copy the expanded argument, escaping quotes. */
    +
    +		n2 = cp;
    +		for (i = ib; i <= ie; i++) {
    +			for (ap = arg[i]; *ap != '\0'; ap++) {
    +				if (*ap == '"') {
    +					memcpy(n2, "\\(dq", 4);
    +					n2 += 4;
    +				} else
    +					*n2++ = *ap;
    +			}
    +			if (i < ie)
    +				*n2++ = ' ';
    +		}
    +	}
    +
    +	/*
    +	 * Replace the macro invocation
    +	 * by the expanded macro.
    +	 */
    +
    +	free(buf->buf);
    +	buf->buf = n1;
    +	*offs = 0;
    +
    +	return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?
    +	   ROFF_REPARSE : ROFF_APPEND;
    +}
    +
    +/*
    + * Calling a high-level macro that was renamed with .rn.
    + * r->current_string has already been set up by roff_parse().
    + */
    +static enum rofferr
    +roff_renamed(ROFF_ARGS)
    +{
    +	char	*nbuf;
    +
    +	buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string,
    +	    buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1;
    +	free(buf->buf);
    +	buf->buf = nbuf;
    +	*offs = 0;
    +	return ROFF_CONT;
    +}
    +
    +static size_t
    +roff_getname(struct roff *r, char **cpp, int ln, int pos)
    +{
    +	char	 *name, *cp;
    +	size_t	  namesz;
    +
    +	name = *cpp;
    +	if ('\0' == *name)
    +		return 0;
    +
    +	/* Read until end of name and terminate it with NUL. */
    +	for (cp = name; 1; cp++) {
    +		if ('\0' == *cp || ' ' == *cp) {
    +			namesz = cp - name;
    +			break;
    +		}
    +		if ('\\' != *cp)
    +			continue;
    +		namesz = cp - name;
    +		if ('{' == cp[1] || '}' == cp[1])
    +			break;
    +		cp++;
    +		if ('\\' == *cp)
    +			continue;
    +		mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos,
    +		    "%.*s", (int)(cp - name + 1), name);
    +		mandoc_escape((const char **)&cp, NULL, NULL);
    +		break;
    +	}
    +
    +	/* Read past spaces. */
    +	while (' ' == *cp)
    +		cp++;
    +
    +	*cpp = cp;
    +	return namesz;
    +}
    +
    +/*
    + * Store *string into the user-defined string called *name.
    + * To clear an existing entry, call with (*r, *name, NULL, 0).
    + * append == 0: replace mode
    + * append == 1: single-line append mode
    + * append == 2: multiline append mode, append '\n' after each call
    + */
    +static void
    +roff_setstr(struct roff *r, const char *name, const char *string,
    +	int append)
    +{
    +	size_t	 namesz;
    +
    +	namesz = strlen(name);
    +	roff_setstrn(&r->strtab, name, namesz, string,
    +	    string ? strlen(string) : 0, append);
    +	roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
    +}
    +
    +static void
    +roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
    +		const char *string, size_t stringsz, int append)
    +{
    +	struct roffkv	*n;
    +	char		*c;
    +	int		 i;
    +	size_t		 oldch, newch;
    +
    +	/* Search for an existing string with the same name. */
    +	n = *r;
    +
    +	while (n && (namesz != n->key.sz ||
    +			strncmp(n->key.p, name, namesz)))
    +		n = n->next;
    +
    +	if (NULL == n) {
    +		/* Create a new string table entry. */
    +		n = mandoc_malloc(sizeof(struct roffkv));
    +		n->key.p = mandoc_strndup(name, namesz);
    +		n->key.sz = namesz;
    +		n->val.p = NULL;
    +		n->val.sz = 0;
    +		n->next = *r;
    +		*r = n;
    +	} else if (0 == append) {
    +		free(n->val.p);
    +		n->val.p = NULL;
    +		n->val.sz = 0;
    +	}
    +
    +	if (NULL == string)
    +		return;
    +
    +	/*
    +	 * One additional byte for the '\n' in multiline mode,
    +	 * and one for the terminating '\0'.
    +	 */
    +	newch = stringsz + (1 < append ? 2u : 1u);
    +
    +	if (NULL == n->val.p) {
    +		n->val.p = mandoc_malloc(newch);
    +		*n->val.p = '\0';
    +		oldch = 0;
    +	} else {
    +		oldch = n->val.sz;
    +		n->val.p = mandoc_realloc(n->val.p, oldch + newch);
    +	}
    +
    +	/* Skip existing content in the destination buffer. */
    +	c = n->val.p + (int)oldch;
    +
    +	/* Append new content to the destination buffer. */
    +	i = 0;
    +	while (i < (int)stringsz) {
    +		/*
    +		 * Rudimentary roff copy mode:
    +		 * Handle escaped backslashes.
    +		 */
    +		if ('\\' == string[i] && '\\' == string[i + 1])
    +			i++;
    +		*c++ = string[i++];
    +	}
    +
    +	/* Append terminating bytes. */
    +	if (1 < append)
    +		*c++ = '\n';
    +
    +	*c = '\0';
    +	n->val.sz = (int)(c - n->val.p);
    +}
    +
    +static const char *
    +roff_getstrn(struct roff *r, const char *name, size_t len,
    +    int *deftype)
    +{
    +	const struct roffkv	*n;
    +	int			 found, i;
    +	enum roff_tok		 tok;
    +
    +	found = 0;
    +	for (n = r->strtab; n != NULL; n = n->next) {
    +		if (strncmp(name, n->key.p, len) != 0 ||
    +		    n->key.p[len] != '\0' || n->val.p == NULL)
    +			continue;
    +		if (*deftype & ROFFDEF_USER) {
    +			*deftype = ROFFDEF_USER;
    +			return n->val.p;
    +		} else {
    +			found = 1;
    +			break;
    +		}
    +	}
    +	for (n = r->rentab; n != NULL; n = n->next) {
    +		if (strncmp(name, n->key.p, len) != 0 ||
    +		    n->key.p[len] != '\0' || n->val.p == NULL)
    +			continue;
    +		if (*deftype & ROFFDEF_REN) {
    +			*deftype = ROFFDEF_REN;
    +			return n->val.p;
    +		} else {
    +			found = 1;
    +			break;
    +		}
    +	}
    +	for (i = 0; i < PREDEFS_MAX; i++) {
    +		if (strncmp(name, predefs[i].name, len) != 0 ||
    +		    predefs[i].name[len] != '\0')
    +			continue;
    +		if (*deftype & ROFFDEF_PRE) {
    +			*deftype = ROFFDEF_PRE;
    +			return predefs[i].str;
    +		} else {
    +			found = 1;
    +			break;
    +		}
    +	}
    +	if (r->man->macroset != MACROSET_MAN) {
    +		for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
    +			if (strncmp(name, roff_name[tok], len) != 0 ||
    +			    roff_name[tok][len] != '\0')
    +				continue;
    +			if (*deftype & ROFFDEF_STD) {
    +				*deftype = ROFFDEF_STD;
    +				return NULL;
    +			} else {
    +				found = 1;
    +				break;
    +			}
    +		}
    +	}
    +	if (r->man->macroset != MACROSET_MDOC) {
    +		for (tok = MAN_TH; tok < MAN_MAX; tok++) {
    +			if (strncmp(name, roff_name[tok], len) != 0 ||
    +			    roff_name[tok][len] != '\0')
    +				continue;
    +			if (*deftype & ROFFDEF_STD) {
    +				*deftype = ROFFDEF_STD;
    +				return NULL;
    +			} else {
    +				found = 1;
    +				break;
    +			}
    +		}
    +	}
    +
    +	if (found == 0 && *deftype != ROFFDEF_ANY) {
    +		if (*deftype & ROFFDEF_REN) {
    +			/*
    +			 * This might still be a request,
    +			 * so do not treat it as undefined yet.
    +			 */
    +			*deftype = ROFFDEF_UNDEF;
    +			return NULL;
    +		}
    +
    +		/* Using an undefined string defines it to be empty. */
    +
    +		roff_setstrn(&r->strtab, name, len, "", 0, 0);
    +		roff_setstrn(&r->rentab, name, len, NULL, 0, 0);
    +	}
    +
    +	*deftype = 0;
    +	return NULL;
    +}
    +
    +static void
    +roff_freestr(struct roffkv *r)
    +{
    +	struct roffkv	 *n, *nn;
    +
    +	for (n = r; n; n = nn) {
    +		free(n->key.p);
    +		free(n->val.p);
    +		nn = n->next;
    +		free(n);
    +	}
    +}
    +
    +/* --- accessors and utility functions ------------------------------------ */
    +
    +/*
    + * Duplicate an input string, making the appropriate character
    + * conversations (as stipulated by `tr') along the way.
    + * Returns a heap-allocated string with all the replacements made.
    + */
    +char *
    +roff_strdup(const struct roff *r, const char *p)
    +{
    +	const struct roffkv *cp;
    +	char		*res;
    +	const char	*pp;
    +	size_t		 ssz, sz;
    +	enum mandoc_esc	 esc;
    +
    +	if (NULL == r->xmbtab && NULL == r->xtab)
    +		return mandoc_strdup(p);
    +	else if ('\0' == *p)
    +		return mandoc_strdup("");
    +
    +	/*
    +	 * Step through each character looking for term matches
    +	 * (remember that a `tr' can be invoked with an escape, which is
    +	 * a glyph but the escape is multi-character).
    +	 * We only do this if the character hash has been initialised
    +	 * and the string is >0 length.
    +	 */
    +
    +	res = NULL;
    +	ssz = 0;
    +
    +	while ('\0' != *p) {
    +		assert((unsigned int)*p < 128);
    +		if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) {
    +			sz = r->xtab[(int)*p].sz;
    +			res = mandoc_realloc(res, ssz + sz + 1);
    +			memcpy(res + ssz, r->xtab[(int)*p].p, sz);
    +			ssz += sz;
    +			p++;
    +			continue;
    +		} else if ('\\' != *p) {
    +			res = mandoc_realloc(res, ssz + 2);
    +			res[ssz++] = *p++;
    +			continue;
    +		}
    +
    +		/* Search for term matches. */
    +		for (cp = r->xmbtab; cp; cp = cp->next)
    +			if (0 == strncmp(p, cp->key.p, cp->key.sz))
    +				break;
    +
    +		if (NULL != cp) {
    +			/*
    +			 * A match has been found.
    +			 * Append the match to the array and move
    +			 * forward by its keysize.
    +			 */
    +			res = mandoc_realloc(res,
    +			    ssz + cp->val.sz + 1);
    +			memcpy(res + ssz, cp->val.p, cp->val.sz);
    +			ssz += cp->val.sz;
    +			p += (int)cp->key.sz;
    +			continue;
    +		}
    +
    +		/*
    +		 * Handle escapes carefully: we need to copy
    +		 * over just the escape itself, or else we might
    +		 * do replacements within the escape itself.
    +		 * Make sure to pass along the bogus string.
    +		 */
    +		pp = p++;
    +		esc = mandoc_escape(&p, NULL, NULL);
    +		if (ESCAPE_ERROR == esc) {
    +			sz = strlen(pp);
    +			res = mandoc_realloc(res, ssz + sz + 1);
    +			memcpy(res + ssz, pp, sz);
    +			break;
    +		}
    +		/*
    +		 * We bail out on bad escapes.
    +		 * No need to warn: we already did so when
    +		 * roff_res() was called.
    +		 */
    +		sz = (int)(p - pp);
    +		res = mandoc_realloc(res, ssz + sz + 1);
    +		memcpy(res + ssz, pp, sz);
    +		ssz += sz;
    +	}
    +
    +	res[(int)ssz] = '\0';
    +	return res;
    +}
    +
    +int
    +roff_getformat(const struct roff *r)
    +{
    +
    +	return r->format;
    +}
    +
    +/*
    + * Find out whether a line is a macro line or not.
    + * If it is, adjust the current position and return one; if it isn't,
    + * return zero and don't change the current position.
    + * If the control character has been set with `.cc', then let that grain
    + * precedence.
    + * This is slighly contrary to groff, where using the non-breaking
    + * control character when `cc' has been invoked will cause the
    + * non-breaking macro contents to be printed verbatim.
    + */
    +int
    +roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
    +{
    +	int		pos;
    +
    +	pos = *ppos;
    +
    +	if (r->control != '\0' && cp[pos] == r->control)
    +		pos++;
    +	else if (r->control != '\0')
    +		return 0;
    +	else if ('\\' == cp[pos] && '.' == cp[pos + 1])
    +		pos += 2;
    +	else if ('.' == cp[pos] || '\'' == cp[pos])
    +		pos++;
    +	else
    +		return 0;
    +
    +	while (' ' == cp[pos] || '\t' == cp[pos])
    +		pos++;
    +
    +	*ppos = pos;
    +	return 1;
    +}
    
    Property changes on: head/contrib/mandoc/roff.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/roff.h
    ===================================================================
    --- head/contrib/mandoc/roff.h	(nonexistent)
    +++ head/contrib/mandoc/roff.h	(revision 338826)
    @@ -0,0 +1,580 @@
    +/*	$Id: roff.h,v 1.59 2018/04/11 17:11:13 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +struct	ohash;
    +struct	mdoc_arg;
    +union	mdoc_data;
    +
    +enum	roff_macroset {
    +	MACROSET_NONE = 0,
    +	MACROSET_MDOC,
    +	MACROSET_MAN
    +};
    +
    +enum	roff_sec {
    +	SEC_NONE = 0,
    +	SEC_NAME,
    +	SEC_LIBRARY,
    +	SEC_SYNOPSIS,
    +	SEC_DESCRIPTION,
    +	SEC_CONTEXT,
    +	SEC_IMPLEMENTATION,	/* IMPLEMENTATION NOTES */
    +	SEC_RETURN_VALUES,
    +	SEC_ENVIRONMENT,
    +	SEC_FILES,
    +	SEC_EXIT_STATUS,
    +	SEC_EXAMPLES,
    +	SEC_DIAGNOSTICS,
    +	SEC_COMPATIBILITY,
    +	SEC_ERRORS,
    +	SEC_SEE_ALSO,
    +	SEC_STANDARDS,
    +	SEC_HISTORY,
    +	SEC_AUTHORS,
    +	SEC_CAVEATS,
    +	SEC_BUGS,
    +	SEC_SECURITY,
    +	SEC_CUSTOM,
    +	SEC__MAX
    +};
    +
    +enum	roff_type {
    +	ROFFT_ROOT,
    +	ROFFT_BLOCK,
    +	ROFFT_HEAD,
    +	ROFFT_BODY,
    +	ROFFT_TAIL,
    +	ROFFT_ELEM,
    +	ROFFT_TEXT,
    +	ROFFT_COMMENT,
    +	ROFFT_TBL,
    +	ROFFT_EQN
    +};
    +
    +enum	roff_tok {
    +	ROFF_br = 0,
    +	ROFF_ce,
    +	ROFF_ft,
    +	ROFF_ll,
    +	ROFF_mc,
    +	ROFF_po,
    +	ROFF_rj,
    +	ROFF_sp,
    +	ROFF_ta,
    +	ROFF_ti,
    +	ROFF_MAX,
    +	ROFF_ab,
    +	ROFF_ad,
    +	ROFF_af,
    +	ROFF_aln,
    +	ROFF_als,
    +	ROFF_am,
    +	ROFF_am1,
    +	ROFF_ami,
    +	ROFF_ami1,
    +	ROFF_as,
    +	ROFF_as1,
    +	ROFF_asciify,
    +	ROFF_backtrace,
    +	ROFF_bd,
    +	ROFF_bleedat,
    +	ROFF_blm,
    +	ROFF_box,
    +	ROFF_boxa,
    +	ROFF_bp,
    +	ROFF_BP,
    +	ROFF_break,
    +	ROFF_breakchar,
    +	ROFF_brnl,
    +	ROFF_brp,
    +	ROFF_brpnl,
    +	ROFF_c2,
    +	ROFF_cc,
    +	ROFF_cf,
    +	ROFF_cflags,
    +	ROFF_ch,
    +	ROFF_char,
    +	ROFF_chop,
    +	ROFF_class,
    +	ROFF_close,
    +	ROFF_CL,
    +	ROFF_color,
    +	ROFF_composite,
    +	ROFF_continue,
    +	ROFF_cp,
    +	ROFF_cropat,
    +	ROFF_cs,
    +	ROFF_cu,
    +	ROFF_da,
    +	ROFF_dch,
    +	ROFF_Dd,
    +	ROFF_de,
    +	ROFF_de1,
    +	ROFF_defcolor,
    +	ROFF_dei,
    +	ROFF_dei1,
    +	ROFF_device,
    +	ROFF_devicem,
    +	ROFF_di,
    +	ROFF_do,
    +	ROFF_ds,
    +	ROFF_ds1,
    +	ROFF_dwh,
    +	ROFF_dt,
    +	ROFF_ec,
    +	ROFF_ecr,
    +	ROFF_ecs,
    +	ROFF_el,
    +	ROFF_em,
    +	ROFF_EN,
    +	ROFF_eo,
    +	ROFF_EP,
    +	ROFF_EQ,
    +	ROFF_errprint,
    +	ROFF_ev,
    +	ROFF_evc,
    +	ROFF_ex,
    +	ROFF_fallback,
    +	ROFF_fam,
    +	ROFF_fc,
    +	ROFF_fchar,
    +	ROFF_fcolor,
    +	ROFF_fdeferlig,
    +	ROFF_feature,
    +	/* MAN_fi; ignored in mdoc(7) */
    +	ROFF_fkern,
    +	ROFF_fl,
    +	ROFF_flig,
    +	ROFF_fp,
    +	ROFF_fps,
    +	ROFF_fschar,
    +	ROFF_fspacewidth,
    +	ROFF_fspecial,
    +	ROFF_ftr,
    +	ROFF_fzoom,
    +	ROFF_gcolor,
    +	ROFF_hc,
    +	ROFF_hcode,
    +	ROFF_hidechar,
    +	ROFF_hla,
    +	ROFF_hlm,
    +	ROFF_hpf,
    +	ROFF_hpfa,
    +	ROFF_hpfcode,
    +	ROFF_hw,
    +	ROFF_hy,
    +	ROFF_hylang,
    +	ROFF_hylen,
    +	ROFF_hym,
    +	ROFF_hypp,
    +	ROFF_hys,
    +	ROFF_ie,
    +	ROFF_if,
    +	ROFF_ig,
    +	/* MAN_in; ignored in mdoc(7) */
    +	ROFF_index,
    +	ROFF_it,
    +	ROFF_itc,
    +	ROFF_IX,
    +	ROFF_kern,
    +	ROFF_kernafter,
    +	ROFF_kernbefore,
    +	ROFF_kernpair,
    +	ROFF_lc,
    +	ROFF_lc_ctype,
    +	ROFF_lds,
    +	ROFF_length,
    +	ROFF_letadj,
    +	ROFF_lf,
    +	ROFF_lg,
    +	ROFF_lhang,
    +	ROFF_linetabs,
    +	ROFF_lnr,
    +	ROFF_lnrf,
    +	ROFF_lpfx,
    +	ROFF_ls,
    +	ROFF_lsm,
    +	ROFF_lt,
    +	ROFF_mediasize,
    +	ROFF_minss,
    +	ROFF_mk,
    +	ROFF_mso,
    +	ROFF_na,
    +	ROFF_ne,
    +	/* MAN_nf; ignored in mdoc(7) */
    +	ROFF_nh,
    +	ROFF_nhychar,
    +	ROFF_nm,
    +	ROFF_nn,
    +	ROFF_nop,
    +	ROFF_nr,
    +	ROFF_nrf,
    +	ROFF_nroff,
    +	ROFF_ns,
    +	ROFF_nx,
    +	ROFF_open,
    +	ROFF_opena,
    +	ROFF_os,
    +	ROFF_output,
    +	ROFF_padj,
    +	ROFF_papersize,
    +	ROFF_pc,
    +	ROFF_pev,
    +	ROFF_pi,
    +	ROFF_PI,
    +	ROFF_pl,
    +	ROFF_pm,
    +	ROFF_pn,
    +	ROFF_pnr,
    +	ROFF_ps,
    +	ROFF_psbb,
    +	ROFF_pshape,
    +	ROFF_pso,
    +	ROFF_ptr,
    +	ROFF_pvs,
    +	ROFF_rchar,
    +	ROFF_rd,
    +	ROFF_recursionlimit,
    +	ROFF_return,
    +	ROFF_rfschar,
    +	ROFF_rhang,
    +	ROFF_rm,
    +	ROFF_rn,
    +	ROFF_rnn,
    +	ROFF_rr,
    +	ROFF_rs,
    +	ROFF_rt,
    +	ROFF_schar,
    +	ROFF_sentchar,
    +	ROFF_shc,
    +	ROFF_shift,
    +	ROFF_sizes,
    +	ROFF_so,
    +	ROFF_spacewidth,
    +	ROFF_special,
    +	ROFF_spreadwarn,
    +	ROFF_ss,
    +	ROFF_sty,
    +	ROFF_substring,
    +	ROFF_sv,
    +	ROFF_sy,
    +	ROFF_T_,
    +	ROFF_tc,
    +	ROFF_TE,
    +	ROFF_TH,
    +	ROFF_tkf,
    +	ROFF_tl,
    +	ROFF_tm,
    +	ROFF_tm1,
    +	ROFF_tmc,
    +	ROFF_tr,
    +	ROFF_track,
    +	ROFF_transchar,
    +	ROFF_trf,
    +	ROFF_trimat,
    +	ROFF_trin,
    +	ROFF_trnt,
    +	ROFF_troff,
    +	ROFF_TS,
    +	ROFF_uf,
    +	ROFF_ul,
    +	ROFF_unformat,
    +	ROFF_unwatch,
    +	ROFF_unwatchn,
    +	ROFF_vpt,
    +	ROFF_vs,
    +	ROFF_warn,
    +	ROFF_warnscale,
    +	ROFF_watch,
    +	ROFF_watchlength,
    +	ROFF_watchn,
    +	ROFF_wh,
    +	ROFF_while,
    +	ROFF_write,
    +	ROFF_writec,
    +	ROFF_writem,
    +	ROFF_xflag,
    +	ROFF_cblock,
    +	ROFF_RENAMED,
    +	ROFF_USERDEF,
    +	TOKEN_NONE,
    +	MDOC_Dd,
    +	MDOC_Dt,
    +	MDOC_Os,
    +	MDOC_Sh,
    +	MDOC_Ss,
    +	MDOC_Pp,
    +	MDOC_D1,
    +	MDOC_Dl,
    +	MDOC_Bd,
    +	MDOC_Ed,
    +	MDOC_Bl,
    +	MDOC_El,
    +	MDOC_It,
    +	MDOC_Ad,
    +	MDOC_An,
    +	MDOC_Ap,
    +	MDOC_Ar,
    +	MDOC_Cd,
    +	MDOC_Cm,
    +	MDOC_Dv,
    +	MDOC_Er,
    +	MDOC_Ev,
    +	MDOC_Ex,
    +	MDOC_Fa,
    +	MDOC_Fd,
    +	MDOC_Fl,
    +	MDOC_Fn,
    +	MDOC_Ft,
    +	MDOC_Ic,
    +	MDOC_In,
    +	MDOC_Li,
    +	MDOC_Nd,
    +	MDOC_Nm,
    +	MDOC_Op,
    +	MDOC_Ot,
    +	MDOC_Pa,
    +	MDOC_Rv,
    +	MDOC_St,
    +	MDOC_Va,
    +	MDOC_Vt,
    +	MDOC_Xr,
    +	MDOC__A,
    +	MDOC__B,
    +	MDOC__D,
    +	MDOC__I,
    +	MDOC__J,
    +	MDOC__N,
    +	MDOC__O,
    +	MDOC__P,
    +	MDOC__R,
    +	MDOC__T,
    +	MDOC__V,
    +	MDOC_Ac,
    +	MDOC_Ao,
    +	MDOC_Aq,
    +	MDOC_At,
    +	MDOC_Bc,
    +	MDOC_Bf,
    +	MDOC_Bo,
    +	MDOC_Bq,
    +	MDOC_Bsx,
    +	MDOC_Bx,
    +	MDOC_Db,
    +	MDOC_Dc,
    +	MDOC_Do,
    +	MDOC_Dq,
    +	MDOC_Ec,
    +	MDOC_Ef,
    +	MDOC_Em,
    +	MDOC_Eo,
    +	MDOC_Fx,
    +	MDOC_Ms,
    +	MDOC_No,
    +	MDOC_Ns,
    +	MDOC_Nx,
    +	MDOC_Ox,
    +	MDOC_Pc,
    +	MDOC_Pf,
    +	MDOC_Po,
    +	MDOC_Pq,
    +	MDOC_Qc,
    +	MDOC_Ql,
    +	MDOC_Qo,
    +	MDOC_Qq,
    +	MDOC_Re,
    +	MDOC_Rs,
    +	MDOC_Sc,
    +	MDOC_So,
    +	MDOC_Sq,
    +	MDOC_Sm,
    +	MDOC_Sx,
    +	MDOC_Sy,
    +	MDOC_Tn,
    +	MDOC_Ux,
    +	MDOC_Xc,
    +	MDOC_Xo,
    +	MDOC_Fo,
    +	MDOC_Fc,
    +	MDOC_Oo,
    +	MDOC_Oc,
    +	MDOC_Bk,
    +	MDOC_Ek,
    +	MDOC_Bt,
    +	MDOC_Hf,
    +	MDOC_Fr,
    +	MDOC_Ud,
    +	MDOC_Lb,
    +	MDOC_Lp,
    +	MDOC_Lk,
    +	MDOC_Mt,
    +	MDOC_Brq,
    +	MDOC_Bro,
    +	MDOC_Brc,
    +	MDOC__C,
    +	MDOC_Es,
    +	MDOC_En,
    +	MDOC_Dx,
    +	MDOC__Q,
    +	MDOC__U,
    +	MDOC_Ta,
    +	MDOC_MAX,
    +	MAN_TH,
    +	MAN_SH,
    +	MAN_SS,
    +	MAN_TP,
    +	MAN_LP,
    +	MAN_PP,
    +	MAN_P,
    +	MAN_IP,
    +	MAN_HP,
    +	MAN_SM,
    +	MAN_SB,
    +	MAN_BI,
    +	MAN_IB,
    +	MAN_BR,
    +	MAN_RB,
    +	MAN_R,
    +	MAN_B,
    +	MAN_I,
    +	MAN_IR,
    +	MAN_RI,
    +	MAN_nf,
    +	MAN_fi,
    +	MAN_RE,
    +	MAN_RS,
    +	MAN_DT,
    +	MAN_UC,
    +	MAN_PD,
    +	MAN_AT,
    +	MAN_in,
    +	MAN_OP,
    +	MAN_EX,
    +	MAN_EE,
    +	MAN_UR,
    +	MAN_UE,
    +	MAN_MT,
    +	MAN_ME,
    +	MAN_MAX
    +};
    +
    +enum	roff_next {
    +	ROFF_NEXT_SIBLING = 0,
    +	ROFF_NEXT_CHILD
    +};
    +
    +/*
    + * Indicates that a BODY's formatting has ended, but
    + * the scope is still open.  Used for badly nested blocks.
    + */
    +enum	mdoc_endbody {
    +	ENDBODY_NOT = 0,
    +	ENDBODY_SPACE	/* Is broken: append a space. */
    +};
    +
    +struct	roff_node {
    +	struct roff_node *parent;  /* Parent AST node. */
    +	struct roff_node *child;   /* First child AST node. */
    +	struct roff_node *last;    /* Last child AST node. */
    +	struct roff_node *next;    /* Sibling AST node. */
    +	struct roff_node *prev;    /* Prior sibling AST node. */
    +	struct roff_node *head;    /* BLOCK */
    +	struct roff_node *body;    /* BLOCK/ENDBODY */
    +	struct roff_node *tail;    /* BLOCK */
    +	struct mdoc_arg	 *args;    /* BLOCK/ELEM */
    +	union mdoc_data	 *norm;    /* Normalized arguments. */
    +	char		 *string;  /* TEXT */
    +	const struct tbl_span *span; /* TBL */
    +	struct eqn_box	 *eqn;     /* EQN */
    +	int		  line;    /* Input file line number. */
    +	int		  pos;     /* Input file column number. */
    +	int		  flags;
    +#define	NODE_VALID	 (1 << 0)  /* Has been validated. */
    +#define	NODE_ENDED	 (1 << 1)  /* Gone past body end mark. */
    +#define	NODE_EOS	 (1 << 2)  /* At sentence boundary. */
    +#define	NODE_LINE	 (1 << 3)  /* First macro/text on line. */
    +#define	NODE_SYNPRETTY	 (1 << 4)  /* SYNOPSIS-style formatting. */
    +#define	NODE_BROKEN	 (1 << 5)  /* Must validate parent when ending. */
    +#define	NODE_DELIMO	 (1 << 6)
    +#define	NODE_DELIMC	 (1 << 7)
    +#define	NODE_NOSRC	 (1 << 8)  /* Generated node, not in input file. */
    +#define	NODE_NOPRT	 (1 << 9)  /* Shall not print anything. */
    +	int		  prev_font; /* Before entering this node. */
    +	int		  aux;     /* Decoded node data, type-dependent. */
    +	enum roff_tok	  tok;     /* Request or macro ID. */
    +	enum roff_type	  type;    /* AST node type. */
    +	enum roff_sec	  sec;     /* Current named section. */
    +	enum mdoc_endbody end;     /* BODY */
    +};
    +
    +struct	roff_meta {
    +	char		 *msec;    /* Manual section, usually a digit. */
    +	char		 *vol;     /* Manual volume title. */
    +	char		 *os;      /* Operating system. */
    +	char		 *arch;    /* Machine architecture. */
    +	char		 *title;   /* Manual title, usually CAPS. */
    +	char		 *name;    /* Leading manual name. */
    +	char		 *date;    /* Normalized date. */
    +	int		  hasbody; /* Document is not empty. */
    +	int		  rcsids;  /* Bits indexed by enum mandoc_os. */
    +	enum mandoc_os	  os_e;    /* Operating system. */
    +};
    +
    +struct	roff_man {
    +	struct roff_meta  meta;    /* Document meta-data. */
    +	struct mparse	 *parse;   /* Parse pointer. */
    +	struct roff	 *roff;    /* Roff parser state data. */
    +	struct ohash	 *mdocmac; /* Mdoc macro lookup table. */
    +	struct ohash	 *manmac;  /* Man macro lookup table. */
    +	const char	 *os_s;    /* Default operating system. */
    +	struct roff_node *first;   /* The first node parsed. */
    +	struct roff_node *last;    /* The last node parsed. */
    +	struct roff_node *last_es; /* The most recent Es node. */
    +	int		  quick;   /* Abort parse early. */
    +	int		  flags;   /* Parse flags. */
    +#define	MDOC_LITERAL	 (1 << 1)  /* In a literal scope. */
    +#define	MDOC_PBODY	 (1 << 2)  /* In the document body. */
    +#define	MDOC_NEWLINE	 (1 << 3)  /* First macro/text in a line. */
    +#define	MDOC_PHRASE	 (1 << 4)  /* In a Bl -column phrase. */
    +#define	MDOC_PHRASELIT	 (1 << 5)  /* Literal within a phrase. */
    +#define	MDOC_FREECOL	 (1 << 6)  /* `It' invocation should close. */
    +#define	MDOC_SYNOPSIS	 (1 << 7)  /* SYNOPSIS-style formatting. */
    +#define	MDOC_KEEP	 (1 << 8)  /* In a word keep. */
    +#define	MDOC_SMOFF	 (1 << 9)  /* Spacing is off. */
    +#define	MDOC_NODELIMC	 (1 << 10) /* Disable closing delimiter handling. */
    +#define	MAN_ELINE	 (1 << 11) /* Next-line element scope. */
    +#define	MAN_BLINE	 (1 << 12) /* Next-line block scope. */
    +#define	MDOC_PHRASEQF	 (1 << 13) /* Quote first word encountered. */
    +#define	MDOC_PHRASEQL	 (1 << 14) /* Quote last word of this phrase. */
    +#define	MDOC_PHRASEQN	 (1 << 15) /* Quote first word of the next phrase. */
    +#define	MAN_LITERAL	  MDOC_LITERAL
    +#define	MAN_NEWLINE	  MDOC_NEWLINE
    +	enum roff_macroset macroset; /* Kind of high-level macros used. */
    +	enum roff_sec	  lastsec; /* Last section seen. */
    +	enum roff_sec	  lastnamed; /* Last standard section seen. */
    +	enum roff_next	  next;    /* Where to put the next node. */
    +};
    +
    +extern	const char *const *roff_name;
    +
    +
    +void		 deroff(char **, const struct roff_node *);
    +struct ohash	*roffhash_alloc(enum roff_tok, enum roff_tok);
    +enum roff_tok	 roffhash_find(struct ohash *, const char *, size_t);
    +void		 roffhash_free(struct ohash *);
    +void		 roff_validate(struct roff_man *);
    
    Property changes on: head/contrib/mandoc/roff.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/roff_html.c
    ===================================================================
    --- head/contrib/mandoc/roff_html.c	(nonexistent)
    +++ head/contrib/mandoc/roff_html.c	(revision 338826)
    @@ -0,0 +1,86 @@
    +/*	$Id: roff_html.c,v 1.12 2018/06/25 14:53:58 schwarze Exp $ */
    +/*
    + * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <stddef.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "out.h"
    +#include "html.h"
    +
    +#define	ROFF_HTML_ARGS struct html *h, const struct roff_node *n
    +
    +typedef	void	(*roff_html_pre_fp)(ROFF_HTML_ARGS);
    +
    +static	void	  roff_html_pre_br(ROFF_HTML_ARGS);
    +static	void	  roff_html_pre_ce(ROFF_HTML_ARGS);
    +static	void	  roff_html_pre_sp(ROFF_HTML_ARGS);
    +
    +static	const roff_html_pre_fp roff_html_pre_acts[ROFF_MAX] = {
    +	roff_html_pre_br,  /* br */
    +	roff_html_pre_ce,  /* ce */
    +	NULL,  /* ft */
    +	NULL,  /* ll */
    +	NULL,  /* mc */
    +	NULL,  /* po */
    +	roff_html_pre_ce,  /* rj */
    +	roff_html_pre_sp,  /* sp */
    +	NULL,  /* ta */
    +	NULL,  /* ti */
    +};
    +
    +
    +void
    +roff_html_pre(struct html *h, const struct roff_node *n)
    +{
    +	assert(n->tok < ROFF_MAX);
    +	if (roff_html_pre_acts[n->tok] != NULL)
    +		(*roff_html_pre_acts[n->tok])(h, n);
    +}
    +
    +static void
    +roff_html_pre_br(ROFF_HTML_ARGS)
    +{
    +	struct tag	*t;
    +
    +	t = print_otag(h, TAG_DIV, "");
    +	print_text(h, "\\~");  /* So the div isn't empty. */
    +	print_tagq(h, t);
    +}
    +
    +static void
    +roff_html_pre_ce(ROFF_HTML_ARGS)
    +{
    +	for (n = n->child->next; n != NULL; n = n->next) {
    +		if (n->type == ROFFT_TEXT) {
    +			if (n->flags & NODE_LINE)
    +				roff_html_pre_br(h, n);
    +			print_text(h, n->string);
    +		} else
    +			roff_html_pre(h, n);
    +	}
    +	roff_html_pre_br(h, n);
    +}
    +
    +static void
    +roff_html_pre_sp(ROFF_HTML_ARGS)
    +{
    +	print_paragraph(h);
    +}
    
    Property changes on: head/contrib/mandoc/roff_html.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/st.in
    ===================================================================
    --- head/contrib/mandoc/st.in	(nonexistent)
    +++ head/contrib/mandoc/st.in	(revision 338826)
    @@ -0,0 +1,78 @@
    +/*	$Id: st.in,v 1.30 2018/04/05 09:17:26 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +/*
    + * This file defines the .St macro arguments.  If you add a new
    + * standard, make sure that the left-and side corresponds to the .St
    + * argument (like .St -p1003.1) and the right-hand side corresponds to
    + * the formatted output string.
    + *
    + * Be sure to escape strings.
    + * The non-breaking blanks prevent ending an output line right before
    + * a number.  Groff prevent line breaks at the same places.
    + *
    + * REMEMBER TO ADD NEW STANDARDS TO MDOC.7!
    + */
    +
    +LINE("-p1003.1-88",	"IEEE Std 1003.1-1988 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1-90",	"IEEE Std 1003.1-1990 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1-96",	"ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1-2001",	"IEEE Std 1003.1-2001 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1-2004",	"IEEE Std 1003.1-2004 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1-2008",	"IEEE Std 1003.1-2008 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1-2013",	"IEEE Std 1003.1-2008, 2013 Edition (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1-2016",	"IEEE Std 1003.1-2008, 2016 Edition (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1",	"IEEE Std 1003.1 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-p1003.1b",	"IEEE Std 1003.1b (\\(LqPOSIX.1b\\(Rq)")
    +LINE("-p1003.1b-93",	"IEEE Std 1003.1b-1993 (\\(LqPOSIX.1b\\(Rq)")
    +LINE("-p1003.1c-95",	"IEEE Std 1003.1c-1995 (\\(LqPOSIX.1c\\(Rq)")
    +LINE("-p1003.1g-2000",	"IEEE Std 1003.1g-2000 (\\(LqPOSIX.1g\\(Rq)")
    +LINE("-p1003.1i-95",	"IEEE Std 1003.1i-1995 (\\(LqPOSIX.1i\\(Rq)")
    +LINE("-p1003.2",	"IEEE Std 1003.2 (\\(LqPOSIX.2\\(Rq)")
    +LINE("-p1003.2-92",	"IEEE Std 1003.2-1992 (\\(LqPOSIX.2\\(Rq)")
    +LINE("-p1003.2a-92",	"IEEE Std 1003.2a-1992 (\\(LqPOSIX.2\\(Rq)")
    +LINE("-isoC",		"ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
    +LINE("-isoC-90",	"ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
    +LINE("-isoC-amd1",	"ISO/IEC 9899/AMD1:1995 (\\(LqISO\\~C90, Amendment 1\\(Rq)")
    +LINE("-isoC-tcor1",	"ISO/IEC 9899/TCOR1:1994 (\\(LqISO\\~C90, Technical Corrigendum 1\\(Rq)")
    +LINE("-isoC-tcor2",	"ISO/IEC 9899/TCOR2:1995 (\\(LqISO\\~C90, Technical Corrigendum 2\\(Rq)")
    +LINE("-isoC-99",	"ISO/IEC 9899:1999 (\\(LqISO\\~C99\\(Rq)")
    +LINE("-isoC-2011",	"ISO/IEC 9899:2011 (\\(LqISO\\~C11\\(Rq)")
    +LINE("-iso9945-1-90",	"ISO/IEC 9945-1:1990 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-iso9945-1-96",	"ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
    +LINE("-iso9945-2-93",	"ISO/IEC 9945-2:1993 (\\(LqPOSIX.2\\(Rq)")
    +LINE("-ansiC",		"ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
    +LINE("-ansiC-89",	"ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
    +LINE("-ieee754",	"IEEE Std 754-1985")
    +LINE("-iso8802-3",	"ISO 8802-3: 1989")
    +LINE("-iso8601",	"ISO 8601")
    +LINE("-ieee1275-94",	"IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)")
    +LINE("-xpg3",		"X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)")
    +LINE("-xpg4",		"X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)")
    +LINE("-xpg4.2",		"X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)")
    +LINE("-xbd5",		"X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
    +LINE("-xcu5",		"X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
    +LINE("-xsh4.2",		"X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)")
    +LINE("-xsh5",		"X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
    +LINE("-xns5",		"X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
    +LINE("-xns5.2",		"X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
    +LINE("-xcurses4.2",	"X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
    +LINE("-susv1",		"Version\\~1 of the Single UNIX Specification (\\(lqSUSv1\\(rq)")
    +LINE("-susv2",		"Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
    +LINE("-susv3",		"Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
    +LINE("-susv4",		"Version\\~4 of the Single UNIX Specification (\\(lqSUSv4\\(rq)")
    +LINE("-svid4",		"System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")
    
    Property changes on: head/contrib/mandoc/st.in
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tag.c
    ===================================================================
    --- head/contrib/mandoc/tag.c	(nonexistent)
    +++ head/contrib/mandoc/tag.c	(revision 338826)
    @@ -0,0 +1,252 @@
    +/*	$Id: tag.c,v 1.19 2018/02/23 16:47:10 schwarze Exp $ */
    +/*
    + * Copyright (c) 2015, 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <signal.h>
    +#include <stddef.h>
    +#include <stdint.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc_ohash.h"
    +#include "tag.h"
    +
    +struct tag_entry {
    +	size_t	*lines;
    +	size_t	 maxlines;
    +	size_t	 nlines;
    +	int	 prio;
    +	char	 s[];
    +};
    +
    +static	void	 tag_signal(int) __attribute__((__noreturn__));
    +
    +static struct ohash	 tag_data;
    +static struct tag_files	 tag_files;
    +
    +
    +/*
    + * Prepare for using a pager.
    + * Not all pagers are capable of using a tag file,
    + * but for simplicity, create it anyway.
    + */
    +struct tag_files *
    +tag_init(void)
    +{
    +	struct sigaction	 sa;
    +	int			 ofd;
    +
    +	ofd = -1;
    +	tag_files.tfd = -1;
    +	tag_files.tcpgid = -1;
    +
    +	/* Clean up when dying from a signal. */
    +
    +	memset(&sa, 0, sizeof(sa));
    +	sigfillset(&sa.sa_mask);
    +	sa.sa_handler = tag_signal;
    +	sigaction(SIGHUP, &sa, NULL);
    +	sigaction(SIGINT, &sa, NULL);
    +	sigaction(SIGTERM, &sa, NULL);
    +
    +	/*
    +	 * POSIX requires that a process calling tcsetpgrp(3)
    +	 * from the background gets a SIGTTOU signal.
    +	 * In that case, do not stop.
    +	 */
    +
    +	sa.sa_handler = SIG_IGN;
    +	sigaction(SIGTTOU, &sa, NULL);
    +
    +	/* Save the original standard output for use by the pager. */
    +
    +	if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
    +		goto fail;
    +
    +	/* Create both temporary output files. */
    +
    +	(void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
    +	    sizeof(tag_files.ofn));
    +	(void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
    +	    sizeof(tag_files.tfn));
    +	if ((ofd = mkstemp(tag_files.ofn)) == -1)
    +		goto fail;
    +	if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
    +		goto fail;
    +	if (dup2(ofd, STDOUT_FILENO) == -1)
    +		goto fail;
    +	close(ofd);
    +
    +	/*
    +	 * Set up the ohash table to collect output line numbers
    +	 * where various marked-up terms are documented.
    +	 */
    +
    +	mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
    +	return &tag_files;
    +
    +fail:
    +	tag_unlink();
    +	if (ofd != -1)
    +		close(ofd);
    +	if (tag_files.ofd != -1)
    +		close(tag_files.ofd);
    +	if (tag_files.tfd != -1)
    +		close(tag_files.tfd);
    +	*tag_files.ofn = '\0';
    +	*tag_files.tfn = '\0';
    +	tag_files.ofd = -1;
    +	tag_files.tfd = -1;
    +	return NULL;
    +}
    +
    +/*
    + * Set the line number where a term is defined,
    + * unless it is already defined at a higher priority.
    + */
    +void
    +tag_put(const char *s, int prio, size_t line)
    +{
    +	struct tag_entry	*entry;
    +	size_t			 len;
    +	unsigned int		 slot;
    +
    +	/* Sanity checks. */
    +
    +	if (tag_files.tfd <= 0)
    +		return;
    +	if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e'))
    +		s += 2;
    +	if (*s == '\0' || strchr(s, ' ') != NULL)
    +		return;
    +
    +	slot = ohash_qlookup(&tag_data, s);
    +	entry = ohash_find(&tag_data, slot);
    +
    +	if (entry == NULL) {
    +
    +		/* Build a new entry. */
    +
    +		len = strlen(s) + 1;
    +		entry = mandoc_malloc(sizeof(*entry) + len);
    +		memcpy(entry->s, s, len);
    +		entry->lines = NULL;
    +		entry->maxlines = entry->nlines = 0;
    +		ohash_insert(&tag_data, slot, entry);
    +
    +	} else {
    +
    +		/* Handle priority 0 entries. */
    +
    +		if (prio == 0) {
    +			if (entry->prio == 0)
    +				entry->prio = -1;
    +			return;
    +		}
    +
    +		/* A better entry is already present, ignore the new one. */
    +
    +		if (entry->prio > 0 && entry->prio < prio)
    +			return;
    +
    +		/* The existing entry is worse, clear it. */
    +
    +		if (entry->prio < 1 || entry->prio > prio)
    +			entry->nlines = 0;
    +	}
    +
    +	/* Remember the new line. */
    +
    +	if (entry->maxlines == entry->nlines) {
    +		entry->maxlines += 4;
    +		entry->lines = mandoc_reallocarray(entry->lines,
    +		    entry->maxlines, sizeof(*entry->lines));
    +	}
    +	entry->lines[entry->nlines++] = line;
    +	entry->prio = prio;
    +}
    +
    +/*
    + * Write out the tags file using the previously collected
    + * information and clear the ohash table while going along.
    + */
    +void
    +tag_write(void)
    +{
    +	FILE			*stream;
    +	struct tag_entry	*entry;
    +	size_t			 i;
    +	unsigned int		 slot;
    +
    +	if (tag_files.tfd <= 0)
    +		return;
    +	stream = fdopen(tag_files.tfd, "w");
    +	entry = ohash_first(&tag_data, &slot);
    +	while (entry != NULL) {
    +		if (stream != NULL && entry->prio >= 0)
    +			for (i = 0; i < entry->nlines; i++)
    +				fprintf(stream, "%s %s %zu\n",
    +				    entry->s, tag_files.ofn, entry->lines[i]);
    +		free(entry->lines);
    +		free(entry);
    +		entry = ohash_next(&tag_data, &slot);
    +	}
    +	ohash_delete(&tag_data);
    +	if (stream != NULL)
    +		fclose(stream);
    +	else
    +		close(tag_files.tfd);
    +	tag_files.tfd = -1;
    +}
    +
    +void
    +tag_unlink(void)
    +{
    +	pid_t	 tc_pgid;
    +
    +	if (tag_files.tcpgid != -1) {
    +		tc_pgid = tcgetpgrp(tag_files.ofd);
    +		if (tc_pgid == tag_files.pager_pid ||
    +		    tc_pgid == getpgid(0) ||
    +		    getpgid(tc_pgid) == -1)
    +			(void)tcsetpgrp(tag_files.ofd, tag_files.tcpgid);
    +	}
    +	if (*tag_files.ofn != '\0')
    +		unlink(tag_files.ofn);
    +	if (*tag_files.tfn != '\0')
    +		unlink(tag_files.tfn);
    +}
    +
    +static void
    +tag_signal(int signum)
    +{
    +	struct sigaction	 sa;
    +
    +	tag_unlink();
    +	memset(&sa, 0, sizeof(sa));
    +	sigemptyset(&sa.sa_mask);
    +	sa.sa_handler = SIG_DFL;
    +	sigaction(signum, &sa, NULL);
    +	kill(getpid(), signum);
    +	/* NOTREACHED */
    +	_exit(1);
    +}
    
    Property changes on: head/contrib/mandoc/tag.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tbl.7
    ===================================================================
    --- head/contrib/mandoc/tbl.7	(nonexistent)
    +++ head/contrib/mandoc/tbl.7	(revision 338826)
    @@ -0,0 +1,434 @@
    +.\"	$Id: tbl.7,v 1.29 2017/10/17 23:19:12 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    +.\" Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" 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: October 17 2017 $
    +.Dt TBL 7
    +.Os
    +.Sh NAME
    +.Nm tbl
    +.Nd tbl language reference for mandoc
    +.Sh DESCRIPTION
    +The
    +.Nm tbl
    +language formats tables.
    +It is used within
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +pages.
    +This manual describes the subset of the
    +.Nm
    +language accepted by the
    +.Xr mandoc 1
    +utility.
    +.Pp
    +Each table is started with a
    +.Xr roff 7
    +.Ic \&TS
    +macro, consist of at most one line of
    +.Sx Options ,
    +one or more
    +.Sx Layout
    +lines, one or more
    +.Sx Data
    +lines, and ends with a
    +.Ic \&TE
    +macro.
    +All input must be 7-bit ASCII.
    +.Ss Options
    +If the first input line of a table ends with a semicolon, it contains
    +case-insensitive options separated by spaces, tabs, or commas.
    +Otherwise, it is interpreted as the first
    +.Sx Layout
    +line.
    +.Pp
    +The following options are available.
    +Some of them require arguments enclosed in parentheses:
    +.Bl -tag -width Ds
    +.It Cm allbox
    +Draw a single-line box around each table cell.
    +.It Cm box
    +Draw a single-line box around the table.
    +For GNU compatibility, this may also be invoked with
    +.Cm frame .
    +.It Cm center
    +Center the table instead of left-adjusting it.
    +For GNU compatibility, this may also be invoked with
    +.Cm centre .
    +.It Cm decimalpoint
    +Use the single-character argument as the decimal point with the
    +.Cm n
    +layout key.
    +This is a GNU extension.
    +.It Cm delim
    +Use the two characters of the argument as
    +.Xr eqn 7
    +delimiters.
    +Currently unsupported.
    +.It Cm doublebox
    +Draw a double-line box around the table.
    +For GNU compatibility, this may also be invoked with
    +.Cm doubleframe .
    +.It Cm expand
    +Increase the width of the table to the current line length.
    +Currently ignored.
    +.It Cm linesize
    +Draw lines with the point size given by the unsigned integer argument.
    +Currently ignored.
    +.It Cm nokeep
    +Allow page breaks within the table.
    +This is a GNU extension and currently ignored.
    +.It Cm nospaces
    +Ignore leading and trailing spaces in data cells.
    +This is a GNU extension and currently ignored.
    +.It Cm nowarn
    +Suppress warnings about tables exceeding the current line length.
    +This is a GNU extension and currently ignored.
    +.It Cm tab
    +Use the single-character argument as a delimiter between data cells.
    +By default, the horizontal tabulator character is used.
    +.El
    +.Ss Layout
    +The table layout follows an
    +.Sx Options
    +line or a
    +.Xr roff 7
    +.Ic \&TS
    +or
    +.Ic \&T&
    +macro.
    +Each layout line specifies how one line of
    +.Sx Data
    +is formatted.
    +The last layout line ends with a full stop.
    +It also applies to all remaining data lines.
    +Multiple layout lines can be joined by commas on a single physical
    +input line.
    +.Pp
    +Each layout line consists of one or more layout cell specifications,
    +optionally separated by whitespace.
    +The following case-insensitive key characters start a new cell
    +specification:
    +.Bl -tag -width 2n
    +.It Cm c
    +Center the string in this cell.
    +.It Cm r
    +Right-justify the string in this cell.
    +.It Cm l
    +Left-justify the string in this cell.
    +.It Cm n
    +Justify a number around its last decimal point.
    +If no decimal point is found in the number,
    +it is assumed to trail the number.
    +.It Cm s
    +Horizontally span columns from the last
    +.Pf non- Cm s
    +layout cell.
    +It is an error if a column span follows a
    +.Cm _
    +or
    +.Cm =
    +cell, or comes first on a layout line.
    +The combined cell as a whole consumes only one cell
    +of the corresponding data line.
    +.It Cm a
    +Left-justify a string and pad with one space.
    +.It Cm ^
    +Vertically span rows from the last
    +.Pf non- Cm ^
    +layout cell.
    +It is an error to invoke a vertical span on the first layout line.
    +Unlike a horizontal span, a vertical span consumes a data cell
    +and discards the content.
    +.It Cm _
    +Draw a single horizontal line in this cell.
    +This consumes a data cell and discards the content.
    +It may also be invoked with
    +.Cm \- .
    +.It Cm =
    +Draw a double horizontal line in this cell.
    +This consumes a data cell and discards the content.
    +.El
    +.Pp
    +Each cell key may be followed by zero or more of the following
    +case-insensitive modifiers:
    +.Bl -tag -width 2n
    +.It Cm b
    +Use a bold font for the contents of this cell.
    +.It Cm d
    +Move content down to the last row of this vertical span.
    +Currently ignored.
    +.It Cm e
    +Make this column wider to match the maximum width
    +of any other column also having the
    +.Cm e
    +modifier.
    +.It Cm f
    +The next character selects the font to use for this cell.
    +See the
    +.Xr roff 7
    +manual for supported one-character font names.
    +.It Cm i
    +Use an italic font for the contents of this cell.
    +.It Cm m
    +Specify a cell start macro.
    +This is a GNU extension and currently unsupported.
    +.It Cm p
    +Set the point size to the following unsigned argument,
    +or change it by the following signed argument.
    +Currently ignored.
    +.It Cm v
    +Set the vertical line spacing to the following unsigned argument,
    +or change it by the following signed argument.
    +Currently ignored.
    +.It Cm t
    +Do not vertically center content in this vertical span,
    +leave it in the top row.
    +Currently ignored.
    +.It Cm u
    +Move cell content up by half a table row.
    +Currently ignored.
    +.It Cm w
    +Specify a minimum column width.
    +.It Cm x
    +After determining the width of all other columns, distribute the
    +rest of the line length among all columns having the
    +.Cm x
    +modifier.
    +.It Cm z
    +Do not use this cell for determining the width of this column.
    +.It Cm \&|
    +Draw a single vertical line to the right of this cell.
    +.It Cm ||
    +Draw a double vertical line to the right of this cell.
    +.El
    +.Pp
    +If a modifier consists of decimal digits,
    +it specifies a minimum spacing in units of
    +.Cm n
    +between this column and the next column to the right.
    +The default is 3.
    +If there is a vertical line, it is drawn inside the spacing.
    +.Ss Data
    +The data section follows the last
    +.Sx Layout
    +line.
    +Each data line consists of one or more data cells, delimited by
    +.Cm tab
    +characters.
    +.Pp
    +If a data cells contains only the single character
    +.Ql _
    +or
    +.Ql = ,
    +a single or double horizontal line is drawn across the cell,
    +joining its neighbours.
    +If a data cells contains only the two character sequence
    +.Ql \e_
    +or
    +.Ql \e= ,
    +a single or double horizontal line is drawn inside the cell,
    +not joining its neighbours.
    +If a data line contains nothing but the single character
    +.Ql _
    +or
    +.Ql = ,
    +a horizontal line across the whole table is inserted
    +without consuming a layout row.
    +.Pp
    +In place of any data cell, a text block can be used.
    +It starts with
    +.Ic \&T{
    +at the end of a physical input line.
    +Input line breaks inside the text block
    +neither end the text block nor its data cell.
    +It only ends if
    +.Ic \&T}
    +occurs at the beginning of a physical input line and is followed
    +by an end-of-cell indicator.
    +If the
    +.Ic \&T}
    +is followed by the end of the physical input line, the text block,
    +the data cell, and the data line ends at this point.
    +If the
    +.Ic \&T}
    +is followed by the
    +.Cm tab
    +character, only the text block and the data cell end,
    +but the data line continues with the data cell following the
    +.Cm tab
    +character.
    +If
    +.Ic \&T}
    +is followed by any other character, it does not end the text block,
    +which instead continues to the following physical input line.
    +.Sh EXAMPLES
    +String justification and font selection:
    +.Bd -literal -offset indent
    +\&.TS
    +rb c  lb
    +r  ci l.
    +r	center	l
    +ri	ce	le
    +right	c	left
    +\&.TE
    +.Ed
    +.Bd -filled -offset indent
    +.TS
    +rb c  lb
    +r  ci l.
    +r	center	l
    +ri	ce	le
    +right	c	left
    +.TE
    +.Ed
    +.Pp
    +Some ports in
    +.Ox 6.1
    +to show number alignment and line drawing:
    +.Bd -literal -offset indent
    +\&.TS
    +box tab(:);
    +r| l
    +r  n.
    +software:version
    +_
    +AFL:2.39b
    +Mutt:1.8.0
    +Ruby:1.8.7.374
    +TeX Live:2015
    +\&.TE
    +.Ed
    +.Bd -filled -offset indent
    +.TS
    +box tab(:);
    +r| l
    +r  n.
    +software:version
    +_
    +AFL:2.39b
    +Mutt:1.8.0
    +Ruby:1.8.7.374
    +TeX Live:2015 
    +.TE
    +.Ed
    +.sp 2v
    +Spans and skipping width calculations:
    +.Bd -literal -offset indent
    +\&.TS
    +box tab(:);
    +lz  s | rt
    +lt| cb| ^
    +^ | rz  s.
    +left:r
    +l:center:
    +:right
    +\&.TE
    +.Ed
    +.Bd -filled -offset indent
    +.TS
    +box tab(:);
    +lz  s | rt
    +lt| cb| ^
    +^ | rz  s.
    +left:r
    +l:center:
    +:right
    +.TE
    +.Ed
    +.sp 2v
    +Text blocks, specifying spacings and specifying and equalizing
    +column widths, putting lines into individual cells, and overriding
    +.Cm allbox :
    +.Bd -literal -offset indent
    +\&.TS
    +allbox tab(:);
    +le le||7 lw10.
    +The fourth line:_:line 1
    +of this column:=:line 2
    +determines:\_:line 3
    +the column width.:T{
    +This text is too wide to fit into a column of width 17.
    +T}:line 4
    +T{
    +No break here.
    +T}::line 5
    +\&.TE
    +.Ed
    +.Bd -filled -offset indent
    +.TS
    +allbox tab(:);
    +le le||7 lw10.
    +The fourth line:_:line 1
    +of this column:=:line 2
    +determines:\_:line 3
    +the column width.:T{
    +This text is too wide to fit into a column of width 17.
    +T}:line 4
    +T{
    +No break here.
    +T}::line 5
    +.TE
    +.Ed
    +.sp 2v
    +These examples were constructed to demonstrate many
    +.Nm
    +features in a compact way.
    +In real manual pages, keep tables as simple as possible:
    +Like that, they usually look better, are less fragile, and more portable.
    +.Sh COMPATIBILITY
    +The
    +.Xr mandoc 1
    +implementation of
    +.Nm
    +doesn't support
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +macros and
    +.Xr eqn 7
    +equations inside tables.
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr man 7 ,
    +.Xr mandoc_char 7 ,
    +.Xr mdoc 7 ,
    +.Xr roff 7
    +.Rs
    +.%A M. E. Lesk
    +.%T Tbl\(emA Program to Format Tables
    +.%D June 11, 1976
    +.Re
    +.Sh HISTORY
    +The tbl utility, a preprocessor for troff, was originally written by M.
    +E. Lesk at Bell Labs in 1975.
    +The GNU reimplementation of tbl, part of the groff package, was released
    +in 1990 by James Clark.
    +A standalone tbl implementation was written by Kristaps Dzonsons in
    +2010.
    +This formed the basis of the implementation that first appeared in
    +.Ox 4.9
    +as a part of the
    +.Xr mandoc 1
    +utility.
    +.Sh AUTHORS
    +This
    +.Nm
    +reference was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +and
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
    
    Property changes on: head/contrib/mandoc/tbl.7
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tbl_html.c
    ===================================================================
    --- head/contrib/mandoc/tbl_html.c	(nonexistent)
    +++ head/contrib/mandoc/tbl_html.c	(revision 338826)
    @@ -0,0 +1,152 @@
    +/*	$Id: tbl_html.c,v 1.24 2018/06/25 13:45:57 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "out.h"
    +#include "html.h"
    +
    +static	void	 html_tblopen(struct html *, const struct tbl_span *);
    +static	size_t	 html_tbl_len(size_t, void *);
    +static	size_t	 html_tbl_strlen(const char *, void *);
    +static	size_t	 html_tbl_sulen(const struct roffsu *, void *);
    +
    +
    +static size_t
    +html_tbl_len(size_t sz, void *arg)
    +{
    +	return sz;
    +}
    +
    +static size_t
    +html_tbl_strlen(const char *p, void *arg)
    +{
    +	return strlen(p);
    +}
    +
    +static size_t
    +html_tbl_sulen(const struct roffsu *su, void *arg)
    +{
    +	if (su->scale < 0.0)
    +		return 0;
    +
    +	switch (su->unit) {
    +	case SCALE_FS:  /* 2^16 basic units */
    +		return su->scale * 65536.0 / 24.0;
    +	case SCALE_IN:  /* 10 characters per inch */
    +		return su->scale * 10.0;
    +	case SCALE_CM:  /* 2.54 cm per inch */
    +		return su->scale * 10.0 / 2.54;
    +	case SCALE_PC:  /* 6 pica per inch */
    +	case SCALE_VS:
    +		return su->scale * 10.0 / 6.0;
    +	case SCALE_EN:
    +	case SCALE_EM:
    +		return su->scale;
    +	case SCALE_PT:  /* 12 points per pica */
    +		return su->scale * 10.0 / 6.0 / 12.0;
    +	case SCALE_BU:  /* 24 basic units per character */
    +		return su->scale / 24.0;
    +	case SCALE_MM:  /* 1/1000 inch */
    +		return su->scale / 100.0;
    +	default:
    +		abort();
    +	}
    +}
    +
    +static void
    +html_tblopen(struct html *h, const struct tbl_span *sp)
    +{
    +	if (h->tbl.cols == NULL) {
    +		h->tbl.len = html_tbl_len;
    +		h->tbl.slen = html_tbl_strlen;
    +		h->tbl.sulen = html_tbl_sulen;
    +		tblcalc(&h->tbl, sp, 0, 0);
    +	}
    +	assert(NULL == h->tblt);
    +	h->tblt = print_otag(h, TAG_TABLE, "c", "tbl");
    +}
    +
    +void
    +print_tblclose(struct html *h)
    +{
    +
    +	assert(h->tblt);
    +	print_tagq(h, h->tblt);
    +	h->tblt = NULL;
    +}
    +
    +void
    +print_tbl(struct html *h, const struct tbl_span *sp)
    +{
    +	const struct tbl_dat *dp;
    +	struct tag	*tt;
    +	int		 ic;
    +
    +	/* Inhibit printing of spaces: we do padding ourselves. */
    +
    +	if (h->tblt == NULL)
    +		html_tblopen(h, sp);
    +
    +	assert(h->tblt);
    +
    +	h->flags |= HTML_NONOSPACE;
    +	h->flags |= HTML_NOSPACE;
    +
    +	tt = print_otag(h, TAG_TR, "");
    +
    +	switch (sp->pos) {
    +	case TBL_SPAN_HORIZ:
    +	case TBL_SPAN_DHORIZ:
    +		print_otag(h, TAG_TD, "?", "colspan", "0");
    +		break;
    +	default:
    +		dp = sp->first;
    +		for (ic = 0; ic < sp->opts->cols; ic++) {
    +			print_stagq(h, tt);
    +			print_otag(h, TAG_TD, "");
    +
    +			if (dp == NULL || dp->layout->col > ic)
    +				continue;
    +			if (dp->layout->pos != TBL_CELL_DOWN)
    +				if (dp->string != NULL)
    +					print_text(h, dp->string);
    +			dp = dp->next;
    +		}
    +		break;
    +	}
    +
    +	print_tagq(h, tt);
    +
    +	h->flags &= ~HTML_NONOSPACE;
    +
    +	if (sp->next == NULL) {
    +		assert(h->tbl.cols);
    +		free(h->tbl.cols);
    +		h->tbl.cols = NULL;
    +		print_tblclose(h);
    +	}
    +
    +}
    
    Property changes on: head/contrib/mandoc/tbl_html.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/term_ascii.c
    ===================================================================
    --- head/contrib/mandoc/term_ascii.c	(nonexistent)
    +++ head/contrib/mandoc/term_ascii.c	(revision 338826)
    @@ -0,0 +1,405 @@
    +/*	$Id: term_ascii.c,v 1.61 2018/05/20 21:37:34 schwarze Exp $ */
    +/*
    + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#if HAVE_WCHAR
    +#include <langinfo.h>
    +#include <locale.h>
    +#endif
    +#include <stdint.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +#if HAVE_WCHAR
    +#include <wchar.h>
    +#endif
    +
    +#include "mandoc.h"
    +#include "mandoc_aux.h"
    +#include "out.h"
    +#include "term.h"
    +#include "manconf.h"
    +#include "main.h"
    +
    +static	struct termp	 *ascii_init(enum termenc, const struct manoutput *);
    +static	int		  ascii_hspan(const struct termp *,
    +				const struct roffsu *);
    +static	size_t		  ascii_width(const struct termp *, int);
    +static	void		  ascii_advance(struct termp *, size_t);
    +static	void		  ascii_begin(struct termp *);
    +static	void		  ascii_end(struct termp *);
    +static	void		  ascii_endline(struct termp *);
    +static	void		  ascii_letter(struct termp *, int);
    +static	void		  ascii_setwidth(struct termp *, int, int);
    +
    +#if HAVE_WCHAR
    +static	void		  locale_advance(struct termp *, size_t);
    +static	void		  locale_endline(struct termp *);
    +static	void		  locale_letter(struct termp *, int);
    +static	size_t		  locale_width(const struct termp *, int);
    +#endif
    +
    +
    +static struct termp *
    +ascii_init(enum termenc enc, const struct manoutput *outopts)
    +{
    +#if HAVE_WCHAR
    +	char		*v;
    +#endif
    +	struct termp	*p;
    +
    +	p = mandoc_calloc(1, sizeof(*p));
    +	p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
    +	p->maxtcol = 1;
    +
    +	p->line = 1;
    +	p->defrmargin = p->lastrmargin = 78;
    +	p->fontq = mandoc_reallocarray(NULL,
    +	     (p->fontsz = 8), sizeof(*p->fontq));
    +	p->fontq[0] = p->fontl = TERMFONT_NONE;
    +
    +	p->begin = ascii_begin;
    +	p->end = ascii_end;
    +	p->hspan = ascii_hspan;
    +	p->type = TERMTYPE_CHAR;
    +
    +	p->enc = TERMENC_ASCII;
    +	p->advance = ascii_advance;
    +	p->endline = ascii_endline;
    +	p->letter = ascii_letter;
    +	p->setwidth = ascii_setwidth;
    +	p->width = ascii_width;
    +
    +#if HAVE_WCHAR
    +	if (TERMENC_ASCII != enc) {
    +
    +		/*
    +		 * Do not change any of this to LC_ALL.  It might break
    +		 * the formatting by subtly changing the behaviour of
    +		 * various functions, for example strftime(3).  As a
    +		 * worst case, it might even cause buffer overflows.
    +		 */
    +
    +		v = TERMENC_LOCALE == enc ?
    +		    setlocale(LC_CTYPE, "") :
    +		    setlocale(LC_CTYPE, UTF8_LOCALE);
    +
    +		/*
    +		 * We only support UTF-8,
    +		 * so revert to ASCII for anything else.
    +		 */
    +
    +		if (v != NULL &&
    +		    strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
    +			v = setlocale(LC_CTYPE, "C");
    +
    +		if (v != NULL && MB_CUR_MAX > 1) {
    +			p->enc = enc;
    +			p->advance = locale_advance;
    +			p->endline = locale_endline;
    +			p->letter = locale_letter;
    +			p->width = locale_width;
    +		}
    +	}
    +#endif
    +
    +	if (outopts->mdoc) {
    +		p->mdocstyle = 1;
    +		p->defindent = 5;
    +	}
    +	if (outopts->indent)
    +		p->defindent = outopts->indent;
    +	if (outopts->width)
    +		p->defrmargin = outopts->width;
    +	if (outopts->synopsisonly)
    +		p->synopsisonly = 1;
    +
    +	assert(p->defindent < UINT16_MAX);
    +	assert(p->defrmargin < UINT16_MAX);
    +	return p;
    +}
    +
    +void *
    +ascii_alloc(const struct manoutput *outopts)
    +{
    +
    +	return ascii_init(TERMENC_ASCII, outopts);
    +}
    +
    +void *
    +utf8_alloc(const struct manoutput *outopts)
    +{
    +
    +	return ascii_init(TERMENC_UTF8, outopts);
    +}
    +
    +void *
    +locale_alloc(const struct manoutput *outopts)
    +{
    +
    +	return ascii_init(TERMENC_LOCALE, outopts);
    +}
    +
    +static void
    +ascii_setwidth(struct termp *p, int iop, int width)
    +{
    +
    +	width /= 24;
    +	p->tcol->rmargin = p->defrmargin;
    +	if (iop > 0)
    +		p->defrmargin += width;
    +	else if (iop == 0)
    +		p->defrmargin = width ? (size_t)width : p->lastrmargin;
    +	else if (p->defrmargin > (size_t)width)
    +		p->defrmargin -= width;
    +	else
    +		p->defrmargin = 0;
    +	if (p->defrmargin > 1000)
    +		p->defrmargin = 1000;
    +	p->lastrmargin = p->tcol->rmargin;
    +	p->tcol->rmargin = p->maxrmargin = p->defrmargin;
    +}
    +
    +void
    +terminal_sepline(void *arg)
    +{
    +	struct termp	*p;
    +	size_t		 i;
    +
    +	p = (struct termp *)arg;
    +	(*p->endline)(p);
    +	for (i = 0; i < p->defrmargin; i++)
    +		(*p->letter)(p, '-');
    +	(*p->endline)(p);
    +	(*p->endline)(p);
    +}
    +
    +static size_t
    +ascii_width(const struct termp *p, int c)
    +{
    +
    +	return 1;
    +}
    +
    +void
    +ascii_free(void *arg)
    +{
    +
    +	term_free((struct termp *)arg);
    +}
    +
    +static void
    +ascii_letter(struct termp *p, int c)
    +{
    +
    +	putchar(c);
    +}
    +
    +static void
    +ascii_begin(struct termp *p)
    +{
    +
    +	(*p->headf)(p, p->argf);
    +}
    +
    +static void
    +ascii_end(struct termp *p)
    +{
    +
    +	(*p->footf)(p, p->argf);
    +}
    +
    +static void
    +ascii_endline(struct termp *p)
    +{
    +
    +	p->line++;
    +	p->tcol->offset -= p->ti;
    +	p->ti = 0;
    +	putchar('\n');
    +}
    +
    +static void
    +ascii_advance(struct termp *p, size_t len)
    +{
    +	size_t		i;
    +
    +	assert(len < UINT16_MAX);
    +	for (i = 0; i < len; i++)
    +		putchar(' ');
    +}
    +
    +static int
    +ascii_hspan(const struct termp *p, const struct roffsu *su)
    +{
    +	double		 r;
    +
    +	switch (su->unit) {
    +	case SCALE_BU:
    +		r = su->scale;
    +		break;
    +	case SCALE_CM:
    +		r = su->scale * 240.0 / 2.54;
    +		break;
    +	case SCALE_FS:
    +		r = su->scale * 65536.0;
    +		break;
    +	case SCALE_IN:
    +		r = su->scale * 240.0;
    +		break;
    +	case SCALE_MM:
    +		r = su->scale * 0.24;
    +		break;
    +	case SCALE_VS:
    +	case SCALE_PC:
    +		r = su->scale * 40.0;
    +		break;
    +	case SCALE_PT:
    +		r = su->scale * 10.0 / 3.0;
    +		break;
    +	case SCALE_EN:
    +	case SCALE_EM:
    +		r = su->scale * 24.0;
    +		break;
    +	default:
    +		abort();
    +	}
    +	return r > 0.0 ? r + 0.01 : r - 0.01;
    +}
    +
    +const char *
    +ascii_uc2str(int uc)
    +{
    +	static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
    +	static const char *tab[] = {
    +	"<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
    +	"<BS>",	"\t",	"<LF>",	"<VT>",	"<FF>",	"<CR>",	"<SO>",	"<SI>",
    +	"<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>",
    +	"<CAN>","<EM>",	"<SUB>","<ESC>","<FS>",	"<GS>",	"<RS>",	"<US>",
    +	" ",	"!",	"\"",	"#",	"$",	"%",	"&",	"'",
    +	"(",	")",	"*",	"+",	",",	"-",	".",	"/",
    +	"0",	"1",	"2",	"3",	"4",	"5",	"6",	"7",
    +	"8",	"9",	":",	";",	"<",	"=",	">",	"?",
    +	"@",	"A",	"B",	"C",	"D",	"E",	"F",	"G",
    +	"H",	"I",	"J",	"K",	"L",	"M",	"N",	"O",
    +	"P",	"Q",	"R",	"S",	"T",	"U",	"V",	"W",
    +	"X",	"Y",	"Z",	"[",	"\\",	"]",	"^",	"_",
    +	"`",	"a",	"b",	"c",	"d",	"e",	"f",	"g",
    +	"h",	"i",	"j",	"k",	"l",	"m",	"n",	"o",
    +	"p",	"q",	"r",	"s",	"t",	"u",	"v",	"w",
    +	"x",	"y",	"z",	"{",	"|",	"}",	"~",	"<DEL>",
    +	"<80>",	"<81>",	"<82>",	"<83>",	"<84>",	"<85>",	"<86>",	"<87>",
    +	"<88>",	"<89>",	"<8A>",	"<8B>",	"<8C>",	"<8D>",	"<8E>",	"<8F>",
    +	"<90>",	"<91>",	"<92>",	"<93>",	"<94>",	"<95>",	"<96>",	"<97>",
    +	"<98>",	"<99>",	"<9A>",	"<9B>",	"<9C>",	"<9D>",	"<9E>",	"<9F>",
    +	nbrsp,	"!",	"/\bc",	"GBP",	"o\bx",	"=\bY",	"|",	"<section>",
    +	"\"",	"(C)",	"_\ba",	"<<",	"~",	"",	"(R)",	"-",
    +	"<degree>","+-","^2",	"^3",	"'","<micro>","<paragraph>",".",
    +	",",	"^1",	"_\bo",	">>",	"1/4",	"1/2",	"3/4",	"?",
    +	"`\bA",	"'\bA",	"^\bA",	"~\bA",	"\"\bA","o\bA",	"AE",	",\bC",
    +	"`\bE",	"'\bE",	"^\bE",	"\"\bE","`\bI",	"'\bI",	"^\bI",	"\"\bI",
    +	"Dh",	"~\bN",	"`\bO",	"'\bO",	"^\bO",	"~\bO",	"\"\bO","x",
    +	"/\bO",	"`\bU",	"'\bU",	"^\bU",	"\"\bU","'\bY",	"Th",	"ss",
    +	"`\ba",	"'\ba",	"^\ba",	"~\ba",	"\"\ba","o\ba",	"ae",	",\bc",
    +	"`\be",	"'\be",	"^\be",	"\"\be","`\bi",	"'\bi",	"^\bi",	"\"\bi",
    +	"dh",	"~\bn",	"`\bo",	"'\bo",	"^\bo",	"~\bo",	"\"\bo","/",
    +	"/\bo",	"`\bu",	"'\bu",	"^\bu",	"\"\bu","'\by",	"th",	"\"\by",
    +	"A",	"a",	"A",	"a",	"A",	"a",	"'\bC",	"'\bc",
    +	"^\bC",	"^\bc",	"C",	"c",	"C",	"c",	"D",	"d",
    +	"/\bD",	"/\bd",	"E",	"e",	"E",	"e",	"E",	"e",
    +	"E",	"e",	"E",	"e",	"^\bG",	"^\bg",	"G",	"g",
    +	"G",	"g",	",\bG",	",\bg",	"^\bH",	"^\bh",	"/\bH",	"/\bh",
    +	"~\bI",	"~\bi",	"I",	"i",	"I",	"i",	"I",	"i",
    +	"I",	"i",	"IJ",	"ij",	"^\bJ",	"^\bj",	",\bK",	",\bk",
    +	"q",	"'\bL",	"'\bl",	",\bL",	",\bl",	"L",	"l",	"L",
    +	"l",	"/\bL",	"/\bl",	"'\bN",	"'\bn",	",\bN",	",\bn",	"N",
    +	"n",	"'n",	"Ng",	"ng",	"O",	"o",	"O",	"o",
    +	"O",	"o",	"OE",	"oe",	"'\bR",	"'\br",	",\bR",	",\br",
    +	"R",	"r",	"'\bS",	"'\bs",	"^\bS",	"^\bs",	",\bS",	",\bs",
    +	"S",	"s",	",\bT",	",\bt",	"T",	"t",	"/\bT",	"/\bt",
    +	"~\bU",	"~\bu",	"U",	"u",	"U",	"u",	"U",	"u",
    +	"U",	"u",	"U",	"u",	"^\bW",	"^\bw",	"^\bY",	"^\by",
    +	"\"\bY","'\bZ",	"'\bz",	"Z",	"z",	"Z",	"z",	"s",
    +	"b",	"B",	"B",	"b",	"6",	"6",	"O",	"C",
    +	"c",	"D",	"D",	"D",	"d",	"d",	"3",	"@",
    +	"E",	"F",	",\bf",	"G",	"G",	"hv",	"I",	"/\bI",
    +	"K",	"k",	"/\bl",	"l",	"W",	"N",	"n",	"~\bO",
    +	"O",	"o",	"OI",	"oi",	"P",	"p",	"YR",	"2",
    +	"2",	"SH",	"sh",	"t",	"T",	"t",	"T",	"U",
    +	"u",	"Y",	"V",	"Y",	"y",	"/\bZ",	"/\bz",	"ZH",
    +	"ZH",	"zh",	"zh",	"/\b2",	"5",	"5",	"ts",	"w",
    +	"|",	"||",	"|=",	"!",	"DZ",	"Dz",	"dz",	"LJ",
    +	"Lj",	"lj",	"NJ",	"Nj",	"nj",	"A",	"a",	"I",
    +	"i",	"O",	"o",	"U",	"u",	"U",	"u",	"U",
    +	"u",	"U",	"u",	"U",	"u",	"@",	"A",	"a",
    +	"A",	"a",	"AE",	"ae",	"/\bG",	"/\bg",	"G",	"g",
    +	"K",	"k",	"O",	"o",	"O",	"o",	"ZH",	"zh",
    +	"j",	"DZ",	"Dz",	"dz",	"'\bG",	"'\bg",	"HV",	"W",
    +	"`\bN",	"`\bn",	"A",	"a",	"'\bAE","'\bae","O",	"o"};
    +
    +	assert(uc >= 0);
    +	if ((size_t)uc < sizeof(tab)/sizeof(tab[0]))
    +		return tab[uc];
    +	return mchars_uc2str(uc);
    +}
    +
    +#if HAVE_WCHAR
    +static size_t
    +locale_width(const struct termp *p, int c)
    +{
    +	int		rc;
    +
    +	if (c == ASCII_NBRSP)
    +		c = ' ';
    +	rc = wcwidth(c);
    +	if (rc < 0)
    +		rc = 0;
    +	return rc;
    +}
    +
    +static void
    +locale_advance(struct termp *p, size_t len)
    +{
    +	size_t		i;
    +
    +	assert(len < UINT16_MAX);
    +	for (i = 0; i < len; i++)
    +		putwchar(L' ');
    +}
    +
    +static void
    +locale_endline(struct termp *p)
    +{
    +
    +	p->line++;
    +	p->tcol->offset -= p->ti;
    +	p->ti = 0;
    +	putwchar(L'\n');
    +}
    +
    +static void
    +locale_letter(struct termp *p, int c)
    +{
    +
    +	putwchar(c);
    +}
    +#endif
    
    Property changes on: head/contrib/mandoc/term_ascii.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/term_ps.c
    ===================================================================
    --- head/contrib/mandoc/term_ps.c	(nonexistent)
    +++ head/contrib/mandoc/term_ps.c	(revision 338826)
    @@ -0,0 +1,1359 @@
    +/*	$Id: term_ps.c,v 1.91 2017/11/10 23:42:52 schwarze Exp $ */
    +/*
    + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2017 Marc Espie <espie@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <stdarg.h>
    +#include <stdint.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mandoc_aux.h"
    +#include "out.h"
    +#include "term.h"
    +#include "manconf.h"
    +#include "main.h"
    +
    +/* These work the buffer used by the header and footer. */
    +#define	PS_BUFSLOP	  128
    +
    +/* Convert PostScript point "x" to an AFM unit. */
    +#define	PNT2AFM(p, x) \
    +	(size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale))
    +
    +/* Convert an AFM unit "x" to a PostScript points */
    +#define	AFM2PNT(p, x) \
    +	((double)(x) / (1000.0 / (double)(p)->ps->scale))
    +
    +struct	glyph {
    +	unsigned short	  wx; /* WX in AFM */
    +};
    +
    +struct	font {
    +	const char	 *name; /* FontName in AFM */
    +#define	MAXCHAR		  95 /* total characters we can handle */
    +	struct glyph	  gly[MAXCHAR]; /* glyph metrics */
    +};
    +
    +struct	termp_ps {
    +	int		  flags;
    +#define	PS_INLINE	 (1 << 0)	/* we're in a word */
    +#define	PS_MARGINS	 (1 << 1)	/* we're in the margins */
    +#define	PS_NEWPAGE	 (1 << 2)	/* new page, no words yet */
    +#define	PS_BACKSP	 (1 << 3)	/* last character was backspace */
    +	size_t		  pscol;	/* visible column (AFM units) */
    +	size_t		  pscolnext;	/* used for overstrike */
    +	size_t		  psrow;	/* visible row (AFM units) */
    +	size_t		  lastrow;	/* psrow of the previous word */
    +	char		 *psmarg;	/* margin buf */
    +	size_t		  psmargsz;	/* margin buf size */
    +	size_t		  psmargcur;	/* cur index in margin buf */
    +	char		  last;		/* last non-backspace seen */
    +	enum termfont	  lastf;	/* last set font */
    +	enum termfont	  nextf;	/* building next font here */
    +	size_t		  scale;	/* font scaling factor */
    +	size_t		  pages;	/* number of pages shown */
    +	size_t		  lineheight;	/* line height (AFM units) */
    +	size_t		  top;		/* body top (AFM units) */
    +	size_t		  bottom;	/* body bottom (AFM units) */
    +	const char	 *medianame;	/* for DocumentMedia and PageSize */
    +	size_t		  height;	/* page height (AFM units */
    +	size_t		  width;	/* page width (AFM units) */
    +	size_t		  lastwidth;	/* page width before last ll */
    +	size_t		  left;		/* body left (AFM units) */
    +	size_t		  header;	/* header pos (AFM units) */
    +	size_t		  footer;	/* footer pos (AFM units) */
    +	size_t		  pdfbytes;	/* current output byte */
    +	size_t		  pdflastpg;	/* byte of last page mark */
    +	size_t		  pdfbody;	/* start of body object */
    +	size_t		 *pdfobjs;	/* table of object offsets */
    +	size_t		  pdfobjsz;	/* size of pdfobjs */
    +};
    +
    +static	int		  ps_hspan(const struct termp *,
    +				const struct roffsu *);
    +static	size_t		  ps_width(const struct termp *, int);
    +static	void		  ps_advance(struct termp *, size_t);
    +static	void		  ps_begin(struct termp *);
    +static	void		  ps_closepage(struct termp *);
    +static	void		  ps_end(struct termp *);
    +static	void		  ps_endline(struct termp *);
    +static	void		  ps_growbuf(struct termp *, size_t);
    +static	void		  ps_letter(struct termp *, int);
    +static	void		  ps_pclose(struct termp *);
    +static	void		  ps_plast(struct termp *);
    +static	void		  ps_pletter(struct termp *, int);
    +static	void		  ps_printf(struct termp *, const char *, ...)
    +				__attribute__((__format__ (__printf__, 2, 3)));
    +static	void		  ps_putchar(struct termp *, char);
    +static	void		  ps_setfont(struct termp *, enum termfont);
    +static	void		  ps_setwidth(struct termp *, int, int);
    +static	struct termp	 *pspdf_alloc(const struct manoutput *, enum termtype);
    +static	void		  pdf_obj(struct termp *, size_t);
    +
    +/*
    + * We define, for the time being, three fonts: bold, oblique/italic, and
    + * normal (roman).  The following table hard-codes the font metrics for
    + * ASCII, i.e., 32--127.
    + */
    +
    +static	const struct font fonts[TERMFONT__MAX] = {
    +	{ "Times-Roman", {
    +		{ 250 },
    +		{ 333 },
    +		{ 408 },
    +		{ 500 },
    +		{ 500 },
    +		{ 833 },
    +		{ 778 },
    +		{ 333 },
    +		{ 333 },
    +		{ 333 },
    +		{ 500 },
    +		{ 564 },
    +		{ 250 },
    +		{ 333 },
    +		{ 250 },
    +		{ 278 },
    +		{ 500 },
    +		{ 500 },
    +		{ 500 },
    +		{ 500 },
    +		{ 500 },
    +		{ 500 },
    +		{ 500 },
    +		{ 500 },
    +		{ 500 },
    +		{ 500 },
    +		{ 278 },
    +		{ 278 },
    +		{ 564 },
    +		{ 564 },
    +		{ 564 },
    +		{ 444 },
    +		{ 921 },
    +		{ 722 },
    +		{ 667 },
    +		{ 667 },
    +		{ 722 },
    +		{ 611 },
    +		{ 556 },
    +		{ 722 },
    +		{ 722 },
    +		{ 333 },
    +		{ 389 },
    +		{ 722 },
    +		{ 611 },
    +		{ 889 },
    +		{ 722 },
    +		{ 722 },
    +		{ 556 },
    +		{ 722 },
    +		{ 667 },
    +		{ 556 },
    +		{ 611 },
    +		{ 722 },
    +		{ 722 },
    +		{ 944 },
    +		{ 722 },
    +		{ 722 },
    +		{ 611 },
    +		{ 333 },
    +		{ 278 },
    +		{ 333 },
    +		{ 469 },
    +		{ 500 },
    +		{ 333 },
    +		{ 444 },
    +		{ 500 },
    +		{ 444 },
    +		{  500},
    +		{  444},
    +		{  333},
    +		{  500},
    +		{  500},
    +		{  278},
    +		{  278},
    +		{  500},
    +		{  278},
    +		{  778},
    +		{  500},
    +		{  500},
    +		{  500},
    +		{  500},
    +		{  333},
    +		{  389},
    +		{  278},
    +		{  500},
    +		{  500},
    +		{  722},
    +		{  500},
    +		{  500},
    +		{  444},
    +		{  480},
    +		{  200},
    +		{  480},
    +		{  541},
    +	} },
    +	{ "Times-Bold", {
    +		{ 250  },
    +		{ 333  },
    +		{ 555  },
    +		{ 500  },
    +		{ 500  },
    +		{ 1000 },
    +		{ 833  },
    +		{ 333  },
    +		{ 333  },
    +		{ 333  },
    +		{ 500  },
    +		{ 570  },
    +		{ 250  },
    +		{ 333  },
    +		{ 250  },
    +		{ 278  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 333  },
    +		{ 333  },
    +		{ 570  },
    +		{ 570  },
    +		{ 570  },
    +		{ 500  },
    +		{ 930  },
    +		{ 722  },
    +		{ 667  },
    +		{ 722  },
    +		{ 722  },
    +		{ 667  },
    +		{ 611  },
    +		{ 778  },
    +		{ 778  },
    +		{ 389  },
    +		{ 500  },
    +		{ 778  },
    +		{ 667  },
    +		{ 944  },
    +		{ 722  },
    +		{ 778  },
    +		{ 611  },
    +		{ 778  },
    +		{ 722  },
    +		{ 556  },
    +		{ 667  },
    +		{ 722  },
    +		{ 722  },
    +		{ 1000 },
    +		{ 722  },
    +		{ 722  },
    +		{ 667  },
    +		{ 333  },
    +		{ 278  },
    +		{ 333  },
    +		{ 581  },
    +		{ 500  },
    +		{ 333  },
    +		{ 500  },
    +		{ 556  },
    +		{ 444  },
    +		{  556 },
    +		{  444 },
    +		{  333 },
    +		{  500 },
    +		{  556 },
    +		{  278 },
    +		{  333 },
    +		{  556 },
    +		{  278 },
    +		{  833 },
    +		{  556 },
    +		{  500 },
    +		{  556 },
    +		{  556 },
    +		{  444 },
    +		{  389 },
    +		{  333 },
    +		{  556 },
    +		{  500 },
    +		{  722 },
    +		{  500 },
    +		{  500 },
    +		{  444 },
    +		{  394 },
    +		{  220 },
    +		{  394 },
    +		{  520 },
    +	} },
    +	{ "Times-Italic", {
    +		{ 250  },
    +		{ 333  },
    +		{ 420  },
    +		{ 500  },
    +		{ 500  },
    +		{ 833  },
    +		{ 778  },
    +		{ 333  },
    +		{ 333  },
    +		{ 333  },
    +		{ 500  },
    +		{ 675  },
    +		{ 250  },
    +		{ 333  },
    +		{ 250  },
    +		{ 278  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 500  },
    +		{ 333  },
    +		{ 333  },
    +		{ 675  },
    +		{ 675  },
    +		{ 675  },
    +		{ 500  },
    +		{ 920  },
    +		{ 611  },
    +		{ 611  },
    +		{ 667  },
    +		{ 722  },
    +		{ 611  },
    +		{ 611  },
    +		{ 722  },
    +		{ 722  },
    +		{ 333  },
    +		{ 444  },
    +		{ 667  },
    +		{ 556  },
    +		{ 833  },
    +		{ 667  },
    +		{ 722  },
    +		{ 611  },
    +		{ 722  },
    +		{ 611  },
    +		{ 500  },
    +		{ 556  },
    +		{ 722  },
    +		{ 611  },
    +		{ 833  },
    +		{ 611  },
    +		{ 556  },
    +		{ 556  },
    +		{ 389  },
    +		{ 278  },
    +		{ 389  },
    +		{ 422  },
    +		{ 500  },
    +		{ 333  },
    +		{ 500  },
    +		{ 500  },
    +		{ 444  },
    +		{  500 },
    +		{  444 },
    +		{  278 },
    +		{  500 },
    +		{  500 },
    +		{  278 },
    +		{  278 },
    +		{  444 },
    +		{  278 },
    +		{  722 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  389 },
    +		{  389 },
    +		{  278 },
    +		{  500 },
    +		{  444 },
    +		{  667 },
    +		{  444 },
    +		{  444 },
    +		{  389 },
    +		{  400 },
    +		{  275 },
    +		{  400 },
    +		{  541 },
    +	} },
    +	{ "Times-BoldItalic", {
    +		{  250 },
    +		{  389 },
    +		{  555 },
    +		{  500 },
    +		{  500 },
    +		{  833 },
    +		{  778 },
    +		{  333 },
    +		{  333 },
    +		{  333 },
    +		{  500 },
    +		{  570 },
    +		{  250 },
    +		{  333 },
    +		{  250 },
    +		{  278 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  333 },
    +		{  333 },
    +		{  570 },
    +		{  570 },
    +		{  570 },
    +		{  500 },
    +		{  832 },
    +		{  667 },
    +		{  667 },
    +		{  667 },
    +		{  722 },
    +		{  667 },
    +		{  667 },
    +		{  722 },
    +		{  778 },
    +		{  389 },
    +		{  500 },
    +		{  667 },
    +		{  611 },
    +		{  889 },
    +		{  722 },
    +		{  722 },
    +		{  611 },
    +		{  722 },
    +		{  667 },
    +		{  556 },
    +		{  611 },
    +		{  722 },
    +		{  667 },
    +		{  889 },
    +		{  667 },
    +		{  611 },
    +		{  611 },
    +		{  333 },
    +		{  278 },
    +		{  333 },
    +		{  570 },
    +		{  500 },
    +		{  333 },
    +		{  500 },
    +		{  500 },
    +		{  444 },
    +		{  500 },
    +		{  444 },
    +		{  333 },
    +		{  500 },
    +		{  556 },
    +		{  278 },
    +		{  278 },
    +		{  500 },
    +		{  278 },
    +		{  778 },
    +		{  556 },
    +		{  500 },
    +		{  500 },
    +		{  500 },
    +		{  389 },
    +		{  389 },
    +		{  278 },
    +		{  556 },
    +		{  444 },
    +		{  667 },
    +		{  500 },
    +		{  444 },
    +		{  389 },
    +		{  348 },
    +		{  220 },
    +		{  348 },
    +		{  570 },
    +	} },
    +};
    +
    +void *
    +pdf_alloc(const struct manoutput *outopts)
    +{
    +	return pspdf_alloc(outopts, TERMTYPE_PDF);
    +}
    +
    +void *
    +ps_alloc(const struct manoutput *outopts)
    +{
    +	return pspdf_alloc(outopts, TERMTYPE_PS);
    +}
    +
    +static struct termp *
    +pspdf_alloc(const struct manoutput *outopts, enum termtype type)
    +{
    +	struct termp	*p;
    +	unsigned int	 pagex, pagey;
    +	size_t		 marginx, marginy, lineheight;
    +	const char	*pp;
    +
    +	p = mandoc_calloc(1, sizeof(*p));
    +	p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
    +	p->maxtcol = 1;
    +	p->type = type;
    +
    +	p->enc = TERMENC_ASCII;
    +	p->fontq = mandoc_reallocarray(NULL,
    +	    (p->fontsz = 8), sizeof(*p->fontq));
    +	p->fontq[0] = p->fontl = TERMFONT_NONE;
    +	p->ps = mandoc_calloc(1, sizeof(*p->ps));
    +
    +	p->advance = ps_advance;
    +	p->begin = ps_begin;
    +	p->end = ps_end;
    +	p->endline = ps_endline;
    +	p->hspan = ps_hspan;
    +	p->letter = ps_letter;
    +	p->setwidth = ps_setwidth;
    +	p->width = ps_width;
    +
    +	/* Default to US letter (millimetres). */
    +
    +	p->ps->medianame = "Letter";
    +	pagex = 216;
    +	pagey = 279;
    +
    +	/*
    +	 * The ISO-269 paper sizes can be calculated automatically, but
    +	 * it would require bringing in -lm for pow() and I'd rather not
    +	 * do that.  So just do it the easy way for now.  Since this
    +	 * only happens once, I'm not terribly concerned.
    +	 */
    +
    +	pp = outopts->paper;
    +	if (pp != NULL && strcasecmp(pp, "letter") != 0) {
    +		if (strcasecmp(pp, "a3") == 0) {
    +			p->ps->medianame = "A3";
    +			pagex = 297;
    +			pagey = 420;
    +		} else if (strcasecmp(pp, "a4") == 0) {
    +			p->ps->medianame = "A4";
    +			pagex = 210;
    +			pagey = 297;
    +		} else if (strcasecmp(pp, "a5") == 0) {
    +			p->ps->medianame = "A5";
    +			pagex = 148;
    +			pagey = 210;
    +		} else if (strcasecmp(pp, "legal") == 0) {
    +			p->ps->medianame = "Legal";
    +			pagex = 216;
    +			pagey = 356;
    +		} else if (sscanf(pp, "%ux%u", &pagex, &pagey) == 2)
    +			p->ps->medianame = "CustomSize";
    +		else
    +			warnx("%s: Unknown paper", pp);
    +	}
    +
    +	/*
    +	 * This MUST be defined before any PNT2AFM or AFM2PNT
    +	 * calculations occur.
    +	 */
    +
    +	p->ps->scale = 11;
    +
    +	/* Remember millimetres -> AFM units. */
    +
    +	pagex = PNT2AFM(p, ((double)pagex * 72.0 / 25.4));
    +	pagey = PNT2AFM(p, ((double)pagey * 72.0 / 25.4));
    +
    +	/* Margins are 1/9 the page x and y. */
    +
    +	marginx = (size_t)((double)pagex / 9.0);
    +	marginy = (size_t)((double)pagey / 9.0);
    +
    +	/* Line-height is 1.4em. */
    +
    +	lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4));
    +
    +	p->ps->width = p->ps->lastwidth = (size_t)pagex;
    +	p->ps->height = (size_t)pagey;
    +	p->ps->header = pagey - (marginy / 2) - (lineheight / 2);
    +	p->ps->top = pagey - marginy;
    +	p->ps->footer = (marginy / 2) - (lineheight / 2);
    +	p->ps->bottom = marginy;
    +	p->ps->left = marginx;
    +	p->ps->lineheight = lineheight;
    +
    +	p->defrmargin = pagex - (marginx * 2);
    +	return p;
    +}
    +
    +static void
    +ps_setwidth(struct termp *p, int iop, int width)
    +{
    +	size_t	 lastwidth;
    +
    +	lastwidth = p->ps->width;
    +	if (iop > 0)
    +		p->ps->width += width;
    +	else if (iop == 0)
    +		p->ps->width = width ? (size_t)width : p->ps->lastwidth;
    +	else if (p->ps->width > (size_t)width)
    +		p->ps->width -= width;
    +	else
    +		p->ps->width = 0;
    +	p->ps->lastwidth = lastwidth;
    +}
    +
    +void
    +pspdf_free(void *arg)
    +{
    +	struct termp	*p;
    +
    +	p = (struct termp *)arg;
    +
    +	free(p->ps->psmarg);
    +	free(p->ps->pdfobjs);
    +
    +	free(p->ps);
    +	term_free(p);
    +}
    +
    +static void
    +ps_printf(struct termp *p, const char *fmt, ...)
    +{
    +	va_list		 ap;
    +	int		 pos, len;
    +
    +	va_start(ap, fmt);
    +
    +	/*
    +	 * If we're running in regular mode, then pipe directly into
    +	 * vprintf().  If we're processing margins, then push the data
    +	 * into our growable margin buffer.
    +	 */
    +
    +	if ( ! (PS_MARGINS & p->ps->flags)) {
    +		len = vprintf(fmt, ap);
    +		va_end(ap);
    +		p->ps->pdfbytes += len < 0 ? 0 : (size_t)len;
    +		return;
    +	}
    +
    +	/*
    +	 * XXX: I assume that the in-margin print won't exceed
    +	 * PS_BUFSLOP (128 bytes), which is reasonable but still an
    +	 * assumption that will cause pukeage if it's not the case.
    +	 */
    +
    +	ps_growbuf(p, PS_BUFSLOP);
    +
    +	pos = (int)p->ps->psmargcur;
    +	vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap);
    +
    +	va_end(ap);
    +
    +	p->ps->psmargcur = strlen(p->ps->psmarg);
    +}
    +
    +static void
    +ps_putchar(struct termp *p, char c)
    +{
    +	int		 pos;
    +
    +	/* See ps_printf(). */
    +
    +	if ( ! (PS_MARGINS & p->ps->flags)) {
    +		putchar(c);
    +		p->ps->pdfbytes++;
    +		return;
    +	}
    +
    +	ps_growbuf(p, 2);
    +
    +	pos = (int)p->ps->psmargcur++;
    +	p->ps->psmarg[pos++] = c;
    +	p->ps->psmarg[pos] = '\0';
    +}
    +
    +static void
    +pdf_obj(struct termp *p, size_t obj)
    +{
    +
    +	assert(obj > 0);
    +
    +	if ((obj - 1) >= p->ps->pdfobjsz) {
    +		p->ps->pdfobjsz = obj + 128;
    +		p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs,
    +		    p->ps->pdfobjsz, sizeof(size_t));
    +	}
    +
    +	p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes;
    +	ps_printf(p, "%zu 0 obj\n", obj);
    +}
    +
    +static void
    +ps_closepage(struct termp *p)
    +{
    +	int		 i;
    +	size_t		 len, base;
    +
    +	/*
    +	 * Close out a page that we've already flushed to output.  In
    +	 * PostScript, we simply note that the page must be shown.  In
    +	 * PDF, we must now create the Length, Resource, and Page node
    +	 * for the page contents.
    +	 */
    +
    +	assert(p->ps->psmarg && p->ps->psmarg[0]);
    +	ps_printf(p, "%s", p->ps->psmarg);
    +
    +	if (TERMTYPE_PS != p->type) {
    +		len = p->ps->pdfbytes - p->ps->pdflastpg;
    +		base = p->ps->pages * 4 + p->ps->pdfbody;
    +
    +		ps_printf(p, "endstream\nendobj\n");
    +
    +		/* Length of content. */
    +		pdf_obj(p, base + 1);
    +		ps_printf(p, "%zu\nendobj\n", len);
    +
    +		/* Resource for content. */
    +		pdf_obj(p, base + 2);
    +		ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n");
    +		ps_printf(p, "/Font <<\n");
    +		for (i = 0; i < (int)TERMFONT__MAX; i++)
    +			ps_printf(p, "/F%d %d 0 R\n", i, 3 + i);
    +		ps_printf(p, ">>\n>>\nendobj\n");
    +
    +		/* Page node. */
    +		pdf_obj(p, base + 3);
    +		ps_printf(p, "<<\n");
    +		ps_printf(p, "/Type /Page\n");
    +		ps_printf(p, "/Parent 2 0 R\n");
    +		ps_printf(p, "/Resources %zu 0 R\n", base + 2);
    +		ps_printf(p, "/Contents %zu 0 R\n", base);
    +		ps_printf(p, ">>\nendobj\n");
    +	} else
    +		ps_printf(p, "showpage\n");
    +
    +	p->ps->pages++;
    +	p->ps->psrow = p->ps->top;
    +	assert( ! (PS_NEWPAGE & p->ps->flags));
    +	p->ps->flags |= PS_NEWPAGE;
    +}
    +
    +static void
    +ps_end(struct termp *p)
    +{
    +	size_t		 i, xref, base;
    +
    +	ps_plast(p);
    +	ps_pclose(p);
    +
    +	/*
    +	 * At the end of the file, do one last showpage.  This is the
    +	 * same behaviour as groff(1) and works for multiple pages as
    +	 * well as just one.
    +	 */
    +
    +	if ( ! (PS_NEWPAGE & p->ps->flags)) {
    +		assert(0 == p->ps->flags);
    +		assert('\0' == p->ps->last);
    +		ps_closepage(p);
    +	}
    +
    +	if (TERMTYPE_PS == p->type) {
    +		ps_printf(p, "%%%%Trailer\n");
    +		ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages);
    +		ps_printf(p, "%%%%EOF\n");
    +		return;
    +	}
    +
    +	pdf_obj(p, 2);
    +	ps_printf(p, "<<\n/Type /Pages\n");
    +	ps_printf(p, "/MediaBox [0 0 %zu %zu]\n",
    +			(size_t)AFM2PNT(p, p->ps->width),
    +			(size_t)AFM2PNT(p, p->ps->height));
    +
    +	ps_printf(p, "/Count %zu\n", p->ps->pages);
    +	ps_printf(p, "/Kids [");
    +
    +	for (i = 0; i < p->ps->pages; i++)
    +		ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3);
    +
    +	base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4;
    +
    +	ps_printf(p, "]\n>>\nendobj\n");
    +	pdf_obj(p, base);
    +	ps_printf(p, "<<\n");
    +	ps_printf(p, "/Type /Catalog\n");
    +	ps_printf(p, "/Pages 2 0 R\n");
    +	ps_printf(p, ">>\nendobj\n");
    +	xref = p->ps->pdfbytes;
    +	ps_printf(p, "xref\n");
    +	ps_printf(p, "0 %zu\n", base + 1);
    +	ps_printf(p, "0000000000 65535 f \n");
    +
    +	for (i = 0; i < base; i++)
    +		ps_printf(p, "%.10zu 00000 n \n",
    +		    p->ps->pdfobjs[(int)i]);
    +
    +	ps_printf(p, "trailer\n");
    +	ps_printf(p, "<<\n");
    +	ps_printf(p, "/Size %zu\n", base + 1);
    +	ps_printf(p, "/Root %zu 0 R\n", base);
    +	ps_printf(p, "/Info 1 0 R\n");
    +	ps_printf(p, ">>\n");
    +	ps_printf(p, "startxref\n");
    +	ps_printf(p, "%zu\n", xref);
    +	ps_printf(p, "%%%%EOF\n");
    +}
    +
    +static void
    +ps_begin(struct termp *p)
    +{
    +	size_t		 width, height;
    +	int		 i;
    +
    +	/*
    +	 * Print margins into margin buffer.  Nothing gets output to the
    +	 * screen yet, so we don't need to initialise the primary state.
    +	 */
    +
    +	if (p->ps->psmarg) {
    +		assert(p->ps->psmargsz);
    +		p->ps->psmarg[0] = '\0';
    +	}
    +
    +	/*p->ps->pdfbytes = 0;*/
    +	p->ps->psmargcur = 0;
    +	p->ps->flags = PS_MARGINS;
    +	p->ps->pscol = p->ps->left;
    +	p->ps->psrow = p->ps->header;
    +	p->ps->lastrow = 0; /* impossible row */
    +
    +	ps_setfont(p, TERMFONT_NONE);
    +
    +	(*p->headf)(p, p->argf);
    +	(*p->endline)(p);
    +
    +	p->ps->pscol = p->ps->left;
    +	p->ps->psrow = p->ps->footer;
    +
    +	(*p->footf)(p, p->argf);
    +	(*p->endline)(p);
    +
    +	p->ps->flags &= ~PS_MARGINS;
    +
    +	assert(0 == p->ps->flags);
    +	assert(p->ps->psmarg);
    +	assert('\0' != p->ps->psmarg[0]);
    +
    +	/*
    +	 * Print header and initialise page state.  Following this,
    +	 * stuff gets printed to the screen, so make sure we're sane.
    +	 */
    +
    +	if (TERMTYPE_PS == p->type) {
    +		width = AFM2PNT(p, p->ps->width);
    +		height = AFM2PNT(p, p->ps->height);
    +
    +		ps_printf(p, "%%!PS-Adobe-3.0\n");
    +		ps_printf(p, "%%%%DocumentData: Clean7Bit\n");
    +		ps_printf(p, "%%%%Orientation: Portrait\n");
    +		ps_printf(p, "%%%%Pages: (atend)\n");
    +		ps_printf(p, "%%%%PageOrder: Ascend\n");
    +		ps_printf(p, "%%%%DocumentMedia: man-%s %zu %zu 0 () ()\n",
    +		    p->ps->medianame, width, height);
    +		ps_printf(p, "%%%%DocumentNeededResources: font");
    +
    +		for (i = 0; i < (int)TERMFONT__MAX; i++)
    +			ps_printf(p, " %s", fonts[i].name);
    +
    +		ps_printf(p, "\n%%%%DocumentSuppliedResources: "
    +		    "procset MandocProcs 1.0 0\n");
    +		ps_printf(p, "%%%%EndComments\n");
    +		ps_printf(p, "%%%%BeginProlog\n");
    +		ps_printf(p, "%%%%BeginResource: procset MandocProcs "
    +		    "10170 10170\n");
    +		/* The font size is effectively hard-coded for now. */
    +		ps_printf(p, "/fs %zu def\n", p->ps->scale);
    +		for (i = 0; i < (int)TERMFONT__MAX; i++)
    +			ps_printf(p, "/f%d { /%s fs selectfont } def\n",
    +			    i, fonts[i].name);
    +		ps_printf(p, "/s { 3 1 roll moveto show } bind def\n");
    +		ps_printf(p, "/c { exch currentpoint exch pop "
    +		    "moveto show } bind def\n");
    +		ps_printf(p, "%%%%EndResource\n");
    +		ps_printf(p, "%%%%EndProlog\n");
    +		ps_printf(p, "%%%%BeginSetup\n");
    +		ps_printf(p, "%%%%BeginFeature: *PageSize %s\n",
    +		    p->ps->medianame);
    +		ps_printf(p, "<</PageSize [%zu %zu]>>setpagedevice\n",
    +		    width, height);
    +		ps_printf(p, "%%%%EndFeature\n");
    +		ps_printf(p, "%%%%EndSetup\n");
    +	} else {
    +		ps_printf(p, "%%PDF-1.1\n");
    +		pdf_obj(p, 1);
    +		ps_printf(p, "<<\n");
    +		ps_printf(p, ">>\n");
    +		ps_printf(p, "endobj\n");
    +
    +		for (i = 0; i < (int)TERMFONT__MAX; i++) {
    +			pdf_obj(p, (size_t)i + 3);
    +			ps_printf(p, "<<\n");
    +			ps_printf(p, "/Type /Font\n");
    +			ps_printf(p, "/Subtype /Type1\n");
    +			ps_printf(p, "/Name /F%d\n", i);
    +			ps_printf(p, "/BaseFont /%s\n", fonts[i].name);
    +			ps_printf(p, ">>\nendobj\n");
    +		}
    +	}
    +
    +	p->ps->pdfbody = (size_t)TERMFONT__MAX + 3;
    +	p->ps->pscol = p->ps->left;
    +	p->ps->psrow = p->ps->top;
    +	p->ps->flags |= PS_NEWPAGE;
    +	ps_setfont(p, TERMFONT_NONE);
    +}
    +
    +static void
    +ps_pletter(struct termp *p, int c)
    +{
    +	int		 f;
    +
    +	/*
    +	 * If we haven't opened a page context, then output that we're
    +	 * in a new page and make sure the font is correctly set.
    +	 */
    +
    +	if (PS_NEWPAGE & p->ps->flags) {
    +		if (TERMTYPE_PS == p->type) {
    +			ps_printf(p, "%%%%Page: %zu %zu\n",
    +			    p->ps->pages + 1, p->ps->pages + 1);
    +			ps_printf(p, "f%d\n", (int)p->ps->lastf);
    +		} else {
    +			pdf_obj(p, p->ps->pdfbody +
    +			    p->ps->pages * 4);
    +			ps_printf(p, "<<\n");
    +			ps_printf(p, "/Length %zu 0 R\n",
    +			    p->ps->pdfbody + 1 + p->ps->pages * 4);
    +			ps_printf(p, ">>\nstream\n");
    +		}
    +		p->ps->pdflastpg = p->ps->pdfbytes;
    +		p->ps->flags &= ~PS_NEWPAGE;
    +	}
    +
    +	/*
    +	 * If we're not in a PostScript "word" context, then open one
    +	 * now at the current cursor.
    +	 */
    +
    +	if ( ! (PS_INLINE & p->ps->flags)) {
    +		if (TERMTYPE_PS != p->type) {
    +			ps_printf(p, "BT\n/F%d %zu Tf\n",
    +			    (int)p->ps->lastf, p->ps->scale);
    +			ps_printf(p, "%.3f %.3f Td\n(",
    +			    AFM2PNT(p, p->ps->pscol),
    +			    AFM2PNT(p, p->ps->psrow));
    +		} else {
    +			ps_printf(p, "%.3f", AFM2PNT(p, p->ps->pscol));
    +			if (p->ps->psrow != p->ps->lastrow)
    +				ps_printf(p, " %.3f",
    +				    AFM2PNT(p, p->ps->psrow));
    +			ps_printf(p, "(");
    +		}
    +		p->ps->flags |= PS_INLINE;
    +	}
    +
    +	assert( ! (PS_NEWPAGE & p->ps->flags));
    +
    +	/*
    +	 * We need to escape these characters as per the PostScript
    +	 * specification.  We would also escape non-graphable characters
    +	 * (like tabs), but none of them would get to this point and
    +	 * it's superfluous to abort() on them.
    +	 */
    +
    +	switch (c) {
    +	case '(':
    +	case ')':
    +	case '\\':
    +		ps_putchar(p, '\\');
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	/* Write the character and adjust where we are on the page. */
    +
    +	f = (int)p->ps->lastf;
    +
    +	if (c <= 32 || c - 32 >= MAXCHAR)
    +		c = 32;
    +
    +	ps_putchar(p, (char)c);
    +	c -= 32;
    +	p->ps->pscol += (size_t)fonts[f].gly[c].wx;
    +}
    +
    +static void
    +ps_pclose(struct termp *p)
    +{
    +
    +	/*
    +	 * Spit out that we're exiting a word context (this is a
    +	 * "partial close" because we don't check the last-char buffer
    +	 * or anything).
    +	 */
    +
    +	if ( ! (PS_INLINE & p->ps->flags))
    +		return;
    +
    +	if (TERMTYPE_PS != p->type)
    +		ps_printf(p, ") Tj\nET\n");
    +	else if (p->ps->psrow == p->ps->lastrow)
    +		ps_printf(p, ")c\n");
    +	else {
    +		ps_printf(p, ")s\n");
    +		p->ps->lastrow = p->ps->psrow;
    +	}
    +
    +	p->ps->flags &= ~PS_INLINE;
    +}
    +
    +/* If we have a `last' char that wasn't printed yet, print it now. */
    +static void
    +ps_plast(struct termp *p)
    +{
    +	size_t	 wx;
    +
    +	if (p->ps->last == '\0')
    +		return;
    +
    +	/* Check the font mode; open a new scope if it doesn't match. */
    +
    +	if (p->ps->nextf != p->ps->lastf) {
    +		ps_pclose(p);
    +		ps_setfont(p, p->ps->nextf);
    +	}
    +	p->ps->nextf = TERMFONT_NONE;
    +
    +	/*
    +	 * For an overstrike, if a previous character
    +	 * was wider, advance to center the new one.
    +	 */
    +
    +	if (p->ps->pscolnext) {
    +		wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx;
    +		if (p->ps->pscol + wx < p->ps->pscolnext)
    +			p->ps->pscol = (p->ps->pscol +
    +			    p->ps->pscolnext - wx) / 2;
    +	}
    +
    +	ps_pletter(p, p->ps->last);
    +	p->ps->last = '\0';
    +
    +	/*
    +	 * For an overstrike, if a previous character
    +	 * was wider, advance to the end of the old one.
    +	 */
    +
    +	if (p->ps->pscol < p->ps->pscolnext) {
    +		ps_pclose(p);
    +		p->ps->pscol = p->ps->pscolnext;
    +	}
    +}
    +
    +static void
    +ps_letter(struct termp *p, int arg)
    +{
    +	size_t		savecol;
    +	char		c;
    +
    +	c = arg >= 128 || arg <= 0 ? '?' : arg;
    +
    +	/*
    +	 * When receiving a backspace, merely flag it.
    +	 * We don't know yet whether it is
    +	 * a font instruction or an overstrike.
    +	 */
    +
    +	if (c == '\b') {
    +		assert(p->ps->last != '\0');
    +		assert( ! (p->ps->flags & PS_BACKSP));
    +		p->ps->flags |= PS_BACKSP;
    +		return;
    +	}
    +
    +	/*
    +	 * Decode font instructions.
    +	 */
    +
    +	if (p->ps->flags & PS_BACKSP) {
    +		if (p->ps->last == '_') {
    +			switch (p->ps->nextf) {
    +			case TERMFONT_BI:
    +				break;
    +			case TERMFONT_BOLD:
    +				p->ps->nextf = TERMFONT_BI;
    +				break;
    +			default:
    +				p->ps->nextf = TERMFONT_UNDER;
    +			}
    +			p->ps->last = c;
    +			p->ps->flags &= ~PS_BACKSP;
    +			return;
    +		}
    +		if (p->ps->last == c) {
    +			switch (p->ps->nextf) {
    +			case TERMFONT_BI:
    +				break;
    +			case TERMFONT_UNDER:
    +				p->ps->nextf = TERMFONT_BI;
    +				break;
    +			default:
    +				p->ps->nextf = TERMFONT_BOLD;
    +			}
    +			p->ps->flags &= ~PS_BACKSP;
    +			return;
    +		}
    +
    +		/*
    +		 * This is not a font instruction, but rather
    +		 * the next character.  Prepare for overstrike.
    +		 */
    +
    +		savecol = p->ps->pscol;
    +	} else
    +		savecol = SIZE_MAX;
    +
    +	/*
    +	 * We found the next character, so the font instructions
    +	 * for the previous one are complete.
    +	 * Use them and print it.
    +	 */
    +
    +	ps_plast(p);
    +
    +	/*
    +	 * Do not print the current character yet because font
    +	 * instructions might follow; only remember the character.
    +	 * It will get printed later from ps_plast().
    +	 */
    +
    +	p->ps->last = c;
    +
    +	/*
    +	 * For an overstrike, back up to the previous position.
    +	 * If the previous character is wider than any it overstrikes,
    +	 * remember the current position, because it might also be
    +	 * wider than all that will overstrike it.
    +	 */
    +
    +	if (savecol != SIZE_MAX) {
    +		if (p->ps->pscolnext < p->ps->pscol)
    +			p->ps->pscolnext = p->ps->pscol;
    +		ps_pclose(p);
    +		p->ps->pscol = savecol;
    +		p->ps->flags &= ~PS_BACKSP;
    +	} else
    +		p->ps->pscolnext = 0;
    +}
    +
    +static void
    +ps_advance(struct termp *p, size_t len)
    +{
    +
    +	/*
    +	 * Advance some spaces.  This can probably be made smarter,
    +	 * i.e., to have multiple space-separated words in the same
    +	 * scope, but this is easier:  just close out the current scope
    +	 * and readjust our column settings.
    +	 */
    +
    +	ps_plast(p);
    +	ps_pclose(p);
    +	p->ps->pscol += len;
    +}
    +
    +static void
    +ps_endline(struct termp *p)
    +{
    +
    +	/* Close out any scopes we have open: we're at eoln. */
    +
    +	ps_plast(p);
    +	ps_pclose(p);
    +
    +	/*
    +	 * If we're in the margin, don't try to recalculate our current
    +	 * row.  XXX: if the column tries to be fancy with multiple
    +	 * lines, we'll do nasty stuff.
    +	 */
    +
    +	if (PS_MARGINS & p->ps->flags)
    +		return;
    +
    +	/* Left-justify. */
    +
    +	p->ps->pscol = p->ps->left;
    +
    +	/* If we haven't printed anything, return. */
    +
    +	if (PS_NEWPAGE & p->ps->flags)
    +		return;
    +
    +	/*
    +	 * Put us down a line.  If we're at the page bottom, spit out a
    +	 * showpage and restart our row.
    +	 */
    +
    +	if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) {
    +		p->ps->psrow -= p->ps->lineheight;
    +		return;
    +	}
    +
    +	ps_closepage(p);
    +
    +	p->tcol->offset -= p->ti;
    +	p->ti = 0;
    +}
    +
    +static void
    +ps_setfont(struct termp *p, enum termfont f)
    +{
    +
    +	assert(f < TERMFONT__MAX);
    +	p->ps->lastf = f;
    +
    +	/*
    +	 * If we're still at the top of the page, let the font-setting
    +	 * be delayed until we actually have stuff to print.
    +	 */
    +
    +	if (PS_NEWPAGE & p->ps->flags)
    +		return;
    +
    +	if (TERMTYPE_PS == p->type)
    +		ps_printf(p, "f%d\n", (int)f);
    +	else
    +		ps_printf(p, "/F%d %zu Tf\n",
    +		    (int)f, p->ps->scale);
    +}
    +
    +static size_t
    +ps_width(const struct termp *p, int c)
    +{
    +
    +	if (c <= 32 || c - 32 >= MAXCHAR)
    +		c = 0;
    +	else
    +		c -= 32;
    +
    +	return (size_t)fonts[(int)TERMFONT_NONE].gly[c].wx;
    +}
    +
    +static int
    +ps_hspan(const struct termp *p, const struct roffsu *su)
    +{
    +	double		 r;
    +
    +	/*
    +	 * All of these measurements are derived by converting from the
    +	 * native measurement to AFM units.
    +	 */
    +	switch (su->unit) {
    +	case SCALE_BU:
    +		/*
    +		 * Traditionally, the default unit is fixed to the
    +		 * output media.  So this would refer to the point.  In
    +		 * mandoc(1), however, we stick to the default terminal
    +		 * scaling unit so that output is the same regardless
    +		 * the media.
    +		 */
    +		r = PNT2AFM(p, su->scale * 72.0 / 240.0);
    +		break;
    +	case SCALE_CM:
    +		r = PNT2AFM(p, su->scale * 72.0 / 2.54);
    +		break;
    +	case SCALE_EM:
    +		r = su->scale *
    +		    fonts[(int)TERMFONT_NONE].gly[109 - 32].wx;
    +		break;
    +	case SCALE_EN:
    +		r = su->scale *
    +		    fonts[(int)TERMFONT_NONE].gly[110 - 32].wx;
    +		break;
    +	case SCALE_IN:
    +		r = PNT2AFM(p, su->scale * 72.0);
    +		break;
    +	case SCALE_MM:
    +		r = su->scale *
    +		    fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0;
    +		break;
    +	case SCALE_PC:
    +		r = PNT2AFM(p, su->scale * 12.0);
    +		break;
    +	case SCALE_PT:
    +		r = PNT2AFM(p, su->scale * 1.0);
    +		break;
    +	case SCALE_VS:
    +		r = su->scale * p->ps->lineheight;
    +		break;
    +	default:
    +		r = su->scale;
    +		break;
    +	}
    +
    +	return r * 24.0;
    +}
    +
    +static void
    +ps_growbuf(struct termp *p, size_t sz)
    +{
    +	if (p->ps->psmargcur + sz <= p->ps->psmargsz)
    +		return;
    +
    +	if (sz < PS_BUFSLOP)
    +		sz = PS_BUFSLOP;
    +
    +	p->ps->psmargsz += sz;
    +	p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz);
    +}
    
    Property changes on: head/contrib/mandoc/term_ps.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-noop.c
    ===================================================================
    --- head/contrib/mandoc/test-noop.c	(nonexistent)
    +++ head/contrib/mandoc/test-noop.c	(revision 338826)
    @@ -0,0 +1,5 @@
    +int
    +main(void)
    +{
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-noop.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-strndup.c
    ===================================================================
    --- head/contrib/mandoc/test-strndup.c	(nonexistent)
    +++ head/contrib/mandoc/test-strndup.c	(revision 338826)
    @@ -0,0 +1,10 @@
    +#include <string.h>
    +
    +int
    +main(void)
    +{
    +	char *s;
    +
    +	s = strndup("123", 2);
    +	return s[0] != '1' ? 1 : s[1] != '2' ? 2 : s[2] != '\0' ? 3 : 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-strndup.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tree.c
    ===================================================================
    --- head/contrib/mandoc/tree.c	(nonexistent)
    +++ head/contrib/mandoc/tree.c	(revision 338826)
    @@ -0,0 +1,411 @@
    +/*	$Id: tree.c,v 1.78 2018/04/11 17:11:13 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <time.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "man.h"
    +#include "main.h"
    +
    +static	void	print_box(const struct eqn_box *, int);
    +static	void	print_man(const struct roff_node *, int);
    +static	void	print_meta(const struct roff_meta *);
    +static	void	print_mdoc(const struct roff_node *, int);
    +static	void	print_span(const struct tbl_span *, int);
    +
    +
    +void
    +tree_mdoc(void *arg, const struct roff_man *mdoc)
    +{
    +	print_meta(&mdoc->meta);
    +	putchar('\n');
    +	print_mdoc(mdoc->first->child, 0);
    +}
    +
    +void
    +tree_man(void *arg, const struct roff_man *man)
    +{
    +	print_meta(&man->meta);
    +	if (man->meta.hasbody == 0)
    +		puts("body  = empty");
    +	putchar('\n');
    +	print_man(man->first->child, 0);
    +}
    +
    +static void
    +print_meta(const struct roff_meta *meta)
    +{
    +	if (meta->title != NULL)
    +		printf("title = \"%s\"\n", meta->title);
    +	if (meta->name != NULL)
    +		printf("name  = \"%s\"\n", meta->name);
    +	if (meta->msec != NULL)
    +		printf("sec   = \"%s\"\n", meta->msec);
    +	if (meta->vol != NULL)
    +		printf("vol   = \"%s\"\n", meta->vol);
    +	if (meta->arch != NULL)
    +		printf("arch  = \"%s\"\n", meta->arch);
    +	if (meta->os != NULL)
    +		printf("os    = \"%s\"\n", meta->os);
    +	if (meta->date != NULL)
    +		printf("date  = \"%s\"\n", meta->date);
    +}
    +
    +static void
    +print_mdoc(const struct roff_node *n, int indent)
    +{
    +	const char	 *p, *t;
    +	int		  i, j;
    +	size_t		  argc;
    +	struct mdoc_argv *argv;
    +
    +	if (n == NULL)
    +		return;
    +
    +	argv = NULL;
    +	argc = 0;
    +	t = p = NULL;
    +
    +	switch (n->type) {
    +	case ROFFT_ROOT:
    +		t = "root";
    +		break;
    +	case ROFFT_BLOCK:
    +		t = "block";
    +		break;
    +	case ROFFT_HEAD:
    +		t = "head";
    +		break;
    +	case ROFFT_BODY:
    +		if (n->end)
    +			t = "body-end";
    +		else
    +			t = "body";
    +		break;
    +	case ROFFT_TAIL:
    +		t = "tail";
    +		break;
    +	case ROFFT_ELEM:
    +		t = "elem";
    +		break;
    +	case ROFFT_TEXT:
    +		t = "text";
    +		break;
    +	case ROFFT_COMMENT:
    +		t = "comment";
    +		break;
    +	case ROFFT_TBL:
    +		break;
    +	case ROFFT_EQN:
    +		t = "eqn";
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	switch (n->type) {
    +	case ROFFT_TEXT:
    +	case ROFFT_COMMENT:
    +		p = n->string;
    +		break;
    +	case ROFFT_BODY:
    +		p = roff_name[n->tok];
    +		break;
    +	case ROFFT_HEAD:
    +		p = roff_name[n->tok];
    +		break;
    +	case ROFFT_TAIL:
    +		p = roff_name[n->tok];
    +		break;
    +	case ROFFT_ELEM:
    +		p = roff_name[n->tok];
    +		if (n->args) {
    +			argv = n->args->argv;
    +			argc = n->args->argc;
    +		}
    +		break;
    +	case ROFFT_BLOCK:
    +		p = roff_name[n->tok];
    +		if (n->args) {
    +			argv = n->args->argv;
    +			argc = n->args->argc;
    +		}
    +		break;
    +	case ROFFT_TBL:
    +		break;
    +	case ROFFT_EQN:
    +		p = "EQ";
    +		break;
    +	case ROFFT_ROOT:
    +		p = "root";
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	if (n->span) {
    +		assert(NULL == p && NULL == t);
    +		print_span(n->span, indent);
    +	} else {
    +		for (i = 0; i < indent; i++)
    +			putchar(' ');
    +
    +		printf("%s (%s)", p, t);
    +
    +		for (i = 0; i < (int)argc; i++) {
    +			printf(" -%s", mdoc_argnames[argv[i].arg]);
    +			if (argv[i].sz > 0)
    +				printf(" [");
    +			for (j = 0; j < (int)argv[i].sz; j++)
    +				printf(" [%s]", argv[i].value[j]);
    +			if (argv[i].sz > 0)
    +				printf(" ]");
    +		}
    +
    +		putchar(' ');
    +		if (NODE_DELIMO & n->flags)
    +			putchar('(');
    +		if (NODE_LINE & n->flags)
    +			putchar('*');
    +		printf("%d:%d", n->line, n->pos + 1);
    +		if (NODE_DELIMC & n->flags)
    +			putchar(')');
    +		if (NODE_EOS & n->flags)
    +			putchar('.');
    +		if (NODE_BROKEN & n->flags)
    +			printf(" BROKEN");
    +		if (NODE_NOSRC & n->flags)
    +			printf(" NOSRC");
    +		if (NODE_NOPRT & n->flags)
    +			printf(" NOPRT");
    +		putchar('\n');
    +	}
    +
    +	if (n->eqn)
    +		print_box(n->eqn->first, indent + 4);
    +	if (n->child)
    +		print_mdoc(n->child, indent +
    +		    (n->type == ROFFT_BLOCK ? 2 : 4));
    +	if (n->next)
    +		print_mdoc(n->next, indent);
    +}
    +
    +static void
    +print_man(const struct roff_node *n, int indent)
    +{
    +	const char	 *p, *t;
    +	int		  i;
    +
    +	if (n == NULL)
    +		return;
    +
    +	t = p = NULL;
    +
    +	switch (n->type) {
    +	case ROFFT_ROOT:
    +		t = "root";
    +		break;
    +	case ROFFT_ELEM:
    +		t = "elem";
    +		break;
    +	case ROFFT_TEXT:
    +		t = "text";
    +		break;
    +	case ROFFT_COMMENT:
    +		t = "comment";
    +		break;
    +	case ROFFT_BLOCK:
    +		t = "block";
    +		break;
    +	case ROFFT_HEAD:
    +		t = "head";
    +		break;
    +	case ROFFT_BODY:
    +		t = "body";
    +		break;
    +	case ROFFT_TBL:
    +		break;
    +	case ROFFT_EQN:
    +		t = "eqn";
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	switch (n->type) {
    +	case ROFFT_TEXT:
    +	case ROFFT_COMMENT:
    +		p = n->string;
    +		break;
    +	case ROFFT_ELEM:
    +	case ROFFT_BLOCK:
    +	case ROFFT_HEAD:
    +	case ROFFT_BODY:
    +		p = roff_name[n->tok];
    +		break;
    +	case ROFFT_ROOT:
    +		p = "root";
    +		break;
    +	case ROFFT_TBL:
    +		break;
    +	case ROFFT_EQN:
    +		p = "EQ";
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	if (n->span) {
    +		assert(NULL == p && NULL == t);
    +		print_span(n->span, indent);
    +	} else {
    +		for (i = 0; i < indent; i++)
    +			putchar(' ');
    +		printf("%s (%s) ", p, t);
    +		if (NODE_LINE & n->flags)
    +			putchar('*');
    +		printf("%d:%d", n->line, n->pos + 1);
    +		if (NODE_EOS & n->flags)
    +			putchar('.');
    +		putchar('\n');
    +	}
    +
    +	if (n->eqn)
    +		print_box(n->eqn->first, indent + 4);
    +	if (n->child)
    +		print_man(n->child, indent +
    +		    (n->type == ROFFT_BLOCK ? 2 : 4));
    +	if (n->next)
    +		print_man(n->next, indent);
    +}
    +
    +static void
    +print_box(const struct eqn_box *ep, int indent)
    +{
    +	int		 i;
    +	const char	*t;
    +
    +	static const char *posnames[] = {
    +	    NULL, "sup", "subsup", "sub",
    +	    "to", "from", "fromto",
    +	    "over", "sqrt", NULL };
    +
    +	if (NULL == ep)
    +		return;
    +	for (i = 0; i < indent; i++)
    +		putchar(' ');
    +
    +	t = NULL;
    +	switch (ep->type) {
    +	case EQN_LIST:
    +		t = "eqn-list";
    +		break;
    +	case EQN_SUBEXPR:
    +		t = "eqn-expr";
    +		break;
    +	case EQN_TEXT:
    +		t = "eqn-text";
    +		break;
    +	case EQN_PILE:
    +		t = "eqn-pile";
    +		break;
    +	case EQN_MATRIX:
    +		t = "eqn-matrix";
    +		break;
    +	}
    +
    +	fputs(t, stdout);
    +	if (ep->pos)
    +		printf(" pos=%s", posnames[ep->pos]);
    +	if (ep->left)
    +		printf(" left=\"%s\"", ep->left);
    +	if (ep->right)
    +		printf(" right=\"%s\"", ep->right);
    +	if (ep->top)
    +		printf(" top=\"%s\"", ep->top);
    +	if (ep->bottom)
    +		printf(" bottom=\"%s\"", ep->bottom);
    +	if (ep->text)
    +		printf(" text=\"%s\"", ep->text);
    +	if (ep->font)
    +		printf(" font=%d", ep->font);
    +	if (ep->size != EQN_DEFSIZE)
    +		printf(" size=%d", ep->size);
    +	if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
    +		printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
    +	else if (ep->args)
    +		printf(" args=%zu", ep->args);
    +	putchar('\n');
    +
    +	print_box(ep->first, indent + 4);
    +	print_box(ep->next, indent);
    +}
    +
    +static void
    +print_span(const struct tbl_span *sp, int indent)
    +{
    +	const struct tbl_dat *dp;
    +	int		 i;
    +
    +	for (i = 0; i < indent; i++)
    +		putchar(' ');
    +
    +	switch (sp->pos) {
    +	case TBL_SPAN_HORIZ:
    +		putchar('-');
    +		return;
    +	case TBL_SPAN_DHORIZ:
    +		putchar('=');
    +		return;
    +	default:
    +		break;
    +	}
    +
    +	for (dp = sp->first; dp; dp = dp->next) {
    +		switch (dp->pos) {
    +		case TBL_DATA_HORIZ:
    +		case TBL_DATA_NHORIZ:
    +			putchar('-');
    +			continue;
    +		case TBL_DATA_DHORIZ:
    +		case TBL_DATA_NDHORIZ:
    +			putchar('=');
    +			continue;
    +		default:
    +			break;
    +		}
    +		printf("[\"%s\"", dp->string ? dp->string : "");
    +		if (dp->spans)
    +			printf("(%d)", dp->spans);
    +		if (NULL == dp->layout)
    +			putchar('*');
    +		putchar(']');
    +		putchar(' ');
    +	}
    +
    +	printf("(tbl) %d:1\n", sp->line);
    +}
    
    Property changes on: head/contrib/mandoc/tree.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tbl_term.c
    ===================================================================
    --- head/contrib/mandoc/tbl_term.c	(nonexistent)
    +++ head/contrib/mandoc/tbl_term.c	(revision 338826)
    @@ -0,0 +1,676 @@
    +/*	$Id: tbl_term.c,v 1.57 2017/07/31 16:14:10 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "out.h"
    +#include "term.h"
    +
    +#define	IS_HORIZ(cp)	((cp)->pos == TBL_CELL_HORIZ || \
    +			 (cp)->pos == TBL_CELL_DHORIZ)
    +
    +static	size_t	term_tbl_len(size_t, void *);
    +static	size_t	term_tbl_strlen(const char *, void *);
    +static	size_t	term_tbl_sulen(const struct roffsu *, void *);
    +static	void	tbl_char(struct termp *, char, size_t);
    +static	void	tbl_data(struct termp *, const struct tbl_opts *,
    +			const struct tbl_cell *,
    +			const struct tbl_dat *,
    +			const struct roffcol *);
    +static	void	tbl_literal(struct termp *, const struct tbl_dat *,
    +			const struct roffcol *);
    +static	void	tbl_number(struct termp *, const struct tbl_opts *,
    +			const struct tbl_dat *,
    +			const struct roffcol *);
    +static	void	tbl_hrule(struct termp *, const struct tbl_span *, int);
    +static	void	tbl_word(struct termp *, const struct tbl_dat *);
    +
    +
    +static size_t
    +term_tbl_sulen(const struct roffsu *su, void *arg)
    +{
    +	int	 i;
    +
    +	i = term_hen((const struct termp *)arg, su);
    +	return i > 0 ? i : 0;
    +}
    +
    +static size_t
    +term_tbl_strlen(const char *p, void *arg)
    +{
    +	return term_strlen((const struct termp *)arg, p);
    +}
    +
    +static size_t
    +term_tbl_len(size_t sz, void *arg)
    +{
    +	return term_len((const struct termp *)arg, sz);
    +}
    +
    +void
    +term_tbl(struct termp *tp, const struct tbl_span *sp)
    +{
    +	const struct tbl_cell	*cp, *cpn, *cpp;
    +	const struct tbl_dat	*dp;
    +	static size_t		 offset;
    +	size_t			 coloff, tsz;
    +	int			 ic, horiz, spans, vert, more;
    +	char			 fc;
    +
    +	/* Inhibit printing of spaces: we do padding ourselves. */
    +
    +	tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE;
    +
    +	/*
    +	 * The first time we're invoked for a given table block,
    +	 * calculate the table widths and decimal positions.
    +	 */
    +
    +	if (tp->tbl.cols == NULL) {
    +		tp->tbl.len = term_tbl_len;
    +		tp->tbl.slen = term_tbl_strlen;
    +		tp->tbl.sulen = term_tbl_sulen;
    +		tp->tbl.arg = tp;
    +
    +		tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin);
    +
    +		/* Tables leak .ta settings to subsequent text. */
    +
    +		term_tab_set(tp, NULL);
    +		coloff = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
    +		    sp->opts->lvert;
    +		for (ic = 0; ic < sp->opts->cols; ic++) {
    +			coloff += tp->tbl.cols[ic].width;
    +			term_tab_iset(coloff);
    +			coloff += tp->tbl.cols[ic].spacing;
    +		}
    +
    +		/* Center the table as a whole. */
    +
    +		offset = tp->tcol->offset;
    +		if (sp->opts->opts & TBL_OPT_CENTRE) {
    +			tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)
    +			    ? 2 : !!sp->opts->lvert + !!sp->opts->rvert;
    +			for (ic = 0; ic + 1 < sp->opts->cols; ic++)
    +				tsz += tp->tbl.cols[ic].width +
    +				    tp->tbl.cols[ic].spacing;
    +			if (sp->opts->cols)
    +				tsz += tp->tbl.cols[sp->opts->cols - 1].width;
    +			if (offset + tsz > tp->tcol->rmargin)
    +				tsz -= 1;
    +			tp->tcol->offset = offset + tp->tcol->rmargin > tsz ?
    +			    (offset + tp->tcol->rmargin - tsz) / 2 : 0;
    +		}
    +
    +		/* Horizontal frame at the start of boxed tables. */
    +
    +		if (sp->opts->opts & TBL_OPT_DBOX)
    +			tbl_hrule(tp, sp, 3);
    +		if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
    +			tbl_hrule(tp, sp, 2);
    +	}
    +
    +	/* Set up the columns. */
    +
    +	tp->flags |= TERMP_MULTICOL;
    +	horiz = 0;
    +	switch (sp->pos) {
    +	case TBL_SPAN_HORIZ:
    +	case TBL_SPAN_DHORIZ:
    +		horiz = 1;
    +		term_setcol(tp, 1);
    +		break;
    +	case TBL_SPAN_DATA:
    +		term_setcol(tp, sp->opts->cols + 2);
    +		coloff = tp->tcol->offset;
    +
    +		/* Set up a column for a left vertical frame. */
    +
    +		if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
    +		    sp->opts->lvert)
    +			coloff++;
    +		tp->tcol->rmargin = coloff;
    +
    +		/* Set up the data columns. */
    +
    +		dp = sp->first;
    +		spans = 0;
    +		for (ic = 0; ic < sp->opts->cols; ic++) {
    +			if (spans == 0) {
    +				tp->tcol++;
    +				tp->tcol->offset = coloff;
    +			}
    +			coloff += tp->tbl.cols[ic].width;
    +			tp->tcol->rmargin = coloff;
    +			if (ic + 1 < sp->opts->cols)
    +				coloff += tp->tbl.cols[ic].spacing;
    +			if (spans) {
    +				spans--;
    +				continue;
    +			}
    +			if (dp == NULL)
    +				continue;
    +			spans = dp->spans;
    +			if (ic || sp->layout->first->pos != TBL_CELL_SPAN)
    +				dp = dp->next;
    +		}
    +
    +		/* Set up a column for a right vertical frame. */
    +
    +		tp->tcol++;
    +		tp->tcol->offset = coloff + 1;
    +		tp->tcol->rmargin = tp->maxrmargin;
    +
    +		/* Spans may have reduced the number of columns. */
    +
    +		tp->lasttcol = tp->tcol - tp->tcols;
    +
    +		/* Fill the buffers for all data columns. */
    +
    +		tp->tcol = tp->tcols;
    +		cp = cpn = sp->layout->first;
    +		dp = sp->first;
    +		spans = 0;
    +		for (ic = 0; ic < sp->opts->cols; ic++) {
    +			if (cpn != NULL) {
    +				cp = cpn;
    +				cpn = cpn->next;
    +			}
    +			if (spans) {
    +				spans--;
    +				continue;
    +			}
    +			tp->tcol++;
    +			tp->col = 0;
    +			tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic);
    +			if (dp == NULL)
    +				continue;
    +			spans = dp->spans;
    +			if (cp->pos != TBL_CELL_SPAN)
    +				dp = dp->next;
    +		}
    +		break;
    +	}
    +
    +	do {
    +		/* Print the vertical frame at the start of each row. */
    +
    +		tp->tcol = tp->tcols;
    +		fc = '\0';
    +		if (sp->layout->vert ||
    +		    (sp->next != NULL && sp->next->layout->vert &&
    +		     sp->next->pos == TBL_SPAN_DATA) ||
    +		    (sp->prev != NULL && sp->prev->layout->vert &&
    +		     (horiz || (IS_HORIZ(sp->layout->first) &&
    +		       !IS_HORIZ(sp->prev->layout->first)))) ||
    +		    sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
    +			fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|';
    +		else if (horiz && sp->opts->lvert)
    +			fc = '-';
    +		if (fc != '\0') {
    +			(*tp->advance)(tp, tp->tcols->offset);
    +			(*tp->letter)(tp, fc);
    +			tp->viscol = tp->tcol->offset + 1;
    +		}
    +
    +		/* Print the data cells. */
    +
    +		more = 0;
    +		if (horiz) {
    +			tbl_hrule(tp, sp, 0);
    +			term_flushln(tp);
    +		} else {
    +			cp = sp->layout->first;
    +			cpn = sp->next == NULL ? NULL :
    +			    sp->next->layout->first;
    +			cpp = sp->prev == NULL ? NULL :
    +			    sp->prev->layout->first;
    +			dp = sp->first;
    +			spans = 0;
    +			for (ic = 0; ic < sp->opts->cols; ic++) {
    +
    +				/*
    +				 * Figure out whether to print a
    +				 * vertical line after this cell
    +				 * and advance to next layout cell.
    +				 */
    +
    +				if (cp != NULL) {
    +					vert = cp->vert;
    +					switch (cp->pos) {
    +					case TBL_CELL_HORIZ:
    +						fc = '-';
    +						break;
    +					case TBL_CELL_DHORIZ:
    +						fc = '=';
    +						break;
    +					default:
    +						fc = ' ';
    +						break;
    +					}
    +				} else {
    +					vert = 0;
    +					fc = ' ';
    +				}
    +				if (cpp != NULL) {
    +					if (vert == 0 &&
    +					    cp != NULL &&
    +					    ((IS_HORIZ(cp) &&
    +					      !IS_HORIZ(cpp)) ||
    +					     (cp->next != NULL &&
    +					      cpp->next != NULL &&
    +					      IS_HORIZ(cp->next) &&
    +					      !IS_HORIZ(cpp->next))))
    +						vert = cpp->vert;
    +					cpp = cpp->next;
    +				}
    +				if (vert == 0 &&
    +				    sp->opts->opts & TBL_OPT_ALLBOX)
    +					vert = 1;
    +				if (cpn != NULL) {
    +					if (vert == 0)
    +						vert = cpn->vert;
    +					cpn = cpn->next;
    +				}
    +				if (cp != NULL)
    +					cp = cp->next;
    +
    +				/*
    +				 * Skip later cells in a span,
    +				 * figure out whether to start a span,
    +				 * and advance to next data cell.
    +				 */
    +
    +				if (spans) {
    +					spans--;
    +					continue;
    +				}
    +				if (dp != NULL) {
    +					spans = dp->spans;
    +					if (ic || sp->layout->first->pos
    +					    != TBL_CELL_SPAN)
    +						dp = dp->next;
    +				}
    +
    +				/*
    +				 * Print one line of text in the cell
    +				 * and remember whether there is more.
    +				 */
    +
    +				tp->tcol++;
    +				if (tp->tcol->col < tp->tcol->lastcol)
    +					term_flushln(tp);
    +				if (tp->tcol->col < tp->tcol->lastcol)
    +					more = 1;
    +
    +				/*
    +				 * Vertical frames between data cells,
    +				 * but not after the last column.
    +				 */
    +
    +				if (fc == ' ' && ((vert == 0 &&
    +				     (cp == NULL || !IS_HORIZ(cp))) ||
    +				    tp->tcol + 1 == tp->tcols + tp->lasttcol))
    +					continue;
    +
    +				if (tp->viscol < tp->tcol->rmargin) {
    +					(*tp->advance)(tp, tp->tcol->rmargin
    +					   - tp->viscol);
    +					tp->viscol = tp->tcol->rmargin;
    +				}
    +				while (tp->viscol < tp->tcol->rmargin +
    +				    tp->tbl.cols[ic].spacing / 2) {
    +					(*tp->letter)(tp, fc);
    +					tp->viscol++;
    +				}
    +
    +				if (tp->tcol + 1 == tp->tcols + tp->lasttcol)
    +					continue;
    +
    +				if (fc == ' ' && cp != NULL) {
    +					switch (cp->pos) {
    +					case TBL_CELL_HORIZ:
    +						fc = '-';
    +						break;
    +					case TBL_CELL_DHORIZ:
    +						fc = '=';
    +						break;
    +					default:
    +						break;
    +					}
    +				}
    +				if (tp->tbl.cols[ic].spacing) {
    +					(*tp->letter)(tp, fc == ' ' ? '|' :
    +					    vert ? '+' : fc);
    +					tp->viscol++;
    +				}
    +
    +				if (fc != ' ') {
    +					if (cp != NULL &&
    +					    cp->pos == TBL_CELL_HORIZ)
    +						fc = '-';
    +					else if (cp != NULL &&
    +					    cp->pos == TBL_CELL_DHORIZ)
    +						fc = '=';
    +					else
    +						fc = ' ';
    +				}
    +				if (tp->tbl.cols[ic].spacing > 2 &&
    +				    (vert > 1 || fc != ' ')) {
    +					(*tp->letter)(tp, fc == ' ' ? '|' :
    +					    vert > 1 ? '+' : fc);
    +					tp->viscol++;
    +				}
    +			}
    +		}
    +
    +		/* Print the vertical frame at the end of each row. */
    +
    +		fc = '\0';
    +		if ((sp->layout->last->vert &&
    +		     sp->layout->last->col + 1 == sp->opts->cols) ||
    +		    (sp->next != NULL &&
    +		     sp->next->layout->last->vert &&
    +		     sp->next->layout->last->col + 1 == sp->opts->cols) ||
    +		    (sp->prev != NULL &&
    +		     sp->prev->layout->last->vert &&
    +		     sp->prev->layout->last->col + 1 == sp->opts->cols &&
    +		     (horiz || (IS_HORIZ(sp->layout->last) &&
    +		      !IS_HORIZ(sp->prev->layout->last)))) ||
    +		    (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
    +			fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|';
    +		else if (horiz && sp->opts->rvert)
    +			fc = '-';
    +		if (fc != '\0') {
    +			if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 ||
    +			    sp->layout->last->col + 1 < sp->opts->cols)) {
    +				tp->tcol++;
    +				(*tp->advance)(tp,
    +				    tp->tcol->offset > tp->viscol ?
    +				    tp->tcol->offset - tp->viscol : 1);
    +			}
    +			(*tp->letter)(tp, fc);
    +		}
    +		(*tp->endline)(tp);
    +		tp->viscol = 0;
    +	} while (more);
    +
    +	/*
    +	 * Clean up after this row.  If it is the last line
    +	 * of the table, print the box line and clean up
    +	 * column data; otherwise, print the allbox line.
    +	 */
    +
    +	term_setcol(tp, 1);
    +	tp->flags &= ~TERMP_MULTICOL;
    +	tp->tcol->rmargin = tp->maxrmargin;
    +	if (sp->next == NULL) {
    +		if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
    +			tbl_hrule(tp, sp, 2);
    +			tp->skipvsp = 1;
    +		}
    +		if (sp->opts->opts & TBL_OPT_DBOX) {
    +			tbl_hrule(tp, sp, 3);
    +			tp->skipvsp = 2;
    +		}
    +		assert(tp->tbl.cols);
    +		free(tp->tbl.cols);
    +		tp->tbl.cols = NULL;
    +		tp->tcol->offset = offset;
    +	} else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX &&
    +	    (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA ||
    +	     sp->next->next != NULL))
    +		tbl_hrule(tp, sp, 1);
    +
    +	tp->flags &= ~TERMP_NONOSPACE;
    +}
    +
    +/*
    + * Kinds of horizontal rulers:
    + * 0: inside the table (single or double line with crossings)
    + * 1: inside the table (single or double line with crossings and ends)
    + * 2: inner frame (single line with crossings and ends)
    + * 3: outer frame (single line without crossings with ends)
    + */
    +static void
    +tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
    +{
    +	const struct tbl_cell *cp, *cpn, *cpp;
    +	const struct roffcol *col;
    +	int	 vert;
    +	char	 line, cross;
    +
    +	line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
    +	cross = (kind < 3) ? '+' : '-';
    +
    +	if (kind)
    +		term_word(tp, "+");
    +	cp = sp->layout->first;
    +	cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first;
    +	if (cpp == cp)
    +		cpp = NULL;
    +	cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first;
    +	if (cpn == cp)
    +		cpn = NULL;
    +	for (;;) {
    +		col = tp->tbl.cols + cp->col;
    +		tbl_char(tp, line, col->width + col->spacing / 2);
    +		vert = cp->vert;
    +		if ((cp = cp->next) == NULL)
    +			 break;
    +		if (cpp != NULL) {
    +			if (vert < cpp->vert)
    +				vert = cpp->vert;
    +			cpp = cpp->next;
    +		}
    +		if (cpn != NULL) {
    +			if (vert < cpn->vert)
    +				vert = cpn->vert;
    +			cpn = cpn->next;
    +		}
    +		if (sp->opts->opts & TBL_OPT_ALLBOX && !vert)
    +			vert = 1;
    +		if (col->spacing)
    +			tbl_char(tp, vert ? cross : line, 1);
    +		if (col->spacing > 2)
    +			tbl_char(tp, vert > 1 ? cross : line, 1);
    +		if (col->spacing > 4)
    +			tbl_char(tp, line, (col->spacing - 3) / 2);
    +	}
    +	if (kind) {
    +		term_word(tp, "+");
    +		term_flushln(tp);
    +	}
    +}
    +
    +static void
    +tbl_data(struct termp *tp, const struct tbl_opts *opts,
    +    const struct tbl_cell *cp, const struct tbl_dat *dp,
    +    const struct roffcol *col)
    +{
    +	switch (cp->pos) {
    +	case TBL_CELL_HORIZ:
    +		tbl_char(tp, '-', col->width);
    +		return;
    +	case TBL_CELL_DHORIZ:
    +		tbl_char(tp, '=', col->width);
    +		return;
    +	default:
    +		break;
    +	}
    +
    +	if (dp == NULL)
    +		return;
    +
    +	switch (dp->pos) {
    +	case TBL_DATA_NONE:
    +		return;
    +	case TBL_DATA_HORIZ:
    +	case TBL_DATA_NHORIZ:
    +		tbl_char(tp, '-', col->width);
    +		return;
    +	case TBL_DATA_NDHORIZ:
    +	case TBL_DATA_DHORIZ:
    +		tbl_char(tp, '=', col->width);
    +		return;
    +	default:
    +		break;
    +	}
    +
    +	switch (cp->pos) {
    +	case TBL_CELL_LONG:
    +	case TBL_CELL_CENTRE:
    +	case TBL_CELL_LEFT:
    +	case TBL_CELL_RIGHT:
    +		tbl_literal(tp, dp, col);
    +		break;
    +	case TBL_CELL_NUMBER:
    +		tbl_number(tp, opts, dp, col);
    +		break;
    +	case TBL_CELL_DOWN:
    +	case TBL_CELL_SPAN:
    +		break;
    +	default:
    +		abort();
    +	}
    +}
    +
    +static void
    +tbl_char(struct termp *tp, char c, size_t len)
    +{
    +	size_t		i, sz;
    +	char		cp[2];
    +
    +	cp[0] = c;
    +	cp[1] = '\0';
    +
    +	sz = term_strlen(tp, cp);
    +
    +	for (i = 0; i < len; i += sz)
    +		term_word(tp, cp);
    +}
    +
    +static void
    +tbl_literal(struct termp *tp, const struct tbl_dat *dp,
    +		const struct roffcol *col)
    +{
    +	size_t		 len, padl, padr, width;
    +	int		 ic, spans;
    +
    +	assert(dp->string);
    +	len = term_strlen(tp, dp->string);
    +	width = col->width;
    +	ic = dp->layout->col;
    +	spans = dp->spans;
    +	while (spans--)
    +		width += tp->tbl.cols[++ic].width + 3;
    +
    +	padr = width > len ? width - len : 0;
    +	padl = 0;
    +
    +	switch (dp->layout->pos) {
    +	case TBL_CELL_LONG:
    +		padl = term_len(tp, 1);
    +		padr = padr > padl ? padr - padl : 0;
    +		break;
    +	case TBL_CELL_CENTRE:
    +		if (2 > padr)
    +			break;
    +		padl = padr / 2;
    +		padr -= padl;
    +		break;
    +	case TBL_CELL_RIGHT:
    +		padl = padr;
    +		padr = 0;
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	tbl_char(tp, ASCII_NBRSP, padl);
    +	tbl_word(tp, dp);
    +	tbl_char(tp, ASCII_NBRSP, padr);
    +}
    +
    +static void
    +tbl_number(struct termp *tp, const struct tbl_opts *opts,
    +		const struct tbl_dat *dp,
    +		const struct roffcol *col)
    +{
    +	char		*cp;
    +	char		 buf[2];
    +	size_t		 sz, psz, ssz, d, padl;
    +	int		 i;
    +
    +	/*
    +	 * See calc_data_number().  Left-pad by taking the offset of our
    +	 * and the maximum decimal; right-pad by the remaining amount.
    +	 */
    +
    +	assert(dp->string);
    +
    +	sz = term_strlen(tp, dp->string);
    +
    +	buf[0] = opts->decimal;
    +	buf[1] = '\0';
    +
    +	psz = term_strlen(tp, buf);
    +
    +	if ((cp = strrchr(dp->string, opts->decimal)) != NULL) {
    +		for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
    +			buf[0] = dp->string[i];
    +			ssz += term_strlen(tp, buf);
    +		}
    +		d = ssz + psz;
    +	} else
    +		d = sz + psz;
    +
    +	if (col->decimal > d && col->width > sz) {
    +		padl = col->decimal - d;
    +		if (padl + sz > col->width)
    +			padl = col->width - sz;
    +		tbl_char(tp, ASCII_NBRSP, padl);
    +	} else
    +		padl = 0;
    +	tbl_word(tp, dp);
    +	if (col->width > sz + padl)
    +		tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
    +}
    +
    +static void
    +tbl_word(struct termp *tp, const struct tbl_dat *dp)
    +{
    +	int		 prev_font;
    +
    +	prev_font = tp->fonti;
    +	if (dp->layout->flags & TBL_CELL_BOLD)
    +		term_fontpush(tp, TERMFONT_BOLD);
    +	else if (dp->layout->flags & TBL_CELL_ITALIC)
    +		term_fontpush(tp, TERMFONT_UNDER);
    +
    +	term_word(tp, dp->string);
    +
    +	term_fontpopq(tp, prev_font);
    +}
    
    Property changes on: head/contrib/mandoc/tbl_term.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/att.c
    ===================================================================
    --- head/contrib/mandoc/att.c	(nonexistent)
    +++ head/contrib/mandoc/att.c	(revision 338826)
    @@ -0,0 +1,51 @@
    +/*	$Id: att.c,v 1.16 2017/06/24 14:38:32 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "libmdoc.h"
    +
    +#define LINE(x, y) \
    +	if (0 == strcmp(p, x)) return(y)
    +
    +
    +const char *
    +mdoc_a2att(const char *p)
    +{
    +
    +	LINE("v1",	"Version\\~1 AT&T UNIX");
    +	LINE("v2",	"Version\\~2 AT&T UNIX");
    +	LINE("v3",	"Version\\~3 AT&T UNIX");
    +	LINE("v4",	"Version\\~4 AT&T UNIX");
    +	LINE("v5",	"Version\\~5 AT&T UNIX");
    +	LINE("v6",	"Version\\~6 AT&T UNIX");
    +	LINE("v7",	"Version\\~7 AT&T UNIX");
    +	LINE("32v",	"Version\\~32V AT&T UNIX");
    +	LINE("III",	"AT&T System\\~III UNIX");
    +	LINE("V",	"AT&T System\\~V UNIX");
    +	LINE("V.1",	"AT&T System\\~V Release\\~1 UNIX");
    +	LINE("V.2",	"AT&T System\\~V Release\\~2 UNIX");
    +	LINE("V.3",	"AT&T System\\~V Release\\~3 UNIX");
    +	LINE("V.4",	"AT&T System\\~V Release\\~4 UNIX");
    +
    +	return NULL;
    +}
    
    Property changes on: head/contrib/mandoc/att.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_recallocarray.c
    ===================================================================
    --- head/contrib/mandoc/compat_recallocarray.c	(nonexistent)
    +++ head/contrib/mandoc/compat_recallocarray.c	(revision 338826)
    @@ -0,0 +1,108 @@
    +#include "config.h"
    +
    +#if HAVE_RECALLOCARRAY
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_recallocarray.c,v 1.1 2017/06/12 19:05:47 schwarze Exp $ */
    +/*	$OpenBSD: malloc.c,v 1.225 2017/05/13 07:11:29 otto Exp $ */
    +/*
    + * Copyright (c) 2017 Otto Moerbeek <otto@drijf.net>
    + *
    + * 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 <sys/types.h>
    +#include <errno.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +/*
    + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
    + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
    + */
    +#define MUL_NO_OVERFLOW	((size_t)1 << (sizeof(size_t) * 4))
    +
    +/*
    + * Even though specified in POSIX, the PAGESIZE and PAGE_SIZE
    + * macros have very poor portability.  Since we only use this
    + * to avoid free() overhead for small shrinking, simply pick
    + * an arbitrary number.
    + */
    +#define MALLOC_PAGESIZE         (1UL << 12)
    +
    +
    +void *
    +recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
    +{
    +	size_t oldsize, newsize;
    +	void *newptr;
    +
    +	if (ptr == NULL)
    +		return calloc(newnmemb, size);
    +
    +	if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
    +	    newnmemb > 0 && SIZE_MAX / newnmemb < size) {
    +		errno = ENOMEM;
    +		return NULL;
    +	}
    +	newsize = newnmemb * size;
    +
    +	if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
    +	    oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
    +		errno = EINVAL;
    +		return NULL;
    +	}
    +	oldsize = oldnmemb * size;
    +
    +	/*
    +	 * Don't bother too much if we're shrinking just a bit,
    +	 * we do not shrink for series of small steps, oh well.
    +	 */
    +	if (newsize <= oldsize) {
    +		size_t d = oldsize - newsize;
    +
    +		if (d < oldsize / 2 && d < MALLOC_PAGESIZE) {
    +			memset((char *)ptr + newsize, 0, d);
    +			return ptr;
    +		}
    +	}
    +
    +	newptr = malloc(newsize);
    +	if (newptr == NULL)
    +		return NULL;
    +
    +	if (newsize > oldsize) {
    +		memcpy(newptr, ptr, oldsize);
    +		memset((char *)newptr + oldsize, 0, newsize - oldsize);
    +	} else
    +		memcpy(newptr, ptr, newsize);
    +
    +	/*
    +	 * At this point, the OpenBSD implementation calls
    +	 * explicit_bzero() on the old memory before it is
    +	 * freed.  Since explicit_bzero() is hard to implement
    +	 * portably and we don't handle confidential data in
    +	 * mandoc in the first place, simply free the memory
    +	 * without clearing it.
    +	 */
    +
    +	free(ptr);
    +
    +	return newptr;
    +}
    +
    +#endif /* !HAVE_RECALLOCARRAY */
    
    Property changes on: head/contrib/mandoc/compat_recallocarray.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/demandoc.c
    ===================================================================
    --- head/contrib/mandoc/demandoc.c	(nonexistent)
    +++ head/contrib/mandoc/demandoc.c	(revision 338826)
    @@ -0,0 +1,264 @@
    +/*	$Id: demandoc.c,v 1.29 2017/06/24 14:38:32 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "man.h"
    +#include "mdoc.h"
    +
    +static	void	 pline(int, int *, int *, int);
    +static	void	 pman(const struct roff_node *, int *, int *, int);
    +static	void	 pmandoc(struct mparse *, int, const char *, int);
    +static	void	 pmdoc(const struct roff_node *, int *, int *, int);
    +static	void	 pstring(const char *, int, int *, int);
    +static	void	 usage(void);
    +
    +static	const char	 *progname;
    +
    +int
    +main(int argc, char *argv[])
    +{
    +	struct mparse	*mp;
    +	int		 ch, fd, i, list;
    +	extern int	 optind;
    +
    +	if (argc < 1)
    +		progname = "demandoc";
    +	else if ((progname = strrchr(argv[0], '/')) == NULL)
    +		progname = argv[0];
    +	else
    +		++progname;
    +
    +	mp = NULL;
    +	list = 0;
    +
    +	while (-1 != (ch = getopt(argc, argv, "ikm:pw")))
    +		switch (ch) {
    +		case ('i'):
    +			/* FALLTHROUGH */
    +		case ('k'):
    +			/* FALLTHROUGH */
    +		case ('m'):
    +			/* FALLTHROUGH */
    +		case ('p'):
    +			break;
    +		case ('w'):
    +			list = 1;
    +			break;
    +		default:
    +			usage();
    +			return (int)MANDOCLEVEL_BADARG;
    +		}
    +
    +	argc -= optind;
    +	argv += optind;
    +
    +	mchars_alloc();
    +	mp = mparse_alloc(MPARSE_SO, MANDOCERR_MAX, NULL,
    +	    MANDOC_OS_OTHER, NULL);
    +	assert(mp);
    +
    +	if (argc < 1)
    +		pmandoc(mp, STDIN_FILENO, "<stdin>", list);
    +
    +	for (i = 0; i < argc; i++) {
    +		mparse_reset(mp);
    +		if ((fd = mparse_open(mp, argv[i])) == -1) {
    +			perror(argv[i]);
    +			continue;
    +		}
    +		pmandoc(mp, fd, argv[i], list);
    +	}
    +
    +	mparse_free(mp);
    +	mchars_free();
    +	return (int)MANDOCLEVEL_OK;
    +}
    +
    +static void
    +usage(void)
    +{
    +
    +	fprintf(stderr, "usage: %s [-w] [files...]\n", progname);
    +}
    +
    +static void
    +pmandoc(struct mparse *mp, int fd, const char *fn, int list)
    +{
    +	struct roff_man	*man;
    +	int		 line, col;
    +
    +	mparse_readfd(mp, fd, fn);
    +	close(fd);
    +	mparse_result(mp, &man, NULL);
    +	line = 1;
    +	col = 0;
    +
    +	if (man == NULL)
    +		return;
    +	if (man->macroset == MACROSET_MDOC) {
    +		mdoc_validate(man);
    +		pmdoc(man->first->child, &line, &col, list);
    +	} else {
    +		man_validate(man);
    +		pman(man->first->child, &line, &col, list);
    +	}
    +
    +	if ( ! list)
    +		putchar('\n');
    +}
    +
    +/*
    + * Strip the escapes out of a string, emitting the results.
    + */
    +static void
    +pstring(const char *p, int col, int *colp, int list)
    +{
    +	enum mandoc_esc	 esc;
    +	const char	*start, *end;
    +	int		 emit;
    +
    +	/*
    +	 * Print as many column spaces til we achieve parity with the
    +	 * input document.
    +	 */
    +
    +again:
    +	if (list && '\0' != *p) {
    +		while (isspace((unsigned char)*p))
    +			p++;
    +
    +		while ('\'' == *p || '(' == *p || '"' == *p)
    +			p++;
    +
    +		emit = isalpha((unsigned char)p[0]) &&
    +			isalpha((unsigned char)p[1]);
    +
    +		for (start = p; '\0' != *p; p++)
    +			if ('\\' == *p) {
    +				p++;
    +				esc = mandoc_escape(&p, NULL, NULL);
    +				if (ESCAPE_ERROR == esc)
    +					return;
    +				emit = 0;
    +			} else if (isspace((unsigned char)*p))
    +				break;
    +
    +		end = p - 1;
    +
    +		while (end > start)
    +			if ('.' == *end || ',' == *end ||
    +					'\'' == *end || '"' == *end ||
    +					')' == *end || '!' == *end ||
    +					'?' == *end || ':' == *end ||
    +					';' == *end)
    +				end--;
    +			else
    +				break;
    +
    +		if (emit && end - start >= 1) {
    +			for ( ; start <= end; start++)
    +				if (ASCII_HYPH == *start)
    +					putchar('-');
    +				else
    +					putchar((unsigned char)*start);
    +			putchar('\n');
    +		}
    +
    +		if (isspace((unsigned char)*p))
    +			goto again;
    +
    +		return;
    +	}
    +
    +	while (*colp < col) {
    +		putchar(' ');
    +		(*colp)++;
    +	}
    +
    +	/*
    +	 * Print the input word, skipping any special characters.
    +	 */
    +	while ('\0' != *p)
    +		if ('\\' == *p) {
    +			p++;
    +			esc = mandoc_escape(&p, NULL, NULL);
    +			if (ESCAPE_ERROR == esc)
    +				break;
    +		} else {
    +			putchar((unsigned char )*p++);
    +			(*colp)++;
    +		}
    +}
    +
    +static void
    +pline(int line, int *linep, int *col, int list)
    +{
    +
    +	if (list)
    +		return;
    +
    +	/*
    +	 * Print out as many lines as needed to reach parity with the
    +	 * original input.
    +	 */
    +
    +	while (*linep < line) {
    +		putchar('\n');
    +		(*linep)++;
    +	}
    +
    +	*col = 0;
    +}
    +
    +static void
    +pmdoc(const struct roff_node *p, int *line, int *col, int list)
    +{
    +
    +	for ( ; p; p = p->next) {
    +		if (NODE_LINE & p->flags)
    +			pline(p->line, line, col, list);
    +		if (ROFFT_TEXT == p->type)
    +			pstring(p->string, p->pos, col, list);
    +		if (p->child)
    +			pmdoc(p->child, line, col, list);
    +	}
    +}
    +
    +static void
    +pman(const struct roff_node *p, int *line, int *col, int list)
    +{
    +
    +	for ( ; p; p = p->next) {
    +		if (NODE_LINE & p->flags)
    +			pline(p->line, line, col, list);
    +		if (ROFFT_TEXT == p->type)
    +			pstring(p->string, p->pos, col, list);
    +		if (p->child)
    +			pman(p->child, line, col, list);
    +	}
    +}
    
    Property changes on: head/contrib/mandoc/demandoc.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/eqn.c
    ===================================================================
    --- head/contrib/mandoc/eqn.c	(nonexistent)
    +++ head/contrib/mandoc/eqn.c	(revision 338826)
    @@ -0,0 +1,1103 @@
    +/*	$Id: eqn.c,v 1.78 2017/07/15 16:26:17 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "libmandoc.h"
    +#include "libroff.h"
    +
    +#define	EQN_NEST_MAX	 128 /* maximum nesting of defines */
    +#define	STRNEQ(p1, sz1, p2, sz2) \
    +	((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
    +
    +enum	eqn_tok {
    +	EQN_TOK_DYAD = 0,
    +	EQN_TOK_VEC,
    +	EQN_TOK_UNDER,
    +	EQN_TOK_BAR,
    +	EQN_TOK_TILDE,
    +	EQN_TOK_HAT,
    +	EQN_TOK_DOT,
    +	EQN_TOK_DOTDOT,
    +	EQN_TOK_FWD,
    +	EQN_TOK_BACK,
    +	EQN_TOK_DOWN,
    +	EQN_TOK_UP,
    +	EQN_TOK_FAT,
    +	EQN_TOK_ROMAN,
    +	EQN_TOK_ITALIC,
    +	EQN_TOK_BOLD,
    +	EQN_TOK_SIZE,
    +	EQN_TOK_SUB,
    +	EQN_TOK_SUP,
    +	EQN_TOK_SQRT,
    +	EQN_TOK_OVER,
    +	EQN_TOK_FROM,
    +	EQN_TOK_TO,
    +	EQN_TOK_BRACE_OPEN,
    +	EQN_TOK_BRACE_CLOSE,
    +	EQN_TOK_GSIZE,
    +	EQN_TOK_GFONT,
    +	EQN_TOK_MARK,
    +	EQN_TOK_LINEUP,
    +	EQN_TOK_LEFT,
    +	EQN_TOK_RIGHT,
    +	EQN_TOK_PILE,
    +	EQN_TOK_LPILE,
    +	EQN_TOK_RPILE,
    +	EQN_TOK_CPILE,
    +	EQN_TOK_MATRIX,
    +	EQN_TOK_CCOL,
    +	EQN_TOK_LCOL,
    +	EQN_TOK_RCOL,
    +	EQN_TOK_DELIM,
    +	EQN_TOK_DEFINE,
    +	EQN_TOK_TDEFINE,
    +	EQN_TOK_NDEFINE,
    +	EQN_TOK_UNDEF,
    +	EQN_TOK_ABOVE,
    +	EQN_TOK__MAX,
    +	EQN_TOK_FUNC,
    +	EQN_TOK_QUOTED,
    +	EQN_TOK_SYM,
    +	EQN_TOK_EOF
    +};
    +
    +static	const char *eqn_toks[EQN_TOK__MAX] = {
    +	"dyad", /* EQN_TOK_DYAD */
    +	"vec", /* EQN_TOK_VEC */
    +	"under", /* EQN_TOK_UNDER */
    +	"bar", /* EQN_TOK_BAR */
    +	"tilde", /* EQN_TOK_TILDE */
    +	"hat", /* EQN_TOK_HAT */
    +	"dot", /* EQN_TOK_DOT */
    +	"dotdot", /* EQN_TOK_DOTDOT */
    +	"fwd", /* EQN_TOK_FWD * */
    +	"back", /* EQN_TOK_BACK */
    +	"down", /* EQN_TOK_DOWN */
    +	"up", /* EQN_TOK_UP */
    +	"fat", /* EQN_TOK_FAT */
    +	"roman", /* EQN_TOK_ROMAN */
    +	"italic", /* EQN_TOK_ITALIC */
    +	"bold", /* EQN_TOK_BOLD */
    +	"size", /* EQN_TOK_SIZE */
    +	"sub", /* EQN_TOK_SUB */
    +	"sup", /* EQN_TOK_SUP */
    +	"sqrt", /* EQN_TOK_SQRT */
    +	"over", /* EQN_TOK_OVER */
    +	"from", /* EQN_TOK_FROM */
    +	"to", /* EQN_TOK_TO */
    +	"{", /* EQN_TOK_BRACE_OPEN */
    +	"}", /* EQN_TOK_BRACE_CLOSE */
    +	"gsize", /* EQN_TOK_GSIZE */
    +	"gfont", /* EQN_TOK_GFONT */
    +	"mark", /* EQN_TOK_MARK */
    +	"lineup", /* EQN_TOK_LINEUP */
    +	"left", /* EQN_TOK_LEFT */
    +	"right", /* EQN_TOK_RIGHT */
    +	"pile", /* EQN_TOK_PILE */
    +	"lpile", /* EQN_TOK_LPILE */
    +	"rpile", /* EQN_TOK_RPILE */
    +	"cpile", /* EQN_TOK_CPILE */
    +	"matrix", /* EQN_TOK_MATRIX */
    +	"ccol", /* EQN_TOK_CCOL */
    +	"lcol", /* EQN_TOK_LCOL */
    +	"rcol", /* EQN_TOK_RCOL */
    +	"delim", /* EQN_TOK_DELIM */
    +	"define", /* EQN_TOK_DEFINE */
    +	"tdefine", /* EQN_TOK_TDEFINE */
    +	"ndefine", /* EQN_TOK_NDEFINE */
    +	"undef", /* EQN_TOK_UNDEF */
    +	"above", /* EQN_TOK_ABOVE */
    +};
    +
    +static	const char *const eqn_func[] = {
    +	"acos",	"acsc",	"and",	"arc",	"asec",	"asin", "atan",
    +	"cos",	"cosh", "coth",	"csc",	"det",	"exp",	"for",
    +	"if",	"lim",	"ln",	"log",	"max",	"min",
    +	"sec",	"sin",	"sinh",	"tan",	"tanh",	"Im",	"Re",
    +};
    +
    +enum	eqn_symt {
    +	EQNSYM_alpha = 0,
    +	EQNSYM_beta,
    +	EQNSYM_chi,
    +	EQNSYM_delta,
    +	EQNSYM_epsilon,
    +	EQNSYM_eta,
    +	EQNSYM_gamma,
    +	EQNSYM_iota,
    +	EQNSYM_kappa,
    +	EQNSYM_lambda,
    +	EQNSYM_mu,
    +	EQNSYM_nu,
    +	EQNSYM_omega,
    +	EQNSYM_omicron,
    +	EQNSYM_phi,
    +	EQNSYM_pi,
    +	EQNSYM_ps,
    +	EQNSYM_rho,
    +	EQNSYM_sigma,
    +	EQNSYM_tau,
    +	EQNSYM_theta,
    +	EQNSYM_upsilon,
    +	EQNSYM_xi,
    +	EQNSYM_zeta,
    +	EQNSYM_DELTA,
    +	EQNSYM_GAMMA,
    +	EQNSYM_LAMBDA,
    +	EQNSYM_OMEGA,
    +	EQNSYM_PHI,
    +	EQNSYM_PI,
    +	EQNSYM_PSI,
    +	EQNSYM_SIGMA,
    +	EQNSYM_THETA,
    +	EQNSYM_UPSILON,
    +	EQNSYM_XI,
    +	EQNSYM_inter,
    +	EQNSYM_union,
    +	EQNSYM_prod,
    +	EQNSYM_int,
    +	EQNSYM_sum,
    +	EQNSYM_grad,
    +	EQNSYM_del,
    +	EQNSYM_times,
    +	EQNSYM_cdot,
    +	EQNSYM_nothing,
    +	EQNSYM_approx,
    +	EQNSYM_prime,
    +	EQNSYM_half,
    +	EQNSYM_partial,
    +	EQNSYM_inf,
    +	EQNSYM_muchgreat,
    +	EQNSYM_muchless,
    +	EQNSYM_larrow,
    +	EQNSYM_rarrow,
    +	EQNSYM_pm,
    +	EQNSYM_nequal,
    +	EQNSYM_equiv,
    +	EQNSYM_lessequal,
    +	EQNSYM_moreequal,
    +	EQNSYM_minus,
    +	EQNSYM__MAX
    +};
    +
    +struct	eqnsym {
    +	const char	*str;
    +	const char	*sym;
    +};
    +
    +static	const struct eqnsym eqnsyms[EQNSYM__MAX] = {
    +	{ "alpha", "*a" }, /* EQNSYM_alpha */
    +	{ "beta", "*b" }, /* EQNSYM_beta */
    +	{ "chi", "*x" }, /* EQNSYM_chi */
    +	{ "delta", "*d" }, /* EQNSYM_delta */
    +	{ "epsilon", "*e" }, /* EQNSYM_epsilon */
    +	{ "eta", "*y" }, /* EQNSYM_eta */
    +	{ "gamma", "*g" }, /* EQNSYM_gamma */
    +	{ "iota", "*i" }, /* EQNSYM_iota */
    +	{ "kappa", "*k" }, /* EQNSYM_kappa */
    +	{ "lambda", "*l" }, /* EQNSYM_lambda */
    +	{ "mu", "*m" }, /* EQNSYM_mu */
    +	{ "nu", "*n" }, /* EQNSYM_nu */
    +	{ "omega", "*w" }, /* EQNSYM_omega */
    +	{ "omicron", "*o" }, /* EQNSYM_omicron */
    +	{ "phi", "*f" }, /* EQNSYM_phi */
    +	{ "pi", "*p" }, /* EQNSYM_pi */
    +	{ "psi", "*q" }, /* EQNSYM_psi */
    +	{ "rho", "*r" }, /* EQNSYM_rho */
    +	{ "sigma", "*s" }, /* EQNSYM_sigma */
    +	{ "tau", "*t" }, /* EQNSYM_tau */
    +	{ "theta", "*h" }, /* EQNSYM_theta */
    +	{ "upsilon", "*u" }, /* EQNSYM_upsilon */
    +	{ "xi", "*c" }, /* EQNSYM_xi */
    +	{ "zeta", "*z" }, /* EQNSYM_zeta */
    +	{ "DELTA", "*D" }, /* EQNSYM_DELTA */
    +	{ "GAMMA", "*G" }, /* EQNSYM_GAMMA */
    +	{ "LAMBDA", "*L" }, /* EQNSYM_LAMBDA */
    +	{ "OMEGA", "*W" }, /* EQNSYM_OMEGA */
    +	{ "PHI", "*F" }, /* EQNSYM_PHI */
    +	{ "PI", "*P" }, /* EQNSYM_PI */
    +	{ "PSI", "*Q" }, /* EQNSYM_PSI */
    +	{ "SIGMA", "*S" }, /* EQNSYM_SIGMA */
    +	{ "THETA", "*H" }, /* EQNSYM_THETA */
    +	{ "UPSILON", "*U" }, /* EQNSYM_UPSILON */
    +	{ "XI", "*C" }, /* EQNSYM_XI */
    +	{ "inter", "ca" }, /* EQNSYM_inter */
    +	{ "union", "cu" }, /* EQNSYM_union */
    +	{ "prod", "product" }, /* EQNSYM_prod */
    +	{ "int", "integral" }, /* EQNSYM_int */
    +	{ "sum", "sum" }, /* EQNSYM_sum */
    +	{ "grad", "gr" }, /* EQNSYM_grad */
    +	{ "del", "gr" }, /* EQNSYM_del */
    +	{ "times", "mu" }, /* EQNSYM_times */
    +	{ "cdot", "pc" }, /* EQNSYM_cdot */
    +	{ "nothing", "&" }, /* EQNSYM_nothing */
    +	{ "approx", "~~" }, /* EQNSYM_approx */
    +	{ "prime", "fm" }, /* EQNSYM_prime */
    +	{ "half", "12" }, /* EQNSYM_half */
    +	{ "partial", "pd" }, /* EQNSYM_partial */
    +	{ "inf", "if" }, /* EQNSYM_inf */
    +	{ ">>", ">>" }, /* EQNSYM_muchgreat */
    +	{ "<<", "<<" }, /* EQNSYM_muchless */
    +	{ "<-", "<-" }, /* EQNSYM_larrow */
    +	{ "->", "->" }, /* EQNSYM_rarrow */
    +	{ "+-", "+-" }, /* EQNSYM_pm */
    +	{ "!=", "!=" }, /* EQNSYM_nequal */
    +	{ "==", "==" }, /* EQNSYM_equiv */
    +	{ "<=", "<=" }, /* EQNSYM_lessequal */
    +	{ ">=", ">=" }, /* EQNSYM_moreequal */
    +	{ "-", "mi" }, /* EQNSYM_minus */
    +};
    +
    +enum	parse_mode {
    +	MODE_QUOTED,
    +	MODE_NOSUB,
    +	MODE_SUB,
    +	MODE_TOK
    +};
    +
    +static	struct eqn_box	*eqn_box_alloc(struct eqn_node *, struct eqn_box *);
    +static	struct eqn_box	*eqn_box_makebinary(struct eqn_node *,
    +				struct eqn_box *);
    +static	void		 eqn_def(struct eqn_node *);
    +static	struct eqn_def	*eqn_def_find(struct eqn_node *);
    +static	void		 eqn_delim(struct eqn_node *);
    +static	enum eqn_tok	 eqn_next(struct eqn_node *, enum parse_mode);
    +static	void		 eqn_undef(struct eqn_node *);
    +
    +
    +struct eqn_node *
    +eqn_alloc(struct mparse *parse)
    +{
    +	struct eqn_node *ep;
    +
    +	ep = mandoc_calloc(1, sizeof(*ep));
    +	ep->parse = parse;
    +	ep->gsize = EQN_DEFSIZE;
    +	return ep;
    +}
    +
    +void
    +eqn_reset(struct eqn_node *ep)
    +{
    +	free(ep->data);
    +	ep->data = ep->start = ep->end = NULL;
    +	ep->sz = ep->toksz = 0;
    +}
    +
    +void
    +eqn_read(struct eqn_node *ep, const char *p)
    +{
    +	char		*cp;
    +
    +	if (ep->data == NULL) {
    +		ep->sz = strlen(p);
    +		ep->data = mandoc_strdup(p);
    +	} else {
    +		ep->sz = mandoc_asprintf(&cp, "%s %s", ep->data, p);
    +		free(ep->data);
    +		ep->data = cp;
    +	}
    +	ep->sz += 1;
    +}
    +
    +/*
    + * Find the key "key" of the give size within our eqn-defined values.
    + */
    +static struct eqn_def *
    +eqn_def_find(struct eqn_node *ep)
    +{
    +	int		 i;
    +
    +	for (i = 0; i < (int)ep->defsz; i++)
    +		if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
    +		    ep->defs[i].keysz, ep->start, ep->toksz))
    +			return &ep->defs[i];
    +
    +	return NULL;
    +}
    +
    +/*
    + * Parse a token from the input text.  The modes are:
    + * MODE_QUOTED: Use *ep->start as the delimiter; the token ends
    + *   before its next occurence.  Do not interpret the token in any
    + *   way and return EQN_TOK_QUOTED.  All other modes behave like
    + *   MODE_QUOTED when *ep->start is '"'.
    + * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it;
    + *   otherwise, it ends before the next whitespace or brace.
    + *   Do not interpret the token and return EQN_TOK__MAX.
    + * MODE_SUB: Like MODE_NOSUB, but try to interpret the token as an
    + *   alias created with define.  If it is an alias, replace it with
    + *   its string value and reparse.
    + * MODE_TOK: Like MODE_SUB, but also check the token against the list
    + *   of tokens, and if there is a match, return that token.  Otherwise,
    + *   if the token matches a symbol, return EQN_TOK_SYM; if it matches
    + *   a function name, EQN_TOK_FUNC, or else EQN_TOK__MAX.  Except for
    + *   a token match, *ep->start is set to an allocated string that the
    + *   caller is expected to free.
    + * All modes skip whitespace following the end of the token.
    + */
    +static enum eqn_tok
    +eqn_next(struct eqn_node *ep, enum parse_mode mode)
    +{
    +	static int	 last_len, lim;
    +
    +	struct eqn_def	*def;
    +	size_t		 start;
    +	int		 diff, i, quoted;
    +	enum eqn_tok	 tok;
    +
    +	/*
    +	 * Reset the recursion counter after advancing
    +	 * beyond the end of the previous substitution.
    +	 */
    +	if (ep->end - ep->data >= last_len)
    +		lim = 0;
    +
    +	ep->start = ep->end;
    +	quoted = mode == MODE_QUOTED;
    +	for (;;) {
    +		switch (*ep->start) {
    +		case '\0':
    +			ep->toksz = 0;
    +			return EQN_TOK_EOF;
    +		case '"':
    +			quoted = 1;
    +			break;
    +		default:
    +			break;
    +		}
    +		if (quoted) {
    +			ep->end = strchr(ep->start + 1, *ep->start);
    +			ep->start++;  /* Skip opening quote. */
    +			if (ep->end == NULL) {
    +				mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
    +				    ep->node->line, ep->node->pos, NULL);
    +				ep->end = strchr(ep->start, '\0');
    +			}
    +		} else {
    +			ep->end = ep->start + 1;
    +			if (*ep->start != '{' && *ep->start != '}')
    +				ep->end += strcspn(ep->end, " ^~\"{}\t");
    +		}
    +		ep->toksz = ep->end - ep->start;
    +		if (quoted && *ep->end != '\0')
    +			ep->end++;  /* Skip closing quote. */
    +		while (*ep->end != '\0' && strchr(" \t^~", *ep->end) != NULL)
    +			ep->end++;
    +		if (quoted)  /* Cannot return, may have to strndup. */
    +			break;
    +		if (mode == MODE_NOSUB)
    +			return EQN_TOK__MAX;
    +		if ((def = eqn_def_find(ep)) == NULL)
    +			break;
    +		if (++lim > EQN_NEST_MAX) {
    +			mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
    +			    ep->node->line, ep->node->pos, NULL);
    +			return EQN_TOK_EOF;
    +		}
    +
    +		/* Replace a defined name with its string value. */
    +		if ((diff = def->valsz - ep->toksz) > 0) {
    +			start = ep->start - ep->data;
    +			ep->sz += diff;
    +			ep->data = mandoc_realloc(ep->data, ep->sz + 1);
    +			ep->start = ep->data + start;
    +		}
    +		if (diff)
    +			memmove(ep->start + def->valsz, ep->start + ep->toksz,
    +			    strlen(ep->start + ep->toksz) + 1);
    +		memcpy(ep->start, def->val, def->valsz);
    +		last_len = ep->start - ep->data + def->valsz;
    +	}
    +	if (mode != MODE_TOK)
    +		return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX;
    +	if (quoted) {
    +		ep->start = mandoc_strndup(ep->start, ep->toksz);
    +		return EQN_TOK_QUOTED;
    +	}
    +	for (tok = 0; tok < EQN_TOK__MAX; tok++)
    +		if (STRNEQ(ep->start, ep->toksz,
    +		    eqn_toks[tok], strlen(eqn_toks[tok])))
    +			return tok;
    +
    +	for (i = 0; i < EQNSYM__MAX; i++) {
    +		if (STRNEQ(ep->start, ep->toksz,
    +		    eqnsyms[i].str, strlen(eqnsyms[i].str))) {
    +			mandoc_asprintf(&ep->start,
    +			    "\\[%s]", eqnsyms[i].sym);
    +			return EQN_TOK_SYM;
    +		}
    +	}
    +	ep->start = mandoc_strndup(ep->start, ep->toksz);
    +	for (i = 0; i < (int)(sizeof(eqn_func)/sizeof(*eqn_func)); i++)
    +		if (STRNEQ(ep->start, ep->toksz,
    +		    eqn_func[i], strlen(eqn_func[i])))
    +			return EQN_TOK_FUNC;
    +	return EQN_TOK__MAX;
    +}
    +
    +void
    +eqn_box_free(struct eqn_box *bp)
    +{
    +
    +	if (bp->first)
    +		eqn_box_free(bp->first);
    +	if (bp->next)
    +		eqn_box_free(bp->next);
    +
    +	free(bp->text);
    +	free(bp->left);
    +	free(bp->right);
    +	free(bp->top);
    +	free(bp->bottom);
    +	free(bp);
    +}
    +
    +/*
    + * Allocate a box as the last child of the parent node.
    + */
    +static struct eqn_box *
    +eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
    +{
    +	struct eqn_box	*bp;
    +
    +	bp = mandoc_calloc(1, sizeof(struct eqn_box));
    +	bp->parent = parent;
    +	bp->parent->args++;
    +	bp->expectargs = UINT_MAX;
    +	bp->font = bp->parent->font;
    +	bp->size = ep->gsize;
    +
    +	if (NULL != parent->first) {
    +		parent->last->next = bp;
    +		bp->prev = parent->last;
    +	} else
    +		parent->first = bp;
    +
    +	parent->last = bp;
    +	return bp;
    +}
    +
    +/*
    + * Reparent the current last node (of the current parent) under a new
    + * EQN_SUBEXPR as the first element.
    + * Then return the new parent.
    + * The new EQN_SUBEXPR will have a two-child limit.
    + */
    +static struct eqn_box *
    +eqn_box_makebinary(struct eqn_node *ep, struct eqn_box *parent)
    +{
    +	struct eqn_box	*b, *newb;
    +
    +	assert(NULL != parent->last);
    +	b = parent->last;
    +	if (parent->last == parent->first)
    +		parent->first = NULL;
    +	parent->args--;
    +	parent->last = b->prev;
    +	b->prev = NULL;
    +	newb = eqn_box_alloc(ep, parent);
    +	newb->type = EQN_SUBEXPR;
    +	newb->expectargs = 2;
    +	newb->args = 1;
    +	newb->first = newb->last = b;
    +	newb->first->next = NULL;
    +	b->parent = newb;
    +	return newb;
    +}
    +
    +/*
    + * Parse the "delim" control statement.
    + */
    +static void
    +eqn_delim(struct eqn_node *ep)
    +{
    +	if (ep->end[0] == '\0' || ep->end[1] == '\0') {
    +		mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
    +		    ep->node->line, ep->node->pos, "delim");
    +		if (ep->end[0] != '\0')
    +			ep->end++;
    +	} else if (strncmp(ep->end, "off", 3) == 0) {
    +		ep->delim = 0;
    +		ep->end += 3;
    +	} else if (strncmp(ep->end, "on", 2) == 0) {
    +		if (ep->odelim && ep->cdelim)
    +			ep->delim = 1;
    +		ep->end += 2;
    +	} else {
    +		ep->odelim = *ep->end++;
    +		ep->cdelim = *ep->end++;
    +		ep->delim = 1;
    +	}
    +}
    +
    +/*
    + * Undefine a previously-defined string.
    + */
    +static void
    +eqn_undef(struct eqn_node *ep)
    +{
    +	struct eqn_def	*def;
    +
    +	if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
    +		mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
    +		    ep->node->line, ep->node->pos, "undef");
    +		return;
    +	}
    +	if ((def = eqn_def_find(ep)) == NULL)
    +		return;
    +	free(def->key);
    +	free(def->val);
    +	def->key = def->val = NULL;
    +	def->keysz = def->valsz = 0;
    +}
    +
    +static void
    +eqn_def(struct eqn_node *ep)
    +{
    +	struct eqn_def	*def;
    +	int		 i;
    +
    +	if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
    +		mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
    +		    ep->node->line, ep->node->pos, "define");
    +		return;
    +	}
    +
    +	/*
    +	 * Search for a key that already exists.
    +	 * Create a new key if none is found.
    +	 */
    +	if ((def = eqn_def_find(ep)) == NULL) {
    +		/* Find holes in string array. */
    +		for (i = 0; i < (int)ep->defsz; i++)
    +			if (0 == ep->defs[i].keysz)
    +				break;
    +
    +		if (i == (int)ep->defsz) {
    +			ep->defsz++;
    +			ep->defs = mandoc_reallocarray(ep->defs,
    +			    ep->defsz, sizeof(struct eqn_def));
    +			ep->defs[i].key = ep->defs[i].val = NULL;
    +		}
    +
    +		def = ep->defs + i;
    +		free(def->key);
    +		def->key = mandoc_strndup(ep->start, ep->toksz);
    +		def->keysz = ep->toksz;
    +	}
    +
    +	if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
    +		mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
    +		    ep->node->line, ep->node->pos, "define %s", def->key);
    +		free(def->key);
    +		free(def->val);
    +		def->key = def->val = NULL;
    +		def->keysz = def->valsz = 0;
    +		return;
    +	}
    +	free(def->val);
    +	def->val = mandoc_strndup(ep->start, ep->toksz);
    +	def->valsz = ep->toksz;
    +}
    +
    +void
    +eqn_parse(struct eqn_node *ep)
    +{
    +	struct eqn_box	*cur, *nbox, *parent, *split;
    +	const char	*cp, *cpn;
    +	char		*p;
    +	enum eqn_tok	 tok;
    +	enum { CCL_LET, CCL_DIG, CCL_PUN } ccl, ccln;
    +	int		 size;
    +
    +	parent = ep->node->eqn;
    +	assert(parent != NULL);
    +
    +	/*
    +	 * Empty equation.
    +	 * Do not add it to the high-level syntax tree.
    +	 */
    +
    +	if (ep->data == NULL)
    +		return;
    +
    +	ep->start = ep->end = ep->data + strspn(ep->data, " ^~");
    +
    +next_tok:
    +	tok = eqn_next(ep, MODE_TOK);
    +	switch (tok) {
    +	case EQN_TOK_UNDEF:
    +		eqn_undef(ep);
    +		break;
    +	case EQN_TOK_NDEFINE:
    +	case EQN_TOK_DEFINE:
    +		eqn_def(ep);
    +		break;
    +	case EQN_TOK_TDEFINE:
    +		if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
    +		    eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)
    +			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
    +			    ep->node->line, ep->node->pos, "tdefine");
    +		break;
    +	case EQN_TOK_DELIM:
    +		eqn_delim(ep);
    +		break;
    +	case EQN_TOK_GFONT:
    +		if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
    +			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +		break;
    +	case EQN_TOK_MARK:
    +	case EQN_TOK_LINEUP:
    +		/* Ignore these. */
    +		break;
    +	case EQN_TOK_DYAD:
    +	case EQN_TOK_VEC:
    +	case EQN_TOK_UNDER:
    +	case EQN_TOK_BAR:
    +	case EQN_TOK_TILDE:
    +	case EQN_TOK_HAT:
    +	case EQN_TOK_DOT:
    +	case EQN_TOK_DOTDOT:
    +		if (parent->last == NULL) {
    +			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +			cur = eqn_box_alloc(ep, parent);
    +			cur->type = EQN_TEXT;
    +			cur->text = mandoc_strdup("");
    +		}
    +		parent = eqn_box_makebinary(ep, parent);
    +		parent->type = EQN_LIST;
    +		parent->expectargs = 1;
    +		parent->font = EQNFONT_ROMAN;
    +		switch (tok) {
    +		case EQN_TOK_DOTDOT:
    +			parent->top = mandoc_strdup("\\[ad]");
    +			break;
    +		case EQN_TOK_VEC:
    +			parent->top = mandoc_strdup("\\[->]");
    +			break;
    +		case EQN_TOK_DYAD:
    +			parent->top = mandoc_strdup("\\[<>]");
    +			break;
    +		case EQN_TOK_TILDE:
    +			parent->top = mandoc_strdup("\\[a~]");
    +			break;
    +		case EQN_TOK_UNDER:
    +			parent->bottom = mandoc_strdup("\\[ul]");
    +			break;
    +		case EQN_TOK_BAR:
    +			parent->top = mandoc_strdup("\\[rn]");
    +			break;
    +		case EQN_TOK_DOT:
    +			parent->top = mandoc_strdup("\\[a.]");
    +			break;
    +		case EQN_TOK_HAT:
    +			parent->top = mandoc_strdup("\\[ha]");
    +			break;
    +		default:
    +			abort();
    +		}
    +		parent = parent->parent;
    +		break;
    +	case EQN_TOK_FWD:
    +	case EQN_TOK_BACK:
    +	case EQN_TOK_DOWN:
    +	case EQN_TOK_UP:
    +		if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
    +			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +		break;
    +	case EQN_TOK_FAT:
    +	case EQN_TOK_ROMAN:
    +	case EQN_TOK_ITALIC:
    +	case EQN_TOK_BOLD:
    +		while (parent->args == parent->expectargs)
    +			parent = parent->parent;
    +		/*
    +		 * These values apply to the next word or sequence of
    +		 * words; thus, we mark that we'll have a child with
    +		 * exactly one of those.
    +		 */
    +		parent = eqn_box_alloc(ep, parent);
    +		parent->type = EQN_LIST;
    +		parent->expectargs = 1;
    +		switch (tok) {
    +		case EQN_TOK_FAT:
    +			parent->font = EQNFONT_FAT;
    +			break;
    +		case EQN_TOK_ROMAN:
    +			parent->font = EQNFONT_ROMAN;
    +			break;
    +		case EQN_TOK_ITALIC:
    +			parent->font = EQNFONT_ITALIC;
    +			break;
    +		case EQN_TOK_BOLD:
    +			parent->font = EQNFONT_BOLD;
    +			break;
    +		default:
    +			abort();
    +		}
    +		break;
    +	case EQN_TOK_SIZE:
    +	case EQN_TOK_GSIZE:
    +		/* Accept two values: integral size and a single. */
    +		if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
    +			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +			break;
    +		}
    +		size = mandoc_strntoi(ep->start, ep->toksz, 10);
    +		if (-1 == size) {
    +			mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +			break;
    +		}
    +		if (EQN_TOK_GSIZE == tok) {
    +			ep->gsize = size;
    +			break;
    +		}
    +		while (parent->args == parent->expectargs)
    +			parent = parent->parent;
    +		parent = eqn_box_alloc(ep, parent);
    +		parent->type = EQN_LIST;
    +		parent->expectargs = 1;
    +		parent->size = size;
    +		break;
    +	case EQN_TOK_FROM:
    +	case EQN_TOK_TO:
    +	case EQN_TOK_SUB:
    +	case EQN_TOK_SUP:
    +		/*
    +		 * We have a left-right-associative expression.
    +		 * Repivot under a positional node, open a child scope
    +		 * and keep on reading.
    +		 */
    +		if (parent->last == NULL) {
    +			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +			cur = eqn_box_alloc(ep, parent);
    +			cur->type = EQN_TEXT;
    +			cur->text = mandoc_strdup("");
    +		}
    +		while (parent->expectargs == 1 && parent->args == 1)
    +			parent = parent->parent;
    +		if (tok == EQN_TOK_FROM || tok == EQN_TOK_TO)  {
    +			for (cur = parent; cur != NULL; cur = cur->parent)
    +				if (cur->pos == EQNPOS_SUB ||
    +				    cur->pos == EQNPOS_SUP ||
    +				    cur->pos == EQNPOS_SUBSUP ||
    +				    cur->pos == EQNPOS_SQRT ||
    +				    cur->pos == EQNPOS_OVER)
    +					break;
    +			if (cur != NULL)
    +				parent = cur->parent;
    +		}
    +		if (tok == EQN_TOK_SUP && parent->pos == EQNPOS_SUB) {
    +			parent->expectargs = 3;
    +			parent->pos = EQNPOS_SUBSUP;
    +			break;
    +		}
    +		if (tok == EQN_TOK_TO && parent->pos == EQNPOS_FROM) {
    +			parent->expectargs = 3;
    +			parent->pos = EQNPOS_FROMTO;
    +			break;
    +		}
    +		parent = eqn_box_makebinary(ep, parent);
    +		switch (tok) {
    +		case EQN_TOK_FROM:
    +			parent->pos = EQNPOS_FROM;
    +			break;
    +		case EQN_TOK_TO:
    +			parent->pos = EQNPOS_TO;
    +			break;
    +		case EQN_TOK_SUP:
    +			parent->pos = EQNPOS_SUP;
    +			break;
    +		case EQN_TOK_SUB:
    +			parent->pos = EQNPOS_SUB;
    +			break;
    +		default:
    +			abort();
    +		}
    +		break;
    +	case EQN_TOK_SQRT:
    +		while (parent->args == parent->expectargs)
    +			parent = parent->parent;
    +		/*
    +		 * Accept a left-right-associative set of arguments just
    +		 * like sub and sup and friends but without rebalancing
    +		 * under a pivot.
    +		 */
    +		parent = eqn_box_alloc(ep, parent);
    +		parent->type = EQN_SUBEXPR;
    +		parent->pos = EQNPOS_SQRT;
    +		parent->expectargs = 1;
    +		break;
    +	case EQN_TOK_OVER:
    +		/*
    +		 * We have a right-left-associative fraction.
    +		 * Close out anything that's currently open, then
    +		 * rebalance and continue reading.
    +		 */
    +		if (parent->last == NULL) {
    +			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +			cur = eqn_box_alloc(ep, parent);
    +			cur->type = EQN_TEXT;
    +			cur->text = mandoc_strdup("");
    +		}
    +		while (parent->args == parent->expectargs)
    +			parent = parent->parent;
    +		while (EQN_SUBEXPR == parent->type)
    +			parent = parent->parent;
    +		parent = eqn_box_makebinary(ep, parent);
    +		parent->pos = EQNPOS_OVER;
    +		break;
    +	case EQN_TOK_RIGHT:
    +	case EQN_TOK_BRACE_CLOSE:
    +		/*
    +		 * Close out the existing brace.
    +		 * FIXME: this is a shitty sentinel: we should really
    +		 * have a native EQN_BRACE type or whatnot.
    +		 */
    +		for (cur = parent; cur != NULL; cur = cur->parent)
    +			if (cur->type == EQN_LIST &&
    +			    cur->expectargs > 1 &&
    +			    (tok == EQN_TOK_BRACE_CLOSE ||
    +			     cur->left != NULL))
    +				break;
    +		if (cur == NULL) {
    +			mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +			break;
    +		}
    +		parent = cur;
    +		if (EQN_TOK_RIGHT == tok) {
    +			if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
    +				mandoc_msg(MANDOCERR_REQ_EMPTY,
    +				    ep->parse, ep->node->line,
    +				    ep->node->pos, eqn_toks[tok]);
    +				break;
    +			}
    +			/* Handling depends on right/left. */
    +			if (STRNEQ(ep->start, ep->toksz, "ceiling", 7))
    +				parent->right = mandoc_strdup("\\[rc]");
    +			else if (STRNEQ(ep->start, ep->toksz, "floor", 5))
    +				parent->right = mandoc_strdup("\\[rf]");
    +			else
    +				parent->right =
    +				    mandoc_strndup(ep->start, ep->toksz);
    +		}
    +		parent = parent->parent;
    +		if (tok == EQN_TOK_BRACE_CLOSE &&
    +		    (parent->type == EQN_PILE ||
    +		     parent->type == EQN_MATRIX))
    +			parent = parent->parent;
    +		/* Close out any "singleton" lists. */
    +		while (parent->type == EQN_LIST &&
    +		    parent->expectargs == 1 &&
    +		    parent->args == 1)
    +			parent = parent->parent;
    +		break;
    +	case EQN_TOK_BRACE_OPEN:
    +	case EQN_TOK_LEFT:
    +		/*
    +		 * If we already have something in the stack and we're
    +		 * in an expression, then rewind til we're not any more
    +		 * (just like with the text node).
    +		 */
    +		while (parent->args == parent->expectargs)
    +			parent = parent->parent;
    +		if (EQN_TOK_LEFT == tok &&
    +		    eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
    +			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +			break;
    +		}
    +		parent = eqn_box_alloc(ep, parent);
    +		parent->type = EQN_LIST;
    +		if (EQN_TOK_LEFT == tok) {
    +			if (STRNEQ(ep->start, ep->toksz, "ceiling", 7))
    +				parent->left = mandoc_strdup("\\[lc]");
    +			else if (STRNEQ(ep->start, ep->toksz, "floor", 5))
    +				parent->left = mandoc_strdup("\\[lf]");
    +			else
    +				parent->left =
    +				    mandoc_strndup(ep->start, ep->toksz);
    +		}
    +		break;
    +	case EQN_TOK_PILE:
    +	case EQN_TOK_LPILE:
    +	case EQN_TOK_RPILE:
    +	case EQN_TOK_CPILE:
    +	case EQN_TOK_CCOL:
    +	case EQN_TOK_LCOL:
    +	case EQN_TOK_RCOL:
    +		while (parent->args == parent->expectargs)
    +			parent = parent->parent;
    +		parent = eqn_box_alloc(ep, parent);
    +		parent->type = EQN_PILE;
    +		parent->expectargs = 1;
    +		break;
    +	case EQN_TOK_ABOVE:
    +		for (cur = parent; cur != NULL; cur = cur->parent)
    +			if (cur->type == EQN_PILE)
    +				break;
    +		if (cur == NULL) {
    +			mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
    +			    ep->node->line, ep->node->pos, eqn_toks[tok]);
    +			break;
    +		}
    +		parent = eqn_box_alloc(ep, cur);
    +		parent->type = EQN_LIST;
    +		break;
    +	case EQN_TOK_MATRIX:
    +		while (parent->args == parent->expectargs)
    +			parent = parent->parent;
    +		parent = eqn_box_alloc(ep, parent);
    +		parent->type = EQN_MATRIX;
    +		parent->expectargs = 1;
    +		break;
    +	case EQN_TOK_EOF:
    +		return;
    +	case EQN_TOK__MAX:
    +	case EQN_TOK_FUNC:
    +	case EQN_TOK_QUOTED:
    +	case EQN_TOK_SYM:
    +		p = ep->start;
    +		assert(p != NULL);
    +		/*
    +		 * If we already have something in the stack and we're
    +		 * in an expression, then rewind til we're not any more.
    +		 */
    +		while (parent->args == parent->expectargs)
    +			parent = parent->parent;
    +		cur = eqn_box_alloc(ep, parent);
    +		cur->type = EQN_TEXT;
    +		cur->text = p;
    +		switch (tok) {
    +		case EQN_TOK_FUNC:
    +			cur->font = EQNFONT_ROMAN;
    +			break;
    +		case EQN_TOK_QUOTED:
    +			if (cur->font == EQNFONT_NONE)
    +				cur->font = EQNFONT_ITALIC;
    +			break;
    +		case EQN_TOK_SYM:
    +			break;
    +		default:
    +			if (cur->font != EQNFONT_NONE || *p == '\0')
    +				break;
    +			cpn = p - 1;
    +			ccln = CCL_LET;
    +			split = NULL;
    +			for (;;) {
    +				/* Advance to next character. */
    +				cp = cpn++;
    +				ccl = ccln;
    +				ccln = isalpha((unsigned char)*cpn) ? CCL_LET :
    +				    isdigit((unsigned char)*cpn) ||
    +				    (*cpn == '.' && (ccl == CCL_DIG ||
    +				     isdigit((unsigned char)cpn[1]))) ?
    +				    CCL_DIG : CCL_PUN;
    +				/* No boundary before first character. */
    +				if (cp < p)
    +					continue;
    +				cur->font = ccl == CCL_LET ?
    +				    EQNFONT_ITALIC : EQNFONT_ROMAN;
    +				if (*cp == '\\')
    +					mandoc_escape(&cpn, NULL, NULL);
    +				/* No boundary after last character. */
    +				if (*cpn == '\0')
    +					break;
    +				if (ccln == ccl && *cp != ',' && *cpn != ',')
    +					continue;
    +				/* Boundary found, split the text. */
    +				if (parent->args == parent->expectargs) {
    +					/* Remove the text from the tree. */
    +					if (cur->prev == NULL)
    +						parent->first = cur->next;
    +					else
    +						cur->prev->next = NULL;
    +					parent->last = cur->prev;
    +					parent->args--;
    +					/* Set up a list instead. */
    +					split = eqn_box_alloc(ep, parent);
    +					split->type = EQN_LIST;
    +					/* Insert the word into the list. */
    +					split->first = split->last = cur;
    +					cur->parent = split;
    +					cur->prev = NULL;
    +					parent = split;
    +				}
    +				/* Append a new text box. */
    +				nbox = eqn_box_alloc(ep, parent);
    +				nbox->type = EQN_TEXT;
    +				nbox->text = mandoc_strdup(cpn);
    +				/* Truncate the old box. */
    +				p = mandoc_strndup(cur->text,
    +				    cpn - cur->text);
    +				free(cur->text);
    +				cur->text = p;
    +				/* Setup to process the new box. */
    +				cur = nbox;
    +				p = nbox->text;
    +				cpn = p - 1;
    +				ccln = CCL_LET;
    +			}
    +			if (split != NULL)
    +				parent = split->parent;
    +			break;
    +		}
    +		break;
    +	default:
    +		abort();
    +	}
    +	goto next_tok;
    +}
    +
    +void
    +eqn_free(struct eqn_node *p)
    +{
    +	int		 i;
    +
    +	for (i = 0; i < (int)p->defsz; i++) {
    +		free(p->defs[i].key);
    +		free(p->defs[i].val);
    +	}
    +
    +	free(p->data);
    +	free(p->defs);
    +	free(p);
    +}
    
    Property changes on: head/contrib/mandoc/eqn.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/eqn_html.c
    ===================================================================
    --- head/contrib/mandoc/eqn_html.c	(nonexistent)
    +++ head/contrib/mandoc/eqn_html.c	(revision 338826)
    @@ -0,0 +1,244 @@
    +/*	$Id: eqn_html.c,v 1.17 2017/07/14 13:32:35 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "out.h"
    +#include "html.h"
    +
    +static void
    +eqn_box(struct html *p, const struct eqn_box *bp)
    +{
    +	struct tag	*post, *row, *cell, *t;
    +	const struct eqn_box *child, *parent;
    +	const char	*cp;
    +	size_t		 i, j, rows;
    +	enum htmltag	 tag;
    +	enum eqn_fontt	 font;
    +
    +	if (NULL == bp)
    +		return;
    +
    +	post = NULL;
    +
    +	/*
    +	 * Special handling for a matrix, which is presented to us in
    +	 * column order, but must be printed in row-order.
    +	 */
    +	if (EQN_MATRIX == bp->type) {
    +		if (NULL == bp->first)
    +			goto out;
    +		if (bp->first->type != EQN_LIST ||
    +		    bp->first->expectargs == 1) {
    +			eqn_box(p, bp->first);
    +			goto out;
    +		}
    +		if (NULL == (parent = bp->first->first))
    +			goto out;
    +		/* Estimate the number of rows, first. */
    +		if (NULL == (child = parent->first))
    +			goto out;
    +		for (rows = 0; NULL != child; rows++)
    +			child = child->next;
    +		/* Print row-by-row. */
    +		post = print_otag(p, TAG_MTABLE, "");
    +		for (i = 0; i < rows; i++) {
    +			parent = bp->first->first;
    +			row = print_otag(p, TAG_MTR, "");
    +			while (NULL != parent) {
    +				child = parent->first;
    +				for (j = 0; j < i; j++) {
    +					if (NULL == child)
    +						break;
    +					child = child->next;
    +				}
    +				cell = print_otag(p, TAG_MTD, "");
    +				/*
    +				 * If we have no data for this
    +				 * particular cell, then print a
    +				 * placeholder and continue--don't puke.
    +				 */
    +				if (NULL != child)
    +					eqn_box(p, child->first);
    +				print_tagq(p, cell);
    +				parent = parent->next;
    +			}
    +			print_tagq(p, row);
    +		}
    +		goto out;
    +	}
    +
    +	switch (bp->pos) {
    +	case EQNPOS_TO:
    +		post = print_otag(p, TAG_MOVER, "");
    +		break;
    +	case EQNPOS_SUP:
    +		post = print_otag(p, TAG_MSUP, "");
    +		break;
    +	case EQNPOS_FROM:
    +		post = print_otag(p, TAG_MUNDER, "");
    +		break;
    +	case EQNPOS_SUB:
    +		post = print_otag(p, TAG_MSUB, "");
    +		break;
    +	case EQNPOS_OVER:
    +		post = print_otag(p, TAG_MFRAC, "");
    +		break;
    +	case EQNPOS_FROMTO:
    +		post = print_otag(p, TAG_MUNDEROVER, "");
    +		break;
    +	case EQNPOS_SUBSUP:
    +		post = print_otag(p, TAG_MSUBSUP, "");
    +		break;
    +	case EQNPOS_SQRT:
    +		post = print_otag(p, TAG_MSQRT, "");
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	if (bp->top || bp->bottom) {
    +		assert(NULL == post);
    +		if (bp->top && NULL == bp->bottom)
    +			post = print_otag(p, TAG_MOVER, "");
    +		else if (bp->top && bp->bottom)
    +			post = print_otag(p, TAG_MUNDEROVER, "");
    +		else if (bp->bottom)
    +			post = print_otag(p, TAG_MUNDER, "");
    +	}
    +
    +	if (EQN_PILE == bp->type) {
    +		assert(NULL == post);
    +		if (bp->first != NULL &&
    +		    bp->first->type == EQN_LIST &&
    +		    bp->first->expectargs > 1)
    +			post = print_otag(p, TAG_MTABLE, "");
    +	} else if (bp->type == EQN_LIST && bp->expectargs > 1 &&
    +	    bp->parent && bp->parent->type == EQN_PILE) {
    +		assert(NULL == post);
    +		post = print_otag(p, TAG_MTR, "");
    +		print_otag(p, TAG_MTD, "");
    +	}
    +
    +	if (bp->text != NULL) {
    +		assert(post == NULL);
    +		tag = TAG_MI;
    +		cp = bp->text;
    +		if (isdigit((unsigned char)cp[0]) ||
    +		    (cp[0] == '.' && isdigit((unsigned char)cp[1]))) {
    +			tag = TAG_MN;
    +			while (*++cp != '\0') {
    +				if (*cp != '.' &&
    +				    isdigit((unsigned char)*cp) == 0) {
    +					tag = TAG_MI;
    +					break;
    +				}
    +			}
    +		} else if (*cp != '\0' && isalpha((unsigned char)*cp) == 0) {
    +			tag = TAG_MO;
    +			while (*cp != '\0') {
    +				if (cp[0] == '\\' && cp[1] != '\0') {
    +					cp++;
    +					mandoc_escape(&cp, NULL, NULL);
    +				} else if (isalnum((unsigned char)*cp)) {
    +					tag = TAG_MI;
    +					break;
    +				} else
    +					cp++;
    +			}
    +		}
    +		font = bp->font;
    +		if (bp->text[0] != '\0' &&
    +		    (((tag == TAG_MN || tag == TAG_MO) &&
    +		      font == EQNFONT_ROMAN) ||
    +		     (tag == TAG_MI && font == (bp->text[1] == '\0' ?
    +		      EQNFONT_ITALIC : EQNFONT_ROMAN))))
    +			font = EQNFONT_NONE;
    +		switch (font) {
    +		case EQNFONT_NONE:
    +			post = print_otag(p, tag, "");
    +			break;
    +		case EQNFONT_ROMAN:
    +			post = print_otag(p, tag, "?", "fontstyle", "normal");
    +			break;
    +		case EQNFONT_BOLD:
    +		case EQNFONT_FAT:
    +			post = print_otag(p, tag, "?", "fontweight", "bold");
    +			break;
    +		case EQNFONT_ITALIC:
    +			post = print_otag(p, tag, "?", "fontstyle", "italic");
    +			break;
    +		default:
    +			abort();
    +		}
    +		print_text(p, bp->text);
    +	} else if (NULL == post) {
    +		if (NULL != bp->left || NULL != bp->right)
    +			post = print_otag(p, TAG_MFENCED, "??",
    +			    "open", bp->left == NULL ? "" : bp->left,
    +			    "close", bp->right == NULL ? "" : bp->right);
    +		if (NULL == post)
    +			post = print_otag(p, TAG_MROW, "");
    +		else
    +			print_otag(p, TAG_MROW, "");
    +	}
    +
    +	eqn_box(p, bp->first);
    +
    +out:
    +	if (NULL != bp->bottom) {
    +		t = print_otag(p, TAG_MO, "");
    +		print_text(p, bp->bottom);
    +		print_tagq(p, t);
    +	}
    +	if (NULL != bp->top) {
    +		t = print_otag(p, TAG_MO, "");
    +		print_text(p, bp->top);
    +		print_tagq(p, t);
    +	}
    +
    +	if (NULL != post)
    +		print_tagq(p, post);
    +
    +	eqn_box(p, bp->next);
    +}
    +
    +void
    +print_eqn(struct html *p, const struct eqn_box *bp)
    +{
    +	struct tag	*t;
    +
    +	if (bp->first == NULL)
    +		return;
    +
    +	t = print_otag(p, TAG_MATH, "c", "eqn");
    +
    +	p->flags |= HTML_NONOSPACE;
    +	eqn_box(p, bp);
    +	p->flags &= ~HTML_NONOSPACE;
    +
    +	print_tagq(p, t);
    +}
    
    Property changes on: head/contrib/mandoc/eqn_html.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/lib.c
    ===================================================================
    --- head/contrib/mandoc/lib.c	(nonexistent)
    +++ head/contrib/mandoc/lib.c	(revision 338826)
    @@ -0,0 +1,38 @@
    +/*	$Id: lib.c,v 1.14 2017/06/24 14:38:32 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "libmdoc.h"
    +
    +#define LINE(x, y) \
    +	if (0 == strcmp(p, x)) return(y);
    +
    +const char *
    +mdoc_a2lib(const char *p)
    +{
    +
    +#include "lib.in"
    +
    +	return NULL;
    +}
    
    Property changes on: head/contrib/mandoc/lib.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/libroff.h
    ===================================================================
    --- head/contrib/mandoc/libroff.h	(nonexistent)
    +++ head/contrib/mandoc/libroff.h	(revision 338826)
    @@ -0,0 +1,80 @@
    +/*	$Id: libroff.h,v 1.42 2017/07/08 17:52:49 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +enum	tbl_part {
    +	TBL_PART_OPTS, /* in options (first line) */
    +	TBL_PART_LAYOUT, /* describing layout */
    +	TBL_PART_DATA, /* creating data rows */
    +	TBL_PART_CDATA /* continue previous row */
    +};
    +
    +struct	tbl_node {
    +	struct mparse	 *parse; /* parse point */
    +	int		  pos; /* invocation column */
    +	int		  line; /* invocation line */
    +	enum tbl_part	  part;
    +	struct tbl_opts	  opts;
    +	struct tbl_row	 *first_row;
    +	struct tbl_row	 *last_row;
    +	struct tbl_span	 *first_span;
    +	struct tbl_span	 *current_span;
    +	struct tbl_span	 *last_span;
    +	struct tbl_node	 *next;
    +};
    +
    +struct	eqn_node {
    +	struct mparse	 *parse;  /* main parser, for error reporting */
    +	struct roff_node *node;   /* syntax tree of this equation */
    +	struct eqn_def	 *defs;   /* array of definitions */
    +	char		 *data;   /* source code of this equation */
    +	char		 *start;  /* first byte of the current token */
    +	char		 *end;	  /* first byte of the next token */
    +	size_t		  defsz;  /* number of definitions */
    +	size_t		  sz;     /* length of the source code */
    +	size_t		  toksz;  /* length of the current token */
    +	int		  gsize;  /* default point size */
    +	int		  delim;  /* in-line delimiters enabled */
    +	char		  odelim; /* in-line opening delimiter */
    +	char		  cdelim; /* in-line closing delimiter */
    +};
    +
    +struct	eqn_def {
    +	char		 *key;
    +	size_t		  keysz;
    +	char		 *val;
    +	size_t		  valsz;
    +};
    +
    +
    +struct tbl_node	*tbl_alloc(int, int, struct mparse *);
    +void		 tbl_restart(int, int, struct tbl_node *);
    +void		 tbl_free(struct tbl_node *);
    +void		 tbl_reset(struct tbl_node *);
    +void		 tbl_read(struct tbl_node *, int, const char *, int);
    +void		 tbl_option(struct tbl_node *, int, const char *, int *);
    +void		 tbl_layout(struct tbl_node *, int, const char *, int);
    +void		 tbl_data(struct tbl_node *, int, const char *, int);
    +void		 tbl_cdata(struct tbl_node *, int, const char *, int);
    +const struct tbl_span	*tbl_span(struct tbl_node *);
    +int		 tbl_end(struct tbl_node *);
    +struct eqn_node	*eqn_alloc(struct mparse *);
    +void		 eqn_box_free(struct eqn_box *);
    +void		 eqn_free(struct eqn_node *);
    +void		 eqn_parse(struct eqn_node *);
    +void		 eqn_read(struct eqn_node *, const char *);
    +void		 eqn_reset(struct eqn_node *);
    
    Property changes on: head/contrib/mandoc/libroff.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man.c
    ===================================================================
    --- head/contrib/mandoc/man.c	(nonexistent)
    +++ head/contrib/mandoc/man.c	(revision 338826)
    @@ -0,0 +1,383 @@
    +/*	$Id: man.c,v 1.176 2017/06/28 12:52:45 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdarg.h>
    +#include <stdlib.h>
    +#include <stdio.h>
    +#include <string.h>
    +
    +#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 and cancel preceding \c,
    +	 * but add a single vertical space elsewhere.
    +	 */
    +
    +	if (buf[i] == '\0') {
    +		if (man->flags & (MAN_ELINE | MAN_BLINE)) {
    +			mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
    +			    line, 0, NULL);
    +			return 1;
    +		}
    +		if (man->last->tok == MAN_SH || man->last->tok == MAN_SS)
    +			return 1;
    +		switch (man->last->type) {
    +		case ROFFT_TEXT:
    +			sp = man->last->string;
    +			cp = ep = strchr(sp, '\0') - 2;
    +			if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
    +				break;
    +			while (cp > sp && cp[-1] == '\\')
    +				cp--;
    +			if ((ep - cp) % 2)
    +				break;
    +			*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;
    +		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 (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;
    +}
    
    Property changes on: head/contrib/mandoc/man.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man.options.1
    ===================================================================
    --- head/contrib/mandoc/man.options.1	(nonexistent)
    +++ head/contrib/mandoc/man.options.1	(revision 338826)
    @@ -0,0 +1,1332 @@
    +.\"	$Id: man.options.1,v 1.7 2017/07/04 23:40:01 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.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
    +.Fx
    +SVN repository
    +.It
    +the
    +.Ox
    +CVS repository
    +.It
    +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
    
    Property changes on: head/contrib/mandoc/man.options.1
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man_macro.c
    ===================================================================
    --- head/contrib/mandoc/man_macro.c	(nonexistent)
    +++ head/contrib/mandoc/man_macro.c	(revision 338826)
    @@ -0,0 +1,422 @@
    +/*	$Id: man_macro.c,v 1.123 2017/06/25 11:45:37 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2012-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
    + *
    + * 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 <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#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, 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)) {
    +		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;
    +}
    
    Property changes on: head/contrib/mandoc/man_macro.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/manconf.h
    ===================================================================
    --- head/contrib/mandoc/manconf.h	(nonexistent)
    +++ head/contrib/mandoc/manconf.h	(revision 338826)
    @@ -0,0 +1,50 @@
    +/*	$Id: manconf.h,v 1.5 2017/07/01 09:47:30 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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 *);
    
    Property changes on: head/contrib/mandoc/manconf.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc.3
    ===================================================================
    --- head/contrib/mandoc/mandoc.3	(nonexistent)
    +++ head/contrib/mandoc/mandoc.3	(revision 338826)
    @@ -0,0 +1,713 @@
    +.\"	$Id: mandoc.3,v 1.41 2017/07/04 23:40:01 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    +.\" Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.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
    +.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 mandocerr mmin"
    +.Fa "mandocmsg mmsg"
    +.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 mmin
    +Can be set to
    +.Dv MANDOCERR_BASE ,
    +.Dv MANDOCERR_STYLE ,
    +.Dv MANDOCERR_WARNING ,
    +.Dv MANDOCERR_ERROR ,
    +.Dv MANDOCERR_UNSUPP ,
    +or
    +.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 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
    +.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
    +.Ic \&Ao
    +block extends from TEXT ao to TEXT ac,
    +while the formatting of the
    +.Ic \&Bo
    +block extends from TEXT bo to TEXT bc.
    +It renders as follows in
    +.Fl T Ns Cm ascii
    +mode:
    +.Pp
    +.Dl <ao [bo ac> 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 .
    
    Property changes on: head/contrib/mandoc/mandoc.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_aux.h
    ===================================================================
    --- head/contrib/mandoc/mandoc_aux.h	(nonexistent)
    +++ head/contrib/mandoc/mandoc_aux.h	(revision 338826)
    @@ -0,0 +1,27 @@
    +/*	$Id: mandoc_aux.h,v 1.7 2017/06/12 19:05:47 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +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);
    
    Property changes on: head/contrib/mandoc/mandoc_aux.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_escape.3
    ===================================================================
    --- head/contrib/mandoc/mandoc_escape.3	(nonexistent)
    +++ head/contrib/mandoc/mandoc_escape.3	(revision 338826)
    @@ -0,0 +1,367 @@
    +.\"	$Id: mandoc_escape.3,v 1.4 2017/07/04 23:40:01 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: July 4 2017 $
    +.Dt MANDOC_ESCAPE 3
    +.Os
    +.Sh NAME
    +.Nm mandoc_escape
    +.Nd parse roff escape sequences
    +.Sh SYNOPSIS
    +.In sys/types.h
    +.In mandoc.h
    +.Ft "enum mandoc_esc"
    +.Fo mandoc_escape
    +.Fa "const char **end"
    +.Fa "const char **start"
    +.Fa "int *sz"
    +.Fc
    +.Sh DESCRIPTION
    +This function scans a
    +.Xr roff 7
    +escape sequence.
    +.Pp
    +An escape sequence consists of
    +.Bl -dash -compact -width 2n
    +.It
    +an initial backslash character
    +.Pq Sq \e ,
    +.It
    +a single ASCII character called the escape sequence identifier,
    +.It
    +and, with only a few exceptions, an argument.
    +.El
    +.Pp
    +Arguments can be given in the following forms; some escape sequence
    +identifiers only accept some of these forms as specified below.
    +The first three forms are called the standard forms.
    +.Bl -tag -width 2n
    +.It \&In brackets: Ic \&[ Ns Ar argument Ns Ic \&]
    +The argument starts after the initial
    +.Sq \&[ ,
    +ends before the final
    +.Sq \&] ,
    +and the escape sequence ends with the final
    +.Sq \&] .
    +.It Two-character argument short form: Ic \&( Ns Ar ar
    +This form can only be used for arguments
    +consisting of exactly two characters.
    +It has the same effect as
    +.Ic \&[ Ns Ar ar Ns Ic \&] .
    +.It One-character argument short form: Ar a
    +This form can only be used for arguments
    +consisting of exactly one character.
    +It has the same effect as
    +.Ic \&[ Ns Ar a Ns Ic \&] .
    +.It Delimited form: Ar C Ns Ar argument Ns Ar C
    +The argument starts after the initial delimiter character
    +.Ar C ,
    +ends before the next occurrence of the delimiter character
    +.Ar C ,
    +and the escape sequence ends with that second
    +.Ar C .
    +Some escape sequences allow arbitrary characters
    +.Ar C
    +as quoting characters, some restrict the range of characters
    +that can be used as quoting characters.
    +.El
    +.Pp
    +Upon function entry,
    +.Fa end
    +is expected to point to the escape sequence identifier.
    +The values passed in as
    +.Fa start
    +and
    +.Fa sz
    +are ignored and overwritten.
    +.Pp
    +By design, this function cannot handle those
    +.Xr roff 7
    +escape sequences that require in-place expansion, in particular
    +user-defined strings
    +.Ic \e* ,
    +number registers
    +.Ic \en ,
    +width measurements
    +.Ic \ew ,
    +and numerical expression control
    +.Ic \eB .
    +These are handled by
    +.Fn roff_res ,
    +a private preprocessor function called from
    +.Fn roff_parseln ,
    +see the file
    +.Pa roff.c .
    +.Pp
    +The function
    +.Fn mandoc_escape
    +is used
    +.Bl -dash -compact -width 2n
    +.It
    +recursively by itself, because some escape sequence arguments can
    +in turn contain other escape sequences,
    +.It
    +for error detection internally by the
    +.Xr roff 7
    +parser part of the
    +.Xr mandoc 3
    +library, see the file
    +.Pa roff.c ,
    +.It
    +above all externally by the
    +.Xr mandoc 1
    +formatting modules, in particular
    +.Fl Tascii
    +and
    +.Fl Thtml ,
    +for formatting purposes, see the files
    +.Pa term.c
    +and
    +.Pa html.c ,
    +.It
    +and rarely externally by high-level utilities using the mandoc library,
    +for example
    +.Xr makewhatis 8 ,
    +to purge escape sequences from text.
    +.El
    +.Sh RETURN VALUES
    +Upon function return, the pointer
    +.Fa end
    +is set to the character after the end of the escape sequence,
    +such that the calling higher-level parser can easily continue.
    +.Pp
    +For escape sequences taking an argument, the pointer
    +.Fa start
    +is set to the beginning of the argument and
    +.Fa sz
    +is set to the length of the argument.
    +For escape sequences not taking an argument,
    +.Fa start
    +is set to the character after the end of the sequence and
    +.Fa sz
    +is set to 0.
    +Both
    +.Fa start
    +and
    +.Fa sz
    +may be
    +.Dv NULL ;
    +in that case, the argument and the length are not returned.
    +.Pp
    +For sequences taking an argument, the function
    +.Fn mandoc_escape
    +returns one of the following values:
    +.Bl -tag -width 2n
    +.It Dv ESCAPE_FONT
    +The escape sequence
    +.Ic \ef
    +taking an argument in standard form:
    +.Ic \ef[ , \ef( , \ef Ns Ar a .
    +Two-character arguments starting with the character
    +.Sq C
    +are reduced to one-character arguments by skipping the
    +.Sq C .
    +More specific values are returned for the most commonly used arguments:
    +.Bl -column "argument" "ESCAPE_FONTITALIC"
    +.It argument Ta return value
    +.It Cm R No or Cm 1 Ta Dv ESCAPE_FONTROMAN
    +.It Cm I No or Cm 2 Ta Dv ESCAPE_FONTITALIC
    +.It Cm B No or Cm 3 Ta Dv ESCAPE_FONTBOLD
    +.It Cm P Ta Dv ESCAPE_FONTPREV
    +.It Cm BI Ta Dv ESCAPE_FONTBI
    +.El
    +.It Dv ESCAPE_SPECIAL
    +The escape sequence
    +.Ic \eC
    +taking an argument delimited with the single quote character
    +and, as a special exception, the escape sequences
    +.Em not
    +having an identifier, that is, those where the argument, in standard
    +form, directly follows the initial backslash:
    +.Ic \eC' , \e[ , \e( , \e Ns Ar a .
    +Note that the one-character argument short form can only be used for
    +argument characters that do not clash with escape sequence identifiers.
    +.Pp
    +If the argument matches one of the forms described below under
    +.Dv ESCAPE_UNICODE ,
    +that value is returned instead.
    +.Pp
    +The
    +.Dv ESCAPE_SPECIAL
    +special character escape sequences can be rendered using the functions
    +.Fn mchars_spec2cp
    +and
    +.Fn mchars_spec2str
    +described in the
    +.Xr mchars_alloc 3
    +manual.
    +.It Dv ESCAPE_UNICODE
    +Escape sequences of the same format as described above under
    +.Dv ESCAPE_SPECIAL ,
    +but with an argument of the forms
    +.Ic u Ns Ar XXXX ,
    +.Ic u Ns Ar YXXXX ,
    +or
    +.Ic u10 Ns Ar XXXX
    +where
    +.Ar X
    +and
    +.Ar Y
    +are hexadecimal digits and
    +.Ar Y
    +is not zero:
    +.Ic \eC'u , \e[u .
    +As a special exception,
    +.Fa start
    +is set to the character after the
    +.Ic u ,
    +and the
    +.Fa sz
    +return value does not include the
    +.Ic u
    +either.
    +.Pp
    +Such Unicode character escape sequences can be rendered using the function
    +.Fn mchars_num2uc
    +described in the
    +.Xr mchars_alloc 3
    +manual.
    +.It Dv ESCAPE_NUMBERED
    +The escape sequence
    +.Ic \eN
    +followed by a delimited argument.
    +The delimiter character is arbitrary except that digits cannot be used.
    +If a digit is encountered instead of the opening delimiter, that
    +digit is considered to be the argument and the end of the sequence, and
    +.Dv ESCAPE_IGNORE
    +is returned.
    +.Pp
    +Such ASCII character escape sequences can be rendered using the function
    +.Fn mchars_num2char
    +described in the
    +.Xr mchars_alloc 3
    +manual.
    +.It Dv ESCAPE_OVERSTRIKE
    +The escape sequence
    +.Ic \eo
    +followed by an argument delimited by an arbitrary character.
    +.It Dv ESCAPE_IGNORE
    +.Bl -bullet -width 2n
    +.It
    +The escape sequence
    +.Ic \es
    +followed by an argument in standard form or by an argument delimited
    +by the single quote character:
    +.Ic \es' , \es[ , \es( , \es Ns Ar a .
    +As a special exception, an optional
    +.Sq +
    +or
    +.Sq \-
    +character is allowed after the
    +.Sq s
    +for all forms.
    +.It
    +The escape sequences
    +.Ic \eF ,
    +.Ic \eg ,
    +.Ic \ek ,
    +.Ic \eM ,
    +.Ic \em ,
    +.Ic \en ,
    +.Ic \eV ,
    +and
    +.Ic \eY
    +followed by an argument in standard form.
    +.It
    +The escape sequences
    +.Ic \eA ,
    +.Ic \eb ,
    +.Ic \eD ,
    +.Ic \eR ,
    +.Ic \eX ,
    +and
    +.Ic \eZ
    +followed by an argument delimited by an arbitrary character.
    +.It
    +The escape sequences
    +.Ic \eH ,
    +.Ic \eh ,
    +.Ic \eL ,
    +.Ic \el ,
    +.Ic \eS ,
    +.Ic \ev ,
    +and
    +.Ic \ex
    +followed by an argument delimited by a character that cannot occur
    +in numerical expressions.
    +However, if any character that can occur in numerical expressions
    +is found instead of a delimiter, the sequence is considered to end
    +with that character, and
    +.Dv ESCAPE_ERROR
    +is returned.
    +.El
    +.It Dv ESCAPE_ERROR
    +Escape sequences taking an argument but not matching any of the above patterns.
    +In particular, that happens if the end of the logical input line
    +is reached before the end of the argument.
    +.El
    +.Pp
    +For sequences that do not take an argument, the function
    +.Fn mandoc_escape
    +returns one of the following values:
    +.Bl -tag -width 2n
    +.It Dv ESCAPE_SKIPCHAR
    +The escape sequence
    +.Qq \ez .
    +.It Dv ESCAPE_NOSPACE
    +The escape sequence
    +.Qq \ec .
    +.It Dv ESCAPE_IGNORE
    +The escape sequences
    +.Qq \ed
    +and
    +.Qq \eu .
    +.El
    +.Sh FILES
    +This function is implemented in
    +.Pa mandoc.c .
    +.Sh SEE ALSO
    +.Xr mchars_alloc 3 ,
    +.Xr mandoc_char 7 ,
    +.Xr roff 7
    +.Sh HISTORY
    +This function has been available since mandoc 1.11.2.
    +.Sh AUTHORS
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org
    +.Sh BUGS
    +The function doesn't cleanly distinguish between sequences that are
    +valid and supported, valid and ignored, valid and unsupported,
    +syntactically invalid, or undefined.
    +For sequences that are ignored or unsupported, it doesn't tell
    +whether that deficiency is likely to cause major formatting problems
    +and/or loss of document content.
    +The function is already rather complicated and still parses some
    +sequences incorrectly.
    +.
    +.ig
    +For these sequences, the list given below specifies a starting string
    +and either the length of the argument or an ending character.
    +The argument starts after the starting string.
    +In the former case, the sequence ends with the end of the argument.
    +In the latter case, the argument ends before the ending character,
    +and the sequence ends with the ending character.
    +..
    
    Property changes on: head/contrib/mandoc/mandoc_escape.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_headers.3
    ===================================================================
    --- head/contrib/mandoc/mandoc_headers.3	(nonexistent)
    +++ head/contrib/mandoc/mandoc_headers.3	(revision 338826)
    @@ -0,0 +1,570 @@
    +.Dd $Mdocdate: July 8 2017 $
    +.Dt MANDOC_HEADERS 3
    +.Os
    +.Sh NAME
    +.Nm mandoc_headers
    +.Nd ordering of mandoc include files
    +.Sh DESCRIPTION
    +To support a cleaner coding style, the mandoc header files do not
    +contain any include directives and do not guard against multiple
    +inclusion.
    +The application developer has to make sure that the headers are
    +included in a proper order, and that no header is included more
    +than once.
    +.Pp
    +The headers and functions form three major groups:
    +.Sx Parser interface ,
    +.Sx Parser internals ,
    +and
    +.Sx Formatter interface .
    +.Pp
    +Various rules are given below prohibiting the inclusion of certain
    +combinations of headers into the same file.
    +The intention is to keep the following functional components
    +separate from each other:
    +.Pp
    +.Bl -dash -offset indent -compact
    +.It
    +.Xr mdoc 7
    +parser
    +.It
    +.Xr man 7
    +parser
    +.It
    +.Xr roff 7
    +parser
    +.It
    +.Xr tbl 7
    +parser
    +.It
    +.Xr eqn 7
    +parser
    +.It
    +terminal formatters
    +.It
    +HTML formatters
    +.It
    +search tools
    +.El
    +.Pp
    +Note that mere usage of an opaque struct type does
    +.Em not
    +require inclusion of the header where that type is defined.
    +.Ss Parser interface
    +Each of the following headers can be included without including
    +any other mandoc header.
    +These headers should be included before any other mandoc headers.
    +.Bl -tag -width Ds
    +.It Qq Pa mandoc_aux.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t .
    +.Pp
    +Provides the utility functions documented in
    +.Xr mandoc_malloc 3 .
    +.It Qq Pa mandoc_ohash.h
    +Requires
    +.In stddef.h
    +for
    +.Vt ptrdiff_t
    +and
    +.In stdint.h
    +for
    +.Vt uint32_t .
    +.Pp
    +Includes
    +.In ohash.h
    +and provides
    +.Fn mandoc_ohash_init .
    +.It Qq Pa mandoc.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t .
    +.Pp
    +Provides
    +.Vt enum mandoc_esc ,
    +.Vt enum mandocerr ,
    +.Vt enum mandoclevel ,
    +.Vt enum mandoc_os ,
    +.Vt enum tbl_cellt ,
    +.Vt enum tbl_datt ,
    +.Vt enum tbl_spant ,
    +.Vt enum eqn_boxt ,
    +.Vt enum eqn_fontt ,
    +.Vt enum eqn_pilet ,
    +.Vt enum eqn_post ,
    +.Vt struct tbl_opts ,
    +.Vt struct tbl_cell ,
    +.Vt struct tbl_row ,
    +.Vt struct tbl_dat ,
    +.Vt struct tbl_span ,
    +.Vt struct eqn_box ,
    +the function prototype typedef
    +.Fn mandocmsg ,
    +the function
    +.Xr mandoc_escape 3 ,
    +the functions described in
    +.Xr mchars_alloc 3 ,
    +and the functions
    +.Fn mparse_*
    +described in
    +.Xr mandoc 3 .
    +.Pp
    +Uses the opaque type
    +.Vt struct mparse
    +from
    +.Pa read.c
    +for function prototypes.
    +Uses the type
    +.Vt struct roff_man
    +from
    +.Pa roff.h
    +as an opaque type for function prototypes.
    +.It Qq Pa mandoc_xr.h
    +Provides
    +.Vt struct mandoc_xr
    +and the functions
    +.Fn mandoc_xr_reset ,
    +.Fn mandoc_xr_add ,
    +.Fn mandoc_xr_get ,
    +and
    +.Fn mandoc_xr_free .
    +.It Qq Pa roff.h
    +Requires
    +.Qq Pa mandoc_ohash.h
    +for
    +.Vt struct ohash
    +and
    +.Qq Pa mandoc.h
    +for
    +.Vt enum mandoc_os .
    +.Pp
    +Provides
    +.Vt enum mdoc_endbody ,
    +.Vt enum roff_macroset ,
    +.Vt enum roff_next ,
    +.Vt enum roff_sec ,
    +.Vt enum roff_tok ,
    +.Vt enum roff_type ,
    +.Vt struct roff_man ,
    +.Vt struct roff_meta ,
    +.Vt struct roff_node ,
    +the constant array
    +.Va roff_name
    +and the functions
    +.Fn deroff ,
    +.Fn roffhash_alloc ,
    +.Fn roffhash_find ,
    +.Fn roffhash_free ,
    +and
    +.Fn roff_validate .
    +.Pp
    +Uses pointers to the types
    +.Vt struct mdoc_arg
    +and
    +.Vt union mdoc_data
    +from
    +.Pa mdoc.h
    +as opaque struct members.
    +.El
    +.Pp
    +The following two require
    +.Qq Pa roff.h
    +but no other mandoc headers.
    +Afterwards, any other mandoc headers can be included as needed.
    +.Bl -tag -width Ds
    +.It Qq Pa mdoc.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t .
    +.Pp
    +Provides
    +.Vt enum mdocargt ,
    +.Vt enum mdoc_auth ,
    +.Vt enum mdoc_disp ,
    +.Vt enum mdoc_font ,
    +.Vt enum mdoc_list ,
    +.Vt struct mdoc_argv ,
    +.Vt struct mdoc_arg ,
    +.Vt struct mdoc_an ,
    +.Vt struct mdoc_bd ,
    +.Vt struct mdoc_bf ,
    +.Vt struct mdoc_bl ,
    +.Vt struct mdoc_rs ,
    +.Vt union mdoc_data ,
    +and the functions
    +.Fn mdoc_*
    +described in
    +.Xr mandoc 3 .
    +.Pp
    +Uses the type
    +.Vt struct roff_man
    +from
    +.Pa roff.h
    +as an opaque type for function prototypes.
    +.Pp
    +When this header is included, the same file should not include
    +.Pa libman.h
    +or
    +.Pa libroff.h .
    +.It Qq Pa man.h
    +Provides the functions
    +.Fn man_*
    +described in
    +.Xr mandoc 3 .
    +.Pp
    +Uses the opaque type
    +.Vt struct mparse
    +from
    +.Pa read.c
    +for function prototypes.
    +Uses the type
    +.Vt struct roff_man
    +from
    +.Pa roff.h
    +as an opaque type for function prototypes.
    +.Pp
    +When this header is included, the same file should not include
    +.Pa libmdoc.h
    +or
    +.Pa libroff.h .
    +.El
    +.Ss Parser internals
    +The following headers require inclusion of a parser interface header
    +before they can be included.
    +All parser interface headers should precede all parser internal headers.
    +When any parser internal headers are included, the same file should
    +not include any formatter headers.
    +.Bl -tag -width Ds
    +.It Qq Pa libmandoc.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t
    +and
    +.Qq Pa mandoc.h
    +for
    +.Vt enum mandocerr .
    +.Pp
    +Provides
    +.Vt enum rofferr ,
    +.Vt struct buf ,
    +utility functions needed by multiple parsers,
    +and the top-level functions to call the parsers.
    +.Pp
    +Uses the opaque types
    +.Vt struct mparse
    +from
    +.Pa read.c
    +and
    +.Vt struct roff
    +from
    +.Pa roff.c
    +for function prototypes.
    +Uses the type
    +.Vt struct roff_man
    +from
    +.Pa roff.h
    +as an opaque type for function prototypes.
    +.It Qq Pa roff_int.h
    +Requires
    +.Qq Pa roff.h
    +for
    +.Vt enum roff_type .
    +.Pp
    +Provides functions named
    +.Fn roff_*
    +to handle roff nodes and the two special functions
    +.Fn man_breakscope
    +and
    +.Fn mdoc_argv_free
    +because the latter two are needed by
    +.Qq Pa roff.c .
    +.Pp
    +Uses the types
    +.Vt struct roff_man
    +and
    +.Vt struct roff_node
    +from
    +.Pa roff.h
    +and
    +.Vt struct mdoc_arg
    +from
    +.Pa mdoc.h
    +as opaque types for function prototypes.
    +.It Qq Pa libmdoc.h
    +Requires
    +.Qq Pa roff.h
    +for
    +.Vt enum roff_tok
    +and
    +.Qq Pa mdoc.h
    +for
    +.Vt enum mdoc_*
    +and
    +.Vt struct mdoc_* .
    +.Pp
    +Provides
    +.Vt enum margserr ,
    +.Vt enum mdelim ,
    +.Vt struct mdoc_macro ,
    +and many functions internal to the
    +.Xr mdoc 7
    +parser.
    +.Pp
    +Uses the opaque type
    +.Vt struct mparse
    +from
    +.Pa read.c .
    +Uses the types
    +.Vt struct roff_man
    +and
    +.Vt struct roff_node
    +from
    +.Pa roff.h
    +as opaque types for function prototypes.
    +.Pp
    +When this header is included, the same file should not include
    +.Pa man.h ,
    +.Pa libman.h ,
    +or
    +.Pa libroff.h .
    +.It Qq Pa libman.h
    +Requires
    +.Qq Pa roff.h
    +for
    +.Vt enum roff_tok .
    +.Pp
    +Provides
    +.Vt struct man_macro
    +and some functions internal to the
    +.Xr man 7
    +parser.
    +.Pp
    +Uses the types
    +.Vt struct roff_man
    +and
    +.Vt struct roff_node
    +from
    +.Pa roff.h
    +as opaque types for function prototypes.
    +.Pp
    +When this header is included, the same file should not include
    +.Pa mdoc.h ,
    +.Pa libmdoc.h ,
    +or
    +.Pa libroff.h .
    +.It Qq Pa libroff.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t
    +and
    +.Qq Pa mandoc.h
    +for
    +.Vt struct tbl_*
    +and
    +.Vt struct eqn_box .
    +.Pp
    +Provides
    +.Vt enum tbl_part ,
    +.Vt struct tbl_node ,
    +.Vt struct eqn_def ,
    +.Vt struct eqn_node ,
    +and many functions internal to the
    +.Xr tbl 7
    +and
    +.Xr eqn 7
    +parsers.
    +.Pp
    +Uses the opaque type
    +.Vt struct mparse
    +from
    +.Pa read.c .
    +.Pp
    +When this header is included, the same file should not include
    +.Pa man.h ,
    +.Pa mdoc.h ,
    +.Pa libman.h ,
    +or
    +.Pa libmdoc.h .
    +.El
    +.Ss Formatter interface
    +These headers should be included after any parser interface headers.
    +No parser internal headers should be included by the same file.
    +.Bl -tag -width Ds
    +.It Qq Pa out.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t .
    +.Pp
    +Provides
    +.Vt enum roffscale ,
    +.Vt struct roffcol ,
    +.Vt struct roffsu ,
    +.Vt struct rofftbl ,
    +.Fn a2roffsu ,
    +and
    +.Fn tblcalc .
    +.Pp
    +Uses
    +.Vt struct tbl_span
    +from
    +.Pa mandoc.h
    +as an opaque type for function prototypes.
    +.Pp
    +When this header is included, the same file should not include
    +.Pa mansearch.h .
    +.It Qq Pa term.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t
    +and
    +.Qq Pa out.h
    +for
    +.Vt struct roffsu
    +and
    +.Vt struct rofftbl .
    +.Pp
    +Provides
    +.Vt enum termenc ,
    +.Vt enum termfont ,
    +.Vt enum termtype ,
    +.Vt struct termp_tbl ,
    +.Vt struct termp ,
    +.Fn roff_term_pre ,
    +and many terminal formatting functions.
    +.Pp
    +Uses the opaque type
    +.Vt struct termp_ps
    +from
    +.Pa term_ps.c .
    +Uses
    +.Vt struct tbl_span
    +and
    +.Vt struct eqn_box
    +from
    +.Pa mandoc.h
    +and
    +.Vt struct roff_meta
    +and
    +.Vt struct roff_node
    +from
    +.Pa roff.h
    +as opaque types for function prototypes.
    +.Pp
    +When this header is included, the same file should not include
    +.Pa html.h
    +or
    +.Pa mansearch.h .
    +.It Qq Pa html.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t
    +and
    +.Qq Pa out.h
    +for
    +.Vt struct roffsu
    +and
    +.Vt struct rofftbl .
    +.Pp
    +Provides
    +.Vt enum htmltag ,
    +.Vt enum htmlattr ,
    +.Vt enum htmlfont ,
    +.Vt struct tag ,
    +.Vt struct tagq ,
    +.Vt struct htmlpair ,
    +.Vt struct html ,
    +.Fn roff_html_pre ,
    +and many HTML formatting functions.
    +.Pp
    +Uses
    +.Vt struct tbl_span
    +and
    +.Vt struct eqn_box
    +from
    +.Pa mandoc.h
    +and
    +.Vt struct roff_node
    +from
    +.Pa roff.h
    +as opaque types for function prototypes.
    +.Pp
    +When this header is included, the same file should not include
    +.Pa term.h
    +or
    +.Pa mansearch.h .
    +.It Qq Pa tag.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t .
    +.Pp
    +Provides an interface to generate
    +.Xr ctags 1
    +files for the
    +.Ic :t
    +functionality mentioned in
    +.Xr man 1 .
    +.It Qq Pa main.h
    +Provides the top level steering functions for all formatters.
    +.Pp
    +Uses the type
    +.Vt struct roff_man
    +from
    +.Pa roff.h
    +as an opaque type for function prototypes.
    +.It Qq Pa manconf.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t .
    +.Pp
    +Provides
    +.Vt struct manconf ,
    +.Vt struct manpaths ,
    +.Vt struct manoutput ,
    +and the functions
    +.Fn manconf_parse ,
    +.Fn manconf_output ,
    +.Fn manconf_free ,
    +and
    +.Fn manpath_base .
    +.It Qq Pa mansearch.h
    +Requires
    +.In sys/types.h
    +for
    +.Vt size_t
    +and
    +.In stdint.h
    +for
    +.Vt uint64_t .
    +.Pp
    +Provides
    +.Vt enum argmode ,
    +.Vt struct manpage ,
    +.Vt struct mansearch ,
    +and the functions
    +.Fn mansearch
    +and
    +.Fn mansearch_free .
    +.Pp
    +Uses
    +.Vt struct manpaths
    +from
    +.Pa manconf.h
    +as an opaque type for function prototypes.
    +.Pp
    +When this header is included, the same file should not include
    +.Pa out.h ,
    +.Pa term.h ,
    +or
    +.Pa html.h .
    +.El
    
    Property changes on: head/contrib/mandoc/mandoc_headers.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_xr.c
    ===================================================================
    --- head/contrib/mandoc/mandoc_xr.c	(nonexistent)
    +++ head/contrib/mandoc/mandoc_xr.c	(revision 338826)
    @@ -0,0 +1,121 @@
    +/*	$Id: mandoc_xr.c,v 1.3 2017/07/02 21:18:29 schwarze Exp $ */
    +/*
    + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <stddef.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc_ohash.h"
    +#include "mandoc_xr.h"
    +
    +static struct ohash	 *xr_hash = NULL;
    +static struct mandoc_xr	 *xr_first = NULL;
    +static struct mandoc_xr	 *xr_last = NULL;
    +
    +static void		  mandoc_xr_clear(void);
    +
    +
    +static void
    +mandoc_xr_clear(void)
    +{
    +	struct mandoc_xr	*xr;
    +	unsigned int		 slot;
    +
    +	if (xr_hash == NULL)
    +		return;
    +	for (xr = ohash_first(xr_hash, &slot); xr != NULL;
    +	     xr = ohash_next(xr_hash, &slot))
    +		free(xr);
    +	ohash_delete(xr_hash);
    +}
    +
    +void
    +mandoc_xr_reset(void)
    +{
    +	if (xr_hash == NULL)
    +		xr_hash = mandoc_malloc(sizeof(*xr_hash));
    +	else
    +		mandoc_xr_clear();
    +	mandoc_ohash_init(xr_hash, 5,
    +	    offsetof(struct mandoc_xr, hashkey));
    +	xr_first = xr_last = NULL;
    +}
    +
    +int
    +mandoc_xr_add(const char *sec, const char *name, int line, int pos)
    +{
    +	struct mandoc_xr	 *xr, *oxr;
    +	const char		 *pend;
    +	size_t			  ssz, nsz, tsz;
    +	unsigned int		  slot;
    +	int			  ret;
    +	uint32_t		  hv;
    +
    +	if (xr_hash == NULL)
    +		return 0;
    +
    +	ssz = strlen(sec) + 1;
    +	nsz = strlen(name) + 1;
    +	tsz = ssz + nsz;
    +	xr = mandoc_malloc(sizeof(*xr) + tsz);
    +	xr->next = NULL;
    +	xr->sec = xr->hashkey;
    +	xr->name = xr->hashkey + ssz;
    +	xr->line = line;
    +	xr->pos = pos;
    +	xr->count = 1;
    +	memcpy(xr->sec, sec, ssz);
    +	memcpy(xr->name, name, nsz);
    +
    +	pend = xr->hashkey + tsz;
    +	hv = ohash_interval(xr->hashkey, &pend);
    +	slot = ohash_lookup_memory(xr_hash, xr->hashkey, tsz, hv);
    +	if ((oxr = ohash_find(xr_hash, slot)) == NULL) {
    +		ohash_insert(xr_hash, slot, xr);
    +		if (xr_first == NULL)
    +			xr_first = xr;
    +		else
    +			xr_last->next = xr;
    +		xr_last = xr;
    +		return 0;
    +	}
    +
    +	oxr->count++;
    +	ret = (oxr->line == -1) ^ (xr->line == -1);
    +	if (xr->line == -1)
    +		oxr->line = -1;
    +	free(xr);
    +	return ret;
    +}
    +
    +struct mandoc_xr *
    +mandoc_xr_get(void)
    +{
    +	return xr_first;
    +}
    +
    +void
    +mandoc_xr_free(void)
    +{
    +	mandoc_xr_clear();
    +	free(xr_hash);
    +	xr_hash = NULL;
    +}
    
    Property changes on: head/contrib/mandoc/mandoc_xr.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_xr.h
    ===================================================================
    --- head/contrib/mandoc/mandoc_xr.h	(nonexistent)
    +++ head/contrib/mandoc/mandoc_xr.h	(revision 338826)
    @@ -0,0 +1,31 @@
    +/*	$Id: mandoc_xr.h,v 1.3 2017/07/02 21:18:29 schwarze Exp $ */
    +/*
    + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +struct	mandoc_xr {
    +	struct mandoc_xr *next;
    +	char		 *sec;
    +	char		 *name;
    +	int		  line;  /* Or -1 for this page's own names. */
    +	int		  pos;
    +	int		  count;
    +	char		  hashkey[];
    +};
    +
    +void		  mandoc_xr_reset(void);
    +int		  mandoc_xr_add(const char *, const char *, int, int);
    +struct mandoc_xr *mandoc_xr_get(void);
    +void		  mandoc_xr_free(void);
    
    Property changes on: head/contrib/mandoc/mandoc_xr.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandocd.c
    ===================================================================
    --- head/contrib/mandoc/mandocd.c	(nonexistent)
    +++ head/contrib/mandoc/mandocd.c	(revision 338826)
    @@ -0,0 +1,285 @@
    +/*	$Id: mandocd.c,v 1.6 2017/06/24 14:38:32 schwarze Exp $ */
    +/*
    + * Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
    + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#if HAVE_CMSG_XPG42
    +#define _XPG4_2
    +#endif
    +
    +#include <sys/types.h>
    +#include <sys/socket.h>
    +
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <limits.h>
    +#include <stdint.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "man.h"
    +#include "main.h"
    +#include "manconf.h"
    +
    +enum	outt {
    +	OUTT_ASCII = 0,
    +	OUTT_UTF8,
    +	OUTT_HTML
    +};
    +
    +static	void	  process(struct mparse *, enum outt, void *);
    +static	int	  read_fds(int, int *);
    +static	void	  usage(void) __attribute__((__noreturn__));
    +
    +
    +#define NUM_FDS 3
    +static int
    +read_fds(int clientfd, int *fds)
    +{
    +	struct msghdr	 msg;
    +	struct iovec	 iov[1];
    +	unsigned char	 dummy[1];
    +	struct cmsghdr	*cmsg;
    +	int		*walk;
    +	int		 cnt;
    +
    +	/* Union used for alignment. */
    +	union {
    +		uint8_t controlbuf[CMSG_SPACE(NUM_FDS * sizeof(int))];
    +		struct cmsghdr align;
    +	} u;
    +
    +	memset(&msg, '\0', sizeof(msg));
    +	msg.msg_control = u.controlbuf;
    +	msg.msg_controllen = sizeof(u.controlbuf);
    +
    +	/*
    +	 * Read a dummy byte - sendmsg cannot send an empty message,
    +	 * even if we are only interested in the OOB data.
    +	 */
    +
    +	iov[0].iov_base = dummy;
    +	iov[0].iov_len = sizeof(dummy);
    +	msg.msg_iov = iov;
    +	msg.msg_iovlen = 1;
    +
    +	switch (recvmsg(clientfd, &msg, 0)) {
    +	case -1:
    +		warn("recvmsg");
    +		return -1;
    +	case 0:
    +		return 0;
    +	default:
    +		break;
    +	}
    +
    +	if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) {
    +		warnx("CMSG_FIRSTHDR: missing control message");
    +		return -1;
    +	}
    +
    +	if (cmsg->cmsg_level != SOL_SOCKET ||
    +	    cmsg->cmsg_type != SCM_RIGHTS ||
    +	    cmsg->cmsg_len != CMSG_LEN(NUM_FDS * sizeof(int))) {
    +		warnx("CMSG_FIRSTHDR: invalid control message");
    +		return -1;
    +	}
    +
    +	walk = (int *)CMSG_DATA(cmsg);
    +	for (cnt = 0; cnt < NUM_FDS; cnt++)
    +		fds[cnt] = *walk++;
    +
    +	return 1;
    +}
    +
    +int
    +main(int argc, char *argv[])
    +{
    +	struct manoutput	 options;
    +	struct mparse		*parser;
    +	void			*formatter;
    +	const char		*defos;
    +	const char		*errstr;
    +	int			 clientfd;
    +	int			 old_stdin;
    +	int			 old_stdout;
    +	int			 old_stderr;
    +	int			 fds[3];
    +	int			 state, opt;
    +	enum outt		 outtype;
    +
    +	defos = NULL;
    +	outtype = OUTT_ASCII;
    +	while ((opt = getopt(argc, argv, "I:T:")) != -1) {
    +		switch (opt) {
    +		case 'I':
    +			if (strncmp(optarg, "os=", 3) == 0)
    +				defos = optarg + 3;
    +			else {
    +				warnx("-I %s: Bad argument", optarg);
    +				usage();
    +			}
    +			break;
    +		case 'T':
    +			if (strcmp(optarg, "ascii") == 0)
    +				outtype = OUTT_ASCII;
    +			else if (strcmp(optarg, "utf8") == 0)
    +				outtype = OUTT_UTF8;
    +			else if (strcmp(optarg, "html") == 0)
    +				outtype = OUTT_HTML;
    +			else {
    +				warnx("-T %s: Bad argument", optarg);
    +				usage();
    +			}
    +			break;
    +		default:
    +			usage();
    +		}
    +	}
    +
    +	if (argc > 0) {
    +		argc -= optind;
    +		argv += optind;
    +	}
    +	if (argc != 1)
    +		usage();
    +
    +	errstr = NULL;
    +	clientfd = strtonum(argv[0], 3, INT_MAX, &errstr);
    +	if (errstr)
    +		errx(1, "file descriptor %s %s", argv[1], errstr);
    +
    +	mchars_alloc();
    +	parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
    +	    MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, defos);
    +
    +	memset(&options, 0, sizeof(options));
    +	switch (outtype) {
    +	case OUTT_ASCII:
    +		formatter = ascii_alloc(&options);
    +		break;
    +	case OUTT_UTF8:
    +		formatter = utf8_alloc(&options);
    +		break;
    +	case OUTT_HTML:
    +		options.fragment = 1;
    +		formatter = html_alloc(&options);
    +		break;
    +	}
    +
    +	state = 1;  /* work to do */
    +	fflush(stdout);
    +	fflush(stderr);
    +	if ((old_stdin = dup(STDIN_FILENO)) == -1 ||
    +	    (old_stdout = dup(STDOUT_FILENO)) == -1 ||
    +	    (old_stderr = dup(STDERR_FILENO)) == -1) {
    +		warn("dup");
    +		state = -1;  /* error */
    +	}
    +
    +	while (state == 1 && (state = read_fds(clientfd, fds)) == 1) {
    +		if (dup2(fds[0], STDIN_FILENO) == -1 ||
    +		    dup2(fds[1], STDOUT_FILENO) == -1 ||
    +		    dup2(fds[2], STDERR_FILENO) == -1) {
    +			warn("dup2");
    +			state = -1;
    +			break;
    +		}
    +
    +		close(fds[0]);
    +		close(fds[1]);
    +		close(fds[2]);
    +
    +		process(parser, outtype, formatter);
    +		mparse_reset(parser);
    +
    +		fflush(stdout);
    +		fflush(stderr);
    +		/* Close file descriptors by restoring the old ones. */
    +		if (dup2(old_stderr, STDERR_FILENO) == -1 ||
    +		    dup2(old_stdout, STDOUT_FILENO) == -1 ||
    +		    dup2(old_stdin, STDIN_FILENO) == -1) {
    +			warn("dup2");
    +			state = -1;
    +			break;
    +		}
    +	}
    +
    +	close(clientfd);
    +	switch (outtype) {
    +	case OUTT_ASCII:
    +	case OUTT_UTF8:
    +		ascii_free(formatter);
    +		break;
    +	case OUTT_HTML:
    +		html_free(formatter);
    +		break;
    +	}
    +	mparse_free(parser);
    +	mchars_free();
    +	return state == -1 ? 1 : 0;
    +}
    +
    +static void
    +process(struct mparse *parser, enum outt outtype, void *formatter)
    +{
    +	struct roff_man	 *man;
    +
    +	mparse_readfd(parser, STDIN_FILENO, "<unixfd>");
    +	mparse_result(parser, &man, NULL);
    +
    +	if (man == NULL)
    +		return;
    +
    +	if (man->macroset == MACROSET_MDOC) {
    +		mdoc_validate(man);
    +		switch (outtype) {
    +		case OUTT_ASCII:
    +		case OUTT_UTF8:
    +			terminal_mdoc(formatter, man);
    +			break;
    +		case OUTT_HTML:
    +			html_mdoc(formatter, man);
    +			break;
    +		}
    +	}
    +	if (man->macroset == MACROSET_MAN) {
    +		man_validate(man);
    +		switch (outtype) {
    +		case OUTT_ASCII:
    +		case OUTT_UTF8:
    +			terminal_man(formatter, man);
    +			break;
    +		case OUTT_HTML:
    +			html_man(formatter, man);
    +			break;
    +		}
    +	}
    +}
    +
    +void
    +usage(void)
    +{
    +	fprintf(stderr, "usage: mandocd [-I os=name] [-T output] socket_fd\n");
    +	exit(1);
    +}
    
    Property changes on: head/contrib/mandoc/mandocd.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/manpath.c
    ===================================================================
    --- head/contrib/mandoc/manpath.c	(nonexistent)
    +++ head/contrib/mandoc/manpath.c	(revision 338826)
    @@ -0,0 +1,333 @@
    +/*	$Id: manpath.c,v 1.35 2017/07/01 09:47:30 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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 <sys/types.h>
    +#include <sys/stat.h>
    +
    +#include <ctype.h>
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc_aux.h"
    +#include "manconf.h"
    +
    +static	void	 manconf_file(struct manconf *, const char *);
    +static	void	 manpath_add(struct manpaths *, const char *, int);
    +static	void	 manpath_parseline(struct manpaths *, char *, int);
    +
    +
    +void
    +manconf_parse(struct manconf *conf, const char *file,
    +		char *defp, char *auxp)
    +{
    +	char		*insert;
    +
    +	/* Always prepend -m. */
    +	manpath_parseline(&conf->manpath, auxp, 1);
    +
    +	/* If -M is given, it overrides everything else. */
    +	if (NULL != defp) {
    +		manpath_parseline(&conf->manpath, defp, 1);
    +		return;
    +	}
    +
    +	/* MANPATH and man.conf(5) cooperate. */
    +	defp = getenv("MANPATH");
    +	if (NULL == file)
    +		file = MAN_CONF_FILE;
    +
    +	/* No MANPATH; use man.conf(5) only. */
    +	if (NULL == defp || '\0' == defp[0]) {
    +		manconf_file(conf, file);
    +		return;
    +	}
    +
    +	/* Prepend man.conf(5) to MANPATH. */
    +	if (':' == defp[0]) {
    +		manconf_file(conf, file);
    +		manpath_parseline(&conf->manpath, defp, 0);
    +		return;
    +	}
    +
    +	/* Append man.conf(5) to MANPATH. */
    +	if (':' == defp[strlen(defp) - 1]) {
    +		manpath_parseline(&conf->manpath, defp, 0);
    +		manconf_file(conf, file);
    +		return;
    +	}
    +
    +	/* Insert man.conf(5) into MANPATH. */
    +	insert = strstr(defp, "::");
    +	if (NULL != insert) {
    +		*insert++ = '\0';
    +		manpath_parseline(&conf->manpath, defp, 0);
    +		manconf_file(conf, file);
    +		manpath_parseline(&conf->manpath, insert + 1, 0);
    +		return;
    +	}
    +
    +	/* MANPATH overrides man.conf(5) completely. */
    +	manpath_parseline(&conf->manpath, defp, 0);
    +}
    +
    +void
    +manpath_base(struct manpaths *dirs)
    +{
    +	char path_base[] = MANPATH_BASE;
    +	manpath_parseline(dirs, path_base, 0);
    +}
    +
    +/*
    + * Parse a FULL pathname from a colon-separated list of arrays.
    + */
    +static void
    +manpath_parseline(struct manpaths *dirs, char *path, int complain)
    +{
    +	char	*dir;
    +
    +	if (NULL == path)
    +		return;
    +
    +	for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
    +		manpath_add(dirs, dir, complain);
    +}
    +
    +/*
    + * Add a directory to the array, ignoring bad directories.
    + * Grow the array one-by-one for simplicity's sake.
    + */
    +static void
    +manpath_add(struct manpaths *dirs, const char *dir, int complain)
    +{
    +	char		 buf[PATH_MAX];
    +	struct stat	 sb;
    +	char		*cp;
    +	size_t		 i;
    +
    +	if (NULL == (cp = realpath(dir, buf))) {
    +		if (complain)
    +			warn("manpath: %s", dir);
    +		return;
    +	}
    +
    +	for (i = 0; i < dirs->sz; i++)
    +		if (0 == strcmp(dirs->paths[i], dir))
    +			return;
    +
    +	if (stat(cp, &sb) == -1) {
    +		if (complain)
    +			warn("manpath: %s", dir);
    +		return;
    +	}
    +
    +	dirs->paths = mandoc_reallocarray(dirs->paths,
    +	    dirs->sz + 1, sizeof(char *));
    +
    +	dirs->paths[dirs->sz++] = mandoc_strdup(cp);
    +}
    +
    +void
    +manconf_free(struct manconf *conf)
    +{
    +	size_t		 i;
    +
    +	for (i = 0; i < conf->manpath.sz; i++)
    +		free(conf->manpath.paths[i]);
    +
    +	free(conf->manpath.paths);
    +	free(conf->output.includes);
    +	free(conf->output.man);
    +	free(conf->output.paper);
    +	free(conf->output.style);
    +}
    +
    +static void
    +manconf_file(struct manconf *conf, const char *file)
    +{
    +	const char *const toks[] = { "manpath", "output", "_whatdb" };
    +	char manpath_default[] = MANPATH_DEFAULT;
    +
    +	FILE		*stream;
    +	char		*line, *cp, *ep;
    +	size_t		 linesz, tok, toklen;
    +	ssize_t		 linelen;
    +
    +	if ((stream = fopen(file, "r")) == NULL)
    +		goto out;
    +
    +	line = NULL;
    +	linesz = 0;
    +
    +	while ((linelen = getline(&line, &linesz, stream)) != -1) {
    +		cp = line;
    +		ep = cp + linelen - 1;
    +		while (ep > cp && isspace((unsigned char)*ep))
    +			*ep-- = '\0';
    +		while (isspace((unsigned char)*cp))
    +			cp++;
    +		if (cp == ep || *cp == '#')
    +			continue;
    +
    +		for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
    +			toklen = strlen(toks[tok]);
    +			if (cp + toklen < ep &&
    +			    isspace((unsigned char)cp[toklen]) &&
    +			    strncmp(cp, toks[tok], toklen) == 0) {
    +				cp += toklen;
    +				while (isspace((unsigned char)*cp))
    +					cp++;
    +				break;
    +			}
    +		}
    +
    +		switch (tok) {
    +		case 2:  /* _whatdb */
    +			while (ep > cp && ep[-1] != '/')
    +				ep--;
    +			if (ep == cp)
    +				continue;
    +			*ep = '\0';
    +			/* FALLTHROUGH */
    +		case 0:  /* manpath */
    +			manpath_add(&conf->manpath, cp, 0);
    +			*manpath_default = '\0';
    +			break;
    +		case 1:  /* output */
    +			manconf_output(&conf->output, cp, 1);
    +			break;
    +		default:
    +			break;
    +		}
    +	}
    +	free(line);
    +	fclose(stream);
    +
    +out:
    +	if (*manpath_default != '\0')
    +		manpath_parseline(&conf->manpath, manpath_default, 0);
    +}
    +
    +int
    +manconf_output(struct manoutput *conf, const char *cp, int fromfile)
    +{
    +	const char *const toks[] = {
    +	    "includes", "man", "paper", "style",
    +	    "indent", "width", "fragment", "mdoc", "noval"
    +	};
    +
    +	const char	*errstr;
    +	char		*oldval;
    +	size_t		 len, tok;
    +
    +	for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
    +		len = strlen(toks[tok]);
    +		if ( ! strncmp(cp, toks[tok], len) &&
    +		    strchr(" =	", cp[len]) != NULL) {
    +			cp += len;
    +			if (*cp == '=')
    +				cp++;
    +			while (isspace((unsigned char)*cp))
    +				cp++;
    +			break;
    +		}
    +	}
    +
    +	if (tok < 6 && *cp == '\0') {
    +		warnx("-O %s=?: Missing argument value", toks[tok]);
    +		return -1;
    +	}
    +	if ((tok == 6 || tok == 7) && *cp != '\0') {
    +		warnx("-O %s: Does not take a value: %s", toks[tok], cp);
    +		return -1;
    +	}
    +
    +	switch (tok) {
    +	case 0:
    +		if (conf->includes != NULL) {
    +			oldval = mandoc_strdup(conf->includes);
    +			break;
    +		}
    +		conf->includes = mandoc_strdup(cp);
    +		return 0;
    +	case 1:
    +		if (conf->man != NULL) {
    +			oldval = mandoc_strdup(conf->man);
    +			break;
    +		}
    +		conf->man = mandoc_strdup(cp);
    +		return 0;
    +	case 2:
    +		if (conf->paper != NULL) {
    +			oldval = mandoc_strdup(conf->paper);
    +			break;
    +		}
    +		conf->paper = mandoc_strdup(cp);
    +		return 0;
    +	case 3:
    +		if (conf->style != NULL) {
    +			oldval = mandoc_strdup(conf->style);
    +			break;
    +		}
    +		conf->style = mandoc_strdup(cp);
    +		return 0;
    +	case 4:
    +		if (conf->indent) {
    +			mandoc_asprintf(&oldval, "%zu", conf->indent);
    +			break;
    +		}
    +		conf->indent = strtonum(cp, 0, 1000, &errstr);
    +		if (errstr == NULL)
    +			return 0;
    +		warnx("-O indent=%s is %s", cp, errstr);
    +		return -1;
    +	case 5:
    +		if (conf->width) {
    +			mandoc_asprintf(&oldval, "%zu", conf->width);
    +			break;
    +		}
    +		conf->width = strtonum(cp, 1, 1000, &errstr);
    +		if (errstr == NULL)
    +			return 0;
    +		warnx("-O width=%s is %s", cp, errstr);
    +		return -1;
    +	case 6:
    +		conf->fragment = 1;
    +		return 0;
    +	case 7:
    +		conf->mdoc = 1;
    +		return 0;
    +	case 8:
    +		conf->noval = 1;
    +		return 0;
    +	default:
    +		if (fromfile)
    +			warnx("-O %s: Bad argument", cp);
    +		return -1;
    +	}
    +	if (fromfile == 0)
    +		warnx("-O %s=%s: Option already set to %s",
    +		    toks[tok], cp, oldval);
    +	free(oldval);
    +	return -1;
    +}
    
    Property changes on: head/contrib/mandoc/manpath.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/msec.in
    ===================================================================
    --- head/contrib/mandoc/msec.in	(nonexistent)
    +++ head/contrib/mandoc/msec.in	(revision 338826)
    @@ -0,0 +1,34 @@
    +/*	$Id: msec.in,v 1.6 2010/06/19 20:46:28 kristaps Exp $ */
    +/*
    + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +/*
    + * These are all possible manual-section macros and what they correspond
    + * to when rendered as the volume title.
    + *
    + * Be sure to escape strings.
    + */
    +
    +LINE("1",		"FreeBSD General Commands Manual")
    +LINE("2",		"FreeBSD System Calls Manual")
    +LINE("3",		"FreeBSD Library Functions Manual")
    +LINE("3p",		"Perl Library Functions Manual")
    +LINE("4",		"FreeBSD Kernel Interfaces Manual")
    +LINE("5",		"FreeBSD File Formats Manual")
    +LINE("6",		"FreeBSD Games Manual")
    +LINE("7",		"FreeBSD Miscellaneous Information Manual")
    +LINE("8",		"FreeBSD System Manager\'s Manual")
    +LINE("9",		"FreeBSD Kernel Developer\'s Manual")
    
    Property changes on: head/contrib/mandoc/msec.in
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/out.c
    ===================================================================
    --- head/contrib/mandoc/out.c	(nonexistent)
    +++ head/contrib/mandoc/out.c	(revision 338826)
    @@ -0,0 +1,369 @@
    +/*	$Id: out.c,v 1.70 2017/06/27 18:25:02 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "out.h"
    +
    +static	void	tblcalc_data(struct rofftbl *, struct roffcol *,
    +			const struct tbl_opts *, const struct tbl_dat *,
    +			size_t);
    +static	void	tblcalc_literal(struct rofftbl *, struct roffcol *,
    +			const struct tbl_dat *, size_t);
    +static	void	tblcalc_number(struct rofftbl *, struct roffcol *,
    +			const struct tbl_opts *, const struct tbl_dat *);
    +
    +
    +/*
    + * Parse the *src string and store a scaling unit into *dst.
    + * If the string doesn't specify the unit, use the default.
    + * If no default is specified, fail.
    + * Return a pointer to the byte after the last byte used,
    + * or NULL on total failure.
    + */
    +const char *
    +a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
    +{
    +	char		*endptr;
    +
    +	dst->unit = def == SCALE_MAX ? SCALE_BU : def;
    +	dst->scale = strtod(src, &endptr);
    +	if (endptr == src)
    +		return NULL;
    +
    +	switch (*endptr++) {
    +	case 'c':
    +		dst->unit = SCALE_CM;
    +		break;
    +	case 'i':
    +		dst->unit = SCALE_IN;
    +		break;
    +	case 'f':
    +		dst->unit = SCALE_FS;
    +		break;
    +	case 'M':
    +		dst->unit = SCALE_MM;
    +		break;
    +	case 'm':
    +		dst->unit = SCALE_EM;
    +		break;
    +	case 'n':
    +		dst->unit = SCALE_EN;
    +		break;
    +	case 'P':
    +		dst->unit = SCALE_PC;
    +		break;
    +	case 'p':
    +		dst->unit = SCALE_PT;
    +		break;
    +	case 'u':
    +		dst->unit = SCALE_BU;
    +		break;
    +	case 'v':
    +		dst->unit = SCALE_VS;
    +		break;
    +	default:
    +		endptr--;
    +		if (SCALE_MAX == def)
    +			return NULL;
    +		dst->unit = def;
    +		break;
    +	}
    +	return endptr;
    +}
    +
    +/*
    + * Calculate the abstract widths and decimal positions of columns in a
    + * table.  This routine allocates the columns structures then runs over
    + * all rows and cells in the table.  The function pointers in "tbl" are
    + * used for the actual width calculations.
    + */
    +void
    +tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
    +    size_t offset, size_t rmargin)
    +{
    +	struct roffsu		 su;
    +	const struct tbl_opts	*opts;
    +	const struct tbl_dat	*dp;
    +	struct roffcol		*col;
    +	size_t			 ewidth, xwidth;
    +	int			 spans;
    +	int			 icol, maxcol, necol, nxcol, quirkcol;
    +
    +	/*
    +	 * Allocate the master column specifiers.  These will hold the
    +	 * widths and decimal positions for all cells in the column.  It
    +	 * must be freed and nullified by the caller.
    +	 */
    +
    +	assert(NULL == tbl->cols);
    +	tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
    +	    sizeof(struct roffcol));
    +	opts = sp->opts;
    +
    +	for (maxcol = -1; sp; sp = sp->next) {
    +		if (TBL_SPAN_DATA != sp->pos)
    +			continue;
    +		spans = 1;
    +		/*
    +		 * Account for the data cells in the layout, matching it
    +		 * to data cells in the data section.
    +		 */
    +		for (dp = sp->first; dp; dp = dp->next) {
    +			/* Do not used spanned cells in the calculation. */
    +			if (0 < --spans)
    +				continue;
    +			spans = dp->spans;
    +			if (1 < spans)
    +				continue;
    +			icol = dp->layout->col;
    +			while (maxcol < icol)
    +				tbl->cols[++maxcol].spacing = SIZE_MAX;
    +			col = tbl->cols + icol;
    +			col->flags |= dp->layout->flags;
    +			if (dp->layout->flags & TBL_CELL_WIGN)
    +				continue;
    +			if (dp->layout->wstr != NULL &&
    +			    dp->layout->width == 0 &&
    +			    a2roffsu(dp->layout->wstr, &su, SCALE_EN)
    +			    != NULL)
    +				dp->layout->width =
    +				    (*tbl->sulen)(&su, tbl->arg);
    +			if (col->width < dp->layout->width)
    +				col->width = dp->layout->width;
    +			if (dp->layout->spacing != SIZE_MAX &&
    +			    (col->spacing == SIZE_MAX ||
    +			     col->spacing < dp->layout->spacing))
    +				col->spacing = dp->layout->spacing;
    +			tblcalc_data(tbl, col, opts, dp,
    +			    dp->block == 0 ? 0 :
    +			    dp->layout->width ? dp->layout->width :
    +			    rmargin ? (rmargin + sp->opts->cols / 2)
    +			    / (sp->opts->cols + 1) : 0);
    +		}
    +	}
    +
    +	/*
    +	 * Count columns to equalize and columns to maximize.
    +	 * Find maximum width of the columns to equalize.
    +	 * Find total width of the columns *not* to maximize.
    +	 */
    +
    +	necol = nxcol = 0;
    +	ewidth = xwidth = 0;
    +	for (icol = 0; icol <= maxcol; icol++) {
    +		col = tbl->cols + icol;
    +		if (col->spacing == SIZE_MAX || icol == maxcol)
    +			col->spacing = 3;
    +		if (col->flags & TBL_CELL_EQUAL) {
    +			necol++;
    +			if (ewidth < col->width)
    +				ewidth = col->width;
    +		}
    +		if (col->flags & TBL_CELL_WMAX)
    +			nxcol++;
    +		else
    +			xwidth += col->width;
    +	}
    +
    +	/*
    +	 * Equalize columns, if requested for any of them.
    +	 * Update total width of the columns not to maximize.
    +	 */
    +
    +	if (necol) {
    +		for (icol = 0; icol <= maxcol; icol++) {
    +			col = tbl->cols + icol;
    +			if ( ! (col->flags & TBL_CELL_EQUAL))
    +				continue;
    +			if (col->width == ewidth)
    +				continue;
    +			if (nxcol && rmargin)
    +				xwidth += ewidth - col->width;
    +			col->width = ewidth;
    +		}
    +	}
    +
    +	/*
    +	 * If there are any columns to maximize, find the total
    +	 * available width, deducting 3n margins between columns.
    +	 * Distribute the available width evenly.
    +	 */
    +
    +	if (nxcol && rmargin) {
    +		xwidth += 3*maxcol +
    +		    (opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
    +		     2 : !!opts->lvert + !!opts->rvert);
    +		if (rmargin <= offset + xwidth)
    +			return;
    +		xwidth = rmargin - offset - xwidth;
    +
    +		/*
    +		 * Emulate a bug in GNU tbl width calculation that
    +		 * manifests itself for large numbers of x-columns.
    +		 * Emulating it for 5 x-columns gives identical
    +		 * behaviour for up to 6 x-columns.
    +		 */
    +
    +		if (nxcol == 5) {
    +			quirkcol = xwidth % nxcol + 2;
    +			if (quirkcol != 3 && quirkcol != 4)
    +				quirkcol = -1;
    +		} else
    +			quirkcol = -1;
    +
    +		necol = 0;
    +		ewidth = 0;
    +		for (icol = 0; icol <= maxcol; icol++) {
    +			col = tbl->cols + icol;
    +			if ( ! (col->flags & TBL_CELL_WMAX))
    +				continue;
    +			col->width = (double)xwidth * ++necol / nxcol
    +			    - ewidth + 0.4995;
    +			if (necol == quirkcol)
    +				col->width--;
    +			ewidth += col->width;
    +		}
    +	}
    +}
    +
    +static void
    +tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
    +    const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw)
    +{
    +	size_t		 sz;
    +
    +	/* Branch down into data sub-types. */
    +
    +	switch (dp->layout->pos) {
    +	case TBL_CELL_HORIZ:
    +	case TBL_CELL_DHORIZ:
    +		sz = (*tbl->len)(1, tbl->arg);
    +		if (col->width < sz)
    +			col->width = sz;
    +		break;
    +	case TBL_CELL_LONG:
    +	case TBL_CELL_CENTRE:
    +	case TBL_CELL_LEFT:
    +	case TBL_CELL_RIGHT:
    +		tblcalc_literal(tbl, col, dp, mw);
    +		break;
    +	case TBL_CELL_NUMBER:
    +		tblcalc_number(tbl, col, opts, dp);
    +		break;
    +	case TBL_CELL_DOWN:
    +		break;
    +	default:
    +		abort();
    +	}
    +}
    +
    +static void
    +tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
    +    const struct tbl_dat *dp, size_t mw)
    +{
    +	const char	*str;	/* Beginning of the first line. */
    +	const char	*beg;	/* Beginning of the current line. */
    +	char		*end;	/* End of the current line. */
    +	size_t		 lsz;	/* Length of the current line. */
    +	size_t		 wsz;	/* Length of the current word. */
    +
    +	if (dp->string == NULL || *dp->string == '\0')
    +		return;
    +	str = mw ? mandoc_strdup(dp->string) : dp->string;
    +	lsz = 0;
    +	for (beg = str; beg != NULL && *beg != '\0'; beg = end) {
    +		end = mw ? strchr(beg, ' ') : NULL;
    +		if (end != NULL) {
    +			*end++ = '\0';
    +			while (*end == ' ')
    +				end++;
    +		}
    +		wsz = (*tbl->slen)(beg, tbl->arg);
    +		if (mw && lsz && lsz + 1 + wsz <= mw)
    +			lsz += 1 + wsz;
    +		else
    +			lsz = wsz;
    +		if (col->width < lsz)
    +			col->width = lsz;
    +	}
    +	if (mw)
    +		free((void *)str);
    +}
    +
    +static void
    +tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
    +		const struct tbl_opts *opts, const struct tbl_dat *dp)
    +{
    +	int		 i;
    +	size_t		 sz, psz, ssz, d;
    +	const char	*str;
    +	char		*cp;
    +	char		 buf[2];
    +
    +	/*
    +	 * First calculate number width and decimal place (last + 1 for
    +	 * non-decimal numbers).  If the stored decimal is subsequent to
    +	 * ours, make our size longer by that difference
    +	 * (right-"shifting"); similarly, if ours is subsequent the
    +	 * stored, then extend the stored size by the difference.
    +	 * Finally, re-assign the stored values.
    +	 */
    +
    +	str = dp->string ? dp->string : "";
    +	sz = (*tbl->slen)(str, tbl->arg);
    +
    +	/* FIXME: TBL_DATA_HORIZ et al.? */
    +
    +	buf[0] = opts->decimal;
    +	buf[1] = '\0';
    +
    +	psz = (*tbl->slen)(buf, tbl->arg);
    +
    +	if (NULL != (cp = strrchr(str, opts->decimal))) {
    +		buf[1] = '\0';
    +		for (ssz = 0, i = 0; cp != &str[i]; i++) {
    +			buf[0] = str[i];
    +			ssz += (*tbl->slen)(buf, tbl->arg);
    +		}
    +		d = ssz + psz;
    +	} else
    +		d = sz + psz;
    +
    +	/* Adjust the settings for this column. */
    +
    +	if (col->decimal > d) {
    +		sz += col->decimal - d;
    +		d = col->decimal;
    +	} else
    +		col->width += d - col->decimal;
    +
    +	if (sz > col->width)
    +		col->width = sz;
    +	if (d > col->decimal)
    +		col->decimal = d;
    +}
    
    Property changes on: head/contrib/mandoc/out.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/roff_int.h
    ===================================================================
    --- head/contrib/mandoc/roff_int.h	(nonexistent)
    +++ head/contrib/mandoc/roff_int.h	(revision 338826)
    @@ -0,0 +1,39 @@
    +/*	$Id: roff_int.h,v 1.9 2017/07/08 17:52:50 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +struct roff_node *roff_node_alloc(struct roff_man *, int, int,
    +			enum roff_type, int);
    +void		  roff_node_append(struct roff_man *, struct roff_node *);
    +void		  roff_word_alloc(struct roff_man *, int, int, const char *);
    +void		  roff_word_append(struct roff_man *, const char *);
    +void		  roff_elem_alloc(struct roff_man *, int, int, int);
    +struct roff_node *roff_block_alloc(struct roff_man *, int, int, int);
    +struct roff_node *roff_head_alloc(struct roff_man *, int, int, int);
    +struct roff_node *roff_body_alloc(struct roff_man *, int, int, int);
    +void		  roff_node_unlink(struct roff_man *, struct roff_node *);
    +void		  roff_node_free(struct roff_node *);
    +void		  roff_node_delete(struct roff_man *, struct roff_node *);
    +
    +/*
    + * Functions called from roff.c need to be declared here,
    + * not in libmdoc.h or libman.h, even if they are specific
    + * to either the mdoc(7) or the man(7) parser.
    + */
    +
    +void		  man_breakscope(struct roff_man *, int);
    +void		  mdoc_argv_free(struct mdoc_arg *);
    
    Property changes on: head/contrib/mandoc/roff_int.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/roff_term.c
    ===================================================================
    --- head/contrib/mandoc/roff_term.c	(nonexistent)
    +++ head/contrib/mandoc/roff_term.c	(revision 338826)
    @@ -0,0 +1,248 @@
    +/*	$Id: roff_term.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */
    +/*
    + * Copyright (c) 2010, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <stddef.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "out.h"
    +#include "term.h"
    +
    +#define	ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
    +
    +typedef	void	(*roff_term_pre_fp)(ROFF_TERM_ARGS);
    +
    +static	void	  roff_term_pre_br(ROFF_TERM_ARGS);
    +static	void	  roff_term_pre_ce(ROFF_TERM_ARGS);
    +static	void	  roff_term_pre_ft(ROFF_TERM_ARGS);
    +static	void	  roff_term_pre_ll(ROFF_TERM_ARGS);
    +static	void	  roff_term_pre_mc(ROFF_TERM_ARGS);
    +static	void	  roff_term_pre_po(ROFF_TERM_ARGS);
    +static	void	  roff_term_pre_sp(ROFF_TERM_ARGS);
    +static	void	  roff_term_pre_ta(ROFF_TERM_ARGS);
    +static	void	  roff_term_pre_ti(ROFF_TERM_ARGS);
    +
    +static	const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
    +	roff_term_pre_br,  /* br */
    +	roff_term_pre_ce,  /* ce */
    +	roff_term_pre_ft,  /* ft */
    +	roff_term_pre_ll,  /* ll */
    +	roff_term_pre_mc,  /* mc */
    +	roff_term_pre_po,  /* po */
    +	roff_term_pre_ce,  /* rj */
    +	roff_term_pre_sp,  /* sp */
    +	roff_term_pre_ta,  /* ta */
    +	roff_term_pre_ti,  /* ti */
    +};
    +
    +
    +void
    +roff_term_pre(struct termp *p, const struct roff_node *n)
    +{
    +	assert(n->tok < ROFF_MAX);
    +	(*roff_term_pre_acts[n->tok])(p, n);
    +}
    +
    +static void
    +roff_term_pre_br(ROFF_TERM_ARGS)
    +{
    +	term_newln(p);
    +	if (p->flags & TERMP_BRIND) {
    +		p->tcol->offset = p->tcol->rmargin;
    +		p->tcol->rmargin = p->maxrmargin;
    +		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
    +	}
    +}
    +
    +static void
    +roff_term_pre_ce(ROFF_TERM_ARGS)
    +{
    +	const struct roff_node	*nc1, *nc2;
    +	size_t			 len, lm;
    +
    +	roff_term_pre_br(p, n);
    +	lm = p->tcol->offset;
    +	nc1 = n->child->next;
    +	while (nc1 != NULL) {
    +		nc2 = nc1;
    +		len = 0;
    +		do {
    +			if (nc2->type == ROFFT_TEXT) {
    +				if (len)
    +					len++;
    +				len += term_strlen(p, nc2->string);
    +			}
    +			nc2 = nc2->next;
    +		} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
    +		    (nc2->flags & NODE_LINE) == 0));
    +		p->tcol->offset = len >= p->tcol->rmargin ? 0 :
    +		    lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len :
    +		    n->tok == ROFF_rj ? p->tcol->rmargin - len :
    +		    (lm + p->tcol->rmargin - len) / 2;
    +		while (nc1 != nc2) {
    +			if (nc1->type == ROFFT_TEXT)
    +				term_word(p, nc1->string);
    +			else
    +				roff_term_pre(p, nc1);
    +			nc1 = nc1->next;
    +		}
    +		p->flags |= TERMP_NOSPACE;
    +		term_flushln(p);
    +	}
    +	p->tcol->offset = lm;
    +}
    +
    +static void
    +roff_term_pre_ft(ROFF_TERM_ARGS)
    +{
    +	switch (*n->child->string) {
    +	case '4':
    +	case '3':
    +	case 'B':
    +		term_fontrepl(p, TERMFONT_BOLD);
    +		break;
    +	case '2':
    +	case 'I':
    +		term_fontrepl(p, TERMFONT_UNDER);
    +		break;
    +	case 'P':
    +		term_fontlast(p);
    +		break;
    +	case '1':
    +	case 'C':
    +	case 'R':
    +		term_fontrepl(p, TERMFONT_NONE);
    +		break;
    +	default:
    +		break;
    +	}
    +}
    +
    +static void
    +roff_term_pre_ll(ROFF_TERM_ARGS)
    +{
    +	term_setwidth(p, n->child != NULL ? n->child->string : NULL);
    +}
    +
    +static void
    +roff_term_pre_mc(ROFF_TERM_ARGS)
    +{
    +	if (p->col) {
    +		p->flags |= TERMP_NOBREAK;
    +		term_flushln(p);
    +		p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
    +	}
    +	if (n->child != NULL) {
    +		p->mc = n->child->string;
    +		p->flags |= TERMP_NEWMC;
    +	} else
    +		p->flags |= TERMP_ENDMC;
    +}
    +
    +static void
    +roff_term_pre_po(ROFF_TERM_ARGS)
    +{
    +	struct roffsu	 su;
    +	static int	 po, polast;
    +	int		 ponew;
    +
    +	if (n->child != NULL &&
    +	    a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
    +		ponew = term_hen(p, &su);
    +		if (*n->child->string == '+' ||
    +		    *n->child->string == '-')
    +			ponew += po;
    +	} else
    +		ponew = polast;
    +	polast = po;
    +	po = ponew;
    +
    +	ponew = po - polast + (int)p->tcol->offset;
    +	p->tcol->offset = ponew > 0 ? ponew : 0;
    +}
    +
    +static void
    +roff_term_pre_sp(ROFF_TERM_ARGS)
    +{
    +	struct roffsu	 su;
    +	int		 len;
    +
    +	if (n->child != NULL) {
    +		if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
    +			su.scale = 1.0;
    +		len = term_vspan(p, &su);
    +	} else
    +		len = 1;
    +
    +	if (len < 0)
    +		p->skipvsp -= len;
    +	else
    +		while (len--)
    +			term_vspace(p);
    +
    +	roff_term_pre_br(p, n);
    +}
    +
    +static void
    +roff_term_pre_ta(ROFF_TERM_ARGS)
    +{
    +	term_tab_set(p, NULL);
    +	for (n = n->child; n != NULL; n = n->next)
    +		term_tab_set(p, n->string);
    +}
    +
    +static void
    +roff_term_pre_ti(ROFF_TERM_ARGS)
    +{
    +	struct roffsu	 su;
    +	const char	*cp;
    +	int		 len, sign;
    +
    +	roff_term_pre_br(p, n);
    +
    +	if (n->child == NULL)
    +		return;
    +	cp = n->child->string;
    +	if (*cp == '+') {
    +		sign = 1;
    +		cp++;
    +	} else if (*cp == '-') {
    +		sign = -1;
    +		cp++;
    +	} else
    +		sign = 0;
    +
    +	if (a2roffsu(cp, &su, SCALE_EM) == NULL)
    +		return;
    +	len = term_hen(p, &su);
    +
    +	if (sign == 0) {
    +		p->ti = len - p->tcol->offset;
    +		p->tcol->offset = len;
    +	} else if (sign == 1) {
    +		p->ti = len;
    +		p->tcol->offset += len;
    +	} else if ((size_t)len < p->tcol->offset) {
    +		p->ti = -len;
    +		p->tcol->offset -= len;
    +	} else {
    +		p->ti = -p->tcol->offset;
    +		p->tcol->offset = 0;
    +	}
    +}
    
    Property changes on: head/contrib/mandoc/roff_term.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/roff_validate.c
    ===================================================================
    --- head/contrib/mandoc/roff_validate.c	(nonexistent)
    +++ head/contrib/mandoc/roff_validate.c	(revision 338826)
    @@ -0,0 +1,97 @@
    +/*	$Id: roff_validate.c,v 1.9 2017/06/14 22:51:25 schwarze Exp $ */
    +/*
    + * Copyright (c) 2010, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <stddef.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "libmandoc.h"
    +#include "roff_int.h"
    +
    +#define	ROFF_VALID_ARGS struct roff_man *man, struct roff_node *n
    +
    +typedef	void	(*roff_valid_fp)(ROFF_VALID_ARGS);
    +
    +static	void	  roff_valid_ft(ROFF_VALID_ARGS);
    +
    +static	const roff_valid_fp roff_valids[ROFF_MAX] = {
    +	NULL,  /* br */
    +	NULL,  /* ce */
    +	roff_valid_ft,  /* ft */
    +	NULL,  /* ll */
    +	NULL,  /* mc */
    +	NULL,  /* po */
    +	NULL,  /* rj */
    +	NULL,  /* sp */
    +	NULL,  /* ta */
    +	NULL,  /* ti */
    +};
    +
    +
    +void
    +roff_validate(struct roff_man *man)
    +{
    +	struct roff_node	*n;
    +
    +	n = man->last;
    +	assert(n->tok < ROFF_MAX);
    +	if (roff_valids[n->tok] != NULL)
    +		(*roff_valids[n->tok])(man, n);
    +}
    +
    +static void
    +roff_valid_ft(ROFF_VALID_ARGS)
    +{
    +	char	*cp;
    +
    +	if (n->child == NULL) {
    +		man->next = ROFF_NEXT_CHILD;
    +		roff_word_alloc(man, n->line, n->pos, "P");
    +		man->last = n;
    +		return;
    +	}
    +
    +	cp = n->child->string;
    +	switch (*cp) {
    +	case '1':
    +	case '2':
    +	case '3':
    +	case '4':
    +	case 'I':
    +	case 'P':
    +	case 'R':
    +		if (cp[1] == '\0')
    +			return;
    +		break;
    +	case 'B':
    +		if (cp[1] == '\0' || (cp[1] == 'I' && cp[2] == '\0'))
    +			return;
    +		break;
    +	case 'C':
    +		if (cp[1] == 'W' && cp[2] == '\0')
    +			return;
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
    +	    n->line, n->pos, "ft %s", cp);
    +	roff_node_delete(man, n);
    +}
    
    Property changes on: head/contrib/mandoc/roff_validate.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/soelim.1
    ===================================================================
    --- head/contrib/mandoc/soelim.1	(nonexistent)
    +++ head/contrib/mandoc/soelim.1	(revision 338826)
    @@ -0,0 +1,86 @@
    +.\"	$Id: soelim.1,v 1.5 2017/07/04 23:40:01 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
    +.\" All rights reserved.
    +.\"
    +.\" Redistribution and use in source and binary forms, with or without
    +.\" modification, are permitted provided that the following conditions
    +.\" are met:
    +.\" 1. Redistributions of source code must retain the above copyright
    +.\"    notice, this list of conditions and the following disclaimer.
    +.\" 2. Redistributions in binary form must reproduce the above copyright
    +.\"    notice, this list of conditions and the following disclaimer in the
    +.\"    documentation and/or other materials provided with the distribution.
    +.\"
    +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    +.\" SUCH DAMAGE.
    +.\"
    +.Dd $Mdocdate: July 4 2017 $
    +.Dt SOELIM 1
    +.Os
    +.Sh NAME
    +.Nm soelim
    +.Nd interpret .so requests in manpages
    +.Sh SYNOPSIS
    +.Nm
    +.Op Fl Crtv
    +.Op Fl I Ar dir
    +.Op Ar files ...
    +.Sh DESCRIPTION
    +.Nm
    +reads
    +.Ar files
    +lines by lines.
    +.Pp
    +If a line starts by:
    +.Dq .so anotherfile
    +it replace the line by processing
    +.Dq anotherfile .
    +Otherwise the line is printed to stdout.
    +.Bl -tag -width "-I dir"
    +.It Fl C
    +Recognise
    +.Em .so
    +when not followed by a space character.
    +.It Fl r
    +Compatibility with GNU groff's
    +.Nm soelim
    +(does nothing).
    +.It Fl t
    +Compatibility with GNU groff's
    +.Nm soelim
    +(does nothing).
    +.It Fl v
    +Compatibility with GNU groff's
    +.Nm soelim
    +(does nothing).
    +.It Fl I Ar dir
    +This option specify directories where
    +.Nm
    +searches for files (both those on the command line and those named in
    +.Dq .so
    +directive.)
    +This options may be specified multiple times.
    +The directories will be searched in the order specified.
    +.El
    +.Pp
    +The files are always searched first in the current directory.
    +.Pp
    +A file specified with an absolute path will be opened directly without
    +performing a search.
    +.Sh SEE ALSO
    +.Xr mandoc 1
    +.Sh AUTHORS
    +This version of the
    +.Nm
    +utility was written by
    +.An Baptiste Daroussin Aq Mt bapt@freebsd.org .
    
    Property changes on: head/contrib/mandoc/soelim.1
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/st.c
    ===================================================================
    --- head/contrib/mandoc/st.c	(nonexistent)
    +++ head/contrib/mandoc/st.c	(revision 338826)
    @@ -0,0 +1,38 @@
    +/*	$Id: st.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "libmdoc.h"
    +
    +#define LINE(x, y) \
    +	if (0 == strcmp(p, x)) return(y);
    +
    +const char *
    +mdoc_a2st(const char *p)
    +{
    +
    +#include "st.in"
    +
    +	return NULL;
    +}
    
    Property changes on: head/contrib/mandoc/st.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tbl.c
    ===================================================================
    --- head/contrib/mandoc/tbl.c	(nonexistent)
    +++ head/contrib/mandoc/tbl.c	(revision 338826)
    @@ -0,0 +1,179 @@
    +/*	$Id: tbl.c,v 1.42 2017/07/08 17:52:50 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#include "mandoc.h"
    +#include "mandoc_aux.h"
    +#include "libmandoc.h"
    +#include "libroff.h"
    +
    +
    +void
    +tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
    +{
    +	const char	*cp;
    +	int		 active;
    +
    +	/*
    +	 * In the options section, proceed to the layout section
    +	 * after a semicolon, or right away if there is no semicolon.
    +	 * Ignore semicolons in arguments.
    +	 */
    +
    +	if (tbl->part == TBL_PART_OPTS) {
    +		tbl->part = TBL_PART_LAYOUT;
    +		active = 1;
    +		for (cp = p + pos; *cp != '\0'; cp++) {
    +			switch (*cp) {
    +			case '(':
    +				active = 0;
    +				continue;
    +			case ')':
    +				active = 1;
    +				continue;
    +			case ';':
    +				if (active)
    +					break;
    +				continue;
    +			default:
    +				continue;
    +			}
    +			break;
    +		}
    +		if (*cp == ';') {
    +			tbl_option(tbl, ln, p, &pos);
    +			if (p[pos] == '\0')
    +				return;
    +		}
    +	}
    +
    +	/* Process the other section types.  */
    +
    +	switch (tbl->part) {
    +	case TBL_PART_LAYOUT:
    +		tbl_layout(tbl, ln, p, pos);
    +		break;
    +	case TBL_PART_CDATA:
    +		tbl_cdata(tbl, ln, p, pos);
    +		break;
    +	default:
    +		tbl_data(tbl, ln, p, pos);
    +		break;
    +	}
    +}
    +
    +struct tbl_node *
    +tbl_alloc(int pos, int line, struct mparse *parse)
    +{
    +	struct tbl_node	*tbl;
    +
    +	tbl = mandoc_calloc(1, sizeof(*tbl));
    +	tbl->line = line;
    +	tbl->pos = pos;
    +	tbl->parse = parse;
    +	tbl->part = TBL_PART_OPTS;
    +	tbl->opts.tab = '\t';
    +	tbl->opts.decimal = '.';
    +	return tbl;
    +}
    +
    +void
    +tbl_free(struct tbl_node *tbl)
    +{
    +	struct tbl_row	*rp;
    +	struct tbl_cell	*cp;
    +	struct tbl_span	*sp;
    +	struct tbl_dat	*dp;
    +
    +	while ((rp = tbl->first_row) != NULL) {
    +		tbl->first_row = rp->next;
    +		while (rp->first != NULL) {
    +			cp = rp->first;
    +			rp->first = cp->next;
    +			free(cp->wstr);
    +			free(cp);
    +		}
    +		free(rp);
    +	}
    +
    +	while ((sp = tbl->first_span) != NULL) {
    +		tbl->first_span = sp->next;
    +		while (sp->first != NULL) {
    +			dp = sp->first;
    +			sp->first = dp->next;
    +			free(dp->string);
    +			free(dp);
    +		}
    +		free(sp);
    +	}
    +
    +	free(tbl);
    +}
    +
    +void
    +tbl_restart(int line, int pos, struct tbl_node *tbl)
    +{
    +	if (tbl->part == TBL_PART_CDATA)
    +		mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
    +		    line, pos, "T&");
    +
    +	tbl->part = TBL_PART_LAYOUT;
    +	tbl->line = line;
    +	tbl->pos = pos;
    +}
    +
    +const struct tbl_span *
    +tbl_span(struct tbl_node *tbl)
    +{
    +	struct tbl_span	 *span;
    +
    +	assert(tbl);
    +	span = tbl->current_span ? tbl->current_span->next
    +				 : tbl->first_span;
    +	if (span)
    +		tbl->current_span = span;
    +	return span;
    +}
    +
    +int
    +tbl_end(struct tbl_node *tbl)
    +{
    +	struct tbl_span *sp;
    +
    +	if (tbl->part == TBL_PART_CDATA)
    +		mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
    +		    tbl->line, tbl->pos, "TE");
    +
    +	sp = tbl->first_span;
    +	while (sp != NULL && sp->first == NULL)
    +		sp = sp->next;
    +	if (sp == NULL) {
    +		mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->parse,
    +		    tbl->line, tbl->pos, NULL);
    +		return 0;
    +	}
    +	return 1;
    +}
    
    Property changes on: head/contrib/mandoc/tbl.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tbl_data.c
    ===================================================================
    --- head/contrib/mandoc/tbl_data.c	(nonexistent)
    +++ head/contrib/mandoc/tbl_data.c	(revision 338826)
    @@ -0,0 +1,241 @@
    +/*	$Id: tbl_data.c,v 1.45 2017/07/08 17:52:50 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#include "mandoc.h"
    +#include "mandoc_aux.h"
    +#include "libmandoc.h"
    +#include "libroff.h"
    +
    +static	void		 getdata(struct tbl_node *, struct tbl_span *,
    +				int, const char *, int *);
    +static	struct tbl_span	*newspan(struct tbl_node *, int,
    +				struct tbl_row *);
    +
    +
    +static void
    +getdata(struct tbl_node *tbl, struct tbl_span *dp,
    +		int ln, const char *p, int *pos)
    +{
    +	struct tbl_dat	*dat;
    +	struct tbl_cell	*cp;
    +	int		 sv;
    +
    +	/* Advance to the next layout cell, skipping spanners. */
    +
    +	cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
    +	while (cp != NULL && cp->pos == TBL_CELL_SPAN)
    +		cp = cp->next;
    +
    +	/*
    +	 * If the current layout row is out of cells, allocate
    +	 * a new cell if another row of the table has at least
    +	 * this number of columns, or discard the input if we
    +	 * are beyond the last column of the table as a whole.
    +	 */
    +
    +	if (cp == NULL) {
    +		if (dp->layout->last->col + 1 < dp->opts->cols) {
    +			cp = mandoc_calloc(1, sizeof(*cp));
    +			cp->pos = TBL_CELL_LEFT;
    +			dp->layout->last->next = cp;
    +			cp->col = dp->layout->last->col + 1;
    +			dp->layout->last = cp;
    +		} else {
    +			mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
    +			    ln, *pos, p + *pos);
    +			while (p[*pos])
    +				(*pos)++;
    +			return;
    +		}
    +	}
    +
    +	dat = mandoc_calloc(1, sizeof(*dat));
    +	dat->layout = cp;
    +	dat->pos = TBL_DATA_NONE;
    +	dat->spans = 0;
    +	for (cp = cp->next; cp != NULL; cp = cp->next)
    +		if (cp->pos == TBL_CELL_SPAN)
    +			dat->spans++;
    +		else
    +			break;
    +
    +	if (dp->last == NULL)
    +		dp->first = dat;
    +	else
    +		dp->last->next = dat;
    +	dp->last = dat;
    +
    +	sv = *pos;
    +	while (p[*pos] && p[*pos] != tbl->opts.tab)
    +		(*pos)++;
    +
    +	/*
    +	 * Check for a continued-data scope opening.  This consists of a
    +	 * trailing `T{' at the end of the line.  Subsequent lines,
    +	 * until a standalone `T}', are included in our cell.
    +	 */
    +
    +	if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
    +		tbl->part = TBL_PART_CDATA;
    +		return;
    +	}
    +
    +	dat->string = mandoc_strndup(p + sv, *pos - sv);
    +
    +	if (p[*pos])
    +		(*pos)++;
    +
    +	if ( ! strcmp(dat->string, "_"))
    +		dat->pos = TBL_DATA_HORIZ;
    +	else if ( ! strcmp(dat->string, "="))
    +		dat->pos = TBL_DATA_DHORIZ;
    +	else if ( ! strcmp(dat->string, "\\_"))
    +		dat->pos = TBL_DATA_NHORIZ;
    +	else if ( ! strcmp(dat->string, "\\="))
    +		dat->pos = TBL_DATA_NDHORIZ;
    +	else
    +		dat->pos = TBL_DATA_DATA;
    +
    +	if ((dat->layout->pos == TBL_CELL_HORIZ ||
    +	    dat->layout->pos == TBL_CELL_DHORIZ ||
    +	    dat->layout->pos == TBL_CELL_DOWN) &&
    +	    dat->pos == TBL_DATA_DATA && *dat->string != '\0')
    +		mandoc_msg(MANDOCERR_TBLDATA_SPAN,
    +		    tbl->parse, ln, sv, dat->string);
    +}
    +
    +void
    +tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
    +{
    +	struct tbl_dat	*dat;
    +	size_t		 sz;
    +
    +	dat = tbl->last_span->last;
    +
    +	if (p[pos] == 'T' && p[pos + 1] == '}') {
    +		pos += 2;
    +		if (p[pos] == tbl->opts.tab) {
    +			tbl->part = TBL_PART_DATA;
    +			pos++;
    +			while (p[pos] != '\0')
    +				getdata(tbl, tbl->last_span, ln, p, &pos);
    +			return;
    +		} else if (p[pos] == '\0') {
    +			tbl->part = TBL_PART_DATA;
    +			return;
    +		}
    +
    +		/* Fallthrough: T} is part of a word. */
    +	}
    +
    +	dat->pos = TBL_DATA_DATA;
    +	dat->block = 1;
    +
    +	if (dat->string != NULL) {
    +		sz = strlen(p + pos) + strlen(dat->string) + 2;
    +		dat->string = mandoc_realloc(dat->string, sz);
    +		(void)strlcat(dat->string, " ", sz);
    +		(void)strlcat(dat->string, p + pos, sz);
    +	} else
    +		dat->string = mandoc_strdup(p + pos);
    +
    +	if (dat->layout->pos == TBL_CELL_DOWN)
    +		mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
    +		    ln, pos, dat->string);
    +}
    +
    +static struct tbl_span *
    +newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
    +{
    +	struct tbl_span	*dp;
    +
    +	dp = mandoc_calloc(1, sizeof(*dp));
    +	dp->line = line;
    +	dp->opts = &tbl->opts;
    +	dp->layout = rp;
    +	dp->prev = tbl->last_span;
    +
    +	if (dp->prev == NULL) {
    +		tbl->first_span = dp;
    +		tbl->current_span = NULL;
    +	} else
    +		dp->prev->next = dp;
    +	tbl->last_span = dp;
    +
    +	return dp;
    +}
    +
    +void
    +tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
    +{
    +	struct tbl_row	*rp;
    +	struct tbl_cell	*cp;
    +	struct tbl_span	*sp;
    +
    +	rp = (sp = tbl->last_span) == NULL ? tbl->first_row :
    +	    sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ?
    +	    sp->layout->next : sp->layout;
    +
    +	assert(rp != NULL);
    +
    +	if ( ! strcmp(p, "_")) {
    +		sp = newspan(tbl, ln, rp);
    +		sp->pos = TBL_SPAN_HORIZ;
    +		return;
    +	} else if ( ! strcmp(p, "=")) {
    +		sp = newspan(tbl, ln, rp);
    +		sp->pos = TBL_SPAN_DHORIZ;
    +		return;
    +	}
    +
    +	/*
    +	 * If the layout row contains nothing but horizontal lines,
    +	 * allocate an empty span for it and assign the current span
    +	 * to the next layout row accepting data.
    +	 */
    +
    +	while (rp->next != NULL) {
    +		if (rp->last->col + 1 < tbl->opts.cols)
    +			break;
    +		for (cp = rp->first; cp != NULL; cp = cp->next)
    +			if (cp->pos != TBL_CELL_HORIZ &&
    +			    cp->pos != TBL_CELL_DHORIZ)
    +				break;
    +		if (cp != NULL)
    +			break;
    +		sp = newspan(tbl, ln, rp);
    +		sp->pos = TBL_SPAN_DATA;
    +		rp = rp->next;
    +	}
    +
    +	/* Process a real data row. */
    +
    +	sp = newspan(tbl, ln, rp);
    +	sp->pos = TBL_SPAN_DATA;
    +	while (p[pos] != '\0')
    +		getdata(tbl, sp, ln, p, &pos);
    +}
    
    Property changes on: head/contrib/mandoc/tbl_data.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tbl_layout.c
    ===================================================================
    --- head/contrib/mandoc/tbl_layout.c	(nonexistent)
    +++ head/contrib/mandoc/tbl_layout.c	(revision 338826)
    @@ -0,0 +1,375 @@
    +/*	$Id: tbl_layout.c,v 1.44 2017/06/27 18:25:02 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2012, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <ctype.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#include "mandoc.h"
    +#include "mandoc_aux.h"
    +#include "libmandoc.h"
    +#include "libroff.h"
    +
    +struct	tbl_phrase {
    +	char		 name;
    +	enum tbl_cellt	 key;
    +};
    +
    +static	const struct tbl_phrase keys[] = {
    +	{ 'c',		 TBL_CELL_CENTRE },
    +	{ 'r',		 TBL_CELL_RIGHT },
    +	{ 'l',		 TBL_CELL_LEFT },
    +	{ 'n',		 TBL_CELL_NUMBER },
    +	{ 's',		 TBL_CELL_SPAN },
    +	{ 'a',		 TBL_CELL_LONG },
    +	{ '^',		 TBL_CELL_DOWN },
    +	{ '-',		 TBL_CELL_HORIZ },
    +	{ '_',		 TBL_CELL_HORIZ },
    +	{ '=',		 TBL_CELL_DHORIZ }
    +};
    +
    +#define KEYS_MAX ((int)(sizeof(keys)/sizeof(keys[0])))
    +
    +static	void		 mods(struct tbl_node *, struct tbl_cell *,
    +				int, const char *, int *);
    +static	void		 cell(struct tbl_node *, struct tbl_row *,
    +				int, const char *, int *);
    +static	struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *,
    +				enum tbl_cellt);
    +
    +
    +static void
    +mods(struct tbl_node *tbl, struct tbl_cell *cp,
    +		int ln, const char *p, int *pos)
    +{
    +	char		*endptr;
    +	size_t		 sz;
    +
    +mod:
    +	while (p[*pos] == ' ' || p[*pos] == '\t')
    +		(*pos)++;
    +
    +	/* Row delimiters and cell specifiers end modifier lists. */
    +
    +	if (strchr(".,-=^_ACLNRSaclnrs", p[*pos]) != NULL)
    +		return;
    +
    +	/* Throw away parenthesised expression. */
    +
    +	if ('(' == p[*pos]) {
    +		(*pos)++;
    +		while (p[*pos] && ')' != p[*pos])
    +			(*pos)++;
    +		if (')' == p[*pos]) {
    +			(*pos)++;
    +			goto mod;
    +		}
    +		mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse,
    +		    ln, *pos, NULL);
    +		return;
    +	}
    +
    +	/* Parse numerical spacing from modifier string. */
    +
    +	if (isdigit((unsigned char)p[*pos])) {
    +		cp->spacing = strtoull(p + *pos, &endptr, 10);
    +		*pos = endptr - p;
    +		goto mod;
    +	}
    +
    +	switch (tolower((unsigned char)p[(*pos)++])) {
    +	case 'b':
    +		cp->flags |= TBL_CELL_BOLD;
    +		goto mod;
    +	case 'd':
    +		cp->flags |= TBL_CELL_BALIGN;
    +		goto mod;
    +	case 'e':
    +		cp->flags |= TBL_CELL_EQUAL;
    +		goto mod;
    +	case 'f':
    +		break;
    +	case 'i':
    +		cp->flags |= TBL_CELL_ITALIC;
    +		goto mod;
    +	case 'm':
    +		mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse,
    +		    ln, *pos, "m");
    +		goto mod;
    +	case 'p':
    +	case 'v':
    +		if (p[*pos] == '-' || p[*pos] == '+')
    +			(*pos)++;
    +		while (isdigit((unsigned char)p[*pos]))
    +			(*pos)++;
    +		goto mod;
    +	case 't':
    +		cp->flags |= TBL_CELL_TALIGN;
    +		goto mod;
    +	case 'u':
    +		cp->flags |= TBL_CELL_UP;
    +		goto mod;
    +	case 'w':
    +		sz = 0;
    +		if (p[*pos] == '(') {
    +			(*pos)++;
    +			while (p[*pos + sz] != '\0' && p[*pos + sz] != ')')
    +				sz++;
    +		} else
    +			while (isdigit((unsigned char)p[*pos + sz]))
    +				sz++;
    +		if (sz) {
    +			free(cp->wstr);
    +			cp->wstr = mandoc_strndup(p + *pos, sz);
    +			*pos += sz;
    +			if (p[*pos] == ')')
    +				(*pos)++;
    +		}
    +		goto mod;
    +	case 'x':
    +		cp->flags |= TBL_CELL_WMAX;
    +		goto mod;
    +	case 'z':
    +		cp->flags |= TBL_CELL_WIGN;
    +		goto mod;
    +	case '|':
    +		if (cp->vert < 2)
    +			cp->vert++;
    +		else
    +			mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
    +			    tbl->parse, ln, *pos - 1, NULL);
    +		goto mod;
    +	default:
    +		mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
    +		    ln, *pos - 1, "%c", p[*pos - 1]);
    +		goto mod;
    +	}
    +
    +	/* Ignore parenthised font names for now. */
    +
    +	if (p[*pos] == '(')
    +		goto mod;
    +
    +	/* Support only one-character font-names for now. */
    +
    +	if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) {
    +		mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
    +		    ln, *pos, "TS %s", p + *pos - 1);
    +		if (p[*pos] != '\0')
    +			(*pos)++;
    +		if (p[*pos] != '\0')
    +			(*pos)++;
    +		goto mod;
    +	}
    +
    +	switch (p[(*pos)++]) {
    +	case '3':
    +	case 'B':
    +		cp->flags |= TBL_CELL_BOLD;
    +		goto mod;
    +	case '2':
    +	case 'I':
    +		cp->flags |= TBL_CELL_ITALIC;
    +		goto mod;
    +	case '1':
    +	case 'R':
    +		goto mod;
    +	default:
    +		mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
    +		    ln, *pos - 1, "TS f%c", p[*pos - 1]);
    +		goto mod;
    +	}
    +}
    +
    +static void
    +cell(struct tbl_node *tbl, struct tbl_row *rp,
    +		int ln, const char *p, int *pos)
    +{
    +	int		 i;
    +	enum tbl_cellt	 c;
    +
    +	/* Handle leading vertical lines */
    +
    +	while (p[*pos] == ' ' || p[*pos] == '\t' || p[*pos] == '|') {
    +		if (p[*pos] == '|') {
    +			if (rp->vert < 2)
    +				rp->vert++;
    +			else
    +				mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
    +				    tbl->parse, ln, *pos, NULL);
    +		}
    +		(*pos)++;
    +	}
    +
    +again:
    +	while (p[*pos] == ' ' || p[*pos] == '\t')
    +		(*pos)++;
    +
    +	if (p[*pos] == '.' || p[*pos] == '\0')
    +		return;
    +
    +	/* Parse the column position (`c', `l', `r', ...). */
    +
    +	for (i = 0; i < KEYS_MAX; i++)
    +		if (tolower((unsigned char)p[*pos]) == keys[i].name)
    +			break;
    +
    +	if (i == KEYS_MAX) {
    +		mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
    +		    ln, *pos, "%c", p[*pos]);
    +		(*pos)++;
    +		goto again;
    +	}
    +	c = keys[i].key;
    +
    +	/* Special cases of spanners. */
    +
    +	if (c == TBL_CELL_SPAN) {
    +		if (rp->last == NULL)
    +			mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN,
    +			    tbl->parse, ln, *pos, NULL);
    +		else if (rp->last->pos == TBL_CELL_HORIZ ||
    +		    rp->last->pos == TBL_CELL_DHORIZ)
    +			c = rp->last->pos;
    +	} else if (c == TBL_CELL_DOWN && rp == tbl->first_row)
    +		mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN,
    +		    tbl->parse, ln, *pos, NULL);
    +
    +	(*pos)++;
    +
    +	/* Allocate cell then parse its modifiers. */
    +
    +	mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos);
    +}
    +
    +void
    +tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos)
    +{
    +	struct tbl_row	*rp;
    +
    +	rp = NULL;
    +	for (;;) {
    +		/* Skip whitespace before and after each cell. */
    +
    +		while (p[pos] == ' ' || p[pos] == '\t')
    +			pos++;
    +
    +		switch (p[pos]) {
    +		case ',':  /* Next row on this input line. */
    +			pos++;
    +			rp = NULL;
    +			continue;
    +		case '\0':  /* Next row on next input line. */
    +			return;
    +		case '.':  /* End of layout. */
    +			pos++;
    +			tbl->part = TBL_PART_DATA;
    +
    +			/*
    +			 * When the layout is completely empty,
    +			 * default to one left-justified column.
    +			 */
    +
    +			if (tbl->first_row == NULL) {
    +				tbl->first_row = tbl->last_row =
    +				    mandoc_calloc(1, sizeof(*rp));
    +			}
    +			if (tbl->first_row->first == NULL) {
    +				mandoc_msg(MANDOCERR_TBLLAYOUT_NONE,
    +				    tbl->parse, ln, pos, NULL);
    +				cell_alloc(tbl, tbl->first_row,
    +				    TBL_CELL_LEFT);
    +				if (tbl->opts.lvert < tbl->first_row->vert)
    +					tbl->opts.lvert = tbl->first_row->vert;
    +				return;
    +			}
    +
    +			/*
    +			 * Search for the widest line
    +			 * along the left and right margins.
    +			 */
    +
    +			for (rp = tbl->first_row; rp; rp = rp->next) {
    +				if (tbl->opts.lvert < rp->vert)
    +					tbl->opts.lvert = rp->vert;
    +				if (rp->last != NULL &&
    +				    rp->last->col + 1 == tbl->opts.cols &&
    +				    tbl->opts.rvert < rp->last->vert)
    +					tbl->opts.rvert = rp->last->vert;
    +
    +				/* If the last line is empty, drop it. */
    +
    +				if (rp->next != NULL &&
    +				    rp->next->first == NULL) {
    +					free(rp->next);
    +					rp->next = NULL;
    +					tbl->last_row = rp;
    +				}
    +			}
    +			return;
    +		default:  /* Cell. */
    +			break;
    +		}
    +
    +		/*
    +		 * If the last line had at least one cell,
    +		 * start a new one; otherwise, continue it.
    +		 */
    +
    +		if (rp == NULL) {
    +			if (tbl->last_row == NULL ||
    +			    tbl->last_row->first != NULL) {
    +				rp = mandoc_calloc(1, sizeof(*rp));
    +				if (tbl->last_row)
    +					tbl->last_row->next = rp;
    +				else
    +					tbl->first_row = rp;
    +				tbl->last_row = rp;
    +			} else
    +				rp = tbl->last_row;
    +		}
    +		cell(tbl, rp, ln, p, &pos);
    +	}
    +}
    +
    +static struct tbl_cell *
    +cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
    +{
    +	struct tbl_cell	*p, *pp;
    +
    +	p = mandoc_calloc(1, sizeof(*p));
    +	p->spacing = SIZE_MAX;
    +	p->pos = pos;
    +
    +	if ((pp = rp->last) != NULL) {
    +		pp->next = p;
    +		p->col = pp->col + 1;
    +	} else
    +		rp->first = p;
    +	rp->last = p;
    +
    +	if (tbl->opts.cols <= p->col)
    +		tbl->opts.cols = p->col + 1;
    +
    +	return p;
    +}
    
    Property changes on: head/contrib/mandoc/tbl_layout.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/term.c
    ===================================================================
    --- head/contrib/mandoc/term.c	(nonexistent)
    +++ head/contrib/mandoc/term.c	(revision 338826)
    @@ -0,0 +1,995 @@
    +/*	$Id: term.c,v 1.274 2017/07/28 14:25:48 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "mandoc_aux.h"
    +#include "out.h"
    +#include "term.h"
    +#include "main.h"
    +
    +static	size_t		 cond_width(const struct termp *, int, int *);
    +static	void		 adjbuf(struct termp_col *, size_t);
    +static	void		 bufferc(struct termp *, char);
    +static	void		 encode(struct termp *, const char *, size_t);
    +static	void		 encode1(struct termp *, int);
    +static	void		 endline(struct termp *);
    +
    +
    +void
    +term_setcol(struct termp *p, size_t maxtcol)
    +{
    +	if (maxtcol > p->maxtcol) {
    +		p->tcols = mandoc_recallocarray(p->tcols,
    +		    p->maxtcol, maxtcol, sizeof(*p->tcols));
    +		p->maxtcol = maxtcol;
    +	}
    +	p->lasttcol = maxtcol - 1;
    +	p->tcol = p->tcols;
    +}
    +
    +void
    +term_free(struct termp *p)
    +{
    +	for (p->tcol = p->tcols; p->tcol < p->tcols + p->maxtcol; p->tcol++)
    +		free(p->tcol->buf);
    +	free(p->tcols);
    +	free(p->fontq);
    +	free(p);
    +}
    +
    +void
    +term_begin(struct termp *p, term_margin head,
    +		term_margin foot, const struct roff_meta *arg)
    +{
    +
    +	p->headf = head;
    +	p->footf = foot;
    +	p->argf = arg;
    +	(*p->begin)(p);
    +}
    +
    +void
    +term_end(struct termp *p)
    +{
    +
    +	(*p->end)(p);
    +}
    +
    +/*
    + * Flush a chunk of text.  By default, break the output line each time
    + * the right margin is reached, and continue output on the next line
    + * at the same offset as the chunk itself.  By default, also break the
    + * output line at the end of the chunk.
    + * The following flags may be specified:
    + *
    + *  - TERMP_NOBREAK: Do not break the output line at the right margin,
    + *    but only at the max right margin.  Also, do not break the output
    + *    line at the end of the chunk, such that the next call can pad to
    + *    the next column.  However, if less than p->trailspace blanks,
    + *    which can be 0, 1, or 2, remain to the right margin, the line
    + *    will be broken.
    + *  - TERMP_BRTRSP: Consider trailing whitespace significant
    + *    when deciding whether the chunk fits or not.
    + *  - TERMP_BRIND: If the chunk does not fit and the output line has
    + *    to be broken, start the next line at the right margin instead
    + *    of at the offset.  Used together with TERMP_NOBREAK for the tags
    + *    in various kinds of tagged lists.
    + *  - TERMP_HANG: Do not break the output line at the right margin,
    + *    append the next chunk after it even if this one is too long.
    + *    To be used together with TERMP_NOBREAK.
    + *  - TERMP_NOPAD: Start writing at the current position,
    + *    do not pad with blank characters up to the offset.
    + */
    +void
    +term_flushln(struct termp *p)
    +{
    +	size_t		 vis;   /* current visual position on output */
    +	size_t		 vbl;   /* number of blanks to prepend to output */
    +	size_t		 vend;	/* end of word visual position on output */
    +	size_t		 bp;    /* visual right border position */
    +	size_t		 dv;    /* temporary for visual pos calculations */
    +	size_t		 j;     /* temporary loop index for p->tcol->buf */
    +	size_t		 jhy;	/* last hyph before overflow w/r/t j */
    +	size_t		 maxvis; /* output position of visible boundary */
    +	int		 ntab;	/* number of tabs to prepend */
    +	int		 breakline; /* after this word */
    +
    +	vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
    +	    0 : p->tcol->offset - p->viscol;
    +	if (p->minbl && vbl < p->minbl)
    +		vbl = p->minbl;
    +	maxvis = p->tcol->rmargin > p->viscol + vbl ?
    +	    p->tcol->rmargin - p->viscol - vbl : 0;
    +	bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
    +	    p->maxrmargin > p->viscol + vbl ?
    +	    p->maxrmargin - p->viscol - vbl : 0;
    +	vis = vend = 0;
    +
    +	if ((p->flags & TERMP_MULTICOL) == 0)
    +		p->tcol->col = 0;
    +	while (p->tcol->col < p->tcol->lastcol) {
    +
    +		/*
    +		 * Handle literal tab characters: collapse all
    +		 * subsequent tabs into a single huge set of spaces.
    +		 */
    +
    +		ntab = 0;
    +		while (p->tcol->col < p->tcol->lastcol &&
    +		    p->tcol->buf[p->tcol->col] == '\t') {
    +			vend = term_tab_next(vis);
    +			vbl += vend - vis;
    +			vis = vend;
    +			ntab++;
    +			p->tcol->col++;
    +		}
    +
    +		/*
    +		 * Count up visible word characters.  Control sequences
    +		 * (starting with the CSI) aren't counted.  A space
    +		 * generates a non-printing word, which is valid (the
    +		 * space is printed according to regular spacing rules).
    +		 */
    +
    +		jhy = 0;
    +		breakline = 0;
    +		for (j = p->tcol->col; j < p->tcol->lastcol; j++) {
    +			if (p->tcol->buf[j] == '\n') {
    +				if ((p->flags & TERMP_BRIND) == 0)
    +					breakline = 1;
    +				continue;
    +			}
    +			if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t')
    +				break;
    +
    +			/* Back over the last printed character. */
    +			if (p->tcol->buf[j] == '\b') {
    +				assert(j);
    +				vend -= (*p->width)(p, p->tcol->buf[j - 1]);
    +				continue;
    +			}
    +
    +			/* Regular word. */
    +			/* Break at the hyphen point if we overrun. */
    +			if (vend > vis && vend < bp &&
    +			    (p->tcol->buf[j] == ASCII_HYPH||
    +			     p->tcol->buf[j] == ASCII_BREAK))
    +				jhy = j;
    +
    +			/*
    +			 * Hyphenation now decided, put back a real
    +			 * hyphen such that we get the correct width.
    +			 */
    +			if (p->tcol->buf[j] == ASCII_HYPH)
    +				p->tcol->buf[j] = '-';
    +
    +			vend += (*p->width)(p, p->tcol->buf[j]);
    +		}
    +
    +		/*
    +		 * Find out whether we would exceed the right margin.
    +		 * If so, break to the next line.
    +		 */
    +
    +		if (vend > bp && jhy == 0 && vis > 0 &&
    +		    (p->flags & TERMP_BRNEVER) == 0) {
    +			if (p->flags & TERMP_MULTICOL)
    +				return;
    +
    +			endline(p);
    +			vend -= vis;
    +
    +			/* Use pending tabs on the new line. */
    +
    +			vbl = 0;
    +			while (ntab--)
    +				vbl = term_tab_next(vbl);
    +
    +			/* Re-establish indentation. */
    +
    +			if (p->flags & TERMP_BRIND)
    +				vbl += p->tcol->rmargin;
    +			else
    +				vbl += p->tcol->offset;
    +			maxvis = p->tcol->rmargin > vbl ?
    +			    p->tcol->rmargin - vbl : 0;
    +			bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
    +			    p->maxrmargin > vbl ?  p->maxrmargin - vbl : 0;
    +		}
    +
    +		/*
    +		 * Write out the rest of the word.
    +		 */
    +
    +		for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) {
    +			if (vend > bp && jhy > 0 && p->tcol->col > jhy)
    +				break;
    +			if (p->tcol->buf[p->tcol->col] == '\n')
    +				continue;
    +			if (p->tcol->buf[p->tcol->col] == '\t')
    +				break;
    +			if (p->tcol->buf[p->tcol->col] == ' ') {
    +				j = p->tcol->col;
    +				while (p->tcol->col < p->tcol->lastcol &&
    +				    p->tcol->buf[p->tcol->col] == ' ')
    +					p->tcol->col++;
    +				dv = (p->tcol->col - j) * (*p->width)(p, ' ');
    +				vbl += dv;
    +				vend += dv;
    +				break;
    +			}
    +			if (p->tcol->buf[p->tcol->col] == ASCII_NBRSP) {
    +				vbl += (*p->width)(p, ' ');
    +				continue;
    +			}
    +			if (p->tcol->buf[p->tcol->col] == ASCII_BREAK)
    +				continue;
    +
    +			/*
    +			 * Now we definitely know there will be
    +			 * printable characters to output,
    +			 * so write preceding white space now.
    +			 */
    +			if (vbl) {
    +				(*p->advance)(p, vbl);
    +				p->viscol += vbl;
    +				vbl = 0;
    +			}
    +
    +			(*p->letter)(p, p->tcol->buf[p->tcol->col]);
    +			if (p->tcol->buf[p->tcol->col] == '\b')
    +				p->viscol -= (*p->width)(p,
    +				    p->tcol->buf[p->tcol->col - 1]);
    +			else
    +				p->viscol += (*p->width)(p,
    +				    p->tcol->buf[p->tcol->col]);
    +		}
    +		vis = vend;
    +
    +		if (breakline == 0)
    +			continue;
    +
    +		/* Explicitly requested output line break. */
    +
    +		if (p->flags & TERMP_MULTICOL)
    +			return;
    +
    +		endline(p);
    +		breakline = 0;
    +		vis = vend = 0;
    +
    +		/* Re-establish indentation. */
    +
    +		vbl = p->tcol->offset;
    +		maxvis = p->tcol->rmargin > vbl ?
    +		    p->tcol->rmargin - vbl : 0;
    +		bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
    +		    p->maxrmargin > vbl ?  p->maxrmargin - vbl : 0;
    +	}
    +
    +	/*
    +	 * If there was trailing white space, it was not printed;
    +	 * so reset the cursor position accordingly.
    +	 */
    +
    +	if (vis > vbl)
    +		vis -= vbl;
    +	else
    +		vis = 0;
    +
    +	p->col = p->tcol->col = p->tcol->lastcol = 0;
    +	p->minbl = p->trailspace;
    +	p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD);
    +
    +	if (p->flags & TERMP_MULTICOL)
    +		return;
    +
    +	/* Trailing whitespace is significant in some columns. */
    +
    +	if (vis && vbl && (TERMP_BRTRSP & p->flags))
    +		vis += vbl;
    +
    +	/* If the column was overrun, break the line. */
    +	if ((p->flags & TERMP_NOBREAK) == 0 ||
    +	    ((p->flags & TERMP_HANG) == 0 &&
    +	     vis + p->trailspace * (*p->width)(p, ' ') > maxvis))
    +		endline(p);
    +}
    +
    +static void
    +endline(struct termp *p)
    +{
    +	if ((p->flags & (TERMP_NEWMC | TERMP_ENDMC)) == TERMP_ENDMC) {
    +		p->mc = NULL;
    +		p->flags &= ~TERMP_ENDMC;
    +	}
    +	if (p->mc != NULL) {
    +		if (p->viscol && p->maxrmargin >= p->viscol)
    +			(*p->advance)(p, p->maxrmargin - p->viscol + 1);
    +		p->flags |= TERMP_NOBUF | TERMP_NOSPACE;
    +		term_word(p, p->mc);
    +		p->flags &= ~(TERMP_NOBUF | TERMP_NEWMC);
    +	}
    +	p->viscol = 0;
    +	p->minbl = 0;
    +	(*p->endline)(p);
    +}
    +
    +/*
    + * A newline only breaks an existing line; it won't assert vertical
    + * space.  All data in the output buffer is flushed prior to the newline
    + * assertion.
    + */
    +void
    +term_newln(struct termp *p)
    +{
    +
    +	p->flags |= TERMP_NOSPACE;
    +	if (p->tcol->lastcol || p->viscol)
    +		term_flushln(p);
    +}
    +
    +/*
    + * Asserts a vertical space (a full, empty line-break between lines).
    + * Note that if used twice, this will cause two blank spaces and so on.
    + * All data in the output buffer is flushed prior to the newline
    + * assertion.
    + */
    +void
    +term_vspace(struct termp *p)
    +{
    +
    +	term_newln(p);
    +	p->viscol = 0;
    +	p->minbl = 0;
    +	if (0 < p->skipvsp)
    +		p->skipvsp--;
    +	else
    +		(*p->endline)(p);
    +}
    +
    +/* Swap current and previous font; for \fP and .ft P */
    +void
    +term_fontlast(struct termp *p)
    +{
    +	enum termfont	 f;
    +
    +	f = p->fontl;
    +	p->fontl = p->fontq[p->fonti];
    +	p->fontq[p->fonti] = f;
    +}
    +
    +/* Set font, save current, discard previous; for \f, .ft, .B etc. */
    +void
    +term_fontrepl(struct termp *p, enum termfont f)
    +{
    +
    +	p->fontl = p->fontq[p->fonti];
    +	p->fontq[p->fonti] = f;
    +}
    +
    +/* Set font, save previous. */
    +void
    +term_fontpush(struct termp *p, enum termfont f)
    +{
    +
    +	p->fontl = p->fontq[p->fonti];
    +	if (++p->fonti == p->fontsz) {
    +		p->fontsz += 8;
    +		p->fontq = mandoc_reallocarray(p->fontq,
    +		    p->fontsz, sizeof(*p->fontq));
    +	}
    +	p->fontq[p->fonti] = f;
    +}
    +
    +/* Flush to make the saved pointer current again. */
    +void
    +term_fontpopq(struct termp *p, int i)
    +{
    +
    +	assert(i >= 0);
    +	if (p->fonti > i)
    +		p->fonti = i;
    +}
    +
    +/* Pop one font off the stack. */
    +void
    +term_fontpop(struct termp *p)
    +{
    +
    +	assert(p->fonti);
    +	p->fonti--;
    +}
    +
    +/*
    + * Handle pwords, partial words, which may be either a single word or a
    + * phrase that cannot be broken down (such as a literal string).  This
    + * handles word styling.
    + */
    +void
    +term_word(struct termp *p, const char *word)
    +{
    +	struct roffsu	 su;
    +	const char	 nbrsp[2] = { ASCII_NBRSP, 0 };
    +	const char	*seq, *cp;
    +	int		 sz, uc;
    +	size_t		 csz, lsz, ssz;
    +	enum mandoc_esc	 esc;
    +
    +	if ((p->flags & TERMP_NOBUF) == 0) {
    +		if ((p->flags & TERMP_NOSPACE) == 0) {
    +			if ((p->flags & TERMP_KEEP) == 0) {
    +				bufferc(p, ' ');
    +				if (p->flags & TERMP_SENTENCE)
    +					bufferc(p, ' ');
    +			} else
    +				bufferc(p, ASCII_NBRSP);
    +		}
    +		if (p->flags & TERMP_PREKEEP)
    +			p->flags |= TERMP_KEEP;
    +		if (p->flags & TERMP_NONOSPACE)
    +			p->flags |= TERMP_NOSPACE;
    +		else
    +			p->flags &= ~TERMP_NOSPACE;
    +		p->flags &= ~(TERMP_SENTENCE | TERMP_NONEWLINE);
    +		p->skipvsp = 0;
    +	}
    +
    +	while ('\0' != *word) {
    +		if ('\\' != *word) {
    +			if (TERMP_NBRWORD & p->flags) {
    +				if (' ' == *word) {
    +					encode(p, nbrsp, 1);
    +					word++;
    +					continue;
    +				}
    +				ssz = strcspn(word, "\\ ");
    +			} else
    +				ssz = strcspn(word, "\\");
    +			encode(p, word, ssz);
    +			word += (int)ssz;
    +			continue;
    +		}
    +
    +		word++;
    +		esc = mandoc_escape(&word, &seq, &sz);
    +		if (ESCAPE_ERROR == esc)
    +			continue;
    +
    +		switch (esc) {
    +		case ESCAPE_UNICODE:
    +			uc = mchars_num2uc(seq + 1, sz - 1);
    +			break;
    +		case ESCAPE_NUMBERED:
    +			uc = mchars_num2char(seq, sz);
    +			if (uc < 0)
    +				continue;
    +			break;
    +		case ESCAPE_SPECIAL:
    +			if (p->enc == TERMENC_ASCII) {
    +				cp = mchars_spec2str(seq, sz, &ssz);
    +				if (cp != NULL)
    +					encode(p, cp, ssz);
    +			} else {
    +				uc = mchars_spec2cp(seq, sz);
    +				if (uc > 0)
    +					encode1(p, uc);
    +			}
    +			continue;
    +		case ESCAPE_FONTBOLD:
    +			term_fontrepl(p, TERMFONT_BOLD);
    +			continue;
    +		case ESCAPE_FONTITALIC:
    +			term_fontrepl(p, TERMFONT_UNDER);
    +			continue;
    +		case ESCAPE_FONTBI:
    +			term_fontrepl(p, TERMFONT_BI);
    +			continue;
    +		case ESCAPE_FONT:
    +		case ESCAPE_FONTROMAN:
    +			term_fontrepl(p, TERMFONT_NONE);
    +			continue;
    +		case ESCAPE_FONTPREV:
    +			term_fontlast(p);
    +			continue;
    +		case ESCAPE_BREAK:
    +			bufferc(p, '\n');
    +			continue;
    +		case ESCAPE_NOSPACE:
    +			if (p->flags & TERMP_BACKAFTER)
    +				p->flags &= ~TERMP_BACKAFTER;
    +			else if (*word == '\0')
    +				p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE);
    +			continue;
    +		case ESCAPE_HORIZ:
    +			if (*seq == '|') {
    +				seq++;
    +				uc = -p->col;
    +			} else
    +				uc = 0;
    +			if (a2roffsu(seq, &su, SCALE_EM) == NULL)
    +				continue;
    +			uc += term_hen(p, &su);
    +			if (uc > 0)
    +				while (uc-- > 0)
    +					bufferc(p, ASCII_NBRSP);
    +			else if (p->col > (size_t)(-uc))
    +				p->col += uc;
    +			else {
    +				uc += p->col;
    +				p->col = 0;
    +				if (p->tcol->offset > (size_t)(-uc)) {
    +					p->ti += uc;
    +					p->tcol->offset += uc;
    +				} else {
    +					p->ti -= p->tcol->offset;
    +					p->tcol->offset = 0;
    +				}
    +			}
    +			continue;
    +		case ESCAPE_HLINE:
    +			if ((cp = a2roffsu(seq, &su, SCALE_EM)) == NULL)
    +				continue;
    +			uc = term_hen(p, &su);
    +			if (uc <= 0) {
    +				if (p->tcol->rmargin <= p->tcol->offset)
    +					continue;
    +				lsz = p->tcol->rmargin - p->tcol->offset;
    +			} else
    +				lsz = uc;
    +			if (*cp == seq[-1])
    +				uc = -1;
    +			else if (*cp == '\\') {
    +				seq = cp + 1;
    +				esc = mandoc_escape(&seq, &cp, &sz);
    +				switch (esc) {
    +				case ESCAPE_UNICODE:
    +					uc = mchars_num2uc(cp + 1, sz - 1);
    +					break;
    +				case ESCAPE_NUMBERED:
    +					uc = mchars_num2char(cp, sz);
    +					break;
    +				case ESCAPE_SPECIAL:
    +					uc = mchars_spec2cp(cp, sz);
    +					break;
    +				default:
    +					uc = -1;
    +					break;
    +				}
    +			} else
    +				uc = *cp;
    +			if (uc < 0x20 || (uc > 0x7E && uc < 0xA0))
    +				uc = '_';
    +			if (p->enc == TERMENC_ASCII) {
    +				cp = ascii_uc2str(uc);
    +				csz = term_strlen(p, cp);
    +				ssz = strlen(cp);
    +			} else
    +				csz = (*p->width)(p, uc);
    +			while (lsz >= csz) {
    +				if (p->enc == TERMENC_ASCII)
    +					encode(p, cp, ssz);
    +				else
    +					encode1(p, uc);
    +				lsz -= csz;
    +			}
    +			continue;
    +		case ESCAPE_SKIPCHAR:
    +			p->flags |= TERMP_BACKAFTER;
    +			continue;
    +		case ESCAPE_OVERSTRIKE:
    +			cp = seq + sz;
    +			while (seq < cp) {
    +				if (*seq == '\\') {
    +					mandoc_escape(&seq, NULL, NULL);
    +					continue;
    +				}
    +				encode1(p, *seq++);
    +				if (seq < cp) {
    +					if (p->flags & TERMP_BACKBEFORE)
    +						p->flags |= TERMP_BACKAFTER;
    +					else
    +						p->flags |= TERMP_BACKBEFORE;
    +				}
    +			}
    +			/* Trim trailing backspace/blank pair. */
    +			if (p->tcol->lastcol > 2 &&
    +			    (p->tcol->buf[p->tcol->lastcol - 1] == ' ' ||
    +			     p->tcol->buf[p->tcol->lastcol - 1] == '\t'))
    +				p->tcol->lastcol -= 2;
    +			if (p->col > p->tcol->lastcol)
    +				p->col = p->tcol->lastcol;
    +			continue;
    +		default:
    +			continue;
    +		}
    +
    +		/*
    +		 * Common handling for Unicode and numbered
    +		 * character escape sequences.
    +		 */
    +
    +		if (p->enc == TERMENC_ASCII) {
    +			cp = ascii_uc2str(uc);
    +			encode(p, cp, strlen(cp));
    +		} else {
    +			if ((uc < 0x20 && uc != 0x09) ||
    +			    (uc > 0x7E && uc < 0xA0))
    +				uc = 0xFFFD;
    +			encode1(p, uc);
    +		}
    +	}
    +	p->flags &= ~TERMP_NBRWORD;
    +}
    +
    +static void
    +adjbuf(struct termp_col *c, size_t sz)
    +{
    +	if (c->maxcols == 0)
    +		c->maxcols = 1024;
    +	while (c->maxcols <= sz)
    +		c->maxcols <<= 2;
    +	c->buf = mandoc_reallocarray(c->buf, c->maxcols, sizeof(*c->buf));
    +}
    +
    +static void
    +bufferc(struct termp *p, char c)
    +{
    +	if (p->flags & TERMP_NOBUF) {
    +		(*p->letter)(p, c);
    +		return;
    +	}
    +	if (p->col + 1 >= p->tcol->maxcols)
    +		adjbuf(p->tcol, p->col + 1);
    +	if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
    +		p->tcol->buf[p->col] = c;
    +	if (p->tcol->lastcol < ++p->col)
    +		p->tcol->lastcol = p->col;
    +}
    +
    +/*
    + * See encode().
    + * Do this for a single (probably unicode) value.
    + * Does not check for non-decorated glyphs.
    + */
    +static void
    +encode1(struct termp *p, int c)
    +{
    +	enum termfont	  f;
    +
    +	if (p->flags & TERMP_NOBUF) {
    +		(*p->letter)(p, c);
    +		return;
    +	}
    +
    +	if (p->col + 7 >= p->tcol->maxcols)
    +		adjbuf(p->tcol, p->col + 7);
    +
    +	f = (c == ASCII_HYPH || c > 127 || isgraph(c)) ?
    +	    p->fontq[p->fonti] : TERMFONT_NONE;
    +
    +	if (p->flags & TERMP_BACKBEFORE) {
    +		if (p->tcol->buf[p->col - 1] == ' ' ||
    +		    p->tcol->buf[p->col - 1] == '\t')
    +			p->col--;
    +		else
    +			p->tcol->buf[p->col++] = '\b';
    +		p->flags &= ~TERMP_BACKBEFORE;
    +	}
    +	if (f == TERMFONT_UNDER || f == TERMFONT_BI) {
    +		p->tcol->buf[p->col++] = '_';
    +		p->tcol->buf[p->col++] = '\b';
    +	}
    +	if (f == TERMFONT_BOLD || f == TERMFONT_BI) {
    +		if (c == ASCII_HYPH)
    +			p->tcol->buf[p->col++] = '-';
    +		else
    +			p->tcol->buf[p->col++] = c;
    +		p->tcol->buf[p->col++] = '\b';
    +	}
    +	if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
    +		p->tcol->buf[p->col] = c;
    +	if (p->tcol->lastcol < ++p->col)
    +		p->tcol->lastcol = p->col;
    +	if (p->flags & TERMP_BACKAFTER) {
    +		p->flags |= TERMP_BACKBEFORE;
    +		p->flags &= ~TERMP_BACKAFTER;
    +	}
    +}
    +
    +static void
    +encode(struct termp *p, const char *word, size_t sz)
    +{
    +	size_t		  i;
    +
    +	if (p->flags & TERMP_NOBUF) {
    +		for (i = 0; i < sz; i++)
    +			(*p->letter)(p, word[i]);
    +		return;
    +	}
    +
    +	if (p->col + 2 + (sz * 5) >= p->tcol->maxcols)
    +		adjbuf(p->tcol, p->col + 2 + (sz * 5));
    +
    +	for (i = 0; i < sz; i++) {
    +		if (ASCII_HYPH == word[i] ||
    +		    isgraph((unsigned char)word[i]))
    +			encode1(p, word[i]);
    +		else {
    +			if (p->tcol->lastcol <= p->col ||
    +			    (word[i] != ' ' && word[i] != ASCII_NBRSP))
    +				p->tcol->buf[p->col] = word[i];
    +			p->col++;
    +
    +			/*
    +			 * Postpone the effect of \z while handling
    +			 * an overstrike sequence from ascii_uc2str().
    +			 */
    +
    +			if (word[i] == '\b' &&
    +			    (p->flags & TERMP_BACKBEFORE)) {
    +				p->flags &= ~TERMP_BACKBEFORE;
    +				p->flags |= TERMP_BACKAFTER;
    +			}
    +		}
    +	}
    +	if (p->tcol->lastcol < p->col)
    +		p->tcol->lastcol = p->col;
    +}
    +
    +void
    +term_setwidth(struct termp *p, const char *wstr)
    +{
    +	struct roffsu	 su;
    +	int		 iop, width;
    +
    +	iop = 0;
    +	width = 0;
    +	if (NULL != wstr) {
    +		switch (*wstr) {
    +		case '+':
    +			iop = 1;
    +			wstr++;
    +			break;
    +		case '-':
    +			iop = -1;
    +			wstr++;
    +			break;
    +		default:
    +			break;
    +		}
    +		if (a2roffsu(wstr, &su, SCALE_MAX) != NULL)
    +			width = term_hspan(p, &su);
    +		else
    +			iop = 0;
    +	}
    +	(*p->setwidth)(p, iop, width);
    +}
    +
    +size_t
    +term_len(const struct termp *p, size_t sz)
    +{
    +
    +	return (*p->width)(p, ' ') * sz;
    +}
    +
    +static size_t
    +cond_width(const struct termp *p, int c, int *skip)
    +{
    +
    +	if (*skip) {
    +		(*skip) = 0;
    +		return 0;
    +	} else
    +		return (*p->width)(p, c);
    +}
    +
    +size_t
    +term_strlen(const struct termp *p, const char *cp)
    +{
    +	size_t		 sz, rsz, i;
    +	int		 ssz, skip, uc;
    +	const char	*seq, *rhs;
    +	enum mandoc_esc	 esc;
    +	static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH,
    +			ASCII_BREAK, '\0' };
    +
    +	/*
    +	 * Account for escaped sequences within string length
    +	 * calculations.  This follows the logic in term_word() as we
    +	 * must calculate the width of produced strings.
    +	 */
    +
    +	sz = 0;
    +	skip = 0;
    +	while ('\0' != *cp) {
    +		rsz = strcspn(cp, rej);
    +		for (i = 0; i < rsz; i++)
    +			sz += cond_width(p, *cp++, &skip);
    +
    +		switch (*cp) {
    +		case '\\':
    +			cp++;
    +			esc = mandoc_escape(&cp, &seq, &ssz);
    +			if (ESCAPE_ERROR == esc)
    +				continue;
    +
    +			rhs = NULL;
    +
    +			switch (esc) {
    +			case ESCAPE_UNICODE:
    +				uc = mchars_num2uc(seq + 1, ssz - 1);
    +				break;
    +			case ESCAPE_NUMBERED:
    +				uc = mchars_num2char(seq, ssz);
    +				if (uc < 0)
    +					continue;
    +				break;
    +			case ESCAPE_SPECIAL:
    +				if (p->enc == TERMENC_ASCII) {
    +					rhs = mchars_spec2str(seq, ssz, &rsz);
    +					if (rhs != NULL)
    +						break;
    +				} else {
    +					uc = mchars_spec2cp(seq, ssz);
    +					if (uc > 0)
    +						sz += cond_width(p, uc, &skip);
    +				}
    +				continue;
    +			case ESCAPE_SKIPCHAR:
    +				skip = 1;
    +				continue;
    +			case ESCAPE_OVERSTRIKE:
    +				rsz = 0;
    +				rhs = seq + ssz;
    +				while (seq < rhs) {
    +					if (*seq == '\\') {
    +						mandoc_escape(&seq, NULL, NULL);
    +						continue;
    +					}
    +					i = (*p->width)(p, *seq++);
    +					if (rsz < i)
    +						rsz = i;
    +				}
    +				sz += rsz;
    +				continue;
    +			default:
    +				continue;
    +			}
    +
    +			/*
    +			 * Common handling for Unicode and numbered
    +			 * character escape sequences.
    +			 */
    +
    +			if (rhs == NULL) {
    +				if (p->enc == TERMENC_ASCII) {
    +					rhs = ascii_uc2str(uc);
    +					rsz = strlen(rhs);
    +				} else {
    +					if ((uc < 0x20 && uc != 0x09) ||
    +					    (uc > 0x7E && uc < 0xA0))
    +						uc = 0xFFFD;
    +					sz += cond_width(p, uc, &skip);
    +					continue;
    +				}
    +			}
    +
    +			if (skip) {
    +				skip = 0;
    +				break;
    +			}
    +
    +			/*
    +			 * Common handling for all escape sequences
    +			 * printing more than one character.
    +			 */
    +
    +			for (i = 0; i < rsz; i++)
    +				sz += (*p->width)(p, *rhs++);
    +			break;
    +		case ASCII_NBRSP:
    +			sz += cond_width(p, ' ', &skip);
    +			cp++;
    +			break;
    +		case ASCII_HYPH:
    +			sz += cond_width(p, '-', &skip);
    +			cp++;
    +			break;
    +		default:
    +			break;
    +		}
    +	}
    +
    +	return sz;
    +}
    +
    +int
    +term_vspan(const struct termp *p, const struct roffsu *su)
    +{
    +	double		 r;
    +	int		 ri;
    +
    +	switch (su->unit) {
    +	case SCALE_BU:
    +		r = su->scale / 40.0;
    +		break;
    +	case SCALE_CM:
    +		r = su->scale * 6.0 / 2.54;
    +		break;
    +	case SCALE_FS:
    +		r = su->scale * 65536.0 / 40.0;
    +		break;
    +	case SCALE_IN:
    +		r = su->scale * 6.0;
    +		break;
    +	case SCALE_MM:
    +		r = su->scale * 0.006;
    +		break;
    +	case SCALE_PC:
    +		r = su->scale;
    +		break;
    +	case SCALE_PT:
    +		r = su->scale / 12.0;
    +		break;
    +	case SCALE_EN:
    +	case SCALE_EM:
    +		r = su->scale * 0.6;
    +		break;
    +	case SCALE_VS:
    +		r = su->scale;
    +		break;
    +	default:
    +		abort();
    +	}
    +	ri = r > 0.0 ? r + 0.4995 : r - 0.4995;
    +	return ri < 66 ? ri : 1;
    +}
    +
    +/*
    + * Convert a scaling width to basic units, rounding towards 0.
    + */
    +int
    +term_hspan(const struct termp *p, const struct roffsu *su)
    +{
    +
    +	return (*p->hspan)(p, su);
    +}
    +
    +/*
    + * Convert a scaling width to basic units, rounding to closest.
    + */
    +int
    +term_hen(const struct termp *p, const struct roffsu *su)
    +{
    +	int bu;
    +
    +	if ((bu = (*p->hspan)(p, su)) >= 0)
    +		return (bu + 11) / 24;
    +	else
    +		return -((-bu + 11) / 24);
    +}
    
    Property changes on: head/contrib/mandoc/term.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/term.h
    ===================================================================
    --- head/contrib/mandoc/term.h	(nonexistent)
    +++ head/contrib/mandoc/term.h	(revision 338826)
    @@ -0,0 +1,156 @@
    +/*	$Id: term.h,v 1.130 2017/07/08 14:51:05 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE 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	termenc {
    +	TERMENC_ASCII,
    +	TERMENC_LOCALE,
    +	TERMENC_UTF8
    +};
    +
    +enum	termtype {
    +	TERMTYPE_CHAR,
    +	TERMTYPE_PS,
    +	TERMTYPE_PDF
    +};
    +
    +enum	termfont {
    +	TERMFONT_NONE = 0,
    +	TERMFONT_BOLD,
    +	TERMFONT_UNDER,
    +	TERMFONT_BI,
    +	TERMFONT__MAX
    +};
    +
    +struct	eqn_box;
    +struct	roff_meta;
    +struct	roff_node;
    +struct	tbl_span;
    +struct	termp;
    +
    +typedef void	(*term_margin)(struct termp *, const struct roff_meta *);
    +
    +struct	termp_tbl {
    +	int		  width;	/* width in fixed chars */
    +	int		  decimal;	/* decimal point position */
    +};
    +
    +struct	termp_col {
    +	int		 *buf;		/* Output buffer. */
    +	size_t		  maxcols;	/* Allocated bytes in buf. */
    +	size_t		  lastcol;	/* Last byte in buf. */
    +	size_t		  col;		/* Byte in buf to be written. */
    +	size_t		  rmargin;	/* Current right margin. */
    +	size_t		  offset;	/* Current left margin. */
    +};
    +
    +struct	termp {
    +	struct rofftbl	  tbl;		/* Table configuration. */
    +	struct termp_col *tcols;	/* Array of table columns. */
    +	struct termp_col *tcol;		/* Current table column. */
    +	size_t		  maxtcol;	/* Allocated table columns. */
    +	size_t		  lasttcol;	/* Last column currently used. */
    +	size_t		  line;		/* Current output line number. */
    +	size_t		  defindent;	/* Default indent for text. */
    +	size_t		  defrmargin;	/* Right margin of the device. */
    +	size_t		  lastrmargin;	/* Right margin before the last ll. */
    +	size_t		  maxrmargin;	/* Max right margin. */
    +	size_t		  col;		/* Byte position in buf. */
    +	size_t		  viscol;	/* Chars on current line. */
    +	size_t		  trailspace;	/* See term_flushln(). */
    +	size_t		  minbl;	/* Minimum blanks before next field. */
    +	int		  synopsisonly; /* Print the synopsis only. */
    +	int		  mdocstyle;	/* Imitate mdoc(7) output. */
    +	int		  ti;		/* Temporary indent for one line. */
    +	int		  skipvsp;	/* Vertical space to skip. */
    +	int		  flags;
    +#define	TERMP_SENTENCE	 (1 << 0)	/* Space before a sentence. */
    +#define	TERMP_NOSPACE	 (1 << 1)	/* No space before words. */
    +#define	TERMP_NONOSPACE	 (1 << 2)	/* No space (no autounset). */
    +#define	TERMP_NBRWORD	 (1 << 3)	/* Make next word nonbreaking. */
    +#define	TERMP_KEEP	 (1 << 4)	/* Keep words together. */
    +#define	TERMP_PREKEEP	 (1 << 5)	/* ...starting with the next one. */
    +#define	TERMP_BACKAFTER	 (1 << 6)	/* Back up after next character. */
    +#define	TERMP_BACKBEFORE (1 << 7)	/* Back up before next character. */
    +#define	TERMP_NOBREAK	 (1 << 8)	/* See term_flushln(). */
    +#define	TERMP_BRTRSP	 (1 << 9)	/* See term_flushln(). */
    +#define	TERMP_BRIND	 (1 << 10)	/* See term_flushln(). */
    +#define	TERMP_HANG	 (1 << 11)	/* See term_flushln(). */
    +#define	TERMP_NOPAD	 (1 << 12)	/* See term_flushln(). */
    +#define	TERMP_NOSPLIT	 (1 << 13)	/* Do not break line before .An. */
    +#define	TERMP_SPLIT	 (1 << 14)	/* Break line before .An. */
    +#define	TERMP_NONEWLINE	 (1 << 15)	/* No line break in nofill mode. */
    +#define	TERMP_BRNEVER	 (1 << 16)	/* Don't even break at maxrmargin. */
    +#define	TERMP_NOBUF	 (1 << 17)	/* Bypass output buffer. */
    +#define	TERMP_NEWMC	 (1 << 18)	/* No .mc printed yet. */
    +#define	TERMP_ENDMC	 (1 << 19)	/* Next break ends .mc mode. */
    +#define	TERMP_MULTICOL	 (1 << 20)	/* Multiple column mode. */
    +	enum termtype	  type;		/* Terminal, PS, or PDF. */
    +	enum termenc	  enc;		/* Type of encoding. */
    +	enum termfont	  fontl;	/* Last font set. */
    +	enum termfont	 *fontq;	/* Symmetric fonts. */
    +	int		  fontsz;	/* Allocated size of font stack */
    +	int		  fonti;	/* Index of font stack. */
    +	term_margin	  headf;	/* invoked to print head */
    +	term_margin	  footf;	/* invoked to print foot */
    +	void		(*letter)(struct termp *, int);
    +	void		(*begin)(struct termp *);
    +	void		(*end)(struct termp *);
    +	void		(*endline)(struct termp *);
    +	void		(*advance)(struct termp *, size_t);
    +	void		(*setwidth)(struct termp *, int, int);
    +	size_t		(*width)(const struct termp *, int);
    +	int		(*hspan)(const struct termp *,
    +				const struct roffsu *);
    +	const void	 *argf;		/* arg for headf/footf */
    +	const char	 *mc;		/* Margin character. */
    +	struct termp_ps	 *ps;
    +};
    +
    +
    +const char	 *ascii_uc2str(int);
    +
    +void		  roff_term_pre(struct termp *, const struct roff_node *);
    +
    +void		  term_eqn(struct termp *, const struct eqn_box *);
    +void		  term_tbl(struct termp *, const struct tbl_span *);
    +void		  term_free(struct termp *);
    +void		  term_setcol(struct termp *, size_t);
    +void		  term_newln(struct termp *);
    +void		  term_vspace(struct termp *);
    +void		  term_word(struct termp *, const char *);
    +void		  term_flushln(struct termp *);
    +void		  term_begin(struct termp *, term_margin,
    +			term_margin, const struct roff_meta *);
    +void		  term_end(struct termp *);
    +
    +void		  term_setwidth(struct termp *, const char *);
    +int		  term_hspan(const struct termp *, const struct roffsu *);
    +int		  term_hen(const struct termp *, const struct roffsu *);
    +int		  term_vspan(const struct termp *, const struct roffsu *);
    +size_t		  term_strlen(const struct termp *, const char *);
    +size_t		  term_len(const struct termp *, size_t);
    +
    +void		  term_tab_set(const struct termp *, const char *);
    +void		  term_tab_iset(size_t);
    +size_t		  term_tab_next(size_t);
    +
    +void		  term_fontpush(struct termp *, enum termfont);
    +void		  term_fontpop(struct termp *);
    +void		  term_fontpopq(struct termp *, int);
    +void		  term_fontrepl(struct termp *, enum termfont);
    +void		  term_fontlast(struct termp *);
    
    Property changes on: head/contrib/mandoc/term.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/term_tab.c
    ===================================================================
    --- head/contrib/mandoc/term_tab.c	(nonexistent)
    +++ head/contrib/mandoc/term_tab.c	(revision 338826)
    @@ -0,0 +1,128 @@
    +/*	$OpenBSD: term.c,v 1.119 2017/01/08 18:08:44 schwarze Exp $ */
    +/*
    + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include <sys/types.h>
    +
    +#include <stddef.h>
    +
    +#include "mandoc_aux.h"
    +#include "out.h"
    +#include "term.h"
    +
    +struct tablist {
    +	size_t	*t;	/* Allocated array of tab positions. */
    +	size_t	 s;	/* Allocated number of positions. */
    +	size_t	 n;	/* Currently used number of positions. */
    +};
    +
    +static struct {
    +	struct tablist	 a;	/* All tab positions for lookup. */
    +	struct tablist	 p;	/* Periodic tab positions to add. */
    +	size_t		 d;	/* Default tab width in units of n. */
    +} tabs;
    +
    +
    +void
    +term_tab_set(const struct termp *p, const char *arg)
    +{
    +	static int	 recording_period;
    +
    +	struct roffsu	 su;
    +	struct tablist	*tl;
    +	size_t		 pos;
    +	int		 add;
    +
    +	/* Special arguments: clear all tabs or switch lists. */
    +
    +	if (arg == NULL) {
    +		tabs.a.n = tabs.p.n = 0;
    +		recording_period = 0;
    +		if (tabs.d == 0) {
    +			a2roffsu(".8i", &su, SCALE_IN);
    +			tabs.d = term_hen(p, &su);
    +		}
    +		return;
    +	}
    +	if (arg[0] == 'T' && arg[1] == '\0') {
    +		recording_period = 1;
    +		return;
    +	}
    +
    +	/* Parse the sign, the number, and the unit. */
    +
    +	if (*arg == '+') {
    +		add = 1;
    +		arg++;
    +	} else
    +		add = 0;
    +	if (a2roffsu(arg, &su, SCALE_EM) == NULL)
    +		return;
    +
    +	/* Select the list, and extend it if it is full. */
    +
    +	tl = recording_period ? &tabs.p : &tabs.a;
    +	if (tl->n >= tl->s) {
    +		tl->s += 8;
    +		tl->t = mandoc_reallocarray(tl->t, tl->s, sizeof(*tl->t));
    +	}
    +
    +	/* Append the new position. */
    +
    +	pos = term_hen(p, &su);
    +	tl->t[tl->n] = pos;
    +	if (add && tl->n)
    +		tl->t[tl->n] += tl->t[tl->n - 1];
    +	tl->n++;
    +}
    +
    +/*
    + * Simplified version without a parser,
    + * never incremental, never periodic, for use by tbl(7).
    + */
    +void
    +term_tab_iset(size_t inc)
    +{
    +	if (tabs.a.n >= tabs.a.s) {
    +		tabs.a.s += 8;
    +		tabs.a.t = mandoc_reallocarray(tabs.a.t, tabs.a.s,
    +		    sizeof(*tabs.a.t));
    +	}
    +	tabs.a.t[tabs.a.n++] = inc;
    +}
    +
    +size_t
    +term_tab_next(size_t prev)
    +{
    +	size_t	 i, j;
    +
    +	for (i = 0;; i++) {
    +		if (i == tabs.a.n) {
    +			if (tabs.p.n == 0)
    +				return prev;
    +			tabs.a.n += tabs.p.n;
    +			if (tabs.a.s < tabs.a.n) {
    +				tabs.a.s = tabs.a.n;
    +				tabs.a.t = mandoc_reallocarray(tabs.a.t,
    +				    tabs.a.s, sizeof(*tabs.a.t));
    +			}
    +			for (j = 0; j < tabs.p.n; j++)
    +				tabs.a.t[i + j] = tabs.p.t[j] +
    +				    (i ? tabs.a.t[i - 1] : 0);
    +		}
    +		if (prev < tabs.a.t[i])
    +			return tabs.a.t[i];
    +	}
    +}
    
    Property changes on: head/contrib/mandoc/term_tab.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-recallocarray.c
    ===================================================================
    --- head/contrib/mandoc/test-recallocarray.c	(nonexistent)
    +++ head/contrib/mandoc/test-recallocarray.c	(revision 338826)
    @@ -0,0 +1,11 @@
    +#include <stdlib.h>
    +
    +int
    +main(void)
    +{
    +	void	*p;
    +
    +	if ((p = calloc(2, 2)) == NULL)
    +		return 1;
    +	return !recallocarray(p, 2, 3, 2);
    +}
    
    Property changes on: head/contrib/mandoc/test-recallocarray.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/catman.8
    ===================================================================
    --- head/contrib/mandoc/catman.8	(nonexistent)
    +++ head/contrib/mandoc/catman.8	(revision 338826)
    @@ -0,0 +1,186 @@
    +.\"	$Id: catman.8,v 1.8 2017/03/18 19:56:01 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: March 18 2017 $
    +.Dt CATMAN 8
    +.Os
    +.Sh NAME
    +.Nm catman
    +.Nd format all manual pages below a directory
    +.Sh SYNOPSIS
    +.Nm catman
    +.Op Fl I Cm os Ns = Ns Ar name
    +.Op Fl T Ar output
    +.Ar srcdir dstdir
    +.Sh DESCRIPTION
    +The
    +.Nm
    +utility assumes that all files below
    +.Ar srcdir
    +are manual pages in
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +format and formats all of them, storing the formatted versions in
    +the same relative paths below
    +.Ar dstdir .
    +Subdirectories of
    +.Ar dstdir
    +are created as needed.
    +Existing files are not explicitly deleted, but possibly overwritten.
    +.Pp
    +The options are as follows:
    +.Bl -tag -width Ds
    +.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.
    +.It Fl T Ar output
    +Output format.
    +The
    +.Ar output
    +argument can be
    +.Cm ascii ,
    +.Cm utf8 ,
    +or
    +.Cm html ;
    +see
    +.Xr mandoc 1 .
    +In
    +.Cm html
    +output mode, the
    +.Cm fragment
    +output option is implied.
    +Other output options are not supported.
    +.El
    +.Sh IMPLEMENTATION NOTES
    +Since this version avoids
    +.Xr fork 2
    +and
    +.Xr exec 3
    +overhead and uses the much faster
    +.Sy mandoc
    +parsers and formatters rather than
    +.Sy groff ,
    +it may be about one order of magnitude faster than other
    +.Nm
    +implementations.
    +.Sh EXIT STATUS
    +.Ex -std
    +.Pp
    +Possible errors include:
    +.Bl -bullet
    +.It
    +missing, invalid, or excessive command line arguments
    +.It
    +failure to change the current working directory to
    +.Ar srcdir
    +.It
    +failure to open
    +.Ar dstdir
    +.It
    +communication failure with
    +.Xr mandocd 8
    +.It
    +resource exhaustion, for example file descriptor, process table,
    +or memory exhaustion
    +.El
    +.Pp
    +Except for memory exhaustion and similar system-level failures,
    +failures while trying to open, read, parse, or format individual
    +manual pages, to save individual formatted files to the file system,
    +or even to create directories do not cause
    +.Nm
    +to return an error exit status.
    +In such cases,
    +.Nm
    +will simply continue with the next file or subdirectory.
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr mandocd 8
    +.Sh HISTORY
    +A
    +.Nm
    +utility first appeared in
    +.Fx 1.0 .
    +Other, incompatible implementations appeared in
    +.Nx 1.0
    +and in
    +.Sy man-db No 2.2 .
    +.Pp
    +This version appeared in version 1.14.1 of the
    +.Sy mandoc
    +toolkit.
    +.Sh AUTHORS
    +.An -nosplit
    +The first
    +.Nm
    +implementation was a short shell script by
    +.An Christoph Robitschko
    +in July 1993.
    +.Pp
    +The
    +.Nx
    +implementations were written by
    +.An J. T. Conklin Aq Mt jtc@netbsd.org
    +in 1993,
    +.An Christian E. Hopps Aq Mt chopps@netbsd.org
    +in 1994,
    +and
    +.An Dante Profeta Aq Mt dante@netbsd.org
    +in 1999; the
    +.Sy man-db
    +implementation by
    +.An Graeme W. Wilford
    +in 1994; and the
    +.Fx
    +implementations by
    +.An Wolfram Schneider Aq Mt wosch@freebsd.org
    +in 1995 and
    +.An John Rochester Aq Mt john@jrochester.org
    +in 2002.
    +.Pp
    +The concept of the present version was designed and implemented by
    +.An Michael Stapelberg Aq Mt stapelberg@debian.org
    +in 2017.
    +Option and argument handling and directory iteration was added by
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
    +.Sh CAVEATS
    +All versions of
    +.Nm
    +are incompatible with each other because each caters to the needs
    +of a specific operating system, for example regarding directory
    +structures and file naming conventions.
    +.Pp
    +This version is more flexible than the others in so far as it does
    +not assume any particular directory structure or naming convention.
    +That flexibility comes at the price of not being able to change the
    +names and relative paths of the source files when reusing them to
    +store the formatted files, of not supporting any configuration file
    +formats or environment variables, and of being unable to scan for
    +and remove junk files in
    +.Ar dstdir .
    +.Pp
    +Currently,
    +.Nm
    +always reformats each page, even if the formatted version is newer
    +than the source version.
    
    Property changes on: head/contrib/mandoc/catman.8
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/cgi.h.example
    ===================================================================
    --- head/contrib/mandoc/cgi.h.example	(nonexistent)
    +++ head/contrib/mandoc/cgi.h.example	(revision 338826)
    @@ -0,0 +1,7 @@
    +/* Example compile-time configuration file for man.cgi(8). */
    +
    +#define	SCRIPT_NAME "cgi-bin/man.cgi"
    +#define	MAN_DIR "/man"
    +#define	CSS_DIR ""
    +#define	CUSTOMIZE_TITLE "Manual pages with mandoc"
    +#define	COMPAT_OLDURI Yes
    Index: head/contrib/mandoc/libman.h
    ===================================================================
    --- head/contrib/mandoc/libman.h	(nonexistent)
    +++ head/contrib/mandoc/libman.h	(revision 338826)
    @@ -0,0 +1,40 @@
    +/*	$Id: libman.h,v 1.81 2017/04/29 12:45:41 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#define	MACRO_PROT_ARGS	  struct roff_man *man, \
    +			  enum roff_tok tok, \
    +			  int line, \
    +			  int ppos, \
    +			  int *pos, \
    +			  char *buf
    +
    +struct	man_macro {
    +	void		(*fp)(MACRO_PROT_ARGS);
    +	int		  flags;
    +#define	MAN_SCOPED	 (1 << 0)  /* Optional next-line scope. */
    +#define	MAN_NSCOPED	 (1 << 1)  /* Allowed in next-line element scope. */
    +#define	MAN_BSCOPE	 (1 << 2)  /* Break next-line block scope. */
    +#define	MAN_JOIN	 (1 << 3)  /* Join arguments together. */
    +};
    +
    +extern	const struct man_macro *const man_macros;
    +
    +
    +void		  man_node_validate(struct roff_man *);
    +void		  man_state(struct roff_man *, struct roff_node *);
    +void		  man_unscope(struct roff_man *, const struct roff_node *);
    
    Property changes on: head/contrib/mandoc/libman.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/libmdoc.h
    ===================================================================
    --- head/contrib/mandoc/libmdoc.h	(nonexistent)
    +++ head/contrib/mandoc/libmdoc.h	(revision 338826)
    @@ -0,0 +1,87 @@
    +/*	$Id: libmdoc.h,v 1.112 2017/05/30 16:22:03 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE 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	MACRO_PROT_ARGS	struct roff_man *mdoc, \
    +			enum roff_tok tok, \
    +			int line, \
    +			int ppos, \
    +			int *pos, \
    +			char *buf
    +
    +struct	mdoc_macro {
    +	void		(*fp)(MACRO_PROT_ARGS);
    +	int		  flags;
    +#define	MDOC_CALLABLE	 (1 << 0)
    +#define	MDOC_PARSED	 (1 << 1)
    +#define	MDOC_EXPLICIT	 (1 << 2)
    +#define	MDOC_PROLOGUE	 (1 << 3)
    +#define	MDOC_IGNDELIM	 (1 << 4)
    +#define	MDOC_JOIN	 (1 << 5)
    +};
    +
    +enum	margserr {
    +	ARGS_ERROR,
    +	ARGS_EOLN, /* end-of-line */
    +	ARGS_WORD, /* normal word */
    +	ARGS_PUNCT, /* series of punctuation */
    +	ARGS_PHRASE /* Bl -column phrase */
    +};
    +
    +/*
    + * A punctuation delimiter is opening, closing, or "middle mark"
    + * punctuation.  These govern spacing.
    + * Opening punctuation (e.g., the opening parenthesis) suppresses the
    + * following space; closing punctuation (e.g., the closing parenthesis)
    + * suppresses the leading space; middle punctuation (e.g., the vertical
    + * bar) can do either.  The middle punctuation delimiter bends the rules
    + * depending on usage.
    + */
    +enum	mdelim {
    +	DELIM_NONE = 0,
    +	DELIM_OPEN,
    +	DELIM_MIDDLE,
    +	DELIM_CLOSE,
    +	DELIM_MAX
    +};
    +
    +extern	const struct mdoc_macro *const mdoc_macros;
    +
    +
    +void		  mdoc_macro(MACRO_PROT_ARGS);
    +void		  mdoc_elem_alloc(struct roff_man *, int, int,
    +			enum roff_tok, struct mdoc_arg *);
    +struct roff_node *mdoc_block_alloc(struct roff_man *, int, int,
    +			enum roff_tok, struct mdoc_arg *);
    +void		  mdoc_tail_alloc(struct roff_man *, int, int,
    +			enum roff_tok);
    +struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int,
    +			enum roff_tok, struct roff_node *);
    +void		  mdoc_node_relink(struct roff_man *, struct roff_node *);
    +void		  mdoc_node_validate(struct roff_man *);
    +void		  mdoc_state(struct roff_man *, struct roff_node *);
    +void		  mdoc_state_reset(struct roff_man *);
    +const char	 *mdoc_a2arch(const char *);
    +const char	 *mdoc_a2att(const char *);
    +const char	 *mdoc_a2lib(const char *);
    +enum roff_sec	  mdoc_a2sec(const char *);
    +const char	 *mdoc_a2st(const char *);
    +void		  mdoc_argv(struct roff_man *, int, enum roff_tok,
    +			struct mdoc_arg **, int *, char *);
    +enum margserr	  mdoc_args(struct roff_man *, int,
    +			int *, char *, enum roff_tok, char **);
    +enum mdelim	  mdoc_isdelim(const char *);
    
    Property changes on: head/contrib/mandoc/libmdoc.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/main.h
    ===================================================================
    --- head/contrib/mandoc/main.h	(nonexistent)
    +++ head/contrib/mandoc/main.h	(revision 338826)
    @@ -0,0 +1,53 @@
    +/*	$Id: main.h,v 1.27 2017/03/03 14:23:23 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +struct	roff_man;
    +struct	manoutput;
    +
    +/*
    + * Definitions for main.c-visible output device functions, e.g., -Thtml
    + * and -Tascii.  Note that ascii_alloc() is named as such in
    + * anticipation of latin1_alloc() and so on, all of which map into the
    + * terminal output routines with different character settings.
    + */
    +
    +void		 *html_alloc(const struct manoutput *);
    +void		  html_mdoc(void *, const struct roff_man *);
    +void		  html_man(void *, const struct roff_man *);
    +void		  html_free(void *);
    +
    +void		  tree_mdoc(void *, const struct roff_man *);
    +void		  tree_man(void *, const struct roff_man *);
    +
    +void		  man_mdoc(void *, const struct roff_man *);
    +void		  man_man(void *, const struct roff_man *);
    +
    +void		 *locale_alloc(const struct manoutput *);
    +void		 *utf8_alloc(const struct manoutput *);
    +void		 *ascii_alloc(const struct manoutput *);
    +void		  ascii_free(void *);
    +
    +void		 *pdf_alloc(const struct manoutput *);
    +void		 *ps_alloc(const struct manoutput *);
    +void		  pspdf_free(void *);
    +
    +void		  terminal_mdoc(void *, const struct roff_man *);
    +void		  terminal_man(void *, const struct roff_man *);
    +void		  terminal_sepline(void *);
    +
    +void		  markdown_mdoc(void *, const struct roff_man *);
    
    Property changes on: head/contrib/mandoc/main.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/makewhatis.8
    ===================================================================
    --- head/contrib/mandoc/makewhatis.8	(nonexistent)
    +++ head/contrib/mandoc/makewhatis.8	(revision 338826)
    @@ -0,0 +1,228 @@
    +.\"	$Id: makewhatis.8,v 1.6 2017/05/17 22:27:12 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
    +.\" Copyright (c) 2011, 2012, 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: May 17 2017 $
    +.Dt MAKEWHATIS 8
    +.Os
    +.Sh NAME
    +.Nm makewhatis
    +.Nd index UNIX manuals
    +.Sh SYNOPSIS
    +.Nm
    +.Op Fl aDnpQ
    +.Op Fl T Cm utf8
    +.Op Fl C Ar file
    +.Nm
    +.Op Fl aDnpQ
    +.Op Fl T Cm utf8
    +.Ar dir ...
    +.Nm
    +.Op Fl DnpQ
    +.Op Fl T Cm utf8
    +.Fl d Ar dir
    +.Op Ar
    +.Nm
    +.Op Fl Dnp
    +.Op Fl T Cm utf8
    +.Fl u Ar dir
    +.Op Ar
    +.Nm
    +.Op Fl DQ
    +.Fl t Ar
    +.Sh DESCRIPTION
    +The
    +.Nm
    +utility extracts keywords from
    +.Ux
    +manuals and indexes them in a database for fast retrieval by
    +.Xr apropos 1 ,
    +.Xr whatis 1 ,
    +and
    +.Xr man 1 Ns 's
    +.Fl k
    +option.
    +.Pp
    +By default,
    +.Nm
    +creates a database in each
    +.Ar dir
    +using the files
    +.Sm off
    +.Sy man Ar section Li /
    +.Op Ar arch Li /
    +.Ar title . section
    +.Sm on
    +and
    +.Sm off
    +.Sy cat Ar section Li /
    +.Op Ar arch Li /
    +.Ar title . Sy 0
    +.Sm on
    +in that directory.
    +Existing databases are replaced.
    +If a directory contains no manual pages, no database is created in that
    +directory.
    +If
    +.Ar dir
    +is not provided,
    +.Nm
    +uses the default paths stipulated by
    +.Xr man.conf 5 .
    +.Pp
    +The arguments are as follows:
    +.Bl -tag -width "-C file"
    +.It Fl a
    +Use all directories and files found below
    +.Ar dir ... .
    +.It Fl C Ar file
    +Specify an alternative configuration
    +.Ar file
    +in
    +.Xr man.conf 5
    +format.
    +.It Fl D
    +Display all files added or removed to the index.
    +With a second
    +.Fl D ,
    +also show all keywords added for each file.
    +.It Fl d Ar dir
    +Merge (remove and re-add)
    +.Ar
    +to the database in
    +.Ar dir .
    +.It Fl n
    +Do not create or modify any database; scan and parse only,
    +and print manual page names and descriptions to standard output.
    +.It Fl p
    +Print warnings about potential problems with manual pages
    +to the standard error output.
    +.It Fl Q
    +Quickly build reduced-size databases
    +by reading only the NAME sections of manuals.
    +The resulting databases will usually contain names and descriptions only.
    +.It Fl T Cm utf8
    +Use UTF-8 encoding instead of ASCII for strings stored in the databases.
    +.It Fl t Ar
    +Check the given
    +.Ar files
    +for potential problems.
    +Implies
    +.Fl a ,
    +.Fl n ,
    +and
    +.Fl p .
    +All diagnostic messages are printed to the standard output;
    +the standard error output is not used.
    +.It Fl u Ar dir
    +Remove
    +.Ar
    +from the database in
    +.Ar dir .
    +If that causes the database to become empty, also delete the database file.
    +.El
    +.Pp
    +If fatal parse errors are encountered while parsing, the offending file
    +is printed to stderr, omitted from the index, and the parse continues
    +with the next input file.
    +.Sh ENVIRONMENT
    +.Bl -tag -width MANPATH
    +.It Ev MANPATH
    +A colon-separated list of directories to create databases in.
    +Ignored if a
    +.Ar dir
    +argument or the
    +.Fl t
    +option is specified.
    +.El
    +.Sh FILES
    +.Bl -tag -width Ds
    +.It Pa mandoc.db
    +A database of manpages relative to the directory of the file.
    +This file is portable across architectures and systems, so long as the
    +manpage hierarchy it indexes does not change.
    +.It Pa /etc/man.conf
    +The default
    +.Xr man 1
    +configuration file.
    +.El
    +.Sh EXIT STATUS
    +The
    +.Nm
    +utility exits with one of the following values:
    +.Pp
    +.Bl -tag -width Ds -compact
    +.It 0
    +No errors occurred.
    +.It 5
    +Invalid command line arguments were specified.
    +No input files have been read.
    +.It 6
    +An operating system error occurred, for example memory exhaustion or an
    +error accessing input files.
    +Such errors cause
    +.Nm
    +to exit at once, possibly in the middle of parsing or formatting a file.
    +The output databases are corrupt and should be removed.
    +.El
    +.Sh SEE ALSO
    +.Xr apropos 1 ,
    +.Xr man 1 ,
    +.Xr whatis 1 ,
    +.Xr man.conf 5
    +.Sh HISTORY
    +A
    +.Nm
    +utility first appeared in
    +.Bx 2 .
    +It was rewritten in
    +.Xr perl 1
    +for
    +.Ox 2.7
    +and in C for
    +.Ox 5.6 .
    +.Pp
    +The
    +.Ar dir
    +argument first appeared in
    +.Nx 1.0 ;
    +the options
    +.Fl dpt
    +in
    +.Ox 2.7 ;
    +the option
    +.Fl u
    +in
    +.Ox 3.4 ;
    +and the options
    +.Fl aCDnQT
    +in
    +.Ox 5.6 .
    +.Sh AUTHORS
    +.An -nosplit
    +.An Bill Joy
    +wrote the original
    +.Bx
    +.Nm
    +in February 1979,
    +.An Marc Espie
    +started the Perl version in 2000,
    +and the current version of
    +.Nm
    +was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +and
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
    
    Property changes on: head/contrib/mandoc/makewhatis.8
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man.cgi.3
    ===================================================================
    --- head/contrib/mandoc/man.cgi.3	(nonexistent)
    +++ head/contrib/mandoc/man.cgi.3	(revision 338826)
    @@ -0,0 +1,310 @@
    +.\"	$Id: man.cgi.3,v 1.4 2017/03/15 13:18:53 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: March 15 2017 $
    +.Dt MAN.CGI 3
    +.Os
    +.Sh NAME
    +.Nm man.cgi
    +.Nd internals of the CGI program to search and display manual pages
    +.Sh DESCRIPTION
    +The source code of
    +.Xr man.cgi 8
    +is organized in four levels:
    +.Pp
    +.Bl -enum -compact
    +.It
    +.Sx Top level
    +.It
    +.Sx Page generators
    +.It
    +.Sx Result generators
    +.It
    +.Sx Utility routines
    +.El
    +.Ss Top level
    +The top level of
    +.Xr man.cgi 8
    +consists of the
    +.Fn main
    +program and a few parser routines.
    +.Bl -tag -width 1n
    +.It Ft int Fn main void
    +The main program
    +.Bl -dash -compact
    +.It
    +limits execution time;
    +.It
    +changes to
    +.Dv MAN_DIR ,
    +the data directory containing all the manual trees;
    +.It
    +calls
    +.Fn parse_manpath_conf ;
    +.It
    +if
    +.Ev PATH_INFO
    +is empty, calls
    +.Fn parse_query_string ;
    +otherwise,
    +calls
    +.Fn parse_path_info ;
    +.It
    +validates the manpath and the architecture;
    +.It
    +calls the appropriate one among the
    +.Sx Page generators .
    +.El
    +.It Ft void Fn parse_manpath_conf "struct req *req"
    +Parses and validates
    +.Pa manpath.conf
    +and fills
    +.Va req->p
    +and
    +.Va req->psz .
    +.It Ft void Fn parse_path_info "struct req *req" "const char *path"
    +Parses and validates
    +.Ev PATH_INFO ,
    +clears
    +.Va req->isquery ,
    +and fills
    +.Va req->q .
    +.It Ft void Fn parse_query_string "struct req *req" "const char *qs"
    +Parses and validates
    +.Ev QUERY_STRING ,
    +sets
    +.Va req->isquery ,
    +and fills
    +.Va req->q .
    +This function is the only user of the utility functions
    +.Fn http_decode
    +and
    +.Fn set_query_attr .
    +.El
    +.Ss Page generators
    +The purpose of each page generator is to print a complete HTML page,
    +starting with the HTTP headers and continuing to the page footer.
    +Before starting HTML output with
    +.Fn resp_begin_html ,
    +some page generators do some preparatory work, for example to decide
    +which page to show.
    +Each page generator ends with a call to
    +.Fn resp_end_html .
    +.Bl -tag -width 1n
    +.It Ft void Fn pg_show "struct req *req" "const char *fullpath"
    +This page generator is used when
    +.Ev PATH_INFO
    +contains the complete path to a manual page including manpath,
    +section directory, optional architecture subdirectory, manual name
    +and section number suffix.
    +It validates the manpath, changes into it, validate the filename,
    +and then calls
    +.Fn resp_begin_html ,
    +.Fn resp_searchform ,
    +.Fn resp_show ,
    +and
    +.Fn resp_end_html
    +in that order.
    +.It Ft void Fn pg_search "const struct req *req"
    +This page generator is used when
    +.Ev PATH_INFO
    +contains a search query in short format or when
    +.Ev PATH_INFO
    +is empty and a
    +.Ev QUERY_STRING
    +is provided.
    +If possible, requests using
    +.Ev QUERY_STRING
    +are redirected to URIs using
    +.Ev PATH_INFO
    +by calling
    +.Fn pg_redirect .
    +Otherwise, it changes into the manpath and calls
    +.Xr mansearch 3 .
    +Depending on the result, it calls either
    +.Fn pg_noresult
    +or
    +.Fn pg_searchres .
    +.It Ft void Fn pg_redirect "const struct req *req" "const char *name"
    +This function is special in so far as it does not print an HTML page,
    +but only an HTTP 303 response with a Location: of the form:
    +.Sm off
    +.No http://
    +.Ar host Ns /
    +.Op Ar scriptname Ns /
    +.Op Ar manpath Ns /
    +.Op Ar arch Ns /
    +.Fa name
    +.Op Pf . Ar sec
    +.Sm on
    +.It Ft void Fn pg_noresult "const struct req *req" "const char *msg"
    +This function calls
    +.Fn resp_begin_html ,
    +.Fn resp_searchform ,
    +prints the
    +.Fa msg
    +passed to it, and calls
    +.Fn resp_end_html .
    +.It Ft void Fn pg_searchres "const struct req *req" "struct manpage *r"\
    + "size_t sz"
    +This function first validates the filenames found.
    +If
    +.Ev QUERY_STRING
    +was used and there is exactly one result,
    +it writes an HTTP redirect to that result.
    +Otherwise, it writes an HTML result page beginning with
    +.Fn resp_begin_html
    +and
    +.Fn resp_searchform .
    +If there is more than one result, it writes a list of links
    +to all the results.
    +If it was a
    +.Xr man 1
    +rather than an
    +.Xr apropos 1
    +query or if there is only one single result, it calls
    +.Fn resp_show .
    +Finally, it calls
    +.Fn resp_end_html .
    +.It Ft void Fn pg_index "const struct req *req"
    +This page generator is used when
    +.Ev PATH_INFO
    +and
    +.Ev QUERY_STRING
    +are both empty.
    +It calls
    +.Fn resp_begin_html
    +and
    +.Fn resp_searchform ,
    +writes links to help pages, and calls
    +.Fn resp_end_html .
    +.It Ft void Fn pg_error_badrequest "const char *msg"
    +This page generator is used when
    +.Fn main
    +or
    +.Fn pg_show
    +detect an invalid URI.
    +It calls
    +.Fn resp_begin_html ,
    +prints the
    +.Fa msg
    +provided, and calls
    +.Fn resp_end_html .
    +.It Ft void Fn pg_error_internal void
    +This page generator is used by various functions when errors are
    +detected in the
    +.Pa manpath.conf
    +configuration file, in
    +.Xr mandoc.db 5
    +databases, in the
    +.Xr mandoc 3
    +parser, in file system permissions, or when setting up timeouts.
    +It calls
    +.Fn resp_begin_html ,
    +prints
    +.Qq "Internal Server Error" ,
    +and calls
    +.Fn resp_end_html .
    +Before calling
    +.Fn pg_error_internal ,
    +call
    +.Xr warn 3
    +or
    +.Xr warnx 3
    +to log the reason of the error to the
    +.Xr httpd 8
    +server log file.
    +.El
    +.Ss Result generators
    +The purpose of result generators is to print a chunk of HTML code.
    +When they print untrusted strings or characters,
    +.Fn html_print
    +and
    +.Fn html_putchar
    +are used.
    +The highest level result generators are:
    +.Bl -tag -width 1n
    +.It Ft void Fn resp_begin_html "int code" "const char *msg" "const char *file"
    +This generator calls
    +.Fn resp_begin_http
    +to print the HTTP headers, then prints the HTML header up to the
    +opening tag of the <body> element, then copies the file
    +.Pa header.html
    +to the output, if it exists and is readable.
    +If
    +.Fa file
    +is not
    +.Dv NULL ,
    +it is used for the <title> element.
    +.It Ft void Fn resp_searchform "const struct req *req" "enum focus focus"
    +This generator prints a search form, filling it with data
    +from the provided request object.
    +If the
    +.Fa focus
    +argument is
    +.Dv FOCUS_QUERY ,
    +it sets the document's autofocus to the query input box.
    +.It Ft void Fn resp_show "const struct req *req" "const char *file"
    +This wrapper dispatches to either
    +.Fn resp_catman
    +or
    +.Fn resp_format ,
    +depending on whether
    +.Ar file
    +starts with
    +.Pa cat
    +or
    +.Pa man ,
    +respectively.
    +.It Ft void Fn resp_catman "const struct req *req" "const char *file"
    +This generator translates a preformatted, backspace-encoded manual
    +page to HTML and prints it to the output.
    +.It Ft void Fn resp_format "const struct req *req" "const char *file"
    +This generator formats a manual page on the standard output,
    +using the functions documented in
    +.Xr mchars_alloc 3
    +and
    +.Xr mandoc 3 .
    +.It Ft void Fn resp_end_html void
    +This generator copies the file
    +.Pa footer.html
    +to the output, if it exists and is readable,
    +and closes the <body> and <html> elements.
    +.El
    +.Ss Utility routines
    +These functions take a string and return 1 if it is valid, or 0 otherwise.
    +.Bl -tag -width 1n
    +.It Ft int Fn validate_urifrag "const char *frag"
    +Checks that the string only contains alphanumeric ASCII characters,
    +dashes, dots, slashes, and underscores.
    +.It Ft int Fn validate_manpath "const struct req *req" "const char* manpath"
    +Checks that the string is either
    +.Qq mandoc
    +or one of the manpaths configured in
    +.Pa manpath.conf .
    +.It Ft int Fn validate_filename "const char *file"
    +Checks that the string starts with
    +.Qq man
    +or
    +.Qq cat
    +and does not ascend to parent directories.
    +.El
    +.Sh SEE ALSO
    +.Xr mandoc 3 ,
    +.Xr mansearch 3 ,
    +.Xr mchars_alloc 3 ,
    +.Xr mandoc.db 5 ,
    +.Xr man.cgi 8
    
    Property changes on: head/contrib/mandoc/man.cgi.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man.h
    ===================================================================
    --- head/contrib/mandoc/man.h	(nonexistent)
    +++ head/contrib/mandoc/man.h	(revision 338826)
    @@ -0,0 +1,22 @@
    +/*	$Id: man.h,v 1.78 2017/04/24 23:06:18 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +struct	roff_man;
    +
    +const struct mparse	*man_mparse(const struct roff_man *);
    +void			 man_validate(struct roff_man *);
    
    Property changes on: head/contrib/mandoc/man.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandocd.8
    ===================================================================
    --- head/contrib/mandoc/mandocd.8	(nonexistent)
    +++ head/contrib/mandoc/mandocd.8	(revision 338826)
    @@ -0,0 +1,198 @@
    +.\"	$Id: mandocd.8,v 1.2 2017/03/18 19:56:01 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: March 18 2017 $
    +.Dt MANDOCD 8
    +.Os
    +.Sh NAME
    +.Nm mandocd
    +.Nd server process to format manual pages in batch mode
    +.Sh SYNOPSIS
    +.Nm mandocd
    +.Op Fl I Cm os Ns = Ns Ar name
    +.Op Fl T Ar output
    +.Ar socket_fd
    +.Sh DESCRIPTION
    +The
    +.Nm
    +utility formats many manual pages without requiring
    +.Xr fork 2
    +and
    +.Xr exec 3
    +overhead in between.
    +It does not require listing all the manuals to be formatted on the
    +command line, and it supports writing each formatted manual to its
    +own file descriptor.
    +.Pp
    +This server requires that a connected UNIX domain
    +.Xr socket 2
    +is already present at
    +.Xr exec 3
    +time.
    +Consequently, it cannot be started from the
    +.Xr sh 1
    +command line because the shell cannot supply such a socket.
    +Typically, the socket is created by the parent process using
    +.Xr socketpair 2
    +before calling
    +.Xr fork 2
    +and
    +.Xr exec 3
    +on
    +.Nm .
    +The parent process will pass the file descriptor number as an argument to
    +.Xr exec 3 ,
    +formatted as a decimal ASCII-encoded integer.
    +See
    +.Xr catman 8
    +for a typical implementation of a parent process.
    +.Pp
    +.Nm
    +loops reading one-byte messages with
    +.Xr recvmsg 2
    +from the file descriptor number
    +.Ar socket_fd .
    +It ignores the byte read and only uses the out-of-band auxiliary
    +.Vt struct cmsghdr
    +control data, typically supplied by the calling process using
    +.Xr CMSG_FIRSTHDR 3 .
    +The parent process is expected to pass three file descriptors
    +with each dummy byte.
    +The first one is used for
    +.Xr mdoc 7
    +or
    +.Xr man 7
    +input, the second one for formatted output, and the third one
    +for error output.
    +.Pp
    +The options are as follows:
    +.Bl -tag -width Ds
    +.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.
    +.It Fl T Ar output
    +Output format.
    +The
    +.Ar output
    +argument can be
    +.Cm ascii ,
    +.Cm utf8 ,
    +or
    +.Cm html ;
    +see
    +.Xr mandoc 1 .
    +In
    +.Cm html
    +output mode, the
    +.Cm fragment
    +output option is implied.
    +Other output options are not supported.
    +.El
    +.Pp
    +After exhausting one input file descriptor, all three file descriptors
    +are closed before reading the next dummy byte and control message.
    +.Pp
    +When a zero-byte message is read, when the
    +.Ar socket_fd
    +is closed by the parent process,
    +or when an error occurs,
    +.Nm
    +exits.
    +.Sh EXIT STATUS
    +.Ex -std
    +.Pp
    +A zero-byte message or a closed
    +.Ar socket_fd
    +is considered success.
    +Possible errors include:
    +.Bl -bullet
    +.It
    +missing, invalid, or excessive
    +.Xr exec 3
    +arguments
    +.It
    +.Xr recvmsg 2
    +failure, for example due to
    +.Er EMSGSIZE
    +.It
    +missing or unexpected control data, in particular a
    +.Fa cmsg_level
    +in the
    +.Vt struct cmsghdr
    +that differs from
    +.Dv SOL_SOCKET ,
    +a
    +.Fa cmsg_type
    +that differs from
    +.Dv SCM_RIGHTS ,
    +or a
    +.Fa cmsg_len
    +that is not three times the size of an
    +.Vt int
    +.It
    +invalid file descriptors passed in the
    +.Xr CMSG_DATA 3
    +.It
    +resource exhaustion, in particular
    +.Xr dup 2
    +or
    +.Xr malloc 3
    +failure
    +.El
    +.Pp
    +Except for memory exhaustion and similar system-level failures,
    +parsing and formatting errors do not cause
    +.Nm
    +to return an error exit status.
    +Even after severe parsing errors,
    +.Nm
    +will simply accept and process the next input file descriptor.
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr mandoc 3 ,
    +.Xr catman 8
    +.Sh HISTORY
    +The
    +.Nm
    +utility appeared in version 1.14.1 or the
    +.Sy mandoc
    +toolkit.
    +.Sh AUTHORS
    +.An -nosplit
    +The concept was designed and implemented by
    +.An Michael Stapelberg Aq Mt stapelberg@debian.org .
    +The
    +.Xr mandoc 3
    +glue needed to make it a stand-alone process was added by
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
    +.Sh CAVEATS
    +If the parsed manual pages contain
    +.Xr roff 7
    +.Pf . Ic so
    +requests,
    +.Nm
    +needs to be started with the current working directory set to the
    +root of the manual page tree.
    +Avoid starting it in directories that contain secret files in any
    +subdirectories, in particular in the user starting it has read
    +access to these secret files.
    
    Property changes on: head/contrib/mandoc/mandocd.8
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mansearch.3
    ===================================================================
    --- head/contrib/mandoc/mansearch.3	(nonexistent)
    +++ head/contrib/mandoc/mansearch.3	(revision 338826)
    @@ -0,0 +1,120 @@
    +.\"	$Id: mansearch.3,v 1.5 2017/03/30 22:22:05 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: March 30 2017 $
    +.Dt MANSEARCH 3
    +.Os
    +.Sh NAME
    +.Nm mansearch
    +.Nd search manual page databases
    +.Sh SYNOPSIS
    +.In stdint.h
    +.In manconf.h
    +.In mansearch.h
    +.Ft int
    +.Fo mansearch
    +.Fa "const struct mansearch *search"
    +.Fa "const struct manpaths *paths"
    +.Fa "int argc"
    +.Fa "char *argv[]"
    +.Fa "struct manpage **res"
    +.Fa "size_t *sz"
    +.Fc
    +.Sh DESCRIPTION
    +The
    +.Fn mansearch
    +function returns information about manuals matching a search query from a
    +.Xr mandoc.db 5
    +database.
    +.Pp
    +The query arguments are as follows:
    +.Bl -tag -width Ds
    +.It Fa "const struct mansearch *search"
    +Search options, defined in
    +.In mansearch.h .
    +.It Fa "const struct manpaths *paths"
    +Directories to be searched, defined in
    +.In manconf.h .
    +.It Fa "int argc" , "char *argv[]"
    +Search criteria, usually taken from the command line.
    +.El
    +.Pp
    +The output arguments are as follows:
    +.Bl -tag -width Ds
    +.It Fa "struct manpage **res"
    +Returns a pointer to an array of result structures defined in
    +.In mansearch.h .
    +The user is expected to call
    +.Xr free 3
    +on the
    +.Va file ,
    +.Va names ,
    +and
    +.Va output
    +fields of all structures, as well as the
    +.Fa res
    +array itself.
    +.It Fa "size_t *sz"
    +Returns the number of result structures contained in
    +.Fa res .
    +.El
    +.Sh IMPLEMENTATION NOTES
    +For each manual page tree, the search is done in two steps.
    +In the first step, a list of pages matching the search criteria is built.
    +In the second step, the requested information about these pages is
    +retrieved from the database and assembled into the
    +.Fa res
    +array.
    +.Pp
    +All function mentioned here are defined in the file
    +.Pa mansearch.c .
    +.Ss Finding matches
    +Command line parsing is done by the function
    +.Fn exprcomp
    +building a singly linked list of
    +.Vt expr
    +structures, using the helper functions
    +.Fn expr_and
    +and
    +.Fn exprterm .
    +.Ss Assembling the results
    +The names, sections, and architectures of the manuals found
    +are assembled into the
    +.Va names
    +field of the result structure by the function
    +.Fn buildnames .
    +.Sh FILES
    +.Bl -tag -width mandoc.db -compact
    +.It Pa mandoc.db
    +The manual page database.
    +.El
    +.Sh SEE ALSO
    +.Xr apropos 1 ,
    +.Xr mandoc.db 5 ,
    +.Xr makewhatis 8
    +.Sh HISTORY
    +The
    +.Fn mansearch
    +subsystem first appeared in
    +.Ox 5.6 .
    +.Sh AUTHORS
    +.An -nosplit
    +A module to search manual page databases was first written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +in 2011, at first using the Berkeley DB;
    +he rewrote it for SQLite3 in 2012, and
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org
    +removed the dependency on SQLite3 in 2016.
    
    Property changes on: head/contrib/mandoc/mansearch.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mansearch.h
    ===================================================================
    --- head/contrib/mandoc/mansearch.h	(nonexistent)
    +++ head/contrib/mandoc/mansearch.h	(revision 338826)
    @@ -0,0 +1,118 @@
    +/*	$Id: mansearch.h,v 1.28 2017/04/17 20:05:08 schwarze Exp $ */
    +/*
    + * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2013, 2014, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#define	MANDOC_DB	 "mandoc.db"
    +#define	MANDOCDB_MAGIC	 0x3a7d0cdb
    +#define	MANDOCDB_VERSION 1
    +
    +#define	MACRO_MAX	 36
    +#define	KEY_arch	 0
    +#define	KEY_sec		 1
    +#define	KEY_Nm		 38
    +#define	KEY_Nd		 39
    +#define	KEY_MAX		 40
    +
    +#define	TYPE_arch	 0x0000000000000001ULL
    +#define	TYPE_sec	 0x0000000000000002ULL
    +#define	TYPE_Xr		 0x0000000000000004ULL
    +#define	TYPE_Ar		 0x0000000000000008ULL
    +#define	TYPE_Fa		 0x0000000000000010ULL
    +#define	TYPE_Fl		 0x0000000000000020ULL
    +#define	TYPE_Dv		 0x0000000000000040ULL
    +#define	TYPE_Fn		 0x0000000000000080ULL
    +#define	TYPE_Ic		 0x0000000000000100ULL
    +#define	TYPE_Pa		 0x0000000000000200ULL
    +#define	TYPE_Cm		 0x0000000000000400ULL
    +#define	TYPE_Li		 0x0000000000000800ULL
    +#define	TYPE_Em		 0x0000000000001000ULL
    +#define	TYPE_Cd		 0x0000000000002000ULL
    +#define	TYPE_Va		 0x0000000000004000ULL
    +#define	TYPE_Ft		 0x0000000000008000ULL
    +#define	TYPE_Tn		 0x0000000000010000ULL
    +#define	TYPE_Er		 0x0000000000020000ULL
    +#define	TYPE_Ev		 0x0000000000040000ULL
    +#define	TYPE_Sy		 0x0000000000080000ULL
    +#define	TYPE_Sh		 0x0000000000100000ULL
    +#define	TYPE_In		 0x0000000000200000ULL
    +#define	TYPE_Ss		 0x0000000000400000ULL
    +#define	TYPE_Ox		 0x0000000000800000ULL
    +#define	TYPE_An		 0x0000000001000000ULL
    +#define	TYPE_Mt		 0x0000000002000000ULL
    +#define	TYPE_St		 0x0000000004000000ULL
    +#define	TYPE_Bx		 0x0000000008000000ULL
    +#define	TYPE_At		 0x0000000010000000ULL
    +#define	TYPE_Nx		 0x0000000020000000ULL
    +#define	TYPE_Fx		 0x0000000040000000ULL
    +#define	TYPE_Lk		 0x0000000080000000ULL
    +#define	TYPE_Ms		 0x0000000100000000ULL
    +#define	TYPE_Bsx	 0x0000000200000000ULL
    +#define	TYPE_Dx		 0x0000000400000000ULL
    +#define	TYPE_Rs		 0x0000000800000000ULL
    +#define	TYPE_Vt		 0x0000001000000000ULL
    +#define	TYPE_Lb		 0x0000002000000000ULL
    +#define	TYPE_Nm		 0x0000004000000000ULL
    +#define	TYPE_Nd		 0x0000008000000000ULL
    +
    +#define	NAME_SYN	 0x0000004000000001ULL
    +#define	NAME_FIRST	 0x0000004000000004ULL
    +#define	NAME_TITLE	 0x0000004000000006ULL
    +#define	NAME_HEAD	 0x0000004000000008ULL
    +#define	NAME_FILE	 0x0000004000000010ULL
    +#define	NAME_MASK	 0x000000000000001fULL
    +
    +enum	form {
    +	FORM_SRC = 1,	/* Format is mdoc(7) or man(7). */
    +	FORM_CAT,	/* Manual page is preformatted. */
    +	FORM_NONE	/* Format is unknown. */
    +};
    +
    +enum	argmode {
    +	ARG_FILE = 0,
    +	ARG_NAME,
    +	ARG_WORD,
    +	ARG_EXPR
    +};
    +
    +struct	manpage {
    +	char		*file; /* to be prefixed by manpath */
    +	char		*names; /* a list of names with sections */
    +	char		*output; /* user-defined additional output */
    +	size_t		 ipath; /* number of the manpath */
    +	uint64_t	 bits; /* name type mask */
    +	int		 sec; /* section number, 10 means invalid */
    +	enum form	 form;
    +};
    +
    +struct	mansearch {
    +	const char	*arch; /* architecture/NULL */
    +	const char	*sec; /* mansection/NULL */
    +	const char	*outkey; /* show content of this macro */
    +	enum argmode	 argmode; /* interpretation of arguments */
    +	int		 firstmatch; /* first matching database only */
    +};
    +
    +
    +struct	manpaths;
    +
    +int	mansearch(const struct mansearch *cfg, /* options */
    +		const struct manpaths *paths, /* manpaths */
    +		int argc, /* size of argv */
    +		char *argv[],  /* search terms */
    +		struct manpage **res, /* results */
    +		size_t *ressz); /* results returned */
    +void	mansearch_free(struct manpage *, size_t);
    
    Property changes on: head/contrib/mandoc/mansearch.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc.h
    ===================================================================
    --- head/contrib/mandoc/mdoc.h	(nonexistent)
    +++ head/contrib/mandoc/mdoc.h	(revision 338826)
    @@ -0,0 +1,155 @@
    +/*	$Id: mdoc.h,v 1.145 2017/04/24 23:06:18 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +enum	mdocargt {
    +	MDOC_Split, /* -split */
    +	MDOC_Nosplit, /* -nospli */
    +	MDOC_Ragged, /* -ragged */
    +	MDOC_Unfilled, /* -unfilled */
    +	MDOC_Literal, /* -literal */
    +	MDOC_File, /* -file */
    +	MDOC_Offset, /* -offset */
    +	MDOC_Bullet, /* -bullet */
    +	MDOC_Dash, /* -dash */
    +	MDOC_Hyphen, /* -hyphen */
    +	MDOC_Item, /* -item */
    +	MDOC_Enum, /* -enum */
    +	MDOC_Tag, /* -tag */
    +	MDOC_Diag, /* -diag */
    +	MDOC_Hang, /* -hang */
    +	MDOC_Ohang, /* -ohang */
    +	MDOC_Inset, /* -inset */
    +	MDOC_Column, /* -column */
    +	MDOC_Width, /* -width */
    +	MDOC_Compact, /* -compact */
    +	MDOC_Std, /* -std */
    +	MDOC_Filled, /* -filled */
    +	MDOC_Words, /* -words */
    +	MDOC_Emphasis, /* -emphasis */
    +	MDOC_Symbolic, /* -symbolic */
    +	MDOC_Nested, /* -nested */
    +	MDOC_Centred, /* -centered */
    +	MDOC_ARG_MAX
    +};
    +
    +/*
    + * An argument to a macro (multiple values = `-column xxx yyy').
    + */
    +struct	mdoc_argv {
    +	enum mdocargt	  arg; /* type of argument */
    +	int		  line;
    +	int		  pos;
    +	size_t		  sz; /* elements in "value" */
    +	char		**value; /* argument strings */
    +};
    +
    +/*
    + * Reference-counted macro arguments.  These are refcounted because
    + * blocks have multiple instances of the same arguments spread across
    + * the HEAD, BODY, TAIL, and BLOCK node types.
    + */
    +struct	mdoc_arg {
    +	size_t		  argc;
    +	struct mdoc_argv *argv;
    +	unsigned int	  refcnt;
    +};
    +
    +enum	mdoc_list {
    +	LIST__NONE = 0,
    +	LIST_bullet, /* -bullet */
    +	LIST_column, /* -column */
    +	LIST_dash, /* -dash */
    +	LIST_diag, /* -diag */
    +	LIST_enum, /* -enum */
    +	LIST_hang, /* -hang */
    +	LIST_hyphen, /* -hyphen */
    +	LIST_inset, /* -inset */
    +	LIST_item, /* -item */
    +	LIST_ohang, /* -ohang */
    +	LIST_tag, /* -tag */
    +	LIST_MAX
    +};
    +
    +enum	mdoc_disp {
    +	DISP__NONE = 0,
    +	DISP_centered, /* -centered */
    +	DISP_ragged, /* -ragged */
    +	DISP_unfilled, /* -unfilled */
    +	DISP_filled, /* -filled */
    +	DISP_literal /* -literal */
    +};
    +
    +enum	mdoc_auth {
    +	AUTH__NONE = 0,
    +	AUTH_split, /* -split */
    +	AUTH_nosplit /* -nosplit */
    +};
    +
    +enum	mdoc_font {
    +	FONT__NONE = 0,
    +	FONT_Em, /* Em, -emphasis */
    +	FONT_Li, /* Li, -literal */
    +	FONT_Sy /* Sy, -symbolic */
    +};
    +
    +struct	mdoc_bd {
    +	const char	 *offs; /* -offset */
    +	enum mdoc_disp	  type; /* -ragged, etc. */
    +	int		  comp; /* -compact */
    +};
    +
    +struct	mdoc_bl {
    +	const char	 *width; /* -width */
    +	const char	 *offs; /* -offset */
    +	enum mdoc_list	  type; /* -tag, -enum, etc. */
    +	int		  comp; /* -compact */
    +	size_t		  ncols; /* -column arg count */
    +	const char	**cols; /* -column val ptr */
    +	int		  count; /* -enum counter */
    +};
    +
    +struct	mdoc_bf {
    +	enum mdoc_font	  font; /* font */
    +};
    +
    +struct	mdoc_an {
    +	enum mdoc_auth	  auth; /* -split, etc. */
    +};
    +
    +struct	mdoc_rs {
    +	int		  quote_T; /* whether to quote %T */
    +};
    +
    +/*
    + * Consists of normalised node arguments.  These should be used instead
    + * of iterating through the mdoc_arg pointers of a node: defaults are
    + * provided, etc.
    + */
    +union	mdoc_data {
    +	struct mdoc_an	  An;
    +	struct mdoc_bd	  Bd;
    +	struct mdoc_bf	  Bf;
    +	struct mdoc_bl	  Bl;
    +	struct roff_node *Es;
    +	struct mdoc_rs	  Rs;
    +};
    +
    +/* Names of macro args.  Index is enum mdocargt. */
    +extern	const char *const *mdoc_argnames;
    +
    +void		 mdoc_validate(struct roff_man *);
    
    Property changes on: head/contrib/mandoc/mdoc.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc_argv.c
    ===================================================================
    --- head/contrib/mandoc/mdoc_argv.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc_argv.c	(revision 338826)
    @@ -0,0 +1,678 @@
    +/*	$Id: mdoc_argv.c,v 1.115 2017/05/30 16:22:03 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <stdlib.h>
    +#include <stdio.h>
    +#include <string.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "libmandoc.h"
    +#include "roff_int.h"
    +#include "libmdoc.h"
    +
    +#define	MULTI_STEP	 5 /* pre-allocate argument values */
    +#define	DELIMSZ		 6 /* max possible size of a delimiter */
    +
    +enum	argsflag {
    +	ARGSFL_NONE = 0,
    +	ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */
    +	ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */
    +};
    +
    +enum	argvflag {
    +	ARGV_NONE, /* no args to flag (e.g., -split) */
    +	ARGV_SINGLE, /* one arg to flag (e.g., -file xxx)  */
    +	ARGV_MULTI /* multiple args (e.g., -column xxx yyy) */
    +};
    +
    +struct	mdocarg {
    +	enum argsflag	 flags;
    +	const enum mdocargt *argvs;
    +};
    +
    +static	void		 argn_free(struct mdoc_arg *, int);
    +static	enum margserr	 args(struct roff_man *, int, int *,
    +				char *, enum argsflag, char **);
    +static	int		 args_checkpunct(const char *, int);
    +static	void		 argv_multi(struct roff_man *, int,
    +				struct mdoc_argv *, int *, char *);
    +static	void		 argv_single(struct roff_man *, int,
    +				struct mdoc_argv *, int *, char *);
    +
    +static	const enum argvflag argvflags[MDOC_ARG_MAX] = {
    +	ARGV_NONE,	/* MDOC_Split */
    +	ARGV_NONE,	/* MDOC_Nosplit */
    +	ARGV_NONE,	/* MDOC_Ragged */
    +	ARGV_NONE,	/* MDOC_Unfilled */
    +	ARGV_NONE,	/* MDOC_Literal */
    +	ARGV_SINGLE,	/* MDOC_File */
    +	ARGV_SINGLE,	/* MDOC_Offset */
    +	ARGV_NONE,	/* MDOC_Bullet */
    +	ARGV_NONE,	/* MDOC_Dash */
    +	ARGV_NONE,	/* MDOC_Hyphen */
    +	ARGV_NONE,	/* MDOC_Item */
    +	ARGV_NONE,	/* MDOC_Enum */
    +	ARGV_NONE,	/* MDOC_Tag */
    +	ARGV_NONE,	/* MDOC_Diag */
    +	ARGV_NONE,	/* MDOC_Hang */
    +	ARGV_NONE,	/* MDOC_Ohang */
    +	ARGV_NONE,	/* MDOC_Inset */
    +	ARGV_MULTI,	/* MDOC_Column */
    +	ARGV_SINGLE,	/* MDOC_Width */
    +	ARGV_NONE,	/* MDOC_Compact */
    +	ARGV_NONE,	/* MDOC_Std */
    +	ARGV_NONE,	/* MDOC_Filled */
    +	ARGV_NONE,	/* MDOC_Words */
    +	ARGV_NONE,	/* MDOC_Emphasis */
    +	ARGV_NONE,	/* MDOC_Symbolic */
    +	ARGV_NONE	/* MDOC_Symbolic */
    +};
    +
    +static	const enum mdocargt args_Ex[] = {
    +	MDOC_Std,
    +	MDOC_ARG_MAX
    +};
    +
    +static	const enum mdocargt args_An[] = {
    +	MDOC_Split,
    +	MDOC_Nosplit,
    +	MDOC_ARG_MAX
    +};
    +
    +static	const enum mdocargt args_Bd[] = {
    +	MDOC_Ragged,
    +	MDOC_Unfilled,
    +	MDOC_Filled,
    +	MDOC_Literal,
    +	MDOC_File,
    +	MDOC_Offset,
    +	MDOC_Compact,
    +	MDOC_Centred,
    +	MDOC_ARG_MAX
    +};
    +
    +static	const enum mdocargt args_Bf[] = {
    +	MDOC_Emphasis,
    +	MDOC_Literal,
    +	MDOC_Symbolic,
    +	MDOC_ARG_MAX
    +};
    +
    +static	const enum mdocargt args_Bk[] = {
    +	MDOC_Words,
    +	MDOC_ARG_MAX
    +};
    +
    +static	const enum mdocargt args_Bl[] = {
    +	MDOC_Bullet,
    +	MDOC_Dash,
    +	MDOC_Hyphen,
    +	MDOC_Item,
    +	MDOC_Enum,
    +	MDOC_Tag,
    +	MDOC_Diag,
    +	MDOC_Hang,
    +	MDOC_Ohang,
    +	MDOC_Inset,
    +	MDOC_Column,
    +	MDOC_Width,
    +	MDOC_Offset,
    +	MDOC_Compact,
    +	MDOC_Nested,
    +	MDOC_ARG_MAX
    +};
    +
    +static	const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = {
    +	{ ARGSFL_NONE, NULL }, /* Dd */
    +	{ ARGSFL_NONE, NULL }, /* Dt */
    +	{ ARGSFL_NONE, NULL }, /* Os */
    +	{ ARGSFL_NONE, NULL }, /* Sh */
    +	{ ARGSFL_NONE, NULL }, /* Ss */
    +	{ ARGSFL_NONE, NULL }, /* Pp */
    +	{ ARGSFL_DELIM, NULL }, /* D1 */
    +	{ ARGSFL_DELIM, NULL }, /* Dl */
    +	{ ARGSFL_NONE, args_Bd }, /* Bd */
    +	{ ARGSFL_NONE, NULL }, /* Ed */
    +	{ ARGSFL_NONE, args_Bl }, /* Bl */
    +	{ ARGSFL_NONE, NULL }, /* El */
    +	{ ARGSFL_NONE, NULL }, /* It */
    +	{ ARGSFL_DELIM, NULL }, /* Ad */
    +	{ ARGSFL_DELIM, args_An }, /* An */
    +	{ ARGSFL_DELIM, NULL }, /* Ap */
    +	{ ARGSFL_DELIM, NULL }, /* Ar */
    +	{ ARGSFL_DELIM, NULL }, /* Cd */
    +	{ ARGSFL_DELIM, NULL }, /* Cm */
    +	{ ARGSFL_DELIM, NULL }, /* Dv */
    +	{ ARGSFL_DELIM, NULL }, /* Er */
    +	{ ARGSFL_DELIM, NULL }, /* Ev */
    +	{ ARGSFL_NONE, args_Ex }, /* Ex */
    +	{ ARGSFL_DELIM, NULL }, /* Fa */
    +	{ ARGSFL_NONE, NULL }, /* Fd */
    +	{ ARGSFL_DELIM, NULL }, /* Fl */
    +	{ ARGSFL_DELIM, NULL }, /* Fn */
    +	{ ARGSFL_DELIM, NULL }, /* Ft */
    +	{ ARGSFL_DELIM, NULL }, /* Ic */
    +	{ ARGSFL_DELIM, NULL }, /* In */
    +	{ ARGSFL_DELIM, NULL }, /* Li */
    +	{ ARGSFL_NONE, NULL }, /* Nd */
    +	{ ARGSFL_DELIM, NULL }, /* Nm */
    +	{ ARGSFL_DELIM, NULL }, /* Op */
    +	{ ARGSFL_DELIM, NULL }, /* Ot */
    +	{ ARGSFL_DELIM, NULL }, /* Pa */
    +	{ ARGSFL_NONE, args_Ex }, /* Rv */
    +	{ ARGSFL_DELIM, NULL }, /* St */
    +	{ ARGSFL_DELIM, NULL }, /* Va */
    +	{ ARGSFL_DELIM, NULL }, /* Vt */
    +	{ ARGSFL_DELIM, NULL }, /* Xr */
    +	{ ARGSFL_NONE, NULL }, /* %A */
    +	{ ARGSFL_NONE, NULL }, /* %B */
    +	{ ARGSFL_NONE, NULL }, /* %D */
    +	{ ARGSFL_NONE, NULL }, /* %I */
    +	{ ARGSFL_NONE, NULL }, /* %J */
    +	{ ARGSFL_NONE, NULL }, /* %N */
    +	{ ARGSFL_NONE, NULL }, /* %O */
    +	{ ARGSFL_NONE, NULL }, /* %P */
    +	{ ARGSFL_NONE, NULL }, /* %R */
    +	{ ARGSFL_NONE, NULL }, /* %T */
    +	{ ARGSFL_NONE, NULL }, /* %V */
    +	{ ARGSFL_DELIM, NULL }, /* Ac */
    +	{ ARGSFL_NONE, NULL }, /* Ao */
    +	{ ARGSFL_DELIM, NULL }, /* Aq */
    +	{ ARGSFL_DELIM, NULL }, /* At */
    +	{ ARGSFL_DELIM, NULL }, /* Bc */
    +	{ ARGSFL_NONE, args_Bf }, /* Bf */
    +	{ ARGSFL_NONE, NULL }, /* Bo */
    +	{ ARGSFL_DELIM, NULL }, /* Bq */
    +	{ ARGSFL_DELIM, NULL }, /* Bsx */
    +	{ ARGSFL_DELIM, NULL }, /* Bx */
    +	{ ARGSFL_NONE, NULL }, /* Db */
    +	{ ARGSFL_DELIM, NULL }, /* Dc */
    +	{ ARGSFL_NONE, NULL }, /* Do */
    +	{ ARGSFL_DELIM, NULL }, /* Dq */
    +	{ ARGSFL_DELIM, NULL }, /* Ec */
    +	{ ARGSFL_NONE, NULL }, /* Ef */
    +	{ ARGSFL_DELIM, NULL }, /* Em */
    +	{ ARGSFL_NONE, NULL }, /* Eo */
    +	{ ARGSFL_DELIM, NULL }, /* Fx */
    +	{ ARGSFL_DELIM, NULL }, /* Ms */
    +	{ ARGSFL_DELIM, NULL }, /* No */
    +	{ ARGSFL_DELIM, NULL }, /* Ns */
    +	{ ARGSFL_DELIM, NULL }, /* Nx */
    +	{ ARGSFL_DELIM, NULL }, /* Ox */
    +	{ ARGSFL_DELIM, NULL }, /* Pc */
    +	{ ARGSFL_DELIM, NULL }, /* Pf */
    +	{ ARGSFL_NONE, NULL }, /* Po */
    +	{ ARGSFL_DELIM, NULL }, /* Pq */
    +	{ ARGSFL_DELIM, NULL }, /* Qc */
    +	{ ARGSFL_DELIM, NULL }, /* Ql */
    +	{ ARGSFL_NONE, NULL }, /* Qo */
    +	{ ARGSFL_DELIM, NULL }, /* Qq */
    +	{ ARGSFL_NONE, NULL }, /* Re */
    +	{ ARGSFL_NONE, NULL }, /* Rs */
    +	{ ARGSFL_DELIM, NULL }, /* Sc */
    +	{ ARGSFL_NONE, NULL }, /* So */
    +	{ ARGSFL_DELIM, NULL }, /* Sq */
    +	{ ARGSFL_NONE, NULL }, /* Sm */
    +	{ ARGSFL_DELIM, NULL }, /* Sx */
    +	{ ARGSFL_DELIM, NULL }, /* Sy */
    +	{ ARGSFL_DELIM, NULL }, /* Tn */
    +	{ ARGSFL_DELIM, NULL }, /* Ux */
    +	{ ARGSFL_DELIM, NULL }, /* Xc */
    +	{ ARGSFL_NONE, NULL }, /* Xo */
    +	{ ARGSFL_NONE, NULL }, /* Fo */
    +	{ ARGSFL_DELIM, NULL }, /* Fc */
    +	{ ARGSFL_NONE, NULL }, /* Oo */
    +	{ ARGSFL_DELIM, NULL }, /* Oc */
    +	{ ARGSFL_NONE, args_Bk }, /* Bk */
    +	{ ARGSFL_NONE, NULL }, /* Ek */
    +	{ ARGSFL_NONE, NULL }, /* Bt */
    +	{ ARGSFL_NONE, NULL }, /* Hf */
    +	{ ARGSFL_DELIM, NULL }, /* Fr */
    +	{ ARGSFL_NONE, NULL }, /* Ud */
    +	{ ARGSFL_DELIM, NULL }, /* Lb */
    +	{ ARGSFL_NONE, NULL }, /* Lp */
    +	{ ARGSFL_DELIM, NULL }, /* Lk */
    +	{ ARGSFL_DELIM, NULL }, /* Mt */
    +	{ ARGSFL_DELIM, NULL }, /* Brq */
    +	{ ARGSFL_NONE, NULL }, /* Bro */
    +	{ ARGSFL_DELIM, NULL }, /* Brc */
    +	{ ARGSFL_NONE, NULL }, /* %C */
    +	{ ARGSFL_NONE, NULL }, /* Es */
    +	{ ARGSFL_DELIM, NULL }, /* En */
    +	{ ARGSFL_DELIM, NULL }, /* Dx */
    +	{ ARGSFL_NONE, NULL }, /* %Q */
    +	{ ARGSFL_NONE, NULL }, /* %U */
    +	{ ARGSFL_NONE, NULL }, /* Ta */
    +};
    +static	const struct mdocarg *const mdocargs = __mdocargs - MDOC_Dd;
    +
    +
    +/*
    + * Parse flags and their arguments from the input line.
    + * These come in the form -flag [argument ...].
    + * Some flags take no argument, some one, some multiple.
    + */
    +void
    +mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok,
    +	struct mdoc_arg **reta, int *pos, char *buf)
    +{
    +	struct mdoc_argv	  tmpv;
    +	struct mdoc_argv	**retv;
    +	const enum mdocargt	 *argtable;
    +	char			 *argname;
    +	int			  ipos, retc;
    +	char			  savechar;
    +
    +	*reta = NULL;
    +
    +	/* Which flags does this macro support? */
    +
    +	assert(tok >= MDOC_Dd && tok < MDOC_MAX);
    +	argtable = mdocargs[tok].argvs;
    +	if (argtable == NULL)
    +		return;
    +
    +	/* Loop over the flags on the input line. */
    +
    +	ipos = *pos;
    +	while (buf[ipos] == '-') {
    +
    +		/* Seek to the first unescaped space. */
    +
    +		for (argname = buf + ++ipos; buf[ipos] != '\0'; ipos++)
    +			if (buf[ipos] == ' ' && buf[ipos - 1] != '\\')
    +				break;
    +
    +		/*
    +		 * We want to nil-terminate the word to look it up.
    +		 * But we may not have a flag, in which case we need
    +		 * to restore the line as-is.  So keep around the
    +		 * stray byte, which we'll reset upon exiting.
    +		 */
    +
    +		if ((savechar = buf[ipos]) != '\0')
    +			buf[ipos++] = '\0';
    +
    +		/*
    +		 * Now look up the word as a flag.  Use temporary
    +		 * storage that we'll copy into the node's flags.
    +		 */
    +
    +		while ((tmpv.arg = *argtable++) != MDOC_ARG_MAX)
    +			if ( ! strcmp(argname, mdoc_argnames[tmpv.arg]))
    +				break;
    +
    +		/* If it isn't a flag, restore the saved byte. */
    +
    +		if (tmpv.arg == MDOC_ARG_MAX) {
    +			if (savechar != '\0')
    +				buf[ipos - 1] = savechar;
    +			break;
    +		}
    +
    +		/* Read to the next word (the first argument). */
    +
    +		while (buf[ipos] == ' ')
    +			ipos++;
    +
    +		/* Parse the arguments of the flag. */
    +
    +		tmpv.line  = line;
    +		tmpv.pos   = *pos;
    +		tmpv.sz    = 0;
    +		tmpv.value = NULL;
    +
    +		switch (argvflags[tmpv.arg]) {
    +		case ARGV_SINGLE:
    +			argv_single(mdoc, line, &tmpv, &ipos, buf);
    +			break;
    +		case ARGV_MULTI:
    +			argv_multi(mdoc, line, &tmpv, &ipos, buf);
    +			break;
    +		case ARGV_NONE:
    +			break;
    +		}
    +
    +		/* Append to the return values. */
    +
    +		if (*reta == NULL)
    +			*reta = mandoc_calloc(1, sizeof(**reta));
    +
    +		retc = ++(*reta)->argc;
    +		retv = &(*reta)->argv;
    +		*retv = mandoc_reallocarray(*retv, retc, sizeof(**retv));
    +		memcpy(*retv + retc - 1, &tmpv, sizeof(**retv));
    +
    +		/* Prepare for parsing the next flag. */
    +
    +		*pos = ipos;
    +		argtable = mdocargs[tok].argvs;
    +	}
    +}
    +
    +void
    +mdoc_argv_free(struct mdoc_arg *p)
    +{
    +	int		 i;
    +
    +	if (NULL == p)
    +		return;
    +
    +	if (p->refcnt) {
    +		--(p->refcnt);
    +		if (p->refcnt)
    +			return;
    +	}
    +	assert(p->argc);
    +
    +	for (i = (int)p->argc - 1; i >= 0; i--)
    +		argn_free(p, i);
    +
    +	free(p->argv);
    +	free(p);
    +}
    +
    +static void
    +argn_free(struct mdoc_arg *p, int iarg)
    +{
    +	struct mdoc_argv *arg;
    +	int		  j;
    +
    +	arg = &p->argv[iarg];
    +
    +	if (arg->sz && arg->value) {
    +		for (j = (int)arg->sz - 1; j >= 0; j--)
    +			free(arg->value[j]);
    +		free(arg->value);
    +	}
    +
    +	for (--p->argc; iarg < (int)p->argc; iarg++)
    +		p->argv[iarg] = p->argv[iarg+1];
    +}
    +
    +enum margserr
    +mdoc_args(struct roff_man *mdoc, int line, int *pos,
    +	char *buf, enum roff_tok tok, char **v)
    +{
    +	struct roff_node *n;
    +	char		 *v_local;
    +	enum argsflag	  fl;
    +
    +	if (v == NULL)
    +		v = &v_local;
    +	fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok].flags;
    +
    +	/*
    +	 * We know that we're in an `It', so it's reasonable to expect
    +	 * us to be sitting in a `Bl'.  Someday this may not be the case
    +	 * (if we allow random `It's sitting out there), so provide a
    +	 * safe fall-back into the default behaviour.
    +	 */
    +
    +	if (tok == MDOC_It) {
    +		for (n = mdoc->last; n != NULL; n = n->parent) {
    +			if (n->tok != MDOC_Bl)
    +				continue;
    +			if (n->norm->Bl.type == LIST_column)
    +				fl = ARGSFL_TABSEP;
    +			break;
    +		}
    +	}
    +
    +	return args(mdoc, line, pos, buf, fl, v);
    +}
    +
    +static enum margserr
    +args(struct roff_man *mdoc, int line, int *pos,
    +		char *buf, enum argsflag fl, char **v)
    +{
    +	char		*p;
    +	int		 pairs;
    +
    +	if (buf[*pos] == '\0') {
    +		if (mdoc->flags & MDOC_PHRASELIT &&
    +		    ! (mdoc->flags & MDOC_PHRASE)) {
    +			mandoc_msg(MANDOCERR_ARG_QUOTE,
    +			    mdoc->parse, line, *pos, NULL);
    +			mdoc->flags &= ~MDOC_PHRASELIT;
    +		}
    +		return ARGS_EOLN;
    +	}
    +
    +	*v = buf + *pos;
    +
    +	if (fl == ARGSFL_DELIM && args_checkpunct(buf, *pos))
    +		return ARGS_PUNCT;
    +
    +	/*
    +	 * Tabs in `It' lines in `Bl -column' can't be escaped.
    +	 * Phrases are reparsed for `Ta' and other macros later.
    +	 */
    +
    +	if (fl == ARGSFL_TABSEP) {
    +		if ((p = strchr(*v, '\t')) != NULL) {
    +
    +			/*
    +			 * Words right before and right after
    +			 * tab characters are not parsed,
    +			 * unless there is a blank in between.
    +			 */
    +
    +			if (p > buf && p[-1] != ' ')
    +				mdoc->flags |= MDOC_PHRASEQL;
    +			if (p[1] != ' ')
    +				mdoc->flags |= MDOC_PHRASEQN;
    +
    +			/*
    +			 * One or more blanks after a tab cause
    +			 * one leading blank in the next column.
    +			 * So skip all but one of them.
    +			 */
    +
    +			*pos += (int)(p - *v) + 1;
    +			while (buf[*pos] == ' ' && buf[*pos + 1] == ' ')
    +				(*pos)++;
    +
    +			/*
    +			 * A tab at the end of an input line
    +			 * switches to the next column.
    +			 */
    +
    +			if (buf[*pos] == '\0' || buf[*pos + 1] == '\0')
    +				mdoc->flags |= MDOC_PHRASEQN;
    +		} else {
    +			p = strchr(*v, '\0');
    +			if (p[-1] == ' ')
    +				mandoc_msg(MANDOCERR_SPACE_EOL,
    +				    mdoc->parse, line, *pos, NULL);
    +			*pos += (int)(p - *v);
    +		}
    +
    +		/* Skip any trailing blank characters. */
    +		while (p > *v && p[-1] == ' ' &&
    +		    (p - 1 == *v || p[-2] != '\\'))
    +			p--;
    +		*p = '\0';
    +
    +		return ARGS_PHRASE;
    +	}
    +
    +	/*
    +	 * Process a quoted literal.  A quote begins with a double-quote
    +	 * and ends with a double-quote NOT preceded by a double-quote.
    +	 * NUL-terminate the literal in place.
    +	 * Collapse pairs of quotes inside quoted literals.
    +	 * Whitespace is NOT involved in literal termination.
    +	 */
    +
    +	if (mdoc->flags & MDOC_PHRASELIT || buf[*pos] == '\"') {
    +		if ( ! (mdoc->flags & MDOC_PHRASELIT))
    +			*v = &buf[++(*pos)];
    +
    +		if (mdoc->flags & MDOC_PHRASE)
    +			mdoc->flags |= MDOC_PHRASELIT;
    +
    +		pairs = 0;
    +		for ( ; buf[*pos]; (*pos)++) {
    +			/* Move following text left after quoted quotes. */
    +			if (pairs)
    +				buf[*pos - pairs] = buf[*pos];
    +			if ('\"' != buf[*pos])
    +				continue;
    +			/* Unquoted quotes end quoted args. */
    +			if ('\"' != buf[*pos + 1])
    +				break;
    +			/* Quoted quotes collapse. */
    +			pairs++;
    +			(*pos)++;
    +		}
    +		if (pairs)
    +			buf[*pos - pairs] = '\0';
    +
    +		if (buf[*pos] == '\0') {
    +			if ( ! (mdoc->flags & MDOC_PHRASE))
    +				mandoc_msg(MANDOCERR_ARG_QUOTE,
    +				    mdoc->parse, line, *pos, NULL);
    +			return ARGS_WORD;
    +		}
    +
    +		mdoc->flags &= ~MDOC_PHRASELIT;
    +		buf[(*pos)++] = '\0';
    +
    +		if ('\0' == buf[*pos])
    +			return ARGS_WORD;
    +
    +		while (' ' == buf[*pos])
    +			(*pos)++;
    +
    +		if ('\0' == buf[*pos])
    +			mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
    +			    line, *pos, NULL);
    +
    +		return ARGS_WORD;
    +	}
    +
    +	p = &buf[*pos];
    +	*v = mandoc_getarg(mdoc->parse, &p, line, pos);
    +
    +	/*
    +	 * After parsing the last word in this phrase,
    +	 * tell lookup() whether or not to interpret it.
    +	 */
    +
    +	if (*p == '\0' && mdoc->flags & MDOC_PHRASEQL) {
    +		mdoc->flags &= ~MDOC_PHRASEQL;
    +		mdoc->flags |= MDOC_PHRASEQF;
    +	}
    +	return ARGS_WORD;
    +}
    +
    +/*
    + * Check if the string consists only of space-separated closing
    + * delimiters.  This is a bit of a dance: the first must be a close
    + * delimiter, but it may be followed by middle delimiters.  Arbitrary
    + * whitespace may separate these tokens.
    + */
    +static int
    +args_checkpunct(const char *buf, int i)
    +{
    +	int		 j;
    +	char		 dbuf[DELIMSZ];
    +	enum mdelim	 d;
    +
    +	/* First token must be a close-delimiter. */
    +
    +	for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++)
    +		dbuf[j] = buf[i];
    +
    +	if (DELIMSZ == j)
    +		return 0;
    +
    +	dbuf[j] = '\0';
    +	if (DELIM_CLOSE != mdoc_isdelim(dbuf))
    +		return 0;
    +
    +	while (' ' == buf[i])
    +		i++;
    +
    +	/* Remaining must NOT be open/none. */
    +
    +	while (buf[i]) {
    +		j = 0;
    +		while (buf[i] && ' ' != buf[i] && j < DELIMSZ)
    +			dbuf[j++] = buf[i++];
    +
    +		if (DELIMSZ == j)
    +			return 0;
    +
    +		dbuf[j] = '\0';
    +		d = mdoc_isdelim(dbuf);
    +		if (DELIM_NONE == d || DELIM_OPEN == d)
    +			return 0;
    +
    +		while (' ' == buf[i])
    +			i++;
    +	}
    +
    +	return '\0' == buf[i];
    +}
    +
    +static void
    +argv_multi(struct roff_man *mdoc, int line,
    +		struct mdoc_argv *v, int *pos, char *buf)
    +{
    +	enum margserr	 ac;
    +	char		*p;
    +
    +	for (v->sz = 0; ; v->sz++) {
    +		if (buf[*pos] == '-')
    +			break;
    +		ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
    +		if (ac == ARGS_EOLN)
    +			break;
    +
    +		if (v->sz % MULTI_STEP == 0)
    +			v->value = mandoc_reallocarray(v->value,
    +			    v->sz + MULTI_STEP, sizeof(char *));
    +
    +		v->value[(int)v->sz] = mandoc_strdup(p);
    +	}
    +}
    +
    +static void
    +argv_single(struct roff_man *mdoc, int line,
    +		struct mdoc_argv *v, int *pos, char *buf)
    +{
    +	enum margserr	 ac;
    +	char		*p;
    +
    +	ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
    +	if (ac == ARGS_EOLN)
    +		return;
    +
    +	v->sz = 1;
    +	v->value = mandoc_malloc(sizeof(char *));
    +	v->value[0] = mandoc_strdup(p);
    +}
    
    Property changes on: head/contrib/mandoc/mdoc_argv.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mdoc_macro.c
    ===================================================================
    --- head/contrib/mandoc/mdoc_macro.c	(nonexistent)
    +++ head/contrib/mandoc/mdoc_macro.c	(revision 338826)
    @@ -0,0 +1,1505 @@
    +/*	$Id: mdoc_macro.c,v 1.224 2017/05/30 16:22:03 schwarze Exp $ */
    +/*
    + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <ctype.h>
    +#include <stdlib.h>
    +#include <stdio.h>
    +#include <string.h>
    +#include <time.h>
    +
    +#include "mandoc.h"
    +#include "roff.h"
    +#include "mdoc.h"
    +#include "libmandoc.h"
    +#include "roff_int.h"
    +#include "libmdoc.h"
    +
    +static	void		blk_full(MACRO_PROT_ARGS);
    +static	void		blk_exp_close(MACRO_PROT_ARGS);
    +static	void		blk_part_exp(MACRO_PROT_ARGS);
    +static	void		blk_part_imp(MACRO_PROT_ARGS);
    +static	void		ctx_synopsis(MACRO_PROT_ARGS);
    +static	void		in_line_eoln(MACRO_PROT_ARGS);
    +static	void		in_line_argn(MACRO_PROT_ARGS);
    +static	void		in_line(MACRO_PROT_ARGS);
    +static	void		phrase_ta(MACRO_PROT_ARGS);
    +
    +static	void		append_delims(struct roff_man *, int, int *, char *);
    +static	void		dword(struct roff_man *, int, int, const char *,
    +				enum mdelim, int);
    +static	int		find_pending(struct roff_man *, enum roff_tok,
    +				int, int, struct roff_node *);
    +static	int		lookup(struct roff_man *, int, int, int, const char *);
    +static	int		macro_or_word(MACRO_PROT_ARGS, int);
    +static	void		break_intermediate(struct roff_node *,
    +				struct roff_node *);
    +static	int		parse_rest(struct roff_man *, enum roff_tok,
    +				int, int *, char *);
    +static	enum roff_tok	rew_alt(enum roff_tok);
    +static	void		rew_elem(struct roff_man *, enum roff_tok);
    +static	void		rew_last(struct roff_man *, const struct roff_node *);
    +static	void		rew_pending(struct roff_man *,
    +				const struct roff_node *);
    +
    +const	struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = {
    +	{ in_line_eoln, MDOC_PROLOGUE }, /* Dd */
    +	{ in_line_eoln, MDOC_PROLOGUE }, /* Dt */
    +	{ in_line_eoln, MDOC_PROLOGUE }, /* Os */
    +	{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* Sh */
    +	{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* Ss */
    +	{ in_line_eoln, 0 }, /* Pp */
    +	{ blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* D1 */
    +	{ blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* Dl */
    +	{ blk_full, MDOC_EXPLICIT }, /* Bd */
    +	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ed */
    +	{ blk_full, MDOC_EXPLICIT }, /* Bl */
    +	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* El */
    +	{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_IGNDELIM | MDOC_JOIN }, /* Ap */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
    +	{ in_line_eoln, 0 }, /* Ex */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
    +	{ in_line_eoln, 0 }, /* Fd */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ic */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Li */
    +	{ blk_full, MDOC_JOIN }, /* Nd */
    +	{ ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ot */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
    +	{ in_line_eoln, 0 }, /* Rv */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
    +	{ ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
    +	{ in_line_eoln, MDOC_JOIN }, /* %A */
    +	{ in_line_eoln, MDOC_JOIN }, /* %B */
    +	{ in_line_eoln, MDOC_JOIN }, /* %D */
    +	{ in_line_eoln, MDOC_JOIN }, /* %I */
    +	{ in_line_eoln, MDOC_JOIN }, /* %J */
    +	{ in_line_eoln, 0 }, /* %N */
    +	{ in_line_eoln, MDOC_JOIN }, /* %O */
    +	{ in_line_eoln, 0 }, /* %P */
    +	{ in_line_eoln, MDOC_JOIN }, /* %R */
    +	{ in_line_eoln, MDOC_JOIN }, /* %T */
    +	{ in_line_eoln, 0 }, /* %V */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Ac */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_EXPLICIT | MDOC_JOIN }, /* Ao */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Aq */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Bc */
    +	{ blk_full, MDOC_EXPLICIT }, /* Bf */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_EXPLICIT | MDOC_JOIN }, /* Bo */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Bq */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
    +	{ in_line_eoln, 0 }, /* Db */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Dc */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_EXPLICIT | MDOC_JOIN }, /* Do */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Dq */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ec */
    +	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ef */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Em */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* No */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Pc */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_EXPLICIT | MDOC_JOIN }, /* Po */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Pq */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Qc */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ql */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_EXPLICIT | MDOC_JOIN }, /* Qo */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Qq */
    +	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Re */
    +	{ blk_full, MDOC_EXPLICIT }, /* Rs */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Sc */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_EXPLICIT | MDOC_JOIN }, /* So */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */
    +	{ in_line_argn, 0 }, /* Sm */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ux */
    +	{ blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
    +	{ blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Fc */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_EXPLICIT | MDOC_JOIN }, /* Oo */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Oc */
    +	{ blk_full, MDOC_EXPLICIT }, /* Bk */
    +	{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */
    +	{ in_line_eoln, 0 }, /* Bt */
    +	{ in_line_eoln, 0 }, /* Hf */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fr */
    +	{ in_line_eoln, 0 }, /* Ud */
    +	{ in_line, 0 }, /* Lb */
    +	{ in_line_eoln, 0 }, /* Lp */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
    +	{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Brq */
    +	{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
    +			MDOC_EXPLICIT | MDOC_JOIN }, /* Bro */
    +	{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
    +			 MDOC_EXPLICIT | MDOC_JOIN }, /* Brc */
    +	{ in_line_eoln, MDOC_JOIN }, /* %C */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Es */
    +	{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* En */
    +	{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
    +	{ in_line_eoln, MDOC_JOIN }, /* %Q */
    +	{ in_line_eoln, 0 }, /* %U */
    +	{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
    +};
    +const	struct mdoc_macro *const mdoc_macros = __mdoc_macros - MDOC_Dd;
    +
    +
    +/*
    + * This is called at the end of parsing.  It must traverse up the tree,
    + * closing out open [implicit] scopes.  Obviously, open explicit scopes
    + * are errors.
    + */
    +void
    +mdoc_endparse(struct roff_man *mdoc)
    +{
    +	struct roff_node *n;
    +
    +	/* Scan for open explicit scopes. */
    +
    +	n = mdoc->last->flags & NODE_VALID ?
    +	    mdoc->last->parent : mdoc->last;
    +
    +	for ( ; n; n = n->parent)
    +		if (n->type == ROFFT_BLOCK &&
    +		    mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
    +			mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
    +			    n->line, n->pos, roff_name[n->tok]);
    +
    +	/* Rewind to the first. */
    +
    +	rew_last(mdoc, mdoc->first);
    +	mdoc_state_reset(mdoc);
    +}
    +
    +/*
    + * Look up the macro at *p called by "from",
    + * or as a line macro if from == TOKEN_NONE.
    + */
    +static int
    +lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p)
    +{
    +	enum roff_tok	 res;
    +
    +	if (mdoc->flags & MDOC_PHRASEQF) {
    +		mdoc->flags &= ~MDOC_PHRASEQF;
    +		return TOKEN_NONE;
    +	}
    +	if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) {
    +		res = roffhash_find(mdoc->mdocmac, p, 0);
    +		if (res != TOKEN_NONE) {
    +			if (mdoc_macros[res].flags & MDOC_CALLABLE)
    +				return res;
    +			mandoc_msg(MANDOCERR_MACRO_CALL,
    +			    mdoc->parse, line, ppos, p);
    +		}
    +	}
    +	return TOKEN_NONE;
    +}
    +
    +/*
    + * Rewind up to and including a specific node.
    + */
    +static void
    +rew_last(struct roff_man *mdoc, const struct roff_node *to)
    +{
    +
    +	if (to->flags & NODE_VALID)
    +		return;
    +
    +	while (mdoc->last != to) {
    +		mdoc_state(mdoc, mdoc->last);
    +		mdoc->last->flags |= NODE_VALID | NODE_ENDED;
    +		mdoc->last = mdoc->last->parent;
    +	}
    +	mdoc_state(mdoc, mdoc->last);
    +	mdoc->last->flags |= NODE_VALID | NODE_ENDED;
    +	mdoc->next = ROFF_NEXT_SIBLING;
    +}
    +
    +/*
    + * Rewind up to a specific block, including all blocks that broke it.
    + */
    +static void
    +rew_pending(struct roff_man *mdoc, const struct roff_node *n)
    +{
    +
    +	for (;;) {
    +		rew_last(mdoc, n);
    +
    +		if (mdoc->last == n) {
    +			switch (n->type) {
    +			case ROFFT_HEAD:
    +				roff_body_alloc(mdoc, n->line, n->pos,
    +				    n->tok);
    +				break;
    +			case ROFFT_BLOCK:
    +				break;
    +			default:
    +				return;
    +			}
    +			if ( ! (n->flags & NODE_BROKEN))
    +				return;
    +		} else
    +			n = mdoc->last;
    +
    +		for (;;) {
    +			if ((n = n->parent) == NULL)
    +				return;
    +
    +			if (n->type == ROFFT_BLOCK ||
    +			    n->type == ROFFT_HEAD) {
    +				if (n->flags & NODE_ENDED)
    +					break;
    +				else
    +					return;
    +			}
    +		}
    +	}
    +}
    +
    +/*
    + * For a block closing macro, return the corresponding opening one.
    + * Otherwise, return the macro itself.
    + */
    +static enum roff_tok
    +rew_alt(enum roff_tok tok)
    +{
    +	switch (tok) {
    +	case MDOC_Ac:
    +		return MDOC_Ao;
    +	case MDOC_Bc:
    +		return MDOC_Bo;
    +	case MDOC_Brc:
    +		return MDOC_Bro;
    +	case MDOC_Dc:
    +		return MDOC_Do;
    +	case MDOC_Ec:
    +		return MDOC_Eo;
    +	case MDOC_Ed:
    +		return MDOC_Bd;
    +	case MDOC_Ef:
    +		return MDOC_Bf;
    +	case MDOC_Ek:
    +		return MDOC_Bk;
    +	case MDOC_El:
    +		return MDOC_Bl;
    +	case MDOC_Fc:
    +		return MDOC_Fo;
    +	case MDOC_Oc:
    +		return MDOC_Oo;
    +	case MDOC_Pc:
    +		return MDOC_Po;
    +	case MDOC_Qc:
    +		return MDOC_Qo;
    +	case MDOC_Re:
    +		return MDOC_Rs;
    +	case MDOC_Sc:
    +		return MDOC_So;
    +	case MDOC_Xc:
    +		return MDOC_Xo;
    +	default:
    +		return tok;
    +	}
    +}
    +
    +static void
    +rew_elem(struct roff_man *mdoc, enum roff_tok tok)
    +{
    +	struct roff_node *n;
    +
    +	n = mdoc->last;
    +	if (n->type != ROFFT_ELEM)
    +		n = n->parent;
    +	assert(n->type == ROFFT_ELEM);
    +	assert(tok == n->tok);
    +	rew_last(mdoc, n);
    +}
    +
    +static void
    +break_intermediate(struct roff_node *n, struct roff_node *breaker)
    +{
    +	if (n != breaker &&
    +	    n->type != ROFFT_BLOCK && n->type != ROFFT_HEAD &&
    +	    (n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
    +		n = n->parent;
    +	while (n != breaker) {
    +		if ( ! (n->flags & NODE_VALID))
    +			n->flags |= NODE_BROKEN;
    +		n = n->parent;
    +	}
    +}
    +
    +/*
    + * If there is an open sub-block of the target requiring
    + * explicit close-out, postpone closing out the target until
    + * the rew_pending() call closing out the sub-block.
    + */
    +static int
    +find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos,
    +	struct roff_node *target)
    +{
    +	struct roff_node	*n;
    +	int			 irc;
    +
    +	if (target->flags & NODE_VALID)
    +		return 0;
    +
    +	irc = 0;
    +	for (n = mdoc->last; n != NULL && n != target; n = n->parent) {
    +		if (n->flags & NODE_ENDED)
    +			continue;
    +		if (n->type == ROFFT_BLOCK &&
    +		    mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
    +			irc = 1;
    +			break_intermediate(mdoc->last, target);
    +			if (target->type == ROFFT_HEAD)
    +				target->flags |= NODE_ENDED;
    +			else if ( ! (target->flags & NODE_ENDED)) {
    +				mandoc_vmsg(MANDOCERR_BLK_NEST,
    +				    mdoc->parse, line, ppos,
    +				    "%s breaks %s", roff_name[tok],
    +				    roff_name[n->tok]);
    +				mdoc_endbody_alloc(mdoc, line, ppos,
    +				    tok, target);
    +			}
    +		}
    +	}
    +	return irc;
    +}
    +
    +/*
    + * Allocate a word and check whether it's punctuation or not.
    + * Punctuation consists of those tokens found in mdoc_isdelim().
    + */
    +static void
    +dword(struct roff_man *mdoc, int line, int col, const char *p,
    +		enum mdelim d, int may_append)
    +{
    +
    +	if (d == DELIM_MAX)
    +		d = mdoc_isdelim(p);
    +
    +	if (may_append &&
    +	    ! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) &&
    +	    d == DELIM_NONE && mdoc->last->type == ROFFT_TEXT &&
    +	    mdoc_isdelim(mdoc->last->string) == DELIM_NONE) {
    +		roff_word_append(mdoc, p);
    +		return;
    +	}
    +
    +	roff_word_alloc(mdoc, line, col, p);
    +
    +	/*
    +	 * If the word consists of a bare delimiter,
    +	 * flag the new node accordingly,
    +	 * unless doing so was vetoed by the invoking macro.
    +	 * Always clear the veto, it is only valid for one word.
    +	 */
    +
    +	if (d == DELIM_OPEN)
    +		mdoc->last->flags |= NODE_DELIMO;
    +	else if (d == DELIM_CLOSE &&
    +	    ! (mdoc->flags & MDOC_NODELIMC) &&
    +	    mdoc->last->parent->tok != MDOC_Fd)
    +		mdoc->last->flags |= NODE_DELIMC;
    +	mdoc->flags &= ~MDOC_NODELIMC;
    +}
    +
    +static void
    +append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
    +{
    +	char		*p;
    +	int		 la;
    +
    +	if (buf[*pos] == '\0')
    +		return;
    +
    +	for (;;) {
    +		la = *pos;
    +		if (mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p) ==
    +		    ARGS_EOLN)
    +			break;
    +		dword(mdoc, line, la, p, DELIM_MAX, 1);
    +
    +		/*
    +		 * If we encounter end-of-sentence symbols, then trigger
    +		 * the double-space.
    +		 *
    +		 * XXX: it's easy to allow this to propagate outward to
    +		 * the last symbol, such that `. )' will cause the
    +		 * correct double-spacing.  However, (1) groff isn't
    +		 * smart enough to do this and (2) it would require
    +		 * knowing which symbols break this behaviour, for
    +		 * example, `.  ;' shouldn't propagate the double-space.
    +		 */
    +
    +		if (mandoc_eos(p, strlen(p)))
    +			mdoc->last->flags |= NODE_EOS;
    +	}
    +}
    +
    +/*
    + * Parse one word.
    + * If it is a macro, call it and return 1.
    + * Otherwise, allocate it and return 0.
    + */
    +static int
    +macro_or_word(MACRO_PROT_ARGS, int parsed)
    +{
    +	char		*p;
    +	int		 ntok;
    +
    +	p = buf + ppos;
    +	ntok = TOKEN_NONE;
    +	if (*p == '"')
    +		p++;
    +	else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
    +		ntok = lookup(mdoc, tok, line, ppos, p);
    +
    +	if (ntok == TOKEN_NONE) {
    +		dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE ||
    +		    mdoc_macros[tok].flags & MDOC_JOIN);
    +		return 0;
    +	} else {
    +		if (tok != TOKEN_NONE &&
    +		    mdoc_macros[tok].fp == in_line_eoln)
    +			rew_elem(mdoc, tok);
    +		mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
    +		if (tok == TOKEN_NONE)
    +			append_delims(mdoc, line, pos, buf);
    +		return 1;
    +	}
    +}
    +
    +/*
    + * Close out block partial/full explicit.
    + */
    +static void
    +blk_exp_close(MACRO_PROT_ARGS)
    +{
    +	struct roff_node *body;		/* Our own body. */
    +	struct roff_node *endbody;	/* Our own end marker. */
    +	struct roff_node *itblk;	/* An It block starting later. */
    +	struct roff_node *later;	/* A sub-block starting later. */
    +	struct roff_node *n;		/* Search back to our block. */
    +	struct roff_node *target;	/* For find_pending(). */
    +
    +	int		 j, lastarg, maxargs, nl, pending;
    +	enum margserr	 ac;
    +	enum roff_tok	 atok, ntok;
    +	char		*p;
    +
    +	nl = MDOC_NEWLINE & mdoc->flags;
    +
    +	switch (tok) {
    +	case MDOC_Ec:
    +		maxargs = 1;
    +		break;
    +	case MDOC_Ek:
    +		mdoc->flags &= ~MDOC_KEEP;
    +		/* FALLTHROUGH */
    +	default:
    +		maxargs = 0;
    +		break;
    +	}
    +
    +	/* Search backwards for the beginning of our own body. */
    +
    +	atok = rew_alt(tok);
    +	body = NULL;
    +	for (n = mdoc->last; n; n = n->parent) {
    +		if (n->flags & NODE_ENDED || n->tok != atok ||
    +		    n->type != ROFFT_BODY || n->end != ENDBODY_NOT)
    +			continue;
    +		body = n;
    +		break;
    +	}
    +
    +	/*
    +	 * Search backwards for beginnings of blocks,
    +	 * both of our own and of pending sub-blocks.
    +	 */
    +
    +	endbody = itblk = later = NULL;
    +	for (n = mdoc->last; n; n = n->parent) {
    +		if (n->flags & NODE_ENDED)
    +			continue;
    +
    +		/*
    +		 * Mismatching end macros can never break anything
    +		 * and we only care about the breaking of BLOCKs.
    +		 */
    +
    +		if (body == NULL || n->type != ROFFT_BLOCK)
    +			continue;
    +
    +		/*
    +		 * SYNOPSIS name blocks can not be broken themselves,
    +		 * but they do get broken together with a broken child.
    +		 */
    +
    +		if (n->tok == MDOC_Nm) {
    +			if (later != NULL)
    +				n->flags |= NODE_BROKEN | NODE_ENDED;
    +			continue;
    +		}
    +
    +		if (n->tok == MDOC_It) {
    +			itblk = n;
    +			continue;
    +		}
    +
    +		if (atok == n->tok) {
    +
    +			/*
    +			 * Found the start of our own block.
    +			 * When there is no pending sub block,
    +			 * just proceed to closing out.
    +			 */
    +
    +			if (later == NULL ||
    +			    (tok == MDOC_El && itblk == NULL))
    +				break;
    +
    +			/*
    +			 * When there is a pending sub block, postpone
    +			 * closing out the current block until the
    +			 * rew_pending() closing out the sub-block.
    +			 * Mark the place where the formatting - but not
    +			 * the scope - of the current block ends.
    +			 */
    +
    +			mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse,
    +			    line, ppos, "%s breaks %s",
    +			    roff_name[atok], roff_name[later->tok]);
    +
    +			endbody = mdoc_endbody_alloc(mdoc, line, ppos,
    +			    atok, body);
    +
    +			if (tok == MDOC_El)
    +				itblk->flags |= NODE_ENDED | NODE_BROKEN;
    +
    +			/*
    +			 * If a block closing macro taking arguments
    +			 * breaks another block, put the arguments
    +			 * into the end marker.
    +			 */
    +
    +			if (maxargs)
    +				mdoc->next = ROFF_NEXT_CHILD;
    +			break;
    +		}
    +
    +		/*
    +		 * Explicit blocks close out description lines, but
    +		 * even those can get broken together with a child.
    +		 */
    +
    +		if (n->tok == MDOC_Nd) {
    +			if (later != NULL)
    +				n->flags |= NODE_BROKEN | NODE_ENDED;
    +			else
    +				rew_last(mdoc, n);
    +			continue;
    +		}
    +
    +		/* Breaking an open sub block. */
    +
    +		break_intermediate(mdoc->last, body);
    +		n->flags |= NODE_BROKEN;
    +		if (later == NULL)
    +			later = n;
    +	}
    +
    +	if (body == NULL) {
    +		mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
    +		    line, ppos, roff_name[tok]);
    +		if (maxargs && endbody == NULL) {
    +			/*
    +			 * Stray .Ec without previous .Eo:
    +			 * Break the output line, keep the arguments.
    +			 */
    +			roff_elem_alloc(mdoc, line, ppos, ROFF_br);
    +			rew_elem(mdoc, ROFF_br);
    +		}
    +	} else if (endbody == NULL) {
    +		rew_last(mdoc, body);
    +		if (maxargs)
    +			mdoc_tail_alloc(mdoc, line, ppos, atok);
    +	}
    +
    +	if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
    +		if (buf[*pos] != '\0')
    +			mandoc_vmsg(MANDOCERR_ARG_SKIP,
    +			    mdoc->parse, line, ppos,
    +			    "%s %s", roff_name[tok],
    +			    buf + *pos);
    +		if (endbody == NULL && n != NULL)
    +			rew_pending(mdoc, n);
    +		return;
    +	}
    +
    +	if (endbody != NULL)
    +		n = endbody;
    +
    +	ntok = TOKEN_NONE;
    +	for (j = 0; ; j++) {
    +		lastarg = *pos;
    +
    +		if (j == maxargs && n != NULL)
    +			rew_last(mdoc, n);
    +
    +		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
    +		if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
    +			break;
    +
    +		ntok = lookup(mdoc, tok, line, lastarg, p);
    +
    +		if (ntok == TOKEN_NONE) {
    +			dword(mdoc, line, lastarg, p, DELIM_MAX,
    +			    MDOC_JOIN & mdoc_macros[tok].flags);
    +			continue;
    +		}
    +
    +		if (n != NULL)
    +			rew_last(mdoc, n);
    +		mdoc->flags &= ~MDOC_NEWLINE;
    +		mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
    +		break;
    +	}
    +
    +	if (n != NULL) {
    +		pending = 0;
    +		if (ntok != TOKEN_NONE && n->flags & NODE_BROKEN) {
    +			target = n;
    +			do
    +				target = target->parent;
    +			while ( ! (target->flags & NODE_ENDED));
    +			pending = find_pending(mdoc, ntok, line, ppos, target);
    +		}
    +		if ( ! pending)
    +			rew_pending(mdoc, n);
    +	}
    +	if (nl)
    +		append_delims(mdoc, line, pos, buf);
    +}
    +
    +static void
    +in_line(MACRO_PROT_ARGS)
    +{
    +	int		 la, scope, cnt, firstarg, mayopen, nc, nl;
    +	enum roff_tok	 ntok;
    +	enum margserr	 ac;
    +	enum mdelim	 d;
    +	struct mdoc_arg	*arg;
    +	char		*p;
    +
    +	nl = MDOC_NEWLINE & mdoc->flags;
    +
    +	/*
    +	 * Whether we allow ignored elements (those without content,
    +	 * usually because of reserved words) to squeak by.
    +	 */
    +
    +	switch (tok) {
    +	case MDOC_An:
    +	case MDOC_Ar:
    +	case MDOC_Fl:
    +	case MDOC_Mt:
    +	case MDOC_Nm:
    +	case MDOC_Pa:
    +		nc = 1;
    +		break;
    +	default:
    +		nc = 0;
    +		break;
    +	}
    +
    +	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
    +
    +	d = DELIM_NONE;
    +	firstarg = 1;
    +	mayopen = 1;
    +	for (cnt = scope = 0;; ) {
    +		la = *pos;
    +		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
    +
    +		/*
    +		 * At the end of a macro line,
    +		 * opening delimiters do not suppress spacing.
    +		 */
    +
    +		if (ac == ARGS_EOLN) {
    +			if (d == DELIM_OPEN)
    +				mdoc->last->flags &= ~NODE_DELIMO;
    +			break;
    +		}
    +
    +		/*
    +		 * The rest of the macro line is only punctuation,
    +		 * to be handled by append_delims().
    +		 * If there were no other arguments,
    +		 * do not allow the first one to suppress spacing,
    +		 * even if it turns out to be a closing one.
    +		 */
    +
    +		if (ac == ARGS_PUNCT) {
    +			if (cnt == 0 && (nc == 0 || tok == MDOC_An))
    +				mdoc->flags |= MDOC_NODELIMC;
    +			break;
    +		}
    +
    +		ntok = (tok == MDOC_Fn && !cnt) ?
    +		    TOKEN_NONE : lookup(mdoc, tok, line, la, p);
    +
    +		/*
    +		 * In this case, we've located a submacro and must
    +		 * execute it.  Close out scope, if open.  If no
    +		 * elements have been generated, either create one (nc)
    +		 * or raise a warning.
    +		 */
    +
    +		if (ntok != TOKEN_NONE) {
    +			if (scope)
    +				rew_elem(mdoc, tok);
    +			if (nc && ! cnt) {
    +				mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
    +				rew_last(mdoc, mdoc->last);
    +			} else if ( ! nc && ! cnt) {
    +				mdoc_argv_free(arg);
    +				mandoc_msg(MANDOCERR_MACRO_EMPTY,
    +				    mdoc->parse, line, ppos,
    +				    roff_name[tok]);
    +			}
    +			mdoc_macro(mdoc, ntok, line, la, pos, buf);
    +			if (nl)
    +				append_delims(mdoc, line, pos, buf);
    +			return;
    +		}
    +
    +		/*
    +		 * Handle punctuation.  Set up our scope, if a word;
    +		 * rewind the scope, if a delimiter; then append the word.
    +		 */
    +
    +		if ((d = mdoc_isdelim(p)) != DELIM_NONE) {
    +			/*
    +			 * If we encounter closing punctuation, no word
    +			 * has been emitted, no scope is open, and we're
    +			 * allowed to have an empty element, then start
    +			 * a new scope.
    +			 */
    +			if ((d == DELIM_CLOSE ||
    +			     (d == DELIM_MIDDLE && tok == MDOC_Fl)) &&
    +			    !cnt && !scope && nc && mayopen) {
    +				mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
    +				scope = 1;
    +				cnt++;
    +				if (tok == MDOC_Nm)
    +					mayopen = 0;
    +			}
    +			/*
    +			 * Close out our scope, if one is open, before
    +			 * any punctuation.
    +			 */
    +			if (scope && tok != MDOC_Lk) {
    +				rew_elem(mdoc, tok);
    +				scope = 0;
    +				if (tok == MDOC_Fn)
    +					mayopen = 0;
    +			}
    +		} else if (mayopen && !scope) {
    +			mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
    +			scope = 1;
    +			cnt++;
    +		}
    +
    +		dword(mdoc, line, la, p, d,
    +		    mdoc_macros[tok].flags & MDOC_JOIN);
    +
    +		/*
    +		 * If the first argument is a closing delimiter,
    +		 * do not suppress spacing before it.
    +		 */
    +
    +		if (firstarg && d == DELIM_CLOSE && !nc)
    +			mdoc->last->flags &= ~NODE_DELIMC;
    +		firstarg = 0;
    +
    +		/*
    +		 * `Fl' macros have their scope re-opened with each new
    +		 * word so that the `-' can be added to each one without
    +		 * having to parse out spaces.
    +		 */
    +		if (scope && tok == MDOC_Fl) {
    +			rew_elem(mdoc, tok);
    +			scope = 0;
    +		}
    +	}
    +
    +	if (scope && tok != MDOC_Lk) {
    +		rew_elem(mdoc, tok);
    +		scope = 0;
    +	}
    +
    +	/*
    +	 * If no elements have been collected and we're allowed to have
    +	 * empties (nc), open a scope and close it out.  Otherwise,
    +	 * raise a warning.
    +	 */
    +
    +	if ( ! cnt) {
    +		if (nc) {
    +			mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
    +			rew_last(mdoc, mdoc->last);
    +		} else {
    +			mdoc_argv_free(arg);
    +			mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
    +			    line, ppos, roff_name[tok]);
    +		}
    +	}
    +	if (nl)
    +		append_delims(mdoc, line, pos, buf);
    +	if (scope)
    +		rew_elem(mdoc, tok);
    +}
    +
    +static void
    +blk_full(MACRO_PROT_ARGS)
    +{
    +	int		  la, nl, parsed;
    +	struct mdoc_arg	 *arg;
    +	struct roff_node *blk; /* Our own or a broken block. */
    +	struct roff_node *head; /* Our own head. */
    +	struct roff_node *body; /* Our own body. */
    +	struct roff_node *n;
    +	enum margserr	  ac, lac;
    +	char		 *p;
    +
    +	nl = MDOC_NEWLINE & mdoc->flags;
    +
    +	if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
    +		mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
    +		    line, ppos, roff_name[tok]);
    +		return;
    +	}
    +
    +	if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
    +
    +		/* Here, tok is one of Sh Ss Nm Nd It. */
    +
    +		blk = NULL;
    +		for (n = mdoc->last; n != NULL; n = n->parent) {
    +			if (n->flags & NODE_ENDED) {
    +				if ( ! (n->flags & NODE_VALID))
    +					n->flags |= NODE_BROKEN;
    +				continue;
    +			}
    +			if (n->type != ROFFT_BLOCK)
    +				continue;
    +
    +			if (tok == MDOC_It && n->tok == MDOC_Bl) {
    +				if (blk != NULL) {
    +					mandoc_vmsg(MANDOCERR_BLK_BROKEN,
    +					    mdoc->parse, line, ppos,
    +					    "It breaks %s",
    +					    roff_name[blk->tok]);
    +					rew_pending(mdoc, blk);
    +				}
    +				break;
    +			}
    +
    +			if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
    +				switch (tok) {
    +				case MDOC_Sh:
    +				case MDOC_Ss:
    +					mandoc_vmsg(MANDOCERR_BLK_BROKEN,
    +					    mdoc->parse, line, ppos,
    +					    "%s breaks %s", roff_name[tok],
    +					    roff_name[n->tok]);
    +					rew_pending(mdoc, n);
    +					n = mdoc->last;
    +					continue;
    +				case MDOC_It:
    +					/* Delay in case it's astray. */
    +					blk = n;
    +					continue;
    +				default:
    +					break;
    +				}
    +				break;
    +			}
    +
    +			/* Here, n is one of Sh Ss Nm Nd It. */
    +
    +			if (tok != MDOC_Sh && (n->tok == MDOC_Sh ||
    +			    (tok != MDOC_Ss && (n->tok == MDOC_Ss ||
    +			     (tok != MDOC_It && n->tok == MDOC_It)))))
    +				break;
    +
    +			/* Item breaking an explicit block. */
    +
    +			if (blk != NULL) {
    +				mandoc_vmsg(MANDOCERR_BLK_BROKEN,
    +				    mdoc->parse, line, ppos,
    +				    "It breaks %s", roff_name[blk->tok]);
    +				rew_pending(mdoc, blk);
    +				blk = NULL;
    +			}
    +
    +			/* Close out prior implicit scopes. */
    +
    +			rew_pending(mdoc, n);
    +		}
    +
    +		/* Skip items outside lists. */
    +
    +		if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
    +			mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
    +			    line, ppos, "It %s", buf + *pos);
    +			roff_elem_alloc(mdoc, line, ppos, ROFF_br);
    +			rew_elem(mdoc, ROFF_br);
    +			return;
    +		}
    +	}
    +
    +	/*
    +	 * This routine accommodates implicitly- and explicitly-scoped
    +	 * macro openings.  Implicit ones first close out prior scope
    +	 * (seen above).  Delay opening the head until necessary to
    +	 * allow leading punctuation to print.  Special consideration
    +	 * for `It -column', which has phrase-part syntax instead of
    +	 * regular child nodes.
    +	 */
    +
    +	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
    +	blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg);
    +	head = body = NULL;
    +
    +	/*
    +	 * Exception: Heads of `It' macros in `-diag' lists are not
    +	 * parsed, even though `It' macros in general are parsed.
    +	 */
    +
    +	parsed = tok != MDOC_It ||
    +	    mdoc->last->parent->tok != MDOC_Bl ||
    +	    mdoc->last->parent->norm->Bl.type != LIST_diag;
    +
    +	/*
    +	 * The `Nd' macro has all arguments in its body: it's a hybrid
    +	 * of block partial-explicit and full-implicit.  Stupid.
    +	 */
    +
    +	if (tok == MDOC_Nd) {
    +		head = roff_head_alloc(mdoc, line, ppos, tok);
    +		rew_last(mdoc, head);
    +		body = roff_body_alloc(mdoc, line, ppos, tok);
    +	}
    +
    +	if (tok == MDOC_Bk)
    +		mdoc->flags |= MDOC_KEEP;
    +
    +	ac = ARGS_EOLN;
    +	for (;;) {
    +
    +		/*
    +		 * If we are right after a tab character,
    +		 * do not parse the first word for macros.
    +		 */
    +
    +		if (mdoc->flags & MDOC_PHRASEQN) {
    +			mdoc->flags &= ~MDOC_PHRASEQN;
    +			mdoc->flags |= MDOC_PHRASEQF;
    +		}
    +
    +		la = *pos;
    +		lac = ac;
    +		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
    +		if (ac == ARGS_EOLN) {
    +			if (lac != ARGS_PHRASE ||
    +			    ! (mdoc->flags & MDOC_PHRASEQF))
    +				break;
    +
    +			/*
    +			 * This line ends in a tab; start the next
    +			 * column now, with a leading blank.
    +			 */
    +
    +			if (body != NULL)
    +				rew_last(mdoc, body);
    +			body = roff_body_alloc(mdoc, line, ppos, tok);
    +			roff_word_alloc(mdoc, line, ppos, "\\&");
    +			break;
    +		}
    +
    +		if (tok == MDOC_Bd || tok == MDOC_Bk) {
    +			mandoc_vmsg(MANDOCERR_ARG_EXCESS,
    +			    mdoc->parse, line, la, "%s ... %s",
    +			    roff_name[tok], buf + la);
    +			break;
    +		}
    +		if (tok == MDOC_Rs) {
    +			mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
    +			    line, la, "Rs %s", buf + la);
    +			break;
    +		}
    +		if (ac == ARGS_PUNCT)
    +			break;
    +
    +		/*
    +		 * Emit leading punctuation (i.e., punctuation before
    +		 * the ROFFT_HEAD) for non-phrase types.
    +		 */
    +
    +		if (head == NULL &&
    +		    ac != ARGS_PHRASE &&
    +		    mdoc_isdelim(p) == DELIM_OPEN) {
    +			dword(mdoc, line, la, p, DELIM_OPEN, 0);
    +			continue;
    +		}
    +
    +		/* Open a head if one hasn't been opened. */
    +
    +		if (head == NULL)
    +			head = roff_head_alloc(mdoc, line, ppos, tok);
    +
    +		if (ac == ARGS_PHRASE) {
    +
    +			/*
    +			 * If we haven't opened a body yet, rewind the
    +			 * head; if we have, rewind that instead.
    +			 */
    +
    +			rew_last(mdoc, body == NULL ? head : body);
    +			body = roff_body_alloc(mdoc, line, ppos, tok);
    +
    +			/* Process to the tab or to the end of the line. */
    +
    +			mdoc->flags |= MDOC_PHRASE;
    +			parse_rest(mdoc, TOKEN_NONE, line, &la, buf);
    +			mdoc->flags &= ~MDOC_PHRASE;
    +
    +			/* There may have been `Ta' macros. */
    +
    +			while (body->next != NULL)
    +				body = body->next;
    +			continue;
    +		}
    +
    +		if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
    +			break;
    +	}
    +
    +	if (blk->flags & NODE_VALID)
    +		return;
    +	if (head == NULL)
    +		head = roff_head_alloc(mdoc, line, ppos, tok);
    +	if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs)
    +		append_delims(mdoc, line, pos, buf);
    +	if (body != NULL)
    +		goto out;
    +	if (find_pending(mdoc, tok, line, ppos, head))
    +		return;
    +
    +	/* Close out scopes to remain in a consistent state. */
    +
    +	rew_last(mdoc, head);
    +	body = roff_body_alloc(mdoc, line, ppos, tok);
    +out:
    +	if (mdoc->flags & MDOC_FREECOL) {
    +		rew_last(mdoc, body);
    +		rew_last(mdoc, blk);
    +		mdoc->flags &= ~MDOC_FREECOL;
    +	}
    +}
    +
    +static void
    +blk_part_imp(MACRO_PROT_ARGS)
    +{
    +	int		  la, nl;
    +	enum margserr	  ac;
    +	char		 *p;
    +	struct roff_node *blk; /* saved block context */
    +	struct roff_node *body; /* saved body context */
    +	struct roff_node *n;
    +
    +	nl = MDOC_NEWLINE & mdoc->flags;
    +
    +	/*
    +	 * A macro that spans to the end of the line.  This is generally
    +	 * (but not necessarily) called as the first macro.  The block
    +	 * has a head as the immediate child, which is always empty,
    +	 * followed by zero or more opening punctuation nodes, then the
    +	 * body (which may be empty, depending on the macro), then zero
    +	 * or more closing punctuation nodes.
    +	 */
    +
    +	blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
    +	rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
    +
    +	/*
    +	 * Open the body scope "on-demand", that is, after we've
    +	 * processed all our the leading delimiters (open parenthesis,
    +	 * etc.).
    +	 */
    +
    +	for (body = NULL; ; ) {
    +		la = *pos;
    +		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
    +		if (ac == ARGS_EOLN || ac == ARGS_PUNCT)
    +			break;
    +
    +		if (body == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
    +			dword(mdoc, line, la, p, DELIM_OPEN, 0);
    +			continue;
    +		}
    +
    +		if (body == NULL)
    +			body = roff_body_alloc(mdoc, line, ppos, tok);
    +
    +		if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
    +			break;
    +	}
    +	if (body == NULL)
    +		body = roff_body_alloc(mdoc, line, ppos, tok);
    +
    +	if (find_pending(mdoc, tok, line, ppos, body))
    +		return;
    +
    +	rew_last(mdoc, body);
    +	if (nl)
    +		append_delims(mdoc, line, pos, buf);
    +	rew_pending(mdoc, blk);
    +
    +	/* Move trailing .Ns out of scope. */
    +
    +	for (n = body->child; n && n->next; n = n->next)
    +		/* Do nothing. */ ;
    +	if (n && n->tok == MDOC_Ns)
    +		mdoc_node_relink(mdoc, n);
    +}
    +
    +static void
    +blk_part_exp(MACRO_PROT_ARGS)
    +{
    +	int		  la, nl;
    +	enum margserr	  ac;
    +	struct roff_node *head; /* keep track of head */
    +	char		 *p;
    +
    +	nl = MDOC_NEWLINE & mdoc->flags;
    +
    +	/*
    +	 * The opening of an explicit macro having zero or more leading
    +	 * punctuation nodes; a head with optional single element (the
    +	 * case of `Eo'); and a body that may be empty.
    +	 */
    +
    +	roff_block_alloc(mdoc, line, ppos, tok);
    +	head = NULL;
    +	for (;;) {
    +		la = *pos;
    +		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
    +		if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
    +			break;
    +
    +		/* Flush out leading punctuation. */
    +
    +		if (head == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
    +			dword(mdoc, line, la, p, DELIM_OPEN, 0);
    +			continue;
    +		}
    +
    +		if (head == NULL) {
    +			head = roff_head_alloc(mdoc, line, ppos, tok);
    +			if (tok == MDOC_Eo)  /* Not parsed. */
    +				dword(mdoc, line, la, p, DELIM_MAX, 0);
    +			rew_last(mdoc, head);
    +			roff_body_alloc(mdoc, line, ppos, tok);
    +			if (tok == MDOC_Eo)
    +				continue;
    +		}
    +
    +		if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
    +			break;
    +	}
    +
    +	/* Clean-up to leave in a consistent state. */
    +
    +	if (head == NULL) {
    +		rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
    +		roff_body_alloc(mdoc, line, ppos, tok);
    +	}
    +	if (nl)
    +		append_delims(mdoc, line, pos, buf);
    +}
    +
    +static void
    +in_line_argn(MACRO_PROT_ARGS)
    +{
    +	struct mdoc_arg	*arg;
    +	char		*p;
    +	enum margserr	 ac;
    +	enum roff_tok	 ntok;
    +	int		 state; /* arg#; -1: not yet open; -2: closed */
    +	int		 la, maxargs, nl;
    +
    +	nl = mdoc->flags & MDOC_NEWLINE;
    +
    +	/*
    +	 * A line macro that has a fixed number of arguments (maxargs).
    +	 * Only open the scope once the first non-leading-punctuation is
    +	 * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
    +	 * keep it open until the maximum number of arguments are
    +	 * exhausted.
    +	 */
    +
    +	switch (tok) {
    +	case MDOC_Ap:
    +	case MDOC_Ns:
    +	case MDOC_Ux:
    +		maxargs = 0;
    +		break;
    +	case MDOC_Bx:
    +	case MDOC_Es:
    +	case MDOC_Xr:
    +		maxargs = 2;
    +		break;
    +	default:
    +		maxargs = 1;
    +		break;
    +	}
    +
    +	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
    +
    +	state = -1;
    +	p = NULL;
    +	for (;;) {
    +		la = *pos;
    +		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
    +
    +		if (ac == ARGS_WORD && state == -1 &&
    +		    ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
    +		    mdoc_isdelim(p) == DELIM_OPEN) {
    +			dword(mdoc, line, la, p, DELIM_OPEN, 0);
    +			continue;
    +		}
    +
    +		if (state == -1 && tok != MDOC_In &&
    +		    tok != MDOC_St && tok != MDOC_Xr) {
    +			mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
    +			state = 0;
    +		}
    +
    +		if (ac == ARGS_PUNCT || ac == ARGS_EOLN) {
    +			if (abs(state) < 2 && tok == MDOC_Pf)
    +				mandoc_vmsg(MANDOCERR_PF_SKIP,
    +				    mdoc->parse, line, ppos, "Pf %s",
    +				    p == NULL ? "at eol" : p);
    +			break;
    +		}
    +
    +		if (state == maxargs) {
    +			rew_elem(mdoc, tok);
    +			state = -2;
    +		}
    +
    +		ntok = (tok == MDOC_Pf && state == 0) ?
    +		    TOKEN_NONE : lookup(mdoc, tok, line, la, p);
    +
    +		if (ntok != TOKEN_NONE) {
    +			if (state >= 0) {
    +				rew_elem(mdoc, tok);
    +				state = -2;
    +			}
    +			mdoc_macro(mdoc, ntok, line, la, pos, buf);
    +			break;
    +		}
    +
    +		if (mdoc_macros[tok].flags & MDOC_IGNDELIM ||
    +		    mdoc_isdelim(p) == DELIM_NONE) {
    +			if (state == -1) {
    +				mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
    +				state = 1;
    +			} else if (state >= 0)
    +				state++;
    +		} else if (state >= 0) {
    +			rew_elem(mdoc, tok);
    +			state = -2;
    +		}
    +
    +		dword(mdoc, line, la, p, DELIM_MAX,
    +		    mdoc_macros[tok].flags & MDOC_JOIN);
    +	}
    +
    +	if (state == -1) {
    +		mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
    +		    line, ppos, roff_name[tok]);
    +		return;
    +	}
    +
    +	if (state == 0 && tok == MDOC_Pf)
    +		append_delims(mdoc, line, pos, buf);
    +	if (state >= 0)
    +		rew_elem(mdoc, tok);
    +	if (nl)
    +		append_delims(mdoc, line, pos, buf);
    +}
    +
    +static void
    +in_line_eoln(MACRO_PROT_ARGS)
    +{
    +	struct roff_node	*n;
    +	struct mdoc_arg		*arg;
    +
    +	if ((tok == MDOC_Pp || tok == MDOC_Lp) &&
    +	    ! (mdoc->flags & MDOC_SYNOPSIS)) {
    +		n = mdoc->last;
    +		if (mdoc->next == ROFF_NEXT_SIBLING)
    +			n = n->parent;
    +		if (n->tok == MDOC_Nm)
    +			rew_last(mdoc, n->parent);
    +	}
    +
    +	if (buf[*pos] == '\0' &&
    +	    (tok == MDOC_Fd || *roff_name[tok] == '%')) {
    +		mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
    +		    line, ppos, roff_name[tok]);
    +		return;
    +	}
    +
    +	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
    +	mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
    +	if (parse_rest(mdoc, tok, line, pos, buf))
    +		return;
    +	rew_elem(mdoc, tok);
    +}
    +
    +/*
    + * The simplest argument parser available: Parse the remaining
    + * words until the end of the phrase or line and return 0
    + * or until the next macro, call that macro, and return 1.
    + */
    +static int
    +parse_rest(struct roff_man *mdoc, enum roff_tok tok,
    +    int line, int *pos, char *buf)
    +{
    +	int		 la;
    +
    +	for (;;) {
    +		la = *pos;
    +		if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
    +			return 0;
    +		if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
    +			return 1;
    +	}
    +}
    +
    +static void
    +ctx_synopsis(MACRO_PROT_ARGS)
    +{
    +
    +	if (~mdoc->flags & (MDOC_SYNOPSIS | MDOC_NEWLINE))
    +		in_line(mdoc, tok, line, ppos, pos, buf);
    +	else if (tok == MDOC_Nm)
    +		blk_full(mdoc, tok, line, ppos, pos, buf);
    +	else {
    +		assert(tok == MDOC_Vt);
    +		blk_part_imp(mdoc, tok, line, ppos, pos, buf);
    +	}
    +}
    +
    +/*
    + * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
    + * They're unusual because they're basically free-form text until a
    + * macro is encountered.
    + */
    +static void
    +phrase_ta(MACRO_PROT_ARGS)
    +{
    +	struct roff_node *body, *n;
    +
    +	/* Make sure we are in a column list or ignore this macro. */
    +
    +	body = NULL;
    +	for (n = mdoc->last; n != NULL; n = n->parent) {
    +		if (n->flags & NODE_ENDED)
    +			continue;
    +		if (n->tok == MDOC_It && n->type == ROFFT_BODY)
    +			body = n;
    +		if (n->tok == MDOC_Bl && n->end == ENDBODY_NOT)
    +			break;
    +	}
    +
    +	if (n == NULL || n->norm->Bl.type != LIST_column) {
    +		mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
    +		    line, ppos, "Ta");
    +		return;
    +	}
    +
    +	/* Advance to the next column. */
    +
    +	rew_last(mdoc, body);
    +	roff_body_alloc(mdoc, line, ppos, MDOC_It);
    +	parse_rest(mdoc, TOKEN_NONE, line, pos, buf);
    +}
    
    Property changes on: head/contrib/mandoc/mdoc_macro.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/catman.c
    ===================================================================
    --- head/contrib/mandoc/catman.c	(nonexistent)
    +++ head/contrib/mandoc/catman.c	(revision 338826)
    @@ -0,0 +1,260 @@
    +/*	$Id: catman.c,v 1.21 2017/02/18 12:24:24 schwarze Exp $ */
    +/*
    + * Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
    + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#if HAVE_CMSG_XPG42
    +#define _XPG4_2
    +#endif
    +
    +#include <sys/types.h>
    +#include <sys/socket.h>
    +#include <sys/stat.h>
    +
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <errno.h>
    +#include <fcntl.h>
    +#if HAVE_FTS
    +#include <fts.h>
    +#else
    +#include "compat_fts.h"
    +#endif
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +#include <unistd.h>
    +
    +int	 process_manpage(int, int, const char *);
    +int	 process_tree(int, int);
    +void	 run_mandocd(int, const char *, const char *)
    +		__attribute__((__noreturn__));
    +ssize_t	 sock_fd_write(int, int, int, int);
    +void	 usage(void) __attribute__((__noreturn__));
    +
    +
    +void
    +run_mandocd(int sockfd, const char *outtype, const char* defos)
    +{
    +	char	 sockfdstr[10];
    +
    +	if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1)
    +		err(1, "snprintf");
    +	if (defos == NULL)
    +		execlp("mandocd", "mandocd", "-T", outtype,
    +		    sockfdstr, (char *)NULL);
    +	else
    +		execlp("mandocd", "mandocd", "-T", outtype,
    +		    "-I", defos, sockfdstr, (char *)NULL);
    +	err(1, "exec");
    +}
    +
    +ssize_t
    +sock_fd_write(int fd, int fd0, int fd1, int fd2)
    +{
    +	const struct timespec timeout = { 0, 10000000 };  /* 0.01 s */
    +	struct msghdr	 msg;
    +	struct iovec	 iov;
    +	union {
    +		struct cmsghdr	 cmsghdr;
    +		char		 control[CMSG_SPACE(3 * sizeof(int))];
    +	} cmsgu;
    +	struct cmsghdr	*cmsg;
    +	int		*walk;
    +	ssize_t		 sz;
    +	unsigned char	 dummy[1] = {'\0'};
    +
    +	iov.iov_base = dummy;
    +	iov.iov_len = sizeof(dummy);
    +
    +	msg.msg_name = NULL;
    +	msg.msg_namelen = 0;
    +	msg.msg_iov = &iov;
    +	msg.msg_iovlen = 1;
    +
    +	msg.msg_control = cmsgu.control;
    +	msg.msg_controllen = sizeof(cmsgu.control);
    +
    +	cmsg = CMSG_FIRSTHDR(&msg);
    +	cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int));
    +	cmsg->cmsg_level = SOL_SOCKET;
    +	cmsg->cmsg_type = SCM_RIGHTS;
    +
    +	walk = (int *)CMSG_DATA(cmsg);
    +	*(walk++) = fd0;
    +	*(walk++) = fd1;
    +	*(walk++) = fd2;
    +
    +	/*
    +	 * It appears that on some systems, sendmsg(3)
    +	 * may return EAGAIN even in blocking mode.
    +	 * Seen for example on Oracle Solaris 11.2.
    +	 * The sleeping time was chosen by experimentation,
    +	 * to neither cause more than a handful of retries
    +	 * in normal operation nor unnecessary delays.
    +	 */
    +	for (;;) {
    +		if ((sz = sendmsg(fd, &msg, 0)) != -1 ||
    +		    errno != EAGAIN)
    +			break;
    +		nanosleep(&timeout, NULL);
    +	}
    +	return sz;
    +}
    +
    +int
    +process_manpage(int srv_fd, int dstdir_fd, const char *path)
    +{
    +	int	 in_fd, out_fd;
    +	int	 irc;
    +
    +	if ((in_fd = open(path, O_RDONLY)) == -1) {
    +		warn("open(%s)", path);
    +		return 0;
    +	}
    +
    +	if ((out_fd = openat(dstdir_fd, path,
    +	    O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC,
    +	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
    +		warn("openat(%s)", path);
    +		close(in_fd);
    +		return 0;
    +	}
    +
    +	irc = sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO);
    +
    +	close(in_fd);
    +	close(out_fd);
    +
    +	if (irc < 0) {
    +		warn("sendmsg");
    +		return -1;
    +	}
    +	return 0;
    +}
    +
    +int
    +process_tree(int srv_fd, int dstdir_fd)
    +{
    +	FTS		*ftsp;
    +	FTSENT		*entry;
    +	const char	*argv[2];
    +	const char	*path;
    +
    +	argv[0] = ".";
    +	argv[1] = (char *)NULL;
    +
    +	if ((ftsp = fts_open((char * const *)argv,
    +	    FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
    +		warn("fts_open");
    +		return -1;
    +	}
    +
    +	while ((entry = fts_read(ftsp)) != NULL) {
    +		path = entry->fts_path + 2;
    +		switch (entry->fts_info) {
    +		case FTS_F:
    +			if (process_manpage(srv_fd, dstdir_fd, path) == -1) {
    +				fts_close(ftsp);
    +				return -1;
    +			}
    +			break;
    +		case FTS_D:
    +			if (*path != '\0' &&
    +			    mkdirat(dstdir_fd, path, S_IRWXU | S_IRGRP |
    +			      S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
    +			    errno != EEXIST) {
    +				warn("mkdirat(%s)", path);
    +				(void)fts_set(ftsp, entry, FTS_SKIP);
    +			}
    +			break;
    +		case FTS_DP:
    +			break;
    +		default:
    +			warnx("%s: not a regular file", path);
    +			break;
    +		}
    +	}
    +
    +	fts_close(ftsp);
    +	return 0;
    +}
    +
    +int
    +main(int argc, char **argv)
    +{
    +	const char	*defos, *outtype;
    +	int		 srv_fds[2];
    +	int		 dstdir_fd;
    +	int		 opt;
    +	pid_t		 pid;
    +
    +	defos = NULL;
    +	outtype = "ascii";
    +	while ((opt = getopt(argc, argv, "I:T:")) != -1) {
    +		switch (opt) {
    +		case 'I':
    +			defos = optarg;
    +			break;
    +		case 'T':
    +			outtype = optarg;
    +			break;
    +		default:
    +			usage();
    +		}
    +	}
    +
    +	if (argc > 0) {
    +		argc -= optind;
    +		argv += optind;
    +	}
    +	if (argc != 2)
    +		usage();
    +
    +	if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1)
    +		err(1, "socketpair");
    +
    +	pid = fork();
    +	switch (pid) {
    +	case -1:
    +		err(1, "fork");
    +	case 0:
    +		close(srv_fds[0]);
    +		run_mandocd(srv_fds[1], outtype, defos);
    +	default:
    +		break;
    +	}
    +	close(srv_fds[1]);
    +
    +	if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1)
    +		err(1, "open(%s)", argv[1]);
    +
    +	if (chdir(argv[0]) == -1)
    +		err(1, "chdir(%s)", argv[0]);
    +
    +	return process_tree(srv_fds[0], dstdir_fd) == -1 ? 1 : 0;
    +}
    +
    +void
    +usage(void)
    +{
    +	fprintf(stderr, "usage: %s [-I os=name] [-T output] "
    +	    "srcdir dstdir\n", BINM_CATMAN);
    +	exit(1);
    +}
    
    Property changes on: head/contrib/mandoc/catman.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_fts.c
    ===================================================================
    --- head/contrib/mandoc/compat_fts.c	(nonexistent)
    +++ head/contrib/mandoc/compat_fts.c	(revision 338826)
    @@ -0,0 +1,701 @@
    +#include "config.h"
    +
    +#if HAVE_FTS
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_fts.c,v 1.14 2017/02/18 12:24:24 schwarze Exp $	*/
    +/*	$OpenBSD: fts.c,v 1.56 2016/09/21 04:38:56 guenther Exp $	*/
    +
    +/*-
    + * Copyright (c) 1990, 1993, 1994
    + *	The Regents of the University of California.  All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. Neither the name of the University nor the names of its contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + */
    +
    +#include <sys/stat.h>
    +#include <sys/types.h>
    +
    +#include <dirent.h>
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <limits.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +#include "compat_fts.h"
    +
    +#define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
    +
    +static FTSENT	*fts_alloc(FTS *, const char *, size_t);
    +static FTSENT	*fts_build(FTS *);
    +static void	 fts_lfree(FTSENT *);
    +static void	 fts_load(FTS *, FTSENT *);
    +static size_t	 fts_maxarglen(char * const *);
    +static void	 fts_padjust(FTS *, FTSENT *);
    +static int	 fts_palloc(FTS *, size_t);
    +static FTSENT	*fts_sort(FTS *, FTSENT *, int);
    +static unsigned short	 fts_stat(FTS *, FTSENT *);
    +
    +#define	ISDOT(a)	(a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
    +#ifndef	O_CLOEXEC
    +#define	O_CLOEXEC	0
    +#endif
    +
    +#define	CLR(opt)	(sp->fts_options &= ~(opt))
    +#define	ISSET(opt)	(sp->fts_options & (opt))
    +#define	SET(opt)	(sp->fts_options |= (opt))
    +
    +FTS *
    +fts_open(char * const *argv, int options,
    +    int (*compar)(const FTSENT **, const FTSENT **))
    +{
    +	FTS *sp;
    +	FTSENT *p, *root;
    +	int nitems;
    +	FTSENT *parent, *prev;
    +
    +	/* Options check. */
    +	if (options & ~FTS_OPTIONMASK) {
    +		errno = EINVAL;
    +		return (NULL);
    +	}
    +
    +	/* At least one path must be specified. */
    +	if (*argv == NULL) {
    +		errno = EINVAL;
    +		return (NULL);
    +	}
    +
    +	/* Allocate/initialize the stream */
    +	if ((sp = calloc(1, sizeof(FTS))) == NULL)
    +		return (NULL);
    +	sp->fts_compar = compar;
    +	sp->fts_options = options;
    +
    +	/*
    +	 * Start out with 1K of path space, and enough, in any case,
    +	 * to hold the user's paths.
    +	 */
    +	if (fts_palloc(sp, MAXIMUM(fts_maxarglen(argv), PATH_MAX)))
    +		goto mem1;
    +
    +	/* Allocate/initialize root's parent. */
    +	if ((parent = fts_alloc(sp, "", 0)) == NULL)
    +		goto mem2;
    +	parent->fts_level = FTS_ROOTPARENTLEVEL;
    +
    +	/* Allocate/initialize root(s). */
    +	for (root = prev = NULL, nitems = 0; *argv; ++argv, ++nitems) {
    +		if ((p = fts_alloc(sp, *argv, strlen(*argv))) == NULL)
    +			goto mem3;
    +		p->fts_level = FTS_ROOTLEVEL;
    +		p->fts_parent = parent;
    +		p->fts_accpath = p->fts_name;
    +		p->fts_info = fts_stat(sp, p);
    +
    +		/* Command-line "." and ".." are real directories. */
    +		if (p->fts_info == FTS_DOT)
    +			p->fts_info = FTS_D;
    +
    +		/*
    +		 * If comparison routine supplied, traverse in sorted
    +		 * order; otherwise traverse in the order specified.
    +		 */
    +		if (compar) {
    +			p->fts_link = root;
    +			root = p;
    +		} else {
    +			p->fts_link = NULL;
    +			if (root == NULL)
    +				root = p;
    +			else
    +				prev->fts_link = p;
    +			prev = p;
    +		}
    +	}
    +	if (compar && nitems > 1)
    +		root = fts_sort(sp, root, nitems);
    +
    +	/*
    +	 * Allocate a dummy pointer and make fts_read think that we've just
    +	 * finished the node before the root(s); set p->fts_info to FTS_INIT
    +	 * so that everything about the "current" node is ignored.
    +	 */
    +	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
    +		goto mem3;
    +	sp->fts_cur->fts_link = root;
    +	sp->fts_cur->fts_info = FTS_INIT;
    +
    +	if (nitems == 0)
    +		free(parent);
    +
    +	return (sp);
    +
    +mem3:	fts_lfree(root);
    +	free(parent);
    +mem2:	free(sp->fts_path);
    +mem1:	free(sp);
    +	return (NULL);
    +}
    +
    +static void
    +fts_load(FTS *sp, FTSENT *p)
    +{
    +	size_t len;
    +	char *cp;
    +
    +	/*
    +	 * Load the stream structure for the next traversal.  Since we don't
    +	 * actually enter the directory until after the preorder visit, set
    +	 * the fts_accpath field specially so the chdir gets done to the right
    +	 * place and the user can access the first node.  From fts_open it's
    +	 * known that the path will fit.
    +	 */
    +	len = p->fts_pathlen = p->fts_namelen;
    +	memmove(sp->fts_path, p->fts_name, len + 1);
    +	if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
    +		len = strlen(++cp);
    +		memmove(p->fts_name, cp, len + 1);
    +		p->fts_namelen = len;
    +	}
    +	p->fts_accpath = p->fts_path = sp->fts_path;
    +	sp->fts_dev = p->fts_dev;
    +}
    +
    +int
    +fts_close(FTS *sp)
    +{
    +	FTSENT *freep, *p;
    +
    +	/*
    +	 * This still works if we haven't read anything -- the dummy structure
    +	 * points to the root list, so we step through to the end of the root
    +	 * list which has a valid parent pointer.
    +	 */
    +	if (sp->fts_cur) {
    +		for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
    +			freep = p;
    +			p = p->fts_link ? p->fts_link : p->fts_parent;
    +			free(freep);
    +		}
    +		free(p);
    +	}
    +
    +	/* Free up child linked list, sort array, path buffer, stream ptr.*/
    +	if (sp->fts_child)
    +		fts_lfree(sp->fts_child);
    +	free(sp->fts_array);
    +	free(sp->fts_path);
    +	free(sp);
    +
    +	return (0);
    +}
    +
    +/*
    + * Special case of "/" at the end of the path so that slashes aren't
    + * appended which would cause paths to be written as "....//foo".
    + */
    +#define	NAPPEND(p)							\
    +	(p->fts_path[p->fts_pathlen - 1] == '/'				\
    +	    ? p->fts_pathlen - 1 : p->fts_pathlen)
    +
    +FTSENT *
    +fts_read(FTS *sp)
    +{
    +	FTSENT *p, *tmp;
    +	int instr;
    +	char *t;
    +
    +	/* If finished or unrecoverable error, return NULL. */
    +	if (sp->fts_cur == NULL || ISSET(FTS_STOP))
    +		return (NULL);
    +
    +	/* Set current node pointer. */
    +	p = sp->fts_cur;
    +
    +	/* Save and zero out user instructions. */
    +	instr = p->fts_instr;
    +	p->fts_instr = FTS_NOINSTR;
    +
    +	/* Directory in pre-order. */
    +	if (p->fts_info == FTS_D) {
    +		/* If skipped or crossed mount point, do post-order visit. */
    +		if (instr == FTS_SKIP ||
    +		    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
    +			if (sp->fts_child) {
    +				fts_lfree(sp->fts_child);
    +				sp->fts_child = NULL;
    +			}
    +			p->fts_info = FTS_DP;
    +			return (p);
    +		}
    +
    +		/*
    +		 * If haven't read do so.  If the read fails, fts_build sets
    +		 * FTS_STOP or the fts_info field of the node.
    +		 */
    +		if (sp->fts_child) {
    +			/* nothing */
    +		} else if ((sp->fts_child = fts_build(sp)) == NULL) {
    +			if (ISSET(FTS_STOP))
    +				return (NULL);
    +			return (p);
    +		}
    +		p = sp->fts_child;
    +		sp->fts_child = NULL;
    +		goto name;
    +	}
    +
    +	/* Move to the next node on this level. */
    +next:	tmp = p;
    +	if ((p = p->fts_link)) {
    +		free(tmp);
    +
    +		/*
    +		 * If reached the top, return to the original directory (or
    +		 * the root of the tree), and load the paths for the next root.
    +		 */
    +		if (p->fts_level == FTS_ROOTLEVEL) {
    +			fts_load(sp, p);
    +			return (sp->fts_cur = p);
    +		}
    +
    +		/*
    +		 * User may have called fts_set on the node.  If skipped,
    +		 * ignore.  If followed, get a file descriptor so we can
    +		 * get back if necessary.
    +		 */
    +		if (p->fts_instr == FTS_SKIP)
    +			goto next;
    +
    +name:		t = sp->fts_path + NAPPEND(p->fts_parent);
    +		*t++ = '/';
    +		memmove(t, p->fts_name, p->fts_namelen + 1);
    +		return (sp->fts_cur = p);
    +	}
    +
    +	/* Move up to the parent node. */
    +	p = tmp->fts_parent;
    +	free(tmp);
    +
    +	if (p->fts_level == FTS_ROOTPARENTLEVEL) {
    +		/*
    +		 * Done; free everything up and set errno to 0 so the user
    +		 * can distinguish between error and EOF.
    +		 */
    +		free(p);
    +		errno = 0;
    +		return (sp->fts_cur = NULL);
    +	}
    +
    +	/* NUL terminate the pathname. */
    +	sp->fts_path[p->fts_pathlen] = '\0';
    +
    +	p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
    +	return (sp->fts_cur = p);
    +}
    +
    +/*
    + * Fts_set takes the stream as an argument although it's not used in this
    + * implementation; it would be necessary if anyone wanted to add global
    + * semantics to fts using fts_set.  An error return is allowed for similar
    + * reasons.
    + */
    +int
    +fts_set(FTS *sp, FTSENT *p, int instr)
    +{
    +	if (instr && instr != FTS_NOINSTR && instr != FTS_SKIP) {
    +		errno = EINVAL;
    +		return (1);
    +	}
    +	p->fts_instr = instr;
    +	return (0);
    +}
    +
    +/*
    + * This is the tricky part -- do not casually change *anything* in here.  The
    + * idea is to build the linked list of entries that are used by fts_children
    + * and fts_read.  There are lots of special cases.
    + *
    + * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
    + * set and it's a physical walk (so that symbolic links can't be directories),
    + * we can do things quickly.  First, if it's a 4.4BSD file system, the type
    + * of the file is in the directory entry.  Otherwise, we assume that the number
    + * of subdirectories in a node is equal to the number of links to the parent.
    + * The former skips all stat calls.  The latter skips stat calls in any leaf
    + * directories and for any files after the subdirectories in the directory have
    + * been found, cutting the stat calls by about 2/3.
    + */
    +static FTSENT *
    +fts_build(FTS *sp)
    +{
    +	struct dirent *dp;
    +	FTSENT *p, *head;
    +	FTSENT *cur, *tail;
    +	DIR *dirp;
    +	void *oldaddr;
    +	size_t dlen, len, maxlen;
    +	int nitems, level, doadjust;
    +	int saved_errno;
    +	char *cp;
    +
    +	/* Set current node pointer. */
    +	cur = sp->fts_cur;
    +
    +	/*
    +	 * Open the directory for reading.  If this fails, we're done.
    +	 * If being called from fts_read, set the fts_info field.
    +	 */
    +	if ((dirp = opendir(cur->fts_accpath)) == NULL) {
    +		cur->fts_info = FTS_DNR;
    +		cur->fts_errno = errno;
    +		return (NULL);
    +	}
    +
    +	/*
    +	 * Figure out the max file name length that can be stored in the
    +	 * current path -- the inner loop allocates more path as necessary.
    +	 * We really wouldn't have to do the maxlen calculations here, we
    +	 * could do them in fts_read before returning the path, but it's a
    +	 * lot easier here since the length is part of the dirent structure.
    +	 *
    +	 * If not changing directories set a pointer so that can just append
    +	 * each new name into the path.
    +	 */
    +	len = NAPPEND(cur);
    +	cp = sp->fts_path + len;
    +	*cp++ = '/';
    +	len++;
    +	maxlen = sp->fts_pathlen - len;
    +
    +	/*
    +	 * fts_level is signed so we must prevent it from wrapping
    +	 * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL.
    +	 */
    +	level = cur->fts_level;
    +	if (level < FTS_MAXLEVEL)
    +	    level++;
    +
    +	/* Read the directory, attaching each entry to the `link' pointer. */
    +	doadjust = 0;
    +	for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
    +		if (ISDOT(dp->d_name))
    +			continue;
    +
    +#if HAVE_DIRENT_NAMLEN
    +		dlen = dp->d_namlen;
    +#else
    +		dlen = strlen(dp->d_name);
    +#endif
    +
    +		if (!(p = fts_alloc(sp, dp->d_name, dlen)))
    +			goto mem1;
    +		if (dlen >= maxlen) {	/* include space for NUL */
    +			oldaddr = sp->fts_path;
    +			if (fts_palloc(sp, dlen + len + 1)) {
    +				/*
    +				 * No more memory for path or structures.  Save
    +				 * errno, free up the current structure and the
    +				 * structures already allocated.
    +				 */
    +mem1:				saved_errno = errno;
    +				free(p);
    +				fts_lfree(head);
    +				(void)closedir(dirp);
    +				cur->fts_info = FTS_ERR;
    +				SET(FTS_STOP);
    +				errno = saved_errno;
    +				return (NULL);
    +			}
    +			/* Did realloc() change the pointer? */
    +			if (oldaddr != sp->fts_path) {
    +				doadjust = 1;
    +				cp = sp->fts_path + len;
    +			}
    +			maxlen = sp->fts_pathlen - len;
    +		}
    +
    +		p->fts_level = level;
    +		p->fts_parent = sp->fts_cur;
    +		p->fts_pathlen = len + dlen;
    +		if (p->fts_pathlen < len) {
    +			/*
    +			 * If we wrap, free up the current structure and
    +			 * the structures already allocated, then error
    +			 * out with ENAMETOOLONG.
    +			 */
    +			free(p);
    +			fts_lfree(head);
    +			(void)closedir(dirp);
    +			cur->fts_info = FTS_ERR;
    +			SET(FTS_STOP);
    +			errno = ENAMETOOLONG;
    +			return (NULL);
    +		}
    +
    +		/* Build a file name for fts_stat to stat. */
    +		p->fts_accpath = p->fts_path;
    +		memmove(cp, p->fts_name, p->fts_namelen + 1);
    +		/* Stat it. */
    +		p->fts_info = fts_stat(sp, p);
    +
    +		/* We walk in directory order so "ls -f" doesn't get upset. */
    +		p->fts_link = NULL;
    +		if (head == NULL)
    +			head = tail = p;
    +		else {
    +			tail->fts_link = p;
    +			tail = p;
    +		}
    +		++nitems;
    +	}
    +	if (dirp)
    +		(void)closedir(dirp);
    +
    +	/*
    +	 * If realloc() changed the address of the path, adjust the
    +	 * addresses for the rest of the tree and the dir list.
    +	 */
    +	if (doadjust)
    +		fts_padjust(sp, head);
    +
    +	/*
    +	 * If not changing directories, reset the path back to original
    +	 * state.
    +	 */
    +	if (len == sp->fts_pathlen || nitems == 0)
    +		--cp;
    +	*cp = '\0';
    +
    +	/* If didn't find anything, return NULL. */
    +	if (!nitems) {
    +		cur->fts_info = FTS_DP;
    +		return (NULL);
    +	}
    +
    +	/* Sort the entries. */
    +	if (sp->fts_compar && nitems > 1)
    +		head = fts_sort(sp, head, nitems);
    +	return (head);
    +}
    +
    +static unsigned short
    +fts_stat(FTS *sp, FTSENT *p)
    +{
    +	FTSENT *t;
    +	dev_t dev;
    +	ino_t ino;
    +	struct stat *sbp;
    +
    +	/* If user needs stat info, stat buffer already allocated. */
    +	sbp = p->fts_statp;
    +
    +	if (lstat(p->fts_accpath, sbp)) {
    +		p->fts_errno = errno;
    +		memset(sbp, 0, sizeof(struct stat));
    +		return (FTS_NS);
    +	}
    +
    +	if (S_ISDIR(sbp->st_mode)) {
    +		/*
    +		 * Set the device/inode.  Used to find cycles and check for
    +		 * crossing mount points.  Also remember the link count, used
    +		 * in fts_build to limit the number of stat calls.  It is
    +		 * understood that these fields are only referenced if fts_info
    +		 * is set to FTS_D.
    +		 */
    +		dev = p->fts_dev = sbp->st_dev;
    +		ino = p->fts_ino = sbp->st_ino;
    +		p->fts_nlink = sbp->st_nlink;
    +
    +		if (ISDOT(p->fts_name))
    +			return (FTS_DOT);
    +
    +		/*
    +		 * Cycle detection is done by brute force when the directory
    +		 * is first encountered.  If the tree gets deep enough or the
    +		 * number of symbolic links to directories is high enough,
    +		 * something faster might be worthwhile.
    +		 */
    +		for (t = p->fts_parent;
    +		    t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
    +			if (ino == t->fts_ino && dev == t->fts_dev) {
    +				p->fts_cycle = t;
    +				return (FTS_DC);
    +			}
    +		return (FTS_D);
    +	}
    +	if (S_ISLNK(sbp->st_mode))
    +		return (FTS_SL);
    +	if (S_ISREG(sbp->st_mode))
    +		return (FTS_F);
    +	return (FTS_DEFAULT);
    +}
    +
    +static FTSENT *
    +fts_sort(FTS *sp, FTSENT *head, int nitems)
    +{
    +	FTSENT **ap, *p;
    +
    +	/*
    +	 * Construct an array of pointers to the structures and call qsort(3).
    +	 * Reassemble the array in the order returned by qsort.  If unable to
    +	 * sort for memory reasons, return the directory entries in their
    +	 * current order.  Allocate enough space for the current needs plus
    +	 * 40 so don't realloc one entry at a time.
    +	 */
    +	if (nitems > sp->fts_nitems) {
    +		struct _ftsent **a;
    +
    +		sp->fts_nitems = nitems + 40;
    +		if ((a = reallocarray(sp->fts_array,
    +		    sp->fts_nitems, sizeof(FTSENT *))) == NULL) {
    +			free(sp->fts_array);
    +			sp->fts_array = NULL;
    +			sp->fts_nitems = 0;
    +			return (head);
    +		}
    +		sp->fts_array = a;
    +	}
    +	for (ap = sp->fts_array, p = head; p; p = p->fts_link)
    +		*ap++ = p;
    +	qsort(sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
    +	for (head = *(ap = sp->fts_array); --nitems; ++ap)
    +		ap[0]->fts_link = ap[1];
    +	ap[0]->fts_link = NULL;
    +	return (head);
    +}
    +
    +static FTSENT *
    +fts_alloc(FTS *sp, const char *name, size_t namelen)
    +{
    +	FTSENT *p;
    +	size_t len;
    +
    +	len = sizeof(FTSENT) + namelen;
    +	if ((p = calloc(1, len)) == NULL)
    +		return (NULL);
    +
    +	p->fts_path = sp->fts_path;
    +	p->fts_namelen = namelen;
    +	p->fts_instr = FTS_NOINSTR;
    +	p->fts_statp = malloc(sizeof(struct stat));
    +	if (p->fts_statp == NULL) {
    +		free(p);
    +		return (NULL);
    +	}
    +	memcpy(p->fts_name, name, namelen);
    +
    +	return (p);
    +}
    +
    +static void
    +fts_lfree(FTSENT *head)
    +{
    +	FTSENT *p;
    +
    +	/* Free a linked list of structures. */
    +	while ((p = head)) {
    +		head = head->fts_link;
    +		free(p);
    +	}
    +}
    +
    +/*
    + * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
    + * Most systems will allow creation of paths much longer than PATH_MAX, even
    + * though the kernel won't resolve them.  Add the size (not just what's needed)
    + * plus 256 bytes so don't realloc the path 2 bytes at a time.
    + */
    +static int
    +fts_palloc(FTS *sp, size_t more)
    +{
    +	char *p;
    +
    +	/*
    +	 * Check for possible wraparound.
    +	 */
    +	more += 256;
    +	if (sp->fts_pathlen + more < sp->fts_pathlen) {
    +		free(sp->fts_path);
    +		sp->fts_path = NULL;
    +		errno = ENAMETOOLONG;
    +		return (1);
    +	}
    +	sp->fts_pathlen += more;
    +	p = realloc(sp->fts_path, sp->fts_pathlen);
    +	if (p == NULL) {
    +		free(sp->fts_path);
    +		sp->fts_path = NULL;
    +		return (1);
    +	}
    +	sp->fts_path = p;
    +	return (0);
    +}
    +
    +/*
    + * When the path is realloc'd, have to fix all of the pointers in structures
    + * already returned.
    + */
    +static void
    +fts_padjust(FTS *sp, FTSENT *head)
    +{
    +	FTSENT *p;
    +	char *addr = sp->fts_path;
    +
    +#define	ADJUST(p) {							\
    +	if ((p)->fts_accpath != (p)->fts_name) {			\
    +		(p)->fts_accpath =					\
    +		    (char *)addr + ((p)->fts_accpath - (p)->fts_path);	\
    +	}								\
    +	(p)->fts_path = addr;						\
    +}
    +	/* Adjust the current set of children. */
    +	for (p = sp->fts_child; p; p = p->fts_link)
    +		ADJUST(p);
    +
    +	/* Adjust the rest of the tree, including the current level. */
    +	for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
    +		ADJUST(p);
    +		p = p->fts_link ? p->fts_link : p->fts_parent;
    +	}
    +}
    +
    +static size_t
    +fts_maxarglen(char * const *argv)
    +{
    +	size_t len, max;
    +
    +	for (max = 0; *argv; ++argv)
    +		if ((len = strlen(*argv)) > max)
    +			max = len;
    +	return (max + 1);
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_fts.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dba.c
    ===================================================================
    --- head/contrib/mandoc/dba.c	(nonexistent)
    +++ head/contrib/mandoc/dba.c	(revision 338826)
    @@ -0,0 +1,508 @@
    +/*	$Id: dba.c,v 1.10 2017/02/17 14:43:54 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Allocation-based version of the mandoc database, for read-write access.
    + * The interface is defined in "dba.h".
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +#if HAVE_ENDIAN
    +#include <endian.h>
    +#elif HAVE_SYS_ENDIAN
    +#include <sys/endian.h>
    +#elif HAVE_NTOHL
    +#include <arpa/inet.h>
    +#endif
    +#include <errno.h>
    +#include <stddef.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc_ohash.h"
    +#include "mansearch.h"
    +#include "dba_write.h"
    +#include "dba_array.h"
    +#include "dba.h"
    +
    +struct macro_entry {
    +	struct dba_array	*pages;
    +	char			 value[];
    +};
    +
    +static void	*prepend(const char *, char);
    +static void	 dba_pages_write(struct dba_array *);
    +static int	 compare_names(const void *, const void *);
    +static int	 compare_strings(const void *, const void *);
    +
    +static struct macro_entry
    +		*get_macro_entry(struct ohash *, const char *, int32_t);
    +static void	 dba_macros_write(struct dba_array *);
    +static void	 dba_macro_write(struct ohash *);
    +static int	 compare_entries(const void *, const void *);
    +
    +
    +/*** top-level functions **********************************************/
    +
    +struct dba *
    +dba_new(int32_t npages)
    +{
    +	struct dba	*dba;
    +	struct ohash	*macro;
    +	int32_t		 im;
    +
    +	dba = mandoc_malloc(sizeof(*dba));
    +	dba->pages = dba_array_new(npages, DBA_GROW);
    +	dba->macros = dba_array_new(MACRO_MAX, 0);
    +	for (im = 0; im < MACRO_MAX; im++) {
    +		macro = mandoc_malloc(sizeof(*macro));
    +		mandoc_ohash_init(macro, 4,
    +		    offsetof(struct macro_entry, value));
    +		dba_array_set(dba->macros, im, macro);
    +	}
    +	return dba;
    +}
    +
    +void
    +dba_free(struct dba *dba)
    +{
    +	struct dba_array	*page;
    +	struct ohash		*macro;
    +	struct macro_entry	*entry;
    +	unsigned int		 slot;
    +
    +	dba_array_FOREACH(dba->macros, macro) {
    +		for (entry = ohash_first(macro, &slot); entry != NULL;
    +		     entry = ohash_next(macro, &slot)) {
    +			dba_array_free(entry->pages);
    +			free(entry);
    +		}
    +		ohash_delete(macro);
    +		free(macro);
    +	}
    +	dba_array_free(dba->macros);
    +
    +	dba_array_undel(dba->pages);
    +	dba_array_FOREACH(dba->pages, page) {
    +		dba_array_free(dba_array_get(page, DBP_NAME));
    +		dba_array_free(dba_array_get(page, DBP_SECT));
    +		dba_array_free(dba_array_get(page, DBP_ARCH));
    +		free(dba_array_get(page, DBP_DESC));
    +		dba_array_free(dba_array_get(page, DBP_FILE));
    +		dba_array_free(page);
    +	}
    +	dba_array_free(dba->pages);
    +
    +	free(dba);
    +}
    +
    +/*
    + * Write the complete mandoc database to disk; the format is:
    + * - One integer each for magic and version.
    + * - One pointer each to the macros table and to the final magic.
    + * - The pages table.
    + * - The macros table.
    + * - And at the very end, the magic integer again.
    + */
    +int
    +dba_write(const char *fname, struct dba *dba)
    +{
    +	int	 save_errno;
    +	int32_t	 pos_end, pos_macros, pos_macros_ptr;
    +
    +	if (dba_open(fname) == -1)
    +		return -1;
    +	dba_int_write(MANDOCDB_MAGIC);
    +	dba_int_write(MANDOCDB_VERSION);
    +	pos_macros_ptr = dba_skip(1, 2);
    +	dba_pages_write(dba->pages);
    +	pos_macros = dba_tell();
    +	dba_macros_write(dba->macros);
    +	pos_end = dba_tell();
    +	dba_int_write(MANDOCDB_MAGIC);
    +	dba_seek(pos_macros_ptr);
    +	dba_int_write(pos_macros);
    +	dba_int_write(pos_end);
    +	if (dba_close() == -1) {
    +		save_errno = errno;
    +		unlink(fname);
    +		errno = save_errno;
    +		return -1;
    +	}
    +	return 0;
    +}
    +
    +
    +/*** functions for handling pages *************************************/
    +
    +/*
    + * Create a new page and append it to the pages table.
    + */
    +struct dba_array *
    +dba_page_new(struct dba_array *pages, const char *arch,
    +    const char *desc, const char *file, enum form form)
    +{
    +	struct dba_array *page, *entry;
    +
    +	page = dba_array_new(DBP_MAX, 0);
    +	entry = dba_array_new(1, DBA_STR | DBA_GROW);
    +	dba_array_add(page, entry);
    +	entry = dba_array_new(1, DBA_STR | DBA_GROW);
    +	dba_array_add(page, entry);
    +	if (arch != NULL && *arch != '\0') {
    +		entry = dba_array_new(1, DBA_STR | DBA_GROW);
    +		dba_array_add(entry, (void *)arch);
    +	} else
    +		entry = NULL;
    +	dba_array_add(page, entry);
    +	dba_array_add(page, mandoc_strdup(desc));
    +	entry = dba_array_new(1, DBA_STR | DBA_GROW);
    +	dba_array_add(entry, prepend(file, form));
    +	dba_array_add(page, entry);
    +	dba_array_add(pages, page);
    +	return page;
    +}
    +
    +/*
    + * Add a section, architecture, or file name to an existing page.
    + * Passing the NULL pointer for the architecture makes the page MI.
    + * In that case, any earlier or later architectures are ignored.
    + */
    +void
    +dba_page_add(struct dba_array *page, int32_t ie, const char *str)
    +{
    +	struct dba_array	*entries;
    +	char			*entry;
    +
    +	entries = dba_array_get(page, ie);
    +	if (ie == DBP_ARCH) {
    +		if (entries == NULL)
    +			return;
    +		if (str == NULL || *str == '\0') {
    +			dba_array_free(entries);
    +			dba_array_set(page, DBP_ARCH, NULL);
    +			return;
    +		}
    +	}
    +	if (*str == '\0')
    +		return;
    +	dba_array_FOREACH(entries, entry) {
    +		if (ie == DBP_FILE && *entry < ' ')
    +			entry++;
    +		if (strcmp(entry, str) == 0)
    +			return;
    +	}
    +	dba_array_add(entries, (void *)str);
    +}
    +
    +/*
    + * Add an additional name to an existing page.
    + */
    +void
    +dba_page_alias(struct dba_array *page, const char *name, uint64_t mask)
    +{
    +	struct dba_array	*entries;
    +	char			*entry;
    +	char			 maskbyte;
    +
    +	if (*name == '\0')
    +		return;
    +	maskbyte = mask & NAME_MASK;
    +	entries = dba_array_get(page, DBP_NAME);
    +	dba_array_FOREACH(entries, entry) {
    +		if (strcmp(entry + 1, name) == 0) {
    +			*entry |= maskbyte;
    +			return;
    +		}
    +	}
    +	dba_array_add(entries, prepend(name, maskbyte));
    +}
    +
    +/*
    + * Return a pointer to a temporary copy of instr with inbyte prepended.
    + */
    +static void *
    +prepend(const char *instr, char inbyte)
    +{
    +	static char	*outstr = NULL;
    +	static size_t	 outlen = 0;
    +	size_t		 newlen;
    +
    +	newlen = strlen(instr) + 1;
    +	if (newlen > outlen) {
    +		outstr = mandoc_realloc(outstr, newlen + 1);
    +		outlen = newlen;
    +	}
    +	*outstr = inbyte;
    +	memcpy(outstr + 1, instr, newlen);
    +	return outstr;
    +}
    +
    +/*
    + * Write the pages table to disk; the format is:
    + * - One integer containing the number of pages.
    + * - For each page, five pointers to the names, sections,
    + *   architectures, description, and file names of the page.
    + *   MI pages write 0 instead of the architecture pointer.
    + * - One list each for names, sections, architectures, descriptions and
    + *   file names.  The description for each page ends with a NUL byte.
    + *   For all the other lists, each string ends with a NUL byte,
    + *   and the last string for a page ends with two NUL bytes.
    + * - To assure alignment of following integers,
    + *   the end is padded with NUL bytes up to a multiple of four bytes.
    + */
    +static void
    +dba_pages_write(struct dba_array *pages)
    +{
    +	struct dba_array	*page, *entry;
    +	int32_t			 pos_pages, pos_end;
    +
    +	pos_pages = dba_array_writelen(pages, 5);
    +	dba_array_FOREACH(pages, page) {
    +		dba_array_setpos(page, DBP_NAME, dba_tell());
    +		entry = dba_array_get(page, DBP_NAME);
    +		dba_array_sort(entry, compare_names);
    +		dba_array_writelst(entry);
    +	}
    +	dba_array_FOREACH(pages, page) {
    +		dba_array_setpos(page, DBP_SECT, dba_tell());
    +		entry = dba_array_get(page, DBP_SECT);
    +		dba_array_sort(entry, compare_strings);
    +		dba_array_writelst(entry);
    +	}
    +	dba_array_FOREACH(pages, page) {
    +		if ((entry = dba_array_get(page, DBP_ARCH)) != NULL) {
    +			dba_array_setpos(page, DBP_ARCH, dba_tell());
    +			dba_array_sort(entry, compare_strings);
    +			dba_array_writelst(entry);
    +		} else
    +			dba_array_setpos(page, DBP_ARCH, 0);
    +	}
    +	dba_array_FOREACH(pages, page) {
    +		dba_array_setpos(page, DBP_DESC, dba_tell());
    +		dba_str_write(dba_array_get(page, DBP_DESC));
    +	}
    +	dba_array_FOREACH(pages, page) {
    +		dba_array_setpos(page, DBP_FILE, dba_tell());
    +		dba_array_writelst(dba_array_get(page, DBP_FILE));
    +	}
    +	pos_end = dba_align();
    +	dba_seek(pos_pages);
    +	dba_array_FOREACH(pages, page)
    +		dba_array_writepos(page);
    +	dba_seek(pos_end);
    +}
    +
    +static int
    +compare_names(const void *vp1, const void *vp2)
    +{
    +	const char	*cp1, *cp2;
    +	int		 diff;
    +
    +	cp1 = *(const char * const *)vp1;
    +	cp2 = *(const char * const *)vp2;
    +	return (diff = *cp2 - *cp1) ? diff :
    +	    strcasecmp(cp1 + 1, cp2 + 1);
    +}
    +
    +static int
    +compare_strings(const void *vp1, const void *vp2)
    +{
    +	const char	*cp1, *cp2;
    +
    +	cp1 = *(const char * const *)vp1;
    +	cp2 = *(const char * const *)vp2;
    +	return strcmp(cp1, cp2);
    +}
    +
    +/*** functions for handling macros ************************************/
    +
    +/*
    + * In the hash table for a single macro, look up an entry by
    + * the macro value or add an empty one if it doesn't exist yet.
    + */
    +static struct macro_entry *
    +get_macro_entry(struct ohash *macro, const char *value, int32_t np)
    +{
    +	struct macro_entry	*entry;
    +	size_t			 len;
    +	unsigned int		 slot;
    +
    +	slot = ohash_qlookup(macro, value);
    +	if ((entry = ohash_find(macro, slot)) == NULL) {
    +		len = strlen(value) + 1;
    +		entry = mandoc_malloc(sizeof(*entry) + len);
    +		memcpy(&entry->value, value, len);
    +		entry->pages = dba_array_new(np, DBA_GROW);
    +		ohash_insert(macro, slot, entry);
    +	}
    +	return entry;
    +}
    +
    +/*
    + * In addition to get_macro_entry(), add multiple page references,
    + * converting them from the on-disk format (byte offsets in the file)
    + * to page pointers in memory.
    + */
    +void
    +dba_macro_new(struct dba *dba, int32_t im, const char *value,
    +    const int32_t *pp)
    +{
    +	struct macro_entry	*entry;
    +	const int32_t		*ip;
    +	int32_t			 np;
    +
    +	np = 0;
    +	for (ip = pp; *ip; ip++)
    +		np++;
    +
    +	entry = get_macro_entry(dba_array_get(dba->macros, im), value, np);
    +	for (ip = pp; *ip; ip++)
    +		dba_array_add(entry->pages, dba_array_get(dba->pages,
    +		    be32toh(*ip) / 5 / sizeof(*ip) - 1));
    +}
    +
    +/*
    + * In addition to get_macro_entry(), add one page reference,
    + * directly taking the in-memory page pointer as an argument.
    + */
    +void
    +dba_macro_add(struct dba_array *macros, int32_t im, const char *value,
    +    struct dba_array *page)
    +{
    +	struct macro_entry	*entry;
    +
    +	if (*value == '\0')
    +		return;
    +	entry = get_macro_entry(dba_array_get(macros, im), value, 1);
    +	dba_array_add(entry->pages, page);
    +}
    +
    +/*
    + * Write the macros table to disk; the format is:
    + * - The number of macro tables (actually, MACRO_MAX).
    + * - That number of pointers to the individual macro tables.
    + * - The individual macro tables.
    + */
    +static void
    +dba_macros_write(struct dba_array *macros)
    +{
    +	struct ohash		*macro;
    +	int32_t			 im, pos_macros, pos_end;
    +
    +	pos_macros = dba_array_writelen(macros, 1);
    +	im = 0;
    +	dba_array_FOREACH(macros, macro) {
    +		dba_array_setpos(macros, im++, dba_tell());
    +		dba_macro_write(macro);
    +	}
    +	pos_end = dba_tell();
    +	dba_seek(pos_macros);
    +	dba_array_writepos(macros);
    +	dba_seek(pos_end);
    +}
    +
    +/*
    + * Write one individual macro table to disk; the format is:
    + * - The number of entries in the table.
    + * - For each entry, two pointers, the first one to the value
    + *   and the second one to the list of pages.
    + * - A list of values, each ending in a NUL byte.
    + * - To assure alignment of following integers,
    + *   padding with NUL bytes up to a multiple of four bytes.
    + * - A list of pointers to pages, each list ending in a 0 integer.
    + */
    +static void
    +dba_macro_write(struct ohash *macro)
    +{
    +	struct macro_entry	**entries, *entry;
    +	struct dba_array	 *page;
    +	int32_t			 *kpos, *dpos;
    +	unsigned int		  ie, ne, slot;
    +	int			  use;
    +	int32_t			  addr, pos_macro, pos_end;
    +
    +	/* Temporary storage for filtering and sorting. */
    +
    +	ne = ohash_entries(macro);
    +	entries = mandoc_reallocarray(NULL, ne, sizeof(*entries));
    +	kpos = mandoc_reallocarray(NULL, ne, sizeof(*kpos));
    +	dpos = mandoc_reallocarray(NULL, ne, sizeof(*dpos));
    +
    +	/* Build a list of non-empty entries and sort it. */
    +
    +	ne = 0;
    +	for (entry = ohash_first(macro, &slot); entry != NULL;
    +	     entry = ohash_next(macro, &slot)) {
    +		use = 0;
    +		dba_array_FOREACH(entry->pages, page)
    +			if (dba_array_getpos(page))
    +				use = 1;
    +		if (use)
    +			entries[ne++] = entry;
    +	}
    +	qsort(entries, ne, sizeof(*entries), compare_entries);
    +
    +	/* Number of entries, and space for the pointer pairs. */
    +
    +	dba_int_write(ne);
    +	pos_macro = dba_skip(2, ne);
    +
    +	/* String table. */
    +
    +	for (ie = 0; ie < ne; ie++) {
    +		kpos[ie] = dba_tell();
    +		dba_str_write(entries[ie]->value);
    +	}
    +	dba_align();
    +
    +	/* Pages table. */
    +
    +	for (ie = 0; ie < ne; ie++) {
    +		dpos[ie] = dba_tell();
    +		dba_array_FOREACH(entries[ie]->pages, page)
    +			if ((addr = dba_array_getpos(page)))
    +				dba_int_write(addr);
    +		dba_int_write(0);
    +	}
    +	pos_end = dba_tell();
    +
    +	/* Fill in the pointer pairs. */
    +
    +	dba_seek(pos_macro);
    +	for (ie = 0; ie < ne; ie++) {
    +		dba_int_write(kpos[ie]);
    +		dba_int_write(dpos[ie]);
    +	}
    +	dba_seek(pos_end);
    +
    +	free(entries);
    +	free(kpos);
    +	free(dpos);
    +}
    +
    +static int
    +compare_entries(const void *vp1, const void *vp2)
    +{
    +	const struct macro_entry *ep1, *ep2;
    +
    +	ep1 = *(const struct macro_entry * const *)vp1;
    +	ep2 = *(const struct macro_entry * const *)vp2;
    +	return strcmp(ep1->value, ep2->value);
    +}
    
    Property changes on: head/contrib/mandoc/dba.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dbm_map.c
    ===================================================================
    --- head/contrib/mandoc/dbm_map.c	(nonexistent)
    +++ head/contrib/mandoc/dbm_map.c	(revision 338826)
    @@ -0,0 +1,194 @@
    +/*	$Id: dbm_map.c,v 1.8 2017/02/17 14:43:54 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Low-level routines for the map-based version
    + * of the mandoc database, for read-only access.
    + * The interface is defined in "dbm_map.h".
    + */
    +#include "config.h"
    +
    +#include <sys/mman.h>
    +#include <sys/stat.h>
    +#include <sys/types.h>
    +
    +#if HAVE_ENDIAN
    +#include <endian.h>
    +#elif HAVE_SYS_ENDIAN
    +#include <sys/endian.h>
    +#elif HAVE_NTOHL
    +#include <arpa/inet.h>
    +#endif
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <regex.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "mansearch.h"
    +#include "dbm_map.h"
    +#include "dbm.h"
    +
    +static struct stat	 st;
    +static char		*dbm_base;
    +static int		 ifd;
    +static int32_t		 max_offset;
    +
    +/*
    + * Open a disk-based database for read-only access.
    + * Validate the file format as far as it is not mandoc-specific.
    + * Return 0 on success.  Return -1 and set errno on failure.
    + */
    +int
    +dbm_map(const char *fname)
    +{
    +	int		 save_errno;
    +	const int32_t	*magic;
    +
    +	if ((ifd = open(fname, O_RDONLY)) == -1)
    +		return -1;
    +	if (fstat(ifd, &st) == -1)
    +		goto fail;
    +	if (st.st_size < 5) {
    +		warnx("dbm_map(%s): File too short", fname);
    +		errno = EFTYPE;
    +		goto fail;
    +	}
    +	if (st.st_size > INT32_MAX) {
    +		errno = EFBIG;
    +		goto fail;
    +	}
    +	if ((dbm_base = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED,
    +	    ifd, 0)) == MAP_FAILED)
    +		goto fail;
    +	magic = dbm_getint(0);
    +	if (be32toh(*magic) != MANDOCDB_MAGIC) {
    +		if (strncmp(dbm_base, "SQLite format 3", 15))
    +			warnx("dbm_map(%s): "
    +			    "Bad initial magic %x (expected %x)",
    +			    fname, be32toh(*magic), MANDOCDB_MAGIC);
    +		else
    +			warnx("dbm_map(%s): "
    +			    "Obsolete format based on SQLite 3",
    +			    fname);
    +		errno = EFTYPE;
    +		goto fail;
    +	}
    +	magic = dbm_getint(1);
    +	if (be32toh(*magic) != MANDOCDB_VERSION) {
    +		warnx("dbm_map(%s): Bad version number %d (expected %d)",
    +		    fname, be32toh(*magic), MANDOCDB_VERSION);
    +		errno = EFTYPE;
    +		goto fail;
    +	}
    +	max_offset = be32toh(*dbm_getint(3)) + sizeof(int32_t);
    +	if (st.st_size != max_offset) {
    +		warnx("dbm_map(%s): Inconsistent file size %lld (expected %d)",
    +		    fname, (long long)st.st_size, max_offset);
    +		errno = EFTYPE;
    +		goto fail;
    +	}
    +	if ((magic = dbm_get(*dbm_getint(3))) == NULL) {
    +		errno = EFTYPE;
    +		goto fail;
    +	}
    +	if (be32toh(*magic) != MANDOCDB_MAGIC) {
    +		warnx("dbm_map(%s): Bad final magic %x (expected %x)",
    +		    fname, be32toh(*magic), MANDOCDB_MAGIC);
    +		errno = EFTYPE;
    +		goto fail;
    +	}
    +	return 0;
    +
    +fail:
    +	save_errno = errno;
    +	close(ifd);
    +	errno = save_errno;
    +	return -1;
    +}
    +
    +void
    +dbm_unmap(void)
    +{
    +	if (munmap(dbm_base, st.st_size) == -1)
    +		warn("dbm_unmap: munmap");
    +	if (close(ifd) == -1)
    +		warn("dbm_unmap: close");
    +	dbm_base = (char *)-1;
    +}
    +
    +/*
    + * Take a raw integer as it was read from the database.
    + * Interpret it as an offset into the database file
    + * and return a pointer to that place in the file.
    + */
    +void *
    +dbm_get(int32_t offset)
    +{
    +	offset = be32toh(offset);
    +	if (offset < 0) {
    +		warnx("dbm_get: Database corrupt: offset %d", offset);
    +		return NULL;
    +	}
    +	if (offset >= max_offset) {
    +		warnx("dbm_get: Database corrupt: offset %d > %d",
    +		    offset, max_offset);
    +		return NULL;
    +	}
    +	return dbm_base + offset;
    +}
    +
    +/*
    + * Assume the database starts with some integers.
    + * Assume they are numbered starting from 0, increasing.
    + * Get a pointer to one with the number "offset".
    + */
    +int32_t *
    +dbm_getint(int32_t offset)
    +{
    +	return (int32_t *)dbm_base + offset;
    +}
    +
    +/*
    + * The reverse of dbm_get().
    + * Take pointer into the database file
    + * and convert it to the raw integer
    + * that would be used to refer to that place in the file.
    + */
    +int32_t
    +dbm_addr(const void *p)
    +{
    +	return htobe32((const char *)p - dbm_base);
    +}
    +
    +int
    +dbm_match(const struct dbm_match *match, const char *str)
    +{
    +	switch (match->type) {
    +	case DBM_EXACT:
    +		return strcmp(str, match->str) == 0;
    +	case DBM_SUB:
    +		return strcasestr(str, match->str) != NULL;
    +	case DBM_REGEX:
    +		return regexec(match->re, str, 0, NULL, 0) == 0;
    +	default:
    +		abort();
    +	}
    +}
    
    Property changes on: head/contrib/mandoc/dbm_map.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/preconv.c
    ===================================================================
    --- head/contrib/mandoc/preconv.c	(nonexistent)
    +++ head/contrib/mandoc/preconv.c	(revision 338826)
    @@ -0,0 +1,176 @@
    +/*	$Id: preconv.c,v 1.16 2017/02/18 13:43:52 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <assert.h>
    +#include <stdio.h>
    +#include <string.h>
    +#include "mandoc.h"
    +#include "libmandoc.h"
    +
    +int
    +preconv_encode(const struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
    +    int *filenc)
    +{
    +	const unsigned char	*cu;
    +	int			 nby;
    +	unsigned int		 accum;
    +
    +	cu = (const unsigned char *)ib->buf + *ii;
    +	assert(*cu & 0x80);
    +
    +	if ( ! (*filenc & MPARSE_UTF8))
    +		goto latin;
    +
    +	nby = 1;
    +	while (nby < 5 && *cu & (1 << (7 - nby)))
    +		nby++;
    +
    +	switch (nby) {
    +	case 2:
    +		accum = *cu & 0x1f;
    +		if (accum < 0x02)  /* Obfuscated ASCII. */
    +			goto latin;
    +		break;
    +	case 3:
    +		accum = *cu & 0x0f;
    +		break;
    +	case 4:
    +		accum = *cu & 0x07;
    +		if (accum > 0x04) /* Beyond Unicode. */
    +			goto latin;
    +		break;
    +	default:  /* Bad sequence header. */
    +		goto latin;
    +	}
    +
    +	cu++;
    +	switch (nby) {
    +	case 3:
    +		if ((accum == 0x00 && ! (*cu & 0x20)) ||  /* Use 2-byte. */
    +		    (accum == 0x0d && *cu & 0x20))  /* Surrogates. */
    +			goto latin;
    +		break;
    +	case 4:
    +		if ((accum == 0x00 && ! (*cu & 0x30)) ||  /* Use 3-byte. */
    +		    (accum == 0x04 && *cu & 0x30))  /* Beyond Unicode. */
    +			goto latin;
    +		break;
    +	default:
    +		break;
    +	}
    +
    +	while (--nby) {
    +		if ((*cu & 0xc0) != 0x80)  /* Invalid continuation. */
    +			goto latin;
    +		accum <<= 6;
    +		accum += *cu & 0x3f;
    +		cu++;
    +	}
    +
    +	assert(accum > 0x7f);
    +	assert(accum < 0x110000);
    +	assert(accum < 0xd800 || accum > 0xdfff);
    +
    +	*oi += snprintf(ob->buf + *oi, 11, "\\[u%.4X]", accum);
    +	*ii = (const char *)cu - ib->buf;
    +	*filenc &= ~MPARSE_LATIN1;
    +	return 1;
    +
    +latin:
    +	if ( ! (*filenc & MPARSE_LATIN1))
    +		return 0;
    +
    +	*oi += snprintf(ob->buf + *oi, 11,
    +	    "\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
    +
    +	*filenc &= ~MPARSE_UTF8;
    +	return 1;
    +}
    +
    +int
    +preconv_cue(const struct buf *b, size_t offset)
    +{
    +	const char	*ln, *eoln, *eoph;
    +	size_t		 sz, phsz;
    +
    +	ln = b->buf + offset;
    +	sz = b->sz - offset;
    +
    +	/* Look for the end-of-line. */
    +
    +	if (NULL == (eoln = memchr(ln, '\n', sz)))
    +		eoln = ln + sz;
    +
    +	/* Check if we have the correct header/trailer. */
    +
    +	if ((sz = (size_t)(eoln - ln)) < 10 ||
    +	    memcmp(ln, ".\\\" -*-", 7) || memcmp(eoln - 3, "-*-", 3))
    +		return MPARSE_UTF8 | MPARSE_LATIN1;
    +
    +	/* Move after the header and adjust for the trailer. */
    +
    +	ln += 7;
    +	sz -= 10;
    +
    +	while (sz > 0) {
    +		while (sz > 0 && ' ' == *ln) {
    +			ln++;
    +			sz--;
    +		}
    +		if (0 == sz)
    +			break;
    +
    +		/* Find the end-of-phrase marker (or eoln). */
    +
    +		if (NULL == (eoph = memchr(ln, ';', sz)))
    +			eoph = eoln - 3;
    +		else
    +			eoph++;
    +
    +		/* Only account for the "coding" phrase. */
    +
    +		if ((phsz = eoph - ln) < 7 ||
    +		    strncasecmp(ln, "coding:", 7)) {
    +			sz -= phsz;
    +			ln += phsz;
    +			continue;
    +		}
    +
    +		sz -= 7;
    +		ln += 7;
    +
    +		while (sz > 0 && ' ' == *ln) {
    +			ln++;
    +			sz--;
    +		}
    +		if (0 == sz)
    +			return 0;
    +
    +		/* Check us against known encodings. */
    +
    +		if (phsz > 4 && !strncasecmp(ln, "utf-8", 5))
    +			return MPARSE_UTF8;
    +		if (phsz > 10 && !strncasecmp(ln, "iso-latin-1", 11))
    +			return MPARSE_LATIN1;
    +		return 0;
    +	}
    +	return MPARSE_UTF8 | MPARSE_LATIN1;
    +}
    
    Property changes on: head/contrib/mandoc/preconv.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-O_DIRECTORY.c
    ===================================================================
    --- head/contrib/mandoc/test-O_DIRECTORY.c	(nonexistent)
    +++ head/contrib/mandoc/test-O_DIRECTORY.c	(revision 338826)
    @@ -0,0 +1,7 @@
    +#include <fcntl.h>
    +
    +int
    +main(void)
    +{
    +	return open(".", O_RDONLY | O_DIRECTORY) == -1;
    +}
    
    Property changes on: head/contrib/mandoc/test-O_DIRECTORY.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-cmsg.c
    ===================================================================
    --- head/contrib/mandoc/test-cmsg.c	(nonexistent)
    +++ head/contrib/mandoc/test-cmsg.c	(revision 338826)
    @@ -0,0 +1,13 @@
    +#include <stddef.h>
    +#include <sys/socket.h>
    +
    +int
    +main(void)
    +{
    +	struct msghdr	 msg;
    +
    +	msg.msg_control = NULL;
    +	msg.msg_controllen = 0;
    +
    +	return CMSG_FIRSTHDR(&msg) != NULL;
    +}
    
    Property changes on: head/contrib/mandoc/test-cmsg.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-recvmsg.c
    ===================================================================
    --- head/contrib/mandoc/test-recvmsg.c	(nonexistent)
    +++ head/contrib/mandoc/test-recvmsg.c	(revision 338826)
    @@ -0,0 +1,8 @@
    +#include <sys/socket.h>
    +#include <stddef.h>
    +
    +int
    +main(void)
    +{
    +	return recvmsg(-1, NULL, 0) != -1;
    +}
    
    Property changes on: head/contrib/mandoc/test-recvmsg.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_fts.h
    ===================================================================
    --- head/contrib/mandoc/compat_fts.h	(nonexistent)
    +++ head/contrib/mandoc/compat_fts.h	(revision 338826)
    @@ -0,0 +1,105 @@
    +/*	$OpenBSD: fts.h,v 1.14 2012/12/05 23:19:57 deraadt Exp $	*/
    +/*	$NetBSD: fts.h,v 1.7 2012/03/01 16:18:51 hans Exp $	*/
    +
    +/*
    + * Copyright (c) 1989, 1993
    + *	The Regents of the University of California.  All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. Neither the name of the University nor the names of its contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + *
    + *	@(#)fts.h	8.3 (Berkeley) 8/14/94
    + */
    +
    +#ifndef	_FTS_H_
    +#define	_FTS_H_
    +
    +typedef struct {
    +	struct _ftsent *fts_cur;	/* current node */
    +	struct _ftsent *fts_child;	/* linked list of children */
    +	struct _ftsent **fts_array;	/* sort array */
    +	dev_t fts_dev;			/* starting device # */
    +	char *fts_path;			/* path for this descent */
    +	size_t fts_pathlen;		/* sizeof(path) */
    +	int fts_nitems;			/* elements in the sort array */
    +	int (*fts_compar)();		/* compare function */
    +
    +#define	FTS_NOCHDIR	0x0004		/* don't change directories */
    +#define	FTS_PHYSICAL	0x0010		/* physical walk */
    +#define	FTS_XDEV	0x0040		/* don't cross devices */
    +#define	FTS_OPTIONMASK	0x0054		/* valid user option mask */
    +
    +#define	FTS_STOP	0x2000		/* (private) unrecoverable error */
    +	int fts_options;		/* fts_open options, global flags */
    +} FTS;
    +
    +typedef struct _ftsent {
    +	struct _ftsent *fts_cycle;	/* cycle node */
    +	struct _ftsent *fts_parent;	/* parent directory */
    +	struct _ftsent *fts_link;	/* next file in directory */
    +	char *fts_accpath;		/* access path */
    +	char *fts_path;			/* root path */
    +	int fts_errno;			/* errno for this node */
    +	size_t fts_pathlen;		/* strlen(fts_path) */
    +	size_t fts_namelen;		/* strlen(fts_name) */
    +
    +	ino_t fts_ino;			/* inode */
    +	dev_t fts_dev;			/* device */
    +	nlink_t fts_nlink;		/* link count */
    +
    +#define	FTS_ROOTPARENTLEVEL	-1
    +#define	FTS_ROOTLEVEL		 0
    +#define	FTS_MAXLEVEL		 0x7fffffff
    +	int fts_level;		/* depth (-1 to N) */
    +
    +#define	FTS_D		 1		/* preorder directory */
    +#define	FTS_DC		 2		/* directory that causes cycles */
    +#define	FTS_DEFAULT	 3		/* none of the above */
    +#define	FTS_DNR		 4		/* unreadable directory */
    +#define	FTS_DOT		 5		/* dot or dot-dot */
    +#define	FTS_DP		 6		/* postorder directory */
    +#define	FTS_ERR		 7		/* error; errno is set */
    +#define	FTS_F		 8		/* regular file */
    +#define	FTS_INIT	 9		/* initialized only */
    +#define	FTS_NS		10		/* stat(2) failed */
    +#define	FTS_NSOK	11		/* no stat(2) requested */
    +#define	FTS_SL		12		/* symbolic link */
    +	unsigned short fts_info;	/* user flags for FTSENT structure */
    +
    +#define	FTS_NOINSTR	 3		/* no instructions */
    +#define	FTS_SKIP	 4		/* discard node */
    +	unsigned short fts_instr;	/* fts_set() instructions */
    +
    +	struct stat *fts_statp;		/* stat(2) information */
    +	char fts_name[1];		/* file name */
    +} FTSENT;
    +
    +
    +int	 fts_close(FTS *);
    +FTS	*fts_open(char * const *, int,
    +	    int (*)(const FTSENT **, const FTSENT **));
    +FTSENT	*fts_read(FTS *);
    +int	 fts_set(FTS *, FTSENT *, int);
    +
    +#endif /* !_FTS_H_ */
    
    Property changes on: head/contrib/mandoc/compat_fts.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dba.h
    ===================================================================
    --- head/contrib/mandoc/dba.h	(nonexistent)
    +++ head/contrib/mandoc/dba.h	(revision 338826)
    @@ -0,0 +1,50 @@
    +/*	$Id: dba.h,v 1.2 2016/08/17 20:46:56 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Public interface of the allocation-based version
    + * of the mandoc database, for read-write access.
    + * To be used by dba.c, dba_read.c, and makewhatis(8).
    + */
    +
    +#define	DBP_NAME	0
    +#define	DBP_SECT	1
    +#define	DBP_ARCH	2
    +#define	DBP_DESC	3
    +#define	DBP_FILE	4
    +#define	DBP_MAX		5
    +
    +struct dba_array;
    +
    +struct dba {
    +	struct dba_array	*pages;
    +	struct dba_array	*macros;
    +};
    +
    +
    +struct dba	*dba_new(int32_t);
    +void		 dba_free(struct dba *);
    +struct dba	*dba_read(const char *);
    +int		 dba_write(const char *, struct dba *);
    +
    +struct dba_array *dba_page_new(struct dba_array *, const char *,
    +			const char *, const char *, enum form);
    +void		 dba_page_add(struct dba_array *, int32_t, const char *);
    +void		 dba_page_alias(struct dba_array *, const char *, uint64_t);
    +
    +void		 dba_macro_new(struct dba *, int32_t,
    +			const char *, const int32_t *);
    +void		 dba_macro_add(struct dba_array *, int32_t,
    +			const char *, struct dba_array *);
    
    Property changes on: head/contrib/mandoc/dba.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dba_array.c
    ===================================================================
    --- head/contrib/mandoc/dba_array.c	(nonexistent)
    +++ head/contrib/mandoc/dba_array.c	(revision 338826)
    @@ -0,0 +1,188 @@
    +/*	$Id: dba_array.c,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Allocation-based arrays for the mandoc database, for read-write access.
    + * The interface is defined in "dba_array.h".
    + */
    +#include <assert.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc_aux.h"
    +#include "dba_write.h"
    +#include "dba_array.h"
    +
    +struct dba_array {
    +	void	**ep;	/* Array of entries. */
    +	int32_t	 *em;	/* Array of map positions. */
    +	int	  flags;
    +	int32_t	  ea;	/* Entries allocated. */
    +	int32_t	  eu;	/* Entries used (including deleted). */
    +	int32_t	  ed;	/* Entries deleted. */
    +	int32_t	  ec;	/* Currently active entry. */
    +	int32_t	  pos;  /* Map position of this array. */
    +};
    +
    +
    +struct dba_array *
    +dba_array_new(int32_t ea, int flags)
    +{
    +	struct dba_array	*array;
    +
    +	assert(ea > 0);
    +	array = mandoc_malloc(sizeof(*array));
    +	array->ep = mandoc_reallocarray(NULL, ea, sizeof(*array->ep));
    +	array->em = mandoc_reallocarray(NULL, ea, sizeof(*array->em));
    +	array->ea = ea;
    +	array->eu = 0;
    +	array->ed = 0;
    +	array->ec = 0;
    +	array->flags = flags;
    +	array->pos = 0;
    +	return array;
    +}
    +
    +void
    +dba_array_free(struct dba_array *array)
    +{
    +	int32_t	 ie;
    +
    +	if (array == NULL)
    +		return;
    +	if (array->flags & DBA_STR)
    +		for (ie = 0; ie < array->eu; ie++)
    +			free(array->ep[ie]);
    +	free(array->ep);
    +	free(array->em);
    +	free(array);
    +}
    +
    +void
    +dba_array_set(struct dba_array *array, int32_t ie, void *entry)
    +{
    +	assert(ie >= 0);
    +	assert(ie < array->ea);
    +	assert(ie <= array->eu);
    +	if (ie == array->eu)
    +		array->eu++;
    +	if (array->flags & DBA_STR)
    +		entry = mandoc_strdup(entry);
    +	array->ep[ie] = entry;
    +	array->em[ie] = 0;
    +}
    +
    +void
    +dba_array_add(struct dba_array *array, void *entry)
    +{
    +	if (array->eu == array->ea) {
    +		assert(array->flags & DBA_GROW);
    +		array->ep = mandoc_reallocarray(array->ep,
    +		    2, sizeof(*array->ep) * array->ea);
    +		array->em = mandoc_reallocarray(array->em,
    +		    2, sizeof(*array->em) * array->ea);
    +		array->ea *= 2;
    +	}
    +	dba_array_set(array, array->eu, entry);
    +}
    +
    +void *
    +dba_array_get(struct dba_array *array, int32_t ie)
    +{
    +	if (ie < 0 || ie >= array->eu || array->em[ie] == -1)
    +		return NULL;
    +	return array->ep[ie];
    +}
    +
    +void
    +dba_array_start(struct dba_array *array)
    +{
    +	array->ec = array->eu;
    +}
    +
    +void *
    +dba_array_next(struct dba_array *array)
    +{
    +	if (array->ec < array->eu)
    +		array->ec++;
    +	else
    +		array->ec = 0;
    +	while (array->ec < array->eu && array->em[array->ec] == -1)
    +		array->ec++;
    +	return array->ec < array->eu ? array->ep[array->ec] : NULL;
    +}
    +
    +void
    +dba_array_del(struct dba_array *array)
    +{
    +	if (array->ec < array->eu && array->em[array->ec] != -1) {
    +		array->em[array->ec] = -1;
    +		array->ed++;
    +	}
    +}
    +
    +void
    +dba_array_undel(struct dba_array *array)
    +{
    +	memset(array->em, 0, sizeof(*array->em) * array->eu);
    +}
    +
    +void
    +dba_array_setpos(struct dba_array *array, int32_t ie, int32_t pos)
    +{
    +	array->em[ie] = pos;
    +}
    +
    +int32_t
    +dba_array_getpos(struct dba_array *array)
    +{
    +	return array->pos;
    +}
    +
    +void
    +dba_array_sort(struct dba_array *array, dba_compare_func func)
    +{
    +	assert(array->ed == 0);
    +	qsort(array->ep, array->eu, sizeof(*array->ep), func);
    +}
    +
    +int32_t
    +dba_array_writelen(struct dba_array *array, int32_t nmemb)
    +{
    +	dba_int_write(array->eu - array->ed);
    +	return dba_skip(nmemb, array->eu - array->ed);
    +}
    +
    +void
    +dba_array_writepos(struct dba_array *array)
    +{
    +	int32_t	 ie;
    +
    +	array->pos = dba_tell();
    +	for (ie = 0; ie < array->eu; ie++)
    +		if (array->em[ie] != -1)
    +			dba_int_write(array->em[ie]);
    +}
    +
    +void
    +dba_array_writelst(struct dba_array *array)
    +{
    +	const char	*str;
    +
    +	dba_array_FOREACH(array, str)
    +		dba_str_write(str);
    +	dba_char_write('\0');
    +}
    
    Property changes on: head/contrib/mandoc/dba_array.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dba_array.h
    ===================================================================
    --- head/contrib/mandoc/dba_array.h	(nonexistent)
    +++ head/contrib/mandoc/dba_array.h	(revision 338826)
    @@ -0,0 +1,47 @@
    +/*	$Id: dba_array.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Public interface for allocation-based arrays
    + * for the mandoc database, for read-write access.
    + * To be used by dba*.c and by makewhatis(8).
    + */
    +
    +struct dba_array;
    +
    +#define	DBA_STR		0x01	/* Map contains strings, not pointers. */
    +#define	DBA_GROW	0x02	/* Allow the array to grow. */
    +
    +#define	dba_array_FOREACH(a, e) \
    +	dba_array_start(a); \
    +	while (((e) = dba_array_next(a)) != NULL)
    +
    +typedef int dba_compare_func(const void *, const void *);
    +
    +struct dba_array *dba_array_new(int32_t, int);
    +void		 dba_array_free(struct dba_array *);
    +void		 dba_array_set(struct dba_array *, int32_t, void *);
    +void		 dba_array_add(struct dba_array *, void *);
    +void		*dba_array_get(struct dba_array *, int32_t);
    +void		 dba_array_start(struct dba_array *);
    +void		*dba_array_next(struct dba_array *);
    +void		 dba_array_del(struct dba_array *);
    +void		 dba_array_undel(struct dba_array *);
    +void		 dba_array_setpos(struct dba_array *, int32_t, int32_t);
    +int32_t		 dba_array_getpos(struct dba_array *);
    +void		 dba_array_sort(struct dba_array *, dba_compare_func);
    +int32_t		 dba_array_writelen(struct dba_array *, int32_t);
    +void		 dba_array_writepos(struct dba_array *);
    +void		 dba_array_writelst(struct dba_array *);
    
    Property changes on: head/contrib/mandoc/dba_array.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dba_read.c
    ===================================================================
    --- head/contrib/mandoc/dba_read.c	(nonexistent)
    +++ head/contrib/mandoc/dba_read.c	(revision 338826)
    @@ -0,0 +1,72 @@
    +/*	$Id: dba_read.c,v 1.4 2016/08/17 20:46:56 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Function to read the mandoc database from disk into RAM,
    + * such that data can be added or removed.
    + * The interface is defined in "dba.h".
    + * This file is seperate from dba.c because this also uses "dbm.h".
    + */
    +#include <regex.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <stdio.h>
    +#include <string.h>
    +
    +#include "mandoc_aux.h"
    +#include "mansearch.h"
    +#include "dba_array.h"
    +#include "dba.h"
    +#include "dbm.h"
    +
    +
    +struct dba *
    +dba_read(const char *fname)
    +{
    +	struct dba		*dba;
    +	struct dba_array	*page;
    +	struct dbm_page		*pdata;
    +	struct dbm_macro	*mdata;
    +	const char		*cp;
    +	int32_t			 im, ip, iv, npages;
    +
    +	if (dbm_open(fname) == -1)
    +		return NULL;
    +	npages = dbm_page_count();
    +	dba = dba_new(npages < 128 ? 128 : npages);
    +	for (ip = 0; ip < npages; ip++) {
    +		pdata = dbm_page_get(ip);
    +		page = dba_page_new(dba->pages, pdata->arch,
    +		    pdata->desc, pdata->file + 1, *pdata->file);
    +		for (cp = pdata->name; *cp != '\0'; cp = strchr(cp, '\0') + 1)
    +			dba_page_add(page, DBP_NAME, cp);
    +		for (cp = pdata->sect; *cp != '\0'; cp = strchr(cp, '\0') + 1)
    +			dba_page_add(page, DBP_SECT, cp);
    +		if ((cp = pdata->arch) != NULL)
    +			while (*(cp = strchr(cp, '\0') + 1) != '\0')
    +				dba_page_add(page, DBP_ARCH, cp);
    +		cp = pdata->file;
    +		while (*(cp = strchr(cp, '\0') + 1) != '\0')
    +			dba_page_add(page, DBP_FILE, cp);
    +	}
    +	for (im = 0; im < MACRO_MAX; im++) {
    +		for (iv = 0; iv < dbm_macro_count(im); iv++) {
    +			mdata = dbm_macro_get(im, iv);
    +			dba_macro_new(dba, im, mdata->value, mdata->pp);
    +		}
    +	}
    +	dbm_close();
    +	return dba;
    +}
    
    Property changes on: head/contrib/mandoc/dba_read.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dba_write.c
    ===================================================================
    --- head/contrib/mandoc/dba_write.c	(nonexistent)
    +++ head/contrib/mandoc/dba_write.c	(revision 338826)
    @@ -0,0 +1,127 @@
    +/*	$Id: dba_write.c,v 1.3 2016/08/05 23:15:08 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Low-level functions for serializing allocation-based data to disk.
    + * The interface is defined in "dba_write.h".
    + */
    +#include "config.h"
    +
    +#include <assert.h>
    +#if HAVE_ENDIAN
    +#include <endian.h>
    +#elif HAVE_SYS_ENDIAN
    +#include <sys/endian.h>
    +#elif HAVE_NTOHL
    +#include <arpa/inet.h>
    +#endif
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <stdint.h>
    +#include <stdio.h>
    +
    +#include "dba_write.h"
    +
    +static FILE	*ofp;
    +
    +
    +int
    +dba_open(const char *fname)
    +{
    +	ofp = fopen(fname, "w");
    +	return ofp == NULL ? -1 : 0;
    +}
    +
    +int
    +dba_close(void)
    +{
    +	return fclose(ofp) == EOF ? -1 : 0;
    +}
    +
    +int32_t
    +dba_tell(void)
    +{
    +	long		 pos;
    +
    +	if ((pos = ftell(ofp)) == -1)
    +		err(1, "ftell");
    +	if (pos >= INT32_MAX) {
    +		errno = EOVERFLOW;
    +		err(1, "ftell = %ld", pos);
    +	}
    +	return pos;
    +}
    +
    +void
    +dba_seek(int32_t pos)
    +{
    +	if (fseek(ofp, pos, SEEK_SET) == -1)
    +		err(1, "fseek(%d)", pos);
    +}
    +
    +int32_t
    +dba_align(void)
    +{
    +	int32_t		 pos;
    +
    +	pos = dba_tell();
    +	while (pos & 3) {
    +		dba_char_write('\0');
    +		pos++;
    +	}
    +	return pos;
    +}
    +
    +int32_t
    +dba_skip(int32_t nmemb, int32_t sz)
    +{
    +	const int32_t	 out[5] = {0, 0, 0, 0, 0};
    +	int32_t		 i, pos;
    +
    +	assert(sz >= 0);
    +	assert(nmemb > 0);
    +	assert(nmemb <= 5);
    +	pos = dba_tell();
    +	for (i = 0; i < sz; i++)
    +		if (nmemb - fwrite(&out, sizeof(out[0]), nmemb, ofp))
    +			err(1, "fwrite");
    +	return pos;
    +}
    +
    +void
    +dba_char_write(int c)
    +{
    +	if (putc(c, ofp) == EOF)
    +		err(1, "fputc");
    +}
    +
    +void
    +dba_str_write(const char *str)
    +{
    +	if (fputs(str, ofp) == EOF)
    +		err(1, "fputs");
    +	dba_char_write('\0');
    +}
    +
    +void
    +dba_int_write(int32_t i)
    +{
    +	i = htobe32(i);
    +	if (fwrite(&i, sizeof(i), 1, ofp) != 1)
    +		err(1, "fwrite");
    +}
    
    Property changes on: head/contrib/mandoc/dba_write.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dba_write.h
    ===================================================================
    --- head/contrib/mandoc/dba_write.h	(nonexistent)
    +++ head/contrib/mandoc/dba_write.h	(revision 338826)
    @@ -0,0 +1,30 @@
    +/*	$Id: dba_write.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Internal interface to low-level functions
    + * for serializing allocation-based data to disk.
    + * For use by dba_array.c and dba.c only.
    + */
    +
    +int	 dba_open(const char *);
    +int	 dba_close(void);
    +int32_t	 dba_tell(void);
    +void	 dba_seek(int32_t);
    +int32_t	 dba_align(void);
    +int32_t	 dba_skip(int32_t, int32_t);
    +void	 dba_char_write(int);
    +void	 dba_str_write(const char *);
    +void	 dba_int_write(int32_t);
    
    Property changes on: head/contrib/mandoc/dba_write.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dbm.c
    ===================================================================
    --- head/contrib/mandoc/dbm.c	(nonexistent)
    +++ head/contrib/mandoc/dbm.c	(revision 338826)
    @@ -0,0 +1,480 @@
    +/*	$Id: dbm.c,v 1.5 2016/10/18 22:27:25 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Map-based version of the mandoc database, for read-only access.
    + * The interface is defined in "dbm.h".
    + */
    +#include "config.h"
    +
    +#include <assert.h>
    +#if HAVE_ENDIAN
    +#include <endian.h>
    +#elif HAVE_SYS_ENDIAN
    +#include <sys/endian.h>
    +#elif HAVE_NTOHL
    +#include <arpa/inet.h>
    +#endif
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <errno.h>
    +#include <regex.h>
    +#include <stdint.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mansearch.h"
    +#include "dbm_map.h"
    +#include "dbm.h"
    +
    +struct macro {
    +	int32_t	value;
    +	int32_t	pages;
    +};
    +
    +struct page {
    +	int32_t	name;
    +	int32_t	sect;
    +	int32_t	arch;
    +	int32_t	desc;
    +	int32_t	file;
    +};
    +
    +enum iter {
    +	ITER_NONE = 0,
    +	ITER_NAME,
    +	ITER_SECT,
    +	ITER_ARCH,
    +	ITER_DESC,
    +	ITER_MACRO
    +};
    +
    +static struct macro	*macros[MACRO_MAX];
    +static int32_t		 nvals[MACRO_MAX];
    +static struct page	*pages;
    +static int32_t		 npages;
    +static enum iter	 iteration;
    +
    +static struct dbm_res	 page_bytitle(enum iter, const struct dbm_match *);
    +static struct dbm_res	 page_byarch(const struct dbm_match *);
    +static struct dbm_res	 page_bymacro(int32_t, const struct dbm_match *);
    +static char		*macro_bypage(int32_t, int32_t);
    +
    +
    +/*** top level functions **********************************************/
    +
    +/*
    + * Open a disk-based mandoc database for read-only access.
    + * Map the pages and macros[] arrays.
    + * Return 0 on success.  Return -1 and set errno on failure.
    + */
    +int
    +dbm_open(const char *fname)
    +{
    +	const int32_t	*mp, *ep;
    +	int32_t		 im;
    +
    +	if (dbm_map(fname) == -1)
    +		return -1;
    +
    +	if ((npages = be32toh(*dbm_getint(4))) < 0) {
    +		warnx("dbm_open(%s): Invalid number of pages: %d",
    +		    fname, npages);
    +		goto fail;
    +	}
    +	pages = (struct page *)dbm_getint(5);
    +
    +	if ((mp = dbm_get(*dbm_getint(2))) == NULL) {
    +		warnx("dbm_open(%s): Invalid offset of macros array", fname);
    +		goto fail;
    +	}
    +	if (be32toh(*mp) != MACRO_MAX) {
    +		warnx("dbm_open(%s): Invalid number of macros: %d",
    +		    fname, be32toh(*mp));
    +		goto fail;
    +	}
    +	for (im = 0; im < MACRO_MAX; im++) {
    +		if ((ep = dbm_get(*++mp)) == NULL) {
    +			warnx("dbm_open(%s): Invalid offset of macro %d",
    +			    fname, im);
    +			goto fail;
    +		}
    +		nvals[im] = be32toh(*ep);
    +		macros[im] = (struct macro *)++ep;
    +	}
    +	return 0;
    +
    +fail:
    +	dbm_unmap();
    +	errno = EFTYPE;
    +	return -1;
    +}
    +
    +void
    +dbm_close(void)
    +{
    +	dbm_unmap();
    +}
    +
    +
    +/*** functions for handling pages *************************************/
    +
    +int32_t
    +dbm_page_count(void)
    +{
    +	return npages;
    +}
    +
    +/*
    + * Give the caller pointers to the data for one manual page.
    + */
    +struct dbm_page *
    +dbm_page_get(int32_t ip)
    +{
    +	static struct dbm_page	 res;
    +
    +	assert(ip >= 0);
    +	assert(ip < npages);
    +	res.name = dbm_get(pages[ip].name);
    +	if (res.name == NULL)
    +		res.name = "(NULL)";
    +	res.sect = dbm_get(pages[ip].sect);
    +	if (res.sect == NULL)
    +		res.sect = "(NULL)";
    +	res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL;
    +	res.desc = dbm_get(pages[ip].desc);
    +	if (res.desc == NULL)
    +		res.desc = "(NULL)";
    +	res.file = dbm_get(pages[ip].file);
    +	if (res.file == NULL)
    +		res.file = " (NULL)";
    +	res.addr = dbm_addr(pages + ip);
    +	return &res;
    +}
    +
    +/*
    + * Functions to start filtered iterations over manual pages.
    + */
    +void
    +dbm_page_byname(const struct dbm_match *match)
    +{
    +	assert(match != NULL);
    +	page_bytitle(ITER_NAME, match);
    +}
    +
    +void
    +dbm_page_bysect(const struct dbm_match *match)
    +{
    +	assert(match != NULL);
    +	page_bytitle(ITER_SECT, match);
    +}
    +
    +void
    +dbm_page_byarch(const struct dbm_match *match)
    +{
    +	assert(match != NULL);
    +	page_byarch(match);
    +}
    +
    +void
    +dbm_page_bydesc(const struct dbm_match *match)
    +{
    +	assert(match != NULL);
    +	page_bytitle(ITER_DESC, match);
    +}
    +
    +void
    +dbm_page_bymacro(int32_t im, const struct dbm_match *match)
    +{
    +	assert(im >= 0);
    +	assert(im < MACRO_MAX);
    +	assert(match != NULL);
    +	page_bymacro(im, match);
    +}
    +
    +/*
    + * Return the number of the next manual page in the current iteration.
    + */
    +struct dbm_res
    +dbm_page_next(void)
    +{
    +	struct dbm_res			 res = {-1, 0};
    +
    +	switch(iteration) {
    +	case ITER_NONE:
    +		return res;
    +	case ITER_ARCH:
    +		return page_byarch(NULL);
    +	case ITER_MACRO:
    +		return page_bymacro(0, NULL);
    +	default:
    +		return page_bytitle(iteration, NULL);
    +	}
    +}
    +
    +/*
    + * Functions implementing the iteration over manual pages.
    + */
    +static struct dbm_res
    +page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match)
    +{
    +	static const struct dbm_match	*match;
    +	static const char		*cp;	
    +	static int32_t			 ip;
    +	struct dbm_res			 res = {-1, 0};
    +
    +	assert(arg_iter == ITER_NAME || arg_iter == ITER_DESC ||
    +	    arg_iter == ITER_SECT);
    +
    +	/* Initialize for a new iteration. */
    +
    +	if (arg_match != NULL) {
    +		iteration = arg_iter;
    +		match = arg_match;
    +		switch (iteration) {
    +		case ITER_NAME:
    +			cp = dbm_get(pages[0].name);
    +			break;
    +		case ITER_SECT:
    +			cp = dbm_get(pages[0].sect);
    +			break;
    +		case ITER_DESC:
    +			cp = dbm_get(pages[0].desc);
    +			break;
    +		default:
    +			abort();
    +		}
    +		if (cp == NULL) {
    +			iteration = ITER_NONE;
    +			match = NULL;
    +			cp = NULL;
    +			ip = npages;
    +		} else
    +			ip = 0;
    +		return res;
    +	}
    +
    +	/* Search for a name. */
    +
    +	while (ip < npages) {
    +		if (iteration == ITER_NAME)
    +			cp++;
    +		if (dbm_match(match, cp))
    +			break;
    +		cp = strchr(cp, '\0') + 1;
    +		if (iteration == ITER_DESC)
    +			ip++;
    +		else if (*cp == '\0') {
    +			cp++;
    +			ip++;
    +		}
    +	}
    +
    +	/* Reached the end without a match. */
    +
    +	if (ip == npages) {
    +		iteration = ITER_NONE;
    +		match = NULL;
    +		cp = NULL;
    +		return res;
    +	}
    +
    +	/* Found a match; save the quality for later retrieval. */
    +
    +	res.page = ip;
    +	res.bits = iteration == ITER_NAME ? cp[-1] : 0;
    +
    +	/* Skip the remaining names of this page. */
    +
    +	if (++ip < npages) {
    +		do {
    +			cp++;
    +		} while (cp[-1] != '\0' ||
    +		    (iteration != ITER_DESC && cp[-2] != '\0'));
    +	}
    +	return res;
    +}
    +
    +static struct dbm_res
    +page_byarch(const struct dbm_match *arg_match)
    +{
    +	static const struct dbm_match	*match;
    +	struct dbm_res			 res = {-1, 0};
    +	static int32_t			 ip;
    +	const char			*cp;	
    +
    +	/* Initialize for a new iteration. */
    +
    +	if (arg_match != NULL) {
    +		iteration = ITER_ARCH;
    +		match = arg_match;
    +		ip = 0;
    +		return res;
    +	}
    +
    +	/* Search for an architecture. */
    +
    +	for ( ; ip < npages; ip++)
    +		if (pages[ip].arch)
    +			for (cp = dbm_get(pages[ip].arch);
    +			    *cp != '\0';
    +			    cp = strchr(cp, '\0') + 1)
    +				if (dbm_match(match, cp)) {
    +					res.page = ip++;
    +					return res;
    +				}
    +
    +	/* Reached the end without a match. */
    +
    +	iteration = ITER_NONE;
    +	match = NULL;
    +	return res;
    +}
    +
    +static struct dbm_res
    +page_bymacro(int32_t arg_im, const struct dbm_match *arg_match)
    +{
    +	static const struct dbm_match	*match;
    +	static const int32_t		*pp;
    +	static const char		*cp;
    +	static int32_t			 im, iv;
    +	struct dbm_res			 res = {-1, 0};
    +
    +	assert(im >= 0);
    +	assert(im < MACRO_MAX);
    +
    +	/* Initialize for a new iteration. */
    +
    +	if (arg_match != NULL) {
    +		iteration = ITER_MACRO;
    +		match = arg_match;
    +		im = arg_im;
    +		cp = nvals[im] ? dbm_get(macros[im]->value) : NULL;
    +		pp = NULL;
    +		iv = -1;
    +		return res;
    +	}
    +	if (iteration != ITER_MACRO)
    +		return res;
    +
    +	/* Find the next matching macro value. */
    +
    +	while (pp == NULL || *pp == 0) {
    +		if (++iv == nvals[im]) {
    +			iteration = ITER_NONE;
    +			return res;
    +		}
    +		if (iv)
    +			cp = strchr(cp, '\0') + 1;
    +		if (dbm_match(match, cp))
    +			pp = dbm_get(macros[im][iv].pages);
    +	}
    +
    +	/* Found a matching page. */
    +
    +	res.page = (struct page *)dbm_get(*pp++) - pages;
    +	return res;
    +}
    +
    +
    +/*** functions for handling macros ************************************/
    +
    +int32_t
    +dbm_macro_count(int32_t im)
    +{
    +	assert(im >= 0);
    +	assert(im < MACRO_MAX);
    +	return nvals[im];
    +}
    +
    +struct dbm_macro *
    +dbm_macro_get(int32_t im, int32_t iv)
    +{
    +	static struct dbm_macro macro;
    +
    +	assert(im >= 0);
    +	assert(im < MACRO_MAX);
    +	assert(iv >= 0);
    +	assert(iv < nvals[im]);
    +	macro.value = dbm_get(macros[im][iv].value);
    +	macro.pp = dbm_get(macros[im][iv].pages);
    +	return ¯o;
    +}
    +
    +/*
    + * Filtered iteration over macro entries.
    + */
    +void
    +dbm_macro_bypage(int32_t im, int32_t ip)
    +{
    +	assert(im >= 0);
    +	assert(im < MACRO_MAX);
    +	assert(ip != 0);
    +	macro_bypage(im, ip);
    +}
    +
    +char *
    +dbm_macro_next(void)
    +{
    +	return macro_bypage(MACRO_MAX, 0);
    +}
    +
    +static char *
    +macro_bypage(int32_t arg_im, int32_t arg_ip)
    +{
    +	static const int32_t	*pp;
    +	static int32_t		 im, ip, iv;
    +
    +	/* Initialize for a new iteration. */
    +
    +	if (arg_im < MACRO_MAX && arg_ip != 0) {
    +		im = arg_im;
    +		ip = arg_ip;
    +		pp = dbm_get(macros[im]->pages);
    +		iv = 0;
    +		return NULL;
    +	}
    +	if (im >= MACRO_MAX)
    +		return NULL;
    +
    +	/* Search for the next value. */
    +
    +	while (iv < nvals[im]) {
    +		if (*pp == ip)
    +			break;
    +		if (*pp == 0)
    +			iv++;
    +		pp++;
    +	}
    +
    +	/* Reached the end without a match. */
    +
    +	if (iv == nvals[im]) {
    +		im = MACRO_MAX;
    +		ip = 0;
    +		pp = NULL;
    +		return NULL;
    +	}
    +
    +	/* Found a match; skip the remaining pages of this entry. */
    +
    +	if (++iv < nvals[im])
    +		while (*pp++ != 0)
    +			continue;
    +
    +	return dbm_get(macros[im][iv - 1].value);
    +}
    
    Property changes on: head/contrib/mandoc/dbm.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dbm.h
    ===================================================================
    --- head/contrib/mandoc/dbm.h	(nonexistent)
    +++ head/contrib/mandoc/dbm.h	(revision 338826)
    @@ -0,0 +1,68 @@
    +/*	$Id: dbm.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Public interface for the map-based version
    + * of the mandoc database, for read-only access.
    + * To be used by dbm*.c, dba_read.c, and man(1) and apropos(1).
    + */
    +
    +enum dbm_mtype {
    +	DBM_EXACT = 0,
    +	DBM_SUB,
    +	DBM_REGEX
    +};
    +
    +struct dbm_match {
    +	regex_t		*re;
    +	const char	*str;
    +	enum dbm_mtype	 type;
    +};
    +
    +struct dbm_res {
    +	int32_t		 page;
    +	int32_t		 bits;
    +};
    +
    +struct dbm_page {
    +	const char	*name;
    +	const char	*sect;
    +	const char	*arch;
    +	const char	*desc;
    +	const char	*file;
    +	int32_t		 addr;
    +};
    +
    +struct dbm_macro {
    +	const char	*value;
    +	const int32_t	*pp;
    +};
    +
    +int		 dbm_open(const char *);
    +void		 dbm_close(void);
    +
    +int32_t		 dbm_page_count(void);
    +struct dbm_page	*dbm_page_get(int32_t);
    +void		 dbm_page_byname(const struct dbm_match *);
    +void		 dbm_page_bysect(const struct dbm_match *);
    +void		 dbm_page_byarch(const struct dbm_match *);
    +void		 dbm_page_bydesc(const struct dbm_match *);
    +void		 dbm_page_bymacro(int32_t, const struct dbm_match *);
    +struct dbm_res	 dbm_page_next(void);
    +
    +int32_t		 dbm_macro_count(int32_t);
    +struct dbm_macro *dbm_macro_get(int32_t, int32_t);
    +void		 dbm_macro_bypage(int32_t, int32_t);
    +char		*dbm_macro_next(void);
    
    Property changes on: head/contrib/mandoc/dbm.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/dbm_map.h
    ===================================================================
    --- head/contrib/mandoc/dbm_map.h	(nonexistent)
    +++ head/contrib/mandoc/dbm_map.h	(revision 338826)
    @@ -0,0 +1,29 @@
    +/*	$Id: dbm_map.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
    +/*
    + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * Private interface for low-level routines for the map-based version 
    + * of the mandoc database, for read-only access.
    + * To be used by dbm*.c only.
    + */
    +
    +struct dbm_match;
    +
    +int		 dbm_map(const char *);
    +void		 dbm_unmap(void);
    +void		*dbm_get(int32_t);
    +int32_t		*dbm_getint(int32_t);
    +int32_t		 dbm_addr(const void *);
    +int		 dbm_match(const struct dbm_match *, const char *);
    
    Property changes on: head/contrib/mandoc/dbm_map.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc.db.5
    ===================================================================
    --- head/contrib/mandoc/mandoc.db.5	(nonexistent)
    +++ head/contrib/mandoc/mandoc.db.5	(revision 338826)
    @@ -0,0 +1,228 @@
    +.\"	$Id: mandoc.db.5,v 1.5 2016/08/01 12:27:15 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2014, 2016 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: August 1 2016 $
    +.Dt MANDOC.DB 5
    +.Os
    +.Sh NAME
    +.Nm mandoc.db
    +.Nd manual page database
    +.Sh DESCRIPTION
    +The
    +.Nm
    +file format is used to store information about installed manual
    +pages to facilitate semantic searching for manuals.
    +Each manual page tree contains its own
    +.Nm
    +file; see
    +.Sx FILES
    +for examples.
    +.Pp
    +Such database files are generated by
    +.Xr makewhatis 8
    +and used by
    +.Xr man 1 ,
    +.Xr apropos 1
    +and
    +.Xr whatis 1 .
    +.Pp
    +The file format uses three datatypes:
    +.Pp
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +32-bit signed integer numbers in big endian (network) byte ordering
    +.It
    +NUL-terminated strings
    +.It
    +lists of NUL-terminated strings, terminated by a second NUL character
    +.El
    +.Pp
    +Numbers are aligned to four-byte boundaries; where they follow
    +strings or lists of strings, padding with additional NUL characters
    +occurs.
    +Some, but not all, numbers point to positions in the file.
    +These pointers are measured in bytes, and the first byte of the
    +file is considered to be byte 0.
    +.Pp
    +Each file consists of:
    +.Pp
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +One magic number, 0x3a7d0cdb.
    +.It
    +One version number, currently 1.
    +.It
    +One pointer to the macros table.
    +.It
    +One pointer to the final magic number.
    +.It
    +The pages table (variable length).
    +.It
    +The macros table (variable length).
    +.It
    +The magic number once again, 0x3a7d0cdb.
    +.El
    +.Pp
    +The pages table contains one entry for each physical manual page
    +file, no matter how many hard and soft links it may have in the
    +file system.
    +The pages table consists of:
    +.Pp
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +The number of pages in the database.
    +.It
    +For each page:
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +One pointer to the list of names.
    +.It
    +One pointer to the list of sections.
    +.It
    +One pointer to the list of architectures
    +or 0 if the page is machine-independent.
    +.It
    +One pointer to the one-line description string.
    +.It
    +One pointer to the list of filenames.
    +.El
    +.It
    +For each page, the list of names.
    +Each name is preceded by a single byte indicating the sources of the name.
    +The meaning of the bits is:
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +0x10: The name appears in a filename.
    +.It
    +0x08: The name appears in a header line, i.e. in a .Dt or .TH macro.
    +.It
    +0x04: The name is the first one in the title line, i.e. it appears
    +in the first .Nm macro in the NAME section.
    +.It
    +0x02: The name appears in any .Nm macro in the NAME section.
    +.It
    +0x01: The name appears in an .Nm block in the SYNOPSIS section.
    +.El
    +.It
    +For each page, the list of sections.
    +Each section is given as a string, not as a number.
    +.It
    +For each architecture-dependent page, the list of architectures.
    +.It
    +For each page, the one-line description string taken from the .Nd macro.
    +.It
    +For each page, the list of filenames relative to the root of the
    +respective manpath.
    +This list includes hard links, soft links, and links simulated
    +with .so
    +.Xr roff 7
    +requests.
    +The first filename is preceded by a single byte
    +having the following significance:
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +.Dv FORM_SRC No = 0x01 :
    +The file format is
    +.Xr mdoc 7
    +or
    +.Xr man 7 .
    +.It
    +.Dv FORM_CAT No = 0x02 :
    +The manual page is preformatted.
    +.El
    +.It
    +Zero to three NUL bytes for padding.
    +.El
    +.Pp
    +The macros table consists of:
    +.Pp
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +The number of different macro keys, currently 36.
    +The ordering of macros is defined in
    +.In mansearch.h
    +and the significance of the macro keys is documented in
    +.Xr apropos 1 .
    +.It
    +For each macro key, one pointer to the respective macro table.
    +.It
    +For each macro key, the macro table (variable length).
    +.El
    +.Pp
    +Each macro table consists of:
    +.Pp
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +The number of entries in the table.
    +.It
    +For each entry:
    +.Bl -dash -compact -offset 2n -width 1n
    +.It
    +One pointer to the value of the macro key.
    +Each value is a string of text taken from some macro invocation.
    +.It
    +One pointer to the list of pages.
    +.El
    +.It
    +For each entry, the value of the macro key.
    +.It
    +Zero to three NUL bytes for padding.
    +.It
    +For each entry, one or more pointers to pages in the pages table,
    +pointing to the pointer to the list of names,
    +followed by the number 0.
    +.El
    +.Sh FILES
    +.Bl -tag -width /usr/share/man/mandoc.db -compact
    +.It Pa /usr/share/man/mandoc.db
    +The manual page database for the base system.
    +.It Pa /usr/X11R6/man/mandoc.db
    +The same for the
    +.Xr X 7
    +Window System.
    +.It Pa /usr/local/man/mandoc.db
    +The same for
    +.Xr packages 7 .
    +.El
    +.Pp
    +A program to dump
    +.Nm
    +files in a human-readable format suitable for
    +.Xr diff 1
    +is provided in the directory
    +.Pa /usr/src/regress/usr.bin/mandoc/db/dbm_dump/ .
    +.Sh SEE ALSO
    +.Xr apropos 1 ,
    +.Xr man 1 ,
    +.Xr whatis 1 ,
    +.Xr makewhatis 8
    +.Sh HISTORY
    +A manual page database
    +.Pa /usr/lib/whatis
    +first appeared in
    +.Bx 2 .
    +The present format first appeared in
    +.Ox 6.1 .
    +.Sh AUTHORS
    +.An -nosplit
    +The original version of
    +.Xr makewhatis 8
    +was written by
    +.An Bill Joy
    +in 1979.
    +The present database format was designed by
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org
    +in 2016.
    
    Property changes on: head/contrib/mandoc/mandoc.db.5
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-EFTYPE.c
    ===================================================================
    --- head/contrib/mandoc/test-EFTYPE.c	(nonexistent)
    +++ head/contrib/mandoc/test-EFTYPE.c	(revision 338826)
    @@ -0,0 +1,7 @@
    +#include <errno.h>
    +
    +int
    +main(void)
    +{
    +	return !EFTYPE;
    +}
    
    Property changes on: head/contrib/mandoc/test-EFTYPE.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-PATH_MAX.c
    ===================================================================
    --- head/contrib/mandoc/test-PATH_MAX.c	(nonexistent)
    +++ head/contrib/mandoc/test-PATH_MAX.c	(revision 338826)
    @@ -0,0 +1,30 @@
    +/*
    + * POSIX allows PATH_MAX to not be defined, see
    + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html;
    + * the GNU Hurd is an example of a system not having it.
    + *
    + * Arguably, it would be better to test sysconf(_SC_PATH_MAX),
    + * but since the individual *.c files include "config.h" before
    + * <limits.h>, overriding an excessive value of PATH_MAX from
    + * "config.h" is impossible anyway, so for now, the simplest
    + * fix is to provide a value only on systems not having any.
    + * So far, we encountered no system defining PATH_MAX to an
    + * impractically large value, even though POSIX explicitly
    + * allows that.
    + *
    + * The real fix would be to replace all static buffers of size
    + * PATH_MAX by dynamically allocated buffers.  But that is
    + * somewhat intrusive because it touches several files and
    + * because it requires changing struct mlink in mandocdb.c.
    + * So i'm postponing that for now.
    + */
    +
    +#include <limits.h>
    +#include <stdio.h>
    +
    +int
    +main(void)
    +{
    +	printf("PATH_MAX is defined to be %ld\n", (long)PATH_MAX);
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-PATH_MAX.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-be32toh.c
    ===================================================================
    --- head/contrib/mandoc/test-be32toh.c	(nonexistent)
    +++ head/contrib/mandoc/test-be32toh.c	(revision 338826)
    @@ -0,0 +1,11 @@
    +#ifdef SYS_ENDIAN
    +#include <sys/endian.h>
    +#else
    +#include <endian.h>
    +#endif
    +
    +int
    +main(void)
    +{
    +	return htobe32(be32toh(0x3a7d0cdb)) != 0x3a7d0cdb;
    +}
    
    Property changes on: head/contrib/mandoc/test-be32toh.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-fts.c
    ===================================================================
    --- head/contrib/mandoc/test-fts.c	(nonexistent)
    +++ head/contrib/mandoc/test-fts.c	(revision 338826)
    @@ -0,0 +1,59 @@
    +#include <sys/types.h>
    +#include <sys/stat.h>
    +#include <fts.h>
    +#include <stdio.h>
    +#include <string.h>
    +
    +#ifdef FTS_COMPARE_CONST
    +int fts_compare(const FTSENT *const *, const FTSENT *const *);
    +#else
    +int fts_compare(const FTSENT **, const FTSENT **);
    +#endif
    +
    +int
    +main(void)
    +{
    +	const char	*argv[2];
    +	FTS		*ftsp;
    +	FTSENT		*entry;
    +
    +	argv[0] = ".";
    +	argv[1] = (char *)NULL;
    +
    +	ftsp = fts_open((char * const *)argv,
    +	    FTS_PHYSICAL | FTS_NOCHDIR, fts_compare);
    +
    +	if (ftsp == NULL) {
    +		perror("fts_open");
    +		return 1;
    +	}
    +
    +	entry = fts_read(ftsp);
    +
    +	if (entry == NULL) {
    +		perror("fts_read");
    +		return 1;
    +	}
    +
    +	if (fts_set(ftsp, entry, FTS_SKIP) != 0) {
    +		perror("fts_set");
    +		return 1;
    +	}
    +
    +	if (fts_close(ftsp) != 0) {
    +		perror("fts_close");
    +		return 1;
    +	}
    +
    +	return 0;
    +}
    +
    +int
    +#ifdef FTS_COMPARE_CONST
    +fts_compare(const FTSENT *const *a, const FTSENT *const *b)
    +#else
    +fts_compare(const FTSENT **a, const FTSENT **b)
    +#endif
    +{
    +	return strcmp((*a)->fts_name, (*b)->fts_name);
    +}
    
    Property changes on: head/contrib/mandoc/test-fts.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-nanosleep.c
    ===================================================================
    --- head/contrib/mandoc/test-nanosleep.c	(nonexistent)
    +++ head/contrib/mandoc/test-nanosleep.c	(revision 338826)
    @@ -0,0 +1,17 @@
    +#include <stdio.h>
    +#include <time.h>
    +
    +int
    +main(void)
    +{
    +	struct timespec	 timeout;
    +
    +	timeout.tv_sec = 0;
    +	timeout.tv_nsec = 100000000;	/* 0.1 seconds */
    +	
    +	if (nanosleep(&timeout, NULL)) {
    +		perror("nanosleep");
    +		return 1;
    +	}
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-nanosleep.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-ntohl.c
    ===================================================================
    --- head/contrib/mandoc/test-ntohl.c	(nonexistent)
    +++ head/contrib/mandoc/test-ntohl.c	(revision 338826)
    @@ -0,0 +1,7 @@
    +#include <arpa/inet.h>
    +
    +int
    +main(void)
    +{
    +	return htonl(ntohl(0x3a7d0cdb)) != 0x3a7d0cdb;
    +}
    
    Property changes on: head/contrib/mandoc/test-ntohl.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-ohash.c
    ===================================================================
    --- head/contrib/mandoc/test-ohash.c	(nonexistent)
    +++ head/contrib/mandoc/test-ohash.c	(revision 338826)
    @@ -0,0 +1,39 @@
    +#include <stdint.h>
    +#include <stddef.h>
    +#include <stdlib.h>
    +#include <ohash.h>
    +
    +static void	*xmalloc(size_t, void *);
    +static void	*xcalloc(size_t, size_t, void *);
    +static void	 xfree(void *, void *);
    +
    +
    +static void *
    +xmalloc(size_t sz, void *arg) {
    +	return calloc(1,sz);
    +}
    +
    +static void *
    +xcalloc(size_t nmemb, size_t sz, void *arg)
    +{
    +	return calloc(nmemb,sz);
    +}
    +
    +static void
    +xfree(void *p, void *arg)
    +{
    +	free(p);
    +}
    +
    +int
    +main(void)
    +{
    +	struct ohash h;
    +	struct ohash_info i;
    +	i.alloc = xmalloc;
    +	i.calloc = xcalloc;
    +	i.free = xfree;
    +	ohash_init(&h, 2, &i);
    +	ohash_delete(&h);
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-ohash.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-sandbox_init.c
    ===================================================================
    --- head/contrib/mandoc/test-sandbox_init.c	(nonexistent)
    +++ head/contrib/mandoc/test-sandbox_init.c	(revision 338826)
    @@ -0,0 +1,13 @@
    +#include <sandbox.h>
    +
    +int
    +main(void)
    +{
    +	char	*ep;
    +	int	 rc;
    +
    +	rc = sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, &ep);
    +	if (-1 == rc)
    +		sandbox_free_error(ep);
    +	return(-1 == rc);
    +}
    
    Property changes on: head/contrib/mandoc/test-sandbox_init.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-vasprintf.c
    ===================================================================
    --- head/contrib/mandoc/test-vasprintf.c	(nonexistent)
    +++ head/contrib/mandoc/test-vasprintf.c	(revision 338826)
    @@ -0,0 +1,52 @@
    +/*	$Id: test-vasprintf.c,v 1.4 2016/07/18 18:35:05 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#if defined(__linux__) || defined(__MINT__)
    +#define _GNU_SOURCE /* vasprintf() */
    +#endif
    +
    +#include <stdarg.h>
    +#include <stdio.h>
    +#include <string.h>
    +
    +static int	 testfunc(char **, const char *, ...);
    +
    +
    +static int
    +testfunc(char **ret, const char *format, ...)
    +{
    +	va_list	 ap;
    +	int	 irc;
    +
    +	va_start(ap, format);
    +	irc = vasprintf(ret, format, ap);
    +	va_end(ap);
    +
    +	return irc;
    +}
    +
    +int
    +main(void)
    +{
    +	char	*ret;
    +
    +	if (testfunc(&ret, "%s.", "Text") != 5)
    +		return 1;
    +	if (strcmp(ret, "Text."))
    +		return 2;
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-vasprintf.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-wchar.c
    ===================================================================
    --- head/contrib/mandoc/test-wchar.c	(nonexistent)
    +++ head/contrib/mandoc/test-wchar.c	(revision 338826)
    @@ -0,0 +1,63 @@
    +/*	$Id: test-wchar.c,v 1.4 2016/07/31 09:29:13 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#if defined(__linux__) || defined(__MINT__)
    +#define _GNU_SOURCE /* wcwidth() */
    +#endif
    +
    +#include <locale.h>
    +#include <stdio.h>
    +#include <wchar.h>
    +#include <unistd.h>
    +
    +int
    +main(void)
    +{
    +	wchar_t	 wc;
    +	int	 width;
    +
    +	if (setlocale(LC_ALL, "") == NULL) {
    +		fputs("setlocale(LC_ALL, \"\") failed\n", stderr);
    +		return 1;
    +	}
    +
    +	if (setlocale(LC_CTYPE, UTF8_LOCALE) == NULL) {
    +		fprintf(stderr, "setlocale(LC_CTYPE, \"%s\") failed\n",
    +		    UTF8_LOCALE);
    +		return 1;
    +	}
    +
    +	if (sizeof(wchar_t) < 4) {
    +		fprintf(stderr, "wchar_t is only %zu bytes\n",
    +		    sizeof(wchar_t));
    +		return 1;
    +	}
    +
    +	if ((width = wcwidth(L' ')) != 1) {
    +		fprintf(stderr, "wcwidth(L' ') returned %d\n", width);
    +		return 1;
    +	}
    +
    +	dup2(STDERR_FILENO, STDOUT_FILENO);
    +	wc = L'*';
    +	if (putwchar(wc) != (wint_t)wc) {
    +		fputs("bad putwchar return value\n", stderr);
    +		return 1;
    +	}
    +
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-wchar.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_malloc.3
    ===================================================================
    --- head/contrib/mandoc/mandoc_malloc.3	(nonexistent)
    +++ head/contrib/mandoc/mandoc_malloc.3	(revision 338826)
    @@ -0,0 +1,191 @@
    +.\"	$Id: mandoc_malloc.3,v 1.2 2016/07/07 19:19:01 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: July 7 2016 $
    +.Dt MANDOC_MALLOC 3
    +.Os
    +.Sh NAME
    +.Nm mandoc_malloc ,
    +.Nm mandoc_realloc ,
    +.Nm mandoc_reallocarray ,
    +.Nm mandoc_calloc ,
    +.Nm mandoc_strdup ,
    +.Nm mandoc_strndup ,
    +.Nm mandoc_asprintf
    +.Nd memory allocation function wrappers used in the mandoc library
    +.Sh SYNOPSIS
    +.In sys/types.h
    +.In mandoc_aux.h
    +.Ft "void *"
    +.Fo mandoc_malloc
    +.Fa "size_t size"
    +.Fc
    +.Ft "void *"
    +.Fo mandoc_realloc
    +.Fa "void *ptr"
    +.Fa "size_t size"
    +.Fc
    +.Ft "void *"
    +.Fo mandoc_reallocarray
    +.Fa "void *ptr"
    +.Fa "size_t nmemb"
    +.Fa "size_t size"
    +.Fc
    +.Ft "void *"
    +.Fo mandoc_calloc
    +.Fa "size_t nmemb"
    +.Fa "size_t size"
    +.Fc
    +.Ft "char *"
    +.Fo mandoc_strdup
    +.Fa "const char *s"
    +.Fc
    +.Ft "char *"
    +.Fo mandoc_strndup
    +.Fa "const char *s"
    +.Fa "size_t maxlen"
    +.Fc
    +.Ft int
    +.Fo mandoc_asprintf
    +.Fa "char **ret"
    +.Fa "const char *format"
    +.Fa "..."
    +.Fc
    +.Sh DESCRIPTION
    +These functions call the libc functions of the same names, passing
    +through their return values when successful.
    +In case of failure, they do not return, but instead call
    +.Xr err 3 .
    +They can be used both internally by any code in the mandoc libraries
    +and externally by programs using that library, for example
    +.Xr mandoc 1 ,
    +.Xr man 1 ,
    +.Xr apropos 1 ,
    +.Xr makewhatis 8 ,
    +and
    +.Xr man.cgi 8 .
    +.Pp
    +The function
    +.Fn mandoc_malloc
    +allocates one new object, leaving the memory uninitialized.
    +The functions
    +.Fn mandoc_realloc
    +and
    +.Fn mandoc_reallocarray
    +change the size of an existing object or array, possibly moving it.
    +When shrinking the size, existing data is truncated; when growing,
    +the additional memory is not initialized.
    +The function
    +.Fn mandoc_calloc
    +allocates a new array, initializing it to zero.
    +.Pp
    +The argument
    +.Fa size
    +is the size of each object.
    +The argument
    +.Fa nmemb
    +is the new number of objects in the array.
    +The argument
    +.Fa ptr
    +is a pointer to the existing object or array to be resized; if it is
    +.Dv NULL ,
    +a new object or array is allocated.
    +.Pp
    +The functions
    +.Fn mandoc_strdup
    +and
    +.Fn mandoc_strndup
    +copy a string into newly allocated memory.
    +For
    +.Fn mandoc_strdup ,
    +the string pointed to by
    +.Fa s
    +needs to be NUL-terminated.
    +For
    +.Fn mandoc_strndup ,
    +at most
    +.Fa maxlen
    +bytes are copied.
    +The function
    +.Fn mandoc_asprintf
    +writes output formatted according to
    +.Fa format
    +into newly allocated memory and returns a pointer to the result in
    +.Fa ret .
    +For all three string functions, the result is always NUL-terminated.
    +.Pp
    +When the objects and strings are no longer needed,
    +the pointers returned by these functions can be passed to
    +.Xr free 3 .
    +.Sh RETURN VALUES
    +The function
    +.Fn mandoc_asprintf
    +always returns the number of characters written, excluding the
    +final NUL byte.
    +It never returns -1.
    +.Pp
    +The other functions always return a valid pointer; they never return
    +.Dv NULL .
    +.Sh FILES
    +These functions are implemented in
    +.Pa mandoc_aux.c .
    +.Sh SEE ALSO
    +.Xr asprintf 3 ,
    +.Xr err 3 ,
    +.Xr malloc 3 ,
    +.Xr strdup 3
    +.Sh STANDARDS
    +The functions
    +.Fn malloc ,
    +.Fn realloc ,
    +and
    +.Fn calloc
    +are required by
    +.St -ansiC .
    +The functions
    +.Fn strdup
    +and
    +.Fn strndup
    +are required by
    +.St -p1003.1-2008 .
    +The function
    +.Fn asprintf
    +is a widespread extension that first appeared in the GNU C library.
    +.Pp
    +The function
    +.Fn reallocarray
    +is an extension that first appeared in
    +.Ox 5.6 .
    +If it is not provided by the operating system, the mandoc build system
    +uses a bundled portable implementation.
    +.Sh HISTORY
    +The functions
    +.Fn mandoc_malloc ,
    +.Fn mandoc_realloc ,
    +.Fn mandoc_calloc ,
    +and
    +.Fn mandoc_strdup
    +have been available since mandoc 1.9.12,
    +.Fn mandoc_strndup
    +since 1.11.5,
    +and
    +.Fn mandoc_asprintf
    +and
    +.Fn mandoc_reallocarray
    +since 1.12.4 and 1.13.0.
    +.Sh AUTHORS
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org
    
    Property changes on: head/contrib/mandoc/mandoc_malloc.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mchars_alloc.3
    ===================================================================
    --- head/contrib/mandoc/mchars_alloc.3	(nonexistent)
    +++ head/contrib/mandoc/mchars_alloc.3	(revision 338826)
    @@ -0,0 +1,227 @@
    +.\"	$Id: mchars_alloc.3,v 1.4 2016/07/07 19:19:01 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: July 7 2016 $
    +.Dt MCHARS_ALLOC 3
    +.Os
    +.Sh NAME
    +.Nm mchars_alloc ,
    +.Nm mchars_free ,
    +.Nm mchars_num2char ,
    +.Nm mchars_num2uc ,
    +.Nm mchars_spec2cp ,
    +.Nm mchars_spec2str ,
    +.Nm mchars_uc2str
    +.Nd character table for mandoc
    +.Sh SYNOPSIS
    +.In sys/types.h
    +.In mandoc.h
    +.Ft void
    +.Fn mchars_alloc void
    +.Ft void
    +.Fn mchars_free void
    +.Ft char
    +.Fo mchars_num2char
    +.Fa "const char *decimal"
    +.Fa "size_t sz"
    +.Fc
    +.Ft int
    +.Fo mchars_num2uc
    +.Fa "const char *hexadecimal"
    +.Fa "size_t sz"
    +.Fc
    +.Ft int
    +.Fo mchars_spec2cp
    +.Fa "const char *name"
    +.Fa "size_t sz"
    +.Fc
    +.Ft "const char *"
    +.Fo mchars_spec2str
    +.Fa "const char *name"
    +.Fa "size_t sz"
    +.Fa "size_t *rsz"
    +.Fc
    +.Ft "const char *"
    +.Fn mchars_uc2str "int codepoint"
    +.Sh DESCRIPTION
    +These functions translate Unicode character numbers and
    +.Xr roff 7
    +character names into glyphs.
    +See
    +.Xr mandoc_char 7
    +for a list of
    +.Xr roff 7
    +special characters.
    +These functions are intended for external use by programs formatting
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +pages for output, for example the
    +.Xr mandoc 1
    +output formatter modules and
    +.Xr makewhatis 8 .
    +The
    +.Fa decimal ,
    +.Fa hexadecimal ,
    +.Fa name ,
    +and
    +.Fa size
    +input arguments are usually obtained from the
    +.Xr mandoc_escape 3
    +parser function.
    +.Pp
    +The function
    +.Fn mchars_num2char
    +converts a
    +.Fa decimal
    +string representation of a character number consisting of
    +.Fa sz
    +digits into a printable ASCII character.
    +If the input string is non-numeric or does not represent a printable
    +ASCII character, the NUL character
    +.Pq Sq \e0
    +is returned.
    +For example, the
    +.Xr mandoc 1
    +.Fl Tascii ,
    +.Fl Tutf8 ,
    +and
    +.Fl Thtml
    +output modules use this function to render
    +.Xr roff 7
    +.Ic \eN
    +escape sequences.
    +.Pp
    +The function
    +.Fn mchars_num2uc
    +converts a
    +.Fa hexadecimal
    +string representation of a Unicode codepoint consisting of
    +.Fa sz
    +digits into an integer representation.
    +If the input string is non-numeric or represents an ASCII character,
    +the NUL character
    +.Pq Sq \e0
    +is returned.
    +For example, the
    +.Xr mandoc 1
    +.Fl Tutf8
    +and
    +.Fl Thtml
    +output modules use this function to render
    +.Xr roff 7
    +.Ic \e[u Ns Ar XXXX Ns Ic \&]
    +and
    +.Ic \eC\(aqu Ns Ar XXXX Ns Ic \(aq
    +escape sequences.
    +.Pp
    +The function
    +.Fn mchars_alloc
    +initializes a static
    +.Vt "struct ohash"
    +object for subsequent use by the following two lookup functions.
    +When no longer needed, this object can be destroyed with
    +.Fn mchars_free .
    +.Pp
    +The function
    +.Fn mchars_spec2cp
    +looks up a
    +.Xr roff 7
    +special character
    +.Fa name
    +consisting of
    +.Fa sz
    +characters and returns the corresponding Unicode codepoint.
    +If the
    +.Ar name
    +is not recognized, \-1 is returned.
    +For example, the
    +.Xr mandoc 1
    +.Fl Tutf8
    +and
    +.Fl Thtml
    +output modules use this function to render
    +.Xr roff 7
    +.Ic \e[ Ns Ar name Ns Ic \&]
    +and
    +.Ic \eC\(aq Ns Ar name Ns Ic \(aq
    +escape sequences.
    +.Pp
    +The function
    +.Fn mchars_spec2str
    +looks up a
    +.Xr roff 7
    +special character
    +.Fa name
    +consisting of
    +.Fa sz
    +characters and returns an ASCII string representation.
    +The length of the representation is returned in
    +.Fa rsz .
    +In many cases, the meaning of such ASCII representations
    +is not quite obvious, so using
    +.Xr roff 7
    +special characters in documents intended for ASCII rendering
    +is usually a bad idea.
    +If the
    +.Ar name
    +is not recognized,
    +.Dv NULL
    +is returned.
    +For example,
    +.Xr makewhatis 8
    +and the
    +.Xr mandoc 1
    +.Fl Tascii
    +output module use this function to render
    +.Xr roff 7
    +.Ic \e[ Ns Ar name Ns Ic \&]
    +and
    +.Ic \eC\(aq Ns Ar name Ns Ic \(aq
    +escape sequences.
    +.Pp
    +The function
    +.Fn mchars_uc2str
    +performs a reverse lookup of the Unicode
    +.Fa codepoint
    +and returns an ASCII string representation, or the string
    +.Qq <?>
    +if none is available.
    +.Sh FILES
    +These funtions are implemented in the file
    +.Pa chars.c .
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr mandoc_escape 3 ,
    +.Xr ohash_init 3 ,
    +.Xr mandoc_char 7 ,
    +.Xr roff 7
    +.Sh HISTORY
    +These functions and their predecessors have been available since the
    +following mandoc versions:
    +.Bl -column "mchars_num2char()" "1.11.3" "chars_num2char()" "1.10.10"
    +.It Sy function Ta since Ta Sy predecessor Ta since
    +.It Fn mchars_alloc Ta 1.11.3 Ta Fn ascii2htab Ta 1.5.3
    +.It Fn mchars_free Ta 1.11.2 Ta Fn asciifree Ta 1.6.0
    +.It Fn mchars_num2char Ta 1.11.2 Ta Fn chars_num2char Ta 1.10.10
    +.It Fn mchars_num2uc Ta 1.11.3 Ta \(em Ta \(em
    +.It Fn mchars_spec2cp Ta 1.11.2 Ta Fn chars_spec2cp Ta 1.10.5
    +.It Fn mchars_spec2str Ta 1.11.2 Ta Fn a2ascii Ta 1.5.3
    +.It Fn mchars_uc2str Ta 1.13.2 Ta \(em Ta \(em
    +.El
    +.Sh AUTHORS
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org
    
    Property changes on: head/contrib/mandoc/mchars_alloc.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-rewb-bsd.c
    ===================================================================
    --- head/contrib/mandoc/test-rewb-bsd.c	(nonexistent)
    +++ head/contrib/mandoc/test-rewb-bsd.c	(revision 338826)
    @@ -0,0 +1,27 @@
    +#include <sys/types.h>
    +#include <stddef.h>
    +#include <regex.h>
    +
    +int
    +main(void)
    +{
    +	regex_t	 re;
    +
    +	if (regcomp(&re, "[[:<:]]word[[:>:]]", REG_EXTENDED | REG_NOSUB))
    +		return 1;
    +	if (regexec(&re, "the word is here", 0, NULL, 0))
    +		return 2;
    +	if (regexec(&re, "same word", 0, NULL, 0))
    +		return 3;
    +	if (regexec(&re, "word again", 0, NULL, 0))
    +		return 4;
    +	if (regexec(&re, "word", 0, NULL, 0))
    +		return 5;
    +	if (regexec(&re, "wordy", 0, NULL, 0) != REG_NOMATCH)
    +		return 6;
    +	if (regexec(&re, "sword", 0, NULL, 0) != REG_NOMATCH)
    +		return 7;
    +	if (regexec(&re, "reworded", 0, NULL, 0) != REG_NOMATCH)
    +		return 8;
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-rewb-bsd.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-rewb-sysv.c
    ===================================================================
    --- head/contrib/mandoc/test-rewb-sysv.c	(nonexistent)
    +++ head/contrib/mandoc/test-rewb-sysv.c	(revision 338826)
    @@ -0,0 +1,27 @@
    +#include <sys/types.h>
    +#include <stddef.h>
    +#include <regex.h>
    +
    +int
    +main(void)
    +{
    +	regex_t	 re;
    +
    +	if (regcomp(&re, "\\<word\\>", REG_EXTENDED | REG_NOSUB))
    +		return 1;
    +	if (regexec(&re, "the word is here", 0, NULL, 0))
    +		return 2;
    +	if (regexec(&re, "same word", 0, NULL, 0))
    +		return 3;
    +	if (regexec(&re, "word again", 0, NULL, 0))
    +		return 4;
    +	if (regexec(&re, "word", 0, NULL, 0))
    +		return 5;
    +	if (regexec(&re, "wordy", 0, NULL, 0) != REG_NOMATCH)
    +		return 6;
    +	if (regexec(&re, "sword", 0, NULL, 0) != REG_NOMATCH)
    +		return 7;
    +	if (regexec(&re, "reworded", 0, NULL, 0) != REG_NOMATCH)
    +		return 8;
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-rewb-sysv.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_err.c
    ===================================================================
    --- head/contrib/mandoc/compat_err.c	(nonexistent)
    +++ head/contrib/mandoc/compat_err.c	(revision 338826)
    @@ -0,0 +1,112 @@
    +#include "config.h"
    +
    +#if HAVE_ERR
    +
    +int dummy;
    +
    +#else
    +
    +/* $Id: compat_err.c,v 1.4 2015/11/26 07:42:11 schwarze Exp $ */
    +/*
    + * Copyright (c) 1993
    + *      The Regents of the University of California.  All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. Neither the name of the University nor the names of its contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + */
    +
    +#include <errno.h>
    +#include <stdarg.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +static void vwarni(const char *, va_list);
    +static void vwarnxi(const char *, va_list);
    +
    +static void
    +vwarnxi(const char *fmt, va_list ap)
    +{
    +	fprintf(stderr, "%s: ", getprogname());
    +	if (fmt != NULL)
    +		vfprintf(stderr, fmt, ap);
    +}
    +
    +static void
    +vwarni(const char *fmt, va_list ap)
    +{
    +	int sverrno;
    +
    +	sverrno = errno;
    +	vwarnxi(fmt, ap);
    +	if (fmt != NULL)
    +		fputs(": ", stderr);
    +	fprintf(stderr, "%s\n", strerror(sverrno));
    +}
    +
    +void
    +err(int eval, const char *fmt, ...)
    +{
    +	va_list ap;
    +
    +	va_start(ap, fmt);
    +	vwarni(fmt, ap);
    +	va_end(ap);
    +	exit(eval);
    +}
    +
    +void
    +errx(int eval, const char *fmt, ...)
    +{
    +	va_list ap;
    +
    +	va_start(ap, fmt);
    +	vwarnxi(fmt, ap);
    +	va_end(ap);
    +	fputc('\n', stderr);
    +	exit(eval);
    +}
    +
    +void
    +warn(const char *fmt, ...)
    +{
    +	va_list ap;
    +
    +	va_start(ap, fmt);
    +	vwarni(fmt, ap);
    +	va_end(ap);
    +}
    +
    +void
    +warnx(const char *fmt, ...)
    +{
    +	va_list ap;
    +
    +	va_start(ap, fmt);
    +	vwarnxi(fmt, ap);
    +	va_end(ap);
    +	fputc('\n', stderr);
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_err.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_getline.c
    ===================================================================
    --- head/contrib/mandoc/compat_getline.c	(nonexistent)
    +++ head/contrib/mandoc/compat_getline.c	(revision 338826)
    @@ -0,0 +1,68 @@
    +#include "config.h"
    +
    +#if HAVE_GETLINE
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_getline.c,v 1.1 2015/11/07 20:52:52 schwarze Exp $ */
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#include <sys/types.h>
    +#include <errno.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +
    +ssize_t
    +getline(char **buf, size_t *bufsz, FILE *fp)
    +{
    +	char	*nbuf;
    +	size_t	 nbufsz, pos;
    +	int	 c;
    +
    +	if (buf == NULL || bufsz == NULL) {
    +		errno = EINVAL;
    +		return -1;
    +	}
    +
    +	if (*buf == NULL)
    +		*bufsz = 0;
    +	else
    +		**buf = '\0';
    +
    +	pos = 0;
    +	for (;;) {
    +		if (pos + 1 >= *bufsz) {
    +			nbufsz = *bufsz ? *bufsz * 2 : BUFSIZ;
    +			if ((nbuf = realloc(*buf, nbufsz)) == NULL)
    +				return -1;
    +			*buf = nbuf;
    +			*bufsz = nbufsz;
    +		}
    +		if ((c = fgetc(fp)) == EOF) {
    +			(*buf)[pos] = '\0';
    +			return pos > 0 && feof(fp) ? (ssize_t)pos : -1;
    +		}
    +		(*buf)[pos++] = c;
    +		(*buf)[pos] = '\0';
    +		if (c == '\n')
    +			return pos;
    +	}
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_getline.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_isblank.c
    ===================================================================
    --- head/contrib/mandoc/compat_isblank.c	(nonexistent)
    +++ head/contrib/mandoc/compat_isblank.c	(revision 338826)
    @@ -0,0 +1,33 @@
    +#include "config.h"
    +
    +#if HAVE_ISBLANK
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_isblank.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +int
    +isblank(int c)
    +{
    +
    +	return c == ' ' || c == '\t';
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_isblank.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_mkdtemp.c
    ===================================================================
    --- head/contrib/mandoc/compat_mkdtemp.c	(nonexistent)
    +++ head/contrib/mandoc/compat_mkdtemp.c	(revision 338826)
    @@ -0,0 +1,61 @@
    +#include "config.h"
    +
    +#if HAVE_MKDTEMP
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_mkdtemp.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * The algorithm of this function is inspired by OpenBSD mkdtemp(3)
    + * by Theo de Raadt and Todd Miller, but the code differs.
    + */
    +
    +#include <sys/stat.h>
    +#include <errno.h>
    +#include <limits.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +char *
    +mkdtemp(char *path)
    +{
    +	char		*start, *cp;
    +	unsigned	 int tries;
    +
    +	start = strchr(path, '\0');
    +	while (start > path && start[-1] == 'X')
    +		start--;
    +
    +	for (tries = INT_MAX; tries; tries--) {
    +		if (mktemp(path) == NULL) {
    +			errno = EEXIST;
    +			return NULL;
    +		}
    +		if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) == 0)
    +			return path;
    +		if (errno != EEXIST)
    +			return NULL;
    +		for (cp = start; *cp != '\0'; cp++)
    +			*cp = 'X';
    +	}
    +	errno = EEXIST;
    +	return NULL;
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_mkdtemp.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_ohash.h
    ===================================================================
    --- head/contrib/mandoc/compat_ohash.h	(nonexistent)
    +++ head/contrib/mandoc/compat_ohash.h	(revision 338826)
    @@ -0,0 +1,72 @@
    +/* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */
    +
    +/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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.
    + */
    +
    +#ifndef OHASH_H
    +#define OHASH_H
    +
    +/* Open hashing support. 
    + * Open hashing was chosen because it is much lighter than other hash
    + * techniques, and more efficient in most cases.
    + */
    +
    +/* user-visible data structure */
    +struct ohash_info {
    +	ptrdiff_t key_offset;
    +	void *data;	/* user data */
    +	void *(*calloc)(size_t, size_t, void *);
    +	void (*free)(void *, void *);
    +	void *(*alloc)(size_t, void *);
    +};
    +
    +struct _ohash_record;
    +
    +/* private structure. It's there just so you can do a sizeof */
    +struct ohash {
    +	struct _ohash_record 	*t;
    +	struct ohash_info 	info;
    +	unsigned int 		size;
    +	unsigned int 		total;
    +	unsigned int 		deleted;
    +};
    +
    +/* For this to be tweakable, we use small primitives, and leave part of the
    + * logic to the client application.  e.g., hashing is left to the client
    + * application.  We also provide a simple table entry lookup that yields
    + * a hashing table index (opaque) to be used in find/insert/remove.
    + * The keys are stored at a known position in the client data.
    + */
    +void ohash_init(struct ohash *, unsigned, struct ohash_info *);
    +void ohash_delete(struct ohash *);
    +
    +unsigned int ohash_lookup_interval(struct ohash *, const char *,
    +	    const char *, uint32_t);
    +unsigned int ohash_lookup_memory(struct ohash *, const char *,
    +	    size_t, uint32_t);
    +void *ohash_find(struct ohash *, unsigned int);
    +void *ohash_remove(struct ohash *, unsigned int);
    +void *ohash_insert(struct ohash *, unsigned int, void *);
    +void *ohash_first(struct ohash *, unsigned int *);
    +void *ohash_next(struct ohash *, unsigned int *);
    +unsigned int ohash_entries(struct ohash *);
    +
    +void *ohash_create_entry(struct ohash_info *, const char *, const char **);
    +uint32_t ohash_interval(const char *, const char **);
    +
    +unsigned int ohash_qlookupi(struct ohash *, const char *, const char **);
    +unsigned int ohash_qlookup(struct ohash *, const char *);
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_ohash.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_progname.c
    ===================================================================
    --- head/contrib/mandoc/compat_progname.c	(nonexistent)
    +++ head/contrib/mandoc/compat_progname.c	(revision 338826)
    @@ -0,0 +1,42 @@
    +#include "config.h"
    +
    +#if HAVE_PROGNAME
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_progname.c,v 1.1 2015/11/06 16:30:33 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +static const char *progname;
    +
    +void
    +setprogname(const char *name)
    +{
    +
    +	progname = name;
    +}
    +
    +const char *
    +getprogname(void)
    +{
    +
    +	return progname;
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_progname.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_stringlist.c
    ===================================================================
    --- head/contrib/mandoc/compat_stringlist.c	(nonexistent)
    +++ head/contrib/mandoc/compat_stringlist.c	(revision 338826)
    @@ -0,0 +1,119 @@
    +#include "config.h"
    +
    +#if HAVE_STRINGLIST
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_stringlist.c,v 1.6 2015/11/07 14:22:29 schwarze Exp $	*/
    +/*
    + * Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
    + * All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
    + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
    + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + */
    +
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <stdlib.h>
    +#include <string.h>
    +#include "compat_stringlist.h"
    +
    +#define _SL_CHUNKSIZE	20
    +
    +/*
    + * sl_init(): Initialize a string list
    + */
    +StringList *
    +sl_init(void)
    +{
    +	StringList *sl;
    +
    +	sl = malloc(sizeof(StringList));
    +	if (sl == NULL)
    +		err(1, "stringlist");
    +
    +	sl->sl_cur = 0;
    +	sl->sl_max = _SL_CHUNKSIZE;
    +	sl->sl_str = reallocarray(NULL, sl->sl_max, sizeof(char *));
    +	if (sl->sl_str == NULL)
    +		err(1, "stringlist");
    +	return sl;
    +}
    +
    +
    +/*
    + * sl_add(): Add an item to the string list
    + */
    +int
    +sl_add(StringList *sl, char *name)
    +{
    +	if (sl->sl_cur == sl->sl_max - 1) {
    +		sl->sl_max += _SL_CHUNKSIZE;
    +		sl->sl_str = reallocarray(sl->sl_str,
    +		    sl->sl_max, sizeof(char *));
    +		if (sl->sl_str == NULL)
    +			return (-1);
    +	}
    +	sl->sl_str[sl->sl_cur++] = name;
    +	return (0);
    +}
    +
    +
    +/*
    + * sl_free(): Free a stringlist
    + */
    +void
    +sl_free(StringList *sl, int all)
    +{
    +	size_t i;
    +
    +	if (sl == NULL)
    +		return;
    +	if (sl->sl_str) {
    +		if (all)
    +			for (i = 0; i < sl->sl_cur; i++)
    +				free(sl->sl_str[i]);
    +		free(sl->sl_str);
    +	}
    +	free(sl);
    +}
    +
    +
    +/*
    + * sl_find(): Find a name in the string list
    + */
    +char *
    +sl_find(StringList *sl, const char *name)
    +{
    +	size_t i;
    +
    +	for (i = 0; i < sl->sl_cur; i++)
    +		if (strcmp(sl->sl_str[i], name) == 0)
    +			return sl->sl_str[i];
    +
    +	return NULL;
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_stringlist.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_stringlist.h
    ===================================================================
    --- head/contrib/mandoc/compat_stringlist.h	(nonexistent)
    +++ head/contrib/mandoc/compat_stringlist.h	(revision 338826)
    @@ -0,0 +1,45 @@
    +/*	$Id: compat_stringlist.h,v 1.4 2015/11/07 14:01:16 schwarze Exp $	*/
    +/*	$NetBSD: stringlist.h,v 1.2 1997/01/17 06:11:36 lukem Exp $	*/
    +
    +/*
    + * Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
    + * All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
    + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
    + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + */
    +
    +#include <sys/types.h>
    +
    +/*
    + * Simple string list
    + */
    +typedef struct _stringlist {
    +	char	**sl_str;
    +	size_t	  sl_max;
    +	size_t	  sl_cur;
    +} StringList;
    +
    +
    +StringList *sl_init(void);
    +int	 sl_add(StringList *, char *);
    +void	 sl_free(StringList *, int);
    +char	*sl_find(StringList *, const char *);
    
    Property changes on: head/contrib/mandoc/compat_stringlist.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_vasprintf.c
    ===================================================================
    --- head/contrib/mandoc/compat_vasprintf.c	(nonexistent)
    +++ head/contrib/mandoc/compat_vasprintf.c	(revision 338826)
    @@ -0,0 +1,56 @@
    +#include "config.h"
    +
    +#if HAVE_VASPRINTF
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_vasprintf.c,v 1.3 2015/10/06 18:32:19 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + *
    + * This fallback implementation is not efficient:
    + * It does the formatting twice.
    + * Short of fiddling with the unknown internals of the system's
    + * printf(3) or completely reimplementing printf(3), i can't think
    + * of another portable solution.
    + */
    +
    +#include <stdarg.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +
    +int
    +vasprintf(char **ret, const char *format, va_list ap)
    +{
    +	char	 buf[2];
    +	va_list	 ap2;
    +	int	 sz;
    +
    +	va_copy(ap2, ap);
    +	sz = vsnprintf(buf, sizeof(buf), format, ap2);
    +	va_end(ap2);
    +
    +	if (sz != -1 && (*ret = malloc(sz + 1)) != NULL) {
    +		if (vsnprintf(*ret, sz + 1, format, ap) == sz)
    +			return sz;
    +		free(*ret);
    +	}
    +	*ret = NULL;
    +	return -1;
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_vasprintf.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_ohash.c
    ===================================================================
    --- head/contrib/mandoc/mandoc_ohash.c	(nonexistent)
    +++ head/contrib/mandoc/mandoc_ohash.c	(revision 338826)
    @@ -0,0 +1,63 @@
    +/*	$Id: mandoc_ohash.c,v 1.2 2015/10/19 18:58:47 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include <sys/types.h>
    +#include <stddef.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +
    +#include "mandoc_aux.h"
    +#include "mandoc_ohash.h"
    +
    +static	void	 *hash_alloc(size_t, void *);
    +static	void	 *hash_calloc(size_t, size_t, void *);
    +static	void	  hash_free(void *, void *);
    +
    +
    +void
    +mandoc_ohash_init(struct ohash *h, unsigned int sz, ptrdiff_t ko)
    +{
    +	struct ohash_info info;
    +
    +	info.alloc = hash_alloc;
    +	info.calloc = hash_calloc;
    +	info.free = hash_free;
    +	info.data = NULL;
    +	info.key_offset = ko;
    +
    +	ohash_init(h, sz, &info);
    +}
    +
    +static void *
    +hash_alloc(size_t sz, void *arg)
    +{
    +
    +	return mandoc_malloc(sz);
    +}
    +
    +static void *
    +hash_calloc(size_t n, size_t sz, void *arg)
    +{
    +
    +	return mandoc_calloc(n, sz);
    +}
    +
    +static void
    +hash_free(void *p, void *arg)
    +{
    +
    +	free(p);
    +}
    
    Property changes on: head/contrib/mandoc/mandoc_ohash.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/mandoc_ohash.h
    ===================================================================
    --- head/contrib/mandoc/mandoc_ohash.h	(nonexistent)
    +++ head/contrib/mandoc/mandoc_ohash.h	(revision 338826)
    @@ -0,0 +1,23 @@
    +/*	$Id: mandoc_ohash.h,v 1.2 2015/11/07 14:01:16 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#if HAVE_OHASH
    +#include <ohash.h>
    +#else
    +#include "compat_ohash.h"
    +#endif
    +
    +void		  mandoc_ohash_init(struct ohash *, unsigned int, ptrdiff_t);
    
    Property changes on: head/contrib/mandoc/mandoc_ohash.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/msec.c
    ===================================================================
    --- head/contrib/mandoc/msec.c	(nonexistent)
    +++ head/contrib/mandoc/msec.c	(revision 338826)
    @@ -0,0 +1,36 @@
    +/*	$Id: msec.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "libmandoc.h"
    +
    +#define LINE(x, y) \
    +	if (0 == strcmp(p, x)) return(y);
    +
    +const char *
    +mandoc_a2msec(const char *p)
    +{
    +
    +#include "msec.in"
    +
    +	return NULL;
    +}
    
    Property changes on: head/contrib/mandoc/msec.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/soelim.c
    ===================================================================
    --- head/contrib/mandoc/soelim.c	(nonexistent)
    +++ head/contrib/mandoc/soelim.c	(revision 338826)
    @@ -0,0 +1,182 @@
    +/*	$Id: soelim.c,v 1.5 2015/11/07 14:22:29 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
    + * All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer
    + *    in this position and unchanged.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
    + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
    + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <ctype.h>
    +#if HAVE_ERR
    +#include <err.h>
    +#endif
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#if HAVE_STRINGLIST
    +#include <stringlist.h>
    +#else
    +#include "compat_stringlist.h"
    +#endif
    +#include <unistd.h>
    +
    +#define C_OPTION 0x1
    +
    +static StringList *includes;
    +
    +static void
    +usage(void)
    +{
    +
    +	fprintf(stderr, "usage: soelim [-Crtv] [-I dir] [files]\n");
    +
    +	exit(EXIT_FAILURE);
    +}
    +
    +static FILE *
    +soelim_fopen(const char *name)
    +{
    +	FILE *f;
    +	char path[PATH_MAX];
    +	size_t i;
    +
    +	if (strcmp(name, "-") == 0)
    +		return (stdin);
    +
    +	if ((f = fopen(name, "r")) != NULL)
    +		return (f);
    +
    +	if (*name == '/') {
    +		warn("can't open '%s'", name);
    +		return (NULL);
    +	}
    +
    +	for (i = 0; i < includes->sl_cur; i++) {
    +		snprintf(path, sizeof(path), "%s/%s", includes->sl_str[i],
    +		    name);
    +		if ((f = fopen(path, "r")) != NULL)
    +			return (f);
    +	}
    +
    +	warn("can't open '%s'", name);
    +
    +	return (f);
    +}
    +
    +static int
    +soelim_file(FILE *f, int flag)
    +{
    +	char *line = NULL;
    +	char *walk, *cp;
    +	size_t linecap = 0;
    +	ssize_t linelen;
    +
    +	if (f == NULL)
    +		return (1);
    +
    +	while ((linelen = getline(&line, &linecap, f)) > 0) {
    +		if (strncmp(line, ".so", 3) != 0) {
    +			printf("%s", line);
    +			continue;
    +		}
    +
    +		walk = line + 3;
    +		if (!isspace(*walk) && ((flag & C_OPTION) == 0)) {
    +			printf("%s", line);
    +			continue;
    +		}
    +
    +		while (isspace(*walk))
    +			walk++;
    +
    +		cp = walk;
    +		while (*cp != '\0' && !isspace(*cp))
    +			cp++;
    +		*cp = 0;
    +		if (cp < line + linelen)
    +			cp++;
    +
    +		if (*walk == '\0') {
    +			printf("%s", line);
    +			continue;
    +		}
    +		if (soelim_file(soelim_fopen(walk), flag) == 1) {
    +			free(line);
    +			return (1);
    +		}
    +		if (*cp != '\0')
    +			printf("%s", cp);
    +	}
    +
    +	free(line);
    +	fclose(f);
    +
    +	return (0);
    +}
    +
    +int
    +main(int argc, char **argv)
    +{
    +	int ch, i;
    +	int ret = 0;
    +	int flags = 0;
    +
    +	includes = sl_init();
    +	if (includes == NULL)
    +		err(EXIT_FAILURE, "sl_init()");
    +
    +	while ((ch = getopt(argc, argv, "CrtvI:")) != -1) {
    +		switch (ch) {
    +		case 'C':
    +			flags |= C_OPTION;
    +			break;
    +		case 'r':
    +		case 'v':
    +		case 't':
    +			/* stub compatibility with groff's soelim */
    +			break;
    +		case 'I':
    +			sl_add(includes, optarg);
    +			break;
    +		default:
    +			sl_free(includes, 0);
    +			usage();
    +		}
    +	}
    +
    +	argc -= optind;
    +	argv += optind;
    +
    +	if (argc == 0)
    +		ret = soelim_file(stdin, flags);
    +
    +	for (i = 0; i < argc; i++)
    +		ret = soelim_file(soelim_fopen(argv[i]), flags);
    +
    +	sl_free(includes, 0);
    +
    +	return (ret);
    +}
    
    Property changes on: head/contrib/mandoc/soelim.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tag.h
    ===================================================================
    --- head/contrib/mandoc/tag.h	(nonexistent)
    +++ head/contrib/mandoc/tag.h	(revision 338826)
    @@ -0,0 +1,31 @@
    +/*      $Id: tag.h,v 1.7 2015/11/20 21:59:54 schwarze Exp $    */
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +struct	tag_files {
    +	char	 ofn[20];
    +	char	 tfn[20];
    +	int	 ofd;
    +	int	 tfd;
    +	pid_t	 tcpgid;
    +	pid_t	 pager_pid;
    +};
    +
    +
    +struct tag_files *tag_init(void);
    +void	 tag_put(const char *, int, size_t);
    +void	 tag_write(void);
    +void	 tag_unlink(void);
    
    Property changes on: head/contrib/mandoc/tag.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/tbl_opts.c
    ===================================================================
    --- head/contrib/mandoc/tbl_opts.c	(nonexistent)
    +++ head/contrib/mandoc/tbl_opts.c	(revision 338826)
    @@ -0,0 +1,173 @@
    +/*	$Id: tbl_opts.c,v 1.21 2015/09/26 00:54:04 schwarze Exp $ */
    +/*
    + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +#include "config.h"
    +
    +#include <sys/types.h>
    +
    +#include <ctype.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "mandoc.h"
    +#include "libmandoc.h"
    +#include "libroff.h"
    +
    +#define	KEY_DPOINT	0
    +#define	KEY_DELIM	1
    +#define	KEY_LINESIZE	2
    +#define	KEY_TAB		3
    +
    +struct	tbl_phrase {
    +	const char	*name;
    +	int		 key;
    +};
    +
    +static	const struct tbl_phrase keys[] = {
    +	{"decimalpoint", 0},
    +	{"delim",	 0},
    +	{"linesize",	 0},
    +	{"tab",		 0},
    +	{"allbox",	 TBL_OPT_ALLBOX | TBL_OPT_BOX},
    +	{"box",		 TBL_OPT_BOX},
    +	{"frame",	 TBL_OPT_BOX},
    +	{"center",	 TBL_OPT_CENTRE},
    +	{"centre",	 TBL_OPT_CENTRE},
    +	{"doublebox",	 TBL_OPT_DBOX},
    +	{"doubleframe",  TBL_OPT_DBOX},
    +	{"expand",	 TBL_OPT_EXPAND},
    +	{"nokeep",	 TBL_OPT_NOKEEP},
    +	{"nospaces",	 TBL_OPT_NOSPACE},
    +	{"nowarn",	 TBL_OPT_NOWARN},
    +};
    +
    +#define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0])))
    +
    +static	void	 arg(struct tbl_node *, int, const char *, int *, int);
    +
    +
    +static void
    +arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
    +{
    +	int		 len, want;
    +
    +	while (p[*pos] == ' ' || p[*pos] == '\t')
    +		(*pos)++;
    +
    +	/* Arguments are enclosed in parentheses. */
    +
    +	len = 0;
    +	if (p[*pos] == '(') {
    +		(*pos)++;
    +		while (p[*pos + len] != ')')
    +			len++;
    +	}
    +
    +	switch (key) {
    +	case KEY_DELIM:
    +		mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse,
    +		    ln, *pos, "%.*s", len, p + *pos);
    +		want = 2;
    +		break;
    +	case KEY_TAB:
    +		want = 1;
    +		if (len == want)
    +			tbl->opts.tab = p[*pos];
    +		break;
    +	case KEY_LINESIZE:
    +		want = 0;
    +		break;
    +	case KEY_DPOINT:
    +		want = 1;
    +		if (len == want)
    +			tbl->opts.decimal = p[*pos];
    +		break;
    +	default:
    +		abort();
    +	}
    +
    +	if (len == 0)
    +		mandoc_msg(MANDOCERR_TBLOPT_NOARG,
    +		    tbl->parse, ln, *pos, keys[key].name);
    +	else if (want && len != want)
    +		mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ,
    +		    tbl->parse, ln, *pos, "%s want %d have %d",
    +		    keys[key].name, want, len);
    +
    +	*pos += len;
    +	if (p[*pos] == ')')
    +		(*pos)++;
    +}
    +
    +/*
    + * Parse one line of options up to the semicolon.
    + * Each option can be preceded by blanks and/or commas,
    + * and some options are followed by arguments.
    + */
    +void
    +tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
    +{
    +	int		 i, pos, len;
    +
    +	pos = *offs;
    +	for (;;) {
    +		while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
    +			pos++;
    +
    +		if (p[pos] == ';') {
    +			*offs = pos + 1;
    +			return;
    +		}
    +
    +		/* Parse one option name. */
    +
    +		len = 0;
    +		while (isalpha((unsigned char)p[pos + len]))
    +			len++;
    +
    +		if (len == 0) {
    +			mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA,
    +			    tbl->parse, ln, pos, "%c", p[pos]);
    +			pos++;
    +			continue;
    +		}
    +
    +		/* Look up the option name. */
    +
    +		i = 0;
    +		while (i < KEY_MAXKEYS &&
    +		    (strncasecmp(p + pos, keys[i].name, len) ||
    +		     keys[i].name[len] != '\0'))
    +			i++;
    +
    +		if (i == KEY_MAXKEYS) {
    +			mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse,
    +			    ln, pos, "%.*s", len, p + pos);
    +			pos += len;
    +			continue;
    +		}
    +
    +		/* Handle the option. */
    +
    +		pos += len;
    +		if (keys[i].key)
    +			tbl->opts.opts |= keys[i].key;
    +		else
    +			arg(tbl, ln, p, &pos, i);
    +	}
    +}
    
    Property changes on: head/contrib/mandoc/tbl_opts.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-dirent-namlen.c
    ===================================================================
    --- head/contrib/mandoc/test-dirent-namlen.c	(nonexistent)
    +++ head/contrib/mandoc/test-dirent-namlen.c	(revision 338826)
    @@ -0,0 +1,10 @@
    +#include <sys/types.h>
    +#include <dirent.h>
    +
    +int
    +main(void)
    +{
    +	struct dirent	 entry;
    +
    +	return sizeof(entry.d_namlen) == 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-dirent-namlen.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-err.c
    ===================================================================
    --- head/contrib/mandoc/test-err.c	(nonexistent)
    +++ head/contrib/mandoc/test-err.c	(revision 338826)
    @@ -0,0 +1,28 @@
    +/*	$Id: test-err.c,v 1.1 2015/10/11 21:12:55 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#include <err.h>
    +
    +int
    +main(void)
    +{
    +	warnx("%d. warnx", 1);
    +	warn("%d. warn", 2);
    +	err(0, "%d. err", 3);
    +	/* NOTREACHED */
    +	return 1;
    +}
    
    Property changes on: head/contrib/mandoc/test-err.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-getline.c
    ===================================================================
    --- head/contrib/mandoc/test-getline.c	(nonexistent)
    +++ head/contrib/mandoc/test-getline.c	(revision 338826)
    @@ -0,0 +1,13 @@
    +#include <sys/types.h>
    +#include <stdio.h>
    +#include <unistd.h>
    +
    +int
    +main(void)
    +{
    +	char	*line = NULL;
    +	size_t	 linesz = 0;
    +
    +	fclose(stdin);
    +	return getline(&line, &linesz, stdin) != -1;
    +}
    
    Property changes on: head/contrib/mandoc/test-getline.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-getsubopt.c
    ===================================================================
    --- head/contrib/mandoc/test-getsubopt.c	(nonexistent)
    +++ head/contrib/mandoc/test-getsubopt.c	(revision 338826)
    @@ -0,0 +1,34 @@
    +/*	$Id: test-getsubopt.c,v 1.4 2015/10/06 18:32:20 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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.
    + */
    +
    +#if defined(__linux__) || defined(__MINT__)
    +#define _GNU_SOURCE /* getsubopt() */
    +#endif
    +
    +#include <stdlib.h>
    +
    +int
    +main(void)
    +{
    +	char buf[] = "k=v";
    +	char *options = buf;
    +	char token0[] = "k";
    +	char *const tokens[] = { token0, NULL };
    +	char *value = NULL;
    +	return ! (getsubopt(&options, tokens, &value) == 0
    +	    && value == buf+2 && options == buf+3);
    +}
    
    Property changes on: head/contrib/mandoc/test-getsubopt.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-isblank.c
    ===================================================================
    --- head/contrib/mandoc/test-isblank.c	(nonexistent)
    +++ head/contrib/mandoc/test-isblank.c	(revision 338826)
    @@ -0,0 +1,7 @@
    +#include <ctype.h>
    +
    +int
    +main(void)
    +{
    +	return !isblank(' ') || !isblank('\t') || isblank('_');
    +}
    
    Property changes on: head/contrib/mandoc/test-isblank.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-mkdtemp.c
    ===================================================================
    --- head/contrib/mandoc/test-mkdtemp.c	(nonexistent)
    +++ head/contrib/mandoc/test-mkdtemp.c	(revision 338826)
    @@ -0,0 +1,12 @@
    +#include <stdlib.h>
    +#include <unistd.h>
    +
    +int
    +main(void)
    +{
    +	char	dirname[] = "/tmp/temp.XXXXXX";
    +
    +	if (mkdtemp(dirname) != dirname)
    +		return 1;
    +	return rmdir(dirname) == -1;
    +}
    
    Property changes on: head/contrib/mandoc/test-mkdtemp.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-pledge.c
    ===================================================================
    --- head/contrib/mandoc/test-pledge.c	(nonexistent)
    +++ head/contrib/mandoc/test-pledge.c	(revision 338826)
    @@ -0,0 +1,7 @@
    +#include <unistd.h>
    +
    +int
    +main(void)
    +{
    +	return !!pledge("stdio", NULL);
    +}
    
    Property changes on: head/contrib/mandoc/test-pledge.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-progname.c
    ===================================================================
    --- head/contrib/mandoc/test-progname.c	(nonexistent)
    +++ head/contrib/mandoc/test-progname.c	(revision 338826)
    @@ -0,0 +1,10 @@
    +#include <stdlib.h>
    +
    +int
    +main(void)
    +{
    +	const char * progname;
    +
    +	progname = getprogname();
    +	return progname == NULL;
    +}
    
    Property changes on: head/contrib/mandoc/test-progname.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-reallocarray.c
    ===================================================================
    --- head/contrib/mandoc/test-reallocarray.c	(nonexistent)
    +++ head/contrib/mandoc/test-reallocarray.c	(revision 338826)
    @@ -0,0 +1,7 @@
    +#include <stdlib.h>
    +
    +int
    +main(void)
    +{
    +	return !reallocarray(NULL, 2, 2);
    +}
    
    Property changes on: head/contrib/mandoc/test-reallocarray.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-strcasestr.c
    ===================================================================
    --- head/contrib/mandoc/test-strcasestr.c	(nonexistent)
    +++ head/contrib/mandoc/test-strcasestr.c	(revision 338826)
    @@ -0,0 +1,13 @@
    +#if defined(__linux__) || defined(__MINT__)
    +# define _GNU_SOURCE /* strcasestr() */
    +#endif
    +
    +#include <string.h>
    +
    +int
    +main(void)
    +{
    +	const char *big = "BigString";
    +	char *cp = strcasestr(big, "Gst");
    +	return cp != big + 2;
    +}
    
    Property changes on: head/contrib/mandoc/test-strcasestr.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-stringlist.c
    ===================================================================
    --- head/contrib/mandoc/test-stringlist.c	(nonexistent)
    +++ head/contrib/mandoc/test-stringlist.c	(revision 338826)
    @@ -0,0 +1,37 @@
    +/*	$Id: test-stringlist.c,v 1.2 2015/10/06 18:32:20 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#include <stringlist.h>
    +
    +int
    +main(void)
    +{
    +	StringList	*sl;
    +	char		 teststr[] = "test";
    +
    +	if ((sl = sl_init()) == NULL)
    +		return 1;
    +	if (sl_add(sl, teststr))
    +		return 2;
    +	if (sl->sl_cur != 1)
    +		return 3;
    +	if (sl->sl_str[0] != teststr)
    +		return 4;
    +
    +	sl_free(sl, 0);
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-stringlist.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-strlcat.c
    ===================================================================
    --- head/contrib/mandoc/test-strlcat.c	(nonexistent)
    +++ head/contrib/mandoc/test-strlcat.c	(revision 338826)
    @@ -0,0 +1,9 @@
    +#include <string.h>
    +
    +int
    +main(void)
    +{
    +	char buf[3] = "a";
    +	return ! (strlcat(buf, "b", sizeof(buf)) == 2 &&
    +	    buf[0] == 'a' && buf[1] == 'b' && buf[2] == '\0');
    +}
    
    Property changes on: head/contrib/mandoc/test-strlcat.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-strlcpy.c
    ===================================================================
    --- head/contrib/mandoc/test-strlcpy.c	(nonexistent)
    +++ head/contrib/mandoc/test-strlcpy.c	(revision 338826)
    @@ -0,0 +1,9 @@
    +#include <string.h>
    +
    +int
    +main(void)
    +{
    +	char buf[2] = "";
    +	return ! (strlcpy(buf, "a", sizeof(buf)) == 1 &&
    +	    buf[0] == 'a' && buf[1] == '\0');
    +}
    
    Property changes on: head/contrib/mandoc/test-strlcpy.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-strptime.c
    ===================================================================
    --- head/contrib/mandoc/test-strptime.c	(nonexistent)
    +++ head/contrib/mandoc/test-strptime.c	(revision 338826)
    @@ -0,0 +1,14 @@
    +#if defined(__linux__) || defined(__MINT__)
    +# define _GNU_SOURCE /* strptime() */
    +#endif
    +
    +#include <time.h>
    +
    +int
    +main(void)
    +{
    +	struct tm tm;
    +	const char input[] = "2014-01-04";
    +	return ! (strptime(input, "%Y-%m-%d", &tm) == input + 10 &&
    +	    tm.tm_year == 114 && tm.tm_mon == 0 && tm.tm_mday == 4);
    +}
    
    Property changes on: head/contrib/mandoc/test-strptime.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-strsep.c
    ===================================================================
    --- head/contrib/mandoc/test-strsep.c	(nonexistent)
    +++ head/contrib/mandoc/test-strsep.c	(revision 338826)
    @@ -0,0 +1,10 @@
    +#include <string.h>
    +
    +int
    +main(void)
    +{
    +	char buf[6] = "aybxc";
    +	char *workp = buf;
    +	char *retp = strsep(&workp, "xy");
    +	return ! (retp == buf && buf[1] == '\0' && workp == buf + 2);
    +}
    
    Property changes on: head/contrib/mandoc/test-strsep.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-strtonum.c
    ===================================================================
    --- head/contrib/mandoc/test-strtonum.c	(nonexistent)
    +++ head/contrib/mandoc/test-strtonum.c	(revision 338826)
    @@ -0,0 +1,42 @@
    +/*	$Id: test-strtonum.c,v 1.2 2015/10/06 18:32:20 schwarze Exp $	*/
    +/*
    + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * copyright notice and this permission notice appear in all copies.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    + */
    +
    +#include <stdlib.h>
    +
    +int
    +main(void)
    +{
    +	const char *errstr;
    +
    +	if (strtonum("1", 0, 2, &errstr) != 1)
    +		return 1;
    +	if (errstr != NULL)
    +		return 2;
    +	if (strtonum("1x", 0, 2, &errstr) != 0)
    +		return 3;
    +	if (errstr == NULL)
    +		return 4;
    +	if (strtonum("2", 0, 1, &errstr) != 0)
    +		return 5;
    +	if (errstr == NULL)
    +		return 6;
    +	if (strtonum("0", 1, 2, &errstr) != 0)
    +		return 7;
    +	if (errstr == NULL)
    +		return 8;
    +	return 0;
    +}
    
    Property changes on: head/contrib/mandoc/test-strtonum.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_strtonum.c
    ===================================================================
    --- head/contrib/mandoc/compat_strtonum.c	(nonexistent)
    +++ head/contrib/mandoc/compat_strtonum.c	(revision 338826)
    @@ -0,0 +1,76 @@
    +#include "config.h"
    +
    +#if HAVE_STRTONUM
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_strtonum.c,v 1.1 2015/02/16 14:56:22 schwarze Exp $	*/
    +/*	$OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $	*/
    +
    +/*
    + * Copyright (c) 2004 Ted Unangst and Todd Miller
    + * All rights reserved.
    + *
    + * 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 <errno.h>
    +#include <limits.h>
    +#include <stdlib.h>
    +
    +#define	INVALID		1
    +#define	TOOSMALL	2
    +#define	TOOLARGE	3
    +
    +long long
    +strtonum(const char *numstr, long long minval, long long maxval,
    +    const char **errstrp)
    +{
    +	long long ll = 0;
    +	int error = 0;
    +	char *ep;
    +	struct errval {
    +		const char *errstr;
    +		int err;
    +	} ev[4] = {
    +		{ NULL,		0 },
    +		{ "invalid",	EINVAL },
    +		{ "too small",	ERANGE },
    +		{ "too large",	ERANGE },
    +	};
    +
    +	ev[0].err = errno;
    +	errno = 0;
    +	if (minval > maxval) {
    +		error = INVALID;
    +	} else {
    +		ll = strtoll(numstr, &ep, 10);
    +		if (numstr == ep || *ep != '\0')
    +			error = INVALID;
    +		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
    +			error = TOOSMALL;
    +		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
    +			error = TOOLARGE;
    +	}
    +	if (errstrp != NULL)
    +		*errstrp = ev[error].errstr;
    +	errno = ev[error].err;
    +	if (error)
    +		ll = 0;
    +
    +	return (ll);
    +}
    +
    +#endif /* !HAVE_STRTONUM */
    
    Property changes on: head/contrib/mandoc/compat_strtonum.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/man-cgi.css
    ===================================================================
    --- head/contrib/mandoc/man-cgi.css	(nonexistent)
    +++ head/contrib/mandoc/man-cgi.css	(revision 338826)
    @@ -0,0 +1,13 @@
    +body				{ font-family: Helvetica, Arial, sans-serif; }
    +body > div			{ padding-left: 2em;
    +				  padding-top: 1em; }
    +body > div#mancgi		{ padding-left: 0em;
    +				  padding-top: 0em; }
    +body > div.results		{ font-size: smaller; }
    +#mancgi fieldset		{ text-align: center;
    +				  border: thin solid silver;
    +				  border-radius: 1em;
    +			  	  font-size: small; }
    +#mancgi input[name=expr] 	{ width: 25%; }
    +.results td.title		{ vertical-align: top;
    +				  padding-right: 1em; }
    
    Property changes on: head/contrib/mandoc/man-cgi.css
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/css
    \ No newline at end of property
    Index: head/contrib/mandoc/tbl.3
    ===================================================================
    --- head/contrib/mandoc/tbl.3	(nonexistent)
    +++ head/contrib/mandoc/tbl.3	(revision 338826)
    @@ -0,0 +1,354 @@
    +.\"	$Id: tbl.3,v 1.2 2015/01/30 04:11:50 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" copyright notice and this permission notice appear in all copies.
    +.\"
    +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +.\"
    +.Dd $Mdocdate: January 30 2015 $
    +.Dt TBL 3
    +.Os
    +.Sh NAME
    +.Nm tbl_alloc ,
    +.Nm tbl_read ,
    +.Nm tbl_restart ,
    +.Nm tbl_span ,
    +.Nm tbl_end ,
    +.Nm tbl_free
    +.Nd roff table parser library for mandoc
    +.Sh SYNOPSIS
    +.In mandoc.h
    +.In libmandoc.h
    +.In libroff.h
    +.Ft struct tbl_node *
    +.Fo tbl_alloc
    +.Fa "int pos"
    +.Fa "int line"
    +.Fa "struct mparse *parse"
    +.Fc
    +.Ft enum rofferr
    +.Fo tbl_read
    +.Fa "struct tbl_node *tbl"
    +.Fa "int ln"
    +.Fa "const char *p"
    +.Fa "int offs"
    +.Fc
    +.Ft void
    +.Fo tbl_restart
    +.Fa "int line"
    +.Fa "int pos"
    +.Fa "struct tbl_node *tbl"
    +.Fc
    +.Ft const struct tbl_span *
    +.Fo tbl_span
    +.Fa "struct tbl_node *tbl"
    +.Fc
    +.Ft void
    +.Fo tbl_end
    +.Fa "struct tbl_node **tblp"
    +.Fc
    +.Ft void
    +.Fo tbl_free
    +.Fa "struct tbl_node *tbl"
    +.Fc
    +.Sh DESCRIPTION
    +This library is tightly integrated into the
    +.Xr mandoc 1
    +utility and not designed for stand-alone use.
    +The present manual is intended as a reference for developers working on
    +.Xr mandoc 1 .
    +.Ss Data structures
    +Unless otherwise noted, all of the following data structures are defined in
    +.In mandoc.h
    +and are deleted in
    +.Fn tbl_free .
    +.Bl -tag -width Ds
    +.It Vt struct tbl_node
    +This structure describes a complete table.
    +It is defined in
    +.In libroff.h ,
    +created in
    +.Fn tbl_alloc ,
    +and stored in the members
    +.Fa first_tbl ,
    +.Fa last_tbl ,
    +and
    +.Fa tbl
    +of
    +.Vt struct roff Bq Pa roff.c .
    +.Pp
    +The
    +.Fa first_span ,
    +.Fa current_span ,
    +.Fa last_span ,
    +and
    +.Fa next
    +members may be
    +.Dv NULL .
    +The
    +.Fa first_row
    +and
    +.Fa last_row
    +members may be
    +.Dv NULL ,
    +but if there is a span, the function
    +.Fn tbl_layout
    +guarantees that these pointers are not
    +.Dv NULL .
    +The function
    +.Fn tbl_alloc
    +guarantees that the
    +.Fa parse
    +member is not
    +.Dv NULL .
    +.It Vt struct tbl_opts
    +This structure describes the options of one table.
    +It is used as a substructure of
    +.Vt struct tbl_node
    +and thus created and deleted together with it.
    +It is filled in
    +.Fn tbl_options .
    +.It Vt struct tbl_row
    +This structure describes one layout line in a table
    +by maintaining a list of all the cells in that line.
    +It is allocated and filled in
    +.Fn row Bq Pa tbl_layout.c
    +and referenced from the
    +.Fa layout
    +member of
    +.Vt struct tbl_node .
    +.Pp
    +The
    +.Fa next
    +member may be
    +.Dv NULL .
    +The function
    +.Fn tbl_layout
    +guarantees that the
    +.Fa first
    +and
    +.Fa last
    +members are not NULL.
    +.It Vt struct tbl_cell
    +This structure describes one layout cell in a table,
    +in particular its alignment, membership in spans, and
    +usage for lines.
    +It is allocated and filled in
    +.Fn cell_alloc Bq Pa tbl_layout.c
    +and referenced from the
    +.Fa first
    +and
    +.Fa last
    +members of
    +.Vt struct tbl_row .
    +.Pp
    +The
    +.Fa next
    +member may be
    +.Dv NULL .
    +.It Vt struct tbl_span
    +This structure describes one data line in a table
    +by maintaining a list of all data cells in that line
    +or by specifying that it is a horizontal line.
    +It is allocated and filled in
    +.Fn newspan Bq Pa tbl_data.c
    +which is called from
    +.Fn tbl_data
    +and referenced from the
    +.Fa first_span ,
    +.Fa current_span ,
    +and
    +.Fa last_span
    +members of
    +.Vt struct tbl_node ,
    +and from the
    +.Fa span
    +members of
    +.Vt struct man_node
    +and
    +.Vt struct mdoc_node
    +from
    +.In man.h
    +and
    +.In mdoc.h .
    +.Pp
    +The
    +.Fa first ,
    +.Fa last ,
    +.Fa prev ,
    +and
    +.Fa next
    +members may be
    +.Dv NULL .
    +The function
    +.Fn newspan Bq Pa tbl_data.c
    +guarantees that the
    +.Fa opts
    +and
    +.Fa layout
    +members are not
    +.Dv NULL .
    +.It Vt struct tbl_dat
    +This structure describes one data cell in a table by specifying
    +whether it contains a line or data, whether it spans additional
    +layout cells, and by storing the data.
    +It is allocated and filled in
    +.Fn tbl_data
    +and referenced from the
    +.Fa first
    +and
    +.Fa last
    +members of
    +.Vt struct tbl_span .
    +.Pp
    +The
    +.Fa string
    +and
    +.Fa next
    +members may be
    +.Dv NULL .
    +The function
    +.Fn getdata
    +guarantees that the
    +.Fa layout
    +member is not
    +.Dv NULL .
    +.El
    +.Ss Interface functions
    +The following functions are implemented in
    +.Pa tbl.c ,
    +and all callers in
    +.Pa roff.c .
    +.Bl -tag -width Ds
    +.It Fn tbl_alloc
    +Allocates, initializes, and returns a new
    +.Vt struct tbl_node .
    +Called from
    +.Fn roff_TS .
    +.It Fn tbl_read
    +Dispatches to
    +.Fn tbl_option ,
    +.Fn tbl_layout ,
    +.Fn tbl_cdata ,
    +and
    +.Fn tbl_data ,
    +see below.
    +Called from
    +.Fn roff_parseln .
    +.It Fn tbl_restart
    +Resets the
    +.Fa part
    +member of
    +.Vt struct tbl_node
    +to
    +.Dv TBL_PART_LAYOUT .
    +Called from
    +.Fn roff_T_ .
    +.It Fn tbl_span
    +On the first call, return the first
    +.Vt struct tbl_span ;
    +for later calls, return the next one or
    +.Dv NULL .
    +Called from
    +.Fn roff_span .
    +.It Fn tbl_end
    +Flags the last span as
    +.Dv TBL_SPAN_LAST
    +and clears the pointer passed as an argment.
    +Called from
    +.Fn roff_TE
    +and
    +.Fn roff_endparse .
    +.It Fn tbl_free
    +Frees the specified
    +.Vt struct tbl_node
    +and all the tbl_row, tbl_cell, tbl_span, and tbl_dat structures
    +referenced from it.
    +Called from
    +.Fn roff_free
    +and
    +.Fn roff_reset .
    +.El
    +.Ss Private functions
    +.Bl -tag -width Ds
    +.It Ft int Fn tbl_options "struct tbl_node *tbl" "int ln" "const char *p"
    +Parses the options line into
    +.Vt struct tbl_opts .
    +Implemented in
    +.Pa tbl_opts.c ,
    +called from
    +.Fn tbl_read .
    +.It Ft int Fn tbl_layout "struct tbl_node *tbl" "int ln" "const char *p"
    +Allocates and fills one
    +.Vt struct tbl_row
    +for each layout line and one
    +.Vt struct tbl_cell
    +for each layout cell.
    +Implemented in
    +.Pa tbl_layout.c ,
    +called from
    +.Fn tbl_read .
    +.It Ft int Fn tbl_data "struct tbl_node *tbl" "int ln" "const char *p"
    +Allocates one
    +.Vt struct tbl_span
    +for each data line and calls
    +.Fn getdata
    +for each data cell.
    +Implemented in
    +.Pa tbl_data.c ,
    +called from
    +.Fn tbl_read .
    +.It Ft int Fn tbl_cdata "struct tbl_node *tbl" "int ln" "const char *p"
    +Continues parsing a data line:
    +When finding
    +.Sq T} ,
    +switches back to
    +.Dv TBL_PART_DATA
    +mode and calls
    +.Fn getdata
    +if there are more data cells on the line.
    +Otherwise, appends the data to the current data cell.
    +Implemented in
    +.Pa tbl_data.c ,
    +called from
    +.Fn tbl_read .
    +.It Xo
    +.Ft int
    +.Fo getdata
    +.Fa "struct tbl_node *tbl"
    +.Fa "struct tbl_span *dp"
    +.Fa "int ln"
    +.Fa "const char *p"
    +.Fa "int *pos"
    +.Fc
    +.Xc
    +Parses one data cell into one
    +.Vt struct tbl_dat .
    +Implemented in
    +.Pa tbl_data.c ,
    +called from
    +.Fn tbl_data
    +and
    +.Fn tbl_cdata .
    +.El
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr mandoc 3 ,
    +.Xr tbl 7
    +.Sh AUTHORS
    +.An -nosplit
    +The
    +.Nm tbl
    +library was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
    +with contributions from
    +.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
    
    Property changes on: head/contrib/mandoc/tbl.3
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_reallocarray.c
    ===================================================================
    --- head/contrib/mandoc/compat_reallocarray.c	(nonexistent)
    +++ head/contrib/mandoc/compat_reallocarray.c	(revision 338826)
    @@ -0,0 +1,49 @@
    +#include "config.h"
    +
    +#if HAVE_REALLOCARRAY
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_reallocarray.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $	*/
    +/*	$OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $	*/
    +/*
    + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
    + *
    + * 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 <sys/types.h>
    +#include <errno.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +
    +/*
    + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
    + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
    + */
    +#define MUL_NO_OVERFLOW	((size_t)1 << (sizeof(size_t) * 4))
    +
    +void *
    +reallocarray(void *optr, size_t nmemb, size_t size)
    +{
    +	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
    +	    nmemb > 0 && SIZE_MAX / nmemb < size) {
    +		errno = ENOMEM;
    +		return NULL;
    +	}
    +	return realloc(optr, size * nmemb);
    +}
    +
    +#endif /*!HAVE_REALLOCARRAY*/
    
    Property changes on: head/contrib/mandoc/compat_reallocarray.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_strcasestr.c
    ===================================================================
    --- head/contrib/mandoc/compat_strcasestr.c	(nonexistent)
    +++ head/contrib/mandoc/compat_strcasestr.c	(revision 338826)
    @@ -0,0 +1,73 @@
    +#include "config.h"
    +
    +#if HAVE_STRCASESTR
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_strcasestr.c,v 1.4 2014/12/11 09:19:32 schwarze Exp $	*/
    +/*	$NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $	*/
    +
    +/*-
    + * Copyright (c) 1990, 1993
    + *	The Regents of the University of California.  All rights reserved.
    + *
    + * This code is derived from software contributed to Berkeley by
    + * Chris Torek.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. Neither the name of the University nor the names of its contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + */
    +
    +#include <sys/types.h>
    +#include <ctype.h>
    +#include <string.h>
    +
    +#define	__UNCONST(a)	((void *)(unsigned long)(const void *)(a))
    +
    +/*
    + * Find the first occurrence of find in s, ignore case.
    + */
    +char *
    +strcasestr(const char *s, const char *find)
    +{
    +	char c, sc;
    +	size_t len;
    +
    +	if ((c = *find++) != 0) {
    +		c = tolower((unsigned char)c);
    +		len = strlen(find);
    +		do {
    +			do {
    +				if ((sc = *s++) == 0)
    +					return (NULL);
    +			} while ((char)tolower((unsigned char)sc) != c);
    +		} while (strncasecmp(s, find, len) != 0);
    +		s--;
    +	}
    +	return __UNCONST(s);
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_strcasestr.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_strsep.c
    ===================================================================
    --- head/contrib/mandoc/compat_strsep.c	(nonexistent)
    +++ head/contrib/mandoc/compat_strsep.c	(revision 338826)
    @@ -0,0 +1,79 @@
    +#include "config.h"
    +
    +#if HAVE_STRSEP
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_strsep.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $	*/
    +/*	$OpenBSD: strsep.c,v 1.7 2014/02/05 20:42:32 stsp Exp $	*/
    +
    +/*-
    + * Copyright (c) 1990, 1993
    + *	The Regents of the University of California.  All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. Neither the name of the University nor the names of its contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + */
    +
    +/*
    + * Get next token from string *stringp, where tokens are possibly-empty
    + * strings separated by characters from delim.  
    + *
    + * Writes NULs into the string at *stringp to end tokens.
    + * delim need not remain constant from call to call.
    + * On return, *stringp points past the last NUL written (if there might
    + * be further tokens), or is NULL (if there are definitely no more tokens).
    + *
    + * If *stringp is NULL, strsep returns NULL.
    + */
    +char *
    +strsep(char **stringp, const char *delim)
    +{
    +	char *s;
    +	const char *spanp;
    +	int c, sc;
    +	char *tok;
    +
    +	if ((s = *stringp) == NULL)
    +		return (NULL);
    +	for (tok = s;;) {
    +		c = *s++;
    +		spanp = delim;
    +		do {
    +			if ((sc = *spanp++) == c) {
    +				if (c == 0)
    +					s = NULL;
    +				else
    +					s[-1] = 0;
    +				*stringp = s;
    +				return (tok);
    +			}
    +		} while (sc != 0);
    +	}
    +	/* NOTREACHED */
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_strsep.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/manpath.h
    ===================================================================
    --- head/contrib/mandoc/manpath.h	(nonexistent)
    +++ head/contrib/mandoc/manpath.h	(revision 338826)
    @@ -0,0 +1,34 @@
    +/*	$Id: manpath.h,v 1.7 2014/12/01 04:05:32 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
    + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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.
    + */
    +
    +/*
    + * Unsorted list of unique, absolute paths to be searched for manual
    + * databases.
    + */
    +struct	manpaths {
    +	size_t	  sz;
    +	char	**paths;
    +};
    +
    +__BEGIN_DECLS
    +
    +void	 manpath_manconf(struct manpaths *, const char *);
    +void	 manpath_parse(struct manpaths *, const char *, char *, char *);
    +void	 manpath_free(struct manpaths *);
    +
    +__END_DECLS
    
    Property changes on: head/contrib/mandoc/manpath.h
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_getsubopt.c
    ===================================================================
    --- head/contrib/mandoc/compat_getsubopt.c	(nonexistent)
    +++ head/contrib/mandoc/compat_getsubopt.c	(revision 338826)
    @@ -0,0 +1,96 @@
    +#include "config.h"
    +
    +#if HAVE_GETSUBOPT
    +
    +int dummy;
    +
    +#else
    +
    +/*	$Id: compat_getsubopt.c,v 1.5 2014/08/17 20:53:50 schwarze Exp $	*/
    +/*	$OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $	*/
    +
    +/*-
    + * Copyright (c) 1990, 1993
    + *	The Regents of the University of California.  All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + * 1. Redistributions of source code must retain the above copyright
    + *    notice, this list of conditions and the following disclaimer.
    + * 2. Redistributions in binary form must reproduce the above copyright
    + *    notice, this list of conditions and the following disclaimer in the
    + *    documentation and/or other materials provided with the distribution.
    + * 3. Neither the name of the University nor the names of its contributors
    + *    may be used to endorse or promote products derived from this software
    + *    without specific prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + */
    +
    +#include <unistd.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +int
    +getsubopt(char **optionp, char * const *tokens, char **valuep)
    +{
    +	int cnt;
    +	char *suboptarg;
    +	char *p;
    +
    +	suboptarg = *valuep = NULL;
    +
    +	if (!optionp || !*optionp)
    +		return(-1);
    +
    +	/* skip leading white-space, commas */
    +	for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
    +
    +	if (!*p) {
    +		*optionp = p;
    +		return(-1);
    +	}
    +
    +	/* save the start of the token, and skip the rest of the token. */
    +	for (suboptarg = p;
    +	    *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';);
    +
    +	if (*p) {
    +		/*
    +		 * If there's an equals sign, set the value pointer, and
    +		 * skip over the value part of the token.  Terminate the
    +		 * token.
    +		 */
    +		if (*p == '=') {
    +			*p = '\0';
    +			for (*valuep = ++p;
    +			    *p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
    +			if (*p) 
    +				*p++ = '\0';
    +		} else
    +			*p++ = '\0';
    +		/* Skip any whitespace or commas after this token. */
    +		for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
    +	}
    +
    +	/* set optionp for next round. */
    +	*optionp = p;
    +
    +	for (cnt = 0; *tokens; ++tokens, ++cnt)
    +		if (!strcmp(suboptarg, *tokens))
    +			return(cnt);
    +	return(-1);
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_getsubopt.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_ohash.c
    ===================================================================
    --- head/contrib/mandoc/compat_ohash.c	(nonexistent)
    +++ head/contrib/mandoc/compat_ohash.c	(revision 338826)
    @@ -0,0 +1,339 @@
    +#include "config.h"
    +
    +#if HAVE_OHASH
    +
    +int dummy;
    +
    +#else
    +
    +/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */
    +
    +/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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 <sys/types.h>
    +
    +#include <stddef.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <limits.h>
    +#include "compat_ohash.h"
    +
    +struct _ohash_record {
    +	uint32_t	hv;
    +	const char	*p;
    +};
    +
    +#define DELETED		((const char *)h)
    +#define NONE		(h->size)
    +
    +/* Don't bother changing the hash table if the change is small enough.  */
    +#define MINSIZE		(1UL << 4)
    +#define MINDELETED	4
    +
    +static void ohash_resize(struct ohash *);
    +
    +
    +/* This handles the common case of variable length keys, where the
    + * key is stored at the end of the record.
    + */
    +void *
    +ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
    +{
    +	char *p;
    +
    +	if (!*end)
    +		*end = start + strlen(start);
    +	p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
    +	if (p) {
    +		memcpy(p+i->key_offset, start, *end-start);
    +		p[i->key_offset + (*end - start)] = '\0';
    +	}
    +	return (void *)p;
    +}
    +
    +/* hash_delete only frees the hash structure. Use hash_first/hash_next
    + * to free entries as well.  */
    +void
    +ohash_delete(struct ohash *h)
    +{
    +	(h->info.free)(h->t, h->info.data);
    +#ifndef NDEBUG
    +	h->t = NULL;
    +#endif
    +}
    +
    +static void
    +ohash_resize(struct ohash *h)
    +{
    +	struct _ohash_record *n;
    +	size_t ns;
    +	unsigned int	j;
    +	unsigned int	i, incr;
    +
    +	if (4 * h->deleted < h->total) {
    +		if (h->size >= (UINT_MAX >> 1U))
    +			ns = UINT_MAX;
    +		else
    +			ns = h->size << 1U;
    +	} else if (3 * h->deleted > 2 * h->total)
    +		ns = h->size >> 1U;
    +	else
    +		ns = h->size;
    +	if (ns < MINSIZE)
    +		ns = MINSIZE;
    +#ifdef STATS_HASH
    +	STAT_HASH_EXPAND++;
    +	STAT_HASH_SIZE += ns - h->size;
    +#endif
    +
    +	n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data);
    +	if (!n)
    +		return;
    +
    +	for (j = 0; j < h->size; j++) {
    +		if (h->t[j].p != NULL && h->t[j].p != DELETED) {
    +			i = h->t[j].hv % ns;
    +			incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
    +			while (n[i].p != NULL) {
    +				i += incr;
    +				if (i >= ns)
    +					i -= ns;
    +			}
    +			n[i].hv = h->t[j].hv;
    +			n[i].p = h->t[j].p;
    +		}
    +	}
    +	(h->info.free)(h->t, h->info.data);
    +	h->t = n;
    +	h->size = ns;
    +	h->total -= h->deleted;
    +	h->deleted = 0;
    +}
    +
    +void *
    +ohash_remove(struct ohash *h, unsigned int i)
    +{
    +	void		*result = (void *)h->t[i].p;
    +
    +	if (result == NULL || result == DELETED)
    +		return NULL;
    +
    +#ifdef STATS_HASH
    +	STAT_HASH_ENTRIES--;
    +#endif
    +	h->t[i].p = DELETED;
    +	h->deleted++;
    +	if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
    +		ohash_resize(h);
    +	return result;
    +}
    +
    +void *
    +ohash_find(struct ohash *h, unsigned int i)
    +{
    +	if (h->t[i].p == DELETED)
    +		return NULL;
    +	else
    +		return (void *)h->t[i].p;
    +}
    +
    +void *
    +ohash_insert(struct ohash *h, unsigned int i, void *p)
    +{
    +#ifdef STATS_HASH
    +	STAT_HASH_ENTRIES++;
    +#endif
    +	if (h->t[i].p == DELETED) {
    +		h->deleted--;
    +		h->t[i].p = p;
    +	} else {
    +		h->t[i].p = p;
    +		/* Arbitrary resize boundary.  Tweak if not efficient enough.  */
    +		if (++h->total * 4 > h->size * 3)
    +			ohash_resize(h);
    +	}
    +	return p;
    +}
    +
    +unsigned int
    +ohash_entries(struct ohash *h)
    +{
    +	return h->total - h->deleted;
    +}
    +
    +void *
    +ohash_first(struct ohash *h, unsigned int *pos)
    +{
    +	*pos = 0;
    +	return ohash_next(h, pos);
    +}
    +
    +void *
    +ohash_next(struct ohash *h, unsigned int *pos)
    +{
    +	for (; *pos < h->size; (*pos)++)
    +		if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
    +			return (void *)h->t[(*pos)++].p;
    +	return NULL;
    +}
    +
    +void
    +ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
    +{
    +	h->size = 1UL << size;
    +	if (h->size < MINSIZE)
    +		h->size = MINSIZE;
    +#ifdef STATS_HASH
    +	STAT_HASH_CREATION++;
    +	STAT_HASH_SIZE += h->size;
    +#endif
    +	/* Copy info so that caller may free it.  */
    +	h->info.key_offset = info->key_offset;
    +	h->info.calloc = info->calloc;
    +	h->info.free = info->free;
    +	h->info.alloc = info->alloc;
    +	h->info.data = info->data;
    +	h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record),
    +		    h->info.data);
    +	h->total = h->deleted = 0;
    +}
    +
    +uint32_t
    +ohash_interval(const char *s, const char **e)
    +{
    +	uint32_t k;
    +
    +	if (!*e)
    +		*e = s + strlen(s);
    +	if (s == *e)
    +		k = 0;
    +	else
    +		k = *s++;
    +	while (s != *e)
    +		k =  ((k << 2) | (k >> 30)) ^ *s++;
    +	return k;
    +}
    +
    +unsigned int
    +ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
    +    uint32_t hv)
    +{
    +	unsigned int	i, incr;
    +	unsigned int	empty;
    +
    +#ifdef STATS_HASH
    +	STAT_HASH_LOOKUP++;
    +#endif
    +	empty = NONE;
    +	i = hv % h->size;
    +	incr = ((hv % (h->size-2)) & ~1) + 1;
    +	while (h->t[i].p != NULL) {
    +#ifdef STATS_HASH
    +		STAT_HASH_LENGTH++;
    +#endif
    +		if (h->t[i].p == DELETED) {
    +			if (empty == NONE)
    +				empty = i;
    +		} else if (h->t[i].hv == hv &&
    +		    strncmp(h->t[i].p+h->info.key_offset, start,
    +			end - start) == 0 &&
    +		    (h->t[i].p+h->info.key_offset)[end-start] == '\0') {
    +			if (empty != NONE) {
    +				h->t[empty].hv = hv;
    +				h->t[empty].p = h->t[i].p;
    +				h->t[i].p = DELETED;
    +				return empty;
    +			} else {
    +#ifdef STATS_HASH
    +				STAT_HASH_POSITIVE++;
    +#endif
    +				return i;
    +			}
    +		}
    +		i += incr;
    +		if (i >= h->size)
    +			i -= h->size;
    +	}
    +
    +	/* Found an empty position.  */
    +	if (empty != NONE)
    +		i = empty;
    +	h->t[i].hv = hv;
    +	return i;
    +}
    +
    +unsigned int
    +ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
    +{
    +	unsigned int	i, incr;
    +	unsigned int	empty;
    +
    +#ifdef STATS_HASH
    +	STAT_HASH_LOOKUP++;
    +#endif
    +	empty = NONE;
    +	i = hv % h->size;
    +	incr = ((hv % (h->size-2)) & ~1) + 1;
    +	while (h->t[i].p != NULL) {
    +#ifdef STATS_HASH
    +		STAT_HASH_LENGTH++;
    +#endif
    +		if (h->t[i].p == DELETED) {
    +			if (empty == NONE)
    +				empty = i;
    +		} else if (h->t[i].hv == hv &&
    +		    memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
    +			if (empty != NONE) {
    +				h->t[empty].hv = hv;
    +				h->t[empty].p = h->t[i].p;
    +				h->t[i].p = DELETED;
    +				return empty;
    +			} else {
    +#ifdef STATS_HASH
    +				STAT_HASH_POSITIVE++;
    +#endif
    +			}	return i;
    +		}
    +		i += incr;
    +		if (i >= h->size)
    +			i -= h->size;
    +	}
    +
    +	/* Found an empty position.  */
    +	if (empty != NONE)
    +		i = empty;
    +	h->t[i].hv = hv;
    +	return i;
    +}
    +
    +unsigned int
    +ohash_qlookup(struct ohash *h, const char *s)
    +{
    +	const char *e = NULL;
    +	return ohash_qlookupi(h, s, &e);
    +}
    +
    +unsigned int
    +ohash_qlookupi(struct ohash *h, const char *s, const char **e)
    +{
    +	uint32_t hv;
    +
    +	hv = ohash_interval(s, e);
    +	return ohash_lookup_interval(h, s, *e, hv);
    +}
    +
    +#endif /*!HAVE_OHASH*/
    
    Property changes on: head/contrib/mandoc/compat_ohash.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_strlcat.c
    ===================================================================
    --- head/contrib/mandoc/compat_strlcat.c	(nonexistent)
    +++ head/contrib/mandoc/compat_strlcat.c	(revision 338826)
    @@ -0,0 +1,65 @@
    +#include "config.h"
    +
    +#if HAVE_STRLCAT
    +
    +int dummy;
    +
    +#else
    +
    +/*	$OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $	*/
    +
    +/*
    + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
    + *
    + * 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 <sys/types.h>
    +#include <string.h>
    +
    +/*
    + * Appends src to string dst of size siz (unlike strncat, siz is the
    + * full size of dst, not space left).  At most siz-1 characters
    + * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
    + * Returns strlen(src) + MIN(siz, strlen(initial dst)).
    + * If retval >= siz, truncation occurred.
    + */
    +size_t
    +strlcat(char *dst, const char *src, size_t siz)
    +{
    +	char *d = dst;
    +	const char *s = src;
    +	size_t n = siz;
    +	size_t dlen;
    +
    +	/* Find the end of dst and adjust bytes left but don't go past end */
    +	while (n-- != 0 && *d != '\0')
    +		d++;
    +	dlen = d - dst;
    +	n = siz - dlen;
    +
    +	if (n == 0)
    +		return(dlen + strlen(s));
    +	while (*s != '\0') {
    +		if (n != 1) {
    +			*d++ = *s;
    +			n--;
    +		}
    +		s++;
    +	}
    +	*d = '\0';
    +
    +	return(dlen + (s - src));	/* count does not include NUL */
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_strlcat.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/compat_strlcpy.c
    ===================================================================
    --- head/contrib/mandoc/compat_strlcpy.c	(nonexistent)
    +++ head/contrib/mandoc/compat_strlcpy.c	(revision 338826)
    @@ -0,0 +1,61 @@
    +#include "config.h"
    +
    +#if HAVE_STRLCPY
    +
    +int dummy;
    +
    +#else
    +
    +/*	$OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $	*/
    +
    +/*
    + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
    + *
    + * 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 <sys/types.h>
    +#include <string.h>
    +
    +/*
    + * Copy src to string dst of size siz.  At most siz-1 characters
    + * will be copied.  Always NUL terminates (unless siz == 0).
    + * Returns strlen(src); if retval >= siz, truncation occurred.
    + */
    +size_t
    +strlcpy(char *dst, const char *src, size_t siz)
    +{
    +	char *d = dst;
    +	const char *s = src;
    +	size_t n = siz;
    +
    +	/* Copy as many bytes as will fit */
    +	if (n != 0) {
    +		while (--n != 0) {
    +			if ((*d++ = *s++) == '\0')
    +				break;
    +		}
    +	}
    +
    +	/* Not enough room in dst, add NUL and traverse rest of src */
    +	if (n == 0) {
    +		if (siz != 0)
    +			*d = '\0';		/* NUL-terminate dst */
    +		while (*s++)
    +			;
    +	}
    +
    +	return(s - src - 1);	/* count does not include NUL */
    +}
    +
    +#endif
    
    Property changes on: head/contrib/mandoc/compat_strlcpy.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/demandoc.1
    ===================================================================
    --- head/contrib/mandoc/demandoc.1	(nonexistent)
    +++ head/contrib/mandoc/demandoc.1	(revision 338826)
    @@ -0,0 +1,108 @@
    +.\"	$Id: demandoc.1,v 1.8 2014/09/12 00:10:26 schwarze Exp $
    +.\"
    +.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    +.\"
    +.\" Permission to use, copy, modify, and distribute this software for any
    +.\" purpose with or without fee is hereby granted, provided that the above
    +.\" 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: September 12 2014 $
    +.Dt DEMANDOC 1
    +.Os
    +.Sh NAME
    +.Nm demandoc
    +.Nd emit only text of UNIX manuals
    +.Sh SYNOPSIS
    +.Nm demandoc
    +.Op Fl w
    +.Op Ar
    +.Sh DESCRIPTION
    +The
    +.Nm
    +utility emits only the text portions of well-formed
    +.Xr mdoc 7
    +and
    +.Xr man 7
    +.Ux
    +manual files.
    +.Pp
    +By default,
    +.Nm
    +parses standard input and outputs only text nodes, preserving line
    +and column position.
    +Escape sequences are omitted from the output.
    +.Pp
    +Its arguments are as follows:
    +.Bl -tag -width Ds
    +.It Fl w
    +Output a word list.
    +This outputs each word of text on its own line.
    +A
    +.Qq word ,
    +in this case, refers to whitespace-delimited terms beginning with at
    +least two letters and not consisting of any escape sequences.
    +Words have their leading and trailing punctuation
    +.Pq double-quotes, sentence punctuation, etc.
    +stripped.
    +.It Ar
    +The input files.
    +.El
    +.Pp
    +If a document is not well-formed, it is skipped.
    +.Pp
    +The
    +.Fl i ,
    +.Fl k ,
    +.Fl m ,
    +and
    +.Fl p
    +flags are silently discarded for calling compatibility with the
    +historical deroff.
    +.Sh EXIT STATUS
    +The
    +.Nm
    +utility exits with one of the following values:
    +.Pp
    +.Bl -tag -width Ds -compact
    +.It 0
    +No errors occurred.
    +.It 6
    +An operating system error occurred, for example memory exhaustion or an
    +error accessing input files.
    +Such errors cause
    +.Nm
    +to exit at once, possibly in the middle of parsing or formatting a file.
    +The output databases are corrupt and should be removed .
    +.El
    +.Sh EXAMPLES
    +The traditional usage of
    +.Nm
    +is for spell-checking manuals on
    +.Bx .
    +This is accomplished as follows (assuming British spelling):
    +.Pp
    +.Dl $ demandoc -w file.1 | spell -b
    +.Sh SEE ALSO
    +.Xr mandoc 1 ,
    +.Xr man 7 ,
    +.Xr mdoc 7
    +.Sh HISTORY
    +.Nm
    +replaces the historical deroff utility for handling modern
    +.Xr man 7
    +and
    +.Xr mdoc 7
    +documents.
    +.Sh AUTHORS
    +The
    +.Nm
    +utility was written by
    +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
    
    Property changes on: head/contrib/mandoc/demandoc.1
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/test-fgetln.c
    ===================================================================
    --- head/contrib/mandoc/test-fgetln.c	(nonexistent)
    +++ head/contrib/mandoc/test-fgetln.c	(revision 338826)
    @@ -0,0 +1,11 @@
    +#include <sys/types.h>
    +#include <stdio.h>
    +#include <unistd.h>
    +
    +int
    +main(void)
    +{
    +	size_t sz;
    +	fclose(stdin);
    +	return(NULL != fgetln(stdin, &sz));
    +}
    
    Property changes on: head/contrib/mandoc/test-fgetln.c
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:keywords
    ## -0,0 +1 ##
    +FreeBSD=%H
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc/predefs.in
    ===================================================================
    --- head/contrib/mandoc/predefs.in	(nonexistent)
    +++ head/contrib/mandoc/predefs.in	(revision 338826)
    @@ -0,0 +1,65 @@
    +/*	$Id: predefs.in,v 1.4 2012/07/18 10:39:19 schwarze Exp $ */
    +/*
    + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    + *
    + * Permission to use, copy, modify, and distribute this software for any
    + * purpose with or without fee is hereby granted, provided that the above
    + * 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.
    + */
    +
    +/*
    + * The predefined-string translation tables.  Each corresponds to a
    + * predefined strings from (e.g.) tmac/mdoc/doc-nroff.  The left-hand
    + * side corresponds to the input sequence (\*x, \*(xx and so on).  The
    + * right-hand side is what's produced by libroff.
    + *
    + * XXX - C-escape strings!
    + * XXX - update PREDEF_MAX in roff.c if adding more!
    + */
    +
    +PREDEF("Am", "&")
    +PREDEF("Ba", "\\fR|\\fP")
    +PREDEF("Ge", "\\(>=")
    +PREDEF("Gt", ">")
    +PREDEF("If", "infinity")
    +PREDEF("Le", "\\(<=")
    +PREDEF("Lq", "\\(lq")
    +PREDEF("Lt", "<")
    +PREDEF("Na", "NaN")
    +PREDEF("Ne", "\\(!=")
    +PREDEF("Pi", "pi")
    +PREDEF("Pm", "\\(+-")
    +PREDEF("Rq", "\\(rq")
    +PREDEF("left-bracket", "[")
    +PREDEF("left-parenthesis", "(")
    +PREDEF("lp", "(")
    +PREDEF("left-singlequote", "\\(oq")
    +PREDEF("q", "\\(dq")
    +PREDEF("quote-left", "\\(oq")
    +PREDEF("quote-right", "\\(cq")
    +PREDEF("R", "\\(rg")
    +PREDEF("right-bracket", "]")
    +PREDEF("right-parenthesis", ")")
    +PREDEF("rp", ")")
    +PREDEF("right-singlequote", "\\(cq")
    +PREDEF("Tm", "(Tm)")
    +PREDEF("Px", "POSIX")
    +PREDEF("Ai", "ANSI")
    +PREDEF("\'", "\\\'")
    +PREDEF("aa", "\\(aa")
    +PREDEF("ga", "\\(ga")
    +PREDEF("`",  "\\`")
    +PREDEF("lq", "\\(lq")
    +PREDEF("rq", "\\(rq")
    +PREDEF("ua", "\\(ua")
    +PREDEF("va", "\\(va")
    +PREDEF("<=", "\\(<=")
    +PREDEF(">=", "\\(>=")
    
    Property changes on: head/contrib/mandoc/predefs.in
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/plain
    \ No newline at end of property
    Index: head/contrib/mandoc
    ===================================================================
    --- head/contrib/mandoc	(nonexistent)
    +++ head/contrib/mandoc	(revision 338826)
    
    Property changes on: head/contrib/mandoc
    ___________________________________________________________________
    Added: svn:mergeinfo
    ## -0,0 +0,14 ##
       Merged /projects/bsd_rdma_4_9/contrib/mdocml:r319973-326168
       Merged /projects/clang350-import/contrib/mdocml:r274961-276476
       Merged /projects/clang360-import/contrib/mdocml:r277327-280030
       Merged /projects/clang370-import/contrib/mdocml:r287506-288928
       Merged /projects/clang380-import/contrib/mdocml:r292913-296412
       Merged /vendor/mdocml/dist:r241676-338817
       Merged /projects/clang390-import/contrib/mdocml:r303250-309123
       Merged /vendor/mandoc/dist:r338818-338821
       Merged /projects/clang-trunk/contrib/mdocml:r283596-287505
       Merged /projects/bectl/contrib/mdocml:r336666-337662
       Merged /projects/mpsutil/contrib/mdocml:r286179-290100
       Merged /projects/collation/contrib/mdocml:r286424-290491
       Merged /projects/clang400-import/contrib/mdocml:r311132-314524
       Merged /projects/clang500-import/contrib/mdocml:r316992-321352
    Index: head/usr.bin/mandoc/Makefile
    ===================================================================
    --- head/usr.bin/mandoc/Makefile	(revision 338825)
    +++ head/usr.bin/mandoc/Makefile	(revision 338826)
    @@ -1,100 +1,100 @@
     # $FreeBSD$
     
     .include <src.opts.mk>
     
    -MDOCMLDIR=	${SRCTOP}/contrib/mdocml
    -.PATH: ${MDOCMLDIR}
    +MANDOCDIR=	${SRCTOP}/contrib/mandoc
    +.PATH: ${MANDOCDIR}
     
     PROG=	mandoc
     MAN=	mandoc.1 eqn.7 mandoc_char.7 tbl.7 man.7 mdoc.7 roff.7
     MLINKS=	mandoc.1 mdocml.1
     .if ${MK_MAN_UTILS} != no
     MAN+=	apropos.1 makewhatis.8
     MLINKS+=	apropos.1 whatis.1
     LINKS=	${BINDIR}/mandoc ${BINDIR}/whatis \
     	${BINDIR}/mandoc ${BINDIR}/makewhatis \
     	${BINDIR}/mandoc ${BINDIR}/apropos
     .endif
     
     LIBMAN_SRCS=	man.c \
     		man_macro.c \
     		man_validate.c
     
     LIBMDOC_SRCS=	att.c \
     		lib.c \
     		mdoc.c \
     		mdoc_argv.c \
     		mdoc_macro.c \
     		mdoc_markdown.c \
     		mdoc_state.c \
     		mdoc_validate.c \
     		st.c \
     
     LIBROFF_SRCS=	eqn.c \
     		roff.c \
     		roff_html.c \
     		roff_term.c \
     		roff_validate.c \
     		tbl.c \
     		tbl_data.c \
     		tbl_layout.c \
     		tbl_opts.c \
     
     LIB_SRCS=	${LIBMAN_SRCS} \
     		${LIBMDOC_SRCS} \
     		${LIBROFF_SRCS} \
     		chars.c \
     		mandoc.c \
     		mandoc_aux.c \
     		mandoc_ohash.c \
     		mandoc_xr.c \
     		msec.c \
     		preconv.c \
     		read.c \
     		compat_recallocarray.c \
     
     HTML_SRCS=	eqn_html.c \
     		html.c \
     		man_html.c \
     		mdoc_html.c \
     		tbl_html.c
     
     MAN_SRCS=	mdoc_man.c
     
     TERM_SRCS=	eqn_term.c \
     		man_term.c \
     		mdoc_term.c \
     		term.c \
     		term_ascii.c \
     		term_ps.c \
     		term_tab.c \
     		tbl_term.c
     
     DBM_SRCS=	dbm.c \
     		dbm_map.c \
     		mansearch.c
     
     DBA_SRCS=	dba.c \
     		dba_array.c \
     		dba_read.c \
     		dba_write.c \
     		mandocdb.c
     
     SRCS=		${LIB_SRCS} \
     		${HTML_SRCS} \
     		${MAN_SRCS} \
     		${TERM_SRCS} \
     		${DBM_SRCS} \
     		${DBA_SRCS} \
     		main.c \
     		manpath.c \
     		out.c \
     		tag.c \
     		tree.c
     
     WARNS?=	3
     CFLAGS+= -DHAVE_CONFIG_H \
     	 -I${SRCTOP}/lib/libopenbsd/
     LIBADD=	openbsd z
     
     .include <bsd.prog.mk>