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