]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
1 /* $Id: mdoc.c,v 1.19 2009/01/06 15:49:44 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.
29 const char *const __mdoc_macronames
[MDOC_MAX
] = {
30 "\\\"", "Dd", "Dt", "Os",
31 "Sh", "Ss", "Pp", "D1",
32 "Dl", "Bd", "Ed", "Bl",
33 "El", "It", "Ad", "An",
34 "Ar", "Cd", "Cm", "Dv",
35 "Er", "Ev", "Ex", "Fa",
36 "Fd", "Fl", "Fn", "Ft",
37 "Ic", "In", "Li", "Nd",
38 "Nm", "Op", "Ot", "Pa",
39 "Rv", "St", "Va", "Vt",
41 "Xr", "\%A", "\%B", "\%D",
43 "\%I", "\%J", "\%N", "\%O",
45 "\%P", "\%R", "\%T", "\%V",
46 "Ac", "Ao", "Aq", "At",
47 "Bc", "Bf", "Bo", "Bq",
48 "Bsx", "Bx", "Db", "Dc",
49 "Do", "Dq", "Ec", "Ef",
50 "Em", "Eo", "Fx", "Ms",
51 "No", "Ns", "Nx", "Ox",
52 "Pc", "Pf", "Po", "Pq",
53 "Qc", "Ql", "Qo", "Qq",
54 "Re", "Rs", "Sc", "So",
55 "Sq", "Sm", "Sx", "Sy",
56 "Tn", "Ux", "Xc", "Xo",
57 "Fo", "Fc", "Oo", "Oc",
58 "Bk", "Ek", "Bt", "Hf",
62 const char *const __mdoc_argnames
[MDOC_ARG_MAX
] = {
63 "split", "nosplit", "ragged",
64 "unfilled", "literal", "file",
65 "offset", "bullet", "dash",
66 "hyphen", "item", "enum",
67 "tag", "diag", "hang",
68 "ohang", "inset", "column",
69 "width", "compact", "std",
70 "p1003.1-88", "p1003.1-90", "p1003.1-96",
71 "p1003.1-2001", "p1003.1-2004", "p1003.1",
72 "p1003.1b", "p1003.1b-93", "p1003.1c-95",
73 "p1003.1g-2000", "p1003.2-92", "p1387.2-95",
74 "p1003.2", "p1387.2", "isoC-90",
75 "isoC-amd1", "isoC-tcor1", "isoC-tcor2",
76 "isoC-99", "ansiC", "ansiC-89",
77 "ansiC-99", "ieee754", "iso8802-3",
78 "xpg3", "xpg4", "xpg4.2",
79 "xpg4.3", "xbd5", "xcu5",
80 "xsh5", "xns5", "xns5.2d2.0",
81 "xcurses4.2", "susv2", "susv3",
82 "svid4", "filled", "words",
83 "emphasis", "symbolic",
86 const struct mdoc_macro __mdoc_macros
[MDOC_MAX
] = {
88 { macro_prologue
, MDOC_PROLOGUE
}, /* Dd */
89 { macro_prologue
, MDOC_PROLOGUE
}, /* Dt */
90 { macro_prologue
, MDOC_PROLOGUE
}, /* Os */
91 { macro_scoped
, 0 }, /* Sh */
92 { macro_scoped
, 0 }, /* Ss */
93 { macro_text
, 0 }, /* Pp */
94 { macro_scoped_line
, MDOC_PARSED
}, /* D1 */
95 { macro_scoped_line
, MDOC_PARSED
}, /* Dl */
96 { macro_scoped
, MDOC_EXPLICIT
}, /* Bd */
97 { macro_close_explicit
, 0 }, /* Ed */
98 { macro_scoped
, MDOC_EXPLICIT
}, /* Bl */
99 { macro_close_explicit
, 0 }, /* El */
100 { macro_scoped
, MDOC_NESTED
| MDOC_PARSED
}, /* It */
101 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ad */
102 { macro_constant
, MDOC_PARSED
}, /* An */
103 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ar */
104 { macro_constant
, MDOC_QUOTABLE
}, /* Cd */
105 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Cm */
106 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Dv */
107 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Er */
108 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ev */
109 { macro_constant
, 0 }, /* Ex */
110 { macro_text
, MDOC_CALLABLE
| MDOC_QUOTABLE
| MDOC_PARSED
}, /* Fa */
111 { macro_constant
, 0 }, /* Fd */
112 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Fl */
113 { macro_text
, MDOC_CALLABLE
| MDOC_QUOTABLE
| MDOC_PARSED
}, /* Fn */
114 { macro_text
, MDOC_PARSED
}, /* Ft */
115 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ic */
116 { macro_constant
, 0 }, /* In */
117 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Li */
118 { macro_constant
, 0 }, /* Nd */
119 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Nm */
120 { macro_scoped_line
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Op */
121 { macro_obsolete
, 0 }, /* Ot */
122 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Pa */
123 { macro_constant
, 0 }, /* Rv */
124 /* XXX - supposed to be (but isn't) callable. */
125 { macro_constant_delimited
, MDOC_PARSED
}, /* St */
126 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Va */
127 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Vt */
128 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Xr */
129 { macro_constant
, MDOC_QUOTABLE
| MDOC_PARSED
}, /* %A */
130 { macro_constant
, MDOC_QUOTABLE
| MDOC_PARSED
}, /* %B */
131 { macro_constant
, MDOC_QUOTABLE
}, /* %D */
132 { macro_constant
, MDOC_QUOTABLE
| MDOC_PARSED
}, /* %I */
133 { macro_constant
, MDOC_QUOTABLE
| MDOC_PARSED
}, /* %J */
134 { macro_constant
, MDOC_QUOTABLE
}, /* %N */
135 { macro_constant
, MDOC_QUOTABLE
}, /* %O */
136 { macro_constant
, MDOC_QUOTABLE
}, /* %P */
137 { macro_constant
, MDOC_QUOTABLE
}, /* %R */
138 { macro_constant
, MDOC_QUOTABLE
| MDOC_PARSED
}, /* %T */
139 { macro_constant
, MDOC_QUOTABLE
}, /* %V */
140 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ac */
141 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ao */
142 { macro_scoped_line
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Aq */
143 { macro_constant
, 0 }, /* At */
144 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Bc */
145 { macro_scoped
, MDOC_EXPLICIT
}, /* Bf */
146 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Bo */
147 { macro_scoped_line
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Bq */
148 { macro_constant_delimited
, MDOC_PARSED
}, /* Bsx */
149 { macro_constant_delimited
, MDOC_PARSED
}, /* Bx */
150 { macro_constant
, 0 }, /* Db */
151 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Dc */
152 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Do */
153 { macro_scoped_line
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Dq */
154 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ec */
155 { macro_close_explicit
, 0 }, /* Ef */
156 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Em */
157 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Eo */
158 { macro_constant_delimited
, MDOC_PARSED
}, /* Fx */
159 { macro_text
, MDOC_PARSED
}, /* Ms */
160 { macro_constant_delimited
, MDOC_CALLABLE
| MDOC_PARSED
}, /* No */
161 { macro_constant_delimited
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ns */
162 { macro_constant_delimited
, MDOC_PARSED
}, /* Nx */
163 { macro_constant_delimited
, MDOC_PARSED
}, /* Ox */
164 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Pc */
165 { macro_constant
, MDOC_PARSED
}, /* Pf */
166 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Po */
167 { macro_scoped_line
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Pq */
168 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Qc */
169 { macro_scoped_line
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Ql */
170 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Qo */
171 { macro_scoped_line
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Qq */
172 { macro_close_explicit
, 0 }, /* Re */
173 { macro_scoped
, MDOC_EXPLICIT
}, /* Rs */
174 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Sc */
175 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* So */
176 { macro_scoped_line
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Sq */
177 { macro_constant
, 0 }, /* Sm */
178 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Sx */
179 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Sy */
180 { macro_text
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Tn */
181 { macro_constant_delimited
, MDOC_PARSED
}, /* Ux */
182 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Xc */
183 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Xo */
184 /* XXX - .Fo supposed to be (but isn't) callable. */
185 { macro_scoped
, MDOC_EXPLICIT
| MDOC_PARSED
}, /* Fo */
186 /* XXX - .Fc supposed to be (but isn't) callable. */
187 { macro_close_explicit
, MDOC_PARSED
}, /* Fc */
188 { macro_constant_scoped
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Oo */
189 { macro_close_explicit
, MDOC_CALLABLE
| MDOC_PARSED
}, /* Oc */
190 { macro_scoped
, MDOC_EXPLICIT
}, /* Bk */
191 { macro_close_explicit
, 0 }, /* Ek */
192 { macro_constant
, 0 }, /* Bt */
193 { macro_constant
, 0 }, /* Hf */
194 { macro_obsolete
, 0 }, /* Fr */
195 { macro_constant
, 0 }, /* Ud */
198 const char * const *mdoc_macronames
= __mdoc_macronames
;
199 const char * const *mdoc_argnames
= __mdoc_argnames
;
200 const struct mdoc_macro
* const mdoc_macros
= __mdoc_macros
;
203 static struct mdoc_arg
*argdup(size_t, const struct mdoc_arg
*);
204 static void argfree(size_t, struct mdoc_arg
*);
205 static void argcpy(struct mdoc_arg
*,
206 const struct mdoc_arg
*);
208 static void mdoc_node_freelist(struct mdoc_node
*);
209 static void mdoc_node_append(struct mdoc
*, int,
211 static void mdoc_elem_free(struct mdoc_elem
*);
212 static void mdoc_text_free(struct mdoc_text
*);
215 const struct mdoc_node
*
216 mdoc_result(struct mdoc
*mdoc
)
224 mdoc_free(struct mdoc
*mdoc
)
228 mdoc_node_freelist(mdoc
->first
);
230 mdoc_tokhash_free(mdoc
->htab
);
237 mdoc_alloc(void *data
, const struct mdoc_cb
*cb
)
241 p
= xcalloc(1, sizeof(struct mdoc
));
244 (void)memcpy(&p
->cb
, cb
, sizeof(struct mdoc_cb
));
246 p
->htab
= mdoc_tokhash_alloc();
252 mdoc_parseln(struct mdoc
*mdoc
, char *buf
)
258 if (SEC_PROLOGUE
== mdoc
->sec_lastn
)
259 return(mdoc_err(mdoc
, -1, 0, ERR_SYNTAX_NOTEXT
));
260 mdoc_word_alloc(mdoc
, 0, buf
);
261 mdoc
->next
= MDOC_NEXT_SIBLING
;
265 if (buf
[1] && '\\' == buf
[1])
266 if (buf
[2] && '\"' == buf
[2])
270 while (buf
[i
] && ! isspace(buf
[i
]) && i
< (int)sizeof(tmp
))
273 if (i
== (int)sizeof(tmp
))
274 return(mdoc_err(mdoc
, -1, 1, ERR_MACRO_NOTSUP
));
276 return(mdoc_err(mdoc
, -1, 1, ERR_MACRO_NOTSUP
));
280 (void)memcpy(tmp
, buf
+ 1, (size_t)i
);
283 if (MDOC_MAX
== (c
= mdoc_find(mdoc
, tmp
)))
284 return(mdoc_err(mdoc
, c
, 1, ERR_MACRO_NOTSUP
));
286 while (buf
[i
] && isspace(buf
[i
]))
289 return(mdoc_macro(mdoc
, c
, 1, &i
, buf
));
294 mdoc_msg(struct mdoc
*mdoc
, int pos
, const char *fmt
, ...)
299 if (NULL
== mdoc
->cb
.mdoc_msg
)
303 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
306 (*mdoc
->cb
.mdoc_msg
)(mdoc
->data
, pos
, buf
);
311 mdoc_err(struct mdoc
*mdoc
, int tok
, int pos
, enum mdoc_err type
)
314 if (NULL
== mdoc
->cb
.mdoc_err
)
316 return((*mdoc
->cb
.mdoc_err
)(mdoc
->data
, tok
, pos
, type
));
321 mdoc_warn(struct mdoc
*mdoc
, int tok
, int pos
, enum mdoc_warn type
)
324 if (NULL
== mdoc
->cb
.mdoc_warn
)
326 return((*mdoc
->cb
.mdoc_warn
)(mdoc
->data
, tok
, pos
, type
));
331 mdoc_macro(struct mdoc
*mdoc
, int tok
, int ppos
, int *pos
, char *buf
)
334 if ( ! (MDOC_PROLOGUE
& mdoc_macros
[tok
].flags
) &&
335 SEC_PROLOGUE
== mdoc
->sec_lastn
)
336 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE
));
338 if (NULL
== (mdoc_macros
[tok
].fp
)) {
339 (void)mdoc_err(mdoc
, tok
, ppos
, ERR_MACRO_NOTSUP
);
343 if (1 != ppos
&& ! (MDOC_CALLABLE
& mdoc_macros
[tok
].flags
)) {
344 (void)mdoc_err(mdoc
, tok
, ppos
, ERR_MACRO_NOTCALL
);
348 return((*mdoc_macros
[tok
].fp
)(mdoc
, tok
, ppos
, pos
, buf
));
353 mdoc_node_append(struct mdoc
*mdoc
, int pos
, struct mdoc_node
*p
)
355 const char *nn
, *on
, *nt
, *ot
, *act
;
359 nn
= p
->data
.text
.string
;
363 nn
= mdoc_macronames
[p
->data
.body
.tok
];
367 nn
= mdoc_macronames
[p
->data
.elem
.tok
];
371 nn
= mdoc_macronames
[p
->data
.head
.tok
];
375 nn
= mdoc_macronames
[p
->data
.tail
.tok
];
379 nn
= mdoc_macronames
[p
->data
.block
.tok
];
387 if (NULL
== mdoc
->first
) {
388 assert(NULL
== mdoc
->last
);
391 mdoc_msg(mdoc
, pos
, "parse: root %s `%s'", nt
, nn
);
395 switch (mdoc
->last
->type
) {
401 on
= mdoc_macronames
[mdoc
->last
->data
.body
.tok
];
405 on
= mdoc_macronames
[mdoc
->last
->data
.elem
.tok
];
409 on
= mdoc_macronames
[mdoc
->last
->data
.head
.tok
];
413 on
= mdoc_macronames
[mdoc
->last
->data
.tail
.tok
];
417 on
= mdoc_macronames
[mdoc
->last
->data
.block
.tok
];
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
;
432 case (MDOC_NEXT_CHILD
):
433 mdoc
->last
->child
= p
;
434 p
->parent
= mdoc
->last
;
442 mdoc_msg(mdoc
, pos
, "parse: %s `%s' %s of %s `%s'",
443 nt
, nn
, act
, ot
, on
);
450 mdoc_tail_alloc(struct mdoc
*mdoc
, int pos
, int tok
)
457 p
= xcalloc(1, sizeof(struct mdoc_node
));
460 p
->data
.tail
.tok
= tok
;
462 mdoc_node_append(mdoc
, pos
, p
);
467 mdoc_head_alloc(struct mdoc
*mdoc
, int pos
, int tok
)
474 p
= xcalloc(1, sizeof(struct mdoc_node
));
477 p
->data
.head
.tok
= tok
;
479 mdoc_node_append(mdoc
, pos
, p
);
484 mdoc_body_alloc(struct mdoc
*mdoc
, int pos
, int tok
)
491 p
= xcalloc(1, sizeof(struct mdoc_node
));
494 p
->data
.body
.tok
= tok
;
496 mdoc_node_append(mdoc
, pos
, p
);
501 mdoc_block_alloc(struct mdoc
*mdoc
, int pos
, int tok
,
502 size_t argsz
, const struct mdoc_arg
*args
)
506 p
= xcalloc(1, sizeof(struct mdoc_node
));
508 p
->type
= MDOC_BLOCK
;
509 p
->data
.block
.tok
= tok
;
510 p
->data
.block
.argc
= argsz
;
511 p
->data
.block
.argv
= argdup(argsz
, args
);
513 mdoc_node_append(mdoc
, pos
, p
);
518 mdoc_elem_alloc(struct mdoc
*mdoc
, int pos
, int tok
,
519 size_t argsz
, const struct mdoc_arg
*args
)
523 p
= xcalloc(1, sizeof(struct mdoc_node
));
525 p
->data
.elem
.tok
= tok
;
526 p
->data
.elem
.argc
= argsz
;
527 p
->data
.elem
.argv
= argdup(argsz
, args
);
529 mdoc_node_append(mdoc
, pos
, p
);
534 mdoc_word_alloc(struct mdoc
*mdoc
, int pos
, const char *word
)
538 p
= xcalloc(1, sizeof(struct mdoc_node
));
540 p
->data
.text
.string
= xstrdup(word
);
542 mdoc_node_append(mdoc
, pos
, p
);
547 argfree(size_t sz
, struct mdoc_arg
*p
)
556 for (i
= 0; i
< (int)sz
; i
++)
560 for (j
= 0; j
< (int)p
[i
].sz
; j
++)
569 mdoc_elem_free(struct mdoc_elem
*p
)
572 argfree(p
->argc
, p
->argv
);
577 mdoc_block_free(struct mdoc_block
*p
)
580 argfree(p
->argc
, p
->argv
);
585 mdoc_text_free(struct mdoc_text
*p
)
594 mdoc_node_free(struct mdoc_node
*p
)
599 mdoc_text_free(&p
->data
.text
);
602 mdoc_elem_free(&p
->data
.elem
);
605 mdoc_block_free(&p
->data
.block
);
616 mdoc_node_freelist(struct mdoc_node
*p
)
620 mdoc_node_freelist(p
->child
);
622 mdoc_node_freelist(p
->next
);
629 mdoc_find(const struct mdoc
*mdoc
, const char *key
)
632 return(mdoc_tokhash_find(mdoc
->htab
, key
));
637 argcpy(struct mdoc_arg
*dst
, const struct mdoc_arg
*src
)
642 if (0 == (dst
->sz
= src
->sz
))
644 dst
->value
= xcalloc(dst
->sz
, sizeof(char *));
645 for (i
= 0; i
< (int)dst
->sz
; i
++)
646 dst
->value
[i
] = xstrdup(src
->value
[i
]);
650 static struct mdoc_arg
*
651 argdup(size_t argsz
, const struct mdoc_arg
*args
)
659 pp
= xcalloc((size_t)argsz
, sizeof(struct mdoc_arg
));
660 for (i
= 0; i
< (int)argsz
; i
++)
661 argcpy(&pp
[i
], &args
[i
]);