]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_action.c
d7d03ea962cc89c3fdfe1282b7a55666d6a45677
[mandoc.git] / mdoc_action.c
1 /* $Id: mdoc_action.c,v 1.84 2010/11/29 15:45:15 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
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 above
7 * copyright notice and this permission notice appear in all copies.
8 *
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.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #ifndef OSNAME
22 #include <sys/utsname.h>
23 #endif
24
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30
31 #include "mandoc.h"
32 #include "libmdoc.h"
33 #include "libmandoc.h"
34
35 /*
36 * FIXME: this file is deprecated. All future "actions" should be
37 * pushed into mdoc_validate.c.
38 */
39
40 #define POST_ARGS struct mdoc *m, struct mdoc_node *n
41 #define PRE_ARGS struct mdoc *m, struct mdoc_node *n
42
43 #define NUMSIZ 32
44 #define DATESIZ 32
45
46 struct actions {
47 int (*pre)(PRE_ARGS);
48 int (*post)(POST_ARGS);
49 };
50
51 static int concat(struct mdoc *, char *,
52 const struct mdoc_node *, size_t);
53
54 static int post_bl(POST_ARGS);
55 static int post_bl_head(POST_ARGS);
56 static int post_bl_tagwidth(POST_ARGS);
57 static int post_bl_width(POST_ARGS);
58 static int post_dd(POST_ARGS);
59 static int post_dt(POST_ARGS);
60 static int post_nm(POST_ARGS);
61 static int post_os(POST_ARGS);
62 static int post_pa(POST_ARGS);
63 static int post_prol(POST_ARGS);
64 static int post_std(POST_ARGS);
65
66 static const struct actions mdoc_actions[MDOC_MAX] = {
67 { NULL, NULL }, /* Ap */
68 { NULL, post_dd }, /* Dd */
69 { NULL, post_dt }, /* Dt */
70 { NULL, post_os }, /* Os */
71 { NULL, NULL }, /* Sh */
72 { NULL, NULL }, /* Ss */
73 { NULL, NULL }, /* Pp */
74 { NULL, NULL }, /* D1 */
75 { NULL, NULL }, /* Dl */
76 { NULL, NULL }, /* Bd */
77 { NULL, NULL }, /* Ed */
78 { NULL, post_bl }, /* Bl */
79 { NULL, NULL }, /* El */
80 { NULL, NULL }, /* It */
81 { NULL, NULL }, /* Ad */
82 { NULL, NULL }, /* An */
83 { NULL, NULL }, /* Ar */
84 { NULL, NULL }, /* Cd */
85 { NULL, NULL }, /* Cm */
86 { NULL, NULL }, /* Dv */
87 { NULL, NULL }, /* Er */
88 { NULL, NULL }, /* Ev */
89 { NULL, post_std }, /* Ex */
90 { NULL, NULL }, /* Fa */
91 { NULL, NULL }, /* Fd */
92 { NULL, NULL }, /* Fl */
93 { NULL, NULL }, /* Fn */
94 { NULL, NULL }, /* Ft */
95 { NULL, NULL }, /* Ic */
96 { NULL, NULL }, /* In */
97 { NULL, NULL }, /* Li */
98 { NULL, NULL }, /* Nd */
99 { NULL, post_nm }, /* Nm */
100 { NULL, NULL }, /* Op */
101 { NULL, NULL }, /* Ot */
102 { NULL, post_pa }, /* Pa */
103 { NULL, post_std }, /* Rv */
104 { NULL, NULL }, /* St */
105 { NULL, NULL }, /* Va */
106 { NULL, NULL }, /* Vt */
107 { NULL, NULL }, /* Xr */
108 { NULL, NULL }, /* %A */
109 { NULL, NULL }, /* %B */
110 { NULL, NULL }, /* %D */
111 { NULL, NULL }, /* %I */
112 { NULL, NULL }, /* %J */
113 { NULL, NULL }, /* %N */
114 { NULL, NULL }, /* %O */
115 { NULL, NULL }, /* %P */
116 { NULL, NULL }, /* %R */
117 { NULL, NULL }, /* %T */
118 { NULL, NULL }, /* %V */
119 { NULL, NULL }, /* Ac */
120 { NULL, NULL }, /* Ao */
121 { NULL, NULL }, /* Aq */
122 { NULL, NULL }, /* At */
123 { NULL, NULL }, /* Bc */
124 { NULL, NULL }, /* Bf */
125 { NULL, NULL }, /* Bo */
126 { NULL, NULL }, /* Bq */
127 { NULL, NULL }, /* Bsx */
128 { NULL, NULL }, /* Bx */
129 { NULL, NULL }, /* Db */
130 { NULL, NULL }, /* Dc */
131 { NULL, NULL }, /* Do */
132 { NULL, NULL }, /* Dq */
133 { NULL, NULL }, /* Ec */
134 { NULL, NULL }, /* Ef */
135 { NULL, NULL }, /* Em */
136 { NULL, NULL }, /* Eo */
137 { NULL, NULL }, /* Fx */
138 { NULL, NULL }, /* Ms */
139 { NULL, NULL }, /* No */
140 { NULL, NULL }, /* Ns */
141 { NULL, NULL }, /* Nx */
142 { NULL, NULL }, /* Ox */
143 { NULL, NULL }, /* Pc */
144 { NULL, NULL }, /* Pf */
145 { NULL, NULL }, /* Po */
146 { NULL, NULL }, /* Pq */
147 { NULL, NULL }, /* Qc */
148 { NULL, NULL }, /* Ql */
149 { NULL, NULL }, /* Qo */
150 { NULL, NULL }, /* Qq */
151 { NULL, NULL }, /* Re */
152 { NULL, NULL }, /* Rs */
153 { NULL, NULL }, /* Sc */
154 { NULL, NULL }, /* So */
155 { NULL, NULL }, /* Sq */
156 { NULL, NULL }, /* Sm */
157 { NULL, NULL }, /* Sx */
158 { NULL, NULL }, /* Sy */
159 { NULL, NULL }, /* Tn */
160 { NULL, NULL }, /* Ux */
161 { NULL, NULL }, /* Xc */
162 { NULL, NULL }, /* Xo */
163 { NULL, NULL }, /* Fo */
164 { NULL, NULL }, /* Fc */
165 { NULL, NULL }, /* Oo */
166 { NULL, NULL }, /* Oc */
167 { NULL, NULL }, /* Bk */
168 { NULL, NULL }, /* Ek */
169 { NULL, NULL }, /* Bt */
170 { NULL, NULL }, /* Hf */
171 { NULL, NULL }, /* Fr */
172 { NULL, NULL }, /* Ud */
173 { NULL, NULL }, /* Lb */
174 { NULL, NULL }, /* Lp */
175 { NULL, NULL }, /* Lk */
176 { NULL, NULL }, /* Mt */
177 { NULL, NULL }, /* Brq */
178 { NULL, NULL }, /* Bro */
179 { NULL, NULL }, /* Brc */
180 { NULL, NULL }, /* %C */
181 { NULL, NULL }, /* Es */
182 { NULL, NULL }, /* En */
183 { NULL, NULL }, /* Dx */
184 { NULL, NULL }, /* %Q */
185 { NULL, NULL }, /* br */
186 { NULL, NULL }, /* sp */
187 { NULL, NULL }, /* %U */
188 { NULL, NULL }, /* Ta */
189 };
190
191
192 int
193 mdoc_action_pre(struct mdoc *m, struct mdoc_node *n)
194 {
195
196 switch (n->type) {
197 case (MDOC_ROOT):
198 /* FALLTHROUGH */
199 case (MDOC_TEXT):
200 return(1);
201 default:
202 break;
203 }
204
205 if (NULL == mdoc_actions[n->tok].pre)
206 return(1);
207 return((*mdoc_actions[n->tok].pre)(m, n));
208 }
209
210
211 int
212 mdoc_action_post(struct mdoc *m)
213 {
214
215 if (MDOC_ACTED & m->last->flags)
216 return(1);
217 m->last->flags |= MDOC_ACTED;
218
219 switch (m->last->type) {
220 case (MDOC_TEXT):
221 /* FALLTHROUGH */
222 case (MDOC_ROOT):
223 return(1);
224 default:
225 break;
226 }
227
228 if (NULL == mdoc_actions[m->last->tok].post)
229 return(1);
230 return((*mdoc_actions[m->last->tok].post)(m, m->last));
231 }
232
233
234 /*
235 * Concatenate sibling nodes together. All siblings must be of type
236 * MDOC_TEXT or an assertion is raised. Concatenation is separated by a
237 * single whitespace.
238 */
239 static int
240 concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz)
241 {
242
243 assert(sz);
244 p[0] = '\0';
245 for ( ; n; n = n->next) {
246 assert(MDOC_TEXT == n->type);
247 /*
248 * XXX: yes, these can technically be resized, but it's
249 * highly unlikely that we're going to get here, so let
250 * it slip for now.
251 */
252 if (strlcat(p, n->string, sz) >= sz) {
253 mdoc_nmsg(m, n, MANDOCERR_MEM);
254 return(0);
255 }
256 if (NULL == n->next)
257 continue;
258 if (strlcat(p, " ", sz) >= sz) {
259 mdoc_nmsg(m, n, MANDOCERR_MEM);
260 return(0);
261 }
262 }
263
264 return(1);
265 }
266
267
268 /*
269 * Macros accepting `-std' as an argument have the name of the current
270 * document (`Nm') filled in as the argument if it's not provided.
271 */
272 static int
273 post_std(POST_ARGS)
274 {
275 struct mdoc_node *nn;
276
277 if (n->child)
278 return(1);
279 if (NULL == m->meta.name)
280 return(1);
281
282 nn = n;
283 m->next = MDOC_NEXT_CHILD;
284
285 if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
286 return(0);
287 m->last = nn;
288 return(1);
289 }
290
291
292 /*
293 * The `Nm' macro's first use sets the name of the document. See also
294 * post_std(), etc.
295 */
296 static int
297 post_nm(POST_ARGS)
298 {
299 char buf[BUFSIZ];
300
301 if (m->meta.name)
302 return(1);
303 if ( ! concat(m, buf, n->child, BUFSIZ))
304 return(0);
305 m->meta.name = mandoc_strdup(buf);
306 return(1);
307 }
308
309 /*
310 * Parse out the contents of `Dt'. See in-line documentation for how we
311 * handle the various fields of this macro.
312 */
313 static int
314 post_dt(POST_ARGS)
315 {
316 struct mdoc_node *nn;
317 const char *cp;
318
319 if (m->meta.title)
320 free(m->meta.title);
321 if (m->meta.vol)
322 free(m->meta.vol);
323 if (m->meta.arch)
324 free(m->meta.arch);
325
326 m->meta.title = m->meta.vol = m->meta.arch = NULL;
327 /* Handles: `.Dt'
328 * --> title = unknown, volume = local, msec = 0, arch = NULL
329 */
330
331 if (NULL == (nn = n->child)) {
332 /* XXX: make these macro values. */
333 /* FIXME: warn about missing values. */
334 m->meta.title = mandoc_strdup("UNKNOWN");
335 m->meta.vol = mandoc_strdup("LOCAL");
336 m->meta.msec = mandoc_strdup("1");
337 return(post_prol(m, n));
338 }
339
340 /* Handles: `.Dt TITLE'
341 * --> title = TITLE, volume = local, msec = 0, arch = NULL
342 */
343
344 m->meta.title = mandoc_strdup
345 ('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
346
347 if (NULL == (nn = nn->next)) {
348 /* FIXME: warn about missing msec. */
349 /* XXX: make this a macro value. */
350 m->meta.vol = mandoc_strdup("LOCAL");
351 m->meta.msec = mandoc_strdup("1");
352 return(post_prol(m, n));
353 }
354
355 /* Handles: `.Dt TITLE SEC'
356 * --> title = TITLE, volume = SEC is msec ?
357 * format(msec) : SEC,
358 * msec = SEC is msec ? atoi(msec) : 0,
359 * arch = NULL
360 */
361
362 cp = mdoc_a2msec(nn->string);
363 if (cp) {
364 m->meta.vol = mandoc_strdup(cp);
365 m->meta.msec = mandoc_strdup(nn->string);
366 } else if (mdoc_nmsg(m, n, MANDOCERR_BADMSEC)) {
367 m->meta.vol = mandoc_strdup(nn->string);
368 m->meta.msec = mandoc_strdup(nn->string);
369 } else
370 return(0);
371
372 if (NULL == (nn = nn->next))
373 return(post_prol(m, n));
374
375 /* Handles: `.Dt TITLE SEC VOL'
376 * --> title = TITLE, volume = VOL is vol ?
377 * format(VOL) :
378 * VOL is arch ? format(arch) :
379 * VOL
380 */
381
382 cp = mdoc_a2vol(nn->string);
383 if (cp) {
384 free(m->meta.vol);
385 m->meta.vol = mandoc_strdup(cp);
386 } else {
387 /* FIXME: warn about bad arch. */
388 cp = mdoc_a2arch(nn->string);
389 if (NULL == cp) {
390 free(m->meta.vol);
391 m->meta.vol = mandoc_strdup(nn->string);
392 } else
393 m->meta.arch = mandoc_strdup(cp);
394 }
395
396 /* Ignore any subsequent parameters... */
397 /* FIXME: warn about subsequent parameters. */
398
399 return(post_prol(m, n));
400 }
401
402
403 /*
404 * Set the operating system by way of the `Os' macro. Note that if an
405 * argument isn't provided and -DOSNAME="\"foo\"" is provided during
406 * compilation, this value will be used instead of filling in "sysname
407 * release" from uname().
408 */
409 static int
410 post_os(POST_ARGS)
411 {
412 char buf[BUFSIZ];
413 #ifndef OSNAME
414 struct utsname utsname;
415 #endif
416
417 if (m->meta.os)
418 free(m->meta.os);
419
420 if ( ! concat(m, buf, n->child, BUFSIZ))
421 return(0);
422
423 /* XXX: yes, these can all be dynamically-adjusted buffers, but
424 * it's really not worth the extra hackery.
425 */
426
427 if ('\0' == buf[0]) {
428 #ifdef OSNAME
429 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
430 mdoc_nmsg(m, n, MANDOCERR_MEM);
431 return(0);
432 }
433 #else /*!OSNAME */
434 if (-1 == uname(&utsname))
435 return(mdoc_nmsg(m, n, MANDOCERR_UTSNAME));
436
437 if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
438 mdoc_nmsg(m, n, MANDOCERR_MEM);
439 return(0);
440 }
441 if (strlcat(buf, " ", 64) >= BUFSIZ) {
442 mdoc_nmsg(m, n, MANDOCERR_MEM);
443 return(0);
444 }
445 if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
446 mdoc_nmsg(m, n, MANDOCERR_MEM);
447 return(0);
448 }
449 #endif /*!OSNAME*/
450 }
451
452 m->meta.os = mandoc_strdup(buf);
453 return(post_prol(m, n));
454 }
455
456
457 /*
458 * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
459 * Uses the first head macro. NOTE AGAIN: this is ONLY if the -width
460 * argument has NOT been provided. See post_bl_width() for converting
461 * the -width string.
462 */
463 static int
464 post_bl_tagwidth(POST_ARGS)
465 {
466 struct mdoc_node *nn;
467 size_t sz, ssz;
468 int i;
469 char buf[NUMSIZ];
470
471 sz = 10;
472
473 for (nn = n->body->child; nn; nn = nn->next) {
474 if (MDOC_It != nn->tok)
475 continue;
476
477 assert(MDOC_BLOCK == nn->type);
478 nn = nn->head->child;
479
480 if (nn == NULL) {
481 /* No -width for .Bl and first .It is emtpy */
482 if ( ! mdoc_nmsg(m, n, MANDOCERR_NOWIDTHARG))
483 return(0);
484 break;
485 }
486
487 if (MDOC_TEXT == nn->type) {
488 sz = strlen(nn->string) + 1;
489 break;
490 }
491
492 if (0 != (ssz = mdoc_macro2len(nn->tok)))
493 sz = ssz;
494 else if ( ! mdoc_nmsg(m, n, MANDOCERR_NOWIDTHARG))
495 return(0);
496
497 break;
498 }
499
500 /* Defaults to ten ens. */
501
502 snprintf(buf, NUMSIZ, "%zun", sz);
503
504 /*
505 * We have to dynamically add this to the macro's argument list.
506 * We're guaranteed that a MDOC_Width doesn't already exist.
507 */
508
509 assert(n->args);
510 i = (int)(n->args->argc)++;
511
512 n->args->argv = mandoc_realloc(n->args->argv,
513 n->args->argc * sizeof(struct mdoc_argv));
514
515 n->args->argv[i].arg = MDOC_Width;
516 n->args->argv[i].line = n->line;
517 n->args->argv[i].pos = n->pos;
518 n->args->argv[i].sz = 1;
519 n->args->argv[i].value = mandoc_malloc(sizeof(char *));
520 n->args->argv[i].value[0] = mandoc_strdup(buf);
521
522 /* Set our width! */
523 n->data.Bl->width = n->args->argv[i].value[0];
524 return(1);
525 }
526
527
528 /*
529 * Calculate the real width of a list from the -width string, which may
530 * contain a macro (with a known default width), a literal string, or a
531 * scaling width.
532 */
533 static int
534 post_bl_width(POST_ARGS)
535 {
536 size_t width;
537 int i;
538 enum mdoct tok;
539 char buf[NUMSIZ];
540
541 /*
542 * If the value to -width is a macro, then we re-write it to be
543 * the macro's width as set in share/tmac/mdoc/doc-common.
544 */
545
546 if (0 == strcmp(n->data.Bl->width, "Ds"))
547 width = 6;
548 else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl->width)))
549 return(1);
550 else if (0 == (width = mdoc_macro2len(tok)))
551 return(mdoc_nmsg(m, n, MANDOCERR_BADWIDTH));
552
553 /* The value already exists: free and reallocate it. */
554
555 assert(n->args);
556
557 for (i = 0; i < (int)n->args->argc; i++)
558 if (MDOC_Width == n->args->argv[i].arg)
559 break;
560
561 assert(i < (int)n->args->argc);
562
563 snprintf(buf, NUMSIZ, "%zun", width);
564 free(n->args->argv[i].value[0]);
565 n->args->argv[i].value[0] = mandoc_strdup(buf);
566
567 /* Set our width! */
568 n->data.Bl->width = n->args->argv[i].value[0];
569 return(1);
570 }
571
572
573 /*
574 * Do processing for -column lists, which can have two distinct styles
575 * of invocation. Merge this two styles into a consistent form.
576 */
577 /* ARGSUSED */
578 static int
579 post_bl_head(POST_ARGS)
580 {
581 int i, c;
582 struct mdoc_node *np, *nn, *nnp;
583
584 if (LIST_column != n->data.Bl->type)
585 return(1);
586 else if (NULL == n->child)
587 return(1);
588
589 np = n->parent;
590 assert(np->args);
591
592 for (c = 0; c < (int)np->args->argc; c++)
593 if (MDOC_Column == np->args->argv[c].arg)
594 break;
595
596 assert(c < (int)np->args->argc);
597 assert(0 == np->args->argv[c].sz);
598
599 /*
600 * Accomodate for new-style groff column syntax. Shuffle the
601 * child nodes, all of which must be TEXT, as arguments for the
602 * column field. Then, delete the head children.
603 */
604
605 np->args->argv[c].sz = (size_t)n->nchild;
606 np->args->argv[c].value = mandoc_malloc
607 ((size_t)n->nchild * sizeof(char *));
608
609 n->data.Bl->ncols = np->args->argv[c].sz;
610 n->data.Bl->cols = (const char **)np->args->argv[c].value;
611
612 for (i = 0, nn = n->child; nn; i++) {
613 np->args->argv[c].value[i] = nn->string;
614 nn->string = NULL;
615 nnp = nn;
616 nn = nn->next;
617 mdoc_node_delete(NULL, nnp);
618 }
619
620 n->nchild = 0;
621 n->child = NULL;
622 return(1);
623 }
624
625
626 static int
627 post_bl(POST_ARGS)
628 {
629
630 if (MDOC_HEAD == n->type)
631 return(post_bl_head(m, n));
632 if (MDOC_BLOCK != n->type)
633 return(1);
634
635 /*
636 * These are fairly complicated, so we've broken them into two
637 * functions. post_bl_tagwidth() is called when a -tag is
638 * specified, but no -width (it must be guessed). The second
639 * when a -width is specified (macro indicators must be
640 * rewritten into real lengths).
641 */
642
643 if (LIST_tag == n->data.Bl->type && NULL == n->data.Bl->width) {
644 if ( ! post_bl_tagwidth(m, n))
645 return(0);
646 } else if (NULL != n->data.Bl->width) {
647 if ( ! post_bl_width(m, n))
648 return(0);
649 } else
650 return(1);
651
652 assert(n->data.Bl->width);
653 return(1);
654 }
655
656
657 /*
658 * The `Pa' macro defaults to a tilde if no value is provided as an
659 * argument.
660 */
661 static int
662 post_pa(POST_ARGS)
663 {
664 struct mdoc_node *np;
665
666 if (n->child)
667 return(1);
668
669 np = n;
670 m->next = MDOC_NEXT_CHILD;
671 if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
672 return(0);
673 m->last = np;
674 return(1);
675 }
676
677
678 /*
679 * Parse the date field in `Dd'.
680 */
681 static int
682 post_dd(POST_ARGS)
683 {
684 char buf[DATESIZ];
685
686 if (NULL == n->child) {
687 m->meta.date = time(NULL);
688 return(post_prol(m, n));
689 }
690
691 if ( ! concat(m, buf, n->child, DATESIZ))
692 return(0);
693
694 m->meta.date = mandoc_a2time
695 (MTIME_MDOCDATE | MTIME_CANONICAL, buf);
696
697 if (0 == m->meta.date) {
698 if ( ! mdoc_nmsg(m, n, MANDOCERR_BADDATE))
699 return(0);
700 m->meta.date = time(NULL);
701 }
702
703 return(post_prol(m, n));
704 }
705
706
707 /*
708 * Remove prologue macros from the document after they're processed.
709 * The final document uses mdoc_meta for these values and discards the
710 * originals.
711 */
712 static int
713 post_prol(POST_ARGS)
714 {
715
716 mdoc_node_delete(m, n);
717 if (m->meta.title && m->meta.date && m->meta.os)
718 m->flags |= MDOC_PBODY;
719 return(1);
720 }