Merge mdocml v1.12.3 into head

MFC after:	2 weeks
This commit is contained in:
uqs 2014-02-01 09:27:57 +00:00
commit 0745c80c73
54 changed files with 5292 additions and 2439 deletions

370
contrib/mdocml/NEWS Normal file
View File

@ -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/ .

330
contrib/mdocml/TODO Normal file
View File

@ -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

View File

@ -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")

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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 .

View File

@ -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);
@ -337,6 +371,33 @@ print_encode(struct html *h, const char *p, int norecurse)
if (ESCAPE_ERROR == esc)
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. */
@ -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)) {

View File

@ -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 */

View File

@ -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)")

View File

@ -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);

View File

@ -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 *,

View File

@ -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 *);

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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
};

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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,13 +265,29 @@ 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;
}
return(0);
}
/* 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)
@ -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;

View File

@ -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); \
@ -240,6 +249,17 @@ INEQ_DEFINE(1, <=, le1)
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)
{
@ -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);
}

View File

@ -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

View File

@ -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 .

View File

@ -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);
/*
* A parenthesised subexpression. Read until the closing
* parenthesis, making sure to handle any nested subexpressions
* that might ruin our parse.
*/
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);
}
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;
const char *local_start;
int local_sz;
char term;
enum mandoc_esc gly;
cp = *end;
rstart = cp;
if (start)
*start = rstart;
i = lim = 0;
gly = ESCAPE_ERROR;
term = numeric = '\0';
/*
* When the caller doesn't provide return storage,
* use local storage.
*/
switch ((c = cp[i++])) {
if (NULL == start)
start = &local_start;
if (NULL == sz)
sz = &local_sz;
/*
* Beyond the backslash, at least one input character
* is part of the escape sequence. With one exception
* (see below), that character won't be returned.
*/
gly = ESCAPE_ERROR;
*start = ++*end;
*sz = 0;
term = '\0';
switch ((*start)[-1]) {
/*
* First the glyphs. There are several different forms of
* these, but each eventually returns a substring of the glyph
@ -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,17 +86,38 @@ 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 @@ mandoc_escape(const char **end, const char **start, int *sz)
}
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) {
@ -677,32 +636,6 @@ mandoc_eos(const char *p, size_t sz, int enclosed)
return(found && !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.

View File

@ -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 *);

View File

@ -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 ;

View File

@ -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 .

View File

@ -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);

View File

@ -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 */

View File

@ -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);
}

View File

@ -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();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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,33 +307,16 @@ 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;
@ -1497,17 +1513,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);
@ -1765,16 +1784,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;
const struct mdoc_node *link, *descr;
term_fontpush(p, TERMFONT_UNDER);
if (NULL == (link = n->child))
return(0);
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);
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);

View File

@ -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);
@ -1976,6 +2115,32 @@ pre_par(PRE_ARGS)
return(1);
}
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);

View File

@ -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];

View File

@ -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")

View File

@ -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 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
*/
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);
}

View File

@ -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 .

File diff suppressed because it is too large Load Diff

View File

@ -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)")

View File

@ -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 .

View File

@ -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;
struct tbl_node *tbl;
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);
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

View File

@ -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;

View File

@ -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;
}

View File

@ -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(struct tbl_node *tbl, int ln, const char *p, int *pos)
*/
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;
}

View File

@ -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];

View File

@ -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));
if (p->col + 1 + (sz * 5) >= p->maxcols)
adjbuf(p, p->col + 1 + (sz * 5));
for (i = 0; i < len; i++) {
if (ASCII_HYPH != word[i] &&
! isgraph((unsigned char)word[i])) {
p->buf[p->col++] = word[i];
continue;
}
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:

View File

@ -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. */

View File

@ -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;

View File

@ -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)

View File

@ -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>

View File

@ -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}