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