*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is 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_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_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 html_strlen(const char *);
+char *html_make_id(const struct roff_node *, int);
Index: vendor/mandoc/dist/lib.in
===================================================================
--- vendor/mandoc/dist/lib.in (revision 338818)
+++ vendor/mandoc/dist/lib.in (revision 338819)
@@ -1,125 +1,135 @@
-/* $Id: lib.in,v 1.19 2016/11/23 20:22:13 schwarze Exp $ */
+/* $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("libbluetooth", "Bluetooth Library (libbluetooth, \\-lbluetooth)")
LINE("libbsdxml", "eXpat XML parser library (libbsdxml, \\-lbsdxml)")
-LINE("libbsm", "Basic Security Module User Library (libbsm, \\-lbsm)")
-LINE("libc", "Standard C Library (libc, \\-lc)")
+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("libgpib", "General-Purpose Instrument Bus (GPIB) library (libgpib, \\-lgpib)")
+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("libipx", "IPX Address Conversion Support Library (libipx, \\-lipx)")
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", "Capture Library (libpcap, \\-lpcap)")
+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", "Process Manipulation Library (libproc, \\-lproc)")
+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("libstand", "Standalone Applications Library (libstand, \\-lstand)")
+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)")
Index: vendor/mandoc/dist/libmandoc.h
===================================================================
--- vendor/mandoc/dist/libmandoc.h (revision 338818)
+++ vendor/mandoc/dist/libmandoc.h (revision 338819)
@@ -1,73 +1,73 @@
-/* $Id: libmandoc.h,v 1.70 2017/07/08 17:52:49 schwarze Exp $ */
+/* $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(const struct roff *, const char *);
+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 *);
Index: vendor/mandoc/dist/main.c
===================================================================
--- vendor/mandoc/dist/main.c (revision 338818)
+++ vendor/mandoc/dist/main.c (revision 338819)
@@ -1,1185 +1,1253 @@
-/* $Id: main.c,v 1.301 2017/07/26 10:21:55 schwarze Exp $ */
+/* $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-2017 Ingo Schwarze
+ * 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
#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 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;
+ 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) {
- if (search.argmode == ARG_NAME)
- fs_search(&search, &conf.manpath,
- argc, argv, &res, &sz);
- else
- warnx("nothing appropriate");
+ 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) {
- /* For .so only; ignore failure. */
- (void)chdir(conf.manpath.paths[resp->ipath]);
+ else if (resp->form == FORM_SRC)
parse(&curp, fd, resp->file);
- } else
+ 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)
+ 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 = "more -s";
cp = mandoc_strdup(pager);
/*
* Parse the pager command into words.
* Intentionally do not do anything fancy here.
*/
argc = 0;
while (argc + 4 < MAX_PAGER_ARGS) {
argv[argc++] = cp;
cp = strchr(cp, ' ');
if (cp == NULL)
break;
*cp++ = '\0';
while (*cp == ' ')
cp++;
if (*cp == '\0')
break;
}
/* For less(1), use the tag file. */
if ((cmdlen = strlen(argv[0])) >= 4) {
cp = argv[0] + cmdlen - 4;
if (strcmp(cp, "less") == 0) {
argv[argc++] = mandoc_strdup("-T");
argv[argc++] = tag_files->tfn;
}
}
argv[argc++] = tag_files->ofn;
argv[argc] = NULL;
switch (pager_pid = fork()) {
case -1:
err((int)MANDOCLEVEL_SYSERR, "fork");
case 0:
break;
default:
(void)setpgid(pager_pid, 0);
(void)tcsetpgrp(tag_files->ofd, pager_pid);
#if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
tag_files->pager_pid = pager_pid;
return pager_pid;
}
/* The child process becomes the pager. */
if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
err((int)MANDOCLEVEL_SYSERR, "pager stdout");
close(tag_files->ofd);
- close(tag_files->tfd);
+ 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]);
}
Index: vendor/mandoc/dist/man.1
===================================================================
--- vendor/mandoc/dist/man.1 (revision 338818)
+++ vendor/mandoc/dist/man.1 (revision 338819)
@@ -1,384 +1,396 @@
-.\" $Id: man.1,v 1.29 2017/05/17 23:23:00 schwarze Exp $
+.\" $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: May 17 2017 $
+.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
-.Fl a .
+.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.
-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 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 intro 1 ,
+.Xr col 1 ,
+.Xr mandoc 1 ,
+.Xr ul 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
+.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 .
Index: vendor/mandoc/dist/man.7
===================================================================
--- vendor/mandoc/dist/man.7 (revision 338818)
+++ vendor/mandoc/dist/man.7 (revision 338819)
@@ -1,915 +1,902 @@
-.\" $Id: man.7,v 1.136 2017/06/25 11:42:02 schwarze Exp $
+.\" $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: June 25 2017 $
+.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 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 .
+.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
-and
-.Sx \&R .
+.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 \&R
-Text is rendered in roman (the default font).
-.Pp
-See also
-.Sx \&I
-and
-.Sx \&B .
.Ss \&RB
Text is rendered alternately in roman (the default font) and bold face.
Whitespace between arguments is omitted in output.
.Pp
See
.Sx \&BI
for an equivalent example.
.Pp
See also
.Sx \&BI ,
.Sx \&IB ,
.Sx \&BR ,
.Sx \&RI ,
and
.Sx \&IR .
.Ss \&RE
Explicitly close out the scope of a prior
.Sx \&RS .
The default left margin is restored to the state before that
.Sx \&RS
invocation.
.Pp
The syntax is as follows:
.Bd -filled -offset indent
.Pf \. Sx \&RE
.Op Ar level
.Ed
.Pp
Without an argument, the most recent
.Sx \&RS
block is closed out.
If
.Ar level
is 1, all open
.Sx \&RS
blocks are closed out.
Otherwise,
.Ar level No \(mi 1
nested
.Sx \&RS
blocks remain open.
.Ss \&RI
Text is rendered alternately in roman (the default font) and italics.
Whitespace between arguments is omitted in output.
.Pp
See
.Sx \&BI
for an equivalent example.
.Pp
See also
.Sx \&BI ,
.Sx \&IB ,
.Sx \&BR ,
.Sx \&RB ,
and
.Sx \&IR .
.Ss \&RS
Temporarily reset the default left margin.
This has the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&RS
.Op Ar width
.Ed
.Pp
The
.Ar width
argument is a
.Xr roff 7
scaling width.
If not specified, the saved or default width is used.
.Pp
See also
.Sx \&RE .
.Ss \&SB
Text is rendered in small size (one point smaller than the default font)
bold face.
.Ss \&SH
Begin a section.
The scope of a section is only closed by another section or the end of
file.
The paragraph left-margin width is reset to the default.
.Ss \&SM
Text is rendered in small size (one point smaller than the default
font).
.Ss \&SS
Begin a sub-section.
The scope of a sub-section is closed by a subsequent sub-section,
section, or end of file.
The paragraph left-margin width is reset to the default.
.Ss \&TH
Sets the title of the manual page for use in the page header
and footer with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&TH
.Ar title section date
.Op Ar source Op Ar volume
.Ed
.Pp
Conventionally, the document
.Ar title
is given in all caps.
The recommended
.Ar date
format is
.Sy YYYY-MM-DD
as specified in the ISO-8601 standard;
if the argument does not conform, it is printed verbatim.
If the
.Ar date
is empty or not specified, the current date is used.
The optional
.Ar source
string specifies the organisation providing the utility.
When unspecified,
.Xr mandoc 1
uses its
.Fl Ios
argument.
The
.Ar volume
string replaces the default rendered volume, which is dictated by the
manual section.
.Pp
Examples:
.Pp
.Dl \&.TH CVS 5 "1992-02-12" GNU
.Ss \&TP
Begin a paragraph where the head, if exceeding the indentation width, is
followed by a newline; if not, the body follows on the same line after a
buffer to the indentation width.
Subsequent output lines are indented.
The syntax is as follows:
.Bd -filled -offset indent
.Pf \. Sx \&TP
.Op Ar width
.Ed
.Pp
The
.Ar width
argument is a
.Xr roff 7
scaling width.
If specified, it's saved for later paragraph left-margins; if
unspecified, the saved or default width is used.
.Pp
See also
.Sx \&HP ,
.Sx \&IP ,
.Sx \&LP ,
.Sx \&P ,
and
.Sx \&PP .
.Ss \&UC
Sets the volume for the footer for compatibility with man pages from
.Bx
releases.
The optional first argument specifies which release it is from.
.Ss \&UE
End a uniform resource identifier block.
This is a non-standard GNU extension, included only for compatibility.
See
.Sx \&UE .
.Ss \&UR
Begin a uniform resource identifier block.
This is a non-standard GNU extension, included only for compatibility.
It has the following syntax:
.Bd -literal -offset indent
.Pf \. Sx \&UR Ar uri
link description to be shown
.Pf \. Sx UE
.Ed
.Ss \&fi
End literal mode begun by
.Sx \&nf .
.Ss \&in
Indent relative to the current indentation:
.Pp
.D1 Pf \. Sx \&in Op Ar width
.Pp
If
.Ar width
is signed, the new offset is relative.
Otherwise, it is absolute.
This value is reset upon the next paragraph, section, or sub-section.
.Ss \&nf
Begin literal mode: all subsequent free-form lines have their end of
line boundaries preserved.
May be ended by
.Sx \&fi .
Literal mode is implicitly ended by
.Sx \&SH
or
.Sx \&SS .
.Sh MACRO SYNTAX
The
.Nm
macros are classified by scope: line scope or block scope.
Line macros are only scoped to the current line (and, in some
situations, the subsequent line).
Block macros are scoped to the current line and subsequent lines until
closed by another block macro.
.Ss Line Macros
Line macros are generally scoped to the current line, with the body
consisting of zero or more arguments.
If a macro is scoped to the next line and the line arguments are empty,
the next line, which must be text, is used instead.
Thus:
.Bd -literal -offset indent
\&.I
foo
.Ed
.Pp
is equivalent to
.Sq \&.I foo .
If next-line macros are invoked consecutively, only the last is used.
If a next-line macro is followed by a non-next-line macro, an error is
raised.
.Pp
The syntax is as follows:
.Bd -literal -offset indent
\&.YO \(lBbody...\(rB
\(lBbody...\(rB
.Ed
.Bl -column "MacroX" "ArgumentsX" "ScopeXXXXX" "CompatX" -offset indent
.It Em Macro Ta Em Arguments Ta Em Scope Ta Em Notes
.It Sx \&AT Ta <=1 Ta current Ta \&
.It Sx \&B Ta n Ta next-line Ta \&
.It Sx \&BI Ta n Ta current Ta \&
.It Sx \&BR Ta n Ta current Ta \&
.It Sx \&DT Ta 0 Ta current Ta \&
.It Sx \&EE Ta 0 Ta current Ta compat
.It Sx \&EX Ta 0 Ta current Ta compat
.It Sx \&I Ta n Ta next-line Ta \&
.It Sx \&IB Ta n Ta current Ta \&
.It Sx \&IR Ta n Ta current Ta \&
.It Sx \&OP Ta 0, 1 Ta current Ta compat
.It Sx \&PD Ta 1 Ta current Ta \&
-.It Sx \&R Ta n Ta next-line Ta \&
.It Sx \&RB Ta n Ta current Ta \&
.It Sx \&RI Ta n Ta current Ta \&
.It Sx \&SB Ta n Ta next-line Ta \&
.It Sx \&SM Ta n Ta next-line Ta \&
.It Sx \&TH Ta >1, <6 Ta current Ta \&
.It Sx \&UC Ta <=1 Ta current Ta \&
.It Sx \&fi Ta 0 Ta current Ta compat
.It Sx \&in Ta 1 Ta current Ta compat
.It Sx \&nf Ta 0 Ta current Ta compat
.El
.Pp
Macros marked as
.Qq compat
are included for compatibility with the significant corpus of existing
manuals that mix dialects of roff.
These macros should not be used for portable
.Nm
manuals.
.Ss Block Macros
Block macros comprise a head and body.
As with in-line macros, the head is scoped to the current line and, in
one circumstance, the next line (the next-line stipulations as in
.Sx Line Macros
apply here as well).
.Pp
The syntax is as follows:
.Bd -literal -offset indent
\&.YO \(lBhead...\(rB
\(lBhead...\(rB
\(lBbody...\(rB
.Ed
.Pp
The closure of body scope may be to the section, where a macro is closed
by
.Sx \&SH ;
sub-section, closed by a section or
.Sx \&SS ;
part, closed by a section, sub-section, or
.Sx \&RE ;
or paragraph, closed by a section, sub-section, part,
.Sx \&HP ,
.Sx \&IP ,
.Sx \&LP ,
.Sx \&P ,
.Sx \&PP ,
or
.Sx \&TP .
No closure refers to an explicit block closing macro.
.Pp
As a rule, block macros may not be nested; thus, calling a block macro
while another block macro scope is open, and the open scope is not
implicitly closed, is syntactically incorrect.
.Bl -column "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" "compatX" -offset indent
.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope Ta Em Notes
.It Sx \&HP Ta <2 Ta current Ta paragraph Ta \&
.It Sx \&IP Ta <3 Ta current Ta paragraph Ta \&
.It Sx \&LP Ta 0 Ta current Ta paragraph Ta \&
.It Sx \&P Ta 0 Ta current Ta paragraph Ta \&
.It Sx \&PP Ta 0 Ta current Ta paragraph Ta \&
.It Sx \&RE Ta 0 Ta current Ta none Ta compat
.It Sx \&RS Ta 1 Ta current Ta part Ta compat
.It Sx \&SH Ta >0 Ta next-line Ta section Ta \&
.It Sx \&SS Ta >0 Ta next-line Ta sub-section Ta \&
.It Sx \&TP Ta n Ta next-line Ta paragraph Ta \&
.It Sx \&UE Ta 0 Ta current Ta none Ta compat
.It Sx \&UR Ta 1 Ta current Ta part Ta compat
.El
.Pp
Macros marked
.Qq compat
are as mentioned in
.Sx Line Macros .
.Pp
If a block macro is next-line scoped, it may only be followed by in-line
macros for decorating text.
.Ss Font handling
In
.Nm
documents, both
.Sx Physical markup
macros and
.Xr roff 7
.Ql \ef
font escape sequences can be used to choose fonts.
In text lines, the effect of manual font selection by escape sequences
only lasts until the next macro invocation; in macro lines, it only lasts
until the end of the macro scope.
Note that macros like
.Sx \&BR
open and close a font scope for each argument.
.Sh SEE ALSO
.Xr man 1 ,
.Xr mandoc 1 ,
.Xr eqn 7 ,
.Xr mandoc_char 7 ,
.Xr mdoc 7 ,
.Xr roff 7 ,
.Xr tbl 7
.Sh HISTORY
The
.Nm
language first appeared as a macro package for the roff typesetting
system in
.At v7 .
It was later rewritten by James Clark as a macro package for groff.
Eric S. Raymond wrote the extended
.Nm
macros for groff in 2007.
The stand-alone implementation that is part of the
.Xr mandoc 1
utility written by Kristaps Dzonsons appeared in
.Ox 4.6 .
.Sh AUTHORS
This
.Nm
reference was written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
.Sh CAVEATS
Do not use this language.
Use
.Xr mdoc 7 ,
instead.
Index: vendor/mandoc/dist/man.cgi.8
===================================================================
--- vendor/mandoc/dist/man.cgi.8 (revision 338818)
+++ vendor/mandoc/dist/man.cgi.8 (revision 338819)
@@ -1,421 +1,426 @@
-.\" $Id: man.cgi.8,v 1.22 2017/03/18 16:48:24 schwarze Exp $
+.\" $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: March 18 2017 $
+.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 -
-eiher because it violates the query syntax, or because
+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 element.
.It Pa /man/footer.html
An optional file containing static HTML code to be inserted right
before closing the 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.
+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.
Index: vendor/mandoc/dist/man.conf.5
===================================================================
--- vendor/mandoc/dist/man.conf.5 (revision 338818)
+++ vendor/mandoc/dist/man.conf.5 (revision 338819)
@@ -1,131 +1,135 @@
-.\" $Id: man.conf.5,v 1.4 2016/12/28 22:52:17 schwarze Exp $
+.\" $Id: man.conf.5,v 1.5 2017/08/22 18:17: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.
.\"
-.Dd $Mdocdate: December 28 2016 $
+.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, but not strictly required for
-.Xr man 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
Index: vendor/mandoc/dist/man_html.c
===================================================================
--- vendor/mandoc/dist/man_html.c (revision 338818)
+++ vendor/mandoc/dist/man_html.c (revision 338819)
@@ -1,670 +1,646 @@
-/* $Id: man_html.c,v 1.145 2017/06/25 11:42:02 schwarze Exp $ */
+/* $Id: man_html.c,v 1.153 2018/07/27 17:49:31 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons
- * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze
+ * 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 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_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 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 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 tag *t;
+ 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, man->first, h);
+ print_man_head(&man->meta, h);
print_tagq(h, t);
print_otag(h, TAG_BODY, "");
}
- man_root_pre(&man->meta, man->first, h);
+ man_root_pre(&man->meta, h);
t = print_otag(h, TAG_DIV, "c", "manual-text");
- print_man_nodelist(&man->meta, man->first->child, h);
+ print_man_nodelist(&man->meta, n, h);
print_tagq(h, t);
- man_root_post(&man->meta, man->first, h);
+ man_root_post(&man->meta, h);
print_tagq(h, NULL);
}
static void
-print_man_head(MAN_ARGS)
+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 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)
+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(MAN_ARGS)
+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);
+ id = html_make_id(n, 1);
print_otag(h, TAG_H1, "cTi", "Sh", id);
if (id != NULL)
- print_otag(h, TAG_A, "chR", "selflink", id);
- free(id);
+ 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);
+ id = html_make_id(n, 1);
print_otag(h, TAG_H2, "cTi", "Ss", id);
if (id != NULL)
- print_otag(h, TAG_A, "chR", "selflink", id);
- free(id);
+ 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, "c", "It-tag");
+ 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, "c", "It-tag");
+ 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)
{
- 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);
+ 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)
{
- 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);
+ 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;
}
Index: vendor/mandoc/dist/man_term.c
===================================================================
--- vendor/mandoc/dist/man_term.c (revision 338818)
+++ vendor/mandoc/dist/man_term.c (revision 338819)
@@ -1,1101 +1,1116 @@
-/* $Id: man_term.c,v 1.209 2017/07/31 15:19:06 schwarze Exp $ */
+/* $Id: man_term.c,v 1.211 2018/06/10 15:12:35 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons
- * Copyright (c) 2010-2015, 2017 Ingo Schwarze
+ * Copyright (c) 2010-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 "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))
+ 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->tok == MAN_SH && n->body->child == NULL))
+ 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);
}
Index: vendor/mandoc/dist/man_validate.c
===================================================================
--- vendor/mandoc/dist/man_validate.c (revision 338818)
+++ vendor/mandoc/dist/man_validate.c (revision 338819)
@@ -1,494 +1,494 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons
- * Copyright (c) 2010, 2012-2017 Ingo Schwarze
+ * Copyright (c) 2010, 2012-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