Correctly process .%U.
[netbsd-mini2440.git] / external / bsd / mdocml / dist / mdoc_action.c
blobdd973cdd53df0e2ee723bececbf48b0b3071f954
1 /* $Vendor-Id: mdoc_action.c,v 1.44 2009/10/26 04:09:45 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 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 above
7 * copyright notice and this permission notice appear in all copies.
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.
17 #ifndef OSNAME
18 #include <sys/utsname.h>
19 #endif
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
28 #include "libmdoc.h"
30 #define POST_ARGS struct mdoc *m, struct mdoc_node *n
31 #define PRE_ARGS struct mdoc *m, const struct mdoc_node *n
33 struct actions {
34 int (*pre)(PRE_ARGS);
35 int (*post)(POST_ARGS);
38 static int concat(struct mdoc *,
39 const struct mdoc_node *,
40 char *, size_t);
41 static inline int order_rs(int);
43 #ifdef __linux__
44 extern size_t strlcat(char *, const char *, size_t);
45 #endif
47 static int post_ar(POST_ARGS);
48 static int post_at(POST_ARGS);
49 static int post_bl(POST_ARGS);
50 static int post_bl_head(POST_ARGS);
51 static int post_bl_tagwidth(POST_ARGS);
52 static int post_bl_width(POST_ARGS);
53 static int post_dd(POST_ARGS);
54 static int post_display(POST_ARGS);
55 static int post_dt(POST_ARGS);
56 static int post_lb(POST_ARGS);
57 static int post_nm(POST_ARGS);
58 static int post_os(POST_ARGS);
59 static int post_prol(POST_ARGS);
60 static int post_rs(POST_ARGS);
61 static int post_sh(POST_ARGS);
62 static int post_st(POST_ARGS);
63 static int post_std(POST_ARGS);
64 static int post_tilde(POST_ARGS);
66 static int pre_bd(PRE_ARGS);
67 static int pre_bl(PRE_ARGS);
68 static int pre_dl(PRE_ARGS);
69 static int pre_offset(PRE_ARGS);
71 static const struct actions mdoc_actions[MDOC_MAX] = {
72 { NULL, NULL }, /* Ap */
73 { NULL, post_dd }, /* Dd */
74 { NULL, post_dt }, /* Dt */
75 { NULL, post_os }, /* Os */
76 { NULL, post_sh }, /* Sh */
77 { NULL, NULL }, /* Ss */
78 { NULL, NULL }, /* Pp */
79 { NULL, NULL }, /* D1 */
80 { pre_dl, post_display }, /* Dl */
81 { pre_bd, post_display }, /* Bd */
82 { NULL, NULL }, /* Ed */
83 { pre_bl, post_bl }, /* Bl */
84 { NULL, NULL }, /* El */
85 { NULL, NULL }, /* It */
86 { NULL, NULL }, /* Ad */
87 { NULL, NULL }, /* An */
88 { NULL, post_ar }, /* Ar */
89 { NULL, NULL }, /* Cd */
90 { NULL, NULL }, /* Cm */
91 { NULL, NULL }, /* Dv */
92 { NULL, NULL }, /* Er */
93 { NULL, NULL }, /* Ev */
94 { NULL, post_std }, /* Ex */
95 { NULL, NULL }, /* Fa */
96 { NULL, NULL }, /* Fd */
97 { NULL, NULL }, /* Fl */
98 { NULL, NULL }, /* Fn */
99 { NULL, NULL }, /* Ft */
100 { NULL, NULL }, /* Ic */
101 { NULL, NULL }, /* In */
102 { NULL, NULL }, /* Li */
103 { NULL, NULL }, /* Nd */
104 { NULL, post_nm }, /* Nm */
105 { NULL, NULL }, /* Op */
106 { NULL, NULL }, /* Ot */
107 { NULL, post_tilde }, /* Pa */
108 { NULL, post_std }, /* Rv */
109 { NULL, post_st }, /* St */
110 { NULL, NULL }, /* Va */
111 { NULL, NULL }, /* Vt */
112 { NULL, NULL }, /* Xr */
113 { NULL, NULL }, /* %A */
114 { NULL, NULL }, /* %B */
115 { NULL, NULL }, /* %D */
116 { NULL, NULL }, /* %I */
117 { NULL, NULL }, /* %J */
118 { NULL, NULL }, /* %N */
119 { NULL, NULL }, /* %O */
120 { NULL, NULL }, /* %P */
121 { NULL, NULL }, /* %R */
122 { NULL, NULL }, /* %T */
123 { NULL, NULL }, /* %V */
124 { NULL, NULL }, /* Ac */
125 { NULL, NULL }, /* Ao */
126 { NULL, NULL }, /* Aq */
127 { NULL, post_at }, /* At */
128 { NULL, NULL }, /* Bc */
129 { NULL, NULL }, /* Bf */
130 { NULL, NULL }, /* Bo */
131 { NULL, NULL }, /* Bq */
132 { NULL, NULL }, /* Bsx */
133 { NULL, NULL }, /* Bx */
134 { NULL, NULL }, /* Db */
135 { NULL, NULL }, /* Dc */
136 { NULL, NULL }, /* Do */
137 { NULL, NULL }, /* Dq */
138 { NULL, NULL }, /* Ec */
139 { NULL, NULL }, /* Ef */
140 { NULL, NULL }, /* Em */
141 { NULL, NULL }, /* Eo */
142 { NULL, NULL }, /* Fx */
143 { NULL, NULL }, /* Ms */
144 { NULL, NULL }, /* No */
145 { NULL, NULL }, /* Ns */
146 { NULL, NULL }, /* Nx */
147 { NULL, NULL }, /* Ox */
148 { NULL, NULL }, /* Pc */
149 { NULL, NULL }, /* Pf */
150 { NULL, NULL }, /* Po */
151 { NULL, NULL }, /* Pq */
152 { NULL, NULL }, /* Qc */
153 { NULL, NULL }, /* Ql */
154 { NULL, NULL }, /* Qo */
155 { NULL, NULL }, /* Qq */
156 { NULL, NULL }, /* Re */
157 { NULL, post_rs }, /* Rs */
158 { NULL, NULL }, /* Sc */
159 { NULL, NULL }, /* So */
160 { NULL, NULL }, /* Sq */
161 { NULL, NULL }, /* Sm */
162 { NULL, NULL }, /* Sx */
163 { NULL, NULL }, /* Sy */
164 { NULL, NULL }, /* Tn */
165 { NULL, NULL }, /* Ux */
166 { NULL, NULL }, /* Xc */
167 { NULL, NULL }, /* Xo */
168 { NULL, NULL }, /* Fo */
169 { NULL, NULL }, /* Fc */
170 { NULL, NULL }, /* Oo */
171 { NULL, NULL }, /* Oc */
172 { NULL, NULL }, /* Bk */
173 { NULL, NULL }, /* Ek */
174 { NULL, NULL }, /* Bt */
175 { NULL, NULL }, /* Hf */
176 { NULL, NULL }, /* Fr */
177 { NULL, NULL }, /* Ud */
178 { NULL, post_lb }, /* Lb */
179 { NULL, NULL }, /* Lp */
180 { NULL, NULL }, /* Lk */
181 { NULL, NULL }, /* Mt */
182 { NULL, NULL }, /* Brq */
183 { NULL, NULL }, /* Bro */
184 { NULL, NULL }, /* Brc */
185 { NULL, NULL }, /* %C */
186 { NULL, NULL }, /* Es */
187 { NULL, NULL }, /* En */
188 { NULL, NULL }, /* Dx */
189 { NULL, NULL }, /* %Q */
190 { NULL, NULL }, /* br */
191 { NULL, NULL }, /* sp */
192 { NULL, NULL }, /* %U */
195 #define RSORD_MAX 14
197 static const int rsord[RSORD_MAX] = {
198 MDOC__A,
199 MDOC__T,
200 MDOC__B,
201 MDOC__I,
202 MDOC__J,
203 MDOC__R,
204 MDOC__N,
205 MDOC__V,
206 MDOC__U,
207 MDOC__P,
208 MDOC__Q,
209 MDOC__D,
210 MDOC__O,
211 MDOC__C
216 mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
219 switch (n->type) {
220 case (MDOC_ROOT):
221 /* FALLTHROUGH */
222 case (MDOC_TEXT):
223 return(1);
224 default:
225 break;
228 if (NULL == mdoc_actions[n->tok].pre)
229 return(1);
230 return((*mdoc_actions[n->tok].pre)(m, n));
235 mdoc_action_post(struct mdoc *m)
238 if (MDOC_ACTED & m->last->flags)
239 return(1);
240 m->last->flags |= MDOC_ACTED;
242 switch (m->last->type) {
243 case (MDOC_TEXT):
244 /* FALLTHROUGH */
245 case (MDOC_ROOT):
246 return(1);
247 default:
248 break;
251 if (NULL == mdoc_actions[m->last->tok].post)
252 return(1);
253 return((*mdoc_actions[m->last->tok].post)(m, m->last));
257 static int
258 concat(struct mdoc *m, const struct mdoc_node *n,
259 char *buf, size_t sz)
262 for ( ; n; n = n->next) {
263 assert(MDOC_TEXT == n->type);
264 if (strlcat(buf, n->string, sz) >= sz)
265 return(mdoc_nerr(m, n, ETOOLONG));
266 if (NULL == n->next)
267 continue;
268 if (strlcat(buf, " ", sz) >= sz)
269 return(mdoc_nerr(m, n, ETOOLONG));
272 return(1);
276 static int
277 post_std(POST_ARGS)
279 struct mdoc_node *nn;
281 if (n->child)
282 return(1);
284 nn = n;
285 m->next = MDOC_NEXT_CHILD;
286 assert(m->meta.name);
287 if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
288 return(0);
289 m->last = nn;
291 return(1);
295 static int
296 post_nm(POST_ARGS)
298 char buf[64];
300 if (m->meta.name)
301 return(1);
303 buf[0] = 0;
304 if ( ! concat(m, n->child, buf, sizeof(buf)))
305 return(0);
306 if (NULL == (m->meta.name = strdup(buf)))
307 return(mdoc_nerr(m, n, EMALLOC));
309 return(1);
313 static int
314 post_lb(POST_ARGS)
316 const char *p;
317 char *buf;
318 size_t sz;
320 assert(MDOC_TEXT == n->child->type);
321 p = mdoc_a2lib(n->child->string);
322 if (NULL == p) {
323 sz = strlen(n->child->string) +
324 2 + strlen("\\(lqlibrary\\(rq");
325 buf = malloc(sz);
326 if (NULL == buf)
327 return(mdoc_nerr(m, n, EMALLOC));
328 (void)snprintf(buf, sz, "library \\(lq%s\\(rq",
329 n->child->string);
330 free(n->child->string);
331 n->child->string = buf;
332 return(1);
335 free(n->child->string);
336 n->child->string = strdup(p);
337 if (NULL == n->child->string)
338 return(mdoc_nerr(m, n, EMALLOC));
340 return(1);
344 static int
345 post_st(POST_ARGS)
347 const char *p;
349 assert(MDOC_TEXT == n->child->type);
350 p = mdoc_a2st(n->child->string);
351 assert(p);
352 free(n->child->string);
353 n->child->string = strdup(p);
354 if (NULL == n->child->string)
355 return(mdoc_nerr(m, n, EMALLOC));
357 return(1);
361 static int
362 post_at(POST_ARGS)
364 struct mdoc_node *nn;
365 const char *p;
367 if (n->child) {
368 assert(MDOC_TEXT == n->child->type);
369 p = mdoc_a2att(n->child->string);
370 assert(p);
371 free(n->child->string);
372 n->child->string = strdup(p);
373 if (NULL == n->child->string)
374 return(mdoc_nerr(m, n, EMALLOC));
375 return(1);
378 nn = n;
379 m->next = MDOC_NEXT_CHILD;
381 if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
382 return(0);
383 m->last = nn;
385 return(1);
389 static int
390 post_sh(POST_ARGS)
392 enum mdoc_sec sec;
393 char buf[64];
396 * We keep track of the current section /and/ the "named"
397 * section, which is one of the conventional ones, in order to
398 * check ordering.
401 if (MDOC_HEAD != n->type)
402 return(1);
404 buf[0] = 0;
405 if ( ! concat(m, n->child, buf, sizeof(buf)))
406 return(0);
407 if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
408 m->lastnamed = sec;
410 switch ((m->lastsec = sec)) {
411 case (SEC_RETURN_VALUES):
412 /* FALLTHROUGH */
413 case (SEC_ERRORS):
414 switch (m->meta.msec) {
415 case (2):
416 /* FALLTHROUGH */
417 case (3):
418 /* FALLTHROUGH */
419 case (9):
420 break;
421 default:
422 return(mdoc_nwarn(m, n, EBADSEC));
424 break;
425 default:
426 break;
428 return(1);
432 static int
433 post_dt(POST_ARGS)
435 struct mdoc_node *nn;
436 const char *cp;
437 char *ep;
438 long lval;
440 if (m->meta.title)
441 free(m->meta.title);
442 if (m->meta.vol)
443 free(m->meta.vol);
444 if (m->meta.arch)
445 free(m->meta.arch);
447 m->meta.title = m->meta.vol = m->meta.arch = NULL;
448 m->meta.msec = 0;
450 /* Handles: `.Dt'
451 * --> title = unknown, volume = local, msec = 0, arch = NULL
454 if (NULL == (nn = n->child)) {
455 if (NULL == (m->meta.title = strdup("unknown")))
456 return(mdoc_nerr(m, n, EMALLOC));
457 if (NULL == (m->meta.vol = strdup("local")))
458 return(mdoc_nerr(m, n, EMALLOC));
459 return(post_prol(m, n));
462 /* Handles: `.Dt TITLE'
463 * --> title = TITLE, volume = local, msec = 0, arch = NULL
466 if (NULL == (m->meta.title = strdup(nn->string)))
467 return(mdoc_nerr(m, n, EMALLOC));
469 if (NULL == (nn = nn->next)) {
470 if (NULL == (m->meta.vol = strdup("local")))
471 return(mdoc_nerr(m, n, EMALLOC));
472 return(post_prol(m, n));
475 /* Handles: `.Dt TITLE SEC'
476 * --> title = TITLE, volume = SEC is msec ?
477 * format(msec) : SEC,
478 * msec = SEC is msec ? atoi(msec) : 0,
479 * arch = NULL
482 cp = mdoc_a2msec(nn->string);
483 if (cp) {
484 if (NULL == (m->meta.vol = strdup(cp)))
485 return(mdoc_nerr(m, n, EMALLOC));
486 errno = 0;
487 lval = strtol(nn->string, &ep, 10);
488 if (nn->string[0] != '\0' && *ep == '\0')
489 m->meta.msec = (int)lval;
490 } else if (NULL == (m->meta.vol = strdup(nn->string)))
491 return(mdoc_nerr(m, n, EMALLOC));
493 if (NULL == (nn = nn->next))
494 return(post_prol(m, n));
496 /* Handles: `.Dt TITLE SEC VOL'
497 * --> title = TITLE, volume = VOL is vol ?
498 * format(VOL) :
499 * VOL is arch ? format(arch) :
500 * VOL
503 cp = mdoc_a2vol(nn->string);
504 if (cp) {
505 free(m->meta.vol);
506 if (NULL == (m->meta.vol = strdup(cp)))
507 return(mdoc_nerr(m, n, EMALLOC));
508 } else {
509 cp = mdoc_a2arch(nn->string);
510 if (NULL == cp) {
511 free(m->meta.vol);
512 if (NULL == (m->meta.vol = strdup(nn->string)))
513 return(mdoc_nerr(m, n, EMALLOC));
514 } else if (NULL == (m->meta.arch = strdup(cp)))
515 return(mdoc_nerr(m, n, EMALLOC));
518 /* Ignore any subsequent parameters... */
520 return(post_prol(m, n));
524 static int
525 post_os(POST_ARGS)
527 char buf[64];
528 #ifndef OSNAME
529 struct utsname utsname;
530 #endif
533 * Setting OSNAME to be the name of the target operating system,
534 * e.g., "OpenBSD 4.4", will result in the compile-time constant
535 * by supplied instead of the value in uname().
538 if (m->meta.os)
539 free(m->meta.os);
541 buf[0] = 0;
542 if ( ! concat(m, n->child, buf, sizeof(buf)))
543 return(0);
545 if (0 == buf[0]) {
546 #ifdef OSNAME
547 if (strlcat(buf, OSNAME, 64) >= 64)
548 return(mdoc_nerr(m, n, EUTSNAME));
549 #else
550 if (-1 == uname(&utsname))
551 return(mdoc_nerr(m, n, EUTSNAME));
552 if (strlcat(buf, utsname.sysname, 64) >= 64)
553 return(mdoc_nerr(m, n, ETOOLONG));
554 if (strlcat(buf, " ", 64) >= 64)
555 return(mdoc_nerr(m, n, ETOOLONG));
556 if (strlcat(buf, utsname.release, 64) >= 64)
557 return(mdoc_nerr(m, n, ETOOLONG));
558 #endif
561 if (NULL == (m->meta.os = strdup(buf)))
562 return(mdoc_nerr(m, n, EMALLOC));
564 return(post_prol(m, n));
569 * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
570 * Uses the first head macro.
572 static int
573 post_bl_tagwidth(POST_ARGS)
575 struct mdoc_node *nn;
576 int sz;
577 char buf[32];
580 * Use the text width, if a text node, or the default macro
581 * width if a macro.
584 nn = n->body->child;
585 if (nn) {
586 assert(MDOC_BLOCK == nn->type);
587 assert(MDOC_It == nn->tok);
588 nn = nn->head->child;
591 sz = 10; /* Default size. */
593 if (nn) {
594 if (MDOC_TEXT != nn->type) {
595 if (0 == (sz = (int)mdoc_macro2len(nn->tok)))
596 if ( ! mdoc_nwarn(m, n, ENOWIDTH))
597 return(0);
598 } else
599 sz = (int)strlen(nn->string) + 1;
602 if (-1 == snprintf(buf, sizeof(buf), "%dn", sz))
603 return(mdoc_nerr(m, n, ENUMFMT));
606 * We have to dynamically add this to the macro's argument list.
607 * We're guaranteed that a MDOC_Width doesn't already exist.
610 nn = n;
611 assert(nn->args);
612 sz = (int)(nn->args->argc)++;
614 nn->args->argv = realloc(nn->args->argv,
615 nn->args->argc * sizeof(struct mdoc_argv));
617 if (NULL == nn->args->argv)
618 return(mdoc_nerr(m, n, EMALLOC));
620 nn->args->argv[sz].arg = MDOC_Width;
621 nn->args->argv[sz].line = n->line;
622 nn->args->argv[sz].pos = n->pos;
623 nn->args->argv[sz].sz = 1;
624 nn->args->argv[sz].value = calloc(1, sizeof(char *));
626 if (NULL == nn->args->argv[sz].value)
627 return(mdoc_nerr(m, n, EMALLOC));
628 if (NULL == (nn->args->argv[sz].value[0] = strdup(buf)))
629 return(mdoc_nerr(m, n, EMALLOC));
631 return(1);
635 static int
636 post_bl_width(POST_ARGS)
638 size_t width;
639 int i, tok;
640 char buf[32];
641 char *p;
643 if (NULL == n->args)
644 return(1);
646 for (i = 0; i < (int)n->args->argc; i++)
647 if (MDOC_Width == n->args->argv[i].arg)
648 break;
650 if (i == (int)n->args->argc)
651 return(1);
652 p = n->args->argv[i].value[0];
655 * If the value to -width is a macro, then we re-write it to be
656 * the macro's width as set in share/tmac/mdoc/doc-common.
659 if (0 == strcmp(p, "Ds"))
660 width = 6;
661 else if (MDOC_MAX == (tok = mdoc_hash_find(p)))
662 return(1);
663 else if (0 == (width = mdoc_macro2len(tok)))
664 return(mdoc_nwarn(m, n, ENOWIDTH));
666 /* The value already exists: free and reallocate it. */
668 if (-1 == snprintf(buf, sizeof(buf), "%zun", width))
669 return(mdoc_nerr(m, n, ENUMFMT));
671 free(n->args->argv[i].value[0]);
672 n->args->argv[i].value[0] = strdup(buf);
673 if (NULL == n->args->argv[i].value[0])
674 return(mdoc_nerr(m, n, EMALLOC));
676 return(1);
680 /* ARGSUSED */
681 static int
682 post_bl_head(POST_ARGS)
684 int i, c;
685 struct mdoc_node *np, *nn, *nnp;
687 if (NULL == n->child)
688 return(1);
690 np = n->parent;
691 assert(np->args);
693 for (c = 0; c < (int)np->args->argc; c++)
694 if (MDOC_Column == np->args->argv[c].arg)
695 break;
697 /* Only process -column. */
699 if (c == (int)np->args->argc)
700 return(1);
702 assert(0 == np->args->argv[c].sz);
705 * Accomodate for new-style groff column syntax. Shuffle the
706 * child nodes, all of which must be TEXT, as arguments for the
707 * column field. Then, delete the head children.
710 np->args->argv[c].sz = (size_t)n->nchild;
711 np->args->argv[c].value = malloc
712 ((size_t)n->nchild * sizeof(char *));
714 for (i = 0, nn = n->child; nn; i++) {
715 np->args->argv[c].value[i] = nn->string;
716 nn->string = NULL;
717 nnp = nn;
718 nn = nn->next;
719 mdoc_node_free(nnp);
722 n->nchild = 0;
723 n->child = NULL;
725 return(1);
729 static int
730 post_bl(POST_ARGS)
732 int i, r, len;
734 if (MDOC_HEAD == n->type)
735 return(post_bl_head(m, n));
736 if (MDOC_BLOCK != n->type)
737 return(1);
740 * These are fairly complicated, so we've broken them into two
741 * functions. post_bl_tagwidth() is called when a -tag is
742 * specified, but no -width (it must be guessed). The second
743 * when a -width is specified (macro indicators must be
744 * rewritten into real lengths).
747 len = (int)(n->args ? n->args->argc : 0);
749 for (r = i = 0; i < len; i++) {
750 if (MDOC_Tag == n->args->argv[i].arg)
751 r |= 1 << 0;
752 if (MDOC_Width == n->args->argv[i].arg)
753 r |= 1 << 1;
756 if (r & (1 << 0) && ! (r & (1 << 1))) {
757 if ( ! post_bl_tagwidth(m, n))
758 return(0);
759 } else if (r & (1 << 1))
760 if ( ! post_bl_width(m, n))
761 return(0);
763 return(1);
767 static int
768 post_tilde(POST_ARGS)
770 struct mdoc_node *np;
772 if (n->child)
773 return(1);
775 np = n;
776 m->next = MDOC_NEXT_CHILD;
778 if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
779 return(0);
780 m->last = np;
782 return(1);
786 static int
787 post_ar(POST_ARGS)
789 struct mdoc_node *np;
791 if (n->child)
792 return(1);
794 np = n;
795 m->next = MDOC_NEXT_CHILD;
796 if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
797 return(0);
798 if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
799 return(0);
800 m->last = np;
802 return(1);
806 static int
807 post_dd(POST_ARGS)
809 char buf[64];
811 buf[0] = 0;
812 if ( ! concat(m, n->child, buf, sizeof(buf)))
813 return(0);
815 if (0 == (m->meta.date = mdoc_atotime(buf))) {
816 if ( ! mdoc_nwarn(m, n, EBADDATE))
817 return(0);
818 m->meta.date = time(NULL);
821 return(post_prol(m, n));
825 static int
826 post_prol(POST_ARGS)
828 struct mdoc_node *np;
830 /* Remove prologue macros from AST. */
832 if (n->parent->child == n)
833 n->parent->child = n->prev;
834 if (n->prev)
835 n->prev->next = NULL;
837 np = n;
838 assert(NULL == n->next);
840 if (n->prev) {
841 m->last = n->prev;
842 m->next = MDOC_NEXT_SIBLING;
843 } else {
844 m->last = n->parent;
845 m->next = MDOC_NEXT_CHILD;
848 mdoc_node_freelist(np);
850 if (m->meta.title && m->meta.date && m->meta.os)
851 m->flags |= MDOC_PBODY;
853 return(1);
857 static int
858 pre_dl(PRE_ARGS)
861 if (MDOC_BODY == n->type)
862 m->flags |= MDOC_LITERAL;
863 return(1);
867 static int
868 pre_offset(PRE_ARGS)
870 int i;
873 * Make sure that an empty offset produces an 8n length space as
874 * stipulated by mdoc.samples.
877 assert(n->args);
878 for (i = 0; i < (int)n->args->argc; i++) {
879 if (MDOC_Offset != n->args->argv[i].arg)
880 continue;
881 if (n->args->argv[i].sz)
882 break;
883 assert(1 == n->args->refcnt);
884 /* If no value set, length of <string>. */
885 n->args->argv[i].value =
886 calloc(1, sizeof(char *));
887 if (NULL == n->args->argv[i].value)
888 return(mdoc_nerr(m, n, EMALLOC));
889 n->args->argv[i].sz++;
890 n->args->argv[i].value[0] = strdup("8n");
891 if (NULL == n->args->argv[i].value[0])
892 return(mdoc_nerr(m, n, EMALLOC));
893 break;
896 return(1);
900 static int
901 pre_bl(PRE_ARGS)
904 return(MDOC_BLOCK == n->type ? pre_offset(m, n) : 1);
908 static int
909 pre_bd(PRE_ARGS)
911 int i;
913 if (MDOC_BLOCK == n->type)
914 return(pre_offset(m, n));
915 if (MDOC_BODY != n->type)
916 return(1);
918 /* Enter literal context if `Bd -literal' or `-unfilled'. */
920 for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
921 if (MDOC_Literal == n->args->argv[i].arg)
922 m->flags |= MDOC_LITERAL;
923 else if (MDOC_Unfilled == n->args->argv[i].arg)
924 m->flags |= MDOC_LITERAL;
926 return(1);
930 static int
931 post_display(POST_ARGS)
934 if (MDOC_BODY == n->type)
935 m->flags &= ~MDOC_LITERAL;
936 return(1);
940 static inline int
941 order_rs(int t)
943 int i;
945 for (i = 0; i < RSORD_MAX; i++)
946 if (rsord[i] == t)
947 return(i);
949 abort();
950 /* NOTREACHED */
954 /* ARGSUSED */
955 static int
956 post_rs(POST_ARGS)
958 struct mdoc_node *nn, *next, *prev;
959 int o;
961 if (MDOC_BLOCK != n->type)
962 return(1);
964 assert(n->body->child);
965 for (next = NULL, nn = n->body->child->next; nn; nn = next) {
966 o = order_rs(nn->tok);
968 /* Remove `nn' from the chain. */
969 next = nn->next;
970 if (next)
971 next->prev = nn->prev;
973 prev = nn->prev;
974 if (prev)
975 prev->next = nn->next;
977 nn->prev = nn->next = NULL;
980 * Scan back until we reach a node that's ordered before
981 * us, then set ourselves as being the next.
983 for ( ; prev; prev = prev->prev)
984 if (order_rs(prev->tok) <= o)
985 break;
987 nn->prev = prev;
988 if (prev) {
989 if (prev->next)
990 prev->next->prev = nn;
991 nn->next = prev->next;
992 prev->next = nn;
993 continue;
996 n->body->child->prev = nn;
997 nn->next = n->body->child;
998 n->body->child = nn;
1000 return(1);