]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
1 /* $Id: mdoc.c,v 1.88 2009/07/06 13:04:52 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_macronames
[MDOC_MAX
] = {
27 "Ap", "Dd", "Dt", "Os",
28 "Sh", "Ss", "Pp", "D1",
29 "Dl", "Bd", "Ed", "Bl",
30 "El", "It", "Ad", "An",
31 "Ar", "Cd", "Cm", "Dv",
32 "Er", "Ev", "Ex", "Fa",
33 "Fd", "Fl", "Fn", "Ft",
34 "Ic", "In", "Li", "Nd",
35 "Nm", "Op", "Ot", "Pa",
36 "Rv", "St", "Va", "Vt",
38 "Xr", "\%A", "\%B", "\%D",
40 "\%I", "\%J", "\%N", "\%O",
42 "\%P", "\%R", "\%T", "\%V",
43 "Ac", "Ao", "Aq", "At",
44 "Bc", "Bf", "Bo", "Bq",
45 "Bsx", "Bx", "Db", "Dc",
46 "Do", "Dq", "Ec", "Ef",
47 "Em", "Eo", "Fx", "Ms",
48 "No", "Ns", "Nx", "Ox",
49 "Pc", "Pf", "Po", "Pq",
50 "Qc", "Ql", "Qo", "Qq",
51 "Re", "Rs", "Sc", "So",
52 "Sq", "Sm", "Sx", "Sy",
53 "Tn", "Ux", "Xc", "Xo",
54 "Fo", "Fc", "Oo", "Oc",
55 "Bk", "Ek", "Bt", "Hf",
56 "Fr", "Ud", "Lb", "Lp",
57 "Lk", "Mt", "Brq", "Bro",
59 "Brc", "\%C", "Es", "En",
64 const char *const __mdoc_argnames
[MDOC_ARG_MAX
] = {
65 "split", "nosplit", "ragged",
66 "unfilled", "literal", "file",
67 "offset", "bullet", "dash",
68 "hyphen", "item", "enum",
69 "tag", "diag", "hang",
70 "ohang", "inset", "column",
71 "width", "compact", "std",
72 "filled", "words", "emphasis",
76 const char * const *mdoc_macronames
= __mdoc_macronames
;
77 const char * const *mdoc_argnames
= __mdoc_argnames
;
79 static void mdoc_free1(struct mdoc
*);
80 static int mdoc_alloc1(struct mdoc
*);
81 static struct mdoc_node
*node_alloc(struct mdoc
*, int, int,
83 static int node_append(struct mdoc
*,
85 static int parsetext(struct mdoc
*, int, char *);
86 static int parsemacro(struct mdoc
*, int, char *);
87 static int macrowarn(struct mdoc
*, int, const char *);
90 const struct mdoc_node
*
91 mdoc_node(const struct mdoc
*m
)
94 return(MDOC_HALT
& m
->flags
? NULL
: m
->first
);
98 const struct mdoc_meta
*
99 mdoc_meta(const struct mdoc
*m
)
102 return(MDOC_HALT
& m
->flags
? NULL
: &m
->meta
);
107 * Frees volatile resources (parse tree, meta-data, fields).
110 mdoc_free1(struct mdoc
*mdoc
)
114 mdoc_node_freelist(mdoc
->first
);
115 if (mdoc
->meta
.title
)
116 free(mdoc
->meta
.title
);
120 free(mdoc
->meta
.name
);
122 free(mdoc
->meta
.arch
);
124 free(mdoc
->meta
.vol
);
129 * Allocate all volatile resources (parse tree, meta-data, fields).
132 mdoc_alloc1(struct mdoc
*mdoc
)
135 bzero(&mdoc
->meta
, sizeof(struct mdoc_meta
));
137 mdoc
->lastnamed
= mdoc
->lastsec
= SEC_NONE
;
138 mdoc
->last
= calloc(1, sizeof(struct mdoc_node
));
139 if (NULL
== mdoc
->last
)
142 mdoc
->first
= mdoc
->last
;
143 mdoc
->last
->type
= MDOC_ROOT
;
144 mdoc
->next
= MDOC_NEXT_CHILD
;
150 * Free up volatile resources (see mdoc_free1()) then re-initialises the
151 * data with mdoc_alloc1(). After invocation, parse data has been reset
152 * and the parser is ready for re-invocation on a new tree; however,
153 * cross-parse non-volatile data is kept intact.
156 mdoc_reset(struct mdoc
*mdoc
)
160 return(mdoc_alloc1(mdoc
));
165 * Completely free up all volatile and non-volatile parse resources.
166 * After invocation, the pointer is no longer usable.
169 mdoc_free(struct mdoc
*mdoc
)
174 mdoc_hash_free(mdoc
->htab
);
180 * Allocate volatile and non-volatile parse resources.
183 mdoc_alloc(void *data
, int pflags
, const struct mdoc_cb
*cb
)
187 if (NULL
== (p
= calloc(1, sizeof(struct mdoc
))))
190 (void)memcpy(&p
->cb
, cb
, sizeof(struct mdoc_cb
));
195 if (NULL
== (p
->htab
= mdoc_hash_alloc())) {
198 } else if (mdoc_alloc1(p
))
207 * Climb back up the parse tree, validating open scopes. Mostly calls
208 * through to macro_end() in macro.c.
211 mdoc_endparse(struct mdoc
*m
)
214 if (MDOC_HALT
& m
->flags
)
216 else if (mdoc_macroend(m
))
218 m
->flags
|= MDOC_HALT
;
224 * Main parse routine. Parses a single line -- really just hands off to
225 * the macro (parsemacro()) or text parser (parsetext()).
228 mdoc_parseln(struct mdoc
*m
, int ln
, char *buf
)
231 if (MDOC_HALT
& m
->flags
)
234 return('.' == *buf
? parsemacro(m
, ln
, buf
) :
235 parsetext(m
, ln
, buf
));
240 mdoc_verr(struct mdoc
*mdoc
, int ln
, int pos
,
241 const char *fmt
, ...)
246 if (NULL
== mdoc
->cb
.mdoc_err
)
250 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
253 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, ln
, pos
, buf
));
258 mdoc_vwarn(struct mdoc
*mdoc
, int ln
, int pos
, const char *fmt
, ...)
263 if (NULL
== mdoc
->cb
.mdoc_warn
)
267 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
270 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, ln
, pos
, buf
));
275 mdoc_err(struct mdoc
*m
, int line
, int pos
, int iserr
, enum merr type
)
286 p
= "macro disallowed in document body";
289 p
= "macro disallowed in document prologue";
292 p
= "memory exhausted";
295 p
= "text disallowed in document prologue";
298 p
= "blank lines disallowed in non-literal contexts";
301 p
= "whitespace disallowed after delimiter";
304 p
= "text argument too long";
307 p
= "invalid escape sequence";
310 p
= "invalid character";
313 p
= "displays may not be nested";
316 p
= "expected boolean value";
319 p
= "argument repeated";
322 p
= "multiple display types specified";
325 p
= "multiple list types specified";
328 p
= "missing list type";
331 p
= "missing display type";
334 p
= "the NAME section must come first";
337 p
= "expected line arguments";
340 p
= "document has no prologue";
343 p
= "document has no data";
346 p
= "column syntax style mismatch";
349 p
= "expected valid AT&T symbol";
352 p
= "default name not yet set";
355 p
= "superfluous width argument";
358 p
= "missing width argument";
361 p
= "document section in wrong manual section";
364 p
= "document section out of conventional order";
367 p
= "document section repeated";
370 p
= "unknown standard";
373 p
= "NAME section contents incomplete/badly-ordered";
376 p
= "suggested no multi-line arguments";
379 p
= "suggested multi-line arguments";
382 p
= "suggested no line arguments";
385 p
= "prologue macros out-of-order";
388 p
= "prologue macros repeated";
391 p
= "argument value suggested";
394 p
= "invalid font mode";
397 p
= "inappropriate manual section";
400 p
= "inappropriate document section";
403 p
= "unterminated quoted parameter";
406 p
= "unexpected quoted parameter";
409 p
= "argument-like parameter";
412 p
= "last list column is empty";
415 p
= "trailing whitespace";
418 p
= "bad number format";
424 p
= "malformed date syntax";
427 p
= "explicit scope still open on exit";
430 p
= "unterminated quotation";
433 p
= "closure has no prior context";
436 p
= "unexpect line arguments";
439 p
= "ignoring empty element";
442 p
= "crufty end-of-line scope violation";
445 p
= "macro-like parameter";
448 p
= "macro marked obsolete";
455 return(mdoc_verr(m
, line
, pos
, p
));
457 return(mdoc_vwarn(m
, line
, pos
, p
));
462 mdoc_macro(struct mdoc
*m
, int tok
,
463 int ln
, int pp
, int *pos
, char *buf
)
466 if (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
&&
467 MDOC_PBODY
& m
->flags
)
468 return(mdoc_perr(m
, ln
, pp
, EPROLBODY
));
469 if ( ! (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
) &&
470 ! (MDOC_PBODY
& m
->flags
))
471 return(mdoc_perr(m
, ln
, pp
, EBODYPROL
));
473 if (1 != pp
&& ! (MDOC_CALLABLE
& mdoc_macros
[tok
].flags
))
474 return(mdoc_perr(m
, ln
, pp
, ENOCALL
));
476 return((*mdoc_macros
[tok
].fp
)(m
, tok
, ln
, pp
, pos
, buf
));
481 node_append(struct mdoc
*mdoc
, struct mdoc_node
*p
)
486 assert(MDOC_ROOT
!= p
->type
);
488 switch (mdoc
->next
) {
489 case (MDOC_NEXT_SIBLING
):
490 mdoc
->last
->next
= p
;
491 p
->prev
= mdoc
->last
;
492 p
->parent
= mdoc
->last
->parent
;
494 case (MDOC_NEXT_CHILD
):
495 mdoc
->last
->child
= p
;
496 p
->parent
= mdoc
->last
;
505 if ( ! mdoc_valid_pre(mdoc
, p
))
507 if ( ! mdoc_action_pre(mdoc
, p
))
512 assert(MDOC_BLOCK
== p
->parent
->type
);
516 assert(MDOC_BLOCK
== p
->parent
->type
);
520 assert(MDOC_BLOCK
== p
->parent
->type
);
531 if ( ! mdoc_valid_post(mdoc
))
533 if ( ! mdoc_action_post(mdoc
))
544 static struct mdoc_node
*
545 node_alloc(struct mdoc
*mdoc
, int line
,
546 int pos
, int tok
, enum mdoc_type type
)
550 if (NULL
== (p
= calloc(1, sizeof(struct mdoc_node
)))) {
551 (void)mdoc_nerr(mdoc
, mdoc
->last
, EMALLOC
);
555 p
->sec
= mdoc
->lastsec
;
559 if (MDOC_TEXT
!= (p
->type
= type
))
567 mdoc_tail_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
571 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_TAIL
);
574 return(node_append(mdoc
, p
));
579 mdoc_head_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
586 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_HEAD
);
589 return(node_append(mdoc
, p
));
594 mdoc_body_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
598 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BODY
);
601 return(node_append(mdoc
, p
));
606 mdoc_block_alloc(struct mdoc
*mdoc
, int line
, int pos
,
607 int tok
, struct mdoc_arg
*args
)
611 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_BLOCK
);
617 return(node_append(mdoc
, p
));
622 mdoc_elem_alloc(struct mdoc
*mdoc
, int line
, int pos
,
623 int tok
, struct mdoc_arg
*args
)
627 p
= node_alloc(mdoc
, line
, pos
, tok
, MDOC_ELEM
);
633 return(node_append(mdoc
, p
));
638 mdoc_word_alloc(struct mdoc
*mdoc
,
639 int line
, int pos
, const char *word
)
643 p
= node_alloc(mdoc
, line
, pos
, -1, MDOC_TEXT
);
646 if (NULL
== (p
->string
= strdup(word
))) {
647 (void)mdoc_nerr(mdoc
, mdoc
->last
, EMALLOC
);
651 return(node_append(mdoc
, p
));
656 mdoc_node_free(struct mdoc_node
*p
)
664 mdoc_argv_free(p
->args
);
670 mdoc_node_freelist(struct mdoc_node
*p
)
674 mdoc_node_freelist(p
->child
);
676 mdoc_node_freelist(p
->next
);
678 assert(0 == p
->nchild
);
684 * Parse free-form text, that is, a line that does not begin with the
688 parsetext(struct mdoc
*m
, int line
, char *buf
)
691 if (SEC_NONE
== m
->lastnamed
)
692 return(mdoc_perr(m
, line
, 0, ETEXTPROL
));
694 if (0 == buf
[0] && ! (MDOC_LITERAL
& m
->flags
))
695 return(mdoc_perr(m
, line
, 0, ENOBLANK
));
697 if ( ! mdoc_word_alloc(m
, line
, 0, buf
))
700 m
->next
= MDOC_NEXT_SIBLING
;
706 macrowarn(struct mdoc
*m
, int ln
, const char *buf
)
708 if ( ! (MDOC_IGN_MACRO
& m
->pflags
))
709 return(mdoc_verr(m
, ln
, 1,
710 "unknown macro: %s%s",
711 buf
, strlen(buf
) > 3 ? "..." : ""));
712 return(mdoc_vwarn(m
, ln
, 1, "unknown macro: %s%s",
713 buf
, strlen(buf
) > 3 ? "..." : ""));
718 * Parse a macro line, that is, a line beginning with the control
722 parsemacro(struct mdoc
*m
, int ln
, char *buf
)
727 /* Empty lines are ignored. */
734 while (buf
[i
] && ' ' == buf
[i
])
738 return(mdoc_perr(m
, ln
, 1, ESPACE
));
741 /* Copy the first word into a nil-terminated buffer. */
743 for (i
= 1; i
< 5; i
++) {
744 if (0 == (mac
[i
- 1] = buf
[i
]))
746 else if (' ' == buf
[i
])
752 if (i
== 5 || i
<= 2) {
753 if ( ! macrowarn(m
, ln
, mac
))
758 if (MDOC_MAX
== (c
= mdoc_hash_find(m
->htab
, mac
))) {
759 if ( ! macrowarn(m
, ln
, mac
))
764 /* The macro is sane. Jump to the next word. */
766 while (buf
[i
] && ' ' == buf
[i
])
769 /* Begin recursive parse sequence. */
771 if ( ! mdoc_macro(m
, c
, ln
, 1, &i
, buf
))
776 err
: /* Error out. */
778 m
->flags
|= MDOC_HALT
;