]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
1 /* $Id: mdoc.c,v 1.84 2009/06/17 07:59:47 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 const struct mdoc_node
*
101 mdoc_node(const struct mdoc
*m
)
104 return(MDOC_HALT
& m
->flags
? NULL
: m
->first
);
108 const struct mdoc_meta
*
109 mdoc_meta(const struct mdoc
*m
)
112 return(MDOC_HALT
& m
->flags
? NULL
: &m
->meta
);
117 mdoc_free1(struct mdoc
*mdoc
)
121 mdoc_node_freelist(mdoc
->first
);
122 if (mdoc
->meta
.title
)
123 free(mdoc
->meta
.title
);
127 free(mdoc
->meta
.name
);
129 free(mdoc
->meta
.arch
);
131 free(mdoc
->meta
.vol
);
136 mdoc_alloc1(struct mdoc
*mdoc
)
139 bzero(&mdoc
->meta
, sizeof(struct mdoc_meta
));
141 mdoc
->lastnamed
= mdoc
->lastsec
= 0;
142 mdoc
->last
= calloc(1, sizeof(struct mdoc_node
));
143 if (NULL
== mdoc
->last
)
146 mdoc
->first
= mdoc
->last
;
147 mdoc
->last
->type
= MDOC_ROOT
;
148 mdoc
->next
= MDOC_NEXT_CHILD
;
154 * Free up all resources contributed by a parse: the node tree,
155 * meta-data and so on. Then reallocate the root node for another
159 mdoc_reset(struct mdoc
*mdoc
)
163 return(mdoc_alloc1(mdoc
));
168 * Completely free up all resources.
171 mdoc_free(struct mdoc
*mdoc
)
176 mdoc_hash_free(mdoc
->htab
);
182 mdoc_alloc(void *data
, int pflags
, const struct mdoc_cb
*cb
)
186 if (NULL
== (p
= calloc(1, sizeof(struct mdoc
))))
189 (void)memcpy(&p
->cb
, cb
, sizeof(struct mdoc_cb
));
194 if (NULL
== (p
->htab
= mdoc_hash_alloc())) {
197 } else if (mdoc_alloc1(p
))
206 * Climb back up the parse tree, validating open scopes. Mostly calls
207 * through to macro_end in macro.c.
210 mdoc_endparse(struct mdoc
*m
)
213 if (MDOC_HALT
& m
->flags
)
215 else if (mdoc_macroend(m
))
217 m
->flags
|= MDOC_HALT
;
223 * Main parse routine. Parses a single line -- really just hands off to
224 * the macro or text parser.
227 mdoc_parseln(struct mdoc
*m
, int ln
, char *buf
)
230 if (MDOC_HALT
& m
->flags
)
233 return('.' == *buf
? parsemacro(m
, ln
, buf
) :
234 parsetext(m
, ln
, buf
));
239 mdoc_verr(struct mdoc
*mdoc
, int ln
, int pos
,
240 const char *fmt
, ...)
245 if (NULL
== mdoc
->cb
.mdoc_err
)
249 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
251 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, ln
, pos
, buf
));
256 mdoc_vwarn(struct mdoc
*mdoc
, int ln
, int pos
,
257 enum mdoc_warn type
, const char *fmt
, ...)
262 if (NULL
== mdoc
->cb
.mdoc_warn
)
266 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
268 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, ln
, pos
, type
, buf
));
273 mdoc_nerr(struct mdoc
*mdoc
, const struct mdoc_node
*node
,
274 const char *fmt
, ...)
279 if (NULL
== mdoc
->cb
.mdoc_err
)
283 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
285 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
,
286 node
->line
, node
->pos
, buf
));
291 mdoc_warn(struct mdoc
*mdoc
, enum mdoc_warn type
,
292 const char *fmt
, ...)
297 if (NULL
== mdoc
->cb
.mdoc_warn
)
301 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
303 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, mdoc
->last
->line
,
304 mdoc
->last
->pos
, type
, buf
));
309 mdoc_err(struct mdoc
*mdoc
, const char *fmt
, ...)
314 if (NULL
== mdoc
->cb
.mdoc_err
)
318 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
320 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, mdoc
->last
->line
,
321 mdoc
->last
->pos
, buf
));
326 mdoc_pwarn(struct mdoc
*mdoc
, int line
, int pos
, enum mdoc_warn type
,
327 const char *fmt
, ...)
332 if (NULL
== mdoc
->cb
.mdoc_warn
)
336 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
338 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
,
339 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)perr(mdoc
, (mdoc
)->last
->line
,
484 (mdoc
)->last
->pos
, EMALLOC
);
488 p
->sec
= mdoc
->lastsec
;
492 if (MDOC_TEXT
!= (p
->type
= type
))
500 mdoc_tail_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
504 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_TAIL
);
507 return(node_append(mdoc
, p
));
512 mdoc_head_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
519 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_HEAD
);
522 return(node_append(mdoc
, p
));
527 mdoc_body_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
531 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BODY
);
534 return(node_append(mdoc
, p
));
539 mdoc_block_alloc(struct mdoc
*mdoc
, int line
, int pos
,
540 int tok
, struct mdoc_arg
*args
)
544 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BLOCK
);
550 return(node_append(mdoc
, p
));
555 mdoc_elem_alloc(struct mdoc
*mdoc
, int line
, int pos
,
556 int tok
, struct mdoc_arg
*args
)
560 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_ELEM
);
566 return(node_append(mdoc
, p
));
571 mdoc_word_alloc(struct mdoc
*mdoc
,
572 int line
, int pos
, const char *word
)
576 p
= node_alloc(mdoc
, line
, pos
, -1, MDOC_TEXT
);
579 if (NULL
== (p
->string
= strdup(word
))) {
580 (void)perr(mdoc
, (mdoc
)->last
->line
,
581 (mdoc
)->last
->pos
, EMALLOC
);
584 return(node_append(mdoc
, p
));
589 mdoc_node_free(struct mdoc_node
*p
)
595 mdoc_argv_free(p
->args
);
601 mdoc_node_freelist(struct mdoc_node
*p
)
605 mdoc_node_freelist(p
->child
);
607 mdoc_node_freelist(p
->next
);
614 * Parse free-form text, that is, a line that does not begin with the
618 parsetext(struct mdoc
*m
, int line
, char *buf
)
621 if (SEC_PROLOGUE
== m
->lastnamed
)
622 return(perr(m
, line
, 0, ETEXTPROL
));
624 if (0 == buf
[0] && ! (MDOC_LITERAL
& m
->flags
))
625 return(perr(m
, line
, 0, ENOBLANK
));
627 if ( ! mdoc_word_alloc(m
, line
, 0, buf
))
630 m
->next
= MDOC_NEXT_SIBLING
;
636 macrowarn(struct mdoc
*m
, int ln
, const char *buf
)
638 if ( ! (MDOC_IGN_MACRO
& m
->pflags
))
639 return(mdoc_perr(m
, ln
, 1,
640 "unknown macro: %s%s",
641 buf
, strlen(buf
) > 3 ? "..." : ""));
642 return(mdoc_pwarn(m
, ln
, 1, WARN_SYNTAX
,
643 "unknown macro: %s%s",
644 buf
, strlen(buf
) > 3 ? "..." : ""));
649 * Parse a macro line, that is, a line beginning with the control
653 parsemacro(struct mdoc
*m
, int ln
, char *buf
)
658 /* Empty lines are ignored. */
665 while (buf
[i
] && ' ' == buf
[i
])
669 return(perr(m
, ln
, 1, ESPACE
));
672 /* Copy the first word into a nil-terminated buffer. */
674 for (i
= 1; i
< 5; i
++) {
675 if (0 == (mac
[i
- 1] = buf
[i
]))
677 else if (' ' == buf
[i
])
683 if (i
== 5 || i
<= 2) {
684 if ( ! macrowarn(m
, ln
, mac
))
689 if (MDOC_MAX
== (c
= mdoc_hash_find(m
->htab
, mac
))) {
690 if ( ! macrowarn(m
, ln
, mac
))
695 /* The macro is sane. Jump to the next word. */
697 while (buf
[i
] && ' ' == buf
[i
])
700 /* Begin recursive parse sequence. */
702 if ( ! mdoc_macro(m
, c
, ln
, 1, &i
, buf
))
707 err
: /* Error out. */
709 m
->flags
|= MDOC_HALT
;