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