Index: vendor/mandoc/20190723/Makefile.depend =================================================================== --- vendor/mandoc/20190723/Makefile.depend (nonexistent) +++ vendor/mandoc/20190723/Makefile.depend (revision 350350) @@ -0,0 +1,81 @@ +arch.o: arch.c config.h roff.h +att.o: att.c config.h roff.h libmdoc.h +catman.o: catman.c config.h compat_fts.h +cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h mansearch.h cgi.h +chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h +compat_err.o: compat_err.c config.h +compat_fts.o: compat_fts.c config.h compat_fts.h +compat_getline.o: compat_getline.c config.h +compat_getsubopt.o: compat_getsubopt.c config.h +compat_isblank.o: compat_isblank.c config.h +compat_mkdtemp.o: compat_mkdtemp.c config.h +compat_ohash.o: compat_ohash.c config.h compat_ohash.h +compat_progname.o: compat_progname.c config.h +compat_reallocarray.o: compat_reallocarray.c config.h +compat_recallocarray.o: compat_recallocarray.c config.h +compat_strcasestr.o: compat_strcasestr.c config.h +compat_stringlist.o: compat_stringlist.c config.h compat_stringlist.h +compat_strlcat.o: compat_strlcat.c config.h +compat_strlcpy.o: compat_strlcpy.c config.h +compat_strndup.o: compat_strndup.c config.h +compat_strsep.o: compat_strsep.c config.h +compat_strtonum.o: compat_strtonum.c config.h +compat_vasprintf.o: compat_vasprintf.c config.h +dba.o: dba.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mansearch.h dba_write.h dba_array.h dba.h +dba_array.o: dba_array.c mandoc_aux.h dba_write.h dba_array.h +dba_read.o: dba_read.c mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h +dba_write.o: dba_write.c config.h dba_write.h +dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h +dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.h +demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h mandoc_parse.h +eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h eqn.h libmandoc.h eqn_parse.h +eqn_html.o: eqn_html.c config.h mandoc.h roff.h eqn.h out.h html.h +eqn_term.o: eqn_term.c config.h eqn.h out.h term.h +html.o: html.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h out.h html.h manconf.h main.h +lib.o: lib.c config.h roff.h libmdoc.h lib.in +main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h mandoc_parse.h tag.h main.h manconf.h mansearch.h +man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h +man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h tag.h main.h +man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h roff_int.h +mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h +mandoc_msg.o: mandoc_msg.c config.h mandoc.h +mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h +mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h +mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h +mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h manconf.h mansearch.h dba_array.h dba.h +manpath.o: manpath.c config.h mandoc_aux.h mandoc.h manconf.h +mansearch.o: mansearch.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h +mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h html.h main.h +mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h +mdoc_markdown.o: mdoc_markdown.c mandoc_aux.h mandoc.h roff.h mdoc.h main.h +mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_term.o: mdoc_term.c config.h mandoc_aux.h roff.h mdoc.h out.h term.h tag.h main.h +mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +msec.o: msec.c config.h mandoc.h libmandoc.h msec.in +out.o: out.c config.h mandoc_aux.h tbl.h out.h +preconv.o: preconv.c config.h mandoc.h roff.h mandoc_parse.h libmandoc.h +read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h libmandoc.h roff_int.h +roff.o: roff.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mandoc_parse.h libmandoc.h roff_int.h tbl_parse.h eqn_parse.h predefs.in +roff_html.o: roff_html.c mandoc.h roff.h out.h html.h +roff_term.o: roff_term.c mandoc.h roff.h out.h term.h +roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h +soelim.o: soelim.c config.h compat_stringlist.h +st.o: st.c config.h mandoc.h roff.h libmdoc.h +tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h tag.h +tbl.o: tbl.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h +tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h +tbl_html.o: tbl_html.c config.h mandoc.h roff.h tbl.h out.h html.h +tbl_layout.o: tbl_layout.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h +tbl_opts.o: tbl_opts.c config.h mandoc.h tbl.h libmandoc.h tbl_int.h +tbl_term.o: tbl_term.c config.h mandoc.h tbl.h out.h term.h +term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h +term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h manconf.h main.h +term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h manconf.h main.h +term_tab.o: term_tab.c mandoc_aux.h out.h term.h +tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h tbl.h eqn.h main.h Property changes on: vendor/mandoc/20190723/Makefile.depend ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/TODO =================================================================== --- vendor/mandoc/20190723/TODO (nonexistent) +++ vendor/mandoc/20190723/TODO (revision 350350) @@ -0,0 +1,583 @@ +************************************************************************ +* Official mandoc TODO. +* $Id: TODO,v 1.295 2019/06/11 16:04:36 schwarze Exp $ +************************************************************************ + +Many issues are annotated for difficulty as follows: + + - loc = locality of the issue + * single file issue, affects file only, or very few + ** single module issue, affects several files of one module + *** cross-module issue, significantly impacts multiple modules + and may require substantial changes to internal interfaces + - exist = difficulty of the existing code in this area + * affected code is straightforward and easy to read and change + ** affected code is somewhat complex, but once you understand + the design, not particularly difficult to understand + *** affected code uses a special, exceptionally tricky design + - algo = difficulty of the new algorithm to be written + * the required logic and code is straightforward + ** the required logic is somewhat complex and needs a careful design + *** the required logic is exceptionally tricky, + maybe an approach to solve that is not even known yet + - size = the amount of code to be written or changed + * a small number of lines (at most 100, usually much less) + ** a considerable amount of code (several dozen to a few hundred) + *** a large amount of code (many hundreds, maybe thousands) + - imp = importance of the issue + * mostly for completeness + ** would be nice to have + *** issue causes considerable inconvenience + +Obviously, as the issues have not been solved yet, these annotations +are mere guesses, and some may be wrong. + +************************************************************************ +* missing features +************************************************************************ + +--- missing roff features ---------------------------------------------- + +- .ad (adjust margins) + .ad l -- adjust left margin only (flush left) + .ad r -- adjust right margin only (flush right) + .ad c -- center text on line + .ad b -- adjust both margins (alias: .ad n) + .na -- temporarily disable adjustment without changing the mode + .ad -- re-enable adjustment without changing the mode + Adjustment mode is ignored while in no-fill mode (.nf). + loc *** exist *** algo ** size ** imp ** (parser reorg would help) + +- .fc (field control) + found by naddy@ in xloadimage(1) + loc ** exist *** algo * size * imp * + +- .ns (no-space mode) occurs in xine-config(1) + when implementing this, also let .TH set it + reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500 + loc *** exist *** algo *** size ** imp * + +- \w'' improve width measurements + would not be very useful without an expression parser, see below + needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100 + loc ** exist *** algo *** size * imp *** + +- .als only works for macros in mandoc, not for user-defined strings. + Also, the "val" field in struct roffkv would have to be replaced + with a pointer to a reference-counted wrapper, and an alias + would have to point to the same wrapper as the original. + .als to undefined does nothing; the alias is not created. + .rm'ing the original leaves the alias to point to the old value. + .de .als .de changes both, but + .de .als .rm .de only changes the new value, not the alias. + Found in groffer(1) version 1.19 + Jan Stary 20 Apr 2019 20:16:54 +0200 + loc * exist ** algo ** size ** imp * + +- roff string condition comparisons fail when vars contain quotes: + .ds s ' + .if '\*s'' \&... + hard to fix because of the basic architecture (string replacement + happens before roff(7) syntax parsing) + Found in groffer(1) version 1.19 + Jan Stary 20 Apr 2019 20:16:54 +0200 + loc * exist *** algo *** size ** imp * + +--- missing mdoc features ---------------------------------------------- + +- .Bl -column .Xo support is missing + ultimate goal: + restore .Xr and .Dv to + lib/libc/compat-43/sigvec.3 + lib/libc/gen/signal.3 + lib/libc/sys/sigaction.2 + loc * exist *** algo *** size * imp ** + +- edge case: decide how to deal with blk_full bad nesting, e.g. + .Sh .Nm .Bk .Nm .Ek .Sh found by jmc@ in ssh-keygen(1) + from jmc@ Wed, 14 Jul 2010 18:10:32 +0100 + loc * exist *** algo *** size ** imp ** + +- .Bd -filled should not be the same as .Bd -ragged, but align both + the left and right margin. In groff, it is implemented in terms + of .ad b, which we don't have either. Found in cksum(1). + loc *** exist *** algo ** size ** imp ** (parser reorg would help) + +- implement blank `Bl -column', such as + .Bl -column + .It foo Ta bar + .El + loc * exist *** algo *** size * imp * + +- explicitly disallow nested `Bl -column', which would clobber internal + flags defined for struct mdoc_macro + loc * exist * algo * size * imp ** + +- In .Bl -column .It, the end of the line probably has to be regarded + as an implicit .Ta, if there could be one, see the following mildly + ugly code from login.conf(5): + .Bl -column minpasswordlen program xetcxmotd + .It path Ta path Ta value of Dv _PATH_DEFPATH + .br + Default search path. + reported by Michal Mazurek + via jmc@ Thu, 7 Apr 2011 16:00:53 +0059 + loc * exist *** algo ** size * imp ** + +- inside `.Bl -column' phrases, punctuation is handled like normal + text, e.g. `.Bl -column .It Fl x . Ta ...' should give "-x -." + +- inside `.Bl -column' phrases, TERMP_IGNDELIM handling by `Pf' + is not safe, e.g. `.Bl -column .It Pf a b .' gives "ab." + but should give "ab ." + +- prohibit `Nm' from having non-text HEAD children + (e.g., NetBSD mDNSShared/dns-sd.1) + (mdoc_html.c and mdoc_term.c `Nm' handlers can be slightly simplified) + +- support translated section names + e.g. x11/scrotwm scrotwm_es.1:21:2: error: NAME section must be first + that one uses NOMBRE because it is spanish... + deraadt tends to think that section-dependent macro behaviour + is a bad idea in the first place, so this may be irrelevant + loc ** exist ** algo ** size * imp ** + +- When there is free text in the SYNOPSIS and that free text contains + the .Nm macro, groff somehow understands to treat the .Nm as an in-line + macro, while mandoc treats it as a block macro and breaks the line. + No idea how the logic for distinguishing in-line and block instances + should be, needs investigation. + uqs@ Thu, 2 Jun 2011 11:03:51 +0200 + uqs@ Thu, 2 Jun 2011 11:33:35 +0200 + loc * exist ** algo *** size * imp ** + +--- missing man features ----------------------------------------------- + +- groff_www(7) .MTO and .URL + These macros were used by the GNU grep(1) man page. + The groff_www(7) manual page itself uses them, too. + We should probably *not* add them to mandoc. + Just mentioning this here to keep track of the abuse. + Laura Morales 20 Apr 2018 07:33:02 +0200 + loc ** exist * algo * size ** imp * + +--- missing tbl features ----------------------------------------------- + +- vertical centering in cells vertically spanned with ^ + pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200 + loc * exist *** algo *** size ** imp * + +- support mdoc(7) and man(7) macros inside tbl(7) code; + probably requires the parser reorg and letting tbl(7) + use roff_node such that macro sets can mix; + informed by bapt@ that FreeBSD needs this: 3 Jan 2015 23:32:23 +0100 + loc *** exist ** algo *** size ** imp *** + +- look at the POSIX manuals in the books/man-pages-posix port, + they use some unsupported tbl(7) features, mostly macros in tbl(7). + loc * exist ** algo ** size ** imp *** + +- look what Joerg Schilling manual pages use + Thu, 19 Mar 2015 18:31:48 +0100 + +--- missing eqn features ----------------------------------------------- + +- In a matrix, break the output line after each matrix line. + Found in the discussion at CDBUG 2015. Suggested by Avi Weinstock. + This may not be the ideal solution after all: eqn(7) matrices + are lists of columns, so Avi's proposal would show each *column* + on its own *line*, which is likely to cause confusion. + A better solution, but much harder to implement, would be to + actually show the coordinates of column vectors on different + terminal output lines, using the clumnated output facilities + developed for .Bl -tag, .Bl -column, and also used for tbl(7). + loc * exist * algo ** size ** imp ** + +- The "size" keyword is parsed, but ignored by the formatter. + loc * exist * algo * size * imp * + +- The spacing characters `~', `^', and tab are currently ignored, + see User's Guide (Second Edition) page 2 section 4. + loc * exist * algo ** size * imp ** + +- Mark and lineup are parsed and ignored, + see User's Guide (Second Edition) page 5 section 15. + loc ** exist ** algo ** size ** imp ** + +- GNU eqn converts some operators to special characters, for example, + input HYPHEN-MINUS becomes output \(mi, unless it is part of a + quoted word. mandoc(1) only does this when the operator is + surrounded by blanks, not when it is part of an unquoted word. + Also, check whether there are more such cases (e.g., +?). + reported by bentley@ 20 Jun 2017 02:04:29 -0600 + loc * exist ** algo ** size * imp * + +- Primes, opprime, and ' + bentley@ Thu, 13 Jul 2017 23:14:20 -0600 + +--- missing misc features ---------------------------------------------- + +- man -ks 1,8 route; kn@ Jul 13, 2018 orally + +- italic correction (\/) in PostScript mode + Werner LEMBERG on groff at gnu dot org Sun, 10 Nov 2013 12:47:46 + loc ** exist ** algo * size * imp * + +- change the default PAGER to more -Es and use the pager + even for apropos title line output; req by bapt@ + loc * exist * algo * size * imp *** + +- clean up escape sequence handling, creating three classes: + (1) fully implemented, or parsed and ignored without loss of content + (2) unimplemented, potentially causing loss of content + or serious mangling of formatting (e.g. \n) -> ERROR + see textproc/mgdiff(1) for nice examples + (3) undefined, just output the character -> perhaps WARNING + loc *** exist ** algo ** size ** imp *** (parser reorg helps) + +- kettenis wants base roff, ms, and me Fri, 1 Jan 2010 22:13:15 +0100 (CET) + loc ** exist ** algo ** size *** imp * + +--- compatibility checks ----------------------------------------------- + +- is .Bk implemented correctly in modern groff? + sobrado@ Tue, 19 Apr 2011 22:12:55 +0200 + +- compare output to Heirloom roff, Solaris roff, and + http://repo.or.cz/w/neatroff.git http://litcave.rudi.ir/ + +- look at AT&T DWB http://www2.research.att.com/sw/download + Carsten Kunze has patches + Mon, 4 Aug 2014 17:01:28 +0200 + ported version: https://github.com/n-t-roff/DWB3.3 + Carsten Kunze Wed, 22 Apr 2015 11:21:43 +0200 + +- look at pages generated from reStructeredText, e.g. devel/mercurial hg(1) + These are a weird mixture of man(7) and custom autogenerated low-level + roff stuff. Figure out to what extent we can cope. + For details, see http://docutils.sourceforge.net/rst.html + noted by stsp@ Sat, 24 Apr 2010 09:17:55 +0200 + reminded by nicm@ Mon, 3 May 2010 09:52:41 +0100 + +- look at pages generated from ronn(1) github.com/rtomayko/ronn + (based on markdown) + +- look at pages generated from Texinfo source by yat2m, e.g. security/gnupg + First impression is not that bad. + +- look at pages generated by pandoc; see + https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/Writers/Man.hs + porting planned by kili@ Thu, 19 Jun 2014 19:46:28 +0200 + +- check compatibility with Plan9: + http://swtch.com/usr/local/plan9/tmac/tmac.an + http://swtch.com/plan9port/man/man7/man.html + "Anthony J. Bentley" 28 Dec 2010 21:58:40 -0700 + +- check compatibility with COHERENT troff: + http://www.nesssoftware.com/home/mwc/source.php + +- check compatibility with the man(7) formatter + https://raw.githubusercontent.com/rofl0r/hardcore-utils/master/man.c + +- check compatibility with + http://ikiwiki.info/plugins/contrib/mandoc/ + https://github.com/schmonz/ikiwiki/compare/mandoc + Amitai Schlair Mon, 19 May 2014 14:05:53 -0400 + +- check compatibility with + https://git.sr.ht/~sircmpwn/scdoc + +- check features of the Slackware man.conf(5) format + Carsten Kunze Wed, 11 Mar 2015 17:57:24 +0100 + +************************************************************************ +* formatting issues: ugly output +************************************************************************ + +- revisit empty in-line macros + look at the difference between "Em x Em ." and "Sq x Em ." + Carsten Kunze Fri, 12 Dec 2014 00:15:41 +0100 + loc *** exist *** algo *** size * imp ** + +- a column list with blank `Ta' cells triggers a spurious + start-with-whitespace printing of a newline + +- In .Bl -column, .It a"bc" + shows the quotes in groff, but not in mandoc + loc * exist *** algo ** size * imp ** + +- In .Bl -column, + .It Em AuthenticationKey Length + ought to render "Key Length" with emphasis, too, + see OpenBSD iked.conf(5). + reported again Nicolas Joly via wiz@ Wed, 12 Oct 2011 00:20:00 +0200 + loc * exist *** algo *** size ** imp *** + +- empty phrases in .Bl column produce too few blanks + try e.g. .Bl -column It Ta Ta + reported by millert Fri, 02 Apr 2010 16:13:46 -0400 + loc * exist *** algo *** size * imp ** + +- .%T can have trailing punctuation. Currently, it puts the trailing + punctuation into a trailing MDOC_TEXT element inside its own scope. + That element should rather be outside its scope, such that the + punctuation does not get underlines. This is not trivial to + implement because .%T then needs some features of in_line_eoln() - + slurp all arguments into one single text element - and one feature + of in_line() - put trailing punctuation out of scope. + Found in mount_nfs(8) and exports(5), search for "Appendix". + loc ** exist ** algo *** size * imp ** + +- Trailing punctuation after .%T triggers EOS spacing, at least + outside .Rs (eek!). Simply setting ARGSFL_DELIM for .%T is not + the right solution, it sends mandoc into an endless loop. + reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100 + loc * exist ** algo ** size * imp ** + +- global variables in the SYNOPSIS of section 3 pages + .Vt vs .Vt/.Va vs .Ft/.Va vs .Ft/.Fa ... + from kristaps@ Tue, 08 Jun 2010 11:13:32 +0200 + +- implicit whitespace around inline equations + example code: where '$times$' denotes matrix multiplication + must not have an HTML line break, nor a blank, before + partial solution: html.c {"math", HTML_NLINSIDE | HTML_INDENT}, + bentley@ Thu, 13 Jul 2017 19:00:59 -0600 + +- in enclosures, mandoc sometimes fancies a bogus end of sentence + reminded by jmc@ Thu, 23 Sep 2010 18:13:39 +0059 + loc * exist ** algo *** size * imp *** + +- a line starting with "\fB something" counts as starting with whitespace + and triggers a line break; found in audio/normalize-mp3(1) + This will become easier once escape sequences are represented + by syntax tree nodes. + loc ** exist * algo ** size * imp ** + +- formatting /usr/local/man/man1/latex2man.1 with groff and mandoc + reveals lots of bugs both in groff and mandoc... + reported by bentley@ Wed, 22 May 2013 23:49:30 -0600 + +--- PostScript and PDF issues ------------------------------------------ + +- PDF output doesn't use a monospaced font for .Bd -literal + Example: "mandoc -Tpdf afterboot.8 > output.pdf && pdfviewer output.pdf". + Search the text "Routing tables". + Also check what PostScript mode does when fixing this. + reported by juanfra@ Wed, 04 Jun 2014 21:44:58 +0200 + instructions from juanfra@ Wed, 11 Jun 2014 02:21:01 +0200 + add a new <> block to the PDF files with /BaseFont /Courier + and change the /Name from /F0 to the new font (/F5 (?)). + re-reported by tb@ Mon, 16 Mar 2015 16:47:21 +0100 + loc * exist ** algo ** size * imp ** + +--- HTML issues -------------------------------------------------------- + +- .Bf at the beginning of a paragraph inserts a bogus 1ex horizontal + space, see for example random(3). Introduced in + http://mdocml.bsd.lv/cgi-bin/cvsweb/mdoc_html.c.diff?r1=1.91&r2=1.92 + reported by deraadt@ Mon, 28 Sep 2015 20:14:13 -0600 (MDT) + loc ** exist ** algo ** size * imp * + +- jsg on icb, Nov 3, 2014: + try to guess Xr in man(7) for hyperlinking + and render them with + https://github.com/Debian/debiman/issues/15 + loc * exist * algo ** size ** imp ** + +- The tables used to render the three-part page headers actually force + the width of the to the max-width given for . + Not yet sure how to fix that... + Observed by an Anonymous Coward on undeadly.org: + http://undeadly.org/cgi?action=article&sid=20140925064244&pid=1 + loc * exist * algo ** size * imp *** + +- generate tags in HTML + idea from florian@ Tue, 7 Apr 2015 00:26:28 +0000 + may be possible to implement with .Lk img://something.png alt_text + +- check https://github.com/trentm/mdocml + +************************************************************************ +* formatting issues: gratuitous differences +************************************************************************ + +- .Fn reopens a new scope after punctuation in mandoc, + but closes its scope for good in groff. + Do we want to change mandoc or groff? + Steffen Nurpmeso Sat, 08 Nov 2014 13:34:59 +0100 + loc * exist ** algo ** size * imp ** + +- In .Bl -enum -width 0n, groff continues one the same line after + the number, mandoc breaks the line. + mail to kristaps@ Mon, 20 Jul 2009 02:21:39 +0200 + loc * exist ** algo ** size * imp ** + +- .Pp between two .It in .Bl -column should produce one, + not two blank lines, see e.g. login.conf(5). + reported by jmc@ Sun, 17 Apr 2011 14:04:58 +0059 + reported again by sthen@ Wed, 18 Jan 2012 02:09:39 +0000 (UTC) + loc * exist *** algo ** size * imp ** + +- If the *first* line after .It is .Pp, break the line right after + the tag, do not pad with space characters before breaking. + See the description of the a, c, and i commands in sed(1). + loc * exist ** algo ** size * imp ** + +- If the first line after .It is .D1, do not assert a blank line + in between, see for example tmux(1). + reported by nicm@ 13 Jan 2011 00:18:57 +0000 + loc * exist ** algo ** size * imp ** + +- Trailing punctuation after .It should trigger EOS spacing. + reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100 + Probably, this should be fixed somewhere in termp_it_pre(), not sure. + loc * exist ** algo ** size * imp ** + +- When the -width string contains macros, the macros must be rendered + before measuring the width, for example + .Bl -tag -width ".Dv message" + in magic(5), located in src/usr.bin/file, is the same + as -width 7n, not -width 11n. + The same applies to .Bl -column column widths; + reported again by Nicolas Joly Thu, 1 Mar 2012 13:41:26 +0100 via wiz@ 5 Mar + reported again by Franco Fichtner Fri, 27 Sep 2013 21:02:28 +0200 + reported again by Bruce Evans Fri, 17 Feb 2017 21:22:44 +0100 via bapt@ + loc *** exist *** algo *** size ** imp *** + An easy partial fix would be to just skip the first word if it starts + with a dot, including any following white space, when measuring. + loc * exist * algo * size * imp *** + +- The \& zero-width character counts as output. + That is, when it is alone on a line between two .Pp, + we want three blank lines, not two as in mandoc. + loc ** exist ** algo ** size * imp ** + +- Sequences of multiple man(7) paragraphs (.PP, .IP) interspersed + with .ps and .nf/.fi produce execessive blank lines, see libJudy + and graphics/dcmtk. The parser reorg may help with this. + +- trailing whitespace must be ignored even when followed by a font escape, + see for example + makes + \fBdig \fR + operate in batch mode + in dig(1). + loc ** exist ** algo ** size * imp ** + +************************************************************************ +* warning issues +************************************************************************ + +- warn about duplicate .Sh/.Ss heads + gre(4): Rename duplicate sections 20 Apr 2018 15:27:33 +0200 + loc * exist * algo * size * imp ** + +- style message about macros inside .Bd -literal and .Dl, in particular + font changing macros like .Cm, .Ar, .Fa (from the mdoclint TODO) + +- style message about mismatches between the section number in the + file name (if it is known) and the section number in .Dt + (from the mdoclint TODO) + +- style message about NULL without .Dv (from the mdoclint TODO) + +- style message about error constants without .Er (from the mdoclint TODO) + +- warn when .Sh or .Ss contain other macros + Steffen Nurpmeso, savannah.gnu.org/bugs/index.php?45034 + loc * exist * algo * size * imp ** + +- style message about violations of the convention + .An name Aq Mt localpart@domain in AUTHORS (from the mdoclint TODO) + +- warn about attempts to call non-callable macros + Steffen Nurpmeso Tue, 11 Nov 2014 22:55:16 +0100 + Note that formatting is inconsistent in groff. + .Fn Po prints "Po()", .Ar Sh prints "file ..." and no "Sh". + Relatively hard because the relevant code is scattered + all over mdoc_macro.c and all subtly different. + loc ** exist ** algo ** size ** imp ** + +- warn about punctuation - e.g. ',' and ';' - at the beginning + of a text line, if it is likely intended to follow the preceding + output without intervening whitespace, in particular after a + macro line (from the mdoclint TODO) + +- makewhatis -p complains about language subdirectories: + /usr/local/man//ru: Unknown directory part + + +************************************************************************ +* documentation issues +************************************************************************ + +- mark macros as: page structure domain, manual domain, general text domain + is this useful? + +- mention /usr/share/misc/mdoc.template in mdoc(7)? + +- Is all the content from http://www.std.com/obi/BSD/doc/usd/28.tbl/tbl + covered in tbl(7)? + +************************************************************************ +* performance issues +************************************************************************ + +- the PDF file is HUGE: this can be reduced by using relative offsets + +************************************************************************ +* structural issues +************************************************************************ + +- POSIX says in the documentation of sysconf(3) that PATH_MAX + is allowed to be so large that it is a bad idea to use it + for sizing static buffers. So use dynamic buffers throughout. + See the file test-PATH_MAX.c for details. + Found by Aaron M. Ucko in the GNU Hurd via Bdale Garbee, + https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=829624 + +- Is it possible to further simplify ENDBODY_SPACE? + +- Find better ways to prevent endless loops + in roff(7) macro and string expansion. + +- make buffers for parsing functions const + christos@ via wiz@ Fri, 18 Dec 2015 17:10:01 +0100 + +- struct mparse refactoring + Steffen Nurpmeso Thu, 04 Sep 2014 12:50:00 +0200 + +************************************************************************ +* CGI issues +************************************************************************ + + - Enable HTTP compression by detecting gzip encoding and filtering + output through libz. + - Privilege separation (see OpenSSH). + - Enable caching support via HTTP 304 and If-Modified-Since. + +************************************************************************ +* to improve in the groff_mdoc(7) macros +************************************************************************ + +- .Cd # arch1, arch2 in section 4 pages: + find better way to indicate multiple architectures, maybe: + allow .Dt vgafb 4 "macppc sparc64" + already shown as "Device Drivers Manual (macppc sparc64)" + for apropos, make that "vgafb(4) - macppc # sparc64" instead of "- all" + groff can be made to show multiple arches, too, but it is + tedious to do the string parsing in roff code... + jmc@ 23 Apr 2018 07:24:52 +0100 [man for vgafb(4)...] + loc ** exist ** algo * size * imp *** + +- use uname(1) to set doc-default-operating-system at install time + tobimensch Mon, 1 Dec 2014 00:25:07 +0100 + +- apostrophe (39), circumflex (94), grave (96), tilde (126) + in manuals: \(aq, \(ha, \`, \(ti + Re: [Groff] ASCII Minus Sign in man Pages. + bentley@ 26 Apr 2017 10:02:06 -0600 + Do we need to fix existing manuals? + Do we need to fix the definition of the mdoc(7) language? Index: vendor/mandoc/20190723/arch.c =================================================================== --- vendor/mandoc/20190723/arch.c (nonexistent) +++ vendor/mandoc/20190723/arch.c (revision 350350) @@ -0,0 +1,54 @@ +/* $Id: arch.c,v 1.15 2019/05/21 07:52:00 schwarze Exp $ */ +/* + * Copyright (c) 2017, 2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include "roff.h" + +int +arch_valid(const char *arch, enum mandoc_os os) +{ + const char *openbsd_arch[] = { + "alpha", "amd64", "arm64", "armv7", "hppa", "i386", + "landisk", "loongson", "luna88k", "macppc", "mips64", + "octeon", "sgi", "sparc64", NULL + }; + const char *netbsd_arch[] = { + "acorn26", "acorn32", "algor", "alpha", "amiga", + "arc", "atari", + "bebox", "cats", "cesfic", "cobalt", "dreamcast", + "emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5", + "hp300", "hpcarm", "hpcmips", "hpcsh", "hppa", + "i386", "ibmnws", "luna68k", + "mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc", + "netwinder", "news68k", "newsmips", "next68k", + "pc532", "playstation2", "pmax", "pmppc", "prep", + "sandpoint", "sbmips", "sgimips", "shark", + "sparc", "sparc64", "sun2", "sun3", + "vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL + }; + const char **arches[] = { NULL, netbsd_arch, openbsd_arch }; + const char **arch_p; + + if ((arch_p = arches[os]) == NULL) + return 1; + for (; *arch_p != NULL; arch_p++) + if (strcmp(*arch_p, arch) == 0) + return 1; + return 0; +} Property changes on: vendor/mandoc/20190723/arch.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/cgi.c =================================================================== --- vendor/mandoc/20190723/cgi.c (nonexistent) +++ vendor/mandoc/20190723/cgi.c (revision 350350) @@ -0,0 +1,1253 @@ +/* $Id: cgi.c,v 1.167 2019/07/10 12:49:20 schwarze Exp $ */ +/* + * Copyright (c) 2011, 2012 Kristaps Dzonsons + * Copyright (c) 2014, 2015, 2016, 2017, 2018 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include +#include + +#include +#if HAVE_ERR +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "man.h" +#include "mandoc_parse.h" +#include "main.h" +#include "manconf.h" +#include "mansearch.h" +#include "cgi.h" + +/* + * A query as passed to the search function. + */ +struct query { + char *manpath; /* desired manual directory */ + char *arch; /* architecture */ + char *sec; /* manual section */ + char *query; /* unparsed query expression */ + int equal; /* match whole names, not substrings */ +}; + +struct req { + struct query q; + char **p; /* array of available manpaths */ + size_t psz; /* number of available manpaths */ + int isquery; /* QUERY_STRING used, not PATH_INFO */ +}; + +enum focus { + FOCUS_NONE = 0, + FOCUS_QUERY +}; + +static void html_print(const char *); +static void html_putchar(char); +static int http_decode(char *); +static void http_encode(const char *p); +static void parse_manpath_conf(struct req *); +static void parse_path_info(struct req *req, const char *path); +static void parse_query_string(struct req *, const char *); +static void pg_error_badrequest(const char *); +static void pg_error_internal(void); +static void pg_index(const struct req *); +static void pg_noresult(const struct req *, const char *); +static void pg_redirect(const struct req *, const char *); +static void pg_search(const struct req *); +static void pg_searchres(const struct req *, + struct manpage *, size_t); +static void pg_show(struct req *, const char *); +static void resp_begin_html(int, const char *, const char *); +static void resp_begin_http(int, const char *); +static void resp_catman(const struct req *, const char *); +static void resp_copy(const char *); +static void resp_end_html(void); +static void resp_format(const struct req *, const char *); +static void resp_searchform(const struct req *, enum focus); +static void resp_show(const struct req *, const char *); +static void set_query_attr(char **, char **); +static int validate_arch(const char *); +static int validate_filename(const char *); +static int validate_manpath(const struct req *, const char *); +static int validate_urifrag(const char *); + +static const char *scriptname = SCRIPT_NAME; + +static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9}; +static const char *const sec_numbers[] = { + "0", "1", "2", "3", "3p", "4", "5", "6", "7", "8", "9" +}; +static const char *const sec_names[] = { + "All Sections", + "1 - General Commands", + "2 - System Calls", + "3 - Library Functions", + "3p - Perl Library", + "4 - Device Drivers", + "5 - File Formats", + "6 - Games", + "7 - Miscellaneous Information", + "8 - System Manager\'s Manual", + "9 - Kernel Developer\'s Manual" +}; +static const int sec_MAX = sizeof(sec_names) / sizeof(char *); + +static const char *const arch_names[] = { + "amd64", "alpha", "armv7", "arm64", + "hppa", "i386", "landisk", + "loongson", "luna88k", "macppc", "mips64", + "octeon", "sgi", "socppc", "sparc64", + "amiga", "arc", "armish", "arm32", + "atari", "aviion", "beagle", "cats", + "hppa64", "hp300", + "ia64", "mac68k", "mvme68k", "mvme88k", + "mvmeppc", "palm", "pc532", "pegasos", + "pmax", "powerpc", "solbourne", "sparc", + "sun3", "vax", "wgrisc", "x68k", + "zaurus" +}; +static const int arch_MAX = sizeof(arch_names) / sizeof(char *); + +/* + * Print a character, escaping HTML along the way. + * This will pass non-ASCII straight to output: be warned! + */ +static void +html_putchar(char c) +{ + + switch (c) { + case '"': + printf("""); + break; + case '&': + printf("&"); + break; + case '>': + printf(">"); + break; + case '<': + printf("<"); + break; + default: + putchar((unsigned char)c); + break; + } +} + +/* + * Call through to html_putchar(). + * Accepts NULL strings. + */ +static void +html_print(const char *p) +{ + + if (NULL == p) + return; + while ('\0' != *p) + html_putchar(*p++); +} + +/* + * Transfer the responsibility for the allocated string *val + * to the query structure. + */ +static void +set_query_attr(char **attr, char **val) +{ + + free(*attr); + if (**val == '\0') { + *attr = NULL; + free(*val); + } else + *attr = *val; + *val = NULL; +} + +/* + * Parse the QUERY_STRING for key-value pairs + * and store the values into the query structure. + */ +static void +parse_query_string(struct req *req, const char *qs) +{ + char *key, *val; + size_t keysz, valsz; + + req->isquery = 1; + req->q.manpath = NULL; + req->q.arch = NULL; + req->q.sec = NULL; + req->q.query = NULL; + req->q.equal = 1; + + key = val = NULL; + while (*qs != '\0') { + + /* Parse one key. */ + + keysz = strcspn(qs, "=;&"); + key = mandoc_strndup(qs, keysz); + qs += keysz; + if (*qs != '=') + goto next; + + /* Parse one value. */ + + valsz = strcspn(++qs, ";&"); + val = mandoc_strndup(qs, valsz); + qs += valsz; + + /* Decode and catch encoding errors. */ + + if ( ! (http_decode(key) && http_decode(val))) + goto next; + + /* Handle key-value pairs. */ + + if ( ! strcmp(key, "query")) + set_query_attr(&req->q.query, &val); + + else if ( ! strcmp(key, "apropos")) + req->q.equal = !strcmp(val, "0"); + + else if ( ! strcmp(key, "manpath")) { +#ifdef COMPAT_OLDURI + if ( ! strncmp(val, "OpenBSD ", 8)) { + val[7] = '-'; + if ('C' == val[8]) + val[8] = 'c'; + } +#endif + set_query_attr(&req->q.manpath, &val); + } + + else if ( ! (strcmp(key, "sec") +#ifdef COMPAT_OLDURI + && strcmp(key, "sektion") +#endif + )) { + if ( ! strcmp(val, "0")) + *val = '\0'; + set_query_attr(&req->q.sec, &val); + } + + else if ( ! strcmp(key, "arch")) { + if ( ! strcmp(val, "default")) + *val = '\0'; + set_query_attr(&req->q.arch, &val); + } + + /* + * The key must be freed in any case. + * The val may have been handed over to the query + * structure, in which case it is now NULL. + */ +next: + free(key); + key = NULL; + free(val); + val = NULL; + + if (*qs != '\0') + qs++; + } +} + +/* + * HTTP-decode a string. The standard explanation is that this turns + * "%4e+foo" into "n foo" in the regular way. This is done in-place + * over the allocated string. + */ +static int +http_decode(char *p) +{ + char hex[3]; + char *q; + int c; + + hex[2] = '\0'; + + q = p; + for ( ; '\0' != *p; p++, q++) { + if ('%' == *p) { + if ('\0' == (hex[0] = *(p + 1))) + return 0; + if ('\0' == (hex[1] = *(p + 2))) + return 0; + if (1 != sscanf(hex, "%x", &c)) + return 0; + if ('\0' == c) + return 0; + + *q = (char)c; + p += 2; + } else + *q = '+' == *p ? ' ' : *p; + } + + *q = '\0'; + return 1; +} + +static void +http_encode(const char *p) +{ + for (; *p != '\0'; p++) { + if (isalnum((unsigned char)*p) == 0 && + strchr("-._~", *p) == NULL) + printf("%%%2.2X", (unsigned char)*p); + else + putchar(*p); + } +} + +static void +resp_begin_http(int code, const char *msg) +{ + + if (200 != code) + printf("Status: %d %s\r\n", code, msg); + + printf("Content-Type: text/html; charset=utf-8\r\n" + "Cache-Control: no-cache\r\n" + "Pragma: no-cache\r\n" + "\r\n"); + + fflush(stdout); +} + +static void +resp_copy(const char *filename) +{ + char buf[4096]; + ssize_t sz; + int fd; + + if ((fd = open(filename, O_RDONLY)) != -1) { + fflush(stdout); + while ((sz = read(fd, buf, sizeof(buf))) > 0) + write(STDOUT_FILENO, buf, sz); + close(fd); + } +} + +static void +resp_begin_html(int code, const char *msg, const char *file) +{ + char *cp; + + resp_begin_http(code, msg); + + printf("\n" + "\n" + "\n" + " \n" + " \n" + " \n" + " ", + CSS_DIR); + if (file != NULL) { + if ((cp = strrchr(file, '/')) != NULL) + file = cp + 1; + if ((cp = strrchr(file, '.')) != NULL) { + printf("%.*s(%s) - ", (int)(cp - file), file, cp + 1); + } else + printf("%s - ", file); + } + printf("%s\n" + "\n" + "\n", + CUSTOMIZE_TITLE); + + resp_copy(MAN_DIR "/header.html"); +} + +static void +resp_end_html(void) +{ + + resp_copy(MAN_DIR "/footer.html"); + + puts("\n" + ""); +} + +static void +resp_searchform(const struct req *req, enum focus focus) +{ + int i; + + printf("
\n" + "
\n" + " Manual Page Search Parameters\n", + scriptname); + + /* Write query input box. */ + + printf(" q.query != NULL) + html_print(req->q.query); + printf( "\" size=\"40\""); + if (focus == FOCUS_QUERY) + printf(" autofocus"); + puts(">"); + + /* Write submission buttons. */ + + printf( " \n" + " \n" + "
\n"); + + /* Write section selector. */ + + puts(" "); + + /* Write architecture selector. */ + + printf( " "); + + /* Write manpath selector. */ + + if (req->psz > 1) { + puts(" "); + } + + puts("
\n" + "
"); +} + +static int +validate_urifrag(const char *frag) +{ + + while ('\0' != *frag) { + if ( ! (isalnum((unsigned char)*frag) || + '-' == *frag || '.' == *frag || + '/' == *frag || '_' == *frag)) + return 0; + frag++; + } + return 1; +} + +static int +validate_manpath(const struct req *req, const char* manpath) +{ + size_t i; + + for (i = 0; i < req->psz; i++) + if ( ! strcmp(manpath, req->p[i])) + return 1; + + return 0; +} + +static int +validate_arch(const char *arch) +{ + int i; + + for (i = 0; i < arch_MAX; i++) + if (strcmp(arch, arch_names[i]) == 0) + return 1; + + return 0; +} + +static int +validate_filename(const char *file) +{ + + if ('.' == file[0] && '/' == file[1]) + file += 2; + + return ! (strstr(file, "../") || strstr(file, "/..") || + (strncmp(file, "man", 3) && strncmp(file, "cat", 3))); +} + +static void +pg_index(const struct req *req) +{ + + resp_begin_html(200, NULL, NULL); + resp_searchform(req, FOCUS_QUERY); + printf("

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

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

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

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

Bad Request

\n" + "

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

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

Internal Server Error

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

You specified an invalid manual file.

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

You specified an invalid manual file.

"); + return; + } + + mchars_alloc(); + mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 | + MPARSE_VALIDATE, MANDOC_OS_OTHER, req->q.manpath); + mparse_readfd(mp, fd, file); + close(fd); + meta = mparse_result(mp); + + memset(&conf, 0, sizeof(conf)); + conf.fragment = 1; + conf.style = mandoc_strdup(CSS_DIR "/mandoc.css"); + usepath = strcmp(req->q.manpath, req->p[0]); + mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S", + scriptname, *scriptname == '\0' ? "" : "/", + usepath ? req->q.manpath : "", usepath ? "/" : ""); + + vp = html_alloc(&conf); + if (meta->macroset == MACROSET_MDOC) + html_mdoc(vp, meta); + else + html_man(vp, meta); + + html_free(vp); + mparse_free(mp); + mchars_free(); + free(conf.man); + free(conf.style); +} + +static void +resp_show(const struct req *req, const char *file) +{ + + if ('.' == file[0] && '/' == file[1]) + file += 2; + + if ('c' == *file) + resp_catman(req, file); + else + resp_format(req, file); +} + +static void +pg_show(struct req *req, const char *fullpath) +{ + char *manpath; + const char *file; + + if ((file = strchr(fullpath, '/')) == NULL) { + pg_error_badrequest( + "You did not specify a page to show."); + return; + } + manpath = mandoc_strndup(fullpath, file - fullpath); + file++; + + if ( ! validate_manpath(req, manpath)) { + pg_error_badrequest( + "You specified an invalid manpath."); + free(manpath); + return; + } + + /* + * Begin by chdir()ing into the manpath. + * This way we can pick up the database files, which are + * relative to the manpath root. + */ + + if (chdir(manpath) == -1) { + warn("chdir %s", manpath); + pg_error_internal(); + free(manpath); + return; + } + free(manpath); + + if ( ! validate_filename(file)) { + pg_error_badrequest( + "You specified an invalid manual file."); + return; + } + + resp_begin_html(200, NULL, file); + resp_searchform(req, FOCUS_NONE); + resp_show(req, file); + resp_end_html(); +} + +static void +pg_search(const struct req *req) +{ + struct mansearch search; + struct manpaths paths; + struct manpage *res; + char **argv; + char *query, *rp, *wp; + size_t ressz; + int argc; + + /* + * Begin by chdir()ing into the root of the manpath. + * This way we can pick up the database files, which are + * relative to the manpath root. + */ + + if (chdir(req->q.manpath) == -1) { + warn("chdir %s", req->q.manpath); + pg_error_internal(); + return; + } + + search.arch = req->q.arch; + search.sec = req->q.sec; + search.outkey = "Nd"; + search.argmode = req->q.equal ? ARG_NAME : ARG_EXPR; + search.firstmatch = 1; + + paths.sz = 1; + paths.paths = mandoc_malloc(sizeof(char *)); + paths.paths[0] = mandoc_strdup("."); + + /* + * Break apart at spaces with backslash-escaping. + */ + + argc = 0; + argv = NULL; + rp = query = mandoc_strdup(req->q.query); + for (;;) { + while (isspace((unsigned char)*rp)) + rp++; + if (*rp == '\0') + break; + argv = mandoc_reallocarray(argv, argc + 1, sizeof(char *)); + argv[argc++] = wp = rp; + for (;;) { + if (isspace((unsigned char)*rp)) { + *wp = '\0'; + rp++; + break; + } + if (rp[0] == '\\' && rp[1] != '\0') + rp++; + if (wp != rp) + *wp = *rp; + if (*rp == '\0') + break; + wp++; + rp++; + } + } + + res = NULL; + ressz = 0; + if (req->isquery && req->q.equal && argc == 1) + pg_redirect(req, argv[0]); + else if (mansearch(&search, &paths, argc, argv, &res, &ressz) == 0) + pg_noresult(req, "You entered an invalid query."); + else if (ressz == 0) + pg_noresult(req, "No results found."); + else + pg_searchres(req, res, ressz); + + free(query); + mansearch_free(res, ressz); + free(paths.paths[0]); + free(paths.paths); +} + +int +main(void) +{ + struct req req; + struct itimerval itimer; + const char *path; + const char *querystring; + int i; + +#if HAVE_PLEDGE + /* + * The "rpath" pledge could be revoked after mparse_readfd() + * if the file desciptor to "/footer.html" would be opened + * up front, but it's probably not worth the complication + * of the code it would cause: it would require scattering + * pledge() calls in multiple low-level resp_*() functions. + */ + + if (pledge("stdio rpath", NULL) == -1) { + warn("pledge"); + pg_error_internal(); + return EXIT_FAILURE; + } +#endif + + /* Poor man's ReDoS mitigation. */ + + itimer.it_value.tv_sec = 2; + itimer.it_value.tv_usec = 0; + itimer.it_interval.tv_sec = 2; + itimer.it_interval.tv_usec = 0; + if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) == -1) { + warn("setitimer"); + pg_error_internal(); + return EXIT_FAILURE; + } + + /* + * First we change directory into the MAN_DIR so that + * subsequent scanning for manpath directories is rooted + * relative to the same position. + */ + + if (chdir(MAN_DIR) == -1) { + warn("MAN_DIR: %s", MAN_DIR); + pg_error_internal(); + return EXIT_FAILURE; + } + + memset(&req, 0, sizeof(struct req)); + req.q.equal = 1; + parse_manpath_conf(&req); + + /* Parse the path info and the query string. */ + + if ((path = getenv("PATH_INFO")) == NULL) + path = ""; + else if (*path == '/') + path++; + + if (*path != '\0') { + parse_path_info(&req, path); + if (req.q.manpath == NULL || req.q.sec == NULL || + *req.q.query == '\0' || access(path, F_OK) == -1) + path = ""; + } else if ((querystring = getenv("QUERY_STRING")) != NULL) + parse_query_string(&req, querystring); + + /* Validate parsed data and add defaults. */ + + if (req.q.manpath == NULL) + req.q.manpath = mandoc_strdup(req.p[0]); + else if ( ! validate_manpath(&req, req.q.manpath)) { + pg_error_badrequest( + "You specified an invalid manpath."); + return EXIT_FAILURE; + } + + if (req.q.arch != NULL && validate_arch(req.q.arch) == 0) { + pg_error_badrequest( + "You specified an invalid architecture."); + return EXIT_FAILURE; + } + + /* Dispatch to the three different pages. */ + + if ('\0' != *path) + pg_show(&req, path); + else if (NULL != req.q.query) + pg_search(&req); + else + pg_index(&req); + + free(req.q.manpath); + free(req.q.arch); + free(req.q.sec); + free(req.q.query); + for (i = 0; i < (int)req.psz; i++) + free(req.p[i]); + free(req.p); + return EXIT_SUCCESS; +} + +/* + * Translate PATH_INFO to a query. + */ +static void +parse_path_info(struct req *req, const char *path) +{ + const char *name, *sec, *end; + + req->isquery = 0; + req->q.equal = 1; + req->q.manpath = NULL; + req->q.arch = NULL; + + /* Mandatory manual page name. */ + if ((name = strrchr(path, '/')) == NULL) + name = path; + else + name++; + + /* Optional trailing section. */ + sec = strrchr(name, '.'); + if (sec != NULL && isdigit((unsigned char)*++sec)) { + req->q.query = mandoc_strndup(name, sec - name - 1); + req->q.sec = mandoc_strdup(sec); + } else { + req->q.query = mandoc_strdup(name); + req->q.sec = NULL; + } + + /* Handle the case of name[.section] only. */ + if (name == path) + return; + + /* Optional manpath. */ + end = strchr(path, '/'); + req->q.manpath = mandoc_strndup(path, end - path); + if (validate_manpath(req, req->q.manpath)) { + path = end + 1; + if (name == path) + return; + } else { + free(req->q.manpath); + req->q.manpath = NULL; + } + + /* Optional section. */ + if (strncmp(path, "man", 3) == 0 || strncmp(path, "cat", 3) == 0) { + path += 3; + end = strchr(path, '/'); + free(req->q.sec); + req->q.sec = mandoc_strndup(path, end - path); + path = end + 1; + if (name == path) + return; + } + + /* Optional architecture. */ + end = strchr(path, '/'); + if (end + 1 != name) { + pg_error_badrequest( + "You specified too many directory components."); + exit(EXIT_FAILURE); + } + req->q.arch = mandoc_strndup(path, end - path); + if (validate_arch(req->q.arch) == 0) { + pg_error_badrequest( + "You specified an invalid directory component."); + exit(EXIT_FAILURE); + } +} + +/* + * Scan for indexable paths. + */ +static void +parse_manpath_conf(struct req *req) +{ + FILE *fp; + char *dp; + size_t dpsz; + ssize_t len; + + if ((fp = fopen("manpath.conf", "r")) == NULL) { + warn("%s/manpath.conf", MAN_DIR); + pg_error_internal(); + exit(EXIT_FAILURE); + } + + dp = NULL; + dpsz = 0; + + while ((len = getline(&dp, &dpsz, fp)) != -1) { + if (dp[len - 1] == '\n') + dp[--len] = '\0'; + req->p = mandoc_realloc(req->p, + (req->psz + 1) * sizeof(char *)); + if ( ! validate_urifrag(dp)) { + warnx("%s/manpath.conf contains " + "unsafe path \"%s\"", MAN_DIR, dp); + pg_error_internal(); + exit(EXIT_FAILURE); + } + if (strchr(dp, '/') != NULL) { + warnx("%s/manpath.conf contains " + "path with slash \"%s\"", MAN_DIR, dp); + pg_error_internal(); + exit(EXIT_FAILURE); + } + req->p[req->psz++] = dp; + dp = NULL; + dpsz = 0; + } + free(dp); + + if (req->p == NULL) { + warnx("%s/manpath.conf is empty", MAN_DIR); + pg_error_internal(); + exit(EXIT_FAILURE); + } +} Property changes on: vendor/mandoc/20190723/cgi.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/configure =================================================================== --- vendor/mandoc/20190723/configure (nonexistent) +++ vendor/mandoc/20190723/configure (revision 350350) @@ -0,0 +1,636 @@ +#!/bin/sh +# +# $Id: configure,v 1.71 2019/07/01 22:56:24 schwarze Exp $ +# +# Copyright (c) 2014-2019 Ingo Schwarze +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +set -e + +[ -w config.log ] && mv config.log config.log.old +[ -w config.h ] && mv config.h config.h.old + +# Output file descriptor usage: +# 1 (stdout): config.h, Makefile.local +# 2 (stderr): original stderr, usually to the console +# 3: config.log + +exec 3> config.log +echo "file config.log: writing..." + +# --- default settings ------------------------------------------------- +# Initialize all variables here, +# such that nothing can leak in from the environment. + +SOURCEDIR=`dirname "$0"` + +MANPATH_BASE="/usr/share/man:/usr/X11R6/man" +MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" +OSENUM= +OSNAME= +UTF8_LOCALE= + +CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | env -i make -sf -` +CFLAGS= +LDADD= +LDFLAGS= +LD_NANOSLEEP= +LD_OHASH= +LD_RECVMSG= +STATIC= + +BUILD_CGI=0 +BUILD_CATMAN=0 +INSTALL_LIBMANDOC=0 + +HAVE_CMSG= +HAVE_CMSG_XPG42=0 +HAVE_DIRENT_NAMLEN= +HAVE_EFTYPE= +HAVE_ENDIAN= +HAVE_ERR= +HAVE_FTS= +HAVE_FTS_COMPARE_CONST= +HAVE_GETLINE= +HAVE_GETSUBOPT= +HAVE_ISBLANK= +HAVE_LESS_T= +HAVE_MKDTEMP= +HAVE_NANOSLEEP= +HAVE_NTOHL= +HAVE_O_DIRECTORY= +HAVE_OHASH= +HAVE_PATH_MAX= +HAVE_PLEDGE= +HAVE_PROGNAME= +HAVE_REALLOCARRAY= +HAVE_RECALLOCARRAY= +HAVE_RECVMSG= +HAVE_REWB_BSD= +HAVE_REWB_SYSV= +HAVE_SANDBOX_INIT= +HAVE_STRCASESTR= +HAVE_STRINGLIST= +HAVE_STRLCAT= +HAVE_STRLCPY= +HAVE_STRNDUP= +HAVE_STRPTIME= +HAVE_STRSEP= +HAVE_STRTONUM= +HAVE_SYS_ENDIAN= +HAVE_VASPRINTF= +HAVE_WCHAR= + +NEED_GNU_SOURCE=0 +NEED_OPENBSD_SOURCE=0 + +PREFIX="/usr/local" +BINDIR= +SBINDIR= +BIN_FROM_SBIN= +INCLUDEDIR= +LIBDIR= +MANDIR= +HOMEBREWDIR= + +WWWPREFIX="/var/www" +HTDOCDIR= +CGIBINDIR= + +BINM_APROPOS="apropos" +BINM_CATMAN="catman" +BINM_MAKEWHATIS="makewhatis" +BINM_MAN="man" +BINM_SOELIM="soelim" +BINM_WHATIS="whatis" +MANM_MAN="man" +MANM_MANCONF="man.conf" +MANM_MDOC="mdoc" +MANM_ROFF="roff" +MANM_EQN="eqn" +MANM_TBL="tbl" + +INSTALL="install" +INSTALL_PROGRAM= +INSTALL_LIB= +INSTALL_MAN= +INSTALL_DATA= +LN="ln -f" + +# --- manual settings from configure.local ----------------------------- + +if [ -r ./configure.local ]; then + echo "file configure.local: reading..." 1>&2 + echo "file configure.local: reading..." 1>&3 + cat ./configure.local 1>&3 + . ./configure.local +else + echo "file configure.local: no (fully automatic configuration)" 1>&2 + echo "file configure.local: no (fully automatic configuration)" 1>&3 +fi +echo 1>&3 + +# --- tests functions -------------------------------------------------- + +# Check whether this HAVE_ setting is manually overridden. +# If yes, use the override, if no, do not decide anything yet. +# Arguments: test file name, test var name, manual value +ismanual() { + [ -z "${3}" ] && return 1 + echo "tested ${1}: HAVE_${2}=${3} (manual)" 1>&2 + echo "tested ${1}: HAVE_${2}=${3} (manual)" 1>&3 + echo 1>&3 + return 0 +} + +# Run a single autoconfiguration test. +# In case of success, enable the feature. +# In case of failure, do not decide anything yet. +# Arguments: test file name, test var name, additional CFLAGS +singletest() { + n=${1}${3}${4} + cat 1>&3 << __HEREDOC__ +testing ${n} ... +${COMP} -o test-${1} test-${1}.c ${3} ${4} +__HEREDOC__ + + if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} ${4} 1>&3 2>&3 + then + echo "partial result of ${n}: ${CC} succeeded" 1>&3 + else + echo "result of ${n}: ${CC} failed with exit status $?" 1>&3 + echo "result of compiling ${n}: no" 1>&3 + echo 1>&3 + return 1 + fi + + if ./test-${1} 1>&3 2>&3; then + echo "tested ${n}: yes" 1>&2 + echo "result of running ${n}: yes" 1>&3 + echo 1>&3 + eval HAVE_${2}=1 + [ "X$3" = "X-D_GNU_SOURCE" ] && NEED_GNU_SOURCE=1 + [ "X$3" = "X-D_OPENBSD_SOURCE" ] && NEED_OPENBSD_SOURCE=1 + rm "test-${1}" + return 0 + else + echo "result of ${n}: execution failed with exit status $?" 1>&3 + echo "result of running ${n}: no" 1>&3 + echo 1>&3 + rm "test-${1}" + return 1 + fi +} + +# Run a complete autoconfiguration test, including the check for +# a manual override and disabling the feature on failure. +# Arguments: test file name, test var name, additional CFLAGS +runtest() { + eval _manual=\${HAVE_${2}} + ismanual "${1}" "${2}" "${_manual}" && return 0 + singletest "${1}" "${2}" "${3}" "${4}" && return 0 + echo "tested ${1}${3}${4}: no" 1>&2 + eval HAVE_${2}=0 + return 1 +} + +# Select a UTF-8 locale. +get_locale() { + [ -n "${HAVE_WCHAR}" ] && [ "${HAVE_WCHAR}" -eq 0 ] && return 0 + ismanual UTF8_LOCALE UTF8_LOCALE "$UTF8_LOCALE" && return 0 + echo "testing UTF8_LOCALE ..." 1>&3 + UTF8_LOCALE=`locale -a | grep -i '^en_US\.UTF-*8$' | head -n 1` + if [ -z "${UTF8_LOCALE}" ]; then + UTF8_LOCALE=`locale -a | grep -i '\.UTF-*8' | head -n 1` + [ -n "${UTF8_LOCALE}" ] || return 1 + fi + echo "selected UTF8_LOCALE=${UTF8_LOCALE}" 1>&2 + echo "selected UTF8_LOCALE=${UTF8_LOCALE}" 1>&3 + echo 1>&3 + return 0; +} + +# --- operating system ------------------------------------------------- + +if [ -n "${OSENUM}" ]; then + echo "OSENUM specified manually: ${OSENUM}" 1>&2 + echo "OSENUM specified manually: ${OSENUM}" 1>&3 +else + OSDETECT=`uname` + if [ "X${OSDETECT}" = "XNetBSD" ]; then + OSENUM=MANDOC_OS_NETBSD + elif [ "X${OSDETECT}" = "XOpenBSD" ]; then + OSENUM=MANDOC_OS_OPENBSD + else + OSENUM=MANDOC_OS_OTHER + fi + echo "tested operating system: ${OSDETECT} -> OSENUM=${OSENUM}" 1>&2 + echo "tested operating system: ${OSDETECT} -> OSENUM=${OSENUM}" 1>&3 + unset OSDETECT +fi +echo 1>&3 + +# --- compiler options ------------------------------------------------- + +DEFCFLAGS="-g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter" + +if [ -n "${CFLAGS}" ]; then + COMP="${CC} ${CFLAGS} -Wno-unused -Werror" +else + COMP="${CC} ${DEFCFLAGS} -Wno-unused -Werror" +fi +echo -n "tested ${CC} -W: " 1>&2 +echo -n "testing ${CC} -W: " 1>&3 +runtest noop WFLAG || true + +if [ -n "${CFLAGS}" ]; then + echo "CFLAGS specified manually:" 1>&3 +elif [ ${HAVE_WFLAG} -eq 0 ]; then + CFLAGS="-g" +else + CFLAGS="${DEFCFLAGS}" +fi +echo "selected CFLAGS=\"${CFLAGS}\"" 1>&2 +echo "selected CFLAGS=\"${CFLAGS}\"" 1>&3 +echo 1>&3 + +COMP="${CC} ${CFLAGS}" +[ ${HAVE_WFLAG} -eq 0 ] || COMP="${COMP} -Wno-unused -Werror" + +if [ -n "${STATIC}" ]; then + echo "selected STATIC=\"${STATIC}\" (manual)" 1>&2 + echo "selected STATIC=\"${STATIC}\" (manual)" 1>&3 + echo 1>&3 +else + runtest noop STATIC -static || true + [ ${HAVE_STATIC} -eq 0 ] || STATIC="-static" + echo "selected STATIC=\"${STATIC}\"" 1>&2 + echo "selected STATIC=\"${STATIC}\"" 1>&3 + echo 1>&3 +fi + +# --- tests for config.h ---------------------------------------------- + +# --- library functions --- +runtest dirent-namlen DIRENT_NAMLEN || true +runtest be32toh ENDIAN || true +runtest be32toh SYS_ENDIAN -DSYS_ENDIAN || true +runtest EFTYPE EFTYPE || true +runtest err ERR || true +runtest getline GETLINE || true +singletest getsubopt GETSUBOPT || \ + runtest getsubopt GETSUBOPT -D_GNU_SOURCE || true +runtest isblank ISBLANK || true +runtest mkdtemp MKDTEMP || true +runtest ntohl NTOHL || true +runtest O_DIRECTORY O_DIRECTORY || true +runtest PATH_MAX PATH_MAX || true +runtest pledge PLEDGE || true +runtest sandbox_init SANDBOX_INIT || true +runtest progname PROGNAME || true +singletest reallocarray REALLOCARRAY || \ + runtest reallocarray REALLOCARRAY -D_OPENBSD_SOURCE || true +singletest recallocarray RECALLOCARRAY || \ + runtest recallocarray RECALLOCARRAY -D_OPENBSD_SOURCE || true +runtest rewb-bsd REWB_BSD || true +runtest rewb-sysv REWB_SYSV || true +singletest strcasestr STRCASESTR || \ + runtest strcasestr STRCASESTR -D_GNU_SOURCE || true +runtest stringlist STRINGLIST || true +runtest strlcat STRLCAT || true +runtest strlcpy STRLCPY || true +runtest strndup STRNDUP || true +singletest strptime STRPTIME || \ + runtest strptime STRPTIME -D_GNU_SOURCE || true +runtest strsep STRSEP || true +singletest strtonum STRTONUM || \ + runtest strtonum STRTONUM -D_OPENBSD_SOURCE || true +singletest vasprintf VASPRINTF || \ + runtest vasprintf VASPRINTF -D_GNU_SOURCE || true + +if [ ${HAVE_ENDIAN} -eq 0 -a \ + ${HAVE_SYS_ENDIAN} -eq 0 -a \ + ${HAVE_NTOHL} -eq 0 ]; then + echo "FATAL: no endian conversion functions found" 1>&2 + echo "FATAL: no endian conversion functions found" 1>&3 + exit 1 +fi + +if ismanual fts FTS ${HAVE_FTS}; then + HAVE_FTS_COMPARE_CONST=0 +elif runtest fts FTS_COMPARE_CONST -DFTS_COMPARE_CONST; then + HAVE_FTS=1 +else + runtest fts FTS || true +fi + +if ismanual "less -T" LESS_T ${HAVE_LESS_T}; then + : +elif less -ET /dev/null test-noop.c 1>/dev/null 2>&3; then + HAVE_LESS_T=1 + echo "tested less -T: yes" 1>&2 + echo "tested less -T: yes" 1>&3 + echo 1>&3 +else + HAVE_LESS_T=0 + echo "tested less -T: no" 1>&2 + echo "tested less -T: no" 1>&3 + echo 1>&3 +fi + +# --- wide character and locale support --- +if get_locale; then + singletest wchar WCHAR -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || \ + runtest wchar WCHAR -D_GNU_SOURCE \ + -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || true +else + HAVE_WCHAR=0 + echo "tested wchar: no (no UTF8_LOCALE)" 1>&2 + echo "tested wchar: no (no UTF8_LOCALE)" 1>&3 + echo 1>&3 +fi + +# --- nanosleep --- +if [ -n "${LD_NANOSLEEP}" ]; then + runtest nanosleep NANOSLEEP "${LD_NANOSLEEP}" || true +elif singletest nanosleep NANOSLEEP; then + : +elif runtest nanosleep NANOSLEEP "-lrt"; then + LD_NANOSLEEP="-lrt" +fi +if [ "${HAVE_NANOSLEEP}" -eq 0 ]; then + echo "FATAL: nanosleep: no" 1>&2 + echo "FATAL: nanosleep: no" 1>&3 + exit 1 +fi + +if [ ${BUILD_CATMAN} -gt 0 ]; then + # --- recvmsg --- + if [ -n "${LD_RECVMSG}" ]; then + runtest recvmsg RECVMSG "${LD_RECVMSG}" || true + elif singletest recvmsg RECVMSG; then + : + elif runtest recvmsg RECVMSG "-lsocket"; then + LD_RECVMSG="-lsocket" + fi + if [ "${HAVE_RECVMSG}" -eq 0 ]; then + echo "FATAL: recvmsg: no" 1>&2 + echo "FATAL: recvmsg: no" 1>&3 + echo "Without recvmsg(2), you cannot BUILD_CATMAN." 1>&2 + exit 1 + fi + + # --- cmsg --- + if singletest cmsg CMSG; then + : + elif runtest cmsg CMSG "-D_XPG4_2"; then + HAVE_CMSG_XPG42=1 + fi + if [ "${HAVE_CMSG}" -eq 0 ]; then + echo "FATAL: cmsg: no" 1>&2 + echo "FATAL: cmsg: no" 1>&3 + echo "Without CMSG_FIRSTHDR(3), you cannot BUILD_CATMAN." 1>&2 + exit 1 + fi +fi + +# --- ohash --- +if ismanual ohash OHASH "${HAVE_OHASH}"; then + : +elif [ -n "${LD_OHASH}" ]; then + runtest ohash OHASH "${LD_OHASH}" || true +elif singletest ohash OHASH; then + : +elif runtest ohash OHASH "-lutil"; then + LD_OHASH="-lutil" +fi +if [ "${HAVE_OHASH}" -eq 0 ]; then + LD_OHASH= +fi + +# --- LDADD --- +LDADD="${LDADD} ${LD_NANOSLEEP} ${LD_RECVMSG} ${LD_OHASH} -lz" +echo "selected LDADD=\"${LDADD}\"" 1>&2 +echo "selected LDADD=\"${LDADD}\"" 1>&3 +echo 1>&3 + +# --- write config.h --- + +exec > config.h + +cat << __HEREDOC__ +#ifdef __cplusplus +#error "Do not use C++. See the INSTALL file." +#endif + +#if !defined(__GNUC__) || (__GNUC__ < 4) +#define __attribute__(x) +#endif + +__HEREDOC__ + +[ ${NEED_GNU_SOURCE} -eq 0 ] || echo "#define _GNU_SOURCE" +[ ${NEED_OPENBSD_SOURCE} -eq 0 ] || echo "#define _OPENBSD_SOURCE" + +[ ${HAVE_GETLINE} -eq 0 -o \ + ${HAVE_REALLOCARRAY} -eq 0 -o ${HAVE_RECALLOCARRAY} -eq 0 -o \ + ${HAVE_STRLCAT} -eq 0 -o ${HAVE_STRLCPY} -eq 0 -o \ + ${HAVE_STRNDUP} -eq 0 ] \ + && echo "#include " +[ ${HAVE_VASPRINTF} -eq 0 ] && echo "#include " +[ ${HAVE_GETLINE} -eq 0 ] && echo "#include " + +echo +echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\"" +echo "#define MANPATH_BASE \"${MANPATH_BASE}\"" +echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\"" +echo "#define OSENUM ${OSENUM}" +[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\"" +[ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\"" +[ -n "${HOMEBREWDIR}" ] && echo "#define HOMEBREWDIR \"${HOMEBREWDIR}\"" +[ ${HAVE_EFTYPE} -eq 0 ] && echo "#define EFTYPE EINVAL" +[ ${HAVE_O_DIRECTORY} -eq 0 ] && echo "#define O_DIRECTORY 0" +[ ${HAVE_PATH_MAX} -eq 0 ] && echo "#define PATH_MAX 4096" +if [ ${HAVE_ENDIAN} -eq 0 -a ${HAVE_SYS_ENDIAN} -eq 0 ]; then + echo "#define be32toh ntohl" + echo "#define htobe32 htonl" +fi + +cat << __HEREDOC__ +#define HAVE_CMSG_XPG42 ${HAVE_CMSG_XPG42} +#define HAVE_DIRENT_NAMLEN ${HAVE_DIRENT_NAMLEN} +#define HAVE_ENDIAN ${HAVE_ENDIAN} +#define HAVE_ERR ${HAVE_ERR} +#define HAVE_FTS ${HAVE_FTS} +#define HAVE_FTS_COMPARE_CONST ${HAVE_FTS_COMPARE_CONST} +#define HAVE_GETLINE ${HAVE_GETLINE} +#define HAVE_GETSUBOPT ${HAVE_GETSUBOPT} +#define HAVE_ISBLANK ${HAVE_ISBLANK} +#define HAVE_LESS_T ${HAVE_LESS_T} +#define HAVE_MKDTEMP ${HAVE_MKDTEMP} +#define HAVE_NTOHL ${HAVE_NTOHL} +#define HAVE_PLEDGE ${HAVE_PLEDGE} +#define HAVE_PROGNAME ${HAVE_PROGNAME} +#define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY} +#define HAVE_RECALLOCARRAY ${HAVE_RECALLOCARRAY} +#define HAVE_REWB_BSD ${HAVE_REWB_BSD} +#define HAVE_REWB_SYSV ${HAVE_REWB_SYSV} +#define HAVE_SANDBOX_INIT ${HAVE_SANDBOX_INIT} +#define HAVE_STRCASESTR ${HAVE_STRCASESTR} +#define HAVE_STRINGLIST ${HAVE_STRINGLIST} +#define HAVE_STRLCAT ${HAVE_STRLCAT} +#define HAVE_STRLCPY ${HAVE_STRLCPY} +#define HAVE_STRNDUP ${HAVE_STRNDUP} +#define HAVE_STRPTIME ${HAVE_STRPTIME} +#define HAVE_STRSEP ${HAVE_STRSEP} +#define HAVE_STRTONUM ${HAVE_STRTONUM} +#define HAVE_SYS_ENDIAN ${HAVE_SYS_ENDIAN} +#define HAVE_VASPRINTF ${HAVE_VASPRINTF} +#define HAVE_WCHAR ${HAVE_WCHAR} +#define HAVE_OHASH ${HAVE_OHASH} + +#define BINM_APROPOS "${BINM_APROPOS}" +#define BINM_CATMAN "${BINM_CATMAN}" +#define BINM_MAKEWHATIS "${BINM_MAKEWHATIS}" +#define BINM_MAN "${BINM_MAN}" +#define BINM_SOELIM "${BINM_SOELIM}" +#define BINM_WHATIS "${BINM_WHATIS}" + +__HEREDOC__ + +if [ ${HAVE_ERR} -eq 0 ]; then + echo "extern void err(int, const char *, ...);" + echo "extern void errx(int, const char *, ...);" + echo "extern void warn(const char *, ...);" + echo "extern void warnx(const char *, ...);" +fi + +[ ${HAVE_GETLINE} -eq 0 ] && \ + echo "extern ssize_t getline(char **, size_t *, FILE *);" + +[ ${HAVE_GETSUBOPT} -eq 0 ] && \ + echo "extern int getsubopt(char **, char * const *, char **);" + +[ ${HAVE_ISBLANK} -eq 0 ] && \ + echo "extern int isblank(int);" + +[ ${HAVE_MKDTEMP} -eq 0 ] && \ + echo "extern char *mkdtemp(char *);" + +if [ ${HAVE_PROGNAME} -eq 0 ]; then + echo "extern const char *getprogname(void);" + echo "extern void setprogname(const char *);" +fi + +[ ${HAVE_REALLOCARRAY} -eq 0 ] && \ + echo "extern void *reallocarray(void *, size_t, size_t);" + +[ ${HAVE_RECALLOCARRAY} -eq 0 ] && \ + echo "extern void *recallocarray(void *, size_t, size_t, size_t);" + +[ ${HAVE_STRCASESTR} -eq 0 ] && \ + echo "extern char *strcasestr(const char *, const char *);" + +[ ${HAVE_STRLCAT} -eq 0 ] && \ + echo "extern size_t strlcat(char *, const char *, size_t);" + +[ ${HAVE_STRLCPY} -eq 0 ] && \ + echo "extern size_t strlcpy(char *, const char *, size_t);" + +[ ${HAVE_STRNDUP} -eq 0 ] && \ + echo "extern char *strndup(const char *, size_t);" + +[ ${HAVE_STRSEP} -eq 0 ] && \ + echo "extern char *strsep(char **, const char *);" + +[ ${HAVE_STRTONUM} -eq 0 ] && \ + echo "extern long long strtonum(const char *, long long, long long, const char **);" + +[ ${HAVE_VASPRINTF} -eq 0 ] && \ + echo "extern int vasprintf(char **, const char *, va_list);" + +echo "file config.h: written" 1>&2 +echo "file config.h: written" 1>&3 + +# --- tests for Makefile.local ----------------------------------------- + +exec > Makefile.local + +[ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin" +[ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin" +[ -z "${BIN_FROM_SBIN}" ] && BIN_FROM_SBIN="../bin" +[ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include/mandoc" +[ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib/mandoc" +[ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man" + +[ -z "${HTDOCDIR}" ] && HTDOCDIR="${WWWPREFIX}/htdocs" +[ -z "${CGIBINDIR}" ] && CGIBINDIR="${WWWPREFIX}/cgi-bin" + +[ -z "${INSTALL_PROGRAM}" ] && INSTALL_PROGRAM="${INSTALL} -m 0555" +[ -z "${INSTALL_LIB}" ] && INSTALL_LIB="${INSTALL} -m 0444" +[ -z "${INSTALL_MAN}" ] && INSTALL_MAN="${INSTALL} -m 0444" +[ -z "${INSTALL_DATA}" ] && INSTALL_DATA="${INSTALL} -m 0444" + +BUILD_TARGETS= +[ ${BUILD_CGI} -gt 0 ] && BUILD_TARGETS="man.cgi" +[ ${BUILD_CATMAN} -gt 0 ] && \ + BUILD_TARGETS="${BUILD_TARGETS} mandocd catman" +INSTALL_TARGETS= +[ ${INSTALL_LIBMANDOC} -gt 0 ] && INSTALL_TARGETS="lib-install" +[ ${BUILD_CGI} -gt 0 ] && INSTALL_TARGETS="${INSTALL_TARGETS} cgi-install" +[ ${BUILD_CATMAN} -gt 0 ] && \ + INSTALL_TARGETS="${INSTALL_TARGETS} catman-install" + +cat << __HEREDOC__ +BUILD_TARGETS = ${BUILD_TARGETS} +INSTALL_TARGETS = ${INSTALL_TARGETS} +CC = ${CC} +CFLAGS = ${CFLAGS} +LDADD = ${LDADD} +LDFLAGS = ${LDFLAGS} +STATIC = ${STATIC} +PREFIX = ${PREFIX} +BINDIR = ${BINDIR} +SBINDIR = ${SBINDIR} +BIN_FROM_SBIN = ${BIN_FROM_SBIN} +INCLUDEDIR = ${INCLUDEDIR} +LIBDIR = ${LIBDIR} +MANDIR = ${MANDIR} +WWWPREFIX = ${WWWPREFIX} +HTDOCDIR = ${HTDOCDIR} +CGIBINDIR = ${CGIBINDIR} +BINM_APROPOS = ${BINM_APROPOS} +BINM_CATMAN = ${BINM_CATMAN} +BINM_MAKEWHATIS = ${BINM_MAKEWHATIS} +BINM_MAN = ${BINM_MAN} +BINM_SOELIM = ${BINM_SOELIM} +BINM_WHATIS = ${BINM_WHATIS} +MANM_MAN = ${MANM_MAN} +MANM_MANCONF = ${MANM_MANCONF} +MANM_MDOC = ${MANM_MDOC} +MANM_ROFF = ${MANM_ROFF} +MANM_EQN = ${MANM_EQN} +MANM_TBL = ${MANM_TBL} +INSTALL = ${INSTALL} +INSTALL_PROGRAM = ${INSTALL_PROGRAM} +INSTALL_LIB = ${INSTALL_LIB} +INSTALL_MAN = ${INSTALL_MAN} +INSTALL_DATA = ${INSTALL_DATA} +LN = ${LN} +__HEREDOC__ + +echo "file Makefile.local: written" 1>&2 +echo "file Makefile.local: written" 1>&3 + +exit 0 Property changes on: vendor/mandoc/20190723/configure ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: vendor/mandoc/20190723/dbm.c =================================================================== --- vendor/mandoc/20190723/dbm.c (nonexistent) +++ vendor/mandoc/20190723/dbm.c (revision 350350) @@ -0,0 +1,480 @@ +/* $Id: dbm.c,v 1.7 2019/07/01 22:56:24 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Map-based version of the mandoc database, for read-only access. + * The interface is defined in "dbm.h". + */ +#include "config.h" + +#include +#if HAVE_ENDIAN +#include +#elif HAVE_SYS_ENDIAN +#include +#elif HAVE_NTOHL +#include +#endif +#if HAVE_ERR +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "mansearch.h" +#include "dbm_map.h" +#include "dbm.h" + +struct macro { + int32_t value; + int32_t pages; +}; + +struct page { + int32_t name; + int32_t sect; + int32_t arch; + int32_t desc; + int32_t file; +}; + +enum iter { + ITER_NONE = 0, + ITER_NAME, + ITER_SECT, + ITER_ARCH, + ITER_DESC, + ITER_MACRO +}; + +static struct macro *macros[MACRO_MAX]; +static int32_t nvals[MACRO_MAX]; +static struct page *pages; +static int32_t npages; +static enum iter iteration; + +static struct dbm_res page_bytitle(enum iter, const struct dbm_match *); +static struct dbm_res page_byarch(const struct dbm_match *); +static struct dbm_res page_bymacro(int32_t, const struct dbm_match *); +static char *macro_bypage(int32_t, int32_t); + + +/*** top level functions **********************************************/ + +/* + * Open a disk-based mandoc database for read-only access. + * Map the pages and macros[] arrays. + * Return 0 on success. Return -1 and set errno on failure. + */ +int +dbm_open(const char *fname) +{ + const int32_t *mp, *ep; + int32_t im; + + if (dbm_map(fname) == -1) + return -1; + + if ((npages = be32toh(*dbm_getint(4))) < 0) { + warnx("dbm_open(%s): Invalid number of pages: %d", + fname, npages); + goto fail; + } + pages = (struct page *)dbm_getint(5); + + if ((mp = dbm_get(*dbm_getint(2))) == NULL) { + warnx("dbm_open(%s): Invalid offset of macros array", fname); + goto fail; + } + if (be32toh(*mp) != MACRO_MAX) { + warnx("dbm_open(%s): Invalid number of macros: %d", + fname, be32toh(*mp)); + goto fail; + } + for (im = 0; im < MACRO_MAX; im++) { + if ((ep = dbm_get(*++mp)) == NULL) { + warnx("dbm_open(%s): Invalid offset of macro %d", + fname, im); + goto fail; + } + nvals[im] = be32toh(*ep); + macros[im] = (struct macro *)++ep; + } + return 0; + +fail: + dbm_unmap(); + errno = EFTYPE; + return -1; +} + +void +dbm_close(void) +{ + dbm_unmap(); +} + + +/*** functions for handling pages *************************************/ + +int32_t +dbm_page_count(void) +{ + return npages; +} + +/* + * Give the caller pointers to the data for one manual page. + */ +struct dbm_page * +dbm_page_get(int32_t ip) +{ + static struct dbm_page res; + + assert(ip >= 0); + assert(ip < npages); + res.name = dbm_get(pages[ip].name); + if (res.name == NULL) + res.name = "(NULL)\0"; + res.sect = dbm_get(pages[ip].sect); + if (res.sect == NULL) + res.sect = "(NULL)\0"; + res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL; + res.desc = dbm_get(pages[ip].desc); + if (res.desc == NULL) + res.desc = "(NULL)"; + res.file = dbm_get(pages[ip].file); + if (res.file == NULL) + res.file = " (NULL)\0"; + res.addr = dbm_addr(pages + ip); + return &res; +} + +/* + * Functions to start filtered iterations over manual pages. + */ +void +dbm_page_byname(const struct dbm_match *match) +{ + assert(match != NULL); + page_bytitle(ITER_NAME, match); +} + +void +dbm_page_bysect(const struct dbm_match *match) +{ + assert(match != NULL); + page_bytitle(ITER_SECT, match); +} + +void +dbm_page_byarch(const struct dbm_match *match) +{ + assert(match != NULL); + page_byarch(match); +} + +void +dbm_page_bydesc(const struct dbm_match *match) +{ + assert(match != NULL); + page_bytitle(ITER_DESC, match); +} + +void +dbm_page_bymacro(int32_t im, const struct dbm_match *match) +{ + assert(im >= 0); + assert(im < MACRO_MAX); + assert(match != NULL); + page_bymacro(im, match); +} + +/* + * Return the number of the next manual page in the current iteration. + */ +struct dbm_res +dbm_page_next(void) +{ + struct dbm_res res = {-1, 0}; + + switch(iteration) { + case ITER_NONE: + return res; + case ITER_ARCH: + return page_byarch(NULL); + case ITER_MACRO: + return page_bymacro(0, NULL); + default: + return page_bytitle(iteration, NULL); + } +} + +/* + * Functions implementing the iteration over manual pages. + */ +static struct dbm_res +page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match) +{ + static const struct dbm_match *match; + static const char *cp; + static int32_t ip; + struct dbm_res res = {-1, 0}; + + assert(arg_iter == ITER_NAME || arg_iter == ITER_DESC || + arg_iter == ITER_SECT); + + /* Initialize for a new iteration. */ + + if (arg_match != NULL) { + iteration = arg_iter; + match = arg_match; + switch (iteration) { + case ITER_NAME: + cp = dbm_get(pages[0].name); + break; + case ITER_SECT: + cp = dbm_get(pages[0].sect); + break; + case ITER_DESC: + cp = dbm_get(pages[0].desc); + break; + default: + abort(); + } + if (cp == NULL) { + iteration = ITER_NONE; + match = NULL; + cp = NULL; + ip = npages; + } else + ip = 0; + return res; + } + + /* Search for a name. */ + + while (ip < npages) { + if (iteration == ITER_NAME) + cp++; + if (dbm_match(match, cp)) + break; + cp = strchr(cp, '\0') + 1; + if (iteration == ITER_DESC) + ip++; + else if (*cp == '\0') { + cp++; + ip++; + } + } + + /* Reached the end without a match. */ + + if (ip == npages) { + iteration = ITER_NONE; + match = NULL; + cp = NULL; + return res; + } + + /* Found a match; save the quality for later retrieval. */ + + res.page = ip; + res.bits = iteration == ITER_NAME ? cp[-1] : 0; + + /* Skip the remaining names of this page. */ + + if (++ip < npages) { + do { + cp++; + } while (cp[-1] != '\0' || + (iteration != ITER_DESC && cp[-2] != '\0')); + } + return res; +} + +static struct dbm_res +page_byarch(const struct dbm_match *arg_match) +{ + static const struct dbm_match *match; + struct dbm_res res = {-1, 0}; + static int32_t ip; + const char *cp; + + /* Initialize for a new iteration. */ + + if (arg_match != NULL) { + iteration = ITER_ARCH; + match = arg_match; + ip = 0; + return res; + } + + /* Search for an architecture. */ + + for ( ; ip < npages; ip++) + if (pages[ip].arch) + for (cp = dbm_get(pages[ip].arch); + *cp != '\0'; + cp = strchr(cp, '\0') + 1) + if (dbm_match(match, cp)) { + res.page = ip++; + return res; + } + + /* Reached the end without a match. */ + + iteration = ITER_NONE; + match = NULL; + return res; +} + +static struct dbm_res +page_bymacro(int32_t arg_im, const struct dbm_match *arg_match) +{ + static const struct dbm_match *match; + static const int32_t *pp; + static const char *cp; + static int32_t im, iv; + struct dbm_res res = {-1, 0}; + + assert(im >= 0); + assert(im < MACRO_MAX); + + /* Initialize for a new iteration. */ + + if (arg_match != NULL) { + iteration = ITER_MACRO; + match = arg_match; + im = arg_im; + cp = nvals[im] ? dbm_get(macros[im]->value) : NULL; + pp = NULL; + iv = -1; + return res; + } + if (iteration != ITER_MACRO) + return res; + + /* Find the next matching macro value. */ + + while (pp == NULL || *pp == 0) { + if (++iv == nvals[im]) { + iteration = ITER_NONE; + return res; + } + if (iv) + cp = strchr(cp, '\0') + 1; + if (dbm_match(match, cp)) + pp = dbm_get(macros[im][iv].pages); + } + + /* Found a matching page. */ + + res.page = (struct page *)dbm_get(*pp++) - pages; + return res; +} + + +/*** functions for handling macros ************************************/ + +int32_t +dbm_macro_count(int32_t im) +{ + assert(im >= 0); + assert(im < MACRO_MAX); + return nvals[im]; +} + +struct dbm_macro * +dbm_macro_get(int32_t im, int32_t iv) +{ + static struct dbm_macro macro; + + assert(im >= 0); + assert(im < MACRO_MAX); + assert(iv >= 0); + assert(iv < nvals[im]); + macro.value = dbm_get(macros[im][iv].value); + macro.pp = dbm_get(macros[im][iv].pages); + return ¯o; +} + +/* + * Filtered iteration over macro entries. + */ +void +dbm_macro_bypage(int32_t im, int32_t ip) +{ + assert(im >= 0); + assert(im < MACRO_MAX); + assert(ip != 0); + macro_bypage(im, ip); +} + +char * +dbm_macro_next(void) +{ + return macro_bypage(MACRO_MAX, 0); +} + +static char * +macro_bypage(int32_t arg_im, int32_t arg_ip) +{ + static const int32_t *pp; + static int32_t im, ip, iv; + + /* Initialize for a new iteration. */ + + if (arg_im < MACRO_MAX && arg_ip != 0) { + im = arg_im; + ip = arg_ip; + pp = dbm_get(macros[im]->pages); + iv = 0; + return NULL; + } + if (im >= MACRO_MAX) + return NULL; + + /* Search for the next value. */ + + while (iv < nvals[im]) { + if (*pp == ip) + break; + if (*pp == 0) + iv++; + pp++; + } + + /* Reached the end without a match. */ + + if (iv == nvals[im]) { + im = MACRO_MAX; + ip = 0; + pp = NULL; + return NULL; + } + + /* Found a match; skip the remaining pages of this entry. */ + + if (++iv < nvals[im]) + while (*pp++ != 0) + continue; + + return dbm_get(macros[im][iv - 1].value); +} Property changes on: vendor/mandoc/20190723/dbm.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dbm_map.h =================================================================== --- vendor/mandoc/20190723/dbm_map.h (nonexistent) +++ vendor/mandoc/20190723/dbm_map.h (revision 350350) @@ -0,0 +1,29 @@ +/* $Id: dbm_map.h,v 1.2 2019/07/01 22:56:24 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Private interface for low-level routines for the map-based version + * of the mandoc database, for read-only access. + * To be used by dbm*.c only. + */ + +struct dbm_match; + +int dbm_map(const char *); +void dbm_unmap(void); +void *dbm_get(int32_t); +int32_t *dbm_getint(int32_t); +int32_t dbm_addr(const void *); +int dbm_match(const struct dbm_match *, const char *); Property changes on: vendor/mandoc/20190723/dbm_map.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/eqn.7 =================================================================== --- vendor/mandoc/20190723/eqn.7 (nonexistent) +++ vendor/mandoc/20190723/eqn.7 (revision 350350) @@ -0,0 +1,500 @@ +.\" $Id: eqn.7,v 1.38 2019/04/23 17:57:49 schwarze Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons +.\" Copyright (c) 2014 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: April 23 2019 $ +.Dt EQN 7 +.Os +.Sh NAME +.Nm eqn +.Nd eqn language reference for mandoc +.Sh DESCRIPTION +The +.Nm eqn +language is an equation-formatting language. +It is used within +.Xr mdoc 7 +and +.Xr man 7 +.Ux +manual pages. +It describes the +.Em structure +of an equation, not its mathematical meaning. +This manual describes the +.Nm +language accepted by the +.Xr mandoc 1 +utility, which corresponds to the Second Edition +.Nm +specification (see +.Sx SEE ALSO +for references). +.Pp +Equations within +.Xr mdoc 7 +or +.Xr man 7 +documents are enclosed by the standalone +.Sq \&.EQ +and +.Sq \&.EN +tags. +Equations are multi-line blocks consisting of formulas and control +statements. +.Sh EQUATION STRUCTURE +Each equation is bracketed by +.Sq \&.EQ +and +.Sq \&.EN +strings. +.Em Note : +these are not the same as +.Xr roff 7 +macros, and may only be invoked as +.Sq \&.EQ . +.Pp +The equation grammar is as follows, where quoted strings are +case-sensitive literals in the input: +.Bd -literal -offset indent +eqn : box | eqn box +box : text + | \(dq{\(dq eqn \(dq}\(dq + | \(dqdefine\(dq text text + | \(dqndefine\(dq text text + | \(dqtdefine\(dq text text + | \(dqgfont\(dq text + | \(dqgsize\(dq text + | \(dqset\(dq text text + | \(dqundef\(dq text + | \(dqsqrt\(dq box + | box pos box + | box mark + | \(dqmatrix\(dq \(dq{\(dq [col \(dq{\(dq list \(dq}\(dq]* \(dq}\(dq + | pile \(dq{\(dq list \(dq}\(dq + | font box + | \(dqsize\(dq text box + | \(dqleft\(dq text eqn [\(dqright\(dq text] +col : \(dqlcol\(dq | \(dqrcol\(dq | \(dqccol\(dq | \(dqcol\(dq +text : [^space\e\(dq]+ | \e\(dq.*\e\(dq +pile : \(dqlpile\(dq | \(dqcpile\(dq | \(dqrpile\(dq | \(dqpile\(dq +pos : \(dqover\(dq | \(dqsup\(dq | \(dqsub\(dq | \(dqto\(dq | \(dqfrom\(dq +mark : \(dqdot\(dq | \(dqdotdot\(dq | \(dqhat\(dq | \(dqtilde\(dq | \(dqvec\(dq + | \(dqdyad\(dq | \(dqbar\(dq | \(dqunder\(dq +font : \(dqroman\(dq | \(dqitalic\(dq | \(dqbold\(dq | \(dqfat\(dq +list : eqn + | list \(dqabove\(dq eqn +space : [\e^~ \et] +.Ed +.Pp +White-space consists of the space, tab, circumflex, and tilde +characters. +It is required to delimit tokens consisting of alphabetic characters +and it is ignored at other places. +Braces and quotes also delimit tokens. +If within a quoted string, these space characters are retained. +Quoted strings are also not scanned for keywords, glyph names, +and expansion of definitions. +To print a literal quote character, it can be prepended with a +backslash or expressed with the \e(dq escape sequence. +.Pp +Subequations can be enclosed in braces to pass them as arguments +to operation keywords, overriding standard operation precedence. +Braces can be nested. +To set a brace verbatim, it needs to be enclosed in quotes. +.Pp +The following text terms are translated into a rendered glyph, if +available: alpha, beta, chi, delta, epsilon, eta, gamma, iota, kappa, +lambda, mu, nu, omega, omicron, phi, pi, psi, rho, sigma, tau, theta, +upsilon, xi, zeta, DELTA, GAMMA, LAMBDA, OMEGA, PHI, PI, PSI, SIGMA, +THETA, UPSILON, XI, inter (intersection), union (union), prod (product), +int (integral), sum (summation), grad (gradient), del (vector +differential), times (multiply), cdot (center-dot), nothing (zero-width +space), approx (approximately equals), prime (prime), half (one-half), +partial (partial differential), inf (infinity), >> (much greater), << +(much less), <\- (left arrow), \-> (right arrow), +\- (plus-minus), != +(not equal), == (equivalence), <= (less-than-equal), and >= +(more-than-equal). +The character escape sequences documented in +.Xr mandoc_char 7 +can be used, too. +.Pp +The following control statements are available: +.Bl -tag -width Ds +.It Cm define +Replace all occurrences of a key with a value. +Its syntax is as follows: +.Pp +.D1 Cm define Ar key cvalc +.Pp +The first character of the value string, +.Ar c , +is used as the delimiter for the value +.Ar val . +This allows for arbitrary enclosure of terms (not just quotes), such as +.Pp +.D1 Cm define Ar foo \(aqbar baz\(aq +.D1 Cm define Ar foo cbar bazc +.Pp +It is an error to have an empty +.Ar key +or +.Ar val . +Note that a quoted +.Ar key +causes errors in some +.Nm +implementations and should not be considered portable. +It is not expanded for replacements. +Definitions may refer to other definitions; these are evaluated +recursively when text replacement occurs and not when the definition is +created. +.Pp +Definitions can create arbitrary strings, for example, the following is +a legal construction. +.Bd -literal -offset indent +define foo \(aqdefine\(aq +foo bar \(aqbaz\(aq +.Ed +.Pp +Self-referencing definitions will raise an error. +The +.Cm ndefine +statement is a synonym for +.Cm define , +while +.Cm tdefine +is discarded. +.It Cm gfont +Set the default font of subsequent output. +Its syntax is as follows: +.Pp +.D1 Cm gfont Ar font +.Pp +In mandoc, this value is discarded. +.It Cm gsize +Set the default size of subsequent output. +Its syntax is as follows: +.Pp +.D1 Cm gsize Oo +|\- Oc Ns Ar size +.Pp +The +.Ar size +value should be an integer. +If prepended by a sign, +the font size is changed relative to the current size. +.It Cm set +Set an equation mode. +In mandoc, both arguments are thrown away. +Its syntax is as follows: +.Pp +.D1 Cm set Ar key val +.Pp +The +.Ar key +and +.Ar val +are not expanded for replacements. +This statement is a GNU extension. +.It Cm undef +Unset a previously-defined key. +Its syntax is as follows: +.Pp +.D1 Cm define Ar key +.Pp +Once invoked, the definition for +.Ar key +is discarded. +The +.Ar key +is not expanded for replacements. +This statement is a GNU extension. +.El +.Pp +Operation keywords have the following semantics: +.Bl -tag -width Ds +.It Cm above +See +.Cm pile . +.It Cm bar +Draw a line over the preceding box. +.It Cm bold +Set the following box using bold font. +.It Cm ccol +Like +.Cm cpile , +but for use in +.Cm matrix . +.It Cm cpile +Like +.Cm pile , +but with slightly increased vertical spacing. +.It Cm dot +Set a single dot over the preceding box. +.It Cm dotdot +Set two dots (dieresis) over the preceding box. +.It Cm dyad +Set a dyad symbol (left-right arrow) over the preceding box. +.It Cm fat +A synonym for +.Cm bold . +.It Cm font +Set the second argument using the font specified by the first argument; +currently not recognized by the +.Xr mandoc 1 +.Nm +parser. +.It Cm from +Set the following box below the preceding box, +using a slightly smaller font. +Used for sums, integrals, limits, and the like. +.It Cm hat +Set a hat (circumflex) over the preceding box. +.It Cm italic +Set the following box using italic font. +.It Cm lcol +Like +.Cm lpile , +but for use in +.Cm matrix . +.It Cm left +Set the first argument as a big left delimiter before the second argument. +As an optional third argument, +.Cm right +can follow. +In that case, the fourth argument is set as a big right delimiter after +the second argument. +.It Cm lpile +Like +.Cm cpile , +but subequations are left-justified. +.It Cm matrix +Followed by a list of columns enclosed in braces. +All columns need to have the same number of subequations. +The columns are set as a matrix. +The difference compared to multiple subsequent +.Cm pile +operators is that in a +.Cm matrix , +corresponding subequations in all columns line up horizontally, +while each +.Cm pile +does vertical spacing independently. +.It Cm over +Set a fraction. +The preceding box is the numerator, the following box is the denominator. +.It Cm pile +Followed by a list of subequations enclosed in braces, +the subequations being separated by +.Cm above +keywords. +Sets the subequations one above the other, each of them centered. +Typically used to represent vectors in coordinate representation. +.It Cm rcol +Like +.Cm rpile , +but for use in +.Cm matrix . +.It Cm right +See +.Cm left ; +.Cm right +cannot be used without +.Cm left . +To set a big right delimiter without a big left delimiter, the following +construction can be used: +.Pp +.D1 Cm left No \(dq\(dq Ar box Cm right Ar delimiter +.It Cm roman +Set the following box using the default font. +.It Cm rpile +Like +.Cm cpile , +but subequations are right-justified. +.It Cm size +Set the second argument with the font size specified by the first +argument; currently ignored by +.Xr mandoc 1 . +By prepending a plus or minus sign to the first argument, +the font size can be selected relative to the current size. +.It Cm sqrt +Set the square root of the following box. +.It Cm sub +Set the following box as a subscript to the preceding box. +.It Cm sup +Set the following box as a superscript to the preceding box. +As a special case, if a +.Cm sup +clause immediately follows a +.Cm sub +clause as in +.Pp +.D1 Ar mainbox Cm sub Ar subbox Cm sup Ar supbox +.Pp +both are set with respect to the same +.Ar mainbox , +that is, +.Ar supbox +is set above +.Ar subbox . +.It Cm tilde +Set a tilde over the preceding box. +.It Cm to +Set the following box above the preceding box, +using a slightly smaller font. +Used for sums and integrals and the like. +As a special case, if a +.Cm to +clause immediately follows a +.Cm from +clause as in +.Pp +.D1 Ar mainbox Cm from Ar frombox Cm to Ar tobox +.Pp +both are set below and above the same +.Ar mainbox . +.It Cm under +Underline the preceding box. +.It Cm vec +Set a vector symbol (right arrow) over the preceding box. +.El +.Pp +The binary operations +.Cm from , +.Cm to , +.Cm sub , +and +.Cm sup +group to the right, that is, +.Pp +.D1 Ar mainbox Cm sup Ar supbox Cm sub Ar subbox +.Pp +is the same as +.Pp +.D1 Ar mainbox Cm sup Brq Ar supbox Cm sub Ar subbox +.Pp +and different from +.Pp +.D1 Bro Ar mainbox Cm sup Ar supbox Brc Cm sub Ar subbox . +.Pp +By contrast, +.Cm over +groups to the left. +.Pp +In the following list, earlier operations bind more tightly than +later operations: +.Pp +.Bl -enum -compact +.It +.Cm dyad , +.Cm vec , +.Cm under , +.Cm bar , +.Cm tilde , +.Cm hat , +.Cm dot , +.Cm dotdot +.It +.Cm fat , +.Cm roman , +.Cm italic , +.Cm bold , +.Cm size +.It +.Cm sub , +.Cm sup +.It +.Cm sqrt +.It +.Cm over +.It +.Cm from , +.Cm to +.El +.Sh COMPATIBILITY +This section documents the compatibility of mandoc +.Nm +and the troff +.Nm +implementation (including GNU troff). +.Pp +.Bl -dash -compact +.It +The text string +.Sq \e\(dq +is interpreted as a literal quote in troff. +In mandoc, this is interpreted as a comment. +.It +In troff, The circumflex and tilde white-space symbols map to +fixed-width spaces. +In mandoc, these characters are synonyms for the space character. +.It +The troff implementation of +.Nm +allows for equation alignment with the +.Cm mark +and +.Cm lineup +tokens. +mandoc discards these tokens. +The +.Cm back Ar n , +.Cm fwd Ar n , +.Cm up Ar n , +and +.Cm down Ar n +commands are also ignored. +.El +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr man 7 , +.Xr mandoc_char 7 , +.Xr mdoc 7 , +.Xr roff 7 +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T System for Typesetting Mathematics +.%J Communications of the ACM +.%V 18 +.%P pp. 151\(en157 +.%D March, 1975 +.Re +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T Typesetting Mathematics, User's Guide +.%D 1976 +.Re +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T Typesetting Mathematics, User's Guide (Second Edition) +.%D 1978 +.Re +.Sh HISTORY +The eqn utility, a preprocessor for troff, was originally written by +Brian W. Kernighan and Lorinda L. Cherry in 1975. +The GNU reimplementation of eqn, part of the GNU troff package, was +released in 1989 by James Clark. +The eqn component of +.Xr mandoc 1 +was added in 2011. +.Sh AUTHORS +This +.Nm +reference was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . Property changes on: vendor/mandoc/20190723/eqn.7 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/eqn_html.c =================================================================== --- vendor/mandoc/20190723/eqn_html.c (nonexistent) +++ vendor/mandoc/20190723/eqn_html.c (revision 350350) @@ -0,0 +1,246 @@ +/* $Id: eqn_html.c,v 1.19 2019/03/17 18:21:45 schwarze Exp $ */ +/* + * Copyright (c) 2011, 2014 Kristaps Dzonsons + * Copyright (c) 2017 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "eqn.h" +#include "out.h" +#include "html.h" + +static void +eqn_box(struct html *p, const struct eqn_box *bp) +{ + struct tag *post, *row, *cell, *t; + const struct eqn_box *child, *parent; + const char *cp; + size_t i, j, rows; + enum htmltag tag; + enum eqn_fontt font; + + if (NULL == bp) + return; + + post = NULL; + + /* + * Special handling for a matrix, which is presented to us in + * column order, but must be printed in row-order. + */ + if (EQN_MATRIX == bp->type) { + if (NULL == bp->first) + goto out; + if (bp->first->type != EQN_LIST || + bp->first->expectargs == 1) { + eqn_box(p, bp->first); + goto out; + } + if (NULL == (parent = bp->first->first)) + goto out; + /* Estimate the number of rows, first. */ + if (NULL == (child = parent->first)) + goto out; + for (rows = 0; NULL != child; rows++) + child = child->next; + /* Print row-by-row. */ + post = print_otag(p, TAG_MTABLE, ""); + for (i = 0; i < rows; i++) { + parent = bp->first->first; + row = print_otag(p, TAG_MTR, ""); + while (NULL != parent) { + child = parent->first; + for (j = 0; j < i; j++) { + if (NULL == child) + break; + child = child->next; + } + cell = print_otag(p, TAG_MTD, ""); + /* + * If we have no data for this + * particular cell, then print a + * placeholder and continue--don't puke. + */ + if (NULL != child) + eqn_box(p, child->first); + print_tagq(p, cell); + parent = parent->next; + } + print_tagq(p, row); + } + goto out; + } + + switch (bp->pos) { + case EQNPOS_TO: + post = print_otag(p, TAG_MOVER, ""); + break; + case EQNPOS_SUP: + post = print_otag(p, TAG_MSUP, ""); + break; + case EQNPOS_FROM: + post = print_otag(p, TAG_MUNDER, ""); + break; + case EQNPOS_SUB: + post = print_otag(p, TAG_MSUB, ""); + break; + case EQNPOS_OVER: + post = print_otag(p, TAG_MFRAC, ""); + break; + case EQNPOS_FROMTO: + post = print_otag(p, TAG_MUNDEROVER, ""); + break; + case EQNPOS_SUBSUP: + post = print_otag(p, TAG_MSUBSUP, ""); + break; + case EQNPOS_SQRT: + post = print_otag(p, TAG_MSQRT, ""); + break; + default: + break; + } + + if (bp->top || bp->bottom) { + assert(NULL == post); + if (bp->top && NULL == bp->bottom) + post = print_otag(p, TAG_MOVER, ""); + else if (bp->top && bp->bottom) + post = print_otag(p, TAG_MUNDEROVER, ""); + else if (bp->bottom) + post = print_otag(p, TAG_MUNDER, ""); + } + + if (EQN_PILE == bp->type) { + assert(NULL == post); + if (bp->first != NULL && + bp->first->type == EQN_LIST && + bp->first->expectargs > 1) + post = print_otag(p, TAG_MTABLE, ""); + } else if (bp->type == EQN_LIST && bp->expectargs > 1 && + bp->parent && bp->parent->type == EQN_PILE) { + assert(NULL == post); + post = print_otag(p, TAG_MTR, ""); + print_otag(p, TAG_MTD, ""); + } + + if (bp->text != NULL) { + assert(post == NULL); + tag = TAG_MI; + cp = bp->text; + if (isdigit((unsigned char)cp[0]) || + (cp[0] == '.' && isdigit((unsigned char)cp[1]))) { + tag = TAG_MN; + while (*++cp != '\0') { + if (*cp != '.' && + isdigit((unsigned char)*cp) == 0) { + tag = TAG_MI; + break; + } + } + } else if (*cp != '\0' && isalpha((unsigned char)*cp) == 0) { + tag = TAG_MO; + while (*cp != '\0') { + if (cp[0] == '\\' && cp[1] != '\0') { + cp++; + mandoc_escape(&cp, NULL, NULL); + } else if (isalnum((unsigned char)*cp)) { + tag = TAG_MI; + break; + } else + cp++; + } + } + font = bp->font; + if (bp->text[0] != '\0' && + (((tag == TAG_MN || tag == TAG_MO) && + font == EQNFONT_ROMAN) || + (tag == TAG_MI && font == (bp->text[1] == '\0' ? + EQNFONT_ITALIC : EQNFONT_ROMAN)))) + font = EQNFONT_NONE; + switch (font) { + case EQNFONT_NONE: + post = print_otag(p, tag, ""); + break; + case EQNFONT_ROMAN: + post = print_otag(p, tag, "?", "fontstyle", "normal"); + break; + case EQNFONT_BOLD: + case EQNFONT_FAT: + post = print_otag(p, tag, "?", "fontweight", "bold"); + break; + case EQNFONT_ITALIC: + post = print_otag(p, tag, "?", "fontstyle", "italic"); + break; + default: + abort(); + } + print_text(p, bp->text); + } else if (NULL == post) { + if (NULL != bp->left || NULL != bp->right) + post = print_otag(p, TAG_MFENCED, "??", + "open", bp->left == NULL ? "" : bp->left, + "close", bp->right == NULL ? "" : bp->right); + if (NULL == post) + post = print_otag(p, TAG_MROW, ""); + else + print_otag(p, TAG_MROW, ""); + } + + eqn_box(p, bp->first); + +out: + if (NULL != bp->bottom) { + t = print_otag(p, TAG_MO, ""); + print_text(p, bp->bottom); + print_tagq(p, t); + } + if (NULL != bp->top) { + t = print_otag(p, TAG_MO, ""); + print_text(p, bp->top); + print_tagq(p, t); + } + + if (NULL != post) + print_tagq(p, post); + + eqn_box(p, bp->next); +} + +void +print_eqn(struct html *p, const struct eqn_box *bp) +{ + struct tag *t; + + if (bp->first == NULL) + return; + + t = print_otag(p, TAG_MATH, "c", "eqn"); + + p->flags |= HTML_NONOSPACE; + eqn_box(p, bp); + p->flags &= ~HTML_NONOSPACE; + + print_tagq(p, t); +} Property changes on: vendor/mandoc/20190723/eqn_html.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/html.c =================================================================== --- vendor/mandoc/20190723/html.c (nonexistent) +++ vendor/mandoc/20190723/html.c (revision 350350) @@ -0,0 +1,965 @@ +/* $Id: html.c,v 1.255 2019/04/30 15:53:00 schwarze Exp $ */ +/* + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons + * Copyright (c) 2011-2015, 2017-2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "mandoc.h" +#include "roff.h" +#include "out.h" +#include "html.h" +#include "manconf.h" +#include "main.h" + +struct htmldata { + const char *name; + int flags; +#define HTML_NOSTACK (1 << 0) +#define HTML_AUTOCLOSE (1 << 1) +#define HTML_NLBEFORE (1 << 2) +#define HTML_NLBEGIN (1 << 3) +#define HTML_NLEND (1 << 4) +#define HTML_NLAFTER (1 << 5) +#define HTML_NLAROUND (HTML_NLBEFORE | HTML_NLAFTER) +#define HTML_NLINSIDE (HTML_NLBEGIN | HTML_NLEND) +#define HTML_NLALL (HTML_NLAROUND | HTML_NLINSIDE) +#define HTML_INDENT (1 << 6) +#define HTML_NOINDENT (1 << 7) +}; + +static const struct htmldata htmltags[TAG_MAX] = { + {"html", HTML_NLALL}, + {"head", HTML_NLALL | HTML_INDENT}, + {"body", HTML_NLALL}, + {"meta", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, + {"title", HTML_NLAROUND}, + {"div", HTML_NLAROUND}, + {"div", 0}, + {"section", HTML_NLALL}, + {"h1", HTML_NLAROUND}, + {"h2", HTML_NLAROUND}, + {"span", 0}, + {"link", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, + {"br", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, + {"a", 0}, + {"table", HTML_NLALL | HTML_INDENT}, + {"tr", HTML_NLALL | HTML_INDENT}, + {"td", HTML_NLAROUND}, + {"li", HTML_NLAROUND | HTML_INDENT}, + {"ul", HTML_NLALL | HTML_INDENT}, + {"ol", HTML_NLALL | HTML_INDENT}, + {"dl", HTML_NLALL | HTML_INDENT}, + {"dt", HTML_NLAROUND}, + {"dd", HTML_NLAROUND | HTML_INDENT}, + {"p", HTML_NLAROUND | HTML_INDENT}, + {"pre", HTML_NLALL | HTML_NOINDENT}, + {"var", 0}, + {"cite", 0}, + {"b", 0}, + {"i", 0}, + {"code", 0}, + {"small", 0}, + {"style", HTML_NLALL | HTML_INDENT}, + {"math", HTML_NLALL | HTML_INDENT}, + {"mrow", 0}, + {"mi", 0}, + {"mn", 0}, + {"mo", 0}, + {"msup", 0}, + {"msub", 0}, + {"msubsup", 0}, + {"mfrac", 0}, + {"msqrt", 0}, + {"mfenced", 0}, + {"mtable", 0}, + {"mtr", 0}, + {"mtd", 0}, + {"munderover", 0}, + {"munder", 0}, + {"mover", 0}, +}; + +/* Avoid duplicate HTML id= attributes. */ +static struct ohash id_unique; + +static void html_reset_internal(struct html *); +static void print_byte(struct html *, char); +static void print_endword(struct html *); +static void print_indent(struct html *); +static void print_word(struct html *, const char *); + +static void print_ctag(struct html *, struct tag *); +static int print_escape(struct html *, char); +static int print_encode(struct html *, const char *, const char *, int); +static void print_href(struct html *, const char *, const char *, int); +static void print_metaf(struct html *); + + +void * +html_alloc(const struct manoutput *outopts) +{ + struct html *h; + + h = mandoc_calloc(1, sizeof(struct html)); + + h->tag = NULL; + h->style = outopts->style; + if ((h->base_man1 = outopts->man) == NULL) + h->base_man2 = NULL; + else if ((h->base_man2 = strchr(h->base_man1, ';')) != NULL) + *h->base_man2++ = '\0'; + h->base_includes = outopts->includes; + if (outopts->fragment) + h->oflags |= HTML_FRAGMENT; + if (outopts->toc) + h->oflags |= HTML_TOC; + + mandoc_ohash_init(&id_unique, 4, 0); + + return h; +} + +static void +html_reset_internal(struct html *h) +{ + struct tag *tag; + char *cp; + unsigned int slot; + + while ((tag = h->tag) != NULL) { + h->tag = tag->next; + free(tag); + } + cp = ohash_first(&id_unique, &slot); + while (cp != NULL) { + free(cp); + cp = ohash_next(&id_unique, &slot); + } + ohash_delete(&id_unique); +} + +void +html_reset(void *p) +{ + html_reset_internal(p); + mandoc_ohash_init(&id_unique, 4, 0); +} + +void +html_free(void *p) +{ + html_reset_internal(p); + free(p); +} + +void +print_gen_head(struct html *h) +{ + struct tag *t; + + print_otag(h, TAG_META, "?", "charset", "utf-8"); + if (h->style != NULL) { + print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet", + h->style, "type", "text/css", "media", "all"); + return; + } + + /* + * Print a minimal embedded style sheet. + */ + + t = print_otag(h, TAG_STYLE, ""); + print_text(h, "table.head, table.foot { width: 100%; }"); + print_endline(h); + print_text(h, "td.head-rtitle, td.foot-os { text-align: right; }"); + print_endline(h); + print_text(h, "td.head-vol { text-align: center; }"); + print_endline(h); + print_text(h, "div.Pp { margin: 1ex 0ex; }"); + print_endline(h); + print_text(h, "div.Nd, div.Bf, div.Op { display: inline; }"); + print_endline(h); + print_text(h, "span.Pa, span.Ad { font-style: italic; }"); + print_endline(h); + print_text(h, "span.Ms { font-weight: bold; }"); + print_endline(h); + print_text(h, "dl.Bl-diag "); + print_byte(h, '>'); + print_text(h, " dt { font-weight: bold; }"); + print_endline(h); + print_text(h, "code.Nm, code.Fl, code.Cm, code.Ic, " + "code.In, code.Fd, code.Fn,"); + print_endline(h); + print_text(h, "code.Cd { font-weight: bold; " + "font-family: inherit; }"); + print_tagq(h, t); +} + +int +html_setfont(struct html *h, enum mandoc_esc font) +{ + switch (font) { + case ESCAPE_FONTPREV: + font = h->metal; + break; + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTBI: + case ESCAPE_FONTCW: + case ESCAPE_FONTROMAN: + break; + case ESCAPE_FONT: + font = ESCAPE_FONTROMAN; + break; + default: + return 0; + } + h->metal = h->metac; + h->metac = font; + return 1; +} + +static void +print_metaf(struct html *h) +{ + if (h->metaf) { + print_tagq(h, h->metaf); + h->metaf = NULL; + } + switch (h->metac) { + case ESCAPE_FONTITALIC: + h->metaf = print_otag(h, TAG_I, ""); + break; + case ESCAPE_FONTBOLD: + h->metaf = print_otag(h, TAG_B, ""); + break; + case ESCAPE_FONTBI: + h->metaf = print_otag(h, TAG_B, ""); + print_otag(h, TAG_I, ""); + break; + case ESCAPE_FONTCW: + h->metaf = print_otag(h, TAG_SPAN, "c", "Li"); + break; + default: + break; + } +} + +void +html_close_paragraph(struct html *h) +{ + struct tag *t; + + for (t = h->tag; t != NULL && t->closed == 0; t = t->next) { + switch(t->tag) { + case TAG_P: + case TAG_PRE: + print_tagq(h, t); + break; + case TAG_A: + print_tagq(h, t); + continue; + default: + continue; + } + break; + } +} + +/* + * ROFF_nf switches to no-fill mode, ROFF_fi to fill mode. + * TOKEN_NONE does not switch. The old mode is returned. + */ +enum roff_tok +html_fillmode(struct html *h, enum roff_tok want) +{ + struct tag *t; + enum roff_tok had; + + for (t = h->tag; t != NULL; t = t->next) + if (t->tag == TAG_PRE) + break; + + had = t == NULL ? ROFF_fi : ROFF_nf; + + if (want != had) { + switch (want) { + case ROFF_fi: + print_tagq(h, t); + break; + case ROFF_nf: + html_close_paragraph(h); + print_otag(h, TAG_PRE, ""); + break; + case TOKEN_NONE: + break; + default: + abort(); + } + } + return had; +} + +char * +html_make_id(const struct roff_node *n, int unique) +{ + const struct roff_node *nch; + char *buf, *bufs, *cp; + unsigned int slot; + int suffix; + + for (nch = n->child; nch != NULL; nch = nch->next) + if (nch->type != ROFFT_TEXT) + return NULL; + + buf = NULL; + deroff(&buf, n); + if (buf == NULL) + return NULL; + + /* + * In ID attributes, only use ASCII characters that are + * permitted in URL-fragment strings according to the + * explicit list at: + * https://url.spec.whatwg.org/#url-fragment-string + */ + + for (cp = buf; *cp != '\0'; cp++) + if (isalnum((unsigned char)*cp) == 0 && + strchr("!$&'()*+,-./:;=?@_~", *cp) == NULL) + *cp = '_'; + + if (unique == 0) + return buf; + + /* Avoid duplicate HTML id= attributes. */ + + bufs = NULL; + suffix = 1; + slot = ohash_qlookup(&id_unique, buf); + cp = ohash_find(&id_unique, slot); + if (cp != NULL) { + while (cp != NULL) { + free(bufs); + if (++suffix > 127) { + free(buf); + return NULL; + } + mandoc_asprintf(&bufs, "%s_%d", buf, suffix); + slot = ohash_qlookup(&id_unique, bufs); + cp = ohash_find(&id_unique, slot); + } + free(buf); + buf = bufs; + } + ohash_insert(&id_unique, slot, buf); + return buf; +} + +static int +print_escape(struct html *h, char c) +{ + + switch (c) { + case '<': + print_word(h, "<"); + break; + case '>': + print_word(h, ">"); + break; + case '&': + print_word(h, "&"); + break; + case '"': + print_word(h, """); + break; + case ASCII_NBRSP: + print_word(h, " "); + break; + case ASCII_HYPH: + print_byte(h, '-'); + break; + case ASCII_BREAK: + break; + default: + return 0; + } + return 1; +} + +static int +print_encode(struct html *h, const char *p, const char *pend, int norecurse) +{ + char numbuf[16]; + const char *seq; + size_t sz; + int c, len, breakline, nospace; + enum mandoc_esc esc; + static const char rejs[10] = { ' ', '\\', '<', '>', '&', '"', + ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' }; + + if (pend == NULL) + pend = strchr(p, '\0'); + + breakline = 0; + nospace = 0; + + while (p < pend) { + if (HTML_SKIPCHAR & h->flags && '\\' != *p) { + h->flags &= ~HTML_SKIPCHAR; + p++; + continue; + } + + for (sz = strcspn(p, rejs); sz-- && p < pend; p++) + print_byte(h, *p); + + if (breakline && + (p >= pend || *p == ' ' || *p == ASCII_NBRSP)) { + print_otag(h, TAG_BR, ""); + breakline = 0; + while (p < pend && (*p == ' ' || *p == ASCII_NBRSP)) + p++; + continue; + } + + if (p >= pend) + break; + + if (*p == ' ') { + print_endword(h); + p++; + continue; + } + + if (print_escape(h, *p++)) + continue; + + esc = mandoc_escape(&p, &seq, &len); + switch (esc) { + case ESCAPE_FONT: + case ESCAPE_FONTPREV: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBI: + case ESCAPE_FONTCW: + case ESCAPE_FONTROMAN: + if (0 == norecurse) { + h->flags |= HTML_NOSPACE; + if (html_setfont(h, esc)) + print_metaf(h); + h->flags &= ~HTML_NOSPACE; + } + continue; + case ESCAPE_SKIPCHAR: + h->flags |= HTML_SKIPCHAR; + continue; + case ESCAPE_ERROR: + continue; + default: + break; + } + + if (h->flags & HTML_SKIPCHAR) { + h->flags &= ~HTML_SKIPCHAR; + continue; + } + + switch (esc) { + case ESCAPE_UNICODE: + /* Skip past "u" header. */ + c = mchars_num2uc(seq + 1, len - 1); + break; + case ESCAPE_NUMBERED: + c = mchars_num2char(seq, len); + if (c < 0) + continue; + break; + case ESCAPE_SPECIAL: + c = mchars_spec2cp(seq, len); + if (c <= 0) + continue; + break; + case ESCAPE_UNDEF: + c = *seq; + break; + case ESCAPE_DEVICE: + print_word(h, "html"); + continue; + case ESCAPE_BREAK: + breakline = 1; + continue; + case ESCAPE_NOSPACE: + if ('\0' == *p) + nospace = 1; + continue; + case ESCAPE_OVERSTRIKE: + if (len == 0) + continue; + c = seq[len - 1]; + break; + default: + continue; + } + if ((c < 0x20 && c != 0x09) || + (c > 0x7E && c < 0xA0)) + c = 0xFFFD; + if (c > 0x7E) { + (void)snprintf(numbuf, sizeof(numbuf), "&#x%.4X;", c); + print_word(h, numbuf); + } else if (print_escape(h, c) == 0) + print_byte(h, c); + } + + return nospace; +} + +static void +print_href(struct html *h, const char *name, const char *sec, int man) +{ + struct stat sb; + const char *p, *pp; + char *filename; + + if (man) { + pp = h->base_man1; + if (h->base_man2 != NULL) { + mandoc_asprintf(&filename, "%s.%s", name, sec); + if (stat(filename, &sb) == -1) + pp = h->base_man2; + free(filename); + } + } else + pp = h->base_includes; + + while ((p = strchr(pp, '%')) != NULL) { + print_encode(h, pp, p, 1); + if (man && p[1] == 'S') { + if (sec == NULL) + print_byte(h, '1'); + else + print_encode(h, sec, NULL, 1); + } else if ((man && p[1] == 'N') || + (man == 0 && p[1] == 'I')) + print_encode(h, name, NULL, 1); + else + print_encode(h, p, p + 2, 1); + pp = p + 2; + } + if (*pp != '\0') + print_encode(h, pp, NULL, 1); +} + +struct tag * +print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) +{ + va_list ap; + struct tag *t; + const char *attr; + char *arg1, *arg2; + int style_written, tflags; + + tflags = htmltags[tag].flags; + + /* Push this tag onto the stack of open scopes. */ + + if ((tflags & HTML_NOSTACK) == 0) { + t = mandoc_malloc(sizeof(struct tag)); + t->tag = tag; + t->next = h->tag; + t->refcnt = 0; + t->closed = 0; + h->tag = t; + } else + t = NULL; + + if (tflags & HTML_NLBEFORE) + print_endline(h); + if (h->col == 0) + print_indent(h); + else if ((h->flags & HTML_NOSPACE) == 0) { + if (h->flags & HTML_KEEP) + print_word(h, " "); + else { + if (h->flags & HTML_PREKEEP) + h->flags |= HTML_KEEP; + print_endword(h); + } + } + + if ( ! (h->flags & HTML_NONOSPACE)) + h->flags &= ~HTML_NOSPACE; + else + h->flags |= HTML_NOSPACE; + + /* Print out the tag name and attributes. */ + + print_byte(h, '<'); + print_word(h, htmltags[tag].name); + + va_start(ap, fmt); + + while (*fmt != '\0' && *fmt != 's') { + + /* Parse attributes and arguments. */ + + arg1 = va_arg(ap, char *); + arg2 = NULL; + switch (*fmt++) { + case 'c': + attr = "class"; + break; + case 'h': + attr = "href"; + break; + case 'i': + attr = "id"; + break; + case '?': + attr = arg1; + arg1 = va_arg(ap, char *); + break; + default: + abort(); + } + if (*fmt == 'M') + arg2 = va_arg(ap, char *); + if (arg1 == NULL) + continue; + + /* Print the attributes. */ + + print_byte(h, ' '); + print_word(h, attr); + print_byte(h, '='); + print_byte(h, '"'); + switch (*fmt) { + case 'I': + print_href(h, arg1, NULL, 0); + fmt++; + break; + case 'M': + print_href(h, arg1, arg2, 1); + fmt++; + break; + case 'R': + print_byte(h, '#'); + print_encode(h, arg1, NULL, 1); + fmt++; + break; + default: + print_encode(h, arg1, NULL, 1); + break; + } + print_byte(h, '"'); + } + + style_written = 0; + while (*fmt++ == 's') { + arg1 = va_arg(ap, char *); + arg2 = va_arg(ap, char *); + if (arg2 == NULL) + continue; + print_byte(h, ' '); + if (style_written == 0) { + print_word(h, "style=\""); + style_written = 1; + } + print_word(h, arg1); + print_byte(h, ':'); + print_byte(h, ' '); + print_word(h, arg2); + print_byte(h, ';'); + } + if (style_written) + print_byte(h, '"'); + + va_end(ap); + + /* Accommodate for "well-formed" singleton escaping. */ + + if (HTML_AUTOCLOSE & htmltags[tag].flags) + print_byte(h, '/'); + + print_byte(h, '>'); + + if (tflags & HTML_NLBEGIN) + print_endline(h); + else + h->flags |= HTML_NOSPACE; + + if (tflags & HTML_INDENT) + h->indent++; + if (tflags & HTML_NOINDENT) + h->noindent++; + + return t; +} + +static void +print_ctag(struct html *h, struct tag *tag) +{ + int tflags; + + if (tag->closed == 0) { + tag->closed = 1; + if (tag == h->metaf) + h->metaf = NULL; + if (tag == h->tblt) + h->tblt = NULL; + + tflags = htmltags[tag->tag].flags; + if (tflags & HTML_INDENT) + h->indent--; + if (tflags & HTML_NOINDENT) + h->noindent--; + if (tflags & HTML_NLEND) + print_endline(h); + print_indent(h); + print_byte(h, '<'); + print_byte(h, '/'); + print_word(h, htmltags[tag->tag].name); + print_byte(h, '>'); + if (tflags & HTML_NLAFTER) + print_endline(h); + } + if (tag->refcnt == 0) { + h->tag = tag->next; + free(tag); + } +} + +void +print_gen_decls(struct html *h) +{ + print_word(h, ""); + print_endline(h); +} + +void +print_gen_comment(struct html *h, struct roff_node *n) +{ + int wantblank; + + print_word(h, "") == NULL && + (wantblank || *n->string != '\0')) { + print_endline(h); + print_indent(h); + print_word(h, n->string); + wantblank = *n->string != '\0'; + } + n = n->next; + } + if (wantblank) + print_endline(h); + print_word(h, " -->"); + print_endline(h); + h->indent = 0; +} + +void +print_text(struct html *h, const char *word) +{ + if (h->col && (h->flags & HTML_NOSPACE) == 0) { + if ( ! (HTML_KEEP & h->flags)) { + if (HTML_PREKEEP & h->flags) + h->flags |= HTML_KEEP; + print_endword(h); + } else + print_word(h, " "); + } + + assert(h->metaf == NULL); + print_metaf(h); + print_indent(h); + if ( ! print_encode(h, word, NULL, 0)) { + if ( ! (h->flags & HTML_NONOSPACE)) + h->flags &= ~HTML_NOSPACE; + h->flags &= ~HTML_NONEWLINE; + } else + h->flags |= HTML_NOSPACE | HTML_NONEWLINE; + + if (h->metaf != NULL) { + print_tagq(h, h->metaf); + h->metaf = NULL; + } + + h->flags &= ~HTML_IGNDELIM; +} + +void +print_tagq(struct html *h, const struct tag *until) +{ + struct tag *this, *next; + + for (this = h->tag; this != NULL; this = next) { + next = this == until ? NULL : this->next; + print_ctag(h, this); + } +} + +/* + * Close out all open elements up to but excluding suntil. + * Note that a paragraph just inside stays open together with it + * because paragraphs include subsequent phrasing content. + */ +void +print_stagq(struct html *h, const struct tag *suntil) +{ + struct tag *this, *next; + + for (this = h->tag; this != NULL; this = next) { + next = this->next; + if (this == suntil || (next == suntil && + (this->tag == TAG_P || this->tag == TAG_PRE))) + break; + print_ctag(h, this); + } +} + + +/*********************************************************************** + * Low level output functions. + * They implement line breaking using a short static buffer. + ***********************************************************************/ + +/* + * Buffer one HTML output byte. + * If the buffer is full, flush and deactivate it and start a new line. + * If the buffer is inactive, print directly. + */ +static void +print_byte(struct html *h, char c) +{ + if ((h->flags & HTML_BUFFER) == 0) { + putchar(c); + h->col++; + return; + } + + if (h->col + h->bufcol < sizeof(h->buf)) { + h->buf[h->bufcol++] = c; + return; + } + + putchar('\n'); + h->col = 0; + print_indent(h); + putchar(' '); + putchar(' '); + fwrite(h->buf, h->bufcol, 1, stdout); + putchar(c); + h->col = (h->indent + 1) * 2 + h->bufcol + 1; + h->bufcol = 0; + h->flags &= ~HTML_BUFFER; +} + +/* + * If something was printed on the current output line, end it. + * Not to be called right after print_indent(). + */ +void +print_endline(struct html *h) +{ + if (h->col == 0) + return; + + if (h->bufcol) { + putchar(' '); + fwrite(h->buf, h->bufcol, 1, stdout); + h->bufcol = 0; + } + putchar('\n'); + h->col = 0; + h->flags |= HTML_NOSPACE; + h->flags &= ~HTML_BUFFER; +} + +/* + * Flush the HTML output buffer. + * If it is inactive, activate it. + */ +static void +print_endword(struct html *h) +{ + if (h->noindent) { + print_byte(h, ' '); + return; + } + + if ((h->flags & HTML_BUFFER) == 0) { + h->col++; + h->flags |= HTML_BUFFER; + } else if (h->bufcol) { + putchar(' '); + fwrite(h->buf, h->bufcol, 1, stdout); + h->col += h->bufcol + 1; + } + h->bufcol = 0; +} + +/* + * If at the beginning of a new output line, + * perform indentation and mark the line as containing output. + * Make sure to really produce some output right afterwards, + * but do not use print_otag() for producing it. + */ +static void +print_indent(struct html *h) +{ + size_t i; + + if (h->col) + return; + + if (h->noindent == 0) { + h->col = h->indent * 2; + for (i = 0; i < h->col; i++) + putchar(' '); + } + h->flags &= ~HTML_NOSPACE; +} + +/* + * Print or buffer some characters + * depending on the current HTML output buffer state. + */ +static void +print_word(struct html *h, const char *cp) +{ + while (*cp != '\0') + print_byte(h, *cp++); +} Property changes on: vendor/mandoc/20190723/html.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/html.h =================================================================== --- vendor/mandoc/20190723/html.h (nonexistent) +++ vendor/mandoc/20190723/html.h (revision 350350) @@ -0,0 +1,134 @@ +/* $Id: html.h,v 1.103 2019/04/30 15:53:00 schwarze Exp $ */ +/* + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons + * Copyright (c) 2017, 2018, 2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +enum htmltag { + TAG_HTML, + TAG_HEAD, + TAG_BODY, + TAG_META, + TAG_TITLE, + TAG_DIV, + TAG_IDIV, + TAG_SECTION, + TAG_H1, + TAG_H2, + TAG_SPAN, + TAG_LINK, + TAG_BR, + TAG_A, + TAG_TABLE, + TAG_TR, + TAG_TD, + TAG_LI, + TAG_UL, + TAG_OL, + TAG_DL, + TAG_DT, + TAG_DD, + TAG_P, + 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 +}; + +struct tag { + struct tag *next; + int refcnt; + int closed; + 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_SKIPCHAR (1 << 6) /* skip the next character */ +#define HTML_NOSPLIT (1 << 7) /* do not break line before .An */ +#define HTML_SPLIT (1 << 8) /* break line before .An */ +#define HTML_NONEWLINE (1 << 9) /* No line break in nofill mode. */ +#define HTML_BUFFER (1 << 10) /* Collect a word to see if it fits. */ +#define HTML_TOCDONE (1 << 11) /* The TOC was already written. */ + size_t indent; /* current output indentation level */ + int noindent; /* indent disabled by
 */
+	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_man1; /* bases for manpage href */
+	char		 *base_man2;
+	char		 *base_includes; /* base for include href */
+	char		 *style; /* style-sheet URI */
+	struct tag	 *metaf; /* current open font scope */
+	enum mandoc_esc	  metal; /* last used font */
+	enum mandoc_esc	  metac; /* current font mode */
+	int		  oflags; /* output options */
+#define	HTML_FRAGMENT	 (1 << 0) /* don't emit HTML/HEAD/BODY */
+#define	HTML_TOC	 (1 << 1) /* emit a table of contents */
+};
+
+
+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_endline(struct html *);
+
+void		  html_close_paragraph(struct html *);
+enum roff_tok	  html_fillmode(struct html *, enum roff_tok);
+char		 *html_make_id(const struct roff_node *, int);
+int		  html_setfont(struct html *, enum mandoc_esc);

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

Property changes on: vendor/mandoc/20190723/lib.in
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/main.c
===================================================================
--- vendor/mandoc/20190723/main.c	(nonexistent)
+++ vendor/mandoc/20190723/main.c	(revision 350350)
@@ -0,0 +1,1251 @@
+/*	$Id: main.c,v 1.332 2019/07/19 20:27:25 schwarze Exp $ */
+/*
+ * Copyright (c) 2008-2012 Kristaps Dzonsons 
+ * Copyright (c) 2010-2012, 2014-2019 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 
+
+#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "mandoc_xr.h"
+#include "roff.h"
+#include "mdoc.h"
+#include "man.h"
+#include "mandoc_parse.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 mandoc_os	  os_e;		/* check base system conventions */
+	enum outt	  outtype;	/* which output to use */
+};
+
+
+int			  mandocdb(int, char *[]);
+
+static	void		  check_xr(void);
+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	void		  outdata_alloc(struct curparse *);
+static	void		  parse(struct curparse *, int, const char *);
+static	void		  passthrough(int, int);
+static	pid_t		  spawn_pager(struct tag_files *);
+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};
+
+
+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, *tagarg;
+	unsigned char	*uc;
+	size_t		 i, sz, ssz;
+	int		 prio, best_prio;
+	enum outmode	 outmode;
+	int		 fd, startdir;
+	int		 show_usage;
+	int		 options;
+	int		 use_pager;
+	int		 status, signum;
+	int		 c;
+	pid_t		 pager_pid, tc_pgid, man_pgid, pid;
+
+#if HAVE_PROGNAME
+	progname = getprogname();
+#else
+	if (argc < 1)
+		progname = mandoc_strdup("mandoc");
+	else if ((progname = strrchr(argv[0], '/')) == NULL)
+		progname = argv[0];
+	else
+		++progname;
+	setprogname(progname);
+#endif
+
+	mandoc_msg_setoutfile(stderr);
+	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) {
+		mandoc_msg(MANDOCERR_PLEDGE, 0, 0, "%s", strerror(errno));
+		return mandoc_msg_getrc();
+	}
+#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.outopts = &conf.output;
+	options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
+
+	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) != 0) {
+				mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0,
+				    "-I %s", optarg);
+				return mandoc_msg_getrc();
+			}
+			if (curp.os_s != NULL) {
+				mandoc_msg(MANDOCERR_BADARG_DUPE, 0, 0,
+				    "-I %s", optarg);
+				return mandoc_msg_getrc();
+			}
+			curp.os_s = mandoc_strdup(optarg + 3);
+			break;
+		case 'K':
+			options &= ~(MPARSE_UTF8 | MPARSE_LATIN1);
+			if (strcmp(optarg, "utf-8") == 0)
+				options |=  MPARSE_UTF8;
+			else if (strcmp(optarg, "iso-8859-1") == 0)
+				options |=  MPARSE_LATIN1;
+			else if (strcmp(optarg, "us-ascii") != 0) {
+				mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0,
+				    "-K %s", optarg);
+				return mandoc_msg_getrc();
+			}
+			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 (strcmp(optarg, "ascii") == 0)
+				curp.outtype = OUTT_ASCII;
+			else if (strcmp(optarg, "lint") == 0) {
+				curp.outtype = OUTT_LINT;
+				mandoc_msg_setoutfile(stdout);
+				mandoc_msg_setmin(MANDOCERR_BASE);
+			} else if (strcmp(optarg, "tree") == 0)
+				curp.outtype = OUTT_TREE;
+			else if (strcmp(optarg, "man") == 0)
+				curp.outtype = OUTT_MAN;
+			else if (strcmp(optarg, "html") == 0)
+				curp.outtype = OUTT_HTML;
+			else if (strcmp(optarg, "markdown") == 0)
+				curp.outtype = OUTT_MARKDOWN;
+			else if (strcmp(optarg, "utf8") == 0)
+				curp.outtype = OUTT_UTF8;
+			else if (strcmp(optarg, "locale") == 0)
+				curp.outtype = OUTT_LOCALE;
+			else if (strcmp(optarg, "ps") == 0)
+				curp.outtype = OUTT_PS;
+			else if (strcmp(optarg, "pdf") == 0)
+				curp.outtype = OUTT_PDF;
+			else {
+				mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0,
+				    "-T %s", optarg);
+				return mandoc_msg_getrc();
+			}
+			break;
+		case 'W':
+			if (woptions(&curp, optarg) == -1)
+				return mandoc_msg_getrc();
+			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) {
+				if (manconf_output(&conf.output,
+				    strsep(&oarg, ","), 0) == -1)
+					return mandoc_msg_getrc();
+			}
+		}
+	}
+
+	if (curp.outtype != OUTT_TREE || !curp.outopts->noval)
+		options |= MPARSE_VALIDATE;
+
+	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 == 0) {
+		if (pledge("stdio rpath", NULL) == -1) {
+			mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
+			    "%s", strerror(errno));
+			return mandoc_msg_getrc();
+		}
+	}
+#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[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
+	}
+
+	/*
+	 * Use the first argument for -O tag in addition to
+	 * using it as a search term for man(1) or apropos(1).
+	 */
+
+	if (conf.output.tag != NULL && *conf.output.tag == '\0') {
+		tagarg = argc > 0 && search.argmode == ARG_EXPR ?
+		    strchr(*argv, '=') : NULL;
+		conf.output.tag = tagarg == NULL ? *argv : tagarg + 1;
+	}
+
+	/* man(1), whatis(1), apropos(1) */
+
+	if (search.argmode != ARG_FILE) {
+		if (search.argmode == ARG_NAME &&
+		    outmode == OUTMODE_ONE)
+			search.firstmatch = 1;
+
+		/* Access the mandoc database. */
+
+		manconf_parse(&conf, conf_file, defpaths, auxpaths);
+		if ( ! mansearch(&search, &conf.manpath,
+		    argc, argv, &res, &sz))
+			usage(search.argmode);
+
+		if (sz == 0 && search.argmode == ARG_NAME)
+			(void)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) {
+					mandoc_msg_setinfilename(argv[c]);
+					mandoc_msg(MANDOCERR_BADARG_BAD,
+					    0, 0, "%s", strerror(errno));
+					mandoc_msg_setinfilename(NULL);
+					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].bits = 0;
+				res[sz].ipath = SIZE_MAX;
+				res[sz].sec = 10;
+				res[sz].form = FORM_SRC;
+				sz++;
+			}
+		}
+
+		if (sz == 0) {
+			if (search.argmode != ARG_NAME)
+				warnx("nothing appropriate");
+			mandoc_msg_setrc(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 = 40;
+		} 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; /* No section at all. */
+				prio = sec_prios[sec[0] - '1'];
+				if (search.sec != NULL) {
+					ssz = strlen(search.sec);
+					if (strncmp(sec, search.sec, ssz) == 0)
+						sec += ssz;
+				} else
+					sec++; /* Prefer without suffix. */
+				if (*sec != '/')
+					prio += 10; /* Wrong dir name. */
+				if (search.sec != NULL &&
+				    (strlen(sec) <= ssz  + 3 ||
+				     strcmp(sec + strlen(sec) - ssz,
+				      search.sec) != 0))
+					prio += 20; /* Wrong file ext. */
+				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) {
+			mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
+			    "%s", strerror(errno));
+			return mandoc_msg_getrc();
+		}
+	} else {
+		if (pledge("stdio rpath", NULL) == -1) {
+			mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
+			    "%s", strerror(errno));
+			return mandoc_msg_getrc();
+		}
+	}
+#endif
+
+	if (search.argmode == ARG_FILE && auxpaths != NULL) {
+		if (strcmp(auxpaths, "doc") == 0)
+			options |= MPARSE_MDOC;
+		else if (strcmp(auxpaths, "an") == 0)
+			options |= MPARSE_MAN;
+	}
+
+	mchars_alloc();
+	curp.mp = mparse_alloc(options, curp.os_e, curp.os_s);
+
+	if (argc < 1) {
+		if (use_pager) {
+			tag_files = tag_init();
+			if (tag_files != NULL)
+				tag_files->tagname = conf.output.tag;
+		}
+		thisarg = "";
+		mandoc_msg_setinfilename(thisarg);
+		parse(&curp, STDIN_FILENO, thisarg);
+		mandoc_msg_setinfilename(NULL);
+	}
+
+	/*
+	 * 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);
+			thisarg = resp->file;
+		} else
+			thisarg = *argv;
+
+		mandoc_msg_setinfilename(thisarg);
+		fd = mparse_open(curp.mp, thisarg);
+		if (fd != -1) {
+			if (use_pager) {
+				use_pager = 0;
+				tag_files = tag_init();
+				if (tag_files != NULL)
+					tag_files->tagname = conf.output.tag;
+			}
+
+			if (resp == NULL || resp->form == FORM_SRC)
+				parse(&curp, fd, thisarg);
+			else
+				passthrough(fd, conf.output.synopsisonly);
+
+			if (ferror(stdout)) {
+				if (tag_files != NULL) {
+					mandoc_msg(MANDOCERR_WRITE, 0, 0,
+					    "%s: %s", tag_files->ofn,
+					    strerror(errno));
+					tag_unlink();
+					tag_files = NULL;
+				} else
+					mandoc_msg(MANDOCERR_WRITE, 0, 0,
+					    "%s", strerror(errno));
+				break;
+			}
+
+			if (argc > 1 && curp.outtype <= OUTT_UTF8) {
+				if (curp.outdata == NULL)
+					outdata_alloc(&curp);
+				terminal_sepline(curp.outdata);
+			}
+		} else
+			mandoc_msg(resp == NULL ? MANDOCERR_BADARG_BAD :
+			    MANDOCERR_OPEN, 0, 0, "%s", strerror(errno));
+
+		mandoc_msg_setinfilename(NULL);
+
+		if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
+			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) {
+				mandoc_msg(MANDOCERR_WAIT, 0, 0,
+				    "%s", strerror(errno));
+				break;
+			}
+			if (!WIFSTOPPED(status))
+				break;
+
+			signum = WSTOPSIG(status);
+		}
+		tag_unlink();
+	} else if (curp.outtype != OUTT_LINT &&
+	    (search.argmode == ARG_FILE || sz > 0))
+		mandoc_msg_summary();
+
+	return (int)mandoc_msg_getrc();
+}
+
+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)
+{
+	struct stat	 sb;
+	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 (stat(file, &sb) != -1)
+		goto found;
+	free(file);
+
+	mandoc_asprintf(&file, "%s/cat%s/%s.0",
+	    paths->paths[ipath], sec, name);
+	if (stat(file, &sb) != -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 (stat(file, &sb) != -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)
+		mandoc_msg(MANDOCERR_GLOB, 0, 0,
+		    "%s: %s", file, strerror(errno));
+	free(file);
+	if (globres == 0)
+		file = mandoc_strdup(*globinfo.gl_pathv);
+	globfree(&globinfo);
+	if (globres == 0) {
+		if (stat(file, &sb) != -1)
+			goto found;
+		free(file);
+	}
+	if (res != NULL || ipath + 1 != paths->sz)
+		return -1;
+
+	mandoc_asprintf(&file, "%s.%s", name, sec);
+	globres = stat(file, &sb);
+	free(file);
+	return globres;
+
+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 0;
+	}
+	*res = mandoc_reallocarray(*res, ++*ressz, sizeof(**res));
+	page = *res + (*ressz - 1);
+	page->file = file;
+	page->names = NULL;
+	page->output = NULL;
+	page->bits = NAME_FILE & NAME_MASK;
+	page->ipath = ipath;
+	page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
+	page->form = form;
+	return 0;
+}
+
+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) != -1 &&
+				    cfg->firstmatch)
+					return 0;
+			} else for (isec = 0; isec < nsec; isec++)
+				if (fs_lookup(paths, ipath, sections[isec],
+				    cfg->arch, *argv, res, ressz) != -1 &&
+				    cfg->firstmatch)
+					return 0;
+		}
+		if (res != NULL && *ressz == lastsz &&
+		    strchr(*argv, '/') == NULL) {
+			if (cfg->arch != NULL &&
+			    arch_valid(cfg->arch, OSENUM) == 0)
+				warnx("Unknown architecture \"%s\".",
+				    cfg->arch);
+			else if (cfg->sec == NULL)
+				warnx("No entry for %s in the manual.",
+				    *argv);
+			else
+				warnx("No entry for %s in section %s "
+				    "of the manual.", *argv, cfg->sec);
+		}
+		lastsz = *ressz;
+		argv++;
+		argc--;
+	}
+	return -1;
+}
+
+static void
+parse(struct curparse *curp, int fd, const char *file)
+{
+	struct roff_meta *meta;
+
+	/* Begin by parsing the file itself. */
+
+	assert(file);
+	assert(fd >= 0);
+
+	mparse_readfd(curp->mp, fd, file);
+	if (fd != STDIN_FILENO)
+		close(fd);
+
+	/*
+	 * With -Wstop and warnings or errors of at least the requested
+	 * level, do not produce output.
+	 */
+
+	if (curp->wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
+		return;
+
+	if (curp->outdata == NULL)
+		outdata_alloc(curp);
+	else if (curp->outtype == OUTT_HTML)
+		html_reset(curp);
+
+	mandoc_xr_reset();
+	meta = mparse_result(curp->mp);
+
+	/* Execute the out device, if it exists. */
+
+	if (meta->macroset == MACROSET_MDOC) {
+		switch (curp->outtype) {
+		case OUTT_HTML:
+			html_mdoc(curp->outdata, meta);
+			break;
+		case OUTT_TREE:
+			tree_mdoc(curp->outdata, meta);
+			break;
+		case OUTT_MAN:
+			man_mdoc(curp->outdata, meta);
+			break;
+		case OUTT_PDF:
+		case OUTT_ASCII:
+		case OUTT_UTF8:
+		case OUTT_LOCALE:
+		case OUTT_PS:
+			terminal_mdoc(curp->outdata, meta);
+			break;
+		case OUTT_MARKDOWN:
+			markdown_mdoc(curp->outdata, meta);
+			break;
+		default:
+			break;
+		}
+	}
+	if (meta->macroset == MACROSET_MAN) {
+		switch (curp->outtype) {
+		case OUTT_HTML:
+			html_man(curp->outdata, meta);
+			break;
+		case OUTT_TREE:
+			tree_man(curp->outdata, meta);
+			break;
+		case OUTT_MAN:
+			mparse_copy(curp->mp);
+			break;
+		case OUTT_PDF:
+		case OUTT_ASCII:
+		case OUTT_UTF8:
+		case OUTT_LOCALE:
+		case OUTT_PS:
+			terminal_man(curp->outdata, meta);
+			break;
+		default:
+			break;
+		}
+	}
+	if (mandoc_msg_getmin() < MANDOCERR_STYLE)
+		check_xr();
+}
+
+static void
+check_xr(void)
+{
+	static struct manpaths	 paths;
+	struct mansearch	 search;
+	struct mandoc_xr	*xr;
+	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) != -1)
+			continue;
+		if (xr->count == 1)
+			mandoc_msg(MANDOCERR_XR_BAD, xr->line,
+			    xr->pos + 1, "Xr %s %s", xr->name, xr->sec);
+		else
+			mandoc_msg(MANDOCERR_XR_BAD, xr->line,
+			    xr->pos + 1, "Xr %s %s (%d times)",
+			    xr->name, xr->sec, xr->count);
+	}
+}
+
+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(int fd, int synopsis_only)
+{
+	const char	 synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS";
+	const char	 synr[] = "SYNOPSIS";
+
+	FILE		*stream;
+	char		*line, *cp;
+	size_t		 linesz;
+	ssize_t		 len, written;
+	int		 lno, print;
+
+	stream = NULL;
+	line = NULL;
+	linesz = 0;
+
+	if (fflush(stdout) == EOF) {
+		mandoc_msg(MANDOCERR_FFLUSH, 0, 0, "%s", strerror(errno));
+		goto done;
+	}
+	if ((stream = fdopen(fd, "r")) == NULL) {
+		close(fd);
+		mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno));
+		goto done;
+	}
+
+	lno = print = 0;
+	while ((len = getline(&line, &linesz, stream)) != -1) {
+		lno++;
+		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) {
+				mandoc_msg(MANDOCERR_WRITE, 0, 0,
+				    "%s", strerror(errno));
+				goto done;
+			}
+		}
+	}
+	if (ferror(stream))
+		mandoc_msg(MANDOCERR_GETLINE, lno, 0, "%s", strerror(errno));
+
+done:
+	free(line);
+	if (stream != NULL)
+		fclose(stream);
+}
+
+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:
+			mandoc_msg_setmin(MANDOCERR_BASE);
+			break;
+		case 3:
+			mandoc_msg_setmin(MANDOCERR_STYLE);
+			break;
+		case 4:
+			mandoc_msg_setmin(MANDOCERR_WARNING);
+			break;
+		case 5:
+			mandoc_msg_setmin(MANDOCERR_ERROR);
+			break;
+		case 6:
+			mandoc_msg_setmin(MANDOCERR_UNSUPP);
+			break;
+		case 7:
+			mandoc_msg_setmin(MANDOCERR_BADARG);
+			break;
+		case 8:
+			mandoc_msg_setmin(MANDOCERR_BASE);
+			curp->os_e = MANDOC_OS_OPENBSD;
+			break;
+		case 9:
+			mandoc_msg_setmin(MANDOCERR_BASE);
+			curp->os_e = MANDOC_OS_NETBSD;
+			break;
+		default:
+			mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-W %s", o);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+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;
+#if HAVE_LESS_T
+	size_t		 cmdlen;
+#endif
+	int		 argc, use_ofn;
+	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 + 5 < 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. */
+
+	use_ofn = 1;
+#if HAVE_LESS_T
+	if (*tag_files->tfn != '\0' && (cmdlen = strlen(argv[0])) >= 4) {
+		cp = argv[0] + cmdlen - 4;
+		if (strcmp(cp, "less") == 0) {
+			argv[argc++] = mandoc_strdup("-T");
+			argv[argc++] = tag_files->tfn;
+			if (tag_files->tagname != NULL) {
+				argv[argc++] = mandoc_strdup("-t");
+				argv[argc++] = tag_files->tagname;
+				use_ofn = 0;
+			}
+		}
+	}
+#endif
+	if (use_ofn)
+		argv[argc++] = tag_files->ofn;
+	argv[argc] = NULL;
+
+	switch (pager_pid = fork()) {
+	case -1:
+		mandoc_msg(MANDOCERR_FORK, 0, 0, "%s", strerror(errno));
+		exit(mandoc_msg_getrc());
+	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) {
+			mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
+			    "%s", strerror(errno));
+			exit(mandoc_msg_getrc());
+		}
+#endif
+		tag_files->pager_pid = pager_pid;
+		return pager_pid;
+	}
+
+	/* The child process becomes the pager. */
+
+	if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) {
+		mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
+		_exit(mandoc_msg_getrc());
+	}
+	close(tag_files->ofd);
+	assert(tag_files->tfd == -1);
+
+	/* Do not start the pager before controlling the terminal. */
+
+	while (tcgetpgrp(STDOUT_FILENO) != getpid())
+		nanosleep(&timeout, NULL);
+
+	execvp(argv[0], argv);
+	mandoc_msg(MANDOCERR_EXEC, 0, 0, "%s: %s", argv[0], strerror(errno));
+	_exit(mandoc_msg_getrc());
+}

Property changes on: vendor/mandoc/20190723/main.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/man.7
===================================================================
--- vendor/mandoc/20190723/man.7	(nonexistent)
+++ vendor/mandoc/20190723/man.7	(revision 350350)
@@ -0,0 +1,616 @@
+.\"	$Id: man.7,v 1.144 2019/07/09 03:46:59 schwarze Exp $
+.\"
+.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons 
+.\" Copyright (c) 2011-2015,2017,2018,2019 Ingo Schwarze 
+.\" Copyright (c) 2017 Anthony Bentley 
+.\" 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: July 9 2019 $
+.Dt MAN 7
+.Os
+.Sh NAME
+.Nm man
+.Nd legacy formatting language for manual pages
+.Sh DESCRIPTION
+The
+.Nm man
+language was the standard formatting language for
+.At
+manual pages from 1979 to 1989.
+Do not use it to write new manual pages: it is a purely presentational
+language and 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 portable 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.
+.Pp
+Each
+.Nm
+document starts with the
+.Ic TH
+macro specifying the document's name and section, followed by the
+.Sx NAME
+section formatted as follows:
+.Bd -literal -offset indent
+\&.TH PROGNAME 1 1979-01-10
+\&.SH NAME
+\efBprogname\efR \e(en one line about what it does
+.Ed
+.Sh MACRO OVERVIEW
+This overview is sorted such that macros of similar purpose are listed
+together.
+Deprecated and non-portable 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 "RS, RE" description
+.It Ic TH Ta set the title: Ar name section date Op Ar source Op Ar volume
+.It Ic AT Ta display AT&T UNIX version in the page footer (<= 1 argument)
+.It Ic UC Ta display BSD version in the page footer (<= 1 argument)
+.El
+.Ss Sections and paragraphs
+.Bl -column "RS, RE" description
+.It Ic SH Ta section header (one line)
+.It Ic SS Ta subsection header (one line)
+.It Ic PP Ta start an undecorated paragraph (no arguments)
+.It Ic RS , RE Ta reset the left margin: Op Ar width
+.It Ic IP Ta indented paragraph: Op Ar head Op Ar width
+.It Ic TP Ta tagged paragraph: Op Ar width
+.It Ic PD Ta set vertical paragraph distance: Op Ar height
+.It Ic in Ta additional indent: Op Ar width
+.El
+.Ss Physical markup
+.Bl -column "RS, RE" description
+.It Ic B Ta boldface font
+.It Ic I Ta italic font
+.It Ic SB Ta small boldface font
+.It Ic SM Ta small roman font
+.It Ic BI Ta alternate between boldface and italic fonts
+.It Ic BR Ta alternate between boldface and roman fonts
+.It Ic IB Ta alternate between italic and boldface fonts
+.It Ic IR Ta alternate between italic and roman fonts
+.It Ic RB Ta alternate between roman and boldface fonts
+.It Ic 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 .
+.Bl -tag -width 3n
+.It Ic AT
+Sets the volume for the footer for compatibility with man pages from
+.At
+releases.
+The optional arguments specify which release it is from.
+.It Ic B
+Text is rendered in bold face.
+.It Ic 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
+Example:
+.Pp
+.Dl \&.BI bold italic bold italic
+.It Ic BR
+Text is rendered alternately in bold face and roman (the default font).
+Whitespace between arguments is omitted in output.
+See also
+.Ic BI .
+.It Ic 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.
+.It Ic EE
+This is a non-standard Version 9
+.At
+extension later adopted by GNU.
+In
+.Xr mandoc 1 ,
+it does the same as the
+.Xr roff 7
+.Ic fi
+request (switch to fill mode).
+.It Ic EX
+This is a non-standard Version 9
+.At
+extension later adopted by GNU.
+In
+.Xr mandoc 1 ,
+it does the same as the
+.Xr roff 7
+.Ic nf
+request (switch to no-fill mode).
+.It Ic HP
+Begin a paragraph whose initial output line is left-justified, but
+subsequent output lines are indented, with the following syntax:
+.Pp
+.D1 Pf . Ic HP Op Ar width
+.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
+This macro is portable, but deprecated
+because it has no good representation in HTML output,
+usually ending up indistinguishable from
+.Ic PP .
+.It Ic I
+Text is rendered in italics.
+.It Ic IB
+Text is rendered alternately in italics and bold face.
+Whitespace between arguments is omitted in output.
+See also
+.Ic BI .
+.It Ic IP
+Begin an indented paragraph with the following syntax:
+.Pp
+.D1 Pf . Ic IP Op Ar head Op Ar width
+.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.
+.It Ic IR
+Text is rendered alternately in italics and roman (the default font).
+Whitespace between arguments is omitted in output.
+See also
+.Ic BI .
+.It Ic LP
+A synonym for
+.Ic PP .
+.It Ic ME
+End a mailto block started with
+.Ic MT .
+This is a non-standard GNU extension.
+.It Ic MT
+Begin a mailto block.
+This is a non-standard GNU extension.
+It has the following syntax:
+.Bd -unfilled -offset indent
+.Pf . Ic MT Ar address
+link description to be shown
+.Pf . Ic ME
+.Ed
+.It Ic OP
+Optional command-line argument.
+This is a non-standard GNU extension.
+It has the following syntax:
+.Pp
+.D1 Pf . Ic OP Ar key Op Ar value
+.Pp
+The
+.Ar key
+is usually a command-line flag and
+.Ar value
+its argument.
+.It Ic P
+A synonym for
+.Ic PP .
+.It Ic PD
+Specify the vertical space to be inserted before each new paragraph.
+.br
+The syntax is as follows:
+.Pp
+.D1 Pf . Ic PD Op Ar height
+.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
+.Ic HP ,
+.Ic IP ,
+.Ic LP ,
+.Ic P ,
+.Ic PP ,
+.Ic SH ,
+.Ic SS ,
+.Ic SY ,
+and
+.Ic TP .
+.It Ic PP
+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.
+.It Ic RB
+Text is rendered alternately in roman (the default font) and bold face.
+Whitespace between arguments is omitted in output.
+See also
+.Ic BI .
+.It Ic RE
+Explicitly close out the scope of a prior
+.Ic RS .
+The default left margin is restored to the state before that
+.Ic RS
+invocation.
+.Pp
+The syntax is as follows:
+.Pp
+.D1 Pf . Ic RE Op Ar level
+.Pp
+Without an argument, the most recent
+.Ic RS
+block is closed out.
+If
+.Ar level
+is 1, all open
+.Ic RS
+blocks are closed out.
+Otherwise,
+.Ar level No \(mi 1
+nested
+.Ic RS
+blocks remain open.
+.It Ic RI
+Text is rendered alternately in roman (the default font) and italics.
+Whitespace between arguments is omitted in output.
+See also
+.Ic BI .
+.It Ic RS
+Temporarily reset the default left margin.
+This has the following syntax:
+.Pp
+.D1 Pf . Ic RS Op Ar width
+.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
+.Ic RE .
+.It Ic SB
+Text is rendered in small size (one point smaller than the default font)
+bold face.
+.It Ic 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.
+.It Ic SM
+Text is rendered in small size (one point smaller than the default
+font).
+.It Ic 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.
+.It Ic SY
+Begin a synopsis block with the following syntax:
+.Bd -unfilled -offset indent
+.Pf . Ic SY Ar command
+.Ar arguments
+.Pf . Ic YS
+.Ed
+.Pp
+This is a non-standard GNU extension
+and very rarely used even in GNU manual pages.
+Formatting is similar to
+.Ic IP .
+.It Ic TH
+Set the name of the manual page for use in the page header
+and footer with the following syntax:
+.Pp
+.D1 Pf . Ic TH Ar name section date Op Ar source Op Ar volume
+.Pp
+Conventionally, the document
+.Ar name
+is given in all caps.
+The
+.Ar section
+is usually a single digit, in a few cases followed by a letter.
+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 volume title of the
+.Ar section .
+.Pp
+Examples:
+.Pp
+.Dl \&.TH CVS 5 "1992-02-12" GNU
+.It Ic 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
+advancing to the indentation width.
+Subsequent output lines are indented.
+The syntax is as follows:
+.Bd -unfilled -offset indent
+.Pf . Ic TP Op Ar width
+.Ar head No \e" one line
+.Ar body
+.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.
+.It Ic TQ
+Like
+.Ic TP ,
+except that no vertical spacing is inserted before the paragraph.
+This is a non-standard GNU extension
+and very rarely used even in GNU manual pages.
+.It Ic 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.
+.It Ic UE
+End a uniform resource identifier block started with
+.Ic UR .
+This is a non-standard GNU extension.
+.It Ic UR
+Begin a uniform resource identifier block.
+This is a non-standard GNU extension.
+It has the following syntax:
+.Bd -unfilled -offset indent
+.Pf . Ic UR Ar uri
+link description to be shown
+.Pf . Ic UE
+.Ed
+.It Ic YS
+End a synopsis block started with
+.Ic SY .
+This is a non-standard GNU extension.
+.It Ic in
+Indent relative to the current indentation:
+.Pp
+.D1 Pf . Ic 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.
+.El
+.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 Ic AT  Ta    <=1       Ta    current   Ta    \&
+.It Ic B   Ta    n         Ta    next-line Ta    \&
+.It Ic BI  Ta    n         Ta    current   Ta    \&
+.It Ic BR  Ta    n         Ta    current   Ta    \&
+.It Ic DT  Ta    0         Ta    current   Ta    \&
+.It Ic EE  Ta    0         Ta    current   Ta    Version 9 At
+.It Ic EX  Ta    0         Ta    current   Ta    Version 9 At
+.It Ic I   Ta    n         Ta    next-line Ta    \&
+.It Ic IB  Ta    n         Ta    current   Ta    \&
+.It Ic IR  Ta    n         Ta    current   Ta    \&
+.It Ic OP  Ta    >=1       Ta    current   Ta    GNU
+.It Ic PD  Ta    1         Ta    current   Ta    \&
+.It Ic RB  Ta    n         Ta    current   Ta    \&
+.It Ic RI  Ta    n         Ta    current   Ta    \&
+.It Ic SB  Ta    n         Ta    next-line Ta    \&
+.It Ic SM  Ta    n         Ta    next-line Ta    \&
+.It Ic TH  Ta    >1, <6    Ta    current   Ta    \&
+.It Ic UC  Ta    <=1       Ta    current   Ta    \&
+.It Ic in  Ta    1         Ta    current   Ta    Xr roff 7
+.El
+.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
+.Ic SH ;
+sub-section, closed by a section or
+.Ic SS ;
+or paragraph, closed by a section, sub-section,
+.Ic HP ,
+.Ic IP ,
+.Ic LP ,
+.Ic P ,
+.Ic PP ,
+.Ic RE ,
+.Ic SY ,
+or
+.Ic 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 Ic HP  Ta    <2        Ta    current    Ta    paragraph   Ta    \&
+.It Ic IP  Ta    <3        Ta    current    Ta    paragraph   Ta    \&
+.It Ic LP  Ta    0         Ta    current    Ta    paragraph   Ta    \&
+.It Ic ME  Ta    0         Ta    none       Ta    none        Ta    GNU
+.It Ic MT  Ta    1         Ta    current    Ta    to \&ME     Ta    GNU
+.It Ic P   Ta    0         Ta    current    Ta    paragraph   Ta    \&
+.It Ic PP  Ta    0         Ta    current    Ta    paragraph   Ta    \&
+.It Ic RE  Ta    <=1       Ta    current    Ta    none        Ta    \&
+.It Ic RS  Ta    1         Ta    current    Ta    to \&RE     Ta    \&
+.It Ic SH  Ta    >0        Ta    next-line  Ta    section     Ta    \&
+.It Ic SS  Ta    >0        Ta    next-line  Ta    sub-section Ta    \&
+.It Ic SY  Ta    1         Ta    current    Ta    to \&YS     Ta    GNU
+.It Ic TP  Ta    n         Ta    next-line  Ta    paragraph   Ta    \&
+.It Ic TQ  Ta    n         Ta    next-line  Ta    paragraph   Ta    GNU
+.It Ic UE  Ta    0         Ta    current    Ta    none        Ta    GNU
+.It Ic UR  Ta    1         Ta    current    Ta    part        Ta    GNU
+.It Ic YS  Ta    0         Ta    none       Ta    none        Ta    GNU
+.El
+.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
+.Ic 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 .

Property changes on: vendor/mandoc/20190723/man.7
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/man_html.c
===================================================================
--- vendor/mandoc/20190723/man_html.c	(nonexistent)
+++ vendor/mandoc/20190723/man_html.c	(revision 350350)
@@ -0,0 +1,643 @@
+/*	$Id: man_html.c,v 1.174 2019/04/30 15:53:00 schwarze Exp $ */
+/*
+ * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons 
+ * Copyright (c) 2013-2015, 2017-2019 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"
+
+#define	MAN_ARGS	  const struct roff_meta *man, \
+			  const struct roff_node *n, \
+			  struct html *h
+
+struct	man_html_act {
+	int		(*pre)(MAN_ARGS);
+	int		(*post)(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	char		  list_continues(const struct roff_node *,
+				const struct roff_node *);
+static	int		  man_B_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_SY_pre(MAN_ARGS);
+static	int		  man_UR_pre(MAN_ARGS);
+static	int		  man_abort_pre(MAN_ARGS);
+static	int		  man_alt_pre(MAN_ARGS);
+static	int		  man_ign_pre(MAN_ARGS);
+static	int		  man_in_pre(MAN_ARGS);
+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 man_html_act man_html_acts[MAN_MAX - MAN_TH] = {
+	{ NULL, NULL }, /* TH */
+	{ man_SH_pre, NULL }, /* SH */
+	{ man_SH_pre, NULL }, /* SS */
+	{ man_IP_pre, NULL }, /* TP */
+	{ man_IP_pre, NULL }, /* TQ */
+	{ man_abort_pre, NULL }, /* LP */
+	{ man_PP_pre, NULL }, /* PP */
+	{ man_abort_pre, NULL }, /* P */
+	{ man_IP_pre, NULL }, /* IP */
+	{ man_PP_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 }, /* 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_SY_pre, NULL }, /* SY */
+	{ NULL, NULL }, /* YS */
+	{ 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 */
+};
+
+
+void
+html_man(void *arg, const struct roff_meta *man)
+{
+	struct html		*h;
+	struct roff_node	*n;
+	struct tag		*t;
+
+	h = (struct html *)arg;
+	n = man->first->child;
+
+	if ((h->oflags & HTML_FRAGMENT) == 0) {
+		print_gen_decls(h);
+		print_otag(h, TAG_HTML, "");
+		if (n != NULL && n->type == ROFFT_COMMENT)
+			print_gen_comment(h, n);
+		t = print_otag(h, TAG_HEAD, "");
+		print_man_head(man, h);
+		print_tagq(h, t);
+		print_otag(h, TAG_BODY, "");
+	}
+
+	man_root_pre(man, h);
+	t = print_otag(h, TAG_DIV, "c", "manual-text");
+	print_man_nodelist(man, n, h);
+	print_tagq(h, t);
+	man_root_post(man, h);
+	print_tagq(h, NULL);
+}
+
+static void
+print_man_head(const struct roff_meta *man, struct html *h)
+{
+	char	*cp;
+
+	print_gen_head(h);
+	mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec);
+	print_otag(h, TAG_TITLE, "");
+	print_text(h, cp);
+	free(cp);
+}
+
+static void
+print_man_nodelist(MAN_ARGS)
+{
+	while (n != NULL) {
+		print_man_node(man, n, h);
+		n = n->next;
+	}
+}
+
+static void
+print_man_node(MAN_ARGS)
+{
+	struct tag	*t;
+	int		 child;
+
+	if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
+		return;
+
+	html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
+
+	child = 1;
+	switch (n->type) {
+	case ROFFT_TEXT:
+		if (*n->string == '\0') {
+			print_endline(h);
+			return;
+		}
+		if (*n->string == ' ' && n->flags & NODE_LINE &&
+		    (h->flags & HTML_NONEWLINE) == 0)
+			print_endline(h);
+		else if (n->flags & NODE_DELIMC)
+			h->flags |= HTML_NOSPACE;
+		t = h->tag;
+		t->refcnt++;
+		print_text(h, n->string);
+		break;
+	case ROFFT_EQN:
+		t = h->tag;
+		t->refcnt++;
+		print_eqn(h, n->eqn);
+		break;
+	case ROFFT_TBL:
+		/*
+		 * 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 (h->metac != ESCAPE_FONTROMAN) {
+			h->metal = h->metac;
+			h->metac = ESCAPE_FONTROMAN;
+		}
+
+		/*
+		 * Close out the current table, if it's open, and unset
+		 * the "meta" table state.  This will be reopened on the
+		 * next table element.
+		 */
+		if (h->tblt != NULL)
+			print_tblclose(h);
+		t = h->tag;
+		t->refcnt++;
+		if (n->tok < ROFF_MAX) {
+			roff_html_pre(h, n);
+			t->refcnt--;
+			print_stagq(h, t);
+			return;
+		}
+		assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
+		if (man_html_acts[n->tok - MAN_TH].pre != NULL)
+			child = (*man_html_acts[n->tok - MAN_TH].pre)(man,
+			    n, h);
+		break;
+	}
+
+	if (child && n->child != NULL)
+		print_man_nodelist(man, n->child, h);
+
+	/* This will automatically close out any font scope. */
+	t->refcnt--;
+	if (n->type == ROFFT_BLOCK &&
+	    (n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) {
+		t = h->tag;
+		while (t->tag != TAG_DL && t->tag != TAG_UL)
+			t = t->next;
+		/*
+		 * Close the list if no further item of the same type
+		 * follows; otherwise, close the item only.
+		 */
+		if (list_continues(n, n->next) == '\0') {
+			print_tagq(h, t);
+			t = NULL;
+		}
+	}
+	if (t != NULL)
+		print_stagq(h, t);
+
+	if (n->flags & NODE_NOFILL && n->tok != MAN_YS &&
+	    (n->next != NULL && n->next->flags & NODE_LINE)) {
+		/* In .nf = 
, print even empty lines. */
+		h->col++;
+		print_endline(h);
+	}
+}
+
+static void
+man_root_pre(const struct roff_meta *man, struct html *h)
+{
+	struct tag	*t, *tt;
+	char		*title;
+
+	assert(man->title);
+	assert(man->msec);
+	mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
+
+	t = print_otag(h, TAG_TABLE, "c", "head");
+	tt = print_otag(h, TAG_TR, "");
+
+	print_otag(h, TAG_TD, "c", "head-ltitle");
+	print_text(h, title);
+	print_stagq(h, tt);
+
+	print_otag(h, TAG_TD, "c", "head-vol");
+	if (man->vol != NULL)
+		print_text(h, man->vol);
+	print_stagq(h, tt);
+
+	print_otag(h, TAG_TD, "c", "head-rtitle");
+	print_text(h, title);
+	print_tagq(h, t);
+	free(title);
+}
+
+static void
+man_root_post(const struct roff_meta *man, struct html *h)
+{
+	struct tag	*t, *tt;
+
+	t = print_otag(h, TAG_TABLE, "c", "foot");
+	tt = print_otag(h, TAG_TR, "");
+
+	print_otag(h, TAG_TD, "c", "foot-date");
+	print_text(h, man->date);
+	print_stagq(h, tt);
+
+	print_otag(h, TAG_TD, "c", "foot-os");
+	if (man->os != NULL)
+		print_text(h, man->os);
+	print_tagq(h, t);
+}
+
+static int
+man_SH_pre(MAN_ARGS)
+{
+	const char	*class;
+	char		*id;
+	enum htmltag	 tag;
+
+	if (n->tok == MAN_SH) {
+		tag = TAG_H1;
+		class = "Sh";
+	} else {
+		tag = TAG_H2;
+		class = "Ss";
+	}
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		print_otag(h, TAG_SECTION, "c", class);
+		break;
+	case ROFFT_HEAD:
+		id = html_make_id(n, 1);
+		print_otag(h, tag, "ci", class, id);
+		if (id != NULL)
+			print_otag(h, TAG_A, "chR", "permalink", id);
+		break;
+	case ROFFT_BODY:
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+static int
+man_alt_pre(MAN_ARGS)
+{
+	const struct roff_node	*nn;
+	struct tag	*t;
+	int		 i;
+	enum htmltag	 fp;
+
+	for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) {
+		switch (n->tok) {
+		case MAN_BI:
+			fp = i % 2 ? TAG_I : TAG_B;
+			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 (n->tok == MAN_SB)
+		print_otag(h, TAG_B, "");
+	return 1;
+}
+
+static int
+man_PP_pre(MAN_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		break;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		if (n->child != NULL &&
+		    (n->child->flags & NODE_NOFILL) == 0)
+			print_otag(h, TAG_P, "c",
+			    n->tok == MAN_PP ? "Pp" : "Pp HP");
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+static char
+list_continues(const struct roff_node *n1, const struct roff_node *n2)
+{
+	const char *s1, *s2;
+	char c1, c2;
+
+	if (n1 == NULL || n1->type != ROFFT_BLOCK ||
+	    n2 == NULL || n2->type != ROFFT_BLOCK)
+		return '\0';
+	if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) &&
+	    (n2->tok == MAN_TP || n2->tok == MAN_TQ))
+		return ' ';
+	if (n1->tok != MAN_IP || n2->tok != MAN_IP)
+		return '\0';
+	n1 = n1->head->child;
+	n2 = n2->head->child;
+	s1 = n1 == NULL ? "" : n1->string;
+	s2 = n2 == NULL ? "" : n2->string;
+	c1 = strcmp(s1, "*") == 0 ? '*' :
+	     strcmp(s1, "\\-") == 0 ? '-' :
+	     strcmp(s1, "\\(bu") == 0 ? 'b' : ' ';
+	c2 = strcmp(s2, "*") == 0 ? '*' :
+	     strcmp(s2, "\\-") == 0 ? '-' :
+	     strcmp(s2, "\\(bu") == 0 ? 'b' : ' ';
+	return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1;
+}
+
+static int
+man_IP_pre(MAN_ARGS)
+{
+	const struct roff_node	*nn;
+	const char		*list_class;
+	enum htmltag		 list_elem, body_elem;
+	char			 list_type;
+
+	nn = n->type == ROFFT_BLOCK ? n : n->parent;
+	if ((list_type = list_continues(nn->prev, nn)) == '\0') {
+		/* Start a new list. */
+		if ((list_type = list_continues(nn, nn->next)) == '\0')
+			list_type = ' ';
+		switch (list_type) {
+		case ' ':
+			list_class = "Bl-tag";
+			list_elem = TAG_DL;
+			break;
+		case '*':
+			list_class = "Bl-bullet";
+			list_elem = TAG_UL;
+			break;
+		case '-':
+			list_class = "Bl-dash";
+			list_elem = TAG_UL;
+			break;
+		default:
+			abort();
+		}
+	} else {
+		/* Continue a list that was started earlier. */
+		list_class = NULL;
+		list_elem = TAG_MAX;
+	}
+	body_elem = list_type == ' ' ? TAG_DD : TAG_LI;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		if (list_elem != TAG_MAX)
+			print_otag(h, list_elem, "c", list_class);
+		return 1;
+	case ROFFT_HEAD:
+		if (body_elem == TAG_LI)
+			return 0;
+		print_otag(h, TAG_DT, "");
+		break;
+	case ROFFT_BODY:
+		print_otag(h, body_elem, "");
+		return 1;
+	default:
+		abort();
+	}
+
+	switch(n->tok) {
+	case MAN_IP:  /* Only print the first header element. */
+		if (n->child != NULL)
+			print_man_node(man, n->child, h);
+		break;
+	case MAN_TP:  /* Only print next-line header elements. */
+	case MAN_TQ:
+		nn = n->child;
+		while (nn != NULL && (NODE_LINE & nn->flags) == 0)
+			nn = nn->next;
+		while (nn != NULL) {
+			print_man_node(man, nn, h);
+			nn = nn->next;
+		}
+		break;
+	default:
+		abort();
+	}
+	return 0;
+}
+
+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 ((n = n->child) != NULL) {
+		print_otag(h, TAG_B, "");
+		print_text(h, n->string);
+	}
+
+	print_stagq(h, tt);
+
+	if (n != NULL && n->next != NULL) {
+		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)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		break;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		print_otag(h, TAG_DIV, "c", "Bd-indent");
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+static int
+man_SY_pre(MAN_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		print_otag(h, TAG_TABLE, "c", "Nm");
+		print_otag(h, TAG_TR, "");
+		break;
+	case ROFFT_HEAD:
+		print_otag(h, TAG_TD, "");
+		print_otag(h, TAG_CODE, "c", "Nm");
+		break;
+	case ROFFT_BODY:
+		print_otag(h, TAG_TD, "");
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+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, "ch", "Mt", cp);
+			free(cp);
+		} else
+			print_otag(h, TAG_A, "ch", "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;
+}
+
+static int
+man_abort_pre(MAN_ARGS)
+{
+	abort();
+}

Property changes on: vendor/mandoc/20190723/man_html.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/man_term.c
===================================================================
--- vendor/mandoc/20190723/man_term.c	(nonexistent)
+++ vendor/mandoc/20190723/man_term.c	(revision 350350)
@@ -0,0 +1,1225 @@
+/*	$Id: man_term.c,v 1.232 2019/07/23 17:53:35 schwarze Exp $ */
+/*
+ * Copyright (c) 2008-2012 Kristaps Dzonsons 
+ * Copyright (c) 2010-2015, 2017-2019 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 "tag.h"
+#include "main.h"
+
+#define	MAXMARGINS	  64 /* maximum number of indented scopes */
+
+struct	mtermp {
+	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	man_term_act {
+	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_SY(DECL_ARGS);
+static	int		  pre_TP(DECL_ARGS);
+static	int		  pre_UR(DECL_ARGS);
+static	int		  pre_abort(DECL_ARGS);
+static	int		  pre_alternate(DECL_ARGS);
+static	int		  pre_ign(DECL_ARGS);
+static	int		  pre_in(DECL_ARGS);
+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_SY(DECL_ARGS);
+static	void		  post_TP(DECL_ARGS);
+static	void		  post_UR(DECL_ARGS);
+
+static	void		  tag_man(struct termp *, struct roff_node *);
+
+static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
+	{ NULL, NULL, 0 }, /* TH */
+	{ pre_SH, post_SH, 0 }, /* SH */
+	{ pre_SS, post_SH, 0 }, /* SS */
+	{ pre_TP, post_TP, 0 }, /* TP */
+	{ pre_TP, post_TP, 0 }, /* TQ */
+	{ pre_abort, NULL, 0 }, /* LP */
+	{ pre_PP, NULL, 0 }, /* PP */
+	{ pre_abort, 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 */
+	{ 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_SY, post_SY, 0 }, /* SY */
+	{ NULL, NULL, 0 }, /* YS */
+	{ 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 man_term_act *man_term_act(enum roff_tok);
+
+
+static const struct man_term_act *
+man_term_act(enum roff_tok tok)
+{
+	assert(tok >= MAN_TH && tok <= MAN_MAX);
+	return man_term_acts + (tok - MAN_TH);
+}
+
+void
+terminal_man(void *arg, const struct roff_meta *man)
+{
+	struct mtermp		 mt;
+	struct termp		*p;
+	struct roff_node	*n, *nc, *nn;
+	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(mt));
+	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) {
+		for (nn = NULL; n != NULL; n = n->next) {
+			if (n->tok != MAN_SH)
+				continue;
+			nc = n->child->child;
+			if (nc->type != ROFFT_TEXT)
+				continue;
+			if (strcmp(nc->string, "SYNOPSIS") == 0)
+				break;
+			if (nn == NULL && strcmp(nc->string, "NAME") == 0)
+				nn = n;
+		}
+		if (n == NULL)
+			n = nn;
+		p->flags |= TERMP_NOSPACE;
+		if (n != NULL && (n = n->child->next->child) != NULL)
+			print_man_nodelist(p, &mt, n, man);
+		term_newln(p);
+	} else {
+		term_begin(p, print_man_head, print_man_foot, man);
+		p->flags |= TERMP_NOSPACE;
+		if (n != NULL)
+			print_man_nodelist(p, &mt, n, man);
+		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 != NULL && n->body->child != NULL)
+		if (n->body->child->type == ROFFT_TBL)
+			return;
+
+	if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
+		if (n->prev == NULL)
+			return;
+
+	for (i = 0; i < pardist; i++)
+		term_vspace(p);
+}
+
+
+static int
+pre_abort(DECL_ARGS)
+{
+	abort();
+}
+
+static int
+pre_ign(DECL_ARGS)
+{
+	return 0;
+}
+
+static int
+pre_I(DECL_ARGS)
+{
+	term_fontrepl(p, TERMFONT_UNDER);
+	return 1;
+}
+
+static int
+pre_literal(DECL_ARGS)
+{
+	term_newln(p);
+
+	/*
+	 * 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			 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();
+	}
+	for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) {
+		term_fontrepl(p, font[i]);
+		assert(nn->type == ROFFT_TEXT);
+		term_word(p, nn->string);
+		if (nn->flags & NODE_EOS)
+			p->flags |= TERMP_SENTENCE;
+		if (nn->next != NULL)
+			p->flags |= TERMP_NOSPACE;
+	}
+	return 0;
+}
+
+static int
+pre_B(DECL_ARGS)
+{
+	term_fontrepl(p, TERMFONT_BOLD);
+	return 1;
+}
+
+static int
+pre_OP(DECL_ARGS)
+{
+	term_word(p, "[");
+	p->flags |= TERMP_KEEP | TERMP_NOSPACE;
+
+	if ((n = n->child) != NULL) {
+		term_fontrepl(p, TERMFONT_BOLD);
+		term_word(p, n->string);
+	}
+	if (n != NULL && n->next != NULL) {
+		term_fontrepl(p, TERMFONT_UNDER);
+		term_word(p, n->next->string);
+	}
+	term_fontrepl(p, TERMFONT_NONE);
+	p->flags &= ~TERMP_KEEP;
+	p->flags |= TERMP_NOSPACE;
+	term_word(p, "]");
+	return 0;
+}
+
+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_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		break;
+	default:
+		abort();
+	}
+
+	if (n->child == NULL)
+		return 0;
+
+	if ((n->child->flags & NODE_NOFILL) == 0) {
+		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_BLOCK:
+	case ROFFT_HEAD:
+		break;
+	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:
+		abort();
+	}
+}
+
+static int
+pre_PP(DECL_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
+		print_bvspace(p, n, mt->pardist);
+		break;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		p->tcol->offset = mt->offset;
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+static int
+pre_IP(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_HEAD:
+		p->flags |= TERMP_NOBREAK;
+		p->trailspace = 1;
+		break;
+	case ROFFT_BODY:
+		p->flags |= TERMP_NOSPACE;
+		break;
+	default:
+		abort();
+	}
+
+	/* 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;
+		if (n->child != NULL) {
+			print_man_node(p, mt, n->child, meta);
+			tag_man(p, n->child);
+		}
+		return 0;
+	case ROFFT_BODY:
+		p->tcol->offset = mt->offset + len;
+		p->tcol->rmargin = p->maxrmargin;
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+static void
+post_IP(DECL_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		break;
+	case ROFFT_HEAD:
+		term_flushln(p);
+		p->flags &= ~TERMP_NOBREAK;
+		p->trailspace = 0;
+		p->tcol->rmargin = p->maxrmargin;
+		break;
+	case ROFFT_BODY:
+		term_newln(p);
+		p->tcol->offset = mt->offset;
+		break;
+	default:
+		abort();
+	}
+}
+
+static int
+pre_TP(DECL_ARGS)
+{
+	struct roffsu		 su;
+	struct roff_node	*nn;
+	int			 len;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		if (n->tok == MAN_TP)
+			print_bvspace(p, n, mt->pardist);
+		return 1;
+	case ROFFT_HEAD:
+		p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
+		p->trailspace = 1;
+		break;
+	case ROFFT_BODY:
+		p->flags |= TERMP_NOSPACE;
+		break;
+	default:
+		abort();
+	}
+
+	/* 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;
+
+		/* Don't print same-line elements. */
+		nn = n->child;
+		while (nn != NULL && (nn->flags & NODE_LINE) == 0)
+			nn = nn->next;
+
+		if (nn == NULL)
+			return 0;
+
+		if (nn->type == ROFFT_TEXT)
+			tag_man(p, nn);
+		else if (nn->child != NULL &&
+		    nn->child->type == ROFFT_TEXT &&
+		    (nn->tok == MAN_B || nn->tok == MAN_BI ||
+		     nn->tok == MAN_BR || nn->tok == MAN_I ||
+		     nn->tok == MAN_IB || nn->tok == MAN_IR))
+			tag_man(p, nn->child);
+
+		while (nn != NULL) {
+			print_man_node(p, mt, nn, meta);
+			nn = nn->next;
+		}
+		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:
+		abort();
+	}
+	return 1;
+}
+
+static void
+post_TP(DECL_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		break;
+	case ROFFT_HEAD:
+		term_flushln(p);
+		break;
+	case ROFFT_BODY:
+		term_newln(p);
+		p->tcol->offset = mt->offset;
+		break;
+	default:
+		abort();
+	}
+}
+
+static int
+pre_SS(DECL_ARGS)
+{
+	int	 i;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		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 &&
+		    man_term_act(n->tok)->flags & MAN_NOTEXT);
+		if (n == NULL || n->type == ROFFT_COMMENT ||
+		    (n->tok == MAN_SS && n->body->child == NULL))
+			break;
+
+		for (i = 0; i < mt->pardist; i++)
+			term_vspace(p);
+		break;
+	case ROFFT_HEAD:
+		term_fontrepl(p, TERMFONT_BOLD);
+		p->tcol->offset = term_len(p, 3);
+		p->tcol->rmargin = mt->offset;
+		p->trailspace = mt->offset;
+		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
+		break;
+	case ROFFT_BODY:
+		p->tcol->offset = mt->offset;
+		p->tcol->rmargin = p->maxrmargin;
+		p->trailspace = 0;
+		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
+		break;
+	default:
+		break;
+	}
+	return 1;
+}
+
+static int
+pre_SH(DECL_ARGS)
+{
+	int	 i;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		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 &&
+		    man_term_act(n->tok)->flags & MAN_NOTEXT);
+		if (n == NULL || n->type == ROFFT_COMMENT ||
+		    (n->tok == MAN_SH && n->body->child == NULL))
+			break;
+
+		for (i = 0; i < mt->pardist; i++)
+			term_vspace(p);
+		break;
+	case ROFFT_HEAD:
+		term_fontrepl(p, TERMFONT_BOLD);
+		p->tcol->offset = 0;
+		p->tcol->rmargin = mt->offset;
+		p->trailspace = mt->offset;
+		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
+		break;
+	case ROFFT_BODY:
+		p->tcol->offset = mt->offset;
+		p->tcol->rmargin = p->maxrmargin;
+		p->trailspace = 0;
+		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+static void
+post_SH(DECL_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		break;
+	case ROFFT_HEAD:
+	case ROFFT_BODY:
+		term_newln(p);
+		break;
+	default:
+		abort();
+	}
+}
+
+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;
+	case ROFFT_BODY:
+		break;
+	default:
+		abort();
+	}
+
+	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:
+	case ROFFT_HEAD:
+		return;
+	case ROFFT_BODY:
+		break;
+	default:
+		abort();
+	}
+	term_newln(p);
+	mt->offset -= n->parent->head->aux;
+	p->tcol->offset = mt->offset;
+	if (--mt->lmarginsz < MAXMARGINS)
+		mt->lmargincur = mt->lmarginsz;
+}
+
+static int
+pre_SY(DECL_ARGS)
+{
+	const struct roff_node	*nn;
+	int			 len;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		if (n->prev == NULL || n->prev->tok != MAN_SY)
+			print_bvspace(p, n, mt->pardist);
+		return 1;
+	case ROFFT_HEAD:
+	case ROFFT_BODY:
+		break;
+	default:
+		abort();
+	}
+
+	nn = n->parent->head->child;
+	len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1;
+
+	switch (n->type) {
+	case ROFFT_HEAD:
+		p->tcol->offset = mt->offset;
+		p->tcol->rmargin = mt->offset + len;
+		if (n->next->child == NULL ||
+		    (n->next->child->flags & NODE_NOFILL) == 0)
+			p->flags |= TERMP_NOBREAK;
+		term_fontrepl(p, TERMFONT_BOLD);
+		break;
+	case ROFFT_BODY:
+		mt->lmargin[mt->lmargincur] = len;
+		p->tcol->offset = mt->offset + len;
+		p->tcol->rmargin = p->maxrmargin;
+		p->flags |= TERMP_NOSPACE;
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+static void
+post_SY(DECL_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		break;
+	case ROFFT_HEAD:
+		term_flushln(p);
+		p->flags &= ~TERMP_NOBREAK;
+		break;
+	case ROFFT_BODY:
+		term_newln(p);
+		p->tcol->offset = mt->offset;
+		break;
+	default:
+		abort();
+	}
+}
+
+static int
+pre_UR(DECL_ARGS)
+{
+	return n->type != ROFFT_HEAD;
+}
+
+static void
+post_UR(DECL_ARGS)
+{
+	if (n->type != ROFFT_BLOCK)
+		return;
+
+	term_word(p, "<");
+	p->flags |= TERMP_NOSPACE;
+
+	if (n->child->child != NULL)
+		print_man_node(p, mt, n->child->child, meta);
+
+	p->flags |= TERMP_NOSPACE;
+	term_word(p, ">");
+}
+
+static void
+print_man_node(DECL_ARGS)
+{
+	const struct man_term_act *act;
+	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);
+		else if (n->flags & NODE_DELIMC)
+			p->flags |= TERMP_NOSPACE;
+
+		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;
+	}
+
+	act = man_term_act(n->tok);
+	if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
+		term_fontrepl(p, TERMFONT_NONE);
+
+	c = 1;
+	if (act->pre != NULL)
+		c = (*act->pre)(p, mt, n, meta);
+
+	if (c && n->child != NULL)
+		print_man_nodelist(p, mt, n->child, meta);
+
+	if (act->post != NULL)
+		(*act->post)(p, mt, n, meta);
+	if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
+		term_fontrepl(p, TERMFONT_NONE);
+
+out:
+	/*
+	 * 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 (n->flags & NODE_NOFILL &&
+	    ! (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 (n->flags & NODE_EOS)
+		p->flags |= TERMP_SENTENCE;
+}
+
+static void
+print_man_nodelist(DECL_ARGS)
+{
+	while (n != NULL) {
+		print_man_node(p, mt, n, meta);
+		n = n->next;
+	}
+}
+
+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 != NULL) {
+		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);
+}
+
+/*
+ * Skip leading whitespace, dashes, backslashes, and font escapes,
+ * then create a tag if the first following byte is a letter.
+ * Priority is high unless whitespace is present.
+ */
+static void
+tag_man(struct termp *p, struct roff_node *n)
+{
+	const char	*cp, *arg;
+	int		 prio, sz;
+
+	assert(n->type == ROFFT_TEXT);
+	cp = n->string;
+	prio = 1;
+	for (;;) {
+		switch (*cp) {
+		case ' ':
+		case '\t':
+			prio = INT_MAX;
+			/* FALLTHROUGH */
+		case '-':
+			cp++;
+			break;
+		case '\\':
+			cp++;
+			switch (mandoc_escape(&cp, &arg, &sz)) {
+			case ESCAPE_FONT:
+			case ESCAPE_FONTROMAN:
+			case ESCAPE_FONTITALIC:
+			case ESCAPE_FONTBOLD:
+			case ESCAPE_FONTPREV:
+			case ESCAPE_FONTBI:
+				break;
+			case ESCAPE_SPECIAL:
+				if (sz != 1)
+					return;
+				switch (*arg) {
+				case '&':
+				case '-':
+				case 'e':
+					break;
+				default:
+					return;
+				}
+				break;
+			default:
+				return;
+			}
+			break;
+		default:
+			if (isalpha((unsigned char)*cp))
+				tag_put(cp, prio, p->line);
+			return;
+		}
+	}
+}

Property changes on: vendor/mandoc/20190723/man_term.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/man_validate.c
===================================================================
--- vendor/mandoc/20190723/man_validate.c	(nonexistent)
+++ vendor/mandoc/20190723/man_validate.c	(revision 350350)
@@ -0,0 +1,537 @@
+/*	$Id: man_validate.c,v 1.149 2019/06/27 15:07:30 schwarze Exp $ */
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "roff.h"
+#include "man.h"
+#include "libmandoc.h"
+#include "roff_int.h"
+#include "libman.h"
+
+#define	CHKARGS	  struct roff_man *man, struct roff_node *n
+
+typedef	void	(*v_check)(CHKARGS);
+
+static	void	  check_abort(CHKARGS) __attribute__((__noreturn__));
+static	void	  check_par(CHKARGS);
+static	void	  check_part(CHKARGS);
+static	void	  check_root(CHKARGS);
+static	void	  check_text(CHKARGS);
+
+static	void	  post_AT(CHKARGS);
+static	void	  post_EE(CHKARGS);
+static	void	  post_EX(CHKARGS);
+static	void	  post_IP(CHKARGS);
+static	void	  post_OP(CHKARGS);
+static	void	  post_SH(CHKARGS);
+static	void	  post_TH(CHKARGS);
+static	void	  post_UC(CHKARGS);
+static	void	  post_UR(CHKARGS);
+static	void	  post_in(CHKARGS);
+
+static	const v_check man_valids[MAN_MAX - MAN_TH] = {
+	post_TH,    /* TH */
+	post_SH,    /* SH */
+	post_SH,    /* SS */
+	NULL,       /* TP */
+	NULL,       /* TQ */
+	check_abort,/* LP */
+	check_par,  /* PP */
+	check_abort,/* P */
+	post_IP,    /* IP */
+	NULL,       /* HP */
+	NULL,       /* SM */
+	NULL,       /* SB */
+	NULL,       /* BI */
+	NULL,       /* IB */
+	NULL,       /* BR */
+	NULL,       /* RB */
+	NULL,       /* R */
+	NULL,       /* B */
+	NULL,       /* I */
+	NULL,       /* IR */
+	NULL,       /* RI */
+	NULL,       /* RE */
+	check_part, /* RS */
+	NULL,       /* DT */
+	post_UC,    /* UC */
+	NULL,       /* PD */
+	post_AT,    /* AT */
+	post_in,    /* in */
+	NULL,       /* SY */
+	NULL,       /* YS */
+	post_OP,    /* OP */
+	post_EX,    /* EX */
+	post_EE,    /* EE */
+	post_UR,    /* UR */
+	NULL,       /* UE */
+	post_UR,    /* MT */
+	NULL,       /* ME */
+};
+
+
+/* Validate the subtree rooted at man->last. */
+void
+man_validate(struct roff_man *man)
+{
+	struct roff_node *n;
+	const v_check	 *cp;
+
+	/*
+	 * Translate obsolete macros such that later code
+	 * does not need to look for them.
+	 */
+
+	n = man->last;
+	switch (n->tok) {
+	case MAN_LP:
+	case MAN_P:
+		n->tok = MAN_PP;
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * Iterate over all children, recursing into each one
+	 * in turn, depth-first.
+	 */
+
+	man->last = man->last->child;
+	while (man->last != NULL) {
+		man_validate(man);
+		if (man->last == n)
+			man->last = man->last->child;
+		else
+			man->last = man->last->next;
+	}
+
+	/* Finally validate the macro itself. */
+
+	man->last = n;
+	man->next = ROFF_NEXT_SIBLING;
+	switch (n->type) {
+	case ROFFT_TEXT:
+		check_text(man, n);
+		break;
+	case ROFFT_ROOT:
+		check_root(man, n);
+		break;
+	case ROFFT_COMMENT:
+	case ROFFT_EQN:
+	case ROFFT_TBL:
+		break;
+	default:
+		if (n->tok < ROFF_MAX) {
+			roff_validate(man);
+			break;
+		}
+		assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
+		cp = man_valids + (n->tok - MAN_TH);
+		if (*cp)
+			(*cp)(man, n);
+		if (man->last == n)
+			n->flags |= NODE_VALID;
+		break;
+	}
+}
+
+static void
+check_root(CHKARGS)
+{
+	assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
+
+	if (n->last == NULL || n->last->type == ROFFT_COMMENT)
+		mandoc_msg(MANDOCERR_DOC_EMPTY, n->line, n->pos, NULL);
+	else
+		man->meta.hasbody = 1;
+
+	if (NULL == man->meta.title) {
+		mandoc_msg(MANDOCERR_TH_NOTITLE, n->line, n->pos, NULL);
+
+		/*
+		 * If a title hasn't been set, do so now (by
+		 * implication, date and section also aren't set).
+		 */
+
+		man->meta.title = mandoc_strdup("");
+		man->meta.msec = mandoc_strdup("");
+		man->meta.date = mandoc_normdate(man, NULL, n->line, n->pos);
+	}
+
+	if (man->meta.os_e &&
+	    (man->meta.rcsids & (1 << man->meta.os_e)) == 0)
+		mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0,
+		    man->meta.os_e == MANDOC_OS_OPENBSD ?
+		    "(OpenBSD)" : "(NetBSD)");
+}
+
+static void
+check_abort(CHKARGS)
+{
+	abort();
+}
+
+static void
+check_text(CHKARGS)
+{
+	char		*cp, *p;
+
+	if (n->flags & NODE_NOFILL)
+		return;
+
+	cp = n->string;
+	for (p = cp; NULL != (p = strchr(p, '\t')); p++)
+		mandoc_msg(MANDOCERR_FI_TAB,
+		    n->line, n->pos + (int)(p - cp), NULL);
+}
+
+static void
+post_EE(CHKARGS)
+{
+	if ((n->flags & NODE_NOFILL) == 0)
+		mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "EE");
+}
+
+static void
+post_EX(CHKARGS)
+{
+	if (n->flags & NODE_NOFILL)
+		mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "EX");
+}
+
+static void
+post_OP(CHKARGS)
+{
+
+	if (n->child == NULL)
+		mandoc_msg(MANDOCERR_OP_EMPTY, n->line, n->pos, "OP");
+	else if (n->child->next != NULL && n->child->next->next != NULL) {
+		n = n->child->next->next;
+		mandoc_msg(MANDOCERR_ARG_EXCESS,
+		    n->line, n->pos, "OP ... %s", n->string);
+	}
+}
+
+static void
+post_SH(CHKARGS)
+{
+	struct roff_node	*nc;
+
+	if (n->type != ROFFT_BODY || (nc = n->child) == NULL)
+		return;
+
+	if (nc->tok == MAN_PP && nc->body->child != NULL) {
+		while (nc->body->last != NULL) {
+			man->next = ROFF_NEXT_CHILD;
+			roff_node_relink(man, nc->body->last);
+			man->last = n;
+		}
+	}
+
+	if (nc->tok == MAN_PP || nc->tok == ROFF_sp || nc->tok == ROFF_br) {
+		mandoc_msg(MANDOCERR_PAR_SKIP, nc->line, nc->pos,
+		    "%s after %s", roff_name[nc->tok], roff_name[n->tok]);
+		roff_node_delete(man, nc);
+	}
+
+	/*
+	 * Trailing PP is empty, so it is deleted by check_par().
+	 * Trailing sp is significant.
+	 */
+
+	if ((nc = n->last) != NULL && nc->tok == ROFF_br) {
+		mandoc_msg(MANDOCERR_PAR_SKIP,
+		    nc->line, nc->pos, "%s at the end of %s",
+		    roff_name[nc->tok], roff_name[n->tok]);
+		roff_node_delete(man, nc);
+	}
+}
+
+static void
+post_UR(CHKARGS)
+{
+	if (n->type == ROFFT_HEAD && n->child == NULL)
+		mandoc_msg(MANDOCERR_UR_NOHEAD, n->line, n->pos,
+		    "%s", roff_name[n->tok]);
+	check_part(man, n);
+}
+
+static void
+check_part(CHKARGS)
+{
+
+	if (n->type == ROFFT_BODY && n->child == NULL)
+		mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos,
+		    "%s", roff_name[n->tok]);
+}
+
+static void
+check_par(CHKARGS)
+{
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		if (n->body->child == NULL)
+			roff_node_delete(man, n);
+		break;
+	case ROFFT_BODY:
+		if (n->child != NULL &&
+		    (n->child->tok == ROFF_sp || n->child->tok == ROFF_br)) {
+			mandoc_msg(MANDOCERR_PAR_SKIP,
+			    n->child->line, n->child->pos,
+			    "%s after %s", roff_name[n->child->tok],
+			    roff_name[n->tok]);
+			roff_node_delete(man, n->child);
+		}
+		if (n->child == NULL)
+			mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
+			    "%s empty", roff_name[n->tok]);
+		break;
+	case ROFFT_HEAD:
+		if (n->child != NULL)
+			mandoc_msg(MANDOCERR_ARG_SKIP,
+			    n->line, n->pos, "%s %s%s",
+			    roff_name[n->tok], n->child->string,
+			    n->child->next != NULL ? " ..." : "");
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+post_IP(CHKARGS)
+{
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		if (n->head->child == NULL && n->body->child == NULL)
+			roff_node_delete(man, n);
+		break;
+	case ROFFT_BODY:
+		if (n->parent->head->child == NULL && n->child == NULL)
+			mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
+			    "%s empty", roff_name[n->tok]);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+post_TH(CHKARGS)
+{
+	struct roff_node *nb;
+	const char	*p;
+
+	free(man->meta.title);
+	free(man->meta.vol);
+	free(man->meta.os);
+	free(man->meta.msec);
+	free(man->meta.date);
+
+	man->meta.title = man->meta.vol = man->meta.date =
+	    man->meta.msec = man->meta.os = NULL;
+
+	nb = n;
+
+	/* ->TITLE<- MSEC DATE OS VOL */
+
+	n = n->child;
+	if (n != NULL && n->string != NULL) {
+		for (p = n->string; *p != '\0'; p++) {
+			/* Only warn about this once... */
+			if (isalpha((unsigned char)*p) &&
+			    ! isupper((unsigned char)*p)) {
+				mandoc_msg(MANDOCERR_TITLE_CASE, n->line,
+				    n->pos + (int)(p - n->string),
+				    "TH %s", n->string);
+				break;
+			}
+		}
+		man->meta.title = mandoc_strdup(n->string);
+	} else {
+		man->meta.title = mandoc_strdup("");
+		mandoc_msg(MANDOCERR_TH_NOTITLE, nb->line, nb->pos, "TH");
+	}
+
+	/* TITLE ->MSEC<- DATE OS VOL */
+
+	if (n != NULL)
+		n = n->next;
+	if (n != NULL && n->string != NULL)
+		man->meta.msec = mandoc_strdup(n->string);
+	else {
+		man->meta.msec = mandoc_strdup("");
+		mandoc_msg(MANDOCERR_MSEC_MISSING,
+		    nb->line, nb->pos, "TH %s", man->meta.title);
+	}
+
+	/* TITLE MSEC ->DATE<- OS VOL */
+
+	if (n != NULL)
+		n = n->next;
+	if (n != NULL && n->string != NULL && n->string[0] != '\0')
+		man->meta.date = mandoc_normdate(man,
+		    n->string, n->line, n->pos);
+	else {
+		man->meta.date = mandoc_strdup("");
+		mandoc_msg(MANDOCERR_DATE_MISSING,
+		    n == NULL ? nb->line : n->line,
+		    n == NULL ? nb->pos : n->pos, "TH");
+	}
+
+	/* TITLE MSEC DATE ->OS<- VOL */
+
+	if (n && (n = n->next))
+		man->meta.os = mandoc_strdup(n->string);
+	else if (man->os_s != NULL)
+		man->meta.os = mandoc_strdup(man->os_s);
+	if (man->meta.os_e == MANDOC_OS_OTHER && man->meta.os != NULL) {
+		if (strstr(man->meta.os, "OpenBSD") != NULL)
+			man->meta.os_e = MANDOC_OS_OPENBSD;
+		else if (strstr(man->meta.os, "NetBSD") != NULL)
+			man->meta.os_e = MANDOC_OS_NETBSD;
+	}
+
+	/* TITLE MSEC DATE OS ->VOL<- */
+	/* If missing, use the default VOL name for MSEC. */
+
+	if (n && (n = n->next))
+		man->meta.vol = mandoc_strdup(n->string);
+	else if ('\0' != man->meta.msec[0] &&
+	    (NULL != (p = mandoc_a2msec(man->meta.msec))))
+		man->meta.vol = mandoc_strdup(p);
+
+	if (n != NULL && (n = n->next) != NULL)
+		mandoc_msg(MANDOCERR_ARG_EXCESS,
+		    n->line, n->pos, "TH ... %s", n->string);
+
+	/*
+	 * Remove the `TH' node after we've processed it for our
+	 * meta-data.
+	 */
+	roff_node_delete(man, man->last);
+}
+
+static void
+post_UC(CHKARGS)
+{
+	static const char * const bsd_versions[] = {
+	    "3rd Berkeley Distribution",
+	    "4th Berkeley Distribution",
+	    "4.2 Berkeley Distribution",
+	    "4.3 Berkeley Distribution",
+	    "4.4 Berkeley Distribution",
+	};
+
+	const char	*p, *s;
+
+	n = n->child;
+
+	if (n == NULL || n->type != ROFFT_TEXT)
+		p = bsd_versions[0];
+	else {
+		s = n->string;
+		if (0 == strcmp(s, "3"))
+			p = bsd_versions[0];
+		else if (0 == strcmp(s, "4"))
+			p = bsd_versions[1];
+		else if (0 == strcmp(s, "5"))
+			p = bsd_versions[2];
+		else if (0 == strcmp(s, "6"))
+			p = bsd_versions[3];
+		else if (0 == strcmp(s, "7"))
+			p = bsd_versions[4];
+		else
+			p = bsd_versions[0];
+	}
+
+	free(man->meta.os);
+	man->meta.os = mandoc_strdup(p);
+}
+
+static void
+post_AT(CHKARGS)
+{
+	static const char * const unix_versions[] = {
+	    "7th Edition",
+	    "System III",
+	    "System V",
+	    "System V Release 2",
+	};
+
+	struct roff_node *nn;
+	const char	*p, *s;
+
+	n = n->child;
+
+	if (n == NULL || n->type != ROFFT_TEXT)
+		p = unix_versions[0];
+	else {
+		s = n->string;
+		if (0 == strcmp(s, "3"))
+			p = unix_versions[0];
+		else if (0 == strcmp(s, "4"))
+			p = unix_versions[1];
+		else if (0 == strcmp(s, "5")) {
+			nn = n->next;
+			if (nn != NULL &&
+			    nn->type == ROFFT_TEXT &&
+			    nn->string[0] != '\0')
+				p = unix_versions[3];
+			else
+				p = unix_versions[2];
+		} else
+			p = unix_versions[0];
+	}
+
+	free(man->meta.os);
+	man->meta.os = mandoc_strdup(p);
+}
+
+static void
+post_in(CHKARGS)
+{
+	char	*s;
+
+	if (n->parent->tok != MAN_TP ||
+	    n->parent->type != ROFFT_HEAD ||
+	    n->child == NULL ||
+	    *n->child->string == '+' ||
+	    *n->child->string == '-')
+		return;
+	mandoc_asprintf(&s, "+%s", n->child->string);
+	free(n->child->string);
+	n->child->string = s;
+}

Property changes on: vendor/mandoc/20190723/man_validate.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/mandoc.1
===================================================================
--- vendor/mandoc/20190723/mandoc.1	(nonexistent)
+++ vendor/mandoc/20190723/mandoc.1	(revision 350350)
@@ -0,0 +1,2317 @@
+.\"	$Id: mandoc.1,v 1.240 2019/07/10 19:39:01 schwarze Exp $
+.\"
+.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+.\" Copyright (c) 2012, 2014-2019 Ingo Schwarze 
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: July 10 2019 $
+.Dt MANDOC 1
+.Os
+.Sh NAME
+.Nm mandoc
+.Nd format manual pages
+.Sh SYNOPSIS
+.Nm mandoc
+.Op Fl ac
+.Op Fl I Cm os Ns = Ns Ar name
+.Op Fl K Ar encoding
+.Op Fl mdoc | man
+.Op Fl O Ar options
+.Op Fl T Ar output
+.Op Fl W Ar level
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility formats manual pages for display.
+.Pp
+By default,
+.Nm
+reads
+.Xr mdoc 7
+or
+.Xr man 7
+text from stdin and produces
+.Fl T Cm locale
+output.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+If the standard output is a terminal device and
+.Fl c
+is not specified, use
+.Xr more 1
+to paginate the output, just like
+.Xr man 1
+would.
+.It Fl c
+Copy the formatted manual pages to the standard output without using
+.Xr more 1
+to paginate them.
+This is the default.
+It can be specified to override
+.Fl a .
+.It Fl I Cm os Ns = Ns Ar name
+Override the default operating system
+.Ar name
+for the
+.Xr mdoc 7
+.Ic \&Os
+and for the
+.Xr man 7
+.Ic \&TH
+macro.
+.It Fl K Ar encoding
+Specify the input encoding.
+The supported
+.Ar encoding
+arguments are
+.Cm us-ascii ,
+.Cm iso-8859-1 ,
+and
+.Cm utf-8 .
+If not specified, autodetection uses the first match in the following
+list:
+.Bl -enum
+.It
+If the first three bytes of the input file are the UTF-8 byte order
+mark (BOM, 0xefbbbf), input is interpreted as
+.Cm utf-8 .
+.It
+If the first or second line of the input file matches the
+.Sy emacs
+mode line format
+.Pp
+.D1 .\e" -*- Oo ...; Oc coding: Ar encoding ; No -*-
+.Pp
+then input is interpreted according to
+.Ar encoding .
+.It
+If the first non-ASCII byte in the file introduces a valid UTF-8
+sequence, input is interpreted as
+.Cm utf-8 .
+.It
+Otherwise, input is interpreted as
+.Cm iso-8859-1 .
+.El
+.It Fl mdoc | man
+With
+.Fl mdoc ,
+all input files are interpreted as
+.Xr mdoc 7 .
+With
+.Fl man ,
+all input files are interpreted as
+.Xr man 7 .
+By default, the input language is automatically detected for each file:
+if the first macro is
+.Ic \&Dd
+or
+.Ic \&Dt ,
+the
+.Xr mdoc 7
+parser is used; otherwise, the
+.Xr man 7
+parser is used.
+With other arguments,
+.Fl m
+is silently ignored.
+.It Fl O Ar options
+Comma-separated output options.
+See the descriptions of the individual output formats for supported
+.Ar options .
+.It Fl T Ar output
+Select the output format.
+Supported values for the
+.Ar output
+argument are
+.Cm ascii ,
+.Cm html ,
+the default of
+.Cm locale ,
+.Cm man ,
+.Cm markdown ,
+.Cm pdf ,
+.Cm ps ,
+.Cm tree ,
+and
+.Cm utf8 .
+.Pp
+The special
+.Fl T Cm lint
+mode only parses the input and produces no output.
+It implies
+.Fl W Cm all
+and redirects parser messages, which usually appear on standard
+error output, to standard output.
+.It Fl W Ar level
+Specify the minimum message
+.Ar level
+to be reported on the standard error output and to affect the exit status.
+The
+.Ar level
+can be
+.Cm base ,
+.Cm style ,
+.Cm warning ,
+.Cm error ,
+or
+.Cm unsupp .
+The
+.Cm base
+level automatically derives the operating system from the contents of the
+.Ic \&Os
+macro, from the
+.Fl Ios
+command line option, or from the
+.Xr uname 3
+return value.
+The levels
+.Cm openbsd
+and
+.Cm netbsd
+are variants of
+.Cm base
+that bypass autodetection and request validation of base system
+conventions for a particular operating system.
+The level
+.Cm all
+is an alias for
+.Cm base .
+By default,
+.Nm
+is silent.
+See
+.Sx EXIT STATUS
+and
+.Sx DIAGNOSTICS
+for details.
+.Pp
+The special option
+.Fl W Cm stop
+tells
+.Nm
+to exit after parsing a file that causes warnings or errors of at least
+the requested level.
+No formatted output will be produced from that file.
+If both a
+.Ar level
+and
+.Cm stop
+are requested, they can be joined with a comma, for example
+.Fl W Cm error , Ns Cm stop .
+.It Ar file
+Read from the given input file.
+If multiple files are specified, they are processed in the given order.
+If unspecified,
+.Nm
+reads from standard input.
+.El
+.Pp
+The options
+.Fl fhklw
+are also supported and are documented in
+.Xr man 1 .
+In
+.Fl f
+and
+.Fl k
+mode,
+.Nm
+also supports the options
+.Fl CMmOSs
+described in the
+.Xr apropos 1
+manual.
+The options
+.Fl fkl
+are mutually exclusive and override each other.
+.Ss ASCII Output
+Use
+.Fl T Cm ascii
+to force text output in 7-bit ASCII character encoding documented in the
+.Xr ascii 7
+manual page, ignoring the
+.Xr locale 1
+set in the environment.
+.Pp
+Font styles are applied by using back-spaced encoding such that an
+underlined character
+.Sq c
+is rendered as
+.Sq _ Ns \e[bs] Ns c ,
+where
+.Sq \e[bs]
+is the back-space character number 8.
+Emboldened characters are rendered as
+.Sq c Ns \e[bs] Ns c .
+This markup is typically converted to appropriate terminal sequences by
+the pager or
+.Xr ul 1 .
+To remove the markup, pipe the output to
+.Xr col 1
+.Fl b
+instead.
+.Pp
+The special characters documented in
+.Xr mandoc_char 7
+are rendered best-effort in an ASCII equivalent.
+In particular, opening and closing
+.Sq single quotes
+are represented as characters number 0x60 and 0x27, respectively,
+which agrees with all ASCII standards from 1965 to the latest
+revision (2012) and which matches the traditional way in which
+.Xr roff 7
+formatters represent single quotes in ASCII output.
+This correct ASCII rendering may look strange with modern
+Unicode-compatible fonts because contrary to ASCII, Unicode uses
+the code point U+0060 for the grave accent only, never for an opening
+quote.
+.Pp
+The following
+.Fl O
+arguments are accepted:
+.Bl -tag -width Ds
+.It Cm indent Ns = Ns Ar indent
+The left margin for normal text is set to
+.Ar indent
+blank characters instead of the default of five for
+.Xr mdoc 7
+and seven for
+.Xr man 7 .
+Increasing this is not recommended; it may result in degraded formatting,
+for example overfull lines or ugly line breaks.
+When output is to a pager on a terminal that is less than 66 columns
+wide, the default is reduced to three columns.
+.It Cm mdoc
+Format
+.Xr man 7
+input files in
+.Xr mdoc 7
+output style.
+Specifically, this suppresses the two additional blank lines near the
+top and the bottom of each page, and it implies
+.Fl O Cm indent Ns =5 .
+One useful application is for checking that
+.Fl T Cm man
+output formats in the same way as the
+.Xr mdoc 7
+source it was generated from.
+.It Cm tag Ns Op = Ns Ar term
+If the formatted manual page is opened in a pager,
+go to the definition of the
+.Ar term
+rather than showing the manual page from the beginning.
+If no
+.Ar term
+is specified, reuse the first command line argument that is not a
+.Ar section
+number.
+If that argument is in
+.Xr apropos 1
+.Ar key Ns = Ns Ar val
+format, only the
+.Ar val
+is used rather than the argument as a whole.
+This is useful for commands like
+.Ql man -akO tag Ic=ulimit
+to search for a keyword and jump right to its definition
+in the matching manual pages.
+.It Cm width Ns = Ns Ar width
+The output width is set to
+.Ar width
+instead of the default of 78.
+When output is to a pager on a terminal that is less than 79 columns
+wide, the default is reduced to one less than the terminal width.
+In any case, lines that are output in literal mode are never wrapped
+and may exceed the output width.
+.El
+.Ss HTML Output
+Output produced by
+.Fl T Cm html
+conforms to HTML5 using optional self-closing tags.
+Default styles use only CSS1.
+Equations rendered from
+.Xr eqn 7
+blocks use MathML.
+.Pp
+The file
+.Pa /usr/share/misc/mandoc.css
+documents style-sheet classes available for customising output.
+If a style-sheet is not specified with
+.Fl O Cm style ,
+.Fl T Cm html
+defaults to simple output (via an embedded style-sheet)
+readable in any graphical or text-based web
+browser.
+.Pp
+Non-ASCII characters are rendered
+as hexadecimal Unicode character references.
+.Pp
+The following
+.Fl O
+arguments are accepted:
+.Bl -tag -width Ds
+.It Cm fragment
+Omit the  declaration and the , , and 
+elements and only emit the subtree below the  element.
+The
+.Cm style
+argument will be ignored.
+This is useful when embedding manual content within existing documents.
+.It Cm includes Ns = Ns Ar fmt
+The string
+.Ar fmt ,
+for example,
+.Ar ../src/%I.html ,
+is used as a template for linked header files (usually via the
+.Ic \&In
+macro).
+Instances of
+.Sq \&%I
+are replaced with the include filename.
+The default is not to present a
+hyperlink.
+.It Cm man Ns = Ns Ar fmt Ns Op ; Ns Ar fmt
+The string
+.Ar fmt ,
+for example,
+.Ar ../html%S/%N.%S.html ,
+is used as a template for linked manuals (usually via the
+.Ic \&Xr
+macro).
+Instances of
+.Sq \&%N
+and
+.Sq %S
+are replaced with the linked manual's name and section, respectively.
+If no section is included, section 1 is assumed.
+The default is not to
+present a hyperlink.
+If two formats are given and a file
+.Ar %N.%S
+exists in the current directory, the first format is used;
+otherwise, the second format is used.
+.It Cm style Ns = Ns Ar style.css
+The file
+.Ar style.css
+is used for an external style-sheet.
+This must be a valid absolute or
+relative URI.
+.It Cm toc
+If an input file contains at least two non-standard sections,
+print a table of contents near the beginning of the output.
+.El
+.Ss Locale Output
+By default,
+.Nm
+automatically selects UTF-8 or ASCII output according to the current
+.Xr locale 1 .
+If any of the environment variables
+.Ev LC_ALL ,
+.Ev LC_CTYPE ,
+or
+.Ev LANG
+are set and the first one that is set
+selects the UTF-8 character encoding, it produces
+.Sx UTF-8 Output ;
+otherwise, it falls back to
+.Sx ASCII Output .
+This output mode can also be selected explicitly with
+.Fl T Cm locale .
+.Ss Man Output
+Use
+.Fl T Cm man
+to translate
+.Xr mdoc 7
+input into
+.Xr man 7
+output format.
+This is useful for distributing manual sources to legacy systems
+lacking
+.Xr mdoc 7
+formatters.
+.Pp
+If the input format of a file is
+.Xr man 7 ,
+the input is copied to the output, expanding any
+.Xr roff 7
+.Ic so
+requests.
+The parser is also run, and as usual, the
+.Fl W
+level controls which
+.Sx DIAGNOSTICS
+are displayed before copying the input to the output.
+.Ss Markdown Output
+Use
+.Fl T Cm markdown
+to translate
+.Xr mdoc 7
+input to the markdown format conforming to
+.Lk http://daringfireball.net/projects/markdown/syntax.text\
+ "John Gruber's 2004 specification" .
+The output also almost conforms to the
+.Lk http://commonmark.org/ CommonMark
+specification.
+.Pp
+The character set used for the markdown output is ASCII.
+Non-ASCII characters are encoded as HTML entities.
+Since that is not possible in literal font contexts, because these
+are rendered as code spans and code blocks in the markdown output,
+non-ASCII characters are transliterated to ASCII approximations in
+these contexts.
+.Pp
+Markdown is a very weak markup language, so all semantic markup is
+lost, and even part of the presentational markup may be lost.
+Do not use this as an intermediate step in converting to HTML;
+instead, use
+.Fl T Cm html
+directly.
+.Pp
+The
+.Xr man 7 ,
+.Xr tbl 7 ,
+and
+.Xr eqn 7
+input languages are not supported by
+.Fl T Cm markdown
+output mode.
+.Ss PDF Output
+PDF-1.1 output may be generated by
+.Fl T Cm pdf .
+See
+.Sx PostScript Output
+for
+.Fl O
+arguments and defaults.
+.Ss PostScript Output
+PostScript
+.Qq Adobe-3.0
+Level-2 pages may be generated by
+.Fl T Cm ps .
+Output pages default to letter sized and are rendered in the Times font
+family, 11-point.
+Margins are calculated as 1/9 the page length and width.
+Line-height is 1.4m.
+.Pp
+Special characters are rendered as in
+.Sx ASCII Output .
+.Pp
+The following
+.Fl O
+arguments are accepted:
+.Bl -tag -width Ds
+.It Cm paper Ns = Ns Ar name
+The paper size
+.Ar name
+may be one of
+.Ar a3 ,
+.Ar a4 ,
+.Ar a5 ,
+.Ar legal ,
+or
+.Ar letter .
+You may also manually specify dimensions as
+.Ar NNxNN ,
+width by height in millimetres.
+If an unknown value is encountered,
+.Ar letter
+is used.
+.El
+.Ss UTF-8 Output
+Use
+.Fl T Cm utf8
+to force text output in UTF-8 multi-byte character encoding,
+ignoring the
+.Xr locale 1
+settings in the environment.
+See
+.Sx ASCII Output
+regarding font styles and
+.Fl O
+arguments.
+.Pp
+On operating systems lacking locale or wide character support, and
+on those where the internal character representation is not UCS-4,
+.Nm
+always falls back to
+.Sx ASCII Output .
+.Ss Syntax tree output
+Use
+.Fl T Cm tree
+to show a human readable representation of the syntax tree.
+It is useful for debugging the source code of manual pages.
+The exact format is subject to change, so don't write parsers for it.
+.Pp
+The first paragraph shows meta data found in the
+.Xr mdoc 7
+prologue, on the
+.Xr man 7
+.Ic \&TH
+line, or the fallbacks used.
+.Pp
+In the tree dump, each output line shows one syntax tree node.
+Child nodes are indented with respect to their parent node.
+The columns are:
+.Pp
+.Bl -enum -compact
+.It
+For macro nodes, the macro name; for text and
+.Xr tbl 7
+nodes, the content.
+There is a special format for
+.Xr eqn 7
+nodes.
+.It
+Node type (text, elem, block, head, body, body-end, tail, tbl, eqn).
+.It
+Flags:
+.Bl -dash -compact
+.It
+An opening parenthesis if the node is an opening delimiter.
+.It
+An asterisk if the node starts a new input line.
+.It
+The input line number (starting at one).
+.It
+A colon.
+.It
+The input column number (starting at one).
+.It
+A closing parenthesis if the node is a closing delimiter.
+.It
+A full stop if the node ends a sentence.
+.It
+BROKEN if the node is a block broken by another block.
+.It
+NOSRC if the node is not in the input file,
+but automatically generated from macros.
+.It
+NOPRT if the node is not supposed to generate output
+for any output format.
+.El
+.El
+.Pp
+The following
+.Fl O
+argument is accepted:
+.Bl -tag -width Ds
+.It Cm noval
+Skip validation and show the unvalidated syntax tree.
+This can help to find out whether a given behaviour is caused by
+the parser or by the validator.
+Meta data is not available in this case.
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width MANPAGER
+.It Ev LC_CTYPE
+The character encoding
+.Xr locale 1 .
+When
+.Sx Locale Output
+is selected, it decides whether to use ASCII or UTF-8 output format.
+It never affects the interpretation of input files.
+.It Ev MANPAGER
+Any non-empty value of the environment variable
+.Ev MANPAGER
+is used instead of the standard pagination program,
+.Xr more 1 ;
+see
+.Xr man 1
+for details.
+Only used if
+.Fl a
+or
+.Fl l
+is specified.
+.It Ev PAGER
+Specifies the pagination program to use when
+.Ev MANPAGER
+is not defined.
+If neither PAGER nor MANPAGER is defined,
+.Xr more 1
+.Fl s
+is used.
+Only used if
+.Fl a
+or
+.Fl l
+is specified.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values, controlled by the message
+.Ar level
+associated with the
+.Fl W
+option:
+.Pp
+.Bl -tag -width Ds -compact
+.It 0
+No base system convention violations, style suggestions, warnings,
+or errors occurred, or those that did were ignored because they
+were lower than the requested
+.Ar level .
+.It 1
+At least one base system convention violation or style suggestion
+occurred, but no warning or error, and
+.Fl W Cm base
+or
+.Fl W Cm style
+was specified.
+.It 2
+At least one warning occurred, but no error, and
+.Fl W Cm warning
+or a lower
+.Ar level
+was requested.
+.It 3
+At least one parsing error occurred,
+but no unsupported feature was encountered, and
+.Fl W Cm error
+or a lower
+.Ar level
+was requested.
+.It 4
+At least one unsupported feature was encountered, and
+.Fl W Cm unsupp
+or a lower
+.Ar level
+was requested.
+.It 5
+Invalid command line arguments were specified.
+No input files have been read.
+.It 6
+An operating system error occurred, for example exhaustion
+of memory, file descriptors, or process table entries.
+Such errors may cause
+.Nm
+to exit at once, possibly in the middle of parsing or formatting a file.
+.El
+.Pp
+Note that selecting
+.Fl T Cm lint
+output mode implies
+.Fl W Cm all .
+.Sh EXAMPLES
+To page manuals to the terminal:
+.Pp
+.Dl $ mandoc -l mandoc.1 man.1 apropos.1 makewhatis.8
+.Pp
+To produce HTML manuals with
+.Pa /usr/share/misc/mandoc.css
+as the style-sheet:
+.Pp
+.Dl $ mandoc \-T html -O style=/usr/share/misc/mandoc.css mdoc.7 > mdoc.7.html
+.Pp
+To check over a large set of manuals:
+.Pp
+.Dl $ mandoc \-T lint \(gafind /usr/src -name \e*\e.[1-9]\(ga
+.Pp
+To produce a series of PostScript manuals for A4 paper:
+.Pp
+.Dl $ mandoc \-T ps \-O paper=a4 mdoc.7 man.7 > manuals.ps
+.Pp
+Convert a modern
+.Xr mdoc 7
+manual to the older
+.Xr man 7
+format, for use on systems lacking an
+.Xr mdoc 7
+parser:
+.Pp
+.Dl $ mandoc \-T man foo.mdoc > foo.man
+.Sh DIAGNOSTICS
+Messages displayed by
+.Nm
+follow this format:
+.Bd -ragged -offset indent
+.Nm :
+.Ar file : Ns Ar line : Ns Ar column : level : message : macro arguments
+.Pq Ar os
+.Ed
+.Pp
+The first three fields identify the
+.Ar file
+name,
+.Ar line
+number, and
+.Ar column
+number of the input file where the message was triggered.
+The line and column numbers start at 1.
+Both are omitted for messages referring to an input file as a whole.
+All
+.Ar level
+and
+.Ar message
+strings are explained below.
+The name of the
+.Ar macro
+triggering the message and its
+.Ar arguments
+are omitted where meaningless.
+The
+.Ar os
+operating system specifier is omitted for messages that are relevant
+for all operating systems.
+Fatal messages about invalid command line arguments
+or operating system errors, for example when memory is exhausted,
+may also omit the
+.Ar file
+and
+.Ar level
+fields.
+.Pp
+Message levels have the following meanings:
+.Bl -tag -width "warning"
+.It Cm syserr
+An operating system error occurred.
+There isn't necessarily anything wrong with the input files.
+Output may all the same be missing or incomplete.
+.It Cm badarg
+Invalid command line arguments were specified.
+No input files have been read and no output is produced.
+.It Cm unsupp
+An input file uses unsupported low-level
+.Xr roff 7
+features.
+The output may be incomplete and/or misformatted,
+so using GNU troff instead of
+.Nm
+to process the file may be preferable.
+.It Cm error
+Indicates a risk of information loss or severe misformatting,
+in most cases caused by serious syntax errors.
+.It Cm warning
+Indicates a risk that the information shown or its formatting
+may mismatch the author's intent in minor ways.
+Additionally, syntax errors are classified at least as warnings,
+even if they do not usually cause misformatting.
+.It Cm style
+An input file uses dubious or discouraged style.
+This is not a complaint about the syntax, and probably neither
+formatting nor portability are in danger.
+While great care is taken to avoid false positives on the higher
+message levels, the
+.Cm style
+level tries to reduce the probability that issues go unnoticed,
+so it may occasionally issue bogus suggestions.
+Please use your good judgement to decide whether any particular
+.Cm style
+suggestion really justifies a change to the input file.
+.It Cm base
+A convention used in the base system of a specific operating system
+is not adhered to.
+These are not markup mistakes, and neither the quality of formatting
+nor portability are in danger.
+Messages of the
+.Cm base
+level are printed with the more intuitive
+.Cm style
+.Ar level
+tag.
+.El
+.Pp
+Messages of the
+.Cm base ,
+.Cm style ,
+.Cm warning ,
+.Cm error ,
+and
+.Cm unsupp
+levels are hidden unless their level, or a lower level, is requested using a
+.Fl W
+option or
+.Fl T Cm lint
+output mode.
+.Pp
+As indicated below, all
+.Cm base
+and some
+.Cm style
+checks are only performed if a specific operating system name occurs
+in the arguments of the
+.Fl W
+command line option, of the
+.Ic \&Os
+macro, of the
+.Fl Ios
+command line option, or, if neither are present, in the return value
+of the
+.Xr uname 3
+function.
+.Ss Conventions for base system manuals
+.Bl -ohang
+.It Sy "Mdocdate found"
+.Pq mdoc , Nx
+The
+.Ic \&Dd
+macro uses CVS
+.Ic Mdocdate
+keyword substitution, which is not supported by the
+.Nx
+base system.
+Consider using the conventional
+.Dq "Month dd, yyyy"
+format instead.
+.It Sy "Mdocdate missing"
+.Pq mdoc , Ox
+The
+.Ic \&Dd
+macro does not use CVS
+.Ic Mdocdate
+keyword substitution, but using it is conventionally expected in the
+.Ox
+base system.
+.It Sy "unknown architecture"
+.Pq mdoc , Ox , Nx
+The third argument of the
+.Ic \&Dt
+macro does not match any of the architectures this operating system
+is running on.
+.It Sy "operating system explicitly specified"
+.Pq mdoc , Ox , Nx
+The
+.Ic \&Os
+macro has an argument.
+In the base system, it is conventionally left blank.
+.It Sy "RCS id missing"
+.Pq Ox , Nx
+The manual page lacks the comment line with the RCS identifier
+generated by CVS
+.Ic OpenBSD
+or
+.Ic NetBSD
+keyword substitution as conventionally used in these operating systems.
+.It Sy "referenced manual not found"
+.Pq mdoc
+An
+.Ic \&Xr
+macro references a manual page that is not found in the base system.
+The path to look for base system manuals is configurable at compile
+time and defaults to
+.Pa /usr/share/man : /usr/X11R6/man .
+.El
+.Ss Style suggestions
+.Bl -ohang
+.It Sy "legacy man(7) date format"
+.Pq mdoc
+The
+.Ic \&Dd
+macro uses the legacy
+.Xr man 7
+date format
+.Dq yyyy-dd-mm .
+Consider using the conventional
+.Xr mdoc 7
+date format
+.Dq "Month dd, yyyy"
+instead.
+.It Sy "normalizing date format to" : No ...
+.Pq mdoc , man
+The
+.Ic \&Dd
+or
+.Ic \&TH
+macro provides an abbreviated month name or a day number with a
+leading zero.
+In the formatted output, the month name is written out in full
+and the leading zero is omitted.
+.It Sy "lower case character in document title"
+.Pq mdoc , man
+The title is still used as given in the
+.Ic \&Dt
+or
+.Ic \&TH
+macro.
+.It Sy "duplicate RCS id"
+A single manual page contains two copies of the RCS identifier for
+the same operating system.
+Consider deleting the later instance and moving the first one up
+to the top of the page.
+.It Sy "possible typo in section name"
+.Pq mdoc
+Fuzzy string matching revealed that the argument of an
+.Ic \&Sh
+macro is similar, but not identical to a standard section name.
+.It Sy "unterminated quoted argument"
+.Pq roff
+Macro arguments can be enclosed in double quote characters
+such that space characters and macro names contained in the quoted
+argument need not be escaped.
+The closing quote of the last argument of a macro can be omitted.
+However, omitting it is not recommended because it makes the code
+harder to read.
+.It Sy "useless macro"
+.Pq mdoc
+A
+.Ic \&Bt ,
+.Ic \&Tn ,
+or
+.Ic \&Ud
+macro was found.
+Simply delete it: it serves no useful purpose.
+.It Sy "consider using OS macro"
+.Pq mdoc
+A string was found in plain text or in a
+.Ic \&Bx
+macro that could be represented using
+.Ic \&Ox ,
+.Ic \&Nx ,
+.Ic \&Fx ,
+or
+.Ic \&Dx .
+.It Sy "errnos out of order"
+.Pq mdoc, Nx
+The
+.Ic \&Er
+items in a
+.Ic \&Bl
+list are not in alphabetical order.
+.It Sy "duplicate errno"
+.Pq mdoc, Nx
+A
+.Ic \&Bl
+list contains two consecutive
+.Ic \&It
+entries describing the same
+.Ic \&Er
+number.
+.It Sy "trailing delimiter"
+.Pq mdoc
+The last argument of an
+.Ic \&Ex , \&Fo , \&Nd , \&Nm , \&Os , \&Sh , \&Ss , \&St ,
+or
+.Ic \&Sx
+macro ends with a trailing delimiter.
+This is usually bad style and often indicates typos.
+Most likely, the delimiter can be removed.
+.It Sy "no blank before trailing delimiter"
+.Pq mdoc
+The last argument of a macro that supports trailing delimiter
+arguments is longer than one byte and ends with a trailing delimiter.
+Consider inserting a blank such that the delimiter becomes a separate
+argument, thus moving it out of the scope of the macro.
+.It Sy "fill mode already enabled, skipping"
+.Pq man
+A
+.Ic \&fi
+request occurs even though the document is still in fill mode,
+or already switched back to fill mode.
+It has no effect.
+.It Sy "fill mode already disabled, skipping"
+.Pq man
+An
+.Ic \&nf
+request occurs even though the document already switched to no-fill mode
+and did not switch back to fill mode yet.
+It has no effect.
+.It Sy "verbatim \(dq--\(dq, maybe consider using \e(em"
+.Pq mdoc
+Even though the ASCII output device renders an em-dash as
+.Qq \-\- ,
+that is not a good way to write it in an input file
+because it renders poorly on all other output devices.
+.It Sy "function name without markup"
+.Pq mdoc
+A word followed by an empty pair of parentheses occurs on a text line.
+Consider using an
+.Ic \&Fn
+or
+.Ic \&Xr
+macro.
+.It Sy "whitespace at end of input line"
+.Pq mdoc , man , roff
+Whitespace at the end of input lines is almost never semantically
+significant \(em but in the odd case where it might be, it is
+extremely confusing when reviewing and maintaining documents.
+.It Sy "bad comment style"
+.Pq roff
+Comment lines start with a dot, a backslash, and a double-quote character.
+The
+.Nm
+utility treats the line as a comment line even without the backslash,
+but leaving out the backslash might not be portable.
+.El
+.Ss Warnings related to the document prologue
+.Bl -ohang
+.It Sy "missing manual title, using UNTITLED"
+.Pq mdoc
+A
+.Ic \&Dt
+macro has no arguments, or there is no
+.Ic \&Dt
+macro before the first non-prologue macro.
+.It Sy "missing manual title, using \(dq\(dq"
+.Pq man
+There is no
+.Ic \&TH
+macro, or it has no arguments.
+.It Sy "missing manual section, using \(dq\(dq"
+.Pq mdoc , man
+A
+.Ic \&Dt
+or
+.Ic \&TH
+macro lacks the mandatory section argument.
+.It Sy "unknown manual section"
+.Pq mdoc
+The section number in a
+.Ic \&Dt
+line is invalid, but still used.
+.It Sy "missing date, using today's date"
+.Pq mdoc, man
+The document was parsed as
+.Xr mdoc 7
+and it has no
+.Ic \&Dd
+macro, or the
+.Ic \&Dd
+macro has no arguments or only empty arguments;
+or the document was parsed as
+.Xr man 7
+and it has no
+.Ic \&TH
+macro, or the
+.Ic \&TH
+macro has less than three arguments or its third argument is empty.
+.It Sy "cannot parse date, using it verbatim"
+.Pq mdoc , man
+The date given in a
+.Ic \&Dd
+or
+.Ic \&TH
+macro does not follow the conventional format.
+.It Sy "date in the future, using it anyway"
+.Pq mdoc , man
+The date given in a
+.Ic \&Dd
+or
+.Ic \&TH
+macro is more than a day ahead of the current system
+.Xr time 3 .
+.It Sy "missing Os macro, using \(dq\(dq"
+.Pq mdoc
+The default or current system is not shown in this case.
+.It Sy "late prologue macro"
+.Pq mdoc
+A
+.Ic \&Dd
+or
+.Ic \&Os
+macro occurs after some non-prologue macro, but still takes effect.
+.It Sy "prologue macros out of order"
+.Pq mdoc
+The prologue macros are not given in the conventional order
+.Ic \&Dd ,
+.Ic \&Dt ,
+.Ic \&Os .
+All three macros are used even when given in another order.
+.El
+.Ss Warnings regarding document structure
+.Bl -ohang
+.It Sy ".so is fragile, better use ln(1)"
+.Pq roff
+Including files only works when the parser program runs with the correct
+current working directory.
+.It Sy "no document body"
+.Pq mdoc , man
+The document body contains neither text nor macros.
+An empty document is shown, consisting only of a header and a footer line.
+.It Sy "content before first section header"
+.Pq mdoc , man
+Some macros or text precede the first
+.Ic \&Sh
+or
+.Ic \&SH
+section header.
+The offending macros and text are parsed and added to the top level
+of the syntax tree, outside any section block.
+.It Sy "first section is not NAME"
+.Pq mdoc
+The argument of the first
+.Ic \&Sh
+macro is not
+.Sq NAME .
+This may confuse
+.Xr makewhatis 8
+and
+.Xr apropos 1 .
+.It Sy "NAME section without Nm before Nd"
+.Pq mdoc
+The NAME section does not contain any
+.Ic \&Nm
+child macro before the first
+.Ic \&Nd
+macro.
+.It Sy "NAME section without description"
+.Pq mdoc
+The NAME section lacks the mandatory
+.Ic \&Nd
+child macro.
+.It Sy "description not at the end of NAME"
+.Pq mdoc
+The NAME section does contain an
+.Ic \&Nd
+child macro, but other content follows it.
+.It Sy "bad NAME section content"
+.Pq mdoc
+The NAME section contains plain text or macros other than
+.Ic \&Nm
+and
+.Ic \&Nd .
+.It Sy "missing comma before name"
+.Pq mdoc
+The NAME section contains an
+.Ic \&Nm
+macro that is neither the first one nor preceded by a comma.
+.It Sy "missing description line, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Nd
+macro lacks the required argument.
+The title line of the manual will end after the dash.
+.It Sy "description line outside NAME section"
+.Pq mdoc
+An
+.Ic \&Nd
+macro appears outside the NAME section.
+The arguments are printed anyway and the following text is used for
+.Xr apropos 1 ,
+but none of that behaviour is portable.
+.It Sy "sections out of conventional order"
+.Pq mdoc
+A standard section occurs after another section it usually precedes.
+All section titles are used as given,
+and the order of sections is not changed.
+.It Sy "duplicate section title"
+.Pq mdoc
+The same standard section title occurs more than once.
+.It Sy "unexpected section"
+.Pq mdoc
+A standard section header occurs in a section of the manual
+where it normally isn't useful.
+.It Sy "cross reference to self"
+.Pq mdoc
+An
+.Ic \&Xr
+macro refers to a name and section matching the section of the present
+manual page and a name mentioned in an
+.Ic \&Nm
+macro in the NAME or SYNOPSIS section, or in an
+.Ic \&Fn
+or
+.Ic \&Fo
+macro in the SYNOPSIS.
+Consider using
+.Ic \&Nm
+or
+.Ic \&Fn
+instead of
+.Ic \&Xr .
+.It Sy "unusual Xr order"
+.Pq mdoc
+In the SEE ALSO section, an
+.Ic \&Xr
+macro with a lower section number follows one with a higher number,
+or two
+.Ic \&Xr
+macros referring to the same section are out of alphabetical order.
+.It Sy "unusual Xr punctuation"
+.Pq mdoc
+In the SEE ALSO section, punctuation between two
+.Ic \&Xr
+macros differs from a single comma, or there is trailing punctuation
+after the last
+.Ic \&Xr
+macro.
+.It Sy "AUTHORS section without An macro"
+.Pq mdoc
+An AUTHORS sections contains no
+.Ic \&An
+macros, or only empty ones.
+Probably, there are author names lacking markup.
+.El
+.Ss "Warnings related to macros and nesting"
+.Bl -ohang
+.It Sy "obsolete macro"
+.Pq mdoc
+See the
+.Xr mdoc 7
+manual for replacements.
+.It Sy "macro neither callable nor escaped"
+.Pq mdoc
+The name of a macro that is not callable appears on a macro line.
+It is printed verbatim.
+If the intention is to call it, move it to its own input line;
+otherwise, escape it by prepending
+.Sq \e& .
+.It Sy "skipping paragraph macro"
+In
+.Xr mdoc 7
+documents, this happens
+.Bl -dash -compact
+.It
+at the beginning and end of sections and subsections
+.It
+right before non-compact lists and displays
+.It
+at the end of items in non-column, non-compact lists
+.It
+and for multiple consecutive paragraph macros.
+.El
+In
+.Xr man 7
+documents, it happens
+.Bl -dash -compact
+.It
+for empty
+.Ic \&P ,
+.Ic \&PP ,
+and
+.Ic \&LP
+macros
+.It
+for
+.Ic \&IP
+macros having neither head nor body arguments
+.It
+for
+.Ic \&br
+or
+.Ic \&sp
+right after
+.Ic \&SH
+or
+.Ic \&SS
+.El
+.It Sy "moving paragraph macro out of list"
+.Pq mdoc
+A list item in a
+.Ic \&Bl
+list contains a trailing paragraph macro.
+The paragraph macro is moved after the end of the list.
+.It Sy "skipping no-space macro"
+.Pq mdoc
+An input line begins with an
+.Ic \&Ns
+macro, or the next argument after an
+.Ic \&Ns
+macro is an isolated closing delimiter.
+The macro is ignored.
+.It Sy "blocks badly nested"
+.Pq mdoc
+If two blocks intersect, one should completely contain the other.
+Otherwise, rendered output is likely to look strange in any output
+format, and rendering in SGML-based output formats is likely to be
+outright wrong because such languages do not support badly nested
+blocks at all.
+Typical examples of badly nested blocks are
+.Qq Ic \&Ao \&Bo \&Ac \&Bc
+and
+.Qq Ic \&Ao \&Bq \&Ac .
+In these examples,
+.Ic \&Ac
+breaks
+.Ic \&Bo
+and
+.Ic \&Bq ,
+respectively.
+.It Sy "nested displays are not portable"
+.Pq mdoc
+A
+.Ic \&Bd ,
+.Ic \&D1 ,
+or
+.Ic \&Dl
+display occurs nested inside another
+.Ic \&Bd
+display.
+This works with
+.Nm ,
+but fails with most other implementations.
+.It Sy "moving content out of list"
+.Pq mdoc
+A
+.Ic \&Bl
+list block contains text or macros before the first
+.Ic \&It
+macro.
+The offending children are moved before the beginning of the list.
+.It Sy "first macro on line"
+Inside a
+.Ic \&Bl Fl column
+list, a
+.Ic \&Ta
+macro occurs as the first macro on a line, which is not portable.
+.It Sy "line scope broken"
+.Pq man
+While parsing the next-line scope of the previous macro,
+another macro is found that prematurely terminates the previous one.
+The previous, interrupted macro is deleted from the parse tree.
+.El
+.Ss "Warnings related to missing arguments"
+.Bl -ohang
+.It Sy "skipping empty request"
+.Pq roff , eqn
+The macro name is missing from a macro definition request,
+or an
+.Xr eqn 7
+control statement or operation keyword lacks its required argument.
+.It Sy "conditional request controls empty scope"
+.Pq roff
+A conditional request is only useful if any of the following
+follows it on the same logical input line:
+.Bl -dash -compact
+.It
+The
+.Sq \e{
+keyword to open a multi-line scope.
+.It
+A request or macro or some text, resulting in a single-line scope.
+.It
+The immediate end of the logical line without any intervening whitespace,
+resulting in next-line scope.
+.El
+Here, a conditional request is followed by trailing whitespace only,
+and there is no other content on its logical input line.
+Note that it doesn't matter whether the logical input line is split
+across multiple physical input lines using
+.Sq \e
+line continuation characters.
+This is one of the rare cases
+where trailing whitespace is syntactically significant.
+The conditional request controls a scope containing whitespace only,
+so it is unlikely to have a significant effect,
+except that it may control a following
+.Ic \&el
+clause.
+.It Sy "skipping empty macro"
+.Pq mdoc
+The indicated macro has no arguments and hence no effect.
+.It Sy "empty block"
+.Pq mdoc , man
+A
+.Ic \&Bd ,
+.Ic \&Bk ,
+.Ic \&Bl ,
+.Ic \&D1 ,
+.Ic \&Dl ,
+.Ic \&MT ,
+.Ic \&RS ,
+or
+.Ic \&UR
+block contains nothing in its body and will produce no output.
+.It Sy "empty argument, using 0n"
+.Pq mdoc
+The required width is missing after
+.Ic \&Bd
+or
+.Ic \&Bl
+.Fl offset
+or
+.Fl width .
+.It Sy "missing display type, using -ragged"
+.Pq mdoc
+The
+.Ic \&Bd
+macro is invoked without the required display type.
+.It Sy "list type is not the first argument"
+.Pq mdoc
+In a
+.Ic \&Bl
+macro, at least one other argument precedes the type argument.
+The
+.Nm
+utility copes with any argument order, but some other
+.Xr mdoc 7
+implementations do not.
+.It Sy "missing -width in -tag list, using 8n"
+.Pq mdoc
+Every
+.Ic \&Bl
+macro having the
+.Fl tag
+argument requires
+.Fl width ,
+too.
+.It Sy "missing utility name, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Ex Fl std
+macro is called without an argument before
+.Ic \&Nm
+has first been called with an argument.
+.It Sy "missing function name, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Fo
+macro is called without an argument.
+No function name is printed.
+.It Sy "empty head in list item"
+.Pq mdoc
+In a
+.Ic \&Bl
+.Fl diag ,
+.Fl hang ,
+.Fl inset ,
+.Fl ohang ,
+or
+.Fl tag
+list, an
+.Ic \&It
+macro lacks the required argument.
+The item head is left empty.
+.It Sy "empty list item"
+.Pq mdoc
+In a
+.Ic \&Bl
+.Fl bullet ,
+.Fl dash ,
+.Fl enum ,
+or
+.Fl hyphen
+list, an
+.Ic \&It
+block is empty.
+An empty list item is shown.
+.It Sy "missing argument, using next line"
+.Pq mdoc
+An
+.Ic \&It
+macro in a
+.Ic \&Bd Fl column
+list has no arguments.
+While
+.Nm
+uses the text or macros of the following line, if any, for the cell,
+other formatters may misformat the list.
+.It Sy "missing font type, using \efR"
+.Pq mdoc
+A
+.Ic \&Bf
+macro has no argument.
+It switches to the default font.
+.It Sy "unknown font type, using \efR"
+.Pq mdoc
+The
+.Ic \&Bf
+argument is invalid.
+The default font is used instead.
+.It Sy "nothing follows prefix"
+.Pq mdoc
+A
+.Ic \&Pf
+macro has no argument, or only one argument and no macro follows
+on the same input line.
+This defeats its purpose; in particular, spacing is not suppressed
+before the text or macros following on the next input line.
+.It Sy "empty reference block"
+.Pq mdoc
+An
+.Ic \&Rs
+macro is immediately followed by an
+.Ic \&Re
+macro on the next input line.
+Such an empty block does not produce any output.
+.It Sy "missing section argument"
+.Pq mdoc
+An
+.Ic \&Xr
+macro lacks its second, section number argument.
+The first argument, i.e. the name, is printed, but without subsequent
+parentheses.
+.It Sy "missing -std argument, adding it"
+.Pq mdoc
+An
+.Ic \&Ex
+or
+.Ic \&Rv
+macro lacks the required
+.Fl std
+argument.
+The
+.Nm
+utility assumes
+.Fl std
+even when it is not specified, but other implementations may not.
+.It Sy "missing option string, using \(dq\(dq"
+.Pq man
+The
+.Ic \&OP
+macro is invoked without any argument.
+An empty pair of square brackets is shown.
+.It Sy "missing resource identifier, using \(dq\(dq"
+.Pq man
+The
+.Ic \&MT
+or
+.Ic \&UR
+macro is invoked without any argument.
+An empty pair of angle brackets is shown.
+.It Sy "missing eqn box, using \(dq\(dq"
+.Pq eqn
+A diacritic mark or a binary operator is found,
+but there is nothing to the left of it.
+An empty box is inserted.
+.El
+.Ss "Warnings related to bad macro arguments"
+.Bl -ohang
+.It Sy "duplicate argument"
+.Pq mdoc
+A
+.Ic \&Bd
+or
+.Ic \&Bl
+macro has more than one
+.Fl compact ,
+more than one
+.Fl offset ,
+or more than one
+.Fl width
+argument.
+All but the last instances of these arguments are ignored.
+.It Sy "skipping duplicate argument"
+.Pq mdoc
+An
+.Ic \&An
+macro has more than one
+.Fl split
+or
+.Fl nosplit
+argument.
+All but the first of these arguments are ignored.
+.It Sy "skipping duplicate display type"
+.Pq mdoc
+A
+.Ic \&Bd
+macro has more than one type argument; the first one is used.
+.It Sy "skipping duplicate list type"
+.Pq mdoc
+A
+.Ic \&Bl
+macro has more than one type argument; the first one is used.
+.It Sy "skipping -width argument"
+.Pq mdoc
+A
+.Ic \&Bl
+.Fl column ,
+.Fl diag ,
+.Fl ohang ,
+.Fl inset ,
+or
+.Fl item
+list has a
+.Fl width
+argument.
+That has no effect.
+.It Sy "wrong number of cells"
+In a line of a
+.Ic \&Bl Fl column
+list, the number of tabs or
+.Ic \&Ta
+macros is less than the number expected from the list header line
+or exceeds the expected number by more than one.
+Missing cells remain empty, and all cells exceeding the number of
+columns are joined into one single cell.
+.It Sy "unknown AT&T UNIX version"
+.Pq mdoc
+An
+.Ic \&At
+macro has an invalid argument.
+It is used verbatim, with
+.Qq "AT&T UNIX "
+prefixed to it.
+.It Sy "comma in function argument"
+.Pq mdoc
+An argument of an
+.Ic \&Fa
+or
+.Ic \&Fn
+macro contains a comma; it should probably be split into two arguments.
+.It Sy "parenthesis in function name"
+.Pq mdoc
+The first argument of an
+.Ic \&Fc
+or
+.Ic \&Fn
+macro contains an opening or closing parenthesis; that's probably wrong,
+parentheses are added automatically.
+.It Sy "unknown library name"
+.Pq mdoc, not on Ox
+An
+.Ic \&Lb
+macro has an unknown name argument and will be rendered as
+.Qq library Dq Ar name .
+.It Sy "invalid content in Rs block"
+.Pq mdoc
+An
+.Ic \&Rs
+block contains plain text or non-% macros.
+The bogus content is left in the syntax tree.
+Formatting may be poor.
+.It Sy "invalid Boolean argument"
+.Pq mdoc
+An
+.Ic \&Sm
+macro has an argument other than
+.Cm on
+or
+.Cm off .
+The invalid argument is moved out of the macro, which leaves the macro
+empty, causing it to toggle the spacing mode.
+.It Sy "argument contains two font escapes"
+.Pq roff
+The second argument of a
+.Ic char
+request contains more than one font escape sequence.
+A wrong font may remain active after using the character.
+.It Sy "unknown font, skipping request"
+.Pq man , tbl
+A
+.Xr roff 7
+.Ic \&ft
+request or a
+.Xr tbl 7
+.Ic \&f
+layout modifier has an unknown
+.Ar font
+argument.
+.It Sy "odd number of characters in request"
+.Pq roff
+A
+.Ic \&tr
+request contains an odd number of characters.
+The last character is mapped to the blank character.
+.El
+.Ss "Warnings related to plain text"
+.Bl -ohang
+.It Sy "blank line in fill mode, using .sp"
+.Pq mdoc
+The meaning of blank input lines is only well-defined in non-fill mode:
+In fill mode, line breaks of text input lines are not supposed to be
+significant.
+However, for compatibility with groff, blank lines in fill mode
+are formatted like
+.Ic \&sp
+requests.
+To request a paragraph break, use
+.Ic \&Pp
+instead of a blank line.
+.It Sy "tab in filled text"
+.Pq mdoc , man
+The meaning of tab characters is only well-defined in non-fill mode:
+In fill mode, whitespace is not supposed to be significant
+on text input lines.
+As an implementation dependent choice, tab characters on text lines
+are passed through to the formatters in any case.
+Given that the text before the tab character will be filled,
+it is hard to predict which tab stop position the tab will advance to.
+.It Sy "new sentence, new line"
+.Pq mdoc
+A new sentence starts in the middle of a text line.
+Start it on a new input line to help formatters produce correct spacing.
+.It Sy "invalid escape sequence"
+.Pq roff
+An escape sequence has an invalid opening argument delimiter, lacks the
+closing argument delimiter, the argument is of an invalid form, or it is
+a character escape sequence with an invalid name.
+If the argument is incomplete,
+.Ic \e*
+and
+.Ic \en
+expand to an empty string,
+.Ic \eB
+to the digit
+.Sq 0 ,
+and
+.Ic \ew
+to the length of the incomplete argument.
+All other invalid escape sequences are ignored.
+.It Sy "undefined escape, printing literally"
+.Pq roff
+In an escape sequence, the first character
+right after the leading backslash is invalid.
+That character is printed literally,
+which is equivalent to ignoring the backslash.
+.It Sy "undefined string, using \(dq\(dq"
+.Pq roff
+If a string is used without being defined before,
+its value is implicitly set to the empty string.
+However, defining strings explicitly before use
+keeps the code more readable.
+.El
+.Ss "Warnings related to tables"
+.Bl -ohang
+.It Sy "tbl line starts with span"
+.Pq tbl
+The first cell in a table layout line is a horizontal span
+.Pq Sq Cm s .
+Data provided for this cell is ignored, and nothing is printed in the cell.
+.It Sy "tbl column starts with span"
+.Pq tbl
+The first line of a table layout specification
+requests a vertical span
+.Pq Sq Cm ^ .
+Data provided for this cell is ignored, and nothing is printed in the cell.
+.It Sy "skipping vertical bar in tbl layout"
+.Pq tbl
+A table layout specification contains more than two consecutive vertical bars.
+A double bar is printed, all additional bars are discarded.
+.El
+.Ss "Errors related to tables"
+.Bl -ohang
+.It Sy "non-alphabetic character in tbl options"
+.Pq tbl
+The table options line contains a character other than a letter,
+blank, or comma where the beginning of an option name is expected.
+The character is ignored.
+.It Sy "skipping unknown tbl option"
+.Pq tbl
+The table options line contains a string of letters that does not
+match any known option name.
+The word is ignored.
+.It Sy "missing tbl option argument"
+.Pq tbl
+A table option that requires an argument is not followed by an
+opening parenthesis, or the opening parenthesis is immediately
+followed by a closing parenthesis.
+The option is ignored.
+.It Sy "wrong tbl option argument size"
+.Pq tbl
+A table option argument contains an invalid number of characters.
+Both the option and the argument are ignored.
+.It Sy "empty tbl layout"
+.Pq tbl
+A table layout specification is completely empty,
+specifying zero lines and zero columns.
+As a fallback, a single left-justified column is used.
+.It Sy "invalid character in tbl layout"
+.Pq tbl
+A table layout specification contains a character that can neither
+be interpreted as a layout key character nor as a layout modifier,
+or a modifier precedes the first key.
+The invalid character is discarded.
+.It Sy "unmatched parenthesis in tbl layout"
+.Pq tbl
+A table layout specification contains an opening parenthesis,
+but no matching closing parenthesis.
+The rest of the input line, starting from the parenthesis, has no effect.
+.It Sy "tbl without any data cells"
+.Pq tbl
+A table does not contain any data cells.
+It will probably produce no output.
+.It Sy "ignoring data in spanned tbl cell"
+.Pq tbl
+A table cell is marked as a horizontal span
+.Pq Sq Cm s
+or vertical span
+.Pq Sq Cm ^
+in the table layout, but it contains data.
+The data is ignored.
+.It Sy "ignoring extra tbl data cells"
+.Pq tbl
+A data line contains more cells than the corresponding layout line.
+The data in the extra cells is ignored.
+.It Sy "data block open at end of tbl"
+.Pq tbl
+A data block is opened with
+.Cm T{ ,
+but never closed with a matching
+.Cm T} .
+The remaining data lines of the table are all put into one cell,
+and any remaining cells stay empty.
+.El
+.Ss "Errors related to roff, mdoc, and man code"
+.Bl -ohang
+.It Sy "duplicate prologue macro"
+.Pq mdoc
+One of the prologue macros occurs more than once.
+The last instance overrides all previous ones.
+.It Sy "skipping late title macro"
+.Pq mdoc
+The
+.Ic \&Dt
+macro appears after the first non-prologue macro.
+Traditional formatters cannot handle this because
+they write the page header before parsing the document body.
+Even though this technical restriction does not apply to
+.Nm ,
+traditional semantics is preserved.
+The late macro is discarded including its arguments.
+.It Sy "input stack limit exceeded, infinite loop?"
+.Pq roff
+Explicit recursion limits are implemented for the following features,
+in order to prevent infinite loops:
+.Bl -dash -compact
+.It
+expansion of nested escape sequences
+including expansion of strings and number registers,
+.It
+expansion of nested user-defined macros,
+.It
+and
+.Ic \&so
+file inclusion.
+.El
+When a limit is hit, the output is incorrect, typically losing
+some content, but the parser can continue.
+.It Sy "skipping bad character"
+.Pq mdoc , man , roff
+The input file contains a byte that is not a printable
+.Xr ascii 7
+character.
+The message mentions the character number.
+The offending byte is replaced with a question mark
+.Pq Sq \&? .
+Consider editing the input file to replace the byte with an ASCII
+transliteration of the intended character.
+.It Sy "skipping unknown macro"
+.Pq mdoc , man , roff
+The first identifier on a request or macro line is neither recognized as a
+.Xr roff 7
+request, nor as a user-defined macro, nor, respectively, as an
+.Xr mdoc 7
+or
+.Xr man 7
+macro.
+It may be mistyped or unsupported.
+The request or macro is discarded including its arguments.
+.It Sy "skipping request outside macro"
+.Pq roff
+A
+.Ic shift
+or
+.Ic return
+request occurs outside any macro definition and has no effect.
+.It Sy "skipping insecure request"
+.Pq roff
+An input file attempted to run a shell command
+or to read or write an external file.
+Such attempts are denied for security reasons.
+.It Sy "skipping item outside list"
+.Pq mdoc , eqn
+An
+.Ic \&It
+macro occurs outside any
+.Ic \&Bl
+list, or an
+.Xr eqn 7
+.Ic above
+delimiter occurs outside any pile.
+It is discarded including its arguments.
+.It Sy "skipping column outside column list"
+.Pq mdoc
+A
+.Ic \&Ta
+macro occurs outside any
+.Ic \&Bl Fl column
+block.
+It is discarded including its arguments.
+.It Sy "skipping end of block that is not open"
+.Pq mdoc , man , eqn , tbl , roff
+Various syntax elements can only be used to explicitly close blocks
+that have previously been opened.
+An
+.Xr mdoc 7
+block closing macro, a
+.Xr man 7
+.Ic \&ME , \&RE
+or
+.Ic \&UE
+macro, an
+.Xr eqn 7
+right delimiter or closing brace, or the end of an equation, table, or
+.Xr roff 7
+conditional request is encountered but no matching block is open.
+The offending request or macro is discarded.
+.It Sy "fewer RS blocks open, skipping"
+.Pq man
+The
+.Ic \&RE
+macro is invoked with an argument, but less than the specified number of
+.Ic \&RS
+blocks is open.
+The
+.Ic \&RE
+macro is discarded.
+.It Sy "inserting missing end of block"
+.Pq mdoc , tbl
+Various
+.Xr mdoc 7
+macros as well as tables require explicit closing by dedicated macros.
+A block that doesn't support bad nesting
+ends before all of its children are properly closed.
+The open child nodes are closed implicitly.
+.It Sy "appending missing end of block"
+.Pq mdoc , man , eqn , tbl , roff
+At the end of the document, an explicit
+.Xr mdoc 7
+block, a
+.Xr man 7
+next-line scope or
+.Ic \&MT , \&RS
+or
+.Ic \&UR
+block, an equation, table, or
+.Xr roff 7
+conditional or ignore block is still open.
+The open block is closed implicitly.
+.It Sy "escaped character not allowed in a name"
+.Pq roff
+Macro, string and register identifiers consist of printable,
+non-whitespace ASCII characters.
+Escape sequences and characters and strings expressed in terms of them
+cannot form part of a name.
+The first argument of an
+.Ic \&am ,
+.Ic \&as ,
+.Ic \&de ,
+.Ic \&ds ,
+.Ic \&nr ,
+or
+.Ic \&rr
+request, or any argument of an
+.Ic \&rm
+request, or the name of a request or user defined macro being called,
+is terminated by an escape sequence.
+In the cases of
+.Ic \&as ,
+.Ic \&ds ,
+and
+.Ic \&nr ,
+the request has no effect at all.
+In the cases of
+.Ic \&am ,
+.Ic \&de ,
+.Ic \&rr ,
+and
+.Ic \&rm ,
+what was parsed up to this point is used as the arguments to the request,
+and the rest of the input line is discarded including the escape sequence.
+When parsing for a request or a user-defined macro name to be called,
+only the escape sequence is discarded.
+The characters preceding it are used as the request or macro name,
+the characters following it are used as the arguments to the request or macro.
+.It Sy "using macro argument outside macro"
+.Pq roff
+The escape sequence \e$ occurs outside any macro definition
+and expands to the empty string.
+.It Sy "argument number is not numeric"
+.Pq roff
+The argument of the escape sequence \e$ is not a digit;
+the escape sequence expands to the empty string.
+.It Sy "NOT IMPLEMENTED: Bd -file"
+.Pq mdoc
+For security reasons, the
+.Ic \&Bd
+macro does not support the
+.Fl file
+argument.
+By requesting the inclusion of a sensitive file, a malicious document
+might otherwise trick a privileged user into inadvertently displaying
+the file on the screen, revealing the file content to bystanders.
+The argument is ignored including the file name following it.
+.It Sy "skipping display without arguments"
+.Pq mdoc
+A
+.Ic \&Bd
+block macro does not have any arguments.
+The block is discarded, and the block content is displayed in
+whatever mode was active before the block.
+.It Sy "missing list type, using -item"
+.Pq mdoc
+A
+.Ic \&Bl
+macro fails to specify the list type.
+.It Sy "argument is not numeric, using 1"
+.Pq roff
+The argument of a
+.Ic \&ce
+request is not a number.
+.It Sy "argument is not a character"
+.Pq roff
+The first argument of a
+.Ic char
+request is neither a single ASCII character
+nor a single character escape sequence.
+The request is ignored including all its arguments.
+.It Sy "missing manual name, using \(dq\(dq"
+.Pq mdoc
+The first call to
+.Ic \&Nm ,
+or any call in the NAME section, lacks the required argument.
+.It Sy "uname(3) system call failed, using UNKNOWN"
+.Pq mdoc
+The
+.Ic \&Os
+macro is called without arguments, and the
+.Xr uname 3
+system call failed.
+As a workaround,
+.Nm
+can be compiled with
+.Sm off
+.Fl D Cm OSNAME=\(dq\e\(dq Ar string Cm \e\(dq\(dq .
+.Sm on
+.It Sy "unknown standard specifier"
+.Pq mdoc
+An
+.Ic \&St
+macro has an unknown argument and is discarded.
+.It Sy "skipping request without numeric argument"
+.Pq roff , eqn
+An
+.Ic \&it
+request or an
+.Xr eqn 7
+.Ic \&size
+or
+.Ic \&gsize
+statement has a non-numeric or negative argument or no argument at all.
+The invalid request or statement is ignored.
+.It Sy "excessive shift"
+.Pq roff
+The argument of a
+.Ic shift
+request is larger than the number of arguments of the macro that is
+currently being executed.
+All macro arguments are deleted and \en(.$ is set to zero.
+.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq"
+.Pq roff
+For security reasons,
+.Nm
+allows
+.Ic \&so
+file inclusion requests only with relative paths
+and only without ascending to any parent directory.
+By requesting the inclusion of a sensitive file, a malicious document
+might otherwise trick a privileged user into inadvertently displaying
+the file on the screen, revealing the file content to bystanders.
+.Nm
+only shows the path as it appears behind
+.Ic \&so .
+.It Sy ".so request failed"
+.Pq roff
+Servicing a
+.Ic \&so
+request requires reading an external file, but the file could not be
+opened.
+.Nm
+only shows the path as it appears behind
+.Ic \&so .
+.It Sy "skipping all arguments"
+.Pq mdoc , man , eqn , roff
+An
+.Xr mdoc 7
+.Ic \&Bt ,
+.Ic \&Ed ,
+.Ic \&Ef ,
+.Ic \&Ek ,
+.Ic \&El ,
+.Ic \&Lp ,
+.Ic \&Pp ,
+.Ic \&Re ,
+.Ic \&Rs ,
+or
+.Ic \&Ud
+macro, an
+.Ic \&It
+macro in a list that don't support item heads, a
+.Xr man 7
+.Ic \&LP ,
+.Ic \&P ,
+or
+.Ic \&PP
+macro, an
+.Xr eqn 7
+.Ic \&EQ
+or
+.Ic \&EN
+macro, or a
+.Xr roff 7
+.Ic \&br ,
+.Ic \&fi ,
+or
+.Ic \&nf
+request or
+.Sq \&..
+block closing request is invoked with at least one argument.
+All arguments are ignored.
+.It Sy "skipping excess arguments"
+.Pq mdoc , man , roff
+A macro or request is invoked with too many arguments:
+.Bl -dash -offset 2n -width 2n -compact
+.It
+.Ic \&Fo ,
+.Ic \&MT ,
+.Ic \&PD ,
+.Ic \&RS ,
+.Ic \&UR ,
+.Ic \&ft ,
+or
+.Ic \&sp
+with more than one argument
+.It
+.Ic \&An
+with another argument after
+.Fl split
+or
+.Fl nosplit
+.It
+.Ic \&RE
+with more than one argument or with a non-integer argument
+.It
+.Ic \&OP
+or a request of the
+.Ic \&de
+family with more than two arguments
+.It
+.Ic \&Dt
+with more than three arguments
+.It
+.Ic \&TH
+with more than five arguments
+.It
+.Ic \&Bd ,
+.Ic \&Bk ,
+or
+.Ic \&Bl
+with invalid arguments
+.El
+The excess arguments are ignored.
+.El
+.Ss Unsupported features
+.Bl -ohang
+.It Sy "input too large"
+.Pq mdoc , man
+Currently,
+.Nm
+cannot handle input files larger than its arbitrary size limit
+of 2^31 bytes (2 Gigabytes).
+Since useful manuals are always small, this is not a problem in practice.
+Parsing is aborted as soon as the condition is detected.
+.It Sy "unsupported control character"
+.Pq roff
+An ASCII control character supported by other
+.Xr roff 7
+implementations but not by
+.Nm
+was found in an input file.
+It is replaced by a question mark.
+.It Sy "unsupported escape sequence"
+.Pq roff
+An input file contains an escape sequence supported by GNU troff
+or Heirloom troff but not by
+.Nm ,
+and it is likely that this will cause information loss
+or considerable misformatting.
+.It Sy "unsupported roff request"
+.Pq roff
+An input file contains a
+.Xr roff 7
+request supported by GNU troff or Heirloom troff but not by
+.Nm ,
+and it is likely that this will cause information loss
+or considerable misformatting.
+.It Sy "eqn delim option in tbl"
+.Pq eqn , tbl
+The options line of a table defines equation delimiters.
+Any equation source code contained in the table will be printed unformatted.
+.It Sy "unsupported table layout modifier"
+.Pq tbl
+A table layout specification contains an
+.Sq Cm m
+modifier.
+The modifier is discarded.
+.It Sy "ignoring macro in table"
+.Pq tbl , mdoc , man
+A table contains an invocation of an
+.Xr mdoc 7
+or
+.Xr man 7
+macro or of an undefined macro.
+The macro is ignored, and its arguments are handled
+as if they were a text line.
+.El
+.Ss Bad command line arguments
+.Bl -ohang
+.It Sy "bad command line argument"
+The argument following one of the
+.Fl IKMmOTW
+command line options is invalid, or a
+.Ar file
+given as a command line argument cannot be opened.
+.It Sy "duplicate command line argument"
+The
+.Fl I
+command line option was specified twice.
+.It Sy "option has a superfluous value"
+An argument to the
+.Fl O
+option has a value but does not accept one.
+.It Sy "missing option value"
+An argument to the
+.Fl O
+option has no argument but requires one.
+.It Sy "bad option value"
+An argument to the
+.Fl O
+.Cm indent
+or
+.Cm width
+option has an invalid value.
+.It Sy "duplicate option value"
+The same
+.Fl O
+option is specified more than once.
+.It Sy "no such tag"
+The
+.Fl O Cm tag
+option was specified but the tag was not found in any of the displayed
+manual pages.
+.El
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr man 1 ,
+.Xr eqn 7 ,
+.Xr man 7 ,
+.Xr mandoc_char 7 ,
+.Xr mdoc 7 ,
+.Xr roff 7 ,
+.Xr tbl 7
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Ox 4.8 .
+The option
+.Fl I
+appeared in
+.Ox 5.2 ,
+and
+.Fl aCcfhKklMSsw
+in
+.Ox 5.7 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and is maintained by
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .

Property changes on: vendor/mandoc/20190723/mandoc.1
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/mandoc.c
===================================================================
--- vendor/mandoc/20190723/mandoc.c	(nonexistent)
+++ vendor/mandoc/20190723/mandoc.c	(revision 350350)
@@ -0,0 +1,648 @@
+/*	$Id: mandoc.c,v 1.116 2019/06/27 15:07:30 schwarze Exp $ */
+/*
+ * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons 
+ * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "roff.h"
+#include "libmandoc.h"
+#include "roff_int.h"
+
+static	int	 a2time(time_t *, const char *, const char *);
+static	char	*time2a(time_t);
+
+
+enum mandoc_esc
+mandoc_font(const char *cp, int sz)
+{
+	switch (sz) {
+	case 0:
+		return ESCAPE_FONTPREV;
+	case 1:
+		switch (cp[0]) {
+		case 'B':
+		case '3':
+			return ESCAPE_FONTBOLD;
+		case 'I':
+		case '2':
+			return ESCAPE_FONTITALIC;
+		case 'P':
+			return ESCAPE_FONTPREV;
+		case 'R':
+		case '1':
+			return ESCAPE_FONTROMAN;
+		case '4':
+			return ESCAPE_FONTBI;
+		default:
+			return ESCAPE_ERROR;
+		}
+	case 2:
+		switch (cp[0]) {
+		case 'B':
+			switch (cp[1]) {
+			case 'I':
+				return ESCAPE_FONTBI;
+			default:
+				return ESCAPE_ERROR;
+			}
+		case 'C':
+			switch (cp[1]) {
+			case 'B':
+				return ESCAPE_FONTBOLD;
+			case 'I':
+				return ESCAPE_FONTITALIC;
+			case 'R':
+			case 'W':
+				return ESCAPE_FONTCW;
+			default:
+				return ESCAPE_ERROR;
+			}
+		default:
+			return ESCAPE_ERROR;
+		}
+	default:
+		return ESCAPE_ERROR;
+	}
+}
+
+enum mandoc_esc
+mandoc_escape(const char **end, const char **start, int *sz)
+{
+	const char	*local_start;
+	int		 local_sz, c, i;
+	char		 term;
+	enum mandoc_esc	 gly;
+
+	/*
+	 * When the caller doesn't provide return storage,
+	 * use local storage.
+	 */
+
+	if (NULL == start)
+		start = &local_start;
+	if (NULL == sz)
+		sz = &local_sz;
+
+	/*
+	 * Treat "\E" just like "\";
+	 * it only makes a difference in copy mode.
+	 */
+
+	if (**end == 'E')
+		++*end;
+
+	/*
+	 * Beyond the backslash, at least one input character
+	 * is part of the escape sequence.  With one exception
+	 * (see below), that character won't be returned.
+	 */
+
+	gly = ESCAPE_ERROR;
+	*start = ++*end;
+	*sz = 0;
+	term = '\0';
+
+	switch ((*start)[-1]) {
+	/*
+	 * First the glyphs.  There are several different forms of
+	 * these, but each eventually returns a substring of the glyph
+	 * name.
+	 */
+	case '(':
+		gly = ESCAPE_SPECIAL;
+		*sz = 2;
+		break;
+	case '[':
+		if (**start == ' ') {
+			++*end;
+			return ESCAPE_ERROR;
+		}
+		gly = ESCAPE_SPECIAL;
+		term = ']';
+		break;
+	case 'C':
+		if ('\'' != **start)
+			return ESCAPE_ERROR;
+		*start = ++*end;
+		gly = ESCAPE_SPECIAL;
+		term = '\'';
+		break;
+
+	/*
+	 * Escapes taking no arguments at all.
+	 */
+	case '!':
+	case '?':
+		return ESCAPE_UNSUPP;
+	case '%':
+	case '&':
+	case ')':
+	case ',':
+	case '/':
+	case '^':
+	case 'a':
+	case 'd':
+	case 'r':
+	case 't':
+	case 'u':
+	case '{':
+	case '|':
+	case '}':
+		return ESCAPE_IGNORE;
+	case 'c':
+		return ESCAPE_NOSPACE;
+	case 'p':
+		return ESCAPE_BREAK;
+
+	/*
+	 * The \z escape is supposed to output the following
+	 * character without advancing the cursor position.
+	 * Since we are mostly dealing with terminal mode,
+	 * let us just skip the next character.
+	 */
+	case 'z':
+		return ESCAPE_SKIPCHAR;
+
+	/*
+	 * Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where
+	 * 'X' is the trigger.  These have opaque sub-strings.
+	 */
+	case 'F':
+	case 'f':
+	case 'g':
+	case 'k':
+	case 'M':
+	case 'm':
+	case 'n':
+	case 'O':
+	case 'V':
+	case 'Y':
+		gly = (*start)[-1] == 'f' ? ESCAPE_FONT : ESCAPE_IGNORE;
+		switch (**start) {
+		case '(':
+			if ((*start)[-1] == 'O')
+				gly = ESCAPE_ERROR;
+			*start = ++*end;
+			*sz = 2;
+			break;
+		case '[':
+			if ((*start)[-1] == 'O')
+				gly = (*start)[1] == '5' ?
+				    ESCAPE_UNSUPP : ESCAPE_ERROR;
+			*start = ++*end;
+			term = ']';
+			break;
+		default:
+			if ((*start)[-1] == 'O') {
+				switch (**start) {
+				case '0':
+					gly = ESCAPE_UNSUPP;
+					break;
+				case '1':
+				case '2':
+				case '3':
+				case '4':
+					break;
+				default:
+					gly = ESCAPE_ERROR;
+					break;
+				}
+			}
+			*sz = 1;
+			break;
+		}
+		break;
+	case '*':
+		if (strncmp(*start, "(.T", 3) != 0)
+			abort();
+		gly = ESCAPE_DEVICE;
+		*start = ++*end;
+		*sz = 2;
+		break;
+
+	/*
+	 * These escapes are of the form \X'Y', where 'X' is the trigger
+	 * and 'Y' is any string.  These have opaque sub-strings.
+	 * The \B and \w escapes are handled in roff.c, roff_res().
+	 */
+	case 'A':
+	case 'b':
+	case 'D':
+	case 'R':
+	case 'X':
+	case 'Z':
+		gly = ESCAPE_IGNORE;
+		/* FALLTHROUGH */
+	case 'o':
+		if (**start == '\0')
+			return ESCAPE_ERROR;
+		if (gly == ESCAPE_ERROR)
+			gly = ESCAPE_OVERSTRIKE;
+		term = **start;
+		*start = ++*end;
+		break;
+
+	/*
+	 * These escapes are of the form \X'N', where 'X' is the trigger
+	 * and 'N' resolves to a numerical expression.
+	 */
+	case 'h':
+	case 'H':
+	case 'L':
+	case 'l':
+	case 'S':
+	case 'v':
+	case 'x':
+		if (strchr(" %&()*+-./0123456789:<=>", **start)) {
+			if ('\0' != **start)
+				++*end;
+			return ESCAPE_ERROR;
+		}
+		switch ((*start)[-1]) {
+		case 'h':
+			gly = ESCAPE_HORIZ;
+			break;
+		case 'l':
+			gly = ESCAPE_HLINE;
+			break;
+		default:
+			gly = ESCAPE_IGNORE;
+			break;
+		}
+		term = **start;
+		*start = ++*end;
+		break;
+
+	/*
+	 * Special handling for the numbered character escape.
+	 * XXX Do any other escapes need similar handling?
+	 */
+	case 'N':
+		if ('\0' == **start)
+			return ESCAPE_ERROR;
+		(*end)++;
+		if (isdigit((unsigned char)**start)) {
+			*sz = 1;
+			return ESCAPE_IGNORE;
+		}
+		(*start)++;
+		while (isdigit((unsigned char)**end))
+			(*end)++;
+		*sz = *end - *start;
+		if ('\0' != **end)
+			(*end)++;
+		return ESCAPE_NUMBERED;
+
+	/*
+	 * Sizes get a special category of their own.
+	 */
+	case 's':
+		gly = ESCAPE_IGNORE;
+
+		/* See +/- counts as a sign. */
+		if ('+' == **end || '-' == **end || ASCII_HYPH == **end)
+			*start = ++*end;
+
+		switch (**end) {
+		case '(':
+			*start = ++*end;
+			*sz = 2;
+			break;
+		case '[':
+			*start = ++*end;
+			term = ']';
+			break;
+		case '\'':
+			*start = ++*end;
+			term = '\'';
+			break;
+		case '3':
+		case '2':
+		case '1':
+			*sz = (*end)[-1] == 's' &&
+			    isdigit((unsigned char)(*end)[1]) ? 2 : 1;
+			break;
+		default:
+			*sz = 1;
+			break;
+		}
+
+		break;
+
+	/*
+	 * Several special characters can be encoded as
+	 * one-byte escape sequences without using \[].
+	 */
+	case ' ':
+	case '\'':
+	case '-':
+	case '.':
+	case '0':
+	case ':':
+	case '_':
+	case '`':
+	case 'e':
+	case '~':
+		gly = ESCAPE_SPECIAL;
+		/* FALLTHROUGH */
+	default:
+		if (gly == ESCAPE_ERROR)
+			gly = ESCAPE_UNDEF;
+		*start = --*end;
+		*sz = 1;
+		break;
+	}
+
+	/*
+	 * Read up to the terminating character,
+	 * paying attention to nested escapes.
+	 */
+
+	if ('\0' != term) {
+		while (**end != term) {
+			switch (**end) {
+			case '\0':
+				return ESCAPE_ERROR;
+			case '\\':
+				(*end)++;
+				if (ESCAPE_ERROR ==
+				    mandoc_escape(end, NULL, NULL))
+					return ESCAPE_ERROR;
+				break;
+			default:
+				(*end)++;
+				break;
+			}
+		}
+		*sz = (*end)++ - *start;
+
+		/*
+		 * The file chars.c only provides one common list
+		 * of character names, but \[-] == \- is the only
+		 * one of the characters with one-byte names that
+		 * allows enclosing the name in brackets.
+		 */
+		if (gly == ESCAPE_SPECIAL && *sz == 1 && **start != '-')
+			return ESCAPE_ERROR;
+	} else {
+		assert(*sz > 0);
+		if ((size_t)*sz > strlen(*start))
+			return ESCAPE_ERROR;
+		*end += *sz;
+	}
+
+	/* Run post-processors. */
+
+	switch (gly) {
+	case ESCAPE_FONT:
+		gly = mandoc_font(*start, *sz);
+		break;
+	case ESCAPE_SPECIAL:
+		if (**start == 'c') {
+			if (*sz < 6 || *sz > 7 ||
+			    strncmp(*start, "char", 4) != 0 ||
+			    (int)strspn(*start + 4, "0123456789") + 4 < *sz)
+				break;
+			c = 0;
+			for (i = 4; i < *sz; i++)
+				c = 10 * c + ((*start)[i] - '0');
+			if (c < 0x21 || (c > 0x7e && c < 0xa0) || c > 0xff)
+				break;
+			*start += 4;
+			*sz -= 4;
+			gly = ESCAPE_NUMBERED;
+			break;
+		}
+
+		/*
+		 * Unicode escapes are defined in groff as \[u0000]
+		 * to \[u10FFFF], where the contained value must be
+		 * a valid Unicode codepoint.  Here, however, only
+		 * check the length and range.
+		 */
+		if (**start != 'u' || *sz < 5 || *sz > 7)
+			break;
+		if (*sz == 7 && ((*start)[1] != '1' || (*start)[2] != '0'))
+			break;
+		if (*sz == 6 && (*start)[1] == '0')
+			break;
+		if (*sz == 5 && (*start)[1] == 'D' &&
+		    strchr("89ABCDEF", (*start)[2]) != NULL)
+			break;
+		if ((int)strspn(*start + 1, "0123456789ABCDEFabcdef")
+		    + 1 == *sz)
+			gly = ESCAPE_UNICODE;
+		break;
+	default:
+		break;
+	}
+
+	return gly;
+}
+
+static int
+a2time(time_t *t, const char *fmt, const char *p)
+{
+	struct tm	 tm;
+	char		*pp;
+
+	memset(&tm, 0, sizeof(struct tm));
+
+	pp = NULL;
+#if HAVE_STRPTIME
+	pp = strptime(p, fmt, &tm);
+#endif
+	if (NULL != pp && '\0' == *pp) {
+		*t = mktime(&tm);
+		return 1;
+	}
+
+	return 0;
+}
+
+static char *
+time2a(time_t t)
+{
+	struct tm	*tm;
+	char		*buf, *p;
+	size_t		 ssz;
+	int		 isz;
+
+	buf = NULL;
+	tm = localtime(&t);
+	if (tm == NULL)
+		goto fail;
+
+	/*
+	 * Reserve space:
+	 * up to 9 characters for the month (September) + blank
+	 * up to 2 characters for the day + comma + blank
+	 * 4 characters for the year and a terminating '\0'
+	 */
+
+	p = buf = mandoc_malloc(10 + 4 + 4 + 1);
+
+	if ((ssz = strftime(p, 10 + 1, "%B ", tm)) == 0)
+		goto fail;
+	p += (int)ssz;
+
+	/*
+	 * The output format is just "%d" here, not "%2d" or "%02d".
+	 * That's also the reason why we can't just format the
+	 * date as a whole with "%B %e, %Y" or "%B %d, %Y".
+	 * Besides, the present approach is less prone to buffer
+	 * overflows, in case anybody should ever introduce the bug
+	 * of looking at LC_TIME.
+	 */
+
+	isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday);
+	if (isz < 0 || isz > 4)
+		goto fail;
+	p += isz;
+
+	if (strftime(p, 4 + 1, "%Y", tm) == 0)
+		goto fail;
+	return buf;
+
+fail:
+	free(buf);
+	return mandoc_strdup("");
+}
+
+char *
+mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
+{
+	char		*cp;
+	time_t		 t;
+
+	if (man->quick)
+		return mandoc_strdup(in == NULL ? "" : in);
+
+	/* No date specified: use today's date. */
+
+	if (in == NULL || *in == '\0')
+		mandoc_msg(MANDOCERR_DATE_MISSING, ln, pos, NULL);
+	if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0)
+		return time2a(time(NULL));
+
+	/* Valid mdoc(7) date format. */
+
+	if (a2time(&t, "$" "Mdocdate: %b %d %Y $", in) ||
+	    a2time(&t, "%b %d, %Y", in)) {
+		cp = time2a(t);
+		if (t > time(NULL) + 86400)
+			mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", cp);
+		else if (*in != '$' && strcmp(in, cp) != 0)
+			mandoc_msg(MANDOCERR_DATE_NORM, ln, pos, "%s", cp);
+		return cp;
+	}
+
+	/* In man(7), do not warn about the legacy format. */
+
+	if (a2time(&t, "%Y-%m-%d", in) == 0)
+		mandoc_msg(MANDOCERR_DATE_BAD, ln, pos, "%s", in);
+	else if (t > time(NULL) + 86400)
+		mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", in);
+	else if (man->meta.macroset == MACROSET_MDOC)
+		mandoc_msg(MANDOCERR_DATE_LEGACY, ln, pos, "Dd %s", in);
+
+	/* Use any non-mdoc(7) date verbatim. */
+
+	return mandoc_strdup(in);
+}
+
+int
+mandoc_eos(const char *p, size_t sz)
+{
+	const char	*q;
+	int		 enclosed, found;
+
+	if (0 == sz)
+		return 0;
+
+	/*
+	 * End-of-sentence recognition must include situations where
+	 * some symbols, such as `)', allow prior EOS punctuation to
+	 * propagate outward.
+	 */
+
+	enclosed = found = 0;
+	for (q = p + (int)sz - 1; q >= p; q--) {
+		switch (*q) {
+		case '\"':
+		case '\'':
+		case ']':
+		case ')':
+			if (0 == found)
+				enclosed = 1;
+			break;
+		case '.':
+		case '!':
+		case '?':
+			found = 1;
+			break;
+		default:
+			return found &&
+			    (!enclosed || isalnum((unsigned char)*q));
+		}
+	}
+
+	return found && !enclosed;
+}
+
+/*
+ * Convert a string to a long that may not be <0.
+ * If the string is invalid, or is less than 0, return -1.
+ */
+int
+mandoc_strntoi(const char *p, size_t sz, int base)
+{
+	char		 buf[32];
+	char		*ep;
+	long		 v;
+
+	if (sz > 31)
+		return -1;
+
+	memcpy(buf, p, sz);
+	buf[(int)sz] = '\0';
+
+	errno = 0;
+	v = strtol(buf, &ep, base);
+
+	if (buf[0] == '\0' || *ep != '\0')
+		return -1;
+
+	if (v > INT_MAX)
+		v = INT_MAX;
+	if (v < INT_MIN)
+		v = INT_MIN;
+
+	return (int)v;
+}

Property changes on: vendor/mandoc/20190723/mandoc.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/mandoc.css
===================================================================
--- vendor/mandoc/20190723/mandoc.css	(nonexistent)
+++ vendor/mandoc/20190723/mandoc.css	(revision 350350)
@@ -0,0 +1,360 @@
+/* $Id: mandoc.css,v 1.46 2019/06/02 16:57:13 schwarze Exp $ */
+/*
+ * Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
+ *
+ * Written by Ingo Schwarze .
+ * I place this file into the public domain.
+ * Permission to use, copy, modify, and distribute it for any purpose
+ * with or without fee is hereby granted, without any conditions.
+ */
+
+/* Global defaults. */
+
+html {		max-width: 65em;
+		--bg: #FFFFFF;
+		--fg: #000000; }
+body {		background: var(--bg);
+		color: var(--fg);
+		font-family: Helvetica,Arial,sans-serif; }
+h1 {		font-size: 110%; }
+table {		margin-top: 0em;
+		margin-bottom: 0em;
+		border-collapse: collapse; }
+/* Some browsers set border-color in a browser style for tbody,
+ * but not for table, resulting in inconsistent border styling. */
+tbody {		border-color: inherit; }
+tr {		border-color: inherit; }
+td {		vertical-align: top;
+		padding-left: 0.2em;
+		padding-right: 0.2em;
+		border-color: inherit; }
+ul, ol, dl {	margin-top: 0em;
+		margin-bottom: 0em; }
+li, dt {	margin-top: 1em; }
+
+.permalink {	border-bottom: thin dotted;
+		color: inherit;
+		font: inherit;
+		text-decoration: inherit; }
+* {		clear: both }
+
+/* Search form and search results. */
+
+fieldset {	border: thin solid silver;
+		border-radius: 1em;
+		text-align: center; }
+input[name=expr] {
+		width: 25%; }
+
+table.results {	margin-top: 1em;
+		margin-left: 2em;
+		font-size: smaller; }
+
+/* Header and footer lines. */
+
+table.head {	width: 100%;
+		border-bottom: 1px dotted #808080;
+		margin-bottom: 1em;
+		font-size: smaller; }
+td.head-vol {	text-align: center; }
+td.head-rtitle {
+		text-align: right; }
+
+table.foot {	width: 100%;
+		border-top: 1px dotted #808080;
+		margin-top: 1em;
+		font-size: smaller; }
+td.foot-os {	text-align: right; }
+
+/* Sections and paragraphs. */
+
+.manual-text {
+		margin-left: 3.8em; }
+.Nd { }
+section.Sh { }
+h1.Sh {		margin-top: 1.2em;
+		margin-bottom: 0.6em;
+		margin-left: -3.2em; }
+section.Ss { }
+h2.Ss {		margin-top: 1.2em;
+		margin-bottom: 0.6em;
+		margin-left: -1.2em;
+		font-size: 105%; }
+.Pp {		margin: 0.6em 0em; }
+.Sx { }
+.Xr { }
+
+/* Displays and lists. */
+
+.Bd { }
+.Bd-indent {	margin-left: 3.8em; }
+
+.Bl-bullet {	list-style-type: disc;
+		padding-left: 1em; }
+.Bl-bullet > li { }
+.Bl-dash {	list-style-type: none;
+		padding-left: 0em; }
+.Bl-dash > li:before {
+		content: "\2014  "; }
+.Bl-item {	list-style-type: none;
+		padding-left: 0em; }
+.Bl-item > li { }
+.Bl-compact > li {
+		margin-top: 0em; }
+
+.Bl-enum {	padding-left: 2em; }
+.Bl-enum > li { }
+.Bl-compact > li {
+		margin-top: 0em; }
+
+.Bl-diag { }
+.Bl-diag > dt {
+		font-style: normal;
+		font-weight: bold; }
+.Bl-diag > dd {
+		margin-left: 0em; }
+.Bl-hang { }
+.Bl-hang > dt { }
+.Bl-hang > dd {
+		margin-left: 5.5em; }
+.Bl-inset { }
+.Bl-inset > dt { }
+.Bl-inset > dd {
+		margin-left: 0em; }
+.Bl-ohang { }
+.Bl-ohang > dt { }
+.Bl-ohang > dd {
+		margin-left: 0em; }
+.Bl-tag {	margin-top: 0.6em;
+		margin-left: 5.5em; }
+.Bl-tag > dt {
+		float: left;
+		margin-top: 0em;
+		margin-left: -5.5em;
+		padding-right: 0.5em;
+		vertical-align: top; }
+.Bl-tag > dd {
+		clear: right;
+		width: 100%;
+		margin-top: 0em;
+		margin-left: 0em;
+		margin-bottom: 0.6em;
+		vertical-align: top;
+		overflow: auto; }
+.Bl-compact {	margin-top: 0em; }
+.Bl-compact > dd {
+		margin-bottom: 0em; }
+.Bl-compact > dt {
+		margin-top: 0em; }
+
+.Bl-column { }
+.Bl-column > tbody > tr { }
+.Bl-column > tbody > tr > td {
+		margin-top: 1em; }
+.Bl-compact > tbody > tr > td {
+		margin-top: 0em; }
+
+.Rs {		font-style: normal;
+		font-weight: normal; }
+.RsA { }
+.RsB {		font-style: italic;
+		font-weight: normal; }
+.RsC { }
+.RsD { }
+.RsI {		font-style: italic;
+		font-weight: normal; }
+.RsJ {		font-style: italic;
+		font-weight: normal; }
+.RsN { }
+.RsO { }
+.RsP { }
+.RsQ { }
+.RsR { }
+.RsT {		text-decoration: underline; }
+.RsU { }
+.RsV { }
+
+.eqn { }
+.tbl td {	vertical-align: middle; }
+
+.HP {		margin-left: 3.8em;
+		text-indent: -3.8em; }
+
+/* Semantic markup for command line utilities. */
+
+table.Nm { }
+code.Nm {	font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Fl {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Cm {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Ar {		font-style: italic;
+		font-weight: normal; }
+.Op {		display: inline; }
+.Ic {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Ev {		font-style: normal;
+		font-weight: normal;
+		font-family: monospace; }
+.Pa {		font-style: italic;
+		font-weight: normal; }
+
+/* Semantic markup for function libraries. */
+
+.Lb { }
+code.In {	font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+a.In { }
+.Fd {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Ft {		font-style: italic;
+		font-weight: normal; }
+.Fn {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Fa {		font-style: italic;
+		font-weight: normal; }
+.Vt {		font-style: italic;
+		font-weight: normal; }
+.Va {		font-style: italic;
+		font-weight: normal; }
+.Dv {		font-style: normal;
+		font-weight: normal;
+		font-family: monospace; }
+.Er {		font-style: normal;
+		font-weight: normal;
+		font-family: monospace; }
+
+/* Various semantic markup. */
+
+.An { }
+.Lk { }
+.Mt { }
+.Cd {		font-style: normal;
+		font-weight: bold;
+		font-family: inherit; }
+.Ad {		font-style: italic;
+		font-weight: normal; }
+.Ms {		font-style: normal;
+		font-weight: bold; }
+.St { }
+.Ux { }
+
+/* Physical markup. */
+
+.Bf {		display: inline; }
+.No {		font-style: normal;
+		font-weight: normal; }
+.Em {		font-style: italic;
+		font-weight: normal; }
+.Sy {		font-style: normal;
+		font-weight: bold; }
+.Li {		font-style: normal;
+		font-weight: normal;
+		font-family: monospace; }
+
+/* Tooltip support. */
+
+h1.Sh, h2.Ss {	position: relative; }
+.An, .Ar, .Cd, .Cm, .Dv, .Em, .Er, .Ev, .Fa, .Fd, .Fl, .Fn, .Ft,
+.Ic, code.In, .Lb, .Lk, .Ms, .Mt, .Nd, code.Nm, .Pa, .Rs,
+.St, .Sx, .Sy, .Va, .Vt, .Xr {
+		display: inline-block;
+		position: relative; }
+
+.An::before {	content: "An"; }
+.Ar::before {	content: "Ar"; }
+.Cd::before {	content: "Cd"; }
+.Cm::before {	content: "Cm"; }
+.Dv::before {	content: "Dv"; }
+.Em::before {	content: "Em"; }
+.Er::before {	content: "Er"; }
+.Ev::before {	content: "Ev"; }
+.Fa::before {	content: "Fa"; }
+.Fd::before {	content: "Fd"; }
+.Fl::before {	content: "Fl"; }
+.Fn::before {	content: "Fn"; }
+.Ft::before {	content: "Ft"; }
+.Ic::before {	content: "Ic"; }
+code.In::before { content: "In"; }
+.Lb::before {	content: "Lb"; }
+.Lk::before {	content: "Lk"; }
+.Ms::before {	content: "Ms"; }
+.Mt::before {	content: "Mt"; }
+.Nd::before {	content: "Nd"; }
+code.Nm::before { content: "Nm"; }
+.Pa::before {	content: "Pa"; }
+.Rs::before {	content: "Rs"; }
+h1.Sh::before {	content: "Sh"; }
+h2.Ss::before {	content: "Ss"; }
+.St::before {	content: "St"; }
+.Sx::before {	content: "Sx"; }
+.Sy::before {	content: "Sy"; }
+.Va::before {	content: "Va"; }
+.Vt::before {	content: "Vt"; }
+.Xr::before {	content: "Xr"; }
+
+.An::before, .Ar::before, .Cd::before, .Cm::before,
+.Dv::before, .Em::before, .Er::before, .Ev::before,
+.Fa::before, .Fd::before, .Fl::before, .Fn::before, .Ft::before,
+.Ic::before, code.In::before, .Lb::before, .Lk::before,
+.Ms::before, .Mt::before, .Nd::before, code.Nm::before,
+.Pa::before, .Rs::before,
+h1.Sh::before, h2.Ss::before, .St::before, .Sx::before, .Sy::before,
+.Va::before, .Vt::before, .Xr::before {
+		opacity: 0;
+		transition: .15s ease opacity;
+		pointer-events: none;
+		position: absolute;
+		bottom: 100%;
+		box-shadow: 0 0 .35em var(--fg);
+		padding: .15em .25em;
+		white-space: nowrap;
+		font-family: Helvetica,Arial,sans-serif;
+		font-style: normal;
+		font-weight: bold;
+		background: var(--bg);
+		color: var(--fg); }
+.An:hover::before, .Ar:hover::before, .Cd:hover::before, .Cm:hover::before,
+.Dv:hover::before, .Em:hover::before, .Er:hover::before, .Ev:hover::before,
+.Fa:hover::before, .Fd:hover::before, .Fl:hover::before, .Fn:hover::before,
+.Ft:hover::before, .Ic:hover::before, code.In:hover::before,
+.Lb:hover::before, .Lk:hover::before, .Ms:hover::before, .Mt:hover::before,
+.Nd:hover::before, code.Nm:hover::before, .Pa:hover::before,
+.Rs:hover::before, h1.Sh:hover::before, h2.Ss:hover::before, .St:hover::before,
+.Sx:hover::before, .Sy:hover::before, .Va:hover::before, .Vt:hover::before,
+.Xr:hover::before {
+		opacity: 1;
+		pointer-events: inherit; }
+
+/* Overrides to avoid excessive margins on small devices. */
+
+@media (max-width: 37.5em) {
+.manual-text {
+		margin-left: 0.5em; }
+h1.Sh, h2.Ss {	margin-left: 0em; }
+.Bd-indent {	margin-left: 2em; }
+.Bl-hang > dd {
+		margin-left: 2em; }
+.Bl-tag {	margin-left: 2em; }
+.Bl-tag > dt {
+		margin-left: -2em; }
+.HP {		margin-left: 2em;
+		text-indent: -2em; }
+}
+
+/* Overrides for a dark color scheme for accessibility. */
+
+@media (prefers-color-scheme: dark) {
+html {		--bg: #1E1F21;
+		--fg: #EEEFF1; }
+:link {		color: #BAD7FF; }
+:visited {	color: #F6BAFF; }
+}

Property changes on: vendor/mandoc/20190723/mandoc.css
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/css
\ No newline at end of property
Index: vendor/mandoc/20190723/mandoc.h
===================================================================
--- vendor/mandoc/20190723/mandoc.h	(nonexistent)
+++ vendor/mandoc/20190723/mandoc.h	(revision 350350)
@@ -0,0 +1,319 @@
+/*	$Id: mandoc.h,v 1.264 2019/07/14 18:16:13 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons 
+ * Copyright (c) 2012-2019 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.
+ *
+ * Error handling, escape sequence, and character utilities.
+ */
+
+#define ASCII_NBRSP	 31  /* non-breaking space */
+#define	ASCII_HYPH	 30  /* breakable hyphen */
+#define	ASCII_BREAK	 29  /* breakable zero-width space */
+
+/*
+ * Status level.  This refers to both internal status (i.e., whilst
+ * running, when warnings/errors are reported) and an indicator of a
+ * threshold of when to halt (when said internal state exceeds the
+ * threshold).
+ */
+enum	mandoclevel {
+	MANDOCLEVEL_OK = 0,
+	MANDOCLEVEL_STYLE, /* style suggestions */
+	MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */
+	MANDOCLEVEL_ERROR, /* input has been thrown away */
+	MANDOCLEVEL_UNSUPP, /* input needs unimplemented features */
+	MANDOCLEVEL_BADARG, /* bad argument in invocation */
+	MANDOCLEVEL_SYSERR, /* system error */
+	MANDOCLEVEL_MAX
+};
+
+/*
+ * All possible things that can go wrong within a parse, be it libroff,
+ * libmdoc, or libman.
+ */
+enum	mandocerr {
+	MANDOCERR_OK,
+
+	MANDOCERR_BASE, /* ===== start of base system conventions ===== */
+
+	MANDOCERR_MDOCDATE, /* Mdocdate found: Dd ... */
+	MANDOCERR_MDOCDATE_MISSING, /* Mdocdate missing: Dd ... */
+	MANDOCERR_ARCH_BAD,  /* unknown architecture: Dt ... arch */
+	MANDOCERR_OS_ARG,  /* operating system explicitly specified: Os ... */
+	MANDOCERR_RCS_MISSING, /* RCS id missing */
+	MANDOCERR_XR_BAD,  /* referenced manual not found: Xr name sec */
+
+	MANDOCERR_STYLE, /* ===== start of style suggestions ===== */
+
+	MANDOCERR_DATE_LEGACY, /* legacy man(7) date format: Dd ... */
+	MANDOCERR_DATE_NORM, /* normalizing date format to: ... */
+	MANDOCERR_TITLE_CASE, /* lower case character in document title */
+	MANDOCERR_RCS_REP, /* duplicate RCS id: ... */
+	MANDOCERR_SEC_TYPO,  /* possible typo in section name: Sh ... */
+	MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
+	MANDOCERR_MACRO_USELESS, /* useless macro: macro */
+	MANDOCERR_BX, /* consider using OS macro: macro */
+	MANDOCERR_ER_ORDER, /* errnos out of order: Er ... */
+	MANDOCERR_ER_REP, /* duplicate errno: Er ... */
+	MANDOCERR_DELIM, /* trailing delimiter: macro ... */
+	MANDOCERR_DELIM_NB, /* no blank before trailing delimiter: macro ... */
+	MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
+	MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
+	MANDOCERR_DASHDASH, /* verbatim "--", maybe consider using \(em */
+	MANDOCERR_FUNC, /* function name without markup: name() */
+	MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
+	MANDOCERR_COMMENT_BAD, /* bad comment style */
+
+	MANDOCERR_WARNING, /* ===== start of warnings ===== */
+
+	/* related to the prologue */
+	MANDOCERR_DT_NOTITLE, /* missing manual title, using UNTITLED: line */
+	MANDOCERR_TH_NOTITLE, /* missing manual title, using "": [macro] */
+	MANDOCERR_MSEC_MISSING, /* missing manual section, using "": macro */
+	MANDOCERR_MSEC_BAD, /* unknown manual section: Dt ... section */
+	MANDOCERR_DATE_MISSING, /* missing date, using today's date */
+	MANDOCERR_DATE_BAD, /* cannot parse date, using it verbatim: date */
+	MANDOCERR_DATE_FUTURE, /* date in the future, using it anyway: date */
+	MANDOCERR_OS_MISSING, /* missing Os macro, using "" */
+	MANDOCERR_PROLOG_LATE, /* late prologue macro: macro */
+	MANDOCERR_PROLOG_ORDER, /* prologue macros out of order: macros */
+
+	/* related to document structure */
+	MANDOCERR_SO, /* .so is fragile, better use ln(1): so path */
+	MANDOCERR_DOC_EMPTY, /* no document body */
+	MANDOCERR_SEC_BEFORE, /* content before first section header: macro */
+	MANDOCERR_NAMESEC_FIRST, /* first section is not NAME: Sh title */
+	MANDOCERR_NAMESEC_NONM, /* NAME section without Nm before Nd */
+	MANDOCERR_NAMESEC_NOND, /* NAME section without description */
+	MANDOCERR_NAMESEC_ND, /* description not at the end of NAME */
+	MANDOCERR_NAMESEC_BAD, /* bad NAME section content: macro */
+	MANDOCERR_NAMESEC_PUNCT, /* missing comma before name: Nm name */
+	MANDOCERR_ND_EMPTY, /* missing description line, using "" */
+	MANDOCERR_ND_LATE, /* description line outside NAME section */
+	MANDOCERR_SEC_ORDER, /* sections out of conventional order: Sh title */
+	MANDOCERR_SEC_REP, /* duplicate section title: Sh title */
+	MANDOCERR_SEC_MSEC, /* unexpected section: Sh title for ... only */
+	MANDOCERR_XR_SELF,  /* cross reference to self: Xr name sec */
+	MANDOCERR_XR_ORDER, /* unusual Xr order: ... after ... */
+	MANDOCERR_XR_PUNCT, /* unusual Xr punctuation: ... after ... */
+	MANDOCERR_AN_MISSING, /* AUTHORS section without An macro */
+
+	/* related to macros and nesting */
+	MANDOCERR_MACRO_OBS, /* obsolete macro: macro */
+	MANDOCERR_MACRO_CALL, /* macro neither callable nor escaped: macro */
+	MANDOCERR_PAR_SKIP, /* skipping paragraph macro: macro ... */
+	MANDOCERR_PAR_MOVE, /* moving paragraph macro out of list: macro */
+	MANDOCERR_NS_SKIP, /* skipping no-space macro */
+	MANDOCERR_BLK_NEST, /* blocks badly nested: macro ... */
+	MANDOCERR_BD_NEST, /* nested displays are not portable: macro ... */
+	MANDOCERR_BL_MOVE, /* moving content out of list: macro */
+	MANDOCERR_TA_LINE, /* first macro on line: Ta */
+	MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */
+	MANDOCERR_BLK_BLANK, /* skipping blank line in line scope */
+
+	/* related to missing arguments */
+	MANDOCERR_REQ_EMPTY, /* skipping empty request: request */
+	MANDOCERR_COND_EMPTY, /* conditional request controls empty scope */
+	MANDOCERR_MACRO_EMPTY, /* skipping empty macro: macro */
+	MANDOCERR_BLK_EMPTY, /* empty block: macro */
+	MANDOCERR_ARG_EMPTY, /* empty argument, using 0n: macro arg */
+	MANDOCERR_BD_NOTYPE, /* missing display type, using -ragged: Bd */
+	MANDOCERR_BL_LATETYPE, /* list type is not the first argument: Bl arg */
+	MANDOCERR_BL_NOWIDTH, /* missing -width in -tag list, using 6n */
+	MANDOCERR_EX_NONAME, /* missing utility name, using "": Ex */
+	MANDOCERR_FO_NOHEAD, /* missing function name, using "": Fo */
+	MANDOCERR_IT_NOHEAD, /* empty head in list item: Bl -type It */
+	MANDOCERR_IT_NOBODY, /* empty list item: Bl -type It */
+	MANDOCERR_IT_NOARG, /* missing argument, using next line: Bl -c It */
+	MANDOCERR_BF_NOFONT, /* missing font type, using \fR: Bf */
+	MANDOCERR_BF_BADFONT, /* unknown font type, using \fR: Bf font */
+	MANDOCERR_PF_SKIP, /* nothing follows prefix: Pf arg */
+	MANDOCERR_RS_EMPTY, /* empty reference block: Rs */
+	MANDOCERR_XR_NOSEC, /* missing section argument: Xr arg */
+	MANDOCERR_ARG_STD, /* missing -std argument, adding it: macro */
+	MANDOCERR_OP_EMPTY, /* missing option string, using "": OP */
+	MANDOCERR_UR_NOHEAD, /* missing resource identifier, using "": UR */
+	MANDOCERR_EQN_NOBOX, /* missing eqn box, using "": op */
+
+	/* related to bad arguments */
+	MANDOCERR_ARG_REP, /* duplicate argument: macro arg */
+	MANDOCERR_AN_REP, /* skipping duplicate argument: An -arg */
+	MANDOCERR_BD_REP, /* skipping duplicate display type: Bd -type */
+	MANDOCERR_BL_REP, /* skipping duplicate list type: Bl -type */
+	MANDOCERR_BL_SKIPW, /* skipping -width argument: Bl -type */
+	MANDOCERR_BL_COL, /* wrong number of cells */
+	MANDOCERR_AT_BAD, /* unknown AT&T UNIX version: At version */
+	MANDOCERR_FA_COMMA, /* comma in function argument: arg */
+	MANDOCERR_FN_PAREN, /* parenthesis in function name: arg */
+	MANDOCERR_LB_BAD, /* unknown library name: Lb ... */
+	MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */
+	MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */
+	MANDOCERR_CHAR_FONT, /* argument contains two font escapes */
+	MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
+	MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */
+
+	/* related to plain text */
+	MANDOCERR_FI_BLANK, /* blank line in fill mode, using .sp */
+	MANDOCERR_FI_TAB, /* tab in filled text */
+	MANDOCERR_EOS, /* new sentence, new line */
+	MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
+	MANDOCERR_ESC_UNDEF, /* undefined escape, printing literally: char */
+	MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
+
+	/* related to tables */
+	MANDOCERR_TBLLAYOUT_SPAN, /* tbl line starts with span */
+	MANDOCERR_TBLLAYOUT_DOWN, /* tbl column starts with span */
+	MANDOCERR_TBLLAYOUT_VERT, /* skipping vertical bar in tbl layout */
+
+	MANDOCERR_ERROR, /* ===== start of errors ===== */
+
+	/* related to tables */
+	MANDOCERR_TBLOPT_ALPHA, /* non-alphabetic character in tbl options */
+	MANDOCERR_TBLOPT_BAD, /* skipping unknown tbl option: option */
+	MANDOCERR_TBLOPT_NOARG, /* missing tbl option argument: option */
+	MANDOCERR_TBLOPT_ARGSZ, /* wrong tbl option argument size: option */
+	MANDOCERR_TBLLAYOUT_NONE, /* empty tbl layout */
+	MANDOCERR_TBLLAYOUT_CHAR, /* invalid character in tbl layout: char */
+	MANDOCERR_TBLLAYOUT_PAR, /* unmatched parenthesis in tbl layout */
+	MANDOCERR_TBLDATA_NONE, /* tbl without any data cells */
+	MANDOCERR_TBLDATA_SPAN, /* ignoring data in spanned tbl cell: data */
+	MANDOCERR_TBLDATA_EXTRA, /* ignoring extra tbl data cells: data */
+	MANDOCERR_TBLDATA_BLK, /* data block open at end of tbl: macro */
+
+	/* related to document structure and macros */
+	MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */
+	MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */
+	MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
+	MANDOCERR_CHAR_BAD, /* skipping bad character: number */
+	MANDOCERR_MACRO, /* skipping unknown macro: macro */
+	MANDOCERR_REQ_NOMAC, /* skipping request outside macro: ... */
+	MANDOCERR_REQ_INSEC, /* skipping insecure request: request */
+	MANDOCERR_IT_STRAY, /* skipping item outside list: It ... */
+	MANDOCERR_TA_STRAY, /* skipping column outside column list: Ta */
+	MANDOCERR_BLK_NOTOPEN, /* skipping end of block that is not open */
+	MANDOCERR_RE_NOTOPEN, /* fewer RS blocks open, skipping: RE arg */
+	MANDOCERR_BLK_BROKEN, /* inserting missing end of block: macro ... */
+	MANDOCERR_BLK_NOEND, /* appending missing end of block: macro */
+
+	/* related to request and macro arguments */
+	MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
+	MANDOCERR_ARG_UNDEF, /* using macro argument outside macro */
+	MANDOCERR_ARG_NONUM, /* argument number is not numeric */
+	MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
+	MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
+	MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
+	MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */
+	MANDOCERR_CHAR_ARG, /* argument is not a character: char ... */
+	MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
+	MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
+	MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
+	MANDOCERR_IT_NONUM, /* skipping request without numeric argument */
+	MANDOCERR_SHIFT, /* excessive shift: ..., but max is ... */
+	MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
+	MANDOCERR_SO_FAIL, /* .so request failed */
+	MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
+	MANDOCERR_ARG_EXCESS, /* skipping excess arguments: macro ... args */
+	MANDOCERR_DIVZERO, /* divide by zero */
+
+	MANDOCERR_UNSUPP, /* ===== start of unsupported features ===== */
+
+	MANDOCERR_TOOLARGE, /* input too large */
+	MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */
+	MANDOCERR_ESC_UNSUPP, /* unsupported escape sequence: escape */
+	MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */
+	MANDOCERR_WHILE_NEST, /* nested .while loops */
+	MANDOCERR_WHILE_OUTOF, /* end of scope with open .while loop */
+	MANDOCERR_WHILE_INTO, /* end of .while loop in inner scope */
+	MANDOCERR_WHILE_FAIL, /* cannot continue this .while loop */
+	MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */
+	MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */
+	MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */
+
+	MANDOCERR_BADARG, /* ===== start of bad invocations ===== */
+
+	MANDOCERR_BADARG_BAD, /* bad argument */
+	MANDOCERR_BADARG_DUPE, /* duplicate argument */
+	MANDOCERR_BADVAL, /* does not take a value */
+	MANDOCERR_BADVAL_MISS, /* missing argument value */
+	MANDOCERR_BADVAL_BAD, /* bad argument value */
+	MANDOCERR_BADVAL_DUPE, /* duplicate argument value */
+	MANDOCERR_TAG, /* no such tag */
+
+	MANDOCERR_SYSERR, /* ===== start of system errors ===== */
+
+	MANDOCERR_DUP,
+	MANDOCERR_EXEC,
+	MANDOCERR_FDOPEN,
+	MANDOCERR_FFLUSH,
+	MANDOCERR_FORK,
+	MANDOCERR_FSTAT,
+	MANDOCERR_GETLINE,
+	MANDOCERR_GLOB,
+	MANDOCERR_GZCLOSE,
+	MANDOCERR_GZDOPEN,
+	MANDOCERR_MKSTEMP,
+	MANDOCERR_OPEN,
+	MANDOCERR_PLEDGE,
+	MANDOCERR_READ,
+	MANDOCERR_WAIT,
+	MANDOCERR_WRITE,
+
+	MANDOCERR_MAX
+};
+
+enum	mandoc_esc {
+	ESCAPE_ERROR = 0, /* bail! unparsable escape */
+	ESCAPE_UNSUPP, /* unsupported escape; ignore it */
+	ESCAPE_IGNORE, /* escape to be ignored */
+	ESCAPE_UNDEF, /* undefined escape; print literal character */
+	ESCAPE_SPECIAL, /* a regular special character */
+	ESCAPE_FONT, /* a generic font mode */
+	ESCAPE_FONTBOLD, /* bold font mode */
+	ESCAPE_FONTITALIC, /* italic font mode */
+	ESCAPE_FONTBI, /* bold italic font mode */
+	ESCAPE_FONTROMAN, /* roman font mode */
+	ESCAPE_FONTCW, /* constant width font mode */
+	ESCAPE_FONTPREV, /* previous font mode */
+	ESCAPE_NUMBERED, /* a numbered glyph */
+	ESCAPE_UNICODE, /* a unicode codepoint */
+	ESCAPE_DEVICE, /* print the output device name */
+	ESCAPE_BREAK, /* break the output line */
+	ESCAPE_NOSPACE, /* suppress space if the last on a line */
+	ESCAPE_HORIZ, /* horizontal movement */
+	ESCAPE_HLINE, /* horizontal line drawing */
+	ESCAPE_SKIPCHAR, /* skip the next character */
+	ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */
+};
+
+
+enum mandoc_esc	  mandoc_font(const char *, int sz);
+enum mandoc_esc	  mandoc_escape(const char **, const char **, int *);
+void		  mandoc_msg_setoutfile(FILE *);
+const char	 *mandoc_msg_getinfilename(void);
+void		  mandoc_msg_setinfilename(const char *);
+enum mandocerr	  mandoc_msg_getmin(void);
+void		  mandoc_msg_setmin(enum mandocerr);
+enum mandoclevel  mandoc_msg_getrc(void);
+void		  mandoc_msg_setrc(enum mandoclevel);
+void		  mandoc_msg(enum mandocerr, int, int, const char *, ...)
+			__attribute__((__format__ (__printf__, 4, 5)));
+void		  mandoc_msg_summary(void);
+void		  mchars_alloc(void);
+void		  mchars_free(void);
+int		  mchars_num2char(const char *, size_t);
+const char	 *mchars_uc2str(int);
+int		  mchars_num2uc(const char *, size_t);
+int		  mchars_spec2cp(const char *, size_t);
+const char	 *mchars_spec2str(const char *, size_t, size_t *);

Property changes on: vendor/mandoc/20190723/mandoc.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/mandoc_char.7
===================================================================
--- vendor/mandoc/20190723/mandoc_char.7	(nonexistent)
+++ vendor/mandoc/20190723/mandoc_char.7	(revision 350350)
@@ -0,0 +1,834 @@
+.\"	$Id: mandoc_char.7,v 1.76 2019/03/31 19:17:26 schwarze Exp $
+.\"
+.\" Copyright (c) 2003 Jason McIntyre 
+.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+.\" Copyright (c) 2011,2013,2015,2017,2018 Ingo Schwarze 
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: March 31 2019 $
+.Dt MANDOC_CHAR 7
+.Os
+.Sh NAME
+.Nm mandoc_char
+.Nd mandoc special characters
+.Sh DESCRIPTION
+This page documents the
+.Xr roff 7
+escape sequences accepted by
+.Xr mandoc 1
+to represent special characters in
+.Xr mdoc 7
+and
+.Xr man 7
+documents.
+.Pp
+The rendering depends on the
+.Xr mandoc 1
+output mode; it can be inspected by calling
+.Xr man 1
+on the
+.Nm
+manual page with different
+.Fl T
+arguments.
+In ASCII output, the rendering of some characters may be hard
+to interpret for the reader.
+Many are rendered as descriptive strings like
+.Qq  ,
+.Qq  ,
+or
+.Qq  ,
+which may look ugly, and many are replaced by similar ASCII characters.
+In particular, accented characters are usually shown without the accent.
+For that reason, try to avoid using any of the special characters
+documented here except those discussed in the
+.Sx DESCRIPTION ,
+unless they are essential for explaining the subject matter at hand,
+for example when documenting complicated mathematical functions.
+.Pp
+In particular, in English manual pages, do not use special-character
+escape sequences to represent national language characters in author
+names; instead, provide ASCII transcriptions of the names.
+.Ss Dashes and Hyphens
+In typography there are different types of dashes of various width:
+the hyphen (\(hy),
+the en-dash (\(en),
+the em-dash (\(em),
+and the mathematical minus sign (\(mi).
+.Pp
+Hyphens are used for adjectives;
+to separate the two parts of a compound word;
+or to separate a word across two successive lines of text.
+The hyphen does not need to be escaped:
+.Bd -unfilled -offset indent
+blue-eyed
+lorry-driver
+.Ed
+.Pp
+The en-dash is used to separate the two elements of a range,
+or can be used the same way as an em-dash.
+It should be written as
+.Sq \e(en :
+.Bd -unfilled -offset indent
+pp. 95\e(en97.
+Go away \e(en or else!
+.Ed
+.Pp
+The em-dash can be used to show an interruption
+or can be used the same way as colons, semi-colons, or parentheses.
+It should be written as
+.Sq \e(em :
+.Bd -unfilled -offset indent
+Three things \e(em apples, oranges, and bananas.
+This is not that \e(em rather, this is that.
+.Ed
+.Pp
+In
+.Xr roff 7
+documents, the minus sign is normally written as
+.Sq \e- .
+In manual pages, some style guides recommend to also use
+.Sq \e-
+if an ASCII 0x2d
+.Dq hyphen-minus
+output glyph that can be copied and pasted is desired in output modes
+supporting it, for example in
+.Fl T Cm utf8
+and
+.Fl T Cm html .
+But currently, no practically relevant manual page formatter requires
+that subtlety, so in manual pages, it is sufficient to write plain
+.Sq -
+to represent hyphen, minus, and hyphen-minus.
+.Pp
+If a word on a text input line contains a hyphen, a formatter may decide
+to insert an output line break after the hyphen if that helps filling
+the current output line, but the whole word would overflow the line.
+If it is important that the word is not broken across lines in this
+way, a zero-width space
+.Pq Sq \e&
+can be inserted before or after the hyphen.
+While
+.Xr mandoc 1
+never breaks the output line after hyphens adjacent to a zero-width
+space, after any of the other dash- or hyphen-like characters
+represented by escape sequences, or after hyphens inside words in
+macro arguments, other software may not respect these rules and may
+break the line even in such cases.
+.Pp
+Some
+.Xr roff 7
+implementations contains dictionaries allowing to break the line
+at syllable boundaries even inside words that contain no hyphens.
+Such automatic hyphenation is not supported by
+.Xr mandoc 1 ,
+which only breaks the line at whitespace, and inside words only
+after existing hyphens.
+.Ss Spaces
+To separate words in normal text, for indenting and alignment
+in literal context, and when none of the following special cases apply,
+just use the normal space character
+.Pq Sq \  .
+.Pp
+When filling text, output lines may be broken between words, i.e. at space
+characters.
+To prevent a line break between two particular words,
+use the unpaddable non-breaking space escape sequence
+.Pq Sq \e\ \&
+instead of the normal space character.
+For example, the input string
+.Dq number\e\ 1
+will be kept together as
+.Dq number\ 1
+on the same output line.
+.Pp
+On request and macro lines, the normal space character serves as an
+argument delimiter.
+To include whitespace into arguments, quoting is usually the best choice;
+see the MACRO SYNTAX section in
+.Xr roff 7 .
+In some cases, using the non-breaking space escape sequence
+.Pq Sq \e\ \&
+may be preferable.
+.Pp
+To escape macro names and to protect whitespace at the end
+of input lines, the zero-width space
+.Pq Sq \e&
+is often useful.
+For example, in
+.Xr mdoc 7 ,
+a normal space character can be displayed in single quotes in either
+of the following ways:
+.Pp
+.Dl .Sq \(dq \(dq
+.Dl .Sq \e \e&
+.Ss Quotes
+On request and macro lines, the double-quote character
+.Pq Sq \(dq
+is handled specially to allow quoting.
+One way to prevent this special handling is by using the
+.Sq \e(dq
+escape sequence.
+.Pp
+Note that on text lines, literal double-quote characters can be used
+verbatim.
+All other quote-like characters can be used verbatim as well,
+even on request and macro lines.
+.Ss Accents
+In output modes supporting such special output characters, for example
+.Fl T Cm pdf ,
+and sometimes less consistently in
+.Fl T Cm utf8 ,
+some
+.Xr roff 7
+formatters convert the following ASCII input characters to the
+following Unicode special output characters:
+.Bl -column x(ga U+2018 -offset indent
+.It \(ga Ta U+2018 Ta left single quotation mark
+.It \(aq Ta U+2019 Ta right single quotation mark
+.It \(ti Ta U+02DC Ta small tilde
+.It \(ha Ta U+02C6 Ta modifier letter circumflex
+.El
+.Pp
+In prose, this automatic substitution is often desirable;
+but when these characters have to be displayed as plain ASCII
+characters, for example in source code samples, they require
+escaping to render as follows:
+.Bl -column x(ga U+2018 -offset indent
+.It \e(ga Ta U+0060 Ta grave accent
+.It \e(aq Ta U+0027 Ta apostrophe
+.It \e(ti Ta U+007E Ta tilde
+.It \e(ha Ta U+005E Ta circumflex accent
+.El
+.Ss Periods
+The period
+.Pq Sq \&.
+is handled specially at the beginning of an input line,
+where it introduces a
+.Xr roff 7
+request or a macro, and when appearing alone as a macro argument in
+.Xr mdoc 7 .
+In such situations, prepend a zero-width space
+.Pq Sq \e&.
+to make it behave like normal text.
+.Pp
+Do not use the
+.Sq \e.
+escape sequence.
+It does not prevent special handling of the period.
+.Ss Backslashes
+To include a literal backslash
+.Pq Sq \e
+into the output, use the
+.Pq Sq \ee
+escape sequence.
+.Pp
+Note that doubling it
+.Pq Sq \e\e
+is not the right way to output a backslash.
+Because
+.Xr mandoc 1
+does not implement full
+.Xr roff 7
+functionality, it may work with
+.Xr mandoc 1 ,
+but it may have weird effects on complete
+.Xr roff 7
+implementations.
+.Sh SPECIAL CHARACTERS
+Special characters are encoded as
+.Sq \eX
+.Pq for a one-character escape ,
+.Sq \e(XX
+.Pq two-character ,
+and
+.Sq \e[N]
+.Pq N-character .
+For details, see the
+.Em Special Characters
+subsection of the
+.Xr roff 7
+manual.
+.Pp
+Spacing:
+.Bl -column "Input" "Description" -offset indent -compact
+.It Em Input Ta Em Description
+.It Sq \e\ \& Ta unpaddable non-breaking space
+.It \e\(ti   Ta paddable non-breaking space
+.It \e0      Ta digit-width space allowing line break
+.It \e|      Ta one-sixth \e(em narrow space, zero width in nroff mode
+.It \e^      Ta one-twelfth \e(em half-narrow space, zero width in nroff
+.It \e&      Ta zero-width non-breaking space
+.It \e)      Ta zero-width space transparent to end-of-sentence detection
+.It \e%      Ta zero-width space allowing hyphenation
+.It \e:      Ta zero-width space allowing line break
+.El
+.Pp
+Lines:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(ba    Ta \(ba        Ta bar
+.It \e(br    Ta \(br        Ta box rule
+.It \e(ul    Ta \(ul        Ta underscore
+.It \e(ru    Ta \(ru        Ta underscore (width 0.5m)
+.It \e(rn    Ta \(rn        Ta overline
+.It \e(bb    Ta \(bb        Ta broken bar
+.It \e(sl    Ta \(sl        Ta forward slash
+.It \e(rs    Ta \(rs        Ta backward slash
+.El
+.Pp
+Text markers:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(ci    Ta \(ci        Ta circle
+.It \e(bu    Ta \(bu        Ta bullet
+.It \e(dd    Ta \(dd        Ta double dagger
+.It \e(dg    Ta \(dg        Ta dagger
+.It \e(lz    Ta \(lz        Ta lozenge
+.It \e(sq    Ta \(sq        Ta white square
+.It \e(ps    Ta \(ps        Ta paragraph
+.It \e(sc    Ta \(sc        Ta section
+.It \e(lh    Ta \(lh        Ta left hand
+.It \e(rh    Ta \(rh        Ta right hand
+.It \e(at    Ta \(at        Ta at
+.It \e(sh    Ta \(sh        Ta hash (pound)
+.It \e(CR    Ta \(CR        Ta carriage return
+.It \e(OK    Ta \(OK        Ta check mark
+.It \e(CL    Ta \(CL        Ta club suit
+.It \e(SP    Ta \(SP        Ta spade suit
+.It \e(HE    Ta \(HE        Ta heart suit
+.It \e(DI    Ta \(DI        Ta diamond suit
+.El
+.Pp
+Legal symbols:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(co    Ta \(co        Ta copyright
+.It \e(rg    Ta \(rg        Ta registered
+.It \e(tm    Ta \(tm        Ta trademarked
+.El
+.Pp
+Punctuation:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(em    Ta \(em        Ta em-dash
+.It \e(en    Ta \(en        Ta en-dash
+.It \e(hy    Ta \(hy        Ta hyphen
+.It \ee      Ta \e          Ta back-slash
+.It \e.      Ta \.          Ta period
+.It \e(r!    Ta \(r!        Ta upside-down exclamation
+.It \e(r?    Ta \(r?        Ta upside-down question
+.El
+.Pp
+Quotes:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(Bq    Ta \(Bq        Ta right low double-quote
+.It \e(bq    Ta \(bq        Ta right low single-quote
+.It \e(lq    Ta \(lq        Ta left double-quote
+.It \e(rq    Ta \(rq        Ta right double-quote
+.It \e(oq    Ta \(oq        Ta left single-quote
+.It \e(cq    Ta \(cq        Ta right single-quote
+.It \e(aq    Ta \(aq        Ta apostrophe quote (ASCII character)
+.It \e(dq    Ta \(dq        Ta double quote (ASCII character)
+.It \e(Fo    Ta \(Fo        Ta left guillemet
+.It \e(Fc    Ta \(Fc        Ta right guillemet
+.It \e(fo    Ta \(fo        Ta left single guillemet
+.It \e(fc    Ta \(fc        Ta right single guillemet
+.El
+.Pp
+Brackets:
+.Bl -column "xxbracketrightbtx" Rendered Description -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(lB    Ta \(lB        Ta left bracket
+.It \e(rB    Ta \(rB        Ta right bracket
+.It \e(lC    Ta \(lC        Ta left brace
+.It \e(rC    Ta \(rC        Ta right brace
+.It \e(la    Ta \(la        Ta left angle
+.It \e(ra    Ta \(ra        Ta right angle
+.It \e(bv    Ta \(bv        Ta brace extension (special font)
+.It \e[braceex] Ta \[braceex] Ta brace extension
+.It \e[bracketlefttp] Ta \[bracketlefttp] Ta top-left hooked bracket
+.It \e[bracketleftbt] Ta \[bracketleftbt] Ta bottom-left hooked bracket
+.It \e[bracketleftex] Ta \[bracketleftex] Ta left hooked bracket extension
+.It \e[bracketrighttp] Ta \[bracketrighttp] Ta top-right hooked bracket
+.It \e[bracketrightbt] Ta \[bracketrightbt] Ta bottom-right hooked bracket
+.It \e[bracketrightex] Ta \[bracketrightex] Ta right hooked bracket extension
+.It \e(lt    Ta \(lt        Ta top-left hooked brace
+.It \e[bracelefttp] Ta \[bracelefttp] Ta top-left hooked brace
+.It \e(lk    Ta \(lk        Ta mid-left hooked brace
+.It \e[braceleftmid] Ta \[braceleftmid] Ta mid-left hooked brace
+.It \e(lb    Ta \(lb        Ta bottom-left hooked brace
+.It \e[braceleftbt] Ta \[braceleftbt] Ta bottom-left hooked brace
+.It \e[braceleftex] Ta \[braceleftex] Ta left hooked brace extension
+.It \e(rt    Ta \(rt        Ta top-left hooked brace
+.It \e[bracerighttp] Ta \[bracerighttp] Ta top-right hooked brace
+.It \e(rk    Ta \(rk        Ta mid-right hooked brace
+.It \e[bracerightmid] Ta \[bracerightmid] Ta mid-right hooked brace
+.It \e(rb    Ta \(rb        Ta bottom-right hooked brace
+.It \e[bracerightbt] Ta \[bracerightbt] Ta bottom-right hooked brace
+.It \e[bracerightex] Ta \[bracerightex] Ta right hooked brace extension
+.It \e[parenlefttp] Ta \[parenlefttp] Ta top-left hooked parenthesis
+.It \e[parenleftbt] Ta \[parenleftbt] Ta bottom-left hooked parenthesis
+.It \e[parenleftex] Ta \[parenleftex] Ta left hooked parenthesis extension
+.It \e[parenrighttp] Ta \[parenrighttp] Ta top-right hooked parenthesis
+.It \e[parenrightbt] Ta \[parenrightbt] Ta bottom-right hooked parenthesis
+.It \e[parenrightex] Ta \[parenrightex] Ta right hooked parenthesis extension
+.El
+.Pp
+Arrows:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(<-    Ta \(<-        Ta left arrow
+.It \e(->    Ta \(->        Ta right arrow
+.It \e(<>    Ta \(<>        Ta left-right arrow
+.It \e(da    Ta \(da        Ta down arrow
+.It \e(ua    Ta \(ua        Ta up arrow
+.It \e(va    Ta \(va        Ta up-down arrow
+.It \e(lA    Ta \(lA        Ta left double-arrow
+.It \e(rA    Ta \(rA        Ta right double-arrow
+.It \e(hA    Ta \(hA        Ta left-right double-arrow
+.It \e(uA    Ta \(uA        Ta up double-arrow
+.It \e(dA    Ta \(dA        Ta down double-arrow
+.It \e(vA    Ta \(vA        Ta up-down double-arrow
+.It \e(an    Ta \(an        Ta horizontal arrow extension
+.El
+.Pp
+Logical:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(AN    Ta \(AN        Ta logical and
+.It \e(OR    Ta \(OR        Ta logical or
+.It \e[tno]  Ta \[tno]      Ta logical not (text font)
+.It \e(no    Ta \(no        Ta logical not (special font)
+.It \e(te    Ta \(te        Ta existential quantifier
+.It \e(fa    Ta \(fa        Ta universal quantifier
+.It \e(st    Ta \(st        Ta such that
+.It \e(tf    Ta \(tf        Ta therefore
+.It \e(3d    Ta \(3d        Ta therefore
+.It \e(or    Ta \(or        Ta bitwise or
+.El
+.Pp
+Mathematical:
+.Bl -column "xxcoproductxx" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e-      Ta \-          Ta minus (text font)
+.It \e(mi    Ta \(mi        Ta minus (special font)
+.It +        Ta +           Ta plus (text font)
+.It \e(pl    Ta \(pl        Ta plus (special font)
+.It \e(-+    Ta \(-+        Ta minus-plus
+.It \e[t+-]  Ta \[t+-]      Ta plus-minus (text font)
+.It \e(+-    Ta \(+-        Ta plus-minus (special font)
+.It \e(pc    Ta \(pc        Ta center-dot
+.It \e[tmu]  Ta \[tmu]      Ta multiply (text font)
+.It \e(mu    Ta \(mu        Ta multiply (special font)
+.It \e(c*    Ta \(c*        Ta circle-multiply
+.It \e(c+    Ta \(c+        Ta circle-plus
+.It \e[tdi]  Ta \[tdi]      Ta divide (text font)
+.It \e(di    Ta \(di        Ta divide (special font)
+.It \e(f/    Ta \(f/        Ta fraction
+.It \e(**    Ta \(**        Ta asterisk
+.It \e(<=    Ta \(<=        Ta less-than-equal
+.It \e(>=    Ta \(>=        Ta greater-than-equal
+.It \e(<<    Ta \(<<        Ta much less
+.It \e(>>    Ta \(>>        Ta much greater
+.It \e(eq    Ta \(eq        Ta equal
+.It \e(!=    Ta \(!=        Ta not equal
+.It \e(==    Ta \(==        Ta equivalent
+.It \e(ne    Ta \(ne        Ta not equivalent
+.It \e(ap    Ta \(ap        Ta tilde operator
+.It \e(|=    Ta \(|=        Ta asymptotically equal
+.It \e(=\(ti Ta \(=~        Ta approximately equal
+.It \e(\(ti\(ti Ta \(~~        Ta almost equal
+.It \e(\(ti= Ta \(~=        Ta almost equal
+.It \e(pt    Ta \(pt        Ta proportionate
+.It \e(es    Ta \(es        Ta empty set
+.It \e(mo    Ta \(mo        Ta element
+.It \e(nm    Ta \(nm        Ta not element
+.It \e(sb    Ta \(sb        Ta proper subset
+.It \e(nb    Ta \(nb        Ta not subset
+.It \e(sp    Ta \(sp        Ta proper superset
+.It \e(nc    Ta \(nc        Ta not superset
+.It \e(ib    Ta \(ib        Ta reflexive subset
+.It \e(ip    Ta \(ip        Ta reflexive superset
+.It \e(ca    Ta \(ca        Ta intersection
+.It \e(cu    Ta \(cu        Ta union
+.It \e(/_    Ta \(/_        Ta angle
+.It \e(pp    Ta \(pp        Ta perpendicular
+.It \e(is    Ta \(is        Ta integral
+.It \e[integral] Ta \[integral] Ta integral
+.It \e[sum]    Ta \[sum]   Ta summation
+.It \e[product] Ta \[product] Ta product
+.It \e[coproduct] Ta \[coproduct] Ta coproduct
+.It \e(gr    Ta \(gr        Ta gradient
+.It \e(sr    Ta \(sr        Ta square root
+.It \e[sqrt] Ta \[sqrt]     Ta square root
+.It \e(lc    Ta \(lc        Ta left-ceiling
+.It \e(rc    Ta \(rc        Ta right-ceiling
+.It \e(lf    Ta \(lf        Ta left-floor
+.It \e(rf    Ta \(rf        Ta right-floor
+.It \e(if    Ta \(if        Ta infinity
+.It \e(Ah    Ta \(Ah        Ta aleph
+.It \e(Im    Ta \(Im        Ta imaginary
+.It \e(Re    Ta \(Re        Ta real
+.It \e(wp    Ta \(wp        Ta Weierstrass p
+.It \e(pd    Ta \(pd        Ta partial differential
+.It \e(-h    Ta \(-h        Ta Planck constant over 2\(*p
+.It \e[hbar] Ta \[hbar]     Ta Planck constant over 2\(*p
+.It \e(12    Ta \(12        Ta one-half
+.It \e(14    Ta \(14        Ta one-fourth
+.It \e(34    Ta \(34        Ta three-fourths
+.It \e(18    Ta \(18        Ta one-eighth
+.It \e(38    Ta \(38        Ta three-eighths
+.It \e(58    Ta \(58        Ta five-eighths
+.It \e(78    Ta \(78        Ta seven-eighths
+.It \e(S1    Ta \(S1        Ta superscript 1
+.It \e(S2    Ta \(S2        Ta superscript 2
+.It \e(S3    Ta \(S3        Ta superscript 3
+.El
+.Pp
+Ligatures:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(ff    Ta \(ff        Ta ff ligature
+.It \e(fi    Ta \(fi        Ta fi ligature
+.It \e(fl    Ta \(fl        Ta fl ligature
+.It \e(Fi    Ta \(Fi        Ta ffi ligature
+.It \e(Fl    Ta \(Fl        Ta ffl ligature
+.It \e(AE    Ta \(AE        Ta AE
+.It \e(ae    Ta \(ae        Ta ae
+.It \e(OE    Ta \(OE        Ta OE
+.It \e(oe    Ta \(oe        Ta oe
+.It \e(ss    Ta \(ss        Ta German eszett
+.It \e(IJ    Ta \(IJ        Ta IJ ligature
+.It \e(ij    Ta \(ij        Ta ij ligature
+.El
+.Pp
+Accents:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(a"    Ta \(a"        Ta Hungarian umlaut
+.It \e(a-    Ta \(a-        Ta macron
+.It \e(a.    Ta \(a.        Ta dotted
+.It \e(a^    Ta \(a^        Ta circumflex
+.It \e(aa    Ta \(aa        Ta acute
+.It \e\(aq   Ta \'          Ta acute
+.It \e(ga    Ta \(ga        Ta grave
+.It \e\(ga   Ta \`          Ta grave
+.It \e(ab    Ta \(ab        Ta breve
+.It \e(ac    Ta \(ac        Ta cedilla
+.It \e(ad    Ta \(ad        Ta dieresis
+.It \e(ah    Ta \(ah        Ta caron
+.It \e(ao    Ta \(ao        Ta ring
+.It \e(a\(ti Ta \(a~        Ta tilde
+.It \e(ho    Ta \(ho        Ta ogonek
+.It \e(ha    Ta \(ha        Ta hat (ASCII character)
+.It \e(ti    Ta \(ti        Ta tilde (ASCII character)
+.El
+.Pp
+Accented letters:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(\(aqA Ta \('A        Ta acute A
+.It \e(\(aqE Ta \('E        Ta acute E
+.It \e(\(aqI Ta \('I        Ta acute I
+.It \e(\(aqO Ta \('O        Ta acute O
+.It \e(\(aqU Ta \('U        Ta acute U
+.It \e(\(aqY Ta \('Y        Ta acute Y
+.It \e(\(aqa Ta \('a        Ta acute a
+.It \e(\(aqe Ta \('e        Ta acute e
+.It \e(\(aqi Ta \('i        Ta acute i
+.It \e(\(aqo Ta \('o        Ta acute o
+.It \e(\(aqu Ta \('u        Ta acute u
+.It \e(\(aqy Ta \('y        Ta acute y
+.It \e(\(gaA Ta \(`A        Ta grave A
+.It \e(\(gaE Ta \(`E        Ta grave E
+.It \e(\(gaI Ta \(`I        Ta grave I
+.It \e(\(gaO Ta \(`O        Ta grave O
+.It \e(\(gaU Ta \(`U        Ta grave U
+.It \e(\(gaa Ta \(`a        Ta grave a
+.It \e(\(gae Ta \(`e        Ta grave e
+.It \e(\(gai Ta \(`i        Ta grave i
+.It \e(\(gao Ta \(`i        Ta grave o
+.It \e(\(gau Ta \(`u        Ta grave u
+.It \e(\(tiA Ta \(~A        Ta tilde A
+.It \e(\(tiN Ta \(~N        Ta tilde N
+.It \e(\(tiO Ta \(~O        Ta tilde O
+.It \e(\(tia Ta \(~a        Ta tilde a
+.It \e(\(tin Ta \(~n        Ta tilde n
+.It \e(\(tio Ta \(~o        Ta tilde o
+.It \e(:A    Ta \(:A        Ta dieresis A
+.It \e(:E    Ta \(:E        Ta dieresis E
+.It \e(:I    Ta \(:I        Ta dieresis I
+.It \e(:O    Ta \(:O        Ta dieresis O
+.It \e(:U    Ta \(:U        Ta dieresis U
+.It \e(:a    Ta \(:a        Ta dieresis a
+.It \e(:e    Ta \(:e        Ta dieresis e
+.It \e(:i    Ta \(:i        Ta dieresis i
+.It \e(:o    Ta \(:o        Ta dieresis o
+.It \e(:u    Ta \(:u        Ta dieresis u
+.It \e(:y    Ta \(:y        Ta dieresis y
+.It \e(^A    Ta \(^A        Ta circumflex A
+.It \e(^E    Ta \(^E        Ta circumflex E
+.It \e(^I    Ta \(^I        Ta circumflex I
+.It \e(^O    Ta \(^O        Ta circumflex O
+.It \e(^U    Ta \(^U        Ta circumflex U
+.It \e(^a    Ta \(^a        Ta circumflex a
+.It \e(^e    Ta \(^e        Ta circumflex e
+.It \e(^i    Ta \(^i        Ta circumflex i
+.It \e(^o    Ta \(^o        Ta circumflex o
+.It \e(^u    Ta \(^u        Ta circumflex u
+.It \e(,C    Ta \(,C        Ta cedilla C
+.It \e(,c    Ta \(,c        Ta cedilla c
+.It \e(/L    Ta \(/L        Ta stroke L
+.It \e(/l    Ta \(/l        Ta stroke l
+.It \e(/O    Ta \(/O        Ta stroke O
+.It \e(/o    Ta \(/o        Ta stroke o
+.It \e(oA    Ta \(oA        Ta ring A
+.It \e(oa    Ta \(oa        Ta ring a
+.El
+.Pp
+Special letters:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(-D    Ta \(-D        Ta Eth
+.It \e(Sd    Ta \(Sd        Ta eth
+.It \e(TP    Ta \(TP        Ta Thorn
+.It \e(Tp    Ta \(Tp        Ta thorn
+.It \e(.i    Ta \(.i        Ta dotless i
+.It \e(.j    Ta \(.j        Ta dotless j
+.El
+.Pp
+Currency:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(Do    Ta \(Do        Ta dollar
+.It \e(ct    Ta \(ct        Ta cent
+.It \e(Eu    Ta \(Eu        Ta Euro symbol
+.It \e(eu    Ta \(eu        Ta Euro symbol
+.It \e(Ye    Ta \(Ye        Ta yen
+.It \e(Po    Ta \(Po        Ta pound
+.It \e(Cs    Ta \(Cs        Ta Scandinavian
+.It \e(Fn    Ta \(Fn        Ta florin
+.El
+.Pp
+Units:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(de    Ta \(de        Ta degree
+.It \e(%0    Ta \(%0        Ta per-thousand
+.It \e(fm    Ta \(fm        Ta minute
+.It \e(sd    Ta \(sd        Ta second
+.It \e(mc    Ta \(mc        Ta micro
+.It \e(Of    Ta \(Of        Ta Spanish female ordinal
+.It \e(Om    Ta \(Om        Ta Spanish masculine ordinal
+.El
+.Pp
+Greek letters:
+.Bl -column "Input" "Rendered" "Description" -offset indent -compact
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e(*A    Ta \(*A        Ta Alpha
+.It \e(*B    Ta \(*B        Ta Beta
+.It \e(*G    Ta \(*G        Ta Gamma
+.It \e(*D    Ta \(*D        Ta Delta
+.It \e(*E    Ta \(*E        Ta Epsilon
+.It \e(*Z    Ta \(*Z        Ta Zeta
+.It \e(*Y    Ta \(*Y        Ta Eta
+.It \e(*H    Ta \(*H        Ta Theta
+.It \e(*I    Ta \(*I        Ta Iota
+.It \e(*K    Ta \(*K        Ta Kappa
+.It \e(*L    Ta \(*L        Ta Lambda
+.It \e(*M    Ta \(*M        Ta Mu
+.It \e(*N    Ta \(*N        Ta Nu
+.It \e(*C    Ta \(*C        Ta Xi
+.It \e(*O    Ta \(*O        Ta Omicron
+.It \e(*P    Ta \(*P        Ta Pi
+.It \e(*R    Ta \(*R        Ta Rho
+.It \e(*S    Ta \(*S        Ta Sigma
+.It \e(*T    Ta \(*T        Ta Tau
+.It \e(*U    Ta \(*U        Ta Upsilon
+.It \e(*F    Ta \(*F        Ta Phi
+.It \e(*X    Ta \(*X        Ta Chi
+.It \e(*Q    Ta \(*Q        Ta Psi
+.It \e(*W    Ta \(*W        Ta Omega
+.It \e(*a    Ta \(*a        Ta alpha
+.It \e(*b    Ta \(*b        Ta beta
+.It \e(*g    Ta \(*g        Ta gamma
+.It \e(*d    Ta \(*d        Ta delta
+.It \e(*e    Ta \(*e        Ta epsilon
+.It \e(*z    Ta \(*z        Ta zeta
+.It \e(*y    Ta \(*y        Ta eta
+.It \e(*h    Ta \(*h        Ta theta
+.It \e(*i    Ta \(*i        Ta iota
+.It \e(*k    Ta \(*k        Ta kappa
+.It \e(*l    Ta \(*l        Ta lambda
+.It \e(*m    Ta \(*m        Ta mu
+.It \e(*n    Ta \(*n        Ta nu
+.It \e(*c    Ta \(*c        Ta xi
+.It \e(*o    Ta \(*o        Ta omicron
+.It \e(*p    Ta \(*p        Ta pi
+.It \e(*r    Ta \(*r        Ta rho
+.It \e(*s    Ta \(*s        Ta sigma
+.It \e(*t    Ta \(*t        Ta tau
+.It \e(*u    Ta \(*u        Ta upsilon
+.It \e(*f    Ta \(*f        Ta phi
+.It \e(*x    Ta \(*x        Ta chi
+.It \e(*q    Ta \(*q        Ta psi
+.It \e(*w    Ta \(*w        Ta omega
+.It \e(+h    Ta \(+h        Ta theta variant
+.It \e(+f    Ta \(+f        Ta phi variant
+.It \e(+p    Ta \(+p        Ta pi variant
+.It \e(+e    Ta \(+e        Ta epsilon variant
+.It \e(ts    Ta \(ts        Ta sigma terminal
+.El
+.Sh PREDEFINED STRINGS
+Predefined strings are inherited from the macro packages of historical
+troff implementations.
+They are
+.Em not recommended
+for use, as they differ across implementations.
+Manuals using these predefined strings are almost certainly not
+portable.
+.Pp
+Their syntax is similar to special characters, using
+.Sq \e*X
+.Pq for a one-character escape ,
+.Sq \e*(XX
+.Pq two-character ,
+and
+.Sq \e*[N]
+.Pq N-character .
+For details, see the
+.Em Predefined Strings
+subsection of the
+.Xr roff 7
+manual.
+.Bl -column "Input" "Rendered" "Description" -offset indent
+.It Em Input Ta Em Rendered Ta Em Description
+.It \e*(Ba   Ta \*(Ba       Ta vertical bar
+.It \e*(Ne   Ta \*(Ne       Ta not equal
+.It \e*(Ge   Ta \*(Ge       Ta greater-than-equal
+.It \e*(Le   Ta \*(Le       Ta less-than-equal
+.It \e*(Gt   Ta \*(Gt       Ta greater-than
+.It \e*(Lt   Ta \*(Lt       Ta less-than
+.It \e*(Pm   Ta \*(Pm       Ta plus-minus
+.It \e*(If   Ta \*(If       Ta infinity
+.It \e*(Pi   Ta \*(Pi       Ta pi
+.It \e*(Na   Ta \*(Na       Ta NaN
+.It \e*(Am   Ta \*(Am       Ta ampersand
+.It \e*R     Ta \*R         Ta restricted mark
+.It \e*(Tm   Ta \*(Tm       Ta trade mark
+.It \e*q     Ta \*q         Ta double-quote
+.It \e*(Rq   Ta \*(Rq       Ta right-double-quote
+.It \e*(Lq   Ta \*(Lq       Ta left-double-quote
+.It \e*(lp   Ta \*(lp       Ta right-parenthesis
+.It \e*(rp   Ta \*(rp       Ta left-parenthesis
+.It \e*(lq   Ta \*(lq       Ta left double-quote
+.It \e*(rq   Ta \*(rq       Ta right double-quote
+.It \e*(ua   Ta \*(ua       Ta up arrow
+.It \e*(va   Ta \*(va       Ta up-down arrow
+.It \e*(<=   Ta \*(<=       Ta less-than-equal
+.It \e*(>=   Ta \*(>=       Ta greater-than-equal
+.It \e*(aa   Ta \*(aa       Ta acute
+.It \e*(ga   Ta \*(ga       Ta grave
+.It \e*(Px   Ta \*(Px       Ta POSIX standard name
+.It \e*(Ai   Ta \*(Ai       Ta ANSI standard name
+.El
+.Sh UNICODE CHARACTERS
+The escape sequences
+.Pp
+.Dl \e[uXXXX] and \eC\(aquXXXX\(aq
+.Pp
+are interpreted as Unicode codepoints.
+The codepoint must be in the range above U+0080 and less than U+10FFFF.
+For compatibility, the hexadecimal digits
+.Sq A
+to
+.Sq F
+must be given as uppercase characters,
+and points must be zero-padded to four characters; if
+greater than four characters, no zero padding is allowed.
+Unicode surrogates are not allowed.
+.Sh NUMBERED CHARACTERS
+For backward compatibility with existing manuals,
+.Xr mandoc 1
+also supports the
+.Pp
+.Dl \eN\(aq Ns Ar number Ns \(aq and \e[ Ns Cm char Ns Ar number ]
+.Pp
+escape sequences, inserting the character
+.Ar number
+from the current character set into the output.
+Of course, this is inherently non-portable and is already marked
+as deprecated in the Heirloom roff manual;
+on top of that, the second form is a GNU extension.
+For example, do not use \eN\(aq34\(aq or \e[char34], use \e(dq,
+or even the plain
+.Sq \(dq
+character where possible.
+.Sh COMPATIBILITY
+This section documents compatibility between mandoc and other
+troff implementations, at this time limited to GNU troff
+.Pq Qq groff .
+.Pp
+.Bl -dash -compact
+.It
+The \eN\(aq\(aq escape sequence is limited to printable characters; in
+groff, it accepts arbitrary character numbers.
+.It
+In
+.Fl T Ns Cm ascii ,
+the
+\e(ss, \e(nm, \e(nb, \e(nc, \e(ib, \e(ip, \e(pp, \e[sum], \e[product],
+\e[coproduct], \e(gr, \e(-h, and \e(a. special characters render
+differently between mandoc and groff.
+.It
+In
+.Fl T Ns Cm html ,
+the \e(\(ti=, \e(nb, and \e(nc special characters render differently
+between mandoc and groff.
+.It
+The
+.Fl T Ns Cm ps
+and
+.Fl T Ns Cm pdf
+modes format like
+.Fl T Ns Cm ascii
+instead of rendering glyphs as in groff.
+.It
+The \e[radicalex], \e[sqrtex], and \e(ru special characters have been omitted
+from mandoc either because they are poorly documented or they have no
+known representation.
+.El
+.Sh SEE ALSO
+.Xr mandoc 1 ,
+.Xr man 7 ,
+.Xr mdoc 7 ,
+.Xr roff 7
+.Sh AUTHORS
+The
+.Nm
+manual page was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
+.Sh CAVEATS
+The predefined string
+.Sq \e*(Ba
+mimics the behaviour of the
+.Sq \&|
+character in
+.Xr mdoc 7 ;
+thus, if you wish to render a vertical bar with no side effects, use
+the
+.Sq \e(ba
+escape.

Property changes on: vendor/mandoc/20190723/mandoc_char.7
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/mandoc_headers.3
===================================================================
--- vendor/mandoc/20190723/mandoc_headers.3	(nonexistent)
+++ vendor/mandoc/20190723/mandoc_headers.3	(revision 350350)
@@ -0,0 +1,701 @@
+.\"	$Id: mandoc_headers.3,v 1.31 2019/03/17 18:21:45 schwarze Exp $
+.\"
+.\" Copyright (c) 2014-2019 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 17 2019 $
+.Dt MANDOC_HEADERS 3
+.Os
+.Sh NAME
+.Nm mandoc_headers
+.Nd ordering of mandoc include files
+.Sh DESCRIPTION
+To support a cleaner coding style, the mandoc header files do not
+contain any include directives and do not guard against multiple
+inclusion.
+The application developer has to make sure that the headers are
+included in a proper order, and that no header is included more
+than once.
+.Pp
+The headers and functions form three major groups:
+.Sx Parser interface ,
+.Sx Parser internals ,
+and
+.Sx Formatter interface .
+.Pp
+Various rules are given below prohibiting the inclusion of certain
+combinations of headers into the same file.
+The intention is to keep the following functional components
+separate from each other:
+.Pp
+.Bl -dash -offset indent -compact
+.It
+.Xr roff 7
+parser
+.It
+.Xr mdoc 7
+parser
+.It
+.Xr man 7
+parser
+.It
+.Xr tbl 7
+parser
+.It
+.Xr eqn 7
+parser
+.It
+terminal formatters
+.It
+HTML formatters
+.It
+search tools
+.It
+main programs
+.El
+.Pp
+Note that mere usage of an opaque struct type does
+.Em not
+require inclusion of the header where that type is defined.
+.Ss Parser interface
+Each of the following headers can be included without including
+any other mandoc header.
+These headers should be included before any other mandoc headers.
+.Bl -tag -width Ds
+.It Qq Pa mandoc_aux.h
+Memory allocation utility functions; can be used everywhere.
+.Pp
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides the functions documented in
+.Xr mandoc_malloc 3 .
+.It Qq Pa mandoc_ohash.h
+Hashing utility functions; can be used everywhere.
+.Pp
+Requires
+.In stddef.h
+for
+.Vt ptrdiff_t
+and
+.In stdint.h
+for
+.Vt uint32_t .
+.Pp
+Includes
+.In ohash.h
+and provides
+.Fn mandoc_ohash_init .
+.It Qq Pa mandoc.h
+Error handling, escape sequence, and character utilities;
+can be used everywhere.
+.Pp
+Requires
+.In sys/types.h
+for
+.Vt size_t
+and
+.In stdio.h
+for
+.Vt FILE .
+.Pp
+Provides
+.Vt enum mandoc_esc ,
+.Vt enum mandocerr ,
+.Vt enum mandoclevel ,
+the function
+.Xr mandoc_escape 3 ,
+the functions described in
+.Xr mchars_alloc 3 ,
+and the
+.Fn mandoc_msg*
+functions.
+.It Qq Pa roff.h
+Common data types for all syntax trees and related functions;
+can be used everywhere.
+.Pp
+Provides
+.Vt enum mandoc_os ,
+.Vt enum mdoc_endbody ,
+.Vt enum roff_macroset ,
+.Vt enum roff_sec ,
+.Vt enum roff_tok ,
+.Vt enum roff_type ,
+.Vt struct roff_man ,
+.Vt struct roff_meta ,
+.Vt struct roff_node ,
+the constant array
+.Va roff_name
+and the function
+.Fn deroff .
+.Pp
+Uses pointers to the types
+.Vt struct ohash
+from
+.Qq Pa mandoc_ohash.h ,
+.Vt struct mdoc_arg
+and
+.Vt union mdoc_data
+from
+.Qq Pa mdoc.h ,
+.Vt struct tbl_span
+from
+.Qq Pa tbl.h ,
+and
+.Vt struct eqn_box
+from
+.Qq Pa eqn.h
+as opaque struct members.
+.It Qq Pa tbl.h
+Data structures for the
+.Xr tbl 7
+parse tree; can be used everywhere.
+.Pp
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides
+.Vt enum tbl_cellt ,
+.Vt enum tbl_datt ,
+.Vt enum tbl_spant ,
+.Vt struct tbl_opts ,
+.Vt struct tbl_cell ,
+.Vt struct tbl_row ,
+.Vt struct tbl_dat ,
+and
+.Vt struct tbl_span .
+.It Qq Pa eqn.h
+Data structures for the
+.Xr eqn 7
+parse tree; can be used everywhere.
+.Pp
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides
+.Vt enum eqn_boxt ,
+.Vt enum eqn_fontt ,
+.Vt enum eqn_post ,
+and
+.Vt struct eqn_box .
+.It Qq Pa mandoc_parse.h
+Top level parser interface, for use in the main program
+and in the main parser, but not in formatters.
+.Pp
+Requires
+.Qq Pa mandoc.h
+for
+.Vt enum mandocerr
+and
+.Vt enum mandoclevel
+and
+.Qq Pa roff.h
+for
+.Vt enum mandoc_os .
+.Pp
+Uses the opaque type
+.Vt struct mparse
+from
+.Pa read.c
+for function prototypes.
+Uses
+.Vt struct roff_meta
+from
+.Qq Pa roff.h
+as an opaque type for function prototypes.
+.It Qq Pa mandoc_xr.h
+Cross reference validation; intended for use in the main program
+and in parsers, but not in formatters.
+.Pp
+Provides
+.Vt struct mandoc_xr
+and the functions
+.Fn mandoc_xr_reset ,
+.Fn mandoc_xr_add ,
+.Fn mandoc_xr_get ,
+and
+.Fn mandoc_xr_free .
+.El
+.Pp
+The following two require
+.Qq Pa roff.h
+but no other mandoc headers.
+Afterwards, any other mandoc headers can be included as needed.
+.Bl -tag -width Ds
+.It Qq Pa mdoc.h
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides
+.Vt enum mdocargt ,
+.Vt enum mdoc_auth ,
+.Vt enum mdoc_disp ,
+.Vt enum mdoc_font ,
+.Vt enum mdoc_list ,
+.Vt struct mdoc_argv ,
+.Vt struct mdoc_arg ,
+.Vt struct mdoc_an ,
+.Vt struct mdoc_bd ,
+.Vt struct mdoc_bf ,
+.Vt struct mdoc_bl ,
+.Vt struct mdoc_rs ,
+.Vt union mdoc_data ,
+and the functions
+.Fn mdoc_*
+described in
+.Xr mandoc 3 .
+.Pp
+Uses the types
+.Vt struct roff_node
+from
+.Qq Pa roff.h
+and
+.Vt struct roff_man
+from
+.Qq Pa roff_int.h
+as opaque types for function prototypes.
+.Pp
+When this header is included, the same file should not include
+internals of different parsers.
+.It Qq Pa man.h
+Provides the functions
+.Fn man_*
+described in
+.Xr mandoc 3 .
+.Pp
+Uses the type
+.Vt struct roff_man
+from
+.Qq Pa roff.h
+as an opaque type for function prototypes.
+.Pp
+When this header is included, the same file should not include
+internals of different parsers.
+.El
+.Ss Parser internals
+Most of the following headers require inclusion of a parser interface header
+before they can be included.
+All parser interface headers should precede all parser internal headers.
+When any parser internal headers are included, the same file should
+not include any formatter headers.
+.Bl -tag -width Ds
+.It Qq Pa libmandoc.h
+Requires
+.In sys/types.h
+for
+.Vt size_t
+and
+.Qq Pa mandoc.h
+for
+.Vt enum mandocerr .
+.Pp
+Provides
+.Vt struct buf ,
+utility functions needed by multiple parsers,
+and the top-level functions to call the parsers.
+.Pp
+Uses the opaque type
+.Vt struct roff
+from
+.Pa roff.c
+for function prototypes.
+Uses the type
+.Vt struct roff_man
+from
+.Qq Pa roff.h
+as an opaque type for function prototypes.
+.It Qq Pa roff_int.h
+Parser internals shared by multiple parsers.
+Can be used in all parsers, but not in main programs or formatters.
+.Pp
+Requires
+.Qq Pa roff.h
+for
+.Vt enum roff_type
+and
+.Vt enum roff_tok .
+.Pp
+Provides
+.Vt enum roff_next ,
+.Vt struct roff_man ,
+functions named
+.Fn roff_*
+to handle roff nodes,
+.Fn roffhash_alloc ,
+.Fn roffhash_find ,
+.Fn roffhash_free ,
+and
+.Fn roff_validate ,
+and the two special functions
+.Fn man_breakscope
+and
+.Fn mdoc_argv_free
+because the latter two are needed by
+.Pa roff.c .
+.Pp
+Uses the types
+.Vt struct ohash
+from
+.Qq Pa mandoc_ohash.h ,
+.Vt struct roff_node
+and
+.Vt struct roff_meta
+from
+.Qq Pa roff.h ,
+.Vt struct roff
+from
+.Pa roff.c ,
+and
+.Vt struct mdoc_arg
+from
+.Qq Pa mdoc.h
+as opaque types for function prototypes.
+.It Qq Pa libmdoc.h
+Requires
+.Qq Pa roff.h
+for
+.Vt enum roff_tok
+and
+.Vt enum roff_sec .
+.Pp
+Provides
+.Vt enum margserr ,
+.Vt enum mdelim ,
+.Vt struct mdoc_macro ,
+and many functions internal to the
+.Xr mdoc 7
+parser.
+.Pp
+Uses the types
+.Vt struct roff_node
+from
+.Qq Pa roff.h ,
+.Vt struct roff_man
+from
+.Qq Pa roff_int.h ,
+and
+.Vt struct mdoc_arg
+from
+.Qq Pa mdoc.h
+as opaque types for function prototypes.
+.Pp
+When this header is included, the same file should not include
+interfaces of different parsers.
+.It Qq Pa libman.h
+Requires
+.Qq Pa roff.h
+for
+.Vt enum roff_tok .
+.Pp
+Provides
+.Vt struct man_macro
+and some functions internal to the
+.Xr man 7
+parser.
+.Pp
+Uses the types
+.Vt struct roff_node
+from
+.Qq Pa roff.h
+and
+.Vt struct roff_man
+from
+.Qq Pa roff_int.h
+as opaque types for function prototypes.
+.Pp
+When this header is included, the same file should not include
+interfaces of different parsers.
+.It Qq Pa eqn_parse.h
+External interface of the
+.Xr eqn 7
+parser, for use in the
+.Xr roff 7
+and
+.Xr eqn 7
+parsers only.
+.Pp
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides
+.Vt struct eqn_node
+and the functions
+.Fn eqn_alloc ,
+.Fn eqn_box_new ,
+.Fn eqn_box_free ,
+.Fn eqn_free ,
+.Fn eqn_parse ,
+.Fn eqn_read ,
+and
+.Fn eqn_reset .
+.Pp
+Uses the type
+.Vt struct eqn_box
+from
+.Qq Pa mandoc.h
+as an opaque type for function prototypes.
+Uses the types
+.Vt struct roff_node
+from
+.Qq Pa roff.h
+and
+.Vt struct eqn_def
+from
+.Pa eqn.c
+as opaque struct members.
+.Pp
+When this header is included, the same file should not include
+internals of different parsers.
+.It Qq Pa tbl_parse.h
+External interface of the
+.Xr tbl 7
+parser, for use in the
+.Xr roff 7
+and
+.Xr tbl 7
+parsers only.
+.Pp
+Provides the functions documented in
+.Xr tbl 3 .
+.Pp
+Uses the types
+.Vt struct tbl_span
+from
+.Qq Pa tbl.h
+and
+.Vt struct tbl_node
+from
+.Qq Pa tbl_int.h
+as opaque types for function prototypes.
+.Pp
+When this header is included, the same file should not include
+internals of different parsers.
+.It Qq Pa tbl_int.h
+Internal interfaces of the
+.Xr tbl 7
+parser, for use inside the
+.Xr tbl 7
+parser only.
+.Pp
+Requires
+.Qq Pa tbl.h
+for
+.Vt struct tbl_opts .
+.Pp
+Provides
+.Vt enum tbl_part ,
+.Vt struct tbl_node ,
+and the functions
+.Fn tbl_option ,
+.Fn tbl_layout ,
+.Fn tbl_data ,
+.Fn tbl_cdata ,
+and
+.Fn tbl_reset .
+.Pp
+When this header is included, the same file should not include
+interfaces of different parsers.
+.El
+.Ss Formatter interface
+These headers should be included after any parser interface headers.
+No parser internal headers should be included by the same file.
+.Bl -tag -width Ds
+.It Qq Pa out.h
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides
+.Vt enum roffscale ,
+.Vt struct roffcol ,
+.Vt struct roffsu ,
+.Vt struct rofftbl ,
+.Fn a2roffsu ,
+and
+.Fn tblcalc .
+.Pp
+Uses
+.Vt struct tbl_span
+from
+.Qq Pa mandoc.h
+as an opaque type for function prototypes.
+.Pp
+When this header is included, the same file should not include
+.Qq Pa mansearch.h .
+.It Qq Pa term.h
+Requires
+.In sys/types.h
+for
+.Vt size_t
+and
+.Qq Pa out.h
+for
+.Vt struct roffsu
+and
+.Vt struct rofftbl .
+.Pp
+Provides
+.Vt enum termenc ,
+.Vt enum termfont ,
+.Vt enum termtype ,
+.Vt struct termp_tbl ,
+.Vt struct termp ,
+.Fn roff_term_pre ,
+and many terminal formatting functions.
+.Pp
+Uses the opaque type
+.Vt struct termp_ps
+from
+.Pa term_ps.c .
+Uses
+.Vt struct tbl_span
+and
+.Vt struct eqn_box
+from
+.Qq Pa mandoc.h
+and
+.Vt struct roff_meta
+and
+.Vt struct roff_node
+from
+.Qq Pa roff.h
+as opaque types for function prototypes.
+.Pp
+When this header is included, the same file should not include
+.Qq Pa html.h
+or
+.Qq Pa mansearch.h .
+.It Qq Pa html.h
+Requires
+.In sys/types.h
+for
+.Vt size_t ,
+.Qq Pa mandoc.h
+for
+.Vt enum mandoc_esc ,
+.Qq Pa roff.h
+for
+.Vt enum roff_tok ,
+and
+.Qq Pa out.h
+for
+.Vt struct roffsu
+and
+.Vt struct rofftbl .
+.Pp
+Provides
+.Vt enum htmltag ,
+.Vt enum htmlattr ,
+.Vt enum htmlfont ,
+.Vt struct tag ,
+.Vt struct tagq ,
+.Vt struct htmlpair ,
+.Vt struct html ,
+.Fn roff_html_pre ,
+and many HTML formatting functions.
+.Pp
+Uses
+.Vt struct tbl_span
+and
+.Vt struct eqn_box
+from
+.Qq Pa mandoc.h
+and
+.Vt struct roff_node
+from
+.Qq Pa roff.h
+as opaque types for function prototypes.
+.Pp
+When this header is included, the same file should not include
+.Qq Pa term.h
+or
+.Qq Pa mansearch.h .
+.It Qq Pa tag.h
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides an interface to generate
+.Xr ctags 1
+files for the
+.Ic :t
+functionality mentioned in
+.Xr man 1 .
+.It Qq Pa main.h
+Provides the top level steering functions for all formatters.
+.Pp
+Uses the type
+.Vt struct roff_meta
+from
+.Qq Pa roff.h
+as an opaque type for function prototypes.
+.It Qq Pa manconf.h
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides
+.Vt struct manconf ,
+.Vt struct manpaths ,
+.Vt struct manoutput ,
+and the functions
+.Fn manconf_parse ,
+.Fn manconf_output ,
+.Fn manconf_free ,
+and
+.Fn manpath_base .
+.It Qq Pa mansearch.h
+Requires
+.In sys/types.h
+for
+.Vt size_t
+and
+.In stdint.h
+for
+.Vt uint64_t .
+.Pp
+Provides
+.Vt enum argmode ,
+.Vt struct manpage ,
+.Vt struct mansearch ,
+and the functions
+.Fn mansearch
+and
+.Fn mansearch_free .
+.Pp
+Uses
+.Vt struct manpaths
+from
+.Qq Pa manconf.h
+as an opaque type for function prototypes.
+.Pp
+When this header is included, the same file should not include
+.Qq Pa out.h ,
+.Qq Pa term.h ,
+or
+.Qq Pa html.h .
+.El

Property changes on: vendor/mandoc/20190723/mandoc_headers.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/mandoc_msg.c
===================================================================
--- vendor/mandoc/20190723/mandoc_msg.c	(nonexistent)
+++ vendor/mandoc/20190723/mandoc_msg.c	(revision 350350)
@@ -0,0 +1,366 @@
+/*	$Id: mandoc_msg.c,v 1.8 2019/07/14 18:16:13 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2014-2019 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 "mandoc.h"
+
+static	const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = {
+	MANDOCERR_OK,
+	MANDOCERR_OK,
+	MANDOCERR_WARNING,
+	MANDOCERR_ERROR,
+	MANDOCERR_UNSUPP,
+	MANDOCERR_BADARG,
+	MANDOCERR_SYSERR
+};
+
+static	const char *const level_name[MANDOCLEVEL_MAX] = {
+	"SUCCESS",
+	"STYLE",
+	"WARNING",
+	"ERROR",
+	"UNSUPP",
+	"BADARG",
+	"SYSERR"
+};
+
+static	const char *const type_message[MANDOCERR_MAX] = {
+	"ok",
+
+	"base system convention",
+
+	"Mdocdate found",
+	"Mdocdate missing",
+	"unknown architecture",
+	"operating system explicitly specified",
+	"RCS id missing",
+	"referenced manual not found",
+
+	"generic style suggestion",
+
+	"legacy man(7) date format",
+	"normalizing date format to",
+	"lower case character in document title",
+	"duplicate RCS id",
+	"possible typo in section name",
+	"unterminated quoted argument",
+	"useless macro",
+	"consider using OS macro",
+	"errnos out of order",
+	"duplicate errno",
+	"trailing delimiter",
+	"no blank before trailing delimiter",
+	"fill mode already enabled, skipping",
+	"fill mode already disabled, skipping",
+	"verbatim \"--\", maybe consider using \\(em",
+	"function name without markup",
+	"whitespace at end of input line",
+	"bad comment style",
+
+	"generic warning",
+
+	/* related to the prologue */
+	"missing manual title, using UNTITLED",
+	"missing manual title, using \"\"",
+	"missing manual section, using \"\"",
+	"unknown manual section",
+	"missing date, using today's date",
+	"cannot parse date, using it verbatim",
+	"date in the future, using it anyway",
+	"missing Os macro, using \"\"",
+	"late prologue macro",
+	"prologue macros out of order",
+
+	/* related to document structure */
+	".so is fragile, better use ln(1)",
+	"no document body",
+	"content before first section header",
+	"first section is not \"NAME\"",
+	"NAME section without Nm before Nd",
+	"NAME section without description",
+	"description not at the end of NAME",
+	"bad NAME section content",
+	"missing comma before name",
+	"missing description line, using \"\"",
+	"description line outside NAME section",
+	"sections out of conventional order",
+	"duplicate section title",
+	"unexpected section",
+	"cross reference to self",
+	"unusual Xr order",
+	"unusual Xr punctuation",
+	"AUTHORS section without An macro",
+
+	/* related to macros and nesting */
+	"obsolete macro",
+	"macro neither callable nor escaped",
+	"skipping paragraph macro",
+	"moving paragraph macro out of list",
+	"skipping no-space macro",
+	"blocks badly nested",
+	"nested displays are not portable",
+	"moving content out of list",
+	"first macro on line",
+	"line scope broken",
+	"skipping blank line in line scope",
+
+	/* related to missing macro arguments */
+	"skipping empty request",
+	"conditional request controls empty scope",
+	"skipping empty macro",
+	"empty block",
+	"empty argument, using 0n",
+	"missing display type, using -ragged",
+	"list type is not the first argument",
+	"missing -width in -tag list, using 6n",
+	"missing utility name, using \"\"",
+	"missing function name, using \"\"",
+	"empty head in list item",
+	"empty list item",
+	"missing argument, using next line",
+	"missing font type, using \\fR",
+	"unknown font type, using \\fR",
+	"nothing follows prefix",
+	"empty reference block",
+	"missing section argument",
+	"missing -std argument, adding it",
+	"missing option string, using \"\"",
+	"missing resource identifier, using \"\"",
+	"missing eqn box, using \"\"",
+
+	/* related to bad macro arguments */
+	"duplicate argument",
+	"skipping duplicate argument",
+	"skipping duplicate display type",
+	"skipping duplicate list type",
+	"skipping -width argument",
+	"wrong number of cells",
+	"unknown AT&T UNIX version",
+	"comma in function argument",
+	"parenthesis in function name",
+	"unknown library name",
+	"invalid content in Rs block",
+	"invalid Boolean argument",
+	"argument contains two font escapes",
+	"unknown font, skipping request",
+	"odd number of characters in request",
+
+	/* related to plain text */
+	"blank line in fill mode, using .sp",
+	"tab in filled text",
+	"new sentence, new line",
+	"invalid escape sequence",
+	"undefined escape, printing literally",
+	"undefined string, using \"\"",
+
+	/* related to tables */
+	"tbl line starts with span",
+	"tbl column starts with span",
+	"skipping vertical bar in tbl layout",
+
+	"generic error",
+
+	/* related to tables */
+	"non-alphabetic character in tbl options",
+	"skipping unknown tbl option",
+	"missing tbl option argument",
+	"wrong tbl option argument size",
+	"empty tbl layout",
+	"invalid character in tbl layout",
+	"unmatched parenthesis in tbl layout",
+	"tbl without any data cells",
+	"ignoring data in spanned tbl cell",
+	"ignoring extra tbl data cells",
+	"data block open at end of tbl",
+
+	/* related to document structure and macros */
+	"duplicate prologue macro",
+	"skipping late title macro",
+	"input stack limit exceeded, infinite loop?",
+	"skipping bad character",
+	"skipping unknown macro",
+	"ignoring request outside macro",
+	"skipping insecure request",
+	"skipping item outside list",
+	"skipping column outside column list",
+	"skipping end of block that is not open",
+	"fewer RS blocks open, skipping",
+	"inserting missing end of block",
+	"appending missing end of block",
+
+	/* related to request and macro arguments */
+	"escaped character not allowed in a name",
+	"using macro argument outside macro",
+	"argument number is not numeric",
+	"NOT IMPLEMENTED: Bd -file",
+	"skipping display without arguments",
+	"missing list type, using -item",
+	"argument is not numeric, using 1",
+	"argument is not a character",
+	"missing manual name, using \"\"",
+	"uname(3) system call failed, using UNKNOWN",
+	"unknown standard specifier",
+	"skipping request without numeric argument",
+	"excessive shift",
+	"NOT IMPLEMENTED: .so with absolute path or \"..\"",
+	".so request failed",
+	"skipping all arguments",
+	"skipping excess arguments",
+	"divide by zero",
+
+	"unsupported feature",
+	"input too large",
+	"unsupported control character",
+	"unsupported escape sequence",
+	"unsupported roff request",
+	"nested .while loops",
+	"end of scope with open .while loop",
+	"end of .while loop in inner scope",
+	"cannot continue this .while loop",
+	"eqn delim option in tbl",
+	"unsupported tbl layout modifier",
+	"ignoring macro in table",
+
+	/* bad command line arguments */
+	NULL,
+	"bad command line argument",
+	"duplicate command line argument",
+	"option has a superfluous value",
+	"missing option value",
+	"bad option value",
+	"duplicate option value",
+	"no such tag",
+
+	/* system errors */
+	NULL,
+	"dup",
+	"exec",
+	"fdopen",
+	"fflush",
+	"fork",
+	"fstat",
+	"getline",
+	"glob",
+	"gzclose",
+	"gzdopen",
+	"mkstemp",
+	"open",
+	"pledge",
+	"read",
+	"wait",
+	"write",
+};
+
+static	FILE		*fileptr = NULL;
+static	const char	*filename = NULL;
+static	enum mandocerr	 min_type = MANDOCERR_BADARG;
+static	enum mandoclevel rc = MANDOCLEVEL_OK;
+
+
+void
+mandoc_msg_setoutfile(FILE *fp)
+{
+	fileptr = fp;
+}
+
+const char *
+mandoc_msg_getinfilename(void)
+{
+	return filename;
+}
+
+void
+mandoc_msg_setinfilename(const char *fn)
+{
+	filename = fn;
+}
+
+enum mandocerr
+mandoc_msg_getmin(void)
+{
+	return min_type;
+}
+
+void
+mandoc_msg_setmin(enum mandocerr t)
+{
+	min_type = t;
+}
+
+enum mandoclevel
+mandoc_msg_getrc(void)
+{
+	return rc;
+}
+
+void
+mandoc_msg_setrc(enum mandoclevel level)
+{
+	if (rc < level)
+		rc = level;
+}
+
+void
+mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...)
+{
+	va_list			 ap;
+	enum mandoclevel	 level;
+
+	if (t < min_type)
+		return;
+
+	level = MANDOCLEVEL_SYSERR;
+	while (t < lowest_type[level])
+		level--;
+	mandoc_msg_setrc(level);
+
+	if (fileptr == NULL)
+		return;
+
+	fprintf(fileptr, "%s:", getprogname());
+	if (filename != NULL)
+		fprintf(fileptr, " %s:", filename);
+
+	if (line > 0)
+		fprintf(fileptr, "%d:%d:", line, col + 1);
+
+	fprintf(fileptr, " %s", level_name[level]);
+	if (type_message[t] != NULL)
+		fprintf(fileptr, ": %s", type_message[t]);
+
+	if (fmt != NULL) {
+		fprintf(fileptr, ": ");
+		va_start(ap, fmt);
+		vfprintf(fileptr, fmt, ap);
+		va_end(ap);
+	}
+	fputc('\n', fileptr);
+}
+
+void
+mandoc_msg_summary(void)
+{
+	if (fileptr != NULL && rc != MANDOCLEVEL_OK)
+		fprintf(fileptr,
+		    "%s: see above the output for %s messages\n",
+		    getprogname(), level_name[rc]);
+}

Property changes on: vendor/mandoc/20190723/mandoc_msg.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/mandocdb.c
===================================================================
--- vendor/mandoc/20190723/mandocdb.c	(nonexistent)
+++ vendor/mandoc/20190723/mandocdb.c	(revision 350350)
@@ -0,0 +1,2367 @@
+/*	$Id: mandocdb.c,v 1.263 2019/05/03 18:17:12 schwarze Exp $ */
+/*
+ * Copyright (c) 2011, 2012 Kristaps Dzonsons 
+ * Copyright (c) 2011-2019 Ingo Schwarze 
+ * Copyright (c) 2016 Ed Maste 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is 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 
+#if HAVE_ERR
+#include 
+#endif
+#include 
+#include 
+#if HAVE_FTS
+#include 
+#else
+#include "compat_fts.h"
+#endif
+#include 
+#if HAVE_SANDBOX_INIT
+#include 
+#endif
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "mandoc_aux.h"
+#include "mandoc_ohash.h"
+#include "mandoc.h"
+#include "roff.h"
+#include "mdoc.h"
+#include "man.h"
+#include "mandoc_parse.h"
+#include "manconf.h"
+#include "mansearch.h"
+#include "dba_array.h"
+#include "dba.h"
+
+extern const char *const mansearch_keynames[];
+
+enum	op {
+	OP_DEFAULT = 0, /* new dbs from dir list or default config */
+	OP_CONFFILE, /* new databases from custom config file */
+	OP_UPDATE, /* delete/add entries in existing database */
+	OP_DELETE, /* delete entries from existing database */
+	OP_TEST /* change no databases, report potential problems */
+};
+
+struct	str {
+	const struct mpage *mpage; /* if set, the owning parse */
+	uint64_t	 mask; /* bitmask in sequence */
+	char		 key[]; /* rendered text */
+};
+
+struct	inodev {
+	ino_t		 st_ino;
+	dev_t		 st_dev;
+};
+
+struct	mpage {
+	struct inodev	 inodev;  /* used for hashing routine */
+	struct dba_array *dba;
+	char		*sec;     /* section from file content */
+	char		*arch;    /* architecture from file content */
+	char		*title;   /* title from file content */
+	char		*desc;    /* description from file content */
+	struct mpage	*next;    /* singly linked list */
+	struct mlink	*mlinks;  /* singly linked list */
+	int		 name_head_done;
+	enum form	 form;    /* format from file content */
+};
+
+struct	mlink {
+	char		 file[PATH_MAX]; /* filename rel. to manpath */
+	char		*dsec;    /* section from directory */
+	char		*arch;    /* architecture from directory */
+	char		*name;    /* name from file name (not empty) */
+	char		*fsec;    /* section from file name suffix */
+	struct mlink	*next;    /* singly linked list */
+	struct mpage	*mpage;   /* parent */
+	int		 gzip;	  /* filename has a .gz suffix */
+	enum form	 dform;   /* format from directory */
+	enum form	 fform;   /* format from file name suffix */
+};
+
+typedef	int (*mdoc_fp)(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+
+struct	mdoc_handler {
+	mdoc_fp		 fp; /* optional handler */
+	uint64_t	 mask;  /* set unless handler returns 0 */
+	int		 taboo;  /* node flags that must not be set */
+};
+
+
+int		 mandocdb(int, char *[]);
+
+static	void	 dbadd(struct dba *, struct mpage *);
+static	void	 dbadd_mlink(const struct mlink *mlink);
+static	void	 dbprune(struct dba *);
+static	void	 dbwrite(struct dba *);
+static	void	 filescan(const char *);
+#if HAVE_FTS_COMPARE_CONST
+static	int	 fts_compare(const FTSENT *const *, const FTSENT *const *);
+#else
+static	int	 fts_compare(const FTSENT **, const FTSENT **);
+#endif
+static	void	 mlink_add(struct mlink *, const struct stat *);
+static	void	 mlink_check(struct mpage *, struct mlink *);
+static	void	 mlink_free(struct mlink *);
+static	void	 mlinks_undupe(struct mpage *);
+static	void	 mpages_free(void);
+static	void	 mpages_merge(struct dba *, struct mparse *);
+static	void	 parse_cat(struct mpage *, int);
+static	void	 parse_man(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	void	 parse_mdoc(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_head(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_Fa(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_Fd(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	void	 parse_mdoc_fname(struct mpage *, const struct roff_node *);
+static	int	 parse_mdoc_Fn(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_Fo(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_Nd(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_Nm(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_Sh(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_Va(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	int	 parse_mdoc_Xr(struct mpage *, const struct roff_meta *,
+			const struct roff_node *);
+static	void	 putkey(const struct mpage *, char *, uint64_t);
+static	void	 putkeys(const struct mpage *, char *, size_t, uint64_t);
+static	void	 putmdockey(const struct mpage *,
+			const struct roff_node *, uint64_t, int);
+static	int	 render_string(char **, size_t *);
+static	void	 say(const char *, const char *, ...)
+			__attribute__((__format__ (__printf__, 2, 3)));
+static	int	 set_basedir(const char *, int);
+static	int	 treescan(void);
+static	size_t	 utf8(unsigned int, char [7]);
+
+static	int		 nodb; /* no database changes */
+static	int		 mparse_options; /* abort the parse early */
+static	int		 use_all; /* use all found files */
+static	int		 debug; /* print what we're doing */
+static	int		 warnings; /* warn about crap */
+static	int		 write_utf8; /* write UTF-8 output; else ASCII */
+static	int		 exitcode; /* to be returned by main */
+static	enum op		 op; /* operational mode */
+static	char		 basedir[PATH_MAX]; /* current base directory */
+static	struct mpage	*mpage_head; /* list of distinct manual pages */
+static	struct ohash	 mpages; /* table of distinct manual pages */
+static	struct ohash	 mlinks; /* table of directory entries */
+static	struct ohash	 names; /* table of all names */
+static	struct ohash	 strings; /* table of all strings */
+static	uint64_t	 name_mask;
+
+static	const struct mdoc_handler mdoc_handlers[MDOC_MAX - MDOC_Dd] = {
+	{ NULL, 0, NODE_NOPRT },  /* Dd */
+	{ NULL, 0, NODE_NOPRT },  /* Dt */
+	{ NULL, 0, NODE_NOPRT },  /* Os */
+	{ parse_mdoc_Sh, TYPE_Sh, 0 }, /* Sh */
+	{ parse_mdoc_head, TYPE_Ss, 0 }, /* Ss */
+	{ NULL, 0, 0 },  /* Pp */
+	{ NULL, 0, 0 },  /* D1 */
+	{ NULL, 0, 0 },  /* Dl */
+	{ NULL, 0, 0 },  /* Bd */
+	{ NULL, 0, 0 },  /* Ed */
+	{ NULL, 0, 0 },  /* Bl */
+	{ NULL, 0, 0 },  /* El */
+	{ NULL, 0, 0 },  /* It */
+	{ NULL, 0, 0 },  /* Ad */
+	{ NULL, TYPE_An, 0 },  /* An */
+	{ NULL, 0, 0 },  /* Ap */
+	{ NULL, TYPE_Ar, 0 },  /* Ar */
+	{ NULL, TYPE_Cd, 0 },  /* Cd */
+	{ NULL, TYPE_Cm, 0 },  /* Cm */
+	{ NULL, TYPE_Dv, 0 },  /* Dv */
+	{ NULL, TYPE_Er, 0 },  /* Er */
+	{ NULL, TYPE_Ev, 0 },  /* Ev */
+	{ NULL, 0, 0 },  /* Ex */
+	{ parse_mdoc_Fa, 0, 0 },  /* Fa */
+	{ parse_mdoc_Fd, 0, 0 },  /* Fd */
+	{ NULL, TYPE_Fl, 0 },  /* Fl */
+	{ parse_mdoc_Fn, 0, 0 },  /* Fn */
+	{ NULL, TYPE_Ft | TYPE_Vt, 0 },  /* Ft */
+	{ NULL, TYPE_Ic, 0 },  /* Ic */
+	{ NULL, TYPE_In, 0 },  /* In */
+	{ NULL, TYPE_Li, 0 },  /* Li */
+	{ parse_mdoc_Nd, 0, 0 },  /* Nd */
+	{ parse_mdoc_Nm, 0, 0 },  /* Nm */
+	{ NULL, 0, 0 },  /* Op */
+	{ NULL, 0, 0 },  /* Ot */
+	{ NULL, TYPE_Pa, NODE_NOSRC },  /* Pa */
+	{ NULL, 0, 0 },  /* Rv */
+	{ NULL, TYPE_St, 0 },  /* St */
+	{ parse_mdoc_Va, TYPE_Va, 0 },  /* Va */
+	{ parse_mdoc_Va, TYPE_Vt, 0 },  /* Vt */
+	{ parse_mdoc_Xr, 0, 0 },  /* Xr */
+	{ NULL, 0, 0 },  /* %A */
+	{ NULL, 0, 0 },  /* %B */
+	{ NULL, 0, 0 },  /* %D */
+	{ NULL, 0, 0 },  /* %I */
+	{ NULL, 0, 0 },  /* %J */
+	{ NULL, 0, 0 },  /* %N */
+	{ NULL, 0, 0 },  /* %O */
+	{ NULL, 0, 0 },  /* %P */
+	{ NULL, 0, 0 },  /* %R */
+	{ NULL, 0, 0 },  /* %T */
+	{ NULL, 0, 0 },  /* %V */
+	{ NULL, 0, 0 },  /* Ac */
+	{ NULL, 0, 0 },  /* Ao */
+	{ NULL, 0, 0 },  /* Aq */
+	{ NULL, TYPE_At, 0 },  /* At */
+	{ NULL, 0, 0 },  /* Bc */
+	{ NULL, 0, 0 },  /* Bf */
+	{ NULL, 0, 0 },  /* Bo */
+	{ NULL, 0, 0 },  /* Bq */
+	{ NULL, TYPE_Bsx, NODE_NOSRC },  /* Bsx */
+	{ NULL, TYPE_Bx, NODE_NOSRC },  /* Bx */
+	{ NULL, 0, 0 },  /* Db */
+	{ NULL, 0, 0 },  /* Dc */
+	{ NULL, 0, 0 },  /* Do */
+	{ NULL, 0, 0 },  /* Dq */
+	{ NULL, 0, 0 },  /* Ec */
+	{ NULL, 0, 0 },  /* Ef */
+	{ NULL, TYPE_Em, 0 },  /* Em */
+	{ NULL, 0, 0 },  /* Eo */
+	{ NULL, TYPE_Fx, NODE_NOSRC },  /* Fx */
+	{ NULL, TYPE_Ms, 0 },  /* Ms */
+	{ NULL, 0, 0 },  /* No */
+	{ NULL, 0, 0 },  /* Ns */
+	{ NULL, TYPE_Nx, NODE_NOSRC },  /* Nx */
+	{ NULL, TYPE_Ox, NODE_NOSRC },  /* Ox */
+	{ NULL, 0, 0 },  /* Pc */
+	{ NULL, 0, 0 },  /* Pf */
+	{ NULL, 0, 0 },  /* Po */
+	{ NULL, 0, 0 },  /* Pq */
+	{ NULL, 0, 0 },  /* Qc */
+	{ NULL, 0, 0 },  /* Ql */
+	{ NULL, 0, 0 },  /* Qo */
+	{ NULL, 0, 0 },  /* Qq */
+	{ NULL, 0, 0 },  /* Re */
+	{ NULL, 0, 0 },  /* Rs */
+	{ NULL, 0, 0 },  /* Sc */
+	{ NULL, 0, 0 },  /* So */
+	{ NULL, 0, 0 },  /* Sq */
+	{ NULL, 0, 0 },  /* Sm */
+	{ NULL, 0, 0 },  /* Sx */
+	{ NULL, TYPE_Sy, 0 },  /* Sy */
+	{ NULL, TYPE_Tn, 0 },  /* Tn */
+	{ NULL, 0, NODE_NOSRC },  /* Ux */
+	{ NULL, 0, 0 },  /* Xc */
+	{ NULL, 0, 0 },  /* Xo */
+	{ parse_mdoc_Fo, 0, 0 },  /* Fo */
+	{ NULL, 0, 0 },  /* Fc */
+	{ NULL, 0, 0 },  /* Oo */
+	{ NULL, 0, 0 },  /* Oc */
+	{ NULL, 0, 0 },  /* Bk */
+	{ NULL, 0, 0 },  /* Ek */
+	{ NULL, 0, 0 },  /* Bt */
+	{ NULL, 0, 0 },  /* Hf */
+	{ NULL, 0, 0 },  /* Fr */
+	{ NULL, 0, 0 },  /* Ud */
+	{ NULL, TYPE_Lb, NODE_NOSRC },  /* Lb */
+	{ NULL, 0, 0 },  /* Lp */
+	{ NULL, TYPE_Lk, 0 },  /* Lk */
+	{ NULL, TYPE_Mt, NODE_NOSRC },  /* Mt */
+	{ NULL, 0, 0 },  /* Brq */
+	{ NULL, 0, 0 },  /* Bro */
+	{ NULL, 0, 0 },  /* Brc */
+	{ NULL, 0, 0 },  /* %C */
+	{ NULL, 0, 0 },  /* Es */
+	{ NULL, 0, 0 },  /* En */
+	{ NULL, TYPE_Dx, NODE_NOSRC },  /* Dx */
+	{ NULL, 0, 0 },  /* %Q */
+	{ NULL, 0, 0 },  /* %U */
+	{ NULL, 0, 0 },  /* Ta */
+};
+
+
+int
+mandocdb(int argc, char *argv[])
+{
+	struct manconf	  conf;
+	struct mparse	 *mp;
+	struct dba	 *dba;
+	const char	 *path_arg, *progname;
+	size_t		  j, sz;
+	int		  ch, i;
+
+#if HAVE_PLEDGE
+	if (pledge("stdio rpath wpath cpath", NULL) == -1) {
+		warn("pledge");
+		return (int)MANDOCLEVEL_SYSERR;
+	}
+#endif
+
+#if HAVE_SANDBOX_INIT
+	if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) {
+		warnx("sandbox_init");
+		return (int)MANDOCLEVEL_SYSERR;
+	}
+#endif
+
+	memset(&conf, 0, sizeof(conf));
+
+	/*
+	 * We accept a few different invocations.
+	 * The CHECKOP macro makes sure that invocation styles don't
+	 * clobber each other.
+	 */
+#define	CHECKOP(_op, _ch) do \
+	if (OP_DEFAULT != (_op)) { \
+		warnx("-%c: Conflicting option", (_ch)); \
+		goto usage; \
+	} while (/*CONSTCOND*/0)
+
+	mparse_options = MPARSE_VALIDATE;
+	path_arg = NULL;
+	op = OP_DEFAULT;
+
+	while (-1 != (ch = getopt(argc, argv, "aC:Dd:npQT:tu:v")))
+		switch (ch) {
+		case 'a':
+			use_all = 1;
+			break;
+		case 'C':
+			CHECKOP(op, ch);
+			path_arg = optarg;
+			op = OP_CONFFILE;
+			break;
+		case 'D':
+			debug++;
+			break;
+		case 'd':
+			CHECKOP(op, ch);
+			path_arg = optarg;
+			op = OP_UPDATE;
+			break;
+		case 'n':
+			nodb = 1;
+			break;
+		case 'p':
+			warnings = 1;
+			break;
+		case 'Q':
+			mparse_options |= MPARSE_QUICK;
+			break;
+		case 'T':
+			if (strcmp(optarg, "utf8")) {
+				warnx("-T%s: Unsupported output format",
+				    optarg);
+				goto usage;
+			}
+			write_utf8 = 1;
+			break;
+		case 't':
+			CHECKOP(op, ch);
+			dup2(STDOUT_FILENO, STDERR_FILENO);
+			op = OP_TEST;
+			nodb = warnings = 1;
+			break;
+		case 'u':
+			CHECKOP(op, ch);
+			path_arg = optarg;
+			op = OP_DELETE;
+			break;
+		case 'v':
+			/* Compatibility with espie@'s makewhatis. */
+			break;
+		default:
+			goto usage;
+		}
+
+	argc -= optind;
+	argv += optind;
+
+#if HAVE_PLEDGE
+	if (nodb) {
+		if (pledge("stdio rpath", NULL) == -1) {
+			warn("pledge");
+			return (int)MANDOCLEVEL_SYSERR;
+		}
+	}
+#endif
+
+	if (OP_CONFFILE == op && argc > 0) {
+		warnx("-C: Too many arguments");
+		goto usage;
+	}
+
+	exitcode = (int)MANDOCLEVEL_OK;
+	mchars_alloc();
+	mp = mparse_alloc(mparse_options, MANDOC_OS_OTHER, NULL);
+	mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
+	mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
+
+	if (OP_UPDATE == op || OP_DELETE == op || OP_TEST == op) {
+
+		/*
+		 * Most of these deal with a specific directory.
+		 * Jump into that directory first.
+		 */
+		if (OP_TEST != op && 0 == set_basedir(path_arg, 1))
+			goto out;
+
+		dba = nodb ? dba_new(128) : dba_read(MANDOC_DB);
+		if (dba != NULL) {
+			/*
+			 * The existing database is usable.  Process
+			 * all files specified on the command-line.
+			 */
+			use_all = 1;
+			for (i = 0; i < argc; i++)
+				filescan(argv[i]);
+			if (nodb == 0)
+				dbprune(dba);
+		} else {
+			/* Database missing or corrupt. */
+			if (op != OP_UPDATE || errno != ENOENT)
+				say(MANDOC_DB, "%s: Automatically recreating"
+				    " from scratch", strerror(errno));
+			exitcode = (int)MANDOCLEVEL_OK;
+			op = OP_DEFAULT;
+			if (0 == treescan())
+				goto out;
+			dba = dba_new(128);
+		}
+		if (OP_DELETE != op)
+			mpages_merge(dba, mp);
+		if (nodb == 0)
+			dbwrite(dba);
+		dba_free(dba);
+	} else {
+		/*
+		 * If we have arguments, use them as our manpaths.
+		 * If we don't, use man.conf(5).
+		 */
+		if (argc > 0) {
+			conf.manpath.paths = mandoc_reallocarray(NULL,
+			    argc, sizeof(char *));
+			conf.manpath.sz = (size_t)argc;
+			for (i = 0; i < argc; i++)
+				conf.manpath.paths[i] = mandoc_strdup(argv[i]);
+		} else
+			manconf_parse(&conf, path_arg, NULL, NULL);
+
+		if (conf.manpath.sz == 0) {
+			exitcode = (int)MANDOCLEVEL_BADARG;
+			say("", "Empty manpath");
+		}
+
+		/*
+		 * First scan the tree rooted at a base directory, then
+		 * build a new database and finally move it into place.
+		 * Ignore zero-length directories and strip trailing
+		 * slashes.
+		 */
+		for (j = 0; j < conf.manpath.sz; j++) {
+			sz = strlen(conf.manpath.paths[j]);
+			if (sz && conf.manpath.paths[j][sz - 1] == '/')
+				conf.manpath.paths[j][--sz] = '\0';
+			if (0 == sz)
+				continue;
+
+			if (j) {
+				mandoc_ohash_init(&mpages, 6,
+				    offsetof(struct mpage, inodev));
+				mandoc_ohash_init(&mlinks, 6,
+				    offsetof(struct mlink, file));
+			}
+
+			if ( ! set_basedir(conf.manpath.paths[j], argc > 0))
+				continue;
+			if (0 == treescan())
+				continue;
+			dba = dba_new(128);
+			mpages_merge(dba, mp);
+			if (nodb == 0)
+				dbwrite(dba);
+			dba_free(dba);
+
+			if (j + 1 < conf.manpath.sz) {
+				mpages_free();
+				ohash_delete(&mpages);
+				ohash_delete(&mlinks);
+			}
+		}
+	}
+out:
+	manconf_free(&conf);
+	mparse_free(mp);
+	mchars_free();
+	mpages_free();
+	ohash_delete(&mpages);
+	ohash_delete(&mlinks);
+	return exitcode;
+usage:
+	progname = getprogname();
+	fprintf(stderr, "usage: %s [-aDnpQ] [-C file] [-Tutf8]\n"
+			"       %s [-aDnpQ] [-Tutf8] dir ...\n"
+			"       %s [-DnpQ] [-Tutf8] -d dir [file ...]\n"
+			"       %s [-Dnp] -u dir [file ...]\n"
+			"       %s [-Q] -t file ...\n",
+		        progname, progname, progname, progname, progname);
+
+	return (int)MANDOCLEVEL_BADARG;
+}
+
+/*
+ * To get a singly linked list in alpha order while inserting entries
+ * at the beginning, process directory entries in reverse alpha order.
+ */
+static int
+#if HAVE_FTS_COMPARE_CONST
+fts_compare(const FTSENT *const *a, const FTSENT *const *b)
+#else
+fts_compare(const FTSENT **a, const FTSENT **b)
+#endif
+{
+	return -strcmp((*a)->fts_name, (*b)->fts_name);
+}
+
+/*
+ * Scan a directory tree rooted at "basedir" for manpages.
+ * We use fts(), scanning directory parts along the way for clues to our
+ * section and architecture.
+ *
+ * If use_all has been specified, grok all files.
+ * If not, sanitise paths to the following:
+ *
+ *   [./]man*[/]/.
+ * or + * [./]cat
[/]/.0 + * + * TODO: accommodate for multi-language directories. + */ +static int +treescan(void) +{ + char buf[PATH_MAX]; + FTS *f; + FTSENT *ff; + struct mlink *mlink; + int gzip; + enum form dform; + char *dsec, *arch, *fsec, *cp; + const char *path; + const char *argv[2]; + + argv[0] = "."; + argv[1] = NULL; + + f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR, + fts_compare); + if (f == NULL) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say("", "&fts_open"); + return 0; + } + + dsec = arch = NULL; + dform = FORM_NONE; + + while ((ff = fts_read(f)) != NULL) { + path = ff->fts_path + 2; + switch (ff->fts_info) { + + /* + * Symbolic links require various sanity checks, + * then get handled just like regular files. + */ + case FTS_SL: + if (realpath(path, buf) == NULL) { + if (warnings) + say(path, "&realpath"); + continue; + } + if (strstr(buf, basedir) != buf +#ifdef HOMEBREWDIR + && strstr(buf, HOMEBREWDIR) != buf +#endif + ) { + if (warnings) say("", + "%s: outside base directory", buf); + continue; + } + /* Use logical inode to avoid mpages dupe. */ + if (stat(path, ff->fts_statp) == -1) { + if (warnings) + say(path, "&stat"); + continue; + } + /* FALLTHROUGH */ + + /* + * If we're a regular file, add an mlink by using the + * stored directory data and handling the filename. + */ + case FTS_F: + if ( ! strcmp(path, MANDOC_DB)) + continue; + if ( ! use_all && ff->fts_level < 2) { + if (warnings) + say(path, "Extraneous file"); + continue; + } + gzip = 0; + fsec = NULL; + while (fsec == NULL) { + fsec = strrchr(ff->fts_name, '.'); + if (fsec == NULL || strcmp(fsec+1, "gz")) + break; + gzip = 1; + *fsec = '\0'; + fsec = NULL; + } + if (fsec == NULL) { + if ( ! use_all) { + if (warnings) + say(path, + "No filename suffix"); + continue; + } + } else if ( ! strcmp(++fsec, "html")) { + if (warnings) + say(path, "Skip html"); + continue; + } else if ( ! strcmp(fsec, "ps")) { + if (warnings) + say(path, "Skip ps"); + continue; + } else if ( ! strcmp(fsec, "pdf")) { + if (warnings) + say(path, "Skip pdf"); + continue; + } else if ( ! use_all && + ((dform == FORM_SRC && + strncmp(fsec, dsec, strlen(dsec))) || + (dform == FORM_CAT && strcmp(fsec, "0")))) { + if (warnings) + say(path, "Wrong filename suffix"); + continue; + } else + fsec[-1] = '\0'; + + mlink = mandoc_calloc(1, sizeof(struct mlink)); + if (strlcpy(mlink->file, path, + sizeof(mlink->file)) >= + sizeof(mlink->file)) { + say(path, "Filename too long"); + free(mlink); + continue; + } + mlink->dform = dform; + mlink->dsec = dsec; + mlink->arch = arch; + mlink->name = ff->fts_name; + mlink->fsec = fsec; + mlink->gzip = gzip; + mlink_add(mlink, ff->fts_statp); + continue; + + case FTS_D: + case FTS_DP: + break; + + default: + if (warnings) + say(path, "Not a regular file"); + continue; + } + + switch (ff->fts_level) { + case 0: + /* Ignore the root directory. */ + break; + case 1: + /* + * This might contain manX/ or catX/. + * Try to infer this from the name. + * If we're not in use_all, enforce it. + */ + cp = ff->fts_name; + if (ff->fts_info == FTS_DP) { + dform = FORM_NONE; + dsec = NULL; + break; + } + + if ( ! strncmp(cp, "man", 3)) { + dform = FORM_SRC; + dsec = cp + 3; + } else if ( ! strncmp(cp, "cat", 3)) { + dform = FORM_CAT; + dsec = cp + 3; + } else { + dform = FORM_NONE; + dsec = NULL; + } + + if (dsec != NULL || use_all) + break; + + if (warnings) + say(path, "Unknown directory part"); + fts_set(f, ff, FTS_SKIP); + break; + case 2: + /* + * Possibly our architecture. + * If we're descending, keep tabs on it. + */ + if (ff->fts_info != FTS_DP && dsec != NULL) + arch = ff->fts_name; + else + arch = NULL; + break; + default: + if (ff->fts_info == FTS_DP || use_all) + break; + if (warnings) + say(path, "Extraneous directory part"); + fts_set(f, ff, FTS_SKIP); + break; + } + } + + fts_close(f); + return 1; +} + +/* + * Add a file to the mlinks table. + * Do not verify that it's a "valid" looking manpage (we'll do that + * later). + * + * Try to infer the manual section, architecture, and page name from the + * path, assuming it looks like + * + * [./]man*[/]/.
+ * or + * [./]cat
[/]/.0 + * + * See treescan() for the fts(3) version of this. + */ +static void +filescan(const char *file) +{ + char buf[PATH_MAX]; + struct stat st; + struct mlink *mlink; + char *p, *start; + + assert(use_all); + + if (0 == strncmp(file, "./", 2)) + file += 2; + + /* + * We have to do lstat(2) before realpath(3) loses + * the information whether this is a symbolic link. + * We need to know that because for symbolic links, + * we want to use the orginal file name, while for + * regular files, we want to use the real path. + */ + if (-1 == lstat(file, &st)) { + exitcode = (int)MANDOCLEVEL_BADARG; + say(file, "&lstat"); + return; + } else if (0 == ((S_IFREG | S_IFLNK) & st.st_mode)) { + exitcode = (int)MANDOCLEVEL_BADARG; + say(file, "Not a regular file"); + return; + } + + /* + * We have to resolve the file name to the real path + * in any case for the base directory check. + */ + if (NULL == realpath(file, buf)) { + exitcode = (int)MANDOCLEVEL_BADARG; + say(file, "&realpath"); + return; + } + + if (OP_TEST == op) + start = buf; + else if (strstr(buf, basedir) == buf) + start = buf + strlen(basedir); +#ifdef HOMEBREWDIR + else if (strstr(buf, HOMEBREWDIR) == buf) + start = buf; +#endif + else { + exitcode = (int)MANDOCLEVEL_BADARG; + say("", "%s: outside base directory", buf); + return; + } + + /* + * Now we are sure the file is inside our tree. + * If it is a symbolic link, ignore the real path + * and use the original name. + * This implies passing stuff like "cat1/../man1/foo.1" + * on the command line won't work. So don't do that. + * Note the stat(2) can still fail if the link target + * doesn't exist. + */ + if (S_IFLNK & st.st_mode) { + if (-1 == stat(buf, &st)) { + exitcode = (int)MANDOCLEVEL_BADARG; + say(file, "&stat"); + return; + } + if (strlcpy(buf, file, sizeof(buf)) >= sizeof(buf)) { + say(file, "Filename too long"); + return; + } + start = buf; + if (OP_TEST != op && strstr(buf, basedir) == buf) + start += strlen(basedir); + } + + mlink = mandoc_calloc(1, sizeof(struct mlink)); + mlink->dform = FORM_NONE; + if (strlcpy(mlink->file, start, sizeof(mlink->file)) >= + sizeof(mlink->file)) { + say(start, "Filename too long"); + free(mlink); + return; + } + + /* + * In test mode or when the original name is absolute + * but outside our tree, guess the base directory. + */ + + if (op == OP_TEST || (start == buf && *start == '/')) { + if (strncmp(buf, "man/", 4) == 0) + start = buf + 4; + else if ((start = strstr(buf, "/man/")) != NULL) + start += 5; + else + start = buf; + } + + /* + * First try to guess our directory structure. + * If we find a separator, try to look for man* or cat*. + * If we find one of these and what's underneath is a directory, + * assume it's an architecture. + */ + if (NULL != (p = strchr(start, '/'))) { + *p++ = '\0'; + if (0 == strncmp(start, "man", 3)) { + mlink->dform = FORM_SRC; + mlink->dsec = start + 3; + } else if (0 == strncmp(start, "cat", 3)) { + mlink->dform = FORM_CAT; + mlink->dsec = start + 3; + } + + start = p; + if (NULL != mlink->dsec && NULL != (p = strchr(start, '/'))) { + *p++ = '\0'; + mlink->arch = start; + start = p; + } + } + + /* + * Now check the file suffix. + * Suffix of `.0' indicates a catpage, `.1-9' is a manpage. + */ + p = strrchr(start, '\0'); + while (p-- > start && '/' != *p && '.' != *p) + /* Loop. */ ; + + if ('.' == *p) { + *p++ = '\0'; + mlink->fsec = p; + } + + /* + * Now try to parse the name. + * Use the filename portion of the path. + */ + mlink->name = start; + if (NULL != (p = strrchr(start, '/'))) { + mlink->name = p + 1; + *p = '\0'; + } + mlink_add(mlink, &st); +} + +static void +mlink_add(struct mlink *mlink, const struct stat *st) +{ + struct inodev inodev; + struct mpage *mpage; + unsigned int slot; + + assert(NULL != mlink->file); + + mlink->dsec = mandoc_strdup(mlink->dsec ? mlink->dsec : ""); + mlink->arch = mandoc_strdup(mlink->arch ? mlink->arch : ""); + mlink->name = mandoc_strdup(mlink->name ? mlink->name : ""); + mlink->fsec = mandoc_strdup(mlink->fsec ? mlink->fsec : ""); + + if ('0' == *mlink->fsec) { + free(mlink->fsec); + mlink->fsec = mandoc_strdup(mlink->dsec); + mlink->fform = FORM_CAT; + } else if ('1' <= *mlink->fsec && '9' >= *mlink->fsec) + mlink->fform = FORM_SRC; + else + mlink->fform = FORM_NONE; + + slot = ohash_qlookup(&mlinks, mlink->file); + assert(NULL == ohash_find(&mlinks, slot)); + ohash_insert(&mlinks, slot, mlink); + + memset(&inodev, 0, sizeof(inodev)); /* Clear padding. */ + inodev.st_ino = st->st_ino; + inodev.st_dev = st->st_dev; + slot = ohash_lookup_memory(&mpages, (char *)&inodev, + sizeof(struct inodev), inodev.st_ino); + mpage = ohash_find(&mpages, slot); + if (NULL == mpage) { + mpage = mandoc_calloc(1, sizeof(struct mpage)); + mpage->inodev.st_ino = inodev.st_ino; + mpage->inodev.st_dev = inodev.st_dev; + mpage->form = FORM_NONE; + mpage->next = mpage_head; + mpage_head = mpage; + ohash_insert(&mpages, slot, mpage); + } else + mlink->next = mpage->mlinks; + mpage->mlinks = mlink; + mlink->mpage = mpage; +} + +static void +mlink_free(struct mlink *mlink) +{ + + free(mlink->dsec); + free(mlink->arch); + free(mlink->name); + free(mlink->fsec); + free(mlink); +} + +static void +mpages_free(void) +{ + struct mpage *mpage; + struct mlink *mlink; + + while ((mpage = mpage_head) != NULL) { + while ((mlink = mpage->mlinks) != NULL) { + mpage->mlinks = mlink->next; + mlink_free(mlink); + } + mpage_head = mpage->next; + free(mpage->sec); + free(mpage->arch); + free(mpage->title); + free(mpage->desc); + free(mpage); + } +} + +/* + * For each mlink to the mpage, check whether the path looks like + * it is formatted, and if it does, check whether a source manual + * exists by the same name, ignoring the suffix. + * If both conditions hold, drop the mlink. + */ +static void +mlinks_undupe(struct mpage *mpage) +{ + char buf[PATH_MAX]; + struct mlink **prev; + struct mlink *mlink; + char *bufp; + + mpage->form = FORM_CAT; + prev = &mpage->mlinks; + while (NULL != (mlink = *prev)) { + if (FORM_CAT != mlink->dform) { + mpage->form = FORM_NONE; + goto nextlink; + } + (void)strlcpy(buf, mlink->file, sizeof(buf)); + bufp = strstr(buf, "cat"); + assert(NULL != bufp); + memcpy(bufp, "man", 3); + if (NULL != (bufp = strrchr(buf, '.'))) + *++bufp = '\0'; + (void)strlcat(buf, mlink->dsec, sizeof(buf)); + if (NULL == ohash_find(&mlinks, + ohash_qlookup(&mlinks, buf))) + goto nextlink; + if (warnings) + say(mlink->file, "Man source exists: %s", buf); + if (use_all) + goto nextlink; + *prev = mlink->next; + mlink_free(mlink); + continue; +nextlink: + prev = &(*prev)->next; + } +} + +static void +mlink_check(struct mpage *mpage, struct mlink *mlink) +{ + struct str *str; + unsigned int slot; + + /* + * Check whether the manual section given in a file + * agrees with the directory where the file is located. + * Some manuals have suffixes like (3p) on their + * section number either inside the file or in the + * directory name, some are linked into more than one + * section, like encrypt(1) = makekey(8). + */ + + if (FORM_SRC == mpage->form && + strcasecmp(mpage->sec, mlink->dsec)) + say(mlink->file, "Section \"%s\" manual in %s directory", + mpage->sec, mlink->dsec); + + /* + * Manual page directories exist for each kernel + * architecture as returned by machine(1). + * However, many manuals only depend on the + * application architecture as returned by arch(1). + * For example, some (2/ARM) manuals are shared + * across the "armish" and "zaurus" kernel + * architectures. + * A few manuals are even shared across completely + * different architectures, for example fdformat(1) + * on amd64, i386, and sparc64. + */ + + if (strcasecmp(mpage->arch, mlink->arch)) + say(mlink->file, "Architecture \"%s\" manual in " + "\"%s\" directory", mpage->arch, mlink->arch); + + /* + * XXX + * parse_cat() doesn't set NAME_TITLE yet. + */ + + if (FORM_CAT == mpage->form) + return; + + /* + * Check whether this mlink + * appears as a name in the NAME section. + */ + + slot = ohash_qlookup(&names, mlink->name); + str = ohash_find(&names, slot); + assert(NULL != str); + if ( ! (NAME_TITLE & str->mask)) + say(mlink->file, "Name missing in NAME section"); +} + +/* + * Run through the files in the global vector "mpages" + * and add them to the database specified in "basedir". + * + * This handles the parsing scheme itself, using the cues of directory + * and filename to determine whether the file is parsable or not. + */ +static void +mpages_merge(struct dba *dba, struct mparse *mp) +{ + struct mpage *mpage, *mpage_dest; + struct mlink *mlink, *mlink_dest; + struct roff_meta *meta; + char *cp; + int fd; + + for (mpage = mpage_head; mpage != NULL; mpage = mpage->next) { + mlinks_undupe(mpage); + if ((mlink = mpage->mlinks) == NULL) + continue; + + name_mask = NAME_MASK; + mandoc_ohash_init(&names, 4, offsetof(struct str, key)); + mandoc_ohash_init(&strings, 6, offsetof(struct str, key)); + mparse_reset(mp); + meta = NULL; + + if ((fd = mparse_open(mp, mlink->file)) == -1) { + say(mlink->file, "&open"); + goto nextpage; + } + + /* + * Interpret the file as mdoc(7) or man(7) source + * code, unless it is known to be formatted. + */ + if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) { + mparse_readfd(mp, fd, mlink->file); + close(fd); + fd = -1; + meta = mparse_result(mp); + } + + if (meta != NULL && meta->sodest != NULL) { + mlink_dest = ohash_find(&mlinks, + ohash_qlookup(&mlinks, meta->sodest)); + if (mlink_dest == NULL) { + mandoc_asprintf(&cp, "%s.gz", meta->sodest); + mlink_dest = ohash_find(&mlinks, + ohash_qlookup(&mlinks, cp)); + free(cp); + } + if (mlink_dest != NULL) { + + /* The .so target exists. */ + + mpage_dest = mlink_dest->mpage; + while (1) { + mlink->mpage = mpage_dest; + + /* + * If the target was already + * processed, add the links + * to the database now. + * Otherwise, this will + * happen when we come + * to the target. + */ + + if (mpage_dest->dba != NULL) + dbadd_mlink(mlink); + + if (mlink->next == NULL) + break; + mlink = mlink->next; + } + + /* Move all links to the target. */ + + mlink->next = mlink_dest->next; + mlink_dest->next = mpage->mlinks; + mpage->mlinks = NULL; + goto nextpage; + } + meta->macroset = MACROSET_NONE; + } + if (meta != NULL && meta->macroset == MACROSET_MDOC) { + mpage->form = FORM_SRC; + mpage->sec = meta->msec; + mpage->sec = mandoc_strdup( + mpage->sec == NULL ? "" : mpage->sec); + mpage->arch = meta->arch; + mpage->arch = mandoc_strdup( + mpage->arch == NULL ? "" : mpage->arch); + mpage->title = mandoc_strdup(meta->title); + } else if (meta != NULL && meta->macroset == MACROSET_MAN) { + if (*meta->msec != '\0' || *meta->title != '\0') { + mpage->form = FORM_SRC; + mpage->sec = mandoc_strdup(meta->msec); + mpage->arch = mandoc_strdup(mlink->arch); + mpage->title = mandoc_strdup(meta->title); + } else + meta = NULL; + } + + assert(mpage->desc == NULL); + if (meta == NULL || meta->sodest != NULL) { + mpage->sec = mandoc_strdup(mlink->dsec); + mpage->arch = mandoc_strdup(mlink->arch); + mpage->title = mandoc_strdup(mlink->name); + if (meta == NULL) { + mpage->form = FORM_CAT; + parse_cat(mpage, fd); + } else + mpage->form = FORM_SRC; + } else if (meta->macroset == MACROSET_MDOC) + parse_mdoc(mpage, meta, meta->first); + else + parse_man(mpage, meta, meta->first); + if (mpage->desc == NULL) { + mpage->desc = mandoc_strdup(mlink->name); + if (warnings) + say(mlink->file, "No one-line description, " + "using filename \"%s\"", mlink->name); + } + + for (mlink = mpage->mlinks; + mlink != NULL; + mlink = mlink->next) { + putkey(mpage, mlink->name, NAME_FILE); + if (warnings && !use_all) + mlink_check(mpage, mlink); + } + + dbadd(dba, mpage); + +nextpage: + ohash_delete(&strings); + ohash_delete(&names); + } +} + +static void +parse_cat(struct mpage *mpage, int fd) +{ + FILE *stream; + struct mlink *mlink; + char *line, *p, *title, *sec; + size_t linesz, plen, titlesz; + ssize_t len; + int offs; + + mlink = mpage->mlinks; + stream = fd == -1 ? fopen(mlink->file, "r") : fdopen(fd, "r"); + if (stream == NULL) { + if (fd != -1) + close(fd); + if (warnings) + say(mlink->file, "&fopen"); + return; + } + + line = NULL; + linesz = 0; + + /* Parse the section number from the header line. */ + + while (getline(&line, &linesz, stream) != -1) { + if (*line == '\n') + continue; + if ((sec = strchr(line, '(')) == NULL) + break; + if ((p = strchr(++sec, ')')) == NULL) + break; + free(mpage->sec); + mpage->sec = mandoc_strndup(sec, p - sec); + if (warnings && *mlink->dsec != '\0' && + strcasecmp(mpage->sec, mlink->dsec)) + say(mlink->file, + "Section \"%s\" manual in %s directory", + mpage->sec, mlink->dsec); + break; + } + + /* Skip to first blank line. */ + + while (line == NULL || *line != '\n') + if (getline(&line, &linesz, stream) == -1) + break; + + /* + * Assume the first line that is not indented + * is the first section header. Skip to it. + */ + + while (getline(&line, &linesz, stream) != -1) + if (*line != '\n' && *line != ' ') + break; + + /* + * Read up until the next section into a buffer. + * Strip the leading and trailing newline from each read line, + * appending a trailing space. + * Ignore empty (whitespace-only) lines. + */ + + titlesz = 0; + title = NULL; + + while ((len = getline(&line, &linesz, stream)) != -1) { + if (*line != ' ') + break; + offs = 0; + while (isspace((unsigned char)line[offs])) + offs++; + if (line[offs] == '\0') + continue; + title = mandoc_realloc(title, titlesz + len - offs); + memcpy(title + titlesz, line + offs, len - offs); + titlesz += len - offs; + title[titlesz - 1] = ' '; + } + free(line); + + /* + * If no page content can be found, or the input line + * is already the next section header, or there is no + * trailing newline, reuse the page title as the page + * description. + */ + + if (NULL == title || '\0' == *title) { + if (warnings) + say(mlink->file, "Cannot find NAME section"); + fclose(stream); + free(title); + return; + } + + title[titlesz - 1] = '\0'; + + /* + * Skip to the first dash. + * Use the remaining line as the description (no more than 70 + * bytes). + */ + + if (NULL != (p = strstr(title, "- "))) { + for (p += 2; ' ' == *p || '\b' == *p; p++) + /* Skip to next word. */ ; + } else { + if (warnings) + say(mlink->file, "No dash in title line, " + "reusing \"%s\" as one-line description", title); + p = title; + } + + plen = strlen(p); + + /* Strip backspace-encoding from line. */ + + while (NULL != (line = memchr(p, '\b', plen))) { + len = line - p; + if (0 == len) { + memmove(line, line + 1, plen--); + continue; + } + memmove(line - 1, line + 1, plen - len); + plen -= 2; + } + + /* + * Cut off excessive one-line descriptions. + * Bad pages are not worth better heuristics. + */ + + mpage->desc = mandoc_strndup(p, 150); + fclose(stream); + free(title); +} + +/* + * Put a type/word pair into the word database for this particular file. + */ +static void +putkey(const struct mpage *mpage, char *value, uint64_t type) +{ + putkeys(mpage, value, strlen(value), type); +} + +/* + * Grok all nodes at or below a certain mdoc node into putkey(). + */ +static void +putmdockey(const struct mpage *mpage, + const struct roff_node *n, uint64_t m, int taboo) +{ + + for ( ; NULL != n; n = n->next) { + if (n->flags & taboo) + continue; + if (NULL != n->child) + putmdockey(mpage, n->child, m, taboo); + if (n->type == ROFFT_TEXT) + putkey(mpage, n->string, m); + } +} + +static void +parse_man(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + const struct roff_node *head, *body; + char *start, *title; + char byte; + size_t sz; + + if (n == NULL) + return; + + /* + * We're only searching for one thing: the first text child in + * the BODY of a NAME section. Since we don't keep track of + * sections in -man, run some hoops to find out whether we're in + * the correct section or not. + */ + + if (n->type == ROFFT_BODY && n->tok == MAN_SH) { + body = n; + if ((head = body->parent->head) != NULL && + (head = head->child) != NULL && + head->next == NULL && + head->type == ROFFT_TEXT && + strcmp(head->string, "NAME") == 0 && + body->child != NULL) { + + /* + * Suck the entire NAME section into memory. + * Yes, we might run away. + * But too many manuals have big, spread-out + * NAME sections over many lines. + */ + + title = NULL; + deroff(&title, body); + if (NULL == title) + return; + + /* + * Go through a special heuristic dance here. + * Conventionally, one or more manual names are + * comma-specified prior to a whitespace, then a + * dash, then a description. Try to puzzle out + * the name parts here. + */ + + start = title; + for ( ;; ) { + sz = strcspn(start, " ,"); + if ('\0' == start[sz]) + break; + + byte = start[sz]; + start[sz] = '\0'; + + /* + * Assume a stray trailing comma in the + * name list if a name begins with a dash. + */ + + if ('-' == start[0] || + ('\\' == start[0] && '-' == start[1])) + break; + + putkey(mpage, start, NAME_TITLE); + if ( ! (mpage->name_head_done || + strcasecmp(start, meta->title))) { + putkey(mpage, start, NAME_HEAD); + mpage->name_head_done = 1; + } + + if (' ' == byte) { + start += sz + 1; + break; + } + + assert(',' == byte); + start += sz + 1; + while (' ' == *start) + start++; + } + + if (start == title) { + putkey(mpage, start, NAME_TITLE); + if ( ! (mpage->name_head_done || + strcasecmp(start, meta->title))) { + putkey(mpage, start, NAME_HEAD); + mpage->name_head_done = 1; + } + free(title); + return; + } + + while (isspace((unsigned char)*start)) + start++; + + if (0 == strncmp(start, "-", 1)) + start += 1; + else if (0 == strncmp(start, "\\-\\-", 4)) + start += 4; + else if (0 == strncmp(start, "\\-", 2)) + start += 2; + else if (0 == strncmp(start, "\\(en", 4)) + start += 4; + else if (0 == strncmp(start, "\\(em", 4)) + start += 4; + + while (' ' == *start) + start++; + + /* + * Cut off excessive one-line descriptions. + * Bad pages are not worth better heuristics. + */ + + mpage->desc = mandoc_strndup(start, 150); + free(title); + return; + } + } + + for (n = n->child; n; n = n->next) { + if (NULL != mpage->desc) + break; + parse_man(mpage, meta, n); + } +} + +static void +parse_mdoc(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + const struct mdoc_handler *handler; + + for (n = n->child; n != NULL; n = n->next) { + if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX) + continue; + assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); + handler = mdoc_handlers + (n->tok - MDOC_Dd); + if (n->flags & handler->taboo) + continue; + + switch (n->type) { + case ROFFT_ELEM: + case ROFFT_BLOCK: + case ROFFT_HEAD: + case ROFFT_BODY: + case ROFFT_TAIL: + if (handler->fp != NULL && + (*handler->fp)(mpage, meta, n) == 0) + break; + if (handler->mask) + putmdockey(mpage, n->child, + handler->mask, handler->taboo); + break; + default: + continue; + } + if (NULL != n->child) + parse_mdoc(mpage, meta, n); + } +} + +static int +parse_mdoc_Fa(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + uint64_t mask; + + mask = TYPE_Fa; + if (n->sec == SEC_SYNOPSIS) + mask |= TYPE_Vt; + + putmdockey(mpage, n->child, mask, 0); + return 0; +} + +static int +parse_mdoc_Fd(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + char *start, *end; + size_t sz; + + if (SEC_SYNOPSIS != n->sec || + NULL == (n = n->child) || + n->type != ROFFT_TEXT) + return 0; + + /* + * Only consider those `Fd' macro fields that begin with an + * "inclusion" token (versus, e.g., #define). + */ + + if (strcmp("#include", n->string)) + return 0; + + if ((n = n->next) == NULL || n->type != ROFFT_TEXT) + return 0; + + /* + * Strip away the enclosing angle brackets and make sure we're + * not zero-length. + */ + + start = n->string; + if ('<' == *start || '"' == *start) + start++; + + if (0 == (sz = strlen(start))) + return 0; + + end = &start[(int)sz - 1]; + if ('>' == *end || '"' == *end) + end--; + + if (end > start) + putkeys(mpage, start, end - start + 1, TYPE_In); + return 0; +} + +static void +parse_mdoc_fname(struct mpage *mpage, const struct roff_node *n) +{ + char *cp; + size_t sz; + + if (n->type != ROFFT_TEXT) + return; + + /* Skip function pointer punctuation. */ + + cp = n->string; + while (*cp == '(' || *cp == '*') + cp++; + sz = strcspn(cp, "()"); + + putkeys(mpage, cp, sz, TYPE_Fn); + if (n->sec == SEC_SYNOPSIS) + putkeys(mpage, cp, sz, NAME_SYN); +} + +static int +parse_mdoc_Fn(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + uint64_t mask; + + if (n->child == NULL) + return 0; + + parse_mdoc_fname(mpage, n->child); + + n = n->child->next; + if (n != NULL && n->type == ROFFT_TEXT) { + mask = TYPE_Fa; + if (n->sec == SEC_SYNOPSIS) + mask |= TYPE_Vt; + putmdockey(mpage, n, mask, 0); + } + + return 0; +} + +static int +parse_mdoc_Fo(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + + if (n->type != ROFFT_HEAD) + return 1; + + if (n->child != NULL) + parse_mdoc_fname(mpage, n->child); + + return 0; +} + +static int +parse_mdoc_Va(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + char *cp; + + if (n->type != ROFFT_ELEM && n->type != ROFFT_BODY) + return 0; + + if (n->child != NULL && + n->child->next == NULL && + n->child->type == ROFFT_TEXT) + return 1; + + cp = NULL; + deroff(&cp, n); + if (cp != NULL) { + putkey(mpage, cp, TYPE_Vt | (n->tok == MDOC_Va || + n->type == ROFFT_BODY ? TYPE_Va : 0)); + free(cp); + } + + return 0; +} + +static int +parse_mdoc_Xr(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + char *cp; + + if (NULL == (n = n->child)) + return 0; + + if (NULL == n->next) { + putkey(mpage, n->string, TYPE_Xr); + return 0; + } + + mandoc_asprintf(&cp, "%s(%s)", n->string, n->next->string); + putkey(mpage, cp, TYPE_Xr); + free(cp); + return 0; +} + +static int +parse_mdoc_Nd(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + + if (n->type == ROFFT_BODY) + deroff(&mpage->desc, n); + return 0; +} + +static int +parse_mdoc_Nm(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + + if (SEC_NAME == n->sec) + putmdockey(mpage, n->child, NAME_TITLE, 0); + else if (n->sec == SEC_SYNOPSIS && n->type == ROFFT_HEAD) { + if (n->child == NULL) + putkey(mpage, meta->name, NAME_SYN); + else + putmdockey(mpage, n->child, NAME_SYN, 0); + } + if ( ! (mpage->name_head_done || + n->child == NULL || n->child->string == NULL || + strcasecmp(n->child->string, meta->title))) { + putkey(mpage, n->child->string, NAME_HEAD); + mpage->name_head_done = 1; + } + return 0; +} + +static int +parse_mdoc_Sh(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + + return n->sec == SEC_CUSTOM && n->type == ROFFT_HEAD; +} + +static int +parse_mdoc_head(struct mpage *mpage, const struct roff_meta *meta, + const struct roff_node *n) +{ + + return n->type == ROFFT_HEAD; +} + +/* + * Add a string to the hash table for the current manual. + * Each string has a bitmask telling which macros it belongs to. + * When we finish the manual, we'll dump the table. + */ +static void +putkeys(const struct mpage *mpage, char *cp, size_t sz, uint64_t v) +{ + struct ohash *htab; + struct str *s; + const char *end; + unsigned int slot; + int i, mustfree; + + if (0 == sz) + return; + + mustfree = render_string(&cp, &sz); + + if (TYPE_Nm & v) { + htab = &names; + v &= name_mask; + if (v & NAME_FIRST) + name_mask &= ~NAME_FIRST; + if (debug > 1) + say(mpage->mlinks->file, + "Adding name %*s, bits=0x%llx", (int)sz, cp, + (unsigned long long)v); + } else { + htab = &strings; + if (debug > 1) + for (i = 0; i < KEY_MAX; i++) + if ((uint64_t)1 << i & v) + say(mpage->mlinks->file, + "Adding key %s=%*s", + mansearch_keynames[i], (int)sz, cp); + } + + end = cp + sz; + slot = ohash_qlookupi(htab, cp, &end); + s = ohash_find(htab, slot); + + if (NULL != s && mpage == s->mpage) { + s->mask |= v; + return; + } else if (NULL == s) { + s = mandoc_calloc(1, sizeof(struct str) + sz + 1); + memcpy(s->key, cp, sz); + ohash_insert(htab, slot, s); + } + s->mpage = mpage; + s->mask = v; + + if (mustfree) + free(cp); +} + +/* + * Take a Unicode codepoint and produce its UTF-8 encoding. + * This isn't the best way to do this, but it works. + * The magic numbers are from the UTF-8 packaging. + * They're not as scary as they seem: read the UTF-8 spec for details. + */ +static size_t +utf8(unsigned int cp, char out[7]) +{ + size_t rc; + + rc = 0; + if (cp <= 0x0000007F) { + rc = 1; + out[0] = (char)cp; + } else if (cp <= 0x000007FF) { + rc = 2; + out[0] = (cp >> 6 & 31) | 192; + out[1] = (cp & 63) | 128; + } else if (cp <= 0x0000FFFF) { + rc = 3; + out[0] = (cp >> 12 & 15) | 224; + out[1] = (cp >> 6 & 63) | 128; + out[2] = (cp & 63) | 128; + } else if (cp <= 0x001FFFFF) { + rc = 4; + out[0] = (cp >> 18 & 7) | 240; + out[1] = (cp >> 12 & 63) | 128; + out[2] = (cp >> 6 & 63) | 128; + out[3] = (cp & 63) | 128; + } else if (cp <= 0x03FFFFFF) { + rc = 5; + out[0] = (cp >> 24 & 3) | 248; + out[1] = (cp >> 18 & 63) | 128; + out[2] = (cp >> 12 & 63) | 128; + out[3] = (cp >> 6 & 63) | 128; + out[4] = (cp & 63) | 128; + } else if (cp <= 0x7FFFFFFF) { + rc = 6; + out[0] = (cp >> 30 & 1) | 252; + out[1] = (cp >> 24 & 63) | 128; + out[2] = (cp >> 18 & 63) | 128; + out[3] = (cp >> 12 & 63) | 128; + out[4] = (cp >> 6 & 63) | 128; + out[5] = (cp & 63) | 128; + } else + return 0; + + out[rc] = '\0'; + return rc; +} + +/* + * If the string contains escape sequences, + * replace it with an allocated rendering and return 1, + * such that the caller can free it after use. + * Otherwise, do nothing and return 0. + */ +static int +render_string(char **public, size_t *psz) +{ + const char *src, *scp, *addcp, *seq; + char *dst; + size_t ssz, dsz, addsz; + char utfbuf[7], res[6]; + int seqlen, unicode; + + res[0] = '\\'; + res[1] = '\t'; + res[2] = ASCII_NBRSP; + res[3] = ASCII_HYPH; + res[4] = ASCII_BREAK; + res[5] = '\0'; + + src = scp = *public; + ssz = *psz; + dst = NULL; + dsz = 0; + + while (scp < src + *psz) { + + /* Leave normal characters unchanged. */ + + if (strchr(res, *scp) == NULL) { + if (dst != NULL) + dst[dsz++] = *scp; + scp++; + continue; + } + + /* + * Found something that requires replacing, + * make sure we have a destination buffer. + */ + + if (dst == NULL) { + dst = mandoc_malloc(ssz + 1); + dsz = scp - src; + memcpy(dst, src, dsz); + } + + /* Handle single-char special characters. */ + + switch (*scp) { + case '\\': + break; + case '\t': + case ASCII_NBRSP: + dst[dsz++] = ' '; + scp++; + continue; + case ASCII_HYPH: + dst[dsz++] = '-'; + /* FALLTHROUGH */ + case ASCII_BREAK: + scp++; + continue; + default: + abort(); + } + + /* + * Found an escape sequence. + * Read past the slash, then parse it. + * Ignore everything except characters. + */ + + scp++; + if (mandoc_escape(&scp, &seq, &seqlen) != ESCAPE_SPECIAL) + continue; + + /* + * Render the special character + * as either UTF-8 or ASCII. + */ + + if (write_utf8) { + unicode = mchars_spec2cp(seq, seqlen); + if (unicode <= 0) + continue; + addsz = utf8(unicode, utfbuf); + if (addsz == 0) + continue; + addcp = utfbuf; + } else { + addcp = mchars_spec2str(seq, seqlen, &addsz); + if (addcp == NULL) + continue; + if (*addcp == ASCII_NBRSP) { + addcp = " "; + addsz = 1; + } + } + + /* Copy the rendered glyph into the stream. */ + + ssz += addsz; + dst = mandoc_realloc(dst, ssz + 1); + memcpy(dst + dsz, addcp, addsz); + dsz += addsz; + } + if (dst != NULL) { + *public = dst; + *psz = dsz; + } + + /* Trim trailing whitespace and NUL-terminate. */ + + while (*psz > 0 && (*public)[*psz - 1] == ' ') + --*psz; + if (dst != NULL) { + (*public)[*psz] = '\0'; + return 1; + } else + return 0; +} + +static void +dbadd_mlink(const struct mlink *mlink) +{ + dba_page_alias(mlink->mpage->dba, mlink->name, NAME_FILE); + dba_page_add(mlink->mpage->dba, DBP_SECT, mlink->dsec); + dba_page_add(mlink->mpage->dba, DBP_SECT, mlink->fsec); + dba_page_add(mlink->mpage->dba, DBP_ARCH, mlink->arch); + dba_page_add(mlink->mpage->dba, DBP_FILE, mlink->file); +} + +/* + * Flush the current page's terms (and their bits) into the database. + * Also, handle escape sequences at the last possible moment. + */ +static void +dbadd(struct dba *dba, struct mpage *mpage) +{ + struct mlink *mlink; + struct str *key; + char *cp; + uint64_t mask; + size_t i; + unsigned int slot; + int mustfree; + + mlink = mpage->mlinks; + + if (nodb) { + for (key = ohash_first(&names, &slot); NULL != key; + key = ohash_next(&names, &slot)) + free(key); + for (key = ohash_first(&strings, &slot); NULL != key; + key = ohash_next(&strings, &slot)) + free(key); + if (0 == debug) + return; + while (NULL != mlink) { + fputs(mlink->name, stdout); + if (NULL == mlink->next || + strcmp(mlink->dsec, mlink->next->dsec) || + strcmp(mlink->fsec, mlink->next->fsec) || + strcmp(mlink->arch, mlink->next->arch)) { + putchar('('); + if ('\0' == *mlink->dsec) + fputs(mlink->fsec, stdout); + else + fputs(mlink->dsec, stdout); + if ('\0' != *mlink->arch) + printf("/%s", mlink->arch); + putchar(')'); + } + mlink = mlink->next; + if (NULL != mlink) + fputs(", ", stdout); + } + printf(" - %s\n", mpage->desc); + return; + } + + if (debug) + say(mlink->file, "Adding to database"); + + cp = mpage->desc; + i = strlen(cp); + mustfree = render_string(&cp, &i); + mpage->dba = dba_page_new(dba->pages, + *mpage->arch == '\0' ? mlink->arch : mpage->arch, + cp, mlink->file, mpage->form); + if (mustfree) + free(cp); + dba_page_add(mpage->dba, DBP_SECT, mpage->sec); + + while (mlink != NULL) { + dbadd_mlink(mlink); + mlink = mlink->next; + } + + for (key = ohash_first(&names, &slot); NULL != key; + key = ohash_next(&names, &slot)) { + assert(key->mpage == mpage); + dba_page_alias(mpage->dba, key->key, key->mask); + free(key); + } + for (key = ohash_first(&strings, &slot); NULL != key; + key = ohash_next(&strings, &slot)) { + assert(key->mpage == mpage); + i = 0; + for (mask = TYPE_Xr; mask <= TYPE_Lb; mask *= 2) { + if (key->mask & mask) + dba_macro_add(dba->macros, i, + key->key, mpage->dba); + i++; + } + free(key); + } +} + +static void +dbprune(struct dba *dba) +{ + struct dba_array *page, *files; + char *file; + + dba_array_FOREACH(dba->pages, page) { + files = dba_array_get(page, DBP_FILE); + dba_array_FOREACH(files, file) { + if (*file < ' ') + file++; + if (ohash_find(&mlinks, ohash_qlookup(&mlinks, + file)) != NULL) { + if (debug) + say(file, "Deleting from database"); + dba_array_del(dba->pages); + break; + } + } + } +} + +/* + * Write the database from memory to disk. + */ +static void +dbwrite(struct dba *dba) +{ + struct stat sb1, sb2; + char tfn[33], *cp1, *cp2; + off_t i; + int fd1, fd2; + + /* + * Do not write empty databases, and delete existing ones + * when makewhatis -u causes them to become empty. + */ + + dba_array_start(dba->pages); + if (dba_array_next(dba->pages) == NULL) { + if (unlink(MANDOC_DB) == -1 && errno != ENOENT) + say(MANDOC_DB, "&unlink"); + return; + } + + /* + * Build the database in a temporary file, + * then atomically move it into place. + */ + + if (dba_write(MANDOC_DB "~", dba) != -1) { + if (rename(MANDOC_DB "~", MANDOC_DB) == -1) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say(MANDOC_DB, "&rename"); + unlink(MANDOC_DB "~"); + } + return; + } + + /* + * We lack write permission and cannot replace the database + * file, but let's at least check whether the data changed. + */ + + (void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn)); + if (mkdtemp(tfn) == NULL) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say("", "&%s", tfn); + return; + } + cp1 = cp2 = MAP_FAILED; + fd1 = fd2 = -1; + (void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn)); + if (dba_write(tfn, dba) == -1) { + say(tfn, "&dba_write"); + goto err; + } + if ((fd1 = open(MANDOC_DB, O_RDONLY, 0)) == -1) { + say(MANDOC_DB, "&open"); + goto err; + } + if ((fd2 = open(tfn, O_RDONLY, 0)) == -1) { + say(tfn, "&open"); + goto err; + } + if (fstat(fd1, &sb1) == -1) { + say(MANDOC_DB, "&fstat"); + goto err; + } + if (fstat(fd2, &sb2) == -1) { + say(tfn, "&fstat"); + goto err; + } + if (sb1.st_size != sb2.st_size) + goto err; + if ((cp1 = mmap(NULL, sb1.st_size, PROT_READ, MAP_PRIVATE, + fd1, 0)) == MAP_FAILED) { + say(MANDOC_DB, "&mmap"); + goto err; + } + if ((cp2 = mmap(NULL, sb2.st_size, PROT_READ, MAP_PRIVATE, + fd2, 0)) == MAP_FAILED) { + say(tfn, "&mmap"); + goto err; + } + for (i = 0; i < sb1.st_size; i++) + if (cp1[i] != cp2[i]) + goto err; + goto out; + +err: + exitcode = (int)MANDOCLEVEL_SYSERR; + say(MANDOC_DB, "Data changed, but cannot replace database"); + +out: + if (cp1 != MAP_FAILED) + munmap(cp1, sb1.st_size); + if (cp2 != MAP_FAILED) + munmap(cp2, sb2.st_size); + if (fd1 != -1) + close(fd1); + if (fd2 != -1) + close(fd2); + unlink(tfn); + *strrchr(tfn, '/') = '\0'; + rmdir(tfn); +} + +static int +set_basedir(const char *targetdir, int report_baddir) +{ + static char startdir[PATH_MAX]; + static int getcwd_status; /* 1 = ok, 2 = failure */ + static int chdir_status; /* 1 = changed directory */ + char *cp; + + /* + * Remember the original working directory, if possible. + * This will be needed if the second or a later directory + * on the command line is given as a relative path. + * Do not error out if the current directory is not + * searchable: Maybe it won't be needed after all. + */ + if (0 == getcwd_status) { + if (NULL == getcwd(startdir, sizeof(startdir))) { + getcwd_status = 2; + (void)strlcpy(startdir, strerror(errno), + sizeof(startdir)); + } else + getcwd_status = 1; + } + + /* + * We are leaving the old base directory. + * Do not use it any longer, not even for messages. + */ + *basedir = '\0'; + + /* + * If and only if the directory was changed earlier and + * the next directory to process is given as a relative path, + * first go back, or bail out if that is impossible. + */ + if (chdir_status && '/' != *targetdir) { + if (2 == getcwd_status) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say("", "getcwd: %s", startdir); + return 0; + } + if (-1 == chdir(startdir)) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say("", "&chdir %s", startdir); + return 0; + } + } + + /* + * Always resolve basedir to the canonicalized absolute + * pathname and append a trailing slash, such that + * we can reliably check whether files are inside. + */ + if (NULL == realpath(targetdir, basedir)) { + if (report_baddir || errno != ENOENT) { + exitcode = (int)MANDOCLEVEL_BADARG; + say("", "&%s: realpath", targetdir); + } + return 0; + } else if (-1 == chdir(basedir)) { + if (report_baddir || errno != ENOENT) { + exitcode = (int)MANDOCLEVEL_BADARG; + say("", "&chdir"); + } + return 0; + } + chdir_status = 1; + cp = strchr(basedir, '\0'); + if ('/' != cp[-1]) { + if (cp - basedir >= PATH_MAX - 1) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say("", "Filename too long"); + return 0; + } + *cp++ = '/'; + *cp = '\0'; + } + return 1; +} + +static void +say(const char *file, const char *format, ...) +{ + va_list ap; + int use_errno; + + if ('\0' != *basedir) + fprintf(stderr, "%s", basedir); + if ('\0' != *basedir && '\0' != *file) + fputc('/', stderr); + if ('\0' != *file) + fprintf(stderr, "%s", file); + + use_errno = 1; + if (NULL != format) { + switch (*format) { + case '&': + format++; + break; + case '\0': + format = NULL; + break; + default: + use_errno = 0; + break; + } + } + if (NULL != format) { + if ('\0' != *basedir || '\0' != *file) + fputs(": ", stderr); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + } + if (use_errno) { + if ('\0' != *basedir || '\0' != *file || NULL != format) + fputs(": ", stderr); + perror(NULL); + } else + fputc('\n', stderr); +} Property changes on: vendor/mandoc/20190723/mandocdb.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/manpath.c =================================================================== --- vendor/mandoc/20190723/manpath.c (nonexistent) +++ vendor/mandoc/20190723/manpath.c (revision 350350) @@ -0,0 +1,347 @@ +/* $Id: manpath.c,v 1.40 2019/07/10 19:39:01 schwarze Exp $ */ +/* + * Copyright (c) 2011,2014,2015,2017-2019 Ingo Schwarze + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "manconf.h" + +static void manconf_file(struct manconf *, const char *); +static void manpath_add(struct manpaths *, const char *, char); +static void manpath_parseline(struct manpaths *, char *, char); + + +void +manconf_parse(struct manconf *conf, const char *file, + char *defp, char *auxp) +{ + char *insert; + + /* Always prepend -m. */ + manpath_parseline(&conf->manpath, auxp, 'm'); + + /* If -M is given, it overrides everything else. */ + if (NULL != defp) { + manpath_parseline(&conf->manpath, defp, 'M'); + return; + } + + /* MANPATH and man.conf(5) cooperate. */ + defp = getenv("MANPATH"); + if (NULL == file) + file = MAN_CONF_FILE; + + /* No MANPATH; use man.conf(5) only. */ + if (NULL == defp || '\0' == defp[0]) { + manconf_file(conf, file); + return; + } + + /* Prepend man.conf(5) to MANPATH. */ + if (':' == defp[0]) { + manconf_file(conf, file); + manpath_parseline(&conf->manpath, defp, '\0'); + return; + } + + /* Append man.conf(5) to MANPATH. */ + if (':' == defp[strlen(defp) - 1]) { + manpath_parseline(&conf->manpath, defp, '\0'); + manconf_file(conf, file); + return; + } + + /* Insert man.conf(5) into MANPATH. */ + insert = strstr(defp, "::"); + if (NULL != insert) { + *insert++ = '\0'; + manpath_parseline(&conf->manpath, defp, '\0'); + manconf_file(conf, file); + manpath_parseline(&conf->manpath, insert + 1, '\0'); + return; + } + + /* MANPATH overrides man.conf(5) completely. */ + manpath_parseline(&conf->manpath, defp, '\0'); +} + +void +manpath_base(struct manpaths *dirs) +{ + char path_base[] = MANPATH_BASE; + manpath_parseline(dirs, path_base, '\0'); +} + +/* + * Parse a FULL pathname from a colon-separated list of arrays. + */ +static void +manpath_parseline(struct manpaths *dirs, char *path, char option) +{ + char *dir; + + if (NULL == path) + return; + + for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) + manpath_add(dirs, dir, option); +} + +/* + * Add a directory to the array, ignoring bad directories. + * Grow the array one-by-one for simplicity's sake. + */ +static void +manpath_add(struct manpaths *dirs, const char *dir, char option) +{ + char buf[PATH_MAX]; + struct stat sb; + char *cp; + size_t i; + + if ((cp = realpath(dir, buf)) == NULL) + goto fail; + + for (i = 0; i < dirs->sz; i++) + if (strcmp(dirs->paths[i], dir) == 0) + return; + + if (stat(cp, &sb) == -1) + goto fail; + + dirs->paths = mandoc_reallocarray(dirs->paths, + dirs->sz + 1, sizeof(*dirs->paths)); + dirs->paths[dirs->sz++] = mandoc_strdup(cp); + return; + +fail: + if (option != '\0') + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-%c %s: %s", option, dir, strerror(errno)); +} + +void +manconf_free(struct manconf *conf) +{ + size_t i; + + for (i = 0; i < conf->manpath.sz; i++) + free(conf->manpath.paths[i]); + + free(conf->manpath.paths); + free(conf->output.includes); + free(conf->output.man); + free(conf->output.paper); + free(conf->output.style); +} + +static void +manconf_file(struct manconf *conf, const char *file) +{ + const char *const toks[] = { "manpath", "output", "_whatdb" }; + char manpath_default[] = MANPATH_DEFAULT; + + FILE *stream; + char *line, *cp, *ep; + size_t linesz, tok, toklen; + ssize_t linelen; + + if ((stream = fopen(file, "r")) == NULL) + goto out; + + line = NULL; + linesz = 0; + + while ((linelen = getline(&line, &linesz, stream)) != -1) { + cp = line; + ep = cp + linelen - 1; + while (ep > cp && isspace((unsigned char)*ep)) + *ep-- = '\0'; + while (isspace((unsigned char)*cp)) + cp++; + if (cp == ep || *cp == '#') + continue; + + for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) { + toklen = strlen(toks[tok]); + if (cp + toklen < ep && + isspace((unsigned char)cp[toklen]) && + strncmp(cp, toks[tok], toklen) == 0) { + cp += toklen; + while (isspace((unsigned char)*cp)) + cp++; + break; + } + } + + switch (tok) { + case 2: /* _whatdb */ + while (ep > cp && ep[-1] != '/') + ep--; + if (ep == cp) + continue; + *ep = '\0'; + /* FALLTHROUGH */ + case 0: /* manpath */ + manpath_add(&conf->manpath, cp, '\0'); + *manpath_default = '\0'; + break; + case 1: /* output */ + manconf_output(&conf->output, cp, 1); + break; + default: + break; + } + } + free(line); + fclose(stream); + +out: + if (*manpath_default != '\0') + manpath_parseline(&conf->manpath, manpath_default, '\0'); +} + +int +manconf_output(struct manoutput *conf, const char *cp, int fromfile) +{ + const char *const toks[] = { + "includes", "man", "paper", "style", "indent", "width", + "tag", "fragment", "mdoc", "noval", "toc" + }; + const size_t ntoks = sizeof(toks) / sizeof(toks[0]); + + const char *errstr; + char *oldval; + size_t len, tok; + + for (tok = 0; tok < ntoks; tok++) { + len = strlen(toks[tok]); + if (strncmp(cp, toks[tok], len) == 0 && + strchr(" = ", cp[len]) != NULL) { + cp += len; + if (*cp == '=') + cp++; + while (isspace((unsigned char)*cp)) + cp++; + break; + } + } + + if (tok < 6 && *cp == '\0') { + mandoc_msg(MANDOCERR_BADVAL_MISS, 0, 0, "-O %s=?", toks[tok]); + return -1; + } + if (tok > 6 && tok < ntoks && *cp != '\0') { + mandoc_msg(MANDOCERR_BADVAL, 0, 0, "-O %s=%s", toks[tok], cp); + return -1; + } + + switch (tok) { + case 0: + if (conf->includes != NULL) { + oldval = mandoc_strdup(conf->includes); + break; + } + conf->includes = mandoc_strdup(cp); + return 0; + case 1: + if (conf->man != NULL) { + oldval = mandoc_strdup(conf->man); + break; + } + conf->man = mandoc_strdup(cp); + return 0; + case 2: + if (conf->paper != NULL) { + oldval = mandoc_strdup(conf->paper); + break; + } + conf->paper = mandoc_strdup(cp); + return 0; + case 3: + if (conf->style != NULL) { + oldval = mandoc_strdup(conf->style); + break; + } + conf->style = mandoc_strdup(cp); + return 0; + case 4: + if (conf->indent) { + mandoc_asprintf(&oldval, "%zu", conf->indent); + break; + } + conf->indent = strtonum(cp, 0, 1000, &errstr); + if (errstr == NULL) + return 0; + mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0, + "-O indent=%s is %s", cp, errstr); + return -1; + case 5: + if (conf->width) { + mandoc_asprintf(&oldval, "%zu", conf->width); + break; + } + conf->width = strtonum(cp, 1, 1000, &errstr); + if (errstr == NULL) + return 0; + mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0, + "-O width=%s is %s", cp, errstr); + return -1; + case 6: + if (conf->tag != NULL) { + oldval = mandoc_strdup(conf->tag); + break; + } + conf->tag = mandoc_strdup(cp); + return 0; + case 7: + conf->fragment = 1; + return 0; + case 8: + conf->mdoc = 1; + return 0; + case 9: + conf->noval = 1; + return 0; + case 10: + conf->toc = 1; + return 0; + default: + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-O %s", cp); + return -1; + } + if (fromfile) { + free(oldval); + return 0; + } else { + mandoc_msg(MANDOCERR_BADVAL_DUPE, 0, 0, + "-O %s=%s: already set to %s", toks[tok], cp, oldval); + free(oldval); + return -1; + } +} Property changes on: vendor/mandoc/20190723/manpath.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mansearch.c =================================================================== --- vendor/mandoc/20190723/mansearch.c (nonexistent) +++ vendor/mandoc/20190723/mansearch.c (revision 350350) @@ -0,0 +1,851 @@ +/* $Id: mansearch.c,v 1.82 2019/07/01 22:56:24 schwarze Exp $ */ +/* + * Copyright (c) 2012 Kristaps Dzonsons + * Copyright (c) 2013-2018 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include +#include + +#include +#if HAVE_ERR +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "manconf.h" +#include "mansearch.h" +#include "dbm.h" + +struct expr { + /* Used for terms: */ + struct dbm_match match; /* Match type and expression. */ + uint64_t bits; /* Type mask. */ + /* Used for OR and AND groups: */ + struct expr *next; /* Next child in the parent group. */ + struct expr *child; /* First child in this group. */ + enum { EXPR_TERM, EXPR_OR, EXPR_AND } type; +}; + +const char *const mansearch_keynames[KEY_MAX] = { + "arch", "sec", "Xr", "Ar", "Fa", "Fl", "Dv", "Fn", + "Ic", "Pa", "Cm", "Li", "Em", "Cd", "Va", "Ft", + "Tn", "Er", "Ev", "Sy", "Sh", "In", "Ss", "Ox", + "An", "Mt", "St", "Bx", "At", "Nx", "Fx", "Lk", + "Ms", "Bsx", "Dx", "Rs", "Vt", "Lb", "Nm", "Nd" +}; + + +static struct ohash *manmerge(struct expr *, struct ohash *); +static struct ohash *manmerge_term(struct expr *, struct ohash *); +static struct ohash *manmerge_or(struct expr *, struct ohash *); +static struct ohash *manmerge_and(struct expr *, struct ohash *); +static char *buildnames(const struct dbm_page *); +static char *buildoutput(size_t, struct dbm_page *); +static size_t lstlen(const char *, size_t); +static void lstcat(char *, size_t *, const char *, const char *); +static int lstmatch(const char *, const char *); +static struct expr *exprcomp(const struct mansearch *, + int, char *[], int *); +static struct expr *expr_and(const struct mansearch *, + int, char *[], int *); +static struct expr *exprterm(const struct mansearch *, + int, char *[], int *); +static void exprfree(struct expr *); +static int manpage_compare(const void *, const void *); + + +int +mansearch(const struct mansearch *search, + const struct manpaths *paths, + int argc, char *argv[], + struct manpage **res, size_t *sz) +{ + char buf[PATH_MAX]; + struct dbm_res *rp; + struct expr *e; + struct dbm_page *page; + struct manpage *mpage; + struct ohash *htab; + size_t cur, i, maxres, outkey; + unsigned int slot; + int argi, chdir_status, getcwd_status, im; + + argi = 0; + if ((e = exprcomp(search, argc, argv, &argi)) == NULL) { + *sz = 0; + return 0; + } + + cur = maxres = 0; + if (res != NULL) + *res = NULL; + + outkey = KEY_Nd; + if (search->outkey != NULL) + for (im = 0; im < KEY_MAX; im++) + if (0 == strcasecmp(search->outkey, + mansearch_keynames[im])) { + outkey = im; + break; + } + + /* + * Remember the original working directory, if possible. + * This will be needed if the second or a later directory + * is given as a relative path. + * Do not error out if the current directory is not + * searchable: Maybe it won't be needed after all. + */ + + if (getcwd(buf, PATH_MAX) == NULL) { + getcwd_status = 0; + (void)strlcpy(buf, strerror(errno), sizeof(buf)); + } else + getcwd_status = 1; + + /* + * Loop over the directories (containing databases) for us to + * search. + * Don't let missing/bad databases/directories phase us. + * In each, try to open the resident database and, if it opens, + * scan it for our match expression. + */ + + chdir_status = 0; + for (i = 0; i < paths->sz; i++) { + if (chdir_status && paths->paths[i][0] != '/') { + if ( ! getcwd_status) { + warnx("%s: getcwd: %s", paths->paths[i], buf); + continue; + } else if (chdir(buf) == -1) { + warn("%s", buf); + continue; + } + } + if (chdir(paths->paths[i]) == -1) { + warn("%s", paths->paths[i]); + continue; + } + chdir_status = 1; + + if (dbm_open(MANDOC_DB) == -1) { + if (errno != ENOENT) + warn("%s/%s", paths->paths[i], MANDOC_DB); + continue; + } + + if ((htab = manmerge(e, NULL)) == NULL) { + dbm_close(); + continue; + } + + for (rp = ohash_first(htab, &slot); rp != NULL; + rp = ohash_next(htab, &slot)) { + page = dbm_page_get(rp->page); + + if (lstmatch(search->sec, page->sect) == 0 || + lstmatch(search->arch, page->arch) == 0 || + (search->argmode == ARG_NAME && + rp->bits <= (int32_t)(NAME_SYN & NAME_MASK))) + continue; + + if (res == NULL) { + cur = 1; + break; + } + if (cur + 1 > maxres) { + maxres += 1024; + *res = mandoc_reallocarray(*res, + maxres, sizeof(**res)); + } + mpage = *res + cur; + mandoc_asprintf(&mpage->file, "%s/%s", + paths->paths[i], page->file + 1); + if (access(chdir_status ? page->file + 1 : + mpage->file, R_OK) == -1) { + warn("%s", mpage->file); + warnx("outdated mandoc.db contains " + "bogus %s entry, run makewhatis %s", + page->file + 1, paths->paths[i]); + free(mpage->file); + free(rp); + continue; + } + mpage->names = buildnames(page); + mpage->output = buildoutput(outkey, page); + mpage->bits = search->firstmatch ? rp->bits : 0; + mpage->ipath = i; + mpage->sec = *page->sect - '0'; + if (mpage->sec < 0 || mpage->sec > 9) + mpage->sec = 10; + mpage->form = *page->file; + free(rp); + cur++; + } + ohash_delete(htab); + free(htab); + dbm_close(); + + /* + * In man(1) mode, prefer matches in earlier trees + * over matches in later trees. + */ + + if (cur && search->firstmatch) + break; + } + if (res != NULL) + qsort(*res, cur, sizeof(struct manpage), manpage_compare); + if (chdir_status && getcwd_status && chdir(buf) == -1) + warn("%s", buf); + exprfree(e); + *sz = cur; + return res != NULL || cur; +} + +/* + * Merge the results for the expression tree rooted at e + * into the the result list htab. + */ +static struct ohash * +manmerge(struct expr *e, struct ohash *htab) +{ + switch (e->type) { + case EXPR_TERM: + return manmerge_term(e, htab); + case EXPR_OR: + return manmerge_or(e->child, htab); + case EXPR_AND: + return manmerge_and(e->child, htab); + default: + abort(); + } +} + +static struct ohash * +manmerge_term(struct expr *e, struct ohash *htab) +{ + struct dbm_res res, *rp; + uint64_t ib; + unsigned int slot; + int im; + + if (htab == NULL) { + htab = mandoc_malloc(sizeof(*htab)); + mandoc_ohash_init(htab, 4, offsetof(struct dbm_res, page)); + } + + for (im = 0, ib = 1; im < KEY_MAX; im++, ib <<= 1) { + if ((e->bits & ib) == 0) + continue; + + switch (ib) { + case TYPE_arch: + dbm_page_byarch(&e->match); + break; + case TYPE_sec: + dbm_page_bysect(&e->match); + break; + case TYPE_Nm: + dbm_page_byname(&e->match); + break; + case TYPE_Nd: + dbm_page_bydesc(&e->match); + break; + default: + dbm_page_bymacro(im - 2, &e->match); + break; + } + + /* + * When hashing for deduplication, use the unique + * page ID itself instead of a hash function; + * that is quite efficient. + */ + + for (;;) { + res = dbm_page_next(); + if (res.page == -1) + break; + slot = ohash_lookup_memory(htab, + (char *)&res, sizeof(res.page), res.page); + if ((rp = ohash_find(htab, slot)) != NULL) { + rp->bits |= res.bits; + continue; + } + rp = mandoc_malloc(sizeof(*rp)); + *rp = res; + ohash_insert(htab, slot, rp); + } + } + return htab; +} + +static struct ohash * +manmerge_or(struct expr *e, struct ohash *htab) +{ + while (e != NULL) { + htab = manmerge(e, htab); + e = e->next; + } + return htab; +} + +static struct ohash * +manmerge_and(struct expr *e, struct ohash *htab) +{ + struct ohash *hand, *h1, *h2; + struct dbm_res *res; + unsigned int slot1, slot2; + + /* Evaluate the first term of the AND clause. */ + + hand = manmerge(e, NULL); + + while ((e = e->next) != NULL) { + + /* Evaluate the next term and prepare for ANDing. */ + + h2 = manmerge(e, NULL); + if (ohash_entries(h2) < ohash_entries(hand)) { + h1 = h2; + h2 = hand; + } else + h1 = hand; + hand = mandoc_malloc(sizeof(*hand)); + mandoc_ohash_init(hand, 4, offsetof(struct dbm_res, page)); + + /* Keep all pages that are in both result sets. */ + + for (res = ohash_first(h1, &slot1); res != NULL; + res = ohash_next(h1, &slot1)) { + if (ohash_find(h2, ohash_lookup_memory(h2, + (char *)res, sizeof(res->page), + res->page)) == NULL) + free(res); + else + ohash_insert(hand, ohash_lookup_memory(hand, + (char *)res, sizeof(res->page), + res->page), res); + } + + /* Discard the merged results. */ + + for (res = ohash_first(h2, &slot2); res != NULL; + res = ohash_next(h2, &slot2)) + free(res); + ohash_delete(h2); + free(h2); + ohash_delete(h1); + free(h1); + } + + /* Merge the result of the AND into htab. */ + + if (htab == NULL) + return hand; + + for (res = ohash_first(hand, &slot1); res != NULL; + res = ohash_next(hand, &slot1)) { + slot2 = ohash_lookup_memory(htab, + (char *)res, sizeof(res->page), res->page); + if (ohash_find(htab, slot2) == NULL) + ohash_insert(htab, slot2, res); + else + free(res); + } + + /* Discard the merged result. */ + + ohash_delete(hand); + free(hand); + return htab; +} + +void +mansearch_free(struct manpage *res, size_t sz) +{ + size_t i; + + for (i = 0; i < sz; i++) { + free(res[i].file); + free(res[i].names); + free(res[i].output); + } + free(res); +} + +static int +manpage_compare(const void *vp1, const void *vp2) +{ + const struct manpage *mp1, *mp2; + const char *cp1, *cp2; + size_t sz1, sz2; + int diff; + + mp1 = vp1; + mp2 = vp2; + if ((diff = mp2->bits - mp1->bits) || + (diff = mp1->sec - mp2->sec)) + return diff; + + /* Fall back to alphabetic ordering of names. */ + sz1 = strcspn(mp1->names, "("); + sz2 = strcspn(mp2->names, "("); + if (sz1 < sz2) + sz1 = sz2; + if ((diff = strncasecmp(mp1->names, mp2->names, sz1))) + return diff; + + /* For identical names and sections, prefer arch-dependent. */ + cp1 = strchr(mp1->names + sz1, '/'); + cp2 = strchr(mp2->names + sz2, '/'); + return cp1 != NULL && cp2 != NULL ? strcasecmp(cp1, cp2) : + cp1 != NULL ? -1 : cp2 != NULL ? 1 : 0; +} + +static char * +buildnames(const struct dbm_page *page) +{ + char *buf; + size_t i, sz; + + sz = lstlen(page->name, 2) + 1 + lstlen(page->sect, 2) + + (page->arch == NULL ? 0 : 1 + lstlen(page->arch, 2)) + 2; + buf = mandoc_malloc(sz); + i = 0; + lstcat(buf, &i, page->name, ", "); + buf[i++] = '('; + lstcat(buf, &i, page->sect, ", "); + if (page->arch != NULL) { + buf[i++] = '/'; + lstcat(buf, &i, page->arch, ", "); + } + buf[i++] = ')'; + buf[i++] = '\0'; + assert(i == sz); + return buf; +} + +/* + * Count the buffer space needed to print the NUL-terminated + * list of NUL-terminated strings, when printing sep separator + * characters between strings. + */ +static size_t +lstlen(const char *cp, size_t sep) +{ + size_t sz; + + for (sz = 0; *cp != '\0'; cp++) { + + /* Skip names appearing only in the SYNOPSIS. */ + if (*cp <= (char)(NAME_SYN & NAME_MASK)) { + while (*cp != '\0') + cp++; + continue; + } + + /* Skip name class markers. */ + if (*cp < ' ') + cp++; + + /* Print a separator before each but the first string. */ + if (sz) + sz += sep; + + /* Copy one string. */ + while (*cp != '\0') { + sz++; + cp++; + } + } + return sz; +} + +/* + * Print the NUL-terminated list of NUL-terminated strings + * into the buffer, seperating strings with sep. + */ +static void +lstcat(char *buf, size_t *i, const char *cp, const char *sep) +{ + const char *s; + size_t i_start; + + for (i_start = *i; *cp != '\0'; cp++) { + + /* Skip names appearing only in the SYNOPSIS. */ + if (*cp <= (char)(NAME_SYN & NAME_MASK)) { + while (*cp != '\0') + cp++; + continue; + } + + /* Skip name class markers. */ + if (*cp < ' ') + cp++; + + /* Print a separator before each but the first string. */ + if (*i > i_start) { + s = sep; + while (*s != '\0') + buf[(*i)++] = *s++; + } + + /* Copy one string. */ + while (*cp != '\0') + buf[(*i)++] = *cp++; + } + +} + +/* + * Return 1 if the string *want occurs in any of the strings + * in the NUL-terminated string list *have, or 0 otherwise. + * If either argument is NULL or empty, assume no filtering + * is desired and return 1. + */ +static int +lstmatch(const char *want, const char *have) +{ + if (want == NULL || have == NULL || *have == '\0') + return 1; + while (*have != '\0') { + if (strcasestr(have, want) != NULL) + return 1; + have = strchr(have, '\0') + 1; + } + return 0; +} + +/* + * Build a list of values taken by the macro im in the manual page. + */ +static char * +buildoutput(size_t im, struct dbm_page *page) +{ + const char *oldoutput, *sep, *input; + char *output, *newoutput, *value; + size_t sz, i; + + switch (im) { + case KEY_Nd: + return mandoc_strdup(page->desc); + case KEY_Nm: + input = page->name; + break; + case KEY_sec: + input = page->sect; + break; + case KEY_arch: + input = page->arch; + if (input == NULL) + input = "all\0"; + break; + default: + input = NULL; + break; + } + + if (input != NULL) { + sz = lstlen(input, 3) + 1; + output = mandoc_malloc(sz); + i = 0; + lstcat(output, &i, input, " # "); + output[i++] = '\0'; + assert(i == sz); + return output; + } + + output = NULL; + dbm_macro_bypage(im - 2, page->addr); + while ((value = dbm_macro_next()) != NULL) { + if (output == NULL) { + oldoutput = ""; + sep = ""; + } else { + oldoutput = output; + sep = " # "; + } + mandoc_asprintf(&newoutput, "%s%s%s", oldoutput, sep, value); + free(output); + output = newoutput; + } + return output; +} + +/* + * Compile a set of string tokens into an expression. + * Tokens in "argv" are assumed to be individual expression atoms (e.g., + * "(", "foo=bar", etc.). + */ +static struct expr * +exprcomp(const struct mansearch *search, int argc, char *argv[], int *argi) +{ + struct expr *parent, *child; + int needterm, nested; + + if ((nested = *argi) == argc) + return NULL; + needterm = 1; + parent = child = NULL; + while (*argi < argc) { + if (strcmp(")", argv[*argi]) == 0) { + if (needterm) + warnx("missing term " + "before closing parenthesis"); + needterm = 0; + if (nested) + break; + warnx("ignoring unmatched right parenthesis"); + ++*argi; + continue; + } + if (strcmp("-o", argv[*argi]) == 0) { + if (needterm) { + if (*argi > 0) + warnx("ignoring -o after %s", + argv[*argi - 1]); + else + warnx("ignoring initial -o"); + } + needterm = 1; + ++*argi; + continue; + } + needterm = 0; + if (child == NULL) { + child = expr_and(search, argc, argv, argi); + continue; + } + if (parent == NULL) { + parent = mandoc_calloc(1, sizeof(*parent)); + parent->type = EXPR_OR; + parent->next = NULL; + parent->child = child; + } + child->next = expr_and(search, argc, argv, argi); + child = child->next; + } + if (needterm && *argi) + warnx("ignoring trailing %s", argv[*argi - 1]); + return parent == NULL ? child : parent; +} + +static struct expr * +expr_and(const struct mansearch *search, int argc, char *argv[], int *argi) +{ + struct expr *parent, *child; + int needterm; + + needterm = 1; + parent = child = NULL; + while (*argi < argc) { + if (strcmp(")", argv[*argi]) == 0) { + if (needterm) + warnx("missing term " + "before closing parenthesis"); + needterm = 0; + break; + } + if (strcmp("-o", argv[*argi]) == 0) + break; + if (strcmp("-a", argv[*argi]) == 0) { + if (needterm) { + if (*argi > 0) + warnx("ignoring -a after %s", + argv[*argi - 1]); + else + warnx("ignoring initial -a"); + } + needterm = 1; + ++*argi; + continue; + } + if (needterm == 0) + break; + if (child == NULL) { + child = exprterm(search, argc, argv, argi); + if (child != NULL) + needterm = 0; + continue; + } + needterm = 0; + if (parent == NULL) { + parent = mandoc_calloc(1, sizeof(*parent)); + parent->type = EXPR_AND; + parent->next = NULL; + parent->child = child; + } + child->next = exprterm(search, argc, argv, argi); + if (child->next != NULL) { + child = child->next; + needterm = 0; + } + } + if (needterm && *argi) + warnx("ignoring trailing %s", argv[*argi - 1]); + return parent == NULL ? child : parent; +} + +static struct expr * +exprterm(const struct mansearch *search, int argc, char *argv[], int *argi) +{ + char errbuf[BUFSIZ]; + struct expr *e; + char *key, *val; + uint64_t iterbit; + int cs, i, irc; + + if (strcmp("(", argv[*argi]) == 0) { + ++*argi; + e = exprcomp(search, argc, argv, argi); + if (*argi < argc) { + assert(strcmp(")", argv[*argi]) == 0); + ++*argi; + } else + warnx("unclosed parenthesis"); + return e; + } + + if (strcmp("-i", argv[*argi]) == 0 && *argi + 1 < argc) { + cs = 0; + ++*argi; + } else + cs = 1; + + e = mandoc_calloc(1, sizeof(*e)); + e->type = EXPR_TERM; + e->bits = 0; + e->next = NULL; + e->child = NULL; + + if (search->argmode == ARG_NAME) { + e->bits = TYPE_Nm; + e->match.type = DBM_EXACT; + e->match.str = argv[(*argi)++]; + return e; + } + + /* + * Separate macro keys from search string. + * If needed, request regular expression handling. + */ + + if (search->argmode == ARG_WORD) { + e->bits = TYPE_Nm; + e->match.type = DBM_REGEX; +#if HAVE_REWB_BSD + mandoc_asprintf(&val, "[[:<:]]%s[[:>:]]", argv[*argi]); +#elif HAVE_REWB_SYSV + mandoc_asprintf(&val, "\\<%s\\>", argv[*argi]); +#else + mandoc_asprintf(&val, + "(^|[^a-zA-Z01-9_])%s([^a-zA-Z01-9_]|$)", argv[*argi]); +#endif + cs = 0; + } else if ((val = strpbrk(argv[*argi], "=~")) == NULL) { + e->bits = TYPE_Nm | TYPE_Nd; + e->match.type = DBM_REGEX; + val = argv[*argi]; + cs = 0; + } else { + if (val == argv[*argi]) + e->bits = TYPE_Nm | TYPE_Nd; + if (*val == '=') { + e->match.type = DBM_SUB; + e->match.str = val + 1; + } else + e->match.type = DBM_REGEX; + *val++ = '\0'; + if (strstr(argv[*argi], "arch") != NULL) + cs = 0; + } + + /* Compile regular expressions. */ + + if (e->match.type == DBM_REGEX) { + e->match.re = mandoc_malloc(sizeof(*e->match.re)); + irc = regcomp(e->match.re, val, + REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE)); + if (irc) { + regerror(irc, e->match.re, errbuf, sizeof(errbuf)); + warnx("regcomp /%s/: %s", val, errbuf); + } + if (search->argmode == ARG_WORD) + free(val); + if (irc) { + free(e->match.re); + free(e); + ++*argi; + return NULL; + } + } + + if (e->bits) { + ++*argi; + return e; + } + + /* + * Parse out all possible fields. + * If the field doesn't resolve, bail. + */ + + while (NULL != (key = strsep(&argv[*argi], ","))) { + if ('\0' == *key) + continue; + for (i = 0, iterbit = 1; i < KEY_MAX; i++, iterbit <<= 1) { + if (0 == strcasecmp(key, mansearch_keynames[i])) { + e->bits |= iterbit; + break; + } + } + if (i == KEY_MAX) { + if (strcasecmp(key, "any")) + warnx("treating unknown key " + "\"%s\" as \"any\"", key); + e->bits |= ~0ULL; + } + } + + ++*argi; + return e; +} + +static void +exprfree(struct expr *e) +{ + if (e->next != NULL) + exprfree(e->next); + if (e->child != NULL) + exprfree(e->child); + free(e); +} Property changes on: vendor/mandoc/20190723/mansearch.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mansearch.h =================================================================== --- vendor/mandoc/20190723/mansearch.h (nonexistent) +++ vendor/mandoc/20190723/mansearch.h (revision 350350) @@ -0,0 +1,118 @@ +/* $Id: mansearch.h,v 1.30 2019/04/30 18:51:57 schwarze Exp $ */ +/* + * Copyright (c) 2012 Kristaps Dzonsons + * Copyright (c) 2013, 2014, 2016, 2017 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define MANDOC_DB "mandoc.db" +#define MANDOCDB_MAGIC 0x3a7d0cdb +#define MANDOCDB_VERSION 1 + +#define MACRO_MAX 36 +#define KEY_arch 0 +#define KEY_sec 1 +#define KEY_Nm 38 +#define KEY_Nd 39 +#define KEY_MAX 40 + +#define TYPE_arch 0x0000000000000001ULL +#define TYPE_sec 0x0000000000000002ULL +#define TYPE_Xr 0x0000000000000004ULL +#define TYPE_Ar 0x0000000000000008ULL +#define TYPE_Fa 0x0000000000000010ULL +#define TYPE_Fl 0x0000000000000020ULL +#define TYPE_Dv 0x0000000000000040ULL +#define TYPE_Fn 0x0000000000000080ULL +#define TYPE_Ic 0x0000000000000100ULL +#define TYPE_Pa 0x0000000000000200ULL +#define TYPE_Cm 0x0000000000000400ULL +#define TYPE_Li 0x0000000000000800ULL +#define TYPE_Em 0x0000000000001000ULL +#define TYPE_Cd 0x0000000000002000ULL +#define TYPE_Va 0x0000000000004000ULL +#define TYPE_Ft 0x0000000000008000ULL +#define TYPE_Tn 0x0000000000010000ULL +#define TYPE_Er 0x0000000000020000ULL +#define TYPE_Ev 0x0000000000040000ULL +#define TYPE_Sy 0x0000000000080000ULL +#define TYPE_Sh 0x0000000000100000ULL +#define TYPE_In 0x0000000000200000ULL +#define TYPE_Ss 0x0000000000400000ULL +#define TYPE_Ox 0x0000000000800000ULL +#define TYPE_An 0x0000000001000000ULL +#define TYPE_Mt 0x0000000002000000ULL +#define TYPE_St 0x0000000004000000ULL +#define TYPE_Bx 0x0000000008000000ULL +#define TYPE_At 0x0000000010000000ULL +#define TYPE_Nx 0x0000000020000000ULL +#define TYPE_Fx 0x0000000040000000ULL +#define TYPE_Lk 0x0000000080000000ULL +#define TYPE_Ms 0x0000000100000000ULL +#define TYPE_Bsx 0x0000000200000000ULL +#define TYPE_Dx 0x0000000400000000ULL +#define TYPE_Rs 0x0000000800000000ULL +#define TYPE_Vt 0x0000001000000000ULL +#define TYPE_Lb 0x0000002000000000ULL +#define TYPE_Nm 0x0000004000000000ULL +#define TYPE_Nd 0x0000008000000000ULL + +#define NAME_SYN 0x0000004000000001ULL +#define NAME_FIRST 0x0000004000000004ULL +#define NAME_TITLE 0x0000004000000006ULL +#define NAME_HEAD 0x0000004000000008ULL +#define NAME_FILE 0x0000004000000010ULL +#define NAME_MASK 0x000000000000001fULL + +enum form { + FORM_SRC = 1, /* Format is mdoc(7) or man(7). */ + FORM_CAT, /* Manual page is preformatted. */ + FORM_NONE /* Format is unknown. */ +}; + +enum argmode { + ARG_FILE = 0, + ARG_NAME, + ARG_WORD, + ARG_EXPR +}; + +struct manpage { + char *file; /* to be prefixed by manpath */ + char *names; /* a list of names with sections */ + char *output; /* user-defined additional output */ + uint64_t bits; /* name type mask */ + size_t ipath; /* number of the manpath */ + int sec; /* section number, 10 means invalid */ + enum form form; +}; + +struct mansearch { + const char *arch; /* architecture/NULL */ + const char *sec; /* mansection/NULL */ + const char *outkey; /* show content of this macro */ + enum argmode argmode; /* interpretation of arguments */ + int firstmatch; /* first matching database only */ +}; + + +struct manpaths; + +int mansearch(const struct mansearch *cfg, /* options */ + const struct manpaths *paths, /* manpaths */ + int argc, /* size of argv */ + char *argv[], /* search terms */ + struct manpage **res, /* results */ + size_t *ressz); /* results returned */ +void mansearch_free(struct manpage *, size_t); Property changes on: vendor/mandoc/20190723/mansearch.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mdoc.7 =================================================================== --- vendor/mandoc/20190723/mdoc.7 (nonexistent) +++ vendor/mandoc/20190723/mdoc.7 (revision 350350) @@ -0,0 +1,3131 @@ +.\" $Id: mdoc.7,v 1.279 2019/07/15 19:20:30 schwarze Exp $ +.\" +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons +.\" Copyright (c) 2010, 2011, 2013-2018 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 15 2019 $ +.Dt MDOC 7 +.Os +.Sh NAME +.Nm mdoc +.Nd semantic markup language for formatting manual pages +.Sh DESCRIPTION +The +.Nm mdoc +language supports authoring of manual pages for the +.Xr man 1 +utility by allowing semantic annotations of words, phrases, +page sections and complete manual pages. +Such annotations are used by formatting tools to achieve a uniform +presentation across all manuals written in +.Nm , +and to support hyperlinking if supported by the output medium. +.Pp +This reference document describes the structure of manual pages +and the syntax and usage of the +.Nm +language. +The reference implementation of a parsing and formatting tool is +.Xr mandoc 1 ; +the +.Sx COMPATIBILITY +section describes compatibility with other implementations. +.Pp +In an +.Nm +document, lines beginning with the control character +.Sq \&. +are called +.Dq macro lines . +The first word is the macro name. +It consists of two or three letters. +Most macro names begin with a capital letter. +For a list of available macros, see +.Sx MACRO OVERVIEW . +The words following the macro name are arguments to the macro, optionally +including the names of other, callable macros; see +.Sx MACRO SYNTAX +for details. +.Pp +Lines not beginning with the control character are called +.Dq text lines . +They provide free-form text to be printed; the formatting of the text +depends on the respective processing context: +.Bd -literal -offset indent +\&.Sh Macro lines change control state. +Text lines are interpreted within the current state. +.Ed +.Pp +Many aspects of the basic syntax of the +.Nm +language are based on the +.Xr roff 7 +language; see the +.Em LANGUAGE SYNTAX +and +.Em MACRO SYNTAX +sections in the +.Xr roff 7 +manual for details, in particular regarding +comments, escape sequences, whitespace, and quoting. +However, using +.Xr roff 7 +requests in +.Nm +documents is discouraged; +.Xr mandoc 1 +supports some of them merely for backward compatibility. +.Sh MANUAL STRUCTURE +A well-formed +.Nm +document consists of a document prologue followed by one or more +sections. +.Pp +The prologue, which consists of the +.Ic \&Dd , +.Ic \&Dt , +and +.Ic \&Os +macros in that order, is required for every document. +.Pp +The first section (sections are denoted by +.Ic \&Sh ) +must be the NAME section, consisting of at least one +.Ic \&Nm +followed by +.Ic \&Nd . +.Pp +Following that, convention dictates specifying at least the +.Em SYNOPSIS +and +.Em DESCRIPTION +sections, although this varies between manual sections. +.Pp +The following is a well-formed skeleton +.Nm +file for a utility +.Qq progname : +.Bd -literal -offset indent +\&.Dd $\&Mdocdate$ +\&.Dt PROGNAME section +\&.Os +\&.Sh NAME +\&.Nm progname +\&.Nd one line about what it does +\&.\e\(dq .Sh LIBRARY +\&.\e\(dq For sections 2, 3, and 9 only. +\&.\e\(dq Not used in OpenBSD. +\&.Sh SYNOPSIS +\&.Nm progname +\&.Op Fl options +\&.Ar +\&.Sh DESCRIPTION +The +\&.Nm +utility processes files ... +\&.\e\(dq .Sh CONTEXT +\&.\e\(dq For section 9 functions only. +\&.\e\(dq .Sh IMPLEMENTATION NOTES +\&.\e\(dq Not used in OpenBSD. +\&.\e\(dq .Sh RETURN VALUES +\&.\e\(dq For sections 2, 3, and 9 function return values only. +\&.\e\(dq .Sh ENVIRONMENT +\&.\e\(dq For sections 1, 6, 7, and 8 only. +\&.\e\(dq .Sh FILES +\&.\e\(dq .Sh EXIT STATUS +\&.\e\(dq For sections 1, 6, and 8 only. +\&.\e\(dq .Sh EXAMPLES +\&.\e\(dq .Sh DIAGNOSTICS +\&.\e\(dq For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only. +\&.\e\(dq .Sh ERRORS +\&.\e\(dq For sections 2, 3, 4, and 9 errno settings only. +\&.\e\(dq .Sh SEE ALSO +\&.\e\(dq .Xr foobar 1 +\&.\e\(dq .Sh STANDARDS +\&.\e\(dq .Sh HISTORY +\&.\e\(dq .Sh AUTHORS +\&.\e\(dq .Sh CAVEATS +\&.\e\(dq .Sh BUGS +\&.\e\(dq .Sh SECURITY CONSIDERATIONS +\&.\e\(dq Not used in OpenBSD. +.Ed +.Pp +The sections in an +.Nm +document are conventionally ordered as they appear above. +Sections should be composed as follows: +.Bl -ohang -offset Ds +.It Em NAME +The name(s) and a one line description of the documented material. +The syntax for this as follows: +.Bd -literal -offset indent +\&.Nm name0 , +\&.Nm name1 , +\&.Nm name2 +\&.Nd a one line description +.Ed +.Pp +Multiple +.Sq \&Nm +names should be separated by commas. +.Pp +The +.Ic \&Nm +macro(s) must precede the +.Ic \&Nd +macro. +.Pp +See +.Ic \&Nm +and +.Ic \&Nd . +.It Em LIBRARY +The name of the library containing the documented material, which is +assumed to be a function in a section 2, 3, or 9 manual. +The syntax for this is as follows: +.Bd -literal -offset indent +\&.Lb libarm +.Ed +.Pp +See +.Ic \&Lb . +.It Em SYNOPSIS +Documents the utility invocation syntax, function call syntax, or device +configuration. +.Pp +For the first, utilities (sections 1, 6, and 8), this is +generally structured as follows: +.Bd -literal -offset indent +\&.Nm bar +\&.Op Fl v +\&.Op Fl o Ar file +\&.Op Ar +\&.Nm foo +\&.Op Fl v +\&.Op Fl o Ar file +\&.Op Ar +.Ed +.Pp +Commands should be ordered alphabetically. +.Pp +For the second, function calls (sections 2, 3, 9): +.Bd -literal -offset indent +\&.In header.h +\&.Vt extern const char *global; +\&.Ft "char *" +\&.Fn foo "const char *src" +\&.Ft "char *" +\&.Fn bar "const char *src" +.Ed +.Pp +Ordering of +.Ic \&In , +.Ic \&Vt , +.Ic \&Fn , +and +.Ic \&Fo +macros should follow C header-file conventions. +.Pp +And for the third, configurations (section 4): +.Bd -literal -offset indent +\&.Cd \(dqit* at isa? port 0x2e\(dq +\&.Cd \(dqit* at isa? port 0x4e\(dq +.Ed +.Pp +Manuals not in these sections generally don't need a +.Em SYNOPSIS . +.Pp +Some macros are displayed differently in the +.Em SYNOPSIS +section, particularly +.Ic \&Nm , +.Ic \&Cd , +.Ic \&Fd , +.Ic \&Fn , +.Ic \&Fo , +.Ic \&In , +.Ic \&Vt , +and +.Ic \&Ft . +All of these macros are output on their own line. +If two such dissimilar macros are pairwise invoked (except for +.Ic \&Ft +before +.Ic \&Fo +or +.Ic \&Fn ) , +they are separated by a vertical space, unless in the case of +.Ic \&Fo , +.Ic \&Fn , +and +.Ic \&Ft , +which are always separated by vertical space. +.Pp +When text and macros following an +.Ic \&Nm +macro starting an input line span multiple output lines, +all output lines but the first will be indented to align +with the text immediately following the +.Ic \&Nm +macro, up to the next +.Ic \&Nm , +.Ic \&Sh , +or +.Ic \&Ss +macro or the end of an enclosing block, whichever comes first. +.It Em DESCRIPTION +This begins with an expansion of the brief, one line description in +.Em NAME : +.Bd -literal -offset indent +The +\&.Nm +utility does this, that, and the other. +.Ed +.Pp +It usually follows with a breakdown of the options (if documenting a +command), such as: +.Bd -literal -offset indent +The arguments are as follows: +\&.Bl \-tag \-width Ds +\&.It Fl v +Print verbose information. +\&.El +.Ed +.Pp +List the options in alphabetical order, +uppercase before lowercase for each letter and +with no regard to whether an option takes an argument. +Put digits in ascending order before all letter options. +.Pp +Manuals not documenting a command won't include the above fragment. +.Pp +Since the +.Em DESCRIPTION +section usually contains most of the text of a manual, longer manuals +often use the +.Ic \&Ss +macro to form subsections. +In very long manuals, the +.Em DESCRIPTION +may be split into multiple sections, each started by an +.Ic \&Sh +macro followed by a non-standard section name, and each having +several subsections, like in the present +.Nm +manual. +.It Em CONTEXT +This section lists the contexts in which functions can be called in section 9. +The contexts are autoconf, process, or interrupt. +.It Em IMPLEMENTATION NOTES +Implementation-specific notes should be kept here. +This is useful when implementing standard functions that may have side +effects or notable algorithmic implications. +.It Em RETURN VALUES +This section documents the +return values of functions in sections 2, 3, and 9. +.Pp +See +.Ic \&Rv . +.It Em ENVIRONMENT +Lists the environment variables used by the utility, +and explains the syntax and semantics of their values. +The +.Xr environ 7 +manual provides examples of typical content and formatting. +.Pp +See +.Ic \&Ev . +.It Em FILES +Documents files used. +It's helpful to document both the file name and a short description of how +the file is used (created, modified, etc.). +.Pp +See +.Ic \&Pa . +.It Em EXIT STATUS +This section documents the +command exit status for section 1, 6, and 8 utilities. +Historically, this information was described in +.Em DIAGNOSTICS , +a practise that is now discouraged. +.Pp +See +.Ic \&Ex . +.It Em EXAMPLES +Example usages. +This often contains snippets of well-formed, well-tested invocations. +Make sure that examples work properly! +.It Em DIAGNOSTICS +Documents error messages. +In section 4 and 9 manuals, these are usually messages printed by the +kernel to the console and to the kernel log. +In section 1, 6, 7, and 8, these are usually messages printed by +userland programs to the standard error output. +.Pp +Historically, this section was used in place of +.Em EXIT STATUS +for manuals in sections 1, 6, and 8; however, this practise is +discouraged. +.Pp +See +.Ic \&Bl +.Fl diag . +.It Em ERRORS +Documents +.Xr errno 2 +settings in sections 2, 3, 4, and 9. +.Pp +See +.Ic \&Er . +.It Em SEE ALSO +References other manuals with related topics. +This section should exist for most manuals. +Cross-references should conventionally be ordered first by section, then +alphabetically (ignoring case). +.Pp +References to other documentation concerning the topic of the manual page, +for example authoritative books or journal articles, may also be +provided in this section. +.Pp +See +.Ic \&Rs +and +.Ic \&Xr . +.It Em STANDARDS +References any standards implemented or used. +If not adhering to any standards, the +.Em HISTORY +section should be used instead. +.Pp +See +.Ic \&St . +.It Em HISTORY +A brief history of the subject, including where it was first implemented, +and when it was ported to or reimplemented for the operating system at hand. +.It Em AUTHORS +Credits to the person or persons who wrote the code and/or documentation. +Authors should generally be noted by both name and email address. +.Pp +See +.Ic \&An . +.It Em CAVEATS +Common misuses and misunderstandings should be explained +in this section. +.It Em BUGS +Known bugs, limitations, and work-arounds should be described +in this section. +.It Em SECURITY CONSIDERATIONS +Documents any security precautions that operators should consider. +.El +.Sh MACRO OVERVIEW +This overview is sorted such that macros of similar purpose are listed +together, to help find the best macro for any given purpose. +Deprecated macros are not included in the overview, but can be found below +in the alphabetical +.Sx MACRO REFERENCE . +.Ss Document preamble and NAME section macros +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Dd Ta document date: Cm $\&Mdocdate$ | Ar month day , year +.It Ic \&Dt Ta document title: Ar TITLE section Op Ar arch +.It Ic \&Os Ta operating system version: Op Ar system Op Ar version +.It Ic \&Nm Ta document name (one argument) +.It Ic \&Nd Ta document description (one line) +.El +.Ss Sections and cross references +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Sh Ta section header (one line) +.It Ic \&Ss Ta subsection header (one line) +.It Ic \&Sx Ta internal cross reference to a section or subsection +.It Ic \&Xr Ta cross reference to another manual page: Ar name section +.It Ic \&Pp Ta start a text paragraph (no arguments) +.El +.Ss Displays and lists +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Bd , \&Ed Ta display block: +.Fl Ar type +.Op Fl offset Ar width +.Op Fl compact +.It Ic \&D1 Ta indented display (one line) +.It Ic \&Dl Ta indented literal display (one line) +.It Ic \&Ql Ta in-line literal display: Ql text +.It Ic \&Bl , \&El Ta list block: +.Fl Ar type +.Op Fl width Ar val +.Op Fl offset Ar val +.Op Fl compact +.It Ic \&It Ta list item (syntax depends on Fl Ar type ) +.It Ic \&Ta Ta table cell separator in Ic \&Bl Fl column No lists +.It Ic \&Rs , \&%* , \&Re Ta bibliographic block (references) +.El +.Ss Spacing control +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Pf Ta prefix, no following horizontal space (one argument) +.It Ic \&Ns Ta roman font, no preceding horizontal space (no arguments) +.It Ic \&Ap Ta apostrophe without surrounding whitespace (no arguments) +.It Ic \&Sm Ta switch horizontal spacing mode: Op Cm on | off +.It Ic \&Bk , \&Ek Ta keep block: Fl words +.El +.Ss Semantic markup for command line utilities +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Nm Ta start a SYNOPSIS block with the name of a utility +.It Ic \&Fl Ta command line options (flags) (>=0 arguments) +.It Ic \&Cm Ta command modifier (>0 arguments) +.It Ic \&Ar Ta command arguments (>=0 arguments) +.It Ic \&Op , \&Oo , \&Oc Ta optional syntax elements (enclosure) +.It Ic \&Ic Ta internal or interactive command (>0 arguments) +.It Ic \&Ev Ta environmental variable (>0 arguments) +.It Ic \&Pa Ta file system path (>=0 arguments) +.El +.Ss Semantic markup for function libraries +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Lb Ta function library (one argument) +.It Ic \&In Ta include file (one argument) +.It Ic \&Fd Ta other preprocessor directive (>0 arguments) +.It Ic \&Ft Ta function type (>0 arguments) +.It Ic \&Fo , \&Fc Ta function block: Ar funcname +.It Ic \&Fn Ta function name: Ar funcname Op Ar argument ... +.It Ic \&Fa Ta function argument (>0 arguments) +.It Ic \&Vt Ta variable type (>0 arguments) +.It Ic \&Va Ta variable name (>0 arguments) +.It Ic \&Dv Ta defined variable or preprocessor constant (>0 arguments) +.It Ic \&Er Ta error constant (>0 arguments) +.It Ic \&Ev Ta environmental variable (>0 arguments) +.El +.Ss Various semantic markup +.Bl -column "Brq, Bro, Brc" description +.It Ic \&An Ta author name (>0 arguments) +.It Ic \&Lk Ta hyperlink: Ar uri Op Ar display_name +.It Ic \&Mt Ta Do mailto Dc hyperlink: Ar localpart Ns @ Ns Ar domain +.It Ic \&Cd Ta kernel configuration declaration (>0 arguments) +.It Ic \&Ad Ta memory address (>0 arguments) +.It Ic \&Ms Ta mathematical symbol (>0 arguments) +.El +.Ss Physical markup +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Em Ta italic font or underline (emphasis) (>0 arguments) +.It Ic \&Sy Ta boldface font (symbolic) (>0 arguments) +.It Ic \&No Ta return to roman font (normal) (>0 arguments) +.It Ic \&Bf , \&Ef Ta font block: Fl Ar type | Cm \&Em | \&Li | \&Sy +.El +.Ss Physical enclosures +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Dq , \&Do , \&Dc Ta enclose in typographic double quotes: Dq text +.It Ic \&Qq , \&Qo , \&Qc Ta enclose in typewriter double quotes: Qq text +.It Ic \&Sq , \&So , \&Sc Ta enclose in single quotes: Sq text +.It Ic \&Pq , \&Po , \&Pc Ta enclose in parentheses: Pq text +.It Ic \&Bq , \&Bo , \&Bc Ta enclose in square brackets: Bq text +.It Ic \&Brq , \&Bro , \&Brc Ta enclose in curly braces: Brq text +.It Ic \&Aq , \&Ao , \&Ac Ta enclose in angle brackets: Aq text +.It Ic \&Eo , \&Ec Ta generic enclosure +.El +.Ss Text production +.Bl -column "Brq, Bro, Brc" description +.It Ic \&Ex Fl std Ta standard command exit values: Op Ar utility ... +.It Ic \&Rv Fl std Ta standard function return values: Op Ar function ... +.It Ic \&St Ta reference to a standards document (one argument) +.It Ic \&At Ta At +.It Ic \&Bx Ta Bx +.It Ic \&Bsx Ta Bsx +.It Ic \&Nx Ta Nx +.It Ic \&Fx Ta Fx +.It Ic \&Ox Ta Ox +.It Ic \&Dx Ta Dx +.El +.Sh MACRO REFERENCE +This section is a canonical reference of all macros, arranged +alphabetically. +For the scoping of individual macros, see +.Sx MACRO SYNTAX . +.Bl -tag -width 3n +.It Ic \&%A Ar first_name ... last_name +Author name of an +.Ic \&Rs +block. +Multiple authors should each be accorded their own +.Ic \%%A +line. +Author names should be ordered with full or abbreviated forename(s) +first, then full surname. +.It Ic \&%B Ar title +Book title of an +.Ic \&Rs +block. +This macro may also be used in a non-bibliographic context when +referring to book titles. +.It Ic \&%C Ar location +Publication city or location of an +.Ic \&Rs +block. +.It Ic \&%D Oo Ar month day , Oc Ar year +Publication date of an +.Ic \&Rs +block. +Provide the full English name of the +.Ar month +and all four digits of the +.Ar year . +.It Ic \&%I Ar name +Publisher or issuer name of an +.Ic \&Rs +block. +.It Ic \&%J Ar name +Journal name of an +.Ic \&Rs +block. +.It Ic \&%N Ar number +Issue number (usually for journals) of an +.Ic \&Rs +block. +.It Ic \&%O Ar line +Optional information of an +.Ic \&Rs +block. +.It Ic \&%P Ar number +Book or journal page number of an +.Ic \&Rs +block. +Conventionally, the argument starts with +.Ql p.\& +for a single page or +.Ql pp.\& +for a range of pages, for example: +.Pp +.Dl .%P pp. 42\e(en47 +.It Ic \&%Q Ar name +Institutional author (school, government, etc.) of an +.Ic \&Rs +block. +Multiple institutional authors should each be accorded their own +.Ic \&%Q +line. +.It Ic \&%R Ar name +Technical report name of an +.Ic \&Rs +block. +.It Ic \&%T Ar title +Article title of an +.Ic \&Rs +block. +This macro may also be used in a non-bibliographical context when +referring to article titles. +.It Ic \&%U Ar protocol Ns :// Ns Ar path +URI of reference document. +.It Ic \&%V Ar number +Volume number of an +.Ic \&Rs +block. +.It Ic \&Ac +Close an +.Ic \&Ao +block. +Does not have any tail arguments. +.It Ic \&Ad Ar address +Memory address. +Do not use this for postal addresses. +.Pp +Examples: +.Dl \&.Ad [0,$] +.Dl \&.Ad 0x00000000 +.It Ic \&An Fl split | nosplit | Ar first_name ... last_name +Author name. +Can be used both for the authors of the program, function, or driver +documented in the manual, or for the authors of the manual itself. +Requires either the name of an author or one of the following arguments: +.Pp +.Bl -tag -width "-nosplitX" -offset indent -compact +.It Fl split +Start a new output line before each subsequent invocation of +.Ic \&An . +.It Fl nosplit +The opposite of +.Fl split . +.El +.Pp +The default is +.Fl nosplit . +The effect of selecting either of the +.Fl split +modes ends at the beginning of the +.Em AUTHORS +section. +In the +.Em AUTHORS +section, the default is +.Fl nosplit +for the first author listing and +.Fl split +for all other author listings. +.Pp +Examples: +.Dl \&.An -nosplit +.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv +.It Ic \&Ao Ar block +Begin a block enclosed by angle brackets. +Does not have any head arguments. +This macro is almost never useful. +See +.Ic \&Aq +for more details. +.It Ic \&Ap +Inserts an apostrophe without any surrounding whitespace. +This is generally used as a grammatical device when referring to the verb +form of a function. +.Pp +Examples: +.Dl \&.Fn execve \&Ap d +.It Ic \&Aq Ar line +Enclose the rest of the input line in angle brackets. +The only important use case is for email addresses. +See +.Ic \&Mt +for an example. +.Pp +Occasionally, it is used for names of characters and keys, for example: +.Bd -literal -offset indent +Press the +\&.Aq escape +key to ... +.Ed +.Pp +For URIs, use +.Ic \&Lk +instead, and +.Ic \&In +for +.Dq #include +directives. +Never wrap +.Ic \&Ar +in +.Ic \&Aq . +.Pp +Since +.Ic \&Aq +usually renders with non-ASCII characters in non-ASCII output modes, +do not use it where the ASCII characters +.Sq < +and +.Sq > +are required as syntax elements. +Instead, use these characters directly in such cases, combining them +with the macros +.Ic \&Pf , +.Ic \&Ns , +or +.Ic \&Eo +as needed. +.Pp +See also +.Ic \&Ao . +.It Ic \&Ar Op Ar placeholder ... +Command arguments. +If an argument is not provided, the string +.Dq file ...\& +is used as a default. +.Pp +Examples: +.Dl ".Fl o Ar file" +.Dl ".Ar" +.Dl ".Ar arg1 , arg2 ." +.Pp +The arguments to the +.Ic \&Ar +macro are names and placeholders for command arguments; +for fixed strings to be passed verbatim as arguments, use +.Ic \&Fl +or +.Ic \&Cm . +.It Ic \&At Op Ar version +Formats an +.At +version. +Accepts one optional argument: +.Pp +.Bl -tag -width "v[1-7] | 32vX" -offset indent -compact +.It Cm v[1-7] | 32v +A version of +.At . +.It Cm III +.At III . +.It Cm V | V.[1-4] +A version of +.At V . +.El +.Pp +Note that these arguments do not begin with a hyphen. +.Pp +Examples: +.Dl \&.At +.Dl \&.At III +.Dl \&.At V.1 +.Pp +See also +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Fx , +.Ic \&Nx , +and +.Ic \&Ox . +.It Ic \&Bc +Close a +.Ic \&Bo +block. +Does not have any tail arguments. +.It Ic \&Bd Fl Ns Ar type Oo Fl offset Ar width Oc Op Fl compact +Begin a display block. +Display blocks are used to select a different indentation and +justification than the one used by the surrounding text. +They may contain both macro lines and text lines. +By default, a display block is preceded by a vertical space. +.Pp +The +.Ar type +must be one of the following: +.Bl -tag -width 13n -offset indent +.It Fl centered +Produce one output line from each input line, and center-justify each line. +Using this display type is not recommended; many +.Nm +implementations render it poorly. +.It Fl filled +Change the positions of line breaks to fill each line, and left- and +right-justify the resulting block. +.It Fl literal +Produce one output line from each input line, +and do not justify the block at all. +Preserve white space as it appears in the input. +Always use a constant-width font. +Use this for displaying source code. +.It Fl ragged +Change the positions of line breaks to fill each line, and left-justify +the resulting block. +.It Fl unfilled +The same as +.Fl literal , +but using the same font as for normal text, which is a variable width font +if supported by the output device. +.El +.Pp +The +.Ar type +must be provided first. +Additional arguments may follow: +.Bl -tag -width 13n -offset indent +.It Fl offset Ar width +Indent the display by the +.Ar width , +which may be one of the following: +.Bl -item +.It +One of the pre-defined strings +.Cm indent , +the width of a standard indentation (six constant width characters); +.Cm indent-two , +twice +.Cm indent ; +.Cm left , +which has no effect; +.Cm right , +which justifies to the right margin; or +.Cm center , +which aligns around an imagined center axis. +.It +A macro invocation, which selects a predefined width +associated with that macro. +The most popular is the imaginary macro +.Ar \&Ds , +which resolves to +.Sy 6n . +.It +A scaling width as described in +.Xr roff 7 . +.It +An arbitrary string, which indents by the length of this string. +.El +.Pp +When the argument is missing, +.Fl offset +is ignored. +.It Fl compact +Do not assert vertical space before the display. +.El +.Pp +Examples: +.Bd -literal -offset indent +\&.Bd \-literal \-offset indent \-compact + Hello world. +\&.Ed +.Ed +.Pp +See also +.Ic \&D1 +and +.Ic \&Dl . +.It Ic \&Bf Fl emphasis | literal | symbolic | Cm \&Em | \&Li | \&Sy +Change the font mode for a scoped block of text. +The +.Fl emphasis +and +.Cm \&Em +argument are equivalent, as are +.Fl symbolic +and +.Cm \&Sy , +and +.Fl literal +and +.Cm \&Li . +Without an argument, this macro does nothing. +The font mode continues until broken by a new font mode in a nested +scope or +.Ic \&Ef +is encountered. +.Pp +See also +.Ic \&Li , +.Ic \&Ef , +.Ic \&Em , +and +.Ic \&Sy . +.It Ic \&Bk Fl words +For each macro, keep its output together on the same output line, +until the end of the macro or the end of the input line is reached, +whichever comes first. +Line breaks in text lines are unaffected. +.Pp +The +.Fl words +argument is required; additional arguments are ignored. +.Pp +The following example will not break within each +.Ic \&Op +macro line: +.Bd -literal -offset indent +\&.Bk \-words +\&.Op Fl f Ar flags +\&.Op Fl o Ar output +\&.Ek +.Ed +.Pp +Be careful in using over-long lines within a keep block! +Doing so will clobber the right margin. +.It Xo +.Ic \&Bl +.Fl Ns Ar type +.Op Fl width Ar val +.Op Fl offset Ar val +.Op Fl compact +.Op Ar col ... +.Xc +Begin a list. +Lists consist of items specified using the +.Ic \&It +macro, containing a head or a body or both. +.Pp +The list +.Ar type +is mandatory and must be specified first. +The +.Fl width +and +.Fl offset +arguments accept macro names as described for +.Ic \&Bd +.Fl offset , +scaling widths as described in +.Xr roff 7 , +or use the length of the given string. +The +.Fl offset +is a global indentation for the whole list, affecting both item heads +and bodies. +For those list types supporting it, the +.Fl width +argument requests an additional indentation of item bodies, +to be added to the +.Fl offset . +Unless the +.Fl compact +argument is specified, list entries are separated by vertical space. +.Pp +A list must specify one of the following list types: +.Bl -tag -width 12n -offset indent +.It Fl bullet +No item heads can be specified, but a bullet will be printed at the head +of each item. +Item bodies start on the same output line as the bullet +and are indented according to the +.Fl width +argument. +.It Fl column +A columnated list. +The +.Fl width +argument has no effect; instead, the string length of each argument +specifies the width of one column. +If the first line of the body of a +.Fl column +list is not an +.Ic \&It +macro line, +.Ic \&It +contexts spanning one input line each are implied until an +.Ic \&It +macro line is encountered, at which point items start being interpreted as +described in the +.Ic \&It +documentation. +.It Fl dash +Like +.Fl bullet , +except that dashes are used in place of bullets. +.It Fl diag +Like +.Fl inset , +except that item heads are not parsed for macro invocations. +Most often used in the +.Em DIAGNOSTICS +section with error constants in the item heads. +.It Fl enum +A numbered list. +No item heads can be specified. +Formatted like +.Fl bullet , +except that cardinal numbers are used in place of bullets, +starting at 1. +.It Fl hang +Like +.Fl tag , +except that the first lines of item bodies are not indented, but follow +the item heads like in +.Fl inset +lists. +.It Fl hyphen +Synonym for +.Fl dash . +.It Fl inset +Item bodies follow items heads on the same line, using normal inter-word +spacing. +Bodies are not indented, and the +.Fl width +argument is ignored. +.It Fl item +No item heads can be specified, and none are printed. +Bodies are not indented, and the +.Fl width +argument is ignored. +.It Fl ohang +Item bodies start on the line following item heads and are not indented. +The +.Fl width +argument is ignored. +.It Fl tag +Item bodies are indented according to the +.Fl width +argument. +When an item head fits inside the indentation, the item body follows +this head on the same output line. +Otherwise, the body starts on the output line following the head. +.El +.Pp +Lists may be nested within lists and displays. +Nesting of +.Fl column +and +.Fl enum +lists may not be portable. +.Pp +See also +.Ic \&El +and +.Ic \&It . +.It Ic \&Bo Ar block +Begin a block enclosed by square brackets. +Does not have any head arguments. +.Pp +Examples: +.Bd -literal -offset indent -compact +\&.Bo 1 , +\&.Dv BUFSIZ \&Bc +.Ed +.Pp +See also +.Ic \&Bq . +.It Ic \&Bq Ar line +Encloses its arguments in square brackets. +.Pp +Examples: +.Dl \&.Bq 1 , \&Dv BUFSIZ +.Pp +.Em Remarks : +this macro is sometimes abused to emulate optional arguments for +commands; the correct macros to use for this purpose are +.Ic \&Op , +.Ic \&Oo , +and +.Ic \&Oc . +.Pp +See also +.Ic \&Bo . +.It Ic \&Brc +Close a +.Ic \&Bro +block. +Does not have any tail arguments. +.It Ic \&Bro Ar block +Begin a block enclosed by curly braces. +Does not have any head arguments. +.Pp +Examples: +.Bd -literal -offset indent -compact +\&.Bro 1 , ... , +\&.Va n \&Brc +.Ed +.Pp +See also +.Ic \&Brq . +.It Ic \&Brq Ar line +Encloses its arguments in curly braces. +.Pp +Examples: +.Dl \&.Brq 1 , ... , \&Va n +.Pp +See also +.Ic \&Bro . +.It Ic \&Bsx Op Ar version +Format the +.Bsx +version provided as an argument, or a default value if +no argument is provided. +.Pp +Examples: +.Dl \&.Bsx 1.0 +.Dl \&.Bsx +.Pp +See also +.Ic \&At , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Fx , +.Ic \&Nx , +and +.Ic \&Ox . +.It Ic \&Bt +Supported only for compatibility, do not use this in new manuals. +Prints +.Dq is currently in beta test. +.It Ic \&Bx Op Ar version Op Ar variant +Format the +.Bx +version provided as an argument, or a default value if no +argument is provided. +.Pp +Examples: +.Dl \&.Bx 4.3 Tahoe +.Dl \&.Bx 4.4 +.Dl \&.Bx +.Pp +See also +.Ic \&At , +.Ic \&Bsx , +.Ic \&Dx , +.Ic \&Fx , +.Ic \&Nx , +and +.Ic \&Ox . +.It Ic \&Cd Ar line +Kernel configuration declaration. +This denotes strings accepted by +.Xr config 8 . +It is most often used in section 4 manual pages. +.Pp +Examples: +.Dl \&.Cd device le0 at scode? +.Pp +.Em Remarks : +this macro is commonly abused by using quoted literals to retain +whitespace and align consecutive +.Ic \&Cd +declarations. +This practise is discouraged. +.It Ic \&Cm Ar keyword ... +Command modifiers. +Typically used for fixed strings passed as arguments to interactive +commands, to commands in interpreted scripts, or to configuration +file directives, unless +.Ic \&Fl +is more appropriate. +.Pp +Examples: +.Dl ".Nm mt Fl f Ar device Cm rewind" +.Dl ".Nm ps Fl o Cm pid , Ns Cm command" +.Dl ".Nm dd Cm if= Ns Ar file1 Cm of= Ns Ar file2" +.Dl ".Ic set Fl o Cm vi" +.Dl ".Ic lookup Cm file bind" +.Dl ".Ic permit Ar identity Op Cm as Ar target" +.It Ic \&D1 Ar line +One-line indented display. +This is formatted by the default rules and is useful for simple indented +statements. +It is followed by a newline. +.Pp +Examples: +.Dl \&.D1 \&Fl abcdefgh +.Pp +See also +.Ic \&Bd +and +.Ic \&Dl . +.It Ic \&Db +This macro is obsolete. +No replacement is needed. +It is ignored by +.Xr mandoc 1 +and groff including its arguments. +It was formerly used to toggle a debugging mode. +.It Ic \&Dc +Close a +.Ic \&Do +block. +Does not have any tail arguments. +.It Ic \&Dd Cm $\&Mdocdate$ | Ar month day , year +Document date for display in the page footer. +This is the mandatory first macro of any +.Nm +manual. +.Pp +The +.Ar month +is the full English month name, the +.Ar day +is an integer number, and the +.Ar year +is the full four-digit year. +.Pp +Other arguments are not portable; the +.Xr mandoc 1 +utility handles them as follows: +.Bl -dash -offset 3n -compact +.It +To have the date automatically filled in by the +.Ox +version of +.Xr cvs 1 , +the special string +.Dq $\&Mdocdate$ +can be given as an argument. +.It +The traditional, purely numeric +.Xr man 7 +format +.Ar year Ns \(en Ns Ar month Ns \(en Ns Ar day +is accepted, too. +.It +If a date string cannot be parsed, it is used verbatim. +.It +If no date string is given, the current date is used. +.El +.Pp +Examples: +.Dl \&.Dd $\&Mdocdate$ +.Dl \&.Dd $\&Mdocdate: July 2 2018$ +.Dl \&.Dd July 2, 2018 +.Pp +See also +.Ic \&Dt +and +.Ic \&Os . +.It Ic \&Dl Ar line +One-line indented display. +This is formatted as literal text and is useful for commands and +invocations. +It is followed by a newline. +.Pp +Examples: +.Dl \&.Dl % mandoc mdoc.7 \e(ba less +.Pp +See also +.Ic \&Ql , +.Ic \&Bd Fl literal , +and +.Ic \&D1 . +.It Ic \&Do Ar block +Begin a block enclosed by double quotes. +Does not have any head arguments. +.Pp +Examples: +.Bd -literal -offset indent -compact +\&.Do +April is the cruellest month +\&.Dc +\e(em T.S. Eliot +.Ed +.Pp +See also +.Ic \&Dq . +.It Ic \&Dq Ar line +Encloses its arguments in +.Dq typographic +double-quotes. +.Pp +Examples: +.Bd -literal -offset indent -compact +\&.Dq April is the cruellest month +\e(em T.S. Eliot +.Ed +.Pp +See also +.Ic \&Qq , +.Ic \&Sq , +and +.Ic \&Do . +.It Ic \&Dt Ar TITLE section Op Ar arch +Document title for display in the page header. +This is the mandatory second macro of any +.Nm +file. +.Pp +Its arguments are as follows: +.Bl -tag -width section -offset 2n +.It Ar TITLE +The document's title (name), defaulting to +.Dq UNTITLED +if unspecified. +To achieve a uniform appearance of page header lines, +it should by convention be all caps. +.It Ar section +The manual section. +This may be one of +.Cm 1 +.Pq General Commands , +.Cm 2 +.Pq System Calls , +.Cm 3 +.Pq Library Functions , +.Cm 3p +.Pq Perl Library , +.Cm 4 +.Pq Device Drivers , +.Cm 5 +.Pq File Formats , +.Cm 6 +.Pq Games , +.Cm 7 +.Pq Miscellaneous Information , +.Cm 8 +.Pq System Manager's Manual , +or +.Cm 9 +.Pq Kernel Developer's Manual . +It should correspond to the manual's filename suffix and defaults to +the empty string if unspecified. +.It Ar arch +This specifies the machine architecture a manual page applies to, +where relevant, for example +.Cm alpha , +.Cm amd64 , +.Cm i386 , +or +.Cm sparc64 . +The list of valid architectures varies by operating system. +.El +.Pp +Examples: +.Dl \&.Dt FOO 1 +.Dl \&.Dt FOO 9 i386 +.Pp +See also +.Ic \&Dd +and +.Ic \&Os . +.It Ic \&Dv Ar identifier ... +Defined variables such as preprocessor constants, constant symbols, +enumeration values, and so on. +.Pp +Examples: +.Dl \&.Dv NULL +.Dl \&.Dv BUFSIZ +.Dl \&.Dv STDOUT_FILENO +.Pp +See also +.Ic \&Er +and +.Ic \&Ev +for special-purpose constants, +.Ic \&Va +for variable symbols, and +.Ic \&Fd +for listing preprocessor variable definitions in the +.Em SYNOPSIS . +.It Ic \&Dx Op Ar version +Format the +.Dx +version provided as an argument, or a default +value if no argument is provided. +.Pp +Examples: +.Dl \&.Dx 2.4.1 +.Dl \&.Dx +.Pp +See also +.Ic \&At , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Fx , +.Ic \&Nx , +and +.Ic \&Ox . +.It Ic \&Ec Op Ar closing_delimiter +Close a scope started by +.Ic \&Eo . +.Pp +The +.Ar closing_delimiter +argument is used as the enclosure tail, for example, specifying \e(rq +will emulate +.Ic \&Dc . +.It Ic \&Ed +End a display context started by +.Ic \&Bd . +.It Ic \&Ef +End a font mode context started by +.Ic \&Bf . +.It Ic \&Ek +End a keep context started by +.Ic \&Bk . +.It Ic \&El +End a list context started by +.Ic \&Bl . +See also +.Ic \&It . +.It Ic \&Em Ar word ... +Request an italic font. +If the output device does not provide that, underline. +.Pp +This is most often used for stress emphasis (not to be confused with +importance, see +.Ic \&Sy ) . +In the rare cases where none of the semantic markup macros fit, +it can also be used for technical terms and placeholders, except +that for syntax elements, +.Ic \&Sy +and +.Ic \&Ar +are preferred, respectively. +.Pp +Examples: +.Bd -literal -compact -offset indent +Selected lines are those +\&.Em not +matching any of the specified patterns. +Some of the functions use a +\&.Em hold space +to save the pattern space for subsequent retrieval. +.Ed +.Pp +See also +.Ic \&No , +.Ic \&Ql , +and +.Ic \&Sy . +.It Ic \&En Ar word ... +This macro is obsolete. +Use +.Ic \&Eo +or any of the other enclosure macros. +.Pp +It encloses its argument in the delimiters specified by the last +.Ic \&Es +macro. +.It Ic \&Eo Op Ar opening_delimiter +An arbitrary enclosure. +The +.Ar opening_delimiter +argument is used as the enclosure head, for example, specifying \e(lq +will emulate +.Ic \&Do . +.It Ic \&Er Ar identifier ... +Error constants for definitions of the +.Va errno +libc global variable. +This is most often used in section 2 and 3 manual pages. +.Pp +Examples: +.Dl \&.Er EPERM +.Dl \&.Er ENOENT +.Pp +See also +.Ic \&Dv +for general constants. +.It Ic \&Es Ar opening_delimiter closing_delimiter +This macro is obsolete. +Use +.Ic \&Eo +or any of the other enclosure macros. +.Pp +It takes two arguments, defining the delimiters to be used by subsequent +.Ic \&En +macros. +.It Ic \&Ev Ar identifier ... +Environmental variables such as those specified in +.Xr environ 7 . +.Pp +Examples: +.Dl \&.Ev DISPLAY +.Dl \&.Ev PATH +.Pp +See also +.Ic \&Dv +for general constants. +.It Ic \&Ex Fl std Op Ar utility ... +Insert a standard sentence regarding command exit values of 0 on success +and >0 on failure. +This is most often used in section 1, 6, and 8 manual pages. +.Pp +If +.Ar utility +is not specified, the document's name set by +.Ic \&Nm +is used. +Multiple +.Ar utility +arguments are treated as separate utilities. +.Pp +See also +.Ic \&Rv . +.It Ic \&Fa Ar argument ... +Function argument or parameter. +Each argument may be a name and a type (recommended for the +.Em SYNOPSIS +section), a name alone (for function invocations), +or a type alone (for function prototypes). +If both a type and a name are given or if the type consists of multiple +words, all words belonging to the same function argument have to be +given in a single argument to the +.Ic \&Fa +macro. +.Pp +This macro is also used to specify the field name of a structure. +.Pp +Most often, the +.Ic \&Fa +macro is used in the +.Em SYNOPSIS +within +.Ic \&Fo +blocks when documenting multi-line function prototypes. +If invoked with multiple arguments, the arguments are separated by a +comma. +Furthermore, if the following macro is another +.Ic \&Fa , +the last argument will also have a trailing comma. +.Pp +Examples: +.Dl \&.Fa \(dqconst char *p\(dq +.Dl \&.Fa \(dqint a\(dq \(dqint b\(dq \(dqint c\(dq +.Dl \&.Fa \(dqchar *\(dq size_t +.Pp +See also +.Ic \&Fo . +.It Ic \&Fc +End a function context started by +.Ic \&Fo . +.It Ic \&Fd Pf # Ar directive Op Ar argument ... +Preprocessor directive, in particular for listing it in the +.Em SYNOPSIS . +Historically, it was also used to document include files. +The latter usage has been deprecated in favour of +.Ic \&In . +.Pp +Examples: +.Dl \&.Fd #define sa_handler __sigaction_u.__sa_handler +.Dl \&.Fd #define SIO_MAXNFDS +.Dl \&.Fd #ifdef FS_DEBUG +.Dl \&.Ft void +.Dl \&.Fn dbg_open \(dqconst char *\(dq +.Dl \&.Fd #endif +.Pp +See also +.Sx MANUAL STRUCTURE , +.Ic \&In , +and +.Ic \&Dv . +.It Ic \&Fl Op Ar word ... +Command-line flag or option. +Used when listing arguments to command-line utilities. +Prints a fixed-width hyphen +.Sq \- +directly followed by each argument. +If no arguments are provided, a hyphen is printed followed by a space. +If the argument is a macro, a hyphen is prefixed to the subsequent macro +output. +.Pp +Examples: +.Dl ".Fl R Op Fl H | L | P" +.Dl ".Op Fl 1AaCcdFfgHhikLlmnopqRrSsTtux" +.Dl ".Fl type Cm d Fl name Pa CVS" +.Dl ".Fl Ar signal_number" +.Dl ".Fl o Fl" +.Pp +See also +.Ic \&Cm . +.It Ic \&Fn Ar funcname Op Ar argument ... +A function name. +.Pp +Function arguments are surrounded in parenthesis and +are delimited by commas. +If no arguments are specified, blank parenthesis are output. +In the +.Em SYNOPSIS +section, this macro starts a new output line, +and a blank line is automatically inserted between function definitions. +.Pp +Examples: +.Dl \&.Fn \(dqint funcname\(dq \(dqint arg0\(dq \(dqint arg1\(dq +.Dl \&.Fn funcname \(dqint arg0\(dq +.Dl \&.Fn funcname arg0 +.Bd -literal -offset indent +\&.Ft functype +\&.Fn funcname +.Ed +.Pp +When referring to a function documented in another manual page, use +.Ic \&Xr +instead. +See also +.Sx MANUAL STRUCTURE , +.Ic \&Fo , +and +.Ic \&Ft . +.It Ic \&Fo Ar funcname +Begin a function block. +This is a multi-line version of +.Ic \&Fn . +.Pp +Invocations usually occur in the following context: +.Bd -ragged -offset indent +.Pf \. Ic \&Ft Ar functype +.br +.Pf \. Ic \&Fo Ar funcname +.br +.Pf \. Ic \&Fa Qq Ar argtype Ar argname +.br +\&.\.\. +.br +.Pf \. Ic \&Fc +.Ed +.Pp +A +.Ic \&Fo +scope is closed by +.Ic \&Fc . +.Pp +See also +.Sx MANUAL STRUCTURE , +.Ic \&Fa , +.Ic \&Fc , +and +.Ic \&Ft . +.It Ic \&Fr Ar number +This macro is obsolete. +No replacement markup is needed. +.Pp +It was used to show numerical function return values in an italic font. +.It Ic \&Ft Ar functype +A function type. +.Pp +In the +.Em SYNOPSIS +section, a new output line is started after this macro. +.Pp +Examples: +.Dl \&.Ft int +.Bd -literal -offset indent -compact +\&.Ft functype +\&.Fn funcname +.Ed +.Pp +See also +.Sx MANUAL STRUCTURE , +.Ic \&Fn , +and +.Ic \&Fo . +.It Ic \&Fx Op Ar version +Format the +.Fx +version provided as an argument, or a default value +if no argument is provided. +.Pp +Examples: +.Dl \&.Fx 7.1 +.Dl \&.Fx +.Pp +See also +.Ic \&At , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Nx , +and +.Ic \&Ox . +.It Ic \&Hf Ar filename +This macro is not implemented in +.Xr mandoc 1 . +It was used to include the contents of a (header) file literally. +.It Ic \&Ic Ar keyword ... +Internal or interactive command, or configuration instruction +in a configuration file. +See also +.Ic \&Cm . +.Pp +Examples: +.Dl \&.Ic :wq +.Dl \&.Ic hash +.Dl \&.Ic alias +.Pp +Note that using +.Ic \&Ql , +.Ic \&Dl , +or +.Ic \&Bd Fl literal +is preferred for displaying code samples; the +.Ic \&Ic +macro is used when referring to an individual command name. +.It Ic \&In Ar filename +The name of an include file. +This macro is most often used in section 2, 3, and 9 manual pages. +.Pp +When invoked as the first macro on an input line in the +.Em SYNOPSIS +section, the argument is displayed in angle brackets +and preceded by +.Qq #include , +and a blank line is inserted in front if there is a preceding +function declaration. +In other sections, it only encloses its argument in angle brackets +and causes no line break. +.Pp +Examples: +.Dl \&.In sys/types.h +.Pp +See also +.Sx MANUAL STRUCTURE . +.It Ic \&It Op Ar head +A list item. +The syntax of this macro depends on the list type. +.Pp +Lists +of type +.Fl hang , +.Fl ohang , +.Fl inset , +and +.Fl diag +have the following syntax: +.Pp +.D1 Pf \. Ic \&It Ar args +.Pp +Lists of type +.Fl bullet , +.Fl dash , +.Fl enum , +.Fl hyphen +and +.Fl item +have the following syntax: +.Pp +.D1 Pf \. Ic \&It +.Pp +with subsequent lines interpreted within the scope of the +.Ic \&It +until either a closing +.Ic \&El +or another +.Ic \&It . +.Pp +The +.Fl tag +list has the following syntax: +.Pp +.D1 Pf \. Ic \&It Op Cm args +.Pp +Subsequent lines are interpreted as with +.Fl bullet +and family. +The line arguments correspond to the list's left-hand side; body +arguments correspond to the list's contents. +.Pp +The +.Fl column +list is the most complicated. +Its syntax is as follows: +.Pp +.D1 Pf \. Ic \&It Ar cell Op Ic \&Ta Ar cell ... +.D1 Pf \. Ic \&It Ar cell Op Ar cell ... +.Pp +The arguments consist of one or more lines of text and macros +representing a complete table line. +Cells within the line are delimited by the special +.Ic \&Ta +block macro or by literal tab characters. +.Pp +Using literal tabs is strongly discouraged because they are very +hard to use correctly and +.Nm +code using them is very hard to read. +In particular, a blank character is syntactically significant +before and after the literal tab character. +If a word precedes or follows the tab without an intervening blank, +that word is never interpreted as a macro call, but always output +literally. +.Pp +The tab cell delimiter may only be used within the +.Ic \&It +line itself; on following lines, only the +.Ic \&Ta +macro can be used to delimit cells, and portability requires that +.Ic \&Ta +is called by other macros: some parsers do not recognize it when +it appears as the first macro on a line. +.Pp +Note that quoted strings may span tab-delimited cells on an +.Ic \&It +line. +For example, +.Pp +.Dl .It \(dqcol1 ,\& col2 ,\(dq \&; +.Pp +will preserve the whitespace before both commas, +but not the whitespace before the semicolon. +.Pp +See also +.Ic \&Bl . +.It Ic \&Lb Cm lib Ns Ar name +Specify a library. +.Pp +The +.Ar name +parameter may be a system library, such as +.Cm z +or +.Cm pam , +in which case a small library description is printed next to the linker +invocation; or a custom library, in which case the library name is +printed in quotes. +This is most commonly used in the +.Em SYNOPSIS +section as described in +.Sx MANUAL STRUCTURE . +.Pp +Examples: +.Dl \&.Lb libz +.Dl \&.Lb libmandoc +.It Ic \&Li Ar word ... +Request a typewriter (literal) font. +Deprecated because on terminal output devices, this is usually +indistinguishable from normal text. +For literal displays, use +.Ic \&Ql Pq in-line , +.Ic \&Dl Pq single line , +or +.Ic \&Bd Fl literal Pq multi-line +instead. +.It Ic \&Lk Ar uri Op Ar display_name +Format a hyperlink. +.Pp +Examples: +.Dl \&.Lk http://bsd.lv \(dqThe BSD.lv Project\(dq +.Dl \&.Lk http://bsd.lv +.Pp +See also +.Ic \&Mt . +.It Ic \&Lp +Deprecated synonym for +.Ic \&Pp . +.It Ic \&Ms Ar name +Display a mathematical symbol. +.Pp +Examples: +.Dl \&.Ms sigma +.Dl \&.Ms aleph +.It Ic \&Mt Ar localpart Ns @ Ns Ar domain +Format a +.Dq mailto: +hyperlink. +.Pp +Examples: +.Dl \&.Mt discuss@manpages.bsd.lv +.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv +.It Ic \&Nd Ar line +A one line description of the manual's content. +This is the mandatory last macro of the +.Em NAME +section and not appropriate for other sections. +.Pp +Examples: +.Dl Pf . Ic \&Nd mdoc language reference +.Dl Pf . Ic \&Nd format and display UNIX manuals +.Pp +The +.Ic \&Nd +macro technically accepts child macros and terminates with a subsequent +.Ic \&Sh +invocation. +Do not assume this behaviour: some +.Xr whatis 1 +database generators are not smart enough to parse more than the line +arguments and will display macros verbatim. +.Pp +See also +.Ic \&Nm . +.It Ic \&Nm Op Ar name +The name of the manual page, or \(em in particular in section 1, 6, +and 8 pages \(em of an additional command or feature documented in +the manual page. +When first invoked, the +.Ic \&Nm +macro expects a single argument, the name of the manual page. +Usually, the first invocation happens in the +.Em NAME +section of the page. +The specified name will be remembered and used whenever the macro is +called again without arguments later in the page. +The +.Ic \&Nm +macro uses +.Sx Block full-implicit +semantics when invoked as the first macro on an input line in the +.Em SYNOPSIS +section; otherwise, it uses ordinary +.Sx In-line +semantics. +.Pp +Examples: +.Bd -literal -offset indent +\&.Sh SYNOPSIS +\&.Nm cat +\&.Op Fl benstuv +\&.Op Ar +.Ed +.Pp +In the +.Em SYNOPSIS +of section 2, 3 and 9 manual pages, use the +.Ic \&Fn +macro rather than +.Ic \&Nm +to mark up the name of the manual page. +.It Ic \&No Ar word ... +Normal text. +Closes the scope of any preceding in-line macro. +When used after physical formatting macros like +.Ic \&Em +or +.Ic \&Sy , +switches back to the standard font face and weight. +Can also be used to embed plain text strings in macro lines +using semantic annotation macros. +.Pp +Examples: +.Dl ".Em italic , Sy bold , No and roman" +.Bd -literal -offset indent +\&.Sm off +\&.Cm :C No / Ar pattern No / Ar replacement No / +\&.Sm on +.Ed +.Pp +See also +.Ic \&Em , +.Ic \&Ql , +and +.Ic \&Sy . +.It Ic \&Ns +Suppress a space between the output of the preceding macro +and the following text or macro. +Following invocation, input is interpreted as normal text +just like after an +.Ic \&No +macro. +.Pp +This has no effect when invoked at the start of a macro line. +.Pp +Examples: +.Dl ".Ar name Ns = Ns Ar value" +.Dl ".Cm :M Ns Ar pattern" +.Dl ".Fl o Ns Ar output" +.Pp +See also +.Ic \&No +and +.Ic \&Sm . +.It Ic \&Nx Op Ar version +Format the +.Nx +version provided as an argument, or a default value if +no argument is provided. +.Pp +Examples: +.Dl \&.Nx 5.01 +.Dl \&.Nx +.Pp +See also +.Ic \&At , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Fx , +and +.Ic \&Ox . +.It Ic \&Oc +Close multi-line +.Ic \&Oo +context. +.It Ic \&Oo Ar block +Multi-line version of +.Ic \&Op . +.Pp +Examples: +.Bd -literal -offset indent -compact +\&.Oo +\&.Op Fl flag Ns Ar value +\&.Oc +.Ed +.It Ic \&Op Ar line +Optional part of a command line. +Prints the argument(s) in brackets. +This is most often used in the +.Em SYNOPSIS +section of section 1 and 8 manual pages. +.Pp +Examples: +.Dl \&.Op \&Fl a \&Ar b +.Dl \&.Op \&Ar a | b +.Pp +See also +.Ic \&Oo . +.It Ic \&Os Op Ar system Op Ar version +Operating system version for display in the page footer. +This is the mandatory third macro of +any +.Nm +file. +.Pp +The optional +.Ar system +parameter specifies the relevant operating system or environment. +It is suggested to leave it unspecified, in which case +.Xr mandoc 1 +uses its +.Fl Ios +argument or, if that isn't specified either, +.Fa sysname +and +.Fa release +as returned by +.Xr uname 3 . +.Pp +Examples: +.Dl \&.Os +.Dl \&.Os KTH/CSC/TCS +.Dl \&.Os BSD 4.3 +.Pp +See also +.Ic \&Dd +and +.Ic \&Dt . +.It Ic \&Ot Ar functype +This macro is obsolete. +Use +.Ic \&Ft +instead; with +.Xr mandoc 1 , +both have the same effect. +.Pp +Historical +.Nm +packages described it as +.Dq "old function type (FORTRAN)" . +.It Ic \&Ox Op Ar version +Format the +.Ox +version provided as an argument, or a default value +if no argument is provided. +.Pp +Examples: +.Dl \&.Ox 4.5 +.Dl \&.Ox +.Pp +See also +.Ic \&At , +.Ic \&Bsx , +.Ic \&Bx , +.Ic \&Dx , +.Ic \&Fx , +and +.Ic \&Nx . +.It Ic \&Pa Ar name ... +An absolute or relative file system path, or a file or directory name. +If an argument is not provided, the character +.Sq \(ti +is used as a default. +.Pp +Examples: +.Dl \&.Pa /usr/bin/mandoc +.Dl \&.Pa /usr/share/man/man7/mdoc.7 +.Pp +See also +.Ic \&Lk . +.It Ic \&Pc +Close parenthesised context opened by +.Ic \&Po . +.It Ic \&Pf Ar prefix macro Op Ar argument ... +Removes the space between its argument and the following macro. +It is equivalent to: +.Pp +.D1 Ic \&No Pf \e& Ar prefix Ic \&Ns Ar macro Op Ar argument ... +.Pp +The +.Ar prefix +argument is not parsed for macro names or delimiters, +but used verbatim as if it were escaped. +.Pp +Examples: +.Dl ".Pf $ Ar variable_name" +.Dl ".Pf . Ar macro_name" +.Dl ".Pf 0x Ar hex_digits" +.Pp +See also +.Ic \&Ns +and +.Ic \&Sm . +.It Ic \&Po Ar block +Multi-line version of +.Ic \&Pq . +.It Ic \&Pp +Break a paragraph. +This will assert vertical space between prior and subsequent macros +and/or text. +.Pp +Paragraph breaks are not needed before or after +.Ic \&Sh +or +.Ic \&Ss +macros or before displays +.Pq Ic \&Bd Ar line +or lists +.Pq Ic \&Bl +unless the +.Fl compact +flag is given. +.It Ic \&Pq Ar line +Parenthesised enclosure. +.Pp +See also +.Ic \&Po . +.It Ic \&Qc +Close quoted context opened by +.Ic \&Qo . +.It Ic \&Ql Ar line +In-line literal display. +This can be used for complete command invocations and for multi-word +code examples when an indented display is not desired. +.Pp +See also +.Ic \&Dl +and +.Ic \&Bd +.Fl literal . +.It Ic \&Qo Ar block +Multi-line version of +.Ic \&Qq . +.It Ic \&Qq Ar line +Encloses its arguments in +.Qq typewriter +double-quotes. +Consider using +.Ic \&Dq . +.Pp +See also +.Ic \&Dq , +.Ic \&Sq , +and +.Ic \&Qo . +.It Ic \&Re +Close an +.Ic \&Rs +block. +Does not have any tail arguments. +.It Ic \&Rs +Begin a bibliographic +.Pq Dq reference +block. +Does not have any head arguments. +The block macro may only contain +.Ic \&%A , +.Ic \&%B , +.Ic \&%C , +.Ic \&%D , +.Ic \&%I , +.Ic \&%J , +.Ic \&%N , +.Ic \&%O , +.Ic \&%P , +.Ic \&%Q , +.Ic \&%R , +.Ic \&%T , +.Ic \&%U , +and +.Ic \&%V +child macros (at least one must be specified). +.Pp +Examples: +.Bd -literal -offset indent -compact +\&.Rs +\&.%A J. E. Hopcroft +\&.%A J. D. Ullman +\&.%B Introduction to Automata Theory, Languages, and Computation +\&.%I Addison-Wesley +\&.%C Reading, Massachusetts +\&.%D 1979 +\&.Re +.Ed +.Pp +If an +.Ic \&Rs +block is used within a SEE ALSO section, a vertical space is asserted +before the rendered output, else the block continues on the current +line. +.It Ic \&Rv Fl std Op Ar function ... +Insert a standard sentence regarding a function call's return value of 0 +on success and \-1 on error, with the +.Va errno +libc global variable set on error. +.Pp +If +.Ar function +is not specified, the document's name set by +.Ic \&Nm +is used. +Multiple +.Ar function +arguments are treated as separate functions. +.Pp +See also +.Ic \&Ex . +.It Ic \&Sc +Close single-quoted context opened by +.Ic \&So . +.It Ic \&Sh Ar TITLE LINE +Begin a new section. +For a list of conventional manual sections, see +.Sx MANUAL STRUCTURE . +These sections should be used unless it's absolutely necessary that +custom sections be used. +.Pp +Section names should be unique so that they may be keyed by +.Ic \&Sx . +Although this macro is parsed, it should not consist of child node or it +may not be linked with +.Ic \&Sx . +.Pp +See also +.Ic \&Pp , +.Ic \&Ss , +and +.Ic \&Sx . +.It Ic \&Sm Op Cm on | off +Switches the spacing mode for output generated from macros. +.Pp +By default, spacing is +.Cm on . +When switched +.Cm off , +no white space is inserted between macro arguments and between the +output generated from adjacent macros, but text lines +still get normal spacing between words and sentences. +.Pp +When called without an argument, the +.Ic \&Sm +macro toggles the spacing mode. +Using this is not recommended because it makes the code harder to read. +.It Ic \&So Ar block +Multi-line version of +.Ic \&Sq . +.It Ic \&Sq Ar line +Encloses its arguments in +.Sq typewriter +single-quotes. +.Pp +See also +.Ic \&Dq , +.Ic \&Qq , +and +.Ic \&So . +.It Ic \&Ss Ar Title line +Begin a new subsection. +Unlike with +.Ic \&Sh , +there is no convention for the naming of subsections. +Except +.Em DESCRIPTION , +the conventional sections described in +.Sx MANUAL STRUCTURE +rarely have subsections. +.Pp +Sub-section names should be unique so that they may be keyed by +.Ic \&Sx . +Although this macro is parsed, it should not consist of child node or it +may not be linked with +.Ic \&Sx . +.Pp +See also +.Ic \&Pp , +.Ic \&Sh , +and +.Ic \&Sx . +.It Ic \&St Fl Ns Ar abbreviation +Replace an abbreviation for a standard with the full form. +The following standards are recognised. +Where multiple lines are given without a blank line in between, +they all refer to the same standard, and using the first form +is recommended. +.Bl -tag -width 1n +.It C language standards +.Pp +.Bl -tag -width "-p1003.1g-2000" -compact +.It \-ansiC +.St -ansiC +.It \-ansiC-89 +.St -ansiC-89 +.It \-isoC +.St -isoC +.It \-isoC-90 +.St -isoC-90 +.br +The original C standard. +.Pp +.It \-isoC-amd1 +.St -isoC-amd1 +.Pp +.It \-isoC-tcor1 +.St -isoC-tcor1 +.Pp +.It \-isoC-tcor2 +.St -isoC-tcor2 +.Pp +.It \-isoC-99 +.St -isoC-99 +.br +The second major version of the C language standard. +.Pp +.It \-isoC-2011 +.St -isoC-2011 +.br +The third major version of the C language standard. +.El +.It POSIX.1 before the Single UNIX Specification +.Pp +.Bl -tag -width "-p1003.1g-2000" -compact +.It \-p1003.1-88 +.St -p1003.1-88 +.It \-p1003.1 +.St -p1003.1 +.br +The original POSIX standard, based on ANSI C. +.Pp +.It \-p1003.1-90 +.St -p1003.1-90 +.It \-iso9945-1-90 +.St -iso9945-1-90 +.br +The first update of POSIX.1. +.Pp +.It \-p1003.1b-93 +.St -p1003.1b-93 +.It \-p1003.1b +.St -p1003.1b +.br +Real-time extensions. +.Pp +.It \-p1003.1c-95 +.St -p1003.1c-95 +.br +POSIX thread interfaces. +.Pp +.It \-p1003.1i-95 +.St -p1003.1i-95 +.br +Technical Corrigendum. +.Pp +.It \-p1003.1-96 +.St -p1003.1-96 +.It \-iso9945-1-96 +.St -iso9945-1-96 +.br +Includes POSIX.1-1990, 1b, 1c, and 1i. +.El +.It X/Open Portability Guide version 4 and related standards +.Pp +.Bl -tag -width "-p1003.1g-2000" -compact +.It \-xpg3 +.St -xpg3 +.br +An XPG4 precursor, published in 1989. +.Pp +.It \-p1003.2 +.St -p1003.2 +.It \-p1003.2-92 +.St -p1003.2-92 +.It \-iso9945-2-93 +.St -iso9945-2-93 +.br +An XCU4 precursor. +.Pp +.It \-p1003.2a-92 +.St -p1003.2a-92 +.br +Updates to POSIX.2. +.Pp +.It \-xpg4 +.St -xpg4 +.br +Based on POSIX.1 and POSIX.2, published in 1992. +.El +.It Single UNIX Specification version 1 and related standards +.Pp +.Bl -tag -width "-p1003.1g-2000" -compact +.It \-susv1 +.St -susv1 +.It \-xpg4.2 +.St -xpg4.2 +.br +This standard was published in 1994. +It was used as the basis for UNIX 95 certification. +The following three refer to parts of it. +.Pp +.It \-xsh4.2 +.St -xsh4.2 +.Pp +.It \-xcurses4.2 +.St -xcurses4.2 +.Pp +.It \-p1003.1g-2000 +.St -p1003.1g-2000 +.br +Networking APIs, including sockets. +.Pp +.It \-svid4 +.St -svid4 , +.br +Published in 1995. +.El +.It Single UNIX Specification version 2 and related standards +.Pp +.Bl -tag -width "-p1003.1g-2000" -compact +.It \-susv2 +.St -susv2 +This Standard was published in 1997 +and is also called X/Open Portability Guide version 5. +It was used as the basis for UNIX 98 certification. +The following refer to parts of it. +.Pp +.It \-xbd5 +.St -xbd5 +.Pp +.It \-xsh5 +.St -xsh5 +.Pp +.It \-xcu5 +.St -xcu5 +.Pp +.It \-xns5 +.St -xns5 +.It \-xns5.2 +.St -xns5.2 +.El +.It Single UNIX Specification version 3 +.Pp +.Bl -tag -width "-p1003.1-2001" -compact +.It \-p1003.1-2001 +.St -p1003.1-2001 +.It \-susv3 +.St -susv3 +.br +This standard is based on C99, SUSv2, POSIX.1-1996, 1d, and 1j. +It is also called X/Open Portability Guide version 6. +It is used as the basis for UNIX 03 certification. +.Pp +.It \-p1003.1-2004 +.St -p1003.1-2004 +.br +The second and last Technical Corrigendum. +.El +.It Single UNIX Specification version 4 +.Pp +.Bl -tag -width "-p1003.1g-2000" -compact +.It \-p1003.1-2008 +.St -p1003.1-2008 +.It \-susv4 +.St -susv4 +.br +This standard is also called +X/Open Portability Guide version 7. +.El +.It Other standards +.Pp +.Bl -tag -width "-p1003.1g-2000" -compact +.It \-ieee754 +.St -ieee754 +.br +Floating-point arithmetic. +.Pp +.It \-iso8601 +.St -iso8601 +.br +Representation of dates and times, published in 1988. +.Pp +.It \-iso8802-3 +.St -iso8802-3 +.br +Ethernet local area networks. +.Pp +.It \-ieee1275-94 +.St -ieee1275-94 +.El +.El +.It Ic \&Sx Ar Title line +Reference a section or subsection in the same manual page. +The referenced section or subsection name must be identical to the +enclosed argument, including whitespace. +.Pp +Examples: +.Dl \&.Sx MANUAL STRUCTURE +.Pp +See also +.Ic \&Sh +and +.Ic \&Ss . +.It Ic \&Sy Ar word ... +Request a boldface font. +.Pp +This is most often used to indicate importance or seriousness (not to be +confused with stress emphasis, see +.Ic \&Em ) . +When none of the semantic macros fit, it is also adequate for syntax +elements that have to be given or that appear verbatim. +.Pp +Examples: +.Bd -literal -compact -offset indent +\&.Sy Warning : +If +\&.Sy s +appears in the owner permissions, set-user-ID mode is set. +This utility replaces the former +\&.Sy dumpdir +program. +.Ed +.Pp +See also +.Ic \&Em , +.Ic \&No , +and +.Ic \&Ql . +.It Ic \&Ta +Table cell separator in +.Ic \&Bl Fl column +lists; can only be used below +.Ic \&It . +.It Ic \&Tn Ar word ... +Supported only for compatibility, do not use this in new manuals. +Even though the macro name +.Pq Dq tradename +suggests a semantic function, historic usage is inconsistent, mostly +using it as a presentation-level macro to request a small caps font. +.It Ic \&Ud +Supported only for compatibility, do not use this in new manuals. +Prints out +.Dq currently under development. +.It Ic \&Ux +Supported only for compatibility, do not use this in new manuals. +Prints out +.Dq Ux . +.It Ic \&Va Oo Ar type Oc Ar identifier ... +A variable name. +.Pp +Examples: +.Dl \&.Va foo +.Dl \&.Va const char *bar ; +.Pp +For function arguments and parameters, use +.Ic \&Fa +instead. +For declarations of global variables in the +.Em SYNOPSIS +section, use +.Ic \&Vt . +.It Ic \&Vt Ar type Op Ar identifier +A variable type. +.Pp +This is also used for indicating global variables in the +.Em SYNOPSIS +section, in which case a variable name is also specified. +Note that it accepts +.Sx Block partial-implicit +syntax when invoked as the first macro on an input line in the +.Em SYNOPSIS +section, else it accepts ordinary +.Sx In-line +syntax. +In the former case, this macro starts a new output line, +and a blank line is inserted in front if there is a preceding +function definition or include directive. +.Pp +Examples: +.Dl \&.Vt unsigned char +.Dl \&.Vt extern const char * const sys_signame[] \&; +.Pp +For parameters in function prototypes, use +.Ic \&Fa +instead, for function return types +.Ic \&Ft , +and for variable names outside the +.Em SYNOPSIS +section +.Ic \&Va , +even when including a type with the name. +See also +.Sx MANUAL STRUCTURE . +.It Ic \&Xc +Close a scope opened by +.Ic \&Xo . +.It Ic \&Xo Ar block +Extend the header of an +.Ic \&It +macro or the body of a partial-implicit block macro +beyond the end of the input line. +This macro originally existed to work around the 9-argument limit +of historic +.Xr roff 7 . +.It Ic \&Xr Ar name section +Link to another manual +.Pq Qq cross-reference . +.Pp +Cross reference the +.Ar name +and +.Ar section +number of another man page. +.Pp +Examples: +.Dl \&.Xr mandoc 1 +.Dl \&.Xr mandoc 1 \&; +.Dl \&.Xr mandoc 1 \&Ns s behaviour +.El +.Sh MACRO SYNTAX +The syntax of a macro depends on its classification. +In this section, +.Sq \-arg +refers to macro arguments, which may be followed by zero or more +.Sq parm +parameters; +.Sq \&Yo +opens the scope of a macro; and if specified, +.Sq \&Yc +closes it out. +.Pp +The +.Em Callable +column indicates that the macro may also be called by passing its name +as an argument to another macro. +For example, +.Sq \&.Op \&Fl O \&Ar file +produces +.Sq Op Fl O Ar file . +To prevent a macro call and render the macro name literally, +escape it by prepending a zero-width space, +.Sq \e& . +For example, +.Sq \&Op \e&Fl O +produces +.Sq Op \&Fl O . +If a macro is not callable but its name appears as an argument +to another macro, it is interpreted as opaque text. +For example, +.Sq \&.Fl \&Sh +produces +.Sq Fl \&Sh . +.Pp +The +.Em Parsed +column indicates whether the macro may call other macros by receiving +their names as arguments. +If a macro is not parsed but the name of another macro appears +as an argument, it is interpreted as opaque text. +.Pp +The +.Em Scope +column, if applicable, describes closure rules. +.Ss Block full-explicit +Multi-line scope closed by an explicit closing macro. +All macros contains bodies; only +.Ic \s&Bf +and +.Pq optionally +.Ic \&Bl +contain a head. +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB +\(lBbody...\(rB +\&.Yc +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope +.It Ic \&Bd Ta \&No Ta \&No Ta closed by Ic \&Ed +.It Ic \&Bf Ta \&No Ta \&No Ta closed by Ic \&Ef +.It Ic \&Bk Ta \&No Ta \&No Ta closed by Ic \&Ek +.It Ic \&Bl Ta \&No Ta \&No Ta closed by Ic \&El +.It Ic \&Ed Ta \&No Ta \&No Ta opened by Ic \&Bd +.It Ic \&Ef Ta \&No Ta \&No Ta opened by Ic \&Bf +.It Ic \&Ek Ta \&No Ta \&No Ta opened by Ic \&Bk +.It Ic \&El Ta \&No Ta \&No Ta opened by Ic \&Bl +.El +.Ss Block full-implicit +Multi-line scope closed by end-of-file or implicitly by another macro. +All macros have bodies; some +.Po +.Ic \&It Fl bullet , +.Fl hyphen , +.Fl dash , +.Fl enum , +.Fl item +.Pc +don't have heads; only one +.Po +.Ic \&It +in +.Ic \&Bl Fl column +.Pc +has multiple heads. +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead... \(lBTa head...\(rB\(rB +\(lBbody...\(rB +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXXXXXXXXX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope +.It Ic \&It Ta \&No Ta Yes Ta closed by Ic \&It , Ic \&El +.It Ic \&Nd Ta \&No Ta \&No Ta closed by Ic \&Sh +.It Ic \&Nm Ta \&No Ta Yes Ta closed by Ic \&Nm , Ic \&Sh , Ic \&Ss +.It Ic \&Sh Ta \&No Ta Yes Ta closed by Ic \&Sh +.It Ic \&Ss Ta \&No Ta Yes Ta closed by Ic \&Sh , Ic \&Ss +.El +.Pp +Note that the +.Ic \&Nm +macro is a +.Sx Block full-implicit +macro only when invoked as the first macro +in a +.Em SYNOPSIS +section line, else it is +.Sx In-line . +.Ss Block partial-explicit +Like block full-explicit, but also with single-line scope. +Each has at least a body and, in limited circumstances, a head +.Po +.Ic \&Fo , +.Ic \&Eo +.Pc +and/or tail +.Pq Ic \&Ec . +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB +\(lBbody...\(rB +\&.Yc \(lBtail...\(rB + +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB \ +\(lBbody...\(rB \&Yc \(lBtail...\(rB +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope +.It Ic \&Ac Ta Yes Ta Yes Ta opened by Ic \&Ao +.It Ic \&Ao Ta Yes Ta Yes Ta closed by Ic \&Ac +.It Ic \&Bc Ta Yes Ta Yes Ta closed by Ic \&Bo +.It Ic \&Bo Ta Yes Ta Yes Ta opened by Ic \&Bc +.It Ic \&Brc Ta Yes Ta Yes Ta opened by Ic \&Bro +.It Ic \&Bro Ta Yes Ta Yes Ta closed by Ic \&Brc +.It Ic \&Dc Ta Yes Ta Yes Ta opened by Ic \&Do +.It Ic \&Do Ta Yes Ta Yes Ta closed by Ic \&Dc +.It Ic \&Ec Ta Yes Ta Yes Ta opened by Ic \&Eo +.It Ic \&Eo Ta Yes Ta Yes Ta closed by Ic \&Ec +.It Ic \&Fc Ta Yes Ta Yes Ta opened by Ic \&Fo +.It Ic \&Fo Ta \&No Ta \&No Ta closed by Ic \&Fc +.It Ic \&Oc Ta Yes Ta Yes Ta closed by Ic \&Oo +.It Ic \&Oo Ta Yes Ta Yes Ta opened by Ic \&Oc +.It Ic \&Pc Ta Yes Ta Yes Ta closed by Ic \&Po +.It Ic \&Po Ta Yes Ta Yes Ta opened by Ic \&Pc +.It Ic \&Qc Ta Yes Ta Yes Ta opened by Ic \&Oo +.It Ic \&Qo Ta Yes Ta Yes Ta closed by Ic \&Oc +.It Ic \&Re Ta \&No Ta \&No Ta opened by Ic \&Rs +.It Ic \&Rs Ta \&No Ta \&No Ta closed by Ic \&Re +.It Ic \&Sc Ta Yes Ta Yes Ta opened by Ic \&So +.It Ic \&So Ta Yes Ta Yes Ta closed by Ic \&Sc +.It Ic \&Xc Ta Yes Ta Yes Ta opened by Ic \&Xo +.It Ic \&Xo Ta Yes Ta Yes Ta closed by Ic \&Xc +.El +.Ss Block partial-implicit +Like block full-implicit, but with single-line scope closed by the +end of the line. +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBbody...\(rB \(lBres...\(rB +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed +.It Ic \&Aq Ta Yes Ta Yes +.It Ic \&Bq Ta Yes Ta Yes +.It Ic \&Brq Ta Yes Ta Yes +.It Ic \&D1 Ta \&No Ta \&Yes +.It Ic \&Dl Ta \&No Ta Yes +.It Ic \&Dq Ta Yes Ta Yes +.It Ic \&En Ta Yes Ta Yes +.It Ic \&Op Ta Yes Ta Yes +.It Ic \&Pq Ta Yes Ta Yes +.It Ic \&Ql Ta Yes Ta Yes +.It Ic \&Qq Ta Yes Ta Yes +.It Ic \&Sq Ta Yes Ta Yes +.It Ic \&Vt Ta Yes Ta Yes +.El +.Pp +Note that the +.Ic \&Vt +macro is a +.Sx Block partial-implicit +only when invoked as the first macro +in a +.Em SYNOPSIS +section line, else it is +.Sx In-line . +.Ss Special block macro +The +.Ic \&Ta +macro can only be used below +.Ic \&It +in +.Ic \&Bl Fl column +lists. +It delimits blocks representing table cells; +these blocks have bodies, but no heads. +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope +.It Ic \&Ta Ta Yes Ta Yes Ta closed by Ic \&Ta , Ic \&It +.El +.Ss In-line +Closed by the end of the line, fixed argument lengths, +and/or subsequent macros. +In-line macros have only text children. +If a number (or inequality) of arguments is +.Pq n , +then the macro accepts an arbitrary number of arguments. +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB \(lBres...\(rB + +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB Yc... + +\&.Yo \(lB\-arg \(lBval...\(rB\(rB arg0 arg1 argN +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" "Arguments" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Arguments +.It Ic \&%A Ta \&No Ta \&No Ta >0 +.It Ic \&%B Ta \&No Ta \&No Ta >0 +.It Ic \&%C Ta \&No Ta \&No Ta >0 +.It Ic \&%D Ta \&No Ta \&No Ta >0 +.It Ic \&%I Ta \&No Ta \&No Ta >0 +.It Ic \&%J Ta \&No Ta \&No Ta >0 +.It Ic \&%N Ta \&No Ta \&No Ta >0 +.It Ic \&%O Ta \&No Ta \&No Ta >0 +.It Ic \&%P Ta \&No Ta \&No Ta >0 +.It Ic \&%Q Ta \&No Ta \&No Ta >0 +.It Ic \&%R Ta \&No Ta \&No Ta >0 +.It Ic \&%T Ta \&No Ta \&No Ta >0 +.It Ic \&%U Ta \&No Ta \&No Ta >0 +.It Ic \&%V Ta \&No Ta \&No Ta >0 +.It Ic \&Ad Ta Yes Ta Yes Ta >0 +.It Ic \&An Ta Yes Ta Yes Ta >0 +.It Ic \&Ap Ta Yes Ta Yes Ta 0 +.It Ic \&Ar Ta Yes Ta Yes Ta n +.It Ic \&At Ta Yes Ta Yes Ta 1 +.It Ic \&Bsx Ta Yes Ta Yes Ta n +.It Ic \&Bt Ta \&No Ta \&No Ta 0 +.It Ic \&Bx Ta Yes Ta Yes Ta n +.It Ic \&Cd Ta Yes Ta Yes Ta >0 +.It Ic \&Cm Ta Yes Ta Yes Ta >0 +.It Ic \&Db Ta \&No Ta \&No Ta 1 +.It Ic \&Dd Ta \&No Ta \&No Ta n +.It Ic \&Dt Ta \&No Ta \&No Ta n +.It Ic \&Dv Ta Yes Ta Yes Ta >0 +.It Ic \&Dx Ta Yes Ta Yes Ta n +.It Ic \&Em Ta Yes Ta Yes Ta >0 +.It Ic \&Er Ta Yes Ta Yes Ta >0 +.It Ic \&Es Ta Yes Ta Yes Ta 2 +.It Ic \&Ev Ta Yes Ta Yes Ta >0 +.It Ic \&Ex Ta \&No Ta \&No Ta n +.It Ic \&Fa Ta Yes Ta Yes Ta >0 +.It Ic \&Fd Ta \&No Ta \&No Ta >0 +.It Ic \&Fl Ta Yes Ta Yes Ta n +.It Ic \&Fn Ta Yes Ta Yes Ta >0 +.It Ic \&Fr Ta Yes Ta Yes Ta >0 +.It Ic \&Ft Ta Yes Ta Yes Ta >0 +.It Ic \&Fx Ta Yes Ta Yes Ta n +.It Ic \&Hf Ta \&No Ta \&No Ta n +.It Ic \&Ic Ta Yes Ta Yes Ta >0 +.It Ic \&In Ta \&No Ta \&No Ta 1 +.It Ic \&Lb Ta \&No Ta \&No Ta 1 +.It Ic \&Li Ta Yes Ta Yes Ta >0 +.It Ic \&Lk Ta Yes Ta Yes Ta >0 +.It Ic \&Lp Ta \&No Ta \&No Ta 0 +.It Ic \&Ms Ta Yes Ta Yes Ta >0 +.It Ic \&Mt Ta Yes Ta Yes Ta >0 +.It Ic \&Nm Ta Yes Ta Yes Ta n +.It Ic \&No Ta Yes Ta Yes Ta >0 +.It Ic \&Ns Ta Yes Ta Yes Ta 0 +.It Ic \&Nx Ta Yes Ta Yes Ta n +.It Ic \&Os Ta \&No Ta \&No Ta n +.It Ic \&Ot Ta Yes Ta Yes Ta >0 +.It Ic \&Ox Ta Yes Ta Yes Ta n +.It Ic \&Pa Ta Yes Ta Yes Ta n +.It Ic \&Pf Ta Yes Ta Yes Ta 1 +.It Ic \&Pp Ta \&No Ta \&No Ta 0 +.It Ic \&Rv Ta \&No Ta \&No Ta n +.It Ic \&Sm Ta \&No Ta \&No Ta <2 +.It Ic \&St Ta \&No Ta Yes Ta 1 +.It Ic \&Sx Ta Yes Ta Yes Ta >0 +.It Ic \&Sy Ta Yes Ta Yes Ta >0 +.It Ic \&Tn Ta Yes Ta Yes Ta >0 +.It Ic \&Ud Ta \&No Ta \&No Ta 0 +.It Ic \&Ux Ta Yes Ta Yes Ta n +.It Ic \&Va Ta Yes Ta Yes Ta n +.It Ic \&Vt Ta Yes Ta Yes Ta >0 +.It Ic \&Xr Ta Yes Ta Yes Ta 2 +.El +.Ss Delimiters +When a macro argument consists of one single input character +considered as a delimiter, the argument gets special handling. +This does not apply when delimiters appear in arguments containing +more than one character. +Consequently, to prevent special handling and just handle it +like any other argument, a delimiter can be escaped by prepending +a zero-width space +.Pq Sq \e& . +In text lines, delimiters never need escaping, but may be used +as normal punctuation. +.Pp +For many macros, when the leading arguments are opening delimiters, +these delimiters are put before the macro scope, +and when the trailing arguments are closing delimiters, +these delimiters are put after the macro scope. +Spacing is suppressed after opening delimiters +and before closing delimiters. +For example, +.Pp +.D1 Pf \. \&Aq "( [ word ] ) ." +.Pp +renders as: +.Pp +.D1 Aq ( [ word ] ) . +.Pp +Opening delimiters are: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It \&( +left parenthesis +.It \&[ +left bracket +.El +.Pp +Closing delimiters are: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It \&. +period +.It \&, +comma +.It \&: +colon +.It \&; +semicolon +.It \&) +right parenthesis +.It \&] +right bracket +.It \&? +question mark +.It \&! +exclamation mark +.El +.Pp +Note that even a period preceded by a backslash +.Pq Sq \e.\& +gets this special handling; use +.Sq \e&.\& +to prevent that. +.Pp +Many in-line macros interrupt their scope when they encounter +delimiters, and resume their scope when more arguments follow that +are not delimiters. +For example, +.Pp +.D1 Pf \. \&Fl "a ( b | c \e*(Ba d ) e" +.Pp +renders as: +.Pp +.D1 Fl a ( b | c \*(Ba d ) e +.Pp +This applies to both opening and closing delimiters, +and also to the middle delimiter, which does not suppress spacing: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It \&| +vertical bar +.El +.Pp +As a special case, the predefined string \e*(Ba is handled and rendered +in the same way as a plain +.Sq \&| +character. +Using this predefined string is not recommended in new manuals. +.Pp +Appending a zero-width space +.Pq Sq \e& +to the end of an input line is also useful to prevent the interpretation +of a trailing period, exclamation or question mark as the end of a +sentence, for example when an abbreviation happens to occur +at the end of a text or macro input line. +.Ss Font handling +In +.Nm +documents, usage of semantic markup is recommended in order to have +proper fonts automatically selected; only when no fitting semantic markup +is available, consider falling back to +.Sx Physical markup +macros. +Whenever any +.Nm +macro switches the +.Xr roff 7 +font mode, it will automatically restore the previous font when exiting +its scope. +Manually switching the font using the +.Xr roff 7 +.Ql \ef +font escape sequences is never required. +.Sh COMPATIBILITY +This section provides an incomplete list of compatibility issues +between mandoc and GNU troff +.Pq Qq groff . +.Pp +The following problematic behaviour is found in groff: +.Pp +.Bl -dash -compact +.It +.Ic \&Dd +with non-standard arguments behaves very strangely. +When there are three arguments, they are printed verbatim. +Any other number of arguments is replaced by the current date, +but without any arguments the string +.Dq Epoch +is printed. +.It +.Ic \&Lk +only accepts a single link-name argument; the remainder is misformatted. +.It +.Ic \&Pa +does not format its arguments when used in the FILES section under +certain list types. +.It +.Ic \&Ta +can only be called by other macros, but not at the beginning of a line. +.It +.Ic \&%C +is not implemented (up to and including groff-1.22.2). +.It +.Sq \ef +.Pq font face +and +.Sq \eF +.Pq font family face +.Sx Text Decoration +escapes behave irregularly when specified within line-macro scopes. +.It +Negative scaling units return to prior lines. +Instead, mandoc truncates them to zero. +.El +.Pp +The following features are unimplemented in mandoc: +.Pp +.Bl -dash -compact +.It +.Ic \&Bd Fl file Ar file +is unsupported for security reasons. +.It +.Ic \&Bd +.Fl filled +does not adjust the right margin, but is an alias for +.Ic \&Bd +.Fl ragged . +.It +.Ic \&Bd +.Fl literal +does not use a literal font, but is an alias for +.Ic \&Bd +.Fl unfilled . +.It +.Ic \&Bd +.Fl offset Cm center +and +.Fl offset Cm right +don't work. +Groff does not implement centered and flush-right rendering either, +but produces large indentations. +.El +.Sh SEE ALSO +.Xr man 1 , +.Xr mandoc 1 , +.Xr eqn 7 , +.Xr man 7 , +.Xr mandoc_char 7 , +.Xr roff 7 , +.Xr tbl 7 +.Pp +The web page +.Lk http://mandoc.bsd.lv/mdoc/ "extended documentation for the mdoc language" +provides a few tutorial-style pages for beginners, an extensive style +guide for advanced authors, and an alphabetic index helping to choose +the best macros for various kinds of content. +.Sh HISTORY +The +.Nm +language first appeared as a troff macro package in +.Bx 4.4 . +It was later significantly updated by Werner Lemberg and Ruslan Ermilov +in groff-1.17. +The standalone implementation that is part of the +.Xr mandoc 1 +utility written by Kristaps Dzonsons appeared in +.Ox 4.6 . +.Sh AUTHORS +The +.Nm +reference was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . Property changes on: vendor/mandoc/20190723/mdoc.7 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mdoc_argv.c =================================================================== --- vendor/mandoc/20190723/mdoc_argv.c (nonexistent) +++ vendor/mandoc/20190723/mdoc_argv.c (revision 350350) @@ -0,0 +1,682 @@ +/* $Id: mdoc_argv.c,v 1.120 2019/07/11 17:06:17 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2012, 2014-2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "libmandoc.h" +#include "roff_int.h" +#include "libmdoc.h" + +#define MULTI_STEP 5 /* pre-allocate argument values */ +#define DELIMSZ 6 /* max possible size of a delimiter */ + +enum argsflag { + ARGSFL_NONE = 0, + ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */ + ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */ +}; + +enum argvflag { + ARGV_NONE, /* no args to flag (e.g., -split) */ + ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */ + ARGV_MULTI /* multiple args (e.g., -column xxx yyy) */ +}; + +struct mdocarg { + enum argsflag flags; + const enum mdocargt *argvs; +}; + +static void argn_free(struct mdoc_arg *, int); +static enum margserr args(struct roff_man *, int, int *, + char *, enum argsflag, char **); +static int args_checkpunct(const char *, int); +static void argv_multi(struct roff_man *, int, + struct mdoc_argv *, int *, char *); +static void argv_single(struct roff_man *, int, + struct mdoc_argv *, int *, char *); + +static const enum argvflag argvflags[MDOC_ARG_MAX] = { + ARGV_NONE, /* MDOC_Split */ + ARGV_NONE, /* MDOC_Nosplit */ + ARGV_NONE, /* MDOC_Ragged */ + ARGV_NONE, /* MDOC_Unfilled */ + ARGV_NONE, /* MDOC_Literal */ + ARGV_SINGLE, /* MDOC_File */ + ARGV_SINGLE, /* MDOC_Offset */ + ARGV_NONE, /* MDOC_Bullet */ + ARGV_NONE, /* MDOC_Dash */ + ARGV_NONE, /* MDOC_Hyphen */ + ARGV_NONE, /* MDOC_Item */ + ARGV_NONE, /* MDOC_Enum */ + ARGV_NONE, /* MDOC_Tag */ + ARGV_NONE, /* MDOC_Diag */ + ARGV_NONE, /* MDOC_Hang */ + ARGV_NONE, /* MDOC_Ohang */ + ARGV_NONE, /* MDOC_Inset */ + ARGV_MULTI, /* MDOC_Column */ + ARGV_SINGLE, /* MDOC_Width */ + ARGV_NONE, /* MDOC_Compact */ + ARGV_NONE, /* MDOC_Std */ + ARGV_NONE, /* MDOC_Filled */ + ARGV_NONE, /* MDOC_Words */ + ARGV_NONE, /* MDOC_Emphasis */ + ARGV_NONE, /* MDOC_Symbolic */ + ARGV_NONE /* MDOC_Symbolic */ +}; + +static const enum mdocargt args_Ex[] = { + MDOC_Std, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_An[] = { + MDOC_Split, + MDOC_Nosplit, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_Bd[] = { + MDOC_Ragged, + MDOC_Unfilled, + MDOC_Filled, + MDOC_Literal, + MDOC_File, + MDOC_Offset, + MDOC_Compact, + MDOC_Centred, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_Bf[] = { + MDOC_Emphasis, + MDOC_Literal, + MDOC_Symbolic, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_Bk[] = { + MDOC_Words, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_Bl[] = { + MDOC_Bullet, + MDOC_Dash, + MDOC_Hyphen, + MDOC_Item, + MDOC_Enum, + MDOC_Tag, + MDOC_Diag, + MDOC_Hang, + MDOC_Ohang, + MDOC_Inset, + MDOC_Column, + MDOC_Width, + MDOC_Offset, + MDOC_Compact, + MDOC_Nested, + MDOC_ARG_MAX +}; + +static const struct mdocarg mdocargs[MDOC_MAX - MDOC_Dd] = { + { ARGSFL_NONE, NULL }, /* Dd */ + { ARGSFL_NONE, NULL }, /* Dt */ + { ARGSFL_NONE, NULL }, /* Os */ + { ARGSFL_NONE, NULL }, /* Sh */ + { ARGSFL_NONE, NULL }, /* Ss */ + { ARGSFL_NONE, NULL }, /* Pp */ + { ARGSFL_DELIM, NULL }, /* D1 */ + { ARGSFL_DELIM, NULL }, /* Dl */ + { ARGSFL_NONE, args_Bd }, /* Bd */ + { ARGSFL_NONE, NULL }, /* Ed */ + { ARGSFL_NONE, args_Bl }, /* Bl */ + { ARGSFL_NONE, NULL }, /* El */ + { ARGSFL_NONE, NULL }, /* It */ + { ARGSFL_DELIM, NULL }, /* Ad */ + { ARGSFL_DELIM, args_An }, /* An */ + { ARGSFL_DELIM, NULL }, /* Ap */ + { ARGSFL_DELIM, NULL }, /* Ar */ + { ARGSFL_DELIM, NULL }, /* Cd */ + { ARGSFL_DELIM, NULL }, /* Cm */ + { ARGSFL_DELIM, NULL }, /* Dv */ + { ARGSFL_DELIM, NULL }, /* Er */ + { ARGSFL_DELIM, NULL }, /* Ev */ + { ARGSFL_NONE, args_Ex }, /* Ex */ + { ARGSFL_DELIM, NULL }, /* Fa */ + { ARGSFL_NONE, NULL }, /* Fd */ + { ARGSFL_DELIM, NULL }, /* Fl */ + { ARGSFL_DELIM, NULL }, /* Fn */ + { ARGSFL_DELIM, NULL }, /* Ft */ + { ARGSFL_DELIM, NULL }, /* Ic */ + { ARGSFL_DELIM, NULL }, /* In */ + { ARGSFL_DELIM, NULL }, /* Li */ + { ARGSFL_NONE, NULL }, /* Nd */ + { ARGSFL_DELIM, NULL }, /* Nm */ + { ARGSFL_DELIM, NULL }, /* Op */ + { ARGSFL_DELIM, NULL }, /* Ot */ + { ARGSFL_DELIM, NULL }, /* Pa */ + { ARGSFL_NONE, args_Ex }, /* Rv */ + { ARGSFL_DELIM, NULL }, /* St */ + { ARGSFL_DELIM, NULL }, /* Va */ + { ARGSFL_DELIM, NULL }, /* Vt */ + { ARGSFL_DELIM, NULL }, /* Xr */ + { ARGSFL_NONE, NULL }, /* %A */ + { ARGSFL_NONE, NULL }, /* %B */ + { ARGSFL_NONE, NULL }, /* %D */ + { ARGSFL_NONE, NULL }, /* %I */ + { ARGSFL_NONE, NULL }, /* %J */ + { ARGSFL_NONE, NULL }, /* %N */ + { ARGSFL_NONE, NULL }, /* %O */ + { ARGSFL_NONE, NULL }, /* %P */ + { ARGSFL_NONE, NULL }, /* %R */ + { ARGSFL_NONE, NULL }, /* %T */ + { ARGSFL_NONE, NULL }, /* %V */ + { ARGSFL_DELIM, NULL }, /* Ac */ + { ARGSFL_NONE, NULL }, /* Ao */ + { ARGSFL_DELIM, NULL }, /* Aq */ + { ARGSFL_DELIM, NULL }, /* At */ + { ARGSFL_DELIM, NULL }, /* Bc */ + { ARGSFL_NONE, args_Bf }, /* Bf */ + { ARGSFL_NONE, NULL }, /* Bo */ + { ARGSFL_DELIM, NULL }, /* Bq */ + { ARGSFL_DELIM, NULL }, /* Bsx */ + { ARGSFL_DELIM, NULL }, /* Bx */ + { ARGSFL_NONE, NULL }, /* Db */ + { ARGSFL_DELIM, NULL }, /* Dc */ + { ARGSFL_NONE, NULL }, /* Do */ + { ARGSFL_DELIM, NULL }, /* Dq */ + { ARGSFL_DELIM, NULL }, /* Ec */ + { ARGSFL_NONE, NULL }, /* Ef */ + { ARGSFL_DELIM, NULL }, /* Em */ + { ARGSFL_NONE, NULL }, /* Eo */ + { ARGSFL_DELIM, NULL }, /* Fx */ + { ARGSFL_DELIM, NULL }, /* Ms */ + { ARGSFL_DELIM, NULL }, /* No */ + { ARGSFL_DELIM, NULL }, /* Ns */ + { ARGSFL_DELIM, NULL }, /* Nx */ + { ARGSFL_DELIM, NULL }, /* Ox */ + { ARGSFL_DELIM, NULL }, /* Pc */ + { ARGSFL_DELIM, NULL }, /* Pf */ + { ARGSFL_NONE, NULL }, /* Po */ + { ARGSFL_DELIM, NULL }, /* Pq */ + { ARGSFL_DELIM, NULL }, /* Qc */ + { ARGSFL_DELIM, NULL }, /* Ql */ + { ARGSFL_NONE, NULL }, /* Qo */ + { ARGSFL_DELIM, NULL }, /* Qq */ + { ARGSFL_NONE, NULL }, /* Re */ + { ARGSFL_NONE, NULL }, /* Rs */ + { ARGSFL_DELIM, NULL }, /* Sc */ + { ARGSFL_NONE, NULL }, /* So */ + { ARGSFL_DELIM, NULL }, /* Sq */ + { ARGSFL_NONE, NULL }, /* Sm */ + { ARGSFL_DELIM, NULL }, /* Sx */ + { ARGSFL_DELIM, NULL }, /* Sy */ + { ARGSFL_DELIM, NULL }, /* Tn */ + { ARGSFL_DELIM, NULL }, /* Ux */ + { ARGSFL_DELIM, NULL }, /* Xc */ + { ARGSFL_NONE, NULL }, /* Xo */ + { ARGSFL_NONE, NULL }, /* Fo */ + { ARGSFL_DELIM, NULL }, /* Fc */ + { ARGSFL_NONE, NULL }, /* Oo */ + { ARGSFL_DELIM, NULL }, /* Oc */ + { ARGSFL_NONE, args_Bk }, /* Bk */ + { ARGSFL_NONE, NULL }, /* Ek */ + { ARGSFL_NONE, NULL }, /* Bt */ + { ARGSFL_NONE, NULL }, /* Hf */ + { ARGSFL_DELIM, NULL }, /* Fr */ + { ARGSFL_NONE, NULL }, /* Ud */ + { ARGSFL_DELIM, NULL }, /* Lb */ + { ARGSFL_NONE, NULL }, /* Lp */ + { ARGSFL_DELIM, NULL }, /* Lk */ + { ARGSFL_DELIM, NULL }, /* Mt */ + { ARGSFL_DELIM, NULL }, /* Brq */ + { ARGSFL_NONE, NULL }, /* Bro */ + { ARGSFL_DELIM, NULL }, /* Brc */ + { ARGSFL_NONE, NULL }, /* %C */ + { ARGSFL_NONE, NULL }, /* Es */ + { ARGSFL_DELIM, NULL }, /* En */ + { ARGSFL_DELIM, NULL }, /* Dx */ + { ARGSFL_NONE, NULL }, /* %Q */ + { ARGSFL_NONE, NULL }, /* %U */ + { ARGSFL_NONE, NULL }, /* Ta */ +}; + + +/* + * Parse flags and their arguments from the input line. + * These come in the form -flag [argument ...]. + * Some flags take no argument, some one, some multiple. + */ +void +mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok, + struct mdoc_arg **reta, int *pos, char *buf) +{ + struct mdoc_argv tmpv; + struct mdoc_argv **retv; + const enum mdocargt *argtable; + char *argname; + int ipos, retc; + char savechar; + + *reta = NULL; + + /* Which flags does this macro support? */ + + assert(tok >= MDOC_Dd && tok < MDOC_MAX); + argtable = mdocargs[tok - MDOC_Dd].argvs; + if (argtable == NULL) + return; + + /* Loop over the flags on the input line. */ + + ipos = *pos; + while (buf[ipos] == '-') { + + /* Seek to the first unescaped space. */ + + for (argname = buf + ++ipos; buf[ipos] != '\0'; ipos++) + if (buf[ipos] == ' ' && buf[ipos - 1] != '\\') + break; + + /* + * We want to nil-terminate the word to look it up. + * But we may not have a flag, in which case we need + * to restore the line as-is. So keep around the + * stray byte, which we'll reset upon exiting. + */ + + if ((savechar = buf[ipos]) != '\0') + buf[ipos++] = '\0'; + + /* + * Now look up the word as a flag. Use temporary + * storage that we'll copy into the node's flags. + */ + + while ((tmpv.arg = *argtable++) != MDOC_ARG_MAX) + if ( ! strcmp(argname, mdoc_argnames[tmpv.arg])) + break; + + /* If it isn't a flag, restore the saved byte. */ + + if (tmpv.arg == MDOC_ARG_MAX) { + if (savechar != '\0') + buf[ipos - 1] = savechar; + break; + } + + /* Read to the next word (the first argument). */ + + while (buf[ipos] == ' ') + ipos++; + + /* Parse the arguments of the flag. */ + + tmpv.line = line; + tmpv.pos = *pos; + tmpv.sz = 0; + tmpv.value = NULL; + + switch (argvflags[tmpv.arg]) { + case ARGV_SINGLE: + argv_single(mdoc, line, &tmpv, &ipos, buf); + break; + case ARGV_MULTI: + argv_multi(mdoc, line, &tmpv, &ipos, buf); + break; + case ARGV_NONE: + break; + } + + /* Append to the return values. */ + + if (*reta == NULL) + *reta = mandoc_calloc(1, sizeof(**reta)); + + retc = ++(*reta)->argc; + retv = &(*reta)->argv; + *retv = mandoc_reallocarray(*retv, retc, sizeof(**retv)); + memcpy(*retv + retc - 1, &tmpv, sizeof(**retv)); + + /* Prepare for parsing the next flag. */ + + *pos = ipos; + argtable = mdocargs[tok - MDOC_Dd].argvs; + } +} + +void +mdoc_argv_free(struct mdoc_arg *p) +{ + int i; + + if (NULL == p) + return; + + if (p->refcnt) { + --(p->refcnt); + if (p->refcnt) + return; + } + assert(p->argc); + + for (i = (int)p->argc - 1; i >= 0; i--) + argn_free(p, i); + + free(p->argv); + free(p); +} + +static void +argn_free(struct mdoc_arg *p, int iarg) +{ + struct mdoc_argv *arg; + int j; + + arg = &p->argv[iarg]; + + if (arg->sz && arg->value) { + for (j = (int)arg->sz - 1; j >= 0; j--) + free(arg->value[j]); + free(arg->value); + } + + for (--p->argc; iarg < (int)p->argc; iarg++) + p->argv[iarg] = p->argv[iarg+1]; +} + +enum margserr +mdoc_args(struct roff_man *mdoc, int line, int *pos, + char *buf, enum roff_tok tok, char **v) +{ + struct roff_node *n; + enum argsflag fl; + + fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok - MDOC_Dd].flags; + + /* + * We know that we're in an `It', so it's reasonable to expect + * us to be sitting in a `Bl'. Someday this may not be the case + * (if we allow random `It's sitting out there), so provide a + * safe fall-back into the default behaviour. + */ + + if (tok == MDOC_It) { + for (n = mdoc->last; n != NULL; n = n->parent) { + if (n->tok != MDOC_Bl) + continue; + if (n->norm->Bl.type == LIST_column) + fl = ARGSFL_TABSEP; + break; + } + } + + return args(mdoc, line, pos, buf, fl, v); +} + +static enum margserr +args(struct roff_man *mdoc, int line, int *pos, + char *buf, enum argsflag fl, char **v) +{ + char *p; + char *v_local; + int pairs; + + if (buf[*pos] == '\0') { + if (mdoc->flags & MDOC_PHRASELIT && + ! (mdoc->flags & MDOC_PHRASE)) { + mandoc_msg(MANDOCERR_ARG_QUOTE, line, *pos, NULL); + mdoc->flags &= ~MDOC_PHRASELIT; + } + mdoc->flags &= ~MDOC_PHRASEQL; + return ARGS_EOLN; + } + + if (v == NULL) + v = &v_local; + *v = buf + *pos; + + if (fl == ARGSFL_DELIM && args_checkpunct(buf, *pos)) + return ARGS_PUNCT; + + /* + * Tabs in `It' lines in `Bl -column' can't be escaped. + * Phrases are reparsed for `Ta' and other macros later. + */ + + if (fl == ARGSFL_TABSEP) { + if ((p = strchr(*v, '\t')) != NULL) { + + /* + * Words right before and right after + * tab characters are not parsed, + * unless there is a blank in between. + */ + + if (p > buf && p[-1] != ' ') + mdoc->flags |= MDOC_PHRASEQL; + if (p[1] != ' ') + mdoc->flags |= MDOC_PHRASEQN; + + /* + * One or more blanks after a tab cause + * one leading blank in the next column. + * So skip all but one of them. + */ + + *pos += (int)(p - *v) + 1; + while (buf[*pos] == ' ' && buf[*pos + 1] == ' ') + (*pos)++; + + /* + * A tab at the end of an input line + * switches to the next column. + */ + + if (buf[*pos] == '\0' || buf[*pos + 1] == '\0') + mdoc->flags |= MDOC_PHRASEQN; + } else { + p = strchr(*v, '\0'); + if (p[-1] == ' ') + mandoc_msg(MANDOCERR_SPACE_EOL, + line, *pos, NULL); + *pos += (int)(p - *v); + } + + /* Skip any trailing blank characters. */ + while (p > *v && p[-1] == ' ' && + (p - 1 == *v || p[-2] != '\\')) + p--; + *p = '\0'; + + return ARGS_PHRASE; + } + + /* + * Process a quoted literal. A quote begins with a double-quote + * and ends with a double-quote NOT preceded by a double-quote. + * NUL-terminate the literal in place. + * Collapse pairs of quotes inside quoted literals. + * Whitespace is NOT involved in literal termination. + */ + + if (mdoc->flags & MDOC_PHRASELIT || + (mdoc->flags & MDOC_PHRASE && buf[*pos] == '\"')) { + if ((mdoc->flags & MDOC_PHRASELIT) == 0) { + *v = &buf[++(*pos)]; + mdoc->flags |= MDOC_PHRASELIT; + } + pairs = 0; + for ( ; buf[*pos]; (*pos)++) { + /* Move following text left after quoted quotes. */ + if (pairs) + buf[*pos - pairs] = buf[*pos]; + if ('\"' != buf[*pos]) + continue; + /* Unquoted quotes end quoted args. */ + if ('\"' != buf[*pos + 1]) + break; + /* Quoted quotes collapse. */ + pairs++; + (*pos)++; + } + if (pairs) + buf[*pos - pairs] = '\0'; + + if (buf[*pos] == '\0') { + if ( ! (mdoc->flags & MDOC_PHRASE)) + mandoc_msg(MANDOCERR_ARG_QUOTE, + line, *pos, NULL); + return ARGS_WORD; + } + + mdoc->flags &= ~MDOC_PHRASELIT; + buf[(*pos)++] = '\0'; + + if ('\0' == buf[*pos]) + return ARGS_WORD; + + while (' ' == buf[*pos]) + (*pos)++; + + if ('\0' == buf[*pos]) + mandoc_msg(MANDOCERR_SPACE_EOL, line, *pos, NULL); + + return ARGS_WORD; + } + + p = &buf[*pos]; + *v = roff_getarg(mdoc->roff, &p, line, pos); + if (v == &v_local) + free(*v); + + /* + * After parsing the last word in this phrase, + * tell lookup() whether or not to interpret it. + */ + + if (*p == '\0' && mdoc->flags & MDOC_PHRASEQL) { + mdoc->flags &= ~MDOC_PHRASEQL; + mdoc->flags |= MDOC_PHRASEQF; + } + return ARGS_ALLOC; +} + +/* + * Check if the string consists only of space-separated closing + * delimiters. This is a bit of a dance: the first must be a close + * delimiter, but it may be followed by middle delimiters. Arbitrary + * whitespace may separate these tokens. + */ +static int +args_checkpunct(const char *buf, int i) +{ + int j; + char dbuf[DELIMSZ]; + enum mdelim d; + + /* First token must be a close-delimiter. */ + + for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++) + dbuf[j] = buf[i]; + + if (DELIMSZ == j) + return 0; + + dbuf[j] = '\0'; + if (DELIM_CLOSE != mdoc_isdelim(dbuf)) + return 0; + + while (' ' == buf[i]) + i++; + + /* Remaining must NOT be open/none. */ + + while (buf[i]) { + j = 0; + while (buf[i] && ' ' != buf[i] && j < DELIMSZ) + dbuf[j++] = buf[i++]; + + if (DELIMSZ == j) + return 0; + + dbuf[j] = '\0'; + d = mdoc_isdelim(dbuf); + if (DELIM_NONE == d || DELIM_OPEN == d) + return 0; + + while (' ' == buf[i]) + i++; + } + + return '\0' == buf[i]; +} + +static void +argv_multi(struct roff_man *mdoc, int line, + struct mdoc_argv *v, int *pos, char *buf) +{ + enum margserr ac; + char *p; + + for (v->sz = 0; ; v->sz++) { + if (buf[*pos] == '-') + break; + ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); + if (ac == ARGS_EOLN) + break; + + if (v->sz % MULTI_STEP == 0) + v->value = mandoc_reallocarray(v->value, + v->sz + MULTI_STEP, sizeof(char *)); + + if (ac != ARGS_ALLOC) + p = mandoc_strdup(p); + v->value[(int)v->sz] = p; + } +} + +static void +argv_single(struct roff_man *mdoc, int line, + struct mdoc_argv *v, int *pos, char *buf) +{ + enum margserr ac; + char *p; + + ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); + if (ac == ARGS_EOLN) + return; + + if (ac != ARGS_ALLOC) + p = mandoc_strdup(p); + + v->sz = 1; + v->value = mandoc_malloc(sizeof(char *)); + v->value[0] = p; +} Property changes on: vendor/mandoc/20190723/mdoc_argv.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mdoc_markdown.c =================================================================== --- vendor/mandoc/20190723/mdoc_markdown.c (nonexistent) +++ vendor/mandoc/20190723/mdoc_markdown.c (revision 350350) @@ -0,0 +1,1591 @@ +/* $Id: mdoc_markdown.c,v 1.31 2019/07/01 22:56:24 schwarze Exp $ */ +/* + * Copyright (c) 2017, 2018 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include + +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "main.h" + +struct md_act { + int (*cond)(struct roff_node *n); + int (*pre)(struct roff_node *n); + void (*post)(struct roff_node *n); + const char *prefix; /* pre-node string constant */ + const char *suffix; /* post-node string constant */ +}; + +static void md_nodelist(struct roff_node *); +static void md_node(struct roff_node *); +static const char *md_stack(char c); +static void md_preword(void); +static void md_rawword(const char *); +static void md_word(const char *); +static void md_named(const char *); +static void md_char(unsigned char); +static void md_uri(const char *); + +static int md_cond_head(struct roff_node *); +static int md_cond_body(struct roff_node *); + +static int md_pre_abort(struct roff_node *); +static int md_pre_raw(struct roff_node *); +static int md_pre_word(struct roff_node *); +static int md_pre_skip(struct roff_node *); +static void md_pre_syn(struct roff_node *); +static int md_pre_An(struct roff_node *); +static int md_pre_Ap(struct roff_node *); +static int md_pre_Bd(struct roff_node *); +static int md_pre_Bk(struct roff_node *); +static int md_pre_Bl(struct roff_node *); +static int md_pre_D1(struct roff_node *); +static int md_pre_Dl(struct roff_node *); +static int md_pre_En(struct roff_node *); +static int md_pre_Eo(struct roff_node *); +static int md_pre_Fa(struct roff_node *); +static int md_pre_Fd(struct roff_node *); +static int md_pre_Fn(struct roff_node *); +static int md_pre_Fo(struct roff_node *); +static int md_pre_In(struct roff_node *); +static int md_pre_It(struct roff_node *); +static int md_pre_Lk(struct roff_node *); +static int md_pre_Mt(struct roff_node *); +static int md_pre_Nd(struct roff_node *); +static int md_pre_Nm(struct roff_node *); +static int md_pre_No(struct roff_node *); +static int md_pre_Ns(struct roff_node *); +static int md_pre_Pp(struct roff_node *); +static int md_pre_Rs(struct roff_node *); +static int md_pre_Sh(struct roff_node *); +static int md_pre_Sm(struct roff_node *); +static int md_pre_Vt(struct roff_node *); +static int md_pre_Xr(struct roff_node *); +static int md_pre__T(struct roff_node *); +static int md_pre_br(struct roff_node *); + +static void md_post_raw(struct roff_node *); +static void md_post_word(struct roff_node *); +static void md_post_pc(struct roff_node *); +static void md_post_Bk(struct roff_node *); +static void md_post_Bl(struct roff_node *); +static void md_post_D1(struct roff_node *); +static void md_post_En(struct roff_node *); +static void md_post_Eo(struct roff_node *); +static void md_post_Fa(struct roff_node *); +static void md_post_Fd(struct roff_node *); +static void md_post_Fl(struct roff_node *); +static void md_post_Fn(struct roff_node *); +static void md_post_Fo(struct roff_node *); +static void md_post_In(struct roff_node *); +static void md_post_It(struct roff_node *); +static void md_post_Lb(struct roff_node *); +static void md_post_Nm(struct roff_node *); +static void md_post_Pf(struct roff_node *); +static void md_post_Vt(struct roff_node *); +static void md_post__T(struct roff_node *); + +static const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = { + { NULL, NULL, NULL, NULL, NULL }, /* Dd */ + { NULL, NULL, NULL, NULL, NULL }, /* Dt */ + { NULL, NULL, NULL, NULL, NULL }, /* Os */ + { NULL, md_pre_Sh, NULL, NULL, NULL }, /* Sh */ + { NULL, md_pre_Sh, NULL, NULL, NULL }, /* Ss */ + { NULL, md_pre_Pp, NULL, NULL, NULL }, /* Pp */ + { md_cond_body, md_pre_D1, md_post_D1, NULL, NULL }, /* D1 */ + { md_cond_body, md_pre_Dl, md_post_D1, NULL, NULL }, /* Dl */ + { md_cond_body, md_pre_Bd, md_post_D1, NULL, NULL }, /* Bd */ + { NULL, NULL, NULL, NULL, NULL }, /* Ed */ + { md_cond_body, md_pre_Bl, md_post_Bl, NULL, NULL }, /* Bl */ + { NULL, NULL, NULL, NULL, NULL }, /* El */ + { NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */ + { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */ + { NULL, md_pre_An, NULL, NULL, NULL }, /* An */ + { NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */ + { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ar */ + { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */ + { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */ + { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Dv */ + { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Er */ + { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Ev */ + { NULL, NULL, NULL, NULL, NULL }, /* Ex */ + { NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */ + { NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */ + { NULL, md_pre_raw, md_post_Fl, "**-", "**" }, /* Fl */ + { NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */ + { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */ + { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */ + { NULL, md_pre_In, md_post_In, NULL, NULL }, /* In */ + { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */ + { md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */ + { NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */ + { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */ + { NULL, md_pre_abort, NULL, NULL, NULL }, /* Ot */ + { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */ + { NULL, NULL, NULL, NULL, NULL }, /* Rv */ + { NULL, NULL, NULL, NULL, NULL }, /* St */ + { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Va */ + { NULL, md_pre_Vt, md_post_Vt, "*", "*" }, /* Vt */ + { NULL, md_pre_Xr, NULL, NULL, NULL }, /* Xr */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %A */ + { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %B */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %D */ + { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %I */ + { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %J */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %N */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %O */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %P */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %R */ + { NULL, md_pre__T, md_post__T, NULL, NULL }, /* %T */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %V */ + { NULL, NULL, NULL, NULL, NULL }, /* Ac */ + { md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Ao */ + { md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Aq */ + { NULL, NULL, NULL, NULL, NULL }, /* At */ + { NULL, NULL, NULL, NULL, NULL }, /* Bc */ + { NULL, NULL, NULL, NULL, NULL }, /* Bf XXX not implemented */ + { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bo */ + { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bq */ + { NULL, NULL, NULL, NULL, NULL }, /* Bsx */ + { NULL, NULL, NULL, NULL, NULL }, /* Bx */ + { NULL, NULL, NULL, NULL, NULL }, /* Db */ + { NULL, NULL, NULL, NULL, NULL }, /* Dc */ + { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Do */ + { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Dq */ + { NULL, NULL, NULL, NULL, NULL }, /* Ec */ + { NULL, NULL, NULL, NULL, NULL }, /* Ef */ + { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Em */ + { md_cond_body, md_pre_Eo, md_post_Eo, NULL, NULL }, /* Eo */ + { NULL, NULL, NULL, NULL, NULL }, /* Fx */ + { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ms */ + { NULL, md_pre_No, NULL, NULL, NULL }, /* No */ + { NULL, md_pre_Ns, NULL, NULL, NULL }, /* Ns */ + { NULL, NULL, NULL, NULL, NULL }, /* Nx */ + { NULL, NULL, NULL, NULL, NULL }, /* Ox */ + { NULL, NULL, NULL, NULL, NULL }, /* Pc */ + { NULL, NULL, md_post_Pf, NULL, NULL }, /* Pf */ + { md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Po */ + { md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Pq */ + { NULL, NULL, NULL, NULL, NULL }, /* Qc */ + { md_cond_body, md_pre_raw, md_post_raw, "'`", "`'" }, /* Ql */ + { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qo */ + { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qq */ + { NULL, NULL, NULL, NULL, NULL }, /* Re */ + { md_cond_body, md_pre_Rs, NULL, NULL, NULL }, /* Rs */ + { NULL, NULL, NULL, NULL, NULL }, /* Sc */ + { md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* So */ + { md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* Sq */ + { NULL, md_pre_Sm, NULL, NULL, NULL }, /* Sm */ + { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Sx */ + { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Sy */ + { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Tn */ + { NULL, NULL, NULL, NULL, NULL }, /* Ux */ + { NULL, NULL, NULL, NULL, NULL }, /* Xc */ + { NULL, NULL, NULL, NULL, NULL }, /* Xo */ + { NULL, md_pre_Fo, md_post_Fo, "**", "**" }, /* Fo */ + { NULL, NULL, NULL, NULL, NULL }, /* Fc */ + { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Oo */ + { NULL, NULL, NULL, NULL, NULL }, /* Oc */ + { NULL, md_pre_Bk, md_post_Bk, NULL, NULL }, /* Bk */ + { NULL, NULL, NULL, NULL, NULL }, /* Ek */ + { NULL, NULL, NULL, NULL, NULL }, /* Bt */ + { NULL, NULL, NULL, NULL, NULL }, /* Hf */ + { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */ + { NULL, NULL, NULL, NULL, NULL }, /* Ud */ + { NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */ + { NULL, md_pre_abort, NULL, NULL, NULL }, /* Lp */ + { NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */ + { NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */ + { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */ + { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */ + { NULL, NULL, NULL, NULL, NULL }, /* Brc */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %C */ + { NULL, md_pre_skip, NULL, NULL, NULL }, /* Es */ + { md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */ + { NULL, NULL, NULL, NULL, NULL }, /* Dx */ + { NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */ + { NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */ + { NULL, NULL, NULL, NULL, NULL }, /* Ta */ +}; +static const struct md_act *md_act(enum roff_tok); + +static int outflags; +#define MD_spc (1 << 0) /* Blank character before next word. */ +#define MD_spc_force (1 << 1) /* Even before trailing punctuation. */ +#define MD_nonl (1 << 2) /* Prevent linebreak in markdown code. */ +#define MD_nl (1 << 3) /* Break markdown code line. */ +#define MD_br (1 << 4) /* Insert an output line break. */ +#define MD_sp (1 << 5) /* Insert a paragraph break. */ +#define MD_Sm (1 << 6) /* Horizontal spacing mode. */ +#define MD_Bk (1 << 7) /* Word keep mode. */ +#define MD_An_split (1 << 8) /* Author mode is "split". */ +#define MD_An_nosplit (1 << 9) /* Author mode is "nosplit". */ + +static int escflags; /* Escape in generated markdown code: */ +#define ESC_BOL (1 << 0) /* "#*+-" near the beginning of a line. */ +#define ESC_NUM (1 << 1) /* "." after a leading number. */ +#define ESC_HYP (1 << 2) /* "(" immediately after "]". */ +#define ESC_SQU (1 << 4) /* "]" when "[" is open. */ +#define ESC_FON (1 << 5) /* "*" immediately after unrelated "*". */ +#define ESC_EOL (1 << 6) /* " " at the and of a line. */ + +static int code_blocks, quote_blocks, list_blocks; +static int outcount; + + +static const struct md_act * +md_act(enum roff_tok tok) +{ + assert(tok >= MDOC_Dd && tok <= MDOC_MAX); + return md_acts + (tok - MDOC_Dd); +} + +void +markdown_mdoc(void *arg, const struct roff_meta *mdoc) +{ + outflags = MD_Sm; + md_word(mdoc->title); + if (mdoc->msec != NULL) { + outflags &= ~MD_spc; + md_word("("); + md_word(mdoc->msec); + md_word(")"); + } + md_word("-"); + md_word(mdoc->vol); + if (mdoc->arch != NULL) { + md_word("("); + md_word(mdoc->arch); + md_word(")"); + } + outflags |= MD_sp; + + md_nodelist(mdoc->first->child); + + outflags |= MD_sp; + md_word(mdoc->os); + md_word("-"); + md_word(mdoc->date); + putchar('\n'); +} + +static void +md_nodelist(struct roff_node *n) +{ + while (n != NULL) { + md_node(n); + n = n->next; + } +} + +static void +md_node(struct roff_node *n) +{ + const struct md_act *act; + int cond, process_children; + + if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) + return; + + if (outflags & MD_nonl) + outflags &= ~(MD_nl | MD_sp); + else if (outflags & MD_spc && n->flags & NODE_LINE) + outflags |= MD_nl; + + act = NULL; + cond = 0; + process_children = 1; + n->flags &= ~NODE_ENDED; + + if (n->type == ROFFT_TEXT) { + if (n->flags & NODE_DELIMC) + outflags &= ~(MD_spc | MD_spc_force); + else if (outflags & MD_Sm) + outflags |= MD_spc_force; + md_word(n->string); + if (n->flags & NODE_DELIMO) + outflags &= ~(MD_spc | MD_spc_force); + else if (outflags & MD_Sm) + outflags |= MD_spc; + } else if (n->tok < ROFF_MAX) { + switch (n->tok) { + case ROFF_br: + process_children = md_pre_br(n); + break; + case ROFF_sp: + process_children = md_pre_Pp(n); + break; + default: + process_children = 0; + break; + } + } else { + act = md_act(n->tok); + cond = act->cond == NULL || (*act->cond)(n); + if (cond && act->pre != NULL && + (n->end == ENDBODY_NOT || n->child != NULL)) + process_children = (*act->pre)(n); + } + + if (process_children && n->child != NULL) + md_nodelist(n->child); + + if (n->flags & NODE_ENDED) + return; + + if (cond && act->post != NULL) + (*act->post)(n); + + if (n->end != ENDBODY_NOT) + n->body->flags |= NODE_ENDED; +} + +static const char * +md_stack(char c) +{ + static char *stack; + static size_t sz; + static size_t cur; + + switch (c) { + case '\0': + break; + case (char)-1: + assert(cur); + stack[--cur] = '\0'; + break; + default: + if (cur + 1 >= sz) { + sz += 8; + stack = mandoc_realloc(stack, sz); + } + stack[cur] = c; + stack[++cur] = '\0'; + break; + } + return stack == NULL ? "" : stack; +} + +/* + * Handle vertical and horizontal spacing. + */ +static void +md_preword(void) +{ + const char *cp; + + /* + * If a list block is nested inside a code block or a blockquote, + * blank lines for paragraph breaks no longer work; instead, + * they terminate the list. Work around this markdown issue + * by using mere line breaks instead. + */ + + if (list_blocks && outflags & MD_sp) { + outflags &= ~MD_sp; + outflags |= MD_br; + } + + /* + * End the old line if requested. + * Escape whitespace at the end of the markdown line + * such that it won't look like an output line break. + */ + + if (outflags & MD_sp) + putchar('\n'); + else if (outflags & MD_br) { + putchar(' '); + putchar(' '); + } else if (outflags & MD_nl && escflags & ESC_EOL) + md_named("zwnj"); + + /* Start a new line if necessary. */ + + if (outflags & (MD_nl | MD_br | MD_sp)) { + putchar('\n'); + for (cp = md_stack('\0'); *cp != '\0'; cp++) { + putchar(*cp); + if (*cp == '>') + putchar(' '); + } + outflags &= ~(MD_nl | MD_br | MD_sp); + escflags = ESC_BOL; + outcount = 0; + + /* Handle horizontal spacing. */ + + } else if (outflags & MD_spc) { + if (outflags & MD_Bk) + fputs(" ", stdout); + else + putchar(' '); + escflags &= ~ESC_FON; + outcount++; + } + + outflags &= ~(MD_spc_force | MD_nonl); + if (outflags & MD_Sm) + outflags |= MD_spc; + else + outflags &= ~MD_spc; +} + +/* + * Print markdown syntax elements. + * Can also be used for constant strings when neither escaping + * nor delimiter handling is required. + */ +static void +md_rawword(const char *s) +{ + md_preword(); + + if (*s == '\0') + return; + + if (escflags & ESC_FON) { + escflags &= ~ESC_FON; + if (*s == '*' && !code_blocks) + fputs("‌", stdout); + } + + while (*s != '\0') { + switch(*s) { + case '*': + if (s[1] == '\0') + escflags |= ESC_FON; + break; + case '[': + escflags |= ESC_SQU; + break; + case ']': + escflags |= ESC_HYP; + escflags &= ~ESC_SQU; + break; + default: + break; + } + md_char(*s++); + } + if (s[-1] == ' ') + escflags |= ESC_EOL; + else + escflags &= ~ESC_EOL; +} + +/* + * Print text and mdoc(7) syntax elements. + */ +static void +md_word(const char *s) +{ + const char *seq, *prevfont, *currfont, *nextfont; + char c; + int bs, sz, uc, breakline; + + /* No spacing before closing delimiters. */ + if (s[0] != '\0' && s[1] == '\0' && + strchr("!),.:;?]", s[0]) != NULL && + (outflags & MD_spc_force) == 0) + outflags &= ~MD_spc; + + md_preword(); + + if (*s == '\0') + return; + + /* No spacing after opening delimiters. */ + if ((s[0] == '(' || s[0] == '[') && s[1] == '\0') + outflags &= ~MD_spc; + + breakline = 0; + prevfont = currfont = ""; + while ((c = *s++) != '\0') { + bs = 0; + switch(c) { + case ASCII_NBRSP: + if (code_blocks) + c = ' '; + else { + md_named("nbsp"); + c = '\0'; + } + break; + case ASCII_HYPH: + bs = escflags & ESC_BOL && !code_blocks; + c = '-'; + break; + case ASCII_BREAK: + continue; + case '#': + case '+': + case '-': + bs = escflags & ESC_BOL && !code_blocks; + break; + case '(': + bs = escflags & ESC_HYP && !code_blocks; + break; + case ')': + bs = escflags & ESC_NUM && !code_blocks; + break; + case '*': + case '[': + case '_': + case '`': + bs = !code_blocks; + break; + case '.': + bs = escflags & ESC_NUM && !code_blocks; + break; + case '<': + if (code_blocks == 0) { + md_named("lt"); + c = '\0'; + } + break; + case '=': + if (escflags & ESC_BOL && !code_blocks) { + md_named("equals"); + c = '\0'; + } + break; + case '>': + if (code_blocks == 0) { + md_named("gt"); + c = '\0'; + } + break; + case '\\': + uc = 0; + nextfont = NULL; + switch (mandoc_escape(&s, &seq, &sz)) { + case ESCAPE_UNICODE: + uc = mchars_num2uc(seq + 1, sz - 1); + break; + case ESCAPE_NUMBERED: + uc = mchars_num2char(seq, sz); + break; + case ESCAPE_SPECIAL: + uc = mchars_spec2cp(seq, sz); + break; + case ESCAPE_UNDEF: + uc = *seq; + break; + case ESCAPE_DEVICE: + md_rawword("markdown"); + continue; + case ESCAPE_FONTBOLD: + nextfont = "**"; + break; + case ESCAPE_FONTITALIC: + nextfont = "*"; + break; + case ESCAPE_FONTBI: + nextfont = "***"; + break; + case ESCAPE_FONT: + case ESCAPE_FONTCW: + case ESCAPE_FONTROMAN: + nextfont = ""; + break; + case ESCAPE_FONTPREV: + nextfont = prevfont; + break; + case ESCAPE_BREAK: + breakline = 1; + break; + case ESCAPE_NOSPACE: + case ESCAPE_SKIPCHAR: + case ESCAPE_OVERSTRIKE: + /* XXX not implemented */ + /* FALLTHROUGH */ + case ESCAPE_ERROR: + default: + break; + } + if (nextfont != NULL && !code_blocks) { + if (*currfont != '\0') { + outflags &= ~MD_spc; + md_rawword(currfont); + } + prevfont = currfont; + currfont = nextfont; + if (*currfont != '\0') { + outflags &= ~MD_spc; + md_rawword(currfont); + } + } + if (uc) { + if ((uc < 0x20 && uc != 0x09) || + (uc > 0x7E && uc < 0xA0)) + uc = 0xFFFD; + if (code_blocks) { + seq = mchars_uc2str(uc); + fputs(seq, stdout); + outcount += strlen(seq); + } else { + printf("&#%d;", uc); + outcount++; + } + escflags &= ~ESC_FON; + } + c = '\0'; + break; + case ']': + bs = escflags & ESC_SQU && !code_blocks; + escflags |= ESC_HYP; + break; + default: + break; + } + if (bs) + putchar('\\'); + md_char(c); + if (breakline && + (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) { + printf(" \n"); + breakline = 0; + while (*s == ' ' || *s == ASCII_NBRSP) + s++; + } + } + if (*currfont != '\0') { + outflags &= ~MD_spc; + md_rawword(currfont); + } else if (s[-2] == ' ') + escflags |= ESC_EOL; + else + escflags &= ~ESC_EOL; +} + +/* + * Print a single HTML named character reference. + */ +static void +md_named(const char *s) +{ + printf("&%s;", s); + escflags &= ~(ESC_FON | ESC_EOL); + outcount++; +} + +/* + * Print a single raw character and maintain certain escape flags. + */ +static void +md_char(unsigned char c) +{ + if (c != '\0') { + putchar(c); + if (c == '*') + escflags |= ESC_FON; + else + escflags &= ~ESC_FON; + outcount++; + } + if (c != ']') + escflags &= ~ESC_HYP; + if (c == ' ' || c == '\t' || c == '>') + return; + if (isdigit(c) == 0) + escflags &= ~ESC_NUM; + else if (escflags & ESC_BOL) + escflags |= ESC_NUM; + escflags &= ~ESC_BOL; +} + +static int +md_cond_head(struct roff_node *n) +{ + return n->type == ROFFT_HEAD; +} + +static int +md_cond_body(struct roff_node *n) +{ + return n->type == ROFFT_BODY; +} + +static int +md_pre_abort(struct roff_node *n) +{ + abort(); +} + +static int +md_pre_raw(struct roff_node *n) +{ + const char *prefix; + + if ((prefix = md_act(n->tok)->prefix) != NULL) { + md_rawword(prefix); + outflags &= ~MD_spc; + if (*prefix == '`') + code_blocks++; + } + return 1; +} + +static void +md_post_raw(struct roff_node *n) +{ + const char *suffix; + + if ((suffix = md_act(n->tok)->suffix) != NULL) { + outflags &= ~(MD_spc | MD_nl); + md_rawword(suffix); + if (*suffix == '`') + code_blocks--; + } +} + +static int +md_pre_word(struct roff_node *n) +{ + const char *prefix; + + if ((prefix = md_act(n->tok)->prefix) != NULL) { + md_word(prefix); + outflags &= ~MD_spc; + } + return 1; +} + +static void +md_post_word(struct roff_node *n) +{ + const char *suffix; + + if ((suffix = md_act(n->tok)->suffix) != NULL) { + outflags &= ~(MD_spc | MD_nl); + md_word(suffix); + } +} + +static void +md_post_pc(struct roff_node *n) +{ + md_post_raw(n); + if (n->parent->tok != MDOC_Rs) + return; + if (n->next != NULL) { + md_word(","); + if (n->prev != NULL && + n->prev->tok == n->tok && + n->next->tok == n->tok) + md_word("and"); + } else { + md_word("."); + outflags |= MD_nl; + } +} + +static int +md_pre_skip(struct roff_node *n) +{ + return 0; +} + +static void +md_pre_syn(struct roff_node *n) +{ + if (n->prev == NULL || ! (n->flags & NODE_SYNPRETTY)) + return; + + if (n->prev->tok == n->tok && + n->tok != MDOC_Ft && + n->tok != MDOC_Fo && + n->tok != MDOC_Fn) { + outflags |= MD_br; + return; + } + + switch (n->prev->tok) { + case MDOC_Fd: + case MDOC_Fn: + case MDOC_Fo: + case MDOC_In: + case MDOC_Vt: + outflags |= MD_sp; + break; + case MDOC_Ft: + if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) { + outflags |= MD_sp; + break; + } + /* FALLTHROUGH */ + default: + outflags |= MD_br; + break; + } +} + +static int +md_pre_An(struct roff_node *n) +{ + switch (n->norm->An.auth) { + case AUTH_split: + outflags &= ~MD_An_nosplit; + outflags |= MD_An_split; + return 0; + case AUTH_nosplit: + outflags &= ~MD_An_split; + outflags |= MD_An_nosplit; + return 0; + default: + if (outflags & MD_An_split) + outflags |= MD_br; + else if (n->sec == SEC_AUTHORS && + ! (outflags & MD_An_nosplit)) + outflags |= MD_An_split; + return 1; + } +} + +static int +md_pre_Ap(struct roff_node *n) +{ + outflags &= ~MD_spc; + md_word("'"); + outflags &= ~MD_spc; + return 0; +} + +static int +md_pre_Bd(struct roff_node *n) +{ + switch (n->norm->Bd.type) { + case DISP_unfilled: + case DISP_literal: + return md_pre_Dl(n); + default: + return md_pre_D1(n); + } +} + +static int +md_pre_Bk(struct roff_node *n) +{ + switch (n->type) { + case ROFFT_BLOCK: + return 1; + case ROFFT_BODY: + outflags |= MD_Bk; + return 1; + default: + return 0; + } +} + +static void +md_post_Bk(struct roff_node *n) +{ + if (n->type == ROFFT_BODY) + outflags &= ~MD_Bk; +} + +static int +md_pre_Bl(struct roff_node *n) +{ + n->norm->Bl.count = 0; + if (n->norm->Bl.type == LIST_column) + md_pre_Dl(n); + outflags |= MD_sp; + return 1; +} + +static void +md_post_Bl(struct roff_node *n) +{ + n->norm->Bl.count = 0; + if (n->norm->Bl.type == LIST_column) + md_post_D1(n); + outflags |= MD_sp; +} + +static int +md_pre_D1(struct roff_node *n) +{ + /* + * Markdown blockquote syntax does not work inside code blocks. + * The best we can do is fall back to another nested code block. + */ + if (code_blocks) { + md_stack('\t'); + code_blocks++; + } else { + md_stack('>'); + quote_blocks++; + } + outflags |= MD_sp; + return 1; +} + +static void +md_post_D1(struct roff_node *n) +{ + md_stack((char)-1); + if (code_blocks) + code_blocks--; + else + quote_blocks--; + outflags |= MD_sp; +} + +static int +md_pre_Dl(struct roff_node *n) +{ + /* + * Markdown code block syntax does not work inside blockquotes. + * The best we can do is fall back to another nested blockquote. + */ + if (quote_blocks) { + md_stack('>'); + quote_blocks++; + } else { + md_stack('\t'); + code_blocks++; + } + outflags |= MD_sp; + return 1; +} + +static int +md_pre_En(struct roff_node *n) +{ + if (n->norm->Es == NULL || + n->norm->Es->child == NULL) + return 1; + + md_word(n->norm->Es->child->string); + outflags &= ~MD_spc; + return 1; +} + +static void +md_post_En(struct roff_node *n) +{ + if (n->norm->Es == NULL || + n->norm->Es->child == NULL || + n->norm->Es->child->next == NULL) + return; + + outflags &= ~MD_spc; + md_word(n->norm->Es->child->next->string); +} + +static int +md_pre_Eo(struct roff_node *n) +{ + if (n->end == ENDBODY_NOT && + n->parent->head->child == NULL && + n->child != NULL && + n->child->end != ENDBODY_NOT) + md_preword(); + else if (n->end != ENDBODY_NOT ? n->child != NULL : + n->parent->head->child != NULL && (n->child != NULL || + (n->parent->tail != NULL && n->parent->tail->child != NULL))) + outflags &= ~(MD_spc | MD_nl); + return 1; +} + +static void +md_post_Eo(struct roff_node *n) +{ + if (n->end != ENDBODY_NOT) { + outflags |= MD_spc; + return; + } + + if (n->child == NULL && n->parent->head->child == NULL) + return; + + if (n->parent->tail != NULL && n->parent->tail->child != NULL) + outflags &= ~MD_spc; + else + outflags |= MD_spc; +} + +static int +md_pre_Fa(struct roff_node *n) +{ + int am_Fa; + + am_Fa = n->tok == MDOC_Fa; + + if (am_Fa) + n = n->child; + + while (n != NULL) { + md_rawword("*"); + outflags &= ~MD_spc; + md_node(n); + outflags &= ~MD_spc; + md_rawword("*"); + if ((n = n->next) != NULL) + md_word(","); + } + return 0; +} + +static void +md_post_Fa(struct roff_node *n) +{ + if (n->next != NULL && n->next->tok == MDOC_Fa) + md_word(","); +} + +static int +md_pre_Fd(struct roff_node *n) +{ + md_pre_syn(n); + md_pre_raw(n); + return 1; +} + +static void +md_post_Fd(struct roff_node *n) +{ + md_post_raw(n); + outflags |= MD_br; +} + +static void +md_post_Fl(struct roff_node *n) +{ + md_post_raw(n); + if (n->child == NULL && n->next != NULL && + n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE)) + outflags &= ~MD_spc; +} + +static int +md_pre_Fn(struct roff_node *n) +{ + md_pre_syn(n); + + if ((n = n->child) == NULL) + return 0; + + md_rawword("**"); + outflags &= ~MD_spc; + md_node(n); + outflags &= ~MD_spc; + md_rawword("**"); + outflags &= ~MD_spc; + md_word("("); + + if ((n = n->next) != NULL) + md_pre_Fa(n); + return 0; +} + +static void +md_post_Fn(struct roff_node *n) +{ + md_word(")"); + if (n->flags & NODE_SYNPRETTY) { + md_word(";"); + outflags |= MD_sp; + } +} + +static int +md_pre_Fo(struct roff_node *n) +{ + switch (n->type) { + case ROFFT_BLOCK: + md_pre_syn(n); + break; + case ROFFT_HEAD: + if (n->child == NULL) + return 0; + md_pre_raw(n); + break; + case ROFFT_BODY: + outflags &= ~(MD_spc | MD_nl); + md_word("("); + break; + default: + break; + } + return 1; +} + +static void +md_post_Fo(struct roff_node *n) +{ + switch (n->type) { + case ROFFT_HEAD: + if (n->child != NULL) + md_post_raw(n); + break; + case ROFFT_BODY: + md_post_Fn(n); + break; + default: + break; + } +} + +static int +md_pre_In(struct roff_node *n) +{ + if (n->flags & NODE_SYNPRETTY) { + md_pre_syn(n); + md_rawword("**"); + outflags &= ~MD_spc; + md_word("#include <"); + } else { + md_word("<"); + outflags &= ~MD_spc; + md_rawword("*"); + } + outflags &= ~MD_spc; + return 1; +} + +static void +md_post_In(struct roff_node *n) +{ + if (n->flags & NODE_SYNPRETTY) { + outflags &= ~MD_spc; + md_rawword(">**"); + outflags |= MD_nl; + } else { + outflags &= ~MD_spc; + md_rawword("*>"); + } +} + +static int +md_pre_It(struct roff_node *n) +{ + struct roff_node *bln; + + switch (n->type) { + case ROFFT_BLOCK: + return 1; + + case ROFFT_HEAD: + bln = n->parent->parent; + if (bln->norm->Bl.comp == 0 && + bln->norm->Bl.type != LIST_column) + outflags |= MD_sp; + outflags |= MD_nl; + + switch (bln->norm->Bl.type) { + case LIST_item: + outflags |= MD_br; + return 0; + case LIST_inset: + case LIST_diag: + case LIST_ohang: + outflags |= MD_br; + return 1; + case LIST_tag: + case LIST_hang: + outflags |= MD_sp; + return 1; + case LIST_bullet: + md_rawword("*\t"); + break; + case LIST_dash: + case LIST_hyphen: + md_rawword("-\t"); + break; + case LIST_enum: + md_preword(); + if (bln->norm->Bl.count < 99) + bln->norm->Bl.count++; + printf("%d.\t", bln->norm->Bl.count); + escflags &= ~ESC_FON; + break; + case LIST_column: + outflags |= MD_br; + return 0; + default: + return 0; + } + outflags &= ~MD_spc; + outflags |= MD_nonl; + outcount = 0; + md_stack('\t'); + if (code_blocks || quote_blocks) + list_blocks++; + return 0; + + case ROFFT_BODY: + bln = n->parent->parent; + switch (bln->norm->Bl.type) { + case LIST_ohang: + outflags |= MD_br; + break; + case LIST_tag: + case LIST_hang: + md_pre_D1(n); + break; + default: + break; + } + return 1; + + default: + return 0; + } +} + +static void +md_post_It(struct roff_node *n) +{ + struct roff_node *bln; + int i, nc; + + if (n->type != ROFFT_BODY) + return; + + bln = n->parent->parent; + switch (bln->norm->Bl.type) { + case LIST_bullet: + case LIST_dash: + case LIST_hyphen: + case LIST_enum: + md_stack((char)-1); + if (code_blocks || quote_blocks) + list_blocks--; + break; + case LIST_tag: + case LIST_hang: + md_post_D1(n); + break; + + case LIST_column: + if (n->next == NULL) + break; + + /* Calculate the array index of the current column. */ + + i = 0; + while ((n = n->prev) != NULL && n->type != ROFFT_HEAD) + i++; + + /* + * If a width was specified for this column, + * subtract what printed, and + * add the same spacing as in mdoc_term.c. + */ + + nc = bln->norm->Bl.ncols; + i = i < nc ? strlen(bln->norm->Bl.cols[i]) - outcount + + (nc < 5 ? 4 : nc == 5 ? 3 : 1) : 1; + if (i < 1) + i = 1; + while (i-- > 0) + putchar(' '); + + outflags &= ~MD_spc; + escflags &= ~ESC_FON; + outcount = 0; + break; + + default: + break; + } +} + +static void +md_post_Lb(struct roff_node *n) +{ + if (n->sec == SEC_LIBRARY) + outflags |= MD_br; +} + +static void +md_uri(const char *s) +{ + while (*s != '\0') { + if (strchr("%()<>", *s) != NULL) { + printf("%%%2.2hhX", *s); + outcount += 3; + } else { + putchar(*s); + outcount++; + } + s++; + } +} + +static int +md_pre_Lk(struct roff_node *n) +{ + const struct roff_node *link, *descr, *punct; + + if ((link = n->child) == NULL) + return 0; + + /* Find beginning of trailing punctuation. */ + punct = n->last; + while (punct != link && punct->flags & NODE_DELIMC) + punct = punct->prev; + punct = punct->next; + + /* Link text. */ + descr = link->next; + if (descr == punct) + descr = link; /* no text */ + md_rawword("["); + outflags &= ~MD_spc; + do { + md_word(descr->string); + descr = descr->next; + } while (descr != punct); + outflags &= ~MD_spc; + + /* Link target. */ + md_rawword("]("); + md_uri(link->string); + outflags &= ~MD_spc; + md_rawword(")"); + + /* Trailing punctuation. */ + while (punct != NULL) { + md_word(punct->string); + punct = punct->next; + } + return 0; +} + +static int +md_pre_Mt(struct roff_node *n) +{ + const struct roff_node *nch; + + md_rawword("["); + outflags &= ~MD_spc; + for (nch = n->child; nch != NULL; nch = nch->next) + md_word(nch->string); + outflags &= ~MD_spc; + md_rawword("](mailto:"); + for (nch = n->child; nch != NULL; nch = nch->next) { + md_uri(nch->string); + if (nch->next != NULL) { + putchar(' '); + outcount++; + } + } + outflags &= ~MD_spc; + md_rawword(")"); + return 0; +} + +static int +md_pre_Nd(struct roff_node *n) +{ + outflags &= ~MD_nl; + outflags |= MD_spc; + md_word("-"); + return 1; +} + +static int +md_pre_Nm(struct roff_node *n) +{ + switch (n->type) { + case ROFFT_BLOCK: + outflags |= MD_Bk; + md_pre_syn(n); + break; + case ROFFT_HEAD: + case ROFFT_ELEM: + md_pre_raw(n); + break; + default: + break; + } + return 1; +} + +static void +md_post_Nm(struct roff_node *n) +{ + switch (n->type) { + case ROFFT_BLOCK: + outflags &= ~MD_Bk; + break; + case ROFFT_HEAD: + case ROFFT_ELEM: + md_post_raw(n); + break; + default: + break; + } +} + +static int +md_pre_No(struct roff_node *n) +{ + outflags |= MD_spc_force; + return 1; +} + +static int +md_pre_Ns(struct roff_node *n) +{ + outflags &= ~MD_spc; + return 0; +} + +static void +md_post_Pf(struct roff_node *n) +{ + if (n->next != NULL && (n->next->flags & NODE_LINE) == 0) + outflags &= ~MD_spc; +} + +static int +md_pre_Pp(struct roff_node *n) +{ + outflags |= MD_sp; + return 0; +} + +static int +md_pre_Rs(struct roff_node *n) +{ + if (n->sec == SEC_SEE_ALSO) + outflags |= MD_sp; + return 1; +} + +static int +md_pre_Sh(struct roff_node *n) +{ + switch (n->type) { + case ROFFT_BLOCK: + if (n->sec == SEC_AUTHORS) + outflags &= ~(MD_An_split | MD_An_nosplit); + break; + case ROFFT_HEAD: + outflags |= MD_sp; + md_rawword(n->tok == MDOC_Sh ? "#" : "##"); + break; + case ROFFT_BODY: + outflags |= MD_sp; + break; + default: + break; + } + return 1; +} + +static int +md_pre_Sm(struct roff_node *n) +{ + if (n->child == NULL) + outflags ^= MD_Sm; + else if (strcmp("on", n->child->string) == 0) + outflags |= MD_Sm; + else + outflags &= ~MD_Sm; + + if (outflags & MD_Sm) + outflags |= MD_spc; + + return 0; +} + +static int +md_pre_Vt(struct roff_node *n) +{ + switch (n->type) { + case ROFFT_BLOCK: + md_pre_syn(n); + return 1; + case ROFFT_BODY: + case ROFFT_ELEM: + md_pre_raw(n); + return 1; + default: + return 0; + } +} + +static void +md_post_Vt(struct roff_node *n) +{ + switch (n->type) { + case ROFFT_BODY: + case ROFFT_ELEM: + md_post_raw(n); + break; + default: + break; + } +} + +static int +md_pre_Xr(struct roff_node *n) +{ + n = n->child; + if (n == NULL) + return 0; + md_node(n); + n = n->next; + if (n == NULL) + return 0; + outflags &= ~MD_spc; + md_word("("); + md_node(n); + md_word(")"); + return 0; +} + +static int +md_pre__T(struct roff_node *n) +{ + if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) + md_word("\""); + else + md_rawword("*"); + outflags &= ~MD_spc; + return 1; +} + +static void +md_post__T(struct roff_node *n) +{ + outflags &= ~MD_spc; + if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) + md_word("\""); + else + md_rawword("*"); + md_post_pc(n); +} + +static int +md_pre_br(struct roff_node *n) +{ + outflags |= MD_br; + return 0; +} Property changes on: vendor/mandoc/20190723/mdoc_markdown.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mdoc_term.c =================================================================== --- vendor/mandoc/20190723/mdoc_term.c (nonexistent) +++ vendor/mandoc/20190723/mdoc_term.c (revision 350350) @@ -0,0 +1,2088 @@ +/* $Id: mdoc_term.c,v 1.374 2019/06/27 12:20:18 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2010, 2012-2019 Ingo Schwarze + * Copyright (c) 2013 Franco Fichtner + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "roff.h" +#include "mdoc.h" +#include "out.h" +#include "term.h" +#include "tag.h" +#include "main.h" + +struct termpair { + struct termpair *ppair; + int count; +}; + +#define DECL_ARGS struct termp *p, \ + struct termpair *pair, \ + const struct roff_meta *meta, \ + struct roff_node *n + +struct mdoc_term_act { + int (*pre)(DECL_ARGS); + void (*post)(DECL_ARGS); +}; + +static int a2width(const struct termp *, const char *); + +static void print_bvspace(struct termp *, + const struct roff_node *, + const struct roff_node *); +static void print_mdoc_node(DECL_ARGS); +static void print_mdoc_nodelist(DECL_ARGS); +static void print_mdoc_head(struct termp *, const struct roff_meta *); +static void print_mdoc_foot(struct termp *, const struct roff_meta *); +static void synopsis_pre(struct termp *, + const struct roff_node *); + +static void termp____post(DECL_ARGS); +static void termp__t_post(DECL_ARGS); +static void termp_bd_post(DECL_ARGS); +static void termp_bk_post(DECL_ARGS); +static void termp_bl_post(DECL_ARGS); +static void termp_eo_post(DECL_ARGS); +static void termp_fd_post(DECL_ARGS); +static void termp_fo_post(DECL_ARGS); +static void termp_in_post(DECL_ARGS); +static void termp_it_post(DECL_ARGS); +static void termp_lb_post(DECL_ARGS); +static void termp_nm_post(DECL_ARGS); +static void termp_pf_post(DECL_ARGS); +static void termp_quote_post(DECL_ARGS); +static void termp_sh_post(DECL_ARGS); +static void termp_ss_post(DECL_ARGS); +static void termp_xx_post(DECL_ARGS); + +static int termp__a_pre(DECL_ARGS); +static int termp__t_pre(DECL_ARGS); +static int termp_abort_pre(DECL_ARGS); +static int termp_an_pre(DECL_ARGS); +static int termp_ap_pre(DECL_ARGS); +static int termp_bd_pre(DECL_ARGS); +static int termp_bf_pre(DECL_ARGS); +static int termp_bk_pre(DECL_ARGS); +static int termp_bl_pre(DECL_ARGS); +static int termp_bold_pre(DECL_ARGS); +static int termp_cd_pre(DECL_ARGS); +static int termp_d1_pre(DECL_ARGS); +static int termp_eo_pre(DECL_ARGS); +static int termp_em_pre(DECL_ARGS); +static int termp_er_pre(DECL_ARGS); +static int termp_ex_pre(DECL_ARGS); +static int termp_fa_pre(DECL_ARGS); +static int termp_fd_pre(DECL_ARGS); +static int termp_fl_pre(DECL_ARGS); +static int termp_fn_pre(DECL_ARGS); +static int termp_fo_pre(DECL_ARGS); +static int termp_ft_pre(DECL_ARGS); +static int termp_in_pre(DECL_ARGS); +static int termp_it_pre(DECL_ARGS); +static int termp_li_pre(DECL_ARGS); +static int termp_lk_pre(DECL_ARGS); +static int termp_nd_pre(DECL_ARGS); +static int termp_nm_pre(DECL_ARGS); +static int termp_ns_pre(DECL_ARGS); +static int termp_quote_pre(DECL_ARGS); +static int termp_rs_pre(DECL_ARGS); +static int termp_sh_pre(DECL_ARGS); +static int termp_skip_pre(DECL_ARGS); +static int termp_sm_pre(DECL_ARGS); +static int termp_pp_pre(DECL_ARGS); +static int termp_ss_pre(DECL_ARGS); +static int termp_sy_pre(DECL_ARGS); +static int termp_tag_pre(DECL_ARGS); +static int termp_under_pre(DECL_ARGS); +static int termp_vt_pre(DECL_ARGS); +static int termp_xr_pre(DECL_ARGS); +static int termp_xx_pre(DECL_ARGS); + +static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = { + { NULL, NULL }, /* Dd */ + { NULL, NULL }, /* Dt */ + { NULL, NULL }, /* Os */ + { termp_sh_pre, termp_sh_post }, /* Sh */ + { termp_ss_pre, termp_ss_post }, /* Ss */ + { termp_pp_pre, NULL }, /* Pp */ + { termp_d1_pre, termp_bl_post }, /* D1 */ + { termp_d1_pre, termp_bl_post }, /* Dl */ + { termp_bd_pre, termp_bd_post }, /* Bd */ + { NULL, NULL }, /* Ed */ + { termp_bl_pre, termp_bl_post }, /* Bl */ + { NULL, NULL }, /* El */ + { termp_it_pre, termp_it_post }, /* It */ + { termp_under_pre, NULL }, /* Ad */ + { termp_an_pre, NULL }, /* An */ + { termp_ap_pre, NULL }, /* Ap */ + { termp_under_pre, NULL }, /* Ar */ + { termp_cd_pre, NULL }, /* Cd */ + { termp_bold_pre, NULL }, /* Cm */ + { termp_li_pre, NULL }, /* Dv */ + { termp_er_pre, NULL }, /* Er */ + { termp_tag_pre, NULL }, /* Ev */ + { termp_ex_pre, NULL }, /* Ex */ + { termp_fa_pre, NULL }, /* Fa */ + { termp_fd_pre, termp_fd_post }, /* Fd */ + { termp_fl_pre, NULL }, /* Fl */ + { termp_fn_pre, NULL }, /* Fn */ + { termp_ft_pre, NULL }, /* Ft */ + { termp_bold_pre, NULL }, /* Ic */ + { termp_in_pre, termp_in_post }, /* In */ + { termp_li_pre, NULL }, /* Li */ + { termp_nd_pre, NULL }, /* Nd */ + { termp_nm_pre, termp_nm_post }, /* Nm */ + { termp_quote_pre, termp_quote_post }, /* Op */ + { termp_abort_pre, NULL }, /* Ot */ + { termp_under_pre, NULL }, /* Pa */ + { termp_ex_pre, NULL }, /* Rv */ + { NULL, NULL }, /* St */ + { termp_under_pre, NULL }, /* Va */ + { termp_vt_pre, NULL }, /* Vt */ + { termp_xr_pre, NULL }, /* Xr */ + { termp__a_pre, termp____post }, /* %A */ + { termp_under_pre, termp____post }, /* %B */ + { NULL, termp____post }, /* %D */ + { termp_under_pre, termp____post }, /* %I */ + { termp_under_pre, termp____post }, /* %J */ + { NULL, termp____post }, /* %N */ + { NULL, termp____post }, /* %O */ + { NULL, termp____post }, /* %P */ + { NULL, termp____post }, /* %R */ + { termp__t_pre, termp__t_post }, /* %T */ + { NULL, termp____post }, /* %V */ + { NULL, NULL }, /* Ac */ + { termp_quote_pre, termp_quote_post }, /* Ao */ + { termp_quote_pre, termp_quote_post }, /* Aq */ + { NULL, NULL }, /* At */ + { NULL, NULL }, /* Bc */ + { termp_bf_pre, NULL }, /* Bf */ + { termp_quote_pre, termp_quote_post }, /* Bo */ + { termp_quote_pre, termp_quote_post }, /* Bq */ + { termp_xx_pre, termp_xx_post }, /* Bsx */ + { NULL, NULL }, /* Bx */ + { termp_skip_pre, NULL }, /* Db */ + { NULL, NULL }, /* Dc */ + { termp_quote_pre, termp_quote_post }, /* Do */ + { termp_quote_pre, termp_quote_post }, /* Dq */ + { NULL, NULL }, /* Ec */ /* FIXME: no space */ + { NULL, NULL }, /* Ef */ + { termp_em_pre, NULL }, /* Em */ + { termp_eo_pre, termp_eo_post }, /* Eo */ + { termp_xx_pre, termp_xx_post }, /* Fx */ + { termp_bold_pre, NULL }, /* Ms */ + { termp_li_pre, NULL }, /* No */ + { termp_ns_pre, NULL }, /* Ns */ + { termp_xx_pre, termp_xx_post }, /* Nx */ + { termp_xx_pre, termp_xx_post }, /* Ox */ + { NULL, NULL }, /* Pc */ + { NULL, termp_pf_post }, /* Pf */ + { termp_quote_pre, termp_quote_post }, /* Po */ + { termp_quote_pre, termp_quote_post }, /* Pq */ + { NULL, NULL }, /* Qc */ + { termp_quote_pre, termp_quote_post }, /* Ql */ + { termp_quote_pre, termp_quote_post }, /* Qo */ + { termp_quote_pre, termp_quote_post }, /* Qq */ + { NULL, NULL }, /* Re */ + { termp_rs_pre, NULL }, /* Rs */ + { NULL, NULL }, /* Sc */ + { termp_quote_pre, termp_quote_post }, /* So */ + { termp_quote_pre, termp_quote_post }, /* Sq */ + { termp_sm_pre, NULL }, /* Sm */ + { termp_under_pre, NULL }, /* Sx */ + { termp_sy_pre, NULL }, /* Sy */ + { NULL, NULL }, /* Tn */ + { termp_xx_pre, termp_xx_post }, /* Ux */ + { NULL, NULL }, /* Xc */ + { NULL, NULL }, /* Xo */ + { termp_fo_pre, termp_fo_post }, /* Fo */ + { NULL, NULL }, /* Fc */ + { termp_quote_pre, termp_quote_post }, /* Oo */ + { NULL, NULL }, /* Oc */ + { termp_bk_pre, termp_bk_post }, /* Bk */ + { NULL, NULL }, /* Ek */ + { NULL, NULL }, /* Bt */ + { NULL, NULL }, /* Hf */ + { termp_under_pre, NULL }, /* Fr */ + { NULL, NULL }, /* Ud */ + { NULL, termp_lb_post }, /* Lb */ + { termp_abort_pre, NULL }, /* Lp */ + { termp_lk_pre, NULL }, /* Lk */ + { termp_under_pre, NULL }, /* Mt */ + { termp_quote_pre, termp_quote_post }, /* Brq */ + { termp_quote_pre, termp_quote_post }, /* Bro */ + { NULL, NULL }, /* Brc */ + { NULL, termp____post }, /* %C */ + { termp_skip_pre, NULL }, /* Es */ + { termp_quote_pre, termp_quote_post }, /* En */ + { termp_xx_pre, termp_xx_post }, /* Dx */ + { NULL, termp____post }, /* %Q */ + { NULL, termp____post }, /* %U */ + { NULL, NULL }, /* Ta */ +}; + +static int fn_prio; + + +void +terminal_mdoc(void *arg, const struct roff_meta *mdoc) +{ + struct roff_node *n, *nn; + struct termp *p; + size_t save_defindent; + + p = (struct termp *)arg; + p->tcol->rmargin = p->maxrmargin = p->defrmargin; + term_tab_set(p, NULL); + term_tab_set(p, "T"); + term_tab_set(p, ".5i"); + + n = mdoc->first->child; + if (p->synopsisonly) { + for (nn = NULL; n != NULL; n = n->next) { + if (n->tok != MDOC_Sh) + continue; + if (n->sec == SEC_SYNOPSIS) + break; + if (nn == NULL && n->sec == SEC_NAME) + nn = n; + } + if (n == NULL) + n = nn; + p->flags |= TERMP_NOSPACE; + if (n != NULL && (n = n->child->next->child) != NULL) + print_mdoc_nodelist(p, NULL, mdoc, n); + term_newln(p); + } else { + save_defindent = p->defindent; + if (p->defindent == 0) + p->defindent = 5; + term_begin(p, print_mdoc_head, print_mdoc_foot, mdoc); + while (n != NULL && + (n->type == ROFFT_COMMENT || + n->flags & NODE_NOPRT)) + n = n->next; + if (n != NULL) { + if (n->tok != MDOC_Sh) + term_vspace(p); + print_mdoc_nodelist(p, NULL, mdoc, n); + } + term_end(p); + p->defindent = save_defindent; + } +} + +static void +print_mdoc_nodelist(DECL_ARGS) +{ + + while (n != NULL) { + print_mdoc_node(p, pair, meta, n); + n = n->next; + } +} + +static void +print_mdoc_node(DECL_ARGS) +{ + const struct mdoc_term_act *act; + struct termpair npair; + size_t offset, rmargin; + int chld; + + /* + * In no-fill mode, break the output line at the beginning + * of new input lines except after \c, and nowhere else. + */ + + if (n->flags & NODE_NOFILL) { + if (n->flags & NODE_LINE && + (p->flags & TERMP_NONEWLINE) == 0) + term_newln(p); + p->flags |= TERMP_BRNEVER; + } else + p->flags &= ~TERMP_BRNEVER; + + if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) + return; + + chld = 1; + offset = p->tcol->offset; + rmargin = p->tcol->rmargin; + n->flags &= ~NODE_ENDED; + n->prev_font = p->fonti; + + memset(&npair, 0, sizeof(struct termpair)); + npair.ppair = pair; + + /* + * Keeps only work until the end of a line. If a keep was + * invoked in a prior line, revert it to PREKEEP. + */ + + if (p->flags & TERMP_KEEP && n->flags & NODE_LINE) { + p->flags &= ~TERMP_KEEP; + p->flags |= TERMP_PREKEEP; + } + + /* + * After the keep flags have been set up, we may now + * produce output. Note that some pre-handlers do so. + */ + + act = NULL; + switch (n->type) { + case ROFFT_TEXT: + if (n->flags & NODE_LINE) { + switch (*n->string) { + case '\0': + if (p->flags & TERMP_NONEWLINE) + term_newln(p); + else + term_vspace(p); + return; + case ' ': + if ((p->flags & TERMP_NONEWLINE) == 0) + term_newln(p); + break; + default: + break; + } + } + if (NODE_DELIMC & n->flags) + p->flags |= TERMP_NOSPACE; + term_word(p, n->string); + if (NODE_DELIMO & n->flags) + p->flags |= TERMP_NOSPACE; + break; + case ROFFT_EQN: + if ( ! (n->flags & NODE_LINE)) + p->flags |= TERMP_NOSPACE; + term_eqn(p, n->eqn); + if (n->next != NULL && ! (n->next->flags & NODE_LINE)) + p->flags |= TERMP_NOSPACE; + break; + case ROFFT_TBL: + if (p->tbl.cols == NULL) + term_newln(p); + term_tbl(p, n->span); + break; + default: + if (n->tok < ROFF_MAX) { + roff_term_pre(p, n); + return; + } + assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); + act = mdoc_term_acts + (n->tok - MDOC_Dd); + if (act->pre != NULL && + (n->end == ENDBODY_NOT || n->child != NULL)) + chld = (*act->pre)(p, &npair, meta, n); + break; + } + + if (chld && n->child) + print_mdoc_nodelist(p, &npair, meta, n->child); + + term_fontpopq(p, + (ENDBODY_NOT == n->end ? n : n->body)->prev_font); + + switch (n->type) { + case ROFFT_TEXT: + break; + case ROFFT_TBL: + break; + case ROFFT_EQN: + break; + default: + if (act->post == NULL || n->flags & NODE_ENDED) + break; + (void)(*act->post)(p, &npair, meta, n); + + /* + * Explicit end tokens not only call the post + * handler, but also tell the respective block + * that it must not call the post handler again. + */ + if (ENDBODY_NOT != n->end) + n->body->flags |= NODE_ENDED; + break; + } + + if (NODE_EOS & n->flags) + p->flags |= TERMP_SENTENCE; + + if (n->type != ROFFT_TEXT) + p->tcol->offset = offset; + p->tcol->rmargin = rmargin; +} + +static void +print_mdoc_foot(struct termp *p, const struct roff_meta *meta) +{ + size_t sz; + + term_fontrepl(p, TERMFONT_NONE); + + /* + * Output the footer in new-groff style, that is, three columns + * with the middle being the manual date and flanking columns + * being the operating system: + * + * SYSTEM DATE SYSTEM + */ + + term_vspace(p); + + p->tcol->offset = 0; + sz = term_strlen(p, meta->date); + p->tcol->rmargin = p->maxrmargin > sz ? + (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0; + p->trailspace = 1; + p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; + + term_word(p, meta->os); + term_flushln(p); + + p->tcol->offset = p->tcol->rmargin; + sz = term_strlen(p, meta->os); + p->tcol->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0; + p->flags |= TERMP_NOSPACE; + + term_word(p, meta->date); + term_flushln(p); + + p->tcol->offset = p->tcol->rmargin; + p->tcol->rmargin = p->maxrmargin; + p->trailspace = 0; + p->flags &= ~TERMP_NOBREAK; + p->flags |= TERMP_NOSPACE; + + term_word(p, meta->os); + term_flushln(p); + + p->tcol->offset = 0; + p->tcol->rmargin = p->maxrmargin; + p->flags = 0; +} + +static void +print_mdoc_head(struct termp *p, const struct roff_meta *meta) +{ + char *volume, *title; + size_t vollen, titlen; + + /* + * The header is strange. It has three components, which are + * really two with the first duplicated. It goes like this: + * + * IDENTIFIER TITLE IDENTIFIER + * + * The IDENTIFIER is NAME(SECTION), which is the command-name + * (if given, or "unknown" if not) followed by the manual page + * section. These are given in `Dt'. The TITLE is a free-form + * string depending on the manual volume. If not specified, it + * switches on the manual section. + */ + + assert(meta->vol); + if (NULL == meta->arch) + volume = mandoc_strdup(meta->vol); + else + mandoc_asprintf(&volume, "%s (%s)", + meta->vol, meta->arch); + vollen = term_strlen(p, volume); + + if (NULL == meta->msec) + title = mandoc_strdup(meta->title); + else + mandoc_asprintf(&title, "%s(%s)", + meta->title, meta->msec); + titlen = term_strlen(p, title); + + p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; + p->trailspace = 1; + p->tcol->offset = 0; + p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? + (p->maxrmargin - vollen + term_len(p, 1)) / 2 : + vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; + + term_word(p, title); + term_flushln(p); + + p->flags |= TERMP_NOSPACE; + p->tcol->offset = p->tcol->rmargin; + p->tcol->rmargin = p->tcol->offset + vollen + titlen < + p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin; + + term_word(p, volume); + term_flushln(p); + + p->flags &= ~TERMP_NOBREAK; + p->trailspace = 0; + if (p->tcol->rmargin + titlen <= p->maxrmargin) { + p->flags |= TERMP_NOSPACE; + p->tcol->offset = p->tcol->rmargin; + p->tcol->rmargin = p->maxrmargin; + term_word(p, title); + term_flushln(p); + } + + p->flags &= ~TERMP_NOSPACE; + p->tcol->offset = 0; + p->tcol->rmargin = p->maxrmargin; + free(title); + free(volume); +} + +static int +a2width(const struct termp *p, const char *v) +{ + struct roffsu su; + const char *end; + + end = a2roffsu(v, &su, SCALE_MAX); + if (end == NULL || *end != '\0') { + SCALE_HS_INIT(&su, term_strlen(p, v)); + su.scale /= term_strlen(p, "0"); + } + return term_hen(p, &su); +} + +/* + * Determine how much space to print out before block elements of `It' + * (and thus `Bl') and `Bd'. And then go ahead and print that space, + * too. + */ +static void +print_bvspace(struct termp *p, + const struct roff_node *bl, + const struct roff_node *n) +{ + const struct roff_node *nn; + + assert(n); + + term_newln(p); + + if (MDOC_Bd == bl->tok && bl->norm->Bd.comp) + return; + if (MDOC_Bl == bl->tok && bl->norm->Bl.comp) + return; + + /* Do not vspace directly after Ss/Sh. */ + + nn = n; + while (nn->prev != NULL && + (nn->prev->type == ROFFT_COMMENT || + nn->prev->flags & NODE_NOPRT)) + nn = nn->prev; + while (nn->prev == NULL) { + do { + nn = nn->parent; + if (nn->type == ROFFT_ROOT) + return; + } while (nn->type != ROFFT_BLOCK); + if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss) + return; + if (nn->tok == MDOC_It && + nn->parent->parent->norm->Bl.type != LIST_item) + break; + } + + /* A `-column' does not assert vspace within the list. */ + + if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type) + if (n->prev && MDOC_It == n->prev->tok) + return; + + /* A `-diag' without body does not vspace. */ + + if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type) + if (n->prev && MDOC_It == n->prev->tok) { + assert(n->prev->body); + if (NULL == n->prev->body->child) + return; + } + + term_vspace(p); +} + + +static int +termp_it_pre(DECL_ARGS) +{ + struct roffsu su; + char buf[24]; + const struct roff_node *bl, *nn; + size_t ncols, dcol; + int i, offset, width; + enum mdoc_list type; + + if (n->type == ROFFT_BLOCK) { + print_bvspace(p, n->parent->parent, n); + return 1; + } + + bl = n->parent->parent->parent; + type = bl->norm->Bl.type; + + /* + * Defaults for specific list types. + */ + + switch (type) { + case LIST_bullet: + case LIST_dash: + case LIST_hyphen: + case LIST_enum: + width = term_len(p, 2); + break; + case LIST_hang: + case LIST_tag: + width = term_len(p, 8); + break; + case LIST_column: + width = term_len(p, 10); + break; + default: + width = 0; + break; + } + offset = 0; + + /* + * First calculate width and offset. This is pretty easy unless + * we're a -column list, in which case all prior columns must + * be accounted for. + */ + + if (bl->norm->Bl.offs != NULL) { + offset = a2width(p, bl->norm->Bl.offs); + if (offset < 0 && (size_t)(-offset) > p->tcol->offset) + offset = -p->tcol->offset; + else if (offset > SHRT_MAX) + offset = 0; + } + + switch (type) { + case LIST_column: + if (n->type == ROFFT_HEAD) + break; + + /* + * Imitate groff's column handling: + * - For each earlier column, add its width. + * - For less than 5 columns, add four more blanks per + * column. + * - For exactly 5 columns, add three more blank per + * column. + * - For more than 5 columns, add only one column. + */ + ncols = bl->norm->Bl.ncols; + dcol = ncols < 5 ? term_len(p, 4) : + ncols == 5 ? term_len(p, 3) : term_len(p, 1); + + /* + * Calculate the offset by applying all prior ROFFT_BODY, + * so we stop at the ROFFT_HEAD (nn->prev == NULL). + */ + + for (i = 0, nn = n->prev; + nn->prev && i < (int)ncols; + nn = nn->prev, i++) { + SCALE_HS_INIT(&su, + term_strlen(p, bl->norm->Bl.cols[i])); + su.scale /= term_strlen(p, "0"); + offset += term_hen(p, &su) + dcol; + } + + /* + * When exceeding the declared number of columns, leave + * the remaining widths at 0. This will later be + * adjusted to the default width of 10, or, for the last + * column, stretched to the right margin. + */ + if (i >= (int)ncols) + break; + + /* + * Use the declared column widths, extended as explained + * in the preceding paragraph. + */ + SCALE_HS_INIT(&su, term_strlen(p, bl->norm->Bl.cols[i])); + su.scale /= term_strlen(p, "0"); + width = term_hen(p, &su) + dcol; + break; + default: + if (NULL == bl->norm->Bl.width) + break; + + /* + * Note: buffer the width by 2, which is groff's magic + * number for buffering single arguments. See the above + * handling for column for how this changes. + */ + width = a2width(p, bl->norm->Bl.width) + term_len(p, 2); + if (width < 0 && (size_t)(-width) > p->tcol->offset) + width = -p->tcol->offset; + else if (width > SHRT_MAX) + width = 0; + break; + } + + /* + * Whitespace control. Inset bodies need an initial space, + * while diagonal bodies need two. + */ + + p->flags |= TERMP_NOSPACE; + + switch (type) { + case LIST_diag: + if (n->type == ROFFT_BODY) + term_word(p, "\\ \\ "); + break; + case LIST_inset: + if (n->type == ROFFT_BODY && n->parent->head->child != NULL) + term_word(p, "\\ "); + break; + default: + break; + } + + p->flags |= TERMP_NOSPACE; + + switch (type) { + case LIST_diag: + if (n->type == ROFFT_HEAD) + term_fontpush(p, TERMFONT_BOLD); + break; + default: + break; + } + + /* + * Pad and break control. This is the tricky part. These flags + * are documented in term_flushln() in term.c. Note that we're + * going to unset all of these flags in termp_it_post() when we + * exit. + */ + + switch (type) { + case LIST_enum: + case LIST_bullet: + case LIST_dash: + case LIST_hyphen: + if (n->type == ROFFT_HEAD) { + p->flags |= TERMP_NOBREAK | TERMP_HANG; + p->trailspace = 1; + } else if (width <= (int)term_len(p, 2)) + p->flags |= TERMP_NOPAD; + break; + case LIST_hang: + if (n->type != ROFFT_HEAD) + break; + p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG; + p->trailspace = 1; + break; + case LIST_tag: + if (n->type != ROFFT_HEAD) + break; + + p->flags |= TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND; + p->trailspace = 2; + + if (NULL == n->next || NULL == n->next->child) + p->flags |= TERMP_HANG; + break; + case LIST_column: + if (n->type == ROFFT_HEAD) + break; + + if (NULL == n->next) { + p->flags &= ~TERMP_NOBREAK; + p->trailspace = 0; + } else { + p->flags |= TERMP_NOBREAK; + p->trailspace = 1; + } + + break; + case LIST_diag: + if (n->type != ROFFT_HEAD) + break; + p->flags |= TERMP_NOBREAK | TERMP_BRIND; + p->trailspace = 1; + break; + default: + break; + } + + /* + * Margin control. Set-head-width lists have their right + * margins shortened. The body for these lists has the offset + * necessarily lengthened. Everybody gets the offset. + */ + + p->tcol->offset += offset; + + switch (type) { + case LIST_bullet: + case LIST_dash: + case LIST_enum: + case LIST_hyphen: + case LIST_hang: + case LIST_tag: + if (n->type == ROFFT_HEAD) + p->tcol->rmargin = p->tcol->offset + width; + else + p->tcol->offset += width; + break; + case LIST_column: + assert(width); + p->tcol->rmargin = p->tcol->offset + width; + /* + * XXX - this behaviour is not documented: the + * right-most column is filled to the right margin. + */ + if (n->type == ROFFT_HEAD) + break; + if (n->next == NULL && p->tcol->rmargin < p->maxrmargin) + p->tcol->rmargin = p->maxrmargin; + break; + default: + break; + } + + /* + * The dash, hyphen, bullet and enum lists all have a special + * HEAD character (temporarily bold, in some cases). + */ + + if (n->type == ROFFT_HEAD) + switch (type) { + case LIST_bullet: + term_fontpush(p, TERMFONT_BOLD); + term_word(p, "\\[bu]"); + term_fontpop(p); + break; + case LIST_dash: + case LIST_hyphen: + term_fontpush(p, TERMFONT_BOLD); + term_word(p, "-"); + term_fontpop(p); + break; + case LIST_enum: + (pair->ppair->ppair->count)++; + (void)snprintf(buf, sizeof(buf), "%d.", + pair->ppair->ppair->count); + term_word(p, buf); + break; + default: + break; + } + + /* + * If we're not going to process our children, indicate so here. + */ + + switch (type) { + case LIST_bullet: + case LIST_item: + case LIST_dash: + case LIST_hyphen: + case LIST_enum: + if (n->type == ROFFT_HEAD) + return 0; + break; + case LIST_column: + if (n->type == ROFFT_HEAD) + return 0; + p->minbl = 0; + break; + default: + break; + } + + return 1; +} + +static void +termp_it_post(DECL_ARGS) +{ + enum mdoc_list type; + + if (n->type == ROFFT_BLOCK) + return; + + type = n->parent->parent->parent->norm->Bl.type; + + switch (type) { + case LIST_item: + case LIST_diag: + case LIST_inset: + if (n->type == ROFFT_BODY) + term_newln(p); + break; + case LIST_column: + if (n->type == ROFFT_BODY) + term_flushln(p); + break; + default: + term_newln(p); + break; + } + + /* + * Now that our output is flushed, we can reset our tags. Since + * only `It' sets these flags, we're free to assume that nobody + * has munged them in the meanwhile. + */ + + p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND | TERMP_HANG); + p->trailspace = 0; +} + +static int +termp_nm_pre(DECL_ARGS) +{ + const char *cp; + + if (n->type == ROFFT_BLOCK) { + p->flags |= TERMP_PREKEEP; + return 1; + } + + if (n->type == ROFFT_BODY) { + if (n->child == NULL) + return 0; + p->flags |= TERMP_NOSPACE; + cp = NULL; + if (n->prev->child != NULL) + cp = n->prev->child->string; + if (cp == NULL) + cp = meta->name; + if (cp == NULL) + p->tcol->offset += term_len(p, 6); + else + p->tcol->offset += term_len(p, 1) + + term_strlen(p, cp); + return 1; + } + + if (n->child == NULL) + return 0; + + if (n->type == ROFFT_HEAD) + synopsis_pre(p, n->parent); + + if (n->type == ROFFT_HEAD && + n->next != NULL && n->next->child != NULL) { + p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND; + p->trailspace = 1; + p->tcol->rmargin = p->tcol->offset + term_len(p, 1); + if (n->child == NULL) + p->tcol->rmargin += term_strlen(p, meta->name); + else if (n->child->type == ROFFT_TEXT) { + p->tcol->rmargin += term_strlen(p, n->child->string); + if (n->child->next != NULL) + p->flags |= TERMP_HANG; + } else { + p->tcol->rmargin += term_len(p, 5); + p->flags |= TERMP_HANG; + } + } + + term_fontpush(p, TERMFONT_BOLD); + return 1; +} + +static void +termp_nm_post(DECL_ARGS) +{ + + if (n->type == ROFFT_BLOCK) { + p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); + } else if (n->type == ROFFT_HEAD && + NULL != n->next && NULL != n->next->child) { + term_flushln(p); + p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG); + p->trailspace = 0; + } else if (n->type == ROFFT_BODY && n->child != NULL) + term_flushln(p); +} + +static int +termp_fl_pre(DECL_ARGS) +{ + + termp_tag_pre(p, pair, meta, n); + term_fontpush(p, TERMFONT_BOLD); + term_word(p, "\\-"); + + if (!(n->child == NULL && + (n->next == NULL || + n->next->type == ROFFT_TEXT || + n->next->flags & NODE_LINE))) + p->flags |= TERMP_NOSPACE; + + return 1; +} + +static int +termp__a_pre(DECL_ARGS) +{ + + if (n->prev && MDOC__A == n->prev->tok) + if (NULL == n->next || MDOC__A != n->next->tok) + term_word(p, "and"); + + return 1; +} + +static int +termp_an_pre(DECL_ARGS) +{ + + if (n->norm->An.auth == AUTH_split) { + p->flags &= ~TERMP_NOSPLIT; + p->flags |= TERMP_SPLIT; + return 0; + } + if (n->norm->An.auth == AUTH_nosplit) { + p->flags &= ~TERMP_SPLIT; + p->flags |= TERMP_NOSPLIT; + return 0; + } + + if (p->flags & TERMP_SPLIT) + term_newln(p); + + if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT)) + p->flags |= TERMP_SPLIT; + + return 1; +} + +static int +termp_ns_pre(DECL_ARGS) +{ + + if ( ! (NODE_LINE & n->flags)) + p->flags |= TERMP_NOSPACE; + return 1; +} + +static int +termp_rs_pre(DECL_ARGS) +{ + + if (SEC_SEE_ALSO != n->sec) + return 1; + if (n->type == ROFFT_BLOCK && n->prev != NULL) + term_vspace(p); + return 1; +} + +static int +termp_ex_pre(DECL_ARGS) +{ + term_newln(p); + return 1; +} + +static int +termp_nd_pre(DECL_ARGS) +{ + + if (n->type == ROFFT_BODY) + term_word(p, "\\(en"); + return 1; +} + +static int +termp_bl_pre(DECL_ARGS) +{ + + return n->type != ROFFT_HEAD; +} + +static void +termp_bl_post(DECL_ARGS) +{ + + if (n->type != ROFFT_BLOCK) + return; + term_newln(p); + if (n->tok != MDOC_Bl || n->norm->Bl.type != LIST_column) + return; + term_tab_set(p, NULL); + term_tab_set(p, "T"); + term_tab_set(p, ".5i"); +} + +static int +termp_xr_pre(DECL_ARGS) +{ + + if (NULL == (n = n->child)) + return 0; + + assert(n->type == ROFFT_TEXT); + term_word(p, n->string); + + if (NULL == (n = n->next)) + return 0; + + p->flags |= TERMP_NOSPACE; + term_word(p, "("); + p->flags |= TERMP_NOSPACE; + + assert(n->type == ROFFT_TEXT); + term_word(p, n->string); + + p->flags |= TERMP_NOSPACE; + term_word(p, ")"); + + return 0; +} + +/* + * This decides how to assert whitespace before any of the SYNOPSIS set + * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain + * macro combos). + */ +static void +synopsis_pre(struct termp *p, const struct roff_node *n) +{ + /* + * Obviously, if we're not in a SYNOPSIS or no prior macros + * exist, do nothing. + */ + if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags)) + return; + + /* + * If we're the second in a pair of like elements, emit our + * newline and return. UNLESS we're `Fo', `Fn', `Fn', in which + * case we soldier on. + */ + if (n->prev->tok == n->tok && + MDOC_Ft != n->tok && + MDOC_Fo != n->tok && + MDOC_Fn != n->tok) { + term_newln(p); + return; + } + + /* + * If we're one of the SYNOPSIS set and non-like pair-wise after + * another (or Fn/Fo, which we've let slip through) then assert + * vertical space, else only newline and move on. + */ + switch (n->prev->tok) { + case MDOC_Fd: + case MDOC_Fn: + case MDOC_Fo: + case MDOC_In: + case MDOC_Vt: + term_vspace(p); + break; + case MDOC_Ft: + if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) { + term_vspace(p); + break; + } + /* FALLTHROUGH */ + default: + term_newln(p); + break; + } +} + +static int +termp_vt_pre(DECL_ARGS) +{ + + if (n->type == ROFFT_ELEM) { + synopsis_pre(p, n); + return termp_under_pre(p, pair, meta, n); + } else if (n->type == ROFFT_BLOCK) { + synopsis_pre(p, n); + return 1; + } else if (n->type == ROFFT_HEAD) + return 0; + + return termp_under_pre(p, pair, meta, n); +} + +static int +termp_bold_pre(DECL_ARGS) +{ + + termp_tag_pre(p, pair, meta, n); + term_fontpush(p, TERMFONT_BOLD); + return 1; +} + +static int +termp_fd_pre(DECL_ARGS) +{ + + synopsis_pre(p, n); + return termp_bold_pre(p, pair, meta, n); +} + +static void +termp_fd_post(DECL_ARGS) +{ + + term_newln(p); +} + +static int +termp_sh_pre(DECL_ARGS) +{ + + switch (n->type) { + case ROFFT_BLOCK: + /* + * Vertical space before sections, except + * when the previous section was empty. + */ + if (n->prev == NULL || + n->prev->tok != MDOC_Sh || + (n->prev->body != NULL && + n->prev->body->child != NULL)) + term_vspace(p); + break; + case ROFFT_HEAD: + term_fontpush(p, TERMFONT_BOLD); + break; + case ROFFT_BODY: + p->tcol->offset = term_len(p, p->defindent); + term_tab_set(p, NULL); + term_tab_set(p, "T"); + term_tab_set(p, ".5i"); + switch (n->sec) { + case SEC_DESCRIPTION: + fn_prio = 0; + break; + case SEC_AUTHORS: + p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT); + break; + default: + break; + } + break; + default: + break; + } + return 1; +} + +static void +termp_sh_post(DECL_ARGS) +{ + + switch (n->type) { + case ROFFT_HEAD: + term_newln(p); + break; + case ROFFT_BODY: + term_newln(p); + p->tcol->offset = 0; + break; + default: + break; + } +} + +static void +termp_lb_post(DECL_ARGS) +{ + + if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags) + term_newln(p); +} + +static int +termp_d1_pre(DECL_ARGS) +{ + + if (n->type != ROFFT_BLOCK) + return 1; + term_newln(p); + p->tcol->offset += term_len(p, p->defindent + 1); + term_tab_set(p, NULL); + term_tab_set(p, "T"); + term_tab_set(p, ".5i"); + return 1; +} + +static int +termp_ft_pre(DECL_ARGS) +{ + + /* NB: NODE_LINE does not effect this! */ + synopsis_pre(p, n); + term_fontpush(p, TERMFONT_UNDER); + return 1; +} + +static int +termp_fn_pre(DECL_ARGS) +{ + size_t rmargin = 0; + int pretty; + + pretty = NODE_SYNPRETTY & n->flags; + + synopsis_pre(p, n); + + if (NULL == (n = n->child)) + return 0; + + if (pretty) { + rmargin = p->tcol->rmargin; + p->tcol->rmargin = p->tcol->offset + term_len(p, 4); + p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG; + } + + assert(n->type == ROFFT_TEXT); + term_fontpush(p, TERMFONT_BOLD); + term_word(p, n->string); + term_fontpop(p); + + if (n->sec == SEC_DESCRIPTION || n->sec == SEC_CUSTOM) + tag_put(n->string, ++fn_prio, p->line); + + if (pretty) { + term_flushln(p); + p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG); + p->flags |= TERMP_NOPAD; + p->tcol->offset = p->tcol->rmargin; + p->tcol->rmargin = rmargin; + } + + p->flags |= TERMP_NOSPACE; + term_word(p, "("); + p->flags |= TERMP_NOSPACE; + + for (n = n->next; n; n = n->next) { + assert(n->type == ROFFT_TEXT); + term_fontpush(p, TERMFONT_UNDER); + if (pretty) + p->flags |= TERMP_NBRWORD; + term_word(p, n->string); + term_fontpop(p); + + if (n->next) { + p->flags |= TERMP_NOSPACE; + term_word(p, ","); + } + } + + p->flags |= TERMP_NOSPACE; + term_word(p, ")"); + + if (pretty) { + p->flags |= TERMP_NOSPACE; + term_word(p, ";"); + term_flushln(p); + } + + return 0; +} + +static int +termp_fa_pre(DECL_ARGS) +{ + const struct roff_node *nn; + + if (n->parent->tok != MDOC_Fo) { + term_fontpush(p, TERMFONT_UNDER); + return 1; + } + + for (nn = n->child; nn; nn = nn->next) { + term_fontpush(p, TERMFONT_UNDER); + p->flags |= TERMP_NBRWORD; + term_word(p, nn->string); + term_fontpop(p); + + if (nn->next || (n->next && n->next->tok == MDOC_Fa)) { + p->flags |= TERMP_NOSPACE; + term_word(p, ","); + } + } + + return 0; +} + +static int +termp_bd_pre(DECL_ARGS) +{ + int offset; + + if (n->type == ROFFT_BLOCK) { + print_bvspace(p, n, n); + return 1; + } else if (n->type == ROFFT_HEAD) + return 0; + + /* Handle the -offset argument. */ + + if (n->norm->Bd.offs == NULL || + ! strcmp(n->norm->Bd.offs, "left")) + /* nothing */; + else if ( ! strcmp(n->norm->Bd.offs, "indent")) + p->tcol->offset += term_len(p, p->defindent + 1); + else if ( ! strcmp(n->norm->Bd.offs, "indent-two")) + p->tcol->offset += term_len(p, (p->defindent + 1) * 2); + else { + offset = a2width(p, n->norm->Bd.offs); + if (offset < 0 && (size_t)(-offset) > p->tcol->offset) + p->tcol->offset = 0; + else if (offset < SHRT_MAX) + p->tcol->offset += offset; + } + + switch (n->norm->Bd.type) { + case DISP_literal: + term_tab_set(p, NULL); + term_tab_set(p, "T"); + term_tab_set(p, "8n"); + break; + case DISP_centered: + p->flags |= TERMP_CENTER; + break; + default: + break; + } + return 1; +} + +static void +termp_bd_post(DECL_ARGS) +{ + if (n->type != ROFFT_BODY) + return; + if (n->norm->Bd.type == DISP_unfilled || + n->norm->Bd.type == DISP_literal) + p->flags |= TERMP_BRNEVER; + p->flags |= TERMP_NOSPACE; + term_newln(p); + p->flags &= ~TERMP_BRNEVER; + if (n->norm->Bd.type == DISP_centered) + p->flags &= ~TERMP_CENTER; +} + +static int +termp_xx_pre(DECL_ARGS) +{ + if ((n->aux = p->flags & TERMP_PREKEEP) == 0) + p->flags |= TERMP_PREKEEP; + return 1; +} + +static void +termp_xx_post(DECL_ARGS) +{ + if (n->aux == 0) + p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); +} + +static void +termp_pf_post(DECL_ARGS) +{ + + if ( ! (n->next == NULL || n->next->flags & NODE_LINE)) + p->flags |= TERMP_NOSPACE; +} + +static int +termp_ss_pre(DECL_ARGS) +{ + struct roff_node *nn; + + switch (n->type) { + case ROFFT_BLOCK: + term_newln(p); + for (nn = n->prev; nn != NULL; nn = nn->prev) + if (nn->type != ROFFT_COMMENT && + (nn->flags & NODE_NOPRT) == 0) + break; + if (nn != NULL) + term_vspace(p); + break; + case ROFFT_HEAD: + term_fontpush(p, TERMFONT_BOLD); + p->tcol->offset = term_len(p, (p->defindent+1)/2); + break; + case ROFFT_BODY: + p->tcol->offset = term_len(p, p->defindent); + term_tab_set(p, NULL); + term_tab_set(p, "T"); + term_tab_set(p, ".5i"); + break; + default: + break; + } + + return 1; +} + +static void +termp_ss_post(DECL_ARGS) +{ + + if (n->type == ROFFT_HEAD || n->type == ROFFT_BODY) + term_newln(p); +} + +static int +termp_cd_pre(DECL_ARGS) +{ + + synopsis_pre(p, n); + term_fontpush(p, TERMFONT_BOLD); + return 1; +} + +static int +termp_in_pre(DECL_ARGS) +{ + + synopsis_pre(p, n); + + if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags) { + term_fontpush(p, TERMFONT_BOLD); + term_word(p, "#include"); + term_word(p, "<"); + } else { + term_word(p, "<"); + term_fontpush(p, TERMFONT_UNDER); + } + + p->flags |= TERMP_NOSPACE; + return 1; +} + +static void +termp_in_post(DECL_ARGS) +{ + + if (NODE_SYNPRETTY & n->flags) + term_fontpush(p, TERMFONT_BOLD); + + p->flags |= TERMP_NOSPACE; + term_word(p, ">"); + + if (NODE_SYNPRETTY & n->flags) + term_fontpop(p); +} + +static int +termp_pp_pre(DECL_ARGS) +{ + fn_prio = 0; + term_vspace(p); + return 0; +} + +static int +termp_skip_pre(DECL_ARGS) +{ + + return 0; +} + +static int +termp_quote_pre(DECL_ARGS) +{ + + if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM) + return 1; + + switch (n->tok) { + case MDOC_Ao: + case MDOC_Aq: + term_word(p, n->child != NULL && n->child->next == NULL && + n->child->tok == MDOC_Mt ? "<" : "\\(la"); + break; + case MDOC_Bro: + case MDOC_Brq: + term_word(p, "{"); + break; + case MDOC_Oo: + case MDOC_Op: + case MDOC_Bo: + case MDOC_Bq: + term_word(p, "["); + break; + case MDOC__T: + /* FALLTHROUGH */ + case MDOC_Do: + case MDOC_Dq: + term_word(p, "\\(lq"); + break; + case MDOC_En: + if (NULL == n->norm->Es || + NULL == n->norm->Es->child) + return 1; + term_word(p, n->norm->Es->child->string); + break; + case MDOC_Po: + case MDOC_Pq: + term_word(p, "("); + break; + case MDOC_Qo: + case MDOC_Qq: + term_word(p, "\""); + break; + case MDOC_Ql: + case MDOC_So: + case MDOC_Sq: + term_word(p, "\\(oq"); + break; + default: + abort(); + } + + p->flags |= TERMP_NOSPACE; + return 1; +} + +static void +termp_quote_post(DECL_ARGS) +{ + + if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM) + return; + + p->flags |= TERMP_NOSPACE; + + switch (n->tok) { + case MDOC_Ao: + case MDOC_Aq: + term_word(p, n->child != NULL && n->child->next == NULL && + n->child->tok == MDOC_Mt ? ">" : "\\(ra"); + break; + case MDOC_Bro: + case MDOC_Brq: + term_word(p, "}"); + break; + case MDOC_Oo: + case MDOC_Op: + case MDOC_Bo: + case MDOC_Bq: + term_word(p, "]"); + break; + case MDOC__T: + /* FALLTHROUGH */ + case MDOC_Do: + case MDOC_Dq: + term_word(p, "\\(rq"); + break; + case MDOC_En: + if (n->norm->Es == NULL || + n->norm->Es->child == NULL || + n->norm->Es->child->next == NULL) + p->flags &= ~TERMP_NOSPACE; + else + term_word(p, n->norm->Es->child->next->string); + break; + case MDOC_Po: + case MDOC_Pq: + term_word(p, ")"); + break; + case MDOC_Qo: + case MDOC_Qq: + term_word(p, "\""); + break; + case MDOC_Ql: + case MDOC_So: + case MDOC_Sq: + term_word(p, "\\(cq"); + break; + default: + abort(); + } +} + +static int +termp_eo_pre(DECL_ARGS) +{ + + if (n->type != ROFFT_BODY) + return 1; + + if (n->end == ENDBODY_NOT && + n->parent->head->child == NULL && + n->child != NULL && + n->child->end != ENDBODY_NOT) + term_word(p, "\\&"); + else if (n->end != ENDBODY_NOT ? n->child != NULL : + n->parent->head->child != NULL && (n->child != NULL || + (n->parent->tail != NULL && n->parent->tail->child != NULL))) + p->flags |= TERMP_NOSPACE; + + return 1; +} + +static void +termp_eo_post(DECL_ARGS) +{ + int body, tail; + + if (n->type != ROFFT_BODY) + return; + + if (n->end != ENDBODY_NOT) { + p->flags &= ~TERMP_NOSPACE; + return; + } + + body = n->child != NULL || n->parent->head->child != NULL; + tail = n->parent->tail != NULL && n->parent->tail->child != NULL; + + if (body && tail) + p->flags |= TERMP_NOSPACE; + else if ( ! (body || tail)) + term_word(p, "\\&"); + else if ( ! tail) + p->flags &= ~TERMP_NOSPACE; +} + +static int +termp_fo_pre(DECL_ARGS) +{ + size_t rmargin = 0; + int pretty; + + pretty = NODE_SYNPRETTY & n->flags; + + if (n->type == ROFFT_BLOCK) { + synopsis_pre(p, n); + return 1; + } else if (n->type == ROFFT_BODY) { + if (pretty) { + rmargin = p->tcol->rmargin; + p->tcol->rmargin = p->tcol->offset + term_len(p, 4); + p->flags |= TERMP_NOBREAK | TERMP_BRIND | + TERMP_HANG; + } + p->flags |= TERMP_NOSPACE; + term_word(p, "("); + p->flags |= TERMP_NOSPACE; + if (pretty) { + term_flushln(p); + p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | + TERMP_HANG); + p->flags |= TERMP_NOPAD; + p->tcol->offset = p->tcol->rmargin; + p->tcol->rmargin = rmargin; + } + return 1; + } + + if (NULL == n->child) + return 0; + + /* XXX: we drop non-initial arguments as per groff. */ + + assert(n->child->string); + term_fontpush(p, TERMFONT_BOLD); + term_word(p, n->child->string); + return 0; +} + +static void +termp_fo_post(DECL_ARGS) +{ + + if (n->type != ROFFT_BODY) + return; + + p->flags |= TERMP_NOSPACE; + term_word(p, ")"); + + if (NODE_SYNPRETTY & n->flags) { + p->flags |= TERMP_NOSPACE; + term_word(p, ";"); + term_flushln(p); + } +} + +static int +termp_bf_pre(DECL_ARGS) +{ + + if (n->type == ROFFT_HEAD) + return 0; + else if (n->type != ROFFT_BODY) + return 1; + + if (FONT_Em == n->norm->Bf.font) + term_fontpush(p, TERMFONT_UNDER); + else if (FONT_Sy == n->norm->Bf.font) + term_fontpush(p, TERMFONT_BOLD); + else + term_fontpush(p, TERMFONT_NONE); + + return 1; +} + +static int +termp_sm_pre(DECL_ARGS) +{ + + if (NULL == n->child) + p->flags ^= TERMP_NONOSPACE; + else if (0 == strcmp("on", n->child->string)) + p->flags &= ~TERMP_NONOSPACE; + else + p->flags |= TERMP_NONOSPACE; + + if (p->col && ! (TERMP_NONOSPACE & p->flags)) + p->flags &= ~TERMP_NOSPACE; + + return 0; +} + +static int +termp_ap_pre(DECL_ARGS) +{ + + p->flags |= TERMP_NOSPACE; + term_word(p, "'"); + p->flags |= TERMP_NOSPACE; + return 1; +} + +static void +termp____post(DECL_ARGS) +{ + + /* + * Handle lists of authors. In general, print each followed by + * a comma. Don't print the comma if there are only two + * authors. + */ + if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok) + if (NULL == n->next->next || MDOC__A != n->next->next->tok) + if (NULL == n->prev || MDOC__A != n->prev->tok) + return; + + /* TODO: %U. */ + + if (NULL == n->parent || MDOC_Rs != n->parent->tok) + return; + + p->flags |= TERMP_NOSPACE; + if (NULL == n->next) { + term_word(p, "."); + p->flags |= TERMP_SENTENCE; + } else + term_word(p, ","); +} + +static int +termp_li_pre(DECL_ARGS) +{ + + termp_tag_pre(p, pair, meta, n); + term_fontpush(p, TERMFONT_NONE); + return 1; +} + +static int +termp_lk_pre(DECL_ARGS) +{ + const struct roff_node *link, *descr, *punct; + + if ((link = n->child) == NULL) + return 0; + + /* Find beginning of trailing punctuation. */ + punct = n->last; + while (punct != link && punct->flags & NODE_DELIMC) + punct = punct->prev; + punct = punct->next; + + /* Link text. */ + if ((descr = link->next) != NULL && descr != punct) { + term_fontpush(p, TERMFONT_UNDER); + while (descr != punct) { + if (descr->flags & (NODE_DELIMC | NODE_DELIMO)) + p->flags |= TERMP_NOSPACE; + term_word(p, descr->string); + descr = descr->next; + } + term_fontpop(p); + p->flags |= TERMP_NOSPACE; + term_word(p, ":"); + } + + /* Link target. */ + term_fontpush(p, TERMFONT_BOLD); + term_word(p, link->string); + term_fontpop(p); + + /* Trailing punctuation. */ + while (punct != NULL) { + p->flags |= TERMP_NOSPACE; + term_word(p, punct->string); + punct = punct->next; + } + return 0; +} + +static int +termp_bk_pre(DECL_ARGS) +{ + + switch (n->type) { + case ROFFT_BLOCK: + break; + case ROFFT_HEAD: + return 0; + case ROFFT_BODY: + if (n->parent->args != NULL || n->prev->child == NULL) + p->flags |= TERMP_PREKEEP; + break; + default: + abort(); + } + + return 1; +} + +static void +termp_bk_post(DECL_ARGS) +{ + + if (n->type == ROFFT_BODY) + p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); +} + +static void +termp__t_post(DECL_ARGS) +{ + + /* + * If we're in an `Rs' and there's a journal present, then quote + * us instead of underlining us (for disambiguation). + */ + if (n->parent && MDOC_Rs == n->parent->tok && + n->parent->norm->Rs.quote_T) + termp_quote_post(p, pair, meta, n); + + termp____post(p, pair, meta, n); +} + +static int +termp__t_pre(DECL_ARGS) +{ + + /* + * If we're in an `Rs' and there's a journal present, then quote + * us instead of underlining us (for disambiguation). + */ + if (n->parent && MDOC_Rs == n->parent->tok && + n->parent->norm->Rs.quote_T) + return termp_quote_pre(p, pair, meta, n); + + term_fontpush(p, TERMFONT_UNDER); + return 1; +} + +static int +termp_under_pre(DECL_ARGS) +{ + + term_fontpush(p, TERMFONT_UNDER); + return 1; +} + +static int +termp_em_pre(DECL_ARGS) +{ + if (n->child != NULL && + n->child->type == ROFFT_TEXT) + tag_put(n->child->string, 0, p->line); + term_fontpush(p, TERMFONT_UNDER); + return 1; +} + +static int +termp_sy_pre(DECL_ARGS) +{ + if (n->child != NULL && + n->child->type == ROFFT_TEXT) + tag_put(n->child->string, 0, p->line); + term_fontpush(p, TERMFONT_BOLD); + return 1; +} + +static int +termp_er_pre(DECL_ARGS) +{ + + if (n->sec == SEC_ERRORS && + (n->parent->tok == MDOC_It || + (n->parent->tok == MDOC_Bq && + n->parent->parent->parent->tok == MDOC_It))) + tag_put(n->child->string, 1, p->line); + return 1; +} + +static int +termp_tag_pre(DECL_ARGS) +{ + + if (n->child != NULL && + n->child->type == ROFFT_TEXT && + (n->prev == NULL || + (n->prev->type == ROFFT_TEXT && + strcmp(n->prev->string, "|") == 0)) && + (n->parent->tok == MDOC_It || + (n->parent->tok == MDOC_Xo && + n->parent->parent->prev == NULL && + n->parent->parent->parent->tok == MDOC_It))) + tag_put(n->child->string, 1, p->line); + return 1; +} + +static int +termp_abort_pre(DECL_ARGS) +{ + abort(); +} Property changes on: vendor/mandoc/20190723/mdoc_term.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mdoc_validate.c =================================================================== --- vendor/mandoc/20190723/mdoc_validate.c (nonexistent) +++ vendor/mandoc/20190723/mdoc_validate.c (revision 350350) @@ -0,0 +1,2863 @@ +/* $Id: mdoc_validate.c,v 1.374 2019/06/27 15:07:30 schwarze Exp $ */ +/* + * Copyright (c) 2008-2012 Kristaps Dzonsons + * Copyright (c) 2010-2019 Ingo Schwarze + * Copyright (c) 2010 Joerg Sonnenberger + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include +#ifndef OSNAME +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "mandoc_xr.h" +#include "roff.h" +#include "mdoc.h" +#include "libmandoc.h" +#include "roff_int.h" +#include "libmdoc.h" + +/* FIXME: .Bl -diag can't have non-text children in HEAD. */ + +#define POST_ARGS struct roff_man *mdoc + +enum check_ineq { + CHECK_LT, + CHECK_GT, + CHECK_EQ +}; + +typedef void (*v_post)(POST_ARGS); + +static int build_list(struct roff_man *, int); +static void check_argv(struct roff_man *, + struct roff_node *, struct mdoc_argv *); +static void check_args(struct roff_man *, struct roff_node *); +static void check_text(struct roff_man *, int, int, char *); +static void check_text_em(struct roff_man *, int, int, char *); +static void check_toptext(struct roff_man *, int, int, const char *); +static int child_an(const struct roff_node *); +static size_t macro2len(enum roff_tok); +static void rewrite_macro2len(struct roff_man *, char **); +static int similar(const char *, const char *); + +static void post_abort(POST_ARGS) __attribute__((__noreturn__)); +static void post_an(POST_ARGS); +static void post_an_norm(POST_ARGS); +static void post_at(POST_ARGS); +static void post_bd(POST_ARGS); +static void post_bf(POST_ARGS); +static void post_bk(POST_ARGS); +static void post_bl(POST_ARGS); +static void post_bl_block(POST_ARGS); +static void post_bl_head(POST_ARGS); +static void post_bl_norm(POST_ARGS); +static void post_bx(POST_ARGS); +static void post_defaults(POST_ARGS); +static void post_display(POST_ARGS); +static void post_dd(POST_ARGS); +static void post_delim(POST_ARGS); +static void post_delim_nb(POST_ARGS); +static void post_dt(POST_ARGS); +static void post_en(POST_ARGS); +static void post_es(POST_ARGS); +static void post_eoln(POST_ARGS); +static void post_ex(POST_ARGS); +static void post_fa(POST_ARGS); +static void post_fn(POST_ARGS); +static void post_fname(POST_ARGS); +static void post_fo(POST_ARGS); +static void post_hyph(POST_ARGS); +static void post_ignpar(POST_ARGS); +static void post_it(POST_ARGS); +static void post_lb(POST_ARGS); +static void post_nd(POST_ARGS); +static void post_nm(POST_ARGS); +static void post_ns(POST_ARGS); +static void post_obsolete(POST_ARGS); +static void post_os(POST_ARGS); +static void post_par(POST_ARGS); +static void post_prevpar(POST_ARGS); +static void post_root(POST_ARGS); +static void post_rs(POST_ARGS); +static void post_rv(POST_ARGS); +static void post_sh(POST_ARGS); +static void post_sh_head(POST_ARGS); +static void post_sh_name(POST_ARGS); +static void post_sh_see_also(POST_ARGS); +static void post_sh_authors(POST_ARGS); +static void post_sm(POST_ARGS); +static void post_st(POST_ARGS); +static void post_std(POST_ARGS); +static void post_sx(POST_ARGS); +static void post_useless(POST_ARGS); +static void post_xr(POST_ARGS); +static void post_xx(POST_ARGS); + +static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = { + post_dd, /* Dd */ + post_dt, /* Dt */ + post_os, /* Os */ + post_sh, /* Sh */ + post_ignpar, /* Ss */ + post_par, /* Pp */ + post_display, /* D1 */ + post_display, /* Dl */ + post_display, /* Bd */ + NULL, /* Ed */ + post_bl, /* Bl */ + NULL, /* El */ + post_it, /* It */ + post_delim_nb, /* Ad */ + post_an, /* An */ + NULL, /* Ap */ + post_defaults, /* Ar */ + NULL, /* Cd */ + post_delim_nb, /* Cm */ + post_delim_nb, /* Dv */ + post_delim_nb, /* Er */ + post_delim_nb, /* Ev */ + post_ex, /* Ex */ + post_fa, /* Fa */ + NULL, /* Fd */ + post_delim_nb, /* Fl */ + post_fn, /* Fn */ + post_delim_nb, /* Ft */ + post_delim_nb, /* Ic */ + post_delim_nb, /* In */ + post_defaults, /* Li */ + post_nd, /* Nd */ + post_nm, /* Nm */ + post_delim_nb, /* Op */ + post_abort, /* Ot */ + post_defaults, /* Pa */ + post_rv, /* Rv */ + post_st, /* St */ + post_delim_nb, /* Va */ + post_delim_nb, /* Vt */ + post_xr, /* Xr */ + NULL, /* %A */ + post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ + NULL, /* %D */ + NULL, /* %I */ + NULL, /* %J */ + post_hyph, /* %N */ + post_hyph, /* %O */ + NULL, /* %P */ + post_hyph, /* %R */ + post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ + NULL, /* %V */ + NULL, /* Ac */ + NULL, /* Ao */ + post_delim_nb, /* Aq */ + post_at, /* At */ + NULL, /* Bc */ + post_bf, /* Bf */ + NULL, /* Bo */ + NULL, /* Bq */ + post_xx, /* Bsx */ + post_bx, /* Bx */ + post_obsolete, /* Db */ + NULL, /* Dc */ + NULL, /* Do */ + NULL, /* Dq */ + NULL, /* Ec */ + NULL, /* Ef */ + post_delim_nb, /* Em */ + NULL, /* Eo */ + post_xx, /* Fx */ + post_delim_nb, /* Ms */ + NULL, /* No */ + post_ns, /* Ns */ + post_xx, /* Nx */ + post_xx, /* Ox */ + NULL, /* Pc */ + NULL, /* Pf */ + NULL, /* Po */ + post_delim_nb, /* Pq */ + NULL, /* Qc */ + post_delim_nb, /* Ql */ + NULL, /* Qo */ + post_delim_nb, /* Qq */ + NULL, /* Re */ + post_rs, /* Rs */ + NULL, /* Sc */ + NULL, /* So */ + post_delim_nb, /* Sq */ + post_sm, /* Sm */ + post_sx, /* Sx */ + post_delim_nb, /* Sy */ + post_useless, /* Tn */ + post_xx, /* Ux */ + NULL, /* Xc */ + NULL, /* Xo */ + post_fo, /* Fo */ + NULL, /* Fc */ + NULL, /* Oo */ + NULL, /* Oc */ + post_bk, /* Bk */ + NULL, /* Ek */ + post_eoln, /* Bt */ + post_obsolete, /* Hf */ + post_obsolete, /* Fr */ + post_eoln, /* Ud */ + post_lb, /* Lb */ + post_abort, /* Lp */ + post_delim_nb, /* Lk */ + post_defaults, /* Mt */ + post_delim_nb, /* Brq */ + NULL, /* Bro */ + NULL, /* Brc */ + NULL, /* %C */ + post_es, /* Es */ + post_en, /* En */ + post_xx, /* Dx */ + NULL, /* %Q */ + NULL, /* %U */ + NULL, /* Ta */ +}; + +#define RSORD_MAX 14 /* Number of `Rs' blocks. */ + +static const enum roff_tok rsord[RSORD_MAX] = { + MDOC__A, + MDOC__T, + MDOC__B, + MDOC__I, + MDOC__J, + MDOC__R, + MDOC__N, + MDOC__V, + MDOC__U, + MDOC__P, + MDOC__Q, + MDOC__C, + MDOC__D, + MDOC__O +}; + +static const char * const secnames[SEC__MAX] = { + NULL, + "NAME", + "LIBRARY", + "SYNOPSIS", + "DESCRIPTION", + "CONTEXT", + "IMPLEMENTATION NOTES", + "RETURN VALUES", + "ENVIRONMENT", + "FILES", + "EXIT STATUS", + "EXAMPLES", + "DIAGNOSTICS", + "COMPATIBILITY", + "ERRORS", + "SEE ALSO", + "STANDARDS", + "HISTORY", + "AUTHORS", + "CAVEATS", + "BUGS", + "SECURITY CONSIDERATIONS", + NULL +}; + + +/* Validate the subtree rooted at mdoc->last. */ +void +mdoc_validate(struct roff_man *mdoc) +{ + struct roff_node *n, *np; + const v_post *p; + + /* + * Translate obsolete macros to modern macros first + * such that later code does not need to look + * for the obsolete versions. + */ + + n = mdoc->last; + switch (n->tok) { + case MDOC_Lp: + n->tok = MDOC_Pp; + break; + case MDOC_Ot: + post_obsolete(mdoc); + n->tok = MDOC_Ft; + break; + default: + break; + } + + /* + * Iterate over all children, recursing into each one + * in turn, depth-first. + */ + + mdoc->last = mdoc->last->child; + while (mdoc->last != NULL) { + mdoc_validate(mdoc); + if (mdoc->last == n) + mdoc->last = mdoc->last->child; + else + mdoc->last = mdoc->last->next; + } + + /* Finally validate the macro itself. */ + + mdoc->last = n; + mdoc->next = ROFF_NEXT_SIBLING; + switch (n->type) { + case ROFFT_TEXT: + np = n->parent; + if (n->sec != SEC_SYNOPSIS || + (np->tok != MDOC_Cd && np->tok != MDOC_Fd)) + check_text(mdoc, n->line, n->pos, n->string); + if ((n->flags & NODE_NOFILL) == 0 && + (np->tok != MDOC_It || np->type != ROFFT_HEAD || + np->parent->parent->norm->Bl.type != LIST_diag)) + check_text_em(mdoc, n->line, n->pos, n->string); + if (np->tok == MDOC_It || (np->type == ROFFT_BODY && + (np->tok == MDOC_Sh || np->tok == MDOC_Ss))) + check_toptext(mdoc, n->line, n->pos, n->string); + break; + case ROFFT_COMMENT: + case ROFFT_EQN: + case ROFFT_TBL: + break; + case ROFFT_ROOT: + post_root(mdoc); + break; + default: + check_args(mdoc, mdoc->last); + + /* + * Closing delimiters are not special at the + * beginning of a block, opening delimiters + * are not special at the end. + */ + + if (n->child != NULL) + n->child->flags &= ~NODE_DELIMC; + if (n->last != NULL) + n->last->flags &= ~NODE_DELIMO; + + /* Call the macro's postprocessor. */ + + if (n->tok < ROFF_MAX) { + roff_validate(mdoc); + break; + } + + assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); + p = mdoc_valids + (n->tok - MDOC_Dd); + if (*p) + (*p)(mdoc); + if (mdoc->last == n) + mdoc_state(mdoc, n); + break; + } +} + +static void +check_args(struct roff_man *mdoc, struct roff_node *n) +{ + int i; + + if (NULL == n->args) + return; + + assert(n->args->argc); + for (i = 0; i < (int)n->args->argc; i++) + check_argv(mdoc, n, &n->args->argv[i]); +} + +static void +check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v) +{ + int i; + + for (i = 0; i < (int)v->sz; i++) + check_text(mdoc, v->line, v->pos, v->value[i]); +} + +static void +check_text(struct roff_man *mdoc, int ln, int pos, char *p) +{ + char *cp; + + if (mdoc->last->flags & NODE_NOFILL) + return; + + for (cp = p; NULL != (p = strchr(p, '\t')); p++) + mandoc_msg(MANDOCERR_FI_TAB, ln, pos + (int)(p - cp), NULL); +} + +static void +check_text_em(struct roff_man *mdoc, int ln, int pos, char *p) +{ + const struct roff_node *np, *nn; + char *cp; + + np = mdoc->last->prev; + nn = mdoc->last->next; + + /* Look for em-dashes wrongly encoded as "--". */ + + for (cp = p; *cp != '\0'; cp++) { + if (cp[0] != '-' || cp[1] != '-') + continue; + cp++; + + /* Skip input sequences of more than two '-'. */ + + if (cp[1] == '-') { + while (cp[1] == '-') + cp++; + continue; + } + + /* Skip "--" directly attached to something else. */ + + if ((cp - p > 1 && cp[-2] != ' ') || + (cp[1] != '\0' && cp[1] != ' ')) + continue; + + /* Require a letter right before or right afterwards. */ + + if ((cp - p > 2 ? + isalpha((unsigned char)cp[-3]) : + np != NULL && + np->type == ROFFT_TEXT && + *np->string != '\0' && + isalpha((unsigned char)np->string[ + strlen(np->string) - 1])) || + (cp[1] != '\0' && cp[2] != '\0' ? + isalpha((unsigned char)cp[2]) : + nn != NULL && + nn->type == ROFFT_TEXT && + isalpha((unsigned char)*nn->string))) { + mandoc_msg(MANDOCERR_DASHDASH, + ln, pos + (int)(cp - p) - 1, NULL); + break; + } + } +} + +static void +check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) +{ + const char *cp, *cpr; + + if (*p == '\0') + return; + + if ((cp = strstr(p, "OpenBSD")) != NULL) + mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Ox"); + if ((cp = strstr(p, "NetBSD")) != NULL) + mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Nx"); + if ((cp = strstr(p, "FreeBSD")) != NULL) + mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Fx"); + if ((cp = strstr(p, "DragonFly")) != NULL) + mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Dx"); + + cp = p; + while ((cp = strstr(cp + 1, "()")) != NULL) { + for (cpr = cp - 1; cpr >= p; cpr--) + if (*cpr != '_' && !isalnum((unsigned char)*cpr)) + break; + if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) { + cpr++; + mandoc_msg(MANDOCERR_FUNC, ln, pos + (int)(cpr - p), + "%.*s()", (int)(cp - cpr), cpr); + } + } +} + +static void +post_abort(POST_ARGS) +{ + abort(); +} + +static void +post_delim(POST_ARGS) +{ + const struct roff_node *nch; + const char *lc; + enum mdelim delim; + enum roff_tok tok; + + tok = mdoc->last->tok; + nch = mdoc->last->last; + if (nch == NULL || nch->type != ROFFT_TEXT) + return; + lc = strchr(nch->string, '\0') - 1; + if (lc < nch->string) + return; + delim = mdoc_isdelim(lc); + if (delim == DELIM_NONE || delim == DELIM_OPEN) + return; + if (*lc == ')' && (tok == MDOC_Nd || tok == MDOC_Sh || + tok == MDOC_Ss || tok == MDOC_Fo)) + return; + + mandoc_msg(MANDOCERR_DELIM, nch->line, + nch->pos + (int)(lc - nch->string), "%s%s %s", roff_name[tok], + nch == mdoc->last->child ? "" : " ...", nch->string); +} + +static void +post_delim_nb(POST_ARGS) +{ + const struct roff_node *nch; + const char *lc, *cp; + int nw; + enum mdelim delim; + enum roff_tok tok; + + /* + * Find candidates: at least two bytes, + * the last one a closing or middle delimiter. + */ + + tok = mdoc->last->tok; + nch = mdoc->last->last; + if (nch == NULL || nch->type != ROFFT_TEXT) + return; + lc = strchr(nch->string, '\0') - 1; + if (lc <= nch->string) + return; + delim = mdoc_isdelim(lc); + if (delim == DELIM_NONE || delim == DELIM_OPEN) + return; + + /* + * Reduce false positives by allowing various cases. + */ + + /* Escaped delimiters. */ + if (lc > nch->string + 1 && lc[-2] == '\\' && + (lc[-1] == '&' || lc[-1] == 'e')) + return; + + /* Specific byte sequences. */ + switch (*lc) { + case ')': + for (cp = lc; cp >= nch->string; cp--) + if (*cp == '(') + return; + break; + case '.': + if (lc > nch->string + 1 && lc[-2] == '.' && lc[-1] == '.') + return; + if (lc[-1] == '.') + return; + break; + case ';': + if (tok == MDOC_Vt) + return; + break; + case '?': + if (lc[-1] == '?') + return; + break; + case ']': + for (cp = lc; cp >= nch->string; cp--) + if (*cp == '[') + return; + break; + case '|': + if (lc == nch->string + 1 && lc[-1] == '|') + return; + default: + break; + } + + /* Exactly two non-alphanumeric bytes. */ + if (lc == nch->string + 1 && !isalnum((unsigned char)lc[-1])) + return; + + /* At least three alphabetic words with a sentence ending. */ + if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em || + tok == MDOC_Li || tok == MDOC_Pq || tok == MDOC_Sy)) { + nw = 0; + for (cp = lc - 1; cp >= nch->string; cp--) { + if (*cp == ' ') { + nw++; + if (cp > nch->string && cp[-1] == ',') + cp--; + } else if (isalpha((unsigned int)*cp)) { + if (nw > 1) + return; + } else + break; + } + } + + mandoc_msg(MANDOCERR_DELIM_NB, nch->line, + nch->pos + (int)(lc - nch->string), "%s%s %s", roff_name[tok], + nch == mdoc->last->child ? "" : " ...", nch->string); +} + +static void +post_bl_norm(POST_ARGS) +{ + struct roff_node *n; + struct mdoc_argv *argv, *wa; + int i; + enum mdocargt mdoclt; + enum mdoc_list lt; + + n = mdoc->last->parent; + n->norm->Bl.type = LIST__NONE; + + /* + * First figure out which kind of list to use: bind ourselves to + * the first mentioned list type and warn about any remaining + * ones. If we find no list type, we default to LIST_item. + */ + + wa = (n->args == NULL) ? NULL : n->args->argv; + mdoclt = MDOC_ARG_MAX; + for (i = 0; n->args && i < (int)n->args->argc; i++) { + argv = n->args->argv + i; + lt = LIST__NONE; + switch (argv->arg) { + /* Set list types. */ + case MDOC_Bullet: + lt = LIST_bullet; + break; + case MDOC_Dash: + lt = LIST_dash; + break; + case MDOC_Enum: + lt = LIST_enum; + break; + case MDOC_Hyphen: + lt = LIST_hyphen; + break; + case MDOC_Item: + lt = LIST_item; + break; + case MDOC_Tag: + lt = LIST_tag; + break; + case MDOC_Diag: + lt = LIST_diag; + break; + case MDOC_Hang: + lt = LIST_hang; + break; + case MDOC_Ohang: + lt = LIST_ohang; + break; + case MDOC_Inset: + lt = LIST_inset; + break; + case MDOC_Column: + lt = LIST_column; + break; + /* Set list arguments. */ + case MDOC_Compact: + if (n->norm->Bl.comp) + mandoc_msg(MANDOCERR_ARG_REP, + argv->line, argv->pos, "Bl -compact"); + n->norm->Bl.comp = 1; + break; + case MDOC_Width: + wa = argv; + if (0 == argv->sz) { + mandoc_msg(MANDOCERR_ARG_EMPTY, + argv->line, argv->pos, "Bl -width"); + n->norm->Bl.width = "0n"; + break; + } + if (NULL != n->norm->Bl.width) + mandoc_msg(MANDOCERR_ARG_REP, + argv->line, argv->pos, + "Bl -width %s", argv->value[0]); + rewrite_macro2len(mdoc, argv->value); + n->norm->Bl.width = argv->value[0]; + break; + case MDOC_Offset: + if (0 == argv->sz) { + mandoc_msg(MANDOCERR_ARG_EMPTY, + argv->line, argv->pos, "Bl -offset"); + break; + } + if (NULL != n->norm->Bl.offs) + mandoc_msg(MANDOCERR_ARG_REP, + argv->line, argv->pos, + "Bl -offset %s", argv->value[0]); + rewrite_macro2len(mdoc, argv->value); + n->norm->Bl.offs = argv->value[0]; + break; + default: + continue; + } + if (LIST__NONE == lt) + continue; + mdoclt = argv->arg; + + /* Check: multiple list types. */ + + if (LIST__NONE != n->norm->Bl.type) { + mandoc_msg(MANDOCERR_BL_REP, n->line, n->pos, + "Bl -%s", mdoc_argnames[argv->arg]); + continue; + } + + /* The list type should come first. */ + + if (n->norm->Bl.width || + n->norm->Bl.offs || + n->norm->Bl.comp) + mandoc_msg(MANDOCERR_BL_LATETYPE, + n->line, n->pos, "Bl -%s", + mdoc_argnames[n->args->argv[0].arg]); + + n->norm->Bl.type = lt; + if (LIST_column == lt) { + n->norm->Bl.ncols = argv->sz; + n->norm->Bl.cols = (void *)argv->value; + } + } + + /* Allow lists to default to LIST_item. */ + + if (LIST__NONE == n->norm->Bl.type) { + mandoc_msg(MANDOCERR_BL_NOTYPE, n->line, n->pos, "Bl"); + n->norm->Bl.type = LIST_item; + mdoclt = MDOC_Item; + } + + /* + * Validate the width field. Some list types don't need width + * types and should be warned about them. Others should have it + * and must also be warned. Yet others have a default and need + * no warning. + */ + + switch (n->norm->Bl.type) { + case LIST_tag: + if (n->norm->Bl.width == NULL) + mandoc_msg(MANDOCERR_BL_NOWIDTH, + n->line, n->pos, "Bl -tag"); + break; + case LIST_column: + case LIST_diag: + case LIST_ohang: + case LIST_inset: + case LIST_item: + if (n->norm->Bl.width != NULL) + mandoc_msg(MANDOCERR_BL_SKIPW, wa->line, wa->pos, + "Bl -%s", mdoc_argnames[mdoclt]); + n->norm->Bl.width = NULL; + break; + case LIST_bullet: + case LIST_dash: + case LIST_hyphen: + if (n->norm->Bl.width == NULL) + n->norm->Bl.width = "2n"; + break; + case LIST_enum: + if (n->norm->Bl.width == NULL) + n->norm->Bl.width = "3n"; + break; + default: + break; + } +} + +static void +post_bd(POST_ARGS) +{ + struct roff_node *n; + struct mdoc_argv *argv; + int i; + enum mdoc_disp dt; + + n = mdoc->last; + for (i = 0; n->args && i < (int)n->args->argc; i++) { + argv = n->args->argv + i; + dt = DISP__NONE; + + switch (argv->arg) { + case MDOC_Centred: + dt = DISP_centered; + break; + case MDOC_Ragged: + dt = DISP_ragged; + break; + case MDOC_Unfilled: + dt = DISP_unfilled; + break; + case MDOC_Filled: + dt = DISP_filled; + break; + case MDOC_Literal: + dt = DISP_literal; + break; + case MDOC_File: + mandoc_msg(MANDOCERR_BD_FILE, n->line, n->pos, NULL); + break; + case MDOC_Offset: + if (0 == argv->sz) { + mandoc_msg(MANDOCERR_ARG_EMPTY, + argv->line, argv->pos, "Bd -offset"); + break; + } + if (NULL != n->norm->Bd.offs) + mandoc_msg(MANDOCERR_ARG_REP, + argv->line, argv->pos, + "Bd -offset %s", argv->value[0]); + rewrite_macro2len(mdoc, argv->value); + n->norm->Bd.offs = argv->value[0]; + break; + case MDOC_Compact: + if (n->norm->Bd.comp) + mandoc_msg(MANDOCERR_ARG_REP, + argv->line, argv->pos, "Bd -compact"); + n->norm->Bd.comp = 1; + break; + default: + abort(); + } + if (DISP__NONE == dt) + continue; + + if (DISP__NONE == n->norm->Bd.type) + n->norm->Bd.type = dt; + else + mandoc_msg(MANDOCERR_BD_REP, n->line, n->pos, + "Bd -%s", mdoc_argnames[argv->arg]); + } + + if (DISP__NONE == n->norm->Bd.type) { + mandoc_msg(MANDOCERR_BD_NOTYPE, n->line, n->pos, "Bd"); + n->norm->Bd.type = DISP_ragged; + } +} + +/* + * Stand-alone line macros. + */ + +static void +post_an_norm(POST_ARGS) +{ + struct roff_node *n; + struct mdoc_argv *argv; + size_t i; + + n = mdoc->last; + if (n->args == NULL) + return; + + for (i = 1; i < n->args->argc; i++) { + argv = n->args->argv + i; + mandoc_msg(MANDOCERR_AN_REP, argv->line, argv->pos, + "An -%s", mdoc_argnames[argv->arg]); + } + + argv = n->args->argv; + if (argv->arg == MDOC_Split) + n->norm->An.auth = AUTH_split; + else if (argv->arg == MDOC_Nosplit) + n->norm->An.auth = AUTH_nosplit; + else + abort(); +} + +static void +post_eoln(POST_ARGS) +{ + struct roff_node *n; + + post_useless(mdoc); + n = mdoc->last; + if (n->child != NULL) + mandoc_msg(MANDOCERR_ARG_SKIP, n->line, + n->pos, "%s %s", roff_name[n->tok], n->child->string); + + while (n->child != NULL) + roff_node_delete(mdoc, n->child); + + roff_word_alloc(mdoc, n->line, n->pos, n->tok == MDOC_Bt ? + "is currently in beta test." : "currently under development."); + mdoc->last->flags |= NODE_EOS | NODE_NOSRC; + mdoc->last = n; +} + +static int +build_list(struct roff_man *mdoc, int tok) +{ + struct roff_node *n; + int ic; + + n = mdoc->last->next; + for (ic = 1;; ic++) { + roff_elem_alloc(mdoc, n->line, n->pos, tok); + mdoc->last->flags |= NODE_NOSRC; + roff_node_relink(mdoc, n); + n = mdoc->last = mdoc->last->parent; + mdoc->next = ROFF_NEXT_SIBLING; + if (n->next == NULL) + return ic; + if (ic > 1 || n->next->next != NULL) { + roff_word_alloc(mdoc, n->line, n->pos, ","); + mdoc->last->flags |= NODE_DELIMC | NODE_NOSRC; + } + n = mdoc->last->next; + if (n->next == NULL) { + roff_word_alloc(mdoc, n->line, n->pos, "and"); + mdoc->last->flags |= NODE_NOSRC; + } + } +} + +static void +post_ex(POST_ARGS) +{ + struct roff_node *n; + int ic; + + post_std(mdoc); + + n = mdoc->last; + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, n->line, n->pos, "The"); + mdoc->last->flags |= NODE_NOSRC; + + if (mdoc->last->next != NULL) + ic = build_list(mdoc, MDOC_Nm); + else if (mdoc->meta.name != NULL) { + roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Nm); + mdoc->last->flags |= NODE_NOSRC; + roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = mdoc->last->parent; + mdoc->next = ROFF_NEXT_SIBLING; + ic = 1; + } else { + mandoc_msg(MANDOCERR_EX_NONAME, n->line, n->pos, "Ex"); + ic = 0; + } + + roff_word_alloc(mdoc, n->line, n->pos, + ic > 1 ? "utilities exit\\~0" : "utility exits\\~0"); + mdoc->last->flags |= NODE_NOSRC; + roff_word_alloc(mdoc, n->line, n->pos, + "on success, and\\~>0 if an error occurs."); + mdoc->last->flags |= NODE_EOS | NODE_NOSRC; + mdoc->last = n; +} + +static void +post_lb(POST_ARGS) +{ + struct roff_node *n; + const char *p; + + post_delim_nb(mdoc); + + n = mdoc->last; + assert(n->child->type == ROFFT_TEXT); + mdoc->next = ROFF_NEXT_CHILD; + + if ((p = mdoc_a2lib(n->child->string)) != NULL) { + n->child->flags |= NODE_NOPRT; + roff_word_alloc(mdoc, n->line, n->pos, p); + mdoc->last->flags = NODE_NOSRC; + mdoc->last = n; + return; + } + + mandoc_msg(MANDOCERR_LB_BAD, n->child->line, + n->child->pos, "Lb %s", n->child->string); + + roff_word_alloc(mdoc, n->line, n->pos, "library"); + mdoc->last->flags = NODE_NOSRC; + roff_word_alloc(mdoc, n->line, n->pos, "\\(lq"); + mdoc->last->flags = NODE_DELIMO | NODE_NOSRC; + mdoc->last = mdoc->last->next; + roff_word_alloc(mdoc, n->line, n->pos, "\\(rq"); + mdoc->last->flags = NODE_DELIMC | NODE_NOSRC; + mdoc->last = n; +} + +static void +post_rv(POST_ARGS) +{ + struct roff_node *n; + int ic; + + post_std(mdoc); + + n = mdoc->last; + mdoc->next = ROFF_NEXT_CHILD; + if (n->child != NULL) { + roff_word_alloc(mdoc, n->line, n->pos, "The"); + mdoc->last->flags |= NODE_NOSRC; + ic = build_list(mdoc, MDOC_Fn); + roff_word_alloc(mdoc, n->line, n->pos, + ic > 1 ? "functions return" : "function returns"); + mdoc->last->flags |= NODE_NOSRC; + roff_word_alloc(mdoc, n->line, n->pos, + "the value\\~0 if successful;"); + } else + roff_word_alloc(mdoc, n->line, n->pos, "Upon successful " + "completion, the value\\~0 is returned;"); + mdoc->last->flags |= NODE_NOSRC; + + roff_word_alloc(mdoc, n->line, n->pos, "otherwise " + "the value\\~\\-1 is returned and the global variable"); + mdoc->last->flags |= NODE_NOSRC; + roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Va); + mdoc->last->flags |= NODE_NOSRC; + roff_word_alloc(mdoc, n->line, n->pos, "errno"); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = mdoc->last->parent; + mdoc->next = ROFF_NEXT_SIBLING; + roff_word_alloc(mdoc, n->line, n->pos, + "is set to indicate the error."); + mdoc->last->flags |= NODE_EOS | NODE_NOSRC; + mdoc->last = n; +} + +static void +post_std(POST_ARGS) +{ + struct roff_node *n; + + post_delim(mdoc); + + n = mdoc->last; + if (n->args && n->args->argc == 1) + if (n->args->argv[0].arg == MDOC_Std) + return; + + mandoc_msg(MANDOCERR_ARG_STD, n->line, n->pos, + "%s", roff_name[n->tok]); +} + +static void +post_st(POST_ARGS) +{ + struct roff_node *n, *nch; + const char *p; + + n = mdoc->last; + nch = n->child; + assert(nch->type == ROFFT_TEXT); + + if ((p = mdoc_a2st(nch->string)) == NULL) { + mandoc_msg(MANDOCERR_ST_BAD, + nch->line, nch->pos, "St %s", nch->string); + roff_node_delete(mdoc, n); + return; + } + + nch->flags |= NODE_NOPRT; + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, nch->line, nch->pos, p); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last= n; +} + +static void +post_obsolete(POST_ARGS) +{ + struct roff_node *n; + + n = mdoc->last; + if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) + mandoc_msg(MANDOCERR_MACRO_OBS, n->line, n->pos, + "%s", roff_name[n->tok]); +} + +static void +post_useless(POST_ARGS) +{ + struct roff_node *n; + + n = mdoc->last; + mandoc_msg(MANDOCERR_MACRO_USELESS, n->line, n->pos, + "%s", roff_name[n->tok]); +} + +/* + * Block macros. + */ + +static void +post_bf(POST_ARGS) +{ + struct roff_node *np, *nch; + + /* + * Unlike other data pointers, these are "housed" by the HEAD + * element, which contains the goods. + */ + + np = mdoc->last; + if (np->type != ROFFT_HEAD) + return; + + assert(np->parent->type == ROFFT_BLOCK); + assert(np->parent->tok == MDOC_Bf); + + /* Check the number of arguments. */ + + nch = np->child; + if (np->parent->args == NULL) { + if (nch == NULL) { + mandoc_msg(MANDOCERR_BF_NOFONT, + np->line, np->pos, "Bf"); + return; + } + nch = nch->next; + } + if (nch != NULL) + mandoc_msg(MANDOCERR_ARG_EXCESS, + nch->line, nch->pos, "Bf ... %s", nch->string); + + /* Extract argument into data. */ + + if (np->parent->args != NULL) { + switch (np->parent->args->argv[0].arg) { + case MDOC_Emphasis: + np->norm->Bf.font = FONT_Em; + break; + case MDOC_Literal: + np->norm->Bf.font = FONT_Li; + break; + case MDOC_Symbolic: + np->norm->Bf.font = FONT_Sy; + break; + default: + abort(); + } + return; + } + + /* Extract parameter into data. */ + + if ( ! strcmp(np->child->string, "Em")) + np->norm->Bf.font = FONT_Em; + else if ( ! strcmp(np->child->string, "Li")) + np->norm->Bf.font = FONT_Li; + else if ( ! strcmp(np->child->string, "Sy")) + np->norm->Bf.font = FONT_Sy; + else + mandoc_msg(MANDOCERR_BF_BADFONT, np->child->line, + np->child->pos, "Bf %s", np->child->string); +} + +static void +post_fname(POST_ARGS) +{ + const struct roff_node *n; + const char *cp; + size_t pos; + + n = mdoc->last->child; + pos = strcspn(n->string, "()"); + cp = n->string + pos; + if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) + mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos, + "%s", n->string); +} + +static void +post_fn(POST_ARGS) +{ + + post_fname(mdoc); + post_fa(mdoc); +} + +static void +post_fo(POST_ARGS) +{ + const struct roff_node *n; + + n = mdoc->last; + + if (n->type != ROFFT_HEAD) + return; + + if (n->child == NULL) { + mandoc_msg(MANDOCERR_FO_NOHEAD, n->line, n->pos, "Fo"); + return; + } + if (n->child != n->last) { + mandoc_msg(MANDOCERR_ARG_EXCESS, + n->child->next->line, n->child->next->pos, + "Fo ... %s", n->child->next->string); + while (n->child != n->last) + roff_node_delete(mdoc, n->last); + } else + post_delim(mdoc); + + post_fname(mdoc); +} + +static void +post_fa(POST_ARGS) +{ + const struct roff_node *n; + const char *cp; + + for (n = mdoc->last->child; n != NULL; n = n->next) { + for (cp = n->string; *cp != '\0'; cp++) { + /* Ignore callbacks and alterations. */ + if (*cp == '(' || *cp == '{') + break; + if (*cp != ',') + continue; + mandoc_msg(MANDOCERR_FA_COMMA, n->line, + n->pos + (int)(cp - n->string), "%s", n->string); + break; + } + } + post_delim_nb(mdoc); +} + +static void +post_nm(POST_ARGS) +{ + struct roff_node *n; + + n = mdoc->last; + + if (n->sec == SEC_NAME && n->child != NULL && + n->child->type == ROFFT_TEXT && mdoc->meta.msec != NULL) + mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1); + + if (n->last != NULL && n->last->tok == MDOC_Pp) + roff_node_relink(mdoc, n->last); + + if (mdoc->meta.name == NULL) + deroff(&mdoc->meta.name, n); + + if (mdoc->meta.name == NULL || + (mdoc->lastsec == SEC_NAME && n->child == NULL)) + mandoc_msg(MANDOCERR_NM_NONAME, n->line, n->pos, "Nm"); + + switch (n->type) { + case ROFFT_ELEM: + post_delim_nb(mdoc); + break; + case ROFFT_HEAD: + post_delim(mdoc); + break; + default: + return; + } + + if ((n->child != NULL && n->child->type == ROFFT_TEXT) || + mdoc->meta.name == NULL) + return; + + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = n; +} + +static void +post_nd(POST_ARGS) +{ + struct roff_node *n; + + n = mdoc->last; + + if (n->type != ROFFT_BODY) + return; + + if (n->sec != SEC_NAME) + mandoc_msg(MANDOCERR_ND_LATE, n->line, n->pos, "Nd"); + + if (n->child == NULL) + mandoc_msg(MANDOCERR_ND_EMPTY, n->line, n->pos, "Nd"); + else + post_delim(mdoc); + + post_hyph(mdoc); +} + +static void +post_display(POST_ARGS) +{ + struct roff_node *n, *np; + + n = mdoc->last; + switch (n->type) { + case ROFFT_BODY: + if (n->end != ENDBODY_NOT) { + if (n->tok == MDOC_Bd && + n->body->parent->args == NULL) + roff_node_delete(mdoc, n); + } else if (n->child == NULL) + mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, + "%s", roff_name[n->tok]); + else if (n->tok == MDOC_D1) + post_hyph(mdoc); + break; + case ROFFT_BLOCK: + if (n->tok == MDOC_Bd) { + if (n->args == NULL) { + mandoc_msg(MANDOCERR_BD_NOARG, + n->line, n->pos, "Bd"); + mdoc->next = ROFF_NEXT_SIBLING; + while (n->body->child != NULL) + roff_node_relink(mdoc, + n->body->child); + roff_node_delete(mdoc, n); + break; + } + post_bd(mdoc); + post_prevpar(mdoc); + } + for (np = n->parent; np != NULL; np = np->parent) { + if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) { + mandoc_msg(MANDOCERR_BD_NEST, n->line, + n->pos, "%s in Bd", roff_name[n->tok]); + break; + } + } + break; + default: + break; + } +} + +static void +post_defaults(POST_ARGS) +{ + struct roff_node *nn; + + if (mdoc->last->child != NULL) { + post_delim_nb(mdoc); + return; + } + + /* + * The `Ar' defaults to "file ..." if no value is provided as an + * argument; the `Mt' and `Pa' macros use "~"; the `Li' just + * gets an empty string. + */ + + nn = mdoc->last; + switch (nn->tok) { + case MDOC_Ar: + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, nn->line, nn->pos, "file"); + mdoc->last->flags |= NODE_NOSRC; + roff_word_alloc(mdoc, nn->line, nn->pos, "..."); + mdoc->last->flags |= NODE_NOSRC; + break; + case MDOC_Pa: + case MDOC_Mt: + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, nn->line, nn->pos, "~"); + mdoc->last->flags |= NODE_NOSRC; + break; + default: + abort(); + } + mdoc->last = nn; +} + +static void +post_at(POST_ARGS) +{ + struct roff_node *n, *nch; + const char *att; + + n = mdoc->last; + nch = n->child; + + /* + * If we have a child, look it up in the standard keys. If a + * key exist, use that instead of the child; if it doesn't, + * prefix "AT&T UNIX " to the existing data. + */ + + att = NULL; + if (nch != NULL && ((att = mdoc_a2att(nch->string)) == NULL)) + mandoc_msg(MANDOCERR_AT_BAD, + nch->line, nch->pos, "At %s", nch->string); + + mdoc->next = ROFF_NEXT_CHILD; + if (att != NULL) { + roff_word_alloc(mdoc, nch->line, nch->pos, att); + nch->flags |= NODE_NOPRT; + } else + roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = n; +} + +static void +post_an(POST_ARGS) +{ + struct roff_node *np, *nch; + + post_an_norm(mdoc); + + np = mdoc->last; + nch = np->child; + if (np->norm->An.auth == AUTH__NONE) { + if (nch == NULL) + mandoc_msg(MANDOCERR_MACRO_EMPTY, + np->line, np->pos, "An"); + else + post_delim_nb(mdoc); + } else if (nch != NULL) + mandoc_msg(MANDOCERR_ARG_EXCESS, + nch->line, nch->pos, "An ... %s", nch->string); +} + +static void +post_en(POST_ARGS) +{ + + post_obsolete(mdoc); + if (mdoc->last->type == ROFFT_BLOCK) + mdoc->last->norm->Es = mdoc->last_es; +} + +static void +post_es(POST_ARGS) +{ + + post_obsolete(mdoc); + mdoc->last_es = mdoc->last; +} + +static void +post_xx(POST_ARGS) +{ + struct roff_node *n; + const char *os; + char *v; + + post_delim_nb(mdoc); + + n = mdoc->last; + switch (n->tok) { + case MDOC_Bsx: + os = "BSD/OS"; + break; + case MDOC_Dx: + os = "DragonFly"; + break; + case MDOC_Fx: + os = "FreeBSD"; + break; + case MDOC_Nx: + os = "NetBSD"; + if (n->child == NULL) + break; + v = n->child->string; + if ((v[0] != '0' && v[0] != '1') || v[1] != '.' || + v[2] < '0' || v[2] > '9' || + v[3] < 'a' || v[3] > 'z' || v[4] != '\0') + break; + n->child->flags |= NODE_NOPRT; + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, n->child->line, n->child->pos, v); + v = mdoc->last->string; + v[3] = toupper((unsigned char)v[3]); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = n; + break; + case MDOC_Ox: + os = "OpenBSD"; + break; + case MDOC_Ux: + os = "UNIX"; + break; + default: + abort(); + } + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, n->line, n->pos, os); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = n; +} + +static void +post_it(POST_ARGS) +{ + struct roff_node *nbl, *nit, *nch; + int i, cols; + enum mdoc_list lt; + + post_prevpar(mdoc); + + nit = mdoc->last; + if (nit->type != ROFFT_BLOCK) + return; + + nbl = nit->parent->parent; + lt = nbl->norm->Bl.type; + + switch (lt) { + case LIST_tag: + case LIST_hang: + case LIST_ohang: + case LIST_inset: + case LIST_diag: + if (nit->head->child == NULL) + mandoc_msg(MANDOCERR_IT_NOHEAD, + nit->line, nit->pos, "Bl -%s It", + mdoc_argnames[nbl->args->argv[0].arg]); + break; + case LIST_bullet: + case LIST_dash: + case LIST_enum: + case LIST_hyphen: + if (nit->body == NULL || nit->body->child == NULL) + mandoc_msg(MANDOCERR_IT_NOBODY, + nit->line, nit->pos, "Bl -%s It", + mdoc_argnames[nbl->args->argv[0].arg]); + /* FALLTHROUGH */ + case LIST_item: + if ((nch = nit->head->child) != NULL) + mandoc_msg(MANDOCERR_ARG_SKIP, + nit->line, nit->pos, "It %s", + nch->string == NULL ? roff_name[nch->tok] : + nch->string); + break; + case LIST_column: + cols = (int)nbl->norm->Bl.ncols; + + assert(nit->head->child == NULL); + + if (nit->head->next->child == NULL && + nit->head->next->next == NULL) { + mandoc_msg(MANDOCERR_MACRO_EMPTY, + nit->line, nit->pos, "It"); + roff_node_delete(mdoc, nit); + break; + } + + i = 0; + for (nch = nit->child; nch != NULL; nch = nch->next) { + if (nch->type != ROFFT_BODY) + continue; + if (i++ && nch->flags & NODE_LINE) + mandoc_msg(MANDOCERR_TA_LINE, + nch->line, nch->pos, "Ta"); + } + if (i < cols || i > cols + 1) + mandoc_msg(MANDOCERR_BL_COL, nit->line, nit->pos, + "%d columns, %d cells", cols, i); + else if (nit->head->next->child != NULL && + nit->head->next->child->flags & NODE_LINE) + mandoc_msg(MANDOCERR_IT_NOARG, + nit->line, nit->pos, "Bl -column It"); + break; + default: + abort(); + } +} + +static void +post_bl_block(POST_ARGS) +{ + struct roff_node *n, *ni, *nc; + + post_prevpar(mdoc); + + n = mdoc->last; + for (ni = n->body->child; ni != NULL; ni = ni->next) { + if (ni->body == NULL) + continue; + nc = ni->body->last; + while (nc != NULL) { + switch (nc->tok) { + case MDOC_Pp: + case ROFF_br: + break; + default: + nc = NULL; + continue; + } + if (ni->next == NULL) { + mandoc_msg(MANDOCERR_PAR_MOVE, nc->line, + nc->pos, "%s", roff_name[nc->tok]); + roff_node_relink(mdoc, nc); + } else if (n->norm->Bl.comp == 0 && + n->norm->Bl.type != LIST_column) { + mandoc_msg(MANDOCERR_PAR_SKIP, + nc->line, nc->pos, + "%s before It", roff_name[nc->tok]); + roff_node_delete(mdoc, nc); + } else + break; + nc = ni->body->last; + } + } +} + +/* + * If the argument of -offset or -width is a macro, + * replace it with the associated default width. + */ +static void +rewrite_macro2len(struct roff_man *mdoc, char **arg) +{ + size_t width; + enum roff_tok tok; + + if (*arg == NULL) + return; + else if ( ! strcmp(*arg, "Ds")) + width = 6; + else if ((tok = roffhash_find(mdoc->mdocmac, *arg, 0)) == TOKEN_NONE) + return; + else + width = macro2len(tok); + + free(*arg); + mandoc_asprintf(arg, "%zun", width); +} + +static void +post_bl_head(POST_ARGS) +{ + struct roff_node *nbl, *nh, *nch, *nnext; + struct mdoc_argv *argv; + int i, j; + + post_bl_norm(mdoc); + + nh = mdoc->last; + if (nh->norm->Bl.type != LIST_column) { + if ((nch = nh->child) == NULL) + return; + mandoc_msg(MANDOCERR_ARG_EXCESS, + nch->line, nch->pos, "Bl ... %s", nch->string); + while (nch != NULL) { + roff_node_delete(mdoc, nch); + nch = nh->child; + } + return; + } + + /* + * Append old-style lists, where the column width specifiers + * trail as macro parameters, to the new-style ("normal-form") + * lists where they're argument values following -column. + */ + + if (nh->child == NULL) + return; + + nbl = nh->parent; + for (j = 0; j < (int)nbl->args->argc; j++) + if (nbl->args->argv[j].arg == MDOC_Column) + break; + + assert(j < (int)nbl->args->argc); + + /* + * Accommodate for new-style groff column syntax. Shuffle the + * child nodes, all of which must be TEXT, as arguments for the + * column field. Then, delete the head children. + */ + + argv = nbl->args->argv + j; + i = argv->sz; + for (nch = nh->child; nch != NULL; nch = nch->next) + argv->sz++; + argv->value = mandoc_reallocarray(argv->value, + argv->sz, sizeof(char *)); + + nh->norm->Bl.ncols = argv->sz; + nh->norm->Bl.cols = (void *)argv->value; + + for (nch = nh->child; nch != NULL; nch = nnext) { + argv->value[i++] = nch->string; + nch->string = NULL; + nnext = nch->next; + roff_node_delete(NULL, nch); + } + nh->child = NULL; +} + +static void +post_bl(POST_ARGS) +{ + struct roff_node *nparent, *nprev; /* of the Bl block */ + struct roff_node *nblock, *nbody; /* of the Bl */ + struct roff_node *nchild, *nnext; /* of the Bl body */ + const char *prev_Er; + int order; + + nbody = mdoc->last; + switch (nbody->type) { + case ROFFT_BLOCK: + post_bl_block(mdoc); + return; + case ROFFT_HEAD: + post_bl_head(mdoc); + return; + case ROFFT_BODY: + break; + default: + return; + } + if (nbody->end != ENDBODY_NOT) + return; + + nchild = nbody->child; + if (nchild == NULL) { + mandoc_msg(MANDOCERR_BLK_EMPTY, + nbody->line, nbody->pos, "Bl"); + return; + } + while (nchild != NULL) { + nnext = nchild->next; + if (nchild->tok == MDOC_It || + (nchild->tok == MDOC_Sm && + nnext != NULL && nnext->tok == MDOC_It)) { + nchild = nnext; + continue; + } + + /* + * In .Bl -column, the first rows may be implicit, + * that is, they may not start with .It macros. + * Such rows may be followed by nodes generated on the + * roff level, for example .TS, which cannot be moved + * out of the list. In that case, wrap such roff nodes + * into an implicit row. + */ + + if (nchild->prev != NULL) { + mdoc->last = nchild; + mdoc->next = ROFF_NEXT_SIBLING; + roff_block_alloc(mdoc, nchild->line, + nchild->pos, MDOC_It); + roff_head_alloc(mdoc, nchild->line, + nchild->pos, MDOC_It); + mdoc->next = ROFF_NEXT_SIBLING; + roff_body_alloc(mdoc, nchild->line, + nchild->pos, MDOC_It); + while (nchild->tok != MDOC_It) { + roff_node_relink(mdoc, nchild); + if ((nchild = nnext) == NULL) + break; + nnext = nchild->next; + mdoc->next = ROFF_NEXT_SIBLING; + } + mdoc->last = nbody; + continue; + } + + mandoc_msg(MANDOCERR_BL_MOVE, nchild->line, nchild->pos, + "%s", roff_name[nchild->tok]); + + /* + * Move the node out of the Bl block. + * First, collect all required node pointers. + */ + + nblock = nbody->parent; + nprev = nblock->prev; + nparent = nblock->parent; + + /* + * Unlink this child. + */ + + nbody->child = nnext; + if (nnext == NULL) + nbody->last = NULL; + else + nnext->prev = NULL; + + /* + * Relink this child. + */ + + nchild->parent = nparent; + nchild->prev = nprev; + nchild->next = nblock; + + nblock->prev = nchild; + if (nprev == NULL) + nparent->child = nchild; + else + nprev->next = nchild; + + nchild = nnext; + } + + if (mdoc->meta.os_e != MANDOC_OS_NETBSD) + return; + + prev_Er = NULL; + for (nchild = nbody->child; nchild != NULL; nchild = nchild->next) { + if (nchild->tok != MDOC_It) + continue; + if ((nnext = nchild->head->child) == NULL) + continue; + if (nnext->type == ROFFT_BLOCK) + nnext = nnext->body->child; + if (nnext == NULL || nnext->tok != MDOC_Er) + continue; + nnext = nnext->child; + if (prev_Er != NULL) { + order = strcmp(prev_Er, nnext->string); + if (order > 0) + mandoc_msg(MANDOCERR_ER_ORDER, + nnext->line, nnext->pos, + "Er %s %s (NetBSD)", + prev_Er, nnext->string); + else if (order == 0) + mandoc_msg(MANDOCERR_ER_REP, + nnext->line, nnext->pos, + "Er %s (NetBSD)", prev_Er); + } + prev_Er = nnext->string; + } +} + +static void +post_bk(POST_ARGS) +{ + struct roff_node *n; + + n = mdoc->last; + + if (n->type == ROFFT_BLOCK && n->body->child == NULL) { + mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, "Bk"); + roff_node_delete(mdoc, n); + } +} + +static void +post_sm(POST_ARGS) +{ + struct roff_node *nch; + + nch = mdoc->last->child; + + if (nch == NULL) { + mdoc->flags ^= MDOC_SMOFF; + return; + } + + assert(nch->type == ROFFT_TEXT); + + if ( ! strcmp(nch->string, "on")) { + mdoc->flags &= ~MDOC_SMOFF; + return; + } + if ( ! strcmp(nch->string, "off")) { + mdoc->flags |= MDOC_SMOFF; + return; + } + + mandoc_msg(MANDOCERR_SM_BAD, nch->line, nch->pos, + "%s %s", roff_name[mdoc->last->tok], nch->string); + roff_node_relink(mdoc, nch); + return; +} + +static void +post_root(POST_ARGS) +{ + struct roff_node *n; + + /* Add missing prologue data. */ + + if (mdoc->meta.date == NULL) + mdoc->meta.date = mandoc_normdate(mdoc, NULL, 0, 0); + + if (mdoc->meta.title == NULL) { + mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF"); + mdoc->meta.title = mandoc_strdup("UNTITLED"); + } + + if (mdoc->meta.vol == NULL) + mdoc->meta.vol = mandoc_strdup("LOCAL"); + + if (mdoc->meta.os == NULL) { + mandoc_msg(MANDOCERR_OS_MISSING, 0, 0, NULL); + mdoc->meta.os = mandoc_strdup(""); + } else if (mdoc->meta.os_e && + (mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0) + mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0, + mdoc->meta.os_e == MANDOC_OS_OPENBSD ? + "(OpenBSD)" : "(NetBSD)"); + + if (mdoc->meta.arch != NULL && + arch_valid(mdoc->meta.arch, mdoc->meta.os_e) == 0) { + n = mdoc->meta.first->child; + while (n->tok != MDOC_Dt || + n->child == NULL || + n->child->next == NULL || + n->child->next->next == NULL) + n = n->next; + n = n->child->next->next; + mandoc_msg(MANDOCERR_ARCH_BAD, n->line, n->pos, + "Dt ... %s %s", mdoc->meta.arch, + mdoc->meta.os_e == MANDOC_OS_OPENBSD ? + "(OpenBSD)" : "(NetBSD)"); + } + + /* Check that we begin with a proper `Sh'. */ + + n = mdoc->meta.first->child; + while (n != NULL && + (n->type == ROFFT_COMMENT || + (n->tok >= MDOC_Dd && + mdoc_macro(n->tok)->flags & MDOC_PROLOGUE))) + n = n->next; + + if (n == NULL) + mandoc_msg(MANDOCERR_DOC_EMPTY, 0, 0, NULL); + else if (n->tok != MDOC_Sh) + mandoc_msg(MANDOCERR_SEC_BEFORE, n->line, n->pos, + "%s", roff_name[n->tok]); +} + +static void +post_rs(POST_ARGS) +{ + struct roff_node *np, *nch, *next, *prev; + int i, j; + + np = mdoc->last; + + if (np->type != ROFFT_BODY) + return; + + if (np->child == NULL) { + mandoc_msg(MANDOCERR_RS_EMPTY, np->line, np->pos, "Rs"); + return; + } + + /* + * The full `Rs' block needs special handling to order the + * sub-elements according to `rsord'. Pick through each element + * and correctly order it. This is an insertion sort. + */ + + next = NULL; + for (nch = np->child->next; nch != NULL; nch = next) { + /* Determine order number of this child. */ + for (i = 0; i < RSORD_MAX; i++) + if (rsord[i] == nch->tok) + break; + + if (i == RSORD_MAX) { + mandoc_msg(MANDOCERR_RS_BAD, nch->line, nch->pos, + "%s", roff_name[nch->tok]); + i = -1; + } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) + np->norm->Rs.quote_T++; + + /* + * Remove this child from the chain. This somewhat + * repeats roff_node_unlink(), but since we're + * just re-ordering, there's no need for the + * full unlink process. + */ + + if ((next = nch->next) != NULL) + next->prev = nch->prev; + + if ((prev = nch->prev) != NULL) + prev->next = nch->next; + + nch->prev = nch->next = NULL; + + /* + * Scan back until we reach a node that's + * to be ordered before this child. + */ + + for ( ; prev ; prev = prev->prev) { + /* Determine order of `prev'. */ + for (j = 0; j < RSORD_MAX; j++) + if (rsord[j] == prev->tok) + break; + if (j == RSORD_MAX) + j = -1; + + if (j <= i) + break; + } + + /* + * Set this child back into its correct place + * in front of the `prev' node. + */ + + nch->prev = prev; + + if (prev == NULL) { + np->child->prev = nch; + nch->next = np->child; + np->child = nch; + } else { + if (prev->next) + prev->next->prev = nch; + nch->next = prev->next; + prev->next = nch; + } + } +} + +/* + * For some arguments of some macros, + * convert all breakable hyphens into ASCII_HYPH. + */ +static void +post_hyph(POST_ARGS) +{ + struct roff_node *nch; + char *cp; + + for (nch = mdoc->last->child; nch != NULL; nch = nch->next) { + if (nch->type != ROFFT_TEXT) + continue; + cp = nch->string; + if (*cp == '\0') + continue; + while (*(++cp) != '\0') + if (*cp == '-' && + isalpha((unsigned char)cp[-1]) && + isalpha((unsigned char)cp[1])) + *cp = ASCII_HYPH; + } +} + +static void +post_ns(POST_ARGS) +{ + struct roff_node *n; + + n = mdoc->last; + if (n->flags & NODE_LINE || + (n->next != NULL && n->next->flags & NODE_DELIMC)) + mandoc_msg(MANDOCERR_NS_SKIP, n->line, n->pos, NULL); +} + +static void +post_sx(POST_ARGS) +{ + post_delim(mdoc); + post_hyph(mdoc); +} + +static void +post_sh(POST_ARGS) +{ + + post_ignpar(mdoc); + + switch (mdoc->last->type) { + case ROFFT_HEAD: + post_sh_head(mdoc); + break; + case ROFFT_BODY: + switch (mdoc->lastsec) { + case SEC_NAME: + post_sh_name(mdoc); + break; + case SEC_SEE_ALSO: + post_sh_see_also(mdoc); + break; + case SEC_AUTHORS: + post_sh_authors(mdoc); + break; + default: + break; + } + break; + default: + break; + } +} + +static void +post_sh_name(POST_ARGS) +{ + struct roff_node *n; + int hasnm, hasnd; + + hasnm = hasnd = 0; + + for (n = mdoc->last->child; n != NULL; n = n->next) { + switch (n->tok) { + case MDOC_Nm: + if (hasnm && n->child != NULL) + mandoc_msg(MANDOCERR_NAMESEC_PUNCT, + n->line, n->pos, + "Nm %s", n->child->string); + hasnm = 1; + continue; + case MDOC_Nd: + hasnd = 1; + if (n->next != NULL) + mandoc_msg(MANDOCERR_NAMESEC_ND, + n->line, n->pos, NULL); + break; + case TOKEN_NONE: + if (n->type == ROFFT_TEXT && + n->string[0] == ',' && n->string[1] == '\0' && + n->next != NULL && n->next->tok == MDOC_Nm) { + n = n->next; + continue; + } + /* FALLTHROUGH */ + default: + mandoc_msg(MANDOCERR_NAMESEC_BAD, + n->line, n->pos, "%s", roff_name[n->tok]); + continue; + } + break; + } + + if ( ! hasnm) + mandoc_msg(MANDOCERR_NAMESEC_NONM, + mdoc->last->line, mdoc->last->pos, NULL); + if ( ! hasnd) + mandoc_msg(MANDOCERR_NAMESEC_NOND, + mdoc->last->line, mdoc->last->pos, NULL); +} + +static void +post_sh_see_also(POST_ARGS) +{ + const struct roff_node *n; + const char *name, *sec; + const char *lastname, *lastsec, *lastpunct; + int cmp; + + n = mdoc->last->child; + lastname = lastsec = lastpunct = NULL; + while (n != NULL) { + if (n->tok != MDOC_Xr || + n->child == NULL || + n->child->next == NULL) + break; + + /* Process one .Xr node. */ + + name = n->child->string; + sec = n->child->next->string; + if (lastsec != NULL) { + if (lastpunct[0] != ',' || lastpunct[1] != '\0') + mandoc_msg(MANDOCERR_XR_PUNCT, n->line, + n->pos, "%s before %s(%s)", + lastpunct, name, sec); + cmp = strcmp(lastsec, sec); + if (cmp > 0) + mandoc_msg(MANDOCERR_XR_ORDER, n->line, + n->pos, "%s(%s) after %s(%s)", + name, sec, lastname, lastsec); + else if (cmp == 0 && + strcasecmp(lastname, name) > 0) + mandoc_msg(MANDOCERR_XR_ORDER, n->line, + n->pos, "%s after %s", name, lastname); + } + lastname = name; + lastsec = sec; + + /* Process the following node. */ + + n = n->next; + if (n == NULL) + break; + if (n->tok == MDOC_Xr) { + lastpunct = "none"; + continue; + } + if (n->type != ROFFT_TEXT) + break; + for (name = n->string; *name != '\0'; name++) + if (isalpha((const unsigned char)*name)) + return; + lastpunct = n->string; + if (n->next == NULL || n->next->tok == MDOC_Rs) + mandoc_msg(MANDOCERR_XR_PUNCT, n->line, + n->pos, "%s after %s(%s)", + lastpunct, lastname, lastsec); + n = n->next; + } +} + +static int +child_an(const struct roff_node *n) +{ + + for (n = n->child; n != NULL; n = n->next) + if ((n->tok == MDOC_An && n->child != NULL) || child_an(n)) + return 1; + return 0; +} + +static void +post_sh_authors(POST_ARGS) +{ + + if ( ! child_an(mdoc->last)) + mandoc_msg(MANDOCERR_AN_MISSING, + mdoc->last->line, mdoc->last->pos, NULL); +} + +/* + * Return an upper bound for the string distance (allowing + * transpositions). Not a full Levenshtein implementation + * because Levenshtein is quadratic in the string length + * and this function is called for every standard name, + * so the check for each custom name would be cubic. + * The following crude heuristics is linear, resulting + * in quadratic behaviour for checking one custom name, + * which does not cause measurable slowdown. + */ +static int +similar(const char *s1, const char *s2) +{ + const int maxdist = 3; + int dist = 0; + + while (s1[0] != '\0' && s2[0] != '\0') { + if (s1[0] == s2[0]) { + s1++; + s2++; + continue; + } + if (++dist > maxdist) + return INT_MAX; + if (s1[1] == s2[1]) { /* replacement */ + s1++; + s2++; + } else if (s1[0] == s2[1] && s1[1] == s2[0]) { + s1 += 2; /* transposition */ + s2 += 2; + } else if (s1[0] == s2[1]) /* insertion */ + s2++; + else if (s1[1] == s2[0]) /* deletion */ + s1++; + else + return INT_MAX; + } + dist += strlen(s1) + strlen(s2); + return dist > maxdist ? INT_MAX : dist; +} + +static void +post_sh_head(POST_ARGS) +{ + struct roff_node *nch; + const char *goodsec; + const char *const *testsec; + int dist, mindist; + enum roff_sec sec; + + /* + * Process a new section. Sections are either "named" or + * "custom". Custom sections are user-defined, while named ones + * follow a conventional order and may only appear in certain + * manual sections. + */ + + sec = mdoc->last->sec; + + /* The NAME should be first. */ + + if (sec != SEC_NAME && mdoc->lastnamed == SEC_NONE) + mandoc_msg(MANDOCERR_NAMESEC_FIRST, + mdoc->last->line, mdoc->last->pos, "Sh %s", + sec != SEC_CUSTOM ? secnames[sec] : + (nch = mdoc->last->child) == NULL ? "" : + nch->type == ROFFT_TEXT ? nch->string : + roff_name[nch->tok]); + + /* The SYNOPSIS gets special attention in other areas. */ + + if (sec == SEC_SYNOPSIS) { + roff_setreg(mdoc->roff, "nS", 1, '='); + mdoc->flags |= MDOC_SYNOPSIS; + } else { + roff_setreg(mdoc->roff, "nS", 0, '='); + mdoc->flags &= ~MDOC_SYNOPSIS; + } + + /* Mark our last section. */ + + mdoc->lastsec = sec; + + /* We don't care about custom sections after this. */ + + if (sec == SEC_CUSTOM) { + if ((nch = mdoc->last->child) == NULL || + nch->type != ROFFT_TEXT || nch->next != NULL) + return; + goodsec = NULL; + mindist = INT_MAX; + for (testsec = secnames + 1; *testsec != NULL; testsec++) { + dist = similar(nch->string, *testsec); + if (dist < mindist) { + goodsec = *testsec; + mindist = dist; + } + } + if (goodsec != NULL) + mandoc_msg(MANDOCERR_SEC_TYPO, nch->line, nch->pos, + "Sh %s instead of %s", nch->string, goodsec); + return; + } + + /* + * Check whether our non-custom section is being repeated or is + * out of order. + */ + + if (sec == mdoc->lastnamed) + mandoc_msg(MANDOCERR_SEC_REP, mdoc->last->line, + mdoc->last->pos, "Sh %s", secnames[sec]); + + if (sec < mdoc->lastnamed) + mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->last->line, + mdoc->last->pos, "Sh %s", secnames[sec]); + + /* Mark the last named section. */ + + mdoc->lastnamed = sec; + + /* Check particular section/manual conventions. */ + + if (mdoc->meta.msec == NULL) + return; + + goodsec = NULL; + switch (sec) { + case SEC_ERRORS: + if (*mdoc->meta.msec == '4') + break; + goodsec = "2, 3, 4, 9"; + /* FALLTHROUGH */ + case SEC_RETURN_VALUES: + case SEC_LIBRARY: + if (*mdoc->meta.msec == '2') + break; + if (*mdoc->meta.msec == '3') + break; + if (NULL == goodsec) + goodsec = "2, 3, 9"; + /* FALLTHROUGH */ + case SEC_CONTEXT: + if (*mdoc->meta.msec == '9') + break; + if (NULL == goodsec) + goodsec = "9"; + mandoc_msg(MANDOCERR_SEC_MSEC, + mdoc->last->line, mdoc->last->pos, + "Sh %s for %s only", secnames[sec], goodsec); + break; + default: + break; + } +} + +static void +post_xr(POST_ARGS) +{ + struct roff_node *n, *nch; + + n = mdoc->last; + nch = n->child; + if (nch->next == NULL) { + mandoc_msg(MANDOCERR_XR_NOSEC, + n->line, n->pos, "Xr %s", nch->string); + } else { + assert(nch->next == n->last); + if(mandoc_xr_add(nch->next->string, nch->string, + nch->line, nch->pos)) + mandoc_msg(MANDOCERR_XR_SELF, + nch->line, nch->pos, "Xr %s %s", + nch->string, nch->next->string); + } + post_delim_nb(mdoc); +} + +static void +post_ignpar(POST_ARGS) +{ + struct roff_node *np; + + switch (mdoc->last->type) { + case ROFFT_BLOCK: + post_prevpar(mdoc); + return; + case ROFFT_HEAD: + post_delim(mdoc); + post_hyph(mdoc); + return; + case ROFFT_BODY: + break; + default: + return; + } + + if ((np = mdoc->last->child) != NULL) + if (np->tok == MDOC_Pp || + np->tok == ROFF_br || np->tok == ROFF_sp) { + mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, + "%s after %s", roff_name[np->tok], + roff_name[mdoc->last->tok]); + roff_node_delete(mdoc, np); + } + + if ((np = mdoc->last->last) != NULL) + if (np->tok == MDOC_Pp || np->tok == ROFF_br) { + mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, + "%s at the end of %s", roff_name[np->tok], + roff_name[mdoc->last->tok]); + roff_node_delete(mdoc, np); + } +} + +static void +post_prevpar(POST_ARGS) +{ + struct roff_node *n; + + n = mdoc->last; + if (NULL == n->prev) + return; + if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) + return; + + /* + * Don't allow `Pp' prior to a paragraph-type + * block: `Pp' or non-compact `Bd' or `Bl'. + */ + + if (n->prev->tok != MDOC_Pp && n->prev->tok != ROFF_br) + return; + if (n->tok == MDOC_Bl && n->norm->Bl.comp) + return; + if (n->tok == MDOC_Bd && n->norm->Bd.comp) + return; + if (n->tok == MDOC_It && n->parent->norm->Bl.comp) + return; + + mandoc_msg(MANDOCERR_PAR_SKIP, n->prev->line, n->prev->pos, + "%s before %s", roff_name[n->prev->tok], roff_name[n->tok]); + roff_node_delete(mdoc, n->prev); +} + +static void +post_par(POST_ARGS) +{ + struct roff_node *np; + + post_prevpar(mdoc); + + np = mdoc->last; + if (np->child != NULL) + mandoc_msg(MANDOCERR_ARG_SKIP, np->line, np->pos, + "%s %s", roff_name[np->tok], np->child->string); +} + +static void +post_dd(POST_ARGS) +{ + struct roff_node *n; + char *datestr; + + n = mdoc->last; + n->flags |= NODE_NOPRT; + + if (mdoc->meta.date != NULL) { + mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Dd"); + free(mdoc->meta.date); + } else if (mdoc->flags & MDOC_PBODY) + mandoc_msg(MANDOCERR_PROLOG_LATE, n->line, n->pos, "Dd"); + else if (mdoc->meta.title != NULL) + mandoc_msg(MANDOCERR_PROLOG_ORDER, + n->line, n->pos, "Dd after Dt"); + else if (mdoc->meta.os != NULL) + mandoc_msg(MANDOCERR_PROLOG_ORDER, + n->line, n->pos, "Dd after Os"); + + datestr = NULL; + deroff(&datestr, n); + mdoc->meta.date = mandoc_normdate(mdoc, datestr, n->line, n->pos); + free(datestr); +} + +static void +post_dt(POST_ARGS) +{ + struct roff_node *nn, *n; + const char *cp; + char *p; + + n = mdoc->last; + n->flags |= NODE_NOPRT; + + if (mdoc->flags & MDOC_PBODY) { + mandoc_msg(MANDOCERR_DT_LATE, n->line, n->pos, "Dt"); + return; + } + + if (mdoc->meta.title != NULL) + mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Dt"); + else if (mdoc->meta.os != NULL) + mandoc_msg(MANDOCERR_PROLOG_ORDER, + n->line, n->pos, "Dt after Os"); + + free(mdoc->meta.title); + free(mdoc->meta.msec); + free(mdoc->meta.vol); + free(mdoc->meta.arch); + + mdoc->meta.title = NULL; + mdoc->meta.msec = NULL; + mdoc->meta.vol = NULL; + mdoc->meta.arch = NULL; + + /* Mandatory first argument: title. */ + + nn = n->child; + if (nn == NULL || *nn->string == '\0') { + mandoc_msg(MANDOCERR_DT_NOTITLE, n->line, n->pos, "Dt"); + mdoc->meta.title = mandoc_strdup("UNTITLED"); + } else { + mdoc->meta.title = mandoc_strdup(nn->string); + + /* Check that all characters are uppercase. */ + + for (p = nn->string; *p != '\0'; p++) + if (islower((unsigned char)*p)) { + mandoc_msg(MANDOCERR_TITLE_CASE, nn->line, + nn->pos + (int)(p - nn->string), + "Dt %s", nn->string); + break; + } + } + + /* Mandatory second argument: section. */ + + if (nn != NULL) + nn = nn->next; + + if (nn == NULL) { + mandoc_msg(MANDOCERR_MSEC_MISSING, n->line, n->pos, + "Dt %s", mdoc->meta.title); + mdoc->meta.vol = mandoc_strdup("LOCAL"); + return; /* msec and arch remain NULL. */ + } + + mdoc->meta.msec = mandoc_strdup(nn->string); + + /* Infer volume title from section number. */ + + cp = mandoc_a2msec(nn->string); + if (cp == NULL) { + mandoc_msg(MANDOCERR_MSEC_BAD, + nn->line, nn->pos, "Dt ... %s", nn->string); + mdoc->meta.vol = mandoc_strdup(nn->string); + } else + mdoc->meta.vol = mandoc_strdup(cp); + + /* Optional third argument: architecture. */ + + if ((nn = nn->next) == NULL) + return; + + for (p = nn->string; *p != '\0'; p++) + *p = tolower((unsigned char)*p); + mdoc->meta.arch = mandoc_strdup(nn->string); + + /* Ignore fourth and later arguments. */ + + if ((nn = nn->next) != NULL) + mandoc_msg(MANDOCERR_ARG_EXCESS, + nn->line, nn->pos, "Dt ... %s", nn->string); +} + +static void +post_bx(POST_ARGS) +{ + struct roff_node *n, *nch; + const char *macro; + + post_delim_nb(mdoc); + + n = mdoc->last; + nch = n->child; + + if (nch != NULL) { + macro = !strcmp(nch->string, "Open") ? "Ox" : + !strcmp(nch->string, "Net") ? "Nx" : + !strcmp(nch->string, "Free") ? "Fx" : + !strcmp(nch->string, "DragonFly") ? "Dx" : NULL; + if (macro != NULL) + mandoc_msg(MANDOCERR_BX, + n->line, n->pos, "%s", macro); + mdoc->last = nch; + nch = nch->next; + mdoc->next = ROFF_NEXT_SIBLING; + roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); + mdoc->last->flags |= NODE_NOSRC; + mdoc->next = ROFF_NEXT_SIBLING; + } else + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, n->line, n->pos, "BSD"); + mdoc->last->flags |= NODE_NOSRC; + + if (nch == NULL) { + mdoc->last = n; + return; + } + + roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); + mdoc->last->flags |= NODE_NOSRC; + mdoc->next = ROFF_NEXT_SIBLING; + roff_word_alloc(mdoc, n->line, n->pos, "-"); + mdoc->last->flags |= NODE_NOSRC; + roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = n; + + /* + * Make `Bx's second argument always start with an uppercase + * letter. Groff checks if it's an "accepted" term, but we just + * uppercase blindly. + */ + + *nch->string = (char)toupper((unsigned char)*nch->string); +} + +static void +post_os(POST_ARGS) +{ +#ifndef OSNAME + struct utsname utsname; + static char *defbuf; +#endif + struct roff_node *n; + + n = mdoc->last; + n->flags |= NODE_NOPRT; + + if (mdoc->meta.os != NULL) + mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Os"); + else if (mdoc->flags & MDOC_PBODY) + mandoc_msg(MANDOCERR_PROLOG_LATE, n->line, n->pos, "Os"); + + post_delim(mdoc); + + /* + * Set the operating system by way of the `Os' macro. + * The order of precedence is: + * 1. the argument of the `Os' macro, unless empty + * 2. the -Ios=foo command line argument, if provided + * 3. -DOSNAME="\"foo\"", if provided during compilation + * 4. "sysname release" from uname(3) + */ + + free(mdoc->meta.os); + mdoc->meta.os = NULL; + deroff(&mdoc->meta.os, n); + if (mdoc->meta.os) + goto out; + + if (mdoc->os_s != NULL) { + mdoc->meta.os = mandoc_strdup(mdoc->os_s); + goto out; + } + +#ifdef OSNAME + mdoc->meta.os = mandoc_strdup(OSNAME); +#else /*!OSNAME */ + if (defbuf == NULL) { + if (uname(&utsname) == -1) { + mandoc_msg(MANDOCERR_OS_UNAME, n->line, n->pos, "Os"); + defbuf = mandoc_strdup("UNKNOWN"); + } else + mandoc_asprintf(&defbuf, "%s %s", + utsname.sysname, utsname.release); + } + mdoc->meta.os = mandoc_strdup(defbuf); +#endif /*!OSNAME*/ + +out: + if (mdoc->meta.os_e == MANDOC_OS_OTHER) { + if (strstr(mdoc->meta.os, "OpenBSD") != NULL) + mdoc->meta.os_e = MANDOC_OS_OPENBSD; + else if (strstr(mdoc->meta.os, "NetBSD") != NULL) + mdoc->meta.os_e = MANDOC_OS_NETBSD; + } + + /* + * This is the earliest point where we can check + * Mdocdate conventions because we don't know + * the operating system earlier. + */ + + if (n->child != NULL) + mandoc_msg(MANDOCERR_OS_ARG, n->child->line, n->child->pos, + "Os %s (%s)", n->child->string, + mdoc->meta.os_e == MANDOC_OS_OPENBSD ? + "OpenBSD" : "NetBSD"); + + while (n->tok != MDOC_Dd) + if ((n = n->prev) == NULL) + return; + if ((n = n->child) == NULL) + return; + if (strncmp(n->string, "$" "Mdocdate", 9)) { + if (mdoc->meta.os_e == MANDOC_OS_OPENBSD) + mandoc_msg(MANDOCERR_MDOCDATE_MISSING, n->line, + n->pos, "Dd %s (OpenBSD)", n->string); + } else { + if (mdoc->meta.os_e == MANDOC_OS_NETBSD) + mandoc_msg(MANDOCERR_MDOCDATE, n->line, + n->pos, "Dd %s (NetBSD)", n->string); + } +} + +enum roff_sec +mdoc_a2sec(const char *p) +{ + int i; + + for (i = 0; i < (int)SEC__MAX; i++) + if (secnames[i] && 0 == strcmp(p, secnames[i])) + return (enum roff_sec)i; + + return SEC_CUSTOM; +} + +static size_t +macro2len(enum roff_tok macro) +{ + + switch (macro) { + case MDOC_Ad: + return 12; + case MDOC_Ao: + return 12; + case MDOC_An: + return 12; + case MDOC_Aq: + return 12; + case MDOC_Ar: + return 12; + case MDOC_Bo: + return 12; + case MDOC_Bq: + return 12; + case MDOC_Cd: + return 12; + case MDOC_Cm: + return 10; + case MDOC_Do: + return 10; + case MDOC_Dq: + return 12; + case MDOC_Dv: + return 12; + case MDOC_Eo: + return 12; + case MDOC_Em: + return 10; + case MDOC_Er: + return 17; + case MDOC_Ev: + return 15; + case MDOC_Fa: + return 12; + case MDOC_Fl: + return 10; + case MDOC_Fo: + return 16; + case MDOC_Fn: + return 16; + case MDOC_Ic: + return 10; + case MDOC_Li: + return 16; + case MDOC_Ms: + return 6; + case MDOC_Nm: + return 10; + case MDOC_No: + return 12; + case MDOC_Oo: + return 10; + case MDOC_Op: + return 14; + case MDOC_Pa: + return 32; + case MDOC_Pf: + return 12; + case MDOC_Po: + return 12; + case MDOC_Pq: + return 12; + case MDOC_Ql: + return 16; + case MDOC_Qo: + return 12; + case MDOC_So: + return 12; + case MDOC_Sq: + return 12; + case MDOC_Sy: + return 6; + case MDOC_Sx: + return 16; + case MDOC_Tn: + return 10; + case MDOC_Va: + return 12; + case MDOC_Vt: + return 12; + case MDOC_Xr: + return 10; + default: + break; + }; + return 0; +} Property changes on: vendor/mandoc/20190723/mdoc_validate.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/out.c =================================================================== --- vendor/mandoc/20190723/out.c (nonexistent) +++ vendor/mandoc/20190723/out.c (revision 350350) @@ -0,0 +1,553 @@ +/* $Id: out.c,v 1.78 2019/03/29 21:27:06 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "tbl.h" +#include "out.h" + +struct tbl_colgroup { + struct tbl_colgroup *next; + size_t wanted; + int startcol; + int endcol; +}; + +static size_t tblcalc_data(struct rofftbl *, struct roffcol *, + const struct tbl_opts *, const struct tbl_dat *, + size_t); +static size_t tblcalc_literal(struct rofftbl *, struct roffcol *, + const struct tbl_dat *, size_t); +static size_t tblcalc_number(struct rofftbl *, struct roffcol *, + const struct tbl_opts *, const struct tbl_dat *); + + +/* + * Parse the *src string and store a scaling unit into *dst. + * If the string doesn't specify the unit, use the default. + * If no default is specified, fail. + * Return a pointer to the byte after the last byte used, + * or NULL on total failure. + */ +const char * +a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) +{ + char *endptr; + + dst->unit = def == SCALE_MAX ? SCALE_BU : def; + dst->scale = strtod(src, &endptr); + if (endptr == src) + return NULL; + + switch (*endptr++) { + case 'c': + dst->unit = SCALE_CM; + break; + case 'i': + dst->unit = SCALE_IN; + break; + case 'f': + dst->unit = SCALE_FS; + break; + case 'M': + dst->unit = SCALE_MM; + break; + case 'm': + dst->unit = SCALE_EM; + break; + case 'n': + dst->unit = SCALE_EN; + break; + case 'P': + dst->unit = SCALE_PC; + break; + case 'p': + dst->unit = SCALE_PT; + break; + case 'u': + dst->unit = SCALE_BU; + break; + case 'v': + dst->unit = SCALE_VS; + break; + default: + endptr--; + if (SCALE_MAX == def) + return NULL; + dst->unit = def; + break; + } + return endptr; +} + +/* + * Calculate the abstract widths and decimal positions of columns in a + * table. This routine allocates the columns structures then runs over + * all rows and cells in the table. The function pointers in "tbl" are + * used for the actual width calculations. + */ +void +tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first, + size_t offset, size_t rmargin) +{ + struct roffsu su; + const struct tbl_opts *opts; + const struct tbl_span *sp; + const struct tbl_dat *dp; + struct roffcol *col; + struct tbl_colgroup *first_group, **gp, *g; + size_t *colwidth; + size_t ewidth, min1, min2, wanted, width, xwidth; + int done, icol, maxcol, necol, nxcol, quirkcol; + + /* + * Allocate the master column specifiers. These will hold the + * widths and decimal positions for all cells in the column. It + * must be freed and nullified by the caller. + */ + + assert(tbl->cols == NULL); + tbl->cols = mandoc_calloc((size_t)sp_first->opts->cols, + sizeof(struct roffcol)); + opts = sp_first->opts; + + maxcol = -1; + first_group = NULL; + for (sp = sp_first; sp != NULL; sp = sp->next) { + if (sp->pos != TBL_SPAN_DATA) + continue; + + /* + * Account for the data cells in the layout, matching it + * to data cells in the data section. + */ + + gp = &first_group; + for (dp = sp->first; dp != NULL; dp = dp->next) { + icol = dp->layout->col; + while (maxcol < icol + dp->hspans) + tbl->cols[++maxcol].spacing = SIZE_MAX; + col = tbl->cols + icol; + col->flags |= dp->layout->flags; + if (dp->layout->flags & TBL_CELL_WIGN) + continue; + + /* Handle explicit width specifications. */ + + if (dp->layout->wstr != NULL && + dp->layout->width == 0 && + a2roffsu(dp->layout->wstr, &su, SCALE_EN) + != NULL) + dp->layout->width = + (*tbl->sulen)(&su, tbl->arg); + if (col->width < dp->layout->width) + col->width = dp->layout->width; + if (dp->layout->spacing != SIZE_MAX && + (col->spacing == SIZE_MAX || + col->spacing < dp->layout->spacing)) + col->spacing = dp->layout->spacing; + + /* + * Calculate an automatic width. + * Except for spanning cells, apply it. + */ + + width = tblcalc_data(tbl, + dp->hspans == 0 ? col : NULL, + opts, dp, + dp->block == 0 ? 0 : + dp->layout->width ? dp->layout->width : + rmargin ? (rmargin + sp->opts->cols / 2) + / (sp->opts->cols + 1) : 0); + if (dp->hspans == 0) + continue; + + /* + * Build an ordered, singly linked list + * of all groups of columns joined by spans, + * recording the minimum width for each group. + */ + + while (*gp != NULL && ((*gp)->startcol < icol || + (*gp)->endcol < icol + dp->hspans)) + gp = &(*gp)->next; + if (*gp == NULL || (*gp)->startcol > icol || + (*gp)->endcol > icol + dp->hspans) { + g = mandoc_malloc(sizeof(*g)); + g->next = *gp; + g->wanted = width; + g->startcol = icol; + g->endcol = icol + dp->hspans; + *gp = g; + } else if ((*gp)->wanted < width) + (*gp)->wanted = width; + } + } + + /* + * Column spacings are needed for span width calculations, + * so set the default values now. + */ + + for (icol = 0; icol <= maxcol; icol++) + if (tbl->cols[icol].spacing == SIZE_MAX || icol == maxcol) + tbl->cols[icol].spacing = 3; + + /* + * Replace the minimum widths with the missing widths, + * and dismiss groups that are already wide enough. + */ + + gp = &first_group; + while ((g = *gp) != NULL) { + done = 0; + for (icol = g->startcol; icol <= g->endcol; icol++) { + width = tbl->cols[icol].width; + if (icol < g->endcol) + width += tbl->cols[icol].spacing; + if (g->wanted <= width) { + done = 1; + break; + } else + (*gp)->wanted -= width; + } + if (done) { + *gp = g->next; + free(g); + } else + gp = &(*gp)->next; + } + + colwidth = mandoc_reallocarray(NULL, maxcol + 1, sizeof(*colwidth)); + while (first_group != NULL) { + + /* + * Rebuild the array of the widths of all columns + * participating in spans that require expansion. + */ + + for (icol = 0; icol <= maxcol; icol++) + colwidth[icol] = SIZE_MAX; + for (g = first_group; g != NULL; g = g->next) + for (icol = g->startcol; icol <= g->endcol; icol++) + colwidth[icol] = tbl->cols[icol].width; + + /* + * Find the smallest and second smallest column width + * among the columns which may need expamsion. + */ + + min1 = min2 = SIZE_MAX; + for (icol = 0; icol <= maxcol; icol++) { + if (min1 > colwidth[icol]) { + min2 = min1; + min1 = colwidth[icol]; + } else if (min1 < colwidth[icol] && + min2 > colwidth[icol]) + min2 = colwidth[icol]; + } + + /* + * Find the minimum wanted width + * for any one of the narrowest columns, + * and mark the columns wanting that width. + */ + + wanted = min2; + for (g = first_group; g != NULL; g = g->next) { + necol = 0; + for (icol = g->startcol; icol <= g->endcol; icol++) + if (tbl->cols[icol].width == min1) + necol++; + if (necol == 0) + continue; + width = min1 + (g->wanted - 1) / necol + 1; + if (width > min2) + width = min2; + if (wanted > width) + wanted = width; + for (icol = g->startcol; icol <= g->endcol; icol++) + if (colwidth[icol] == min1 || + (colwidth[icol] < min2 && + colwidth[icol] > width)) + colwidth[icol] = width; + } + + /* Record the effect of the widening on the group list. */ + + gp = &first_group; + while ((g = *gp) != NULL) { + done = 0; + for (icol = g->startcol; icol <= g->endcol; icol++) { + if (colwidth[icol] != wanted || + tbl->cols[icol].width == wanted) + continue; + if (g->wanted <= wanted - min1) { + done = 1; + break; + } + g->wanted -= wanted - min1; + } + if (done) { + *gp = g->next; + free(g); + } else + gp = &(*gp)->next; + } + + /* Record the effect of the widening on the columns. */ + + for (icol = 0; icol <= maxcol; icol++) + if (colwidth[icol] == wanted) + tbl->cols[icol].width = wanted; + } + free(colwidth); + + /* + * Align numbers with text. + * Count columns to equalize and columns to maximize. + * Find maximum width of the columns to equalize. + * Find total width of the columns *not* to maximize. + */ + + necol = nxcol = 0; + ewidth = xwidth = 0; + for (icol = 0; icol <= maxcol; icol++) { + col = tbl->cols + icol; + if (col->width > col->nwidth) + col->decimal += (col->width - col->nwidth) / 2; + else + col->width = col->nwidth; + if (col->flags & TBL_CELL_EQUAL) { + necol++; + if (ewidth < col->width) + ewidth = col->width; + } + if (col->flags & TBL_CELL_WMAX) + nxcol++; + else + xwidth += col->width; + } + + /* + * Equalize columns, if requested for any of them. + * Update total width of the columns not to maximize. + */ + + if (necol) { + for (icol = 0; icol <= maxcol; icol++) { + col = tbl->cols + icol; + if ( ! (col->flags & TBL_CELL_EQUAL)) + continue; + if (col->width == ewidth) + continue; + if (nxcol && rmargin) + xwidth += ewidth - col->width; + col->width = ewidth; + } + } + + /* + * If there are any columns to maximize, find the total + * available width, deducting 3n margins between columns. + * Distribute the available width evenly. + */ + + if (nxcol && rmargin) { + xwidth += 3*maxcol + + (opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ? + 2 : !!opts->lvert + !!opts->rvert); + if (rmargin <= offset + xwidth) + return; + xwidth = rmargin - offset - xwidth; + + /* + * Emulate a bug in GNU tbl width calculation that + * manifests itself for large numbers of x-columns. + * Emulating it for 5 x-columns gives identical + * behaviour for up to 6 x-columns. + */ + + if (nxcol == 5) { + quirkcol = xwidth % nxcol + 2; + if (quirkcol != 3 && quirkcol != 4) + quirkcol = -1; + } else + quirkcol = -1; + + necol = 0; + ewidth = 0; + for (icol = 0; icol <= maxcol; icol++) { + col = tbl->cols + icol; + if ( ! (col->flags & TBL_CELL_WMAX)) + continue; + col->width = (double)xwidth * ++necol / nxcol + - ewidth + 0.4995; + if (necol == quirkcol) + col->width--; + ewidth += col->width; + } + } +} + +static size_t +tblcalc_data(struct rofftbl *tbl, struct roffcol *col, + const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw) +{ + size_t sz; + + /* Branch down into data sub-types. */ + + switch (dp->layout->pos) { + case TBL_CELL_HORIZ: + case TBL_CELL_DHORIZ: + sz = (*tbl->len)(1, tbl->arg); + if (col != NULL && col->width < sz) + col->width = sz; + return sz; + case TBL_CELL_LONG: + case TBL_CELL_CENTRE: + case TBL_CELL_LEFT: + case TBL_CELL_RIGHT: + return tblcalc_literal(tbl, col, dp, mw); + case TBL_CELL_NUMBER: + return tblcalc_number(tbl, col, opts, dp); + case TBL_CELL_DOWN: + return 0; + default: + abort(); + } +} + +static size_t +tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, + const struct tbl_dat *dp, size_t mw) +{ + const char *str; /* Beginning of the first line. */ + const char *beg; /* Beginning of the current line. */ + char *end; /* End of the current line. */ + size_t lsz; /* Length of the current line. */ + size_t wsz; /* Length of the current word. */ + size_t msz; /* Length of the longest line. */ + + if (dp->string == NULL || *dp->string == '\0') + return 0; + str = mw ? mandoc_strdup(dp->string) : dp->string; + msz = lsz = 0; + for (beg = str; beg != NULL && *beg != '\0'; beg = end) { + end = mw ? strchr(beg, ' ') : NULL; + if (end != NULL) { + *end++ = '\0'; + while (*end == ' ') + end++; + } + wsz = (*tbl->slen)(beg, tbl->arg); + if (mw && lsz && lsz + 1 + wsz <= mw) + lsz += 1 + wsz; + else + lsz = wsz; + if (msz < lsz) + msz = lsz; + } + if (mw) + free((void *)str); + if (col != NULL && col->width < msz) + col->width = msz; + return msz; +} + +static size_t +tblcalc_number(struct rofftbl *tbl, struct roffcol *col, + const struct tbl_opts *opts, const struct tbl_dat *dp) +{ + const char *cp, *lastdigit, *lastpoint; + size_t intsz, totsz; + char buf[2]; + + if (dp->string == NULL || *dp->string == '\0') + return 0; + + totsz = (*tbl->slen)(dp->string, tbl->arg); + if (col == NULL) + return totsz; + + /* + * Find the last digit and + * the last decimal point that is adjacent to a digit. + * The alignment indicator "\&" overrides everything. + */ + + lastdigit = lastpoint = NULL; + for (cp = dp->string; cp[0] != '\0'; cp++) { + if (cp[0] == '\\' && cp[1] == '&') { + lastdigit = lastpoint = cp; + break; + } else if (cp[0] == opts->decimal && + (isdigit((unsigned char)cp[1]) || + (cp > dp->string && isdigit((unsigned char)cp[-1])))) + lastpoint = cp; + else if (isdigit((unsigned char)cp[0])) + lastdigit = cp; + } + + /* Not a number, treat as a literal string. */ + + if (lastdigit == NULL) { + if (col != NULL && col->width < totsz) + col->width = totsz; + return totsz; + } + + /* Measure the width of the integer part. */ + + if (lastpoint == NULL) + lastpoint = lastdigit + 1; + intsz = 0; + buf[1] = '\0'; + for (cp = dp->string; cp < lastpoint; cp++) { + buf[0] = cp[0]; + intsz += (*tbl->slen)(buf, tbl->arg); + } + + /* + * If this number has more integer digits than all numbers + * seen on earlier lines, shift them all to the right. + * If it has fewer, shift this number to the right. + */ + + if (intsz > col->decimal) { + col->nwidth += intsz - col->decimal; + col->decimal = intsz; + } else + totsz += col->decimal - intsz; + + /* Update the maximum total width seen so far. */ + + if (totsz > col->nwidth) + col->nwidth = totsz; + return totsz; +} Property changes on: vendor/mandoc/20190723/out.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/read.c =================================================================== --- vendor/mandoc/20190723/read.c (nonexistent) +++ vendor/mandoc/20190723/read.c (revision 350350) @@ -0,0 +1,711 @@ +/* $Id: read.c,v 1.214 2019/07/10 19:39:01 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2010-2019 Ingo Schwarze + * Copyright (c) 2010, 2012 Joerg Sonnenberger + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "man.h" +#include "mandoc_parse.h" +#include "libmandoc.h" +#include "roff_int.h" + +#define REPARSE_LIMIT 1000 + +struct mparse { + struct roff *roff; /* roff parser (!NULL) */ + struct roff_man *man; /* man parser */ + struct buf *primary; /* buffer currently being parsed */ + struct buf *secondary; /* copy of top level input */ + struct buf *loop; /* open .while request line */ + const char *os_s; /* default operating system */ + int options; /* parser options */ + int gzip; /* current input file is gzipped */ + int filenc; /* encoding of the current file */ + int reparse_count; /* finite interp. stack */ + int line; /* line number in the file */ +}; + +static void choose_parser(struct mparse *); +static void free_buf_list(struct buf *); +static void resize_buf(struct buf *, size_t); +static int mparse_buf_r(struct mparse *, struct buf, size_t, int); +static int read_whole_file(struct mparse *, int, struct buf *, int *); +static void mparse_end(struct mparse *); + + +static void +resize_buf(struct buf *buf, size_t initial) +{ + + buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial; + buf->buf = mandoc_realloc(buf->buf, buf->sz); +} + +static void +free_buf_list(struct buf *buf) +{ + struct buf *tmp; + + while (buf != NULL) { + tmp = buf; + buf = tmp->next; + free(tmp->buf); + free(tmp); + } +} + +static void +choose_parser(struct mparse *curp) +{ + char *cp, *ep; + int format; + + /* + * If neither command line arguments -mdoc or -man select + * a parser nor the roff parser found a .Dd or .TH macro + * yet, look ahead in the main input buffer. + */ + + if ((format = roff_getformat(curp->roff)) == 0) { + cp = curp->primary->buf; + ep = cp + curp->primary->sz; + while (cp < ep) { + if (*cp == '.' || *cp == '\'') { + cp++; + if (cp[0] == 'D' && cp[1] == 'd') { + format = MPARSE_MDOC; + break; + } + if (cp[0] == 'T' && cp[1] == 'H') { + format = MPARSE_MAN; + break; + } + } + cp = memchr(cp, '\n', ep - cp); + if (cp == NULL) + break; + cp++; + } + } + + if (format == MPARSE_MDOC) { + curp->man->meta.macroset = MACROSET_MDOC; + if (curp->man->mdocmac == NULL) + curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX); + } else { + curp->man->meta.macroset = MACROSET_MAN; + if (curp->man->manmac == NULL) + curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX); + } + curp->man->meta.first->tok = TOKEN_NONE; +} + +/* + * Main parse routine for a buffer. + * It assumes encoding and line numbering are already set up. + * It can recurse directly (for invocations of user-defined + * macros, inline equations, and input line traps) + * and indirectly (for .so file inclusion). + */ +static int +mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) +{ + struct buf ln; + struct buf *firstln, *lastln, *thisln, *loop; + char *cp; + size_t pos; /* byte number in the ln buffer */ + int line_result, result; + int of; + int lnn; /* line number in the real file */ + int fd; + int inloop; /* Saw .while on this level. */ + unsigned char c; + + ln.sz = 256; + ln.buf = mandoc_malloc(ln.sz); + ln.next = NULL; + firstln = lastln = loop = NULL; + lnn = curp->line; + pos = 0; + inloop = 0; + result = ROFF_CONT; + + while (i < blk.sz && (blk.buf[i] != '\0' || pos != 0)) { + if (start) { + curp->line = lnn; + curp->reparse_count = 0; + + if (lnn < 3 && + curp->filenc & MPARSE_UTF8 && + curp->filenc & MPARSE_LATIN1) + curp->filenc = preconv_cue(&blk, i); + } + + while (i < blk.sz && (start || blk.buf[i] != '\0')) { + + /* + * When finding an unescaped newline character, + * leave the character loop to process the line. + * Skip a preceding carriage return, if any. + */ + + if ('\r' == blk.buf[i] && i + 1 < blk.sz && + '\n' == blk.buf[i + 1]) + ++i; + if ('\n' == blk.buf[i]) { + ++i; + ++lnn; + break; + } + + /* + * Make sure we have space for the worst + * case of 12 bytes: "\\[u10ffff]\n\0" + */ + + if (pos + 12 > ln.sz) + resize_buf(&ln, 256); + + /* + * Encode 8-bit input. + */ + + c = blk.buf[i]; + if (c & 0x80) { + if ( ! (curp->filenc && preconv_encode( + &blk, &i, &ln, &pos, &curp->filenc))) { + mandoc_msg(MANDOCERR_CHAR_BAD, + curp->line, pos, "0x%x", c); + ln.buf[pos++] = '?'; + i++; + } + continue; + } + + /* + * Exclude control characters. + */ + + if (c == 0x7f || (c < 0x20 && c != 0x09)) { + mandoc_msg(c == 0x00 || c == 0x04 || + c > 0x0a ? MANDOCERR_CHAR_BAD : + MANDOCERR_CHAR_UNSUPP, + curp->line, pos, "0x%x", c); + i++; + if (c != '\r') + ln.buf[pos++] = '?'; + continue; + } + + ln.buf[pos++] = blk.buf[i++]; + } + ln.buf[pos] = '\0'; + + /* + * Maintain a lookaside buffer of all lines. + * parsed from this input source. + */ + + thisln = mandoc_malloc(sizeof(*thisln)); + thisln->buf = mandoc_strdup(ln.buf); + thisln->sz = strlen(ln.buf) + 1; + thisln->next = NULL; + if (firstln == NULL) { + firstln = lastln = thisln; + if (curp->secondary == NULL) + curp->secondary = firstln; + } else { + lastln->next = thisln; + lastln = thisln; + } + + /* XXX Ugly hack to mark the end of the input. */ + + if (i == blk.sz || blk.buf[i] == '\0') { + if (pos + 2 > ln.sz) + resize_buf(&ln, 256); + ln.buf[pos++] = '\n'; + ln.buf[pos] = '\0'; + } + + /* + * A significant amount of complexity is contained by + * the roff preprocessor. It's line-oriented but can be + * expressed on one line, so we need at times to + * readjust our starting point and re-run it. The roff + * preprocessor can also readjust the buffers with new + * data, so we pass them in wholesale. + */ + + of = 0; +rerun: + line_result = roff_parseln(curp->roff, curp->line, &ln, &of); + + /* Process options. */ + + if (line_result & ROFF_APPEND) + assert(line_result == (ROFF_IGN | ROFF_APPEND)); + + if (line_result & ROFF_USERCALL) + assert((line_result & ROFF_MASK) == ROFF_REPARSE); + + if (line_result & ROFF_USERRET) { + assert(line_result == (ROFF_IGN | ROFF_USERRET)); + if (start == 0) { + /* Return from the current macro. */ + result = ROFF_USERRET; + goto out; + } + } + + switch (line_result & ROFF_LOOPMASK) { + case ROFF_IGN: + break; + case ROFF_WHILE: + if (curp->loop != NULL) { + if (loop == curp->loop) + break; + mandoc_msg(MANDOCERR_WHILE_NEST, + curp->line, pos, NULL); + } + curp->loop = thisln; + loop = NULL; + inloop = 1; + break; + case ROFF_LOOPCONT: + case ROFF_LOOPEXIT: + if (curp->loop == NULL) { + mandoc_msg(MANDOCERR_WHILE_FAIL, + curp->line, pos, NULL); + break; + } + if (inloop == 0) { + mandoc_msg(MANDOCERR_WHILE_INTO, + curp->line, pos, NULL); + curp->loop = loop = NULL; + break; + } + if (line_result & ROFF_LOOPCONT) + loop = curp->loop; + else { + curp->loop = loop = NULL; + inloop = 0; + } + break; + default: + abort(); + } + + /* Process the main instruction from the roff parser. */ + + switch (line_result & ROFF_MASK) { + case ROFF_IGN: + break; + case ROFF_CONT: + if (curp->man->meta.macroset == MACROSET_NONE) + choose_parser(curp); + if ((curp->man->meta.macroset == MACROSET_MDOC ? + mdoc_parseln(curp->man, curp->line, ln.buf, of) : + man_parseln(curp->man, curp->line, ln.buf, of) + ) == 2) + goto out; + break; + case ROFF_RERUN: + goto rerun; + case ROFF_REPARSE: + if (++curp->reparse_count > REPARSE_LIMIT) { + /* Abort and return to the top level. */ + result = ROFF_IGN; + mandoc_msg(MANDOCERR_ROFFLOOP, + curp->line, pos, NULL); + goto out; + } + result = mparse_buf_r(curp, ln, of, 0); + if (line_result & ROFF_USERCALL) { + roff_userret(curp->roff); + /* Continue normally. */ + if (result & ROFF_USERRET) + result = ROFF_CONT; + } + if (start == 0 && result != ROFF_CONT) + goto out; + break; + case ROFF_SO: + if ( ! (curp->options & MPARSE_SO) && + (i >= blk.sz || blk.buf[i] == '\0')) { + curp->man->meta.sodest = + mandoc_strdup(ln.buf + of); + goto out; + } + if ((fd = mparse_open(curp, ln.buf + of)) != -1) { + mparse_readfd(curp, fd, ln.buf + of); + close(fd); + } else { + mandoc_msg(MANDOCERR_SO_FAIL, + curp->line, of, ".so %s: %s", + ln.buf + of, strerror(errno)); + ln.sz = mandoc_asprintf(&cp, + ".sp\nSee the file %s.\n.sp", + ln.buf + of); + free(ln.buf); + ln.buf = cp; + of = 0; + mparse_buf_r(curp, ln, of, 0); + } + break; + default: + abort(); + } + + /* Start the next input line. */ + + if (loop != NULL && + (line_result & ROFF_LOOPMASK) == ROFF_IGN) + loop = loop->next; + + if (loop != NULL) { + if ((line_result & ROFF_APPEND) == 0) + *ln.buf = '\0'; + if (ln.sz < loop->sz) + resize_buf(&ln, loop->sz); + (void)strlcat(ln.buf, loop->buf, ln.sz); + of = 0; + goto rerun; + } + + pos = (line_result & ROFF_APPEND) ? strlen(ln.buf) : 0; + } +out: + if (inloop) { + if (result != ROFF_USERRET) + mandoc_msg(MANDOCERR_WHILE_OUTOF, + curp->line, pos, NULL); + curp->loop = NULL; + } + free(ln.buf); + if (firstln != curp->secondary) + free_buf_list(firstln); + return result; +} + +static int +read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) +{ + struct stat st; + gzFile gz; + size_t off; + ssize_t ssz; + int gzerrnum, retval; + + if (fstat(fd, &st) == -1) { + mandoc_msg(MANDOCERR_FSTAT, 0, 0, "%s", strerror(errno)); + return -1; + } + + /* + * If we're a regular file, try just reading in the whole entry + * via mmap(). This is faster than reading it into blocks, and + * since each file is only a few bytes to begin with, I'm not + * concerned that this is going to tank any machines. + */ + + if (curp->gzip == 0 && S_ISREG(st.st_mode)) { + if (st.st_size > 0x7fffffff) { + mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL); + return -1; + } + *with_mmap = 1; + fb->sz = (size_t)st.st_size; + fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0); + if (fb->buf != MAP_FAILED) + return 0; + } + + if (curp->gzip) { + /* + * Duplicating the file descriptor is required + * because we will have to call gzclose(3) + * to free memory used internally by zlib, + * but that will also close the file descriptor, + * which this function must not do. + */ + if ((fd = dup(fd)) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, + "%s", strerror(errno)); + return -1; + } + if ((gz = gzdopen(fd, "rb")) == NULL) { + mandoc_msg(MANDOCERR_GZDOPEN, 0, 0, + "%s", strerror(errno)); + close(fd); + return -1; + } + } else + gz = NULL; + + /* + * If this isn't a regular file (like, say, stdin), then we must + * go the old way and just read things in bit by bit. + */ + + *with_mmap = 0; + off = 0; + retval = -1; + fb->sz = 0; + fb->buf = NULL; + for (;;) { + if (off == fb->sz) { + if (fb->sz == (1U << 31)) { + mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL); + break; + } + resize_buf(fb, 65536); + } + ssz = curp->gzip ? + gzread(gz, fb->buf + (int)off, fb->sz - off) : + read(fd, fb->buf + (int)off, fb->sz - off); + if (ssz == 0) { + fb->sz = off; + retval = 0; + break; + } + if (ssz == -1) { + if (curp->gzip) + (void)gzerror(gz, &gzerrnum); + mandoc_msg(MANDOCERR_READ, 0, 0, "%s", + curp->gzip && gzerrnum != Z_ERRNO ? + zError(gzerrnum) : strerror(errno)); + break; + } + off += (size_t)ssz; + } + + if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK) + mandoc_msg(MANDOCERR_GZCLOSE, 0, 0, "%s", + gzerrnum == Z_ERRNO ? strerror(errno) : + zError(gzerrnum)); + if (retval == -1) { + free(fb->buf); + fb->buf = NULL; + } + return retval; +} + +static void +mparse_end(struct mparse *curp) +{ + if (curp->man->meta.macroset == MACROSET_NONE) + curp->man->meta.macroset = MACROSET_MAN; + if (curp->man->meta.macroset == MACROSET_MDOC) + mdoc_endparse(curp->man); + else + man_endparse(curp->man); + roff_endparse(curp->roff); +} + +/* + * Read the whole file into memory and call the parsers. + * Called recursively when an .so request is encountered. + */ +void +mparse_readfd(struct mparse *curp, int fd, const char *filename) +{ + static int recursion_depth; + + struct buf blk; + struct buf *save_primary; + const char *save_filename; + size_t offset; + int save_filenc, save_lineno; + int with_mmap; + + if (recursion_depth > 64) { + mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL); + return; + } + if (read_whole_file(curp, fd, &blk, &with_mmap) == -1) + return; + + /* + * Save some properties of the parent file. + */ + + save_primary = curp->primary; + save_filenc = curp->filenc; + save_lineno = curp->line; + save_filename = mandoc_msg_getinfilename(); + + curp->primary = &blk; + curp->filenc = curp->options & (MPARSE_UTF8 | MPARSE_LATIN1); + curp->line = 1; + mandoc_msg_setinfilename(filename); + + /* Skip an UTF-8 byte order mark. */ + if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 && + (unsigned char)blk.buf[0] == 0xef && + (unsigned char)blk.buf[1] == 0xbb && + (unsigned char)blk.buf[2] == 0xbf) { + offset = 3; + curp->filenc &= ~MPARSE_LATIN1; + } else + offset = 0; + + recursion_depth++; + mparse_buf_r(curp, blk, offset, 1); + if (--recursion_depth == 0) + mparse_end(curp); + + /* + * Clean up and restore saved parent properties. + */ + + if (with_mmap) + munmap(blk.buf, blk.sz); + else + free(blk.buf); + + curp->primary = save_primary; + curp->filenc = save_filenc; + curp->line = save_lineno; + if (save_filename != NULL) + mandoc_msg_setinfilename(save_filename); +} + +int +mparse_open(struct mparse *curp, const char *file) +{ + char *cp; + int fd, save_errno; + + cp = strrchr(file, '.'); + curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz")); + + /* First try to use the filename as it is. */ + + if ((fd = open(file, O_RDONLY)) != -1) + return fd; + + /* + * If that doesn't work and the filename doesn't + * already end in .gz, try appending .gz. + */ + + if ( ! curp->gzip) { + save_errno = errno; + mandoc_asprintf(&cp, "%s.gz", file); + fd = open(cp, O_RDONLY); + free(cp); + errno = save_errno; + if (fd != -1) { + curp->gzip = 1; + return fd; + } + } + + /* Neither worked, give up. */ + + return -1; +} + +struct mparse * +mparse_alloc(int options, enum mandoc_os os_e, const char *os_s) +{ + struct mparse *curp; + + curp = mandoc_calloc(1, sizeof(struct mparse)); + + curp->options = options; + curp->os_s = os_s; + + curp->roff = roff_alloc(options); + curp->man = roff_man_alloc(curp->roff, curp->os_s, + curp->options & MPARSE_QUICK ? 1 : 0); + if (curp->options & MPARSE_MDOC) { + curp->man->meta.macroset = MACROSET_MDOC; + if (curp->man->mdocmac == NULL) + curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX); + } else if (curp->options & MPARSE_MAN) { + curp->man->meta.macroset = MACROSET_MAN; + if (curp->man->manmac == NULL) + curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX); + } + curp->man->meta.first->tok = TOKEN_NONE; + curp->man->meta.os_e = os_e; + return curp; +} + +void +mparse_reset(struct mparse *curp) +{ + roff_reset(curp->roff); + roff_man_reset(curp->man); + free_buf_list(curp->secondary); + curp->secondary = NULL; + curp->gzip = 0; +} + +void +mparse_free(struct mparse *curp) +{ + roffhash_free(curp->man->mdocmac); + roffhash_free(curp->man->manmac); + roff_man_free(curp->man); + roff_free(curp->roff); + free_buf_list(curp->secondary); + free(curp); +} + +struct roff_meta * +mparse_result(struct mparse *curp) +{ + roff_state_reset(curp->man); + if (curp->options & MPARSE_VALIDATE) { + if (curp->man->meta.macroset == MACROSET_MDOC) + mdoc_validate(curp->man); + else + man_validate(curp->man); + } + return &curp->man->meta; +} + +void +mparse_copy(const struct mparse *p) +{ + struct buf *buf; + + for (buf = p->secondary; buf != NULL; buf = buf->next) + puts(buf->buf); +} Property changes on: vendor/mandoc/20190723/read.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/roff.7 =================================================================== --- vendor/mandoc/20190723/roff.7 (nonexistent) +++ vendor/mandoc/20190723/roff.7 (revision 350350) @@ -0,0 +1,2342 @@ +.\" $Id: roff.7,v 1.114 2019/07/15 19:20:30 schwarze Exp $ +.\" +.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons +.\" Copyright (c) 2010-2019 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 15 2019 $ +.Dt ROFF 7 +.Os +.Sh NAME +.Nm roff +.Nd roff language reference for mandoc +.Sh DESCRIPTION +The +.Nm roff +language is a general purpose text formatting language. +Since traditional implementations of the +.Xr mdoc 7 +and +.Xr man 7 +manual formatting languages are based on it, +many real-world manuals use small numbers of +.Nm +requests and escape sequences intermixed with their +.Xr mdoc 7 +or +.Xr man 7 +code. +To properly format such manuals, the +.Xr mandoc 1 +utility supports a subset of +.Nm +requests and escapes. +Even though this manual page lists all +.Nm +requests and escape sequences, it only contains partial information +about requests not supported by +.Xr mandoc 1 +and about language features that do not matter for manual pages. +For complete +.Nm +manuals, consult the +.Sx SEE ALSO +section. +.Pp +Input lines beginning with the control character +.Sq \&. +are parsed for requests and macros. +Such lines are called +.Dq request lines +or +.Dq macro lines , +respectively. +Requests change the processing state and manipulate the formatting; +some macros also define the document structure and produce formatted +output. +The single quote +.Pq Qq \(aq +is accepted as an alternative control character, +treated by +.Xr mandoc 1 +just like +.Ql \&. +.Pp +Lines not beginning with control characters are called +.Dq text lines . +They provide free-form text to be printed; the formatting of the text +depends on the respective processing context. +.Sh LANGUAGE SYNTAX +.Nm +documents may contain only graphable 7-bit ASCII characters, the space +character, and, in certain circumstances, the tab character. +The backslash character +.Sq \e +indicates the start of an escape sequence, used for example for +.Sx Comments +and +.Sx Special Characters . +For a complete listing of escape sequences, consult the +.Sx ESCAPE SEQUENCE REFERENCE +below. +.Ss Comments +Text following an escaped double-quote +.Sq \e\(dq , +whether in a request, macro, or text line, is ignored to the end of the line. +A request line beginning with a control character and comment escape +.Sq \&.\e\(dq +is also ignored. +Furthermore, request lines with only a control character and optional +trailing whitespace are stripped from input. +.Pp +Examples: +.Bd -literal -offset indent -compact +\&.\e\(dq This is a comment line. +\&.\e\(dq The next line is ignored: +\&. +\&.Sh EXAMPLES \e\(dq This is a comment, too. +\&example text \e\(dq And so is this. +.Ed +.Ss Special Characters +Special characters are used to encode special glyphs and are rendered +differently across output media. +They may occur in request, macro, and text lines. +Sequences begin with the escape character +.Sq \e +followed by either an open-parenthesis +.Sq \&( +for two-character sequences; an open-bracket +.Sq \&[ +for n-character sequences (terminated at a close-bracket +.Sq \&] ) ; +or a single one character sequence. +.Pp +Examples: +.Bl -tag -width Ds -offset indent -compact +.It Li \e(em +Two-letter em dash escape. +.It Li \ee +One-letter backslash escape. +.El +.Pp +See +.Xr mandoc_char 7 +for a complete list. +.Ss Font Selection +In +.Xr mdoc 7 +and +.Xr man 7 +documents, fonts are usually selected with macros. +The +.Ic \ef +escape sequence and the +.Ic \&ft +request can be used to manually change the font, +but this is not recommended in +.Xr mdoc 7 +documents. +Such manual font changes are overridden by many subsequent macros. +.Pp +The following fonts are supported: +.Pp +.Bl -tag -width CW -offset indent -compact +.It Cm B +Bold font. +.It Cm BI +A font that is both bold and italic. +.It Cm CB +Bold constant width font. +Same as +.Cm B +in terminal output. +.It Cm CI +Italic constant width font. +Same as +.Cm I +in terminal output. +.It Cm CR +Regular constant width font. +Same as +.Cm R +in terminal output. +.It Cm CW +An alias for +.Cm CR . +.It Cm I +Italic font. +.It Cm P +Return to the previous font. +If a macro caused a font change since the last +.Ic \ef +eascape sequence or +.Ic \&ft +request, this returns to the font before the last font change in +the macro rather than to the font before the last manual font change. +.It Cm R +Roman font. +This is the default font. +.It Cm 1 +An alias for +.Cm R . +.It Cm 2 +An alias for +.Cm I . +.It Cm 3 +An alias for +.Cm B . +.It Cm 4 +An alias for +.Cm BI . +.El +.Pp +Examples: +.Bl -tag -width Ds -offset indent -compact +.It Li \efBbold\efR +Write in \fBbold\fP, then switch to regular font mode. +.It Li \efIitalic\efP +Write in \fIitalic\fP, then return to previous font mode. +.It Li \ef(BIbold italic\efP +Write in \f(BIbold italic\fP, then return to previous font mode. +.El +.Ss Whitespace +Whitespace consists of the space character. +In text lines, whitespace is preserved within a line. +In request and macro lines, whitespace delimits arguments and is discarded. +.Pp +Unescaped trailing spaces are stripped from text line input unless in a +literal context. +In general, trailing whitespace on any input line is discouraged for +reasons of portability. +In the rare case that a space character is needed at the end of an +input line, it may be forced by +.Sq \e\ \e& . +.Pp +Literal space characters can be produced in the output +using escape sequences. +In macro lines, they can also be included in arguments using quotation; see +.Sx MACRO SYNTAX +for details. +.Pp +Blank text lines, which may include whitespace, are only permitted +within literal contexts. +If the first character of a text line is a space, that line is printed +with a leading newline. +.Ss Scaling Widths +Many requests and macros support scaled widths for their arguments. +The syntax for a scaled width is +.Sq Li [+-]?[0-9]*.[0-9]*[:unit:] , +where a decimal must be preceded or followed by at least one digit. +.Pp +The following scaling units are accepted: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It c +centimetre +.It i +inch +.It P +pica (1/6 inch) +.It p +point (1/72 inch) +.It f +scale +.Sq u +by 65536 +.It v +default vertical span +.It m +width of rendered +.Sq m +.Pq em +character +.It n +width of rendered +.Sq n +.Pq en +character +.It u +default horizontal span for the terminal +.It M +mini-em (1/100 em) +.El +.Pp +Using anything other than +.Sq m , +.Sq n , +or +.Sq v +is necessarily non-portable across output media. +See +.Sx COMPATIBILITY . +.Pp +If a scaling unit is not provided, the numerical value is interpreted +under the default rules of +.Sq v +for vertical spaces and +.Sq u +for horizontal ones. +.Pp +Examples: +.Bl -tag -width ".Bl -tag -width 2i" -offset indent -compact +.It Li \&.Bl -tag -width 2i +two-inch tagged list indentation in +.Xr mdoc 7 +.It Li \&.HP 2i +two-inch tagged list indentation in +.Xr man 7 +.It Li \&.sp 2v +two vertical spaces +.El +.Ss Sentence Spacing +Each sentence should terminate at the end of an input line. +By doing this, a formatter will be able to apply the proper amount of +spacing after the end of sentence (unescaped) period, exclamation mark, +or question mark followed by zero or more non-sentence closing +delimiters +.Po +.Sq \&) , +.Sq \&] , +.Sq \&' , +.Sq \&" +.Pc . +.Pp +The proper spacing is also intelligently preserved if a sentence ends at +the boundary of a macro line. +.Pp +If an input line happens to end with a period, exclamation or question +mark that isn't the end of a sentence, append a zero-width space +.Pq Sq \e& . +.Pp +Examples: +.Bd -literal -offset indent -compact +Do not end sentences mid-line like this. Instead, +end a sentence like this. +A macro would end like this: +\&.Xr mandoc 1 \&. +An abbreviation at the end of an input line needs escaping, e.g.\e& +like this. +.Ed +.Sh REQUEST SYNTAX +A request or macro line consists of: +.Pp +.Bl -enum -compact +.It +the control character +.Sq \&. +or +.Sq \(aq +at the beginning of the line, +.It +optionally an arbitrary amount of whitespace, +.It +the name of the request or the macro, which is one word of arbitrary +length, terminated by whitespace, +.It +and zero or more arguments delimited by whitespace. +.El +.Pp +Thus, the following request lines are all equivalent: +.Bd -literal -offset indent +\&.ig end +\&.ig end +\&. ig end +.Ed +.Sh MACRO SYNTAX +Macros are provided by the +.Xr mdoc 7 +and +.Xr man 7 +languages and can be defined by the +.Ic \&de +request. +When called, they follow the same syntax as requests, except that +macro arguments may optionally be quoted by enclosing them +in double quote characters +.Pq Sq \(dq . +Quoted text, even if it contains whitespace or would cause +a macro invocation when unquoted, is always considered literal text. +Inside quoted text, pairs of double quote characters +.Pq Sq Qq +resolve to single double quote characters. +.Pp +To be recognised as the beginning of a quoted argument, the opening +quote character must be preceded by a space character. +A quoted argument extends to the next double quote character that is not +part of a pair, or to the end of the input line, whichever comes earlier. +Leaving out the terminating double quote character at the end of the line +is discouraged. +For clarity, if more arguments follow on the same input line, +it is recommended to follow the terminating double quote character +by a space character; in case the next character after the terminating +double quote character is anything else, it is regarded as the beginning +of the next, unquoted argument. +.Pp +Both in quoted and unquoted arguments, pairs of backslashes +.Pq Sq \e\e +resolve to single backslashes. +In unquoted arguments, space characters can alternatively be included +by preceding them with a backslash +.Pq Sq \e\~ , +but quoting is usually better for clarity. +.Pp +Examples: +.Bl -tag -width Ds -offset indent -compact +.It Li .Fn strlen \(dqconst char *s\(dq +Group arguments +.Qq const char *s +into one function argument. +If unspecified, +.Qq const , +.Qq char , +and +.Qq *s +would be considered separate arguments. +.It Li .Op \(dqFl a\(dq +Consider +.Qq \&Fl a +as literal text instead of a flag macro. +.El +.Sh REQUEST REFERENCE +The +.Xr mandoc 1 +.Nm +parser recognises the following requests. +For requests marked as "ignored" or "unsupported", any arguments are +ignored, and the number of arguments is not checked. +.Bl -tag -width Ds +.It Ic \&ab Op Ar message +Abort processing. +Currently unsupported. +.It Ic \&ad Op Cm b | c | l | n | r +Set line adjustment mode for subsequent text. +Currently ignored. +.It Ic \&af Ar registername format +Assign an output format to a number register. +Currently ignored. +.It Ic \&aln Ar newname oldname +Create an alias for a number register. +Currently unsupported. +.It Ic \&als Ar newname oldname +Create an alias for a request, string, macro, or diversion. +.It Ic \&am Ar macroname Op Ar endmacro +Append to a macro definition. +The syntax of this request is the same as that of +.Ic \&de . +.It Ic \&am1 Ar macroname Op Ar endmacro +Append to a macro definition, switching roff compatibility mode off +during macro execution (groff extension). +The syntax of this request is the same as that of +.Ic \&de1 . +Since +.Xr mandoc 1 +does not implement +.Nm +compatibility mode at all, it handles this request as an alias for +.Ic \&am . +.It Ic \&ami Ar macrostring Op Ar endstring +Append to a macro definition, specifying the macro name indirectly +(groff extension). +The syntax of this request is the same as that of +.Ic \&dei . +.It Ic \&ami1 Ar macrostring Op Ar endstring +Append to a macro definition, specifying the macro name indirectly +and switching roff compatibility mode off during macro execution +(groff extension). +The syntax of this request is the same as that of +.Ic \&dei1 . +Since +.Xr mandoc 1 +does not implement +.Nm +compatibility mode at all, it handles this request as an alias for +.Ic \&ami . +.It Ic \&as Ar stringname Op Ar string +Append to a user-defined string. +The syntax of this request is the same as that of +.Ic \&ds . +If a user-defined string with the specified name does not yet exist, +it is set to the empty string before appending. +.It Ic \&as1 Ar stringname Op Ar string +Append to a user-defined string, switching roff compatibility mode off +during macro execution (groff extension). +The syntax of this request is the same as that of +.Ic \&ds1 . +Since +.Xr mandoc 1 +does not implement +.Nm +compatibility mode at all, it handles this request as an alias for +.Ic \&as . +.It Ic \&asciify Ar divname +Fully unformat a diversion. +Currently unsupported. +.It Ic \&backtrace +Print a backtrace of the input stack. +This is a groff extension and currently ignored. +.It Ic \&bd Ar font Oo Ar curfont Oc Op Ar offset +Artificially embolden by repeated printing with small shifts. +Currently ignored. +.It Ic \&bleedat Ar left top width height +Set the BleedBox page parameter for PDF generation. +This is a Heirloom extension and currently ignored. +.It Ic \&blm Ar macroname +Set a blank line trap. +Currently unsupported. +.It Ic \&box Ar divname +Begin a diversion without including a partially filled line. +Currently unsupported. +.It Ic \&boxa Ar divname +Add to a diversion without including a partially filled line. +Currently unsupported. +.It Ic \&bp Oo Cm + Ns | Ns Cm - Oc Ns Ar pagenumber +Begin a new page. +Currently ignored. +.It Ic \&BP Ar source height width position offset flags label +Define a frame and place a picture in it. +This is a Heirloom extension and currently unsupported. +.It Ic \&br +Break the output line. +.It Ic \&break +Break out of the innermost +.Ic \&while +loop. +.It Ic \&breakchar Ar char ... +Optional line break characters. +This is a Heirloom extension and currently ignored. +.It Ic \&brnl Ar N +Break output line after the next +.Ar N +input lines. +This is a Heirloom extension and currently ignored. +.It Ic \&brp +Break and spread output line. +Currently, this is implemented as an alias for +.Ic \&br . +.It Ic \&brpnl Ar N +Break and spread output line after the next +.Ar N +input lines. +This is a Heirloom extension and currently ignored. +.It Ic \&c2 Op Ar char +Change the no-break control character. +Currently unsupported. +.It Ic \&cc Op Ar char +Change the control character. +If +.Ar char +is not specified, the control character is reset to +.Sq \&. . +Trailing characters are ignored. +.It Ic \&ce Op Ar N +Center the next +.Ar N +input lines without filling. +.Ar N +defaults to 1. +An argument of 0 or less ends centering. +Currently, high level macros abort centering. +.It Ic \&cf Ar filename +Output the contents of a file. +Ignored because insecure. +.It Ic \&cflags Ar flags char ... +Set character flags. +This is a groff extension and currently ignored. +.It Ic \&ch Ar macroname Op Ar dist +Change a trap location. +Currently ignored. +.It Ic \&char Ar glyph Op Ar string +Define or redefine the ASCII character or character escape sequence +.Ar glyph +to be rendered as +.Ar string , +which can be empty. +Only partially supported in +.Xr mandoc 1 ; +may interact incorrectly with +.Ic \&tr . +.It Ic \&chop Ar stringname +Remove the last character from a macro, string, or diversion. +Currently unsupported. +.It Ic \&class Ar classname char ... +Define a character class. +This is a groff extension and currently ignored. +.It Ic \&close Ar streamname +Close an open file. +Ignored because insecure. +.It Ic \&CL Ar color text +Print text in color. +This is a Heirloom extension and currently unsupported. +.It Ic \&color Op Cm 1 | 0 +Activate or deactivate colors. +This is a groff extension and currently ignored. +.It Ic \&composite Ar from to +Define a name component for composite glyph names. +This is a groff extension and currently unsupported. +.It Ic \&continue +Immediately start the next iteration of a +.Ic \&while +loop. +Currently unsupported. +.It Ic \&cp Op Cm 1 | 0 +Switch +.Nm +compatibility mode on or off. +Currently ignored. +.It Ic \&cropat Ar left top width height +Set the CropBox page parameter for PDF generation. +This is a Heirloom extension and currently ignored. +.It Ic \&cs Ar font Op Ar width Op Ar emsize +Constant character spacing mode. +Currently ignored. +.It Ic \&cu Op Ar N +Underline next +.Ar N +input lines including whitespace. +Currently ignored. +.It Ic \&da Ar divname +Append to a diversion. +Currently unsupported. +.It Ic \&dch Ar macroname Op Ar dist +Change a trap location in the current diversion. +This is a Heirloom extension and currently unsupported. +.It Ic \&de Ar macroname Op Ar endmacro +Define a +.Nm +macro. +Its syntax can be either +.Bd -literal -offset indent +.Pf . Ic \&de Ar macroname +.Ar definition +\&.. +.Ed +.Pp +or +.Bd -literal -offset indent +.Pf . Ic \&de Ar macroname Ar endmacro +.Ar definition +.Pf . Ar endmacro +.Ed +.Pp +Both forms define or redefine the macro +.Ar macroname +to represent the +.Ar definition , +which may consist of one or more input lines, including the newline +characters terminating each line, optionally containing calls to +.Nm +requests, +.Nm +macros or high-level macros like +.Xr man 7 +or +.Xr mdoc 7 +macros, whichever applies to the document in question. +.Pp +Specifying a custom +.Ar endmacro +works in the same way as for +.Ic \&ig ; +namely, the call to +.Sq Pf . Ar endmacro +first ends the +.Ar definition , +and after that, it is also evaluated as a +.Nm +request or +.Nm +macro, but not as a high-level macro. +.Pp +The macro can be invoked later using the syntax +.Pp +.D1 Pf . Ar macroname Op Ar argument Op Ar argument ... +.Pp +Regarding argument parsing, see +.Sx MACRO SYNTAX +above. +.Pp +The line invoking the macro will be replaced +in the input stream by the +.Ar definition , +replacing all occurrences of +.No \e\e$ Ns Ar N , +where +.Ar N +is a digit, by the +.Ar N Ns th Ar argument . +For example, +.Bd -literal -offset indent +\&.de ZN +\efI\e^\e\e$1\e^\efP\e\e$2 +\&.. +\&.ZN XtFree . +.Ed +.Pp +produces +.Pp +.D1 \efI\e^XtFree\e^\efP. +.Pp +in the input stream, and thus in the output: \fI\^XtFree\^\fP. +Each occurrence of \e\e$* is replaced with all the arguments, +joined together with single space characters. +The variant \e\e$@ is similar, except that each argument is +individually quoted. +.Pp +Since macros and user-defined strings share a common string table, +defining a macro +.Ar macroname +clobbers the user-defined string +.Ar macroname , +and the +.Ar definition +can also be printed using the +.Sq \e* +string interpolation syntax described below +.Ic ds , +but this is rarely useful because every macro definition contains at least +one explicit newline character. +.Pp +In order to prevent endless recursion, both groff and +.Xr mandoc 1 +limit the stack depth for expanding macros and strings +to a large, but finite number, and +.Xr mandoc 1 +also limits the length of the expanded input line. +Do not rely on the exact values of these limits. +.It Ic \&de1 Ar macroname Op Ar endmacro +Define a +.Nm +macro that will be executed with +.Nm +compatibility mode switched off during macro execution. +This is a groff extension. +Since +.Xr mandoc 1 +does not implement +.Nm +compatibility mode at all, it handles this request as an alias for +.Ic \&de . +.It Ic \&defcolor Ar newname scheme component ... +Define a color name. +This is a groff extension and currently ignored. +.It Ic \&dei Ar macrostring Op Ar endstring +Define a +.Nm +macro, specifying the macro name indirectly (groff extension). +The syntax of this request is the same as that of +.Ic \&de . +The effect is the same as: +.Pp +.D1 Pf . Cm \&de No \e* Ns Bo Ar macrostring Bc Op \e* Ns Bq Ar endstring +.It Ic \&dei1 Ar macrostring Op Ar endstring +Define a +.Nm +macro that will be executed with +.Nm +compatibility mode switched off during macro execution, +specifying the macro name indirectly (groff extension). +Since +.Xr mandoc 1 +does not implement +.Nm +compatibility mode at all, it handles this request as an alias for +.Ic \&dei . +.It Ic \&device Ar string ... +.It Ic \&devicem Ar stringname +These two requests only make sense with the groff-specific intermediate +output format and are unsupported. +.It Ic \&di Ar divname +Begin a diversion. +Currently unsupported. +.It Ic \&do Ar command Op Ar argument ... +Execute +.Nm +request or macro line with compatibility mode disabled. +Currently unsupported. +.It Ic \&ds Ar stringname Op Oo \(dq Oc Ns Ar string +Define a user-defined string. +The +.Ar stringname +and +.Ar string +arguments are space-separated. +If the +.Ar string +begins with a double-quote character, that character will not be part +of the string. +All remaining characters on the input line form the +.Ar string , +including whitespace and double-quote characters, even trailing ones. +.Pp +The +.Ar string +can be interpolated into subsequent text by using +.No \e* Ns Bq Ar stringname +for a +.Ar stringname +of arbitrary length, or \e*(NN or \e*N if the length of +.Ar stringname +is two or one characters, respectively. +Interpolation can be prevented by escaping the leading backslash; +that is, an asterisk preceded by an even number of backslashes +does not trigger string interpolation. +.Pp +Since user-defined strings and macros share a common string table, +defining a string +.Ar stringname +clobbers the macro +.Ar stringname , +and the +.Ar stringname +used for defining a string can also be invoked as a macro, +in which case the following input line will be appended to the +.Ar string , +forming a new input line passed to the +.Nm +parser. +For example, +.Bd -literal -offset indent +\&.ds badidea .S +\&.badidea +H SYNOPSIS +.Ed +.Pp +invokes the +.Ic SH +macro when used in a +.Xr man 7 +document. +Such abuse is of course strongly discouraged. +.It Ic \&ds1 Ar stringname Op Oo \(dq Oc Ns Ar string +Define a user-defined string that will be expanded with +.Nm +compatibility mode switched off during string expansion. +This is a groff extension. +Since +.Xr mandoc 1 +does not implement +.Nm +compatibility mode at all, it handles this request as an alias for +.Ic \&ds . +.It Ic \&dwh Ar dist macroname +Set a location trap in the current diversion. +This is a Heirloom extension and currently unsupported. +.It Ic \&dt Op Ar dist macroname +Set a trap within a diversion. +Currently unsupported. +.It Ic \&ec Op Ar char +Enable the escape mechanism and change the escape character. +The +.Ar char +argument defaults to the backslash +.Pq Sq \e . +.It Ic \&ecr +Restore the escape character. +Currently unsupported. +.It Ic \&ecs +Save the escape character. +Currently unsupported. +.It Ic \&el Ar body +The +.Dq else +half of an if/else conditional. +Pops a result off the stack of conditional evaluations pushed by +.Ic \&ie +and uses it as its conditional. +If no stack entries are present (e.g., due to no prior +.Ic \&ie +calls) +then false is assumed. +The syntax of this request is similar to +.Ic \&if +except that the conditional is missing. +.It Ic \&em Ar macroname +Set a trap at the end of input. +Currently unsupported. +.It Ic \&EN +End an equation block. +See +.Ic \&EQ . +.It Ic \&eo +Disable the escape mechanism completely. +.It Ic \&EP +End a picture started by +.Ic \&BP . +This is a Heirloom extension and currently unsupported. +.It Ic \&EQ +Begin an equation block. +See +.Xr eqn 7 +for a description of the equation language. +.It Ic \&errprint Ar message +Print a string like an error message. +This is a Heirloom extension and currently ignored. +.It Ic \&ev Op Ar envname +Switch to another environment. +Currently unsupported. +.It Ic \&evc Op Ar envname +Copy an environment into the current environment. +Currently unsupported. +.It Ic \&ex +Abort processing and exit. +Currently unsupported. +.It Ic \&fallback Ar curfont font ... +Select the fallback sequence for a font. +This is a Heirloom extension and currently ignored. +.It Ic \&fam Op Ar familyname +Change the font family. +This is a groff extension and currently ignored. +.It Ic \&fc Op Ar delimchar Op Ar padchar +Define a delimiting and a padding character for fields. +Currently unsupported. +.It Ic \&fchar Ar glyphname Op Ar string +Define a fallback glyph. +Currently unsupported. +.It Ic \&fcolor Ar colorname +Set the fill color for \eD objects. +This is a groff extension and currently ignored. +.It Ic \&fdeferlig Ar font string ... +Defer ligature building. +This is a Heirloom extension and currently ignored. +.It Ic \&feature Cm + Ns | Ns Cm - Ns Ar name +Enable or disable an OpenType feature. +This is a Heirloom extension and currently ignored. +.It Ic \&fi +Break the output line and switch to fill mode, +which is active by default but can be ended with the +.Ic \&nf +request. +In fill mode, input from subsequent input lines is added to +the same output line until the next word no longer fits, +at which point the output line is broken. +This request is implied by the +.Xr mdoc 7 +.Ic \&Sh +macro and by the +.Xr man 7 +.Ic \&SH , +.Ic \&SS , +and +.Ic \&EE +macros. +.It Ic \&fkern Ar font minkern +Control the use of kerning tables for a font. +This is a Heirloom extension and currently ignored. +.It Ic \&fl +Flush output. +Currently ignored. +.It Ic \&flig Ar font string char ... +Define ligatures. +This is a Heirloom extension and currently ignored. +.It Ic \&fp Ar position font Op Ar filename +Assign font position. +Currently ignored. +.It Ic \&fps Ar mapname ... +Mount a font with a special character map. +This is a Heirloom extension and currently ignored. +.It Ic \&fschar Ar font glyphname Op Ar string +Define a font-specific fallback glyph. +This is a groff extension and currently unsupported. +.It Ic \&fspacewidth Ar font Op Ar afmunits +Set a font-specific width for the space character. +This is a Heirloom extension and currently ignored. +.It Ic \&fspecial Ar curfont Op Ar font ... +Conditionally define a special font. +This is a groff extension and currently ignored. +.It Ic \&ft Op Ar font +Change the font; see +.Sx Font Selection . +The +.Ar font +argument defaults to +.Cm P . +.It Ic \&ftr Ar newname Op Ar oldname +Translate font name. +This is a groff extension and currently ignored. +.It Ic \&fzoom Ar font Op Ar permille +Zoom font size. +Currently ignored. +.It Ic \&gcolor Op Ar colorname +Set glyph color. +This is a groff extension and currently ignored. +.It Ic \&hc Op Ar char +Set the hyphenation character. +Currently ignored. +.It Ic \&hcode Ar char code ... +Set hyphenation codes of characters. +Currently ignored. +.It Ic \&hidechar Ar font char ... +Hide characters in a font. +This is a Heirloom extension and currently ignored. +.It Ic \&hla Ar language +Set hyphenation language. +This is a groff extension and currently ignored. +.It Ic \&hlm Op Ar number +Set maximum number of consecutive hyphenated lines. +Currently ignored. +.It Ic \&hpf Ar filename +Load hyphenation pattern file. +This is a groff extension and currently ignored. +.It Ic \&hpfa Ar filename +Load hyphenation pattern file, appending to the current patterns. +This is a groff extension and currently ignored. +.It Ic \&hpfcode Ar code code ... +Define mapping values for character codes in hyphenation patterns. +This is a groff extension and currently ignored. +.It Ic \&hw Ar word ... +Specify hyphenation points in words. +Currently ignored. +.It Ic \&hy Op Ar mode +Set automatic hyphenation mode. +Currently ignored. +.It Ic \&hylang Ar language +Set hyphenation language. +This is a Heirloom extension and currently ignored. +.It Ic \&hylen Ar nchar +Minimum word length for hyphenation. +This is a Heirloom extension and currently ignored. +.It Ic \&hym Op Ar length +Set hyphenation margin. +This is a groff extension and currently ignored. +.It Ic \&hypp Ar penalty ... +Define hyphenation penalties. +This is a Heirloom extension and currently ignored. +.It Ic \&hys Op Ar length +Set hyphenation space. +This is a groff extension and currently ignored. +.It Ic \&ie Ar condition body +The +.Dq if +half of an if/else conditional. +The result of the conditional is pushed into a stack used by subsequent +invocations of +.Ic \&el , +which may be separated by any intervening input (or not exist at all). +Its syntax is equivalent to +.Ic \&if . +.It Ic \&if Ar condition body +Begin a conditional. +This request can also be written as follows: +.Bd -unfilled -offset indent +.Pf . Ic \&if Ar condition No \e{ Ns Ar body +.Ar body ... Ns \e} +.Ed +.Bd -unfilled -offset indent +.Pf . Ic \&if Ar condition No \e{\e +.Ar body ... +.Pf . No \e} +.Ed +.Pp +The +.Ar condition +is a boolean expression. +Currently, +.Xr mandoc 1 +supports the following subset of roff conditionals: +.Bl -bullet +.It +If +.Sq \&! +is prefixed to +.Ar condition , +it is logically inverted. +.It +If the first character of +.Ar condition +is +.Sq n +.Pq nroff mode +or +.Sq o +.Pq odd page , +it evaluates to true, and the +.Ar body +starts with the next character. +.It +If the first character of +.Ar condition +is +.Sq e +.Pq even page , +.Sq t +.Pq troff mode , +or +.Sq v +.Pq vroff mode , +it evaluates to false, and the +.Ar body +starts with the next character. +.It +If the first character of +.Ar condition +is +.Sq c +.Pq character available , +it evaluates to true if the following character is an ASCII character +or a valid character escape sequence, or to false otherwise. +The +.Ar body +starts with the character following that next character. +.It +If the first character of +.Ar condition +is +.Sq d , +it evaluates to true if the rest of +.Ar condition +is the name of an existing user defined macro or string; +otherwise, it evaluates to false. +.It +If the first character of +.Ar condition +is +.Sq r , +it evaluates to true if the rest of +.Ar condition +is the name of an existing number register; +otherwise, it evaluates to false. +.It +If the +.Ar condition +starts with a parenthesis or with an optionally signed +integer number, it is evaluated according to the rules of +.Sx Numerical expressions +explained below. +It evaluates to true if the result is positive, +or to false if the result is zero or negative. +.It +Otherwise, the first character of +.Ar condition +is regarded as a delimiter and it evaluates to true if the string +extending from its first to its second occurrence is equal to the +string extending from its second to its third occurrence. +.It +If +.Ar condition +cannot be parsed, it evaluates to false. +.El +.Pp +If a conditional is false, its children are not processed, but are +syntactically interpreted to preserve the integrity of the input +document. +Thus, +.Pp +.D1 \&.if t .ig +.Pp +will discard the +.Sq \&.ig , +which may lead to interesting results, but +.Pp +.D1 \&.if t .if t \e{\e +.Pp +will continue to syntactically interpret to the block close of the final +conditional. +Sub-conditionals, in this case, obviously inherit the truth value of +the parent. +.Pp +If the +.Ar body +section is begun by an escaped brace +.Sq \e{ , +scope continues until the end of the input line containing the +matching closing-brace escape sequence +.Sq \e} . +If the +.Ar body +is not enclosed in braces, scope continues until the end of the line. +If the +.Ar condition +is followed by a +.Ar body +on the same line, whether after a brace or not, then requests and macros +.Em must +begin with a control character. +It is generally more intuitive, in this case, to write +.Bd -unfilled -offset indent +.Pf . Ic \&if Ar condition No \e{\e +.Pf . Ar request +.Pf . No \e} +.Ed +.Pp +than having the request or macro follow as +.Pp +.D1 Pf . Ic \&if Ar condition Pf \e{. Ar request +.Pp +The scope of a conditional is always parsed, but only executed if the +conditional evaluates to true. +.Pp +Note that the +.Sq \e} +is converted into a zero-width escape sequence if not passed as a +standalone macro +.Sq \&.\e} . +For example, +.Pp +.D1 \&.Fl a \e} b +.Pp +will result in +.Sq \e} +being considered an argument of the +.Sq \&Fl +macro. +.It Ic \&ig Op Ar endmacro +Ignore input. +Its syntax can be either +.Bd -literal -offset indent +.Pf . Cm \&ig +.Ar ignored text +\&.. +.Ed +.Pp +or +.Bd -literal -offset indent +.Pf . Cm \&ig Ar endmacro +.Ar ignored text +.Pf . Ar endmacro +.Ed +.Pp +In the first case, input is ignored until a +.Sq \&.. +request is encountered on its own line. +In the second case, input is ignored until the specified +.Sq Pf . Ar endmacro +is encountered. +Do not use the escape character +.Sq \e +anywhere in the definition of +.Ar endmacro ; +it would cause very strange behaviour. +.Pp +When the +.Ar endmacro +is a roff request or a roff macro, like in +.Pp +.D1 \&.ig if +.Pp +the subsequent invocation of +.Ic \&if +will first terminate the +.Ar ignored text , +then be invoked as usual. +Otherwise, it only terminates the +.Ar ignored text , +and arguments following it or the +.Sq \&.. +request are discarded. +.It Ic \&in Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width +Change indentation. +See +.Xr man 7 . +Ignored in +.Xr mdoc 7 . +.It Ic \&index Ar register stringname substring +Find a substring in a string. +This is a Heirloom extension and currently unsupported. +.It Ic \&it Ar expression macro +Set an input line trap. +The named +.Ar macro +will be invoked after processing the number of input text lines +specified by the numerical +.Ar expression . +While evaluating the +.Ar expression , +the unit suffixes described below +.Sx Scaling Widths +are ignored. +.It Ic \&itc Ar expression macro +Set an input line trap, not counting lines ending with \ec. +Currently unsupported. +.It Ic \&IX Ar class keystring +To support the generation of a table of contents, +.Xr pod2man 1 +emits this user-defined macro, usually without defining it. +To avoid reporting large numbers of spurious errors, +.Xr mandoc 1 +ignores it. +.It Ic \&kern Op Cm 1 | 0 +Switch kerning on or off. +Currently ignored. +.It Ic \&kernafter Ar font char ... afmunits ... +Increase kerning after some characters. +This is a Heirloom extension and currently ignored. +.It Ic \&kernbefore Ar font char ... afmunits ... +Increase kerning before some characters. +This is a Heirloom extension and currently ignored. +.It Ic \&kernpair Ar font char ... font char ... afmunits +Add a kerning pair to the kerning table. +This is a Heirloom extension and currently ignored. +.It Ic \&lc Op Ar glyph +Define a leader repetition character. +Currently unsupported. +.It Ic \&lc_ctype Ar localename +Set the +.Dv LC_CTYPE +locale. +This is a Heirloom extension and currently unsupported. +.It Ic \&lds Ar macroname string +Define a local string. +This is a Heirloom extension and currently unsupported. +.It Ic \&length Ar register string +Count the number of input characters in a string. +Currently unsupported. +.It Ic \&letadj Ar lspmin lshmin letss lspmax lshmax +Dynamic letter spacing and reshaping. +This is a Heirloom extension and currently ignored. +.It Ic \&lf Ar lineno Op Ar filename +Change the line number for error messages. +Ignored because insecure. +.It Ic \&lg Op Cm 1 | 0 +Switch the ligature mechanism on or off. +Currently ignored. +.It Ic \&lhang Ar font char ... afmunits +Hang characters at left margin. +This is a Heirloom extension and currently ignored. +.It Ic \&linetabs Op Cm 1 | 0 +Enable or disable line-tabs mode. +This is a groff extension and currently unsupported. +.It Ic \&ll Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width +Change the output line length. +If the +.Ar width +argument is omitted, the line length is reset to its previous value. +The default setting for terminal output is 78n. +If a sign is given, the line length is added to or subtracted from; +otherwise, it is set to the provided value. +Using this request in new manuals is discouraged for several reasons, +among others because it overrides the +.Xr mandoc 1 +.Fl O Cm width +command line option. +.It Ic \&lnr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar value Op Ar increment +Set local number register. +This is a Heirloom extension and currently unsupported. +.It Ic \&lnrf Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar value Op Ar increment +Set local floating-point register. +This is a Heirloom extension and currently unsupported. +.It Ic \&lpfx Ar string +Set a line prefix. +This is a Heirloom extension and currently unsupported. +.It Ic \&ls Op Ar factor +Set line spacing. +It takes one integer argument specifying the vertical distance of +subsequent output text lines measured in v units. +Currently ignored. +.It Ic \&lsm Ar macroname +Set a leading spaces trap. +This is a groff extension and currently unsupported. +.It Ic \< Op Oo Cm + Ns | Ns Cm - Oc Ns Ar width +Set title line length. +Currently ignored. +.It Ic \&mc Ar glyph Op Ar dist +Print margin character in the right margin. +The +.Ar dist +is currently ignored; instead, 1n is used. +.It Ic \&mediasize Ar media +Set the device media size. +This is a Heirloom extension and currently ignored. +.It Ic \&minss Ar width +Set minimum word space. +This is a Heirloom extension and currently ignored. +.It Ic \&mk Op Ar register +Mark vertical position. +Currently ignored. +.It Ic \&mso Ar filename +Load a macro file using the search path. +Ignored because insecure. +.It Ic \&na +Disable adjusting without changing the adjustment mode. +Currently ignored. +.It Ic \&ne Op Ar height +Declare the need for the specified minimum vertical space +before the next trap or the bottom of the page. +Currently ignored. +.It Ic \&nf +Break the output line and switch to no-fill mode. +Subsequent input lines are kept together on the same output line +even when exceeding the right margin, +and line breaks in subsequent input cause output line breaks. +This request is implied by the +.Xr mdoc 7 +.Ic \&Bd Fl unfilled +and +.Ic \&Bd Fl literal +macros and by the +.Xr man 7 +.Ic \&EX +macro. +The +.Ic \&fi +request switches back to the default fill mode. +.It Ic \&nh +Turn off automatic hyphenation mode. +Currently ignored. +.It Ic \&nhychar Ar char ... +Define hyphenation-inhibiting characters. +This is a Heirloom extension and currently ignored. +.It Ic \&nm Op Ar start Op Ar inc Op Ar space Op Ar indent +Print line numbers. +Currently unsupported. +.It Ic \&nn Op Ar number +Temporarily turn off line numbering. +Currently unsupported. +.It Ic \&nop Ar body +Execute the rest of the input line as a request, macro, or text line, +skipping the +.Ic \&nop +request and any space characters immediately following it. +This is mostly used to indent text lines inside macro definitions. +.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression Op Ar stepsize +Define or change a register. +A register is an arbitrary string value that defines some sort of state, +which influences parsing and/or formatting. +For the syntax of +.Ar expression , +see +.Sx Numerical expressions +below. +If it is prefixed by a sign, the register will be +incremented or decremented instead of assigned to. +.Pp +The +.Ar stepsize +is used by the +.Ic \en+ +auto-increment feature. +It remains unchanged when omitted while changing an existing register, +and it defaults to 0 when defining a new register. +.Pp +The following +.Ar register +is handled specially: +.Bl -tag -width Ds +.It Cm nS +If set to a positive integer value, certain +.Xr mdoc 7 +macros will behave in the same way as in the +.Em SYNOPSIS +section. +If set to 0, these macros will behave in the same way as outside the +.Em SYNOPSIS +section, even when called within the +.Em SYNOPSIS +section itself. +Note that starting a new +.Xr mdoc 7 +section with the +.Ic \&Sh +macro will reset this register. +.El +.It Xo +.Ic \&nrf Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression +.Op Ar increment +.Xc +Define or change a floating-point register. +This is a Heirloom extension and currently unsupported. +.It Ic \&nroff +Force nroff mode. +This is a groff extension and currently ignored. +.It Ic \&ns +Turn on no-space mode. +Currently ignored. +.It Ic \&nx Op Ar filename +Abort processing of the current input file and process another one. +Ignored because insecure. +.It Ic \&open Ar stream file +Open a file for writing. +Ignored because insecure. +.It Ic \&opena Ar stream file +Open a file for appending. +Ignored because insecure. +.It Ic \&os +Output saved vertical space. +Currently ignored. +.It Ic \&output Ar string +Output directly to intermediate output. +Not supported. +.It Ic \&padj Op Cm 1 | 0 +Globally control paragraph-at-once adjustment. +This is a Heirloom extension and currently ignored. +.It Ic \&papersize Ar media +Set the paper size. +This is a Heirloom extension and currently ignored. +.It Ic \&pc Op Ar char +Change the page number character. +Currently ignored. +.It Ic \&pev +Print environments. +This is a groff extension and currently ignored. +.It Ic \&pi Ar command +Pipe output to a shell command. +Ignored because insecure. +.It Ic \&PI +Low-level request used by +.Ic \&BP . +This is a Heirloom extension and currently unsupported. +.It Ic \&pl Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height +Change page length. +Currently ignored. +.It Ic \&pm +Print names and sizes of macros, strings, and diversions +to standard error output. +Currently ignored. +.It Ic \&pn Oo Cm + Ns | Ns Cm - Oc Ns Ar number +Change the page number of the next page. +Currently ignored. +.It Ic \&pnr +Print all number registers on standard error output. +Currently ignored. +.It Ic \&po Op Oo Cm + Ns | Ns Cm - Oc Ns Ar offset +Set a horizontal page offset. +If no argument is specified, the page offset is reverted to its +previous value. +If a sign is specified, the new page offset is calculated relative +to the current one; otherwise, it is absolute. +The argument follows the syntax of +.Sx Scaling Widths +and the default scaling unit is +.Cm m . +.It Ic \&ps Op Oo Cm + Ns | Ns Cm - Oc Ns size +Change point size. +Currently ignored. +.It Ic \&psbb Ar filename +Retrieve the bounding box of a PostScript file. +Currently unsupported. +.It Ic \&pshape Ar indent length ... +Set a special shape for the current paragraph. +This is a Heirloom extension and currently unsupported. +.It Ic \&pso Ar command +Include output of a shell command. +Ignored because insecure. +.It Ic \&ptr +Print the names and positions of all traps on standard error output. +This is a groff extension and currently ignored. +.It Ic \&pvs Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height +Change post-vertical spacing. +This is a groff extension and currently ignored. +.It Ic \&rchar Ar glyph ... +Remove glyph definitions. +Currently unsupported. +.It Ic \&rd Op Ar prompt Op Ar argument ... +Read from standard input. +Currently ignored. +.It Ic \&recursionlimit Ar maxrec maxtail +Set the maximum stack depth for recursive macros. +This is a Heirloom extension and currently ignored. +.It Ic \&return Op Ar twice +Exit the presently executed macro and return to the caller. +The argument is currently ignored. +.It Ic \&rfschar Ar font glyph ... +Remove font-specific fallback glyph definitions. +Currently unsupported. +.It Ic \&rhang Ar font char ... afmunits +Hang characters at right margin. +This is a Heirloom extension and currently ignored. +.It Ic \&rj Op Ar N +Justify the next +.Ar N +input lines to the right margin without filling. +.Ar N +defaults to 1. +An argument of 0 or less ends right adjustment. +.It Ic \&rm Ar macroname +Remove a request, macro or string. +.It Ic \&rn Ar oldname newname +Rename a request, macro, diversion, or string. +In +.Xr mandoc 1 , +user-defined macros, +.Xr mdoc 7 +and +.Xr man 7 +macros, and user-defined strings can be renamed, but renaming of +predefined strings and of +.Nm +requests is not supported, and diversions are not implemented at all. +.It Ic \&rnn Ar oldname newname +Rename a number register. +Currently unsupported. +.It Ic \&rr Ar register +Remove a register. +.It Ic \&rs +End no-space mode. +Currently ignored. +.It Ic \&rt Op Ar dist +Return to marked vertical position. +Currently ignored. +.It Ic \&schar Ar glyph Op Ar string +Define global fallback glyph. +This is a groff extension and currently unsupported. +.It Ic \&sentchar Ar char ... +Define sentence-ending characters. +This is a Heirloom extension and currently ignored. +.It Ic \&shc Op Ar glyph +Change the soft hyphen character. +Currently ignored. +.It Ic \&shift Op Ar number +Shift macro arguments +.Ar number +times, by default once: \e\e$i becomes what \e\e$i+number was. +Also decrement \en(.$ by +.Ar number . +.It Ic \&sizes Ar size ... +Define permissible point sizes. +This is a groff extension and currently ignored. +.It Ic \&so Ar filename +Include a source file. +The file is read and its contents processed as input in place of the +.Ic \&so +request line. +To avoid inadvertent inclusion of unrelated files, +.Xr mandoc 1 +only accepts relative paths not containing the strings +.Qq ../ +and +.Qq /.. . +.Pp +This request requires +.Xr man 1 +to change to the right directory before calling +.Xr mandoc 1 , +per convention to the root of the manual tree. +Typical usage looks like: +.Pp +.Dl \&.so man3/Xcursor.3 +.Pp +As the whole concept is rather fragile, the use of +.Ic \&so +is discouraged. +Use +.Xr ln 1 +instead. +.It Ic \&sp Op Ar height +Break the output line and emit vertical space. +The argument follows the syntax of +.Sx Scaling Widths +and defaults to one blank line +.Pq Li 1v . +.It Ic \&spacewidth Op Cm 1 | 0 +Set the space width from the font metrics file. +This is a Heirloom extension and currently ignored. +.It Ic \&special Op Ar font ... +Define a special font. +This is a groff extension and currently ignored. +.It Ic \&spreadwarn Op Ar width +Warn about wide spacing between words. +Currently ignored. +.It Ic \&ss Ar wordspace Op Ar sentencespace +Set space character size. +Currently ignored. +.It Ic \&sty Ar position style +Associate style with a font position. +This is a groff extension and currently ignored. +.It Ic \&substring Ar stringname startpos Op Ar endpos +Replace a user-defined string with a substring. +Currently unsupported. +.It Ic \&sv Op Ar height +Save vertical space. +Currently ignored. +.It Ic \&sy Ar command +Execute shell command. +Ignored because insecure. +.It Ic \&T& +Re-start a table layout, retaining the options of the prior table +invocation. +See +.Ic \&TS . +.It Ic \&ta Op Ar width ... Op Cm T Ar width ... +Set tab stops. +Each +.Ar width +argument follows the syntax of +.Sx Scaling Widths . +If prefixed by a plus sign, it is relative to the previous tab stop. +The arguments after the +.Cm T +marker are used repeatedly as often as needed; for each reuse, +they are taken relative to the last previously established tab stop. +When +.Ic \&ta +is called without arguments, all tab stops are cleared. +.It Ic \&tc Op Ar glyph +Change tab repetition character. +Currently unsupported. +.It Ic \&TE +End a table context. +See +.Ic \&TS . +.It Ic \&ti Oo Cm + Ns | Ns Cm - Oc Ns Ar width +Break the output line and indent the next output line by +.Ar width . +If a sign is specified, the temporary indentation is calculated +relative to the current indentation; otherwise, it is absolute. +The argument follows the syntax of +.Sx Scaling Widths +and the default scaling unit is +.Cm m . +.It Ic \&tkf Ar font minps width1 maxps width2 +Enable track kerning for a font. +Currently ignored. +.It Ic \&tl No \& Ap Ar left Ap Ar center Ap Ar right Ap +Print a title line. +Currently unsupported. +.It Ic \&tm Ar string +Print to standard error output. +Currently ignored. +.It Ic \&tm1 Ar string +Print to standard error output, allowing leading blanks. +This is a groff extension and currently ignored. +.It Ic \&tmc Ar string +Print to standard error output without a trailing newline. +This is a groff extension and currently ignored. +.It Ic \&tr Ar glyph glyph ... +Output character translation. +The first glyph in each pair is replaced by the second one. +Character escapes can be used; for example, +.Pp +.Dl tr \e(xx\e(yy +.Pp +replaces all invocations of \e(xx with \e(yy. +.It Ic \&track Ar font minps width1 maxps width2 +Static letter space tracking. +This is a Heirloom extension and currently ignored. +.It Ic \&transchar Ar char ... +Define transparent characters for sentence-ending. +This is a Heirloom extension and currently ignored. +.It Ic \&trf Ar filename +Output the contents of a file, disallowing invalid characters. +This is a groff extension and ignored because insecure. +.It Ic \&trimat Ar left top width height +Set the TrimBox page parameter for PDF generation. +This is a Heirloom extension and currently ignored. +.It Ic \&trin Ar glyph glyph ... +Output character translation, ignored by +.Ic \&asciify . +Currently unsupported. +.It Ic \&trnt Ar glyph glyph ... +Output character translation, ignored by \e!. +Currently unsupported. +.It Ic \&troff +Force troff mode. +This is a groff extension and currently ignored. +.It Ic \&TS +Begin a table, which formats input in aligned rows and columns. +See +.Xr tbl 7 +for a description of the tbl language. +.It Ic \&uf Ar font +Globally set the underline font. +Currently ignored. +.It Ic \&ul Op Ar N +Underline next +.Ar N +input lines. +Currently ignored. +.It Ic \&unformat Ar divname +Unformat spaces and tabs in a diversion. +Currently unsupported. +.It Ic \&unwatch Ar macroname +Disable notification for string or macro. +This is a Heirloom extension and currently ignored. +.It Ic \&unwatchn Ar register +Disable notification for register. +This is a Heirloom extension and currently ignored. +.It Ic \&vpt Op Cm 1 | 0 +Enable or disable vertical position traps. +This is a groff extension and currently ignored. +.It Ic \&vs Op Oo Cm + Ns | Ns Cm - Oc Ns Ar height +Change vertical spacing. +Currently ignored. +.It Ic \&warn Ar flags +Set warning level. +Currently ignored. +.It Ic \&warnscale Ar si +Set the scaling indicator used in warnings. +This is a groff extension and currently ignored. +.It Ic \&watch Ar macroname +Notify on change of string or macro. +This is a Heirloom extension and currently ignored. +.It Ic \&watchlength Ar maxlength +On change, report the contents of macros and strings +up to the specified length. +This is a Heirloom extension and currently ignored. +.It Ic \&watchn Ar register +Notify on change of register. +This is a Heirloom extension and currently ignored. +.It Ic \&wh Ar dist Op Ar macroname +Set a page location trap. +Currently unsupported. +.It Ic \&while Ar condition body +Repeated execution while a +.Ar condition +is true, with syntax similar to +.Ic \&if . +Currently implemented with two restrictions: cannot nest, +and each loop must start and end in the same scope. +.It Ic \&write Oo \(dq Oc Ns Ar string +Write to an open file. +Ignored because insecure. +.It Ic \&writec Oo \(dq Oc Ns Ar string +Write to an open file without appending a newline. +Ignored because insecure. +.It Ic \&writem Ar macroname +Write macro or string to an open file. +Ignored because insecure. +.It Ic \&xflag Ar level +Set the extension level. +This is a Heirloom extension and currently ignored. +.El +.Ss Numerical expressions +The +.Ic \&nr , +.Ic \&if , +and +.Ic \&ie +requests accept integer numerical expressions as arguments. +These are always evaluated using the C +.Vt int +type; integer overflow works the same way as in the C language. +Numbers consist of an arbitrary number of digits +.Sq 0 +to +.Sq 9 +prefixed by an optional sign +.Sq + +or +.Sq - . +Each number may be followed by one optional scaling unit described below +.Sx Scaling Widths . +The following equations hold: +.Bd -literal -offset indent +1i = 6v = 6P = 10m = 10n = 72p = 1000M = 240u = 240 +254c = 100i = 24000u = 24000 +1f = 65536u = 65536 +.Ed +.Pp +The following binary operators are implemented. +Unless otherwise stated, they behave as in the C language: +.Pp +.Bl -tag -width 2n -compact +.It Ic + +addition +.It Ic - +subtraction +.It Ic * +multiplication +.It Ic / +division +.It Ic % +remainder of division +.It Ic < +less than +.It Ic > +greater than +.It Ic == +equal to +.It Ic = +equal to, same effect as +.Ic == +(this differs from C) +.It Ic <= +less than or equal to +.It Ic >= +greater than or equal to +.It Ic <> +not equal to (corresponds to C +.Ic != ; +this one is of limited portability, it is supported by Heirloom roff, +but not by groff) +.It Ic & +logical and (corresponds to C +.Ic && ) +.It Ic \&: +logical or (corresponds to C +.Ic || ) +.It Ic ? +maximum (not available in C) +.El +.Pp +There is no concept of precedence; evaluation proceeds from left to right, +except when subexpressions are enclosed in parentheses. +Inside parentheses, whitespace is ignored. +.Sh ESCAPE SEQUENCE REFERENCE +The +.Xr mandoc 1 +.Nm +parser recognises the following escape sequences. +In +.Xr mdoc 7 +and +.Xr man 7 +documents, using escape sequences is discouraged except for those +described in the +.Sx LANGUAGE SYNTAX +section above. +.Pp +A backslash followed by any character not listed here +simply prints that character itself. +.Bl -tag -width Ds +.It Ic \e +A backslash at the end of an input line can be used to continue the +logical input line on the next physical input line, joining the text +on both lines together as if it were on a single input line. +.It Ic \e +The escape sequence backslash-space +.Pq Sq \e\ \& +is an unpaddable space-sized non-breaking space character; see +.Sx Whitespace +and +.Xr mandoc_char 7 . +.It Ic \e! +Embed text up to and including the end of the input line into the +current diversion or into intermediate output without interpreting +requests, macros, and escapes. +Currently unsupported. +.It Ic \e\(dq +The rest of the input line is treated as +.Sx Comments . +.It Ic \e# +Line continuation with comment. +Discard the rest of the physical input line and continue the logical +input line on the next physical input line, joining the text on +both lines together as if it were on a single input line. +This is a groff extension. +.It Ic \e$ Ns Ar arg +Macro argument expansion, see +.Ic \&de . +.It Ic \e% +Hyphenation allowed at this point of the word; ignored by +.Xr mandoc 1 . +.It Ic \e& +Non-printing zero-width character, +often used for various kinds of escaping; see +.Sx Whitespace , +.Xr mandoc_char 7 , +and the +.Dq MACRO SYNTAX +and +.Dq Delimiters +sections in +.Xr mdoc 7 . +.It Ic \e\(aq +Acute accent special character; use +.Ic \e(aa +instead. +.It Ic \e( Ns Ar cc +.Sx Special Characters +with two-letter names, see +.Xr mandoc_char 7 . +.It Ic \e) +Zero-width space transparent to end-of-sentence detection; +ignored by +.Xr mandoc 1 . +.It Ic \e*[ Ns Ar name Ns Ic \&] +Interpolate the string with the +.Ar name . +For short names, there are variants +.Ic \e* Ns Ar c +and +.Ic \e*( Ns Ar cc . +.Pp +One string is predefined on the +.Nm +language level: +.Ic \e*(.T +expands to the name of the output device, +for example ascii, utf8, ps, pdf, html, or markdown. +.Pp +Macro sets traditionally predefine additional strings which are not +portable and differ across implementations. +Those supported by +.Xr mandoc 1 +are listed in +.Xr mandoc_char 7 . +.Pp +Strings can be defined, changed, and deleted with the +.Ic \&ds , +.Ic \&as , +and +.Ic \&rm +requests. +.It Ic \e, +Left italic correction (groff extension); ignored by +.Xr mandoc 1 . +.It Ic \e- +Special character +.Dq mathematical minus sign ; +see +.Xr mandoc_char 7 +for details. +.It Ic \e/ +Right italic correction (groff extension); ignored by +.Xr mandoc 1 . +.It Ic \e: +Breaking the line is allowed at this point of the word +without inserting a hyphen. +.It Ic \e? +Embed the text up to the next +.Ic \e? +into the current diversion without interpreting requests, macros, +and escapes. +This is a groff extension and currently unsupported. +.It Ic \e[ Ns Ar name Ns Ic \&] +.Sx Special Characters +with names of arbitrary length, see +.Xr mandoc_char 7 . +.It Ic \e^ +One-twelfth em half-narrow space character, effectively zero-width in +.Xr mandoc 1 . +.It Ic \e_ +Underline special character; use +.Ic \e(ul +instead. +.It Ic \e` +Grave accent special character; use +.Ic \e(ga +instead. +.It Ic \e{ +Begin conditional input; see +.Ic \&if . +.It Ic \e\(ba +One-sixth em narrow space character, effectively zero-width in +.Xr mandoc 1 . +.It Ic \e} +End conditional input; see +.Ic \&if . +.It Ic \e~ +Paddable non-breaking space character. +.It Ic \e0 +Digit width space character. +.It Ic \eA\(aq Ns Ar string Ns Ic \(aq +Anchor definition; ignored by +.Xr mandoc 1 . +.It Ic \ea +Leader character; ignored by +.Xr mandoc 1 . +.It Ic \eB\(aq Ns Ar string Ns Ic \(aq +Interpolate +.Sq 1 +if +.Ar string +conforms to the syntax of +.Sx Numerical expressions +explained above or +.Sq 0 +otherwise. +.It Ic \eb\(aq Ns Ar string Ns Ic \(aq +Bracket building function; ignored by +.Xr mandoc 1 . +.It Ic \eC\(aq Ns Ar name Ns Ic \(aq +.Sx Special Characters +with names of arbitrary length. +.It Ic \ec +When encountered at the end of an input text line, +the next input text line is considered to continue that line, +even if there are request or macro lines in between. +No whitespace is inserted. +.It Ic \eD\(aq Ns Ar string Ns Ic \(aq +Draw graphics function; ignored by +.Xr mandoc 1 . +.It Ic \ed +Move down by half a line; ignored by +.Xr mandoc 1 . +.It Ic \eE +Escape character intended to not be interpreted in copy mode. +In +.Xr mandoc 1 , +it currently does the same as +.Ic \e +itself. +.It Ic \ee +Backslash special character. +.It Ic \eF[ Ns Ar name Ns Ic \&] +Switch font family (groff extension); ignored by +.Xr mandoc 1 . +For short names, there are variants +.Ic \eF Ns Ar c +and +.Ic \eF( Ns Ar cc . +.It Ic \ef[ Ns Ar name Ns Ic \&] +Switch to the font +.Ar name , +see +.Sx Font Selection . +For short names, there are variants +.Ic \ef Ns Ar c +and +.Ic \ef( Ns Ar cc . +An empty name +.Ic \ef[] +defaults to +.Ic \efP . +.It Ic \eg[ Ns Ar name Ns Ic \&] +Interpolate the format of a number register; ignored by +.Xr mandoc 1 . +For short names, there are variants +.Ic \eg Ns Ar c +and +.Ic \eg( Ns Ar cc . +.It Ic \eH\(aq Ns Oo +|- Oc Ns Ar number Ns Ic \(aq +Set the height of the current font; ignored by +.Xr mandoc 1 . +.It Ic \eh\(aq Ns Oo Cm \&| Oc Ns Ar width Ns Ic \(aq +Horizontal motion. +If the vertical bar is given, the motion is relative to the current +indentation. +Otherwise, it is relative to the current position. +The default scaling unit is +.Cm m . +.It Ic \ek[ Ns Ar name Ns Ic \&] +Mark horizontal input place in register; ignored by +.Xr mandoc 1 . +For short names, there are variants +.Ic \ek Ns Ar c +and +.Ic \ek( Ns Ar cc . +.It Ic \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns Ic \(aq +Vertical line drawing function; ignored by +.Xr mandoc 1 . +.It Ic \el\(aq Ns Ar width Ns Oo Ar c Oc Ns Ic \(aq +Draw a horizontal line of +.Ar width +using the glyph +.Ar c . +.It Ic \eM[ Ns Ar name Ns Ic \&] +Set fill (background) color (groff extension); ignored by +.Xr mandoc 1 . +For short names, there are variants +.Ic \eM Ns Ar c +and +.Ic \eM( Ns Ar cc . +.It Ic \em[ Ns Ar name Ns Ic \&] +Set glyph drawing color (groff extension); ignored by +.Xr mandoc 1 . +For short names, there are variants +.Ic \em Ns Ar c +and +.Ic \em( Ns Ar cc . +.It Ic \eN\(aq Ns Ar number Ns Ic \(aq +Character +.Ar number +on the current font. +.It Ic \en Ns Oo +|- Oc Ns Ic \&[ Ns Ar name Ns Ic \&] +Interpolate the number register +.Ar name . +For short names, there are variants +.Ic \en Ns Ar c +and +.Ic \en( Ns Ar cc . +If the optional sign is specified, +the register is first incremented or decremented by the +.Ar stepsize +that was specified in the relevant +.Ic \&nr +request, and the changed value is interpolated. +.It Ic \eO Ns Ar digit , Ic \eO[5 Ns arguments Ns Ic \&] +Suppress output. +This is a groff extension and currently unsupported. +With an argument of +.Ic 1 , 2 , 3 , +or +.Ic 4 , +it is ignored. +.It Ic \eo\(aq Ns Ar string Ns Ic \(aq +Overstrike, writing all the characters contained in the +.Ar string +to the same output position. +In terminal and HTML output modes, +only the last one of the characters is visible. +.It Ic \ep +Break the output line at the end of the current word. +.It Ic \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns Ic \(aq +Set number register; ignored by +.Xr mandoc 1 . +.It Ic \er +Move up by one line; ignored by +.Xr mandoc 1 . +.It Ic \eS\(aq Ns Ar number Ns Ic \(aq +Slant output; ignored by +.Xr mandoc 1 . +.It Ic \es\(aq Ns Oo +|- Oc Ns Ar number Ns Ic \(aq +Change point size; ignored by +.Xr mandoc 1 . +Alternative forms +.Ic \es Ns Oo +|- Oc Ns Ar n , +.Ic \es Ns Oo +|- Oc Ns Ic \(aq Ns Ar number Ns Ic \(aq , +.Ic \es[ Ns Oo +|- Oc Ns Ar number Ns Ic \&] , +and +.Ic \es Ns Oo +|- Oc Ns Ic \&[ Ns Ar number Ns Ic \&] +are also parsed and ignored. +.It Ic \et +Horizontal tab; ignored by +.Xr mandoc 1 . +.It Ic \eu +Move up by half a line; ignored by +.Xr mandoc 1 . +.It Ic \eV[ Ns Ar name Ns Ic \&] +Interpolate an environment variable; ignored by +.Xr mandoc 1 . +For short names, there are variants +.Ic \eV Ns Ar c +and +.Ic \eV( Ns Ar cc . +.It Ic \ev\(aq Ns Ar number Ns Ic \(aq +Vertical motion; ignored by +.Xr mandoc 1 . +.It Ic \ew\(aq Ns Ar string Ns Ic \(aq +Interpolate the width of the +.Ar string . +The +.Xr mandoc 1 +implementation assumes that after expansion of user-defined strings, the +.Ar string +only contains normal characters, no escape sequences, and that each +character has a width of 24 basic units. +.It Ic \eX\(aq Ns Ar string Ns Ic \(aq +Output +.Ar string +as device control function; ignored in nroff mode and by +.Xr mandoc 1 . +.It Ic \ex\(aq Ns Ar number Ns Ic \(aq +Extra line space function; ignored by +.Xr mandoc 1 . +.It Ic \eY[ Ns Ar name Ns Ic \&] +Output a string as a device control function; ignored in nroff mode and by +.Xr mandoc 1 . +For short names, there are variants +.Ic \eY Ns Ar c +and +.Ic \eY( Ns Ar cc . +.It Ic \eZ\(aq Ns Ar string Ns Ic \(aq +Print +.Ar string +with zero width and height; ignored by +.Xr mandoc 1 . +.It Ic \ez +Output the next character without advancing the cursor position. +.El +.Sh COMPATIBILITY +The +.Xr mandoc 1 +implementation of the +.Nm +language is incomplete. +Major unimplemented features include: +.Pp +.Bl -dash -compact +.It +For security reasons, +.Xr mandoc 1 +never reads or writes external files except via +.Ic \&so +requests with safe relative paths. +.It +There is no automatic hyphenation, no adjustment to the right margin, +and very limited support for centering; the output is always set flush-left. +.It +Support for setting tabulator and leader characters is missing, +and support for manually changing indentation is limited. +.It +The +.Sq u +scaling unit is the default terminal unit. +In traditional troff systems, this unit changes depending on the +output media. +.It +Width measurements are implemented in a crude way +and often yield wrong results. +Support for explicit movement requests and escapes is limited. +.It +There is no concept of output pages, no support for floats, +graphics drawing, and picture inclusion; +terminal output is always continuous. +.It +Requests regarding color, font families, font sizes, +and glyph manipulation are ignored. +Font support is very limited. +Kerning is not implemented, and no ligatures are produced. +.It +The +.Qq \(aq +macro control character does not suppress output line breaks. +.It +Diversions and environments are not implemented, +and support for traps is very incomplete. +.It +Use of macros is not supported inside +.Xr tbl 7 +code. +.El +.Pp +The special semantics of the +.Cm nS +number register is an idiosyncrasy of +.Ox +manuals and not supported by other +.Xr mdoc 7 +implementations. +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr eqn 7 , +.Xr man 7 , +.Xr mandoc_char 7 , +.Xr mdoc 7 , +.Xr tbl 7 +.Rs +.%A Joseph F. Ossanna +.%A Brian W. Kernighan +.%I AT&T Bell Laboratories +.%T Troff User's Manual +.%R Computing Science Technical Report +.%N 54 +.%C Murray Hill, New Jersey +.%D 1976 and 1992 +.%U http://www.kohala.com/start/troff/cstr54.ps +.Re +.Rs +.%A Joseph F. Ossanna +.%A Brian W. Kernighan +.%A Gunnar Ritter +.%T Heirloom Documentation Tools Nroff/Troff User's Manual +.%D September 17, 2007 +.%U http://heirloom.sourceforge.net/doctools/troff.pdf +.Re +.Sh HISTORY +The RUNOFF typesetting system, whose input forms the basis for +.Nm , +was written in MAD and FAP for the CTSS operating system by Jerome E. +Saltzer in 1964. +Doug McIlroy rewrote it in BCPL in 1969, renaming it +.Nm . +Dennis M. Ritchie rewrote McIlroy's +.Nm +in PDP-11 assembly for +.At v1 , +Joseph F. Ossanna improved roff and renamed it nroff +for +.At v2 , +then ported nroff to C as troff, which Brian W. Kernighan released with +.At v7 . +In 1989, James Clarke re-implemented troff in C++, naming it groff. +.Sh AUTHORS +.An -nosplit +This +.Nm +reference was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +and +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: vendor/mandoc/20190723/roff.7 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/roff.c =================================================================== --- vendor/mandoc/20190723/roff.c (nonexistent) +++ vendor/mandoc/20190723/roff.c (revision 350350) @@ -0,0 +1,4295 @@ +/* $Id: roff.c,v 1.366 2019/07/01 22:56:24 schwarze Exp $ */ +/* + * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons + * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "mandoc.h" +#include "roff.h" +#include "mandoc_parse.h" +#include "libmandoc.h" +#include "roff_int.h" +#include "tbl_parse.h" +#include "eqn_parse.h" + +/* + * ASCII_ESC is used to signal from roff_getarg() to roff_expand() + * that an escape sequence resulted from copy-in processing and + * needs to be checked or interpolated. As it is used nowhere + * else, it is defined here rather than in a header file. + */ +#define ASCII_ESC 27 + +/* Maximum number of string expansions per line, to break infinite loops. */ +#define EXPAND_LIMIT 1000 + +/* Types of definitions of macros and strings. */ +#define ROFFDEF_USER (1 << 1) /* User-defined. */ +#define ROFFDEF_PRE (1 << 2) /* Predefined. */ +#define ROFFDEF_REN (1 << 3) /* Renamed standard macro. */ +#define ROFFDEF_STD (1 << 4) /* mdoc(7) or man(7) macro. */ +#define ROFFDEF_ANY (ROFFDEF_USER | ROFFDEF_PRE | \ + ROFFDEF_REN | ROFFDEF_STD) +#define ROFFDEF_UNDEF (1 << 5) /* Completely undefined. */ + +/* --- data types --------------------------------------------------------- */ + +/* + * An incredibly-simple string buffer. + */ +struct roffstr { + char *p; /* nil-terminated buffer */ + size_t sz; /* saved strlen(p) */ +}; + +/* + * A key-value roffstr pair as part of a singly-linked list. + */ +struct roffkv { + struct roffstr key; + struct roffstr val; + struct roffkv *next; /* next in list */ +}; + +/* + * A single number register as part of a singly-linked list. + */ +struct roffreg { + struct roffstr key; + int val; + int step; + struct roffreg *next; +}; + +/* + * Association of request and macro names with token IDs. + */ +struct roffreq { + enum roff_tok tok; + char name[]; +}; + +/* + * A macro processing context. + * More than one is needed when macro calls are nested. + */ +struct mctx { + char **argv; + int argc; + int argsz; +}; + +struct roff { + struct roff_man *man; /* mdoc or man parser */ + struct roffnode *last; /* leaf of stack */ + struct mctx *mstack; /* stack of macro contexts */ + int *rstack; /* stack of inverted `ie' values */ + struct ohash *reqtab; /* request lookup table */ + struct roffreg *regtab; /* number registers */ + struct roffkv *strtab; /* user-defined strings & macros */ + struct roffkv *rentab; /* renamed strings & macros */ + struct roffkv *xmbtab; /* multi-byte trans table (`tr') */ + struct roffstr *xtab; /* single-byte trans table (`tr') */ + const char *current_string; /* value of last called user macro */ + struct tbl_node *first_tbl; /* first table parsed */ + struct tbl_node *last_tbl; /* last table parsed */ + struct tbl_node *tbl; /* current table being parsed */ + struct eqn_node *last_eqn; /* equation parser */ + struct eqn_node *eqn; /* active equation parser */ + int eqn_inline; /* current equation is inline */ + int options; /* parse options */ + int mstacksz; /* current size of mstack */ + int mstackpos; /* position in mstack */ + int rstacksz; /* current size limit of rstack */ + int rstackpos; /* position in rstack */ + int format; /* current file in mdoc or man format */ + char control; /* control character */ + char escape; /* escape character */ +}; + +/* + * A macro definition, condition, or ignored block. + */ +struct roffnode { + enum roff_tok tok; /* type of node */ + struct roffnode *parent; /* up one in stack */ + int line; /* parse line */ + int col; /* parse col */ + char *name; /* node name, e.g. macro name */ + char *end; /* custom end macro of the block */ + int endspan; /* scope to: 1=eol 2=next line -1=\} */ + int rule; /* content is: 1=evaluated 0=skipped */ +}; + +#define ROFF_ARGS struct roff *r, /* parse ctx */ \ + enum roff_tok tok, /* tok of macro */ \ + struct buf *buf, /* input buffer */ \ + int ln, /* parse line */ \ + int ppos, /* original pos in buffer */ \ + int pos, /* current pos in buffer */ \ + int *offs /* reset offset of buffer data */ + +typedef int (*roffproc)(ROFF_ARGS); + +struct roffmac { + roffproc proc; /* process new macro */ + roffproc text; /* process as child text of macro */ + roffproc sub; /* process as child of macro */ + int flags; +#define ROFFMAC_STRUCT (1 << 0) /* always interpret */ +}; + +struct predef { + const char *name; /* predefined input name */ + const char *str; /* replacement symbol */ +}; + +#define PREDEF(__name, __str) \ + { (__name), (__str) }, + +/* --- function prototypes ------------------------------------------------ */ + +static int roffnode_cleanscope(struct roff *); +static int roffnode_pop(struct roff *); +static void roffnode_push(struct roff *, enum roff_tok, + const char *, int, int); +static void roff_addtbl(struct roff_man *, int, struct tbl_node *); +static int roff_als(ROFF_ARGS); +static int roff_block(ROFF_ARGS); +static int roff_block_text(ROFF_ARGS); +static int roff_block_sub(ROFF_ARGS); +static int roff_break(ROFF_ARGS); +static int roff_cblock(ROFF_ARGS); +static int roff_cc(ROFF_ARGS); +static int roff_ccond(struct roff *, int, int); +static int roff_char(ROFF_ARGS); +static int roff_cond(ROFF_ARGS); +static int roff_cond_text(ROFF_ARGS); +static int roff_cond_sub(ROFF_ARGS); +static int roff_ds(ROFF_ARGS); +static int roff_ec(ROFF_ARGS); +static int roff_eo(ROFF_ARGS); +static int roff_eqndelim(struct roff *, struct buf *, int); +static int roff_evalcond(struct roff *r, int, char *, int *); +static int roff_evalnum(struct roff *, int, + const char *, int *, int *, int); +static int roff_evalpar(struct roff *, int, + const char *, int *, int *, int); +static int roff_evalstrcond(const char *, int *); +static int roff_expand(struct roff *, struct buf *, + int, int, char); +static void roff_free1(struct roff *); +static void roff_freereg(struct roffreg *); +static void roff_freestr(struct roffkv *); +static size_t roff_getname(struct roff *, char **, int, int); +static int roff_getnum(const char *, int *, int *, int); +static int roff_getop(const char *, int *, char *); +static int roff_getregn(struct roff *, + const char *, size_t, char); +static int roff_getregro(const struct roff *, + const char *name); +static const char *roff_getstrn(struct roff *, + const char *, size_t, int *); +static int roff_hasregn(const struct roff *, + const char *, size_t); +static int roff_insec(ROFF_ARGS); +static int roff_it(ROFF_ARGS); +static int roff_line_ignore(ROFF_ARGS); +static void roff_man_alloc1(struct roff_man *); +static void roff_man_free1(struct roff_man *); +static int roff_manyarg(ROFF_ARGS); +static int roff_noarg(ROFF_ARGS); +static int roff_nop(ROFF_ARGS); +static int roff_nr(ROFF_ARGS); +static int roff_onearg(ROFF_ARGS); +static enum roff_tok roff_parse(struct roff *, char *, int *, + int, int); +static int roff_parsetext(struct roff *, struct buf *, + int, int *); +static int roff_renamed(ROFF_ARGS); +static int roff_return(ROFF_ARGS); +static int roff_rm(ROFF_ARGS); +static int roff_rn(ROFF_ARGS); +static int roff_rr(ROFF_ARGS); +static void roff_setregn(struct roff *, const char *, + size_t, int, char, int); +static void roff_setstr(struct roff *, + const char *, const char *, int); +static void roff_setstrn(struct roffkv **, const char *, + size_t, const char *, size_t, int); +static int roff_shift(ROFF_ARGS); +static int roff_so(ROFF_ARGS); +static int roff_tr(ROFF_ARGS); +static int roff_Dd(ROFF_ARGS); +static int roff_TE(ROFF_ARGS); +static int roff_TS(ROFF_ARGS); +static int roff_EQ(ROFF_ARGS); +static int roff_EN(ROFF_ARGS); +static int roff_T_(ROFF_ARGS); +static int roff_unsupp(ROFF_ARGS); +static int roff_userdef(ROFF_ARGS); + +/* --- constant data ------------------------------------------------------ */ + +#define ROFFNUM_SCALE (1 << 0) /* Honour scaling in roff_getnum(). */ +#define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */ + +const char *__roff_name[MAN_MAX + 1] = { + "br", "ce", "fi", "ft", + "ll", "mc", "nf", + "po", "rj", "sp", + "ta", "ti", NULL, + "ab", "ad", "af", "aln", + "als", "am", "am1", "ami", + "ami1", "as", "as1", "asciify", + "backtrace", "bd", "bleedat", "blm", + "box", "boxa", "bp", "BP", + "break", "breakchar", "brnl", "brp", + "brpnl", "c2", "cc", + "cf", "cflags", "ch", "char", + "chop", "class", "close", "CL", + "color", "composite", "continue", "cp", + "cropat", "cs", "cu", "da", + "dch", "Dd", "de", "de1", + "defcolor", "dei", "dei1", "device", + "devicem", "di", "do", "ds", + "ds1", "dwh", "dt", "ec", + "ecr", "ecs", "el", "em", + "EN", "eo", "EP", "EQ", + "errprint", "ev", "evc", "ex", + "fallback", "fam", "fc", "fchar", + "fcolor", "fdeferlig", "feature", "fkern", + "fl", "flig", "fp", "fps", + "fschar", "fspacewidth", "fspecial", "ftr", + "fzoom", "gcolor", "hc", "hcode", + "hidechar", "hla", "hlm", "hpf", + "hpfa", "hpfcode", "hw", "hy", + "hylang", "hylen", "hym", "hypp", + "hys", "ie", "if", "ig", + "index", "it", "itc", "IX", + "kern", "kernafter", "kernbefore", "kernpair", + "lc", "lc_ctype", "lds", "length", + "letadj", "lf", "lg", "lhang", + "linetabs", "lnr", "lnrf", "lpfx", + "ls", "lsm", "lt", + "mediasize", "minss", "mk", "mso", + "na", "ne", "nh", "nhychar", + "nm", "nn", "nop", "nr", + "nrf", "nroff", "ns", "nx", + "open", "opena", "os", "output", + "padj", "papersize", "pc", "pev", + "pi", "PI", "pl", "pm", + "pn", "pnr", "ps", + "psbb", "pshape", "pso", "ptr", + "pvs", "rchar", "rd", "recursionlimit", + "return", "rfschar", "rhang", + "rm", "rn", "rnn", "rr", + "rs", "rt", "schar", "sentchar", + "shc", "shift", "sizes", "so", + "spacewidth", "special", "spreadwarn", "ss", + "sty", "substring", "sv", "sy", + "T&", "tc", "TE", + "TH", "tkf", "tl", + "tm", "tm1", "tmc", "tr", + "track", "transchar", "trf", "trimat", + "trin", "trnt", "troff", "TS", + "uf", "ul", "unformat", "unwatch", + "unwatchn", "vpt", "vs", "warn", + "warnscale", "watch", "watchlength", "watchn", + "wh", "while", "write", "writec", + "writem", "xflag", ".", NULL, + NULL, "text", + "Dd", "Dt", "Os", "Sh", + "Ss", "Pp", "D1", "Dl", + "Bd", "Ed", "Bl", "El", + "It", "Ad", "An", "Ap", + "Ar", "Cd", "Cm", "Dv", + "Er", "Ev", "Ex", "Fa", + "Fd", "Fl", "Fn", "Ft", + "Ic", "In", "Li", "Nd", + "Nm", "Op", "Ot", "Pa", + "Rv", "St", "Va", "Vt", + "Xr", "%A", "%B", "%D", + "%I", "%J", "%N", "%O", + "%P", "%R", "%T", "%V", + "Ac", "Ao", "Aq", "At", + "Bc", "Bf", "Bo", "Bq", + "Bsx", "Bx", "Db", "Dc", + "Do", "Dq", "Ec", "Ef", + "Em", "Eo", "Fx", "Ms", + "No", "Ns", "Nx", "Ox", + "Pc", "Pf", "Po", "Pq", + "Qc", "Ql", "Qo", "Qq", + "Re", "Rs", "Sc", "So", + "Sq", "Sm", "Sx", "Sy", + "Tn", "Ux", "Xc", "Xo", + "Fo", "Fc", "Oo", "Oc", + "Bk", "Ek", "Bt", "Hf", + "Fr", "Ud", "Lb", "Lp", + "Lk", "Mt", "Brq", "Bro", + "Brc", "%C", "Es", "En", + "Dx", "%Q", "%U", "Ta", + NULL, + "TH", "SH", "SS", "TP", + "TQ", + "LP", "PP", "P", "IP", + "HP", "SM", "SB", "BI", + "IB", "BR", "RB", "R", + "B", "I", "IR", "RI", + "RE", "RS", "DT", "UC", + "PD", "AT", "in", + "SY", "YS", "OP", + "EX", "EE", "UR", + "UE", "MT", "ME", NULL +}; +const char *const *roff_name = __roff_name; + +static struct roffmac roffs[TOKEN_NONE] = { + { roff_noarg, NULL, NULL, 0 }, /* br */ + { roff_onearg, NULL, NULL, 0 }, /* ce */ + { roff_noarg, NULL, NULL, 0 }, /* fi */ + { roff_onearg, NULL, NULL, 0 }, /* ft */ + { roff_onearg, NULL, NULL, 0 }, /* ll */ + { roff_onearg, NULL, NULL, 0 }, /* mc */ + { roff_noarg, NULL, NULL, 0 }, /* nf */ + { roff_onearg, NULL, NULL, 0 }, /* po */ + { roff_onearg, NULL, NULL, 0 }, /* rj */ + { roff_onearg, NULL, NULL, 0 }, /* sp */ + { roff_manyarg, NULL, NULL, 0 }, /* ta */ + { roff_onearg, NULL, NULL, 0 }, /* ti */ + { NULL, NULL, NULL, 0 }, /* ROFF_MAX */ + { roff_unsupp, NULL, NULL, 0 }, /* ab */ + { roff_line_ignore, NULL, NULL, 0 }, /* ad */ + { roff_line_ignore, NULL, NULL, 0 }, /* af */ + { roff_unsupp, NULL, NULL, 0 }, /* aln */ + { roff_als, NULL, NULL, 0 }, /* als */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* am */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* am1 */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami1 */ + { roff_ds, NULL, NULL, 0 }, /* as */ + { roff_ds, NULL, NULL, 0 }, /* as1 */ + { roff_unsupp, NULL, NULL, 0 }, /* asciify */ + { roff_line_ignore, NULL, NULL, 0 }, /* backtrace */ + { roff_line_ignore, NULL, NULL, 0 }, /* bd */ + { roff_line_ignore, NULL, NULL, 0 }, /* bleedat */ + { roff_unsupp, NULL, NULL, 0 }, /* blm */ + { roff_unsupp, NULL, NULL, 0 }, /* box */ + { roff_unsupp, NULL, NULL, 0 }, /* boxa */ + { roff_line_ignore, NULL, NULL, 0 }, /* bp */ + { roff_unsupp, NULL, NULL, 0 }, /* BP */ + { roff_break, NULL, NULL, 0 }, /* break */ + { roff_line_ignore, NULL, NULL, 0 }, /* breakchar */ + { roff_line_ignore, NULL, NULL, 0 }, /* brnl */ + { roff_noarg, NULL, NULL, 0 }, /* brp */ + { roff_line_ignore, NULL, NULL, 0 }, /* brpnl */ + { roff_unsupp, NULL, NULL, 0 }, /* c2 */ + { roff_cc, NULL, NULL, 0 }, /* cc */ + { roff_insec, NULL, NULL, 0 }, /* cf */ + { roff_line_ignore, NULL, NULL, 0 }, /* cflags */ + { roff_line_ignore, NULL, NULL, 0 }, /* ch */ + { roff_char, NULL, NULL, 0 }, /* char */ + { roff_unsupp, NULL, NULL, 0 }, /* chop */ + { roff_line_ignore, NULL, NULL, 0 }, /* class */ + { roff_insec, NULL, NULL, 0 }, /* close */ + { roff_unsupp, NULL, NULL, 0 }, /* CL */ + { roff_line_ignore, NULL, NULL, 0 }, /* color */ + { roff_unsupp, NULL, NULL, 0 }, /* composite */ + { roff_unsupp, NULL, NULL, 0 }, /* continue */ + { roff_line_ignore, NULL, NULL, 0 }, /* cp */ + { roff_line_ignore, NULL, NULL, 0 }, /* cropat */ + { roff_line_ignore, NULL, NULL, 0 }, /* cs */ + { roff_line_ignore, NULL, NULL, 0 }, /* cu */ + { roff_unsupp, NULL, NULL, 0 }, /* da */ + { roff_unsupp, NULL, NULL, 0 }, /* dch */ + { roff_Dd, NULL, NULL, 0 }, /* Dd */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* de */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* de1 */ + { roff_line_ignore, NULL, NULL, 0 }, /* defcolor */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* dei */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* dei1 */ + { roff_unsupp, NULL, NULL, 0 }, /* device */ + { roff_unsupp, NULL, NULL, 0 }, /* devicem */ + { roff_unsupp, NULL, NULL, 0 }, /* di */ + { roff_unsupp, NULL, NULL, 0 }, /* do */ + { roff_ds, NULL, NULL, 0 }, /* ds */ + { roff_ds, NULL, NULL, 0 }, /* ds1 */ + { roff_unsupp, NULL, NULL, 0 }, /* dwh */ + { roff_unsupp, NULL, NULL, 0 }, /* dt */ + { roff_ec, NULL, NULL, 0 }, /* ec */ + { roff_unsupp, NULL, NULL, 0 }, /* ecr */ + { roff_unsupp, NULL, NULL, 0 }, /* ecs */ + { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* el */ + { roff_unsupp, NULL, NULL, 0 }, /* em */ + { roff_EN, NULL, NULL, 0 }, /* EN */ + { roff_eo, NULL, NULL, 0 }, /* eo */ + { roff_unsupp, NULL, NULL, 0 }, /* EP */ + { roff_EQ, NULL, NULL, 0 }, /* EQ */ + { roff_line_ignore, NULL, NULL, 0 }, /* errprint */ + { roff_unsupp, NULL, NULL, 0 }, /* ev */ + { roff_unsupp, NULL, NULL, 0 }, /* evc */ + { roff_unsupp, NULL, NULL, 0 }, /* ex */ + { roff_line_ignore, NULL, NULL, 0 }, /* fallback */ + { roff_line_ignore, NULL, NULL, 0 }, /* fam */ + { roff_unsupp, NULL, NULL, 0 }, /* fc */ + { roff_unsupp, NULL, NULL, 0 }, /* fchar */ + { roff_line_ignore, NULL, NULL, 0 }, /* fcolor */ + { roff_line_ignore, NULL, NULL, 0 }, /* fdeferlig */ + { roff_line_ignore, NULL, NULL, 0 }, /* feature */ + { roff_line_ignore, NULL, NULL, 0 }, /* fkern */ + { roff_line_ignore, NULL, NULL, 0 }, /* fl */ + { roff_line_ignore, NULL, NULL, 0 }, /* flig */ + { roff_line_ignore, NULL, NULL, 0 }, /* fp */ + { roff_line_ignore, NULL, NULL, 0 }, /* fps */ + { roff_unsupp, NULL, NULL, 0 }, /* fschar */ + { roff_line_ignore, NULL, NULL, 0 }, /* fspacewidth */ + { roff_line_ignore, NULL, NULL, 0 }, /* fspecial */ + { roff_line_ignore, NULL, NULL, 0 }, /* ftr */ + { roff_line_ignore, NULL, NULL, 0 }, /* fzoom */ + { roff_line_ignore, NULL, NULL, 0 }, /* gcolor */ + { roff_line_ignore, NULL, NULL, 0 }, /* hc */ + { roff_line_ignore, NULL, NULL, 0 }, /* hcode */ + { roff_line_ignore, NULL, NULL, 0 }, /* hidechar */ + { roff_line_ignore, NULL, NULL, 0 }, /* hla */ + { roff_line_ignore, NULL, NULL, 0 }, /* hlm */ + { roff_line_ignore, NULL, NULL, 0 }, /* hpf */ + { roff_line_ignore, NULL, NULL, 0 }, /* hpfa */ + { roff_line_ignore, NULL, NULL, 0 }, /* hpfcode */ + { roff_line_ignore, NULL, NULL, 0 }, /* hw */ + { roff_line_ignore, NULL, NULL, 0 }, /* hy */ + { roff_line_ignore, NULL, NULL, 0 }, /* hylang */ + { roff_line_ignore, NULL, NULL, 0 }, /* hylen */ + { roff_line_ignore, NULL, NULL, 0 }, /* hym */ + { roff_line_ignore, NULL, NULL, 0 }, /* hypp */ + { roff_line_ignore, NULL, NULL, 0 }, /* hys */ + { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* ie */ + { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* if */ + { roff_block, roff_block_text, roff_block_sub, 0 }, /* ig */ + { roff_unsupp, NULL, NULL, 0 }, /* index */ + { roff_it, NULL, NULL, 0 }, /* it */ + { roff_unsupp, NULL, NULL, 0 }, /* itc */ + { roff_line_ignore, NULL, NULL, 0 }, /* IX */ + { roff_line_ignore, NULL, NULL, 0 }, /* kern */ + { roff_line_ignore, NULL, NULL, 0 }, /* kernafter */ + { roff_line_ignore, NULL, NULL, 0 }, /* kernbefore */ + { roff_line_ignore, NULL, NULL, 0 }, /* kernpair */ + { roff_unsupp, NULL, NULL, 0 }, /* lc */ + { roff_unsupp, NULL, NULL, 0 }, /* lc_ctype */ + { roff_unsupp, NULL, NULL, 0 }, /* lds */ + { roff_unsupp, NULL, NULL, 0 }, /* length */ + { roff_line_ignore, NULL, NULL, 0 }, /* letadj */ + { roff_insec, NULL, NULL, 0 }, /* lf */ + { roff_line_ignore, NULL, NULL, 0 }, /* lg */ + { roff_line_ignore, NULL, NULL, 0 }, /* lhang */ + { roff_unsupp, NULL, NULL, 0 }, /* linetabs */ + { roff_unsupp, NULL, NULL, 0 }, /* lnr */ + { roff_unsupp, NULL, NULL, 0 }, /* lnrf */ + { roff_unsupp, NULL, NULL, 0 }, /* lpfx */ + { roff_line_ignore, NULL, NULL, 0 }, /* ls */ + { roff_unsupp, NULL, NULL, 0 }, /* lsm */ + { roff_line_ignore, NULL, NULL, 0 }, /* lt */ + { roff_line_ignore, NULL, NULL, 0 }, /* mediasize */ + { roff_line_ignore, NULL, NULL, 0 }, /* minss */ + { roff_line_ignore, NULL, NULL, 0 }, /* mk */ + { roff_insec, NULL, NULL, 0 }, /* mso */ + { roff_line_ignore, NULL, NULL, 0 }, /* na */ + { roff_line_ignore, NULL, NULL, 0 }, /* ne */ + { roff_line_ignore, NULL, NULL, 0 }, /* nh */ + { roff_line_ignore, NULL, NULL, 0 }, /* nhychar */ + { roff_unsupp, NULL, NULL, 0 }, /* nm */ + { roff_unsupp, NULL, NULL, 0 }, /* nn */ + { roff_nop, NULL, NULL, 0 }, /* nop */ + { roff_nr, NULL, NULL, 0 }, /* nr */ + { roff_unsupp, NULL, NULL, 0 }, /* nrf */ + { roff_line_ignore, NULL, NULL, 0 }, /* nroff */ + { roff_line_ignore, NULL, NULL, 0 }, /* ns */ + { roff_insec, NULL, NULL, 0 }, /* nx */ + { roff_insec, NULL, NULL, 0 }, /* open */ + { roff_insec, NULL, NULL, 0 }, /* opena */ + { roff_line_ignore, NULL, NULL, 0 }, /* os */ + { roff_unsupp, NULL, NULL, 0 }, /* output */ + { roff_line_ignore, NULL, NULL, 0 }, /* padj */ + { roff_line_ignore, NULL, NULL, 0 }, /* papersize */ + { roff_line_ignore, NULL, NULL, 0 }, /* pc */ + { roff_line_ignore, NULL, NULL, 0 }, /* pev */ + { roff_insec, NULL, NULL, 0 }, /* pi */ + { roff_unsupp, NULL, NULL, 0 }, /* PI */ + { roff_line_ignore, NULL, NULL, 0 }, /* pl */ + { roff_line_ignore, NULL, NULL, 0 }, /* pm */ + { roff_line_ignore, NULL, NULL, 0 }, /* pn */ + { roff_line_ignore, NULL, NULL, 0 }, /* pnr */ + { roff_line_ignore, NULL, NULL, 0 }, /* ps */ + { roff_unsupp, NULL, NULL, 0 }, /* psbb */ + { roff_unsupp, NULL, NULL, 0 }, /* pshape */ + { roff_insec, NULL, NULL, 0 }, /* pso */ + { roff_line_ignore, NULL, NULL, 0 }, /* ptr */ + { roff_line_ignore, NULL, NULL, 0 }, /* pvs */ + { roff_unsupp, NULL, NULL, 0 }, /* rchar */ + { roff_line_ignore, NULL, NULL, 0 }, /* rd */ + { roff_line_ignore, NULL, NULL, 0 }, /* recursionlimit */ + { roff_return, NULL, NULL, 0 }, /* return */ + { roff_unsupp, NULL, NULL, 0 }, /* rfschar */ + { roff_line_ignore, NULL, NULL, 0 }, /* rhang */ + { roff_rm, NULL, NULL, 0 }, /* rm */ + { roff_rn, NULL, NULL, 0 }, /* rn */ + { roff_unsupp, NULL, NULL, 0 }, /* rnn */ + { roff_rr, NULL, NULL, 0 }, /* rr */ + { roff_line_ignore, NULL, NULL, 0 }, /* rs */ + { roff_line_ignore, NULL, NULL, 0 }, /* rt */ + { roff_unsupp, NULL, NULL, 0 }, /* schar */ + { roff_line_ignore, NULL, NULL, 0 }, /* sentchar */ + { roff_line_ignore, NULL, NULL, 0 }, /* shc */ + { roff_shift, NULL, NULL, 0 }, /* shift */ + { roff_line_ignore, NULL, NULL, 0 }, /* sizes */ + { roff_so, NULL, NULL, 0 }, /* so */ + { roff_line_ignore, NULL, NULL, 0 }, /* spacewidth */ + { roff_line_ignore, NULL, NULL, 0 }, /* special */ + { roff_line_ignore, NULL, NULL, 0 }, /* spreadwarn */ + { roff_line_ignore, NULL, NULL, 0 }, /* ss */ + { roff_line_ignore, NULL, NULL, 0 }, /* sty */ + { roff_unsupp, NULL, NULL, 0 }, /* substring */ + { roff_line_ignore, NULL, NULL, 0 }, /* sv */ + { roff_insec, NULL, NULL, 0 }, /* sy */ + { roff_T_, NULL, NULL, 0 }, /* T& */ + { roff_unsupp, NULL, NULL, 0 }, /* tc */ + { roff_TE, NULL, NULL, 0 }, /* TE */ + { roff_Dd, NULL, NULL, 0 }, /* TH */ + { roff_line_ignore, NULL, NULL, 0 }, /* tkf */ + { roff_unsupp, NULL, NULL, 0 }, /* tl */ + { roff_line_ignore, NULL, NULL, 0 }, /* tm */ + { roff_line_ignore, NULL, NULL, 0 }, /* tm1 */ + { roff_line_ignore, NULL, NULL, 0 }, /* tmc */ + { roff_tr, NULL, NULL, 0 }, /* tr */ + { roff_line_ignore, NULL, NULL, 0 }, /* track */ + { roff_line_ignore, NULL, NULL, 0 }, /* transchar */ + { roff_insec, NULL, NULL, 0 }, /* trf */ + { roff_line_ignore, NULL, NULL, 0 }, /* trimat */ + { roff_unsupp, NULL, NULL, 0 }, /* trin */ + { roff_unsupp, NULL, NULL, 0 }, /* trnt */ + { roff_line_ignore, NULL, NULL, 0 }, /* troff */ + { roff_TS, NULL, NULL, 0 }, /* TS */ + { roff_line_ignore, NULL, NULL, 0 }, /* uf */ + { roff_line_ignore, NULL, NULL, 0 }, /* ul */ + { roff_unsupp, NULL, NULL, 0 }, /* unformat */ + { roff_line_ignore, NULL, NULL, 0 }, /* unwatch */ + { roff_line_ignore, NULL, NULL, 0 }, /* unwatchn */ + { roff_line_ignore, NULL, NULL, 0 }, /* vpt */ + { roff_line_ignore, NULL, NULL, 0 }, /* vs */ + { roff_line_ignore, NULL, NULL, 0 }, /* warn */ + { roff_line_ignore, NULL, NULL, 0 }, /* warnscale */ + { roff_line_ignore, NULL, NULL, 0 }, /* watch */ + { roff_line_ignore, NULL, NULL, 0 }, /* watchlength */ + { roff_line_ignore, NULL, NULL, 0 }, /* watchn */ + { roff_unsupp, NULL, NULL, 0 }, /* wh */ + { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /*while*/ + { roff_insec, NULL, NULL, 0 }, /* write */ + { roff_insec, NULL, NULL, 0 }, /* writec */ + { roff_insec, NULL, NULL, 0 }, /* writem */ + { roff_line_ignore, NULL, NULL, 0 }, /* xflag */ + { roff_cblock, NULL, NULL, 0 }, /* . */ + { roff_renamed, NULL, NULL, 0 }, + { roff_userdef, NULL, NULL, 0 } +}; + +/* Array of injected predefined strings. */ +#define PREDEFS_MAX 38 +static const struct predef predefs[PREDEFS_MAX] = { +#include "predefs.in" +}; + +static int roffce_lines; /* number of input lines to center */ +static struct roff_node *roffce_node; /* active request */ +static int roffit_lines; /* number of lines to delay */ +static char *roffit_macro; /* nil-terminated macro line */ + + +/* --- request table ------------------------------------------------------ */ + +struct ohash * +roffhash_alloc(enum roff_tok mintok, enum roff_tok maxtok) +{ + struct ohash *htab; + struct roffreq *req; + enum roff_tok tok; + size_t sz; + unsigned int slot; + + htab = mandoc_malloc(sizeof(*htab)); + mandoc_ohash_init(htab, 8, offsetof(struct roffreq, name)); + + for (tok = mintok; tok < maxtok; tok++) { + if (roff_name[tok] == NULL) + continue; + sz = strlen(roff_name[tok]); + req = mandoc_malloc(sizeof(*req) + sz + 1); + req->tok = tok; + memcpy(req->name, roff_name[tok], sz + 1); + slot = ohash_qlookup(htab, req->name); + ohash_insert(htab, slot, req); + } + return htab; +} + +void +roffhash_free(struct ohash *htab) +{ + struct roffreq *req; + unsigned int slot; + + if (htab == NULL) + return; + for (req = ohash_first(htab, &slot); req != NULL; + req = ohash_next(htab, &slot)) + free(req); + ohash_delete(htab); + free(htab); +} + +enum roff_tok +roffhash_find(struct ohash *htab, const char *name, size_t sz) +{ + struct roffreq *req; + const char *end; + + if (sz) { + end = name + sz; + req = ohash_find(htab, ohash_qlookupi(htab, name, &end)); + } else + req = ohash_find(htab, ohash_qlookup(htab, name)); + return req == NULL ? TOKEN_NONE : req->tok; +} + +/* --- stack of request blocks -------------------------------------------- */ + +/* + * Pop the current node off of the stack of roff instructions currently + * pending. Return 1 if it is a loop or 0 otherwise. + */ +static int +roffnode_pop(struct roff *r) +{ + struct roffnode *p; + int inloop; + + p = r->last; + inloop = p->tok == ROFF_while; + r->last = p->parent; + free(p->name); + free(p->end); + free(p); + return inloop; +} + +/* + * Push a roff node onto the instruction stack. This must later be + * removed with roffnode_pop(). + */ +static void +roffnode_push(struct roff *r, enum roff_tok tok, const char *name, + int line, int col) +{ + struct roffnode *p; + + p = mandoc_calloc(1, sizeof(struct roffnode)); + p->tok = tok; + if (name) + p->name = mandoc_strdup(name); + p->parent = r->last; + p->line = line; + p->col = col; + p->rule = p->parent ? p->parent->rule : 0; + + r->last = p; +} + +/* --- roff parser state data management ---------------------------------- */ + +static void +roff_free1(struct roff *r) +{ + int i; + + tbl_free(r->first_tbl); + r->first_tbl = r->last_tbl = r->tbl = NULL; + + eqn_free(r->last_eqn); + r->last_eqn = r->eqn = NULL; + + while (r->mstackpos >= 0) + roff_userret(r); + + while (r->last) + roffnode_pop(r); + + free (r->rstack); + r->rstack = NULL; + r->rstacksz = 0; + r->rstackpos = -1; + + roff_freereg(r->regtab); + r->regtab = NULL; + + roff_freestr(r->strtab); + roff_freestr(r->rentab); + roff_freestr(r->xmbtab); + r->strtab = r->rentab = r->xmbtab = NULL; + + if (r->xtab) + for (i = 0; i < 128; i++) + free(r->xtab[i].p); + free(r->xtab); + r->xtab = NULL; +} + +void +roff_reset(struct roff *r) +{ + roff_free1(r); + r->format = r->options & (MPARSE_MDOC | MPARSE_MAN); + r->control = '\0'; + r->escape = '\\'; + roffce_lines = 0; + roffce_node = NULL; + roffit_lines = 0; + roffit_macro = NULL; +} + +void +roff_free(struct roff *r) +{ + int i; + + roff_free1(r); + for (i = 0; i < r->mstacksz; i++) + free(r->mstack[i].argv); + free(r->mstack); + roffhash_free(r->reqtab); + free(r); +} + +struct roff * +roff_alloc(int options) +{ + struct roff *r; + + r = mandoc_calloc(1, sizeof(struct roff)); + r->reqtab = roffhash_alloc(0, ROFF_RENAMED); + r->options = options; + r->format = options & (MPARSE_MDOC | MPARSE_MAN); + r->mstackpos = -1; + r->rstackpos = -1; + r->escape = '\\'; + return r; +} + +/* --- syntax tree state data management ---------------------------------- */ + +static void +roff_man_free1(struct roff_man *man) +{ + if (man->meta.first != NULL) + roff_node_delete(man, man->meta.first); + free(man->meta.msec); + free(man->meta.vol); + free(man->meta.os); + free(man->meta.arch); + free(man->meta.title); + free(man->meta.name); + free(man->meta.date); + free(man->meta.sodest); +} + +void +roff_state_reset(struct roff_man *man) +{ + man->last = man->meta.first; + man->last_es = NULL; + man->flags = 0; + man->lastsec = man->lastnamed = SEC_NONE; + man->next = ROFF_NEXT_CHILD; + roff_setreg(man->roff, "nS", 0, '='); +} + +static void +roff_man_alloc1(struct roff_man *man) +{ + memset(&man->meta, 0, sizeof(man->meta)); + man->meta.first = mandoc_calloc(1, sizeof(*man->meta.first)); + man->meta.first->type = ROFFT_ROOT; + man->meta.macroset = MACROSET_NONE; + roff_state_reset(man); +} + +void +roff_man_reset(struct roff_man *man) +{ + roff_man_free1(man); + roff_man_alloc1(man); +} + +void +roff_man_free(struct roff_man *man) +{ + roff_man_free1(man); + free(man); +} + +struct roff_man * +roff_man_alloc(struct roff *roff, const char *os_s, int quick) +{ + struct roff_man *man; + + man = mandoc_calloc(1, sizeof(*man)); + man->roff = roff; + man->os_s = os_s; + man->quick = quick; + roff_man_alloc1(man); + roff->man = man; + return man; +} + +/* --- syntax tree handling ----------------------------------------------- */ + +struct roff_node * +roff_node_alloc(struct roff_man *man, int line, int pos, + enum roff_type type, int tok) +{ + struct roff_node *n; + + n = mandoc_calloc(1, sizeof(*n)); + n->line = line; + n->pos = pos; + n->tok = tok; + n->type = type; + n->sec = man->lastsec; + + if (man->flags & MDOC_SYNOPSIS) + n->flags |= NODE_SYNPRETTY; + else + n->flags &= ~NODE_SYNPRETTY; + if ((man->flags & (ROFF_NOFILL | ROFF_NONOFILL)) == ROFF_NOFILL) + n->flags |= NODE_NOFILL; + else + n->flags &= ~NODE_NOFILL; + if (man->flags & MDOC_NEWLINE) + n->flags |= NODE_LINE; + man->flags &= ~MDOC_NEWLINE; + + return n; +} + +void +roff_node_append(struct roff_man *man, struct roff_node *n) +{ + + switch (man->next) { + case ROFF_NEXT_SIBLING: + if (man->last->next != NULL) { + n->next = man->last->next; + man->last->next->prev = n; + } else + man->last->parent->last = n; + man->last->next = n; + n->prev = man->last; + n->parent = man->last->parent; + break; + case ROFF_NEXT_CHILD: + if (man->last->child != NULL) { + n->next = man->last->child; + man->last->child->prev = n; + } else + man->last->last = n; + man->last->child = n; + n->parent = man->last; + break; + default: + abort(); + } + man->last = n; + + switch (n->type) { + case ROFFT_HEAD: + n->parent->head = n; + break; + case ROFFT_BODY: + if (n->end != ENDBODY_NOT) + return; + n->parent->body = n; + break; + case ROFFT_TAIL: + n->parent->tail = n; + break; + default: + return; + } + + /* + * Copy over the normalised-data pointer of our parent. Not + * everybody has one, but copying a null pointer is fine. + */ + + n->norm = n->parent->norm; + assert(n->parent->type == ROFFT_BLOCK); +} + +void +roff_word_alloc(struct roff_man *man, int line, int pos, const char *word) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE); + n->string = roff_strdup(man->roff, word); + roff_node_append(man, n); + n->flags |= NODE_VALID | NODE_ENDED; + man->next = ROFF_NEXT_SIBLING; +} + +void +roff_word_append(struct roff_man *man, const char *word) +{ + struct roff_node *n; + char *addstr, *newstr; + + n = man->last; + addstr = roff_strdup(man->roff, word); + mandoc_asprintf(&newstr, "%s %s", n->string, addstr); + free(addstr); + free(n->string); + n->string = newstr; + man->next = ROFF_NEXT_SIBLING; +} + +void +roff_elem_alloc(struct roff_man *man, int line, int pos, int tok) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok); + roff_node_append(man, n); + man->next = ROFF_NEXT_CHILD; +} + +struct roff_node * +roff_block_alloc(struct roff_man *man, int line, int pos, int tok) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok); + roff_node_append(man, n); + man->next = ROFF_NEXT_CHILD; + return n; +} + +struct roff_node * +roff_head_alloc(struct roff_man *man, int line, int pos, int tok) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_HEAD, tok); + roff_node_append(man, n); + man->next = ROFF_NEXT_CHILD; + return n; +} + +struct roff_node * +roff_body_alloc(struct roff_man *man, int line, int pos, int tok) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_BODY, tok); + roff_node_append(man, n); + man->next = ROFF_NEXT_CHILD; + return n; +} + +static void +roff_addtbl(struct roff_man *man, int line, struct tbl_node *tbl) +{ + struct roff_node *n; + struct tbl_span *span; + + if (man->meta.macroset == MACROSET_MAN) + man_breakscope(man, ROFF_TS); + while ((span = tbl_span(tbl)) != NULL) { + n = roff_node_alloc(man, line, 0, ROFFT_TBL, TOKEN_NONE); + n->span = span; + roff_node_append(man, n); + n->flags |= NODE_VALID | NODE_ENDED; + man->next = ROFF_NEXT_SIBLING; + } +} + +void +roff_node_unlink(struct roff_man *man, struct roff_node *n) +{ + + /* Adjust siblings. */ + + if (n->prev) + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + + /* Adjust parent. */ + + if (n->parent != NULL) { + if (n->parent->child == n) + n->parent->child = n->next; + if (n->parent->last == n) + n->parent->last = n->prev; + } + + /* Adjust parse point. */ + + if (man == NULL) + return; + if (man->last == n) { + if (n->prev == NULL) { + man->last = n->parent; + man->next = ROFF_NEXT_CHILD; + } else { + man->last = n->prev; + man->next = ROFF_NEXT_SIBLING; + } + } + if (man->meta.first == n) + man->meta.first = NULL; +} + +void +roff_node_relink(struct roff_man *man, struct roff_node *n) +{ + roff_node_unlink(man, n); + n->prev = n->next = NULL; + roff_node_append(man, n); +} + +void +roff_node_free(struct roff_node *n) +{ + + if (n->args != NULL) + mdoc_argv_free(n->args); + if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM) + free(n->norm); + eqn_box_free(n->eqn); + free(n->string); + free(n); +} + +void +roff_node_delete(struct roff_man *man, struct roff_node *n) +{ + + while (n->child != NULL) + roff_node_delete(man, n->child); + roff_node_unlink(man, n); + roff_node_free(n); +} + +void +deroff(char **dest, const struct roff_node *n) +{ + char *cp; + size_t sz; + + if (n->type != ROFFT_TEXT) { + for (n = n->child; n != NULL; n = n->next) + deroff(dest, n); + return; + } + + /* Skip leading whitespace. */ + + for (cp = n->string; *cp != '\0'; cp++) { + if (cp[0] == '\\' && cp[1] != '\0' && + strchr(" %&0^|~", cp[1]) != NULL) + cp++; + else if ( ! isspace((unsigned char)*cp)) + break; + } + + /* Skip trailing backslash. */ + + sz = strlen(cp); + if (sz > 0 && cp[sz - 1] == '\\') + sz--; + + /* Skip trailing whitespace. */ + + for (; sz; sz--) + if ( ! isspace((unsigned char)cp[sz-1])) + break; + + /* Skip empty strings. */ + + if (sz == 0) + return; + + if (*dest == NULL) { + *dest = mandoc_strndup(cp, sz); + return; + } + + mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp); + free(*dest); + *dest = cp; +} + +/* --- main functions of the roff parser ---------------------------------- */ + +/* + * In the current line, expand escape sequences that produce parsable + * input text. Also check the syntax of the remaining escape sequences, + * which typically produce output glyphs or change formatter state. + */ +static int +roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char newesc) +{ + struct mctx *ctx; /* current macro call context */ + char ubuf[24]; /* buffer to print the number */ + struct roff_node *n; /* used for header comments */ + const char *start; /* start of the string to process */ + char *stesc; /* start of an escape sequence ('\\') */ + const char *esct; /* type of esccape sequence */ + char *ep; /* end of comment string */ + const char *stnam; /* start of the name, after "[(*" */ + const char *cp; /* end of the name, e.g. before ']' */ + const char *res; /* the string to be substituted */ + char *nbuf; /* new buffer to copy buf->buf to */ + size_t maxl; /* expected length of the escape name */ + size_t naml; /* actual length of the escape name */ + size_t asz; /* length of the replacement */ + size_t rsz; /* length of the rest of the string */ + int inaml; /* length returned from mandoc_escape() */ + int expand_count; /* to avoid infinite loops */ + int npos; /* position in numeric expression */ + int arg_complete; /* argument not interrupted by eol */ + int quote_args; /* true for \\$@, false for \\$* */ + int done; /* no more input available */ + int deftype; /* type of definition to paste */ + int rcsid; /* kind of RCS id seen */ + enum mandocerr err; /* for escape sequence problems */ + char sign; /* increment number register */ + char term; /* character terminating the escape */ + + /* Search forward for comments. */ + + done = 0; + start = buf->buf + pos; + for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) { + if (stesc[0] != newesc || stesc[1] == '\0') + continue; + stesc++; + if (*stesc != '"' && *stesc != '#') + continue; + + /* Comment found, look for RCS id. */ + + rcsid = 0; + if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) { + rcsid = 1 << MANDOC_OS_OPENBSD; + cp += 8; + } else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) { + rcsid = 1 << MANDOC_OS_NETBSD; + cp += 7; + } + if (cp != NULL && + isalnum((unsigned char)*cp) == 0 && + strchr(cp, '$') != NULL) { + if (r->man->meta.rcsids & rcsid) + mandoc_msg(MANDOCERR_RCS_REP, ln, + (int)(stesc - buf->buf) + 1, + "%s", stesc + 1); + r->man->meta.rcsids |= rcsid; + } + + /* Handle trailing whitespace. */ + + ep = strchr(stesc--, '\0') - 1; + if (*ep == '\n') { + done = 1; + ep--; + } + if (*ep == ' ' || *ep == '\t') + mandoc_msg(MANDOCERR_SPACE_EOL, + ln, (int)(ep - buf->buf), NULL); + + /* + * Save comments preceding the title macro + * in the syntax tree. + */ + + if (newesc != ASCII_ESC && r->format == 0) { + while (*ep == ' ' || *ep == '\t') + ep--; + ep[1] = '\0'; + n = roff_node_alloc(r->man, + ln, stesc + 1 - buf->buf, + ROFFT_COMMENT, TOKEN_NONE); + n->string = mandoc_strdup(stesc + 2); + roff_node_append(r->man, n); + n->flags |= NODE_VALID | NODE_ENDED; + r->man->next = ROFF_NEXT_SIBLING; + } + + /* Line continuation with comment. */ + + if (stesc[1] == '#') { + *stesc = '\0'; + return ROFF_IGN | ROFF_APPEND; + } + + /* Discard normal comments. */ + + while (stesc > start && stesc[-1] == ' ' && + (stesc == start + 1 || stesc[-2] != '\\')) + stesc--; + *stesc = '\0'; + break; + } + if (stesc == start) + return ROFF_CONT; + stesc--; + + /* Notice the end of the input. */ + + if (*stesc == '\n') { + *stesc-- = '\0'; + done = 1; + } + + expand_count = 0; + while (stesc >= start) { + if (*stesc != newesc) { + + /* + * If we have a non-standard escape character, + * escape literal backslashes because all + * processing in subsequent functions uses + * the standard escaping rules. + */ + + if (newesc != ASCII_ESC && *stesc == '\\') { + *stesc = '\0'; + buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s", + buf->buf, stesc + 1) + 1; + start = nbuf + pos; + stesc = nbuf + (stesc - buf->buf); + free(buf->buf); + buf->buf = nbuf; + } + + /* Search backwards for the next escape. */ + + stesc--; + continue; + } + + /* If it is escaped, skip it. */ + + for (cp = stesc - 1; cp >= start; cp--) + if (*cp != r->escape) + break; + + if ((stesc - cp) % 2 == 0) { + while (stesc > cp) + *stesc-- = '\\'; + continue; + } else if (stesc[1] != '\0') { + *stesc = '\\'; + } else { + *stesc-- = '\0'; + if (done) + continue; + else + return ROFF_IGN | ROFF_APPEND; + } + + /* Decide whether to expand or to check only. */ + + term = '\0'; + cp = stesc + 1; + if (*cp == 'E') + cp++; + esct = cp; + switch (*esct) { + case '*': + case '$': + res = NULL; + break; + case 'B': + case 'w': + term = cp[1]; + /* FALLTHROUGH */ + case 'n': + sign = cp[1]; + if (sign == '+' || sign == '-') + cp++; + res = ubuf; + break; + default: + err = MANDOCERR_OK; + switch(mandoc_escape(&cp, &stnam, &inaml)) { + case ESCAPE_SPECIAL: + if (mchars_spec2cp(stnam, inaml) >= 0) + break; + /* FALLTHROUGH */ + case ESCAPE_ERROR: + err = MANDOCERR_ESC_BAD; + break; + case ESCAPE_UNDEF: + err = MANDOCERR_ESC_UNDEF; + break; + case ESCAPE_UNSUPP: + err = MANDOCERR_ESC_UNSUPP; + break; + default: + break; + } + if (err != MANDOCERR_OK) + mandoc_msg(err, ln, (int)(stesc - buf->buf), + "%.*s", (int)(cp - stesc), stesc); + stesc--; + continue; + } + + if (EXPAND_LIMIT < ++expand_count) { + mandoc_msg(MANDOCERR_ROFFLOOP, + ln, (int)(stesc - buf->buf), NULL); + return ROFF_IGN; + } + + /* + * The third character decides the length + * of the name of the string or register. + * Save a pointer to the name. + */ + + if (term == '\0') { + switch (*++cp) { + case '\0': + maxl = 0; + break; + case '(': + cp++; + maxl = 2; + break; + case '[': + cp++; + term = ']'; + maxl = 0; + break; + default: + maxl = 1; + break; + } + } else { + cp += 2; + maxl = 0; + } + stnam = cp; + + /* Advance to the end of the name. */ + + naml = 0; + arg_complete = 1; + while (maxl == 0 || naml < maxl) { + if (*cp == '\0') { + mandoc_msg(MANDOCERR_ESC_BAD, ln, + (int)(stesc - buf->buf), "%s", stesc); + arg_complete = 0; + break; + } + if (maxl == 0 && *cp == term) { + cp++; + break; + } + if (*cp++ != '\\' || *esct != 'w') { + naml++; + continue; + } + switch (mandoc_escape(&cp, NULL, NULL)) { + case ESCAPE_SPECIAL: + case ESCAPE_UNICODE: + case ESCAPE_NUMBERED: + case ESCAPE_UNDEF: + case ESCAPE_OVERSTRIKE: + naml++; + break; + default: + break; + } + } + + /* + * Retrieve the replacement string; if it is + * undefined, resume searching for escapes. + */ + + switch (*esct) { + case '*': + if (arg_complete) { + deftype = ROFFDEF_USER | ROFFDEF_PRE; + res = roff_getstrn(r, stnam, naml, &deftype); + + /* + * If not overriden, let \*(.T + * through to the formatters. + */ + + if (res == NULL && naml == 2 && + stnam[0] == '.' && stnam[1] == 'T') { + roff_setstrn(&r->strtab, + ".T", 2, NULL, 0, 0); + stesc--; + continue; + } + } + break; + case '$': + if (r->mstackpos < 0) { + mandoc_msg(MANDOCERR_ARG_UNDEF, ln, + (int)(stesc - buf->buf), "%.3s", stesc); + break; + } + ctx = r->mstack + r->mstackpos; + npos = esct[1] - '1'; + if (npos >= 0 && npos <= 8) { + res = npos < ctx->argc ? + ctx->argv[npos] : ""; + break; + } + if (esct[1] == '*') + quote_args = 0; + else if (esct[1] == '@') + quote_args = 1; + else { + mandoc_msg(MANDOCERR_ARG_NONUM, ln, + (int)(stesc - buf->buf), "%.3s", stesc); + break; + } + asz = 0; + for (npos = 0; npos < ctx->argc; npos++) { + if (npos) + asz++; /* blank */ + if (quote_args) + asz += 2; /* quotes */ + asz += strlen(ctx->argv[npos]); + } + if (asz != 3) { + rsz = buf->sz - (stesc - buf->buf) - 3; + if (asz < 3) + memmove(stesc + asz, stesc + 3, rsz); + buf->sz += asz - 3; + nbuf = mandoc_realloc(buf->buf, buf->sz); + start = nbuf + pos; + stesc = nbuf + (stesc - buf->buf); + buf->buf = nbuf; + if (asz > 3) + memmove(stesc + asz, stesc + 3, rsz); + } + for (npos = 0; npos < ctx->argc; npos++) { + if (npos) + *stesc++ = ' '; + if (quote_args) + *stesc++ = '"'; + cp = ctx->argv[npos]; + while (*cp != '\0') + *stesc++ = *cp++; + if (quote_args) + *stesc++ = '"'; + } + continue; + case 'B': + npos = 0; + ubuf[0] = arg_complete && + roff_evalnum(r, ln, stnam, &npos, + NULL, ROFFNUM_SCALE) && + stnam + npos + 1 == cp ? '1' : '0'; + ubuf[1] = '\0'; + break; + case 'n': + if (arg_complete) + (void)snprintf(ubuf, sizeof(ubuf), "%d", + roff_getregn(r, stnam, naml, sign)); + else + ubuf[0] = '\0'; + break; + case 'w': + /* use even incomplete args */ + (void)snprintf(ubuf, sizeof(ubuf), "%d", + 24 * (int)naml); + break; + } + + if (res == NULL) { + if (*esct == '*') + mandoc_msg(MANDOCERR_STR_UNDEF, + ln, (int)(stesc - buf->buf), + "%.*s", (int)naml, stnam); + res = ""; + } else if (buf->sz + strlen(res) > SHRT_MAX) { + mandoc_msg(MANDOCERR_ROFFLOOP, + ln, (int)(stesc - buf->buf), NULL); + return ROFF_IGN; + } + + /* Replace the escape sequence by the string. */ + + *stesc = '\0'; + buf->sz = mandoc_asprintf(&nbuf, "%s%s%s", + buf->buf, res, cp) + 1; + + /* Prepare for the next replacement. */ + + start = nbuf + pos; + stesc = nbuf + (stesc - buf->buf) + strlen(res); + free(buf->buf); + buf->buf = nbuf; + } + return ROFF_CONT; +} + +/* + * Parse a quoted or unquoted roff-style request or macro argument. + * Return a pointer to the parsed argument, which is either the original + * pointer or advanced by one byte in case the argument is quoted. + * NUL-terminate the argument in place. + * Collapse pairs of quotes inside quoted arguments. + * Advance the argument pointer to the next argument, + * or to the NUL byte terminating the argument line. + */ +char * +roff_getarg(struct roff *r, char **cpp, int ln, int *pos) +{ + struct buf buf; + char *cp, *start; + int newesc, pairs, quoted, white; + + /* Quoting can only start with a new word. */ + start = *cpp; + quoted = 0; + if ('"' == *start) { + quoted = 1; + start++; + } + + newesc = pairs = white = 0; + for (cp = start; '\0' != *cp; cp++) { + + /* + * Move the following text left + * after quoted quotes and after "\\" and "\t". + */ + if (pairs) + cp[-pairs] = cp[0]; + + if ('\\' == cp[0]) { + /* + * In copy mode, translate double to single + * backslashes and backslash-t to literal tabs. + */ + switch (cp[1]) { + case 'a': + case 't': + cp[-pairs] = '\t'; + pairs++; + cp++; + break; + case '\\': + newesc = 1; + cp[-pairs] = ASCII_ESC; + pairs++; + cp++; + break; + case ' ': + /* Skip escaped blanks. */ + if (0 == quoted) + cp++; + break; + default: + break; + } + } else if (0 == quoted) { + if (' ' == cp[0]) { + /* Unescaped blanks end unquoted args. */ + white = 1; + break; + } + } else if ('"' == cp[0]) { + if ('"' == cp[1]) { + /* Quoted quotes collapse. */ + pairs++; + cp++; + } else { + /* Unquoted quotes end quoted args. */ + quoted = 2; + break; + } + } + } + + /* Quoted argument without a closing quote. */ + if (1 == quoted) + mandoc_msg(MANDOCERR_ARG_QUOTE, ln, *pos, NULL); + + /* NUL-terminate this argument and move to the next one. */ + if (pairs) + cp[-pairs] = '\0'; + if ('\0' != *cp) { + *cp++ = '\0'; + while (' ' == *cp) + cp++; + } + *pos += (int)(cp - start) + (quoted ? 1 : 0); + *cpp = cp; + + if ('\0' == *cp && (white || ' ' == cp[-1])) + mandoc_msg(MANDOCERR_SPACE_EOL, ln, *pos, NULL); + + start = mandoc_strdup(start); + if (newesc == 0) + return start; + + buf.buf = start; + buf.sz = strlen(start) + 1; + buf.next = NULL; + if (roff_expand(r, &buf, ln, 0, ASCII_ESC) & ROFF_IGN) { + free(buf.buf); + buf.buf = mandoc_strdup(""); + } + return buf.buf; +} + + +/* + * Process text streams. + */ +static int +roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs) +{ + size_t sz; + const char *start; + char *p; + int isz; + enum mandoc_esc esc; + + /* Spring the input line trap. */ + + if (roffit_lines == 1) { + isz = mandoc_asprintf(&p, "%s\n.%s", buf->buf, roffit_macro); + free(buf->buf); + buf->buf = p; + buf->sz = isz + 1; + *offs = 0; + free(roffit_macro); + roffit_lines = 0; + return ROFF_REPARSE; + } else if (roffit_lines > 1) + --roffit_lines; + + if (roffce_node != NULL && buf->buf[pos] != '\0') { + if (roffce_lines < 1) { + r->man->last = roffce_node; + r->man->next = ROFF_NEXT_SIBLING; + roffce_lines = 0; + roffce_node = NULL; + } else + roffce_lines--; + } + + /* Convert all breakable hyphens into ASCII_HYPH. */ + + start = p = buf->buf + pos; + + while (*p != '\0') { + sz = strcspn(p, "-\\"); + p += sz; + + if (*p == '\0') + break; + + if (*p == '\\') { + /* Skip over escapes. */ + p++; + esc = mandoc_escape((const char **)&p, NULL, NULL); + if (esc == ESCAPE_ERROR) + break; + while (*p == '-') + p++; + continue; + } else if (p == start) { + p++; + continue; + } + + if (isalpha((unsigned char)p[-1]) && + isalpha((unsigned char)p[1])) + *p = ASCII_HYPH; + p++; + } + return ROFF_CONT; +} + +int +roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) +{ + enum roff_tok t; + int e; + int pos; /* parse point */ + int spos; /* saved parse point for messages */ + int ppos; /* original offset in buf->buf */ + int ctl; /* macro line (boolean) */ + + ppos = pos = *offs; + + /* Handle in-line equation delimiters. */ + + if (r->tbl == NULL && + r->last_eqn != NULL && r->last_eqn->delim && + (r->eqn == NULL || r->eqn_inline)) { + e = roff_eqndelim(r, buf, pos); + if (e == ROFF_REPARSE) + return e; + assert(e == ROFF_CONT); + } + + /* Expand some escape sequences. */ + + e = roff_expand(r, buf, ln, pos, r->escape); + if ((e & ROFF_MASK) == ROFF_IGN) + return e; + assert(e == ROFF_CONT); + + ctl = roff_getcontrol(r, buf->buf, &pos); + + /* + * First, if a scope is open and we're not a macro, pass the + * text through the macro's filter. + * Equations process all content themselves. + * Tables process almost all content themselves, but we want + * to warn about macros before passing it there. + */ + + if (r->last != NULL && ! ctl) { + t = r->last->tok; + e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs); + if ((e & ROFF_MASK) == ROFF_IGN) + return e; + e &= ~ROFF_MASK; + } else + e = ROFF_IGN; + if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) { + eqn_read(r->eqn, buf->buf + ppos); + return e; + } + if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) { + tbl_read(r->tbl, ln, buf->buf, ppos); + roff_addtbl(r->man, ln, r->tbl); + return e; + } + if ( ! ctl) + return roff_parsetext(r, buf, pos, offs) | e; + + /* Skip empty request lines. */ + + if (buf->buf[pos] == '"') { + mandoc_msg(MANDOCERR_COMMENT_BAD, ln, pos, NULL); + return ROFF_IGN; + } else if (buf->buf[pos] == '\0') + return ROFF_IGN; + + /* + * If a scope is open, go to the child handler for that macro, + * as it may want to preprocess before doing anything with it. + * Don't do so if an equation is open. + */ + + if (r->last) { + t = r->last->tok; + return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs); + } + + /* No scope is open. This is a new request or macro. */ + + spos = pos; + t = roff_parse(r, buf->buf, &pos, ln, ppos); + + /* Tables ignore most macros. */ + + if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS || + t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) { + mandoc_msg(MANDOCERR_TBLMACRO, + ln, pos, "%s", buf->buf + spos); + if (t != TOKEN_NONE) + return ROFF_IGN; + while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ') + pos++; + while (buf->buf[pos] == ' ') + pos++; + tbl_read(r->tbl, ln, buf->buf, pos); + roff_addtbl(r->man, ln, r->tbl); + return ROFF_IGN; + } + + /* For now, let high level macros abort .ce mode. */ + + if (ctl && roffce_node != NULL && + (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ || + t == ROFF_TH || t == ROFF_TS)) { + r->man->last = roffce_node; + r->man->next = ROFF_NEXT_SIBLING; + roffce_lines = 0; + roffce_node = NULL; + } + + /* + * This is neither a roff request nor a user-defined macro. + * Let the standard macro set parsers handle it. + */ + + if (t == TOKEN_NONE) + return ROFF_CONT; + + /* Execute a roff request or a user defined macro. */ + + return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs); +} + +/* + * Internal interface function to tell the roff parser that execution + * of the current macro ended. This is required because macro + * definitions usually do not end with a .return request. + */ +void +roff_userret(struct roff *r) +{ + struct mctx *ctx; + int i; + + assert(r->mstackpos >= 0); + ctx = r->mstack + r->mstackpos; + for (i = 0; i < ctx->argc; i++) + free(ctx->argv[i]); + ctx->argc = 0; + r->mstackpos--; +} + +void +roff_endparse(struct roff *r) +{ + if (r->last != NULL) + mandoc_msg(MANDOCERR_BLK_NOEND, r->last->line, + r->last->col, "%s", roff_name[r->last->tok]); + + if (r->eqn != NULL) { + mandoc_msg(MANDOCERR_BLK_NOEND, + r->eqn->node->line, r->eqn->node->pos, "EQ"); + eqn_parse(r->eqn); + r->eqn = NULL; + } + + if (r->tbl != NULL) { + tbl_end(r->tbl, 1); + r->tbl = NULL; + } +} + +/* + * Parse a roff node's type from the input buffer. This must be in the + * form of ".foo xxx" in the usual way. + */ +static enum roff_tok +roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos) +{ + char *cp; + const char *mac; + size_t maclen; + int deftype; + enum roff_tok t; + + cp = buf + *pos; + + if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp) + return TOKEN_NONE; + + mac = cp; + maclen = roff_getname(r, &cp, ln, ppos); + + deftype = ROFFDEF_USER | ROFFDEF_REN; + r->current_string = roff_getstrn(r, mac, maclen, &deftype); + switch (deftype) { + case ROFFDEF_USER: + t = ROFF_USERDEF; + break; + case ROFFDEF_REN: + t = ROFF_RENAMED; + break; + default: + t = roffhash_find(r->reqtab, mac, maclen); + break; + } + if (t != TOKEN_NONE) + *pos = cp - buf; + else if (deftype == ROFFDEF_UNDEF) { + /* Using an undefined macro defines it to be empty. */ + roff_setstrn(&r->strtab, mac, maclen, "", 0, 0); + roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0); + } + return t; +} + +/* --- handling of request blocks ----------------------------------------- */ + +static int +roff_cblock(ROFF_ARGS) +{ + + /* + * A block-close `..' should only be invoked as a child of an + * ignore macro, otherwise raise a warning and just ignore it. + */ + + if (r->last == NULL) { + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, ".."); + return ROFF_IGN; + } + + switch (r->last->tok) { + case ROFF_am: + /* ROFF_am1 is remapped to ROFF_am in roff_block(). */ + case ROFF_ami: + case ROFF_de: + /* ROFF_de1 is remapped to ROFF_de in roff_block(). */ + case ROFF_dei: + case ROFF_ig: + break; + default: + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, ".."); + return ROFF_IGN; + } + + if (buf->buf[pos] != '\0') + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, + ".. %s", buf->buf + pos); + + roffnode_pop(r); + roffnode_cleanscope(r); + return ROFF_IGN; + +} + +/* + * Pop all nodes ending at the end of the current input line. + * Return the number of loops ended. + */ +static int +roffnode_cleanscope(struct roff *r) +{ + int inloop; + + inloop = 0; + while (r->last != NULL) { + if (--r->last->endspan != 0) + break; + inloop += roffnode_pop(r); + } + return inloop; +} + +/* + * Handle the closing \} of a conditional block. + * Apart from generating warnings, this only pops nodes. + * Return the number of loops ended. + */ +static int +roff_ccond(struct roff *r, int ln, int ppos) +{ + if (NULL == r->last) { + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}"); + return 0; + } + + switch (r->last->tok) { + case ROFF_el: + case ROFF_ie: + case ROFF_if: + case ROFF_while: + break; + default: + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}"); + return 0; + } + + if (r->last->endspan > -1) { + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}"); + return 0; + } + + return roffnode_pop(r) + roffnode_cleanscope(r); +} + +static int +roff_block(ROFF_ARGS) +{ + const char *name, *value; + char *call, *cp, *iname, *rname; + size_t csz, namesz, rsz; + int deftype; + + /* Ignore groff compatibility mode for now. */ + + if (tok == ROFF_de1) + tok = ROFF_de; + else if (tok == ROFF_dei1) + tok = ROFF_dei; + else if (tok == ROFF_am1) + tok = ROFF_am; + else if (tok == ROFF_ami1) + tok = ROFF_ami; + + /* Parse the macro name argument. */ + + cp = buf->buf + pos; + if (tok == ROFF_ig) { + iname = NULL; + namesz = 0; + } else { + iname = cp; + namesz = roff_getname(r, &cp, ln, ppos); + iname[namesz] = '\0'; + } + + /* Resolve the macro name argument if it is indirect. */ + + if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) { + deftype = ROFFDEF_USER; + name = roff_getstrn(r, iname, namesz, &deftype); + if (name == NULL) { + mandoc_msg(MANDOCERR_STR_UNDEF, + ln, (int)(iname - buf->buf), + "%.*s", (int)namesz, iname); + namesz = 0; + } else + namesz = strlen(name); + } else + name = iname; + + if (namesz == 0 && tok != ROFF_ig) { + mandoc_msg(MANDOCERR_REQ_EMPTY, + ln, ppos, "%s", roff_name[tok]); + return ROFF_IGN; + } + + roffnode_push(r, tok, name, ln, ppos); + + /* + * At the beginning of a `de' macro, clear the existing string + * with the same name, if there is one. New content will be + * appended from roff_block_text() in multiline mode. + */ + + if (tok == ROFF_de || tok == ROFF_dei) { + roff_setstrn(&r->strtab, name, namesz, "", 0, 0); + roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); + } else if (tok == ROFF_am || tok == ROFF_ami) { + deftype = ROFFDEF_ANY; + value = roff_getstrn(r, iname, namesz, &deftype); + switch (deftype) { /* Before appending, ... */ + case ROFFDEF_PRE: /* copy predefined to user-defined. */ + roff_setstrn(&r->strtab, name, namesz, + value, strlen(value), 0); + break; + case ROFFDEF_REN: /* call original standard macro. */ + csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n", + (int)strlen(value), value); + roff_setstrn(&r->strtab, name, namesz, call, csz, 0); + roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); + free(call); + break; + case ROFFDEF_STD: /* rename and call standard macro. */ + rsz = mandoc_asprintf(&rname, "__%s_renamed", name); + roff_setstrn(&r->rentab, rname, rsz, name, namesz, 0); + csz = mandoc_asprintf(&call, ".%.*s \\$* \\\"\n", + (int)rsz, rname); + roff_setstrn(&r->strtab, name, namesz, call, csz, 0); + free(call); + free(rname); + break; + default: + break; + } + } + + if (*cp == '\0') + return ROFF_IGN; + + /* Get the custom end marker. */ + + iname = cp; + namesz = roff_getname(r, &cp, ln, ppos); + + /* Resolve the end marker if it is indirect. */ + + if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) { + deftype = ROFFDEF_USER; + name = roff_getstrn(r, iname, namesz, &deftype); + if (name == NULL) { + mandoc_msg(MANDOCERR_STR_UNDEF, + ln, (int)(iname - buf->buf), + "%.*s", (int)namesz, iname); + namesz = 0; + } else + namesz = strlen(name); + } else + name = iname; + + if (namesz) + r->last->end = mandoc_strndup(name, namesz); + + if (*cp != '\0') + mandoc_msg(MANDOCERR_ARG_EXCESS, + ln, pos, ".%s ... %s", roff_name[tok], cp); + + return ROFF_IGN; +} + +static int +roff_block_sub(ROFF_ARGS) +{ + enum roff_tok t; + int i, j; + + /* + * First check whether a custom macro exists at this level. If + * it does, then check against it. This is some of groff's + * stranger behaviours. If we encountered a custom end-scope + * tag and that tag also happens to be a "real" macro, then we + * need to try interpreting it again as a real macro. If it's + * not, then return ignore. Else continue. + */ + + if (r->last->end) { + for (i = pos, j = 0; r->last->end[j]; j++, i++) + if (buf->buf[i] != r->last->end[j]) + break; + + if (r->last->end[j] == '\0' && + (buf->buf[i] == '\0' || + buf->buf[i] == ' ' || + buf->buf[i] == '\t')) { + roffnode_pop(r); + roffnode_cleanscope(r); + + while (buf->buf[i] == ' ' || buf->buf[i] == '\t') + i++; + + pos = i; + if (roff_parse(r, buf->buf, &pos, ln, ppos) != + TOKEN_NONE) + return ROFF_RERUN; + return ROFF_IGN; + } + } + + /* + * If we have no custom end-query or lookup failed, then try + * pulling it out of the hashtable. + */ + + t = roff_parse(r, buf->buf, &pos, ln, ppos); + + if (t != ROFF_cblock) { + if (tok != ROFF_ig) + roff_setstr(r, r->last->name, buf->buf + ppos, 2); + return ROFF_IGN; + } + + return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); +} + +static int +roff_block_text(ROFF_ARGS) +{ + + if (tok != ROFF_ig) + roff_setstr(r, r->last->name, buf->buf + pos, 2); + + return ROFF_IGN; +} + +static int +roff_cond_sub(ROFF_ARGS) +{ + struct roffnode *bl; + char *ep; + int endloop, irc, rr; + enum roff_tok t; + + irc = ROFF_IGN; + rr = r->last->rule; + endloop = tok != ROFF_while ? ROFF_IGN : + rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT; + if (roffnode_cleanscope(r)) + irc |= endloop; + + /* + * If `\}' occurs on a macro line without a preceding macro, + * drop the line completely. + */ + + ep = buf->buf + pos; + if (ep[0] == '\\' && ep[1] == '}') + rr = 0; + + /* + * The closing delimiter `\}' rewinds the conditional scope + * but is otherwise ignored when interpreting the line. + */ + + while ((ep = strchr(ep, '\\')) != NULL) { + switch (ep[1]) { + case '}': + memmove(ep, ep + 2, strlen(ep + 2) + 1); + if (roff_ccond(r, ln, ep - buf->buf)) + irc |= endloop; + break; + case '\0': + ++ep; + break; + default: + ep += 2; + break; + } + } + + /* + * Fully handle known macros when they are structurally + * required or when the conditional evaluated to true. + */ + + t = roff_parse(r, buf->buf, &pos, ln, ppos); + if (t == ROFF_break) { + if (irc & ROFF_LOOPMASK) + irc = ROFF_IGN | ROFF_LOOPEXIT; + else if (rr) { + for (bl = r->last; bl != NULL; bl = bl->parent) { + bl->rule = 0; + if (bl->tok == ROFF_while) + break; + } + } + } else if (t != TOKEN_NONE && + (rr || roffs[t].flags & ROFFMAC_STRUCT)) + irc |= (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); + else + irc |= rr ? ROFF_CONT : ROFF_IGN; + return irc; +} + +static int +roff_cond_text(ROFF_ARGS) +{ + char *ep; + int endloop, irc, rr; + + irc = ROFF_IGN; + rr = r->last->rule; + endloop = tok != ROFF_while ? ROFF_IGN : + rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT; + if (roffnode_cleanscope(r)) + irc |= endloop; + + /* + * If `\}' occurs on a text line with neither preceding + * nor following characters, drop the line completely. + */ + + ep = buf->buf + pos; + if (strcmp(ep, "\\}") == 0) + rr = 0; + + /* + * The closing delimiter `\}' rewinds the conditional scope + * but is otherwise ignored when interpreting the line. + */ + + while ((ep = strchr(ep, '\\')) != NULL) { + switch (ep[1]) { + case '}': + memmove(ep, ep + 2, strlen(ep + 2) + 1); + if (roff_ccond(r, ln, ep - buf->buf)) + irc |= endloop; + break; + case '\0': + ++ep; + break; + default: + ep += 2; + break; + } + } + if (rr) + irc |= ROFF_CONT; + return irc; +} + +/* --- handling of numeric and conditional expressions -------------------- */ + +/* + * Parse a single signed integer number. Stop at the first non-digit. + * If there is at least one digit, return success and advance the + * parse point, else return failure and let the parse point unchanged. + * Ignore overflows, treat them just like the C language. + */ +static int +roff_getnum(const char *v, int *pos, int *res, int flags) +{ + int myres, scaled, n, p; + + if (NULL == res) + res = &myres; + + p = *pos; + n = v[p] == '-'; + if (n || v[p] == '+') + p++; + + if (flags & ROFFNUM_WHITE) + while (isspace((unsigned char)v[p])) + p++; + + for (*res = 0; isdigit((unsigned char)v[p]); p++) + *res = 10 * *res + v[p] - '0'; + if (p == *pos + n) + return 0; + + if (n) + *res = -*res; + + /* Each number may be followed by one optional scaling unit. */ + + switch (v[p]) { + case 'f': + scaled = *res * 65536; + break; + case 'i': + scaled = *res * 240; + break; + case 'c': + scaled = *res * 240 / 2.54; + break; + case 'v': + case 'P': + scaled = *res * 40; + break; + case 'm': + case 'n': + scaled = *res * 24; + break; + case 'p': + scaled = *res * 10 / 3; + break; + case 'u': + scaled = *res; + break; + case 'M': + scaled = *res * 6 / 25; + break; + default: + scaled = *res; + p--; + break; + } + if (flags & ROFFNUM_SCALE) + *res = scaled; + + *pos = p + 1; + return 1; +} + +/* + * Evaluate a string comparison condition. + * The first character is the delimiter. + * Succeed if the string up to its second occurrence + * matches the string up to its third occurence. + * Advance the cursor after the third occurrence + * or lacking that, to the end of the line. + */ +static int +roff_evalstrcond(const char *v, int *pos) +{ + const char *s1, *s2, *s3; + int match; + + match = 0; + s1 = v + *pos; /* initial delimiter */ + s2 = s1 + 1; /* for scanning the first string */ + s3 = strchr(s2, *s1); /* for scanning the second string */ + + if (NULL == s3) /* found no middle delimiter */ + goto out; + + while ('\0' != *++s3) { + if (*s2 != *s3) { /* mismatch */ + s3 = strchr(s3, *s1); + break; + } + if (*s3 == *s1) { /* found the final delimiter */ + match = 1; + break; + } + s2++; + } + +out: + if (NULL == s3) + s3 = strchr(s2, '\0'); + else if (*s3 != '\0') + s3++; + *pos = s3 - v; + return match; +} + +/* + * Evaluate an optionally negated single character, numerical, + * or string condition. + */ +static int +roff_evalcond(struct roff *r, int ln, char *v, int *pos) +{ + const char *start, *end; + char *cp, *name; + size_t sz; + int deftype, len, number, savepos, istrue, wanttrue; + + if ('!' == v[*pos]) { + wanttrue = 0; + (*pos)++; + } else + wanttrue = 1; + + switch (v[*pos]) { + case '\0': + return 0; + case 'n': + case 'o': + (*pos)++; + return wanttrue; + case 'e': + case 't': + case 'v': + (*pos)++; + return !wanttrue; + case 'c': + do { + (*pos)++; + } while (v[*pos] == ' '); + + /* + * Quirk for groff compatibility: + * The horizontal tab is neither available nor unavailable. + */ + + if (v[*pos] == '\t') { + (*pos)++; + return 0; + } + + /* Printable ASCII characters are available. */ + + if (v[*pos] != '\\') { + (*pos)++; + return wanttrue; + } + + end = v + ++*pos; + switch (mandoc_escape(&end, &start, &len)) { + case ESCAPE_SPECIAL: + istrue = mchars_spec2cp(start, len) != -1; + break; + case ESCAPE_UNICODE: + istrue = 1; + break; + case ESCAPE_NUMBERED: + istrue = mchars_num2char(start, len) != -1; + break; + default: + istrue = !wanttrue; + break; + } + *pos = end - v; + return istrue == wanttrue; + case 'd': + case 'r': + cp = v + *pos + 1; + while (*cp == ' ') + cp++; + name = cp; + sz = roff_getname(r, &cp, ln, cp - v); + if (sz == 0) + istrue = 0; + else if (v[*pos] == 'r') + istrue = roff_hasregn(r, name, sz); + else { + deftype = ROFFDEF_ANY; + roff_getstrn(r, name, sz, &deftype); + istrue = !!deftype; + } + *pos = (name + sz) - v; + return istrue == wanttrue; + default: + break; + } + + savepos = *pos; + if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE)) + return (number > 0) == wanttrue; + else if (*pos == savepos) + return roff_evalstrcond(v, pos) == wanttrue; + else + return 0; +} + +static int +roff_line_ignore(ROFF_ARGS) +{ + + return ROFF_IGN; +} + +static int +roff_insec(ROFF_ARGS) +{ + + mandoc_msg(MANDOCERR_REQ_INSEC, ln, ppos, "%s", roff_name[tok]); + return ROFF_IGN; +} + +static int +roff_unsupp(ROFF_ARGS) +{ + + mandoc_msg(MANDOCERR_REQ_UNSUPP, ln, ppos, "%s", roff_name[tok]); + return ROFF_IGN; +} + +static int +roff_cond(ROFF_ARGS) +{ + int irc; + + roffnode_push(r, tok, NULL, ln, ppos); + + /* + * An `.el' has no conditional body: it will consume the value + * of the current rstack entry set in prior `ie' calls or + * defaults to DENY. + * + * If we're not an `el', however, then evaluate the conditional. + */ + + r->last->rule = tok == ROFF_el ? + (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) : + roff_evalcond(r, ln, buf->buf, &pos); + + /* + * An if-else will put the NEGATION of the current evaluated + * conditional into the stack of rules. + */ + + if (tok == ROFF_ie) { + if (r->rstackpos + 1 == r->rstacksz) { + r->rstacksz += 16; + r->rstack = mandoc_reallocarray(r->rstack, + r->rstacksz, sizeof(int)); + } + r->rstack[++r->rstackpos] = !r->last->rule; + } + + /* If the parent has false as its rule, then so do we. */ + + if (r->last->parent && !r->last->parent->rule) + r->last->rule = 0; + + /* + * Determine scope. + * If there is nothing on the line after the conditional, + * not even whitespace, use next-line scope. + * Except that .while does not support next-line scope. + */ + + if (buf->buf[pos] == '\0' && tok != ROFF_while) { + r->last->endspan = 2; + goto out; + } + + while (buf->buf[pos] == ' ') + pos++; + + /* An opening brace requests multiline scope. */ + + if (buf->buf[pos] == '\\' && buf->buf[pos + 1] == '{') { + r->last->endspan = -1; + pos += 2; + while (buf->buf[pos] == ' ') + pos++; + goto out; + } + + /* + * Anything else following the conditional causes + * single-line scope. Warn if the scope contains + * nothing but trailing whitespace. + */ + + if (buf->buf[pos] == '\0') + mandoc_msg(MANDOCERR_COND_EMPTY, + ln, ppos, "%s", roff_name[tok]); + + r->last->endspan = 1; + +out: + *offs = pos; + irc = ROFF_RERUN; + if (tok == ROFF_while) + irc |= ROFF_WHILE; + return irc; +} + +static int +roff_ds(ROFF_ARGS) +{ + char *string; + const char *name; + size_t namesz; + + /* Ignore groff compatibility mode for now. */ + + if (tok == ROFF_ds1) + tok = ROFF_ds; + else if (tok == ROFF_as1) + tok = ROFF_as; + + /* + * The first word is the name of the string. + * If it is empty or terminated by an escape sequence, + * abort the `ds' request without defining anything. + */ + + name = string = buf->buf + pos; + if (*name == '\0') + return ROFF_IGN; + + namesz = roff_getname(r, &string, ln, pos); + switch (name[namesz]) { + case '\\': + return ROFF_IGN; + case '\t': + string = buf->buf + pos + namesz; + break; + default: + break; + } + + /* Read past the initial double-quote, if any. */ + if (*string == '"') + string++; + + /* The rest is the value. */ + roff_setstrn(&r->strtab, name, namesz, string, strlen(string), + ROFF_as == tok); + roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); + return ROFF_IGN; +} + +/* + * Parse a single operator, one or two characters long. + * If the operator is recognized, return success and advance the + * parse point, else return failure and let the parse point unchanged. + */ +static int +roff_getop(const char *v, int *pos, char *res) +{ + + *res = v[*pos]; + + switch (*res) { + case '+': + case '-': + case '*': + case '/': + case '%': + case '&': + case ':': + break; + case '<': + switch (v[*pos + 1]) { + case '=': + *res = 'l'; + (*pos)++; + break; + case '>': + *res = '!'; + (*pos)++; + break; + case '?': + *res = 'i'; + (*pos)++; + break; + default: + break; + } + break; + case '>': + switch (v[*pos + 1]) { + case '=': + *res = 'g'; + (*pos)++; + break; + case '?': + *res = 'a'; + (*pos)++; + break; + default: + break; + } + break; + case '=': + if ('=' == v[*pos + 1]) + (*pos)++; + break; + default: + return 0; + } + (*pos)++; + + return *res; +} + +/* + * Evaluate either a parenthesized numeric expression + * or a single signed integer number. + */ +static int +roff_evalpar(struct roff *r, int ln, + const char *v, int *pos, int *res, int flags) +{ + + if ('(' != v[*pos]) + return roff_getnum(v, pos, res, flags); + + (*pos)++; + if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE)) + return 0; + + /* + * Omission of the closing parenthesis + * is an error in validation mode, + * but ignored in evaluation mode. + */ + + if (')' == v[*pos]) + (*pos)++; + else if (NULL == res) + return 0; + + return 1; +} + +/* + * Evaluate a complete numeric expression. + * Proceed left to right, there is no concept of precedence. + */ +static int +roff_evalnum(struct roff *r, int ln, const char *v, + int *pos, int *res, int flags) +{ + int mypos, operand2; + char operator; + + if (NULL == pos) { + mypos = 0; + pos = &mypos; + } + + if (flags & ROFFNUM_WHITE) + while (isspace((unsigned char)v[*pos])) + (*pos)++; + + if ( ! roff_evalpar(r, ln, v, pos, res, flags)) + return 0; + + while (1) { + if (flags & ROFFNUM_WHITE) + while (isspace((unsigned char)v[*pos])) + (*pos)++; + + if ( ! roff_getop(v, pos, &operator)) + break; + + if (flags & ROFFNUM_WHITE) + while (isspace((unsigned char)v[*pos])) + (*pos)++; + + if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags)) + return 0; + + if (flags & ROFFNUM_WHITE) + while (isspace((unsigned char)v[*pos])) + (*pos)++; + + if (NULL == res) + continue; + + switch (operator) { + case '+': + *res += operand2; + break; + case '-': + *res -= operand2; + break; + case '*': + *res *= operand2; + break; + case '/': + if (operand2 == 0) { + mandoc_msg(MANDOCERR_DIVZERO, + ln, *pos, "%s", v); + *res = 0; + break; + } + *res /= operand2; + break; + case '%': + if (operand2 == 0) { + mandoc_msg(MANDOCERR_DIVZERO, + ln, *pos, "%s", v); + *res = 0; + break; + } + *res %= operand2; + break; + case '<': + *res = *res < operand2; + break; + case '>': + *res = *res > operand2; + break; + case 'l': + *res = *res <= operand2; + break; + case 'g': + *res = *res >= operand2; + break; + case '=': + *res = *res == operand2; + break; + case '!': + *res = *res != operand2; + break; + case '&': + *res = *res && operand2; + break; + case ':': + *res = *res || operand2; + break; + case 'i': + if (operand2 < *res) + *res = operand2; + break; + case 'a': + if (operand2 > *res) + *res = operand2; + break; + default: + abort(); + } + } + return 1; +} + +/* --- register management ------------------------------------------------ */ + +void +roff_setreg(struct roff *r, const char *name, int val, char sign) +{ + roff_setregn(r, name, strlen(name), val, sign, INT_MIN); +} + +static void +roff_setregn(struct roff *r, const char *name, size_t len, + int val, char sign, int step) +{ + struct roffreg *reg; + + /* Search for an existing register with the same name. */ + reg = r->regtab; + + while (reg != NULL && (reg->key.sz != len || + strncmp(reg->key.p, name, len) != 0)) + reg = reg->next; + + if (NULL == reg) { + /* Create a new register. */ + reg = mandoc_malloc(sizeof(struct roffreg)); + reg->key.p = mandoc_strndup(name, len); + reg->key.sz = len; + reg->val = 0; + reg->step = 0; + reg->next = r->regtab; + r->regtab = reg; + } + + if ('+' == sign) + reg->val += val; + else if ('-' == sign) + reg->val -= val; + else + reg->val = val; + if (step != INT_MIN) + reg->step = step; +} + +/* + * Handle some predefined read-only number registers. + * For now, return -1 if the requested register is not predefined; + * in case a predefined read-only register having the value -1 + * were to turn up, another special value would have to be chosen. + */ +static int +roff_getregro(const struct roff *r, const char *name) +{ + + switch (*name) { + case '$': /* Number of arguments of the last macro evaluated. */ + return r->mstackpos < 0 ? 0 : r->mstack[r->mstackpos].argc; + case 'A': /* ASCII approximation mode is always off. */ + return 0; + case 'g': /* Groff compatibility mode is always on. */ + return 1; + case 'H': /* Fixed horizontal resolution. */ + return 24; + case 'j': /* Always adjust left margin only. */ + return 0; + case 'T': /* Some output device is always defined. */ + return 1; + case 'V': /* Fixed vertical resolution. */ + return 40; + default: + return -1; + } +} + +int +roff_getreg(struct roff *r, const char *name) +{ + return roff_getregn(r, name, strlen(name), '\0'); +} + +static int +roff_getregn(struct roff *r, const char *name, size_t len, char sign) +{ + struct roffreg *reg; + int val; + + if ('.' == name[0] && 2 == len) { + val = roff_getregro(r, name + 1); + if (-1 != val) + return val; + } + + for (reg = r->regtab; reg; reg = reg->next) { + if (len == reg->key.sz && + 0 == strncmp(name, reg->key.p, len)) { + switch (sign) { + case '+': + reg->val += reg->step; + break; + case '-': + reg->val -= reg->step; + break; + default: + break; + } + return reg->val; + } + } + + roff_setregn(r, name, len, 0, '\0', INT_MIN); + return 0; +} + +static int +roff_hasregn(const struct roff *r, const char *name, size_t len) +{ + struct roffreg *reg; + int val; + + if ('.' == name[0] && 2 == len) { + val = roff_getregro(r, name + 1); + if (-1 != val) + return 1; + } + + for (reg = r->regtab; reg; reg = reg->next) + if (len == reg->key.sz && + 0 == strncmp(name, reg->key.p, len)) + return 1; + + return 0; +} + +static void +roff_freereg(struct roffreg *reg) +{ + struct roffreg *old_reg; + + while (NULL != reg) { + free(reg->key.p); + old_reg = reg; + reg = reg->next; + free(old_reg); + } +} + +static int +roff_nr(ROFF_ARGS) +{ + char *key, *val, *step; + size_t keysz; + int iv, is, len; + char sign; + + key = val = buf->buf + pos; + if (*key == '\0') + return ROFF_IGN; + + keysz = roff_getname(r, &val, ln, pos); + if (key[keysz] == '\\' || key[keysz] == '\t') + return ROFF_IGN; + + sign = *val; + if (sign == '+' || sign == '-') + val++; + + len = 0; + if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0) + return ROFF_IGN; + + step = val + len; + while (isspace((unsigned char)*step)) + step++; + if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0) + is = INT_MIN; + + roff_setregn(r, key, keysz, iv, sign, is); + return ROFF_IGN; +} + +static int +roff_rr(ROFF_ARGS) +{ + struct roffreg *reg, **prev; + char *name, *cp; + size_t namesz; + + name = cp = buf->buf + pos; + if (*name == '\0') + return ROFF_IGN; + namesz = roff_getname(r, &cp, ln, pos); + name[namesz] = '\0'; + + prev = &r->regtab; + while (1) { + reg = *prev; + if (reg == NULL || !strcmp(name, reg->key.p)) + break; + prev = ®->next; + } + if (reg != NULL) { + *prev = reg->next; + free(reg->key.p); + free(reg); + } + return ROFF_IGN; +} + +/* --- handler functions for roff requests -------------------------------- */ + +static int +roff_rm(ROFF_ARGS) +{ + const char *name; + char *cp; + size_t namesz; + + cp = buf->buf + pos; + while (*cp != '\0') { + name = cp; + namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf)); + roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0); + roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); + if (name[namesz] == '\\' || name[namesz] == '\t') + break; + } + return ROFF_IGN; +} + +static int +roff_it(ROFF_ARGS) +{ + int iv; + + /* Parse the number of lines. */ + + if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) { + mandoc_msg(MANDOCERR_IT_NONUM, + ln, ppos, "%s", buf->buf + 1); + return ROFF_IGN; + } + + while (isspace((unsigned char)buf->buf[pos])) + pos++; + + /* + * Arm the input line trap. + * Special-casing "an-trap" is an ugly workaround to cope + * with DocBook stupidly fiddling with man(7) internals. + */ + + roffit_lines = iv; + roffit_macro = mandoc_strdup(iv != 1 || + strcmp(buf->buf + pos, "an-trap") ? + buf->buf + pos : "br"); + return ROFF_IGN; +} + +static int +roff_Dd(ROFF_ARGS) +{ + int mask; + enum roff_tok t, te; + + switch (tok) { + case ROFF_Dd: + tok = MDOC_Dd; + te = MDOC_MAX; + if (r->format == 0) + r->format = MPARSE_MDOC; + mask = MPARSE_MDOC | MPARSE_QUICK; + break; + case ROFF_TH: + tok = MAN_TH; + te = MAN_MAX; + if (r->format == 0) + r->format = MPARSE_MAN; + mask = MPARSE_QUICK; + break; + default: + abort(); + } + if ((r->options & mask) == 0) + for (t = tok; t < te; t++) + roff_setstr(r, roff_name[t], NULL, 0); + return ROFF_CONT; +} + +static int +roff_TE(ROFF_ARGS) +{ + r->man->flags &= ~ROFF_NONOFILL; + if (r->tbl == NULL) { + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "TE"); + return ROFF_IGN; + } + if (tbl_end(r->tbl, 0) == 0) { + r->tbl = NULL; + free(buf->buf); + buf->buf = mandoc_strdup(".sp"); + buf->sz = 4; + *offs = 0; + return ROFF_REPARSE; + } + r->tbl = NULL; + return ROFF_IGN; +} + +static int +roff_T_(ROFF_ARGS) +{ + + if (NULL == r->tbl) + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "T&"); + else + tbl_restart(ln, ppos, r->tbl); + + return ROFF_IGN; +} + +/* + * Handle in-line equation delimiters. + */ +static int +roff_eqndelim(struct roff *r, struct buf *buf, int pos) +{ + char *cp1, *cp2; + const char *bef_pr, *bef_nl, *mac, *aft_nl, *aft_pr; + + /* + * Outside equations, look for an opening delimiter. + * If we are inside an equation, we already know it is + * in-line, or this function wouldn't have been called; + * so look for a closing delimiter. + */ + + cp1 = buf->buf + pos; + cp2 = strchr(cp1, r->eqn == NULL ? + r->last_eqn->odelim : r->last_eqn->cdelim); + if (cp2 == NULL) + return ROFF_CONT; + + *cp2++ = '\0'; + bef_pr = bef_nl = aft_nl = aft_pr = ""; + + /* Handle preceding text, protecting whitespace. */ + + if (*buf->buf != '\0') { + if (r->eqn == NULL) + bef_pr = "\\&"; + bef_nl = "\n"; + } + + /* + * Prepare replacing the delimiter with an equation macro + * and drop leading white space from the equation. + */ + + if (r->eqn == NULL) { + while (*cp2 == ' ') + cp2++; + mac = ".EQ"; + } else + mac = ".EN"; + + /* Handle following text, protecting whitespace. */ + + if (*cp2 != '\0') { + aft_nl = "\n"; + if (r->eqn != NULL) + aft_pr = "\\&"; + } + + /* Do the actual replacement. */ + + buf->sz = mandoc_asprintf(&cp1, "%s%s%s%s%s%s%s", buf->buf, + bef_pr, bef_nl, mac, aft_nl, aft_pr, cp2) + 1; + free(buf->buf); + buf->buf = cp1; + + /* Toggle the in-line state of the eqn subsystem. */ + + r->eqn_inline = r->eqn == NULL; + return ROFF_REPARSE; +} + +static int +roff_EQ(ROFF_ARGS) +{ + struct roff_node *n; + + if (r->man->meta.macroset == MACROSET_MAN) + man_breakscope(r->man, ROFF_EQ); + n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE); + if (ln > r->man->last->line) + n->flags |= NODE_LINE; + n->eqn = eqn_box_new(); + roff_node_append(r->man, n); + r->man->next = ROFF_NEXT_SIBLING; + + assert(r->eqn == NULL); + if (r->last_eqn == NULL) + r->last_eqn = eqn_alloc(); + else + eqn_reset(r->last_eqn); + r->eqn = r->last_eqn; + r->eqn->node = n; + + if (buf->buf[pos] != '\0') + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, + ".EQ %s", buf->buf + pos); + + return ROFF_IGN; +} + +static int +roff_EN(ROFF_ARGS) +{ + if (r->eqn != NULL) { + eqn_parse(r->eqn); + r->eqn = NULL; + } else + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "EN"); + if (buf->buf[pos] != '\0') + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, + "EN %s", buf->buf + pos); + return ROFF_IGN; +} + +static int +roff_TS(ROFF_ARGS) +{ + if (r->tbl != NULL) { + mandoc_msg(MANDOCERR_BLK_BROKEN, ln, ppos, "TS breaks TS"); + tbl_end(r->tbl, 0); + } + r->man->flags |= ROFF_NONOFILL; + r->tbl = tbl_alloc(ppos, ln, r->last_tbl); + if (r->last_tbl == NULL) + r->first_tbl = r->tbl; + r->last_tbl = r->tbl; + return ROFF_IGN; +} + +static int +roff_noarg(ROFF_ARGS) +{ + if (r->man->flags & (MAN_BLINE | MAN_ELINE)) + man_breakscope(r->man, tok); + if (tok == ROFF_brp) + tok = ROFF_br; + roff_elem_alloc(r->man, ln, ppos, tok); + if (buf->buf[pos] != '\0') + mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, + "%s %s", roff_name[tok], buf->buf + pos); + if (tok == ROFF_nf) + r->man->flags |= ROFF_NOFILL; + else if (tok == ROFF_fi) + r->man->flags &= ~ROFF_NOFILL; + r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; + r->man->next = ROFF_NEXT_SIBLING; + return ROFF_IGN; +} + +static int +roff_onearg(ROFF_ARGS) +{ + struct roff_node *n; + char *cp; + int npos; + + if (r->man->flags & (MAN_BLINE | MAN_ELINE) && + (tok == ROFF_ce || tok == ROFF_rj || tok == ROFF_sp || + tok == ROFF_ti)) + man_breakscope(r->man, tok); + + if (roffce_node != NULL && (tok == ROFF_ce || tok == ROFF_rj)) { + r->man->last = roffce_node; + r->man->next = ROFF_NEXT_SIBLING; + } + + roff_elem_alloc(r->man, ln, ppos, tok); + n = r->man->last; + + cp = buf->buf + pos; + if (*cp != '\0') { + while (*cp != '\0' && *cp != ' ') + cp++; + while (*cp == ' ') + *cp++ = '\0'; + if (*cp != '\0') + mandoc_msg(MANDOCERR_ARG_EXCESS, + ln, (int)(cp - buf->buf), + "%s ... %s", roff_name[tok], cp); + roff_word_alloc(r->man, ln, pos, buf->buf + pos); + } + + if (tok == ROFF_ce || tok == ROFF_rj) { + if (r->man->last->type == ROFFT_ELEM) { + roff_word_alloc(r->man, ln, pos, "1"); + r->man->last->flags |= NODE_NOSRC; + } + npos = 0; + if (roff_evalnum(r, ln, r->man->last->string, &npos, + &roffce_lines, 0) == 0) { + mandoc_msg(MANDOCERR_CE_NONUM, + ln, pos, "ce %s", buf->buf + pos); + roffce_lines = 1; + } + if (roffce_lines < 1) { + r->man->last = r->man->last->parent; + roffce_node = NULL; + roffce_lines = 0; + } else + roffce_node = r->man->last->parent; + } else { + n->flags |= NODE_VALID | NODE_ENDED; + r->man->last = n; + } + n->flags |= NODE_LINE; + r->man->next = ROFF_NEXT_SIBLING; + return ROFF_IGN; +} + +static int +roff_manyarg(ROFF_ARGS) +{ + struct roff_node *n; + char *sp, *ep; + + roff_elem_alloc(r->man, ln, ppos, tok); + n = r->man->last; + + for (sp = ep = buf->buf + pos; *sp != '\0'; sp = ep) { + while (*ep != '\0' && *ep != ' ') + ep++; + while (*ep == ' ') + *ep++ = '\0'; + roff_word_alloc(r->man, ln, sp - buf->buf, sp); + } + + n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; + r->man->last = n; + r->man->next = ROFF_NEXT_SIBLING; + return ROFF_IGN; +} + +static int +roff_als(ROFF_ARGS) +{ + char *oldn, *newn, *end, *value; + size_t oldsz, newsz, valsz; + + newn = oldn = buf->buf + pos; + if (*newn == '\0') + return ROFF_IGN; + + newsz = roff_getname(r, &oldn, ln, pos); + if (newn[newsz] == '\\' || newn[newsz] == '\t' || *oldn == '\0') + return ROFF_IGN; + + end = oldn; + oldsz = roff_getname(r, &end, ln, oldn - buf->buf); + if (oldsz == 0) + return ROFF_IGN; + + valsz = mandoc_asprintf(&value, ".%.*s \\$@\\\"\n", + (int)oldsz, oldn); + roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0); + roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); + free(value); + return ROFF_IGN; +} + +/* + * The .break request only makes sense inside conditionals, + * and that case is already handled in roff_cond_sub(). + */ +static int +roff_break(ROFF_ARGS) +{ + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, pos, "break"); + return ROFF_IGN; +} + +static int +roff_cc(ROFF_ARGS) +{ + const char *p; + + p = buf->buf + pos; + + if (*p == '\0' || (r->control = *p++) == '.') + r->control = '\0'; + + if (*p != '\0') + mandoc_msg(MANDOCERR_ARG_EXCESS, + ln, p - buf->buf, "cc ... %s", p); + + return ROFF_IGN; +} + +static int +roff_char(ROFF_ARGS) +{ + const char *p, *kp, *vp; + size_t ksz, vsz; + int font; + + /* Parse the character to be replaced. */ + + kp = buf->buf + pos; + p = kp + 1; + if (*kp == '\0' || (*kp == '\\' && + mandoc_escape(&p, NULL, NULL) != ESCAPE_SPECIAL) || + (*p != ' ' && *p != '\0')) { + mandoc_msg(MANDOCERR_CHAR_ARG, ln, pos, "char %s", kp); + return ROFF_IGN; + } + ksz = p - kp; + while (*p == ' ') + p++; + + /* + * If the replacement string contains a font escape sequence, + * we have to restore the font at the end. + */ + + vp = p; + vsz = strlen(p); + font = 0; + while (*p != '\0') { + if (*p++ != '\\') + continue; + switch (mandoc_escape(&p, NULL, NULL)) { + case ESCAPE_FONT: + case ESCAPE_FONTROMAN: + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTBI: + case ESCAPE_FONTCW: + case ESCAPE_FONTPREV: + font++; + break; + default: + break; + } + } + if (font > 1) + mandoc_msg(MANDOCERR_CHAR_FONT, + ln, (int)(vp - buf->buf), "%s", vp); + + /* + * Approximate the effect of .char using the .tr tables. + * XXX In groff, .char and .tr interact differently. + */ + + if (ksz == 1) { + if (r->xtab == NULL) + r->xtab = mandoc_calloc(128, sizeof(*r->xtab)); + assert((unsigned int)*kp < 128); + free(r->xtab[(int)*kp].p); + r->xtab[(int)*kp].sz = mandoc_asprintf(&r->xtab[(int)*kp].p, + "%s%s", vp, font ? "\fP" : ""); + } else { + roff_setstrn(&r->xmbtab, kp, ksz, vp, vsz, 0); + if (font) + roff_setstrn(&r->xmbtab, kp, ksz, "\\fP", 3, 1); + } + return ROFF_IGN; +} + +static int +roff_ec(ROFF_ARGS) +{ + const char *p; + + p = buf->buf + pos; + if (*p == '\0') + r->escape = '\\'; + else { + r->escape = *p; + if (*++p != '\0') + mandoc_msg(MANDOCERR_ARG_EXCESS, ln, + (int)(p - buf->buf), "ec ... %s", p); + } + return ROFF_IGN; +} + +static int +roff_eo(ROFF_ARGS) +{ + r->escape = '\0'; + if (buf->buf[pos] != '\0') + mandoc_msg(MANDOCERR_ARG_SKIP, + ln, pos, "eo %s", buf->buf + pos); + return ROFF_IGN; +} + +static int +roff_nop(ROFF_ARGS) +{ + while (buf->buf[pos] == ' ') + pos++; + *offs = pos; + return ROFF_RERUN; +} + +static int +roff_tr(ROFF_ARGS) +{ + const char *p, *first, *second; + size_t fsz, ssz; + enum mandoc_esc esc; + + p = buf->buf + pos; + + if (*p == '\0') { + mandoc_msg(MANDOCERR_REQ_EMPTY, ln, ppos, "tr"); + return ROFF_IGN; + } + + while (*p != '\0') { + fsz = ssz = 1; + + first = p++; + if (*first == '\\') { + esc = mandoc_escape(&p, NULL, NULL); + if (esc == ESCAPE_ERROR) { + mandoc_msg(MANDOCERR_ESC_BAD, ln, + (int)(p - buf->buf), "%s", first); + return ROFF_IGN; + } + fsz = (size_t)(p - first); + } + + second = p++; + if (*second == '\\') { + esc = mandoc_escape(&p, NULL, NULL); + if (esc == ESCAPE_ERROR) { + mandoc_msg(MANDOCERR_ESC_BAD, ln, + (int)(p - buf->buf), "%s", second); + return ROFF_IGN; + } + ssz = (size_t)(p - second); + } else if (*second == '\0') { + mandoc_msg(MANDOCERR_TR_ODD, ln, + (int)(first - buf->buf), "tr %s", first); + second = " "; + p--; + } + + if (fsz > 1) { + roff_setstrn(&r->xmbtab, first, fsz, + second, ssz, 0); + continue; + } + + if (r->xtab == NULL) + r->xtab = mandoc_calloc(128, + sizeof(struct roffstr)); + + free(r->xtab[(int)*first].p); + r->xtab[(int)*first].p = mandoc_strndup(second, ssz); + r->xtab[(int)*first].sz = ssz; + } + + return ROFF_IGN; +} + +/* + * Implementation of the .return request. + * There is no need to call roff_userret() from here. + * The read module will call that after rewinding the reader stack + * to the place from where the current macro was called. + */ +static int +roff_return(ROFF_ARGS) +{ + if (r->mstackpos >= 0) + return ROFF_IGN | ROFF_USERRET; + + mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "return"); + return ROFF_IGN; +} + +static int +roff_rn(ROFF_ARGS) +{ + const char *value; + char *oldn, *newn, *end; + size_t oldsz, newsz; + int deftype; + + oldn = newn = buf->buf + pos; + if (*oldn == '\0') + return ROFF_IGN; + + oldsz = roff_getname(r, &newn, ln, pos); + if (oldn[oldsz] == '\\' || oldn[oldsz] == '\t' || *newn == '\0') + return ROFF_IGN; + + end = newn; + newsz = roff_getname(r, &end, ln, newn - buf->buf); + if (newsz == 0) + return ROFF_IGN; + + deftype = ROFFDEF_ANY; + value = roff_getstrn(r, oldn, oldsz, &deftype); + switch (deftype) { + case ROFFDEF_USER: + roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0); + roff_setstrn(&r->strtab, oldn, oldsz, NULL, 0, 0); + roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); + break; + case ROFFDEF_PRE: + roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0); + roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); + break; + case ROFFDEF_REN: + roff_setstrn(&r->rentab, newn, newsz, value, strlen(value), 0); + roff_setstrn(&r->rentab, oldn, oldsz, NULL, 0, 0); + roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); + break; + case ROFFDEF_STD: + roff_setstrn(&r->rentab, newn, newsz, oldn, oldsz, 0); + roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); + break; + default: + roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); + roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); + break; + } + return ROFF_IGN; +} + +static int +roff_shift(ROFF_ARGS) +{ + struct mctx *ctx; + int levels, i; + + levels = 1; + if (buf->buf[pos] != '\0' && + roff_evalnum(r, ln, buf->buf, &pos, &levels, 0) == 0) { + mandoc_msg(MANDOCERR_CE_NONUM, + ln, pos, "shift %s", buf->buf + pos); + levels = 1; + } + if (r->mstackpos < 0) { + mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "shift"); + return ROFF_IGN; + } + ctx = r->mstack + r->mstackpos; + if (levels > ctx->argc) { + mandoc_msg(MANDOCERR_SHIFT, + ln, pos, "%d, but max is %d", levels, ctx->argc); + levels = ctx->argc; + } + if (levels == 0) + return ROFF_IGN; + for (i = 0; i < levels; i++) + free(ctx->argv[i]); + ctx->argc -= levels; + for (i = 0; i < ctx->argc; i++) + ctx->argv[i] = ctx->argv[i + levels]; + return ROFF_IGN; +} + +static int +roff_so(ROFF_ARGS) +{ + char *name, *cp; + + name = buf->buf + pos; + mandoc_msg(MANDOCERR_SO, ln, ppos, "so %s", name); + + /* + * Handle `so'. Be EXTREMELY careful, as we shouldn't be + * opening anything that's not in our cwd or anything beneath + * it. Thus, explicitly disallow traversing up the file-system + * or using absolute paths. + */ + + if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) { + mandoc_msg(MANDOCERR_SO_PATH, ln, ppos, ".so %s", name); + buf->sz = mandoc_asprintf(&cp, + ".sp\nSee the file %s.\n.sp", name) + 1; + free(buf->buf); + buf->buf = cp; + *offs = 0; + return ROFF_REPARSE; + } + + *offs = pos; + return ROFF_SO; +} + +/* --- user defined strings and macros ------------------------------------ */ + +static int +roff_userdef(ROFF_ARGS) +{ + struct mctx *ctx; + char *arg, *ap, *dst, *src; + size_t sz; + + /* If the macro is empty, ignore it altogether. */ + + if (*r->current_string == '\0') + return ROFF_IGN; + + /* Initialize a new macro stack context. */ + + if (++r->mstackpos == r->mstacksz) { + r->mstack = mandoc_recallocarray(r->mstack, + r->mstacksz, r->mstacksz + 8, sizeof(*r->mstack)); + r->mstacksz += 8; + } + ctx = r->mstack + r->mstackpos; + ctx->argsz = 0; + ctx->argc = 0; + ctx->argv = NULL; + + /* + * Collect pointers to macro argument strings, + * NUL-terminating them and escaping quotes. + */ + + src = buf->buf + pos; + while (*src != '\0') { + if (ctx->argc == ctx->argsz) { + ctx->argsz += 8; + ctx->argv = mandoc_reallocarray(ctx->argv, + ctx->argsz, sizeof(*ctx->argv)); + } + arg = roff_getarg(r, &src, ln, &pos); + sz = 1; /* For the terminating NUL. */ + for (ap = arg; *ap != '\0'; ap++) + sz += *ap == '"' ? 4 : 1; + ctx->argv[ctx->argc++] = dst = mandoc_malloc(sz); + for (ap = arg; *ap != '\0'; ap++) { + if (*ap == '"') { + memcpy(dst, "\\(dq", 4); + dst += 4; + } else + *dst++ = *ap; + } + *dst = '\0'; + free(arg); + } + + /* Replace the macro invocation by the macro definition. */ + + free(buf->buf); + buf->buf = mandoc_strdup(r->current_string); + buf->sz = strlen(buf->buf) + 1; + *offs = 0; + + return buf->buf[buf->sz - 2] == '\n' ? + ROFF_REPARSE | ROFF_USERCALL : ROFF_IGN | ROFF_APPEND; +} + +/* + * Calling a high-level macro that was renamed with .rn. + * r->current_string has already been set up by roff_parse(). + */ +static int +roff_renamed(ROFF_ARGS) +{ + char *nbuf; + + buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string, + buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1; + free(buf->buf); + buf->buf = nbuf; + *offs = 0; + return ROFF_CONT; +} + +/* + * Measure the length in bytes of the roff identifier at *cpp + * and advance the pointer to the next word. + */ +static size_t +roff_getname(struct roff *r, char **cpp, int ln, int pos) +{ + char *name, *cp; + size_t namesz; + + name = *cpp; + if (*name == '\0') + return 0; + + /* Advance cp to the byte after the end of the name. */ + + for (cp = name; 1; cp++) { + namesz = cp - name; + if (*cp == '\0') + break; + if (*cp == ' ' || *cp == '\t') { + cp++; + break; + } + if (*cp != '\\') + continue; + if (cp[1] == '{' || cp[1] == '}') + break; + if (*++cp == '\\') + continue; + mandoc_msg(MANDOCERR_NAMESC, ln, pos, + "%.*s", (int)(cp - name + 1), name); + mandoc_escape((const char **)&cp, NULL, NULL); + break; + } + + /* Read past spaces. */ + + while (*cp == ' ') + cp++; + + *cpp = cp; + return namesz; +} + +/* + * Store *string into the user-defined string called *name. + * To clear an existing entry, call with (*r, *name, NULL, 0). + * append == 0: replace mode + * append == 1: single-line append mode + * append == 2: multiline append mode, append '\n' after each call + */ +static void +roff_setstr(struct roff *r, const char *name, const char *string, + int append) +{ + size_t namesz; + + namesz = strlen(name); + roff_setstrn(&r->strtab, name, namesz, string, + string ? strlen(string) : 0, append); + roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); +} + +static void +roff_setstrn(struct roffkv **r, const char *name, size_t namesz, + const char *string, size_t stringsz, int append) +{ + struct roffkv *n; + char *c; + int i; + size_t oldch, newch; + + /* Search for an existing string with the same name. */ + n = *r; + + while (n && (namesz != n->key.sz || + strncmp(n->key.p, name, namesz))) + n = n->next; + + if (NULL == n) { + /* Create a new string table entry. */ + n = mandoc_malloc(sizeof(struct roffkv)); + n->key.p = mandoc_strndup(name, namesz); + n->key.sz = namesz; + n->val.p = NULL; + n->val.sz = 0; + n->next = *r; + *r = n; + } else if (0 == append) { + free(n->val.p); + n->val.p = NULL; + n->val.sz = 0; + } + + if (NULL == string) + return; + + /* + * One additional byte for the '\n' in multiline mode, + * and one for the terminating '\0'. + */ + newch = stringsz + (1 < append ? 2u : 1u); + + if (NULL == n->val.p) { + n->val.p = mandoc_malloc(newch); + *n->val.p = '\0'; + oldch = 0; + } else { + oldch = n->val.sz; + n->val.p = mandoc_realloc(n->val.p, oldch + newch); + } + + /* Skip existing content in the destination buffer. */ + c = n->val.p + (int)oldch; + + /* Append new content to the destination buffer. */ + i = 0; + while (i < (int)stringsz) { + /* + * Rudimentary roff copy mode: + * Handle escaped backslashes. + */ + if ('\\' == string[i] && '\\' == string[i + 1]) + i++; + *c++ = string[i++]; + } + + /* Append terminating bytes. */ + if (1 < append) + *c++ = '\n'; + + *c = '\0'; + n->val.sz = (int)(c - n->val.p); +} + +static const char * +roff_getstrn(struct roff *r, const char *name, size_t len, + int *deftype) +{ + const struct roffkv *n; + int found, i; + enum roff_tok tok; + + found = 0; + for (n = r->strtab; n != NULL; n = n->next) { + if (strncmp(name, n->key.p, len) != 0 || + n->key.p[len] != '\0' || n->val.p == NULL) + continue; + if (*deftype & ROFFDEF_USER) { + *deftype = ROFFDEF_USER; + return n->val.p; + } else { + found = 1; + break; + } + } + for (n = r->rentab; n != NULL; n = n->next) { + if (strncmp(name, n->key.p, len) != 0 || + n->key.p[len] != '\0' || n->val.p == NULL) + continue; + if (*deftype & ROFFDEF_REN) { + *deftype = ROFFDEF_REN; + return n->val.p; + } else { + found = 1; + break; + } + } + for (i = 0; i < PREDEFS_MAX; i++) { + if (strncmp(name, predefs[i].name, len) != 0 || + predefs[i].name[len] != '\0') + continue; + if (*deftype & ROFFDEF_PRE) { + *deftype = ROFFDEF_PRE; + return predefs[i].str; + } else { + found = 1; + break; + } + } + if (r->man->meta.macroset != MACROSET_MAN) { + for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) { + if (strncmp(name, roff_name[tok], len) != 0 || + roff_name[tok][len] != '\0') + continue; + if (*deftype & ROFFDEF_STD) { + *deftype = ROFFDEF_STD; + return NULL; + } else { + found = 1; + break; + } + } + } + if (r->man->meta.macroset != MACROSET_MDOC) { + for (tok = MAN_TH; tok < MAN_MAX; tok++) { + if (strncmp(name, roff_name[tok], len) != 0 || + roff_name[tok][len] != '\0') + continue; + if (*deftype & ROFFDEF_STD) { + *deftype = ROFFDEF_STD; + return NULL; + } else { + found = 1; + break; + } + } + } + + if (found == 0 && *deftype != ROFFDEF_ANY) { + if (*deftype & ROFFDEF_REN) { + /* + * This might still be a request, + * so do not treat it as undefined yet. + */ + *deftype = ROFFDEF_UNDEF; + return NULL; + } + + /* Using an undefined string defines it to be empty. */ + + roff_setstrn(&r->strtab, name, len, "", 0, 0); + roff_setstrn(&r->rentab, name, len, NULL, 0, 0); + } + + *deftype = 0; + return NULL; +} + +static void +roff_freestr(struct roffkv *r) +{ + struct roffkv *n, *nn; + + for (n = r; n; n = nn) { + free(n->key.p); + free(n->val.p); + nn = n->next; + free(n); + } +} + +/* --- accessors and utility functions ------------------------------------ */ + +/* + * Duplicate an input string, making the appropriate character + * conversations (as stipulated by `tr') along the way. + * Returns a heap-allocated string with all the replacements made. + */ +char * +roff_strdup(const struct roff *r, const char *p) +{ + const struct roffkv *cp; + char *res; + const char *pp; + size_t ssz, sz; + enum mandoc_esc esc; + + if (NULL == r->xmbtab && NULL == r->xtab) + return mandoc_strdup(p); + else if ('\0' == *p) + return mandoc_strdup(""); + + /* + * Step through each character looking for term matches + * (remember that a `tr' can be invoked with an escape, which is + * a glyph but the escape is multi-character). + * We only do this if the character hash has been initialised + * and the string is >0 length. + */ + + res = NULL; + ssz = 0; + + while ('\0' != *p) { + assert((unsigned int)*p < 128); + if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) { + sz = r->xtab[(int)*p].sz; + res = mandoc_realloc(res, ssz + sz + 1); + memcpy(res + ssz, r->xtab[(int)*p].p, sz); + ssz += sz; + p++; + continue; + } else if ('\\' != *p) { + res = mandoc_realloc(res, ssz + 2); + res[ssz++] = *p++; + continue; + } + + /* Search for term matches. */ + for (cp = r->xmbtab; cp; cp = cp->next) + if (0 == strncmp(p, cp->key.p, cp->key.sz)) + break; + + if (NULL != cp) { + /* + * A match has been found. + * Append the match to the array and move + * forward by its keysize. + */ + res = mandoc_realloc(res, + ssz + cp->val.sz + 1); + memcpy(res + ssz, cp->val.p, cp->val.sz); + ssz += cp->val.sz; + p += (int)cp->key.sz; + continue; + } + + /* + * Handle escapes carefully: we need to copy + * over just the escape itself, or else we might + * do replacements within the escape itself. + * Make sure to pass along the bogus string. + */ + pp = p++; + esc = mandoc_escape(&p, NULL, NULL); + if (ESCAPE_ERROR == esc) { + sz = strlen(pp); + res = mandoc_realloc(res, ssz + sz + 1); + memcpy(res + ssz, pp, sz); + break; + } + /* + * We bail out on bad escapes. + * No need to warn: we already did so when + * roff_expand() was called. + */ + sz = (int)(p - pp); + res = mandoc_realloc(res, ssz + sz + 1); + memcpy(res + ssz, pp, sz); + ssz += sz; + } + + res[(int)ssz] = '\0'; + return res; +} + +int +roff_getformat(const struct roff *r) +{ + + return r->format; +} + +/* + * Find out whether a line is a macro line or not. + * If it is, adjust the current position and return one; if it isn't, + * return zero and don't change the current position. + * If the control character has been set with `.cc', then let that grain + * precedence. + * This is slighly contrary to groff, where using the non-breaking + * control character when `cc' has been invoked will cause the + * non-breaking macro contents to be printed verbatim. + */ +int +roff_getcontrol(const struct roff *r, const char *cp, int *ppos) +{ + int pos; + + pos = *ppos; + + if (r->control != '\0' && cp[pos] == r->control) + pos++; + else if (r->control != '\0') + return 0; + else if ('\\' == cp[pos] && '.' == cp[pos + 1]) + pos += 2; + else if ('.' == cp[pos] || '\'' == cp[pos]) + pos++; + else + return 0; + + while (' ' == cp[pos] || '\t' == cp[pos]) + pos++; + + *ppos = pos; + return 1; +} Property changes on: vendor/mandoc/20190723/roff.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/roff_html.c =================================================================== --- vendor/mandoc/20190723/roff_html.c (nonexistent) +++ vendor/mandoc/20190723/roff_html.c (revision 350350) @@ -0,0 +1,117 @@ +/* $Id: roff_html.c,v 1.20 2019/04/30 15:53:01 schwarze Exp $ */ +/* + * Copyright (c) 2010 Kristaps Dzonsons + * Copyright (c) 2014, 2017, 2018, 2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include + +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "out.h" +#include "html.h" + +#define ROFF_HTML_ARGS struct html *h, const struct roff_node *n + +typedef void (*roff_html_pre_fp)(ROFF_HTML_ARGS); + +static void roff_html_pre_br(ROFF_HTML_ARGS); +static void roff_html_pre_ce(ROFF_HTML_ARGS); +static void roff_html_pre_fi(ROFF_HTML_ARGS); +static void roff_html_pre_ft(ROFF_HTML_ARGS); +static void roff_html_pre_nf(ROFF_HTML_ARGS); +static void roff_html_pre_sp(ROFF_HTML_ARGS); + +static const roff_html_pre_fp roff_html_pre_acts[ROFF_MAX] = { + roff_html_pre_br, /* br */ + roff_html_pre_ce, /* ce */ + roff_html_pre_fi, /* fi */ + roff_html_pre_ft, /* ft */ + NULL, /* ll */ + NULL, /* mc */ + roff_html_pre_nf, /* nf */ + NULL, /* po */ + roff_html_pre_ce, /* rj */ + roff_html_pre_sp, /* sp */ + NULL, /* ta */ + NULL, /* ti */ +}; + + +void +roff_html_pre(struct html *h, const struct roff_node *n) +{ + assert(n->tok < ROFF_MAX); + if (roff_html_pre_acts[n->tok] != NULL) + (*roff_html_pre_acts[n->tok])(h, n); +} + +static void +roff_html_pre_br(ROFF_HTML_ARGS) +{ + print_otag(h, TAG_BR, ""); +} + +static void +roff_html_pre_ce(ROFF_HTML_ARGS) +{ + for (n = n->child->next; n != NULL; n = n->next) { + if (n->type == ROFFT_TEXT) { + if (n->flags & NODE_LINE) + roff_html_pre_br(h, n); + print_text(h, n->string); + } else + roff_html_pre(h, n); + } + roff_html_pre_br(h, n); +} + +static void +roff_html_pre_fi(ROFF_HTML_ARGS) +{ + if (html_fillmode(h, TOKEN_NONE) == ROFF_fi) + print_otag(h, TAG_BR, ""); +} + +static void +roff_html_pre_ft(ROFF_HTML_ARGS) +{ + const char *cp; + + cp = n->child->string; + html_setfont(h, mandoc_font(cp, (int)strlen(cp))); +} + +static void +roff_html_pre_nf(ROFF_HTML_ARGS) +{ + if (html_fillmode(h, TOKEN_NONE) == ROFF_nf) + print_otag(h, TAG_BR, ""); +} + +static void +roff_html_pre_sp(ROFF_HTML_ARGS) +{ + if (html_fillmode(h, TOKEN_NONE) == ROFF_nf) { + h->col++; + print_endline(h); + } else { + html_close_paragraph(h); + print_otag(h, TAG_P, "c", "Pp"); + } +} Property changes on: vendor/mandoc/20190723/roff_html.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/tag.c =================================================================== --- vendor/mandoc/20190723/tag.c (nonexistent) +++ vendor/mandoc/20190723/tag.c (revision 350350) @@ -0,0 +1,296 @@ +/* $Id: tag.c,v 1.24 2019/07/22 03:21:50 schwarze Exp $ */ +/* + * Copyright (c) 2015, 2016, 2018, 2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "mandoc.h" +#include "tag.h" + +struct tag_entry { + size_t *lines; + size_t maxlines; + size_t nlines; + int prio; + char s[]; +}; + +static void tag_signal(int) __attribute__((__noreturn__)); + +static struct ohash tag_data; +static struct tag_files tag_files; + + +/* + * Prepare for using a pager. + * Not all pagers are capable of using a tag file, + * but for simplicity, create it anyway. + */ +struct tag_files * +tag_init(void) +{ + struct sigaction sa; + int ofd; + + ofd = -1; + tag_files.tfd = -1; + tag_files.tcpgid = -1; + + /* Clean up when dying from a signal. */ + + memset(&sa, 0, sizeof(sa)); + sigfillset(&sa.sa_mask); + sa.sa_handler = tag_signal; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + /* + * POSIX requires that a process calling tcsetpgrp(3) + * from the background gets a SIGTTOU signal. + * In that case, do not stop. + */ + + sa.sa_handler = SIG_IGN; + sigaction(SIGTTOU, &sa, NULL); + + /* Save the original standard output for use by the pager. */ + + if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); + goto fail; + } + + /* Create both temporary output files. */ + + (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX", + sizeof(tag_files.ofn)); + (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX", + sizeof(tag_files.tfn)); + if ((ofd = mkstemp(tag_files.ofn)) == -1) { + mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, + "%s: %s", tag_files.ofn, strerror(errno)); + goto fail; + } + if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) { + mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, + "%s: %s", tag_files.tfn, strerror(errno)); + goto fail; + } + if (dup2(ofd, STDOUT_FILENO) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); + goto fail; + } + close(ofd); + + /* + * Set up the ohash table to collect output line numbers + * where various marked-up terms are documented. + */ + + mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s)); + return &tag_files; + +fail: + tag_unlink(); + if (ofd != -1) + close(ofd); + if (tag_files.ofd != -1) + close(tag_files.ofd); + if (tag_files.tfd != -1) + close(tag_files.tfd); + *tag_files.ofn = '\0'; + *tag_files.tfn = '\0'; + tag_files.ofd = -1; + tag_files.tfd = -1; + return NULL; +} + +/* + * Set the line number where a term is defined, + * unless it is already defined at a lower priority. + */ +void +tag_put(const char *s, int prio, size_t line) +{ + struct tag_entry *entry; + const char *se; + size_t len; + unsigned int slot; + + if (tag_files.tfd <= 0) + return; + + if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e')) + s += 2; + + /* + * Skip whitespace and escapes and whatever follows, + * and if there is any, downgrade the priority. + */ + + len = strcspn(s, " \t\\"); + if (len == 0) + return; + + se = s + len; + if (*se != '\0') + prio = INT_MAX; + + slot = ohash_qlookupi(&tag_data, s, &se); + entry = ohash_find(&tag_data, slot); + + if (entry == NULL) { + + /* Build a new entry. */ + + entry = mandoc_malloc(sizeof(*entry) + len + 1); + memcpy(entry->s, s, len); + entry->s[len] = '\0'; + entry->lines = NULL; + entry->maxlines = entry->nlines = 0; + ohash_insert(&tag_data, slot, entry); + + } else { + + /* + * Lower priority numbers take precedence, + * but 0 is special. + * A tag with priority 0 is only used + * if the tag occurs exactly once. + */ + + if (prio == 0) { + if (entry->prio == 0) + entry->prio = -1; + return; + } + + /* A better entry is already present, ignore the new one. */ + + if (entry->prio > 0 && entry->prio < prio) + return; + + /* The existing entry is worse, clear it. */ + + if (entry->prio < 1 || entry->prio > prio) + entry->nlines = 0; + } + + /* Remember the new line. */ + + if (entry->maxlines == entry->nlines) { + entry->maxlines += 4; + entry->lines = mandoc_reallocarray(entry->lines, + entry->maxlines, sizeof(*entry->lines)); + } + entry->lines[entry->nlines++] = line; + entry->prio = prio; +} + +/* + * Write out the tags file using the previously collected + * information and clear the ohash table while going along. + */ +void +tag_write(void) +{ + FILE *stream; + struct tag_entry *entry; + size_t i; + unsigned int slot; + int empty; + + if (tag_files.tfd <= 0) + return; + if (tag_files.tagname != NULL && ohash_find(&tag_data, + ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) { + mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", tag_files.tagname); + tag_files.tagname = NULL; + } + if ((stream = fdopen(tag_files.tfd, "w")) == NULL) + mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno)); + empty = 1; + entry = ohash_first(&tag_data, &slot); + while (entry != NULL) { + if (stream != NULL && entry->prio >= 0) { + for (i = 0; i < entry->nlines; i++) { + fprintf(stream, "%s %s %zu\n", + entry->s, tag_files.ofn, entry->lines[i]); + empty = 0; + } + } + free(entry->lines); + free(entry); + entry = ohash_next(&tag_data, &slot); + } + ohash_delete(&tag_data); + if (stream != NULL) + fclose(stream); + else + close(tag_files.tfd); + tag_files.tfd = -1; + if (empty) { + unlink(tag_files.tfn); + *tag_files.tfn = '\0'; + } +} + +void +tag_unlink(void) +{ + pid_t tc_pgid; + + if (tag_files.tcpgid != -1) { + tc_pgid = tcgetpgrp(tag_files.ofd); + if (tc_pgid == tag_files.pager_pid || + tc_pgid == getpgid(0) || + getpgid(tc_pgid) == -1) + (void)tcsetpgrp(tag_files.ofd, tag_files.tcpgid); + } + if (*tag_files.ofn != '\0') + unlink(tag_files.ofn); + if (*tag_files.tfn != '\0') + unlink(tag_files.tfn); +} + +static void +tag_signal(int signum) +{ + struct sigaction sa; + + tag_unlink(); + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sigaction(signum, &sa, NULL); + kill(getpid(), signum); + /* NOTREACHED */ + _exit(1); +} Property changes on: vendor/mandoc/20190723/tag.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/tbl_html.c =================================================================== --- vendor/mandoc/20190723/tbl_html.c (nonexistent) +++ vendor/mandoc/20190723/tbl_html.c (revision 350350) @@ -0,0 +1,257 @@ +/* $Id: tbl_html.c,v 1.33 2019/03/17 18:21:45 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "tbl.h" +#include "out.h" +#include "html.h" + +static void html_tblopen(struct html *, const struct tbl_span *); +static size_t html_tbl_len(size_t, void *); +static size_t html_tbl_strlen(const char *, void *); +static size_t html_tbl_sulen(const struct roffsu *, void *); + + +static size_t +html_tbl_len(size_t sz, void *arg) +{ + return sz; +} + +static size_t +html_tbl_strlen(const char *p, void *arg) +{ + return strlen(p); +} + +static size_t +html_tbl_sulen(const struct roffsu *su, void *arg) +{ + if (su->scale < 0.0) + return 0; + + switch (su->unit) { + case SCALE_FS: /* 2^16 basic units */ + return su->scale * 65536.0 / 24.0; + case SCALE_IN: /* 10 characters per inch */ + return su->scale * 10.0; + case SCALE_CM: /* 2.54 cm per inch */ + return su->scale * 10.0 / 2.54; + case SCALE_PC: /* 6 pica per inch */ + case SCALE_VS: + return su->scale * 10.0 / 6.0; + case SCALE_EN: + case SCALE_EM: + return su->scale; + case SCALE_PT: /* 12 points per pica */ + return su->scale * 10.0 / 6.0 / 12.0; + case SCALE_BU: /* 24 basic units per character */ + return su->scale / 24.0; + case SCALE_MM: /* 1/1000 inch */ + return su->scale / 100.0; + default: + abort(); + } +} + +static void +html_tblopen(struct html *h, const struct tbl_span *sp) +{ + html_close_paragraph(h); + if (h->tbl.cols == NULL) { + h->tbl.len = html_tbl_len; + h->tbl.slen = html_tbl_strlen; + h->tbl.sulen = html_tbl_sulen; + tblcalc(&h->tbl, sp, 0, 0); + } + assert(NULL == h->tblt); + h->tblt = print_otag(h, TAG_TABLE, "c?ss", "tbl", + "border", + sp->opts->opts & TBL_OPT_ALLBOX ? "1" : NULL, + "border-style", + sp->opts->opts & TBL_OPT_DBOX ? "double" : + sp->opts->opts & TBL_OPT_BOX ? "solid" : NULL, + "border-top-style", + sp->pos == TBL_SPAN_DHORIZ ? "double" : + sp->pos == TBL_SPAN_HORIZ ? "solid" : NULL); +} + +void +print_tblclose(struct html *h) +{ + + assert(h->tblt); + print_tagq(h, h->tblt); + h->tblt = NULL; +} + +void +print_tbl(struct html *h, const struct tbl_span *sp) +{ + const struct tbl_dat *dp; + const struct tbl_cell *cp; + const struct tbl_span *psp; + struct tag *tt; + const char *hspans, *vspans, *halign, *valign; + const char *bborder, *lborder, *rborder; + char hbuf[4], vbuf[4]; + int i; + + if (h->tblt == NULL) + html_tblopen(h, sp); + + /* + * Horizontal lines spanning the whole table + * are handled by previous or following table rows. + */ + + if (sp->pos != TBL_SPAN_DATA) + return; + + /* Inhibit printing of spaces: we do padding ourselves. */ + + h->flags |= HTML_NONOSPACE; + h->flags |= HTML_NOSPACE; + + /* Draw a vertical line left of this row? */ + + switch (sp->layout->vert) { + case 2: + lborder = "double"; + break; + case 1: + lborder = "solid"; + break; + default: + lborder = NULL; + break; + } + + /* Draw a horizontal line below this row? */ + + bborder = NULL; + if ((psp = sp->next) != NULL) { + switch (psp->pos) { + case TBL_SPAN_DHORIZ: + bborder = "double"; + break; + case TBL_SPAN_HORIZ: + bborder = "solid"; + break; + default: + break; + } + } + + tt = print_otag(h, TAG_TR, "ss", + "border-left-style", lborder, + "border-bottom-style", bborder); + + for (dp = sp->first; dp != NULL; dp = dp->next) { + print_stagq(h, tt); + + /* + * Do not generate elements for continuations + * of spanned cells. Larger elements covering + * this space were already generated earlier. + */ + + cp = dp->layout; + if (cp->pos == TBL_CELL_SPAN || cp->pos == TBL_CELL_DOWN || + (dp->string != NULL && strcmp(dp->string, "\\^") == 0)) + continue; + + /* Determine the attribute values. */ + + if (dp->hspans > 0) { + (void)snprintf(hbuf, sizeof(hbuf), + "%d", dp->hspans + 1); + hspans = hbuf; + } else + hspans = NULL; + if (dp->vspans > 0) { + (void)snprintf(vbuf, sizeof(vbuf), + "%d", dp->vspans + 1); + vspans = vbuf; + } else + vspans = NULL; + + switch (cp->pos) { + case TBL_CELL_CENTRE: + halign = "center"; + break; + case TBL_CELL_RIGHT: + case TBL_CELL_NUMBER: + halign = "right"; + break; + default: + halign = NULL; + break; + } + if (cp->flags & TBL_CELL_TALIGN) + valign = "top"; + else if (cp->flags & TBL_CELL_BALIGN) + valign = "bottom"; + else + valign = NULL; + + for (i = dp->hspans; i > 0; i--) + cp = cp->next; + switch (cp->vert) { + case 2: + rborder = "double"; + break; + case 1: + rborder = "solid"; + break; + default: + rborder = NULL; + break; + } + + /* Print the element and the attributes. */ + + print_otag(h, TAG_TD, "??sss", + "colspan", hspans, "rowspan", vspans, + "vertical-align", valign, + "text-align", halign, + "border-right-style", rborder); + if (dp->string != NULL) + print_text(h, dp->string); + } + + print_tagq(h, tt); + + h->flags &= ~HTML_NONOSPACE; + + if (sp->next == NULL) { + assert(h->tbl.cols); + free(h->tbl.cols); + h->tbl.cols = NULL; + print_tblclose(h); + } +} Property changes on: vendor/mandoc/20190723/tbl_html.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/tbl_term.c =================================================================== --- vendor/mandoc/20190723/tbl_term.c (nonexistent) +++ vendor/mandoc/20190723/tbl_term.c (revision 350350) @@ -0,0 +1,946 @@ +/* $Id: tbl_term.c,v 1.72 2019/07/01 22:56:24 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2011 Kristaps Dzonsons + * Copyright (c) 2011-2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "tbl.h" +#include "out.h" +#include "term.h" + +#define IS_HORIZ(cp) ((cp)->pos == TBL_CELL_HORIZ || \ + (cp)->pos == TBL_CELL_DHORIZ) + + +static size_t term_tbl_len(size_t, void *); +static size_t term_tbl_strlen(const char *, void *); +static size_t term_tbl_sulen(const struct roffsu *, void *); +static void tbl_data(struct termp *, const struct tbl_opts *, + const struct tbl_cell *, + const struct tbl_dat *, + const struct roffcol *); +static void tbl_direct_border(struct termp *, int, size_t); +static void tbl_fill_border(struct termp *, int, size_t); +static void tbl_fill_char(struct termp *, char, size_t); +static void tbl_fill_string(struct termp *, const char *, size_t); +static void tbl_hrule(struct termp *, const struct tbl_span *, + const struct tbl_span *, const struct tbl_span *, + int); +static void tbl_literal(struct termp *, const struct tbl_dat *, + const struct roffcol *); +static void tbl_number(struct termp *, const struct tbl_opts *, + const struct tbl_dat *, + const struct roffcol *); +static void tbl_word(struct termp *, const struct tbl_dat *); + + +/* + * The following border-character tables are indexed + * by ternary (3-based) numbers, as opposed to binary or decimal. + * Each ternary digit describes the line width in one direction: + * 0 means no line, 1 single or light line, 2 double or heavy line. + */ + +/* Positional values of the four directions. */ +#define BRIGHT 1 +#define BDOWN 3 +#define BLEFT (3 * 3) +#define BUP (3 * 3 * 3) +#define BHORIZ (BLEFT + BRIGHT) + +/* Code points to use for each combination of widths. */ +static const int borders_utf8[81] = { + 0x0020, 0x2576, 0x257a, /* 000 right */ + 0x2577, 0x250c, 0x250d, /* 001 down */ + 0x257b, 0x250e, 0x250f, /* 002 */ + 0x2574, 0x2500, 0x257c, /* 010 left */ + 0x2510, 0x252c, 0x252e, /* 011 left down */ + 0x2512, 0x2530, 0x2532, /* 012 */ + 0x2578, 0x257e, 0x2501, /* 020 left */ + 0x2511, 0x252d, 0x252f, /* 021 left down */ + 0x2513, 0x2531, 0x2533, /* 022 */ + 0x2575, 0x2514, 0x2515, /* 100 up */ + 0x2502, 0x251c, 0x251d, /* 101 up down */ + 0x257d, 0x251f, 0x2522, /* 102 */ + 0x2518, 0x2534, 0x2536, /* 110 up left */ + 0x2524, 0x253c, 0x253e, /* 111 all */ + 0x2527, 0x2541, 0x2546, /* 112 */ + 0x2519, 0x2535, 0x2537, /* 120 up left */ + 0x2525, 0x253d, 0x253f, /* 121 all */ + 0x252a, 0x2545, 0x2548, /* 122 */ + 0x2579, 0x2516, 0x2517, /* 200 up */ + 0x257f, 0x251e, 0x2521, /* 201 up down */ + 0x2503, 0x2520, 0x2523, /* 202 */ + 0x251a, 0x2538, 0x253a, /* 210 up left */ + 0x2526, 0x2540, 0x2544, /* 211 all */ + 0x2528, 0x2542, 0x254a, /* 212 */ + 0x251b, 0x2539, 0x253b, /* 220 up left */ + 0x2529, 0x2543, 0x2547, /* 221 all */ + 0x252b, 0x2549, 0x254b, /* 222 */ +}; + +/* ASCII approximations for these code points, compatible with groff. */ +static const int borders_ascii[81] = { + ' ', '-', '=', /* 000 right */ + '|', '+', '+', /* 001 down */ + '|', '+', '+', /* 002 */ + '-', '-', '=', /* 010 left */ + '+', '+', '+', /* 011 left down */ + '+', '+', '+', /* 012 */ + '=', '=', '=', /* 020 left */ + '+', '+', '+', /* 021 left down */ + '+', '+', '+', /* 022 */ + '|', '+', '+', /* 100 up */ + '|', '+', '+', /* 101 up down */ + '|', '+', '+', /* 102 */ + '+', '+', '+', /* 110 up left */ + '+', '+', '+', /* 111 all */ + '+', '+', '+', /* 112 */ + '+', '+', '+', /* 120 up left */ + '+', '+', '+', /* 121 all */ + '+', '+', '+', /* 122 */ + '|', '+', '+', /* 200 up */ + '|', '+', '+', /* 201 up down */ + '|', '+', '+', /* 202 */ + '+', '+', '+', /* 210 up left */ + '+', '+', '+', /* 211 all */ + '+', '+', '+', /* 212 */ + '+', '+', '+', /* 220 up left */ + '+', '+', '+', /* 221 all */ + '+', '+', '+', /* 222 */ +}; + +/* Either of the above according to the selected output encoding. */ +static const int *borders_locale; + + +static size_t +term_tbl_sulen(const struct roffsu *su, void *arg) +{ + int i; + + i = term_hen((const struct termp *)arg, su); + return i > 0 ? i : 0; +} + +static size_t +term_tbl_strlen(const char *p, void *arg) +{ + return term_strlen((const struct termp *)arg, p); +} + +static size_t +term_tbl_len(size_t sz, void *arg) +{ + return term_len((const struct termp *)arg, sz); +} + + +void +term_tbl(struct termp *tp, const struct tbl_span *sp) +{ + const struct tbl_cell *cp, *cpn, *cpp, *cps; + const struct tbl_dat *dp; + static size_t offset; + size_t save_offset; + size_t coloff, tsz; + int hspans, ic, more; + int dvert, fc, horiz, lhori, rhori, uvert; + + /* Inhibit printing of spaces: we do padding ourselves. */ + + tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE; + save_offset = tp->tcol->offset; + + /* + * The first time we're invoked for a given table block, + * calculate the table widths and decimal positions. + */ + + if (tp->tbl.cols == NULL) { + borders_locale = tp->enc == TERMENC_UTF8 ? + borders_utf8 : borders_ascii; + + tp->tbl.len = term_tbl_len; + tp->tbl.slen = term_tbl_strlen; + tp->tbl.sulen = term_tbl_sulen; + tp->tbl.arg = tp; + + tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin); + + /* Tables leak .ta settings to subsequent text. */ + + term_tab_set(tp, NULL); + coloff = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) || + sp->opts->lvert; + for (ic = 0; ic < sp->opts->cols; ic++) { + coloff += tp->tbl.cols[ic].width; + term_tab_iset(coloff); + coloff += tp->tbl.cols[ic].spacing; + } + + /* Center the table as a whole. */ + + offset = tp->tcol->offset; + if (sp->opts->opts & TBL_OPT_CENTRE) { + tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) + ? 2 : !!sp->opts->lvert + !!sp->opts->rvert; + for (ic = 0; ic + 1 < sp->opts->cols; ic++) + tsz += tp->tbl.cols[ic].width + + tp->tbl.cols[ic].spacing; + if (sp->opts->cols) + tsz += tp->tbl.cols[sp->opts->cols - 1].width; + if (offset + tsz > tp->tcol->rmargin) + tsz -= 1; + offset = offset + tp->tcol->rmargin > tsz ? + (offset + tp->tcol->rmargin - tsz) / 2 : 0; + tp->tcol->offset = offset; + } + + /* Horizontal frame at the start of boxed tables. */ + + if (tp->enc == TERMENC_ASCII && + sp->opts->opts & TBL_OPT_DBOX) + tbl_hrule(tp, NULL, sp, sp, TBL_OPT_DBOX); + if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) + tbl_hrule(tp, NULL, sp, sp, TBL_OPT_BOX); + } + + /* Set up the columns. */ + + tp->flags |= TERMP_MULTICOL; + tp->tcol->offset = offset; + horiz = 0; + switch (sp->pos) { + case TBL_SPAN_HORIZ: + case TBL_SPAN_DHORIZ: + horiz = 1; + term_setcol(tp, 1); + break; + case TBL_SPAN_DATA: + term_setcol(tp, sp->opts->cols + 2); + coloff = tp->tcol->offset; + + /* Set up a column for a left vertical frame. */ + + if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) || + sp->opts->lvert) + coloff++; + tp->tcol->rmargin = coloff; + + /* Set up the data columns. */ + + dp = sp->first; + hspans = 0; + for (ic = 0; ic < sp->opts->cols; ic++) { + if (hspans == 0) { + tp->tcol++; + tp->tcol->offset = coloff; + } + coloff += tp->tbl.cols[ic].width; + tp->tcol->rmargin = coloff; + if (ic + 1 < sp->opts->cols) + coloff += tp->tbl.cols[ic].spacing; + if (hspans) { + hspans--; + continue; + } + if (dp == NULL) + continue; + hspans = dp->hspans; + if (ic || sp->layout->first->pos != TBL_CELL_SPAN) + dp = dp->next; + } + + /* Set up a column for a right vertical frame. */ + + tp->tcol++; + tp->tcol->offset = coloff + 1; + tp->tcol->rmargin = tp->maxrmargin; + + /* Spans may have reduced the number of columns. */ + + tp->lasttcol = tp->tcol - tp->tcols; + + /* Fill the buffers for all data columns. */ + + tp->tcol = tp->tcols; + cp = cpn = sp->layout->first; + dp = sp->first; + hspans = 0; + for (ic = 0; ic < sp->opts->cols; ic++) { + if (cpn != NULL) { + cp = cpn; + cpn = cpn->next; + } + if (hspans) { + hspans--; + continue; + } + tp->tcol++; + tp->col = 0; + tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic); + if (dp == NULL) + continue; + hspans = dp->hspans; + if (cp->pos != TBL_CELL_SPAN) + dp = dp->next; + } + break; + } + + do { + /* Print the vertical frame at the start of each row. */ + + tp->tcol = tp->tcols; + uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 : + sp->opts->opts & TBL_OPT_BOX ? 1 : 0; + if (sp->pos == TBL_SPAN_DATA && uvert < sp->layout->vert) + uvert = dvert = sp->layout->vert; + if (sp->next != NULL && sp->next->pos == TBL_SPAN_DATA && + dvert < sp->next->layout->vert) + dvert = sp->next->layout->vert; + if (sp->prev != NULL && uvert < sp->prev->layout->vert && + (horiz || (IS_HORIZ(sp->layout->first) && + !IS_HORIZ(sp->prev->layout->first)))) + uvert = sp->prev->layout->vert; + rhori = sp->pos == TBL_SPAN_DHORIZ || + (sp->first != NULL && sp->first->pos == TBL_DATA_DHORIZ) || + sp->layout->first->pos == TBL_CELL_DHORIZ ? 2 : + sp->pos == TBL_SPAN_HORIZ || + (sp->first != NULL && sp->first->pos == TBL_DATA_HORIZ) || + sp->layout->first->pos == TBL_CELL_HORIZ ? 1 : 0; + fc = BUP * uvert + BDOWN * dvert + BRIGHT * rhori; + if (uvert > 0 || dvert > 0 || (horiz && sp->opts->lvert)) { + (*tp->advance)(tp, tp->tcols->offset); + tp->viscol = tp->tcol->offset; + tbl_direct_border(tp, fc, 1); + } + + /* Print the data cells. */ + + more = 0; + if (horiz) + tbl_hrule(tp, sp->prev, sp, sp->next, 0); + else { + cp = sp->layout->first; + cpn = sp->next == NULL ? NULL : + sp->next->layout->first; + cpp = sp->prev == NULL ? NULL : + sp->prev->layout->first; + dp = sp->first; + hspans = 0; + for (ic = 0; ic < sp->opts->cols; ic++) { + + /* + * Figure out whether to print a + * vertical line after this cell + * and advance to next layout cell. + */ + + uvert = dvert = fc = 0; + if (cp != NULL) { + cps = cp; + while (cps->next != NULL && + cps->next->pos == TBL_CELL_SPAN) + cps = cps->next; + if (sp->pos == TBL_SPAN_DATA) + uvert = dvert = cps->vert; + switch (cp->pos) { + case TBL_CELL_HORIZ: + fc = BHORIZ; + break; + case TBL_CELL_DHORIZ: + fc = BHORIZ * 2; + break; + default: + break; + } + } + if (cpp != NULL) { + if (uvert < cpp->vert && + cp != NULL && + ((IS_HORIZ(cp) && + !IS_HORIZ(cpp)) || + (cp->next != NULL && + cpp->next != NULL && + IS_HORIZ(cp->next) && + !IS_HORIZ(cpp->next)))) + uvert = cpp->vert; + cpp = cpp->next; + } + if (sp->opts->opts & TBL_OPT_ALLBOX) { + if (uvert == 0) + uvert = 1; + if (dvert == 0) + dvert = 1; + } + if (cpn != NULL) { + if (dvert == 0 || + (dvert < cpn->vert && + tp->enc == TERMENC_UTF8)) + dvert = cpn->vert; + cpn = cpn->next; + } + + lhori = (cp != NULL && + cp->pos == TBL_CELL_DHORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_DHORIZ) ? 2 : + (cp != NULL && + cp->pos == TBL_CELL_HORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_HORIZ) ? 1 : 0; + + /* + * Skip later cells in a span, + * figure out whether to start a span, + * and advance to next data cell. + */ + + if (hspans) { + hspans--; + cp = cp->next; + continue; + } + if (dp != NULL) { + hspans = dp->hspans; + if (ic || sp->layout->first->pos + != TBL_CELL_SPAN) + dp = dp->next; + } + + /* + * Print one line of text in the cell + * and remember whether there is more. + */ + + tp->tcol++; + if (tp->tcol->col < tp->tcol->lastcol) + term_flushln(tp); + if (tp->tcol->col < tp->tcol->lastcol) + more = 1; + + /* + * Vertical frames between data cells, + * but not after the last column. + */ + + if (fc == 0 && + ((uvert == 0 && dvert == 0 && + cp != NULL && (cp->next == NULL || + !IS_HORIZ(cp->next))) || + tp->tcol + 1 == + tp->tcols + tp->lasttcol)) { + if (cp != NULL) + cp = cp->next; + continue; + } + + if (tp->viscol < tp->tcol->rmargin) { + (*tp->advance)(tp, tp->tcol->rmargin + - tp->viscol); + tp->viscol = tp->tcol->rmargin; + } + while (tp->viscol < tp->tcol->rmargin + + tp->tbl.cols[ic].spacing / 2) + tbl_direct_border(tp, + BHORIZ * lhori, 1); + + if (tp->tcol + 1 == tp->tcols + tp->lasttcol) + continue; + + if (cp != NULL) + cp = cp->next; + + rhori = (cp != NULL && + cp->pos == TBL_CELL_DHORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_DHORIZ) ? 2 : + (cp != NULL && + cp->pos == TBL_CELL_HORIZ) || + (dp != NULL && + dp->pos == TBL_DATA_HORIZ) ? 1 : 0; + + if (tp->tbl.cols[ic].spacing) + tbl_direct_border(tp, + BLEFT * lhori + BRIGHT * rhori + + BUP * uvert + BDOWN * dvert, 1); + + if (tp->enc == TERMENC_UTF8) + uvert = dvert = 0; + + if (tp->tbl.cols[ic].spacing > 2 && + (uvert > 1 || dvert > 1 || rhori)) + tbl_direct_border(tp, + BHORIZ * rhori + + BUP * (uvert > 1) + + BDOWN * (dvert > 1), 1); + } + } + + /* Print the vertical frame at the end of each row. */ + + uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 : + sp->opts->opts & TBL_OPT_BOX ? 1 : 0; + if (sp->pos == TBL_SPAN_DATA && + uvert < sp->layout->last->vert && + sp->layout->last->col + 1 == sp->opts->cols) + uvert = dvert = sp->layout->last->vert; + if (sp->next != NULL && + dvert < sp->next->layout->last->vert && + sp->next->layout->last->col + 1 == sp->opts->cols) + dvert = sp->next->layout->last->vert; + if (sp->prev != NULL && + uvert < sp->prev->layout->last->vert && + sp->prev->layout->last->col + 1 == sp->opts->cols && + (horiz || (IS_HORIZ(sp->layout->last) && + !IS_HORIZ(sp->prev->layout->last)))) + uvert = sp->prev->layout->last->vert; + lhori = sp->pos == TBL_SPAN_DHORIZ || + (sp->last != NULL && + sp->last->pos == TBL_DATA_DHORIZ && + sp->last->layout->col + 1 == sp->opts->cols) || + (sp->layout->last->pos == TBL_CELL_DHORIZ && + sp->layout->last->col + 1 == sp->opts->cols) ? 2 : + sp->pos == TBL_SPAN_HORIZ || + (sp->last != NULL && + sp->last->pos == TBL_DATA_HORIZ && + sp->last->layout->col + 1 == sp->opts->cols) || + (sp->layout->last->pos == TBL_CELL_HORIZ && + sp->layout->last->col + 1 == sp->opts->cols) ? 1 : 0; + fc = BUP * uvert + BDOWN * dvert + BLEFT * lhori; + if (uvert > 0 || dvert > 0 || (horiz && sp->opts->rvert)) { + if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 || + sp->layout->last->col + 1 < sp->opts->cols)) { + tp->tcol++; + do { + tbl_direct_border(tp, + BHORIZ * lhori, 1); + } while (tp->viscol < tp->tcol->offset); + } + tbl_direct_border(tp, fc, 1); + } + (*tp->endline)(tp); + tp->viscol = 0; + } while (more); + + /* + * Clean up after this row. If it is the last line + * of the table, print the box line and clean up + * column data; otherwise, print the allbox line. + */ + + term_setcol(tp, 1); + tp->flags &= ~TERMP_MULTICOL; + tp->tcol->rmargin = tp->maxrmargin; + if (sp->next == NULL) { + if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) { + tbl_hrule(tp, sp, sp, NULL, TBL_OPT_BOX); + tp->skipvsp = 1; + } + if (tp->enc == TERMENC_ASCII && + sp->opts->opts & TBL_OPT_DBOX) { + tbl_hrule(tp, sp, sp, NULL, TBL_OPT_DBOX); + tp->skipvsp = 2; + } + assert(tp->tbl.cols); + free(tp->tbl.cols); + tp->tbl.cols = NULL; + } else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX && + (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA || + sp->next->next != NULL)) + tbl_hrule(tp, sp, sp, sp->next, TBL_OPT_ALLBOX); + + tp->tcol->offset = save_offset; + tp->flags &= ~TERMP_NONOSPACE; +} + +static void +tbl_hrule(struct termp *tp, const struct tbl_span *spp, + const struct tbl_span *sp, const struct tbl_span *spn, int flags) +{ + const struct tbl_cell *cpp; /* Layout cell above this line. */ + const struct tbl_cell *cp; /* Layout cell in this line. */ + const struct tbl_cell *cpn; /* Layout cell below this line. */ + const struct tbl_dat *dpn; /* Data cell below this line. */ + const struct roffcol *col; /* Contains width and spacing. */ + int opts; /* For the table as a whole. */ + int bw; /* Box line width. */ + int hw; /* Horizontal line width. */ + int lw, rw; /* Left and right line widths. */ + int uw, dw; /* Vertical line widths. */ + + cpp = spp == NULL ? NULL : spp->layout->first; + cp = sp == NULL ? NULL : sp->layout->first; + cpn = spn == NULL ? NULL : spn->layout->first; + dpn = NULL; + if (spn != NULL) { + if (spn->pos == TBL_SPAN_DATA) + dpn = spn->first; + else if (spn->next != NULL) + dpn = spn->next->first; + } + opts = sp->opts->opts; + bw = opts & TBL_OPT_DBOX ? (tp->enc == TERMENC_UTF8 ? 2 : 1) : + opts & (TBL_OPT_BOX | TBL_OPT_ALLBOX) ? 1 : 0; + hw = flags == TBL_OPT_DBOX || flags == TBL_OPT_BOX ? bw : + sp->pos == TBL_SPAN_DHORIZ ? 2 : 1; + + /* Print the left end of the line. */ + + if (tp->viscol == 0) { + (*tp->advance)(tp, tp->tcols->offset); + tp->viscol = tp->tcols->offset; + } + if (flags != 0) + tbl_direct_border(tp, + (spp == NULL ? 0 : BUP * bw) + + (spn == NULL ? 0 : BDOWN * bw) + + (spp == NULL || cpn == NULL || + cpn->pos != TBL_CELL_DOWN ? BRIGHT * hw : 0), 1); + + col = tp->tbl.cols; + for (;;) { + if (cp == NULL) + col++; + else + col = tp->tbl.cols + cp->col; + + /* Print the horizontal line inside this column. */ + + lw = cpp == NULL || cpn == NULL || + (cpn->pos != TBL_CELL_DOWN && + (dpn == NULL || dpn->string == NULL || + strcmp(dpn->string, "\\^") != 0)) + ? hw : 0; + tbl_direct_border(tp, BHORIZ * lw, + col->width + col->spacing / 2); + + /* + * Figure out whether a vertical line is crossing + * at the end of this column, + * and advance to the next column. + */ + + uw = dw = 0; + if (cpp != NULL) { + if (flags != TBL_OPT_DBOX) { + uw = cpp->vert; + if (uw == 0 && opts & TBL_OPT_ALLBOX) + uw = 1; + } + cpp = cpp->next; + } else if (spp != NULL && opts & TBL_OPT_ALLBOX) + uw = 1; + if (cp != NULL) + cp = cp->next; + if (cpn != NULL) { + if (flags != TBL_OPT_DBOX) { + dw = cpn->vert; + if (dw == 0 && opts & TBL_OPT_ALLBOX) + dw = 1; + } + cpn = cpn->next; + while (dpn != NULL && dpn->layout != cpn) + dpn = dpn->next; + } else if (spn != NULL && opts & TBL_OPT_ALLBOX) + dw = 1; + if (col + 1 == tp->tbl.cols + sp->opts->cols) + break; + + /* Vertical lines do not cross spanned cells. */ + + if (cpp != NULL && cpp->pos == TBL_CELL_SPAN) + uw = 0; + if (cpn != NULL && cpn->pos == TBL_CELL_SPAN) + dw = 0; + + /* The horizontal line inside the next column. */ + + rw = cpp == NULL || cpn == NULL || + (cpn->pos != TBL_CELL_DOWN && + (dpn == NULL || dpn->string == NULL || + strcmp(dpn->string, "\\^") != 0)) + ? hw : 0; + + /* The line crossing at the end of this column. */ + + if (col->spacing) + tbl_direct_border(tp, BLEFT * lw + + BRIGHT * rw + BUP * uw + BDOWN * dw, 1); + + /* + * In ASCII output, a crossing may print two characters. + */ + + if (tp->enc != TERMENC_ASCII || (uw < 2 && dw < 2)) + uw = dw = 0; + if (col->spacing > 2) + tbl_direct_border(tp, + BHORIZ * rw + BUP * uw + BDOWN * dw, 1); + + /* Padding before the start of the next column. */ + + if (col->spacing > 4) + tbl_direct_border(tp, + BHORIZ * rw, (col->spacing - 3) / 2); + } + + /* Print the right end of the line. */ + + if (flags != 0) { + tbl_direct_border(tp, + (spp == NULL ? 0 : BUP * bw) + + (spn == NULL ? 0 : BDOWN * bw) + + (spp == NULL || spn == NULL || + spn->layout->last->pos != TBL_CELL_DOWN ? + BLEFT * hw : 0), 1); + (*tp->endline)(tp); + tp->viscol = 0; + } +} + +static void +tbl_data(struct termp *tp, const struct tbl_opts *opts, + const struct tbl_cell *cp, const struct tbl_dat *dp, + const struct roffcol *col) +{ + switch (cp->pos) { + case TBL_CELL_HORIZ: + tbl_fill_border(tp, BHORIZ, col->width); + return; + case TBL_CELL_DHORIZ: + tbl_fill_border(tp, BHORIZ * 2, col->width); + return; + default: + break; + } + + if (dp == NULL) + return; + + switch (dp->pos) { + case TBL_DATA_NONE: + return; + case TBL_DATA_HORIZ: + case TBL_DATA_NHORIZ: + tbl_fill_border(tp, BHORIZ, col->width); + return; + case TBL_DATA_NDHORIZ: + case TBL_DATA_DHORIZ: + tbl_fill_border(tp, BHORIZ * 2, col->width); + return; + default: + break; + } + + switch (cp->pos) { + case TBL_CELL_LONG: + case TBL_CELL_CENTRE: + case TBL_CELL_LEFT: + case TBL_CELL_RIGHT: + tbl_literal(tp, dp, col); + break; + case TBL_CELL_NUMBER: + tbl_number(tp, opts, dp, col); + break; + case TBL_CELL_DOWN: + case TBL_CELL_SPAN: + break; + default: + abort(); + } +} + +static void +tbl_fill_string(struct termp *tp, const char *cp, size_t len) +{ + size_t i, sz; + + sz = term_strlen(tp, cp); + for (i = 0; i < len; i += sz) + term_word(tp, cp); +} + +static void +tbl_fill_char(struct termp *tp, char c, size_t len) +{ + char cp[2]; + + cp[0] = c; + cp[1] = '\0'; + tbl_fill_string(tp, cp, len); +} + +static void +tbl_fill_border(struct termp *tp, int c, size_t len) +{ + char buf[12]; + + if ((c = borders_locale[c]) > 127) { + (void)snprintf(buf, sizeof(buf), "\\[u%04x]", c); + tbl_fill_string(tp, buf, len); + } else + tbl_fill_char(tp, c, len); +} + +static void +tbl_direct_border(struct termp *tp, int c, size_t len) +{ + size_t i, sz; + + c = borders_locale[c]; + sz = (*tp->width)(tp, c); + for (i = 0; i < len; i += sz) { + (*tp->letter)(tp, c); + tp->viscol += sz; + } +} + +static void +tbl_literal(struct termp *tp, const struct tbl_dat *dp, + const struct roffcol *col) +{ + size_t len, padl, padr, width; + int ic, hspans; + + assert(dp->string); + len = term_strlen(tp, dp->string); + width = col->width; + ic = dp->layout->col; + hspans = dp->hspans; + while (hspans--) + width += tp->tbl.cols[++ic].width + 3; + + padr = width > len ? width - len : 0; + padl = 0; + + switch (dp->layout->pos) { + case TBL_CELL_LONG: + padl = term_len(tp, 1); + padr = padr > padl ? padr - padl : 0; + break; + case TBL_CELL_CENTRE: + if (2 > padr) + break; + padl = padr / 2; + padr -= padl; + break; + case TBL_CELL_RIGHT: + padl = padr; + padr = 0; + break; + default: + break; + } + + tbl_fill_char(tp, ASCII_NBRSP, padl); + tbl_word(tp, dp); + tbl_fill_char(tp, ASCII_NBRSP, padr); +} + +static void +tbl_number(struct termp *tp, const struct tbl_opts *opts, + const struct tbl_dat *dp, + const struct roffcol *col) +{ + const char *cp, *lastdigit, *lastpoint; + size_t intsz, padl, totsz; + char buf[2]; + + /* + * Almost the same code as in tblcalc_number(): + * First find the position of the decimal point. + */ + + assert(dp->string); + lastdigit = lastpoint = NULL; + for (cp = dp->string; cp[0] != '\0'; cp++) { + if (cp[0] == '\\' && cp[1] == '&') { + lastdigit = lastpoint = cp; + break; + } else if (cp[0] == opts->decimal && + (isdigit((unsigned char)cp[1]) || + (cp > dp->string && isdigit((unsigned char)cp[-1])))) + lastpoint = cp; + else if (isdigit((unsigned char)cp[0])) + lastdigit = cp; + } + + /* Then measure both widths. */ + + padl = 0; + totsz = term_strlen(tp, dp->string); + if (lastdigit != NULL) { + if (lastpoint == NULL) + lastpoint = lastdigit + 1; + intsz = 0; + buf[1] = '\0'; + for (cp = dp->string; cp < lastpoint; cp++) { + buf[0] = cp[0]; + intsz += term_strlen(tp, buf); + } + + /* + * Pad left to match the decimal position, + * but avoid exceeding the total column width. + */ + + if (col->decimal > intsz && col->width > totsz) { + padl = col->decimal - intsz; + if (padl + totsz > col->width) + padl = col->width - totsz; + } + + /* If it is not a number, simply center the string. */ + + } else if (col->width > totsz) + padl = (col->width - totsz) / 2; + + tbl_fill_char(tp, ASCII_NBRSP, padl); + tbl_word(tp, dp); + + /* Pad right to fill the column. */ + + if (col->width > padl + totsz) + tbl_fill_char(tp, ASCII_NBRSP, col->width - padl - totsz); +} + +static void +tbl_word(struct termp *tp, const struct tbl_dat *dp) +{ + int prev_font; + + prev_font = tp->fonti; + if (dp->layout->flags & TBL_CELL_BOLD) + term_fontpush(tp, TERMFONT_BOLD); + else if (dp->layout->flags & TBL_CELL_ITALIC) + term_fontpush(tp, TERMFONT_UNDER); + + term_word(tp, dp->string); + + term_fontpopq(tp, prev_font); +} Property changes on: vendor/mandoc/20190723/tbl_term.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/term.c =================================================================== --- vendor/mandoc/20190723/term.c (nonexistent) +++ vendor/mandoc/20190723/term.c (revision 350350) @@ -0,0 +1,1114 @@ +/* $Id: term.c,v 1.281 2019/06/03 20:23:41 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2010-2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "mandoc_aux.h" +#include "out.h" +#include "term.h" +#include "main.h" + +static size_t cond_width(const struct termp *, int, int *); +static void adjbuf(struct termp_col *, size_t); +static void bufferc(struct termp *, char); +static void encode(struct termp *, const char *, size_t); +static void encode1(struct termp *, int); +static void endline(struct termp *); +static void term_field(struct termp *, size_t, size_t, + size_t, size_t); +static void term_fill(struct termp *, size_t *, size_t *, + size_t); + + +void +term_setcol(struct termp *p, size_t maxtcol) +{ + if (maxtcol > p->maxtcol) { + p->tcols = mandoc_recallocarray(p->tcols, + p->maxtcol, maxtcol, sizeof(*p->tcols)); + p->maxtcol = maxtcol; + } + p->lasttcol = maxtcol - 1; + p->tcol = p->tcols; +} + +void +term_free(struct termp *p) +{ + for (p->tcol = p->tcols; p->tcol < p->tcols + p->maxtcol; p->tcol++) + free(p->tcol->buf); + free(p->tcols); + free(p->fontq); + free(p); +} + +void +term_begin(struct termp *p, term_margin head, + term_margin foot, const struct roff_meta *arg) +{ + + p->headf = head; + p->footf = foot; + p->argf = arg; + (*p->begin)(p); +} + +void +term_end(struct termp *p) +{ + + (*p->end)(p); +} + +/* + * Flush a chunk of text. By default, break the output line each time + * the right margin is reached, and continue output on the next line + * at the same offset as the chunk itself. By default, also break the + * output line at the end of the chunk. There are many flags modifying + * this behaviour, see the comments in the body of the function. + */ +void +term_flushln(struct termp *p) +{ + size_t vbl; /* Number of blanks to prepend to the output. */ + size_t vbr; /* Actual visual position of the end of field. */ + size_t vfield; /* Desired visual field width. */ + size_t vtarget; /* Desired visual position of the right margin. */ + size_t ic; /* Character position in the input buffer. */ + size_t nbr; /* Number of characters to print in this field. */ + + /* + * Normally, start writing at the left margin, but with the + * NOPAD flag, start writing at the current position instead. + */ + + vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ? + 0 : p->tcol->offset - p->viscol; + if (p->minbl && vbl < p->minbl) + vbl = p->minbl; + + if ((p->flags & TERMP_MULTICOL) == 0) + p->tcol->col = 0; + + /* Loop over output lines. */ + + for (;;) { + vfield = p->tcol->rmargin > p->viscol + vbl ? + p->tcol->rmargin - p->viscol - vbl : 0; + + /* + * Normally, break the line at the the right margin + * of the field, but with the NOBREAK flag, only + * break it at the max right margin of the screen, + * and with the BRNEVER flag, never break it at all. + */ + + vtarget = p->flags & TERMP_BRNEVER ? SIZE_MAX : + (p->flags & TERMP_NOBREAK) == 0 ? vfield : + p->maxrmargin > p->viscol + vbl ? + p->maxrmargin - p->viscol - vbl : 0; + + /* + * Figure out how much text will fit in the field. + * If there is whitespace only, print nothing. + */ + + term_fill(p, &nbr, &vbr, vtarget); + if (nbr == 0) + break; + + /* + * With the CENTER or RIGHT flag, increase the indentation + * to center the text between the left and right margins + * or to adjust it to the right margin, respectively. + */ + + if (vbr < vtarget) { + if (p->flags & TERMP_CENTER) + vbl += (vtarget - vbr) / 2; + else if (p->flags & TERMP_RIGHT) + vbl += vtarget - vbr; + } + + /* Finally, print the field content. */ + + term_field(p, vbl, nbr, vbr, vtarget); + + /* + * If there is no text left in the field, exit the loop. + * If the BRTRSP flag is set, consider trailing + * whitespace significant when deciding whether + * the field fits or not. + */ + + for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) { + switch (p->tcol->buf[ic]) { + case '\t': + if (p->flags & TERMP_BRTRSP) + vbr = term_tab_next(vbr); + continue; + case ' ': + if (p->flags & TERMP_BRTRSP) + vbr += (*p->width)(p, ' '); + continue; + case '\n': + case ASCII_BREAK: + continue; + default: + break; + } + break; + } + if (ic == p->tcol->lastcol) + break; + + /* + * At the location of an automtic line break, input + * space characters are consumed by the line break. + */ + + while (p->tcol->col < p->tcol->lastcol && + p->tcol->buf[p->tcol->col] == ' ') + p->tcol->col++; + + /* + * In multi-column mode, leave the rest of the text + * in the buffer to be handled by a subsequent + * invocation, such that the other columns of the + * table can be handled first. + * In single-column mode, simply break the line. + */ + + if (p->flags & TERMP_MULTICOL) + return; + + endline(p); + p->viscol = 0; + + /* + * Normally, start the next line at the same indentation + * as this one, but with the BRIND flag, start it at the + * right margin instead. This is used together with + * NOBREAK for the tags in various kinds of tagged lists. + */ + + vbl = p->flags & TERMP_BRIND ? + p->tcol->rmargin : p->tcol->offset; + } + + /* Reset output state in preparation for the next field. */ + + p->col = p->tcol->col = p->tcol->lastcol = 0; + p->minbl = p->trailspace; + p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD); + + if (p->flags & TERMP_MULTICOL) + return; + + /* + * The HANG flag means that the next field + * always follows on the same line. + * The NOBREAK flag means that the next field + * follows on the same line unless the field was overrun. + * Normally, break the line at the end of each field. + */ + + if ((p->flags & TERMP_HANG) == 0 && + ((p->flags & TERMP_NOBREAK) == 0 || + vbr + term_len(p, p->trailspace) > vfield)) + endline(p); +} + +/* + * Store the number of input characters to print in this field in *nbr + * and their total visual width to print in *vbr. + * If there is only whitespace in the field, both remain zero. + * The desired visual width of the field is provided by vtarget. + * If the first word is longer, the field will be overrun. + */ +static void +term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget) +{ + size_t ic; /* Character position in the input buffer. */ + size_t vis; /* Visual position of the current character. */ + size_t vn; /* Visual position of the next character. */ + int breakline; /* Break at the end of this word. */ + int graph; /* Last character was non-blank. */ + + *nbr = *vbr = vis = 0; + breakline = graph = 0; + for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) { + switch (p->tcol->buf[ic]) { + case '\b': /* Escape \o (overstrike) or backspace markup. */ + assert(ic > 0); + vis -= (*p->width)(p, p->tcol->buf[ic - 1]); + continue; + + case '\t': /* Normal ASCII whitespace. */ + case ' ': + case ASCII_BREAK: /* Escape \: (breakpoint). */ + switch (p->tcol->buf[ic]) { + case '\t': + vn = term_tab_next(vis); + break; + case ' ': + vn = vis + (*p->width)(p, ' '); + break; + case ASCII_BREAK: + vn = vis; + break; + default: + abort(); + } + /* Can break at the end of a word. */ + if (breakline || vn > vtarget) + break; + if (graph) { + *nbr = ic; + *vbr = vis; + graph = 0; + } + vis = vn; + continue; + + case '\n': /* Escape \p (break at the end of the word). */ + breakline = 1; + continue; + + case ASCII_HYPH: /* Breakable hyphen. */ + graph = 1; + /* + * We are about to decide whether to break the + * line or not, so we no longer need this hyphen + * to be marked as breakable. Put back a real + * hyphen such that we get the correct width. + */ + p->tcol->buf[ic] = '-'; + vis += (*p->width)(p, '-'); + if (vis > vtarget) { + ic++; + break; + } + *nbr = ic + 1; + *vbr = vis; + continue; + + case ASCII_NBRSP: /* Non-breakable space. */ + p->tcol->buf[ic] = ' '; + /* FALLTHROUGH */ + default: /* Printable character. */ + graph = 1; + vis += (*p->width)(p, p->tcol->buf[ic]); + if (vis > vtarget && *nbr > 0) + return; + continue; + } + break; + } + + /* + * If the last word extends to the end of the field without any + * trailing whitespace, the loop could not check yet whether it + * can remain on this line. So do the check now. + */ + + if (graph && (vis <= vtarget || *nbr == 0)) { + *nbr = ic; + *vbr = vis; + } +} + +/* + * Print the contents of one field + * with an indentation of vbl visual columns, + * an input string length of nbr characters, + * an output width of vbr visual columns, + * and a desired field width of vtarget visual columns. + */ +static void +term_field(struct termp *p, size_t vbl, size_t nbr, size_t vbr, size_t vtarget) +{ + size_t ic; /* Character position in the input buffer. */ + size_t vis; /* Visual position of the current character. */ + size_t dv; /* Visual width of the current character. */ + size_t vn; /* Visual position of the next character. */ + + vis = 0; + for (ic = p->tcol->col; ic < nbr; ic++) { + + /* + * To avoid the printing of trailing whitespace, + * do not print whitespace right away, only count it. + */ + + switch (p->tcol->buf[ic]) { + case '\n': + case ASCII_BREAK: + continue; + case '\t': + vn = term_tab_next(vis); + vbl += vn - vis; + vis = vn; + continue; + case ' ': + case ASCII_NBRSP: + dv = (*p->width)(p, ' '); + vbl += dv; + vis += dv; + continue; + default: + break; + } + + /* + * We found a non-blank character to print, + * so write preceding white space now. + */ + + if (vbl > 0) { + (*p->advance)(p, vbl); + p->viscol += vbl; + vbl = 0; + } + + /* Print the character and adjust the visual position. */ + + (*p->letter)(p, p->tcol->buf[ic]); + if (p->tcol->buf[ic] == '\b') { + dv = (*p->width)(p, p->tcol->buf[ic - 1]); + p->viscol -= dv; + vis -= dv; + } else { + dv = (*p->width)(p, p->tcol->buf[ic]); + p->viscol += dv; + vis += dv; + } + } + p->tcol->col = nbr; +} + +static void +endline(struct termp *p) +{ + if ((p->flags & (TERMP_NEWMC | TERMP_ENDMC)) == TERMP_ENDMC) { + p->mc = NULL; + p->flags &= ~TERMP_ENDMC; + } + if (p->mc != NULL) { + if (p->viscol && p->maxrmargin >= p->viscol) + (*p->advance)(p, p->maxrmargin - p->viscol + 1); + p->flags |= TERMP_NOBUF | TERMP_NOSPACE; + term_word(p, p->mc); + p->flags &= ~(TERMP_NOBUF | TERMP_NEWMC); + } + p->viscol = 0; + p->minbl = 0; + (*p->endline)(p); +} + +/* + * A newline only breaks an existing line; it won't assert vertical + * space. All data in the output buffer is flushed prior to the newline + * assertion. + */ +void +term_newln(struct termp *p) +{ + + p->flags |= TERMP_NOSPACE; + if (p->tcol->lastcol || p->viscol) + term_flushln(p); +} + +/* + * Asserts a vertical space (a full, empty line-break between lines). + * Note that if used twice, this will cause two blank spaces and so on. + * All data in the output buffer is flushed prior to the newline + * assertion. + */ +void +term_vspace(struct termp *p) +{ + + term_newln(p); + p->viscol = 0; + p->minbl = 0; + if (0 < p->skipvsp) + p->skipvsp--; + else + (*p->endline)(p); +} + +/* Swap current and previous font; for \fP and .ft P */ +void +term_fontlast(struct termp *p) +{ + enum termfont f; + + f = p->fontl; + p->fontl = p->fontq[p->fonti]; + p->fontq[p->fonti] = f; +} + +/* Set font, save current, discard previous; for \f, .ft, .B etc. */ +void +term_fontrepl(struct termp *p, enum termfont f) +{ + + p->fontl = p->fontq[p->fonti]; + p->fontq[p->fonti] = f; +} + +/* Set font, save previous. */ +void +term_fontpush(struct termp *p, enum termfont f) +{ + + p->fontl = p->fontq[p->fonti]; + if (++p->fonti == p->fontsz) { + p->fontsz += 8; + p->fontq = mandoc_reallocarray(p->fontq, + p->fontsz, sizeof(*p->fontq)); + } + p->fontq[p->fonti] = f; +} + +/* Flush to make the saved pointer current again. */ +void +term_fontpopq(struct termp *p, int i) +{ + + assert(i >= 0); + if (p->fonti > i) + p->fonti = i; +} + +/* Pop one font off the stack. */ +void +term_fontpop(struct termp *p) +{ + + assert(p->fonti); + p->fonti--; +} + +/* + * Handle pwords, partial words, which may be either a single word or a + * phrase that cannot be broken down (such as a literal string). This + * handles word styling. + */ +void +term_word(struct termp *p, const char *word) +{ + struct roffsu su; + const char nbrsp[2] = { ASCII_NBRSP, 0 }; + const char *seq, *cp; + int sz, uc; + size_t csz, lsz, ssz; + enum mandoc_esc esc; + + if ((p->flags & TERMP_NOBUF) == 0) { + if ((p->flags & TERMP_NOSPACE) == 0) { + if ((p->flags & TERMP_KEEP) == 0) { + bufferc(p, ' '); + if (p->flags & TERMP_SENTENCE) + bufferc(p, ' '); + } else + bufferc(p, ASCII_NBRSP); + } + if (p->flags & TERMP_PREKEEP) + p->flags |= TERMP_KEEP; + if (p->flags & TERMP_NONOSPACE) + p->flags |= TERMP_NOSPACE; + else + p->flags &= ~TERMP_NOSPACE; + p->flags &= ~(TERMP_SENTENCE | TERMP_NONEWLINE); + p->skipvsp = 0; + } + + while ('\0' != *word) { + if ('\\' != *word) { + if (TERMP_NBRWORD & p->flags) { + if (' ' == *word) { + encode(p, nbrsp, 1); + word++; + continue; + } + ssz = strcspn(word, "\\ "); + } else + ssz = strcspn(word, "\\"); + encode(p, word, ssz); + word += (int)ssz; + continue; + } + + word++; + esc = mandoc_escape(&word, &seq, &sz); + switch (esc) { + case ESCAPE_UNICODE: + uc = mchars_num2uc(seq + 1, sz - 1); + break; + case ESCAPE_NUMBERED: + uc = mchars_num2char(seq, sz); + if (uc < 0) + continue; + break; + case ESCAPE_SPECIAL: + if (p->enc == TERMENC_ASCII) { + cp = mchars_spec2str(seq, sz, &ssz); + if (cp != NULL) + encode(p, cp, ssz); + } else { + uc = mchars_spec2cp(seq, sz); + if (uc > 0) + encode1(p, uc); + } + continue; + case ESCAPE_UNDEF: + uc = *seq; + break; + case ESCAPE_FONTBOLD: + term_fontrepl(p, TERMFONT_BOLD); + continue; + case ESCAPE_FONTITALIC: + term_fontrepl(p, TERMFONT_UNDER); + continue; + case ESCAPE_FONTBI: + term_fontrepl(p, TERMFONT_BI); + continue; + case ESCAPE_FONT: + case ESCAPE_FONTCW: + case ESCAPE_FONTROMAN: + term_fontrepl(p, TERMFONT_NONE); + continue; + case ESCAPE_FONTPREV: + term_fontlast(p); + continue; + case ESCAPE_BREAK: + bufferc(p, '\n'); + continue; + case ESCAPE_NOSPACE: + if (p->flags & TERMP_BACKAFTER) + p->flags &= ~TERMP_BACKAFTER; + else if (*word == '\0') + p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE); + continue; + case ESCAPE_DEVICE: + if (p->type == TERMTYPE_PDF) + encode(p, "pdf", 3); + else if (p->type == TERMTYPE_PS) + encode(p, "ps", 2); + else if (p->enc == TERMENC_ASCII) + encode(p, "ascii", 5); + else + encode(p, "utf8", 4); + continue; + case ESCAPE_HORIZ: + if (*seq == '|') { + seq++; + uc = -p->col; + } else + uc = 0; + if (a2roffsu(seq, &su, SCALE_EM) == NULL) + continue; + uc += term_hen(p, &su); + if (uc > 0) + while (uc-- > 0) + bufferc(p, ASCII_NBRSP); + else if (p->col > (size_t)(-uc)) + p->col += uc; + else { + uc += p->col; + p->col = 0; + if (p->tcol->offset > (size_t)(-uc)) { + p->ti += uc; + p->tcol->offset += uc; + } else { + p->ti -= p->tcol->offset; + p->tcol->offset = 0; + } + } + continue; + case ESCAPE_HLINE: + if ((cp = a2roffsu(seq, &su, SCALE_EM)) == NULL) + continue; + uc = term_hen(p, &su); + if (uc <= 0) { + if (p->tcol->rmargin <= p->tcol->offset) + continue; + lsz = p->tcol->rmargin - p->tcol->offset; + } else + lsz = uc; + if (*cp == seq[-1]) + uc = -1; + else if (*cp == '\\') { + seq = cp + 1; + esc = mandoc_escape(&seq, &cp, &sz); + switch (esc) { + case ESCAPE_UNICODE: + uc = mchars_num2uc(cp + 1, sz - 1); + break; + case ESCAPE_NUMBERED: + uc = mchars_num2char(cp, sz); + break; + case ESCAPE_SPECIAL: + uc = mchars_spec2cp(cp, sz); + break; + case ESCAPE_UNDEF: + uc = *seq; + break; + default: + uc = -1; + break; + } + } else + uc = *cp; + if (uc < 0x20 || (uc > 0x7E && uc < 0xA0)) + uc = '_'; + if (p->enc == TERMENC_ASCII) { + cp = ascii_uc2str(uc); + csz = term_strlen(p, cp); + ssz = strlen(cp); + } else + csz = (*p->width)(p, uc); + while (lsz >= csz) { + if (p->enc == TERMENC_ASCII) + encode(p, cp, ssz); + else + encode1(p, uc); + lsz -= csz; + } + continue; + case ESCAPE_SKIPCHAR: + p->flags |= TERMP_BACKAFTER; + continue; + case ESCAPE_OVERSTRIKE: + cp = seq + sz; + while (seq < cp) { + if (*seq == '\\') { + mandoc_escape(&seq, NULL, NULL); + continue; + } + encode1(p, *seq++); + if (seq < cp) { + if (p->flags & TERMP_BACKBEFORE) + p->flags |= TERMP_BACKAFTER; + else + p->flags |= TERMP_BACKBEFORE; + } + } + /* Trim trailing backspace/blank pair. */ + if (p->tcol->lastcol > 2 && + (p->tcol->buf[p->tcol->lastcol - 1] == ' ' || + p->tcol->buf[p->tcol->lastcol - 1] == '\t')) + p->tcol->lastcol -= 2; + if (p->col > p->tcol->lastcol) + p->col = p->tcol->lastcol; + continue; + default: + continue; + } + + /* + * Common handling for Unicode and numbered + * character escape sequences. + */ + + if (p->enc == TERMENC_ASCII) { + cp = ascii_uc2str(uc); + encode(p, cp, strlen(cp)); + } else { + if ((uc < 0x20 && uc != 0x09) || + (uc > 0x7E && uc < 0xA0)) + uc = 0xFFFD; + encode1(p, uc); + } + } + p->flags &= ~TERMP_NBRWORD; +} + +static void +adjbuf(struct termp_col *c, size_t sz) +{ + if (c->maxcols == 0) + c->maxcols = 1024; + while (c->maxcols <= sz) + c->maxcols <<= 2; + c->buf = mandoc_reallocarray(c->buf, c->maxcols, sizeof(*c->buf)); +} + +static void +bufferc(struct termp *p, char c) +{ + if (p->flags & TERMP_NOBUF) { + (*p->letter)(p, c); + return; + } + if (p->col + 1 >= p->tcol->maxcols) + adjbuf(p->tcol, p->col + 1); + if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP)) + p->tcol->buf[p->col] = c; + if (p->tcol->lastcol < ++p->col) + p->tcol->lastcol = p->col; +} + +/* + * See encode(). + * Do this for a single (probably unicode) value. + * Does not check for non-decorated glyphs. + */ +static void +encode1(struct termp *p, int c) +{ + enum termfont f; + + if (p->flags & TERMP_NOBUF) { + (*p->letter)(p, c); + return; + } + + if (p->col + 7 >= p->tcol->maxcols) + adjbuf(p->tcol, p->col + 7); + + f = (c == ASCII_HYPH || c > 127 || isgraph(c)) ? + p->fontq[p->fonti] : TERMFONT_NONE; + + if (p->flags & TERMP_BACKBEFORE) { + if (p->tcol->buf[p->col - 1] == ' ' || + p->tcol->buf[p->col - 1] == '\t') + p->col--; + else + p->tcol->buf[p->col++] = '\b'; + p->flags &= ~TERMP_BACKBEFORE; + } + if (f == TERMFONT_UNDER || f == TERMFONT_BI) { + p->tcol->buf[p->col++] = '_'; + p->tcol->buf[p->col++] = '\b'; + } + if (f == TERMFONT_BOLD || f == TERMFONT_BI) { + if (c == ASCII_HYPH) + p->tcol->buf[p->col++] = '-'; + else + p->tcol->buf[p->col++] = c; + p->tcol->buf[p->col++] = '\b'; + } + if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP)) + p->tcol->buf[p->col] = c; + if (p->tcol->lastcol < ++p->col) + p->tcol->lastcol = p->col; + if (p->flags & TERMP_BACKAFTER) { + p->flags |= TERMP_BACKBEFORE; + p->flags &= ~TERMP_BACKAFTER; + } +} + +static void +encode(struct termp *p, const char *word, size_t sz) +{ + size_t i; + + if (p->flags & TERMP_NOBUF) { + for (i = 0; i < sz; i++) + (*p->letter)(p, word[i]); + return; + } + + if (p->col + 2 + (sz * 5) >= p->tcol->maxcols) + adjbuf(p->tcol, p->col + 2 + (sz * 5)); + + for (i = 0; i < sz; i++) { + if (ASCII_HYPH == word[i] || + isgraph((unsigned char)word[i])) + encode1(p, word[i]); + else { + if (p->tcol->lastcol <= p->col || + (word[i] != ' ' && word[i] != ASCII_NBRSP)) + p->tcol->buf[p->col] = word[i]; + p->col++; + + /* + * Postpone the effect of \z while handling + * an overstrike sequence from ascii_uc2str(). + */ + + if (word[i] == '\b' && + (p->flags & TERMP_BACKBEFORE)) { + p->flags &= ~TERMP_BACKBEFORE; + p->flags |= TERMP_BACKAFTER; + } + } + } + if (p->tcol->lastcol < p->col) + p->tcol->lastcol = p->col; +} + +void +term_setwidth(struct termp *p, const char *wstr) +{ + struct roffsu su; + int iop, width; + + iop = 0; + width = 0; + if (NULL != wstr) { + switch (*wstr) { + case '+': + iop = 1; + wstr++; + break; + case '-': + iop = -1; + wstr++; + break; + default: + break; + } + if (a2roffsu(wstr, &su, SCALE_MAX) != NULL) + width = term_hspan(p, &su); + else + iop = 0; + } + (*p->setwidth)(p, iop, width); +} + +size_t +term_len(const struct termp *p, size_t sz) +{ + + return (*p->width)(p, ' ') * sz; +} + +static size_t +cond_width(const struct termp *p, int c, int *skip) +{ + + if (*skip) { + (*skip) = 0; + return 0; + } else + return (*p->width)(p, c); +} + +size_t +term_strlen(const struct termp *p, const char *cp) +{ + size_t sz, rsz, i; + int ssz, skip, uc; + const char *seq, *rhs; + enum mandoc_esc esc; + static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH, + ASCII_BREAK, '\0' }; + + /* + * Account for escaped sequences within string length + * calculations. This follows the logic in term_word() as we + * must calculate the width of produced strings. + */ + + sz = 0; + skip = 0; + while ('\0' != *cp) { + rsz = strcspn(cp, rej); + for (i = 0; i < rsz; i++) + sz += cond_width(p, *cp++, &skip); + + switch (*cp) { + case '\\': + cp++; + rhs = NULL; + esc = mandoc_escape(&cp, &seq, &ssz); + switch (esc) { + case ESCAPE_UNICODE: + uc = mchars_num2uc(seq + 1, ssz - 1); + break; + case ESCAPE_NUMBERED: + uc = mchars_num2char(seq, ssz); + if (uc < 0) + continue; + break; + case ESCAPE_SPECIAL: + if (p->enc == TERMENC_ASCII) { + rhs = mchars_spec2str(seq, ssz, &rsz); + if (rhs != NULL) + break; + } else { + uc = mchars_spec2cp(seq, ssz); + if (uc > 0) + sz += cond_width(p, uc, &skip); + } + continue; + case ESCAPE_UNDEF: + uc = *seq; + break; + case ESCAPE_DEVICE: + if (p->type == TERMTYPE_PDF) { + rhs = "pdf"; + rsz = 3; + } else if (p->type == TERMTYPE_PS) { + rhs = "ps"; + rsz = 2; + } else if (p->enc == TERMENC_ASCII) { + rhs = "ascii"; + rsz = 5; + } else { + rhs = "utf8"; + rsz = 4; + } + break; + case ESCAPE_SKIPCHAR: + skip = 1; + continue; + case ESCAPE_OVERSTRIKE: + rsz = 0; + rhs = seq + ssz; + while (seq < rhs) { + if (*seq == '\\') { + mandoc_escape(&seq, NULL, NULL); + continue; + } + i = (*p->width)(p, *seq++); + if (rsz < i) + rsz = i; + } + sz += rsz; + continue; + default: + continue; + } + + /* + * Common handling for Unicode and numbered + * character escape sequences. + */ + + if (rhs == NULL) { + if (p->enc == TERMENC_ASCII) { + rhs = ascii_uc2str(uc); + rsz = strlen(rhs); + } else { + if ((uc < 0x20 && uc != 0x09) || + (uc > 0x7E && uc < 0xA0)) + uc = 0xFFFD; + sz += cond_width(p, uc, &skip); + continue; + } + } + + if (skip) { + skip = 0; + break; + } + + /* + * Common handling for all escape sequences + * printing more than one character. + */ + + for (i = 0; i < rsz; i++) + sz += (*p->width)(p, *rhs++); + break; + case ASCII_NBRSP: + sz += cond_width(p, ' ', &skip); + cp++; + break; + case ASCII_HYPH: + sz += cond_width(p, '-', &skip); + cp++; + break; + default: + break; + } + } + + return sz; +} + +int +term_vspan(const struct termp *p, const struct roffsu *su) +{ + double r; + int ri; + + switch (su->unit) { + case SCALE_BU: + r = su->scale / 40.0; + break; + case SCALE_CM: + r = su->scale * 6.0 / 2.54; + break; + case SCALE_FS: + r = su->scale * 65536.0 / 40.0; + break; + case SCALE_IN: + r = su->scale * 6.0; + break; + case SCALE_MM: + r = su->scale * 0.006; + break; + case SCALE_PC: + r = su->scale; + break; + case SCALE_PT: + r = su->scale / 12.0; + break; + case SCALE_EN: + case SCALE_EM: + r = su->scale * 0.6; + break; + case SCALE_VS: + r = su->scale; + break; + default: + abort(); + } + ri = r > 0.0 ? r + 0.4995 : r - 0.4995; + return ri < 66 ? ri : 1; +} + +/* + * Convert a scaling width to basic units, rounding towards 0. + */ +int +term_hspan(const struct termp *p, const struct roffsu *su) +{ + + return (*p->hspan)(p, su); +} + +/* + * Convert a scaling width to basic units, rounding to closest. + */ +int +term_hen(const struct termp *p, const struct roffsu *su) +{ + int bu; + + if ((bu = (*p->hspan)(p, su)) >= 0) + return (bu + 11) / 24; + else + return -((-bu + 11) / 24); +} Property changes on: vendor/mandoc/20190723/term.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/INSTALL =================================================================== --- vendor/mandoc/20190723/INSTALL (nonexistent) +++ vendor/mandoc/20190723/INSTALL (revision 350350) @@ -0,0 +1,160 @@ +$Id: INSTALL,v 1.23 2019/03/06 15:58:10 schwarze Exp $ + +About the portable mandoc distribution +-------------------------------------- +The mandoc manpage compiler toolset (formerly called "mdocml") +is a suite of tools compiling mdoc(7), the roff(7) macro language +of choice for BSD manual pages, and man(7), the predominant +historical language for UNIX manuals. + +It includes a man(1) manual viewer and additional tools. +For general information, see . + +In case you have questions or want to provide feedback, read +. Consider subscribing to the +discuss@ mailing list mentioned on that page. If you intend to +help with the development of mandoc, consider subscribing to the +tech@ mailing list, too. + +Enjoy using the mandoc toolset! + +Ingo Schwarze, Karlsruhe, March 2019 + + +Installation +------------ +Before manually installing mandoc on your system, please check +whether the newest version of mandoc is already installed by default +or available via a binary package or a ports system. A list of the +latest bundled and ported versions of mandoc for various operating +systems is maintained at . + +Regarding how packages and ports are maintained for your operating +system, please consult your operating system documentation. +To install mandoc manually, the following steps are needed: + +1. If you want to build the CGI program, man.cgi(8), too, +run the command "echo BUILD_CGI=1 >> configure.local". +Then run "cp cgi.h.example cgi.h" and edit cgi.h as desired. + +2. If you also want to build the catman(8) utility, run the +command "echo BUILD_CATMAN=1 >> configure.local". Note that it +is unlikely to be a drop-in replacement providing the same +functionality as your system's "catman", if your operating +system contains one. + +3. Define MANPATH_DEFAULT in configure.local +if /usr/share/man:/usr/X11R6/man:/usr/local/man is not appropriate +for your operating system. + +4. Run "./configure". +This script attempts autoconfiguration of mandoc for your system. +Read both its standard output and the file "Makefile.local" it +generates. If anything looks wrong or different from what you +wish, read the file "configure.local.example", create and edit +a file "configure.local", and re-run "./configure" until the +result seems right to you. + +5. Run "make". +Any POSIX-compatible make, in particular both BSD make and GNU make, +should work. If the build fails, look at "configure.local.example" +and go back to step 2. + +6. Run "make -n install" and check whether everything will be +installed to the intended places. Otherwise, put some *DIR or *NM* +variables into "configure.local" and go back to step 4. + +7. Optionally run the regression suite. +Basically, that amounts to "cd regress && ./regress.pl". +But you should probably look at "./mandoc -l regress/regress.pl.1" +first. In particular, regarding Solaris systems, look at the BUGS +section of that manual page. + +8. Run "sudo make install". If you intend to build a binary +package using some kind of fake root mechanism, you may need a +command like "make DESTDIR=... install". Read the *-install targets +in the "Makefile" to understand how DESTDIR is used. + +9. Run the command "sudo makewhatis" to build mandoc.db(5) databases +in all the directory trees configured in step 3. Whenever installing +new manual pages, re-run makewhatis(8) to update the databases, or +apropos(1) will not find the new pages. + +10. To set up a man.cgi(8) server, read its manual page. + +Note that a very small number of man(7) pages contain low-level +roff(7) markup that mandoc does not yet understand. On some BSD +systems using mandoc, third-party software is vetted on whether it +may be formatted with mandoc. If not, groff(1) is pulled in as a +dependency and used to install pre-formatted "catpages" instead of +manual page sources. This mechanism is used much less frequently +than in the past. On OpenBSD, only 25 out of about 10000 ports +still require formatting with groff(1). + + +Understanding mandoc dependencies +--------------------------------- +The following libraries are required: + +1. zlib for decompressing gzipped manual pages. + +2. The fts(3) directory traversion functions. +If your system does not have them, the bundled compatibility version +will be used, so you need not worry in that case. But be careful: old +glibc versions of fts(3) were known to be broken on 32bit platforms, +see . +That was presumably fixed in glibc-2.23. +If you run into that problem, set "HAVE_FTS=0" in configure.local. + +3. Marc Espie's ohash(3) library. +If your system does not have it, the bundled compatibility version +will be used, so you probably need not worry about it. + +One of the chief design goals of the mandoc toolbox is to make +sure that nothing related to documentation requires C++. +Consequently, linking mandoc against any kind of C++ program +would defeat the purpose and is not supported. + + +Checking autoconfiguration quality +---------------------------------- +If you want to check whether automatic configuration works well +on your platform, consider the following: + +The mandoc package intentionally does not use GNU autoconf because +we consider that toolset a blatant example of overengineering that +is obsolete nowadays, since all modern operating systems are now +reasonably close to POSIX and do not need arcane shell magic any +longer. If your system does need such magic, consider upgrading +to reasonably modern POSIX-compliant tools rather than asking for +autoconf-style workarounds. + +As far as mandoc is using any features not mandated by ANSI X3.159-1989 +("ANSI C") or IEEE Std 1003.1-2008 ("POSIX") that some modern systems +do not have, we intend to provide autoconfiguration tests and +compat_*.c implementations. Please report any that turn out to be +missing. Note that while we do strive to produce portable code, +we do not slavishly restrict ourselves to POSIX-only interfaces. +For improved security and readability, we do use well-designed, +modern interfaces like reallocarray(3) even if they are still rather +uncommon, of course bundling compat_*.c implementations as needed. + +Where mandoc is using ANSI C or POSIX features that some systems +still lack and that compat_*.c implementations can be provided for +without too much hassle, we will consider adding them, too, so +please report whatever is missing on your platform. + +The following steps can be used to manually check the automatic +configuration on your platform: + +1. Run "make distclean". + +2. Run "./configure" + +3. Read the file "config.log". It shows the compiler commands used +to test the libraries installed on your system and the standard +output and standard error output these commands produce. Watch out +for unexpected failures. Those are most likely to happen if headers +or libraries are installed in unusual places or interfaces defined +in unusual headers. You can also look at the file "config.h" and +check that no "#define HAVE_*" differ from your expectations. Index: vendor/mandoc/20190723/LICENSE =================================================================== --- vendor/mandoc/20190723/LICENSE (nonexistent) +++ vendor/mandoc/20190723/LICENSE (revision 350350) @@ -0,0 +1,55 @@ +$Id: LICENSE,v 1.21 2018/11/26 17:11:11 schwarze Exp $ + +With the exceptions noted below, all non-trivial files contained +in the mandoc toolkit are protected by the Copyright of the following +developers: + +Copyright (c) 2008-2012, 2014 Kristaps Dzonsons +Copyright (c) 2010-2018 Ingo Schwarze +Copyright (c) 1999, 2004, 2017 Marc Espie +Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger +Copyright (c) 2013 Franco Fichtner +Copyright (c) 2014 Baptiste Daroussin +Copyright (c) 2016 Ed Maste +Copyright (c) 2017 Michael Stapelberg +Copyright (c) 2017 Anthony Bentley +Copyright (c) 1998, 2004, 2010 Todd C. Miller +Copyright (c) 2008, 2017 Otto Moerbeek +Copyright (c) 2004 Ted Unangst +Copyright (c) 1994 Christos Zoulas +Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre + +See the individual files for information about who contributed +to which file during which years. + + +The mandoc distribution as a whole is distributed by its developers +under the following license: + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +The following files included from outside sources are protected by +other people's Copyright and are distributed under various 2-clause +and 3-clause BSD licenses; see these individual files for details. + +soelim.c, soelim.1: +Copyright (c) 2014 Baptiste Daroussin + +compat_err.c, compat_fts.c, compat_fts.h, +compat_getsubopt.c, compat_strcasestr.c, compat_strsep.c, +man.1: +Copyright (c) 1989,1990,1993,1994 The Regents of the University of California + +compat_stringlist.c, compat_stringlist.h: +Copyright (c) 1994 Christos Zoulas Index: vendor/mandoc/20190723/Makefile =================================================================== --- vendor/mandoc/20190723/Makefile (nonexistent) +++ vendor/mandoc/20190723/Makefile (revision 350350) @@ -0,0 +1,603 @@ +# $Id: Makefile,v 1.530 2019/03/06 16:08:41 schwarze Exp $ +# +# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons +# Copyright (c) 2011, 2013-2019 Ingo Schwarze +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +VERSION = 1.14.5 + +# === LIST OF FILES ==================================================== + +TESTSRCS = test-be32toh.c \ + test-cmsg.c \ + test-dirent-namlen.c \ + test-EFTYPE.c \ + test-err.c \ + test-fts.c \ + test-getline.c \ + test-getsubopt.c \ + test-isblank.c \ + test-mkdtemp.c \ + test-nanosleep.c \ + test-noop.c \ + test-ntohl.c \ + test-O_DIRECTORY.c \ + test-ohash.c \ + test-PATH_MAX.c \ + test-pledge.c \ + test-progname.c \ + test-reallocarray.c \ + test-recallocarray.c \ + test-recvmsg.c \ + test-rewb-bsd.c \ + test-rewb-sysv.c \ + test-sandbox_init.c \ + test-strcasestr.c \ + test-stringlist.c \ + test-strlcat.c \ + test-strlcpy.c \ + test-strndup.c \ + test-strptime.c \ + test-strsep.c \ + test-strtonum.c \ + test-vasprintf.c \ + test-wchar.c + +SRCS = arch.c \ + att.c \ + catman.c \ + cgi.c \ + chars.c \ + compat_err.c \ + compat_fts.c \ + compat_getline.c \ + compat_getsubopt.c \ + compat_isblank.c \ + compat_mkdtemp.c \ + compat_ohash.c \ + compat_progname.c \ + compat_reallocarray.c \ + compat_recallocarray.c \ + compat_strcasestr.c \ + compat_stringlist.c \ + compat_strlcat.c \ + compat_strlcpy.c \ + compat_strndup.c \ + compat_strsep.c \ + compat_strtonum.c \ + compat_vasprintf.c \ + dba.c \ + dba_array.c \ + dba_read.c \ + dba_write.c \ + dbm.c \ + dbm_map.c \ + demandoc.c \ + eqn.c \ + eqn_html.c \ + eqn_term.c \ + html.c \ + lib.c \ + main.c \ + man.c \ + man_html.c \ + man_macro.c \ + man_term.c \ + man_validate.c \ + mandoc.c \ + mandoc_aux.c \ + mandoc_msg.c \ + mandoc_ohash.c \ + mandoc_xr.c \ + mandocd.c \ + mandocdb.c \ + manpath.c \ + mansearch.c \ + mdoc.c \ + mdoc_argv.c \ + mdoc_html.c \ + mdoc_macro.c \ + mdoc_man.c \ + mdoc_markdown.c \ + mdoc_state.c \ + mdoc_term.c \ + mdoc_validate.c \ + msec.c \ + out.c \ + preconv.c \ + read.c \ + roff.c \ + roff_html.c \ + roff_term.c \ + roff_validate.c \ + soelim.c \ + st.c \ + tag.c \ + tbl.c \ + tbl_data.c \ + tbl_html.c \ + tbl_layout.c \ + tbl_opts.c \ + tbl_term.c \ + term.c \ + term_ascii.c \ + term_ps.c \ + term_tab.c \ + tree.c + +DISTFILES = INSTALL \ + LICENSE \ + Makefile \ + Makefile.depend \ + NEWS \ + TODO \ + apropos.1 \ + catman.8 \ + cgi.h.example \ + compat_fts.h \ + compat_ohash.h \ + compat_stringlist.h \ + configure \ + configure.local.example \ + dba.h \ + dba_array.h \ + dba_write.h \ + dbm.h \ + dbm_map.h \ + demandoc.1 \ + eqn.7 \ + eqn.h \ + eqn_parse.h \ + gmdiff \ + html.h \ + lib.in \ + libman.h \ + libmandoc.h \ + libmdoc.h \ + main.h \ + makewhatis.8 \ + man.1 \ + man.7 \ + man.cgi.3 \ + man.cgi.8 \ + man.conf.5 \ + man.h \ + man.options.1 \ + manconf.h \ + mandoc.1 \ + mandoc.3 \ + mandoc.css \ + mandoc.db.5 \ + mandoc.h \ + mandoc_aux.h \ + mandoc_char.7 \ + mandoc_escape.3 \ + mandoc_headers.3 \ + mandoc_html.3 \ + mandoc_malloc.3 \ + mandoc_ohash.h \ + mandoc_parse.h \ + mandoc_xr.h \ + mandocd.8 \ + mansearch.3 \ + mansearch.h \ + mchars_alloc.3 \ + mdoc.7 \ + mdoc.h \ + msec.in \ + out.h \ + predefs.in \ + roff.7 \ + roff.h \ + roff_int.h \ + soelim.1 \ + tag.h \ + tbl.3 \ + tbl.7 \ + tbl.h \ + tbl_int.h \ + tbl_parse.h \ + term.h \ + $(SRCS) \ + $(TESTSRCS) + +LIBMAN_OBJS = man.o \ + man_macro.o \ + man_validate.o + +LIBMDOC_OBJS = att.o \ + lib.o \ + mdoc.o \ + mdoc_argv.o \ + mdoc_macro.o \ + mdoc_state.o \ + mdoc_validate.o \ + st.o + +LIBROFF_OBJS = eqn.o \ + roff.o \ + roff_validate.o \ + tbl.o \ + tbl_data.o \ + tbl_layout.o \ + tbl_opts.o + +LIBMANDOC_OBJS = $(LIBMAN_OBJS) \ + $(LIBMDOC_OBJS) \ + $(LIBROFF_OBJS) \ + arch.o \ + chars.o \ + mandoc.o \ + mandoc_aux.o \ + mandoc_msg.o \ + mandoc_ohash.o \ + mandoc_xr.o \ + msec.o \ + preconv.o \ + read.o + +COMPAT_OBJS = compat_err.o \ + compat_fts.o \ + compat_getline.o \ + compat_getsubopt.o \ + compat_isblank.o \ + compat_mkdtemp.o \ + compat_ohash.o \ + compat_progname.o \ + compat_reallocarray.o \ + compat_recallocarray.o \ + compat_strcasestr.o \ + compat_strlcat.o \ + compat_strlcpy.o \ + compat_strndup.o \ + compat_strsep.o \ + compat_strtonum.o \ + compat_vasprintf.o + +MANDOC_HTML_OBJS = eqn_html.o \ + html.o \ + man_html.o \ + mdoc_html.o \ + roff_html.o \ + tbl_html.o + +MANDOC_TERM_OBJS = eqn_term.o \ + man_term.o \ + mdoc_term.o \ + roff_term.o \ + term.o \ + term_ascii.o \ + term_ps.o \ + term_tab.o \ + tbl_term.o + +DBM_OBJS = dbm.o \ + dbm_map.o \ + mansearch.o + +DBA_OBJS = dba.o \ + dba_array.o \ + dba_read.o \ + dba_write.o \ + mandocdb.o + +MAIN_OBJS = $(MANDOC_HTML_OBJS) \ + $(MANDOC_MAN_OBJS) \ + $(MANDOC_TERM_OBJS) \ + $(DBM_OBJS) \ + $(DBA_OBJS) \ + main.o \ + manpath.o \ + mdoc_man.o \ + mdoc_markdown.o \ + out.o \ + tag.o \ + tree.o + +CGI_OBJS = $(MANDOC_HTML_OBJS) \ + $(DBM_OBJS) \ + cgi.o \ + out.o + +MANDOCD_OBJS = $(MANDOC_HTML_OBJS) \ + $(MANDOC_TERM_OBJS) \ + mandocd.o \ + out.o \ + tag.o + +DEMANDOC_OBJS = demandoc.o + +SOELIM_OBJS = soelim.o \ + compat_err.o \ + compat_getline.o \ + compat_progname.o \ + compat_reallocarray.o \ + compat_stringlist.o + +WWW_MANS = apropos.1.html \ + demandoc.1.html \ + man.1.html \ + man.options.1.html \ + mandoc.1.html \ + soelim.1.html \ + man.cgi.3.html \ + mandoc.3.html \ + mandoc_escape.3.html \ + mandoc_headers.3.html \ + mandoc_html.3.html \ + mandoc_malloc.3.html \ + mansearch.3.html \ + mchars_alloc.3.html \ + tbl.3.html \ + man.conf.5.html \ + mandoc.db.5.html \ + eqn.7.html \ + man.7.html \ + mandoc_char.7.html \ + mdoc.7.html \ + roff.7.html \ + tbl.7.html \ + catman.8.html \ + makewhatis.8.html \ + man.cgi.8.html \ + mandocd.8.html + +WWW_INCS = eqn.h.html \ + html.h.html \ + man.h.html \ + manconf.h.html \ + mandoc.h.html \ + mandoc_aux.h.html \ + mandoc_parse.h.html \ + mansearch.h.html \ + mdoc.h.html \ + roff.h.html \ + tbl.h.html \ + tbl_int.h.html \ + tbl_parse.h.html + +# === USER CONFIGURATION =============================================== + +include Makefile.local + +# === DEPENDENCY HANDLING ============================================== + +all: mandoc demandoc soelim $(BUILD_TARGETS) Makefile.local + +install: base-install $(INSTALL_TARGETS) + +www: $(WWW_MANS) $(WWW_INCS) + +$(WWW_MANS) $(WWW_INCS): mandoc + +.PHONY: base-install cgi-install install www-install +.PHONY: clean distclean depend + +include Makefile.depend + +# === TARGETS CONTAINING SHELL COMMANDS ================================ + +distclean: clean + rm -f Makefile.local config.h config.h.old config.log config.log.old + +clean: + rm -f libmandoc.a $(LIBMANDOC_OBJS) $(COMPAT_OBJS) + rm -f mandoc $(MAIN_OBJS) + rm -f man.cgi $(CGI_OBJS) + rm -f mandocd catman catman.o $(MANDOCD_OBJS) + rm -f demandoc $(DEMANDOC_OBJS) + rm -f soelim $(SOELIM_OBJS) + rm -f $(WWW_MANS) $(WWW_INCS) mandoc*.tar.gz mandoc*.sha256 + rm -rf *.dSYM + +base-install: mandoc demandoc soelim + mkdir -p $(DESTDIR)$(BINDIR) + mkdir -p $(DESTDIR)$(SBINDIR) + mkdir -p $(DESTDIR)$(MANDIR)/man1 + mkdir -p $(DESTDIR)$(MANDIR)/man5 + mkdir -p $(DESTDIR)$(MANDIR)/man7 + mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_PROGRAM) mandoc demandoc $(DESTDIR)$(BINDIR) + $(INSTALL_PROGRAM) soelim $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) + cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_MAN) + cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_APROPOS) + cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_WHATIS) + cd $(DESTDIR)$(SBINDIR) && \ + $(LN) ${BIN_FROM_SBIN}/mandoc $(BINM_MAKEWHATIS) + $(INSTALL_MAN) mandoc.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1 + $(INSTALL_MAN) soelim.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 + $(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 + $(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 + cd $(DESTDIR)$(MANDIR)/man1 && $(LN) $(BINM_APROPOS).1 $(BINM_WHATIS).1 + $(INSTALL_MAN) man.conf.5 $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 + $(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5 + $(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 + $(INSTALL_MAN) mdoc.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MDOC).7 + $(INSTALL_MAN) roff.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_ROFF).7 + $(INSTALL_MAN) eqn.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_EQN).7 + $(INSTALL_MAN) tbl.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_TBL).7 + $(INSTALL_MAN) mandoc_char.7 $(DESTDIR)$(MANDIR)/man7 + $(INSTALL_MAN) makewhatis.8 \ + $(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8 + +lib-install: libmandoc.a + mkdir -p $(DESTDIR)$(LIBDIR) + mkdir -p $(DESTDIR)$(INCLUDEDIR) + mkdir -p $(DESTDIR)$(MANDIR)/man3 + $(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR) + $(INSTALL_LIB) eqn.h man.h mandoc.h mandoc_aux.h mandoc_parse.h \ + mdoc.h roff.h tbl.h $(DESTDIR)$(INCLUDEDIR) + $(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \ + mansearch.3 mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3 + +cgi-install: man.cgi + mkdir -p $(DESTDIR)$(CGIBINDIR) + mkdir -p $(DESTDIR)$(HTDOCDIR) + $(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR) + $(INSTALL_DATA) mandoc.css $(DESTDIR)$(HTDOCDIR) + +catman-install: mandocd catman + mkdir -p $(DESTDIR)$(SBINDIR) + mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_PROGRAM) mandocd $(DESTDIR)$(SBINDIR) + $(INSTALL_PROGRAM) catman $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN) + $(INSTALL_MAN) mandocd.8 $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_MAN) catman.8 $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8 + +uninstall: + rm -f $(DESTDIR)$(BINDIR)/mandoc + rm -f $(DESTDIR)$(BINDIR)/demandoc + rm -f $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_MAN) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_APROPOS) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_WHATIS) + rm -f $(DESTDIR)$(SBINDIR)/$(BINM_MAKEWHATIS) + rm -f $(DESTDIR)$(MANDIR)/man1/mandoc.1 + rm -f $(DESTDIR)$(MANDIR)/man1/demandoc.1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_WHATIS).1 + rm -f $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 + rm -f $(DESTDIR)$(MANDIR)/man5/mandoc.db.5 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_MDOC).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_ROFF).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_EQN).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_TBL).7 + rm -f $(DESTDIR)$(MANDIR)/man7/mandoc_char.7 + rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8 + rm -f $(DESTDIR)$(CGIBINDIR)/man.cgi + rm -f $(DESTDIR)$(HTDOCDIR)/mandoc.css + rm -f $(DESTDIR)$(SBINDIR)/mandocd + rm -f $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN) + rm -f $(DESTDIR)$(MANDIR)/man8/mandocd.8 + rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8 + rm -f $(DESTDIR)$(LIBDIR)/libmandoc.a + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_escape.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_malloc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mansearch.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mchars_alloc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/tbl.3 + rm -f $(DESTDIR)$(INCLUDEDIR)/eqn.h + rm -f $(DESTDIR)$(INCLUDEDIR)/man.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_aux.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_parse.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mdoc.h + rm -f $(DESTDIR)$(INCLUDEDIR)/roff.h + rm -f $(DESTDIR)$(INCLUDEDIR)/tbl.h + [ ! -e $(DESTDIR)$(INCLUDEDIR) ] || rmdir $(DESTDIR)$(INCLUDEDIR) + +regress: all + cd regress && ./regress.pl + +regress-clean: + cd regress && ./regress.pl . clean + +Makefile.local config.h: configure $(TESTSRCS) + @echo "$@ is out of date; please run ./configure" + @exit 1 + +libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS) + ar rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS) + +mandoc: $(MAIN_OBJS) libmandoc.a + $(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD) + +man.cgi: $(CGI_OBJS) libmandoc.a + $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD) + +mandocd: $(MANDOCD_OBJS) libmandoc.a + $(CC) -o $@ $(LDFLAGS) $(MANDOCD_OBJS) libmandoc.a $(LDADD) + +catman: catman.o libmandoc.a + $(CC) -o $@ $(LDFLAGS) catman.o libmandoc.a $(LDADD) + +demandoc: $(DEMANDOC_OBJS) libmandoc.a + $(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) libmandoc.a $(LDADD) + +soelim: $(SOELIM_OBJS) + $(CC) -o $@ $(LDFLAGS) $(SOELIM_OBJS) + +# --- maintainer targets --- + +www-install: www + $(INSTALL_DATA) mandoc.css $(HTDOCDIR) + $(INSTALL_DATA) $(WWW_MANS) $(HTDOCDIR)/man + $(INSTALL_DATA) $(WWW_INCS) $(HTDOCDIR)/includes + +depend: config.h + mkdep -f Makefile.depend $(CFLAGS) $(SRCS) + perl -e 'undef $$/; $$_ = <>; s|/usr/include/\S+||g; \ + s|\\\n||g; s| +| |g; s| $$||mg; print;' \ + Makefile.depend > Makefile.tmp + mv Makefile.tmp Makefile.depend + +regress-distclean: + @find regress \ + -name '.#*' -o \ + -name '*.orig' -o \ + -name '*.rej' -o \ + -name '*.core' \ + -exec rm -i {} \; + +regress-distcheck: + @find regress ! -type d ! -type f + @find regress -type f \ + ! -path '*/CVS/*' \ + ! -name Makefile \ + ! -name Makefile.inc \ + ! -name '*.in' \ + ! -name '*.out_ascii' \ + ! -name '*.out_utf8' \ + ! -name '*.out_html' \ + ! -name '*.out_markdown' \ + ! -name '*.out_lint' \ + ! -path regress/regress.pl \ + ! -path regress/regress.pl.1 + +dist: mandoc-$(VERSION).sha256 + +mandoc-$(VERSION).sha256: mandoc-$(VERSION).tar.gz + sha256 mandoc-$(VERSION).tar.gz > $@ + +mandoc-$(VERSION).tar.gz: $(DISTFILES) + ls regress/*/*/*.mandoc_* && exit 1 || true + mkdir -p .dist/mandoc-$(VERSION)/ + $(INSTALL) -m 0644 $(DISTFILES) .dist/mandoc-$(VERSION) + cp -pR regress .dist/mandoc-$(VERSION) + find .dist/mandoc-$(VERSION)/regress \ + -type d -name CVS -print0 | xargs -0 rm -rf + chmod 755 .dist/mandoc-$(VERSION)/configure + ( cd .dist/ && tar zcf ../$@ mandoc-$(VERSION) ) + rm -rf .dist/ + +dist-install: dist + $(INSTALL_DATA) mandoc-$(VERSION).tar.gz mandoc-$(VERSION).sha256 \ + $(HTDOCDIR)/snapshots + +# === SUFFIX RULES ===================================================== + +.SUFFIXES: .1 .3 .5 .7 .8 .h +.SUFFIXES: .1.html .3.html .5.html .7.html .8.html .h.html + +.h.h.html: + highlight -I $< > $@ + +.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc + mandoc -Thtml -Wwarning,stop \ + -O 'style=/mandoc.css,man=/man/%N.%S.html;https://man.openbsd.org/%N.%S,includes=/includes/%I.html' \ + $< > $@ Property changes on: vendor/mandoc/20190723/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/NEWS =================================================================== --- vendor/mandoc/20190723/NEWS (nonexistent) +++ vendor/mandoc/20190723/NEWS (revision 350350) @@ -0,0 +1,1144 @@ +$Id: NEWS,v 1.34 2019/03/10 09:32:00 schwarze Exp $ + +This file lists the most important changes in the mandoc.bsd.lv distribution. + +Changes in version 1.14.5, released on March 10, 2019 + + --- MAJOR NEW FEATURES --- + * apropos(1): improve POSIX compliance by accepting case-insensitive + extended regular expressions by default + * new -O tag[=term] output option (open a page at the definition of a term) + * tbl(7) -T html: spanning and horizontal and vertical alignment of cells + * tbl(7) -T html: draw lines on the edges of table cells + * tbl(7) -T utf8: render lines with the Unicode box drawing characters + * mandoc is now able to handle the manual pages of the groff package. + --- MINOR NEW FEATURES --- + * -T html: new option -O toc (table of contents) + * -T html: second argument to -O man to support local and remote links + * mdoc(7) .Bd -centered now fills the text contained in it + * man-ext .SY and .YS macros (synopsis block) + * man-ext .TQ macro (tagged paragraph without vertical space before it) + * tbl(7) \& explicit alignment indicator + * roff(7) .shift, .while, and .return requests + * roff(7) .char request (output glyph definition) + * roff(7) .nop request (no operation) + * roff(7) .ft request: handle the CB, CI, and CR fonts + * roff(7) .if c conditional (character available) + * roff(7) \\$@ escape sequence (insert all macro arguments, quoted) + * roff(7) \*(.T predefined string (interpolate output device name) + * roff(7) \[charNNN] escape sequence (for printable ASCII characters) + * roff(7) \# escape sequence (line continuation with comment) + --- HTML OUTPUT SYNTAX CORRECTIONS --- + * Render .br and \p as
, not as an empty
. + * Render .Pp and .PP as

and automatically close it when needed. + * Stop writing empty list elements for non-compact .Bl -tag lists. + * Do not put

inside if .UR or .MT contain .PP. + * Implement tooltips purely in CSS rather than abusing title= attributes. + --- MINOR FUNCTIONAL IMPROVEMENTS --- + * many improvements to the handling of fill and no-fill mode + * tbl(7): better column widths in the presence of horizontal spans + * several minor improvements to escape sequence handling + * several minor improvements to manual font handling + * portability: autodetect need for _GNU_SOURCE or _OPENBSD_SOURCE + * portability: autodetect whether less(1) supports the -T option + * large numbers of bugfixes of diverse kinds + --- STRUCTURAL IMPROVEMENTS --- + * Disentangle eqn(7) and tbl(7) from other parser header files, + and clean up some parser data structures. + * Substantially simplify error and warning message infrastructure. + --- THANKS TO --- + * John Gardner for crucial help implementing tooltips in CSS. + * Alexander Bluhm, Raphael Graf, Ted Unangst (OpenBSD) + and Daniel Sabogal (Alpine Linux) for patches. + * Anthony Bentley and Jason McIntyre (OpenBSD) for documentation patches, + suggesting new features, bug reports, and useful discussions. + * Kyle Evans and Baptiste Daroussin (FreeBSD) for minor patches. + * Pali Rohar for suggesting multiple new features and for reporting + several bugs and missing features. + * Klemens Nanni (OpenBSD) for suggesting multiple new features. + * Kristaps Dzonsons (bsd.lv), Marc Espie (OpenBSD), Adam Kalisz, + and Laura Morales for suggesting new features. + * Wolfram Schneider and Yuri Pankov (FreeBSD) for reporting missing features. + * Edward Tomasz Napierala (FreeBSD) for suggesting a feature improvement. + * Thomas Klausner (NetBSD) and Sevan Janiyan (SmartOS) + for bug reports and release testing. + * Bryan Steele, Janne Johansson, Kurt Mosiejczuk, Mike Belopuhov, Theo + Buehler, Todd Miller (OpenBSD), Andreas Gustafsson, Christos Zoulas, + Robert Elz (NetBSD), Kurt Jaeger (FreeBSD), Fabio Scotoni, Kelvin + Sherlock, Mark Harris, Orestis Ioannou, Raf Czlonka, and Sean Farrell + for bug reports. + * Ulrich Spoerlein (FreeBSD), Leah Neukirchen (Void Linux), + Matej Cepl (openSUSE), and Jan Stary (MacOS X) for release testing. + * Brian Callahan and Stuart Henderson (OpenBSD) for help + with the OpenBSD groff port. + * Bertrand Garrigues, Branden Robinson, Ralph Corderoy, and Werner + Lemberg (GNU troff) for checking groff patches. + * Scott Cheloha, Theo de Raadt (OpenBSD) + and Natanael Copa (Alpine Linux) for useful discussions. + +Changes in version 1.14.4, released on August 8, 2018 + + --- MAJOR NEW FEATURES --- + * In ASCII output, render mathematical symbols and greek letters + as transliterations conveying the characters' meanings rather + than trying to imitate their shape. Consequently, such characters + can now be used in portable manual pages. All the same, please + limit their use to contexts where they really matter, for example + when showing complicated mathematical formulae. + * First steps towards better support for small screens in HTML + output (responsive design): avoid most style= attributes, in + particular all hard-coded indentations and column widths, and + provide a better mandoc.css style sheet with a @media query, + using em units throughout, and avoiding redundancy in selectors. + * Better HTML output with some more fitting HTML elements, eliminating + needless class= attributes, and avoiding various HTML syntax errors + (element nesting, URL-fragment syntax, duplicate id= attributes). + --- MINOR NEW FEATURES --- + * When a man(1) argument contains a slash, imply -l like in man-db. + * Use TIOCGWINSZ to reduce the default -Owidth and -Oindent during + interactive use on terminals narrower than 79 columns. + * Generated PostScript files are now more than 50% smaller. + * Terminal rendering of eqn(7) is improved in several respects. + * Simplified and nicer output from the mdoc(7) .Lk macro, formatting + all links in-line, even long ones. + * roff(7) \n+ and \n- numerical register auto-increment and -decrement + * roff(7) .nr optional third argument (auto-increment step size) + * Autodetect in ./configure whether the compiler can use -W and -static, + allowing to build on Solaris 10 and 11 without any configure.local. + --- RELIABILITY BUGFIXES --- + * Only activate UTF-8 output when the user really selected UTF-8, + not some other multibyte character encoding. + * Prevent excessive .ll arguments from generating infinite output. + * Fix out of bounds accesses to parse buffers that could happen when + using renamed or user defined macros after roff(7) conditionals. + * Avoid an assertion failure in certain .Bl -column lists. + * Avoid a NULL pointer access on deroff() failure after '.SS ""'. + * Fix a segfault that could be triggered by two invalid .Dt macros. + * Fix two syntax errors in generated PDF files. + * Properly state the page size in generated PostScript files. + * Close a memory leak caused by missing gzclose(3). + * Fix misformatting of man(7) documents lacking .SH macros + in PostScript and PDF output. + * And many minor bugfixes. + --- THANKS TO --- + * Marc Espie (OpenBSD) for implementing the size reduction of + PostScript files, one additional patch for code simplification, + and two bug reports. + * Theo Buehler (OpenBSD) for a bugfix patch, + and Theo de Raadt (OpenBSD) for checking it. + * John Gardner for more than a dozen suggestions regarding HTML output. + * Mike Williams for teaching me how to use %%DocumentMedia and + setpagedevice in PostScript files. + * Werner Lemberg (groff) for feedback on mdoc(7) language changes. + * Colin Watson (man-db) for feedback on man-db semantics. + * Jason McIntyre (OpenBSD) for lots of feedback and suggestions + on diagnostic messages and on the documentation. + * Thomas Klausner (NetBSD) for suggesting two new style messages + and one new feature, for two bug reports, and for release testing. + * Leah Neukirchen (Void Linux) for suggesting a new style message, + five bug reports, and release testing. + * Anthony Bentley (OpenBSD) for reporting multiple bugs and missing + features. + * Paul Irofti (OpenBSD) and Nate Bargmann for suggesting new features. + * Michael Stapelberg (Debian) for bug reports and release testing. + * Christian Weisgerber, Jonathan Gray, Stuart Henderson, + Ted Unangst (OpenBSD), Takeshi Nakayama (NetBSD), + Anton Lazarov, Jakub Klinkovsky, Jan Stary, Jesper Wallin, + Will Backmam, and Wolfgang Mueller for bug reports. + * Sevan Janiyan (NetBSD) for additions to lib.in. + * George Brown for suggesting code simplifications. + * David Coppa, Igor Sobrado (OpenBSD), and Alexander Kuleshov + for documentation improvements. + * Laura Morales and Raf Czlonka for questions resulting in better + documentation. + * Yuri Pankov (illumos) for release testing. + +Changes in version 1.14.3, released on August 5, 2017 + + --- BUG FIXES --- + * man(7): Do not crash with out-of-bounds read access to a constant + array if .sp or a blank line immediately precedes .SS or .SH. + * mdoc(7): Do not crash with out-of-bounds read access to a constant + array if .sp or a blank line precede the first .Sh macro. + * tbl(7): Ignore explicitly specified negative column widths rather than + wrapping around to huge numbers and risking memory exhaustion. + * man(1): No longer use names that only occur in the SYNOPSIS section. + Gets rid of some surprising behaviour and bogus warnings. + --- THANKS TO --- + Leah Neukirchen (Void Linux), Markus Waldeck (Debian), + Peter Bui (nd.edu), and Yuri Pankov (illumos) for bug reports. + +Changes in version 1.14.2, released on July 28, 2017 + + --- MAJOR NEW FEATURES --- + * New mdoc(7) -Tmarkdown output mode. + * For -Thtml, implement internal hyperlinks pointing to authoritative + definitions of various syntax elements, similar to the ctags(1)-like + less(1) :t internal searching in terminal mode. + * Provide a superset of the functionality of the former mdoclint(1) + utility and a new -Wstyle message level with several new messages, + including validity checking of .Xr cross references. + * tbl(7): Implement automatic line breaking inside individual table + cells, and several other formatting improvements. + * eqn(7): Complete rewrite of the lexer, resulting in several bugfixes. + * Continue parser unification, in particular allowing generation + of syntax tree nodes on the roff(7) level, allowing implementation + of many additional roff requests. + --- REMOVED FUNCTIONALITY --- + * Delete the manpage(1) utility. It was never enabled in any release. + * Delete the -Txhtml command line option. It has been an obsolete + alias for the -Thtml output mode for more than two years. + --- MINOR NEW FEATURES --- + * -Tlint now puts parser messages on stdout instead of stderr, + making commands like "man -l -Tlint *.1" useful. + * mdoc(7): Various .Lk formatting improvements. + * mdoc(7) -Thtml: Better CSS for .Bl lists. + * man(7): Implement the .MT/.ME block macro (mailto hyperlink). + * man(7): Implement the .DT macro (restore default tab positions). + * man(7): Improved support for manuals generated with reStructuredText + by partial support for the \n[an-margin] number register. + * man(7) -Thtml: Support deep linking to .SH and .SS headers. + * tbl(7): Implement the "allbox" table option. + * tbl(7): Implement the column spacing and the 'w' (minimum column + width) layout modifiers. + * tbl(7): Significant improvements of the manual page. + * eqn(7): Much improved font selection, including recognition of + well-known function names, and a few other formatting improvements. + * eqn(7) -Thtml: Use and in addition to . + * roff(7): Implement the .ce (centering), .mc (margin character), + .rj (right justify), .ta (define tab stops), .ti (temporary indent), + .als (macro alias), .ec and .eo (escape character control), + .po (page offset), and .rn (macro rename) requests. + * roff(7) .am: Implement appending to mdoc(7) and man(7) macros. + * roff(7): implement the \h (horizontol motion), \l (horizontal + line drawing), and \p (break output line) escape sequences, + and also several additional character escape sequences. + * roff(7): Implement the 'd' conditional (macro or string defined). + * man.cgi(8) now uses pledge(2), too. + * regress.pl(1): simpler user interface, better summary output, + simpler code, and no more recursion. + --- THANKS TO --- + * Anthony Bentley (OpenBSD) for the implementation of .MT/.ME, + reports of many bugs and missing features, and suggestions + for a number of feature and documentation improvements. + * Sebastien Marie (OpenBSD) for two source code patches and + for some useful discussions. + * Florian Obser (OpenBSD) for a bugfix patch and a bug report. + * Jonathan Gray (OpenBSD) for several bug reports from afl(1) + and several more from static analysis tools. + * Theo Buehler (OpenBSD) for several bug reports, most from afl(1). + * Jason McIntyre (OpenBSD) for many useful discussions about a + wide variety of topics, lots of continuous testing, a number of + bug reports, and some suggestions for messages and documentation. + * Thomas Klausner (NetBSD) for lots of help while migrating + mdoclint(1) functionality to mandoc -Tlint, for suggesting + several useful new messages, and for release testing. + * Reyk Floeter (OpenBSD) and Vsevolod Stakhov (FreeBSD) for + suggesting a markdown output mode. + * Thomas Guettler for suggesting -Thtml internal hyperlinks. + * Yuri Pankov (Illumos) for inspiring new warning messages and + for extensive release testing. + * Anton Lindqvist and TJ Townsend (both OpenBSD) and Jan Stary + for multiple bug reports. + * Leah Neukirchen (Void Linux) for bug reports and release testing. + * Michael Stapelberg (Debian) for suggesting feature improvements + and for release testing. + * Martin Natano and Theo de Raadt (both OpenBSD), Andreas Voegele, + Gabriel Guzman, Gonzalo Tornaria, Markus Waldeck, and Raf Czlonka + for bug reports. + * Antoine Jacoutot (OpenBSD) and Steffen Nurpmeso for suggesting + feature improvements. + * Dag-Erling Smoergrav (FreeBSD) for inspiring new warning messages. + * Ted Unangst and Marc Espie (OpenBSD) for providing useful ideas. + * Svyatoslav Mishyn (Crux Linux) for release testing. + * Carsten Kunze (Heirloom roff) for help keeping mandoc and groff + compatible and for committing some of my patches to groff. + +Changes in version 1.14.1, released on February 21, 2017 + + --- MAJOR NEW FEATURES --- + * apropos(1): Reimplement complete semantic search functionality + without the dependency on SQLite3, using only POSIX APIs. + This comes with a completely new mandoc.db(5) file format. + * man(1): Support more than one tag entry for the same search term, + plus some minor improvements to the less(1) :t support. + * -Thtml: Use real macro names for CSS classes. + Systematic cleanup of and many improvements to mandoc.css. + * -Thtml: Produce human readable HTML code by using indentation + and better line breaks. Improve various HTML elements, + and trim several useless ones. + * New catman(8) utility, still somewhat experimental. + * Now includes a portable version of the OpenBSD mandoc regression + suite, see regress/regress.pl.1 for details. + --- REMOVED FUNCTIONALITY --- + * Operating systems that don't provide mmap(3) are no longer supported. + * Drop support for manpath(1). Even if your system has manpath(1), + it is simpler to use MANPATH_DEFAULT in configure.local for + operating system defaults, man.conf(5) for machine-specific + modifications, and ${MANPATH}, -m, and -M for user preferences + than to bother with the complexity of manpath(1). + * makewhatis(8) -p: No longer warn about missing MLINKS since these + are no longer needed for anything. + --- MINOR NEW FEATURES --- + * mdoc(7): Warn about invalid punctuation and content below NAME. + * mdoc(7): Warn about .Xr lacking the second argument (section). + * mdoc(7): Warn about violations of the rule "new sentence, new line". + * roff(7): Warn about trailing whitespace at the end of comments. + * mdoc(7): Improve rendering of double quotes. + * mdoc(7): Always do text production in the validator, never in the + formatters. Cleaner, simpler, shorter, helps NetBSD apropos(1) + and also makes -Ttree output more useful. + * -Ttree: Show metadata and some additional node flags. + New -Onoval output option to show the unvalidated tree. + --- RELIABILITY BUGFIXES --- + * man(1): Make "man -l" work with standard input from a pipe or file, + as long as standard output is a terminal. + * man(7): Fix out of bounds read access if a text node immediately + preceded the first .SH header. + * mdoc(7): Fix out of bounds read access for .Bl without a type + but with a width. + * mdoc(7): Fix out of bounds read access for .Bl -column starting + with a tab character instead of a child .It macro. + * mdoc(7): Fix syntax tree corruption leading to segfaults caused + by stray block end macros in nested blocks of mismatching type. + * man(1): Fix NULL dereference when the first of multiple pages + shown was preformatted. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + caused by partial implicit macros inside .Bl -column table cells. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + for macro sequences like .Bl .Bl .It Bo .El .It. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + caused by .Ta following a nested .Bl -column breaking another block. + * mdoc(7): Fix syntax tree corruption sometimes leading to NULL + dereference caused by indirectly broken .Nd or .Nm blocks. + * mdoc(7) -Thtml: Fix a NULL dereference for .Bl -column with 0 columns. + * mdoc(7): Fix NULL dereference in some specific cases of a + block-end macro calling another block-end macro. + * mdoc(7): Fix NULL dereference if the only child of the head + of the first .Sh was an empty in-line macro. + * eqn(7): Fix NULL dereference in the terminal formatter + for empty matrices and empty square roots. + * mdoc(7): Fix an assertion failure for a .Bd without a type that + breaks another block. + * mdoc(7): Fix an assertion failure that happened for some .Bl -column + lists containing a column width of "-4n", "-3n", or "-2n". + * mdoc(7): Fix an assertion failure caused by .Bl -column without .It + but containing eqn(7) or tbl(7) code. + * roff(7): Fix an assertion failure caused by \z\[u00FF] with -Tps/-Tpdf. + * roff(7): Fix an assertion failures caused by whitespace inside \o'' + (overstrike) sequences. + * -Thtml: Fix an assertion failure caused by -Oman or -Oincludes of + excessive length. + --- PORTABILITY IMPROVEMENTS --- + * man(1): Do not mix stdio narrow and wide stream orientation + on stdout, which could cause output corruption on glibc. + * mandoc(1): Autodetect a suitable locale for -Tutf8 mode. + * ./configure: Autodetect whether PATH_MAX and O_DIRECTORY are defined. + * ./configure: Autodetect if nanosleep(3) needs -lrt. + * ./configure: Provide an ${LN} configuration variable. + * ./configure: Put compiler arguments that may contain -l at the end. + --- MINOR BUGFIXES --- + * mdoc(7): Fix SYNOPSIS output if the first child of .Nm is a macro. + * mdoc(7) -Thtml: Improve formatting of .Bl -tag with short tags. + * man(7) -Thtml: Preserve whitespace in .nf (nofill) mode. + * mandoc(1): Error out on invalid output options on the command line. + --- STRUCTURAL CHANGES, no functional change --- + * Redesign part of the mandoc_html(3) interfaces, making them much + easier to use and reducing the amount of code by a few hundred lines. + --- THANKS TO --- + * Michael Stapelberg (Debian) for designing the new mandocd(8) + and parts of the new catman(8), for release testing, and for a + number of patches and bug reports. + * Baptiste Daroussin (FreeBSD) for profiling the new makewhatis(8) + implementation and suggesting an algorithmic improvement which + more than doubled performance, and for a few bug reports. + * Ed Maste (FreeBSD) for an important patch improving reproducibility + of builds in makewhatis(8), and for a few bug reports. + * Theo Buehler (OpenBSD) for almost twenty important bug reports, + most of them found by systematic afl(1) fuzzing. + * Benny Lofgren, David Dahlberg, and in particular Vadim Zhukov + for crucial help in getting .Bl -tag CSS formatting fixed. + * Svyatoslav Mishyn (Crux Linux) for an initial version of the + patch to autodetect a suitable locale for -Tutf8 mode + and for release testing. + * Jason McIntyre (OpenBSD) for multiple useful discussions + and a number of bug reports. + * Sevan Janiyan (NetBSD) for extensive release testing and multiple + bug reports. + * Thomas Klausner and Christos Zoulas (NetBSD), Yuri Pankov (illumos), + and Leah Neukirchen (Void Linux) for release testing and bug reports. + * Ulrich Spoerlein (FreeBSD) for release testing. + * Alexander Bluhm, Andrew Fresh, Antoine Jacoutot, Antony Bentley, + Christian Weisgerber, Jonathan Gray, Marc Espie, Martijn van Duren, + Stuart Henderson, Ted Unangst, Theo de Raadt (OpenBSD), Abhinav + Upadhyay, Kamil Rytarowski (NetBSD), Aaron M. Ucko, Bdale Garbee, + Reiner Herrmann, Shane Kerr (Debian), Daniel Sabogal (Alpine Linux), + Carsten Kunze (Heirloom roff), Kristaps Dzonsons (bsd.lv), + Anton Lindqvist, Jan Stary, Jeremy A. Mates, Mark Patruck, + Pavan Maddamsetti, Sean Levy , and + Tiago Silva for bug reports. + * Brent Cook, Marc Espie, Philip Guenther, Todd Miller (OpenBSD) + and Markus Waldeck for useful discussions. + * And as usual, OpenCSW for providing me with a Solaris 9/10/11 + testing environment. + +Changes in version 1.13.4, released on July 14, 2016 + + --- MAJOR NEW FEATURES --- + * man.conf(5): Design and implement a simpler configuration file format. + * man(1): Leverage less(1) -T and :t in a way resembling ctags(1) + to jump to the definitions of various terms inside manual pages. + * soelim(1): New implementation by Baptiste Daroussin. + * privilege limitation: Use OpenBSD pledge(2) or OS X sandbox_init(3) + when available. + * man.cgi(8): Support short URIs like http://man.openbsd.org/mdoc . + * mandoc.css: Use one unified stylesheet rather than three different ones. + --- MAJOR FUNCTIONALLY RELEVANT BUGFIXES --- + * mdoc(7): Fix multiple aspects of SYNOPSIS .Nm formatting. + * man(1): Fix process group handling, avoiding unclean shutdowns. + --- PORTABILITY IMPROVEMENTS --- + * Correctly use the ohash(3) compatibility implementation + even when building without SQLite support. + * Add compat glue for building on Solaris 9 and 10. + * Let ./configure select a supported RE syntax for word boundaries. + * Support LDFLAGS, to be used for example for hardening options. + * Avoid mixing putchar(3) and putwchar(3) on the same file descriptor, + it resulted in output corruption on some platforms. + * Avoid reusing va_lists, use va_copy(3) for better portability. + * Do not hardcode the path to the more(1) program. + --- MINOR NEW FEATURES --- + * roff(7): Implement \n(.$ (number of macro arguments). + * roff(7): Fully implement \z (do not advance cursor). + * roff(7): Implement the `r' conditional (register exists). + * roff(7): Implement \\$* (interpolate all arguments). + * roff(7): Parse and ignore \, and \/ (italic corrections). + * When there is no -m, no -M, no MANPATH and no /etc/man.conf, + fall back to /usr/share/man:/usr/X11R6/man:/usr/local/man. + * man(1): Give manuals in purely numerical sections priority over + manuals of the same name in sections with an alphabetical suffix. + * man.cgi(8): Support "header.html" and "footer.html". + * man.cgi(8): Set the "autofocus" attribute on the query text box. + * man.cgi(8): Simplify the search form, drop two useless buttons. + * man.cgi(8): Delete the pseudo-manpath "mandoc", assume that + apropos(1) and man.cgi(8) are installed in the default manpath. + --- RELIABILITY BUGFIXES --- + * mdoc(7): Avoid a use after free and an assertion failure when nodes + are deleted during validation. + * mdoc(7): Avoid a NULL pointer access when .Bd has no arguments. + * mdoc(7): Avoid a NULL pointer access triggered by mismatching end macros. + * mdoc(7): Avoid an assertion when .Fo has no argument. + * mdoc(7): Avoid an assertion when .Ta occurs in .Bl -column. + * mdoc(7): Avoid an assertion when a body gets broken and has a tail. + * roff(7): Avoid an assertion caused by blanks inside \o. + * roff(7): Make .so links to gziped manuals work without mandoc.db(5). + * tbl(7): Avoid a use after free when the last line of a layout is empty. + * eqn(7): Avoid an infinite loop caused by recursive "define". + * makewhatis(8): Avoid a segfault caused by unusual directory structures. + * Fix handling of leading, trailing, and double colons in MANPATH and -m. + --- MINOR BUGFIXES --- + * mdoc(7): Put arguments to end macros of broken partial explicit blocks + inside the breaking block. + * mdoc(7): Let .Dv force normal font. + * mdoc(7): Make trailing whitespace significant in .Bl -tag widths. + * mdoc(7): Fix macro interpretation around tabs in .Bl -column. + * man(7): Use the default width for .RS without arguments. + * man(7): On a new RS nesting level, the saved width starts from + the default width, not from the saved width of the previous level. + * man(7): Allow .PD in next-line scope. + * man(7): Improve handling of empty .HP. + * man(7): Improve formatting of .br and .sp inside .HP. + * man(7): Do not mistreat empty arguments to font alternating + macros as vertical spacing requests. + * man(7): Allow fill mode changes in tagged paragraph next-line scope. + * man(7): Fix minor bugs in block rewinding and simplify the related code. + * man(7): Add missing line breaks before subsection headers. + * man(7): Give section and subsection headers hanging indentation. + * man(7): Make trailing whitespace significant in .TP widths. + * roff(7): Don't allow breaking the output line after hyphens + that immediately follow escape sequences. + * roff(7): Ignore blank characters at the beginning of conditional blocks. + * roff(7): Escape breakable hyphens only after handling input line traps. + * roff(7): Reject \[uD800] to \[uDFFF] (surrogates) in the parser. + * tbl(7): Allow more than one data field after T} on the same input line. + * terminal output: Apply bold and italic to non-ASCII Unicode codepoints. + * terminal output: Improve rounding rules for horizontal scaling widths. + * HTML output: Render ASCII_NBRSP as " ", not "-". + * man(1): Do not match the first part of a name if it continues with a dot. + * man(1): Keep working even if the current directory is unusable. + * man(1): Better error message when $PAGER is invalid. + * makewhatis(8): Improve handling of .Va and .Vt macros. + * apropos(1): Print "nothing appropriate" to stderr when appropriate. + * apropos(1): Abort with a useful error message when elementary + database operations like preparing queries or binding variables fail. + --- STRUCTURAL CHANGES, no functional change --- + * mdoc(7) and man(7): Unified data structures struct roff_node etc. + * mdoc(7) and man(7): Unified node handling library in roff.c. + * mdoc(7) and man(7): Seperate validation phase from parsing. + * roff(7): Major character table cleanup. + * Link with libz rather than forking gunzip(1). + --- THANKS TO --- + * Baptiste Daroussin (FreeBSD) for the new soelim(1) + and for release testing. + * Anthony Bentley (OpenBSD) for unifying mandoc.css, two nice + patches for man.cgi(8), some documentation patches, some bug + reports, and various useful discussions. + * Todd Miller (OpenBSD) for lots of help with process group and + signal handling, a few patches, some bug reports and some useful + discussions. + * Jonathan Gray (OpenBSD) for yet more testing with afl(1) + again resulting in more than half a dozen important bug reports. + * Svyatoslav Mishyn (Crux Linux) for some patches, several bug + reports, and extensive release testing. + * Leah Neukirchen (Void Linux) for a number of compatibility + patches and suggestions and several bug reports. + * Christos Zoulas (NetBSD) for a bug fix patch and some useful + suggestions for cleanup. + * Florian Obser (OpenBSD) for a bugfix patch and some bug reports. + * Sevan Janiyan for help with Solaris compatibility and release + testing on many platforms. + * Jan Holzhueter and OpenCSW in general for help with Solaris + compatibility, and for providing me with a Solaris 9/10/11 testing + environment. + * Michael McConville (OpenBSD) for some simple cleanup patches. + * Thomas Klausner (NetBSD) for some bug reports and release testing. + * Christian Weisgerber, Dmitrij Czarkoff, Igor Sobrado, + Ken Westerback, Marc Espie, Mike Belopuhov, Rafael Neves, + Ted Unangst, Tim van der Molen, Theo Buehler, Theo de Raadt + (OpenBSD), Kurt Jaeger, Dag Erling Smoergrav (FreeBSD), + Joerg Sonnenberger (NetBSD), Carsten Kunze (Heirloom troff), + Daniel Levai, Fabian Raetz, Jan Stary, Jean-Yves Migeon, + Lorenzo Beretta, Markus Waldeck, Maxim Belooussov, Michael Reed, + Peter Bray, and Serguey Parkhomovsky for bug reports and feature + suggestions. + * Alexander Hall, Andrew Fresh, Antoine Jacoutot, Doug Hogan, + Jason McIntyre, Jasper Lievisse Adriaanse, Kent Spillner, + Nicholas Marriott, Peter Hessler, Sebastien Marie, Stefan Sperling, + and Theo de Raadt (OpenBSD) for helpful discussions and feedback. + +Changes in version 1.13.3, released on March 13, 2015 + + --- MAJOR NEW FEATURES --- + * When a manual is missing from an outdated database, let man(1) + show it anyway, using a KISS file system lookup as a fallback. + * Use this to always provide man(1), even without database support. + * Fatal errors no longer exist. If a file can be opened, mandoc + will produce some output; at worst, the output may be almost empty. + * New -Wunsupp message level. + --- POTENTIONALLY SECURITY RELEVANT BUGFIXES --- + * Fix a potential write buffer overrun on incomplete string conditionals. + http://mandoc.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.241 + * Fix a potential write buffer overrun on backslash at EOF in a conditional. + http://mandoc.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.247 + * Fix a use after free sometimes hit when validation deletes a block. + http://mandoc.bsd.lv/cgi-bin/cvsweb/mdoc_macro.c#rev1.180 + --- MAJOR FUNCTIONALLY RELEVANT BUGFIXES --- + * Let man(1) show manuals for the current architecture by default, + and support the MACHINE environment variable. + * Fix the man(1) and apropos(1) -m option, it didn't work at all. + * Do not spawn a pager when there is no output. + * In makewhatis(8), fix detection of hardlinked manuals on platforms + having padding in struct inodev (typically 64bit platforms). + --- PORTABILITY IMPROVEMENTS --- + * Ignore O_CLOEXEC when the operating system doesn't provide it. + * Avoid forward reference to enum type which violates ISO C99. + * Support homebrew-style linking on Mac OS X. + --- MINOR NEW FEATURES --- + * lookup: Accept digit+letter and "n" as section names in man(1), + and consistently handle digit+letter in file name extensions. + * lookup: Speed up -s/-S by using the "mlinks" rather than the "keys" table. + * output: Insert horizontal lines between formatted manual pages. + * input: New stricter and more resilient UTF-8 parser. + * mdoc(7): Refactor block rewinding for simpler and more robust parsing. + * man(7): Use the -Ios option when .TH has less than four arguments. + * tbl(7): Implement the "center" option. + * tbl(7): New option and format parsers, improved in many respects. + * roff(7): Basic implementation of the \o escape sequence (overstrike), + and improved rendering of overstrikes in PostScript and PDF output. + * Message improvements, in particular for, but not restricted to, + eqn(7), tbl(7), and wrong numbers of arguments in mdoc(7) and man(7), + in various cases also improving output generated by invalid input. + * Delete the -V option. It serves no purpose but keeps confusing people. + * gmdiff: Minimal support for Heirloom roff. + --- RELIABILITY BUGFIXES --- + * tbl(7): Fix a read buffer overrun on 'f' at EOL in a layout. + * roff(7): Fix a read buffer overrun on incomplete numerical conditions. + * mdoc(7): Fix a NULL pointer access on .Nd followed by an explicit block. + * mdoc(7): Fix a NULL pointer access on .It Xo without .Xc. + * mdoc(7): Fix a NULL pointer access on .Eo without a tail. + * mdoc(7): Fix a NULL pointer access in the validation of empty .St macros. + * man(7)/tbl(7): Fix a NULL pointer access on .TS right after .TP. + * tbl(7): Fix a NULL pointer access on layout lines without any cells. + * eqn(7): Fix NULL pointer accesses in the terminal formatter. + * roff(7): Fix a NULL pointer access on trailing \s-/\s+ without an argument. + * gz: Fix a potential NULL pointer access after waitpid() failure. + * roff(7): Don't let the modulo operator divide by zero. + * input: Fix an assertion failure on certain invalid UTF-8 input. + * terminal output: Allow arbitrary depth of the font stack (assertion fix). + * mdoc(7): Fix assertion failures and endless loops on invalid block closing. + * mdoc(7): Fix an assertion failure on .Bl .Sm not followed by .It. + * mdoc(7): Fix an assertion failure on .Bl -column ... .El .Ta. + * tbl(7): Fix assertion failures by macros inside table data, + but do not throw away the macro arguments. + * Prevent certain kinds of unreasonable input from producing excessive + output, in one case caused by unsigned integer underflow. + * Fix a potential memory leak in makewhatis(8) on very long filenames. + --- MINOR BUGFIXES --- + * mdoc(7): Fix parsing of badly nested blocks with multiple identical blocks. + * mdoc(7): Support negative indentations for displays and lists. + * mdoc(7): Don't mistreat negative .sp arguments as large positive ones. + * mdoc(7): Some spacing fixes for .Eo/.Ec. + * man(7): Support negative horizontal widths. + * man(7): Do not print out invalid .IP arguments. + * man(7): Correctly handle scaling units after .PD. + * man(7): Support .RE with an argument. + * man(7): Fix restoring indentation after .RS with large negative arguments. + * tbl(7): Prevent tables from breaking the filling of preceding text. + * tbl(7): Fix vertical spacing at the beginning of tables. + * tbl(7): Parser and formatter fixes for line drawing and font modifiers. + * tbl(7): Correct handling of blank data lines. + * eqn(7): Add sometimes missing whitespace before equation output. + * roff(7): Fix vertical scaling, most of it was wrong. + * roff(7): Slightly improve \w width measurements. + * roff(7): Accept the historic aliases \s10 to \s39 for \s(10 to \s(39. + * roff(7): Correctly escape quotes when expanding macro arguments. + * roff(7): Correctly handle scaling units in numerical expressions, + and some other improvements to the parsing of numerical expressions. + * roff(7): Three minor fixes with respect to evaluation of conditionals. + * roff(7): Let .it accept numerical expressions, not just constants. + * mandoc_char(7): Correct some character names and renderings. + * If earlier files set a non-zero exit status, never reset it to zero. + --- THANKS TO --- + * Jonathan Gray (OpenBSD) for yet more testing with afl (the American + Fuzzy Lop security fuzzer), again resulting in many bug reports. + * Theo de Raadt (OpenBSD) for suggesting the main new feature (man(1) file + system lookup) and for reporting an important bug (pager without output). + * Theo Buehler for an important bug report (-s/-S slowness) + and for proposing a nice new feature (lines between pages). + * Jason McIntyre for an important bug report (hardlink detection) + and multiple documentation patches. + * Pascal Stumpf (OpenBSD) and Alessandro de Laurenzis for + important bug reports (architecture and man -m, respectively). + * Thomas Klausner (NetBSD) for proposing a new feature (man(7) -Ios), + a bug report, and release testing. + * Anthony Bentley, Daniel Dickman, Ted Unangst (OpenBSD) and + Kristaps Dzonsons (bsd.lv) for source code patches and bug reports. + * Christian Weisgerber (OpenBSD) for more than half a dozen bug reports. + * Carsten Kunze (Heirloom troff) for bug reports and release testing. + * Antoine Jacoutot (OpenBSD) for release testing. + * Alexis Hildebrandt (Homebrew), Baptiste Daroussin (FreeBSD), + Jonathan Perkin (SmartOS), Pedro Giffuni (FreeBSD), Svyatoslav + Mishyn (Crux Linux), Ulrich Spoerlein (FreeBSD), Jan Stary, Patrick + Keshishian, Sebastien Marie, and Steffen Nurpmeso for bug reports. + +Changes in version 1.13.2, released on December 13, 2014 + + --- MAJOR NEW FEATURES --- + * Include an implementation of man(1), the manual page viewer. + * Unified set of command line option, each one supported by all + command names, including new options -a (format all), -c (no + pager), -h (synopsis only), and -w (list filenames). + * Support the MANPAGER and PAGER environment variables. + * Support gzip'ed manuals by the whole toolset, even as .so targets. + * Support UTF-8 and Latin-1 input by the whole toolset, delete preconv(1). + * Switch the default output mode from -Tascii to -Tlocale. + * Improve -Tascii output for Unicode escape sequences. + * Let the -Thtml output mode produce polyglot HTML5. + * Many improvements for eqn(7), in particular in-line equations, + MathML output in -Thtml mode, and much improved terminal formatting. + --- PORTABILITY IMPROVEMENTS --- + * Change the build sequence to the usual ./configure; make; make install. + * Support ./configure.local for build customizations. + * Autodetect wchar, sqlite3, and manpath support. + * Provide a fallback version of fts(3) for systems lacking it. + * Support choosing alternative binary and manual names. + --- MINOR NEW FEATURES --- + * Rudimentary implementation of the e, x, and z tbl(7) layout + modifiers to equalize, maximize, and ignore the width of columns. + * Implement font modifiers in tbl(7) layouts. + * Allow comma-separated options in the tbl(7) options line. + * Parse and ignore the .pl (page length) roff(7) request. + * Implement .An -[no]split for the mdoc(7) -Thtml output mode. + * Support bold italic font in PostScript and PDF output. + * Warn about commas in function arguments and parentheses in function names. + * Warn about botched .Xr ordering and punctuation below SEE ALSO. + * Warn about AUTHORS sections without .An macros. + * Warn about attempts to call non-callable macros. + * New developer documentation manual page mandoc_headers(3). + --- BUGFIXES --- + * Fix read buffer overrun sometimes triggered by trailing whitespace. + * Fix read buffer overrun triggered by certain invalid \H sequences. + * Fix NULL pointer access triggered by .Bl without any arguments. + * Fix NULL pointer access triggered by .It Nm Fo without .Fc. + * Fix NULL pointer access triggered by .Sh Xo .Sh without .Xc. + * Fix NULL pointer access triggered by missing .Nm. + * Fix an assertion triggered by .It right after .El. + * Fix an assertion triggered by .Ec without preceding .Eo. + * Fix an assertion triggered by .Sm or .Db with multiple arguments. + * Fix assertion failures triggered by very large width arguments. + * Fix a division by zero in the roff(7) parser. + * Prevent negative arguments to .ll from causing integer underflow. + * Correctly autodetect source format even when .Dd is preceded by .ll. + * Multiple fixes with respect to .Bd and .Bl -offset and -width. + * Many bugfixes with respect to scaling units. + * Multiple fixes with respect to delimiter handling by in-line macros. + * Multiple fixes with respect to .Pf. + * Make \c work properly in no-fill mode. + * Stricter syntax checking of Unicode character names. + --- THANKS TO --- + * Kristaps Dzonsons for rewriting the eqn(7) parser, implementing + HTML5 and MathML output, and various other code contributions. + * Jonathan Gray (OpenBSD) for extensive testing with afl (the + American Fuzzy Lop security fuzzer) resulting in many bug reports. + * Anthony Bentley (OpenBSD), Baptiste Daroussin (FreeBSD), Daniel + Dickman, Doug Hogan, Jason McIntyre, Theo de Raadt (OpenBSD), + and Martin Natano for source code patches. + * Carsten Kunze (Heirloom troff), Daniel Levai (Slackware), + Garrett D'Amore (illumos), Giovanni Becchis, Matthew Dempsky, + Stuart Henderson, Ted Unangst, Todd Miller (OpenBSD), Thomas + Klausner (NetBSD), Ulrich Spoerlein (FreeBSD), Justin Haynes, + Marcus Merighi, Sebastien Marie, Steffen Nurpmeso and Theo Buehler + for bug reports. + +Changes in version 1.13.1, released on August 10, 2014 + + --- MAJOR NEW FEATURES --- + * A complete apropos(1)/makewhatis(8)/man.cgi(8) suite + based on SQLite3 is now included. + * The roff(7) parser now provides an almost complete implementation + of numerical expressions. + * Warning and error messages have been improved in many ways. + Almost all fatal errors were downgraded to normal errors and some + even to warnings. Almost all messages now mention the macro where + the issue is detected and many indicate the workaround employed. + The mandoc(1) manual now includes a list explaining all messages. + --- MINOR NEW FEATURES --- + * The roff(7) parser now supports the .ami (append to macro with + indirectly specified name), .as (append to user-defined + string), .dei (define macro with indirectly specified name), + .ll (line length), and .rr (remove register) requests. + * The roff(7) parser now supports string comparison and numerical + conditionals in the .if and .ie requests. + * The roff parser now fully supports the \B (validate numerical + expression) and partially supports the \w (measure text width) + escape sequences. + * The terminal formatter now supports the \: (optional line break) + escape sequence. + * The roff parser now supports expansion of user-defined strings + involving indirect references. + * The roff(7) parser now handles some pre-defined read-only + number registers that occur in the pod2man(1) preamble. + * For backward compatibility, the mdoc(7) parser and formatters + now support the obsolete macros .En, .Es, .Fr, and .Ot. + * The mdoc(7) formatter non partially supports .Bd -centered. + * tbl(7) now handles leading and trailing vertical lines. + * The build system now provides fallback versions of strcasestr(3) + and strsep(3) for systems lacking them. + * The mdoc(7) manual now explains how various standards + supported by the .St macro are related to each other. + --- BUGFIXES --- + * In the roff(7) parser, several bugs were fixed with respect + to closing conditional blocks on macro lines. + * Parsing of roff(7) identifiers and escape sequences was improved + in multiple respects. + * In the mdoc(7) parser, the handling of defective document + prologues was improved in multiple ways. + * The mdoc(7) parser no longer skips content before the first section + header, and it no longer deletes non-.% content from .Rs blocks. + * In the mdoc(7) parser, a crash was fixed related to weird .Sh headers. + * In the mdoc(7) parser, handling of .Sm with missing or invalid + arguments was corrected. + * In the mdoc(7) parser, trailing punctuation at the end of partial + implicit macros no longer triggers end-of-sentence spacing. + * In the terminal formatter, two crashes were fixed: one triggered by + excessive indentation and another by excessively long .Nm arguments. + * In the terminal formatter, a floating point rounding bug was + fixed that sometimes caused an off-by-one error in indentation. + * In the UTF-8 formatter, rendering of accents, breakable hyphens, + and non-breakable spaces was corrected. + * In the HTML formatter, encoding of special characters was + corrected in multiple respects. + * In the mdoc(7) formatter, rendering of .Ex and .Rv was + improved for various edge cases. + * In the mdoc(7) formatter, handling of empty .Bl -inset item + heads was improved. + * In the man(7) formatter, some bugs were fixed with respect + to same-line detection in the context of .TP and .nf macros, + and the indentation of .IP and .TP blocks was improved. + * The mandoc(3) library no longer prints to stderr. + --- THANKS TO --- + Abhinav Upadhyay (NetBSD), Andreas Voegele, Anthony Bentley (OpenBSD), + Christian Weisgerber (OpenBSD), Havard Eidnes (NetBSD), Jan Stary, + Jason McIntyre (OpenBSD), Jeremie Courreges-Anglas (OpenBSD), + Joerg Sonnenberger (NetBSD), Juan Francisco Cantero Hurtado (OpenBSD), + Marc Espie (OpenBSD), Matthias Scheler (NetBSD), Pascal Stumpf (OpenBSD), + Paul Onyschuk (Alpine Linux), Sebastien Marie, Steffen Nurpmeso, + Stuart Henderson (OpenBSD), Ted Unangst (OpenBSD), Theo de Raadt (OpenBSD), + Thomas Klausner (NetBSD), and Ulrich Spoerlein (FreeBSD) + for reporting bugs and missing features. + +Changes in version 1.12.3, released on December 31, 2013 + + * In the mdoc(7) SYNOPSIS, line breaks and hanging indentation + now work correctly for .Fo/.Fa/.Fc and .Fn blocks. + Thanks to Franco Fichtner for doing part of the work. + * The mdoc(7) .Bk macro got some addititonal bugfixes. + * In mdoc(7) macro arguments, double quotes can now be quoted + by doubling them, just like in man(7). + Thanks to Tsugutomo ENAMI for the patch. + * At the end of man(7) macro lines, end-of-sentence spacing + now works. Thanks to Franco Fichtner for the patch. + * For backward compatibility, the man(7) parser now supports the + man-ext .UR/.UE (uniform resource identifier) block macros. + * The man(7) parser now handles closing blocks that are not open + more gracefully. + * The man(7) parser now ignores blank lines right after .SH and .SS. + * In the man(7) formatter, reset indentation when leaving a block, + not just when entering the next one. + * The roff(7) .nr request now supports incrementing and decrementing + number registers and stops parsing the number right before the + first non-digit character. + * The roff(7) parser now supports the alternative escape sequence + syntax \C'uXXXX' for Unicode characters. + * The roff(7) parser now parses and ignores the .fam (font family) + and .hw (hyphenation points) requests and the \d and \u escape + sequences. + * The roff(7) manual got a new ESCAPE SEQUENCE REFERENCE. + +Changes in version 1.12.2, released on Oktober 5, 2013 + + * The mdoc(7) to man(7) converter, to be called as mandoc -Tman, + is now fully functional. + * The mandoc(1) utility now supports the -Ios (default operating system) + input option, and the -Tutf8 output mode now actually works. + * The mandocdb(8) utility no longer truncates existing databases when + starting to build new ones, but only replaces them when the build + actually succeeds. + * The man(7) parser now supports the PD macro (paragraph distance), + and (for GNU man-ext compatibility only) EX (example block) and EE + (example end). Plus several bugfixes regarding indentation, line + breaks, and vertical spacing, and regarding RS following TP. + * The roff(7) parser now supports the \f(BI (bold+italic) font escape, + the \z (zero cursor advance) escape and the cc (change control + character) and it (input line trap) requests. Plus bugfixes regarding + the \t (tab) escape, nested escape sequences, and conditional requests. + * In mdoc(7), several bugs were fixed related to UTF-8 output of quoting + enclosures, delimiter handling, list indentation and horizontal and + vertical spacing, formatting of the Lk, %U, and %C macros, plus some + bugfixes related to the handling of syntax errors like badly nested + font blocks, stray Ta macros outside column lists, unterminated It Xo + blocks, and non-text children of Nm blocks. + * In tbl(7), the width of horizontal spans and the vertical spacing + around tables was corrected, and in man(7) files, a crash was fixed + that was triggered by some particular unclosed T{ macros. + * For mandoc developers, we now provide a tbl(3) library manual and + gmdiff, a very small, very simplistic groff-versus-mandoc output + comparison tool. + * Provide this NEWS file. + +Changes in version 1.12.1, released on March 23, 2012 + + * Significant work on apropos(1) and mandocdb(8). These tools are now + much more robust. A whatis(1) implementation is now handled as an + apropos(1) mode. These tools are also able to minimally handle + pre-formatted pages, that is, those already formatted by another + utility such as GNU troff. + * The man.cgi(7) script is also now available for wider testing. + It interfaces with mandocdb(8) manuals cached by catman(8). + HTML output is generated on-the-fly by libmandoc or internal + methods to convert pre-formatted pages. + * The mailing list archive for the discuss and tech lists are being + hosted by Gmane at gmane.comp.tools.mdocml.user and + gmane.comp.tools.mdocml.devel, respectively. + +Changes in version 1.12.0, released on October 8, 2011 + + * This version features a new, work-in-progress mandoc(1) output mode: + -Tman. This mode allows a system maintainer to distribute man(7) + media for older systems that may not natively support mdoc(7), such + as old Solaris systems. + * The -Ofragment option was added to mandoc(1)'s -Thtml and -Txhtml modes. + * While adding features, an apropos(1) utility has been merged from the + mandoc-tools sandbox. This interfaces with mandocdb(8) for semantic + search of manual content. apropos(1) is different from the traditional + apropos primarily in allowing keyword search (such as for functions, + utilities, etc.) and regular expressions. Note that the calling + syntax for apropos is likely to change as it settles down. + * In documentation news, the mdoc(7) and man(7) manuals have been + made considerably more readable by adding MACRO OVERVIEW sections, by + moving the gory details of the LANGUAGE SYNTAX to the roff(7) manual, + and by moving the very technical MACRO SYNTAX sections down to the + bottom of the page. + * Furthermore, for tbl(7), the -Tascii mode horizontal spacing of tables + was rewritten completely. It is now compatible with groff(1), both + with and without frames and rulers. + * Nesting of indented blocks is now supported in man(7), and several + bugs were fixed regarding indentation and alignment. + * The page headers in mdoc(7) are now nicer for very long titles. + +Changes in version 1.11.7, released on September 2, 2011 + + * Added demandoc(1) utility for stripping away macros and escapes. + This replaces the historical deroff(1) utility. + * Also improved the mdoc(7) and man(7) manuals. + +Changes in version 1.11.6, released on August 16, 2011 + + * Handling of tr macro in roff(7) implemented. This makes Perl + documentation much more readable. Hyphenation is also now enabled in + man(7) format documents. Many other general improvements have been + implemented. + +Changes in version 1.11.5, released on July 24, 2011 + + * Significant eqn(7) improvements. mdocml can now parse arbitrary eqn + input (although few GNU extensions are accepted, nor is mixing + low-level roff with eqn). See the eqn(7) manual for details. + For the time being, equations are rendered as simple in-line text. + The equation parser satisfies the language specified in the + Second Edition User's Guide: + http://www.kohala.com/start/troff/v7man/eqn/eqn2e.ps + +Changes in version 1.11.4, released on July 12, 2011 + + * Bug-fixes and clean-ups across all systems, especially in mandocdb(8) + and the man(7) parser. This release was significantly assisted by + participants in OpenBSD's c2k11. Thanks! + +Changes in version 1.11.3, released on May 26, 2011 + + * Introduce locale-encoding of output with the -Tlocale output option and + Unicode escaped-character input. See mandoc(1) and mandoc_char(7), + respectively, for details. This allows for non-ASCII characters (e.g., + \[u5000]) to be rendered in the locale's encoding, if said environment + supports wide-character encoding (if it does not, -Tascii is used + instead). Locale support can be turned off at compile time by removing + -DUSE_WCHAR in the Makefile, in which case -Tlocale is always a synonym + for -Tascii. + * Furthermore, multibyte-encoded documents, such as those in UTF-8, may + be on-the-fly recoded into mandoc(1) input by using the newly-added + preconv(1) utility. Note: in the future, this feature may be + integrated into mandoc(1). + +Changes in version 1.11.2, released on May 12, 2011 + + * Corrected some installation issues in version 1.11.1. + * Further migration to libmandoc. + * Initial public release (this utility is very much under development) + of mandocdb(8). This utility produces keyword databases of manual + content, which features semantic querying of manual content. + +Changes in version 1.11.1, released on April 4, 2011 + + * The earlier libroff, libmdoc, and libman soup have been merged into + a single library, libmandoc, which manages all aspects of parsing + real manuals, from line-handling to tbl(7) parsing. + * As usual, many general fixes and improvements have also occurred. + In particular, a great deal of redundancy and superfluous code has + been removed with the merging of the backend libraries. + * see also the changes in 1.10.10 + +Changes in version 1.10.10, March 20, 2011, NOT released + + * Initial eqn(7) functionality is in place. For the time being, + this is limited to the recognition of equation blocks; + future version of mdocml will expand upon this framework. + +Changes in version 1.10.9, released on January 7, 2011 + + * Many back-end fixes have been implemented: argument handling (quoting), + man(7) improvements, error/warning classes, and many more. + * Initial tbl(7) functionality (see the "TS", "TE", and "T&" macros in + the roff(7) manual) has been merged from tbl.bsd.lv. Output is still + minimal, especially for -Thtml and -Txhtml, but manages to at least + display data. This means that mandoc(1) now has built-in support + for two troff preprocessors via libroff: soelim(1) and tbl(1). + +Changes in version 1.10.8, released on December 24, 2010 + + * Overhauled the -Thtml and -Txhtml output modes. They now display + readable output in arbitrary browsers, including text-based ones like + lynx(1). See HTML and XHTML manuals in the DOCUMENTATION section + for examples. Attention: available style-sheet classes have been + considerably changed! See the example.style.css file for details. + Lastly, libmdoc and libman have been cleaned up and reduced in size + and complexity. + * see also the changes in 1.10.7 + +Changes in version 1.10.7, December 6, 2010, NOT released + + Significant improvements merged from OpenBSD downstream, including: + * many new roff(7) components, + * in-line implementation of troff's soelim(1), + * broken-block handling, + * overhauled error classifications, and + * cleaned up handling of error conditions. + +Changes in version 1.10.6, released on September 27, 2010 + + * Calling conventions for mandoc(1) have changed: -W improved and -f + deprecated. + * Non-ASCII characters are also now uniformly discarded. + * Lots of documentation improvements. + * Many incremental fixes accomodating for groff's more interesting + productions. + * Lastly, pod2man(1) preambles are now fully accepted after some + considerable roff(7) and special character support. + +Changes in version 1.10.5, released on July 27, 2010 + + * Primarily a bug-fix and polish release, but including -Tpdf support + in mandoc(1) by way of "Summer of Code". Highlights: + * fix "Sm" and "Bd" handling + * fix end-of-sentence handling for embedded sentences + * polish man(7) documentation + * document all mdoc(7) macros + * polish mandoc(1) -Tps output + * lots of internal clean-ups in character escapes + * un-break literal contexts in man(7) documents + * improve -Thtml output for -man + * add mandoc(1) -Tpdf support + +Changes in version 1.10.4, released on July 12, 2010 + + * Lots of features developed during both "Summer of Code" and the + OpenBSD c2k10 hackathon: + * minimal "ds" roff(7) symbols are supported + * beautified SYNOPSIS section output + * acceptance of scope-block breakage in mdoc(7) + * clarify error message status + * many minor bug-fixes and formatting issues resolved + * see also changes in 1.10.3 + +Changes in version 1.10.3, June 29, 2010, NOT released + + * variable font-width and paper-size support in mandoc(1) -Tps output + * "Bk" mdoc(7) support + +Changes in version 1.10.2, released on June 19, 2010 + + * Small release featuring text-decoration in -Tps output, + a few minor relaxations of errors, and some optimisations. + +Changes in version 1.10.1, released on June 7, 2010 + + * This primarily focusses on the "Bl" and "It" macros described in + mdoc(7). Multi-line column support is now fully compatible with groff, + as are implicit list entries for columns. + * Removed manuals(7) in favour of http://manpages.bsd.lv. + * The way we handle the SYNOPSIS section (see the SYNOPSIS documentation + in MANUAL STRUCTURE) has also been considerably simplified compared + to groff's method. + * Furthermore, the -Owidth=width output option has been added to -Tascii, + see mandoc(1). + * Lastly, initial PostScript output has been added with the -Tps option + to mandoc(1). It's brutally simple at the moment: fixed-font, with no + font decorations. + +Changes in version 1.10.0, released on May 29, 2010 + + * Release consisting of the results from the m2k10 hackathon and up-merge + from OpenBSD. This requires a significant note of thanks to Ingo + Schwarze (OpenBSD) and Joerg Sonnenberger (NetBSD) for their hard work, + and again to Joerg for hosting m2k10. Highlights (mostly cribbed from + Ingo's m2k10 report) follow in no particular order: + * a libroff preprocessor in front of libmdoc and libman stripping out + roff(7) instructions; + * end-of-sentence (EOS) detection in free-form and macro lines; + * correct handling of tab-separated columnar lists in mdoc(7); + * improved main calling routines to optionally use mmap(3) for better + performance; + * cleaned up exiting when invoked as -Tlint or over multiple files + with -fign-errors; + * error and warning message handling re-written to be unified for + libroff, libmdoc, and libman; + * handling of badly-nested explicit-scoped macros; + * improved free-form text parsing in libman and libmdoc; + * significant GNU troff compatibility improvements in -Tascii, + largely in terms of spacing; + * a regression framework for making sure the many fragilities of GNU + troff aren't trampled in subsequent work; + * support for -Tascii breaking at hyphens encountered in free-form text; + * and many more minor fixes and improvements + +Changes in version 1.9.25, released on May 13, 2010 + + * Fixed handling of "\*(Ba" escape. + * Backed out -fno-ign-chars (pointless complexity). + * Fixed erroneous breaking of literal lines. + * Fixed SYNOPSIS breaking lines before non-initial macros. + * Changed default section ordering. + * Most importantly, the framework for end-of-sentence double-spacing is + in place, now implemented for the "end-of-sentence, end-of-line" rule. + * This is a stable roll-back point before the mandoc hackathon in Rostock! + +Changes in version 1.9.24, released on May 9, 2010 + + * Rolled back break-at-hyphen. + * -DUGLY is now the default (no feature splits!). + * Free-form text is not de-chunked any more: lines are passed + whole-sale into the front-end, including whitespace. + * Added mailing lists. + +Changes in version 1.9.23, released on April 7, 2010 + + * mdocml has been linked to the OpenBSD build. + * This version incorporates many small changes, mostly from patches + by OpenBSD, allowing crufty manuals to slip by with warnings instead + of erroring-out. + * Some subtle semantic issues, such as punctuation scope, have also + been fixed. + * Lastly, some issues with -Thtml have been fixed, which prompted an + update to the online manual pages style layout. + +Changes in version 1.9.22, released on March 31, 2010 + + * Adjusted merge of the significant work by Ingo Schwarze + in getting "Xo" blocks (block full implicit, e.g., "It" + for non-columnar lists) to work properly. This isn't + enabled by default: you must specify -DUGLY as a compiler + flag (see the Makefile for details). + +Changes in version 1.9.20, released on March 30, 2010 + + * More efforts to get roff instructions in man(7) documents under + control. Note that roff instructions embedded in line-scoped, + next-line macros (e.g. "B") are not supported. + * Leading punctuation for mdoc(7) macros, such as "Fl ( ( a", + are now correctly handled. + +Changes in version 1.9.18, released on March 27, 2010 + + * Many fixes (largely pertaining to scope) + and improvements (e.g., handling of apostrophe-control macros, + which fixes the strange "BR" seen in some macro output) + to handling roff instructions in man(7) documents. + +Changes in version 1.9.17, released on March 25, 2010 + + * Accept perlpod(1) standard preamble. + * Also accept (and discard) "de", "dei", "am", "ami", and "ig" + roff macro blocks. + +Changes in version 1.9.16, released on March 22, 2010 + + * Inspired by patches and bug reports by Ingo Schwarze, + allowed man(7) to accept non-printing elements to be nested + within next-line scopes, such as "br" within "B" or "TH", + which is valid roff. + * Longsoon architecture also noted and Makefile cleaned up. + +Changes in version 1.9.15, released on February 18, 2010 + + * Moved to our new BSD.lv home. + * XHTML is now an acceptable output mode for mandoc(1); + * "Xr" made more compatible with groff; + * "Vt" fixed when invoked in SYNOPSIS; + * "\\" escape removed; + * end-of-line white-space detected for all lines; + * subtle bug fixed in list display for some modes; + * compatibility layer checked in for compilation in diverse + UNIX systems; + * and column lengths handled correctly. + +For older releases, see the ChangeLog files +in http://mandoc.bsd.lv/snapshots/ . Index: vendor/mandoc/20190723/apropos.1 =================================================================== --- vendor/mandoc/20190723/apropos.1 (nonexistent) +++ vendor/mandoc/20190723/apropos.1 (revision 350350) @@ -0,0 +1,510 @@ +.\" $Id: apropos.1,v 1.49 2018/11/22 12:33:52 schwarze Exp $ +.\" +.\" Copyright (c) 2011, 2012 Kristaps Dzonsons +.\" Copyright (c) 2011,2012,2014,2017,2018 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: November 22 2018 $ +.Dt APROPOS 1 +.Os +.Sh NAME +.Nm apropos , +.Nm whatis +.Nd search manual page databases +.Sh SYNOPSIS +.Nm +.Op Fl afk +.Op Fl C Ar file +.Op Fl M Ar path +.Op Fl m Ar path +.Op Fl O Ar outkey +.Op Fl S Ar arch +.Op Fl s Ar section +.Ar expression ... +.Sh DESCRIPTION +The +.Nm apropos +and +.Nm whatis +utilities query manual page databases generated by +.Xr makewhatis 8 , +evaluating +.Ar expression +for each file in each database. +By default, they display the names, section numbers, and description lines +of all matching manuals. +.Pp +By default, +.Nm +searches for +.Xr makewhatis 8 +databases in the default paths stipulated by +.Xr man 1 +and uses case-insensitive extended regular expression matching +over manual names and descriptions +.Pq the Li \&Nm No and Li \&Nd No macro keys . +Multiple terms imply pairwise +.Fl o . +.Pp +.Nm whatis +is a synonym for +.Nm +.Fl f . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +Instead of showing only the title lines, show the complete manual pages, +just like +.Xr man 1 +.Fl a +would. +If the standard output is a terminal device and +.Fl c +is not specified, use +.Xr more 1 +to paginate them. +In +.Fl a +mode, the options +.Fl IKOTW +described in the +.Xr mandoc 1 +manual are also available. +.It Fl C Ar file +Specify an alternative configuration +.Ar file +in +.Xr man.conf 5 +format. +.It Fl f +Search for all words in +.Ar expression +in manual page names only. +The search is case-insensitive and matches whole words only. +In this mode, macro keys, comparison operators, and logical operators +are not available. +.It Fl k +Support the full +.Ar expression +syntax. +It is the default for +.Nm . +.It Fl M Ar path +Use the colon-separated path instead of the default list of paths +searched for +.Xr makewhatis 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl m Ar path +Prepend the colon-separated paths to the list of paths searched +for +.Xr makewhatis 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl O Ar outkey +Show the values associated with the key +.Ar outkey +instead of the manual descriptions. +.It Fl S Ar arch +Restrict the search to pages for the specified +.Xr machine 1 +architecture. +.Ar arch +is case-insensitive. +By default, pages for all architectures are shown. +.It Fl s Ar section +Restrict the search to the specified section of the manual. +By default, pages from all sections are shown. +See +.Xr man 1 +for a listing of sections. +.El +.Pp +The options +.Fl chlw +are also supported and are documented in +.Xr man 1 . +The options +.Fl fkl +are mutually exclusive and override each other. +.Pp +An +.Ar expression +consists of search terms joined by logical operators +.Fl a +.Pq and +and +.Fl o +.Pq or . +The +.Fl a +operator has precedence over +.Fl o +and both are evaluated left-to-right. +.Bl -tag -width Ds +.It \&( Ar expr No \&) +True if the subexpression +.Ar expr +is true. +.It Ar expr1 Fl a Ar expr2 +True if both +.Ar expr1 +and +.Ar expr2 +are true (logical +.Sq and ) . +.It Ar expr1 Oo Fl o Oc Ar expr2 +True if +.Ar expr1 +and/or +.Ar expr2 +evaluate to true (logical +.Sq or ) . +.It Ar term +True if +.Ar term +is satisfied. +This has syntax +.Sm off +.Oo +.Op Ar key Op , Ar key ... +.Pq Cm = | \(ti +.Oc +.Ar val , +.Sm on +where +.Ar key +is an +.Xr mdoc 7 +macro to query and +.Ar val +is its value. +See +.Sx Macro Keys +for a list of available keys. +Operator +.Cm = +evaluates a substring, while +.Cm \(ti +evaluates a case-sensitive extended regular expression. +.It Fl i Ar term +If +.Ar term +is a regular expression, it +is evaluated case-insensitively. +Has no effect on substring terms. +.El +.Pp +Results are sorted first according to the section number in ascending +numerical order, then by the page name in ascending +.Xr ascii 7 +alphabetical order, case-insensitive. +.Pp +Each output line is formatted as +.Pp +.D1 name[, name...](sec) \- description +.Pp +Where +.Dq name +is the manual's name, +.Dq sec +is the manual section, and +.Dq description +is the manual's short description. +If an architecture is specified for the manual, it is displayed as +.Pp +.D1 name(sec/arch) \- description +.Pp +Resulting manuals may be accessed as +.Pp +.Dl $ man \-s sec name +.Pp +If an architecture is specified in the output, use +.Pp +.Dl $ man \-s sec \-S arch name +.Ss Macro Keys +Queries evaluate over a subset of +.Xr mdoc 7 +macros indexed by +.Xr makewhatis 8 . +In addition to the macro keys listed below, the special key +.Cm any +may be used to match any available macro key. +.Pp +Names and description: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Nm Ta manual name +.It Li \&Nd Ta one-line manual description +.It Li arch Ta machine architecture (case-insensitive) +.It Li sec Ta manual section number +.El +.Pp +Sections and cross references: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Sh Ta section header (excluding standard sections) +.It Li \&Ss Ta subsection header +.It Li \&Xr Ta cross reference to another manual page +.It Li \&Rs Ta bibliographic reference +.El +.Pp +Semantic markup for command line utilities: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Fl Ta command line options (flags) +.It Li \&Cm Ta command modifier +.It Li \&Ar Ta command argument +.It Li \&Ic Ta internal or interactive command +.It Li \&Ev Ta environmental variable +.It Li \&Pa Ta file system path +.El +.Pp +Semantic markup for function libraries: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Lb Ta function library name +.It Li \&In Ta include file +.It Li \&Ft Ta function return type +.It Li \&Fn Ta function name +.It Li \&Fa Ta function argument type and name +.It Li \&Vt Ta variable type +.It Li \&Va Ta variable name +.It Li \&Dv Ta defined variable or preprocessor constant +.It Li \&Er Ta error constant +.It Li \&Ev Ta environmental variable +.El +.Pp +Various semantic markup: +.Bl -column "xLix" description -offset indent -compact +.It Li \&An Ta author name +.It Li \&Lk Ta hyperlink +.It Li \&Mt Ta Do mailto Dc hyperlink +.It Li \&Cd Ta kernel configuration declaration +.It Li \&Ms Ta mathematical symbol +.It Li \&Tn Ta tradename +.El +.Pp +Physical markup: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Em Ta italic font or underline +.It Li \&Sy Ta boldface font +.It Li \&Li Ta typewriter font +.El +.Pp +Text production: +.Bl -column "xLix" description -offset indent -compact +.It Li \&St Ta reference to a standards document +.It Li \&At Ta At No version reference +.It Li \&Bx Ta Bx No version reference +.It Li \&Bsx Ta Bsx No version reference +.It Li \&Nx Ta Nx No version reference +.It Li \&Fx Ta Fx No version reference +.It Li \&Ox Ta Ox No version reference +.It Li \&Dx Ta Dx No version reference +.El +.Pp +In general, macro keys are supposed to yield complete results without +expecting the user to consider actual macro usage. +For example, results include: +.Pp +.Bl -tag -width 3n -offset 3n -compact +.It Li \&Fa +function arguments appearing on +.Ic \&Fn +lines +.It Li \&Fn +function names marked up with +.Ic \&Fo +macros +.It Li \&In +include file names marked up with +.Ic \&Fd +macros +.It Li \&Vt +types appearing as function return types and +.It \& +types appearing in function arguments in the SYNOPSIS +.El +.Sh ENVIRONMENT +.Bl -tag -width MANPAGER +.It Ev MANPAGER +Any non-empty value of the environment variable +.Ev MANPAGER +is used instead of the standard pagination program, +.Xr more 1 ; +see +.Xr man 1 +for details. +Only used if +.Fl a +or +.Fl l +is specified. +.It Ev MANPATH +A colon-separated list of directories to search for manual pages; see +.Xr man 1 +for details. +Overridden by +.Fl M , +ignored if +.Fl l +is specified. +.It Ev PAGER +Specifies the pagination program to use when +.Ev MANPAGER +is not defined. +If neither PAGER nor MANPAGER is defined, +.Xr more 1 +.Fl s +is used. +Only used if +.Fl a +or +.Fl l +is specified. +.El +.Sh FILES +.Bl -tag -width "/etc/man.conf" -compact +.It Pa mandoc.db +name of the +.Xr makewhatis 8 +keyword database +.It Pa /etc/man.conf +default +.Xr man 1 +configuration file +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Search for +.Qq .cf +as a substring of manual names and descriptions: +.Pp +.Dl $ apropos =.cf +.Pp +Include matches for +.Qq .cnf +and +.Qq .conf +as well: +.Pp +.Dl $ apropos =.cf =.cnf =.conf +.Pp +Search in names and descriptions using a case-sensitive regular expression: +.Pp +.Dl $ apropos \(aq\(tiset.?[ug]id\(aq +.Pp +Search for manuals in the library section mentioning both the +.Qq optind +and the +.Qq optarg +variables: +.Pp +.Dl $ apropos \-s 3 Va=optind \-a Va=optarg +.Pp +Do exactly the same as calling +.Nm whatis +with the argument +.Qq ssh : +.Pp +.Dl $ apropos \-\- \-i \(aqNm\(ti[[:<:]]ssh[[:>:]]\(aq +.Pp +The following two invocations are equivalent: +.Pp +.D1 Li $ apropos -S Ar arch Li -s Ar section expression +.Bd -ragged -offset indent +.Li $ apropos \e( Ar expression Li \e) +.Li -a arch\(ti^( Ns Ar arch Ns Li |any)$ +.Li -a sec\(ti^ Ns Ar section Ns Li $ +.Ed +.Sh SEE ALSO +.Xr man 1 , +.Xr re_format 7 , +.Xr makewhatis 8 +.Sh STANDARDS +The +.Nm +utility is compliant with the +.St -p1003.1-2008 +specification of +.Xr man 1 +.Fl k . +.Pp +All options, the +.Nm whatis +command, support for logical operators, macro keys, +substring matching, sorting of results, the environment variables +.Ev MANPAGER +and +.Ev MANPATH , +the database format, and the configuration file +are extensions to that specification. +.Sh HISTORY +Part of the functionality of +.Nm whatis +was already provided by the former +.Nm manwhere +utility in +.Bx 1 . +The +.Nm +and +.Nm whatis +utilities first appeared in +.Bx 2 . +They were rewritten from scratch for +.Ox 5.6 . +.Pp +The +.Fl M +option and the +.Ev MANPATH +variable first appeared in +.Bx 4.3 ; +.Fl m +in +.Bx 4.3 Reno ; +.Fl C +in +.Bx 4.4 Lite1 ; +and +.Fl S +and +.Fl s +in +.Ox 4.5 +for +.Nm +and in +.Ox 5.6 +for +.Nm whatis . +The options +.Fl acfhIKklOTWw +appeared in +.Ox 5.7 . +.Sh AUTHORS +.An -nosplit +.An Bill Joy +wrote +.Nm manwhere +in 1977 and the original +.Bx +.Nm +and +.Nm whatis +in February 1979. +The current version was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +and +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: vendor/mandoc/20190723/apropos.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/att.c =================================================================== --- vendor/mandoc/20190723/att.c (nonexistent) +++ vendor/mandoc/20190723/att.c (revision 350350) @@ -0,0 +1,49 @@ +/* $Id: att.c,v 1.18 2018/12/13 11:55:46 schwarze Exp $ */ +/* + * Copyright (c) 2009 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include +#include + +#include "roff.h" +#include "libmdoc.h" + +#define LINE(x, y) \ + if (0 == strcmp(p, x)) return(y) + + +const char * +mdoc_a2att(const char *p) +{ + + LINE("v1", "Version\\~1 AT&T UNIX"); + LINE("v2", "Version\\~2 AT&T UNIX"); + LINE("v3", "Version\\~3 AT&T UNIX"); + LINE("v4", "Version\\~4 AT&T UNIX"); + LINE("v5", "Version\\~5 AT&T UNIX"); + LINE("v6", "Version\\~6 AT&T UNIX"); + LINE("v7", "Version\\~7 AT&T UNIX"); + LINE("32v", "Version\\~32V AT&T UNIX"); + LINE("III", "AT&T System\\~III UNIX"); + LINE("V", "AT&T System\\~V UNIX"); + LINE("V.1", "AT&T System\\~V Release\\~1 UNIX"); + LINE("V.2", "AT&T System\\~V Release\\~2 UNIX"); + LINE("V.3", "AT&T System\\~V Release\\~3 UNIX"); + LINE("V.4", "AT&T System\\~V Release\\~4 UNIX"); + + return NULL; +} Property changes on: vendor/mandoc/20190723/att.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/chars.c =================================================================== --- vendor/mandoc/20190723/chars.c (nonexistent) +++ vendor/mandoc/20190723/chars.c (revision 350350) @@ -0,0 +1,506 @@ +/* $Id: chars.c,v 1.78 2018/12/15 19:30:26 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "libmandoc.h" + +struct ln { + const char roffcode[16]; + const char *ascii; + int unicode; +}; + +/* Special break control characters. */ +static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' }; +static const char ascii_break[2] = { ASCII_BREAK, '\0' }; + +static struct ln lines[] = { + + /* Spacing. */ + { " ", ascii_nbrsp, 0x00a0 }, + { "~", ascii_nbrsp, 0x00a0 }, + { "0", " ", 0x2002 }, + { ":", ascii_break, 0 }, + + /* Lines. */ + { "ba", "|", 0x007c }, + { "br", "|", 0x2502 }, + { "ul", "_", 0x005f }, + { "_", "_", 0x005f }, + { "ru", "_", 0x005f }, + { "rn", "-", 0x203e }, + { "bb", "|", 0x00a6 }, + { "sl", "/", 0x002f }, + { "rs", "\\", 0x005c }, + + /* Text markers. */ + { "ci", "O", 0x25cb }, + { "bu", "+\bo", 0x2022 }, + { "dd", "<**>", 0x2021 }, + { "dg", "<*>", 0x2020 }, + { "lz", "<>", 0x25ca }, + { "sq", "[]", 0x25a1 }, + { "ps", "", 0x00b6 }, + { "sc", "

", 0x00a7 }, + { "lh", "<=", 0x261c }, + { "rh", "=>", 0x261e }, + { "at", "@", 0x0040 }, + { "sh", "#", 0x0023 }, + { "CR", "", 0x21b5 }, + { "OK", "\\/", 0x2713 }, + { "CL", "C", 0x2663 }, + { "SP", "S", 0x2660 }, + { "HE", "H", 0x2665 }, + { "DI", "D", 0x2666 }, + + /* Legal symbols. */ + { "co", "(C)", 0x00a9 }, + { "rg", "(R)", 0x00ae }, + { "tm", "tm", 0x2122 }, + + /* Punctuation. */ + { "em", "--", 0x2014 }, + { "en", "-", 0x2013 }, + { "hy", "-", 0x2010 }, + { "e", "\\", 0x005c }, + { ".", ".", 0x002e }, + { "r!", "!", 0x00a1 }, + { "r?", "?", 0x00bf }, + + /* Quotes. */ + { "Bq", ",,", 0x201e }, + { "bq", ",", 0x201a }, + { "lq", "\"", 0x201c }, + { "rq", "\"", 0x201d }, + { "Lq", "\"", 0x201c }, + { "Rq", "\"", 0x201d }, + { "oq", "`", 0x2018 }, + { "cq", "\'", 0x2019 }, + { "aq", "\'", 0x0027 }, + { "dq", "\"", 0x0022 }, + { "Fo", "<<", 0x00ab }, + { "Fc", ">>", 0x00bb }, + { "fo", "<", 0x2039 }, + { "fc", ">", 0x203a }, + + /* Brackets. */ + { "lB", "[", 0x005b }, + { "rB", "]", 0x005d }, + { "lC", "{", 0x007b }, + { "rC", "}", 0x007d }, + { "la", "<", 0x27e8 }, + { "ra", ">", 0x27e9 }, + { "bv", "|", 0x23aa }, + { "braceex", "|", 0x23aa }, + { "bracketlefttp", "|", 0x23a1 }, + { "bracketleftbt", "|", 0x23a3 }, + { "bracketleftex", "|", 0x23a2 }, + { "bracketrighttp", "|", 0x23a4 }, + { "bracketrightbt", "|", 0x23a6 }, + { "bracketrightex", "|", 0x23a5 }, + { "lt", ",-", 0x23a7 }, + { "bracelefttp", ",-", 0x23a7 }, + { "lk", "{", 0x23a8 }, + { "braceleftmid", "{", 0x23a8 }, + { "lb", "`-", 0x23a9 }, + { "braceleftbt", "`-", 0x23a9 }, + { "braceleftex", "|", 0x23aa }, + { "rt", "-.", 0x23ab }, + { "bracerighttp", "-.", 0x23ab }, + { "rk", "}", 0x23ac }, + { "bracerightmid", "}", 0x23ac }, + { "rb", "-\'", 0x23ad }, + { "bracerightbt", "-\'", 0x23ad }, + { "bracerightex", "|", 0x23aa }, + { "parenlefttp", "/", 0x239b }, + { "parenleftbt", "\\", 0x239d }, + { "parenleftex", "|", 0x239c }, + { "parenrighttp", "\\", 0x239e }, + { "parenrightbt", "/", 0x23a0 }, + { "parenrightex", "|", 0x239f }, + + /* Arrows and lines. */ + { "<-", "<-", 0x2190 }, + { "->", "->", 0x2192 }, + { "<>", "<->", 0x2194 }, + { "da", "|\bv", 0x2193 }, + { "ua", "|\b^", 0x2191 }, + { "va", "^v", 0x2195 }, + { "lA", "<=", 0x21d0 }, + { "rA", "=>", 0x21d2 }, + { "hA", "<=>", 0x21d4 }, + { "uA", "=\b^", 0x21d1 }, + { "dA", "=\bv", 0x21d3 }, + { "vA", "^=v", 0x21d5 }, + { "an", "-", 0x23af }, + + /* Logic. */ + { "AN", "^", 0x2227 }, + { "OR", "v", 0x2228 }, + { "no", "~", 0x00ac }, + { "tno", "~", 0x00ac }, + { "te", "", 0x2203 }, + { "fa", "", 0x2200 }, + { "st", "", 0x220b }, + { "tf", "", 0x2234 }, + { "3d", "", 0x2234 }, + { "or", "|", 0x007c }, + + /* Mathematicals. */ + { "pl", "+", 0x002b }, + { "mi", "-", 0x2212 }, + { "-", "-", 0x002d }, + { "-+", "-+", 0x2213 }, + { "+-", "+-", 0x00b1 }, + { "t+-", "+-", 0x00b1 }, + { "pc", ".", 0x00b7 }, + { "md", ".", 0x22c5 }, + { "mu", "x", 0x00d7 }, + { "tmu", "x", 0x00d7 }, + { "c*", "O\bx", 0x2297 }, + { "c+", "O\b+", 0x2295 }, + { "di", "/", 0x00f7 }, + { "tdi", "/", 0x00f7 }, + { "f/", "/", 0x2044 }, + { "**", "*", 0x2217 }, + { "<=", "<=", 0x2264 }, + { ">=", ">=", 0x2265 }, + { "<<", "<<", 0x226a }, + { ">>", ">>", 0x226b }, + { "eq", "=", 0x003d }, + { "!=", "!=", 0x2260 }, + { "==", "==", 0x2261 }, + { "ne", "!==", 0x2262 }, + { "ap", "~", 0x223c }, + { "|=", "-~", 0x2243 }, + { "=~", "=~", 0x2245 }, + { "~~", "~~", 0x2248 }, + { "~=", "~=", 0x2248 }, + { "pt", "", 0x221d }, + { "es", "{}", 0x2205 }, + { "mo", "", 0x2208 }, + { "nm", "", 0x2209 }, + { "sb", "", 0x2282 }, + { "nb", "", 0x2284 }, + { "sp", "", 0x2283 }, + { "nc", "", 0x2285 }, + { "ib", "", 0x2286 }, + { "ip", "", 0x2287 }, + { "ca", "", 0x2229 }, + { "cu", "", 0x222a }, + { "/_", "", 0x2220 }, + { "pp", "", 0x22a5 }, + { "is", "", 0x222b }, + { "integral", "", 0x222b }, + { "sum", "", 0x2211 }, + { "product", "", 0x220f }, + { "coproduct", "", 0x2210 }, + { "gr", "", 0x2207 }, + { "sr", "", 0x221a }, + { "sqrt", "", 0x221a }, + { "lc", "|~", 0x2308 }, + { "rc", "~|", 0x2309 }, + { "lf", "|_", 0x230a }, + { "rf", "_|", 0x230b }, + { "if", "", 0x221e }, + { "Ah", "", 0x2135 }, + { "Im", "", 0x2111 }, + { "Re", "", 0x211c }, + { "wp", "p", 0x2118 }, + { "pd", "", 0x2202 }, + { "-h", "/h", 0x210f }, + { "hbar", "/h", 0x210f }, + { "12", "1/2", 0x00bd }, + { "14", "1/4", 0x00bc }, + { "34", "3/4", 0x00be }, + { "18", "1/8", 0x215B }, + { "38", "3/8", 0x215C }, + { "58", "5/8", 0x215D }, + { "78", "7/8", 0x215E }, + { "S1", "^1", 0x00B9 }, + { "S2", "^2", 0x00B2 }, + { "S3", "^3", 0x00B3 }, + + /* Ligatures. */ + { "ff", "ff", 0xfb00 }, + { "fi", "fi", 0xfb01 }, + { "fl", "fl", 0xfb02 }, + { "Fi", "ffi", 0xfb03 }, + { "Fl", "ffl", 0xfb04 }, + { "AE", "AE", 0x00c6 }, + { "ae", "ae", 0x00e6 }, + { "OE", "OE", 0x0152 }, + { "oe", "oe", 0x0153 }, + { "ss", "ss", 0x00df }, + { "IJ", "IJ", 0x0132 }, + { "ij", "ij", 0x0133 }, + + /* Accents. */ + { "a\"", "\"", 0x02dd }, + { "a-", "-", 0x00af }, + { "a.", ".", 0x02d9 }, + { "a^", "^", 0x005e }, + { "aa", "\'", 0x00b4 }, + { "\'", "\'", 0x00b4 }, + { "ga", "`", 0x0060 }, + { "`", "`", 0x0060 }, + { "ab", "'\b`", 0x02d8 }, + { "ac", ",", 0x00b8 }, + { "ad", "\"", 0x00a8 }, + { "ah", "v", 0x02c7 }, + { "ao", "o", 0x02da }, + { "a~", "~", 0x007e }, + { "ho", ",", 0x02db }, + { "ha", "^", 0x005e }, + { "ti", "~", 0x007e }, + { "u02DC", "~", 0x02dc }, + + /* Accented letters. */ + { "'A", "'\bA", 0x00c1 }, + { "'E", "'\bE", 0x00c9 }, + { "'I", "'\bI", 0x00cd }, + { "'O", "'\bO", 0x00d3 }, + { "'U", "'\bU", 0x00da }, + { "'Y", "'\bY", 0x00dd }, + { "'a", "'\ba", 0x00e1 }, + { "'e", "'\be", 0x00e9 }, + { "'i", "'\bi", 0x00ed }, + { "'o", "'\bo", 0x00f3 }, + { "'u", "'\bu", 0x00fa }, + { "'y", "'\by", 0x00fd }, + { "`A", "`\bA", 0x00c0 }, + { "`E", "`\bE", 0x00c8 }, + { "`I", "`\bI", 0x00cc }, + { "`O", "`\bO", 0x00d2 }, + { "`U", "`\bU", 0x00d9 }, + { "`a", "`\ba", 0x00e0 }, + { "`e", "`\be", 0x00e8 }, + { "`i", "`\bi", 0x00ec }, + { "`o", "`\bo", 0x00f2 }, + { "`u", "`\bu", 0x00f9 }, + { "~A", "~\bA", 0x00c3 }, + { "~N", "~\bN", 0x00d1 }, + { "~O", "~\bO", 0x00d5 }, + { "~a", "~\ba", 0x00e3 }, + { "~n", "~\bn", 0x00f1 }, + { "~o", "~\bo", 0x00f5 }, + { ":A", "\"\bA", 0x00c4 }, + { ":E", "\"\bE", 0x00cb }, + { ":I", "\"\bI", 0x00cf }, + { ":O", "\"\bO", 0x00d6 }, + { ":U", "\"\bU", 0x00dc }, + { ":a", "\"\ba", 0x00e4 }, + { ":e", "\"\be", 0x00eb }, + { ":i", "\"\bi", 0x00ef }, + { ":o", "\"\bo", 0x00f6 }, + { ":u", "\"\bu", 0x00fc }, + { ":y", "\"\by", 0x00ff }, + { "^A", "^\bA", 0x00c2 }, + { "^E", "^\bE", 0x00ca }, + { "^I", "^\bI", 0x00ce }, + { "^O", "^\bO", 0x00d4 }, + { "^U", "^\bU", 0x00db }, + { "^a", "^\ba", 0x00e2 }, + { "^e", "^\be", 0x00ea }, + { "^i", "^\bi", 0x00ee }, + { "^o", "^\bo", 0x00f4 }, + { "^u", "^\bu", 0x00fb }, + { ",C", ",\bC", 0x00c7 }, + { ",c", ",\bc", 0x00e7 }, + { "/L", "/\bL", 0x0141 }, + { "/l", "/\bl", 0x0142 }, + { "/O", "/\bO", 0x00d8 }, + { "/o", "/\bo", 0x00f8 }, + { "oA", "o\bA", 0x00c5 }, + { "oa", "o\ba", 0x00e5 }, + + /* Special letters. */ + { "-D", "Dh", 0x00d0 }, + { "Sd", "dh", 0x00f0 }, + { "TP", "Th", 0x00de }, + { "Tp", "th", 0x00fe }, + { ".i", "i", 0x0131 }, + { ".j", "j", 0x0237 }, + + /* Currency. */ + { "Do", "$", 0x0024 }, + { "ct", "/\bc", 0x00a2 }, + { "Eu", "EUR", 0x20ac }, + { "eu", "EUR", 0x20ac }, + { "Ye", "=\bY", 0x00a5 }, + { "Po", "-\bL", 0x00a3 }, + { "Cs", "o\bx", 0x00a4 }, + { "Fn", ",\bf", 0x0192 }, + + /* Units. */ + { "de", "", 0x00b0 }, + { "%0", "", 0x2030 }, + { "fm", "\'", 0x2032 }, + { "sd", "''", 0x2033 }, + { "mc", "", 0x00b5 }, + { "Of", "_\ba", 0x00aa }, + { "Om", "_\bo", 0x00ba }, + + /* Greek characters. */ + { "*A", "A", 0x0391 }, + { "*B", "B", 0x0392 }, + { "*G", "", 0x0393 }, + { "*D", "", 0x0394 }, + { "*E", "E", 0x0395 }, + { "*Z", "Z", 0x0396 }, + { "*Y", "H", 0x0397 }, + { "*H", "", 0x0398 }, + { "*I", "I", 0x0399 }, + { "*K", "K", 0x039a }, + { "*L", "", 0x039b }, + { "*M", "M", 0x039c }, + { "*N", "N", 0x039d }, + { "*C", "", 0x039e }, + { "*O", "O", 0x039f }, + { "*P", "", 0x03a0 }, + { "*R", "P", 0x03a1 }, + { "*S", "", 0x03a3 }, + { "*T", "T", 0x03a4 }, + { "*U", "Y", 0x03a5 }, + { "*F", "", 0x03a6 }, + { "*X", "X", 0x03a7 }, + { "*Q", "", 0x03a8 }, + { "*W", "", 0x03a9 }, + { "*a", "", 0x03b1 }, + { "*b", "", 0x03b2 }, + { "*g", "", 0x03b3 }, + { "*d", "", 0x03b4 }, + { "*e", "", 0x03b5 }, + { "*z", "", 0x03b6 }, + { "*y", "", 0x03b7 }, + { "*h", "", 0x03b8 }, + { "*i", "", 0x03b9 }, + { "*k", "", 0x03ba }, + { "*l", "", 0x03bb }, + { "*m", "", 0x03bc }, + { "*n", "", 0x03bd }, + { "*c", "", 0x03be }, + { "*o", "o", 0x03bf }, + { "*p", "", 0x03c0 }, + { "*r", "", 0x03c1 }, + { "*s", "", 0x03c3 }, + { "*t", "", 0x03c4 }, + { "*u", "", 0x03c5 }, + { "*f", "", 0x03d5 }, + { "*x", "", 0x03c7 }, + { "*q", "", 0x03c8 }, + { "*w", "", 0x03c9 }, + { "+h", "", 0x03d1 }, + { "+f", "", 0x03c6 }, + { "+p", "", 0x03d6 }, + { "+e", "", 0x03f5 }, + { "ts", "", 0x03c2 }, +}; + +static struct ohash mchars; + + +void +mchars_free(void) +{ + + ohash_delete(&mchars); +} + +void +mchars_alloc(void) +{ + size_t i; + unsigned int slot; + + mandoc_ohash_init(&mchars, 9, offsetof(struct ln, roffcode)); + for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++) { + slot = ohash_qlookup(&mchars, lines[i].roffcode); + assert(ohash_find(&mchars, slot) == NULL); + ohash_insert(&mchars, slot, lines + i); + } +} + +int +mchars_spec2cp(const char *p, size_t sz) +{ + const struct ln *ln; + const char *end; + + end = p + sz; + ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end)); + return ln != NULL ? ln->unicode : -1; +} + +int +mchars_num2char(const char *p, size_t sz) +{ + int i; + + i = mandoc_strntoi(p, sz, 10); + return i >= 0 && i < 256 ? i : -1; +} + +int +mchars_num2uc(const char *p, size_t sz) +{ + int i; + + i = mandoc_strntoi(p, sz, 16); + assert(i >= 0 && i <= 0x10FFFF); + return i; +} + +const char * +mchars_spec2str(const char *p, size_t sz, size_t *rsz) +{ + const struct ln *ln; + const char *end; + + end = p + sz; + ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end)); + if (ln == NULL) + return NULL; + + *rsz = strlen(ln->ascii); + return ln->ascii; +} + +const char * +mchars_uc2str(int uc) +{ + size_t i; + + for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++) + if (uc == lines[i].unicode) + return lines[i].ascii; + return ""; +} Property changes on: vendor/mandoc/20190723/chars.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/configure.local.example =================================================================== --- vendor/mandoc/20190723/configure.local.example (nonexistent) +++ vendor/mandoc/20190723/configure.local.example (revision 350350) @@ -0,0 +1,328 @@ +# $Id: configure.local.example,v 1.36 2019/03/06 10:18:58 schwarze Exp $ +# +# Copyright (c) 2014-2019 Ingo Schwarze +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# For all settings documented in this file, there are reasonable +# defaults and/or the ./configure script attempts autodetection. +# Consequently, you only need to create a file ./configure.local +# and put any of these settings into it if ./configure autodetection +# fails or if you want to make different choices for other reasons. + +# If autodetection fails, please tell . + +# We recommend that you write ./configure.local from scratch and +# only put the lines there you need. This file contains examples. +# It is not intended as a template to be copied as a whole. + +# --- user settings relevant for all builds ---------------------------- + +# For -Tutf8 and -Tlocale operation, mandoc(1) requires +# providing setlocale(3) and providing wcwidth(3) and +# putwchar(3) with a wchar_t storing UCS-4 values. Theoretically, +# the latter should be tested with the __STDC_ISO_10646__ feature +# macro. In practice, many headers do not provide that +# macro even though they treat wchar_t as UCS-4. So the automatic +# test only checks that wchar_t is wide enough, that is, at least +# four bytes. + +# The following line forces multi-byte support. +# If your C library does not treat wchar_t as UCS-4, the UTF-8 output +# mode will print garbage. + +HAVE_WCHAR=1 + +# The following line disables multi-byte support. +# The output modes -Tutf8 and -Tlocale will be the same as -Tascii. + +HAVE_WCHAR=0 + +# For -Tutf8 mode, mandoc needs to set an arbitrary locale having +# a UTF-8 character set. If autodetection of a suitable locale +# fails or selects an undesirable locale, you can manually choose +# the locale for -Tutf8 mode: + +UTF8_LOCALE=en_US.UTF-8 + +# When man(1) or apropos(1) is called without -m and -M options, +# MANPATH is not set in the environment, and man.conf(5) is not +# available, manuals are searched for in the following directory +# trees by default. + +MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" + +# Validation of cross references with mandoc -Tlint only looks +# for manual pages in the following directories: + +MANPATH_BASE="/usr/share/man:/usr/X11R6/man" + +# When man(1) is called with the -S option and no manual page is +# found matching the requested name and the requested architecture, +# it tries to figure out whether the requested architecture is valid +# for the present operating system. Normally, ./configure detects +# the operating system using uname(1). If that fails or is not +# desired, either of the following lines can be used: + +OSENUM=MANDOC_OS_NETBSD +OSENUM=MANDOC_OS_OPENBSD +OSENUM=MANDOC_OS_OTHER + +# In manual pages written in the mdoc(7) language, the operating system +# version is displayed in the page footer line. If an operating system +# is specified as an argument to the .Os macro, that is always used. +# If the .Os macro has no argument and an operation system is specified +# with the mandoc(1) -Ios= command line option, that is used. +# Otherwise, the uname(3) library function is called at runtime to find +# the name of the operating system. +# If you do not want uname(3) to be called but instead want a fixed +# string to be used, use the following line: + +OSNAME="OpenBSD 6.5" + +# The following installation directories are used. +# It is possible to set only one or a few of these variables, +# there is no need to copy the whole block. +# Even if you set PREFIX to something else, the other variables +# pick it up without copying them all over. + +PREFIX="/usr/local" +BINDIR="${PREFIX}/bin" +SBINDIR="${PREFIX}/sbin" +MANDIR="${PREFIX}/man" + +# If BINDIR and SBINDIR are not subdirectories of the same parent +# directory or if the basename(1) of BINDIR differs from "bin", +# the relative path from SBINDIR to BINDIR is also needed. +# The default is: + +BIN_FROM_SBIN="../bin" + +# Some distributions may want to avoid naming conflicts +# with the configuration files of other man(1) implementations. +# This changes the name of the installed section 5 manual page as well. + +MANM_MANCONF="mandoc.conf" # default is "man.conf" + +# Some distributions may want to avoid naming conflicts among manuals. +# If you want to change the names of installed section 7 manual pages, +# the following alternative names are suggested. +# The suffix ".7" will automatically be appended. +# It is possible to set only one or a few of these variables, +# there is no need to copy the whole block. + +MANM_MAN="mandoc_man" # default is "man" +MANM_MDOC="mandoc_mdoc" # default is "mdoc" +MANM_ROFF="mandoc_roff" # default is "roff" +MANM_EQN="mandoc_eqn" # default is "eqn" +MANM_TBL="mandoc_tbl" # default is "tbl" + +# Some distributions may want to avoid naming conflicts with +# other man(1), apropos(1), makewhatis(8), or soelim(1) utilities. +# If you want to change the names of binary programs, +# the following alternative names are suggested. +# Using different names is possible as well. +# This changes the names of the installed section 1 and section 8 +# manual pages as well. +# It is possible to set only one or two of these variables, +# there is no need to copy the whole block. + +BINM_MAN=mman # default is "man" +BINM_APROPOS=mapropos # default is "apropos" +BINM_WHATIS=mwhatis # default is "whatis" +BINM_MAKEWHATIS=mandocdb # default is "makewhatis" +BINM_SOELIM=msoelim # default is "soelim" + +# Some distributions do not want hardlinks +# between installed binary programs. +# Set the following variable to use symbolic links instead. +# It is also used for links between manual pages. +# It is only used by the install* targets. +# When using this, DESTDIR must be empty or an absolute path. + +LN="ln -sf" # default is "ln -f" + +# Before falling back to the bundled version of the ohash(3) hashing +# library, autoconfiguration tries the following linker flag to +# link against your system version. If you do have ohash(3) on +# your system but it needs different linker flags, set the following +# variable to specify the required linker flags. + +LD_OHASH="-lutil" + +# Some platforms may need an additional linker flag for nanosleep(2). +# If none is needed or it is -lrt, it is autodetected. +# Otherwise, set the following variable. + +LD_NANOSLEEP="-lrt" + +# Some platforms may need an additional linker flag for recvmsg(2). +# If none is needed or it is -lsocket, it is autodetected. +# Otherwise, set the following variable. + +LD_RECVMSG="-lsocket" + +# Some platforms might need additional linker flags to link against +# libmandoc that are not autodetected, though no such cases are +# currently known. + +LDADD="-lm" + +# Some systems may want to set additional linker flags for all the +# binaries, not only for those using libmandoc, for example for +# hardening options. + +LDFLAGS="-Wl,-z,relro" + +# It is possible to change the utility program used for installation +# and the modes files are installed with. The defaults are: + +INSTALL="install" +INSTALL_PROGRAM="${INSTALL} -m 0555" +INSTALL_LIB="${INSTALL} -m 0444" +INSTALL_MAN="${INSTALL} -m 0444" +INSTALL_DATA="${INSTALL} -m 0444" + +# When using the "homebrew" package manager on Mac OS X, the actual +# manuals are located in a so-called "cellar" and only symlinked +# into the manual trees. To allow mandoc to follow such symlinks, +# you have to specify the physical location of the cellar as returned +# by realpath(3), for example: + +PREFIX="/usr/local" +HOMEBREWDIR="${PREFIX}/Cellar" + +# --- user settings for the mandoc(3) library -------------------------- + +# By default, libmandoc.a is not installed. It is almost never needed +# because there is almost no non-mandoc software out there using this +# library. The one notable exception is NetBSD apropos(1). +# So, when building for the NetBSD base system - but not for NetBSD +# ports nor for pkgsrc! - you may want the following: + +INSTALL_LIBMANDOC=1 + +# The following settings are only used when INSTALL_LIBMANDOC is set. + +INCLUDEDIR="${PREFIX}/include/mandoc" +LIBDIR="${PREFIX}/lib/mandoc" + +# --- user settings related to man.cgi --------------------------------- + +# By default, building man.cgi(8) is disabled. To enable it, copy +# cgi.h.example to cgi.h, edit it, and use the following line. + +BUILD_CGI=1 + +# The remaining settings in this section are only relevant if BUILD_CGI +# is enabled. Otherwise, they have no effect either way. + +# By default, man.cgi(8) is linked statically if the compiler supports +# the -static option. If automatic detection fails, you can force +# static linking of man.cgi(8). + +STATIC="-static" + +# Some systems may require -pthread for static linking: + +STATIC="-static -pthread" + +# If static linking works in general but not with additional libraries +# like -lrt or -lz, you can force dynamic linking. This may for +# example be required on SunOS 5.9. + +STATIC=" " + +# Some directories. +# This works just like PREFIX, see above. + +WWWPREFIX="/var/www" +HTDOCDIR="${WWWPREFIX}/htdocs" +CGIBINDIR="${WWWPREFIX}/cgi-bin" + +# --- user settings related to catman ---------------------------------- + +# By default, building mandocd(8) and catman(8) is disabled. +# To enable it, use the following line. +# It does not work on SunOS 5.10 because there is no mkdirat(2) +# nor on SunOS 5.9 which also lacks CMSG_LEN(3) and CMSG_SPACE(3). + +BUILD_CATMAN=1 + +# Install catman(8) with a different name. +# See BINM_MAN above for details of how this works. + +BINM_CATMAN=mcatman # default is "catman" + +# --- settings that rarely need to be touched -------------------------- + +# Do not set these variables unless you really need to. + +# You can manually override the compiler to be used. +# But that's rarely useful because ./configure asks your make(1) +# which compiler to use, and that answer will hardly be wrong. + +CC=cc + +# Because the system compiler may not provide , +# SunOS 5.9 may need: + +CC=gcc + +# IBM AIX may need: + +CC=xlc + +# Normally, leave CFLAGS unset. In that case, -g will automatically +# be used, and various -W options will be added if the compiler +# supports them. If you define CFLAGS manually, it will be used +# unchanged, and nothing will be added. + +CFLAGS="-g" + +# In rare cases, it may be required to skip individual automatic tests. +# Each of the following variables can be set to 0 (test will not be run +# and will be regarded as failed) or 1 (test will not be run and will +# be regarded as successful). + +HAVE_DIRENT_NAMLEN=0 +HAVE_ENDIAN=0 +HAVE_EFTYPE=0 +HAVE_ERR=0 +HAVE_FTS=0 # Setting this implies HAVE_FTS_COMPARE_CONST=0. +HAVE_FTS_COMPARE_CONST=0 # Setting this implies HAVE_FTS=1. +HAVE_GETLINE=0 +HAVE_GETSUBOPT=0 +HAVE_ISBLANK=0 +HAVE_LESS_T=0 +HAVE_MKDTEMP=0 +HAVE_NTOHL=0 +HAVE_O_DIRECTORY=0 +HAVE_OHASH=0 +HAVE_PATH_MAX=0 +HAVE_PLEDGE=0 +HAVE_PROGNAME=0 +HAVE_REALLOCARRAY=0 +HAVE_RECALLOCARRAY=0 +HAVE_REWB_BSD=0 +HAVE_REWB_SYSV=0 +HAVE_STRCASESTR=0 +HAVE_STRINGLIST=0 +HAVE_STRLCAT=0 +HAVE_STRLCPY=0 +HAVE_STRPTIME=0 +HAVE_STRSEP=0 +HAVE_STRTONUM=0 +HAVE_SYS_ENDIAN=0 +HAVE_VASPRINTF=0 +HAVE_WCHAR=0 Index: vendor/mandoc/20190723/demandoc.c =================================================================== --- vendor/mandoc/20190723/demandoc.c (nonexistent) +++ vendor/mandoc/20190723/demandoc.c (revision 350350) @@ -0,0 +1,260 @@ +/* $Id: demandoc.c,v 1.33 2019/03/03 11:01:15 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "man.h" +#include "mdoc.h" +#include "mandoc_parse.h" + +static void pline(int, int *, int *, int); +static void pman(const struct roff_node *, int *, int *, int); +static void pmandoc(struct mparse *, int, const char *, int); +static void pmdoc(const struct roff_node *, int *, int *, int); +static void pstring(const char *, int, int *, int); +static void usage(void); + +static const char *progname; + +int +main(int argc, char *argv[]) +{ + struct mparse *mp; + int ch, fd, i, list; + extern int optind; + + if (argc < 1) + progname = "demandoc"; + else if ((progname = strrchr(argv[0], '/')) == NULL) + progname = argv[0]; + else + ++progname; + + mp = NULL; + list = 0; + + while (-1 != (ch = getopt(argc, argv, "ikm:pw"))) + switch (ch) { + case ('i'): + /* FALLTHROUGH */ + case ('k'): + /* FALLTHROUGH */ + case ('m'): + /* FALLTHROUGH */ + case ('p'): + break; + case ('w'): + list = 1; + break; + default: + usage(); + return (int)MANDOCLEVEL_BADARG; + } + + argc -= optind; + argv += optind; + + mchars_alloc(); + mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 | + MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL); + assert(mp); + + if (argc < 1) + pmandoc(mp, STDIN_FILENO, "", list); + + for (i = 0; i < argc; i++) { + mparse_reset(mp); + if ((fd = mparse_open(mp, argv[i])) == -1) { + perror(argv[i]); + continue; + } + pmandoc(mp, fd, argv[i], list); + } + + mparse_free(mp); + mchars_free(); + return (int)MANDOCLEVEL_OK; +} + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s [-w] [files...]\n", progname); +} + +static void +pmandoc(struct mparse *mp, int fd, const char *fn, int list) +{ + struct roff_meta *meta; + int line, col; + + mparse_readfd(mp, fd, fn); + close(fd); + meta = mparse_result(mp); + line = 1; + col = 0; + + if (meta->macroset == MACROSET_MDOC) + pmdoc(meta->first->child, &line, &col, list); + else + pman(meta->first->child, &line, &col, list); + + if ( ! list) + putchar('\n'); +} + +/* + * Strip the escapes out of a string, emitting the results. + */ +static void +pstring(const char *p, int col, int *colp, int list) +{ + enum mandoc_esc esc; + const char *start, *end; + int emit; + + /* + * Print as many column spaces til we achieve parity with the + * input document. + */ + +again: + if (list && '\0' != *p) { + while (isspace((unsigned char)*p)) + p++; + + while ('\'' == *p || '(' == *p || '"' == *p) + p++; + + emit = isalpha((unsigned char)p[0]) && + isalpha((unsigned char)p[1]); + + for (start = p; '\0' != *p; p++) + if ('\\' == *p) { + p++; + esc = mandoc_escape(&p, NULL, NULL); + if (ESCAPE_ERROR == esc) + return; + emit = 0; + } else if (isspace((unsigned char)*p)) + break; + + end = p - 1; + + while (end > start) + if ('.' == *end || ',' == *end || + '\'' == *end || '"' == *end || + ')' == *end || '!' == *end || + '?' == *end || ':' == *end || + ';' == *end) + end--; + else + break; + + if (emit && end - start >= 1) { + for ( ; start <= end; start++) + if (ASCII_HYPH == *start) + putchar('-'); + else + putchar((unsigned char)*start); + putchar('\n'); + } + + if (isspace((unsigned char)*p)) + goto again; + + return; + } + + while (*colp < col) { + putchar(' '); + (*colp)++; + } + + /* + * Print the input word, skipping any special characters. + */ + while ('\0' != *p) + if ('\\' == *p) { + p++; + esc = mandoc_escape(&p, NULL, NULL); + if (ESCAPE_ERROR == esc) + break; + } else { + putchar((unsigned char )*p++); + (*colp)++; + } +} + +static void +pline(int line, int *linep, int *col, int list) +{ + + if (list) + return; + + /* + * Print out as many lines as needed to reach parity with the + * original input. + */ + + while (*linep < line) { + putchar('\n'); + (*linep)++; + } + + *col = 0; +} + +static void +pmdoc(const struct roff_node *p, int *line, int *col, int list) +{ + + for ( ; p; p = p->next) { + if (NODE_LINE & p->flags) + pline(p->line, line, col, list); + if (ROFFT_TEXT == p->type) + pstring(p->string, p->pos, col, list); + if (p->child) + pmdoc(p->child, line, col, list); + } +} + +static void +pman(const struct roff_node *p, int *line, int *col, int list) +{ + + for ( ; p; p = p->next) { + if (NODE_LINE & p->flags) + pline(p->line, line, col, list); + if (ROFFT_TEXT == p->type) + pstring(p->string, p->pos, col, list); + if (p->child) + pman(p->child, line, col, list); + } +} Property changes on: vendor/mandoc/20190723/demandoc.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/eqn.c =================================================================== --- vendor/mandoc/20190723/eqn.c (nonexistent) +++ vendor/mandoc/20190723/eqn.c (revision 350350) @@ -0,0 +1,1124 @@ +/* $Id: eqn.c,v 1.83 2018/12/14 06:33:14 schwarze Exp $ */ +/* + * Copyright (c) 2011, 2014 Kristaps Dzonsons + * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "roff.h" +#include "eqn.h" +#include "libmandoc.h" +#include "eqn_parse.h" + +#define EQN_NEST_MAX 128 /* maximum nesting of defines */ +#define STRNEQ(p1, sz1, p2, sz2) \ + ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1))) + +enum eqn_tok { + EQN_TOK_DYAD = 0, + EQN_TOK_VEC, + EQN_TOK_UNDER, + EQN_TOK_BAR, + EQN_TOK_TILDE, + EQN_TOK_HAT, + EQN_TOK_DOT, + EQN_TOK_DOTDOT, + EQN_TOK_FWD, + EQN_TOK_BACK, + EQN_TOK_DOWN, + EQN_TOK_UP, + EQN_TOK_FAT, + EQN_TOK_ROMAN, + EQN_TOK_ITALIC, + EQN_TOK_BOLD, + EQN_TOK_SIZE, + EQN_TOK_SUB, + EQN_TOK_SUP, + EQN_TOK_SQRT, + EQN_TOK_OVER, + EQN_TOK_FROM, + EQN_TOK_TO, + EQN_TOK_BRACE_OPEN, + EQN_TOK_BRACE_CLOSE, + EQN_TOK_GSIZE, + EQN_TOK_GFONT, + EQN_TOK_MARK, + EQN_TOK_LINEUP, + EQN_TOK_LEFT, + EQN_TOK_RIGHT, + EQN_TOK_PILE, + EQN_TOK_LPILE, + EQN_TOK_RPILE, + EQN_TOK_CPILE, + EQN_TOK_MATRIX, + EQN_TOK_CCOL, + EQN_TOK_LCOL, + EQN_TOK_RCOL, + EQN_TOK_DELIM, + EQN_TOK_DEFINE, + EQN_TOK_TDEFINE, + EQN_TOK_NDEFINE, + EQN_TOK_UNDEF, + EQN_TOK_ABOVE, + EQN_TOK__MAX, + EQN_TOK_FUNC, + EQN_TOK_QUOTED, + EQN_TOK_SYM, + EQN_TOK_EOF +}; + +static const char *eqn_toks[EQN_TOK__MAX] = { + "dyad", /* EQN_TOK_DYAD */ + "vec", /* EQN_TOK_VEC */ + "under", /* EQN_TOK_UNDER */ + "bar", /* EQN_TOK_BAR */ + "tilde", /* EQN_TOK_TILDE */ + "hat", /* EQN_TOK_HAT */ + "dot", /* EQN_TOK_DOT */ + "dotdot", /* EQN_TOK_DOTDOT */ + "fwd", /* EQN_TOK_FWD * */ + "back", /* EQN_TOK_BACK */ + "down", /* EQN_TOK_DOWN */ + "up", /* EQN_TOK_UP */ + "fat", /* EQN_TOK_FAT */ + "roman", /* EQN_TOK_ROMAN */ + "italic", /* EQN_TOK_ITALIC */ + "bold", /* EQN_TOK_BOLD */ + "size", /* EQN_TOK_SIZE */ + "sub", /* EQN_TOK_SUB */ + "sup", /* EQN_TOK_SUP */ + "sqrt", /* EQN_TOK_SQRT */ + "over", /* EQN_TOK_OVER */ + "from", /* EQN_TOK_FROM */ + "to", /* EQN_TOK_TO */ + "{", /* EQN_TOK_BRACE_OPEN */ + "}", /* EQN_TOK_BRACE_CLOSE */ + "gsize", /* EQN_TOK_GSIZE */ + "gfont", /* EQN_TOK_GFONT */ + "mark", /* EQN_TOK_MARK */ + "lineup", /* EQN_TOK_LINEUP */ + "left", /* EQN_TOK_LEFT */ + "right", /* EQN_TOK_RIGHT */ + "pile", /* EQN_TOK_PILE */ + "lpile", /* EQN_TOK_LPILE */ + "rpile", /* EQN_TOK_RPILE */ + "cpile", /* EQN_TOK_CPILE */ + "matrix", /* EQN_TOK_MATRIX */ + "ccol", /* EQN_TOK_CCOL */ + "lcol", /* EQN_TOK_LCOL */ + "rcol", /* EQN_TOK_RCOL */ + "delim", /* EQN_TOK_DELIM */ + "define", /* EQN_TOK_DEFINE */ + "tdefine", /* EQN_TOK_TDEFINE */ + "ndefine", /* EQN_TOK_NDEFINE */ + "undef", /* EQN_TOK_UNDEF */ + "above", /* EQN_TOK_ABOVE */ +}; + +static const char *const eqn_func[] = { + "acos", "acsc", "and", "arc", "asec", "asin", "atan", + "cos", "cosh", "coth", "csc", "det", "exp", "for", + "if", "lim", "ln", "log", "max", "min", + "sec", "sin", "sinh", "tan", "tanh", "Im", "Re", +}; + +enum eqn_symt { + EQNSYM_alpha = 0, + EQNSYM_beta, + EQNSYM_chi, + EQNSYM_delta, + EQNSYM_epsilon, + EQNSYM_eta, + EQNSYM_gamma, + EQNSYM_iota, + EQNSYM_kappa, + EQNSYM_lambda, + EQNSYM_mu, + EQNSYM_nu, + EQNSYM_omega, + EQNSYM_omicron, + EQNSYM_phi, + EQNSYM_pi, + EQNSYM_ps, + EQNSYM_rho, + EQNSYM_sigma, + EQNSYM_tau, + EQNSYM_theta, + EQNSYM_upsilon, + EQNSYM_xi, + EQNSYM_zeta, + EQNSYM_DELTA, + EQNSYM_GAMMA, + EQNSYM_LAMBDA, + EQNSYM_OMEGA, + EQNSYM_PHI, + EQNSYM_PI, + EQNSYM_PSI, + EQNSYM_SIGMA, + EQNSYM_THETA, + EQNSYM_UPSILON, + EQNSYM_XI, + EQNSYM_inter, + EQNSYM_union, + EQNSYM_prod, + EQNSYM_int, + EQNSYM_sum, + EQNSYM_grad, + EQNSYM_del, + EQNSYM_times, + EQNSYM_cdot, + EQNSYM_nothing, + EQNSYM_approx, + EQNSYM_prime, + EQNSYM_half, + EQNSYM_partial, + EQNSYM_inf, + EQNSYM_muchgreat, + EQNSYM_muchless, + EQNSYM_larrow, + EQNSYM_rarrow, + EQNSYM_pm, + EQNSYM_nequal, + EQNSYM_equiv, + EQNSYM_lessequal, + EQNSYM_moreequal, + EQNSYM_minus, + EQNSYM__MAX +}; + +struct eqnsym { + const char *str; + const char *sym; +}; + +static const struct eqnsym eqnsyms[EQNSYM__MAX] = { + { "alpha", "*a" }, /* EQNSYM_alpha */ + { "beta", "*b" }, /* EQNSYM_beta */ + { "chi", "*x" }, /* EQNSYM_chi */ + { "delta", "*d" }, /* EQNSYM_delta */ + { "epsilon", "*e" }, /* EQNSYM_epsilon */ + { "eta", "*y" }, /* EQNSYM_eta */ + { "gamma", "*g" }, /* EQNSYM_gamma */ + { "iota", "*i" }, /* EQNSYM_iota */ + { "kappa", "*k" }, /* EQNSYM_kappa */ + { "lambda", "*l" }, /* EQNSYM_lambda */ + { "mu", "*m" }, /* EQNSYM_mu */ + { "nu", "*n" }, /* EQNSYM_nu */ + { "omega", "*w" }, /* EQNSYM_omega */ + { "omicron", "*o" }, /* EQNSYM_omicron */ + { "phi", "*f" }, /* EQNSYM_phi */ + { "pi", "*p" }, /* EQNSYM_pi */ + { "psi", "*q" }, /* EQNSYM_psi */ + { "rho", "*r" }, /* EQNSYM_rho */ + { "sigma", "*s" }, /* EQNSYM_sigma */ + { "tau", "*t" }, /* EQNSYM_tau */ + { "theta", "*h" }, /* EQNSYM_theta */ + { "upsilon", "*u" }, /* EQNSYM_upsilon */ + { "xi", "*c" }, /* EQNSYM_xi */ + { "zeta", "*z" }, /* EQNSYM_zeta */ + { "DELTA", "*D" }, /* EQNSYM_DELTA */ + { "GAMMA", "*G" }, /* EQNSYM_GAMMA */ + { "LAMBDA", "*L" }, /* EQNSYM_LAMBDA */ + { "OMEGA", "*W" }, /* EQNSYM_OMEGA */ + { "PHI", "*F" }, /* EQNSYM_PHI */ + { "PI", "*P" }, /* EQNSYM_PI */ + { "PSI", "*Q" }, /* EQNSYM_PSI */ + { "SIGMA", "*S" }, /* EQNSYM_SIGMA */ + { "THETA", "*H" }, /* EQNSYM_THETA */ + { "UPSILON", "*U" }, /* EQNSYM_UPSILON */ + { "XI", "*C" }, /* EQNSYM_XI */ + { "inter", "ca" }, /* EQNSYM_inter */ + { "union", "cu" }, /* EQNSYM_union */ + { "prod", "product" }, /* EQNSYM_prod */ + { "int", "integral" }, /* EQNSYM_int */ + { "sum", "sum" }, /* EQNSYM_sum */ + { "grad", "gr" }, /* EQNSYM_grad */ + { "del", "gr" }, /* EQNSYM_del */ + { "times", "mu" }, /* EQNSYM_times */ + { "cdot", "pc" }, /* EQNSYM_cdot */ + { "nothing", "&" }, /* EQNSYM_nothing */ + { "approx", "~~" }, /* EQNSYM_approx */ + { "prime", "fm" }, /* EQNSYM_prime */ + { "half", "12" }, /* EQNSYM_half */ + { "partial", "pd" }, /* EQNSYM_partial */ + { "inf", "if" }, /* EQNSYM_inf */ + { ">>", ">>" }, /* EQNSYM_muchgreat */ + { "<<", "<<" }, /* EQNSYM_muchless */ + { "<-", "<-" }, /* EQNSYM_larrow */ + { "->", "->" }, /* EQNSYM_rarrow */ + { "+-", "+-" }, /* EQNSYM_pm */ + { "!=", "!=" }, /* EQNSYM_nequal */ + { "==", "==" }, /* EQNSYM_equiv */ + { "<=", "<=" }, /* EQNSYM_lessequal */ + { ">=", ">=" }, /* EQNSYM_moreequal */ + { "-", "mi" }, /* EQNSYM_minus */ +}; + +enum parse_mode { + MODE_QUOTED, + MODE_NOSUB, + MODE_SUB, + MODE_TOK +}; + +struct eqn_def { + char *key; + size_t keysz; + char *val; + size_t valsz; +}; + +static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *); +static struct eqn_box *eqn_box_makebinary(struct eqn_node *, + struct eqn_box *); +static void eqn_def(struct eqn_node *); +static struct eqn_def *eqn_def_find(struct eqn_node *); +static void eqn_delim(struct eqn_node *); +static enum eqn_tok eqn_next(struct eqn_node *, enum parse_mode); +static void eqn_undef(struct eqn_node *); + + +struct eqn_node * +eqn_alloc(void) +{ + struct eqn_node *ep; + + ep = mandoc_calloc(1, sizeof(*ep)); + ep->gsize = EQN_DEFSIZE; + return ep; +} + +void +eqn_reset(struct eqn_node *ep) +{ + free(ep->data); + ep->data = ep->start = ep->end = NULL; + ep->sz = ep->toksz = 0; +} + +void +eqn_read(struct eqn_node *ep, const char *p) +{ + char *cp; + + if (ep->data == NULL) { + ep->sz = strlen(p); + ep->data = mandoc_strdup(p); + } else { + ep->sz = mandoc_asprintf(&cp, "%s %s", ep->data, p); + free(ep->data); + ep->data = cp; + } + ep->sz += 1; +} + +/* + * Find the key "key" of the give size within our eqn-defined values. + */ +static struct eqn_def * +eqn_def_find(struct eqn_node *ep) +{ + int i; + + for (i = 0; i < (int)ep->defsz; i++) + if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key, + ep->defs[i].keysz, ep->start, ep->toksz)) + return &ep->defs[i]; + + return NULL; +} + +/* + * Parse a token from the input text. The modes are: + * MODE_QUOTED: Use *ep->start as the delimiter; the token ends + * before its next occurence. Do not interpret the token in any + * way and return EQN_TOK_QUOTED. All other modes behave like + * MODE_QUOTED when *ep->start is '"'. + * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it; + * otherwise, it ends before the next whitespace or brace. + * Do not interpret the token and return EQN_TOK__MAX. + * MODE_SUB: Like MODE_NOSUB, but try to interpret the token as an + * alias created with define. If it is an alias, replace it with + * its string value and reparse. + * MODE_TOK: Like MODE_SUB, but also check the token against the list + * of tokens, and if there is a match, return that token. Otherwise, + * if the token matches a symbol, return EQN_TOK_SYM; if it matches + * a function name, EQN_TOK_FUNC, or else EQN_TOK__MAX. Except for + * a token match, *ep->start is set to an allocated string that the + * caller is expected to free. + * All modes skip whitespace following the end of the token. + */ +static enum eqn_tok +eqn_next(struct eqn_node *ep, enum parse_mode mode) +{ + static int last_len, lim; + + struct eqn_def *def; + size_t start; + int diff, i, quoted; + enum eqn_tok tok; + + /* + * Reset the recursion counter after advancing + * beyond the end of the previous substitution. + */ + if (ep->end - ep->data >= last_len) + lim = 0; + + ep->start = ep->end; + quoted = mode == MODE_QUOTED; + for (;;) { + switch (*ep->start) { + case '\0': + ep->toksz = 0; + return EQN_TOK_EOF; + case '"': + quoted = 1; + break; + default: + break; + } + if (quoted) { + ep->end = strchr(ep->start + 1, *ep->start); + ep->start++; /* Skip opening quote. */ + if (ep->end == NULL) { + mandoc_msg(MANDOCERR_ARG_QUOTE, + ep->node->line, ep->node->pos, NULL); + ep->end = strchr(ep->start, '\0'); + } + } else { + ep->end = ep->start + 1; + if (*ep->start != '{' && *ep->start != '}') + ep->end += strcspn(ep->end, " ^~\"{}\t"); + } + ep->toksz = ep->end - ep->start; + if (quoted && *ep->end != '\0') + ep->end++; /* Skip closing quote. */ + while (*ep->end != '\0' && strchr(" \t^~", *ep->end) != NULL) + ep->end++; + if (quoted) /* Cannot return, may have to strndup. */ + break; + if (mode == MODE_NOSUB) + return EQN_TOK__MAX; + if ((def = eqn_def_find(ep)) == NULL) + break; + if (++lim > EQN_NEST_MAX) { + mandoc_msg(MANDOCERR_ROFFLOOP, + ep->node->line, ep->node->pos, NULL); + return EQN_TOK_EOF; + } + + /* Replace a defined name with its string value. */ + if ((diff = def->valsz - ep->toksz) > 0) { + start = ep->start - ep->data; + ep->sz += diff; + ep->data = mandoc_realloc(ep->data, ep->sz + 1); + ep->start = ep->data + start; + } + if (diff) + memmove(ep->start + def->valsz, ep->start + ep->toksz, + strlen(ep->start + ep->toksz) + 1); + memcpy(ep->start, def->val, def->valsz); + last_len = ep->start - ep->data + def->valsz; + } + if (mode != MODE_TOK) + return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX; + if (quoted) { + ep->start = mandoc_strndup(ep->start, ep->toksz); + return EQN_TOK_QUOTED; + } + for (tok = 0; tok < EQN_TOK__MAX; tok++) + if (STRNEQ(ep->start, ep->toksz, + eqn_toks[tok], strlen(eqn_toks[tok]))) + return tok; + + for (i = 0; i < EQNSYM__MAX; i++) { + if (STRNEQ(ep->start, ep->toksz, + eqnsyms[i].str, strlen(eqnsyms[i].str))) { + mandoc_asprintf(&ep->start, + "\\[%s]", eqnsyms[i].sym); + return EQN_TOK_SYM; + } + } + ep->start = mandoc_strndup(ep->start, ep->toksz); + for (i = 0; i < (int)(sizeof(eqn_func)/sizeof(*eqn_func)); i++) + if (STRNEQ(ep->start, ep->toksz, + eqn_func[i], strlen(eqn_func[i]))) + return EQN_TOK_FUNC; + return EQN_TOK__MAX; +} + +void +eqn_box_free(struct eqn_box *bp) +{ + if (bp == NULL) + return; + + if (bp->first) + eqn_box_free(bp->first); + if (bp->next) + eqn_box_free(bp->next); + + free(bp->text); + free(bp->left); + free(bp->right); + free(bp->top); + free(bp->bottom); + free(bp); +} + +struct eqn_box * +eqn_box_new(void) +{ + struct eqn_box *bp; + + bp = mandoc_calloc(1, sizeof(*bp)); + bp->expectargs = UINT_MAX; + return bp; +} + +/* + * Allocate a box as the last child of the parent node. + */ +static struct eqn_box * +eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent) +{ + struct eqn_box *bp; + + bp = eqn_box_new(); + bp->parent = parent; + bp->parent->args++; + bp->font = bp->parent->font; + bp->size = ep->gsize; + + if (NULL != parent->first) { + parent->last->next = bp; + bp->prev = parent->last; + } else + parent->first = bp; + + parent->last = bp; + return bp; +} + +/* + * Reparent the current last node (of the current parent) under a new + * EQN_SUBEXPR as the first element. + * Then return the new parent. + * The new EQN_SUBEXPR will have a two-child limit. + */ +static struct eqn_box * +eqn_box_makebinary(struct eqn_node *ep, struct eqn_box *parent) +{ + struct eqn_box *b, *newb; + + assert(NULL != parent->last); + b = parent->last; + if (parent->last == parent->first) + parent->first = NULL; + parent->args--; + parent->last = b->prev; + b->prev = NULL; + newb = eqn_box_alloc(ep, parent); + newb->type = EQN_SUBEXPR; + newb->expectargs = 2; + newb->args = 1; + newb->first = newb->last = b; + newb->first->next = NULL; + b->parent = newb; + return newb; +} + +/* + * Parse the "delim" control statement. + */ +static void +eqn_delim(struct eqn_node *ep) +{ + if (ep->end[0] == '\0' || ep->end[1] == '\0') { + mandoc_msg(MANDOCERR_REQ_EMPTY, + ep->node->line, ep->node->pos, "delim"); + if (ep->end[0] != '\0') + ep->end++; + } else if (strncmp(ep->end, "off", 3) == 0) { + ep->delim = 0; + ep->end += 3; + } else if (strncmp(ep->end, "on", 2) == 0) { + if (ep->odelim && ep->cdelim) + ep->delim = 1; + ep->end += 2; + } else { + ep->odelim = *ep->end++; + ep->cdelim = *ep->end++; + ep->delim = 1; + } +} + +/* + * Undefine a previously-defined string. + */ +static void +eqn_undef(struct eqn_node *ep) +{ + struct eqn_def *def; + + if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) { + mandoc_msg(MANDOCERR_REQ_EMPTY, + ep->node->line, ep->node->pos, "undef"); + return; + } + if ((def = eqn_def_find(ep)) == NULL) + return; + free(def->key); + free(def->val); + def->key = def->val = NULL; + def->keysz = def->valsz = 0; +} + +static void +eqn_def(struct eqn_node *ep) +{ + struct eqn_def *def; + int i; + + if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) { + mandoc_msg(MANDOCERR_REQ_EMPTY, + ep->node->line, ep->node->pos, "define"); + return; + } + + /* + * Search for a key that already exists. + * Create a new key if none is found. + */ + if ((def = eqn_def_find(ep)) == NULL) { + /* Find holes in string array. */ + for (i = 0; i < (int)ep->defsz; i++) + if (0 == ep->defs[i].keysz) + break; + + if (i == (int)ep->defsz) { + ep->defsz++; + ep->defs = mandoc_reallocarray(ep->defs, + ep->defsz, sizeof(struct eqn_def)); + ep->defs[i].key = ep->defs[i].val = NULL; + } + + def = ep->defs + i; + free(def->key); + def->key = mandoc_strndup(ep->start, ep->toksz); + def->keysz = ep->toksz; + } + + if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) { + mandoc_msg(MANDOCERR_REQ_EMPTY, + ep->node->line, ep->node->pos, "define %s", def->key); + free(def->key); + free(def->val); + def->key = def->val = NULL; + def->keysz = def->valsz = 0; + return; + } + free(def->val); + def->val = mandoc_strndup(ep->start, ep->toksz); + def->valsz = ep->toksz; +} + +void +eqn_parse(struct eqn_node *ep) +{ + struct eqn_box *cur, *nbox, *parent, *split; + const char *cp, *cpn; + char *p; + enum eqn_tok tok; + enum { CCL_LET, CCL_DIG, CCL_PUN } ccl, ccln; + int size; + + parent = ep->node->eqn; + assert(parent != NULL); + + /* + * Empty equation. + * Do not add it to the high-level syntax tree. + */ + + if (ep->data == NULL) + return; + + ep->start = ep->end = ep->data + strspn(ep->data, " ^~"); + +next_tok: + tok = eqn_next(ep, MODE_TOK); + switch (tok) { + case EQN_TOK_UNDEF: + eqn_undef(ep); + break; + case EQN_TOK_NDEFINE: + case EQN_TOK_DEFINE: + eqn_def(ep); + break; + case EQN_TOK_TDEFINE: + if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF || + eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) + mandoc_msg(MANDOCERR_REQ_EMPTY, + ep->node->line, ep->node->pos, "tdefine"); + break; + case EQN_TOK_DELIM: + eqn_delim(ep); + break; + case EQN_TOK_GFONT: + if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + break; + case EQN_TOK_MARK: + case EQN_TOK_LINEUP: + /* Ignore these. */ + break; + case EQN_TOK_DYAD: + case EQN_TOK_VEC: + case EQN_TOK_UNDER: + case EQN_TOK_BAR: + case EQN_TOK_TILDE: + case EQN_TOK_HAT: + case EQN_TOK_DOT: + case EQN_TOK_DOTDOT: + if (parent->last == NULL) { + mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + cur = eqn_box_alloc(ep, parent); + cur->type = EQN_TEXT; + cur->text = mandoc_strdup(""); + } + parent = eqn_box_makebinary(ep, parent); + parent->type = EQN_LIST; + parent->expectargs = 1; + parent->font = EQNFONT_ROMAN; + switch (tok) { + case EQN_TOK_DOTDOT: + parent->top = mandoc_strdup("\\[ad]"); + break; + case EQN_TOK_VEC: + parent->top = mandoc_strdup("\\[->]"); + break; + case EQN_TOK_DYAD: + parent->top = mandoc_strdup("\\[<>]"); + break; + case EQN_TOK_TILDE: + parent->top = mandoc_strdup("\\[a~]"); + break; + case EQN_TOK_UNDER: + parent->bottom = mandoc_strdup("\\[ul]"); + break; + case EQN_TOK_BAR: + parent->top = mandoc_strdup("\\[rn]"); + break; + case EQN_TOK_DOT: + parent->top = mandoc_strdup("\\[a.]"); + break; + case EQN_TOK_HAT: + parent->top = mandoc_strdup("\\[ha]"); + break; + default: + abort(); + } + parent = parent->parent; + break; + case EQN_TOK_FWD: + case EQN_TOK_BACK: + case EQN_TOK_DOWN: + case EQN_TOK_UP: + if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + break; + case EQN_TOK_FAT: + case EQN_TOK_ROMAN: + case EQN_TOK_ITALIC: + case EQN_TOK_BOLD: + while (parent->args == parent->expectargs) + parent = parent->parent; + /* + * These values apply to the next word or sequence of + * words; thus, we mark that we'll have a child with + * exactly one of those. + */ + parent = eqn_box_alloc(ep, parent); + parent->type = EQN_LIST; + parent->expectargs = 1; + switch (tok) { + case EQN_TOK_FAT: + parent->font = EQNFONT_FAT; + break; + case EQN_TOK_ROMAN: + parent->font = EQNFONT_ROMAN; + break; + case EQN_TOK_ITALIC: + parent->font = EQNFONT_ITALIC; + break; + case EQN_TOK_BOLD: + parent->font = EQNFONT_BOLD; + break; + default: + abort(); + } + break; + case EQN_TOK_SIZE: + case EQN_TOK_GSIZE: + /* Accept two values: integral size and a single. */ + if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + break; + } + size = mandoc_strntoi(ep->start, ep->toksz, 10); + if (-1 == size) { + mandoc_msg(MANDOCERR_IT_NONUM, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + break; + } + if (EQN_TOK_GSIZE == tok) { + ep->gsize = size; + break; + } + while (parent->args == parent->expectargs) + parent = parent->parent; + parent = eqn_box_alloc(ep, parent); + parent->type = EQN_LIST; + parent->expectargs = 1; + parent->size = size; + break; + case EQN_TOK_FROM: + case EQN_TOK_TO: + case EQN_TOK_SUB: + case EQN_TOK_SUP: + /* + * We have a left-right-associative expression. + * Repivot under a positional node, open a child scope + * and keep on reading. + */ + if (parent->last == NULL) { + mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + cur = eqn_box_alloc(ep, parent); + cur->type = EQN_TEXT; + cur->text = mandoc_strdup(""); + } + while (parent->expectargs == 1 && parent->args == 1) + parent = parent->parent; + if (tok == EQN_TOK_FROM || tok == EQN_TOK_TO) { + for (cur = parent; cur != NULL; cur = cur->parent) + if (cur->pos == EQNPOS_SUB || + cur->pos == EQNPOS_SUP || + cur->pos == EQNPOS_SUBSUP || + cur->pos == EQNPOS_SQRT || + cur->pos == EQNPOS_OVER) + break; + if (cur != NULL) + parent = cur->parent; + } + if (tok == EQN_TOK_SUP && parent->pos == EQNPOS_SUB) { + parent->expectargs = 3; + parent->pos = EQNPOS_SUBSUP; + break; + } + if (tok == EQN_TOK_TO && parent->pos == EQNPOS_FROM) { + parent->expectargs = 3; + parent->pos = EQNPOS_FROMTO; + break; + } + parent = eqn_box_makebinary(ep, parent); + switch (tok) { + case EQN_TOK_FROM: + parent->pos = EQNPOS_FROM; + break; + case EQN_TOK_TO: + parent->pos = EQNPOS_TO; + break; + case EQN_TOK_SUP: + parent->pos = EQNPOS_SUP; + break; + case EQN_TOK_SUB: + parent->pos = EQNPOS_SUB; + break; + default: + abort(); + } + break; + case EQN_TOK_SQRT: + while (parent->args == parent->expectargs) + parent = parent->parent; + /* + * Accept a left-right-associative set of arguments just + * like sub and sup and friends but without rebalancing + * under a pivot. + */ + parent = eqn_box_alloc(ep, parent); + parent->type = EQN_SUBEXPR; + parent->pos = EQNPOS_SQRT; + parent->expectargs = 1; + break; + case EQN_TOK_OVER: + /* + * We have a right-left-associative fraction. + * Close out anything that's currently open, then + * rebalance and continue reading. + */ + if (parent->last == NULL) { + mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + cur = eqn_box_alloc(ep, parent); + cur->type = EQN_TEXT; + cur->text = mandoc_strdup(""); + } + while (parent->args == parent->expectargs) + parent = parent->parent; + while (EQN_SUBEXPR == parent->type) + parent = parent->parent; + parent = eqn_box_makebinary(ep, parent); + parent->pos = EQNPOS_OVER; + break; + case EQN_TOK_RIGHT: + case EQN_TOK_BRACE_CLOSE: + /* + * Close out the existing brace. + * FIXME: this is a shitty sentinel: we should really + * have a native EQN_BRACE type or whatnot. + */ + for (cur = parent; cur != NULL; cur = cur->parent) + if (cur->type == EQN_LIST && + cur->expectargs > 1 && + (tok == EQN_TOK_BRACE_CLOSE || + cur->left != NULL)) + break; + if (cur == NULL) { + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + break; + } + parent = cur; + if (EQN_TOK_RIGHT == tok) { + if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { + mandoc_msg(MANDOCERR_REQ_EMPTY, + ep->node->line, ep->node->pos, + "%s", eqn_toks[tok]); + break; + } + /* Handling depends on right/left. */ + if (STRNEQ(ep->start, ep->toksz, "ceiling", 7)) + parent->right = mandoc_strdup("\\[rc]"); + else if (STRNEQ(ep->start, ep->toksz, "floor", 5)) + parent->right = mandoc_strdup("\\[rf]"); + else + parent->right = + mandoc_strndup(ep->start, ep->toksz); + } + parent = parent->parent; + if (tok == EQN_TOK_BRACE_CLOSE && + (parent->type == EQN_PILE || + parent->type == EQN_MATRIX)) + parent = parent->parent; + /* Close out any "singleton" lists. */ + while (parent->type == EQN_LIST && + parent->expectargs == 1 && + parent->args == 1) + parent = parent->parent; + break; + case EQN_TOK_BRACE_OPEN: + case EQN_TOK_LEFT: + /* + * If we already have something in the stack and we're + * in an expression, then rewind til we're not any more + * (just like with the text node). + */ + while (parent->args == parent->expectargs) + parent = parent->parent; + if (EQN_TOK_LEFT == tok && + eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) { + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + break; + } + parent = eqn_box_alloc(ep, parent); + parent->type = EQN_LIST; + if (EQN_TOK_LEFT == tok) { + if (STRNEQ(ep->start, ep->toksz, "ceiling", 7)) + parent->left = mandoc_strdup("\\[lc]"); + else if (STRNEQ(ep->start, ep->toksz, "floor", 5)) + parent->left = mandoc_strdup("\\[lf]"); + else + parent->left = + mandoc_strndup(ep->start, ep->toksz); + } + break; + case EQN_TOK_PILE: + case EQN_TOK_LPILE: + case EQN_TOK_RPILE: + case EQN_TOK_CPILE: + case EQN_TOK_CCOL: + case EQN_TOK_LCOL: + case EQN_TOK_RCOL: + while (parent->args == parent->expectargs) + parent = parent->parent; + parent = eqn_box_alloc(ep, parent); + parent->type = EQN_PILE; + parent->expectargs = 1; + break; + case EQN_TOK_ABOVE: + for (cur = parent; cur != NULL; cur = cur->parent) + if (cur->type == EQN_PILE) + break; + if (cur == NULL) { + mandoc_msg(MANDOCERR_IT_STRAY, ep->node->line, + ep->node->pos, "%s", eqn_toks[tok]); + break; + } + parent = eqn_box_alloc(ep, cur); + parent->type = EQN_LIST; + break; + case EQN_TOK_MATRIX: + while (parent->args == parent->expectargs) + parent = parent->parent; + parent = eqn_box_alloc(ep, parent); + parent->type = EQN_MATRIX; + parent->expectargs = 1; + break; + case EQN_TOK_EOF: + return; + case EQN_TOK__MAX: + case EQN_TOK_FUNC: + case EQN_TOK_QUOTED: + case EQN_TOK_SYM: + p = ep->start; + assert(p != NULL); + /* + * If we already have something in the stack and we're + * in an expression, then rewind til we're not any more. + */ + while (parent->args == parent->expectargs) + parent = parent->parent; + cur = eqn_box_alloc(ep, parent); + cur->type = EQN_TEXT; + cur->text = p; + switch (tok) { + case EQN_TOK_FUNC: + cur->font = EQNFONT_ROMAN; + break; + case EQN_TOK_QUOTED: + if (cur->font == EQNFONT_NONE) + cur->font = EQNFONT_ITALIC; + break; + case EQN_TOK_SYM: + break; + default: + if (cur->font != EQNFONT_NONE || *p == '\0') + break; + cpn = p - 1; + ccln = CCL_LET; + split = NULL; + for (;;) { + /* Advance to next character. */ + cp = cpn++; + ccl = ccln; + ccln = isalpha((unsigned char)*cpn) ? CCL_LET : + isdigit((unsigned char)*cpn) || + (*cpn == '.' && (ccl == CCL_DIG || + isdigit((unsigned char)cpn[1]))) ? + CCL_DIG : CCL_PUN; + /* No boundary before first character. */ + if (cp < p) + continue; + cur->font = ccl == CCL_LET ? + EQNFONT_ITALIC : EQNFONT_ROMAN; + if (*cp == '\\') + mandoc_escape(&cpn, NULL, NULL); + /* No boundary after last character. */ + if (*cpn == '\0') + break; + if (ccln == ccl && *cp != ',' && *cpn != ',') + continue; + /* Boundary found, split the text. */ + if (parent->args == parent->expectargs) { + /* Remove the text from the tree. */ + if (cur->prev == NULL) + parent->first = cur->next; + else + cur->prev->next = NULL; + parent->last = cur->prev; + parent->args--; + /* Set up a list instead. */ + split = eqn_box_alloc(ep, parent); + split->type = EQN_LIST; + /* Insert the word into the list. */ + split->first = split->last = cur; + cur->parent = split; + cur->prev = NULL; + parent = split; + } + /* Append a new text box. */ + nbox = eqn_box_alloc(ep, parent); + nbox->type = EQN_TEXT; + nbox->text = mandoc_strdup(cpn); + /* Truncate the old box. */ + p = mandoc_strndup(cur->text, + cpn - cur->text); + free(cur->text); + cur->text = p; + /* Setup to process the new box. */ + cur = nbox; + p = nbox->text; + cpn = p - 1; + ccln = CCL_LET; + } + if (split != NULL) + parent = split->parent; + break; + } + break; + default: + abort(); + } + goto next_tok; +} + +void +eqn_free(struct eqn_node *p) +{ + int i; + + if (p == NULL) + return; + + for (i = 0; i < (int)p->defsz; i++) { + free(p->defs[i].key); + free(p->defs[i].val); + } + + free(p->data); + free(p->defs); + free(p); +} Property changes on: vendor/mandoc/20190723/eqn.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/eqn.h =================================================================== --- vendor/mandoc/20190723/eqn.h (nonexistent) +++ vendor/mandoc/20190723/eqn.h (revision 350350) @@ -0,0 +1,72 @@ +/* $Id: eqn.h,v 1.1 2018/12/13 05:23:38 schwarze Exp $ */ +/* + * Copyright (c) 2011, 2014 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Public data types for eqn(7) syntax trees. + */ + +enum eqn_boxt { + EQN_TEXT, /* Text, e.g. number, variable, operator, ... */ + EQN_SUBEXPR, /* Nested eqn(7) subexpression. */ + EQN_LIST, /* List, for example in braces. */ + EQN_PILE, /* Vertical pile. */ + EQN_MATRIX /* List of columns. */ +}; + +enum eqn_fontt { + EQNFONT_NONE = 0, + EQNFONT_ROMAN, + EQNFONT_BOLD, + EQNFONT_FAT, + EQNFONT_ITALIC, + EQNFONT__MAX +}; + +enum eqn_post { + EQNPOS_NONE = 0, + EQNPOS_SUP, + EQNPOS_SUBSUP, + EQNPOS_SUB, + EQNPOS_TO, + EQNPOS_FROM, + EQNPOS_FROMTO, + EQNPOS_OVER, + EQNPOS_SQRT, + EQNPOS__MAX +}; + + /* + * A "box" is a parsed mathematical expression as defined by the eqn.7 + * grammar. + */ +struct eqn_box { + struct eqn_box *parent; + struct eqn_box *prev; + struct eqn_box *next; + struct eqn_box *first; /* First child node. */ + struct eqn_box *last; /* Last child node. */ + char *text; /* Text (or NULL). */ + char *left; /* Left-hand fence. */ + char *right; /* Right-hand fence. */ + char *top; /* Symbol above. */ + char *bottom; /* Symbol below. */ + size_t expectargs; /* Maximal number of arguments. */ + size_t args; /* Actual number of arguments. */ + int size; /* Font size. */ +#define EQN_DEFSIZE INT_MIN + enum eqn_boxt type; /* Type of node. */ + enum eqn_fontt font; /* Font in this box. */ + enum eqn_post pos; /* Position of the next box. */ +}; Property changes on: vendor/mandoc/20190723/eqn.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/eqn_parse.h =================================================================== --- vendor/mandoc/20190723/eqn_parse.h (nonexistent) +++ vendor/mandoc/20190723/eqn_parse.h (revision 350350) @@ -0,0 +1,48 @@ +/* $Id: eqn_parse.h,v 1.3 2018/12/14 06:33:14 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2014, 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. + * + * External interface of the eqn(7) parser. + * For use in the roff(7) and eqn(7) parsers only. + */ + +struct roff_node; +struct eqn_box; +struct eqn_def; + +struct eqn_node { + struct roff_node *node; /* Syntax tree of this equation. */ + struct eqn_def *defs; /* Array of definitions. */ + char *data; /* Source code of this equation. */ + char *start; /* First byte of the current token. */ + char *end; /* First byte of the next token. */ + size_t defsz; /* Number of definitions. */ + size_t sz; /* Length of the source code. */ + size_t toksz; /* Length of the current token. */ + int gsize; /* Default point size. */ + int delim; /* In-line delimiters enabled. */ + char odelim; /* In-line opening delimiter. */ + char cdelim; /* In-line closing delimiter. */ +}; + + +struct eqn_node *eqn_alloc(void); +struct eqn_box *eqn_box_new(void); +void eqn_box_free(struct eqn_box *); +void eqn_free(struct eqn_node *); +void eqn_parse(struct eqn_node *); +void eqn_read(struct eqn_node *, const char *); +void eqn_reset(struct eqn_node *); Property changes on: vendor/mandoc/20190723/eqn_parse.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/eqn_term.c =================================================================== --- vendor/mandoc/20190723/eqn_term.c (nonexistent) +++ vendor/mandoc/20190723/eqn_term.c (revision 350350) @@ -0,0 +1,174 @@ +/* $Id: eqn_term.c,v 1.19 2018/12/13 05:23:38 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include "eqn.h" +#include "out.h" +#include "term.h" + +static const enum termfont fontmap[EQNFONT__MAX] = { + TERMFONT_NONE, /* EQNFONT_NONE */ + TERMFONT_NONE, /* EQNFONT_ROMAN */ + TERMFONT_BOLD, /* EQNFONT_BOLD */ + TERMFONT_BOLD, /* EQNFONT_FAT */ + TERMFONT_UNDER /* EQNFONT_ITALIC */ +}; + +static void eqn_box(struct termp *, const struct eqn_box *); + + +void +term_eqn(struct termp *p, const struct eqn_box *bp) +{ + + eqn_box(p, bp); + p->flags &= ~TERMP_NOSPACE; +} + +static void +eqn_box(struct termp *p, const struct eqn_box *bp) +{ + const struct eqn_box *child; + const char *cp; + int delim; + + /* Delimiters around this box? */ + + if ((bp->type == EQN_LIST && bp->expectargs > 1) || + (bp->type == EQN_PILE && (bp->prev || bp->next)) || + (bp->parent != NULL && (bp->parent->pos == EQNPOS_SQRT || + /* Diacritic followed by ^ or _. */ + ((bp->top != NULL || bp->bottom != NULL) && + bp->parent->type == EQN_SUBEXPR && + bp->parent->pos != EQNPOS_OVER && bp->next != NULL) || + /* Nested over, sub, sup, from, to. */ + (bp->type == EQN_SUBEXPR && bp->pos != EQNPOS_SQRT && + ((bp->parent->type == EQN_LIST && bp->expectargs == 1) || + (bp->parent->type == EQN_SUBEXPR && + bp->pos != EQNPOS_SQRT)))))) { + if ((bp->parent->type == EQN_SUBEXPR && bp->prev != NULL) || + (bp->type == EQN_LIST && + bp->first != NULL && + bp->first->type != EQN_PILE && + bp->first->type != EQN_MATRIX && + bp->prev != NULL && + (bp->prev->type == EQN_LIST || + (bp->prev->type == EQN_TEXT && + (*bp->prev->text == '\\' || + isalpha((unsigned char)*bp->prev->text)))))) + p->flags |= TERMP_NOSPACE; + term_word(p, bp->left != NULL ? bp->left : "("); + p->flags |= TERMP_NOSPACE; + delim = 1; + } else + delim = 0; + + /* Handle Fonts and text. */ + + if (bp->font != EQNFONT_NONE) + term_fontpush(p, fontmap[(int)bp->font]); + + if (bp->text != NULL) { + if (strchr("!\"'),.:;?]}", *bp->text) != NULL) + p->flags |= TERMP_NOSPACE; + term_word(p, bp->text); + if ((cp = strchr(bp->text, '\0')) > bp->text && + (strchr("\"'([{", cp[-1]) != NULL || + (bp->prev == NULL && (cp[-1] == '-' || + (cp >= bp->text + 5 && + strcmp(cp - 5, "\\[mi]") == 0))))) + p->flags |= TERMP_NOSPACE; + } + + /* Special box types. */ + + if (bp->pos == EQNPOS_SQRT) { + term_word(p, "\\(sr"); + if (bp->first != NULL) { + p->flags |= TERMP_NOSPACE; + eqn_box(p, bp->first); + } + } else if (bp->type == EQN_SUBEXPR) { + child = bp->first; + eqn_box(p, child); + p->flags |= TERMP_NOSPACE; + term_word(p, bp->pos == EQNPOS_OVER ? "/" : + (bp->pos == EQNPOS_SUP || + bp->pos == EQNPOS_TO) ? "^" : "_"); + child = child->next; + if (child != NULL) { + p->flags |= TERMP_NOSPACE; + eqn_box(p, child); + if (bp->pos == EQNPOS_FROMTO || + bp->pos == EQNPOS_SUBSUP) { + p->flags |= TERMP_NOSPACE; + term_word(p, "^"); + p->flags |= TERMP_NOSPACE; + child = child->next; + if (child != NULL) + eqn_box(p, child); + } + } + } else { + child = bp->first; + if (bp->type == EQN_MATRIX && + child != NULL && + child->type == EQN_LIST && + child->expectargs > 1) + child = child->first; + while (child != NULL) { + eqn_box(p, + bp->type == EQN_PILE && + child->type == EQN_LIST && + child->expectargs > 1 && + child->args == 1 ? + child->first : child); + child = child->next; + } + } + + /* Handle Fonts and diacritics. */ + + if (bp->font != EQNFONT_NONE) + term_fontpop(p); + if (bp->top != NULL) { + p->flags |= TERMP_NOSPACE; + term_word(p, bp->top); + } + if (bp->bottom != NULL) { + p->flags |= TERMP_NOSPACE; + term_word(p, "_"); + } + + /* Right delimiter after this box? */ + + if (delim) { + p->flags |= TERMP_NOSPACE; + term_word(p, bp->right != NULL ? bp->right : ")"); + if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL) + p->flags |= TERMP_NOSPACE; + } +} Property changes on: vendor/mandoc/20190723/eqn_term.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/gmdiff =================================================================== --- vendor/mandoc/20190723/gmdiff (nonexistent) +++ vendor/mandoc/20190723/gmdiff (revision 350350) @@ -0,0 +1,57 @@ +#!/bin/sh +# Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +if [ `id -u` -eq 0 ]; then + echo "$0: do not run me as root" + exit 1 +fi + +if [ $# -eq 0 ]; then + echo "usage: $0 [-h|-u] manual_source_file ..." + exit 1 +fi + +if [ "X$1" = "X-h" ]; then + shift + export PATH="/usr/local/heirloom-doctools/bin:$PATH" + EQN="neqn" + ROFF="nroff" + MOPT="-Ios=BSD -Tascii $MOPT" + COLPIPE="col -b" +elif [ "X$1" = "X-u" ]; then + shift + ROFF="groff -ket -ww -Tutf8 -P -c" + MOPT="-Ios=OpenBSD -Wall -Tutf8 $MOPT" + COLPIPE="cat" +else + ROFF="groff -ket -ww -mtty-char -Tascii -P -c" + MOPT="-Ios=OpenBSD -Wall -Tascii $MOPT" + COLPIPE="cat" +fi + +while [ -n "$1" ]; do + file=$1 + shift + echo " ========== $file ========== " + $ROFF -mandoc $file | $COLPIPE 2> /tmp/roff.err > /tmp/roff.out + ${MANDOC:=mandoc} $MOPT $file | $COLPIPE \ + 2> /tmp/mandoc.err > /tmp/mandoc.out + for i in roff mandoc; do + [ -s /tmp/$i.err ] && echo "$i errors:" && cat /tmp/$i.err + done + diff -au $DIFFOPT /tmp/roff.out /tmp/mandoc.out 2>&1 +done + +exit 0 Index: vendor/mandoc/20190723/lib.c =================================================================== --- vendor/mandoc/20190723/lib.c (nonexistent) +++ vendor/mandoc/20190723/lib.c (revision 350350) @@ -0,0 +1,35 @@ +/* $Id: lib.c,v 1.15 2018/12/13 11:55:46 schwarze Exp $ */ +/* + * Copyright (c) 2009 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include +#include + +#include "roff.h" +#include "libmdoc.h" + +#define LINE(x, y) \ + if (0 == strcmp(p, x)) return(y); + +const char * +mdoc_a2lib(const char *p) +{ + +#include "lib.in" + + return NULL; +} Property changes on: vendor/mandoc/20190723/lib.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/libman.h =================================================================== --- vendor/mandoc/20190723/libman.h (nonexistent) +++ vendor/mandoc/20190723/libman.h (revision 350350) @@ -0,0 +1,42 @@ +/* $Id: libman.h,v 1.86 2018/12/31 10:04:39 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2014, 2015, 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. + */ + +struct roff_node; +struct roff_man; + +#define MACRO_PROT_ARGS struct roff_man *man, \ + enum roff_tok tok, \ + int line, \ + int ppos, \ + int *pos, \ + char *buf + +struct man_macro { + void (*fp)(MACRO_PROT_ARGS); + int flags; +#define MAN_BSCOPED (1 << 0) /* Optional next-line block scope. */ +#define MAN_ESCOPED (1 << 1) /* Optional next-line element scope. */ +#define MAN_NSCOPED (1 << 2) /* Allowed in next-line element scope. */ +#define MAN_XSCOPE (1 << 3) /* Exit next-line block scope. */ +#define MAN_JOIN (1 << 4) /* Join arguments together. */ +}; + +const struct man_macro *man_macro(enum roff_tok); + +void man_descope(struct roff_man *, int, int, char *); +void man_unscope(struct roff_man *, const struct roff_node *); Property changes on: vendor/mandoc/20190723/libman.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/libmandoc.h =================================================================== --- vendor/mandoc/20190723/libmandoc.h (nonexistent) +++ vendor/mandoc/20190723/libmandoc.h (revision 350350) @@ -0,0 +1,81 @@ +/* $Id: libmandoc.h,v 1.77 2018/12/21 17:15:18 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons + * 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. + */ + +/* + * Return codes passed from the roff parser to the main parser. + */ + +/* Main instruction: what to do with the returned line. */ +#define ROFF_IGN 0x000 /* Don't do anything with it. */ +#define ROFF_CONT 0x001 /* Give it to the high-level parser. */ +#define ROFF_RERUN 0x002 /* Re-run the roff parser with an offset. */ +#define ROFF_REPARSE 0x004 /* Recursively run the main parser on it. */ +#define ROFF_SO 0x008 /* Include the named file. */ +#define ROFF_MASK 0x00f /* Only one of these bits should be set. */ + +/* Options for further parsing, to be OR'ed with the above. */ +#define ROFF_APPEND 0x010 /* Append the next line to this one. */ +#define ROFF_USERCALL 0x020 /* Start execution of a new macro. */ +#define ROFF_USERRET 0x040 /* Abort execution of the current macro. */ +#define ROFF_WHILE 0x100 /* Start a new .while loop. */ +#define ROFF_LOOPCONT 0x200 /* Iterate the current .while loop. */ +#define ROFF_LOOPEXIT 0x400 /* Exit the current .while loop. */ +#define ROFF_LOOPMASK 0xf00 + + +struct buf { + char *buf; + size_t sz; + struct buf *next; +}; + + +struct roff; +struct roff_man; + +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(int); +void roff_reset(struct roff *); +void roff_man_free(struct roff_man *); +struct roff_man *roff_man_alloc(struct roff *, const char *, int); +void roff_man_reset(struct roff_man *); +int roff_parseln(struct roff *, int, struct buf *, int *); +void roff_userret(struct roff *); +void roff_endparse(struct roff *); +void roff_setreg(struct roff *, const char *, int, char sign); +int roff_getreg(struct roff *, const char *); +char *roff_strdup(const struct roff *, const char *); +char *roff_getarg(struct roff *, char **, int, int *); +int roff_getcontrol(const struct roff *, + const char *, int *); +int roff_getformat(const struct roff *); Property changes on: vendor/mandoc/20190723/libmandoc.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/libmdoc.h =================================================================== --- vendor/mandoc/20190723/libmdoc.h (nonexistent) +++ vendor/mandoc/20190723/libmdoc.h (revision 350350) @@ -0,0 +1,87 @@ +/* $Id: libmdoc.h,v 1.117 2018/12/31 04:55:46 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * 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. + */ + +struct roff_node; +struct roff_man; +struct mdoc_arg; + +#define MACRO_PROT_ARGS struct roff_man *mdoc, \ + enum roff_tok tok, \ + int line, \ + int ppos, \ + int *pos, \ + char *buf + +struct mdoc_macro { + void (*fp)(MACRO_PROT_ARGS); + int flags; +#define MDOC_CALLABLE (1 << 0) +#define MDOC_PARSED (1 << 1) +#define MDOC_EXPLICIT (1 << 2) +#define MDOC_PROLOGUE (1 << 3) +#define MDOC_IGNDELIM (1 << 4) +#define MDOC_JOIN (1 << 5) +}; + +enum margserr { + ARGS_ERROR, + ARGS_EOLN, /* end-of-line */ + ARGS_WORD, /* normal word */ + ARGS_ALLOC, /* normal word from roff_getarg() */ + ARGS_PUNCT, /* series of punctuation */ + ARGS_PHRASE /* Bl -column phrase */ +}; + +/* + * A punctuation delimiter is opening, closing, or "middle mark" + * punctuation. These govern spacing. + * Opening punctuation (e.g., the opening parenthesis) suppresses the + * following space; closing punctuation (e.g., the closing parenthesis) + * suppresses the leading space; middle punctuation (e.g., the vertical + * bar) can do either. The middle punctuation delimiter bends the rules + * depending on usage. + */ +enum mdelim { + DELIM_NONE = 0, + DELIM_OPEN, + DELIM_MIDDLE, + DELIM_CLOSE, + DELIM_MAX +}; + +const struct mdoc_macro *mdoc_macro(enum roff_tok); + +void mdoc_elem_alloc(struct roff_man *, int, int, + enum roff_tok, struct mdoc_arg *); +struct roff_node *mdoc_block_alloc(struct roff_man *, int, int, + enum roff_tok, struct mdoc_arg *); +void mdoc_tail_alloc(struct roff_man *, int, int, + enum roff_tok); +struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int, + enum roff_tok, struct roff_node *); +void mdoc_state(struct roff_man *, struct roff_node *); +const char *mdoc_a2arch(const char *); +const char *mdoc_a2att(const char *); +const char *mdoc_a2lib(const char *); +enum roff_sec mdoc_a2sec(const char *); +const char *mdoc_a2st(const char *); +void mdoc_argv(struct roff_man *, int, enum roff_tok, + struct mdoc_arg **, int *, char *); +enum margserr mdoc_args(struct roff_man *, int, + int *, char *, enum roff_tok, char **); +enum mdelim mdoc_isdelim(const char *); Property changes on: vendor/mandoc/20190723/libmdoc.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/main.h =================================================================== --- vendor/mandoc/20190723/main.h (nonexistent) +++ vendor/mandoc/20190723/main.h (revision 350350) @@ -0,0 +1,53 @@ +/* $Id: main.h,v 1.30 2019/03/03 13:02:11 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2014, 2015, 2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct roff_meta; +struct manoutput; + +/* + * Definitions for main.c-visible output device functions, e.g., -Thtml + * and -Tascii. Note that ascii_alloc() is named as such in + * anticipation of latin1_alloc() and so on, all of which map into the + * terminal output routines with different character settings. + */ + +void *html_alloc(const struct manoutput *); +void html_mdoc(void *, const struct roff_meta *); +void html_man(void *, const struct roff_meta *); +void html_reset(void *); +void html_free(void *); + +void tree_mdoc(void *, const struct roff_meta *); +void tree_man(void *, const struct roff_meta *); + +void man_mdoc(void *, const struct roff_meta *); + +void *locale_alloc(const struct manoutput *); +void *utf8_alloc(const struct manoutput *); +void *ascii_alloc(const struct manoutput *); +void ascii_free(void *); + +void *pdf_alloc(const struct manoutput *); +void *ps_alloc(const struct manoutput *); +void pspdf_free(void *); + +void terminal_mdoc(void *, const struct roff_meta *); +void terminal_man(void *, const struct roff_meta *); +void terminal_sepline(void *); + +void markdown_mdoc(void *, const struct roff_meta *); Property changes on: vendor/mandoc/20190723/main.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/man.1 =================================================================== --- vendor/mandoc/20190723/man.1 (nonexistent) +++ vendor/mandoc/20190723/man.1 (revision 350350) @@ -0,0 +1,415 @@ +.\" $Id: man.1,v 1.35 2019/03/09 15:55:01 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-2018 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: March 9 2019 $ +.Dt MAN 1 +.Os +.Sh NAME +.Nm man +.Nd display manual pages +.Sh SYNOPSIS +.Nm man +.Op Fl acfhklw +.Op Fl C Ar file +.Op Fl M Ar path +.Op Fl m Ar path +.Op Fl S Ar subsection +.Op Oo Fl s Oc Ar section +.Ar name ... +.Sh DESCRIPTION +The +.Nm +utility +displays the +manual pages entitled +.Ar name . +Pages may be selected according to +a specific category +.Pq Ar section +or +machine architecture +.Pq Ar subsection . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +Display all matching manual pages. +Normally, only the first page found is displayed. +.It Fl C Ar file +Use the specified +.Ar file +instead of the default configuration file. +This permits users to configure their own manual environment. +See +.Xr man.conf 5 +for a description of the contents of this file. +.It Fl c +Copy the manual page to the standard output instead of using +.Xr more 1 +to paginate it. +This is done by default if the standard output is not a terminal device. +.Pp +When using +.Fl c , +most terminal devices are unable to show the markup. +To print the output of +.Nm +to the terminal with markup but without using a pager, pipe it to +.Xr ul 1 . +To remove the markup, pipe the output to +.Xr col 1 +.Fl b +instead. +.It Fl f +A synonym for +.Xr whatis 1 . +It searches for +.Ar name +in manual page names and displays the header lines from all matching pages. +The search is case insensitive and matches whole words only. +.It Fl h +Display only the SYNOPSIS lines of the requested manual pages. +Implies +.Fl a +and +.Fl c . +.It Fl k +A synonym for +.Xr apropos 1 . +Instead of +.Ar name , +an expression can be provided using the syntax described in the +.Xr apropos 1 +manual. +By default, it displays the header lines of all matching pages. +.It Fl l +A synonym for +.Xr mandoc 1 . +The +.Ar name +arguments are interpreted as filenames. +No search is done and +.Ar file , +.Ar path , +.Ar section , +.Ar subsection , +and +.Fl w +are ignored. +This option implies +.Fl a . +.It Fl M Ar path +Override the list of standard directories which +.Nm +searches for manual pages. +The supplied +.Ar path +must be a colon +.Pq Ql \&: +separated list of directories. +This search path may also be set using the environment variable +.Ev MANPATH . +.It Fl m Ar path +Augment the list of standard directories which +.Nm +searches for manual pages. +The supplied +.Ar path +must be a colon +.Pq Ql \&: +separated list of directories. +These directories will be searched before the standard directories or +the directories specified using the +.Fl M +option or the +.Ev MANPATH +environment variable. +.It Fl S Ar subsection +Only show pages for the specified +.Xr machine 1 +architecture. +.Ar subsection +is case insensitive. +.Pp +By default manual pages for all architectures are installed. +Therefore this option can be used to view pages for one +architecture whilst using another. +.Pp +This option overrides the +.Ev MACHINE +environment variable. +.It Oo Fl s Oc Ar section +Only select manuals from the specified +.Ar section . +The currently available sections are: +.Pp +.Bl -tag -width "localXXX" -offset indent -compact +.It 1 +General commands +.Pq tools and utilities . +.It 2 +System calls and error numbers. +.It 3 +Library functions. +.It 3p +.Xr perl 1 +programmer's reference guide. +.It 4 +Device drivers. +.It 5 +File formats. +.It 6 +Games. +.It 7 +Miscellaneous information. +.It 8 +System maintenance and operation commands. +.It 9 +Kernel internals. +.El +.Pp +If not specified and a match is found in more than one section, +the first match is selected from the following list: +1, 8, 6, 2, 3, 5, 7, 4, 9, 3p. +.It Fl w +List the pathnames of all matching manual pages instead of displaying +any of them. +.El +.Pp +The options +.Fl IKOTW +are also supported and are documented in +.Xr mandoc 1 . +The options +.Fl fkl +are mutually exclusive and override each other. +.Pp +Guidelines for writing +man pages can be found in +.Xr mdoc 7 . +.Pp +The +.Xr mandoc.db 5 +database is used for looking up manual page entries. +In cases where the database is absent, outdated, or corrupt, +.Nm +falls back to looking for files called +.Ar name . Ns Ar section . +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. +The database is kept up to date with +.Xr makewhatis 8 , +which is run by the +.Xr weekly 8 +maintenance script. +.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 . +The +.Fl O Cm tag Ns Op = Ns Ar term +option documented in the +.Xr mandoc 1 +manual opens a manual page at the definition of a specific +.Ar term +rather than at the beginning. +.It Ev MANPATH +The standard search path used by +.Nm +may be changed by specifying a path in the +.Ev MANPATH +environment variable. +The format of the path is a colon +.Pq Ql \&: +separated list of directories. +Invalid paths are ignored. +Overridden by +.Fl M , +ignored if +.Fl l +is specified. +.Pp +If +.Ev MANPATH +begins with a colon, it is appended to the default list; +if it ends with a colon, it is prepended to the default list; +or if it contains two adjacent colons, +the standard search path is inserted between the colons. +If none of these conditions are met, it overrides the +standard search path. +.It Ev PAGER +Specifies the pagination program to use when +.Ev MANPAGER +is not defined. +If neither PAGER nor MANPAGER is defined, +.Xr more 1 +.Fl s +is used. +.El +.Sh FILES +.Bl -tag -width /etc/man.conf -compact +.It Pa /etc/man.conf +default man configuration file +.El +.Sh EXIT STATUS +.Ex -std man +See +.Xr mandoc 1 +for details. +.Sh EXAMPLES +Format a page for pasting extracts into an email message \(em +avoid printing any UTF-8 characters, reduce the width to ease +quoting in replies, and remove markup: +.Pp +.Dl $ man -T ascii -O width=65 pledge | col -b +.Pp +Read a typeset page in a PDF viewer: +.Pp +.Dl $ MANPAGER=mupdf man -T pdf lpd +.Sh SEE ALSO +.Xr apropos 1 , +.Xr col 1 , +.Xr mandoc 1 , +.Xr ul 1 , +.Xr whereis 1 , +.Xr man.conf 5 , +.Xr mdoc 7 +.Sh STANDARDS +The +.Nm +utility is compliant with the +.St -p1003.1-2008 +specification. +.Pp +The flags +.Op Fl aCcfhIKlMmOSsTWw , +as well as the environment variables +.Ev MACHINE , +.Ev MANPAGER , +and +.Ev MANPATH , +are extensions to that specification. +.Sh HISTORY +A +.Nm +command first appeared in +.At v3 . +.Pp +The +.Fl w +option first appeared in +.At v7 ; +.Fl f +and +.Fl k +in +.Bx 4 ; +.Fl M +in +.Bx 4.3 ; +.Fl a +in +.Bx 4.3 Tahoe ; +.Fl c +and +.Fl m +in +.Bx 4.3 Reno ; +.Fl h +in +.Bx 4.3 Net/2 ; +.Fl C +in +.Nx 1.0 ; +.Fl s +and +.Fl S +in +.Ox 2.3 ; +and +.Fl I , +.Fl K , +.Fl l , +.Fl O , +and +.Fl W +in +.Ox 5.7 . +The +.Fl T +option first appeared in +.At III +and was also added in +.Ox 5.7 . Property changes on: vendor/mandoc/20190723/man.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/man.c =================================================================== --- vendor/mandoc/20190723/man.c (nonexistent) +++ vendor/mandoc/20190723/man.c (revision 350350) @@ -0,0 +1,345 @@ +/* $Id: man.c,v 1.187 2019/01/05 00:36:50 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze + * Copyright (c) 2011 Joerg Sonnenberger + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "roff.h" +#include "man.h" +#include "libmandoc.h" +#include "roff_int.h" +#include "libman.h" + +static char *man_hasc(char *); +static int man_ptext(struct roff_man *, int, char *, int); +static int man_pmacro(struct roff_man *, int, char *, int); + + +int +man_parseln(struct roff_man *man, int ln, char *buf, int offs) +{ + + if (man->last->type != ROFFT_EQN || ln > man->last->line) + man->flags |= MAN_NEWLINE; + + return roff_getcontrol(man->roff, buf, &offs) ? + man_pmacro(man, ln, buf, offs) : + man_ptext(man, ln, buf, offs); +} + +/* + * If the string ends with \c, return a pointer to the backslash. + * Otherwise, return NULL. + */ +static char * +man_hasc(char *start) +{ + char *cp, *ep; + + ep = strchr(start, '\0') - 2; + if (ep < start || ep[0] != '\\' || ep[1] != 'c') + return NULL; + for (cp = ep; cp > start; cp--) + if (cp[-1] != '\\') + break; + return (ep - cp) % 2 ? NULL : ep; +} + +void +man_descope(struct roff_man *man, int line, int offs, char *start) +{ + /* Trailing \c keeps next-line scope open. */ + + if (start != NULL && man_hasc(start) != NULL) + return; + + /* + * Co-ordinate what happens with having a next-line scope open: + * first close out the element scopes (if applicable), + * then close out the block scope (also if applicable). + */ + + if (man->flags & MAN_ELINE) { + while (man->last->parent->type != ROFFT_ROOT && + man_macro(man->last->parent->tok)->flags & MAN_ESCOPED) + man_unscope(man, man->last->parent); + man->flags &= ~MAN_ELINE; + } + if ( ! (man->flags & MAN_BLINE)) + return; + man_unscope(man, man->last->parent); + roff_body_alloc(man, line, offs, man->last->tok); + man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); +} + +static int +man_ptext(struct roff_man *man, int line, char *buf, int offs) +{ + int i; + char *ep; + + /* In no-fill mode, whitespace is preserved on text lines. */ + + if (man->flags & ROFF_NOFILL) { + roff_word_alloc(man, line, offs, buf + offs); + man_descope(man, line, offs, buf + offs); + return 1; + } + + for (i = offs; buf[i] == ' '; i++) + /* Skip leading whitespace. */ ; + + /* + * Blank lines are ignored in next line scope + * and right after headings and cancel preceding \c, + * but add a single vertical space elsewhere. + */ + + if (buf[i] == '\0') { + if (man->flags & (MAN_ELINE | MAN_BLINE)) { + mandoc_msg(MANDOCERR_BLK_BLANK, line, 0, NULL); + return 1; + } + if (man->last->tok == MAN_SH || man->last->tok == MAN_SS) + return 1; + if (man->last->type == ROFFT_TEXT && + ((ep = man_hasc(man->last->string)) != NULL)) { + *ep = '\0'; + return 1; + } + roff_elem_alloc(man, line, offs, ROFF_sp); + man->next = ROFF_NEXT_SIBLING; + return 1; + } + + /* + * Warn if the last un-escaped character is whitespace. Then + * strip away the remaining spaces (tabs stay!). + */ + + i = (int)strlen(buf); + assert(i); + + if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { + if (i > 1 && '\\' != buf[i - 2]) + mandoc_msg(MANDOCERR_SPACE_EOL, line, i - 1, NULL); + + for (--i; i && ' ' == buf[i]; i--) + /* Spin back to non-space. */ ; + + /* Jump ahead of escaped whitespace. */ + i += '\\' == buf[i] ? 2 : 1; + + buf[i] = '\0'; + } + roff_word_alloc(man, line, offs, buf + offs); + + /* + * End-of-sentence check. If the last character is an unescaped + * EOS character, then flag the node as being the end of a + * sentence. The front-end will know how to interpret this. + */ + + assert(i); + if (mandoc_eos(buf, (size_t)i)) + man->last->flags |= NODE_EOS; + + man_descope(man, line, offs, buf + offs); + return 1; +} + +static int +man_pmacro(struct roff_man *man, int ln, char *buf, int offs) +{ + struct roff_node *n; + const char *cp; + size_t sz; + enum roff_tok tok; + int ppos; + int bline; + + /* Determine the line macro. */ + + ppos = offs; + tok = TOKEN_NONE; + for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++) + offs++; + if (sz > 0 && sz < 4) + tok = roffhash_find(man->manmac, buf + ppos, sz); + if (tok == TOKEN_NONE) { + mandoc_msg(MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1); + return 1; + } + + /* Skip a leading escape sequence or tab. */ + + switch (buf[offs]) { + case '\\': + cp = buf + offs + 1; + mandoc_escape(&cp, NULL, NULL); + offs = cp - buf; + break; + case '\t': + offs++; + break; + default: + break; + } + + /* Jump to the next non-whitespace word. */ + + while (buf[offs] == ' ') + offs++; + + /* + * Trailing whitespace. Note that tabs are allowed to be passed + * into the parser as "text", so we only warn about spaces here. + */ + + if (buf[offs] == '\0' && buf[offs - 1] == ' ') + mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL); + + /* + * Some macros break next-line scopes; otherwise, remember + * whether we are in next-line scope for a block head. + */ + + man_breakscope(man, tok); + bline = man->flags & MAN_BLINE; + + /* + * If the line in next-line scope ends with \c, keep the + * next-line scope open for the subsequent input line. + * That is not at all portable, only groff >= 1.22.4 + * does it, but *if* this weird idiom occurs in a manual + * page, that's very likely what the author intended. + */ + + if (bline && man_hasc(buf + offs)) + bline = 0; + + /* Call to handler... */ + + (*man_macro(tok)->fp)(man, tok, ln, ppos, &offs, buf); + + /* In quick mode (for mandocdb), abort after the NAME section. */ + + if (man->quick && tok == MAN_SH) { + n = man->last; + if (n->type == ROFFT_BODY && + strcmp(n->prev->child->string, "NAME")) + return 2; + } + + /* + * If we are in a next-line scope for a block head, + * close it out now and switch to the body, + * unless the next-line scope is allowed to continue. + */ + + if (bline == 0 || + (man->flags & MAN_BLINE) == 0 || + man->flags & MAN_ELINE || + man_macro(tok)->flags & MAN_NSCOPED) + return 1; + + man_unscope(man, man->last->parent); + roff_body_alloc(man, ln, ppos, man->last->tok); + man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); + return 1; +} + +void +man_breakscope(struct roff_man *man, int tok) +{ + struct roff_node *n; + + /* + * An element next line scope is open, + * and the new macro is not allowed inside elements. + * Delete the element that is being broken. + */ + + if (man->flags & MAN_ELINE && (tok < MAN_TH || + (man_macro(tok)->flags & MAN_NSCOPED) == 0)) { + n = man->last; + if (n->type == ROFFT_TEXT) + n = n->parent; + if (n->tok < MAN_TH || + (man_macro(n->tok)->flags & (MAN_NSCOPED | MAN_ESCOPED)) + == MAN_NSCOPED) + n = n->parent; + + mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos, + "%s breaks %s", roff_name[tok], roff_name[n->tok]); + + roff_node_delete(man, n); + man->flags &= ~MAN_ELINE; + } + + /* + * Weird special case: + * Switching fill mode closes section headers. + */ + + if (man->flags & MAN_BLINE && + (tok == ROFF_nf || tok == ROFF_fi) && + (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) { + n = man->last; + man_unscope(man, n); + roff_body_alloc(man, n->line, n->pos, n->tok); + man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); + } + + /* + * A block header next line scope is open, + * and the new macro is not allowed inside block headers. + * Delete the block that is being broken. + */ + + if (man->flags & MAN_BLINE && tok != ROFF_nf && tok != ROFF_fi && + (tok < MAN_TH || man_macro(tok)->flags & MAN_XSCOPE)) { + n = man->last; + if (n->type == ROFFT_TEXT) + n = n->parent; + if (n->tok < MAN_TH || + (man_macro(n->tok)->flags & MAN_XSCOPE) == 0) + n = n->parent; + + assert(n->type == ROFFT_HEAD); + n = n->parent; + assert(n->type == ROFFT_BLOCK); + assert(man_macro(n->tok)->flags & MAN_BSCOPED); + + mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos, + "%s breaks %s", roff_name[tok], roff_name[n->tok]); + + roff_node_delete(man, n); + man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); + } +} Property changes on: vendor/mandoc/20190723/man.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/man.conf.5 =================================================================== --- vendor/mandoc/20190723/man.conf.5 (nonexistent) +++ vendor/mandoc/20190723/man.conf.5 (revision 350350) @@ -0,0 +1,136 @@ +.\" $Id: man.conf.5,v 1.6 2018/10/02 14:56:47 schwarze Exp $ +.\" +.\" Copyright (c) 2015, 2017 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: October 2 2018 $ +.Dt MAN.CONF 5 +.Os +.Sh NAME +.Nm man.conf +.Nd configuration file for man +.Sh DESCRIPTION +This is the configuration file +for the +.Xr man 1 , +.Xr apropos 1 , +and +.Xr makewhatis 8 +utilities. +Its presence, and all directives, are optional. +.Pp +This file is an ASCII text file. +Leading whitespace on lines, lines starting with +.Sq # , +and blank lines are ignored. +Words are separated by whitespace. +The first word on each line is the name of a configuration directive. +.Pp +The following directives are supported: +.Bl -tag -width Ds +.It Ic manpath Ar path +Override the default search +.Ar path +for +.Xr man 1 , +.Xr apropos 1 , +and +.Xr makewhatis 8 . +It can be used multiple times to specify multiple paths, +with the order determining the manual page search order. +.Pp +Each path is a tree containing subdirectories +whose names consist of the strings +.Sq man +and/or +.Sq cat +followed by the names of sections, usually single digits. +The former are supposed to contain unformatted manual pages in +.Xr mdoc 7 +and/or +.Xr man 7 +format; file names should end with the name of the section +preceded by a dot. +The latter should contain preformatted manual pages; +file names should end with +.Ql .0 . +.Pp +Creating a +.Xr mandoc.db 5 +database with +.Xr makewhatis 8 +in each directory configured with +.Ic manpath +is recommended and necessary for +.Xr apropos 1 +to work, and also for +.Xr man 1 +on operating systems like +.Ox +that install each manual page with only one file name in the file system, +even if it documents multiple utilities or functions. +.It Ic output Ar option Op Ar value +Configure the default value of an output option. +These directives are overridden by the +.Fl O +command line options of the same names. +For details, see the +.Xr mandoc 1 +manual. +.Pp +.Bl -column fragment integer "ascii, utf8" -compact +.It Ar option Ta Ar value Ta used by Fl T Ta purpose +.It Ta Ta Ta +.It Ic fragment Ta none Ta Cm html Ta print only body +.It Ic includes Ta string Ta Cm html Ta path to header files +.It Ic indent Ta integer Ta Cm ascii , utf8 Ta left margin +.It Ic man Ta string Ta Cm html Ta path for \&Xr links +.It Ic paper Ta string Ta Cm ps , pdf Ta paper size +.It Ic style Ta string Ta Cm html Ta CSS file +.It Ic toc Ta none Ta Cm html Ta print table of contents +.It Ic width Ta integer Ta Cm ascii , utf8 Ta right margin +.El +.It Ic _whatdb Ar path Ns Cm /whatis.db +This directive provides the same functionality as +.Ic manpath , +but using a historic and misleading syntax. +It is kept for backward compatibility for now, +but will eventually be removed. +.El +.Sh FILES +.Pa /etc/man.conf +.Sh EXAMPLES +The following configuration file reproduces the defaults: +installing it is equivalent to not having a +.Nm +file at all. +.Bd -literal -offset indent +manpath /usr/share/man +manpath /usr/X11R6/man +manpath /usr/local/man +.Ed +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr makewhatis 8 +.Sh HISTORY +A relatively complicated +.Nm +file format first appeared in +.Bx 4.3 Reno . +For +.Ox 5.8 , +it was redesigned from scratch, aiming for simplicity. +.Sh AUTHORS +.An Ingo Schwarze Aq Mt schwarze@openbsd.org Property changes on: vendor/mandoc/20190723/man.conf.5 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/man.h =================================================================== --- vendor/mandoc/20190723/man.h (nonexistent) +++ vendor/mandoc/20190723/man.h (revision 350350) @@ -0,0 +1,21 @@ +/* $Id: man.h,v 1.79 2018/08/23 19:33:27 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2014, 2015 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct roff_man; + +void man_validate(struct roff_man *); Property changes on: vendor/mandoc/20190723/man.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/man_macro.c =================================================================== --- vendor/mandoc/20190723/man_macro.c (nonexistent) +++ vendor/mandoc/20190723/man_macro.c (revision 350350) @@ -0,0 +1,468 @@ +/* $Id: man_macro.c,v 1.144 2019/01/05 18:59:46 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2012-2015, 2017-2019 Ingo Schwarze + * Copyright (c) 2013 Franco Fichtner + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "man.h" +#include "libmandoc.h" +#include "roff_int.h" +#include "libman.h" + +static void blk_close(MACRO_PROT_ARGS); +static void blk_exp(MACRO_PROT_ARGS); +static void blk_imp(MACRO_PROT_ARGS); +static void in_line_eoln(MACRO_PROT_ARGS); +static int man_args(struct roff_man *, int, + int *, char *, char **); +static void rew_scope(struct roff_man *, enum roff_tok); + +static const struct man_macro man_macros[MAN_MAX - MAN_TH] = { + { in_line_eoln, MAN_XSCOPE }, /* TH */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SH */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SS */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TP */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TQ */ + { blk_imp, MAN_XSCOPE }, /* LP */ + { blk_imp, MAN_XSCOPE }, /* PP */ + { blk_imp, MAN_XSCOPE }, /* P */ + { blk_imp, MAN_XSCOPE }, /* IP */ + { blk_imp, MAN_XSCOPE }, /* HP */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SM */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SB */ + { in_line_eoln, 0 }, /* BI */ + { in_line_eoln, 0 }, /* IB */ + { in_line_eoln, 0 }, /* BR */ + { in_line_eoln, 0 }, /* RB */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* R */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* B */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* I */ + { in_line_eoln, 0 }, /* IR */ + { in_line_eoln, 0 }, /* RI */ + { blk_close, MAN_XSCOPE }, /* RE */ + { blk_exp, MAN_XSCOPE }, /* RS */ + { in_line_eoln, 0 }, /* DT */ + { in_line_eoln, 0 }, /* UC */ + { in_line_eoln, MAN_NSCOPED }, /* PD */ + { in_line_eoln, 0 }, /* AT */ + { in_line_eoln, MAN_NSCOPED }, /* in */ + { blk_imp, MAN_XSCOPE }, /* SY */ + { blk_close, MAN_XSCOPE }, /* YS */ + { in_line_eoln, 0 }, /* OP */ + { in_line_eoln, MAN_XSCOPE }, /* EX */ + { in_line_eoln, MAN_XSCOPE }, /* EE */ + { blk_exp, MAN_XSCOPE }, /* UR */ + { blk_close, MAN_XSCOPE }, /* UE */ + { blk_exp, MAN_XSCOPE }, /* MT */ + { blk_close, MAN_XSCOPE }, /* ME */ +}; + + +const struct man_macro * +man_macro(enum roff_tok tok) +{ + assert(tok >= MAN_TH && tok <= MAN_MAX); + return man_macros + (tok - MAN_TH); +} + +void +man_unscope(struct roff_man *man, const struct roff_node *to) +{ + struct roff_node *n; + + to = to->parent; + n = man->last; + while (n != to) { + + /* Reached the end of the document? */ + + if (to == NULL && ! (n->flags & NODE_VALID)) { + if (man->flags & (MAN_BLINE | MAN_ELINE) && + man_macro(n->tok)->flags & + (MAN_BSCOPED | MAN_NSCOPED)) { + mandoc_msg(MANDOCERR_BLK_LINE, + n->line, n->pos, + "EOF breaks %s", roff_name[n->tok]); + if (man->flags & MAN_ELINE) + man->flags &= ~MAN_ELINE; + else { + assert(n->type == ROFFT_HEAD); + n = n->parent; + man->flags &= ~MAN_BLINE; + } + man->last = n; + n = n->parent; + roff_node_delete(man, man->last); + continue; + } + if (n->type == ROFFT_BLOCK && + man_macro(n->tok)->fp == blk_exp) + mandoc_msg(MANDOCERR_BLK_NOEND, + n->line, n->pos, "%s", + roff_name[n->tok]); + } + + /* + * We might delete the man->last node + * in the post-validation phase. + * Save a pointer to the parent such that + * we know where to continue the iteration. + */ + + man->last = n; + n = n->parent; + man->last->flags |= NODE_VALID; + } + + /* + * If we ended up at the parent of the node we were + * supposed to rewind to, that means the target node + * got deleted, so add the next node we parse as a child + * of the parent instead of as a sibling of the target. + */ + + man->next = (man->last == to) ? + ROFF_NEXT_CHILD : ROFF_NEXT_SIBLING; +} + +/* + * Rewinding entails ascending the parse tree until a coherent point, + * for example, the `SH' macro will close out any intervening `SS' + * scopes. When a scope is closed, it must be validated and actioned. + */ +static void +rew_scope(struct roff_man *man, enum roff_tok tok) +{ + struct roff_node *n; + + /* Preserve empty paragraphs before RS. */ + + n = man->last; + if (tok == MAN_RS && n->child == NULL && + (n->tok == MAN_P || n->tok == MAN_PP || n->tok == MAN_LP)) + return; + + for (;;) { + if (n->type == ROFFT_ROOT) + return; + if (n->flags & NODE_VALID) { + n = n->parent; + continue; + } + if (n->type != ROFFT_BLOCK) { + if (n->parent->type == ROFFT_ROOT) { + man_unscope(man, n); + return; + } else { + n = n->parent; + continue; + } + } + if (tok != MAN_SH && (n->tok == MAN_SH || + (tok != MAN_SS && (n->tok == MAN_SS || + man_macro(n->tok)->fp == blk_exp)))) + return; + man_unscope(man, n); + n = man->last; + } +} + + +/* + * Close out a generic explicit macro. + */ +void +blk_close(MACRO_PROT_ARGS) +{ + enum roff_tok ctok, ntok; + const struct roff_node *nn; + char *p, *ep; + int cline, cpos, la, nrew, target; + + nrew = 1; + switch (tok) { + case MAN_RE: + ntok = MAN_RS; + la = *pos; + if ( ! man_args(man, line, pos, buf, &p)) + break; + for (nn = man->last->parent; nn; nn = nn->parent) + if (nn->tok == ntok && nn->type == ROFFT_BLOCK) + nrew++; + target = strtol(p, &ep, 10); + if (*ep != '\0') + mandoc_msg(MANDOCERR_ARG_EXCESS, line, + la + (buf[la] == '"') + (int)(ep - p), + "RE ... %s", ep); + free(p); + if (target == 0) + target = 1; + nrew -= target; + if (nrew < 1) { + mandoc_msg(MANDOCERR_RE_NOTOPEN, + line, ppos, "RE %d", target); + return; + } + break; + case MAN_YS: + ntok = MAN_SY; + break; + case MAN_UE: + ntok = MAN_UR; + break; + case MAN_ME: + ntok = MAN_MT; + break; + default: + abort(); + } + + for (nn = man->last->parent; nn; nn = nn->parent) + if (nn->tok == ntok && nn->type == ROFFT_BLOCK && ! --nrew) + break; + + if (nn == NULL) { + mandoc_msg(MANDOCERR_BLK_NOTOPEN, + line, ppos, "%s", roff_name[tok]); + rew_scope(man, MAN_PP); + if (tok == MAN_RE) { + roff_elem_alloc(man, line, ppos, ROFF_br); + man->last->flags |= NODE_LINE | + NODE_VALID | NODE_ENDED; + man->next = ROFF_NEXT_SIBLING; + } + return; + } + + cline = man->last->line; + cpos = man->last->pos; + ctok = man->last->tok; + man_unscope(man, nn); + + if (tok == MAN_RE && nn->head->aux > 0) + roff_setreg(man->roff, "an-margin", nn->head->aux, '-'); + + /* Trailing text. */ + + if (buf[*pos] != '\0') { + roff_word_alloc(man, line, ppos, buf + *pos); + man->last->flags |= NODE_DELIMC; + if (mandoc_eos(man->last->string, strlen(man->last->string))) + man->last->flags |= NODE_EOS; + } + + /* Move a trailing paragraph behind the block. */ + + if (ctok == MAN_LP || ctok == MAN_PP || ctok == MAN_P) { + *pos = strlen(buf); + blk_imp(man, ctok, cline, cpos, pos, buf); + } + + /* Synopsis blocks need an explicit end marker for spacing. */ + + if (tok == MAN_YS && man->last == nn) { + roff_elem_alloc(man, line, ppos, tok); + man_unscope(man, man->last); + } +} + +void +blk_exp(MACRO_PROT_ARGS) +{ + struct roff_node *head; + char *p; + int la; + + if (tok == MAN_RS) { + rew_scope(man, tok); + man->flags |= ROFF_NONOFILL; + } + roff_block_alloc(man, line, ppos, tok); + head = roff_head_alloc(man, line, ppos, tok); + + la = *pos; + if (man_args(man, line, pos, buf, &p)) { + roff_word_alloc(man, line, la, p); + if (tok == MAN_RS) { + if (roff_getreg(man->roff, "an-margin") == 0) + roff_setreg(man->roff, "an-margin", + 7 * 24, '='); + if ((head->aux = strtod(p, NULL) * 24.0) > 0) + roff_setreg(man->roff, "an-margin", + head->aux, '+'); + } + free(p); + } + + if (buf[*pos] != '\0') + mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos, + "%s ... %s", roff_name[tok], buf + *pos); + + man_unscope(man, head); + roff_body_alloc(man, line, ppos, tok); + man->flags &= ~ROFF_NONOFILL; +} + +/* + * Parse an implicit-block macro. These contain a ROFFT_HEAD and a + * ROFFT_BODY contained within a ROFFT_BLOCK. Rules for closing out other + * scopes, such as `SH' closing out an `SS', are defined in the rew + * routines. + */ +void +blk_imp(MACRO_PROT_ARGS) +{ + int la; + char *p; + struct roff_node *n; + + rew_scope(man, tok); + man->flags |= ROFF_NONOFILL; + if (tok == MAN_SH || tok == MAN_SS) + man->flags &= ~ROFF_NOFILL; + roff_block_alloc(man, line, ppos, tok); + n = roff_head_alloc(man, line, ppos, tok); + + /* Add line arguments. */ + + for (;;) { + la = *pos; + if ( ! man_args(man, line, pos, buf, &p)) + break; + roff_word_alloc(man, line, la, p); + free(p); + } + + /* + * For macros having optional next-line scope, + * keep the head open if there were no arguments. + * For `TP' and `TQ', always keep the head open. + */ + + if (man_macro(tok)->flags & MAN_BSCOPED && + (tok == MAN_TP || tok == MAN_TQ || n == man->last)) { + man->flags |= MAN_BLINE; + return; + } + + /* Close out the head and open the body. */ + + man_unscope(man, n); + roff_body_alloc(man, line, ppos, tok); + man->flags &= ~ROFF_NONOFILL; +} + +void +in_line_eoln(MACRO_PROT_ARGS) +{ + int la; + char *p; + struct roff_node *n; + + roff_elem_alloc(man, line, ppos, tok); + n = man->last; + + if (tok == MAN_EX) + man->flags |= ROFF_NOFILL; + else if (tok == MAN_EE) + man->flags &= ~ROFF_NOFILL; + + for (;;) { + if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) { + mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos, + "%s ... %s", roff_name[tok], buf + *pos); + break; + } + la = *pos; + if ( ! man_args(man, line, pos, buf, &p)) + break; + if (man_macro(tok)->flags & MAN_JOIN && + man->last->type == ROFFT_TEXT) + roff_word_append(man, p); + else + roff_word_alloc(man, line, la, p); + free(p); + } + + /* + * Append NODE_EOS in case the last snipped argument + * ends with a dot, e.g. `.IR syslog (3).' + */ + + if (n != man->last && + mandoc_eos(man->last->string, strlen(man->last->string))) + man->last->flags |= NODE_EOS; + + /* + * If no arguments are specified and this is MAN_ESCOPED (i.e., + * next-line scoped), then set our mode to indicate that we're + * waiting for terms to load into our context. + */ + + if (n == man->last && man_macro(tok)->flags & MAN_ESCOPED) { + man->flags |= MAN_ELINE; + return; + } + + assert(man->last->type != ROFFT_ROOT); + man->next = ROFF_NEXT_SIBLING; + + /* Rewind our element scope. */ + + for ( ; man->last; man->last = man->last->parent) { + man->last->flags |= NODE_VALID; + if (man->last == n) + break; + } + + /* Rewind next-line scoped ancestors, if any. */ + + if (man_macro(tok)->flags & MAN_ESCOPED) + man_descope(man, line, ppos, NULL); +} + +void +man_endparse(struct roff_man *man) +{ + man_unscope(man, man->meta.first); +} + +static int +man_args(struct roff_man *man, int line, int *pos, char *buf, char **v) +{ + char *start; + + assert(*pos); + *v = start = buf + *pos; + assert(' ' != *start); + + if ('\0' == *start) + return 0; + + *v = roff_getarg(man->roff, v, line, pos); + return 1; +} Property changes on: vendor/mandoc/20190723/man_macro.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/manconf.h =================================================================== --- vendor/mandoc/20190723/manconf.h (nonexistent) +++ vendor/mandoc/20190723/manconf.h (revision 350350) @@ -0,0 +1,52 @@ +/* $Id: manconf.h,v 1.7 2018/11/22 11:30:23 schwarze Exp $ */ +/* + * Copyright (c) 2011, 2015, 2017, 2018 Ingo Schwarze + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* List of unique, absolute paths to manual trees. */ + +struct manpaths { + char **paths; + size_t sz; +}; + +/* Data from -O options and man.conf(5) output directives. */ + +struct manoutput { + char *includes; + char *man; + char *paper; + char *style; + char *tag; + size_t indent; + size_t width; + int fragment; + int mdoc; + int noval; + int synopsisonly; + int toc; +}; + +struct manconf { + struct manoutput output; + struct manpaths manpath; +}; + + +void manconf_parse(struct manconf *, const char *, char *, char *); +int manconf_output(struct manoutput *, const char *, int); +void manconf_free(struct manconf *); +void manpath_base(struct manpaths *); Property changes on: vendor/mandoc/20190723/manconf.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc.3 =================================================================== --- vendor/mandoc/20190723/mandoc.3 (nonexistent) +++ vendor/mandoc/20190723/mandoc.3 (revision 350350) @@ -0,0 +1,574 @@ +.\" $Id: mandoc.3,v 1.44 2018/12/30 00:49:55 schwarze Exp $ +.\" +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons +.\" Copyright (c) 2010-2017 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: December 30 2018 $ +.Dt MANDOC 3 +.Os +.Sh NAME +.Nm mandoc , +.Nm deroff , +.Nm mparse_alloc , +.Nm mparse_copy , +.Nm mparse_free , +.Nm mparse_open , +.Nm mparse_readfd , +.Nm mparse_reset , +.Nm mparse_result +.Nd mandoc macro compiler library +.Sh SYNOPSIS +.In sys/types.h +.In stdio.h +.In mandoc.h +.Pp +.Fd "#define ASCII_NBRSP" +.Fd "#define ASCII_HYPH" +.Fd "#define ASCII_BREAK" +.Ft struct mparse * +.Fo mparse_alloc +.Fa "int options" +.Fa "enum mandoc_os oe_e" +.Fa "char *os_s" +.Fc +.Ft void +.Fo mparse_free +.Fa "struct mparse *parse" +.Fc +.Ft void +.Fo mparse_copy +.Fa "const struct mparse *parse" +.Fc +.Ft int +.Fo mparse_open +.Fa "struct mparse *parse" +.Fa "const char *fname" +.Fc +.Ft void +.Fo mparse_readfd +.Fa "struct mparse *parse" +.Fa "int fd" +.Fa "const char *fname" +.Fc +.Ft void +.Fo mparse_reset +.Fa "struct mparse *parse" +.Fc +.Ft struct roff_meta * +.Fo mparse_result +.Fa "struct mparse *parse" +.Fc +.In roff.h +.Ft void +.Fo deroff +.Fa "char **dest" +.Fa "const struct roff_node *node" +.Fc +.In sys/types.h +.In mandoc.h +.In mdoc.h +.Vt extern const char * const * mdoc_argnames; +.Vt extern const char * const * mdoc_macronames; +.In sys/types.h +.In mandoc.h +.In man.h +.Vt extern const char * const * man_macronames; +.Sh DESCRIPTION +The +.Nm mandoc +library parses a +.Ux +manual into an abstract syntax tree (AST). +.Ux +manuals are composed of +.Xr mdoc 7 +or +.Xr man 7 , +and may be mixed with +.Xr roff 7 , +.Xr tbl 7 , +and +.Xr eqn 7 +invocations. +.Pp +The following describes a general parse sequence: +.Bl -enum +.It +initiate a parsing sequence with +.Xr mchars_alloc 3 +and +.Fn mparse_alloc ; +.It +open a file with +.Xr open 2 +or +.Fn mparse_open ; +.It +parse it with +.Fn mparse_readfd ; +.It +close it with +.Xr close 2 ; +.It +retrieve the syntax tree with +.Fn mparse_result ; +.It +if information about the validity of the input is needed, fetch it with +.Fn mparse_updaterc ; +.It +iterate over parse nodes with starting from the +.Fa first +member of the returned +.Vt struct roff_meta ; +.It +free all allocated memory with +.Fn mparse_free +and +.Xr mchars_free 3 , +or invoke +.Fn mparse_reset +and go back to step 2 to parse new files. +.El +.Sh REFERENCE +This section documents the functions, types, and variables available +via +.In mandoc.h , +with the exception of those documented in +.Xr mandoc_escape 3 +and +.Xr mchars_alloc 3 . +.Ss Types +.Bl -ohang +.It Vt "enum mandocerr" +An error or warning message during parsing. +.It Vt "enum mandoclevel" +A classification of an +.Vt "enum mandocerr" +as regards system operation. +See the DIAGNOSTICS section in +.Xr mandoc 1 +regarding the meanings of the levels. +.It Vt "struct mparse" +An opaque pointer to a running parse sequence. +Created with +.Fn mparse_alloc +and freed with +.Fn mparse_free . +This may be used across parsed input if +.Fn mparse_reset +is called between parses. +.El +.Ss Functions +.Bl -ohang +.It Fn deroff +Obtain a text-only representation of a +.Vt struct roff_node , +including text contained in its child nodes. +To be used on children of the +.Fa first +member of +.Vt struct roff_meta . +When it is no longer needed, the pointer returned from +.Fn deroff +can be passed to +.Xr free 3 . +.It Fn mparse_alloc +Allocate a parser. +The arguments have the following effect: +.Bl -tag -offset 5n -width inttype +.It Ar options +When the +.Dv MPARSE_MDOC +or +.Dv MPARSE_MAN +bit is set, only that parser is used. +Otherwise, the document type is automatically detected. +.Pp +When the +.Dv MPARSE_SO +bit is set, +.Xr roff 7 +.Ic \&so +file inclusion requests are always honoured. +Otherwise, if the request is the only content in an input file, +only the file name is remembered, to be returned in the +.Fa sodest +field of +.Vt struct roff_meta . +.Pp +When the +.Dv MPARSE_QUICK +bit is set, parsing is aborted after the NAME section. +This is for example useful in +.Xr makewhatis 8 +.Fl Q +to quickly build minimal databases. +.Pp +When the +.Dv MARSE_VALIDATE +bit is set, +.Fn mparse_result +runs the validation functions before returning the syntax tree. +This is almost always required, except in certain debugging scenarios, +for example to dump unvalidated syntax trees. +.It Ar os_e +Operating system to check base system conventions for. +If +.Dv MANDOC_OS_OTHER , +the system is automatically detected from +.Ic \&Os , +.Fl Ios , +or +.Xr uname 3 . +.It Ar os_s +A default string for the +.Xr mdoc 7 +.Ic \&Os +macro, overriding the +.Dv OSNAME +preprocessor definition and the results of +.Xr uname 3 . +Passing +.Dv NULL +sets no default. +.El +.Pp +The same parser may be used for multiple files so long as +.Fn mparse_reset +is called between parses. +.Fn mparse_free +must be called to free the memory allocated by this function. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . +.It Fn mparse_free +Free all memory allocated by +.Fn mparse_alloc . +Declared in +.In mandoc.h , +implemented in +.Pa read.c . +.It Fn mparse_copy +Dump a copy of the input to the standard output; used for +.Fl man T Ns Cm man . +Declared in +.In mandoc.h , +implemented in +.Pa read.c . +.It Fn mparse_open +Open the file for reading. +If that fails and +.Fa fname +does not already end in +.Ql .gz , +try again after appending +.Ql .gz . +Save the information whether the file is zipped or not. +Return a file descriptor open for reading or -1 on failure. +It can be passed to +.Fn mparse_readfd +or used directly. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . +.It Fn mparse_readfd +Parse a file descriptor opened with +.Xr open 2 +or +.Fn mparse_open . +Pass the associated filename in +.Va fname . +This function may be called multiple times with different parameters; however, +.Xr close 2 +and +.Fn mparse_reset +should be invoked between parses. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . +.It Fn mparse_reset +Reset a parser so that +.Fn mparse_readfd +may be used again. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . +.It Fn mparse_result +Obtain the result of a parse. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . +.El +.Ss Variables +.Bl -ohang +.It Va man_macronames +The string representation of a +.Xr man 7 +macro as indexed by +.Vt "enum mant" . +.It Va mdoc_argnames +The string representation of an +.Xr mdoc 7 +macro argument as indexed by +.Vt "enum mdocargt" . +.It Va mdoc_macronames +The string representation of an +.Xr mdoc 7 +macro as indexed by +.Vt "enum mdoct" . +.El +.Sh IMPLEMENTATION NOTES +This section consists of structural documentation for +.Xr mdoc 7 +and +.Xr man 7 +syntax trees and strings. +.Ss Man and Mdoc Strings +Strings may be extracted from mdoc and man meta-data, or from text +nodes (MDOC_TEXT and MAN_TEXT, respectively). +These strings have special non-printing formatting cues embedded in the +text itself, as well as +.Xr roff 7 +escapes preserved from input. +Implementing systems will need to handle both situations to produce +human-readable text. +In general, strings may be assumed to consist of 7-bit ASCII characters. +.Pp +The following non-printing characters may be embedded in text strings: +.Bl -tag -width Ds +.It Dv ASCII_NBRSP +A non-breaking space character. +.It Dv ASCII_HYPH +A soft hyphen. +.It Dv ASCII_BREAK +A breakable zero-width space. +.El +.Pp +Escape characters are also passed verbatim into text strings. +An escape character is a sequence of characters beginning with the +backslash +.Pq Sq \e . +To construct human-readable text, these should be intercepted with +.Xr mandoc_escape 3 +and converted with one the functions described in +.Xr mchars_alloc 3 . +.Ss Man Abstract Syntax Tree +This AST is governed by the ontological rules dictated in +.Xr man 7 +and derives its terminology accordingly. +.Pp +The AST is composed of +.Vt struct roff_node +nodes with element, root and text types as declared by the +.Va type +field. +Each node also provides its parse point (the +.Va line , +.Va pos , +and +.Va sec +fields), its position in the tree (the +.Va parent , +.Va child , +.Va next +and +.Va prev +fields) and some type-specific data. +.Pp +The tree itself is arranged according to the following normal form, +where capitalised non-terminals represent nodes. +.Pp +.Bl -tag -width "ELEMENTXX" -compact +.It ROOT +\(<- mnode+ +.It mnode +\(<- ELEMENT | TEXT | BLOCK +.It BLOCK +\(<- HEAD BODY +.It HEAD +\(<- mnode* +.It BODY +\(<- mnode* +.It ELEMENT +\(<- ELEMENT | TEXT* +.It TEXT +\(<- [[:ascii:]]* +.El +.Pp +The only elements capable of nesting other elements are those with +next-line scope as documented in +.Xr man 7 . +.Ss Mdoc Abstract Syntax Tree +This AST is governed by the ontological +rules dictated in +.Xr mdoc 7 +and derives its terminology accordingly. +.Qq In-line +elements described in +.Xr mdoc 7 +are described simply as +.Qq elements . +.Pp +The AST is composed of +.Vt struct roff_node +nodes with block, head, body, element, root and text types as declared +by the +.Va type +field. +Each node also provides its parse point (the +.Va line , +.Va pos , +and +.Va sec +fields), its position in the tree (the +.Va parent , +.Va child , +.Va last , +.Va next +and +.Va prev +fields) and some type-specific data, in particular, for nodes generated +from macros, the generating macro in the +.Va tok +field. +.Pp +The tree itself is arranged according to the following normal form, +where capitalised non-terminals represent nodes. +.Pp +.Bl -tag -width "ELEMENTXX" -compact +.It ROOT +\(<- mnode+ +.It mnode +\(<- BLOCK | ELEMENT | TEXT +.It BLOCK +\(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]] +.It ELEMENT +\(<- TEXT* +.It HEAD +\(<- mnode* +.It BODY +\(<- mnode* [ENDBODY mnode*] +.It TAIL +\(<- mnode* +.It TEXT +\(<- [[:ascii:]]* +.El +.Pp +Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of +the BLOCK production: these refer to punctuation marks. +Furthermore, although a TEXT node will generally have a non-zero-length +string, in the specific case of +.Sq \&.Bd \-literal , +an empty line will produce a zero-length string. +Multiple body parts are only found in invocations of +.Sq \&Bl \-column , +where a new body introduces a new phrase. +.Pp +The +.Xr mdoc 7 +syntax tree accommodates for broken block structures as well. +The ENDBODY node is available to end the formatting associated +with a given block before the physical end of that block. +It has a non-null +.Va end +field, is of the BODY +.Va type , +has the same +.Va tok +as the BLOCK it is ending, and has a +.Va pending +field pointing to that BLOCK's BODY node. +It is an indirect child of that BODY node +and has no children of its own. +.Pp +An ENDBODY node is generated when a block ends while one of its child +blocks is still open, like in the following example: +.Bd -literal -offset indent +\&.Ao ao +\&.Bo bo ac +\&.Ac bc +\&.Bc end +.Ed +.Pp +This example results in the following block structure: +.Bd -literal -offset indent +BLOCK Ao + HEAD Ao + BODY Ao + TEXT ao + BLOCK Bo, pending -> Ao + HEAD Bo + BODY Bo + TEXT bo + TEXT ac + ENDBODY Ao, pending -> Ao + TEXT bc +TEXT end +.Ed +.Pp +Here, the formatting of the +.Ic \&Ao +block extends from TEXT ao to TEXT ac, +while the formatting of the +.Ic \&Bo +block extends from TEXT bo to TEXT bc. +It renders as follows in +.Fl T Ns Cm ascii +mode: +.Pp +.Dl bc] end +.Pp +Support for badly-nested blocks is only provided for backward +compatibility with some older +.Xr mdoc 7 +implementations. +Using badly-nested blocks is +.Em strongly discouraged ; +for example, the +.Fl T Ns Cm html +front-end to +.Xr mandoc 1 +is unable to render them in any meaningful way. +Furthermore, behaviour when encountering badly-nested blocks is not +consistent across troff implementations, especially when using multiple +levels of badly-nested blocks. +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr man.cgi 3 , +.Xr mandoc_escape 3 , +.Xr mandoc_headers 3 , +.Xr mandoc_malloc 3 , +.Xr mansearch 3 , +.Xr mchars_alloc 3 , +.Xr tbl 3 , +.Xr eqn 7 , +.Xr man 7 , +.Xr mandoc_char 7 , +.Xr mdoc 7 , +.Xr roff 7 , +.Xr tbl 7 +.Sh AUTHORS +.An -nosplit +The +.Nm +library was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +and is maintained by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: vendor/mandoc/20190723/mandoc.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_html.3 =================================================================== --- vendor/mandoc/20190723/mandoc_html.3 (nonexistent) +++ vendor/mandoc/20190723/mandoc_html.3 (revision 350350) @@ -0,0 +1,328 @@ +.\" $Id: mandoc_html.3,v 1.19 2019/01/11 12:56:43 schwarze Exp $ +.\" +.\" Copyright (c) 2014, 2017, 2018 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: January 11 2019 $ +.Dt MANDOC_HTML 3 +.Os +.Sh NAME +.Nm mandoc_html +.Nd internals of the mandoc HTML formatter +.Sh SYNOPSIS +.In "html.h" +.Ft void +.Fn print_gen_decls "struct html *h" +.Ft void +.Fn print_gen_comment "struct html *h" "struct roff_node *n" +.Ft void +.Fn print_gen_head "struct html *h" +.Ft struct tag * +.Fo print_otag +.Fa "struct html *h" +.Fa "enum htmltag tag" +.Fa "const char *fmt" +.Fa ... +.Fc +.Ft void +.Fo print_tagq +.Fa "struct html *h" +.Fa "const struct tag *until" +.Fc +.Ft void +.Fo print_stagq +.Fa "struct html *h" +.Fa "const struct tag *suntil" +.Fc +.Ft void +.Fo print_text +.Fa "struct html *h" +.Fa "const char *word" +.Fc +.Ft char * +.Fo html_make_id +.Fa "const struct roff_node *n" +.Fc +.Ft int +.Fo html_strlen +.Fa "const char *cp" +.Fc +.Sh DESCRIPTION +The mandoc HTML formatter is not a formal library. +However, as it is compiled into more than one program, in particular +.Xr mandoc 1 +and +.Xr man.cgi 8 , +and because it may be security-critical in some contexts, +some documentation is useful to help to use it correctly and +to prevent XSS vulnerabilities. +.Pp +The formatter produces HTML output on the standard output. +Since proper escaping is usually required and best taken care of +at one central place, the language-specific formatters +.Po +.Pa *_html.c , +see +.Sx FILES +.Pc +are not supposed to print directly to +.Dv stdout +using functions like +.Xr printf 3 , +.Xr putc 3 , +.Xr puts 3 , +or +.Xr write 2 . +Instead, they are expected to use the output functions declared in +.Pa html.h +and implemented as part of the main HTML formatting engine in +.Pa html.c . +.Ss Data structures +These structures are declared in +.Pa html.h . +.Bl -tag -width Ds +.It Vt struct html +Internal state of the HTML formatter. +.It Vt struct tag +One entry for the LIFO stack of HTML elements. +Members are +.Fa "enum htmltag tag" +and +.Fa "struct tag *next" . +.El +.Ss Private interface functions +The function +.Fn print_gen_decls +prints the opening +.Ao Pf \&? Ic xml ? Ac +and +.Aq Pf \&! Ic DOCTYPE +declarations required for the current document type. +.Pp +The function +.Fn print_gen_comment +prints the leading comments, usually containing a Copyright notice +and license, as an HTML comment. +It is intended to be called right after opening the +.Aq Ic HTML +element. +Pass the first +.Dv ROFFT_COMMENT +node in +.Fa n . +.Pp +The function +.Fn print_gen_head +prints the opening +.Aq Ic META +and +.Aq Ic LINK +elements for the document +.Aq Ic HEAD , +using the +.Fa style +member of +.Fa h +unless that is +.Dv NULL . +It uses +.Fn print_otag +which takes care of properly encoding attributes, +which is relevant for the +.Fa style +link in particular. +.Pp +The function +.Fn print_otag +prints the start tag of an HTML element with the name +.Fa tag , +optionally including the attributes specified by +.Fa fmt . +If +.Fa fmt +is the empty string, no attributes are written. +Each letter of +.Fa fmt +specifies one attribute to write. +Most attributes require one +.Va char * +argument which becomes the value of the attribute. +The arguments have to be given in the same order as the attribute letters. +If an argument is +.Dv NULL , +the respective attribute is not written. +.Bl -tag -width 1n -offset indent +.It Cm c +Print a +.Cm class +attribute. +.It Cm h +Print a +.Cm href +attribute. +This attribute letter can optionally be followed by a modifier letter. +If followed by +.Cm R , +it formats the link as a local one by prefixing a +.Sq # +character. +If followed by +.Cm I , +it interpretes the argument as a header file name +and generates a link using the +.Xr mandoc 1 +.Fl O Cm includes +option. +If followed by +.Cm M , +it takes two arguments instead of one, a manual page name and +section, and formats them as a link to a manual page using the +.Xr mandoc 1 +.Fl O Cm man +option. +.It Cm i +Print an +.Cm id +attribute. +.It Cm \&? +Print an arbitrary attribute. +This format letter requires two +.Vt char * +arguments, the attribute name and the value. +The name must not be +.Dv NULL . +.It Cm s +Print a +.Cm style +attribute. +If present, it must be the last format letter. +It requires two +.Va char * +arguments. +The first is the name of the style property, the second its value. +The name must not be +.Dv NULL . +The +.Cm s +.Ar fmt +letter can be repeated, each repetition requiring an additional pair of +.Va char * +arguments. +.El +.Pp +.Fn print_otag +uses the private function +.Fn print_encode +to take care of HTML encoding. +If required by the element type, it remembers in +.Fa h +that the element is open. +The function +.Fn print_tagq +is used to close out all open elements up to and including +.Fa until ; +.Fn print_stagq +is a variant to close out all open elements up to but excluding +.Fa suntil . +.Pp +The function +.Fn print_text +prints HTML element content. +It uses the private function +.Fn print_encode +to take care of HTML encoding. +If the document has requested a non-standard font, for example using a +.Xr roff 7 +.Ic \ef +font escape sequence, +.Fn print_text +wraps +.Fa word +in an HTML font selection element using the +.Fn print_otag +and +.Fn print_tagq +functions. +.Pp +The function +.Fn html_make_id +takes a node containing one or more text children +and returns a newly allocated string containing the concatenation +of the child strings, with blanks replaced by underscores. +If the node +.Fa n +contains any non-text child node, +.Fn html_make_id +returns +.Dv NULL +instead. +The caller is responsible for freeing the returned string. +.Pp +The function +.Fn html_strlen +counts the number of characters in +.Fa cp . +It is used as a crude estimate of the width needed to display a string. +.Pp +The functions +.Fn print_eqn , +.Fn print_tbl , +and +.Fn print_tblclose +are not yet documented. +.Sh FILES +.Bl -tag -width mandoc_aux.c -compact +.It Pa main.h +declarations of public functions for use by the main program, +not yet documented +.It Pa html.h +declarations of data types and private functions +for use by language-specific HTML formatters +.It Pa html.c +main HTML formatting engine and utility functions +.It Pa mdoc_html.c +.Xr mdoc 7 +HTML formatter +.It Pa man_html.c +.Xr man 7 +HTML formatter +.It Pa tbl_html.c +.Xr tbl 7 +HTML formatter +.It Pa eqn_html.c +.Xr eqn 7 +HTML formatter +.It Pa out.h +declarations of data types and private functions +for shared use by all mandoc formatters, +not yet documented +.It Pa out.c +private functions for shared use by all mandoc formatters +.It Pa mandoc_aux.h +declarations of common mandoc utility functions, see +.Xr mandoc 3 +.It Pa mandoc_aux.c +implementation of common mandoc utility functions +.El +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr mandoc 3 , +.Xr man.cgi 8 +.Sh AUTHORS +.An -nosplit +The mandoc HTML formatter was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . +It is maintained by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org , +who also wrote this manual. Property changes on: vendor/mandoc/20190723/mandoc_html.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_parse.h =================================================================== --- vendor/mandoc/20190723/mandoc_parse.h (nonexistent) +++ vendor/mandoc/20190723/mandoc_parse.h (revision 350350) @@ -0,0 +1,43 @@ +/* $Id: mandoc_parse.h,v 1.4 2018/12/30 00:49:55 schwarze Exp $ */ +/* + * Copyright (c) 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Top level parser interface. For use in the main program + * and in the main parser, but not in formatters. + */ + +/* + * Parse options. + */ +#define MPARSE_MDOC (1 << 0) /* assume -mdoc */ +#define MPARSE_MAN (1 << 1) /* assume -man */ +#define MPARSE_SO (1 << 2) /* honour .so requests */ +#define MPARSE_QUICK (1 << 3) /* abort the parse early */ +#define MPARSE_UTF8 (1 << 4) /* accept UTF-8 input */ +#define MPARSE_LATIN1 (1 << 5) /* accept ISO-LATIN-1 input */ +#define MPARSE_VALIDATE (1 << 6) /* call validation functions */ + + +struct roff_meta; +struct mparse; + +struct mparse *mparse_alloc(int, enum mandoc_os, const char *); +void mparse_copy(const struct mparse *); +void mparse_free(struct mparse *); +int mparse_open(struct mparse *, const char *); +void mparse_readfd(struct mparse *, int, const char *); +void mparse_reset(struct mparse *); +struct roff_meta *mparse_result(struct mparse *); Property changes on: vendor/mandoc/20190723/mandoc_parse.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandocd.c =================================================================== --- vendor/mandoc/20190723/mandocd.c (nonexistent) +++ vendor/mandoc/20190723/mandocd.c (revision 350350) @@ -0,0 +1,282 @@ +/* $Id: mandocd.c,v 1.11 2019/03/03 13:02:11 schwarze Exp $ */ +/* + * Copyright (c) 2017 Michael Stapelberg + * Copyright (c) 2017, 2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#if HAVE_CMSG_XPG42 +#define _XPG4_2 +#endif + +#include +#include + +#if HAVE_ERR +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "man.h" +#include "mandoc_parse.h" +#include "main.h" +#include "manconf.h" + +enum outt { + OUTT_ASCII = 0, + OUTT_UTF8, + OUTT_HTML +}; + +static void process(struct mparse *, enum outt, void *); +static int read_fds(int, int *); +static void usage(void) __attribute__((__noreturn__)); + + +#define NUM_FDS 3 +static int +read_fds(int clientfd, int *fds) +{ + struct msghdr msg; + struct iovec iov[1]; + unsigned char dummy[1]; + struct cmsghdr *cmsg; + int *walk; + int cnt; + + /* Union used for alignment. */ + union { + uint8_t controlbuf[CMSG_SPACE(NUM_FDS * sizeof(int))]; + struct cmsghdr align; + } u; + + memset(&msg, '\0', sizeof(msg)); + msg.msg_control = u.controlbuf; + msg.msg_controllen = sizeof(u.controlbuf); + + /* + * Read a dummy byte - sendmsg cannot send an empty message, + * even if we are only interested in the OOB data. + */ + + iov[0].iov_base = dummy; + iov[0].iov_len = sizeof(dummy); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + switch (recvmsg(clientfd, &msg, 0)) { + case -1: + warn("recvmsg"); + return -1; + case 0: + return 0; + default: + break; + } + + if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) { + warnx("CMSG_FIRSTHDR: missing control message"); + return -1; + } + + if (cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS || + cmsg->cmsg_len != CMSG_LEN(NUM_FDS * sizeof(int))) { + warnx("CMSG_FIRSTHDR: invalid control message"); + return -1; + } + + walk = (int *)CMSG_DATA(cmsg); + for (cnt = 0; cnt < NUM_FDS; cnt++) + fds[cnt] = *walk++; + + return 1; +} + +int +main(int argc, char *argv[]) +{ + struct manoutput options; + struct mparse *parser; + void *formatter; + const char *defos; + const char *errstr; + int clientfd; + int old_stdin; + int old_stdout; + int old_stderr; + int fds[3]; + int state, opt; + enum outt outtype; + + defos = NULL; + outtype = OUTT_ASCII; + while ((opt = getopt(argc, argv, "I:T:")) != -1) { + switch (opt) { + case 'I': + if (strncmp(optarg, "os=", 3) == 0) + defos = optarg + 3; + else { + warnx("-I %s: Bad argument", optarg); + usage(); + } + break; + case 'T': + if (strcmp(optarg, "ascii") == 0) + outtype = OUTT_ASCII; + else if (strcmp(optarg, "utf8") == 0) + outtype = OUTT_UTF8; + else if (strcmp(optarg, "html") == 0) + outtype = OUTT_HTML; + else { + warnx("-T %s: Bad argument", optarg); + usage(); + } + break; + default: + usage(); + } + } + + if (argc > 0) { + argc -= optind; + argv += optind; + } + if (argc != 1) + usage(); + + errstr = NULL; + clientfd = strtonum(argv[0], 3, INT_MAX, &errstr); + if (errstr) + errx(1, "file descriptor %s %s", argv[1], errstr); + + mchars_alloc(); + parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 | + MPARSE_VALIDATE, MANDOC_OS_OTHER, defos); + + memset(&options, 0, sizeof(options)); + switch (outtype) { + case OUTT_ASCII: + formatter = ascii_alloc(&options); + break; + case OUTT_UTF8: + formatter = utf8_alloc(&options); + break; + case OUTT_HTML: + options.fragment = 1; + formatter = html_alloc(&options); + break; + } + + state = 1; /* work to do */ + fflush(stdout); + fflush(stderr); + if ((old_stdin = dup(STDIN_FILENO)) == -1 || + (old_stdout = dup(STDOUT_FILENO)) == -1 || + (old_stderr = dup(STDERR_FILENO)) == -1) { + warn("dup"); + state = -1; /* error */ + } + + while (state == 1 && (state = read_fds(clientfd, fds)) == 1) { + if (dup2(fds[0], STDIN_FILENO) == -1 || + dup2(fds[1], STDOUT_FILENO) == -1 || + dup2(fds[2], STDERR_FILENO) == -1) { + warn("dup2"); + state = -1; + break; + } + + close(fds[0]); + close(fds[1]); + close(fds[2]); + + process(parser, outtype, formatter); + mparse_reset(parser); + if (outtype == OUTT_HTML) + html_reset(formatter); + + fflush(stdout); + fflush(stderr); + /* Close file descriptors by restoring the old ones. */ + if (dup2(old_stderr, STDERR_FILENO) == -1 || + dup2(old_stdout, STDOUT_FILENO) == -1 || + dup2(old_stdin, STDIN_FILENO) == -1) { + warn("dup2"); + state = -1; + break; + } + } + + close(clientfd); + switch (outtype) { + case OUTT_ASCII: + case OUTT_UTF8: + ascii_free(formatter); + break; + case OUTT_HTML: + html_free(formatter); + break; + } + mparse_free(parser); + mchars_free(); + return state == -1 ? 1 : 0; +} + +static void +process(struct mparse *parser, enum outt outtype, void *formatter) +{ + struct roff_meta *meta; + + mparse_readfd(parser, STDIN_FILENO, ""); + meta = mparse_result(parser); + if (meta->macroset == MACROSET_MDOC) { + switch (outtype) { + case OUTT_ASCII: + case OUTT_UTF8: + terminal_mdoc(formatter, meta); + break; + case OUTT_HTML: + html_mdoc(formatter, meta); + break; + } + } + if (meta->macroset == MACROSET_MAN) { + switch (outtype) { + case OUTT_ASCII: + case OUTT_UTF8: + terminal_man(formatter, meta); + break; + case OUTT_HTML: + html_man(formatter, meta); + break; + } + } +} + +void +usage(void) +{ + fprintf(stderr, "usage: mandocd [-I os=name] [-T output] socket_fd\n"); + exit(1); +} Property changes on: vendor/mandoc/20190723/mandocd.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mdoc.c =================================================================== --- vendor/mandoc/20190723/mdoc.c (nonexistent) +++ vendor/mandoc/20190723/mdoc.c (revision 350350) @@ -0,0 +1,430 @@ +/* $Id: mdoc.c,v 1.274 2018/12/31 07:46:07 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * 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 +#include +#include +#include +#include +#include + +#include "mandoc_aux.h" +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "libmandoc.h" +#include "roff_int.h" +#include "libmdoc.h" + +const char *const __mdoc_argnames[MDOC_ARG_MAX] = { + "split", "nosplit", "ragged", + "unfilled", "literal", "file", + "offset", "bullet", "dash", + "hyphen", "item", "enum", + "tag", "diag", "hang", + "ohang", "inset", "column", + "width", "compact", "std", + "filled", "words", "emphasis", + "symbolic", "nested", "centered" +}; +const char * const *mdoc_argnames = __mdoc_argnames; + +static int mdoc_ptext(struct roff_man *, int, char *, int); +static int mdoc_pmacro(struct roff_man *, int, char *, int); + + +/* + * Main parse routine. Parses a single line -- really just hands off to + * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()). + */ +int +mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs) +{ + + if (mdoc->last->type != ROFFT_EQN || ln > mdoc->last->line) + mdoc->flags |= MDOC_NEWLINE; + + /* + * Let the roff nS register switch SYNOPSIS mode early, + * such that the parser knows at all times + * whether this mode is on or off. + * Note that this mode is also switched by the Sh macro. + */ + if (roff_getreg(mdoc->roff, "nS")) + mdoc->flags |= MDOC_SYNOPSIS; + else + mdoc->flags &= ~MDOC_SYNOPSIS; + + return roff_getcontrol(mdoc->roff, buf, &offs) ? + mdoc_pmacro(mdoc, ln, buf, offs) : + mdoc_ptext(mdoc, ln, buf, offs); +} + +void +mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, enum roff_tok tok) +{ + struct roff_node *p; + + p = roff_node_alloc(mdoc, line, pos, ROFFT_TAIL, tok); + roff_node_append(mdoc, p); + mdoc->next = ROFF_NEXT_CHILD; +} + +struct roff_node * +mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos, + enum roff_tok tok, struct roff_node *body) +{ + struct roff_node *p; + + body->flags |= NODE_ENDED; + body->parent->flags |= NODE_ENDED; + p = roff_node_alloc(mdoc, line, pos, ROFFT_BODY, tok); + p->body = body; + p->norm = body->norm; + p->end = ENDBODY_SPACE; + roff_node_append(mdoc, p); + mdoc->next = ROFF_NEXT_SIBLING; + return p; +} + +struct roff_node * +mdoc_block_alloc(struct roff_man *mdoc, int line, int pos, + enum roff_tok tok, struct mdoc_arg *args) +{ + struct roff_node *p; + + p = roff_node_alloc(mdoc, line, pos, ROFFT_BLOCK, tok); + p->args = args; + if (p->args) + (args->refcnt)++; + + switch (tok) { + case MDOC_Bd: + case MDOC_Bf: + case MDOC_Bl: + case MDOC_En: + case MDOC_Rs: + p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); + break; + default: + break; + } + roff_node_append(mdoc, p); + mdoc->next = ROFF_NEXT_CHILD; + return p; +} + +void +mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos, + enum roff_tok tok, struct mdoc_arg *args) +{ + struct roff_node *p; + + p = roff_node_alloc(mdoc, line, pos, ROFFT_ELEM, tok); + p->args = args; + if (p->args) + (args->refcnt)++; + + switch (tok) { + case MDOC_An: + p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); + break; + default: + break; + } + roff_node_append(mdoc, p); + mdoc->next = ROFF_NEXT_CHILD; +} + +/* + * Parse free-form text, that is, a line that does not begin with the + * control character. + */ +static int +mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) +{ + struct roff_node *n; + const char *cp, *sp; + char *c, *ws, *end; + + n = mdoc->last; + + /* + * If a column list contains plain text, assume an implicit item + * macro. This can happen one or more times at the beginning + * of such a list, intermixed with non-It mdoc macros and with + * nodes generated on the roff level, for example by tbl. + */ + + if ((n->tok == MDOC_Bl && n->type == ROFFT_BODY && + n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) || + (n->parent != NULL && n->parent->tok == MDOC_Bl && + n->parent->norm->Bl.type == LIST_column)) { + mdoc->flags |= MDOC_FREECOL; + (*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It, + line, offs, &offs, buf); + return 1; + } + + /* + * Search for the beginning of unescaped trailing whitespace (ws) + * and for the first character not to be output (end). + */ + + /* FIXME: replace with strcspn(). */ + ws = NULL; + for (c = end = buf + offs; *c; c++) { + switch (*c) { + case ' ': + if (NULL == ws) + ws = c; + continue; + case '\t': + /* + * Always warn about trailing tabs, + * even outside literal context, + * where they should be put on the next line. + */ + if (NULL == ws) + ws = c; + /* + * Strip trailing tabs in literal context only; + * outside, they affect the next line. + */ + if (mdoc->flags & ROFF_NOFILL) + continue; + break; + case '\\': + /* Skip the escaped character, too, if any. */ + if (c[1]) + c++; + /* FALLTHROUGH */ + default: + ws = NULL; + break; + } + end = c + 1; + } + *end = '\0'; + + if (ws) + mandoc_msg(MANDOCERR_SPACE_EOL, line, (int)(ws - buf), NULL); + + /* + * Blank lines are allowed in no-fill mode + * and cancel preceding \c, + * but add a single vertical space elsewhere. + */ + + if (buf[offs] == '\0' && (mdoc->flags & ROFF_NOFILL) == 0) { + switch (mdoc->last->type) { + case ROFFT_TEXT: + sp = mdoc->last->string; + cp = end = strchr(sp, '\0') - 2; + if (cp < sp || cp[0] != '\\' || cp[1] != 'c') + break; + while (cp > sp && cp[-1] == '\\') + cp--; + if ((end - cp) % 2) + break; + *end = '\0'; + return 1; + default: + break; + } + mandoc_msg(MANDOCERR_FI_BLANK, line, (int)(c - buf), NULL); + roff_elem_alloc(mdoc, line, offs, ROFF_sp); + mdoc->last->flags |= NODE_VALID | NODE_ENDED; + mdoc->next = ROFF_NEXT_SIBLING; + return 1; + } + + roff_word_alloc(mdoc, line, offs, buf+offs); + + if (mdoc->flags & ROFF_NOFILL) + return 1; + + /* + * End-of-sentence check. If the last character is an unescaped + * EOS character, then flag the node as being the end of a + * sentence. The front-end will know how to interpret this. + */ + + assert(buf < end); + + if (mandoc_eos(buf+offs, (size_t)(end-buf-offs))) + mdoc->last->flags |= NODE_EOS; + + for (c = buf + offs; c != NULL; c = strchr(c + 1, '.')) { + if (c - buf < offs + 2) + continue; + if (end - c < 3) + break; + if (c[1] != ' ' || + isalnum((unsigned char)c[-2]) == 0 || + isalnum((unsigned char)c[-1]) == 0 || + (c[-2] == 'n' && c[-1] == 'c') || + (c[-2] == 'v' && c[-1] == 's')) + continue; + c += 2; + if (*c == ' ') + c++; + if (*c == ' ') + c++; + if (isupper((unsigned char)(*c))) + mandoc_msg(MANDOCERR_EOS, line, (int)(c - buf), NULL); + } + + return 1; +} + +/* + * Parse a macro line, that is, a line beginning with the control + * character. + */ +static int +mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs) +{ + struct roff_node *n; + const char *cp; + size_t sz; + enum roff_tok tok; + int sv; + + /* Determine the line macro. */ + + sv = offs; + tok = TOKEN_NONE; + for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++) + offs++; + if (sz == 2 || sz == 3) + tok = roffhash_find(mdoc->mdocmac, buf + sv, sz); + if (tok == TOKEN_NONE) { + mandoc_msg(MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1); + return 1; + } + + /* Skip a leading escape sequence or tab. */ + + switch (buf[offs]) { + case '\\': + cp = buf + offs + 1; + mandoc_escape(&cp, NULL, NULL); + offs = cp - buf; + break; + case '\t': + offs++; + break; + default: + break; + } + + /* Jump to the next non-whitespace word. */ + + while (buf[offs] == ' ') + offs++; + + /* + * Trailing whitespace. Note that tabs are allowed to be passed + * into the parser as "text", so we only warn about spaces here. + */ + + if ('\0' == buf[offs] && ' ' == buf[offs - 1]) + mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL); + + /* + * If an initial macro or a list invocation, divert directly + * into macro processing. + */ + + n = mdoc->last; + if (n == NULL || tok == MDOC_It || tok == MDOC_El) { + (*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf); + return 1; + } + + /* + * If a column list contains a non-It macro, assume an implicit + * item macro. This can happen one or more times at the + * beginning of such a list, intermixed with text lines and + * with nodes generated on the roff level, for example by tbl. + */ + + if ((n->tok == MDOC_Bl && n->type == ROFFT_BODY && + n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) || + (n->parent != NULL && n->parent->tok == MDOC_Bl && + n->parent->norm->Bl.type == LIST_column)) { + mdoc->flags |= MDOC_FREECOL; + (*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It, ln, sv, &sv, buf); + return 1; + } + + /* Normal processing of a macro. */ + + (*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf); + + /* In quick mode (for mandocdb), abort after the NAME section. */ + + if (mdoc->quick && MDOC_Sh == tok && + SEC_NAME != mdoc->last->sec) + return 2; + + return 1; +} + +enum mdelim +mdoc_isdelim(const char *p) +{ + + if ('\0' == p[0]) + return DELIM_NONE; + + if ('\0' == p[1]) + switch (p[0]) { + case '(': + case '[': + return DELIM_OPEN; + case '|': + return DELIM_MIDDLE; + case '.': + case ',': + case ';': + case ':': + case '?': + case '!': + case ')': + case ']': + return DELIM_CLOSE; + default: + return DELIM_NONE; + } + + if ('\\' != p[0]) + return DELIM_NONE; + + if (0 == strcmp(p + 1, ".")) + return DELIM_CLOSE; + if (0 == strcmp(p + 1, "fR|\\fP")) + return DELIM_MIDDLE; + + return DELIM_NONE; +} Property changes on: vendor/mandoc/20190723/mdoc.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mdoc.h =================================================================== --- vendor/mandoc/20190723/mdoc.h (nonexistent) +++ vendor/mandoc/20190723/mdoc.h (revision 350350) @@ -0,0 +1,158 @@ +/* $Id: mdoc.h,v 1.146 2018/12/30 00:49:55 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2014, 2015 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct roff_node; +struct roff_man; + +enum mdocargt { + MDOC_Split, /* -split */ + MDOC_Nosplit, /* -nospli */ + MDOC_Ragged, /* -ragged */ + MDOC_Unfilled, /* -unfilled */ + MDOC_Literal, /* -literal */ + MDOC_File, /* -file */ + MDOC_Offset, /* -offset */ + MDOC_Bullet, /* -bullet */ + MDOC_Dash, /* -dash */ + MDOC_Hyphen, /* -hyphen */ + MDOC_Item, /* -item */ + MDOC_Enum, /* -enum */ + MDOC_Tag, /* -tag */ + MDOC_Diag, /* -diag */ + MDOC_Hang, /* -hang */ + MDOC_Ohang, /* -ohang */ + MDOC_Inset, /* -inset */ + MDOC_Column, /* -column */ + MDOC_Width, /* -width */ + MDOC_Compact, /* -compact */ + MDOC_Std, /* -std */ + MDOC_Filled, /* -filled */ + MDOC_Words, /* -words */ + MDOC_Emphasis, /* -emphasis */ + MDOC_Symbolic, /* -symbolic */ + MDOC_Nested, /* -nested */ + MDOC_Centred, /* -centered */ + MDOC_ARG_MAX +}; + +/* + * An argument to a macro (multiple values = `-column xxx yyy'). + */ +struct mdoc_argv { + enum mdocargt arg; /* type of argument */ + int line; + int pos; + size_t sz; /* elements in "value" */ + char **value; /* argument strings */ +}; + +/* + * Reference-counted macro arguments. These are refcounted because + * blocks have multiple instances of the same arguments spread across + * the HEAD, BODY, TAIL, and BLOCK node types. + */ +struct mdoc_arg { + size_t argc; + struct mdoc_argv *argv; + unsigned int refcnt; +}; + +enum mdoc_list { + LIST__NONE = 0, + LIST_bullet, /* -bullet */ + LIST_column, /* -column */ + LIST_dash, /* -dash */ + LIST_diag, /* -diag */ + LIST_enum, /* -enum */ + LIST_hang, /* -hang */ + LIST_hyphen, /* -hyphen */ + LIST_inset, /* -inset */ + LIST_item, /* -item */ + LIST_ohang, /* -ohang */ + LIST_tag, /* -tag */ + LIST_MAX +}; + +enum mdoc_disp { + DISP__NONE = 0, + DISP_centered, /* -centered */ + DISP_ragged, /* -ragged */ + DISP_unfilled, /* -unfilled */ + DISP_filled, /* -filled */ + DISP_literal /* -literal */ +}; + +enum mdoc_auth { + AUTH__NONE = 0, + AUTH_split, /* -split */ + AUTH_nosplit /* -nosplit */ +}; + +enum mdoc_font { + FONT__NONE = 0, + FONT_Em, /* Em, -emphasis */ + FONT_Li, /* Li, -literal */ + FONT_Sy /* Sy, -symbolic */ +}; + +struct mdoc_bd { + const char *offs; /* -offset */ + enum mdoc_disp type; /* -ragged, etc. */ + int comp; /* -compact */ +}; + +struct mdoc_bl { + const char *width; /* -width */ + const char *offs; /* -offset */ + enum mdoc_list type; /* -tag, -enum, etc. */ + int comp; /* -compact */ + size_t ncols; /* -column arg count */ + const char **cols; /* -column val ptr */ + int count; /* -enum counter */ +}; + +struct mdoc_bf { + enum mdoc_font font; /* font */ +}; + +struct mdoc_an { + enum mdoc_auth auth; /* -split, etc. */ +}; + +struct mdoc_rs { + int quote_T; /* whether to quote %T */ +}; + +/* + * Consists of normalised node arguments. These should be used instead + * of iterating through the mdoc_arg pointers of a node: defaults are + * provided, etc. + */ +union mdoc_data { + struct mdoc_an An; + struct mdoc_bd Bd; + struct mdoc_bf Bf; + struct mdoc_bl Bl; + struct roff_node *Es; + struct mdoc_rs Rs; +}; + +/* Names of macro args. Index is enum mdocargt. */ +extern const char *const *mdoc_argnames; + +void mdoc_validate(struct roff_man *); Property changes on: vendor/mandoc/20190723/mdoc.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mdoc_html.c =================================================================== --- vendor/mandoc/20190723/mdoc_html.c (nonexistent) +++ vendor/mandoc/20190723/mdoc_html.c (revision 350350) @@ -0,0 +1,1841 @@ +/* $Id: mdoc_html.c,v 1.328 2019/03/01 10:57:18 schwarze Exp $ */ +/* + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons + * Copyright (c) 2014-2019 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 "mdoc.h" +#include "out.h" +#include "html.h" +#include "main.h" + +#define MDOC_ARGS const struct roff_meta *meta, \ + struct roff_node *n, \ + struct html *h + +#ifndef MIN +#define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b)) +#endif + +struct mdoc_html_act { + int (*pre)(MDOC_ARGS); + void (*post)(MDOC_ARGS); +}; + +static char *cond_id(const struct roff_node *); +static void print_mdoc_head(const struct roff_meta *, + struct html *); +static void print_mdoc_node(MDOC_ARGS); +static void print_mdoc_nodelist(MDOC_ARGS); +static void synopsis_pre(struct html *, + const struct roff_node *); + +static void mdoc_root_post(const struct roff_meta *, + struct html *); +static int mdoc_root_pre(const struct roff_meta *, + struct html *); + +static void mdoc__x_post(MDOC_ARGS); +static int mdoc__x_pre(MDOC_ARGS); +static int mdoc_abort_pre(MDOC_ARGS); +static int mdoc_ad_pre(MDOC_ARGS); +static int mdoc_an_pre(MDOC_ARGS); +static int mdoc_ap_pre(MDOC_ARGS); +static int mdoc_ar_pre(MDOC_ARGS); +static int mdoc_bd_pre(MDOC_ARGS); +static int mdoc_bf_pre(MDOC_ARGS); +static void mdoc_bk_post(MDOC_ARGS); +static int mdoc_bk_pre(MDOC_ARGS); +static int mdoc_bl_pre(MDOC_ARGS); +static int mdoc_cd_pre(MDOC_ARGS); +static int mdoc_cm_pre(MDOC_ARGS); +static int mdoc_d1_pre(MDOC_ARGS); +static int mdoc_dv_pre(MDOC_ARGS); +static int mdoc_fa_pre(MDOC_ARGS); +static int mdoc_fd_pre(MDOC_ARGS); +static int mdoc_fl_pre(MDOC_ARGS); +static int mdoc_fn_pre(MDOC_ARGS); +static int mdoc_ft_pre(MDOC_ARGS); +static int mdoc_em_pre(MDOC_ARGS); +static void mdoc_eo_post(MDOC_ARGS); +static int mdoc_eo_pre(MDOC_ARGS); +static int mdoc_er_pre(MDOC_ARGS); +static int mdoc_ev_pre(MDOC_ARGS); +static int mdoc_ex_pre(MDOC_ARGS); +static void mdoc_fo_post(MDOC_ARGS); +static int mdoc_fo_pre(MDOC_ARGS); +static int mdoc_ic_pre(MDOC_ARGS); +static int mdoc_igndelim_pre(MDOC_ARGS); +static int mdoc_in_pre(MDOC_ARGS); +static int mdoc_it_pre(MDOC_ARGS); +static int mdoc_lb_pre(MDOC_ARGS); +static int mdoc_li_pre(MDOC_ARGS); +static int mdoc_lk_pre(MDOC_ARGS); +static int mdoc_mt_pre(MDOC_ARGS); +static int mdoc_ms_pre(MDOC_ARGS); +static int mdoc_nd_pre(MDOC_ARGS); +static int mdoc_nm_pre(MDOC_ARGS); +static int mdoc_no_pre(MDOC_ARGS); +static int mdoc_ns_pre(MDOC_ARGS); +static int mdoc_pa_pre(MDOC_ARGS); +static void mdoc_pf_post(MDOC_ARGS); +static int mdoc_pp_pre(MDOC_ARGS); +static void mdoc_quote_post(MDOC_ARGS); +static int mdoc_quote_pre(MDOC_ARGS); +static int mdoc_rs_pre(MDOC_ARGS); +static int mdoc_sh_pre(MDOC_ARGS); +static int mdoc_skip_pre(MDOC_ARGS); +static int mdoc_sm_pre(MDOC_ARGS); +static int mdoc_ss_pre(MDOC_ARGS); +static int mdoc_st_pre(MDOC_ARGS); +static int mdoc_sx_pre(MDOC_ARGS); +static int mdoc_sy_pre(MDOC_ARGS); +static int mdoc_va_pre(MDOC_ARGS); +static int mdoc_vt_pre(MDOC_ARGS); +static int mdoc_xr_pre(MDOC_ARGS); +static int mdoc_xx_pre(MDOC_ARGS); + +static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = { + {NULL, NULL}, /* Dd */ + {NULL, NULL}, /* Dt */ + {NULL, NULL}, /* Os */ + {mdoc_sh_pre, NULL }, /* Sh */ + {mdoc_ss_pre, NULL }, /* Ss */ + {mdoc_pp_pre, NULL}, /* Pp */ + {mdoc_d1_pre, NULL}, /* D1 */ + {mdoc_d1_pre, NULL}, /* Dl */ + {mdoc_bd_pre, NULL}, /* Bd */ + {NULL, NULL}, /* Ed */ + {mdoc_bl_pre, NULL}, /* Bl */ + {NULL, NULL}, /* El */ + {mdoc_it_pre, NULL}, /* It */ + {mdoc_ad_pre, NULL}, /* Ad */ + {mdoc_an_pre, NULL}, /* An */ + {mdoc_ap_pre, NULL}, /* Ap */ + {mdoc_ar_pre, NULL}, /* Ar */ + {mdoc_cd_pre, NULL}, /* Cd */ + {mdoc_cm_pre, NULL}, /* Cm */ + {mdoc_dv_pre, NULL}, /* Dv */ + {mdoc_er_pre, NULL}, /* Er */ + {mdoc_ev_pre, NULL}, /* Ev */ + {mdoc_ex_pre, NULL}, /* Ex */ + {mdoc_fa_pre, NULL}, /* Fa */ + {mdoc_fd_pre, NULL}, /* Fd */ + {mdoc_fl_pre, NULL}, /* Fl */ + {mdoc_fn_pre, NULL}, /* Fn */ + {mdoc_ft_pre, NULL}, /* Ft */ + {mdoc_ic_pre, NULL}, /* Ic */ + {mdoc_in_pre, NULL}, /* In */ + {mdoc_li_pre, NULL}, /* Li */ + {mdoc_nd_pre, NULL}, /* Nd */ + {mdoc_nm_pre, NULL}, /* Nm */ + {mdoc_quote_pre, mdoc_quote_post}, /* Op */ + {mdoc_abort_pre, NULL}, /* Ot */ + {mdoc_pa_pre, NULL}, /* Pa */ + {mdoc_ex_pre, NULL}, /* Rv */ + {mdoc_st_pre, NULL}, /* St */ + {mdoc_va_pre, NULL}, /* Va */ + {mdoc_vt_pre, NULL}, /* Vt */ + {mdoc_xr_pre, NULL}, /* Xr */ + {mdoc__x_pre, mdoc__x_post}, /* %A */ + {mdoc__x_pre, mdoc__x_post}, /* %B */ + {mdoc__x_pre, mdoc__x_post}, /* %D */ + {mdoc__x_pre, mdoc__x_post}, /* %I */ + {mdoc__x_pre, mdoc__x_post}, /* %J */ + {mdoc__x_pre, mdoc__x_post}, /* %N */ + {mdoc__x_pre, mdoc__x_post}, /* %O */ + {mdoc__x_pre, mdoc__x_post}, /* %P */ + {mdoc__x_pre, mdoc__x_post}, /* %R */ + {mdoc__x_pre, mdoc__x_post}, /* %T */ + {mdoc__x_pre, mdoc__x_post}, /* %V */ + {NULL, NULL}, /* Ac */ + {mdoc_quote_pre, mdoc_quote_post}, /* Ao */ + {mdoc_quote_pre, mdoc_quote_post}, /* Aq */ + {mdoc_xx_pre, NULL}, /* At */ + {NULL, NULL}, /* Bc */ + {mdoc_bf_pre, NULL}, /* Bf */ + {mdoc_quote_pre, mdoc_quote_post}, /* Bo */ + {mdoc_quote_pre, mdoc_quote_post}, /* Bq */ + {mdoc_xx_pre, NULL}, /* Bsx */ + {mdoc_xx_pre, NULL}, /* Bx */ + {mdoc_skip_pre, NULL}, /* Db */ + {NULL, NULL}, /* Dc */ + {mdoc_quote_pre, mdoc_quote_post}, /* Do */ + {mdoc_quote_pre, mdoc_quote_post}, /* Dq */ + {NULL, NULL}, /* Ec */ /* FIXME: no space */ + {NULL, NULL}, /* Ef */ + {mdoc_em_pre, NULL}, /* Em */ + {mdoc_eo_pre, mdoc_eo_post}, /* Eo */ + {mdoc_xx_pre, NULL}, /* Fx */ + {mdoc_ms_pre, NULL}, /* Ms */ + {mdoc_no_pre, NULL}, /* No */ + {mdoc_ns_pre, NULL}, /* Ns */ + {mdoc_xx_pre, NULL}, /* Nx */ + {mdoc_xx_pre, NULL}, /* Ox */ + {NULL, NULL}, /* Pc */ + {mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */ + {mdoc_quote_pre, mdoc_quote_post}, /* Po */ + {mdoc_quote_pre, mdoc_quote_post}, /* Pq */ + {NULL, NULL}, /* Qc */ + {mdoc_quote_pre, mdoc_quote_post}, /* Ql */ + {mdoc_quote_pre, mdoc_quote_post}, /* Qo */ + {mdoc_quote_pre, mdoc_quote_post}, /* Qq */ + {NULL, NULL}, /* Re */ + {mdoc_rs_pre, NULL}, /* Rs */ + {NULL, NULL}, /* Sc */ + {mdoc_quote_pre, mdoc_quote_post}, /* So */ + {mdoc_quote_pre, mdoc_quote_post}, /* Sq */ + {mdoc_sm_pre, NULL}, /* Sm */ + {mdoc_sx_pre, NULL}, /* Sx */ + {mdoc_sy_pre, NULL}, /* Sy */ + {NULL, NULL}, /* Tn */ + {mdoc_xx_pre, NULL}, /* Ux */ + {NULL, NULL}, /* Xc */ + {NULL, NULL}, /* Xo */ + {mdoc_fo_pre, mdoc_fo_post}, /* Fo */ + {NULL, NULL}, /* Fc */ + {mdoc_quote_pre, mdoc_quote_post}, /* Oo */ + {NULL, NULL}, /* Oc */ + {mdoc_bk_pre, mdoc_bk_post}, /* Bk */ + {NULL, NULL}, /* Ek */ + {NULL, NULL}, /* Bt */ + {NULL, NULL}, /* Hf */ + {mdoc_em_pre, NULL}, /* Fr */ + {NULL, NULL}, /* Ud */ + {mdoc_lb_pre, NULL}, /* Lb */ + {mdoc_abort_pre, NULL}, /* Lp */ + {mdoc_lk_pre, NULL}, /* Lk */ + {mdoc_mt_pre, NULL}, /* Mt */ + {mdoc_quote_pre, mdoc_quote_post}, /* Brq */ + {mdoc_quote_pre, mdoc_quote_post}, /* Bro */ + {NULL, NULL}, /* Brc */ + {mdoc__x_pre, mdoc__x_post}, /* %C */ + {mdoc_skip_pre, NULL}, /* Es */ + {mdoc_quote_pre, mdoc_quote_post}, /* En */ + {mdoc_xx_pre, NULL}, /* Dx */ + {mdoc__x_pre, mdoc__x_post}, /* %Q */ + {mdoc__x_pre, mdoc__x_post}, /* %U */ + {NULL, NULL}, /* Ta */ +}; + + +/* + * See the same function in mdoc_term.c for documentation. + */ +static void +synopsis_pre(struct html *h, const struct roff_node *n) +{ + + if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags)) + return; + + if (n->prev->tok == n->tok && + MDOC_Fo != n->tok && + MDOC_Ft != n->tok && + MDOC_Fn != n->tok) { + print_otag(h, TAG_BR, ""); + return; + } + + switch (n->prev->tok) { + case MDOC_Fd: + case MDOC_Fn: + case MDOC_Fo: + case MDOC_In: + case MDOC_Vt: + break; + case MDOC_Ft: + if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) + break; + /* FALLTHROUGH */ + default: + print_otag(h, TAG_BR, ""); + return; + } + html_close_paragraph(h); + print_otag(h, TAG_P, "c", "Pp"); +} + +void +html_mdoc(void *arg, const struct roff_meta *mdoc) +{ + struct html *h; + struct roff_node *n; + struct tag *t; + + h = (struct html *)arg; + n = mdoc->first->child; + + if ((h->oflags & HTML_FRAGMENT) == 0) { + print_gen_decls(h); + print_otag(h, TAG_HTML, ""); + if (n != NULL && n->type == ROFFT_COMMENT) + print_gen_comment(h, n); + t = print_otag(h, TAG_HEAD, ""); + print_mdoc_head(mdoc, h); + print_tagq(h, t); + print_otag(h, TAG_BODY, ""); + } + + mdoc_root_pre(mdoc, h); + t = print_otag(h, TAG_DIV, "c", "manual-text"); + print_mdoc_nodelist(mdoc, n, h); + print_tagq(h, t); + mdoc_root_post(mdoc, h); + print_tagq(h, NULL); +} + +static void +print_mdoc_head(const struct roff_meta *meta, struct html *h) +{ + char *cp; + + print_gen_head(h); + + if (meta->arch != NULL && meta->msec != NULL) + mandoc_asprintf(&cp, "%s(%s) (%s)", meta->title, + meta->msec, meta->arch); + else if (meta->msec != NULL) + mandoc_asprintf(&cp, "%s(%s)", meta->title, meta->msec); + else if (meta->arch != NULL) + mandoc_asprintf(&cp, "%s (%s)", meta->title, meta->arch); + else + cp = mandoc_strdup(meta->title); + + print_otag(h, TAG_TITLE, ""); + print_text(h, cp); + free(cp); +} + +static void +print_mdoc_nodelist(MDOC_ARGS) +{ + + while (n != NULL) { + print_mdoc_node(meta, n, h); + n = n->next; + } +} + +static void +print_mdoc_node(MDOC_ARGS) +{ + struct tag *t; + int child; + + if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) + return; + + html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi); + + child = 1; + n->flags &= ~NODE_ENDED; + switch (n->type) { + case ROFFT_TEXT: + t = h->tag; + t->refcnt++; + + /* No tables in this mode... */ + assert(NULL == h->tblt); + + /* + * Make sure that if we're in a literal mode already + * (i.e., within a
) don't print the newline.
+		 */
+		if (*n->string == ' ' && n->flags & NODE_LINE &&
+		    (h->flags & HTML_NONEWLINE) == 0 &&
+		    (n->flags & NODE_NOFILL) == 0)
+			print_otag(h, TAG_BR, "");
+		if (NODE_DELIMC & n->flags)
+			h->flags |= HTML_NOSPACE;
+		print_text(h, n->string);
+		if (NODE_DELIMO & n->flags)
+			h->flags |= HTML_NOSPACE;
+		break;
+	case ROFFT_EQN:
+		t = h->tag;
+		t->refcnt++;
+		print_eqn(h, n->eqn);
+		break;
+	case ROFFT_TBL:
+		/*
+		 * This will take care of initialising all of the table
+		 * state data for the first table, then tearing it down
+		 * for the last one.
+		 */
+		print_tbl(h, n->span);
+		return;
+	default:
+		/*
+		 * Close out the current table, if it's open, and unset
+		 * the "meta" table state.  This will be reopened on the
+		 * next table element.
+		 */
+		if (h->tblt != NULL)
+			print_tblclose(h);
+		assert(h->tblt == NULL);
+		t = h->tag;
+		t->refcnt++;
+		if (n->tok < ROFF_MAX) {
+			roff_html_pre(h, n);
+			t->refcnt--;
+			print_stagq(h, t);
+			return;
+		}
+		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
+		if (mdoc_html_acts[n->tok - MDOC_Dd].pre != NULL &&
+		    (n->end == ENDBODY_NOT || n->child != NULL))
+			child = (*mdoc_html_acts[n->tok - MDOC_Dd].pre)(meta,
+			    n, h);
+		break;
+	}
+
+	if (h->flags & HTML_KEEP && n->flags & NODE_LINE) {
+		h->flags &= ~HTML_KEEP;
+		h->flags |= HTML_PREKEEP;
+	}
+
+	if (child && n->child != NULL)
+		print_mdoc_nodelist(meta, n->child, h);
+
+	t->refcnt--;
+	print_stagq(h, t);
+
+	switch (n->type) {
+	case ROFFT_TEXT:
+	case ROFFT_EQN:
+		break;
+	default:
+		if (mdoc_html_acts[n->tok - MDOC_Dd].post == NULL ||
+		    n->flags & NODE_ENDED)
+			break;
+		(*mdoc_html_acts[n->tok - MDOC_Dd].post)(meta, n, h);
+		if (n->end != ENDBODY_NOT)
+			n->body->flags |= NODE_ENDED;
+		break;
+	}
+
+	if (n->flags & NODE_NOFILL &&
+	    (n->next == NULL || n->next->flags & NODE_LINE)) {
+		h->col++;
+		print_endline(h);
+	}
+}
+
+static void
+mdoc_root_post(const struct roff_meta *meta, struct html *h)
+{
+	struct tag	*t, *tt;
+
+	t = print_otag(h, TAG_TABLE, "c", "foot");
+	tt = print_otag(h, TAG_TR, "");
+
+	print_otag(h, TAG_TD, "c", "foot-date");
+	print_text(h, meta->date);
+	print_stagq(h, tt);
+
+	print_otag(h, TAG_TD, "c", "foot-os");
+	print_text(h, meta->os);
+	print_tagq(h, t);
+}
+
+static int
+mdoc_root_pre(const struct roff_meta *meta, struct html *h)
+{
+	struct tag	*t, *tt;
+	char		*volume, *title;
+
+	if (NULL == meta->arch)
+		volume = mandoc_strdup(meta->vol);
+	else
+		mandoc_asprintf(&volume, "%s (%s)",
+		    meta->vol, meta->arch);
+
+	if (NULL == meta->msec)
+		title = mandoc_strdup(meta->title);
+	else
+		mandoc_asprintf(&title, "%s(%s)",
+		    meta->title, meta->msec);
+
+	t = print_otag(h, TAG_TABLE, "c", "head");
+	tt = print_otag(h, TAG_TR, "");
+
+	print_otag(h, TAG_TD, "c", "head-ltitle");
+	print_text(h, title);
+	print_stagq(h, tt);
+
+	print_otag(h, TAG_TD, "c", "head-vol");
+	print_text(h, volume);
+	print_stagq(h, tt);
+
+	print_otag(h, TAG_TD, "c", "head-rtitle");
+	print_text(h, title);
+	print_tagq(h, t);
+
+	free(title);
+	free(volume);
+	return 1;
+}
+
+static char *
+cond_id(const struct roff_node *n)
+{
+	if (n->child != NULL &&
+	    n->child->type == ROFFT_TEXT &&
+	    (n->prev == NULL ||
+	     (n->prev->type == ROFFT_TEXT &&
+	      strcmp(n->prev->string, "|") == 0)) &&
+	    (n->parent->tok == MDOC_It ||
+	     (n->parent->tok == MDOC_Xo &&
+	      n->parent->parent->prev == NULL &&
+	      n->parent->parent->parent->tok == MDOC_It)))
+		return html_make_id(n, 1);
+	return NULL;
+}
+
+static int
+mdoc_sh_pre(MDOC_ARGS)
+{
+	struct roff_node	*sn, *subn;
+	struct tag		*t, *tsec, *tsub;
+	char			*id;
+	int			 sc;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		if ((h->oflags & HTML_TOC) == 0 ||
+		    h->flags & HTML_TOCDONE ||
+		    n->sec <= SEC_SYNOPSIS) {
+			print_otag(h, TAG_SECTION, "c", "Sh");
+			break;
+		}
+		h->flags |= HTML_TOCDONE;
+		sc = 0;
+		for (sn = n->next; sn != NULL; sn = sn->next)
+			if (sn->sec == SEC_CUSTOM)
+				if (++sc == 2)
+					break;
+		if (sc < 2)
+			break;
+		t = print_otag(h, TAG_H1, "c", "Sh");
+		print_text(h, "TABLE OF CONTENTS");
+		print_tagq(h, t);
+		t = print_otag(h, TAG_UL, "c", "Bl-compact");
+		for (sn = n; sn != NULL; sn = sn->next) {
+			tsec = print_otag(h, TAG_LI, "");
+			id = html_make_id(sn->head, 0);
+			tsub = print_otag(h, TAG_A, "hR", id);
+			free(id);
+			print_mdoc_nodelist(meta, sn->head->child, h);
+			print_tagq(h, tsub);
+			tsub = NULL;
+			for (subn = sn->body->child; subn != NULL;
+			    subn = subn->next) {
+				if (subn->tok != MDOC_Ss)
+					continue;
+				id = html_make_id(subn->head, 0);
+				if (id == NULL)
+					continue;
+				if (tsub == NULL)
+					print_otag(h, TAG_UL,
+					    "c", "Bl-compact");
+				tsub = print_otag(h, TAG_LI, "");
+				print_otag(h, TAG_A, "hR", id);
+				free(id);
+				print_mdoc_nodelist(meta,
+				    subn->head->child, h);
+				print_tagq(h, tsub);
+			}
+			print_tagq(h, tsec);
+		}
+		print_tagq(h, t);
+		print_otag(h, TAG_SECTION, "c", "Sh");
+		break;
+	case ROFFT_HEAD:
+		id = html_make_id(n, 1);
+		print_otag(h, TAG_H1, "ci", "Sh", id);
+		if (id != NULL)
+			print_otag(h, TAG_A, "chR", "permalink", id);
+		break;
+	case ROFFT_BODY:
+		if (n->sec == SEC_AUTHORS)
+			h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
+		break;
+	default:
+		break;
+	}
+	return 1;
+}
+
+static int
+mdoc_ss_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		print_otag(h, TAG_SECTION, "c", "Ss");
+		return 1;
+	case ROFFT_HEAD:
+		break;
+	case ROFFT_BODY:
+		return 1;
+	default:
+		abort();
+	}
+
+	id = html_make_id(n, 1);
+	print_otag(h, TAG_H2, "ci", "Ss", id);
+	if (id != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	return 1;
+}
+
+static int
+mdoc_fl_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	if ((id = cond_id(n)) != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "ci", "Fl", id);
+
+	print_text(h, "\\-");
+	if (!(n->child == NULL &&
+	    (n->next == NULL ||
+	     n->next->type == ROFFT_TEXT ||
+	     n->next->flags & NODE_LINE)))
+		h->flags |= HTML_NOSPACE;
+
+	return 1;
+}
+
+static int
+mdoc_cm_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	if ((id = cond_id(n)) != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "ci", "Cm", id);
+	return 1;
+}
+
+static int
+mdoc_nd_pre(MDOC_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		return 1;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		break;
+	default:
+		abort();
+	}
+	print_text(h, "\\(em");
+	/* Cannot use TAG_SPAN because it may contain blocks. */
+	print_otag(h, TAG_DIV, "c", "Nd");
+	return 1;
+}
+
+static int
+mdoc_nm_pre(MDOC_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		break;
+	case ROFFT_HEAD:
+		print_otag(h, TAG_TD, "");
+		/* FALLTHROUGH */
+	case ROFFT_ELEM:
+		print_otag(h, TAG_CODE, "c", "Nm");
+		return 1;
+	case ROFFT_BODY:
+		print_otag(h, TAG_TD, "");
+		return 1;
+	default:
+		abort();
+	}
+	html_close_paragraph(h);
+	synopsis_pre(h, n);
+	print_otag(h, TAG_TABLE, "c", "Nm");
+	print_otag(h, TAG_TR, "");
+	return 1;
+}
+
+static int
+mdoc_xr_pre(MDOC_ARGS)
+{
+	if (NULL == n->child)
+		return 0;
+
+	if (h->base_man1)
+		print_otag(h, TAG_A, "chM", "Xr",
+		    n->child->string, n->child->next == NULL ?
+		    NULL : n->child->next->string);
+	else
+		print_otag(h, TAG_A, "c", "Xr");
+
+	n = n->child;
+	print_text(h, n->string);
+
+	if (NULL == (n = n->next))
+		return 0;
+
+	h->flags |= HTML_NOSPACE;
+	print_text(h, "(");
+	h->flags |= HTML_NOSPACE;
+	print_text(h, n->string);
+	h->flags |= HTML_NOSPACE;
+	print_text(h, ")");
+	return 0;
+}
+
+static int
+mdoc_ns_pre(MDOC_ARGS)
+{
+
+	if ( ! (NODE_LINE & n->flags))
+		h->flags |= HTML_NOSPACE;
+	return 1;
+}
+
+static int
+mdoc_ar_pre(MDOC_ARGS)
+{
+	print_otag(h, TAG_VAR, "c", "Ar");
+	return 1;
+}
+
+static int
+mdoc_xx_pre(MDOC_ARGS)
+{
+	print_otag(h, TAG_SPAN, "c", "Ux");
+	return 1;
+}
+
+static int
+mdoc_it_pre(MDOC_ARGS)
+{
+	const struct roff_node	*bl;
+	enum mdoc_list		 type;
+
+	bl = n->parent;
+	while (bl->tok != MDOC_Bl)
+		bl = bl->parent;
+	type = bl->norm->Bl.type;
+
+	switch (type) {
+	case LIST_bullet:
+	case LIST_dash:
+	case LIST_hyphen:
+	case LIST_item:
+	case LIST_enum:
+		switch (n->type) {
+		case ROFFT_HEAD:
+			return 0;
+		case ROFFT_BODY:
+			print_otag(h, TAG_LI, "");
+			break;
+		default:
+			break;
+		}
+		break;
+	case LIST_diag:
+	case LIST_hang:
+	case LIST_inset:
+	case LIST_ohang:
+		switch (n->type) {
+		case ROFFT_HEAD:
+			print_otag(h, TAG_DT, "");
+			break;
+		case ROFFT_BODY:
+			print_otag(h, TAG_DD, "");
+			break;
+		default:
+			break;
+		}
+		break;
+	case LIST_tag:
+		switch (n->type) {
+		case ROFFT_HEAD:
+			print_otag(h, TAG_DT, "");
+			break;
+		case ROFFT_BODY:
+			if (n->child == NULL) {
+				print_otag(h, TAG_DD, "s", "width", "auto");
+				print_text(h, "\\ ");
+			} else
+				print_otag(h, TAG_DD, "");
+			break;
+		default:
+			break;
+		}
+		break;
+	case LIST_column:
+		switch (n->type) {
+		case ROFFT_HEAD:
+			break;
+		case ROFFT_BODY:
+			print_otag(h, TAG_TD, "");
+			break;
+		default:
+			print_otag(h, TAG_TR, "");
+		}
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+static int
+mdoc_bl_pre(MDOC_ARGS)
+{
+	char		 cattr[32];
+	struct mdoc_bl	*bl;
+	enum htmltag	 elemtype;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		break;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		return 1;
+	default:
+		abort();
+	}
+
+	bl = &n->norm->Bl;
+	switch (bl->type) {
+	case LIST_bullet:
+		elemtype = TAG_UL;
+		(void)strlcpy(cattr, "Bl-bullet", sizeof(cattr));
+		break;
+	case LIST_dash:
+	case LIST_hyphen:
+		elemtype = TAG_UL;
+		(void)strlcpy(cattr, "Bl-dash", sizeof(cattr));
+		break;
+	case LIST_item:
+		elemtype = TAG_UL;
+		(void)strlcpy(cattr, "Bl-item", sizeof(cattr));
+		break;
+	case LIST_enum:
+		elemtype = TAG_OL;
+		(void)strlcpy(cattr, "Bl-enum", sizeof(cattr));
+		break;
+	case LIST_diag:
+		elemtype = TAG_DL;
+		(void)strlcpy(cattr, "Bl-diag", sizeof(cattr));
+		break;
+	case LIST_hang:
+		elemtype = TAG_DL;
+		(void)strlcpy(cattr, "Bl-hang", sizeof(cattr));
+		break;
+	case LIST_inset:
+		elemtype = TAG_DL;
+		(void)strlcpy(cattr, "Bl-inset", sizeof(cattr));
+		break;
+	case LIST_ohang:
+		elemtype = TAG_DL;
+		(void)strlcpy(cattr, "Bl-ohang", sizeof(cattr));
+		break;
+	case LIST_tag:
+		if (bl->offs)
+			print_otag(h, TAG_DIV, "c", "Bd-indent");
+		print_otag(h, TAG_DL, "c", bl->comp ?
+		    "Bl-tag Bl-compact" : "Bl-tag");
+		return 1;
+	case LIST_column:
+		elemtype = TAG_TABLE;
+		(void)strlcpy(cattr, "Bl-column", sizeof(cattr));
+		break;
+	default:
+		abort();
+	}
+	if (bl->offs != NULL)
+		(void)strlcat(cattr, " Bd-indent", sizeof(cattr));
+	if (bl->comp)
+		(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
+	print_otag(h, elemtype, "c", cattr);
+	return 1;
+}
+
+static int
+mdoc_ex_pre(MDOC_ARGS)
+{
+	if (n->prev)
+		print_otag(h, TAG_BR, "");
+	return 1;
+}
+
+static int
+mdoc_st_pre(MDOC_ARGS)
+{
+	print_otag(h, TAG_SPAN, "c", "St");
+	return 1;
+}
+
+static int
+mdoc_em_pre(MDOC_ARGS)
+{
+	print_otag(h, TAG_I, "c", "Em");
+	return 1;
+}
+
+static int
+mdoc_d1_pre(MDOC_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		break;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		return 1;
+	default:
+		abort();
+	}
+	print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
+	if (n->tok == MDOC_Dl)
+		print_otag(h, TAG_CODE, "c", "Li");
+	return 1;
+}
+
+static int
+mdoc_sx_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	id = html_make_id(n, 0);
+	print_otag(h, TAG_A, "chR", "Sx", id);
+	free(id);
+	return 1;
+}
+
+static int
+mdoc_bd_pre(MDOC_ARGS)
+{
+	char			 buf[16];
+	struct roff_node	*nn;
+	int			 comp;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		return 1;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		break;
+	default:
+		abort();
+	}
+
+	/* Handle preceding whitespace. */
+
+	comp = n->norm->Bd.comp;
+	for (nn = n; nn != NULL && comp == 0; nn = nn->parent) {
+		if (nn->type != ROFFT_BLOCK)
+			continue;
+		if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
+			comp = 1;
+		if (nn->prev != NULL)
+			break;
+	}
+	(void)strlcpy(buf, "Bd", sizeof(buf));
+	if (comp == 0)
+		(void)strlcat(buf, " Pp", sizeof(buf));
+
+	/* Handle the -offset argument. */
+
+	if (n->norm->Bd.offs != NULL &&
+	    strcmp(n->norm->Bd.offs, "left") != 0)
+		(void)strlcat(buf, " Bd-indent", sizeof(buf));
+
+	print_otag(h, TAG_DIV, "c", buf);
+	return 1;
+}
+
+static int
+mdoc_pa_pre(MDOC_ARGS)
+{
+	print_otag(h, TAG_SPAN, "c", "Pa");
+	return 1;
+}
+
+static int
+mdoc_ad_pre(MDOC_ARGS)
+{
+	print_otag(h, TAG_SPAN, "c", "Ad");
+	return 1;
+}
+
+static int
+mdoc_an_pre(MDOC_ARGS)
+{
+	if (n->norm->An.auth == AUTH_split) {
+		h->flags &= ~HTML_NOSPLIT;
+		h->flags |= HTML_SPLIT;
+		return 0;
+	}
+	if (n->norm->An.auth == AUTH_nosplit) {
+		h->flags &= ~HTML_SPLIT;
+		h->flags |= HTML_NOSPLIT;
+		return 0;
+	}
+
+	if (h->flags & HTML_SPLIT)
+		print_otag(h, TAG_BR, "");
+
+	if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
+		h->flags |= HTML_SPLIT;
+
+	print_otag(h, TAG_SPAN, "c", "An");
+	return 1;
+}
+
+static int
+mdoc_cd_pre(MDOC_ARGS)
+{
+	synopsis_pre(h, n);
+	print_otag(h, TAG_CODE, "c", "Cd");
+	return 1;
+}
+
+static int
+mdoc_dv_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	if ((id = cond_id(n)) != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "ci", "Dv", id);
+	return 1;
+}
+
+static int
+mdoc_ev_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	if ((id = cond_id(n)) != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "ci", "Ev", id);
+	return 1;
+}
+
+static int
+mdoc_er_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	id = n->sec == SEC_ERRORS &&
+	    (n->parent->tok == MDOC_It ||
+	     (n->parent->tok == MDOC_Bq &&
+	      n->parent->parent->parent->tok == MDOC_It)) ?
+	    html_make_id(n, 1) : NULL;
+
+	if (id != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "ci", "Er", id);
+	return 1;
+}
+
+static int
+mdoc_fa_pre(MDOC_ARGS)
+{
+	const struct roff_node	*nn;
+	struct tag		*t;
+
+	if (n->parent->tok != MDOC_Fo) {
+		print_otag(h, TAG_VAR, "c", "Fa");
+		return 1;
+	}
+
+	for (nn = n->child; nn; nn = nn->next) {
+		t = print_otag(h, TAG_VAR, "c", "Fa");
+		print_text(h, nn->string);
+		print_tagq(h, t);
+		if (nn->next) {
+			h->flags |= HTML_NOSPACE;
+			print_text(h, ",");
+		}
+	}
+
+	if (n->child && n->next && n->next->tok == MDOC_Fa) {
+		h->flags |= HTML_NOSPACE;
+		print_text(h, ",");
+	}
+
+	return 0;
+}
+
+static int
+mdoc_fd_pre(MDOC_ARGS)
+{
+	struct tag	*t;
+	char		*buf, *cp;
+
+	synopsis_pre(h, n);
+
+	if (NULL == (n = n->child))
+		return 0;
+
+	assert(n->type == ROFFT_TEXT);
+
+	if (strcmp(n->string, "#include")) {
+		print_otag(h, TAG_CODE, "c", "Fd");
+		return 1;
+	}
+
+	print_otag(h, TAG_CODE, "c", "In");
+	print_text(h, n->string);
+
+	if (NULL != (n = n->next)) {
+		assert(n->type == ROFFT_TEXT);
+
+		if (h->base_includes) {
+			cp = n->string;
+			if (*cp == '<' || *cp == '"')
+				cp++;
+			buf = mandoc_strdup(cp);
+			cp = strchr(buf, '\0') - 1;
+			if (cp >= buf && (*cp == '>' || *cp == '"'))
+				*cp = '\0';
+			t = print_otag(h, TAG_A, "chI", "In", buf);
+			free(buf);
+		} else
+			t = print_otag(h, TAG_A, "c", "In");
+
+		print_text(h, n->string);
+		print_tagq(h, t);
+
+		n = n->next;
+	}
+
+	for ( ; n; n = n->next) {
+		assert(n->type == ROFFT_TEXT);
+		print_text(h, n->string);
+	}
+
+	return 0;
+}
+
+static int
+mdoc_vt_pre(MDOC_ARGS)
+{
+	if (n->type == ROFFT_BLOCK) {
+		synopsis_pre(h, n);
+		return 1;
+	} else if (n->type == ROFFT_ELEM) {
+		synopsis_pre(h, n);
+	} else if (n->type == ROFFT_HEAD)
+		return 0;
+
+	print_otag(h, TAG_VAR, "c", "Vt");
+	return 1;
+}
+
+static int
+mdoc_ft_pre(MDOC_ARGS)
+{
+	synopsis_pre(h, n);
+	print_otag(h, TAG_VAR, "c", "Ft");
+	return 1;
+}
+
+static int
+mdoc_fn_pre(MDOC_ARGS)
+{
+	struct tag	*t;
+	char		 nbuf[BUFSIZ];
+	const char	*sp, *ep;
+	int		 sz, pretty;
+
+	pretty = NODE_SYNPRETTY & n->flags;
+	synopsis_pre(h, n);
+
+	/* Split apart into type and name. */
+	assert(n->child->string);
+	sp = n->child->string;
+
+	ep = strchr(sp, ' ');
+	if (NULL != ep) {
+		t = print_otag(h, TAG_VAR, "c", "Ft");
+
+		while (ep) {
+			sz = MIN((int)(ep - sp), BUFSIZ - 1);
+			(void)memcpy(nbuf, sp, (size_t)sz);
+			nbuf[sz] = '\0';
+			print_text(h, nbuf);
+			sp = ++ep;
+			ep = strchr(sp, ' ');
+		}
+		print_tagq(h, t);
+	}
+
+	t = print_otag(h, TAG_CODE, "c", "Fn");
+
+	if (sp)
+		print_text(h, sp);
+
+	print_tagq(h, t);
+
+	h->flags |= HTML_NOSPACE;
+	print_text(h, "(");
+	h->flags |= HTML_NOSPACE;
+
+	for (n = n->child->next; n; n = n->next) {
+		if (NODE_SYNPRETTY & n->flags)
+			t = print_otag(h, TAG_VAR, "cs", "Fa",
+			    "white-space", "nowrap");
+		else
+			t = print_otag(h, TAG_VAR, "c", "Fa");
+		print_text(h, n->string);
+		print_tagq(h, t);
+		if (n->next) {
+			h->flags |= HTML_NOSPACE;
+			print_text(h, ",");
+		}
+	}
+
+	h->flags |= HTML_NOSPACE;
+	print_text(h, ")");
+
+	if (pretty) {
+		h->flags |= HTML_NOSPACE;
+		print_text(h, ";");
+	}
+
+	return 0;
+}
+
+static int
+mdoc_sm_pre(MDOC_ARGS)
+{
+
+	if (NULL == n->child)
+		h->flags ^= HTML_NONOSPACE;
+	else if (0 == strcmp("on", n->child->string))
+		h->flags &= ~HTML_NONOSPACE;
+	else
+		h->flags |= HTML_NONOSPACE;
+
+	if ( ! (HTML_NONOSPACE & h->flags))
+		h->flags &= ~HTML_NOSPACE;
+
+	return 0;
+}
+
+static int
+mdoc_skip_pre(MDOC_ARGS)
+{
+
+	return 0;
+}
+
+static int
+mdoc_pp_pre(MDOC_ARGS)
+{
+	if ((n->flags & NODE_NOFILL) == 0) {
+		html_close_paragraph(h);
+		print_otag(h, TAG_P, "c", "Pp");
+	}
+	return 0;
+}
+
+static int
+mdoc_lk_pre(MDOC_ARGS)
+{
+	const struct roff_node *link, *descr, *punct;
+	struct tag	*t;
+
+	if ((link = n->child) == NULL)
+		return 0;
+
+	/* Find beginning of trailing punctuation. */
+	punct = n->last;
+	while (punct != link && punct->flags & NODE_DELIMC)
+		punct = punct->prev;
+	punct = punct->next;
+
+	/* Link target and link text. */
+	descr = link->next;
+	if (descr == punct)
+		descr = link;  /* no text */
+	t = print_otag(h, TAG_A, "ch", "Lk", link->string);
+	do {
+		if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
+			h->flags |= HTML_NOSPACE;
+		print_text(h, descr->string);
+		descr = descr->next;
+	} while (descr != punct);
+	print_tagq(h, t);
+
+	/* Trailing punctuation. */
+	while (punct != NULL) {
+		h->flags |= HTML_NOSPACE;
+		print_text(h, punct->string);
+		punct = punct->next;
+	}
+	return 0;
+}
+
+static int
+mdoc_mt_pre(MDOC_ARGS)
+{
+	struct tag	*t;
+	char		*cp;
+
+	for (n = n->child; n; n = n->next) {
+		assert(n->type == ROFFT_TEXT);
+
+		mandoc_asprintf(&cp, "mailto:%s", n->string);
+		t = print_otag(h, TAG_A, "ch", "Mt", cp);
+		print_text(h, n->string);
+		print_tagq(h, t);
+		free(cp);
+	}
+
+	return 0;
+}
+
+static int
+mdoc_fo_pre(MDOC_ARGS)
+{
+	struct tag	*t;
+
+	if (n->type == ROFFT_BODY) {
+		h->flags |= HTML_NOSPACE;
+		print_text(h, "(");
+		h->flags |= HTML_NOSPACE;
+		return 1;
+	} else if (n->type == ROFFT_BLOCK) {
+		synopsis_pre(h, n);
+		return 1;
+	}
+
+	if (n->child == NULL)
+		return 0;
+
+	assert(n->child->string);
+	t = print_otag(h, TAG_CODE, "c", "Fn");
+	print_text(h, n->child->string);
+	print_tagq(h, t);
+	return 0;
+}
+
+static void
+mdoc_fo_post(MDOC_ARGS)
+{
+
+	if (n->type != ROFFT_BODY)
+		return;
+	h->flags |= HTML_NOSPACE;
+	print_text(h, ")");
+	h->flags |= HTML_NOSPACE;
+	print_text(h, ";");
+}
+
+static int
+mdoc_in_pre(MDOC_ARGS)
+{
+	struct tag	*t;
+
+	synopsis_pre(h, n);
+	print_otag(h, TAG_CODE, "c", "In");
+
+	/*
+	 * The first argument of the `In' gets special treatment as
+	 * being a linked value.  Subsequent values are printed
+	 * afterward.  groff does similarly.  This also handles the case
+	 * of no children.
+	 */
+
+	if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags)
+		print_text(h, "#include");
+
+	print_text(h, "<");
+	h->flags |= HTML_NOSPACE;
+
+	if (NULL != (n = n->child)) {
+		assert(n->type == ROFFT_TEXT);
+
+		if (h->base_includes)
+			t = print_otag(h, TAG_A, "chI", "In", n->string);
+		else
+			t = print_otag(h, TAG_A, "c", "In");
+		print_text(h, n->string);
+		print_tagq(h, t);
+
+		n = n->next;
+	}
+
+	h->flags |= HTML_NOSPACE;
+	print_text(h, ">");
+
+	for ( ; n; n = n->next) {
+		assert(n->type == ROFFT_TEXT);
+		print_text(h, n->string);
+	}
+
+	return 0;
+}
+
+static int
+mdoc_ic_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	if ((id = cond_id(n)) != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "ci", "Ic", id);
+	return 1;
+}
+
+static int
+mdoc_va_pre(MDOC_ARGS)
+{
+	print_otag(h, TAG_VAR, "c", "Va");
+	return 1;
+}
+
+static int
+mdoc_ap_pre(MDOC_ARGS)
+{
+
+	h->flags |= HTML_NOSPACE;
+	print_text(h, "\\(aq");
+	h->flags |= HTML_NOSPACE;
+	return 1;
+}
+
+static int
+mdoc_bf_pre(MDOC_ARGS)
+{
+	const char	*cattr;
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		html_close_paragraph(h);
+		return 1;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		break;
+	default:
+		abort();
+	}
+
+	if (FONT_Em == n->norm->Bf.font)
+		cattr = "Bf Em";
+	else if (FONT_Sy == n->norm->Bf.font)
+		cattr = "Bf Sy";
+	else if (FONT_Li == n->norm->Bf.font)
+		cattr = "Bf Li";
+	else
+		cattr = "Bf No";
+
+	/* Cannot use TAG_SPAN because it may contain blocks. */
+	print_otag(h, TAG_DIV, "c", cattr);
+	return 1;
+}
+
+static int
+mdoc_ms_pre(MDOC_ARGS)
+{
+	char *id;
+
+	if ((id = cond_id(n)) != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_SPAN, "ci", "Ms", id);
+	return 1;
+}
+
+static int
+mdoc_igndelim_pre(MDOC_ARGS)
+{
+
+	h->flags |= HTML_IGNDELIM;
+	return 1;
+}
+
+static void
+mdoc_pf_post(MDOC_ARGS)
+{
+
+	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
+		h->flags |= HTML_NOSPACE;
+}
+
+static int
+mdoc_rs_pre(MDOC_ARGS)
+{
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		if (n->sec == SEC_SEE_ALSO)
+			html_close_paragraph(h);
+		break;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		if (n->sec == SEC_SEE_ALSO)
+			print_otag(h, TAG_P, "c", "Pp");
+		print_otag(h, TAG_CITE, "c", "Rs");
+		break;
+	default:
+		abort();
+	}
+	return 1;
+}
+
+static int
+mdoc_no_pre(MDOC_ARGS)
+{
+	char *id;
+
+	if ((id = cond_id(n)) != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_SPAN, "ci", "No", id);
+	return 1;
+}
+
+static int
+mdoc_li_pre(MDOC_ARGS)
+{
+	char	*id;
+
+	if ((id = cond_id(n)) != NULL)
+		print_otag(h, TAG_A, "chR", "permalink", id);
+	print_otag(h, TAG_CODE, "ci", "Li", id);
+	return 1;
+}
+
+static int
+mdoc_sy_pre(MDOC_ARGS)
+{
+	print_otag(h, TAG_B, "c", "Sy");
+	return 1;
+}
+
+static int
+mdoc_lb_pre(MDOC_ARGS)
+{
+	if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
+		print_otag(h, TAG_BR, "");
+
+	print_otag(h, TAG_SPAN, "c", "Lb");
+	return 1;
+}
+
+static int
+mdoc__x_pre(MDOC_ARGS)
+{
+	const char	*cattr;
+	enum htmltag	 t;
+
+	t = TAG_SPAN;
+
+	switch (n->tok) {
+	case MDOC__A:
+		cattr = "RsA";
+		if (n->prev && MDOC__A == n->prev->tok)
+			if (NULL == n->next || MDOC__A != n->next->tok)
+				print_text(h, "and");
+		break;
+	case MDOC__B:
+		t = TAG_I;
+		cattr = "RsB";
+		break;
+	case MDOC__C:
+		cattr = "RsC";
+		break;
+	case MDOC__D:
+		cattr = "RsD";
+		break;
+	case MDOC__I:
+		t = TAG_I;
+		cattr = "RsI";
+		break;
+	case MDOC__J:
+		t = TAG_I;
+		cattr = "RsJ";
+		break;
+	case MDOC__N:
+		cattr = "RsN";
+		break;
+	case MDOC__O:
+		cattr = "RsO";
+		break;
+	case MDOC__P:
+		cattr = "RsP";
+		break;
+	case MDOC__Q:
+		cattr = "RsQ";
+		break;
+	case MDOC__R:
+		cattr = "RsR";
+		break;
+	case MDOC__T:
+		cattr = "RsT";
+		break;
+	case MDOC__U:
+		print_otag(h, TAG_A, "ch", "RsU", n->child->string);
+		return 1;
+	case MDOC__V:
+		cattr = "RsV";
+		break;
+	default:
+		abort();
+	}
+
+	print_otag(h, t, "c", cattr);
+	return 1;
+}
+
+static void
+mdoc__x_post(MDOC_ARGS)
+{
+
+	if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
+		if (NULL == n->next->next || MDOC__A != n->next->next->tok)
+			if (NULL == n->prev || MDOC__A != n->prev->tok)
+				return;
+
+	/* TODO: %U */
+
+	if (NULL == n->parent || MDOC_Rs != n->parent->tok)
+		return;
+
+	h->flags |= HTML_NOSPACE;
+	print_text(h, n->next ? "," : ".");
+}
+
+static int
+mdoc_bk_pre(MDOC_ARGS)
+{
+
+	switch (n->type) {
+	case ROFFT_BLOCK:
+		break;
+	case ROFFT_HEAD:
+		return 0;
+	case ROFFT_BODY:
+		if (n->parent->args != NULL || n->prev->child == NULL)
+			h->flags |= HTML_PREKEEP;
+		break;
+	default:
+		abort();
+	}
+
+	return 1;
+}
+
+static void
+mdoc_bk_post(MDOC_ARGS)
+{
+
+	if (n->type == ROFFT_BODY)
+		h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
+}
+
+static int
+mdoc_quote_pre(MDOC_ARGS)
+{
+	if (n->type != ROFFT_BODY)
+		return 1;
+
+	switch (n->tok) {
+	case MDOC_Ao:
+	case MDOC_Aq:
+		print_text(h, n->child != NULL && n->child->next == NULL &&
+		    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
+		break;
+	case MDOC_Bro:
+	case MDOC_Brq:
+		print_text(h, "\\(lC");
+		break;
+	case MDOC_Bo:
+	case MDOC_Bq:
+		print_text(h, "\\(lB");
+		break;
+	case MDOC_Oo:
+	case MDOC_Op:
+		print_text(h, "\\(lB");
+		/*
+		 * Give up on semantic markup for now.
+		 * We cannot use TAG_SPAN because .Oo may contain blocks.
+		 * We cannot use TAG_IDIV because we might be in a
+		 * phrasing context (like .Dl or .Pp); we cannot
+		 * close out a .Pp at this point either because
+		 * that would break the line.
+		 */
+		/* XXX print_otag(h, TAG_???, "c", "Op"); */
+		break;
+	case MDOC_En:
+		if (NULL == n->norm->Es ||
+		    NULL == n->norm->Es->child)
+			return 1;
+		print_text(h, n->norm->Es->child->string);
+		break;
+	case MDOC_Do:
+	case MDOC_Dq:
+	case MDOC_Qo:
+	case MDOC_Qq:
+		print_text(h, "\\(lq");
+		break;
+	case MDOC_Po:
+	case MDOC_Pq:
+		print_text(h, "(");
+		break;
+	case MDOC_Ql:
+		print_text(h, "\\(oq");
+		h->flags |= HTML_NOSPACE;
+		print_otag(h, TAG_CODE, "c", "Li");
+		break;
+	case MDOC_So:
+	case MDOC_Sq:
+		print_text(h, "\\(oq");
+		break;
+	default:
+		abort();
+	}
+
+	h->flags |= HTML_NOSPACE;
+	return 1;
+}
+
+static void
+mdoc_quote_post(MDOC_ARGS)
+{
+
+	if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
+		return;
+
+	h->flags |= HTML_NOSPACE;
+
+	switch (n->tok) {
+	case MDOC_Ao:
+	case MDOC_Aq:
+		print_text(h, n->child != NULL && n->child->next == NULL &&
+		    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
+		break;
+	case MDOC_Bro:
+	case MDOC_Brq:
+		print_text(h, "\\(rC");
+		break;
+	case MDOC_Oo:
+	case MDOC_Op:
+	case MDOC_Bo:
+	case MDOC_Bq:
+		print_text(h, "\\(rB");
+		break;
+	case MDOC_En:
+		if (n->norm->Es == NULL ||
+		    n->norm->Es->child == NULL ||
+		    n->norm->Es->child->next == NULL)
+			h->flags &= ~HTML_NOSPACE;
+		else
+			print_text(h, n->norm->Es->child->next->string);
+		break;
+	case MDOC_Qo:
+	case MDOC_Qq:
+	case MDOC_Do:
+	case MDOC_Dq:
+		print_text(h, "\\(rq");
+		break;
+	case MDOC_Po:
+	case MDOC_Pq:
+		print_text(h, ")");
+		break;
+	case MDOC_Ql:
+	case MDOC_So:
+	case MDOC_Sq:
+		print_text(h, "\\(cq");
+		break;
+	default:
+		abort();
+	}
+}
+
+static int
+mdoc_eo_pre(MDOC_ARGS)
+{
+
+	if (n->type != ROFFT_BODY)
+		return 1;
+
+	if (n->end == ENDBODY_NOT &&
+	    n->parent->head->child == NULL &&
+	    n->child != NULL &&
+	    n->child->end != ENDBODY_NOT)
+		print_text(h, "\\&");
+	else if (n->end != ENDBODY_NOT ? n->child != NULL :
+	    n->parent->head->child != NULL && (n->child != NULL ||
+	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
+		h->flags |= HTML_NOSPACE;
+	return 1;
+}
+
+static void
+mdoc_eo_post(MDOC_ARGS)
+{
+	int	 body, tail;
+
+	if (n->type != ROFFT_BODY)
+		return;
+
+	if (n->end != ENDBODY_NOT) {
+		h->flags &= ~HTML_NOSPACE;
+		return;
+	}
+
+	body = n->child != NULL || n->parent->head->child != NULL;
+	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
+
+	if (body && tail)
+		h->flags |= HTML_NOSPACE;
+	else if ( ! tail)
+		h->flags &= ~HTML_NOSPACE;
+}
+
+static int
+mdoc_abort_pre(MDOC_ARGS)
+{
+	abort();
+}

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

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

Property changes on: vendor/mandoc/20190723/mdoc_man.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/mdoc_state.c
===================================================================
--- vendor/mandoc/20190723/mdoc_state.c	(nonexistent)
+++ vendor/mandoc/20190723/mdoc_state.c	(revision 350350)
@@ -0,0 +1,253 @@
+/*	$Id: mdoc_state.c,v 1.15 2019/01/01 07:42:04 schwarze Exp $ */
+/*
+ * Copyright (c) 2014, 2015, 2017 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include "mandoc.h"
+#include "roff.h"
+#include "mdoc.h"
+#include "libmandoc.h"
+#include "roff_int.h"
+#include "libmdoc.h"
+
+#define STATE_ARGS  struct roff_man *mdoc, struct roff_node *n
+
+typedef	void	(*state_handler)(STATE_ARGS);
+
+static	void	 state_bl(STATE_ARGS);
+static	void	 state_sh(STATE_ARGS);
+static	void	 state_sm(STATE_ARGS);
+
+static	const state_handler state_handlers[MDOC_MAX - MDOC_Dd] = {
+	NULL,		/* Dd */
+	NULL,		/* Dt */
+	NULL,		/* Os */
+	state_sh,	/* Sh */
+	NULL,		/* Ss */
+	NULL,		/* Pp */
+	NULL,		/* D1 */
+	NULL,		/* Dl */
+	NULL,		/* Bd */
+	NULL,		/* Ed */
+	state_bl,	/* Bl */
+	NULL,		/* El */
+	NULL,		/* It */
+	NULL,		/* Ad */
+	NULL,		/* An */
+	NULL,		/* Ap */
+	NULL,		/* Ar */
+	NULL,		/* Cd */
+	NULL,		/* Cm */
+	NULL,		/* Dv */
+	NULL,		/* Er */
+	NULL,		/* Ev */
+	NULL,		/* Ex */
+	NULL,		/* Fa */
+	NULL,		/* Fd */
+	NULL,		/* Fl */
+	NULL,		/* Fn */
+	NULL,		/* Ft */
+	NULL,		/* Ic */
+	NULL,		/* In */
+	NULL,		/* Li */
+	NULL,		/* Nd */
+	NULL,		/* Nm */
+	NULL,		/* Op */
+	NULL,		/* Ot */
+	NULL,		/* Pa */
+	NULL,		/* Rv */
+	NULL,		/* St */
+	NULL,		/* Va */
+	NULL,		/* Vt */
+	NULL,		/* Xr */
+	NULL,		/* %A */
+	NULL,		/* %B */
+	NULL,		/* %D */
+	NULL,		/* %I */
+	NULL,		/* %J */
+	NULL,		/* %N */
+	NULL,		/* %O */
+	NULL,		/* %P */
+	NULL,		/* %R */
+	NULL,		/* %T */
+	NULL,		/* %V */
+	NULL,		/* Ac */
+	NULL,		/* Ao */
+	NULL,		/* Aq */
+	NULL,		/* At */
+	NULL,		/* Bc */
+	NULL,		/* Bf */
+	NULL,		/* Bo */
+	NULL,		/* Bq */
+	NULL,		/* Bsx */
+	NULL,		/* Bx */
+	NULL,		/* Db */
+	NULL,		/* Dc */
+	NULL,		/* Do */
+	NULL,		/* Dq */
+	NULL,		/* Ec */
+	NULL,		/* Ef */
+	NULL,		/* Em */
+	NULL,		/* Eo */
+	NULL,		/* Fx */
+	NULL,		/* Ms */
+	NULL,		/* No */
+	NULL,		/* Ns */
+	NULL,		/* Nx */
+	NULL,		/* Ox */
+	NULL,		/* Pc */
+	NULL,		/* Pf */
+	NULL,		/* Po */
+	NULL,		/* Pq */
+	NULL,		/* Qc */
+	NULL,		/* Ql */
+	NULL,		/* Qo */
+	NULL,		/* Qq */
+	NULL,		/* Re */
+	NULL,		/* Rs */
+	NULL,		/* Sc */
+	NULL,		/* So */
+	NULL,		/* Sq */
+	state_sm,	/* Sm */
+	NULL,		/* Sx */
+	NULL,		/* Sy */
+	NULL,		/* Tn */
+	NULL,		/* Ux */
+	NULL,		/* Xc */
+	NULL,		/* Xo */
+	NULL,		/* Fo */
+	NULL,		/* Fc */
+	NULL,		/* Oo */
+	NULL,		/* Oc */
+	NULL,		/* Bk */
+	NULL,		/* Ek */
+	NULL,		/* Bt */
+	NULL,		/* Hf */
+	NULL,		/* Fr */
+	NULL,		/* Ud */
+	NULL,		/* Lb */
+	NULL,		/* Lp */
+	NULL,		/* Lk */
+	NULL,		/* Mt */
+	NULL,		/* Brq */
+	NULL,		/* Bro */
+	NULL,		/* Brc */
+	NULL,		/* %C */
+	NULL,		/* Es */
+	NULL,		/* En */
+	NULL,		/* Dx */
+	NULL,		/* %Q */
+	NULL,		/* %U */
+	NULL,		/* Ta */
+};
+
+
+void
+mdoc_state(struct roff_man *mdoc, struct roff_node *n)
+{
+	state_handler handler;
+
+	if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
+		return;
+
+	assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
+	if ((mdoc_macro(n->tok)->flags & MDOC_PROLOGUE) == 0)
+		mdoc->flags |= MDOC_PBODY;
+
+	handler = state_handlers[n->tok - MDOC_Dd];
+	if (*handler)
+		(*handler)(mdoc, n);
+}
+
+static void
+state_bl(STATE_ARGS)
+{
+	struct mdoc_arg	*args;
+	size_t		 i;
+
+	if (n->type != ROFFT_HEAD || n->parent->args == NULL)
+		return;
+
+	args = n->parent->args;
+	for (i = 0; i < args->argc; i++) {
+		switch(args->argv[i].arg) {
+		case MDOC_Diag:
+			n->norm->Bl.type = LIST_diag;
+			return;
+		case MDOC_Column:
+			n->norm->Bl.type = LIST_column;
+			return;
+		default:
+			break;
+		}
+	}
+}
+
+static void
+state_sh(STATE_ARGS)
+{
+	struct roff_node *nch;
+	char		 *secname;
+
+	if (n->type != ROFFT_HEAD)
+		return;
+
+	if ( ! (n->flags & NODE_VALID)) {
+		secname = NULL;
+		deroff(&secname, n);
+
+		/*
+		 * Set the section attribute for the BLOCK, HEAD,
+		 * and HEAD children; the latter can only be TEXT
+		 * nodes, so no recursion is needed.  For other
+		 * nodes, including the .Sh BODY, this is done
+		 * when allocating the node data structures, but
+		 * for .Sh BLOCK and HEAD, the section is still
+		 * unknown at that time.
+		 */
+
+		n->sec = n->parent->sec = secname == NULL ?
+		    SEC_CUSTOM : mdoc_a2sec(secname);
+		for (nch = n->child; nch != NULL; nch = nch->next)
+			nch->sec = n->sec;
+		free(secname);
+	}
+
+	if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) {
+		roff_setreg(mdoc->roff, "nS", 1, '=');
+		mdoc->flags |= MDOC_SYNOPSIS;
+	} else {
+		roff_setreg(mdoc->roff, "nS", 0, '=');
+		mdoc->flags &= ~MDOC_SYNOPSIS;
+	}
+}
+
+static void
+state_sm(STATE_ARGS)
+{
+
+	if (n->child == NULL)
+		mdoc->flags ^= MDOC_SMOFF;
+	else if ( ! strcmp(n->child->string, "on"))
+		mdoc->flags &= ~MDOC_SMOFF;
+	else if ( ! strcmp(n->child->string, "off"))
+		mdoc->flags |= MDOC_SMOFF;
+}

Property changes on: vendor/mandoc/20190723/mdoc_state.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/msec.c
===================================================================
--- vendor/mandoc/20190723/msec.c	(nonexistent)
+++ vendor/mandoc/20190723/msec.c	(revision 350350)
@@ -0,0 +1,37 @@
+/*	$Id: msec.c,v 1.16 2018/12/14 01:18:26 schwarze Exp $ */
+/*
+ * Copyright (c) 2009 Kristaps Dzonsons 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include 
+
+#include 
+#include 
+
+#include "mandoc.h"
+#include "libmandoc.h"
+
+#define LINE(x, y) \
+	if (0 == strcmp(p, x)) return(y);
+
+const char *
+mandoc_a2msec(const char *p)
+{
+
+#include "msec.in"
+
+	return NULL;
+}

Property changes on: vendor/mandoc/20190723/msec.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/out.h
===================================================================
--- vendor/mandoc/20190723/out.h	(nonexistent)
+++ vendor/mandoc/20190723/out.h	(revision 350350)
@@ -0,0 +1,68 @@
+/*	$Id: out.h,v 1.33 2018/08/18 20:18:14 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2014, 2017, 2018 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+enum	roffscale {
+	SCALE_CM, /* centimeters (c) */
+	SCALE_IN, /* inches (i) */
+	SCALE_PC, /* pica (P) */
+	SCALE_PT, /* points (p) */
+	SCALE_EM, /* ems (m) */
+	SCALE_MM, /* mini-ems (M) */
+	SCALE_EN, /* ens (n) */
+	SCALE_BU, /* default horizontal (u) */
+	SCALE_VS, /* default vertical (v) */
+	SCALE_FS, /* syn. for u (f) */
+	SCALE_MAX
+};
+
+struct	roffcol {
+	size_t		 width; /* width of cell */
+	size_t		 nwidth; /* max. width of number in cell */
+	size_t		 decimal; /* decimal position in cell */
+	size_t		 spacing; /* spacing after the column */
+	int		 flags; /* layout flags, see tbl_cell */
+};
+
+struct	roffsu {
+	enum roffscale	  unit;
+	double		  scale;
+};
+
+typedef	size_t	(*tbl_sulen)(const struct roffsu *, void *);
+typedef	size_t	(*tbl_strlen)(const char *, void *);
+typedef	size_t	(*tbl_len)(size_t, void *);
+
+struct	rofftbl {
+	tbl_sulen	 sulen; /* calculate scaling unit length */
+	tbl_strlen	 slen; /* calculate string length */
+	tbl_len		 len; /* produce width of empty space */
+	struct roffcol	*cols; /* master column specifiers */
+	void		*arg; /* passed to sulen, slen, and len */
+};
+
+#define	SCALE_HS_INIT(p, v) \
+	do { (p)->unit = SCALE_EN; \
+	     (p)->scale = (v); } \
+	while (/* CONSTCOND */ 0)
+
+
+struct	tbl_span;
+
+const char	 *a2roffsu(const char *, struct roffsu *, enum roffscale);
+void		  tblcalc(struct rofftbl *tbl,
+			const struct tbl_span *, size_t, size_t);

Property changes on: vendor/mandoc/20190723/out.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/preconv.c
===================================================================
--- vendor/mandoc/20190723/preconv.c	(nonexistent)
+++ vendor/mandoc/20190723/preconv.c	(revision 350350)
@@ -0,0 +1,179 @@
+/*	$Id: preconv.c,v 1.17 2018/12/13 11:55:47 schwarze Exp $ */
+/*
+ * Copyright (c) 2011 Kristaps Dzonsons 
+ * Copyright (c) 2014 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include 
+
+#include 
+#include 
+#include 
+
+#include "mandoc.h"
+#include "roff.h"
+#include "mandoc_parse.h"
+#include "libmandoc.h"
+
+int
+preconv_encode(const struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
+    int *filenc)
+{
+	const unsigned char	*cu;
+	int			 nby;
+	unsigned int		 accum;
+
+	cu = (const unsigned char *)ib->buf + *ii;
+	assert(*cu & 0x80);
+
+	if ( ! (*filenc & MPARSE_UTF8))
+		goto latin;
+
+	nby = 1;
+	while (nby < 5 && *cu & (1 << (7 - nby)))
+		nby++;
+
+	switch (nby) {
+	case 2:
+		accum = *cu & 0x1f;
+		if (accum < 0x02)  /* Obfuscated ASCII. */
+			goto latin;
+		break;
+	case 3:
+		accum = *cu & 0x0f;
+		break;
+	case 4:
+		accum = *cu & 0x07;
+		if (accum > 0x04) /* Beyond Unicode. */
+			goto latin;
+		break;
+	default:  /* Bad sequence header. */
+		goto latin;
+	}
+
+	cu++;
+	switch (nby) {
+	case 3:
+		if ((accum == 0x00 && ! (*cu & 0x20)) ||  /* Use 2-byte. */
+		    (accum == 0x0d && *cu & 0x20))  /* Surrogates. */
+			goto latin;
+		break;
+	case 4:
+		if ((accum == 0x00 && ! (*cu & 0x30)) ||  /* Use 3-byte. */
+		    (accum == 0x04 && *cu & 0x30))  /* Beyond Unicode. */
+			goto latin;
+		break;
+	default:
+		break;
+	}
+
+	while (--nby) {
+		if ((*cu & 0xc0) != 0x80)  /* Invalid continuation. */
+			goto latin;
+		accum <<= 6;
+		accum += *cu & 0x3f;
+		cu++;
+	}
+
+	assert(accum > 0x7f);
+	assert(accum < 0x110000);
+	assert(accum < 0xd800 || accum > 0xdfff);
+
+	*oi += snprintf(ob->buf + *oi, 11, "\\[u%.4X]", accum);
+	*ii = (const char *)cu - ib->buf;
+	*filenc &= ~MPARSE_LATIN1;
+	return 1;
+
+latin:
+	if ( ! (*filenc & MPARSE_LATIN1))
+		return 0;
+
+	*oi += snprintf(ob->buf + *oi, 11,
+	    "\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
+
+	*filenc &= ~MPARSE_UTF8;
+	return 1;
+}
+
+int
+preconv_cue(const struct buf *b, size_t offset)
+{
+	const char	*ln, *eoln, *eoph;
+	size_t		 sz, phsz;
+
+	ln = b->buf + offset;
+	sz = b->sz - offset;
+
+	/* Look for the end-of-line. */
+
+	if (NULL == (eoln = memchr(ln, '\n', sz)))
+		eoln = ln + sz;
+
+	/* Check if we have the correct header/trailer. */
+
+	if ((sz = (size_t)(eoln - ln)) < 10 ||
+	    memcmp(ln, ".\\\" -*-", 7) || memcmp(eoln - 3, "-*-", 3))
+		return MPARSE_UTF8 | MPARSE_LATIN1;
+
+	/* Move after the header and adjust for the trailer. */
+
+	ln += 7;
+	sz -= 10;
+
+	while (sz > 0) {
+		while (sz > 0 && ' ' == *ln) {
+			ln++;
+			sz--;
+		}
+		if (0 == sz)
+			break;
+
+		/* Find the end-of-phrase marker (or eoln). */
+
+		if (NULL == (eoph = memchr(ln, ';', sz)))
+			eoph = eoln - 3;
+		else
+			eoph++;
+
+		/* Only account for the "coding" phrase. */
+
+		if ((phsz = eoph - ln) < 7 ||
+		    strncasecmp(ln, "coding:", 7)) {
+			sz -= phsz;
+			ln += phsz;
+			continue;
+		}
+
+		sz -= 7;
+		ln += 7;
+
+		while (sz > 0 && ' ' == *ln) {
+			ln++;
+			sz--;
+		}
+		if (0 == sz)
+			return 0;
+
+		/* Check us against known encodings. */
+
+		if (phsz > 4 && !strncasecmp(ln, "utf-8", 5))
+			return MPARSE_UTF8;
+		if (phsz > 10 && !strncasecmp(ln, "iso-latin-1", 11))
+			return MPARSE_LATIN1;
+		return 0;
+	}
+	return MPARSE_UTF8 | MPARSE_LATIN1;
+}

Property changes on: vendor/mandoc/20190723/preconv.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/roff.h
===================================================================
--- vendor/mandoc/20190723/roff.h	(nonexistent)
+++ vendor/mandoc/20190723/roff.h	(revision 350350)
@@ -0,0 +1,552 @@
+/*	$Id: roff.h,v 1.69 2019/03/04 13:01:57 schwarze Exp $	*/
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2013-2015, 2017-2019 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.
+ *
+ * Common data types for all syntax trees and related functions.
+ */
+
+struct	ohash;
+struct	mdoc_arg;
+union	mdoc_data;
+struct	tbl_span;
+struct	eqn_box;
+
+enum	roff_macroset {
+	MACROSET_NONE = 0,
+	MACROSET_MDOC,
+	MACROSET_MAN
+};
+
+enum	roff_sec {
+	SEC_NONE = 0,
+	SEC_NAME,
+	SEC_LIBRARY,
+	SEC_SYNOPSIS,
+	SEC_DESCRIPTION,
+	SEC_CONTEXT,
+	SEC_IMPLEMENTATION,	/* IMPLEMENTATION NOTES */
+	SEC_RETURN_VALUES,
+	SEC_ENVIRONMENT,
+	SEC_FILES,
+	SEC_EXIT_STATUS,
+	SEC_EXAMPLES,
+	SEC_DIAGNOSTICS,
+	SEC_COMPATIBILITY,
+	SEC_ERRORS,
+	SEC_SEE_ALSO,
+	SEC_STANDARDS,
+	SEC_HISTORY,
+	SEC_AUTHORS,
+	SEC_CAVEATS,
+	SEC_BUGS,
+	SEC_SECURITY,
+	SEC_CUSTOM,
+	SEC__MAX
+};
+
+enum	roff_type {
+	ROFFT_ROOT,
+	ROFFT_BLOCK,
+	ROFFT_HEAD,
+	ROFFT_BODY,
+	ROFFT_TAIL,
+	ROFFT_ELEM,
+	ROFFT_TEXT,
+	ROFFT_COMMENT,
+	ROFFT_TBL,
+	ROFFT_EQN
+};
+
+enum	roff_tok {
+	ROFF_br = 0,
+	ROFF_ce,
+	ROFF_fi,
+	ROFF_ft,
+	ROFF_ll,
+	ROFF_mc,
+	ROFF_nf,
+	ROFF_po,
+	ROFF_rj,
+	ROFF_sp,
+	ROFF_ta,
+	ROFF_ti,
+	ROFF_MAX,
+	ROFF_ab,
+	ROFF_ad,
+	ROFF_af,
+	ROFF_aln,
+	ROFF_als,
+	ROFF_am,
+	ROFF_am1,
+	ROFF_ami,
+	ROFF_ami1,
+	ROFF_as,
+	ROFF_as1,
+	ROFF_asciify,
+	ROFF_backtrace,
+	ROFF_bd,
+	ROFF_bleedat,
+	ROFF_blm,
+	ROFF_box,
+	ROFF_boxa,
+	ROFF_bp,
+	ROFF_BP,
+	ROFF_break,
+	ROFF_breakchar,
+	ROFF_brnl,
+	ROFF_brp,
+	ROFF_brpnl,
+	ROFF_c2,
+	ROFF_cc,
+	ROFF_cf,
+	ROFF_cflags,
+	ROFF_ch,
+	ROFF_char,
+	ROFF_chop,
+	ROFF_class,
+	ROFF_close,
+	ROFF_CL,
+	ROFF_color,
+	ROFF_composite,
+	ROFF_continue,
+	ROFF_cp,
+	ROFF_cropat,
+	ROFF_cs,
+	ROFF_cu,
+	ROFF_da,
+	ROFF_dch,
+	ROFF_Dd,
+	ROFF_de,
+	ROFF_de1,
+	ROFF_defcolor,
+	ROFF_dei,
+	ROFF_dei1,
+	ROFF_device,
+	ROFF_devicem,
+	ROFF_di,
+	ROFF_do,
+	ROFF_ds,
+	ROFF_ds1,
+	ROFF_dwh,
+	ROFF_dt,
+	ROFF_ec,
+	ROFF_ecr,
+	ROFF_ecs,
+	ROFF_el,
+	ROFF_em,
+	ROFF_EN,
+	ROFF_eo,
+	ROFF_EP,
+	ROFF_EQ,
+	ROFF_errprint,
+	ROFF_ev,
+	ROFF_evc,
+	ROFF_ex,
+	ROFF_fallback,
+	ROFF_fam,
+	ROFF_fc,
+	ROFF_fchar,
+	ROFF_fcolor,
+	ROFF_fdeferlig,
+	ROFF_feature,
+	ROFF_fkern,
+	ROFF_fl,
+	ROFF_flig,
+	ROFF_fp,
+	ROFF_fps,
+	ROFF_fschar,
+	ROFF_fspacewidth,
+	ROFF_fspecial,
+	ROFF_ftr,
+	ROFF_fzoom,
+	ROFF_gcolor,
+	ROFF_hc,
+	ROFF_hcode,
+	ROFF_hidechar,
+	ROFF_hla,
+	ROFF_hlm,
+	ROFF_hpf,
+	ROFF_hpfa,
+	ROFF_hpfcode,
+	ROFF_hw,
+	ROFF_hy,
+	ROFF_hylang,
+	ROFF_hylen,
+	ROFF_hym,
+	ROFF_hypp,
+	ROFF_hys,
+	ROFF_ie,
+	ROFF_if,
+	ROFF_ig,
+	/* MAN_in; ignored in mdoc(7) */
+	ROFF_index,
+	ROFF_it,
+	ROFF_itc,
+	ROFF_IX,
+	ROFF_kern,
+	ROFF_kernafter,
+	ROFF_kernbefore,
+	ROFF_kernpair,
+	ROFF_lc,
+	ROFF_lc_ctype,
+	ROFF_lds,
+	ROFF_length,
+	ROFF_letadj,
+	ROFF_lf,
+	ROFF_lg,
+	ROFF_lhang,
+	ROFF_linetabs,
+	ROFF_lnr,
+	ROFF_lnrf,
+	ROFF_lpfx,
+	ROFF_ls,
+	ROFF_lsm,
+	ROFF_lt,
+	ROFF_mediasize,
+	ROFF_minss,
+	ROFF_mk,
+	ROFF_mso,
+	ROFF_na,
+	ROFF_ne,
+	ROFF_nh,
+	ROFF_nhychar,
+	ROFF_nm,
+	ROFF_nn,
+	ROFF_nop,
+	ROFF_nr,
+	ROFF_nrf,
+	ROFF_nroff,
+	ROFF_ns,
+	ROFF_nx,
+	ROFF_open,
+	ROFF_opena,
+	ROFF_os,
+	ROFF_output,
+	ROFF_padj,
+	ROFF_papersize,
+	ROFF_pc,
+	ROFF_pev,
+	ROFF_pi,
+	ROFF_PI,
+	ROFF_pl,
+	ROFF_pm,
+	ROFF_pn,
+	ROFF_pnr,
+	ROFF_ps,
+	ROFF_psbb,
+	ROFF_pshape,
+	ROFF_pso,
+	ROFF_ptr,
+	ROFF_pvs,
+	ROFF_rchar,
+	ROFF_rd,
+	ROFF_recursionlimit,
+	ROFF_return,
+	ROFF_rfschar,
+	ROFF_rhang,
+	ROFF_rm,
+	ROFF_rn,
+	ROFF_rnn,
+	ROFF_rr,
+	ROFF_rs,
+	ROFF_rt,
+	ROFF_schar,
+	ROFF_sentchar,
+	ROFF_shc,
+	ROFF_shift,
+	ROFF_sizes,
+	ROFF_so,
+	ROFF_spacewidth,
+	ROFF_special,
+	ROFF_spreadwarn,
+	ROFF_ss,
+	ROFF_sty,
+	ROFF_substring,
+	ROFF_sv,
+	ROFF_sy,
+	ROFF_T_,
+	ROFF_tc,
+	ROFF_TE,
+	ROFF_TH,
+	ROFF_tkf,
+	ROFF_tl,
+	ROFF_tm,
+	ROFF_tm1,
+	ROFF_tmc,
+	ROFF_tr,
+	ROFF_track,
+	ROFF_transchar,
+	ROFF_trf,
+	ROFF_trimat,
+	ROFF_trin,
+	ROFF_trnt,
+	ROFF_troff,
+	ROFF_TS,
+	ROFF_uf,
+	ROFF_ul,
+	ROFF_unformat,
+	ROFF_unwatch,
+	ROFF_unwatchn,
+	ROFF_vpt,
+	ROFF_vs,
+	ROFF_warn,
+	ROFF_warnscale,
+	ROFF_watch,
+	ROFF_watchlength,
+	ROFF_watchn,
+	ROFF_wh,
+	ROFF_while,
+	ROFF_write,
+	ROFF_writec,
+	ROFF_writem,
+	ROFF_xflag,
+	ROFF_cblock,
+	ROFF_RENAMED,
+	ROFF_USERDEF,
+	TOKEN_NONE,
+	MDOC_Dd,
+	MDOC_Dt,
+	MDOC_Os,
+	MDOC_Sh,
+	MDOC_Ss,
+	MDOC_Pp,
+	MDOC_D1,
+	MDOC_Dl,
+	MDOC_Bd,
+	MDOC_Ed,
+	MDOC_Bl,
+	MDOC_El,
+	MDOC_It,
+	MDOC_Ad,
+	MDOC_An,
+	MDOC_Ap,
+	MDOC_Ar,
+	MDOC_Cd,
+	MDOC_Cm,
+	MDOC_Dv,
+	MDOC_Er,
+	MDOC_Ev,
+	MDOC_Ex,
+	MDOC_Fa,
+	MDOC_Fd,
+	MDOC_Fl,
+	MDOC_Fn,
+	MDOC_Ft,
+	MDOC_Ic,
+	MDOC_In,
+	MDOC_Li,
+	MDOC_Nd,
+	MDOC_Nm,
+	MDOC_Op,
+	MDOC_Ot,
+	MDOC_Pa,
+	MDOC_Rv,
+	MDOC_St,
+	MDOC_Va,
+	MDOC_Vt,
+	MDOC_Xr,
+	MDOC__A,
+	MDOC__B,
+	MDOC__D,
+	MDOC__I,
+	MDOC__J,
+	MDOC__N,
+	MDOC__O,
+	MDOC__P,
+	MDOC__R,
+	MDOC__T,
+	MDOC__V,
+	MDOC_Ac,
+	MDOC_Ao,
+	MDOC_Aq,
+	MDOC_At,
+	MDOC_Bc,
+	MDOC_Bf,
+	MDOC_Bo,
+	MDOC_Bq,
+	MDOC_Bsx,
+	MDOC_Bx,
+	MDOC_Db,
+	MDOC_Dc,
+	MDOC_Do,
+	MDOC_Dq,
+	MDOC_Ec,
+	MDOC_Ef,
+	MDOC_Em,
+	MDOC_Eo,
+	MDOC_Fx,
+	MDOC_Ms,
+	MDOC_No,
+	MDOC_Ns,
+	MDOC_Nx,
+	MDOC_Ox,
+	MDOC_Pc,
+	MDOC_Pf,
+	MDOC_Po,
+	MDOC_Pq,
+	MDOC_Qc,
+	MDOC_Ql,
+	MDOC_Qo,
+	MDOC_Qq,
+	MDOC_Re,
+	MDOC_Rs,
+	MDOC_Sc,
+	MDOC_So,
+	MDOC_Sq,
+	MDOC_Sm,
+	MDOC_Sx,
+	MDOC_Sy,
+	MDOC_Tn,
+	MDOC_Ux,
+	MDOC_Xc,
+	MDOC_Xo,
+	MDOC_Fo,
+	MDOC_Fc,
+	MDOC_Oo,
+	MDOC_Oc,
+	MDOC_Bk,
+	MDOC_Ek,
+	MDOC_Bt,
+	MDOC_Hf,
+	MDOC_Fr,
+	MDOC_Ud,
+	MDOC_Lb,
+	MDOC_Lp,
+	MDOC_Lk,
+	MDOC_Mt,
+	MDOC_Brq,
+	MDOC_Bro,
+	MDOC_Brc,
+	MDOC__C,
+	MDOC_Es,
+	MDOC_En,
+	MDOC_Dx,
+	MDOC__Q,
+	MDOC__U,
+	MDOC_Ta,
+	MDOC_MAX,
+	MAN_TH,
+	MAN_SH,
+	MAN_SS,
+	MAN_TP,
+	MAN_TQ,
+	MAN_LP,
+	MAN_PP,
+	MAN_P,
+	MAN_IP,
+	MAN_HP,
+	MAN_SM,
+	MAN_SB,
+	MAN_BI,
+	MAN_IB,
+	MAN_BR,
+	MAN_RB,
+	MAN_R,
+	MAN_B,
+	MAN_I,
+	MAN_IR,
+	MAN_RI,
+	MAN_RE,
+	MAN_RS,
+	MAN_DT,
+	MAN_UC,
+	MAN_PD,
+	MAN_AT,
+	MAN_in,
+	MAN_SY,
+	MAN_YS,
+	MAN_OP,
+	MAN_EX,
+	MAN_EE,
+	MAN_UR,
+	MAN_UE,
+	MAN_MT,
+	MAN_ME,
+	MAN_MAX
+};
+
+/*
+ * Indicates that a BODY's formatting has ended, but
+ * the scope is still open.  Used for badly nested blocks.
+ */
+enum	mdoc_endbody {
+	ENDBODY_NOT = 0,
+	ENDBODY_SPACE	/* Is broken: append a space. */
+};
+
+enum	mandoc_os {
+	MANDOC_OS_OTHER = 0,
+	MANDOC_OS_NETBSD,
+	MANDOC_OS_OPENBSD
+};
+
+struct	roff_node {
+	struct roff_node *parent;  /* Parent AST node. */
+	struct roff_node *child;   /* First child AST node. */
+	struct roff_node *last;    /* Last child AST node. */
+	struct roff_node *next;    /* Sibling AST node. */
+	struct roff_node *prev;    /* Prior sibling AST node. */
+	struct roff_node *head;    /* BLOCK */
+	struct roff_node *body;    /* BLOCK/ENDBODY */
+	struct roff_node *tail;    /* BLOCK */
+	struct mdoc_arg	 *args;    /* BLOCK/ELEM */
+	union mdoc_data	 *norm;    /* Normalized arguments. */
+	char		 *string;  /* TEXT */
+	struct tbl_span	 *span;    /* TBL */
+	struct eqn_box	 *eqn;     /* EQN */
+	int		  line;    /* Input file line number. */
+	int		  pos;     /* Input file column number. */
+	int		  flags;
+#define	NODE_VALID	 (1 << 0)  /* Has been validated. */
+#define	NODE_ENDED	 (1 << 1)  /* Gone past body end mark. */
+#define	NODE_BROKEN	 (1 << 2)  /* Must validate parent when ending. */
+#define	NODE_LINE	 (1 << 3)  /* First macro/text on line. */
+#define	NODE_DELIMO	 (1 << 4)
+#define	NODE_DELIMC	 (1 << 5)
+#define	NODE_EOS	 (1 << 6)  /* At sentence boundary. */
+#define	NODE_SYNPRETTY	 (1 << 7)  /* SYNOPSIS-style formatting. */
+#define	NODE_NOFILL	 (1 << 8)  /* Fill mode switched off. */
+#define	NODE_NOSRC	 (1 << 9)  /* Generated node, not in input file. */
+#define	NODE_NOPRT	 (1 << 10) /* Shall not print anything. */
+	int		  prev_font; /* Before entering this node. */
+	int		  aux;     /* Decoded node data, type-dependent. */
+	enum roff_tok	  tok;     /* Request or macro ID. */
+	enum roff_type	  type;    /* AST node type. */
+	enum roff_sec	  sec;     /* Current named section. */
+	enum mdoc_endbody end;     /* BODY */
+};
+
+struct	roff_meta {
+	struct roff_node *first;   /* The first node parsed. */
+	char		 *msec;    /* Manual section, usually a digit. */
+	char		 *vol;     /* Manual volume title. */
+	char		 *os;      /* Operating system. */
+	char		 *arch;    /* Machine architecture. */
+	char		 *title;   /* Manual title, usually CAPS. */
+	char		 *name;    /* Leading manual name. */
+	char		 *date;    /* Normalized date. */
+	char		 *sodest;  /* .so target file name or NULL. */
+	int		  hasbody; /* Document is not empty. */
+	int		  rcsids;  /* Bits indexed by enum mandoc_os. */
+	enum mandoc_os	  os_e;    /* Operating system. */
+	enum roff_macroset macroset; /* Kind of high-level macros used. */
+};
+
+extern	const char *const *roff_name;
+
+
+int		 arch_valid(const char *, enum mandoc_os);
+void		 deroff(char **, const struct roff_node *);

Property changes on: vendor/mandoc/20190723/roff.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/roff_int.h
===================================================================
--- vendor/mandoc/20190723/roff_int.h	(nonexistent)
+++ vendor/mandoc/20190723/roff_int.h	(revision 350350)
@@ -0,0 +1,93 @@
+/*	$Id: roff_int.h,v 1.16 2019/01/05 00:36:50 schwarze Exp $	*/
+/*
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2013-2015, 2017-2019 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.
+ *
+ * Parser internals shared by multiple parsers.
+ */
+
+struct	ohash;
+struct	roff_node;
+struct	roff_meta;
+struct	roff;
+struct	mdoc_arg;
+
+enum	roff_next {
+	ROFF_NEXT_SIBLING = 0,
+	ROFF_NEXT_CHILD
+};
+
+struct	roff_man {
+	struct roff_meta  meta;    /* Public parse results. */
+	struct roff	 *roff;    /* Roff parser state data. */
+	struct ohash	 *mdocmac; /* Mdoc macro lookup table. */
+	struct ohash	 *manmac;  /* Man macro lookup table. */
+	const char	 *os_s;    /* Default operating system. */
+	struct roff_node *last;    /* The last node parsed. */
+	struct roff_node *last_es; /* The most recent Es node. */
+	int		  quick;   /* Abort parse early. */
+	int		  flags;   /* Parse flags. */
+#define	ROFF_NOFILL	 (1 << 1)  /* Fill mode switched off. */
+#define	MDOC_PBODY	 (1 << 2)  /* In the document body. */
+#define	MDOC_NEWLINE	 (1 << 3)  /* First macro/text in a line. */
+#define	MDOC_PHRASE	 (1 << 4)  /* In a Bl -column phrase. */
+#define	MDOC_PHRASELIT	 (1 << 5)  /* Literal within a phrase. */
+#define	MDOC_FREECOL	 (1 << 6)  /* `It' invocation should close. */
+#define	MDOC_SYNOPSIS	 (1 << 7)  /* SYNOPSIS-style formatting. */
+#define	MDOC_KEEP	 (1 << 8)  /* In a word keep. */
+#define	MDOC_SMOFF	 (1 << 9)  /* Spacing is off. */
+#define	MDOC_NODELIMC	 (1 << 10) /* Disable closing delimiter handling. */
+#define	MAN_ELINE	 (1 << 11) /* Next-line element scope. */
+#define	MAN_BLINE	 (1 << 12) /* Next-line block scope. */
+#define	MDOC_PHRASEQF	 (1 << 13) /* Quote first word encountered. */
+#define	MDOC_PHRASEQL	 (1 << 14) /* Quote last word of this phrase. */
+#define	MDOC_PHRASEQN	 (1 << 15) /* Quote first word of the next phrase. */
+#define	ROFF_NONOFILL	 (1 << 16) /* Temporarily suspend no-fill mode. */
+#define	MAN_NEWLINE	  MDOC_NEWLINE
+	enum roff_sec	  lastsec; /* Last section seen. */
+	enum roff_sec	  lastnamed; /* Last standard section seen. */
+	enum roff_next	  next;    /* Where to put the next node. */
+};
+
+
+struct roff_node *roff_node_alloc(struct roff_man *, int, int,
+			enum roff_type, int);
+void		  roff_node_append(struct roff_man *, struct roff_node *);
+void		  roff_word_alloc(struct roff_man *, int, int, const char *);
+void		  roff_word_append(struct roff_man *, const char *);
+void		  roff_elem_alloc(struct roff_man *, int, int, int);
+struct roff_node *roff_block_alloc(struct roff_man *, int, int, int);
+struct roff_node *roff_head_alloc(struct roff_man *, int, int, int);
+struct roff_node *roff_body_alloc(struct roff_man *, int, int, int);
+void		  roff_node_unlink(struct roff_man *, struct roff_node *);
+void		  roff_node_relink(struct roff_man *, struct roff_node *);
+void		  roff_node_free(struct roff_node *);
+void		  roff_node_delete(struct roff_man *, struct roff_node *);
+
+struct ohash	 *roffhash_alloc(enum roff_tok, enum roff_tok);
+enum roff_tok	  roffhash_find(struct ohash *, const char *, size_t);
+void		  roffhash_free(struct ohash *);
+
+void		  roff_state_reset(struct roff_man *);
+void		  roff_validate(struct roff_man *);
+
+/*
+ * Functions called from roff.c need to be declared here,
+ * not in libmdoc.h or libman.h, even if they are specific
+ * to either the mdoc(7) or the man(7) parser.
+ */
+
+void		  man_breakscope(struct roff_man *, int);
+void		  mdoc_argv_free(struct mdoc_arg *);

Property changes on: vendor/mandoc/20190723/roff_int.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/roff_term.c
===================================================================
--- vendor/mandoc/20190723/roff_term.c	(nonexistent)
+++ vendor/mandoc/20190723/roff_term.c	(revision 350350)
@@ -0,0 +1,244 @@
+/*	$Id: roff_term.c,v 1.19 2019/01/04 03:24:33 schwarze Exp $ */
+/*
+ * Copyright (c) 2010,2014,2015,2017-2019 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include 
+
+#include 
+#include 
+#include 
+
+#include "mandoc.h"
+#include "roff.h"
+#include "out.h"
+#include "term.h"
+
+#define	ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
+
+typedef	void	(*roff_term_pre_fp)(ROFF_TERM_ARGS);
+
+static	void	  roff_term_pre_br(ROFF_TERM_ARGS);
+static	void	  roff_term_pre_ce(ROFF_TERM_ARGS);
+static	void	  roff_term_pre_ft(ROFF_TERM_ARGS);
+static	void	  roff_term_pre_ll(ROFF_TERM_ARGS);
+static	void	  roff_term_pre_mc(ROFF_TERM_ARGS);
+static	void	  roff_term_pre_po(ROFF_TERM_ARGS);
+static	void	  roff_term_pre_sp(ROFF_TERM_ARGS);
+static	void	  roff_term_pre_ta(ROFF_TERM_ARGS);
+static	void	  roff_term_pre_ti(ROFF_TERM_ARGS);
+
+static	const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
+	roff_term_pre_br,  /* br */
+	roff_term_pre_ce,  /* ce */
+	roff_term_pre_br,  /* fi */
+	roff_term_pre_ft,  /* ft */
+	roff_term_pre_ll,  /* ll */
+	roff_term_pre_mc,  /* mc */
+	roff_term_pre_br,  /* nf */
+	roff_term_pre_po,  /* po */
+	roff_term_pre_ce,  /* rj */
+	roff_term_pre_sp,  /* sp */
+	roff_term_pre_ta,  /* ta */
+	roff_term_pre_ti,  /* ti */
+};
+
+
+void
+roff_term_pre(struct termp *p, const struct roff_node *n)
+{
+	assert(n->tok < ROFF_MAX);
+	(*roff_term_pre_acts[n->tok])(p, n);
+}
+
+static void
+roff_term_pre_br(ROFF_TERM_ARGS)
+{
+	term_newln(p);
+	if (p->flags & TERMP_BRIND) {
+		p->tcol->offset = p->tcol->rmargin;
+		p->tcol->rmargin = p->maxrmargin;
+		p->trailspace = 0;
+		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
+		p->flags |= TERMP_NOSPACE;
+	}
+}
+
+static void
+roff_term_pre_ce(ROFF_TERM_ARGS)
+{
+	const struct roff_node	*nc1, *nc2;
+
+	roff_term_pre_br(p, n);
+	p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
+	nc1 = n->child->next;
+	while (nc1 != NULL) {
+		nc2 = nc1;
+		do {
+			nc2 = nc2->next;
+		} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
+		    (nc2->flags & NODE_LINE) == 0));
+		while (nc1 != nc2) {
+			if (nc1->type == ROFFT_TEXT)
+				term_word(p, nc1->string);
+			else
+				roff_term_pre(p, nc1);
+			nc1 = nc1->next;
+		}
+		p->flags |= TERMP_NOSPACE;
+		term_flushln(p);
+	}
+	p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
+}
+
+static void
+roff_term_pre_ft(ROFF_TERM_ARGS)
+{
+	const char	*cp;
+
+	cp = n->child->string;
+	switch (mandoc_font(cp, (int)strlen(cp))) {
+	case ESCAPE_FONTBOLD:
+		term_fontrepl(p, TERMFONT_BOLD);
+		break;
+	case ESCAPE_FONTITALIC:
+		term_fontrepl(p, TERMFONT_UNDER);
+		break;
+	case ESCAPE_FONTBI:
+		term_fontrepl(p, TERMFONT_BI);
+		break;
+	case ESCAPE_FONTPREV:
+		term_fontlast(p);
+		break;
+	case ESCAPE_FONTROMAN:
+	case ESCAPE_FONTCW:
+		term_fontrepl(p, TERMFONT_NONE);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+roff_term_pre_ll(ROFF_TERM_ARGS)
+{
+	term_setwidth(p, n->child != NULL ? n->child->string : NULL);
+}
+
+static void
+roff_term_pre_mc(ROFF_TERM_ARGS)
+{
+	if (p->col) {
+		p->flags |= TERMP_NOBREAK;
+		term_flushln(p);
+		p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
+	}
+	if (n->child != NULL) {
+		p->mc = n->child->string;
+		p->flags |= TERMP_NEWMC;
+	} else
+		p->flags |= TERMP_ENDMC;
+}
+
+static void
+roff_term_pre_po(ROFF_TERM_ARGS)
+{
+	struct roffsu	 su;
+	static int	 po, polast;
+	int		 ponew;
+
+	if (n->child != NULL &&
+	    a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
+		ponew = term_hen(p, &su);
+		if (*n->child->string == '+' ||
+		    *n->child->string == '-')
+			ponew += po;
+	} else
+		ponew = polast;
+	polast = po;
+	po = ponew;
+
+	ponew = po - polast + (int)p->tcol->offset;
+	p->tcol->offset = ponew > 0 ? ponew : 0;
+}
+
+static void
+roff_term_pre_sp(ROFF_TERM_ARGS)
+{
+	struct roffsu	 su;
+	int		 len;
+
+	if (n->child != NULL) {
+		if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
+			su.scale = 1.0;
+		len = term_vspan(p, &su);
+	} else
+		len = 1;
+
+	if (len < 0)
+		p->skipvsp -= len;
+	else
+		while (len--)
+			term_vspace(p);
+
+	roff_term_pre_br(p, n);
+}
+
+static void
+roff_term_pre_ta(ROFF_TERM_ARGS)
+{
+	term_tab_set(p, NULL);
+	for (n = n->child; n != NULL; n = n->next)
+		term_tab_set(p, n->string);
+}
+
+static void
+roff_term_pre_ti(ROFF_TERM_ARGS)
+{
+	struct roffsu	 su;
+	const char	*cp;
+	int		 len, sign;
+
+	roff_term_pre_br(p, n);
+
+	if (n->child == NULL)
+		return;
+	cp = n->child->string;
+	if (*cp == '+') {
+		sign = 1;
+		cp++;
+	} else if (*cp == '-') {
+		sign = -1;
+		cp++;
+	} else
+		sign = 0;
+
+	if (a2roffsu(cp, &su, SCALE_EM) == NULL)
+		return;
+	len = term_hen(p, &su);
+
+	if (sign == 0) {
+		p->ti = len - p->tcol->offset;
+		p->tcol->offset = len;
+	} else if (sign == 1) {
+		p->ti = len;
+		p->tcol->offset += len;
+	} else if ((size_t)len < p->tcol->offset) {
+		p->ti = -len;
+		p->tcol->offset -= len;
+	} else {
+		p->ti = -p->tcol->offset;
+		p->tcol->offset = 0;
+	}
+}

Property changes on: vendor/mandoc/20190723/roff_term.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/roff_validate.c
===================================================================
--- vendor/mandoc/20190723/roff_validate.c	(nonexistent)
+++ vendor/mandoc/20190723/roff_validate.c	(revision 350350)
@@ -0,0 +1,149 @@
+/*	$Id: roff_validate.c,v 1.18 2018/12/31 09:02:37 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2017, 2018 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include 
+
+#include 
+#include 
+#include 
+
+#include "mandoc.h"
+#include "roff.h"
+#include "libmandoc.h"
+#include "roff_int.h"
+
+#define	ROFF_VALID_ARGS struct roff_man *man, struct roff_node *n
+
+typedef	void	(*roff_valid_fp)(ROFF_VALID_ARGS);
+
+static	void	  roff_valid_br(ROFF_VALID_ARGS);
+static	void	  roff_valid_fi(ROFF_VALID_ARGS);
+static	void	  roff_valid_ft(ROFF_VALID_ARGS);
+static	void	  roff_valid_nf(ROFF_VALID_ARGS);
+static	void	  roff_valid_sp(ROFF_VALID_ARGS);
+
+static	const roff_valid_fp roff_valids[ROFF_MAX] = {
+	roff_valid_br,  /* br */
+	NULL,  /* ce */
+	roff_valid_fi,  /* fi */
+	roff_valid_ft,  /* ft */
+	NULL,  /* ll */
+	NULL,  /* mc */
+	roff_valid_nf,  /* nf */
+	NULL,  /* po */
+	NULL,  /* rj */
+	roff_valid_sp,  /* sp */
+	NULL,  /* ta */
+	NULL,  /* ti */
+};
+
+
+void
+roff_validate(struct roff_man *man)
+{
+	struct roff_node	*n;
+
+	n = man->last;
+	assert(n->tok < ROFF_MAX);
+	if (roff_valids[n->tok] != NULL)
+		(*roff_valids[n->tok])(man, n);
+}
+
+static void
+roff_valid_br(ROFF_VALID_ARGS)
+{
+	struct roff_node	*np;
+
+	if (n->next != NULL && n->next->type == ROFFT_TEXT &&
+	    *n->next->string == ' ') {
+		mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
+		    "br before text line with leading blank");
+		roff_node_delete(man, n);
+		return;
+	}
+
+	if ((np = n->prev) == NULL)
+		return;
+
+	switch (np->tok) {
+	case ROFF_br:
+	case ROFF_sp:
+	case MDOC_Pp:
+		mandoc_msg(MANDOCERR_PAR_SKIP,
+		    n->line, n->pos, "br after %s", roff_name[np->tok]);
+		roff_node_delete(man, n);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+roff_valid_fi(ROFF_VALID_ARGS)
+{
+	if ((n->flags & NODE_NOFILL) == 0)
+		mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "fi");
+}
+
+static void
+roff_valid_ft(ROFF_VALID_ARGS)
+{
+	const char		*cp;
+
+	if (n->child == NULL) {
+		man->next = ROFF_NEXT_CHILD;
+		roff_word_alloc(man, n->line, n->pos, "P");
+		man->last = n;
+		return;
+	}
+
+	cp = n->child->string;
+	if (mandoc_font(cp, (int)strlen(cp)) != ESCAPE_ERROR)
+		return;
+	mandoc_msg(MANDOCERR_FT_BAD, n->line, n->pos, "ft %s", cp);
+	roff_node_delete(man, n);
+}
+
+static void
+roff_valid_nf(ROFF_VALID_ARGS)
+{
+	if (n->flags & NODE_NOFILL)
+		mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "nf");
+}
+
+static void
+roff_valid_sp(ROFF_VALID_ARGS)
+{
+	struct roff_node	*np;
+
+	if ((np = n->prev) == NULL)
+		return;
+
+	switch (np->tok) {
+	case ROFF_br:
+		mandoc_msg(MANDOCERR_PAR_SKIP,
+		    np->line, np->pos, "br before sp");
+		roff_node_delete(man, np);
+		break;
+	case MDOC_Pp:
+		mandoc_msg(MANDOCERR_PAR_SKIP,
+		    n->line, n->pos, "sp after Pp");
+		roff_node_delete(man, n);
+		break;
+	default:
+		break;
+	}
+}

Property changes on: vendor/mandoc/20190723/roff_validate.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/st.c
===================================================================
--- vendor/mandoc/20190723/st.c	(nonexistent)
+++ vendor/mandoc/20190723/st.c	(revision 350350)
@@ -0,0 +1,82 @@
+/*	$Id: st.c,v 1.16 2018/12/14 01:18:26 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2010 Kristaps Dzonsons 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include 
+
+#include 
+#include 
+
+#include "mandoc.h"
+#include "roff.h"
+#include "libmdoc.h"
+
+#define LINE(x, y) \
+	if (0 == strcmp(p, x)) return(y);
+
+const char *
+mdoc_a2st(const char *p)
+{
+LINE("-p1003.1-88",	"IEEE Std 1003.1-1988 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-90",	"IEEE Std 1003.1-1990 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-96",	"ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-2001",	"IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-2004",	"IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-2008",	"IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1",	"IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1b",	"IEEE Std 1003.1b (\\(lqPOSIX.1b\\(rq)")
+LINE("-p1003.1b-93",	"IEEE Std 1003.1b-1993 (\\(lqPOSIX.1b\\(rq)")
+LINE("-p1003.1c-95",	"IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)")
+LINE("-p1003.1g-2000",	"IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)")
+LINE("-p1003.1i-95",	"IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)")
+LINE("-p1003.2",	"IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
+LINE("-p1003.2-92",	"IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
+LINE("-p1003.2a-92",	"IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
+LINE("-isoC",		"ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
+LINE("-isoC-90",	"ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
+LINE("-isoC-amd1",	"ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
+LINE("-isoC-tcor1",	"ISO/IEC 9899/TCOR1:1994 (\\(lqISO\\~C90, Technical Corrigendum 1\\(rq)")
+LINE("-isoC-tcor2",	"ISO/IEC 9899/TCOR2:1995 (\\(lqISO\\~C90, Technical Corrigendum 2\\(rq)")
+LINE("-isoC-99",	"ISO/IEC 9899:1999 (\\(lqISO\\~C99\\(rq)")
+LINE("-isoC-2011",	"ISO/IEC 9899:2011 (\\(lqISO\\~C11\\(rq)")
+LINE("-iso9945-1-90",	"ISO/IEC 9945-1:1990 (\\(lqPOSIX.1\\(rq)")
+LINE("-iso9945-1-96",	"ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
+LINE("-iso9945-2-93",	"ISO/IEC 9945-2:1993 (\\(lqPOSIX.2\\(rq)")
+LINE("-ansiC",		"ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
+LINE("-ansiC-89",	"ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
+LINE("-ieee754",	"IEEE Std 754-1985")
+LINE("-iso8802-3",	"ISO 8802-3: 1989")
+LINE("-iso8601",	"ISO 8601")
+LINE("-ieee1275-94",	"IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)")
+LINE("-xpg3",		"X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)")
+LINE("-xpg4",		"X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)")
+LINE("-xpg4.2",		"X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)")
+LINE("-xbd5",		"X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
+LINE("-xcu5",		"X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
+LINE("-xsh4.2",		"X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)")
+LINE("-xsh5",		"X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
+LINE("-xns5",		"X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
+LINE("-xns5.2",		"X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
+LINE("-xcurses4.2",	"X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
+LINE("-susv1",		"Version\\~1 of the Single UNIX Specification (\\(lqSUSv1\\(rq)")
+LINE("-susv2",		"Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
+LINE("-susv3",		"Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
+LINE("-susv4",		"Version\\~4 of the Single UNIX Specification (\\(lqSUSv4\\(rq)")
+LINE("-svid4",		"System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")
+
+	return NULL;
+}

Property changes on: vendor/mandoc/20190723/st.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tag.h
===================================================================
--- vendor/mandoc/20190723/tag.h	(nonexistent)
+++ vendor/mandoc/20190723/tag.h	(revision 350350)
@@ -0,0 +1,32 @@
+/*      $Id: tag.h,v 1.8 2018/11/22 11:30:23 schwarze Exp $    */
+/*
+ * Copyright (c) 2015 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct	tag_files {
+	char	 ofn[20];
+	char	 tfn[20];
+	char	*tagname;
+	int	 ofd;
+	int	 tfd;
+	pid_t	 tcpgid;
+	pid_t	 pager_pid;
+};
+
+
+struct tag_files *tag_init(void);
+void	 tag_put(const char *, int, size_t);
+void	 tag_write(void);
+void	 tag_unlink(void);

Property changes on: vendor/mandoc/20190723/tag.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl.3
===================================================================
--- vendor/mandoc/20190723/tbl.3	(nonexistent)
+++ vendor/mandoc/20190723/tbl.3	(revision 350350)
@@ -0,0 +1,349 @@
+.\"	$Id: tbl.3,v 1.6 2018/12/14 06:33:14 schwarze Exp $
+.\"
+.\" Copyright (c) 2013, 2015, 2018 Ingo Schwarze 
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: December 14 2018 $
+.Dt TBL 3
+.Os
+.Sh NAME
+.Nm tbl_alloc ,
+.Nm tbl_read ,
+.Nm tbl_restart ,
+.Nm tbl_span ,
+.Nm tbl_end ,
+.Nm tbl_free
+.Nd roff table parser library for mandoc
+.Sh SYNOPSIS
+.In sys/types.h
+.In tbl.h
+.In tbl_parse.h
+.Ft struct tbl_node *
+.Fo tbl_alloc
+.Fa "int pos"
+.Fa "int line"
+.Fc
+.Ft void
+.Fo tbl_read
+.Fa "struct tbl_node *tbl"
+.Fa "int ln"
+.Fa "const char *p"
+.Fa "int offs"
+.Fc
+.Ft void
+.Fo tbl_restart
+.Fa "int line"
+.Fa "int pos"
+.Fa "struct tbl_node *tbl"
+.Fc
+.Ft const struct tbl_span *
+.Fo tbl_span
+.Fa "struct tbl_node *tbl"
+.Fc
+.Ft void
+.Fo tbl_end
+.Fa "struct tbl_node **tblp"
+.Fc
+.Ft void
+.Fo tbl_free
+.Fa "struct tbl_node *tbl"
+.Fc
+.Sh DESCRIPTION
+This library is tightly integrated into the
+.Xr mandoc 1
+utility and not designed for stand-alone use.
+The present manual is intended as a reference for developers working on
+.Xr mandoc 1 .
+.Ss Data structures
+Unless otherwise noted, all of the following data structures are declared in
+.In tbl.h
+and are deleted in
+.Fn tbl_free .
+.Bl -tag -width Ds
+.It Vt struct tbl_node
+This structure describes a complete table.
+It is declared in
+.In tbl_int.h ,
+created in
+.Fn tbl_alloc ,
+and stored in the members
+.Fa first_tbl ,
+.Fa last_tbl ,
+and
+.Fa tbl
+of
+.Vt struct roff Bq Pa roff.c .
+.Pp
+The
+.Fa first_span ,
+.Fa current_span ,
+.Fa last_span ,
+and
+.Fa next
+members may be
+.Dv NULL .
+The
+.Fa first_row
+and
+.Fa last_row
+members may be
+.Dv NULL ,
+but if there is a span, the function
+.Fn tbl_layout
+guarantees that these pointers are not
+.Dv NULL .
+.It Vt struct tbl_opts
+This structure describes the options of one table.
+It is used as a substructure of
+.Vt struct tbl_node
+and thus created and deleted together with it.
+It is filled in
+.Fn tbl_options .
+.It Vt struct tbl_row
+This structure describes one layout line in a table
+by maintaining a list of all the cells in that line.
+It is allocated and filled in
+.Fn row Bq Pa tbl_layout.c
+and referenced from the
+.Fa layout
+member of
+.Vt struct tbl_node .
+.Pp
+The
+.Fa next
+member may be
+.Dv NULL .
+The function
+.Fn tbl_layout
+guarantees that the
+.Fa first
+and
+.Fa last
+members are not NULL.
+.It Vt struct tbl_cell
+This structure describes one layout cell in a table,
+in particular its alignment, membership in spans, and
+usage for lines.
+It is allocated and filled in
+.Fn cell_alloc Bq Pa tbl_layout.c
+and referenced from the
+.Fa first
+and
+.Fa last
+members of
+.Vt struct tbl_row .
+.Pp
+The
+.Fa next
+member may be
+.Dv NULL .
+.It Vt struct tbl_span
+This structure describes one data line in a table
+by maintaining a list of all data cells in that line
+or by specifying that it is a horizontal line.
+It is allocated and filled in
+.Fn newspan Bq Pa tbl_data.c
+which is called from
+.Fn tbl_data
+and referenced from the
+.Fa first_span ,
+.Fa current_span ,
+and
+.Fa last_span
+members of
+.Vt struct tbl_node ,
+and from the
+.Fa span
+members of
+.Vt struct man_node
+and
+.Vt struct mdoc_node
+from
+.In man.h
+and
+.In mdoc.h .
+.Pp
+The
+.Fa first ,
+.Fa last ,
+.Fa prev ,
+and
+.Fa next
+members may be
+.Dv NULL .
+The function
+.Fn newspan Bq Pa tbl_data.c
+guarantees that the
+.Fa opts
+and
+.Fa layout
+members are not
+.Dv NULL .
+.It Vt struct tbl_dat
+This structure describes one data cell in a table by specifying
+whether it contains a line or data, whether it spans additional
+layout cells, and by storing the data.
+It is allocated and filled in
+.Fn tbl_data
+and referenced from the
+.Fa first
+and
+.Fa last
+members of
+.Vt struct tbl_span .
+.Pp
+The
+.Fa string
+and
+.Fa next
+members may be
+.Dv NULL .
+The function
+.Fn getdata
+guarantees that the
+.Fa layout
+member is not
+.Dv NULL .
+.El
+.Ss Interface functions
+The following functions are implemented in
+.Pa tbl.c ,
+and all callers are in
+.Pa roff.c .
+.Bl -tag -width Ds
+.It Fn tbl_alloc
+Allocates, initializes, and returns a new
+.Vt struct tbl_node .
+Called from
+.Fn roff_TS .
+.It Fn tbl_read
+Dispatches to
+.Fn tbl_option ,
+.Fn tbl_layout ,
+.Fn tbl_cdata ,
+and
+.Fn tbl_data ,
+see below.
+Called from
+.Fn roff_parseln .
+.It Fn tbl_restart
+Resets the
+.Fa part
+member of
+.Vt struct tbl_node
+to
+.Dv TBL_PART_LAYOUT .
+Called from
+.Fn roff_T_ .
+.It Fn tbl_span
+On the first call, return the first
+.Vt struct tbl_span ;
+for later calls, return the next one or
+.Dv NULL .
+Called from
+.Fn roff_span .
+.It Fn tbl_end
+Flags the last span as
+.Dv TBL_SPAN_LAST
+and clears the pointer passed as an argment.
+Called from
+.Fn roff_TE
+and
+.Fn roff_endparse .
+.It Fn tbl_free
+Frees the specified
+.Vt struct tbl_node
+and all the tbl_row, tbl_cell, tbl_span, and tbl_dat structures
+referenced from it.
+Called from
+.Fn roff_free
+and
+.Fn roff_reset .
+.El
+.Ss Private functions
+The following functions are declared in
+.In tbl_int.h .
+.Bl -tag -width Ds
+.It Ft int Fn tbl_options "struct tbl_node *tbl" "int ln" "const char *p"
+Parses the options line into
+.Vt struct tbl_opts .
+Implemented in
+.Pa tbl_opts.c ,
+called from
+.Fn tbl_read .
+.It Ft int Fn tbl_layout "struct tbl_node *tbl" "int ln" "const char *p"
+Allocates and fills one
+.Vt struct tbl_row
+for each layout line and one
+.Vt struct tbl_cell
+for each layout cell.
+Implemented in
+.Pa tbl_layout.c ,
+called from
+.Fn tbl_read .
+.It Ft int Fn tbl_data "struct tbl_node *tbl" "int ln" "const char *p"
+Allocates one
+.Vt struct tbl_span
+for each data line and calls
+.Fn getdata
+for each data cell.
+Implemented in
+.Pa tbl_data.c ,
+called from
+.Fn tbl_read .
+.It Ft int Fn tbl_cdata "struct tbl_node *tbl" "int ln" "const char *p"
+Continues parsing a data line:
+When finding
+.Sq T} ,
+switches back to
+.Dv TBL_PART_DATA
+mode and calls
+.Fn getdata
+if there are more data cells on the line.
+Otherwise, appends the data to the current data cell.
+Implemented in
+.Pa tbl_data.c ,
+called from
+.Fn tbl_read .
+.It Xo
+.Ft int
+.Fo getdata
+.Fa "struct tbl_node *tbl"
+.Fa "struct tbl_span *dp"
+.Fa "int ln"
+.Fa "const char *p"
+.Fa "int *pos"
+.Fc
+.Xc
+Parses one data cell into one
+.Vt struct tbl_dat .
+Implemented in
+.Pa tbl_data.c ,
+called from
+.Fn tbl_data
+and
+.Fn tbl_cdata .
+.El
+.Sh SEE ALSO
+.Xr mandoc 1 ,
+.Xr mandoc 3 ,
+.Xr tbl 7
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm tbl
+library was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+with contributions from
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .

Property changes on: vendor/mandoc/20190723/tbl.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl.7
===================================================================
--- vendor/mandoc/20190723/tbl.7	(nonexistent)
+++ vendor/mandoc/20190723/tbl.7	(revision 350350)
@@ -0,0 +1,454 @@
+.\"	$Id: tbl.7,v 1.34 2019/03/02 21:03:02 schwarze Exp $
+.\"
+.\" Copyright (c) 2010, 2011 Kristaps Dzonsons 
+.\" Copyright (c) 2014,2015,2017,2018,2019 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 2 2019 $
+.Dt TBL 7
+.Os
+.Sh NAME
+.Nm tbl
+.Nd tbl language reference for mandoc
+.Sh DESCRIPTION
+The
+.Nm tbl
+language formats tables.
+It is used within
+.Xr mdoc 7
+and
+.Xr man 7
+pages.
+This manual describes the subset of the
+.Nm
+language accepted by the
+.Xr mandoc 1
+utility.
+.Pp
+Each table is started with a
+.Xr roff 7
+.Ic \&TS
+macro, consist of at most one line of
+.Sx Options ,
+one or more
+.Sx Layout
+lines, one or more
+.Sx Data
+lines, and ends with a
+.Ic \&TE
+macro.
+All input must be 7-bit ASCII.
+.Ss Options
+If the first input line of a table ends with a semicolon, it contains
+case-insensitive options separated by spaces, tabs, or commas.
+Otherwise, it is interpreted as the first
+.Sx Layout
+line.
+.Pp
+The following options are available.
+Some of them require arguments enclosed in parentheses:
+.Bl -tag -width Ds
+.It Cm allbox
+Draw a single-line box around each table cell.
+.It Cm box
+Draw a single-line box around the table.
+For GNU compatibility, this may also be invoked with
+.Cm frame .
+.It Cm center
+Center the table instead of left-adjusting it.
+For GNU compatibility, this may also be invoked with
+.Cm centre .
+.It Cm decimalpoint
+Use the single-character argument as the decimal point with the
+.Cm n
+layout key.
+This is a GNU extension.
+.It Cm delim
+Use the two characters of the argument as
+.Xr eqn 7
+delimiters.
+Currently unsupported.
+.It Cm doublebox
+Draw a double-line box around the table.
+For GNU compatibility, this may also be invoked with
+.Cm doubleframe .
+.It Cm expand
+Increase the width of the table to the current line length.
+Currently ignored.
+.It Cm linesize
+Draw lines with the point size given by the unsigned integer argument.
+Currently ignored.
+.It Cm nokeep
+Allow page breaks within the table.
+This is a GNU extension and currently ignored.
+.It Cm nospaces
+Ignore leading and trailing spaces in data cells.
+This is a GNU extension and currently ignored.
+.It Cm nowarn
+Suppress warnings about tables exceeding the current line length.
+This is a GNU extension and currently ignored.
+.It Cm tab
+Use the single-character argument as a delimiter between data cells.
+By default, the horizontal tabulator character is used.
+.El
+.Ss Layout
+The table layout follows an
+.Sx Options
+line or a
+.Xr roff 7
+.Ic \&TS
+or
+.Ic \&T&
+macro.
+Each layout line specifies how one line of
+.Sx Data
+is formatted.
+The last layout line ends with a full stop.
+It also applies to all remaining data lines.
+Multiple layout lines can be joined by commas on a single physical
+input line.
+.Pp
+Each layout line consists of one or more layout cell specifications,
+optionally separated by whitespace.
+The following case-insensitive key characters start a new cell
+specification:
+.Bl -tag -width 2n
+.It Cm c
+Center the string in this cell.
+.It Cm r
+Right-justify the string in this cell.
+.It Cm l
+Left-justify the string in this cell.
+.It Cm n
+Justify a number around its last decimal point.
+If no decimal point is found in the number,
+it is assumed to trail the number.
+.It Cm s
+Horizontally span columns from the last
+.Pf non- Cm s
+layout cell.
+It is an error if a column span follows a
+.Cm _
+or
+.Cm =
+cell, or comes first on a layout line.
+The combined cell as a whole consumes only one cell
+of the corresponding data line.
+.It Cm a
+Left-justify a string and pad with one space.
+.It Cm \(ha
+Vertically span rows from the last
+.Pf non- Cm \(ha
+layout cell.
+It is an error to invoke a vertical span on the first layout line.
+Unlike a horizontal span, a vertical span consumes a data cell
+and discards the content.
+.It Cm _
+Draw a single horizontal line in this cell.
+This consumes a data cell and discards the content.
+It may also be invoked with
+.Cm \- .
+.It Cm =
+Draw a double horizontal line in this cell.
+This consumes a data cell and discards the content.
+.El
+.Pp
+Each cell key may be followed by zero or more of the following
+case-insensitive modifiers:
+.Bl -tag -width 2n
+.It Cm b
+Use a bold font for the contents of this cell.
+.It Cm d
+Move content down to the last row of this vertical span.
+Currently ignored.
+.It Cm e
+Make this column wider to match the maximum width
+of any other column also having the
+.Cm e
+modifier.
+.It Cm f
+The next character selects the font to use for this cell.
+See the
+.Xr roff 7
+manual for supported one-character font names.
+.It Cm i
+Use an italic font for the contents of this cell.
+.It Cm m
+Specify a cell start macro.
+This is a GNU extension and currently unsupported.
+.It Cm p
+Set the point size to the following unsigned argument,
+or change it by the following signed argument.
+Currently ignored.
+.It Cm v
+Set the vertical line spacing to the following unsigned argument,
+or change it by the following signed argument.
+Currently ignored.
+.It Cm t
+Do not vertically center content in this vertical span,
+leave it in the top row.
+Currently ignored.
+.It Cm u
+Move cell content up by half a table row.
+Currently ignored.
+.It Cm w
+Specify a minimum column width.
+.It Cm x
+After determining the width of all other columns, distribute the
+rest of the line length among all columns having the
+.Cm x
+modifier.
+.It Cm z
+Do not use this cell for determining the width of this column.
+.It Cm \&|
+Draw a single vertical line to the right of this cell.
+.It Cm ||
+Draw a double vertical line to the right of this cell.
+.El
+.Pp
+If a modifier consists of decimal digits,
+it specifies a minimum spacing in units of
+.Cm n
+between this column and the next column to the right.
+The default is 3.
+If there is a vertical line, it is drawn inside the spacing.
+.Ss Data
+The data section follows the last
+.Sx Layout
+line.
+Each data line consists of one or more data cells, delimited by
+.Cm tab
+characters.
+.Pp
+If a data cell contains only the two bytes
+.Ql \e\(ha ,
+the cell above spans to this row, as if the layout specification
+of this cell were
+.Cm \(ha .
+.Pp
+If a data cell contains only the single character
+.Ql _
+or
+.Ql = ,
+a single or double horizontal line is drawn across the cell,
+joining its neighbours.
+If a data cell contains only the two character sequence
+.Ql \e_
+or
+.Ql \e= ,
+a single or double horizontal line is drawn inside the cell,
+not joining its neighbours.
+If a data line contains nothing but the single character
+.Ql _
+or
+.Ql = ,
+a horizontal line across the whole table is inserted
+without consuming a layout row.
+.Pp
+In place of any data cell, a text block can be used.
+It starts with
+.Ic \&T{
+at the end of a physical input line.
+Input line breaks inside the text block
+neither end the text block nor its data cell.
+It only ends if
+.Ic \&T}
+occurs at the beginning of a physical input line and is followed
+by an end-of-cell indicator.
+If the
+.Ic \&T}
+is followed by the end of the physical input line, the text block,
+the data cell, and the data line ends at this point.
+If the
+.Ic \&T}
+is followed by the
+.Cm tab
+character, only the text block and the data cell end,
+but the data line continues with the data cell following the
+.Cm tab
+character.
+If
+.Ic \&T}
+is followed by any other character, it does not end the text block,
+which instead continues to the following physical input line.
+.Sh EXAMPLES
+String justification and font selection:
+.Bd -literal -offset indent
+\&.TS
+rb c  lb
+r  ci l.
+r	center	l
+ri	ce	le
+right	c	left
+\&.TE
+.Ed
+.Bd -filled -offset indent
+.TS
+rb c  lb
+r  ci l.
+r	center	l
+ri	ce	le
+right	c	left
+.TE
+.Ed
+.Pp
+Some ports in
+.Ox 6.1
+to show number alignment and line drawing:
+.Bd -literal -offset indent
+\&.TS
+box tab(:);
+r| l
+r  n.
+software:version
+_
+AFL:2.39b
+Mutt:1.8.0
+Ruby:1.8.7.374
+TeX Live:2015
+\&.TE
+.Ed
+.Bd -filled -offset indent
+.TS
+box tab(:);
+r| l
+r  n.
+software:version
+_
+AFL:2.39b
+Mutt:1.8.0
+Ruby:1.8.7.374
+TeX Live:2015
+.TE
+.Ed
+.sp 2v
+Spans and skipping width calculations:
+.Bd -literal -offset indent
+\&.TS
+box tab(:);
+lz  s | rt
+lt| cb| \(ha
+\(ha | rz  s.
+left:r
+l:center:
+:right
+\&.TE
+.Ed
+.Bd -filled -offset indent
+.TS
+box tab(:);
+lz  s | rt
+lt| cb| ^
+^ | rz  s.
+left:r
+l:center:
+:right
+.TE
+.Ed
+.sp 2v
+Text blocks, specifying spacings and specifying and equalizing
+column widths, putting lines into individual cells, and overriding
+.Cm allbox :
+.Bd -literal -offset indent
+\&.TS
+allbox tab(:);
+le le||7 lw10.
+The fourth line:_:line 1
+of this column:=:line 2
+determines:\_:line 3
+the column width.:T{
+This text is too wide to fit into a column of width 17.
+T}:line 4
+T{
+No break here.
+T}::line 5
+\&.TE
+.Ed
+.Bd -filled -offset indent
+.TS
+allbox tab(:);
+le le||7 lw10.
+The fourth line:_:line 1
+of this column:=:line 2
+determines:\_:line 3
+the column width.:T{
+This text is too wide to fit into a column of width 17.
+T}:line 4
+T{
+No break here.
+T}::line 5
+.TE
+.Ed
+.sp 2v
+These examples were constructed to demonstrate many
+.Nm
+features in a compact way.
+In real manual pages, keep tables as simple as possible.
+They usually look better, are less fragile, and are more portable.
+.Sh COMPATIBILITY
+The
+.Xr mandoc 1
+implementation of
+.Nm
+doesn't support
+.Xr mdoc 7
+and
+.Xr man 7
+macros and
+.Xr eqn 7
+equations inside tables.
+.Sh SEE ALSO
+.Xr mandoc 1 ,
+.Xr man 7 ,
+.Xr mandoc_char 7 ,
+.Xr mdoc 7 ,
+.Xr roff 7
+.Rs
+.%A M. E. Lesk
+.%T Tbl\(emA Program to Format Tables
+.%D June 11, 1976
+.Re
+.Sh HISTORY
+The tbl utility, a preprocessor for troff, was originally written by M.
+E. Lesk at Bell Labs in 1975.
+The GNU reimplementation of tbl, part of the groff package, was released
+in 1990 by James Clark.
+A standalone tbl implementation was written by Kristaps Dzonsons in
+2010.
+This formed the basis of the implementation that first appeared in
+.Ox 4.9
+as a part of the
+.Xr mandoc 1
+utility.
+.Sh AUTHORS
+This
+.Nm
+reference was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
+.Sh BUGS
+In
+.Fl T
+.Cm utf8
+output mode, heavy lines are drawn instead of double lines.
+This cannot be improved because the Unicode standard only provides
+an incomplete set of box drawing characters with double lines,
+whereas it provides a full set of box drawing characters
+with heavy lines.
+It is unlikely this can be improved in the future because the box
+drawing characters are already marked in Unicode as characters
+intended only for backward compatibility with legacy systems,
+and their use is not encouraged.
+So it seems unlikely that the missing ones might get added in the future.

Property changes on: vendor/mandoc/20190723/tbl.7
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl.c
===================================================================
--- vendor/mandoc/20190723/tbl.c	(nonexistent)
+++ vendor/mandoc/20190723/tbl.c	(revision 350350)
@@ -0,0 +1,183 @@
+/*	$Id: tbl.c,v 1.46 2018/12/14 06:33:14 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2011, 2015 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "tbl.h"
+#include "libmandoc.h"
+#include "tbl_parse.h"
+#include "tbl_int.h"
+
+
+void
+tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
+{
+	const char	*cp;
+	int		 active;
+
+	/*
+	 * In the options section, proceed to the layout section
+	 * after a semicolon, or right away if there is no semicolon.
+	 * Ignore semicolons in arguments.
+	 */
+
+	if (tbl->part == TBL_PART_OPTS) {
+		tbl->part = TBL_PART_LAYOUT;
+		active = 1;
+		for (cp = p + pos; *cp != '\0'; cp++) {
+			switch (*cp) {
+			case '(':
+				active = 0;
+				continue;
+			case ')':
+				active = 1;
+				continue;
+			case ';':
+				if (active)
+					break;
+				continue;
+			default:
+				continue;
+			}
+			break;
+		}
+		if (*cp == ';') {
+			tbl_option(tbl, ln, p, &pos);
+			if (p[pos] == '\0')
+				return;
+		}
+	}
+
+	/* Process the other section types.  */
+
+	switch (tbl->part) {
+	case TBL_PART_LAYOUT:
+		tbl_layout(tbl, ln, p, pos);
+		break;
+	case TBL_PART_CDATA:
+		tbl_cdata(tbl, ln, p, pos);
+		break;
+	default:
+		tbl_data(tbl, ln, p, pos);
+		break;
+	}
+}
+
+struct tbl_node *
+tbl_alloc(int pos, int line, struct tbl_node *last_tbl)
+{
+	struct tbl_node	*tbl;
+
+	tbl = mandoc_calloc(1, sizeof(*tbl));
+	if (last_tbl != NULL)
+		last_tbl->next = tbl;
+	tbl->line = line;
+	tbl->pos = pos;
+	tbl->part = TBL_PART_OPTS;
+	tbl->opts.tab = '\t';
+	tbl->opts.decimal = '.';
+	return tbl;
+}
+
+void
+tbl_free(struct tbl_node *tbl)
+{
+	struct tbl_node	*old_tbl;
+	struct tbl_row	*rp;
+	struct tbl_cell	*cp;
+	struct tbl_span	*sp;
+	struct tbl_dat	*dp;
+
+	while (tbl != NULL) {
+		while ((rp = tbl->first_row) != NULL) {
+			tbl->first_row = rp->next;
+			while (rp->first != NULL) {
+				cp = rp->first;
+				rp->first = cp->next;
+				free(cp->wstr);
+				free(cp);
+			}
+			free(rp);
+		}
+		while ((sp = tbl->first_span) != NULL) {
+			tbl->first_span = sp->next;
+			while (sp->first != NULL) {
+				dp = sp->first;
+				sp->first = dp->next;
+				free(dp->string);
+				free(dp);
+			}
+			free(sp);
+		}
+		old_tbl = tbl;
+		tbl = tbl->next;
+		free(old_tbl);
+	}
+}
+
+void
+tbl_restart(int line, int pos, struct tbl_node *tbl)
+{
+	if (tbl->part == TBL_PART_CDATA)
+		mandoc_msg(MANDOCERR_TBLDATA_BLK, line, pos, "T&");
+
+	tbl->part = TBL_PART_LAYOUT;
+	tbl->line = line;
+	tbl->pos = pos;
+}
+
+struct tbl_span *
+tbl_span(struct tbl_node *tbl)
+{
+	struct tbl_span	 *span;
+
+	span = tbl->current_span ? tbl->current_span->next
+				 : tbl->first_span;
+	if (span != NULL)
+		tbl->current_span = span;
+	return span;
+}
+
+int
+tbl_end(struct tbl_node *tbl, int still_open)
+{
+	struct tbl_span *sp;
+
+	if (still_open)
+		mandoc_msg(MANDOCERR_BLK_NOEND, tbl->line, tbl->pos, "TS");
+	else if (tbl->part == TBL_PART_CDATA)
+		mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->line, tbl->pos, "TE");
+
+	sp = tbl->first_span;
+	while (sp != NULL && sp->first == NULL)
+		sp = sp->next;
+	if (sp == NULL) {
+		mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->line, tbl->pos, NULL);
+		return 0;
+	}
+	return 1;
+}

Property changes on: vendor/mandoc/20190723/tbl.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl.h
===================================================================
--- vendor/mandoc/20190723/tbl.h	(nonexistent)
+++ vendor/mandoc/20190723/tbl.h	(revision 350350)
@@ -0,0 +1,122 @@
+/*	$Id: tbl.h,v 1.1 2018/12/12 21:54:35 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 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.
+ */
+
+struct	tbl_opts {
+	int		  opts;
+#define	TBL_OPT_ALLBOX	 (1 << 0)  /* Option "allbox". */
+#define	TBL_OPT_BOX	 (1 << 1)  /* Option "box". */
+#define	TBL_OPT_CENTRE	 (1 << 2)  /* Option "center". */
+#define	TBL_OPT_DBOX	 (1 << 3)  /* Option "doublebox". */
+#define	TBL_OPT_EXPAND	 (1 << 4)  /* Option "expand". */
+#define	TBL_OPT_NOKEEP	 (1 << 5)  /* Option "nokeep". */
+#define	TBL_OPT_NOSPACE	 (1 << 6)  /* Option "nospaces". */
+#define	TBL_OPT_NOWARN	 (1 << 7)  /* Option "nowarn". */
+	int		  cols;    /* Number of columns. */
+	int		  lvert;   /* Width of left vertical line. */
+	int		  rvert;   /* Width of right vertical line. */
+	char		  tab;     /* Option "tab": cell separator. */
+	char		  decimal; /* Option "decimalpoint". */
+};
+
+enum	tbl_cellt {
+	TBL_CELL_CENTRE,  /* c, C */
+	TBL_CELL_RIGHT,   /* r, R */
+	TBL_CELL_LEFT,    /* l, L */
+	TBL_CELL_NUMBER,  /* n, N */
+	TBL_CELL_SPAN,    /* s, S */
+	TBL_CELL_LONG,    /* a, A */
+	TBL_CELL_DOWN,    /* ^    */
+	TBL_CELL_HORIZ,   /* _, - */
+	TBL_CELL_DHORIZ,  /* =    */
+	TBL_CELL_MAX
+};
+
+/*
+ * A cell in a layout row.
+ */
+struct	tbl_cell {
+	struct tbl_cell	 *next;     /* Layout cell to the right. */
+	char		 *wstr;     /* Min width represented as a string. */
+	size_t		  width;    /* Minimum column width. */
+	size_t		  spacing;  /* To the right of the column. */
+	int		  vert;     /* Width of subsequent vertical line. */
+	int		  col;      /* Column number, starting from 0. */
+	int		  flags;
+#define	TBL_CELL_BOLD	 (1 << 0)   /* b, B, fB */
+#define	TBL_CELL_ITALIC	 (1 << 1)   /* i, I, fI */
+#define	TBL_CELL_TALIGN	 (1 << 2)   /* t, T */
+#define	TBL_CELL_UP	 (1 << 3)   /* u, U */
+#define	TBL_CELL_BALIGN	 (1 << 4)   /* d, D */
+#define	TBL_CELL_WIGN	 (1 << 5)   /* z, Z */
+#define	TBL_CELL_EQUAL	 (1 << 6)   /* e, E */
+#define	TBL_CELL_WMAX	 (1 << 7)   /* x, X */
+	enum tbl_cellt	  pos;
+};
+
+/*
+ * A layout row.
+ */
+struct	tbl_row {
+	struct tbl_row	 *next;   /* Layout row below. */
+	struct tbl_cell	 *first;  /* Leftmost layout cell. */
+	struct tbl_cell	 *last;   /* Rightmost layout cell. */
+	int		  vert;   /* Width of left vertical line. */
+};
+
+enum	tbl_datt {
+	TBL_DATA_NONE,    /* Uninitialized row. */
+	TBL_DATA_DATA,    /* Contains data rather than a line. */
+	TBL_DATA_HORIZ,   /* _: connecting horizontal line. */
+	TBL_DATA_DHORIZ,  /* =: connecting double horizontal line. */
+	TBL_DATA_NHORIZ,  /* \_: isolated horizontal line. */
+	TBL_DATA_NDHORIZ  /* \=: isolated double horizontal line. */
+};
+
+/*
+ * A cell within a row of data.  The "string" field contains the
+ * actual string value that's in the cell.  The rest is layout.
+ */
+struct	tbl_dat {
+	struct tbl_dat	 *next;    /* Data cell to the right. */
+	struct tbl_cell	 *layout;  /* Associated layout cell. */
+	char		 *string;  /* Data, or NULL if not TBL_DATA_DATA. */
+	int		  hspans;  /* How many horizontal spans follow. */
+	int		  vspans;  /* How many vertical spans follow. */
+	int		  block;   /* T{ text block T} */
+	enum tbl_datt	  pos;
+};
+
+enum	tbl_spant {
+	TBL_SPAN_DATA,   /* Contains data rather than a line. */
+	TBL_SPAN_HORIZ,  /* _: horizontal line. */
+	TBL_SPAN_DHORIZ  /* =: double horizontal line. */
+};
+
+/*
+ * A row of data in a table.
+ */
+struct	tbl_span {
+	struct tbl_opts	 *opts;    /* Options for the table as a whole. */
+	struct tbl_span	 *prev;    /* Data row above. */
+	struct tbl_span	 *next;    /* Data row below. */
+	struct tbl_row	 *layout;  /* Associated layout row. */
+	struct tbl_dat	 *first;   /* Leftmost data cell. */
+	struct tbl_dat	 *last;    /* Rightmost data cell. */
+	int		  line;    /* Input file line number. */
+	enum tbl_spant	  pos;
+};

Property changes on: vendor/mandoc/20190723/tbl.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl_data.c
===================================================================
--- vendor/mandoc/20190723/tbl_data.c	(nonexistent)
+++ vendor/mandoc/20190723/tbl_data.c	(revision 350350)
@@ -0,0 +1,300 @@
+/*	$Id: tbl_data.c,v 1.52 2019/02/09 16:00:39 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2011,2015,2017,2018,2019 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "tbl.h"
+#include "libmandoc.h"
+#include "tbl_int.h"
+
+static	void		 getdata(struct tbl_node *, struct tbl_span *,
+				int, const char *, int *);
+static	struct tbl_span	*newspan(struct tbl_node *, int,
+				struct tbl_row *);
+
+
+static void
+getdata(struct tbl_node *tbl, struct tbl_span *dp,
+		int ln, const char *p, int *pos)
+{
+	struct tbl_dat	*dat, *pdat;
+	struct tbl_cell	*cp;
+	struct tbl_span	*pdp;
+	int		 sv;
+
+	/*
+	 * Determine the length of the string in the cell
+	 * and advance the parse point to the end of the cell.
+	 */
+
+	sv = *pos;
+	while (p[*pos] != '\0' && p[*pos] != tbl->opts.tab)
+		(*pos)++;
+
+	/* Advance to the next layout cell, skipping spanners. */
+
+	cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
+	while (cp != NULL && cp->pos == TBL_CELL_SPAN)
+		cp = cp->next;
+
+	/*
+	 * If the current layout row is out of cells, allocate
+	 * a new cell if another row of the table has at least
+	 * this number of columns, or discard the input if we
+	 * are beyond the last column of the table as a whole.
+	 */
+
+	if (cp == NULL) {
+		if (dp->layout->last->col + 1 < dp->opts->cols) {
+			cp = mandoc_calloc(1, sizeof(*cp));
+			cp->pos = TBL_CELL_LEFT;
+			dp->layout->last->next = cp;
+			cp->col = dp->layout->last->col + 1;
+			dp->layout->last = cp;
+		} else {
+			mandoc_msg(MANDOCERR_TBLDATA_EXTRA,
+			    ln, sv, "%s", p + sv);
+			while (p[*pos] != '\0')
+				(*pos)++;
+			return;
+		}
+	}
+
+	dat = mandoc_malloc(sizeof(*dat));
+	dat->layout = cp;
+	dat->next = NULL;
+	dat->string = NULL;
+	dat->hspans = 0;
+	dat->vspans = 0;
+	dat->block = 0;
+	dat->pos = TBL_DATA_NONE;
+
+	/*
+	 * Increment the number of vertical spans in a data cell above,
+	 * if this cell vertically extends one or more cells above.
+	 * The iteration must be done over data rows,
+	 * not over layout rows, because one layout row
+	 * can be reused for more than one data row.
+	 */
+
+	if (cp->pos == TBL_CELL_DOWN ||
+	    (*pos - sv == 2 && p[sv] == '\\' && p[sv + 1] == '^')) {
+		pdp = dp;
+		while ((pdp = pdp->prev) != NULL) {
+			pdat = pdp->first;
+			while (pdat != NULL &&
+			    pdat->layout->col < dat->layout->col)
+				pdat = pdat->next;
+			if (pdat == NULL)
+				break;
+			if (pdat->layout->pos != TBL_CELL_DOWN &&
+			    strcmp(pdat->string, "\\^") != 0) {
+				pdat->vspans++;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * Count the number of horizontal spans to the right of this cell.
+	 * This is purely a matter of the layout, independent of the data.
+	 */
+
+	for (cp = cp->next; cp != NULL; cp = cp->next)
+		if (cp->pos == TBL_CELL_SPAN)
+			dat->hspans++;
+		else
+			break;
+
+	/* Append the new data cell to the data row. */
+
+	if (dp->last == NULL)
+		dp->first = dat;
+	else
+		dp->last->next = dat;
+	dp->last = dat;
+
+	/*
+	 * Check for a continued-data scope opening.  This consists of a
+	 * trailing `T{' at the end of the line.  Subsequent lines,
+	 * until a standalone `T}', are included in our cell.
+	 */
+
+	if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
+		tbl->part = TBL_PART_CDATA;
+		return;
+	}
+
+	dat->string = mandoc_strndup(p + sv, *pos - sv);
+
+	if (p[*pos] != '\0')
+		(*pos)++;
+
+	if ( ! strcmp(dat->string, "_"))
+		dat->pos = TBL_DATA_HORIZ;
+	else if ( ! strcmp(dat->string, "="))
+		dat->pos = TBL_DATA_DHORIZ;
+	else if ( ! strcmp(dat->string, "\\_"))
+		dat->pos = TBL_DATA_NHORIZ;
+	else if ( ! strcmp(dat->string, "\\="))
+		dat->pos = TBL_DATA_NDHORIZ;
+	else
+		dat->pos = TBL_DATA_DATA;
+
+	if ((dat->layout->pos == TBL_CELL_HORIZ ||
+	    dat->layout->pos == TBL_CELL_DHORIZ ||
+	    dat->layout->pos == TBL_CELL_DOWN) &&
+	    dat->pos == TBL_DATA_DATA && *dat->string != '\0')
+		mandoc_msg(MANDOCERR_TBLDATA_SPAN,
+		    ln, sv, "%s", dat->string);
+}
+
+void
+tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
+{
+	struct tbl_dat	*dat;
+	size_t		 sz;
+
+	dat = tbl->last_span->last;
+
+	if (p[pos] == 'T' && p[pos + 1] == '}') {
+		pos += 2;
+		if (p[pos] == tbl->opts.tab) {
+			tbl->part = TBL_PART_DATA;
+			pos++;
+			while (p[pos] != '\0')
+				getdata(tbl, tbl->last_span, ln, p, &pos);
+			return;
+		} else if (p[pos] == '\0') {
+			tbl->part = TBL_PART_DATA;
+			return;
+		}
+
+		/* Fallthrough: T} is part of a word. */
+	}
+
+	dat->pos = TBL_DATA_DATA;
+	dat->block = 1;
+
+	if (dat->string != NULL) {
+		sz = strlen(p + pos) + strlen(dat->string) + 2;
+		dat->string = mandoc_realloc(dat->string, sz);
+		(void)strlcat(dat->string, " ", sz);
+		(void)strlcat(dat->string, p + pos, sz);
+	} else
+		dat->string = mandoc_strdup(p + pos);
+
+	if (dat->layout->pos == TBL_CELL_DOWN)
+		mandoc_msg(MANDOCERR_TBLDATA_SPAN,
+		    ln, pos, "%s", dat->string);
+}
+
+static struct tbl_span *
+newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
+{
+	struct tbl_span	*dp;
+
+	dp = mandoc_calloc(1, sizeof(*dp));
+	dp->line = line;
+	dp->opts = &tbl->opts;
+	dp->layout = rp;
+	dp->prev = tbl->last_span;
+
+	if (dp->prev == NULL) {
+		tbl->first_span = dp;
+		tbl->current_span = NULL;
+	} else
+		dp->prev->next = dp;
+	tbl->last_span = dp;
+
+	return dp;
+}
+
+void
+tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
+{
+	struct tbl_row	*rp;
+	struct tbl_cell	*cp;
+	struct tbl_span	*sp;
+
+	rp = (sp = tbl->last_span) == NULL ? tbl->first_row :
+	    sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ?
+	    sp->layout->next : sp->layout;
+
+	assert(rp != NULL);
+
+	if (p[1] == '\0') {
+		switch (p[0]) {
+		case '.':
+			/*
+			 * Empty request lines must be handled here
+			 * and cannot be discarded in roff_parseln()
+			 * because in the layout section, they
+			 * are significant and end the layout.
+			 */
+			return;
+		case '_':
+			sp = newspan(tbl, ln, rp);
+			sp->pos = TBL_SPAN_HORIZ;
+			return;
+		case '=':
+			sp = newspan(tbl, ln, rp);
+			sp->pos = TBL_SPAN_DHORIZ;
+			return;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * If the layout row contains nothing but horizontal lines,
+	 * allocate an empty span for it and assign the current span
+	 * to the next layout row accepting data.
+	 */
+
+	while (rp->next != NULL) {
+		if (rp->last->col + 1 < tbl->opts.cols)
+			break;
+		for (cp = rp->first; cp != NULL; cp = cp->next)
+			if (cp->pos != TBL_CELL_HORIZ &&
+			    cp->pos != TBL_CELL_DHORIZ)
+				break;
+		if (cp != NULL)
+			break;
+		sp = newspan(tbl, ln, rp);
+		sp->pos = TBL_SPAN_DATA;
+		rp = rp->next;
+	}
+
+	/* Process a real data row. */
+
+	sp = newspan(tbl, ln, rp);
+	sp->pos = TBL_SPAN_DATA;
+	while (p[pos] != '\0')
+		getdata(tbl, sp, ln, p, &pos);
+}

Property changes on: vendor/mandoc/20190723/tbl_data.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl_int.h
===================================================================
--- vendor/mandoc/20190723/tbl_int.h	(nonexistent)
+++ vendor/mandoc/20190723/tbl_int.h	(revision 350350)
@@ -0,0 +1,47 @@
+/*	$Id: tbl_int.h,v 1.2 2018/12/14 06:33:14 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2011,2013,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.
+ *
+ * Internal interfaces of the tbl(7) parser.
+ * For use inside the tbl(7) parser only.
+ */
+
+enum	tbl_part {
+	TBL_PART_OPTS,    /* In the first line, ends with semicolon. */
+	TBL_PART_LAYOUT,  /* In the layout section, ends with full stop. */
+	TBL_PART_DATA,    /* In the data section, ends with TE. */
+	TBL_PART_CDATA    /* In a T{ block, ends with T} */
+};
+
+struct	tbl_node {
+	struct tbl_opts	  opts;		/* Options for the whole table. */
+	struct tbl_node	 *next;		/* Next table. */
+	struct tbl_row	 *first_row;	/* First layout row. */
+	struct tbl_row	 *last_row;	/* Last layout row. */
+	struct tbl_span	 *first_span;	/* First data row. */
+	struct tbl_span	 *current_span;	/* Data row being parsed. */
+	struct tbl_span	 *last_span;	/* Last data row. */
+	int		  line;		/* Line number in input file. */
+	int		  pos;		/* Column number in input file. */
+	enum tbl_part	  part;		/* Table section being parsed. */
+};
+
+
+void		 tbl_option(struct tbl_node *, int, const char *, int *);
+void		 tbl_layout(struct tbl_node *, int, const char *, int);
+void		 tbl_data(struct tbl_node *, int, const char *, int);
+void		 tbl_cdata(struct tbl_node *, int, const char *, int);
+void		 tbl_reset(struct tbl_node *);

Property changes on: vendor/mandoc/20190723/tbl_int.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl_layout.c
===================================================================
--- vendor/mandoc/20190723/tbl_layout.c	(nonexistent)
+++ vendor/mandoc/20190723/tbl_layout.c	(revision 350350)
@@ -0,0 +1,373 @@
+/*	$Id: tbl_layout.c,v 1.48 2018/12/14 05:18:03 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2012, 2014, 2015, 2017 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "tbl.h"
+#include "libmandoc.h"
+#include "tbl_int.h"
+
+struct	tbl_phrase {
+	char		 name;
+	enum tbl_cellt	 key;
+};
+
+static	const struct tbl_phrase keys[] = {
+	{ 'c',		 TBL_CELL_CENTRE },
+	{ 'r',		 TBL_CELL_RIGHT },
+	{ 'l',		 TBL_CELL_LEFT },
+	{ 'n',		 TBL_CELL_NUMBER },
+	{ 's',		 TBL_CELL_SPAN },
+	{ 'a',		 TBL_CELL_LONG },
+	{ '^',		 TBL_CELL_DOWN },
+	{ '-',		 TBL_CELL_HORIZ },
+	{ '_',		 TBL_CELL_HORIZ },
+	{ '=',		 TBL_CELL_DHORIZ }
+};
+
+#define KEYS_MAX ((int)(sizeof(keys)/sizeof(keys[0])))
+
+static	void		 mods(struct tbl_node *, struct tbl_cell *,
+				int, const char *, int *);
+static	void		 cell(struct tbl_node *, struct tbl_row *,
+				int, const char *, int *);
+static	struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *,
+				enum tbl_cellt);
+
+
+static void
+mods(struct tbl_node *tbl, struct tbl_cell *cp,
+		int ln, const char *p, int *pos)
+{
+	char		*endptr;
+	size_t		 sz;
+
+mod:
+	while (p[*pos] == ' ' || p[*pos] == '\t')
+		(*pos)++;
+
+	/* Row delimiters and cell specifiers end modifier lists. */
+
+	if (strchr(".,-=^_ACLNRSaclnrs", p[*pos]) != NULL)
+		return;
+
+	/* Throw away parenthesised expression. */
+
+	if ('(' == p[*pos]) {
+		(*pos)++;
+		while (p[*pos] && ')' != p[*pos])
+			(*pos)++;
+		if (')' == p[*pos]) {
+			(*pos)++;
+			goto mod;
+		}
+		mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, ln, *pos, NULL);
+		return;
+	}
+
+	/* Parse numerical spacing from modifier string. */
+
+	if (isdigit((unsigned char)p[*pos])) {
+		cp->spacing = strtoull(p + *pos, &endptr, 10);
+		*pos = endptr - p;
+		goto mod;
+	}
+
+	switch (tolower((unsigned char)p[(*pos)++])) {
+	case 'b':
+		cp->flags |= TBL_CELL_BOLD;
+		goto mod;
+	case 'd':
+		cp->flags |= TBL_CELL_BALIGN;
+		goto mod;
+	case 'e':
+		cp->flags |= TBL_CELL_EQUAL;
+		goto mod;
+	case 'f':
+		break;
+	case 'i':
+		cp->flags |= TBL_CELL_ITALIC;
+		goto mod;
+	case 'm':
+		mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, ln, *pos, "m");
+		goto mod;
+	case 'p':
+	case 'v':
+		if (p[*pos] == '-' || p[*pos] == '+')
+			(*pos)++;
+		while (isdigit((unsigned char)p[*pos]))
+			(*pos)++;
+		goto mod;
+	case 't':
+		cp->flags |= TBL_CELL_TALIGN;
+		goto mod;
+	case 'u':
+		cp->flags |= TBL_CELL_UP;
+		goto mod;
+	case 'w':
+		sz = 0;
+		if (p[*pos] == '(') {
+			(*pos)++;
+			while (p[*pos + sz] != '\0' && p[*pos + sz] != ')')
+				sz++;
+		} else
+			while (isdigit((unsigned char)p[*pos + sz]))
+				sz++;
+		if (sz) {
+			free(cp->wstr);
+			cp->wstr = mandoc_strndup(p + *pos, sz);
+			*pos += sz;
+			if (p[*pos] == ')')
+				(*pos)++;
+		}
+		goto mod;
+	case 'x':
+		cp->flags |= TBL_CELL_WMAX;
+		goto mod;
+	case 'z':
+		cp->flags |= TBL_CELL_WIGN;
+		goto mod;
+	case '|':
+		if (cp->vert < 2)
+			cp->vert++;
+		else
+			mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
+			    ln, *pos - 1, NULL);
+		goto mod;
+	default:
+		mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR,
+		    ln, *pos - 1, "%c", p[*pos - 1]);
+		goto mod;
+	}
+
+	/* Ignore parenthised font names for now. */
+
+	if (p[*pos] == '(')
+		goto mod;
+
+	/* Support only one-character font-names for now. */
+
+	if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) {
+		mandoc_msg(MANDOCERR_FT_BAD,
+		    ln, *pos, "TS %s", p + *pos - 1);
+		if (p[*pos] != '\0')
+			(*pos)++;
+		if (p[*pos] != '\0')
+			(*pos)++;
+		goto mod;
+	}
+
+	switch (p[(*pos)++]) {
+	case '3':
+	case 'B':
+		cp->flags |= TBL_CELL_BOLD;
+		goto mod;
+	case '2':
+	case 'I':
+		cp->flags |= TBL_CELL_ITALIC;
+		goto mod;
+	case '1':
+	case 'R':
+		goto mod;
+	default:
+		mandoc_msg(MANDOCERR_FT_BAD,
+		    ln, *pos - 1, "TS f%c", p[*pos - 1]);
+		goto mod;
+	}
+}
+
+static void
+cell(struct tbl_node *tbl, struct tbl_row *rp,
+		int ln, const char *p, int *pos)
+{
+	int		 i;
+	enum tbl_cellt	 c;
+
+	/* Handle leading vertical lines */
+
+	while (p[*pos] == ' ' || p[*pos] == '\t' || p[*pos] == '|') {
+		if (p[*pos] == '|') {
+			if (rp->vert < 2)
+				rp->vert++;
+			else
+				mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
+				    ln, *pos, NULL);
+		}
+		(*pos)++;
+	}
+
+again:
+	while (p[*pos] == ' ' || p[*pos] == '\t')
+		(*pos)++;
+
+	if (p[*pos] == '.' || p[*pos] == '\0')
+		return;
+
+	/* Parse the column position (`c', `l', `r', ...). */
+
+	for (i = 0; i < KEYS_MAX; i++)
+		if (tolower((unsigned char)p[*pos]) == keys[i].name)
+			break;
+
+	if (i == KEYS_MAX) {
+		mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR,
+		    ln, *pos, "%c", p[*pos]);
+		(*pos)++;
+		goto again;
+	}
+	c = keys[i].key;
+
+	/* Special cases of spanners. */
+
+	if (c == TBL_CELL_SPAN) {
+		if (rp->last == NULL)
+			mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, ln, *pos, NULL);
+		else if (rp->last->pos == TBL_CELL_HORIZ ||
+		    rp->last->pos == TBL_CELL_DHORIZ)
+			c = rp->last->pos;
+	} else if (c == TBL_CELL_DOWN && rp == tbl->first_row)
+		mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, ln, *pos, NULL);
+
+	(*pos)++;
+
+	/* Allocate cell then parse its modifiers. */
+
+	mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos);
+}
+
+void
+tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos)
+{
+	struct tbl_row	*rp;
+
+	rp = NULL;
+	for (;;) {
+		/* Skip whitespace before and after each cell. */
+
+		while (p[pos] == ' ' || p[pos] == '\t')
+			pos++;
+
+		switch (p[pos]) {
+		case ',':  /* Next row on this input line. */
+			pos++;
+			rp = NULL;
+			continue;
+		case '\0':  /* Next row on next input line. */
+			return;
+		case '.':  /* End of layout. */
+			pos++;
+			tbl->part = TBL_PART_DATA;
+
+			/*
+			 * When the layout is completely empty,
+			 * default to one left-justified column.
+			 */
+
+			if (tbl->first_row == NULL) {
+				tbl->first_row = tbl->last_row =
+				    mandoc_calloc(1, sizeof(*rp));
+			}
+			if (tbl->first_row->first == NULL) {
+				mandoc_msg(MANDOCERR_TBLLAYOUT_NONE,
+				    ln, pos, NULL);
+				cell_alloc(tbl, tbl->first_row,
+				    TBL_CELL_LEFT);
+				if (tbl->opts.lvert < tbl->first_row->vert)
+					tbl->opts.lvert = tbl->first_row->vert;
+				return;
+			}
+
+			/*
+			 * Search for the widest line
+			 * along the left and right margins.
+			 */
+
+			for (rp = tbl->first_row; rp; rp = rp->next) {
+				if (tbl->opts.lvert < rp->vert)
+					tbl->opts.lvert = rp->vert;
+				if (rp->last != NULL &&
+				    rp->last->col + 1 == tbl->opts.cols &&
+				    tbl->opts.rvert < rp->last->vert)
+					tbl->opts.rvert = rp->last->vert;
+
+				/* If the last line is empty, drop it. */
+
+				if (rp->next != NULL &&
+				    rp->next->first == NULL) {
+					free(rp->next);
+					rp->next = NULL;
+					tbl->last_row = rp;
+				}
+			}
+			return;
+		default:  /* Cell. */
+			break;
+		}
+
+		/*
+		 * If the last line had at least one cell,
+		 * start a new one; otherwise, continue it.
+		 */
+
+		if (rp == NULL) {
+			if (tbl->last_row == NULL ||
+			    tbl->last_row->first != NULL) {
+				rp = mandoc_calloc(1, sizeof(*rp));
+				if (tbl->last_row)
+					tbl->last_row->next = rp;
+				else
+					tbl->first_row = rp;
+				tbl->last_row = rp;
+			} else
+				rp = tbl->last_row;
+		}
+		cell(tbl, rp, ln, p, &pos);
+	}
+}
+
+static struct tbl_cell *
+cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
+{
+	struct tbl_cell	*p, *pp;
+
+	p = mandoc_calloc(1, sizeof(*p));
+	p->spacing = SIZE_MAX;
+	p->pos = pos;
+
+	if ((pp = rp->last) != NULL) {
+		pp->next = p;
+		p->col = pp->col + 1;
+	} else
+		rp->first = p;
+	rp->last = p;
+
+	if (tbl->opts.cols <= p->col)
+		tbl->opts.cols = p->col + 1;
+
+	return p;
+}

Property changes on: vendor/mandoc/20190723/tbl_layout.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl_opts.c
===================================================================
--- vendor/mandoc/20190723/tbl_opts.c	(nonexistent)
+++ vendor/mandoc/20190723/tbl_opts.c	(revision 350350)
@@ -0,0 +1,173 @@
+/*	$Id: tbl_opts.c,v 1.24 2018/12/14 05:18:03 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2015 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include "mandoc.h"
+#include "tbl.h"
+#include "libmandoc.h"
+#include "tbl_int.h"
+
+#define	KEY_DPOINT	0
+#define	KEY_DELIM	1
+#define	KEY_LINESIZE	2
+#define	KEY_TAB		3
+
+struct	tbl_phrase {
+	const char	*name;
+	int		 key;
+};
+
+static	const struct tbl_phrase keys[] = {
+	{"decimalpoint", 0},
+	{"delim",	 0},
+	{"linesize",	 0},
+	{"tab",		 0},
+	{"allbox",	 TBL_OPT_ALLBOX | TBL_OPT_BOX},
+	{"box",		 TBL_OPT_BOX},
+	{"frame",	 TBL_OPT_BOX},
+	{"center",	 TBL_OPT_CENTRE},
+	{"centre",	 TBL_OPT_CENTRE},
+	{"doublebox",	 TBL_OPT_DBOX},
+	{"doubleframe",  TBL_OPT_DBOX},
+	{"expand",	 TBL_OPT_EXPAND},
+	{"nokeep",	 TBL_OPT_NOKEEP},
+	{"nospaces",	 TBL_OPT_NOSPACE},
+	{"nowarn",	 TBL_OPT_NOWARN},
+};
+
+#define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0])))
+
+static	void	 arg(struct tbl_node *, int, const char *, int *, int);
+
+
+static void
+arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
+{
+	int		 len, want;
+
+	while (p[*pos] == ' ' || p[*pos] == '\t')
+		(*pos)++;
+
+	/* Arguments are enclosed in parentheses. */
+
+	len = 0;
+	if (p[*pos] == '(') {
+		(*pos)++;
+		while (p[*pos + len] != ')')
+			len++;
+	}
+
+	switch (key) {
+	case KEY_DELIM:
+		mandoc_msg(MANDOCERR_TBLOPT_EQN,
+		    ln, *pos, "%.*s", len, p + *pos);
+		want = 2;
+		break;
+	case KEY_TAB:
+		want = 1;
+		if (len == want)
+			tbl->opts.tab = p[*pos];
+		break;
+	case KEY_LINESIZE:
+		want = 0;
+		break;
+	case KEY_DPOINT:
+		want = 1;
+		if (len == want)
+			tbl->opts.decimal = p[*pos];
+		break;
+	default:
+		abort();
+	}
+
+	if (len == 0)
+		mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos,
+		    "%s", keys[key].name);
+	else if (want && len != want)
+		mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos,
+		    "%s want %d have %d", keys[key].name, want, len);
+
+	*pos += len;
+	if (p[*pos] == ')')
+		(*pos)++;
+}
+
+/*
+ * Parse one line of options up to the semicolon.
+ * Each option can be preceded by blanks and/or commas,
+ * and some options are followed by arguments.
+ */
+void
+tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
+{
+	int		 i, pos, len;
+
+	pos = *offs;
+	for (;;) {
+		while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
+			pos++;
+
+		if (p[pos] == ';') {
+			*offs = pos + 1;
+			return;
+		}
+
+		/* Parse one option name. */
+
+		len = 0;
+		while (isalpha((unsigned char)p[pos + len]))
+			len++;
+
+		if (len == 0) {
+			mandoc_msg(MANDOCERR_TBLOPT_ALPHA,
+			    ln, pos, "%c", p[pos]);
+			pos++;
+			continue;
+		}
+
+		/* Look up the option name. */
+
+		i = 0;
+		while (i < KEY_MAXKEYS &&
+		    (strncasecmp(p + pos, keys[i].name, len) ||
+		     keys[i].name[len] != '\0'))
+			i++;
+
+		if (i == KEY_MAXKEYS) {
+			mandoc_msg(MANDOCERR_TBLOPT_BAD,
+			    ln, pos, "%.*s", len, p + pos);
+			pos += len;
+			continue;
+		}
+
+		/* Handle the option. */
+
+		pos += len;
+		if (keys[i].key)
+			tbl->opts.opts |= keys[i].key;
+		else
+			arg(tbl, ln, p, &pos, i);
+	}
+}

Property changes on: vendor/mandoc/20190723/tbl_opts.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/tbl_parse.h
===================================================================
--- vendor/mandoc/20190723/tbl_parse.h	(nonexistent)
+++ vendor/mandoc/20190723/tbl_parse.h	(revision 350350)
@@ -0,0 +1,30 @@
+/*	$Id: tbl_parse.h,v 1.2 2018/12/14 06:33:14 schwarze Exp $ */
+/*
+ * Copyright (c) 2011 Kristaps Dzonsons 
+ * Copyright (c) 2011, 2017 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * External interface of the tbl(7) parser.
+ * For use in the roff(7) and tbl(7) parsers only.
+ */
+
+struct tbl_node;
+struct tbl_span;
+
+struct tbl_node	*tbl_alloc(int, int, struct tbl_node *);
+int		 tbl_end(struct tbl_node *, int);
+void		 tbl_free(struct tbl_node *);
+void		 tbl_read(struct tbl_node *, int, const char *, int);
+void		 tbl_restart(int, int, struct tbl_node *);
+struct tbl_span	*tbl_span(struct tbl_node *);

Property changes on: vendor/mandoc/20190723/tbl_parse.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/term.h
===================================================================
--- vendor/mandoc/20190723/term.h	(nonexistent)
+++ vendor/mandoc/20190723/term.h	(revision 350350)
@@ -0,0 +1,158 @@
+/*	$Id: term.h,v 1.131 2019/01/04 03:21:02 schwarze Exp $ */
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2011-2015, 2017, 2019 Ingo Schwarze 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+enum	termenc {
+	TERMENC_ASCII,
+	TERMENC_LOCALE,
+	TERMENC_UTF8
+};
+
+enum	termtype {
+	TERMTYPE_CHAR,
+	TERMTYPE_PS,
+	TERMTYPE_PDF
+};
+
+enum	termfont {
+	TERMFONT_NONE = 0,
+	TERMFONT_BOLD,
+	TERMFONT_UNDER,
+	TERMFONT_BI,
+	TERMFONT__MAX
+};
+
+struct	eqn_box;
+struct	roff_meta;
+struct	roff_node;
+struct	tbl_span;
+struct	termp;
+
+typedef void	(*term_margin)(struct termp *, const struct roff_meta *);
+
+struct	termp_tbl {
+	int		  width;	/* width in fixed chars */
+	int		  decimal;	/* decimal point position */
+};
+
+struct	termp_col {
+	int		 *buf;		/* Output buffer. */
+	size_t		  maxcols;	/* Allocated bytes in buf. */
+	size_t		  lastcol;	/* Last byte in buf. */
+	size_t		  col;		/* Byte in buf to be written. */
+	size_t		  rmargin;	/* Current right margin. */
+	size_t		  offset;	/* Current left margin. */
+};
+
+struct	termp {
+	struct rofftbl	  tbl;		/* Table configuration. */
+	struct termp_col *tcols;	/* Array of table columns. */
+	struct termp_col *tcol;		/* Current table column. */
+	size_t		  maxtcol;	/* Allocated table columns. */
+	size_t		  lasttcol;	/* Last column currently used. */
+	size_t		  line;		/* Current output line number. */
+	size_t		  defindent;	/* Default indent for text. */
+	size_t		  defrmargin;	/* Right margin of the device. */
+	size_t		  lastrmargin;	/* Right margin before the last ll. */
+	size_t		  maxrmargin;	/* Max right margin. */
+	size_t		  col;		/* Byte position in buf. */
+	size_t		  viscol;	/* Chars on current line. */
+	size_t		  trailspace;	/* See term_flushln(). */
+	size_t		  minbl;	/* Minimum blanks before next field. */
+	int		  synopsisonly; /* Print the synopsis only. */
+	int		  mdocstyle;	/* Imitate mdoc(7) output. */
+	int		  ti;		/* Temporary indent for one line. */
+	int		  skipvsp;	/* Vertical space to skip. */
+	int		  flags;
+#define	TERMP_SENTENCE	 (1 << 0)	/* Space before a sentence. */
+#define	TERMP_NOSPACE	 (1 << 1)	/* No space before words. */
+#define	TERMP_NONOSPACE	 (1 << 2)	/* No space (no autounset). */
+#define	TERMP_NBRWORD	 (1 << 3)	/* Make next word nonbreaking. */
+#define	TERMP_KEEP	 (1 << 4)	/* Keep words together. */
+#define	TERMP_PREKEEP	 (1 << 5)	/* ...starting with the next one. */
+#define	TERMP_BACKAFTER	 (1 << 6)	/* Back up after next character. */
+#define	TERMP_BACKBEFORE (1 << 7)	/* Back up before next character. */
+#define	TERMP_NOBREAK	 (1 << 8)	/* See term_flushln(). */
+#define	TERMP_BRTRSP	 (1 << 9)	/* See term_flushln(). */
+#define	TERMP_BRIND	 (1 << 10)	/* See term_flushln(). */
+#define	TERMP_HANG	 (1 << 11)	/* See term_flushln(). */
+#define	TERMP_NOPAD	 (1 << 12)	/* See term_flushln(). */
+#define	TERMP_NOSPLIT	 (1 << 13)	/* Do not break line before .An. */
+#define	TERMP_SPLIT	 (1 << 14)	/* Break line before .An. */
+#define	TERMP_NONEWLINE	 (1 << 15)	/* No line break in nofill mode. */
+#define	TERMP_BRNEVER	 (1 << 16)	/* Don't even break at maxrmargin. */
+#define	TERMP_NOBUF	 (1 << 17)	/* Bypass output buffer. */
+#define	TERMP_NEWMC	 (1 << 18)	/* No .mc printed yet. */
+#define	TERMP_ENDMC	 (1 << 19)	/* Next break ends .mc mode. */
+#define	TERMP_MULTICOL	 (1 << 20)	/* Multiple column mode. */
+#define	TERMP_CENTER	 (1 << 21)	/* Center output lines. */
+#define	TERMP_RIGHT	 (1 << 22)	/* Adjust to the right margin. */
+	enum termtype	  type;		/* Terminal, PS, or PDF. */
+	enum termenc	  enc;		/* Type of encoding. */
+	enum termfont	  fontl;	/* Last font set. */
+	enum termfont	 *fontq;	/* Symmetric fonts. */
+	int		  fontsz;	/* Allocated size of font stack */
+	int		  fonti;	/* Index of font stack. */
+	term_margin	  headf;	/* invoked to print head */
+	term_margin	  footf;	/* invoked to print foot */
+	void		(*letter)(struct termp *, int);
+	void		(*begin)(struct termp *);
+	void		(*end)(struct termp *);
+	void		(*endline)(struct termp *);
+	void		(*advance)(struct termp *, size_t);
+	void		(*setwidth)(struct termp *, int, int);
+	size_t		(*width)(const struct termp *, int);
+	int		(*hspan)(const struct termp *,
+				const struct roffsu *);
+	const void	 *argf;		/* arg for headf/footf */
+	const char	 *mc;		/* Margin character. */
+	struct termp_ps	 *ps;
+};
+
+
+const char	 *ascii_uc2str(int);
+
+void		  roff_term_pre(struct termp *, const struct roff_node *);
+
+void		  term_eqn(struct termp *, const struct eqn_box *);
+void		  term_tbl(struct termp *, const struct tbl_span *);
+void		  term_free(struct termp *);
+void		  term_setcol(struct termp *, size_t);
+void		  term_newln(struct termp *);
+void		  term_vspace(struct termp *);
+void		  term_word(struct termp *, const char *);
+void		  term_flushln(struct termp *);
+void		  term_begin(struct termp *, term_margin,
+			term_margin, const struct roff_meta *);
+void		  term_end(struct termp *);
+
+void		  term_setwidth(struct termp *, const char *);
+int		  term_hspan(const struct termp *, const struct roffsu *);
+int		  term_hen(const struct termp *, const struct roffsu *);
+int		  term_vspan(const struct termp *, const struct roffsu *);
+size_t		  term_strlen(const struct termp *, const char *);
+size_t		  term_len(const struct termp *, size_t);
+
+void		  term_tab_set(const struct termp *, const char *);
+void		  term_tab_iset(size_t);
+size_t		  term_tab_next(size_t);
+
+void		  term_fontpush(struct termp *, enum termfont);
+void		  term_fontpop(struct termp *);
+void		  term_fontpopq(struct termp *, int);
+void		  term_fontrepl(struct termp *, enum termfont);
+void		  term_fontlast(struct termp *);

Property changes on: vendor/mandoc/20190723/term.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: vendor/mandoc/20190723/term_ascii.c
===================================================================
--- vendor/mandoc/20190723/term_ascii.c	(nonexistent)
+++ vendor/mandoc/20190723/term_ascii.c	(revision 350350)
@@ -0,0 +1,404 @@
+/*	$Id: term_ascii.c,v 1.64 2018/11/28 14:23:06 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 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 
+#if HAVE_WCHAR
+#include 
+#include 
+#endif
+#include 
+#include 
+#include 
+#include 
+#include 
+#if HAVE_WCHAR
+#include 
+#endif
+
+#include "mandoc.h"
+#include "mandoc_aux.h"
+#include "out.h"
+#include "term.h"
+#include "manconf.h"
+#include "main.h"
+
+static	struct termp	 *ascii_init(enum termenc, const struct manoutput *);
+static	int		  ascii_hspan(const struct termp *,
+				const struct roffsu *);
+static	size_t		  ascii_width(const struct termp *, int);
+static	void		  ascii_advance(struct termp *, size_t);
+static	void		  ascii_begin(struct termp *);
+static	void		  ascii_end(struct termp *);
+static	void		  ascii_endline(struct termp *);
+static	void		  ascii_letter(struct termp *, int);
+static	void		  ascii_setwidth(struct termp *, int, int);
+
+#if HAVE_WCHAR
+static	void		  locale_advance(struct termp *, size_t);
+static	void		  locale_endline(struct termp *);
+static	void		  locale_letter(struct termp *, int);
+static	size_t		  locale_width(const struct termp *, int);
+#endif
+
+
+static struct termp *
+ascii_init(enum termenc enc, const struct manoutput *outopts)
+{
+#if HAVE_WCHAR
+	char		*v;
+#endif
+	struct termp	*p;
+
+	p = mandoc_calloc(1, sizeof(*p));
+	p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
+	p->maxtcol = 1;
+
+	p->line = 1;
+	p->defrmargin = p->lastrmargin = 78;
+	p->fontq = mandoc_reallocarray(NULL,
+	     (p->fontsz = 8), sizeof(*p->fontq));
+	p->fontq[0] = p->fontl = TERMFONT_NONE;
+
+	p->begin = ascii_begin;
+	p->end = ascii_end;
+	p->hspan = ascii_hspan;
+	p->type = TERMTYPE_CHAR;
+
+	p->enc = TERMENC_ASCII;
+	p->advance = ascii_advance;
+	p->endline = ascii_endline;
+	p->letter = ascii_letter;
+	p->setwidth = ascii_setwidth;
+	p->width = ascii_width;
+
+#if HAVE_WCHAR
+	if (enc != TERMENC_ASCII) {
+
+		/*
+		 * Do not change any of this to LC_ALL.  It might break
+		 * the formatting by subtly changing the behaviour of
+		 * various functions, for example strftime(3).  As a
+		 * worst case, it might even cause buffer overflows.
+		 */
+
+		v = enc == TERMENC_LOCALE ?
+		    setlocale(LC_CTYPE, "") :
+		    setlocale(LC_CTYPE, UTF8_LOCALE);
+
+		/*
+		 * We only support UTF-8,
+		 * so revert to ASCII for anything else.
+		 */
+
+		if (v != NULL &&
+		    strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
+			v = setlocale(LC_CTYPE, "C");
+
+		if (v != NULL && MB_CUR_MAX > 1) {
+			p->enc = TERMENC_UTF8;
+			p->advance = locale_advance;
+			p->endline = locale_endline;
+			p->letter = locale_letter;
+			p->width = locale_width;
+		}
+	}
+#endif
+
+	if (outopts->mdoc) {
+		p->mdocstyle = 1;
+		p->defindent = 5;
+	}
+	if (outopts->indent)
+		p->defindent = outopts->indent;
+	if (outopts->width)
+		p->defrmargin = outopts->width;
+	if (outopts->synopsisonly)
+		p->synopsisonly = 1;
+
+	assert(p->defindent < UINT16_MAX);
+	assert(p->defrmargin < UINT16_MAX);
+	return p;
+}
+
+void *
+ascii_alloc(const struct manoutput *outopts)
+{
+
+	return ascii_init(TERMENC_ASCII, outopts);
+}
+
+void *
+utf8_alloc(const struct manoutput *outopts)
+{
+
+	return ascii_init(TERMENC_UTF8, outopts);
+}
+
+void *
+locale_alloc(const struct manoutput *outopts)
+{
+
+	return ascii_init(TERMENC_LOCALE, outopts);
+}
+
+static void
+ascii_setwidth(struct termp *p, int iop, int width)
+{
+
+	width /= 24;
+	p->tcol->rmargin = p->defrmargin;
+	if (iop > 0)
+		p->defrmargin += width;
+	else if (iop == 0)
+		p->defrmargin = width ? (size_t)width : p->lastrmargin;
+	else if (p->defrmargin > (size_t)width)
+		p->defrmargin -= width;
+	else
+		p->defrmargin = 0;
+	if (p->defrmargin > 1000)
+		p->defrmargin = 1000;
+	p->lastrmargin = p->tcol->rmargin;
+	p->tcol->rmargin = p->maxrmargin = p->defrmargin;
+}
+
+void
+terminal_sepline(void *arg)
+{
+	struct termp	*p;
+	size_t		 i;
+
+	p = (struct termp *)arg;
+	(*p->endline)(p);
+	for (i = 0; i < p->defrmargin; i++)
+		(*p->letter)(p, '-');
+	(*p->endline)(p);
+	(*p->endline)(p);
+}
+
+static size_t
+ascii_width(const struct termp *p, int c)
+{
+	return c != ASCII_BREAK;
+}
+
+void
+ascii_free(void *arg)
+{
+
+	term_free((struct termp *)arg);
+}
+
+static void
+ascii_letter(struct termp *p, int c)
+{
+
+	putchar(c);
+}
+
+static void
+ascii_begin(struct termp *p)
+{
+
+	(*p->headf)(p, p->argf);
+}
+
+static void
+ascii_end(struct termp *p)
+{
+
+	(*p->footf)(p, p->argf);
+}
+
+static void
+ascii_endline(struct termp *p)
+{
+
+	p->line++;
+	p->tcol->offset -= p->ti;
+	p->ti = 0;
+	putchar('\n');
+}
+
+static void
+ascii_advance(struct termp *p, size_t len)
+{
+	size_t		i;
+
+	assert(len < UINT16_MAX);
+	for (i = 0; i < len; i++)
+		putchar(' ');
+}
+
+static int
+ascii_hspan(const struct termp *p, const struct roffsu *su)
+{
+	double		 r;
+
+	switch (su->unit) {
+	case SCALE_BU:
+		r = su->scale;
+		break;
+	case SCALE_CM:
+		r = su->scale * 240.0 / 2.54;
+		break;
+	case SCALE_FS:
+		r = su->scale * 65536.0;
+		break;
+	case SCALE_IN:
+		r = su->scale * 240.0;
+		break;
+	case SCALE_MM:
+		r = su->scale * 0.24;
+		break;
+	case SCALE_VS:
+	case SCALE_PC:
+		r = su->scale * 40.0;
+		break;
+	case SCALE_PT:
+		r = su->scale * 10.0 / 3.0;
+		break;
+	case SCALE_EN:
+	case SCALE_EM:
+		r = su->scale * 24.0;
+		break;
+	default:
+		abort();
+	}
+	return r > 0.0 ? r + 0.01 : r - 0.01;
+}
+
+const char *
+ascii_uc2str(int uc)
+{
+	static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
+	static const char *tab[] = {
+	"","","","","","","","",
+	"",	"\t",	"",	"",	"",	"",	"",	"",
+	"","","","","","","","",
+	"","",	"","","",	"",	"",	"",
+	" ",	"!",	"\"",	"#",	"$",	"%",	"&",	"'",
+	"(",	")",	"*",	"+",	",",	"-",	".",	"/",
+	"0",	"1",	"2",	"3",	"4",	"5",	"6",	"7",
+	"8",	"9",	":",	";",	"<",	"=",	">",	"?",
+	"@",	"A",	"B",	"C",	"D",	"E",	"F",	"G",
+	"H",	"I",	"J",	"K",	"L",	"M",	"N",	"O",
+	"P",	"Q",	"R",	"S",	"T",	"U",	"V",	"W",
+	"X",	"Y",	"Z",	"[",	"\\",	"]",	"^",	"_",
+	"`",	"a",	"b",	"c",	"d",	"e",	"f",	"g",
+	"h",	"i",	"j",	"k",	"l",	"m",	"n",	"o",
+	"p",	"q",	"r",	"s",	"t",	"u",	"v",	"w",
+	"x",	"y",	"z",	"{",	"|",	"}",	"~",	"",
+	"<80>",	"<81>",	"<82>",	"<83>",	"<84>",	"<85>",	"<86>",	"<87>",
+	"<88>",	"<89>",	"<8A>",	"<8B>",	"<8C>",	"<8D>",	"<8E>",	"<8F>",
+	"<90>",	"<91>",	"<92>",	"<93>",	"<94>",	"<95>",	"<96>",	"<97>",
+	"<98>",	"<99>",	"<9A>",	"<9B>",	"<9C>",	"<9D>",	"<9E>",	"<9F>",
+	nbrsp,	"!",	"/\bc",	"-\bL",	"o\bx",	"=\bY",	"|",	"
", + "\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-", + "","+-","^2", "^3", "'","","",".", + ",", "^1", "_\bo", ">>", "1/4", "1/2", "3/4", "?", + "`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC", + "`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI", + "Dh", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x", + "/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss", + "`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc", + "`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi", + "dh", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","/", + "/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by", + "A", "a", "A", "a", "A", "a", "'\bC", "'\bc", + "^\bC", "^\bc", "C", "c", "C", "c", "D", "d", + "/\bD", "/\bd", "E", "e", "E", "e", "E", "e", + "E", "e", "E", "e", "^\bG", "^\bg", "G", "g", + "G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh", + "~\bI", "~\bi", "I", "i", "I", "i", "I", "i", + "I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk", + "q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L", + "l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N", + "n", "'n", "Ng", "ng", "O", "o", "O", "o", + "O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br", + "R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs", + "S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt", + "~\bU", "~\bu", "U", "u", "U", "u", "U", "u", + "U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by", + "\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s", + "b", "B", "B", "b", "6", "6", "O", "C", + "c", "D", "D", "D", "d", "d", "3", "@", + "E", "F", ",\bf", "G", "G", "hv", "I", "/\bI", + "K", "k", "/\bl", "l", "W", "N", "n", "~\bO", + "O", "o", "OI", "oi", "P", "p", "YR", "2", + "2", "SH", "sh", "t", "T", "t", "T", "U", + "u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH", + "ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w", + "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ", + "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I", + "i", "O", "o", "U", "u", "U", "u", "U", + "u", "U", "u", "U", "u", "@", "A", "a", + "A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g", + "K", "k", "O", "o", "O", "o", "ZH", "zh", + "j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W", + "`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"}; + + assert(uc >= 0); + if ((size_t)uc < sizeof(tab)/sizeof(tab[0])) + return tab[uc]; + return mchars_uc2str(uc); +} + +#if HAVE_WCHAR +static size_t +locale_width(const struct termp *p, int c) +{ + int rc; + + if (c == ASCII_NBRSP) + c = ' '; + rc = wcwidth(c); + if (rc < 0) + rc = 0; + return rc; +} + +static void +locale_advance(struct termp *p, size_t len) +{ + size_t i; + + assert(len < UINT16_MAX); + for (i = 0; i < len; i++) + putwchar(L' '); +} + +static void +locale_endline(struct termp *p) +{ + + p->line++; + p->tcol->offset -= p->ti; + p->ti = 0; + putwchar(L'\n'); +} + +static void +locale_letter(struct termp *p, int c) +{ + + putwchar(c); +} +#endif Property changes on: vendor/mandoc/20190723/term_ascii.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/term_tab.c =================================================================== --- vendor/mandoc/20190723/term_tab.c (nonexistent) +++ vendor/mandoc/20190723/term_tab.c (revision 350350) @@ -0,0 +1,128 @@ +/* $Id: term_tab.c,v 1.5 2018/12/16 00:21:05 schwarze Exp $ */ +/* + * Copyright (c) 2017 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include + +#include + +#include "mandoc_aux.h" +#include "out.h" +#include "term.h" + +struct tablist { + size_t *t; /* Allocated array of tab positions. */ + size_t s; /* Allocated number of positions. */ + size_t n; /* Currently used number of positions. */ +}; + +static struct { + struct tablist a; /* All tab positions for lookup. */ + struct tablist p; /* Periodic tab positions to add. */ + size_t d; /* Default tab width in units of n. */ +} tabs; + + +void +term_tab_set(const struct termp *p, const char *arg) +{ + static int recording_period; + + struct roffsu su; + struct tablist *tl; + size_t pos; + int add; + + /* Special arguments: clear all tabs or switch lists. */ + + if (arg == NULL) { + tabs.a.n = tabs.p.n = 0; + recording_period = 0; + if (tabs.d == 0) { + a2roffsu(".8i", &su, SCALE_IN); + tabs.d = term_hen(p, &su); + } + return; + } + if (arg[0] == 'T' && arg[1] == '\0') { + recording_period = 1; + return; + } + + /* Parse the sign, the number, and the unit. */ + + if (*arg == '+') { + add = 1; + arg++; + } else + add = 0; + if (a2roffsu(arg, &su, SCALE_EM) == NULL) + return; + + /* Select the list, and extend it if it is full. */ + + tl = recording_period ? &tabs.p : &tabs.a; + if (tl->n >= tl->s) { + tl->s += 8; + tl->t = mandoc_reallocarray(tl->t, tl->s, sizeof(*tl->t)); + } + + /* Append the new position. */ + + pos = term_hen(p, &su); + tl->t[tl->n] = pos; + if (add && tl->n) + tl->t[tl->n] += tl->t[tl->n - 1]; + tl->n++; +} + +/* + * Simplified version without a parser, + * never incremental, never periodic, for use by tbl(7). + */ +void +term_tab_iset(size_t inc) +{ + if (tabs.a.n >= tabs.a.s) { + tabs.a.s += 8; + tabs.a.t = mandoc_reallocarray(tabs.a.t, tabs.a.s, + sizeof(*tabs.a.t)); + } + tabs.a.t[tabs.a.n++] = inc; +} + +size_t +term_tab_next(size_t prev) +{ + size_t i, j; + + for (i = 0;; i++) { + if (i == tabs.a.n) { + if (tabs.p.n == 0) + return prev; + tabs.a.n += tabs.p.n; + if (tabs.a.s < tabs.a.n) { + tabs.a.s = tabs.a.n; + tabs.a.t = mandoc_reallocarray(tabs.a.t, + tabs.a.s, sizeof(*tabs.a.t)); + } + for (j = 0; j < tabs.p.n; j++) + tabs.a.t[i + j] = tabs.p.t[j] + + (i ? tabs.a.t[i - 1] : 0); + } + if (prev < tabs.a.t[i]) + return tabs.a.t[i]; + } +} Property changes on: vendor/mandoc/20190723/term_tab.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-getsubopt.c =================================================================== --- vendor/mandoc/20190723/test-getsubopt.c (nonexistent) +++ vendor/mandoc/20190723/test-getsubopt.c (revision 350350) @@ -0,0 +1,37 @@ +/* $Id: test-getsubopt.c,v 1.6 2018/08/15 14:37:41 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +/* + * NetBSD declared this function in the wrong header before August 2018. + * No harm is done by allowing that, too: + * The only file using it, main.c, also includes unistd.h, anyway. + */ +#include + +int +main(void) +{ + char buf[] = "k=v"; + char *options = buf; + char token0[] = "k"; + char *const tokens[] = { token0, NULL }; + char *value = NULL; + return ! (getsubopt(&options, tokens, &value) == 0 + && value == buf+2 && options == buf+3); +} Property changes on: vendor/mandoc/20190723/test-getsubopt.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-strcasestr.c =================================================================== --- vendor/mandoc/20190723/test-strcasestr.c (nonexistent) +++ vendor/mandoc/20190723/test-strcasestr.c (revision 350350) @@ -0,0 +1,9 @@ +#include + +int +main(void) +{ + const char *big = "BigString"; + char *cp = strcasestr(big, "Gst"); + return cp != big + 2; +} Property changes on: vendor/mandoc/20190723/test-strcasestr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-stringlist.c =================================================================== --- vendor/mandoc/20190723/test-stringlist.c (nonexistent) +++ vendor/mandoc/20190723/test-stringlist.c (revision 350350) @@ -0,0 +1,38 @@ +/* $Id: test-stringlist.c,v 1.3 2018/08/15 02:48:51 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +int +main(void) +{ + StringList *sl; + char teststr[] = "test"; + + if ((sl = sl_init()) == NULL) + return 1; + if (sl_add(sl, teststr)) + return 2; + if (sl->sl_cur != 1) + return 3; + if (sl->sl_str[0] != teststr) + return 4; + + sl_free(sl, 0); + return 0; +} Property changes on: vendor/mandoc/20190723/test-stringlist.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-strptime.c =================================================================== --- vendor/mandoc/20190723/test-strptime.c (nonexistent) +++ vendor/mandoc/20190723/test-strptime.c (revision 350350) @@ -0,0 +1,10 @@ +#include + +int +main(void) +{ + struct tm tm; + const char input[] = "2014-01-04"; + return ! (strptime(input, "%Y-%m-%d", &tm) == input + 10 && + tm.tm_year == 114 && tm.tm_mon == 0 && tm.tm_mday == 4); +} Property changes on: vendor/mandoc/20190723/test-strptime.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-vasprintf.c =================================================================== --- vendor/mandoc/20190723/test-vasprintf.c (nonexistent) +++ vendor/mandoc/20190723/test-vasprintf.c (revision 350350) @@ -0,0 +1,48 @@ +/* $Id: test-vasprintf.c,v 1.5 2018/08/15 02:15:52 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +static int testfunc(char **, const char *, ...); + + +static int +testfunc(char **ret, const char *format, ...) +{ + va_list ap; + int irc; + + va_start(ap, format); + irc = vasprintf(ret, format, ap); + va_end(ap); + + return irc; +} + +int +main(void) +{ + char *ret; + + if (testfunc(&ret, "%s.", "Text") != 5) + return 1; + if (strcmp(ret, "Text.")) + return 2; + return 0; +} Property changes on: vendor/mandoc/20190723/test-vasprintf.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-wchar.c =================================================================== --- vendor/mandoc/20190723/test-wchar.c (nonexistent) +++ vendor/mandoc/20190723/test-wchar.c (revision 350350) @@ -0,0 +1,59 @@ +/* $Id: test-wchar.c,v 1.5 2018/08/15 02:15:52 schwarze Exp $ */ +/* + * Copyright (c) 2014 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +int +main(void) +{ + wchar_t wc; + int width; + + if (setlocale(LC_ALL, "") == NULL) { + fputs("setlocale(LC_ALL, \"\") failed\n", stderr); + return 1; + } + + if (setlocale(LC_CTYPE, UTF8_LOCALE) == NULL) { + fprintf(stderr, "setlocale(LC_CTYPE, \"%s\") failed\n", + UTF8_LOCALE); + return 1; + } + + if (sizeof(wchar_t) < 4) { + fprintf(stderr, "wchar_t is only %zu bytes\n", + sizeof(wchar_t)); + return 1; + } + + if ((width = wcwidth(L' ')) != 1) { + fprintf(stderr, "wcwidth(L' ') returned %d\n", width); + return 1; + } + + dup2(STDERR_FILENO, STDOUT_FILENO); + wc = L'*'; + if (putwchar(wc) != (wint_t)wc) { + fputs("bad putwchar return value\n", stderr); + return 1; + } + + return 0; +} Property changes on: vendor/mandoc/20190723/test-wchar.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/tree.c =================================================================== --- vendor/mandoc/20190723/tree.c (nonexistent) +++ vendor/mandoc/20190723/tree.c (revision 350350) @@ -0,0 +1,425 @@ +/* $Id: tree.c,v 1.84 2019/01/01 05:56:34 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons + * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "man.h" +#include "tbl.h" +#include "eqn.h" +#include "main.h" + +static void print_box(const struct eqn_box *, int); +static void print_man(const struct roff_node *, int); +static void print_meta(const struct roff_meta *); +static void print_mdoc(const struct roff_node *, int); +static void print_span(const struct tbl_span *, int); + + +void +tree_mdoc(void *arg, const struct roff_meta *mdoc) +{ + print_meta(mdoc); + putchar('\n'); + print_mdoc(mdoc->first->child, 0); +} + +void +tree_man(void *arg, const struct roff_meta *man) +{ + print_meta(man); + if (man->hasbody == 0) + puts("body = empty"); + putchar('\n'); + print_man(man->first->child, 0); +} + +static void +print_meta(const struct roff_meta *meta) +{ + if (meta->title != NULL) + printf("title = \"%s\"\n", meta->title); + if (meta->name != NULL) + printf("name = \"%s\"\n", meta->name); + if (meta->msec != NULL) + printf("sec = \"%s\"\n", meta->msec); + if (meta->vol != NULL) + printf("vol = \"%s\"\n", meta->vol); + if (meta->arch != NULL) + printf("arch = \"%s\"\n", meta->arch); + if (meta->os != NULL) + printf("os = \"%s\"\n", meta->os); + if (meta->date != NULL) + printf("date = \"%s\"\n", meta->date); +} + +static void +print_mdoc(const struct roff_node *n, int indent) +{ + const char *p, *t; + int i, j; + size_t argc; + struct mdoc_argv *argv; + + if (n == NULL) + return; + + argv = NULL; + argc = 0; + t = p = NULL; + + switch (n->type) { + case ROFFT_ROOT: + t = "root"; + break; + case ROFFT_BLOCK: + t = "block"; + break; + case ROFFT_HEAD: + t = "head"; + break; + case ROFFT_BODY: + if (n->end) + t = "body-end"; + else + t = "body"; + break; + case ROFFT_TAIL: + t = "tail"; + break; + case ROFFT_ELEM: + t = "elem"; + break; + case ROFFT_TEXT: + t = "text"; + break; + case ROFFT_COMMENT: + t = "comment"; + break; + case ROFFT_TBL: + break; + case ROFFT_EQN: + t = "eqn"; + break; + default: + abort(); + } + + switch (n->type) { + case ROFFT_TEXT: + case ROFFT_COMMENT: + p = n->string; + break; + case ROFFT_BODY: + p = roff_name[n->tok]; + break; + case ROFFT_HEAD: + p = roff_name[n->tok]; + break; + case ROFFT_TAIL: + p = roff_name[n->tok]; + break; + case ROFFT_ELEM: + p = roff_name[n->tok]; + if (n->args) { + argv = n->args->argv; + argc = n->args->argc; + } + break; + case ROFFT_BLOCK: + p = roff_name[n->tok]; + if (n->args) { + argv = n->args->argv; + argc = n->args->argc; + } + break; + case ROFFT_TBL: + break; + case ROFFT_EQN: + p = "EQ"; + break; + case ROFFT_ROOT: + p = "root"; + break; + default: + abort(); + } + + if (n->span) { + assert(NULL == p && NULL == t); + print_span(n->span, indent); + } else { + for (i = 0; i < indent; i++) + putchar(' '); + + printf("%s (%s)", p, t); + + for (i = 0; i < (int)argc; i++) { + printf(" -%s", mdoc_argnames[argv[i].arg]); + if (argv[i].sz > 0) + printf(" ["); + for (j = 0; j < (int)argv[i].sz; j++) + printf(" [%s]", argv[i].value[j]); + if (argv[i].sz > 0) + printf(" ]"); + } + + putchar(' '); + if (n->flags & NODE_DELIMO) + putchar('('); + if (n->flags & NODE_LINE) + putchar('*'); + printf("%d:%d", n->line, n->pos + 1); + if (n->flags & NODE_DELIMC) + putchar(')'); + if (n->flags & NODE_EOS) + putchar('.'); + if (n->flags & NODE_BROKEN) + printf(" BROKEN"); + if (n->flags & NODE_NOFILL) + printf(" NOFILL"); + if (n->flags & NODE_NOSRC) + printf(" NOSRC"); + if (n->flags & NODE_NOPRT) + printf(" NOPRT"); + putchar('\n'); + } + + if (n->eqn) + print_box(n->eqn->first, indent + 4); + if (n->child) + print_mdoc(n->child, indent + + (n->type == ROFFT_BLOCK ? 2 : 4)); + if (n->next) + print_mdoc(n->next, indent); +} + +static void +print_man(const struct roff_node *n, int indent) +{ + const char *p, *t; + int i; + + if (n == NULL) + return; + + t = p = NULL; + + switch (n->type) { + case ROFFT_ROOT: + t = "root"; + break; + case ROFFT_ELEM: + t = "elem"; + break; + case ROFFT_TEXT: + t = "text"; + break; + case ROFFT_COMMENT: + t = "comment"; + break; + case ROFFT_BLOCK: + t = "block"; + break; + case ROFFT_HEAD: + t = "head"; + break; + case ROFFT_BODY: + t = "body"; + break; + case ROFFT_TBL: + break; + case ROFFT_EQN: + t = "eqn"; + break; + default: + abort(); + } + + switch (n->type) { + case ROFFT_TEXT: + case ROFFT_COMMENT: + p = n->string; + break; + case ROFFT_ELEM: + case ROFFT_BLOCK: + case ROFFT_HEAD: + case ROFFT_BODY: + p = roff_name[n->tok]; + break; + case ROFFT_ROOT: + p = "root"; + break; + case ROFFT_TBL: + break; + case ROFFT_EQN: + p = "EQ"; + break; + default: + abort(); + } + + if (n->span) { + assert(NULL == p && NULL == t); + print_span(n->span, indent); + } else { + for (i = 0; i < indent; i++) + putchar(' '); + printf("%s (%s) ", p, t); + if (n->flags & NODE_LINE) + putchar('*'); + printf("%d:%d", n->line, n->pos + 1); + if (n->flags & NODE_DELIMC) + putchar(')'); + if (n->flags & NODE_EOS) + putchar('.'); + if (n->flags & NODE_NOFILL) + printf(" NOFILL"); + putchar('\n'); + } + + if (n->eqn) + print_box(n->eqn->first, indent + 4); + if (n->child) + print_man(n->child, indent + + (n->type == ROFFT_BLOCK ? 2 : 4)); + if (n->next) + print_man(n->next, indent); +} + +static void +print_box(const struct eqn_box *ep, int indent) +{ + int i; + const char *t; + + static const char *posnames[] = { + NULL, "sup", "subsup", "sub", + "to", "from", "fromto", + "over", "sqrt", NULL }; + + if (NULL == ep) + return; + for (i = 0; i < indent; i++) + putchar(' '); + + t = NULL; + switch (ep->type) { + case EQN_LIST: + t = "eqn-list"; + break; + case EQN_SUBEXPR: + t = "eqn-expr"; + break; + case EQN_TEXT: + t = "eqn-text"; + break; + case EQN_PILE: + t = "eqn-pile"; + break; + case EQN_MATRIX: + t = "eqn-matrix"; + break; + } + + fputs(t, stdout); + if (ep->pos) + printf(" pos=%s", posnames[ep->pos]); + if (ep->left) + printf(" left=\"%s\"", ep->left); + if (ep->right) + printf(" right=\"%s\"", ep->right); + if (ep->top) + printf(" top=\"%s\"", ep->top); + if (ep->bottom) + printf(" bottom=\"%s\"", ep->bottom); + if (ep->text) + printf(" text=\"%s\"", ep->text); + if (ep->font) + printf(" font=%d", ep->font); + if (ep->size != EQN_DEFSIZE) + printf(" size=%d", ep->size); + if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args) + printf(" badargs=%zu(%zu)", ep->args, ep->expectargs); + else if (ep->args) + printf(" args=%zu", ep->args); + putchar('\n'); + + print_box(ep->first, indent + 4); + print_box(ep->next, indent); +} + +static void +print_span(const struct tbl_span *sp, int indent) +{ + const struct tbl_dat *dp; + int i; + + for (i = 0; i < indent; i++) + putchar(' '); + + switch (sp->pos) { + case TBL_SPAN_HORIZ: + putchar('-'); + putchar(' '); + break; + case TBL_SPAN_DHORIZ: + putchar('='); + putchar(' '); + break; + default: + for (dp = sp->first; dp; dp = dp->next) { + switch (dp->pos) { + case TBL_DATA_HORIZ: + case TBL_DATA_NHORIZ: + putchar('-'); + putchar(' '); + continue; + case TBL_DATA_DHORIZ: + case TBL_DATA_NDHORIZ: + putchar('='); + putchar(' '); + continue; + default: + break; + } + printf("[\"%s\"", dp->string ? dp->string : ""); + if (dp->hspans) + printf(">%d", dp->hspans); + if (dp->vspans) + printf("v%d", dp->vspans); + if (dp->layout == NULL) + putchar('*'); + else if (dp->layout->pos == TBL_CELL_DOWN) + putchar('^'); + putchar(']'); + putchar(' '); + } + break; + } + printf("(tbl) %d:1\n", sp->line); +} Property changes on: vendor/mandoc/20190723/tree.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_strndup.c =================================================================== --- vendor/mandoc/20190723/compat_strndup.c (nonexistent) +++ vendor/mandoc/20190723/compat_strndup.c (revision 350350) @@ -0,0 +1,50 @@ +#include "config.h" + +#if HAVE_STRNDUP + +int dummy; + +#else + +/* $Id: compat_strndup.c,v 1.1 2018/02/27 11:16:23 schwarze Exp $ */ +/* OpenBSD: strndup.c,v 1.2 2015/08/31 02:53:57 guenther Exp */ +/* + * Copyright (c) 2010 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +char * +strndup(const char *str, size_t maxlen) +{ + char *copy; + size_t len; + + for (len = 0; len < maxlen && str[len] != '\0'; len++) + continue; + + copy = malloc(len + 1); + if (copy != NULL) { + (void)memcpy(copy, str, len); + copy[len] = '\0'; + } + + return copy; +} + +#endif Property changes on: vendor/mandoc/20190723/compat_strndup.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/man.cgi.8 =================================================================== --- vendor/mandoc/20190723/man.cgi.8 (nonexistent) +++ vendor/mandoc/20190723/man.cgi.8 (revision 350350) @@ -0,0 +1,426 @@ +.\" $Id: man.cgi.8,v 1.23 2018/05/20 21:48:44 schwarze Exp $ +.\" +.\" Copyright (c) 2014, 2015, 2016 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: May 20 2018 $ +.Dt MAN.CGI 8 +.Os +.Sh NAME +.Nm man.cgi +.Nd CGI program to search and display manual pages +.Sh DESCRIPTION +The +.Nm +CGI program searches for manual pages on a WWW server +and displays them to HTTP clients, +providing functionality equivalent to the +.Xr man 1 +and +.Xr apropos 1 +utilities. +It can use multiple manual trees in parallel. +.Ss HTML search interface +At the top of each generated HTML page, +.Nm +displays a search form containing these elements: +.Bl -enum +.It +An input box for search queries, expecting +either a name of a manual page or an +.Ar expression +using the syntax described in the +.Xr apropos 1 +manual; filling this in is required for each search. +.Pp +The expression is broken into words at whitespace. +Whitespace characters and backslashes can be escaped +by prepending a backslash. +The effect of prepending a backslash to another character is undefined; +in the current implementation, it has no effect. +.It +A +.Xr man 1 +submit button. +The string in the input box is interpreted as the name of a manual page. +.It +An +.Xr apropos 1 +submit button. +The string in the input box is interpreted as a search +.Ar expression . +.It +A dropdown menu to optionally select a manual section. +If one is provided, it has the same effect as the +.Xr man 1 +and +.Xr apropos 1 +.Fl s +option. +Otherwise, pages from all sections are shown. +.It +A dropdown menu to optionally select an architecture. +If one is provided, it has the same effect as the +.Xr man 1 +and +.Xr apropos 1 +.Fl S +option. +By default, pages for all architectures are shown. +.It +A dropdown menu to select a manual tree. +If the configuration file +.Pa /var/www/man/manpath.conf +contains only one manpath, the dropdown menu is not shown. +By default, the first manpath given in the file is used. +.El +.Ss Program output +The +.Nm +program generates five kinds of output pages: +.Bl -tag -width Ds +.It The index page. +This is returned when calling +.Nm +without +.Ev PATH_INFO +and without a +.Ev QUERY_STRING . +It serves as a starting point for using the program +and shows the search form only. +.It A list page. +Lists are returned when searches match more than one manual page. +The first column shows the names and section numbers of manuals +as clickable links. +The second column shows the one-line descriptions of the manuals. +For +.Xr man 1 +style searches, the content of the first manual page follows the list. +.It A manual page. +This output format is used when a search matches exactly one +manual page, or when a link on a list page or an +.Ic \&Xr +link on another manual page is followed. +.It A no-result page. +This is shown when a search request returns no results - +either because it violates the query syntax, or because +the search does not match any manual pages. +.It \&An error page. +This cannot happen by merely clicking the +.Dq Search +button, but only by manually entering an invalid URI. +It does not show the search form, but only an error message +and a link back to the index page. +.El +.Ss Setup +For each manual tree, create one first-level subdirectory below +.Pa /var/www/man . +The name of one of these directories is called a +.Dq manpath +in the context of +.Nm . +Create a single ASCII text file +.Pa /var/www/man/manpath.conf +containing the names of these directories, one per line. +The directory given first is used as the default manpath. +.Pp +Inside each of these directories, use the same directory and file +structure as found below +.Pa /usr/share/man , +that is, second-level subdirectories +.Pa /var/www/man/*/man1 , /var/www/man/*/man2 +etc. containing source +.Xr mdoc 7 +and +.Xr man 7 +manuals with file name extensions matching the section numbers, +second-level subdirectories +.Pa /var/www/man/*/cat1 , /var/www/man/*/cat2 +etc. containing preformatted manuals with the file name extension +.Sq 0 , +and optional third-level subdirectories for architectures. +Use +.Xr makewhatis 8 +to create a +.Xr mandoc.db 5 +database inside each manpath. +.Pp +Configure your web server to execute CGI programs located in +.Pa /cgi-bin . +When using +.Ox +.Xr httpd 8 , +the +.Xr slowcgi 8 +proxy daemon is needed to translate FastCGI requests to plain old CGI. +.Pp +To compile +.Nm , +first copy +.Pa cgi.h.example +to +.Pa cgi.h +and edit it according to your needs. +It contains the following compile-time definitions: +.Bl -tag -width Ds +.It Ev COMPAT_OLDURI +Only useful for running on www.openbsd.org to deal with old URIs containing +.Qq "manpath=OpenBSD " +where the blank character has to be translated to a hyphen. +When compiling for other sites, this definition can be deleted. +.It Dv CSS_DIR +An optional file system path to the directory containing the file +.Pa mandoc.css , +to be specified relative to the server's document root, +and to be specified without a trailing slash. +When empty, the CSS file is assumed to be in the document root. +Otherwise, a leading slash is needed. +This is used in generated HTML code. +.It Dv CUSTOMIZE_TITLE +An ASCII string to be used for the HTML element. +.It Dv MAN_DIR +A file system path to the +.Nm +data directory relative to the web server +.Xr chroot 2 +directory, to be specified with a leading slash and without a trailing slash. +It needs to have at least one component; the root directory cannot be used +for this purpose. +The files +.Pa manpath.conf , +.Pa header.html , +and +.Pa footer.html +are looked up in this directory. +It is also prepended to the manpath when opening +.Xr mandoc.db 5 +and manual page files. +.It Dv SCRIPT_NAME +The initial component of URIs, to be specified without leading +and trailing slashes. +It can be empty. +.El +.Pp +After editing +.Pa cgi.h , +run +.Pp +.Dl make man.cgi +.Pp +and copy the resulting binary to the proper location, +for example using the command: +.Pp +.Dl make installcgi +.Pp +In addition to that, make sure the default manpath contains the files +.Pa man1/apropos.1 +and +.Pa man8/man.cgi.8 , +or the documentation links at the bottom of the index page will not work. +.Ss URI interface +.Nm +uniform resource identifiers are not needed for interactive use, +but can be useful for deep linking. +They consist of: +.Bl -enum +.It +The +.Cm http:// +or +.Cm https:// +protocol specifier. +.It +The host name. +.It +The +.Dv SCRIPT_NAME , +preceded by a slash unless empty. +.It +To show a single page, a slash, the manpath, another slash, +and the name of the requested file, for example +.Pa /OpenBSD-current/man1/mandoc.1 . +This can be abbreviated according to the following syntax: +.Sm off +.Op / Ar manpath +.Op / Cm man Ar sec +.Op / Ar arch +.Pf / Ar name Op \&. Ar sec +.Sm on +.It +For searches, a query string starting with a question mark +and consisting of +.Ar key Ns = Ns Ar value +pairs, separated by ampersands, for example +.Pa ?manpath=OpenBSD-current&query=mandoc . +Supported keys are +.Cm manpath , +.Cm query , +.Cm sec , +.Cm arch , +corresponding to +.Xr apropos 1 +.Fl M , +.Ar expression , +.Fl s , +.Fl S , +respectively, and +.Cm apropos , +which is a boolean parameter to select or deselect the +.Xr apropos 1 +query mode. +For backward compatibility with the traditional +.Nm , +.Cm sektion +is supported as an alias for +.Cm sec . +.El +.Ss Restricted character set +For security reasons, in particular to prevent cross site scripting +attacks, some strings used by +.Nm +can only contain the following characters: +.Pp +.Bl -dash -compact -offset indent +.It +lower case and upper case ASCII letters +.It +the ten decimal digits +.It +the dash +.Pq Sq - +.It +the dot +.Pq Sq \&. +.It +the slash +.Pq Sq / +.It +the underscore +.Pq Sq _ +.El +.Pp +In particular, this applies to all manpaths and architecture names. +.Sh ENVIRONMENT +The web server may pass the following CGI variables to +.Nm : +.Bl -tag -width Ds +.It Ev SCRIPT_NAME +The initial part of the URI passed from the client to the server, +starting after the server's host name and ending before +.Ev PATH_INFO . +This is ignored by +.Nm . +When constructing URIs for links and redirections, the +.Dv SCRIPT_NAME +preprocessor constant is used instead. +.It Ev PATH_INFO +The final part of the URI path passed from the client to the server, +starting after the +.Ev SCRIPT_NAME +and ending before the +.Ev QUERY_STRING . +It is used by the +.Cm show +page to acquire the manpath and filename it needs. +.It Ev QUERY_STRING +The HTTP query string passed from the client to the server. +It is the final part of the URI, after the question mark. +It is used by the +.Cm search +page to acquire the named parameters it needs. +.El +.Sh FILES +.Bl -tag -width Ds +.It Pa /var/www +Default web server +.Xr chroot 2 +directory. +All the following paths are specified relative to this directory. +.It Pa /cgi-bin/man.cgi +The usual file system path to the +.Nm +program inside the web server +.Xr chroot 2 +directory. +A different name can be chosen, but in any case, it needs to be configured in +.Xr httpd.conf 5 . +.It Pa /htdocs +The file system path to the server document root directory +relative to the server +.Xr chroot 2 +directory. +This is part of the web server configuration and not specific to +.Nm . +.It Pa /htdocs/mandoc.css +A style sheet for +.Xr mandoc 1 +HTML styling, referenced from each generated HTML page. +.It Pa /man +Default +.Nm +data directory containing all the manual trees. +Can be overridden by +.Dv MAN_DIR . +.It Pa /man/manpath.conf +The list of available manpaths, one per line. +If any of the lines in this file contains a slash +.Pq Sq / +or any character not contained in the +.Sx Restricted character set , +.Nm +reports an internal server error and exits without doing anything. +.It Pa /man/header.html +An optional file containing static HTML code to be inserted right +after opening the <BODY> element. +.It Pa /man/footer.html +An optional file containing static HTML code to be inserted right +before closing the <BODY> element. +.It Pa /man/OpenBSD-current/man1/mandoc.1 +An example +.Xr mdoc 7 +source file located below the +.Dq OpenBSD-current +manpath. +.El +.Sh COMPATIBILITY +The +.Nm +CGI program is call-compatible with queries from the traditional +.Pa man.cgi +script by Wolfram Schneider. +However, the output looks quite different. +.Sh SEE ALSO +.Xr apropos 1 , +.Xr mandoc.db 5 , +.Xr makewhatis 8 , +.Xr slowcgi 8 +.Sh HISTORY +A version of +.Nm +based on +.Xr mandoc 1 +first appeared in mdocml-1.12.1 (March 2012). +The current +.Xr mandoc.db 5 +database format first appeared in +.Ox 6.1 . +.Sh AUTHORS +.An -nosplit +The +.Nm +program was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +and is maintained by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org , +who also designed and implemented the database format. Property changes on: vendor/mandoc/20190723/man.cgi.8 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_aux.c =================================================================== --- vendor/mandoc/20190723/mandoc_aux.c (nonexistent) +++ vendor/mandoc/20190723/mandoc_aux.c (revision 350350) @@ -0,0 +1,118 @@ +/* $Id: mandoc_aux.c,v 1.11 2018/02/07 20:04:57 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include <sys/types.h> + +#if HAVE_ERR +#include <err.h> +#endif +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "mandoc.h" +#include "mandoc_aux.h" + + +int +mandoc_asprintf(char **dest, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vasprintf(dest, fmt, ap); + va_end(ap); + + if (ret == -1) + err((int)MANDOCLEVEL_SYSERR, NULL); + return ret; +} + +void * +mandoc_calloc(size_t num, size_t size) +{ + void *ptr; + + ptr = calloc(num, size); + if (ptr == NULL) + err((int)MANDOCLEVEL_SYSERR, NULL); + return ptr; +} + +void * +mandoc_malloc(size_t size) +{ + void *ptr; + + ptr = malloc(size); + if (ptr == NULL) + err((int)MANDOCLEVEL_SYSERR, NULL); + return ptr; +} + +void * +mandoc_realloc(void *ptr, size_t size) +{ + ptr = realloc(ptr, size); + if (ptr == NULL) + err((int)MANDOCLEVEL_SYSERR, NULL); + return ptr; +} + +void * +mandoc_reallocarray(void *ptr, size_t num, size_t size) +{ + ptr = reallocarray(ptr, num, size); + if (ptr == NULL) + err((int)MANDOCLEVEL_SYSERR, NULL); + return ptr; +} + +void * +mandoc_recallocarray(void *ptr, size_t oldnum, size_t num, size_t size) +{ + ptr = recallocarray(ptr, oldnum, num, size); + if (ptr == NULL) + err((int)MANDOCLEVEL_SYSERR, NULL); + return ptr; +} + +char * +mandoc_strdup(const char *ptr) +{ + char *p; + + p = strdup(ptr); + if (p == NULL) + err((int)MANDOCLEVEL_SYSERR, NULL); + return p; +} + +char * +mandoc_strndup(const char *ptr, size_t sz) +{ + char *p; + + p = strndup(ptr, sz); + if (p == NULL) + err((int)MANDOCLEVEL_SYSERR, NULL); + return p; +} Property changes on: vendor/mandoc/20190723/mandoc_aux.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/term_ps.c =================================================================== --- vendor/mandoc/20190723/term_ps.c (nonexistent) +++ vendor/mandoc/20190723/term_ps.c (revision 350350) @@ -0,0 +1,1359 @@ +/* $Id: term_ps.c,v 1.91 2017/11/10 23:42:52 schwarze Exp $ */ +/* + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2017 Marc Espie <espie@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include <sys/types.h> + +#include <assert.h> +#if HAVE_ERR +#include <err.h> +#endif +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "mandoc_aux.h" +#include "out.h" +#include "term.h" +#include "manconf.h" +#include "main.h" + +/* These work the buffer used by the header and footer. */ +#define PS_BUFSLOP 128 + +/* Convert PostScript point "x" to an AFM unit. */ +#define PNT2AFM(p, x) \ + (size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale)) + +/* Convert an AFM unit "x" to a PostScript points */ +#define AFM2PNT(p, x) \ + ((double)(x) / (1000.0 / (double)(p)->ps->scale)) + +struct glyph { + unsigned short wx; /* WX in AFM */ +}; + +struct font { + const char *name; /* FontName in AFM */ +#define MAXCHAR 95 /* total characters we can handle */ + struct glyph gly[MAXCHAR]; /* glyph metrics */ +}; + +struct termp_ps { + int flags; +#define PS_INLINE (1 << 0) /* we're in a word */ +#define PS_MARGINS (1 << 1) /* we're in the margins */ +#define PS_NEWPAGE (1 << 2) /* new page, no words yet */ +#define PS_BACKSP (1 << 3) /* last character was backspace */ + size_t pscol; /* visible column (AFM units) */ + size_t pscolnext; /* used for overstrike */ + size_t psrow; /* visible row (AFM units) */ + size_t lastrow; /* psrow of the previous word */ + char *psmarg; /* margin buf */ + size_t psmargsz; /* margin buf size */ + size_t psmargcur; /* cur index in margin buf */ + char last; /* last non-backspace seen */ + enum termfont lastf; /* last set font */ + enum termfont nextf; /* building next font here */ + size_t scale; /* font scaling factor */ + size_t pages; /* number of pages shown */ + size_t lineheight; /* line height (AFM units) */ + size_t top; /* body top (AFM units) */ + size_t bottom; /* body bottom (AFM units) */ + const char *medianame; /* for DocumentMedia and PageSize */ + size_t height; /* page height (AFM units */ + size_t width; /* page width (AFM units) */ + size_t lastwidth; /* page width before last ll */ + size_t left; /* body left (AFM units) */ + size_t header; /* header pos (AFM units) */ + size_t footer; /* footer pos (AFM units) */ + size_t pdfbytes; /* current output byte */ + size_t pdflastpg; /* byte of last page mark */ + size_t pdfbody; /* start of body object */ + size_t *pdfobjs; /* table of object offsets */ + size_t pdfobjsz; /* size of pdfobjs */ +}; + +static int ps_hspan(const struct termp *, + const struct roffsu *); +static size_t ps_width(const struct termp *, int); +static void ps_advance(struct termp *, size_t); +static void ps_begin(struct termp *); +static void ps_closepage(struct termp *); +static void ps_end(struct termp *); +static void ps_endline(struct termp *); +static void ps_growbuf(struct termp *, size_t); +static void ps_letter(struct termp *, int); +static void ps_pclose(struct termp *); +static void ps_plast(struct termp *); +static void ps_pletter(struct termp *, int); +static void ps_printf(struct termp *, const char *, ...) + __attribute__((__format__ (__printf__, 2, 3))); +static void ps_putchar(struct termp *, char); +static void ps_setfont(struct termp *, enum termfont); +static void ps_setwidth(struct termp *, int, int); +static struct termp *pspdf_alloc(const struct manoutput *, enum termtype); +static void pdf_obj(struct termp *, size_t); + +/* + * We define, for the time being, three fonts: bold, oblique/italic, and + * normal (roman). The following table hard-codes the font metrics for + * ASCII, i.e., 32--127. + */ + +static const struct font fonts[TERMFONT__MAX] = { + { "Times-Roman", { + { 250 }, + { 333 }, + { 408 }, + { 500 }, + { 500 }, + { 833 }, + { 778 }, + { 333 }, + { 333 }, + { 333 }, + { 500 }, + { 564 }, + { 250 }, + { 333 }, + { 250 }, + { 278 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 278 }, + { 278 }, + { 564 }, + { 564 }, + { 564 }, + { 444 }, + { 921 }, + { 722 }, + { 667 }, + { 667 }, + { 722 }, + { 611 }, + { 556 }, + { 722 }, + { 722 }, + { 333 }, + { 389 }, + { 722 }, + { 611 }, + { 889 }, + { 722 }, + { 722 }, + { 556 }, + { 722 }, + { 667 }, + { 556 }, + { 611 }, + { 722 }, + { 722 }, + { 944 }, + { 722 }, + { 722 }, + { 611 }, + { 333 }, + { 278 }, + { 333 }, + { 469 }, + { 500 }, + { 333 }, + { 444 }, + { 500 }, + { 444 }, + { 500}, + { 444}, + { 333}, + { 500}, + { 500}, + { 278}, + { 278}, + { 500}, + { 278}, + { 778}, + { 500}, + { 500}, + { 500}, + { 500}, + { 333}, + { 389}, + { 278}, + { 500}, + { 500}, + { 722}, + { 500}, + { 500}, + { 444}, + { 480}, + { 200}, + { 480}, + { 541}, + } }, + { "Times-Bold", { + { 250 }, + { 333 }, + { 555 }, + { 500 }, + { 500 }, + { 1000 }, + { 833 }, + { 333 }, + { 333 }, + { 333 }, + { 500 }, + { 570 }, + { 250 }, + { 333 }, + { 250 }, + { 278 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 333 }, + { 333 }, + { 570 }, + { 570 }, + { 570 }, + { 500 }, + { 930 }, + { 722 }, + { 667 }, + { 722 }, + { 722 }, + { 667 }, + { 611 }, + { 778 }, + { 778 }, + { 389 }, + { 500 }, + { 778 }, + { 667 }, + { 944 }, + { 722 }, + { 778 }, + { 611 }, + { 778 }, + { 722 }, + { 556 }, + { 667 }, + { 722 }, + { 722 }, + { 1000 }, + { 722 }, + { 722 }, + { 667 }, + { 333 }, + { 278 }, + { 333 }, + { 581 }, + { 500 }, + { 333 }, + { 500 }, + { 556 }, + { 444 }, + { 556 }, + { 444 }, + { 333 }, + { 500 }, + { 556 }, + { 278 }, + { 333 }, + { 556 }, + { 278 }, + { 833 }, + { 556 }, + { 500 }, + { 556 }, + { 556 }, + { 444 }, + { 389 }, + { 333 }, + { 556 }, + { 500 }, + { 722 }, + { 500 }, + { 500 }, + { 444 }, + { 394 }, + { 220 }, + { 394 }, + { 520 }, + } }, + { "Times-Italic", { + { 250 }, + { 333 }, + { 420 }, + { 500 }, + { 500 }, + { 833 }, + { 778 }, + { 333 }, + { 333 }, + { 333 }, + { 500 }, + { 675 }, + { 250 }, + { 333 }, + { 250 }, + { 278 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 333 }, + { 333 }, + { 675 }, + { 675 }, + { 675 }, + { 500 }, + { 920 }, + { 611 }, + { 611 }, + { 667 }, + { 722 }, + { 611 }, + { 611 }, + { 722 }, + { 722 }, + { 333 }, + { 444 }, + { 667 }, + { 556 }, + { 833 }, + { 667 }, + { 722 }, + { 611 }, + { 722 }, + { 611 }, + { 500 }, + { 556 }, + { 722 }, + { 611 }, + { 833 }, + { 611 }, + { 556 }, + { 556 }, + { 389 }, + { 278 }, + { 389 }, + { 422 }, + { 500 }, + { 333 }, + { 500 }, + { 500 }, + { 444 }, + { 500 }, + { 444 }, + { 278 }, + { 500 }, + { 500 }, + { 278 }, + { 278 }, + { 444 }, + { 278 }, + { 722 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 389 }, + { 389 }, + { 278 }, + { 500 }, + { 444 }, + { 667 }, + { 444 }, + { 444 }, + { 389 }, + { 400 }, + { 275 }, + { 400 }, + { 541 }, + } }, + { "Times-BoldItalic", { + { 250 }, + { 389 }, + { 555 }, + { 500 }, + { 500 }, + { 833 }, + { 778 }, + { 333 }, + { 333 }, + { 333 }, + { 500 }, + { 570 }, + { 250 }, + { 333 }, + { 250 }, + { 278 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 500 }, + { 333 }, + { 333 }, + { 570 }, + { 570 }, + { 570 }, + { 500 }, + { 832 }, + { 667 }, + { 667 }, + { 667 }, + { 722 }, + { 667 }, + { 667 }, + { 722 }, + { 778 }, + { 389 }, + { 500 }, + { 667 }, + { 611 }, + { 889 }, + { 722 }, + { 722 }, + { 611 }, + { 722 }, + { 667 }, + { 556 }, + { 611 }, + { 722 }, + { 667 }, + { 889 }, + { 667 }, + { 611 }, + { 611 }, + { 333 }, + { 278 }, + { 333 }, + { 570 }, + { 500 }, + { 333 }, + { 500 }, + { 500 }, + { 444 }, + { 500 }, + { 444 }, + { 333 }, + { 500 }, + { 556 }, + { 278 }, + { 278 }, + { 500 }, + { 278 }, + { 778 }, + { 556 }, + { 500 }, + { 500 }, + { 500 }, + { 389 }, + { 389 }, + { 278 }, + { 556 }, + { 444 }, + { 667 }, + { 500 }, + { 444 }, + { 389 }, + { 348 }, + { 220 }, + { 348 }, + { 570 }, + } }, +}; + +void * +pdf_alloc(const struct manoutput *outopts) +{ + return pspdf_alloc(outopts, TERMTYPE_PDF); +} + +void * +ps_alloc(const struct manoutput *outopts) +{ + return pspdf_alloc(outopts, TERMTYPE_PS); +} + +static struct termp * +pspdf_alloc(const struct manoutput *outopts, enum termtype type) +{ + struct termp *p; + unsigned int pagex, pagey; + size_t marginx, marginy, lineheight; + const char *pp; + + p = mandoc_calloc(1, sizeof(*p)); + p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol)); + p->maxtcol = 1; + p->type = type; + + p->enc = TERMENC_ASCII; + p->fontq = mandoc_reallocarray(NULL, + (p->fontsz = 8), sizeof(*p->fontq)); + p->fontq[0] = p->fontl = TERMFONT_NONE; + p->ps = mandoc_calloc(1, sizeof(*p->ps)); + + p->advance = ps_advance; + p->begin = ps_begin; + p->end = ps_end; + p->endline = ps_endline; + p->hspan = ps_hspan; + p->letter = ps_letter; + p->setwidth = ps_setwidth; + p->width = ps_width; + + /* Default to US letter (millimetres). */ + + p->ps->medianame = "Letter"; + pagex = 216; + pagey = 279; + + /* + * The ISO-269 paper sizes can be calculated automatically, but + * it would require bringing in -lm for pow() and I'd rather not + * do that. So just do it the easy way for now. Since this + * only happens once, I'm not terribly concerned. + */ + + pp = outopts->paper; + if (pp != NULL && strcasecmp(pp, "letter") != 0) { + if (strcasecmp(pp, "a3") == 0) { + p->ps->medianame = "A3"; + pagex = 297; + pagey = 420; + } else if (strcasecmp(pp, "a4") == 0) { + p->ps->medianame = "A4"; + pagex = 210; + pagey = 297; + } else if (strcasecmp(pp, "a5") == 0) { + p->ps->medianame = "A5"; + pagex = 148; + pagey = 210; + } else if (strcasecmp(pp, "legal") == 0) { + p->ps->medianame = "Legal"; + pagex = 216; + pagey = 356; + } else if (sscanf(pp, "%ux%u", &pagex, &pagey) == 2) + p->ps->medianame = "CustomSize"; + else + warnx("%s: Unknown paper", pp); + } + + /* + * This MUST be defined before any PNT2AFM or AFM2PNT + * calculations occur. + */ + + p->ps->scale = 11; + + /* Remember millimetres -> AFM units. */ + + pagex = PNT2AFM(p, ((double)pagex * 72.0 / 25.4)); + pagey = PNT2AFM(p, ((double)pagey * 72.0 / 25.4)); + + /* Margins are 1/9 the page x and y. */ + + marginx = (size_t)((double)pagex / 9.0); + marginy = (size_t)((double)pagey / 9.0); + + /* Line-height is 1.4em. */ + + lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4)); + + p->ps->width = p->ps->lastwidth = (size_t)pagex; + p->ps->height = (size_t)pagey; + p->ps->header = pagey - (marginy / 2) - (lineheight / 2); + p->ps->top = pagey - marginy; + p->ps->footer = (marginy / 2) - (lineheight / 2); + p->ps->bottom = marginy; + p->ps->left = marginx; + p->ps->lineheight = lineheight; + + p->defrmargin = pagex - (marginx * 2); + return p; +} + +static void +ps_setwidth(struct termp *p, int iop, int width) +{ + size_t lastwidth; + + lastwidth = p->ps->width; + if (iop > 0) + p->ps->width += width; + else if (iop == 0) + p->ps->width = width ? (size_t)width : p->ps->lastwidth; + else if (p->ps->width > (size_t)width) + p->ps->width -= width; + else + p->ps->width = 0; + p->ps->lastwidth = lastwidth; +} + +void +pspdf_free(void *arg) +{ + struct termp *p; + + p = (struct termp *)arg; + + free(p->ps->psmarg); + free(p->ps->pdfobjs); + + free(p->ps); + term_free(p); +} + +static void +ps_printf(struct termp *p, const char *fmt, ...) +{ + va_list ap; + int pos, len; + + va_start(ap, fmt); + + /* + * If we're running in regular mode, then pipe directly into + * vprintf(). If we're processing margins, then push the data + * into our growable margin buffer. + */ + + if ( ! (PS_MARGINS & p->ps->flags)) { + len = vprintf(fmt, ap); + va_end(ap); + p->ps->pdfbytes += len < 0 ? 0 : (size_t)len; + return; + } + + /* + * XXX: I assume that the in-margin print won't exceed + * PS_BUFSLOP (128 bytes), which is reasonable but still an + * assumption that will cause pukeage if it's not the case. + */ + + ps_growbuf(p, PS_BUFSLOP); + + pos = (int)p->ps->psmargcur; + vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap); + + va_end(ap); + + p->ps->psmargcur = strlen(p->ps->psmarg); +} + +static void +ps_putchar(struct termp *p, char c) +{ + int pos; + + /* See ps_printf(). */ + + if ( ! (PS_MARGINS & p->ps->flags)) { + putchar(c); + p->ps->pdfbytes++; + return; + } + + ps_growbuf(p, 2); + + pos = (int)p->ps->psmargcur++; + p->ps->psmarg[pos++] = c; + p->ps->psmarg[pos] = '\0'; +} + +static void +pdf_obj(struct termp *p, size_t obj) +{ + + assert(obj > 0); + + if ((obj - 1) >= p->ps->pdfobjsz) { + p->ps->pdfobjsz = obj + 128; + p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs, + p->ps->pdfobjsz, sizeof(size_t)); + } + + p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes; + ps_printf(p, "%zu 0 obj\n", obj); +} + +static void +ps_closepage(struct termp *p) +{ + int i; + size_t len, base; + + /* + * Close out a page that we've already flushed to output. In + * PostScript, we simply note that the page must be shown. In + * PDF, we must now create the Length, Resource, and Page node + * for the page contents. + */ + + assert(p->ps->psmarg && p->ps->psmarg[0]); + ps_printf(p, "%s", p->ps->psmarg); + + if (TERMTYPE_PS != p->type) { + len = p->ps->pdfbytes - p->ps->pdflastpg; + base = p->ps->pages * 4 + p->ps->pdfbody; + + ps_printf(p, "endstream\nendobj\n"); + + /* Length of content. */ + pdf_obj(p, base + 1); + ps_printf(p, "%zu\nendobj\n", len); + + /* Resource for content. */ + pdf_obj(p, base + 2); + ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n"); + ps_printf(p, "/Font <<\n"); + for (i = 0; i < (int)TERMFONT__MAX; i++) + ps_printf(p, "/F%d %d 0 R\n", i, 3 + i); + ps_printf(p, ">>\n>>\nendobj\n"); + + /* Page node. */ + pdf_obj(p, base + 3); + ps_printf(p, "<<\n"); + ps_printf(p, "/Type /Page\n"); + ps_printf(p, "/Parent 2 0 R\n"); + ps_printf(p, "/Resources %zu 0 R\n", base + 2); + ps_printf(p, "/Contents %zu 0 R\n", base); + ps_printf(p, ">>\nendobj\n"); + } else + ps_printf(p, "showpage\n"); + + p->ps->pages++; + p->ps->psrow = p->ps->top; + assert( ! (PS_NEWPAGE & p->ps->flags)); + p->ps->flags |= PS_NEWPAGE; +} + +static void +ps_end(struct termp *p) +{ + size_t i, xref, base; + + ps_plast(p); + ps_pclose(p); + + /* + * At the end of the file, do one last showpage. This is the + * same behaviour as groff(1) and works for multiple pages as + * well as just one. + */ + + if ( ! (PS_NEWPAGE & p->ps->flags)) { + assert(0 == p->ps->flags); + assert('\0' == p->ps->last); + ps_closepage(p); + } + + if (TERMTYPE_PS == p->type) { + ps_printf(p, "%%%%Trailer\n"); + ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages); + ps_printf(p, "%%%%EOF\n"); + return; + } + + pdf_obj(p, 2); + ps_printf(p, "<<\n/Type /Pages\n"); + ps_printf(p, "/MediaBox [0 0 %zu %zu]\n", + (size_t)AFM2PNT(p, p->ps->width), + (size_t)AFM2PNT(p, p->ps->height)); + + ps_printf(p, "/Count %zu\n", p->ps->pages); + ps_printf(p, "/Kids ["); + + for (i = 0; i < p->ps->pages; i++) + ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3); + + base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4; + + ps_printf(p, "]\n>>\nendobj\n"); + pdf_obj(p, base); + ps_printf(p, "<<\n"); + ps_printf(p, "/Type /Catalog\n"); + ps_printf(p, "/Pages 2 0 R\n"); + ps_printf(p, ">>\nendobj\n"); + xref = p->ps->pdfbytes; + ps_printf(p, "xref\n"); + ps_printf(p, "0 %zu\n", base + 1); + ps_printf(p, "0000000000 65535 f \n"); + + for (i = 0; i < base; i++) + ps_printf(p, "%.10zu 00000 n \n", + p->ps->pdfobjs[(int)i]); + + ps_printf(p, "trailer\n"); + ps_printf(p, "<<\n"); + ps_printf(p, "/Size %zu\n", base + 1); + ps_printf(p, "/Root %zu 0 R\n", base); + ps_printf(p, "/Info 1 0 R\n"); + ps_printf(p, ">>\n"); + ps_printf(p, "startxref\n"); + ps_printf(p, "%zu\n", xref); + ps_printf(p, "%%%%EOF\n"); +} + +static void +ps_begin(struct termp *p) +{ + size_t width, height; + int i; + + /* + * Print margins into margin buffer. Nothing gets output to the + * screen yet, so we don't need to initialise the primary state. + */ + + if (p->ps->psmarg) { + assert(p->ps->psmargsz); + p->ps->psmarg[0] = '\0'; + } + + /*p->ps->pdfbytes = 0;*/ + p->ps->psmargcur = 0; + p->ps->flags = PS_MARGINS; + p->ps->pscol = p->ps->left; + p->ps->psrow = p->ps->header; + p->ps->lastrow = 0; /* impossible row */ + + ps_setfont(p, TERMFONT_NONE); + + (*p->headf)(p, p->argf); + (*p->endline)(p); + + p->ps->pscol = p->ps->left; + p->ps->psrow = p->ps->footer; + + (*p->footf)(p, p->argf); + (*p->endline)(p); + + p->ps->flags &= ~PS_MARGINS; + + assert(0 == p->ps->flags); + assert(p->ps->psmarg); + assert('\0' != p->ps->psmarg[0]); + + /* + * Print header and initialise page state. Following this, + * stuff gets printed to the screen, so make sure we're sane. + */ + + if (TERMTYPE_PS == p->type) { + width = AFM2PNT(p, p->ps->width); + height = AFM2PNT(p, p->ps->height); + + ps_printf(p, "%%!PS-Adobe-3.0\n"); + ps_printf(p, "%%%%DocumentData: Clean7Bit\n"); + ps_printf(p, "%%%%Orientation: Portrait\n"); + ps_printf(p, "%%%%Pages: (atend)\n"); + ps_printf(p, "%%%%PageOrder: Ascend\n"); + ps_printf(p, "%%%%DocumentMedia: man-%s %zu %zu 0 () ()\n", + p->ps->medianame, width, height); + ps_printf(p, "%%%%DocumentNeededResources: font"); + + for (i = 0; i < (int)TERMFONT__MAX; i++) + ps_printf(p, " %s", fonts[i].name); + + ps_printf(p, "\n%%%%DocumentSuppliedResources: " + "procset MandocProcs 1.0 0\n"); + ps_printf(p, "%%%%EndComments\n"); + ps_printf(p, "%%%%BeginProlog\n"); + ps_printf(p, "%%%%BeginResource: procset MandocProcs " + "10170 10170\n"); + /* The font size is effectively hard-coded for now. */ + ps_printf(p, "/fs %zu def\n", p->ps->scale); + for (i = 0; i < (int)TERMFONT__MAX; i++) + ps_printf(p, "/f%d { /%s fs selectfont } def\n", + i, fonts[i].name); + ps_printf(p, "/s { 3 1 roll moveto show } bind def\n"); + ps_printf(p, "/c { exch currentpoint exch pop " + "moveto show } bind def\n"); + ps_printf(p, "%%%%EndResource\n"); + ps_printf(p, "%%%%EndProlog\n"); + ps_printf(p, "%%%%BeginSetup\n"); + ps_printf(p, "%%%%BeginFeature: *PageSize %s\n", + p->ps->medianame); + ps_printf(p, "<</PageSize [%zu %zu]>>setpagedevice\n", + width, height); + ps_printf(p, "%%%%EndFeature\n"); + ps_printf(p, "%%%%EndSetup\n"); + } else { + ps_printf(p, "%%PDF-1.1\n"); + pdf_obj(p, 1); + ps_printf(p, "<<\n"); + ps_printf(p, ">>\n"); + ps_printf(p, "endobj\n"); + + for (i = 0; i < (int)TERMFONT__MAX; i++) { + pdf_obj(p, (size_t)i + 3); + ps_printf(p, "<<\n"); + ps_printf(p, "/Type /Font\n"); + ps_printf(p, "/Subtype /Type1\n"); + ps_printf(p, "/Name /F%d\n", i); + ps_printf(p, "/BaseFont /%s\n", fonts[i].name); + ps_printf(p, ">>\nendobj\n"); + } + } + + p->ps->pdfbody = (size_t)TERMFONT__MAX + 3; + p->ps->pscol = p->ps->left; + p->ps->psrow = p->ps->top; + p->ps->flags |= PS_NEWPAGE; + ps_setfont(p, TERMFONT_NONE); +} + +static void +ps_pletter(struct termp *p, int c) +{ + int f; + + /* + * If we haven't opened a page context, then output that we're + * in a new page and make sure the font is correctly set. + */ + + if (PS_NEWPAGE & p->ps->flags) { + if (TERMTYPE_PS == p->type) { + ps_printf(p, "%%%%Page: %zu %zu\n", + p->ps->pages + 1, p->ps->pages + 1); + ps_printf(p, "f%d\n", (int)p->ps->lastf); + } else { + pdf_obj(p, p->ps->pdfbody + + p->ps->pages * 4); + ps_printf(p, "<<\n"); + ps_printf(p, "/Length %zu 0 R\n", + p->ps->pdfbody + 1 + p->ps->pages * 4); + ps_printf(p, ">>\nstream\n"); + } + p->ps->pdflastpg = p->ps->pdfbytes; + p->ps->flags &= ~PS_NEWPAGE; + } + + /* + * If we're not in a PostScript "word" context, then open one + * now at the current cursor. + */ + + if ( ! (PS_INLINE & p->ps->flags)) { + if (TERMTYPE_PS != p->type) { + ps_printf(p, "BT\n/F%d %zu Tf\n", + (int)p->ps->lastf, p->ps->scale); + ps_printf(p, "%.3f %.3f Td\n(", + AFM2PNT(p, p->ps->pscol), + AFM2PNT(p, p->ps->psrow)); + } else { + ps_printf(p, "%.3f", AFM2PNT(p, p->ps->pscol)); + if (p->ps->psrow != p->ps->lastrow) + ps_printf(p, " %.3f", + AFM2PNT(p, p->ps->psrow)); + ps_printf(p, "("); + } + p->ps->flags |= PS_INLINE; + } + + assert( ! (PS_NEWPAGE & p->ps->flags)); + + /* + * We need to escape these characters as per the PostScript + * specification. We would also escape non-graphable characters + * (like tabs), but none of them would get to this point and + * it's superfluous to abort() on them. + */ + + switch (c) { + case '(': + case ')': + case '\\': + ps_putchar(p, '\\'); + break; + default: + break; + } + + /* Write the character and adjust where we are on the page. */ + + f = (int)p->ps->lastf; + + if (c <= 32 || c - 32 >= MAXCHAR) + c = 32; + + ps_putchar(p, (char)c); + c -= 32; + p->ps->pscol += (size_t)fonts[f].gly[c].wx; +} + +static void +ps_pclose(struct termp *p) +{ + + /* + * Spit out that we're exiting a word context (this is a + * "partial close" because we don't check the last-char buffer + * or anything). + */ + + if ( ! (PS_INLINE & p->ps->flags)) + return; + + if (TERMTYPE_PS != p->type) + ps_printf(p, ") Tj\nET\n"); + else if (p->ps->psrow == p->ps->lastrow) + ps_printf(p, ")c\n"); + else { + ps_printf(p, ")s\n"); + p->ps->lastrow = p->ps->psrow; + } + + p->ps->flags &= ~PS_INLINE; +} + +/* If we have a `last' char that wasn't printed yet, print it now. */ +static void +ps_plast(struct termp *p) +{ + size_t wx; + + if (p->ps->last == '\0') + return; + + /* Check the font mode; open a new scope if it doesn't match. */ + + if (p->ps->nextf != p->ps->lastf) { + ps_pclose(p); + ps_setfont(p, p->ps->nextf); + } + p->ps->nextf = TERMFONT_NONE; + + /* + * For an overstrike, if a previous character + * was wider, advance to center the new one. + */ + + if (p->ps->pscolnext) { + wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx; + if (p->ps->pscol + wx < p->ps->pscolnext) + p->ps->pscol = (p->ps->pscol + + p->ps->pscolnext - wx) / 2; + } + + ps_pletter(p, p->ps->last); + p->ps->last = '\0'; + + /* + * For an overstrike, if a previous character + * was wider, advance to the end of the old one. + */ + + if (p->ps->pscol < p->ps->pscolnext) { + ps_pclose(p); + p->ps->pscol = p->ps->pscolnext; + } +} + +static void +ps_letter(struct termp *p, int arg) +{ + size_t savecol; + char c; + + c = arg >= 128 || arg <= 0 ? '?' : arg; + + /* + * When receiving a backspace, merely flag it. + * We don't know yet whether it is + * a font instruction or an overstrike. + */ + + if (c == '\b') { + assert(p->ps->last != '\0'); + assert( ! (p->ps->flags & PS_BACKSP)); + p->ps->flags |= PS_BACKSP; + return; + } + + /* + * Decode font instructions. + */ + + if (p->ps->flags & PS_BACKSP) { + if (p->ps->last == '_') { + switch (p->ps->nextf) { + case TERMFONT_BI: + break; + case TERMFONT_BOLD: + p->ps->nextf = TERMFONT_BI; + break; + default: + p->ps->nextf = TERMFONT_UNDER; + } + p->ps->last = c; + p->ps->flags &= ~PS_BACKSP; + return; + } + if (p->ps->last == c) { + switch (p->ps->nextf) { + case TERMFONT_BI: + break; + case TERMFONT_UNDER: + p->ps->nextf = TERMFONT_BI; + break; + default: + p->ps->nextf = TERMFONT_BOLD; + } + p->ps->flags &= ~PS_BACKSP; + return; + } + + /* + * This is not a font instruction, but rather + * the next character. Prepare for overstrike. + */ + + savecol = p->ps->pscol; + } else + savecol = SIZE_MAX; + + /* + * We found the next character, so the font instructions + * for the previous one are complete. + * Use them and print it. + */ + + ps_plast(p); + + /* + * Do not print the current character yet because font + * instructions might follow; only remember the character. + * It will get printed later from ps_plast(). + */ + + p->ps->last = c; + + /* + * For an overstrike, back up to the previous position. + * If the previous character is wider than any it overstrikes, + * remember the current position, because it might also be + * wider than all that will overstrike it. + */ + + if (savecol != SIZE_MAX) { + if (p->ps->pscolnext < p->ps->pscol) + p->ps->pscolnext = p->ps->pscol; + ps_pclose(p); + p->ps->pscol = savecol; + p->ps->flags &= ~PS_BACKSP; + } else + p->ps->pscolnext = 0; +} + +static void +ps_advance(struct termp *p, size_t len) +{ + + /* + * Advance some spaces. This can probably be made smarter, + * i.e., to have multiple space-separated words in the same + * scope, but this is easier: just close out the current scope + * and readjust our column settings. + */ + + ps_plast(p); + ps_pclose(p); + p->ps->pscol += len; +} + +static void +ps_endline(struct termp *p) +{ + + /* Close out any scopes we have open: we're at eoln. */ + + ps_plast(p); + ps_pclose(p); + + /* + * If we're in the margin, don't try to recalculate our current + * row. XXX: if the column tries to be fancy with multiple + * lines, we'll do nasty stuff. + */ + + if (PS_MARGINS & p->ps->flags) + return; + + /* Left-justify. */ + + p->ps->pscol = p->ps->left; + + /* If we haven't printed anything, return. */ + + if (PS_NEWPAGE & p->ps->flags) + return; + + /* + * Put us down a line. If we're at the page bottom, spit out a + * showpage and restart our row. + */ + + if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) { + p->ps->psrow -= p->ps->lineheight; + return; + } + + ps_closepage(p); + + p->tcol->offset -= p->ti; + p->ti = 0; +} + +static void +ps_setfont(struct termp *p, enum termfont f) +{ + + assert(f < TERMFONT__MAX); + p->ps->lastf = f; + + /* + * If we're still at the top of the page, let the font-setting + * be delayed until we actually have stuff to print. + */ + + if (PS_NEWPAGE & p->ps->flags) + return; + + if (TERMTYPE_PS == p->type) + ps_printf(p, "f%d\n", (int)f); + else + ps_printf(p, "/F%d %zu Tf\n", + (int)f, p->ps->scale); +} + +static size_t +ps_width(const struct termp *p, int c) +{ + + if (c <= 32 || c - 32 >= MAXCHAR) + c = 0; + else + c -= 32; + + return (size_t)fonts[(int)TERMFONT_NONE].gly[c].wx; +} + +static int +ps_hspan(const struct termp *p, const struct roffsu *su) +{ + double r; + + /* + * All of these measurements are derived by converting from the + * native measurement to AFM units. + */ + switch (su->unit) { + case SCALE_BU: + /* + * Traditionally, the default unit is fixed to the + * output media. So this would refer to the point. In + * mandoc(1), however, we stick to the default terminal + * scaling unit so that output is the same regardless + * the media. + */ + r = PNT2AFM(p, su->scale * 72.0 / 240.0); + break; + case SCALE_CM: + r = PNT2AFM(p, su->scale * 72.0 / 2.54); + break; + case SCALE_EM: + r = su->scale * + fonts[(int)TERMFONT_NONE].gly[109 - 32].wx; + break; + case SCALE_EN: + r = su->scale * + fonts[(int)TERMFONT_NONE].gly[110 - 32].wx; + break; + case SCALE_IN: + r = PNT2AFM(p, su->scale * 72.0); + break; + case SCALE_MM: + r = su->scale * + fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0; + break; + case SCALE_PC: + r = PNT2AFM(p, su->scale * 12.0); + break; + case SCALE_PT: + r = PNT2AFM(p, su->scale * 1.0); + break; + case SCALE_VS: + r = su->scale * p->ps->lineheight; + break; + default: + r = su->scale; + break; + } + + return r * 24.0; +} + +static void +ps_growbuf(struct termp *p, size_t sz) +{ + if (p->ps->psmargcur + sz <= p->ps->psmargsz) + return; + + if (sz < PS_BUFSLOP) + sz = PS_BUFSLOP; + + p->ps->psmargsz += sz; + p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz); +} Property changes on: vendor/mandoc/20190723/term_ps.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-noop.c =================================================================== --- vendor/mandoc/20190723/test-noop.c (nonexistent) +++ vendor/mandoc/20190723/test-noop.c (revision 350350) @@ -0,0 +1,5 @@ +int +main(void) +{ + return 0; +} Property changes on: vendor/mandoc/20190723/test-noop.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-strndup.c =================================================================== --- vendor/mandoc/20190723/test-strndup.c (nonexistent) +++ vendor/mandoc/20190723/test-strndup.c (revision 350350) @@ -0,0 +1,10 @@ +#include <string.h> + +int +main(void) +{ + char *s; + + s = strndup("123", 2); + return s[0] != '1' ? 1 : s[1] != '2' ? 2 : s[2] != '\0' ? 3 : 0; +} Property changes on: vendor/mandoc/20190723/test-strndup.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_recallocarray.c =================================================================== --- vendor/mandoc/20190723/compat_recallocarray.c (nonexistent) +++ vendor/mandoc/20190723/compat_recallocarray.c (revision 350350) @@ -0,0 +1,108 @@ +#include "config.h" + +#if HAVE_RECALLOCARRAY + +int dummy; + +#else + +/* $Id: compat_recallocarray.c,v 1.1 2017/06/12 19:05:47 schwarze Exp $ */ +/* $OpenBSD: malloc.c,v 1.225 2017/05/13 07:11:29 otto Exp $ */ +/* + * Copyright (c) 2017 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + +/* + * Even though specified in POSIX, the PAGESIZE and PAGE_SIZE + * macros have very poor portability. Since we only use this + * to avoid free() overhead for small shrinking, simply pick + * an arbitrary number. + */ +#define MALLOC_PAGESIZE (1UL << 12) + + +void * +recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) +{ + size_t oldsize, newsize; + void *newptr; + + if (ptr == NULL) + return calloc(newnmemb, size); + + if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + newnmemb > 0 && SIZE_MAX / newnmemb < size) { + errno = ENOMEM; + return NULL; + } + newsize = newnmemb * size; + + if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { + errno = EINVAL; + return NULL; + } + oldsize = oldnmemb * size; + + /* + * Don't bother too much if we're shrinking just a bit, + * we do not shrink for series of small steps, oh well. + */ + if (newsize <= oldsize) { + size_t d = oldsize - newsize; + + if (d < oldsize / 2 && d < MALLOC_PAGESIZE) { + memset((char *)ptr + newsize, 0, d); + return ptr; + } + } + + newptr = malloc(newsize); + if (newptr == NULL) + return NULL; + + if (newsize > oldsize) { + memcpy(newptr, ptr, oldsize); + memset((char *)newptr + oldsize, 0, newsize - oldsize); + } else + memcpy(newptr, ptr, newsize); + + /* + * At this point, the OpenBSD implementation calls + * explicit_bzero() on the old memory before it is + * freed. Since explicit_bzero() is hard to implement + * portably and we don't handle confidential data in + * mandoc in the first place, simply free the memory + * without clearing it. + */ + + free(ptr); + + return newptr; +} + +#endif /* !HAVE_RECALLOCARRAY */ Property changes on: vendor/mandoc/20190723/compat_recallocarray.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/man.options.1 =================================================================== --- vendor/mandoc/20190723/man.options.1 (nonexistent) +++ vendor/mandoc/20190723/man.options.1 (revision 350350) @@ -0,0 +1,1332 @@ +.\" $Id: man.options.1,v 1.7 2017/07/04 23:40:01 schwarze Exp $ +.\" +.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 4 2017 $ +.Dt MAN.OPTIONS 1 +.Os +.Sh NAME +.Nm man.options +.Nd assignment of option letters in manual page utilities +.\" +.\" Sources that occur repeatedly. +.\" Only use if the precise implementation time is unknown. +.\" +.de PWB +.No PWB/UNIX 1.0 Pq July 1, 1977 \\$1 +.. +.de At7 +.At v7 Pq January 1979 \\$1 +.. +.de At3 +.At III Pq June 1980 \\$1 +.. +.de Bx4 +.Bx 4 Pq November 16, 1980 \\$1 +.. +.de At5 +.At V Pq January 1983 \\$1 +.. +.de Bx43 +.Bx 4.3 Pq June 1986 \\$1 +.. +.\" option was present in groff-1.01 as contained in 4.3BSD-Net/2 +.\" and no mention of it could be found in the ChangeLog, +.\" so it's probably older than groff-0.4, where the log started +.de g04 +.No probably before groff-0.4 Pq before July 14, 1990 \\$1 +.. +.de Eaton +.No Eaton Pq before July 7, 1993; 1990/91? \\$1 +.. +.\" man-1.5e was released on July 11, 1998. +.de man15e +.No man-1.5e Pq not before 1993, not after 1998 \\$1 +.. +.\" man-1.5g was released on April 7, 1999. +.de man15g +.No man-1.5g Pq not before 1993, not after 1999 \\$1 +.. +.\" code first seen in the initial import of man-db into CVS , +.\" which was more or less debian man-db-2.3.17 +.\" Colin Watson's first release was 2.3.18 on May 14, 2001 +.\" no clue about it found in ChangeLog-2013, +.\" so it was probably already present before man-db-2.2a4 +.de dbI +.No man-db probably before 2.2a4 Pq before Nov 8, 1994 \\$1 +.. +.\" +.\" -------------------------------------------------------------------- +.\" +.Sh DESCRIPTION +This manual page lists option letters used in many different versions +of the +.Nm man , +.Nm apropos , +.Nm whatis , +.Nm mandoc , +.Nm makewhatis , +.Nm mandb , +.Nm makemandb , +.Nm catman , +and +.Nm manpath +utilities. +Option letters used by +.Nm groff , +.Nm nroff , +.Nm troff , +and +.Nm roff +are also included because beginning with +.At v7 , +many versions of +.Xr man 1 +pass on unrecognized options to these programs. +.Pp +For each option letter, information is first grouped into paragraphs, +each paragraph describing similar functionality and starting with +one line briefly summarizing that functionality. +.Pp +For each program using the letter for that functionality, one line +is provided, giving the name of the program, a colon, the system +where this letter first appeared for this functionality in this +program, optionally a comma and a list of other system versions +introducing the same, a semicolon, and a list of current systems +supporting it. +If a system appears before the semicolon, it is not repeated +afterwards. +.Pp +Entries are sorted by historical precedence, except that obsolete +options are moved to the end. +Dates are commit dates where known, and release dates otherwise. +.Bl -tag -width 3n +.It Fl a +display all matching manual pages +.br +.Nm man : +.Bx 4.3 Tahoe Pq June 1988 , +.Eaton ; +.Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +only display items that match all keywords +.br +.Nm apropos : +.No man-db Pq Aug 29, 2007 +.Pp +use all directories and files for +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.Pp +.Bq superseded by Fl T Cm ascii +ASCII output mode +.br +.Nm troff : +.At7 +.br +.Nm groff : +.g04 +.It Fl B +use specified browser +.br +.Nm man : +.No man-1.6 Pq June 24, 2005 +.It Fl b +print a backtrace with each warning or error message +.br +.Nm groff : +.g04 +.Pp +.Bq obsolete hardware +report whether the phototypesetter is busy +.br +.Nm troff : +.At7 +.It Fl C +alternate configuration file +.br +.Nm apropos , whatis : +.Bx 4.4 Lite1 Pq April 22, 1994 , +.No man-db Pq Feb 22, 2003 ; +.Ox , Nx +.br +.Nm man : +.Nx 1.0 Pq Oct 26, 1994 , +.man15e ; +.Ox +.br +.Nm mandb , catman , manpath : +.No man-db Pq Feb 22, 2003 +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +.Bq obsolete +enable compatibility mode +.br +.Nm groff : +.No before groff-0.5 Pq before August 3, 1990 +.It Fl c +do not use a pager +.br +.Nm man : +.Bx 4.3 Reno Pq June 1990 ; +.Ox , Nx +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +process given catpath +.br +.Nm makewhatis : +.Pq not before 1992, not after 1995 +.Pp +recreate databases from scratch +.br +.Nm mandb : +.dbI +.Pp +produce a catpath as opposed to a manpath +.br +.Nm manpath : +.dbI +.Pp +internal option for use by +.Xr catman 1 +.br +.Nm man : +.dbI +.Pp +reformat source page even if cat page exists +.br +.Nm man : +.man15e +.Pp +disable terminal color output in +.Xr grotty 1 +.br +.Nm groff : +.No groff-1.18.0 Pq Oct 4, 2001 +.Pp +recreate nroff versions from SGML sources +.br +.Nm catman : +.No Solaris 9-11 +.Pp +.Bq obsolete +postprocess with +.Xr col 1 +.br +.Nm man : +.At3 , +.At5 +.It Fl D +reset whatever was set with +.Ev MANOPT +.br +.Nm man : +.dbI +.Pp +print debugging info in addition to manual page +.br +.Nm man : +.man15e +.Pp +set default input encoding for +.Xr preconv 1 +.br +.Nm groff : +.No groff-1.20 Pq August 20, 2008 +.Pp +display all files added to +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.It Fl d +define a user-defined string +.br +.Nm groff : +.g04 +.Pp +print debugging information +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm manpath : +.Eaton ; +.Fx , No man-db +.br +.Nm apropos , whatis : +.dbI ; +.Fx +.br +.Nm mandb , catman : +.dbI +.Pp +remove and re-add a file to +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 2.7 Pq Feb 3, 2000 +.Pp +.Bq superseded by Fl l +interpret arguments as file names +.br +.Nm man : +.At3 , +.At5 +.It Fl E +inhibit all error messages +.br +.Nm groff : +.g04 +.Pp +select output encoding +.br +.Nm man : +.No man-db Pq Dec 23, 2001 +.It Fl e +preprocess with +.Xr eqn 7 +.br +.Nm man : +.At7 +.br +.Nm groff : +.g04 +.Pp +adjust text to left and right margins +.br +.Nm nroff : +.At7 +.Pp +use exact matching +.br +.Nm apropos , whatis : +.dbI +.Pp +restrict search by section extension +.br +.Nm man : +.No man-db-2.3.5 Pq April 21, 1995 +.It Fl F +use alternate font directory +.br +.Nm troff : +.Bx 4.2 Pq September 1983 +.br +.Nm groff : +.g04 +.Pp +preformat only, do not display +.br +.Nm man : +.No man-1.5g Pq April 7, 1999 +.Pp +force searching dirs, do not use index (default) +.br +.Nm man : +.No illumos , Solaris 9-11 +.It Fl f +.Xr whatis 1 +mode +.br +.Nm man : +.Bx4 , +.Eaton ; +.Ox , Fx , No man-db , man-1.6 +.br +.Nm apropos , whatis : +.No man-db Pq Dec 2, 2010 , +.Ox 5.7 Pq August 27, 2014 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +set the default font family +.br +.Nm groff : +.g04 +.Pp +force formatting even if cat page is newer +.br +.Nm catman : +.Fx Pq March 15, 1995 +.Pp +update only the entries for the given file +.br +.Nm mandb : +.No man-db Pq Feb 21, 2003 +.Pp +force rebuilding the database from scratch +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.Pp +locate manual page related to given file name +.br +.Nm man : +.No illumos , Solaris 9-11 +.Pp +.Bq obsolete hardware +do not feed out paper nor stop phototypesetter +.br +.Nm troff : +.At7 +.It Fl G +preprocess with +.Xr grap 1 +.br +.Nm groff : +.No groff-1.16 Pq May 1, 2000 +.It Fl g +produce a global manpath +.br +.Nm manpath : +.No man-db-2.2a7 Pq Nov 16, 1994 +.Pp +preprocess with +.Xr grn 1 +.br +.Nm groff : +.No groff-1.16 Pq Feb 20, 2000 +.Pp +.Bq obsolete hardware +output to a GCOS phototypesetter +.br +.Nm troff : +.At7 +.Pp +.Bq obsolete hardware +output to a DASI 300 terminal in 12-pitch mode +.br +.Nm man : +.PWB +.It Fl H +read hyphenation patterns from the given file +.br +.Nm groff : +.g04 +.Pp +produce HTML output +.br +.Nm man : +.No man-db-1.3.12 to 1.3.17 Pq not before 1996, not after 2001 +.Pp +use program to render HTML files as text +.br +.Nm man : +.No man-1.6 Pq June 24, 2005 +.It Fl h +print a help message and exit +.br +.Nm groff : +.g04 +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 +.br +.Nm manpath : +.Eaton ; +.Fx , No man-db +.br +.Nm apropos , whatis , mandb , catman : +.dbI +.Pp +display the SYNOPSIS lines only +.br +.Nm man : +.Bx 4.3 Net/2 Pq August 20, 1991 ; +.Ox , Nx +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq Sep 3, 2014 +.Pp +turn on HTML formatting +.br +.Nm apropos : +.Nx Pq Apr 2, 2013 +.Pp +.Bq obsolete +replace spaces by tabs in the output +.br +.Nm roff , nroff : +.At7 +.It Fl I +input file search path for +.Xr soelim 1 +.br +.Nm groff : +.No groff-1.12 Pq Sep 11, 1999 +.Pp +respect case when matching manual page names +.br +.Nm man , catman : +.No man-db Pq Apr 21, 2002 +.Pp +input options, in particular default operating system name +.br +.Nm mandoc : +.Ox 5.2 Pq May 24, 2012 +.br +.Nm man , apropos , whatis : +.Ox 5.7 Pq August 27, 2014 +.It Fl i +read standard input after the input files are exhausted +.br +.Nm nroff , troff : +.At7 +.br +.Nm groff : +.g04 +.Pp +ignore case when matching manual page names +.br +.Nm man , catman : +.No man-db Pq Apr 21, 2002 +.Pp +turn on terminal escape code formatting +.br +.Nm apropos : +.Nx Pq March 29, 2013 +.It Fl J +preprocess with +.Xr gideal 1 +.br +.Nm groff : +.No groff-1.22.3 Pq June 17, 2014 +.It Fl j +preprocess with +.Xr chem 1 +.br +.Nm groff : +.No groff-1.22 Pq Jan 22, 2011 +.It Fl K +source code full text search +.br +.Nm man : +.man15e , +.No man-db Pq June 28, 2009 ; +.No Solaris 11 +.Pp +input encoding +.br +.Nm groff : +.No groff-1.20 Pq Dec 31, 2005 +.br +.Nm man , apropos , whatis , mandoc : +.Ox 5.7 Pq Oct 30, 2014 +.It Fl k +.Xr apropos 1 +mode +.br +.Nm man : +.Bx4 , +.Eaton ; +.No POSIX , Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +ignore formatting errors +.br +.Nm catman : +.Nx Pq April 26, 1994 +.Pp +preprocess with +.Xr preconv 1 +.br +.Nm groff : +.No groff-1.20 Pq Dec 31, 2005 +.Pp +.Bq obsolete hardware +display on a Tektronix 4014 terminal +.br +.Nm man : +.At7 +.It Fl L +pass argument to the spooler +.br +.Nm groff : +.No groff-0.6 Pq Sep 14, 1990 +.Pp +use alternate +.Xr locale 1 +.br +.Nm man , apropos , whatis : +.No before man-db-2.2a13 Pq before Dec 15, 1994 +.Pp +print list of locales +.br +.Nm manpath : +.Fx Pq Nov 23, 1999 +.Pp +use +.Xr locale 1 +specified in the environment +.br +.Nm catman : +.Fx Pq May 18, 2002 +.It Fl l +spool the output +.br +.Nm groff : +.g04 +.Pp +interpret arguments as file names +.br +.Nm man : +.No before man-2.2a7 Pq before Nov 16, 1994 , +.Ox 5.7 Pq Aug 30, 2014 +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq Aug 30, 2014 +.Pp +do not trim output to the terminal width +.br +.Nm apropos , whatis : +.No man-db Pq Aug 19, 2007 +.Pp +only parse NAME sections +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.Pp +legacy mode: search Nm,Nd, no context or formatting +.br +.Nm apropos : +.Nx Pq March 29, 2013 +.Pp +list all manual pages matching name within the search path +.br +.Nm man : +.No illumos , Solaris 9-11 +.It Fl M +override manual page search path +.br +.Nm man : +.Bx43 , +.Eaton ; +.Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm apropos , whatis : +.Bx43 , +.No before man-db-2.2a14 Pq before Dec 16, 1994 ; +.Ox , No illumos +.br +.Nm catman : +.dbI ; +.Nx Pq July 27, 1993 , +.No Solaris 9-11 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +prepend to macro file search path +.br +.Nm groff : +.g04 +.Pp +do not show the context of the match +.br +.Nm apropos : +.Nx Pq May 22, 2016 +.It Fl m +specify input macro language +.br +.Nm nroff , troff : +.At7 +.br +.Nm groff : +.g04 +.br +.Nm mandoc : +.Ox 4.8 Pq April 6, 2009 +.Pp +augment manual page search path +.br +.Nm man , apropos , whatis : +.Bx 4.3 Reno Pq June 1990 ; +.Ox , Nx +.br +.Nm catman : +.Nx Pq Apr 4, 1999 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +override operating system +.br +.Nm man : +.Eaton ; +.No man-db , man-1.6 +.br +.Nm apropos , whatis , manpath : +.dbI +.Pp +override architecture +.br +.Nm man : +.Fx Pq Jan 11, 2002 +.Pp +show the context of the match +.br +.Nm apropos : +.Nx Pq May 22, 2016 +.It Fl N +do not allow newlines between +.Xr eqn 7 +delimiters +.br +.Nm groff : +.No groff-1.01 Pq Feb 21, 1991 +.It Fl n +specify a page number for the first page +.br +.Nm troff : +.At7 +.br +.Nm groff : +.g04 +.Pp +.Xr nroff 1 +output mode +.br +.Nm man : +.At7 +.Pp +do not create the +.Xr whatis 1 +database +.br +.Nm catman : +.Nx Pq July 27, 1993 +.Pp +print commands instead of executing them +.br +.Nm catman : +.Fx Pq May 18, 2002 , +.No Solaris 9-11 +.Pp +limit the number of results +.br +.Nm apropos : +.Nx Pq Feb 7, 2012 +.Pp +dry run simulating +.Xr mandoc.db 5 +creation +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.It Fl O +output options +.br +.Nm mandoc : +.Ox 4.8 Pq Oct 27, 2009 +.br +.Nm man , apropos , whatis : +.Ox 5.7 Pq August 27, 2014 +.It Fl o +select pages by numbers +.br +.Nm nroff , troff : +.At7 +.br +.Nm groff : +.g04 +.Pp +force use of non-localized manual pages +.br +.Nm man : +.Fx Pq June 7, 1999 +.Pp +optimize index for speed and disk space +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.It Fl P +pass argument to postprocessor +.br +.Nm groff : +.No groff-0.6 Pq Sep 14, 1990 +.Pp +use specified pager +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 +.Pp +turn on pager formatting +.br +.Nm apropos : +.Nx Pq Apr 2, 2013 +.It Fl p +preprocess with +.Xr pic 1 +.br +.Nm groff : +.g04 +.Pp +use the given list of preprocessors +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 +.Pp +dry run, display commands instead of executing them +.br +.Nm catman : +.Nx Pq July 27, 1993 , +.Fx Pq March 15, 1995 to May 18, 2002 , +.No Solaris 9-11 +.Pp +print warnings when building +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 2.7 Pq April 23, 2000 +.Pp +do not look for deleted manual pages +.br +.Nm mandb : +.No man-db Pq June 28, 2001 +.Pp +print the search path for manual pages +.br +.Nm man : +.Nx Pq June 14 , 2011 +.Pp +turn on pager formatting and pipe through pager +.br +.Nm apropos : +.Nx Pq Feb 7, 2012 +.Pp +.Bq obsolete hardware +set phototypesetter point size +.br +.Nm troff : +.At7 +.It Fl Q +print only fatal error messages +.br +.Nm makemandb : +.Nx Pq Aug 29, 2012 +.Pp +quick mode of +.Xr mandoc.db 5 +creation +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.It Fl q +invoke the simultaneous input-output mode of the .rd request +.br +.Nm nroff , troff : +.At7 +.Pp +issue no warnings +.br +.Nm manpath : +.Eaton ; +.Fx , No man-db +.br +.Nm mandb : +.dbI +.Pp +print only warnings and errors, no status updates +.br +.Nm makemandb : +.Nx Pq Aug 29, 2012 +.It Fl R +postprocess with +.Xr refer 1 +.br +.Nm groff : +.No groff-1.02 Pq June 2, 1991 +.Pp +recode to the specified encoding +.br +.Nm man : +.No man-db Pq Dec 31, 2007 +.It Fl r +set number register +.br +.Nm nroff , troff : +.At7 +.br +.Nm groff : +.g04 +.Pp +scan for and remove junk files +.br +.Nm catman : +.Fx Pq March 31, 1995 +.Pp +set +.Xr less 1 +prompt +.br +.Nm man : +.No man-db-2.3.5 Pq April 21, 1995 +.Pp +use regular expression matching +.br +.Nm apropos , whatis : +.No man-db-2.3.5 Pq April 21, 1995 +.Pp +turn off formatting +.br +.Nm apropos : +.Nx Pq Feb 10, 2013 +.Pp +check for formatting errors, do not display +.br +.Nm man : +.No illumos , Solaris 9-11 +.It Fl S +manual section search list +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 +.Pp +safer mode +.br +.Nm groff : +.No groff-1.10 Pq May 17, 1994 +.Pp +restrict architecture +.br +.Nm man : +.Ox 2.3 Pq March 9, 1998 , +.Nx Pq May 27, 2000 +.br +.Nm apropos : +.Ox 4.5 Pq Dec 24, 2008 , +.Nx Pq May 8, 2009 +.br +.Nm whatis : +.Ox 5.6 Pq April 18, 2014 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.It Fl s +preprocess with +.Xr soelim 1 +.br +.Nm groff : +.g04 +.Pp +silent mode, do not echo commands +.br +.Nm catman : +.Nx Pq April 26, 1994 +.Pp +restrict section +.br +.Nm makewhatis : +.man15g +.br +.Nm man : +.Ox 2.3 Pq March 9, 1998 , +.Nx Pq June 12, 2000 ; +.No illumos , Solaris 9-11 +.br +.Nm apropos : +.No man-db Pq Nov 16, 2003 , +.Ox 4.5 Pq Dec 24, 2008 , +.Nx Pq May 8, 2009 ; +.No illumos +.br +.Nm whatis : +.No man-db Pq Nov 16, 2003 , +.Ox 5.6 Pq April 18, 2014 ; +.No illumos +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +do not look for stray cats +.br +.Nm mandb : +.dbI +.Pp +.Bq SysV compat, recommends Fl S +manual section search list +.br +.Nm man : +.No man-db Pq Jan 1, 2008 +.Pp +.Bq superseded by Fl h +display the SYNOPSIS lines only +.br +.Nm man : +.PWB +.Pp +.Bq obsolete hardware +pause before each page for paper manipulation +.br +.Nm roff : +.At7 +.Pp +.Bq obsolete hardware +.Xr troff 1 +output mode, small format +.br +.Nm man : +.At3 , +.At5 +.It Fl T +select terminal output format +.br +.Nm nroff : +.At7 +.br +.Nm man : +.At3 , +.At5 , +.dbI , +.Ox 5.7 Pq August 27, 2014 +.br +.Nm groff : +.g04 +.br +.Nm mandoc : +.Ox 4.8 Pq April 6, 2009 +.br +.Nm apropos , whatis : +.Ox 5.7 Pq August 27, 2014 +.Pp +use UTF-8 for +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.Pp +.Bq superseded by Fl m +use other macro package +.br +.Nm man , catman : +.No Solaris 9-11 +.It Fl t +.Xr troff 1 +output mode +.br +.Nm man : +.PWB , +.At7 , +.Bx 2 Pq May 10, 1979 , +.At3 , +.At5 , +.Eaton ; +.Fx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm catman : +.No Solaris 9-11 +.Pp +preprocess with +.Xr tbl 7 +.br +.Nm groff : +.g04 +.Pp +check manual pages in the hierarchy +.br +.Nm mandb : +.No man-db-1.3.12 to 1.3.17 Pq not before 1996, not after 2001 +.Pp +check files for problems related to +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 2.7 Pq April 23, 2000 +.It Fl U +unsafe mode +.br +.Nm groff : +.No groff-1.12 Pq Dec 13, 1999 +.It Fl u +update database +.br +.Nm makewhatis : +.Pq not before 1992, not after 1995 +.Pp +create user databases only +.br +.Nm mandb : +.dbI +.Pp +update database cache (requires suid) +.br +.Nm man : +.No before man-db-2.2a10 Pq before Dec 6, 1994 +.Pp +remove files from +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 3.4 Pq July 9, 2003 +.It Fl V +print the pipeline on stdout instead of executing it +.br +.Nm groff : +.No groff-0.6 Pq Sep 2, 1990 +.Pp +print version information +.br +.Nm man , apropos , whatis , mandb , catman , manpath : +.dbI +.It Fl v +print version number +.br +.Nm groff : +.g04 +.Pp +verbose mode +.br +.Nm catman : +.Fx Pq March 15, 1995 +.br +.Nm makewhatis : +.man15g +.br +.Nm apropos , whatis : +.No man-db Pq Dec 29, 2002 +.Pp +print the name of every parsed file +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.Pp +.Bq obsolete hardware +produce output on the Versatec printer +.br +.Nm man : +.PWB +.It Fl W +disable the named warning +.br +.Nm groff : +.No groff-0.5 Pq August 14, 1990 +.Pp +list pathnames without additional information +.br +.Nm man : +.man15e +.Pp +list pathnames of cat files +.br +.Nm man : +.No man-db Pq Aug 13, 2002 +.Pp +minimum message level to display +.br +.Nm mandoc : +.Ox 4.8 Pq April 6, 2009 +.br +.Nm man , apropos , whatis : +.Ox 5.7 Pq August 27, 2014 +.It Fl w +list pathnames +.br +.Nm man : +.At7 , +.At3 , +.At5 , +.Eaton ; +.Ox , Fx , Nx , No man-db , man-1.6 +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +enable the named warning +.br +.Nm groff : +.No groff-0.5 Pq August 14, 1990 +.Pp +only create the +.Xr whatis 1 +database +.br +.Nm catman : +.Nx Pq July 27, 1993 , +.No Solaris 9-11 +.Pp +use wildcard matching +.br +.Nm apropos , whatis : +.No man-db-2.3.5 Pq April 21, 1995 +.Pp +use manpath obtained from man --path +.br +.Nm makewhatis : +.man15g +.Pp +update the +.Xr whatis 1 +database +.br +.Nm man : +.No illumos +.Pp +.Bq obsolete hardware +wait until the phototypesetter is available +.br +.Nm troff : +.At7 +.It Fl X +display with +.Xr gxditview 1 +.br +.Nm groff : +.No groff-1.06 Pq Sep 1, 1992 +.br +.Nm man : +.dbI +.It Fl y +use the non-compacted version of the macros +.br +.Nm man : +.At3 , +.At5 +.It Fl Z +do not run preprocessors +.br +.Nm groff : +.g04 +.br +.Nm man : +.No man-db-2.2a5 Pq Nov 10, 1994 +.It Fl z +suppress formatted output from +.Xr troff 1 , +print only error messages +.br +.Nm groff : +.g04 +.It Fl 7 +ASCII output mode +.br +.Nm man : +.No man-db-2.3.5 Pq April 21, 1995 +.It Fl \&? +print a help message and exit +.br +.Nm groff : +.g04 +.br +.Nm man , manpath : +.Eaton ; +.Fx , No man-db +.br +.Nm apropos , whatis , mandb , catman : +.dbI +.El +.Pp +Multi-letter options: +.Bl -tag -width Ds +.It Fl hp +.Bq obsolete hardware +output to a Hewlett Packard terminal +.br +.Nm man : +.PWB +.It Fl 12 +.Bq obsolete hardware +use 12-pitch for certain terminals +.br +.Nm man : +.At3 , +.At5 +.It Fl 450 +.Bq obsolete hardware +output to a DASI 450 terminal +.br +.Nm man : +.PWB +.El +.Pp +In +.At v3 , +.Xr man 1 +had no options. +.br +The syntax was: +.Sy man Ar name Op Ar section +.Pp +In +.At v4 , +.br +the syntax changed to: +.Sy man Oo Ar section Oc Op Ar name ... +.Sh AUTHORS +This information was assembled by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org +using +.Bl -bullet -compact +.It +the Unix Archive of the Unix Heritage Society +.It +the CSRG Archive CD-ROMs +.It +the +.Fx +SVN repository +.It +the +.Ox +CVS repository +.It +the +.Nx +CVS repository +.It +the GNU roff (groff) git repository +.It +the 4.3BSD-Net/2 groff CHANGES file (Oct 1990 to March 1991) +.It +the 4.3BSD-Net/2 groff ChangeLog file (July 1990 to March 1991) +.It +the man-db CVS and git repositories (since April 2001) +.It +the man-db NEWS file (April 1995 to Dec 2016) +.It +the man-db ChangeLog-2013 file (Nov 1994 to Dec 2013) +.It +release tarballs man-1.5g (July 1998) to man-1.5p (Jan 2005), +man-1.6 (June 2005), and man-1.6a to man-1.6g (Dec 2010) +.It +a makewhatis release tarball without version number from 1995 +.It +the illumos manual pages on the WWW +.It +and Solaris 11, SunOS 5.10, and SunOS 5.9 machines at opencsw.org. +.El Property changes on: vendor/mandoc/20190723/man.options.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_aux.h =================================================================== --- vendor/mandoc/20190723/mandoc_aux.h (nonexistent) +++ vendor/mandoc/20190723/mandoc_aux.h (revision 350350) @@ -0,0 +1,27 @@ +/* $Id: mandoc_aux.h,v 1.7 2017/06/12 19:05:47 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +int mandoc_asprintf(char **, const char *, ...) + __attribute__((__format__ (__printf__, 2, 3))); +void *mandoc_calloc(size_t, size_t); +void *mandoc_malloc(size_t); +void *mandoc_realloc(void *, size_t); +void *mandoc_reallocarray(void *, size_t, size_t); +void *mandoc_recallocarray(void *, size_t, size_t, size_t); +char *mandoc_strdup(const char *); +char *mandoc_strndup(const char *, size_t); Property changes on: vendor/mandoc/20190723/mandoc_aux.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_escape.3 =================================================================== --- vendor/mandoc/20190723/mandoc_escape.3 (nonexistent) +++ vendor/mandoc/20190723/mandoc_escape.3 (revision 350350) @@ -0,0 +1,367 @@ +.\" $Id: mandoc_escape.3,v 1.4 2017/07/04 23:40:01 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 4 2017 $ +.Dt MANDOC_ESCAPE 3 +.Os +.Sh NAME +.Nm mandoc_escape +.Nd parse roff escape sequences +.Sh SYNOPSIS +.In sys/types.h +.In mandoc.h +.Ft "enum mandoc_esc" +.Fo mandoc_escape +.Fa "const char **end" +.Fa "const char **start" +.Fa "int *sz" +.Fc +.Sh DESCRIPTION +This function scans a +.Xr roff 7 +escape sequence. +.Pp +An escape sequence consists of +.Bl -dash -compact -width 2n +.It +an initial backslash character +.Pq Sq \e , +.It +a single ASCII character called the escape sequence identifier, +.It +and, with only a few exceptions, an argument. +.El +.Pp +Arguments can be given in the following forms; some escape sequence +identifiers only accept some of these forms as specified below. +The first three forms are called the standard forms. +.Bl -tag -width 2n +.It \&In brackets: Ic \&[ Ns Ar argument Ns Ic \&] +The argument starts after the initial +.Sq \&[ , +ends before the final +.Sq \&] , +and the escape sequence ends with the final +.Sq \&] . +.It Two-character argument short form: Ic \&( Ns Ar ar +This form can only be used for arguments +consisting of exactly two characters. +It has the same effect as +.Ic \&[ Ns Ar ar Ns Ic \&] . +.It One-character argument short form: Ar a +This form can only be used for arguments +consisting of exactly one character. +It has the same effect as +.Ic \&[ Ns Ar a Ns Ic \&] . +.It Delimited form: Ar C Ns Ar argument Ns Ar C +The argument starts after the initial delimiter character +.Ar C , +ends before the next occurrence of the delimiter character +.Ar C , +and the escape sequence ends with that second +.Ar C . +Some escape sequences allow arbitrary characters +.Ar C +as quoting characters, some restrict the range of characters +that can be used as quoting characters. +.El +.Pp +Upon function entry, +.Fa end +is expected to point to the escape sequence identifier. +The values passed in as +.Fa start +and +.Fa sz +are ignored and overwritten. +.Pp +By design, this function cannot handle those +.Xr roff 7 +escape sequences that require in-place expansion, in particular +user-defined strings +.Ic \e* , +number registers +.Ic \en , +width measurements +.Ic \ew , +and numerical expression control +.Ic \eB . +These are handled by +.Fn roff_res , +a private preprocessor function called from +.Fn roff_parseln , +see the file +.Pa roff.c . +.Pp +The function +.Fn mandoc_escape +is used +.Bl -dash -compact -width 2n +.It +recursively by itself, because some escape sequence arguments can +in turn contain other escape sequences, +.It +for error detection internally by the +.Xr roff 7 +parser part of the +.Xr mandoc 3 +library, see the file +.Pa roff.c , +.It +above all externally by the +.Xr mandoc 1 +formatting modules, in particular +.Fl Tascii +and +.Fl Thtml , +for formatting purposes, see the files +.Pa term.c +and +.Pa html.c , +.It +and rarely externally by high-level utilities using the mandoc library, +for example +.Xr makewhatis 8 , +to purge escape sequences from text. +.El +.Sh RETURN VALUES +Upon function return, the pointer +.Fa end +is set to the character after the end of the escape sequence, +such that the calling higher-level parser can easily continue. +.Pp +For escape sequences taking an argument, the pointer +.Fa start +is set to the beginning of the argument and +.Fa sz +is set to the length of the argument. +For escape sequences not taking an argument, +.Fa start +is set to the character after the end of the sequence and +.Fa sz +is set to 0. +Both +.Fa start +and +.Fa sz +may be +.Dv NULL ; +in that case, the argument and the length are not returned. +.Pp +For sequences taking an argument, the function +.Fn mandoc_escape +returns one of the following values: +.Bl -tag -width 2n +.It Dv ESCAPE_FONT +The escape sequence +.Ic \ef +taking an argument in standard form: +.Ic \ef[ , \ef( , \ef Ns Ar a . +Two-character arguments starting with the character +.Sq C +are reduced to one-character arguments by skipping the +.Sq C . +More specific values are returned for the most commonly used arguments: +.Bl -column "argument" "ESCAPE_FONTITALIC" +.It argument Ta return value +.It Cm R No or Cm 1 Ta Dv ESCAPE_FONTROMAN +.It Cm I No or Cm 2 Ta Dv ESCAPE_FONTITALIC +.It Cm B No or Cm 3 Ta Dv ESCAPE_FONTBOLD +.It Cm P Ta Dv ESCAPE_FONTPREV +.It Cm BI Ta Dv ESCAPE_FONTBI +.El +.It Dv ESCAPE_SPECIAL +The escape sequence +.Ic \eC +taking an argument delimited with the single quote character +and, as a special exception, the escape sequences +.Em not +having an identifier, that is, those where the argument, in standard +form, directly follows the initial backslash: +.Ic \eC' , \e[ , \e( , \e Ns Ar a . +Note that the one-character argument short form can only be used for +argument characters that do not clash with escape sequence identifiers. +.Pp +If the argument matches one of the forms described below under +.Dv ESCAPE_UNICODE , +that value is returned instead. +.Pp +The +.Dv ESCAPE_SPECIAL +special character escape sequences can be rendered using the functions +.Fn mchars_spec2cp +and +.Fn mchars_spec2str +described in the +.Xr mchars_alloc 3 +manual. +.It Dv ESCAPE_UNICODE +Escape sequences of the same format as described above under +.Dv ESCAPE_SPECIAL , +but with an argument of the forms +.Ic u Ns Ar XXXX , +.Ic u Ns Ar YXXXX , +or +.Ic u10 Ns Ar XXXX +where +.Ar X +and +.Ar Y +are hexadecimal digits and +.Ar Y +is not zero: +.Ic \eC'u , \e[u . +As a special exception, +.Fa start +is set to the character after the +.Ic u , +and the +.Fa sz +return value does not include the +.Ic u +either. +.Pp +Such Unicode character escape sequences can be rendered using the function +.Fn mchars_num2uc +described in the +.Xr mchars_alloc 3 +manual. +.It Dv ESCAPE_NUMBERED +The escape sequence +.Ic \eN +followed by a delimited argument. +The delimiter character is arbitrary except that digits cannot be used. +If a digit is encountered instead of the opening delimiter, that +digit is considered to be the argument and the end of the sequence, and +.Dv ESCAPE_IGNORE +is returned. +.Pp +Such ASCII character escape sequences can be rendered using the function +.Fn mchars_num2char +described in the +.Xr mchars_alloc 3 +manual. +.It Dv ESCAPE_OVERSTRIKE +The escape sequence +.Ic \eo +followed by an argument delimited by an arbitrary character. +.It Dv ESCAPE_IGNORE +.Bl -bullet -width 2n +.It +The escape sequence +.Ic \es +followed by an argument in standard form or by an argument delimited +by the single quote character: +.Ic \es' , \es[ , \es( , \es Ns Ar a . +As a special exception, an optional +.Sq + +or +.Sq \- +character is allowed after the +.Sq s +for all forms. +.It +The escape sequences +.Ic \eF , +.Ic \eg , +.Ic \ek , +.Ic \eM , +.Ic \em , +.Ic \en , +.Ic \eV , +and +.Ic \eY +followed by an argument in standard form. +.It +The escape sequences +.Ic \eA , +.Ic \eb , +.Ic \eD , +.Ic \eR , +.Ic \eX , +and +.Ic \eZ +followed by an argument delimited by an arbitrary character. +.It +The escape sequences +.Ic \eH , +.Ic \eh , +.Ic \eL , +.Ic \el , +.Ic \eS , +.Ic \ev , +and +.Ic \ex +followed by an argument delimited by a character that cannot occur +in numerical expressions. +However, if any character that can occur in numerical expressions +is found instead of a delimiter, the sequence is considered to end +with that character, and +.Dv ESCAPE_ERROR +is returned. +.El +.It Dv ESCAPE_ERROR +Escape sequences taking an argument but not matching any of the above patterns. +In particular, that happens if the end of the logical input line +is reached before the end of the argument. +.El +.Pp +For sequences that do not take an argument, the function +.Fn mandoc_escape +returns one of the following values: +.Bl -tag -width 2n +.It Dv ESCAPE_SKIPCHAR +The escape sequence +.Qq \ez . +.It Dv ESCAPE_NOSPACE +The escape sequence +.Qq \ec . +.It Dv ESCAPE_IGNORE +The escape sequences +.Qq \ed +and +.Qq \eu . +.El +.Sh FILES +This function is implemented in +.Pa mandoc.c . +.Sh SEE ALSO +.Xr mchars_alloc 3 , +.Xr mandoc_char 7 , +.Xr roff 7 +.Sh HISTORY +This function has been available since mandoc 1.11.2. +.Sh AUTHORS +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +.An Ingo Schwarze Aq Mt schwarze@openbsd.org +.Sh BUGS +The function doesn't cleanly distinguish between sequences that are +valid and supported, valid and ignored, valid and unsupported, +syntactically invalid, or undefined. +For sequences that are ignored or unsupported, it doesn't tell +whether that deficiency is likely to cause major formatting problems +and/or loss of document content. +The function is already rather complicated and still parses some +sequences incorrectly. +. +.ig +For these sequences, the list given below specifies a starting string +and either the length of the argument or an ending character. +The argument starts after the starting string. +In the former case, the sequence ends with the end of the argument. +In the latter case, the argument ends before the ending character, +and the sequence ends with the ending character. +.. Property changes on: vendor/mandoc/20190723/mandoc_escape.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_xr.c =================================================================== --- vendor/mandoc/20190723/mandoc_xr.c (nonexistent) +++ vendor/mandoc/20190723/mandoc_xr.c (revision 350350) @@ -0,0 +1,121 @@ +/* $Id: mandoc_xr.c,v 1.3 2017/07/02 21:18:29 schwarze Exp $ */ +/* + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <sys/types.h> + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "mandoc_xr.h" + +static struct ohash *xr_hash = NULL; +static struct mandoc_xr *xr_first = NULL; +static struct mandoc_xr *xr_last = NULL; + +static void mandoc_xr_clear(void); + + +static void +mandoc_xr_clear(void) +{ + struct mandoc_xr *xr; + unsigned int slot; + + if (xr_hash == NULL) + return; + for (xr = ohash_first(xr_hash, &slot); xr != NULL; + xr = ohash_next(xr_hash, &slot)) + free(xr); + ohash_delete(xr_hash); +} + +void +mandoc_xr_reset(void) +{ + if (xr_hash == NULL) + xr_hash = mandoc_malloc(sizeof(*xr_hash)); + else + mandoc_xr_clear(); + mandoc_ohash_init(xr_hash, 5, + offsetof(struct mandoc_xr, hashkey)); + xr_first = xr_last = NULL; +} + +int +mandoc_xr_add(const char *sec, const char *name, int line, int pos) +{ + struct mandoc_xr *xr, *oxr; + const char *pend; + size_t ssz, nsz, tsz; + unsigned int slot; + int ret; + uint32_t hv; + + if (xr_hash == NULL) + return 0; + + ssz = strlen(sec) + 1; + nsz = strlen(name) + 1; + tsz = ssz + nsz; + xr = mandoc_malloc(sizeof(*xr) + tsz); + xr->next = NULL; + xr->sec = xr->hashkey; + xr->name = xr->hashkey + ssz; + xr->line = line; + xr->pos = pos; + xr->count = 1; + memcpy(xr->sec, sec, ssz); + memcpy(xr->name, name, nsz); + + pend = xr->hashkey + tsz; + hv = ohash_interval(xr->hashkey, &pend); + slot = ohash_lookup_memory(xr_hash, xr->hashkey, tsz, hv); + if ((oxr = ohash_find(xr_hash, slot)) == NULL) { + ohash_insert(xr_hash, slot, xr); + if (xr_first == NULL) + xr_first = xr; + else + xr_last->next = xr; + xr_last = xr; + return 0; + } + + oxr->count++; + ret = (oxr->line == -1) ^ (xr->line == -1); + if (xr->line == -1) + oxr->line = -1; + free(xr); + return ret; +} + +struct mandoc_xr * +mandoc_xr_get(void) +{ + return xr_first; +} + +void +mandoc_xr_free(void) +{ + mandoc_xr_clear(); + free(xr_hash); + xr_hash = NULL; +} Property changes on: vendor/mandoc/20190723/mandoc_xr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_xr.h =================================================================== --- vendor/mandoc/20190723/mandoc_xr.h (nonexistent) +++ vendor/mandoc/20190723/mandoc_xr.h (revision 350350) @@ -0,0 +1,31 @@ +/* $Id: mandoc_xr.h,v 1.3 2017/07/02 21:18:29 schwarze Exp $ */ +/* + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct mandoc_xr { + struct mandoc_xr *next; + char *sec; + char *name; + int line; /* Or -1 for this page's own names. */ + int pos; + int count; + char hashkey[]; +}; + +void mandoc_xr_reset(void); +int mandoc_xr_add(const char *, const char *, int, int); +struct mandoc_xr *mandoc_xr_get(void); +void mandoc_xr_free(void); Property changes on: vendor/mandoc/20190723/mandoc_xr.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/msec.in =================================================================== --- vendor/mandoc/20190723/msec.in (nonexistent) +++ vendor/mandoc/20190723/msec.in (revision 350350) @@ -0,0 +1,34 @@ +/* $Id: msec.in,v 1.8 2017/06/24 17:37:06 schwarze Exp $ */ +/* + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * These are all possible manual-section macros and what they correspond + * to when rendered as the volume title. + * + * Be sure to escape strings. + */ + +LINE("1", "General Commands Manual") +LINE("2", "System Calls Manual") +LINE("3", "Library Functions Manual") +LINE("3p", "Perl Library Manual") +LINE("4", "Device Drivers Manual") +LINE("5", "File Formats Manual") +LINE("6", "Games Manual") +LINE("7", "Miscellaneous Information Manual") +LINE("8", "System Manager\'s Manual") +LINE("9", "Kernel Developer\'s Manual") Property changes on: vendor/mandoc/20190723/msec.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/soelim.1 =================================================================== --- vendor/mandoc/20190723/soelim.1 (nonexistent) +++ vendor/mandoc/20190723/soelim.1 (revision 350350) @@ -0,0 +1,86 @@ +.\" $Id: soelim.1,v 1.5 2017/07/04 23:40:01 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd $Mdocdate: July 4 2017 $ +.Dt SOELIM 1 +.Os +.Sh NAME +.Nm soelim +.Nd interpret .so requests in manpages +.Sh SYNOPSIS +.Nm +.Op Fl Crtv +.Op Fl I Ar dir +.Op Ar files ... +.Sh DESCRIPTION +.Nm +reads +.Ar files +lines by lines. +.Pp +If a line starts by: +.Dq .so anotherfile +it replace the line by processing +.Dq anotherfile . +Otherwise the line is printed to stdout. +.Bl -tag -width "-I dir" +.It Fl C +Recognise +.Em .so +when not followed by a space character. +.It Fl r +Compatibility with GNU groff's +.Nm soelim +(does nothing). +.It Fl t +Compatibility with GNU groff's +.Nm soelim +(does nothing). +.It Fl v +Compatibility with GNU groff's +.Nm soelim +(does nothing). +.It Fl I Ar dir +This option specify directories where +.Nm +searches for files (both those on the command line and those named in +.Dq .so +directive.) +This options may be specified multiple times. +The directories will be searched in the order specified. +.El +.Pp +The files are always searched first in the current directory. +.Pp +A file specified with an absolute path will be opened directly without +performing a search. +.Sh SEE ALSO +.Xr mandoc 1 +.Sh AUTHORS +This version of the +.Nm +utility was written by +.An Baptiste Daroussin Aq Mt bapt@freebsd.org . Property changes on: vendor/mandoc/20190723/soelim.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-recallocarray.c =================================================================== --- vendor/mandoc/20190723/test-recallocarray.c (nonexistent) +++ vendor/mandoc/20190723/test-recallocarray.c (revision 350350) @@ -0,0 +1,11 @@ +#include <stdlib.h> + +int +main(void) +{ + void *p; + + if ((p = calloc(2, 2)) == NULL) + return 1; + return !recallocarray(p, 2, 3, 2); +} Property changes on: vendor/mandoc/20190723/test-recallocarray.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/catman.8 =================================================================== --- vendor/mandoc/20190723/catman.8 (nonexistent) +++ vendor/mandoc/20190723/catman.8 (revision 350350) @@ -0,0 +1,186 @@ +.\" $Id: catman.8,v 1.8 2017/03/18 19:56:01 schwarze Exp $ +.\" +.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: March 18 2017 $ +.Dt CATMAN 8 +.Os +.Sh NAME +.Nm catman +.Nd format all manual pages below a directory +.Sh SYNOPSIS +.Nm catman +.Op Fl I Cm os Ns = Ns Ar name +.Op Fl T Ar output +.Ar srcdir dstdir +.Sh DESCRIPTION +The +.Nm +utility assumes that all files below +.Ar srcdir +are manual pages in +.Xr mdoc 7 +and +.Xr man 7 +format and formats all of them, storing the formatted versions in +the same relative paths below +.Ar dstdir . +Subdirectories of +.Ar dstdir +are created as needed. +Existing files are not explicitly deleted, but possibly overwritten. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl I Cm os Ns = Ns Ar name +Override the default operating system +.Ar name +for the +.Xr mdoc 7 +.Ic \&Os +and for the +.Xr man 7 +.Ic TH +macro. +.It Fl T Ar output +Output format. +The +.Ar output +argument can be +.Cm ascii , +.Cm utf8 , +or +.Cm html ; +see +.Xr mandoc 1 . +In +.Cm html +output mode, the +.Cm fragment +output option is implied. +Other output options are not supported. +.El +.Sh IMPLEMENTATION NOTES +Since this version avoids +.Xr fork 2 +and +.Xr exec 3 +overhead and uses the much faster +.Sy mandoc +parsers and formatters rather than +.Sy groff , +it may be about one order of magnitude faster than other +.Nm +implementations. +.Sh EXIT STATUS +.Ex -std +.Pp +Possible errors include: +.Bl -bullet +.It +missing, invalid, or excessive command line arguments +.It +failure to change the current working directory to +.Ar srcdir +.It +failure to open +.Ar dstdir +.It +communication failure with +.Xr mandocd 8 +.It +resource exhaustion, for example file descriptor, process table, +or memory exhaustion +.El +.Pp +Except for memory exhaustion and similar system-level failures, +failures while trying to open, read, parse, or format individual +manual pages, to save individual formatted files to the file system, +or even to create directories do not cause +.Nm +to return an error exit status. +In such cases, +.Nm +will simply continue with the next file or subdirectory. +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr mandocd 8 +.Sh HISTORY +A +.Nm +utility first appeared in +.Fx 1.0 . +Other, incompatible implementations appeared in +.Nx 1.0 +and in +.Sy man-db No 2.2 . +.Pp +This version appeared in version 1.14.1 of the +.Sy mandoc +toolkit. +.Sh AUTHORS +.An -nosplit +The first +.Nm +implementation was a short shell script by +.An Christoph Robitschko +in July 1993. +.Pp +The +.Nx +implementations were written by +.An J. T. Conklin Aq Mt jtc@netbsd.org +in 1993, +.An Christian E. Hopps Aq Mt chopps@netbsd.org +in 1994, +and +.An Dante Profeta Aq Mt dante@netbsd.org +in 1999; the +.Sy man-db +implementation by +.An Graeme W. Wilford +in 1994; and the +.Fx +implementations by +.An Wolfram Schneider Aq Mt wosch@freebsd.org +in 1995 and +.An John Rochester Aq Mt john@jrochester.org +in 2002. +.Pp +The concept of the present version was designed and implemented by +.An Michael Stapelberg Aq Mt stapelberg@debian.org +in 2017. +Option and argument handling and directory iteration was added by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . +.Sh CAVEATS +All versions of +.Nm +are incompatible with each other because each caters to the needs +of a specific operating system, for example regarding directory +structures and file naming conventions. +.Pp +This version is more flexible than the others in so far as it does +not assume any particular directory structure or naming convention. +That flexibility comes at the price of not being able to change the +names and relative paths of the source files when reusing them to +store the formatted files, of not supporting any configuration file +formats or environment variables, and of being unable to scan for +and remove junk files in +.Ar dstdir . +.Pp +Currently, +.Nm +always reformats each page, even if the formatted version is newer +than the source version. Property changes on: vendor/mandoc/20190723/catman.8 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/cgi.h.example =================================================================== --- vendor/mandoc/20190723/cgi.h.example (nonexistent) +++ vendor/mandoc/20190723/cgi.h.example (revision 350350) @@ -0,0 +1,7 @@ +/* Example compile-time configuration file for man.cgi(8). */ + +#define SCRIPT_NAME "cgi-bin/man.cgi" +#define MAN_DIR "/man" +#define CSS_DIR "" +#define CUSTOMIZE_TITLE "Manual pages with mandoc" +#define COMPAT_OLDURI Yes Index: vendor/mandoc/20190723/makewhatis.8 =================================================================== --- vendor/mandoc/20190723/makewhatis.8 (nonexistent) +++ vendor/mandoc/20190723/makewhatis.8 (revision 350350) @@ -0,0 +1,228 @@ +.\" $Id: makewhatis.8,v 1.6 2017/05/17 22:27:12 schwarze Exp $ +.\" +.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2011, 2012, 2014, 2017 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: May 17 2017 $ +.Dt MAKEWHATIS 8 +.Os +.Sh NAME +.Nm makewhatis +.Nd index UNIX manuals +.Sh SYNOPSIS +.Nm +.Op Fl aDnpQ +.Op Fl T Cm utf8 +.Op Fl C Ar file +.Nm +.Op Fl aDnpQ +.Op Fl T Cm utf8 +.Ar dir ... +.Nm +.Op Fl DnpQ +.Op Fl T Cm utf8 +.Fl d Ar dir +.Op Ar +.Nm +.Op Fl Dnp +.Op Fl T Cm utf8 +.Fl u Ar dir +.Op Ar +.Nm +.Op Fl DQ +.Fl t Ar +.Sh DESCRIPTION +The +.Nm +utility extracts keywords from +.Ux +manuals and indexes them in a database for fast retrieval by +.Xr apropos 1 , +.Xr whatis 1 , +and +.Xr man 1 Ns 's +.Fl k +option. +.Pp +By default, +.Nm +creates a database in each +.Ar dir +using the files +.Sm off +.Sy man Ar section Li / +.Op Ar arch Li / +.Ar title . section +.Sm on +and +.Sm off +.Sy cat Ar section Li / +.Op Ar arch Li / +.Ar title . Sy 0 +.Sm on +in that directory. +Existing databases are replaced. +If a directory contains no manual pages, no database is created in that +directory. +If +.Ar dir +is not provided, +.Nm +uses the default paths stipulated by +.Xr man.conf 5 . +.Pp +The arguments are as follows: +.Bl -tag -width "-C file" +.It Fl a +Use all directories and files found below +.Ar dir ... . +.It Fl C Ar file +Specify an alternative configuration +.Ar file +in +.Xr man.conf 5 +format. +.It Fl D +Display all files added or removed to the index. +With a second +.Fl D , +also show all keywords added for each file. +.It Fl d Ar dir +Merge (remove and re-add) +.Ar +to the database in +.Ar dir . +.It Fl n +Do not create or modify any database; scan and parse only, +and print manual page names and descriptions to standard output. +.It Fl p +Print warnings about potential problems with manual pages +to the standard error output. +.It Fl Q +Quickly build reduced-size databases +by reading only the NAME sections of manuals. +The resulting databases will usually contain names and descriptions only. +.It Fl T Cm utf8 +Use UTF-8 encoding instead of ASCII for strings stored in the databases. +.It Fl t Ar +Check the given +.Ar files +for potential problems. +Implies +.Fl a , +.Fl n , +and +.Fl p . +All diagnostic messages are printed to the standard output; +the standard error output is not used. +.It Fl u Ar dir +Remove +.Ar +from the database in +.Ar dir . +If that causes the database to become empty, also delete the database file. +.El +.Pp +If fatal parse errors are encountered while parsing, the offending file +is printed to stderr, omitted from the index, and the parse continues +with the next input file. +.Sh ENVIRONMENT +.Bl -tag -width MANPATH +.It Ev MANPATH +A colon-separated list of directories to create databases in. +Ignored if a +.Ar dir +argument or the +.Fl t +option is specified. +.El +.Sh FILES +.Bl -tag -width Ds +.It Pa mandoc.db +A database of manpages relative to the directory of the file. +This file is portable across architectures and systems, so long as the +manpage hierarchy it indexes does not change. +.It Pa /etc/man.conf +The default +.Xr man 1 +configuration file. +.El +.Sh EXIT STATUS +The +.Nm +utility exits with one of the following values: +.Pp +.Bl -tag -width Ds -compact +.It 0 +No errors occurred. +.It 5 +Invalid command line arguments were specified. +No input files have been read. +.It 6 +An operating system error occurred, for example memory exhaustion or an +error accessing input files. +Such errors cause +.Nm +to exit at once, possibly in the middle of parsing or formatting a file. +The output databases are corrupt and should be removed. +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr whatis 1 , +.Xr man.conf 5 +.Sh HISTORY +A +.Nm +utility first appeared in +.Bx 2 . +It was rewritten in +.Xr perl 1 +for +.Ox 2.7 +and in C for +.Ox 5.6 . +.Pp +The +.Ar dir +argument first appeared in +.Nx 1.0 ; +the options +.Fl dpt +in +.Ox 2.7 ; +the option +.Fl u +in +.Ox 3.4 ; +and the options +.Fl aCDnQT +in +.Ox 5.6 . +.Sh AUTHORS +.An -nosplit +.An Bill Joy +wrote the original +.Bx +.Nm +in February 1979, +.An Marc Espie +started the Perl version in 2000, +and the current version of +.Nm +was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +and +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: vendor/mandoc/20190723/makewhatis.8 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/man.cgi.3 =================================================================== --- vendor/mandoc/20190723/man.cgi.3 (nonexistent) +++ vendor/mandoc/20190723/man.cgi.3 (revision 350350) @@ -0,0 +1,310 @@ +.\" $Id: man.cgi.3,v 1.4 2017/03/15 13:18:53 schwarze Exp $ +.\" +.\" Copyright (c) 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: March 15 2017 $ +.Dt MAN.CGI 3 +.Os +.Sh NAME +.Nm man.cgi +.Nd internals of the CGI program to search and display manual pages +.Sh DESCRIPTION +The source code of +.Xr man.cgi 8 +is organized in four levels: +.Pp +.Bl -enum -compact +.It +.Sx Top level +.It +.Sx Page generators +.It +.Sx Result generators +.It +.Sx Utility routines +.El +.Ss Top level +The top level of +.Xr man.cgi 8 +consists of the +.Fn main +program and a few parser routines. +.Bl -tag -width 1n +.It Ft int Fn main void +The main program +.Bl -dash -compact +.It +limits execution time; +.It +changes to +.Dv MAN_DIR , +the data directory containing all the manual trees; +.It +calls +.Fn parse_manpath_conf ; +.It +if +.Ev PATH_INFO +is empty, calls +.Fn parse_query_string ; +otherwise, +calls +.Fn parse_path_info ; +.It +validates the manpath and the architecture; +.It +calls the appropriate one among the +.Sx Page generators . +.El +.It Ft void Fn parse_manpath_conf "struct req *req" +Parses and validates +.Pa manpath.conf +and fills +.Va req->p +and +.Va req->psz . +.It Ft void Fn parse_path_info "struct req *req" "const char *path" +Parses and validates +.Ev PATH_INFO , +clears +.Va req->isquery , +and fills +.Va req->q . +.It Ft void Fn parse_query_string "struct req *req" "const char *qs" +Parses and validates +.Ev QUERY_STRING , +sets +.Va req->isquery , +and fills +.Va req->q . +This function is the only user of the utility functions +.Fn http_decode +and +.Fn set_query_attr . +.El +.Ss Page generators +The purpose of each page generator is to print a complete HTML page, +starting with the HTTP headers and continuing to the page footer. +Before starting HTML output with +.Fn resp_begin_html , +some page generators do some preparatory work, for example to decide +which page to show. +Each page generator ends with a call to +.Fn resp_end_html . +.Bl -tag -width 1n +.It Ft void Fn pg_show "struct req *req" "const char *fullpath" +This page generator is used when +.Ev PATH_INFO +contains the complete path to a manual page including manpath, +section directory, optional architecture subdirectory, manual name +and section number suffix. +It validates the manpath, changes into it, validate the filename, +and then calls +.Fn resp_begin_html , +.Fn resp_searchform , +.Fn resp_show , +and +.Fn resp_end_html +in that order. +.It Ft void Fn pg_search "const struct req *req" +This page generator is used when +.Ev PATH_INFO +contains a search query in short format or when +.Ev PATH_INFO +is empty and a +.Ev QUERY_STRING +is provided. +If possible, requests using +.Ev QUERY_STRING +are redirected to URIs using +.Ev PATH_INFO +by calling +.Fn pg_redirect . +Otherwise, it changes into the manpath and calls +.Xr mansearch 3 . +Depending on the result, it calls either +.Fn pg_noresult +or +.Fn pg_searchres . +.It Ft void Fn pg_redirect "const struct req *req" "const char *name" +This function is special in so far as it does not print an HTML page, +but only an HTTP 303 response with a Location: of the form: +.Sm off +.No http:// +.Ar host Ns / +.Op Ar scriptname Ns / +.Op Ar manpath Ns / +.Op Ar arch Ns / +.Fa name +.Op Pf . Ar sec +.Sm on +.It Ft void Fn pg_noresult "const struct req *req" "const char *msg" +This function calls +.Fn resp_begin_html , +.Fn resp_searchform , +prints the +.Fa msg +passed to it, and calls +.Fn resp_end_html . +.It Ft void Fn pg_searchres "const struct req *req" "struct manpage *r"\ + "size_t sz" +This function first validates the filenames found. +If +.Ev QUERY_STRING +was used and there is exactly one result, +it writes an HTTP redirect to that result. +Otherwise, it writes an HTML result page beginning with +.Fn resp_begin_html +and +.Fn resp_searchform . +If there is more than one result, it writes a list of links +to all the results. +If it was a +.Xr man 1 +rather than an +.Xr apropos 1 +query or if there is only one single result, it calls +.Fn resp_show . +Finally, it calls +.Fn resp_end_html . +.It Ft void Fn pg_index "const struct req *req" +This page generator is used when +.Ev PATH_INFO +and +.Ev QUERY_STRING +are both empty. +It calls +.Fn resp_begin_html +and +.Fn resp_searchform , +writes links to help pages, and calls +.Fn resp_end_html . +.It Ft void Fn pg_error_badrequest "const char *msg" +This page generator is used when +.Fn main +or +.Fn pg_show +detect an invalid URI. +It calls +.Fn resp_begin_html , +prints the +.Fa msg +provided, and calls +.Fn resp_end_html . +.It Ft void Fn pg_error_internal void +This page generator is used by various functions when errors are +detected in the +.Pa manpath.conf +configuration file, in +.Xr mandoc.db 5 +databases, in the +.Xr mandoc 3 +parser, in file system permissions, or when setting up timeouts. +It calls +.Fn resp_begin_html , +prints +.Qq "Internal Server Error" , +and calls +.Fn resp_end_html . +Before calling +.Fn pg_error_internal , +call +.Xr warn 3 +or +.Xr warnx 3 +to log the reason of the error to the +.Xr httpd 8 +server log file. +.El +.Ss Result generators +The purpose of result generators is to print a chunk of HTML code. +When they print untrusted strings or characters, +.Fn html_print +and +.Fn html_putchar +are used. +The highest level result generators are: +.Bl -tag -width 1n +.It Ft void Fn resp_begin_html "int code" "const char *msg" "const char *file" +This generator calls +.Fn resp_begin_http +to print the HTTP headers, then prints the HTML header up to the +opening tag of the <body> element, then copies the file +.Pa header.html +to the output, if it exists and is readable. +If +.Fa file +is not +.Dv NULL , +it is used for the <title> element. +.It Ft void Fn resp_searchform "const struct req *req" "enum focus focus" +This generator prints a search form, filling it with data +from the provided request object. +If the +.Fa focus +argument is +.Dv FOCUS_QUERY , +it sets the document's autofocus to the query input box. +.It Ft void Fn resp_show "const struct req *req" "const char *file" +This wrapper dispatches to either +.Fn resp_catman +or +.Fn resp_format , +depending on whether +.Ar file +starts with +.Pa cat +or +.Pa man , +respectively. +.It Ft void Fn resp_catman "const struct req *req" "const char *file" +This generator translates a preformatted, backspace-encoded manual +page to HTML and prints it to the output. +.It Ft void Fn resp_format "const struct req *req" "const char *file" +This generator formats a manual page on the standard output, +using the functions documented in +.Xr mchars_alloc 3 +and +.Xr mandoc 3 . +.It Ft void Fn resp_end_html void +This generator copies the file +.Pa footer.html +to the output, if it exists and is readable, +and closes the <body> and <html> elements. +.El +.Ss Utility routines +These functions take a string and return 1 if it is valid, or 0 otherwise. +.Bl -tag -width 1n +.It Ft int Fn validate_urifrag "const char *frag" +Checks that the string only contains alphanumeric ASCII characters, +dashes, dots, slashes, and underscores. +.It Ft int Fn validate_manpath "const struct req *req" "const char* manpath" +Checks that the string is either +.Qq mandoc +or one of the manpaths configured in +.Pa manpath.conf . +.It Ft int Fn validate_filename "const char *file" +Checks that the string starts with +.Qq man +or +.Qq cat +and does not ascend to parent directories. +.El +.Sh SEE ALSO +.Xr mandoc 3 , +.Xr mansearch 3 , +.Xr mchars_alloc 3 , +.Xr mandoc.db 5 , +.Xr man.cgi 8 Property changes on: vendor/mandoc/20190723/man.cgi.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandocd.8 =================================================================== --- vendor/mandoc/20190723/mandocd.8 (nonexistent) +++ vendor/mandoc/20190723/mandocd.8 (revision 350350) @@ -0,0 +1,198 @@ +.\" $Id: mandocd.8,v 1.2 2017/03/18 19:56:01 schwarze Exp $ +.\" +.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: March 18 2017 $ +.Dt MANDOCD 8 +.Os +.Sh NAME +.Nm mandocd +.Nd server process to format manual pages in batch mode +.Sh SYNOPSIS +.Nm mandocd +.Op Fl I Cm os Ns = Ns Ar name +.Op Fl T Ar output +.Ar socket_fd +.Sh DESCRIPTION +The +.Nm +utility formats many manual pages without requiring +.Xr fork 2 +and +.Xr exec 3 +overhead in between. +It does not require listing all the manuals to be formatted on the +command line, and it supports writing each formatted manual to its +own file descriptor. +.Pp +This server requires that a connected UNIX domain +.Xr socket 2 +is already present at +.Xr exec 3 +time. +Consequently, it cannot be started from the +.Xr sh 1 +command line because the shell cannot supply such a socket. +Typically, the socket is created by the parent process using +.Xr socketpair 2 +before calling +.Xr fork 2 +and +.Xr exec 3 +on +.Nm . +The parent process will pass the file descriptor number as an argument to +.Xr exec 3 , +formatted as a decimal ASCII-encoded integer. +See +.Xr catman 8 +for a typical implementation of a parent process. +.Pp +.Nm +loops reading one-byte messages with +.Xr recvmsg 2 +from the file descriptor number +.Ar socket_fd . +It ignores the byte read and only uses the out-of-band auxiliary +.Vt struct cmsghdr +control data, typically supplied by the calling process using +.Xr CMSG_FIRSTHDR 3 . +The parent process is expected to pass three file descriptors +with each dummy byte. +The first one is used for +.Xr mdoc 7 +or +.Xr man 7 +input, the second one for formatted output, and the third one +for error output. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl I Cm os Ns = Ns Ar name +Override the default operating system +.Ar name +for the +.Xr mdoc 7 +.Ic \&Os +and for the +.Xr man 7 +.Ic TH +macro. +.It Fl T Ar output +Output format. +The +.Ar output +argument can be +.Cm ascii , +.Cm utf8 , +or +.Cm html ; +see +.Xr mandoc 1 . +In +.Cm html +output mode, the +.Cm fragment +output option is implied. +Other output options are not supported. +.El +.Pp +After exhausting one input file descriptor, all three file descriptors +are closed before reading the next dummy byte and control message. +.Pp +When a zero-byte message is read, when the +.Ar socket_fd +is closed by the parent process, +or when an error occurs, +.Nm +exits. +.Sh EXIT STATUS +.Ex -std +.Pp +A zero-byte message or a closed +.Ar socket_fd +is considered success. +Possible errors include: +.Bl -bullet +.It +missing, invalid, or excessive +.Xr exec 3 +arguments +.It +.Xr recvmsg 2 +failure, for example due to +.Er EMSGSIZE +.It +missing or unexpected control data, in particular a +.Fa cmsg_level +in the +.Vt struct cmsghdr +that differs from +.Dv SOL_SOCKET , +a +.Fa cmsg_type +that differs from +.Dv SCM_RIGHTS , +or a +.Fa cmsg_len +that is not three times the size of an +.Vt int +.It +invalid file descriptors passed in the +.Xr CMSG_DATA 3 +.It +resource exhaustion, in particular +.Xr dup 2 +or +.Xr malloc 3 +failure +.El +.Pp +Except for memory exhaustion and similar system-level failures, +parsing and formatting errors do not cause +.Nm +to return an error exit status. +Even after severe parsing errors, +.Nm +will simply accept and process the next input file descriptor. +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr mandoc 3 , +.Xr catman 8 +.Sh HISTORY +The +.Nm +utility appeared in version 1.14.1 or the +.Sy mandoc +toolkit. +.Sh AUTHORS +.An -nosplit +The concept was designed and implemented by +.An Michael Stapelberg Aq Mt stapelberg@debian.org . +The +.Xr mandoc 3 +glue needed to make it a stand-alone process was added by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . +.Sh CAVEATS +If the parsed manual pages contain +.Xr roff 7 +.Pf . Ic so +requests, +.Nm +needs to be started with the current working directory set to the +root of the manual page tree. +Avoid starting it in directories that contain secret files in any +subdirectories, in particular in the user starting it has read +access to these secret files. Property changes on: vendor/mandoc/20190723/mandocd.8 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mansearch.3 =================================================================== --- vendor/mandoc/20190723/mansearch.3 (nonexistent) +++ vendor/mandoc/20190723/mansearch.3 (revision 350350) @@ -0,0 +1,120 @@ +.\" $Id: mansearch.3,v 1.5 2017/03/30 22:22:05 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: March 30 2017 $ +.Dt MANSEARCH 3 +.Os +.Sh NAME +.Nm mansearch +.Nd search manual page databases +.Sh SYNOPSIS +.In stdint.h +.In manconf.h +.In mansearch.h +.Ft int +.Fo mansearch +.Fa "const struct mansearch *search" +.Fa "const struct manpaths *paths" +.Fa "int argc" +.Fa "char *argv[]" +.Fa "struct manpage **res" +.Fa "size_t *sz" +.Fc +.Sh DESCRIPTION +The +.Fn mansearch +function returns information about manuals matching a search query from a +.Xr mandoc.db 5 +database. +.Pp +The query arguments are as follows: +.Bl -tag -width Ds +.It Fa "const struct mansearch *search" +Search options, defined in +.In mansearch.h . +.It Fa "const struct manpaths *paths" +Directories to be searched, defined in +.In manconf.h . +.It Fa "int argc" , "char *argv[]" +Search criteria, usually taken from the command line. +.El +.Pp +The output arguments are as follows: +.Bl -tag -width Ds +.It Fa "struct manpage **res" +Returns a pointer to an array of result structures defined in +.In mansearch.h . +The user is expected to call +.Xr free 3 +on the +.Va file , +.Va names , +and +.Va output +fields of all structures, as well as the +.Fa res +array itself. +.It Fa "size_t *sz" +Returns the number of result structures contained in +.Fa res . +.El +.Sh IMPLEMENTATION NOTES +For each manual page tree, the search is done in two steps. +In the first step, a list of pages matching the search criteria is built. +In the second step, the requested information about these pages is +retrieved from the database and assembled into the +.Fa res +array. +.Pp +All function mentioned here are defined in the file +.Pa mansearch.c . +.Ss Finding matches +Command line parsing is done by the function +.Fn exprcomp +building a singly linked list of +.Vt expr +structures, using the helper functions +.Fn expr_and +and +.Fn exprterm . +.Ss Assembling the results +The names, sections, and architectures of the manuals found +are assembled into the +.Va names +field of the result structure by the function +.Fn buildnames . +.Sh FILES +.Bl -tag -width mandoc.db -compact +.It Pa mandoc.db +The manual page database. +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr mandoc.db 5 , +.Xr makewhatis 8 +.Sh HISTORY +The +.Fn mansearch +subsystem first appeared in +.Ox 5.6 . +.Sh AUTHORS +.An -nosplit +A module to search manual page databases was first written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +in 2011, at first using the Berkeley DB; +he rewrote it for SQLite3 in 2012, and +.An Ingo Schwarze Aq Mt schwarze@openbsd.org +removed the dependency on SQLite3 in 2016. Property changes on: vendor/mandoc/20190723/mansearch.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/catman.c =================================================================== --- vendor/mandoc/20190723/catman.c (nonexistent) +++ vendor/mandoc/20190723/catman.c (revision 350350) @@ -0,0 +1,260 @@ +/* $Id: catman.c,v 1.21 2017/02/18 12:24:24 schwarze Exp $ */ +/* + * Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org> + * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#if HAVE_CMSG_XPG42 +#define _XPG4_2 +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#if HAVE_ERR +#include <err.h> +#endif +#include <errno.h> +#include <fcntl.h> +#if HAVE_FTS +#include <fts.h> +#else +#include "compat_fts.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +int process_manpage(int, int, const char *); +int process_tree(int, int); +void run_mandocd(int, const char *, const char *) + __attribute__((__noreturn__)); +ssize_t sock_fd_write(int, int, int, int); +void usage(void) __attribute__((__noreturn__)); + + +void +run_mandocd(int sockfd, const char *outtype, const char* defos) +{ + char sockfdstr[10]; + + if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1) + err(1, "snprintf"); + if (defos == NULL) + execlp("mandocd", "mandocd", "-T", outtype, + sockfdstr, (char *)NULL); + else + execlp("mandocd", "mandocd", "-T", outtype, + "-I", defos, sockfdstr, (char *)NULL); + err(1, "exec"); +} + +ssize_t +sock_fd_write(int fd, int fd0, int fd1, int fd2) +{ + const struct timespec timeout = { 0, 10000000 }; /* 0.01 s */ + struct msghdr msg; + struct iovec iov; + union { + struct cmsghdr cmsghdr; + char control[CMSG_SPACE(3 * sizeof(int))]; + } cmsgu; + struct cmsghdr *cmsg; + int *walk; + ssize_t sz; + unsigned char dummy[1] = {'\0'}; + + iov.iov_base = dummy; + iov.iov_len = sizeof(dummy); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_control = cmsgu.control; + msg.msg_controllen = sizeof(cmsgu.control); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + walk = (int *)CMSG_DATA(cmsg); + *(walk++) = fd0; + *(walk++) = fd1; + *(walk++) = fd2; + + /* + * It appears that on some systems, sendmsg(3) + * may return EAGAIN even in blocking mode. + * Seen for example on Oracle Solaris 11.2. + * The sleeping time was chosen by experimentation, + * to neither cause more than a handful of retries + * in normal operation nor unnecessary delays. + */ + for (;;) { + if ((sz = sendmsg(fd, &msg, 0)) != -1 || + errno != EAGAIN) + break; + nanosleep(&timeout, NULL); + } + return sz; +} + +int +process_manpage(int srv_fd, int dstdir_fd, const char *path) +{ + int in_fd, out_fd; + int irc; + + if ((in_fd = open(path, O_RDONLY)) == -1) { + warn("open(%s)", path); + return 0; + } + + if ((out_fd = openat(dstdir_fd, path, + O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { + warn("openat(%s)", path); + close(in_fd); + return 0; + } + + irc = sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO); + + close(in_fd); + close(out_fd); + + if (irc < 0) { + warn("sendmsg"); + return -1; + } + return 0; +} + +int +process_tree(int srv_fd, int dstdir_fd) +{ + FTS *ftsp; + FTSENT *entry; + const char *argv[2]; + const char *path; + + argv[0] = "."; + argv[1] = (char *)NULL; + + if ((ftsp = fts_open((char * const *)argv, + FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) { + warn("fts_open"); + return -1; + } + + while ((entry = fts_read(ftsp)) != NULL) { + path = entry->fts_path + 2; + switch (entry->fts_info) { + case FTS_F: + if (process_manpage(srv_fd, dstdir_fd, path) == -1) { + fts_close(ftsp); + return -1; + } + break; + case FTS_D: + if (*path != '\0' && + mkdirat(dstdir_fd, path, S_IRWXU | S_IRGRP | + S_IXGRP | S_IROTH | S_IXOTH) == -1 && + errno != EEXIST) { + warn("mkdirat(%s)", path); + (void)fts_set(ftsp, entry, FTS_SKIP); + } + break; + case FTS_DP: + break; + default: + warnx("%s: not a regular file", path); + break; + } + } + + fts_close(ftsp); + return 0; +} + +int +main(int argc, char **argv) +{ + const char *defos, *outtype; + int srv_fds[2]; + int dstdir_fd; + int opt; + pid_t pid; + + defos = NULL; + outtype = "ascii"; + while ((opt = getopt(argc, argv, "I:T:")) != -1) { + switch (opt) { + case 'I': + defos = optarg; + break; + case 'T': + outtype = optarg; + break; + default: + usage(); + } + } + + if (argc > 0) { + argc -= optind; + argv += optind; + } + if (argc != 2) + usage(); + + if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1) + err(1, "socketpair"); + + pid = fork(); + switch (pid) { + case -1: + err(1, "fork"); + case 0: + close(srv_fds[0]); + run_mandocd(srv_fds[1], outtype, defos); + default: + break; + } + close(srv_fds[1]); + + if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1) + err(1, "open(%s)", argv[1]); + + if (chdir(argv[0]) == -1) + err(1, "chdir(%s)", argv[0]); + + return process_tree(srv_fds[0], dstdir_fd) == -1 ? 1 : 0; +} + +void +usage(void) +{ + fprintf(stderr, "usage: %s [-I os=name] [-T output] " + "srcdir dstdir\n", BINM_CATMAN); + exit(1); +} Property changes on: vendor/mandoc/20190723/catman.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_fts.c =================================================================== --- vendor/mandoc/20190723/compat_fts.c (nonexistent) +++ vendor/mandoc/20190723/compat_fts.c (revision 350350) @@ -0,0 +1,701 @@ +#include "config.h" + +#if HAVE_FTS + +int dummy; + +#else + +/* $Id: compat_fts.c,v 1.14 2017/02/18 12:24:24 schwarze Exp $ */ +/* $OpenBSD: fts.c,v 1.56 2016/09/21 04:38:56 guenther Exp $ */ + +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/stat.h> +#include <sys/types.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "compat_fts.h" + +#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) + +static FTSENT *fts_alloc(FTS *, const char *, size_t); +static FTSENT *fts_build(FTS *); +static void fts_lfree(FTSENT *); +static void fts_load(FTS *, FTSENT *); +static size_t fts_maxarglen(char * const *); +static void fts_padjust(FTS *, FTSENT *); +static int fts_palloc(FTS *, size_t); +static FTSENT *fts_sort(FTS *, FTSENT *, int); +static unsigned short fts_stat(FTS *, FTSENT *); + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +FTS * +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT **, const FTSENT **)) +{ + FTS *sp; + FTSENT *p, *root; + int nitems; + FTSENT *parent, *prev; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* At least one path must be specified. */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream */ + if ((sp = calloc(1, sizeof(FTS))) == NULL) + return (NULL); + sp->fts_compar = compar; + sp->fts_options = options; + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAXIMUM(fts_maxarglen(argv), PATH_MAX))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Allocate/initialize root(s). */ + for (root = prev = NULL, nitems = 0; *argv; ++argv, ++nitems) { + if ((p = fts_alloc(sp, *argv, strlen(*argv))) == NULL) + goto mem3; + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + root = p; + else + prev->fts_link = p; + prev = p; + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + if (nitems == 0) + free(parent); + + return (sp); + +mem3: fts_lfree(root); + free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS *sp, FTSENT *p) +{ + size_t len; + char *cp; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +fts_close(FTS *sp) +{ + FTSENT *freep, *p; + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Free up child linked list, sort array, path buffer, stream ptr.*/ + if (sp->fts_child) + fts_lfree(sp->fts_child); + free(sp->fts_array); + free(sp->fts_path); + free(sp); + + return (0); +} + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +FTSENT * +fts_read(FTS *sp) +{ + FTSENT *p, *tmp; + int instr; + char *t; + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child) { + /* nothing */ + } else if ((sp->fts_child = fts_build(sp)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link)) { + free(tmp); + + /* + * If reached the top, return to the original directory (or + * the root of the tree), and load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) + goto next; + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + free(tmp); + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +int +fts_set(FTS *sp, FTSENT *p, int instr) +{ + if (instr && instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +fts_build(FTS *sp) +{ + struct dirent *dp; + FTSENT *p, *head; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + size_t dlen, len, maxlen; + int nitems, level, doadjust; + int saved_errno; + char *cp; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ + if ((dirp = opendir(cur->fts_accpath)) == NULL) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + return (NULL); + } + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + cp = sp->fts_path + len; + *cp++ = '/'; + len++; + maxlen = sp->fts_pathlen - len; + + /* + * fts_level is signed so we must prevent it from wrapping + * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL. + */ + level = cur->fts_level; + if (level < FTS_MAXLEVEL) + level++; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { + if (ISDOT(dp->d_name)) + continue; + +#if HAVE_DIRENT_NAMLEN + dlen = dp->d_namlen; +#else + dlen = strlen(dp->d_name); +#endif + + if (!(p = fts_alloc(sp, dp->d_name, dlen))) + goto mem1; + if (dlen >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, dlen + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = saved_errno; + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + + p->fts_level = level; + p->fts_parent = sp->fts_cur; + p->fts_pathlen = len + dlen; + if (p->fts_pathlen < len) { + /* + * If we wrap, free up the current structure and + * the structures already allocated, then error + * out with ENAMETOOLONG. + */ + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } + + /* Build a file name for fts_stat to stat. */ + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, p->fts_namelen + 1); + /* Stat it. */ + p->fts_info = fts_stat(sp, p); + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + if (dirp) + (void)closedir(dirp); + + /* + * If realloc() changed the address of the path, adjust the + * addresses for the rest of the tree and the dir list. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (len == sp->fts_pathlen || nitems == 0) + --cp; + *cp = '\0'; + + /* If didn't find anything, return NULL. */ + if (!nitems) { + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static unsigned short +fts_stat(FTS *sp, FTSENT *p) +{ + FTSENT *t; + dev_t dev; + ino_t ino; + struct stat *sbp; + + /* If user needs stat info, stat buffer already allocated. */ + sbp = p->fts_statp; + + if (lstat(p->fts_accpath, sbp)) { + p->fts_errno = errno; + memset(sbp, 0, sizeof(struct stat)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, int nitems) +{ + FTSENT **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + struct _ftsent **a; + + sp->fts_nitems = nitems + 40; + if ((a = reallocarray(sp->fts_array, + sp->fts_nitems, sizeof(FTSENT *))) == NULL) { + free(sp->fts_array); + sp->fts_array = NULL; + sp->fts_nitems = 0; + return (head); + } + sp->fts_array = a; + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort(sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, const char *name, size_t namelen) +{ + FTSENT *p; + size_t len; + + len = sizeof(FTSENT) + namelen; + if ((p = calloc(1, len)) == NULL) + return (NULL); + + p->fts_path = sp->fts_path; + p->fts_namelen = namelen; + p->fts_instr = FTS_NOINSTR; + p->fts_statp = malloc(sizeof(struct stat)); + if (p->fts_statp == NULL) { + free(p); + return (NULL); + } + memcpy(p->fts_name, name, namelen); + + return (p); +} + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* Free a linked list of structures. */ + while ((p = head)) { + head = head->fts_link; + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than PATH_MAX, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t more) +{ + char *p; + + /* + * Check for possible wraparound. + */ + more += 256; + if (sp->fts_pathlen + more < sp->fts_pathlen) { + free(sp->fts_path); + sp->fts_path = NULL; + errno = ENAMETOOLONG; + return (1); + } + sp->fts_pathlen += more; + p = realloc(sp->fts_path, sp->fts_pathlen); + if (p == NULL) { + free(sp->fts_path); + sp->fts_path = NULL; + return (1); + } + sp->fts_path = p; + return (0); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, FTSENT *head) +{ + FTSENT *p; + char *addr = sp->fts_path; + +#define ADJUST(p) { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +#endif Property changes on: vendor/mandoc/20190723/compat_fts.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dba.c =================================================================== --- vendor/mandoc/20190723/dba.c (nonexistent) +++ vendor/mandoc/20190723/dba.c (revision 350350) @@ -0,0 +1,508 @@ +/* $Id: dba.c,v 1.10 2017/02/17 14:43:54 schwarze Exp $ */ +/* + * Copyright (c) 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Allocation-based version of the mandoc database, for read-write access. + * The interface is defined in "dba.h". + */ +#include "config.h" + +#include <sys/types.h> +#if HAVE_ENDIAN +#include <endian.h> +#elif HAVE_SYS_ENDIAN +#include <sys/endian.h> +#elif HAVE_NTOHL +#include <arpa/inet.h> +#endif +#include <errno.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "mansearch.h" +#include "dba_write.h" +#include "dba_array.h" +#include "dba.h" + +struct macro_entry { + struct dba_array *pages; + char value[]; +}; + +static void *prepend(const char *, char); +static void dba_pages_write(struct dba_array *); +static int compare_names(const void *, const void *); +static int compare_strings(const void *, const void *); + +static struct macro_entry + *get_macro_entry(struct ohash *, const char *, int32_t); +static void dba_macros_write(struct dba_array *); +static void dba_macro_write(struct ohash *); +static int compare_entries(const void *, const void *); + + +/*** top-level functions **********************************************/ + +struct dba * +dba_new(int32_t npages) +{ + struct dba *dba; + struct ohash *macro; + int32_t im; + + dba = mandoc_malloc(sizeof(*dba)); + dba->pages = dba_array_new(npages, DBA_GROW); + dba->macros = dba_array_new(MACRO_MAX, 0); + for (im = 0; im < MACRO_MAX; im++) { + macro = mandoc_malloc(sizeof(*macro)); + mandoc_ohash_init(macro, 4, + offsetof(struct macro_entry, value)); + dba_array_set(dba->macros, im, macro); + } + return dba; +} + +void +dba_free(struct dba *dba) +{ + struct dba_array *page; + struct ohash *macro; + struct macro_entry *entry; + unsigned int slot; + + dba_array_FOREACH(dba->macros, macro) { + for (entry = ohash_first(macro, &slot); entry != NULL; + entry = ohash_next(macro, &slot)) { + dba_array_free(entry->pages); + free(entry); + } + ohash_delete(macro); + free(macro); + } + dba_array_free(dba->macros); + + dba_array_undel(dba->pages); + dba_array_FOREACH(dba->pages, page) { + dba_array_free(dba_array_get(page, DBP_NAME)); + dba_array_free(dba_array_get(page, DBP_SECT)); + dba_array_free(dba_array_get(page, DBP_ARCH)); + free(dba_array_get(page, DBP_DESC)); + dba_array_free(dba_array_get(page, DBP_FILE)); + dba_array_free(page); + } + dba_array_free(dba->pages); + + free(dba); +} + +/* + * Write the complete mandoc database to disk; the format is: + * - One integer each for magic and version. + * - One pointer each to the macros table and to the final magic. + * - The pages table. + * - The macros table. + * - And at the very end, the magic integer again. + */ +int +dba_write(const char *fname, struct dba *dba) +{ + int save_errno; + int32_t pos_end, pos_macros, pos_macros_ptr; + + if (dba_open(fname) == -1) + return -1; + dba_int_write(MANDOCDB_MAGIC); + dba_int_write(MANDOCDB_VERSION); + pos_macros_ptr = dba_skip(1, 2); + dba_pages_write(dba->pages); + pos_macros = dba_tell(); + dba_macros_write(dba->macros); + pos_end = dba_tell(); + dba_int_write(MANDOCDB_MAGIC); + dba_seek(pos_macros_ptr); + dba_int_write(pos_macros); + dba_int_write(pos_end); + if (dba_close() == -1) { + save_errno = errno; + unlink(fname); + errno = save_errno; + return -1; + } + return 0; +} + + +/*** functions for handling pages *************************************/ + +/* + * Create a new page and append it to the pages table. + */ +struct dba_array * +dba_page_new(struct dba_array *pages, const char *arch, + const char *desc, const char *file, enum form form) +{ + struct dba_array *page, *entry; + + page = dba_array_new(DBP_MAX, 0); + entry = dba_array_new(1, DBA_STR | DBA_GROW); + dba_array_add(page, entry); + entry = dba_array_new(1, DBA_STR | DBA_GROW); + dba_array_add(page, entry); + if (arch != NULL && *arch != '\0') { + entry = dba_array_new(1, DBA_STR | DBA_GROW); + dba_array_add(entry, (void *)arch); + } else + entry = NULL; + dba_array_add(page, entry); + dba_array_add(page, mandoc_strdup(desc)); + entry = dba_array_new(1, DBA_STR | DBA_GROW); + dba_array_add(entry, prepend(file, form)); + dba_array_add(page, entry); + dba_array_add(pages, page); + return page; +} + +/* + * Add a section, architecture, or file name to an existing page. + * Passing the NULL pointer for the architecture makes the page MI. + * In that case, any earlier or later architectures are ignored. + */ +void +dba_page_add(struct dba_array *page, int32_t ie, const char *str) +{ + struct dba_array *entries; + char *entry; + + entries = dba_array_get(page, ie); + if (ie == DBP_ARCH) { + if (entries == NULL) + return; + if (str == NULL || *str == '\0') { + dba_array_free(entries); + dba_array_set(page, DBP_ARCH, NULL); + return; + } + } + if (*str == '\0') + return; + dba_array_FOREACH(entries, entry) { + if (ie == DBP_FILE && *entry < ' ') + entry++; + if (strcmp(entry, str) == 0) + return; + } + dba_array_add(entries, (void *)str); +} + +/* + * Add an additional name to an existing page. + */ +void +dba_page_alias(struct dba_array *page, const char *name, uint64_t mask) +{ + struct dba_array *entries; + char *entry; + char maskbyte; + + if (*name == '\0') + return; + maskbyte = mask & NAME_MASK; + entries = dba_array_get(page, DBP_NAME); + dba_array_FOREACH(entries, entry) { + if (strcmp(entry + 1, name) == 0) { + *entry |= maskbyte; + return; + } + } + dba_array_add(entries, prepend(name, maskbyte)); +} + +/* + * Return a pointer to a temporary copy of instr with inbyte prepended. + */ +static void * +prepend(const char *instr, char inbyte) +{ + static char *outstr = NULL; + static size_t outlen = 0; + size_t newlen; + + newlen = strlen(instr) + 1; + if (newlen > outlen) { + outstr = mandoc_realloc(outstr, newlen + 1); + outlen = newlen; + } + *outstr = inbyte; + memcpy(outstr + 1, instr, newlen); + return outstr; +} + +/* + * Write the pages table to disk; the format is: + * - One integer containing the number of pages. + * - For each page, five pointers to the names, sections, + * architectures, description, and file names of the page. + * MI pages write 0 instead of the architecture pointer. + * - One list each for names, sections, architectures, descriptions and + * file names. The description for each page ends with a NUL byte. + * For all the other lists, each string ends with a NUL byte, + * and the last string for a page ends with two NUL bytes. + * - To assure alignment of following integers, + * the end is padded with NUL bytes up to a multiple of four bytes. + */ +static void +dba_pages_write(struct dba_array *pages) +{ + struct dba_array *page, *entry; + int32_t pos_pages, pos_end; + + pos_pages = dba_array_writelen(pages, 5); + dba_array_FOREACH(pages, page) { + dba_array_setpos(page, DBP_NAME, dba_tell()); + entry = dba_array_get(page, DBP_NAME); + dba_array_sort(entry, compare_names); + dba_array_writelst(entry); + } + dba_array_FOREACH(pages, page) { + dba_array_setpos(page, DBP_SECT, dba_tell()); + entry = dba_array_get(page, DBP_SECT); + dba_array_sort(entry, compare_strings); + dba_array_writelst(entry); + } + dba_array_FOREACH(pages, page) { + if ((entry = dba_array_get(page, DBP_ARCH)) != NULL) { + dba_array_setpos(page, DBP_ARCH, dba_tell()); + dba_array_sort(entry, compare_strings); + dba_array_writelst(entry); + } else + dba_array_setpos(page, DBP_ARCH, 0); + } + dba_array_FOREACH(pages, page) { + dba_array_setpos(page, DBP_DESC, dba_tell()); + dba_str_write(dba_array_get(page, DBP_DESC)); + } + dba_array_FOREACH(pages, page) { + dba_array_setpos(page, DBP_FILE, dba_tell()); + dba_array_writelst(dba_array_get(page, DBP_FILE)); + } + pos_end = dba_align(); + dba_seek(pos_pages); + dba_array_FOREACH(pages, page) + dba_array_writepos(page); + dba_seek(pos_end); +} + +static int +compare_names(const void *vp1, const void *vp2) +{ + const char *cp1, *cp2; + int diff; + + cp1 = *(const char * const *)vp1; + cp2 = *(const char * const *)vp2; + return (diff = *cp2 - *cp1) ? diff : + strcasecmp(cp1 + 1, cp2 + 1); +} + +static int +compare_strings(const void *vp1, const void *vp2) +{ + const char *cp1, *cp2; + + cp1 = *(const char * const *)vp1; + cp2 = *(const char * const *)vp2; + return strcmp(cp1, cp2); +} + +/*** functions for handling macros ************************************/ + +/* + * In the hash table for a single macro, look up an entry by + * the macro value or add an empty one if it doesn't exist yet. + */ +static struct macro_entry * +get_macro_entry(struct ohash *macro, const char *value, int32_t np) +{ + struct macro_entry *entry; + size_t len; + unsigned int slot; + + slot = ohash_qlookup(macro, value); + if ((entry = ohash_find(macro, slot)) == NULL) { + len = strlen(value) + 1; + entry = mandoc_malloc(sizeof(*entry) + len); + memcpy(&entry->value, value, len); + entry->pages = dba_array_new(np, DBA_GROW); + ohash_insert(macro, slot, entry); + } + return entry; +} + +/* + * In addition to get_macro_entry(), add multiple page references, + * converting them from the on-disk format (byte offsets in the file) + * to page pointers in memory. + */ +void +dba_macro_new(struct dba *dba, int32_t im, const char *value, + const int32_t *pp) +{ + struct macro_entry *entry; + const int32_t *ip; + int32_t np; + + np = 0; + for (ip = pp; *ip; ip++) + np++; + + entry = get_macro_entry(dba_array_get(dba->macros, im), value, np); + for (ip = pp; *ip; ip++) + dba_array_add(entry->pages, dba_array_get(dba->pages, + be32toh(*ip) / 5 / sizeof(*ip) - 1)); +} + +/* + * In addition to get_macro_entry(), add one page reference, + * directly taking the in-memory page pointer as an argument. + */ +void +dba_macro_add(struct dba_array *macros, int32_t im, const char *value, + struct dba_array *page) +{ + struct macro_entry *entry; + + if (*value == '\0') + return; + entry = get_macro_entry(dba_array_get(macros, im), value, 1); + dba_array_add(entry->pages, page); +} + +/* + * Write the macros table to disk; the format is: + * - The number of macro tables (actually, MACRO_MAX). + * - That number of pointers to the individual macro tables. + * - The individual macro tables. + */ +static void +dba_macros_write(struct dba_array *macros) +{ + struct ohash *macro; + int32_t im, pos_macros, pos_end; + + pos_macros = dba_array_writelen(macros, 1); + im = 0; + dba_array_FOREACH(macros, macro) { + dba_array_setpos(macros, im++, dba_tell()); + dba_macro_write(macro); + } + pos_end = dba_tell(); + dba_seek(pos_macros); + dba_array_writepos(macros); + dba_seek(pos_end); +} + +/* + * Write one individual macro table to disk; the format is: + * - The number of entries in the table. + * - For each entry, two pointers, the first one to the value + * and the second one to the list of pages. + * - A list of values, each ending in a NUL byte. + * - To assure alignment of following integers, + * padding with NUL bytes up to a multiple of four bytes. + * - A list of pointers to pages, each list ending in a 0 integer. + */ +static void +dba_macro_write(struct ohash *macro) +{ + struct macro_entry **entries, *entry; + struct dba_array *page; + int32_t *kpos, *dpos; + unsigned int ie, ne, slot; + int use; + int32_t addr, pos_macro, pos_end; + + /* Temporary storage for filtering and sorting. */ + + ne = ohash_entries(macro); + entries = mandoc_reallocarray(NULL, ne, sizeof(*entries)); + kpos = mandoc_reallocarray(NULL, ne, sizeof(*kpos)); + dpos = mandoc_reallocarray(NULL, ne, sizeof(*dpos)); + + /* Build a list of non-empty entries and sort it. */ + + ne = 0; + for (entry = ohash_first(macro, &slot); entry != NULL; + entry = ohash_next(macro, &slot)) { + use = 0; + dba_array_FOREACH(entry->pages, page) + if (dba_array_getpos(page)) + use = 1; + if (use) + entries[ne++] = entry; + } + qsort(entries, ne, sizeof(*entries), compare_entries); + + /* Number of entries, and space for the pointer pairs. */ + + dba_int_write(ne); + pos_macro = dba_skip(2, ne); + + /* String table. */ + + for (ie = 0; ie < ne; ie++) { + kpos[ie] = dba_tell(); + dba_str_write(entries[ie]->value); + } + dba_align(); + + /* Pages table. */ + + for (ie = 0; ie < ne; ie++) { + dpos[ie] = dba_tell(); + dba_array_FOREACH(entries[ie]->pages, page) + if ((addr = dba_array_getpos(page))) + dba_int_write(addr); + dba_int_write(0); + } + pos_end = dba_tell(); + + /* Fill in the pointer pairs. */ + + dba_seek(pos_macro); + for (ie = 0; ie < ne; ie++) { + dba_int_write(kpos[ie]); + dba_int_write(dpos[ie]); + } + dba_seek(pos_end); + + free(entries); + free(kpos); + free(dpos); +} + +static int +compare_entries(const void *vp1, const void *vp2) +{ + const struct macro_entry *ep1, *ep2; + + ep1 = *(const struct macro_entry * const *)vp1; + ep2 = *(const struct macro_entry * const *)vp2; + return strcmp(ep1->value, ep2->value); +} Property changes on: vendor/mandoc/20190723/dba.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dbm_map.c =================================================================== --- vendor/mandoc/20190723/dbm_map.c (nonexistent) +++ vendor/mandoc/20190723/dbm_map.c (revision 350350) @@ -0,0 +1,194 @@ +/* $Id: dbm_map.c,v 1.8 2017/02/17 14:43:54 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Low-level routines for the map-based version + * of the mandoc database, for read-only access. + * The interface is defined in "dbm_map.h". + */ +#include "config.h" + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#if HAVE_ENDIAN +#include <endian.h> +#elif HAVE_SYS_ENDIAN +#include <sys/endian.h> +#elif HAVE_NTOHL +#include <arpa/inet.h> +#endif +#if HAVE_ERR +#include <err.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <regex.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "mansearch.h" +#include "dbm_map.h" +#include "dbm.h" + +static struct stat st; +static char *dbm_base; +static int ifd; +static int32_t max_offset; + +/* + * Open a disk-based database for read-only access. + * Validate the file format as far as it is not mandoc-specific. + * Return 0 on success. Return -1 and set errno on failure. + */ +int +dbm_map(const char *fname) +{ + int save_errno; + const int32_t *magic; + + if ((ifd = open(fname, O_RDONLY)) == -1) + return -1; + if (fstat(ifd, &st) == -1) + goto fail; + if (st.st_size < 5) { + warnx("dbm_map(%s): File too short", fname); + errno = EFTYPE; + goto fail; + } + if (st.st_size > INT32_MAX) { + errno = EFBIG; + goto fail; + } + if ((dbm_base = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, + ifd, 0)) == MAP_FAILED) + goto fail; + magic = dbm_getint(0); + if (be32toh(*magic) != MANDOCDB_MAGIC) { + if (strncmp(dbm_base, "SQLite format 3", 15)) + warnx("dbm_map(%s): " + "Bad initial magic %x (expected %x)", + fname, be32toh(*magic), MANDOCDB_MAGIC); + else + warnx("dbm_map(%s): " + "Obsolete format based on SQLite 3", + fname); + errno = EFTYPE; + goto fail; + } + magic = dbm_getint(1); + if (be32toh(*magic) != MANDOCDB_VERSION) { + warnx("dbm_map(%s): Bad version number %d (expected %d)", + fname, be32toh(*magic), MANDOCDB_VERSION); + errno = EFTYPE; + goto fail; + } + max_offset = be32toh(*dbm_getint(3)) + sizeof(int32_t); + if (st.st_size != max_offset) { + warnx("dbm_map(%s): Inconsistent file size %lld (expected %d)", + fname, (long long)st.st_size, max_offset); + errno = EFTYPE; + goto fail; + } + if ((magic = dbm_get(*dbm_getint(3))) == NULL) { + errno = EFTYPE; + goto fail; + } + if (be32toh(*magic) != MANDOCDB_MAGIC) { + warnx("dbm_map(%s): Bad final magic %x (expected %x)", + fname, be32toh(*magic), MANDOCDB_MAGIC); + errno = EFTYPE; + goto fail; + } + return 0; + +fail: + save_errno = errno; + close(ifd); + errno = save_errno; + return -1; +} + +void +dbm_unmap(void) +{ + if (munmap(dbm_base, st.st_size) == -1) + warn("dbm_unmap: munmap"); + if (close(ifd) == -1) + warn("dbm_unmap: close"); + dbm_base = (char *)-1; +} + +/* + * Take a raw integer as it was read from the database. + * Interpret it as an offset into the database file + * and return a pointer to that place in the file. + */ +void * +dbm_get(int32_t offset) +{ + offset = be32toh(offset); + if (offset < 0) { + warnx("dbm_get: Database corrupt: offset %d", offset); + return NULL; + } + if (offset >= max_offset) { + warnx("dbm_get: Database corrupt: offset %d > %d", + offset, max_offset); + return NULL; + } + return dbm_base + offset; +} + +/* + * Assume the database starts with some integers. + * Assume they are numbered starting from 0, increasing. + * Get a pointer to one with the number "offset". + */ +int32_t * +dbm_getint(int32_t offset) +{ + return (int32_t *)dbm_base + offset; +} + +/* + * The reverse of dbm_get(). + * Take pointer into the database file + * and convert it to the raw integer + * that would be used to refer to that place in the file. + */ +int32_t +dbm_addr(const void *p) +{ + return htobe32((const char *)p - dbm_base); +} + +int +dbm_match(const struct dbm_match *match, const char *str) +{ + switch (match->type) { + case DBM_EXACT: + return strcmp(str, match->str) == 0; + case DBM_SUB: + return strcasestr(str, match->str) != NULL; + case DBM_REGEX: + return regexec(match->re, str, 0, NULL, 0) == 0; + default: + abort(); + } +} Property changes on: vendor/mandoc/20190723/dbm_map.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-O_DIRECTORY.c =================================================================== --- vendor/mandoc/20190723/test-O_DIRECTORY.c (nonexistent) +++ vendor/mandoc/20190723/test-O_DIRECTORY.c (revision 350350) @@ -0,0 +1,7 @@ +#include <fcntl.h> + +int +main(void) +{ + return open(".", O_RDONLY | O_DIRECTORY) == -1; +} Property changes on: vendor/mandoc/20190723/test-O_DIRECTORY.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-cmsg.c =================================================================== --- vendor/mandoc/20190723/test-cmsg.c (nonexistent) +++ vendor/mandoc/20190723/test-cmsg.c (revision 350350) @@ -0,0 +1,13 @@ +#include <stddef.h> +#include <sys/socket.h> + +int +main(void) +{ + struct msghdr msg; + + msg.msg_control = NULL; + msg.msg_controllen = 0; + + return CMSG_FIRSTHDR(&msg) != NULL; +} Property changes on: vendor/mandoc/20190723/test-cmsg.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-recvmsg.c =================================================================== --- vendor/mandoc/20190723/test-recvmsg.c (nonexistent) +++ vendor/mandoc/20190723/test-recvmsg.c (revision 350350) @@ -0,0 +1,8 @@ +#include <sys/socket.h> +#include <stddef.h> + +int +main(void) +{ + return recvmsg(-1, NULL, 0) != -1; +} Property changes on: vendor/mandoc/20190723/test-recvmsg.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_fts.h =================================================================== --- vendor/mandoc/20190723/compat_fts.h (nonexistent) +++ vendor/mandoc/20190723/compat_fts.h (revision 350350) @@ -0,0 +1,105 @@ +/* $OpenBSD: fts.h,v 1.14 2012/12/05 23:19:57 deraadt Exp $ */ +/* $NetBSD: fts.h,v 1.7 2012/03/01 16:18:51 hans Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fts.h 8.3 (Berkeley) 8/14/94 + */ + +#ifndef _FTS_H_ +#define _FTS_H_ + +typedef struct { + struct _ftsent *fts_cur; /* current node */ + struct _ftsent *fts_child; /* linked list of children */ + struct _ftsent **fts_array; /* sort array */ + dev_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + size_t fts_pathlen; /* sizeof(path) */ + int fts_nitems; /* elements in the sort array */ + int (*fts_compar)(); /* compare function */ + +#define FTS_NOCHDIR 0x0004 /* don't change directories */ +#define FTS_PHYSICAL 0x0010 /* physical walk */ +#define FTS_XDEV 0x0040 /* don't cross devices */ +#define FTS_OPTIONMASK 0x0054 /* valid user option mask */ + +#define FTS_STOP 0x2000 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ +} FTS; + +typedef struct _ftsent { + struct _ftsent *fts_cycle; /* cycle node */ + struct _ftsent *fts_parent; /* parent directory */ + struct _ftsent *fts_link; /* next file in directory */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + int fts_errno; /* errno for this node */ + size_t fts_pathlen; /* strlen(fts_path) */ + size_t fts_namelen; /* strlen(fts_name) */ + + ino_t fts_ino; /* inode */ + dev_t fts_dev; /* device */ + nlink_t fts_nlink; /* link count */ + +#define FTS_ROOTPARENTLEVEL -1 +#define FTS_ROOTLEVEL 0 +#define FTS_MAXLEVEL 0x7fffffff + int fts_level; /* depth (-1 to N) */ + +#define FTS_D 1 /* preorder directory */ +#define FTS_DC 2 /* directory that causes cycles */ +#define FTS_DEFAULT 3 /* none of the above */ +#define FTS_DNR 4 /* unreadable directory */ +#define FTS_DOT 5 /* dot or dot-dot */ +#define FTS_DP 6 /* postorder directory */ +#define FTS_ERR 7 /* error; errno is set */ +#define FTS_F 8 /* regular file */ +#define FTS_INIT 9 /* initialized only */ +#define FTS_NS 10 /* stat(2) failed */ +#define FTS_NSOK 11 /* no stat(2) requested */ +#define FTS_SL 12 /* symbolic link */ + unsigned short fts_info; /* user flags for FTSENT structure */ + +#define FTS_NOINSTR 3 /* no instructions */ +#define FTS_SKIP 4 /* discard node */ + unsigned short fts_instr; /* fts_set() instructions */ + + struct stat *fts_statp; /* stat(2) information */ + char fts_name[1]; /* file name */ +} FTSENT; + + +int fts_close(FTS *); +FTS *fts_open(char * const *, int, + int (*)(const FTSENT **, const FTSENT **)); +FTSENT *fts_read(FTS *); +int fts_set(FTS *, FTSENT *, int); + +#endif /* !_FTS_H_ */ Property changes on: vendor/mandoc/20190723/compat_fts.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dba.h =================================================================== --- vendor/mandoc/20190723/dba.h (nonexistent) +++ vendor/mandoc/20190723/dba.h (revision 350350) @@ -0,0 +1,50 @@ +/* $Id: dba.h,v 1.2 2016/08/17 20:46:56 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Public interface of the allocation-based version + * of the mandoc database, for read-write access. + * To be used by dba.c, dba_read.c, and makewhatis(8). + */ + +#define DBP_NAME 0 +#define DBP_SECT 1 +#define DBP_ARCH 2 +#define DBP_DESC 3 +#define DBP_FILE 4 +#define DBP_MAX 5 + +struct dba_array; + +struct dba { + struct dba_array *pages; + struct dba_array *macros; +}; + + +struct dba *dba_new(int32_t); +void dba_free(struct dba *); +struct dba *dba_read(const char *); +int dba_write(const char *, struct dba *); + +struct dba_array *dba_page_new(struct dba_array *, const char *, + const char *, const char *, enum form); +void dba_page_add(struct dba_array *, int32_t, const char *); +void dba_page_alias(struct dba_array *, const char *, uint64_t); + +void dba_macro_new(struct dba *, int32_t, + const char *, const int32_t *); +void dba_macro_add(struct dba_array *, int32_t, + const char *, struct dba_array *); Property changes on: vendor/mandoc/20190723/dba.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dba_array.c =================================================================== --- vendor/mandoc/20190723/dba_array.c (nonexistent) +++ vendor/mandoc/20190723/dba_array.c (revision 350350) @@ -0,0 +1,188 @@ +/* $Id: dba_array.c,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Allocation-based arrays for the mandoc database, for read-write access. + * The interface is defined in "dba_array.h". + */ +#include <assert.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "mandoc_aux.h" +#include "dba_write.h" +#include "dba_array.h" + +struct dba_array { + void **ep; /* Array of entries. */ + int32_t *em; /* Array of map positions. */ + int flags; + int32_t ea; /* Entries allocated. */ + int32_t eu; /* Entries used (including deleted). */ + int32_t ed; /* Entries deleted. */ + int32_t ec; /* Currently active entry. */ + int32_t pos; /* Map position of this array. */ +}; + + +struct dba_array * +dba_array_new(int32_t ea, int flags) +{ + struct dba_array *array; + + assert(ea > 0); + array = mandoc_malloc(sizeof(*array)); + array->ep = mandoc_reallocarray(NULL, ea, sizeof(*array->ep)); + array->em = mandoc_reallocarray(NULL, ea, sizeof(*array->em)); + array->ea = ea; + array->eu = 0; + array->ed = 0; + array->ec = 0; + array->flags = flags; + array->pos = 0; + return array; +} + +void +dba_array_free(struct dba_array *array) +{ + int32_t ie; + + if (array == NULL) + return; + if (array->flags & DBA_STR) + for (ie = 0; ie < array->eu; ie++) + free(array->ep[ie]); + free(array->ep); + free(array->em); + free(array); +} + +void +dba_array_set(struct dba_array *array, int32_t ie, void *entry) +{ + assert(ie >= 0); + assert(ie < array->ea); + assert(ie <= array->eu); + if (ie == array->eu) + array->eu++; + if (array->flags & DBA_STR) + entry = mandoc_strdup(entry); + array->ep[ie] = entry; + array->em[ie] = 0; +} + +void +dba_array_add(struct dba_array *array, void *entry) +{ + if (array->eu == array->ea) { + assert(array->flags & DBA_GROW); + array->ep = mandoc_reallocarray(array->ep, + 2, sizeof(*array->ep) * array->ea); + array->em = mandoc_reallocarray(array->em, + 2, sizeof(*array->em) * array->ea); + array->ea *= 2; + } + dba_array_set(array, array->eu, entry); +} + +void * +dba_array_get(struct dba_array *array, int32_t ie) +{ + if (ie < 0 || ie >= array->eu || array->em[ie] == -1) + return NULL; + return array->ep[ie]; +} + +void +dba_array_start(struct dba_array *array) +{ + array->ec = array->eu; +} + +void * +dba_array_next(struct dba_array *array) +{ + if (array->ec < array->eu) + array->ec++; + else + array->ec = 0; + while (array->ec < array->eu && array->em[array->ec] == -1) + array->ec++; + return array->ec < array->eu ? array->ep[array->ec] : NULL; +} + +void +dba_array_del(struct dba_array *array) +{ + if (array->ec < array->eu && array->em[array->ec] != -1) { + array->em[array->ec] = -1; + array->ed++; + } +} + +void +dba_array_undel(struct dba_array *array) +{ + memset(array->em, 0, sizeof(*array->em) * array->eu); +} + +void +dba_array_setpos(struct dba_array *array, int32_t ie, int32_t pos) +{ + array->em[ie] = pos; +} + +int32_t +dba_array_getpos(struct dba_array *array) +{ + return array->pos; +} + +void +dba_array_sort(struct dba_array *array, dba_compare_func func) +{ + assert(array->ed == 0); + qsort(array->ep, array->eu, sizeof(*array->ep), func); +} + +int32_t +dba_array_writelen(struct dba_array *array, int32_t nmemb) +{ + dba_int_write(array->eu - array->ed); + return dba_skip(nmemb, array->eu - array->ed); +} + +void +dba_array_writepos(struct dba_array *array) +{ + int32_t ie; + + array->pos = dba_tell(); + for (ie = 0; ie < array->eu; ie++) + if (array->em[ie] != -1) + dba_int_write(array->em[ie]); +} + +void +dba_array_writelst(struct dba_array *array) +{ + const char *str; + + dba_array_FOREACH(array, str) + dba_str_write(str); + dba_char_write('\0'); +} Property changes on: vendor/mandoc/20190723/dba_array.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dba_array.h =================================================================== --- vendor/mandoc/20190723/dba_array.h (nonexistent) +++ vendor/mandoc/20190723/dba_array.h (revision 350350) @@ -0,0 +1,47 @@ +/* $Id: dba_array.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Public interface for allocation-based arrays + * for the mandoc database, for read-write access. + * To be used by dba*.c and by makewhatis(8). + */ + +struct dba_array; + +#define DBA_STR 0x01 /* Map contains strings, not pointers. */ +#define DBA_GROW 0x02 /* Allow the array to grow. */ + +#define dba_array_FOREACH(a, e) \ + dba_array_start(a); \ + while (((e) = dba_array_next(a)) != NULL) + +typedef int dba_compare_func(const void *, const void *); + +struct dba_array *dba_array_new(int32_t, int); +void dba_array_free(struct dba_array *); +void dba_array_set(struct dba_array *, int32_t, void *); +void dba_array_add(struct dba_array *, void *); +void *dba_array_get(struct dba_array *, int32_t); +void dba_array_start(struct dba_array *); +void *dba_array_next(struct dba_array *); +void dba_array_del(struct dba_array *); +void dba_array_undel(struct dba_array *); +void dba_array_setpos(struct dba_array *, int32_t, int32_t); +int32_t dba_array_getpos(struct dba_array *); +void dba_array_sort(struct dba_array *, dba_compare_func); +int32_t dba_array_writelen(struct dba_array *, int32_t); +void dba_array_writepos(struct dba_array *); +void dba_array_writelst(struct dba_array *); Property changes on: vendor/mandoc/20190723/dba_array.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dba_read.c =================================================================== --- vendor/mandoc/20190723/dba_read.c (nonexistent) +++ vendor/mandoc/20190723/dba_read.c (revision 350350) @@ -0,0 +1,72 @@ +/* $Id: dba_read.c,v 1.4 2016/08/17 20:46:56 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Function to read the mandoc database from disk into RAM, + * such that data can be added or removed. + * The interface is defined in "dba.h". + * This file is seperate from dba.c because this also uses "dbm.h". + */ +#include <regex.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "mandoc_aux.h" +#include "mansearch.h" +#include "dba_array.h" +#include "dba.h" +#include "dbm.h" + + +struct dba * +dba_read(const char *fname) +{ + struct dba *dba; + struct dba_array *page; + struct dbm_page *pdata; + struct dbm_macro *mdata; + const char *cp; + int32_t im, ip, iv, npages; + + if (dbm_open(fname) == -1) + return NULL; + npages = dbm_page_count(); + dba = dba_new(npages < 128 ? 128 : npages); + for (ip = 0; ip < npages; ip++) { + pdata = dbm_page_get(ip); + page = dba_page_new(dba->pages, pdata->arch, + pdata->desc, pdata->file + 1, *pdata->file); + for (cp = pdata->name; *cp != '\0'; cp = strchr(cp, '\0') + 1) + dba_page_add(page, DBP_NAME, cp); + for (cp = pdata->sect; *cp != '\0'; cp = strchr(cp, '\0') + 1) + dba_page_add(page, DBP_SECT, cp); + if ((cp = pdata->arch) != NULL) + while (*(cp = strchr(cp, '\0') + 1) != '\0') + dba_page_add(page, DBP_ARCH, cp); + cp = pdata->file; + while (*(cp = strchr(cp, '\0') + 1) != '\0') + dba_page_add(page, DBP_FILE, cp); + } + for (im = 0; im < MACRO_MAX; im++) { + for (iv = 0; iv < dbm_macro_count(im); iv++) { + mdata = dbm_macro_get(im, iv); + dba_macro_new(dba, im, mdata->value, mdata->pp); + } + } + dbm_close(); + return dba; +} Property changes on: vendor/mandoc/20190723/dba_read.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dba_write.c =================================================================== --- vendor/mandoc/20190723/dba_write.c (nonexistent) +++ vendor/mandoc/20190723/dba_write.c (revision 350350) @@ -0,0 +1,127 @@ +/* $Id: dba_write.c,v 1.3 2016/08/05 23:15:08 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Low-level functions for serializing allocation-based data to disk. + * The interface is defined in "dba_write.h". + */ +#include "config.h" + +#include <assert.h> +#if HAVE_ENDIAN +#include <endian.h> +#elif HAVE_SYS_ENDIAN +#include <sys/endian.h> +#elif HAVE_NTOHL +#include <arpa/inet.h> +#endif +#if HAVE_ERR +#include <err.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> + +#include "dba_write.h" + +static FILE *ofp; + + +int +dba_open(const char *fname) +{ + ofp = fopen(fname, "w"); + return ofp == NULL ? -1 : 0; +} + +int +dba_close(void) +{ + return fclose(ofp) == EOF ? -1 : 0; +} + +int32_t +dba_tell(void) +{ + long pos; + + if ((pos = ftell(ofp)) == -1) + err(1, "ftell"); + if (pos >= INT32_MAX) { + errno = EOVERFLOW; + err(1, "ftell = %ld", pos); + } + return pos; +} + +void +dba_seek(int32_t pos) +{ + if (fseek(ofp, pos, SEEK_SET) == -1) + err(1, "fseek(%d)", pos); +} + +int32_t +dba_align(void) +{ + int32_t pos; + + pos = dba_tell(); + while (pos & 3) { + dba_char_write('\0'); + pos++; + } + return pos; +} + +int32_t +dba_skip(int32_t nmemb, int32_t sz) +{ + const int32_t out[5] = {0, 0, 0, 0, 0}; + int32_t i, pos; + + assert(sz >= 0); + assert(nmemb > 0); + assert(nmemb <= 5); + pos = dba_tell(); + for (i = 0; i < sz; i++) + if (nmemb - fwrite(&out, sizeof(out[0]), nmemb, ofp)) + err(1, "fwrite"); + return pos; +} + +void +dba_char_write(int c) +{ + if (putc(c, ofp) == EOF) + err(1, "fputc"); +} + +void +dba_str_write(const char *str) +{ + if (fputs(str, ofp) == EOF) + err(1, "fputs"); + dba_char_write('\0'); +} + +void +dba_int_write(int32_t i) +{ + i = htobe32(i); + if (fwrite(&i, sizeof(i), 1, ofp) != 1) + err(1, "fwrite"); +} Property changes on: vendor/mandoc/20190723/dba_write.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dba_write.h =================================================================== --- vendor/mandoc/20190723/dba_write.h (nonexistent) +++ vendor/mandoc/20190723/dba_write.h (revision 350350) @@ -0,0 +1,30 @@ +/* $Id: dba_write.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Internal interface to low-level functions + * for serializing allocation-based data to disk. + * For use by dba_array.c and dba.c only. + */ + +int dba_open(const char *); +int dba_close(void); +int32_t dba_tell(void); +void dba_seek(int32_t); +int32_t dba_align(void); +int32_t dba_skip(int32_t, int32_t); +void dba_char_write(int); +void dba_str_write(const char *); +void dba_int_write(int32_t); Property changes on: vendor/mandoc/20190723/dba_write.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/dbm.h =================================================================== --- vendor/mandoc/20190723/dbm.h (nonexistent) +++ vendor/mandoc/20190723/dbm.h (revision 350350) @@ -0,0 +1,68 @@ +/* $Id: dbm.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */ +/* + * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Public interface for the map-based version + * of the mandoc database, for read-only access. + * To be used by dbm*.c, dba_read.c, and man(1) and apropos(1). + */ + +enum dbm_mtype { + DBM_EXACT = 0, + DBM_SUB, + DBM_REGEX +}; + +struct dbm_match { + regex_t *re; + const char *str; + enum dbm_mtype type; +}; + +struct dbm_res { + int32_t page; + int32_t bits; +}; + +struct dbm_page { + const char *name; + const char *sect; + const char *arch; + const char *desc; + const char *file; + int32_t addr; +}; + +struct dbm_macro { + const char *value; + const int32_t *pp; +}; + +int dbm_open(const char *); +void dbm_close(void); + +int32_t dbm_page_count(void); +struct dbm_page *dbm_page_get(int32_t); +void dbm_page_byname(const struct dbm_match *); +void dbm_page_bysect(const struct dbm_match *); +void dbm_page_byarch(const struct dbm_match *); +void dbm_page_bydesc(const struct dbm_match *); +void dbm_page_bymacro(int32_t, const struct dbm_match *); +struct dbm_res dbm_page_next(void); + +int32_t dbm_macro_count(int32_t); +struct dbm_macro *dbm_macro_get(int32_t, int32_t); +void dbm_macro_bypage(int32_t, int32_t); +char *dbm_macro_next(void); Property changes on: vendor/mandoc/20190723/dbm.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc.db.5 =================================================================== --- vendor/mandoc/20190723/mandoc.db.5 (nonexistent) +++ vendor/mandoc/20190723/mandoc.db.5 (revision 350350) @@ -0,0 +1,228 @@ +.\" $Id: mandoc.db.5,v 1.5 2016/08/01 12:27:15 schwarze Exp $ +.\" +.\" Copyright (c) 2014, 2016 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: August 1 2016 $ +.Dt MANDOC.DB 5 +.Os +.Sh NAME +.Nm mandoc.db +.Nd manual page database +.Sh DESCRIPTION +The +.Nm +file format is used to store information about installed manual +pages to facilitate semantic searching for manuals. +Each manual page tree contains its own +.Nm +file; see +.Sx FILES +for examples. +.Pp +Such database files are generated by +.Xr makewhatis 8 +and used by +.Xr man 1 , +.Xr apropos 1 +and +.Xr whatis 1 . +.Pp +The file format uses three datatypes: +.Pp +.Bl -dash -compact -offset 2n -width 1n +.It +32-bit signed integer numbers in big endian (network) byte ordering +.It +NUL-terminated strings +.It +lists of NUL-terminated strings, terminated by a second NUL character +.El +.Pp +Numbers are aligned to four-byte boundaries; where they follow +strings or lists of strings, padding with additional NUL characters +occurs. +Some, but not all, numbers point to positions in the file. +These pointers are measured in bytes, and the first byte of the +file is considered to be byte 0. +.Pp +Each file consists of: +.Pp +.Bl -dash -compact -offset 2n -width 1n +.It +One magic number, 0x3a7d0cdb. +.It +One version number, currently 1. +.It +One pointer to the macros table. +.It +One pointer to the final magic number. +.It +The pages table (variable length). +.It +The macros table (variable length). +.It +The magic number once again, 0x3a7d0cdb. +.El +.Pp +The pages table contains one entry for each physical manual page +file, no matter how many hard and soft links it may have in the +file system. +The pages table consists of: +.Pp +.Bl -dash -compact -offset 2n -width 1n +.It +The number of pages in the database. +.It +For each page: +.Bl -dash -compact -offset 2n -width 1n +.It +One pointer to the list of names. +.It +One pointer to the list of sections. +.It +One pointer to the list of architectures +or 0 if the page is machine-independent. +.It +One pointer to the one-line description string. +.It +One pointer to the list of filenames. +.El +.It +For each page, the list of names. +Each name is preceded by a single byte indicating the sources of the name. +The meaning of the bits is: +.Bl -dash -compact -offset 2n -width 1n +.It +0x10: The name appears in a filename. +.It +0x08: The name appears in a header line, i.e. in a .Dt or .TH macro. +.It +0x04: The name is the first one in the title line, i.e. it appears +in the first .Nm macro in the NAME section. +.It +0x02: The name appears in any .Nm macro in the NAME section. +.It +0x01: The name appears in an .Nm block in the SYNOPSIS section. +.El +.It +For each page, the list of sections. +Each section is given as a string, not as a number. +.It +For each architecture-dependent page, the list of architectures. +.It +For each page, the one-line description string taken from the .Nd macro. +.It +For each page, the list of filenames relative to the root of the +respective manpath. +This list includes hard links, soft links, and links simulated +with .so +.Xr roff 7 +requests. +The first filename is preceded by a single byte +having the following significance: +.Bl -dash -compact -offset 2n -width 1n +.It +.Dv FORM_SRC No = 0x01 : +The file format is +.Xr mdoc 7 +or +.Xr man 7 . +.It +.Dv FORM_CAT No = 0x02 : +The manual page is preformatted. +.El +.It +Zero to three NUL bytes for padding. +.El +.Pp +The macros table consists of: +.Pp +.Bl -dash -compact -offset 2n -width 1n +.It +The number of different macro keys, currently 36. +The ordering of macros is defined in +.In mansearch.h +and the significance of the macro keys is documented in +.Xr apropos 1 . +.It +For each macro key, one pointer to the respective macro table. +.It +For each macro key, the macro table (variable length). +.El +.Pp +Each macro table consists of: +.Pp +.Bl -dash -compact -offset 2n -width 1n +.It +The number of entries in the table. +.It +For each entry: +.Bl -dash -compact -offset 2n -width 1n +.It +One pointer to the value of the macro key. +Each value is a string of text taken from some macro invocation. +.It +One pointer to the list of pages. +.El +.It +For each entry, the value of the macro key. +.It +Zero to three NUL bytes for padding. +.It +For each entry, one or more pointers to pages in the pages table, +pointing to the pointer to the list of names, +followed by the number 0. +.El +.Sh FILES +.Bl -tag -width /usr/share/man/mandoc.db -compact +.It Pa /usr/share/man/mandoc.db +The manual page database for the base system. +.It Pa /usr/X11R6/man/mandoc.db +The same for the +.Xr X 7 +Window System. +.It Pa /usr/local/man/mandoc.db +The same for +.Xr packages 7 . +.El +.Pp +A program to dump +.Nm +files in a human-readable format suitable for +.Xr diff 1 +is provided in the directory +.Pa /usr/src/regress/usr.bin/mandoc/db/dbm_dump/ . +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr whatis 1 , +.Xr makewhatis 8 +.Sh HISTORY +A manual page database +.Pa /usr/lib/whatis +first appeared in +.Bx 2 . +The present format first appeared in +.Ox 6.1 . +.Sh AUTHORS +.An -nosplit +The original version of +.Xr makewhatis 8 +was written by +.An Bill Joy +in 1979. +The present database format was designed by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org +in 2016. Property changes on: vendor/mandoc/20190723/mandoc.db.5 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-EFTYPE.c =================================================================== --- vendor/mandoc/20190723/test-EFTYPE.c (nonexistent) +++ vendor/mandoc/20190723/test-EFTYPE.c (revision 350350) @@ -0,0 +1,7 @@ +#include <errno.h> + +int +main(void) +{ + return !EFTYPE; +} Property changes on: vendor/mandoc/20190723/test-EFTYPE.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-PATH_MAX.c =================================================================== --- vendor/mandoc/20190723/test-PATH_MAX.c (nonexistent) +++ vendor/mandoc/20190723/test-PATH_MAX.c (revision 350350) @@ -0,0 +1,30 @@ +/* + * POSIX allows PATH_MAX to not be defined, see + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html; + * the GNU Hurd is an example of a system not having it. + * + * Arguably, it would be better to test sysconf(_SC_PATH_MAX), + * but since the individual *.c files include "config.h" before + * <limits.h>, overriding an excessive value of PATH_MAX from + * "config.h" is impossible anyway, so for now, the simplest + * fix is to provide a value only on systems not having any. + * So far, we encountered no system defining PATH_MAX to an + * impractically large value, even though POSIX explicitly + * allows that. + * + * The real fix would be to replace all static buffers of size + * PATH_MAX by dynamically allocated buffers. But that is + * somewhat intrusive because it touches several files and + * because it requires changing struct mlink in mandocdb.c. + * So i'm postponing that for now. + */ + +#include <limits.h> +#include <stdio.h> + +int +main(void) +{ + printf("PATH_MAX is defined to be %ld\n", (long)PATH_MAX); + return 0; +} Property changes on: vendor/mandoc/20190723/test-PATH_MAX.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-be32toh.c =================================================================== --- vendor/mandoc/20190723/test-be32toh.c (nonexistent) +++ vendor/mandoc/20190723/test-be32toh.c (revision 350350) @@ -0,0 +1,11 @@ +#ifdef SYS_ENDIAN +#include <sys/endian.h> +#else +#include <endian.h> +#endif + +int +main(void) +{ + return htobe32(be32toh(0x3a7d0cdb)) != 0x3a7d0cdb; +} Property changes on: vendor/mandoc/20190723/test-be32toh.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-fts.c =================================================================== --- vendor/mandoc/20190723/test-fts.c (nonexistent) +++ vendor/mandoc/20190723/test-fts.c (revision 350350) @@ -0,0 +1,59 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fts.h> +#include <stdio.h> +#include <string.h> + +#ifdef FTS_COMPARE_CONST +int fts_compare(const FTSENT *const *, const FTSENT *const *); +#else +int fts_compare(const FTSENT **, const FTSENT **); +#endif + +int +main(void) +{ + const char *argv[2]; + FTS *ftsp; + FTSENT *entry; + + argv[0] = "."; + argv[1] = (char *)NULL; + + ftsp = fts_open((char * const *)argv, + FTS_PHYSICAL | FTS_NOCHDIR, fts_compare); + + if (ftsp == NULL) { + perror("fts_open"); + return 1; + } + + entry = fts_read(ftsp); + + if (entry == NULL) { + perror("fts_read"); + return 1; + } + + if (fts_set(ftsp, entry, FTS_SKIP) != 0) { + perror("fts_set"); + return 1; + } + + if (fts_close(ftsp) != 0) { + perror("fts_close"); + return 1; + } + + return 0; +} + +int +#ifdef FTS_COMPARE_CONST +fts_compare(const FTSENT *const *a, const FTSENT *const *b) +#else +fts_compare(const FTSENT **a, const FTSENT **b) +#endif +{ + return strcmp((*a)->fts_name, (*b)->fts_name); +} Property changes on: vendor/mandoc/20190723/test-fts.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-nanosleep.c =================================================================== --- vendor/mandoc/20190723/test-nanosleep.c (nonexistent) +++ vendor/mandoc/20190723/test-nanosleep.c (revision 350350) @@ -0,0 +1,17 @@ +#include <stdio.h> +#include <time.h> + +int +main(void) +{ + struct timespec timeout; + + timeout.tv_sec = 0; + timeout.tv_nsec = 100000000; /* 0.1 seconds */ + + if (nanosleep(&timeout, NULL)) { + perror("nanosleep"); + return 1; + } + return 0; +} Property changes on: vendor/mandoc/20190723/test-nanosleep.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-ntohl.c =================================================================== --- vendor/mandoc/20190723/test-ntohl.c (nonexistent) +++ vendor/mandoc/20190723/test-ntohl.c (revision 350350) @@ -0,0 +1,7 @@ +#include <arpa/inet.h> + +int +main(void) +{ + return htonl(ntohl(0x3a7d0cdb)) != 0x3a7d0cdb; +} Property changes on: vendor/mandoc/20190723/test-ntohl.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-ohash.c =================================================================== --- vendor/mandoc/20190723/test-ohash.c (nonexistent) +++ vendor/mandoc/20190723/test-ohash.c (revision 350350) @@ -0,0 +1,39 @@ +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <ohash.h> + +static void *xmalloc(size_t, void *); +static void *xcalloc(size_t, size_t, void *); +static void xfree(void *, void *); + + +static void * +xmalloc(size_t sz, void *arg) { + return calloc(1,sz); +} + +static void * +xcalloc(size_t nmemb, size_t sz, void *arg) +{ + return calloc(nmemb,sz); +} + +static void +xfree(void *p, void *arg) +{ + free(p); +} + +int +main(void) +{ + struct ohash h; + struct ohash_info i; + i.alloc = xmalloc; + i.calloc = xcalloc; + i.free = xfree; + ohash_init(&h, 2, &i); + ohash_delete(&h); + return 0; +} Property changes on: vendor/mandoc/20190723/test-ohash.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-sandbox_init.c =================================================================== --- vendor/mandoc/20190723/test-sandbox_init.c (nonexistent) +++ vendor/mandoc/20190723/test-sandbox_init.c (revision 350350) @@ -0,0 +1,13 @@ +#include <sandbox.h> + +int +main(void) +{ + char *ep; + int rc; + + rc = sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, &ep); + if (-1 == rc) + sandbox_free_error(ep); + return(-1 == rc); +} Property changes on: vendor/mandoc/20190723/test-sandbox_init.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_malloc.3 =================================================================== --- vendor/mandoc/20190723/mandoc_malloc.3 (nonexistent) +++ vendor/mandoc/20190723/mandoc_malloc.3 (revision 350350) @@ -0,0 +1,191 @@ +.\" $Id: mandoc_malloc.3,v 1.2 2016/07/07 19:19:01 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 7 2016 $ +.Dt MANDOC_MALLOC 3 +.Os +.Sh NAME +.Nm mandoc_malloc , +.Nm mandoc_realloc , +.Nm mandoc_reallocarray , +.Nm mandoc_calloc , +.Nm mandoc_strdup , +.Nm mandoc_strndup , +.Nm mandoc_asprintf +.Nd memory allocation function wrappers used in the mandoc library +.Sh SYNOPSIS +.In sys/types.h +.In mandoc_aux.h +.Ft "void *" +.Fo mandoc_malloc +.Fa "size_t size" +.Fc +.Ft "void *" +.Fo mandoc_realloc +.Fa "void *ptr" +.Fa "size_t size" +.Fc +.Ft "void *" +.Fo mandoc_reallocarray +.Fa "void *ptr" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fc +.Ft "void *" +.Fo mandoc_calloc +.Fa "size_t nmemb" +.Fa "size_t size" +.Fc +.Ft "char *" +.Fo mandoc_strdup +.Fa "const char *s" +.Fc +.Ft "char *" +.Fo mandoc_strndup +.Fa "const char *s" +.Fa "size_t maxlen" +.Fc +.Ft int +.Fo mandoc_asprintf +.Fa "char **ret" +.Fa "const char *format" +.Fa "..." +.Fc +.Sh DESCRIPTION +These functions call the libc functions of the same names, passing +through their return values when successful. +In case of failure, they do not return, but instead call +.Xr err 3 . +They can be used both internally by any code in the mandoc libraries +and externally by programs using that library, for example +.Xr mandoc 1 , +.Xr man 1 , +.Xr apropos 1 , +.Xr makewhatis 8 , +and +.Xr man.cgi 8 . +.Pp +The function +.Fn mandoc_malloc +allocates one new object, leaving the memory uninitialized. +The functions +.Fn mandoc_realloc +and +.Fn mandoc_reallocarray +change the size of an existing object or array, possibly moving it. +When shrinking the size, existing data is truncated; when growing, +the additional memory is not initialized. +The function +.Fn mandoc_calloc +allocates a new array, initializing it to zero. +.Pp +The argument +.Fa size +is the size of each object. +The argument +.Fa nmemb +is the new number of objects in the array. +The argument +.Fa ptr +is a pointer to the existing object or array to be resized; if it is +.Dv NULL , +a new object or array is allocated. +.Pp +The functions +.Fn mandoc_strdup +and +.Fn mandoc_strndup +copy a string into newly allocated memory. +For +.Fn mandoc_strdup , +the string pointed to by +.Fa s +needs to be NUL-terminated. +For +.Fn mandoc_strndup , +at most +.Fa maxlen +bytes are copied. +The function +.Fn mandoc_asprintf +writes output formatted according to +.Fa format +into newly allocated memory and returns a pointer to the result in +.Fa ret . +For all three string functions, the result is always NUL-terminated. +.Pp +When the objects and strings are no longer needed, +the pointers returned by these functions can be passed to +.Xr free 3 . +.Sh RETURN VALUES +The function +.Fn mandoc_asprintf +always returns the number of characters written, excluding the +final NUL byte. +It never returns -1. +.Pp +The other functions always return a valid pointer; they never return +.Dv NULL . +.Sh FILES +These functions are implemented in +.Pa mandoc_aux.c . +.Sh SEE ALSO +.Xr asprintf 3 , +.Xr err 3 , +.Xr malloc 3 , +.Xr strdup 3 +.Sh STANDARDS +The functions +.Fn malloc , +.Fn realloc , +and +.Fn calloc +are required by +.St -ansiC . +The functions +.Fn strdup +and +.Fn strndup +are required by +.St -p1003.1-2008 . +The function +.Fn asprintf +is a widespread extension that first appeared in the GNU C library. +.Pp +The function +.Fn reallocarray +is an extension that first appeared in +.Ox 5.6 . +If it is not provided by the operating system, the mandoc build system +uses a bundled portable implementation. +.Sh HISTORY +The functions +.Fn mandoc_malloc , +.Fn mandoc_realloc , +.Fn mandoc_calloc , +and +.Fn mandoc_strdup +have been available since mandoc 1.9.12, +.Fn mandoc_strndup +since 1.11.5, +and +.Fn mandoc_asprintf +and +.Fn mandoc_reallocarray +since 1.12.4 and 1.13.0. +.Sh AUTHORS +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +.An Ingo Schwarze Aq Mt schwarze@openbsd.org Property changes on: vendor/mandoc/20190723/mandoc_malloc.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mchars_alloc.3 =================================================================== --- vendor/mandoc/20190723/mchars_alloc.3 (nonexistent) +++ vendor/mandoc/20190723/mchars_alloc.3 (revision 350350) @@ -0,0 +1,227 @@ +.\" $Id: mchars_alloc.3,v 1.4 2016/07/07 19:19:01 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 7 2016 $ +.Dt MCHARS_ALLOC 3 +.Os +.Sh NAME +.Nm mchars_alloc , +.Nm mchars_free , +.Nm mchars_num2char , +.Nm mchars_num2uc , +.Nm mchars_spec2cp , +.Nm mchars_spec2str , +.Nm mchars_uc2str +.Nd character table for mandoc +.Sh SYNOPSIS +.In sys/types.h +.In mandoc.h +.Ft void +.Fn mchars_alloc void +.Ft void +.Fn mchars_free void +.Ft char +.Fo mchars_num2char +.Fa "const char *decimal" +.Fa "size_t sz" +.Fc +.Ft int +.Fo mchars_num2uc +.Fa "const char *hexadecimal" +.Fa "size_t sz" +.Fc +.Ft int +.Fo mchars_spec2cp +.Fa "const char *name" +.Fa "size_t sz" +.Fc +.Ft "const char *" +.Fo mchars_spec2str +.Fa "const char *name" +.Fa "size_t sz" +.Fa "size_t *rsz" +.Fc +.Ft "const char *" +.Fn mchars_uc2str "int codepoint" +.Sh DESCRIPTION +These functions translate Unicode character numbers and +.Xr roff 7 +character names into glyphs. +See +.Xr mandoc_char 7 +for a list of +.Xr roff 7 +special characters. +These functions are intended for external use by programs formatting +.Xr mdoc 7 +and +.Xr man 7 +pages for output, for example the +.Xr mandoc 1 +output formatter modules and +.Xr makewhatis 8 . +The +.Fa decimal , +.Fa hexadecimal , +.Fa name , +and +.Fa size +input arguments are usually obtained from the +.Xr mandoc_escape 3 +parser function. +.Pp +The function +.Fn mchars_num2char +converts a +.Fa decimal +string representation of a character number consisting of +.Fa sz +digits into a printable ASCII character. +If the input string is non-numeric or does not represent a printable +ASCII character, the NUL character +.Pq Sq \e0 +is returned. +For example, the +.Xr mandoc 1 +.Fl Tascii , +.Fl Tutf8 , +and +.Fl Thtml +output modules use this function to render +.Xr roff 7 +.Ic \eN +escape sequences. +.Pp +The function +.Fn mchars_num2uc +converts a +.Fa hexadecimal +string representation of a Unicode codepoint consisting of +.Fa sz +digits into an integer representation. +If the input string is non-numeric or represents an ASCII character, +the NUL character +.Pq Sq \e0 +is returned. +For example, the +.Xr mandoc 1 +.Fl Tutf8 +and +.Fl Thtml +output modules use this function to render +.Xr roff 7 +.Ic \e[u Ns Ar XXXX Ns Ic \&] +and +.Ic \eC\(aqu Ns Ar XXXX Ns Ic \(aq +escape sequences. +.Pp +The function +.Fn mchars_alloc +initializes a static +.Vt "struct ohash" +object for subsequent use by the following two lookup functions. +When no longer needed, this object can be destroyed with +.Fn mchars_free . +.Pp +The function +.Fn mchars_spec2cp +looks up a +.Xr roff 7 +special character +.Fa name +consisting of +.Fa sz +characters and returns the corresponding Unicode codepoint. +If the +.Ar name +is not recognized, \-1 is returned. +For example, the +.Xr mandoc 1 +.Fl Tutf8 +and +.Fl Thtml +output modules use this function to render +.Xr roff 7 +.Ic \e[ Ns Ar name Ns Ic \&] +and +.Ic \eC\(aq Ns Ar name Ns Ic \(aq +escape sequences. +.Pp +The function +.Fn mchars_spec2str +looks up a +.Xr roff 7 +special character +.Fa name +consisting of +.Fa sz +characters and returns an ASCII string representation. +The length of the representation is returned in +.Fa rsz . +In many cases, the meaning of such ASCII representations +is not quite obvious, so using +.Xr roff 7 +special characters in documents intended for ASCII rendering +is usually a bad idea. +If the +.Ar name +is not recognized, +.Dv NULL +is returned. +For example, +.Xr makewhatis 8 +and the +.Xr mandoc 1 +.Fl Tascii +output module use this function to render +.Xr roff 7 +.Ic \e[ Ns Ar name Ns Ic \&] +and +.Ic \eC\(aq Ns Ar name Ns Ic \(aq +escape sequences. +.Pp +The function +.Fn mchars_uc2str +performs a reverse lookup of the Unicode +.Fa codepoint +and returns an ASCII string representation, or the string +.Qq <?> +if none is available. +.Sh FILES +These funtions are implemented in the file +.Pa chars.c . +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr mandoc_escape 3 , +.Xr ohash_init 3 , +.Xr mandoc_char 7 , +.Xr roff 7 +.Sh HISTORY +These functions and their predecessors have been available since the +following mandoc versions: +.Bl -column "mchars_num2char()" "1.11.3" "chars_num2char()" "1.10.10" +.It Sy function Ta since Ta Sy predecessor Ta since +.It Fn mchars_alloc Ta 1.11.3 Ta Fn ascii2htab Ta 1.5.3 +.It Fn mchars_free Ta 1.11.2 Ta Fn asciifree Ta 1.6.0 +.It Fn mchars_num2char Ta 1.11.2 Ta Fn chars_num2char Ta 1.10.10 +.It Fn mchars_num2uc Ta 1.11.3 Ta \(em Ta \(em +.It Fn mchars_spec2cp Ta 1.11.2 Ta Fn chars_spec2cp Ta 1.10.5 +.It Fn mchars_spec2str Ta 1.11.2 Ta Fn a2ascii Ta 1.5.3 +.It Fn mchars_uc2str Ta 1.13.2 Ta \(em Ta \(em +.El +.Sh AUTHORS +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +.An Ingo Schwarze Aq Mt schwarze@openbsd.org Property changes on: vendor/mandoc/20190723/mchars_alloc.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-rewb-bsd.c =================================================================== --- vendor/mandoc/20190723/test-rewb-bsd.c (nonexistent) +++ vendor/mandoc/20190723/test-rewb-bsd.c (revision 350350) @@ -0,0 +1,27 @@ +#include <sys/types.h> +#include <stddef.h> +#include <regex.h> + +int +main(void) +{ + regex_t re; + + if (regcomp(&re, "[[:<:]]word[[:>:]]", REG_EXTENDED | REG_NOSUB)) + return 1; + if (regexec(&re, "the word is here", 0, NULL, 0)) + return 2; + if (regexec(&re, "same word", 0, NULL, 0)) + return 3; + if (regexec(&re, "word again", 0, NULL, 0)) + return 4; + if (regexec(&re, "word", 0, NULL, 0)) + return 5; + if (regexec(&re, "wordy", 0, NULL, 0) != REG_NOMATCH) + return 6; + if (regexec(&re, "sword", 0, NULL, 0) != REG_NOMATCH) + return 7; + if (regexec(&re, "reworded", 0, NULL, 0) != REG_NOMATCH) + return 8; + return 0; +} Property changes on: vendor/mandoc/20190723/test-rewb-bsd.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-rewb-sysv.c =================================================================== --- vendor/mandoc/20190723/test-rewb-sysv.c (nonexistent) +++ vendor/mandoc/20190723/test-rewb-sysv.c (revision 350350) @@ -0,0 +1,27 @@ +#include <sys/types.h> +#include <stddef.h> +#include <regex.h> + +int +main(void) +{ + regex_t re; + + if (regcomp(&re, "\\<word\\>", REG_EXTENDED | REG_NOSUB)) + return 1; + if (regexec(&re, "the word is here", 0, NULL, 0)) + return 2; + if (regexec(&re, "same word", 0, NULL, 0)) + return 3; + if (regexec(&re, "word again", 0, NULL, 0)) + return 4; + if (regexec(&re, "word", 0, NULL, 0)) + return 5; + if (regexec(&re, "wordy", 0, NULL, 0) != REG_NOMATCH) + return 6; + if (regexec(&re, "sword", 0, NULL, 0) != REG_NOMATCH) + return 7; + if (regexec(&re, "reworded", 0, NULL, 0) != REG_NOMATCH) + return 8; + return 0; +} Property changes on: vendor/mandoc/20190723/test-rewb-sysv.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_err.c =================================================================== --- vendor/mandoc/20190723/compat_err.c (nonexistent) +++ vendor/mandoc/20190723/compat_err.c (revision 350350) @@ -0,0 +1,112 @@ +#include "config.h" + +#if HAVE_ERR + +int dummy; + +#else + +/* $Id: compat_err.c,v 1.4 2015/11/26 07:42:11 schwarze Exp $ */ +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void vwarni(const char *, va_list); +static void vwarnxi(const char *, va_list); + +static void +vwarnxi(const char *fmt, va_list ap) +{ + fprintf(stderr, "%s: ", getprogname()); + if (fmt != NULL) + vfprintf(stderr, fmt, ap); +} + +static void +vwarni(const char *fmt, va_list ap) +{ + int sverrno; + + sverrno = errno; + vwarnxi(fmt, ap); + if (fmt != NULL) + fputs(": ", stderr); + fprintf(stderr, "%s\n", strerror(sverrno)); +} + +void +err(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarni(fmt, ap); + va_end(ap); + exit(eval); +} + +void +errx(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarnxi(fmt, ap); + va_end(ap); + fputc('\n', stderr); + exit(eval); +} + +void +warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarni(fmt, ap); + va_end(ap); +} + +void +warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarnxi(fmt, ap); + va_end(ap); + fputc('\n', stderr); +} + +#endif Property changes on: vendor/mandoc/20190723/compat_err.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_getline.c =================================================================== --- vendor/mandoc/20190723/compat_getline.c (nonexistent) +++ vendor/mandoc/20190723/compat_getline.c (revision 350350) @@ -0,0 +1,68 @@ +#include "config.h" + +#if HAVE_GETLINE + +int dummy; + +#else + +/* $Id: compat_getline.c,v 1.1 2015/11/07 20:52:52 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +ssize_t +getline(char **buf, size_t *bufsz, FILE *fp) +{ + char *nbuf; + size_t nbufsz, pos; + int c; + + if (buf == NULL || bufsz == NULL) { + errno = EINVAL; + return -1; + } + + if (*buf == NULL) + *bufsz = 0; + else + **buf = '\0'; + + pos = 0; + for (;;) { + if (pos + 1 >= *bufsz) { + nbufsz = *bufsz ? *bufsz * 2 : BUFSIZ; + if ((nbuf = realloc(*buf, nbufsz)) == NULL) + return -1; + *buf = nbuf; + *bufsz = nbufsz; + } + if ((c = fgetc(fp)) == EOF) { + (*buf)[pos] = '\0'; + return pos > 0 && feof(fp) ? (ssize_t)pos : -1; + } + (*buf)[pos++] = c; + (*buf)[pos] = '\0'; + if (c == '\n') + return pos; + } +} + +#endif Property changes on: vendor/mandoc/20190723/compat_getline.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_isblank.c =================================================================== --- vendor/mandoc/20190723/compat_isblank.c (nonexistent) +++ vendor/mandoc/20190723/compat_isblank.c (revision 350350) @@ -0,0 +1,33 @@ +#include "config.h" + +#if HAVE_ISBLANK + +int dummy; + +#else + +/* $Id: compat_isblank.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +int +isblank(int c) +{ + + return c == ' ' || c == '\t'; +} + +#endif Property changes on: vendor/mandoc/20190723/compat_isblank.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_mkdtemp.c =================================================================== --- vendor/mandoc/20190723/compat_mkdtemp.c (nonexistent) +++ vendor/mandoc/20190723/compat_mkdtemp.c (revision 350350) @@ -0,0 +1,61 @@ +#include "config.h" + +#if HAVE_MKDTEMP + +int dummy; + +#else + +/* $Id: compat_mkdtemp.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * The algorithm of this function is inspired by OpenBSD mkdtemp(3) + * by Theo de Raadt and Todd Miller, but the code differs. + */ + +#include <sys/stat.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +char * +mkdtemp(char *path) +{ + char *start, *cp; + unsigned int tries; + + start = strchr(path, '\0'); + while (start > path && start[-1] == 'X') + start--; + + for (tries = INT_MAX; tries; tries--) { + if (mktemp(path) == NULL) { + errno = EEXIST; + return NULL; + } + if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) == 0) + return path; + if (errno != EEXIST) + return NULL; + for (cp = start; *cp != '\0'; cp++) + *cp = 'X'; + } + errno = EEXIST; + return NULL; +} + +#endif Property changes on: vendor/mandoc/20190723/compat_mkdtemp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_ohash.h =================================================================== --- vendor/mandoc/20190723/compat_ohash.h (nonexistent) +++ vendor/mandoc/20190723/compat_ohash.h (revision 350350) @@ -0,0 +1,72 @@ +/* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */ + +/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef OHASH_H +#define OHASH_H + +/* Open hashing support. + * Open hashing was chosen because it is much lighter than other hash + * techniques, and more efficient in most cases. + */ + +/* user-visible data structure */ +struct ohash_info { + ptrdiff_t key_offset; + void *data; /* user data */ + void *(*calloc)(size_t, size_t, void *); + void (*free)(void *, void *); + void *(*alloc)(size_t, void *); +}; + +struct _ohash_record; + +/* private structure. It's there just so you can do a sizeof */ +struct ohash { + struct _ohash_record *t; + struct ohash_info info; + unsigned int size; + unsigned int total; + unsigned int deleted; +}; + +/* For this to be tweakable, we use small primitives, and leave part of the + * logic to the client application. e.g., hashing is left to the client + * application. We also provide a simple table entry lookup that yields + * a hashing table index (opaque) to be used in find/insert/remove. + * The keys are stored at a known position in the client data. + */ +void ohash_init(struct ohash *, unsigned, struct ohash_info *); +void ohash_delete(struct ohash *); + +unsigned int ohash_lookup_interval(struct ohash *, const char *, + const char *, uint32_t); +unsigned int ohash_lookup_memory(struct ohash *, const char *, + size_t, uint32_t); +void *ohash_find(struct ohash *, unsigned int); +void *ohash_remove(struct ohash *, unsigned int); +void *ohash_insert(struct ohash *, unsigned int, void *); +void *ohash_first(struct ohash *, unsigned int *); +void *ohash_next(struct ohash *, unsigned int *); +unsigned int ohash_entries(struct ohash *); + +void *ohash_create_entry(struct ohash_info *, const char *, const char **); +uint32_t ohash_interval(const char *, const char **); + +unsigned int ohash_qlookupi(struct ohash *, const char *, const char **); +unsigned int ohash_qlookup(struct ohash *, const char *); + +#endif Property changes on: vendor/mandoc/20190723/compat_ohash.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_progname.c =================================================================== --- vendor/mandoc/20190723/compat_progname.c (nonexistent) +++ vendor/mandoc/20190723/compat_progname.c (revision 350350) @@ -0,0 +1,42 @@ +#include "config.h" + +#if HAVE_PROGNAME + +int dummy; + +#else + +/* $Id: compat_progname.c,v 1.1 2015/11/06 16:30:33 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +static const char *progname; + +void +setprogname(const char *name) +{ + + progname = name; +} + +const char * +getprogname(void) +{ + + return progname; +} + +#endif Property changes on: vendor/mandoc/20190723/compat_progname.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_stringlist.c =================================================================== --- vendor/mandoc/20190723/compat_stringlist.c (nonexistent) +++ vendor/mandoc/20190723/compat_stringlist.c (revision 350350) @@ -0,0 +1,119 @@ +#include "config.h" + +#if HAVE_STRINGLIST + +int dummy; + +#else + +/* $Id: compat_stringlist.c,v 1.6 2015/11/07 14:22:29 schwarze Exp $ */ +/* + * Copyright (c) 1994 Christos Zoulas <christos@netbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_ERR +#include <err.h> +#endif +#include <stdlib.h> +#include <string.h> +#include "compat_stringlist.h" + +#define _SL_CHUNKSIZE 20 + +/* + * sl_init(): Initialize a string list + */ +StringList * +sl_init(void) +{ + StringList *sl; + + sl = malloc(sizeof(StringList)); + if (sl == NULL) + err(1, "stringlist"); + + sl->sl_cur = 0; + sl->sl_max = _SL_CHUNKSIZE; + sl->sl_str = reallocarray(NULL, sl->sl_max, sizeof(char *)); + if (sl->sl_str == NULL) + err(1, "stringlist"); + return sl; +} + + +/* + * sl_add(): Add an item to the string list + */ +int +sl_add(StringList *sl, char *name) +{ + if (sl->sl_cur == sl->sl_max - 1) { + sl->sl_max += _SL_CHUNKSIZE; + sl->sl_str = reallocarray(sl->sl_str, + sl->sl_max, sizeof(char *)); + if (sl->sl_str == NULL) + return (-1); + } + sl->sl_str[sl->sl_cur++] = name; + return (0); +} + + +/* + * sl_free(): Free a stringlist + */ +void +sl_free(StringList *sl, int all) +{ + size_t i; + + if (sl == NULL) + return; + if (sl->sl_str) { + if (all) + for (i = 0; i < sl->sl_cur; i++) + free(sl->sl_str[i]); + free(sl->sl_str); + } + free(sl); +} + + +/* + * sl_find(): Find a name in the string list + */ +char * +sl_find(StringList *sl, const char *name) +{ + size_t i; + + for (i = 0; i < sl->sl_cur; i++) + if (strcmp(sl->sl_str[i], name) == 0) + return sl->sl_str[i]; + + return NULL; +} + +#endif Property changes on: vendor/mandoc/20190723/compat_stringlist.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_stringlist.h =================================================================== --- vendor/mandoc/20190723/compat_stringlist.h (nonexistent) +++ vendor/mandoc/20190723/compat_stringlist.h (revision 350350) @@ -0,0 +1,45 @@ +/* $Id: compat_stringlist.h,v 1.4 2015/11/07 14:01:16 schwarze Exp $ */ +/* $NetBSD: stringlist.h,v 1.2 1997/01/17 06:11:36 lukem Exp $ */ + +/* + * Copyright (c) 1994 Christos Zoulas <christos@netbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> + +/* + * Simple string list + */ +typedef struct _stringlist { + char **sl_str; + size_t sl_max; + size_t sl_cur; +} StringList; + + +StringList *sl_init(void); +int sl_add(StringList *, char *); +void sl_free(StringList *, int); +char *sl_find(StringList *, const char *); Property changes on: vendor/mandoc/20190723/compat_stringlist.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_vasprintf.c =================================================================== --- vendor/mandoc/20190723/compat_vasprintf.c (nonexistent) +++ vendor/mandoc/20190723/compat_vasprintf.c (revision 350350) @@ -0,0 +1,56 @@ +#include "config.h" + +#if HAVE_VASPRINTF + +int dummy; + +#else + +/* $Id: compat_vasprintf.c,v 1.3 2015/10/06 18:32:19 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * This fallback implementation is not efficient: + * It does the formatting twice. + * Short of fiddling with the unknown internals of the system's + * printf(3) or completely reimplementing printf(3), i can't think + * of another portable solution. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +int +vasprintf(char **ret, const char *format, va_list ap) +{ + char buf[2]; + va_list ap2; + int sz; + + va_copy(ap2, ap); + sz = vsnprintf(buf, sizeof(buf), format, ap2); + va_end(ap2); + + if (sz != -1 && (*ret = malloc(sz + 1)) != NULL) { + if (vsnprintf(*ret, sz + 1, format, ap) == sz) + return sz; + free(*ret); + } + *ret = NULL; + return -1; +} + +#endif Property changes on: vendor/mandoc/20190723/compat_vasprintf.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_ohash.c =================================================================== --- vendor/mandoc/20190723/mandoc_ohash.c (nonexistent) +++ vendor/mandoc/20190723/mandoc_ohash.c (revision 350350) @@ -0,0 +1,63 @@ +/* $Id: mandoc_ohash.c,v 1.2 2015/10/19 18:58:47 schwarze Exp $ */ +/* + * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <sys/types.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" + +static void *hash_alloc(size_t, void *); +static void *hash_calloc(size_t, size_t, void *); +static void hash_free(void *, void *); + + +void +mandoc_ohash_init(struct ohash *h, unsigned int sz, ptrdiff_t ko) +{ + struct ohash_info info; + + info.alloc = hash_alloc; + info.calloc = hash_calloc; + info.free = hash_free; + info.data = NULL; + info.key_offset = ko; + + ohash_init(h, sz, &info); +} + +static void * +hash_alloc(size_t sz, void *arg) +{ + + return mandoc_malloc(sz); +} + +static void * +hash_calloc(size_t n, size_t sz, void *arg) +{ + + return mandoc_calloc(n, sz); +} + +static void +hash_free(void *p, void *arg) +{ + + free(p); +} Property changes on: vendor/mandoc/20190723/mandoc_ohash.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/mandoc_ohash.h =================================================================== --- vendor/mandoc/20190723/mandoc_ohash.h (nonexistent) +++ vendor/mandoc/20190723/mandoc_ohash.h (revision 350350) @@ -0,0 +1,23 @@ +/* $Id: mandoc_ohash.h,v 1.2 2015/11/07 14:01:16 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#if HAVE_OHASH +#include <ohash.h> +#else +#include "compat_ohash.h" +#endif + +void mandoc_ohash_init(struct ohash *, unsigned int, ptrdiff_t); Property changes on: vendor/mandoc/20190723/mandoc_ohash.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/soelim.c =================================================================== --- vendor/mandoc/20190723/soelim.c (nonexistent) +++ vendor/mandoc/20190723/soelim.c (revision 350350) @@ -0,0 +1,182 @@ +/* $Id: soelim.c,v 1.5 2015/11/07 14:22:29 schwarze Exp $ */ +/* + * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include <sys/types.h> + +#include <ctype.h> +#if HAVE_ERR +#include <err.h> +#endif +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if HAVE_STRINGLIST +#include <stringlist.h> +#else +#include "compat_stringlist.h" +#endif +#include <unistd.h> + +#define C_OPTION 0x1 + +static StringList *includes; + +static void +usage(void) +{ + + fprintf(stderr, "usage: soelim [-Crtv] [-I dir] [files]\n"); + + exit(EXIT_FAILURE); +} + +static FILE * +soelim_fopen(const char *name) +{ + FILE *f; + char path[PATH_MAX]; + size_t i; + + if (strcmp(name, "-") == 0) + return (stdin); + + if ((f = fopen(name, "r")) != NULL) + return (f); + + if (*name == '/') { + warn("can't open '%s'", name); + return (NULL); + } + + for (i = 0; i < includes->sl_cur; i++) { + snprintf(path, sizeof(path), "%s/%s", includes->sl_str[i], + name); + if ((f = fopen(path, "r")) != NULL) + return (f); + } + + warn("can't open '%s'", name); + + return (f); +} + +static int +soelim_file(FILE *f, int flag) +{ + char *line = NULL; + char *walk, *cp; + size_t linecap = 0; + ssize_t linelen; + + if (f == NULL) + return (1); + + while ((linelen = getline(&line, &linecap, f)) > 0) { + if (strncmp(line, ".so", 3) != 0) { + printf("%s", line); + continue; + } + + walk = line + 3; + if (!isspace(*walk) && ((flag & C_OPTION) == 0)) { + printf("%s", line); + continue; + } + + while (isspace(*walk)) + walk++; + + cp = walk; + while (*cp != '\0' && !isspace(*cp)) + cp++; + *cp = 0; + if (cp < line + linelen) + cp++; + + if (*walk == '\0') { + printf("%s", line); + continue; + } + if (soelim_file(soelim_fopen(walk), flag) == 1) { + free(line); + return (1); + } + if (*cp != '\0') + printf("%s", cp); + } + + free(line); + fclose(f); + + return (0); +} + +int +main(int argc, char **argv) +{ + int ch, i; + int ret = 0; + int flags = 0; + + includes = sl_init(); + if (includes == NULL) + err(EXIT_FAILURE, "sl_init()"); + + while ((ch = getopt(argc, argv, "CrtvI:")) != -1) { + switch (ch) { + case 'C': + flags |= C_OPTION; + break; + case 'r': + case 'v': + case 't': + /* stub compatibility with groff's soelim */ + break; + case 'I': + sl_add(includes, optarg); + break; + default: + sl_free(includes, 0); + usage(); + } + } + + argc -= optind; + argv += optind; + + if (argc == 0) + ret = soelim_file(stdin, flags); + + for (i = 0; i < argc; i++) + ret = soelim_file(soelim_fopen(argv[i]), flags); + + sl_free(includes, 0); + + return (ret); +} Property changes on: vendor/mandoc/20190723/soelim.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-dirent-namlen.c =================================================================== --- vendor/mandoc/20190723/test-dirent-namlen.c (nonexistent) +++ vendor/mandoc/20190723/test-dirent-namlen.c (revision 350350) @@ -0,0 +1,10 @@ +#include <sys/types.h> +#include <dirent.h> + +int +main(void) +{ + struct dirent entry; + + return sizeof(entry.d_namlen) == 0; +} Property changes on: vendor/mandoc/20190723/test-dirent-namlen.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-err.c =================================================================== --- vendor/mandoc/20190723/test-err.c (nonexistent) +++ vendor/mandoc/20190723/test-err.c (revision 350350) @@ -0,0 +1,28 @@ +/* $Id: test-err.c,v 1.1 2015/10/11 21:12:55 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <err.h> + +int +main(void) +{ + warnx("%d. warnx", 1); + warn("%d. warn", 2); + err(0, "%d. err", 3); + /* NOTREACHED */ + return 1; +} Property changes on: vendor/mandoc/20190723/test-err.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-getline.c =================================================================== --- vendor/mandoc/20190723/test-getline.c (nonexistent) +++ vendor/mandoc/20190723/test-getline.c (revision 350350) @@ -0,0 +1,13 @@ +#include <sys/types.h> +#include <stdio.h> +#include <unistd.h> + +int +main(void) +{ + char *line = NULL; + size_t linesz = 0; + + fclose(stdin); + return getline(&line, &linesz, stdin) != -1; +} Property changes on: vendor/mandoc/20190723/test-getline.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-isblank.c =================================================================== --- vendor/mandoc/20190723/test-isblank.c (nonexistent) +++ vendor/mandoc/20190723/test-isblank.c (revision 350350) @@ -0,0 +1,7 @@ +#include <ctype.h> + +int +main(void) +{ + return !isblank(' ') || !isblank('\t') || isblank('_'); +} Property changes on: vendor/mandoc/20190723/test-isblank.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-mkdtemp.c =================================================================== --- vendor/mandoc/20190723/test-mkdtemp.c (nonexistent) +++ vendor/mandoc/20190723/test-mkdtemp.c (revision 350350) @@ -0,0 +1,12 @@ +#include <stdlib.h> +#include <unistd.h> + +int +main(void) +{ + char dirname[] = "/tmp/temp.XXXXXX"; + + if (mkdtemp(dirname) != dirname) + return 1; + return rmdir(dirname) == -1; +} Property changes on: vendor/mandoc/20190723/test-mkdtemp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-pledge.c =================================================================== --- vendor/mandoc/20190723/test-pledge.c (nonexistent) +++ vendor/mandoc/20190723/test-pledge.c (revision 350350) @@ -0,0 +1,7 @@ +#include <unistd.h> + +int +main(void) +{ + return !!pledge("stdio", NULL); +} Property changes on: vendor/mandoc/20190723/test-pledge.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-progname.c =================================================================== --- vendor/mandoc/20190723/test-progname.c (nonexistent) +++ vendor/mandoc/20190723/test-progname.c (revision 350350) @@ -0,0 +1,10 @@ +#include <stdlib.h> + +int +main(void) +{ + const char * progname; + + progname = getprogname(); + return progname == NULL; +} Property changes on: vendor/mandoc/20190723/test-progname.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-reallocarray.c =================================================================== --- vendor/mandoc/20190723/test-reallocarray.c (nonexistent) +++ vendor/mandoc/20190723/test-reallocarray.c (revision 350350) @@ -0,0 +1,7 @@ +#include <stdlib.h> + +int +main(void) +{ + return !reallocarray(NULL, 2, 2); +} Property changes on: vendor/mandoc/20190723/test-reallocarray.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-strlcat.c =================================================================== --- vendor/mandoc/20190723/test-strlcat.c (nonexistent) +++ vendor/mandoc/20190723/test-strlcat.c (revision 350350) @@ -0,0 +1,9 @@ +#include <string.h> + +int +main(void) +{ + char buf[3] = "a"; + return ! (strlcat(buf, "b", sizeof(buf)) == 2 && + buf[0] == 'a' && buf[1] == 'b' && buf[2] == '\0'); +} Property changes on: vendor/mandoc/20190723/test-strlcat.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-strlcpy.c =================================================================== --- vendor/mandoc/20190723/test-strlcpy.c (nonexistent) +++ vendor/mandoc/20190723/test-strlcpy.c (revision 350350) @@ -0,0 +1,9 @@ +#include <string.h> + +int +main(void) +{ + char buf[2] = ""; + return ! (strlcpy(buf, "a", sizeof(buf)) == 1 && + buf[0] == 'a' && buf[1] == '\0'); +} Property changes on: vendor/mandoc/20190723/test-strlcpy.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-strsep.c =================================================================== --- vendor/mandoc/20190723/test-strsep.c (nonexistent) +++ vendor/mandoc/20190723/test-strsep.c (revision 350350) @@ -0,0 +1,10 @@ +#include <string.h> + +int +main(void) +{ + char buf[6] = "aybxc"; + char *workp = buf; + char *retp = strsep(&workp, "xy"); + return ! (retp == buf && buf[1] == '\0' && workp == buf + 2); +} Property changes on: vendor/mandoc/20190723/test-strsep.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/test-strtonum.c =================================================================== --- vendor/mandoc/20190723/test-strtonum.c (nonexistent) +++ vendor/mandoc/20190723/test-strtonum.c (revision 350350) @@ -0,0 +1,42 @@ +/* $Id: test-strtonum.c,v 1.2 2015/10/06 18:32:20 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdlib.h> + +int +main(void) +{ + const char *errstr; + + if (strtonum("1", 0, 2, &errstr) != 1) + return 1; + if (errstr != NULL) + return 2; + if (strtonum("1x", 0, 2, &errstr) != 0) + return 3; + if (errstr == NULL) + return 4; + if (strtonum("2", 0, 1, &errstr) != 0) + return 5; + if (errstr == NULL) + return 6; + if (strtonum("0", 1, 2, &errstr) != 0) + return 7; + if (errstr == NULL) + return 8; + return 0; +} Property changes on: vendor/mandoc/20190723/test-strtonum.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_strtonum.c =================================================================== --- vendor/mandoc/20190723/compat_strtonum.c (nonexistent) +++ vendor/mandoc/20190723/compat_strtonum.c (revision 350350) @@ -0,0 +1,76 @@ +#include "config.h" + +#if HAVE_STRTONUM + +int dummy; + +#else + +/* $Id: compat_strtonum.c,v 1.1 2015/02/16 14:56:22 schwarze Exp $ */ +/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + int error = 0; + char *ep; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) { + error = INVALID; + } else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} + +#endif /* !HAVE_STRTONUM */ Property changes on: vendor/mandoc/20190723/compat_strtonum.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_reallocarray.c =================================================================== --- vendor/mandoc/20190723/compat_reallocarray.c (nonexistent) +++ vendor/mandoc/20190723/compat_reallocarray.c (revision 350350) @@ -0,0 +1,49 @@ +#include "config.h" + +#if HAVE_REALLOCARRAY + +int dummy; + +#else + +/* $Id: compat_reallocarray.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $ */ +/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} + +#endif /*!HAVE_REALLOCARRAY*/ Property changes on: vendor/mandoc/20190723/compat_reallocarray.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_strcasestr.c =================================================================== --- vendor/mandoc/20190723/compat_strcasestr.c (nonexistent) +++ vendor/mandoc/20190723/compat_strcasestr.c (revision 350350) @@ -0,0 +1,73 @@ +#include "config.h" + +#if HAVE_STRCASESTR + +int dummy; + +#else + +/* $Id: compat_strcasestr.c,v 1.4 2014/12/11 09:19:32 schwarze Exp $ */ +/* $NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <string.h> + +#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) + +/* + * Find the first occurrence of find in s, ignore case. + */ +char * +strcasestr(const char *s, const char *find) +{ + char c, sc; + size_t len; + + if ((c = *find++) != 0) { + c = tolower((unsigned char)c); + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) + return (NULL); + } while ((char)tolower((unsigned char)sc) != c); + } while (strncasecmp(s, find, len) != 0); + s--; + } + return __UNCONST(s); +} + +#endif Property changes on: vendor/mandoc/20190723/compat_strcasestr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_strsep.c =================================================================== --- vendor/mandoc/20190723/compat_strsep.c (nonexistent) +++ vendor/mandoc/20190723/compat_strsep.c (revision 350350) @@ -0,0 +1,79 @@ +#include "config.h" + +#if HAVE_STRSEP + +int dummy; + +#else + +/* $Id: compat_strsep.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $ */ +/* $OpenBSD: strsep.c,v 1.7 2014/02/05 20:42:32 stsp Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(char **stringp, const char *delim) +{ + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +#endif Property changes on: vendor/mandoc/20190723/compat_strsep.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_getsubopt.c =================================================================== --- vendor/mandoc/20190723/compat_getsubopt.c (nonexistent) +++ vendor/mandoc/20190723/compat_getsubopt.c (revision 350350) @@ -0,0 +1,96 @@ +#include "config.h" + +#if HAVE_GETSUBOPT + +int dummy; + +#else + +/* $Id: compat_getsubopt.c,v 1.5 2014/08/17 20:53:50 schwarze Exp $ */ +/* $OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +int +getsubopt(char **optionp, char * const *tokens, char **valuep) +{ + int cnt; + char *suboptarg; + char *p; + + suboptarg = *valuep = NULL; + + if (!optionp || !*optionp) + return(-1); + + /* skip leading white-space, commas */ + for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + + if (!*p) { + *optionp = p; + return(-1); + } + + /* save the start of the token, and skip the rest of the token. */ + for (suboptarg = p; + *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';); + + if (*p) { + /* + * If there's an equals sign, set the value pointer, and + * skip over the value part of the token. Terminate the + * token. + */ + if (*p == '=') { + *p = '\0'; + for (*valuep = ++p; + *p && *p != ',' && *p != ' ' && *p != '\t'; ++p); + if (*p) + *p++ = '\0'; + } else + *p++ = '\0'; + /* Skip any whitespace or commas after this token. */ + for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + } + + /* set optionp for next round. */ + *optionp = p; + + for (cnt = 0; *tokens; ++tokens, ++cnt) + if (!strcmp(suboptarg, *tokens)) + return(cnt); + return(-1); +} + +#endif Property changes on: vendor/mandoc/20190723/compat_getsubopt.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_ohash.c =================================================================== --- vendor/mandoc/20190723/compat_ohash.c (nonexistent) +++ vendor/mandoc/20190723/compat_ohash.c (revision 350350) @@ -0,0 +1,339 @@ +#include "config.h" + +#if HAVE_OHASH + +int dummy; + +#else + +/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */ + +/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include "compat_ohash.h" + +struct _ohash_record { + uint32_t hv; + const char *p; +}; + +#define DELETED ((const char *)h) +#define NONE (h->size) + +/* Don't bother changing the hash table if the change is small enough. */ +#define MINSIZE (1UL << 4) +#define MINDELETED 4 + +static void ohash_resize(struct ohash *); + + +/* This handles the common case of variable length keys, where the + * key is stored at the end of the record. + */ +void * +ohash_create_entry(struct ohash_info *i, const char *start, const char **end) +{ + char *p; + + if (!*end) + *end = start + strlen(start); + p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); + if (p) { + memcpy(p+i->key_offset, start, *end-start); + p[i->key_offset + (*end - start)] = '\0'; + } + return (void *)p; +} + +/* hash_delete only frees the hash structure. Use hash_first/hash_next + * to free entries as well. */ +void +ohash_delete(struct ohash *h) +{ + (h->info.free)(h->t, h->info.data); +#ifndef NDEBUG + h->t = NULL; +#endif +} + +static void +ohash_resize(struct ohash *h) +{ + struct _ohash_record *n; + size_t ns; + unsigned int j; + unsigned int i, incr; + + if (4 * h->deleted < h->total) { + if (h->size >= (UINT_MAX >> 1U)) + ns = UINT_MAX; + else + ns = h->size << 1U; + } else if (3 * h->deleted > 2 * h->total) + ns = h->size >> 1U; + else + ns = h->size; + if (ns < MINSIZE) + ns = MINSIZE; +#ifdef STATS_HASH + STAT_HASH_EXPAND++; + STAT_HASH_SIZE += ns - h->size; +#endif + + n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data); + if (!n) + return; + + for (j = 0; j < h->size; j++) { + if (h->t[j].p != NULL && h->t[j].p != DELETED) { + i = h->t[j].hv % ns; + incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1; + while (n[i].p != NULL) { + i += incr; + if (i >= ns) + i -= ns; + } + n[i].hv = h->t[j].hv; + n[i].p = h->t[j].p; + } + } + (h->info.free)(h->t, h->info.data); + h->t = n; + h->size = ns; + h->total -= h->deleted; + h->deleted = 0; +} + +void * +ohash_remove(struct ohash *h, unsigned int i) +{ + void *result = (void *)h->t[i].p; + + if (result == NULL || result == DELETED) + return NULL; + +#ifdef STATS_HASH + STAT_HASH_ENTRIES--; +#endif + h->t[i].p = DELETED; + h->deleted++; + if (h->deleted >= MINDELETED && 4 * h->deleted > h->total) + ohash_resize(h); + return result; +} + +void * +ohash_find(struct ohash *h, unsigned int i) +{ + if (h->t[i].p == DELETED) + return NULL; + else + return (void *)h->t[i].p; +} + +void * +ohash_insert(struct ohash *h, unsigned int i, void *p) +{ +#ifdef STATS_HASH + STAT_HASH_ENTRIES++; +#endif + if (h->t[i].p == DELETED) { + h->deleted--; + h->t[i].p = p; + } else { + h->t[i].p = p; + /* Arbitrary resize boundary. Tweak if not efficient enough. */ + if (++h->total * 4 > h->size * 3) + ohash_resize(h); + } + return p; +} + +unsigned int +ohash_entries(struct ohash *h) +{ + return h->total - h->deleted; +} + +void * +ohash_first(struct ohash *h, unsigned int *pos) +{ + *pos = 0; + return ohash_next(h, pos); +} + +void * +ohash_next(struct ohash *h, unsigned int *pos) +{ + for (; *pos < h->size; (*pos)++) + if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) + return (void *)h->t[(*pos)++].p; + return NULL; +} + +void +ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) +{ + h->size = 1UL << size; + if (h->size < MINSIZE) + h->size = MINSIZE; +#ifdef STATS_HASH + STAT_HASH_CREATION++; + STAT_HASH_SIZE += h->size; +#endif + /* Copy info so that caller may free it. */ + h->info.key_offset = info->key_offset; + h->info.calloc = info->calloc; + h->info.free = info->free; + h->info.alloc = info->alloc; + h->info.data = info->data; + h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record), + h->info.data); + h->total = h->deleted = 0; +} + +uint32_t +ohash_interval(const char *s, const char **e) +{ + uint32_t k; + + if (!*e) + *e = s + strlen(s); + if (s == *e) + k = 0; + else + k = *s++; + while (s != *e) + k = ((k << 2) | (k >> 30)) ^ *s++; + return k; +} + +unsigned int +ohash_lookup_interval(struct ohash *h, const char *start, const char *end, + uint32_t hv) +{ + unsigned int i, incr; + unsigned int empty; + +#ifdef STATS_HASH + STAT_HASH_LOOKUP++; +#endif + empty = NONE; + i = hv % h->size; + incr = ((hv % (h->size-2)) & ~1) + 1; + while (h->t[i].p != NULL) { +#ifdef STATS_HASH + STAT_HASH_LENGTH++; +#endif + if (h->t[i].p == DELETED) { + if (empty == NONE) + empty = i; + } else if (h->t[i].hv == hv && + strncmp(h->t[i].p+h->info.key_offset, start, + end - start) == 0 && + (h->t[i].p+h->info.key_offset)[end-start] == '\0') { + if (empty != NONE) { + h->t[empty].hv = hv; + h->t[empty].p = h->t[i].p; + h->t[i].p = DELETED; + return empty; + } else { +#ifdef STATS_HASH + STAT_HASH_POSITIVE++; +#endif + return i; + } + } + i += incr; + if (i >= h->size) + i -= h->size; + } + + /* Found an empty position. */ + if (empty != NONE) + i = empty; + h->t[i].hv = hv; + return i; +} + +unsigned int +ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv) +{ + unsigned int i, incr; + unsigned int empty; + +#ifdef STATS_HASH + STAT_HASH_LOOKUP++; +#endif + empty = NONE; + i = hv % h->size; + incr = ((hv % (h->size-2)) & ~1) + 1; + while (h->t[i].p != NULL) { +#ifdef STATS_HASH + STAT_HASH_LENGTH++; +#endif + if (h->t[i].p == DELETED) { + if (empty == NONE) + empty = i; + } else if (h->t[i].hv == hv && + memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { + if (empty != NONE) { + h->t[empty].hv = hv; + h->t[empty].p = h->t[i].p; + h->t[i].p = DELETED; + return empty; + } else { +#ifdef STATS_HASH + STAT_HASH_POSITIVE++; +#endif + } return i; + } + i += incr; + if (i >= h->size) + i -= h->size; + } + + /* Found an empty position. */ + if (empty != NONE) + i = empty; + h->t[i].hv = hv; + return i; +} + +unsigned int +ohash_qlookup(struct ohash *h, const char *s) +{ + const char *e = NULL; + return ohash_qlookupi(h, s, &e); +} + +unsigned int +ohash_qlookupi(struct ohash *h, const char *s, const char **e) +{ + uint32_t hv; + + hv = ohash_interval(s, e); + return ohash_lookup_interval(h, s, *e, hv); +} + +#endif /*!HAVE_OHASH*/ Property changes on: vendor/mandoc/20190723/compat_ohash.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_strlcat.c =================================================================== --- vendor/mandoc/20190723/compat_strlcat.c (nonexistent) +++ vendor/mandoc/20190723/compat_strlcat.c (revision 350350) @@ -0,0 +1,65 @@ +#include "config.h" + +#if HAVE_STRLCAT + +int dummy; + +#else + +/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + +#endif Property changes on: vendor/mandoc/20190723/compat_strlcat.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/compat_strlcpy.c =================================================================== --- vendor/mandoc/20190723/compat_strlcpy.c (nonexistent) +++ vendor/mandoc/20190723/compat_strlcpy.c (revision 350350) @@ -0,0 +1,61 @@ +#include "config.h" + +#if HAVE_STRLCPY + +int dummy; + +#else + +/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +#endif Property changes on: vendor/mandoc/20190723/compat_strlcpy.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/demandoc.1 =================================================================== --- vendor/mandoc/20190723/demandoc.1 (nonexistent) +++ vendor/mandoc/20190723/demandoc.1 (revision 350350) @@ -0,0 +1,108 @@ +.\" $Id: demandoc.1,v 1.8 2014/09/12 00:10:26 schwarze Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: September 12 2014 $ +.Dt DEMANDOC 1 +.Os +.Sh NAME +.Nm demandoc +.Nd emit only text of UNIX manuals +.Sh SYNOPSIS +.Nm demandoc +.Op Fl w +.Op Ar +.Sh DESCRIPTION +The +.Nm +utility emits only the text portions of well-formed +.Xr mdoc 7 +and +.Xr man 7 +.Ux +manual files. +.Pp +By default, +.Nm +parses standard input and outputs only text nodes, preserving line +and column position. +Escape sequences are omitted from the output. +.Pp +Its arguments are as follows: +.Bl -tag -width Ds +.It Fl w +Output a word list. +This outputs each word of text on its own line. +A +.Qq word , +in this case, refers to whitespace-delimited terms beginning with at +least two letters and not consisting of any escape sequences. +Words have their leading and trailing punctuation +.Pq double-quotes, sentence punctuation, etc. +stripped. +.It Ar +The input files. +.El +.Pp +If a document is not well-formed, it is skipped. +.Pp +The +.Fl i , +.Fl k , +.Fl m , +and +.Fl p +flags are silently discarded for calling compatibility with the +historical deroff. +.Sh EXIT STATUS +The +.Nm +utility exits with one of the following values: +.Pp +.Bl -tag -width Ds -compact +.It 0 +No errors occurred. +.It 6 +An operating system error occurred, for example memory exhaustion or an +error accessing input files. +Such errors cause +.Nm +to exit at once, possibly in the middle of parsing or formatting a file. +The output databases are corrupt and should be removed . +.El +.Sh EXAMPLES +The traditional usage of +.Nm +is for spell-checking manuals on +.Bx . +This is accomplished as follows (assuming British spelling): +.Pp +.Dl $ demandoc -w file.1 | spell -b +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr man 7 , +.Xr mdoc 7 +.Sh HISTORY +.Nm +replaces the historical deroff utility for handling modern +.Xr man 7 +and +.Xr mdoc 7 +documents. +.Sh AUTHORS +The +.Nm +utility was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . Property changes on: vendor/mandoc/20190723/demandoc.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/mandoc/20190723/predefs.in =================================================================== --- vendor/mandoc/20190723/predefs.in (nonexistent) +++ vendor/mandoc/20190723/predefs.in (revision 350350) @@ -0,0 +1,65 @@ +/* $Id: predefs.in,v 1.4 2012/07/18 10:39:19 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * The predefined-string translation tables. Each corresponds to a + * predefined strings from (e.g.) tmac/mdoc/doc-nroff. The left-hand + * side corresponds to the input sequence (\*x, \*(xx and so on). The + * right-hand side is what's produced by libroff. + * + * XXX - C-escape strings! + * XXX - update PREDEF_MAX in roff.c if adding more! + */ + +PREDEF("Am", "&") +PREDEF("Ba", "\\fR|\\fP") +PREDEF("Ge", "\\(>=") +PREDEF("Gt", ">") +PREDEF("If", "infinity") +PREDEF("Le", "\\(<=") +PREDEF("Lq", "\\(lq") +PREDEF("Lt", "<") +PREDEF("Na", "NaN") +PREDEF("Ne", "\\(!=") +PREDEF("Pi", "pi") +PREDEF("Pm", "\\(+-") +PREDEF("Rq", "\\(rq") +PREDEF("left-bracket", "[") +PREDEF("left-parenthesis", "(") +PREDEF("lp", "(") +PREDEF("left-singlequote", "\\(oq") +PREDEF("q", "\\(dq") +PREDEF("quote-left", "\\(oq") +PREDEF("quote-right", "\\(cq") +PREDEF("R", "\\(rg") +PREDEF("right-bracket", "]") +PREDEF("right-parenthesis", ")") +PREDEF("rp", ")") +PREDEF("right-singlequote", "\\(cq") +PREDEF("Tm", "(Tm)") +PREDEF("Px", "POSIX") +PREDEF("Ai", "ANSI") +PREDEF("\'", "\\\'") +PREDEF("aa", "\\(aa") +PREDEF("ga", "\\(ga") +PREDEF("`", "\\`") +PREDEF("lq", "\\(lq") +PREDEF("rq", "\\(rq") +PREDEF("ua", "\\(ua") +PREDEF("va", "\\(va") +PREDEF("<=", "\\(<=") +PREDEF(">=", "\\(>=") Property changes on: vendor/mandoc/20190723/predefs.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property