]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_action.c
Portability: replaced queue macros in html.c (Joerg Sonnenberger).
[mandoc.git] / mdoc_action.c
1 /* $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>
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 #ifndef OSNAME
18 #include <sys/utsname.h>
19 #endif
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27
28 #include "libmdoc.h"
29
30 #define POST_ARGS struct mdoc *m, struct mdoc_node *n
31 #define PRE_ARGS struct mdoc *m, const struct mdoc_node *n
32
33 struct actions {
34 int (*pre)(PRE_ARGS);
35 int (*post)(POST_ARGS);
36 };
37
38 static int concat(struct mdoc *,
39 const struct mdoc_node *,
40 char *, size_t);
41 static inline int order_rs(int);
42
43 #ifdef __linux__
44 extern size_t strlcat(char *, const char *, size_t);
45 #endif
46
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);
65
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);
70
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 */
193 };
194
195 #define RSORD_MAX 13
196
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__P,
207 MDOC__Q,
208 MDOC__D,
209 MDOC__O,
210 MDOC__C
211 };
212
213
214 int
215 mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
216 {
217
218 switch (n->type) {
219 case (MDOC_ROOT):
220 /* FALLTHROUGH */
221 case (MDOC_TEXT):
222 return(1);
223 default:
224 break;
225 }
226
227 if (NULL == mdoc_actions[n->tok].pre)
228 return(1);
229 return((*mdoc_actions[n->tok].pre)(m, n));
230 }
231
232
233 int
234 mdoc_action_post(struct mdoc *m)
235 {
236
237 if (MDOC_ACTED & m->last->flags)
238 return(1);
239 m->last->flags |= MDOC_ACTED;
240
241 switch (m->last->type) {
242 case (MDOC_TEXT):
243 /* FALLTHROUGH */
244 case (MDOC_ROOT):
245 return(1);
246 default:
247 break;
248 }
249
250 if (NULL == mdoc_actions[m->last->tok].post)
251 return(1);
252 return((*mdoc_actions[m->last->tok].post)(m, m->last));
253 }
254
255
256 static int
257 concat(struct mdoc *m, const struct mdoc_node *n,
258 char *buf, size_t sz)
259 {
260
261 for ( ; n; n = n->next) {
262 assert(MDOC_TEXT == n->type);
263 if (strlcat(buf, n->string, sz) >= sz)
264 return(mdoc_nerr(m, n, ETOOLONG));
265 if (NULL == n->next)
266 continue;
267 if (strlcat(buf, " ", sz) >= sz)
268 return(mdoc_nerr(m, n, ETOOLONG));
269 }
270
271 return(1);
272 }
273
274
275 static int
276 post_std(POST_ARGS)
277 {
278 struct mdoc_node *nn;
279
280 if (n->child)
281 return(1);
282
283 nn = n;
284 m->next = MDOC_NEXT_CHILD;
285 assert(m->meta.name);
286 if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
287 return(0);
288 m->last = nn;
289
290 return(1);
291 }
292
293
294 static int
295 post_nm(POST_ARGS)
296 {
297 char buf[64];
298
299 if (m->meta.name)
300 return(1);
301
302 buf[0] = 0;
303 if ( ! concat(m, n->child, buf, sizeof(buf)))
304 return(0);
305 if (NULL == (m->meta.name = strdup(buf)))
306 return(mdoc_nerr(m, n, EMALLOC));
307
308 return(1);
309 }
310
311
312 static int
313 post_lb(POST_ARGS)
314 {
315 const char *p;
316 char *buf;
317 size_t sz;
318
319 assert(MDOC_TEXT == n->child->type);
320 p = mdoc_a2lib(n->child->string);
321 if (NULL == p) {
322 sz = strlen(n->child->string) +
323 2 + strlen("\\(lqlibrary\\(rq");
324 buf = malloc(sz);
325 if (NULL == buf)
326 return(mdoc_nerr(m, n, EMALLOC));
327 (void)snprintf(buf, sz, "library \\(lq%s\\(rq",
328 n->child->string);
329 free(n->child->string);
330 n->child->string = buf;
331 return(1);
332 }
333
334 free(n->child->string);
335 n->child->string = strdup(p);
336 if (NULL == n->child->string)
337 return(mdoc_nerr(m, n, EMALLOC));
338
339 return(1);
340 }
341
342
343 static int
344 post_st(POST_ARGS)
345 {
346 const char *p;
347
348 assert(MDOC_TEXT == n->child->type);
349 p = mdoc_a2st(n->child->string);
350 assert(p);
351 free(n->child->string);
352 n->child->string = strdup(p);
353 if (NULL == n->child->string)
354 return(mdoc_nerr(m, n, EMALLOC));
355
356 return(1);
357 }
358
359
360 static int
361 post_at(POST_ARGS)
362 {
363 struct mdoc_node *nn;
364 const char *p;
365
366 if (n->child) {
367 assert(MDOC_TEXT == n->child->type);
368 p = mdoc_a2att(n->child->string);
369 assert(p);
370 free(n->child->string);
371 n->child->string = strdup(p);
372 if (NULL == n->child->string)
373 return(mdoc_nerr(m, n, EMALLOC));
374 return(1);
375 }
376
377 nn = n;
378 m->next = MDOC_NEXT_CHILD;
379
380 if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
381 return(0);
382 m->last = nn;
383
384 return(1);
385 }
386
387
388 static int
389 post_sh(POST_ARGS)
390 {
391 enum mdoc_sec sec;
392 char buf[64];
393
394 /*
395 * We keep track of the current section /and/ the "named"
396 * section, which is one of the conventional ones, in order to
397 * check ordering.
398 */
399
400 if (MDOC_HEAD != n->type)
401 return(1);
402
403 buf[0] = 0;
404 if ( ! concat(m, n->child, buf, sizeof(buf)))
405 return(0);
406 if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
407 m->lastnamed = sec;
408
409 switch ((m->lastsec = sec)) {
410 case (SEC_RETURN_VALUES):
411 /* FALLTHROUGH */
412 case (SEC_ERRORS):
413 switch (m->meta.msec) {
414 case (2):
415 /* FALLTHROUGH */
416 case (3):
417 /* FALLTHROUGH */
418 case (9):
419 break;
420 default:
421 return(mdoc_nwarn(m, n, EBADSEC));
422 }
423 break;
424 default:
425 break;
426 }
427 return(1);
428 }
429
430
431 static int
432 post_dt(POST_ARGS)
433 {
434 struct mdoc_node *nn;
435 const char *cp;
436 char *ep;
437 long lval;
438
439 if (m->meta.title)
440 free(m->meta.title);
441 if (m->meta.vol)
442 free(m->meta.vol);
443 if (m->meta.arch)
444 free(m->meta.arch);
445
446 m->meta.title = m->meta.vol = m->meta.arch = NULL;
447 m->meta.msec = 0;
448
449 /* Handles: `.Dt'
450 * --> title = unknown, volume = local, msec = 0, arch = NULL
451 */
452
453 if (NULL == (nn = n->child)) {
454 if (NULL == (m->meta.title = strdup("unknown")))
455 return(mdoc_nerr(m, n, EMALLOC));
456 if (NULL == (m->meta.vol = strdup("local")))
457 return(mdoc_nerr(m, n, EMALLOC));
458 return(post_prol(m, n));
459 }
460
461 /* Handles: `.Dt TITLE'
462 * --> title = TITLE, volume = local, msec = 0, arch = NULL
463 */
464
465 if (NULL == (m->meta.title = strdup(nn->string)))
466 return(mdoc_nerr(m, n, EMALLOC));
467
468 if (NULL == (nn = nn->next)) {
469 if (NULL == (m->meta.vol = strdup("local")))
470 return(mdoc_nerr(m, n, EMALLOC));
471 return(post_prol(m, n));
472 }
473
474 /* Handles: `.Dt TITLE SEC'
475 * --> title = TITLE, volume = SEC is msec ?
476 * format(msec) : SEC,
477 * msec = SEC is msec ? atoi(msec) : 0,
478 * arch = NULL
479 */
480
481 cp = mdoc_a2msec(nn->string);
482 if (cp) {
483 if (NULL == (m->meta.vol = strdup(cp)))
484 return(mdoc_nerr(m, n, EMALLOC));
485 errno = 0;
486 lval = strtol(nn->string, &ep, 10);
487 if (nn->string[0] != '\0' && *ep == '\0')
488 m->meta.msec = (int)lval;
489 } else if (NULL == (m->meta.vol = strdup(nn->string)))
490 return(mdoc_nerr(m, n, EMALLOC));
491
492 if (NULL == (nn = nn->next))
493 return(post_prol(m, n));
494
495 /* Handles: `.Dt TITLE SEC VOL'
496 * --> title = TITLE, volume = VOL is vol ?
497 * format(VOL) :
498 * VOL is arch ? format(arch) :
499 * VOL
500 */
501
502 cp = mdoc_a2vol(nn->string);
503 if (cp) {
504 free(m->meta.vol);
505 if (NULL == (m->meta.vol = strdup(cp)))
506 return(mdoc_nerr(m, n, EMALLOC));
507 } else {
508 cp = mdoc_a2arch(nn->string);
509 if (NULL == cp) {
510 free(m->meta.vol);
511 if (NULL == (m->meta.vol = strdup(nn->string)))
512 return(mdoc_nerr(m, n, EMALLOC));
513 } else if (NULL == (m->meta.arch = strdup(cp)))
514 return(mdoc_nerr(m, n, EMALLOC));
515 }
516
517 /* Ignore any subsequent parameters... */
518
519 return(post_prol(m, n));
520 }
521
522
523 static int
524 post_os(POST_ARGS)
525 {
526 char buf[64];
527 #ifndef OSNAME
528 struct utsname utsname;
529 #endif
530
531 /*
532 * Setting OSNAME to be the name of the target operating system,
533 * e.g., "OpenBSD 4.4", will result in the compile-time constant
534 * by supplied instead of the value in uname().
535 */
536
537 if (m->meta.os)
538 free(m->meta.os);
539
540 buf[0] = 0;
541 if ( ! concat(m, n->child, buf, sizeof(buf)))
542 return(0);
543
544 if (0 == buf[0]) {
545 #ifdef OSNAME
546 if (strlcat(buf, OSNAME, 64) >= 64)
547 return(mdoc_nerr(m, n, EUTSNAME));
548 #else
549 if (-1 == uname(&utsname))
550 return(mdoc_nerr(m, n, EUTSNAME));
551 if (strlcat(buf, utsname.sysname, 64) >= 64)
552 return(mdoc_nerr(m, n, ETOOLONG));
553 if (strlcat(buf, " ", 64) >= 64)
554 return(mdoc_nerr(m, n, ETOOLONG));
555 if (strlcat(buf, utsname.release, 64) >= 64)
556 return(mdoc_nerr(m, n, ETOOLONG));
557 #endif
558 }
559
560 if (NULL == (m->meta.os = strdup(buf)))
561 return(mdoc_nerr(m, n, EMALLOC));
562
563 return(post_prol(m, n));
564 }
565
566
567 /*
568 * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
569 * Uses the first head macro.
570 */
571 static int
572 post_bl_tagwidth(POST_ARGS)
573 {
574 struct mdoc_node *nn;
575 int sz;
576 char buf[32];
577
578 /*
579 * Use the text width, if a text node, or the default macro
580 * width if a macro.
581 */
582
583 nn = n->body->child;
584 if (nn) {
585 assert(MDOC_BLOCK == nn->type);
586 assert(MDOC_It == nn->tok);
587 nn = nn->head->child;
588 }
589
590 sz = 10; /* Default size. */
591
592 if (nn) {
593 if (MDOC_TEXT != nn->type) {
594 if (0 == (sz = (int)mdoc_macro2len(nn->tok)))
595 if ( ! mdoc_nwarn(m, n, ENOWIDTH))
596 return(0);
597 } else
598 sz = (int)strlen(nn->string) + 1;
599 }
600
601 if (-1 == snprintf(buf, sizeof(buf), "%dn", sz))
602 return(mdoc_nerr(m, n, ENUMFMT));
603
604 /*
605 * We have to dynamically add this to the macro's argument list.
606 * We're guaranteed that a MDOC_Width doesn't already exist.
607 */
608
609 nn = n;
610 assert(nn->args);
611 sz = (int)(nn->args->argc)++;
612
613 nn->args->argv = realloc(nn->args->argv,
614 nn->args->argc * sizeof(struct mdoc_argv));
615
616 if (NULL == nn->args->argv)
617 return(mdoc_nerr(m, n, EMALLOC));
618
619 nn->args->argv[sz].arg = MDOC_Width;
620 nn->args->argv[sz].line = n->line;
621 nn->args->argv[sz].pos = n->pos;
622 nn->args->argv[sz].sz = 1;
623 nn->args->argv[sz].value = calloc(1, sizeof(char *));
624
625 if (NULL == nn->args->argv[sz].value)
626 return(mdoc_nerr(m, n, EMALLOC));
627 if (NULL == (nn->args->argv[sz].value[0] = strdup(buf)))
628 return(mdoc_nerr(m, n, EMALLOC));
629
630 return(1);
631 }
632
633
634 static int
635 post_bl_width(POST_ARGS)
636 {
637 size_t width;
638 int i, tok;
639 char buf[32];
640 char *p;
641
642 if (NULL == n->args)
643 return(1);
644
645 for (i = 0; i < (int)n->args->argc; i++)
646 if (MDOC_Width == n->args->argv[i].arg)
647 break;
648
649 if (i == (int)n->args->argc)
650 return(1);
651 p = n->args->argv[i].value[0];
652
653 /*
654 * If the value to -width is a macro, then we re-write it to be
655 * the macro's width as set in share/tmac/mdoc/doc-common.
656 */
657
658 if (0 == strcmp(p, "Ds"))
659 width = 6;
660 else if (MDOC_MAX == (tok = mdoc_hash_find(p)))
661 return(1);
662 else if (0 == (width = mdoc_macro2len(tok)))
663 return(mdoc_nwarn(m, n, ENOWIDTH));
664
665 /* The value already exists: free and reallocate it. */
666
667 if (-1 == snprintf(buf, sizeof(buf), "%zun", width))
668 return(mdoc_nerr(m, n, ENUMFMT));
669
670 free(n->args->argv[i].value[0]);
671 n->args->argv[i].value[0] = strdup(buf);
672 if (NULL == n->args->argv[i].value[0])
673 return(mdoc_nerr(m, n, EMALLOC));
674
675 return(1);
676 }
677
678
679 /* ARGSUSED */
680 static int
681 post_bl_head(POST_ARGS)
682 {
683 int i, c;
684 struct mdoc_node *np, *nn, *nnp;
685
686 if (NULL == n->child)
687 return(1);
688
689 np = n->parent;
690 assert(np->args);
691
692 for (c = 0; c < (int)np->args->argc; c++)
693 if (MDOC_Column == np->args->argv[c].arg)
694 break;
695
696 /* Only process -column. */
697
698 if (c == (int)np->args->argc)
699 return(1);
700
701 assert(0 == np->args->argv[c].sz);
702
703 /*
704 * Accomodate for new-style groff column syntax. Shuffle the
705 * child nodes, all of which must be TEXT, as arguments for the
706 * column field. Then, delete the head children.
707 */
708
709 np->args->argv[c].sz = (size_t)n->nchild;
710 np->args->argv[c].value = malloc
711 ((size_t)n->nchild * sizeof(char *));
712
713 for (i = 0, nn = n->child; nn; i++) {
714 np->args->argv[c].value[i] = nn->string;
715 nn->string = NULL;
716 nnp = nn;
717 nn = nn->next;
718 mdoc_node_free(nnp);
719 }
720
721 n->nchild = 0;
722 n->child = NULL;
723
724 return(1);
725 }
726
727
728 static int
729 post_bl(POST_ARGS)
730 {
731 int i, r, len;
732
733 if (MDOC_HEAD == n->type)
734 return(post_bl_head(m, n));
735 if (MDOC_BLOCK != n->type)
736 return(1);
737
738 /*
739 * These are fairly complicated, so we've broken them into two
740 * functions. post_bl_tagwidth() is called when a -tag is
741 * specified, but no -width (it must be guessed). The second
742 * when a -width is specified (macro indicators must be
743 * rewritten into real lengths).
744 */
745
746 len = (int)(n->args ? n->args->argc : 0);
747
748 for (r = i = 0; i < len; i++) {
749 if (MDOC_Tag == n->args->argv[i].arg)
750 r |= 1 << 0;
751 if (MDOC_Width == n->args->argv[i].arg)
752 r |= 1 << 1;
753 }
754
755 if (r & (1 << 0) && ! (r & (1 << 1))) {
756 if ( ! post_bl_tagwidth(m, n))
757 return(0);
758 } else if (r & (1 << 1))
759 if ( ! post_bl_width(m, n))
760 return(0);
761
762 return(1);
763 }
764
765
766 static int
767 post_tilde(POST_ARGS)
768 {
769 struct mdoc_node *np;
770
771 if (n->child)
772 return(1);
773
774 np = n;
775 m->next = MDOC_NEXT_CHILD;
776
777 if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
778 return(0);
779 m->last = np;
780
781 return(1);
782 }
783
784
785 static int
786 post_ar(POST_ARGS)
787 {
788 struct mdoc_node *np;
789
790 if (n->child)
791 return(1);
792
793 np = n;
794 m->next = MDOC_NEXT_CHILD;
795 if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
796 return(0);
797 if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
798 return(0);
799 m->last = np;
800
801 return(1);
802 }
803
804
805 static int
806 post_dd(POST_ARGS)
807 {
808 char buf[64];
809
810 buf[0] = 0;
811 if ( ! concat(m, n->child, buf, sizeof(buf)))
812 return(0);
813
814 if (0 == (m->meta.date = mdoc_atotime(buf))) {
815 if ( ! mdoc_nwarn(m, n, EBADDATE))
816 return(0);
817 m->meta.date = time(NULL);
818 }
819
820 return(post_prol(m, n));
821 }
822
823
824 static int
825 post_prol(POST_ARGS)
826 {
827 struct mdoc_node *np;
828
829 /* Remove prologue macros from AST. */
830
831 if (n->parent->child == n)
832 n->parent->child = n->prev;
833 if (n->prev)
834 n->prev->next = NULL;
835
836 np = n;
837 assert(NULL == n->next);
838
839 if (n->prev) {
840 m->last = n->prev;
841 m->next = MDOC_NEXT_SIBLING;
842 } else {
843 m->last = n->parent;
844 m->next = MDOC_NEXT_CHILD;
845 }
846
847 mdoc_node_freelist(np);
848
849 if (m->meta.title && m->meta.date && m->meta.os)
850 m->flags |= MDOC_PBODY;
851
852 return(1);
853 }
854
855
856 static int
857 pre_dl(PRE_ARGS)
858 {
859
860 if (MDOC_BODY == n->type)
861 m->flags |= MDOC_LITERAL;
862 return(1);
863 }
864
865
866 static int
867 pre_offset(PRE_ARGS)
868 {
869 int i;
870
871 /*
872 * Make sure that an empty offset produces an 8n length space as
873 * stipulated by mdoc.samples.
874 */
875
876 assert(n->args);
877 for (i = 0; i < (int)n->args->argc; i++) {
878 if (MDOC_Offset != n->args->argv[i].arg)
879 continue;
880 if (n->args->argv[i].sz)
881 break;
882 assert(1 == n->args->refcnt);
883 /* If no value set, length of <string>. */
884 n->args->argv[i].value =
885 calloc(1, sizeof(char *));
886 if (NULL == n->args->argv[i].value)
887 return(mdoc_nerr(m, n, EMALLOC));
888 n->args->argv[i].sz++;
889 n->args->argv[i].value[0] = strdup("8n");
890 if (NULL == n->args->argv[i].value[0])
891 return(mdoc_nerr(m, n, EMALLOC));
892 break;
893 }
894
895 return(1);
896 }
897
898
899 static int
900 pre_bl(PRE_ARGS)
901 {
902
903 return(MDOC_BLOCK == n->type ? pre_offset(m, n) : 1);
904 }
905
906
907 static int
908 pre_bd(PRE_ARGS)
909 {
910 int i;
911
912 if (MDOC_BLOCK == n->type)
913 return(pre_offset(m, n));
914 if (MDOC_BODY != n->type)
915 return(1);
916
917 /* Enter literal context if `Bd -literal' or `-unfilled'. */
918
919 for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
920 if (MDOC_Literal == n->args->argv[i].arg)
921 m->flags |= MDOC_LITERAL;
922 else if (MDOC_Unfilled == n->args->argv[i].arg)
923 m->flags |= MDOC_LITERAL;
924
925 return(1);
926 }
927
928
929 static int
930 post_display(POST_ARGS)
931 {
932
933 if (MDOC_BODY == n->type)
934 m->flags &= ~MDOC_LITERAL;
935 return(1);
936 }
937
938
939 static inline int
940 order_rs(int t)
941 {
942 int i;
943
944 for (i = 0; i < RSORD_MAX; i++)
945 if (rsord[i] == t)
946 return(i);
947
948 abort();
949 /* NOTREACHED */
950 }
951
952
953 /* ARGSUSED */
954 static int
955 post_rs(POST_ARGS)
956 {
957 struct mdoc_node *nn, *next, *prev;
958 int o;
959
960 if (MDOC_BLOCK != n->type)
961 return(1);
962
963 assert(n->body->child);
964 for (next = NULL, nn = n->body->child->next; nn; nn = next) {
965 o = order_rs(nn->tok);
966
967 /* Remove `nn' from the chain. */
968 next = nn->next;
969 if (next)
970 next->prev = nn->prev;
971
972 prev = nn->prev;
973 if (prev)
974 prev->next = nn->next;
975
976 nn->prev = nn->next = NULL;
977
978 /*
979 * Scan back until we reach a node that's ordered before
980 * us, then set ourselves as being the next.
981 */
982 for ( ; prev; prev = prev->prev)
983 if (order_rs(prev->tok) <= o)
984 break;
985
986 nn->prev = prev;
987 if (prev) {
988 if (prev->next)
989 prev->next->prev = nn;
990 nn->next = prev->next;
991 prev->next = nn;
992 continue;
993 }
994
995 n->body->child->prev = nn;
996 nn->next = n->body->child;
997 n->body->child = nn;
998 }
999 return(1);
1000 }