1*a40ea1a7SYuri Pankov /* $Id: man_term.c,v 1.191 2017/02/15 14:10:08 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4*a40ea1a7SYuri Pankov * Copyright (c) 2010-2015, 2017 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 * 10371584c2SYuri 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 12371584c2SYuri 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" 30371584c2SYuri Pankov #include "mandoc.h" 31371584c2SYuri Pankov #include "roff.h" 3295c635efSGarrett D'Amore #include "man.h" 33371584c2SYuri 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, \ 51371584c2SYuri Pankov struct roff_node *n, \ 52371584c2SYuri 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); 63371584c2SYuri Pankov static void print_man_head(struct termp *, 64371584c2SYuri Pankov const struct roff_meta *); 65371584c2SYuri Pankov static void print_man_foot(struct termp *, 66371584c2SYuri Pankov const struct roff_meta *); 6795c635efSGarrett D'Amore static void print_bvspace(struct termp *, 68371584c2SYuri 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 141371584c2SYuri Pankov terminal_man(void *arg, const struct roff_man *man) 14295c635efSGarrett D'Amore { 14395c635efSGarrett D'Amore struct termp *p; 144371584c2SYuri Pankov struct roff_node *n; 14595c635efSGarrett D'Amore struct mtermp mt; 146*a40ea1a7SYuri Pankov size_t save_defindent; 14795c635efSGarrett D'Amore 14895c635efSGarrett D'Amore p = (struct termp *)arg; 14995c635efSGarrett D'Amore p->overstep = 0; 150260e9a87SYuri Pankov p->rmargin = p->maxrmargin = p->defrmargin; 15195c635efSGarrett D'Amore p->tabwidth = term_len(p, 5); 15295c635efSGarrett D'Amore 15395c635efSGarrett D'Amore memset(&mt, 0, sizeof(struct mtermp)); 15495c635efSGarrett D'Amore mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); 15595c635efSGarrett D'Amore mt.offset = term_len(p, p->defindent); 156698f87a4SGarrett D'Amore mt.pardist = 1; 15795c635efSGarrett D'Amore 158371584c2SYuri Pankov n = man->first->child; 159260e9a87SYuri Pankov if (p->synopsisonly) { 160260e9a87SYuri Pankov while (n != NULL) { 161260e9a87SYuri Pankov if (n->tok == MAN_SH && 162371584c2SYuri Pankov n->child->child->type == ROFFT_TEXT && 163260e9a87SYuri Pankov !strcmp(n->child->child->string, "SYNOPSIS")) { 164260e9a87SYuri Pankov if (n->child->next->child != NULL) 165260e9a87SYuri Pankov print_man_nodelist(p, &mt, 166371584c2SYuri Pankov n->child->next->child, 167371584c2SYuri Pankov &man->meta); 168260e9a87SYuri Pankov term_newln(p); 169260e9a87SYuri Pankov break; 170260e9a87SYuri Pankov } 171260e9a87SYuri Pankov n = n->next; 172260e9a87SYuri Pankov } 173260e9a87SYuri Pankov } else { 174*a40ea1a7SYuri Pankov save_defindent = p->defindent; 175260e9a87SYuri Pankov if (p->defindent == 0) 176260e9a87SYuri Pankov p->defindent = 7; 177371584c2SYuri Pankov term_begin(p, print_man_head, print_man_foot, &man->meta); 178260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 179260e9a87SYuri Pankov if (n != NULL) 180371584c2SYuri Pankov print_man_nodelist(p, &mt, n, &man->meta); 18195c635efSGarrett D'Amore term_end(p); 182*a40ea1a7SYuri Pankov p->defindent = save_defindent; 18395c635efSGarrett D'Amore } 18495c635efSGarrett D'Amore } 18595c635efSGarrett D'Amore 18695c635efSGarrett D'Amore /* 18795c635efSGarrett D'Amore * Printing leading vertical space before a block. 18895c635efSGarrett D'Amore * This is used for the paragraph macros. 18995c635efSGarrett D'Amore * The rules are pretty simple, since there's very little nesting going 19095c635efSGarrett D'Amore * on here. Basically, if we're the first within another block (SS/SH), 19195c635efSGarrett D'Amore * then don't emit vertical space. If we are (RS), then do. If not the 19295c635efSGarrett D'Amore * first, print it. 19395c635efSGarrett D'Amore */ 19495c635efSGarrett D'Amore static void 195371584c2SYuri Pankov print_bvspace(struct termp *p, const struct roff_node *n, int pardist) 19695c635efSGarrett D'Amore { 197698f87a4SGarrett D'Amore int i; 19895c635efSGarrett D'Amore 19995c635efSGarrett D'Amore term_newln(p); 20095c635efSGarrett D'Amore 20195c635efSGarrett D'Amore if (n->body && n->body->child) 202371584c2SYuri Pankov if (n->body->child->type == ROFFT_TBL) 20395c635efSGarrett D'Amore return; 20495c635efSGarrett D'Amore 205371584c2SYuri Pankov if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) 20695c635efSGarrett D'Amore if (NULL == n->prev) 20795c635efSGarrett D'Amore return; 20895c635efSGarrett D'Amore 209698f87a4SGarrett D'Amore for (i = 0; i < pardist; i++) 21095c635efSGarrett D'Amore term_vspace(p); 21195c635efSGarrett D'Amore } 21295c635efSGarrett D'Amore 213260e9a87SYuri Pankov 21495c635efSGarrett D'Amore static int 21595c635efSGarrett D'Amore pre_ign(DECL_ARGS) 21695c635efSGarrett D'Amore { 21795c635efSGarrett D'Amore 218371584c2SYuri Pankov return 0; 21995c635efSGarrett D'Amore } 22095c635efSGarrett D'Amore 221260e9a87SYuri Pankov static int 222260e9a87SYuri Pankov pre_ll(DECL_ARGS) 223260e9a87SYuri Pankov { 22495c635efSGarrett D'Amore 225371584c2SYuri Pankov term_setwidth(p, n->child != NULL ? n->child->string : NULL); 226371584c2SYuri Pankov return 0; 227260e9a87SYuri Pankov } 228260e9a87SYuri Pankov 22995c635efSGarrett D'Amore static int 23095c635efSGarrett D'Amore pre_I(DECL_ARGS) 23195c635efSGarrett D'Amore { 23295c635efSGarrett D'Amore 23395c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 234371584c2SYuri Pankov return 1; 23595c635efSGarrett D'Amore } 23695c635efSGarrett D'Amore 23795c635efSGarrett D'Amore static int 23895c635efSGarrett D'Amore pre_literal(DECL_ARGS) 23995c635efSGarrett D'Amore { 24095c635efSGarrett D'Amore 24195c635efSGarrett D'Amore term_newln(p); 24295c635efSGarrett D'Amore 243698f87a4SGarrett D'Amore if (MAN_nf == n->tok || MAN_EX == n->tok) 24495c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 24595c635efSGarrett D'Amore else 24695c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 24795c635efSGarrett D'Amore 24895c635efSGarrett D'Amore /* 24995c635efSGarrett D'Amore * Unlike .IP and .TP, .HP does not have a HEAD. 25095c635efSGarrett D'Amore * So in case a second call to term_flushln() is needed, 25195c635efSGarrett D'Amore * indentation has to be set up explicitly. 25295c635efSGarrett D'Amore */ 25395c635efSGarrett D'Amore if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) { 25495c635efSGarrett D'Amore p->offset = p->rmargin; 25595c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 256698f87a4SGarrett D'Amore p->trailspace = 0; 257260e9a87SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 25895c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 25995c635efSGarrett D'Amore } 26095c635efSGarrett D'Amore 261371584c2SYuri Pankov return 0; 26295c635efSGarrett D'Amore } 26395c635efSGarrett D'Amore 26495c635efSGarrett D'Amore static int 265698f87a4SGarrett D'Amore pre_PD(DECL_ARGS) 266698f87a4SGarrett D'Amore { 267260e9a87SYuri Pankov struct roffsu su; 268698f87a4SGarrett D'Amore 269698f87a4SGarrett D'Amore n = n->child; 270260e9a87SYuri Pankov if (n == NULL) { 271698f87a4SGarrett D'Amore mt->pardist = 1; 272371584c2SYuri Pankov return 0; 273698f87a4SGarrett D'Amore } 274371584c2SYuri Pankov assert(n->type == ROFFT_TEXT); 275260e9a87SYuri Pankov if (a2roffsu(n->string, &su, SCALE_VS)) 276260e9a87SYuri Pankov mt->pardist = term_vspan(p, &su); 277371584c2SYuri Pankov return 0; 278698f87a4SGarrett D'Amore } 279698f87a4SGarrett D'Amore 280698f87a4SGarrett D'Amore static int 28195c635efSGarrett D'Amore pre_alternate(DECL_ARGS) 28295c635efSGarrett D'Amore { 28395c635efSGarrett D'Amore enum termfont font[2]; 284371584c2SYuri Pankov struct roff_node *nn; 28595c635efSGarrett D'Amore int savelit, i; 28695c635efSGarrett D'Amore 28795c635efSGarrett D'Amore switch (n->tok) { 288260e9a87SYuri Pankov case MAN_RB: 28995c635efSGarrett D'Amore font[0] = TERMFONT_NONE; 29095c635efSGarrett D'Amore font[1] = TERMFONT_BOLD; 29195c635efSGarrett D'Amore break; 292260e9a87SYuri Pankov case MAN_RI: 29395c635efSGarrett D'Amore font[0] = TERMFONT_NONE; 29495c635efSGarrett D'Amore font[1] = TERMFONT_UNDER; 29595c635efSGarrett D'Amore break; 296260e9a87SYuri Pankov case MAN_BR: 29795c635efSGarrett D'Amore font[0] = TERMFONT_BOLD; 29895c635efSGarrett D'Amore font[1] = TERMFONT_NONE; 29995c635efSGarrett D'Amore break; 300260e9a87SYuri Pankov case MAN_BI: 30195c635efSGarrett D'Amore font[0] = TERMFONT_BOLD; 30295c635efSGarrett D'Amore font[1] = TERMFONT_UNDER; 30395c635efSGarrett D'Amore break; 304260e9a87SYuri Pankov case MAN_IR: 30595c635efSGarrett D'Amore font[0] = TERMFONT_UNDER; 30695c635efSGarrett D'Amore font[1] = TERMFONT_NONE; 30795c635efSGarrett D'Amore break; 308260e9a87SYuri Pankov case MAN_IB: 30995c635efSGarrett D'Amore font[0] = TERMFONT_UNDER; 31095c635efSGarrett D'Amore font[1] = TERMFONT_BOLD; 31195c635efSGarrett D'Amore break; 31295c635efSGarrett D'Amore default: 31395c635efSGarrett D'Amore abort(); 31495c635efSGarrett D'Amore } 31595c635efSGarrett D'Amore 31695c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 31795c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 31895c635efSGarrett D'Amore 31995c635efSGarrett D'Amore for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) { 32095c635efSGarrett D'Amore term_fontrepl(p, font[i]); 32195c635efSGarrett D'Amore if (savelit && NULL == nn->next) 32295c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 323371584c2SYuri Pankov assert(nn->type == ROFFT_TEXT); 324371584c2SYuri Pankov term_word(p, nn->string); 325*a40ea1a7SYuri Pankov if (nn->flags & NODE_EOS) 326371584c2SYuri Pankov p->flags |= TERMP_SENTENCE; 32795c635efSGarrett D'Amore if (nn->next) 32895c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 32995c635efSGarrett D'Amore } 33095c635efSGarrett D'Amore 331371584c2SYuri Pankov return 0; 33295c635efSGarrett D'Amore } 33395c635efSGarrett D'Amore 33495c635efSGarrett D'Amore static int 33595c635efSGarrett D'Amore pre_B(DECL_ARGS) 33695c635efSGarrett D'Amore { 33795c635efSGarrett D'Amore 33895c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 339371584c2SYuri Pankov return 1; 34095c635efSGarrett D'Amore } 34195c635efSGarrett D'Amore 34295c635efSGarrett D'Amore static int 34395c635efSGarrett D'Amore pre_OP(DECL_ARGS) 34495c635efSGarrett D'Amore { 34595c635efSGarrett D'Amore 34695c635efSGarrett D'Amore term_word(p, "["); 34795c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 34895c635efSGarrett D'Amore 34995c635efSGarrett D'Amore if (NULL != (n = n->child)) { 35095c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 35195c635efSGarrett D'Amore term_word(p, n->string); 35295c635efSGarrett D'Amore } 35395c635efSGarrett D'Amore if (NULL != n && NULL != n->next) { 35495c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 35595c635efSGarrett D'Amore term_word(p, n->next->string); 35695c635efSGarrett D'Amore } 35795c635efSGarrett D'Amore 35895c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 35995c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 36095c635efSGarrett D'Amore term_word(p, "]"); 361371584c2SYuri Pankov return 0; 36295c635efSGarrett D'Amore } 36395c635efSGarrett D'Amore 36495c635efSGarrett D'Amore static int 36595c635efSGarrett D'Amore pre_ft(DECL_ARGS) 36695c635efSGarrett D'Amore { 36795c635efSGarrett D'Amore const char *cp; 36895c635efSGarrett D'Amore 36995c635efSGarrett D'Amore if (NULL == n->child) { 37095c635efSGarrett D'Amore term_fontlast(p); 371371584c2SYuri Pankov return 0; 37295c635efSGarrett D'Amore } 37395c635efSGarrett D'Amore 37495c635efSGarrett D'Amore cp = n->child->string; 37595c635efSGarrett D'Amore switch (*cp) { 376260e9a87SYuri Pankov case '4': 377260e9a87SYuri Pankov case '3': 378260e9a87SYuri Pankov case 'B': 37995c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 38095c635efSGarrett D'Amore break; 381260e9a87SYuri Pankov case '2': 382260e9a87SYuri Pankov case 'I': 38395c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_UNDER); 38495c635efSGarrett D'Amore break; 385260e9a87SYuri Pankov case 'P': 38695c635efSGarrett D'Amore term_fontlast(p); 38795c635efSGarrett D'Amore break; 388260e9a87SYuri Pankov case '1': 389260e9a87SYuri Pankov case 'C': 390260e9a87SYuri 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 } 396371584c2SYuri Pankov return 0; 39795c635efSGarrett D'Amore } 39895c635efSGarrett D'Amore 39995c635efSGarrett D'Amore static int 40095c635efSGarrett D'Amore pre_in(DECL_ARGS) 40195c635efSGarrett D'Amore { 402260e9a87SYuri Pankov struct roffsu su; 40395c635efSGarrett D'Amore const char *cp; 404260e9a87SYuri Pankov size_t v; 405260e9a87SYuri 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; 411371584c2SYuri Pankov 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 424260e9a87SYuri Pankov if ( ! a2roffsu(++cp, &su, SCALE_EN)) 425371584c2SYuri Pankov return 0; 42695c635efSGarrett D'Amore 427371584c2SYuri Pankov v = (term_hspan(p, &su) + 11) / 24; 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; 435260e9a87SYuri Pankov if (p->offset > SHRT_MAX) 436260e9a87SYuri Pankov p->offset = term_len(p, p->defindent); 43795c635efSGarrett D'Amore 438371584c2SYuri Pankov return 0; 43995c635efSGarrett D'Amore } 44095c635efSGarrett D'Amore 44195c635efSGarrett D'Amore static int 44295c635efSGarrett D'Amore pre_sp(DECL_ARGS) 44395c635efSGarrett D'Amore { 444260e9a87SYuri Pankov struct roffsu su; 445260e9a87SYuri Pankov int i, len; 44695c635efSGarrett D'Amore 44795c635efSGarrett D'Amore if ((NULL == n->prev && n->parent)) { 448698f87a4SGarrett D'Amore switch (n->parent->tok) { 449260e9a87SYuri Pankov case MAN_SH: 450260e9a87SYuri Pankov case MAN_SS: 451260e9a87SYuri Pankov case MAN_PP: 452260e9a87SYuri Pankov case MAN_LP: 453260e9a87SYuri Pankov case MAN_P: 454371584c2SYuri Pankov return 0; 455698f87a4SGarrett D'Amore default: 456698f87a4SGarrett D'Amore break; 457698f87a4SGarrett D'Amore } 45895c635efSGarrett D'Amore } 45995c635efSGarrett D'Amore 460260e9a87SYuri Pankov if (n->tok == MAN_br) 46195c635efSGarrett D'Amore len = 0; 462260e9a87SYuri Pankov else if (n->child == NULL) 463698f87a4SGarrett D'Amore len = 1; 464260e9a87SYuri Pankov else { 465260e9a87SYuri Pankov if ( ! a2roffsu(n->child->string, &su, SCALE_VS)) 466260e9a87SYuri Pankov su.scale = 1.0; 467260e9a87SYuri Pankov len = term_vspan(p, &su); 46895c635efSGarrett D'Amore } 46995c635efSGarrett D'Amore 470260e9a87SYuri Pankov if (len == 0) 47195c635efSGarrett D'Amore term_newln(p); 472260e9a87SYuri Pankov else if (len < 0) 473260e9a87SYuri Pankov p->skipvsp -= len; 474698f87a4SGarrett D'Amore else 47595c635efSGarrett D'Amore for (i = 0; i < len; i++) 47695c635efSGarrett D'Amore term_vspace(p); 47795c635efSGarrett D'Amore 478371584c2SYuri Pankov /* 479371584c2SYuri Pankov * Handle an explicit break request in the same way 480371584c2SYuri Pankov * as an overflowing line. 481371584c2SYuri Pankov */ 482371584c2SYuri Pankov 483371584c2SYuri Pankov if (p->flags & TERMP_BRIND) { 484371584c2SYuri Pankov p->offset = p->rmargin; 485371584c2SYuri Pankov p->rmargin = p->maxrmargin; 486371584c2SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 487371584c2SYuri Pankov } 488371584c2SYuri Pankov 489371584c2SYuri Pankov return 0; 49095c635efSGarrett D'Amore } 49195c635efSGarrett D'Amore 49295c635efSGarrett D'Amore static int 49395c635efSGarrett D'Amore pre_HP(DECL_ARGS) 49495c635efSGarrett D'Amore { 495260e9a87SYuri Pankov struct roffsu su; 496371584c2SYuri Pankov const struct roff_node *nn; 497260e9a87SYuri Pankov int len; 49895c635efSGarrett D'Amore 49995c635efSGarrett D'Amore switch (n->type) { 500371584c2SYuri Pankov case ROFFT_BLOCK: 501698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 502371584c2SYuri Pankov return 1; 503371584c2SYuri Pankov case ROFFT_BODY: 50495c635efSGarrett D'Amore break; 50595c635efSGarrett D'Amore default: 506371584c2SYuri Pankov return 0; 50795c635efSGarrett D'Amore } 50895c635efSGarrett D'Amore 509698f87a4SGarrett D'Amore if ( ! (MANT_LITERAL & mt->fl)) { 510260e9a87SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND; 511698f87a4SGarrett D'Amore p->trailspace = 2; 512698f87a4SGarrett D'Amore } 513698f87a4SGarrett D'Amore 51495c635efSGarrett D'Amore /* Calculate offset. */ 51595c635efSGarrett D'Amore 516260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 517260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 518371584c2SYuri Pankov len = term_hspan(p, &su) / 24; 519260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 520260e9a87SYuri Pankov len = -mt->offset; 521260e9a87SYuri Pankov else if (len > SHRT_MAX) 522260e9a87SYuri Pankov len = term_len(p, p->defindent); 523260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 524260e9a87SYuri Pankov } else 525260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 52695c635efSGarrett D'Amore 52795c635efSGarrett D'Amore p->offset = mt->offset; 52895c635efSGarrett D'Amore p->rmargin = mt->offset + len; 529371584c2SYuri Pankov return 1; 53095c635efSGarrett D'Amore } 53195c635efSGarrett D'Amore 53295c635efSGarrett D'Amore static void 53395c635efSGarrett D'Amore post_HP(DECL_ARGS) 53495c635efSGarrett D'Amore { 53595c635efSGarrett D'Amore 53695c635efSGarrett D'Amore switch (n->type) { 537371584c2SYuri Pankov case ROFFT_BODY: 538698f87a4SGarrett D'Amore term_newln(p); 539371584c2SYuri Pankov 540371584c2SYuri Pankov /* 541371584c2SYuri Pankov * Compatibility with a groff bug. 542371584c2SYuri Pankov * The .HP macro uses the undocumented .tag request 543371584c2SYuri Pankov * which causes a line break and cancels no-space 544371584c2SYuri Pankov * mode even if there isn't any output. 545371584c2SYuri Pankov */ 546371584c2SYuri Pankov 547371584c2SYuri Pankov if (n->child == NULL) 548371584c2SYuri Pankov term_vspace(p); 549371584c2SYuri Pankov 550260e9a87SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 551698f87a4SGarrett D'Amore p->trailspace = 0; 55295c635efSGarrett D'Amore p->offset = mt->offset; 55395c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 55495c635efSGarrett D'Amore break; 55595c635efSGarrett D'Amore default: 55695c635efSGarrett D'Amore break; 55795c635efSGarrett D'Amore } 55895c635efSGarrett D'Amore } 55995c635efSGarrett D'Amore 56095c635efSGarrett D'Amore static int 56195c635efSGarrett D'Amore pre_PP(DECL_ARGS) 56295c635efSGarrett D'Amore { 56395c635efSGarrett D'Amore 56495c635efSGarrett D'Amore switch (n->type) { 565371584c2SYuri Pankov case ROFFT_BLOCK: 56695c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 567698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 56895c635efSGarrett D'Amore break; 56995c635efSGarrett D'Amore default: 57095c635efSGarrett D'Amore p->offset = mt->offset; 57195c635efSGarrett D'Amore break; 57295c635efSGarrett D'Amore } 57395c635efSGarrett D'Amore 574371584c2SYuri Pankov return n->type != ROFFT_HEAD; 57595c635efSGarrett D'Amore } 57695c635efSGarrett D'Amore 57795c635efSGarrett D'Amore static int 57895c635efSGarrett D'Amore pre_IP(DECL_ARGS) 57995c635efSGarrett D'Amore { 580260e9a87SYuri Pankov struct roffsu su; 581371584c2SYuri Pankov const struct roff_node *nn; 582260e9a87SYuri Pankov int len, savelit; 58395c635efSGarrett D'Amore 58495c635efSGarrett D'Amore switch (n->type) { 585371584c2SYuri Pankov case ROFFT_BODY: 58695c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 58795c635efSGarrett D'Amore break; 588371584c2SYuri Pankov case ROFFT_HEAD: 58995c635efSGarrett D'Amore p->flags |= TERMP_NOBREAK; 590698f87a4SGarrett D'Amore p->trailspace = 1; 59195c635efSGarrett D'Amore break; 592371584c2SYuri Pankov case ROFFT_BLOCK: 593698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 59495c635efSGarrett D'Amore /* FALLTHROUGH */ 59595c635efSGarrett D'Amore default: 596371584c2SYuri Pankov return 1; 59795c635efSGarrett D'Amore } 59895c635efSGarrett D'Amore 59995c635efSGarrett D'Amore /* Calculate the offset from the optional second argument. */ 600260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 601260e9a87SYuri Pankov (nn = nn->next) != NULL && 602260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 603371584c2SYuri Pankov len = term_hspan(p, &su) / 24; 604260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 605260e9a87SYuri Pankov len = -mt->offset; 606260e9a87SYuri Pankov else if (len > SHRT_MAX) 607260e9a87SYuri Pankov len = term_len(p, p->defindent); 608260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 609260e9a87SYuri Pankov } else 610260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 61195c635efSGarrett D'Amore 61295c635efSGarrett D'Amore switch (n->type) { 613371584c2SYuri Pankov case ROFFT_HEAD: 61495c635efSGarrett D'Amore p->offset = mt->offset; 61595c635efSGarrett D'Amore p->rmargin = mt->offset + len; 61695c635efSGarrett D'Amore 61795c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 61895c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 61995c635efSGarrett D'Amore 62095c635efSGarrett D'Amore if (n->child) 621698f87a4SGarrett D'Amore print_man_node(p, mt, n->child, meta); 62295c635efSGarrett D'Amore 62395c635efSGarrett D'Amore if (savelit) 62495c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 62595c635efSGarrett D'Amore 626371584c2SYuri Pankov return 0; 627371584c2SYuri Pankov case ROFFT_BODY: 62895c635efSGarrett D'Amore p->offset = mt->offset + len; 62995c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 63095c635efSGarrett D'Amore break; 63195c635efSGarrett D'Amore default: 63295c635efSGarrett D'Amore break; 63395c635efSGarrett D'Amore } 63495c635efSGarrett D'Amore 635371584c2SYuri Pankov return 1; 63695c635efSGarrett D'Amore } 63795c635efSGarrett D'Amore 63895c635efSGarrett D'Amore static void 63995c635efSGarrett D'Amore post_IP(DECL_ARGS) 64095c635efSGarrett D'Amore { 64195c635efSGarrett D'Amore 64295c635efSGarrett D'Amore switch (n->type) { 643371584c2SYuri Pankov case ROFFT_HEAD: 64495c635efSGarrett D'Amore term_flushln(p); 64595c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 646698f87a4SGarrett D'Amore p->trailspace = 0; 64795c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 64895c635efSGarrett D'Amore break; 649371584c2SYuri Pankov case ROFFT_BODY: 65095c635efSGarrett D'Amore term_newln(p); 651698f87a4SGarrett D'Amore p->offset = mt->offset; 65295c635efSGarrett D'Amore break; 65395c635efSGarrett D'Amore default: 65495c635efSGarrett D'Amore break; 65595c635efSGarrett D'Amore } 65695c635efSGarrett D'Amore } 65795c635efSGarrett D'Amore 65895c635efSGarrett D'Amore static int 65995c635efSGarrett D'Amore pre_TP(DECL_ARGS) 66095c635efSGarrett D'Amore { 661260e9a87SYuri Pankov struct roffsu su; 662371584c2SYuri Pankov struct roff_node *nn; 663260e9a87SYuri Pankov int len, savelit; 66495c635efSGarrett D'Amore 66595c635efSGarrett D'Amore switch (n->type) { 666371584c2SYuri Pankov case ROFFT_HEAD: 667371584c2SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRTRSP; 668698f87a4SGarrett D'Amore p->trailspace = 1; 66995c635efSGarrett D'Amore break; 670371584c2SYuri Pankov case ROFFT_BODY: 67195c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 67295c635efSGarrett D'Amore break; 673371584c2SYuri Pankov case ROFFT_BLOCK: 674698f87a4SGarrett D'Amore print_bvspace(p, n, mt->pardist); 67595c635efSGarrett D'Amore /* FALLTHROUGH */ 67695c635efSGarrett D'Amore default: 677371584c2SYuri Pankov return 1; 67895c635efSGarrett D'Amore } 67995c635efSGarrett D'Amore 68095c635efSGarrett D'Amore /* Calculate offset. */ 68195c635efSGarrett D'Amore 682260e9a87SYuri Pankov if ((nn = n->parent->head->child) != NULL && 683*a40ea1a7SYuri Pankov nn->string != NULL && ! (NODE_LINE & nn->flags) && 684260e9a87SYuri Pankov a2roffsu(nn->string, &su, SCALE_EN)) { 685371584c2SYuri Pankov len = term_hspan(p, &su) / 24; 686260e9a87SYuri Pankov if (len < 0 && (size_t)(-len) > mt->offset) 687260e9a87SYuri Pankov len = -mt->offset; 688260e9a87SYuri Pankov else if (len > SHRT_MAX) 689260e9a87SYuri Pankov len = term_len(p, p->defindent); 690260e9a87SYuri Pankov mt->lmargin[mt->lmargincur] = len; 691260e9a87SYuri Pankov } else 692260e9a87SYuri Pankov len = mt->lmargin[mt->lmargincur]; 69395c635efSGarrett D'Amore 69495c635efSGarrett D'Amore switch (n->type) { 695371584c2SYuri Pankov case ROFFT_HEAD: 69695c635efSGarrett D'Amore p->offset = mt->offset; 69795c635efSGarrett D'Amore p->rmargin = mt->offset + len; 69895c635efSGarrett D'Amore 69995c635efSGarrett D'Amore savelit = MANT_LITERAL & mt->fl; 70095c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 70195c635efSGarrett D'Amore 70295c635efSGarrett D'Amore /* Don't print same-line elements. */ 703260e9a87SYuri Pankov nn = n->child; 704*a40ea1a7SYuri Pankov while (NULL != nn && 0 == (NODE_LINE & nn->flags)) 705260e9a87SYuri Pankov nn = nn->next; 706260e9a87SYuri Pankov 707260e9a87SYuri Pankov while (NULL != nn) { 708698f87a4SGarrett D'Amore print_man_node(p, mt, nn, meta); 709260e9a87SYuri Pankov nn = nn->next; 710260e9a87SYuri Pankov } 71195c635efSGarrett D'Amore 71295c635efSGarrett D'Amore if (savelit) 71395c635efSGarrett D'Amore mt->fl |= MANT_LITERAL; 714371584c2SYuri Pankov return 0; 715371584c2SYuri Pankov case ROFFT_BODY: 71695c635efSGarrett D'Amore p->offset = mt->offset + len; 71795c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 718698f87a4SGarrett D'Amore p->trailspace = 0; 719371584c2SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP); 72095c635efSGarrett D'Amore break; 72195c635efSGarrett D'Amore default: 72295c635efSGarrett D'Amore break; 72395c635efSGarrett D'Amore } 72495c635efSGarrett D'Amore 725371584c2SYuri Pankov return 1; 72695c635efSGarrett D'Amore } 72795c635efSGarrett D'Amore 72895c635efSGarrett D'Amore static void 72995c635efSGarrett D'Amore post_TP(DECL_ARGS) 73095c635efSGarrett D'Amore { 73195c635efSGarrett D'Amore 73295c635efSGarrett D'Amore switch (n->type) { 733371584c2SYuri Pankov case ROFFT_HEAD: 73495c635efSGarrett D'Amore term_flushln(p); 73595c635efSGarrett D'Amore break; 736371584c2SYuri Pankov case ROFFT_BODY: 73795c635efSGarrett D'Amore term_newln(p); 738698f87a4SGarrett D'Amore p->offset = mt->offset; 73995c635efSGarrett D'Amore break; 74095c635efSGarrett D'Amore default: 74195c635efSGarrett D'Amore break; 74295c635efSGarrett D'Amore } 74395c635efSGarrett D'Amore } 74495c635efSGarrett D'Amore 74595c635efSGarrett D'Amore static int 74695c635efSGarrett D'Amore pre_SS(DECL_ARGS) 74795c635efSGarrett D'Amore { 748698f87a4SGarrett D'Amore int i; 74995c635efSGarrett D'Amore 75095c635efSGarrett D'Amore switch (n->type) { 751371584c2SYuri Pankov case ROFFT_BLOCK: 75295c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 75395c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 75495c635efSGarrett D'Amore mt->offset = term_len(p, p->defindent); 755260e9a87SYuri Pankov 756260e9a87SYuri Pankov /* 757260e9a87SYuri Pankov * No vertical space before the first subsection 758260e9a87SYuri Pankov * and after an empty subsection. 759260e9a87SYuri Pankov */ 760260e9a87SYuri Pankov 761260e9a87SYuri Pankov do { 762260e9a87SYuri Pankov n = n->prev; 763371584c2SYuri Pankov } while (n != NULL && n->tok != TOKEN_NONE && 764371584c2SYuri Pankov termacts[n->tok].flags & MAN_NOTEXT); 765260e9a87SYuri Pankov if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL)) 76695c635efSGarrett D'Amore break; 767260e9a87SYuri Pankov 768698f87a4SGarrett D'Amore for (i = 0; i < mt->pardist; i++) 76995c635efSGarrett D'Amore term_vspace(p); 77095c635efSGarrett D'Amore break; 771371584c2SYuri Pankov case ROFFT_HEAD: 77295c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 773698f87a4SGarrett D'Amore p->offset = term_len(p, 3); 774371584c2SYuri Pankov p->rmargin = mt->offset; 775371584c2SYuri Pankov p->trailspace = mt->offset; 776371584c2SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND; 77795c635efSGarrett D'Amore break; 778371584c2SYuri Pankov case ROFFT_BODY: 77995c635efSGarrett D'Amore p->offset = mt->offset; 780371584c2SYuri Pankov p->rmargin = p->maxrmargin; 781371584c2SYuri Pankov p->trailspace = 0; 782371584c2SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 78395c635efSGarrett D'Amore break; 78495c635efSGarrett D'Amore default: 78595c635efSGarrett D'Amore break; 78695c635efSGarrett D'Amore } 78795c635efSGarrett D'Amore 788371584c2SYuri Pankov return 1; 78995c635efSGarrett D'Amore } 79095c635efSGarrett D'Amore 79195c635efSGarrett D'Amore static void 79295c635efSGarrett D'Amore post_SS(DECL_ARGS) 79395c635efSGarrett D'Amore { 79495c635efSGarrett D'Amore 79595c635efSGarrett D'Amore switch (n->type) { 796371584c2SYuri Pankov case ROFFT_HEAD: 79795c635efSGarrett D'Amore term_newln(p); 79895c635efSGarrett D'Amore break; 799371584c2SYuri Pankov case ROFFT_BODY: 80095c635efSGarrett D'Amore term_newln(p); 80195c635efSGarrett D'Amore break; 80295c635efSGarrett D'Amore default: 80395c635efSGarrett D'Amore break; 80495c635efSGarrett D'Amore } 80595c635efSGarrett D'Amore } 80695c635efSGarrett D'Amore 80795c635efSGarrett D'Amore static int 80895c635efSGarrett D'Amore pre_SH(DECL_ARGS) 80995c635efSGarrett D'Amore { 810698f87a4SGarrett D'Amore int i; 81195c635efSGarrett D'Amore 81295c635efSGarrett D'Amore switch (n->type) { 813371584c2SYuri Pankov case ROFFT_BLOCK: 81495c635efSGarrett D'Amore mt->fl &= ~MANT_LITERAL; 81595c635efSGarrett D'Amore mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 81695c635efSGarrett D'Amore mt->offset = term_len(p, p->defindent); 817260e9a87SYuri Pankov 818260e9a87SYuri Pankov /* 819260e9a87SYuri Pankov * No vertical space before the first section 820260e9a87SYuri Pankov * and after an empty section. 821260e9a87SYuri Pankov */ 822260e9a87SYuri Pankov 823260e9a87SYuri Pankov do { 824260e9a87SYuri Pankov n = n->prev; 825*a40ea1a7SYuri Pankov } while (n != NULL && n->tok != TOKEN_NONE && 826*a40ea1a7SYuri Pankov termacts[n->tok].flags & MAN_NOTEXT); 827260e9a87SYuri Pankov if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL)) 82895c635efSGarrett D'Amore break; 829260e9a87SYuri Pankov 830698f87a4SGarrett D'Amore for (i = 0; i < mt->pardist; i++) 83195c635efSGarrett D'Amore term_vspace(p); 83295c635efSGarrett D'Amore break; 833371584c2SYuri Pankov case ROFFT_HEAD: 83495c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_BOLD); 83595c635efSGarrett D'Amore p->offset = 0; 836371584c2SYuri Pankov p->rmargin = mt->offset; 837371584c2SYuri Pankov p->trailspace = mt->offset; 838371584c2SYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND; 83995c635efSGarrett D'Amore break; 840371584c2SYuri Pankov case ROFFT_BODY: 84195c635efSGarrett D'Amore p->offset = mt->offset; 842371584c2SYuri Pankov p->rmargin = p->maxrmargin; 843371584c2SYuri Pankov p->trailspace = 0; 844371584c2SYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 84595c635efSGarrett D'Amore break; 84695c635efSGarrett D'Amore default: 84795c635efSGarrett D'Amore break; 84895c635efSGarrett D'Amore } 84995c635efSGarrett D'Amore 850371584c2SYuri Pankov return 1; 85195c635efSGarrett D'Amore } 85295c635efSGarrett D'Amore 85395c635efSGarrett D'Amore static void 85495c635efSGarrett D'Amore post_SH(DECL_ARGS) 85595c635efSGarrett D'Amore { 85695c635efSGarrett D'Amore 85795c635efSGarrett D'Amore switch (n->type) { 858371584c2SYuri Pankov case ROFFT_HEAD: 85995c635efSGarrett D'Amore term_newln(p); 86095c635efSGarrett D'Amore break; 861371584c2SYuri Pankov case ROFFT_BODY: 86295c635efSGarrett D'Amore term_newln(p); 86395c635efSGarrett D'Amore break; 86495c635efSGarrett D'Amore default: 86595c635efSGarrett D'Amore break; 86695c635efSGarrett D'Amore } 86795c635efSGarrett D'Amore } 86895c635efSGarrett D'Amore 86995c635efSGarrett D'Amore static int 87095c635efSGarrett D'Amore pre_RS(DECL_ARGS) 87195c635efSGarrett D'Amore { 872260e9a87SYuri Pankov struct roffsu su; 87395c635efSGarrett D'Amore 87495c635efSGarrett D'Amore switch (n->type) { 875371584c2SYuri Pankov case ROFFT_BLOCK: 87695c635efSGarrett D'Amore term_newln(p); 877371584c2SYuri Pankov return 1; 878371584c2SYuri Pankov case ROFFT_HEAD: 879371584c2SYuri Pankov return 0; 88095c635efSGarrett D'Amore default: 88195c635efSGarrett D'Amore break; 88295c635efSGarrett D'Amore } 88395c635efSGarrett D'Amore 884260e9a87SYuri Pankov n = n->parent->head; 885260e9a87SYuri Pankov n->aux = SHRT_MAX + 1; 886371584c2SYuri Pankov if (n->child == NULL) 887371584c2SYuri Pankov n->aux = mt->lmargin[mt->lmargincur]; 888371584c2SYuri Pankov else if (a2roffsu(n->child->string, &su, SCALE_EN)) 889371584c2SYuri Pankov n->aux = term_hspan(p, &su) / 24; 890260e9a87SYuri Pankov if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) 891260e9a87SYuri Pankov n->aux = -mt->offset; 892260e9a87SYuri Pankov else if (n->aux > SHRT_MAX) 893260e9a87SYuri Pankov n->aux = term_len(p, p->defindent); 89495c635efSGarrett D'Amore 895260e9a87SYuri Pankov mt->offset += n->aux; 896260e9a87SYuri Pankov p->offset = mt->offset; 89795c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 89895c635efSGarrett D'Amore 89995c635efSGarrett D'Amore if (++mt->lmarginsz < MAXMARGINS) 90095c635efSGarrett D'Amore mt->lmargincur = mt->lmarginsz; 90195c635efSGarrett D'Amore 902371584c2SYuri Pankov mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 903371584c2SYuri Pankov return 1; 90495c635efSGarrett D'Amore } 90595c635efSGarrett D'Amore 90695c635efSGarrett D'Amore static void 90795c635efSGarrett D'Amore post_RS(DECL_ARGS) 90895c635efSGarrett D'Amore { 90995c635efSGarrett D'Amore 91095c635efSGarrett D'Amore switch (n->type) { 911371584c2SYuri Pankov case ROFFT_BLOCK: 91295c635efSGarrett D'Amore return; 913371584c2SYuri Pankov case ROFFT_HEAD: 91495c635efSGarrett D'Amore return; 91595c635efSGarrett D'Amore default: 91695c635efSGarrett D'Amore term_newln(p); 91795c635efSGarrett D'Amore break; 91895c635efSGarrett D'Amore } 91995c635efSGarrett D'Amore 920260e9a87SYuri Pankov mt->offset -= n->parent->head->aux; 92195c635efSGarrett D'Amore p->offset = mt->offset; 92295c635efSGarrett D'Amore 92395c635efSGarrett D'Amore if (--mt->lmarginsz < MAXMARGINS) 92495c635efSGarrett D'Amore mt->lmargincur = mt->lmarginsz; 92595c635efSGarrett D'Amore } 92695c635efSGarrett D'Amore 927698f87a4SGarrett D'Amore static int 928698f87a4SGarrett D'Amore pre_UR(DECL_ARGS) 929698f87a4SGarrett D'Amore { 930698f87a4SGarrett D'Amore 931371584c2SYuri Pankov return n->type != ROFFT_HEAD; 932698f87a4SGarrett D'Amore } 933698f87a4SGarrett D'Amore 934698f87a4SGarrett D'Amore static void 935698f87a4SGarrett D'Amore post_UR(DECL_ARGS) 936698f87a4SGarrett D'Amore { 937698f87a4SGarrett D'Amore 938371584c2SYuri Pankov if (n->type != ROFFT_BLOCK) 939698f87a4SGarrett D'Amore return; 940698f87a4SGarrett D'Amore 941698f87a4SGarrett D'Amore term_word(p, "<"); 942698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 943698f87a4SGarrett D'Amore 944698f87a4SGarrett D'Amore if (NULL != n->child->child) 945698f87a4SGarrett D'Amore print_man_node(p, mt, n->child->child, meta); 946698f87a4SGarrett D'Amore 947698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 948698f87a4SGarrett D'Amore term_word(p, ">"); 949698f87a4SGarrett D'Amore } 950698f87a4SGarrett D'Amore 95195c635efSGarrett D'Amore static void 95295c635efSGarrett D'Amore print_man_node(DECL_ARGS) 95395c635efSGarrett D'Amore { 95495c635efSGarrett D'Amore size_t rm, rmax; 95595c635efSGarrett D'Amore int c; 95695c635efSGarrett D'Amore 95795c635efSGarrett D'Amore switch (n->type) { 958371584c2SYuri Pankov case ROFFT_TEXT: 95995c635efSGarrett D'Amore /* 96095c635efSGarrett D'Amore * If we have a blank line, output a vertical space. 96195c635efSGarrett D'Amore * If we have a space as the first character, break 96295c635efSGarrett D'Amore * before printing the line's data. 96395c635efSGarrett D'Amore */ 96495c635efSGarrett D'Amore if ('\0' == *n->string) { 96595c635efSGarrett D'Amore term_vspace(p); 96695c635efSGarrett D'Amore return; 967*a40ea1a7SYuri Pankov } else if (' ' == *n->string && NODE_LINE & n->flags) 96895c635efSGarrett D'Amore term_newln(p); 96995c635efSGarrett D'Amore 97095c635efSGarrett D'Amore term_word(p, n->string); 971698f87a4SGarrett D'Amore goto out; 97295c635efSGarrett D'Amore 973371584c2SYuri Pankov case ROFFT_EQN: 974*a40ea1a7SYuri Pankov if ( ! (n->flags & NODE_LINE)) 975260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 97695c635efSGarrett D'Amore term_eqn(p, n->eqn); 977*a40ea1a7SYuri Pankov if (n->next != NULL && ! (n->next->flags & NODE_LINE)) 978260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 97995c635efSGarrett D'Amore return; 980371584c2SYuri Pankov case ROFFT_TBL: 981260e9a87SYuri Pankov if (p->tbl.cols == NULL) 982260e9a87SYuri Pankov term_vspace(p); 98395c635efSGarrett D'Amore term_tbl(p, n->span); 98495c635efSGarrett D'Amore return; 98595c635efSGarrett D'Amore default: 98695c635efSGarrett D'Amore break; 98795c635efSGarrett D'Amore } 98895c635efSGarrett D'Amore 98995c635efSGarrett D'Amore if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) 99095c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 99195c635efSGarrett D'Amore 99295c635efSGarrett D'Amore c = 1; 99395c635efSGarrett D'Amore if (termacts[n->tok].pre) 994698f87a4SGarrett D'Amore c = (*termacts[n->tok].pre)(p, mt, n, meta); 99595c635efSGarrett D'Amore 99695c635efSGarrett D'Amore if (c && n->child) 997698f87a4SGarrett D'Amore print_man_nodelist(p, mt, n->child, meta); 99895c635efSGarrett D'Amore 99995c635efSGarrett D'Amore if (termacts[n->tok].post) 1000698f87a4SGarrett D'Amore (*termacts[n->tok].post)(p, mt, n, meta); 100195c635efSGarrett D'Amore if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) 100295c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 100395c635efSGarrett D'Amore 1004698f87a4SGarrett D'Amore out: 1005698f87a4SGarrett D'Amore /* 1006698f87a4SGarrett D'Amore * If we're in a literal context, make sure that words 1007698f87a4SGarrett D'Amore * together on the same line stay together. This is a 1008698f87a4SGarrett D'Amore * POST-printing call, so we check the NEXT word. Since 1009698f87a4SGarrett D'Amore * -man doesn't have nested macros, we don't need to be 1010698f87a4SGarrett D'Amore * more specific than this. 1011698f87a4SGarrett D'Amore */ 1012260e9a87SYuri Pankov if (mt->fl & MANT_LITERAL && 1013260e9a87SYuri Pankov ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && 1014*a40ea1a7SYuri Pankov (n->next == NULL || n->next->flags & NODE_LINE)) { 1015698f87a4SGarrett D'Amore rm = p->rmargin; 1016698f87a4SGarrett D'Amore rmax = p->maxrmargin; 1017698f87a4SGarrett D'Amore p->rmargin = p->maxrmargin = TERM_MAXMARGIN; 1018698f87a4SGarrett D'Amore p->flags |= TERMP_NOSPACE; 1019260e9a87SYuri Pankov if (n->string != NULL && *n->string != '\0') 1020698f87a4SGarrett D'Amore term_flushln(p); 1021698f87a4SGarrett D'Amore else 1022698f87a4SGarrett D'Amore term_newln(p); 1023698f87a4SGarrett D'Amore if (rm < rmax && n->parent->tok == MAN_HP) { 1024698f87a4SGarrett D'Amore p->offset = rm; 1025698f87a4SGarrett D'Amore p->rmargin = rmax; 1026698f87a4SGarrett D'Amore } else 1027698f87a4SGarrett D'Amore p->rmargin = rm; 1028698f87a4SGarrett D'Amore p->maxrmargin = rmax; 1029698f87a4SGarrett D'Amore } 1030*a40ea1a7SYuri Pankov if (NODE_EOS & n->flags) 103195c635efSGarrett D'Amore p->flags |= TERMP_SENTENCE; 103295c635efSGarrett D'Amore } 103395c635efSGarrett D'Amore 103495c635efSGarrett D'Amore 103595c635efSGarrett D'Amore static void 103695c635efSGarrett D'Amore print_man_nodelist(DECL_ARGS) 103795c635efSGarrett D'Amore { 103895c635efSGarrett D'Amore 1039260e9a87SYuri Pankov while (n != NULL) { 1040698f87a4SGarrett D'Amore print_man_node(p, mt, n, meta); 1041260e9a87SYuri Pankov n = n->next; 104295c635efSGarrett D'Amore } 1043260e9a87SYuri Pankov } 104495c635efSGarrett D'Amore 104595c635efSGarrett D'Amore static void 1046371584c2SYuri Pankov print_man_foot(struct termp *p, const struct roff_meta *meta) 104795c635efSGarrett D'Amore { 1048260e9a87SYuri Pankov char *title; 1049260e9a87SYuri Pankov size_t datelen, titlen; 105095c635efSGarrett D'Amore 105195c635efSGarrett D'Amore assert(meta->title); 105295c635efSGarrett D'Amore assert(meta->msec); 105395c635efSGarrett D'Amore assert(meta->date); 105495c635efSGarrett D'Amore 105595c635efSGarrett D'Amore term_fontrepl(p, TERMFONT_NONE); 105695c635efSGarrett D'Amore 1057260e9a87SYuri Pankov if (meta->hasbody) 105895c635efSGarrett D'Amore term_vspace(p); 105995c635efSGarrett D'Amore 106095c635efSGarrett D'Amore /* 106195c635efSGarrett D'Amore * Temporary, undocumented option to imitate mdoc(7) output. 1062371584c2SYuri Pankov * In the bottom right corner, use the operating system 1063371584c2SYuri Pankov * instead of the title. 106495c635efSGarrett D'Amore */ 106595c635efSGarrett D'Amore 106695c635efSGarrett D'Amore if ( ! p->mdocstyle) { 1067260e9a87SYuri Pankov if (meta->hasbody) { 106895c635efSGarrett D'Amore term_vspace(p); 106995c635efSGarrett D'Amore term_vspace(p); 1070260e9a87SYuri Pankov } 1071260e9a87SYuri Pankov mandoc_asprintf(&title, "%s(%s)", 1072260e9a87SYuri Pankov meta->title, meta->msec); 1073371584c2SYuri Pankov } else if (meta->os) { 1074371584c2SYuri Pankov title = mandoc_strdup(meta->os); 107595c635efSGarrett D'Amore } else { 1076260e9a87SYuri Pankov title = mandoc_strdup(""); 107795c635efSGarrett D'Amore } 107895c635efSGarrett D'Amore datelen = term_strlen(p, meta->date); 107995c635efSGarrett D'Amore 1080371584c2SYuri Pankov /* Bottom left corner: operating system. */ 108195c635efSGarrett D'Amore 108295c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 1083698f87a4SGarrett D'Amore p->trailspace = 1; 108495c635efSGarrett D'Amore p->offset = 0; 1085260e9a87SYuri Pankov p->rmargin = p->maxrmargin > datelen ? 1086260e9a87SYuri Pankov (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; 108795c635efSGarrett D'Amore 1088371584c2SYuri Pankov if (meta->os) 1089371584c2SYuri Pankov term_word(p, meta->os); 109095c635efSGarrett D'Amore term_flushln(p); 109195c635efSGarrett D'Amore 109295c635efSGarrett D'Amore /* At the bottom in the middle: manual date. */ 109395c635efSGarrett D'Amore 109495c635efSGarrett D'Amore p->offset = p->rmargin; 1095260e9a87SYuri Pankov titlen = term_strlen(p, title); 1096260e9a87SYuri Pankov p->rmargin = p->maxrmargin > titlen ? p->maxrmargin - titlen : 0; 1097260e9a87SYuri Pankov p->flags |= TERMP_NOSPACE; 109895c635efSGarrett D'Amore 109995c635efSGarrett D'Amore term_word(p, meta->date); 110095c635efSGarrett D'Amore term_flushln(p); 110195c635efSGarrett D'Amore 110295c635efSGarrett D'Amore /* Bottom right corner: manual title and section. */ 110395c635efSGarrett D'Amore 110495c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 110595c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 1106698f87a4SGarrett D'Amore p->trailspace = 0; 110795c635efSGarrett D'Amore p->offset = p->rmargin; 110895c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 110995c635efSGarrett D'Amore 111095c635efSGarrett D'Amore term_word(p, title); 111195c635efSGarrett D'Amore term_flushln(p); 1112260e9a87SYuri Pankov free(title); 111395c635efSGarrett D'Amore } 111495c635efSGarrett D'Amore 111595c635efSGarrett D'Amore static void 1116371584c2SYuri Pankov print_man_head(struct termp *p, const struct roff_meta *meta) 111795c635efSGarrett D'Amore { 1118260e9a87SYuri Pankov const char *volume; 1119260e9a87SYuri Pankov char *title; 1120260e9a87SYuri Pankov size_t vollen, titlen; 112195c635efSGarrett D'Amore 1122698f87a4SGarrett D'Amore assert(meta->title); 1123698f87a4SGarrett D'Amore assert(meta->msec); 112495c635efSGarrett D'Amore 1125260e9a87SYuri Pankov volume = NULL == meta->vol ? "" : meta->vol; 1126260e9a87SYuri Pankov vollen = term_strlen(p, volume); 112795c635efSGarrett D'Amore 112895c635efSGarrett D'Amore /* Top left corner: manual title and section. */ 112995c635efSGarrett D'Amore 1130260e9a87SYuri Pankov mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); 113195c635efSGarrett D'Amore titlen = term_strlen(p, title); 113295c635efSGarrett D'Amore 113395c635efSGarrett D'Amore p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; 1134698f87a4SGarrett D'Amore p->trailspace = 1; 113595c635efSGarrett D'Amore p->offset = 0; 1136260e9a87SYuri Pankov p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? 1137260e9a87SYuri Pankov (p->maxrmargin - vollen + term_len(p, 1)) / 2 : 1138260e9a87SYuri Pankov vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; 113995c635efSGarrett D'Amore 114095c635efSGarrett D'Amore term_word(p, title); 114195c635efSGarrett D'Amore term_flushln(p); 114295c635efSGarrett D'Amore 114395c635efSGarrett D'Amore /* At the top in the middle: manual volume. */ 114495c635efSGarrett D'Amore 114595c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 114695c635efSGarrett D'Amore p->offset = p->rmargin; 1147260e9a87SYuri Pankov p->rmargin = p->offset + vollen + titlen < p->maxrmargin ? 114895c635efSGarrett D'Amore p->maxrmargin - titlen : p->maxrmargin; 114995c635efSGarrett D'Amore 1150260e9a87SYuri Pankov term_word(p, volume); 115195c635efSGarrett D'Amore term_flushln(p); 115295c635efSGarrett D'Amore 115395c635efSGarrett D'Amore /* Top right corner: title and section, again. */ 115495c635efSGarrett D'Amore 115595c635efSGarrett D'Amore p->flags &= ~TERMP_NOBREAK; 1156698f87a4SGarrett D'Amore p->trailspace = 0; 115795c635efSGarrett D'Amore if (p->rmargin + titlen <= p->maxrmargin) { 115895c635efSGarrett D'Amore p->flags |= TERMP_NOSPACE; 115995c635efSGarrett D'Amore p->offset = p->rmargin; 116095c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 116195c635efSGarrett D'Amore term_word(p, title); 116295c635efSGarrett D'Amore term_flushln(p); 116395c635efSGarrett D'Amore } 116495c635efSGarrett D'Amore 116595c635efSGarrett D'Amore p->flags &= ~TERMP_NOSPACE; 116695c635efSGarrett D'Amore p->offset = 0; 116795c635efSGarrett D'Amore p->rmargin = p->maxrmargin; 116895c635efSGarrett D'Amore 116995c635efSGarrett D'Amore /* 117095c635efSGarrett D'Amore * Groff prints three blank lines before the content. 117195c635efSGarrett D'Amore * Do the same, except in the temporary, undocumented 117295c635efSGarrett D'Amore * mode imitating mdoc(7) output. 117395c635efSGarrett D'Amore */ 117495c635efSGarrett D'Amore 117595c635efSGarrett D'Amore term_vspace(p); 117695c635efSGarrett D'Amore if ( ! p->mdocstyle) { 117795c635efSGarrett D'Amore term_vspace(p); 117895c635efSGarrett D'Amore term_vspace(p); 117995c635efSGarrett D'Amore } 1180260e9a87SYuri Pankov free(title); 118195c635efSGarrett D'Amore } 1182