From: Sascha Wildner Date: Sat, 27 Mar 2010 19:25:34 +0000 (+0100) Subject: mandoc(1): Update to 1.9.19. X-Git-Url: https://gitweb.dragonflybsd.org/~syl/dragonfly.git/commitdiff_plain/17fcb2343dcfdde409ef92b8b235f9efbba9b18a mandoc(1): Update to 1.9.19. For a full list of changes, see . Thanks-to: Kristaps Dzonsons --- diff --git a/share/man/man7/mandoc_char.7 b/share/man/man7/mandoc_char.7 index 25d99cea89..209345f275 100644 --- a/share/man/man7/mandoc_char.7 +++ b/share/man/man7/mandoc_char.7 @@ -1,4 +1,4 @@ -.\" $Id: mandoc_char.7,v 1.31 2010/01/07 09:16:19 kristaps Exp $ +.\" $Id: mandoc_char.7,v 1.33 2010/03/23 13:25:01 kristaps Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons .\" @@ -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 February 20, 2010 +.Dd March 27, 2010 .Dt MANDOC_CHAR 7 .Os . @@ -540,6 +540,25 @@ implementations: .It \e*(>= Ta \*(>= Ta greater-than-equal .It \e*(aa Ta \*(aa Ta acute .It \e*(ga Ta \*(ga Ta grave +.It \e*(-- Ta \*(-- Ta dash +.It \e*(PI Ta \*(PI Ta pi +.It \e*(L" Ta \*(L" Ta left double-quote +.It \e*(R" Ta \*(R" Ta right double-quote +.It \e*(C+ Ta \*(C+ Ta C++ +.It \e*(C` Ta \*(C` Ta left single-quote +.It \e*(C' Ta \*(C' Ta right single-quote +.It \e*(Aq Ta \*(Aq Ta apostrophe quote +.It \e*^ Ta \*^ Ta up-arrow +.It \e*, Ta \*, Ta comma +.It \e*~ Ta \*~ Ta tilde +.It \e*/ Ta \*/ Ta forward slash +.It \e*: Ta \*: Ta umlaut +.It \e*8 Ta \*8 Ta beta +.It \e*o Ta \*o Ta degree symbol +.It \e*(D- Ta \*(D- Ta Eth +.It \e*(d- Ta \*(d- Ta eth +.It \e*(TH Ta \*(TH Ta Thorn +.It \e*(th Ta \*(th Ta thorn .El . . @@ -578,19 +597,6 @@ having no known representation: .Xr mandoc 1 . . -.Sh STANDARDS -.Rs -.%A The Unicode Consortium -.%T The Unicode Standard: Worldwide Character Encoding, Version 5.2 -.%D 1991 -.Re -.Rs -.%A W3C -.%T HTML 4.01 Specification -.%D December, 1999 -.Re -. -. .Sh AUTHORS The .Nm diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile index 306442b492..2b22f52083 100644 --- a/usr.bin/mandoc/Makefile +++ b/usr.bin/mandoc/Makefile @@ -1,6 +1,6 @@ # $OpenBSD: Makefile,v 1.21 2009/10/27 21:40:07 schwarze Exp $ -VERSION=1.9.15 +VERSION=1.9.19 CFLAGS+=-DVERSION=\"${VERSION}\" WARNS?= 3 diff --git a/usr.bin/mandoc/arch.in b/usr.bin/mandoc/arch.in index 97bd2f639a..fc0db57843 100644 --- a/usr.bin/mandoc/arch.in +++ b/usr.bin/mandoc/arch.in @@ -1,4 +1,4 @@ -/* $Id: arch.in,v 1.5 2009/06/10 20:18:43 kristaps Exp $ */ +/* $Id: arch.in,v 1.7 2010/03/26 07:07:58 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -25,6 +25,7 @@ */ LINE("alpha", "Alpha") +LINE("amd64", "AMD64") LINE("amiga", "Amiga") LINE("arc", "ARC") LINE("arm", "ARM") @@ -35,6 +36,7 @@ LINE("hppa", "HPPA") LINE("hppa64", "HPPA64") LINE("i386", "i386") LINE("landisk", "LANDISK") +LINE("loongson", "Loongson") LINE("luna88k", "Luna88k") LINE("mac68k", "Mac68k") LINE("macppc", "MacPPC") diff --git a/usr.bin/mandoc/chars.c b/usr.bin/mandoc/chars.c index aece6b4285..746535ba8e 100644 --- a/usr.bin/mandoc/chars.c +++ b/usr.bin/mandoc/chars.c @@ -1,4 +1,4 @@ -/* $Id: chars.c,v 1.16 2010/01/28 06:04:59 kristaps Exp $ */ +/* $Id: chars.c,v 1.17 2010/03/23 13:25:01 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -38,7 +38,7 @@ struct ln { #define CHARS_BOTH (CHARS_CHAR | CHARS_STRING) }; -#define LINES_MAX 350 +#define LINES_MAX 369 #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 15157c17f2..68ad9566de 100644 --- a/usr.bin/mandoc/chars.in +++ b/usr.bin/mandoc/chars.in @@ -1,4 +1,4 @@ -/* $Id: chars.in,v 1.20 2010/01/05 19:51:10 kristaps Exp $ */ +/* $Id: chars.in,v 1.21 2010/03/23 13:25:01 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -50,10 +50,10 @@ CHAR("a\"", 2, "\"", 1, "̋", 6) CHAR("a-", 2, "-", 1, "¯", 6) CHAR("a.", 2, ".", 1, "˙", 6) CHAR("a^", 2, "^", 1, "̂", 6) -CHAR("\'", 1, "\'", 1, "́", 6) +BOTH("\'", 1, "\'", 1, "́", 6) BOTH("aa", 2, "\'", 1, "́", 6) BOTH("ga", 2, "`", 1, "̀", 6) -CHAR("`", 1, "`", 1, "̀", 6) +BOTH("`", 1, "`", 1, "̀", 6) CHAR("ab", 2, "`", 1, "̆", 6) CHAR("ac", 2, ",", 1, "̧", 6) CHAR("ad", 2, "\"", 1, "̈", 6) @@ -321,8 +321,8 @@ CHAR("fi", 2, "fi", 2, "fi", 8) CHAR("fl", 2, "fl", 2, "fl", 8) CHAR("Fi", 2, "ffi", 3, "ffi", 8) CHAR("Fl", 2, "ffl", 3, "ffl", 8) -CHAR("AE", 2, "AE", 2, "Æ", 6) -CHAR("ae", 2, "ae", 2, "æ", 6) +BOTH("AE", 2, "AE", 2, "Æ", 6) +BOTH("ae", 2, "ae", 2, "æ", 6) CHAR("OE", 2, "OE", 2, "Œ", 6) CHAR("oe", 2, "oe", 2, "œ", 6) CHAR("ss", 2, "ss", 2, "ß", 6) @@ -347,6 +347,27 @@ CHAR("Po", 2, "L", 1, "£", 6) CHAR("Cs", 2, "x", 1, "¤", 6) CHAR("Fn", 2, "f", 1, "ƒ", 6) +/* pod2man holdovers. */ +STRING("--", 2, "--", 2, "—", 7) +STRING("PI", 2, "pi", 2, "π", 6) +STRING("L\"", 2, "``", 2, "“", 7) +STRING("R\"", 2, "\'\'", 2, "”", 7) +STRING("C+", 2, "C++", 3, "C++", 3) +STRING("C`", 2, "`", 1, "‘", 7) +STRING("C\'", 2, "\'", 1, "’", 7) +STRING("Aq", 2, "\'", 1, "\'", 1) +STRING("^", 1, "^", 1, "^", 1) +STRING(",", 1, ",", 1, ",", 1) +STRING("~", 1, "~", 1, "~", 1) +STRING("/", 1, "/", 1, "/", 1) +STRING(":", 1, "\"", 1, "̈", 6) +STRING("8", 1, "B", 1, "β", 6) +STRING("o", 1, "o", 1, "°", 6) +STRING("D-", 2, "D", 1, "Ð", 6) +STRING("d-", 2, "o", 1, "ð", 6) +STRING("TH", 2, "b", 1, "Þ", 6) +STRING("th", 2, "b", 1, "þ", 6) + /* Old style. */ STRING("Am", 2, "&", 1, "&", 5) STRING("Ba", 2, "|", 1, "|", 1) diff --git a/usr.bin/mandoc/libman.h b/usr.bin/mandoc/libman.h index c0b5cb462f..ecd7da6251 100644 --- a/usr.bin/mandoc/libman.h +++ b/usr.bin/mandoc/libman.h @@ -1,4 +1,4 @@ -/* $Id: libman.h,v 1.23 2009/10/30 05:58:36 kristaps Exp $ */ +/* $Id: libman.h,v 1.28 2010/03/27 10:04:56 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -32,7 +32,8 @@ struct man { #define MAN_HALT (1 << 0) #define MAN_ELINE (1 << 1) /* Next-line element scope. */ #define MAN_BLINE (1 << 2) /* Next-line block scope. */ -#define MAN_LITERAL (1 << 3) /* Literal input. */ +#define MAN_ILINE (1 << 3) /* Ignored in next-line scope. */ +#define MAN_LITERAL (1 << 4) /* Literal input. */ enum man_next next; struct man_node *last; struct man_node *first; @@ -44,6 +45,7 @@ enum merr { WMSEC, WDATE, WLNSCOPE, + WLNSCOPE2, WTSPACE, WTQUOTE, WNODATA, @@ -58,10 +60,13 @@ enum merr { WNOSCOPE, WOLITERAL, WNLITERAL, + WROFFNEST, + WROFFSCOPE, + WTITLECASE, WERRMAX }; -#define MACRO_PROT_ARGS struct man *m, int tok, int line, \ +#define MACRO_PROT_ARGS struct man *m, enum mant tok, int line, \ int ppos, int *pos, char *buf struct man_macro { @@ -70,6 +75,8 @@ struct man_macro { #define MAN_SCOPED (1 << 0) #define MAN_EXPLICIT (1 << 1) /* See blk_imp(). */ #define MAN_FSCOPED (1 << 2) /* See blk_imp(). */ +#define MAN_NSCOPED (1 << 3) /* See in_line_eoln(). */ +#define MAN_NOCLOSE (1 << 4) /* See blk_exp(). */ }; extern const struct man_macro *const man_macros; @@ -86,14 +93,13 @@ __BEGIN_DECLS man_err((m), (n)->line, (n)->pos, 0, (t)) int man_word_alloc(struct man *, int, int, const char *); -int man_block_alloc(struct man *, int, int, int); -int man_head_alloc(struct man *, int, int, int); -int man_body_alloc(struct man *, int, int, int); -int man_elem_alloc(struct man *, int, int, int); -void man_node_free(struct man_node *); -void man_node_freelist(struct man_node *); +int man_block_alloc(struct man *, int, int, enum mant); +int man_head_alloc(struct man *, int, int, enum mant); +int man_body_alloc(struct man *, int, int, enum mant); +int man_elem_alloc(struct man *, int, int, enum mant); +void man_node_delete(struct man *, struct man_node *); void man_hash_init(void); -int man_hash_find(const char *); +enum mant man_hash_find(const char *); int man_macroend(struct man *); int man_args(struct man *, int, int *, char *, char **); #define ARGS_ERROR (-1) @@ -107,7 +113,8 @@ int man_valid_post(struct man *); int man_valid_pre(struct man *, const struct man_node *); int man_action_post(struct man *); int man_action_pre(struct man *, struct man_node *); -int man_unscope(struct man *, const struct man_node *); +int man_unscope(struct man *, + const struct man_node *, enum merr); __END_DECLS diff --git a/usr.bin/mandoc/main.c b/usr.bin/mandoc/main.c index a4a4ce8fec..361ceadce9 100644 --- a/usr.bin/mandoc/main.c +++ b/usr.bin/mandoc/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.59 2010/01/29 14:39:38 kristaps Exp $ */ +/* $Id: main.c,v 1.60 2010/03/22 20:43:00 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -68,11 +68,11 @@ struct curparse { #define WARN_WALL (1 << 0) /* All-warnings mask. */ #define WARN_WERR (1 << 2) /* Warnings->errors. */ int fflags; -#define IGN_SCOPE (1 << 0) /* Ignore scope errors. */ -#define NO_IGN_ESCAPE (1 << 1) /* Don't ignore bad escapes. */ -#define NO_IGN_MACRO (1 << 2) /* Don't ignore bad macros. */ -#define NO_IGN_CHARS (1 << 3) /* Don't ignore bad chars. */ -#define IGN_ERRORS (1 << 4) /* Ignore failed parse. */ +#define FL_IGN_SCOPE (1 << 0) /* Ignore scope errors. */ +#define FL_NIGN_ESCAPE (1 << 1) /* Don't ignore bad escapes. */ +#define FL_NIGN_MACRO (1 << 2) /* Don't ignore bad macros. */ +#define FL_NIGN_CHARS (1 << 3) /* Don't ignore bad chars. */ +#define FL_IGN_ERRORS (1 << 4) /* Ignore failed parse. */ enum intt inttype; /* Input parsers... */ struct man *man; struct man *lastman; @@ -86,8 +86,12 @@ struct curparse { char outopts[BUFSIZ]; }; +#define FL_STRICT FL_NIGN_ESCAPE | \ + FL_NIGN_MACRO | \ + FL_NIGN_CHARS + static int foptions(int *, char *); -static int toptions(enum outt *, char *); +static int toptions(struct curparse *, char *); static int moptions(enum intt *, char *); static int woptions(int *, char *); static int merr(void *, int, int, const char *); @@ -140,7 +144,7 @@ main(int argc, char *argv[]) (void)strlcat(curp.outopts, ",", BUFSIZ); break; case ('T'): - if ( ! toptions(&curp.outtype, optarg)) + if ( ! toptions(&curp, optarg)) return(EXIT_FAILURE); break; case ('W'): @@ -168,7 +172,7 @@ main(int argc, char *argv[]) curp.fd = STDIN_FILENO; c = fdesc(&blk, &ln, &curp); - if ( ! (IGN_ERRORS & curp.fflags)) + if ( ! (FL_IGN_ERRORS & curp.fflags)) rc = 1 == c ? 1 : 0; else rc = -1 == c ? 0 : 1; @@ -176,7 +180,7 @@ main(int argc, char *argv[]) while (rc && *argv) { c = ffile(&blk, &ln, *argv, &curp); - if ( ! (IGN_ERRORS & curp.fflags)) + if ( ! (FL_IGN_ERRORS & curp.fflags)) rc = 1 == c ? 1 : 0; else rc = -1 == c ? 0 : 1; @@ -240,11 +244,11 @@ man_init(struct curparse *curp) pflags = MAN_IGN_MACRO | MAN_IGN_ESCAPE | MAN_IGN_CHARS; - if (curp->fflags & NO_IGN_MACRO) + if (curp->fflags & FL_NIGN_MACRO) pflags &= ~MAN_IGN_MACRO; - if (curp->fflags & NO_IGN_CHARS) + if (curp->fflags & FL_NIGN_CHARS) pflags &= ~MAN_IGN_CHARS; - if (curp->fflags & NO_IGN_ESCAPE) + if (curp->fflags & FL_NIGN_ESCAPE) pflags &= ~MAN_IGN_ESCAPE; return(man_alloc(curp, pflags, &mancb)); @@ -264,13 +268,13 @@ mdoc_init(struct curparse *curp) pflags = MDOC_IGN_MACRO | MDOC_IGN_ESCAPE | MDOC_IGN_CHARS; - if (curp->fflags & IGN_SCOPE) + if (curp->fflags & FL_IGN_SCOPE) pflags |= MDOC_IGN_SCOPE; - if (curp->fflags & NO_IGN_ESCAPE) + if (curp->fflags & FL_NIGN_ESCAPE) pflags &= ~MDOC_IGN_ESCAPE; - if (curp->fflags & NO_IGN_MACRO) + if (curp->fflags & FL_NIGN_MACRO) pflags &= ~MDOC_IGN_MACRO; - if (curp->fflags & NO_IGN_CHARS) + if (curp->fflags & FL_NIGN_CHARS) pflags &= ~MDOC_IGN_CHARS; return(mdoc_alloc(curp, pflags, &mdoccb)); @@ -542,19 +546,22 @@ moptions(enum intt *tflags, char *arg) static int -toptions(enum outt *tflags, char *arg) +toptions(struct curparse *curp, char *arg) { if (0 == strcmp(arg, "ascii")) - *tflags = OUTT_ASCII; - else if (0 == strcmp(arg, "lint")) - *tflags = OUTT_LINT; + curp->outtype = OUTT_ASCII; + else if (0 == strcmp(arg, "lint")) { + curp->outtype = OUTT_LINT; + curp->wflags |= WARN_WALL; + curp->fflags |= FL_STRICT; + } else if (0 == strcmp(arg, "tree")) - *tflags = OUTT_TREE; + curp->outtype = OUTT_TREE; else if (0 == strcmp(arg, "html")) - *tflags = OUTT_HTML; + curp->outtype = OUTT_HTML; else if (0 == strcmp(arg, "xhtml")) - *tflags = OUTT_XHTML; + curp->outtype = OUTT_XHTML; else { fprintf(stderr, "%s: Bad argument\n", arg); return(0); @@ -583,26 +590,25 @@ foptions(int *fflags, char *arg) o = arg; switch (getsubopt(&arg, UNCONST(toks), &v)) { case (0): - *fflags |= IGN_SCOPE; + *fflags |= FL_IGN_SCOPE; break; case (1): - *fflags |= NO_IGN_ESCAPE; + *fflags |= FL_NIGN_ESCAPE; break; case (2): - *fflags |= NO_IGN_MACRO; + *fflags |= FL_NIGN_MACRO; break; case (3): - *fflags |= NO_IGN_CHARS; + *fflags |= FL_NIGN_CHARS; break; case (4): - *fflags |= IGN_ERRORS; + *fflags |= FL_IGN_ERRORS; break; case (5): - *fflags |= NO_IGN_ESCAPE | - NO_IGN_MACRO | NO_IGN_CHARS; + *fflags |= FL_STRICT; break; case (6): - *fflags &= ~NO_IGN_ESCAPE; + *fflags &= ~FL_NIGN_ESCAPE; break; default: fprintf(stderr, "%s: Bad argument\n", o); diff --git a/usr.bin/mandoc/man.3 b/usr.bin/mandoc/man.3 index 6a03afaa78..c1391424ad 100644 --- a/usr.bin/mandoc/man.3 +++ b/usr.bin/mandoc/man.3 @@ -1,4 +1,4 @@ -.\" $Id: man.3,v 1.12 2010/02/17 19:22:01 kristaps Exp $ +.\" $Id: man.3,v 1.13 2010/03/27 10:04:56 kristaps Exp $ .\" .\" Copyright (c) 2009-2010 Kristaps Dzonsons .\" @@ -14,11 +14,13 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd February 20, 2010 +.Dd March 27, 2010 .Dt MAN 3 .Os -.\" SECTION +. +. .Sh NAME +.Nm man , .Nm man_alloc , .Nm man_parseln , .Nm man_endparse , @@ -27,7 +29,8 @@ .Nm man_free , .Nm man_reset .Nd man macro compiler library -.\" SECTION +. +. .Sh SYNOPSIS .In man.h .Vt extern const char * const * man_macronames; @@ -45,16 +48,17 @@ .Fn man_meta "const struct man *man" .Ft int .Fn man_endparse "struct man *man" -.\" SECTION +. +. .Sh DESCRIPTION The -.Nm man +.Nm library parses lines of .Xr man 7 input (and .Em only man) into an abstract syntax tree (AST). -.\" PARAGRAPH +. .Pp In general, applications initiate a parsing sequence with .Fn man_alloc , @@ -74,8 +78,58 @@ function may be used in order to reset the parser for another input sequence. See the .Sx EXAMPLES section for a full example. -.\" PARAGRAPH +. +.Pp +Beyond the full set of macros defined in +.Xr man 7 , +the +.Nm +library also accepts the following macros: +. .Pp +.Bl -tag -width Ds -compact +.It am +.It ami +.It de +.It dei +.It ig +Instructional macros in the original roff language. Blocks begun by +these macros end with +.Sq .. +and may begin anywhere, although they may not break the next-line +scoping rules specified in +.Xr man 7 . +These blocks are discarded. +. +.It PD +Has no effect. Handled as a current-scope line macro. +. +.It Sp +A synonym for +.Sq sp 0.5v +.Pq part of the standard preamble for Perl documentation . +Handled as a line macro. +. +.It UC +Has no effect. Handled as a current-scope line macro. +. +.It Vb +A synonym for +.Sq nf +.Pq part of the standard preamble for Perl documentation . +Handled as a current-scope line macro. +. +.It Ve +A synonym for +.Sq fi , +closing +.Sq Vb +.Pq part of the standard preamble for Perl documentation . +Handled as a current-scope line macro. +.El +. +. +.Sh REFERENCE This section further defines the .Sx Types , .Sx Functions @@ -84,7 +138,8 @@ and available to programmers. Following that, the .Sx Abstract Syntax Tree section documents the output tree. -.\" SUBSECTION +. +. .Ss Types Both functions (see .Sx Functions ) @@ -92,16 +147,16 @@ and variables (see .Sx Variables ) may use the following types: .Bl -ohang -.\" LIST-ITEM +. .It Vt struct man An opaque type defined in .Pa man.c . Its values are only used privately within the library. -.\" LIST-ITEM +. .It Vt struct man_cb A set of message callbacks defined in .Pa man.h . -.\" LIST-ITEM +. .It Vt struct man_node A parsed node. Defined in .Pa man.h . @@ -109,11 +164,12 @@ See .Sx Abstract Syntax Tree for details. .El -.\" SUBSECTION +. +. .Ss Functions Function descriptions follow: .Bl -ohang -.\" LIST-ITEM +. .It Fn man_alloc Allocates a parsing structure. The .Fa data @@ -126,29 +182,29 @@ arguments are defined in .Pa man.h . Returns NULL on failure. If non-NULL, the pointer must be freed with .Fn man_free . -.\" LIST-ITEM +. .It Fn man_reset Reset the parser for another parse routine. After its use, .Fn man_parseln behaves as if invoked for the first time. -.\" LIST-ITEM +. .It Fn man_free Free all resources of a parser. The pointer is no longer valid after invocation. -.\" LIST-ITEM +. .It Fn man_parseln Parse a nil-terminated line of input. This line should not contain the trailing newline. Returns 0 on failure, 1 on success. The input buffer .Fa buf is modified by this function. -.\" LIST-ITEM +. .It Fn man_endparse Signals that the parse is complete. Note that if .Fn man_endparse is called subsequent to .Fn man_node , the resulting tree is incomplete. Returns 0 on failure, 1 on success. -.\" LIST-ITEM +. .It Fn man_node Returns the first node of the parse. Note that if .Fn man_parseln @@ -163,15 +219,17 @@ or .Fn man_endparse return 0, the data will be incomplete. .El -.\" SUBSECTION +. +. .Ss Variables The following variables are also defined: .Bl -ohang -.\" LIST-ITEM +. .It Va man_macronames An array of string-ified token names. .El -.\" SUBSECTION +. +. .Ss Abstract Syntax Tree The .Nm @@ -185,13 +243,13 @@ or after or .Fn man_parseln fail, it may be incomplete. -.\" PARAGRAPH +. .Pp This AST is governed by the ontological rules dictated in .Xr man 7 and derives its terminology accordingly. -.\" PARAGRAPH +. .Pp The AST is composed of .Vt struct man_node @@ -210,13 +268,12 @@ fields), its position in the tree (the and .Va prev fields) and some type-specific data. -.\" PARAGRAPH +. .Pp The tree itself is arranged according to the following normal form, where capitalised non-terminals represent nodes. .Pp .Bl -tag -width "ELEMENTXX" -compact -.\" LIST-ITEM .It ROOT \(<- mnode+ .It mnode @@ -232,12 +289,13 @@ where capitalised non-terminals represent nodes. .It TEXT \(<- [[:alpha:]]* .El -.\" PARAGRAPH +. .Pp The only elements capable of nesting other elements are those with next-lint scope as documented in .Xr man 7 . -.\" SECTION +. +. .Sh EXAMPLES The following example reads lines from stdin and parses them, operating on the finished parse tree with @@ -273,11 +331,13 @@ if (NULL == (node = man_node(man))) parsed(man, node); man_free(man); .Ed -.\" SECTION +. +. .Sh SEE ALSO .Xr mandoc 1 , .Xr man 7 -.\" SECTION +. +. .Sh AUTHORS The .Nm diff --git a/usr.bin/mandoc/man.7 b/usr.bin/mandoc/man.7 index 8e09c6b36d..6aa434ce8f 100644 --- a/usr.bin/mandoc/man.7 +++ b/usr.bin/mandoc/man.7 @@ -1,4 +1,4 @@ -.\" $Id: man.7,v 1.55 2010/01/07 19:10:09 kristaps Exp $ +.\" $Id: man.7,v 1.60 2010/03/27 10:22:28 kristaps Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons .\" @@ -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 February 20, 2010 +.Dd March 27, 2010 .Dt MAN 7 .Os . @@ -403,9 +403,11 @@ Documents any security precautions that operators should consider. Macros are one to three three characters in length and begin with a control character , .Sq \&. , -at the beginning of the line. An arbitrary amount of whitespace may -sit between the control character and the macro name. Thus, the -following are equivalent: +at the beginning of the line. The +.Sq \(aq +macro control character is also accepted. An arbitrary amount of +whitespace (spaces or tabs) may sit between the control character and +the macro name. Thus, the following are equivalent: .Bd -literal -offset indent \&.PP \&.\ \ \ PP @@ -423,8 +425,8 @@ subsequent lines until closed by another block macro. .Ss Line Macros Line macros are generally scoped to the current line, with the body consisting of zero or more arguments. If a macro is scoped to the next -line and the line arguments are empty, the next line is used instead, -else the general syntax is used. Thus: +line and the line arguments are empty, the next line, which must be +text, is used instead. Thus: .Bd -literal -offset indent \&.I foo @@ -433,63 +435,69 @@ foo .Pp is equivalent to .Sq \&.I foo . -If next-line macros are invoked consecutively, only the last is used; in -other words, if a next-line macro is preceded by a block macro, it is -ignored. +If next-line macros are invoked consecutively, only the last is used. +If a next-line macro is followed by a non-next-line macro, an error is +raised (unless in the case of +.Sx \&br , +.Sx \&sp , +.Sx \&Sp , +or +.Sx \&na ) . +.Pp +The syntax is as follows: .Bd -literal -offset indent \&.YO \(lBbody...\(rB \(lBbody...\(rB .Ed . .Pp -.Bl -column -compact -offset indent "MacroX" "ArgumentsX" "ScopeXXXXX" -.It Em Macro Ta Em Arguments Ta Em Scope -.It Sx \&B Ta n Ta next-line -.It Sx \&BI Ta n Ta current -.It Sx \&BR Ta n Ta current -.It Sx \&DT Ta 0 Ta current -.It Sx \&I Ta n Ta next-line -.It Sx \&IB Ta n Ta current -.It Sx \&IR Ta n Ta current -.It Sx \&PD Ta n Ta current -.It Sx \&R Ta n Ta next-line -.It Sx \&RB Ta n Ta current -.It Sx \&RI Ta n Ta current -.It Sx \&SB Ta n Ta next-line -.It Sx \&SM Ta n Ta next-line -.It Sx \&TH Ta >1, <6 Ta current -.It Sx \&UC Ta n Ta current -.It Sx \&br Ta 0 Ta current -.It Sx \&fi Ta 0 Ta current -.It Sx \&i Ta n Ta current -.It Sx \&na Ta 0 Ta current -.It Sx \&nf Ta 0 Ta current -.It Sx \&r Ta 0 Ta current -.It Sx \&sp Ta 1 Ta current +.Bl -column -compact -offset indent "MacroX" "ArgumentsX" "ScopeXXXXX" "CompatX" +.It Em Macro Ta Em Arguments Ta Em Scope Ta Em Notes +.It Sx \&B Ta n Ta next-line Ta \& +.It Sx \&BI Ta n Ta current Ta \& +.It Sx \&BR Ta n Ta current Ta \& +.It Sx \&DT Ta 0 Ta current Ta \& +.It Sx \&I Ta n Ta next-line Ta \& +.It Sx \&IB Ta n Ta current Ta \& +.It Sx \&IR Ta n Ta current Ta \& +.\" .It Sx \&PD Ta n Ta current Ta compat +.It Sx \&R Ta n Ta next-line Ta \& +.It Sx \&RB Ta n Ta current Ta \& +.It Sx \&RI Ta n Ta current Ta \& +.It Sx \&SB Ta n Ta next-line Ta \& +.It Sx \&SM Ta n Ta next-line Ta \& +.It Sx \&TH Ta >1, <6 Ta current Ta \& +.\" .It Sx \&UC Ta n Ta current Ta compat +.It Sx \&br Ta 0 Ta current Ta compat +.It Sx \&fi Ta 0 Ta current Ta compat +.It Sx \&i Ta n Ta current Ta compat +.It Sx \&na Ta 0 Ta current Ta compat +.It Sx \&nf Ta 0 Ta current Ta compat +.It Sx \&r Ta 0 Ta current Ta compat +.It Sx \&sp Ta 1 Ta current Ta compat +.\" .It Sx \&Sp Ta 0 Ta current Ta compat +.\" .It Sx \&Vb Ta <1 Ta current Ta compat +.\" .It Sx \&Ve Ta 0 Ta current Ta compat .El . .Pp -The -.Sx \&PD , -.Sx \&RS , -.Sx \&RE , -.Sx \&UC , -.Sx \&br , -.Sx \&fi , -.Sx \&i , -.Sx \&na , -.Sx \&nf , -.Sx \&r , -and -.Sx \&sp -macros should not be used. They're included for compatibility. +Macros marked as +.Qq compat +are included for compatibility with the significant corpus of existing +manuals that mix dialects of roff. These macros should not be used for +portable +.Nm +manuals. . . .Ss Block Macros Block macros are comprised of a head and body. Like for in-line macros, the head is scoped to the current line and, in one circumstance, the -next line; the body is scoped to subsequent lines and is closed out by a -subsequent block macro invocation. +next line (the next-line stipulations as in +.Sx Line Macros +apply here as well). +.Pp +The syntax is as follows: .Bd -literal -offset indent \&.YO \(lBhead...\(rB \(lBhead...\(rB @@ -515,33 +523,34 @@ or No closure refers to an explicit block closing macro. . .Pp -.Bl -column "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" -compact -offset indent -.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope -.It Sx \&HP Ta <2 Ta current Ta paragraph -.It Sx \&IP Ta <3 Ta current Ta paragraph -.It Sx \&LP Ta 0 Ta current Ta paragraph -.It Sx \&P Ta 0 Ta current Ta paragraph -.It Sx \&PP Ta 0 Ta current Ta paragraph -.It Sx \&RE Ta 0 Ta current Ta none -.It Sx \&RS Ta 1 Ta current Ta part -.It Sx \&SH Ta >0 Ta next-line Ta section -.It Sx \&SS Ta >0 Ta next-line Ta sub-section -.It Sx \&TP Ta n Ta next-line Ta paragraph +As a rule, block macros may not be nested; thus, calling a block macro +while another block macro scope is open, and the open scope is not +implicitly closed, is syntactically incorrect. +. +.Pp +.Bl -column -compact -offset indent "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" "compatX" +.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope Ta Em Notes +.It Sx \&HP Ta <2 Ta current Ta paragraph Ta \& +.It Sx \&IP Ta <3 Ta current Ta paragraph Ta \& +.It Sx \&LP Ta 0 Ta current Ta paragraph Ta \& +.It Sx \&P Ta 0 Ta current Ta paragraph Ta \& +.It Sx \&PP Ta 0 Ta current Ta paragraph Ta \& +.It Sx \&RE Ta 0 Ta current Ta none Ta compat +.It Sx \&RS Ta 1 Ta current Ta part Ta compat +.It Sx \&SH Ta >0 Ta next-line Ta section Ta \& +.It Sx \&SS Ta >0 Ta next-line Ta sub-section Ta \& +.It Sx \&TP Ta n Ta next-line Ta paragraph Ta \& .El +.Pp +. +Macros marked +.Qq compat +are as mentioned in +.Sx Line Macros . . .Pp If a block macro is next-line scoped, it may only be followed by in-line -macros (excluding -.Sx \&DT , -.Sx \&PD , -.Sx \&TH , -.Sx \&UC , -.Sx \&br , -.Sx \&na , -.Sx \&sp , -.Sx \&nf , -and -.Sx \&fi ) . +macros for decorating text. . . .Sh REFERENCE @@ -896,14 +905,14 @@ See also .Sx \&P , and .Sx \&PP . -. -. -.Ss \&PD -Has no effect. Included for compatibility. -. -. -.Ss \&UC -Has no effect. Included for compatibility. +.\" . +.\" . +.\" .Ss \&PD +.\" Has no effect. Included for compatibility. +.\" . +.\" . +.\" .Ss \&UC +.\" Has no effect. Included for compatibility. . . .Ss \&br @@ -971,31 +980,54 @@ macro. Defaults to 1, if unspecified. See also .Sx \&br . . +.\" .Ss \&Sp +.\" A synonym for +.\" .Sx \&sp +.\" .Cm 0.5v . +.\" . +.\" .Ss \&Vb +.\" A synonym for +.\" .Sx \&nf . +.\" Accepts an argument (the height of the formatted space) which is +.\" disregarded. +.\" . +.\" .Ss \&Ve +.\" A synonym for +.\" .Sx \&fi . +.\" . . .Sh COMPATIBILITY -This section documents compatibility with other roff implementations, at -this time limited to -.Xr groff 1 . +This section documents areas of questionable portability between +implementations of the +.Nm +language. +. .Pp .Bl -dash -compact .It -The -.Xr groff 1 -.Sx \&i -macro will italicise all subsequent text if a line argument is not -provided. This behaviour is not implemented. +In quoted literals, GNU troff allowed pair-wise double-quotes to produce +a standalone double-quote in formatted output. It is not known whether +this behaviour is exhibited by other formatters. +. .It -In quoted literals, groff allowed pair-wise double-quotes to produce a -standalone double-quote in formatted output. This idiosyncratic -behaviour is no longer applicable. +Blocks of whitespace are stripped from macro and free-form text lines +(except when in literal mode) in mandoc. This is not the case for GNU +troff: for maximum portability, whitespace sensitive blocks should be +enclosed in literal contexts. +. .It The .Sx \&sp -macro does not accept negative numbers. +macro does not accept negative values in mandoc. In GNU troff, this +would result in strange behaviour. +. .It -Blocks of whitespace are stripped from both macro and free-form text -lines (except when in literal mode), while groff would retain whitespace -in free-form text lines. +The +.Sq \(aq +macro control character, in GNU troff (and prior troffs) suppresses a +newline before macro output; in mandoc, it is an alias for the standard +.Sq \&. +control character. .El . . diff --git a/usr.bin/mandoc/man.c b/usr.bin/mandoc/man.c index 721fcff199..7b84ee5dd4 100644 --- a/usr.bin/mandoc/man.c +++ b/usr.bin/mandoc/man.c @@ -1,4 +1,4 @@ -/* $Id: man.c,v 1.49 2010/01/07 10:24:43 kristaps Exp $ */ +/* $Id: man.c,v 1.57 2010/03/27 10:26:39 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -31,6 +31,7 @@ const char *const __man_merrnames[WERRMAX] = { "invalid manual section", /* WMSEC */ "invalid date format", /* WDATE */ "scope of prior line violated", /* WLNSCOPE */ + "over-zealous prior line scope violation", /* WLNSCOPE2 */ "trailing whitespace", /* WTSPACE */ "unterminated quoted parameter", /* WTQUOTE */ "document has no body", /* WNODATA */ @@ -44,7 +45,10 @@ const char *const __man_merrnames[WERRMAX] = { "scope open on exit", /* WEXITSCOPE */ "no scope context", /* WNOSCOPE */ "literal context already open", /* WOLITERAL */ - "no literal context open" /* WNLITERAL */ + "no literal context open", /* WNLITERAL */ + "invalid nesting of roff declarations", /* WROFFNEST */ + "scope in roff instructions broken", /* WROFFSCOPE */ + "document title should be uppercase", /* WTITLECASE */ }; const char *const __man_macronames[MAN_MAX] = { @@ -55,15 +59,21 @@ const char *const __man_macronames[MAN_MAX] = { "R", "B", "I", "IR", "RI", "na", "i", "sp", "nf", "fi", "r", "RE", - "RS", "DT", "UC", "PD" + "RS", "DT", "UC", "PD", + "Sp", "Vb", "Ve", "de", + "dei", "am", "ami", "ig", + ".", }; const char * const *man_macronames = __man_macronames; static struct man_node *man_node_alloc(int, int, - enum man_type, int); + enum man_type, enum mant); static int man_node_append(struct man *, struct man_node *); +static void man_node_free(struct man_node *); +static void man_node_unlink(struct man *, + struct man_node *); static int man_ptext(struct man *, int, char *); static int man_pmacro(struct man *, int, char *); static void man_free1(struct man *); @@ -143,7 +153,7 @@ int man_parseln(struct man *m, int ln, char *buf) { - return('.' == *buf ? + return('.' == *buf || '\'' == *buf ? man_pmacro(m, ln, buf) : man_ptext(m, ln, buf)); } @@ -154,7 +164,7 @@ man_free1(struct man *man) { if (man->first) - man_node_freelist(man->first); + man_node_delete(man, man->first); if (man->meta.title) free(man->meta.title); if (man->meta.source) @@ -173,6 +183,7 @@ man_alloc1(struct man *m) 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; } @@ -200,6 +211,7 @@ man_node_append(struct man *man, struct man_node *p) /* NOTREACHED */ } + assert(p->parent); p->parent->nchild++; if ( ! man_valid_pre(man, p)) @@ -236,7 +248,7 @@ man_node_append(struct man *man, struct man_node *p) static struct man_node * -man_node_alloc(int line, int pos, enum man_type type, int tok) +man_node_alloc(int line, int pos, enum man_type type, enum mant tok) { struct man_node *p; @@ -250,7 +262,7 @@ man_node_alloc(int line, int pos, enum man_type type, int tok) int -man_elem_alloc(struct man *m, int line, int pos, int tok) +man_elem_alloc(struct man *m, int line, int pos, enum mant tok) { struct man_node *p; @@ -263,7 +275,7 @@ man_elem_alloc(struct man *m, int line, int pos, int tok) int -man_head_alloc(struct man *m, int line, int pos, int tok) +man_head_alloc(struct man *m, int line, int pos, enum mant tok) { struct man_node *p; @@ -276,7 +288,7 @@ man_head_alloc(struct man *m, int line, int pos, int tok) int -man_body_alloc(struct man *m, int line, int pos, int tok) +man_body_alloc(struct man *m, int line, int pos, enum mant tok) { struct man_node *p; @@ -289,7 +301,7 @@ man_body_alloc(struct man *m, int line, int pos, int tok) int -man_block_alloc(struct man *m, int line, int pos, int tok) +man_block_alloc(struct man *m, int line, int pos, enum mant tok) { struct man_node *p; @@ -308,7 +320,7 @@ pstring(struct man *m, int line, int pos, struct man_node *n; size_t sv; - n = man_node_alloc(line, pos, MAN_TEXT, -1); + n = man_node_alloc(line, pos, MAN_TEXT, MAN_MAX); n->string = mandoc_malloc(len + 1); sv = strlcpy(n->string, p, len + 1); @@ -330,30 +342,29 @@ man_word_alloc(struct man *m, int line, int pos, const char *word) } -void +/* + * Free all of the resources held by a node. This does NOT unlink a + * node from its context; for that, see man_node_unlink(). + */ +static void man_node_free(struct man_node *p) { if (p->string) free(p->string); - if (p->parent) - p->parent->nchild--; free(p); } void -man_node_freelist(struct man_node *p) +man_node_delete(struct man *m, struct man_node *p) { - struct man_node *n; - if (p->child) - man_node_freelist(p->child); - assert(0 == p->nchild); - n = p->next; + while (p->child) + man_node_delete(m, p->child); + + man_node_unlink(m, p); man_node_free(p); - if (n) - man_node_freelist(n); } @@ -434,7 +445,7 @@ descope: if (MAN_ELINE & m->flags) { m->flags &= ~MAN_ELINE; - if ( ! man_unscope(m, m->last->parent)) + if ( ! man_unscope(m, m->last->parent, WERRMAX)) return(0); } @@ -442,7 +453,7 @@ descope: return(1); m->flags &= ~MAN_BLINE; - if ( ! man_unscope(m, m->last->parent)) + if ( ! man_unscope(m, m->last->parent, WERRMAX)) return(0); return(man_body_alloc(m, line, 0, m->last->tok)); } @@ -463,7 +474,8 @@ macrowarn(struct man *m, int ln, const char *buf) int man_pmacro(struct man *m, int ln, char *buf) { - int i, j, c, ppos, fl; + int i, j, ppos, fl; + enum mant tok; char mac[5]; struct man_node *n; @@ -476,9 +488,13 @@ man_pmacro(struct man *m, int ln, char *buf) i = 1; - if (' ' == buf[i]) { + /* + * Skip whitespace between the control character and initial + * text. "Whitespace" is both spaces and tabs. + */ + if (' ' == buf[i] || '\t' == buf[i]) { i++; - while (buf[i] && ' ' == buf[i]) + while (buf[i] && (' ' == buf[i] || '\t' == buf[i])) i++; if ('\0' == buf[i]) goto out; @@ -513,7 +529,7 @@ man_pmacro(struct man *m, int ln, char *buf) return(1); } - if (MAN_MAX == (c = man_hash_find(mac))) { + if (MAN_MAX == (tok = man_hash_find(mac))) { if ( ! macrowarn(m, ln, mac)) goto err; return(1); @@ -530,42 +546,71 @@ man_pmacro(struct man *m, int ln, char *buf) if ( ! man_pwarn(m, ln, i - 1, WTSPACE)) goto err; - /* Remove prior ELINE macro, if applicable. */ + /* + * Remove prior ELINE macro, as it's being clobbering by a new + * macro. Note that NSCOPED macros do not close out ELINE + * macros---they don't print text---so we let those slip by. + */ + + if ( ! (MAN_NSCOPED & man_macros[tok].flags) && + m->flags & MAN_ELINE) { + assert(MAN_TEXT != m->last->type); + + /* + * This occurs in the following construction: + * .B + * .br + * .B + * .br + * I hate man macros. + * Flat-out disallow this madness. + */ + if (MAN_NSCOPED & man_macros[m->last->tok].flags) + return(man_perr(m, ln, ppos, WLNSCOPE)); - if (m->flags & MAN_ELINE) { n = m->last; + + assert(n); assert(NULL == n->child); assert(0 == n->nchild); + if ( ! man_nwarn(m, n, WLNSCOPE)) return(0); - if (n->prev) { - assert(n != n->parent->child); - assert(n == n->prev->next); - n->prev->next = NULL; - m->last = n->prev; - m->next = MAN_NEXT_SIBLING; - } else { - assert(n == n->parent->child); - n->parent->child = NULL; - m->last = n->parent; - m->next = MAN_NEXT_CHILD; - } - - man_node_free(n); + man_node_delete(m, n); m->flags &= ~MAN_ELINE; } /* Begin recursive parse sequence. */ - assert(man_macros[c].fp); + assert(man_macros[tok].fp); - if ( ! (*man_macros[c].fp)(m, c, ln, ppos, &i, buf)) + if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &i, buf)) goto err; out: - if ( ! (MAN_BLINE & fl)) + /* + * We weren't in a block-line scope when entering the + * above-parsed macro, so return. + * + * FIXME: this prohibits the nesting of blocks (e.g., `de' and + * family) within BLINE or ELINE systems. This is annoying. + */ + + if ( ! (MAN_BLINE & fl)) { + m->flags &= ~MAN_ILINE; return(1); + } + + /* + * 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; + return(1); + } /* * If we've opened a new next-line element scope, then return @@ -580,7 +625,7 @@ out: assert(MAN_BLINE & m->flags); m->flags &= ~MAN_BLINE; - if ( ! man_unscope(m, m->last->parent)) + if ( ! man_unscope(m, m->last->parent, WERRMAX)) return(0); return(man_body_alloc(m, ln, 0, m->last->tok)); @@ -636,3 +681,45 @@ man_err(struct man *m, int line, int pos, int iserr, enum merr type) return(man_vwarn(m, line, pos, p)); } + + +/* + * Unlink a node from its context. If "m" is provided, the last parse + * point will also be adjusted accordingly. + */ +static void +man_node_unlink(struct man *m, struct man_node *n) +{ + + /* Adjust siblings. */ + + if (n->prev) + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + + /* Adjust parent. */ + + if (n->parent) { + n->parent->nchild--; + if (n->parent->child == n) + n->parent->child = n->prev ? n->prev : n->next; + } + + /* Adjust parse point, if applicable. */ + + if (m && m->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; + } else { + m->last = n->parent; + m->next = MAN_NEXT_CHILD; + } + } + + if (m && m->first == n) + m->first = NULL; +} diff --git a/usr.bin/mandoc/man.h b/usr.bin/mandoc/man.h index efb8568c42..cbcbaea9d9 100644 --- a/usr.bin/mandoc/man.h +++ b/usr.bin/mandoc/man.h @@ -1,4 +1,4 @@ -/* $Id: man.h,v 1.23 2009/10/30 05:58:37 kristaps Exp $ */ +/* $Id: man.h,v 1.27 2010/03/27 10:13:16 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -19,39 +19,50 @@ #include -#define MAN_br 0 -#define MAN_TH 1 -#define MAN_SH 2 -#define MAN_SS 3 -#define MAN_TP 4 -#define MAN_LP 5 -#define MAN_PP 6 -#define MAN_P 7 -#define MAN_IP 8 -#define MAN_HP 9 -#define MAN_SM 10 -#define MAN_SB 11 -#define MAN_BI 12 -#define MAN_IB 13 -#define MAN_BR 14 -#define MAN_RB 15 -#define MAN_R 16 -#define MAN_B 17 -#define MAN_I 18 -#define MAN_IR 19 -#define MAN_RI 20 -#define MAN_na 21 -#define MAN_i 22 -#define MAN_sp 23 -#define MAN_nf 24 -#define MAN_fi 25 -#define MAN_r 26 -#define MAN_RE 27 -#define MAN_RS 28 -#define MAN_DT 29 -#define MAN_UC 30 -#define MAN_PD 31 -#define MAN_MAX 32 +enum mant { + MAN_br = 0, + MAN_TH, + MAN_SH, + MAN_SS, + MAN_TP, + MAN_LP, + MAN_PP, + MAN_P, + MAN_IP, + MAN_HP, + MAN_SM, + MAN_SB, + MAN_BI, + MAN_IB, + MAN_BR, + MAN_RB, + MAN_R, + MAN_B, + MAN_I, + MAN_IR, + MAN_RI, + MAN_na, + MAN_i, + MAN_sp, + MAN_nf, + MAN_fi, + MAN_r, + MAN_RE, + MAN_RS, + MAN_DT, + MAN_UC, + MAN_PD, + MAN_Sp, + MAN_Vb, + MAN_Ve, + MAN_de, + MAN_dei, + MAN_am, + MAN_ami, + MAN_ig, + MAN_dot, + MAN_MAX +}; enum man_type { MAN_TEXT, @@ -78,7 +89,7 @@ struct man_node { int nchild; int line; int pos; - int tok; + enum mant tok; int flags; #define MAN_VALID (1 << 0) #define MAN_ACTED (1 << 1) diff --git a/usr.bin/mandoc/man_action.c b/usr.bin/mandoc/man_action.c index e0e801a979..de7fa42f8f 100644 --- a/usr.bin/mandoc/man_action.c +++ b/usr.bin/mandoc/man_action.c @@ -1,4 +1,4 @@ -/* $Id: man_action.c,v 1.25 2010/01/01 17:14:27 kristaps Exp $ */ +/* $Id: man_action.c,v 1.30 2010/03/27 10:04:56 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -14,7 +14,6 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include @@ -28,6 +27,7 @@ struct actions { }; static int post_TH(struct man *); +static int post_de(struct man *); static int post_fi(struct man *); static int post_nf(struct man *); @@ -64,6 +64,15 @@ const struct actions man_actions[MAN_MAX] = { { NULL }, /* DT */ { NULL }, /* UC */ { NULL }, /* PD */ + { NULL }, /* Sp */ + { post_nf }, /* Vb */ + { post_fi }, /* Ve */ + { post_de }, /* de */ + { post_de }, /* dei */ + { post_de }, /* am */ + { post_de }, /* ami */ + { post_de }, /* ig */ + { NULL }, /* . */ }; @@ -102,6 +111,20 @@ post_fi(struct man *m) } +static int +post_de(struct man *m) +{ + + /* + * XXX: for the time being, we indiscriminately remove roff + * instructions from the parse stream. + */ + if (MAN_BLOCK == m->last->type) + man_node_delete(m, m->last); + return(1); +} + + static int post_nf(struct man *m) { @@ -175,23 +198,9 @@ post_TH(struct man *m) m->meta.vol = mandoc_strdup(n->string); /* - * The end document shouldn't have the prologue macros as part - * of the syntax tree (they encompass only meta-data). + * Remove the `TH' node after we've processed it for our + * meta-data. */ - - if (m->last->parent->child == m->last) { - m->last->parent->child = NULL; - n = m->last; - m->last = m->last->parent; - m->next = MAN_NEXT_CHILD; - } else { - assert(m->last->prev); - m->last->prev->next = NULL; - n = m->last; - m->last = m->last->prev; - m->next = MAN_NEXT_SIBLING; - } - - man_node_freelist(n); + man_node_delete(m, m->last); return(1); } diff --git a/usr.bin/mandoc/man_hash.c b/usr.bin/mandoc/man_hash.c index b19d63aaed..a68c1a5a75 100644 --- a/usr.bin/mandoc/man_hash.c +++ b/usr.bin/mandoc/man_hash.c @@ -1,4 +1,4 @@ -/* $Id: man_hash.c,v 1.16 2010/01/01 17:14:28 kristaps Exp $ */ +/* $Id: man_hash.c,v 1.18 2010/03/27 10:14:32 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -17,13 +17,33 @@ #include #include +#include #include #include #include #include "libman.h" -static u_char table[26 * 6]; +#define HASH_DEPTH 6 + +#define HASH_ROW(x) do { \ + if ('.' == (x)) \ + (x) = 26; \ + else if (isupper((u_char)(x))) \ + (x) -= 65; \ + else \ + (x) -= 97; \ + (x) *= HASH_DEPTH; \ + } while (/* CONSTCOND */ 0) + +/* + * Lookup table is indexed first by lower-case first letter (plus one + * for the period, which is stored in the last row), then by lower or + * uppercase second letter. Buckets correspond to the index of the + * macro (the integer value of the enum stored as a char to save a bit + * of space). + */ +static u_char table[27 * HASH_DEPTH]; /* * XXX - this hash has global scope, so if intended for use as a library @@ -36,39 +56,45 @@ man_hash_init(void) memset(table, UCHAR_MAX, sizeof(table)); + assert(/* LINTED */ + MAN_MAX < UCHAR_MAX); + for (i = 0; i < MAN_MAX; i++) { x = man_macronames[i][0]; - assert((x >= 65 && x <= 90) || - (x >= 97 && x <= 122)); - x -= (x <= 90) ? 65 : 97; - x *= 6; + assert(isalpha((u_char)x) || '.' == x); - for (j = 0; j < 6; j++) + HASH_ROW(x); + + for (j = 0; j < HASH_DEPTH; j++) if (UCHAR_MAX == table[x + j]) { table[x + j] = (u_char)i; break; } - assert(j < 6); + + assert(j < HASH_DEPTH); } } -int + +enum mant man_hash_find(const char *tmp) { - int x, i, tok; + int x, y, i; + enum mant tok; - if (0 == (x = tmp[0])) + if ('\0' == (x = tmp[0])) return(MAN_MAX); - if ( ! ((x >= 65 && x <= 90) || (x >= 97 && x <= 122))) + if ( ! (isalpha((u_char)x) || '.' == x)) return(MAN_MAX); - x -= (x <= 90) ? 65 : 97; - x *= 6; + HASH_ROW(x); - for (i = 0; i < 6; i++) { - if (UCHAR_MAX == (tok = table[x + i])) + for (i = 0; i < HASH_DEPTH; i++) { + if (UCHAR_MAX == (y = table[x + i])) return(MAN_MAX); + + tok = (enum mant)y; if (0 == strcmp(tmp, man_macronames[tok])) return(tok); } diff --git a/usr.bin/mandoc/man_html.c b/usr.bin/mandoc/man_html.c index 4e34937378..3b1560ddfd 100644 --- a/usr.bin/mandoc/man_html.c +++ b/usr.bin/mandoc/man_html.c @@ -1,4 +1,4 @@ -/* $Id: man_html.c,v 1.26 2010/01/29 14:39:38 kristaps Exp $ */ +/* $Id: man_html.c,v 1.30 2010/03/24 20:10:53 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -99,6 +99,15 @@ static const struct htmlman mans[MAN_MAX] = { { man_ign_pre, NULL }, /* DT */ { man_ign_pre, NULL }, /* UC */ { man_ign_pre, NULL }, /* PD */ + { man_br_pre, NULL }, /* Sp */ + { man_ign_pre, NULL }, /* Vb */ + { NULL, NULL }, /* Ve */ + { man_ign_pre, NULL }, /* de */ + { man_ign_pre, NULL }, /* dei */ + { man_ign_pre, NULL }, /* am */ + { man_ign_pre, NULL }, /* ami */ + { man_ign_pre, NULL }, /* ig */ + { NULL, NULL }, /* . */ }; @@ -177,6 +186,12 @@ print_man_node(MAN_ARGS) bufinit(h); + /* + * FIXME: embedded elements within next-line scopes (e.g., `br' + * within an empty `B') will cause formatting to be forgotten + * due to scope closing out. + */ + switch (n->type) { case (MAN_ROOT): child = man_root_pre(m, n, h); @@ -331,10 +346,18 @@ man_br_pre(MAN_ARGS) SCALE_VS_INIT(&su, 1); - if (MAN_sp == n->tok && n->child) - a2roffsu(n->child->string, &su, SCALE_VS); - else if (MAN_br == n->tok) + switch (n->tok) { + case (MAN_Sp): + SCALE_VS_INIT(&su, 0.5); + break; + case (MAN_sp): + if (n->child) + a2roffsu(n->child->string, &su, SCALE_VS); + break; + default: su.scale = 0; + break; + } bufcat_su(h, "height", &su); PAIR_STYLE_INIT(&tag, h); @@ -563,6 +586,8 @@ man_IP_pre(MAN_ARGS) SCALE_HS_INIT(&su, INDENT); width = 0; + /* Width is the last token. */ + if (MAN_IP == n->tok && NULL != nn) if (NULL != (nn = nn->next)) { for ( ; nn->next; nn = nn->next) @@ -570,8 +595,15 @@ man_IP_pre(MAN_ARGS) width = a2width(nn, &su); } - if (MAN_TP == n->tok && NULL != nn) - width = a2width(nn, &su); + /* Width is the first token. */ + + if (MAN_TP == n->tok && NULL != nn) { + /* Skip past non-text children. */ + while (nn && MAN_TEXT != nn->type) + nn = nn->next; + if (nn) + width = a2width(nn, &su); + } if (MAN_BLOCK == n->type) { bufcat_su(h, "margin-left", &su); @@ -596,11 +628,20 @@ man_IP_pre(MAN_ARGS) PAIR_STYLE_INIT(&tag, h); print_otag(h, TAG_DIV, 1, &tag); - /* With a length string, manually omit the last child. */ + /* + * Without a length string, we can print all of our children. + */ if ( ! width) return(1); + /* + * When a length has been specified, we need to carefully print + * our child context: IP gets all children printed but the last + * (the width), while TP gets all children printed but the first + * (the width). + */ + if (MAN_IP == n->tok) for (nn = n->child; nn->next; nn = nn->next) print_man_node(m, nn, h); diff --git a/usr.bin/mandoc/man_macro.c b/usr.bin/mandoc/man_macro.c index 408fc8d431..f8f892bd41 100644 --- a/usr.bin/mandoc/man_macro.c +++ b/usr.bin/mandoc/man_macro.c @@ -1,4 +1,4 @@ -/* $Id: man_macro.c,v 1.30 2010/01/01 17:14:28 kristaps Exp $ */ +/* $Id: man_macro.c,v 1.40 2010/03/27 10:14:32 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -21,22 +21,29 @@ #include "libman.h" -#define REW_REWIND (0) /* See rew_scope(). */ -#define REW_NOHALT (1) /* See rew_scope(). */ -#define REW_HALT (2) /* See rew_scope(). */ +enum rew { + REW_REWIND, + REW_NOHALT, + REW_HALT +}; -static int in_line_eoln(MACRO_PROT_ARGS); -static int blk_imp(MACRO_PROT_ARGS); static int blk_close(MACRO_PROT_ARGS); +static int blk_dotted(MACRO_PROT_ARGS); +static int blk_exp(MACRO_PROT_ARGS); +static int blk_imp(MACRO_PROT_ARGS); +static int in_line_eoln(MACRO_PROT_ARGS); -static int rew_scope(enum man_type, struct man *, int); -static int rew_dohalt(int, enum man_type, +static int rew_scope(enum man_type, + struct man *, enum mant); +static enum rew rew_dohalt(enum mant, enum man_type, const struct man_node *); -static int rew_block(int, enum man_type, +static enum rew rew_block(enum mant, enum man_type, const struct man_node *); +static int rew_warn(struct man *, + struct man_node *, enum merr); const struct man_macro __man_macros[MAN_MAX] = { - { in_line_eoln, 0 }, /* br */ + { in_line_eoln, MAN_NSCOPED }, /* br */ { in_line_eoln, 0 }, /* TH */ { blk_imp, MAN_SCOPED }, /* SH */ { blk_imp, MAN_SCOPED }, /* SS */ @@ -57,31 +64,64 @@ const struct man_macro __man_macros[MAN_MAX] = { { in_line_eoln, MAN_SCOPED }, /* I */ { in_line_eoln, 0 }, /* IR */ { in_line_eoln, 0 }, /* RI */ - { in_line_eoln, 0 }, /* na */ + { in_line_eoln, MAN_NSCOPED }, /* na */ { in_line_eoln, 0 }, /* i */ - { in_line_eoln, 0 }, /* sp */ + { in_line_eoln, MAN_NSCOPED }, /* sp */ { in_line_eoln, 0 }, /* nf */ { in_line_eoln, 0 }, /* fi */ { in_line_eoln, 0 }, /* r */ { blk_close, 0 }, /* RE */ - { blk_imp, MAN_EXPLICIT }, /* RS */ + { blk_exp, MAN_EXPLICIT }, /* RS */ { in_line_eoln, 0 }, /* DT */ { in_line_eoln, 0 }, /* UC */ { in_line_eoln, 0 }, /* PD */ + { in_line_eoln, MAN_NSCOPED }, /* Sp */ + { in_line_eoln, 0 }, /* Vb */ + { in_line_eoln, 0 }, /* Ve */ + { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* de */ + { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* dei */ + { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* am */ + { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* ami */ + { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* ig */ + { blk_dotted, 0 }, /* . */ }; const struct man_macro * const man_macros = __man_macros; +/* + * Warn when "n" is an explicit non-roff macro. + */ +static int +rew_warn(struct man *m, struct man_node *n, enum merr er) +{ + + if (er == WERRMAX || MAN_BLOCK != n->type) + return(1); + if (MAN_VALID & n->flags) + return(1); + if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags)) + return(1); + if (MAN_NOCLOSE & man_macros[n->tok].flags) + return(1); + return(man_nwarn(m, n, er)); +} + + +/* + * Rewind scope. If a code "er" != WERRMAX has been provided, it will + * be used if an explicit block scope is being closed out. + */ int -man_unscope(struct man *m, const struct man_node *n) +man_unscope(struct man *m, const struct man_node *n, enum merr er) { assert(n); - m->next = MAN_NEXT_SIBLING; /* LINTED */ while (m->last != n) { + if ( ! rew_warn(m, m->last, er)) + return(0); if ( ! man_valid_post(m)) return(0); if ( ! man_action_post(m)) @@ -90,14 +130,22 @@ man_unscope(struct man *m, const struct man_node *n) assert(m->last); } + if ( ! rew_warn(m, m->last, er)) + return(0); if ( ! man_valid_post(m)) return(0); - return(man_action_post(m)); + if ( ! man_action_post(m)) + return(0); + + m->next = MAN_ROOT == m->last->type ? + MAN_NEXT_CHILD : MAN_NEXT_SIBLING; + + return(1); } -static int -rew_block(int ntok, enum man_type type, const struct man_node *n) +static enum rew +rew_block(enum mant ntok, enum man_type type, const struct man_node *n) { if (MAN_BLOCK == type && ntok == n->parent->tok && @@ -112,23 +160,52 @@ rew_block(int ntok, enum man_type type, const struct man_node *n) * section (all less sections), and scoped to subsections (all less * sections and subsections). */ -static int -rew_dohalt(int tok, enum man_type type, const struct man_node *n) +static enum rew +rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) { - int c; + enum rew c; + /* We cannot progress beyond the root ever. */ if (MAN_ROOT == n->type) return(REW_HALT); + assert(n->parent); + + /* Normal nodes shouldn't go to the level of the root. */ if (MAN_ROOT == n->parent->type) return(REW_REWIND); + + /* Already-validated nodes should be closed out. */ if (MAN_VALID & n->flags) return(REW_NOHALT); - /* Rewind to ourselves, first. */ + /* First: rewind to ourselves. */ if (type == n->type && tok == n->tok) return(REW_REWIND); + /* + * If we're a roff macro, then we can close out anything that + * stands between us and our parent context. + */ + if (MAN_NOCLOSE & man_macros[tok].flags) + return(REW_NOHALT); + + /* + * Don't clobber roff macros: this is a bit complicated. If the + * current macro is a roff macro, halt immediately and don't + * rewind. If it's not, and the parent is, then close out the + * current scope and halt at the parent. + */ + if (MAN_NOCLOSE & man_macros[n->tok].flags) + return(REW_HALT); + if (MAN_NOCLOSE & man_macros[n->parent->tok].flags) + return(REW_REWIND); + + /* + * Next follow the implicit scope-smashings as defined by man.7: + * section, sub-section, etc. + */ + switch (tok) { case (MAN_SH): break; @@ -168,10 +245,10 @@ rew_dohalt(int 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, int tok) +rew_scope(enum man_type type, struct man *m, enum mant tok) { struct man_node *n; - int c; + enum rew c; /* LINTED */ for (n = m->last; n; n = n->parent) { @@ -187,18 +264,78 @@ rew_scope(enum man_type type, struct man *m, int tok) break; } - /* Rewind until the current point. */ - + /* + * Rewind until the current point. Warn if we're a roff + * instruction that's mowing over explicit scopes. + */ assert(n); - return(man_unscope(m, n)); + if (MAN_NOCLOSE & man_macros[tok].flags) + return(man_unscope(m, n, WROFFSCOPE)); + + return(man_unscope(m, n, WERRMAX)); } +/* + * Closure for dotted macros (de, dei, am, ami, ign). This must handle + * any of these as the parent node, so it needs special handling. + * Beyond this, it's the same as blk_close(). + */ +/* ARGSUSED */ +int +blk_dotted(MACRO_PROT_ARGS) +{ + enum mant ntok; + struct man_node *nn; + + /* Check for any of the following parents... */ + + for (nn = m->last->parent; nn; nn = nn->parent) + if (nn->tok == MAN_de || nn->tok == MAN_dei || + nn->tok == MAN_am || + nn->tok == MAN_ami || + nn->tok == MAN_ig) { + ntok = nn->tok; + break; + } + + if (NULL == nn) { + if ( ! man_pwarn(m, line, ppos, WNOSCOPE)) + return(0); + return(1); + } + + if ( ! rew_scope(MAN_BODY, m, ntok)) + return(0); + if ( ! rew_scope(MAN_BLOCK, m, ntok)) + return(0); + + /* + * XXX: manually adjust our next-line status. roff macros are, + * for the moment, ignored, so we don't want to close out bodies + * and so on. + */ + + switch (m->last->type) { + case (MAN_BODY): + m->next = MAN_NEXT_CHILD; + break; + default: + break; + } + + return(1); +} + + +/* + * Close out a generic explicit macro. + */ /* ARGSUSED */ int blk_close(MACRO_PROT_ARGS) { - int ntok; + enum mant ntok; const struct man_node *nn; switch (tok) { @@ -222,11 +359,58 @@ blk_close(MACRO_PROT_ARGS) return(0); if ( ! rew_scope(MAN_BLOCK, m, ntok)) return(0); - m->next = MAN_NEXT_SIBLING; + return(1); } +int +blk_exp(MACRO_PROT_ARGS) +{ + int w, la; + char *p; + + /* + * Close out prior scopes. "Regular" explicit macros cannot be + * nested, but we allow roff macros to be placed just about + * anywhere. + */ + + if ( ! (MAN_NOCLOSE & man_macros[tok].flags)) { + if ( ! rew_scope(MAN_BODY, m, tok)) + return(0); + if ( ! rew_scope(MAN_BLOCK, m, tok)) + return(0); + } + + if ( ! man_block_alloc(m, line, ppos, tok)) + return(0); + if ( ! man_head_alloc(m, line, ppos, tok)) + return(0); + + for (;;) { + la = *pos; + w = man_args(m, line, pos, buf, &p); + + if (-1 == w) + return(0); + if (0 == w) + break; + + if ( ! man_word_alloc(m, line, la, p)) + return(0); + } + + assert(m); + assert(tok != MAN_MAX); + + if ( ! rew_scope(MAN_HEAD, m, tok)) + return(0); + return(man_body_alloc(m, line, ppos, tok)); +} + + + /* * Parse an implicit-block macro. These contain a MAN_HEAD and a * MAN_BODY contained within a MAN_BLOCK. Rules for closing out other @@ -286,7 +470,6 @@ blk_imp(MACRO_PROT_ARGS) if ( ! rew_scope(MAN_HEAD, m, tok)) return(0); - return(man_body_alloc(m, line, ppos, tok)); } @@ -311,19 +494,33 @@ in_line_eoln(MACRO_PROT_ARGS) return(0); if (0 == w) break; - if ( ! man_word_alloc(m, line, la, p)) return(0); } + /* + * 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) { + assert( ! (MAN_NSCOPED & man_macros[tok].flags)); m->flags |= MAN_ELINE; return(1); } + /* Set ignorable context, if applicable. */ + + if (MAN_NSCOPED & man_macros[tok].flags) { + assert( ! (MAN_SCOPED & man_macros[tok].flags)); + m->flags |= MAN_ILINE; + } + /* - * Note that when TH is pruned, we'll be back at the root, so - * make sure that we don't clobber as its sibling. + * Rewind our element scope. Note that when TH is pruned, we'll + * be back at the root, so make sure that we don't clobber as + * its sibling. */ for ( ; m->last; m->last = m->last->parent) { @@ -347,8 +544,9 @@ in_line_eoln(MACRO_PROT_ARGS) return(0); if (m->last->type != MAN_ROOT && ! man_action_post(m)) return(0); - if (m->last->type != MAN_ROOT) - m->next = MAN_NEXT_SIBLING; + + m->next = MAN_ROOT == m->last->type ? + MAN_NEXT_CHILD : MAN_NEXT_SIBLING; return(1); } @@ -357,19 +555,6 @@ in_line_eoln(MACRO_PROT_ARGS) int man_macroend(struct man *m) { - struct man_node *n; - - n = MAN_VALID & m->last->flags ? - m->last->parent : m->last; - - for ( ; n; n = n->parent) { - if (MAN_BLOCK != n->type) - continue; - if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags)) - continue; - if ( ! man_nwarn(m, n, WEXITSCOPE)) - return(0); - } - return(man_unscope(m, m->first)); + return(man_unscope(m, m->first, WEXITSCOPE)); } diff --git a/usr.bin/mandoc/man_term.c b/usr.bin/mandoc/man_term.c index 4da50c5a59..b1e6d9fbfc 100644 --- a/usr.bin/mandoc/man_term.c +++ b/usr.bin/mandoc/man_term.c @@ -1,4 +1,4 @@ -/* $Id: man_term.c,v 1.55 2010/01/01 17:14:28 kristaps Exp $ */ +/* $Id: man_term.c,v 1.59 2010/03/24 20:10:53 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -61,6 +61,8 @@ struct mtermp { struct termact { int (*pre)(DECL_ARGS); void (*post)(DECL_ARGS); + int flags; +#define MAN_NOTEXT (1 << 0) /* Never has text children. */ }; static int a2width(const struct man_node *); @@ -101,38 +103,47 @@ static void post_SS(DECL_ARGS); static void post_TP(DECL_ARGS); static const struct termact termacts[MAN_MAX] = { - { pre_br, NULL }, /* br */ - { NULL, NULL }, /* TH */ - { pre_SH, post_SH }, /* SH */ - { pre_SS, post_SS }, /* SS */ - { pre_TP, post_TP }, /* TP */ - { pre_PP, NULL }, /* LP */ - { pre_PP, NULL }, /* PP */ - { pre_PP, NULL }, /* P */ - { pre_IP, post_IP }, /* IP */ - { pre_HP, post_HP }, /* HP */ - { NULL, NULL }, /* SM */ - { pre_B, NULL }, /* SB */ - { pre_BI, NULL }, /* BI */ - { pre_BI, NULL }, /* IB */ - { pre_RB, NULL }, /* BR */ - { pre_RB, NULL }, /* RB */ - { NULL, NULL }, /* R */ - { pre_B, NULL }, /* B */ - { pre_I, NULL }, /* I */ - { pre_RI, NULL }, /* IR */ - { pre_RI, NULL }, /* RI */ - { NULL, NULL }, /* na */ - { pre_I, NULL }, /* i */ - { pre_sp, NULL }, /* sp */ - { pre_nf, NULL }, /* nf */ - { pre_fi, NULL }, /* fi */ - { NULL, NULL }, /* r */ - { NULL, NULL }, /* RE */ - { pre_RS, post_RS }, /* RS */ - { pre_ign, NULL }, /* DT */ - { pre_ign, NULL }, /* UC */ - { pre_ign, NULL }, /* PD */ + { pre_br, NULL, MAN_NOTEXT }, /* br */ + { NULL, NULL, 0 }, /* TH */ + { pre_SH, post_SH, 0 }, /* SH */ + { pre_SS, post_SS, 0 }, /* SS */ + { pre_TP, post_TP, 0 }, /* TP */ + { pre_PP, NULL, 0 }, /* LP */ + { pre_PP, NULL, 0 }, /* PP */ + { pre_PP, NULL, 0 }, /* P */ + { pre_IP, post_IP, 0 }, /* IP */ + { pre_HP, post_HP, 0 }, /* HP */ + { NULL, NULL, 0 }, /* SM */ + { pre_B, NULL, 0 }, /* SB */ + { pre_BI, NULL, 0 }, /* BI */ + { pre_BI, NULL, 0 }, /* IB */ + { pre_RB, NULL, 0 }, /* BR */ + { pre_RB, NULL, 0 }, /* RB */ + { NULL, NULL, 0 }, /* R */ + { pre_B, NULL, 0 }, /* B */ + { pre_I, NULL, 0 }, /* I */ + { pre_RI, NULL, 0 }, /* IR */ + { pre_RI, NULL, 0 }, /* RI */ + { NULL, NULL, MAN_NOTEXT }, /* na */ + { pre_I, NULL, 0 }, /* i */ + { pre_sp, NULL, MAN_NOTEXT }, /* sp */ + { pre_nf, NULL, 0 }, /* nf */ + { pre_fi, NULL, 0 }, /* fi */ + { NULL, NULL, 0 }, /* r */ + { NULL, NULL, 0 }, /* RE */ + { pre_RS, post_RS, 0 }, /* RS */ + { pre_ign, NULL, 0 }, /* DT */ + { pre_ign, NULL, 0 }, /* UC */ + { pre_ign, NULL, 0 }, /* PD */ + { pre_sp, NULL, MAN_NOTEXT }, /* Sp */ + { pre_nf, NULL, 0 }, /* Vb */ + { pre_fi, NULL, 0 }, /* Ve */ + { pre_ign, NULL, MAN_NOTEXT }, /* de */ + { pre_ign, NULL, MAN_NOTEXT }, /* dei */ + { pre_ign, NULL, MAN_NOTEXT }, /* am */ + { pre_ign, NULL, MAN_NOTEXT }, /* ami */ + { pre_ign, NULL, MAN_NOTEXT }, /* ig */ + { NULL, NULL, 0 }, /* . */ }; @@ -147,6 +158,9 @@ terminal_man(void *arg, const struct man *man) p = (struct termp *)arg; + p->overstep = 0; + p->maxrmargin = 65; + if (NULL == p->symtab) switch (p->enc) { case (TERMENC_ASCII): @@ -242,6 +256,7 @@ static int pre_fi(DECL_ARGS) { + p->rmargin = p->maxrmargin = 65; mt->fl &= ~MANT_LITERAL; return(1); } @@ -252,9 +267,11 @@ static int pre_nf(DECL_ARGS) { + p->rmargin = p->maxrmargin = 78; term_newln(p); mt->fl |= MANT_LITERAL; - return(1); + + return(MAN_Vb != n->tok); } @@ -570,10 +587,13 @@ pre_TP(DECL_ARGS) /* Calculate offset. */ - if (NULL != (nn = n->parent->head->child)) - if (NULL != nn->next) + if (NULL != (nn = n->parent->head->child)) { + while (nn && MAN_TEXT != nn->type) + nn = nn->next; + if (nn && nn->next) if ((ival = a2width(nn)) >= 0) len = (size_t)ival; + } switch (n->type) { case (MAN_HEAD): @@ -767,6 +787,8 @@ post_RS(DECL_ARGS) case (MAN_BLOCK): mt->offset = mt->lmargin = INDENT; break; + case (MAN_HEAD): + break; default: term_newln(p); p->offset = INDENT; @@ -799,7 +821,8 @@ print_man_node(DECL_ARGS) } break; default: - term_fontrepl(p, TERMFONT_NONE); + if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) + term_fontrepl(p, TERMFONT_NONE); if (termacts[n->tok].pre) c = (*termacts[n->tok].pre)(p, mt, n, m); break; @@ -811,7 +834,8 @@ print_man_node(DECL_ARGS) if (MAN_TEXT != n->type) { if (termacts[n->tok].post) (*termacts[n->tok].post)(p, mt, n, m); - term_fontrepl(p, TERMFONT_NONE); + if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) + term_fontrepl(p, TERMFONT_NONE); } } @@ -862,18 +886,24 @@ static void print_man_head(struct termp *p, const struct man_meta *m) { char buf[BUFSIZ], title[BUFSIZ]; + size_t buflen, titlen; p->rmargin = p->maxrmargin; + p->offset = 0; buf[0] = title[0] = '\0'; if (m->vol) strlcpy(buf, m->vol, BUFSIZ); + buflen = strlen(buf); snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec); + titlen = strlen(title); p->offset = 0; - p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2; + p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ? + (p->maxrmargin - strlen(buf) + 1) / 2 : + p->maxrmargin - buflen; p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; term_word(p, title); @@ -881,18 +911,20 @@ print_man_head(struct termp *p, const struct man_meta *m) p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; p->offset = p->rmargin; - p->rmargin = p->maxrmargin - strlen(title); + p->rmargin = p->offset + buflen + titlen < p->maxrmargin ? + p->maxrmargin - titlen : p->maxrmargin; term_word(p, buf); term_flushln(p); - p->offset = p->rmargin; - p->rmargin = p->maxrmargin; p->flags &= ~TERMP_NOBREAK; - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - - term_word(p, title); - term_flushln(p); + if (p->rmargin + titlen <= p->maxrmargin) { + p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; + p->offset = p->rmargin; + p->rmargin = p->maxrmargin; + term_word(p, title); + term_flushln(p); + } p->rmargin = p->maxrmargin; p->offset = 0; diff --git a/usr.bin/mandoc/man_validate.c b/usr.bin/mandoc/man_validate.c index 00112d3d58..416a73e088 100644 --- a/usr.bin/mandoc/man_validate.c +++ b/usr.bin/mandoc/man_validate.c @@ -1,4 +1,4 @@ -/* $Id: man_validate.c,v 1.28 2010/01/01 17:14:28 kristaps Exp $ */ +/* $Id: man_validate.c,v 1.32 2010/03/27 10:04:56 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -42,21 +42,24 @@ static int check_ge2(CHKARGS); static int check_le5(CHKARGS); static int check_par(CHKARGS); static int check_part(CHKARGS); +static int check_roff(CHKARGS); static int check_root(CHKARGS); static int check_sec(CHKARGS); static int check_text(CHKARGS); +static int check_title(CHKARGS); static v_check posts_eq0[] = { check_eq0, NULL }; -static v_check posts_ge2_le5[] = { check_ge2, check_le5, NULL }; +static v_check posts_th[] = { check_ge2, check_le5, check_title, NULL }; static v_check posts_par[] = { check_par, NULL }; static v_check posts_part[] = { check_part, NULL }; static v_check posts_sec[] = { check_sec, NULL }; -static v_check posts_sp[] = { check_le1, NULL }; +static v_check posts_le1[] = { check_le1, NULL }; static v_check pres_bline[] = { check_bline, NULL }; +static v_check pres_roff[] = { check_bline, check_roff, NULL }; static const struct man_valid man_valids[MAN_MAX] = { - { pres_bline, posts_eq0 }, /* br */ - { pres_bline, posts_ge2_le5 }, /* TH */ /* FIXME: make sure capitalised. */ + { NULL, posts_eq0 }, /* br */ + { pres_bline, posts_th }, /* TH */ { pres_bline, posts_sec }, /* SH */ { pres_bline, posts_sec }, /* SS */ { pres_bline, posts_par }, /* TP */ @@ -76,9 +79,9 @@ static const struct man_valid man_valids[MAN_MAX] = { { NULL, NULL }, /* I */ { NULL, NULL }, /* IR */ { NULL, NULL }, /* RI */ - { pres_bline, posts_eq0 }, /* na */ + { NULL, posts_eq0 }, /* na */ { NULL, NULL }, /* i */ - { pres_bline, posts_sp }, /* sp */ + { NULL, posts_le1 }, /* sp */ { pres_bline, posts_eq0 }, /* nf */ { pres_bline, posts_eq0 }, /* fi */ { NULL, NULL }, /* r */ @@ -87,6 +90,15 @@ static const struct man_valid man_valids[MAN_MAX] = { { NULL, NULL }, /* DT */ { NULL, NULL }, /* UC */ { NULL, NULL }, /* PD */ + { NULL, posts_eq0 }, /* Sp */ + { pres_bline, posts_le1 }, /* Vb */ + { pres_bline, posts_eq0 }, /* Ve */ + { pres_roff, NULL }, /* de */ + { pres_roff, NULL }, /* dei */ + { pres_roff, NULL }, /* am */ + { pres_roff, NULL }, /* ami */ + { pres_roff, NULL }, /* ig */ + { NULL, NULL }, /* . */ }; @@ -158,6 +170,24 @@ check_root(CHKARGS) } +static int +check_title(CHKARGS) +{ + const char *p; + + assert(n->child); + if ('\0' == *n->child->string) + return(man_nerr(m, n, WNOTITLE)); + + for (p = n->child->string; '\0' != *p; p++) + if (isalpha((u_char)*p) && ! isupper((u_char)*p)) + if ( ! man_nwarn(m, n, WTITLECASE)) + return(0); + + return(1); +} + + static int check_text(CHKARGS) { @@ -277,5 +307,24 @@ check_bline(CHKARGS) assert( ! (MAN_ELINE & m->flags)); if (MAN_BLINE & m->flags) return(man_nerr(m, n, WLNSCOPE)); + + return(1); +} + + +static int +check_roff(CHKARGS) +{ + + if (MAN_BLOCK != n->type) + return(1); + + for (n = n->parent; n; n = n->parent) + if (MAN_de == n->tok || MAN_dei == n->tok || + MAN_am == n->tok || + MAN_ami == n->tok || + MAN_ig == n->tok) + return(man_nerr(m, n, WROFFNEST)); + return(1); } diff --git a/usr.bin/mandoc/mandoc.1 b/usr.bin/mandoc/mandoc.1 index 3a78d8e709..eff713294a 100644 --- a/usr.bin/mandoc/mandoc.1 +++ b/usr.bin/mandoc/mandoc.1 @@ -1,4 +1,4 @@ -.\" $Id: mandoc.1,v 1.50 2010/01/29 14:39:38 kristaps Exp $ +.\" $Id: mandoc.1,v 1.54 2010/03/27 10:10:10 kristaps Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons .\" @@ -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 February 20, 2010 +.Dd March 27, 2010 .Dt MANDOC 1 .Os . @@ -176,6 +176,10 @@ Produce an indented parse tree. . .It Fl T Ns Ar lint Parse only: produce no output. +Implies +.Fl W Ns Ar all +and +.Fl f Ns Ar strict . .El . .Pp @@ -225,6 +229,8 @@ over a large set of manuals passed on the command line. .Ss Output Options For the time being, only .Fl T Ns Ar html +and +.Fl T Ns Ar xhtml accepts output options: .Bl -tag -width Ds .It Fl O Ns Ar style=style.css @@ -502,8 +508,9 @@ and .Fl T Ns Ar xhtml CSS2 styling used for .Fl m Ns Ar doc -input lists does not render properly in brain-dead browsers, such as -Internet Explorer 6 and earlier. +input lists does not render properly in older browsers, such as Internet +Explorer 6 and earlier. +. .Pp In .Fl T Ns Ar html @@ -514,6 +521,7 @@ the maximum size of an element attribute is determined by which is usually 1024 bytes. Be aware of this when setting long link formats, e.g., .Fl O Ns Ar style=really/long/link . +. .Pp The .Fl T Ns Ar html @@ -525,3 +533,29 @@ font size escape documented in .Xr mdoc 7 and .Xr man 7 . +. +.Pp +Nesting elements within next-line element scopes of +.Fl m Ns Ar an , +such as +.Sq br +within an empty +.Sq B , +will confuse +.Fl T Ns Ar html +and +.Fl T Ns Ar xhtml +and cause them to forget the formatting of the prior next-line scope. +. +.Pp +The +.Sq i +macro in +.Fl m Ns Ar an +should italicise all subsequent text if a line argument is not provided. +This behaviour is not implemented. +. +The +.Sq \(aq +control character is an alias for the standard macro control character +and does not emit a line-break as stipulated in GNU troff. diff --git a/usr.bin/mandoc/mdoc.7 b/usr.bin/mandoc/mdoc.7 index e5374ffd25..fb0188514b 100644 --- a/usr.bin/mandoc/mdoc.7 +++ b/usr.bin/mandoc/mdoc.7 @@ -1,4 +1,4 @@ -.\" $Id: mdoc.7,v 1.84 2010/02/17 19:22:50 kristaps Exp $ +.\" $Id: mdoc.7,v 1.86 2010/03/26 07:07:58 kristaps Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons .\" @@ -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 February 20, 2010 +.Dd March 27, 2010 .Dt MDOC 7 .Os . @@ -1553,6 +1553,7 @@ subsequent that. It, too, is optional. It must be one of .Ar hppa64 , .Ar i386 , .Ar landisk , +.Ar loongson , .Ar luna88k , .Ar mac68k , .Ar macppc , diff --git a/usr.bin/mandoc/mdoc_term.c b/usr.bin/mandoc/mdoc_term.c index 2023d5bc83..4835fcde3b 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.110 2010/01/30 08:42:21 kristaps Exp $ */ +/* $Id: mdoc_term.c,v 1.111 2010/03/23 12:42:22 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -266,6 +266,9 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc) p = (struct termp *)arg; + p->overstep = 0; + p->maxrmargin = 78; + if (NULL == p->symtab) switch (p->enc) { case (TERMENC_ASCII): diff --git a/usr.bin/mandoc/term.c b/usr.bin/mandoc/term.c index 7a7091633c..4779745840 100644 --- a/usr.bin/mandoc/term.c +++ b/usr.bin/mandoc/term.c @@ -1,4 +1,4 @@ -/* $Id: term.c,v 1.128 2010/01/01 17:14:30 kristaps Exp $ */ +/* $Id: term.c,v 1.129 2010/03/23 12:42:22 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -79,7 +79,6 @@ term_alloc(enum termenc enc) perror(NULL); exit(EXIT_FAILURE); } - p->maxrmargin = 78; p->enc = enc; return(p); } @@ -132,7 +131,6 @@ term_flushln(struct termp *p) size_t bp; /* visual right border position */ int j; /* temporary loop index */ size_t maxvis, mmax; - static int overstep = 0; /* * First, establish the maximum columns of "visible" content. @@ -143,12 +141,12 @@ term_flushln(struct termp *p) assert(p->offset < p->rmargin); - maxvis = (int)(p->rmargin - p->offset) - overstep < 0 ? + maxvis = (int)(p->rmargin - p->offset) - p->overstep < 0 ? /* LINTED */ - 0 : p->rmargin - p->offset - overstep; - mmax = (int)(p->maxrmargin - p->offset) - overstep < 0 ? + 0 : p->rmargin - p->offset - p->overstep; + mmax = (int)(p->maxrmargin - p->offset) - p->overstep < 0 ? /* LINTED */ - 0 : p->maxrmargin - p->offset - overstep; + 0 : p->maxrmargin - p->offset - p->overstep; bp = TERMP_NOBREAK & p->flags ? mmax : maxvis; @@ -211,10 +209,10 @@ term_flushln(struct termp *p) putchar(' '); vis = 0; } - /* Remove the overstep width. */ + /* Remove the p->overstep width. */ bp += (int)/* LINTED */ - overstep; - overstep = 0; + p->overstep; + p->overstep = 0; } else { for (j = 0; j < (int)vbl; j++) putchar(' '); @@ -238,7 +236,7 @@ term_flushln(struct termp *p) } p->col = 0; - overstep = 0; + p->overstep = 0; if ( ! (TERMP_NOBREAK & p->flags)) { putchar('\n'); @@ -247,7 +245,7 @@ term_flushln(struct termp *p) if (TERMP_HANG & p->flags) { /* We need one blank after the tag. */ - overstep = /* LINTED */ + p->overstep = /* LINTED */ vis - maxvis + 1; /* @@ -260,12 +258,12 @@ term_flushln(struct termp *p) * move it one step LEFT and flag the rest of the line * to be longer. */ - if (overstep >= -1) { - assert((int)maxvis + overstep >= 0); + if (p->overstep >= -1) { + assert((int)maxvis + p->overstep >= 0); /* LINTED */ - maxvis += overstep; + maxvis += p->overstep; } else - overstep = 0; + p->overstep = 0; } else if (TERMP_DANGLE & p->flags) return; diff --git a/usr.bin/mandoc/term.h b/usr.bin/mandoc/term.h index 134c83de64..4a1ed9022e 100644 --- a/usr.bin/mandoc/term.h +++ b/usr.bin/mandoc/term.h @@ -1,4 +1,4 @@ -/* $Id: term.h,v 1.51 2009/11/12 05:50:13 kristaps Exp $ */ +/* $Id: term.h,v 1.52 2010/03/23 12:42:22 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -35,6 +35,7 @@ struct termp { size_t maxcols; /* Max size of buf. */ size_t offset; /* Margin offest. */ size_t col; /* Bytes in buf. */ + int overstep; /* See termp_flushln(). */ int flags; #define TERMP_NOSPACE (1 << 2) /* No space before words. */ #define TERMP_NOLPAD (1 << 3) /* See term_flushln(). */