]> git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
Actions and validations properly added.
[mandoc.git] / mdoc.c
1 /* $Id: mdoc.c,v 1.16 2009/01/05 14:14:04 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4 *
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
8 * copies.
9 *
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.
18 */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <err.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "private.h"
28
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",
40 /* LINTED */
41 "Xr", "\%A", "\%B", "\%D",
42 /* LINTED */
43 "\%I", "\%J", "\%N", "\%O",
44 /* LINTED */
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",
59 "Fr", "Ud",
60 };
61
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",
84 };
85
86 const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
87 { NULL, 0 }, /* \" */
88 { NULL, MDOC_PROLOGUE }, /* Dd */
89 { NULL, MDOC_PROLOGUE }, /* Dt */
90 { NULL, MDOC_PROLOGUE }, /* Os */
91 { macro_scoped, 0 }, /* Sh */
92 { macro_scoped, 0 }, /* Ss */
93 { macro_text, 0 }, /* Pp */
94 { macro_scoped_line, 0 }, /* D1 */
95 { macro_scoped_line, 0 }, /* 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 { NULL, 0 }, /* It */
101 { macro_text, MDOC_CALLABLE }, /* Ad */
102 { macro_constant, 0 }, /* An */
103 { macro_text, MDOC_CALLABLE }, /* Ar */
104 { macro_constant, MDOC_QUOTABLE }, /* Cd */
105 { macro_text, MDOC_CALLABLE }, /* Cm */
106 { macro_text, MDOC_CALLABLE }, /* Dv */
107 { macro_text, MDOC_CALLABLE }, /* Er */
108 { macro_text, MDOC_CALLABLE }, /* Ev */
109 { macro_constant, 0 }, /* Ex */
110 { macro_text, MDOC_CALLABLE }, /* Fa */
111 { macro_constant, 0 }, /* Fd */
112 { macro_text, MDOC_CALLABLE }, /* Fl */
113 { macro_text, MDOC_CALLABLE | MDOC_QUOTABLE }, /* Fn */
114 { macro_text, 0 }, /* Ft */
115 { macro_text, MDOC_CALLABLE }, /* Ic */
116 { macro_constant, 0 }, /* In */
117 { macro_text, MDOC_CALLABLE }, /* Li */
118 { macro_constant, 0 }, /* Nd */
119 { NULL, 0 }, /* Nm */
120 { macro_scoped_line, MDOC_CALLABLE }, /* Op */
121 { macro_obsolete, 0 }, /* Ot */
122 { macro_text, MDOC_CALLABLE }, /* Pa */
123 { macro_constant, 0 }, /* Rv */
124 { macro_constant, 0 }, /* St */
125 { macro_text, MDOC_CALLABLE }, /* Va */
126 { macro_text, MDOC_CALLABLE }, /* Vt */
127 { macro_text, MDOC_CALLABLE }, /* Xr */
128 { macro_constant, MDOC_QUOTABLE }, /* %A */
129 { macro_constant, MDOC_QUOTABLE }, /* %B */
130 { macro_constant, MDOC_QUOTABLE }, /* %D */
131 { macro_constant, MDOC_QUOTABLE }, /* %I */
132 { macro_constant, MDOC_QUOTABLE }, /* %J */
133 { macro_constant, MDOC_QUOTABLE }, /* %N */
134 { macro_constant, MDOC_QUOTABLE }, /* %O */
135 { macro_constant, MDOC_QUOTABLE }, /* %P */
136 { macro_constant, MDOC_QUOTABLE }, /* %R */
137 { macro_constant, MDOC_QUOTABLE }, /* %T */
138 { macro_constant, MDOC_QUOTABLE }, /* %V */
139 { NULL, 0 }, /* Ac */
140 { NULL, 0 }, /* Ao */
141 { macro_scoped_line, MDOC_CALLABLE }, /* Aq */
142 { macro_constant, 0 }, /* At */
143 { NULL, 0 }, /* Bc */
144 { macro_scoped, MDOC_EXPLICIT }, /* Bf */
145 { NULL, 0 }, /* Bo */
146 { macro_scoped_line, MDOC_CALLABLE }, /* Bq */
147 { macro_constant_delimited, 0 }, /* Bsx */
148 { macro_constant_delimited, 0 }, /* Bx */
149 { macro_constant, 0 }, /* Db */
150 { NULL, 0 }, /* Dc */
151 { NULL, 0 }, /* Do */
152 { macro_scoped_line, MDOC_CALLABLE }, /* Dq */
153 { NULL, 0 }, /* Ec */
154 { macro_close_explicit, 0 }, /* Ef */
155 { macro_text, MDOC_CALLABLE }, /* Em */
156 { NULL, 0 }, /* Eo */
157 { macro_constant_delimited, 0 }, /* Fx */
158 { macro_text, 0 }, /* Ms */
159 { macro_constant_delimited, MDOC_CALLABLE }, /* No */
160 { macro_constant_delimited, MDOC_CALLABLE }, /* Ns */
161 { macro_constant_delimited, 0 }, /* Nx */
162 { macro_constant_delimited, 0 }, /* Ox */
163 { NULL, 0 }, /* Pc */
164 { macro_constant, 0 }, /* Pf */
165 { NULL, 0 }, /* Po */
166 { macro_scoped_line, MDOC_CALLABLE }, /* Pq */
167 { NULL, 0 }, /* Qc */
168 { macro_scoped_line, MDOC_CALLABLE }, /* Ql */
169 { NULL, 0 }, /* Qo */
170 { macro_scoped_line, MDOC_CALLABLE }, /* Qq */
171 { macro_scoped, MDOC_EXPLICIT }, /* Re */
172 { macro_scoped, MDOC_EXPLICIT }, /* Rs */
173 { NULL, 0 }, /* Sc */
174 { NULL, 0 }, /* So */
175 { macro_scoped_line, MDOC_CALLABLE }, /* Sq */
176 { macro_constant, 0 }, /* Sm */
177 { macro_text, MDOC_CALLABLE }, /* Sx */
178 { macro_text, MDOC_CALLABLE }, /* Sy */
179 { macro_text, MDOC_CALLABLE }, /* Tn */
180 { macro_constant_delimited, 0 }, /* Ux */
181 { NULL, 0 }, /* Xc */
182 { NULL, 0 }, /* Xo */
183 { NULL, 0 }, /* Fo */
184 { NULL, 0 }, /* Fc */
185 { NULL, 0 }, /* Oo */
186 { NULL, 0 }, /* Oc */
187 { NULL, 0 }, /* Bk */
188 { NULL, 0 }, /* Ek */
189 { macro_constant, 0 }, /* Bt */
190 { macro_constant, 0 }, /* Hf */
191 { macro_obsolete, 0 }, /* Fr */
192 { macro_constant, 0 }, /* Ud */
193 };
194
195 const char * const *mdoc_macronames = __mdoc_macronames;
196 const char * const *mdoc_argnames = __mdoc_argnames;
197 const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
198
199
200 static struct mdoc_arg *argdup(size_t, const struct mdoc_arg *);
201 static void argfree(size_t, struct mdoc_arg *);
202 static void argcpy(struct mdoc_arg *,
203 const struct mdoc_arg *);
204
205 static void mdoc_node_freelist(struct mdoc_node *);
206 static void mdoc_node_append(struct mdoc *, int,
207 struct mdoc_node *);
208 static void mdoc_elem_free(struct mdoc_elem *);
209 static void mdoc_text_free(struct mdoc_text *);
210
211
212 const struct mdoc_node *
213 mdoc_result(struct mdoc *mdoc)
214 {
215
216 return(mdoc->first);
217 }
218
219
220 void
221 mdoc_free(struct mdoc *mdoc)
222 {
223
224 if (mdoc->first)
225 mdoc_node_freelist(mdoc->first);
226 if (mdoc->htab)
227 mdoc_tokhash_free(mdoc->htab);
228
229 free(mdoc);
230 }
231
232
233 struct mdoc *
234 mdoc_alloc(void *data, const struct mdoc_cb *cb)
235 {
236 struct mdoc *p;
237
238 p = xcalloc(1, sizeof(struct mdoc));
239
240 p->data = data;
241 (void)memcpy(&p->cb, cb, sizeof(struct mdoc_cb));
242
243 p->htab = mdoc_tokhash_alloc();
244 return(p);
245 }
246
247
248 int
249 mdoc_parseln(struct mdoc *mdoc, char *buf)
250 {
251 int c, i;
252 char tmp[5];
253
254 if ('.' != *buf) {
255 mdoc_word_alloc(mdoc, 0, buf);
256 mdoc->next = MDOC_NEXT_SIBLING;
257 return(1);
258 }
259
260 if (buf[1] && '\\' == buf[1])
261 if (buf[2] && '\"' == buf[2])
262 return(1);
263
264 i = 1;
265 while (buf[i] && ! isspace(buf[i]) && i < (int)sizeof(tmp))
266 i++;
267
268 if (i == (int)sizeof(tmp))
269 return(mdoc_err(mdoc, -1, 1, ERR_MACRO_NOTSUP));
270 else if (i <= 2)
271 return(mdoc_err(mdoc, -1, 1, ERR_MACRO_NOTSUP));
272
273 i--;
274
275 (void)memcpy(tmp, buf + 1, (size_t)i);
276 tmp[i++] = 0;
277
278 if (MDOC_MAX == (c = mdoc_find(mdoc, tmp)))
279 return(mdoc_err(mdoc, c, 1, ERR_MACRO_NOTSUP));
280
281 while (buf[i] && isspace(buf[i]))
282 i++;
283
284 return(mdoc_macro(mdoc, c, 1, &i, buf));
285 }
286
287
288 void
289 mdoc_msg(struct mdoc *mdoc, int pos, const char *fmt, ...)
290 {
291 va_list ap;
292 char buf[256];
293
294 if (NULL == mdoc->cb.mdoc_msg)
295 return;
296
297 va_start(ap, fmt);
298 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
299 va_end(ap);
300
301 (*mdoc->cb.mdoc_msg)(mdoc->data, pos, buf);
302 }
303
304
305 int
306 mdoc_err(struct mdoc *mdoc, int tok, int pos, enum mdoc_err type)
307 {
308
309 if (NULL == mdoc->cb.mdoc_err)
310 return(0);
311 return((*mdoc->cb.mdoc_err)(mdoc->data, tok, pos, type));
312 }
313
314
315 int
316 mdoc_warn(struct mdoc *mdoc, int tok, int pos, enum mdoc_warn type)
317 {
318
319 if (NULL == mdoc->cb.mdoc_warn)
320 return(0);
321 return((*mdoc->cb.mdoc_warn)(mdoc->data, tok, pos, type));
322 }
323
324
325 int
326 mdoc_macro(struct mdoc *mdoc, int tok, int ppos, int *pos, char *buf)
327 {
328
329 if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
330 SEC_PROLOGUE == mdoc->sec_lastn)
331 return(macro_prologue(mdoc, tok, ppos, pos, buf));
332
333 if (SEC_PROLOGUE == mdoc->sec_lastn)
334 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
335
336 if (NULL == (mdoc_macros[tok].fp)) {
337 (void)mdoc_err(mdoc, tok, ppos, ERR_MACRO_NOTSUP);
338 return(0);
339 }
340
341 if (1 != ppos && ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
342 (void)mdoc_err(mdoc, tok, ppos, ERR_MACRO_NOTCALL);
343 return(0);
344 }
345
346 return((*mdoc_macros[tok].fp)(mdoc, tok, ppos, pos, buf));
347 }
348
349
350 static void
351 mdoc_node_append(struct mdoc *mdoc, int pos, struct mdoc_node *p)
352 {
353 const char *nn, *on, *nt, *ot, *act;
354
355 switch (p->type) {
356 case (MDOC_TEXT):
357 nn = p->data.text.string;
358 nt = "text";
359 break;
360 case (MDOC_BODY):
361 nn = mdoc_macronames[p->data.body.tok];
362 nt = "body";
363 break;
364 case (MDOC_ELEM):
365 nn = mdoc_macronames[p->data.elem.tok];
366 nt = "elem";
367 break;
368 case (MDOC_HEAD):
369 nn = mdoc_macronames[p->data.head.tok];
370 nt = "head";
371 break;
372 case (MDOC_BLOCK):
373 nn = mdoc_macronames[p->data.block.tok];
374 nt = "block";
375 break;
376 default:
377 abort();
378 /* NOTREACHED */
379 }
380
381 if (NULL == mdoc->first) {
382 assert(NULL == mdoc->last);
383 mdoc->first = p;
384 mdoc->last = p;
385 mdoc_msg(mdoc, pos, "parse: root %s `%s'", nt, nn);
386 return;
387 }
388
389 switch (mdoc->last->type) {
390 case (MDOC_TEXT):
391 on = "<text>";
392 ot = "text";
393 break;
394 case (MDOC_BODY):
395 on = mdoc_macronames[mdoc->last->data.body.tok];
396 ot = "body";
397 break;
398 case (MDOC_ELEM):
399 on = mdoc_macronames[mdoc->last->data.elem.tok];
400 ot = "elem";
401 break;
402 case (MDOC_HEAD):
403 on = mdoc_macronames[mdoc->last->data.head.tok];
404 ot = "head";
405 break;
406 case (MDOC_BLOCK):
407 on = mdoc_macronames[mdoc->last->data.block.tok];
408 ot = "block";
409 break;
410 default:
411 abort();
412 /* NOTREACHED */
413 }
414
415 switch (mdoc->next) {
416 case (MDOC_NEXT_SIBLING):
417 mdoc->last->next = p;
418 p->prev = mdoc->last;
419 p->parent = mdoc->last->parent;
420 act = "sibling";
421 break;
422 case (MDOC_NEXT_CHILD):
423 mdoc->last->child = p;
424 p->parent = mdoc->last;
425 act = "child";
426 break;
427 default:
428 abort();
429 /* NOTREACHED */
430 }
431
432 mdoc_msg(mdoc, pos, "parse: %s `%s' %s of %s `%s'",
433 nt, nn, act, ot, on);
434
435 mdoc->last = p;
436 }
437
438
439 void
440 mdoc_head_alloc(struct mdoc *mdoc, int pos, int tok)
441 {
442 struct mdoc_node *p;
443
444 assert(mdoc->first);
445 assert(mdoc->last);
446
447 p = xcalloc(1, sizeof(struct mdoc_node));
448
449 p->type = MDOC_HEAD;
450 p->data.head.tok = tok;
451
452 mdoc_node_append(mdoc, pos, p);
453 }
454
455
456 void
457 mdoc_body_alloc(struct mdoc *mdoc, int pos, int tok)
458 {
459 struct mdoc_node *p;
460
461 assert(mdoc->first);
462 assert(mdoc->last);
463
464 p = xcalloc(1, sizeof(struct mdoc_node));
465
466 p->type = MDOC_BODY;
467 p->data.body.tok = tok;
468
469 mdoc_node_append(mdoc, pos, p);
470 }
471
472
473 void
474 mdoc_block_alloc(struct mdoc *mdoc, int pos, int tok,
475 size_t argsz, const struct mdoc_arg *args)
476 {
477 struct mdoc_node *p;
478
479 p = xcalloc(1, sizeof(struct mdoc_node));
480
481 p->type = MDOC_BLOCK;
482 p->data.block.tok = tok;
483 p->data.block.argc = argsz;
484 p->data.block.argv = argdup(argsz, args);
485
486 mdoc_node_append(mdoc, pos, p);
487 }
488
489
490 void
491 mdoc_elem_alloc(struct mdoc *mdoc, int pos, int tok,
492 size_t argsz, const struct mdoc_arg *args)
493 {
494 struct mdoc_node *p;
495
496 p = xcalloc(1, sizeof(struct mdoc_node));
497 p->type = MDOC_ELEM;
498 p->data.elem.tok = tok;
499 /* FIXME: freeing of params... */
500 p->data.elem.argc = argsz;
501 p->data.elem.argv = argdup(argsz, args);
502
503 mdoc_node_append(mdoc, pos, p);
504 }
505
506
507 void
508 mdoc_word_alloc(struct mdoc *mdoc, int pos, const char *word)
509 {
510 struct mdoc_node *p;
511
512 p = xcalloc(1, sizeof(struct mdoc_node));
513 p->type = MDOC_TEXT;
514 p->data.text.string = xstrdup(word);
515
516 mdoc_node_append(mdoc, pos, p);
517 }
518
519
520 static void
521 argfree(size_t sz, struct mdoc_arg *p)
522 {
523 int i, j;
524
525 if (0 == sz)
526 return;
527
528 assert(p);
529 /* LINTED */
530 for (i = 0; i < (int)sz; i++)
531 if (p[i].sz > 0) {
532 assert(p[i].value);
533 /* LINTED */
534 for (j = 0; j < (int)p[i].sz; j++)
535 free(p[i].value[j]);
536 }
537 free(p);
538 }
539
540
541 static void
542 mdoc_elem_free(struct mdoc_elem *p)
543 {
544
545 argfree(p->argc, p->argv);
546 }
547
548
549 static void
550 mdoc_block_free(struct mdoc_block *p)
551 {
552
553 argfree(p->argc, p->argv);
554 }
555
556
557 static void
558 mdoc_text_free(struct mdoc_text *p)
559 {
560
561 if (p->string)
562 free(p->string);
563 }
564
565
566 void
567 mdoc_node_free(struct mdoc_node *p)
568 {
569
570 switch (p->type) {
571 case (MDOC_TEXT):
572 mdoc_text_free(&p->data.text);
573 break;
574 case (MDOC_ELEM):
575 mdoc_elem_free(&p->data.elem);
576 break;
577 case (MDOC_BLOCK):
578 mdoc_block_free(&p->data.block);
579 break;
580 default:
581 break;
582 }
583
584 free(p);
585 }
586
587
588 static void
589 mdoc_node_freelist(struct mdoc_node *p)
590 {
591
592 if (p->child)
593 mdoc_node_freelist(p->child);
594 if (p->next)
595 mdoc_node_freelist(p->next);
596
597 mdoc_node_free(p);
598 }
599
600
601 int
602 mdoc_find(const struct mdoc *mdoc, const char *key)
603 {
604
605 return(mdoc_tokhash_find(mdoc->htab, key));
606 }
607
608
609 static void
610 argcpy(struct mdoc_arg *dst, const struct mdoc_arg *src)
611 {
612 int i;
613
614 dst->arg = src->arg;
615 if (0 == (dst->sz = src->sz))
616 return;
617 dst->value = xcalloc(dst->sz, sizeof(char *));
618 for (i = 0; i < (int)dst->sz; i++)
619 dst->value[i] = xstrdup(src->value[i]);
620 }
621
622
623 static struct mdoc_arg *
624 argdup(size_t argsz, const struct mdoc_arg *args)
625 {
626 struct mdoc_arg *pp;
627 int i;
628
629 if (0 == argsz)
630 return(NULL);
631
632 pp = xcalloc((size_t)argsz, sizeof(struct mdoc_arg));
633 for (i = 0; i < (int)argsz; i++)
634 argcpy(&pp[i], &args[i]);
635
636 return(pp);
637 }
638