1*371584c2SYuri Pankov /* $Id: man_term.c,v 1.187 2016/01/08 17:48:09 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4260e9a87SYuri 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 * 10*371584c2SYuri Pankov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*371584c2SYuri Pankov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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> 24260e9a87SYuri 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 29260e9a87SYuri Pankov #include "mandoc_aux.h" 30*371584c2SYuri Pankov #include "mandoc.h" 31*371584c2SYuri Pankov #include "roff.h" 3295c635efSGarrett D'Amore #include "man.h" 33*371584c2SYuri Pankov #include "out.h" 3495c635efSGarrett D'Amore #include "term.h" 3595c635efSGarrett D'Amore #include "main.h" 3695c635efSGarrett D'Amore 3795c635efSGarrett D'Amore #define MAXMARGINS 64 /* maximum number of indented scopes */ 3895c635efSGarrett D'Amore 3995c635efSGarrett D'Amore struct mtermp { 4095c635efSGarrett D'Amore int fl; 4195c635efSGarrett D'Amore #define MANT_LITERAL (1 << 0) 42260e9a87SYuri Pankov int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */ 4395c635efSGarrett D'Amore int lmargincur; /* index of current margin */ 4495c635efSGarrett D'Amore int lmarginsz; /* actual number of nested margins */ 4595c635efSGarrett D'Amore size_t offset; /* default offset to visible page */ 46698f87a4SGarrett D'Amore int pardist; /* vert. space before par., unit: [v] */ 4795c635efSGarrett D'Amore }; 4895c635efSGarrett D'Amore 4995c635efSGarrett D'Amore #define DECL_ARGS struct termp *p, \ 5095c635efSGarrett D'Amore struct mtermp *mt, \ 51*371584c2SYuri Pankov struct roff_node *n, \ 52*371584c2SYuri Pankov const struct roff_meta *meta 5395c635efSGarrett D'Amore 5495c635efSGarrett D'Amore struct termact { 5595c635efSGarrett D'Amore int (*pre)(DECL_ARGS); 5695c635efSGarrett D'Amore void (*post)(DECL_ARGS); 5795c635efSGarrett D'Amore int flags; 5895c635efSGarrett D'Amore #define MAN_NOTEXT (1 << 0) /* Never has text children. */ 5995c635efSGarrett D'Amore }; 6095c635efSGarrett D'Amore 6195c635efSGarrett D'Amore static void print_man_nodelist(DECL_ARGS); 6295c635efSGarrett D'Amore static void print_man_node(DECL_ARGS); 63*371584c2SYuri Pankov static void print_man_head(struct termp *, 64*371584c2SYuri Pankov const struct roff_meta *); 65*371584c2SYuri Pankov static void print_man_foot(struct termp *, 66*371584c2SYuri Pankov const struct roff_meta *); 6795c635efSGarrett D'Amore static void print_bvspace(struct termp *, 68*371584c2SYuri Pankov const struct roff_node *, int); 6995c635efSGarrett D'Amore 7095c635efSGarrett D'Amore static int pre_B(DECL_ARGS); 7195c635efSGarrett D'Amore static int pre_HP(DECL_ARGS); 7295c635efSGarrett D'Amore static int pre_I(DECL_ARGS); 7395c635efSGarrett D'Amore static int pre_IP(DECL_ARGS); 7495c635efSGarrett D'Amore static int pre_OP(DECL_ARGS); 75698f87a4SGarrett D'Amore static int pre_PD(DECL_ARGS); 7695c635efSGarrett D'Amore static int pre_PP(DECL_ARGS); 7795c635efSGarrett D'Amore static int pre_RS(DECL_ARGS); 7895c635efSGarrett D'Amore static int pre_SH(DECL_ARGS); 7995c635efSGarrett D'Amore static int pre_SS(DECL_ARGS); 8095c635efSGarrett D'Amore static int pre_TP(DECL_ARGS); 81698f87a4SGarrett D'Amore static int pre_UR(DECL_ARGS); 8295c635efSGarrett D'Amore static int pre_alternate(DECL_ARGS); 8395c635efSGarrett D'Amore static int pre_ft(DECL_ARGS); 8495c635efSGarrett D'Amore static int pre_ign(DECL_ARGS); 8595c635efSGarrett D'Amore static int pre_in(DECL_ARGS); 8695c635efSGarrett D'Amore static int pre_literal(DECL_ARGS); 87260e9a87SYuri Pankov static int pre_ll(DECL_ARGS); 8895c635efSGarrett D'Amore static int pre_sp(DECL_ARGS); 8995c635efSGarrett D'Amore 9095c635efSGarrett D'Amore static void post_IP(DECL_ARGS); 9195c635efSGarrett D'Amore static void post_HP(DECL_ARGS); 9295c635efSGarrett D'Amore static void post_RS(DECL_ARGS); 9395c635efSGarrett D'Amore static void post_SH(DECL_ARGS); 9495c635efSGarrett D'Amore static void post_SS(DECL_ARGS); 9595c635efSGarrett D'Amore static void post_TP(DECL_ARGS); 96698f87a4SGarrett D'Amore static void post_UR(DECL_ARGS); 9795c635efSGarrett D'Amore 9895c635efSGarrett D'Amore static const struct termact termacts[MAN_MAX] = { 9995c635efSGarrett D'Amore { pre_sp, NULL, MAN_NOTEXT }, /* br */ 10095c635efSGarrett D'Amore { NULL, NULL, 0 }, /* TH */ 10195c635efSGarrett D'Amore { pre_SH, post_SH, 0 }, /* SH */ 10295c635efSGarrett D'Amore { pre_SS, post_SS, 0 }, /* SS */ 10395c635efSGarrett D'Amore { pre_TP, post_TP, 0 }, /* TP */ 10495c635efSGarrett D'Amore { pre_PP, NULL, 0 }, /* LP */ 10595c635efSGarrett D'Amore { pre_PP, NULL, 0 }, /* PP */ 10695c635efSGarrett D'Amore { pre_PP, NULL, 0 }, /* P */ 10795c635efSGarrett D'Amore { pre_IP, post_IP, 0 }, /* IP */ 10895c635efSGarrett D'Amore { pre_HP, post_HP, 0 }, /* HP */ 10995c635efSGarrett D'Amore { NULL, NULL, 0 }, /* SM */ 11095c635efSGarrett D'Amore { pre_B, NULL, 0 }, /* SB */ 11195c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* BI */ 11295c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* IB */ 11395c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* BR */ 11495c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* RB */ 11595c635efSGarrett D'Amore { NULL, NULL, 0 }, /* R */ 11695c635efSGarrett D'Amore { pre_B, NULL, 0 }, /* B */ 11795c635efSGarrett D'Amore { pre_I, NULL, 0 }, /* I */ 11895c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* IR */ 11995c635efSGarrett D'Amore { pre_alternate, NULL, 0 }, /* RI */ 12095c635efSGarrett D'Amore { pre_sp, NULL, MAN_NOTEXT }, /* sp */ 12195c635efSGarrett D'Amore { pre_literal, NULL, 0 }, /* nf */ 12295c635efSGarrett D'Amore { pre_literal, NULL, 0 }, /* fi */ 12395c635efSGarrett D'Amore { NULL, NULL, 0 }, /* RE */ 12495c635efSGarrett D'Amore { pre_RS, post_RS, 0 }, /* RS */ 12595c635efSGarrett D'Amore { pre_ign, NULL, 0 }, /* DT */ 126260e9a87SYuri Pankov { pre_ign, NULL, MAN_NOTEXT }, /* UC */ 127698f87a4SGarrett D'Amore { pre_PD, NULL, MAN_NOTEXT }, /* PD */ 12895c635efSGarrett D'Amore { pre_ign, NULL, 0 }, /* AT */ 12995c635efSGarrett D'Amore { pre_in, NULL, MAN_NOTEXT }, /* in */ 13095c635efSGarrett D'Amore { pre_ft, NULL, MAN_NOTEXT }, /* ft */ 13195c635efSGarrett D'Amore { pre_OP, NULL, 0 }, /* OP */ 132698f87a4SGarrett D'Amore { pre_literal, NULL, 0 }, /* EX */ 133698f87a4SGarrett D'Amore { pre_literal, NULL, 0 }, /* EE */ 134698f87a4SGarrett D'Amore { pre_UR, post_UR, 0 }, /* UR */ 135698f87a4SGarrett D'Amore { NULL, NULL, 0 }, /* UE */ 136260e9a87SYuri Pankov { pre_ll, NULL, MAN_NOTEXT }, /* ll */ 13795c635efSGarrett D'Amore }; 13895c635efSGarrett D'Amore 13995c635efSGarrett D'Amore 14095c635efSGarrett D'Amore void 141*371584c2SYuri Pankov terminal_man(void *arg, const struct roff_man *man) 14295c635efSGarrett D'Amore { 14395c635efSGarrett D'Amore struct termp *p; 144*371584c2SYuri Pankov struct roff_node *n; 14595c635efSGarrett D'Amore struct mtermp mt; 14695c635efSGarrett D'Amore 14795c635efSGarrett D'Amore p = (struct termp *)arg; 14895c635efSGarrett D'Amore p->overstep = 0; 149260e9a87SYuri Pankov p->rmargin = p->maxrmargin = p->defrmargin; 15095c635efSGarrett D'Amore p->tabwidth = term_len(p, 5); 15195c635efSGarrett D'Amore 15295c635efSGarrett D'Amore memset(&mt, 0, sizeof(struct mtermp)); 15395c635efSGarrett D'Amore mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); 15495c635efSGarrett D'Amore mt.offset = term_len(p, p->defindent); 155698f87a4SGarrett D'Amore mt.pardist = 1; 15695c635efSGarrett D'Amore 157*371584c2SYuri Pankov n = man->first->child; 158260e9a87SYuri Pankov if (p->synopsisonly) { 159260e9a87SYuri Pankov while (n != NULL) { 160260e9a87SYuri Pankov if (n->tok == MAN_SH && 161*371584c2SYuri Pankov n->child->child->type == ROFFT_TEXT && 162260e9a87SYuri Pankov !strcmp(n->child->child->string, "SYNOPSIS")) { 163260e9a87SYuri Pankov if (n->child->next->child != NULL) 164260e9a87SYuri Pankov print_man_nodelist(p, &mt, 165*371584c2SYuri Pankov n->child->next->child, 166*371584c2SYuri Pankov &man->meta); 167260e9a87SYuri Pankov term_newln(p); 168260e9a87SYuri Pankov break; 169260e9a87SYuri Pankov } 170260e9a87SYuri Pankov n = n->next; 171260e9a87SYuri Pankov } 172260e9a87SYuri Pankov } else { 173260e9a87SYuri Pankov if (p->defindent == 0) 174260e9a87SYuri Pankov p->defindent = 7; 175*371584c2SYuri Pankov term_begin(p, print_man_head, print_man_foot, &man->meta); 176260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 177260e9a87SYuri Pankov if (n != NULL) 178*371584c2SYuri Pankov print_man_nodelist(p, &mt, n, &man->meta); 17995c635efSGarrett D'Amore term_end(p); 18095c635efSGarrett D'Amore } 18195c635efSGarrett D'Amore } 18295c635efSGarrett D'Amore 18395c635efSGarrett D'Amore /* 18495c635efSGarrett D'Amore * Printing leading vertical space before a block. 18595c635efSGarrett D'Amore * This is used for the paragraph macros. 18695c635efSGarrett D'Amore * The rules are pretty simple, since there's very little nesting going 18795c635efSGarrett D'Amore * on here. Basically, if we're the first within another block (SS/SH), 18895c635efSGarrett D'Amore * then don't emit vertical space. If we are (RS), then do. If not the 18995c635efSGarrett D'Amore * first, print it. 19095c635efSGarrett D'Amore */ 19195c635efSGarrett D'Amore static void 192*371584c2SYuri Pankov print_bvspace(struct termp *p, const struct roff_node *n, int pardist) 19395c635efSGarrett D'Amore { 194698f87a4SGarrett D'Amore int i; 19595c635efSGarrett D'Amore 19695c635efSGarrett D'Amore term_newln(p); 19795c635efSGarrett D'Amore 19895c635efSGarrett D'Amore if (n->body && n->body->child) 199*371584c2SYuri Pankov if (n->body->child->type == ROFFT_TBL) 20095c635efSGarrett D'Amore return; 20195c635efSGarrett D'Amore 202*371584c2SYuri Pankov if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) 20395c635efSGarrett D'Amore if (NULL == n->prev) 20495c635efSGarrett D'Amore return; 20595c635efSGarrett D'Amore 206698f87a4SGarrett D'Amore for (i = 0; i < pardist; i++) 20795c635efSGarrett D'Amore term_vspace(p); 20895c635efSGarrett D'Amore } 20995c635efSGarrett D'Amore 210260e9a87SYuri Pankov 21195c635efSGarrett D'Amore static int 21295c635efSGarrett D'Amore pre_ign(DECL_ARGS) 21395c635efSGarrett D'Amore { 21495c635efSGarrett D'Amore 215*371584c2SYuri Pankov return 0; 21695c635efSGarrett D'Amore } 21795c635efSGarrett D'Amore 218260e9a87SYuri Pankov static int 219260e9a87SYuri Pankov pre_ll(DECL_ARGS) 220260e9a87SYuri Pankov { 22195c635efSGarrett D'Amore 222*371584c2SYuri Pankov term_setwidth(p, n->child != NULL ? n->child->string : NULL); 223*371584c2SYuri Pankov return 0; 224260e9a87SYuri Pankov } 225260e9a87SYuri Pankov 22695c635efSGarrett D'Amore static int 22795c635efSGarrett D'Amore pre_I(DECL_ARGS) 22895c635efSGarrett D'Amore { 22995c635efSGarrett D'Amore 23095c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 231*371584c2SYuri Pankov return 1; 23295c635efSGarrett D'Amore } 23395c635efSGarrett D'Amore 23495c635efSGarrett D'Amore static int 23595c635efSGarrett D'Amore pre_literal(DECL_ARGS) 23695c635efSGarrett D'Amore { 23795c635efSGarrett D'Amore 23895c635efSGarrett D'Amore term_newln(p); 23995c635efSGarrett D'Amore 240698f87a4SGarrett D'Amore if (MAN_nf == n->tok || MAN_EX == n->tok) 24195c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 24295c635efSGarrett D'Amore else 24395c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 24495c635efSGarrett D'Amore 24595c635efSGarrett D'Amore /* 24695c635efSGarrett D'Amore * Unlike .IP and .TP, .HP does not have a HEAD. 24795c635efSGarrett D'Amore * So in case a second call to term_flushln() is needed, 24895c635efSGarrett D'Amore * indentation has to be set up explicitly. 24995c635efSGarrett D'Amore */ 25095c635efSGarrett D'Amore if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) { 25195c635efSGarrett D'Amore p->offset = p->rmargin; 25295c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 253698f87a4SGarrett D'Amore p->trailspace = 0; 254260e9a87SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 25595c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 25695c635efSGarrett D'Amore } 25795c635efSGarrett D'Amore 258*371584c2SYuri Pankov return 0; 25995c635efSGarrett D'Amore } 26095c635efSGarrett D'Amore 26195c635efSGarrett D'Amore static int 262698f87a4SGarrett D'Amore pre_PD(DECL_ARGS) 263698f87a4SGarrett D'Amore { 264260e9a87SYuri Pankov struct roffsu su; 265698f87a4SGarrett D'Amore 266698f87a4SGarrett D'Amore n = n->child; 267260e9a87SYuri Pankov if (n == NULL) { 268698f87a4SGarrett D'Amore mt->pardist = 1; 269*371584c2SYuri Pankov return 0; 270698f87a4SGarrett D'Amore } 271*371584c2SYuri Pankov assert(n->type == ROFFT_TEXT); 272260e9a87SYuri Pankov if (a2roffsu(n->string, &su, SCALE_VS)) 273260e9a87SYuri Pankov mt->pardist = term_vspan(p, &su); 274*371584c2SYuri Pankov return 0; 275698f87a4SGarrett D'Amore } 276698f87a4SGarrett D'Amore 277698f87a4SGarrett D'Amore static int 27895c635efSGarrett D'Amore pre_alternate(DECL_ARGS) 27995c635efSGarrett D'Amore { 28095c635efSGarrett D'Amore enum termfont font[2]; 281*371584c2SYuri Pankov struct roff_node *nn; 28295c635efSGarrett D'Amore int savelit, i; 28395c635efSGarrett D'Amore 28495c635efSGarrett D'Amore switch (n->tok) { 285260e9a87SYuri Pankov case MAN_RB: 28695c635efSGarrett D'Amore font[0] = TERMFONT_NONE; 28795c635efSGarrett D'Amore font[1] = TERMFONT_BOLD; 28895c635efSGarrett D'Amore break; 289260e9a87SYuri Pankov case MAN_RI: 29095c635efSGarrett D'Amore font[0] = TERMFONT_NONE; 29195c635efSGarrett D'Amore font[1] = TERMFONT_UNDER; 29295c635efSGarrett D'Amore break; 293260e9a87SYuri Pankov case MAN_BR: 29495c635efSGarrett D'Amore font[0] = TERMFONT_BOLD; 29595c635efSGarrett D'Amore font[1] = TERMFONT_NONE; 29695c635efSGarrett D'Amore break; 297260e9a87SYuri Pankov case MAN_BI: 29895c635efSGarrett D'Amore font[0] = TERMFONT_BOLD; 29995c635efSGarrett D'Amore font[1] = TERMFONT_UNDER; 30095c635efSGarrett D'Amore break; 301260e9a87SYuri Pankov case MAN_IR: 30295c635efSGarrett D'Amore font[0] = TERMFONT_UNDER; 30395c635efSGarrett D'Amore font[1] = TERMFONT_NONE; 30495c635efSGarrett D'Amore break; 305260e9a87SYuri Pankov case MAN_IB: 30695c635efSGarrett D'Amore font[0] = TERMFONT_UNDER; 30795c635efSGarrett D'Amore font[1] = TERMFONT_BOLD; 30895c635efSGarrett D'Amore break; 30995c635efSGarrett D'Amore default: 31095c635efSGarrett D'Amore abort(); 31195c635efSGarrett D'Amore } 31295c635efSGarrett D'Amore 31395c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 31495c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 31595c635efSGarrett D'Amore 31695c635efSGarrett D'Amore for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) { 31795c635efSGarrett D'Amore term_fontrepl(p, font[i]); 31895c635efSGarrett D'Amore if (savelit && NULL == nn->next) 31995c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 320*371584c2SYuri Pankov assert(nn->type == ROFFT_TEXT); 321*371584c2SYuri Pankov term_word(p, nn->string); 322*371584c2SYuri Pankov if (nn->flags & MAN_EOS) 323*371584c2SYuri Pankov p->flags |= TERMP_SENTENCE; 32495c635efSGarrett D'Amore if (nn->next) 32595c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 32695c635efSGarrett D'Amore } 32795c635efSGarrett D'Amore 328*371584c2SYuri Pankov return 0; 32995c635efSGarrett D'Amore } 33095c635efSGarrett D'Amore 33195c635efSGarrett D'Amore static int 33295c635efSGarrett D'Amore pre_B(DECL_ARGS) 33395c635efSGarrett D'Amore { 33495c635efSGarrett D'Amore 33595c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 336*371584c2SYuri Pankov return 1; 33795c635efSGarrett D'Amore } 33895c635efSGarrett D'Amore 33995c635efSGarrett D'Amore static int 34095c635efSGarrett D'Amore pre_OP(DECL_ARGS) 34195c635efSGarrett D'Amore { 34295c635efSGarrett D'Amore 34395c635efSGarrett D'Amore term_word(p, "["); 34495c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 34595c635efSGarrett D'Amore 34695c635efSGarrett D'Amore if (NULL != (n = n->child)) { 34795c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 34895c635efSGarrett D'Amore term_word(p, n->string); 34995c635efSGarrett D'Amore } 35095c635efSGarrett D'Amore if (NULL != n && NULL != n->next) { 35195c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 35295c635efSGarrett D'Amore term_word(p, n->next->string); 35395c635efSGarrett D'Amore } 35495c635efSGarrett D'Amore 35595c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 35695c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 35795c635efSGarrett D'Amore term_word(p, "]"); 358*371584c2SYuri Pankov return 0; 35995c635efSGarrett D'Amore } 36095c635efSGarrett D'Amore 36195c635efSGarrett D'Amore static int 36295c635efSGarrett D'Amore pre_ft(DECL_ARGS) 36395c635efSGarrett D'Amore { 36495c635efSGarrett D'Amore const char *cp; 36595c635efSGarrett D'Amore 36695c635efSGarrett D'Amore if (NULL == n->child) { 36795c635efSGarrett D'Amore term_fontlast(p); 368*371584c2SYuri Pankov return 0; 36995c635efSGarrett D'Amore } 37095c635efSGarrett D'Amore 37195c635efSGarrett D'Amore cp = n->child->string; 37295c635efSGarrett D'Amore switch (*cp) { 373260e9a87SYuri Pankov case '4': 374260e9a87SYuri Pankov case '3': 375260e9a87SYuri Pankov case 'B': 37695c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 37795c635efSGarrett D'Amore break; 378260e9a87SYuri Pankov case '2': 379260e9a87SYuri Pankov case 'I': 38095c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 38195c635efSGarrett D'Amore break; 382260e9a87SYuri Pankov case 'P': 38395c635efSGarrett D'Amore term_fontlast(p); 38495c635efSGarrett D'Amore break; 385260e9a87SYuri Pankov case '1': 386260e9a87SYuri Pankov case 'C': 387260e9a87SYuri Pankov case 'R': 38895c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 38995c635efSGarrett D'Amore break; 39095c635efSGarrett D'Amore default: 39195c635efSGarrett D'Amore break; 39295c635efSGarrett D'Amore } 393*371584c2SYuri Pankov return 0; 39495c635efSGarrett D'Amore } 39595c635efSGarrett D'Amore 39695c635efSGarrett D'Amore static int 39795c635efSGarrett D'Amore pre_in(DECL_ARGS) 39895c635efSGarrett D'Amore { 399260e9a87SYuri Pankov struct roffsu su; 40095c635efSGarrett D'Amore const char *cp; 401260e9a87SYuri Pankov size_t v; 402260e9a87SYuri Pankov int less; 40395c635efSGarrett D'Amore 40495c635efSGarrett D'Amore term_newln(p); 40595c635efSGarrett D'Amore 40695c635efSGarrett D'Amore if (NULL == n->child) { 40795c635efSGarrett D'Amore p->offset = mt->offset; 408*371584c2SYuri Pankov return 0; 40995c635efSGarrett D'Amore } 41095c635efSGarrett D'Amore 41195c635efSGarrett D'Amore cp = n->child->string; 41295c635efSGarrett D'Amore less = 0; 41395c635efSGarrett D'Amore 41495c635efSGarrett D'Amore if ('-' == *cp) 41595c635efSGarrett D'Amore less = -1; 41695c635efSGarrett D'Amore else if ('+' == *cp) 41795c635efSGarrett D'Amore less = 1; 41895c635efSGarrett D'Amore else 41995c635efSGarrett D'Amore cp--; 42095c635efSGarrett D'Amore 421260e9a87SYuri Pankov if ( ! a2roffsu(++cp, &su, SCALE_EN)) 422*371584c2SYuri Pankov return 0; 42395c635efSGarrett D'Amore 424*371584c2SYuri Pankov v = (term_hspan(p, &su) + 11) / 24; 42595c635efSGarrett D'Amore 42695c635efSGarrett D'Amore if (less < 0) 42795c635efSGarrett D'Amore p->offset -= p->offset > v ? v : p->offset; 42895c635efSGarrett D'Amore else if (less > 0) 42995c635efSGarrett D'Amore p->offset += v; 43095c635efSGarrett D'Amore else 43195c635efSGarrett D'Amore p->offset = v; 432260e9a87SYuri Pankov if (p->offset > SHRT_MAX) 433260e9a87SYuri Pankov p->offset = term_len(p, p->defindent); 43495c635efSGarrett D'Amore 435*371584c2SYuri Pankov return 0; 43695c635efSGarrett D'Amore } 43795c635efSGarrett D'Amore 43895c635efSGarrett D'Amore static int 43995c635efSGarrett D'Amore pre_sp(DECL_ARGS) 44095c635efSGarrett D'Amore { 441260e9a87SYuri Pankov struct roffsu su; 442260e9a87SYuri Pankov int i, len; 44395c635efSGarrett D'Amore 44495c635efSGarrett D'Amore if ((NULL == n->prev && n->parent)) { 445698f87a4SGarrett D'Amore switch (n->parent->tok) { 446260e9a87SYuri Pankov case MAN_SH: 447260e9a87SYuri Pankov case MAN_SS: 448260e9a87SYuri Pankov case MAN_PP: 449260e9a87SYuri Pankov case MAN_LP: 450260e9a87SYuri Pankov case MAN_P: 451*371584c2SYuri Pankov return 0; 452698f87a4SGarrett D'Amore default: 453698f87a4SGarrett D'Amore break; 454698f87a4SGarrett D'Amore } 45595c635efSGarrett D'Amore } 45695c635efSGarrett D'Amore 457260e9a87SYuri Pankov if (n->tok == MAN_br) 45895c635efSGarrett D'Amore len = 0; 459260e9a87SYuri Pankov else if (n->child == NULL) 460698f87a4SGarrett D'Amore len = 1; 461260e9a87SYuri Pankov else { 462260e9a87SYuri Pankov if ( ! a2roffsu(n->child->string, &su, SCALE_VS)) 463260e9a87SYuri Pankov su.scale = 1.0; 464260e9a87SYuri Pankov len = term_vspan(p, &su); 46595c635efSGarrett D'Amore } 46695c635efSGarrett D'Amore 467260e9a87SYuri Pankov if (len == 0) 46895c635efSGarrett D'Amore term_newln(p); 469260e9a87SYuri Pankov else if (len < 0) 470260e9a87SYuri Pankov p->skipvsp -= len; 471698f87a4SGarrett D'Amore else 47295c635efSGarrett D'Amore for (i = 0; i < len; i++) 47395c635efSGarrett D'Amore term_vspace(p); 47495c635efSGarrett D'Amore 475*371584c2SYuri Pankov /* 476*371584c2SYuri Pankov * Handle an explicit break request in the same way 477*371584c2SYuri Pankov * as an overflowing line. 478*371584c2SYuri Pankov */ 479*371584c2SYuri Pankov 480*371584c2SYuri Pankov if (p->flags & TERMP_BRIND) { 481*371584c2SYuri Pankov p->offset = p->rmargin; 482*371584c2SYuri Pankov p->rmargin = p->maxrmargin; 483*371584c2SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 484*371584c2SYuri Pankov } 485*371584c2SYuri Pankov 486*371584c2SYuri Pankov return 0; 48795c635efSGarrett D'Amore } 48895c635efSGarrett D'Amore 48995c635efSGarrett D'Amore static int 49095c635efSGarrett D'Amore pre_HP(DECL_ARGS) 49195c635efSGarrett D'Amore { 492260e9a87SYuri Pankov struct roffsu su; 493*371584c2SYuri Pankov const struct roff_node *nn; 494260e9a87SYuri Pankov int len; 49595c635efSGarrett D'Amore 49695c635efSGarrett D'Amore switch (n->type) { 497*371584c2SYuri Pankov case ROFFT_BLOCK: 498698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 499*371584c2SYuri Pankov return 1; 500*371584c2SYuri Pankov case ROFFT_BODY: 50195c635efSGarrett D'Amore break; 50295c635efSGarrett D'Amore default: 503*371584c2SYuri Pankov return 0; 50495c635efSGarrett D'Amore } 50595c635efSGarrett D'Amore 506698f87a4SGarrett D'Amore if ( ! (MANT_LITERAL & mt->fl)) { 507260e9a87SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND; 508698f87a4SGarrett D'Amore p->trailspace = 2; 509698f87a4SGarrett D'Amore } 510698f87a4SGarrett D'Amore 51195c635efSGarrett D'Amore /* Calculate offset. */ 51295c635efSGarrett D'Amore 513260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 514260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 515*371584c2SYuri Pankov len = term_hspan(p, &su) / 24; 516260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 517260e9a87SYuri Pankov len = -mt->offset; 518260e9a87SYuri Pankov else if (len > SHRT_MAX) 519260e9a87SYuri Pankov len = term_len(p, p->defindent); 520260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 521260e9a87SYuri Pankov } else 522260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 52395c635efSGarrett D'Amore 52495c635efSGarrett D'Amore p->offset = mt->offset; 52595c635efSGarrett D'Amore p->rmargin = mt->offset + len; 526*371584c2SYuri Pankov return 1; 52795c635efSGarrett D'Amore } 52895c635efSGarrett D'Amore 52995c635efSGarrett D'Amore static void 53095c635efSGarrett D'Amore post_HP(DECL_ARGS) 53195c635efSGarrett D'Amore { 53295c635efSGarrett D'Amore 53395c635efSGarrett D'Amore switch (n->type) { 534*371584c2SYuri Pankov case ROFFT_BODY: 535698f87a4SGarrett D'Amore term_newln(p); 536*371584c2SYuri Pankov 537*371584c2SYuri Pankov /* 538*371584c2SYuri Pankov * Compatibility with a groff bug. 539*371584c2SYuri Pankov * The .HP macro uses the undocumented .tag request 540*371584c2SYuri Pankov * which causes a line break and cancels no-space 541*371584c2SYuri Pankov * mode even if there isn't any output. 542*371584c2SYuri Pankov */ 543*371584c2SYuri Pankov 544*371584c2SYuri Pankov if (n->child == NULL) 545*371584c2SYuri Pankov term_vspace(p); 546*371584c2SYuri Pankov 547260e9a87SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 548698f87a4SGarrett D'Amore p->trailspace = 0; 54995c635efSGarrett D'Amore p->offset = mt->offset; 55095c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 55195c635efSGarrett D'Amore break; 55295c635efSGarrett D'Amore default: 55395c635efSGarrett D'Amore break; 55495c635efSGarrett D'Amore } 55595c635efSGarrett D'Amore } 55695c635efSGarrett D'Amore 55795c635efSGarrett D'Amore static int 55895c635efSGarrett D'Amore pre_PP(DECL_ARGS) 55995c635efSGarrett D'Amore { 56095c635efSGarrett D'Amore 56195c635efSGarrett D'Amore switch (n->type) { 562*371584c2SYuri Pankov case ROFFT_BLOCK: 56395c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 564698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 56595c635efSGarrett D'Amore break; 56695c635efSGarrett D'Amore default: 56795c635efSGarrett D'Amore p->offset = mt->offset; 56895c635efSGarrett D'Amore break; 56995c635efSGarrett D'Amore } 57095c635efSGarrett D'Amore 571*371584c2SYuri Pankov return n->type != ROFFT_HEAD; 57295c635efSGarrett D'Amore } 57395c635efSGarrett D'Amore 57495c635efSGarrett D'Amore static int 57595c635efSGarrett D'Amore pre_IP(DECL_ARGS) 57695c635efSGarrett D'Amore { 577260e9a87SYuri Pankov struct roffsu su; 578*371584c2SYuri Pankov const struct roff_node *nn; 579260e9a87SYuri Pankov int len, savelit; 58095c635efSGarrett D'Amore 58195c635efSGarrett D'Amore switch (n->type) { 582*371584c2SYuri Pankov case ROFFT_BODY: 58395c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 58495c635efSGarrett D'Amore break; 585*371584c2SYuri Pankov case ROFFT_HEAD: 58695c635efSGarrett D'Amore p->flags |= TERMP_NOBREAK; 587698f87a4SGarrett D'Amore p->trailspace = 1; 58895c635efSGarrett D'Amore break; 589*371584c2SYuri Pankov case ROFFT_BLOCK: 590698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 59195c635efSGarrett D'Amore /* FALLTHROUGH */ 59295c635efSGarrett D'Amore default: 593*371584c2SYuri Pankov return 1; 59495c635efSGarrett D'Amore } 59595c635efSGarrett D'Amore 59695c635efSGarrett D'Amore /* Calculate the offset from the optional second argument. */ 597260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 598260e9a87SYuri Pankov (nn = nn->next) != NULL && 599260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 600*371584c2SYuri Pankov len = term_hspan(p, &su) / 24; 601260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 602260e9a87SYuri Pankov len = -mt->offset; 603260e9a87SYuri Pankov else if (len > SHRT_MAX) 604260e9a87SYuri Pankov len = term_len(p, p->defindent); 605260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 606260e9a87SYuri Pankov } else 607260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 60895c635efSGarrett D'Amore 60995c635efSGarrett D'Amore switch (n->type) { 610*371584c2SYuri Pankov case ROFFT_HEAD: 61195c635efSGarrett D'Amore p->offset = mt->offset; 61295c635efSGarrett D'Amore p->rmargin = mt->offset + len; 61395c635efSGarrett D'Amore 61495c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 61595c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 61695c635efSGarrett D'Amore 61795c635efSGarrett D'Amore if (n->child) 618698f87a4SGarrett D'Amore print_man_node(p, mt, n->child, meta); 61995c635efSGarrett D'Amore 62095c635efSGarrett D'Amore if (savelit) 62195c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 62295c635efSGarrett D'Amore 623*371584c2SYuri Pankov return 0; 624*371584c2SYuri Pankov case ROFFT_BODY: 62595c635efSGarrett D'Amore p->offset = mt->offset + len; 62695c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 62795c635efSGarrett D'Amore break; 62895c635efSGarrett D'Amore default: 62995c635efSGarrett D'Amore break; 63095c635efSGarrett D'Amore } 63195c635efSGarrett D'Amore 632*371584c2SYuri Pankov return 1; 63395c635efSGarrett D'Amore } 63495c635efSGarrett D'Amore 63595c635efSGarrett D'Amore static void 63695c635efSGarrett D'Amore post_IP(DECL_ARGS) 63795c635efSGarrett D'Amore { 63895c635efSGarrett D'Amore 63995c635efSGarrett D'Amore switch (n->type) { 640*371584c2SYuri Pankov case ROFFT_HEAD: 64195c635efSGarrett D'Amore term_flushln(p); 64295c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 643698f87a4SGarrett D'Amore p->trailspace = 0; 64495c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 64595c635efSGarrett D'Amore break; 646*371584c2SYuri Pankov case ROFFT_BODY: 64795c635efSGarrett D'Amore term_newln(p); 648698f87a4SGarrett D'Amore p->offset = mt->offset; 64995c635efSGarrett D'Amore break; 65095c635efSGarrett D'Amore default: 65195c635efSGarrett D'Amore break; 65295c635efSGarrett D'Amore } 65395c635efSGarrett D'Amore } 65495c635efSGarrett D'Amore 65595c635efSGarrett D'Amore static int 65695c635efSGarrett D'Amore pre_TP(DECL_ARGS) 65795c635efSGarrett D'Amore { 658260e9a87SYuri Pankov struct roffsu su; 659*371584c2SYuri Pankov struct roff_node *nn; 660260e9a87SYuri Pankov int len, savelit; 66195c635efSGarrett D'Amore 66295c635efSGarrett D'Amore switch (n->type) { 663*371584c2SYuri Pankov case ROFFT_HEAD: 664*371584c2SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRTRSP; 665698f87a4SGarrett D'Amore p->trailspace = 1; 66695c635efSGarrett D'Amore break; 667*371584c2SYuri Pankov case ROFFT_BODY: 66895c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 66995c635efSGarrett D'Amore break; 670*371584c2SYuri Pankov case ROFFT_BLOCK: 671698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 67295c635efSGarrett D'Amore /* FALLTHROUGH */ 67395c635efSGarrett D'Amore default: 674*371584c2SYuri Pankov return 1; 67595c635efSGarrett D'Amore } 67695c635efSGarrett D'Amore 67795c635efSGarrett D'Amore /* Calculate offset. */ 67895c635efSGarrett D'Amore 679260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 680260e9a87SYuri Pankov nn->string != NULL && ! (MAN_LINE & nn->flags) && 681260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 682*371584c2SYuri Pankov len = term_hspan(p, &su) / 24; 683260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 684260e9a87SYuri Pankov len = -mt->offset; 685260e9a87SYuri Pankov else if (len > SHRT_MAX) 686260e9a87SYuri Pankov len = term_len(p, p->defindent); 687260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 688260e9a87SYuri Pankov } else 689260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 69095c635efSGarrett D'Amore 69195c635efSGarrett D'Amore switch (n->type) { 692*371584c2SYuri Pankov case ROFFT_HEAD: 69395c635efSGarrett D'Amore p->offset = mt->offset; 69495c635efSGarrett D'Amore p->rmargin = mt->offset + len; 69595c635efSGarrett D'Amore 69695c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 69795c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 69895c635efSGarrett D'Amore 69995c635efSGarrett D'Amore /* Don't print same-line elements. */ 700260e9a87SYuri Pankov nn = n->child; 701260e9a87SYuri Pankov while (NULL != nn && 0 == (MAN_LINE & nn->flags)) 702260e9a87SYuri Pankov nn = nn->next; 703260e9a87SYuri Pankov 704260e9a87SYuri Pankov while (NULL != nn) { 705698f87a4SGarrett D'Amore print_man_node(p, mt, nn, meta); 706260e9a87SYuri Pankov nn = nn->next; 707260e9a87SYuri Pankov } 70895c635efSGarrett D'Amore 70995c635efSGarrett D'Amore if (savelit) 71095c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 711*371584c2SYuri Pankov return 0; 712*371584c2SYuri Pankov case ROFFT_BODY: 71395c635efSGarrett D'Amore p->offset = mt->offset + len; 71495c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 715698f87a4SGarrett D'Amore p->trailspace = 0; 716*371584c2SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP); 71795c635efSGarrett D'Amore break; 71895c635efSGarrett D'Amore default: 71995c635efSGarrett D'Amore break; 72095c635efSGarrett D'Amore } 72195c635efSGarrett D'Amore 722*371584c2SYuri Pankov return 1; 72395c635efSGarrett D'Amore } 72495c635efSGarrett D'Amore 72595c635efSGarrett D'Amore static void 72695c635efSGarrett D'Amore post_TP(DECL_ARGS) 72795c635efSGarrett D'Amore { 72895c635efSGarrett D'Amore 72995c635efSGarrett D'Amore switch (n->type) { 730*371584c2SYuri Pankov case ROFFT_HEAD: 73195c635efSGarrett D'Amore term_flushln(p); 73295c635efSGarrett D'Amore break; 733*371584c2SYuri Pankov case ROFFT_BODY: 73495c635efSGarrett D'Amore term_newln(p); 735698f87a4SGarrett D'Amore p->offset = mt->offset; 73695c635efSGarrett D'Amore break; 73795c635efSGarrett D'Amore default: 73895c635efSGarrett D'Amore break; 73995c635efSGarrett D'Amore } 74095c635efSGarrett D'Amore } 74195c635efSGarrett D'Amore 74295c635efSGarrett D'Amore static int 74395c635efSGarrett D'Amore pre_SS(DECL_ARGS) 74495c635efSGarrett D'Amore { 745698f87a4SGarrett D'Amore int i; 74695c635efSGarrett D'Amore 74795c635efSGarrett D'Amore switch (n->type) { 748*371584c2SYuri Pankov case ROFFT_BLOCK: 74995c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 75095c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 75195c635efSGarrett D'Amore mt->offset = term_len(p, p->defindent); 752260e9a87SYuri Pankov 753260e9a87SYuri Pankov /* 754260e9a87SYuri Pankov * No vertical space before the first subsection 755260e9a87SYuri Pankov * and after an empty subsection. 756260e9a87SYuri Pankov */ 757260e9a87SYuri Pankov 758260e9a87SYuri Pankov do { 759260e9a87SYuri Pankov n = n->prev; 760*371584c2SYuri Pankov } while (n != NULL && n->tok != TOKEN_NONE && 761*371584c2SYuri Pankov termacts[n->tok].flags & MAN_NOTEXT); 762260e9a87SYuri Pankov if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL)) 76395c635efSGarrett D'Amore break; 764260e9a87SYuri Pankov 765698f87a4SGarrett D'Amore for (i = 0; i < mt->pardist; i++) 76695c635efSGarrett D'Amore term_vspace(p); 76795c635efSGarrett D'Amore break; 768*371584c2SYuri Pankov case ROFFT_HEAD: 76995c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 770698f87a4SGarrett D'Amore p->offset = term_len(p, 3); 771*371584c2SYuri Pankov p->rmargin = mt->offset; 772*371584c2SYuri Pankov p->trailspace = mt->offset; 773*371584c2SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND; 77495c635efSGarrett D'Amore break; 775*371584c2SYuri Pankov case ROFFT_BODY: 77695c635efSGarrett D'Amore p->offset = mt->offset; 777*371584c2SYuri Pankov p->rmargin = p->maxrmargin; 778*371584c2SYuri Pankov p->trailspace = 0; 779*371584c2SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 78095c635efSGarrett D'Amore break; 78195c635efSGarrett D'Amore default: 78295c635efSGarrett D'Amore break; 78395c635efSGarrett D'Amore } 78495c635efSGarrett D'Amore 785*371584c2SYuri Pankov return 1; 78695c635efSGarrett D'Amore } 78795c635efSGarrett D'Amore 78895c635efSGarrett D'Amore static void 78995c635efSGarrett D'Amore post_SS(DECL_ARGS) 79095c635efSGarrett D'Amore { 79195c635efSGarrett D'Amore 79295c635efSGarrett D'Amore switch (n->type) { 793*371584c2SYuri Pankov case ROFFT_HEAD: 79495c635efSGarrett D'Amore term_newln(p); 79595c635efSGarrett D'Amore break; 796*371584c2SYuri Pankov case ROFFT_BODY: 79795c635efSGarrett D'Amore term_newln(p); 79895c635efSGarrett D'Amore break; 79995c635efSGarrett D'Amore default: 80095c635efSGarrett D'Amore break; 80195c635efSGarrett D'Amore } 80295c635efSGarrett D'Amore } 80395c635efSGarrett D'Amore 80495c635efSGarrett D'Amore static int 80595c635efSGarrett D'Amore pre_SH(DECL_ARGS) 80695c635efSGarrett D'Amore { 807698f87a4SGarrett D'Amore int i; 80895c635efSGarrett D'Amore 80995c635efSGarrett D'Amore switch (n->type) { 810*371584c2SYuri Pankov case ROFFT_BLOCK: 81195c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 81295c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 81395c635efSGarrett D'Amore mt->offset = term_len(p, p->defindent); 814260e9a87SYuri Pankov 815260e9a87SYuri Pankov /* 816260e9a87SYuri Pankov * No vertical space before the first section 817260e9a87SYuri Pankov * and after an empty section. 818260e9a87SYuri Pankov */ 819260e9a87SYuri Pankov 820260e9a87SYuri Pankov do { 821260e9a87SYuri Pankov n = n->prev; 822260e9a87SYuri Pankov } while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT); 823260e9a87SYuri Pankov if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL)) 82495c635efSGarrett D'Amore break; 825260e9a87SYuri Pankov 826698f87a4SGarrett D'Amore for (i = 0; i < mt->pardist; i++) 82795c635efSGarrett D'Amore term_vspace(p); 82895c635efSGarrett D'Amore break; 829*371584c2SYuri Pankov case ROFFT_HEAD: 83095c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 83195c635efSGarrett D'Amore p->offset = 0; 832*371584c2SYuri Pankov p->rmargin = mt->offset; 833*371584c2SYuri Pankov p->trailspace = mt->offset; 834*371584c2SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND; 83595c635efSGarrett D'Amore break; 836*371584c2SYuri Pankov case ROFFT_BODY: 83795c635efSGarrett D'Amore p->offset = mt->offset; 838*371584c2SYuri Pankov p->rmargin = p->maxrmargin; 839*371584c2SYuri Pankov p->trailspace = 0; 840*371584c2SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 84195c635efSGarrett D'Amore break; 84295c635efSGarrett D'Amore default: 84395c635efSGarrett D'Amore break; 84495c635efSGarrett D'Amore } 84595c635efSGarrett D'Amore 846*371584c2SYuri Pankov return 1; 84795c635efSGarrett D'Amore } 84895c635efSGarrett D'Amore 84995c635efSGarrett D'Amore static void 85095c635efSGarrett D'Amore post_SH(DECL_ARGS) 85195c635efSGarrett D'Amore { 85295c635efSGarrett D'Amore 85395c635efSGarrett D'Amore switch (n->type) { 854*371584c2SYuri Pankov case ROFFT_HEAD: 85595c635efSGarrett D'Amore term_newln(p); 85695c635efSGarrett D'Amore break; 857*371584c2SYuri Pankov case ROFFT_BODY: 85895c635efSGarrett D'Amore term_newln(p); 85995c635efSGarrett D'Amore break; 86095c635efSGarrett D'Amore default: 86195c635efSGarrett D'Amore break; 86295c635efSGarrett D'Amore } 86395c635efSGarrett D'Amore } 86495c635efSGarrett D'Amore 86595c635efSGarrett D'Amore static int 86695c635efSGarrett D'Amore pre_RS(DECL_ARGS) 86795c635efSGarrett D'Amore { 868260e9a87SYuri Pankov struct roffsu su; 86995c635efSGarrett D'Amore 87095c635efSGarrett D'Amore switch (n->type) { 871*371584c2SYuri Pankov case ROFFT_BLOCK: 87295c635efSGarrett D'Amore term_newln(p); 873*371584c2SYuri Pankov return 1; 874*371584c2SYuri Pankov case ROFFT_HEAD: 875*371584c2SYuri Pankov return 0; 87695c635efSGarrett D'Amore default: 87795c635efSGarrett D'Amore break; 87895c635efSGarrett D'Amore } 87995c635efSGarrett D'Amore 880260e9a87SYuri Pankov n = n->parent->head; 881260e9a87SYuri Pankov n->aux = SHRT_MAX + 1; 882*371584c2SYuri Pankov if (n->child == NULL) 883*371584c2SYuri Pankov n->aux = mt->lmargin[mt->lmargincur]; 884*371584c2SYuri Pankov else if (a2roffsu(n->child->string, &su, SCALE_EN)) 885*371584c2SYuri Pankov n->aux = term_hspan(p, &su) / 24; 886260e9a87SYuri Pankov if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) 887260e9a87SYuri Pankov n->aux = -mt->offset; 888260e9a87SYuri Pankov else if (n->aux > SHRT_MAX) 889260e9a87SYuri Pankov n->aux = term_len(p, p->defindent); 89095c635efSGarrett D'Amore 891260e9a87SYuri Pankov mt->offset += n->aux; 892260e9a87SYuri Pankov p->offset = mt->offset; 89395c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 89495c635efSGarrett D'Amore 89595c635efSGarrett D'Amore if (++mt->lmarginsz < MAXMARGINS) 89695c635efSGarrett D'Amore mt->lmargincur = mt->lmarginsz; 89795c635efSGarrett D'Amore 898*371584c2SYuri Pankov mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 899*371584c2SYuri Pankov return 1; 90095c635efSGarrett D'Amore } 90195c635efSGarrett D'Amore 90295c635efSGarrett D'Amore static void 90395c635efSGarrett D'Amore post_RS(DECL_ARGS) 90495c635efSGarrett D'Amore { 90595c635efSGarrett D'Amore 90695c635efSGarrett D'Amore switch (n->type) { 907*371584c2SYuri Pankov case ROFFT_BLOCK: 90895c635efSGarrett D'Amore return; 909*371584c2SYuri Pankov case ROFFT_HEAD: 91095c635efSGarrett D'Amore return; 91195c635efSGarrett D'Amore default: 91295c635efSGarrett D'Amore term_newln(p); 91395c635efSGarrett D'Amore break; 91495c635efSGarrett D'Amore } 91595c635efSGarrett D'Amore 916260e9a87SYuri Pankov mt->offset -= n->parent->head->aux; 91795c635efSGarrett D'Amore p->offset = mt->offset; 91895c635efSGarrett D'Amore 91995c635efSGarrett D'Amore if (--mt->lmarginsz < MAXMARGINS) 92095c635efSGarrett D'Amore mt->lmargincur = mt->lmarginsz; 92195c635efSGarrett D'Amore } 92295c635efSGarrett D'Amore 923698f87a4SGarrett D'Amore static int 924698f87a4SGarrett D'Amore pre_UR(DECL_ARGS) 925698f87a4SGarrett D'Amore { 926698f87a4SGarrett D'Amore 927*371584c2SYuri Pankov return n->type != ROFFT_HEAD; 928698f87a4SGarrett D'Amore } 929698f87a4SGarrett D'Amore 930698f87a4SGarrett D'Amore static void 931698f87a4SGarrett D'Amore post_UR(DECL_ARGS) 932698f87a4SGarrett D'Amore { 933698f87a4SGarrett D'Amore 934*371584c2SYuri Pankov if (n->type != ROFFT_BLOCK) 935698f87a4SGarrett D'Amore return; 936698f87a4SGarrett D'Amore 937698f87a4SGarrett D'Amore term_word(p, "<"); 938698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 939698f87a4SGarrett D'Amore 940698f87a4SGarrett D'Amore if (NULL != n->child->child) 941698f87a4SGarrett D'Amore print_man_node(p, mt, n->child->child, meta); 942698f87a4SGarrett D'Amore 943698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 944698f87a4SGarrett D'Amore term_word(p, ">"); 945698f87a4SGarrett D'Amore } 946698f87a4SGarrett D'Amore 94795c635efSGarrett D'Amore static void 94895c635efSGarrett D'Amore print_man_node(DECL_ARGS) 94995c635efSGarrett D'Amore { 95095c635efSGarrett D'Amore size_t rm, rmax; 95195c635efSGarrett D'Amore int c; 95295c635efSGarrett D'Amore 95395c635efSGarrett D'Amore switch (n->type) { 954*371584c2SYuri Pankov case ROFFT_TEXT: 95595c635efSGarrett D'Amore /* 95695c635efSGarrett D'Amore * If we have a blank line, output a vertical space. 95795c635efSGarrett D'Amore * If we have a space as the first character, break 95895c635efSGarrett D'Amore * before printing the line's data. 95995c635efSGarrett D'Amore */ 96095c635efSGarrett D'Amore if ('\0' == *n->string) { 96195c635efSGarrett D'Amore term_vspace(p); 96295c635efSGarrett D'Amore return; 96395c635efSGarrett D'Amore } else if (' ' == *n->string && MAN_LINE & n->flags) 96495c635efSGarrett D'Amore term_newln(p); 96595c635efSGarrett D'Amore 96695c635efSGarrett D'Amore term_word(p, n->string); 967698f87a4SGarrett D'Amore goto out; 96895c635efSGarrett D'Amore 969*371584c2SYuri Pankov case ROFFT_EQN: 970260e9a87SYuri Pankov if ( ! (n->flags & MAN_LINE)) 971260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 97295c635efSGarrett D'Amore term_eqn(p, n->eqn); 973260e9a87SYuri Pankov if (n->next != NULL && ! (n->next->flags & MAN_LINE)) 974260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 97595c635efSGarrett D'Amore return; 976*371584c2SYuri Pankov case ROFFT_TBL: 977260e9a87SYuri Pankov if (p->tbl.cols == NULL) 978260e9a87SYuri Pankov term_vspace(p); 97995c635efSGarrett D'Amore term_tbl(p, n->span); 98095c635efSGarrett D'Amore return; 98195c635efSGarrett D'Amore default: 98295c635efSGarrett D'Amore break; 98395c635efSGarrett D'Amore } 98495c635efSGarrett D'Amore 98595c635efSGarrett D'Amore if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) 98695c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 98795c635efSGarrett D'Amore 98895c635efSGarrett D'Amore c = 1; 98995c635efSGarrett D'Amore if (termacts[n->tok].pre) 990698f87a4SGarrett D'Amore c = (*termacts[n->tok].pre)(p, mt, n, meta); 99195c635efSGarrett D'Amore 99295c635efSGarrett D'Amore if (c && n->child) 993698f87a4SGarrett D'Amore print_man_nodelist(p, mt, n->child, meta); 99495c635efSGarrett D'Amore 99595c635efSGarrett D'Amore if (termacts[n->tok].post) 996698f87a4SGarrett D'Amore (*termacts[n->tok].post)(p, mt, n, meta); 99795c635efSGarrett D'Amore if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) 99895c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 99995c635efSGarrett D'Amore 1000698f87a4SGarrett D'Amore out: 1001698f87a4SGarrett D'Amore /* 1002698f87a4SGarrett D'Amore * If we're in a literal context, make sure that words 1003698f87a4SGarrett D'Amore * together on the same line stay together. This is a 1004698f87a4SGarrett D'Amore * POST-printing call, so we check the NEXT word. Since 1005698f87a4SGarrett D'Amore * -man doesn't have nested macros, we don't need to be 1006698f87a4SGarrett D'Amore * more specific than this. 1007698f87a4SGarrett D'Amore */ 1008260e9a87SYuri Pankov if (mt->fl & MANT_LITERAL && 1009260e9a87SYuri Pankov ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && 1010260e9a87SYuri Pankov (n->next == NULL || n->next->flags & MAN_LINE)) { 1011698f87a4SGarrett D'Amore rm = p->rmargin; 1012698f87a4SGarrett D'Amore rmax = p->maxrmargin; 1013698f87a4SGarrett D'Amore p->rmargin = p->maxrmargin = TERM_MAXMARGIN; 1014698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 1015260e9a87SYuri Pankov if (n->string != NULL && *n->string != '\0') 1016698f87a4SGarrett D'Amore term_flushln(p); 1017698f87a4SGarrett D'Amore else 1018698f87a4SGarrett D'Amore term_newln(p); 1019698f87a4SGarrett D'Amore if (rm < rmax && n->parent->tok == MAN_HP) { 1020698f87a4SGarrett D'Amore p->offset = rm; 1021698f87a4SGarrett D'Amore p->rmargin = rmax; 1022698f87a4SGarrett D'Amore } else 1023698f87a4SGarrett D'Amore p->rmargin = rm; 1024698f87a4SGarrett D'Amore p->maxrmargin = rmax; 1025698f87a4SGarrett D'Amore } 102695c635efSGarrett D'Amore if (MAN_EOS & n->flags) 102795c635efSGarrett D'Amore p->flags |= TERMP_SENTENCE; 102895c635efSGarrett D'Amore } 102995c635efSGarrett D'Amore 103095c635efSGarrett D'Amore 103195c635efSGarrett D'Amore static void 103295c635efSGarrett D'Amore print_man_nodelist(DECL_ARGS) 103395c635efSGarrett D'Amore { 103495c635efSGarrett D'Amore 1035260e9a87SYuri Pankov while (n != NULL) { 1036698f87a4SGarrett D'Amore print_man_node(p, mt, n, meta); 1037260e9a87SYuri Pankov n = n->next; 103895c635efSGarrett D'Amore } 1039260e9a87SYuri Pankov } 104095c635efSGarrett D'Amore 104195c635efSGarrett D'Amore static void 1042*371584c2SYuri Pankov print_man_foot(struct termp *p, const struct roff_meta *meta) 104395c635efSGarrett D'Amore { 1044260e9a87SYuri Pankov char *title; 1045260e9a87SYuri Pankov size_t datelen, titlen; 104695c635efSGarrett D'Amore 104795c635efSGarrett D'Amore assert(meta->title); 104895c635efSGarrett D'Amore assert(meta->msec); 104995c635efSGarrett D'Amore assert(meta->date); 105095c635efSGarrett D'Amore 105195c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 105295c635efSGarrett D'Amore 1053260e9a87SYuri Pankov if (meta->hasbody) 105495c635efSGarrett D'Amore term_vspace(p); 105595c635efSGarrett D'Amore 105695c635efSGarrett D'Amore /* 105795c635efSGarrett D'Amore * Temporary, undocumented option to imitate mdoc(7) output. 1058*371584c2SYuri Pankov * In the bottom right corner, use the operating system 1059*371584c2SYuri Pankov * instead of the title. 106095c635efSGarrett D'Amore */ 106195c635efSGarrett D'Amore 106295c635efSGarrett D'Amore if ( ! p->mdocstyle) { 1063260e9a87SYuri Pankov if (meta->hasbody) { 106495c635efSGarrett D'Amore term_vspace(p); 106595c635efSGarrett D'Amore term_vspace(p); 1066260e9a87SYuri Pankov } 1067260e9a87SYuri Pankov mandoc_asprintf(&title, "%s(%s)", 1068260e9a87SYuri Pankov meta->title, meta->msec); 1069*371584c2SYuri Pankov } else if (meta->os) { 1070*371584c2SYuri Pankov title = mandoc_strdup(meta->os); 107195c635efSGarrett D'Amore } else { 1072260e9a87SYuri Pankov title = mandoc_strdup(""); 107395c635efSGarrett D'Amore } 107495c635efSGarrett D'Amore datelen = term_strlen(p, meta->date); 107595c635efSGarrett D'Amore 1076*371584c2SYuri Pankov /* Bottom left corner: operating system. */ 107795c635efSGarrett D'Amore 107895c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 1079698f87a4SGarrett D'Amore p->trailspace = 1; 108095c635efSGarrett D'Amore p->offset = 0; 1081260e9a87SYuri Pankov p->rmargin = p->maxrmargin > datelen ? 1082260e9a87SYuri Pankov (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; 108395c635efSGarrett D'Amore 1084*371584c2SYuri Pankov if (meta->os) 1085*371584c2SYuri Pankov term_word(p, meta->os); 108695c635efSGarrett D'Amore term_flushln(p); 108795c635efSGarrett D'Amore 108895c635efSGarrett D'Amore /* At the bottom in the middle: manual date. */ 108995c635efSGarrett D'Amore 109095c635efSGarrett D'Amore p->offset = p->rmargin; 1091260e9a87SYuri Pankov titlen = term_strlen(p, title); 1092260e9a87SYuri Pankov p->rmargin = p->maxrmargin > titlen ? p->maxrmargin - titlen : 0; 1093260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 109495c635efSGarrett D'Amore 109595c635efSGarrett D'Amore term_word(p, meta->date); 109695c635efSGarrett D'Amore term_flushln(p); 109795c635efSGarrett D'Amore 109895c635efSGarrett D'Amore /* Bottom right corner: manual title and section. */ 109995c635efSGarrett D'Amore 110095c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 110195c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 1102698f87a4SGarrett D'Amore p->trailspace = 0; 110395c635efSGarrett D'Amore p->offset = p->rmargin; 110495c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 110595c635efSGarrett D'Amore 110695c635efSGarrett D'Amore term_word(p, title); 110795c635efSGarrett D'Amore term_flushln(p); 1108260e9a87SYuri Pankov free(title); 110995c635efSGarrett D'Amore } 111095c635efSGarrett D'Amore 111195c635efSGarrett D'Amore static void 1112*371584c2SYuri Pankov print_man_head(struct termp *p, const struct roff_meta *meta) 111395c635efSGarrett D'Amore { 1114260e9a87SYuri Pankov const char *volume; 1115260e9a87SYuri Pankov char *title; 1116260e9a87SYuri Pankov size_t vollen, titlen; 111795c635efSGarrett D'Amore 1118698f87a4SGarrett D'Amore assert(meta->title); 1119698f87a4SGarrett D'Amore assert(meta->msec); 112095c635efSGarrett D'Amore 1121260e9a87SYuri Pankov volume = NULL == meta->vol ? "" : meta->vol; 1122260e9a87SYuri Pankov vollen = term_strlen(p, volume); 112395c635efSGarrett D'Amore 112495c635efSGarrett D'Amore /* Top left corner: manual title and section. */ 112595c635efSGarrett D'Amore 1126260e9a87SYuri Pankov mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); 112795c635efSGarrett D'Amore titlen = term_strlen(p, title); 112895c635efSGarrett D'Amore 112995c635efSGarrett D'Amore p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; 1130698f87a4SGarrett D'Amore p->trailspace = 1; 113195c635efSGarrett D'Amore p->offset = 0; 1132260e9a87SYuri Pankov p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? 1133260e9a87SYuri Pankov (p->maxrmargin - vollen + term_len(p, 1)) / 2 : 1134260e9a87SYuri Pankov vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; 113595c635efSGarrett D'Amore 113695c635efSGarrett D'Amore term_word(p, title); 113795c635efSGarrett D'Amore term_flushln(p); 113895c635efSGarrett D'Amore 113995c635efSGarrett D'Amore /* At the top in the middle: manual volume. */ 114095c635efSGarrett D'Amore 114195c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 114295c635efSGarrett D'Amore p->offset = p->rmargin; 1143260e9a87SYuri Pankov p->rmargin = p->offset + vollen + titlen < p->maxrmargin ? 114495c635efSGarrett D'Amore p->maxrmargin - titlen : p->maxrmargin; 114595c635efSGarrett D'Amore 1146260e9a87SYuri Pankov term_word(p, volume); 114795c635efSGarrett D'Amore term_flushln(p); 114895c635efSGarrett D'Amore 114995c635efSGarrett D'Amore /* Top right corner: title and section, again. */ 115095c635efSGarrett D'Amore 115195c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 1152698f87a4SGarrett D'Amore p->trailspace = 0; 115395c635efSGarrett D'Amore if (p->rmargin + titlen <= p->maxrmargin) { 115495c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 115595c635efSGarrett D'Amore p->offset = p->rmargin; 115695c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 115795c635efSGarrett D'Amore term_word(p, title); 115895c635efSGarrett D'Amore term_flushln(p); 115995c635efSGarrett D'Amore } 116095c635efSGarrett D'Amore 116195c635efSGarrett D'Amore p->flags &= ~TERMP_NOSPACE; 116295c635efSGarrett D'Amore p->offset = 0; 116395c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 116495c635efSGarrett D'Amore 116595c635efSGarrett D'Amore /* 116695c635efSGarrett D'Amore * Groff prints three blank lines before the content. 116795c635efSGarrett D'Amore * Do the same, except in the temporary, undocumented 116895c635efSGarrett D'Amore * mode imitating mdoc(7) output. 116995c635efSGarrett D'Amore */ 117095c635efSGarrett D'Amore 117195c635efSGarrett D'Amore term_vspace(p); 117295c635efSGarrett D'Amore if ( ! p->mdocstyle) { 117395c635efSGarrett D'Amore term_vspace(p); 117495c635efSGarrett D'Amore term_vspace(p); 117595c635efSGarrett D'Amore } 1176260e9a87SYuri Pankov free(title); 117795c635efSGarrett D'Amore } 1178