1 /* $Id: man_term.c,v 1.228 2019/01/05 21:18:26 schwarze Exp $ */
3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
29 #include "mandoc_aux.h"
36 #define MAXMARGINS 64 /* maximum number of indented scopes */
39 int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
40 int lmargincur; /* index of current margin */
41 int lmarginsz; /* actual number of nested margins */
42 size_t offset; /* default offset to visible page */
43 int pardist; /* vert. space before par., unit: [v] */
46 #define DECL_ARGS struct termp *p, \
48 struct roff_node *n, \
49 const struct roff_meta *meta
52 int (*pre)(DECL_ARGS);
53 void (*post)(DECL_ARGS);
55 #define MAN_NOTEXT (1 << 0) /* Never has text children. */
58 static void print_man_nodelist(DECL_ARGS);
59 static void print_man_node(DECL_ARGS);
60 static void print_man_head(struct termp *,
61 const struct roff_meta *);
62 static void print_man_foot(struct termp *,
63 const struct roff_meta *);
64 static void print_bvspace(struct termp *,
65 const struct roff_node *, int);
67 static int pre_B(DECL_ARGS);
68 static int pre_DT(DECL_ARGS);
69 static int pre_HP(DECL_ARGS);
70 static int pre_I(DECL_ARGS);
71 static int pre_IP(DECL_ARGS);
72 static int pre_OP(DECL_ARGS);
73 static int pre_PD(DECL_ARGS);
74 static int pre_PP(DECL_ARGS);
75 static int pre_RS(DECL_ARGS);
76 static int pre_SH(DECL_ARGS);
77 static int pre_SS(DECL_ARGS);
78 static int pre_SY(DECL_ARGS);
79 static int pre_TP(DECL_ARGS);
80 static int pre_UR(DECL_ARGS);
81 static int pre_abort(DECL_ARGS);
82 static int pre_alternate(DECL_ARGS);
83 static int pre_ign(DECL_ARGS);
84 static int pre_in(DECL_ARGS);
85 static int pre_literal(DECL_ARGS);
87 static void post_IP(DECL_ARGS);
88 static void post_HP(DECL_ARGS);
89 static void post_RS(DECL_ARGS);
90 static void post_SH(DECL_ARGS);
91 static void post_SY(DECL_ARGS);
92 static void post_TP(DECL_ARGS);
93 static void post_UR(DECL_ARGS);
95 static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
96 { NULL, NULL, 0 }, /* TH */
97 { pre_SH, post_SH, 0 }, /* SH */
98 { pre_SS, post_SH, 0 }, /* SS */
99 { pre_TP, post_TP, 0 }, /* TP */
100 { pre_TP, post_TP, 0 }, /* TQ */
101 { pre_abort, NULL, 0 }, /* LP */
102 { pre_PP, NULL, 0 }, /* PP */
103 { pre_abort, NULL, 0 }, /* P */
104 { pre_IP, post_IP, 0 }, /* IP */
105 { pre_HP, post_HP, 0 }, /* HP */
106 { NULL, NULL, 0 }, /* SM */
107 { pre_B, NULL, 0 }, /* SB */
108 { pre_alternate, NULL, 0 }, /* BI */
109 { pre_alternate, NULL, 0 }, /* IB */
110 { pre_alternate, NULL, 0 }, /* BR */
111 { pre_alternate, NULL, 0 }, /* RB */
112 { NULL, NULL, 0 }, /* R */
113 { pre_B, NULL, 0 }, /* B */
114 { pre_I, NULL, 0 }, /* I */
115 { pre_alternate, NULL, 0 }, /* IR */
116 { pre_alternate, NULL, 0 }, /* RI */
117 { NULL, NULL, 0 }, /* RE */
118 { pre_RS, post_RS, 0 }, /* RS */
119 { pre_DT, NULL, 0 }, /* DT */
120 { pre_ign, NULL, MAN_NOTEXT }, /* UC */
121 { pre_PD, NULL, MAN_NOTEXT }, /* PD */
122 { pre_ign, NULL, 0 }, /* AT */
123 { pre_in, NULL, MAN_NOTEXT }, /* in */
124 { pre_SY, post_SY, 0 }, /* SY */
125 { NULL, NULL, 0 }, /* YS */
126 { pre_OP, NULL, 0 }, /* OP */
127 { pre_literal, NULL, 0 }, /* EX */
128 { pre_literal, NULL, 0 }, /* EE */
129 { pre_UR, post_UR, 0 }, /* UR */
130 { NULL, NULL, 0 }, /* UE */
131 { pre_UR, post_UR, 0 }, /* MT */
132 { NULL, NULL, 0 }, /* ME */
134 static const struct man_term_act *man_term_act(enum roff_tok);
137 static const struct man_term_act *
138 man_term_act(enum roff_tok tok)
140 assert(tok >= MAN_TH && tok <= MAN_MAX);
141 return man_term_acts + (tok - MAN_TH);
145 terminal_man(void *arg, const struct roff_meta *man)
150 size_t save_defindent;
152 p = (struct termp *)arg;
153 save_defindent = p->defindent;
154 if (p->synopsisonly == 0 && p->defindent == 0)
156 p->tcol->rmargin = p->maxrmargin = p->defrmargin;
157 term_tab_set(p, NULL);
158 term_tab_set(p, "T");
159 term_tab_set(p, ".5i");
161 memset(&mt, 0, sizeof(mt));
162 mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
163 mt.offset = term_len(p, p->defindent);
166 n = man->first->child;
167 if (p->synopsisonly) {
169 if (n->tok == MAN_SH &&
170 n->child->child->type == ROFFT_TEXT &&
171 !strcmp(n->child->child->string, "SYNOPSIS")) {
172 if (n->child->next->child != NULL)
173 print_man_nodelist(p, &mt,
174 n->child->next->child, man);
181 term_begin(p, print_man_head, print_man_foot, man);
182 p->flags |= TERMP_NOSPACE;
184 print_man_nodelist(p, &mt, n, man);
187 p->defindent = save_defindent;
191 * Printing leading vertical space before a block.
192 * This is used for the paragraph macros.
193 * The rules are pretty simple, since there's very little nesting going
194 * on here. Basically, if we're the first within another block (SS/SH),
195 * then don't emit vertical space. If we are (RS), then do. If not the
199 print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
205 if (n->body != NULL && n->body->child != NULL)
206 if (n->body->child->type == ROFFT_TBL)
209 if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
213 for (i = 0; i < pardist; i++)
233 term_fontrepl(p, TERMFONT_UNDER);
238 pre_literal(DECL_ARGS)
243 * Unlike .IP and .TP, .HP does not have a HEAD.
244 * So in case a second call to term_flushln() is needed,
245 * indentation has to be set up explicitly.
247 if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) {
248 p->tcol->offset = p->tcol->rmargin;
249 p->tcol->rmargin = p->maxrmargin;
251 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
252 p->flags |= TERMP_NOSPACE;
267 assert(n->type == ROFFT_TEXT);
268 if (a2roffsu(n->string, &su, SCALE_VS) != NULL)
269 mt->pardist = term_vspan(p, &su);
274 pre_alternate(DECL_ARGS)
276 enum termfont font[2];
277 struct roff_node *nn;
282 font[0] = TERMFONT_NONE;
283 font[1] = TERMFONT_BOLD;
286 font[0] = TERMFONT_NONE;
287 font[1] = TERMFONT_UNDER;
290 font[0] = TERMFONT_BOLD;
291 font[1] = TERMFONT_NONE;
294 font[0] = TERMFONT_BOLD;
295 font[1] = TERMFONT_UNDER;
298 font[0] = TERMFONT_UNDER;
299 font[1] = TERMFONT_NONE;
302 font[0] = TERMFONT_UNDER;
303 font[1] = TERMFONT_BOLD;
308 for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) {
309 term_fontrepl(p, font[i]);
310 assert(nn->type == ROFFT_TEXT);
311 term_word(p, nn->string);
312 if (nn->flags & NODE_EOS)
313 p->flags |= TERMP_SENTENCE;
314 if (nn->next != NULL)
315 p->flags |= TERMP_NOSPACE;
323 term_fontrepl(p, TERMFONT_BOLD);
331 p->flags |= TERMP_KEEP | TERMP_NOSPACE;
333 if ((n = n->child) != NULL) {
334 term_fontrepl(p, TERMFONT_BOLD);
335 term_word(p, n->string);
337 if (n != NULL && n->next != NULL) {
338 term_fontrepl(p, TERMFONT_UNDER);
339 term_word(p, n->next->string);
341 term_fontrepl(p, TERMFONT_NONE);
342 p->flags &= ~TERMP_KEEP;
343 p->flags |= TERMP_NOSPACE;
358 if (n->child == NULL) {
359 p->tcol->offset = mt->offset;
363 cp = n->child->string;
373 if (a2roffsu(++cp, &su, SCALE_EN) == NULL)
376 v = term_hen(p, &su);
379 p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset;
381 p->tcol->offset += v;
384 if (p->tcol->offset > SHRT_MAX)
385 p->tcol->offset = term_len(p, p->defindent);
393 term_tab_set(p, NULL);
394 term_tab_set(p, "T");
395 term_tab_set(p, ".5i");
403 const struct roff_node *nn;
408 print_bvspace(p, n, mt->pardist);
418 if (n->child == NULL)
421 if ((n->child->flags & NODE_NOFILL) == 0) {
422 p->flags |= TERMP_NOBREAK | TERMP_BRIND;
426 /* Calculate offset. */
428 if ((nn = n->parent->head->child) != NULL &&
429 a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
430 len = term_hen(p, &su);
431 if (len < 0 && (size_t)(-len) > mt->offset)
433 else if (len > SHRT_MAX)
434 len = term_len(p, p->defindent);
435 mt->lmargin[mt->lmargincur] = len;
437 len = mt->lmargin[mt->lmargincur];
439 p->tcol->offset = mt->offset;
440 p->tcol->rmargin = mt->offset + len;
455 * Compatibility with a groff bug.
456 * The .HP macro uses the undocumented .tag request
457 * which causes a line break and cancels no-space
458 * mode even if there isn't any output.
461 if (n->child == NULL)
464 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
466 p->tcol->offset = mt->offset;
467 p->tcol->rmargin = p->maxrmargin;
479 mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
480 print_bvspace(p, n, mt->pardist);
485 p->tcol->offset = mt->offset;
497 const struct roff_node *nn;
502 print_bvspace(p, n, mt->pardist);
505 p->flags |= TERMP_NOBREAK;
509 p->flags |= TERMP_NOSPACE;
515 /* Calculate the offset from the optional second argument. */
516 if ((nn = n->parent->head->child) != NULL &&
517 (nn = nn->next) != NULL &&
518 a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
519 len = term_hen(p, &su);
520 if (len < 0 && (size_t)(-len) > mt->offset)
522 else if (len > SHRT_MAX)
523 len = term_len(p, p->defindent);
524 mt->lmargin[mt->lmargincur] = len;
526 len = mt->lmargin[mt->lmargincur];
530 p->tcol->offset = mt->offset;
531 p->tcol->rmargin = mt->offset + len;
532 if (n->child != NULL)
533 print_man_node(p, mt, n->child, meta);
536 p->tcol->offset = mt->offset + len;
537 p->tcol->rmargin = p->maxrmargin;
553 p->flags &= ~TERMP_NOBREAK;
555 p->tcol->rmargin = p->maxrmargin;
559 p->tcol->offset = mt->offset;
570 struct roff_node *nn;
575 if (n->tok == MAN_TP)
576 print_bvspace(p, n, mt->pardist);
579 p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
583 p->flags |= TERMP_NOSPACE;
589 /* Calculate offset. */
591 if ((nn = n->parent->head->child) != NULL &&
592 nn->string != NULL && ! (NODE_LINE & nn->flags) &&
593 a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
594 len = term_hen(p, &su);
595 if (len < 0 && (size_t)(-len) > mt->offset)
597 else if (len > SHRT_MAX)
598 len = term_len(p, p->defindent);
599 mt->lmargin[mt->lmargincur] = len;
601 len = mt->lmargin[mt->lmargincur];
605 p->tcol->offset = mt->offset;
606 p->tcol->rmargin = mt->offset + len;
608 /* Don't print same-line elements. */
610 while (nn != NULL && (nn->flags & NODE_LINE) == 0)
614 print_man_node(p, mt, nn, meta);
619 p->tcol->offset = mt->offset + len;
620 p->tcol->rmargin = p->maxrmargin;
622 p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
641 p->tcol->offset = mt->offset;
655 mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
656 mt->offset = term_len(p, p->defindent);
659 * No vertical space before the first subsection
660 * and after an empty subsection.
665 } while (n != NULL && n->tok >= MAN_TH &&
666 man_term_act(n->tok)->flags & MAN_NOTEXT);
667 if (n == NULL || n->type == ROFFT_COMMENT ||
668 (n->tok == MAN_SS && n->body->child == NULL))
671 for (i = 0; i < mt->pardist; i++)
675 term_fontrepl(p, TERMFONT_BOLD);
676 p->tcol->offset = term_len(p, 3);
677 p->tcol->rmargin = mt->offset;
678 p->trailspace = mt->offset;
679 p->flags |= TERMP_NOBREAK | TERMP_BRIND;
682 p->tcol->offset = mt->offset;
683 p->tcol->rmargin = p->maxrmargin;
685 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
700 mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
701 mt->offset = term_len(p, p->defindent);
704 * No vertical space before the first section
705 * and after an empty section.
710 } while (n != NULL && n->tok >= MAN_TH &&
711 man_term_act(n->tok)->flags & MAN_NOTEXT);
712 if (n == NULL || n->type == ROFFT_COMMENT ||
713 (n->tok == MAN_SH && n->body->child == NULL))
716 for (i = 0; i < mt->pardist; i++)
720 term_fontrepl(p, TERMFONT_BOLD);
722 p->tcol->rmargin = mt->offset;
723 p->trailspace = mt->offset;
724 p->flags |= TERMP_NOBREAK | TERMP_BRIND;
727 p->tcol->offset = mt->offset;
728 p->tcol->rmargin = p->maxrmargin;
730 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
771 n->aux = SHRT_MAX + 1;
772 if (n->child == NULL)
773 n->aux = mt->lmargin[mt->lmargincur];
774 else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL)
775 n->aux = term_hen(p, &su);
776 if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
777 n->aux = -mt->offset;
778 else if (n->aux > SHRT_MAX)
779 n->aux = term_len(p, p->defindent);
781 mt->offset += n->aux;
782 p->tcol->offset = mt->offset;
783 p->tcol->rmargin = p->maxrmargin;
785 if (++mt->lmarginsz < MAXMARGINS)
786 mt->lmargincur = mt->lmarginsz;
788 mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
805 mt->offset -= n->parent->head->aux;
806 p->tcol->offset = mt->offset;
807 if (--mt->lmarginsz < MAXMARGINS)
808 mt->lmargincur = mt->lmarginsz;
814 const struct roff_node *nn;
819 if (n->prev == NULL || n->prev->tok != MAN_SY)
820 print_bvspace(p, n, mt->pardist);
829 nn = n->parent->head->child;
830 len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1;
834 p->tcol->offset = mt->offset;
835 p->tcol->rmargin = mt->offset + len;
836 if (n->next->child == NULL ||
837 (n->next->child->flags & NODE_NOFILL) == 0)
838 p->flags |= TERMP_NOBREAK;
839 term_fontrepl(p, TERMFONT_BOLD);
842 mt->lmargin[mt->lmargincur] = len;
843 p->tcol->offset = mt->offset + len;
844 p->tcol->rmargin = p->maxrmargin;
845 p->flags |= TERMP_NOSPACE;
861 p->flags &= ~TERMP_NOBREAK;
865 p->tcol->offset = mt->offset;
875 return n->type != ROFFT_HEAD;
881 if (n->type != ROFFT_BLOCK)
885 p->flags |= TERMP_NOSPACE;
887 if (n->child->child != NULL)
888 print_man_node(p, mt, n->child->child, meta);
890 p->flags |= TERMP_NOSPACE;
895 print_man_node(DECL_ARGS)
897 const struct man_term_act *act;
903 * If we have a blank line, output a vertical space.
904 * If we have a space as the first character, break
905 * before printing the line's data.
907 if (*n->string == '\0') {
908 if (p->flags & TERMP_NONEWLINE)
913 } else if (*n->string == ' ' && n->flags & NODE_LINE &&
914 (p->flags & TERMP_NONEWLINE) == 0)
916 else if (n->flags & NODE_DELIMC)
917 p->flags |= TERMP_NOSPACE;
919 term_word(p, n->string);
924 if ( ! (n->flags & NODE_LINE))
925 p->flags |= TERMP_NOSPACE;
927 if (n->next != NULL && ! (n->next->flags & NODE_LINE))
928 p->flags |= TERMP_NOSPACE;
931 if (p->tbl.cols == NULL)
933 term_tbl(p, n->span);
939 if (n->tok < ROFF_MAX) {
944 act = man_term_act(n->tok);
945 if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
946 term_fontrepl(p, TERMFONT_NONE);
949 if (act->pre != NULL)
950 c = (*act->pre)(p, mt, n, meta);
952 if (c && n->child != NULL)
953 print_man_nodelist(p, mt, n->child, meta);
955 if (act->post != NULL)
956 (*act->post)(p, mt, n, meta);
957 if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
958 term_fontrepl(p, TERMFONT_NONE);
962 * If we're in a literal context, make sure that words
963 * together on the same line stay together. This is a
964 * POST-printing call, so we check the NEXT word. Since
965 * -man doesn't have nested macros, we don't need to be
966 * more specific than this.
968 if (n->flags & NODE_NOFILL &&
969 ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
970 (n->next == NULL || n->next->flags & NODE_LINE)) {
971 p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
972 if (n->string != NULL && *n->string != '\0')
976 p->flags &= ~TERMP_BRNEVER;
977 if (p->tcol->rmargin < p->maxrmargin &&
978 n->parent->tok == MAN_HP) {
979 p->tcol->offset = p->tcol->rmargin;
980 p->tcol->rmargin = p->maxrmargin;
983 if (n->flags & NODE_EOS)
984 p->flags |= TERMP_SENTENCE;
988 print_man_nodelist(DECL_ARGS)
991 print_man_node(p, mt, n, meta);
997 print_man_foot(struct termp *p, const struct roff_meta *meta)
1000 size_t datelen, titlen;
1002 assert(meta->title);
1006 term_fontrepl(p, TERMFONT_NONE);
1012 * Temporary, undocumented option to imitate mdoc(7) output.
1013 * In the bottom right corner, use the operating system
1014 * instead of the title.
1017 if ( ! p->mdocstyle) {
1018 if (meta->hasbody) {
1022 mandoc_asprintf(&title, "%s(%s)",
1023 meta->title, meta->msec);
1024 } else if (meta->os != NULL) {
1025 title = mandoc_strdup(meta->os);
1027 title = mandoc_strdup("");
1029 datelen = term_strlen(p, meta->date);
1031 /* Bottom left corner: operating system. */
1033 p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1035 p->tcol->offset = 0;
1036 p->tcol->rmargin = p->maxrmargin > datelen ?
1037 (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
1040 term_word(p, meta->os);
1043 /* At the bottom in the middle: manual date. */
1045 p->tcol->offset = p->tcol->rmargin;
1046 titlen = term_strlen(p, title);
1047 p->tcol->rmargin = p->maxrmargin > titlen ?
1048 p->maxrmargin - titlen : 0;
1049 p->flags |= TERMP_NOSPACE;
1051 term_word(p, meta->date);
1054 /* Bottom right corner: manual title and section. */
1056 p->flags &= ~TERMP_NOBREAK;
1057 p->flags |= TERMP_NOSPACE;
1059 p->tcol->offset = p->tcol->rmargin;
1060 p->tcol->rmargin = p->maxrmargin;
1062 term_word(p, title);
1066 * Reset the terminal state for more output after the footer:
1067 * Some output modes, in particular PostScript and PDF, print
1068 * the header and the footer into a buffer such that it can be
1069 * reused for multiple output pages, then go on to format the
1073 p->tcol->offset = 0;
1080 print_man_head(struct termp *p, const struct roff_meta *meta)
1084 size_t vollen, titlen;
1086 assert(meta->title);
1089 volume = NULL == meta->vol ? "" : meta->vol;
1090 vollen = term_strlen(p, volume);
1092 /* Top left corner: manual title and section. */
1094 mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
1095 titlen = term_strlen(p, title);
1097 p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1099 p->tcol->offset = 0;
1100 p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
1101 (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
1102 vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
1104 term_word(p, title);
1107 /* At the top in the middle: manual volume. */
1109 p->flags |= TERMP_NOSPACE;
1110 p->tcol->offset = p->tcol->rmargin;
1111 p->tcol->rmargin = p->tcol->offset + vollen + titlen <
1112 p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
1114 term_word(p, volume);
1117 /* Top right corner: title and section, again. */
1119 p->flags &= ~TERMP_NOBREAK;
1121 if (p->tcol->rmargin + titlen <= p->maxrmargin) {
1122 p->flags |= TERMP_NOSPACE;
1123 p->tcol->offset = p->tcol->rmargin;
1124 p->tcol->rmargin = p->maxrmargin;
1125 term_word(p, title);
1129 p->flags &= ~TERMP_NOSPACE;
1130 p->tcol->offset = 0;
1131 p->tcol->rmargin = p->maxrmargin;
1134 * Groff prints three blank lines before the content.
1135 * Do the same, except in the temporary, undocumented
1136 * mode imitating mdoc(7) output.
1140 if ( ! p->mdocstyle) {