diff options
-rw-r--r-- | usr.bin/mandoc/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/mandoc/chars.c | 4 | ||||
-rw-r--r-- | usr.bin/mandoc/chars.in | 3 | ||||
-rw-r--r-- | usr.bin/mandoc/libmdoc.h | 6 | ||||
-rw-r--r-- | usr.bin/mandoc/main.c | 10 | ||||
-rw-r--r-- | usr.bin/mandoc/mandoc.c | 4 | ||||
-rw-r--r-- | usr.bin/mandoc/mandoc.h | 11 | ||||
-rw-r--r-- | usr.bin/mandoc/manuals.7 | 236 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.3 | 14 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.7 | 385 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.c | 99 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.h | 3 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_action.c | 74 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_argv.c | 49 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_html.c | 137 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_macro.c | 159 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_term.c | 159 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_validate.c | 341 | ||||
-rw-r--r-- | usr.bin/mandoc/roff.7 | 8 | ||||
-rw-r--r-- | usr.bin/mandoc/roff.c | 6 |
20 files changed, 964 insertions, 748 deletions
diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile index 6bf027e8d37..e9e566694d1 100644 --- a/usr.bin/mandoc/Makefile +++ b/usr.bin/mandoc/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.38 2010/06/06 18:08:41 schwarze Exp $ +# $OpenBSD: Makefile,v 1.39 2010/06/06 20:30:08 schwarze Exp $ .include <bsd.own.mk> -VERSION=1.10.0 +VERSION=1.10.1 CFLAGS+=-DVERSION=\"${VERSION}\" CFLAGS+=-W -Wall -Wstrict-prototypes diff --git a/usr.bin/mandoc/chars.c b/usr.bin/mandoc/chars.c index 3f839261af4..fb3c0b64ddc 100644 --- a/usr.bin/mandoc/chars.c +++ b/usr.bin/mandoc/chars.c @@ -1,4 +1,4 @@ -/* $Id: chars.c,v 1.7 2010/05/26 02:39:58 schwarze Exp $ */ +/* $Id: chars.c,v 1.8 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -39,7 +39,7 @@ struct ln { #define CHARS_BOTH (CHARS_CHAR | CHARS_STRING) }; -#define LINES_MAX 369 +#define LINES_MAX 370 #define CHAR(w, x, y, z, a, b) \ { NULL, (w), (y), (a), (x), (z), (b), CHARS_CHAR }, diff --git a/usr.bin/mandoc/chars.in b/usr.bin/mandoc/chars.in index bd8b946934a..39e49923380 100644 --- a/usr.bin/mandoc/chars.in +++ b/usr.bin/mandoc/chars.in @@ -1,4 +1,4 @@ -/* $Id: chars.in,v 1.7 2010/04/02 12:39:47 schwarze Exp $ */ +/* $Id: chars.in,v 1.8 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -44,6 +44,7 @@ CHAR("%", 1, "", 0, "", 0) CHAR("&", 1, "", 0, "", 0) CHAR("^", 1, "", 0, "", 0) CHAR("|", 1, "", 0, "", 0) +CHAR("}", 1, "", 0, "", 0) /* Accents. */ CHAR("a\"", 2, "\"", 1, "̋", 6) diff --git a/usr.bin/mandoc/libmdoc.h b/usr.bin/mandoc/libmdoc.h index 189cd25131d..ceeedfd3f0d 100644 --- a/usr.bin/mandoc/libmdoc.h +++ b/usr.bin/mandoc/libmdoc.h @@ -1,4 +1,4 @@ -/* $Id: libmdoc.h,v 1.36 2010/05/24 00:00:10 schwarze Exp $ */ +/* $Id: libmdoc.h,v 1.37 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -34,6 +34,7 @@ struct mdoc { #define MDOC_NEWLINE (1 << 3) /* first macro/text in a line */ #define MDOC_PHRASELIT (1 << 4) /* literal within a partila phrase */ #define MDOC_PPHRASE (1 << 5) /* within a partial phrase */ +#define MDOC_FREECOL (1 << 6) /* `It' invocation should close */ int pflags; enum mdoc_next next; struct mdoc_node *last; @@ -117,8 +118,7 @@ const char *mdoc_a2st(const char *); const char *mdoc_a2arch(const char *); const char *mdoc_a2vol(const char *); const char *mdoc_a2msec(const char *); -int mdoc_valid_pre(struct mdoc *, - const struct mdoc_node *); +int mdoc_valid_pre(struct mdoc *, struct mdoc_node *); int mdoc_valid_post(struct mdoc *); int mdoc_action_pre(struct mdoc *, struct mdoc_node *); diff --git a/usr.bin/mandoc/main.c b/usr.bin/mandoc/main.c index 0d9858ed90b..19ffe247f4a 100644 --- a/usr.bin/mandoc/main.c +++ b/usr.bin/mandoc/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.33 2010/05/23 22:45:00 schwarze Exp $ */ +/* $Id: main.c,v 1.34 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -86,12 +86,11 @@ struct curparse { static const char * const mandocerrs[MANDOCERR_MAX] = { "ok", "text should be uppercase", - "sections out of conentional order", + "sections out of conventional order", "section name repeats", "out of order prologue", "repeated prologue entry", "list type must come first", - "column syntax is inconsistent", "bad standard", "bad library", "bad escape sequence", @@ -100,7 +99,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "superfluous width argument", "bad date argument", "bad width argument", - "unknown manual sction", + "unknown manual section", "section not in conventional manual section", "end of line whitespace", "scope open on exit", @@ -131,11 +130,12 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "macro requires body argument(s)", "macro requires argument(s)", "no title in document", + "missing list type", "line argument(s) will be lost", "body argument(s) will be lost", + "column syntax is inconsistent", "missing font type", "missing display type", - "missing list type", "displays may not be nested", "no scope to rewind: syntax violated", "scope broken, syntax violated", diff --git a/usr.bin/mandoc/mandoc.c b/usr.bin/mandoc/mandoc.c index 4f534f1589b..e83a98aa8ab 100644 --- a/usr.bin/mandoc/mandoc.c +++ b/usr.bin/mandoc/mandoc.c @@ -1,4 +1,4 @@ -/* $Id: mandoc.c,v 1.12 2010/05/26 02:39:58 schwarze Exp $ */ +/* $Id: mandoc.c,v 1.13 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -57,6 +57,8 @@ mandoc_special(const char *p) /* FALLTHROUGH */ case (' '): /* FALLTHROUGH */ + case ('}'): + /* FALLTHROUGH */ case ('|'): /* FALLTHROUGH */ case ('&'): diff --git a/usr.bin/mandoc/mandoc.h b/usr.bin/mandoc/mandoc.h index fb9911c46a7..6e1efa9e14e 100644 --- a/usr.bin/mandoc/mandoc.h +++ b/usr.bin/mandoc/mandoc.h @@ -1,4 +1,4 @@ -/* $Id: mandoc.h,v 1.5 2010/05/26 02:39:58 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.6 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -26,12 +26,11 @@ __BEGIN_DECLS enum mandocerr { MANDOCERR_OK, MANDOCERR_UPPERCASE, /* text should be uppercase */ - MANDOCERR_SECOOO, /* sections out of conentional order */ + MANDOCERR_SECOOO, /* sections out of conventional order */ MANDOCERR_SECREP, /* section name repeats */ MANDOCERR_PROLOGOOO, /* out of order prologue */ MANDOCERR_PROLOGREP, /* repeated prologue entry */ MANDOCERR_LISTFIRST, /* list type must come first */ - MANDOCERR_COLUMNS, /* column syntax is inconsistent */ MANDOCERR_BADSTANDARD, /* bad standard */ MANDOCERR_BADLIB, /* bad library */ MANDOCERR_BADESCAPE, /* bad escape sequence */ @@ -40,7 +39,7 @@ enum mandocerr { MANDOCERR_WIDTHARG, /* superfluous width argument */ MANDOCERR_BADDATE, /* bad date argument */ MANDOCERR_BADWIDTH, /* bad width argument */ - MANDOCERR_BADMSEC, /* unknown manual sction */ + MANDOCERR_BADMSEC, /* unknown manual section */ MANDOCERR_SECMSEC, /* section not in conventional manual section */ MANDOCERR_EOLNSPACE, /* end of line whitespace */ MANDOCERR_SCOPEEXIT, /* scope open on exit */ @@ -74,17 +73,17 @@ enum mandocerr { MANDOCERR_NOBODY, /* macro requires body argument(s) */ MANDOCERR_NOARGV, /* macro requires argument(s) */ MANDOCERR_NOTITLE, /* no title in document */ + MANDOCERR_LISTTYPE, /* missing list type */ MANDOCERR_ARGSLOST, /* line argument(s) will be lost */ MANDOCERR_BODYLOST, /* body argument(s) will be lost */ #define MANDOCERR_ERROR MANDOCERR_BODYLOST + MANDOCERR_COLUMNS, /* column syntax is inconsistent */ /* FIXME: this should be a MANDOCERR_ERROR */ MANDOCERR_FONTTYPE, /* missing font type */ /* FIXME: this should be a MANDOCERR_ERROR */ MANDOCERR_DISPTYPE, /* missing display type */ /* FIXME: this should be a MANDOCERR_ERROR */ - MANDOCERR_LISTTYPE, /* missing list type */ - /* FIXME: this should be a MANDOCERR_ERROR */ MANDOCERR_NESTEDDISP, /* displays may not be nested */ MANDOCERR_SYNTNOSCOPE, /* request scope close w/none open */ MANDOCERR_SYNTSCOPE, /* scope broken, syntax violated */ diff --git a/usr.bin/mandoc/manuals.7 b/usr.bin/mandoc/manuals.7 deleted file mode 100644 index 3fbb3c9486a..00000000000 --- a/usr.bin/mandoc/manuals.7 +++ /dev/null @@ -1,236 +0,0 @@ -.\" $Id: manuals.7,v 1.6 2010/05/14 01:54:37 schwarze Exp $ -.\" -.\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: May 14 2010 $ -.Dt MANUALS 7 -.Os -.\" SECTION -.Sh NAME -.Nm Writing UNIX Documentation -.Nd a guide to writing UNIX manuals -.\" SECTION -.Sh DESCRIPTION -.Em A utility without good documentation is of no utility at all . -.\" PARAGRAPH -.Pp -A system component's documentation describes the utility of that -component, whether it's a device driver, an executable or, most -importantly, a game. -.Pp -This document serves as a tutorial to writing -.Ux -documentation -.Pq Dq manuals . -.\" SECTION -.Sh ENVIRONMENT -First, copy over the manual template from -.Pa /usr/share/misc/mdoc.template -into your source directory. -.Pp -.Dl % cp /usr/share/misc/mdoc.template \. -.Pp -.Em \&Do not -start afresh or by copying another manual unless you know exactly what -you're doing! If the template doesn't exist, bug your administrator. -.\" SUBSECTION -.Ss Section Numbering -Find an appropriate section for your manual. There may exist multiple -manual names per section, so be specific: -.Pp -.\" LIST -.Bl -tag -width "XXXXXXXXXXXX" -offset indent -compact -.It Em Section -.Em Description -.It 1 -operator utilities -.It 2 -system calls -.It 3, 3p, 3f -programming libraries (C, Perl, Fortran) -.It 5 -file and wire protocol formats -.It 6 -games -.It 7 -tutorials, documents and papers -.It 8 -administrator utilities -.It 9 -in-kernel routines -.El -.Pp -If your manual falls into multiple categories, choose the most -widely-used or, better, re-consider the topic of your manual to be more -specific. You can list all manuals per section by invoking -.Xr apropos 1 , -then provide the -.Fl s -flag to -.Xr man 1 -to see the specific section manual (section 1, in this example): -.\" DISPLAY -.Bd -literal -offset indent -% apropos myname -myname (1) - utility description -myname (3) - library description -% man \-s 1 myname -.Ed -.\" SUBSECTION -.Ss Naming -Name your component. Be terse, erring on the side of clarity. Look for -other manuals by that same name before committing: -.Pp -.Dl % apropos myname -.Pp -Manual files are named -.Pa myname.mysection , -such as -.Pa manuals.7 -for this document. Rename the template file: -.Pp -.Dl % mv mdoc.template myname.mysection -.\" SUBSECTION -.Ss Development Tools -While writing, make sure that your manual is correctly structured: -.Pp -.Dl % mandoc \-Tlint \-Wall \-fstrict name.1 -.Pp -The quick-fix feature of -.Xr vim 1 -is useful for checking over many manuals: -.Bd -literal -offset indent -% mandoc \-Wall \-fstrict \-Tlint \-fign-errors \e - ./path/to/manuals/* 2>&1 > /tmp/mandoc.errs -% vim -q /tmp/mandoc.errs -.Ed -.Pp -You may spell-check your work as follows: -.Pp -.Dl % deroff name.1 | spell -.Pp -If -.Xr ispell 1 -is installed, it has a special mode for manuals: -.Pp -.Dl % ispell \-n name.1 -.Pp -Use -.Xr cvs 1 -or -.Xr rcs 1 -to version-control your work. If you wish the last check-in to effect -your document's date, use the following RCS tag for the date macro: -.Pp -.Dl \&.Dd $Mdocdate: May 14 2010 $ -.\" SUBSECTION -.Ss Viewing -mdoc documents may be paged to your terminal with -.Xr mandoc 1 . -If you plan on distributing your work to systems without this tool, -check it against -.Xr groff 1 : -.Bd -literal -offset indent -% mandoc \-Wall name.1 2>&1 | less -% groff -mandoc name.1 2>&1 | less -.Ed -.\" SUBSECTION -.Ss Automation -Consider adding your mdoc documents to -.Xr make 1 -Makefiles in order to automatically check your input: -.Bd -literal -offset indent -\&.SUFFIXES: .1 .in - -\&.in.1: - mandoc -Wall,error -Tlint $< - cp -f $< $@ -.Ed -.\" SUBSECTION -.Ss Licensing -Your manual must have a license. It should be listed at the start of -your document, just as in source code. -.\" SECTION -.Sh COMPOSITION -Manuals should -.Em always -be written in the -.Xr mdoc 7 -formatting language. -.\" PARAGRAPH -.Pp -Open the template you've copied into -.Pa myname.mysection -and begin editing. -.\" SUBSECTION -.Ss Language -.Bl -enum -.It -Use clear, concise language. Favour simplicity. -.It -Write your manual in non-idiomatic English. Don't worry about -Commonwealth or American spellings \(em just correct ones. -.It -Spell-check your manual, keeping in mind short-letter terms ( -.Xr iwi 4 -vs. -.Xr iwn 4 ) . -.It -If you absolutely must use special characters (diacritics, mathematical -symbols and so on), use the escapes dictated in -.Xr mdoc 7 . -.El -.\" SUBSECTION -.Ss Style -The structure of the mdoc language makes it very hard to have any -particular format style. Keep your lines under 72 characters in length. -If you must have long option lines, use -.Sq \&Oo/Oc . -The same goes for function prototypes. -.Em \&Do not -use -.Sq \&Xo/Xc . -Find another way to structure your line. -.\" SUBSECTION -.Ss References -Other components may be referenced with the -.Sq \&Xr -and -.Sq \&Sx -macros. Make sure that these exist. If you intend to distribute your -manual, make sure -.Sq \&Xr -references are valid across systems (within reason). If you cross-link with -.Sq \&Sx , -make sure that the section reference exists. -.\" SUBSECTION -.Ss Citations -Cite your work. If your system references standards documents or other -publications, please use the -.Sq \&Rs/Re -block macros. -.\" SUBSECTION -.Ss Formatting -.Em Don't style your manual . -Give it meaningful content. The front-end will worry about formatting -and style. -.\" SECTION -.Sh MAINTENANCE -As your component changes and bugs are fixed, your manual may become out -of date. You may be tempted to use tools like Doxygen to automate the -development of your manuals. Don't. -.Pp -.Em Manuals are part of a system component : -if you modify your code or specifications, modify the documentation. diff --git a/usr.bin/mandoc/mdoc.3 b/usr.bin/mandoc/mdoc.3 index eb382e31b9f..5eb59e962d1 100644 --- a/usr.bin/mandoc/mdoc.3 +++ b/usr.bin/mandoc/mdoc.3 @@ -1,4 +1,4 @@ -.\" $Id: mdoc.3,v 1.7 2010/05/26 02:55:16 schwarze Exp $ +.\" $Id: mdoc.3,v 1.8 2010/06/06 20:30:08 schwarze Exp $ .\" .\" Copyright (c) 2009-2010 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: May 26 2010 $ +.Dd $Mdocdate: June 6 2010 $ .Dt MDOC 3 .Os .Sh NAME @@ -221,9 +221,7 @@ where capitalised non-terminals represent nodes. .It mnode \(<- BLOCK | ELEMENT | TEXT .It BLOCK -\(<- (HEAD [TEXT])+ [BODY [TEXT]] [TAIL [TEXT]] -.It BLOCK -\(<- BODY [TEXT] [TAIL [TEXT]] +\(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]] .It ELEMENT \(<- TEXT* .It HEAD @@ -237,12 +235,14 @@ where capitalised non-terminals represent nodes. .El .Pp Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of -the BLOCK production. -These refer to punctuation marks. +the BLOCK production: these refer to punctuation marks. Furthermore, although a TEXT node will generally have a non-zero-length string, in the specific case of .Sq \&.Bd \-literal , an empty line will produce a zero-length string. +Multiple body parts are only found in invocations of +.Sq \&Bl \-column , +where a new body introduces a new phrase. .Sh EXAMPLES The following example reads lines from stdin and parses them, operating on the finished parse tree with diff --git a/usr.bin/mandoc/mdoc.7 b/usr.bin/mandoc/mdoc.7 index 32b7ab70401..6eeb96e9260 100644 --- a/usr.bin/mandoc/mdoc.7 +++ b/usr.bin/mandoc/mdoc.7 @@ -1,4 +1,4 @@ -.\" $Id: mdoc.7,v 1.33 2010/06/06 18:08:41 schwarze Exp $ +.\" $Id: mdoc.7,v 1.34 2010/06/06 20:30:08 schwarze Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> .\" @@ -33,7 +33,7 @@ section describes compatibility with other troff \-mdoc implementations. .Pp An .Nm -document follows simple rules: lines beginning with the control +document follows simple rules: lines beginning with the control character .Sq \. are parsed for macros. Other lines are interpreted within the scope of @@ -122,7 +122,7 @@ escape followed by an indicator: B (bold), I, (italic), R (Roman), or P A numerical representation 3, 2, or 1 (bold, italic, and Roman, respectively) may be used instead. A text decoration is valid within -the current font scope only: if a macro opens a font scope alongside +the current font scope only: if a macro opens a font scope alongside its own scope, such as .Sx \&Bf .Cm \&Sy , @@ -343,18 +343,15 @@ file: \&.Dd $\&Mdocdate$ \&.Dt mdoc 7 \&.Os -\&. \&.Sh NAME \&.Nm foo \&.Nd a description goes here \&.\e\*q The next is for sections 2, 3, & 9 only. \&.\e\*q .Sh LIBRARY -\&. \&.Sh SYNOPSIS \&.Nm foo \&.Op Fl options \&.Ar -\&. \&.Sh DESCRIPTION The \&.Nm @@ -1139,22 +1136,18 @@ macro. These dictate the width of columns either as .Sx Scaling Widths or literal text. -List entry bodies must be left empty. -Column bodies have the following syntax: -.Pp -.D1 .It col1 <TAB> ... coln -.D1 .It col1 Ta ... coln -.D1 .It col1 <TAB> col2 Ta coln -.Pp -where columns may be separated by tabs, the literal string -.Qq Ta , -or a mixture of both. -These are equivalent except that quoted sections propogate over tabs, -for example, -.Pp -.D1 .It \(dqcol1 ; <TAB> col2 ;\(dq ; -.Pp -will preserve the semicolon whitespace except for the last. +If the initial macro of a +.Fl column +list is not an +.Sx \&It , +an +.Sx \&It +context spanning each line is implied until an +.Sx \&It +line macro is encountered, at which point list bodies are interpreted as +described in the +.Sx \&It +documentation. .It Fl dash A list offset by a dash (hyphen). The head of list entries must be empty. @@ -1209,6 +1202,9 @@ after the head as specified by the .Fl width argument. .El +.Pp +See also +.Sx \&It . .Ss \&Bo Begins a block enclosed by square brackets. Does not have any head arguments. @@ -1336,6 +1332,11 @@ See also and .Sx \&Dl . .Ss \&Db +Start a debugging context. +This macro is parsed, but generally ignored. +Its syntax is as follows: +.Pp +.D1 Pf \. Sx \&Db Cm on | off .Ss \&Dc Closes a .Sx \&Do @@ -1345,9 +1346,9 @@ Document date. This is the mandatory first macro of any .Nm manual. -Its calling syntax is as follows: +Its syntax is as follows: .Pp -.D1 \. Ns Sx \&Dd Cm date +.D1 Pf \. Sx \&Dd Cm date .Pp The .Cm date @@ -1406,15 +1407,25 @@ Document title. This is the mandatory second macro of any .Nm file. -Its calling syntax is as follows: -.Pp -.D1 \. Ns Sx \&Dt Cm title section Op Cm volume | arch +Its syntax is as follows: +.Bd -ragged -offset indent +.Pf \. Sx \&Dt +.Oo +.Cm title +.Oo +.Cm section +.Op Cm volume | arch +.Oc +.Oc +.Ed .Pp Its arguments are as follows: .Bl -tag -width Ds -offset Ds .It Cm title -The document's title (name). -This should be capitalised and is required. +The document's title (name), defaulting to +.Qq UNKNOWN +if unspecified. +It should be capitalised. .It Cm section The manual section. This may be one of @@ -1451,8 +1462,9 @@ This may be one of or .Ar paper .Pq paper . -It is also required and should correspond to the manual's filename -suffix. +It should correspond to the manual's filename suffix and defaults to +.Qq 1 +if unspecified. .It Cm volume This overrides the volume inferred from .Ar section . @@ -1524,7 +1536,6 @@ Examples: .D1 \&.Dt FOO 1 .D1 \&.Dt FOO 4 KM .D1 \&.Dt FOO 9 i386 -.D1 \&.Dt FOO 9 KM i386 .Pp See also .Sx \&Dd @@ -1561,6 +1572,13 @@ and .Ss \&Ef .Ss \&Ek .Ss \&El +Ends a list context started by +.Sx \&Bl . +.Pp +See also +.Sx \&Bl +and +.Sx \&It . .Ss \&Em Denotes text that should be emphasised. Note that this is a presentation term and should not be used for @@ -1600,8 +1618,45 @@ is not provided, the document's name as stipulated in .Sx \&Nm is provided. .Ss \&Fa +Function argument. +Its syntax is as follows: +.Bd -ragged -offset indent +.Pf \. Sx \&Fa +.Op Cm argtype +.Cm argname +.Ed +.Pp +This may be invoked for names with or without the corresponding type. +It is also used to specify the field name of a structure. +Most often, the +.Sx \&Fa +macro is used in the +.Em SYNOPSIS +within +.Sx \&Fo +section when documenting multi-line function prototypes. +If invoked with multiple arguments, the arguments are separated by a +comma. +Furthermore, if the following macro is another +.Sx \&Fa , +the last argument will also have a trailing comma. +.Pp +Examples: +.D1 \&.Fa \(dqconst char *p\(dq +.D1 \&.Fa \(dqint a\(dq \(dqint b\(dq \(dqint c\(dq +.D1 \&.Fa foo +.Pp +See also +.Sx \&Fo . .Ss \&Fc .Ss \&Fd +Historically used to document include files. +This usage has been deprecated in favour of +.Sx \&In . +Do not use this macro. +.Pp +See also +.Sx \&In . .Ss \&Fl Command-line flag. Used when listing arguments to command-line utilities. @@ -1621,9 +1676,106 @@ Examples: See also .Sx \&Cm . .Ss \&Fn +A function name. +Its syntax is as follows: +.Bd -ragged -offset indent +.Pf \. Ns Sx \&Fn +.Op Cm functype +.Cm funcname +.Op Oo Cm argtype Oc Cm argname +.Ed +.Pp +If invoked in the +.Em SYNOPSIS +section, vertical space is asserted before and after the macro. +In all cases, the function arguments are surrounded in parenthesis and +are delimited by commas. +If no arguments are specified, blank parenthesis are output. +.Pp +Examples: +.D1 \&.Fn "int funcname" "int arg0" "int arg1" +.D1 \&.Fn funcname "int arg0" +.D1 \&.Fn funcname arg0 +.Bd -literal -offset indent -compact +\&.Ft functype +\&.Fn funcname +.Ed +.Pp +See also +.Sx \&Fa , +.Sx \&Fo , +.Sx \&Fc , +and +.Sx \&Ft . .Ss \&Fo +Begin a function block. +This is a multi-line version of +.Sx \&Fn . +Its syntax is as follows: +.Pp +.D1 Pf \. Sx \&Fo Cm funcname +.Pp +Invocations usually occur in the following context: +.Bd -ragged -offset indent +.Pf \. Sx \&Ft Cm functype +.br +.Pf \. Sx \&Fo Cm funcname +.br +.Pf \. Sx \&Fa Oo Cm argtype Oc Cm argname +.br +\.\.\. +.br +.Pf \. Sx \&Fc +.Ed +.Pp +In the +.Em SYNOPSIS +section, a +.Sx \&Fo +block is surrounded by vertical space unless +.Sx \&Ft +is the prior macro, in which case it is preceded by only a newline. +.Pp +A +.Sx \&Fo +scope is closed by +.Pp +See also +.Sx \&Fa , +.Sx \&Fc , +and +.Sx \&Fn . +.Sx \&Fc . .Ss \&Fr .Ss \&Ft +A function type. +Its syntax is as follows: +.Pp +.D1 Pf \. Sx \&Ft Cm functype +.Pp +If invoked before a +.Sx \&Fo +or +.Sx \&Fn +in the +.Em SYNOPSIS +section, a line-break will follow. +Furthermore, if invoked in the +.Em SYNOPSIS +section, it will assert vertical space prior to its arguments. +.Pp +Examples: +.D1 \&.Ft int +.Bd -literal -offset indent -compact +\&.Ft functype +\&.Fn funcname +.Ed +.Pp +See also +.Sx \&Fo , +.Sx \&Fc , +and +.Sx \&Fn . .Ss \&Fx Format the FreeBSD version provided as an argument, or a default value if no argument is provided. @@ -1644,12 +1796,106 @@ and .Ss \&Hf .Ss \&Ic .Ss \&In +An +.Qq include +file. +In the +.Em SYNOPSIS +section (only if invoked as the line macro), the first argument is +preceded by +.Qq #include , +the arguments is enclosed in angled braces, and a newline is asserted. +In all other invocations, only angled braces will enclose the argument. +.Pp +Examples +.D1 \&.In sys/types .Ss \&It +A list item. +The syntax of this macro depends on the list type. +.Pp +Lists +of type +.Fl hang , +.Fl ohang , +.Fl inset , +and +.Fl diag +have the following syntax: +.Pp +.D1 Pf \. Sx \&It Cm args +.Pp +Lists of type +.Fl bullet , +.Fl dash , +.Fl enum , +.Fl hyphen +and +.Fl item +have the following syntax: +.Pp +.D1 Pf \. Sx \&It +.Pp +with subsequent lines interpreted within the scope of the +.Sx \&It +until either a closing +.Sx \&El +or another +.Sx \&It . +.Pp +The +.Fl tag +list has the following syntax: +.Pp +.D1 Pf \. Sx \&It Op Cm args +.Pp +Subsequent lines are interpreted as with +.Fl bullet +and family. +The line arguments correspond to the list's left-hand side; body +arguments correspond to the list's contents. +.Pp +The +.Fl column +list is the most complicated. +Its syntax is as follows: +.Pp +.D1 Pf \. Sx \&It Op Cm args +.Pp +The +.Cm args +are phrases, a mix of macros and text corresponding to a line column, +delimited by tabs or the special +.Sq \&Ta +pseudo-macro. +Lines subsequent the +.Sx \&It +are interpreted within the scope of the last phrase. +Calling the pseudo-macro +.Sq \&Ta +will open a new phrase scope (this must occur on a macro line to be +interpreted as a macro). Note that the tab phrase delimiter may only be +used within the +.Sx \&It +line itself. +Subsequent this, only the +.Sq \&Ta +pseudo-macro may be used to delimit phrases. +Furthermore, note that quoted sections propogate over tab-delimited +phrases on an +.Sx \&It , +for example, +.Pp +.D1 .It \(dqcol1 ; <TAB> col2 ;\(dq ; +.Pp +will preserve the semicolon whitespace except for the last. +.Pp +See also +.Sx \&Bl . .Ss \&Lb Specify a library. -The calling syntax is as follows: +The syntax is as follows: .Pp -.D1 \. Ns Sx \&Lb Cm library +.D1 Pf \. Sx \&Lb Cm library .Pp The .Cm library @@ -1671,9 +1917,9 @@ Examples: .Ss \&Li .Ss \&Lk Format a hyperlink. -The calling syntax is as follows: +Its syntax is as follows: .Pp -.D1 \. Ns Sx \&Lk Cm uri Op Cm name +.D1 Pf \. Sx \&Lk Cm uri Op Cm name .Pp Examples: .D1 \&.Lk http://bsd.lv "The BSD.lv Project" @@ -1684,6 +1930,15 @@ See also .Ss \&Lp .Ss \&Ms .Ss \&Mt +Format a +.Qq mailto: +hyperlink. +Its syntax is as follows: +.Pp +.D1 Pf \. Sx \&Mt Cm address +.Pp +Examples: +.D1 \&.Mt discuss@manpages.bsd.lv .Ss \&Nd .Ss \&Nm .Ss \&No @@ -1713,9 +1968,10 @@ Document operating system version. This is the mandatory third macro of any .Nm -file. Its calling syntax is as follows: +file. +Its syntax is as follows: .Pp -.D1 \. Ns Sx \&Os Op Cm system +.D1 Pf \. Sx \&Os Op Cm system .Pp The optional .Cm system @@ -1787,6 +2043,7 @@ The block macro may only contain .Sx \&%Q , .Sx \&%R , .Sx \&%T , +.Sx \&%U , and .Sx \&%V child macros (at least one must be specified). @@ -1872,9 +2129,9 @@ since this limit has been lifted, the macro has been deprecated. .Ss \&Xr Link to another manual .Pq Qq cross-reference . -Its calling syntax is +Its syntax is as follows: .Pp -.D1 \. Ns Sx \&Xr Cm name section +.D1 Pf \. Sx \&Xr Cm name section .Pp The .Cm name @@ -1911,6 +2168,49 @@ Heirloom troff, the other significant troff implementation accepting .Pp .Bl -dash -compact .It +groff behaves inconsistently when encountering +.Pf non- Sx \&Fa +children of +.Sx \&Fo +regarding spacing between arguments. +In mandoc, this is not the case: each argument is consistently followed +by a single space and the trailing +.Sq \&) +suppresses prior spacing. +.It +groff behaves inconsistently when encountering +.Sx \&Ft +and +.Sx \&Fn +in the +.Em SYNOPSIS : +at times newline(s) are suppressed dependong on whether a prior +.Sx \&Fn +has been invoked. +In mandoc, this is not the case. +See +.Sx \&Ft +and +.Sx \&Fn +for the normalised behaviour. +.It +Historic groff does not break before an +.Sx \&Fn +when not invoked as the line macro in the +.Em SYNOPSIS +section. +.It +Historic groff formats the +.Sx \&In +badly: trailing arguments are trashed and +.Em SYNOPSIS +is not specially treated. +.It +groff does not accept the +.Sq \&Ta +pseudo-macro as a line macro. +mandoc does. +.It The comment syntax .Sq \e." is no longer accepted. @@ -1983,11 +2283,6 @@ delimiter to render. This is not supported in mandoc. .It In groff, the -.Sx \&Fo -macro only produces the first parameter. -This is not the case in mandoc. -.It -In groff, the .Sx \&Cd , .Sx \&Er , .Sx \&Ex , diff --git a/usr.bin/mandoc/mdoc.c b/usr.bin/mandoc/mdoc.c index 2544ebb9113..aec75eae499 100644 --- a/usr.bin/mandoc/mdoc.c +++ b/usr.bin/mandoc/mdoc.c @@ -1,6 +1,6 @@ -/* $Id: mdoc.c,v 1.55 2010/05/26 02:39:58 schwarze Exp $ */ +/* $Id: mdoc.c,v 1.56 2010/06/06 20:30:08 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> + * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -65,7 +65,7 @@ const char *const __mdoc_macronames[MDOC_MAX] = { /* LINTED */ "Dx", "%Q", "br", "sp", /* LINTED */ - "%U" + "%U", "Ta" }; const char *const __mdoc_argnames[MDOC_ARG_MAX] = { @@ -272,11 +272,11 @@ mdoc_macro(struct mdoc *m, enum mdoct tok, if ( ! mdoc_pmsg(m, ln, pp, MANDOCERR_BADPROLOG)) return(0); if (NULL == m->meta.title) - m->meta.title = mandoc_strdup("unknown"); + m->meta.title = mandoc_strdup("UNKNOWN"); if (NULL == m->meta.vol) - m->meta.vol = mandoc_strdup("local"); + m->meta.vol = mandoc_strdup("LOCAL"); if (NULL == m->meta.os) - m->meta.os = mandoc_strdup("local"); + m->meta.os = mandoc_strdup("LOCAL"); if (0 == m->meta.date) m->meta.date = time(NULL); m->flags |= MDOC_PBODY; @@ -538,7 +538,8 @@ mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) static int mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) { - char *c, *ws, *end; + char *c, *ws, *end; + struct mdoc_node *n; /* Ignore bogus comments. */ @@ -552,16 +553,45 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) if (SEC_NONE == m->lastnamed) return(mdoc_pmsg(m, line, offs, MANDOCERR_NOTEXT)); + assert(m->last); + n = m->last; + + /* + * Divert directly to list processing if we're encountering a + * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry + * (a MDOC_BODY means it's already open, in which case we should + * process within its context in the normal way). + */ + + if (MDOC_Bl == n->tok && MDOC_BODY == n->type && + LIST_column == n->data.list) { + /* `Bl' is open without any children. */ + m->flags |= MDOC_FREECOL; + return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf)); + } + + if (MDOC_It == n->tok && MDOC_BLOCK == n->type && + NULL != n->parent && + MDOC_Bl == n->parent->tok && + LIST_column == n->parent->data.list) { + /* `Bl' has block-level `It' children. */ + m->flags |= MDOC_FREECOL; + return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf)); + } + /* * Search for the beginning of unescaped trailing whitespace (ws) * and for the first character not to be output (end). */ + + /* FIXME: replace with strcspn(). */ ws = NULL; for (c = end = buf + offs; *c; c++) { switch (*c) { case '-': if (mandoc_hyph(buf + offs, c)) *c = ASCII_HYPH; + ws = NULL; break; case ' ': if (NULL == ws) @@ -646,6 +676,7 @@ macrowarn(struct mdoc *m, int ln, const char *buf, int offs) buf, strlen(buf) > 3 ? "..." : ""); /* FIXME: logic should be in driver. */ + /* FIXME: broken, will error out and not omit a message. */ return(MDOC_IGN_MACRO & m->pflags ? rc : 0); } @@ -657,9 +688,10 @@ macrowarn(struct mdoc *m, int ln, const char *buf, int offs) int mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) { - enum mdoct tok; - int i, j, sv; - char mac[5]; + enum mdoct tok; + int i, j, sv; + char mac[5]; + struct mdoc_node *n; /* Empty lines are ignored. */ @@ -727,10 +759,51 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) if ( ! mdoc_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE)) goto err; - /* - * Begin recursive parse sequence. Since we're at the start of - * the line, we don't need to do callable/parseable checks. + /* + * 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, &i, buf)) + goto err; + return(1); + } + + n = m->last; + assert(m->last); + + /* + * If the first macro of a `Bl -column', open an `It' block + * context around the parsed macro. + */ + + if (MDOC_Bl == n->tok && MDOC_BODY == n->type && + LIST_column == n->data.list) { + m->flags |= MDOC_FREECOL; + if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) + goto err; + return(1); + } + + /* + * If we're following a block-level `It' within a `Bl -column' + * context (perhaps opened in the above block or in ptext()), + * then open an `It' block context around the parsed macro. + */ + + if (MDOC_It == n->tok && MDOC_BLOCK == n->type && + NULL != n->parent && + MDOC_Bl == n->parent->tok && + LIST_column == n->parent->data.list) { + m->flags |= MDOC_FREECOL; + if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) + goto err; + return(1); + } + + /* Normal processing of a macro. */ + if ( ! mdoc_macro(m, tok, ln, sv, &i, buf)) goto err; diff --git a/usr.bin/mandoc/mdoc.h b/usr.bin/mandoc/mdoc.h index 3b01a1854b9..80e04579da4 100644 --- a/usr.bin/mandoc/mdoc.h +++ b/usr.bin/mandoc/mdoc.h @@ -1,4 +1,4 @@ -/* $Id: mdoc.h,v 1.26 2010/05/24 00:00:10 schwarze Exp $ */ +/* $Id: mdoc.h,v 1.27 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -149,6 +149,7 @@ enum mdoct { MDOC_br, MDOC_sp, MDOC__U, + MDOC_Ta, MDOC_MAX }; diff --git a/usr.bin/mandoc/mdoc_action.c b/usr.bin/mandoc/mdoc_action.c index 833ca34c497..dbb100c3123 100644 --- a/usr.bin/mandoc/mdoc_action.c +++ b/usr.bin/mandoc/mdoc_action.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_action.c,v 1.39 2010/06/06 18:08:41 schwarze Exp $ */ +/* $Id: mdoc_action.c,v 1.40 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -190,6 +190,7 @@ static const struct actions mdoc_actions[MDOC_MAX] = { { NULL, NULL }, /* br */ { NULL, NULL }, /* sp */ { NULL, NULL }, /* %U */ + { NULL, NULL }, /* Ta */ }; #define RSORD_MAX 14 @@ -495,8 +496,8 @@ post_dt(POST_ARGS) if (NULL == (nn = n->child)) { /* XXX: make these macro values. */ /* FIXME: warn about missing values. */ - m->meta.title = mandoc_strdup("unknown"); - m->meta.vol = mandoc_strdup("local"); + m->meta.title = mandoc_strdup("UNKNOWN"); + m->meta.vol = mandoc_strdup("LOCAL"); m->meta.msec = mandoc_strdup("1"); return(post_prol(m, n)); } @@ -505,12 +506,13 @@ post_dt(POST_ARGS) * --> title = TITLE, volume = local, msec = 0, arch = NULL */ - m->meta.title = mandoc_strdup(nn->string); + m->meta.title = mandoc_strdup + ('\0' == nn->string[0] ? "UNKNOWN" : nn->string); if (NULL == (nn = nn->next)) { /* FIXME: warn about missing msec. */ /* XXX: make this a macro value. */ - m->meta.vol = mandoc_strdup("local"); + m->meta.vol = mandoc_strdup("LOCAL"); m->meta.msec = mandoc_strdup("1"); return(post_prol(m, n)); } @@ -942,8 +944,7 @@ pre_offset(PRE_ARGS) * stipulated by mdoc.samples. */ - assert(n->args); - for (i = 0; i < (int)n->args->argc; i++) { + for (i = 0; n->args && i < (int)n->args->argc; i++) { if (MDOC_Offset != n->args->argv[i].arg) continue; if (n->args->argv[i].sz) @@ -963,63 +964,10 @@ pre_offset(PRE_ARGS) static int pre_bl(PRE_ARGS) { - int pos; - - if (MDOC_BLOCK != n->type) { - assert(n->parent); - assert(MDOC_BLOCK == n->parent->type); - assert(MDOC_Bl == n->parent->tok); - assert(LIST__NONE != n->parent->data.list); - n->data.list = n->parent->data.list; - return(1); - } - - assert(LIST__NONE == n->data.list); - - for (pos = 0; pos < (int)n->args->argc; pos++) { - switch (n->args->argv[pos].arg) { - case (MDOC_Bullet): - n->data.list = LIST_bullet; - break; - case (MDOC_Dash): - n->data.list = LIST_dash; - break; - case (MDOC_Enum): - n->data.list = LIST_enum; - break; - case (MDOC_Hyphen): - n->data.list = LIST_hyphen; - break; - case (MDOC_Item): - n->data.list = LIST_item; - break; - case (MDOC_Tag): - n->data.list = LIST_tag; - break; - case (MDOC_Diag): - n->data.list = LIST_diag; - break; - case (MDOC_Hang): - n->data.list = LIST_hang; - break; - case (MDOC_Ohang): - n->data.list = LIST_ohang; - break; - case (MDOC_Inset): - n->data.list = LIST_inset; - break; - case (MDOC_Column): - n->data.list = LIST_column; - break; - default: - break; - } - if (LIST__NONE != n->data.list) - break; - } - assert(LIST__NONE != n->data.list); - return(pre_offset(m, n)); + if (MDOC_BLOCK == n->type) + return(pre_offset(m, n)); + return(1); } diff --git a/usr.bin/mandoc/mdoc_argv.c b/usr.bin/mandoc/mdoc_argv.c index bdd8a115a9e..ef98643e148 100644 --- a/usr.bin/mandoc/mdoc_argv.c +++ b/usr.bin/mandoc/mdoc_argv.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_argv.c,v 1.29 2010/05/23 22:45:00 schwarze Exp $ */ +/* $Id: mdoc_argv.c,v 1.30 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -206,6 +206,7 @@ static int mdoc_argflags[MDOC_MAX] = { 0, /* br */ 0, /* sp */ 0, /* %U */ + 0, /* Ta */ }; @@ -222,7 +223,7 @@ mdoc_argv(struct mdoc *m, int line, enum mdoct tok, struct mdoc_argv tmp; struct mdoc_arg *arg; - if (0 == buf[*pos]) + if ('\0' == buf[*pos]) return(ARGV_EOLN); assert(' ' != buf[*pos]); @@ -243,10 +244,10 @@ mdoc_argv(struct mdoc *m, int line, enum mdoct tok, /* XXX - save zeroed byte, if not an argument. */ - sv = 0; + sv = '\0'; if (buf[*pos]) { sv = buf[*pos]; - buf[(*pos)++] = 0; + buf[(*pos)++] = '\0'; } (void)memset(&tmp, 0, sizeof(struct mdoc_argv)); @@ -335,7 +336,7 @@ enum margserr mdoc_args(struct mdoc *m, int line, int *pos, char *buf, enum mdoct tok, char **v) { - int fl, c, i; + int fl; struct mdoc_node *n; fl = mdoc_argflags[tok]; @@ -343,26 +344,20 @@ mdoc_args(struct mdoc *m, int line, int *pos, if (MDOC_It != tok) return(args(m, line, pos, buf, fl, v)); - /* - * The `It' macro is a special case, as it acquires parameters from its - * parent `Bl' context, specifically, we're concerned with -column. + /* + * We know that we're in an `It', so it's reasonable to expect + * us to be sitting in a `Bl'. Someday this may not be the case + * (if we allow random `It's sitting out there), so provide a + * safe fall-back into the default behaviour. */ for (n = m->last; n; n = n->parent) - if (MDOC_BLOCK == n->type && MDOC_Bl == n->tok) + if (MDOC_Bl == n->tok) break; - assert(n); - c = (int)(n->args ? n->args->argc : 0); - assert(c > 0); - - /* LINTED */ - for (i = 0; i < c; i++) { - if (MDOC_Column != n->args->argv[i].arg) - continue; + if (n && LIST_column == n->data.list) { fl |= ARGS_TABSEP; fl &= ~ARGS_DELIM; - break; } return(args(m, line, pos, buf, fl, v)); @@ -373,9 +368,10 @@ static enum margserr args(struct mdoc *m, int line, int *pos, char *buf, int fl, char **v) { - int i; - char *p, *pp; - enum margserr rc; + int i; + char *p, *pp; + enum margserr rc; + enum mdelim d; /* * Parse out the terms (like `val' in `.Xx -arg val' or simply @@ -392,7 +388,6 @@ args(struct mdoc *m, int line, int *pos, * phrases like in `Bl -column'. */ - assert(*pos); assert(' ' != buf[*pos]); if ('\0' == buf[*pos]) { @@ -420,7 +415,7 @@ args(struct mdoc *m, int line, int *pos, if ((fl & ARGS_DELIM) && DELIM_CLOSE == mdoc_iscdelim(buf[*pos])) { for (i = *pos; buf[i]; ) { - enum mdelim d = mdoc_iscdelim(buf[i]); + d = mdoc_iscdelim(buf[i]); if (DELIM_NONE == d || DELIM_OPEN == d) break; i++; @@ -433,7 +428,7 @@ args(struct mdoc *m, int line, int *pos, if ('\0' == buf[i]) { *v = &buf[*pos]; - if (' ' != buf[i - 1]) + if (i && ' ' != buf[i - 1]) return(ARGS_PUNCT); if (ARGS_NOWARN & fl) return(ARGS_PUNCT); @@ -464,7 +459,7 @@ args(struct mdoc *m, int line, int *pos, break; if (pp > *v && ' ' != *(pp - 1)) continue; - if (' ' == *(pp + 2) || 0 == *(pp + 2)) + if (' ' == *(pp + 2) || '\0' == *(pp + 2)) break; } @@ -491,7 +486,7 @@ args(struct mdoc *m, int line, int *pos, } /* Whitespace check for eoln case... */ - if (0 == *p && ' ' == *(p - 1) && ! (ARGS_NOWARN & fl)) + if ('\0' == *p && ' ' == *(p - 1) && ! (ARGS_NOWARN & fl)) if ( ! mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE)) return(ARGS_ERROR); @@ -564,7 +559,7 @@ args(struct mdoc *m, int line, int *pos, */ for ( ; buf[*pos]; (*pos)++) - if (' ' == buf[*pos] && '\\' != buf[*pos - 1]) + if (*pos && ' ' == buf[*pos] && '\\' != buf[*pos - 1]) break; if ('\0' == buf[*pos]) diff --git a/usr.bin/mandoc/mdoc_html.c b/usr.bin/mandoc/mdoc_html.c index 658dfbf2c96..be432204989 100644 --- a/usr.bin/mandoc/mdoc_html.c +++ b/usr.bin/mandoc/mdoc_html.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_html.c,v 1.19 2010/05/24 12:33:06 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.20 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -80,6 +80,7 @@ static void mdoc_dq_post(MDOC_ARGS); static int mdoc_dq_pre(MDOC_ARGS); static int mdoc_dv_pre(MDOC_ARGS); static int mdoc_fa_pre(MDOC_ARGS); +static void mdoc_fd_post(MDOC_ARGS); static int mdoc_fd_pre(MDOC_ARGS); static int mdoc_fl_pre(MDOC_ARGS); static int mdoc_fn_pre(MDOC_ARGS); @@ -96,7 +97,8 @@ static int mdoc_it_block_pre(MDOC_ARGS, enum mdoc_list, int, struct roffsu *, struct roffsu *); static int mdoc_it_head_pre(MDOC_ARGS, enum mdoc_list, struct roffsu *); -static int mdoc_it_body_pre(MDOC_ARGS, enum mdoc_list); +static int mdoc_it_body_pre(MDOC_ARGS, enum mdoc_list, + struct roffsu *); static int mdoc_it_pre(MDOC_ARGS); static int mdoc_lb_pre(MDOC_ARGS); static int mdoc_li_pre(MDOC_ARGS); @@ -153,7 +155,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {mdoc_ev_pre, NULL}, /* Ev */ {mdoc_ex_pre, NULL}, /* Ex */ {mdoc_fa_pre, NULL}, /* Fa */ - {mdoc_fd_pre, NULL}, /* Fd */ + {mdoc_fd_pre, mdoc_fd_post}, /* Fd */ {mdoc_fl_pre, NULL}, /* Fl */ {mdoc_fn_pre, NULL}, /* Fn */ {mdoc_ft_pre, NULL}, /* Ft */ @@ -250,6 +252,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {mdoc_sp_pre, NULL}, /* br */ {mdoc_sp_pre, NULL}, /* sp */ {mdoc__x_pre, mdoc__x_post}, /* %U */ + {NULL, NULL}, /* Ta */ }; @@ -826,7 +829,6 @@ mdoc_it_block_pre(MDOC_ARGS, enum mdoc_list type, int comp, struct roffsu su; nn = n->parent->parent; - assert(nn->args); /* XXX: see notes in mdoc_it_pre(). */ @@ -873,7 +875,7 @@ mdoc_it_block_pre(MDOC_ARGS, enum mdoc_list type, int comp, /* ARGSUSED */ static int -mdoc_it_body_pre(MDOC_ARGS, enum mdoc_list type) +mdoc_it_body_pre(MDOC_ARGS, enum mdoc_list type, struct roffsu *width) { struct htmlpair tag; struct roffsu su; @@ -884,6 +886,12 @@ mdoc_it_body_pre(MDOC_ARGS, enum mdoc_list type) case (LIST_ohang): /* FALLTHROUGH */ case (LIST_column): + bufcat_su(h, "min-width", width); + bufcat_style(h, "clear", "none"); + if (n->next) + bufcat_style(h, "float", "left"); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); break; default: /* @@ -916,12 +924,6 @@ mdoc_it_head_pre(MDOC_ARGS, enum mdoc_list type, struct roffsu *width) print_otag(h, TAG_DIV, 0, &tag); return(1); case (LIST_column): - bufcat_su(h, "min-width", width); - bufcat_style(h, "clear", "none"); - if (n->next && MDOC_HEAD == n->next->type) - bufcat_style(h, "float", "left"); - PAIR_STYLE_INIT(&tag, h); - print_otag(h, TAG_DIV, 1, &tag); break; default: bufcat_su(h, "min-width", width); @@ -1008,7 +1010,8 @@ mdoc_it_pre(MDOC_ARGS) /* Get width, offset, and compact arguments. */ - for (wp = -1, comp = i = 0; i < (int)bl->args->argc; i++) + wp = -1; + for (comp = i = 0; bl->args && i < (int)bl->args->argc; i++) switch (bl->args->argv[i].arg) { case (MDOC_Column): wp = i; /* Save for later. */ @@ -1044,25 +1047,21 @@ mdoc_it_pre(MDOC_ARGS) break; } - /* Flip to body/block processing. */ - - if (MDOC_BODY == n->type) - return(mdoc_it_body_pre(m, n, h, type)); - if (MDOC_BLOCK == n->type) - return(mdoc_it_block_pre(m, n, h, type, comp, - &offs, &width)); - - /* Override column widths. */ - - if (LIST_column == type) { + if (LIST_column == type && MDOC_BODY == n->type) { nn = n->parent->child; - for (i = 0; nn && nn != n; nn = nn->next, i++) - /* Counter... */ ; + for (i = 0; nn && nn != n; nn = nn->next) + if (MDOC_BODY == nn->type) + i++; if (i < (int)bl->args->argv[wp].sz) a2width(bl->args->argv[wp].value[i], &width); } - return(mdoc_it_head_pre(m, n, h, type, &width)); + if (MDOC_HEAD == n->type) + return(mdoc_it_head_pre(m, n, h, type, &width)); + else if (MDOC_BODY == n->type) + return(mdoc_it_body_pre(m, n, h, type, &width)); + + return(mdoc_it_block_pre(m, n, h, type, comp, &offs, &width)); } @@ -1244,7 +1243,7 @@ mdoc_d1_pre(MDOC_ARGS) /* FIXME: D1 shouldn't be literal. */ - SCALE_VS_INIT(&su, INDENT - 1); + SCALE_VS_INIT(&su, INDENT - 2); bufcat_su(h, "margin-left", &su); PAIR_CLASS_INIT(&tag[0], "lit"); PAIR_STYLE_INIT(&tag[1], h); @@ -1320,7 +1319,7 @@ mdoc_bd_pre(MDOC_ARGS) SCALE_VS_INIT(&su, 0); type = comp = 0; - for (i = 0; i < (int)bl->args->argc; i++) + for (i = 0; bl->args && i < (int)bl->args->argc; i++) switch (bl->args->argv[i].arg) { case (MDOC_Offset): a2offs(bl->args->argv[i].value[0], &su); @@ -1508,21 +1507,19 @@ mdoc_fa_pre(MDOC_ARGS) /* ARGSUSED */ +static void +mdoc_fd_post(MDOC_ARGS) +{ + + print_otag(h, TAG_BR, 0, NULL); +} + + +/* ARGSUSED */ static int mdoc_fd_pre(MDOC_ARGS) { struct htmlpair tag; - struct roffsu su; - - if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) { - if (n->next && MDOC_Fd != n->next->tok) { - SCALE_VS_INIT(&su, 1); - bufcat_su(h, "margin-bottom", &su); - PAIR_STYLE_INIT(&tag, h); - print_otag(h, TAG_DIV, 1, &tag); - } else - print_otag(h, TAG_DIV, 0, NULL); - } PAIR_CLASS_INIT(&tag, "macro"); print_otag(h, TAG_SPAN, 1, &tag); @@ -1562,8 +1559,8 @@ mdoc_ft_pre(MDOC_ARGS) { struct htmlpair tag; - if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) - print_otag(h, TAG_DIV, 0, NULL); + if (SEC_SYNOPSIS == n->sec && n->prev) + print_otag(h, TAG_BR, 0, NULL); PAIR_CLASS_INIT(&tag, "ftype"); print_otag(h, TAG_SPAN, 1, &tag); @@ -1583,15 +1580,16 @@ mdoc_fn_pre(MDOC_ARGS) int sz, i; struct roffsu su; - if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) { + /* NB: MDOC_LINE has no effect on this macro! */ + if (SEC_SYNOPSIS == n->sec) { SCALE_HS_INIT(&su, INDENT); bufcat_su(h, "margin-left", &su); su.scale = -su.scale; bufcat_su(h, "text-indent", &su); - if (n->next) { + if (n->prev && MDOC_Ft != n->prev->tok) { SCALE_VS_INIT(&su, 1); - bufcat_su(h, "margin-bottom", &su); - } + bufcat_su(h, "margin-top", &su); + } PAIR_STYLE_INIT(&tag[0], h); print_otag(h, TAG_DIV, 1, tag); } @@ -1779,25 +1777,39 @@ mdoc_mt_pre(MDOC_ARGS) static int mdoc_fo_pre(MDOC_ARGS) { - struct htmlpair tag; - struct roffsu su; + struct htmlpair tag; + struct roffsu su; + struct tag *t; if (MDOC_BODY == n->type) { h->flags |= HTML_NOSPACE; print_text(h, "("); h->flags |= HTML_NOSPACE; return(1); - } else if (MDOC_BLOCK == n->type && n->next) { + } else if (MDOC_BLOCK == n->type) { + if (SEC_SYNOPSIS != n->sec) + return(1); + if (NULL == n->prev || MDOC_Ft == n->prev->tok) { + print_otag(h, TAG_DIV, 0, NULL); + return(1); + } SCALE_VS_INIT(&su, 1); - bufcat_su(h, "margin-bottom", &su); + bufcat_su(h, "margin-top", &su); PAIR_STYLE_INIT(&tag, h); print_otag(h, TAG_DIV, 1, &tag); return(1); } + /* XXX: we drop non-initial arguments as per groff. */ + + assert(n->child); + assert(n->child->string); + PAIR_CLASS_INIT(&tag, "fname"); - print_otag(h, TAG_SPAN, 1, &tag); - return(1); + t = print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, n->child->string); + print_tagq(h, t); + return(0); } @@ -1822,31 +1834,16 @@ mdoc_in_pre(MDOC_ARGS) struct tag *t; struct htmlpair tag[2]; int i; - struct roffsu su; - - if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) { - if (n->next && MDOC_In != n->next->tok) { - SCALE_VS_INIT(&su, 1); - bufcat_su(h, "margin-bottom", &su); - PAIR_STYLE_INIT(&tag[0], h); - print_otag(h, TAG_DIV, 1, tag); - } else - print_otag(h, TAG_DIV, 0, NULL); - } - - /* FIXME: there's a buffer bug in here somewhere. */ PAIR_CLASS_INIT(&tag[0], "includes"); print_otag(h, TAG_SPAN, 1, tag); - if (SEC_SYNOPSIS == n->sec) + if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) print_text(h, "#include"); print_text(h, "<"); h->flags |= HTML_NOSPACE; - /* XXX -- see warning in termp_in_post(). */ - for (nn = n->child; nn; nn = nn->next) { PAIR_CLASS_INIT(&tag[0], "link-includes"); i = 1; @@ -1864,6 +1861,9 @@ mdoc_in_pre(MDOC_ARGS) h->flags |= HTML_NOSPACE; print_text(h, ">"); + if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) + print_otag(h, TAG_BR, 0, NULL); + return(0); } @@ -1995,8 +1995,7 @@ mdoc_bf_pre(MDOC_ARGS) else if ( ! strcmp("Li", n->head->child->string)) PAIR_CLASS_INIT(&tag[0], "lit"); } else { - assert(n->args); - for (i = 0; i < (int)n->args->argc; i++) + for (i = 0; n->args && i < (int)n->args->argc; i++) switch (n->args->argv[i].arg) { case (MDOC_Symbolic): PAIR_CLASS_INIT(&tag[0], "symb"); diff --git a/usr.bin/mandoc/mdoc_macro.c b/usr.bin/mandoc/mdoc_macro.c index 230dbd2c8ef..bd0ea15fb34 100644 --- a/usr.bin/mandoc/mdoc_macro.c +++ b/usr.bin/mandoc/mdoc_macro.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.45 2010/06/06 18:08:41 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.46 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -40,13 +40,13 @@ static int in_line_eoln(MACRO_PROT_ARGS); static int in_line_argn(MACRO_PROT_ARGS); static int in_line(MACRO_PROT_ARGS); static int obsolete(MACRO_PROT_ARGS); +static int phrase_ta(MACRO_PROT_ARGS); static int append_delims(struct mdoc *, int, int *, char *); static enum mdoct lookup(enum mdoct, const char *); static enum mdoct lookup_raw(const char *); -static int phrase(struct mdoc *, int, int, - char *, enum margserr); +static int phrase(struct mdoc *, int, int, char *); static enum mdoct rew_alt(enum mdoct); static int rew_dobreak(enum mdoct, const struct mdoc_node *); @@ -182,6 +182,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_eoln, 0 }, /* br */ { in_line_eoln, 0 }, /* sp */ { in_line_eoln, 0 }, /* %U */ + { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */ }; const struct mdoc_macro * const mdoc_macros = __mdoc_macros; @@ -192,7 +193,7 @@ swarn(struct mdoc *mdoc, enum mdoc_type type, int line, int pos, const struct mdoc_node *p) { const char *n, *t, *tt; - int rc; + enum mandocerr ec; n = t = "<root>"; tt = "block"; @@ -225,11 +226,12 @@ swarn(struct mdoc *mdoc, enum mdoc_type type, break; } - rc = mdoc_vmsg(mdoc, MANDOCERR_SCOPE, line, pos, - "%s scope breaks %s of %s", tt, t, n); + ec = (MDOC_IGN_SCOPE & mdoc->pflags) ? + MANDOCERR_SCOPE : MANDOCERR_SYNTSCOPE; - /* FIXME: logic should be in driver. */ - return(MDOC_IGN_SCOPE & mdoc->pflags ? rc : 0); + return(mdoc_vmsg(mdoc, ec, line, pos, + "%s scope breaks %s of %s", + tt, t, n)); } @@ -928,6 +930,7 @@ blk_full(MACRO_PROT_ARGS) struct mdoc_node *head; /* save of head macro */ struct mdoc_node *body; /* save of body macro */ struct mdoc_node *n; + enum mdoc_type mtt; enum mdoct ntok; enum margserr ac, lac; enum margverr av; @@ -996,24 +999,38 @@ blk_full(MACRO_PROT_ARGS) for ( ; ; ) { la = *pos; - lac = ac; + /* Initialise last-phrase-type with ARGS_PEND. */ + lac = ARGS_ERROR == ac ? ARGS_PEND : ac; ac = mdoc_args(m, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); - if (ARGS_EOLN == ac) - break; - if (ARGS_PEND == ac) { - if (ARGS_PPHRASE == lac) - ac = ARGS_PPHRASE; - else - ac = ARGS_PHRASE; + if (ARGS_EOLN == ac) { + if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac) + break; + /* + * This is necessary: if the last token on a + * line is a `Ta' or tab, then we'll get + * ARGS_EOLN, so we must be smart enough to + * reopen our scope if the last parse was a + * phrase or partial phrase. + */ + if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + return(0); + if ( ! mdoc_body_alloc(m, line, ppos, tok)) + return(0); + body = m->last; + break; } - /* Don't emit leading punct. for phrases. */ + /* + * Emit leading punctuation (i.e., punctuation before + * the MDOC_HEAD) for non-phrase types. + */ if (NULL == head && + ARGS_PEND != ac && ARGS_PHRASE != ac && ARGS_PPHRASE != ac && ARGS_QWORD != ac && @@ -1023,24 +1040,47 @@ blk_full(MACRO_PROT_ARGS) continue; } - /* Always re-open head for phrases. */ + /* Open a head if one hasn't been opened. */ - if (NULL == head || - ARGS_PHRASE == ac || - ARGS_PPHRASE == ac) { + if (NULL == head) { if ( ! mdoc_head_alloc(m, line, ppos, tok)) return(0); head = m->last; } - if (ARGS_PHRASE == ac || ARGS_PPHRASE == ac) { + if (ARGS_PHRASE == ac || + ARGS_PEND == ac || + ARGS_PPHRASE == ac) { + /* + * If we haven't opened a body yet, rewind the + * head; if we have, rewind that instead. + */ + + mtt = body ? MDOC_BODY : MDOC_HEAD; + if ( ! rew_sub(mtt, m, tok, line, ppos)) + return(0); + + /* Then allocate our body context. */ + + if ( ! mdoc_body_alloc(m, line, ppos, tok)) + return(0); + body = m->last; + + /* + * Process phrases: set whether we're in a + * partial-phrase (this effects line handling) + * then call down into the phrase parser. + */ + if (ARGS_PPHRASE == ac) m->flags |= MDOC_PPHRASE; - if ( ! phrase(m, line, la, buf, ac)) + if (ARGS_PEND == ac && ARGS_PPHRASE == lac) + m->flags |= MDOC_PPHRASE; + + if ( ! phrase(m, line, la, buf)) return(0); + m->flags &= ~MDOC_PPHRASE; - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) - return(0); continue; } @@ -1069,7 +1109,7 @@ blk_full(MACRO_PROT_ARGS) /* If we've already opened our body, exit now. */ if (NULL != body) - return(1); + goto out; /* * If there is an open (i.e., unvalidated) sub-block requiring @@ -1093,6 +1133,16 @@ blk_full(MACRO_PROT_ARGS) if ( ! mdoc_body_alloc(m, line, ppos, tok)) return(0); +out: + if ( ! (MDOC_FREECOL & m->flags)) + return(1); + + if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + return(0); + if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + return(0); + + m->flags &= ~MDOC_FREECOL; return(1); } @@ -1582,26 +1632,24 @@ obsolete(MACRO_PROT_ARGS) * macro is encountered. */ static int -phrase(struct mdoc *m, int line, int ppos, char *buf, enum margserr ac) +phrase(struct mdoc *m, int line, int ppos, char *buf) { int la, pos; - enum margserr aac; + enum margserr ac; enum mdoct ntok; char *p; - assert(ARGS_PHRASE == ac || ARGS_PPHRASE == ac); - for (pos = ppos; ; ) { la = pos; - aac = mdoc_zargs(m, line, &pos, buf, 0, &p); + ac = mdoc_zargs(m, line, &pos, buf, 0, &p); - if (ARGS_ERROR == aac) + if (ARGS_ERROR == ac) return(0); - if (ARGS_EOLN == aac) + if (ARGS_EOLN == ac) break; - ntok = ARGS_QWORD == aac ? MDOC_MAX : lookup_raw(p); + ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { if ( ! mdoc_word_alloc(m, line, la, p)) @@ -1618,3 +1666,46 @@ phrase(struct mdoc *m, int line, int ppos, char *buf, enum margserr ac) } +/* ARGSUSED */ +static int +phrase_ta(MACRO_PROT_ARGS) +{ + int la; + enum mdoct ntok; + enum margserr ac; + char *p; + + /* + * FIXME: this is overly restrictive: if the `Ta' is unexpected, + * it should simply error out with ARGSLOST. + */ + + if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos)) + return(0); + if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It)) + return(0); + + for (;;) { + la = *pos; + ac = mdoc_zargs(m, line, pos, buf, 0, &p); + + if (ARGS_ERROR == ac) + return(0); + if (ARGS_EOLN == ac) + break; + + ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); + + if (MDOC_MAX == ntok) { + if ( ! mdoc_word_alloc(m, line, la, p)) + return(0); + continue; + } + + if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + return(0); + return(append_delims(m, line, pos, buf)); + } + + return(1); +} diff --git a/usr.bin/mandoc/mdoc_term.c b/usr.bin/mandoc/mdoc_term.c index 43d2a3d3593..733edc54b34 100644 --- a/usr.bin/mandoc/mdoc_term.c +++ b/usr.bin/mandoc/mdoc_term.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_term.c,v 1.84 2010/06/06 18:08:41 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.85 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -78,7 +78,6 @@ static void termp_dq_post(DECL_ARGS); static void termp_fd_post(DECL_ARGS); static void termp_fn_post(DECL_ARGS); static void termp_fo_post(DECL_ARGS); -static void termp_ft_post(DECL_ARGS); static void termp_in_post(DECL_ARGS); static void termp_it_post(DECL_ARGS); static void termp_lb_post(DECL_ARGS); @@ -162,7 +161,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_bold_pre, termp_fd_post }, /* Fd */ { termp_fl_pre, NULL }, /* Fl */ { termp_fn_pre, termp_fn_post }, /* Fn */ - { termp_ft_pre, termp_ft_post }, /* Ft */ + { termp_ft_pre, NULL }, /* Ft */ { termp_bold_pre, NULL }, /* Ic */ { termp_in_pre, termp_in_post }, /* In */ { termp_li_pre, NULL }, /* Li */ @@ -256,6 +255,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_sp_pre, NULL }, /* br */ { termp_sp_pre, NULL }, /* sp */ { termp_under_pre, termp____post }, /* %U */ + { NULL, NULL }, /* Ta */ }; @@ -696,7 +696,7 @@ termp_it_pre(DECL_ARGS) switch (type) { case (LIST_column): - if (MDOC_BODY == n->type) + if (MDOC_HEAD == n->type) break; /* * Imitate groff's column handling: @@ -711,8 +711,13 @@ termp_it_pre(DECL_ARGS) /* LINTED */ dcol = ncols < 5 ? 4 : ncols == 5 ? 3 : 1; + /* + * Calculate the offset by applying all prior MDOC_BODY, + * so we stop at the MDOC_HEAD (NULL == nn->prev). + */ + for (i = 0, nn = n->prev; - nn && i < (int)ncols; + nn->prev && i < (int)ncols; nn = nn->prev, i++) offset += dcol + a2width (&bl->args->argv[vals[2]], i); @@ -865,15 +870,18 @@ termp_it_pre(DECL_ARGS) p->flags |= TERMP_DANGLE; break; case (LIST_column): - if (MDOC_HEAD == n->type) { - assert(n->next); - if (MDOC_BODY == n->next->type) - p->flags &= ~TERMP_NOBREAK; - else - p->flags |= TERMP_NOBREAK; - if (n->prev) - p->flags |= TERMP_NOLPAD; - } + if (MDOC_HEAD == n->type) + break; + + if (NULL == n->next) + p->flags &= ~TERMP_NOBREAK; + else + p->flags |= TERMP_NOBREAK; + + assert(n->prev); + if (MDOC_BODY == n->prev->type) + p->flags |= TERMP_NOLPAD; + break; case (LIST_diag): if (MDOC_HEAD == n->type) @@ -925,9 +933,9 @@ termp_it_pre(DECL_ARGS) * XXX - this behaviour is not documented: the * right-most column is filled to the right margin. */ - if (MDOC_HEAD == n->type && - MDOC_BODY == n->next->type && - p->rmargin < p->maxrmargin) + if (MDOC_HEAD == n->type) + break; + if (NULL == n->next && p->rmargin < p->maxrmargin) p->rmargin = p->maxrmargin; break; default: @@ -981,7 +989,7 @@ termp_it_pre(DECL_ARGS) return(0); break; case (LIST_column): - if (MDOC_BODY == n->type) + if (MDOC_HEAD == n->type) return(0); break; default: @@ -1013,7 +1021,7 @@ termp_it_post(DECL_ARGS) term_newln(p); break; case (LIST_column): - if (MDOC_HEAD == n->type) + if (MDOC_BODY == n->type) term_flushln(p); break; default: @@ -1345,12 +1353,7 @@ static void termp_fd_post(DECL_ARGS) { - if (n->sec != SEC_SYNOPSIS || ! (MDOC_LINE & n->flags)) - return; - term_newln(p); - if (n->next && MDOC_Fd != n->next->tok) - term_vspace(p); } @@ -1503,9 +1506,9 @@ static int termp_ft_pre(DECL_ARGS) { - if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) - if (n->prev && MDOC_Fo == n->prev->tok) - term_vspace(p); + /* NB: MDOC_LINE does not effect this! */ + if (SEC_SYNOPSIS == n->sec && n->prev) + term_vspace(p); term_fontpush(p, TERMFONT_UNDER); return(1); @@ -1513,21 +1516,19 @@ termp_ft_pre(DECL_ARGS) /* ARGSUSED */ -static void -termp_ft_post(DECL_ARGS) -{ - - if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) - term_newln(p); -} - - -/* ARGSUSED */ static int termp_fn_pre(DECL_ARGS) { const struct mdoc_node *nn; + /* NB: MDOC_LINE has no effect on this macro! */ + if (SEC_SYNOPSIS == n->sec) { + if (n->prev && MDOC_Ft == n->prev->tok) + term_newln(p); + else if (n->prev) + term_vspace(p); + } + term_fontpush(p, TERMFONT_BOLD); term_word(p, n->child->string); term_fontpop(p); @@ -1558,8 +1559,9 @@ static void termp_fn_post(DECL_ARGS) { - if (n->sec == SEC_SYNOPSIS && n->next && MDOC_LINE & n->flags) - term_vspace(p); + /* NB: MDOC_LINE has no effect on this macro! */ + if (SEC_SYNOPSIS == n->sec) + term_newln(p); } @@ -1839,11 +1841,18 @@ static int termp_in_pre(DECL_ARGS) { - term_fontpush(p, TERMFONT_BOLD); - if (SEC_SYNOPSIS == n->sec) + if (SEC_SYNOPSIS == n->sec && n->prev && MDOC_In != n->prev->tok) + term_vspace(p); + + if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) { + term_fontpush(p, TERMFONT_BOLD); term_word(p, "#include"); + term_word(p, "<"); + } else { + term_word(p, "<"); + term_fontpush(p, TERMFONT_UNDER); + } - term_word(p, "<"); p->flags |= TERMP_NOSPACE; return(1); } @@ -1854,23 +1863,16 @@ static void termp_in_post(DECL_ARGS) { - term_fontpush(p, TERMFONT_BOLD); + if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) + term_fontpush(p, TERMFONT_BOLD); + p->flags |= TERMP_NOSPACE; term_word(p, ">"); - term_fontpop(p); - - if (SEC_SYNOPSIS != n->sec && ! (MDOC_LINE & n->flags)) - return; - term_newln(p); - /* - * XXX Not entirely correct. If `.In foo bar' is specified in - * the SYNOPSIS section, then it produces a single break after - * the <foo>; mandoc asserts a vertical space. Since this - * construction is rarely used, I think it's fine. - */ - if (n->next && MDOC_In != n->next->tok) - term_vspace(p); + if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags) { + term_fontpop(p); + term_newln(p); + } } @@ -1979,23 +1981,29 @@ termp_pq_post(DECL_ARGS) static int termp_fo_pre(DECL_ARGS) { - const struct mdoc_node *nn; - if (MDOC_BODY == n->type) { + if (MDOC_BLOCK == n->type) { + /* NB: MDOC_LINE has no effect on this macro! */ + if (SEC_SYNOPSIS != n->sec) + return(1); + if (n->prev && MDOC_Ft == n->prev->tok) + term_newln(p); + else if (n->prev) + term_vspace(p); + return(1); + } else if (MDOC_BODY == n->type) { p->flags |= TERMP_NOSPACE; term_word(p, "("); p->flags |= TERMP_NOSPACE; return(1); - } else if (MDOC_HEAD != n->type) - return(1); + } - term_fontpush(p, TERMFONT_BOLD); - for (nn = n->child; nn; nn = nn->next) { - assert(MDOC_TEXT == nn->type); - term_word(p, nn->string); - } - term_fontpop(p); + /* XXX: we drop non-initial arguments as per groff. */ + assert(n->child); + assert(n->child->string); + term_fontpush(p, TERMFONT_BOLD); + term_word(p, n->child->string); return(0); } @@ -2005,13 +2013,18 @@ static void termp_fo_post(DECL_ARGS) { - if (MDOC_BODY != n->type) - return; - p->flags |= TERMP_NOSPACE; - term_word(p, ")"); - p->flags |= TERMP_NOSPACE; - term_word(p, ";"); - term_newln(p); + if (MDOC_BLOCK == n->type) { + /* NB: MDOC_LINE has no effect on this macro! */ + if (SEC_SYNOPSIS == n->sec) + term_newln(p); + } else if (MDOC_BODY == n->type) { + p->flags |= TERMP_NOSPACE; + term_word(p, ")"); + if (SEC_SYNOPSIS == n->sec) { + p->flags |= TERMP_NOSPACE; + term_word(p, ";"); + } + } } diff --git a/usr.bin/mandoc/mdoc_validate.c b/usr.bin/mandoc/mdoc_validate.c index 459da6d17cf..7d336d05567 100644 --- a/usr.bin/mandoc/mdoc_validate.c +++ b/usr.bin/mandoc/mdoc_validate.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.59 2010/06/06 18:08:41 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.60 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -30,7 +30,7 @@ /* FIXME: .Bl -diag can't have non-text children in HEAD. */ /* TODO: ignoring Pp (it's superfluous in some invocations). */ -#define PRE_ARGS struct mdoc *mdoc, const struct mdoc_node *n +#define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n #define POST_ARGS struct mdoc *mdoc typedef int (*v_pre)(PRE_ARGS); @@ -79,6 +79,7 @@ static int post_at(POST_ARGS); static int post_bf(POST_ARGS); static int post_bl(POST_ARGS); static int post_bl_head(POST_ARGS); +static int post_dt(POST_ARGS); static int post_it(POST_ARGS); static int post_lb(POST_ARGS); static int post_nm(POST_ARGS); @@ -109,6 +110,7 @@ static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; static v_post posts_bool[] = { eerr_eq1, ebool, NULL }; static v_post posts_eoln[] = { post_eoln, NULL }; +static v_post posts_dt[] = { post_dt, NULL }; static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; static v_post posts_it[] = { post_it, NULL }; static v_post posts_lb[] = { eerr_eq1, post_lb, NULL }; @@ -143,7 +145,7 @@ static v_pre pres_ss[] = { pre_ss, NULL }; const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Ap */ { pres_dd, posts_text }, /* Dd */ - { pres_dt, NULL }, /* Dt */ + { pres_dt, posts_dt }, /* Dt */ { pres_os, NULL }, /* Os */ { pres_sh, posts_sh }, /* Sh */ { pres_ss, posts_ss }, /* Ss */ @@ -262,11 +264,12 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_notext }, /* br */ { NULL, posts_sp }, /* sp */ { NULL, posts_text1 }, /* %U */ + { NULL, NULL }, /* Ta */ }; int -mdoc_valid_pre(struct mdoc *mdoc, const struct mdoc_node *n) +mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) { v_pre *p; int line, pos; @@ -528,79 +531,117 @@ pre_display(PRE_ARGS) static int pre_bl(PRE_ARGS) { - int pos, type, width, offset; - - if (MDOC_BLOCK != n->type) + int i, width, offs, cmpt, dupl; + enum mdoc_list lt; + + if (MDOC_BLOCK != n->type) { + assert(n->parent); + assert(MDOC_BLOCK == n->parent->type); + assert(MDOC_Bl == n->parent->tok); + assert(LIST__NONE != n->parent->data.list); + n->data.list = n->parent->data.list; return(1); - if (NULL == n->args) { - mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); - return(0); } - /* Make sure that only one type of list is specified. */ + /* + * First figure out which kind of list to use: bind ourselves to + * the first mentioned list type and warn about any remaining + * ones. If we find no list type, we default to LIST_item. + */ - type = offset = width = -1; + assert(LIST__NONE == n->data.list); + offs = width = cmpt = -1; /* LINTED */ - for (pos = 0; pos < (int)n->args->argc; pos++) - switch (n->args->argv[pos].arg) { + for (i = 0; n->args && i < (int)n->args->argc; i++) { + lt = LIST__NONE; + dupl = 0; + switch (n->args->argv[i].arg) { + /* Set list types. */ case (MDOC_Bullet): - /* FALLTHROUGH */ + lt = LIST_bullet; + break; case (MDOC_Dash): - /* FALLTHROUGH */ + lt = LIST_dash; + break; case (MDOC_Enum): - /* FALLTHROUGH */ + lt = LIST_enum; + break; case (MDOC_Hyphen): - /* FALLTHROUGH */ + lt = LIST_hyphen; + break; case (MDOC_Item): - /* FALLTHROUGH */ + lt = LIST_item; + break; case (MDOC_Tag): - /* FALLTHROUGH */ + lt = LIST_tag; + break; case (MDOC_Diag): - /* FALLTHROUGH */ + lt = LIST_diag; + break; case (MDOC_Hang): - /* FALLTHROUGH */ + lt = LIST_hang; + break; case (MDOC_Ohang): - /* FALLTHROUGH */ + lt = LIST_ohang; + break; case (MDOC_Inset): - /* FALLTHROUGH */ + lt = LIST_inset; + break; case (MDOC_Column): - if (type < 0) { - type = n->args->argv[pos].arg; - break; - } - if (mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP)) - break; - return(0); + lt = LIST_column; + break; + /* Set list arguments. */ case (MDOC_Compact): - if (type >= 0) - break; - if (mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) - break; - return(0); + if (cmpt >= 0) + dupl++; + cmpt = i; + break; case (MDOC_Width): if (width >= 0) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) - return(0); - if (type < 0 && ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) - return(0); - width = n->args->argv[pos].arg; + dupl++; + width = i; break; case (MDOC_Offset): - if (offset >= 0) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) - return(0); - if (type < 0 && ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) - return(0); - offset = n->args->argv[pos].arg; - break; - default: + if (offs >= 0) + dupl++; + offs = i; break; } - if (type < 0) { - mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); - return(0); + /* Check: duplicate auxiliary arguments. */ + + if (dupl) + if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) + return(0); + + /* Check: multiple list types. */ + + if (LIST__NONE != lt && n->data.list != LIST__NONE) + if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP)) + return(0); + + /* Assign list type. */ + + if (LIST__NONE != lt && n->data.list == LIST__NONE) + n->data.list = lt; + + /* The list type should come first. */ + + if (n->data.list == LIST__NONE) + if (width >= 0 || offs >= 0 || cmpt >= 0) + if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) + return(0); + + continue; + } + + /* Allow lists to default to LIST_item. */ + + if (LIST__NONE == n->data.list) { + if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE)) + return(0); + n->data.list = LIST_item; } /* @@ -609,23 +650,27 @@ pre_bl(PRE_ARGS) * and must also be warned. */ - switch (type) { - case (MDOC_Tag): - if (width < 0 && ! mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG)) - return(0); - break; - case (MDOC_Column): + switch (n->data.list) { + case (LIST_tag): + if (width >= 0) + break; + if (mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG)) + break; + return(0); + case (LIST_column): /* FALLTHROUGH */ - case (MDOC_Diag): + case (LIST_diag): /* FALLTHROUGH */ - case (MDOC_Ohang): + case (LIST_ohang): /* FALLTHROUGH */ - case (MDOC_Inset): + case (LIST_inset): /* FALLTHROUGH */ - case (MDOC_Item): - if (width >= 0 && ! mdoc_nmsg(mdoc, n, MANDOCERR_WIDTHARG)) - return(0); - break; + case (LIST_item): + if (width < 0) + break; + if (mdoc_nmsg(mdoc, n, MANDOCERR_WIDTHARG)) + break; + return(0); default: break; } @@ -734,10 +779,27 @@ pre_rv(PRE_ARGS) static int -pre_dt(PRE_ARGS) +post_dt(POST_ARGS) { + const struct mdoc_node *nn; + const char *p; + + if (NULL != (nn = mdoc->last->child)) + for (p = nn->string; *p; p++) { + if (toupper((u_char)*p) == *p) + continue; + if ( ! mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE)) + return(0); + break; + } + + return(1); +} - /* FIXME: make sure is capitalised. */ + +static int +pre_dt(PRE_ARGS) +{ if (0 == mdoc->meta.date || mdoc->meta.os) if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) @@ -905,71 +967,37 @@ post_an(POST_ARGS) static int post_it(POST_ARGS) { - int type, i, cols; + int i, cols, rc; + enum mdoc_list lt; struct mdoc_node *n, *c; + enum mandocerr er; if (MDOC_BLOCK != mdoc->last->type) return(1); n = mdoc->last->parent->parent; - if (NULL == n->args) { - mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); - return(0); - } - - /* Some types require block-head, some not. */ - - /* LINTED */ - for (cols = type = -1, i = 0; -1 == type && - i < (int)n->args->argc; i++) - switch (n->args->argv[i].arg) { - case (MDOC_Tag): - /* FALLTHROUGH */ - case (MDOC_Diag): - /* FALLTHROUGH */ - case (MDOC_Hang): - /* FALLTHROUGH */ - case (MDOC_Ohang): - /* FALLTHROUGH */ - case (MDOC_Inset): - /* FALLTHROUGH */ - case (MDOC_Bullet): - /* FALLTHROUGH */ - case (MDOC_Dash): - /* FALLTHROUGH */ - case (MDOC_Enum): - /* FALLTHROUGH */ - case (MDOC_Hyphen): - /* FALLTHROUGH */ - case (MDOC_Item): - type = n->args->argv[i].arg; - break; - case (MDOC_Column): - type = n->args->argv[i].arg; - cols = (int)n->args->argv[i].sz; - break; - default: - break; - } + lt = n->data.list; - if (-1 == type) { + if (LIST__NONE == lt) { mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); return(0); } - switch (type) { - case (MDOC_Tag): - if (NULL == mdoc->last->head->child) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) - return(0); + switch (lt) { + case (LIST_tag): + if (mdoc->last->head->child) + break; + /* FIXME: give this a dummy value. */ + if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) + return(0); break; - case (MDOC_Hang): + case (LIST_hang): /* FALLTHROUGH */ - case (MDOC_Ohang): + case (LIST_ohang): /* FALLTHROUGH */ - case (MDOC_Inset): + case (LIST_inset): /* FALLTHROUGH */ - case (MDOC_Diag): + case (LIST_diag): if (NULL == mdoc->last->head->child) if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) return(0); @@ -977,15 +1005,15 @@ post_it(POST_ARGS) if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) return(0); break; - case (MDOC_Bullet): + case (LIST_bullet): /* FALLTHROUGH */ - case (MDOC_Dash): + case (LIST_dash): /* FALLTHROUGH */ - case (MDOC_Enum): + case (LIST_enum): /* FALLTHROUGH */ - case (MDOC_Hyphen): + case (LIST_hyphen): /* FALLTHROUGH */ - case (MDOC_Item): + case (LIST_item): if (mdoc->last->head->child) if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST)) return(0); @@ -993,32 +1021,36 @@ post_it(POST_ARGS) if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) return(0); break; - case (MDOC_Column): - if (NULL == mdoc->last->head->child) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) - return(0); - if (mdoc->last->body->child) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BODYLOST)) - return(0); - c = mdoc->last->child; - for (i = 0; c && MDOC_HEAD == c->type; c = c->next) - i++; - - if (i < cols) { - if ( ! mdoc_vmsg(mdoc, MANDOCERR_ARGCOUNT, - mdoc->last->line, - mdoc->last->pos, - "columns == %d (have %d)", - cols, i)) + case (LIST_column): + cols = -1; + for (i = 0; i < (int)n->args->argc; i++) + if (MDOC_Column == n->args->argv[i].arg) { + cols = (int)n->args->argv[i].sz; + break; + } + + assert(-1 != cols); + assert(NULL == mdoc->last->head->child); + + if (NULL == mdoc->last->body->child) + if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) return(0); + + for (i = 0, c = mdoc->last->child; c; c = c->next) + if (MDOC_BODY == c->type) + i++; + + if (i < cols) + er = MANDOCERR_ARGCOUNT; + else if (i == cols || i == cols + 1) break; - } else if (i == cols || i == cols + 1) - break; + else + er = MANDOCERR_SYNTARGCOUNT; - mdoc_vmsg(mdoc, MANDOCERR_SYNTARGCOUNT, + rc = mdoc_vmsg(mdoc, er, mdoc->last->line, mdoc->last->pos, "columns == %d (have %d)", cols, i); - return(0); + return(rc); default: break; } @@ -1030,20 +1062,23 @@ post_it(POST_ARGS) static int post_bl_head(POST_ARGS) { - int i; - const struct mdoc_node *n; - const struct mdoc_argv *a; + int i; + struct mdoc_node *n; + assert(mdoc->last->parent); n = mdoc->last->parent; - assert(n->args); - for (i = 0; i < (int)n->args->argc; i++) { - a = &n->args->argv[i]; - if (a->arg == MDOC_Column) { - if (a->sz && mdoc->last->nchild) - return(mdoc_nmsg(mdoc, n, MANDOCERR_COLUMNS)); - return(1); + if (LIST_column == n->data.list) { + for (i = 0; i < (int)n->args->argc; i++) + if (MDOC_Column == n->args->argv[i].arg) + break; + assert(i < (int)n->args->argc); + + if (n->args->argv[i].sz && mdoc->last->nchild) { + mdoc_nmsg(mdoc, n, MANDOCERR_COLUMNS); + return(0); } + return(1); } if (0 == (i = mdoc->last->nchild)) diff --git a/usr.bin/mandoc/roff.7 b/usr.bin/mandoc/roff.7 index a284ac105b5..65fca6dbb95 100644 --- a/usr.bin/mandoc/roff.7 +++ b/usr.bin/mandoc/roff.7 @@ -1,4 +1,4 @@ -.\" $Id: roff.7,v 1.3 2010/05/25 00:02:34 schwarze Exp $ +.\" $Id: roff.7,v 1.4 2010/06/06 20:30:08 schwarze Exp $ .\" .\" Copyright (c) 2010 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: May 25 2010 $ +.Dd $Mdocdate: June 6 2010 $ .Dt ROFF 7 .Os .Sh NAME @@ -207,7 +207,9 @@ macro is discarded. Furthermore, if an explicit closing sequence .Sq \e} is specified in a free-form line, the entire line is accepted within the -scope of the prior macro, not only the text preceding the close. +scope of the prior macro, not only the text preceding the close, with the +.Sq \e} +collapsing into a zero-width space. .Ss \&ig Ignore input. Accepts the following syntax: diff --git a/usr.bin/mandoc/roff.c b/usr.bin/mandoc/roff.c index 62f17651a63..1169b559bad 100644 --- a/usr.bin/mandoc/roff.c +++ b/usr.bin/mandoc/roff.c @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.3 2010/06/06 18:08:41 schwarze Exp $ */ +/* $Id: roff.c,v 1.4 2010/06/06 20:30:08 schwarze Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -666,10 +666,8 @@ roff_cond_text(ROFF_ARGS) return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); } - if (ep > st && '\\' != *(ep - 1)) { - ep = '\0'; + if (ep == st || (ep > st && '\\' != *(ep - 1))) roffnode_pop(r); - } roffnode_cleanscope(r); return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); |