1 /* $Id: mdoc.c,v 1.80 2009/06/15 10:36:01 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 "\\\"", "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", "Ap",
67 "Lp", "Lk", "Mt", "Brq",
69 "Bro", "Brc", "\%C", "Es",
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))
103 * Get the first (root) node of the parse tree.
105 const struct mdoc_node
*
106 mdoc_node(const struct mdoc
*m
)
109 return(MDOC_HALT
& m
->flags
? NULL
: m
->first
);
113 const struct mdoc_meta
*
114 mdoc_meta(const struct mdoc
*m
)
117 return(MDOC_HALT
& m
->flags
? NULL
: &m
->meta
);
122 mdoc_free1(struct mdoc
*mdoc
)
126 mdoc_node_freelist(mdoc
->first
);
127 if (mdoc
->meta
.title
)
128 free(mdoc
->meta
.title
);
132 free(mdoc
->meta
.name
);
134 free(mdoc
->meta
.arch
);
136 free(mdoc
->meta
.vol
);
141 mdoc_alloc1(struct mdoc
*mdoc
)
144 bzero(&mdoc
->meta
, sizeof(struct mdoc_meta
));
146 mdoc
->lastnamed
= mdoc
->lastsec
= 0;
147 mdoc
->last
= calloc(1, sizeof(struct mdoc_node
));
148 if (NULL
== mdoc
->last
)
151 mdoc
->first
= mdoc
->last
;
152 mdoc
->last
->type
= MDOC_ROOT
;
153 mdoc
->next
= MDOC_NEXT_CHILD
;
159 * Free up all resources contributed by a parse: the node tree,
160 * meta-data and so on. Then reallocate the root node for another
164 mdoc_reset(struct mdoc
*mdoc
)
168 return(mdoc_alloc1(mdoc
));
173 * Completely free up all resources.
176 mdoc_free(struct mdoc
*mdoc
)
181 mdoc_hash_free(mdoc
->htab
);
187 mdoc_alloc(void *data
, int pflags
, const struct mdoc_cb
*cb
)
191 if (NULL
== (p
= calloc(1, sizeof(struct mdoc
))))
194 (void)memcpy(&p
->cb
, cb
, sizeof(struct mdoc_cb
));
199 if (NULL
== (p
->htab
= mdoc_hash_alloc())) {
202 } else if (mdoc_alloc1(p
))
211 * Climb back up the parse tree, validating open scopes. Mostly calls
212 * through to macro_end in macro.c.
215 mdoc_endparse(struct mdoc
*m
)
218 if (MDOC_HALT
& m
->flags
)
220 else if (mdoc_macroend(m
))
222 m
->flags
|= MDOC_HALT
;
228 * Main parse routine. Parses a single line -- really just hands off to
229 * the macro or text parser.
232 mdoc_parseln(struct mdoc
*m
, int ln
, char *buf
)
235 /* If in error-mode, then we parse no more. */
237 if (MDOC_HALT
& m
->flags
)
240 return('.' == *buf
? parsemacro(m
, ln
, buf
) :
241 parsetext(m
, ln
, buf
));
246 mdoc_verr(struct mdoc
*mdoc
, int ln
, int pos
,
247 const char *fmt
, ...)
252 if (NULL
== mdoc
->cb
.mdoc_err
)
256 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
258 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, ln
, pos
, buf
));
263 mdoc_vwarn(struct mdoc
*mdoc
, int ln
, int pos
,
264 enum mdoc_warn type
, const char *fmt
, ...)
269 if (NULL
== mdoc
->cb
.mdoc_warn
)
273 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
275 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, ln
, pos
, type
, buf
));
280 mdoc_nerr(struct mdoc
*mdoc
, const struct mdoc_node
*node
, const char *fmt
, ...)
285 if (NULL
== mdoc
->cb
.mdoc_err
)
289 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
291 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, node
->line
, node
->pos
, buf
));
296 mdoc_warn(struct mdoc
*mdoc
, enum mdoc_warn type
, const char *fmt
, ...)
301 if (NULL
== mdoc
->cb
.mdoc_warn
)
305 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
307 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, mdoc
->last
->line
,
308 mdoc
->last
->pos
, type
, buf
));
313 mdoc_err(struct mdoc
*mdoc
, const char *fmt
, ...)
318 if (NULL
== mdoc
->cb
.mdoc_err
)
322 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
324 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, mdoc
->last
->line
,
325 mdoc
->last
->pos
, buf
));
330 mdoc_pwarn(struct mdoc
*mdoc
, int line
, int pos
, enum mdoc_warn type
,
331 const char *fmt
, ...)
336 if (NULL
== mdoc
->cb
.mdoc_warn
)
340 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
342 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, line
, pos
, type
, buf
));
346 mdoc_perr(struct mdoc
*mdoc
, int line
, int pos
, const char *fmt
, ...)
351 if (NULL
== mdoc
->cb
.mdoc_err
)
355 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
357 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, line
, pos
, buf
));
362 mdoc_macro(struct mdoc
*m
, int tok
,
363 int ln
, int pp
, int *pos
, char *buf
)
366 /* FIXME - these should happen during validation. */
368 if (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
&&
369 SEC_PROLOGUE
!= m
->lastnamed
)
370 return(perr(m
, ln
, pp
, EPROLBODY
));
372 if ( ! (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
) &&
373 SEC_PROLOGUE
== m
->lastnamed
)
374 return(perr(m
, ln
, pp
, EBODYPROL
));
376 if (1 != pp
&& ! (MDOC_CALLABLE
& mdoc_macros
[tok
].flags
))
377 return(perr(m
, ln
, pp
, ENOCALL
));
379 return((*mdoc_macros
[tok
].fp
)(m
, tok
, ln
, pp
, pos
, buf
));
384 perr(struct mdoc
*m
, int line
, int pos
, enum merr type
)
394 p
= "macro disallowed in document body";
397 p
= "macro disallowed in document prologue";
400 p
= "memory exhausted";
403 p
= "text disallowed in document prologue";
406 p
= "blank lines disallowed in non-literal contexts";
409 p
= "whitespace disallowed after delimiter";
413 return(mdoc_perr(m
, line
, pos
, p
));
418 node_append(struct mdoc
*mdoc
, struct mdoc_node
*p
)
423 assert(MDOC_ROOT
!= p
->type
);
425 switch (mdoc
->next
) {
426 case (MDOC_NEXT_SIBLING
):
427 mdoc
->last
->next
= p
;
428 p
->prev
= mdoc
->last
;
429 p
->parent
= mdoc
->last
->parent
;
431 case (MDOC_NEXT_CHILD
):
432 mdoc
->last
->child
= p
;
433 p
->parent
= mdoc
->last
;
440 if ( ! mdoc_valid_pre(mdoc
, p
))
442 if ( ! mdoc_action_pre(mdoc
, p
))
447 assert(MDOC_BLOCK
== p
->parent
->type
);
451 assert(MDOC_BLOCK
== p
->parent
->type
);
455 assert(MDOC_BLOCK
== p
->parent
->type
);
466 if ( ! mdoc_valid_post(mdoc
))
468 if ( ! mdoc_action_post(mdoc
))
479 static struct mdoc_node
*
480 node_alloc(struct mdoc
*mdoc
, int line
,
481 int pos
, int tok
, enum mdoc_type type
)
485 if (NULL
== (p
= calloc(1, sizeof(struct mdoc_node
)))) {
486 (void)verr(mdoc
, EMALLOC
);
490 p
->sec
= mdoc
->lastsec
;
494 if (MDOC_TEXT
!= (p
->type
= type
))
502 mdoc_tail_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
506 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_TAIL
);
509 return(node_append(mdoc
, p
));
514 mdoc_head_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
521 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_HEAD
);
524 return(node_append(mdoc
, p
));
529 mdoc_body_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
533 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BODY
);
536 return(node_append(mdoc
, p
));
541 mdoc_block_alloc(struct mdoc
*mdoc
, int line
, int pos
,
542 int tok
, struct mdoc_arg
*args
)
546 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BLOCK
);
552 return(node_append(mdoc
, p
));
557 mdoc_elem_alloc(struct mdoc
*mdoc
, int line
, int pos
,
558 int tok
, struct mdoc_arg
*args
)
562 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_ELEM
);
568 return(node_append(mdoc
, p
));
573 mdoc_word_alloc(struct mdoc
*mdoc
,
574 int line
, int pos
, const char *word
)
578 p
= node_alloc(mdoc
, line
, pos
, -1, MDOC_TEXT
);
581 if (NULL
== (p
->string
= strdup(word
))) {
582 (void)verr(mdoc
, EMALLOC
);
585 return(node_append(mdoc
, p
));
590 mdoc_node_free(struct mdoc_node
*p
)
596 mdoc_argv_free(p
->args
);
602 mdoc_node_freelist(struct mdoc_node
*p
)
606 mdoc_node_freelist(p
->child
);
608 mdoc_node_freelist(p
->next
);
615 * Parse free-form text, that is, a line that does not begin with the
619 parsetext(struct mdoc
*m
, int line
, char *buf
)
622 if (SEC_PROLOGUE
== m
->lastnamed
)
623 return(perr(m
, line
, 0, ETEXTPROL
));
625 if (0 == buf
[0] && ! (MDOC_LITERAL
& m
->flags
))
626 return(perr(m
, line
, 0, ENOBLANK
));
628 if ( ! mdoc_word_alloc(m
, line
, 0, buf
))
631 m
->next
= MDOC_NEXT_SIBLING
;
637 macrowarn(struct mdoc
*m
, int ln
, const char *buf
)
639 if ( ! (MDOC_IGN_MACRO
& m
->pflags
))
640 return(mdoc_perr(m
, ln
, 1,
641 "unknown macro: %s%s",
642 buf
, strlen(buf
) > 3 ? "..." : ""));
643 return(mdoc_pwarn(m
, ln
, 1, WARN_SYNTAX
,
644 "unknown macro: %s%s",
645 buf
, strlen(buf
) > 3 ? "..." : ""));
651 * Parse a macro line, that is, a line beginning with the control
655 parsemacro(struct mdoc
*m
, int ln
, char *buf
)
660 /* Comments and empties are quickly ignored. */
667 while (buf
[i
] && ' ' == buf
[i
])
671 return(perr(m
, ln
, 1, ESPACE
));
674 if (buf
[1] && '\\' == buf
[1])
675 if (buf
[2] && '\"' == buf
[2])
678 /* Copy the first word into a nil-terminated buffer. */
680 for (i
= 1; i
< 5; i
++) {
681 if (0 == (mac
[i
- 1] = buf
[i
]))
683 else if (' ' == buf
[i
])
689 if (i
== 5 || i
<= 2) {
690 if ( ! macrowarn(m
, ln
, mac
))
695 if (MDOC_MAX
== (c
= mdoc_hash_find(m
->htab
, mac
))) {
696 if ( ! macrowarn(m
, ln
, mac
))
701 /* The macro is sane. Jump to the next word. */
703 while (buf
[i
] && ' ' == buf
[i
])
706 /* Begin recursive parse sequence. */
708 if ( ! mdoc_macro(m
, c
, ln
, 1, &i
, buf
))
713 err
: /* Error out. */
715 m
->flags
|= MDOC_HALT
;