1 /* $Id: mdoc_action.c,v 1.24 2009/10/27 21:40:07 schwarze Exp $ */
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.
18 #include <sys/utsname.h>
30 #define POST_ARGS struct mdoc *m, struct mdoc_node *n
31 #define PRE_ARGS struct mdoc *m, const struct mdoc_node *n
35 int (*post)(POST_ARGS);
38 static int concat(struct mdoc *,
39 const struct mdoc_node *,
41 static inline int order_rs(int);
43 static int post_ar(POST_ARGS);
44 static int post_at(POST_ARGS);
45 static int post_bl(POST_ARGS);
46 static int post_bl_head(POST_ARGS);
47 static int post_bl_tagwidth(POST_ARGS);
48 static int post_bl_width(POST_ARGS);
49 static int post_dd(POST_ARGS);
50 static int post_display(POST_ARGS);
51 static int post_dt(POST_ARGS);
52 static int post_lb(POST_ARGS);
53 static int post_nm(POST_ARGS);
54 static int post_os(POST_ARGS);
55 static int post_prol(POST_ARGS);
56 static int post_rs(POST_ARGS);
57 static int post_sh(POST_ARGS);
58 static int post_st(POST_ARGS);
59 static int post_std(POST_ARGS);
60 static int post_tilde(POST_ARGS);
62 static int pre_bd(PRE_ARGS);
63 static int pre_bl(PRE_ARGS);
64 static int pre_dl(PRE_ARGS);
65 static int pre_offset(PRE_ARGS);
67 static const struct actions mdoc_actions[MDOC_MAX] = {
68 { NULL, NULL }, /* Ap */
69 { NULL, post_dd }, /* Dd */
70 { NULL, post_dt }, /* Dt */
71 { NULL, post_os }, /* Os */
72 { NULL, post_sh }, /* Sh */
73 { NULL, NULL }, /* Ss */
74 { NULL, NULL }, /* Pp */
75 { NULL, NULL }, /* D1 */
76 { pre_dl, post_display }, /* Dl */
77 { pre_bd, post_display }, /* Bd */
78 { NULL, NULL }, /* Ed */
79 { pre_bl, post_bl }, /* Bl */
80 { NULL, NULL }, /* El */
81 { NULL, NULL }, /* It */
82 { NULL, NULL }, /* Ad */
83 { NULL, NULL }, /* An */
84 { NULL, post_ar }, /* Ar */
85 { NULL, NULL }, /* Cd */
86 { NULL, NULL }, /* Cm */
87 { NULL, NULL }, /* Dv */
88 { NULL, NULL }, /* Er */
89 { NULL, NULL }, /* Ev */
90 { NULL, post_std }, /* Ex */
91 { NULL, NULL }, /* Fa */
92 { NULL, NULL }, /* Fd */
93 { NULL, NULL }, /* Fl */
94 { NULL, NULL }, /* Fn */
95 { NULL, NULL }, /* Ft */
96 { NULL, NULL }, /* Ic */
97 { NULL, NULL }, /* In */
98 { NULL, NULL }, /* Li */
99 { NULL, NULL }, /* Nd */
100 { NULL, post_nm }, /* Nm */
101 { NULL, NULL }, /* Op */
102 { NULL, NULL }, /* Ot */
103 { NULL, post_tilde }, /* Pa */
104 { NULL, post_std }, /* Rv */
105 { NULL, post_st }, /* St */
106 { NULL, NULL }, /* Va */
107 { NULL, NULL }, /* Vt */
108 { NULL, NULL }, /* Xr */
109 { NULL, NULL }, /* %A */
110 { NULL, NULL }, /* %B */
111 { NULL, NULL }, /* %D */
112 { NULL, NULL }, /* %I */
113 { NULL, NULL }, /* %J */
114 { NULL, NULL }, /* %N */
115 { NULL, NULL }, /* %O */
116 { NULL, NULL }, /* %P */
117 { NULL, NULL }, /* %R */
118 { NULL, NULL }, /* %T */
119 { NULL, NULL }, /* %V */
120 { NULL, NULL }, /* Ac */
121 { NULL, NULL }, /* Ao */
122 { NULL, NULL }, /* Aq */
123 { NULL, post_at }, /* At */
124 { NULL, NULL }, /* Bc */
125 { NULL, NULL }, /* Bf */
126 { NULL, NULL }, /* Bo */
127 { NULL, NULL }, /* Bq */
128 { NULL, NULL }, /* Bsx */
129 { NULL, NULL }, /* Bx */
130 { NULL, NULL }, /* Db */
131 { NULL, NULL }, /* Dc */
132 { NULL, NULL }, /* Do */
133 { NULL, NULL }, /* Dq */
134 { NULL, NULL }, /* Ec */
135 { NULL, NULL }, /* Ef */
136 { NULL, NULL }, /* Em */
137 { NULL, NULL }, /* Eo */
138 { NULL, NULL }, /* Fx */
139 { NULL, NULL }, /* Ms */
140 { NULL, NULL }, /* No */
141 { NULL, NULL }, /* Ns */
142 { NULL, NULL }, /* Nx */
143 { NULL, NULL }, /* Ox */
144 { NULL, NULL }, /* Pc */
145 { NULL, NULL }, /* Pf */
146 { NULL, NULL }, /* Po */
147 { NULL, NULL }, /* Pq */
148 { NULL, NULL }, /* Qc */
149 { NULL, NULL }, /* Ql */
150 { NULL, NULL }, /* Qo */
151 { NULL, NULL }, /* Qq */
152 { NULL, NULL }, /* Re */
153 { NULL, post_rs }, /* Rs */
154 { NULL, NULL }, /* Sc */
155 { NULL, NULL }, /* So */
156 { NULL, NULL }, /* Sq */
157 { NULL, NULL }, /* Sm */
158 { NULL, NULL }, /* Sx */
159 { NULL, NULL }, /* Sy */
160 { NULL, NULL }, /* Tn */
161 { NULL, NULL }, /* Ux */
162 { NULL, NULL }, /* Xc */
163 { NULL, NULL }, /* Xo */
164 { NULL, NULL }, /* Fo */
165 { NULL, NULL }, /* Fc */
166 { NULL, NULL }, /* Oo */
167 { NULL, NULL }, /* Oc */
168 { NULL, NULL }, /* Bk */
169 { NULL, NULL }, /* Ek */
170 { NULL, NULL }, /* Bt */
171 { NULL, NULL }, /* Hf */
172 { NULL, NULL }, /* Fr */
173 { NULL, NULL }, /* Ud */
174 { NULL, post_lb }, /* Lb */
175 { NULL, NULL }, /* Lp */
176 { NULL, NULL }, /* Lk */
177 { NULL, NULL }, /* Mt */
178 { NULL, NULL }, /* Brq */
179 { NULL, NULL }, /* Bro */
180 { NULL, NULL }, /* Brc */
181 { NULL, NULL }, /* %C */
182 { NULL, NULL }, /* Es */
183 { NULL, NULL }, /* En */
184 { NULL, NULL }, /* Dx */
185 { NULL, NULL }, /* %Q */
186 { NULL, NULL }, /* br */
187 { NULL, NULL }, /* sp */
188 { NULL, NULL }, /* %U */
193 static const int rsord[RSORD_MAX] = {
212 mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
224 if (NULL == mdoc_actions[n->tok].pre)
226 return((*mdoc_actions[n->tok].pre)(m, n));
231 mdoc_action_post(struct mdoc *m)
234 if (MDOC_ACTED & m->last->flags)
236 m->last->flags |= MDOC_ACTED;
238 switch (m->last->type) {
247 if (NULL == mdoc_actions[m->last->tok].post)
249 return((*mdoc_actions[m->last->tok].post)(m, m->last));
254 concat(struct mdoc *m, const struct mdoc_node *n,
255 char *buf, size_t sz)
258 for ( ; n; n = n->next) {
259 assert(MDOC_TEXT == n->type);
260 if (strlcat(buf, n->string, sz) >= sz)
261 return(mdoc_nerr(m, n, ETOOLONG));
264 if (strlcat(buf, " ", sz) >= sz)
265 return(mdoc_nerr(m, n, ETOOLONG));
275 struct mdoc_node *nn;
281 m->next = MDOC_NEXT_CHILD;
282 assert(m->meta.name);
283 if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
300 if ( ! concat(m, n->child, buf, sizeof(buf)))
302 if (NULL == (m->meta.name = strdup(buf)))
303 return(mdoc_nerr(m, n, EMALLOC));
316 assert(MDOC_TEXT == n->child->type);
317 p = mdoc_a2lib(n->child->string);
319 sz = strlen(n->child->string) +
320 2 + strlen("\\(lqlibrary\\(rq");
323 return(mdoc_nerr(m, n, EMALLOC));
324 (void)snprintf(buf, sz, "library \\(lq%s\\(rq",
326 free(n->child->string);
327 n->child->string = buf;
331 free(n->child->string);
332 n->child->string = strdup(p);
333 if (NULL == n->child->string)
334 return(mdoc_nerr(m, n, EMALLOC));
345 assert(MDOC_TEXT == n->child->type);
346 p = mdoc_a2st(n->child->string);
348 free(n->child->string);
349 n->child->string = strdup(p);
350 if (NULL == n->child->string)
351 return(mdoc_nerr(m, n, EMALLOC));
360 struct mdoc_node *nn;
364 assert(MDOC_TEXT == n->child->type);
365 p = mdoc_a2att(n->child->string);
367 free(n->child->string);
368 n->child->string = strdup(p);
369 if (NULL == n->child->string)
370 return(mdoc_nerr(m, n, EMALLOC));
375 m->next = MDOC_NEXT_CHILD;
377 if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
392 * We keep track of the current section /and/ the "named"
393 * section, which is one of the conventional ones, in order to
397 if (MDOC_HEAD != n->type)
401 if ( ! concat(m, n->child, buf, sizeof(buf)))
403 if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
406 switch ((m->lastsec = sec)) {
407 case (SEC_RETURN_VALUES):
410 switch (m->meta.msec) {
418 return(mdoc_nwarn(m, n, EBADSEC));
431 struct mdoc_node *nn;
443 m->meta.title = m->meta.vol = m->meta.arch = NULL;
447 * --> title = unknown, volume = local, msec = 0, arch = NULL
450 if (NULL == (nn = n->child)) {
451 if (NULL == (m->meta.title = strdup("unknown")))
452 return(mdoc_nerr(m, n, EMALLOC));
453 if (NULL == (m->meta.vol = strdup("local")))
454 return(mdoc_nerr(m, n, EMALLOC));
455 return(post_prol(m, n));
458 /* Handles: `.Dt TITLE'
459 * --> title = TITLE, volume = local, msec = 0, arch = NULL
462 if (NULL == (m->meta.title = strdup(nn->string)))
463 return(mdoc_nerr(m, n, EMALLOC));
465 if (NULL == (nn = nn->next)) {
466 if (NULL == (m->meta.vol = strdup("local")))
467 return(mdoc_nerr(m, n, EMALLOC));
468 return(post_prol(m, n));
471 /* Handles: `.Dt TITLE SEC'
472 * --> title = TITLE, volume = SEC is msec ?
473 * format(msec) : SEC,
474 * msec = SEC is msec ? atoi(msec) : 0,
478 cp = mdoc_a2msec(nn->string);
480 if (NULL == (m->meta.vol = strdup(cp)))
481 return(mdoc_nerr(m, n, EMALLOC));
483 lval = strtol(nn->string, &ep, 10);
484 if (nn->string[0] != '\0' && *ep == '\0')
485 m->meta.msec = (int)lval;
486 } else if (NULL == (m->meta.vol = strdup(nn->string)))
487 return(mdoc_nerr(m, n, EMALLOC));
489 if (NULL == (nn = nn->next))
490 return(post_prol(m, n));
492 /* Handles: `.Dt TITLE SEC VOL'
493 * --> title = TITLE, volume = VOL is vol ?
495 * VOL is arch ? format(arch) :
499 cp = mdoc_a2vol(nn->string);
502 if (NULL == (m->meta.vol = strdup(cp)))
503 return(mdoc_nerr(m, n, EMALLOC));
505 cp = mdoc_a2arch(nn->string);
508 if (NULL == (m->meta.vol = strdup(nn->string)))
509 return(mdoc_nerr(m, n, EMALLOC));
510 } else if (NULL == (m->meta.arch = strdup(cp)))
511 return(mdoc_nerr(m, n, EMALLOC));
514 /* Ignore any subsequent parameters... */
516 return(post_prol(m, n));
525 struct utsname utsname;
529 * Setting OSNAME to be the name of the target operating system,
530 * e.g., "OpenBSD 4.4", will result in the compile-time constant
531 * by supplied instead of the value in uname().
538 if ( ! concat(m, n->child, buf, sizeof(buf)))
543 if (strlcat(buf, OSNAME, 64) >= 64)
544 return(mdoc_nerr(m, n, EUTSNAME));
546 if (-1 == uname(&utsname))
547 return(mdoc_nerr(m, n, EUTSNAME));
548 if (strlcat(buf, utsname.sysname, 64) >= 64)
549 return(mdoc_nerr(m, n, ETOOLONG));
550 if (strlcat(buf, " ", 64) >= 64)
551 return(mdoc_nerr(m, n, ETOOLONG));
552 if (strlcat(buf, utsname.release, 64) >= 64)
553 return(mdoc_nerr(m, n, ETOOLONG));
557 if (NULL == (m->meta.os = strdup(buf)))
558 return(mdoc_nerr(m, n, EMALLOC));
560 return(post_prol(m, n));
565 * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
566 * Uses the first head macro.
569 post_bl_tagwidth(POST_ARGS)
571 struct mdoc_node *nn;
576 * Use the text width, if a text node, or the default macro
582 assert(MDOC_BLOCK == nn->type);
583 assert(MDOC_It == nn->tok);
584 nn = nn->head->child;
587 sz = 10; /* Default size. */
590 if (MDOC_TEXT != nn->type) {
591 if (0 == (sz = (int)mdoc_macro2len(nn->tok)))
592 if ( ! mdoc_nwarn(m, n, ENOWIDTH))
595 sz = (int)strlen(nn->string) + 1;
598 if (-1 == snprintf(buf, sizeof(buf), "%dn", sz))
599 return(mdoc_nerr(m, n, ENUMFMT));
602 * We have to dynamically add this to the macro's argument list.
603 * We're guaranteed that a MDOC_Width doesn't already exist.
608 sz = (int)(nn->args->argc)++;
610 nn->args->argv = realloc(nn->args->argv,
611 nn->args->argc * sizeof(struct mdoc_argv));
613 if (NULL == nn->args->argv)
614 return(mdoc_nerr(m, n, EMALLOC));
616 nn->args->argv[sz].arg = MDOC_Width;
617 nn->args->argv[sz].line = n->line;
618 nn->args->argv[sz].pos = n->pos;
619 nn->args->argv[sz].sz = 1;
620 nn->args->argv[sz].value = calloc(1, sizeof(char *));
622 if (NULL == nn->args->argv[sz].value)
623 return(mdoc_nerr(m, n, EMALLOC));
624 if (NULL == (nn->args->argv[sz].value[0] = strdup(buf)))
625 return(mdoc_nerr(m, n, EMALLOC));
632 post_bl_width(POST_ARGS)
642 for (i = 0; i < (int)n->args->argc; i++)
643 if (MDOC_Width == n->args->argv[i].arg)
646 if (i == (int)n->args->argc)
648 p = n->args->argv[i].value[0];
651 * If the value to -width is a macro, then we re-write it to be
652 * the macro's width as set in share/tmac/mdoc/doc-common.
655 if (0 == strcmp(p, "Ds"))
657 else if (MDOC_MAX == (tok = mdoc_hash_find(p)))
659 else if (0 == (width = mdoc_macro2len(tok)))
660 return(mdoc_nwarn(m, n, ENOWIDTH));
662 /* The value already exists: free and reallocate it. */
664 if (-1 == snprintf(buf, sizeof(buf), "%zun", width))
665 return(mdoc_nerr(m, n, ENUMFMT));
667 free(n->args->argv[i].value[0]);
668 n->args->argv[i].value[0] = strdup(buf);
669 if (NULL == n->args->argv[i].value[0])
670 return(mdoc_nerr(m, n, EMALLOC));
678 post_bl_head(POST_ARGS)
681 struct mdoc_node *np, *nn, *nnp;
683 if (NULL == n->child)
689 for (c = 0; c < (int)np->args->argc; c++)
690 if (MDOC_Column == np->args->argv[c].arg)
693 /* Only process -column. */
695 if (c == (int)np->args->argc)
698 assert(0 == np->args->argv[c].sz);
701 * Accomodate for new-style groff column syntax. Shuffle the
702 * child nodes, all of which must be TEXT, as arguments for the
703 * column field. Then, delete the head children.
706 np->args->argv[c].sz = (size_t)n->nchild;
707 np->args->argv[c].value = malloc
708 ((size_t)n->nchild * sizeof(char *));
710 for (i = 0, nn = n->child; nn; i++) {
711 np->args->argv[c].value[i] = nn->string;
730 if (MDOC_HEAD == n->type)
731 return(post_bl_head(m, n));
732 if (MDOC_BLOCK != n->type)
736 * These are fairly complicated, so we've broken them into two
737 * functions. post_bl_tagwidth() is called when a -tag is
738 * specified, but no -width (it must be guessed). The second
739 * when a -width is specified (macro indicators must be
740 * rewritten into real lengths).
743 len = (int)(n->args ? n->args->argc : 0);
745 for (r = i = 0; i < len; i++) {
746 if (MDOC_Tag == n->args->argv[i].arg)
748 if (MDOC_Width == n->args->argv[i].arg)
752 if (r & (1 << 0) && ! (r & (1 << 1))) {
753 if ( ! post_bl_tagwidth(m, n))
755 } else if (r & (1 << 1))
756 if ( ! post_bl_width(m, n))
764 post_tilde(POST_ARGS)
766 struct mdoc_node *np;
772 m->next = MDOC_NEXT_CHILD;
774 if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
785 struct mdoc_node *np;
791 m->next = MDOC_NEXT_CHILD;
792 if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
794 if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
808 if ( ! concat(m, n->child, buf, sizeof(buf)))
811 if (0 == (m->meta.date = mdoc_atotime(buf))) {
812 if ( ! mdoc_nwarn(m, n, EBADDATE))
814 m->meta.date = time(NULL);
817 return(post_prol(m, n));
824 struct mdoc_node *np;
826 /* Remove prologue macros from AST. */
828 if (n->parent->child == n)
829 n->parent->child = n->prev;
831 n->prev->next = NULL;
834 assert(NULL == n->next);
838 m->next = MDOC_NEXT_SIBLING;
841 m->next = MDOC_NEXT_CHILD;
844 mdoc_node_freelist(np);
846 if (m->meta.title && m->meta.date && m->meta.os)
847 m->flags |= MDOC_PBODY;
857 if (MDOC_BODY == n->type)
858 m->flags |= MDOC_LITERAL;
869 * Make sure that an empty offset produces an 8n length space as
870 * stipulated by mdoc.samples.
874 for (i = 0; i < (int)n->args->argc; i++) {
875 if (MDOC_Offset != n->args->argv[i].arg)
877 if (n->args->argv[i].sz)
879 assert(1 == n->args->refcnt);
880 /* If no value set, length of <string>. */
881 n->args->argv[i].value =
882 calloc(1, sizeof(char *));
883 if (NULL == n->args->argv[i].value)
884 return(mdoc_nerr(m, n, EMALLOC));
885 n->args->argv[i].sz++;
886 n->args->argv[i].value[0] = strdup("8n");
887 if (NULL == n->args->argv[i].value[0])
888 return(mdoc_nerr(m, n, EMALLOC));
900 return(MDOC_BLOCK == n->type ? pre_offset(m, n) : 1);
909 if (MDOC_BLOCK == n->type)
910 return(pre_offset(m, n));
911 if (MDOC_BODY != n->type)
914 /* Enter literal context if `Bd -literal' or `-unfilled'. */
916 for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
917 if (MDOC_Literal == n->args->argv[i].arg)
918 m->flags |= MDOC_LITERAL;
919 else if (MDOC_Unfilled == n->args->argv[i].arg)
920 m->flags |= MDOC_LITERAL;
927 post_display(POST_ARGS)
930 if (MDOC_BODY == n->type)
931 m->flags &= ~MDOC_LITERAL;
941 for (i = 0; i < RSORD_MAX; i++)
954 struct mdoc_node *nn, *next, *prev;
957 if (MDOC_BLOCK != n->type)
960 assert(n->body->child);
961 for (next = NULL, nn = n->body->child->next; nn; nn = next) {
962 o = order_rs(nn->tok);
964 /* Remove `nn' from the chain. */
967 next->prev = nn->prev;
971 prev->next = nn->next;
973 nn->prev = nn->next = NULL;
976 * Scan back until we reach a node that's ordered before
977 * us, then set ourselves as being the next.
979 for ( ; prev; prev = prev->prev)
980 if (order_rs(prev->tok) <= o)
986 prev->next->prev = nn;
987 nn->next = prev->next;
992 n->body->child->prev = nn;
993 nn->next = n->body->child;