]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
1 /* $Id: mdoc.c,v 1.69 2009/03/21 09:42:07 kristaps Exp $ */
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
30 * Main caller in the libmdoc library. This begins the parsing routine,
31 * handles allocation of data, and so forth. Most of the "work" is done
32 * in macro.c, validate.c and action.c.
35 static struct mdoc_node
*mdoc_node_alloc(const struct mdoc
*);
36 static int mdoc_node_append(struct mdoc
*,
39 static int parsetext(struct mdoc
*, int, char *);
40 static int parsemacro(struct mdoc
*, int, char *);
41 static int macrowarn(struct mdoc
*, int, const char *);
44 const char *const __mdoc_macronames
[MDOC_MAX
] = {
45 "\\\"", "Dd", "Dt", "Os",
46 "Sh", "Ss", "Pp", "D1",
47 "Dl", "Bd", "Ed", "Bl",
48 "El", "It", "Ad", "An",
49 "Ar", "Cd", "Cm", "Dv",
50 "Er", "Ev", "Ex", "Fa",
51 "Fd", "Fl", "Fn", "Ft",
52 "Ic", "In", "Li", "Nd",
53 "Nm", "Op", "Ot", "Pa",
54 "Rv", "St", "Va", "Vt",
56 "Xr", "\%A", "\%B", "\%D",
58 "\%I", "\%J", "\%N", "\%O",
60 "\%P", "\%R", "\%T", "\%V",
61 "Ac", "Ao", "Aq", "At",
62 "Bc", "Bf", "Bo", "Bq",
63 "Bsx", "Bx", "Db", "Dc",
64 "Do", "Dq", "Ec", "Ef",
65 "Em", "Eo", "Fx", "Ms",
66 "No", "Ns", "Nx", "Ox",
67 "Pc", "Pf", "Po", "Pq",
68 "Qc", "Ql", "Qo", "Qq",
69 "Re", "Rs", "Sc", "So",
70 "Sq", "Sm", "Sx", "Sy",
71 "Tn", "Ux", "Xc", "Xo",
72 "Fo", "Fc", "Oo", "Oc",
73 "Bk", "Ek", "Bt", "Hf",
74 "Fr", "Ud", "Lb", "Ap",
75 "Lp", "Lk", "Mt", "Brq",
77 "Bro", "Brc", "\%C", "Es",
82 const char *const __mdoc_argnames
[MDOC_ARG_MAX
] = {
83 "split", "nosplit", "ragged",
84 "unfilled", "literal", "file",
85 "offset", "bullet", "dash",
86 "hyphen", "item", "enum",
87 "tag", "diag", "hang",
88 "ohang", "inset", "column",
89 "width", "compact", "std",
90 "filled", "words", "emphasis",
94 const char * const *mdoc_macronames
= __mdoc_macronames
;
95 const char * const *mdoc_argnames
= __mdoc_argnames
;
99 * Get the first (root) node of the parse tree.
101 const struct mdoc_node
*
102 mdoc_node(const struct mdoc
*mdoc
)
105 if (MDOC_HALT
& mdoc
->flags
)
108 assert(MDOC_ROOT
== mdoc
->first
->type
);
113 const struct mdoc_meta
*
114 mdoc_meta(const struct mdoc
*mdoc
)
117 if (MDOC_HALT
& mdoc
->flags
)
124 * Free up all resources contributed by a parse: the node tree, meta-data and
125 * so on. Then reallocate the root node for another parse.
128 mdoc_reset(struct mdoc
*mdoc
)
132 mdoc_node_freelist(mdoc
->first
);
133 if (mdoc
->meta
.title
)
134 free(mdoc
->meta
.title
);
138 free(mdoc
->meta
.name
);
140 free(mdoc
->meta
.arch
);
142 free(mdoc
->meta
.vol
);
144 bzero(&mdoc
->meta
, sizeof(struct mdoc_meta
));
146 mdoc
->lastnamed
= mdoc
->lastsec
= 0;
148 mdoc
->first
= mdoc
->last
=
149 xcalloc(1, sizeof(struct mdoc_node
));
150 mdoc
->last
->type
= MDOC_ROOT
;
151 mdoc
->next
= MDOC_NEXT_CHILD
;
156 * Completely free up all resources.
159 mdoc_free(struct mdoc
*mdoc
)
163 mdoc_node_freelist(mdoc
->first
);
164 if (mdoc
->meta
.title
)
165 free(mdoc
->meta
.title
);
169 free(mdoc
->meta
.name
);
171 free(mdoc
->meta
.arch
);
173 free(mdoc
->meta
.vol
);
176 mdoc_tokhash_free(mdoc
->htab
);
183 mdoc_alloc(void *data
, int pflags
, const struct mdoc_cb
*cb
)
187 p
= xcalloc(1, sizeof(struct mdoc
));
191 (void)memcpy(&p
->cb
, cb
, sizeof(struct mdoc_cb
));
194 xcalloc(1, sizeof(struct mdoc_node
));
195 p
->last
->type
= MDOC_ROOT
;
197 p
->next
= MDOC_NEXT_CHILD
;
198 p
->htab
= mdoc_tokhash_alloc();
204 * Climb back up the parse tree, validating open scopes. Mostly calls
205 * through to macro_end in macro.c.
208 mdoc_endparse(struct mdoc
*mdoc
)
211 if (MDOC_HALT
& mdoc
->flags
)
213 if (NULL
== mdoc
->first
)
217 if ( ! macro_end(mdoc
)) {
218 mdoc
->flags
|= MDOC_HALT
;
226 * Main parse routine. Parses a single line -- really just hands off to
227 * the macro or text parser.
230 mdoc_parseln(struct mdoc
*m
, int ln
, char *buf
)
233 /* If in error-mode, then we parse no more. */
235 if (MDOC_HALT
& m
->flags
)
238 return('.' == *buf
? parsemacro(m
, ln
, buf
) :
239 parsetext(m
, ln
, buf
));
244 mdoc_vmsg(struct mdoc
*mdoc
, int ln
, int pos
, const char *fmt
, ...)
249 if (NULL
== mdoc
->cb
.mdoc_msg
)
253 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
255 (*mdoc
->cb
.mdoc_msg
)(mdoc
->data
, ln
, pos
, buf
);
260 mdoc_verr(struct mdoc
*mdoc
, int ln
, int pos
,
261 const char *fmt
, ...)
266 if (NULL
== mdoc
->cb
.mdoc_err
)
270 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
272 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, ln
, pos
, buf
));
277 mdoc_vwarn(struct mdoc
*mdoc
, int ln
, int pos
,
278 enum mdoc_warn type
, const char *fmt
, ...)
283 if (NULL
== mdoc
->cb
.mdoc_warn
)
287 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
289 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, ln
, pos
, type
, buf
));
294 mdoc_macro(struct mdoc
*m
, int tok
,
295 int ln
, int pp
, int *pos
, char *buf
)
298 /* FIXME - these should happen during validation. */
300 if (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
&&
301 SEC_PROLOGUE
!= m
->lastnamed
)
302 return(mdoc_perr(m
, ln
, pp
,
303 "disallowed in document body"));
305 if ( ! (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
) &&
306 SEC_PROLOGUE
== m
->lastnamed
)
307 return(mdoc_perr(m
, ln
, pp
,
308 "disallowed in prologue"));
310 if (1 != pp
&& ! (MDOC_CALLABLE
& mdoc_macros
[tok
].flags
))
311 return(mdoc_perr(m
, ln
, pp
, "%s not callable",
312 mdoc_macronames
[tok
]));
314 return((*mdoc_macros
[tok
].fp
)(m
, tok
, ln
, pp
, pos
, buf
));
319 mdoc_node_append(struct mdoc
*mdoc
, struct mdoc_node
*p
)
324 assert(MDOC_ROOT
!= p
->type
);
326 switch (mdoc
->next
) {
327 case (MDOC_NEXT_SIBLING
):
328 mdoc
->last
->next
= p
;
329 p
->prev
= mdoc
->last
;
330 p
->parent
= mdoc
->last
->parent
;
332 case (MDOC_NEXT_CHILD
):
333 mdoc
->last
->child
= p
;
334 p
->parent
= mdoc
->last
;
341 if ( ! mdoc_valid_pre(mdoc
, p
))
343 if ( ! mdoc_action_pre(mdoc
, p
))
348 assert(MDOC_BLOCK
== p
->parent
->type
);
352 assert(MDOC_BLOCK
== p
->parent
->type
);
356 assert(MDOC_BLOCK
== p
->parent
->type
);
368 static struct mdoc_node
*
369 mdoc_node_alloc(const struct mdoc
*mdoc
)
373 p
= xcalloc(1, sizeof(struct mdoc_node
));
374 p
->sec
= mdoc
->lastsec
;
381 mdoc_tail_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
388 p
= mdoc_node_alloc(mdoc
);
395 return(mdoc_node_append(mdoc
, p
));
400 mdoc_head_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
407 p
= mdoc_node_alloc(mdoc
);
414 return(mdoc_node_append(mdoc
, p
));
419 mdoc_body_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
426 p
= mdoc_node_alloc(mdoc
);
433 return(mdoc_node_append(mdoc
, p
));
438 mdoc_root_alloc(struct mdoc
*mdoc
)
442 p
= mdoc_node_alloc(mdoc
);
446 return(mdoc_node_append(mdoc
, p
));
451 mdoc_block_alloc(struct mdoc
*mdoc
, int line
, int pos
,
452 int tok
, struct mdoc_arg
*args
)
456 p
= mdoc_node_alloc(mdoc
);
460 p
->type
= MDOC_BLOCK
;
467 return(mdoc_node_append(mdoc
, p
));
472 mdoc_elem_alloc(struct mdoc
*mdoc
, int line
, int pos
,
473 int tok
, struct mdoc_arg
*args
)
477 p
= mdoc_node_alloc(mdoc
);
488 return(mdoc_node_append(mdoc
, p
));
493 mdoc_word_alloc(struct mdoc
*mdoc
,
494 int line
, int pos
, const char *word
)
498 p
= mdoc_node_alloc(mdoc
);
503 p
->string
= xstrdup(word
);
505 return(mdoc_node_append(mdoc
, p
));
510 mdoc_node_free(struct mdoc_node
*p
)
516 mdoc_argv_free(p
->args
);
522 mdoc_node_freelist(struct mdoc_node
*p
)
526 mdoc_node_freelist(p
->child
);
528 mdoc_node_freelist(p
->next
);
535 * Parse free-form text, that is, a line that does not begin with the
539 parsetext(struct mdoc
*m
, int line
, char *buf
)
542 if (SEC_PROLOGUE
== m
->lastnamed
)
543 return(mdoc_perr(m
, line
, 0,
544 "text disallowed in prologue"));
546 if (0 == buf
[0] && ! (MDOC_LITERAL
& m
->flags
))
547 return(mdoc_perr(m
, line
, 0,
548 "blank lines only in literal context"));
550 if ( ! mdoc_word_alloc(m
, line
, 0, buf
))
553 m
->next
= MDOC_NEXT_SIBLING
;
559 macrowarn(struct mdoc
*m
, int ln
, const char *buf
)
561 if ( ! (MDOC_IGN_MACRO
& m
->pflags
))
562 return(mdoc_perr(m
, ln
, 1, "unknown macro: %s%s",
563 buf
, strlen(buf
) > 3 ? "..." : ""));
564 return(mdoc_pwarn(m
, ln
, 1, WARN_SYNTAX
,
565 "unknown macro: %s%s",
566 buf
, strlen(buf
) > 3 ? "..." : ""));
572 * Parse a macro line, that is, a line beginning with the control
576 parsemacro(struct mdoc
*m
, int ln
, char *buf
)
581 /* Comments and empties are quickly ignored. */
588 while (buf
[i
] && ' ' == buf
[i
])
592 return(mdoc_perr(m
, ln
, 1, "invalid syntax"));
595 if (buf
[1] && '\\' == buf
[1])
596 if (buf
[2] && '\"' == buf
[2])
599 /* Copy the first word into a nil-terminated buffer. */
601 for (i
= 1; i
< 5; i
++) {
602 if (0 == (mac
[i
- 1] = buf
[i
]))
604 else if (' ' == buf
[i
])
610 if (i
== 5 || i
<= 2) {
611 if ( ! macrowarn(m
, ln
, mac
))
616 if (MDOC_MAX
== (c
= mdoc_tokhash_find(m
->htab
, mac
))) {
617 if ( ! macrowarn(m
, ln
, mac
))
622 /* The macro is sane. Jump to the next word. */
624 while (buf
[i
] && ' ' == buf
[i
])
627 /* Begin recursive parse sequence. */
629 if ( ! mdoc_macro(m
, c
, ln
, 1, &i
, buf
))
633 * If we're in literal mode, then add a newline to the end of
634 * macro lines. Our frontends will interpret this correctly
635 * (it's documented in mdoc.3).
640 err
: /* Error out. */
642 m
->flags
|= MDOC_HALT
;