1*260e9a87SYuri Pankov /* $Id: man_term.c,v 1.169 2015/03/06 15:48:52 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4*260e9a87SYuri Pankov * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #include "config.h" 1995c635efSGarrett D'Amore 2095c635efSGarrett D'Amore #include <sys/types.h> 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <assert.h> 2395c635efSGarrett D'Amore #include <ctype.h> 24*260e9a87SYuri Pankov #include <limits.h> 2595c635efSGarrett D'Amore #include <stdio.h> 2695c635efSGarrett D'Amore #include <stdlib.h> 2795c635efSGarrett D'Amore #include <string.h> 2895c635efSGarrett D'Amore 2995c635efSGarrett D'Amore #include "mandoc.h" 30*260e9a87SYuri Pankov #include "mandoc_aux.h" 3195c635efSGarrett D'Amore #include "out.h" 3295c635efSGarrett D'Amore #include "man.h" 3395c635efSGarrett D'Amore #include "term.h" 3495c635efSGarrett D'Amore #include "main.h" 3595c635efSGarrett D'Amore 3695c635efSGarrett D'Amore #define MAXMARGINS 64 /* maximum number of indented scopes */ 3795c635efSGarrett D'Amore 3895c635efSGarrett D'Amore struct mtermp { 3995c635efSGarrett D'Amore int fl; 4095c635efSGarrett D'Amore #define MANT_LITERAL (1 << 0) 41*260e9a87SYuri Pankov int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */ 4295c635efSGarrett D'Amore int lmargincur; /* index of current margin */ 4395c635efSGarrett D'Amore int lmarginsz; /* actual number of nested margins */ 4495c635efSGarrett D'Amore size_t offset; /* default offset to visible page */ 45698f87a4SGarrett D'Amore int pardist; /* vert. space before par., unit: [v] */ 4695c635efSGarrett D'Amore }; 4795c635efSGarrett D'Amore 4895c635efSGarrett D'Amore #define DECL_ARGS struct termp *p, \ 4995c635efSGarrett D'Amore struct mtermp *mt, \ 50*260e9a87SYuri Pankov struct man_node *n, \ 51698f87a4SGarrett D'Amore const struct man_meta *meta 5295c635efSGarrett D'Amore 5395c635efSGarrett D'Amore struct termact { 5495c635efSGarrett D'Amore int (*pre)(DECL_ARGS); 5595c635efSGarrett D'Amore void (*post)(DECL_ARGS); 5695c635efSGarrett D'Amore int flags; 5795c635efSGarrett D'Amore #define MAN_NOTEXT (1 << 0) /* Never has text children. */ 5895c635efSGarrett D'Amore }; 5995c635efSGarrett D'Amore 6095c635efSGarrett D'Amore static void print_man_nodelist(DECL_ARGS); 6195c635efSGarrett D'Amore static void print_man_node(DECL_ARGS); 6295c635efSGarrett D'Amore static void print_man_head(struct termp *, const void *); 6395c635efSGarrett D'Amore static void print_man_foot(struct termp *, const void *); 6495c635efSGarrett D'Amore static void print_bvspace(struct termp *, 65698f87a4SGarrett D'Amore const struct man_node *, int); 6695c635efSGarrett D'Amore 6795c635efSGarrett D'Amore static int pre_B(DECL_ARGS); 6895c635efSGarrett D'Amore static int pre_HP(DECL_ARGS); 6995c635efSGarrett D'Amore static int pre_I(DECL_ARGS); 7095c635efSGarrett D'Amore static int pre_IP(DECL_ARGS); 7195c635efSGarrett D'Amore static int pre_OP(DECL_ARGS); 72698f87a4SGarrett D'Amore static int pre_PD(DECL_ARGS); 7395c635efSGarrett D'Amore static int pre_PP(DECL_ARGS); 7495c635efSGarrett D'Amore static int pre_RS(DECL_ARGS); 7595c635efSGarrett D'Amore static int pre_SH(DECL_ARGS); 7695c635efSGarrett D'Amore static int pre_SS(DECL_ARGS); 7795c635efSGarrett D'Amore static int pre_TP(DECL_ARGS); 78698f87a4SGarrett D'Amore static int pre_UR(DECL_ARGS); 7995c635efSGarrett D'Amore static int pre_alternate(DECL_ARGS); 8095c635efSGarrett D'Amore static int pre_ft(DECL_ARGS); 8195c635efSGarrett D'Amore static int pre_ign(DECL_ARGS); 8295c635efSGarrett D'Amore static int pre_in(DECL_ARGS); 8395c635efSGarrett D'Amore static int pre_literal(DECL_ARGS); 84*260e9a87SYuri Pankov static int pre_ll(DECL_ARGS); 8595c635efSGarrett D'Amore static int pre_sp(DECL_ARGS); 8695c635efSGarrett D'Amore 8795c635efSGarrett D'Amore static void post_IP(DECL_ARGS); 8895c635efSGarrett D'Amore static void post_HP(DECL_ARGS); 8995c635efSGarrett D'Amore static void post_RS(DECL_ARGS); 9095c635efSGarrett D'Amore static void post_SH(DECL_ARGS); 9195c635efSGarrett D'Amore static void post_SS(DECL_ARGS); 9295c635efSGarrett D'Amore static void post_TP(DECL_ARGS); 93698f87a4SGarrett D'Amore static void post_UR(DECL_ARGS); 9495c635efSGarrett D'Amore 9595c635efSGarrett D'Amore static const struct termact termacts[MAN_MAX] = { 9695c635efSGarrett D'Amore { pre_sp, NULL, MAN_NOTEXT }, /* br */ 9795c635efSGarrett D'Amore { NULL, NULL, 0 }, /* TH */ 9895c635efSGarrett D'Amore { pre_SH, post_SH, 0 }, /* SH */ 9995c635efSGarrett D'Amore { pre_SS, post_SS, 0 }, /* SS */ 10095c635efSGarrett D'Amore { pre_TP, post_TP, 0 }, /* TP */ 10195c635efSGarrett D'Amore { pre_PP, NULL, 0 }, /* LP */ 10295c635efSGarrett D'Amore { pre_PP, NULL, 0 }, /* PP */ 10395c635efSGarrett D'Amore { pre_PP, NULL, 0 }, /* P */ 10495c635efSGarrett D'Amore { pre_IP, post_IP, 0 }, /* IP */ 10595c635efSGarrett D'Amore { pre_HP, post_HP, 0 }, /* HP */ 10695c635efSGarrett D'Amore { NULL, NULL, 0 }, /* SM */ 10795c635efSGarrett D'Amore { pre_B, NULL, 0 }, /* SB */ 10895c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* BI */ 10995c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* IB */ 11095c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* BR */ 11195c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* RB */ 11295c635efSGarrett D'Amore { NULL, NULL, 0 }, /* R */ 11395c635efSGarrett D'Amore { pre_B, NULL, 0 }, /* B */ 11495c635efSGarrett D'Amore { pre_I, NULL, 0 }, /* I */ 11595c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* IR */ 11695c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* RI */ 11795c635efSGarrett D'Amore { pre_sp, NULL, MAN_NOTEXT }, /* sp */ 11895c635efSGarrett D'Amore { pre_literal, NULL, 0 }, /* nf */ 11995c635efSGarrett D'Amore { pre_literal, NULL, 0 }, /* fi */ 12095c635efSGarrett D'Amore { NULL, NULL, 0 }, /* RE */ 12195c635efSGarrett D'Amore { pre_RS, post_RS, 0 }, /* RS */ 12295c635efSGarrett D'Amore { pre_ign, NULL, 0 }, /* DT */ 123*260e9a87SYuri Pankov { pre_ign, NULL, MAN_NOTEXT }, /* UC */ 124698f87a4SGarrett D'Amore { pre_PD, NULL, MAN_NOTEXT }, /* PD */ 12595c635efSGarrett D'Amore { pre_ign, NULL, 0 }, /* AT */ 12695c635efSGarrett D'Amore { pre_in, NULL, MAN_NOTEXT }, /* in */ 12795c635efSGarrett D'Amore { pre_ft, NULL, MAN_NOTEXT }, /* ft */ 12895c635efSGarrett D'Amore { pre_OP, NULL, 0 }, /* OP */ 129698f87a4SGarrett D'Amore { pre_literal, NULL, 0 }, /* EX */ 130698f87a4SGarrett D'Amore { pre_literal, NULL, 0 }, /* EE */ 131698f87a4SGarrett D'Amore { pre_UR, post_UR, 0 }, /* UR */ 132698f87a4SGarrett D'Amore { NULL, NULL, 0 }, /* UE */ 133*260e9a87SYuri Pankov { pre_ll, NULL, MAN_NOTEXT }, /* ll */ 13495c635efSGarrett D'Amore }; 13595c635efSGarrett D'Amore 13695c635efSGarrett D'Amore 13795c635efSGarrett D'Amore void 13895c635efSGarrett D'Amore terminal_man(void *arg, const struct man *man) 13995c635efSGarrett D'Amore { 14095c635efSGarrett D'Amore struct termp *p; 141698f87a4SGarrett D'Amore const struct man_meta *meta; 142*260e9a87SYuri Pankov struct man_node *n; 14395c635efSGarrett D'Amore struct mtermp mt; 14495c635efSGarrett D'Amore 14595c635efSGarrett D'Amore p = (struct termp *)arg; 14695c635efSGarrett D'Amore 14795c635efSGarrett D'Amore p->overstep = 0; 148*260e9a87SYuri Pankov p->rmargin = p->maxrmargin = p->defrmargin; 14995c635efSGarrett D'Amore p->tabwidth = term_len(p, 5); 15095c635efSGarrett D'Amore 151*260e9a87SYuri Pankov n = man_node(man)->child; 152698f87a4SGarrett D'Amore meta = man_meta(man); 15395c635efSGarrett D'Amore 15495c635efSGarrett D'Amore memset(&mt, 0, sizeof(struct mtermp)); 15595c635efSGarrett D'Amore 15695c635efSGarrett D'Amore mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); 15795c635efSGarrett D'Amore mt.offset = term_len(p, p->defindent); 158698f87a4SGarrett D'Amore mt.pardist = 1; 15995c635efSGarrett D'Amore 160*260e9a87SYuri Pankov if (p->synopsisonly) { 161*260e9a87SYuri Pankov while (n != NULL) { 162*260e9a87SYuri Pankov if (n->tok == MAN_SH && 163*260e9a87SYuri Pankov n->child->child->type == MAN_TEXT && 164*260e9a87SYuri Pankov !strcmp(n->child->child->string, "SYNOPSIS")) { 165*260e9a87SYuri Pankov if (n->child->next->child != NULL) 166*260e9a87SYuri Pankov print_man_nodelist(p, &mt, 167*260e9a87SYuri Pankov n->child->next->child, meta); 168*260e9a87SYuri Pankov term_newln(p); 169*260e9a87SYuri Pankov break; 170*260e9a87SYuri Pankov } 171*260e9a87SYuri Pankov n = n->next; 172*260e9a87SYuri Pankov } 173*260e9a87SYuri Pankov } else { 174*260e9a87SYuri Pankov if (p->defindent == 0) 175*260e9a87SYuri Pankov p->defindent = 7; 176*260e9a87SYuri Pankov term_begin(p, print_man_head, print_man_foot, meta); 177*260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 178*260e9a87SYuri Pankov if (n != NULL) 179*260e9a87SYuri Pankov print_man_nodelist(p, &mt, n, meta); 18095c635efSGarrett D'Amore term_end(p); 18195c635efSGarrett D'Amore } 18295c635efSGarrett D'Amore } 18395c635efSGarrett D'Amore 18495c635efSGarrett D'Amore /* 18595c635efSGarrett D'Amore * Printing leading vertical space before a block. 18695c635efSGarrett D'Amore * This is used for the paragraph macros. 18795c635efSGarrett D'Amore * The rules are pretty simple, since there's very little nesting going 18895c635efSGarrett D'Amore * on here. Basically, if we're the first within another block (SS/SH), 18995c635efSGarrett D'Amore * then don't emit vertical space. If we are (RS), then do. If not the 19095c635efSGarrett D'Amore * first, print it. 19195c635efSGarrett D'Amore */ 19295c635efSGarrett D'Amore static void 193698f87a4SGarrett D'Amore print_bvspace(struct termp *p, const struct man_node *n, int pardist) 19495c635efSGarrett D'Amore { 195698f87a4SGarrett D'Amore int i; 19695c635efSGarrett D'Amore 19795c635efSGarrett D'Amore term_newln(p); 19895c635efSGarrett D'Amore 19995c635efSGarrett D'Amore if (n->body && n->body->child) 20095c635efSGarrett D'Amore if (MAN_TBL == n->body->child->type) 20195c635efSGarrett D'Amore return; 20295c635efSGarrett D'Amore 20395c635efSGarrett D'Amore if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok) 20495c635efSGarrett D'Amore if (NULL == n->prev) 20595c635efSGarrett D'Amore return; 20695c635efSGarrett D'Amore 207698f87a4SGarrett D'Amore for (i = 0; i < pardist; i++) 20895c635efSGarrett D'Amore term_vspace(p); 20995c635efSGarrett D'Amore } 21095c635efSGarrett D'Amore 211*260e9a87SYuri Pankov 21295c635efSGarrett D'Amore static int 21395c635efSGarrett D'Amore pre_ign(DECL_ARGS) 21495c635efSGarrett D'Amore { 21595c635efSGarrett D'Amore 21695c635efSGarrett D'Amore return(0); 21795c635efSGarrett D'Amore } 21895c635efSGarrett D'Amore 219*260e9a87SYuri Pankov static int 220*260e9a87SYuri Pankov pre_ll(DECL_ARGS) 221*260e9a87SYuri Pankov { 22295c635efSGarrett D'Amore 223*260e9a87SYuri Pankov term_setwidth(p, n->nchild ? n->child->string : NULL); 224*260e9a87SYuri Pankov return(0); 225*260e9a87SYuri Pankov } 226*260e9a87SYuri Pankov 22795c635efSGarrett D'Amore static int 22895c635efSGarrett D'Amore pre_I(DECL_ARGS) 22995c635efSGarrett D'Amore { 23095c635efSGarrett D'Amore 23195c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 23295c635efSGarrett D'Amore return(1); 23395c635efSGarrett D'Amore } 23495c635efSGarrett D'Amore 23595c635efSGarrett D'Amore static int 23695c635efSGarrett D'Amore pre_literal(DECL_ARGS) 23795c635efSGarrett D'Amore { 23895c635efSGarrett D'Amore 23995c635efSGarrett D'Amore term_newln(p); 24095c635efSGarrett D'Amore 241698f87a4SGarrett D'Amore if (MAN_nf == n->tok || MAN_EX == n->tok) 24295c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 24395c635efSGarrett D'Amore else 24495c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 24595c635efSGarrett D'Amore 24695c635efSGarrett D'Amore /* 24795c635efSGarrett D'Amore * Unlike .IP and .TP, .HP does not have a HEAD. 24895c635efSGarrett D'Amore * So in case a second call to term_flushln() is needed, 24995c635efSGarrett D'Amore * indentation has to be set up explicitly. 25095c635efSGarrett D'Amore */ 25195c635efSGarrett D'Amore if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) { 25295c635efSGarrett D'Amore p->offset = p->rmargin; 25395c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 254698f87a4SGarrett D'Amore p->trailspace = 0; 255*260e9a87SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 25695c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 25795c635efSGarrett D'Amore } 25895c635efSGarrett D'Amore 25995c635efSGarrett D'Amore return(0); 26095c635efSGarrett D'Amore } 26195c635efSGarrett D'Amore 26295c635efSGarrett D'Amore static int 263698f87a4SGarrett D'Amore pre_PD(DECL_ARGS) 264698f87a4SGarrett D'Amore { 265*260e9a87SYuri Pankov struct roffsu su; 266698f87a4SGarrett D'Amore 267698f87a4SGarrett D'Amore n = n->child; 268*260e9a87SYuri Pankov if (n == NULL) { 269698f87a4SGarrett D'Amore mt->pardist = 1; 270698f87a4SGarrett D'Amore return(0); 271698f87a4SGarrett D'Amore } 272698f87a4SGarrett D'Amore assert(MAN_TEXT == n->type); 273*260e9a87SYuri Pankov if (a2roffsu(n->string, &su, SCALE_VS)) 274*260e9a87SYuri Pankov mt->pardist = term_vspan(p, &su); 275698f87a4SGarrett D'Amore return(0); 276698f87a4SGarrett D'Amore } 277698f87a4SGarrett D'Amore 278698f87a4SGarrett D'Amore static int 27995c635efSGarrett D'Amore pre_alternate(DECL_ARGS) 28095c635efSGarrett D'Amore { 28195c635efSGarrett D'Amore enum termfont font[2]; 282*260e9a87SYuri Pankov struct man_node *nn; 28395c635efSGarrett D'Amore int savelit, i; 28495c635efSGarrett D'Amore 28595c635efSGarrett D'Amore switch (n->tok) { 286*260e9a87SYuri Pankov case MAN_RB: 28795c635efSGarrett D'Amore font[0] = TERMFONT_NONE; 28895c635efSGarrett D'Amore font[1] = TERMFONT_BOLD; 28995c635efSGarrett D'Amore break; 290*260e9a87SYuri Pankov case MAN_RI: 29195c635efSGarrett D'Amore font[0] = TERMFONT_NONE; 29295c635efSGarrett D'Amore font[1] = TERMFONT_UNDER; 29395c635efSGarrett D'Amore break; 294*260e9a87SYuri Pankov case MAN_BR: 29595c635efSGarrett D'Amore font[0] = TERMFONT_BOLD; 29695c635efSGarrett D'Amore font[1] = TERMFONT_NONE; 29795c635efSGarrett D'Amore break; 298*260e9a87SYuri Pankov case MAN_BI: 29995c635efSGarrett D'Amore font[0] = TERMFONT_BOLD; 30095c635efSGarrett D'Amore font[1] = TERMFONT_UNDER; 30195c635efSGarrett D'Amore break; 302*260e9a87SYuri Pankov case MAN_IR: 30395c635efSGarrett D'Amore font[0] = TERMFONT_UNDER; 30495c635efSGarrett D'Amore font[1] = TERMFONT_NONE; 30595c635efSGarrett D'Amore break; 306*260e9a87SYuri Pankov case MAN_IB: 30795c635efSGarrett D'Amore font[0] = TERMFONT_UNDER; 30895c635efSGarrett D'Amore font[1] = TERMFONT_BOLD; 30995c635efSGarrett D'Amore break; 31095c635efSGarrett D'Amore default: 31195c635efSGarrett D'Amore abort(); 31295c635efSGarrett D'Amore } 31395c635efSGarrett D'Amore 31495c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 31595c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 31695c635efSGarrett D'Amore 31795c635efSGarrett D'Amore for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) { 31895c635efSGarrett D'Amore term_fontrepl(p, font[i]); 31995c635efSGarrett D'Amore if (savelit && NULL == nn->next) 32095c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 321698f87a4SGarrett D'Amore print_man_node(p, mt, nn, meta); 32295c635efSGarrett D'Amore if (nn->next) 32395c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 32495c635efSGarrett D'Amore } 32595c635efSGarrett D'Amore 32695c635efSGarrett D'Amore return(0); 32795c635efSGarrett D'Amore } 32895c635efSGarrett D'Amore 32995c635efSGarrett D'Amore static int 33095c635efSGarrett D'Amore pre_B(DECL_ARGS) 33195c635efSGarrett D'Amore { 33295c635efSGarrett D'Amore 33395c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 33495c635efSGarrett D'Amore return(1); 33595c635efSGarrett D'Amore } 33695c635efSGarrett D'Amore 33795c635efSGarrett D'Amore static int 33895c635efSGarrett D'Amore pre_OP(DECL_ARGS) 33995c635efSGarrett D'Amore { 34095c635efSGarrett D'Amore 34195c635efSGarrett D'Amore term_word(p, "["); 34295c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 34395c635efSGarrett D'Amore 34495c635efSGarrett D'Amore if (NULL != (n = n->child)) { 34595c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 34695c635efSGarrett D'Amore term_word(p, n->string); 34795c635efSGarrett D'Amore } 34895c635efSGarrett D'Amore if (NULL != n && NULL != n->next) { 34995c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 35095c635efSGarrett D'Amore term_word(p, n->next->string); 35195c635efSGarrett D'Amore } 35295c635efSGarrett D'Amore 35395c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 35495c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 35595c635efSGarrett D'Amore term_word(p, "]"); 35695c635efSGarrett D'Amore return(0); 35795c635efSGarrett D'Amore } 35895c635efSGarrett D'Amore 35995c635efSGarrett D'Amore static int 36095c635efSGarrett D'Amore pre_ft(DECL_ARGS) 36195c635efSGarrett D'Amore { 36295c635efSGarrett D'Amore const char *cp; 36395c635efSGarrett D'Amore 36495c635efSGarrett D'Amore if (NULL == n->child) { 36595c635efSGarrett D'Amore term_fontlast(p); 36695c635efSGarrett D'Amore return(0); 36795c635efSGarrett D'Amore } 36895c635efSGarrett D'Amore 36995c635efSGarrett D'Amore cp = n->child->string; 37095c635efSGarrett D'Amore switch (*cp) { 371*260e9a87SYuri Pankov case '4': 37295c635efSGarrett D'Amore /* FALLTHROUGH */ 373*260e9a87SYuri Pankov case '3': 37495c635efSGarrett D'Amore /* FALLTHROUGH */ 375*260e9a87SYuri Pankov case 'B': 37695c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 37795c635efSGarrett D'Amore break; 378*260e9a87SYuri Pankov case '2': 37995c635efSGarrett D'Amore /* FALLTHROUGH */ 380*260e9a87SYuri Pankov case 'I': 38195c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 38295c635efSGarrett D'Amore break; 383*260e9a87SYuri Pankov case 'P': 38495c635efSGarrett D'Amore term_fontlast(p); 38595c635efSGarrett D'Amore break; 386*260e9a87SYuri Pankov case '1': 38795c635efSGarrett D'Amore /* FALLTHROUGH */ 388*260e9a87SYuri Pankov case 'C': 38995c635efSGarrett D'Amore /* FALLTHROUGH */ 390*260e9a87SYuri Pankov case 'R': 39195c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 39295c635efSGarrett D'Amore break; 39395c635efSGarrett D'Amore default: 39495c635efSGarrett D'Amore break; 39595c635efSGarrett D'Amore } 39695c635efSGarrett D'Amore return(0); 39795c635efSGarrett D'Amore } 39895c635efSGarrett D'Amore 39995c635efSGarrett D'Amore static int 40095c635efSGarrett D'Amore pre_in(DECL_ARGS) 40195c635efSGarrett D'Amore { 402*260e9a87SYuri Pankov struct roffsu su; 40395c635efSGarrett D'Amore const char *cp; 404*260e9a87SYuri Pankov size_t v; 405*260e9a87SYuri Pankov int less; 40695c635efSGarrett D'Amore 40795c635efSGarrett D'Amore term_newln(p); 40895c635efSGarrett D'Amore 40995c635efSGarrett D'Amore if (NULL == n->child) { 41095c635efSGarrett D'Amore p->offset = mt->offset; 41195c635efSGarrett D'Amore return(0); 41295c635efSGarrett D'Amore } 41395c635efSGarrett D'Amore 41495c635efSGarrett D'Amore cp = n->child->string; 41595c635efSGarrett D'Amore less = 0; 41695c635efSGarrett D'Amore 41795c635efSGarrett D'Amore if ('-' == *cp) 41895c635efSGarrett D'Amore less = -1; 41995c635efSGarrett D'Amore else if ('+' == *cp) 42095c635efSGarrett D'Amore less = 1; 42195c635efSGarrett D'Amore else 42295c635efSGarrett D'Amore cp--; 42395c635efSGarrett D'Amore 424*260e9a87SYuri Pankov if ( ! a2roffsu(++cp, &su, SCALE_EN)) 42595c635efSGarrett D'Amore return(0); 42695c635efSGarrett D'Amore 427*260e9a87SYuri Pankov v = term_hspan(p, &su); 42895c635efSGarrett D'Amore 42995c635efSGarrett D'Amore if (less < 0) 43095c635efSGarrett D'Amore p->offset -= p->offset > v ? v : p->offset; 43195c635efSGarrett D'Amore else if (less > 0) 43295c635efSGarrett D'Amore p->offset += v; 43395c635efSGarrett D'Amore else 43495c635efSGarrett D'Amore p->offset = v; 435*260e9a87SYuri Pankov if (p->offset > SHRT_MAX) 436*260e9a87SYuri Pankov p->offset = term_len(p, p->defindent); 43795c635efSGarrett D'Amore 43895c635efSGarrett D'Amore return(0); 43995c635efSGarrett D'Amore } 44095c635efSGarrett D'Amore 44195c635efSGarrett D'Amore static int 44295c635efSGarrett D'Amore pre_sp(DECL_ARGS) 44395c635efSGarrett D'Amore { 444*260e9a87SYuri Pankov struct roffsu su; 445*260e9a87SYuri Pankov int i, len; 44695c635efSGarrett D'Amore 44795c635efSGarrett D'Amore if ((NULL == n->prev && n->parent)) { 448698f87a4SGarrett D'Amore switch (n->parent->tok) { 449*260e9a87SYuri Pankov case MAN_SH: 450698f87a4SGarrett D'Amore /* FALLTHROUGH */ 451*260e9a87SYuri Pankov case MAN_SS: 452698f87a4SGarrett D'Amore /* FALLTHROUGH */ 453*260e9a87SYuri Pankov case MAN_PP: 454698f87a4SGarrett D'Amore /* FALLTHROUGH */ 455*260e9a87SYuri Pankov case MAN_LP: 456698f87a4SGarrett D'Amore /* FALLTHROUGH */ 457*260e9a87SYuri Pankov case MAN_P: 458698f87a4SGarrett D'Amore /* FALLTHROUGH */ 45995c635efSGarrett D'Amore return(0); 460698f87a4SGarrett D'Amore default: 461698f87a4SGarrett D'Amore break; 462698f87a4SGarrett D'Amore } 46395c635efSGarrett D'Amore } 46495c635efSGarrett D'Amore 465*260e9a87SYuri Pankov if (n->tok == MAN_br) 46695c635efSGarrett D'Amore len = 0; 467*260e9a87SYuri Pankov else if (n->child == NULL) 468698f87a4SGarrett D'Amore len = 1; 469*260e9a87SYuri Pankov else { 470*260e9a87SYuri Pankov if ( ! a2roffsu(n->child->string, &su, SCALE_VS)) 471*260e9a87SYuri Pankov su.scale = 1.0; 472*260e9a87SYuri Pankov len = term_vspan(p, &su); 47395c635efSGarrett D'Amore } 47495c635efSGarrett D'Amore 475*260e9a87SYuri Pankov if (len == 0) 47695c635efSGarrett D'Amore term_newln(p); 477*260e9a87SYuri Pankov else if (len < 0) 478*260e9a87SYuri Pankov p->skipvsp -= len; 479698f87a4SGarrett D'Amore else 48095c635efSGarrett D'Amore for (i = 0; i < len; i++) 48195c635efSGarrett D'Amore term_vspace(p); 48295c635efSGarrett D'Amore 48395c635efSGarrett D'Amore return(0); 48495c635efSGarrett D'Amore } 48595c635efSGarrett D'Amore 48695c635efSGarrett D'Amore static int 48795c635efSGarrett D'Amore pre_HP(DECL_ARGS) 48895c635efSGarrett D'Amore { 489*260e9a87SYuri Pankov struct roffsu su; 49095c635efSGarrett D'Amore const struct man_node *nn; 491*260e9a87SYuri Pankov int len; 49295c635efSGarrett D'Amore 49395c635efSGarrett D'Amore switch (n->type) { 494*260e9a87SYuri Pankov case MAN_BLOCK: 495698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 49695c635efSGarrett D'Amore return(1); 497*260e9a87SYuri Pankov case MAN_BODY: 49895c635efSGarrett D'Amore break; 49995c635efSGarrett D'Amore default: 50095c635efSGarrett D'Amore return(0); 50195c635efSGarrett D'Amore } 50295c635efSGarrett D'Amore 503698f87a4SGarrett D'Amore if ( ! (MANT_LITERAL & mt->fl)) { 504*260e9a87SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND; 505698f87a4SGarrett D'Amore p->trailspace = 2; 506698f87a4SGarrett D'Amore } 507698f87a4SGarrett D'Amore 50895c635efSGarrett D'Amore /* Calculate offset. */ 50995c635efSGarrett D'Amore 510*260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 511*260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 512*260e9a87SYuri Pankov len = term_hspan(p, &su); 513*260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 514*260e9a87SYuri Pankov len = -mt->offset; 515*260e9a87SYuri Pankov else if (len > SHRT_MAX) 516*260e9a87SYuri Pankov len = term_len(p, p->defindent); 517*260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 518*260e9a87SYuri Pankov } else 519*260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 52095c635efSGarrett D'Amore 52195c635efSGarrett D'Amore p->offset = mt->offset; 52295c635efSGarrett D'Amore p->rmargin = mt->offset + len; 52395c635efSGarrett D'Amore return(1); 52495c635efSGarrett D'Amore } 52595c635efSGarrett D'Amore 52695c635efSGarrett D'Amore static void 52795c635efSGarrett D'Amore post_HP(DECL_ARGS) 52895c635efSGarrett D'Amore { 52995c635efSGarrett D'Amore 53095c635efSGarrett D'Amore switch (n->type) { 531*260e9a87SYuri Pankov case MAN_BODY: 532698f87a4SGarrett D'Amore term_newln(p); 533*260e9a87SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 534698f87a4SGarrett D'Amore p->trailspace = 0; 53595c635efSGarrett D'Amore p->offset = mt->offset; 53695c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 53795c635efSGarrett D'Amore break; 53895c635efSGarrett D'Amore default: 53995c635efSGarrett D'Amore break; 54095c635efSGarrett D'Amore } 54195c635efSGarrett D'Amore } 54295c635efSGarrett D'Amore 54395c635efSGarrett D'Amore static int 54495c635efSGarrett D'Amore pre_PP(DECL_ARGS) 54595c635efSGarrett D'Amore { 54695c635efSGarrett D'Amore 54795c635efSGarrett D'Amore switch (n->type) { 548*260e9a87SYuri Pankov case MAN_BLOCK: 54995c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 550698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 55195c635efSGarrett D'Amore break; 55295c635efSGarrett D'Amore default: 55395c635efSGarrett D'Amore p->offset = mt->offset; 55495c635efSGarrett D'Amore break; 55595c635efSGarrett D'Amore } 55695c635efSGarrett D'Amore 55795c635efSGarrett D'Amore return(MAN_HEAD != n->type); 55895c635efSGarrett D'Amore } 55995c635efSGarrett D'Amore 56095c635efSGarrett D'Amore static int 56195c635efSGarrett D'Amore pre_IP(DECL_ARGS) 56295c635efSGarrett D'Amore { 563*260e9a87SYuri Pankov struct roffsu su; 56495c635efSGarrett D'Amore const struct man_node *nn; 565*260e9a87SYuri Pankov int len, savelit; 56695c635efSGarrett D'Amore 56795c635efSGarrett D'Amore switch (n->type) { 568*260e9a87SYuri Pankov case MAN_BODY: 56995c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 57095c635efSGarrett D'Amore break; 571*260e9a87SYuri Pankov case MAN_HEAD: 57295c635efSGarrett D'Amore p->flags |= TERMP_NOBREAK; 573698f87a4SGarrett D'Amore p->trailspace = 1; 57495c635efSGarrett D'Amore break; 575*260e9a87SYuri Pankov case MAN_BLOCK: 576698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 57795c635efSGarrett D'Amore /* FALLTHROUGH */ 57895c635efSGarrett D'Amore default: 57995c635efSGarrett D'Amore return(1); 58095c635efSGarrett D'Amore } 58195c635efSGarrett D'Amore 58295c635efSGarrett D'Amore /* Calculate the offset from the optional second argument. */ 583*260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 584*260e9a87SYuri Pankov (nn = nn->next) != NULL && 585*260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 586*260e9a87SYuri Pankov len = term_hspan(p, &su); 587*260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 588*260e9a87SYuri Pankov len = -mt->offset; 589*260e9a87SYuri Pankov else if (len > SHRT_MAX) 590*260e9a87SYuri Pankov len = term_len(p, p->defindent); 591*260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 592*260e9a87SYuri Pankov } else 593*260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 59495c635efSGarrett D'Amore 59595c635efSGarrett D'Amore switch (n->type) { 596*260e9a87SYuri Pankov case MAN_HEAD: 59795c635efSGarrett D'Amore p->offset = mt->offset; 59895c635efSGarrett D'Amore p->rmargin = mt->offset + len; 59995c635efSGarrett D'Amore 60095c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 60195c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 60295c635efSGarrett D'Amore 60395c635efSGarrett D'Amore if (n->child) 604698f87a4SGarrett D'Amore print_man_node(p, mt, n->child, meta); 60595c635efSGarrett D'Amore 60695c635efSGarrett D'Amore if (savelit) 60795c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 60895c635efSGarrett D'Amore 60995c635efSGarrett D'Amore return(0); 610*260e9a87SYuri Pankov case MAN_BODY: 61195c635efSGarrett D'Amore p->offset = mt->offset + len; 61295c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 61395c635efSGarrett D'Amore break; 61495c635efSGarrett D'Amore default: 61595c635efSGarrett D'Amore break; 61695c635efSGarrett D'Amore } 61795c635efSGarrett D'Amore 61895c635efSGarrett D'Amore return(1); 61995c635efSGarrett D'Amore } 62095c635efSGarrett D'Amore 62195c635efSGarrett D'Amore static void 62295c635efSGarrett D'Amore post_IP(DECL_ARGS) 62395c635efSGarrett D'Amore { 62495c635efSGarrett D'Amore 62595c635efSGarrett D'Amore switch (n->type) { 626*260e9a87SYuri Pankov case MAN_HEAD: 62795c635efSGarrett D'Amore term_flushln(p); 62895c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 629698f87a4SGarrett D'Amore p->trailspace = 0; 63095c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 63195c635efSGarrett D'Amore break; 632*260e9a87SYuri Pankov case MAN_BODY: 63395c635efSGarrett D'Amore term_newln(p); 634698f87a4SGarrett D'Amore p->offset = mt->offset; 63595c635efSGarrett D'Amore break; 63695c635efSGarrett D'Amore default: 63795c635efSGarrett D'Amore break; 63895c635efSGarrett D'Amore } 63995c635efSGarrett D'Amore } 64095c635efSGarrett D'Amore 64195c635efSGarrett D'Amore static int 64295c635efSGarrett D'Amore pre_TP(DECL_ARGS) 64395c635efSGarrett D'Amore { 644*260e9a87SYuri Pankov struct roffsu su; 645*260e9a87SYuri Pankov struct man_node *nn; 646*260e9a87SYuri Pankov int len, savelit; 64795c635efSGarrett D'Amore 64895c635efSGarrett D'Amore switch (n->type) { 649*260e9a87SYuri Pankov case MAN_HEAD: 65095c635efSGarrett D'Amore p->flags |= TERMP_NOBREAK; 651698f87a4SGarrett D'Amore p->trailspace = 1; 65295c635efSGarrett D'Amore break; 653*260e9a87SYuri Pankov case MAN_BODY: 65495c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 65595c635efSGarrett D'Amore break; 656*260e9a87SYuri Pankov case MAN_BLOCK: 657698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 65895c635efSGarrett D'Amore /* FALLTHROUGH */ 65995c635efSGarrett D'Amore default: 66095c635efSGarrett D'Amore return(1); 66195c635efSGarrett D'Amore } 66295c635efSGarrett D'Amore 66395c635efSGarrett D'Amore /* Calculate offset. */ 66495c635efSGarrett D'Amore 665*260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 666*260e9a87SYuri Pankov nn->string != NULL && ! (MAN_LINE & nn->flags) && 667*260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 668*260e9a87SYuri Pankov len = term_hspan(p, &su); 669*260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 670*260e9a87SYuri Pankov len = -mt->offset; 671*260e9a87SYuri Pankov else if (len > SHRT_MAX) 672*260e9a87SYuri Pankov len = term_len(p, p->defindent); 673*260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 674*260e9a87SYuri Pankov } else 675*260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 67695c635efSGarrett D'Amore 67795c635efSGarrett D'Amore switch (n->type) { 678*260e9a87SYuri Pankov case MAN_HEAD: 67995c635efSGarrett D'Amore p->offset = mt->offset; 68095c635efSGarrett D'Amore p->rmargin = mt->offset + len; 68195c635efSGarrett D'Amore 68295c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 68395c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 68495c635efSGarrett D'Amore 68595c635efSGarrett D'Amore /* Don't print same-line elements. */ 686*260e9a87SYuri Pankov nn = n->child; 687*260e9a87SYuri Pankov while (NULL != nn && 0 == (MAN_LINE & nn->flags)) 688*260e9a87SYuri Pankov nn = nn->next; 689*260e9a87SYuri Pankov 690*260e9a87SYuri Pankov while (NULL != nn) { 691698f87a4SGarrett D'Amore print_man_node(p, mt, nn, meta); 692*260e9a87SYuri Pankov nn = nn->next; 693*260e9a87SYuri Pankov } 69495c635efSGarrett D'Amore 69595c635efSGarrett D'Amore if (savelit) 69695c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 69795c635efSGarrett D'Amore return(0); 698*260e9a87SYuri Pankov case MAN_BODY: 69995c635efSGarrett D'Amore p->offset = mt->offset + len; 70095c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 701698f87a4SGarrett D'Amore p->trailspace = 0; 702698f87a4SGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 70395c635efSGarrett D'Amore break; 70495c635efSGarrett D'Amore default: 70595c635efSGarrett D'Amore break; 70695c635efSGarrett D'Amore } 70795c635efSGarrett D'Amore 70895c635efSGarrett D'Amore return(1); 70995c635efSGarrett D'Amore } 71095c635efSGarrett D'Amore 71195c635efSGarrett D'Amore static void 71295c635efSGarrett D'Amore post_TP(DECL_ARGS) 71395c635efSGarrett D'Amore { 71495c635efSGarrett D'Amore 71595c635efSGarrett D'Amore switch (n->type) { 716*260e9a87SYuri Pankov case MAN_HEAD: 71795c635efSGarrett D'Amore term_flushln(p); 71895c635efSGarrett D'Amore break; 719*260e9a87SYuri Pankov case MAN_BODY: 72095c635efSGarrett D'Amore term_newln(p); 721698f87a4SGarrett D'Amore p->offset = mt->offset; 72295c635efSGarrett D'Amore break; 72395c635efSGarrett D'Amore default: 72495c635efSGarrett D'Amore break; 72595c635efSGarrett D'Amore } 72695c635efSGarrett D'Amore } 72795c635efSGarrett D'Amore 72895c635efSGarrett D'Amore static int 72995c635efSGarrett D'Amore pre_SS(DECL_ARGS) 73095c635efSGarrett D'Amore { 731698f87a4SGarrett D'Amore int i; 73295c635efSGarrett D'Amore 73395c635efSGarrett D'Amore switch (n->type) { 734*260e9a87SYuri Pankov case MAN_BLOCK: 73595c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 73695c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 73795c635efSGarrett D'Amore mt->offset = term_len(p, p->defindent); 738*260e9a87SYuri Pankov 739*260e9a87SYuri Pankov /* 740*260e9a87SYuri Pankov * No vertical space before the first subsection 741*260e9a87SYuri Pankov * and after an empty subsection. 742*260e9a87SYuri Pankov */ 743*260e9a87SYuri Pankov 744*260e9a87SYuri Pankov do { 745*260e9a87SYuri Pankov n = n->prev; 746*260e9a87SYuri Pankov } while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT); 747*260e9a87SYuri Pankov if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL)) 74895c635efSGarrett D'Amore break; 749*260e9a87SYuri Pankov 750698f87a4SGarrett D'Amore for (i = 0; i < mt->pardist; i++) 75195c635efSGarrett D'Amore term_vspace(p); 75295c635efSGarrett D'Amore break; 753*260e9a87SYuri Pankov case MAN_HEAD: 75495c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 755698f87a4SGarrett D'Amore p->offset = term_len(p, 3); 75695c635efSGarrett D'Amore break; 757*260e9a87SYuri Pankov case MAN_BODY: 75895c635efSGarrett D'Amore p->offset = mt->offset; 75995c635efSGarrett D'Amore break; 76095c635efSGarrett D'Amore default: 76195c635efSGarrett D'Amore break; 76295c635efSGarrett D'Amore } 76395c635efSGarrett D'Amore 76495c635efSGarrett D'Amore return(1); 76595c635efSGarrett D'Amore } 76695c635efSGarrett D'Amore 76795c635efSGarrett D'Amore static void 76895c635efSGarrett D'Amore post_SS(DECL_ARGS) 76995c635efSGarrett D'Amore { 77095c635efSGarrett D'Amore 77195c635efSGarrett D'Amore switch (n->type) { 772*260e9a87SYuri Pankov case MAN_HEAD: 77395c635efSGarrett D'Amore term_newln(p); 77495c635efSGarrett D'Amore break; 775*260e9a87SYuri Pankov case MAN_BODY: 77695c635efSGarrett D'Amore term_newln(p); 77795c635efSGarrett D'Amore break; 77895c635efSGarrett D'Amore default: 77995c635efSGarrett D'Amore break; 78095c635efSGarrett D'Amore } 78195c635efSGarrett D'Amore } 78295c635efSGarrett D'Amore 78395c635efSGarrett D'Amore static int 78495c635efSGarrett D'Amore pre_SH(DECL_ARGS) 78595c635efSGarrett D'Amore { 786698f87a4SGarrett D'Amore int i; 78795c635efSGarrett D'Amore 78895c635efSGarrett D'Amore switch (n->type) { 789*260e9a87SYuri Pankov case MAN_BLOCK: 79095c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 79195c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 79295c635efSGarrett D'Amore mt->offset = term_len(p, p->defindent); 793*260e9a87SYuri Pankov 794*260e9a87SYuri Pankov /* 795*260e9a87SYuri Pankov * No vertical space before the first section 796*260e9a87SYuri Pankov * and after an empty section. 797*260e9a87SYuri Pankov */ 798*260e9a87SYuri Pankov 799*260e9a87SYuri Pankov do { 800*260e9a87SYuri Pankov n = n->prev; 801*260e9a87SYuri Pankov } while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT); 802*260e9a87SYuri Pankov if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL)) 80395c635efSGarrett D'Amore break; 804*260e9a87SYuri Pankov 805698f87a4SGarrett D'Amore for (i = 0; i < mt->pardist; i++) 80695c635efSGarrett D'Amore term_vspace(p); 80795c635efSGarrett D'Amore break; 808*260e9a87SYuri Pankov case MAN_HEAD: 80995c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 81095c635efSGarrett D'Amore p->offset = 0; 81195c635efSGarrett D'Amore break; 812*260e9a87SYuri Pankov case MAN_BODY: 81395c635efSGarrett D'Amore p->offset = mt->offset; 81495c635efSGarrett D'Amore break; 81595c635efSGarrett D'Amore default: 81695c635efSGarrett D'Amore break; 81795c635efSGarrett D'Amore } 81895c635efSGarrett D'Amore 81995c635efSGarrett D'Amore return(1); 82095c635efSGarrett D'Amore } 82195c635efSGarrett D'Amore 82295c635efSGarrett D'Amore static void 82395c635efSGarrett D'Amore post_SH(DECL_ARGS) 82495c635efSGarrett D'Amore { 82595c635efSGarrett D'Amore 82695c635efSGarrett D'Amore switch (n->type) { 827*260e9a87SYuri Pankov case MAN_HEAD: 82895c635efSGarrett D'Amore term_newln(p); 82995c635efSGarrett D'Amore break; 830*260e9a87SYuri Pankov case MAN_BODY: 83195c635efSGarrett D'Amore term_newln(p); 83295c635efSGarrett D'Amore break; 83395c635efSGarrett D'Amore default: 83495c635efSGarrett D'Amore break; 83595c635efSGarrett D'Amore } 83695c635efSGarrett D'Amore } 83795c635efSGarrett D'Amore 83895c635efSGarrett D'Amore static int 83995c635efSGarrett D'Amore pre_RS(DECL_ARGS) 84095c635efSGarrett D'Amore { 841*260e9a87SYuri Pankov struct roffsu su; 84295c635efSGarrett D'Amore 84395c635efSGarrett D'Amore switch (n->type) { 844*260e9a87SYuri Pankov case MAN_BLOCK: 84595c635efSGarrett D'Amore term_newln(p); 84695c635efSGarrett D'Amore return(1); 847*260e9a87SYuri Pankov case MAN_HEAD: 84895c635efSGarrett D'Amore return(0); 84995c635efSGarrett D'Amore default: 85095c635efSGarrett D'Amore break; 85195c635efSGarrett D'Amore } 85295c635efSGarrett D'Amore 853*260e9a87SYuri Pankov n = n->parent->head; 854*260e9a87SYuri Pankov n->aux = SHRT_MAX + 1; 855*260e9a87SYuri Pankov if (n->child != NULL && a2roffsu(n->child->string, &su, SCALE_EN)) 856*260e9a87SYuri Pankov n->aux = term_hspan(p, &su); 857*260e9a87SYuri Pankov if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) 858*260e9a87SYuri Pankov n->aux = -mt->offset; 859*260e9a87SYuri Pankov else if (n->aux > SHRT_MAX) 860*260e9a87SYuri Pankov n->aux = term_len(p, p->defindent); 86195c635efSGarrett D'Amore 862*260e9a87SYuri Pankov mt->offset += n->aux; 863*260e9a87SYuri Pankov p->offset = mt->offset; 86495c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 86595c635efSGarrett D'Amore 86695c635efSGarrett D'Amore if (++mt->lmarginsz < MAXMARGINS) 86795c635efSGarrett D'Amore mt->lmargincur = mt->lmarginsz; 86895c635efSGarrett D'Amore 86995c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1]; 87095c635efSGarrett D'Amore return(1); 87195c635efSGarrett D'Amore } 87295c635efSGarrett D'Amore 87395c635efSGarrett D'Amore static void 87495c635efSGarrett D'Amore post_RS(DECL_ARGS) 87595c635efSGarrett D'Amore { 87695c635efSGarrett D'Amore 87795c635efSGarrett D'Amore switch (n->type) { 878*260e9a87SYuri Pankov case MAN_BLOCK: 87995c635efSGarrett D'Amore return; 880*260e9a87SYuri Pankov case MAN_HEAD: 88195c635efSGarrett D'Amore return; 88295c635efSGarrett D'Amore default: 88395c635efSGarrett D'Amore term_newln(p); 88495c635efSGarrett D'Amore break; 88595c635efSGarrett D'Amore } 88695c635efSGarrett D'Amore 887*260e9a87SYuri Pankov mt->offset -= n->parent->head->aux; 88895c635efSGarrett D'Amore p->offset = mt->offset; 88995c635efSGarrett D'Amore 89095c635efSGarrett D'Amore if (--mt->lmarginsz < MAXMARGINS) 89195c635efSGarrett D'Amore mt->lmargincur = mt->lmarginsz; 89295c635efSGarrett D'Amore } 89395c635efSGarrett D'Amore 894698f87a4SGarrett D'Amore static int 895698f87a4SGarrett D'Amore pre_UR(DECL_ARGS) 896698f87a4SGarrett D'Amore { 897698f87a4SGarrett D'Amore 898698f87a4SGarrett D'Amore return (MAN_HEAD != n->type); 899698f87a4SGarrett D'Amore } 900698f87a4SGarrett D'Amore 901698f87a4SGarrett D'Amore static void 902698f87a4SGarrett D'Amore post_UR(DECL_ARGS) 903698f87a4SGarrett D'Amore { 904698f87a4SGarrett D'Amore 905698f87a4SGarrett D'Amore if (MAN_BLOCK != n->type) 906698f87a4SGarrett D'Amore return; 907698f87a4SGarrett D'Amore 908698f87a4SGarrett D'Amore term_word(p, "<"); 909698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 910698f87a4SGarrett D'Amore 911698f87a4SGarrett D'Amore if (NULL != n->child->child) 912698f87a4SGarrett D'Amore print_man_node(p, mt, n->child->child, meta); 913698f87a4SGarrett D'Amore 914698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 915698f87a4SGarrett D'Amore term_word(p, ">"); 916698f87a4SGarrett D'Amore } 917698f87a4SGarrett D'Amore 91895c635efSGarrett D'Amore static void 91995c635efSGarrett D'Amore print_man_node(DECL_ARGS) 92095c635efSGarrett D'Amore { 92195c635efSGarrett D'Amore size_t rm, rmax; 92295c635efSGarrett D'Amore int c; 92395c635efSGarrett D'Amore 92495c635efSGarrett D'Amore switch (n->type) { 925*260e9a87SYuri Pankov case MAN_TEXT: 92695c635efSGarrett D'Amore /* 92795c635efSGarrett D'Amore * If we have a blank line, output a vertical space. 92895c635efSGarrett D'Amore * If we have a space as the first character, break 92995c635efSGarrett D'Amore * before printing the line's data. 93095c635efSGarrett D'Amore */ 93195c635efSGarrett D'Amore if ('\0' == *n->string) { 93295c635efSGarrett D'Amore term_vspace(p); 93395c635efSGarrett D'Amore return; 93495c635efSGarrett D'Amore } else if (' ' == *n->string && MAN_LINE & n->flags) 93595c635efSGarrett D'Amore term_newln(p); 93695c635efSGarrett D'Amore 93795c635efSGarrett D'Amore term_word(p, n->string); 938698f87a4SGarrett D'Amore goto out; 93995c635efSGarrett D'Amore 940*260e9a87SYuri Pankov case MAN_EQN: 941*260e9a87SYuri Pankov if ( ! (n->flags & MAN_LINE)) 942*260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 94395c635efSGarrett D'Amore term_eqn(p, n->eqn); 944*260e9a87SYuri Pankov if (n->next != NULL && ! (n->next->flags & MAN_LINE)) 945*260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 94695c635efSGarrett D'Amore return; 947*260e9a87SYuri Pankov case MAN_TBL: 948*260e9a87SYuri Pankov if (p->tbl.cols == NULL) 949*260e9a87SYuri Pankov term_vspace(p); 95095c635efSGarrett D'Amore term_tbl(p, n->span); 95195c635efSGarrett D'Amore return; 95295c635efSGarrett D'Amore default: 95395c635efSGarrett D'Amore break; 95495c635efSGarrett D'Amore } 95595c635efSGarrett D'Amore 95695c635efSGarrett D'Amore if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) 95795c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 95895c635efSGarrett D'Amore 95995c635efSGarrett D'Amore c = 1; 96095c635efSGarrett D'Amore if (termacts[n->tok].pre) 961698f87a4SGarrett D'Amore c = (*termacts[n->tok].pre)(p, mt, n, meta); 96295c635efSGarrett D'Amore 96395c635efSGarrett D'Amore if (c && n->child) 964698f87a4SGarrett D'Amore print_man_nodelist(p, mt, n->child, meta); 96595c635efSGarrett D'Amore 96695c635efSGarrett D'Amore if (termacts[n->tok].post) 967698f87a4SGarrett D'Amore (*termacts[n->tok].post)(p, mt, n, meta); 96895c635efSGarrett D'Amore if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) 96995c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 97095c635efSGarrett D'Amore 971698f87a4SGarrett D'Amore out: 972698f87a4SGarrett D'Amore /* 973698f87a4SGarrett D'Amore * If we're in a literal context, make sure that words 974698f87a4SGarrett D'Amore * together on the same line stay together. This is a 975698f87a4SGarrett D'Amore * POST-printing call, so we check the NEXT word. Since 976698f87a4SGarrett D'Amore * -man doesn't have nested macros, we don't need to be 977698f87a4SGarrett D'Amore * more specific than this. 978698f87a4SGarrett D'Amore */ 979*260e9a87SYuri Pankov if (mt->fl & MANT_LITERAL && 980*260e9a87SYuri Pankov ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && 981*260e9a87SYuri Pankov (n->next == NULL || n->next->flags & MAN_LINE)) { 982698f87a4SGarrett D'Amore rm = p->rmargin; 983698f87a4SGarrett D'Amore rmax = p->maxrmargin; 984698f87a4SGarrett D'Amore p->rmargin = p->maxrmargin = TERM_MAXMARGIN; 985698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 986*260e9a87SYuri Pankov if (n->string != NULL && *n->string != '\0') 987698f87a4SGarrett D'Amore term_flushln(p); 988698f87a4SGarrett D'Amore else 989698f87a4SGarrett D'Amore term_newln(p); 990698f87a4SGarrett D'Amore if (rm < rmax && n->parent->tok == MAN_HP) { 991698f87a4SGarrett D'Amore p->offset = rm; 992698f87a4SGarrett D'Amore p->rmargin = rmax; 993698f87a4SGarrett D'Amore } else 994698f87a4SGarrett D'Amore p->rmargin = rm; 995698f87a4SGarrett D'Amore p->maxrmargin = rmax; 996698f87a4SGarrett D'Amore } 99795c635efSGarrett D'Amore if (MAN_EOS & n->flags) 99895c635efSGarrett D'Amore p->flags |= TERMP_SENTENCE; 99995c635efSGarrett D'Amore } 100095c635efSGarrett D'Amore 100195c635efSGarrett D'Amore 100295c635efSGarrett D'Amore static void 100395c635efSGarrett D'Amore print_man_nodelist(DECL_ARGS) 100495c635efSGarrett D'Amore { 100595c635efSGarrett D'Amore 1006*260e9a87SYuri Pankov while (n != NULL) { 1007698f87a4SGarrett D'Amore print_man_node(p, mt, n, meta); 1008*260e9a87SYuri Pankov n = n->next; 100995c635efSGarrett D'Amore } 1010*260e9a87SYuri Pankov } 101195c635efSGarrett D'Amore 101295c635efSGarrett D'Amore static void 101395c635efSGarrett D'Amore print_man_foot(struct termp *p, const void *arg) 101495c635efSGarrett D'Amore { 101595c635efSGarrett D'Amore const struct man_meta *meta; 1016*260e9a87SYuri Pankov char *title; 1017*260e9a87SYuri Pankov size_t datelen, titlen; 101895c635efSGarrett D'Amore 101995c635efSGarrett D'Amore meta = (const struct man_meta *)arg; 102095c635efSGarrett D'Amore assert(meta->title); 102195c635efSGarrett D'Amore assert(meta->msec); 102295c635efSGarrett D'Amore assert(meta->date); 102395c635efSGarrett D'Amore 102495c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 102595c635efSGarrett D'Amore 1026*260e9a87SYuri Pankov if (meta->hasbody) 102795c635efSGarrett D'Amore term_vspace(p); 102895c635efSGarrett D'Amore 102995c635efSGarrett D'Amore /* 103095c635efSGarrett D'Amore * Temporary, undocumented option to imitate mdoc(7) output. 103195c635efSGarrett D'Amore * In the bottom right corner, use the source instead of 103295c635efSGarrett D'Amore * the title. 103395c635efSGarrett D'Amore */ 103495c635efSGarrett D'Amore 103595c635efSGarrett D'Amore if ( ! p->mdocstyle) { 1036*260e9a87SYuri Pankov if (meta->hasbody) { 103795c635efSGarrett D'Amore term_vspace(p); 103895c635efSGarrett D'Amore term_vspace(p); 1039*260e9a87SYuri Pankov } 1040*260e9a87SYuri Pankov mandoc_asprintf(&title, "%s(%s)", 1041*260e9a87SYuri Pankov meta->title, meta->msec); 104295c635efSGarrett D'Amore } else if (meta->source) { 1043*260e9a87SYuri Pankov title = mandoc_strdup(meta->source); 104495c635efSGarrett D'Amore } else { 1045*260e9a87SYuri Pankov title = mandoc_strdup(""); 104695c635efSGarrett D'Amore } 104795c635efSGarrett D'Amore datelen = term_strlen(p, meta->date); 104895c635efSGarrett D'Amore 104995c635efSGarrett D'Amore /* Bottom left corner: manual source. */ 105095c635efSGarrett D'Amore 105195c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 1052698f87a4SGarrett D'Amore p->trailspace = 1; 105395c635efSGarrett D'Amore p->offset = 0; 1054*260e9a87SYuri Pankov p->rmargin = p->maxrmargin > datelen ? 1055*260e9a87SYuri Pankov (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; 105695c635efSGarrett D'Amore 105795c635efSGarrett D'Amore if (meta->source) 105895c635efSGarrett D'Amore term_word(p, meta->source); 105995c635efSGarrett D'Amore term_flushln(p); 106095c635efSGarrett D'Amore 106195c635efSGarrett D'Amore /* At the bottom in the middle: manual date. */ 106295c635efSGarrett D'Amore 106395c635efSGarrett D'Amore p->offset = p->rmargin; 1064*260e9a87SYuri Pankov titlen = term_strlen(p, title); 1065*260e9a87SYuri Pankov p->rmargin = p->maxrmargin > titlen ? p->maxrmargin - titlen : 0; 1066*260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 106795c635efSGarrett D'Amore 106895c635efSGarrett D'Amore term_word(p, meta->date); 106995c635efSGarrett D'Amore term_flushln(p); 107095c635efSGarrett D'Amore 107195c635efSGarrett D'Amore /* Bottom right corner: manual title and section. */ 107295c635efSGarrett D'Amore 107395c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 107495c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 1075698f87a4SGarrett D'Amore p->trailspace = 0; 107695c635efSGarrett D'Amore p->offset = p->rmargin; 107795c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 107895c635efSGarrett D'Amore 107995c635efSGarrett D'Amore term_word(p, title); 108095c635efSGarrett D'Amore term_flushln(p); 1081*260e9a87SYuri Pankov free(title); 108295c635efSGarrett D'Amore } 108395c635efSGarrett D'Amore 108495c635efSGarrett D'Amore static void 108595c635efSGarrett D'Amore print_man_head(struct termp *p, const void *arg) 108695c635efSGarrett D'Amore { 1087698f87a4SGarrett D'Amore const struct man_meta *meta; 1088*260e9a87SYuri Pankov const char *volume; 1089*260e9a87SYuri Pankov char *title; 1090*260e9a87SYuri Pankov size_t vollen, titlen; 109195c635efSGarrett D'Amore 1092698f87a4SGarrett D'Amore meta = (const struct man_meta *)arg; 1093698f87a4SGarrett D'Amore assert(meta->title); 1094698f87a4SGarrett D'Amore assert(meta->msec); 109595c635efSGarrett D'Amore 1096*260e9a87SYuri Pankov volume = NULL == meta->vol ? "" : meta->vol; 1097*260e9a87SYuri Pankov vollen = term_strlen(p, volume); 109895c635efSGarrett D'Amore 109995c635efSGarrett D'Amore /* Top left corner: manual title and section. */ 110095c635efSGarrett D'Amore 1101*260e9a87SYuri Pankov mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); 110295c635efSGarrett D'Amore titlen = term_strlen(p, title); 110395c635efSGarrett D'Amore 110495c635efSGarrett D'Amore p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; 1105698f87a4SGarrett D'Amore p->trailspace = 1; 110695c635efSGarrett D'Amore p->offset = 0; 1107*260e9a87SYuri Pankov p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? 1108*260e9a87SYuri Pankov (p->maxrmargin - vollen + term_len(p, 1)) / 2 : 1109*260e9a87SYuri Pankov vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; 111095c635efSGarrett D'Amore 111195c635efSGarrett D'Amore term_word(p, title); 111295c635efSGarrett D'Amore term_flushln(p); 111395c635efSGarrett D'Amore 111495c635efSGarrett D'Amore /* At the top in the middle: manual volume. */ 111595c635efSGarrett D'Amore 111695c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 111795c635efSGarrett D'Amore p->offset = p->rmargin; 1118*260e9a87SYuri Pankov p->rmargin = p->offset + vollen + titlen < p->maxrmargin ? 111995c635efSGarrett D'Amore p->maxrmargin - titlen : p->maxrmargin; 112095c635efSGarrett D'Amore 1121*260e9a87SYuri Pankov term_word(p, volume); 112295c635efSGarrett D'Amore term_flushln(p); 112395c635efSGarrett D'Amore 112495c635efSGarrett D'Amore /* Top right corner: title and section, again. */ 112595c635efSGarrett D'Amore 112695c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 1127698f87a4SGarrett D'Amore p->trailspace = 0; 112895c635efSGarrett D'Amore if (p->rmargin + titlen <= p->maxrmargin) { 112995c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 113095c635efSGarrett D'Amore p->offset = p->rmargin; 113195c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 113295c635efSGarrett D'Amore term_word(p, title); 113395c635efSGarrett D'Amore term_flushln(p); 113495c635efSGarrett D'Amore } 113595c635efSGarrett D'Amore 113695c635efSGarrett D'Amore p->flags &= ~TERMP_NOSPACE; 113795c635efSGarrett D'Amore p->offset = 0; 113895c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 113995c635efSGarrett D'Amore 114095c635efSGarrett D'Amore /* 114195c635efSGarrett D'Amore * Groff prints three blank lines before the content. 114295c635efSGarrett D'Amore * Do the same, except in the temporary, undocumented 114395c635efSGarrett D'Amore * mode imitating mdoc(7) output. 114495c635efSGarrett D'Amore */ 114595c635efSGarrett D'Amore 114695c635efSGarrett D'Amore term_vspace(p); 114795c635efSGarrett D'Amore if ( ! p->mdocstyle) { 114895c635efSGarrett D'Amore term_vspace(p); 114995c635efSGarrett D'Amore term_vspace(p); 115095c635efSGarrett D'Amore } 1151*260e9a87SYuri Pankov free(title); 115295c635efSGarrett D'Amore } 1153