Annotation of mandoc/mandoc.3, Revision 1.20
1.20 ! schwarze 1: .\" $Id: mandoc.3,v 1.19 2013/07/13 19:41:16 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.20 ! schwarze 18: .Dd $Mdocdate: July 13 2013 $
1.1 kristaps 19: .Dt MANDOC 3
20: .Os
21: .Sh NAME
22: .Nm mandoc ,
1.3 kristaps 23: .Nm mandoc_escape ,
1.1 kristaps 24: .Nm man_meta ,
1.14 kristaps 25: .Nm man_mparse ,
1.1 kristaps 26: .Nm man_node ,
1.6 kristaps 27: .Nm mchars_alloc ,
28: .Nm mchars_free ,
29: .Nm mchars_num2char ,
1.7 kristaps 30: .Nm mchars_num2uc ,
1.6 kristaps 31: .Nm mchars_spec2cp ,
32: .Nm mchars_spec2str ,
1.1 kristaps 33: .Nm mdoc_meta ,
34: .Nm mdoc_node ,
35: .Nm mparse_alloc ,
36: .Nm mparse_free ,
1.14 kristaps 37: .Nm mparse_getkeep ,
38: .Nm mparse_keep ,
1.1 kristaps 39: .Nm mparse_readfd ,
40: .Nm mparse_reset ,
1.2 kristaps 41: .Nm mparse_result ,
42: .Nm mparse_strerror ,
43: .Nm mparse_strlevel
1.1 kristaps 44: .Nd mandoc macro compiler library
1.8 kristaps 45: .Sh LIBRARY
46: .Lb mandoc
1.1 kristaps 47: .Sh SYNOPSIS
48: .In man.h
49: .In mdoc.h
50: .In mandoc.h
1.3 kristaps 51: .Ft "enum mandoc_esc"
52: .Fo mandoc_escape
1.15 kristaps 53: .Fa "const char **end"
54: .Fa "const char **start"
55: .Fa "int *sz"
1.3 kristaps 56: .Fc
1.1 kristaps 57: .Ft "const struct man_meta *"
58: .Fo man_meta
59: .Fa "const struct man *man"
60: .Fc
1.14 kristaps 61: .Ft "const struct mparse *"
62: .Fo man_mparse
63: .Fa "const struct man *man"
64: .Fc
1.1 kristaps 65: .Ft "const struct man_node *"
66: .Fo man_node
67: .Fa "const struct man *man"
68: .Fc
1.6 kristaps 69: .Ft "struct mchars *"
1.20 ! schwarze 70: .Fn mchars_alloc "void"
1.6 kristaps 71: .Ft void
72: .Fn mchars_free "struct mchars *p"
73: .Ft char
74: .Fn mchars_num2char "const char *cp" "size_t sz"
1.7 kristaps 75: .Ft int
76: .Fn mchars_num2uc "const char *cp" "size_t sz"
1.6 kristaps 77: .Ft "const char *"
78: .Fo mchars_spec2str
1.16 kristaps 79: .Fa "const struct mchars *p"
1.6 kristaps 80: .Fa "const char *cp"
81: .Fa "size_t sz"
82: .Fa "size_t *rsz"
83: .Fc
84: .Ft int
85: .Fo mchars_spec2cp
1.16 kristaps 86: .Fa "const struct mchars *p"
1.6 kristaps 87: .Fa "const char *cp"
88: .Fa "size_t sz"
89: .Fc
1.1 kristaps 90: .Ft "const struct mdoc_meta *"
91: .Fo mdoc_meta
92: .Fa "const struct mdoc *mdoc"
93: .Fc
94: .Ft "const struct mdoc_node *"
95: .Fo mdoc_node
96: .Fa "const struct mdoc *mdoc"
97: .Fc
98: .Ft void
99: .Fo mparse_alloc
100: .Fa "enum mparset type"
101: .Fa "enum mandoclevel wlevel"
102: .Fa "mandocmsg msg"
103: .Fa "void *msgarg"
104: .Fc
105: .Ft void
106: .Fo mparse_free
107: .Fa "struct mparse *parse"
108: .Fc
1.14 kristaps 109: .Ft void
110: .Fo mparse_getkeep
111: .Fa "const struct mparse *parse"
112: .Fc
113: .Ft void
114: .Fo mparse_keep
115: .Fa "struct mparse *parse"
116: .Fc
1.1 kristaps 117: .Ft "enum mandoclevel"
118: .Fo mparse_readfd
119: .Fa "struct mparse *parse"
120: .Fa "int fd"
121: .Fa "const char *fname"
122: .Fc
123: .Ft void
124: .Fo mparse_reset
125: .Fa "struct mparse *parse"
126: .Fc
127: .Ft void
128: .Fo mparse_result
129: .Fa "struct mparse *parse"
130: .Fa "struct mdoc **mdoc"
131: .Fa "struct man **man"
1.2 kristaps 132: .Fc
133: .Ft "const char *"
134: .Fo mparse_strerror
135: .Fa "enum mandocerr"
136: .Fc
137: .Ft "const char *"
138: .Fo mparse_strlevel
139: .Fa "enum mandoclevel"
1.1 kristaps 140: .Fc
141: .Vt extern const char * const * man_macronames;
142: .Vt extern const char * const * mdoc_argnames;
143: .Vt extern const char * const * mdoc_macronames;
1.4 kristaps 144: .Fd "#define ASCII_NBRSP"
145: .Fd "#define ASCII_HYPH"
1.1 kristaps 146: .Sh DESCRIPTION
147: The
148: .Nm mandoc
149: library parses a
150: .Ux
151: manual into an abstract syntax tree (AST).
152: .Ux
153: manuals are composed of
154: .Xr mdoc 7
155: or
156: .Xr man 7 ,
157: and may be mixed with
158: .Xr roff 7 ,
159: .Xr tbl 7 ,
160: and
161: .Xr eqn 7
162: invocations.
163: .Pp
164: The following describes a general parse sequence:
165: .Bl -enum
166: .It
167: initiate a parsing sequence with
168: .Fn mparse_alloc ;
169: .It
170: parse files or file descriptors with
171: .Fn mparse_readfd ;
172: .It
173: retrieve a parsed syntax tree, if the parse was successful, with
174: .Fn mparse_result ;
175: .It
176: iterate over parse nodes with
177: .Fn mdoc_node
178: or
179: .Fn man_node ;
180: .It
181: free all allocated memory with
182: .Fn mparse_free ,
183: or invoke
184: .Fn mparse_reset
185: and parse new files.
1.3 kristaps 186: .El
1.6 kristaps 187: .Pp
188: The
189: .Nm
190: library also contains routines for translating character strings into glyphs
191: .Pq see Fn mchars_alloc
192: and parsing escape sequences from strings
193: .Pq see Fn mandoc_escape .
1.3 kristaps 194: .Sh REFERENCE
195: This section documents the functions, types, and variables available
196: via
197: .In mandoc.h .
198: .Ss Types
199: .Bl -ohang
200: .It Vt "enum mandoc_esc"
1.11 kristaps 201: An escape sequence classification.
1.3 kristaps 202: .It Vt "enum mandocerr"
1.11 kristaps 203: A fatal error, error, or warning message during parsing.
1.3 kristaps 204: .It Vt "enum mandoclevel"
1.11 kristaps 205: A classification of an
206: .Vt "enum mandoclevel"
207: as regards system operation.
1.6 kristaps 208: .It Vt "struct mchars"
209: An opaque pointer to an object allowing for translation between
210: character strings and glyphs.
211: See
212: .Fn mchars_alloc .
1.3 kristaps 213: .It Vt "enum mparset"
1.11 kristaps 214: The type of parser when reading input.
215: This should usually be
1.12 kristaps 216: .Dv MPARSE_AUTO
1.11 kristaps 217: for auto-detection.
1.3 kristaps 218: .It Vt "struct mparse"
1.11 kristaps 219: An opaque pointer to a running parse sequence.
220: Created with
221: .Fn mparse_alloc
222: and freed with
223: .Fn mparse_free .
224: This may be used across parsed input if
225: .Fn mparse_reset
226: is called between parses.
1.3 kristaps 227: .It Vt "mandocmsg"
1.11 kristaps 228: A prototype for a function to handle fatal error, error, and warning
229: messages emitted by the parser.
1.3 kristaps 230: .El
231: .Ss Functions
232: .Bl -ohang
233: .It Fn mandoc_escape
1.4 kristaps 234: Scan an escape sequence, i.e., a character string beginning with
235: .Sq \e .
1.17 joerg 236: Pass a pointer to the character after the
237: .Sq \e
238: as
1.4 kristaps 239: .Va end ;
240: it will be set to the supremum of the parsed escape sequence unless
1.12 kristaps 241: returning
242: .Dv ESCAPE_ERROR ,
243: in which case the string is bogus and should be
1.4 kristaps 244: thrown away.
1.12 kristaps 245: If not
246: .Dv ESCAPE_ERROR
247: or
248: .Dv ESCAPE_IGNORE ,
1.4 kristaps 249: .Va start
250: is set to the first relevant character of the substring (font, glyph,
251: whatever) of length
252: .Va sz .
253: Both
254: .Va start
255: and
256: .Va sz
1.12 kristaps 257: may be
258: .Dv NULL .
1.18 schwarze 259: Declared in
260: .In mandoc.h ,
261: implemented in
262: .Pa mandoc.c .
1.3 kristaps 263: .It Fn man_meta
1.4 kristaps 264: Obtain the meta-data of a successful parse.
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.14 kristaps 271: .It Fn man_mparse
272: Get the parser used for the current output.
1.18 schwarze 273: Declared in
274: .In man.h ,
275: implemented in
276: .Pa man.c .
1.3 kristaps 277: .It Fn man_node
1.4 kristaps 278: Obtain the root node of a successful parse.
279: This may only be used on a pointer returned by
280: .Fn mparse_result .
1.18 schwarze 281: Declared in
282: .In man.h ,
283: implemented in
284: .Pa man.c .
1.6 kristaps 285: .It Fn mchars_alloc
286: Allocate an
287: .Vt "struct mchars *"
288: object for translating special characters into glyphs.
289: See
290: .Xr mandoc_char 7
291: for an overview of special characters.
292: The object must be freed with
293: .Fn mchars_free .
1.18 schwarze 294: Declared in
295: .In mandoc.h ,
296: implemented in
297: .Pa chars.c .
1.6 kristaps 298: .It Fn mchars_free
299: Free an object created with
300: .Fn mchars_alloc .
1.18 schwarze 301: Declared in
302: .In mandoc.h ,
303: implemented in
304: .Pa chars.c .
1.6 kristaps 305: .It Fn mchars_num2char
1.7 kristaps 306: Convert a character index (e.g., the \eN\(aq\(aq escape) into a
307: printable ASCII character.
308: Returns \e0 (the nil character) if the input sequence is malformed.
1.18 schwarze 309: Declared in
310: .In mandoc.h ,
311: implemented in
312: .Pa chars.c .
1.7 kristaps 313: .It Fn mchars_num2uc
314: Convert a hexadecimal character index (e.g., the \e[uNNNN] escape) into
315: a Unicode codepoint.
1.6 kristaps 316: Returns \e0 (the nil character) if the input sequence is malformed.
1.18 schwarze 317: Declared in
318: .In mandoc.h ,
319: implemented in
320: .Pa chars.c .
1.6 kristaps 321: .It Fn mchars_spec2cp
322: Convert a special character into a valid Unicode codepoint.
1.10 kristaps 323: Returns \-1 on failure or a non-zero Unicode codepoint on success.
1.18 schwarze 324: Declared in
325: .In mandoc.h ,
326: implemented in
327: .Pa chars.c .
1.6 kristaps 328: .It Fn mchars_spec2str
329: Convert a special character into an ASCII string.
1.12 kristaps 330: Returns
331: .Dv NULL
332: on failure.
1.18 schwarze 333: Declared in
334: .In mandoc.h ,
335: implemented in
336: .Pa chars.c .
1.3 kristaps 337: .It Fn mdoc_meta
1.4 kristaps 338: Obtain the meta-data of a successful parse.
339: This may only be used on a pointer returned by
340: .Fn mparse_result .
1.18 schwarze 341: Declared in
342: .In mdoc.h ,
343: implemented in
344: .Pa mdoc.c .
1.3 kristaps 345: .It Fn mdoc_node
1.4 kristaps 346: Obtain the root node of a successful parse.
347: This may only be used on a pointer returned by
348: .Fn mparse_result .
1.18 schwarze 349: Declared in
350: .In mdoc.h ,
351: implemented in
352: .Pa mdoc.c .
1.3 kristaps 353: .It Fn mparse_alloc
1.4 kristaps 354: Allocate a parser.
355: The same parser may be used for multiple files so long as
356: .Fn mparse_reset
357: is called between parses.
358: .Fn mparse_free
359: must be called to free the memory allocated by this function.
1.18 schwarze 360: Declared in
361: .In mandoc.h ,
362: implemented in
363: .Pa read.c .
1.3 kristaps 364: .It Fn mparse_free
1.4 kristaps 365: Free all memory allocated by
366: .Fn mparse_alloc .
1.18 schwarze 367: Declared in
368: .In mandoc.h ,
369: implemented in
370: .Pa read.c .
1.14 kristaps 371: .It Fn mparse_getkeep
372: Acquire the keep buffer.
373: Must follow a call of
374: .Fn mparse_keep .
1.18 schwarze 375: Declared in
376: .In mandoc.h ,
377: implemented in
378: .Pa read.c .
1.14 kristaps 379: .It Fn mparse_keep
380: Instruct the parser to retain a copy of its parsed input.
381: This can be acquired with subsequent
382: .Fn mparse_getkeep
383: calls.
1.18 schwarze 384: Declared in
385: .In mandoc.h ,
386: implemented in
387: .Pa read.c .
1.3 kristaps 388: .It Fn mparse_readfd
1.4 kristaps 389: Parse a file or file descriptor.
390: If
391: .Va fd
392: is -1,
393: .Va fname
394: is opened for reading.
395: Otherwise,
396: .Va fname
397: is assumed to be the name associated with
398: .Va fd .
399: This may be called multiple times with different parameters; however,
400: .Fn mparse_reset
401: should be invoked between parses.
1.18 schwarze 402: Declared in
403: .In mandoc.h ,
404: implemented in
405: .Pa read.c .
1.3 kristaps 406: .It Fn mparse_reset
1.4 kristaps 407: Reset a parser so that
408: .Fn mparse_readfd
409: may be used again.
1.18 schwarze 410: Declared in
411: .In mandoc.h ,
412: implemented in
413: .Pa read.c .
1.3 kristaps 414: .It Fn mparse_result
1.4 kristaps 415: Obtain the result of a parse.
416: Only successful parses
417: .Po
418: i.e., those where
419: .Fn mparse_readfd
420: returned less than MANDOCLEVEL_FATAL
421: .Pc
422: should invoke this function, in which case one of the two pointers will
423: be filled in.
1.18 schwarze 424: Declared in
425: .In mandoc.h ,
426: implemented in
427: .Pa read.c .
1.3 kristaps 428: .It Fn mparse_strerror
1.4 kristaps 429: Return a statically-allocated string representation of an error code.
1.18 schwarze 430: Declared in
431: .In mandoc.h ,
432: implemented in
433: .Pa read.c .
1.3 kristaps 434: .It Fn mparse_strlevel
1.4 kristaps 435: Return a statically-allocated string representation of a level code.
1.18 schwarze 436: Declared in
437: .In mandoc.h ,
438: implemented in
439: .Pa read.c .
1.3 kristaps 440: .El
441: .Ss Variables
442: .Bl -ohang
443: .It Va man_macronames
1.4 kristaps 444: The string representation of a man macro as indexed by
445: .Vt "enum mant" .
1.3 kristaps 446: .It Va mdoc_argnames
1.4 kristaps 447: The string representation of a mdoc macro argument as indexed by
448: .Vt "enum mdocargt" .
1.3 kristaps 449: .It Va mdoc_macronames
1.4 kristaps 450: The string representation of a mdoc macro as indexed by
451: .Vt "enum mdoct" .
1.1 kristaps 452: .El
453: .Sh IMPLEMENTATION NOTES
454: This section consists of structural documentation for
455: .Xr mdoc 7
456: and
457: .Xr man 7
1.11 kristaps 458: syntax trees and strings.
459: .Ss Man and Mdoc Strings
460: Strings may be extracted from mdoc and man meta-data, or from text
461: nodes (MDOC_TEXT and MAN_TEXT, respectively).
462: These strings have special non-printing formatting cues embedded in the
463: text itself, as well as
464: .Xr roff 7
465: escapes preserved from input.
466: Implementing systems will need to handle both situations to produce
467: human-readable text.
468: In general, strings may be assumed to consist of 7-bit ASCII characters.
469: .Pp
470: The following non-printing characters may be embedded in text strings:
471: .Bl -tag -width Ds
472: .It Dv ASCII_NBRSP
473: A non-breaking space character.
474: .It Dv ASCII_HYPH
475: A soft hyphen.
476: .El
477: .Pp
478: Escape characters are also passed verbatim into text strings.
479: An escape character is a sequence of characters beginning with the
480: backslash
481: .Pq Sq \e .
482: To construct human-readable text, these should be intercepted with
483: .Fn mandoc_escape
484: and converted with one of
485: .Fn mchars_num2char ,
486: .Fn mchars_spec2str ,
487: and so on.
1.1 kristaps 488: .Ss Man Abstract Syntax Tree
489: This AST is governed by the ontological rules dictated in
490: .Xr man 7
491: and derives its terminology accordingly.
492: .Pp
493: The AST is composed of
494: .Vt struct man_node
495: nodes with element, root and text types as declared by the
496: .Va type
497: field.
498: Each node also provides its parse point (the
499: .Va line ,
500: .Va sec ,
501: and
502: .Va pos
503: fields), its position in the tree (the
504: .Va parent ,
505: .Va child ,
506: .Va next
507: and
508: .Va prev
509: fields) and some type-specific data.
510: .Pp
511: The tree itself is arranged according to the following normal form,
512: where capitalised non-terminals represent nodes.
513: .Pp
514: .Bl -tag -width "ELEMENTXX" -compact
515: .It ROOT
516: \(<- mnode+
517: .It mnode
518: \(<- ELEMENT | TEXT | BLOCK
519: .It BLOCK
520: \(<- HEAD BODY
521: .It HEAD
522: \(<- mnode*
523: .It BODY
524: \(<- mnode*
525: .It ELEMENT
526: \(<- ELEMENT | TEXT*
527: .It TEXT
1.11 kristaps 528: \(<- [[:ascii:]]*
1.1 kristaps 529: .El
530: .Pp
531: The only elements capable of nesting other elements are those with
532: next-lint scope as documented in
533: .Xr man 7 .
534: .Ss Mdoc Abstract Syntax Tree
535: This AST is governed by the ontological
536: rules dictated in
537: .Xr mdoc 7
538: and derives its terminology accordingly.
539: .Qq In-line
540: elements described in
541: .Xr mdoc 7
542: are described simply as
543: .Qq elements .
544: .Pp
545: The AST is composed of
546: .Vt struct mdoc_node
547: nodes with block, head, body, element, root and text types as declared
548: by the
549: .Va type
550: field.
551: Each node also provides its parse point (the
552: .Va line ,
553: .Va sec ,
554: and
555: .Va pos
556: fields), its position in the tree (the
557: .Va parent ,
558: .Va child ,
559: .Va nchild ,
560: .Va next
561: and
562: .Va prev
563: fields) and some type-specific data, in particular, for nodes generated
564: from macros, the generating macro in the
565: .Va tok
566: field.
567: .Pp
568: The tree itself is arranged according to the following normal form,
569: where capitalised non-terminals represent nodes.
570: .Pp
571: .Bl -tag -width "ELEMENTXX" -compact
572: .It ROOT
573: \(<- mnode+
574: .It mnode
575: \(<- BLOCK | ELEMENT | TEXT
576: .It BLOCK
577: \(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]]
578: .It ELEMENT
579: \(<- TEXT*
580: .It HEAD
581: \(<- mnode*
582: .It BODY
583: \(<- mnode* [ENDBODY mnode*]
584: .It TAIL
585: \(<- mnode*
586: .It TEXT
1.11 kristaps 587: \(<- [[:ascii:]]*
1.1 kristaps 588: .El
589: .Pp
590: Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of
591: the BLOCK production: these refer to punctuation marks.
592: Furthermore, although a TEXT node will generally have a non-zero-length
593: string, in the specific case of
594: .Sq \&.Bd \-literal ,
595: an empty line will produce a zero-length string.
596: Multiple body parts are only found in invocations of
597: .Sq \&Bl \-column ,
598: where a new body introduces a new phrase.
599: .Pp
600: The
601: .Xr mdoc 7
1.5 kristaps 602: syntax tree accommodates for broken block structures as well.
1.1 kristaps 603: The ENDBODY node is available to end the formatting associated
604: with a given block before the physical end of that block.
605: It has a non-null
606: .Va end
607: field, is of the BODY
608: .Va type ,
609: has the same
610: .Va tok
611: as the BLOCK it is ending, and has a
612: .Va pending
613: field pointing to that BLOCK's BODY node.
614: It is an indirect child of that BODY node
615: and has no children of its own.
616: .Pp
617: An ENDBODY node is generated when a block ends while one of its child
618: blocks is still open, like in the following example:
619: .Bd -literal -offset indent
620: \&.Ao ao
621: \&.Bo bo ac
622: \&.Ac bc
623: \&.Bc end
624: .Ed
625: .Pp
626: This example results in the following block structure:
627: .Bd -literal -offset indent
628: BLOCK Ao
629: HEAD Ao
630: BODY Ao
631: TEXT ao
632: BLOCK Bo, pending -> Ao
633: HEAD Bo
634: BODY Bo
635: TEXT bo
636: TEXT ac
637: ENDBODY Ao, pending -> Ao
638: TEXT bc
639: TEXT end
640: .Ed
641: .Pp
642: Here, the formatting of the
643: .Sq \&Ao
644: block extends from TEXT ao to TEXT ac,
645: while the formatting of the
646: .Sq \&Bo
647: block extends from TEXT bo to TEXT bc.
648: It renders as follows in
649: .Fl T Ns Cm ascii
650: mode:
651: .Pp
652: .Dl <ao [bo ac> bc] end
653: .Pp
654: Support for badly-nested blocks is only provided for backward
655: compatibility with some older
656: .Xr mdoc 7
657: implementations.
658: Using badly-nested blocks is
659: .Em strongly discouraged ;
660: for example, the
661: .Fl T Ns Cm html
662: and
663: .Fl T Ns Cm xhtml
664: front-ends to
665: .Xr mandoc 1
666: are unable to render them in any meaningful way.
667: Furthermore, behaviour when encountering badly-nested blocks is not
668: consistent across troff implementations, especially when using multiple
669: levels of badly-nested blocks.
670: .Sh SEE ALSO
671: .Xr mandoc 1 ,
672: .Xr eqn 7 ,
673: .Xr man 7 ,
1.6 kristaps 674: .Xr mandoc_char 7 ,
1.1 kristaps 675: .Xr mdoc 7 ,
676: .Xr roff 7 ,
677: .Xr tbl 7
678: .Sh AUTHORS
679: The
680: .Nm
681: library was written by
1.19 schwarze 682: .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
CVSweb