diff options
author | uqs <uqs@FreeBSD.org> | 2014-02-01 09:27:57 +0000 |
---|---|---|
committer | uqs <uqs@FreeBSD.org> | 2014-02-01 09:27:57 +0000 |
commit | 0745c80c73080aef68ab01f4ccae31a6c48c2b46 (patch) | |
tree | 9d4061e26aeee7d0dac2def4bad4d27a2c9427d9 | |
parent | 06ee51ac6dc8af2b50a8c84976224a439b815071 (diff) | |
parent | 7ae17de732546145e4a582d503a54b9870ada39c (diff) | |
download | FreeBSD-src-0745c80c73080aef68ab01f4ccae31a6c48c2b46.zip FreeBSD-src-0745c80c73080aef68ab01f4ccae31a6c48c2b46.tar.gz |
Merge mdocml v1.12.3 into head
MFC after: 2 weeks
54 files changed, 5281 insertions, 2428 deletions
diff --git a/contrib/mdocml/NEWS b/contrib/mdocml/NEWS new file mode 100644 index 0000000..6f21a38 --- /dev/null +++ b/contrib/mdocml/NEWS @@ -0,0 +1,370 @@ +$Id: NEWS,v 1.3 2013/10/13 16:06:50 schwarze Exp $ + +This file lists the most important changes in the mdocml.bsd.lv distribution. + +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://mdocml.bsd.lv/snapshots/ . diff --git a/contrib/mdocml/TODO b/contrib/mdocml/TODO new file mode 100644 index 0000000..26f42c2 --- /dev/null +++ b/contrib/mdocml/TODO @@ -0,0 +1,330 @@ +************************************************************************ +* Official mandoc TODO. +* $Id: TODO,v 1.162 2013/12/25 14:40:34 schwarze Exp $ +************************************************************************ + +************************************************************************ +* crashes +************************************************************************ + +None known. + +************************************************************************ +* missing features +************************************************************************ + +--- missing roff features ---------------------------------------------- + +- roff.c should treat \n(.H>23 and \n(.V>19 in the pod2man(1) + preamble as true, see for example AUTHORS in MooseX::Getopt.3p + reported by Andreas Voegele <mail at andreasvoegele dot com> + Tue, 22 Nov 2011 15:34:47 +0100 on ports@ + +- .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). + +- .as (append to string) + found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200 + +- .ce (center N lines) + found by naddy@ in xloadimage(1) + found by Juan Francisco Cantero Hurtado <iam at juanfra dot info> + in lang/racket(1) Thu, 20 Jun 2013 03:19:11 +0200 + +- .fc (field control) + found by naddy@ in xloadimage(1) + +- .ll (line length) + found by naddy@ in textproc/enchant(1) Sat, 12 Oct 2013 03:27:10 +0200 + +- .nr third argument (auto-increment step size, requires \n+) + found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700 + +- .ns (no-space mode) occurs in xine-config(1) + reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500 + +- .ta (tab settings) occurs in ircbug(1) and probably gnats(1) + reported by brad@ Sat, 15 Jan 2011 15:50:51 -0500 + +- .ti (temporary indent) + found by naddy@ in xloadimage(1) + found by bentley@ in nmh(1) Mon, 23 Apr 2012 13:38:28 -0600 + +- .while and .shift + found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200 + +- \c (interrupted text) should prevent the line break + even inside .Bd literal; that occurs in chat(8) + also found in cclive(1) - DocBook output + +- \h horizontal move + found in cclive(1) DocBook output + Anthony J. Bentley on discuss@ Sat, 21 Sep 2013 22:29:34 -0600 + +- \n+ and \n- numerical register increment and decrement + found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700 + +- using undefined strings or macros defines them to be empty + wl@ Mon, 14 Nov 2011 14:37:01 +0000 + +--- missing mdoc features ---------------------------------------------- + +- fix bad block nesting involving multiple identical explicit blocks + see the OpenBSD mdoc_macro.c 1.47 commit message + +- .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 + +- 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 + +- \\ is now implemented correctly + * when defining strings and macros using .ds and .de + * when parsing roff(7) and man(7) macro arguments + It does not yet work in mdoc(7) macro arguments + because libmdoc does not yet use mandoc_getarg(). + Also check what happens in plain text, it must be identical to \e. + +- .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). + +- implement blank `Bl -column', such as + .Bl -column + .It foo Ta bar + .El + +- explicitly disallow nested `Bl -column', which would clobber internal + flags defined for struct mdoc_macro + +- 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 <akfaew at jasminek dot net> + via jmc@ Thu, 7 Apr 2011 16:00:53 +0059 + +- 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 ." + +- set a meaningful default if no `Bl' list type is assigned + +- have a blank `It' head for `Bl -tag' not puke + +- 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) + +- 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 + +--- missing man features ----------------------------------------------- + +- groff an-ext.tmac macros (.UR, .UE) occur in xine(5) + reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500 + also occur in freeciv-client(6) freeciv-server(6) freeciv-modpack(6) + reported by bentley@ Tue, 30 Oct 2012 01:05:57 -0600 + +- -T[x]html doesn't stipulate non-collapsing spaces in literal mode + +--- missing tbl features ----------------------------------------------- + +- implement basic non-parametric .de to support e.g. sox(1) + reported by naddy@ Sat, 16 Oct 2010 23:51:57 +0200 + *** sox(1) still doesn't work, tbl(1) errors need investigation + +- allow standalone `.' to be interpreted as an end-of-layout + delimiter instead of being thrown away as a no-op roff line + reported by Yuri Pankov, Wed 18 May 2011 11:34:59 CEST + +--- missing misc features ---------------------------------------------- + +- italic correction (\/) in PostScript mode + Werner LEMBERG on groff at gnu dot org Sun, 10 Nov 2013 12:47:46 + +- The whatis(1) utility looks for whole words in Nm. + If the file name of a page does not agree with the contents of any + of its Nm macros (e.g. pool(9)), add the file name as an Nm entry + to the mandoc.db as well, such that whatis(1) finds it. + If there is a page with a file name that does not appear as a substring + neither in Nm nor in Nd, the same fix would allow finding that page + with apropos(1) using the file name as a key, as well. + Issue reported by tedu@ Fri, 05 Jul 2013 21:15:23 -0400 + +- 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 + +- 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 Texinfo source by yat2m, e.g. security/gnupg + First impression is not that bad. + +- check compatibility with Plan9: + http://swtch.com/usr/local/plan9/tmac/tmac.an + http://swtch.com/plan9port/man/man7/man.html + "Anthony J. Bentley" <anthonyjbentley@gmail.com> 28 Dec 2010 21:58:40 -0700 + +************************************************************************ +* formatting issues: ugly output +************************************************************************ + +- a column list with blank `Ta' cells triggers a spurrious + start-with-whitespace printing of a newline + +- In .Bl -column, + .It Em Authentication<tab>Key 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 + +- 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 + +- .%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". + +- 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 + +- in enclosures, mandoc sometimes fancies a bogus end of sentence + reminded by jmc@ Thu, 23 Sep 2010 18:13:39 +0059 + +- 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 + +************************************************************************ +* formatting issues: gratuitous differences +************************************************************************ + +- .Rv (and probably .Ex) print different text if an `Nm' has been named + or not (run a manual without `Nm blah' to see this). I'm not sure + that this exists in the wild, but it's still an error. + +- In .Bl -bullet, the groff bullet is "+\b+\bo\bo", the mandoc bullet + is just "o\bo". + see for example OpenBSD ksh(1) + +- .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) + +- 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). + +- 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 + +- 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. + +- .Nx 1.0a + should be "NetBSD 1.0A", not "NetBSD 1.0a", + see OpenBSD ccdconfig(8). + +- In .Bl -tag, if a tag exceeds the right margin and must be continued + on the next line, it must be indented by -width, not width+1; + see "rule block|pass" in OpenBSD ifconfig(8). + +- 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 + 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. + +- 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. + +- Header lines of excessive length: + Port OpenBSD man_term.c rev. 1.25 to mdoc_term.c + and document it in mdoc(7) and man(7) COMPATIBILITY + found while talking to Chris Bennett + +- 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). + +************************************************************************ +* performance issues +************************************************************************ + +Several areas can be cleaned up to make mandoc even faster. These are + +- improve hashing mechanism for macros (quite important: performance) + +- improve hashing mechanism for characters (not as important) + +- the PDF file is HUGE: this can be reduced by using relative offsets + +- instead of re-initialising the roff predefined-strings set before each + parse, create a read-only version the first time and copy it + +************************************************************************ +* structural issues +************************************************************************ + +- We use the input line number at several places to distinguish + same-line from different-line input. That plainly doesn't work + with user-defined macros, leading to random breakage. + +- Find better ways to prevent endless loops + in roff(7) macro and string expansion. + +- Finish cleanup of date handling. + Decide which formats should be recognized where. + Update both mdoc(7) and man(7) documentation. + Triggered by Tim van der Molen Tue, 22 Feb 2011 20:30:45 +0100 diff --git a/contrib/mdocml/arch.in b/contrib/mdocml/arch.in index 5113446..d0c445f 100644 --- a/contrib/mdocml/arch.in +++ b/contrib/mdocml/arch.in @@ -1,4 +1,4 @@ -/* $Id: arch.in,v 1.12 2012/01/28 14:02:17 joerg Exp $ */ +/* $Id: arch.in,v 1.14 2013/09/16 22:12:57 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -38,9 +38,9 @@ LINE("arm", "ARM") LINE("arm26", "ARM26") LINE("arm32", "ARM32") LINE("armish", "ARMISH") +LINE("armv7", "ARMv7") LINE("aviion", "AViiON") LINE("atari", "ATARI") -LINE("beagle", "Beagle") LINE("bebox", "BeBox") LINE("cats", "cats") LINE("cesfic", "CESFIC") @@ -81,6 +81,7 @@ LINE("netwinder", "NetWinder") LINE("news68k", "NeWS68k") LINE("newsmips", "NeWSMIPS") LINE("next68k", "NeXT68k") +LINE("octeon", "OCTEON") LINE("ofppc", "OFPPC") LINE("palm", "Palm") LINE("pc532", "PC532") diff --git a/contrib/mdocml/chars.c b/contrib/mdocml/chars.c index ce03347..3ad1f57 100644 --- a/contrib/mdocml/chars.c +++ b/contrib/mdocml/chars.c @@ -1,4 +1,4 @@ -/* $Id: chars.c,v 1.52 2011/11/08 00:15:23 kristaps Exp $ */ +/* $Id: chars.c,v 1.54 2013/06/20 22:39:30 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -37,7 +37,7 @@ struct ln { int unicode; }; -#define LINES_MAX 328 +#define LINES_MAX 329 #define CHAR(in, ch, code) \ { NULL, (in), (ch), (code) }, @@ -77,7 +77,7 @@ mchars_alloc(void) */ tab = mandoc_malloc(sizeof(struct mchars)); - htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln **)); + htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln *)); for (i = 0; i < LINES_MAX; i++) { hash = (int)lines[i].code[0] - PRINT_LO; diff --git a/contrib/mdocml/chars.in b/contrib/mdocml/chars.in index a4c45b3..cc6549e 100644 --- a/contrib/mdocml/chars.in +++ b/contrib/mdocml/chars.in @@ -1,4 +1,4 @@ -/* $Id: chars.in,v 1.42 2011/10/02 10:02:26 kristaps Exp $ */ +/* $Id: chars.in,v 1.43 2013/06/20 22:39:30 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -42,6 +42,7 @@ CHAR("&", "", 0) CHAR("^", "", 0) CHAR("|", "", 0) CHAR("}", "", 0) +CHAR("t", "", 0) /* Accents. */ CHAR("a\"", "\"", 779) diff --git a/contrib/mdocml/config.h b/contrib/mdocml/config.h index 12d3355..0b070d5 100644 --- a/contrib/mdocml/config.h +++ b/contrib/mdocml/config.h @@ -7,6 +7,7 @@ #include <stdio.h> +#define VERSION "1.12.3" #define HAVE_FGETLN #define HAVE_STRPTIME #define HAVE_GETSUBOPT @@ -31,14 +32,16 @@ # endif #endif -#if defined(__APPLE__) -# define htobe32(x) OSSwapHostToBigInt32(x) -# define betoh32(x) OSSwapBigToHostInt32(x) -# define htobe64(x) OSSwapHostToBigInt64(x) -# define betoh64(x) OSSwapBigToHostInt64(x) -#elif defined(__linux__) -# define betoh32(x) be32toh(x) -# define betoh64(x) be64toh(x) +#ifndef HAVE_BETOH64 +# if defined(__APPLE__) +# define betoh64(x) OSSwapBigToHostInt64(x) +# define htobe64(x) OSSwapHostToBigInt64(x) +# elif defined(__sun) +# define betoh64(x) BE_64(x) +# define htobe64(x) BE_64(x) +# else +# define betoh64(x) be64toh(x) +# endif #endif #ifndef HAVE_STRLCAT diff --git a/contrib/mdocml/eqn.7 b/contrib/mdocml/eqn.7 index f86b9c4..dcbad41 100644 --- a/contrib/mdocml/eqn.7 +++ b/contrib/mdocml/eqn.7 @@ -1,4 +1,4 @@ -.\" $Id: eqn.7,v 1.28 2011/09/25 18:37:09 schwarze Exp $ +.\" $Id: eqn.7,v 1.29 2013/07/13 19:41:16 schwarze Exp $ .\" .\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 25 2011 $ +.Dd $Mdocdate: July 13 2013 $ .Dt EQN 7 .Os .Sh NAME @@ -276,5 +276,4 @@ was added in 2011. This .Nm reference was written by -.An Kristaps Dzonsons , -.Mt kristaps@bsd.lv . +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . diff --git a/contrib/mdocml/html.c b/contrib/mdocml/html.c index 326df03..9d28b42 100644 --- a/contrib/mdocml/html.c +++ b/contrib/mdocml/html.c @@ -1,7 +1,7 @@ -/* $Id: html.c,v 1.150 2011/10/05 21:35:17 kristaps Exp $ */ +/* $Id: html.c,v 1.152 2013/08/08 20:07:47 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -235,6 +235,9 @@ print_metaf(struct html *h, enum mandoc_esc deco) case (ESCAPE_FONTBOLD): font = HTMLFONT_BOLD; break; + case (ESCAPE_FONTBI): + font = HTMLFONT_BI; + break; case (ESCAPE_FONT): /* FALLTHROUGH */ case (ESCAPE_FONTROMAN): @@ -253,17 +256,27 @@ print_metaf(struct html *h, enum mandoc_esc deco) h->metal = h->metac; h->metac = font; - if (HTMLFONT_NONE != font) - h->metaf = HTMLFONT_BOLD == font ? - print_otag(h, TAG_B, 0, NULL) : - print_otag(h, TAG_I, 0, NULL); + switch (font) { + case (HTMLFONT_ITALIC): + h->metaf = print_otag(h, TAG_I, 0, NULL); + break; + case (HTMLFONT_BOLD): + h->metaf = print_otag(h, TAG_B, 0, NULL); + break; + case (HTMLFONT_BI): + h->metaf = print_otag(h, TAG_B, 0, NULL); + print_otag(h, TAG_I, 0, NULL); + break; + default: + break; + } } int html_strlen(const char *cp) { - int ssz, sz; - const char *seq, *p; + size_t rsz; + int skip, sz; /* * Account for escaped sequences within string length @@ -274,10 +287,21 @@ html_strlen(const char *cp) */ sz = 0; - while (NULL != (p = strchr(cp, '\\'))) { - sz += (int)(p - cp); - ++cp; - switch (mandoc_escape(&cp, &seq, &ssz)) { + skip = 0; + while (1) { + rsz = strcspn(cp, "\\"); + if (rsz) { + cp += rsz; + if (skip) { + skip = 0; + rsz--; + } + sz += rsz; + } + if ('\0' == *cp) + break; + cp++; + switch (mandoc_escape(&cp, NULL, NULL)) { case (ESCAPE_ERROR): return(sz); case (ESCAPE_UNICODE): @@ -285,15 +309,19 @@ html_strlen(const char *cp) case (ESCAPE_NUMBERED): /* FALLTHROUGH */ case (ESCAPE_SPECIAL): - sz++; + if (skip) + skip = 0; + else + sz++; + break; + case (ESCAPE_SKIPCHAR): + skip = 1; break; default: break; } } - - assert(sz >= 0); - return(sz + strlen(cp)); + return(sz); } static int @@ -308,6 +336,12 @@ print_encode(struct html *h, const char *p, int norecurse) nospace = 0; while ('\0' != *p) { + if (HTML_SKIPCHAR & h->flags && '\\' != *p) { + h->flags &= ~HTML_SKIPCHAR; + p++; + continue; + } + sz = strcspn(p, rejs); fwrite(p, 1, sz, stdout); @@ -338,6 +372,33 @@ print_encode(struct html *h, const char *p, int norecurse) break; switch (esc) { + case (ESCAPE_FONT): + /* FALLTHROUGH */ + case (ESCAPE_FONTPREV): + /* FALLTHROUGH */ + case (ESCAPE_FONTBOLD): + /* FALLTHROUGH */ + case (ESCAPE_FONTITALIC): + /* FALLTHROUGH */ + case (ESCAPE_FONTBI): + /* FALLTHROUGH */ + case (ESCAPE_FONTROMAN): + if (0 == norecurse) + print_metaf(h, esc); + continue; + case (ESCAPE_SKIPCHAR): + h->flags |= HTML_SKIPCHAR; + continue; + default: + break; + } + + if (h->flags & HTML_SKIPCHAR) { + h->flags &= ~HTML_SKIPCHAR; + continue; + } + + switch (esc) { case (ESCAPE_UNICODE): /* Skip passed "u" header. */ c = mchars_num2uc(seq + 1, len - 1); @@ -356,19 +417,6 @@ print_encode(struct html *h, const char *p, int norecurse) else if (-1 == c && 1 == len) putchar((int)*seq); break; - case (ESCAPE_FONT): - /* FALLTHROUGH */ - case (ESCAPE_FONTPREV): - /* FALLTHROUGH */ - case (ESCAPE_FONTBOLD): - /* FALLTHROUGH */ - case (ESCAPE_FONTITALIC): - /* FALLTHROUGH */ - case (ESCAPE_FONTROMAN): - if (norecurse) - break; - print_metaf(h, esc); - break; case (ESCAPE_NOSPACE): if ('\0' == *p) nospace = 1; @@ -511,10 +559,20 @@ print_text(struct html *h, const char *word) } assert(NULL == h->metaf); - if (HTMLFONT_NONE != h->metac) - h->metaf = HTMLFONT_BOLD == h->metac ? - print_otag(h, TAG_B, 0, NULL) : - print_otag(h, TAG_I, 0, NULL); + switch (h->metac) { + case (HTMLFONT_ITALIC): + h->metaf = print_otag(h, TAG_I, 0, NULL); + break; + case (HTMLFONT_BOLD): + h->metaf = print_otag(h, TAG_B, 0, NULL); + break; + case (HTMLFONT_BI): + h->metaf = print_otag(h, TAG_B, 0, NULL); + print_otag(h, TAG_I, 0, NULL); + break; + default: + break; + } assert(word); if ( ! print_encode(h, word, 0)) { diff --git a/contrib/mdocml/html.h b/contrib/mdocml/html.h index 60960702..894cfc4 100644 --- a/contrib/mdocml/html.h +++ b/contrib/mdocml/html.h @@ -1,4 +1,4 @@ -/* $Id: html.h,v 1.47 2011/10/05 21:35:17 kristaps Exp $ */ +/* $Id: html.h,v 1.49 2013/08/08 20:07:47 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -75,6 +75,7 @@ enum htmlfont { HTMLFONT_NONE = 0, HTMLFONT_BOLD, HTMLFONT_ITALIC, + HTMLFONT_BI, HTMLFONT_MAX }; @@ -117,6 +118,7 @@ struct html { #define HTML_PREKEEP (1 << 3) #define HTML_NONOSPACE (1 << 4) /* never add spaces */ #define HTML_LITERAL (1 << 5) /* literal (e.g., <PRE>) context */ +#define HTML_SKIPCHAR (1 << 6) /* skip the next character */ struct tagq tags; /* stack of open tags */ struct rofftbl tbl; /* current table */ struct tag *tblt; /* current open table scope */ diff --git a/contrib/mdocml/lib.in b/contrib/mdocml/lib.in index 6af9110..6e7bb78 100644 --- a/contrib/mdocml/lib.in +++ b/contrib/mdocml/lib.in @@ -1,4 +1,4 @@ -/* $Id: lib.in,v 1.13 2012/01/28 23:46:28 joerg Exp $ */ +/* $Id: lib.in,v 1.17 2013/10/13 15:24:03 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -38,18 +38,24 @@ 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("libdevattr", "Device attribute and event library (libdevattr, \\-ldevattr)") 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("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("libfetch", "File Transfer Library for URLs (libfetch, \\-lfetch)") +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("libgeom", "Userland API Library for Kernel GEOM subsystem (libgeom, \\-lgeom)") LINE("libgpib", "General-Purpose Instrument Bus (GPIB) library (libgpib, \\-lgpib)") +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)") @@ -57,24 +63,31 @@ LINE("libipx", "IPX Address Conversion Support Library (libipx, \\-lipx)") LINE("libiscsi", "iSCSI protocol library (libiscsi, \\-liscsi)") LINE("libisns", "Internet Storage Name Service Library (libisns, \\-lisns)") LINE("libjail", "Jail Library (libjail, \\-ljail)") -LINE("libkiconv", "Kernel side iconv library (libkiconv, \\-lkiconv)") +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("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("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)") @@ -82,6 +95,7 @@ LINE("libprop", "Property Container Object Library (libprop, \\-lprop)") LINE("libpthread", "POSIX Threads Library (libpthread, \\-lpthread)") 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)") @@ -94,6 +108,8 @@ LINE("libsdp", "Bluetooth Service Discovery Protocol User Library (libsdp, \\-l LINE("libssp", "Buffer Overflow Protection Library (libssp, \\-lssp)") LINE("libstdthreads", "C11 Threads Library (libstdthreads, \\-lstdthreads)") LINE("libSystem", "System Library (libSystem, \\-lSystem)") +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)") diff --git a/contrib/mdocml/libman.h b/contrib/mdocml/libman.h index 4bc5128..f2ba6a1 100644 --- a/contrib/mdocml/libman.h +++ b/contrib/mdocml/libman.h @@ -1,4 +1,4 @@ -/* $Id: libman.h,v 1.55 2011/11/07 01:24:40 schwarze Exp $ */ +/* $Id: libman.h,v 1.56 2012/11/17 00:26:33 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -39,7 +39,7 @@ struct man { struct roff *roff; }; -#define MACRO_PROT_ARGS struct man *m, \ +#define MACRO_PROT_ARGS struct man *man, \ enum mant tok, \ int line, \ int ppos, \ @@ -61,10 +61,10 @@ extern const struct man_macro *const man_macros; __BEGIN_DECLS -#define man_pmsg(m, l, p, t) \ - mandoc_msg((t), (m)->parse, (l), (p), NULL) -#define man_nmsg(m, n, t) \ - mandoc_msg((t), (m)->parse, (n)->line, (n)->pos, NULL) +#define man_pmsg(man, l, p, t) \ + mandoc_msg((t), (man)->parse, (l), (p), NULL) +#define man_nmsg(man, n, t) \ + mandoc_msg((t), (man)->parse, (n)->line, (n)->pos, NULL) int man_word_alloc(struct man *, int, int, const char *); int man_block_alloc(struct man *, int, int, enum mant); int man_head_alloc(struct man *, int, int, enum mant); diff --git a/contrib/mdocml/libmandoc.h b/contrib/mdocml/libmandoc.h index de42288..3c005e1 100644 --- a/contrib/mdocml/libmandoc.h +++ b/contrib/mdocml/libmandoc.h @@ -1,6 +1,7 @@ -/* $Id: libmandoc.h,v 1.29 2011/12/02 01:37:14 schwarze Exp $ */ +/* $Id: libmandoc.h,v 1.35 2013/12/15 21:23:52 schwarze Exp $ */ /* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,11 +30,6 @@ enum rofferr { ROFF_ERR /* badness: puke and stop */ }; -enum regs { - REG_nS = 0, /* nS register */ - REG__MAX -}; - __BEGIN_DECLS struct roff; @@ -47,12 +43,11 @@ void mandoc_vmsg(enum mandocerr, struct mparse *, char *mandoc_getarg(struct mparse *, char **, int, int *); char *mandoc_normdate(struct mparse *, char *, int, int); int mandoc_eos(const char *, size_t, int); -int mandoc_getcontrol(const char *, int *); int mandoc_strntoi(const char *, size_t, int); const char *mandoc_a2msec(const char*); void mdoc_free(struct mdoc *); -struct mdoc *mdoc_alloc(struct roff *, struct mparse *); +struct mdoc *mdoc_alloc(struct roff *, struct mparse *, char *); void mdoc_reset(struct mdoc *); int mdoc_parseln(struct mdoc *, int, char *, int); int mdoc_endparse(struct mdoc *); @@ -68,15 +63,16 @@ int man_addspan(struct man *, const struct tbl_span *); int man_addeqn(struct man *, const struct eqn *); void roff_free(struct roff *); -struct roff *roff_alloc(struct mparse *); +struct roff *roff_alloc(enum mparset, struct mparse *); void roff_reset(struct roff *); enum rofferr roff_parseln(struct roff *, int, char **, size_t *, int, int *); void roff_endparse(struct roff *); -int roff_regisset(const struct roff *, enum regs); -unsigned int roff_regget(const struct roff *, enum regs); -void roff_regunset(struct roff *, enum regs); +void roff_setreg(struct roff *, const char *, int, char sign); +int roff_getreg(const struct roff *, const char *); char *roff_strdup(const struct roff *, const char *); +int roff_getcontrol(const struct roff *, + const char *, int *); #if 0 char roff_eqndelim(const struct roff *); void roff_openeqn(struct roff *, const char *, diff --git a/contrib/mdocml/libmdoc.h b/contrib/mdocml/libmdoc.h index af17292..3f14519 100644 --- a/contrib/mdocml/libmdoc.h +++ b/contrib/mdocml/libmdoc.h @@ -1,6 +1,7 @@ -/* $Id: libmdoc.h,v 1.78 2011/12/02 01:37:14 schwarze Exp $ */ +/* $Id: libmdoc.h,v 1.82 2013/10/21 23:47:58 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,6 +25,7 @@ enum mdoc_next { struct mdoc { struct mparse *parse; /* parse pointer */ + char *defos; /* default argument for .Os */ int flags; /* parse flags */ #define MDOC_HALT (1 << 0) /* error in parse: halt */ #define MDOC_LITERAL (1 << 1) /* in a literal scope */ @@ -33,6 +35,8 @@ struct mdoc { #define MDOC_PPHRASE (1 << 5) /* within a partial 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 */ enum mdoc_next next; /* where to put the next node */ struct mdoc_node *last; /* the last node parsed */ struct mdoc_node *first; /* the first node parsed */ @@ -42,7 +46,7 @@ struct mdoc { struct roff *roff; }; -#define MACRO_PROT_ARGS struct mdoc *m, \ +#define MACRO_PROT_ARGS struct mdoc *mdoc, \ enum mdoct tok, \ int line, \ int ppos, \ @@ -56,8 +60,8 @@ struct mdoc_macro { #define MDOC_PARSED (1 << 1) #define MDOC_EXPLICIT (1 << 2) #define MDOC_PROLOGUE (1 << 3) -#define MDOC_IGNDELIM (1 << 4) - /* Reserved words in arguments treated as text. */ +#define MDOC_IGNDELIM (1 << 4) +#define MDOC_JOIN (1 << 5) }; enum margserr { @@ -99,13 +103,14 @@ extern const struct mdoc_macro *const mdoc_macros; __BEGIN_DECLS -#define mdoc_pmsg(m, l, p, t) \ - mandoc_msg((t), (m)->parse, (l), (p), NULL) -#define mdoc_nmsg(m, n, t) \ - mandoc_msg((t), (m)->parse, (n)->line, (n)->pos, NULL) +#define mdoc_pmsg(mdoc, l, p, t) \ + mandoc_msg((t), (mdoc)->parse, (l), (p), NULL) +#define mdoc_nmsg(mdoc, n, t) \ + mandoc_msg((t), (mdoc)->parse, (n)->line, (n)->pos, NULL) int mdoc_macro(MACRO_PROT_ARGS); int mdoc_word_alloc(struct mdoc *, int, int, const char *); +void mdoc_word_append(struct mdoc *, const char *); int mdoc_elem_alloc(struct mdoc *, int, int, enum mdoct, struct mdoc_arg *); int mdoc_block_alloc(struct mdoc *, int, int, @@ -113,10 +118,10 @@ int mdoc_block_alloc(struct mdoc *, int, int, int mdoc_head_alloc(struct mdoc *, int, int, enum mdoct); int mdoc_tail_alloc(struct mdoc *, int, int, enum mdoct); int mdoc_body_alloc(struct mdoc *, int, int, enum mdoct); -int mdoc_endbody_alloc(struct mdoc *m, int line, int pos, - enum mdoct tok, struct mdoc_node *body, - enum mdoc_endbody end); +int mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct, + struct mdoc_node *, enum mdoc_endbody); void mdoc_node_delete(struct mdoc *, struct mdoc_node *); +int mdoc_node_relink(struct mdoc *, struct mdoc_node *); void mdoc_hash_init(void); enum mdoct mdoc_hash_find(const char *); const char *mdoc_a2att(const char *); diff --git a/contrib/mdocml/libroff.h b/contrib/mdocml/libroff.h index 0bdd5a3..5b84c5f 100644 --- a/contrib/mdocml/libroff.h +++ b/contrib/mdocml/libroff.h @@ -1,4 +1,4 @@ -/* $Id: libroff.h,v 1.27 2011/07/25 15:37:00 kristaps Exp $ */ +/* $Id: libroff.h,v 1.28 2013/05/31 21:37:17 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -31,7 +31,7 @@ struct tbl_node { int pos; /* invocation column */ int line; /* invocation line */ enum tbl_part part; - struct tbl opts; + struct tbl_opts opts; struct tbl_row *first_row; struct tbl_row *last_row; struct tbl_span *first_span; diff --git a/contrib/mdocml/main.c b/contrib/mdocml/main.c index fec83fb..7e5c7a9 100644 --- a/contrib/mdocml/main.c +++ b/contrib/mdocml/main.c @@ -1,7 +1,7 @@ -/* $Id: main.c,v 1.165 2011/10/06 22:29:12 kristaps Exp $ */ +/* $Id: main.c,v 1.167 2012/11/19 17:22:26 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2011, 2012 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 @@ -85,6 +85,7 @@ main(int argc, char *argv[]) struct curparse curp; enum mparset type; enum mandoclevel rc; + char *defos; progname = strrchr(argv[0], '/'); if (progname == NULL) @@ -97,10 +98,24 @@ main(int argc, char *argv[]) type = MPARSE_AUTO; curp.outtype = OUTT_ASCII; curp.wlevel = MANDOCLEVEL_FATAL; + defos = NULL; /* LINTED */ - while (-1 != (c = getopt(argc, argv, "m:O:T:VW:"))) + while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:"))) switch (c) { + case ('I'): + if (strncmp(optarg, "os=", 3)) { + fprintf(stderr, "-I%s: Bad argument\n", + optarg); + return((int)MANDOCLEVEL_BADARG); + } + if (defos) { + fprintf(stderr, "-I%s: Duplicate argument\n", + optarg); + return((int)MANDOCLEVEL_BADARG); + } + defos = mandoc_strdup(optarg + 3); + break; case ('m'): if ( ! moptions(&type, optarg)) return((int)MANDOCLEVEL_BADARG); @@ -125,7 +140,7 @@ main(int argc, char *argv[]) /* NOTREACHED */ } - curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp); + curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp, defos); /* * Conditionally start up the lookaside buffer before parsing. @@ -152,6 +167,7 @@ main(int argc, char *argv[]) (*curp.outfree)(curp.outdata); if (curp.mp) mparse_free(curp.mp); + free(defos); return((int)rc); } @@ -170,12 +186,12 @@ usage(void) fprintf(stderr, "usage: %s " "[-V] " - "[-foption] " + "[-Ios=name] " "[-mformat] " "[-Ooption] " "[-Toutput] " - "[-Wlevel] " - "[file...]\n", + "[-Wlevel]\n" + "\t [file ...]\n", progname); exit((int)MANDOCLEVEL_BADARG); diff --git a/contrib/mdocml/man.7 b/contrib/mdocml/man.7 index 1715a7c..f2f4d1d 100644 --- a/contrib/mdocml/man.7 +++ b/contrib/mdocml/man.7 @@ -1,7 +1,7 @@ -.\" $Id: man.7,v 1.113 2012/01/03 15:16:24 kristaps Exp $ +.\" $Id: man.7,v 1.120 2013/09/16 22:58:57 schwarze Exp $ .\" -.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 3 2012 $ +.Dd $Mdocdate: September 16 2013 $ .Dt MAN 7 .Os .Sh NAME @@ -253,6 +253,7 @@ in the alphabetical reference below. .It Sx IP Ta indented paragraph: Op Ar head Op Ar width .It Sx TP Ta tagged paragraph: Op Ar width .It Sx HP Ta hanged paragraph: Op Ar width +.It Sx PD Ta set vertical paragraph distance: Op Ar height .It Sx \&br Ta force output line break in text mode (no arguments) .It Sx \&sp Ta force vertical space: Op Ar height .It Sx fi , nf Ta fill mode and no-fill mode (no arguments) @@ -272,10 +273,6 @@ in the alphabetical reference below. .It Sx RB Ta alternate between roman and boldface fonts .It Sx RI Ta alternate between roman and italic fonts .El -.Ss Semantic markup -.Bl -column "PP, LP, P" description -.It Sx OP Ta optional arguments -.El .Sh MACRO REFERENCE This section is a canonical reference to all macros, arranged alphabetically. @@ -343,6 +340,18 @@ and .Ss \&DT Has no effect. Included for compatibility. +.Ss \&EE +This is a non-standard GNU extension, included only for compatibility. +In +.Xr mandoc 1 , +it does the same as +.Sx \&fi . +.Ss \&EX +This is a non-standard GNU extension, included only for compatibility. +In +.Xr mandoc 1 , +it does the same as +.Sx \&nf . .Ss \&HP Begin a paragraph whose initial output line is left-justified, but subsequent output lines are indented, with the following syntax: @@ -353,8 +362,9 @@ subsequent output lines are indented, with the following syntax: .Pp The .Cm width -argument must conform to -.Sx Scaling Widths . +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 @@ -396,8 +406,9 @@ Begin an indented paragraph with the following syntax: .Pp The .Cm width -argument defines the width of the left margin and is defined by -.Sx Scaling Widths . +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 @@ -443,7 +454,8 @@ and .Sx \&TP . .Ss \&OP Optional command-line argument. -This has the following syntax: +This is a non-standard GNU extension, included only for compatibility. +It has the following syntax: .Bd -filled -offset indent .Pf \. Sx \&OP .Cm key Op Cm value @@ -465,6 +477,36 @@ See also .Sx \&PP , and .Sx \&TP . +.Ss \&PD +Specify the vertical space to be inserted before each new paragraph. +.br +The syntax is as follows: +.Bd -filled -offset indent +.Pf \. Sx \&PD +.Op Cm height +.Ed +.Pp +The +.Cm height +argument is a +.Xr roff 7 +scaling width. +It defaults to +.Cm 1v . +If the unit is omitted, +.Cm v +is assumed. +.Pp +This macro affects the spacing before any subsequent instances of +.Sx \&HP , +.Sx \&IP , +.Sx \&LP , +.Sx \&P , +.Sx \&PP , +.Sx \&SH , +.Sx \&SS , +and +.Sx \&TP . .Ss \&PP Synonym for .Sx \&LP . @@ -529,8 +571,9 @@ This has the following syntax: .Pp The .Cm width -argument must conform to -.Sx Scaling Widths . +argument is a +.Xr roff 7 +scaling width. If not specified, the saved or default width is used. .Pp See also @@ -595,8 +638,9 @@ The syntax is as follows: .Pp The .Cm width -argument must conform to -.Sx Scaling Widths . +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 @@ -609,7 +653,8 @@ and .Sx \&PP . .Ss \&UC Sets the volume for the footer for compatibility with man pages from -BSD releases. +.Bx +releases. The optional first argument specifies which release it is from. .Ss \&br Breaks the current line. @@ -653,10 +698,10 @@ Insert vertical spaces into output with the following syntax: .Op Cm height .Ed .Pp -Insert +The .Cm height -spaces, which must conform to -.Sx Scaling Widths . +argument is a scaling width as described in +.Xr roff 7 . If 0, this is equivalent to the .Sx \&br macro. @@ -904,8 +949,7 @@ utility written by Kristaps Dzonsons appeared in This .Nm reference was written by -.An Kristaps Dzonsons , -.Mt kristaps@bsd.lv . +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . .Sh CAVEATS Do not use this language. Use diff --git a/contrib/mdocml/man.c b/contrib/mdocml/man.c index 1bea561..e6e1c28 100644 --- a/contrib/mdocml/man.c +++ b/contrib/mdocml/man.c @@ -1,4 +1,4 @@ -/* $Id: man.c,v 1.115 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man.c,v 1.121 2013/11/10 22:54:40 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -40,7 +40,8 @@ const char *const __man_macronames[MAN_MAX] = { "RI", "na", "sp", "nf", "fi", "RE", "RS", "DT", "UC", "PD", "AT", "in", - "ft", "OP" + "ft", "OP", "EX", "EE", + "UR", "UE" }; const char * const *man_macronames = __man_macronames; @@ -60,20 +61,20 @@ static int man_descope(struct man *, int, int); const struct man_node * -man_node(const struct man *m) +man_node(const struct man *man) { - assert( ! (MAN_HALT & m->flags)); - return(m->first); + assert( ! (MAN_HALT & man->flags)); + return(man->first); } const struct man_meta * -man_meta(const struct man *m) +man_meta(const struct man *man) { - assert( ! (MAN_HALT & m->flags)); - return(&m->meta); + assert( ! (MAN_HALT & man->flags)); + return(&man->meta); } @@ -112,28 +113,28 @@ man_alloc(struct roff *roff, struct mparse *parse) int -man_endparse(struct man *m) +man_endparse(struct man *man) { - assert( ! (MAN_HALT & m->flags)); - if (man_macroend(m)) + assert( ! (MAN_HALT & man->flags)); + if (man_macroend(man)) return(1); - m->flags |= MAN_HALT; + man->flags |= MAN_HALT; return(0); } int -man_parseln(struct man *m, int ln, char *buf, int offs) +man_parseln(struct man *man, int ln, char *buf, int offs) { - m->flags |= MAN_NEWLINE; + man->flags |= MAN_NEWLINE; - assert( ! (MAN_HALT & m->flags)); + assert( ! (MAN_HALT & man->flags)); - return (mandoc_getcontrol(buf, &offs) ? - man_pmacro(m, ln, buf, offs) : - man_ptext(m, ln, buf, offs)); + return (roff_getcontrol(man->roff, buf, &offs) ? + man_pmacro(man, ln, buf, offs) : + man_ptext(man, ln, buf, offs)); } @@ -157,16 +158,16 @@ man_free1(struct man *man) static void -man_alloc1(struct man *m) +man_alloc1(struct man *man) { - memset(&m->meta, 0, sizeof(struct man_meta)); - m->flags = 0; - m->last = mandoc_calloc(1, sizeof(struct man_node)); - m->first = m->last; - m->last->type = MAN_ROOT; - m->last->tok = MAN_MAX; - m->next = MAN_NEXT_CHILD; + memset(&man->meta, 0, sizeof(struct man_meta)); + man->flags = 0; + man->last = mandoc_calloc(1, sizeof(struct man_node)); + man->first = man->last; + man->last->type = MAN_ROOT; + man->last->tok = MAN_MAX; + man->next = MAN_NEXT_CHILD; } @@ -234,7 +235,7 @@ man_node_append(struct man *man, struct man_node *p) static struct man_node * -man_node_alloc(struct man *m, int line, int pos, +man_node_alloc(struct man *man, int line, int pos, enum man_type type, enum mant tok) { struct man_node *p; @@ -245,89 +246,89 @@ man_node_alloc(struct man *m, int line, int pos, p->type = type; p->tok = tok; - if (MAN_NEWLINE & m->flags) + if (MAN_NEWLINE & man->flags) p->flags |= MAN_LINE; - m->flags &= ~MAN_NEWLINE; + man->flags &= ~MAN_NEWLINE; return(p); } int -man_elem_alloc(struct man *m, int line, int pos, enum mant tok) +man_elem_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_ELEM, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_ELEM, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_tail_alloc(struct man *m, int line, int pos, enum mant tok) +man_tail_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_TAIL, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_TAIL, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_head_alloc(struct man *m, int line, int pos, enum mant tok) +man_head_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_HEAD, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_HEAD, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_body_alloc(struct man *m, int line, int pos, enum mant tok) +man_body_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_BODY, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_BODY, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_block_alloc(struct man *m, int line, int pos, enum mant tok) +man_block_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_BLOCK, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_BLOCK, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_word_alloc(struct man *m, int line, int pos, const char *word) +man_word_alloc(struct man *man, int line, int pos, const char *word) { struct man_node *n; - n = man_node_alloc(m, line, pos, MAN_TEXT, MAN_MAX); - n->string = roff_strdup(m->roff, word); + n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX); + n->string = roff_strdup(man->roff, word); - if ( ! man_node_append(m, n)) + if ( ! man_node_append(man, n)) return(0); - m->next = MAN_NEXT_SIBLING; + man->next = MAN_NEXT_SIBLING; return(1); } @@ -347,52 +348,52 @@ man_node_free(struct man_node *p) void -man_node_delete(struct man *m, struct man_node *p) +man_node_delete(struct man *man, struct man_node *p) { while (p->child) - man_node_delete(m, p->child); + man_node_delete(man, p->child); - man_node_unlink(m, p); + man_node_unlink(man, p); man_node_free(p); } int -man_addeqn(struct man *m, const struct eqn *ep) +man_addeqn(struct man *man, const struct eqn *ep) { struct man_node *n; - assert( ! (MAN_HALT & m->flags)); + assert( ! (MAN_HALT & man->flags)); - n = man_node_alloc(m, ep->ln, ep->pos, MAN_EQN, MAN_MAX); + n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX); n->eqn = ep; - if ( ! man_node_append(m, n)) + if ( ! man_node_append(man, n)) return(0); - m->next = MAN_NEXT_SIBLING; - return(man_descope(m, ep->ln, ep->pos)); + man->next = MAN_NEXT_SIBLING; + return(man_descope(man, ep->ln, ep->pos)); } int -man_addspan(struct man *m, const struct tbl_span *sp) +man_addspan(struct man *man, const struct tbl_span *sp) { struct man_node *n; - assert( ! (MAN_HALT & m->flags)); + assert( ! (MAN_HALT & man->flags)); - n = man_node_alloc(m, sp->line, 0, MAN_TBL, MAN_MAX); + n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX); n->span = sp; - if ( ! man_node_append(m, n)) + if ( ! man_node_append(man, n)) return(0); - m->next = MAN_NEXT_SIBLING; - return(man_descope(m, sp->line, 0)); + man->next = MAN_NEXT_SIBLING; + return(man_descope(man, sp->line, 0)); } static int -man_descope(struct man *m, int line, int offs) +man_descope(struct man *man, int line, int offs) { /* * Co-ordinate what happens with having a next-line scope open: @@ -400,44 +401,51 @@ man_descope(struct man *m, int line, int offs) * out the block scope (also if applicable). */ - if (MAN_ELINE & m->flags) { - m->flags &= ~MAN_ELINE; - if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) + if (MAN_ELINE & man->flags) { + man->flags &= ~MAN_ELINE; + if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); } - if ( ! (MAN_BLINE & m->flags)) + if ( ! (MAN_BLINE & man->flags)) return(1); - m->flags &= ~MAN_BLINE; + man->flags &= ~MAN_BLINE; - if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); - return(man_body_alloc(m, line, offs, m->last->tok)); + return(man_body_alloc(man, line, offs, man->last->tok)); } static int -man_ptext(struct man *m, int line, char *buf, int offs) +man_ptext(struct man *man, int line, char *buf, int offs) { int i; /* Literal free-form text whitespace is preserved. */ - if (MAN_LITERAL & m->flags) { - if ( ! man_word_alloc(m, line, offs, buf + offs)) + if (MAN_LITERAL & man->flags) { + if ( ! man_word_alloc(man, line, offs, buf + offs)) return(0); - return(man_descope(m, line, offs)); + return(man_descope(man, line, offs)); } - /* Pump blank lines directly into the backend. */ - for (i = offs; ' ' == buf[i]; i++) /* Skip leading whitespace. */ ; + /* + * Blank lines are ignored right after headings + * but add a single vertical space elsewhere. + */ + if ('\0' == buf[i]) { /* Allocate a blank entry. */ - if ( ! man_word_alloc(m, line, offs, "")) - return(0); - return(man_descope(m, line, offs)); + if (MAN_SH != man->last->tok && + MAN_SS != man->last->tok) { + if ( ! man_elem_alloc(man, line, offs, MAN_sp)) + return(0); + man->next = MAN_NEXT_SIBLING; + } + return(1); } /* @@ -450,7 +458,7 @@ man_ptext(struct man *m, int line, char *buf, int offs) if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { if (i > 1 && '\\' != buf[i - 2]) - man_pmsg(m, line, i - 1, MANDOCERR_EOLNSPACE); + man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE); for (--i; i && ' ' == buf[i]; i--) /* Spin back to non-space. */ ; @@ -461,7 +469,7 @@ man_ptext(struct man *m, int line, char *buf, int offs) buf[i] = '\0'; } - if ( ! man_word_alloc(m, line, offs, buf + offs)) + if ( ! man_word_alloc(man, line, offs, buf + offs)) return(0); /* @@ -472,13 +480,13 @@ man_ptext(struct man *m, int line, char *buf, int offs) assert(i); if (mandoc_eos(buf, (size_t)i, 0)) - m->last->flags |= MAN_EOS; + man->last->flags |= MAN_EOS; - return(man_descope(m, line, offs)); + return(man_descope(man, line, offs)); } static int -man_pmacro(struct man *m, int ln, char *buf, int offs) +man_pmacro(struct man *man, int ln, char *buf, int offs) { int i, ppos; enum mant tok; @@ -486,7 +494,7 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) struct man_node *n; if ('"' == buf[offs]) { - man_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT); + man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT); return(1); } else if ('\0' == buf[offs]) return(1); @@ -508,7 +516,7 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; if (MAN_MAX == tok) { - mandoc_vmsg(MANDOCERR_MACRO, m->parse, ln, + mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln, ppos, "%s", buf + ppos - 1); return(1); } @@ -524,7 +532,7 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) - man_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE); + man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE); /* * Remove prior ELINE macro, as it's being clobbered by a new @@ -533,8 +541,8 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) */ if ( ! (MAN_NSCOPED & man_macros[tok].flags) && - m->flags & MAN_ELINE) { - n = m->last; + man->flags & MAN_ELINE) { + n = man->last; assert(MAN_TEXT != n->type); /* Remove repeated NSCOPED macros causing ELINE. */ @@ -542,20 +550,20 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) if (MAN_NSCOPED & man_macros[n->tok].flags) n = n->parent; - mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, + mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); - man_node_delete(m, n); - m->flags &= ~MAN_ELINE; + man_node_delete(man, n); + man->flags &= ~MAN_ELINE; } /* * Remove prior BLINE macro that is being clobbered. */ - if ((m->flags & MAN_BLINE) && + if ((man->flags & MAN_BLINE) && (MAN_BSCOPE & man_macros[tok].flags)) { - n = m->last; + n = man->last; /* Might be a text node like 8 in * .TP 8 @@ -573,12 +581,12 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) assert(MAN_BLOCK == n->type); assert(MAN_SCOPED & man_macros[n->tok].flags); - mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, + mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); - man_node_delete(m, n); - m->flags &= ~MAN_BLINE; + man_node_delete(man, n); + man->flags &= ~MAN_BLINE; } /* @@ -587,13 +595,13 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) * when they exit. */ - if (MAN_BLINE & m->flags) - m->flags |= MAN_BPLINE; + if (MAN_BLINE & man->flags) + man->flags |= MAN_BPLINE; /* Call to handler... */ assert(man_macros[tok].fp); - if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &offs, buf)) + if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf)) goto err; /* @@ -601,19 +609,19 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) * above-parsed macro, so return. */ - if ( ! (MAN_BPLINE & m->flags)) { - m->flags &= ~MAN_ILINE; + if ( ! (MAN_BPLINE & man->flags)) { + man->flags &= ~MAN_ILINE; return(1); } - m->flags &= ~MAN_BPLINE; + man->flags &= ~MAN_BPLINE; /* * If we're in a block scope, then allow this macro to slip by * without closing scope around it. */ - if (MAN_ILINE & m->flags) { - m->flags &= ~MAN_ILINE; + if (MAN_ILINE & man->flags) { + man->flags &= ~MAN_ILINE; return(1); } @@ -622,30 +630,30 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) * now, as the next line will close out the block scope. */ - if (MAN_ELINE & m->flags) + if (MAN_ELINE & man->flags) return(1); /* Close out the block scope opened in the prior line. */ - assert(MAN_BLINE & m->flags); - m->flags &= ~MAN_BLINE; + assert(MAN_BLINE & man->flags); + man->flags &= ~MAN_BLINE; - if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); - return(man_body_alloc(m, ln, ppos, m->last->tok)); + return(man_body_alloc(man, ln, ppos, man->last->tok)); err: /* Error out. */ - m->flags |= MAN_HALT; + man->flags |= MAN_HALT; return(0); } /* - * Unlink a node from its context. If "m" is provided, the last parse + * Unlink a node from its context. If "man" is provided, the last parse * point will also be adjusted accordingly. */ static void -man_node_unlink(struct man *m, struct man_node *n) +man_node_unlink(struct man *man, struct man_node *n) { /* Adjust siblings. */ @@ -665,26 +673,26 @@ man_node_unlink(struct man *m, struct man_node *n) /* Adjust parse point, if applicable. */ - if (m && m->last == n) { + if (man && man->last == n) { /*XXX: this can occur when bailing from validation. */ /*assert(NULL == n->next);*/ if (n->prev) { - m->last = n->prev; - m->next = MAN_NEXT_SIBLING; + man->last = n->prev; + man->next = MAN_NEXT_SIBLING; } else { - m->last = n->parent; - m->next = MAN_NEXT_CHILD; + man->last = n->parent; + man->next = MAN_NEXT_CHILD; } } - if (m && m->first == n) - m->first = NULL; + if (man && man->first == n) + man->first = NULL; } const struct mparse * -man_mparse(const struct man *m) +man_mparse(const struct man *man) { - assert(m && m->parse); - return(m->parse); + assert(man && man->parse); + return(man->parse); } diff --git a/contrib/mdocml/man.h b/contrib/mdocml/man.h index 4fc3934..ef9480f 100644 --- a/contrib/mdocml/man.h +++ b/contrib/mdocml/man.h @@ -1,4 +1,4 @@ -/* $Id: man.h,v 1.60 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man.h,v 1.62 2013/10/17 20:54:58 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -52,6 +52,10 @@ enum mant { MAN_in, MAN_ft, MAN_OP, + MAN_EX, + MAN_EE, + MAN_UR, + MAN_UE, MAN_MAX }; diff --git a/contrib/mdocml/man_html.c b/contrib/mdocml/man_html.c index a76ea2d..2c4e220 100644 --- a/contrib/mdocml/man_html.c +++ b/contrib/mdocml/man_html.c @@ -1,6 +1,7 @@ -/* $Id: man_html.c,v 1.86 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man_html.c,v 1.90 2013/10/17 20:54:58 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,7 +38,7 @@ #define INDENT 5 -#define MAN_ARGS const struct man_meta *m, \ +#define MAN_ARGS const struct man_meta *man, \ const struct man_node *n, \ struct mhtml *mh, \ struct html *h @@ -70,6 +71,7 @@ static int man_RS_pre(MAN_ARGS); static int man_SH_pre(MAN_ARGS); static int man_SM_pre(MAN_ARGS); static int man_SS_pre(MAN_ARGS); +static int man_UR_pre(MAN_ARGS); static int man_alt_pre(MAN_ARGS); static int man_br_pre(MAN_ARGS); static int man_ign_pre(MAN_ARGS); @@ -113,6 +115,10 @@ static const struct htmlman mans[MAN_MAX] = { { man_in_pre, NULL }, /* in */ { man_ign_pre, NULL }, /* ft */ { man_OP_pre, NULL }, /* OP */ + { man_literal_pre, NULL }, /* EX */ + { man_literal_pre, NULL }, /* EE */ + { man_UR_pre, NULL }, /* UR */ + { NULL, NULL }, /* UE */ }; /* @@ -139,12 +145,12 @@ print_bvspace(struct html *h, const struct man_node *n) } void -html_man(void *arg, const struct man *m) +html_man(void *arg, const struct man *man) { struct mhtml mh; memset(&mh, 0, sizeof(struct mhtml)); - print_man(man_meta(m), man_node(m), &mh, (struct html *)arg); + print_man(man_meta(man), man_node(man), &mh, (struct html *)arg); putchar('\n'); } @@ -160,14 +166,14 @@ print_man(MAN_ARGS) print_gen_decls(h); t = print_otag(h, TAG_HTML, 0, NULL); tt = print_otag(h, TAG_HEAD, 0, NULL); - print_man_head(m, n, mh, h); + print_man_head(man, n, mh, h); print_tagq(h, tt); print_otag(h, TAG_BODY, 0, NULL); print_otag(h, TAG_DIV, 1, &tag); } else t = print_otag(h, TAG_DIV, 1, &tag); - print_man_nodelist(m, n, mh, h); + print_man_nodelist(man, n, mh, h); print_tagq(h, t); } @@ -178,9 +184,9 @@ print_man_head(MAN_ARGS) { print_gen_head(h); - assert(m->title); - assert(m->msec); - bufcat_fmt(h, "%s(%s)", m->title, m->msec); + assert(man->title); + assert(man->msec); + bufcat_fmt(h, "%s(%s)", man->title, man->msec); print_otag(h, TAG_TITLE, 0, NULL); print_text(h, h->buf); } @@ -190,9 +196,9 @@ static void print_man_nodelist(MAN_ARGS) { - print_man_node(m, n, mh, h); + print_man_node(man, n, mh, h); if (n->next) - print_man_nodelist(m, n->next, mh, h); + print_man_nodelist(man, n->next, mh, h); } @@ -207,7 +213,7 @@ print_man_node(MAN_ARGS) switch (n->type) { case (MAN_ROOT): - man_root_pre(m, n, mh, h); + man_root_pre(man, n, mh, h); break; case (MAN_TEXT): /* @@ -258,25 +264,25 @@ print_man_node(MAN_ARGS) t = h->tags.head; } if (mans[n->tok].pre) - child = (*mans[n->tok].pre)(m, n, mh, h); + child = (*mans[n->tok].pre)(man, n, mh, h); break; } if (child && n->child) - print_man_nodelist(m, n->child, mh, h); + print_man_nodelist(man, n->child, mh, h); /* This will automatically close out any font scope. */ print_stagq(h, t); switch (n->type) { case (MAN_ROOT): - man_root_post(m, n, mh, h); + man_root_post(man, n, mh, h); break; case (MAN_EQN): break; default: if (mans[n->tok].post) - (*mans[n->tok].post)(m, n, mh, h); + (*mans[n->tok].post)(man, n, mh, h); break; } } @@ -304,12 +310,12 @@ man_root_pre(MAN_ARGS) char b[BUFSIZ], title[BUFSIZ]; b[0] = 0; - if (m->vol) - (void)strlcat(b, m->vol, BUFSIZ); + if (man->vol) + (void)strlcat(b, man->vol, BUFSIZ); - assert(m->title); - assert(m->msec); - snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec); + assert(man->title); + assert(man->msec); + snprintf(title, BUFSIZ - 1, "%s(%s)", man->title, man->msec); PAIR_SUMMARY_INIT(&tag[0], "Document Header"); PAIR_CLASS_INIT(&tag[1], "head"); @@ -363,16 +369,16 @@ man_root_post(MAN_ARGS) PAIR_CLASS_INIT(&tag[0], "foot-date"); print_otag(h, TAG_TD, 1, tag); - assert(m->date); - print_text(h, m->date); + assert(man->date); + print_text(h, man->date); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "foot-os"); PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); print_otag(h, TAG_TD, 2, tag); - if (m->source) - print_text(h, m->source); + if (man->source) + print_text(h, man->source); print_tagq(h, t); } @@ -468,7 +474,7 @@ man_alt_pre(MAN_ARGS) if (TAG_MAX != fp) t = print_otag(h, fp, 0, NULL); - print_man_node(m, nn, mh, h); + print_man_node(man, nn, mh, h); if (t) print_tagq(h, t); @@ -543,14 +549,14 @@ man_IP_pre(MAN_ARGS) /* For IP, only print the first header element. */ if (MAN_IP == n->tok && n->child) - print_man_node(m, n->child, mh, h); + print_man_node(man, n->child, mh, h); /* For TP, only print next-line header elements. */ if (MAN_TP == n->tok) for (nn = n->child; nn; nn = nn->next) if (nn->line > n->line) - print_man_node(m, nn, mh, h); + print_man_node(man, nn, mh, h); return(0); } @@ -638,7 +644,7 @@ static int man_literal_pre(MAN_ARGS) { - if (MAN_nf != n->tok) { + if (MAN_fi == n->tok || MAN_EE == n->tok) { print_otag(h, TAG_BR, 0, NULL); mh->fl &= ~MANH_LITERAL; } else @@ -686,3 +692,27 @@ man_RS_pre(MAN_ARGS) print_otag(h, TAG_DIV, 1, &tag); return(1); } + +/* ARGSUSED */ +static int +man_UR_pre(MAN_ARGS) +{ + struct htmlpair tag[2]; + + n = n->child; + assert(MAN_HEAD == n->type); + if (n->nchild) { + assert(MAN_TEXT == n->child->type); + PAIR_CLASS_INIT(&tag[0], "link-ext"); + PAIR_HREF_INIT(&tag[1], n->child->string); + print_otag(h, TAG_A, 2, tag); + } + + assert(MAN_BODY == n->next->type); + if (n->next->nchild) + n = n->next; + + print_man_nodelist(man, n->child, mh, h); + + return(0); +} diff --git a/contrib/mdocml/man_macro.c b/contrib/mdocml/man_macro.c index 4bbbc4f..479d048 100644 --- a/contrib/mdocml/man_macro.c +++ b/contrib/mdocml/man_macro.c @@ -1,6 +1,8 @@ -/* $Id: man_macro.c,v 1.71 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -77,7 +79,7 @@ const struct man_macro __man_macros[MAN_MAX] = { { in_line_eoln, MAN_BSCOPE }, /* nf */ { in_line_eoln, MAN_BSCOPE }, /* fi */ { blk_close, 0 }, /* RE */ - { blk_exp, MAN_EXPLICIT }, /* RS */ + { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */ { in_line_eoln, 0 }, /* DT */ { in_line_eoln, 0 }, /* UC */ { in_line_eoln, 0 }, /* PD */ @@ -85,6 +87,10 @@ const struct man_macro __man_macros[MAN_MAX] = { { in_line_eoln, 0 }, /* in */ { in_line_eoln, 0 }, /* ft */ { in_line_eoln, 0 }, /* OP */ + { in_line_eoln, MAN_BSCOPE }, /* EX */ + { in_line_eoln, MAN_BSCOPE }, /* EE */ + { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */ + { blk_close, 0 }, /* UE */ }; const struct man_macro * const man_macros = __man_macros; @@ -94,7 +100,7 @@ const struct man_macro * const man_macros = __man_macros; * Warn when "n" is an explicit non-roff macro. */ static void -rew_warn(struct man *m, struct man_node *n, enum mandocerr er) +rew_warn(struct man *man, struct man_node *n, enum mandocerr er) { if (er == MANDOCERR_MAX || MAN_BLOCK != n->type) @@ -105,7 +111,7 @@ rew_warn(struct man *m, struct man_node *n, enum mandocerr er) return; assert(er < MANDOCERR_FATAL); - man_nmsg(m, n, er); + man_nmsg(man, n, er); } @@ -114,33 +120,33 @@ rew_warn(struct man *m, struct man_node *n, enum mandocerr er) * will be used if an explicit block scope is being closed out. */ int -man_unscope(struct man *m, const struct man_node *to, +man_unscope(struct man *man, const struct man_node *to, enum mandocerr er) { struct man_node *n; assert(to); - m->next = MAN_NEXT_SIBLING; + man->next = MAN_NEXT_SIBLING; /* LINTED */ - while (m->last != to) { + while (man->last != to) { /* * Save the parent here, because we may delete the - * m->last node in the post-validation phase and reset - * it to m->last->parent, causing a step in the closing + * man->last node in the post-validation phase and reset + * it to man->last->parent, causing a step in the closing * out to be lost. */ - n = m->last->parent; - rew_warn(m, m->last, er); - if ( ! man_valid_post(m)) + n = man->last->parent; + rew_warn(man, man->last, er); + if ( ! man_valid_post(man)) return(0); - m->last = n; - assert(m->last); + man->last = n; + assert(man->last); } - rew_warn(m, m->last, er); - if ( ! man_valid_post(m)) + rew_warn(man, man->last, er); + if ( ! man_valid_post(man)) return(0); return(1); @@ -183,8 +189,12 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) return(REW_NOHALT); /* First: rewind to ourselves. */ - if (type == n->type && tok == n->tok) - return(REW_REWIND); + if (type == n->type && tok == n->tok) { + if (MAN_EXPLICIT & man_macros[n->tok].flags) + return(REW_HALT); + else + return(REW_REWIND); + } /* * Next follow the implicit scope-smashings as defined by man.7: @@ -200,6 +210,10 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) return(c); break; case (MAN_RS): + /* Preserve empty paragraphs before RS. */ + if (0 == n->nchild && (MAN_P == n->tok || + MAN_PP == n->tok || MAN_LP == n->tok)) + return(REW_HALT); /* Rewind to a subsection, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SS, type, n))) return(c); @@ -230,13 +244,13 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) * scopes. When a scope is closed, it must be validated and actioned. */ static int -rew_scope(enum man_type type, struct man *m, enum mant tok) +rew_scope(enum man_type type, struct man *man, enum mant tok) { struct man_node *n; enum rew c; /* LINTED */ - for (n = m->last; n; n = n->parent) { + for (n = man->last; n; n = n->parent) { /* * Whether we should stop immediately (REW_HALT), stop * and rewind until this point (REW_REWIND), or keep @@ -255,7 +269,7 @@ rew_scope(enum man_type type, struct man *m, enum mant tok) */ assert(n); - return(man_unscope(m, n, MANDOCERR_MAX)); + return(man_unscope(man, n, MANDOCERR_MAX)); } @@ -273,22 +287,24 @@ blk_close(MACRO_PROT_ARGS) case (MAN_RE): ntok = MAN_RS; break; + case (MAN_UE): + ntok = MAN_UR; + break; default: abort(); /* NOTREACHED */ } - for (nn = m->last->parent; nn; nn = nn->parent) - if (ntok == nn->tok) + for (nn = man->last->parent; nn; nn = nn->parent) + if (ntok == nn->tok && MAN_BLOCK == nn->type) break; - if (NULL == nn) - man_pmsg(m, line, ppos, MANDOCERR_NOSCOPE); - - if ( ! rew_scope(MAN_BODY, m, ntok)) - return(0); - if ( ! rew_scope(MAN_BLOCK, m, ntok)) - return(0); + if (NULL == nn) { + man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE); + if ( ! rew_scope(MAN_BLOCK, man, MAN_PP)) + return(0); + } else + man_unscope(man, nn, MANDOCERR_MAX); return(1); } @@ -298,34 +314,40 @@ blk_close(MACRO_PROT_ARGS) int blk_exp(MACRO_PROT_ARGS) { + struct man_node *n; int la; char *p; - /* - * Close out prior scopes. "Regular" explicit macros cannot be - * nested, but we allow roff macros to be placed just about - * anywhere. - */ + /* Close out prior implicit scopes. */ - if ( ! man_block_alloc(m, line, ppos, tok)) + if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); - if ( ! man_head_alloc(m, line, ppos, tok)) + + if ( ! man_block_alloc(man, line, ppos, tok)) + return(0); + if ( ! man_head_alloc(man, line, ppos, tok)) return(0); for (;;) { la = *pos; - if ( ! man_args(m, line, pos, buf, &p)) + if ( ! man_args(man, line, pos, buf, &p)) break; - if ( ! man_word_alloc(m, line, la, p)) + if ( ! man_word_alloc(man, line, la, p)) return(0); } - assert(m); + assert(man); assert(tok != MAN_MAX); - if ( ! rew_scope(MAN_HEAD, m, tok)) - return(0); - return(man_body_alloc(m, line, ppos, tok)); + for (n = man->last; n; n = n->parent) { + if (n->tok != tok) + continue; + assert(MAN_HEAD == n->type); + man_unscope(man, n, MANDOCERR_MAX); + break; + } + + return(man_body_alloc(man, line, ppos, tok)); } @@ -346,27 +368,27 @@ blk_imp(MACRO_PROT_ARGS) /* Close out prior scopes. */ - if ( ! rew_scope(MAN_BODY, m, tok)) + if ( ! rew_scope(MAN_BODY, man, tok)) return(0); - if ( ! rew_scope(MAN_BLOCK, m, tok)) + if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); /* Allocate new block & head scope. */ - if ( ! man_block_alloc(m, line, ppos, tok)) + if ( ! man_block_alloc(man, line, ppos, tok)) return(0); - if ( ! man_head_alloc(m, line, ppos, tok)) + if ( ! man_head_alloc(man, line, ppos, tok)) return(0); - n = m->last; + n = man->last; /* Add line arguments. */ for (;;) { la = *pos; - if ( ! man_args(m, line, pos, buf, &p)) + if ( ! man_args(man, line, pos, buf, &p)) break; - if ( ! man_word_alloc(m, line, la, p)) + if ( ! man_word_alloc(man, line, la, p)) return(0); } @@ -375,17 +397,17 @@ blk_imp(MACRO_PROT_ARGS) if (MAN_SCOPED & man_macros[tok].flags) { /* If we're forcing scope (`TP'), keep it open. */ if (MAN_FSCOPED & man_macros[tok].flags) { - m->flags |= MAN_BLINE; + man->flags |= MAN_BLINE; return(1); - } else if (n == m->last) { - m->flags |= MAN_BLINE; + } else if (n == man->last) { + man->flags |= MAN_BLINE; return(1); } } - if ( ! rew_scope(MAN_HEAD, m, tok)) + if ( ! rew_scope(MAN_HEAD, man, tok)) return(0); - return(man_body_alloc(m, line, ppos, tok)); + return(man_body_alloc(man, line, ppos, tok)); } @@ -397,28 +419,37 @@ in_line_eoln(MACRO_PROT_ARGS) char *p; struct man_node *n; - if ( ! man_elem_alloc(m, line, ppos, tok)) + if ( ! man_elem_alloc(man, line, ppos, tok)) return(0); - n = m->last; + n = man->last; for (;;) { la = *pos; - if ( ! man_args(m, line, pos, buf, &p)) + if ( ! man_args(man, line, pos, buf, &p)) break; - if ( ! man_word_alloc(m, line, la, p)) + if ( ! man_word_alloc(man, line, la, p)) return(0); } /* + * Append MAN_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), 0)) + man->last->flags |= MAN_EOS; + + /* * If no arguments are specified and this is MAN_SCOPED (i.e., * next-line scoped), then set our mode to indicate that we're * waiting for terms to load into our context. */ - if (n == m->last && MAN_SCOPED & man_macros[tok].flags) { + if (n == man->last && MAN_SCOPED & man_macros[tok].flags) { assert( ! (MAN_NSCOPED & man_macros[tok].flags)); - m->flags |= MAN_ELINE; + man->flags |= MAN_ELINE; return(1); } @@ -426,11 +457,11 @@ in_line_eoln(MACRO_PROT_ARGS) if (MAN_NSCOPED & man_macros[tok].flags) { assert( ! (MAN_SCOPED & man_macros[tok].flags)); - m->flags |= MAN_ILINE; + man->flags |= MAN_ILINE; } - assert(MAN_ROOT != m->last->type); - m->next = MAN_NEXT_SIBLING; + assert(MAN_ROOT != man->last->type); + man->next = MAN_NEXT_SIBLING; /* * Rewind our element scope. Note that when TH is pruned, we'll @@ -438,22 +469,22 @@ in_line_eoln(MACRO_PROT_ARGS) * its sibling. */ - for ( ; m->last; m->last = m->last->parent) { - if (m->last == n) + for ( ; man->last; man->last = man->last->parent) { + if (man->last == n) break; - if (m->last->type == MAN_ROOT) + if (man->last->type == MAN_ROOT) break; - if ( ! man_valid_post(m)) + if ( ! man_valid_post(man)) return(0); } - assert(m->last); + assert(man->last); /* * Same here regarding whether we're back at the root. */ - if (m->last->type != MAN_ROOT && ! man_valid_post(m)) + if (man->last->type != MAN_ROOT && ! man_valid_post(man)) return(0); return(1); @@ -461,14 +492,14 @@ in_line_eoln(MACRO_PROT_ARGS) int -man_macroend(struct man *m) +man_macroend(struct man *man) { - return(man_unscope(m, m->first, MANDOCERR_SCOPEEXIT)); + return(man_unscope(man, man->first, MANDOCERR_SCOPEEXIT)); } static int -man_args(struct man *m, int line, int *pos, char *buf, char **v) +man_args(struct man *man, int line, int *pos, char *buf, char **v) { char *start; @@ -479,6 +510,6 @@ man_args(struct man *m, int line, int *pos, char *buf, char **v) if ('\0' == *start) return(0); - *v = mandoc_getarg(m->parse, v, line, pos); + *v = mandoc_getarg(man->parse, v, line, pos); return(1); } diff --git a/contrib/mdocml/man_term.c b/contrib/mdocml/man_term.c index 69c5c95..4bd6244 100644 --- a/contrib/mdocml/man_term.c +++ b/contrib/mdocml/man_term.c @@ -1,7 +1,7 @@ -/* $Id: man_term.c,v 1.127 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,8 +35,6 @@ #define MAXMARGINS 64 /* maximum number of indented scopes */ -/* FIXME: have PD set the default vspace width. */ - struct mtermp { int fl; #define MANT_LITERAL (1 << 0) @@ -44,12 +42,13 @@ struct mtermp { 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, \ const struct man_node *n, \ - const struct man_meta *m + const struct man_meta *meta struct termact { int (*pre)(DECL_ARGS); @@ -66,18 +65,20 @@ static void print_man_node(DECL_ARGS); static void print_man_head(struct termp *, const void *); static void print_man_foot(struct termp *, const void *); static void print_bvspace(struct termp *, - const struct man_node *); + const struct man_node *, int); static int pre_B(DECL_ARGS); static int pre_HP(DECL_ARGS); static int pre_I(DECL_ARGS); static int pre_IP(DECL_ARGS); static int pre_OP(DECL_ARGS); +static int pre_PD(DECL_ARGS); static int pre_PP(DECL_ARGS); static int pre_RS(DECL_ARGS); static int pre_SH(DECL_ARGS); static int pre_SS(DECL_ARGS); static int pre_TP(DECL_ARGS); +static int pre_UR(DECL_ARGS); static int pre_alternate(DECL_ARGS); static int pre_ft(DECL_ARGS); static int pre_ign(DECL_ARGS); @@ -91,6 +92,7 @@ static void post_RS(DECL_ARGS); static void post_SH(DECL_ARGS); static void post_SS(DECL_ARGS); static void post_TP(DECL_ARGS); +static void post_UR(DECL_ARGS); static const struct termact termacts[MAN_MAX] = { { pre_sp, NULL, MAN_NOTEXT }, /* br */ @@ -122,11 +124,15 @@ static const struct termact termacts[MAN_MAX] = { { pre_RS, post_RS, 0 }, /* RS */ { pre_ign, NULL, 0 }, /* DT */ { pre_ign, NULL, 0 }, /* UC */ - { pre_ign, NULL, 0 }, /* PD */ + { pre_PD, NULL, MAN_NOTEXT }, /* PD */ { pre_ign, NULL, 0 }, /* AT */ { pre_in, NULL, MAN_NOTEXT }, /* in */ { pre_ft, NULL, MAN_NOTEXT }, /* ft */ { 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 */ }; @@ -136,7 +142,7 @@ terminal_man(void *arg, const struct man *man) { struct termp *p; const struct man_node *n; - const struct man_meta *m; + const struct man_meta *meta; struct mtermp mt; p = (struct termp *)arg; @@ -152,18 +158,19 @@ terminal_man(void *arg, const struct man *man) p->symtab = mchars_alloc(); n = man_node(man); - m = man_meta(man); + meta = man_meta(man); - term_begin(p, print_man_head, print_man_foot, m); + term_begin(p, print_man_head, print_man_foot, meta); p->flags |= TERMP_NOSPACE; memset(&mt, 0, sizeof(struct mtermp)); mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); mt.offset = term_len(p, p->defindent); + mt.pardist = 1; if (n->child) - print_man_nodelist(p, &mt, n->child, m); + print_man_nodelist(p, &mt, n->child, meta); term_end(p); } @@ -201,8 +208,9 @@ a2width(const struct termp *p, const char *cp) * first, print it. */ static void -print_bvspace(struct termp *p, const struct man_node *n) +print_bvspace(struct termp *p, const struct man_node *n, int pardist) { + int i; term_newln(p); @@ -214,7 +222,8 @@ print_bvspace(struct termp *p, const struct man_node *n) if (NULL == n->prev) return; - term_vspace(p); + for (i = 0; i < pardist; i++) + term_vspace(p); } /* ARGSUSED */ @@ -243,7 +252,7 @@ pre_literal(DECL_ARGS) term_newln(p); - if (MAN_nf == n->tok) + if (MAN_nf == n->tok || MAN_EX == n->tok) mt->fl |= MANT_LITERAL; else mt->fl &= ~MANT_LITERAL; @@ -256,7 +265,8 @@ pre_literal(DECL_ARGS) if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) { p->offset = p->rmargin; p->rmargin = p->maxrmargin; - p->flags &= ~(TERMP_NOBREAK | TERMP_TWOSPACE); + p->trailspace = 0; + p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; } @@ -265,6 +275,21 @@ pre_literal(DECL_ARGS) /* ARGSUSED */ static int +pre_PD(DECL_ARGS) +{ + + n = n->child; + if (0 == n) { + mt->pardist = 1; + return(0); + } + assert(MAN_TEXT == n->type); + mt->pardist = atoi(n->string); + return(0); +} + +/* ARGSUSED */ +static int pre_alternate(DECL_ARGS) { enum termfont font[2]; @@ -307,7 +332,7 @@ pre_alternate(DECL_ARGS) term_fontrepl(p, font[i]); if (savelit && NULL == nn->next) mt->fl |= MANT_LITERAL; - print_man_node(p, mt, nn, m); + print_man_node(p, mt, nn, meta); if (nn->next) p->flags |= TERMP_NOSPACE; } @@ -438,28 +463,54 @@ pre_in(DECL_ARGS) static int pre_sp(DECL_ARGS) { + char *s; size_t i, len; + int neg; if ((NULL == n->prev && n->parent)) { - if (MAN_SS == n->parent->tok) - return(0); - if (MAN_SH == n->parent->tok) + switch (n->parent->tok) { + case (MAN_SH): + /* FALLTHROUGH */ + case (MAN_SS): + /* FALLTHROUGH */ + case (MAN_PP): + /* FALLTHROUGH */ + case (MAN_LP): + /* FALLTHROUGH */ + case (MAN_P): + /* FALLTHROUGH */ return(0); + default: + break; + } } + neg = 0; switch (n->tok) { case (MAN_br): len = 0; break; default: - len = n->child ? a2height(p, n->child->string) : 1; + if (NULL == n->child) { + len = 1; + break; + } + s = n->child->string; + if ('-' == *s) { + neg = 1; + s++; + } + len = a2height(p, s); break; } if (0 == len) term_newln(p); - for (i = 0; i < len; i++) - term_vspace(p); + else if (neg) + p->skipvsp += len; + else + for (i = 0; i < len; i++) + term_vspace(p); return(0); } @@ -475,16 +526,19 @@ pre_HP(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): - print_bvspace(p, n); + print_bvspace(p, n, mt->pardist); return(1); case (MAN_BODY): - p->flags |= TERMP_NOBREAK; - p->flags |= TERMP_TWOSPACE; break; default: return(0); } + if ( ! (MANT_LITERAL & mt->fl)) { + p->flags |= TERMP_NOBREAK; + p->trailspace = 2; + } + len = mt->lmargin[mt->lmargincur]; ival = -1; @@ -514,13 +568,10 @@ post_HP(DECL_ARGS) { switch (n->type) { - case (MAN_BLOCK): - term_flushln(p); - break; case (MAN_BODY): - term_flushln(p); + term_newln(p); p->flags &= ~TERMP_NOBREAK; - p->flags &= ~TERMP_TWOSPACE; + p->trailspace = 0; p->offset = mt->offset; p->rmargin = p->maxrmargin; break; @@ -538,7 +589,7 @@ pre_PP(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); - print_bvspace(p, n); + print_bvspace(p, n, mt->pardist); break; default: p->offset = mt->offset; @@ -563,9 +614,10 @@ pre_IP(DECL_ARGS) break; case (MAN_HEAD): p->flags |= TERMP_NOBREAK; + p->trailspace = 1; break; case (MAN_BLOCK): - print_bvspace(p, n); + print_bvspace(p, n, mt->pardist); /* FALLTHROUGH */ default: return(1); @@ -598,7 +650,7 @@ pre_IP(DECL_ARGS) mt->fl &= ~MANT_LITERAL; if (n->child) - print_man_node(p, mt, n->child, m); + print_man_node(p, mt, n->child, meta); if (savelit) mt->fl |= MANT_LITERAL; @@ -625,10 +677,12 @@ post_IP(DECL_ARGS) case (MAN_HEAD): term_flushln(p); p->flags &= ~TERMP_NOBREAK; + p->trailspace = 0; p->rmargin = p->maxrmargin; break; case (MAN_BODY): term_newln(p); + p->offset = mt->offset; break; default: break; @@ -647,12 +701,13 @@ pre_TP(DECL_ARGS) switch (n->type) { case (MAN_HEAD): p->flags |= TERMP_NOBREAK; + p->trailspace = 1; break; case (MAN_BODY): p->flags |= TERMP_NOSPACE; break; case (MAN_BLOCK): - print_bvspace(p, n); + print_bvspace(p, n, mt->pardist); /* FALLTHROUGH */ default: return(1); @@ -683,7 +738,7 @@ pre_TP(DECL_ARGS) /* Don't print same-line elements. */ for (nn = n->child; nn; nn = nn->next) if (nn->line > n->line) - print_man_node(p, mt, nn, m); + print_man_node(p, mt, nn, meta); if (savelit) mt->fl |= MANT_LITERAL; @@ -694,6 +749,8 @@ pre_TP(DECL_ARGS) case (MAN_BODY): p->offset = mt->offset + len; p->rmargin = p->maxrmargin; + p->trailspace = 0; + p->flags &= ~TERMP_NOBREAK; break; default: break; @@ -711,12 +768,10 @@ post_TP(DECL_ARGS) switch (n->type) { case (MAN_HEAD): term_flushln(p); - p->flags &= ~TERMP_NOBREAK; - p->flags &= ~TERMP_TWOSPACE; - p->rmargin = p->maxrmargin; break; case (MAN_BODY): term_newln(p); + p->offset = mt->offset; break; default: break; @@ -728,6 +783,7 @@ post_TP(DECL_ARGS) static int pre_SS(DECL_ARGS) { + int i; switch (n->type) { case (MAN_BLOCK): @@ -740,11 +796,12 @@ pre_SS(DECL_ARGS) break; if (NULL == n->prev) break; - term_vspace(p); + for (i = 0; i < mt->pardist; i++) + term_vspace(p); break; case (MAN_HEAD): term_fontrepl(p, TERMFONT_BOLD); - p->offset = term_len(p, p->defindent/2); + p->offset = term_len(p, 3); break; case (MAN_BODY): p->offset = mt->offset; @@ -779,6 +836,7 @@ post_SS(DECL_ARGS) static int pre_SH(DECL_ARGS) { + int i; switch (n->type) { case (MAN_BLOCK): @@ -792,7 +850,8 @@ pre_SH(DECL_ARGS) /* If the first macro, no vspae. */ if (NULL == n->prev) break; - term_vspace(p); + for (i = 0; i < mt->pardist; i++) + term_vspace(p); break; case (MAN_HEAD): term_fontrepl(p, TERMFONT_BOLD); @@ -890,6 +949,32 @@ post_RS(DECL_ARGS) mt->lmargincur = mt->lmarginsz; } +/* ARGSUSED */ +static int +pre_UR(DECL_ARGS) +{ + + return (MAN_HEAD != n->type); +} + +/* ARGSUSED */ +static void +post_UR(DECL_ARGS) +{ + + if (MAN_BLOCK != n->type) + return; + + term_word(p, "<"); + p->flags |= TERMP_NOSPACE; + + if (NULL != n->child->child) + print_man_node(p, mt, n->child->child, meta); + + p->flags |= TERMP_NOSPACE; + term_word(p, ">"); +} + static void print_man_node(DECL_ARGS) { @@ -910,29 +995,8 @@ print_man_node(DECL_ARGS) term_newln(p); term_word(p, n->string); + goto out; - /* - * If we're in a literal context, make sure that words - * togehter 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 (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) && - (NULL == n->next || - n->next->line > n->line)) { - rm = p->rmargin; - rmax = p->maxrmargin; - p->rmargin = p->maxrmargin = TERM_MAXMARGIN; - p->flags |= TERMP_NOSPACE; - term_flushln(p); - p->rmargin = rm; - p->maxrmargin = rmax; - } - - if (MAN_EOS & n->flags) - p->flags |= TERMP_SENTENCE; - return; case (MAN_EQN): term_eqn(p, n->eqn); return; @@ -954,16 +1018,41 @@ print_man_node(DECL_ARGS) c = 1; if (termacts[n->tok].pre) - c = (*termacts[n->tok].pre)(p, mt, n, m); + c = (*termacts[n->tok].pre)(p, mt, n, meta); if (c && n->child) - print_man_nodelist(p, mt, n->child, m); + print_man_nodelist(p, mt, n->child, meta); if (termacts[n->tok].post) - (*termacts[n->tok].post)(p, mt, n, m); + (*termacts[n->tok].post)(p, mt, n, meta); if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); +out: + /* + * If we're in a literal context, make sure that words + * together on the same line stay together. This is a + * POST-printing call, so we check the NEXT word. Since + * -man doesn't have nested macros, we don't need to be + * more specific than this. + */ + if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) && + (NULL == n->next || n->next->line > n->line)) { + rm = p->rmargin; + rmax = p->maxrmargin; + p->rmargin = p->maxrmargin = TERM_MAXMARGIN; + p->flags |= TERMP_NOSPACE; + if (NULL != n->string && '\0' != *n->string) + term_flushln(p); + else + term_newln(p); + if (rm < rmax && n->parent->tok == MAN_HP) { + p->offset = rm; + p->rmargin = rmax; + } else + p->rmargin = rm; + p->maxrmargin = rmax; + } if (MAN_EOS & n->flags) p->flags |= TERMP_SENTENCE; } @@ -973,10 +1062,10 @@ static void print_man_nodelist(DECL_ARGS) { - print_man_node(p, mt, n, m); + print_man_node(p, mt, n, meta); if ( ! n->next) return; - print_man_nodelist(p, mt, n->next, m); + print_man_nodelist(p, mt, n->next, meta); } @@ -1016,6 +1105,7 @@ print_man_foot(struct termp *p, const void *arg) /* Bottom left corner: manual source. */ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; + p->trailspace = 1; p->offset = 0; p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2; @@ -1038,6 +1128,7 @@ print_man_foot(struct termp *p, const void *arg) p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; + p->trailspace = 0; p->offset = p->rmargin; p->rmargin = p->maxrmargin; @@ -1051,24 +1142,25 @@ print_man_head(struct termp *p, const void *arg) { char buf[BUFSIZ], title[BUFSIZ]; size_t buflen, titlen; - const struct man_meta *m; + const struct man_meta *meta; - m = (const struct man_meta *)arg; - assert(m->title); - assert(m->msec); + meta = (const struct man_meta *)arg; + assert(meta->title); + assert(meta->msec); - if (m->vol) - strlcpy(buf, m->vol, BUFSIZ); + if (meta->vol) + strlcpy(buf, meta->vol, BUFSIZ); else buf[0] = '\0'; buflen = term_strlen(p, buf); /* Top left corner: manual title and section. */ - snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec); + snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec); titlen = term_strlen(p, title); p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; + p->trailspace = 1; p->offset = 0; p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ? (p->maxrmargin - @@ -1091,6 +1183,7 @@ print_man_head(struct termp *p, const void *arg) /* Top right corner: title and section, again. */ p->flags &= ~TERMP_NOBREAK; + p->trailspace = 0; if (p->rmargin + titlen <= p->maxrmargin) { p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; diff --git a/contrib/mdocml/man_validate.c b/contrib/mdocml/man_validate.c index e40b089..da2e557 100644 --- a/contrib/mdocml/man_validate.c +++ b/contrib/mdocml/man_validate.c @@ -1,7 +1,7 @@ -/* $Id: man_validate.c,v 1.80 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man_validate.c,v 1.86 2013/10/17 20:54:58 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,7 +35,7 @@ #include "libman.h" #include "libmandoc.h" -#define CHKARGS struct man *m, struct man_node *n +#define CHKARGS struct man *man, struct man_node *n typedef int (*v_check)(CHKARGS); @@ -49,12 +49,14 @@ static int check_eq2(CHKARGS); static int check_le1(CHKARGS); static int check_ge2(CHKARGS); static int check_le5(CHKARGS); +static int check_head1(CHKARGS); static int check_par(CHKARGS); static int check_part(CHKARGS); static int check_root(CHKARGS); static void check_text(CHKARGS); static int post_AT(CHKARGS); +static int post_IP(CHKARGS); static int post_vs(CHKARGS); static int post_fi(CHKARGS); static int post_ft(CHKARGS); @@ -70,6 +72,8 @@ static v_check posts_eq0[] = { check_eq0, NULL }; static v_check posts_eq2[] = { check_eq2, NULL }; static v_check posts_fi[] = { check_eq0, post_fi, NULL }; static v_check posts_ft[] = { post_ft, NULL }; +static v_check posts_ip[] = { post_IP, NULL }; +static v_check posts_le1[] = { check_le1, NULL }; static v_check posts_nf[] = { check_eq0, post_nf, NULL }; static v_check posts_par[] = { check_par, NULL }; static v_check posts_part[] = { check_part, NULL }; @@ -77,6 +81,7 @@ static v_check posts_sec[] = { post_sec, NULL }; static v_check posts_sp[] = { post_vs, check_le1, NULL }; static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL }; static v_check posts_uc[] = { post_UC, NULL }; +static v_check posts_ur[] = { check_head1, check_part, NULL }; static v_check pres_sec[] = { pre_sec, NULL }; static const struct man_valid man_valids[MAN_MAX] = { @@ -88,7 +93,7 @@ static const struct man_valid man_valids[MAN_MAX] = { { NULL, posts_par }, /* LP */ { NULL, posts_par }, /* PP */ { NULL, posts_par }, /* P */ - { NULL, NULL }, /* IP */ + { NULL, posts_ip }, /* IP */ { NULL, NULL }, /* HP */ { NULL, NULL }, /* SM */ { NULL, NULL }, /* SB */ @@ -109,16 +114,20 @@ static const struct man_valid man_valids[MAN_MAX] = { { NULL, posts_part }, /* RS */ { NULL, NULL }, /* DT */ { NULL, posts_uc }, /* UC */ - { NULL, NULL }, /* PD */ + { NULL, posts_le1 }, /* PD */ { NULL, posts_at }, /* AT */ { NULL, NULL }, /* in */ { NULL, posts_ft }, /* ft */ { NULL, posts_eq2 }, /* OP */ + { NULL, posts_nf }, /* EX */ + { NULL, posts_fi }, /* EE */ + { NULL, posts_ur }, /* UR */ + { NULL, NULL }, /* UE */ }; int -man_valid_pre(struct man *m, struct man_node *n) +man_valid_pre(struct man *man, struct man_node *n) { v_check *cp; @@ -138,27 +147,27 @@ man_valid_pre(struct man *m, struct man_node *n) if (NULL == (cp = man_valids[n->tok].pres)) return(1); for ( ; *cp; cp++) - if ( ! (*cp)(m, n)) + if ( ! (*cp)(man, n)) return(0); return(1); } int -man_valid_post(struct man *m) +man_valid_post(struct man *man) { v_check *cp; - if (MAN_VALID & m->last->flags) + if (MAN_VALID & man->last->flags) return(1); - m->last->flags |= MAN_VALID; + man->last->flags |= MAN_VALID; - switch (m->last->type) { + switch (man->last->type) { case (MAN_TEXT): - check_text(m, m->last); + check_text(man, man->last); return(1); case (MAN_ROOT): - return(check_root(m, m->last)); + return(check_root(man, man->last)); case (MAN_EQN): /* FALLTHROUGH */ case (MAN_TBL): @@ -167,10 +176,10 @@ man_valid_post(struct man *m) break; } - if (NULL == (cp = man_valids[m->last->tok].posts)) + if (NULL == (cp = man_valids[man->last->tok].posts)) return(1); for ( ; *cp; cp++) - if ( ! (*cp)(m, m->last)) + if ( ! (*cp)(man, man->last)) return(0); return(1); @@ -181,29 +190,29 @@ static int check_root(CHKARGS) { - if (MAN_BLINE & m->flags) - man_nmsg(m, n, MANDOCERR_SCOPEEXIT); - else if (MAN_ELINE & m->flags) - man_nmsg(m, n, MANDOCERR_SCOPEEXIT); + if (MAN_BLINE & man->flags) + man_nmsg(man, n, MANDOCERR_SCOPEEXIT); + else if (MAN_ELINE & man->flags) + man_nmsg(man, n, MANDOCERR_SCOPEEXIT); - m->flags &= ~MAN_BLINE; - m->flags &= ~MAN_ELINE; + man->flags &= ~MAN_BLINE; + man->flags &= ~MAN_ELINE; - if (NULL == m->first->child) { - man_nmsg(m, n, MANDOCERR_NODOCBODY); + if (NULL == man->first->child) { + man_nmsg(man, n, MANDOCERR_NODOCBODY); return(0); - } else if (NULL == m->meta.title) { - man_nmsg(m, n, MANDOCERR_NOTITLE); + } else if (NULL == man->meta.title) { + man_nmsg(man, n, MANDOCERR_NOTITLE); /* * If a title hasn't been set, do so now (by * implication, date and section also aren't set). */ - m->meta.title = mandoc_strdup("unknown"); - m->meta.msec = mandoc_strdup("1"); - m->meta.date = mandoc_normdate - (m->parse, NULL, n->line, n->pos); + man->meta.title = mandoc_strdup("unknown"); + man->meta.msec = mandoc_strdup("1"); + man->meta.date = mandoc_normdate + (man->parse, NULL, n->line, n->pos); } return(1); @@ -214,12 +223,12 @@ check_text(CHKARGS) { char *cp, *p; - if (MAN_LITERAL & m->flags) + if (MAN_LITERAL & man->flags) return; cp = n->string; for (p = cp; NULL != (p = strchr(p, '\t')); p++) - man_pmsg(m, n->line, (int)(p - cp), MANDOCERR_BADTAB); + man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB); } #define INEQ_DEFINE(x, ineq, name) \ @@ -228,7 +237,7 @@ check_##name(CHKARGS) \ { \ if (n->nchild ineq (x)) \ return(1); \ - mandoc_vmsg(MANDOCERR_ARGCOUNT, m->parse, n->line, n->pos, \ + mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \ "line arguments %s %d (have %d)", \ #ineq, (x), n->nchild); \ return(1); \ @@ -241,6 +250,17 @@ INEQ_DEFINE(2, >=, ge2) INEQ_DEFINE(5, <=, le5) static int +check_head1(CHKARGS) +{ + + if (MAN_HEAD == n->type && 1 != n->nchild) + mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, + n->pos, "line arguments eq 1 (have %d)", n->nchild); + + return(1); +} + +static int post_ft(CHKARGS) { char *cp; @@ -282,14 +302,14 @@ post_ft(CHKARGS) if (0 == ok) { mandoc_vmsg - (MANDOCERR_BADFONT, m->parse, + (MANDOCERR_BADFONT, man->parse, n->line, n->pos, "%s", cp); *cp = '\0'; } if (1 < n->nchild) mandoc_vmsg - (MANDOCERR_ARGCOUNT, m->parse, n->line, + (MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, "want one child (have %d)", n->nchild); @@ -301,7 +321,7 @@ pre_sec(CHKARGS) { if (MAN_BLOCK == n->type) - m->flags &= ~MAN_LITERAL; + man->flags &= ~MAN_LITERAL; return(1); } @@ -312,7 +332,7 @@ post_sec(CHKARGS) if ( ! (MAN_HEAD == n->type && 0 == n->nchild)) return(1); - man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT); + man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT); return(0); } @@ -321,7 +341,7 @@ check_part(CHKARGS) { if (MAN_BODY == n->type && 0 == n->nchild) - mandoc_msg(MANDOCERR_ARGCWARN, m->parse, n->line, + mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line, n->pos, "want children (have none)"); return(1); @@ -335,15 +355,15 @@ check_par(CHKARGS) switch (n->type) { case (MAN_BLOCK): if (0 == n->body->nchild) - man_node_delete(m, n); + man_node_delete(man, n); break; case (MAN_BODY): if (0 == n->nchild) - man_nmsg(m, n, MANDOCERR_IGNPAR); + man_nmsg(man, n, MANDOCERR_IGNPAR); break; case (MAN_HEAD): if (n->nchild) - man_nmsg(m, n, MANDOCERR_ARGSLOST); + man_nmsg(man, n, MANDOCERR_ARGSLOST); break; default: break; @@ -352,6 +372,24 @@ check_par(CHKARGS) return(1); } +static int +post_IP(CHKARGS) +{ + + switch (n->type) { + case (MAN_BLOCK): + if (0 == n->head->nchild && 0 == n->body->nchild) + man_node_delete(man, n); + break; + case (MAN_BODY): + if (0 == n->parent->head->nchild && 0 == n->nchild) + man_nmsg(man, n, MANDOCERR_IGNPAR); + break; + default: + break; + } + return(1); +} static int post_TH(CHKARGS) @@ -359,21 +397,16 @@ post_TH(CHKARGS) const char *p; int line, pos; - if (m->meta.title) - free(m->meta.title); - if (m->meta.vol) - free(m->meta.vol); - if (m->meta.source) - free(m->meta.source); - if (m->meta.msec) - free(m->meta.msec); - if (m->meta.date) - free(m->meta.date); + free(man->meta.title); + free(man->meta.vol); + free(man->meta.source); + free(man->meta.msec); + free(man->meta.date); line = n->line; pos = n->pos; - m->meta.title = m->meta.vol = m->meta.date = - m->meta.msec = m->meta.source = NULL; + man->meta.title = man->meta.vol = man->meta.date = + man->meta.msec = man->meta.source = NULL; /* ->TITLE<- MSEC DATE SOURCE VOL */ @@ -383,22 +416,22 @@ post_TH(CHKARGS) /* Only warn about this once... */ if (isalpha((unsigned char)*p) && ! isupper((unsigned char)*p)) { - man_nmsg(m, n, MANDOCERR_UPPERCASE); + man_nmsg(man, n, MANDOCERR_UPPERCASE); break; } } - m->meta.title = mandoc_strdup(n->string); + man->meta.title = mandoc_strdup(n->string); } else - m->meta.title = mandoc_strdup(""); + man->meta.title = mandoc_strdup(""); /* TITLE ->MSEC<- DATE SOURCE VOL */ if (n) n = n->next; if (n && n->string) - m->meta.msec = mandoc_strdup(n->string); + man->meta.msec = mandoc_strdup(n->string); else - m->meta.msec = mandoc_strdup(""); + man->meta.msec = mandoc_strdup(""); /* TITLE MSEC ->DATE<- SOURCE VOL */ @@ -406,30 +439,30 @@ post_TH(CHKARGS) n = n->next; if (n && n->string && '\0' != n->string[0]) { pos = n->pos; - m->meta.date = mandoc_normdate - (m->parse, n->string, line, pos); + man->meta.date = mandoc_normdate + (man->parse, n->string, line, pos); } else - m->meta.date = mandoc_strdup(""); + man->meta.date = mandoc_strdup(""); /* TITLE MSEC DATE ->SOURCE<- VOL */ if (n && (n = n->next)) - m->meta.source = mandoc_strdup(n->string); + man->meta.source = mandoc_strdup(n->string); /* TITLE MSEC DATE SOURCE ->VOL<- */ /* If missing, use the default VOL name for MSEC. */ if (n && (n = n->next)) - m->meta.vol = mandoc_strdup(n->string); - else if ('\0' != m->meta.msec[0] && - (NULL != (p = mandoc_a2msec(m->meta.msec)))) - m->meta.vol = mandoc_strdup(p); + 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); /* * Remove the `TH' node after we've processed it for our * meta-data. */ - man_node_delete(m, m->last); + man_node_delete(man, man->last); return(1); } @@ -437,10 +470,10 @@ static int post_nf(CHKARGS) { - if (MAN_LITERAL & m->flags) - man_nmsg(m, n, MANDOCERR_SCOPEREP); + if (MAN_LITERAL & man->flags) + man_nmsg(man, n, MANDOCERR_SCOPEREP); - m->flags |= MAN_LITERAL; + man->flags |= MAN_LITERAL; return(1); } @@ -448,10 +481,10 @@ static int post_fi(CHKARGS) { - if ( ! (MAN_LITERAL & m->flags)) - man_nmsg(m, n, MANDOCERR_WNOSCOPE); + if ( ! (MAN_LITERAL & man->flags)) + man_nmsg(man, n, MANDOCERR_WNOSCOPE); - m->flags &= ~MAN_LITERAL; + man->flags &= ~MAN_LITERAL; return(1); } @@ -488,10 +521,8 @@ post_UC(CHKARGS) p = bsd_versions[0]; } - if (m->meta.source) - free(m->meta.source); - - m->meta.source = mandoc_strdup(p); + free(man->meta.source); + man->meta.source = mandoc_strdup(p); return(1); } @@ -528,10 +559,8 @@ post_AT(CHKARGS) p = unix_versions[0]; } - if (m->meta.source) - free(m->meta.source); - - m->meta.source = mandoc_strdup(p); + free(man->meta.source); + man->meta.source = mandoc_strdup(p); return(1); } @@ -539,12 +568,25 @@ static int post_vs(CHKARGS) { - /* - * Don't warn about this because it occurs in pod2man and would - * cause considerable (unfixable) warnage. - */ - if (NULL == n->prev && MAN_ROOT == n->parent->type) - man_node_delete(m, n); + if (NULL != n->prev) + return(1); + + switch (n->parent->tok) { + case (MAN_SH): + /* FALLTHROUGH */ + case (MAN_SS): + man_nmsg(man, n, MANDOCERR_IGNPAR); + /* FALLTHROUGH */ + case (MAN_MAX): + /* + * Don't warn about this because it occurs in pod2man + * and would cause considerable (unfixable) warnage. + */ + man_node_delete(man, n); + break; + default: + break; + } return(1); } diff --git a/contrib/mdocml/mandoc.1 b/contrib/mdocml/mandoc.1 index dbff0e3..0657bc6 100644 --- a/contrib/mdocml/mandoc.1 +++ b/contrib/mdocml/mandoc.1 @@ -1,6 +1,7 @@ -.\" $Id: mandoc.1,v 1.100 2011/12/25 19:35:44 kristaps Exp $ +.\" $Id: mandoc.1,v 1.103 2013/07/13 19:41:16 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: December 25 2011 $ +.Dd $Mdocdate: July 13 2013 $ .Dt MANDOC 1 .Os .Sh NAME @@ -23,6 +24,9 @@ .Sh SYNOPSIS .Nm mandoc .Op Fl V +.Sm off +.Op Fl I Cm os Li = Ar name +.Sm on .Op Fl m Ns Ar format .Op Fl O Ns Ar option .Op Fl T Ns Ar output @@ -49,6 +53,15 @@ output. .Pp The arguments are as follows: .Bl -tag -width Ds +.Sm off +.It Fl I Cm os Li = Ar name +.Sm on +Override the default operating system +.Ar name +for the +.Xr mdoc 7 +.Sq \&Os +macro. .It Fl m Ns Ar format Input format. See @@ -334,7 +347,7 @@ for font style specification and available command-line arguments. Translate input format into .Xr man 7 output format. -This is useful for distributing manual sources to legancy systems +This is useful for distributing manual sources to legacy systems lacking .Xr mdoc 7 formatters. @@ -637,8 +650,7 @@ lists render similarly. The .Nm utility was written by -.An Kristaps Dzonsons , -.Mt kristaps@bsd.lv . +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . .Sh CAVEATS In .Fl T Ns Cm html diff --git a/contrib/mdocml/mandoc.3 b/contrib/mdocml/mandoc.3 index 4d0b20d..fe6503d 100644 --- a/contrib/mdocml/mandoc.3 +++ b/contrib/mdocml/mandoc.3 @@ -1,4 +1,4 @@ -.\" $Id: mandoc.3,v 1.17 2012/01/13 15:27:14 joerg Exp $ +.\" $Id: mandoc.3,v 1.22 2013/10/06 17:01:52 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 13 2012 $ +.Dd $Mdocdate: October 6 2013 $ .Dt MANDOC 3 .Os .Sh NAME @@ -43,15 +43,15 @@ .Nm mparse_strlevel .Nd mandoc macro compiler library .Sh LIBRARY -.Lb mandoc +.Lb libmandoc .Sh SYNOPSIS .In man.h .In mdoc.h .In mandoc.h .Ft "enum mandoc_esc" .Fo mandoc_escape -.Fa "const char **end" -.Fa "const char **start" +.Fa "const char const **end" +.Fa "const char const **start" .Fa "int *sz" .Fc .Ft "const struct man_meta *" @@ -67,7 +67,7 @@ .Fa "const struct man *man" .Fc .Ft "struct mchars *" -.Fn mchars_alloc +.Fn mchars_alloc "void" .Ft void .Fn mchars_free "struct mchars *p" .Ft char @@ -86,7 +86,6 @@ .Fa "const struct mchars *p" .Fa "const char *cp" .Fa "size_t sz" -.Ft "const char *" .Fc .Ft "const struct mdoc_meta *" .Fo mdoc_meta @@ -257,16 +256,32 @@ and .Va sz may be .Dv NULL . +Declared in +.In mandoc.h , +implemented in +.Pa mandoc.c . .It Fn man_meta Obtain the meta-data of a successful parse. This may only be used on a pointer returned by .Fn mparse_result . +Declared in +.In man.h , +implemented in +.Pa man.c . .It Fn man_mparse Get the parser used for the current output. +Declared in +.In man.h , +implemented in +.Pa man.c . .It Fn man_node Obtain the root node of a successful parse. This may only be used on a pointer returned by .Fn mparse_result . +Declared in +.In man.h , +implemented in +.Pa man.c . .It Fn mchars_alloc Allocate an .Vt "struct mchars *" @@ -276,33 +291,65 @@ See for an overview of special characters. The object must be freed with .Fn mchars_free . +Declared in +.In mandoc.h , +implemented in +.Pa chars.c . .It Fn mchars_free Free an object created with .Fn mchars_alloc . +Declared in +.In mandoc.h , +implemented in +.Pa chars.c . .It Fn mchars_num2char Convert a character index (e.g., the \eN\(aq\(aq escape) into a printable ASCII character. Returns \e0 (the nil character) if the input sequence is malformed. +Declared in +.In mandoc.h , +implemented in +.Pa chars.c . .It Fn mchars_num2uc Convert a hexadecimal character index (e.g., the \e[uNNNN] escape) into a Unicode codepoint. Returns \e0 (the nil character) if the input sequence is malformed. +Declared in +.In mandoc.h , +implemented in +.Pa chars.c . .It Fn mchars_spec2cp Convert a special character into a valid Unicode codepoint. Returns \-1 on failure or a non-zero Unicode codepoint on success. +Declared in +.In mandoc.h , +implemented in +.Pa chars.c . .It Fn mchars_spec2str Convert a special character into an ASCII string. Returns .Dv NULL on failure. +Declared in +.In mandoc.h , +implemented in +.Pa chars.c . .It Fn mdoc_meta Obtain the meta-data of a successful parse. This may only be used on a pointer returned by .Fn mparse_result . +Declared in +.In mdoc.h , +implemented in +.Pa mdoc.c . .It Fn mdoc_node Obtain the root node of a successful parse. This may only be used on a pointer returned by .Fn mparse_result . +Declared in +.In mdoc.h , +implemented in +.Pa mdoc.c . .It Fn mparse_alloc Allocate a parser. The same parser may be used for multiple files so long as @@ -310,18 +357,34 @@ The same parser may be used for multiple files so long as is called between parses. .Fn mparse_free must be called to free the memory allocated by this function. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . .It Fn mparse_free Free all memory allocated by .Fn mparse_alloc . +Declared in +.In mandoc.h , +implemented in +.Pa read.c . .It Fn mparse_getkeep Acquire the keep buffer. Must follow a call of .Fn mparse_keep . +Declared in +.In mandoc.h , +implemented in +.Pa read.c . .It Fn mparse_keep Instruct the parser to retain a copy of its parsed input. This can be acquired with subsequent .Fn mparse_getkeep calls. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . .It Fn mparse_readfd Parse a file or file descriptor. If @@ -336,10 +399,18 @@ is assumed to be the name associated with This may be called multiple times with different parameters; however, .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. Only successful parses @@ -350,10 +421,22 @@ returned less than MANDOCLEVEL_FATAL .Pc should invoke this function, in which case one of the two pointers will be filled in. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . .It Fn mparse_strerror Return a statically-allocated string representation of an error code. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . .It Fn mparse_strlevel Return a statically-allocated string representation of a level code. +Declared in +.In mandoc.h , +implemented in +.Pa read.c . .El .Ss Variables .Bl -ohang @@ -596,5 +679,4 @@ levels of badly-nested blocks. The .Nm library was written by -.An Kristaps Dzonsons , -.Mt kristaps@bsd.lv . +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . diff --git a/contrib/mdocml/mandoc.c b/contrib/mdocml/mandoc.c index 604bb67..da738f2 100644 --- a/contrib/mdocml/mandoc.c +++ b/contrib/mdocml/mandoc.c @@ -1,7 +1,7 @@ -/* $Id: mandoc.c,v 1.62 2011/12/03 16:08:51 schwarze Exp $ */ +/* $Id: mandoc.c,v 1.74 2013/12/30 18:30:32 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,83 +37,38 @@ static int a2time(time_t *, const char *, const char *); static char *time2a(time_t); -static int numescape(const char *); -/* - * Pass over recursive numerical expressions. This context of this - * function is important: it's only called within character-terminating - * escapes (e.g., \s[xxxyyy]), so all we need to do is handle initial - * recursion: we don't care about what's in these blocks. - * This returns the number of characters skipped or -1 if an error - * occurs (the caller should bail). - */ -static int -numescape(const char *start) -{ - int i; - size_t sz; - const char *cp; - i = 0; - - /* The expression consists of a subexpression. */ - - if ('\\' == start[i]) { - cp = &start[++i]; - /* - * Read past the end of the subexpression. - * Bail immediately on errors. - */ - if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL)) - return(-1); - return(i + cp - &start[i]); - } - - if ('(' != start[i++]) - return(0); +enum mandoc_esc +mandoc_escape(const char **end, const char **start, int *sz) +{ + const char *local_start; + int local_sz; + char term; + enum mandoc_esc gly; /* - * A parenthesised subexpression. Read until the closing - * parenthesis, making sure to handle any nested subexpressions - * that might ruin our parse. + * When the caller doesn't provide return storage, + * use local storage. */ - while (')' != start[i]) { - sz = strcspn(&start[i], ")\\"); - i += (int)sz; - - if ('\0' == start[i]) - return(-1); - else if ('\\' != start[i]) - continue; - - cp = &start[++i]; - if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL)) - return(-1); - i += cp - &start[i]; - } - - /* Read past the terminating ')'. */ - return(++i); -} + if (NULL == start) + start = &local_start; + if (NULL == sz) + sz = &local_sz; -enum mandoc_esc -mandoc_escape(const char **end, const char **start, int *sz) -{ - char c, term, numeric; - int i, lim, ssz, rlim; - const char *cp, *rstart; - enum mandoc_esc gly; + /* + * 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. + */ - cp = *end; - rstart = cp; - if (start) - *start = rstart; - i = lim = 0; gly = ESCAPE_ERROR; - term = numeric = '\0'; + *start = ++*end; + *sz = 0; + term = '\0'; - switch ((c = cp[i++])) { + switch ((*start)[-1]) { /* * First the glyphs. There are several different forms of * these, but each eventually returns a substring of the glyph @@ -121,7 +76,7 @@ mandoc_escape(const char **end, const char **start, int *sz) */ case ('('): gly = ESCAPE_SPECIAL; - lim = 2; + *sz = 2; break; case ('['): gly = ESCAPE_SPECIAL; @@ -131,18 +86,39 @@ mandoc_escape(const char **end, const char **start, int *sz) * Unicode codepoint. Here, however, only check whether * it's not a zero-width escape. */ - if ('u' == cp[i] && ']' != cp[i + 1]) + if ('u' == (*start)[0] && ']' != (*start)[1]) gly = ESCAPE_UNICODE; term = ']'; break; case ('C'): - if ('\'' != cp[i]) + if ('\'' != **start) return(ESCAPE_ERROR); - gly = ESCAPE_SPECIAL; + *start = ++*end; + if ('u' == (*start)[0] && '\'' != (*start)[1]) + gly = ESCAPE_UNICODE; + else + gly = ESCAPE_SPECIAL; term = '\''; break; /* + * Escapes taking no arguments at all. + */ + case ('d'): + /* FALLTHROUGH */ + case ('u'): + return(ESCAPE_IGNORE); + + /* + * 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. */ @@ -166,21 +142,17 @@ mandoc_escape(const char **end, const char **start, int *sz) case ('f'): if (ESCAPE_ERROR == gly) gly = ESCAPE_FONT; - - rstart= &cp[i]; - if (start) - *start = rstart; - - switch (cp[i++]) { + switch (**start) { case ('('): - lim = 2; + *start = ++*end; + *sz = 2; break; case ('['): + *start = ++*end; term = ']'; break; default: - lim = 1; - i--; + *sz = 1; break; } break; @@ -193,18 +165,23 @@ mandoc_escape(const char **end, const char **start, int *sz) /* FALLTHROUGH */ case ('b'): /* FALLTHROUGH */ + case ('B'): + /* FALLTHROUGH */ case ('D'): /* FALLTHROUGH */ case ('o'): /* FALLTHROUGH */ case ('R'): /* FALLTHROUGH */ + case ('w'): + /* FALLTHROUGH */ case ('X'): /* FALLTHROUGH */ case ('Z'): - if ('\'' != cp[i++]) + if ('\'' != **start) return(ESCAPE_ERROR); gly = ESCAPE_IGNORE; + *start = ++*end; term = '\''; break; @@ -212,8 +189,6 @@ mandoc_escape(const char **end, const char **start, int *sz) * These escapes are of the form \X'N', where 'X' is the trigger * and 'N' resolves to a numerical expression. */ - case ('B'): - /* FALLTHROUGH */ case ('h'): /* FALLTHROUGH */ case ('H'): @@ -221,20 +196,17 @@ mandoc_escape(const char **end, const char **start, int *sz) case ('L'): /* FALLTHROUGH */ case ('l'): - gly = ESCAPE_NUMBERED; /* FALLTHROUGH */ case ('S'): /* FALLTHROUGH */ case ('v'): /* FALLTHROUGH */ - case ('w'): - /* FALLTHROUGH */ case ('x'): - if (ESCAPE_ERROR == gly) - gly = ESCAPE_IGNORE; - if ('\'' != cp[i++]) + if ('\'' != **start) return(ESCAPE_ERROR); - term = numeric = '\''; + gly = ESCAPE_IGNORE; + *start = ++*end; + term = '\''; break; /* @@ -242,17 +214,17 @@ mandoc_escape(const char **end, const char **start, int *sz) * XXX Do any other escapes need similar handling? */ case ('N'): - if ('\0' == cp[i]) + if ('\0' == **start) return(ESCAPE_ERROR); - *end = &cp[++i]; - if (isdigit((unsigned char)cp[i-1])) + (*end)++; + if (isdigit((unsigned char)**start)) { + *sz = 1; return(ESCAPE_IGNORE); + } + (*start)++; while (isdigit((unsigned char)**end)) (*end)++; - if (start) - *start = &cp[i]; - if (sz) - *sz = *end - &cp[i]; + *sz = *end - *start; if ('\0' != **end) (*end)++; return(ESCAPE_NUMBERED); @@ -263,122 +235,93 @@ mandoc_escape(const char **end, const char **start, int *sz) case ('s'): gly = ESCAPE_IGNORE; - rstart = &cp[i]; - if (start) - *start = rstart; - /* See +/- counts as a sign. */ - c = cp[i]; - if ('+' == c || '-' == c || ASCII_HYPH == c) - ++i; + if ('+' == **end || '-' == **end || ASCII_HYPH == **end) + (*end)++; - switch (cp[i++]) { + switch (**end) { case ('('): - lim = 2; + *start = ++*end; + *sz = 2; break; case ('['): - term = numeric = ']'; + *start = ++*end; + term = ']'; break; case ('\''): - term = numeric = '\''; + *start = ++*end; + term = '\''; break; default: - lim = 1; - i--; + *sz = 1; break; } - /* See +/- counts as a sign. */ - c = cp[i]; - if ('+' == c || '-' == c || ASCII_HYPH == c) - ++i; - break; /* * Anything else is assumed to be a glyph. + * In this case, pass back the character after the backslash. */ default: gly = ESCAPE_SPECIAL; - lim = 1; - i--; + *start = --*end; + *sz = 1; break; } assert(ESCAPE_ERROR != gly); - rstart = &cp[i]; - if (start) - *start = rstart; - /* - * If a terminating block has been specified, we need to - * handle the case of recursion, which could have their - * own terminating blocks that mess up our parse. This, by the - * way, means that the "start" and "size" values will be - * effectively meaningless. - */ - - ssz = 0; - if (numeric && -1 == (ssz = numescape(&cp[i]))) - return(ESCAPE_ERROR); - - i += ssz; - rlim = -1; - - /* - * We have a character terminator. Try to read up to that - * character. If we can't (i.e., we hit the nil), then return - * an error; if we can, calculate our length, read past the - * terminating character, and exit. + * Read up to the terminating character, + * paying attention to nested escapes. */ if ('\0' != term) { - *end = strchr(&cp[i], term); - if ('\0' == *end) + while (**end != term) { + switch (**end) { + case ('\0'): + return(ESCAPE_ERROR); + case ('\\'): + (*end)++; + if (ESCAPE_ERROR == + mandoc_escape(end, NULL, NULL)) + return(ESCAPE_ERROR); + break; + default: + (*end)++; + break; + } + } + *sz = (*end)++ - *start; + } else { + assert(*sz > 0); + if ((size_t)*sz > strlen(*start)) return(ESCAPE_ERROR); - - rlim = *end - &cp[i]; - if (sz) - *sz = rlim; - (*end)++; - goto out; + *end += *sz; } - assert(lim > 0); - - /* - * We have a numeric limit. If the string is shorter than that, - * stop and return an error. Else adjust our endpoint, length, - * and return the current glyph. - */ - - if ((size_t)lim > strlen(&cp[i])) - return(ESCAPE_ERROR); - - rlim = lim; - if (sz) - *sz = rlim; - - *end = &cp[i] + lim; - -out: - assert(rlim >= 0 && rstart); - /* Run post-processors. */ switch (gly) { case (ESCAPE_FONT): - /* - * Pretend that the constant-width font modes are the - * same as the regular font modes. - */ - if (2 == rlim && 'C' == *rstart) - rstart++; - else if (1 != rlim) + if (2 == *sz) { + if ('C' == **start) { + /* + * Treat constant-width font modes + * just like regular font modes. + */ + (*start)++; + (*sz)--; + } else { + if ('B' == (*start)[0] && 'I' == (*start)[1]) + gly = ESCAPE_FONTBI; + break; + } + } else if (1 != *sz) break; - switch (*rstart) { + switch (**start) { case ('3'): /* FALLTHROUGH */ case ('B'): @@ -400,9 +343,7 @@ out: } break; case (ESCAPE_SPECIAL): - if (1 != rlim) - break; - if ('c' == *rstart) + if (1 == *sz && 'c' == **start) gly = ESCAPE_NOSPACE; break; default: @@ -484,10 +425,10 @@ mandoc_strdup(const char *ptr) * 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. - * Null-terminate the argument in place. + * NUL-terminate the argument in place. * Collapse pairs of quotes inside quoted arguments. * Advance the argument pointer to the next argument, - * or to the null byte terminating the argument line. + * or to the NUL byte terminating the argument line. */ char * mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos) @@ -506,17 +447,35 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos) pairs = 0; white = 0; for (cp = start; '\0' != *cp; cp++) { - /* Move left after quoted quotes and escaped backslashes. */ + + /* + * Move the following text left + * after quoted quotes and after "\\" and "\t". + */ if (pairs) cp[-pairs] = cp[0]; + if ('\\' == cp[0]) { - if ('\\' == cp[1]) { - /* Poor man's copy mode. */ + /* + * In copy mode, translate double to single + * backslashes and backslash-t to literal tabs. + */ + switch (cp[1]) { + case ('t'): + cp[0] = '\t'; + /* FALLTHROUGH */ + case ('\\'): pairs++; cp++; - } else if (0 == quoted && ' ' == cp[1]) + break; + case (' '): /* Skip escaped blanks. */ - cp++; + if (0 == quoted) + cp++; + break; + default: + break; + } } else if (0 == quoted) { if (' ' == cp[0]) { /* Unescaped blanks end unquoted args. */ @@ -540,7 +499,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos) if (1 == quoted) mandoc_msg(MANDOCERR_BADQUOTE, parse, ln, *pos, NULL); - /* Null-terminate this argument and move to the next one. */ + /* NUL-terminate this argument and move to the next one. */ if (pairs) cp[-pairs] = '\0'; if ('\0' != *cp) { @@ -678,32 +637,6 @@ mandoc_eos(const char *p, size_t sz, int enclosed) } /* - * 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. - */ -int -mandoc_getcontrol(const char *cp, int *ppos) -{ - int pos; - - pos = *ppos; - - 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); -} - -/* * Convert a string to a long that may not be <0. * If the string is invalid, or is less than 0, return -1. */ diff --git a/contrib/mdocml/mandoc.h b/contrib/mdocml/mandoc.h index a37effc..4c6a32f 100644 --- a/contrib/mdocml/mandoc.h +++ b/contrib/mdocml/mandoc.h @@ -1,6 +1,7 @@ -/* $Id: mandoc.h,v 1.99 2012/02/16 20:51:31 joerg Exp $ */ +/* $Id: mandoc.h,v 1.112 2013/12/30 18:30:32 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -50,6 +51,7 @@ enum mandocerr { MANDOCERR_NOTITLE, /* no title in document */ MANDOCERR_UPPERCASE, /* document title should be all caps */ MANDOCERR_BADMSEC, /* unknown manual section */ + MANDOCERR_BADVOLARCH, /* unknown manual volume or arch */ MANDOCERR_NODATE, /* date missing, using today's date */ MANDOCERR_BADDATE, /* cannot parse date, using it verbatim */ MANDOCERR_PROLOGOOO, /* prologue macros out of order */ @@ -61,14 +63,14 @@ enum mandocerr { MANDOCERR_SO, /* .so is fragile, better use ln(1) */ MANDOCERR_NAMESECFIRST, /* NAME section must come first */ MANDOCERR_BADNAMESEC, /* bad NAME section contents */ - MANDOCERR_NONAME, /* manual name not yet set */ MANDOCERR_SECOOO, /* sections out of conventional order */ MANDOCERR_SECREP, /* duplicate section name */ - MANDOCERR_SECMSEC, /* section not in conventional manual section */ + MANDOCERR_SECMSEC, /* section header suited to sections ... */ /* related to macros and nesting */ MANDOCERR_MACROOBS, /* skipping obsolete macro */ MANDOCERR_IGNPAR, /* skipping paragraph macro */ + MANDOCERR_MOVEPAR, /* moving paragraph macro out of list */ MANDOCERR_IGNNS, /* skipping no-space macro */ MANDOCERR_SCOPENEST, /* blocks badly nested */ MANDOCERR_CHILD, /* child violates parent syntax */ @@ -129,10 +131,12 @@ enum mandocerr { MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ MANDOCERR_BADCHAR, /* skipping bad character */ MANDOCERR_NAMESC, /* escaped character not allowed in a name */ + MANDOCERR_NONAME, /* manual name not yet set */ MANDOCERR_NOTEXT, /* skipping text before the first section header */ MANDOCERR_MACRO, /* skipping unknown macro */ MANDOCERR_REQUEST, /* NOT IMPLEMENTED: skipping request */ MANDOCERR_ARGCOUNT, /* argument count wrong */ + MANDOCERR_STRAYTA, /* skipping column outside column list */ MANDOCERR_NOSCOPE, /* skipping end of block that is not open */ MANDOCERR_SCOPEBROKEN, /* missing end of block */ MANDOCERR_SCOPEEXIT, /* scope open on exit */ @@ -141,6 +145,7 @@ enum mandocerr { MANDOCERR_NOARGS, /* macro requires line argument(s) */ MANDOCERR_NOBODY, /* macro requires body argument(s) */ MANDOCERR_NOARGV, /* macro requires argument(s) */ + MANDOCERR_NUMERIC, /* request requires a numeric argument */ MANDOCERR_LISTTYPE, /* missing list type */ MANDOCERR_ARGSLOST, /* line argument(s) will be lost */ MANDOCERR_BODYLOST, /* body argument(s) will be lost */ @@ -160,7 +165,7 @@ enum mandocerr { MANDOCERR_MAX }; -struct tbl { +struct tbl_opts { char tab; /* cell-separator */ char decimal; /* decimal point */ int linesize; @@ -175,20 +180,14 @@ struct tbl { int cols; /* number of columns */ }; -enum tbl_headt { - TBL_HEAD_DATA, /* plug in data from tbl_dat */ - TBL_HEAD_VERT, /* vertical spacer */ - TBL_HEAD_DVERT /* double-vertical spacer */ -}; - /* * The head of a table specifies all of its columns. When formatting a * tbl_span, iterate over these and plug in data from the tbl_span when * appropriate, using tbl_cell as a guide to placement. */ struct tbl_head { - enum tbl_headt pos; int ident; /* 0 <= unique id < cols */ + int vert; /* width of preceding vertical line */ struct tbl_head *next; struct tbl_head *prev; }; @@ -203,8 +202,6 @@ enum tbl_cellt { TBL_CELL_DOWN, /* ^ */ TBL_CELL_HORIZ, /* _, - */ TBL_CELL_DHORIZ, /* = */ - TBL_CELL_VERT, /* | */ - TBL_CELL_DVERT, /* || */ TBL_CELL_MAX }; @@ -213,6 +210,7 @@ enum tbl_cellt { */ struct tbl_cell { struct tbl_cell *next; + int vert; /* width of preceding vertical line */ enum tbl_cellt pos; size_t spacing; int flags; @@ -266,7 +264,7 @@ enum tbl_spant { * A row of data in a table. */ struct tbl_span { - struct tbl *tbl; + struct tbl_opts *opts; struct tbl_head *head; struct tbl_row *layout; /* layout row */ struct tbl_dat *first; @@ -382,11 +380,13 @@ enum mandoc_esc { ESCAPE_FONT, /* a generic font mode */ ESCAPE_FONTBOLD, /* bold font mode */ ESCAPE_FONTITALIC, /* italic font mode */ + ESCAPE_FONTBI, /* bold italic font mode */ ESCAPE_FONTROMAN, /* roman font mode */ ESCAPE_FONTPREV, /* previous font mode */ ESCAPE_NUMBERED, /* a numbered glyph */ ESCAPE_UNICODE, /* a unicode codepoint */ - ESCAPE_NOSPACE /* suppress space if the last on a line */ + ESCAPE_NOSPACE, /* suppress space if the last on a line */ + ESCAPE_SKIPCHAR /* skip the next character */ }; typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel, @@ -413,8 +413,8 @@ int mchars_spec2cp(const struct mchars *, const char *, size_t); const char *mchars_spec2str(const struct mchars *, const char *, size_t, size_t *); -struct mparse *mparse_alloc(enum mparset, - enum mandoclevel, mandocmsg, void *); +struct mparse *mparse_alloc(enum mparset, enum mandoclevel, + mandocmsg, void *, char *); void mparse_free(struct mparse *); void mparse_keep(struct mparse *); enum mandoclevel mparse_readfd(struct mparse *, int, const char *); diff --git a/contrib/mdocml/mandoc_char.7 b/contrib/mdocml/mandoc_char.7 index acc1b61..8d83566 100644 --- a/contrib/mdocml/mandoc_char.7 +++ b/contrib/mdocml/mandoc_char.7 @@ -1,4 +1,4 @@ -.\" $Id: mandoc_char.7,v 1.51 2011/11/23 10:09:30 kristaps Exp $ +.\" $Id: mandoc_char.7,v 1.56 2013/12/26 17:23:42 schwarze Exp $ .\" .\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org> .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: November 23 2011 $ +.Dd $Mdocdate: December 26 2013 $ .Dt MANDOC_CHAR 7 .Os .Sh NAME @@ -98,26 +98,27 @@ in literal context, and when none of the following special cases apply, just use the normal space character .Pq Sq \ . .Pp -When filling text, lines may be broken between words, i.e. at space +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 non-breaking space escape sequence -.Pq Sq \e~ +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 +.Dq number\e\ 1 will be kept together as -.Dq number\~1 +.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. -In some cases, using either the non-breaking -.Pq Sq \e~ -or the breaking +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\ \& -space escape sequence may be preferable. +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& @@ -194,14 +195,13 @@ manual. Spacing: .Bl -column "Input" "Description" -offset indent -compact .It Em Input Ta Em Description -.It \e~ Ta non-breaking, non-collapsing space -.It \e Ta breaking, non-collapsing n-width space -.It \e^ Ta zero-width space -.It \e% Ta zero-width space +.It Sq \e\ \& Ta unpaddable non-breaking space +.It \e~ Ta paddable non-breaking space +.It \e0 Ta unpaddable, breaking digit-width space +.It \e| Ta one-sixth \e(em narrow space, zero width in nroff mode +.It \e^ Ta one-twelfth \e(em half-narrow space, zero width in nroff .It \e& Ta zero-width space -.It \e| Ta zero-width space -.It \e0 Ta breaking, non-collapsing digit-width space -.It \ec Ta removes any trailing space (if applicable) +.It \e% Ta zero-width space allowing hyphenation .El .Pp Lines: @@ -655,13 +655,18 @@ manual. .It \e*(Ai Ta \*(Ai Ta ANSI standard name .El .Sh UNICODE CHARACTERS -The escape sequence +The escape sequences .Pp -.Dl \e[uXXXX] +.Dl \e[uXXXX] and \eC'uXXXX' .Pp -is interpreted as a Unicode codepoint. +are interpreted as Unicode codepoints. The codepoint must be in the range above U+0080 and less than U+10FFFF. -For compatibility, points must be zero-padded to four characters; if +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. .\" .Pp @@ -684,7 +689,7 @@ For example, do not use \eN'34', use \e(dq, or even the plain .Sq \(dq character where possible. .Sh COMPATIBILITY -This section documents compatibility between mandoc and other other +This section documents compatibility between mandoc and other troff implementations, at this time limited to GNU troff .Pq Qq groff . .Pp @@ -728,12 +733,11 @@ known representation. The .Nm manual page was written by -.An Kristaps Dzonsons , -.Mt kristaps@bsd.lv . +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . .Sh CAVEATS -The +The predefined string .Sq \e*(Ba -escape mimics the behaviour of the +mimics the behaviour of the .Sq \&| character in .Xr mdoc 7 ; diff --git a/contrib/mdocml/mdoc.7 b/contrib/mdocml/mdoc.7 index 44d927b..165c76b 100644 --- a/contrib/mdocml/mdoc.7 +++ b/contrib/mdocml/mdoc.7 @@ -1,7 +1,7 @@ -.\" $Id: mdoc.7,v 1.214 2012/01/03 10:18:05 kristaps Exp $ +.\" $Id: mdoc.7,v 1.223 2013/12/25 14:09:32 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2010, 2011, 2013 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 3 2012 $ +.Dd $Mdocdate: December 25 2013 $ .Dt MDOC 7 .Os .Sh NAME @@ -477,6 +477,7 @@ in the alphabetical .Bl -column "Brq, Bro, Brc" description .It Sx \&Lb Ta function library (one argument) .It Sx \&In Ta include file (one argument) +.It Sx \&Fd Ta other preprocessor directive (>0 arguments) .It Sx \&Ft Ta function type (>0 arguments) .It Sx \&Fo , \&Fc Ta function block: Ar funcname .It Sx \&Fn Ta function name: @@ -657,7 +658,7 @@ for all other author listings. .Pp Examples: .Dl \&.An -nosplit -.Dl \&.An Kristaps Dzonsons \&Aq kristaps@bsd.lv +.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv .Ss \&Ao Begin a block enclosed by angle brackets. Does not have any head arguments. @@ -711,7 +712,9 @@ for fixed strings to be passed verbatim as arguments, use or .Sx \&Cm . .Ss \&At -Formats an AT&T version. +Formats an +.At +version. Accepts one optional argument: .Pp .Bl -tag -width "v[1-7] | 32vX" -offset indent -compact @@ -820,8 +823,8 @@ The most popular is the imaginary macro which resolves to .Sy 6n . .It -A width using the syntax described in -.Sx Scaling Widths . +A scaling width as described in +.Xr roff 7 . .It An arbitrary string, which indents by the length of this string. .El @@ -926,8 +929,8 @@ The .Fl width and .Fl offset -arguments accept -.Sx Scaling Widths +arguments accept scaling widths as described in +.Xr roff 7 or use the length of the given string. The .Fl offset @@ -956,9 +959,9 @@ A columnated list. The .Fl width argument has no effect; instead, each argument specifies the width -of one column, using either the -.Sx Scaling Widths -syntax or the string length of the argument. +of one column, using either the scaling width syntax described in +.Xr roff 7 +or the string length of the argument. If the first line of the body of a .Fl column list is not an @@ -1089,7 +1092,9 @@ Examples: See also .Sx \&Bro . .Ss \&Bsx -Format the BSD/OS version provided as an argument, or a default value if +Format the +.Bsx +version provided as an argument, or a default value if no argument is provided. .Pp Examples: @@ -1109,7 +1114,9 @@ and Prints .Dq is currently in beta test. .Ss \&Bx -Format the BSD version provided as an argument, or a default value if no +Format the +.Bx +version provided as an argument, or a default value if no argument is provided. .Pp Examples: @@ -1401,11 +1408,16 @@ See also .Sx \&Er and .Sx \&Ev -for special-purpose constants and +for special-purpose constants, .Sx \&Va -for variable symbols. +for variable symbols, and +.Sx \&Fd +for listing preprocessor variable definitions in the +.Em SYNOPSIS . .Ss \&Dx -Format the DragonFly BSD version provided as an argument, or a default +Format the +.Dx +version provided as an argument, or a default value if no argument is provided. .Pp Examples: @@ -1562,15 +1574,32 @@ See also End a function context started by .Sx \&Fo . .Ss \&Fd -Historically used to document include files. -This usage has been deprecated in favour of +Preprocessor directive, in particular for listing it in the +.Em SYNOPSIS . +Historically, it was also used to document include files. +The latter usage has been deprecated in favour of .Sx \&In . -Do not use this macro. +.Pp +Its syntax is as follows: +.Bd -ragged -offset indent +.Pf \. Sx \&Fd +.Li # Ns Ar directive +.Op Ar argument ... +.Ed +.Pp +Examples: +.Dl \&.Fd #define sa_handler __sigaction_u.__sa_handler +.Dl \&.Fd #define SIO_MAXNFDS +.Dl \&.Fd #ifdef FS_DEBUG +.Dl \&.Ft void +.Dl \&.Fn dbg_open \(dqconst char *\(dq +.Dl \&.Fd #endif .Pp See also -.Sx MANUAL STRUCTURE +.Sx MANUAL STRUCTURE , +.Sx \&In , and -.Sx \&In . +.Sx \&Dv . .Ss \&Fl Command-line flag or option. Used when listing arguments to command-line utilities. @@ -1851,7 +1880,7 @@ section as described in .Pp Examples: .Dl \&.Lb libz -.Dl \&.Lb mdoc +.Dl \&.Lb libmandoc .Ss \&Li Denotes text that should be in a .Li literal @@ -1902,6 +1931,7 @@ Its syntax is as follows: .Pp Examples: .Dl \&.Mt discuss@manpages.bsd.lv +.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv .Ss \&Nd A one line description of the manual's content. This may only be invoked in the @@ -2083,7 +2113,7 @@ This macro is obsolete and not implemented in .Xr mandoc 1 . .Pp Historical -.Xr mdoc 7 +.Nm packages described it as .Dq "old function type (FORTRAN)" . .Ss \&Ox @@ -2347,20 +2377,26 @@ The following standards are recognised: .St -p1003.1b-93 .It \-p1003.1c-95 .St -p1003.1c-95 +.It \-p1003.1d-99 +.St -p1003.1d-99 .It \-p1003.1g-2000 .St -p1003.1g-2000 .It \-p1003.1i-95 .St -p1003.1i-95 +.It \-p1003.1j-2000 +.St -p1003.1j-2000 +.It \-p1003.1q-2000 +.St -p1003.1q-2000 +.It \-p1003.2 +.St -p1003.2 .It \-p1003.2-92 .St -p1003.2-92 .It \-p1003.2a-92 .St -p1003.2a-92 -.It \-p1387.2-95 -.St -p1387.2-95 -.It \-p1003.2 -.St -p1003.2 .It \-p1387.2 .St -p1387.2 +.It \-p1387.2-95 +.St -p1387.2-95 .It \-isoC .St -isoC .It \-isoC-90 @@ -2407,6 +2443,8 @@ The following standards are recognised: .St -xbd5 .It \-xcu5 .St -xcu5 +.It \-xsh4.2 +.St -xsh4.2 .It \-xsh5 .St -xsh5 .It \-xns5 @@ -2467,7 +2505,9 @@ Examples: Prints out .Dq currently under development. .Ss \&Ux -Format the UNIX name. +Format the +.Ux +name. Accepts no argument. .Pp Examples: @@ -2532,20 +2572,14 @@ Link to another manual .Pq Qq cross-reference . Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Xr Ar name section +.D1 Pf \. Sx \&Xr Ar name Op section .Pp -The +Cross reference the .Ar name and .Ar section -are the name and section of the linked manual. -If -.Ar section -is followed by non-punctuation, an -.Sx \&Ns -is inserted into the token stream. -This behaviour is for compatibility with -GNU troff. +number of another man page; +omitting the section number is rarely useful. .Pp Examples: .Dl \&.Xr mandoc 1 @@ -2569,8 +2603,8 @@ Its syntax is as follows: .Pp The .Ar height -argument must be formatted as described in -.Sx Scaling Widths . +argument is a scaling width as described in +.Xr roff 7 . If unspecified, .Sx \&sp asserts a single vertical space. @@ -2964,7 +2998,7 @@ Manually switching the font using the .Ql \ef font escape sequences is never required. .Sh COMPATIBILITY -This section documents compatibility between mandoc and other other +This section documents compatibility between mandoc and other troff implementations, at this time limited to GNU troff .Pq Qq groff . The term @@ -3168,5 +3202,4 @@ utility written by Kristaps Dzonsons appeared in The .Nm reference was written by -.An Kristaps Dzonsons , -.Mt kristaps@bsd.lv . +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . diff --git a/contrib/mdocml/mdoc.c b/contrib/mdocml/mdoc.c index 81a4ffc..87b3587 100644 --- a/contrib/mdocml/mdoc.c +++ b/contrib/mdocml/mdoc.c @@ -1,7 +1,7 @@ -/* $Id: mdoc.c,v 1.196 2011/09/30 00:13:28 schwarze Exp $ */ +/* $Id: mdoc.c,v 1.206 2013/12/24 19:11:46 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -104,20 +104,20 @@ static int mdoc_ptext(struct mdoc *, int, char *, int); static int mdoc_pmacro(struct mdoc *, int, char *, int); const struct mdoc_node * -mdoc_node(const struct mdoc *m) +mdoc_node(const struct mdoc *mdoc) { - assert( ! (MDOC_HALT & m->flags)); - return(m->first); + assert( ! (MDOC_HALT & mdoc->flags)); + return(mdoc->first); } const struct mdoc_meta * -mdoc_meta(const struct mdoc *m) +mdoc_meta(const struct mdoc *mdoc) { - assert( ! (MDOC_HALT & m->flags)); - return(&m->meta); + assert( ! (MDOC_HALT & mdoc->flags)); + return(&mdoc->meta); } @@ -197,13 +197,14 @@ mdoc_free(struct mdoc *mdoc) * Allocate volatile and non-volatile parse resources. */ struct mdoc * -mdoc_alloc(struct roff *roff, struct mparse *parse) +mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos) { struct mdoc *p; p = mandoc_calloc(1, sizeof(struct mdoc)); p->parse = parse; + p->defos = defos; p->roff = roff; mdoc_hash_init(); @@ -217,61 +218,61 @@ mdoc_alloc(struct roff *roff, struct mparse *parse) * through to macro_end() in macro.c. */ int -mdoc_endparse(struct mdoc *m) +mdoc_endparse(struct mdoc *mdoc) { - assert( ! (MDOC_HALT & m->flags)); - if (mdoc_macroend(m)) + assert( ! (MDOC_HALT & mdoc->flags)); + if (mdoc_macroend(mdoc)) return(1); - m->flags |= MDOC_HALT; + mdoc->flags |= MDOC_HALT; return(0); } int -mdoc_addeqn(struct mdoc *m, const struct eqn *ep) +mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep) { struct mdoc_node *n; - assert( ! (MDOC_HALT & m->flags)); + assert( ! (MDOC_HALT & mdoc->flags)); /* No text before an initial macro. */ - if (SEC_NONE == m->lastnamed) { - mdoc_pmsg(m, ep->ln, ep->pos, MANDOCERR_NOTEXT); + if (SEC_NONE == mdoc->lastnamed) { + mdoc_pmsg(mdoc, ep->ln, ep->pos, MANDOCERR_NOTEXT); return(1); } - n = node_alloc(m, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); + n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); n->eqn = ep; - if ( ! node_append(m, n)) + if ( ! node_append(mdoc, n)) return(0); - m->next = MDOC_NEXT_SIBLING; + mdoc->next = MDOC_NEXT_SIBLING; return(1); } int -mdoc_addspan(struct mdoc *m, const struct tbl_span *sp) +mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp) { struct mdoc_node *n; - assert( ! (MDOC_HALT & m->flags)); + assert( ! (MDOC_HALT & mdoc->flags)); /* No text before an initial macro. */ - if (SEC_NONE == m->lastnamed) { - mdoc_pmsg(m, sp->line, 0, MANDOCERR_NOTEXT); + if (SEC_NONE == mdoc->lastnamed) { + mdoc_pmsg(mdoc, sp->line, 0, MANDOCERR_NOTEXT); return(1); } - n = node_alloc(m, sp->line, 0, MDOC_MAX, MDOC_TBL); + n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL); n->span = sp; - if ( ! node_append(m, n)) + if ( ! node_append(mdoc, n)) return(0); - m->next = MDOC_NEXT_SIBLING; + mdoc->next = MDOC_NEXT_SIBLING; return(1); } @@ -281,12 +282,12 @@ mdoc_addspan(struct mdoc *m, const struct tbl_span *sp) * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()). */ int -mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs) +mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs) { - assert( ! (MDOC_HALT & m->flags)); + assert( ! (MDOC_HALT & mdoc->flags)); - m->flags |= MDOC_NEWLINE; + mdoc->flags |= MDOC_NEWLINE; /* * Let the roff nS register switch SYNOPSIS mode early, @@ -294,16 +295,14 @@ mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs) * whether this mode is on or off. * Note that this mode is also switched by the Sh macro. */ - if (roff_regisset(m->roff, REG_nS)) { - if (roff_regget(m->roff, REG_nS)) - m->flags |= MDOC_SYNOPSIS; - else - m->flags &= ~MDOC_SYNOPSIS; - } + if (roff_getreg(mdoc->roff, "nS")) + mdoc->flags |= MDOC_SYNOPSIS; + else + mdoc->flags &= ~MDOC_SYNOPSIS; - return(mandoc_getcontrol(buf, &offs) ? - mdoc_pmacro(m, ln, buf, offs) : - mdoc_ptext(m, ln, buf, offs)); + return(roff_getcontrol(mdoc->roff, buf, &offs) ? + mdoc_pmacro(mdoc, ln, buf, offs) : + mdoc_ptext(mdoc, ln, buf, offs)); } int @@ -314,31 +313,31 @@ mdoc_macro(MACRO_PROT_ARGS) /* If we're in the body, deny prologue calls. */ if (MDOC_PROLOGUE & mdoc_macros[tok].flags && - MDOC_PBODY & m->flags) { - mdoc_pmsg(m, line, ppos, MANDOCERR_BADBODY); + MDOC_PBODY & mdoc->flags) { + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADBODY); return(1); } /* If we're in the prologue, deny "body" macros. */ if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) && - ! (MDOC_PBODY & m->flags)) { - mdoc_pmsg(m, line, ppos, MANDOCERR_BADPROLOG); - if (NULL == m->meta.msec) - m->meta.msec = mandoc_strdup("1"); - if (NULL == m->meta.title) - m->meta.title = mandoc_strdup("UNKNOWN"); - if (NULL == m->meta.vol) - m->meta.vol = mandoc_strdup("LOCAL"); - if (NULL == m->meta.os) - m->meta.os = mandoc_strdup("LOCAL"); - if (NULL == m->meta.date) - m->meta.date = mandoc_normdate - (m->parse, NULL, line, ppos); - m->flags |= MDOC_PBODY; + ! (MDOC_PBODY & mdoc->flags)) { + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADPROLOG); + if (NULL == mdoc->meta.msec) + mdoc->meta.msec = mandoc_strdup("1"); + if (NULL == mdoc->meta.title) + mdoc->meta.title = mandoc_strdup("UNKNOWN"); + if (NULL == mdoc->meta.vol) + mdoc->meta.vol = mandoc_strdup("LOCAL"); + if (NULL == mdoc->meta.os) + mdoc->meta.os = mandoc_strdup("LOCAL"); + if (NULL == mdoc->meta.date) + mdoc->meta.date = mandoc_normdate + (mdoc->parse, NULL, line, ppos); + mdoc->flags |= MDOC_PBODY; } - return((*mdoc_macros[tok].fp)(m, tok, line, ppos, pos, buf)); + return((*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf)); } @@ -374,6 +373,8 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p) switch (p->type) { case (MDOC_BODY): + if (ENDBODY_NOT != p->end) + break; /* FALLTHROUGH */ case (MDOC_TAIL): /* FALLTHROUGH */ @@ -424,97 +425,99 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p) static struct mdoc_node * -node_alloc(struct mdoc *m, int line, int pos, +node_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, enum mdoc_type type) { struct mdoc_node *p; p = mandoc_calloc(1, sizeof(struct mdoc_node)); - p->sec = m->lastsec; + p->sec = mdoc->lastsec; p->line = line; p->pos = pos; + p->lastline = line; p->tok = tok; p->type = type; /* Flag analysis. */ - if (MDOC_SYNOPSIS & m->flags) + if (MDOC_SYNOPSIS & mdoc->flags) p->flags |= MDOC_SYNPRETTY; else p->flags &= ~MDOC_SYNPRETTY; - if (MDOC_NEWLINE & m->flags) + if (MDOC_NEWLINE & mdoc->flags) p->flags |= MDOC_LINE; - m->flags &= ~MDOC_NEWLINE; + mdoc->flags &= ~MDOC_NEWLINE; return(p); } int -mdoc_tail_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) +mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_TAIL); - if ( ! node_append(m, p)) + p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL); + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_head_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) +mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) { struct mdoc_node *p; - assert(m->first); - assert(m->last); + assert(mdoc->first); + assert(mdoc->last); - p = node_alloc(m, line, pos, tok, MDOC_HEAD); - if ( ! node_append(m, p)) + p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD); + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_body_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) +mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_BODY); - if ( ! node_append(m, p)) + p = node_alloc(mdoc, line, pos, tok, MDOC_BODY); + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_endbody_alloc(struct mdoc *m, int line, int pos, enum mdoct tok, +mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, struct mdoc_node *body, enum mdoc_endbody end) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_BODY); + p = node_alloc(mdoc, line, pos, tok, MDOC_BODY); p->pending = body; + p->norm = body->norm; p->end = end; - if ( ! node_append(m, p)) + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_SIBLING; + mdoc->next = MDOC_NEXT_SIBLING; return(1); } int -mdoc_block_alloc(struct mdoc *m, int line, int pos, +mdoc_block_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, struct mdoc_arg *args) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_BLOCK); + p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK); p->args = args; if (p->args) (args->refcnt)++; @@ -533,20 +536,20 @@ mdoc_block_alloc(struct mdoc *m, int line, int pos, break; } - if ( ! node_append(m, p)) + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_elem_alloc(struct mdoc *m, int line, int pos, +mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, struct mdoc_arg *args) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_ELEM); + p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM); p->args = args; if (p->args) (args->refcnt)++; @@ -559,27 +562,44 @@ mdoc_elem_alloc(struct mdoc *m, int line, int pos, break; } - if ( ! node_append(m, p)) + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p) +mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p) { struct mdoc_node *n; - n = node_alloc(m, line, pos, MDOC_MAX, MDOC_TEXT); - n->string = roff_strdup(m->roff, p); + n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT); + n->string = roff_strdup(mdoc->roff, p); - if ( ! node_append(m, n)) + if ( ! node_append(mdoc, n)) return(0); - m->next = MDOC_NEXT_SIBLING; + mdoc->next = MDOC_NEXT_SIBLING; return(1); } +void +mdoc_word_append(struct mdoc *mdoc, const char *p) +{ + struct mdoc_node *n; + char *addstr, *newstr; + + n = mdoc->last; + addstr = roff_strdup(mdoc->roff, p); + if (-1 == asprintf(&newstr, "%s %s", n->string, addstr)) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + free(addstr); + free(n->string); + n->string = newstr; + mdoc->next = MDOC_NEXT_SIBLING; +} static void mdoc_node_free(struct mdoc_node *p) @@ -596,7 +616,7 @@ mdoc_node_free(struct mdoc_node *p) static void -mdoc_node_unlink(struct mdoc *m, struct mdoc_node *n) +mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n) { /* Adjust siblings. */ @@ -618,35 +638,43 @@ mdoc_node_unlink(struct mdoc *m, struct mdoc_node *n) /* Adjust parse point, if applicable. */ - if (m && m->last == n) { + if (mdoc && mdoc->last == n) { if (n->prev) { - m->last = n->prev; - m->next = MDOC_NEXT_SIBLING; + mdoc->last = n->prev; + mdoc->next = MDOC_NEXT_SIBLING; } else { - m->last = n->parent; - m->next = MDOC_NEXT_CHILD; + mdoc->last = n->parent; + mdoc->next = MDOC_NEXT_CHILD; } } - if (m && m->first == n) - m->first = NULL; + if (mdoc && mdoc->first == n) + mdoc->first = NULL; } void -mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) +mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p) { while (p->child) { assert(p->nchild); - mdoc_node_delete(m, p->child); + mdoc_node_delete(mdoc, p->child); } assert(0 == p->nchild); - mdoc_node_unlink(m, p); + mdoc_node_unlink(mdoc, p); mdoc_node_free(p); } +int +mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p) +{ + + mdoc_node_unlink(mdoc, p); + return(node_append(mdoc, p)); +} + #if 0 /* * Pre-treat a text line. @@ -658,7 +686,7 @@ mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) * the end-of-line, i.e., will re-enter in the next roff parse. */ static int -mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) +mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs) { char *start, *end; char delim; @@ -666,12 +694,12 @@ mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) while ('\0' != buf[offs]) { /* Mark starting position if eqn is set. */ start = NULL; - if ('\0' != (delim = roff_eqndelim(m->roff))) + if ('\0' != (delim = roff_eqndelim(mdoc->roff))) if (NULL != (start = strchr(buf + offs, delim))) *start++ = '\0'; /* Parse text as normal. */ - if ( ! mdoc_ptext(m, line, buf, offs)) + if ( ! mdoc_ptext(mdoc, line, buf, offs)) return(0); /* Continue only if an equation exists. */ @@ -688,11 +716,11 @@ mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) } /* Parse the equation itself. */ - roff_openeqn(m->roff, NULL, line, offs, buf); + roff_openeqn(mdoc->roff, NULL, line, offs, buf); /* Process a finished equation? */ - if (roff_closeeqn(m->roff)) - if ( ! mdoc_addeqn(m, roff_eqn(m->roff))) + if (roff_closeeqn(mdoc->roff)) + if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff))) return(0); offs += (end - (buf + offs)); } @@ -706,20 +734,20 @@ mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) * control character. */ static int -mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) +mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs) { char *c, *ws, *end; struct mdoc_node *n; /* No text before an initial macro. */ - if (SEC_NONE == m->lastnamed) { - mdoc_pmsg(m, line, offs, MANDOCERR_NOTEXT); + if (SEC_NONE == mdoc->lastnamed) { + mdoc_pmsg(mdoc, line, offs, MANDOCERR_NOTEXT); return(1); } - assert(m->last); - n = m->last; + assert(mdoc->last); + n = mdoc->last; /* * Divert directly to list processing if we're encountering a @@ -731,8 +759,8 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) if (MDOC_Bl == n->tok && MDOC_BODY == n->type && LIST_column == n->norm->Bl.type) { /* `Bl' is open without any children. */ - m->flags |= MDOC_FREECOL; - return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf)); + mdoc->flags |= MDOC_FREECOL; + return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf)); } if (MDOC_It == n->tok && MDOC_BLOCK == n->type && @@ -740,8 +768,8 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) MDOC_Bl == n->parent->tok && LIST_column == n->parent->norm->Bl.type) { /* `Bl' has block-level `It' children. */ - m->flags |= MDOC_FREECOL; - return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf)); + mdoc->flags |= MDOC_FREECOL; + return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf)); } /* @@ -769,7 +797,7 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) * Strip trailing tabs in literal context only; * outside, they affect the next line. */ - if (MDOC_LITERAL & m->flags) + if (MDOC_LITERAL & mdoc->flags) continue; break; case '\\': @@ -786,27 +814,28 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) *end = '\0'; if (ws) - mdoc_pmsg(m, line, (int)(ws-buf), MANDOCERR_EOLNSPACE); + mdoc_pmsg(mdoc, line, (int)(ws-buf), MANDOCERR_EOLNSPACE); - if ('\0' == buf[offs] && ! (MDOC_LITERAL & m->flags)) { - mdoc_pmsg(m, line, (int)(c-buf), MANDOCERR_NOBLANKLN); + if ('\0' == buf[offs] && ! (MDOC_LITERAL & mdoc->flags)) { + mdoc_pmsg(mdoc, line, (int)(c-buf), MANDOCERR_NOBLANKLN); /* * Insert a `sp' in the case of a blank line. Technically, * blank lines aren't allowed, but enough manuals assume this * behaviour that we want to work around it. */ - if ( ! mdoc_elem_alloc(m, line, offs, MDOC_sp, NULL)) + if ( ! mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL)) return(0); - m->next = MDOC_NEXT_SIBLING; - return(1); + mdoc->next = MDOC_NEXT_SIBLING; + + return(mdoc_valid_post(mdoc)); } - if ( ! mdoc_word_alloc(m, line, offs, buf+offs)) + if ( ! mdoc_word_alloc(mdoc, line, offs, buf+offs)) return(0); - if (MDOC_LITERAL & m->flags) + if (MDOC_LITERAL & mdoc->flags) return(1); /* @@ -818,7 +847,7 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) assert(buf < end); if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0)) - m->last->flags |= MDOC_EOS; + mdoc->last->flags |= MDOC_EOS; return(1); } @@ -829,7 +858,7 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) * character. */ static int -mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) +mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs) { enum mdoct tok; int i, sv; @@ -839,7 +868,7 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) /* Empty post-control lines are ignored. */ if ('"' == buf[offs]) { - mdoc_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT); + mdoc_pmsg(mdoc, ln, offs, MANDOCERR_BADCOMMENT); return(1); } else if ('\0' == buf[offs]) return(1); @@ -861,7 +890,7 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX; if (MDOC_MAX == tok) { - mandoc_vmsg(MANDOCERR_MACRO, m->parse, + mandoc_vmsg(MANDOCERR_MACRO, mdoc->parse, ln, sv, "%s", buf + sv - 1); return(1); } @@ -882,21 +911,21 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) - mdoc_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE); + mdoc_pmsg(mdoc, ln, offs - 1, MANDOCERR_EOLNSPACE); /* * If an initial macro or a list invocation, divert directly * into macro processing. */ - if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) { - if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) + if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) { + if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf)) goto err; return(1); } - n = m->last; - assert(m->last); + n = mdoc->last; + assert(mdoc->last); /* * If the first macro of a `Bl -column', open an `It' block @@ -905,8 +934,8 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) if (MDOC_Bl == n->tok && MDOC_BODY == n->type && LIST_column == n->norm->Bl.type) { - m->flags |= MDOC_FREECOL; - if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) + mdoc->flags |= MDOC_FREECOL; + if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf)) goto err; return(1); } @@ -921,22 +950,22 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) NULL != n->parent && MDOC_Bl == n->parent->tok && LIST_column == n->parent->norm->Bl.type) { - m->flags |= MDOC_FREECOL; - if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) + mdoc->flags |= MDOC_FREECOL; + if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf)) goto err; return(1); } /* Normal processing of a macro. */ - if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) + if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf)) goto err; return(1); err: /* Error out. */ - m->flags |= MDOC_HALT; + mdoc->flags |= MDOC_HALT; return(0); } @@ -980,7 +1009,7 @@ mdoc_isdelim(const char *p) if (0 == strcmp(p + 1, ".")) return(DELIM_CLOSE); - if (0 == strcmp(p + 1, "*(Ba")) + if (0 == strcmp(p + 1, "fR|\\fP")) return(DELIM_MIDDLE); return(DELIM_NONE); diff --git a/contrib/mdocml/mdoc.h b/contrib/mdocml/mdoc.h index 9cee098..d0153b4 100644 --- a/contrib/mdocml/mdoc.h +++ b/contrib/mdocml/mdoc.h @@ -1,4 +1,4 @@ -/* $Id: mdoc.h,v 1.122 2011/03/22 14:05:45 kristaps Exp $ */ +/* $Id: mdoc.h,v 1.125 2013/12/24 19:11:45 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -311,6 +311,7 @@ struct mdoc_bl { int comp; /* -compact */ size_t ncols; /* -column arg count */ const char **cols; /* -column val ptr */ + int count; /* -enum counter */ }; struct mdoc_bf { @@ -350,6 +351,7 @@ struct mdoc_node { int nchild; /* number children */ int line; /* parse line */ int pos; /* parse column */ + int lastline; /* the node ends on this line */ enum mdoct tok; /* tok or MDOC__MAX if none */ int flags; #define MDOC_VALID (1 << 0) /* has been validated */ @@ -362,6 +364,7 @@ struct mdoc_node { enum mdoc_type type; /* AST node type */ enum mdoc_sec sec; /* current named section */ union mdoc_data *norm; /* normalised args */ + const void *prev_font; /* before entering this node */ /* FIXME: these can be union'd to shave a few bytes. */ struct mdoc_arg *args; /* BLOCK/ELEM */ struct mdoc_node *pending; /* BLOCK */ diff --git a/contrib/mdocml/mdoc_argv.c b/contrib/mdocml/mdoc_argv.c index 08386e0..bb9bc6c 100644 --- a/contrib/mdocml/mdoc_argv.c +++ b/contrib/mdocml/mdoc_argv.c @@ -1,6 +1,7 @@ -/* $Id: mdoc_argv.c,v 1.82 2012/03/23 05:50:24 kristaps Exp $ */ +/* $Id: mdoc_argv.c,v 1.89 2013/12/25 00:50:05 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -42,8 +43,7 @@ enum argsflag { 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) */ - ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */ + ARGV_MULTI /* multiple args (e.g., -column xxx yyy) */ }; struct mdocarg { @@ -57,8 +57,6 @@ static enum margserr args(struct mdoc *, int, int *, static int args_checkpunct(const char *, int); static int argv_multi(struct mdoc *, int, struct mdoc_argv *, int *, char *); -static int argv_opt_single(struct mdoc *, int, - struct mdoc_argv *, int *, char *); static int argv_single(struct mdoc *, int, struct mdoc_argv *, int *, char *); @@ -69,7 +67,7 @@ static const enum argvflag argvflags[MDOC_ARG_MAX] = { ARGV_NONE, /* MDOC_Unfilled */ ARGV_NONE, /* MDOC_Literal */ ARGV_SINGLE, /* MDOC_File */ - ARGV_OPT_SINGLE, /* MDOC_Offset */ + ARGV_SINGLE, /* MDOC_Offset */ ARGV_NONE, /* MDOC_Bullet */ ARGV_NONE, /* MDOC_Dash */ ARGV_NONE, /* MDOC_Hyphen */ @@ -81,7 +79,7 @@ static const enum argvflag argvflags[MDOC_ARG_MAX] = { ARGV_NONE, /* MDOC_Ohang */ ARGV_NONE, /* MDOC_Inset */ ARGV_MULTI, /* MDOC_Column */ - ARGV_OPT_SINGLE, /* MDOC_Width */ + ARGV_SINGLE, /* MDOC_Width */ ARGV_NONE, /* MDOC_Compact */ ARGV_NONE, /* MDOC_Std */ ARGV_NONE, /* MDOC_Filled */ @@ -146,7 +144,7 @@ static const enum mdocargt args_Bl[] = { }; static const struct mdocarg mdocargs[MDOC_MAX] = { - { ARGSFL_NONE, NULL }, /* Ap */ + { ARGSFL_DELIM, NULL }, /* Ap */ { ARGSFL_NONE, NULL }, /* Dd */ { ARGSFL_NONE, NULL }, /* Dt */ { ARGSFL_NONE, NULL }, /* Os */ @@ -163,7 +161,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_DELIM, NULL }, /* Ad */ { ARGSFL_DELIM, args_An }, /* An */ { ARGSFL_DELIM, NULL }, /* Ar */ - { ARGSFL_NONE, NULL }, /* Cd */ + { ARGSFL_DELIM, NULL }, /* Cd */ { ARGSFL_DELIM, NULL }, /* Cm */ { ARGSFL_DELIM, NULL }, /* Dv */ { ARGSFL_DELIM, NULL }, /* Er */ @@ -175,7 +173,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_DELIM, NULL }, /* Fn */ { ARGSFL_DELIM, NULL }, /* Ft */ { ARGSFL_DELIM, NULL }, /* Ic */ - { ARGSFL_NONE, NULL }, /* In */ + { ARGSFL_DELIM, NULL }, /* In */ { ARGSFL_DELIM, NULL }, /* Li */ { ARGSFL_NONE, NULL }, /* Nd */ { ARGSFL_DELIM, NULL }, /* Nm */ @@ -243,7 +241,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_DELIM, NULL }, /* Xc */ { ARGSFL_NONE, NULL }, /* Xo */ { ARGSFL_NONE, NULL }, /* Fo */ - { ARGSFL_NONE, NULL }, /* Fc */ + { ARGSFL_DELIM, NULL }, /* Fc */ { ARGSFL_NONE, NULL }, /* Oo */ { ARGSFL_DELIM, NULL }, /* Oc */ { ARGSFL_NONE, args_Bk }, /* Bk */ @@ -252,7 +250,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_NONE, NULL }, /* Hf */ { ARGSFL_NONE, NULL }, /* Fr */ { ARGSFL_NONE, NULL }, /* Ud */ - { ARGSFL_NONE, NULL }, /* Lb */ + { ARGSFL_DELIM, NULL }, /* Lb */ { ARGSFL_NONE, NULL }, /* Lp */ { ARGSFL_DELIM, NULL }, /* Lk */ { ARGSFL_DELIM, NULL }, /* Mt */ @@ -262,7 +260,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_NONE, NULL }, /* %C */ { ARGSFL_NONE, NULL }, /* Es */ { ARGSFL_NONE, NULL }, /* En */ - { ARGSFL_NONE, NULL }, /* Dx */ + { ARGSFL_DELIM, NULL }, /* Dx */ { ARGSFL_NONE, NULL }, /* %Q */ { ARGSFL_NONE, NULL }, /* br */ { ARGSFL_NONE, NULL }, /* sp */ @@ -277,7 +275,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { * one mandatory value, an optional single value, or no value. */ enum margverr -mdoc_argv(struct mdoc *m, int line, enum mdoct tok, +mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok, struct mdoc_arg **v, int *pos, char *buf) { char *p, sv; @@ -344,15 +342,11 @@ mdoc_argv(struct mdoc *m, int line, enum mdoct tok, switch (argvflags[tmp.arg]) { case (ARGV_SINGLE): - if ( ! argv_single(m, line, &tmp, pos, buf)) + if ( ! argv_single(mdoc, line, &tmp, pos, buf)) return(ARGV_ERROR); break; case (ARGV_MULTI): - if ( ! argv_multi(m, line, &tmp, pos, buf)) - return(ARGV_ERROR); - break; - case (ARGV_OPT_SINGLE): - if ( ! argv_opt_single(m, line, &tmp, pos, buf)) + if ( ! argv_multi(mdoc, line, &tmp, pos, buf)) return(ARGV_ERROR); break; case (ARGV_NONE): @@ -413,14 +407,14 @@ argn_free(struct mdoc_arg *p, int iarg) } enum margserr -mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v) +mdoc_zargs(struct mdoc *mdoc, int line, int *pos, char *buf, char **v) { - return(args(m, line, pos, buf, ARGSFL_NONE, v)); + return(args(mdoc, line, pos, buf, ARGSFL_NONE, v)); } enum margserr -mdoc_args(struct mdoc *m, int line, int *pos, +mdoc_args(struct mdoc *mdoc, int line, int *pos, char *buf, enum mdoct tok, char **v) { enum argsflag fl; @@ -429,7 +423,7 @@ mdoc_args(struct mdoc *m, int line, int *pos, fl = mdocargs[tok].flags; if (MDOC_It != tok) - return(args(m, line, pos, buf, fl, v)); + return(args(mdoc, line, pos, buf, fl, v)); /* * We know that we're in an `It', so it's reasonable to expect @@ -438,35 +432,36 @@ mdoc_args(struct mdoc *m, int line, int *pos, * safe fall-back into the default behaviour. */ - for (n = m->last; n; n = n->parent) + for (n = mdoc->last; n; n = n->parent) if (MDOC_Bl == n->tok) if (LIST_column == n->norm->Bl.type) { fl = ARGSFL_TABSEP; break; } - return(args(m, line, pos, buf, fl, v)); + return(args(mdoc, line, pos, buf, fl, v)); } static enum margserr -args(struct mdoc *m, int line, int *pos, +args(struct mdoc *mdoc, int line, int *pos, char *buf, enum argsflag fl, char **v) { char *p, *pp; + int pairs; enum margserr rc; if ('\0' == buf[*pos]) { - if (MDOC_PPHRASE & m->flags) + if (MDOC_PPHRASE & mdoc->flags) return(ARGS_EOLN); /* * If we're not in a partial phrase and the flag for * being a phrase literal is still set, the punctuation * is unterminated. */ - if (MDOC_PHRASELIT & m->flags) - mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE); + if (MDOC_PHRASELIT & mdoc->flags) + mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE); - m->flags &= ~MDOC_PHRASELIT; + mdoc->flags &= ~MDOC_PHRASELIT; return(ARGS_EOLN); } @@ -489,7 +484,7 @@ args(struct mdoc *m, int line, int *pos, pp = NULL; /* Scan ahead to unescaped `Ta'. */ - if ( ! (MDOC_PHRASELIT & m->flags)) + if ( ! (MDOC_PHRASELIT & mdoc->flags)) for (pp = *v; ; pp++) { if (NULL == (pp = strstr(pp, "Ta"))) break; @@ -523,7 +518,7 @@ args(struct mdoc *m, int line, int *pos, /* Whitespace check for eoln case... */ if ('\0' == *p && ' ' == *(p - 1)) - mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE); + mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE); *pos += (int)(p - *v); @@ -541,37 +536,48 @@ args(struct mdoc *m, int line, int *pos, /* Skip ahead. */ ; return(rc); - } + } - /* + /* * 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_PHRASELIT & m->flags || '\"' == buf[*pos]) { - if ( ! (MDOC_PHRASELIT & m->flags)) + if (MDOC_PHRASELIT & mdoc->flags || '\"' == buf[*pos]) { + if ( ! (MDOC_PHRASELIT & mdoc->flags)) *v = &buf[++(*pos)]; - if (MDOC_PPHRASE & m->flags) - m->flags |= MDOC_PHRASELIT; + if (MDOC_PPHRASE & mdoc->flags) + 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 ('\0' == buf[*pos]) { - if (MDOC_PPHRASE & m->flags) + if (MDOC_PPHRASE & mdoc->flags) return(ARGS_QWORD); - mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE); + mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE); return(ARGS_QWORD); } - m->flags &= ~MDOC_PHRASELIT; + mdoc->flags &= ~MDOC_PHRASELIT; buf[(*pos)++] = '\0'; if ('\0' == buf[*pos]) @@ -581,13 +587,13 @@ args(struct mdoc *m, int line, int *pos, (*pos)++; if ('\0' == buf[*pos]) - mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE); + mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE); return(ARGS_QWORD); } p = &buf[*pos]; - *v = mandoc_getarg(m->parse, &p, line, pos); + *v = mandoc_getarg(mdoc->parse, &p, line, pos); return(ARGS_WORD); } @@ -643,7 +649,7 @@ args_checkpunct(const char *buf, int i) } static int -argv_multi(struct mdoc *m, int line, +argv_multi(struct mdoc *mdoc, int line, struct mdoc_argv *v, int *pos, char *buf) { enum margserr ac; @@ -652,7 +658,7 @@ argv_multi(struct mdoc *m, int line, for (v->sz = 0; ; v->sz++) { if ('-' == buf[*pos]) break; - ac = args(m, line, pos, buf, ARGSFL_NONE, &p); + ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_ERROR == ac) return(0); else if (ARGS_EOLN == ac) @@ -669,16 +675,13 @@ argv_multi(struct mdoc *m, int line, } static int -argv_opt_single(struct mdoc *m, int line, +argv_single(struct mdoc *mdoc, int line, struct mdoc_argv *v, int *pos, char *buf) { enum margserr ac; char *p; - if ('-' == buf[*pos]) - return(1); - - ac = args(m, line, pos, buf, ARGSFL_NONE, &p); + ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_ERROR == ac) return(0); if (ARGS_EOLN == ac) @@ -690,27 +693,3 @@ argv_opt_single(struct mdoc *m, int line, return(1); } - -static int -argv_single(struct mdoc *m, int line, - struct mdoc_argv *v, int *pos, char *buf) -{ - int ppos; - enum margserr ac; - char *p; - - ppos = *pos; - - ac = args(m, line, pos, buf, ARGSFL_NONE, &p); - if (ARGS_EOLN == ac) { - mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT); - return(0); - } else if (ARGS_ERROR == ac) - return(0); - - v->sz = 1; - v->value = mandoc_malloc(sizeof(char *)); - v->value[0] = mandoc_strdup(p); - - return(1); -} diff --git a/contrib/mdocml/mdoc_html.c b/contrib/mdocml/mdoc_html.c index 60ea6dc..a7aa722 100644 --- a/contrib/mdocml/mdoc_html.c +++ b/contrib/mdocml/mdoc_html.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_html.c,v 1.182 2011/11/03 20:37:00 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.186 2013/12/24 20:45:27 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -35,7 +35,7 @@ #define INDENT 5 -#define MDOC_ARGS const struct mdoc_meta *m, \ +#define MDOC_ARGS const struct mdoc_meta *meta, \ const struct mdoc_node *n, \ struct html *h @@ -260,10 +260,11 @@ static const char * const lists[LIST_MAX] = { }; void -html_mdoc(void *arg, const struct mdoc *m) +html_mdoc(void *arg, const struct mdoc *mdoc) { - print_mdoc(mdoc_meta(m), mdoc_node(m), (struct html *)arg); + print_mdoc(mdoc_meta(mdoc), mdoc_node(mdoc), + (struct html *)arg); putchar('\n'); } @@ -361,14 +362,14 @@ print_mdoc(MDOC_ARGS) print_gen_decls(h); t = print_otag(h, TAG_HTML, 0, NULL); tt = print_otag(h, TAG_HEAD, 0, NULL); - print_mdoc_head(m, n, h); + print_mdoc_head(meta, n, h); print_tagq(h, tt); print_otag(h, TAG_BODY, 0, NULL); print_otag(h, TAG_DIV, 1, &tag); } else t = print_otag(h, TAG_DIV, 1, &tag); - print_mdoc_nodelist(m, n, h); + print_mdoc_nodelist(meta, n, h); print_tagq(h, t); } @@ -380,10 +381,10 @@ print_mdoc_head(MDOC_ARGS) print_gen_head(h); bufinit(h); - bufcat_fmt(h, "%s(%s)", m->title, m->msec); + bufcat_fmt(h, "%s(%s)", meta->title, meta->msec); - if (m->arch) - bufcat_fmt(h, " (%s)", m->arch); + if (meta->arch) + bufcat_fmt(h, " (%s)", meta->arch); print_otag(h, TAG_TITLE, 0, NULL); print_text(h, h->buf); @@ -394,9 +395,9 @@ static void print_mdoc_nodelist(MDOC_ARGS) { - print_mdoc_node(m, n, h); + print_mdoc_node(meta, n, h); if (n->next) - print_mdoc_nodelist(m, n->next, h); + print_mdoc_nodelist(meta, n->next, h); } @@ -411,7 +412,7 @@ print_mdoc_node(MDOC_ARGS) switch (n->type) { case (MDOC_ROOT): - child = mdoc_root_pre(m, n, h); + child = mdoc_root_pre(meta, n, h); break; case (MDOC_TEXT): /* No tables in this mode... */ @@ -454,36 +455,32 @@ print_mdoc_node(MDOC_ARGS) assert(NULL == h->tblt); if (mdocs[n->tok].pre && ENDBODY_NOT == n->end) - child = (*mdocs[n->tok].pre)(m, n, h); + child = (*mdocs[n->tok].pre)(meta, n, h); break; } if (HTML_KEEP & h->flags) { - if (n->prev && n->prev->line != n->line) { + if (n->prev ? (n->prev->lastline != n->line) : + (n->parent && n->parent->line != n->line)) { h->flags &= ~HTML_KEEP; h->flags |= HTML_PREKEEP; - } else if (NULL == n->prev) { - if (n->parent && n->parent->line != n->line) { - h->flags &= ~HTML_KEEP; - h->flags |= HTML_PREKEEP; - } } } if (child && n->child) - print_mdoc_nodelist(m, n->child, h); + print_mdoc_nodelist(meta, n->child, h); print_stagq(h, t); switch (n->type) { case (MDOC_ROOT): - mdoc_root_post(m, n, h); + mdoc_root_post(meta, n, h); break; case (MDOC_EQN): break; default: if (mdocs[n->tok].post && ENDBODY_NOT == n->end) - (*mdocs[n->tok].post)(m, n, h); + (*mdocs[n->tok].post)(meta, n, h); break; } } @@ -509,13 +506,13 @@ mdoc_root_post(MDOC_ARGS) PAIR_CLASS_INIT(&tag[0], "foot-date"); print_otag(h, TAG_TD, 1, tag); - print_text(h, m->date); + print_text(h, meta->date); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "foot-os"); PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); print_otag(h, TAG_TD, 2, tag); - print_text(h, m->os); + print_text(h, meta->os); print_tagq(h, t); } @@ -528,15 +525,15 @@ mdoc_root_pre(MDOC_ARGS) struct tag *t, *tt; char b[BUFSIZ], title[BUFSIZ]; - strlcpy(b, m->vol, BUFSIZ); + strlcpy(b, meta->vol, BUFSIZ); - if (m->arch) { + if (meta->arch) { strlcat(b, " (", BUFSIZ); - strlcat(b, m->arch, BUFSIZ); + strlcat(b, meta->arch, BUFSIZ); strlcat(b, ")", BUFSIZ); } - snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec); + snprintf(title, BUFSIZ - 1, "%s(%s)", meta->title, meta->msec); PAIR_SUMMARY_INIT(&tag[0], "Document Header"); PAIR_CLASS_INIT(&tag[1], "head"); @@ -689,13 +686,13 @@ mdoc_nm_pre(MDOC_ARGS) synopsis_pre(h, n); PAIR_CLASS_INIT(&tag, "name"); print_otag(h, TAG_B, 1, &tag); - if (NULL == n->child && m->name) - print_text(h, m->name); + if (NULL == n->child && meta->name) + print_text(h, meta->name); return(1); case (MDOC_HEAD): print_otag(h, TAG_TD, 0, NULL); - if (NULL == n->child && m->name) - print_text(h, m->name); + if (NULL == n->child && meta->name) + print_text(h, meta->name); return(1); case (MDOC_BODY): print_otag(h, TAG_TD, 0, NULL); @@ -712,8 +709,8 @@ mdoc_nm_pre(MDOC_ARGS) if (MDOC_TEXT == n->type) len += html_strlen(n->string); - if (0 == len && m->name) - len = html_strlen(m->name); + if (0 == len && meta->name) + len = html_strlen(meta->name); SCALE_HS_INIT(&su, (double)len); bufinit(h); @@ -981,8 +978,6 @@ mdoc_bl_pre(MDOC_ARGS) struct roffsu su; char buf[BUFSIZ]; - bufinit(h); - if (MDOC_BODY == n->type) { if (LIST_column == n->norm->Bl.type) print_otag(h, TAG_TBODY, 0, NULL); @@ -1001,6 +996,7 @@ mdoc_bl_pre(MDOC_ARGS) */ for (i = 0; i < (int)n->norm->Bl.ncols; i++) { + bufinit(h); a2width(n->norm->Bl.cols[i], &su); if (i < (int)n->norm->Bl.ncols - 1) bufcat_su(h, "width", &su); @@ -1014,6 +1010,7 @@ mdoc_bl_pre(MDOC_ARGS) } SCALE_VS_INIT(&su, 0); + bufinit(h); bufcat_su(h, "margin-top", &su); bufcat_su(h, "margin-bottom", &su); PAIR_STYLE_INIT(&tag[0], h); @@ -1225,7 +1222,7 @@ mdoc_bd_pre(MDOC_ARGS) h->flags |= HTML_LITERAL; for (nn = n->child; nn; nn = nn->next) { - print_mdoc_node(m, nn, h); + print_mdoc_node(meta, nn, h); /* * If the printed node flushes its own line, then we * needn't do it here as well. This is hacky, but the @@ -2273,7 +2270,7 @@ mdoc_quote_post(MDOC_ARGS) case (MDOC_So): /* FALLTHROUGH */ case (MDOC_Sq): - print_text(h, "\\(aq"); + print_text(h, "\\(cq"); break; default: abort(); diff --git a/contrib/mdocml/mdoc_macro.c b/contrib/mdocml/mdoc_macro.c index 11d1473..2a63ca9 100644 --- a/contrib/mdocml/mdoc_macro.c +++ b/contrib/mdocml/mdoc_macro.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_macro.c,v 1.115 2012/01/05 00:43:51 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.125 2013/12/24 20:45:27 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -51,8 +51,8 @@ static int in_line(MACRO_PROT_ARGS); static int obsolete(MACRO_PROT_ARGS); static int phrase_ta(MACRO_PROT_ARGS); -static int dword(struct mdoc *, int, int, - const char *, enum mdelim); +static int dword(struct mdoc *, int, int, const char *, + enum mdelim, int); static int append_delims(struct mdoc *, int, int *, char *); static enum mdoct lookup(enum mdoct, const char *); @@ -70,128 +70,147 @@ static int rew_sub(enum mdoc_type, struct mdoc *, enum mdoct, int, int); const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */ { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ { in_line_eoln, MDOC_PROLOGUE }, /* Os */ - { blk_full, MDOC_PARSED }, /* Sh */ - { blk_full, MDOC_PARSED }, /* Ss */ - { in_line_eoln, 0 }, /* Pp */ - { blk_part_imp, MDOC_PARSED }, /* D1 */ - { blk_part_imp, MDOC_PARSED }, /* Dl */ + { 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 }, /* Ed */ + { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ed */ { blk_full, MDOC_EXPLICIT }, /* Bl */ - { blk_exp_close, MDOC_EXPLICIT }, /* El */ - { blk_full, MDOC_PARSED }, /* It */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */ + { 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, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* 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, 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 }, /* 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 }, /* Ic */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */ - { blk_full, 0 }, /* Nd */ - { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ + { 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 */ { obsolete, 0 }, /* Ot */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ { in_line_eoln, 0 }, /* Rv */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */ - { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ + { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */ - { in_line_eoln, 0 }, /* %A */ - { in_line_eoln, 0 }, /* %B */ - { in_line_eoln, 0 }, /* %D */ - { in_line_eoln, 0 }, /* %I */ - { in_line_eoln, 0 }, /* %J */ + { 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, 0 }, /* %O */ + { in_line_eoln, MDOC_JOIN }, /* %O */ { in_line_eoln, 0 }, /* %P */ - { in_line_eoln, 0 }, /* %R */ - { in_line_eoln, 0 }, /* %T */ + { in_line_eoln, MDOC_JOIN }, /* %R */ + { in_line_eoln, MDOC_JOIN }, /* %T */ { in_line_eoln, 0 }, /* %V */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */ + { 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_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */ - { blk_full, MDOC_EXPLICIT }, /* Bf */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */ + { 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_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */ - { blk_exp_close, MDOC_EXPLICIT }, /* Ef */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */ + { 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_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* No */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Ns */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | + MDOC_IGNDELIM | 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_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */ + { 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 }, /* Po */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */ - { blk_exp_close, MDOC_EXPLICIT }, /* Re */ + { 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_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */ + { 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_eoln, 0 }, /* Sm */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */ + { 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 }, /* Ux */ + { 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_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */ + { 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 }, /* Ek */ + { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */ { in_line_eoln, 0 }, /* Bt */ { in_line_eoln, 0 }, /* Hf */ { obsolete, 0 }, /* 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 }, /* Brq */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */ - { in_line_eoln, 0 }, /* %C */ + { 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 */ { obsolete, 0 }, /* Es */ { obsolete, 0 }, /* En */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ - { in_line_eoln, 0 }, /* %Q */ + { in_line_eoln, MDOC_JOIN }, /* %Q */ { in_line_eoln, 0 }, /* br */ { in_line_eoln, 0 }, /* sp */ { in_line_eoln, 0 }, /* %U */ - { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */ + { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */ }; const struct mdoc_macro * const mdoc_macros = __mdoc_macros; @@ -203,22 +222,23 @@ const struct mdoc_macro * const mdoc_macros = __mdoc_macros; * are errors. */ int -mdoc_macroend(struct mdoc *m) +mdoc_macroend(struct mdoc *mdoc) { struct mdoc_node *n; /* Scan for open explicit scopes. */ - n = MDOC_VALID & m->last->flags ? m->last->parent : m->last; + n = MDOC_VALID & mdoc->last->flags ? + mdoc->last->parent : mdoc->last; for ( ; n; n = n->parent) if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags) - mdoc_nmsg(m, n, MANDOCERR_SCOPEEXIT); + mdoc_nmsg(mdoc, n, MANDOCERR_SCOPEEXIT); /* Rewind to the first. */ - return(rew_last(m, m->first)); + return(rew_last(mdoc, mdoc->first)); } @@ -263,8 +283,8 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to) while (mdoc->last != to) { /* * Save the parent here, because we may delete the - * m->last node in the post-validation phase and reset - * it to m->last->parent, causing a step in the closing + * mdoc->last node in the post-validation phase and reset + * it to mdoc->last->parent, causing a step in the closing * out to be lost. */ np = mdoc->last->parent; @@ -460,7 +480,7 @@ rew_elem(struct mdoc *mdoc, enum mdoct tok) */ static int make_pending(struct mdoc_node *broken, enum mdoct tok, - struct mdoc *m, int line, int ppos) + struct mdoc *mdoc, int line, int ppos) { struct mdoc_node *breaker; @@ -515,7 +535,7 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, taker->pending = broken->pending; } broken->pending = breaker; - mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, + mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[broken->tok]); return(1); @@ -530,41 +550,46 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, static int -rew_sub(enum mdoc_type t, struct mdoc *m, +rew_sub(enum mdoc_type t, struct mdoc *mdoc, enum mdoct tok, int line, int ppos) { struct mdoc_node *n; - n = m->last; + n = mdoc->last; while (n) { switch (rew_dohalt(tok, t, n)) { case (REWIND_NONE): return(1); case (REWIND_THIS): + n->lastline = line - + (MDOC_NEWLINE & mdoc->flags && + ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)); break; case (REWIND_FORCE): - mandoc_vmsg(MANDOCERR_SCOPEBROKEN, m->parse, + mandoc_vmsg(MANDOCERR_SCOPEBROKEN, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[n->tok]); /* FALLTHROUGH */ case (REWIND_MORE): + n->lastline = line - + (MDOC_NEWLINE & mdoc->flags ? 1 : 0); n = n->parent; continue; case (REWIND_LATER): - if (make_pending(n, tok, m, line, ppos) || + if (make_pending(n, tok, mdoc, line, ppos) || MDOC_BLOCK != t) return(1); /* FALLTHROUGH */ case (REWIND_ERROR): - mdoc_pmsg(m, line, ppos, MANDOCERR_NOSCOPE); + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_NOSCOPE); return(1); } break; } assert(n); - if ( ! rew_last(m, n)) + if ( ! rew_last(mdoc, n)) return(0); /* @@ -572,10 +597,10 @@ rew_sub(enum mdoc_type t, struct mdoc *m, * Now that the current block ends, close the enclosing block, too. */ while (NULL != (n = n->pending)) { - if ( ! rew_last(m, n)) + if ( ! rew_last(mdoc, n)) return(0); if (MDOC_HEAD == n->type && - ! mdoc_body_alloc(m, n->line, n->pos, n->tok)) + ! mdoc_body_alloc(mdoc, n->line, n->pos, n->tok)) return(0); } @@ -587,18 +612,26 @@ rew_sub(enum mdoc_type t, struct mdoc *m, * Punctuation consists of those tokens found in mdoc_isdelim(). */ static int -dword(struct mdoc *m, int line, - int col, const char *p, enum mdelim d) +dword(struct mdoc *mdoc, int line, int col, const char *p, + enum mdelim d, int may_append) { if (DELIM_MAX == d) d = mdoc_isdelim(p); - if ( ! mdoc_word_alloc(m, line, col, p)) + if (may_append && + ! ((MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF) & mdoc->flags) && + DELIM_NONE == d && MDOC_TEXT == mdoc->last->type && + DELIM_NONE == mdoc_isdelim(mdoc->last->string)) { + mdoc_word_append(mdoc, p); + return(1); + } + + if ( ! mdoc_word_alloc(mdoc, line, col, p)) return(0); if (DELIM_OPEN == d) - m->last->flags |= MDOC_DELIMO; + mdoc->last->flags |= MDOC_DELIMO; /* * Closing delimiters only suppress the preceding space @@ -610,15 +643,16 @@ dword(struct mdoc *m, int line, * and solve this in the code related to `No'! */ - else if (DELIM_CLOSE == d && m->last->prev && - m->last->prev->tok != MDOC_No) - m->last->flags |= MDOC_DELIMC; + else if (DELIM_CLOSE == d && mdoc->last->prev && + mdoc->last->prev->tok != MDOC_No && + mdoc->last->parent->tok != MDOC_Fd) + mdoc->last->flags |= MDOC_DELIMC; return(1); } static int -append_delims(struct mdoc *m, int line, int *pos, char *buf) +append_delims(struct mdoc *mdoc, int line, int *pos, char *buf) { int la; enum margserr ac; @@ -629,14 +663,14 @@ append_delims(struct mdoc *m, int line, int *pos, char *buf) for (;;) { la = *pos; - ac = mdoc_zargs(m, line, pos, buf, &p); + ac = mdoc_zargs(mdoc, line, pos, buf, &p); if (ARGS_ERROR == ac) return(0); else if (ARGS_EOLN == ac) break; - dword(m, line, la, p, DELIM_MAX); + dword(mdoc, line, la, p, DELIM_MAX, 1); /* * If we encounter end-of-sentence symbols, then trigger @@ -650,7 +684,7 @@ append_delims(struct mdoc *m, int line, int *pos, char *buf) * example, `. ;' shouldn't propagate the double-space. */ if (mandoc_eos(p, strlen(p), 0)) - m->last->flags |= MDOC_EOS; + mdoc->last->flags |= MDOC_EOS; } return(1); @@ -672,12 +706,14 @@ blk_exp_close(MACRO_PROT_ARGS) enum mdoct atok, ntok; char *p; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; switch (tok) { case (MDOC_Ec): maxargs = 1; break; + case (MDOC_Ek): + mdoc->flags &= ~MDOC_KEEP; default: maxargs = 0; break; @@ -689,7 +725,7 @@ blk_exp_close(MACRO_PROT_ARGS) */ atok = rew_alt(tok); body = later = NULL; - for (n = m->last; n; n = n->parent) { + for (n = mdoc->last; n; n = n->parent) { if (MDOC_VALID & n->flags) continue; @@ -718,13 +754,13 @@ blk_exp_close(MACRO_PROT_ARGS) * postpone closing out the current block * until the rew_sub() closing out the sub-block. */ - make_pending(later, tok, m, line, ppos); + make_pending(later, tok, mdoc, line, ppos); /* * Mark the place where the formatting - but not * the scope - of the current block ends. */ - if ( ! mdoc_endbody_alloc(m, line, ppos, + if ( ! mdoc_endbody_alloc(mdoc, line, ppos, atok, body, ENDBODY_SPACE)) return(0); break; @@ -738,37 +774,37 @@ blk_exp_close(MACRO_PROT_ARGS) if (later && MDOC_EXPLICIT & mdoc_macros[later->tok].flags) continue; - if (MDOC_CALLABLE & mdoc_macros[n->tok].flags) + if (MDOC_It != n->tok) later = n; } if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { /* FIXME: do this in validate */ if (buf[*pos]) - mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST); + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_ARGSLOST); - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - return(rew_sub(MDOC_BLOCK, m, tok, line, ppos)); + return(rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)); } - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); if (NULL == later && maxargs > 0) - if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok))) + if ( ! mdoc_tail_alloc(mdoc, line, ppos, rew_alt(tok))) return(0); for (flushed = j = 0; ; j++) { lastarg = *pos; if (j == maxargs && ! flushed) { - if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); flushed = 1; } - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -780,27 +816,31 @@ blk_exp_close(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, lastarg, p, DELIM_MAX)) + if ( ! dword(mdoc, line, lastarg, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } if ( ! flushed) { - if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); flushed = 1; } - if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf)) + + mdoc->flags &= ~MDOC_NEWLINE; + + if ( ! mdoc_macro(mdoc, ntok, line, lastarg, pos, buf)) return(0); break; } - if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! flushed && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } @@ -815,7 +855,7 @@ in_line(MACRO_PROT_ARGS) struct mdoc_arg *arg; char *p; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* * Whether we allow ignored elements (those without content, @@ -843,7 +883,7 @@ in_line(MACRO_PROT_ARGS) for (arg = NULL;; ) { la = *pos; - av = mdoc_argv(m, line, tok, &arg, pos, buf); + av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); if (ARGV_WORD == av) { *pos = la; @@ -860,7 +900,7 @@ in_line(MACRO_PROT_ARGS) for (cnt = scope = 0;; ) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -879,23 +919,25 @@ in_line(MACRO_PROT_ARGS) */ if (MDOC_MAX != ntok) { - if (scope && ! rew_elem(m, tok)) + if (scope && ! rew_elem(mdoc, tok)) return(0); if (nc && 0 == cnt) { - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, + ppos, tok, arg)) return(0); - if ( ! rew_last(m, m->last)) + if ( ! rew_last(mdoc, mdoc->last)) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); + mdoc_pmsg(mdoc, line, ppos, + MANDOCERR_MACROEMPTY); } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } /* @@ -917,7 +959,8 @@ in_line(MACRO_PROT_ARGS) */ if (0 == cnt && (nc || MDOC_Li == tok) && DELIM_CLOSE == d && ! scope) { - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, + ppos, tok, arg)) return(0); if (MDOC_Ar == tok || MDOC_Li == tok || MDOC_Fl == tok) @@ -928,11 +971,11 @@ in_line(MACRO_PROT_ARGS) * Close out our scope, if one is open, before * any punctuation. */ - if (scope && ! rew_elem(m, tok)) + if (scope && ! rew_elem(mdoc, tok)) return(0); scope = 0; } else if ( ! scope) { - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); scope = 1; } @@ -940,7 +983,8 @@ in_line(MACRO_PROT_ARGS) if (DELIM_NONE == d) cnt++; - if ( ! dword(m, line, la, p, d)) + if ( ! dword(mdoc, line, la, p, d, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); /* @@ -949,13 +993,13 @@ in_line(MACRO_PROT_ARGS) * having to parse out spaces. */ if (scope && MDOC_Fl == tok) { - if ( ! rew_elem(m, tok)) + if ( ! rew_elem(mdoc, tok)) return(0); scope = 0; } } - if (scope && ! rew_elem(m, tok)) + if (scope && ! rew_elem(mdoc, tok)) return(0); /* @@ -965,18 +1009,18 @@ in_line(MACRO_PROT_ARGS) */ if (nc && 0 == cnt) { - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); - if ( ! rew_last(m, m->last)) + if ( ! rew_last(mdoc, mdoc->last)) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROEMPTY); } if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } @@ -994,14 +1038,14 @@ blk_full(MACRO_PROT_ARGS) enum margverr av; char *p; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* Close out prior implicit scope. */ if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) { - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); } @@ -1016,7 +1060,7 @@ blk_full(MACRO_PROT_ARGS) for (arg = NULL;; ) { la = *pos; - av = mdoc_argv(m, line, tok, &arg, pos, buf); + av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); if (ARGV_WORD == av) { *pos = la; @@ -1032,7 +1076,7 @@ blk_full(MACRO_PROT_ARGS) return(0); } - if ( ! mdoc_block_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg)) return(0); head = body = NULL; @@ -1042,8 +1086,8 @@ blk_full(MACRO_PROT_ARGS) * parsed, even though `It' macros in general are parsed. */ nparsed = MDOC_It == tok && - MDOC_Bl == m->last->parent->tok && - LIST_diag == m->last->parent->norm->Bl.type; + MDOC_Bl == mdoc->last->parent->tok && + LIST_diag == mdoc->last->parent->norm->Bl.type; /* * The `Nd' macro has all arguments in its body: it's a hybrid @@ -1051,15 +1095,18 @@ blk_full(MACRO_PROT_ARGS) */ if (MDOC_Nd == tok) { - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - head = m->last; - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + head = mdoc->last; + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; - } + body = mdoc->last; + } + + if (MDOC_Bk == tok) + mdoc->flags |= MDOC_KEEP; ac = ARGS_ERROR; @@ -1067,7 +1114,7 @@ blk_full(MACRO_PROT_ARGS) la = *pos; /* Initialise last-phrase-type with ARGS_PEND. */ lac = ARGS_ERROR == ac ? ARGS_PEND : ac; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_PUNCT == ac) break; @@ -1085,11 +1132,11 @@ blk_full(MACRO_PROT_ARGS) * reopen our scope if the last parse was a * phrase or partial phrase. */ - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; break; } @@ -1104,7 +1151,7 @@ blk_full(MACRO_PROT_ARGS) ARGS_PPHRASE != ac && ARGS_QWORD != ac && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! dword(m, line, la, p, DELIM_OPEN)) + if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) return(0); continue; } @@ -1112,9 +1159,9 @@ blk_full(MACRO_PROT_ARGS) /* Open a head if one hasn't been opened. */ if (NULL == head) { - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - head = m->last; + head = mdoc->last; } if (ARGS_PHRASE == ac || @@ -1126,14 +1173,14 @@ blk_full(MACRO_PROT_ARGS) */ mtt = body ? MDOC_BODY : MDOC_HEAD; - if ( ! rew_sub(mtt, m, tok, line, ppos)) + if ( ! rew_sub(mtt, mdoc, tok, line, ppos)) return(0); /* Then allocate our body context. */ - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; /* * Process phrases: set whether we're in a @@ -1142,14 +1189,14 @@ blk_full(MACRO_PROT_ARGS) */ if (ARGS_PPHRASE == ac) - m->flags |= MDOC_PPHRASE; + mdoc->flags |= MDOC_PPHRASE; if (ARGS_PEND == ac && ARGS_PPHRASE == lac) - m->flags |= MDOC_PPHRASE; + mdoc->flags |= MDOC_PPHRASE; - if ( ! phrase(m, line, la, buf)) + if ( ! phrase(mdoc, line, la, buf)) return(0); - m->flags &= ~MDOC_PPHRASE; + mdoc->flags &= ~MDOC_PPHRASE; continue; } @@ -1157,23 +1204,24 @@ blk_full(MACRO_PROT_ARGS) MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); break; } if (NULL == head) { - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - head = m->last; + head = mdoc->last; } - if (nl && ! append_delims(m, line, pos, buf)) + if (nl && ! append_delims(mdoc, line, pos, buf)) return(0); /* If we've already opened our body, exit now. */ @@ -1187,7 +1235,7 @@ blk_full(MACRO_PROT_ARGS) * head to body until the rew_sub() call closing out that * sub-block. */ - for (n = m->last; n && n != head; n = n->parent) { + for (n = mdoc->last; n && n != head; n = n->parent) { if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags && ! (MDOC_VALID & n->flags)) { @@ -1198,21 +1246,21 @@ blk_full(MACRO_PROT_ARGS) /* Close out scopes to remain in a consistent state. */ - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); out: - if ( ! (MDOC_FREECOL & m->flags)) + if ( ! (MDOC_FREECOL & mdoc->flags)) return(1); - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); - m->flags &= ~MDOC_FREECOL; + mdoc->flags &= ~MDOC_FREECOL; return(1); } @@ -1228,7 +1276,7 @@ blk_part_imp(MACRO_PROT_ARGS) struct mdoc_node *body; /* saved body context */ struct mdoc_node *n; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* * A macro that spans to the end of the line. This is generally @@ -1239,14 +1287,14 @@ blk_part_imp(MACRO_PROT_ARGS) * or more closing punctuation nodes. */ - if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL)) + if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL)) return(0); - blk = m->last; + blk = mdoc->last; - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); /* @@ -1257,7 +1305,7 @@ blk_part_imp(MACRO_PROT_ARGS) for (body = NULL; ; ) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -1268,26 +1316,27 @@ blk_part_imp(MACRO_PROT_ARGS) if (NULL == body && ARGS_QWORD != ac && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! dword(m, line, la, p, DELIM_OPEN)) + if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) return(0); continue; - } + } if (NULL == body) { - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; } ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); break; } @@ -1295,9 +1344,9 @@ blk_part_imp(MACRO_PROT_ARGS) /* Clean-ups to leave in a consistent state. */ if (NULL == body) { - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; } for (n = body->child; n && n->next; n = n->next) @@ -1324,12 +1373,13 @@ blk_part_imp(MACRO_PROT_ARGS) * postpone closing out the current block * until the rew_sub() call closing out the sub-block. */ - for (n = m->last; n && n != body && n != blk->parent; n = n->parent) { + for (n = mdoc->last; n && n != body && n != blk->parent; + n = n->parent) { if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags && ! (MDOC_VALID & n->flags)) { - make_pending(n, tok, m, line, ppos); - if ( ! mdoc_endbody_alloc(m, line, ppos, + make_pending(n, tok, mdoc, line, ppos); + if ( ! mdoc_endbody_alloc(mdoc, line, ppos, tok, body, ENDBODY_NOSPACE)) return(0); return(1); @@ -1343,22 +1393,29 @@ blk_part_imp(MACRO_PROT_ARGS) * crufty use of `Op' breakage. */ if (n != body) - mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, + mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos, "%s broken", mdoc_macronames[tok]); - if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if (n && ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); /* Standard appending of delimiters. */ - if (nl && ! append_delims(m, line, pos, buf)) + if (nl && ! append_delims(mdoc, line, pos, buf)) return(0); /* Rewind scope, if applicable. */ - if (n && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if (n && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); + /* Move trailing .Ns out of scope. */ + + for (n = body->child; n && n->next; n = n->next) + /* Do nothing. */ ; + if (n && MDOC_Ns == n->tok) + mdoc_node_relink(mdoc, n); + return(1); } @@ -1373,7 +1430,7 @@ blk_part_exp(MACRO_PROT_ARGS) char *p; enum mdoct ntok; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* * The opening of an explicit macro having zero or more leading @@ -1381,12 +1438,12 @@ blk_part_exp(MACRO_PROT_ARGS) * case of `Eo'); and a body that may be empty. */ - if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL)) + if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL)) return(0); for (head = body = NULL; ; ) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -1400,16 +1457,16 @@ blk_part_exp(MACRO_PROT_ARGS) if (NULL == head && ARGS_QWORD != ac && DELIM_OPEN == mdoc_isdelim(p)) { assert(NULL == body); - if ( ! dword(m, line, la, p, DELIM_OPEN)) + if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) return(0); continue; - } + } if (NULL == head) { assert(NULL == body); - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - head = m->last; + head = mdoc->last; } /* @@ -1421,14 +1478,14 @@ blk_part_exp(MACRO_PROT_ARGS) assert(head); /* No check whether it's a macro! */ if (MDOC_Eo == tok) - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, 0)) return(0); - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; if (MDOC_Eo == tok) continue; @@ -1439,12 +1496,13 @@ blk_part_exp(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); break; } @@ -1452,13 +1510,13 @@ blk_part_exp(MACRO_PROT_ARGS) /* Clean-up to leave in a consistent state. */ if (NULL == head) - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); if (NULL == body) { - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); } @@ -1466,7 +1524,7 @@ blk_part_exp(MACRO_PROT_ARGS) if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } @@ -1481,7 +1539,7 @@ in_line_argn(MACRO_PROT_ARGS) char *p; enum mdoct ntok; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* * A line macro that has a fixed number of arguments (maxargs). @@ -1513,7 +1571,7 @@ in_line_argn(MACRO_PROT_ARGS) for (arg = NULL; ; ) { la = *pos; - av = mdoc_argv(m, line, tok, &arg, pos, buf); + av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); if (ARGV_WORD == av) { *pos = la; @@ -1531,7 +1589,7 @@ in_line_argn(MACRO_PROT_ARGS) for (flushed = j = 0; ; ) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -1543,15 +1601,15 @@ in_line_argn(MACRO_PROT_ARGS) if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && ARGS_QWORD != ac && 0 == j && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! dword(m, line, la, p, DELIM_OPEN)) + if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) return(0); continue; } else if (0 == j) - if ( ! mdoc_elem_alloc(m, line, la, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, la, tok, arg)) return(0); if (j == maxargs && ! flushed) { - if ( ! rew_elem(m, tok)) + if ( ! rew_elem(mdoc, tok)) return(0); flushed = 1; } @@ -1559,10 +1617,10 @@ in_line_argn(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX != ntok) { - if ( ! flushed && ! rew_elem(m, tok)) + if ( ! flushed && ! rew_elem(mdoc, tok)) return(0); flushed = 1; - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); j++; break; @@ -1572,26 +1630,27 @@ in_line_argn(MACRO_PROT_ARGS) ARGS_QWORD != ac && ! flushed && DELIM_NONE != mdoc_isdelim(p)) { - if ( ! rew_elem(m, tok)) + if ( ! rew_elem(mdoc, tok)) return(0); flushed = 1; } - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); j++; } - if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg)) + if (0 == j && ! mdoc_elem_alloc(mdoc, line, la, tok, arg)) return(0); /* Close out in a consistent state. */ - if ( ! flushed && ! rew_elem(m, tok)) + if ( ! flushed && ! rew_elem(mdoc, tok)) return(0); if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } @@ -1608,13 +1667,13 @@ in_line_eoln(MACRO_PROT_ARGS) assert( ! (MDOC_PARSED & mdoc_macros[tok].flags)); if (tok == MDOC_Pp) - rew_sub(MDOC_BLOCK, m, MDOC_Nm, line, ppos); + rew_sub(MDOC_BLOCK, mdoc, MDOC_Nm, line, ppos); /* Parse macro arguments. */ for (arg = NULL; ; ) { la = *pos; - av = mdoc_argv(m, line, tok, &arg, pos, buf); + av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); if (ARGV_WORD == av) { *pos = la; @@ -1631,14 +1690,14 @@ in_line_eoln(MACRO_PROT_ARGS) /* Open element scope. */ - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); /* Parse argument terms. */ for (;;) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -1648,19 +1707,20 @@ in_line_eoln(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! rew_elem(m, tok)) + if ( ! rew_elem(mdoc, tok)) return(0); - return(mdoc_macro(m, ntok, line, la, pos, buf)); + return(mdoc_macro(mdoc, ntok, line, la, pos, buf)); } /* Close out (no delimiters). */ - return(rew_elem(m, tok)); + return(rew_elem(mdoc, tok)); } @@ -1670,15 +1730,15 @@ ctx_synopsis(MACRO_PROT_ARGS) { int nl; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* If we're not in the SYNOPSIS, go straight to in-line. */ - if ( ! (MDOC_SYNOPSIS & m->flags)) - return(in_line(m, tok, line, ppos, pos, buf)); + if ( ! (MDOC_SYNOPSIS & mdoc->flags)) + return(in_line(mdoc, tok, line, ppos, pos, buf)); /* If we're a nested call, same place. */ if ( ! nl) - return(in_line(m, tok, line, ppos, pos, buf)); + return(in_line(mdoc, tok, line, ppos, pos, buf)); /* * XXX: this will open a block scope; however, if later we end @@ -1686,9 +1746,9 @@ ctx_synopsis(MACRO_PROT_ARGS) * the formatting. Be careful. */ if (MDOC_Nm == tok) - return(blk_full(m, tok, line, ppos, pos, buf)); + return(blk_full(mdoc, tok, line, ppos, pos, buf)); assert(MDOC_Vt == tok); - return(blk_part_imp(m, tok, line, ppos, pos, buf)); + return(blk_part_imp(mdoc, tok, line, ppos, pos, buf)); } @@ -1697,7 +1757,7 @@ static int obsolete(MACRO_PROT_ARGS) { - mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS); + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROOBS); return(1); } @@ -1708,7 +1768,7 @@ obsolete(MACRO_PROT_ARGS) * macro is encountered. */ static int -phrase(struct mdoc *m, int line, int ppos, char *buf) +phrase(struct mdoc *mdoc, int line, int ppos, char *buf) { int la, pos; enum margserr ac; @@ -1718,7 +1778,7 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) for (pos = ppos; ; ) { la = pos; - ac = mdoc_zargs(m, line, &pos, buf, &p); + ac = mdoc_zargs(mdoc, line, &pos, buf, &p); if (ARGS_ERROR == ac) return(0); @@ -1728,14 +1788,14 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, &pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, &pos, buf)) return(0); - return(append_delims(m, line, &pos, buf)); + return(append_delims(mdoc, line, &pos, buf)); } return(1); @@ -1746,24 +1806,30 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) static int phrase_ta(MACRO_PROT_ARGS) { + struct mdoc_node *n; int la; enum mdoct ntok; enum margserr ac; char *p; - /* - * FIXME: this is overly restrictive: if the `Ta' is unexpected, - * it should simply error out with ARGSLOST. - */ + /* Make sure we are in a column list or ignore this macro. */ + n = mdoc->last; + while (NULL != n && MDOC_Bl != n->tok) + n = n->parent; + if (NULL == n || LIST_column != n->norm->Bl.type) { + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_STRAYTA); + return(1); + } - if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos)) + /* Advance to the next column. */ + if ( ! rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, MDOC_It)) return(0); for (;;) { la = *pos; - ac = mdoc_zargs(m, line, pos, buf, &p); + ac = mdoc_zargs(mdoc, line, pos, buf, &p); if (ARGS_ERROR == ac) return(0); @@ -1773,14 +1839,15 @@ phrase_ta(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } return(1); diff --git a/contrib/mdocml/mdoc_man.c b/contrib/mdocml/mdoc_man.c index 9d7d2ca..6ee8b3a 100644 --- a/contrib/mdocml/mdoc_man.c +++ b/contrib/mdocml/mdoc_man.c @@ -1,6 +1,6 @@ -/* $Id: mdoc_man.c,v 1.9 2011/10/24 21:47:59 schwarze Exp $ */ +/* $Id: mdoc_man.c,v 1.57 2013/12/25 22:00:45 schwarze Exp $ */ /* - * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,22 +18,18 @@ #include "config.h" #endif +#include <assert.h> #include <stdio.h> #include <string.h> #include "mandoc.h" +#include "out.h" #include "man.h" #include "mdoc.h" #include "main.h" -#define DECL_ARGS const struct mdoc_meta *m, \ - const struct mdoc_node *n, \ - struct mman *mm - -struct mman { - int need_space; /* next word needs prior ws */ - int need_nl; /* next word needs prior nl */ -}; +#define DECL_ARGS const struct mdoc_meta *meta, \ + const struct mdoc_node *n struct manact { int (*cond)(DECL_ARGS); /* DON'T run actions */ @@ -45,29 +41,74 @@ struct manact { static int cond_body(DECL_ARGS); static int cond_head(DECL_ARGS); +static void font_push(char); +static void font_pop(void); +static void mid_it(void); +static void post__t(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_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_sp(DECL_ARGS); +static void post_vt(DECL_ARGS); +static int pre__t(DECL_ARGS); +static int pre_an(DECL_ARGS); static int pre_ap(DECL_ARGS); static int pre_bd(DECL_ARGS); +static int pre_bf(DECL_ARGS); +static int pre_bk(DECL_ARGS); +static int pre_bl(DECL_ARGS); static int pre_br(DECL_ARGS); static int pre_bx(DECL_ARGS); static int pre_dl(DECL_ARGS); static int pre_enc(DECL_ARGS); +static int pre_em(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 int pre_ft(DECL_ARGS); +static int pre_in(DECL_ARGS); static int pre_it(DECL_ARGS); +static int pre_lk(DECL_ARGS); +static int pre_li(DECL_ARGS); static int pre_nm(DECL_ARGS); +static int pre_no(DECL_ARGS); static int pre_ns(DECL_ARGS); static int pre_pp(DECL_ARGS); +static int pre_rs(DECL_ARGS); +static int pre_sm(DECL_ARGS); static int pre_sp(DECL_ARGS); static int pre_sect(DECL_ARGS); +static int pre_sy(DECL_ARGS); +static void pre_syn(const struct mdoc_node *); +static int pre_vt(DECL_ARGS); static int pre_ux(DECL_ARGS); static int pre_xr(DECL_ARGS); -static void print_word(struct mman *, const char *); +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 *); +static void print_width(const char *, + const struct mdoc_node *, size_t); +static void print_count(int *); static void print_node(DECL_ARGS); static const struct manact manacts[MDOC_MAX + 1] = { @@ -82,74 +123,74 @@ static const struct manact manacts[MDOC_MAX + 1] = { { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */ { cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */ { NULL, NULL, NULL, NULL, NULL }, /* Ed */ - { NULL, NULL, NULL, NULL, NULL }, /* Bl */ + { cond_body, pre_bl, post_bl, NULL, NULL }, /* Bl */ { NULL, NULL, NULL, NULL, NULL }, /* El */ - { NULL, pre_it, NULL, NULL, NULL }, /* _It */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ad */ - { NULL, NULL, NULL, NULL, NULL }, /* _An */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cd */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Dv */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Er */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Ev */ + { 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_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_enc, post_enc, "The \\fB", "\\fP\nutility exits 0 on success, and >0 if an error occurs." }, /* Ex */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fa */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fd */ - { NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fn */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ft */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ic */ - { NULL, NULL, NULL, NULL, NULL }, /* _In */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Li */ + { 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, NULL, NULL, NULL, NULL }, /* Ot */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Pa */ + { NULL, pre_em, post_font, NULL, NULL }, /* Pa */ { NULL, pre_enc, post_enc, "The \\fB", "\\fP\nfunction returns the value 0 if successful;\n" "otherwise the value -1 is returned and the global\n" "variable \\fIerrno\\fP is set to indicate the error." }, /* Rv */ { NULL, NULL, NULL, NULL, NULL }, /* St */ - { NULL, NULL, NULL, NULL, NULL }, /* _Va */ - { NULL, NULL, NULL, NULL, NULL }, /* _Vt */ + { 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, NULL, NULL, NULL, NULL }, /* _%B */ - { NULL, NULL, post_percent, NULL, NULL }, /* _%D */ - { NULL, NULL, NULL, NULL, NULL }, /* _%I */ - { NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */ - { NULL, NULL, NULL, NULL, NULL }, /* _%N */ - { NULL, NULL, NULL, NULL, NULL }, /* _%O */ - { NULL, NULL, NULL, NULL, NULL }, /* _%P */ - { NULL, NULL, NULL, NULL, NULL }, /* _%R */ - { NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */ - { NULL, NULL, NULL, NULL, NULL }, /* _%V */ + { 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_enc, post_enc, "<", ">" }, /* Ao */ { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */ { NULL, NULL, NULL, NULL, NULL }, /* At */ { NULL, NULL, NULL, NULL, NULL }, /* Bc */ - { NULL, NULL, NULL, NULL, NULL }, /* _Bf */ + { NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */ { cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */ { cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */ { NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */ { NULL, pre_bx, NULL, NULL, NULL }, /* Bx */ { NULL, NULL, NULL, NULL, NULL }, /* Db */ { NULL, NULL, NULL, NULL, NULL }, /* Dc */ - { cond_body, pre_enc, post_enc, "``", "''" }, /* Do */ - { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ec */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ef */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Em */ - { NULL, NULL, NULL, NULL, NULL }, /* _Eo */ + { 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 */ + { NULL, NULL, post_eo, NULL, NULL }, /* Eo */ { NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ms */ - { NULL, NULL, NULL, NULL, NULL }, /* No */ + { NULL, pre_sy, post_font, NULL, NULL }, /* Ms */ + { NULL, pre_no, NULL, NULL, NULL }, /* No */ { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */ { NULL, pre_ux, NULL, "NetBSD", NULL }, /* Nx */ { NULL, pre_ux, NULL, "OpenBSD", NULL }, /* Ox */ @@ -158,91 +199,324 @@ static const struct manact manacts[MDOC_MAX + 1] = { { 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, "`", "'" }, /* Ql */ + { 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_pp, NULL, NULL, NULL }, /* Rs */ + { cond_body, pre_rs, NULL, NULL, NULL }, /* Rs */ { NULL, NULL, NULL, NULL, NULL }, /* Sc */ - { cond_body, pre_enc, post_enc, "`", "'" }, /* So */ - { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */ - { NULL, NULL, NULL, NULL, NULL }, /* _Sm */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Sx */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Sy */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Tn */ + { 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, pre_ux, NULL, "UNIX", NULL }, /* Ux */ - { NULL, NULL, NULL, NULL, NULL }, /* _Xc */ - { NULL, NULL, NULL, NULL, NULL }, /* _Xo */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fo */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fc */ + { 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, NULL, NULL, NULL, NULL }, /* _Bk */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ek */ + { NULL, pre_bk, post_bk, NULL, NULL }, /* Bk */ + { NULL, NULL, NULL, NULL, NULL }, /* Ek */ { NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */ { NULL, NULL, NULL, NULL, NULL }, /* Hf */ { NULL, NULL, NULL, NULL, NULL }, /* Fr */ { NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */ - { NULL, NULL, NULL, NULL, NULL }, /* _Lb */ + { NULL, NULL, post_lb, NULL, NULL }, /* Lb */ { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */ - { NULL, NULL, NULL, NULL, NULL }, /* _Lk */ - { NULL, NULL, NULL, NULL, NULL }, /* _Mt */ + { 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, NULL, NULL, NULL }, /* _%C */ - { NULL, NULL, NULL, NULL, NULL }, /* _Es */ - { NULL, NULL, NULL, NULL, NULL }, /* _En */ + { NULL, NULL, post_percent, NULL, NULL }, /* %C */ + { NULL, NULL, NULL, NULL, NULL }, /* Es */ + { NULL, NULL, NULL, NULL, NULL }, /* En */ { NULL, pre_ux, NULL, "DragonFly", NULL }, /* Dx */ - { NULL, NULL, NULL, NULL, NULL }, /* _%Q */ + { NULL, NULL, post_percent, NULL, NULL }, /* %Q */ { NULL, pre_br, NULL, NULL, NULL }, /* br */ { NULL, pre_sp, post_sp, NULL, NULL }, /* sp */ - { NULL, NULL, NULL, NULL, NULL }, /* _%U */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ta */ + { NULL, NULL, post_percent, NULL, NULL }, /* %U */ + { NULL, NULL, NULL, NULL, NULL }, /* Ta */ { NULL, NULL, NULL, NULL, NULL }, /* ROOT */ }; +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 size_t 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 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(struct mman *mm, const char *s) +print_word(const char *s) { - if (mm->need_nl) { + if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) { /* * If we need a newline, print it now and start afresh. */ - putchar('\n'); - mm->need_space = 0; - mm->need_nl = 0; - } else if (mm->need_space && '\0' != s[0]) + 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 before - * (1) a nonzero length word; - * (2) a word that is non-punctuation; and - * (3) if punctuation, non-terminating puncutation. + * 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 (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) + 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. */ - mm->need_space = - ('(' != s[0] && '[' != s[0]) || '\0' != s[1]; + 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("\\~"); + printf("\\ "); break; case (ASCII_HYPH): putchar('-'); 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_br; + 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) +{ + char buf[24]; + struct roffsu su; + size_t sz; + + print_line(".RS", MMAN_Bk_susp); + + /* Convert v into a number (of characters). */ + if (NULL == v || '\0' == *v || 0 == strcmp(v, "left")) + sz = 0; + else if (0 == strcmp(v, "indent")) + sz = 6; + else if (0 == strcmp(v, "indent-two")) + sz = 12; + else if (a2roffsu(v, &su, SCALE_MAX)) { + 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; + } + } else + sz = strlen(v); + + /* + * We are inside an enclosing list. + * Add the two indentations. + */ + if (Bl_stack_len) + sz += Bl_stack[Bl_stack_len - 1]; + + snprintf(buf, sizeof(buf), "%zun", sz); + print_word(buf); + outflags |= MMAN_nl; +} + +/* + * Set up the indentation for a list item; used from pre_it(). + */ +void +print_width(const char *v, const struct mdoc_node *child, size_t defsz) +{ + char buf[24]; + struct roffsu su; + size_t sz, chsz; + int numeric, remain; + + numeric = 1; + remain = 0; + + /* Convert v into a number (of characters). */ + if (NULL == v) + sz = defsz; + else if (a2roffsu(v, &su, SCALE_MAX)) { + if (SCALE_EN == su.unit) + sz = su.scale; + else { + sz = 0; + numeric = 0; + } + } else + sz = strlen(v); + + /* XXX Rough estimation, might have multiple parts. */ + chsz = (NULL != child && MDOC_TEXT == child->type) ? + strlen(child->string) : 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 (defsz && chsz > sz) + print_block(".HP", 0); + else { + print_block(".TP", 0); + remain = sz + 2; } + if (numeric) { + snprintf(buf, sizeof(buf), "%zun", sz + 2); + print_word(buf); + } else + print_word(v); + TPremain = remain; +} + +void +print_count(int *count) +{ + char buf[12]; + + snprintf(buf, sizeof(buf), "%d.", ++*count); + print_word(buf); } void @@ -261,37 +535,42 @@ man_man(void *arg, const struct man *man) void man_mdoc(void *arg, const struct mdoc *mdoc) { - const struct mdoc_meta *m; + const struct mdoc_meta *meta; const struct mdoc_node *n; - struct mman mm; - m = mdoc_meta(mdoc); + meta = mdoc_meta(mdoc); n = mdoc_node(mdoc); - printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", - m->title, m->msec, m->date, m->os, m->vol); + printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", + meta->title, meta->msec, meta->date, + meta->os, meta->vol); - memset(&mm, 0, sizeof(struct mman)); + /* Disable hyphenation and if nroff, disable justification. */ + printf(".nh\n.if n .ad l"); - mm.need_nl = 1; - print_node(m, n, &mm); + outflags = MMAN_nl | MMAN_Sm; + if (0 == fontqueue.size) { + fontqueue.size = 8; + fontqueue.head = fontqueue.tail = mandoc_malloc(8); + *fontqueue.tail = 'R'; + } + print_node(meta, n); putchar('\n'); } static void print_node(DECL_ARGS) { - const struct mdoc_node *prev, *sub; + const struct mdoc_node *sub; const struct manact *act; int cond, do_sub; - + /* * Break the line if we were parsed subsequent the current node. * This makes the page structure be more consistent. */ - prev = n->prev ? n->prev : n->parent; - if (prev && prev->line < n->line) - mm->need_nl = 1; + if (MMAN_spc & outflags && MDOC_LINE & n->flags) + outflags |= MMAN_nl; act = NULL; cond = 0; @@ -302,21 +581,22 @@ print_node(DECL_ARGS) * Make sure that we don't happen to start with a * control character at the start of a line. */ - if (mm->need_nl && ('.' == *n->string || + if (MMAN_nl & outflags && ('.' == *n->string || '\'' == *n->string)) { - print_word(mm, "\\&"); - mm->need_space = 0; + print_word(""); + printf("\\&"); + outflags &= ~MMAN_spc; } - print_word(mm, n->string); + print_word(n->string); } else { /* * Conditionally run the pre-node action handler for a * node. */ act = manacts + n->tok; - cond = NULL == act->cond || (*act->cond)(m, n, mm); + cond = NULL == act->cond || (*act->cond)(meta, n); if (cond && act->pre) - do_sub = (*act->pre)(m, n, mm); + do_sub = (*act->pre)(meta, n); } /* @@ -326,13 +606,13 @@ print_node(DECL_ARGS) */ if (do_sub) for (sub = n->child; sub; sub = sub->next) - print_node(m, sub, mm); + print_node(meta, sub); /* * Lastly, conditionally run the post-node handler. */ if (cond && act->post) - (*act->post)(m, n, mm); + (*act->post)(meta, n); } static int @@ -349,10 +629,6 @@ cond_body(DECL_ARGS) return(MDOC_BODY == n->type); } -/* - * Output a font encoding before a node, e.g., \fR. - * This obviously has no trailing space. - */ static int pre_enc(DECL_ARGS) { @@ -361,14 +637,11 @@ pre_enc(DECL_ARGS) prefix = manacts[n->tok].prefix; if (NULL == prefix) return(1); - print_word(mm, prefix); - mm->need_space = 0; + print_word(prefix); + outflags &= ~MMAN_spc; return(1); } -/* - * Output a font encoding subsequent a node, e.g., \fP. - */ static void post_enc(DECL_ARGS) { @@ -377,28 +650,62 @@ post_enc(DECL_ARGS) suffix = manacts[n->tok].suffix; if (NULL == suffix) return; - mm->need_space = 0; - print_word(mm, suffix); + outflags &= ~MMAN_spc; + print_word(suffix); +} + +static void +post_font(DECL_ARGS) +{ + + font_pop(); } -/* - * Used in listings (percent = %A, e.g.). - * FIXME: this is incomplete. - * It doesn't print a nice ", and" for lists. - */ static void post_percent(DECL_ARGS) { - post_enc(m, n, mm); - if (n->next) - print_word(mm, ","); - else { - print_word(mm, "."); - mm->need_nl = 1; + if (pre_em == manacts[n->tok].pre) + font_pop(); + if (n->next) { + print_word(","); + if (n->prev && n->prev->tok == n->tok && + n->next->tok == n->tok) + print_word("and"); + } else { + print_word("."); + outflags |= MMAN_nl; } } +static int +pre__t(DECL_ARGS) +{ + + if (n->parent && MDOC_Rs == n->parent->tok && + n->parent->norm->Rs.quote_T) { + print_word(""); + putchar('\"'); + outflags &= ~MMAN_spc; + } else + font_push('I'); + return(1); +} + +static void +post__t(DECL_ARGS) +{ + + if (n->parent && MDOC_Rs == n->parent->tok && + n->parent->norm->Rs.quote_T) { + outflags &= ~MMAN_spc; + print_word(""); + putchar('\"'); + } else + font_pop(); + post_percent(meta, n); +} + /* * Print before a section header. */ @@ -406,12 +713,13 @@ static int pre_sect(DECL_ARGS) { - if (MDOC_HEAD != n->type) - return(1); - mm->need_nl = 1; - print_word(mm, manacts[n->tok].prefix); - print_word(mm, "\""); - mm->need_space = 0; + if (MDOC_HEAD == n->type) { + outflags |= MMAN_sp; + print_block(manacts[n->tok].prefix, 0); + print_word(""); + putchar('\"'); + outflags &= ~MMAN_spc; + } return(1); } @@ -424,18 +732,84 @@ post_sect(DECL_ARGS) if (MDOC_HEAD != n->type) return; - mm->need_space = 0; - print_word(mm, "\""); - mm->need_nl = 1; + 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 mdoc_node *n) +{ + + if (NULL == n->prev || ! (MDOC_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): + /* FALLTHROUGH */ + case (MDOC_Fn): + /* FALLTHROUGH */ + case (MDOC_Fo): + /* FALLTHROUGH */ + case (MDOC_In): + /* FALLTHROUGH */ + 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) { - mm->need_space = 0; - print_word(mm, "'"); - mm->need_space = 0; + outflags &= ~MMAN_spc; + print_word("'"); + outflags &= ~MMAN_spc; return(0); } @@ -443,12 +817,14 @@ 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) { - mm->need_nl = 1; - print_word(mm, ".nf"); - } - mm->need_nl = 1; + 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); return(1); } @@ -456,21 +832,143 @@ static void post_bd(DECL_ARGS) { + /* Close out this display. */ + print_line(".RE", MMAN_nl); if (DISP_unfilled == n->norm->Bd.type || - DISP_literal == n->norm->Bd.type) { - mm->need_nl = 1; - print_word(mm, ".fi"); + DISP_literal == n->norm->Bd.type) + print_line(".fi", MMAN_nl); + + /* Maybe we are inside an enclosing list? */ + if (NULL != n->parent->next) + mid_it(); +} + +static int +pre_bf(DECL_ARGS) +{ + + switch (n->type) { + case (MDOC_BLOCK): + return(1); + case (MDOC_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; } - mm->need_nl = 1; + return(1); +} + +static void +post_bf(DECL_ARGS) +{ + + if (MDOC_BODY == n->type) + font_pop(); +} + +static int +pre_bk(DECL_ARGS) +{ + + switch (n->type) { + case (MDOC_BLOCK): + return(1); + case (MDOC_BODY): + outflags |= MMAN_Bk; + return(1); + default: + return(0); + } +} + +static void +post_bk(DECL_ARGS) +{ + + if (MDOC_BODY == n->type) + outflags &= ~MMAN_Bk; +} + +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); + 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); + } + + 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): + 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 int pre_br(DECL_ARGS) { - mm->need_nl = 1; - print_word(mm, ".br"); - mm->need_nl = 1; + outflags |= MMAN_br; return(0); } @@ -480,17 +978,17 @@ pre_bx(DECL_ARGS) n = n->child; if (n) { - print_word(mm, n->string); - mm->need_space = 0; + print_word(n->string); + outflags &= ~MMAN_spc; n = n->next; } - print_word(mm, "BSD"); + print_word("BSD"); if (NULL == n) return(0); - mm->need_space = 0; - print_word(mm, "-"); - mm->need_space = 0; - print_word(mm, n->string); + outflags &= ~MMAN_spc; + print_word("-"); + outflags &= ~MMAN_spc; + print_word(n->string); return(0); } @@ -498,9 +996,7 @@ static int pre_dl(DECL_ARGS) { - mm->need_nl = 1; - print_word(mm, ".RS 6n"); - mm->need_nl = 1; + print_offs("6n"); return(1); } @@ -508,9 +1004,213 @@ static void post_dl(DECL_ARGS) { - mm->need_nl = 1; - print_word(mm, ".RE"); - mm->need_nl = 1; + 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 void +post_eo(DECL_ARGS) +{ + + if (MDOC_HEAD == n->type || MDOC_BODY == n->type) + 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 || MDOC_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("\\-"); + outflags &= ~MMAN_spc; + return(1); +} + +static void +post_fl(DECL_ARGS) +{ + + font_pop(); + if (0 == n->nchild && NULL != n->next && + n->next->line == n->line) + outflags &= ~MMAN_spc; +} + +static int +pre_fn(DECL_ARGS) +{ + + pre_syn(n); + + n = n->child; + if (NULL == n) + return(0); + + if (MDOC_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 (MDOC_SYNPRETTY & n->flags) { + print_word(";"); + outflags |= MMAN_PP; + } +} + +static int +pre_fo(DECL_ARGS) +{ + + switch (n->type) { + case (MDOC_BLOCK): + pre_syn(n); + break; + case (MDOC_HEAD): + if (MDOC_SYNPRETTY & n->flags) + print_block(".HP 4n", MMAN_nl); + font_push('B'); + break; + case (MDOC_BODY): + outflags &= ~MMAN_spc; + print_word("("); + outflags &= ~MMAN_spc; + break; + default: + break; + } + return(1); +} + +static void +post_fo(DECL_ARGS) +{ + + switch (n->type) { + case (MDOC_HEAD): + font_pop(); + break; + case (MDOC_BODY): + post_fn(meta, n); + break; + default: + break; + } +} + +static int +pre_ft(DECL_ARGS) +{ + + pre_syn(n); + font_push('I'); + return(1); +} + +static int +pre_in(DECL_ARGS) +{ + + if (MDOC_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 (MDOC_SYNPRETTY & n->flags) { + outflags &= ~MMAN_spc; + print_word(">"); + font_pop(); + outflags |= MMAN_br; + } else { + font_pop(); + outflags &= ~MMAN_spc; + print_word(">"); + } } static int @@ -518,36 +1218,221 @@ pre_it(DECL_ARGS) { const struct mdoc_node *bln; - if (MDOC_HEAD == n->type) { - mm->need_nl = 1; - print_word(mm, ".TP"); - bln = n->parent->parent->prev; + switch (n->type) { + case (MDOC_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): + /* FALLTHROUGH */ + case (LIST_diag): + /* FALLTHROUGH */ + case (LIST_ohang): + if (bln->norm->Bl.type == LIST_diag) + print_line(".B \"", 0); + else + print_line(".R \"", 0); + outflags &= ~MMAN_spc; + return(1); case (LIST_bullet): - print_word(mm, "4n"); - mm->need_nl = 1; - print_word(mm, "\\fBo\\fP"); + /* FALLTHROUGH */ + case (LIST_dash): + /* FALLTHROUGH */ + case (LIST_hyphen): + print_width(bln->norm->Bl.width, NULL, 0); + TPremain = 0; + outflags |= MMAN_nl; + font_push('B'); + if (LIST_bullet == bln->norm->Bl.type) + print_word("o"); + else + print_word("-"); + font_pop(); + break; + case (LIST_enum): + print_width(bln->norm->Bl.width, NULL, 0); + TPremain = 0; + outflags |= MMAN_nl; + print_count(&bln->norm->Bl.count); + break; + case (LIST_hang): + print_width(bln->norm->Bl.width, n->child, 6); + TPremain = 0; + break; + case (LIST_tag): + print_width(bln->norm->Bl.width, n->child, 0); + putchar('\n'); + outflags &= ~MMAN_spc; + return(1); + default: + return(1); + } + outflags |= MMAN_nl; + 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); + snprintf(buf, sizeof(buf), "%zun", 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 mdoc_node *bln; + + bln = n->parent->parent; + + switch (n->type) { + case (MDOC_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 (MDOC_BODY): + switch (bln->norm->Bl.type) { + case (LIST_bullet): + /* FALLTHROUGH */ + case (LIST_dash): + /* FALLTHROUGH */ + case (LIST_hyphen): + /* FALLTHROUGH */ + case (LIST_enum): + /* FALLTHROUGH */ + case (LIST_hang): + /* FALLTHROUGH */ + 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: - if (bln->norm->Bl.width) - print_word(mm, bln->norm->Bl.width); break; } - mm->need_nl = 1; + 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 mdoc_node *link, *descr; + + if (NULL == (link = n->child)) + return(0); + + if (NULL != (descr = link->next)) { + font_push('I'); + while (NULL != descr) { + print_word(descr->string); + descr = descr->next; + } + print_word(":"); + font_pop(); + } + + font_push('B'); + print_word(link->string); + font_pop(); + return(0); +} + +static int +pre_li(DECL_ARGS) +{ + + font_push('R'); return(1); } static int pre_nm(DECL_ARGS) { + char *name; + if (MDOC_BLOCK == n->type) { + outflags |= MMAN_Bk; + pre_syn(n); + } if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) return(1); - print_word(mm, "\\fB"); - mm->need_space = 0; + name = n->child ? n->child->string : meta->name; + if (NULL == name) + return(0); + if (MDOC_HEAD == n->type) { + if (NULL == n->parent->prev) + outflags |= MMAN_sp; + print_block(".HP", 0); + printf(" %zun", strlen(name) + 1); + outflags |= MMAN_nl; + } + font_push('B'); if (NULL == n->child) - print_word(mm, m->name); + print_word(meta->name); return(1); } @@ -555,17 +1440,33 @@ static void post_nm(DECL_ARGS) { - if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) - return; - mm->need_space = 0; - print_word(mm, "\\fP"); + switch (n->type) { + case (MDOC_BLOCK): + outflags &= ~MMAN_Bk; + break; + case (MDOC_HEAD): + /* FALLTHROUGH */ + case (MDOC_ELEM): + font_pop(); + break; + default: + break; + } +} + +static int +pre_no(DECL_ARGS) +{ + + outflags |= MMAN_spc_force; + return(1); } static int pre_ns(DECL_ARGS) { - mm->need_space = 0; + outflags &= ~MMAN_spc; return(0); } @@ -573,28 +1474,52 @@ static void post_pf(DECL_ARGS) { - mm->need_space = 0; + outflags &= ~MMAN_spc; } static int pre_pp(DECL_ARGS) { - mm->need_nl = 1; - if (MDOC_It == n->parent->tok) - print_word(mm, ".sp"); - else - print_word(mm, ".PP"); - mm->need_nl = 1; + 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_sm(DECL_ARGS) +{ + + assert(n->child && MDOC_TEXT == n->child->type); + if (0 == strcmp("on", n->child->string)) + outflags |= MMAN_Sm | MMAN_spc; + else + outflags &= ~MMAN_Sm; + return(0); +} + +static int pre_sp(DECL_ARGS) { - mm->need_nl = 1; - print_word(mm, ".sp"); + if (MMAN_PP & outflags) { + outflags &= ~MMAN_PP; + print_line(".PP", 0); + } else + print_line(".sp", 0); return(1); } @@ -602,7 +1527,43 @@ static void post_sp(DECL_ARGS) { - mm->need_nl = 1; + outflags |= MMAN_nl; +} + +static int +pre_sy(DECL_ARGS) +{ + + font_push('B'); + return(1); +} + +static int +pre_vt(DECL_ARGS) +{ + + if (MDOC_SYNPRETTY & n->flags) { + switch (n->type) { + case (MDOC_BLOCK): + pre_syn(n); + return(1); + case (MDOC_BODY): + break; + default: + return(0); + } + } + font_push('I'); + return(1); +} + +static void +post_vt(DECL_ARGS) +{ + + if (MDOC_SYNPRETTY & n->flags && MDOC_BODY != n->type) + return; + font_pop(); } static int @@ -612,14 +1573,14 @@ pre_xr(DECL_ARGS) n = n->child; if (NULL == n) return(0); - print_node(m, n, mm); + print_node(meta, n); n = n->next; if (NULL == n) return(0); - mm->need_space = 0; - print_word(mm, "("); - print_node(m, n, mm); - print_word(mm, ")"); + outflags &= ~MMAN_spc; + print_word("("); + print_node(meta, n); + print_word(")"); return(0); } @@ -627,11 +1588,11 @@ static int pre_ux(DECL_ARGS) { - print_word(mm, manacts[n->tok].prefix); + print_word(manacts[n->tok].prefix); if (NULL == n->child) return(0); - mm->need_space = 0; - print_word(mm, "\\~"); - mm->need_space = 0; + outflags &= ~MMAN_spc; + print_word("\\ "); + outflags &= ~MMAN_spc; return(1); } diff --git a/contrib/mdocml/mdoc_term.c b/contrib/mdocml/mdoc_term.c index 53335664..268fcae 100644 --- a/contrib/mdocml/mdoc_term.c +++ b/contrib/mdocml/mdoc_term.c @@ -1,7 +1,8 @@ -/* $Id: mdoc_term.c,v 1.238 2011/11/13 13:15:14 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.258 2013/12/25 21:24:12 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -41,8 +42,8 @@ struct termpair { #define DECL_ARGS struct termp *p, \ struct termpair *pair, \ - const struct mdoc_meta *m, \ - const struct mdoc_node *n + const struct mdoc_meta *meta, \ + struct mdoc_node *n struct termact { int (*pre)(DECL_ARGS); @@ -69,7 +70,7 @@ static void termp_an_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_d1_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); @@ -100,7 +101,6 @@ 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_igndelim_pre(DECL_ARGS); static int termp_in_pre(DECL_ARGS); static int termp_it_pre(DECL_ARGS); static int termp_li_pre(DECL_ARGS); @@ -129,8 +129,8 @@ static const struct termact termacts[MDOC_MAX] = { { termp_sh_pre, termp_sh_post }, /* Sh */ { termp_ss_pre, termp_ss_post }, /* Ss */ { termp_sp_pre, NULL }, /* Pp */ - { termp_d1_pre, termp_d1_post }, /* D1 */ - { termp_d1_pre, termp_d1_post }, /* Dl */ + { 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 */ @@ -146,7 +146,7 @@ static const struct termact termacts[MDOC_MAX] = { { NULL, NULL }, /* Ev */ { termp_ex_pre, NULL }, /* Ex */ { termp_fa_pre, NULL }, /* Fa */ - { termp_fd_pre, NULL }, /* Fd */ + { termp_fd_pre, termp_fd_post }, /* Fd */ { termp_fl_pre, NULL }, /* Fl */ { termp_fn_pre, NULL }, /* Fn */ { termp_ft_pre, NULL }, /* Ft */ @@ -194,12 +194,12 @@ static const struct termact termacts[MDOC_MAX] = { { termp_quote_pre, termp_quote_post }, /* Eo */ { termp_xx_pre, NULL }, /* Fx */ { termp_bold_pre, NULL }, /* Ms */ - { termp_igndelim_pre, NULL }, /* No */ + { NULL, NULL }, /* No */ { termp_ns_pre, NULL }, /* Ns */ { termp_xx_pre, NULL }, /* Nx */ { termp_xx_pre, NULL }, /* Ox */ { NULL, NULL }, /* Pc */ - { termp_igndelim_pre, termp_pf_post }, /* Pf */ + { NULL, termp_pf_post }, /* Pf */ { termp_quote_pre, termp_quote_post }, /* Po */ { termp_quote_pre, termp_quote_post }, /* Pq */ { NULL, NULL }, /* Qc */ @@ -242,7 +242,7 @@ static const struct termact termacts[MDOC_MAX] = { { NULL, termp____post }, /* %Q */ { termp_sp_pre, NULL }, /* br */ { termp_sp_pre, NULL }, /* sp */ - { termp_under_pre, termp____post }, /* %U */ + { NULL, termp____post }, /* %U */ { NULL, NULL }, /* Ta */ }; @@ -251,7 +251,7 @@ void terminal_mdoc(void *arg, const struct mdoc *mdoc) { const struct mdoc_node *n; - const struct mdoc_meta *m; + const struct mdoc_meta *meta; struct termp *p; p = (struct termp *)arg; @@ -267,12 +267,12 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc) p->symtab = mchars_alloc(); n = mdoc_node(mdoc); - m = mdoc_meta(mdoc); + meta = mdoc_meta(mdoc); - term_begin(p, print_mdoc_head, print_mdoc_foot, m); + term_begin(p, print_mdoc_head, print_mdoc_foot, meta); if (n->child) - print_mdoc_nodelist(p, NULL, m, n->child); + print_mdoc_nodelist(p, NULL, meta, n->child); term_end(p); } @@ -282,9 +282,9 @@ static void print_mdoc_nodelist(DECL_ARGS) { - print_mdoc_node(p, pair, m, n); + print_mdoc_node(p, pair, meta, n); if (n->next) - print_mdoc_nodelist(p, pair, m, n->next); + print_mdoc_nodelist(p, pair, meta, n->next); } @@ -293,14 +293,13 @@ static void print_mdoc_node(DECL_ARGS) { int chld; - const void *font; struct termpair npair; size_t offset, rmargin; chld = 1; offset = p->offset; rmargin = p->rmargin; - font = term_fontq(p); + n->prev_font = term_fontq(p); memset(&npair, 0, sizeof(struct termpair)); npair.ppair = pair; @@ -308,34 +307,17 @@ print_mdoc_node(DECL_ARGS) /* * Keeps only work until the end of a line. If a keep was * invoked in a prior line, revert it to PREKEEP. - * - * Also let SYNPRETTY sections behave as if they were wrapped - * in a `Bk' block. */ - if (TERMP_KEEP & p->flags || MDOC_SYNPRETTY & n->flags) { - if (n->prev && n->prev->line != n->line) { + if (TERMP_KEEP & p->flags) { + if (n->prev ? (n->prev->lastline != n->line) : + (n->parent && n->parent->line != n->line)) { p->flags &= ~TERMP_KEEP; p->flags |= TERMP_PREKEEP; - } else if (NULL == n->prev) { - if (n->parent && n->parent->line != n->line) { - p->flags &= ~TERMP_KEEP; - p->flags |= TERMP_PREKEEP; - } } } /* - * Since SYNPRETTY sections aren't "turned off" with `Ek', - * we have to intuit whether we should disable formatting. - */ - - if ( ! (MDOC_SYNPRETTY & n->flags) && - ((n->prev && MDOC_SYNPRETTY & n->prev->flags) || - (n->parent && MDOC_SYNPRETTY & n->parent->flags))) - p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); - - /* * After the keep flags have been set up, we may now * produce output. Note that some pre-handlers do so. */ @@ -359,14 +341,15 @@ print_mdoc_node(DECL_ARGS) default: if (termacts[n->tok].pre && ENDBODY_NOT == n->end) chld = (*termacts[n->tok].pre) - (p, &npair, m, n); + (p, &npair, meta, n); break; } if (chld && n->child) - print_mdoc_nodelist(p, &npair, m, n->child); + print_mdoc_nodelist(p, &npair, meta, n->child); - term_fontpopq(p, font); + term_fontpopq(p, + (ENDBODY_NOT == n->end ? n : n->pending)->prev_font); switch (n->type) { case (MDOC_TEXT): @@ -378,7 +361,7 @@ print_mdoc_node(DECL_ARGS) default: if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags) break; - (void)(*termacts[n->tok].post)(p, &npair, m, n); + (void)(*termacts[n->tok].post)(p, &npair, meta, n); /* * Explicit end tokens not only call the post @@ -409,9 +392,9 @@ print_mdoc_node(DECL_ARGS) static void print_mdoc_foot(struct termp *p, const void *arg) { - const struct mdoc_meta *m; + const struct mdoc_meta *meta; - m = (const struct mdoc_meta *)arg; + meta = (const struct mdoc_meta *)arg; term_fontrepl(p, TERMFONT_NONE); @@ -427,25 +410,27 @@ print_mdoc_foot(struct termp *p, const void *arg) p->offset = 0; p->rmargin = (p->maxrmargin - - term_strlen(p, m->date) + term_len(p, 1)) / 2; + term_strlen(p, meta->date) + term_len(p, 1)) / 2; + p->trailspace = 1; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; - term_word(p, m->os); + term_word(p, meta->os); term_flushln(p); p->offset = p->rmargin; - p->rmargin = p->maxrmargin - term_strlen(p, m->os); + p->rmargin = p->maxrmargin - term_strlen(p, meta->os); p->flags |= TERMP_NOSPACE; - term_word(p, m->date); + term_word(p, meta->date); term_flushln(p); p->offset = p->rmargin; p->rmargin = p->maxrmargin; + p->trailspace = 0; p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; - term_word(p, m->os); + term_word(p, meta->os); term_flushln(p); p->offset = 0; @@ -459,9 +444,9 @@ print_mdoc_head(struct termp *p, const void *arg) { char buf[BUFSIZ], title[BUFSIZ]; size_t buflen, titlen; - const struct mdoc_meta *m; + const struct mdoc_meta *meta; - m = (const struct mdoc_meta *)arg; + meta = (const struct mdoc_meta *)arg; /* * The header is strange. It has three components, which are @@ -479,20 +464,21 @@ print_mdoc_head(struct termp *p, const void *arg) p->offset = 0; p->rmargin = p->maxrmargin; - assert(m->vol); - strlcpy(buf, m->vol, BUFSIZ); + assert(meta->vol); + strlcpy(buf, meta->vol, BUFSIZ); buflen = term_strlen(p, buf); - if (m->arch) { + if (meta->arch) { strlcat(buf, " (", BUFSIZ); - strlcat(buf, m->arch, BUFSIZ); + strlcat(buf, meta->arch, BUFSIZ); strlcat(buf, ")", BUFSIZ); } - snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec); + snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec); titlen = term_strlen(p, title); p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; + p->trailspace = 1; p->offset = 0; p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ? (p->maxrmargin - @@ -511,6 +497,7 @@ print_mdoc_head(struct termp *p, const void *arg) term_flushln(p); p->flags &= ~TERMP_NOBREAK; + p->trailspace = 0; if (p->rmargin + titlen <= p->maxrmargin) { p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; @@ -727,12 +714,10 @@ termp_it_pre(DECL_ARGS) case (LIST_dash): /* FALLTHROUGH */ case (LIST_hyphen): - if (width < term_len(p, 4)) - width = term_len(p, 4); - break; + /* FALLTHROUGH */ case (LIST_enum): - if (width < term_len(p, 5)) - width = term_len(p, 5); + if (width < term_len(p, 2)) + width = term_len(p, 2); break; case (LIST_hang): if (0 == width) @@ -787,20 +772,26 @@ termp_it_pre(DECL_ARGS) */ switch (type) { + case (LIST_enum): + /* + * Weird special case. + * Very narrow enum lists actually hang. + */ + if (width == term_len(p, 2)) + p->flags |= TERMP_HANG; + /* FALLTHROUGH */ case (LIST_bullet): /* FALLTHROUGH */ case (LIST_dash): /* FALLTHROUGH */ - case (LIST_enum): - /* FALLTHROUGH */ case (LIST_hyphen): - if (MDOC_HEAD == n->type) - p->flags |= TERMP_NOBREAK; + if (MDOC_HEAD != n->type) + break; + p->flags |= TERMP_NOBREAK; + p->trailspace = 1; break; case (LIST_hang): - if (MDOC_HEAD == n->type) - p->flags |= TERMP_NOBREAK; - else + if (MDOC_HEAD != n->type) break; /* @@ -812,16 +803,18 @@ termp_it_pre(DECL_ARGS) if (n->next->child && (MDOC_Bl == n->next->child->tok || MDOC_Bd == n->next->child->tok)) - p->flags &= ~TERMP_NOBREAK; - else - p->flags |= TERMP_HANG; + break; + + p->flags |= TERMP_NOBREAK | TERMP_HANG; + p->trailspace = 1; break; case (LIST_tag): - if (MDOC_HEAD == n->type) - p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE; - if (MDOC_HEAD != n->type) break; + + p->flags |= TERMP_NOBREAK; + p->trailspace = 2; + if (NULL == n->next || NULL == n->next->child) p->flags |= TERMP_DANGLE; break; @@ -829,15 +822,20 @@ termp_it_pre(DECL_ARGS) if (MDOC_HEAD == n->type) break; - if (NULL == n->next) + if (NULL == n->next) { p->flags &= ~TERMP_NOBREAK; - else + p->trailspace = 0; + } else { p->flags |= TERMP_NOBREAK; + p->trailspace = 1; + } break; case (LIST_diag): - if (MDOC_HEAD == n->type) - p->flags |= TERMP_NOBREAK; + if (MDOC_HEAD != n->type) + break; + p->flags |= TERMP_NOBREAK; + p->trailspace = 1; break; default: break; @@ -989,8 +987,8 @@ termp_it_post(DECL_ARGS) p->flags &= ~TERMP_DANGLE; p->flags &= ~TERMP_NOBREAK; - p->flags &= ~TERMP_TWOSPACE; p->flags &= ~TERMP_HANG; + p->trailspace = 0; } @@ -999,22 +997,25 @@ static int termp_nm_pre(DECL_ARGS) { - if (MDOC_BLOCK == n->type) + if (MDOC_BLOCK == n->type) { + p->flags |= TERMP_PREKEEP; return(1); + } if (MDOC_BODY == n->type) { if (NULL == n->child) return(0); p->flags |= TERMP_NOSPACE; p->offset += term_len(p, 1) + - (NULL == n->prev->child ? term_strlen(p, m->name) : + (NULL == n->prev->child ? + term_strlen(p, meta->name) : MDOC_TEXT == n->prev->child->type ? - term_strlen(p, n->prev->child->string) : + term_strlen(p, n->prev->child->string) : term_len(p, 5)); return(1); } - if (NULL == n->child && NULL == m->name) + if (NULL == n->child && NULL == meta->name) return(0); if (MDOC_HEAD == n->type) @@ -1022,9 +1023,10 @@ termp_nm_pre(DECL_ARGS) if (MDOC_HEAD == n->type && n->next->child) { p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; + p->trailspace = 1; p->rmargin = p->offset + term_len(p, 1); if (NULL == n->child) { - p->rmargin += term_strlen(p, m->name); + p->rmargin += term_strlen(p, meta->name); } else if (MDOC_TEXT == n->child->type) { p->rmargin += term_strlen(p, n->child->string); if (n->child->next) @@ -1037,7 +1039,7 @@ termp_nm_pre(DECL_ARGS) term_fontpush(p, TERMFONT_BOLD); if (NULL == n->child) - term_word(p, m->name); + term_word(p, meta->name); return(1); } @@ -1047,9 +1049,12 @@ static void termp_nm_post(DECL_ARGS) { - if (MDOC_HEAD == n->type && n->next->child) { + if (MDOC_BLOCK == n->type) { + p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); + } else if (MDOC_HEAD == n->type && n->next->child) { term_flushln(p); p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); + p->trailspace = 0; } else if (MDOC_BODY == n->type && n->child) term_flushln(p); } @@ -1375,14 +1380,14 @@ termp_vt_pre(DECL_ARGS) if (MDOC_ELEM == n->type) { synopsis_pre(p, n); - return(termp_under_pre(p, pair, m, n)); + return(termp_under_pre(p, pair, meta, n)); } else if (MDOC_BLOCK == n->type) { synopsis_pre(p, n); return(1); } else if (MDOC_HEAD == n->type) return(0); - return(termp_under_pre(p, pair, m, n)); + return(termp_under_pre(p, pair, meta, n)); } @@ -1402,7 +1407,16 @@ termp_fd_pre(DECL_ARGS) { synopsis_pre(p, n); - return(termp_bold_pre(p, pair, m, n)); + return(termp_bold_pre(p, pair, meta, n)); +} + + +/* ARGSUSED */ +static void +termp_fd_post(DECL_ARGS) +{ + + term_newln(p); } @@ -1425,6 +1439,8 @@ termp_sh_pre(DECL_ARGS) break; case (MDOC_BODY): p->offset = term_len(p, p->defindent); + if (SEC_AUTHORS == n->sec) + p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT); break; default: break; @@ -1498,17 +1514,6 @@ termp_d1_pre(DECL_ARGS) /* ARGSUSED */ -static void -termp_d1_post(DECL_ARGS) -{ - - if (MDOC_BLOCK != n->type) - return; - term_newln(p); -} - - -/* ARGSUSED */ static int termp_ft_pre(DECL_ARGS) { @@ -1524,6 +1529,7 @@ termp_ft_pre(DECL_ARGS) static int termp_fn_pre(DECL_ARGS) { + size_t rmargin = 0; int pretty; pretty = MDOC_SYNPRETTY & n->flags; @@ -1533,11 +1539,24 @@ termp_fn_pre(DECL_ARGS) if (NULL == (n = n->child)) return(0); + if (pretty) { + rmargin = p->rmargin; + p->rmargin = p->offset + term_len(p, 4); + p->flags |= TERMP_NOBREAK | TERMP_HANG; + } + assert(MDOC_TEXT == n->type); term_fontpush(p, TERMFONT_BOLD); term_word(p, n->string); term_fontpop(p); + if (pretty) { + term_flushln(p); + p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); + p->offset = p->rmargin; + p->rmargin = rmargin; + } + p->flags |= TERMP_NOSPACE; term_word(p, "("); p->flags |= TERMP_NOSPACE; @@ -1545,6 +1564,8 @@ termp_fn_pre(DECL_ARGS) for (n = n->next; n; n = n->next) { assert(MDOC_TEXT == n->type); term_fontpush(p, TERMFONT_UNDER); + if (pretty) + p->flags |= TERMP_NBRWORD; term_word(p, n->string); term_fontpop(p); @@ -1560,6 +1581,7 @@ termp_fn_pre(DECL_ARGS) if (pretty) { p->flags |= TERMP_NOSPACE; term_word(p, ";"); + term_flushln(p); } return(0); @@ -1579,20 +1601,16 @@ termp_fa_pre(DECL_ARGS) 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) { + if (nn->next || (n->next && n->next->tok == MDOC_Fa)) { p->flags |= TERMP_NOSPACE; term_word(p, ","); } } - if (n->child && n->next && n->next->tok == MDOC_Fa) { - p->flags |= TERMP_NOSPACE; - term_word(p, ","); - } - return(0); } @@ -1602,7 +1620,7 @@ static int termp_bd_pre(DECL_ARGS) { size_t tabwidth, rm, rmax; - const struct mdoc_node *nn; + struct mdoc_node *nn; if (MDOC_BLOCK == n->type) { print_bvspace(p, n, n); @@ -1634,7 +1652,7 @@ termp_bd_pre(DECL_ARGS) p->rmargin = p->maxrmargin = TERM_MAXMARGIN; for (nn = n->child; nn; nn = nn->next) { - print_mdoc_node(p, pair, m, nn); + print_mdoc_node(p, pair, meta, nn); /* * If the printed node flushes its own line, then we * needn't do it here as well. This is hacky, but the @@ -1751,7 +1769,8 @@ termp_xx_pre(DECL_ARGS) pp = "UNIX"; break; default: - break; + abort(); + /* NOTREACHED */ } term_word(p, pp); @@ -1766,16 +1785,6 @@ termp_xx_pre(DECL_ARGS) /* ARGSUSED */ -static int -termp_igndelim_pre(DECL_ARGS) -{ - - p->flags |= TERMP_IGNDELIM; - return(1); -} - - -/* ARGSUSED */ static void termp_pf_post(DECL_ARGS) { @@ -1923,7 +1932,7 @@ termp_quote_pre(DECL_ARGS) case (MDOC_Do): /* FALLTHROUGH */ case (MDOC_Dq): - term_word(p, "``"); + term_word(p, "\\(lq"); break; case (MDOC_Eo): break; @@ -1944,7 +1953,7 @@ termp_quote_pre(DECL_ARGS) case (MDOC_So): /* FALLTHROUGH */ case (MDOC_Sq): - term_word(p, "`"); + term_word(p, "\\(oq"); break; default: abort(); @@ -1989,7 +1998,7 @@ termp_quote_post(DECL_ARGS) case (MDOC_Do): /* FALLTHROUGH */ case (MDOC_Dq): - term_word(p, "''"); + term_word(p, "\\(rq"); break; case (MDOC_Eo): break; @@ -2010,7 +2019,7 @@ termp_quote_post(DECL_ARGS) case (MDOC_So): /* FALLTHROUGH */ case (MDOC_Sq): - term_word(p, "'"); + term_word(p, "\\(cq"); break; default: abort(); @@ -2023,16 +2032,31 @@ termp_quote_post(DECL_ARGS) static int termp_fo_pre(DECL_ARGS) { + size_t rmargin = 0; + int pretty; + + pretty = MDOC_SYNPRETTY & n->flags; if (MDOC_BLOCK == n->type) { synopsis_pre(p, n); return(1); } else if (MDOC_BODY == n->type) { + if (pretty) { + rmargin = p->rmargin; + p->rmargin = p->offset + term_len(p, 4); + p->flags |= TERMP_NOBREAK | TERMP_HANG; + } p->flags |= TERMP_NOSPACE; term_word(p, "("); p->flags |= TERMP_NOSPACE; + if (pretty) { + term_flushln(p); + p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); + p->offset = p->rmargin; + p->rmargin = rmargin; + } return(1); - } + } if (NULL == n->child) return(0); @@ -2060,6 +2084,7 @@ termp_fo_post(DECL_ARGS) if (MDOC_SYNPRETTY & n->flags) { p->flags |= TERMP_NOSPACE; term_word(p, ";"); + term_flushln(p); } } @@ -2071,7 +2096,7 @@ termp_bf_pre(DECL_ARGS) if (MDOC_HEAD == n->type) return(0); - else if (MDOC_BLOCK != n->type) + else if (MDOC_BODY != n->type) return(1); if (FONT_Em == n->norm->Bf.font) @@ -2157,25 +2182,24 @@ termp_li_pre(DECL_ARGS) static int termp_lk_pre(DECL_ARGS) { - const struct mdoc_node *nn, *sv; - - term_fontpush(p, TERMFONT_UNDER); + const struct mdoc_node *link, *descr; - nn = sv = n->child; - - if (NULL == nn || NULL == nn->next) - return(1); - - for (nn = nn->next; nn; nn = nn->next) - term_word(p, nn->string); - - term_fontpop(p); + if (NULL == (link = n->child)) + return(0); - p->flags |= TERMP_NOSPACE; - term_word(p, ":"); + if (NULL != (descr = link->next)) { + term_fontpush(p, TERMFONT_UNDER); + while (NULL != descr) { + term_word(p, descr->string); + descr = descr->next; + } + p->flags |= TERMP_NOSPACE; + term_word(p, ":"); + term_fontpop(p); + } term_fontpush(p, TERMFONT_BOLD); - term_word(p, sv->string); + term_word(p, link->string); term_fontpop(p); return(0); @@ -2225,9 +2249,9 @@ termp__t_post(DECL_ARGS) */ if (n->parent && MDOC_Rs == n->parent->tok && n->parent->norm->Rs.quote_T) - termp_quote_post(p, pair, m, n); + termp_quote_post(p, pair, meta, n); - termp____post(p, pair, m, n); + termp____post(p, pair, meta, n); } /* ARGSUSED */ @@ -2241,7 +2265,7 @@ termp__t_pre(DECL_ARGS) */ if (n->parent && MDOC_Rs == n->parent->tok && n->parent->norm->Rs.quote_T) - return(termp_quote_pre(p, pair, m, n)); + return(termp_quote_pre(p, pair, meta, n)); term_fontpush(p, TERMFONT_UNDER); return(1); diff --git a/contrib/mdocml/mdoc_validate.c b/contrib/mdocml/mdoc_validate.c index 0a1fce2..588c070 100644 --- a/contrib/mdocml/mdoc_validate.c +++ b/contrib/mdocml/mdoc_validate.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_validate.c,v 1.182 2012/03/23 05:50:25 kristaps Exp $ */ +/* $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,7 +19,7 @@ #include "config.h" #endif -#ifndef OSNAME +#ifndef OSNAME #include <sys/utsname.h> #endif @@ -97,17 +97,19 @@ static int post_bl_block_width(POST_ARGS); static int post_bl_block_tag(POST_ARGS); static int post_bl_head(POST_ARGS); static int post_bx(POST_ARGS); +static int post_defaults(POST_ARGS); static int post_dd(POST_ARGS); static int post_dt(POST_ARGS); -static int post_defaults(POST_ARGS); -static int post_literal(POST_ARGS); static int post_eoln(POST_ARGS); +static int post_hyph(POST_ARGS); +static int post_ignpar(POST_ARGS); static int post_it(POST_ARGS); static int post_lb(POST_ARGS); +static int post_literal(POST_ARGS); static int post_nm(POST_ARGS); static int post_ns(POST_ARGS); static int post_os(POST_ARGS); -static int post_ignpar(POST_ARGS); +static int post_par(POST_ARGS); static int post_prol(POST_ARGS); static int post_root(POST_ARGS); static int post_rs(POST_ARGS); @@ -141,27 +143,30 @@ static v_post posts_bx[] = { post_bx, NULL }; static v_post posts_bool[] = { ebool, NULL }; static v_post posts_eoln[] = { post_eoln, NULL }; static v_post posts_defaults[] = { post_defaults, NULL }; +static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL }; static v_post posts_dd[] = { post_dd, post_prol, NULL }; static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL }; static v_post posts_dt[] = { post_dt, post_prol, NULL }; static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; +static v_post posts_hyph[] = { post_hyph, NULL }; +static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL }; static v_post posts_it[] = { post_it, NULL }; static v_post posts_lb[] = { post_lb, NULL }; -static v_post posts_nd[] = { berr_ge1, NULL }; +static v_post posts_nd[] = { berr_ge1, post_hyph, NULL }; static v_post posts_nm[] = { post_nm, NULL }; static v_post posts_notext[] = { ewarn_eq0, NULL }; static v_post posts_ns[] = { post_ns, NULL }; static v_post posts_os[] = { post_os, post_prol, NULL }; +static v_post posts_pp[] = { post_par, ewarn_eq0, NULL }; static v_post posts_rs[] = { post_rs, NULL }; -static v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL }; -static v_post posts_sp[] = { ewarn_le1, NULL }; -static v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL }; +static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL }; +static v_post posts_sp[] = { post_par, ewarn_le1, NULL }; +static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL }; static v_post posts_st[] = { post_st, NULL }; static v_post posts_std[] = { post_std, NULL }; static v_post posts_text[] = { ewarn_ge1, NULL }; static v_post posts_text1[] = { ewarn_eq1, NULL }; static v_post posts_vt[] = { post_vt, NULL }; -static v_post posts_wline[] = { bwarn_ge1, NULL }; static v_pre pres_an[] = { pre_an, NULL }; static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; static v_pre pres_bl[] = { pre_bl, pre_par, NULL }; @@ -169,8 +174,6 @@ static v_pre pres_d1[] = { pre_display, NULL }; static v_pre pres_dl[] = { pre_literal, pre_display, NULL }; static v_pre pres_dd[] = { pre_dd, NULL }; static v_pre pres_dt[] = { pre_dt, NULL }; -static v_pre pres_er[] = { NULL, NULL }; -static v_pre pres_fd[] = { NULL, NULL }; static v_pre pres_it[] = { pre_it, pre_par, NULL }; static v_pre pres_os[] = { pre_os, NULL }; static v_pre pres_pp[] = { pre_par, NULL }; @@ -185,8 +188,8 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { pres_os, posts_os }, /* Os */ { pres_sh, posts_sh }, /* Sh */ { pres_ss, posts_ss }, /* Ss */ - { pres_pp, posts_notext }, /* Pp */ - { pres_d1, posts_wline }, /* D1 */ + { pres_pp, posts_pp }, /* Pp */ + { pres_d1, posts_d1 }, /* D1 */ { pres_dl, posts_dl }, /* Dl */ { pres_bd, posts_bd }, /* Bd */ { NULL, NULL }, /* Ed */ @@ -199,11 +202,11 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Cd */ { NULL, NULL }, /* Cm */ { NULL, NULL }, /* Dv */ - { pres_er, NULL }, /* Er */ + { NULL, NULL }, /* Er */ { NULL, NULL }, /* Ev */ { pres_std, posts_std }, /* Ex */ { NULL, NULL }, /* Fa */ - { pres_fd, posts_text }, /* Fd */ + { NULL, posts_text }, /* Fd */ { NULL, NULL }, /* Fl */ { NULL, NULL }, /* Fn */ { NULL, NULL }, /* Ft */ @@ -221,15 +224,15 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_vt }, /* Vt */ { NULL, posts_text }, /* Xr */ { NULL, posts_text }, /* %A */ - { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ + { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */ { NULL, posts_text }, /* %D */ { NULL, posts_text }, /* %I */ { NULL, posts_text }, /* %J */ - { NULL, posts_text }, /* %N */ - { NULL, posts_text }, /* %O */ + { NULL, posts_hyphtext }, /* %N */ + { NULL, posts_hyphtext }, /* %O */ { NULL, posts_text }, /* %P */ - { NULL, posts_text }, /* %R */ - { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */ + { NULL, posts_hyphtext }, /* %R */ + { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */ { NULL, posts_text }, /* %V */ { NULL, NULL }, /* Ac */ { NULL, NULL }, /* Ao */ @@ -269,7 +272,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* So */ { NULL, NULL }, /* Sq */ { NULL, posts_bool }, /* Sm */ - { NULL, NULL }, /* Sx */ + { NULL, posts_hyph }, /* Sx */ { NULL, NULL }, /* Sy */ { NULL, NULL }, /* Tn */ { NULL, NULL }, /* Ux */ @@ -286,7 +289,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Fr */ { NULL, posts_eoln }, /* Ud */ { NULL, posts_lb }, /* Lb */ - { NULL, posts_notext }, /* Lp */ + { pres_pp, posts_pp }, /* Lp */ { NULL, NULL }, /* Lk */ { NULL, posts_defaults }, /* Mt */ { NULL, NULL }, /* Brq */ @@ -297,8 +300,8 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* En */ { NULL, NULL }, /* Dx */ { NULL, posts_text }, /* %Q */ - { NULL, posts_notext }, /* br */ - { pres_pp, posts_sp }, /* sp */ + { NULL, posts_pp }, /* br */ + { NULL, posts_sp }, /* sp */ { NULL, posts_text1 }, /* %U */ { NULL, NULL }, /* Ta */ }; @@ -314,12 +317,12 @@ static const enum mdoct rsord[RSORD_MAX] = { MDOC__R, MDOC__N, MDOC__V, + MDOC__U, MDOC__P, MDOC__Q, - MDOC__D, - MDOC__O, MDOC__C, - MDOC__U + MDOC__D, + MDOC__O }; static const char * const secnames[SEC__MAX] = { @@ -414,29 +417,29 @@ mdoc_valid_post(struct mdoc *mdoc) } static int -check_count(struct mdoc *m, enum mdoc_type type, +check_count(struct mdoc *mdoc, enum mdoc_type type, enum check_lvl lvl, enum check_ineq ineq, int val) { const char *p; enum mandocerr t; - if (m->last->type != type) + if (mdoc->last->type != type) return(1); switch (ineq) { case (CHECK_LT): p = "less than "; - if (m->last->nchild < val) + if (mdoc->last->nchild < val) return(1); break; case (CHECK_GT): p = "more than "; - if (m->last->nchild > val) + if (mdoc->last->nchild > val) return(1); break; case (CHECK_EQ): p = ""; - if (val == m->last->nchild) + if (val == mdoc->last->nchild) return(1); break; default: @@ -445,9 +448,9 @@ check_count(struct mdoc *m, enum mdoc_type type, } t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; - mandoc_vmsg(t, m->parse, m->last->line, m->last->pos, + mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos, "want %s%d children (have %d)", - p, val, m->last->nchild); + p, val, mdoc->last->nchild); return(1); } @@ -513,7 +516,7 @@ hwarn_le1(POST_ARGS) } static void -check_args(struct mdoc *m, struct mdoc_node *n) +check_args(struct mdoc *mdoc, struct mdoc_node *n) { int i; @@ -522,34 +525,34 @@ check_args(struct mdoc *m, struct mdoc_node *n) assert(n->args->argc); for (i = 0; i < (int)n->args->argc; i++) - check_argv(m, n, &n->args->argv[i]); + check_argv(mdoc, n, &n->args->argv[i]); } static void -check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v) +check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) { int i; for (i = 0; i < (int)v->sz; i++) - check_text(m, v->line, v->pos, v->value[i]); + check_text(mdoc, v->line, v->pos, v->value[i]); /* FIXME: move to post_std(). */ if (MDOC_Std == v->arg) - if ( ! (v->sz || m->meta.name)) - mdoc_nmsg(m, n, MANDOCERR_NONAME); + if ( ! (v->sz || mdoc->meta.name)) + mdoc_nmsg(mdoc, n, MANDOCERR_NONAME); } static void -check_text(struct mdoc *m, int ln, int pos, char *p) +check_text(struct mdoc *mdoc, int ln, int pos, char *p) { char *cp; - if (MDOC_LITERAL & m->flags) + if (MDOC_LITERAL & mdoc->flags) return; for (cp = p; NULL != (p = strchr(p, '\t')); p++) - mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); + mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); } static int @@ -733,14 +736,14 @@ pre_bl(PRE_ARGS) /* * 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. + * 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) - break; - mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); + if (NULL == n->norm->Bl.width) + mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); break; case (LIST_column): /* FALLTHROUGH */ @@ -754,6 +757,18 @@ pre_bl(PRE_ARGS) if (n->norm->Bl.width) mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); break; + case (LIST_bullet): + /* FALLTHROUGH */ + case (LIST_dash): + /* FALLTHROUGH */ + case (LIST_hyphen): + if (NULL == n->norm->Bl.width) + n->norm->Bl.width = "2n"; + break; + case (LIST_enum): + if (NULL == n->norm->Bl.width) + n->norm->Bl.width = "3n"; + break; default: break; } @@ -874,8 +889,6 @@ pre_sh(PRE_ARGS) if (MDOC_BLOCK != n->type) return(1); - - roff_regunset(mdoc->roff, REG_nS); return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); } @@ -1111,24 +1124,29 @@ post_nm(POST_ARGS) char buf[BUFSIZ]; int c; - /* If no child specified, make sure we have the meta name. */ - - if (NULL == mdoc->last->child && NULL == mdoc->meta.name) { - mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); - return(1); - } else if (mdoc->meta.name) + if (NULL != mdoc->meta.name) return(1); - /* If no meta name, set it from the child. */ + /* Try to use our children for setting the meta name. */ - buf[0] = '\0'; - if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { + if (NULL != mdoc->last->child) { + buf[0] = '\0'; + c = concat(buf, mdoc->last->child, BUFSIZ); + } else + c = 0; + + switch (c) { + case (-1): mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); return(0); + case (0): + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); + mdoc->meta.name = mandoc_strdup("UNKNOWN"); + break; + default: + mdoc->meta.name = mandoc_strdup(buf); + break; } - - assert(c); - mdoc->meta.name = mandoc_strdup(buf); return(1); } @@ -1334,7 +1352,7 @@ post_it(POST_ARGS) static int post_bl_block(POST_ARGS) { - struct mdoc_node *n; + struct mdoc_node *n, *ni, *nc; /* * These are fairly complicated, so we've broken them into two @@ -1350,13 +1368,42 @@ post_bl_block(POST_ARGS) NULL == n->norm->Bl.width) { if ( ! post_bl_block_tag(mdoc)) return(0); + assert(n->norm->Bl.width); } else if (NULL != n->norm->Bl.width) { if ( ! post_bl_block_width(mdoc)) return(0); - } else - return(1); + assert(n->norm->Bl.width); + } - assert(n->norm->Bl.width); + for (ni = n->body->child; ni; ni = ni->next) { + if (NULL == ni->body) + continue; + nc = ni->body->last; + while (NULL != nc) { + switch (nc->tok) { + case (MDOC_Pp): + /* FALLTHROUGH */ + case (MDOC_Lp): + /* FALLTHROUGH */ + case (MDOC_br): + break; + default: + nc = NULL; + continue; + } + if (NULL == ni->next) { + mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR); + if ( ! mdoc_node_relink(mdoc, nc)) + return(0); + } else if (0 == n->norm->Bl.comp && + LIST_column != n->norm->Bl.type) { + mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR); + mdoc_node_delete(mdoc, nc); + } else + break; + nc = ni->body->last; + } + } return(1); } @@ -1544,32 +1591,71 @@ post_bl_head(POST_ARGS) static int post_bl(POST_ARGS) { - struct mdoc_node *n; + struct mdoc_node *nparent, *nprev; /* of the Bl block */ + struct mdoc_node *nblock, *nbody; /* of the Bl */ + struct mdoc_node *nchild, *nnext; /* of the Bl body */ - if (MDOC_HEAD == mdoc->last->type) - return(post_bl_head(mdoc)); - if (MDOC_BLOCK == mdoc->last->type) + nbody = mdoc->last; + switch (nbody->type) { + case (MDOC_BLOCK): return(post_bl_block(mdoc)); - if (MDOC_BODY != mdoc->last->type) + case (MDOC_HEAD): + return(post_bl_head(mdoc)); + case (MDOC_BODY): + break; + default: return(1); + } - for (n = mdoc->last->child; n; n = n->next) { - switch (n->tok) { - case (MDOC_Lp): - /* FALLTHROUGH */ - case (MDOC_Pp): - mdoc_nmsg(mdoc, n, MANDOCERR_CHILD); - /* FALLTHROUGH */ - case (MDOC_It): - /* FALLTHROUGH */ - case (MDOC_Sm): + nchild = nbody->child; + while (NULL != nchild) { + if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) { + nchild = nchild->next; continue; - default: - break; } - mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD); - return(0); + mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD); + + /* + * Move the node out of the Bl block. + * First, collect all required node pointers. + */ + + nblock = nbody->parent; + nprev = nblock->prev; + nparent = nblock->parent; + nnext = nchild->next; + + /* + * Unlink this child. + */ + + assert(NULL == nchild->prev); + if (0 == --nbody->nchild) { + nbody->child = NULL; + nbody->last = NULL; + assert(NULL == nnext); + } else { + nbody->child = nnext; + nnext->prev = NULL; + } + + /* + * Relink this child. + */ + + nchild->parent = nparent; + nchild->prev = nprev; + nchild->next = nblock; + + nblock->prev = nchild; + nparent->nchild++; + if (NULL == nprev) + nparent->child = nchild; + else + nprev->next = nchild; + + nchild = nnext; } return(1); @@ -1588,10 +1674,16 @@ ebool(struct mdoc *mdoc) assert(MDOC_TEXT == mdoc->last->child->type); - if (0 == strcmp(mdoc->last->child->string, "on")) + if (0 == strcmp(mdoc->last->child->string, "on")) { + if (MDOC_Sm == mdoc->last->tok) + mdoc->flags &= ~MDOC_SMOFF; return(1); - if (0 == strcmp(mdoc->last->child->string, "off")) + } + if (0 == strcmp(mdoc->last->child->string, "off")) { + if (MDOC_Sm == mdoc->last->tok) + mdoc->flags |= MDOC_SMOFF; return(1); + } mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL); return(1); @@ -1771,6 +1863,47 @@ post_rs(POST_ARGS) return(1); } +/* + * For some arguments of some macros, + * convert all breakable hyphens into ASCII_HYPH. + */ +static int +post_hyph(POST_ARGS) +{ + struct mdoc_node *n, *nch; + char *cp; + + n = mdoc->last; + switch (n->type) { + case (MDOC_HEAD): + if (MDOC_Sh == n->tok || MDOC_Ss == n->tok) + break; + return(1); + case (MDOC_BODY): + if (MDOC_D1 == n->tok || MDOC_Nd == n->tok) + break; + return(1); + case (MDOC_ELEM): + break; + default: + return(1); + } + + for (nch = n->child; nch; nch = nch->next) { + if (MDOC_TEXT != nch->type) + continue; + cp = nch->string; + if (3 > strnlen(cp, 3)) + continue; + while ('\0' != *(++cp)) + if ('-' == *cp && + isalpha((unsigned char)cp[-1]) && + isalpha((unsigned char)cp[1])) + *cp = ASCII_HYPH; + } + return(1); +} + static int post_ns(POST_ARGS) { @@ -1857,10 +1990,13 @@ post_sh_head(POST_ARGS) /* The SYNOPSIS gets special attention in other areas. */ - if (SEC_SYNOPSIS == sec) + if (SEC_SYNOPSIS == sec) { + roff_setreg(mdoc->roff, "nS", 1, '='); mdoc->flags |= MDOC_SYNOPSIS; - else + } else { + roff_setreg(mdoc->roff, "nS", 0, '='); mdoc->flags &= ~MDOC_SYNOPSIS; + } /* Mark our last section. */ @@ -1916,7 +2052,8 @@ post_sh_head(POST_ARGS) break; if (*mdoc->meta.msec == '9') break; - mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC); + mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse, + mdoc->last->line, mdoc->last->pos, buf); break; default: break; @@ -1962,7 +2099,9 @@ pre_par(PRE_ARGS) * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. */ - if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok) + if (MDOC_Pp != mdoc->last->tok && + MDOC_Lp != mdoc->last->tok && + MDOC_br != mdoc->last->tok) return(1); if (MDOC_Bl == n->tok && n->norm->Bl.comp) return(1); @@ -1977,6 +2116,32 @@ pre_par(PRE_ARGS) } static int +post_par(POST_ARGS) +{ + + if (MDOC_ELEM != mdoc->last->type && + MDOC_BLOCK != mdoc->last->type) + return(1); + + if (NULL == mdoc->last->prev) { + if (MDOC_Sh != mdoc->last->parent->tok && + MDOC_Ss != mdoc->last->parent->tok) + return(1); + } else { + if (MDOC_Pp != mdoc->last->prev->tok && + MDOC_Lp != mdoc->last->prev->tok && + (MDOC_br != mdoc->last->tok || + (MDOC_sp != mdoc->last->prev->tok && + MDOC_br != mdoc->last->prev->tok))) + return(1); + } + + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); + mdoc_node_delete(mdoc, mdoc->last); + return(1); +} + +static int pre_literal(PRE_ARGS) { @@ -2129,9 +2294,9 @@ post_dt(POST_ARGS) free(mdoc->meta.vol); mdoc->meta.vol = mandoc_strdup(cp); } else { - /* FIXME: warn about bad arch. */ cp = mdoc_a2arch(nn->string); if (NULL == cp) { + mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH); free(mdoc->meta.vol); mdoc->meta.vol = mandoc_strdup(nn->string); } else @@ -2192,14 +2357,15 @@ post_os(POST_ARGS) n = mdoc->last; /* - * Set the operating system by way of the `Os' macro. Note that - * if an argument isn't provided and -DOSNAME="\"foo\"" is - * provided during compilation, this value will be used instead - * of filling in "sysname release" from uname(). + * 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) */ - if (mdoc->meta.os) - free(mdoc->meta.os); + free(mdoc->meta.os); buf[0] = '\0'; if (-1 == (c = concat(buf, n->child, BUFSIZ))) { @@ -2209,11 +2375,11 @@ post_os(POST_ARGS) assert(c); - /* XXX: yes, these can all be dynamically-adjusted buffers, but - * it's really not worth the extra hackery. - */ - if ('\0' == buf[0]) { + if (mdoc->defos) { + mdoc->meta.os = mandoc_strdup(mdoc->defos); + return(1); + } #ifdef OSNAME if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { mdoc_nmsg(mdoc, n, MANDOCERR_MEM); diff --git a/contrib/mdocml/out.c b/contrib/mdocml/out.c index 8dbd68a..c931664 100644 --- a/contrib/mdocml/out.c +++ b/contrib/mdocml/out.c @@ -1,4 +1,4 @@ -/* $Id: out.c,v 1.43 2011/09/20 23:05:49 schwarze Exp $ */ +/* $Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -32,11 +32,11 @@ #include "out.h" static void tblcalc_data(struct rofftbl *, struct roffcol *, - const struct tbl *, const struct tbl_dat *); + const struct tbl_opts *, const struct tbl_dat *); static void tblcalc_literal(struct rofftbl *, struct roffcol *, const struct tbl_dat *); static void tblcalc_number(struct rofftbl *, struct roffcol *, - const struct tbl *, const struct tbl_dat *); + const struct tbl_opts *, const struct tbl_dat *); /* * Convert a `scaling unit' to a consistent form, or fail. Scaling @@ -142,7 +142,6 @@ void tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) { const struct tbl_dat *dp; - const struct tbl_head *hp; struct roffcol *col; int spans; @@ -154,9 +153,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) assert(NULL == tbl->cols); tbl->cols = mandoc_calloc - ((size_t)sp->tbl->cols, sizeof(struct roffcol)); - - hp = sp->head; + ((size_t)sp->opts->cols, sizeof(struct roffcol)); for ( ; sp; sp = sp->next) { if (TBL_SPAN_DATA != sp->pos) @@ -175,33 +172,14 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) continue; assert(dp->layout); col = &tbl->cols[dp->layout->head->ident]; - tblcalc_data(tbl, col, sp->tbl, dp); - } - } - - /* - * Calculate width of the spanners. These get one space for a - * vertical line, two for a double-vertical line. - */ - - for ( ; hp; hp = hp->next) { - col = &tbl->cols[hp->ident]; - switch (hp->pos) { - case (TBL_HEAD_VERT): - col->width = (*tbl->len)(1, tbl->arg); - break; - case (TBL_HEAD_DVERT): - col->width = (*tbl->len)(2, tbl->arg); - break; - default: - break; + tblcalc_data(tbl, col, sp->opts, dp); } } } static void tblcalc_data(struct rofftbl *tbl, struct roffcol *col, - const struct tbl *tp, const struct tbl_dat *dp) + const struct tbl_opts *opts, const struct tbl_dat *dp) { size_t sz; @@ -225,7 +203,7 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col, tblcalc_literal(tbl, col, dp); break; case (TBL_CELL_NUMBER): - tblcalc_number(tbl, col, tp, dp); + tblcalc_number(tbl, col, opts, dp); break; case (TBL_CELL_DOWN): break; @@ -251,7 +229,7 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, static void tblcalc_number(struct rofftbl *tbl, struct roffcol *col, - const struct tbl *tp, const struct tbl_dat *dp) + const struct tbl_opts *opts, const struct tbl_dat *dp) { int i; size_t sz, psz, ssz, d; @@ -273,12 +251,12 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col, /* FIXME: TBL_DATA_HORIZ et al.? */ - buf[0] = tp->decimal; + buf[0] = opts->decimal; buf[1] = '\0'; psz = (*tbl->slen)(buf, tbl->arg); - if (NULL != (cp = strrchr(str, tp->decimal))) { + if (NULL != (cp = strrchr(str, opts->decimal))) { buf[1] = '\0'; for (ssz = 0, i = 0; cp != &str[i]; i++) { buf[0] = str[i]; diff --git a/contrib/mdocml/predefs.in b/contrib/mdocml/predefs.in index 70074bb..d1690e3 100644 --- a/contrib/mdocml/predefs.in +++ b/contrib/mdocml/predefs.in @@ -1,4 +1,4 @@ -/* $Id: predefs.in,v 1.3 2011/07/31 11:36:49 schwarze Exp $ */ +/* $Id: predefs.in,v 1.4 2012/07/18 10:39:19 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -26,7 +26,7 @@ */ PREDEF("Am", "&") -PREDEF("Ba", "|") +PREDEF("Ba", "\\fR|\\fP") PREDEF("Ge", "\\(>=") PREDEF("Gt", ">") PREDEF("If", "infinity") diff --git a/contrib/mdocml/read.c b/contrib/mdocml/read.c index 5b14e35..511ba7d 100644 --- a/contrib/mdocml/read.c +++ b/contrib/mdocml/read.c @@ -1,7 +1,7 @@ -/* $Id: read.c,v 1.28 2012/02/16 20:51:31 joerg Exp $ */ +/* $Id: read.c,v 1.39 2013/09/16 00:25:07 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -40,10 +40,6 @@ #include "man.h" #include "main.h" -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif - #define REPARSE_LIMIT 1000 struct buf { @@ -66,14 +62,16 @@ struct mparse { void *arg; /* argument to mmsg */ const char *file; struct buf *secondary; + char *defos; /* default operating system */ }; static void resize_buf(struct buf *, size_t); static void mparse_buf_r(struct mparse *, struct buf, int); -static void mparse_readfd_r(struct mparse *, int, const char *, int); static void pset(const char *, int, struct mparse *); static int read_whole_file(const char *, int, struct buf *, int *); static void mparse_end(struct mparse *); +static void mparse_parse_buffer(struct mparse *, struct buf, + const char *); static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { MANDOCERR_OK, @@ -94,6 +92,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "no title in document", "document title should be all caps", "unknown manual section", + "unknown manual volume or arch", "date missing, using today's date", "cannot parse date, using it verbatim", "prologue macros out of order", @@ -105,14 +104,14 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { ".so is fragile, better use ln(1)", "NAME section must come first", "bad NAME section contents", - "manual name not yet set", "sections out of conventional order", "duplicate section name", - "section not in conventional manual section", + "section header suited to sections 2, 3, and 9 only", /* related to macros and nesting */ "skipping obsolete macro", "skipping paragraph macro", + "moving paragraph macro out of list", "skipping no-space macro", "blocks badly nested", "child violates parent syntax", @@ -173,10 +172,12 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "input stack limit exceeded, infinite loop?", "skipping bad character", "escaped character not allowed in a name", + "manual name not yet set", "skipping text before the first section header", "skipping unknown macro", "NOT IMPLEMENTED, please use groff: skipping request", "argument count wrong", + "skipping column outside column list", "skipping end of block that is not open", "missing end of block", "scope open on exit", @@ -184,6 +185,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "macro requires line argument(s)", "macro requires body argument(s)", "macro requires argument(s)", + "request requires a numeric argument", "missing list type", "line argument(s) will be lost", "body argument(s) will be lost", @@ -247,7 +249,8 @@ pset(const char *buf, int pos, struct mparse *curp) switch (curp->inttype) { case (MPARSE_MDOC): if (NULL == curp->pmdoc) - curp->pmdoc = mdoc_alloc(curp->roff, curp); + curp->pmdoc = mdoc_alloc(curp->roff, curp, + curp->defos); assert(curp->pmdoc); curp->mdoc = curp->pmdoc; return; @@ -263,7 +266,8 @@ pset(const char *buf, int pos, struct mparse *curp) if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) { if (NULL == curp->pmdoc) - curp->pmdoc = mdoc_alloc(curp->roff, curp); + curp->pmdoc = mdoc_alloc(curp->roff, curp, + curp->defos); assert(curp->pmdoc); curp->mdoc = curp->pmdoc; return; @@ -322,6 +326,15 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start) break; } + /* + * Make sure we have space for at least + * one backslash and one other character + * and the trailing NUL byte. + */ + + if (pos + 2 >= (int)ln.sz) + resize_buf(&ln, 256); + /* * Warn about bogus characters. If you're using * non-ASCII encoding, you're screwing your @@ -338,8 +351,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start) mandoc_msg(MANDOCERR_BADCHAR, curp, curp->line, pos, NULL); i++; - if (pos >= (int)ln.sz) - resize_buf(&ln, 256); ln.buf[pos++] = '?'; continue; } @@ -347,8 +358,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start) /* Trailing backslash = a plain char. */ if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) { - if (pos >= (int)ln.sz) - resize_buf(&ln, 256); ln.buf[pos++] = blk.buf[i++]; continue; } @@ -390,10 +399,20 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start) break; } - /* Some other escape sequence, copy & cont. */ + /* Catch escaped bogus characters. */ - if (pos + 1 >= (int)ln.sz) - resize_buf(&ln, 256); + c = (unsigned char) blk.buf[i+1]; + + if ( ! (isascii(c) && + (isgraph(c) || isblank(c)))) { + mandoc_msg(MANDOCERR_BADCHAR, curp, + curp->line, pos, NULL); + i += 2; + ln.buf[pos++] = '?'; + continue; + } + + /* Some other escape sequence, copy & cont. */ ln.buf[pos++] = blk.buf[i++]; ln.buf[pos++] = blk.buf[i++]; @@ -469,7 +488,7 @@ rerun: */ if (curp->secondary) curp->secondary->sz -= pos + 1; - mparse_readfd_r(curp, -1, ln.buf + of, 1); + mparse_readfd(curp, -1, ln.buf + of); if (MANDOCLEVEL_FATAL <= curp->file_status) break; pos = 0; @@ -575,8 +594,7 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap) } *with_mmap = 1; fb->sz = (size_t)st.st_size; - fb->buf = mmap(NULL, fb->sz, PROT_READ, - MAP_FILE|MAP_SHARED, fd, 0); + fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0); if (fb->buf != MAP_FAILED) return(1); } @@ -643,19 +661,25 @@ mparse_end(struct mparse *curp) } static void -mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file, - int re) +mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file) { const char *svfile; + static int recursion_depth; + + if (64 < recursion_depth) { + mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL); + return; + } /* Line number is per-file. */ svfile = curp->file; curp->file = file; curp->line = 1; + recursion_depth++; mparse_buf_r(curp, blk, 1); - if (0 == re && MANDOCLEVEL_FATAL > curp->file_status) + if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status) mparse_end(curp); curp->file = svfile; @@ -670,12 +694,12 @@ mparse_readmem(struct mparse *curp, const void *buf, size_t len, blk.buf = UNCONST(buf); blk.sz = len; - mparse_parse_buffer(curp, blk, file, 0); + mparse_parse_buffer(curp, blk, file); return(curp->file_status); } -static void -mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) +enum mandoclevel +mparse_readfd(struct mparse *curp, int fd, const char *file) { struct buf blk; int with_mmap; @@ -684,7 +708,7 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) if (-1 == (fd = open(file, O_RDONLY, 0))) { perror(file); curp->file_status = MANDOCLEVEL_SYSERR; - return; + goto out; } /* * Run for each opened file; may be called more than once for @@ -695,10 +719,10 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) if ( ! read_whole_file(file, fd, &blk, &with_mmap)) { curp->file_status = MANDOCLEVEL_SYSERR; - return; + goto out; } - mparse_parse_buffer(curp, blk, file, re); + mparse_parse_buffer(curp, blk, file); #ifdef HAVE_MMAP if (with_mmap) @@ -709,18 +733,13 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) if (STDIN_FILENO != fd && -1 == close(fd)) perror(file); -} - -enum mandoclevel -mparse_readfd(struct mparse *curp, int fd, const char *file) -{ - - mparse_readfd_r(curp, fd, file, 0); +out: return(curp->file_status); } struct mparse * -mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg) +mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, + mandocmsg mmsg, void *arg, char *defos) { struct mparse *curp; @@ -732,8 +751,9 @@ mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void curp->mmsg = mmsg; curp->arg = arg; curp->inttype = inttype; + curp->defos = defos; - curp->roff = roff_alloc(curp); + curp->roff = roff_alloc(inttype, curp); return(curp); } diff --git a/contrib/mdocml/roff.7 b/contrib/mdocml/roff.7 index dd32a45..48e16dd 100644 --- a/contrib/mdocml/roff.7 +++ b/contrib/mdocml/roff.7 @@ -1,7 +1,7 @@ -.\" $Id: roff.7,v 1.37 2011/12/11 00:38:11 schwarze Exp $ +.\" $Id: roff.7,v 1.46 2013/12/26 02:43:18 schwarze Exp $ .\" -.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2010, 2011, 2013 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: December 11 2011 $ +.Dd $Mdocdate: December 26 2013 $ .Dt ROFF 7 .Os .Sh NAME @@ -32,7 +32,7 @@ and manual formatting languages are based on it, many real-world manuals use small numbers of .Nm -requests intermixed with their +requests and escape sequences intermixed with their .Xr mdoc 7 or .Xr man 7 @@ -41,8 +41,8 @@ To properly format such manuals, the .Xr mandoc 1 utility supports a tiny subset of .Nm -requests. -Only these requests supported by +requests and escapes. +Only these requests and escapes supported by .Xr mandoc 1 are documented in the present manual, together with the basic language syntax shared by @@ -83,9 +83,9 @@ depends on the respective processing context. .Nm documents may contain only graphable 7-bit ASCII characters, the space character, and, in certain circumstances, the tab character. -The back-space character +The backslash character .Sq \e -indicates the start of an escape sequence for +indicates the start of an escape sequence, used for example for .Sx Comments , .Sx Special Characters , .Sx Predefined Strings , @@ -93,6 +93,9 @@ and user-defined strings defined using the .Sx ds request. +For a listing of escape sequences, consult the +.Sx ESCAPE SEQUENCE REFERENCE +below. .Ss Comments Text following an escaped double-quote .Sq \e\(dq , @@ -146,12 +149,19 @@ respectively) may be used instead. The indicator or numerical representative may be preceded by C (constant-width), which is ignored. .Pp +The two-character indicator +.Sq BI +requests a font that is both bold and italic. +It may not be portable to old roff implementations. +.Pp Examples: .Bl -tag -width Ds -offset indent -compact .It Li \efBbold\efR -Write in bold, then switch to regular font mode. +Write in \fBbold\fP, then switch to regular font mode. .It Li \efIitalic\efP -Write in italic, then return to previous font mode. +Write in \fIitalic\fP, then return to previous font mode. +.It Li \ef(BIbold italic\efP +Write in \f(BIbold italic\fP, then return to previous font mode. .El .Pp Text decoration is @@ -417,6 +427,18 @@ The syntax of this request is the same as that of It is currently ignored by .Xr mandoc 1 , as are its children. +.Ss \&cc +Changes the control character. +Its syntax is as follows: +.Bd -literal -offset indent +.Pf . Cm \&cc Op Ar c +.Ed +.Pp +If +.Ar c +is not specified, the control character is reset to +.Sq \&. . +Trailing characters are ignored. .Ss \&de Define a .Nm @@ -619,6 +641,15 @@ Begin an equation block. See .Xr eqn 7 for a description of the equation language. +.Ss \&fam +Change the font family. +This line-scoped request is intended to have one argument specifying +the font family to be selected. +It is a groff extension, and currently, it is ignored including its +arguments, and the number of arguments is not checked. +.Ss \&hw +Specify hyphenation points in words. +This line-scoped request is currently ignored. .Ss \&hy Set automatic hyphenation mode. This line-scoped request is currently ignored. @@ -786,19 +817,22 @@ the name of the request, macro or string to be undefined. Currently, it is ignored including its arguments, and the number of arguments is not checked. .Ss \&nr -Define a register. +Define or change a register. A register is an arbitrary string value that defines some sort of state, which influences parsing and/or formatting. Its syntax is as follows: .Pp -.D1 Pf \. Cm \&nr Ar name Ar value +.D1 Pf \. Cm \&nr Ar name Oo +|- Oc Ns Ar value .Pp The .Ar value may, at the moment, only be an integer. -So far, only the following register +If it is prefixed by a sign, the register will be +incremented or decremented instead of assigned to. +.Pp +The following register .Ar name -is recognised: +is handled specially: .Bl -tag -width Ds .It Cm nS If set to a positive integer value, certain @@ -895,8 +929,251 @@ Begin a table, which formats input in aligned rows and columns. See .Xr tbl 7 for a description of the tbl language. +.Sh ESCAPE SEQUENCE REFERENCE +The +.Xr mandoc 1 +.Nm +parser recognises the following escape sequences. +Note that the +.Nm +language defines more escape sequences not implemented in +.Xr mandoc 1 . +In +.Xr mdoc 7 +and +.Xr man 7 +documents, using escape sequences is discouraged except for those +described in the +.Sx LANGUAGE SYNTAX +section above. +.Pp +A backslash followed by any character not listed here +simply prints that character itself. +.Ss \e<newline> +A backslash at the end of an input line can be used to continue the +logical input line on the next physical input line, joining the text +on both lines together as if it were on a single input line. +.Ss \e<space> +The escape sequence backslash-space +.Pq Sq \e\ \& +is an unpaddable space-sized non-breaking space character; see +.Sx Whitespace . +.Ss \e\(dq +The rest of the input line is treated as +.Sx Comments . +.Ss \e% +Hyphenation allowed at this point of the word; ignored by +.Xr mandoc 1 . +.Ss \e& +Non-printing zero-width character; see +.Sx Whitespace . +.Ss \e\(aq +Acute accent special character; use +.Sq \e(aa +instead. +.Ss \e( Ns Ar cc +.Sx Special Characters +with two-letter names, see +.Xr mandoc_char 7 . +.Ss \e*[ Ns Ar name ] +Interpolate the string with the +.Ar name ; +see +.Sx Predefined Strings +and +.Sx ds . +For short names, there are variants +.No \e* Ns Ar c +and +.No \e*( Ns Ar cc . +.Ss \e- +Special character +.Dq mathematical minus sign . +.Ss \e[ Ns Ar name ] +.Sx Special Characters +with names of arbitrary length, see +.Xr mandoc_char 7 . +.Ss \e^ +One-twelfth em half-narrow space character, effectively zero-width in +.Xr mandoc 1 . +.Ss \e` +Grave accent special character; use +.Sq \e(ga +instead. +.Ss \e{ +Begin conditional input; see +.Sx if . +.Ss \e\(ba +One-sixth em narrow space character, effectively zero-width in +.Xr mandoc 1 . +.Ss \e} +End conditional input; see +.Sx if . +.Ss \e~ +Paddable non-breaking space character. +.Ss \e0 +Digit width space character. +.Ss \eA\(aq Ns Ar string Ns \(aq +Anchor definition; ignored by +.Xr mandoc 1 . +.Ss \eB\(aq Ns Ar string Ns \(aq +Test whether +.Ar string +is a numerical expession; ignored by +.Xr mandoc 1 . +.Ss \eb\(aq Ns Ar string Ns \(aq +Bracket building function; ignored by +.Xr mandoc 1 . +.Ss \eC\(aq Ns Ar name Ns \(aq +.Sx Special Characters +with names of arbitrary length. +.Ss \ec +Interrupt text processing to insert requests or macros; ignored by +.Xr mandoc 1 . +.Ss \eD\(aq Ns Ar string Ns \(aq +Draw graphics function; ignored by +.Xr mandoc 1 . +.Ss \ed +Move down by half a line; ignored by +.Xr mandoc 1 . +.Ss \ee +Backslash special character. +.Ss \eF[ Ns Ar name ] +Switch font family (groff extension); ignored by +.Xr mandoc 1 . +For short names, there are variants +.No \eF Ns Ar c +and +.No \eF( Ns Ar cc . +.Ss \ef[ Ns Ar name ] +Switch to the font +.Ar name , +see +.Sx Text Decoration . +For short names, there are variants +.No \ef Ns Ar c +and +.No \ef( Ns Ar cc . +.Ss \eg[ Ns Ar name ] +Interpolate the format of a number register; ignored by +.Xr mandoc 1 . +For short names, there are variants +.No \eg Ns Ar c +and +.No \eg( Ns Ar cc . +.Ss \eH\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq +Set the height of the current font; ignored by +.Xr mandoc 1 . +.Ss \eh\(aq Ns Ar number Ns \(aq +Horizontal motion; ignored by +.Xr mandoc 1 . +.Ss \ek[ Ns Ar name ] +Mark horizontal input place in register; ignored by +.Xr mandoc 1 . +For short names, there are variants +.No \ek Ns Ar c +and +.No \ek( Ns Ar cc . +.Ss \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns \(aq +Vertical line drawing function; ignored by +.Xr mandoc 1 . +.Ss \el\(aq Ns Ar number Ns Oo Ar c Oc Ns \(aq +Horizontal line drawing function; ignored by +.Xr mandoc 1 . +.Ss \eM[ Ns Ar name ] +Set fill (background) color (groff extension); ignored by +.Xr mandoc 1 . +For short names, there are variants +.No \eM Ns Ar c +and +.No \eM( Ns Ar cc . +.Ss \em[ Ns Ar name ] +Set glyph drawing color (groff extension); ignored by +.Xr mandoc 1 . +For short names, there are variants +.No \em Ns Ar c +and +.No \em( Ns Ar cc . +.Ss \eN\(aq Ns Ar number Ns \(aq +Character +.Ar number +on the current font. +.Ss \en[ Ns Ar name ] +Interpolate the number register +.Ar name . +For short names, there are variants +.No \en Ns Ar c +and +.No \en( Ns Ar cc . +.Ss \eo\(aq Ns Ar string Ns \(aq +Overstrike +.Ar string ; +ignored by +.Xr mandoc 1 . +.Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq +Set number register; ignored by +.Xr mandoc 1 . +.Ss \eS\(aq Ns Ar number Ns \(aq +Slant output; ignored by +.Xr mandoc 1 . +.Ss \es\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq +Change point size; ignored by +.Xr mandoc 1 . +Alternative forms +.No \es Ns Oo +|- Oc Ns Ar n , +.No \es Ns Oo +|- Oc Ns \(aq Ns Ar number Ns \(aq , +.No \es Ns [ Oo +|- Oc Ns Ar number ] , +and +.No \es Ns Oo +|- Oc Ns [ Ar number Ns ] +are also parsed and ignored. +.Ss \et +Horizontal tab; ignored by +.Xr mandoc 1 . +.Ss \eu +Move up by half a line; ignored by +.Xr mandoc 1 . +.Ss \eV[ Ns Ar name ] +Interpolate an environment variable; ignored by +.Xr mandoc 1 . +For short names, there are variants +.No \eV Ns Ar c +and +.No \eV( Ns Ar cc . +.Ss \ev\(aq Ns Ar number Ns \(aq +Vertical motion; ignored by +.Xr mandoc 1 . +.Ss \ew\(aq Ns Ar string Ns \(aq +Interpolate the width of the +.Ar string ; +ignored by +.Xr mandoc 1 . +.Ss \eX\(aq Ns Ar string Ns \(aq +Output +.Ar string +as device control function; ignored in nroff mode and by +.Xr mandoc 1 . +.Ss \ex\(aq Ns Ar number Ns \(aq +Extra line space function; ignored by +.Xr mandoc 1 . +.Ss \eY[ Ns Ar name ] +Output a string as a device control function; ignored in nroff mode and by +.Xr mandoc 1 . +For short names, there are variants +.No \eY Ns Ar c +and +.No \eY( Ns Ar cc . +.Ss \eZ\(aq Ns Ar string Ns \(aq +Print +.Ar string +with zero width and height; ignored by +.Xr mandoc 1 . +.Ss \ez +Output the next character without advancing the cursor position; +approximated in +.Xr mandoc 1 +by simply skipping the next character. .Sh COMPATIBILITY -This section documents compatibility between mandoc and other other +This section documents compatibility between mandoc and other .Nm implementations, at this time limited to GNU troff .Pq Qq groff . @@ -982,8 +1259,6 @@ In 1989, James Clarke re-implemented troff in C++, naming it groff. This .Nm reference was written by -.An Kristaps Dzonsons , -.Mt kristaps@bsd.lv ; +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv and -.An Ingo Schwarze , -.Mt schwarze@openbsd.org . +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . diff --git a/contrib/mdocml/roff.c b/contrib/mdocml/roff.c index b479cc2..42240d2 100644 --- a/contrib/mdocml/roff.c +++ b/contrib/mdocml/roff.c @@ -1,7 +1,7 @@ -/* $Id: roff.c,v 1.172 2011/10/24 21:41:45 schwarze Exp $ */ +/* $Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp $ */ /* - * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,6 +21,7 @@ #include <assert.h> #include <ctype.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -39,11 +40,14 @@ enum rofft { ROFF_am, ROFF_ami, ROFF_am1, + ROFF_cc, ROFF_de, ROFF_dei, ROFF_de1, ROFF_ds, ROFF_el, + ROFF_fam, + ROFF_hw, ROFF_hy, ROFF_ie, ROFF_if, @@ -58,6 +62,8 @@ enum rofft { ROFF_so, ROFF_ta, ROFF_tr, + ROFF_Dd, + ROFF_TH, ROFF_TS, ROFF_TE, ROFF_T_, @@ -70,18 +76,8 @@ enum rofft { }; enum roffrule { - ROFFRULE_ALLOW, - ROFFRULE_DENY -}; - -/* - * A single register entity. If "set" is zero, the value of the - * register should be the default one, which is per-register. - * Registers are assumed to be unsigned ints for now. - */ -struct reg { - int set; /* whether set or not */ - unsigned int u; /* unsigned integer */ + ROFFRULE_DENY, + ROFFRULE_ALLOW }; /* @@ -101,12 +97,23 @@ struct roffkv { struct roffkv *next; /* next in list */ }; +/* + * A single number register as part of a singly-linked list. + */ +struct roffreg { + struct roffstr key; + int val; + struct roffreg *next; +}; + struct roff { + enum mparset parsetype; /* requested parse type */ struct mparse *parse; /* parse point */ struct roffnode *last; /* leaf of stack */ enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ + char control; /* control character */ int rstackpos; /* position in rstack */ - struct reg regs[REG__MAX]; + struct roffreg *regtab; /* number registers */ struct roffkv *strtab; /* user-defined strings & macros */ struct roffkv *xmbtab; /* multi-byte trans table (`tr') */ struct roffstr *xtab; /* single-byte trans table (`tr') */ @@ -169,6 +176,7 @@ static enum rofferr roff_block(ROFF_ARGS); static enum rofferr roff_block_text(ROFF_ARGS); static enum rofferr roff_block_sub(ROFF_ARGS); static enum rofferr roff_cblock(ROFF_ARGS); +static enum rofferr roff_cc(ROFF_ARGS); static enum rofferr roff_ccond(ROFF_ARGS); static enum rofferr roff_cond(ROFF_ARGS); static enum rofferr roff_cond_text(ROFF_ARGS); @@ -176,16 +184,22 @@ static enum rofferr roff_cond_sub(ROFF_ARGS); static enum rofferr roff_ds(ROFF_ARGS); static enum roffrule roff_evalcond(const char *, int *); static void roff_free1(struct roff *); +static void roff_freereg(struct roffreg *); static void roff_freestr(struct roffkv *); static char *roff_getname(struct roff *, char **, int, int); +static int roff_getnum(const char *, int *, int *); +static int roff_getop(const char *, int *, char *); +static int roff_getregn(const struct roff *, + const char *, size_t); static const char *roff_getstrn(const struct roff *, const char *, size_t); +static enum rofferr roff_it(ROFF_ARGS); static enum rofferr roff_line_ignore(ROFF_ARGS); static enum rofferr roff_nr(ROFF_ARGS); static void roff_openeqn(struct roff *, const char *, int, int, const char *); static enum rofft roff_parse(struct roff *, const char *, int *); -static enum rofferr roff_parsetext(char *); +static enum rofferr roff_parsetext(char **, size_t *, int, int *); static enum rofferr roff_res(struct roff *, char **, size_t *, int, int); static enum rofferr roff_rm(ROFF_ARGS); @@ -195,6 +209,8 @@ static void roff_setstrn(struct roffkv **, const char *, size_t, const char *, size_t, int); static enum rofferr roff_so(ROFF_ARGS); static enum rofferr roff_tr(ROFF_ARGS); +static enum rofferr roff_Dd(ROFF_ARGS); +static enum rofferr roff_TH(ROFF_ARGS); static enum rofferr roff_TE(ROFF_ARGS); static enum rofferr roff_TS(ROFF_ARGS); static enum rofferr roff_EQ(ROFF_ARGS); @@ -215,16 +231,19 @@ static struct roffmac roffs[ROFF_MAX] = { { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, + { "cc", roff_cc, NULL, NULL, 0, NULL }, { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "ds", roff_ds, NULL, NULL, 0, NULL }, { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, + { "fam", roff_line_ignore, NULL, NULL, 0, NULL }, + { "hw", roff_line_ignore, NULL, NULL, 0, NULL }, { "hy", roff_line_ignore, NULL, NULL, 0, NULL }, { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL }, - { "it", roff_line_ignore, NULL, NULL, 0, NULL }, + { "it", roff_it, NULL, NULL, 0, NULL }, { "ne", roff_line_ignore, NULL, NULL, 0, NULL }, { "nh", roff_line_ignore, NULL, NULL, 0, NULL }, { "nr", roff_nr, NULL, NULL, 0, NULL }, @@ -234,6 +253,8 @@ static struct roffmac roffs[ROFF_MAX] = { { "so", roff_so, NULL, NULL, 0, NULL }, { "ta", roff_line_ignore, NULL, NULL, 0, NULL }, { "tr", roff_tr, NULL, NULL, 0, NULL }, + { "Dd", roff_Dd, NULL, NULL, 0, NULL }, + { "TH", roff_TH, NULL, NULL, 0, NULL }, { "TS", roff_TS, NULL, NULL, 0, NULL }, { "TE", roff_TE, NULL, NULL, 0, NULL }, { "T&", roff_T_, NULL, NULL, 0, NULL }, @@ -244,6 +265,37 @@ static struct roffmac roffs[ROFF_MAX] = { { NULL, roff_userdef, NULL, NULL, 0, NULL }, }; +const char *const __mdoc_reserved[] = { + "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At", + "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq", + "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx", + "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq", + "Ds", "Dt", "Dv", "Dx", "D1", + "Ec", "Ed", "Ef", "Ek", "El", "Em", "em", + "En", "Eo", "Eq", "Er", "Es", "Ev", "Ex", + "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx", + "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP", + "Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx", + "Oc", "Oo", "Op", "Os", "Ot", "Ox", + "Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq", + "Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv", + "Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq", + "Ss", "St", "Sx", "Sy", + "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr", + "%A", "%B", "%D", "%I", "%J", "%N", "%O", + "%P", "%Q", "%R", "%T", "%U", "%V", + NULL +}; + +const char *const __man_reserved[] = { + "AT", "B", "BI", "BR", "BT", "DE", "DS", "DT", + "EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR", + "LP", "ME", "MT", "OP", "P", "PD", "PP", "PT", + "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY", + "TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS", + NULL +}; + /* Array of injected predefined strings. */ #define PREDEFS_MAX 38 static const struct predef predefs[PREDEFS_MAX] = { @@ -253,6 +305,9 @@ static const struct predef predefs[PREDEFS_MAX] = { /* See roffhash_find() */ #define ROFF_HASH(p) (p[0] - ASCII_LO) +static int roffit_lines; /* number of lines to delay */ +static char *roffit_macro; /* nil-terminated macro line */ + static void roffhash_init(void) { @@ -351,13 +406,13 @@ roffnode_push(struct roff *r, enum rofft tok, const char *name, static void roff_free1(struct roff *r) { - struct tbl_node *t; + struct tbl_node *tbl; struct eqn_node *e; int i; - while (NULL != (t = r->first_tbl)) { - r->first_tbl = t->next; - tbl_free(t); + while (NULL != (tbl = r->first_tbl)) { + r->first_tbl = tbl->next; + tbl_free(tbl); } r->first_tbl = r->last_tbl = r->tbl = NULL; @@ -377,6 +432,10 @@ roff_free1(struct roff *r) r->strtab = r->xmbtab = NULL; + roff_freereg(r->regtab); + + r->regtab = NULL; + if (r->xtab) for (i = 0; i < 128; i++) free(r->xtab[i].p); @@ -392,7 +451,7 @@ roff_reset(struct roff *r) roff_free1(r); - memset(&r->regs, 0, sizeof(struct reg) * REG__MAX); + r->control = 0; for (i = 0; i < PREDEFS_MAX; i++) roff_setstr(r, predefs[i].name, predefs[i].str, 0); @@ -409,12 +468,13 @@ roff_free(struct roff *r) struct roff * -roff_alloc(struct mparse *parse) +roff_alloc(enum mparset type, struct mparse *parse) { struct roff *r; int i; r = mandoc_calloc(1, sizeof(struct roff)); + r->parsetype = type; r->parse = parse; r->rstackpos = -1; @@ -427,22 +487,23 @@ roff_alloc(struct mparse *parse) } /* - * Pre-filter each and every line for reserved words (one beginning with - * `\*', e.g., `\*(ab'). These must be handled before the actual line - * is processed. - * This also checks the syntax of regular escapes. + * In the current line, expand user-defined strings ("\*") + * and references to number registers ("\n"). + * Also check the syntax of other escape sequences. */ static enum rofferr roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos) { - enum mandoc_esc esc; + char ubuf[12]; /* buffer to print the number */ const char *stesc; /* start of an escape sequence ('\\') */ const char *stnam; /* start of the name, after "[(*" */ const char *cp; /* end of the name, e.g. before ']' */ const char *res; /* the string to be substituted */ - int i, maxl, expand_count; - size_t nsz; - char *n; + char *nbuf; /* new buffer to copy bufp to */ + size_t nsz; /* size of the new buffer */ + size_t maxl; /* expected length of the escape name */ + size_t naml; /* actual length of the escape name */ + int expand_count; /* to avoid infinite loops */ expand_count = 0; @@ -452,7 +513,7 @@ again: stesc = cp++; /* - * The second character must be an asterisk. + * The second character must be an asterisk or an n. * If it isn't, skip it anyway: It is escaped, * so it can't start another escape sequence. */ @@ -460,12 +521,16 @@ again: if ('\0' == *cp) return(ROFF_CONT); - if ('*' != *cp) { - res = cp; - esc = mandoc_escape(&cp, NULL, NULL); - if (ESCAPE_ERROR != esc) + switch (*cp) { + case ('*'): + res = NULL; + break; + case ('n'): + res = ubuf; + break; + default: + if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL)) continue; - cp = res; mandoc_msg (MANDOCERR_BADESCAPE, r->parse, ln, (int)(stesc - *bufp), NULL); @@ -476,7 +541,7 @@ again: /* * The third character decides the length - * of the name of the string. + * of the name of the string or register. * Save a pointer to the name. */ @@ -499,7 +564,7 @@ again: /* Advance to the end of the name. */ - for (i = 0; 0 == maxl || i < maxl; i++, cp++) { + for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) { if ('\0' == *cp) { mandoc_msg (MANDOCERR_BADESCAPE, @@ -516,7 +581,11 @@ again: * undefined, resume searching for escapes. */ - res = roff_getstrn(r, stnam, (size_t)i); + if (NULL == res) + res = roff_getstrn(r, stnam, naml); + else + snprintf(ubuf, sizeof(ubuf), "%d", + roff_getregn(r, stnam, naml)); if (NULL == res) { mandoc_msg @@ -530,15 +599,15 @@ again: pos = stesc - *bufp; nsz = *szp + strlen(res) + 1; - n = mandoc_malloc(nsz); + nbuf = mandoc_malloc(nsz); - strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1)); - strlcat(n, res, nsz); - strlcat(n, cp + (maxl ? 0 : 1), nsz); + strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1)); + strlcat(nbuf, res, nsz); + strlcat(nbuf, cp + (maxl ? 0 : 1), nsz); free(*bufp); - *bufp = n; + *bufp = nbuf; *szp = nsz; if (EXPAND_LIMIT >= ++expand_count) @@ -552,16 +621,20 @@ again: } /* - * Process text streams: convert all breakable hyphens into ASCII_HYPH. + * Process text streams: + * Convert all breakable hyphens into ASCII_HYPH. + * Decrement and spring input line trap. */ static enum rofferr -roff_parsetext(char *p) +roff_parsetext(char **bufp, size_t *szp, int pos, int *offs) { size_t sz; const char *start; + char *p; + int isz; enum mandoc_esc esc; - start = p; + start = p = *bufp + pos; while ('\0' != *p) { sz = strcspn(p, "-\\"); @@ -573,8 +646,7 @@ roff_parsetext(char *p) if ('\\' == *p) { /* Skip over escapes. */ p++; - esc = mandoc_escape - ((const char **)&p, NULL, NULL); + esc = mandoc_escape((const char **)&p, NULL, NULL); if (ESCAPE_ERROR == esc) break; continue; @@ -589,6 +661,22 @@ roff_parsetext(char *p) p++; } + /* Spring the input line trap. */ + if (1 == roffit_lines) { + isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro); + if (-1 == isz) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + free(*bufp); + *bufp = p; + *szp = isz + 1; + *offs = 0; + free(roffit_macro); + roffit_lines = 0; + return(ROFF_REPARSE); + } else if (1 < roffit_lines) + --roffit_lines; return(ROFF_CONT); } @@ -611,7 +699,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, assert(ROFF_CONT == e); ppos = pos; - ctl = mandoc_getcontrol(*bufp, &pos); + ctl = roff_getcontrol(r, *bufp, &pos); /* * First, if a scope is open and we're not a macro, pass the @@ -629,19 +717,14 @@ roff_parseln(struct roff *r, int ln, char **bufp, assert(ROFF_IGN == e || ROFF_CONT == e); if (ROFF_CONT != e) return(e); - if (r->eqn) - return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); - if (r->tbl) - return(tbl_read(r->tbl, ln, *bufp, pos)); - return(roff_parsetext(*bufp + pos)); - } else if ( ! ctl) { - if (r->eqn) - return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); + } + if (r->eqn) + return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); + if ( ! ctl) { if (r->tbl) return(tbl_read(r->tbl, ln, *bufp, pos)); - return(roff_parsetext(*bufp + pos)); - } else if (r->eqn) - return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); + return(roff_parsetext(bufp, szp, pos, offs)); + } /* * If a scope is open, go to the child handler for that macro, @@ -778,7 +861,7 @@ roffnode_cleanscope(struct roff *r) { while (r->last) { - if (--r->last->endspan < 0) + if (--r->last->endspan != 0) break; roffnode_pop(r); } @@ -984,57 +1067,45 @@ roff_cond_sub(ROFF_ARGS) rr = r->last->rule; roffnode_cleanscope(r); + t = roff_parse(r, *bufp, &pos); /* - * If the macro is unknown, first check if it contains a closing - * delimiter `\}'. If it does, close out our scope and return - * the currently-scoped rule (ignore or continue). Else, drop - * into the currently-scoped rule. + * Fully handle known macros when they are structurally + * required or when the conditional evaluated to true. */ - if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { - ep = &(*bufp)[pos]; - for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { - ep++; - if ('}' != *ep) - continue; - - /* - * Make the \} go away. - * This is a little haphazard, as it's not quite - * clear how nroff does this. - * If we're at the end of line, then just chop - * off the \} and resize the buffer. - * If we aren't, then conver it to spaces. - */ + if ((ROFF_MAX != t) && + (ROFF_ccond == t || ROFFRULE_ALLOW == rr || + ROFFMAC_STRUCT & roffs[t].flags)) { + assert(roffs[t].proc); + return((*roffs[t].proc)(r, t, bufp, szp, + ln, ppos, pos, offs)); + } - if ('\0' == *(ep + 1)) { - *--ep = '\0'; - *szp -= 2; - } else - *(ep - 1) = *ep = ' '; + /* Always check for the closing delimiter `\}'. */ - roff_ccond(r, ROFF_ccond, bufp, szp, - ln, pos, pos + 2, offs); - break; - } - return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); - } + ep = &(*bufp)[pos]; + while (NULL != (ep = strchr(ep, '\\'))) { + if ('}' != *(++ep)) + continue; - /* - * A denied conditional must evaluate its children if and only - * if they're either structurally required (such as loops and - * conditionals) or a closing macro. - */ + /* + * If we're at the end of line, then just chop + * off the \} and resize the buffer. + * If we aren't, then convert it to spaces. + */ - if (ROFFRULE_DENY == rr) - if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) - if (ROFF_ccond != t) - return(ROFF_IGN); + if ('\0' == *(ep + 1)) { + *--ep = '\0'; + *szp -= 2; + } else + *(ep - 1) = *ep = ' '; - assert(roffs[t].proc); - return((*roffs[t].proc)(r, t, bufp, szp, - ln, ppos, pos, offs)); + roff_ccond(r, ROFF_ccond, bufp, szp, + ln, pos, pos + 2, offs); + break; + } + return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); } /* ARGSUSED */ @@ -1059,9 +1130,61 @@ roff_cond_text(ROFF_ARGS) return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); } +static int +roff_getnum(const char *v, int *pos, int *res) +{ + int p, n; + + p = *pos; + n = v[p] == '-'; + if (n) + 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; + + *pos = p; + return 1; +} + +static int +roff_getop(const char *v, int *pos, char *res) +{ + int e; + + *res = v[*pos]; + e = v[*pos + 1] == '='; + + switch (*res) { + case '=': + break; + case '>': + if (e) + *res = 'g'; + break; + case '<': + if (e) + *res = 'l'; + break; + default: + return(0); + } + + *pos += 1 + e; + + return(*res); +} + static enum roffrule roff_evalcond(const char *v, int *pos) { + int not, lh, rh; + char op; switch (v[*pos]) { case ('n'): @@ -1074,13 +1197,47 @@ roff_evalcond(const char *v, int *pos) case ('t'): (*pos)++; return(ROFFRULE_DENY); + case ('!'): + (*pos)++; + not = 1; + break; default: + not = 0; break; } - while (v[*pos] && ' ' != v[*pos]) - (*pos)++; - return(ROFFRULE_DENY); + if (!roff_getnum(v, pos, &lh)) + return ROFFRULE_DENY; + if (!roff_getop(v, pos, &op)) { + if (lh < 0) + lh = 0; + goto out; + } + if (!roff_getnum(v, pos, &rh)) + return ROFFRULE_DENY; + switch (op) { + case 'g': + lh = lh >= rh; + break; + case 'l': + lh = lh <= rh; + break; + case '=': + lh = lh == rh; + break; + case '>': + lh = lh > rh; + break; + case '<': + lh = lh < rh; + break; + default: + return ROFFRULE_DENY; + } +out: + if (not) + lh = !lh; + return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY; } /* ARGSUSED */ @@ -1088,9 +1245,6 @@ static enum rofferr roff_line_ignore(ROFF_ARGS) { - if (ROFF_it == tok) - mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); - return(ROFF_IGN); } @@ -1098,8 +1252,8 @@ roff_line_ignore(ROFF_ARGS) static enum rofferr roff_cond(ROFF_ARGS) { - int sv; - enum roffrule rule; + + roffnode_push(r, tok, NULL, ln, ppos); /* * An `.el' has no conditional body: it will consume the value @@ -1109,31 +1263,11 @@ roff_cond(ROFF_ARGS) * If we're not an `el', however, then evaluate the conditional. */ - rule = ROFF_el == tok ? + r->last->rule = ROFF_el == tok ? (r->rstackpos < 0 ? ROFFRULE_DENY : r->rstack[r->rstackpos--]) : roff_evalcond(*bufp, &pos); - sv = pos; - while (' ' == (*bufp)[pos]) - pos++; - - /* - * Roff is weird. If we have just white-space after the - * conditional, it's considered the BODY and we exit without - * really doing anything. Warn about this. It's probably - * wrong. - */ - - if ('\0' == (*bufp)[pos] && sv != pos) { - mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); - return(ROFF_IGN); - } - - roffnode_push(r, tok, NULL, ln, ppos); - - r->last->rule = rule; - /* * An if-else will put the NEGATION of the current evaluated * conditional into the stack of rules. @@ -1156,28 +1290,39 @@ roff_cond(ROFF_ARGS) r->last->rule = ROFFRULE_DENY; /* - * Determine scope. If we're invoked with "\{" trailing the - * conditional, then we're in a multiline scope. Else our scope - * expires on the next line. + * Determine scope. + * If there is nothing on the line after the conditional, + * not even whitespace, use next-line scope. */ - r->last->endspan = 1; + if ('\0' == (*bufp)[pos]) { + r->last->endspan = 2; + goto out; + } + + while (' ' == (*bufp)[pos]) + pos++; + + /* An opening brace requests multiline scope. */ if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) { r->last->endspan = -1; pos += 2; + goto out; } /* - * If there are no arguments on the line, the next-line scope is - * assumed. + * Anything else following the conditional causes + * single-line scope. Warn if the scope contains + * nothing but trailing whitespace. */ if ('\0' == (*bufp)[pos]) - return(ROFF_IGN); + mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); - /* Otherwise re-run the roff parser after recalculating. */ + r->last->endspan = 1; +out: *offs = pos; return(ROFF_RERUN); } @@ -1213,25 +1358,71 @@ roff_ds(ROFF_ARGS) return(ROFF_IGN); } +void +roff_setreg(struct roff *r, const char *name, int val, char sign) +{ + struct roffreg *reg; + + /* Search for an existing register with the same name. */ + reg = r->regtab; + + while (reg && strcmp(name, reg->key.p)) + reg = reg->next; + + if (NULL == reg) { + /* Create a new register. */ + reg = mandoc_malloc(sizeof(struct roffreg)); + reg->key.p = mandoc_strdup(name); + reg->key.sz = strlen(name); + reg->val = 0; + reg->next = r->regtab; + r->regtab = reg; + } + + if ('+' == sign) + reg->val += val; + else if ('-' == sign) + reg->val -= val; + else + reg->val = val; +} + int -roff_regisset(const struct roff *r, enum regs reg) +roff_getreg(const struct roff *r, const char *name) { + struct roffreg *reg; + + for (reg = r->regtab; reg; reg = reg->next) + if (0 == strcmp(name, reg->key.p)) + return(reg->val); - return(r->regs[(int)reg].set); + return(0); } -unsigned int -roff_regget(const struct roff *r, enum regs reg) +static int +roff_getregn(const struct roff *r, const char *name, size_t len) { + struct roffreg *reg; - return(r->regs[(int)reg].u); + for (reg = r->regtab; reg; reg = reg->next) + if (len == reg->key.sz && + 0 == strncmp(name, reg->key.p, len)) + return(reg->val); + + return(0); } -void -roff_regunset(struct roff *r, enum regs reg) +static void +roff_freereg(struct roffreg *reg) { + struct roffreg *old_reg; - r->regs[(int)reg].set = 0; + while (NULL != reg) { + free(reg->key.p); + old_reg = reg; + reg = reg->next; + free(old_reg); + } } /* ARGSUSED */ @@ -1240,18 +1431,21 @@ roff_nr(ROFF_ARGS) { const char *key; char *val; + size_t sz; int iv; + char sign; val = *bufp + pos; key = roff_getname(r, &val, ln, pos); - if (0 == strcmp(key, "nS")) { - r->regs[(int)REG_nS].set = 1; - if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0) - r->regs[(int)REG_nS].u = (unsigned)iv; - else - r->regs[(int)REG_nS].u = 0u; - } + sign = *val; + if ('+' == sign || '-' == sign) + val++; + + sz = strspn(val, "0123456789"); + iv = sz ? mandoc_strntoi(val, sz, 10) : 0; + + roff_setreg(r, key, iv, sign); return(ROFF_IGN); } @@ -1274,6 +1468,57 @@ roff_rm(ROFF_ARGS) /* ARGSUSED */ static enum rofferr +roff_it(ROFF_ARGS) +{ + char *cp; + size_t len; + int iv; + + /* Parse the number of lines. */ + cp = *bufp + pos; + len = strcspn(cp, " \t"); + cp[len] = '\0'; + if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) { + mandoc_msg(MANDOCERR_NUMERIC, r->parse, + ln, ppos, *bufp + 1); + return(ROFF_IGN); + } + cp += len + 1; + + /* Arm the input line trap. */ + roffit_lines = iv; + roffit_macro = mandoc_strdup(cp); + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_Dd(ROFF_ARGS) +{ + const char *const *cp; + + if (MPARSE_MDOC != r->parsetype) + for (cp = __mdoc_reserved; *cp; cp++) + roff_setstr(r, *cp, NULL, 0); + + return(ROFF_CONT); +} + +/* ARGSUSED */ +static enum rofferr +roff_TH(ROFF_ARGS) +{ + const char *const *cp; + + if (MPARSE_MDOC != r->parsetype) + for (cp = __man_reserved; *cp; cp++) + roff_setstr(r, *cp, NULL, 0); + + return(ROFF_CONT); +} + +/* ARGSUSED */ +static enum rofferr roff_TE(ROFF_ARGS) { @@ -1352,21 +1597,38 @@ roff_EN(ROFF_ARGS) static enum rofferr roff_TS(ROFF_ARGS) { - struct tbl_node *t; + struct tbl_node *tbl; if (r->tbl) { mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL); tbl_end(&r->tbl); } - t = tbl_alloc(ppos, ln, r->parse); + tbl = tbl_alloc(ppos, ln, r->parse); if (r->last_tbl) - r->last_tbl->next = t; + r->last_tbl->next = tbl; else - r->first_tbl = r->last_tbl = t; + r->first_tbl = r->last_tbl = tbl; + + r->tbl = r->last_tbl = tbl; + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_cc(ROFF_ARGS) +{ + const char *p; + + p = *bufp + pos; + + if ('\0' == *p || '.' == (r->control = *p++)) + r->control = 0; + + if ('\0' != *p) + mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL); - r->tbl = r->last_tbl = t; return(ROFF_IGN); } @@ -1470,7 +1732,7 @@ roff_userdef(ROFF_ARGS) /* * Collect pointers to macro argument strings - * and null-terminate them. + * and NUL-terminate them. */ cp = *bufp + pos; for (i = 0; i < 9; i++) @@ -1766,3 +2028,38 @@ roff_strdup(const struct roff *r, const char *p) res[(int)ssz] = '\0'; return(res); } + +/* + * 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 (0 != r->control && cp[pos] == r->control) + pos++; + else if (0 != r->control) + 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); +} diff --git a/contrib/mdocml/st.in b/contrib/mdocml/st.in index 3ba41dd..c52ddab 100644 --- a/contrib/mdocml/st.in +++ b/contrib/mdocml/st.in @@ -1,4 +1,4 @@ -/* $Id: st.in,v 1.19 2012/02/26 21:47:09 schwarze Exp $ */ +/* $Id: st.in,v 1.22 2013/12/25 14:09:32 schwarze Exp $ */ /* * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -35,16 +35,19 @@ 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.1\\(rq)") -LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1\\(rq)") -LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1\\(rq)") -LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1\\(rq)") -LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(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.1d-99", "IEEE Std 1003.1d-1999 (\\(lqPOSIX.1d\\(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.1j-2000", "IEEE Std 1003.1j-2000 (\\(lqPOSIX.1j\\(rq)") +LINE("-p1003.1q-2000", "IEEE Std 1003.1q-2000 (\\(lqPOSIX.1q\\(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("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)") -LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)") LINE("-p1387.2", "IEEE Std 1387.2 (\\(lqPOSIX.7.2\\(rq)") +LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.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)") @@ -68,11 +71,12 @@ LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\ LINE("-xpg4.3", "X/Open Portability Guide Issue\\~4, Version\\~3 (\\(lqXPG4.3\\(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("-xns5.2d2.0", "X/Open Networking Services Issue\\~5.2 Draft\\~2.0 (\\(lqXNS5.2D2.0\\(rq)") LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)") -LINE("-susv2", "Version\\~2 of the Single UNIX Specification") -LINE("-susv3", "Version\\~3 of the Single UNIX Specification") +LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)") +LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)") LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)") diff --git a/contrib/mdocml/tbl.7 b/contrib/mdocml/tbl.7 index ea3d2ba..d4c829b 100644 --- a/contrib/mdocml/tbl.7 +++ b/contrib/mdocml/tbl.7 @@ -1,4 +1,4 @@ -.\" $Id: tbl.7,v 1.16 2011/09/03 00:29:21 kristaps Exp $ +.\" $Id: tbl.7,v 1.18 2013/09/16 22:39:19 schwarze Exp $ .\" .\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 3 2011 $ +.Dd $Mdocdate: September 16 2013 $ .Dt TBL 7 .Os .Sh NAME @@ -69,13 +69,6 @@ c5 c5 c5. 4:5:6 .TE .Ed -.Pp -The -.Nm -implementation in -.Xr mandoc 1 -is -.Ud .Sh TABLE STRUCTURE Tables are enclosed by the .Sq TS @@ -344,5 +337,4 @@ utility. This .Nm reference was written by -.An Kristaps Dzonsons , -.Mt kristaps@bsd.lv . +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . diff --git a/contrib/mdocml/tbl.c b/contrib/mdocml/tbl.c index b3d651b..b244ac8 100644 --- a/contrib/mdocml/tbl.c +++ b/contrib/mdocml/tbl.c @@ -1,4 +1,4 @@ -/* $Id: tbl.c,v 1.26 2011/07/25 15:37:00 kristaps Exp $ */ +/* $Id: tbl.c,v 1.27 2013/05/31 22:08:09 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -72,21 +72,21 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs) struct tbl_node * tbl_alloc(int pos, int line, struct mparse *parse) { - struct tbl_node *p; - - p = mandoc_calloc(1, sizeof(struct tbl_node)); - p->line = line; - p->pos = pos; - p->parse = parse; - p->part = TBL_PART_OPTS; - p->opts.tab = '\t'; - p->opts.linesize = 12; - p->opts.decimal = '.'; - return(p); + struct tbl_node *tbl; + + tbl = mandoc_calloc(1, sizeof(struct tbl_node)); + tbl->line = line; + tbl->pos = pos; + tbl->parse = parse; + tbl->part = TBL_PART_OPTS; + tbl->opts.tab = '\t'; + tbl->opts.linesize = 12; + tbl->opts.decimal = '.'; + return(tbl); } void -tbl_free(struct tbl_node *p) +tbl_free(struct tbl_node *tbl) { struct tbl_row *rp; struct tbl_cell *cp; @@ -94,8 +94,8 @@ tbl_free(struct tbl_node *p) struct tbl_dat *dp; struct tbl_head *hp; - while (NULL != (rp = p->first_row)) { - p->first_row = rp->next; + while (NULL != (rp = tbl->first_row)) { + tbl->first_row = rp->next; while (rp->first) { cp = rp->first; rp->first = cp->next; @@ -104,8 +104,8 @@ tbl_free(struct tbl_node *p) free(rp); } - while (NULL != (sp = p->first_span)) { - p->first_span = sp->next; + while (NULL != (sp = tbl->first_span)) { + tbl->first_span = sp->next; while (sp->first) { dp = sp->first; sp->first = dp->next; @@ -116,12 +116,12 @@ tbl_free(struct tbl_node *p) free(sp); } - while (NULL != (hp = p->first_head)) { - p->first_head = hp->next; + while (NULL != (hp = tbl->first_head)) { + tbl->first_head = hp->next; free(hp); } - free(p); + free(tbl); } void diff --git a/contrib/mdocml/tbl_data.c b/contrib/mdocml/tbl_data.c index 129695d..7413aa2 100644 --- a/contrib/mdocml/tbl_data.c +++ b/contrib/mdocml/tbl_data.c @@ -1,4 +1,4 @@ -/* $Id: tbl_data.c,v 1.24 2011/03/20 16:02:05 kristaps Exp $ */ +/* $Id: tbl_data.c,v 1.27 2013/06/01 04:56:50 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -49,13 +49,11 @@ data(struct tbl_node *tbl, struct tbl_span *dp, cp = dp->layout->first; /* - * Skip over spanners and vertical lines to data formats, since + * Skip over spanners, since * we want to match data with data layout cells in the header. */ - while (cp && (TBL_CELL_VERT == cp->pos || - TBL_CELL_DVERT == cp->pos || - TBL_CELL_SPAN == cp->pos)) + while (cp && TBL_CELL_SPAN == cp->pos) cp = cp->next; /* @@ -104,7 +102,7 @@ data(struct tbl_node *tbl, struct tbl_span *dp, if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) { tbl->part = TBL_PART_CDATA; - return(0); + return(1); } assert(*pos - sv >= 0); @@ -187,7 +185,7 @@ newspan(struct tbl_node *tbl, int line, struct tbl_row *rp) dp = mandoc_calloc(1, sizeof(struct tbl_span)); dp->line = line; - dp->tbl = &tbl->opts; + dp->opts = &tbl->opts; dp->layout = rp; dp->head = tbl->first_head; diff --git a/contrib/mdocml/tbl_html.c b/contrib/mdocml/tbl_html.c index 8e7dc05..6b8ced7 100644 --- a/contrib/mdocml/tbl_html.c +++ b/contrib/mdocml/tbl_html.c @@ -1,4 +1,4 @@ -/* $Id: tbl_html.c,v 1.9 2011/09/18 14:14:15 schwarze Exp $ */ +/* $Id: tbl_html.c,v 1.10 2012/05/27 17:54:54 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -119,20 +119,12 @@ print_tbl(struct html *h, const struct tbl_span *sp) print_stagq(h, tt); print_otag(h, TAG_TD, 0, NULL); - switch (hp->pos) { - case (TBL_HEAD_VERT): - /* FALLTHROUGH */ - case (TBL_HEAD_DVERT): - continue; - case (TBL_HEAD_DATA): - if (NULL == dp) - break; - if (TBL_CELL_DOWN != dp->layout->pos) - if (dp->string) - print_text(h, dp->string); - dp = dp->next; + if (NULL == dp) break; - } + if (TBL_CELL_DOWN != dp->layout->pos) + if (dp->string) + print_text(h, dp->string); + dp = dp->next; } break; } diff --git a/contrib/mdocml/tbl_layout.c b/contrib/mdocml/tbl_layout.c index 7601f14..6cce977 100644 --- a/contrib/mdocml/tbl_layout.c +++ b/contrib/mdocml/tbl_layout.c @@ -1,6 +1,7 @@ -/* $Id: tbl_layout.c,v 1.22 2011/09/18 14:14:15 schwarze Exp $ */ +/* $Id: tbl_layout.c,v 1.23 2012/05/27 17:54:54 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2012 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 @@ -51,8 +52,7 @@ static const struct tbl_phrase keys[KEYS_MAX] = { { '^', TBL_CELL_DOWN }, { '-', TBL_CELL_HORIZ }, { '_', TBL_CELL_HORIZ }, - { '=', TBL_CELL_DHORIZ }, - { '|', TBL_CELL_VERT } + { '=', TBL_CELL_DHORIZ } }; static int mods(struct tbl_node *, struct tbl_cell *, @@ -60,10 +60,8 @@ static int mods(struct tbl_node *, struct tbl_cell *, static int cell(struct tbl_node *, struct tbl_row *, int, const char *, int *); static void row(struct tbl_node *, int, const char *, int *); -static struct tbl_cell *cell_alloc(struct tbl_node *, - struct tbl_row *, enum tbl_cellt); -static void head_adjust(const struct tbl_cell *, - struct tbl_head *); +static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *, + enum tbl_cellt, int vert); static int mods(struct tbl_node *tbl, struct tbl_cell *cp, @@ -80,10 +78,6 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp, case (TBL_CELL_HORIZ): /* FALLTHROUGH */ case (TBL_CELL_DHORIZ): - /* FALLTHROUGH */ - case (TBL_CELL_VERT): - /* FALLTHROUGH */ - case (TBL_CELL_DVERT): return(1); default: break; @@ -214,10 +208,17 @@ static int cell(struct tbl_node *tbl, struct tbl_row *rp, int ln, const char *p, int *pos) { - int i; + int vert, i; enum tbl_cellt c; - /* Parse the column position (`r', `R', `|', ...). */ + /* Handle vertical lines. */ + + for (vert = 0; '|' == p[*pos]; ++*pos) + vert++; + while (' ' == p[*pos]) + (*pos)++; + + /* Parse the column position (`c', `l', `r', ...). */ for (i = 0; i < KEYS_MAX; i++) if (tolower((unsigned char)p[*pos]) == keys[i].name) @@ -246,8 +247,6 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, return(0); } else if (rp->last) switch (rp->last->pos) { - case (TBL_CELL_VERT): - case (TBL_CELL_DVERT): case (TBL_CELL_HORIZ): case (TBL_CELL_DHORIZ): mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, @@ -270,25 +269,16 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, (*pos)++; - /* Extra check for the double-vertical. */ - - if (TBL_CELL_VERT == c && '|' == p[*pos]) { - (*pos)++; - c = TBL_CELL_DVERT; - } - /* Disallow adjacent spacers. */ - if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) && - (TBL_CELL_VERT == rp->last->pos || - TBL_CELL_DVERT == rp->last->pos)) { + if (vert > 2) { mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL); return(0); } /* Allocate cell then parse its modifiers. */ - return(mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos)); + return(mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos)); } @@ -308,11 +298,11 @@ row: /* */ rp = mandoc_calloc(1, sizeof(struct tbl_row)); - if (tbl->last_row) { + if (tbl->last_row) tbl->last_row->next = rp; - tbl->last_row = rp; - } else - tbl->last_row = tbl->first_row = rp; + else + tbl->first_row = rp; + tbl->last_row = rp; cell: while (isspace((unsigned char)p[*pos])) @@ -357,7 +347,8 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p) } static struct tbl_cell * -cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) +cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos, + int vert) { struct tbl_cell *p, *pp; struct tbl_head *h, *hp; @@ -365,108 +356,35 @@ cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) p = mandoc_calloc(1, sizeof(struct tbl_cell)); if (NULL != (pp = rp->last)) { - rp->last->next = p; - rp->last = p; - } else - rp->last = rp->first = p; + pp->next = p; + h = pp->head->next; + } else { + rp->first = p; + h = tbl->first_head; + } + rp->last = p; p->pos = pos; + p->vert = vert; - /* - * This is a little bit complicated. Here we determine the - * header the corresponds to a cell. We add headers dynamically - * when need be or re-use them, otherwise. As an example, given - * the following: - * - * 1 c || l - * 2 | c | l - * 3 l l - * 3 || c | l |. - * - * We first add the new headers (as there are none) in (1); then - * in (2) we insert the first spanner (as it doesn't match up - * with the header); then we re-use the prior data headers, - * skipping over the spanners; then we re-use everything and add - * a last spanner. Note that VERT headers are made into DVERT - * ones. - */ - - h = pp ? pp->head->next : tbl->first_head; + /* Re-use header. */ if (h) { - /* Re-use data header. */ - if (TBL_HEAD_DATA == h->pos && - (TBL_CELL_VERT != p->pos && - TBL_CELL_DVERT != p->pos)) { - p->head = h; - return(p); - } - - /* Re-use spanner header. */ - if (TBL_HEAD_DATA != h->pos && - (TBL_CELL_VERT == p->pos || - TBL_CELL_DVERT == p->pos)) { - head_adjust(p, h); - p->head = h; - return(p); - } - - /* Right-shift headers with a new spanner. */ - if (TBL_HEAD_DATA == h->pos && - (TBL_CELL_VERT == p->pos || - TBL_CELL_DVERT == p->pos)) { - hp = mandoc_calloc(1, sizeof(struct tbl_head)); - hp->ident = tbl->opts.cols++; - hp->prev = h->prev; - if (h->prev) - h->prev->next = hp; - if (h == tbl->first_head) - tbl->first_head = hp; - h->prev = hp; - hp->next = h; - head_adjust(p, hp); - p->head = hp; - return(p); - } - - if (NULL != (h = h->next)) { - head_adjust(p, h); - p->head = h; - return(p); - } - - /* Fall through to default case... */ + p->head = h; + return(p); } hp = mandoc_calloc(1, sizeof(struct tbl_head)); hp->ident = tbl->opts.cols++; + hp->vert = vert; if (tbl->last_head) { hp->prev = tbl->last_head; tbl->last_head->next = hp; - tbl->last_head = hp; } else - tbl->last_head = tbl->first_head = hp; + tbl->first_head = hp; + tbl->last_head = hp; - head_adjust(p, hp); p->head = hp; return(p); } - -static void -head_adjust(const struct tbl_cell *cellp, struct tbl_head *head) -{ - if (TBL_CELL_VERT != cellp->pos && - TBL_CELL_DVERT != cellp->pos) { - head->pos = TBL_HEAD_DATA; - return; - } - - if (TBL_CELL_VERT == cellp->pos) - if (TBL_HEAD_DVERT != head->pos) - head->pos = TBL_HEAD_VERT; - - if (TBL_CELL_DVERT == cellp->pos) - head->pos = TBL_HEAD_DVERT; -} - diff --git a/contrib/mdocml/tbl_term.c b/contrib/mdocml/tbl_term.c index f1928f0..e8411ff 100644 --- a/contrib/mdocml/tbl_term.c +++ b/contrib/mdocml/tbl_term.c @@ -1,7 +1,7 @@ -/* $Id: tbl_term.c,v 1.21 2011/09/20 23:05:49 schwarze Exp $ */ +/* $Id: tbl_term.c,v 1.25 2013/05/31 21:37:17 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2012 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 @@ -31,14 +31,14 @@ static size_t term_tbl_len(size_t, void *); static size_t term_tbl_strlen(const char *, void *); static void tbl_char(struct termp *, char, size_t); -static void tbl_data(struct termp *, const struct tbl *, +static void tbl_data(struct termp *, const struct tbl_opts *, const struct tbl_dat *, const struct roffcol *); static size_t tbl_rulewidth(struct termp *, const struct tbl_head *); static void tbl_hframe(struct termp *, 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 *, +static void tbl_number(struct termp *, const struct tbl_opts *, const struct tbl_dat *, const struct roffcol *); static void tbl_hrule(struct termp *, const struct tbl_span *); @@ -96,16 +96,16 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) /* Horizontal frame at the start of boxed tables. */ if (TBL_SPAN_FIRST & sp->flags) { - if (TBL_OPT_DBOX & sp->tbl->opts) + if (TBL_OPT_DBOX & sp->opts->opts) tbl_hframe(tp, sp, 1); - if (TBL_OPT_DBOX & sp->tbl->opts || - TBL_OPT_BOX & sp->tbl->opts) + if (TBL_OPT_DBOX & sp->opts->opts || + TBL_OPT_BOX & sp->opts->opts) tbl_hframe(tp, sp, 0); } /* Vertical frame at the start of each row. */ - if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts) + if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts) term_word(tp, TBL_SPAN_HORIZ == sp->pos || TBL_SPAN_DHORIZ == sp->pos ? "+" : "|"); @@ -126,49 +126,23 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) dp = sp->first; spans = 0; for (hp = sp->head; hp; hp = hp->next) { + /* * If the current data header is invoked during * a spanner ("spans" > 0), don't emit anything * at all. */ - switch (hp->pos) { - case (TBL_HEAD_VERT): - /* FALLTHROUGH */ - case (TBL_HEAD_DVERT): - if (spans <= 0) - tbl_vrule(tp, hp); - continue; - case (TBL_HEAD_DATA): - break; - } if (--spans >= 0) continue; - /* - * All cells get a leading blank, except the - * first one and those after double rulers. - */ + /* Separate columns. */ - if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos) - tbl_char(tp, ASCII_NBRSP, 1); + if (NULL != hp->prev) + tbl_vrule(tp, hp); col = &tp->tbl.cols[hp->ident]; - tbl_data(tp, sp->tbl, dp, col); - - /* No trailing blanks. */ - - if (NULL == hp->next) - break; - - /* - * Add another blank between cells, - * or two when there is no vertical ruler. - */ - - tbl_char(tp, ASCII_NBRSP, - TBL_HEAD_VERT == hp->next->pos || - TBL_HEAD_DVERT == hp->next->pos ? 1 : 2); + tbl_data(tp, sp->opts, dp, col); /* * Go to the next data cell and assign the @@ -185,7 +159,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) /* Vertical frame at the end of each row. */ - if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts) + if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts) term_word(tp, TBL_SPAN_HORIZ == sp->pos || TBL_SPAN_DHORIZ == sp->pos ? "+" : " |"); term_flushln(tp); @@ -196,11 +170,15 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) */ if (TBL_SPAN_LAST & sp->flags) { - if (TBL_OPT_DBOX & sp->tbl->opts || - TBL_OPT_BOX & sp->tbl->opts) + if (TBL_OPT_DBOX & sp->opts->opts || + TBL_OPT_BOX & sp->opts->opts) { tbl_hframe(tp, sp, 0); - if (TBL_OPT_DBOX & sp->tbl->opts) + tp->skipvsp = 1; + } + if (TBL_OPT_DBOX & sp->opts->opts) { tbl_hframe(tp, sp, 1); + tp->skipvsp = 2; + } assert(tp->tbl.cols); free(tp->tbl.cols); tp->tbl.cols = NULL; @@ -222,17 +200,14 @@ tbl_rulewidth(struct termp *tp, const struct tbl_head *hp) size_t width; width = tp->tbl.cols[hp->ident].width; - if (TBL_HEAD_DATA == hp->pos) { - /* Account for leading blanks. */ - if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos) - width++; - /* Account for trailing blanks. */ - width++; - if (hp->next && - TBL_HEAD_VERT != hp->next->pos && - TBL_HEAD_DVERT != hp->next->pos) - width++; - } + + /* Account for leading blanks. */ + if (hp->prev) + width += 2 - hp->vert; + + /* Account for trailing blank. */ + width++; + return(width); } @@ -250,10 +225,11 @@ tbl_hrule(struct termp *tp, const struct tbl_span *sp) if (TBL_SPAN_DHORIZ == sp->pos) c = '='; - for (hp = sp->head; hp; hp = hp->next) - tbl_char(tp, - TBL_HEAD_DATA == hp->pos ? c : '+', - tbl_rulewidth(tp, hp)); + for (hp = sp->head; hp; hp = hp->next) { + if (hp->prev && hp->vert) + tbl_char(tp, '+', hp->vert); + tbl_char(tp, c, tbl_rulewidth(tp, hp)); + } } /* @@ -268,16 +244,17 @@ tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer) const struct tbl_head *hp; term_word(tp, "+"); - for (hp = sp->head; hp; hp = hp->next) - tbl_char(tp, - outer || TBL_HEAD_DATA == hp->pos ? '-' : '+', - tbl_rulewidth(tp, hp)); + for (hp = sp->head; hp; hp = hp->next) { + if (hp->prev && hp->vert) + tbl_char(tp, (outer ? '-' : '+'), hp->vert); + tbl_char(tp, '-', tbl_rulewidth(tp, hp)); + } term_word(tp, "+"); term_flushln(tp); } static void -tbl_data(struct termp *tp, const struct tbl *tbl, +tbl_data(struct termp *tp, const struct tbl_opts *opts, const struct tbl_dat *dp, const struct roffcol *col) { @@ -323,7 +300,7 @@ tbl_data(struct termp *tp, const struct tbl *tbl, tbl_literal(tp, dp, col); break; case (TBL_CELL_NUMBER): - tbl_number(tp, tbl, dp, col); + tbl_number(tp, opts, dp, col); break; case (TBL_CELL_DOWN): tbl_char(tp, ASCII_NBRSP, col->width); @@ -338,16 +315,11 @@ static void tbl_vrule(struct termp *tp, const struct tbl_head *hp) { - switch (hp->pos) { - case (TBL_HEAD_VERT): - term_word(tp, "|"); - break; - case (TBL_HEAD_DVERT): - term_word(tp, "||"); - break; - default: - break; - } + tbl_char(tp, ASCII_NBRSP, 1); + if (0 < hp->vert) + tbl_char(tp, '|', hp->vert); + if (2 > hp->vert) + tbl_char(tp, ASCII_NBRSP, 2 - hp->vert); } static void @@ -369,11 +341,19 @@ static void tbl_literal(struct termp *tp, const struct tbl_dat *dp, const struct roffcol *col) { - size_t len, padl, padr; + struct tbl_head *hp; + size_t width, len, padl, padr; + int spans; assert(dp->string); len = term_strlen(tp, dp->string); - padr = col->width > len ? col->width - len : 0; + + hp = dp->layout->head->next; + width = col->width; + for (spans = dp->spans; spans--; hp = hp->next) + width += tp->tbl.cols[hp->ident].width + 3; + + padr = width > len ? width - len : 0; padl = 0; switch (dp->layout->pos) { @@ -401,7 +381,7 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp, } static void -tbl_number(struct termp *tp, const struct tbl *tbl, +tbl_number(struct termp *tp, const struct tbl_opts *opts, const struct tbl_dat *dp, const struct roffcol *col) { @@ -419,12 +399,12 @@ tbl_number(struct termp *tp, const struct tbl *tbl, sz = term_strlen(tp, dp->string); - buf[0] = tbl->decimal; + buf[0] = opts->decimal; buf[1] = '\0'; psz = term_strlen(tp, buf); - if (NULL != (cp = strrchr(dp->string, tbl->decimal))) { + if (NULL != (cp = strrchr(dp->string, opts->decimal))) { buf[1] = '\0'; for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { buf[0] = dp->string[i]; diff --git a/contrib/mdocml/term.c b/contrib/mdocml/term.c index 4ca15ed..e7b9557 100644 --- a/contrib/mdocml/term.c +++ b/contrib/mdocml/term.c @@ -1,7 +1,7 @@ -/* $Id: term.c,v 1.201 2011/09/21 09:57:13 schwarze Exp $ */ +/* $Id: term.c,v 1.214 2013/12/25 00:39:31 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,7 +33,8 @@ #include "term.h" #include "main.h" -static void adjbuf(struct termp *p, int); +static size_t cond_width(const struct termp *, int, int *); +static void adjbuf(struct termp *p, size_t); static void bufferc(struct termp *, char); static void encode(struct termp *, const char *, size_t); static void encode1(struct termp *, int); @@ -82,9 +83,8 @@ term_end(struct termp *p) * - TERMP_NOBREAK: this is the most important and is used when making * columns. In short: don't print a newline and instead expect the * next call to do the padding up to the start of the next column. - * - * - TERMP_TWOSPACE: make sure there is room for at least two space - * characters of padding. Otherwise, rather break the line. + * p->trailspace may be set to 0, 1, or 2, depending on how many + * space characters are required at the end of the column. * * - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and * the line is overrun, and don't pad-right if it's underrun. @@ -104,14 +104,15 @@ term_end(struct termp *p) void term_flushln(struct termp *p) { - int i; /* current input position in p->buf */ + size_t i; /* current input position in p->buf */ + int ntab; /* number of tabs to prepend */ size_t vis; /* current visual position on output */ size_t vbl; /* number of blanks to prepend to output */ size_t vend; /* end of word visual position on output */ size_t bp; /* visual right border position */ size_t dv; /* temporary for visual pos calculations */ - int j; /* temporary loop index for p->buf */ - int jhy; /* last hyph before overflow w/r/t j */ + size_t j; /* temporary loop index for p->buf */ + size_t jhy; /* last hyph before overflow w/r/t j */ size_t maxvis; /* output position of visible boundary */ size_t mmax; /* used in calculating bp */ @@ -119,7 +120,12 @@ term_flushln(struct termp *p) * First, establish the maximum columns of "visible" content. * This is usually the difference between the right-margin and * an indentation, but can be, for tagged lists or columns, a - * small set of values. + * small set of values. + * + * The following unsigned-signed subtractions look strange, + * but they are actually correct. If the int p->overstep + * is negative, it gets sign extended. Subtracting that + * very large size_t effectively adds a small number to dv. */ assert (p->rmargin >= p->offset); dv = p->rmargin - p->offset; @@ -143,10 +149,12 @@ term_flushln(struct termp *p) * Handle literal tab characters: collapse all * subsequent tabs into a single huge set of spaces. */ + ntab = 0; while (i < p->col && '\t' == p->buf[i]) { vend = (vis / p->tabwidth + 1) * p->tabwidth; vbl += vend - vis; vis = vend; + ntab++; i++; } @@ -158,7 +166,7 @@ term_flushln(struct termp *p) */ for (j = i, jhy = 0; j < p->col; j++) { - if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j]) + if (' ' == p->buf[j] || '\t' == p->buf[j]) break; /* Back over the the last printed character. */ @@ -191,7 +199,16 @@ term_flushln(struct termp *p) } else vbl = p->offset; - /* Remove the p->overstep width. */ + /* use pending tabs on the new line */ + + if (0 < ntab) + vbl += ntab * p->tabwidth; + + /* + * Remove the p->overstep width. + * Again, if p->overstep is negative, + * sign extension does the right thing. + */ bp += (size_t)p->overstep; p->overstep = 0; @@ -207,7 +224,7 @@ term_flushln(struct termp *p) j = i; while (' ' == p->buf[i]) i++; - dv = (size_t)(i - j) * (*p->width)(p, ' '); + dv = (i - j) * (*p->width)(p, ' '); vbl += dv; vend += dv; break; @@ -260,20 +277,17 @@ term_flushln(struct termp *p) } if (TERMP_HANG & p->flags) { - /* We need one blank after the tag. */ - p->overstep = (int)(vis - maxvis + (*p->width)(p, ' ')); + p->overstep = (int)(vis - maxvis + + p->trailspace * (*p->width)(p, ' ')); /* - * Behave exactly the same way as groff: * If we have overstepped the margin, temporarily move * it to the right and flag the rest of the line to be * shorter. - * If we landed right at the margin, be happy. - * If we are one step before the margin, temporarily - * move it one step LEFT and flag the rest of the line - * to be longer. + * If there is a request to keep the columns together, + * allow negative overstep when the column is not full. */ - if (p->overstep < -1) + if (p->trailspace && p->overstep < 0) p->overstep = 0; return; @@ -281,8 +295,7 @@ term_flushln(struct termp *p) return; /* If the column was overrun, break the line. */ - if (maxvis <= vis + - ((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) { + if (maxvis < vis + p->trailspace * (*p->width)(p, ' ')) { (*p->endline)(p); p->viscol = 0; } @@ -316,7 +329,10 @@ term_vspace(struct termp *p) term_newln(p); p->viscol = 0; - (*p->endline)(p); + if (0 < p->skipvsp) + p->skipvsp--; + else + (*p->endline)(p); } void @@ -369,7 +385,7 @@ void term_fontpopq(struct termp *p, const void *key) { - while (p->fonti >= 0 && key != &p->fontq[p->fonti]) + while (p->fonti >= 0 && key < (void *)(p->fontq + p->fonti)) p->fonti--; assert(p->fonti >= 0); } @@ -391,6 +407,7 @@ term_fontpop(struct termp *p) void term_word(struct termp *p, const char *word) { + const char nbrsp[2] = { ASCII_NBRSP, 0 }; const char *seq, *cp; char c; int sz, uc; @@ -399,29 +416,42 @@ term_word(struct termp *p, const char *word) if ( ! (TERMP_NOSPACE & p->flags)) { if ( ! (TERMP_KEEP & p->flags)) { - if (TERMP_PREKEEP & p->flags) - p->flags |= TERMP_KEEP; bufferc(p, ' '); if (TERMP_SENTENCE & p->flags) bufferc(p, ' '); } else bufferc(p, ASCII_NBRSP); } + if (TERMP_PREKEEP & p->flags) + p->flags |= TERMP_KEEP; if ( ! (p->flags & TERMP_NONOSPACE)) p->flags &= ~TERMP_NOSPACE; else p->flags |= TERMP_NOSPACE; - p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM); + p->flags &= ~TERMP_SENTENCE; while ('\0' != *word) { - if ((ssz = strcspn(word, "\\")) > 0) + if ('\\' != *word) { + if (TERMP_SKIPCHAR & p->flags) { + p->flags &= ~TERMP_SKIPCHAR; + word++; + continue; + } + 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; - if ('\\' != *word) + word += (int)ssz; continue; + } word++; esc = mandoc_escape(&word, &seq, &sz); @@ -468,6 +498,9 @@ term_word(struct termp *p, const char *word) case (ESCAPE_FONTITALIC): term_fontrepl(p, TERMFONT_UNDER); break; + case (ESCAPE_FONTBI): + term_fontrepl(p, TERMFONT_BI); + break; case (ESCAPE_FONT): /* FALLTHROUGH */ case (ESCAPE_FONTROMAN): @@ -477,17 +510,23 @@ term_word(struct termp *p, const char *word) term_fontlast(p); break; case (ESCAPE_NOSPACE): - if ('\0' == *word) + if (TERMP_SKIPCHAR & p->flags) + p->flags &= ~TERMP_SKIPCHAR; + else if ('\0' == *word) p->flags |= TERMP_NOSPACE; break; + case (ESCAPE_SKIPCHAR): + p->flags |= TERMP_SKIPCHAR; + break; default: break; } } + p->flags &= ~TERMP_NBRWORD; } static void -adjbuf(struct termp *p, int sz) +adjbuf(struct termp *p, size_t sz) { if (0 == p->maxcols) @@ -495,8 +534,7 @@ adjbuf(struct termp *p, int sz) while (sz >= p->maxcols) p->maxcols <<= 2; - p->buf = mandoc_realloc - (p->buf, sizeof(int) * (size_t)p->maxcols); + p->buf = mandoc_realloc(p->buf, sizeof(int) * p->maxcols); } static void @@ -519,31 +557,39 @@ encode1(struct termp *p, int c) { enum termfont f; - if (p->col + 4 >= p->maxcols) - adjbuf(p, p->col + 4); + if (TERMP_SKIPCHAR & p->flags) { + p->flags &= ~TERMP_SKIPCHAR; + return; + } + + if (p->col + 6 >= p->maxcols) + adjbuf(p, p->col + 6); f = term_fonttop(p); - if (TERMFONT_NONE == f) { - p->buf[p->col++] = c; - return; - } else if (TERMFONT_UNDER == f) { + if (TERMFONT_UNDER == f || TERMFONT_BI == f) { p->buf[p->col++] = '_'; - } else - p->buf[p->col++] = c; - - p->buf[p->col++] = 8; + p->buf[p->col++] = 8; + } + if (TERMFONT_BOLD == f || TERMFONT_BI == f) { + if (ASCII_HYPH == c) + p->buf[p->col++] = '-'; + else + p->buf[p->col++] = c; + p->buf[p->col++] = 8; + } p->buf[p->col++] = c; } static void encode(struct termp *p, const char *word, size_t sz) { - enum termfont f; - int i, len; + size_t i; - /* LINTED */ - len = sz; + if (TERMP_SKIPCHAR & p->flags) { + p->flags &= ~TERMP_SKIPCHAR; + return; + } /* * Encode and buffer a string of characters. If the current @@ -551,35 +597,25 @@ encode(struct termp *p, const char *word, size_t sz) * character by character. */ - if (TERMFONT_NONE == (f = term_fonttop(p))) { - if (p->col + len >= p->maxcols) - adjbuf(p, p->col + len); - for (i = 0; i < len; i++) + if (TERMFONT_NONE == term_fonttop(p)) { + if (p->col + sz >= p->maxcols) + adjbuf(p, p->col + sz); + for (i = 0; i < sz; i++) p->buf[p->col++] = word[i]; return; } /* Pre-buffer, assuming worst-case. */ - if (p->col + 1 + (len * 3) >= p->maxcols) - adjbuf(p, p->col + 1 + (len * 3)); - - for (i = 0; i < len; i++) { - if (ASCII_HYPH != word[i] && - ! isgraph((unsigned char)word[i])) { - p->buf[p->col++] = word[i]; - continue; - } + if (p->col + 1 + (sz * 5) >= p->maxcols) + adjbuf(p, p->col + 1 + (sz * 5)); - if (TERMFONT_UNDER == f) - p->buf[p->col++] = '_'; - else if (ASCII_HYPH == word[i]) - p->buf[p->col++] = '-'; + for (i = 0; i < sz; i++) { + if (ASCII_HYPH == word[i] || + isgraph((unsigned char)word[i])) + encode1(p, word[i]); else p->buf[p->col++] = word[i]; - - p->buf[p->col++] = 8; - p->buf[p->col++] = word[i]; } } @@ -590,12 +626,22 @@ 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, c; + int ssz, skip, c; const char *seq, *rhs; enum mandoc_esc esc; static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' }; @@ -607,10 +653,11 @@ term_strlen(const struct termp *p, const char *cp) */ sz = 0; + skip = 0; while ('\0' != *cp) { rsz = strcspn(cp, rej); for (i = 0; i < rsz; i++) - sz += (*p->width)(p, *cp++); + sz += cond_width(p, *cp++, &skip); c = 0; switch (*cp) { @@ -627,14 +674,14 @@ term_strlen(const struct termp *p, const char *cp) (seq + 1, ssz - 1); if ('\0' == c) break; - sz += (*p->width)(p, c); + sz += cond_width(p, c, &skip); continue; case (ESCAPE_SPECIAL): c = mchars_spec2cp (p->symtab, seq, ssz); if (c <= 0) break; - sz += (*p->width)(p, c); + sz += cond_width(p, c, &skip); continue; default: break; @@ -644,12 +691,12 @@ term_strlen(const struct termp *p, const char *cp) switch (esc) { case (ESCAPE_UNICODE): - sz += (*p->width)(p, '?'); + sz += cond_width(p, '?', &skip); break; case (ESCAPE_NUMBERED): c = mchars_num2char(seq, ssz); if ('\0' != c) - sz += (*p->width)(p, c); + sz += cond_width(p, c, &skip); break; case (ESCAPE_SPECIAL): rhs = mchars_spec2str @@ -661,6 +708,9 @@ term_strlen(const struct termp *p, const char *cp) rhs = seq; rsz = ssz; break; + case (ESCAPE_SKIPCHAR): + skip = 1; + break; default: break; } @@ -668,15 +718,20 @@ term_strlen(const struct termp *p, const char *cp) if (NULL == rhs) break; + if (skip) { + skip = 0; + break; + } + for (i = 0; i < rsz; i++) sz += (*p->width)(p, *rhs++); break; case (ASCII_NBRSP): - sz += (*p->width)(p, ' '); + sz += cond_width(p, ' ', &skip); cp++; break; case (ASCII_HYPH): - sz += (*p->width)(p, '-'); + sz += cond_width(p, '-', &skip); cp++; break; default: diff --git a/contrib/mdocml/term.h b/contrib/mdocml/term.h index 56d076e..8cad4be 100644 --- a/contrib/mdocml/term.h +++ b/contrib/mdocml/term.h @@ -1,6 +1,7 @@ -/* $Id: term.h,v 1.90 2011/12/04 23:10:52 schwarze Exp $ */ +/* $Id: term.h,v 1.97 2013/12/25 00:39:31 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,6 +38,7 @@ enum termfont { TERMFONT_NONE = 0, TERMFONT_BOLD, TERMFONT_UNDER, + TERMFONT_BI, TERMFONT__MAX }; @@ -57,26 +59,28 @@ struct termp { size_t defrmargin; /* Right margin of the device. */ size_t rmargin; /* Current right margin. */ size_t maxrmargin; /* Max right margin. */ - int maxcols; /* Max size of buf. */ + size_t maxcols; /* Max size of buf. */ size_t offset; /* Margin offest. */ size_t tabwidth; /* Distance of tab positions. */ - int col; /* Bytes in buf. */ + size_t col; /* Bytes in buf. */ size_t viscol; /* Chars on current line. */ + size_t trailspace; /* See termp_flushln(). */ int overstep; /* See termp_flushln(). */ + int skipvsp; /* Vertical space to skip. */ int flags; #define TERMP_SENTENCE (1 << 1) /* Space before a sentence. */ #define TERMP_NOSPACE (1 << 2) /* No space before words. */ -#define TERMP_NOBREAK (1 << 4) /* See term_flushln(). */ -#define TERMP_IGNDELIM (1 << 6) /* Delims like regulars. */ -#define TERMP_NONOSPACE (1 << 7) /* No space (no autounset). */ -#define TERMP_DANGLE (1 << 8) /* See term_flushln(). */ -#define TERMP_HANG (1 << 9) /* See term_flushln(). */ -#define TERMP_TWOSPACE (1 << 10) /* See term_flushln(). */ +#define TERMP_NONOSPACE (1 << 3) /* No space (no autounset). */ +#define TERMP_NBRWORD (1 << 4) /* Make next word nonbreaking. */ +#define TERMP_KEEP (1 << 5) /* Keep words together. */ +#define TERMP_PREKEEP (1 << 6) /* ...starting with the next one. */ +#define TERMP_SKIPCHAR (1 << 7) /* Skip the next character. */ +#define TERMP_NOBREAK (1 << 8) /* See term_flushln(). */ +#define TERMP_DANGLE (1 << 9) /* See term_flushln(). */ +#define TERMP_HANG (1 << 10) /* See term_flushln(). */ #define TERMP_NOSPLIT (1 << 11) /* See termp_an_pre/post(). */ #define TERMP_SPLIT (1 << 12) /* See termp_an_pre/post(). */ #define TERMP_ANPREC (1 << 13) /* See termp_an_pre(). */ -#define TERMP_KEEP (1 << 14) /* Keep words together. */ -#define TERMP_PREKEEP (1 << 15) /* ...starting with the next one. */ int *buf; /* Output buffer. */ enum termenc enc; /* Type of encoding. */ struct mchars *symtab; /* Encoded-symbol table. */ diff --git a/contrib/mdocml/term_ascii.c b/contrib/mdocml/term_ascii.c index 2f11478..cb7ac29 100644 --- a/contrib/mdocml/term_ascii.c +++ b/contrib/mdocml/term_ascii.c @@ -1,4 +1,4 @@ -/* $Id: term_ascii.c,v 1.20 2011/12/04 23:10:52 schwarze Exp $ */ +/* $Id: term_ascii.c,v 1.21 2013/06/01 14:27:20 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -73,7 +73,6 @@ ascii_init(enum termenc enc, char *outopts) struct termp *p; p = mandoc_calloc(1, sizeof(struct termp)); - p->enc = enc; p->tabwidth = 5; p->defrmargin = 78; @@ -93,7 +92,7 @@ ascii_init(enum termenc enc, char *outopts) if (TERMENC_ASCII != enc) { v = TERMENC_LOCALE == enc ? setlocale(LC_ALL, "") : - setlocale(LC_CTYPE, "UTF-8"); + setlocale(LC_CTYPE, "en_US.UTF-8"); if (NULL != v && MB_CUR_MAX > 1) { p->enc = enc; p->advance = locale_advance; diff --git a/contrib/mdocml/tree.c b/contrib/mdocml/tree.c index 1430c73..fdb70e1 100644 --- a/contrib/mdocml/tree.c +++ b/contrib/mdocml/tree.c @@ -1,6 +1,7 @@ -/* $Id: tree.c,v 1.47 2011/09/18 14:14:15 schwarze Exp $ */ +/* $Id: tree.c,v 1.50 2013/12/24 19:11:46 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -58,13 +59,11 @@ print_mdoc(const struct mdoc_node *n, int indent) { const char *p, *t; int i, j; - size_t argc, sz; - char **params; + size_t argc; struct mdoc_argv *argv; argv = NULL; - argc = sz = 0; - params = NULL; + argc = 0; t = p = NULL; switch (n->type) { @@ -161,11 +160,14 @@ print_mdoc(const struct mdoc_node *n, int indent) if (argv[i].sz > 0) printf(" ]"); } - - for (i = 0; i < (int)sz; i++) - printf(" [%s]", params[i]); - printf(" %d:%d\n", n->line, n->pos); + putchar(' '); + if (MDOC_LINE & n->flags) + putchar('*'); + printf("%d:%d", n->line, n->pos); + if (n->lastline != n->line) + printf("-%d", n->lastline); + putchar('\n'); } if (n->child) diff --git a/lib/libmandoc/Makefile b/lib/libmandoc/Makefile index 9fca07e..b857b8a 100644 --- a/lib/libmandoc/Makefile +++ b/lib/libmandoc/Makefile @@ -15,6 +15,6 @@ SRCS= arch.c att.c chars.c \ tbl.c tbl_data.c tbl_layout.c tbl_opts.c vol.c WARNS?= 3 -CFLAGS+= -DHAVE_CONFIG_H -DVERSION="\"1.12.1\"" +CFLAGS+= -DHAVE_CONFIG_H .include <bsd.lib.mk> diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile index 0995534..ed88f4e 100644 --- a/usr.bin/mandoc/Makefile +++ b/usr.bin/mandoc/Makefile @@ -15,7 +15,7 @@ SRCS= eqn_html.c eqn_term.c html.c main.c man_html.c man_term.c mdoc_html.c \ term_ascii.c term_ps.c tree.c WARNS?= 3 -CFLAGS+= -DHAVE_CONFIG_H -DVERSION="\"1.12.1\"" +CFLAGS+= -DHAVE_CONFIG_H DPADD= ${LIBMANDOC} LDADD= ${LIBMANDOC} |