Annotation of mandoc/mandoc.3, Revision 1.28
1.28 ! schwarze 1: .\" $Id: mandoc.3,v 1.27 2014/10/28 17:36:19 schwarze Exp $
1.1 kristaps 2: .\"
3: .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4: .\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
5: .\"
6: .\" Permission to use, copy, modify, and distribute this software for any
7: .\" purpose with or without fee is hereby granted, provided that the above
8: .\" copyright notice and this permission notice appear in all copies.
9: .\"
10: .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: .\"
1.28 ! schwarze 18: .Dd $Mdocdate: October 28 2014 $
1.1 kristaps 19: .Dt MANDOC 3
20: .Os
21: .Sh NAME
22: .Nm mandoc ,
1.25 schwarze 23: .Nm man_deroff ,
1.1 kristaps 24: .Nm man_meta ,
1.14 kristaps 25: .Nm man_mparse ,
1.1 kristaps 26: .Nm man_node ,
1.25 schwarze 27: .Nm mdoc_deroff ,
1.1 kristaps 28: .Nm mdoc_meta ,
29: .Nm mdoc_node ,
30: .Nm mparse_alloc ,
31: .Nm mparse_free ,
1.14 kristaps 32: .Nm mparse_getkeep ,
33: .Nm mparse_keep ,
1.26 schwarze 34: .Nm mparse_open ,
1.1 kristaps 35: .Nm mparse_readfd ,
36: .Nm mparse_reset ,
1.2 kristaps 37: .Nm mparse_result ,
38: .Nm mparse_strerror ,
39: .Nm mparse_strlevel
1.26 schwarze 40: .Nm mparse_wait ,
1.1 kristaps 41: .Nd mandoc macro compiler library
1.8 kristaps 42: .Sh LIBRARY
1.22 schwarze 43: .Lb libmandoc
1.1 kristaps 44: .Sh SYNOPSIS
1.25 schwarze 45: .In sys/types.h
1.1 kristaps 46: .In mandoc.h
1.24 schwarze 47: .Fd "#define ASCII_NBRSP"
48: .Fd "#define ASCII_HYPH"
49: .Fd "#define ASCII_BREAK"
1.25 schwarze 50: .Ft struct mparse *
1.1 kristaps 51: .Fo mparse_alloc
1.25 schwarze 52: .Fa "int options"
1.1 kristaps 53: .Fa "enum mandoclevel wlevel"
1.23 schwarze 54: .Fa "mandocmsg mmsg"
1.27 schwarze 55: .Fa "const struct mchars *mchars"
1.23 schwarze 56: .Fa "char *defos"
1.1 kristaps 57: .Fc
58: .Ft void
1.24 schwarze 59: .Fo (*mandocmsg)
60: .Fa "enum mandocerr errtype"
61: .Fa "enum mandoclevel level"
62: .Fa "const char *file"
63: .Fa "int line"
64: .Fa "int col"
65: .Fa "const char *msg"
66: .Fc
67: .Ft void
1.1 kristaps 68: .Fo mparse_free
69: .Fa "struct mparse *parse"
70: .Fc
1.23 schwarze 71: .Ft const char *
1.14 kristaps 72: .Fo mparse_getkeep
73: .Fa "const struct mparse *parse"
74: .Fc
75: .Ft void
76: .Fo mparse_keep
77: .Fa "struct mparse *parse"
78: .Fc
1.1 kristaps 79: .Ft "enum mandoclevel"
1.26 schwarze 80: .Fo mparse_open
81: .Fa "struct mparse *parse"
82: .Fa "int *fd"
83: .Fa "const char *fname"
84: .Fc
85: .Ft "enum mandoclevel"
1.1 kristaps 86: .Fo mparse_readfd
87: .Fa "struct mparse *parse"
88: .Fa "int fd"
89: .Fa "const char *fname"
90: .Fc
91: .Ft void
92: .Fo mparse_reset
93: .Fa "struct mparse *parse"
94: .Fc
95: .Ft void
96: .Fo mparse_result
97: .Fa "struct mparse *parse"
98: .Fa "struct mdoc **mdoc"
99: .Fa "struct man **man"
1.25 schwarze 100: .Fa "char **sodest"
1.2 kristaps 101: .Fc
102: .Ft "const char *"
103: .Fo mparse_strerror
104: .Fa "enum mandocerr"
105: .Fc
106: .Ft "const char *"
107: .Fo mparse_strlevel
108: .Fa "enum mandoclevel"
1.1 kristaps 109: .Fc
1.26 schwarze 110: .Ft "enum mandoclevel"
111: .Fo mparse_wait
112: .Fa "struct mparse *parse"
113: .Fc
1.25 schwarze 114: .In sys/types.h
1.24 schwarze 115: .In mandoc.h
116: .In mdoc.h
1.25 schwarze 117: .Ft void
118: .Fo mdoc_deroff
119: .Fa "char **dest"
120: .Fa "const struct mdoc_node *node"
121: .Fc
1.24 schwarze 122: .Ft "const struct mdoc_meta *"
123: .Fo mdoc_meta
124: .Fa "const struct mdoc *mdoc"
125: .Fc
126: .Ft "const struct mdoc_node *"
127: .Fo mdoc_node
128: .Fa "const struct mdoc *mdoc"
129: .Fc
1.1 kristaps 130: .Vt extern const char * const * mdoc_argnames;
131: .Vt extern const char * const * mdoc_macronames;
1.25 schwarze 132: .In sys/types.h
1.24 schwarze 133: .In mandoc.h
134: .In man.h
1.25 schwarze 135: .Ft void
136: .Fo man_deroff
137: .Fa "char **dest"
138: .Fa "const struct man_node *node"
139: .Fc
1.24 schwarze 140: .Ft "const struct man_meta *"
141: .Fo man_meta
142: .Fa "const struct man *man"
143: .Fc
144: .Ft "const struct mparse *"
145: .Fo man_mparse
146: .Fa "const struct man *man"
147: .Fc
148: .Ft "const struct man_node *"
149: .Fo man_node
150: .Fa "const struct man *man"
151: .Fc
152: .Vt extern const char * const * man_macronames;
1.1 kristaps 153: .Sh DESCRIPTION
154: The
155: .Nm mandoc
156: library parses a
157: .Ux
158: manual into an abstract syntax tree (AST).
159: .Ux
160: manuals are composed of
161: .Xr mdoc 7
162: or
163: .Xr man 7 ,
164: and may be mixed with
165: .Xr roff 7 ,
166: .Xr tbl 7 ,
167: and
168: .Xr eqn 7
169: invocations.
170: .Pp
171: The following describes a general parse sequence:
172: .Bl -enum
173: .It
174: initiate a parsing sequence with
1.27 schwarze 175: .Xr mchars_alloc 3
176: and
1.1 kristaps 177: .Fn mparse_alloc ;
178: .It
179: parse files or file descriptors with
180: .Fn mparse_readfd ;
181: .It
182: retrieve a parsed syntax tree, if the parse was successful, with
183: .Fn mparse_result ;
184: .It
185: iterate over parse nodes with
186: .Fn mdoc_node
187: or
188: .Fn man_node ;
189: .It
190: free all allocated memory with
1.27 schwarze 191: .Fn mparse_free
192: and
193: .Xr mchars_free 3 ,
1.1 kristaps 194: or invoke
195: .Fn mparse_reset
196: and parse new files.
1.3 kristaps 197: .El
198: .Sh REFERENCE
199: This section documents the functions, types, and variables available
200: via
1.25 schwarze 201: .In mandoc.h ,
202: with the exception of those documented in
203: .Xr mandoc_escape 3
204: and
205: .Xr mchars_alloc 3 .
1.3 kristaps 206: .Ss Types
207: .Bl -ohang
208: .It Vt "enum mandocerr"
1.11 kristaps 209: A fatal error, error, or warning message during parsing.
1.3 kristaps 210: .It Vt "enum mandoclevel"
1.11 kristaps 211: A classification of an
1.23 schwarze 212: .Vt "enum mandocerr"
1.11 kristaps 213: as regards system operation.
1.27 schwarze 214: .It Vt "struct mchars"
215: An opaque pointer to a a character table.
216: Created with
217: .Xr mchars_alloc 3
218: and freed with
219: .Xr mchars_free 3 .
1.3 kristaps 220: .It Vt "struct mparse"
1.11 kristaps 221: An opaque pointer to a running parse sequence.
222: Created with
223: .Fn mparse_alloc
224: and freed with
225: .Fn mparse_free .
226: This may be used across parsed input if
227: .Fn mparse_reset
228: is called between parses.
1.3 kristaps 229: .It Vt "mandocmsg"
1.11 kristaps 230: A prototype for a function to handle fatal error, error, and warning
231: messages emitted by the parser.
1.3 kristaps 232: .El
233: .Ss Functions
234: .Bl -ohang
1.25 schwarze 235: .It Fn man_deroff
236: Obtain a text-only representation of a
237: .Vt struct man_node ,
238: including text contained in its child nodes.
239: To be used on children of the pointer returned from
240: .Fn man_node .
241: When it is no longer needed, the pointer returned from
242: .Fn man_deroff
243: can be passed to
244: .Xr free 3 .
1.3 kristaps 245: .It Fn man_meta
1.25 schwarze 246: Obtain the meta-data of a successful
247: .Xr man 7
248: parse.
1.4 kristaps 249: This may only be used on a pointer returned by
250: .Fn mparse_result .
1.18 schwarze 251: Declared in
252: .In man.h ,
253: implemented in
254: .Pa man.c .
1.14 kristaps 255: .It Fn man_mparse
256: Get the parser used for the current output.
1.18 schwarze 257: Declared in
258: .In man.h ,
259: implemented in
260: .Pa man.c .
1.3 kristaps 261: .It Fn man_node
1.25 schwarze 262: Obtain the root node of a successful
263: .Xr man 7
264: parse.
1.4 kristaps 265: This may only be used on a pointer returned by
266: .Fn mparse_result .
1.18 schwarze 267: Declared in
268: .In man.h ,
269: implemented in
270: .Pa man.c .
1.25 schwarze 271: .It Fn mdoc_deroff
272: Obtain a text-only representation of a
273: .Vt struct mdoc_node ,
274: including text contained in its child nodes.
275: To be used on children of the pointer returned from
276: .Fn mdoc_node .
277: When it is no longer needed, the pointer returned from
278: .Fn mdoc_deroff
279: can be passed to
280: .Xr free 3 .
1.3 kristaps 281: .It Fn mdoc_meta
1.25 schwarze 282: Obtain the meta-data of a successful
283: .Xr mdoc
284: parse.
1.4 kristaps 285: This may only be used on a pointer returned by
286: .Fn mparse_result .
1.18 schwarze 287: Declared in
288: .In mdoc.h ,
289: implemented in
290: .Pa mdoc.c .
1.3 kristaps 291: .It Fn mdoc_node
1.25 schwarze 292: Obtain the root node of a successful
293: .Xr mdoc
294: parse.
1.4 kristaps 295: This may only be used on a pointer returned by
296: .Fn mparse_result .
1.18 schwarze 297: Declared in
298: .In mdoc.h ,
299: implemented in
300: .Pa mdoc.c .
1.3 kristaps 301: .It Fn mparse_alloc
1.4 kristaps 302: Allocate a parser.
1.23 schwarze 303: The arguments have the following effect:
304: .Bl -tag -offset 5n -width inttype
1.25 schwarze 305: .It Ar options
306: When the
1.23 schwarze 307: .Dv MPARSE_MDOC
308: or
1.25 schwarze 309: .Dv MPARSE_MAN
310: bit is set, only that parser is used.
311: Otherwise, the document type is automatically detected.
312: .Pp
313: When the
314: .Dv MPARSE_SO
315: bit is set,
316: .Xr roff 7
317: .Ic \&so
318: file inclusion requests are always honoured.
319: Otherwise, if the request is the only content in an input file,
320: only the file name is remembered, to be returned in the
321: .Fa sodest
322: argument of
323: .Fn mparse_result .
324: .Pp
325: When the
326: .Dv MPARSE_QUICK
327: bit is set, parsing is aborted after the NAME section.
328: This is for example useful in
329: .Xr makewhatis 8
330: .Fl Q
331: to quickly build minimal databases.
1.23 schwarze 332: .It Ar wlevel
333: Can be set to
334: .Dv MANDOCLEVEL_FATAL ,
335: .Dv MANDOCLEVEL_ERROR ,
336: or
337: .Dv MANDOCLEVEL_WARNING .
338: Messages below the selected level will be suppressed.
339: .It Ar mmsg
340: A callback function to handle errors and warnings.
341: See
342: .Pa main.c
343: for an example.
1.27 schwarze 344: .It Ar mchars
345: An opaque pointer to a a character table obtained from
346: .Xr mchars_alloc 3 .
1.23 schwarze 347: .It Ar defos
348: A default string for the
349: .Xr mdoc 7
350: .Sq \&Os
351: macro, overriding the
352: .Dv OSNAME
353: preprocessor definition and the results of
354: .Xr uname 3 .
355: .El
356: .Pp
1.4 kristaps 357: The same parser may be used for multiple files so long as
358: .Fn mparse_reset
359: is called between parses.
360: .Fn mparse_free
361: must be called to free the memory allocated by this function.
1.18 schwarze 362: Declared in
363: .In mandoc.h ,
364: implemented in
365: .Pa read.c .
1.3 kristaps 366: .It Fn mparse_free
1.4 kristaps 367: Free all memory allocated by
368: .Fn mparse_alloc .
1.18 schwarze 369: Declared in
370: .In mandoc.h ,
371: implemented in
372: .Pa read.c .
1.14 kristaps 373: .It Fn mparse_getkeep
374: Acquire the keep buffer.
375: Must follow a call of
376: .Fn mparse_keep .
1.18 schwarze 377: Declared in
378: .In mandoc.h ,
379: implemented in
380: .Pa read.c .
1.14 kristaps 381: .It Fn mparse_keep
382: Instruct the parser to retain a copy of its parsed input.
383: This can be acquired with subsequent
384: .Fn mparse_getkeep
385: calls.
1.18 schwarze 386: Declared in
387: .In mandoc.h ,
388: implemented in
389: .Pa read.c .
1.26 schwarze 390: .It Fn mparse_open
391: If the
392: .Fa fname
393: ends in
394: .Pa .gz ,
395: open with
396: .Xr gunzip 1 ;
397: otherwise, with
398: .Xr open 2 .
399: Return a file descriptor open for reading in
400: .Fa fd ,
401: or -1 on failure.
402: It can be passed to
403: .Fn mparse_readfd
404: or used directly.
405: Declared in
406: .In mandoc.h ,
407: implemented in
408: .Pa read.c .
1.3 kristaps 409: .It Fn mparse_readfd
1.4 kristaps 410: Parse a file or file descriptor.
411: If
412: .Va fd
413: is -1,
414: .Va fname
415: is opened for reading.
416: Otherwise,
417: .Va fname
418: is assumed to be the name associated with
419: .Va fd .
420: This may be called multiple times with different parameters; however,
421: .Fn mparse_reset
422: should be invoked between parses.
1.18 schwarze 423: Declared in
424: .In mandoc.h ,
425: implemented in
426: .Pa read.c .
1.3 kristaps 427: .It Fn mparse_reset
1.4 kristaps 428: Reset a parser so that
429: .Fn mparse_readfd
430: may be used again.
1.18 schwarze 431: Declared in
432: .In mandoc.h ,
433: implemented in
434: .Pa read.c .
1.3 kristaps 435: .It Fn mparse_result
1.4 kristaps 436: Obtain the result of a parse.
437: Only successful parses
438: .Po
439: i.e., those where
440: .Fn mparse_readfd
441: returned less than MANDOCLEVEL_FATAL
442: .Pc
1.25 schwarze 443: should invoke this function, in which case one of the three pointers will
1.4 kristaps 444: be filled in.
1.18 schwarze 445: Declared in
446: .In mandoc.h ,
447: implemented in
448: .Pa read.c .
1.3 kristaps 449: .It Fn mparse_strerror
1.4 kristaps 450: Return a statically-allocated string representation of an error code.
1.18 schwarze 451: Declared in
452: .In mandoc.h ,
453: implemented in
454: .Pa read.c .
1.3 kristaps 455: .It Fn mparse_strlevel
1.4 kristaps 456: Return a statically-allocated string representation of a level code.
1.26 schwarze 457: Declared in
458: .In mandoc.h ,
459: implemented in
460: .Pa read.c .
461: .It Fn mparse_wait
462: Bury a
463: .Xr gunzip 1
464: child process
465: .Fa child_pid
466: that was spawned with
467: .Fn mparse_open .
468: To be called after the parse sequence is complete.
469: Returns
470: .Dv MANDOCLEVEL_OK
471: on success and
472: .Dv MANDOCLEVEL_SYSERR
473: on failure, that is, when
474: .Xr wait 2
475: fails, or when
476: .Xr gunzip 1
477: died from a signal or exited with non-zero status.
1.18 schwarze 478: Declared in
479: .In mandoc.h ,
480: implemented in
481: .Pa read.c .
1.3 kristaps 482: .El
483: .Ss Variables
484: .Bl -ohang
485: .It Va man_macronames
1.4 kristaps 486: The string representation of a man macro as indexed by
487: .Vt "enum mant" .
1.3 kristaps 488: .It Va mdoc_argnames
1.4 kristaps 489: The string representation of a mdoc macro argument as indexed by
490: .Vt "enum mdocargt" .
1.3 kristaps 491: .It Va mdoc_macronames
1.4 kristaps 492: The string representation of a mdoc macro as indexed by
493: .Vt "enum mdoct" .
1.1 kristaps 494: .El
495: .Sh IMPLEMENTATION NOTES
496: This section consists of structural documentation for
497: .Xr mdoc 7
498: and
499: .Xr man 7
1.11 kristaps 500: syntax trees and strings.
501: .Ss Man and Mdoc Strings
502: Strings may be extracted from mdoc and man meta-data, or from text
503: nodes (MDOC_TEXT and MAN_TEXT, respectively).
504: These strings have special non-printing formatting cues embedded in the
505: text itself, as well as
506: .Xr roff 7
507: escapes preserved from input.
508: Implementing systems will need to handle both situations to produce
509: human-readable text.
510: In general, strings may be assumed to consist of 7-bit ASCII characters.
511: .Pp
512: The following non-printing characters may be embedded in text strings:
513: .Bl -tag -width Ds
514: .It Dv ASCII_NBRSP
515: A non-breaking space character.
516: .It Dv ASCII_HYPH
517: A soft hyphen.
1.25 schwarze 518: .It Dv ASCII_BREAK
519: A breakable zero-width space.
1.11 kristaps 520: .El
521: .Pp
522: Escape characters are also passed verbatim into text strings.
523: An escape character is a sequence of characters beginning with the
524: backslash
525: .Pq Sq \e .
526: To construct human-readable text, these should be intercepted with
1.25 schwarze 527: .Xr mandoc_escape 3
528: and converted with one the functions described in
529: .Xr mchars_alloc 3 .
1.1 kristaps 530: .Ss Man Abstract Syntax Tree
531: This AST is governed by the ontological rules dictated in
532: .Xr man 7
533: and derives its terminology accordingly.
534: .Pp
535: The AST is composed of
536: .Vt struct man_node
537: nodes with element, root and text types as declared by the
538: .Va type
539: field.
540: Each node also provides its parse point (the
541: .Va line ,
542: .Va sec ,
543: and
544: .Va pos
545: fields), its position in the tree (the
546: .Va parent ,
547: .Va child ,
548: .Va next
549: and
550: .Va prev
551: fields) and some type-specific data.
552: .Pp
553: The tree itself is arranged according to the following normal form,
554: where capitalised non-terminals represent nodes.
555: .Pp
556: .Bl -tag -width "ELEMENTXX" -compact
557: .It ROOT
558: \(<- mnode+
559: .It mnode
560: \(<- ELEMENT | TEXT | BLOCK
561: .It BLOCK
562: \(<- HEAD BODY
563: .It HEAD
564: \(<- mnode*
565: .It BODY
566: \(<- mnode*
567: .It ELEMENT
568: \(<- ELEMENT | TEXT*
569: .It TEXT
1.11 kristaps 570: \(<- [[:ascii:]]*
1.1 kristaps 571: .El
572: .Pp
573: The only elements capable of nesting other elements are those with
1.25 schwarze 574: next-line scope as documented in
1.1 kristaps 575: .Xr man 7 .
576: .Ss Mdoc Abstract Syntax Tree
577: This AST is governed by the ontological
578: rules dictated in
579: .Xr mdoc 7
580: and derives its terminology accordingly.
581: .Qq In-line
582: elements described in
583: .Xr mdoc 7
584: are described simply as
585: .Qq elements .
586: .Pp
587: The AST is composed of
588: .Vt struct mdoc_node
589: nodes with block, head, body, element, root and text types as declared
590: by the
591: .Va type
592: field.
593: Each node also provides its parse point (the
594: .Va line ,
595: .Va sec ,
596: and
597: .Va pos
598: fields), its position in the tree (the
599: .Va parent ,
600: .Va child ,
601: .Va nchild ,
602: .Va next
603: and
604: .Va prev
605: fields) and some type-specific data, in particular, for nodes generated
606: from macros, the generating macro in the
607: .Va tok
608: field.
609: .Pp
610: The tree itself is arranged according to the following normal form,
611: where capitalised non-terminals represent nodes.
612: .Pp
613: .Bl -tag -width "ELEMENTXX" -compact
614: .It ROOT
615: \(<- mnode+
616: .It mnode
617: \(<- BLOCK | ELEMENT | TEXT
618: .It BLOCK
619: \(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]]
620: .It ELEMENT
621: \(<- TEXT*
622: .It HEAD
623: \(<- mnode*
624: .It BODY
625: \(<- mnode* [ENDBODY mnode*]
626: .It TAIL
627: \(<- mnode*
628: .It TEXT
1.11 kristaps 629: \(<- [[:ascii:]]*
1.1 kristaps 630: .El
631: .Pp
632: Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of
633: the BLOCK production: these refer to punctuation marks.
634: Furthermore, although a TEXT node will generally have a non-zero-length
635: string, in the specific case of
636: .Sq \&.Bd \-literal ,
637: an empty line will produce a zero-length string.
638: Multiple body parts are only found in invocations of
639: .Sq \&Bl \-column ,
640: where a new body introduces a new phrase.
641: .Pp
642: The
643: .Xr mdoc 7
1.5 kristaps 644: syntax tree accommodates for broken block structures as well.
1.1 kristaps 645: The ENDBODY node is available to end the formatting associated
646: with a given block before the physical end of that block.
647: It has a non-null
648: .Va end
649: field, is of the BODY
650: .Va type ,
651: has the same
652: .Va tok
653: as the BLOCK it is ending, and has a
654: .Va pending
655: field pointing to that BLOCK's BODY node.
656: It is an indirect child of that BODY node
657: and has no children of its own.
658: .Pp
659: An ENDBODY node is generated when a block ends while one of its child
660: blocks is still open, like in the following example:
661: .Bd -literal -offset indent
662: \&.Ao ao
663: \&.Bo bo ac
664: \&.Ac bc
665: \&.Bc end
666: .Ed
667: .Pp
668: This example results in the following block structure:
669: .Bd -literal -offset indent
670: BLOCK Ao
671: HEAD Ao
672: BODY Ao
673: TEXT ao
674: BLOCK Bo, pending -> Ao
675: HEAD Bo
676: BODY Bo
677: TEXT bo
678: TEXT ac
679: ENDBODY Ao, pending -> Ao
680: TEXT bc
681: TEXT end
682: .Ed
683: .Pp
684: Here, the formatting of the
685: .Sq \&Ao
686: block extends from TEXT ao to TEXT ac,
687: while the formatting of the
688: .Sq \&Bo
689: block extends from TEXT bo to TEXT bc.
690: It renders as follows in
691: .Fl T Ns Cm ascii
692: mode:
693: .Pp
694: .Dl <ao [bo ac> bc] end
695: .Pp
696: Support for badly-nested blocks is only provided for backward
697: compatibility with some older
698: .Xr mdoc 7
699: implementations.
700: Using badly-nested blocks is
701: .Em strongly discouraged ;
702: for example, the
703: .Fl T Ns Cm html
704: and
705: .Fl T Ns Cm xhtml
706: front-ends to
707: .Xr mandoc 1
708: are unable to render them in any meaningful way.
709: Furthermore, behaviour when encountering badly-nested blocks is not
1.25 schwarze 710: consistent across troff implementations, especially when using multiple
1.1 kristaps 711: levels of badly-nested blocks.
712: .Sh SEE ALSO
713: .Xr mandoc 1 ,
1.25 schwarze 714: .Xr mandoc_escape 3 ,
715: .Xr mandoc_malloc 3 ,
716: .Xr mchars_alloc 3 ,
1.1 kristaps 717: .Xr eqn 7 ,
718: .Xr man 7 ,
1.6 kristaps 719: .Xr mandoc_char 7 ,
1.1 kristaps 720: .Xr mdoc 7 ,
721: .Xr roff 7 ,
722: .Xr tbl 7
723: .Sh AUTHORS
724: The
725: .Nm
726: library was written by
1.19 schwarze 727: .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
CVSweb