1*544c191cSchristos.\" Id: mandoc.3,v 1.44 2018/12/30 00:49:55 schwarze Exp 248741257Sjoerg.\" 348741257Sjoerg.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 49508192eSchristos.\" Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> 548741257Sjoerg.\" 648741257Sjoerg.\" Permission to use, copy, modify, and distribute this software for any 748741257Sjoerg.\" purpose with or without fee is hereby granted, provided that the above 848741257Sjoerg.\" copyright notice and this permission notice appear in all copies. 948741257Sjoerg.\" 1048741257Sjoerg.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1148741257Sjoerg.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1248741257Sjoerg.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1348741257Sjoerg.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1448741257Sjoerg.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1548741257Sjoerg.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1648741257Sjoerg.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1748741257Sjoerg.\" 18*544c191cSchristos.Dd December 30, 2018 1948741257Sjoerg.Dt MANDOC 3 2048741257Sjoerg.Os 2148741257Sjoerg.Sh NAME 2248741257Sjoerg.Nm mandoc , 239ff1f2acSchristos.Nm deroff , 2448741257Sjoerg.Nm mparse_alloc , 25*544c191cSchristos.Nm mparse_copy , 2648741257Sjoerg.Nm mparse_free , 27fec65c98Schristos.Nm mparse_open , 2848741257Sjoerg.Nm mparse_readfd , 2948741257Sjoerg.Nm mparse_reset , 30*544c191cSchristos.Nm mparse_result 3148741257Sjoerg.Nd mandoc macro compiler library 3248741257Sjoerg.Sh SYNOPSIS 33fec65c98Schristos.In sys/types.h 34*544c191cSchristos.In stdio.h 3548741257Sjoerg.In mandoc.h 36fec65c98Schristos.Pp 37fec65c98Schristos.Fd "#define ASCII_NBRSP" 38fec65c98Schristos.Fd "#define ASCII_HYPH" 39fec65c98Schristos.Fd "#define ASCII_BREAK" 40fec65c98Schristos.Ft struct mparse * 4148741257Sjoerg.Fo mparse_alloc 42fec65c98Schristos.Fa "int options" 43c9bcef03Schristos.Fa "enum mandoc_os oe_e" 44c9bcef03Schristos.Fa "char *os_s" 45fec65c98Schristos.Fc 46fec65c98Schristos.Ft void 4748741257Sjoerg.Fo mparse_free 4848741257Sjoerg.Fa "struct mparse *parse" 4948741257Sjoerg.Fc 50c5f73b34Sjoerg.Ft void 51*544c191cSchristos.Fo mparse_copy 52*544c191cSchristos.Fa "const struct mparse *parse" 53c5f73b34Sjoerg.Fc 549ff1f2acSchristos.Ft int 55fec65c98Schristos.Fo mparse_open 56fec65c98Schristos.Fa "struct mparse *parse" 57fec65c98Schristos.Fa "const char *fname" 58fec65c98Schristos.Fc 59*544c191cSchristos.Ft void 6048741257Sjoerg.Fo mparse_readfd 6148741257Sjoerg.Fa "struct mparse *parse" 6248741257Sjoerg.Fa "int fd" 6348741257Sjoerg.Fa "const char *fname" 6448741257Sjoerg.Fc 6548741257Sjoerg.Ft void 6648741257Sjoerg.Fo mparse_reset 6748741257Sjoerg.Fa "struct mparse *parse" 6848741257Sjoerg.Fc 69*544c191cSchristos.Ft struct roff_meta * 7048741257Sjoerg.Fo mparse_result 7148741257Sjoerg.Fa "struct mparse *parse" 729508192eSchristos.Fc 739ff1f2acSchristos.In roff.h 749ff1f2acSchristos.Ft void 759ff1f2acSchristos.Fo deroff 769ff1f2acSchristos.Fa "char **dest" 779ff1f2acSchristos.Fa "const struct roff_node *node" 78fec65c98Schristos.Fc 79fec65c98Schristos.In sys/types.h 80fec65c98Schristos.In mandoc.h 81fec65c98Schristos.In mdoc.h 8248741257Sjoerg.Vt extern const char * const * mdoc_argnames; 8348741257Sjoerg.Vt extern const char * const * mdoc_macronames; 84fec65c98Schristos.In sys/types.h 85fec65c98Schristos.In mandoc.h 86fec65c98Schristos.In man.h 879ff1f2acSchristos.Vt extern const char * const * man_macronames; 8848741257Sjoerg.Sh DESCRIPTION 8948741257SjoergThe 9048741257Sjoerg.Nm mandoc 9148741257Sjoerglibrary parses a 9248741257Sjoerg.Ux 9348741257Sjoergmanual into an abstract syntax tree (AST). 9448741257Sjoerg.Ux 9548741257Sjoergmanuals are composed of 9648741257Sjoerg.Xr mdoc 7 9748741257Sjoergor 9848741257Sjoerg.Xr man 7 , 9948741257Sjoergand may be mixed with 10048741257Sjoerg.Xr roff 7 , 10148741257Sjoerg.Xr tbl 7 , 10248741257Sjoergand 10348741257Sjoerg.Xr eqn 7 10448741257Sjoerginvocations. 10548741257Sjoerg.Pp 10648741257SjoergThe following describes a general parse sequence: 10748741257Sjoerg.Bl -enum 10848741257Sjoerg.It 10948741257Sjoerginitiate a parsing sequence with 110fec65c98Schristos.Xr mchars_alloc 3 111fec65c98Schristosand 11248741257Sjoerg.Fn mparse_alloc ; 11348741257Sjoerg.It 114fec65c98Schristosopen a file with 115fec65c98Schristos.Xr open 2 116fec65c98Schristosor 117fec65c98Schristos.Fn mparse_open ; 118fec65c98Schristos.It 119fec65c98Schristosparse it with 12048741257Sjoerg.Fn mparse_readfd ; 12148741257Sjoerg.It 1229ff1f2acSchristosclose it with 1239ff1f2acSchristos.Xr close 2 ; 1249ff1f2acSchristos.It 125fec65c98Schristosretrieve the syntax tree with 12648741257Sjoerg.Fn mparse_result ; 12748741257Sjoerg.It 1289508192eSchristosif information about the validity of the input is needed, fetch it with 1299508192eSchristos.Fn mparse_updaterc ; 1309508192eSchristos.It 1319ff1f2acSchristositerate over parse nodes with starting from the 1329ff1f2acSchristos.Fa first 1339ff1f2acSchristosmember of the returned 134*544c191cSchristos.Vt struct roff_meta ; 13548741257Sjoerg.It 13648741257Sjoergfree all allocated memory with 137fec65c98Schristos.Fn mparse_free 138fec65c98Schristosand 139fec65c98Schristos.Xr mchars_free 3 , 14048741257Sjoergor invoke 14148741257Sjoerg.Fn mparse_reset 1429ff1f2acSchristosand go back to step 2 to parse new files. 14348741257Sjoerg.El 144c5f73b34Sjoerg.Sh REFERENCE 145c5f73b34SjoergThis section documents the functions, types, and variables available 146c5f73b34Sjoergvia 147fec65c98Schristos.In mandoc.h , 148fec65c98Schristoswith the exception of those documented in 149fec65c98Schristos.Xr mandoc_escape 3 150fec65c98Schristosand 151fec65c98Schristos.Xr mchars_alloc 3 . 152c5f73b34Sjoerg.Ss Types 153c5f73b34Sjoerg.Bl -ohang 154c5f73b34Sjoerg.It Vt "enum mandocerr" 155fec65c98SchristosAn error or warning message during parsing. 156c5f73b34Sjoerg.It Vt "enum mandoclevel" 157c5f73b34SjoergA classification of an 158fec65c98Schristos.Vt "enum mandocerr" 159c5f73b34Sjoergas regards system operation. 1609ff1f2acSchristosSee the DIAGNOSTICS section in 1619ff1f2acSchristos.Xr mandoc 1 1629ff1f2acSchristosregarding the meanings of the levels. 163c5f73b34Sjoerg.It Vt "struct mparse" 164c5f73b34SjoergAn opaque pointer to a running parse sequence. 165c5f73b34SjoergCreated with 166c5f73b34Sjoerg.Fn mparse_alloc 167c5f73b34Sjoergand freed with 168c5f73b34Sjoerg.Fn mparse_free . 169c5f73b34SjoergThis may be used across parsed input if 170c5f73b34Sjoerg.Fn mparse_reset 171c5f73b34Sjoergis called between parses. 172c5f73b34Sjoerg.El 173c5f73b34Sjoerg.Ss Functions 174c5f73b34Sjoerg.Bl -ohang 1759ff1f2acSchristos.It Fn deroff 176fec65c98SchristosObtain a text-only representation of a 1779ff1f2acSchristos.Vt struct roff_node , 178fec65c98Schristosincluding text contained in its child nodes. 1799ff1f2acSchristosTo be used on children of the 1809ff1f2acSchristos.Fa first 1819ff1f2acSchristosmember of 182*544c191cSchristos.Vt struct roff_meta . 183fec65c98SchristosWhen it is no longer needed, the pointer returned from 1849ff1f2acSchristos.Fn deroff 185fec65c98Schristoscan be passed to 186fec65c98Schristos.Xr free 3 . 187c5f73b34Sjoerg.It Fn mparse_alloc 188c5f73b34SjoergAllocate a parser. 189fec65c98SchristosThe arguments have the following effect: 190fec65c98Schristos.Bl -tag -offset 5n -width inttype 191fec65c98Schristos.It Ar options 192fec65c98SchristosWhen the 193fec65c98Schristos.Dv MPARSE_MDOC 194fec65c98Schristosor 195fec65c98Schristos.Dv MPARSE_MAN 196fec65c98Schristosbit is set, only that parser is used. 197fec65c98SchristosOtherwise, the document type is automatically detected. 198fec65c98Schristos.Pp 199fec65c98SchristosWhen the 200fec65c98Schristos.Dv MPARSE_SO 201fec65c98Schristosbit is set, 202fec65c98Schristos.Xr roff 7 203fec65c98Schristos.Ic \&so 204fec65c98Schristosfile inclusion requests are always honoured. 205fec65c98SchristosOtherwise, if the request is the only content in an input file, 206fec65c98Schristosonly the file name is remembered, to be returned in the 207fec65c98Schristos.Fa sodest 208*544c191cSchristosfield of 209*544c191cSchristos.Vt struct roff_meta . 210fec65c98Schristos.Pp 211fec65c98SchristosWhen the 212fec65c98Schristos.Dv MPARSE_QUICK 213fec65c98Schristosbit is set, parsing is aborted after the NAME section. 214fec65c98SchristosThis is for example useful in 215fec65c98Schristos.Xr makewhatis 8 216fec65c98Schristos.Fl Q 217fec65c98Schristosto quickly build minimal databases. 218*544c191cSchristos.Pp 219*544c191cSchristosWhen the 220*544c191cSchristos.Dv MARSE_VALIDATE 221*544c191cSchristosbit is set, 222*544c191cSchristos.Fn mparse_result 223*544c191cSchristosruns the validation functions before returning the syntax tree. 224*544c191cSchristosThis is almost always required, except in certain debugging scenarios, 225*544c191cSchristosfor example to dump unvalidated syntax trees. 226c9bcef03Schristos.It Ar os_e 227c9bcef03SchristosOperating system to check base system conventions for. 228c9bcef03SchristosIf 229c9bcef03Schristos.Dv MANDOC_OS_OTHER , 230c9bcef03Schristosthe system is automatically detected from 231c9bcef03Schristos.Ic \&Os , 232c9bcef03Schristos.Fl Ios , 233c9bcef03Schristosor 234c9bcef03Schristos.Xr uname 3 . 235c9bcef03Schristos.It Ar os_s 236fec65c98SchristosA default string for the 237fec65c98Schristos.Xr mdoc 7 238c9bcef03Schristos.Ic \&Os 239fec65c98Schristosmacro, overriding the 240fec65c98Schristos.Dv OSNAME 241fec65c98Schristospreprocessor definition and the results of 242fec65c98Schristos.Xr uname 3 . 2439ff1f2acSchristosPassing 2449ff1f2acSchristos.Dv NULL 2459ff1f2acSchristossets no default. 246fec65c98Schristos.El 247fec65c98Schristos.Pp 248c5f73b34SjoergThe same parser may be used for multiple files so long as 249c5f73b34Sjoerg.Fn mparse_reset 250c5f73b34Sjoergis called between parses. 251c5f73b34Sjoerg.Fn mparse_free 252c5f73b34Sjoergmust be called to free the memory allocated by this function. 25370f041f9SjoergDeclared in 25470f041f9Sjoerg.In mandoc.h , 25570f041f9Sjoergimplemented in 25670f041f9Sjoerg.Pa read.c . 257c5f73b34Sjoerg.It Fn mparse_free 258c5f73b34SjoergFree all memory allocated by 259c5f73b34Sjoerg.Fn mparse_alloc . 26070f041f9SjoergDeclared in 26170f041f9Sjoerg.In mandoc.h , 26270f041f9Sjoergimplemented in 26370f041f9Sjoerg.Pa read.c . 264*544c191cSchristos.It Fn mparse_copy 265*544c191cSchristosDump a copy of the input to the standard output; used for 266*544c191cSchristos.Fl man T Ns Cm man . 26770f041f9SjoergDeclared in 26870f041f9Sjoerg.In mandoc.h , 26970f041f9Sjoergimplemented in 27070f041f9Sjoerg.Pa read.c . 271fec65c98Schristos.It Fn mparse_open 2729ff1f2acSchristosOpen the file for reading. 2739ff1f2acSchristosIf that fails and 274fec65c98Schristos.Fa fname 2759ff1f2acSchristosdoes not already end in 2769ff1f2acSchristos.Ql .gz , 2779ff1f2acSchristostry again after appending 2789ff1f2acSchristos.Ql .gz . 2799ff1f2acSchristosSave the information whether the file is zipped or not. 2809ff1f2acSchristosReturn a file descriptor open for reading or -1 on failure. 281fec65c98SchristosIt can be passed to 282fec65c98Schristos.Fn mparse_readfd 283fec65c98Schristosor used directly. 284fec65c98SchristosDeclared in 285fec65c98Schristos.In mandoc.h , 286fec65c98Schristosimplemented in 287fec65c98Schristos.Pa read.c . 288fec65c98Schristos.It Fn mparse_readfd 289fec65c98SchristosParse a file descriptor opened with 290fec65c98Schristos.Xr open 2 291fec65c98Schristosor 292fec65c98Schristos.Fn mparse_open . 293fec65c98SchristosPass the associated filename in 294fec65c98Schristos.Va fname . 295fec65c98SchristosThis function may be called multiple times with different parameters; however, 2969ff1f2acSchristos.Xr close 2 2979ff1f2acSchristosand 298c5f73b34Sjoerg.Fn mparse_reset 299c5f73b34Sjoergshould be invoked between parses. 30070f041f9SjoergDeclared in 30170f041f9Sjoerg.In mandoc.h , 30270f041f9Sjoergimplemented in 30370f041f9Sjoerg.Pa read.c . 304c5f73b34Sjoerg.It Fn mparse_reset 305c5f73b34SjoergReset a parser so that 306c5f73b34Sjoerg.Fn mparse_readfd 307c5f73b34Sjoergmay be used again. 30870f041f9SjoergDeclared in 30970f041f9Sjoerg.In mandoc.h , 31070f041f9Sjoergimplemented in 31170f041f9Sjoerg.Pa read.c . 312c5f73b34Sjoerg.It Fn mparse_result 313c5f73b34SjoergObtain the result of a parse. 3149508192eSchristosDeclared in 3159508192eSchristos.In mandoc.h , 3169508192eSchristosimplemented in 3179508192eSchristos.Pa read.c . 318c5f73b34Sjoerg.El 319c5f73b34Sjoerg.Ss Variables 320c5f73b34Sjoerg.Bl -ohang 321c5f73b34Sjoerg.It Va man_macronames 3229ff1f2acSchristosThe string representation of a 3239ff1f2acSchristos.Xr man 7 3249ff1f2acSchristosmacro as indexed by 325c5f73b34Sjoerg.Vt "enum mant" . 326c5f73b34Sjoerg.It Va mdoc_argnames 3279ff1f2acSchristosThe string representation of an 3289ff1f2acSchristos.Xr mdoc 7 3299ff1f2acSchristosmacro argument as indexed by 330c5f73b34Sjoerg.Vt "enum mdocargt" . 331c5f73b34Sjoerg.It Va mdoc_macronames 3329ff1f2acSchristosThe string representation of an 3339ff1f2acSchristos.Xr mdoc 7 3349ff1f2acSchristosmacro as indexed by 335c5f73b34Sjoerg.Vt "enum mdoct" . 336c5f73b34Sjoerg.El 33748741257Sjoerg.Sh IMPLEMENTATION NOTES 33848741257SjoergThis section consists of structural documentation for 33948741257Sjoerg.Xr mdoc 7 34048741257Sjoergand 34148741257Sjoerg.Xr man 7 342c5f73b34Sjoergsyntax trees and strings. 343c5f73b34Sjoerg.Ss Man and Mdoc Strings 344c5f73b34SjoergStrings may be extracted from mdoc and man meta-data, or from text 345c5f73b34Sjoergnodes (MDOC_TEXT and MAN_TEXT, respectively). 346c5f73b34SjoergThese strings have special non-printing formatting cues embedded in the 347c5f73b34Sjoergtext itself, as well as 348c5f73b34Sjoerg.Xr roff 7 349c5f73b34Sjoergescapes preserved from input. 350c5f73b34SjoergImplementing systems will need to handle both situations to produce 351c5f73b34Sjoerghuman-readable text. 352c5f73b34SjoergIn general, strings may be assumed to consist of 7-bit ASCII characters. 353c5f73b34Sjoerg.Pp 354c5f73b34SjoergThe following non-printing characters may be embedded in text strings: 355c5f73b34Sjoerg.Bl -tag -width Ds 356c5f73b34Sjoerg.It Dv ASCII_NBRSP 357c5f73b34SjoergA non-breaking space character. 358c5f73b34Sjoerg.It Dv ASCII_HYPH 359c5f73b34SjoergA soft hyphen. 360fec65c98Schristos.It Dv ASCII_BREAK 361fec65c98SchristosA breakable zero-width space. 362c5f73b34Sjoerg.El 363c5f73b34Sjoerg.Pp 364c5f73b34SjoergEscape characters are also passed verbatim into text strings. 365c5f73b34SjoergAn escape character is a sequence of characters beginning with the 366c5f73b34Sjoergbackslash 367c5f73b34Sjoerg.Pq Sq \e . 368c5f73b34SjoergTo construct human-readable text, these should be intercepted with 369fec65c98Schristos.Xr mandoc_escape 3 370fec65c98Schristosand converted with one the functions described in 371fec65c98Schristos.Xr mchars_alloc 3 . 37248741257Sjoerg.Ss Man Abstract Syntax Tree 37348741257SjoergThis AST is governed by the ontological rules dictated in 37448741257Sjoerg.Xr man 7 37548741257Sjoergand derives its terminology accordingly. 37648741257Sjoerg.Pp 37748741257SjoergThe AST is composed of 3789ff1f2acSchristos.Vt struct roff_node 37948741257Sjoergnodes with element, root and text types as declared by the 38048741257Sjoerg.Va type 38148741257Sjoergfield. 38248741257SjoergEach node also provides its parse point (the 38348741257Sjoerg.Va line , 3849ff1f2acSchristos.Va pos , 38548741257Sjoergand 3869ff1f2acSchristos.Va sec 38748741257Sjoergfields), its position in the tree (the 38848741257Sjoerg.Va parent , 38948741257Sjoerg.Va child , 39048741257Sjoerg.Va next 39148741257Sjoergand 39248741257Sjoerg.Va prev 39348741257Sjoergfields) and some type-specific data. 39448741257Sjoerg.Pp 39548741257SjoergThe tree itself is arranged according to the following normal form, 39648741257Sjoergwhere capitalised non-terminals represent nodes. 39748741257Sjoerg.Pp 39848741257Sjoerg.Bl -tag -width "ELEMENTXX" -compact 39948741257Sjoerg.It ROOT 40048741257Sjoerg\(<- mnode+ 40148741257Sjoerg.It mnode 40248741257Sjoerg\(<- ELEMENT | TEXT | BLOCK 40348741257Sjoerg.It BLOCK 40448741257Sjoerg\(<- HEAD BODY 40548741257Sjoerg.It HEAD 40648741257Sjoerg\(<- mnode* 40748741257Sjoerg.It BODY 40848741257Sjoerg\(<- mnode* 40948741257Sjoerg.It ELEMENT 41048741257Sjoerg\(<- ELEMENT | TEXT* 41148741257Sjoerg.It TEXT 412c5f73b34Sjoerg\(<- [[:ascii:]]* 41348741257Sjoerg.El 41448741257Sjoerg.Pp 41548741257SjoergThe only elements capable of nesting other elements are those with 416fec65c98Schristosnext-line scope as documented in 41748741257Sjoerg.Xr man 7 . 41848741257Sjoerg.Ss Mdoc Abstract Syntax Tree 41948741257SjoergThis AST is governed by the ontological 42048741257Sjoergrules dictated in 42148741257Sjoerg.Xr mdoc 7 42248741257Sjoergand derives its terminology accordingly. 42348741257Sjoerg.Qq In-line 42448741257Sjoergelements described in 42548741257Sjoerg.Xr mdoc 7 42648741257Sjoergare described simply as 42748741257Sjoerg.Qq elements . 42848741257Sjoerg.Pp 42948741257SjoergThe AST is composed of 4309ff1f2acSchristos.Vt struct roff_node 43148741257Sjoergnodes with block, head, body, element, root and text types as declared 43248741257Sjoergby the 43348741257Sjoerg.Va type 43448741257Sjoergfield. 43548741257SjoergEach node also provides its parse point (the 43648741257Sjoerg.Va line , 4379ff1f2acSchristos.Va pos , 43848741257Sjoergand 4399ff1f2acSchristos.Va sec 44048741257Sjoergfields), its position in the tree (the 44148741257Sjoerg.Va parent , 44248741257Sjoerg.Va child , 4439ff1f2acSchristos.Va last , 44448741257Sjoerg.Va next 44548741257Sjoergand 44648741257Sjoerg.Va prev 44748741257Sjoergfields) and some type-specific data, in particular, for nodes generated 44848741257Sjoergfrom macros, the generating macro in the 44948741257Sjoerg.Va tok 45048741257Sjoergfield. 45148741257Sjoerg.Pp 45248741257SjoergThe tree itself is arranged according to the following normal form, 45348741257Sjoergwhere capitalised non-terminals represent nodes. 45448741257Sjoerg.Pp 45548741257Sjoerg.Bl -tag -width "ELEMENTXX" -compact 45648741257Sjoerg.It ROOT 45748741257Sjoerg\(<- mnode+ 45848741257Sjoerg.It mnode 45948741257Sjoerg\(<- BLOCK | ELEMENT | TEXT 46048741257Sjoerg.It BLOCK 46148741257Sjoerg\(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]] 46248741257Sjoerg.It ELEMENT 46348741257Sjoerg\(<- TEXT* 46448741257Sjoerg.It HEAD 46548741257Sjoerg\(<- mnode* 46648741257Sjoerg.It BODY 46748741257Sjoerg\(<- mnode* [ENDBODY mnode*] 46848741257Sjoerg.It TAIL 46948741257Sjoerg\(<- mnode* 47048741257Sjoerg.It TEXT 471c5f73b34Sjoerg\(<- [[:ascii:]]* 47248741257Sjoerg.El 47348741257Sjoerg.Pp 47448741257SjoergOf note are the TEXT nodes following the HEAD, BODY and TAIL nodes of 47548741257Sjoergthe BLOCK production: these refer to punctuation marks. 47648741257SjoergFurthermore, although a TEXT node will generally have a non-zero-length 47748741257Sjoergstring, in the specific case of 47848741257Sjoerg.Sq \&.Bd \-literal , 47948741257Sjoergan empty line will produce a zero-length string. 48048741257SjoergMultiple body parts are only found in invocations of 48148741257Sjoerg.Sq \&Bl \-column , 48248741257Sjoergwhere a new body introduces a new phrase. 48348741257Sjoerg.Pp 48448741257SjoergThe 48548741257Sjoerg.Xr mdoc 7 486c5f73b34Sjoergsyntax tree accommodates for broken block structures as well. 48748741257SjoergThe ENDBODY node is available to end the formatting associated 48848741257Sjoergwith a given block before the physical end of that block. 48948741257SjoergIt has a non-null 49048741257Sjoerg.Va end 49148741257Sjoergfield, is of the BODY 49248741257Sjoerg.Va type , 49348741257Sjoerghas the same 49448741257Sjoerg.Va tok 49548741257Sjoergas the BLOCK it is ending, and has a 49648741257Sjoerg.Va pending 49748741257Sjoergfield pointing to that BLOCK's BODY node. 49848741257SjoergIt is an indirect child of that BODY node 49948741257Sjoergand has no children of its own. 50048741257Sjoerg.Pp 50148741257SjoergAn ENDBODY node is generated when a block ends while one of its child 50248741257Sjoergblocks is still open, like in the following example: 50348741257Sjoerg.Bd -literal -offset indent 50448741257Sjoerg\&.Ao ao 50548741257Sjoerg\&.Bo bo ac 50648741257Sjoerg\&.Ac bc 50748741257Sjoerg\&.Bc end 50848741257Sjoerg.Ed 50948741257Sjoerg.Pp 51048741257SjoergThis example results in the following block structure: 51148741257Sjoerg.Bd -literal -offset indent 51248741257SjoergBLOCK Ao 51348741257Sjoerg HEAD Ao 51448741257Sjoerg BODY Ao 51548741257Sjoerg TEXT ao 51648741257Sjoerg BLOCK Bo, pending -> Ao 51748741257Sjoerg HEAD Bo 51848741257Sjoerg BODY Bo 51948741257Sjoerg TEXT bo 52048741257Sjoerg TEXT ac 52148741257Sjoerg ENDBODY Ao, pending -> Ao 52248741257Sjoerg TEXT bc 52348741257SjoergTEXT end 52448741257Sjoerg.Ed 52548741257Sjoerg.Pp 52648741257SjoergHere, the formatting of the 527c9bcef03Schristos.Ic \&Ao 52848741257Sjoergblock extends from TEXT ao to TEXT ac, 52948741257Sjoergwhile the formatting of the 530c9bcef03Schristos.Ic \&Bo 53148741257Sjoergblock extends from TEXT bo to TEXT bc. 53248741257SjoergIt renders as follows in 53348741257Sjoerg.Fl T Ns Cm ascii 53448741257Sjoergmode: 53548741257Sjoerg.Pp 53648741257Sjoerg.Dl <ao [bo ac> bc] end 53748741257Sjoerg.Pp 53848741257SjoergSupport for badly-nested blocks is only provided for backward 53948741257Sjoergcompatibility with some older 54048741257Sjoerg.Xr mdoc 7 54148741257Sjoergimplementations. 54248741257SjoergUsing badly-nested blocks is 54348741257Sjoerg.Em strongly discouraged ; 54448741257Sjoergfor example, the 54548741257Sjoerg.Fl T Ns Cm html 546c9bcef03Schristosfront-end to 54748741257Sjoerg.Xr mandoc 1 548c9bcef03Schristosis unable to render them in any meaningful way. 54948741257SjoergFurthermore, behaviour when encountering badly-nested blocks is not 55048741257Sjoergconsistent across troff implementations, especially when using multiple 55148741257Sjoerglevels of badly-nested blocks. 55248741257Sjoerg.Sh SEE ALSO 55348741257Sjoerg.Xr mandoc 1 , 5549ff1f2acSchristos.Xr man.cgi 3 , 555fec65c98Schristos.Xr mandoc_escape 3 , 5569ff1f2acSchristos.Xr mandoc_headers 3 , 557fec65c98Schristos.Xr mandoc_malloc 3 , 5589ff1f2acSchristos.Xr mansearch 3 , 559fec65c98Schristos.Xr mchars_alloc 3 , 5609ff1f2acSchristos.Xr tbl 3 , 56148741257Sjoerg.Xr eqn 7 , 56248741257Sjoerg.Xr man 7 , 563c5f73b34Sjoerg.Xr mandoc_char 7 , 56448741257Sjoerg.Xr mdoc 7 , 56548741257Sjoerg.Xr roff 7 , 56648741257Sjoerg.Xr tbl 7 56748741257Sjoerg.Sh AUTHORS 5689ff1f2acSchristos.An -nosplit 56948741257SjoergThe 57048741257Sjoerg.Nm 57148741257Sjoerglibrary was written by 5729ff1f2acSchristos.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv 5739ff1f2acSchristosand is maintained by 5749ff1f2acSchristos.An Ingo Schwarze Aq Mt schwarze@openbsd.org . 575