]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_action.c
-offset string can now be blank (supplied with 6n as stipulated by mdoc.samples).
[mandoc.git] / mdoc_action.c
1 /* $Id: mdoc_action.c,v 1.38 2009/09/24 13:03:32 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 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 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 #include <sys/utsname.h>
18
19 #include <assert.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "libmdoc.h"
26
27 #define POST_ARGS struct mdoc *m, struct mdoc_node *n
28 #define PRE_ARGS struct mdoc *m, const struct mdoc_node *n
29
30 struct actions {
31 int (*pre)(PRE_ARGS);
32 int (*post)(POST_ARGS);
33 };
34
35 static int post_ar(POST_ARGS);
36 static int post_at(POST_ARGS);
37 static int post_bl(POST_ARGS);
38 static int post_bl_head(POST_ARGS);
39 static int post_bl_tagwidth(POST_ARGS);
40 static int post_bl_width(POST_ARGS);
41 static int post_dd(POST_ARGS);
42 static int post_display(POST_ARGS);
43 static int post_dt(POST_ARGS);
44 static int post_lb(POST_ARGS);
45 static int post_nm(POST_ARGS);
46 static int post_os(POST_ARGS);
47 static int post_prol(POST_ARGS);
48 static int post_sh(POST_ARGS);
49 static int post_st(POST_ARGS);
50 static int post_std(POST_ARGS);
51 static int post_tilde(POST_ARGS);
52
53 static int pre_bd(PRE_ARGS);
54 static int pre_bl(PRE_ARGS);
55 static int pre_dl(PRE_ARGS);
56 static int pre_offset(PRE_ARGS);
57
58 static const struct actions mdoc_actions[MDOC_MAX] = {
59 { NULL, NULL }, /* Ap */
60 { NULL, post_dd }, /* Dd */
61 { NULL, post_dt }, /* Dt */
62 { NULL, post_os }, /* Os */
63 { NULL, post_sh }, /* Sh */
64 { NULL, NULL }, /* Ss */
65 { NULL, NULL }, /* Pp */
66 { NULL, NULL }, /* D1 */
67 { pre_dl, post_display }, /* Dl */
68 { pre_bd, post_display }, /* Bd */
69 { NULL, NULL }, /* Ed */
70 { pre_bl, post_bl }, /* Bl */
71 { NULL, NULL }, /* El */
72 { NULL, NULL }, /* It */
73 { NULL, NULL }, /* Ad */
74 { NULL, NULL }, /* An */
75 { NULL, post_ar }, /* Ar */
76 { NULL, NULL }, /* Cd */
77 { NULL, NULL }, /* Cm */
78 { NULL, NULL }, /* Dv */
79 { NULL, NULL }, /* Er */
80 { NULL, NULL }, /* Ev */
81 { NULL, post_std }, /* Ex */
82 { NULL, NULL }, /* Fa */
83 { NULL, NULL }, /* Fd */
84 { NULL, NULL }, /* Fl */
85 { NULL, NULL }, /* Fn */
86 { NULL, NULL }, /* Ft */
87 { NULL, NULL }, /* Ic */
88 { NULL, NULL }, /* In */
89 { NULL, NULL }, /* Li */
90 { NULL, NULL }, /* Nd */
91 { NULL, post_nm }, /* Nm */
92 { NULL, NULL }, /* Op */
93 { NULL, NULL }, /* Ot */
94 { NULL, post_tilde }, /* Pa */
95 { NULL, post_std }, /* Rv */
96 { NULL, post_st }, /* St */
97 { NULL, NULL }, /* Va */
98 { NULL, NULL }, /* Vt */
99 { NULL, NULL }, /* Xr */
100 { NULL, NULL }, /* %A */
101 { NULL, NULL }, /* %B */
102 { NULL, NULL }, /* %D */
103 { NULL, NULL }, /* %I */
104 { NULL, NULL }, /* %J */
105 { NULL, NULL }, /* %N */
106 { NULL, NULL }, /* %O */
107 { NULL, NULL }, /* %P */
108 { NULL, NULL }, /* %R */
109 { NULL, NULL }, /* %T */
110 { NULL, NULL }, /* %V */
111 { NULL, NULL }, /* Ac */
112 { NULL, NULL }, /* Ao */
113 { NULL, NULL }, /* Aq */
114 { NULL, post_at }, /* At */
115 { NULL, NULL }, /* Bc */
116 { NULL, NULL }, /* Bf */
117 { NULL, NULL }, /* Bo */
118 { NULL, NULL }, /* Bq */
119 { NULL, NULL }, /* Bsx */
120 { NULL, NULL }, /* Bx */
121 { NULL, NULL }, /* Db */
122 { NULL, NULL }, /* Dc */
123 { NULL, NULL }, /* Do */
124 { NULL, NULL }, /* Dq */
125 { NULL, NULL }, /* Ec */
126 { NULL, NULL }, /* Ef */
127 { NULL, NULL }, /* Em */
128 { NULL, NULL }, /* Eo */
129 { NULL, NULL }, /* Fx */
130 { NULL, NULL }, /* Ms */
131 { NULL, NULL }, /* No */
132 { NULL, NULL }, /* Ns */
133 { NULL, NULL }, /* Nx */
134 { NULL, NULL }, /* Ox */
135 { NULL, NULL }, /* Pc */
136 { NULL, NULL }, /* Pf */
137 { NULL, NULL }, /* Po */
138 { NULL, NULL }, /* Pq */
139 { NULL, NULL }, /* Qc */
140 { NULL, NULL }, /* Ql */
141 { NULL, NULL }, /* Qo */
142 { NULL, NULL }, /* Qq */
143 { NULL, NULL }, /* Re */
144 { NULL, NULL }, /* Rs */
145 { NULL, NULL }, /* Sc */
146 { NULL, NULL }, /* So */
147 { NULL, NULL }, /* Sq */
148 { NULL, NULL }, /* Sm */
149 { NULL, NULL }, /* Sx */
150 { NULL, NULL }, /* Sy */
151 { NULL, NULL }, /* Tn */
152 { NULL, NULL }, /* Ux */
153 { NULL, NULL }, /* Xc */
154 { NULL, NULL }, /* Xo */
155 { NULL, NULL }, /* Fo */
156 { NULL, NULL }, /* Fc */
157 { NULL, NULL }, /* Oo */
158 { NULL, NULL }, /* Oc */
159 { NULL, NULL }, /* Bk */
160 { NULL, NULL }, /* Ek */
161 { NULL, NULL }, /* Bt */
162 { NULL, NULL }, /* Hf */
163 { NULL, NULL }, /* Fr */
164 { NULL, NULL }, /* Ud */
165 { NULL, post_lb }, /* Lb */
166 { NULL, NULL }, /* Lp */
167 { NULL, post_tilde }, /* Lk */
168 { NULL, NULL }, /* Mt */
169 { NULL, NULL }, /* Brq */
170 { NULL, NULL }, /* Bro */
171 { NULL, NULL }, /* Brc */
172 { NULL, NULL }, /* %C */
173 { NULL, NULL }, /* Es */
174 { NULL, NULL }, /* En */
175 { NULL, NULL }, /* Dx */
176 { NULL, NULL }, /* %Q */
177 { NULL, NULL }, /* br */
178 { NULL, NULL }, /* sp */
179 };
180
181 static int concat(struct mdoc *, const struct mdoc_node *,
182 char *, size_t);
183
184 #ifdef __linux__
185 extern size_t strlcat(char *, const char *, size_t);
186 #endif
187
188
189 int
190 mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
191 {
192
193 switch (n->type) {
194 case (MDOC_ROOT):
195 /* FALLTHROUGH */
196 case (MDOC_TEXT):
197 return(1);
198 default:
199 break;
200 }
201
202 if (NULL == mdoc_actions[n->tok].pre)
203 return(1);
204 return((*mdoc_actions[n->tok].pre)(m, n));
205 }
206
207
208 int
209 mdoc_action_post(struct mdoc *m)
210 {
211
212 if (MDOC_ACTED & m->last->flags)
213 return(1);
214 m->last->flags |= MDOC_ACTED;
215
216 switch (m->last->type) {
217 case (MDOC_TEXT):
218 /* FALLTHROUGH */
219 case (MDOC_ROOT):
220 return(1);
221 default:
222 break;
223 }
224
225 if (NULL == mdoc_actions[m->last->tok].post)
226 return(1);
227 return((*mdoc_actions[m->last->tok].post)(m, m->last));
228 }
229
230
231 static int
232 concat(struct mdoc *m, const struct mdoc_node *n,
233 char *buf, size_t sz)
234 {
235
236 for ( ; n; n = n->next) {
237 assert(MDOC_TEXT == n->type);
238 if (strlcat(buf, n->string, sz) >= sz)
239 return(mdoc_nerr(m, n, ETOOLONG));
240 if (NULL == n->next)
241 continue;
242 if (strlcat(buf, " ", sz) >= sz)
243 return(mdoc_nerr(m, n, ETOOLONG));
244 }
245
246 return(1);
247 }
248
249
250 static int
251 post_std(POST_ARGS)
252 {
253 struct mdoc_node *nn;
254
255 if (n->child)
256 return(1);
257
258 nn = n;
259 m->next = MDOC_NEXT_CHILD;
260 assert(m->meta.name);
261 if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
262 return(0);
263 m->last = nn;
264
265 return(1);
266 }
267
268
269 static int
270 post_nm(POST_ARGS)
271 {
272 char buf[64];
273
274 if (m->meta.name)
275 return(1);
276
277 buf[0] = 0;
278 if ( ! concat(m, n->child, buf, sizeof(buf)))
279 return(0);
280 if (NULL == (m->meta.name = strdup(buf)))
281 return(mdoc_nerr(m, n, EMALLOC));
282
283 return(1);
284 }
285
286
287 static int
288 post_lb(POST_ARGS)
289 {
290 const char *p;
291 char *buf;
292 size_t sz;
293
294 assert(MDOC_TEXT == n->child->type);
295 p = mdoc_a2lib(n->child->string);
296 if (NULL == p) {
297 sz = strlen(n->child->string) +
298 2 + strlen("\\(lqlibrary\\(rq");
299 buf = malloc(sz);
300 if (NULL == buf)
301 return(mdoc_nerr(m, n, EMALLOC));
302 (void)snprintf(buf, sz, "library \\(lq%s\\(rq",
303 n->child->string);
304 free(n->child->string);
305 n->child->string = buf;
306 return(1);
307 }
308
309 free(n->child->string);
310 n->child->string = strdup(p);
311 if (NULL == n->child->string)
312 return(mdoc_nerr(m, n, EMALLOC));
313
314 return(1);
315 }
316
317
318 static int
319 post_st(POST_ARGS)
320 {
321 const char *p;
322
323 assert(MDOC_TEXT == n->child->type);
324 p = mdoc_a2st(n->child->string);
325 assert(p);
326 free(n->child->string);
327 n->child->string = strdup(p);
328 if (NULL == n->child->string)
329 return(mdoc_nerr(m, n, EMALLOC));
330
331 return(1);
332 }
333
334
335 static int
336 post_at(POST_ARGS)
337 {
338 struct mdoc_node *nn;
339 const char *p;
340
341 if (n->child) {
342 assert(MDOC_TEXT == n->child->type);
343 p = mdoc_a2att(n->child->string);
344 assert(p);
345 free(n->child->string);
346 n->child->string = strdup(p);
347 if (NULL == n->child->string)
348 return(mdoc_nerr(m, n, EMALLOC));
349 return(1);
350 }
351
352 nn = n;
353 m->next = MDOC_NEXT_CHILD;
354
355 if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
356 return(0);
357 m->last = nn;
358
359 return(1);
360 }
361
362
363 static int
364 post_sh(POST_ARGS)
365 {
366 enum mdoc_sec sec;
367 char buf[64];
368
369 /*
370 * We keep track of the current section /and/ the "named"
371 * section, which is one of the conventional ones, in order to
372 * check ordering.
373 */
374
375 if (MDOC_HEAD != n->type)
376 return(1);
377
378 buf[0] = 0;
379 if ( ! concat(m, n->child, buf, sizeof(buf)))
380 return(0);
381 if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
382 m->lastnamed = sec;
383
384 switch ((m->lastsec = sec)) {
385 case (SEC_RETURN_VALUES):
386 /* FALLTHROUGH */
387 case (SEC_ERRORS):
388 switch (m->meta.msec) {
389 case (2):
390 /* FALLTHROUGH */
391 case (3):
392 /* FALLTHROUGH */
393 case (9):
394 break;
395 default:
396 return(mdoc_nwarn(m, n, EBADSEC));
397 }
398 break;
399 default:
400 break;
401 }
402 return(1);
403 }
404
405
406 static int
407 post_dt(POST_ARGS)
408 {
409 struct mdoc_node *nn;
410 const char *cp;
411 char *ep;
412 long lval;
413
414 if (m->meta.title)
415 free(m->meta.title);
416 if (m->meta.vol)
417 free(m->meta.vol);
418 if (m->meta.arch)
419 free(m->meta.arch);
420
421 m->meta.title = m->meta.vol = m->meta.arch = NULL;
422 m->meta.msec = 0;
423
424 /* Handles: `.Dt'
425 * --> title = unknown, volume = local, msec = 0, arch = NULL
426 */
427
428 if (NULL == (nn = n->child)) {
429 if (NULL == (m->meta.title = strdup("unknown")))
430 return(mdoc_nerr(m, n, EMALLOC));
431 if (NULL == (m->meta.vol = strdup("local")))
432 return(mdoc_nerr(m, n, EMALLOC));
433 return(post_prol(m, n));
434 }
435
436 /* Handles: `.Dt TITLE'
437 * --> title = TITLE, volume = local, msec = 0, arch = NULL
438 */
439
440 if (NULL == (m->meta.title = strdup(nn->string)))
441 return(mdoc_nerr(m, n, EMALLOC));
442
443 if (NULL == (nn = nn->next)) {
444 if (NULL == (m->meta.vol = strdup("local")))
445 return(mdoc_nerr(m, n, EMALLOC));
446 return(post_prol(m, n));
447 }
448
449 /* Handles: `.Dt TITLE SEC'
450 * --> title = TITLE, volume = SEC is msec ?
451 * format(msec) : SEC,
452 * msec = SEC is msec ? atoi(msec) : 0,
453 * arch = NULL
454 */
455
456 cp = mdoc_a2msec(nn->string);
457 if (cp) {
458 if (NULL == (m->meta.vol = strdup(cp)))
459 return(mdoc_nerr(m, n, EMALLOC));
460 errno = 0;
461 lval = strtol(nn->string, &ep, 10);
462 if (nn->string[0] != '\0' && *ep == '\0')
463 m->meta.msec = (int)lval;
464 } else if (NULL == (m->meta.vol = strdup(nn->string)))
465 return(mdoc_nerr(m, n, EMALLOC));
466
467 if (NULL == (nn = nn->next))
468 return(post_prol(m, n));
469
470 /* Handles: `.Dt TITLE SEC VOL'
471 * --> title = TITLE, volume = VOL is vol ?
472 * format(VOL) :
473 * VOL is arch ? format(arch) :
474 * VOL
475 */
476
477 cp = mdoc_a2vol(nn->string);
478 if (cp) {
479 free(m->meta.vol);
480 if (NULL == (m->meta.vol = strdup(cp)))
481 return(mdoc_nerr(m, n, EMALLOC));
482 } else {
483 cp = mdoc_a2arch(nn->string);
484 if (NULL == cp) {
485 free(m->meta.vol);
486 if (NULL == (m->meta.vol = strdup(nn->string)))
487 return(mdoc_nerr(m, n, EMALLOC));
488 } else if (NULL == (m->meta.arch = strdup(cp)))
489 return(mdoc_nerr(m, n, EMALLOC));
490 }
491
492 /* Ignore any subsequent parameters... */
493
494 return(post_prol(m, n));
495 }
496
497
498 static int
499 post_os(POST_ARGS)
500 {
501 char buf[64];
502 struct utsname utsname;
503
504 if (m->meta.os)
505 free(m->meta.os);
506
507 buf[0] = 0;
508 if ( ! concat(m, n->child, buf, sizeof(buf)))
509 return(0);
510
511 if (0 == buf[0]) {
512 if (-1 == uname(&utsname))
513 return(mdoc_nerr(m, n, EUTSNAME));
514 if (strlcat(buf, utsname.sysname, 64) >= 64)
515 return(mdoc_nerr(m, n, ETOOLONG));
516 if (strlcat(buf, " ", 64) >= 64)
517 return(mdoc_nerr(m, n, ETOOLONG));
518 if (strlcat(buf, utsname.release, 64) >= 64)
519 return(mdoc_nerr(m, n, ETOOLONG));
520 }
521
522 if (NULL == (m->meta.os = strdup(buf)))
523 return(mdoc_nerr(m, n, EMALLOC));
524
525 return(post_prol(m, n));
526 }
527
528
529 /*
530 * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
531 * Uses the first head macro.
532 */
533 static int
534 post_bl_tagwidth(POST_ARGS)
535 {
536 struct mdoc_node *nn;
537 int sz;
538 char buf[32];
539
540 /*
541 * Use the text width, if a text node, or the default macro
542 * width if a macro.
543 */
544
545 nn = n->body->child;
546 if (nn) {
547 assert(MDOC_BLOCK == nn->type);
548 assert(MDOC_It == nn->tok);
549 nn = nn->head->child;
550 }
551
552 sz = 10; /* Default size. */
553
554 if (nn) {
555 if (MDOC_TEXT != nn->type) {
556 if (0 == (sz = (int)mdoc_macro2len(nn->tok)))
557 if ( ! mdoc_nwarn(m, n, ENOWIDTH))
558 return(0);
559 } else
560 sz = (int)strlen(nn->string) + 1;
561 }
562
563 if (-1 == snprintf(buf, sizeof(buf), "%dn", sz))
564 return(mdoc_nerr(m, n, ENUMFMT));
565
566 /*
567 * We have to dynamically add this to the macro's argument list.
568 * We're guaranteed that a MDOC_Width doesn't already exist.
569 */
570
571 nn = n;
572 assert(nn->args);
573 sz = (int)(nn->args->argc)++;
574
575 nn->args->argv = realloc(nn->args->argv,
576 nn->args->argc * sizeof(struct mdoc_argv));
577
578 if (NULL == nn->args->argv)
579 return(mdoc_nerr(m, n, EMALLOC));
580
581 nn->args->argv[sz].arg = MDOC_Width;
582 nn->args->argv[sz].line = n->line;
583 nn->args->argv[sz].pos = n->pos;
584 nn->args->argv[sz].sz = 1;
585 nn->args->argv[sz].value = calloc(1, sizeof(char *));
586
587 if (NULL == nn->args->argv[sz].value)
588 return(mdoc_nerr(m, n, EMALLOC));
589 if (NULL == (nn->args->argv[sz].value[0] = strdup(buf)))
590 return(mdoc_nerr(m, n, EMALLOC));
591
592 return(1);
593 }
594
595
596 static int
597 post_bl_width(POST_ARGS)
598 {
599 size_t width;
600 int i, tok;
601 char buf[32];
602 char *p;
603
604 if (NULL == n->args)
605 return(1);
606
607 for (i = 0; i < (int)n->args->argc; i++)
608 if (MDOC_Width == n->args->argv[i].arg)
609 break;
610
611 if (i == (int)n->args->argc)
612 return(1);
613 p = n->args->argv[i].value[0];
614
615 /*
616 * If the value to -width is a macro, then we re-write it to be
617 * the macro's width as set in share/tmac/mdoc/doc-common.
618 */
619
620 if (0 == strcmp(p, "Ds"))
621 width = 6;
622 else if (MDOC_MAX == (tok = mdoc_hash_find(p)))
623 return(1);
624 else if (0 == (width = mdoc_macro2len(tok)))
625 return(mdoc_nwarn(m, n, ENOWIDTH));
626
627 /* The value already exists: free and reallocate it. */
628
629 if (-1 == snprintf(buf, sizeof(buf), "%zun", width))
630 return(mdoc_nerr(m, n, ENUMFMT));
631
632 free(n->args->argv[i].value[0]);
633 n->args->argv[i].value[0] = strdup(buf);
634 if (NULL == n->args->argv[i].value[0])
635 return(mdoc_nerr(m, n, EMALLOC));
636
637 return(1);
638 }
639
640
641 /* ARGSUSED */
642 static int
643 post_bl_head(POST_ARGS)
644 {
645 int i, c;
646 struct mdoc_node *np, *nn, *nnp;
647
648 if (NULL == n->child)
649 return(1);
650
651 np = n->parent;
652 assert(np->args);
653
654 for (c = 0; c < (int)np->args->argc; c++)
655 if (MDOC_Column == np->args->argv[c].arg)
656 break;
657
658 /* Only process -column. */
659
660 if (c == (int)np->args->argc)
661 return(1);
662
663 assert(0 == np->args->argv[c].sz);
664
665 /*
666 * Accomodate for new-style groff column syntax. Shuffle the
667 * child nodes, all of which must be TEXT, as arguments for the
668 * column field. Then, delete the head children.
669 */
670
671 np->args->argv[c].sz = (size_t)n->nchild;
672 np->args->argv[c].value = malloc
673 ((size_t)n->nchild * sizeof(char *));
674
675 for (i = 0, nn = n->child; nn; i++) {
676 np->args->argv[c].value[i] = nn->string;
677 nn->string = NULL;
678 nnp = nn;
679 nn = nn->next;
680 mdoc_node_free(nnp);
681 }
682
683 n->nchild = 0;
684 n->child = NULL;
685
686 return(1);
687 }
688
689
690 static int
691 post_bl(POST_ARGS)
692 {
693 int i, r, len;
694
695 if (MDOC_HEAD == n->type)
696 return(post_bl_head(m, n));
697 if (MDOC_BLOCK != n->type)
698 return(1);
699
700 /*
701 * These are fairly complicated, so we've broken them into two
702 * functions. post_bl_tagwidth() is called when a -tag is
703 * specified, but no -width (it must be guessed). The second
704 * when a -width is specified (macro indicators must be
705 * rewritten into real lengths).
706 */
707
708 len = (int)(n->args ? n->args->argc : 0);
709
710 for (r = i = 0; i < len; i++) {
711 if (MDOC_Tag == n->args->argv[i].arg)
712 r |= 1 << 0;
713 if (MDOC_Width == n->args->argv[i].arg)
714 r |= 1 << 1;
715 }
716
717 if (r & (1 << 0) && ! (r & (1 << 1))) {
718 if ( ! post_bl_tagwidth(m, n))
719 return(0);
720 } else if (r & (1 << 1))
721 if ( ! post_bl_width(m, n))
722 return(0);
723
724 return(1);
725 }
726
727
728 static int
729 post_tilde(POST_ARGS)
730 {
731 struct mdoc_node *np;
732
733 if (n->child)
734 return(1);
735
736 np = n;
737 m->next = MDOC_NEXT_CHILD;
738
739 /* XXX: not documented for `Lk'. */
740 if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
741 return(0);
742 m->last = np;
743
744 return(1);
745 }
746
747
748 static int
749 post_ar(POST_ARGS)
750 {
751 struct mdoc_node *np;
752
753 if (n->child)
754 return(1);
755
756 np = n;
757 m->next = MDOC_NEXT_CHILD;
758 if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
759 return(0);
760 if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
761 return(0);
762 m->last = np;
763
764 return(1);
765 }
766
767
768 static int
769 post_dd(POST_ARGS)
770 {
771 char buf[64];
772
773 buf[0] = 0;
774 if ( ! concat(m, n->child, buf, sizeof(buf)))
775 return(0);
776
777 if (0 == (m->meta.date = mdoc_atotime(buf))) {
778 if ( ! mdoc_nwarn(m, n, EBADDATE))
779 return(0);
780 m->meta.date = time(NULL);
781 }
782
783 return(post_prol(m, n));
784 }
785
786
787 static int
788 post_prol(POST_ARGS)
789 {
790 struct mdoc_node *np;
791
792 /* Remove prologue macros from AST. */
793
794 if (n->parent->child == n)
795 n->parent->child = n->prev;
796 if (n->prev)
797 n->prev->next = NULL;
798
799 np = n;
800 assert(NULL == n->next);
801
802 if (n->prev) {
803 m->last = n->prev;
804 m->next = MDOC_NEXT_SIBLING;
805 } else {
806 m->last = n->parent;
807 m->next = MDOC_NEXT_CHILD;
808 }
809
810 mdoc_node_freelist(np);
811
812 if (m->meta.title && m->meta.date && m->meta.os)
813 m->flags |= MDOC_PBODY;
814
815 return(1);
816 }
817
818
819 static int
820 pre_dl(PRE_ARGS)
821 {
822
823 if (MDOC_BODY == n->type)
824 m->flags |= MDOC_LITERAL;
825 return(1);
826 }
827
828
829 static int
830 pre_offset(PRE_ARGS)
831 {
832 int i;
833
834 /*
835 * Make sure that an empty offset produces an 8n length space as
836 * stipulated by mdoc.samples.
837 */
838
839 assert(n->args);
840 for (i = 0; i < (int)n->args->argc; i++) {
841 if (MDOC_Offset != n->args->argv[i].arg)
842 continue;
843 if (n->args->argv[i].sz)
844 break;
845 assert(1 == n->args->refcnt);
846 /* If no value set, length of <string>. */
847 n->args->argv[i].value =
848 calloc(1, sizeof(char *));
849 if (NULL == n->args->argv[i].value)
850 return(mdoc_nerr(m, n, EMALLOC));
851 n->args->argv[i].sz++;
852 n->args->argv[i].value[0] = strdup("8n");
853 if (NULL == n->args->argv[i].value[0])
854 return(mdoc_nerr(m, n, EMALLOC));
855 break;
856 }
857
858 return(1);
859 }
860
861
862 static int
863 pre_bl(PRE_ARGS)
864 {
865
866 return(MDOC_BLOCK == n->type ? pre_offset(m, n) : 1);
867 }
868
869
870 static int
871 pre_bd(PRE_ARGS)
872 {
873 int i;
874
875 if (MDOC_BLOCK == n->type)
876 return(pre_offset(m, n));
877 if (MDOC_BODY != n->type)
878 return(1);
879
880 /* Enter literal context if `Bd -literal' or `-unfilled'. */
881
882 for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
883 if (MDOC_Literal == n->args->argv[i].arg)
884 m->flags |= MDOC_LITERAL;
885 else if (MDOC_Unfilled == n->args->argv[i].arg)
886 m->flags |= MDOC_LITERAL;
887
888 return(1);
889 }
890
891
892 static int
893 post_display(POST_ARGS)
894 {
895
896 if (MDOC_BODY == n->type)
897 m->flags &= ~MDOC_LITERAL;
898 return(1);
899 }
900
901