]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
1 /* $Id: mdoc.c,v 1.89 2009/07/07 09:29:15 kristaps Exp $ */
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 const char *const __mdoc_merrnames
[MERRMAX
] = {
27 "trailing whitespace", /* ETAILWS */
28 "empty last list column", /* ECOLEMPTY */
29 "argument-like parameter", /* EARGVPARM */
30 "unexpected quoted parameter", /* EQUOTPARM */
31 "unterminated quoted parameter", /* EQUOTTERM */
32 "system: malloc error", /* EMALLOC */
33 "argument parameter suggested", /* EARGVAL */
34 "macro not callable", /* ENOCALL */
35 "macro disallowed in prologue", /* EBODYPROL */
36 "macro disallowed in body", /* EPROLBODY */
37 "text disallowed in prologue", /* ETEXTPROL */
38 "blank line disallowed", /* ENOBLANK */
39 "text parameter too long", /* ETOOLONG */
40 "invalid escape sequence", /* EESCAPE */
41 "invalid character", /* EPRINT */
42 "document has no body", /* ENODAT */
43 "document has no prologue", /* ENOPROLOGUE */
44 "expected line arguments", /* ELINE */
45 "invalid AT&T argument", /* EATT */
46 "default name not yet set", /* ENAME */
47 "missing list type", /* ELISTTYPE */
48 "missing display type", /* EDISPTYPE */
49 "too many display types", /* EMULTIDISP */
50 "too many list types", /* EMULTILIST */
51 "NAME section must be first", /* ESECNAME */
52 "badly-formed NAME section", /* ENAMESECINC */
53 "argument repeated", /* EARGREP */
54 "expected boolean parameter", /* EBOOL */
55 "inconsistent column syntax", /* ECOLMIS */
56 "nested display invalid", /* ENESTDISP */
57 "width argument missing", /* EMISSWIDTH */
58 "invalid section for this manual section", /* EWRONGMSEC */
59 "section out of conventional order", /* ESECOOO */
60 "section repeated", /* ESECREP */
61 "invalid standard argument", /* EBADSTAND */
62 "multi-line arguments discouraged", /* ENOMULTILINE */
63 "multi-line arguments suggested", /* EMULTILINE */
64 "line arguments discouraged", /* ENOLINE */
65 "prologue macro out of conventional order", /* EPROLOOO */
66 "prologue macro repeated", /* EPROLREP */
67 "invalid manual section", /* EBADMSEC */
68 "invalid section", /* EBADSEC */
69 "invalid font mode", /* EFONT */
70 "invalid date syntax", /* EBADDATE */
71 "invalid number format", /* ENUMFMT */
72 "superfluous width argument", /* ENOWIDTH */
73 "system: utsname error", /* EUTSNAME */
74 "obsolete macro", /* EOBS */
75 "macro-like parameter", /* EMACPARM */
76 "end-of-line scope violation", /* EIMPBRK */
77 "empty macro ignored", /* EIGNE */
78 "unclosed explicit scope", /* EOPEN */
79 "unterminated quoted phrase", /* EQUOTPHR */
80 "closure macro without prior context", /* ENOCTX */
81 "invalid whitespace after control character", /* ESPACE */
84 const char *const __mdoc_macronames
[MDOC_MAX
] = {
85 "Ap", "Dd", "Dt", "Os",
86 "Sh", "Ss", "Pp", "D1",
87 "Dl", "Bd", "Ed", "Bl",
88 "El", "It", "Ad", "An",
89 "Ar", "Cd", "Cm", "Dv",
90 "Er", "Ev", "Ex", "Fa",
91 "Fd", "Fl", "Fn", "Ft",
92 "Ic", "In", "Li", "Nd",
93 "Nm", "Op", "Ot", "Pa",
94 "Rv", "St", "Va", "Vt",
96 "Xr", "\%A", "\%B", "\%D",
98 "\%I", "\%J", "\%N", "\%O",
100 "\%P", "\%R", "\%T", "\%V",
101 "Ac", "Ao", "Aq", "At",
102 "Bc", "Bf", "Bo", "Bq",
103 "Bsx", "Bx", "Db", "Dc",
104 "Do", "Dq", "Ec", "Ef",
105 "Em", "Eo", "Fx", "Ms",
106 "No", "Ns", "Nx", "Ox",
107 "Pc", "Pf", "Po", "Pq",
108 "Qc", "Ql", "Qo", "Qq",
109 "Re", "Rs", "Sc", "So",
110 "Sq", "Sm", "Sx", "Sy",
111 "Tn", "Ux", "Xc", "Xo",
112 "Fo", "Fc", "Oo", "Oc",
113 "Bk", "Ek", "Bt", "Hf",
114 "Fr", "Ud", "Lb", "Lp",
115 "Lk", "Mt", "Brq", "Bro",
117 "Brc", "\%C", "Es", "En",
122 const char *const __mdoc_argnames
[MDOC_ARG_MAX
] = {
123 "split", "nosplit", "ragged",
124 "unfilled", "literal", "file",
125 "offset", "bullet", "dash",
126 "hyphen", "item", "enum",
127 "tag", "diag", "hang",
128 "ohang", "inset", "column",
129 "width", "compact", "std",
130 "filled", "words", "emphasis",
134 const char * const *mdoc_macronames
= __mdoc_macronames
;
135 const char * const *mdoc_argnames
= __mdoc_argnames
;
137 static void mdoc_free1(struct mdoc
*);
138 static int mdoc_alloc1(struct mdoc
*);
139 static struct mdoc_node
*node_alloc(struct mdoc
*, int, int,
140 int, enum mdoc_type
);
141 static int node_append(struct mdoc
*,
143 static int parsetext(struct mdoc
*, int, char *);
144 static int parsemacro(struct mdoc
*, int, char *);
145 static int macrowarn(struct mdoc
*, int, const char *);
148 const struct mdoc_node
*
149 mdoc_node(const struct mdoc
*m
)
152 return(MDOC_HALT
& m
->flags
? NULL
: m
->first
);
156 const struct mdoc_meta
*
157 mdoc_meta(const struct mdoc
*m
)
160 return(MDOC_HALT
& m
->flags
? NULL
: &m
->meta
);
165 * Frees volatile resources (parse tree, meta-data, fields).
168 mdoc_free1(struct mdoc
*mdoc
)
172 mdoc_node_freelist(mdoc
->first
);
173 if (mdoc
->meta
.title
)
174 free(mdoc
->meta
.title
);
178 free(mdoc
->meta
.name
);
180 free(mdoc
->meta
.arch
);
182 free(mdoc
->meta
.vol
);
187 * Allocate all volatile resources (parse tree, meta-data, fields).
190 mdoc_alloc1(struct mdoc
*mdoc
)
193 bzero(&mdoc
->meta
, sizeof(struct mdoc_meta
));
195 mdoc
->lastnamed
= mdoc
->lastsec
= SEC_NONE
;
196 mdoc
->last
= calloc(1, sizeof(struct mdoc_node
));
197 if (NULL
== mdoc
->last
)
200 mdoc
->first
= mdoc
->last
;
201 mdoc
->last
->type
= MDOC_ROOT
;
202 mdoc
->next
= MDOC_NEXT_CHILD
;
208 * Free up volatile resources (see mdoc_free1()) then re-initialises the
209 * data with mdoc_alloc1(). After invocation, parse data has been reset
210 * and the parser is ready for re-invocation on a new tree; however,
211 * cross-parse non-volatile data is kept intact.
214 mdoc_reset(struct mdoc
*mdoc
)
218 return(mdoc_alloc1(mdoc
));
223 * Completely free up all volatile and non-volatile parse resources.
224 * After invocation, the pointer is no longer usable.
227 mdoc_free(struct mdoc
*mdoc
)
232 mdoc_hash_free(mdoc
->htab
);
238 * Allocate volatile and non-volatile parse resources.
241 mdoc_alloc(void *data
, int pflags
, const struct mdoc_cb
*cb
)
245 if (NULL
== (p
= calloc(1, sizeof(struct mdoc
))))
248 (void)memcpy(&p
->cb
, cb
, sizeof(struct mdoc_cb
));
253 if (NULL
== (p
->htab
= mdoc_hash_alloc())) {
256 } else if (mdoc_alloc1(p
))
265 * Climb back up the parse tree, validating open scopes. Mostly calls
266 * through to macro_end() in macro.c.
269 mdoc_endparse(struct mdoc
*m
)
272 if (MDOC_HALT
& m
->flags
)
274 else if (mdoc_macroend(m
))
276 m
->flags
|= MDOC_HALT
;
282 * Main parse routine. Parses a single line -- really just hands off to
283 * the macro (parsemacro()) or text parser (parsetext()).
286 mdoc_parseln(struct mdoc
*m
, int ln
, char *buf
)
289 if (MDOC_HALT
& m
->flags
)
292 return('.' == *buf
? parsemacro(m
, ln
, buf
) :
293 parsetext(m
, ln
, buf
));
298 mdoc_verr(struct mdoc
*mdoc
, int ln
, int pos
,
299 const char *fmt
, ...)
304 if (NULL
== mdoc
->cb
.mdoc_err
)
308 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
311 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, ln
, pos
, buf
));
316 mdoc_vwarn(struct mdoc
*mdoc
, int ln
, int pos
, const char *fmt
, ...)
321 if (NULL
== mdoc
->cb
.mdoc_warn
)
325 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
328 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, ln
, pos
, buf
));
333 mdoc_err(struct mdoc
*m
, int line
, int pos
, int iserr
, enum merr type
)
337 p
= __mdoc_merrnames
[(int)type
];
341 return(mdoc_verr(m
, line
, pos
, p
));
343 return(mdoc_vwarn(m
, line
, pos
, p
));
348 mdoc_macro(struct mdoc
*m
, int tok
,
349 int ln
, int pp
, int *pos
, char *buf
)
352 if (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
&&
353 MDOC_PBODY
& m
->flags
)
354 return(mdoc_perr(m
, ln
, pp
, EPROLBODY
));
355 if ( ! (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
) &&
356 ! (MDOC_PBODY
& m
->flags
))
357 return(mdoc_perr(m
, ln
, pp
, EBODYPROL
));
359 if (1 != pp
&& ! (MDOC_CALLABLE
& mdoc_macros
[tok
].flags
))
360 return(mdoc_perr(m
, ln
, pp
, ENOCALL
));
362 return((*mdoc_macros
[tok
].fp
)(m
, tok
, ln
, pp
, pos
, buf
));
367 node_append(struct mdoc
*mdoc
, struct mdoc_node
*p
)
372 assert(MDOC_ROOT
!= p
->type
);
374 switch (mdoc
->next
) {
375 case (MDOC_NEXT_SIBLING
):
376 mdoc
->last
->next
= p
;
377 p
->prev
= mdoc
->last
;
378 p
->parent
= mdoc
->last
->parent
;
380 case (MDOC_NEXT_CHILD
):
381 mdoc
->last
->child
= p
;
382 p
->parent
= mdoc
->last
;
391 if ( ! mdoc_valid_pre(mdoc
, p
))
393 if ( ! mdoc_action_pre(mdoc
, p
))
398 assert(MDOC_BLOCK
== p
->parent
->type
);
402 assert(MDOC_BLOCK
== p
->parent
->type
);
406 assert(MDOC_BLOCK
== p
->parent
->type
);
417 if ( ! mdoc_valid_post(mdoc
))
419 if ( ! mdoc_action_post(mdoc
))
430 static struct mdoc_node
*
431 node_alloc(struct mdoc
*mdoc
, int line
,
432 int pos
, int tok
, enum mdoc_type type
)
436 if (NULL
== (p
= calloc(1, sizeof(struct mdoc_node
)))) {
437 (void)mdoc_nerr(mdoc
, mdoc
->last
, EMALLOC
);
441 p
->sec
= mdoc
->lastsec
;
445 if (MDOC_TEXT
!= (p
->type
= type
))
453 mdoc_tail_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
457 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_TAIL
);
460 return(node_append(mdoc
, p
));
465 mdoc_head_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
472 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_HEAD
);
475 return(node_append(mdoc
, p
));
480 mdoc_body_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
484 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BODY
);
487 return(node_append(mdoc
, p
));
492 mdoc_block_alloc(struct mdoc
*mdoc
, int line
, int pos
,
493 int tok
, struct mdoc_arg
*args
)
497 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BLOCK
);
503 return(node_append(mdoc
, p
));
508 mdoc_elem_alloc(struct mdoc
*mdoc
, int line
, int pos
,
509 int tok
, struct mdoc_arg
*args
)
513 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_ELEM
);
519 return(node_append(mdoc
, p
));
524 mdoc_word_alloc(struct mdoc
*mdoc
,
525 int line
, int pos
, const char *word
)
529 p
= node_alloc(mdoc
, line
, pos
, -1, MDOC_TEXT
);
532 if (NULL
== (p
->string
= strdup(word
))) {
533 (void)mdoc_nerr(mdoc
, mdoc
->last
, EMALLOC
);
537 return(node_append(mdoc
, p
));
542 mdoc_node_free(struct mdoc_node
*p
)
550 mdoc_argv_free(p
->args
);
556 mdoc_node_freelist(struct mdoc_node
*p
)
560 mdoc_node_freelist(p
->child
);
562 mdoc_node_freelist(p
->next
);
564 assert(0 == p
->nchild
);
570 * Parse free-form text, that is, a line that does not begin with the
574 parsetext(struct mdoc
*m
, int line
, char *buf
)
577 if (SEC_NONE
== m
->lastnamed
)
578 return(mdoc_perr(m
, line
, 0, ETEXTPROL
));
580 if (0 == buf
[0] && ! (MDOC_LITERAL
& m
->flags
))
581 return(mdoc_perr(m
, line
, 0, ENOBLANK
));
583 if ( ! mdoc_word_alloc(m
, line
, 0, buf
))
586 m
->next
= MDOC_NEXT_SIBLING
;
592 macrowarn(struct mdoc
*m
, int ln
, const char *buf
)
594 if ( ! (MDOC_IGN_MACRO
& m
->pflags
))
595 return(mdoc_verr(m
, ln
, 1,
596 "unknown macro: %s%s",
597 buf
, strlen(buf
) > 3 ? "..." : ""));
598 return(mdoc_vwarn(m
, ln
, 1, "unknown macro: %s%s",
599 buf
, strlen(buf
) > 3 ? "..." : ""));
604 * Parse a macro line, that is, a line beginning with the control
608 parsemacro(struct mdoc
*m
, int ln
, char *buf
)
613 /* Empty lines are ignored. */
620 while (buf
[i
] && ' ' == buf
[i
])
624 return(mdoc_perr(m
, ln
, 1, ESPACE
));
627 /* Copy the first word into a nil-terminated buffer. */
629 for (i
= 1; i
< 5; i
++) {
630 if (0 == (mac
[i
- 1] = buf
[i
]))
632 else if (' ' == buf
[i
])
638 if (i
== 5 || i
<= 2) {
639 if ( ! macrowarn(m
, ln
, mac
))
644 if (MDOC_MAX
== (c
= mdoc_hash_find(m
->htab
, mac
))) {
645 if ( ! macrowarn(m
, ln
, mac
))
650 /* The macro is sane. Jump to the next word. */
652 while (buf
[i
] && ' ' == buf
[i
])
655 /* Begin recursive parse sequence. */
657 if ( ! mdoc_macro(m
, c
, ln
, 1, &i
, buf
))
662 err
: /* Error out. */
664 m
->flags
|= MDOC_HALT
;