]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
1 /* $Id: mdoc.c,v 1.83 2009/06/16 20:22:23 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.
36 const char *const __mdoc_macronames
[MDOC_MAX
] = {
37 "Ap", "Dd", "Dt", "Os",
38 "Sh", "Ss", "Pp", "D1",
39 "Dl", "Bd", "Ed", "Bl",
40 "El", "It", "Ad", "An",
41 "Ar", "Cd", "Cm", "Dv",
42 "Er", "Ev", "Ex", "Fa",
43 "Fd", "Fl", "Fn", "Ft",
44 "Ic", "In", "Li", "Nd",
45 "Nm", "Op", "Ot", "Pa",
46 "Rv", "St", "Va", "Vt",
48 "Xr", "\%A", "\%B", "\%D",
50 "\%I", "\%J", "\%N", "\%O",
52 "\%P", "\%R", "\%T", "\%V",
53 "Ac", "Ao", "Aq", "At",
54 "Bc", "Bf", "Bo", "Bq",
55 "Bsx", "Bx", "Db", "Dc",
56 "Do", "Dq", "Ec", "Ef",
57 "Em", "Eo", "Fx", "Ms",
58 "No", "Ns", "Nx", "Ox",
59 "Pc", "Pf", "Po", "Pq",
60 "Qc", "Ql", "Qo", "Qq",
61 "Re", "Rs", "Sc", "So",
62 "Sq", "Sm", "Sx", "Sy",
63 "Tn", "Ux", "Xc", "Xo",
64 "Fo", "Fc", "Oo", "Oc",
65 "Bk", "Ek", "Bt", "Hf",
66 "Fr", "Ud", "Lb", "Lp",
67 "Lk", "Mt", "Brq", "Bro",
69 "Brc", "\%C", "Es", "En",
74 const char *const __mdoc_argnames
[MDOC_ARG_MAX
] = {
75 "split", "nosplit", "ragged",
76 "unfilled", "literal", "file",
77 "offset", "bullet", "dash",
78 "hyphen", "item", "enum",
79 "tag", "diag", "hang",
80 "ohang", "inset", "column",
81 "width", "compact", "std",
82 "filled", "words", "emphasis",
86 const char * const *mdoc_macronames
= __mdoc_macronames
;
87 const char * const *mdoc_argnames
= __mdoc_argnames
;
89 static void mdoc_free1(struct mdoc
*);
90 static int mdoc_alloc1(struct mdoc
*);
91 static struct mdoc_node
*node_alloc(struct mdoc
*, int, int,
93 static int node_append(struct mdoc
*,
95 static int parsetext(struct mdoc
*, int, char *);
96 static int parsemacro(struct mdoc
*, int, char *);
97 static int macrowarn(struct mdoc
*, int, const char *);
98 static int perr(struct mdoc
*, int, int, enum merr
);
100 #define verr(m, t) perr((m), (m)->last->line, (m)->last->pos, (t))
102 const struct mdoc_node
*
103 mdoc_node(const struct mdoc
*m
)
106 return(MDOC_HALT
& m
->flags
? NULL
: m
->first
);
110 const struct mdoc_meta
*
111 mdoc_meta(const struct mdoc
*m
)
114 return(MDOC_HALT
& m
->flags
? NULL
: &m
->meta
);
119 mdoc_free1(struct mdoc
*mdoc
)
123 mdoc_node_freelist(mdoc
->first
);
124 if (mdoc
->meta
.title
)
125 free(mdoc
->meta
.title
);
129 free(mdoc
->meta
.name
);
131 free(mdoc
->meta
.arch
);
133 free(mdoc
->meta
.vol
);
138 mdoc_alloc1(struct mdoc
*mdoc
)
141 bzero(&mdoc
->meta
, sizeof(struct mdoc_meta
));
143 mdoc
->lastnamed
= mdoc
->lastsec
= 0;
144 mdoc
->last
= calloc(1, sizeof(struct mdoc_node
));
145 if (NULL
== mdoc
->last
)
148 mdoc
->first
= mdoc
->last
;
149 mdoc
->last
->type
= MDOC_ROOT
;
150 mdoc
->next
= MDOC_NEXT_CHILD
;
156 * Free up all resources contributed by a parse: the node tree,
157 * meta-data and so on. Then reallocate the root node for another
161 mdoc_reset(struct mdoc
*mdoc
)
165 return(mdoc_alloc1(mdoc
));
170 * Completely free up all resources.
173 mdoc_free(struct mdoc
*mdoc
)
178 mdoc_hash_free(mdoc
->htab
);
184 mdoc_alloc(void *data
, int pflags
, const struct mdoc_cb
*cb
)
188 if (NULL
== (p
= calloc(1, sizeof(struct mdoc
))))
191 (void)memcpy(&p
->cb
, cb
, sizeof(struct mdoc_cb
));
196 if (NULL
== (p
->htab
= mdoc_hash_alloc())) {
199 } else if (mdoc_alloc1(p
))
208 * Climb back up the parse tree, validating open scopes. Mostly calls
209 * through to macro_end in macro.c.
212 mdoc_endparse(struct mdoc
*m
)
215 if (MDOC_HALT
& m
->flags
)
217 else if (mdoc_macroend(m
))
219 m
->flags
|= MDOC_HALT
;
225 * Main parse routine. Parses a single line -- really just hands off to
226 * the macro or text parser.
229 mdoc_parseln(struct mdoc
*m
, int ln
, char *buf
)
232 /* If in error-mode, then we parse no more. */
234 if (MDOC_HALT
& m
->flags
)
237 return('.' == *buf
? parsemacro(m
, ln
, buf
) :
238 parsetext(m
, ln
, buf
));
243 mdoc_verr(struct mdoc
*mdoc
, int ln
, int pos
,
244 const char *fmt
, ...)
249 if (NULL
== mdoc
->cb
.mdoc_err
)
253 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
255 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, ln
, pos
, buf
));
260 mdoc_vwarn(struct mdoc
*mdoc
, int ln
, int pos
,
261 enum mdoc_warn type
, const char *fmt
, ...)
266 if (NULL
== mdoc
->cb
.mdoc_warn
)
270 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
272 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, ln
, pos
, type
, buf
));
277 mdoc_nerr(struct mdoc
*mdoc
, const struct mdoc_node
*node
, const char *fmt
, ...)
282 if (NULL
== mdoc
->cb
.mdoc_err
)
286 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
288 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, node
->line
, node
->pos
, buf
));
293 mdoc_warn(struct mdoc
*mdoc
, enum mdoc_warn type
, const char *fmt
, ...)
298 if (NULL
== mdoc
->cb
.mdoc_warn
)
302 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
304 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, mdoc
->last
->line
,
305 mdoc
->last
->pos
, type
, buf
));
310 mdoc_err(struct mdoc
*mdoc
, const char *fmt
, ...)
315 if (NULL
== mdoc
->cb
.mdoc_err
)
319 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
321 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, mdoc
->last
->line
,
322 mdoc
->last
->pos
, buf
));
327 mdoc_pwarn(struct mdoc
*mdoc
, int line
, int pos
, enum mdoc_warn type
,
328 const char *fmt
, ...)
333 if (NULL
== mdoc
->cb
.mdoc_warn
)
337 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
339 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, line
, pos
, type
, buf
));
343 mdoc_perr(struct mdoc
*mdoc
, int line
, int pos
, const char *fmt
, ...)
348 if (NULL
== mdoc
->cb
.mdoc_err
)
352 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
354 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, line
, pos
, buf
));
359 mdoc_macro(struct mdoc
*m
, int tok
,
360 int ln
, int pp
, int *pos
, char *buf
)
363 /* FIXME - these should happen during validation. */
365 if (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
&&
366 SEC_PROLOGUE
!= m
->lastnamed
)
367 return(perr(m
, ln
, pp
, EPROLBODY
));
369 if ( ! (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
) &&
370 SEC_PROLOGUE
== m
->lastnamed
)
371 return(perr(m
, ln
, pp
, EBODYPROL
));
373 if (1 != pp
&& ! (MDOC_CALLABLE
& mdoc_macros
[tok
].flags
))
374 return(perr(m
, ln
, pp
, ENOCALL
));
376 return((*mdoc_macros
[tok
].fp
)(m
, tok
, ln
, pp
, pos
, buf
));
381 perr(struct mdoc
*m
, int line
, int pos
, enum merr type
)
391 p
= "macro disallowed in document body";
394 p
= "macro disallowed in document prologue";
397 p
= "memory exhausted";
400 p
= "text disallowed in document prologue";
403 p
= "blank lines disallowed in non-literal contexts";
406 p
= "whitespace disallowed after delimiter";
410 return(mdoc_perr(m
, line
, pos
, p
));
415 node_append(struct mdoc
*mdoc
, struct mdoc_node
*p
)
420 assert(MDOC_ROOT
!= p
->type
);
422 switch (mdoc
->next
) {
423 case (MDOC_NEXT_SIBLING
):
424 mdoc
->last
->next
= p
;
425 p
->prev
= mdoc
->last
;
426 p
->parent
= mdoc
->last
->parent
;
428 case (MDOC_NEXT_CHILD
):
429 mdoc
->last
->child
= p
;
430 p
->parent
= mdoc
->last
;
437 if ( ! mdoc_valid_pre(mdoc
, p
))
439 if ( ! mdoc_action_pre(mdoc
, p
))
444 assert(MDOC_BLOCK
== p
->parent
->type
);
448 assert(MDOC_BLOCK
== p
->parent
->type
);
452 assert(MDOC_BLOCK
== p
->parent
->type
);
463 if ( ! mdoc_valid_post(mdoc
))
465 if ( ! mdoc_action_post(mdoc
))
476 static struct mdoc_node
*
477 node_alloc(struct mdoc
*mdoc
, int line
,
478 int pos
, int tok
, enum mdoc_type type
)
482 if (NULL
== (p
= calloc(1, sizeof(struct mdoc_node
)))) {
483 (void)verr(mdoc
, EMALLOC
);
487 p
->sec
= mdoc
->lastsec
;
491 if (MDOC_TEXT
!= (p
->type
= type
))
499 mdoc_tail_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
503 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_TAIL
);
506 return(node_append(mdoc
, p
));
511 mdoc_head_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
518 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_HEAD
);
521 return(node_append(mdoc
, p
));
526 mdoc_body_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
530 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BODY
);
533 return(node_append(mdoc
, p
));
538 mdoc_block_alloc(struct mdoc
*mdoc
, int line
, int pos
,
539 int tok
, struct mdoc_arg
*args
)
543 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BLOCK
);
549 return(node_append(mdoc
, p
));
554 mdoc_elem_alloc(struct mdoc
*mdoc
, int line
, int pos
,
555 int tok
, struct mdoc_arg
*args
)
559 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_ELEM
);
565 return(node_append(mdoc
, p
));
570 mdoc_word_alloc(struct mdoc
*mdoc
,
571 int line
, int pos
, const char *word
)
575 p
= node_alloc(mdoc
, line
, pos
, -1, MDOC_TEXT
);
578 if (NULL
== (p
->string
= strdup(word
))) {
579 (void)verr(mdoc
, EMALLOC
);
582 return(node_append(mdoc
, p
));
587 mdoc_node_free(struct mdoc_node
*p
)
593 mdoc_argv_free(p
->args
);
599 mdoc_node_freelist(struct mdoc_node
*p
)
603 mdoc_node_freelist(p
->child
);
605 mdoc_node_freelist(p
->next
);
612 * Parse free-form text, that is, a line that does not begin with the
616 parsetext(struct mdoc
*m
, int line
, char *buf
)
619 if (SEC_PROLOGUE
== m
->lastnamed
)
620 return(perr(m
, line
, 0, ETEXTPROL
));
622 if (0 == buf
[0] && ! (MDOC_LITERAL
& m
->flags
))
623 return(perr(m
, line
, 0, ENOBLANK
));
625 if ( ! mdoc_word_alloc(m
, line
, 0, buf
))
628 m
->next
= MDOC_NEXT_SIBLING
;
634 macrowarn(struct mdoc
*m
, int ln
, const char *buf
)
636 if ( ! (MDOC_IGN_MACRO
& m
->pflags
))
637 return(mdoc_perr(m
, ln
, 1,
638 "unknown macro: %s%s",
639 buf
, strlen(buf
) > 3 ? "..." : ""));
640 return(mdoc_pwarn(m
, ln
, 1, WARN_SYNTAX
,
641 "unknown macro: %s%s",
642 buf
, strlen(buf
) > 3 ? "..." : ""));
647 * Parse a macro line, that is, a line beginning with the control
651 parsemacro(struct mdoc
*m
, int ln
, char *buf
)
656 /* Empty lines are ignored. */
663 while (buf
[i
] && ' ' == buf
[i
])
667 return(perr(m
, ln
, 1, ESPACE
));
670 /* Copy the first word into a nil-terminated buffer. */
672 for (i
= 1; i
< 5; i
++) {
673 if (0 == (mac
[i
- 1] = buf
[i
]))
675 else if (' ' == buf
[i
])
681 if (i
== 5 || i
<= 2) {
682 if ( ! macrowarn(m
, ln
, mac
))
687 if (MDOC_MAX
== (c
= mdoc_hash_find(m
->htab
, mac
))) {
688 if ( ! macrowarn(m
, ln
, mac
))
693 /* The macro is sane. Jump to the next word. */
695 while (buf
[i
] && ' ' == buf
[i
])
698 /* Begin recursive parse sequence. */
700 if ( ! mdoc_macro(m
, c
, ln
, 1, &i
, buf
))
705 err
: /* Error out. */
707 m
->flags
|= MDOC_HALT
;