]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
ca3f5752a648092b916352875150daa8c2043bc9
1 /* $Id: mdoc.c,v 1.50 2009/03/02 17:14:46 kristaps Exp $ */
3 * Copyright (c) 2008 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
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 and validate.c.
35 static struct mdoc_arg
*argdup(size_t, const struct mdoc_arg
*);
36 static void argfree(size_t, struct mdoc_arg
*);
37 static void argcpy(struct mdoc_arg
*,
38 const struct mdoc_arg
*);
40 static struct mdoc_node
*mdoc_node_alloc(const struct mdoc
*);
41 static int mdoc_node_append(struct mdoc
*,
43 static void mdoc_elem_free(struct mdoc_elem
*);
44 static void mdoc_text_free(struct mdoc_text
*);
47 const char *const __mdoc_macronames
[MDOC_MAX
] = {
48 "\\\"", "Dd", "Dt", "Os",
49 "Sh", "Ss", "Pp", "D1",
50 "Dl", "Bd", "Ed", "Bl",
51 "El", "It", "Ad", "An",
52 "Ar", "Cd", "Cm", "Dv",
53 "Er", "Ev", "Ex", "Fa",
54 "Fd", "Fl", "Fn", "Ft",
55 "Ic", "In", "Li", "Nd",
56 "Nm", "Op", "Ot", "Pa",
57 "Rv", "St", "Va", "Vt",
59 "Xr", "\%A", "\%B", "\%D",
61 "\%I", "\%J", "\%N", "\%O",
63 "\%P", "\%R", "\%T", "\%V",
64 "Ac", "Ao", "Aq", "At",
65 "Bc", "Bf", "Bo", "Bq",
66 "Bsx", "Bx", "Db", "Dc",
67 "Do", "Dq", "Ec", "Ef",
68 "Em", "Eo", "Fx", "Ms",
69 "No", "Ns", "Nx", "Ox",
70 "Pc", "Pf", "Po", "Pq",
71 "Qc", "Ql", "Qo", "Qq",
72 "Re", "Rs", "Sc", "So",
73 "Sq", "Sm", "Sx", "Sy",
74 "Tn", "Ux", "Xc", "Xo",
75 "Fo", "Fc", "Oo", "Oc",
76 "Bk", "Ek", "Bt", "Hf",
80 const char *const __mdoc_argnames
[MDOC_ARG_MAX
] = {
81 "split", "nosplit", "ragged",
82 "unfilled", "literal", "file",
83 "offset", "bullet", "dash",
84 "hyphen", "item", "enum",
85 "tag", "diag", "hang",
86 "ohang", "inset", "column",
87 "width", "compact", "std",
88 "p1003.1-88", "p1003.1-90", "p1003.1-96",
89 "p1003.1-2001", "p1003.1-2004", "p1003.1",
90 "p1003.1b", "p1003.1b-93", "p1003.1c-95",
91 "p1003.1g-2000", "p1003.2-92", "p1387.2-95",
92 "p1003.2", "p1387.2", "isoC-90",
93 "isoC-amd1", "isoC-tcor1", "isoC-tcor2",
94 "isoC-99", "ansiC", "ansiC-89",
95 "ansiC-99", "ieee754", "iso8802-3",
96 "xpg3", "xpg4", "xpg4.2",
97 "xpg4.3", "xbd5", "xcu5",
98 "xsh5", "xns5", "xns5.2d2.0",
99 "xcurses4.2", "susv2", "susv3",
100 "svid4", "filled", "words",
101 "emphasis", "symbolic",
104 const char * const *mdoc_macronames
= __mdoc_macronames
;
105 const char * const *mdoc_argnames
= __mdoc_argnames
;
108 const struct mdoc_node
*
109 mdoc_node(const struct mdoc
*mdoc
)
116 const struct mdoc_meta
*
117 mdoc_meta(const struct mdoc
*mdoc
)
125 mdoc_free(struct mdoc
*mdoc
)
129 mdoc_node_freelist(mdoc
->first
);
131 mdoc_tokhash_free(mdoc
->htab
);
132 if (mdoc
->meta
.title
)
133 free(mdoc
->meta
.title
);
137 free(mdoc
->meta
.name
);
144 mdoc_alloc(void *data
, const struct mdoc_cb
*cb
)
148 p
= xcalloc(1, sizeof(struct mdoc
));
152 (void)memcpy(&p
->cb
, cb
, sizeof(struct mdoc_cb
));
154 p
->last
= xcalloc(1, sizeof(struct mdoc_node
));
155 p
->last
->type
= MDOC_ROOT
;
158 p
->next
= MDOC_NEXT_CHILD
;
159 p
->htab
= mdoc_tokhash_alloc();
166 mdoc_endparse(struct mdoc
*mdoc
)
169 if (MDOC_HALT
& mdoc
->flags
)
171 if (NULL
== mdoc
->first
)
175 if ( ! macro_end(mdoc
)) {
176 mdoc
->flags
|= MDOC_HALT
;
184 * Main line-parsing routine. If the line is a macro-line (started with
185 * a '.' control character), then pass along to the parser, which parses
186 * subsequent macros until the end of line. If normal text, simply
187 * append the entire line to the chain.
190 mdoc_parseln(struct mdoc
*mdoc
, int line
, char *buf
)
195 if (MDOC_HALT
& mdoc
->flags
)
202 * Free-form text. Not allowed in the prologue.
204 if (SEC_PROLOGUE
== mdoc
->lastnamed
)
205 return(mdoc_perr(mdoc
, line
, 0,
206 "no text in prologue"));
208 if ( ! mdoc_word_alloc(mdoc
, line
, 0, buf
))
210 mdoc
->next
= MDOC_NEXT_SIBLING
;
215 * Control-character detected. Begin the parsing sequence.
218 if (buf
[1] && '\\' == buf
[1])
219 if (buf
[2] && '\"' == buf
[2])
223 while (buf
[i
] && ! isspace((int)buf
[i
]) && i
< (int)sizeof(tmp
))
226 if (i
== (int)sizeof(tmp
)) {
227 mdoc
->flags
|= MDOC_HALT
;
228 return(mdoc_perr(mdoc
, line
, 1, "unknown macro"));
230 mdoc
->flags
|= MDOC_HALT
;
231 return(mdoc_perr(mdoc
, line
, 1, "unknown macro"));
236 (void)memcpy(tmp
, buf
+ 1, (size_t)i
);
239 if (MDOC_MAX
== (c
= mdoc_find(mdoc
, tmp
))) {
240 mdoc
->flags
|= MDOC_HALT
;
241 return(mdoc_perr(mdoc
, line
, 1, "unknown macro"));
244 while (buf
[i
] && isspace((int)buf
[i
]))
247 if ( ! mdoc_macro(mdoc
, c
, line
, 1, &i
, buf
)) {
248 mdoc
->flags
|= MDOC_HALT
;
257 mdoc_vmsg(struct mdoc
*mdoc
, int ln
, int pos
, const char *fmt
, ...)
262 if (NULL
== mdoc
->cb
.mdoc_msg
)
266 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
268 (*mdoc
->cb
.mdoc_msg
)(mdoc
->data
, ln
, pos
, buf
);
273 mdoc_verr(struct mdoc
*mdoc
, int ln
, int pos
,
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
, ln
, pos
, buf
));
290 mdoc_vwarn(struct mdoc
*mdoc
, int ln
, int pos
,
291 enum mdoc_warn type
, const char *fmt
, ...)
296 if (NULL
== mdoc
->cb
.mdoc_warn
)
300 (void)vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
302 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, ln
, pos
, type
, buf
));
307 mdoc_macro(struct mdoc
*mdoc
, int tok
,
308 int ln
, int ppos
, int *pos
, char *buf
)
311 assert(mdoc_macros
[tok
].fp
);
313 if (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
&&
314 SEC_PROLOGUE
!= mdoc
->lastnamed
)
315 return(mdoc_perr(mdoc
, ln
, ppos
, "macro disallowed in document body"));
316 if ( ! (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
) &&
317 SEC_PROLOGUE
== mdoc
->lastnamed
)
318 return(mdoc_perr(mdoc
, ln
, ppos
, "macro disallowed in document prologue"));
319 if (1 != ppos
&& ! (MDOC_CALLABLE
& mdoc_macros
[tok
].flags
))
320 return(mdoc_perr(mdoc
, ln
, ppos
, "macro not callable"));
321 return((*mdoc_macros
[tok
].fp
)(mdoc
, tok
, ln
, ppos
, pos
, buf
));
326 mdoc_node_append(struct mdoc
*mdoc
, struct mdoc_node
*p
)
328 const char *nn
, *nt
, *on
, *ot
, *act
;
332 assert(MDOC_ROOT
!= p
->type
);
334 /* See if we exceed the suggest line-max. */
348 /* This sort-of works (re-opening of text macros...). */
349 if (mdoc
->linetok
> MDOC_LINEARG_SOFTMAX
)
350 if ( ! mdoc_nwarn(mdoc
, p
, WARN_COMPAT
,
351 "suggested %d tokens per line exceeded (has %d)",
352 MDOC_LINEARG_SOFTMAX
, mdoc
->linetok
))
355 if (MDOC_TEXT
== mdoc
->last
->type
)
357 else if (MDOC_ROOT
== mdoc
->last
->type
)
360 on
= mdoc_macronames
[mdoc
->last
->tok
];
362 if (MDOC_TEXT
== p
->type
)
364 else if (MDOC_ROOT
== p
->type
)
367 nn
= mdoc_macronames
[p
->tok
];
369 ot
= mdoc_type2a(mdoc
->last
->type
);
370 nt
= mdoc_type2a(p
->type
);
372 switch (mdoc
->next
) {
373 case (MDOC_NEXT_SIBLING
):
374 mdoc
->last
->next
= p
;
375 p
->prev
= mdoc
->last
;
376 p
->parent
= mdoc
->last
->parent
;
379 case (MDOC_NEXT_CHILD
):
380 mdoc
->last
->child
= p
;
381 p
->parent
= mdoc
->last
;
389 if ( ! mdoc_valid_pre(mdoc
, p
))
394 assert(MDOC_BLOCK
== p
->parent
->type
);
395 p
->parent
->data
.block
.head
= p
;
398 assert(MDOC_BLOCK
== p
->parent
->type
);
399 p
->parent
->data
.block
.tail
= p
;
402 assert(MDOC_BLOCK
== p
->parent
->type
);
403 p
->parent
->data
.block
.body
= p
;
410 mdoc_msg(mdoc
, "parse: %s `%s' %s of %s `%s'",
411 nt
, nn
, act
, ot
, on
);
416 static struct mdoc_node
*
417 mdoc_node_alloc(const struct mdoc
*mdoc
)
421 p
= xcalloc(1, sizeof(struct mdoc_node
));
422 p
->sec
= mdoc
->lastsec
;
429 mdoc_tail_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
436 p
= mdoc_node_alloc(mdoc
);
443 return(mdoc_node_append(mdoc
, p
));
448 mdoc_head_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
455 p
= mdoc_node_alloc(mdoc
);
462 return(mdoc_node_append(mdoc
, p
));
467 mdoc_body_alloc(struct mdoc
*mdoc
, int line
, int pos
, int tok
)
474 p
= mdoc_node_alloc(mdoc
);
481 return(mdoc_node_append(mdoc
, p
));
486 mdoc_root_alloc(struct mdoc
*mdoc
)
490 p
= mdoc_node_alloc(mdoc
);
494 return(mdoc_node_append(mdoc
, p
));
499 mdoc_block_alloc(struct mdoc
*mdoc
, int line
, int pos
,
500 int tok
, size_t argsz
, const struct mdoc_arg
*args
)
504 p
= mdoc_node_alloc(mdoc
);
508 p
->type
= MDOC_BLOCK
;
510 p
->data
.block
.argc
= argsz
;
511 p
->data
.block
.argv
= argdup(argsz
, args
);
513 return(mdoc_node_append(mdoc
, p
));
518 mdoc_elem_alloc(struct mdoc
*mdoc
, int line
, int pos
,
519 int tok
, size_t argsz
, const struct mdoc_arg
*args
)
523 p
= mdoc_node_alloc(mdoc
);
529 p
->data
.elem
.argc
= argsz
;
530 p
->data
.elem
.argv
= argdup(argsz
, args
);
532 return(mdoc_node_append(mdoc
, p
));
537 mdoc_word_alloc(struct mdoc
*mdoc
,
538 int line
, int pos
, const char *word
)
542 p
= mdoc_node_alloc(mdoc
);
547 p
->data
.text
.string
= xstrdup(word
);
549 return(mdoc_node_append(mdoc
, p
));
554 argfree(size_t sz
, struct mdoc_arg
*p
)
563 for (i
= 0; i
< (int)sz
; i
++)
567 for (j
= 0; j
< (int)p
[i
].sz
; j
++)
576 mdoc_elem_free(struct mdoc_elem
*p
)
579 argfree(p
->argc
, p
->argv
);
584 mdoc_block_free(struct mdoc_block
*p
)
587 argfree(p
->argc
, p
->argv
);
592 mdoc_text_free(struct mdoc_text
*p
)
601 mdoc_node_free(struct mdoc_node
*p
)
606 mdoc_text_free(&p
->data
.text
);
609 mdoc_elem_free(&p
->data
.elem
);
612 mdoc_block_free(&p
->data
.block
);
623 mdoc_node_freelist(struct mdoc_node
*p
)
627 mdoc_node_freelist(p
->child
);
629 mdoc_node_freelist(p
->next
);
636 mdoc_find(const struct mdoc
*mdoc
, const char *key
)
639 return(mdoc_tokhash_find(mdoc
->htab
, key
));
644 argcpy(struct mdoc_arg
*dst
, const struct mdoc_arg
*src
)
648 dst
->line
= src
->line
;
651 if (0 == (dst
->sz
= src
->sz
))
653 dst
->value
= xcalloc(dst
->sz
, sizeof(char *));
654 for (i
= 0; i
< (int)dst
->sz
; i
++)
655 dst
->value
[i
] = xstrdup(src
->value
[i
]);
659 static struct mdoc_arg
*
660 argdup(size_t argsz
, const struct mdoc_arg
*args
)
668 pp
= xcalloc((size_t)argsz
, sizeof(struct mdoc_arg
));
669 for (i
= 0; i
< (int)argsz
; i
++)
670 argcpy(&pp
[i
], &args
[i
]);
676 /* FIXME: deprecate. */
678 mdoc_node2a(struct mdoc_node
*node
)
685 (void)xstrlcat(buf
, mdoc_type2a(node
->type
), 64);
686 if (MDOC_ROOT
== node
->type
)
688 (void)xstrlcat(buf
, " `", 64);
689 if (MDOC_TEXT
== node
->type
)
690 (void)xstrlcat(buf
, node
->data
.text
.string
, 64);
692 (void)xstrlcat(buf
, mdoc_macronames
[node
->tok
], 64);
693 (void)xstrlcat(buf
, "'", 64);