1*7295610fSBaptiste Daroussin /* $Id: man_term.c,v 1.228 2019/01/05 21:18:26 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 361d06d6bSBaptiste Daroussin * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4*7295610fSBaptiste Daroussin * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org> 561d06d6bSBaptiste Daroussin * 661d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 761d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 861d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 961d06d6bSBaptiste Daroussin * 1061d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1161d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1261d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 1361d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1461d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1561d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1661d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1761d06d6bSBaptiste Daroussin */ 1861d06d6bSBaptiste Daroussin #include "config.h" 1961d06d6bSBaptiste Daroussin 2061d06d6bSBaptiste Daroussin #include <sys/types.h> 2161d06d6bSBaptiste Daroussin 2261d06d6bSBaptiste Daroussin #include <assert.h> 2361d06d6bSBaptiste Daroussin #include <ctype.h> 2461d06d6bSBaptiste Daroussin #include <limits.h> 2561d06d6bSBaptiste Daroussin #include <stdio.h> 2661d06d6bSBaptiste Daroussin #include <stdlib.h> 2761d06d6bSBaptiste Daroussin #include <string.h> 2861d06d6bSBaptiste Daroussin 2961d06d6bSBaptiste Daroussin #include "mandoc_aux.h" 3061d06d6bSBaptiste Daroussin #include "roff.h" 3161d06d6bSBaptiste Daroussin #include "man.h" 3261d06d6bSBaptiste Daroussin #include "out.h" 3361d06d6bSBaptiste Daroussin #include "term.h" 3461d06d6bSBaptiste Daroussin #include "main.h" 3561d06d6bSBaptiste Daroussin 3661d06d6bSBaptiste Daroussin #define MAXMARGINS 64 /* maximum number of indented scopes */ 3761d06d6bSBaptiste Daroussin 3861d06d6bSBaptiste Daroussin struct mtermp { 3961d06d6bSBaptiste Daroussin int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */ 4061d06d6bSBaptiste Daroussin int lmargincur; /* index of current margin */ 4161d06d6bSBaptiste Daroussin int lmarginsz; /* actual number of nested margins */ 4261d06d6bSBaptiste Daroussin size_t offset; /* default offset to visible page */ 4361d06d6bSBaptiste Daroussin int pardist; /* vert. space before par., unit: [v] */ 4461d06d6bSBaptiste Daroussin }; 4561d06d6bSBaptiste Daroussin 4661d06d6bSBaptiste Daroussin #define DECL_ARGS struct termp *p, \ 4761d06d6bSBaptiste Daroussin struct mtermp *mt, \ 4861d06d6bSBaptiste Daroussin struct roff_node *n, \ 4961d06d6bSBaptiste Daroussin const struct roff_meta *meta 5061d06d6bSBaptiste Daroussin 51*7295610fSBaptiste Daroussin struct man_term_act { 5261d06d6bSBaptiste Daroussin int (*pre)(DECL_ARGS); 5361d06d6bSBaptiste Daroussin void (*post)(DECL_ARGS); 5461d06d6bSBaptiste Daroussin int flags; 5561d06d6bSBaptiste Daroussin #define MAN_NOTEXT (1 << 0) /* Never has text children. */ 5661d06d6bSBaptiste Daroussin }; 5761d06d6bSBaptiste Daroussin 5861d06d6bSBaptiste Daroussin static void print_man_nodelist(DECL_ARGS); 5961d06d6bSBaptiste Daroussin static void print_man_node(DECL_ARGS); 6061d06d6bSBaptiste Daroussin static void print_man_head(struct termp *, 6161d06d6bSBaptiste Daroussin const struct roff_meta *); 6261d06d6bSBaptiste Daroussin static void print_man_foot(struct termp *, 6361d06d6bSBaptiste Daroussin const struct roff_meta *); 6461d06d6bSBaptiste Daroussin static void print_bvspace(struct termp *, 6561d06d6bSBaptiste Daroussin const struct roff_node *, int); 6661d06d6bSBaptiste Daroussin 6761d06d6bSBaptiste Daroussin static int pre_B(DECL_ARGS); 6861d06d6bSBaptiste Daroussin static int pre_DT(DECL_ARGS); 6961d06d6bSBaptiste Daroussin static int pre_HP(DECL_ARGS); 7061d06d6bSBaptiste Daroussin static int pre_I(DECL_ARGS); 7161d06d6bSBaptiste Daroussin static int pre_IP(DECL_ARGS); 7261d06d6bSBaptiste Daroussin static int pre_OP(DECL_ARGS); 7361d06d6bSBaptiste Daroussin static int pre_PD(DECL_ARGS); 7461d06d6bSBaptiste Daroussin static int pre_PP(DECL_ARGS); 7561d06d6bSBaptiste Daroussin static int pre_RS(DECL_ARGS); 7661d06d6bSBaptiste Daroussin static int pre_SH(DECL_ARGS); 7761d06d6bSBaptiste Daroussin static int pre_SS(DECL_ARGS); 78*7295610fSBaptiste Daroussin static int pre_SY(DECL_ARGS); 7961d06d6bSBaptiste Daroussin static int pre_TP(DECL_ARGS); 8061d06d6bSBaptiste Daroussin static int pre_UR(DECL_ARGS); 81*7295610fSBaptiste Daroussin static int pre_abort(DECL_ARGS); 8261d06d6bSBaptiste Daroussin static int pre_alternate(DECL_ARGS); 8361d06d6bSBaptiste Daroussin static int pre_ign(DECL_ARGS); 8461d06d6bSBaptiste Daroussin static int pre_in(DECL_ARGS); 8561d06d6bSBaptiste Daroussin static int pre_literal(DECL_ARGS); 8661d06d6bSBaptiste Daroussin 8761d06d6bSBaptiste Daroussin static void post_IP(DECL_ARGS); 8861d06d6bSBaptiste Daroussin static void post_HP(DECL_ARGS); 8961d06d6bSBaptiste Daroussin static void post_RS(DECL_ARGS); 9061d06d6bSBaptiste Daroussin static void post_SH(DECL_ARGS); 91*7295610fSBaptiste Daroussin static void post_SY(DECL_ARGS); 9261d06d6bSBaptiste Daroussin static void post_TP(DECL_ARGS); 9361d06d6bSBaptiste Daroussin static void post_UR(DECL_ARGS); 9461d06d6bSBaptiste Daroussin 95*7295610fSBaptiste Daroussin static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = { 9661d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* TH */ 9761d06d6bSBaptiste Daroussin { pre_SH, post_SH, 0 }, /* SH */ 98*7295610fSBaptiste Daroussin { pre_SS, post_SH, 0 }, /* SS */ 9961d06d6bSBaptiste Daroussin { pre_TP, post_TP, 0 }, /* TP */ 100*7295610fSBaptiste Daroussin { pre_TP, post_TP, 0 }, /* TQ */ 101*7295610fSBaptiste Daroussin { pre_abort, NULL, 0 }, /* LP */ 10261d06d6bSBaptiste Daroussin { pre_PP, NULL, 0 }, /* PP */ 103*7295610fSBaptiste Daroussin { pre_abort, NULL, 0 }, /* P */ 10461d06d6bSBaptiste Daroussin { pre_IP, post_IP, 0 }, /* IP */ 10561d06d6bSBaptiste Daroussin { pre_HP, post_HP, 0 }, /* HP */ 10661d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* SM */ 10761d06d6bSBaptiste Daroussin { pre_B, NULL, 0 }, /* SB */ 10861d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* BI */ 10961d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* IB */ 11061d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* BR */ 11161d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* RB */ 11261d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* R */ 11361d06d6bSBaptiste Daroussin { pre_B, NULL, 0 }, /* B */ 11461d06d6bSBaptiste Daroussin { pre_I, NULL, 0 }, /* I */ 11561d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* IR */ 11661d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* RI */ 11761d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* RE */ 11861d06d6bSBaptiste Daroussin { pre_RS, post_RS, 0 }, /* RS */ 11961d06d6bSBaptiste Daroussin { pre_DT, NULL, 0 }, /* DT */ 12061d06d6bSBaptiste Daroussin { pre_ign, NULL, MAN_NOTEXT }, /* UC */ 12161d06d6bSBaptiste Daroussin { pre_PD, NULL, MAN_NOTEXT }, /* PD */ 12261d06d6bSBaptiste Daroussin { pre_ign, NULL, 0 }, /* AT */ 12361d06d6bSBaptiste Daroussin { pre_in, NULL, MAN_NOTEXT }, /* in */ 124*7295610fSBaptiste Daroussin { pre_SY, post_SY, 0 }, /* SY */ 125*7295610fSBaptiste Daroussin { NULL, NULL, 0 }, /* YS */ 12661d06d6bSBaptiste Daroussin { pre_OP, NULL, 0 }, /* OP */ 12761d06d6bSBaptiste Daroussin { pre_literal, NULL, 0 }, /* EX */ 12861d06d6bSBaptiste Daroussin { pre_literal, NULL, 0 }, /* EE */ 12961d06d6bSBaptiste Daroussin { pre_UR, post_UR, 0 }, /* UR */ 13061d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* UE */ 13161d06d6bSBaptiste Daroussin { pre_UR, post_UR, 0 }, /* MT */ 13261d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* ME */ 13361d06d6bSBaptiste Daroussin }; 134*7295610fSBaptiste Daroussin static const struct man_term_act *man_term_act(enum roff_tok); 13561d06d6bSBaptiste Daroussin 13661d06d6bSBaptiste Daroussin 137*7295610fSBaptiste Daroussin static const struct man_term_act * 138*7295610fSBaptiste Daroussin man_term_act(enum roff_tok tok) 139*7295610fSBaptiste Daroussin { 140*7295610fSBaptiste Daroussin assert(tok >= MAN_TH && tok <= MAN_MAX); 141*7295610fSBaptiste Daroussin return man_term_acts + (tok - MAN_TH); 142*7295610fSBaptiste Daroussin } 143*7295610fSBaptiste Daroussin 14461d06d6bSBaptiste Daroussin void 145*7295610fSBaptiste Daroussin terminal_man(void *arg, const struct roff_meta *man) 14661d06d6bSBaptiste Daroussin { 147*7295610fSBaptiste Daroussin struct mtermp mt; 14861d06d6bSBaptiste Daroussin struct termp *p; 14961d06d6bSBaptiste Daroussin struct roff_node *n; 15061d06d6bSBaptiste Daroussin size_t save_defindent; 15161d06d6bSBaptiste Daroussin 15261d06d6bSBaptiste Daroussin p = (struct termp *)arg; 15361d06d6bSBaptiste Daroussin save_defindent = p->defindent; 15461d06d6bSBaptiste Daroussin if (p->synopsisonly == 0 && p->defindent == 0) 15561d06d6bSBaptiste Daroussin p->defindent = 7; 15661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin = p->defrmargin; 15761d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 15861d06d6bSBaptiste Daroussin term_tab_set(p, "T"); 15961d06d6bSBaptiste Daroussin term_tab_set(p, ".5i"); 16061d06d6bSBaptiste Daroussin 161*7295610fSBaptiste Daroussin memset(&mt, 0, sizeof(mt)); 16261d06d6bSBaptiste Daroussin mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); 16361d06d6bSBaptiste Daroussin mt.offset = term_len(p, p->defindent); 16461d06d6bSBaptiste Daroussin mt.pardist = 1; 16561d06d6bSBaptiste Daroussin 16661d06d6bSBaptiste Daroussin n = man->first->child; 16761d06d6bSBaptiste Daroussin if (p->synopsisonly) { 16861d06d6bSBaptiste Daroussin while (n != NULL) { 16961d06d6bSBaptiste Daroussin if (n->tok == MAN_SH && 17061d06d6bSBaptiste Daroussin n->child->child->type == ROFFT_TEXT && 17161d06d6bSBaptiste Daroussin !strcmp(n->child->child->string, "SYNOPSIS")) { 17261d06d6bSBaptiste Daroussin if (n->child->next->child != NULL) 17361d06d6bSBaptiste Daroussin print_man_nodelist(p, &mt, 174*7295610fSBaptiste Daroussin n->child->next->child, man); 17561d06d6bSBaptiste Daroussin term_newln(p); 17661d06d6bSBaptiste Daroussin break; 17761d06d6bSBaptiste Daroussin } 17861d06d6bSBaptiste Daroussin n = n->next; 17961d06d6bSBaptiste Daroussin } 18061d06d6bSBaptiste Daroussin } else { 181*7295610fSBaptiste Daroussin term_begin(p, print_man_head, print_man_foot, man); 18261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 18361d06d6bSBaptiste Daroussin if (n != NULL) 184*7295610fSBaptiste Daroussin print_man_nodelist(p, &mt, n, man); 18561d06d6bSBaptiste Daroussin term_end(p); 18661d06d6bSBaptiste Daroussin } 18761d06d6bSBaptiste Daroussin p->defindent = save_defindent; 18861d06d6bSBaptiste Daroussin } 18961d06d6bSBaptiste Daroussin 19061d06d6bSBaptiste Daroussin /* 19161d06d6bSBaptiste Daroussin * Printing leading vertical space before a block. 19261d06d6bSBaptiste Daroussin * This is used for the paragraph macros. 19361d06d6bSBaptiste Daroussin * The rules are pretty simple, since there's very little nesting going 19461d06d6bSBaptiste Daroussin * on here. Basically, if we're the first within another block (SS/SH), 19561d06d6bSBaptiste Daroussin * then don't emit vertical space. If we are (RS), then do. If not the 19661d06d6bSBaptiste Daroussin * first, print it. 19761d06d6bSBaptiste Daroussin */ 19861d06d6bSBaptiste Daroussin static void 19961d06d6bSBaptiste Daroussin print_bvspace(struct termp *p, const struct roff_node *n, int pardist) 20061d06d6bSBaptiste Daroussin { 20161d06d6bSBaptiste Daroussin int i; 20261d06d6bSBaptiste Daroussin 20361d06d6bSBaptiste Daroussin term_newln(p); 20461d06d6bSBaptiste Daroussin 205*7295610fSBaptiste Daroussin if (n->body != NULL && n->body->child != NULL) 20661d06d6bSBaptiste Daroussin if (n->body->child->type == ROFFT_TBL) 20761d06d6bSBaptiste Daroussin return; 20861d06d6bSBaptiste Daroussin 20961d06d6bSBaptiste Daroussin if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) 210*7295610fSBaptiste Daroussin if (n->prev == NULL) 21161d06d6bSBaptiste Daroussin return; 21261d06d6bSBaptiste Daroussin 21361d06d6bSBaptiste Daroussin for (i = 0; i < pardist; i++) 21461d06d6bSBaptiste Daroussin term_vspace(p); 21561d06d6bSBaptiste Daroussin } 21661d06d6bSBaptiste Daroussin 21761d06d6bSBaptiste Daroussin 21861d06d6bSBaptiste Daroussin static int 219*7295610fSBaptiste Daroussin pre_abort(DECL_ARGS) 220*7295610fSBaptiste Daroussin { 221*7295610fSBaptiste Daroussin abort(); 222*7295610fSBaptiste Daroussin } 223*7295610fSBaptiste Daroussin 224*7295610fSBaptiste Daroussin static int 22561d06d6bSBaptiste Daroussin pre_ign(DECL_ARGS) 22661d06d6bSBaptiste Daroussin { 22761d06d6bSBaptiste Daroussin return 0; 22861d06d6bSBaptiste Daroussin } 22961d06d6bSBaptiste Daroussin 23061d06d6bSBaptiste Daroussin static int 23161d06d6bSBaptiste Daroussin pre_I(DECL_ARGS) 23261d06d6bSBaptiste Daroussin { 23361d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 23461d06d6bSBaptiste Daroussin return 1; 23561d06d6bSBaptiste Daroussin } 23661d06d6bSBaptiste Daroussin 23761d06d6bSBaptiste Daroussin static int 23861d06d6bSBaptiste Daroussin pre_literal(DECL_ARGS) 23961d06d6bSBaptiste Daroussin { 24061d06d6bSBaptiste Daroussin term_newln(p); 24161d06d6bSBaptiste Daroussin 24261d06d6bSBaptiste Daroussin /* 24361d06d6bSBaptiste Daroussin * Unlike .IP and .TP, .HP does not have a HEAD. 24461d06d6bSBaptiste Daroussin * So in case a second call to term_flushln() is needed, 24561d06d6bSBaptiste Daroussin * indentation has to be set up explicitly. 24661d06d6bSBaptiste Daroussin */ 24761d06d6bSBaptiste Daroussin if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) { 24861d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 24961d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 25061d06d6bSBaptiste Daroussin p->trailspace = 0; 25161d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 25261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 25361d06d6bSBaptiste Daroussin } 25461d06d6bSBaptiste Daroussin return 0; 25561d06d6bSBaptiste Daroussin } 25661d06d6bSBaptiste Daroussin 25761d06d6bSBaptiste Daroussin static int 25861d06d6bSBaptiste Daroussin pre_PD(DECL_ARGS) 25961d06d6bSBaptiste Daroussin { 26061d06d6bSBaptiste Daroussin struct roffsu su; 26161d06d6bSBaptiste Daroussin 26261d06d6bSBaptiste Daroussin n = n->child; 26361d06d6bSBaptiste Daroussin if (n == NULL) { 26461d06d6bSBaptiste Daroussin mt->pardist = 1; 26561d06d6bSBaptiste Daroussin return 0; 26661d06d6bSBaptiste Daroussin } 26761d06d6bSBaptiste Daroussin assert(n->type == ROFFT_TEXT); 26861d06d6bSBaptiste Daroussin if (a2roffsu(n->string, &su, SCALE_VS) != NULL) 26961d06d6bSBaptiste Daroussin mt->pardist = term_vspan(p, &su); 27061d06d6bSBaptiste Daroussin return 0; 27161d06d6bSBaptiste Daroussin } 27261d06d6bSBaptiste Daroussin 27361d06d6bSBaptiste Daroussin static int 27461d06d6bSBaptiste Daroussin pre_alternate(DECL_ARGS) 27561d06d6bSBaptiste Daroussin { 27661d06d6bSBaptiste Daroussin enum termfont font[2]; 27761d06d6bSBaptiste Daroussin struct roff_node *nn; 278*7295610fSBaptiste Daroussin int i; 27961d06d6bSBaptiste Daroussin 28061d06d6bSBaptiste Daroussin switch (n->tok) { 28161d06d6bSBaptiste Daroussin case MAN_RB: 28261d06d6bSBaptiste Daroussin font[0] = TERMFONT_NONE; 28361d06d6bSBaptiste Daroussin font[1] = TERMFONT_BOLD; 28461d06d6bSBaptiste Daroussin break; 28561d06d6bSBaptiste Daroussin case MAN_RI: 28661d06d6bSBaptiste Daroussin font[0] = TERMFONT_NONE; 28761d06d6bSBaptiste Daroussin font[1] = TERMFONT_UNDER; 28861d06d6bSBaptiste Daroussin break; 28961d06d6bSBaptiste Daroussin case MAN_BR: 29061d06d6bSBaptiste Daroussin font[0] = TERMFONT_BOLD; 29161d06d6bSBaptiste Daroussin font[1] = TERMFONT_NONE; 29261d06d6bSBaptiste Daroussin break; 29361d06d6bSBaptiste Daroussin case MAN_BI: 29461d06d6bSBaptiste Daroussin font[0] = TERMFONT_BOLD; 29561d06d6bSBaptiste Daroussin font[1] = TERMFONT_UNDER; 29661d06d6bSBaptiste Daroussin break; 29761d06d6bSBaptiste Daroussin case MAN_IR: 29861d06d6bSBaptiste Daroussin font[0] = TERMFONT_UNDER; 29961d06d6bSBaptiste Daroussin font[1] = TERMFONT_NONE; 30061d06d6bSBaptiste Daroussin break; 30161d06d6bSBaptiste Daroussin case MAN_IB: 30261d06d6bSBaptiste Daroussin font[0] = TERMFONT_UNDER; 30361d06d6bSBaptiste Daroussin font[1] = TERMFONT_BOLD; 30461d06d6bSBaptiste Daroussin break; 30561d06d6bSBaptiste Daroussin default: 30661d06d6bSBaptiste Daroussin abort(); 30761d06d6bSBaptiste Daroussin } 308*7295610fSBaptiste Daroussin for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) { 30961d06d6bSBaptiste Daroussin term_fontrepl(p, font[i]); 31061d06d6bSBaptiste Daroussin assert(nn->type == ROFFT_TEXT); 31161d06d6bSBaptiste Daroussin term_word(p, nn->string); 31261d06d6bSBaptiste Daroussin if (nn->flags & NODE_EOS) 31361d06d6bSBaptiste Daroussin p->flags |= TERMP_SENTENCE; 314*7295610fSBaptiste Daroussin if (nn->next != NULL) 31561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 31661d06d6bSBaptiste Daroussin } 31761d06d6bSBaptiste Daroussin return 0; 31861d06d6bSBaptiste Daroussin } 31961d06d6bSBaptiste Daroussin 32061d06d6bSBaptiste Daroussin static int 32161d06d6bSBaptiste Daroussin pre_B(DECL_ARGS) 32261d06d6bSBaptiste Daroussin { 32361d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 32461d06d6bSBaptiste Daroussin return 1; 32561d06d6bSBaptiste Daroussin } 32661d06d6bSBaptiste Daroussin 32761d06d6bSBaptiste Daroussin static int 32861d06d6bSBaptiste Daroussin pre_OP(DECL_ARGS) 32961d06d6bSBaptiste Daroussin { 33061d06d6bSBaptiste Daroussin term_word(p, "["); 331*7295610fSBaptiste Daroussin p->flags |= TERMP_KEEP | TERMP_NOSPACE; 33261d06d6bSBaptiste Daroussin 333*7295610fSBaptiste Daroussin if ((n = n->child) != NULL) { 33461d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 33561d06d6bSBaptiste Daroussin term_word(p, n->string); 33661d06d6bSBaptiste Daroussin } 337*7295610fSBaptiste Daroussin if (n != NULL && n->next != NULL) { 33861d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 33961d06d6bSBaptiste Daroussin term_word(p, n->next->string); 34061d06d6bSBaptiste Daroussin } 34161d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 342*7295610fSBaptiste Daroussin p->flags &= ~TERMP_KEEP; 34361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 34461d06d6bSBaptiste Daroussin term_word(p, "]"); 34561d06d6bSBaptiste Daroussin return 0; 34661d06d6bSBaptiste Daroussin } 34761d06d6bSBaptiste Daroussin 34861d06d6bSBaptiste Daroussin static int 34961d06d6bSBaptiste Daroussin pre_in(DECL_ARGS) 35061d06d6bSBaptiste Daroussin { 35161d06d6bSBaptiste Daroussin struct roffsu su; 35261d06d6bSBaptiste Daroussin const char *cp; 35361d06d6bSBaptiste Daroussin size_t v; 35461d06d6bSBaptiste Daroussin int less; 35561d06d6bSBaptiste Daroussin 35661d06d6bSBaptiste Daroussin term_newln(p); 35761d06d6bSBaptiste Daroussin 35861d06d6bSBaptiste Daroussin if (n->child == NULL) { 35961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 36061d06d6bSBaptiste Daroussin return 0; 36161d06d6bSBaptiste Daroussin } 36261d06d6bSBaptiste Daroussin 36361d06d6bSBaptiste Daroussin cp = n->child->string; 36461d06d6bSBaptiste Daroussin less = 0; 36561d06d6bSBaptiste Daroussin 366*7295610fSBaptiste Daroussin if (*cp == '-') 36761d06d6bSBaptiste Daroussin less = -1; 368*7295610fSBaptiste Daroussin else if (*cp == '+') 36961d06d6bSBaptiste Daroussin less = 1; 37061d06d6bSBaptiste Daroussin else 37161d06d6bSBaptiste Daroussin cp--; 37261d06d6bSBaptiste Daroussin 37361d06d6bSBaptiste Daroussin if (a2roffsu(++cp, &su, SCALE_EN) == NULL) 37461d06d6bSBaptiste Daroussin return 0; 37561d06d6bSBaptiste Daroussin 37661d06d6bSBaptiste Daroussin v = term_hen(p, &su); 37761d06d6bSBaptiste Daroussin 37861d06d6bSBaptiste Daroussin if (less < 0) 37961d06d6bSBaptiste Daroussin p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset; 38061d06d6bSBaptiste Daroussin else if (less > 0) 38161d06d6bSBaptiste Daroussin p->tcol->offset += v; 38261d06d6bSBaptiste Daroussin else 38361d06d6bSBaptiste Daroussin p->tcol->offset = v; 38461d06d6bSBaptiste Daroussin if (p->tcol->offset > SHRT_MAX) 38561d06d6bSBaptiste Daroussin p->tcol->offset = term_len(p, p->defindent); 38661d06d6bSBaptiste Daroussin 38761d06d6bSBaptiste Daroussin return 0; 38861d06d6bSBaptiste Daroussin } 38961d06d6bSBaptiste Daroussin 39061d06d6bSBaptiste Daroussin static int 39161d06d6bSBaptiste Daroussin pre_DT(DECL_ARGS) 39261d06d6bSBaptiste Daroussin { 39361d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 39461d06d6bSBaptiste Daroussin term_tab_set(p, "T"); 39561d06d6bSBaptiste Daroussin term_tab_set(p, ".5i"); 39661d06d6bSBaptiste Daroussin return 0; 39761d06d6bSBaptiste Daroussin } 39861d06d6bSBaptiste Daroussin 39961d06d6bSBaptiste Daroussin static int 40061d06d6bSBaptiste Daroussin pre_HP(DECL_ARGS) 40161d06d6bSBaptiste Daroussin { 40261d06d6bSBaptiste Daroussin struct roffsu su; 40361d06d6bSBaptiste Daroussin const struct roff_node *nn; 40461d06d6bSBaptiste Daroussin int len; 40561d06d6bSBaptiste Daroussin 40661d06d6bSBaptiste Daroussin switch (n->type) { 40761d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 40861d06d6bSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 40961d06d6bSBaptiste Daroussin return 1; 410*7295610fSBaptiste Daroussin case ROFFT_HEAD: 411*7295610fSBaptiste Daroussin return 0; 41261d06d6bSBaptiste Daroussin case ROFFT_BODY: 41361d06d6bSBaptiste Daroussin break; 41461d06d6bSBaptiste Daroussin default: 415*7295610fSBaptiste Daroussin abort(); 41661d06d6bSBaptiste Daroussin } 41761d06d6bSBaptiste Daroussin 418*7295610fSBaptiste Daroussin if (n->child == NULL) 419*7295610fSBaptiste Daroussin return 0; 420*7295610fSBaptiste Daroussin 421*7295610fSBaptiste Daroussin if ((n->child->flags & NODE_NOFILL) == 0) { 42261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 42361d06d6bSBaptiste Daroussin p->trailspace = 2; 42461d06d6bSBaptiste Daroussin } 42561d06d6bSBaptiste Daroussin 42661d06d6bSBaptiste Daroussin /* Calculate offset. */ 42761d06d6bSBaptiste Daroussin 42861d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 42961d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 43061d06d6bSBaptiste Daroussin len = term_hen(p, &su); 43161d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 43261d06d6bSBaptiste Daroussin len = -mt->offset; 43361d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 43461d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 43561d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 43661d06d6bSBaptiste Daroussin } else 43761d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 43861d06d6bSBaptiste Daroussin 43961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 44061d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 44161d06d6bSBaptiste Daroussin return 1; 44261d06d6bSBaptiste Daroussin } 44361d06d6bSBaptiste Daroussin 44461d06d6bSBaptiste Daroussin static void 44561d06d6bSBaptiste Daroussin post_HP(DECL_ARGS) 44661d06d6bSBaptiste Daroussin { 44761d06d6bSBaptiste Daroussin switch (n->type) { 448*7295610fSBaptiste Daroussin case ROFFT_BLOCK: 449*7295610fSBaptiste Daroussin case ROFFT_HEAD: 450*7295610fSBaptiste Daroussin break; 45161d06d6bSBaptiste Daroussin case ROFFT_BODY: 45261d06d6bSBaptiste Daroussin term_newln(p); 45361d06d6bSBaptiste Daroussin 45461d06d6bSBaptiste Daroussin /* 45561d06d6bSBaptiste Daroussin * Compatibility with a groff bug. 45661d06d6bSBaptiste Daroussin * The .HP macro uses the undocumented .tag request 45761d06d6bSBaptiste Daroussin * which causes a line break and cancels no-space 45861d06d6bSBaptiste Daroussin * mode even if there isn't any output. 45961d06d6bSBaptiste Daroussin */ 46061d06d6bSBaptiste Daroussin 46161d06d6bSBaptiste Daroussin if (n->child == NULL) 46261d06d6bSBaptiste Daroussin term_vspace(p); 46361d06d6bSBaptiste Daroussin 46461d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 46561d06d6bSBaptiste Daroussin p->trailspace = 0; 46661d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 46761d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 46861d06d6bSBaptiste Daroussin break; 46961d06d6bSBaptiste Daroussin default: 470*7295610fSBaptiste Daroussin abort(); 47161d06d6bSBaptiste Daroussin } 47261d06d6bSBaptiste Daroussin } 47361d06d6bSBaptiste Daroussin 47461d06d6bSBaptiste Daroussin static int 47561d06d6bSBaptiste Daroussin pre_PP(DECL_ARGS) 47661d06d6bSBaptiste Daroussin { 47761d06d6bSBaptiste Daroussin switch (n->type) { 47861d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 47961d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 48061d06d6bSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 48161d06d6bSBaptiste Daroussin break; 482*7295610fSBaptiste Daroussin case ROFFT_HEAD: 483*7295610fSBaptiste Daroussin return 0; 484*7295610fSBaptiste Daroussin case ROFFT_BODY: 48561d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 48661d06d6bSBaptiste Daroussin break; 487*7295610fSBaptiste Daroussin default: 488*7295610fSBaptiste Daroussin abort(); 48961d06d6bSBaptiste Daroussin } 490*7295610fSBaptiste Daroussin return 1; 49161d06d6bSBaptiste Daroussin } 49261d06d6bSBaptiste Daroussin 49361d06d6bSBaptiste Daroussin static int 49461d06d6bSBaptiste Daroussin pre_IP(DECL_ARGS) 49561d06d6bSBaptiste Daroussin { 49661d06d6bSBaptiste Daroussin struct roffsu su; 49761d06d6bSBaptiste Daroussin const struct roff_node *nn; 498*7295610fSBaptiste Daroussin int len; 49961d06d6bSBaptiste Daroussin 50061d06d6bSBaptiste Daroussin switch (n->type) { 501*7295610fSBaptiste Daroussin case ROFFT_BLOCK: 502*7295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 503*7295610fSBaptiste Daroussin return 1; 50461d06d6bSBaptiste Daroussin case ROFFT_HEAD: 50561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 50661d06d6bSBaptiste Daroussin p->trailspace = 1; 50761d06d6bSBaptiste Daroussin break; 508*7295610fSBaptiste Daroussin case ROFFT_BODY: 509*7295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 510*7295610fSBaptiste Daroussin break; 51161d06d6bSBaptiste Daroussin default: 512*7295610fSBaptiste Daroussin abort(); 51361d06d6bSBaptiste Daroussin } 51461d06d6bSBaptiste Daroussin 51561d06d6bSBaptiste Daroussin /* Calculate the offset from the optional second argument. */ 51661d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 51761d06d6bSBaptiste Daroussin (nn = nn->next) != NULL && 51861d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 51961d06d6bSBaptiste Daroussin len = term_hen(p, &su); 52061d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 52161d06d6bSBaptiste Daroussin len = -mt->offset; 52261d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 52361d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 52461d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 52561d06d6bSBaptiste Daroussin } else 52661d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 52761d06d6bSBaptiste Daroussin 52861d06d6bSBaptiste Daroussin switch (n->type) { 52961d06d6bSBaptiste Daroussin case ROFFT_HEAD: 53061d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 53161d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 532*7295610fSBaptiste Daroussin if (n->child != NULL) 53361d06d6bSBaptiste Daroussin print_man_node(p, mt, n->child, meta); 53461d06d6bSBaptiste Daroussin return 0; 53561d06d6bSBaptiste Daroussin case ROFFT_BODY: 53661d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset + len; 53761d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 53861d06d6bSBaptiste Daroussin break; 53961d06d6bSBaptiste Daroussin default: 540*7295610fSBaptiste Daroussin abort(); 54161d06d6bSBaptiste Daroussin } 54261d06d6bSBaptiste Daroussin return 1; 54361d06d6bSBaptiste Daroussin } 54461d06d6bSBaptiste Daroussin 54561d06d6bSBaptiste Daroussin static void 54661d06d6bSBaptiste Daroussin post_IP(DECL_ARGS) 54761d06d6bSBaptiste Daroussin { 54861d06d6bSBaptiste Daroussin switch (n->type) { 549*7295610fSBaptiste Daroussin case ROFFT_BLOCK: 550*7295610fSBaptiste Daroussin break; 55161d06d6bSBaptiste Daroussin case ROFFT_HEAD: 55261d06d6bSBaptiste Daroussin term_flushln(p); 55361d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 55461d06d6bSBaptiste Daroussin p->trailspace = 0; 55561d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 55661d06d6bSBaptiste Daroussin break; 55761d06d6bSBaptiste Daroussin case ROFFT_BODY: 55861d06d6bSBaptiste Daroussin term_newln(p); 55961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 56061d06d6bSBaptiste Daroussin break; 56161d06d6bSBaptiste Daroussin default: 562*7295610fSBaptiste Daroussin abort(); 56361d06d6bSBaptiste Daroussin } 56461d06d6bSBaptiste Daroussin } 56561d06d6bSBaptiste Daroussin 56661d06d6bSBaptiste Daroussin static int 56761d06d6bSBaptiste Daroussin pre_TP(DECL_ARGS) 56861d06d6bSBaptiste Daroussin { 56961d06d6bSBaptiste Daroussin struct roffsu su; 57061d06d6bSBaptiste Daroussin struct roff_node *nn; 571*7295610fSBaptiste Daroussin int len; 57261d06d6bSBaptiste Daroussin 57361d06d6bSBaptiste Daroussin switch (n->type) { 574*7295610fSBaptiste Daroussin case ROFFT_BLOCK: 575*7295610fSBaptiste Daroussin if (n->tok == MAN_TP) 576*7295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 577*7295610fSBaptiste Daroussin return 1; 57861d06d6bSBaptiste Daroussin case ROFFT_HEAD: 57961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRTRSP; 58061d06d6bSBaptiste Daroussin p->trailspace = 1; 58161d06d6bSBaptiste Daroussin break; 58261d06d6bSBaptiste Daroussin case ROFFT_BODY: 58361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 58461d06d6bSBaptiste Daroussin break; 58561d06d6bSBaptiste Daroussin default: 586*7295610fSBaptiste Daroussin abort(); 58761d06d6bSBaptiste Daroussin } 58861d06d6bSBaptiste Daroussin 58961d06d6bSBaptiste Daroussin /* Calculate offset. */ 59061d06d6bSBaptiste Daroussin 59161d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 59261d06d6bSBaptiste Daroussin nn->string != NULL && ! (NODE_LINE & nn->flags) && 59361d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 59461d06d6bSBaptiste Daroussin len = term_hen(p, &su); 59561d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 59661d06d6bSBaptiste Daroussin len = -mt->offset; 59761d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 59861d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 59961d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 60061d06d6bSBaptiste Daroussin } else 60161d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 60261d06d6bSBaptiste Daroussin 60361d06d6bSBaptiste Daroussin switch (n->type) { 60461d06d6bSBaptiste Daroussin case ROFFT_HEAD: 60561d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 60661d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 60761d06d6bSBaptiste Daroussin 60861d06d6bSBaptiste Daroussin /* Don't print same-line elements. */ 60961d06d6bSBaptiste Daroussin nn = n->child; 610*7295610fSBaptiste Daroussin while (nn != NULL && (nn->flags & NODE_LINE) == 0) 61161d06d6bSBaptiste Daroussin nn = nn->next; 61261d06d6bSBaptiste Daroussin 613*7295610fSBaptiste Daroussin while (nn != NULL) { 61461d06d6bSBaptiste Daroussin print_man_node(p, mt, nn, meta); 61561d06d6bSBaptiste Daroussin nn = nn->next; 61661d06d6bSBaptiste Daroussin } 61761d06d6bSBaptiste Daroussin return 0; 61861d06d6bSBaptiste Daroussin case ROFFT_BODY: 61961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset + len; 62061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 62161d06d6bSBaptiste Daroussin p->trailspace = 0; 62261d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP); 62361d06d6bSBaptiste Daroussin break; 62461d06d6bSBaptiste Daroussin default: 625*7295610fSBaptiste Daroussin abort(); 62661d06d6bSBaptiste Daroussin } 62761d06d6bSBaptiste Daroussin return 1; 62861d06d6bSBaptiste Daroussin } 62961d06d6bSBaptiste Daroussin 63061d06d6bSBaptiste Daroussin static void 63161d06d6bSBaptiste Daroussin post_TP(DECL_ARGS) 63261d06d6bSBaptiste Daroussin { 63361d06d6bSBaptiste Daroussin switch (n->type) { 634*7295610fSBaptiste Daroussin case ROFFT_BLOCK: 635*7295610fSBaptiste Daroussin break; 63661d06d6bSBaptiste Daroussin case ROFFT_HEAD: 63761d06d6bSBaptiste Daroussin term_flushln(p); 63861d06d6bSBaptiste Daroussin break; 63961d06d6bSBaptiste Daroussin case ROFFT_BODY: 64061d06d6bSBaptiste Daroussin term_newln(p); 64161d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 64261d06d6bSBaptiste Daroussin break; 64361d06d6bSBaptiste Daroussin default: 644*7295610fSBaptiste Daroussin abort(); 64561d06d6bSBaptiste Daroussin } 64661d06d6bSBaptiste Daroussin } 64761d06d6bSBaptiste Daroussin 64861d06d6bSBaptiste Daroussin static int 64961d06d6bSBaptiste Daroussin pre_SS(DECL_ARGS) 65061d06d6bSBaptiste Daroussin { 65161d06d6bSBaptiste Daroussin int i; 65261d06d6bSBaptiste Daroussin 65361d06d6bSBaptiste Daroussin switch (n->type) { 65461d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 65561d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 65661d06d6bSBaptiste Daroussin mt->offset = term_len(p, p->defindent); 65761d06d6bSBaptiste Daroussin 65861d06d6bSBaptiste Daroussin /* 65961d06d6bSBaptiste Daroussin * No vertical space before the first subsection 66061d06d6bSBaptiste Daroussin * and after an empty subsection. 66161d06d6bSBaptiste Daroussin */ 66261d06d6bSBaptiste Daroussin 66361d06d6bSBaptiste Daroussin do { 66461d06d6bSBaptiste Daroussin n = n->prev; 66561d06d6bSBaptiste Daroussin } while (n != NULL && n->tok >= MAN_TH && 666*7295610fSBaptiste Daroussin man_term_act(n->tok)->flags & MAN_NOTEXT); 66761d06d6bSBaptiste Daroussin if (n == NULL || n->type == ROFFT_COMMENT || 66861d06d6bSBaptiste Daroussin (n->tok == MAN_SS && n->body->child == NULL)) 66961d06d6bSBaptiste Daroussin break; 67061d06d6bSBaptiste Daroussin 67161d06d6bSBaptiste Daroussin for (i = 0; i < mt->pardist; i++) 67261d06d6bSBaptiste Daroussin term_vspace(p); 67361d06d6bSBaptiste Daroussin break; 67461d06d6bSBaptiste Daroussin case ROFFT_HEAD: 67561d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 67661d06d6bSBaptiste Daroussin p->tcol->offset = term_len(p, 3); 67761d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset; 67861d06d6bSBaptiste Daroussin p->trailspace = mt->offset; 67961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 68061d06d6bSBaptiste Daroussin break; 68161d06d6bSBaptiste Daroussin case ROFFT_BODY: 68261d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 68361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 68461d06d6bSBaptiste Daroussin p->trailspace = 0; 68561d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 68661d06d6bSBaptiste Daroussin break; 68761d06d6bSBaptiste Daroussin default: 68861d06d6bSBaptiste Daroussin break; 68961d06d6bSBaptiste Daroussin } 69061d06d6bSBaptiste Daroussin return 1; 69161d06d6bSBaptiste Daroussin } 69261d06d6bSBaptiste Daroussin 69361d06d6bSBaptiste Daroussin static int 69461d06d6bSBaptiste Daroussin pre_SH(DECL_ARGS) 69561d06d6bSBaptiste Daroussin { 69661d06d6bSBaptiste Daroussin int i; 69761d06d6bSBaptiste Daroussin 69861d06d6bSBaptiste Daroussin switch (n->type) { 69961d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 70061d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 70161d06d6bSBaptiste Daroussin mt->offset = term_len(p, p->defindent); 70261d06d6bSBaptiste Daroussin 70361d06d6bSBaptiste Daroussin /* 70461d06d6bSBaptiste Daroussin * No vertical space before the first section 70561d06d6bSBaptiste Daroussin * and after an empty section. 70661d06d6bSBaptiste Daroussin */ 70761d06d6bSBaptiste Daroussin 70861d06d6bSBaptiste Daroussin do { 70961d06d6bSBaptiste Daroussin n = n->prev; 71061d06d6bSBaptiste Daroussin } while (n != NULL && n->tok >= MAN_TH && 711*7295610fSBaptiste Daroussin man_term_act(n->tok)->flags & MAN_NOTEXT); 71261d06d6bSBaptiste Daroussin if (n == NULL || n->type == ROFFT_COMMENT || 71361d06d6bSBaptiste Daroussin (n->tok == MAN_SH && n->body->child == NULL)) 71461d06d6bSBaptiste Daroussin break; 71561d06d6bSBaptiste Daroussin 71661d06d6bSBaptiste Daroussin for (i = 0; i < mt->pardist; i++) 71761d06d6bSBaptiste Daroussin term_vspace(p); 71861d06d6bSBaptiste Daroussin break; 71961d06d6bSBaptiste Daroussin case ROFFT_HEAD: 72061d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 72161d06d6bSBaptiste Daroussin p->tcol->offset = 0; 72261d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset; 72361d06d6bSBaptiste Daroussin p->trailspace = mt->offset; 72461d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 72561d06d6bSBaptiste Daroussin break; 72661d06d6bSBaptiste Daroussin case ROFFT_BODY: 72761d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 72861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 72961d06d6bSBaptiste Daroussin p->trailspace = 0; 73061d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 73161d06d6bSBaptiste Daroussin break; 73261d06d6bSBaptiste Daroussin default: 733*7295610fSBaptiste Daroussin abort(); 73461d06d6bSBaptiste Daroussin } 73561d06d6bSBaptiste Daroussin return 1; 73661d06d6bSBaptiste Daroussin } 73761d06d6bSBaptiste Daroussin 73861d06d6bSBaptiste Daroussin static void 73961d06d6bSBaptiste Daroussin post_SH(DECL_ARGS) 74061d06d6bSBaptiste Daroussin { 74161d06d6bSBaptiste Daroussin switch (n->type) { 742*7295610fSBaptiste Daroussin case ROFFT_BLOCK: 74361d06d6bSBaptiste Daroussin break; 744*7295610fSBaptiste Daroussin case ROFFT_HEAD: 74561d06d6bSBaptiste Daroussin case ROFFT_BODY: 74661d06d6bSBaptiste Daroussin term_newln(p); 74761d06d6bSBaptiste Daroussin break; 74861d06d6bSBaptiste Daroussin default: 749*7295610fSBaptiste Daroussin abort(); 75061d06d6bSBaptiste Daroussin } 75161d06d6bSBaptiste Daroussin } 75261d06d6bSBaptiste Daroussin 75361d06d6bSBaptiste Daroussin static int 75461d06d6bSBaptiste Daroussin pre_RS(DECL_ARGS) 75561d06d6bSBaptiste Daroussin { 75661d06d6bSBaptiste Daroussin struct roffsu su; 75761d06d6bSBaptiste Daroussin 75861d06d6bSBaptiste Daroussin switch (n->type) { 75961d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 76061d06d6bSBaptiste Daroussin term_newln(p); 76161d06d6bSBaptiste Daroussin return 1; 76261d06d6bSBaptiste Daroussin case ROFFT_HEAD: 76361d06d6bSBaptiste Daroussin return 0; 764*7295610fSBaptiste Daroussin case ROFFT_BODY: 76561d06d6bSBaptiste Daroussin break; 766*7295610fSBaptiste Daroussin default: 767*7295610fSBaptiste Daroussin abort(); 76861d06d6bSBaptiste Daroussin } 76961d06d6bSBaptiste Daroussin 77061d06d6bSBaptiste Daroussin n = n->parent->head; 77161d06d6bSBaptiste Daroussin n->aux = SHRT_MAX + 1; 77261d06d6bSBaptiste Daroussin if (n->child == NULL) 77361d06d6bSBaptiste Daroussin n->aux = mt->lmargin[mt->lmargincur]; 77461d06d6bSBaptiste Daroussin else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL) 77561d06d6bSBaptiste Daroussin n->aux = term_hen(p, &su); 77661d06d6bSBaptiste Daroussin if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) 77761d06d6bSBaptiste Daroussin n->aux = -mt->offset; 77861d06d6bSBaptiste Daroussin else if (n->aux > SHRT_MAX) 77961d06d6bSBaptiste Daroussin n->aux = term_len(p, p->defindent); 78061d06d6bSBaptiste Daroussin 78161d06d6bSBaptiste Daroussin mt->offset += n->aux; 78261d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 78361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 78461d06d6bSBaptiste Daroussin 78561d06d6bSBaptiste Daroussin if (++mt->lmarginsz < MAXMARGINS) 78661d06d6bSBaptiste Daroussin mt->lmargincur = mt->lmarginsz; 78761d06d6bSBaptiste Daroussin 78861d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 78961d06d6bSBaptiste Daroussin return 1; 79061d06d6bSBaptiste Daroussin } 79161d06d6bSBaptiste Daroussin 79261d06d6bSBaptiste Daroussin static void 79361d06d6bSBaptiste Daroussin post_RS(DECL_ARGS) 79461d06d6bSBaptiste Daroussin { 79561d06d6bSBaptiste Daroussin switch (n->type) { 79661d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 79761d06d6bSBaptiste Daroussin case ROFFT_HEAD: 79861d06d6bSBaptiste Daroussin return; 799*7295610fSBaptiste Daroussin case ROFFT_BODY: 80061d06d6bSBaptiste Daroussin break; 801*7295610fSBaptiste Daroussin default: 802*7295610fSBaptiste Daroussin abort(); 80361d06d6bSBaptiste Daroussin } 804*7295610fSBaptiste Daroussin term_newln(p); 80561d06d6bSBaptiste Daroussin mt->offset -= n->parent->head->aux; 80661d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 80761d06d6bSBaptiste Daroussin if (--mt->lmarginsz < MAXMARGINS) 80861d06d6bSBaptiste Daroussin mt->lmargincur = mt->lmarginsz; 80961d06d6bSBaptiste Daroussin } 81061d06d6bSBaptiste Daroussin 81161d06d6bSBaptiste Daroussin static int 812*7295610fSBaptiste Daroussin pre_SY(DECL_ARGS) 813*7295610fSBaptiste Daroussin { 814*7295610fSBaptiste Daroussin const struct roff_node *nn; 815*7295610fSBaptiste Daroussin int len; 816*7295610fSBaptiste Daroussin 817*7295610fSBaptiste Daroussin switch (n->type) { 818*7295610fSBaptiste Daroussin case ROFFT_BLOCK: 819*7295610fSBaptiste Daroussin if (n->prev == NULL || n->prev->tok != MAN_SY) 820*7295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 821*7295610fSBaptiste Daroussin return 1; 822*7295610fSBaptiste Daroussin case ROFFT_HEAD: 823*7295610fSBaptiste Daroussin case ROFFT_BODY: 824*7295610fSBaptiste Daroussin break; 825*7295610fSBaptiste Daroussin default: 826*7295610fSBaptiste Daroussin abort(); 827*7295610fSBaptiste Daroussin } 828*7295610fSBaptiste Daroussin 829*7295610fSBaptiste Daroussin nn = n->parent->head->child; 830*7295610fSBaptiste Daroussin len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1; 831*7295610fSBaptiste Daroussin 832*7295610fSBaptiste Daroussin switch (n->type) { 833*7295610fSBaptiste Daroussin case ROFFT_HEAD: 834*7295610fSBaptiste Daroussin p->tcol->offset = mt->offset; 835*7295610fSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 836*7295610fSBaptiste Daroussin if (n->next->child == NULL || 837*7295610fSBaptiste Daroussin (n->next->child->flags & NODE_NOFILL) == 0) 838*7295610fSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 839*7295610fSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 840*7295610fSBaptiste Daroussin break; 841*7295610fSBaptiste Daroussin case ROFFT_BODY: 842*7295610fSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 843*7295610fSBaptiste Daroussin p->tcol->offset = mt->offset + len; 844*7295610fSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 845*7295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 846*7295610fSBaptiste Daroussin break; 847*7295610fSBaptiste Daroussin default: 848*7295610fSBaptiste Daroussin abort(); 849*7295610fSBaptiste Daroussin } 850*7295610fSBaptiste Daroussin return 1; 851*7295610fSBaptiste Daroussin } 852*7295610fSBaptiste Daroussin 853*7295610fSBaptiste Daroussin static void 854*7295610fSBaptiste Daroussin post_SY(DECL_ARGS) 855*7295610fSBaptiste Daroussin { 856*7295610fSBaptiste Daroussin switch (n->type) { 857*7295610fSBaptiste Daroussin case ROFFT_BLOCK: 858*7295610fSBaptiste Daroussin break; 859*7295610fSBaptiste Daroussin case ROFFT_HEAD: 860*7295610fSBaptiste Daroussin term_flushln(p); 861*7295610fSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 862*7295610fSBaptiste Daroussin break; 863*7295610fSBaptiste Daroussin case ROFFT_BODY: 864*7295610fSBaptiste Daroussin term_newln(p); 865*7295610fSBaptiste Daroussin p->tcol->offset = mt->offset; 866*7295610fSBaptiste Daroussin break; 867*7295610fSBaptiste Daroussin default: 868*7295610fSBaptiste Daroussin abort(); 869*7295610fSBaptiste Daroussin } 870*7295610fSBaptiste Daroussin } 871*7295610fSBaptiste Daroussin 872*7295610fSBaptiste Daroussin static int 87361d06d6bSBaptiste Daroussin pre_UR(DECL_ARGS) 87461d06d6bSBaptiste Daroussin { 87561d06d6bSBaptiste Daroussin return n->type != ROFFT_HEAD; 87661d06d6bSBaptiste Daroussin } 87761d06d6bSBaptiste Daroussin 87861d06d6bSBaptiste Daroussin static void 87961d06d6bSBaptiste Daroussin post_UR(DECL_ARGS) 88061d06d6bSBaptiste Daroussin { 88161d06d6bSBaptiste Daroussin if (n->type != ROFFT_BLOCK) 88261d06d6bSBaptiste Daroussin return; 88361d06d6bSBaptiste Daroussin 88461d06d6bSBaptiste Daroussin term_word(p, "<"); 88561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 88661d06d6bSBaptiste Daroussin 887*7295610fSBaptiste Daroussin if (n->child->child != NULL) 88861d06d6bSBaptiste Daroussin print_man_node(p, mt, n->child->child, meta); 88961d06d6bSBaptiste Daroussin 89061d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 89161d06d6bSBaptiste Daroussin term_word(p, ">"); 89261d06d6bSBaptiste Daroussin } 89361d06d6bSBaptiste Daroussin 89461d06d6bSBaptiste Daroussin static void 89561d06d6bSBaptiste Daroussin print_man_node(DECL_ARGS) 89661d06d6bSBaptiste Daroussin { 897*7295610fSBaptiste Daroussin const struct man_term_act *act; 89861d06d6bSBaptiste Daroussin int c; 89961d06d6bSBaptiste Daroussin 90061d06d6bSBaptiste Daroussin switch (n->type) { 90161d06d6bSBaptiste Daroussin case ROFFT_TEXT: 90261d06d6bSBaptiste Daroussin /* 90361d06d6bSBaptiste Daroussin * If we have a blank line, output a vertical space. 90461d06d6bSBaptiste Daroussin * If we have a space as the first character, break 90561d06d6bSBaptiste Daroussin * before printing the line's data. 90661d06d6bSBaptiste Daroussin */ 90761d06d6bSBaptiste Daroussin if (*n->string == '\0') { 90861d06d6bSBaptiste Daroussin if (p->flags & TERMP_NONEWLINE) 90961d06d6bSBaptiste Daroussin term_newln(p); 91061d06d6bSBaptiste Daroussin else 91161d06d6bSBaptiste Daroussin term_vspace(p); 91261d06d6bSBaptiste Daroussin return; 91361d06d6bSBaptiste Daroussin } else if (*n->string == ' ' && n->flags & NODE_LINE && 91461d06d6bSBaptiste Daroussin (p->flags & TERMP_NONEWLINE) == 0) 91561d06d6bSBaptiste Daroussin term_newln(p); 916*7295610fSBaptiste Daroussin else if (n->flags & NODE_DELIMC) 917*7295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 91861d06d6bSBaptiste Daroussin 91961d06d6bSBaptiste Daroussin term_word(p, n->string); 92061d06d6bSBaptiste Daroussin goto out; 92161d06d6bSBaptiste Daroussin case ROFFT_COMMENT: 92261d06d6bSBaptiste Daroussin return; 92361d06d6bSBaptiste Daroussin case ROFFT_EQN: 92461d06d6bSBaptiste Daroussin if ( ! (n->flags & NODE_LINE)) 92561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 92661d06d6bSBaptiste Daroussin term_eqn(p, n->eqn); 92761d06d6bSBaptiste Daroussin if (n->next != NULL && ! (n->next->flags & NODE_LINE)) 92861d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 92961d06d6bSBaptiste Daroussin return; 93061d06d6bSBaptiste Daroussin case ROFFT_TBL: 93161d06d6bSBaptiste Daroussin if (p->tbl.cols == NULL) 93261d06d6bSBaptiste Daroussin term_vspace(p); 93361d06d6bSBaptiste Daroussin term_tbl(p, n->span); 93461d06d6bSBaptiste Daroussin return; 93561d06d6bSBaptiste Daroussin default: 93661d06d6bSBaptiste Daroussin break; 93761d06d6bSBaptiste Daroussin } 93861d06d6bSBaptiste Daroussin 93961d06d6bSBaptiste Daroussin if (n->tok < ROFF_MAX) { 94061d06d6bSBaptiste Daroussin roff_term_pre(p, n); 94161d06d6bSBaptiste Daroussin return; 94261d06d6bSBaptiste Daroussin } 94361d06d6bSBaptiste Daroussin 944*7295610fSBaptiste Daroussin act = man_term_act(n->tok); 945*7295610fSBaptiste Daroussin if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) 94661d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 94761d06d6bSBaptiste Daroussin 94861d06d6bSBaptiste Daroussin c = 1; 949*7295610fSBaptiste Daroussin if (act->pre != NULL) 950*7295610fSBaptiste Daroussin c = (*act->pre)(p, mt, n, meta); 95161d06d6bSBaptiste Daroussin 952*7295610fSBaptiste Daroussin if (c && n->child != NULL) 95361d06d6bSBaptiste Daroussin print_man_nodelist(p, mt, n->child, meta); 95461d06d6bSBaptiste Daroussin 955*7295610fSBaptiste Daroussin if (act->post != NULL) 956*7295610fSBaptiste Daroussin (*act->post)(p, mt, n, meta); 957*7295610fSBaptiste Daroussin if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) 95861d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 95961d06d6bSBaptiste Daroussin 96061d06d6bSBaptiste Daroussin out: 96161d06d6bSBaptiste Daroussin /* 96261d06d6bSBaptiste Daroussin * If we're in a literal context, make sure that words 96361d06d6bSBaptiste Daroussin * together on the same line stay together. This is a 96461d06d6bSBaptiste Daroussin * POST-printing call, so we check the NEXT word. Since 96561d06d6bSBaptiste Daroussin * -man doesn't have nested macros, we don't need to be 96661d06d6bSBaptiste Daroussin * more specific than this. 96761d06d6bSBaptiste Daroussin */ 968*7295610fSBaptiste Daroussin if (n->flags & NODE_NOFILL && 96961d06d6bSBaptiste Daroussin ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && 97061d06d6bSBaptiste Daroussin (n->next == NULL || n->next->flags & NODE_LINE)) { 97161d06d6bSBaptiste Daroussin p->flags |= TERMP_BRNEVER | TERMP_NOSPACE; 97261d06d6bSBaptiste Daroussin if (n->string != NULL && *n->string != '\0') 97361d06d6bSBaptiste Daroussin term_flushln(p); 97461d06d6bSBaptiste Daroussin else 97561d06d6bSBaptiste Daroussin term_newln(p); 97661d06d6bSBaptiste Daroussin p->flags &= ~TERMP_BRNEVER; 97761d06d6bSBaptiste Daroussin if (p->tcol->rmargin < p->maxrmargin && 97861d06d6bSBaptiste Daroussin n->parent->tok == MAN_HP) { 97961d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 98061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 98161d06d6bSBaptiste Daroussin } 98261d06d6bSBaptiste Daroussin } 983*7295610fSBaptiste Daroussin if (n->flags & NODE_EOS) 98461d06d6bSBaptiste Daroussin p->flags |= TERMP_SENTENCE; 98561d06d6bSBaptiste Daroussin } 98661d06d6bSBaptiste Daroussin 98761d06d6bSBaptiste Daroussin static void 98861d06d6bSBaptiste Daroussin print_man_nodelist(DECL_ARGS) 98961d06d6bSBaptiste Daroussin { 99061d06d6bSBaptiste Daroussin while (n != NULL) { 99161d06d6bSBaptiste Daroussin print_man_node(p, mt, n, meta); 99261d06d6bSBaptiste Daroussin n = n->next; 99361d06d6bSBaptiste Daroussin } 99461d06d6bSBaptiste Daroussin } 99561d06d6bSBaptiste Daroussin 99661d06d6bSBaptiste Daroussin static void 99761d06d6bSBaptiste Daroussin print_man_foot(struct termp *p, const struct roff_meta *meta) 99861d06d6bSBaptiste Daroussin { 99961d06d6bSBaptiste Daroussin char *title; 100061d06d6bSBaptiste Daroussin size_t datelen, titlen; 100161d06d6bSBaptiste Daroussin 100261d06d6bSBaptiste Daroussin assert(meta->title); 100361d06d6bSBaptiste Daroussin assert(meta->msec); 100461d06d6bSBaptiste Daroussin assert(meta->date); 100561d06d6bSBaptiste Daroussin 100661d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 100761d06d6bSBaptiste Daroussin 100861d06d6bSBaptiste Daroussin if (meta->hasbody) 100961d06d6bSBaptiste Daroussin term_vspace(p); 101061d06d6bSBaptiste Daroussin 101161d06d6bSBaptiste Daroussin /* 101261d06d6bSBaptiste Daroussin * Temporary, undocumented option to imitate mdoc(7) output. 101361d06d6bSBaptiste Daroussin * In the bottom right corner, use the operating system 101461d06d6bSBaptiste Daroussin * instead of the title. 101561d06d6bSBaptiste Daroussin */ 101661d06d6bSBaptiste Daroussin 101761d06d6bSBaptiste Daroussin if ( ! p->mdocstyle) { 101861d06d6bSBaptiste Daroussin if (meta->hasbody) { 101961d06d6bSBaptiste Daroussin term_vspace(p); 102061d06d6bSBaptiste Daroussin term_vspace(p); 102161d06d6bSBaptiste Daroussin } 102261d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", 102361d06d6bSBaptiste Daroussin meta->title, meta->msec); 1024*7295610fSBaptiste Daroussin } else if (meta->os != NULL) { 102561d06d6bSBaptiste Daroussin title = mandoc_strdup(meta->os); 102661d06d6bSBaptiste Daroussin } else { 102761d06d6bSBaptiste Daroussin title = mandoc_strdup(""); 102861d06d6bSBaptiste Daroussin } 102961d06d6bSBaptiste Daroussin datelen = term_strlen(p, meta->date); 103061d06d6bSBaptiste Daroussin 103161d06d6bSBaptiste Daroussin /* Bottom left corner: operating system. */ 103261d06d6bSBaptiste Daroussin 103361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 103461d06d6bSBaptiste Daroussin p->trailspace = 1; 103561d06d6bSBaptiste Daroussin p->tcol->offset = 0; 103661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin > datelen ? 103761d06d6bSBaptiste Daroussin (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; 103861d06d6bSBaptiste Daroussin 103961d06d6bSBaptiste Daroussin if (meta->os) 104061d06d6bSBaptiste Daroussin term_word(p, meta->os); 104161d06d6bSBaptiste Daroussin term_flushln(p); 104261d06d6bSBaptiste Daroussin 104361d06d6bSBaptiste Daroussin /* At the bottom in the middle: manual date. */ 104461d06d6bSBaptiste Daroussin 104561d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 104661d06d6bSBaptiste Daroussin titlen = term_strlen(p, title); 104761d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin > titlen ? 104861d06d6bSBaptiste Daroussin p->maxrmargin - titlen : 0; 104961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 105061d06d6bSBaptiste Daroussin 105161d06d6bSBaptiste Daroussin term_word(p, meta->date); 105261d06d6bSBaptiste Daroussin term_flushln(p); 105361d06d6bSBaptiste Daroussin 105461d06d6bSBaptiste Daroussin /* Bottom right corner: manual title and section. */ 105561d06d6bSBaptiste Daroussin 105661d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 105761d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 105861d06d6bSBaptiste Daroussin p->trailspace = 0; 105961d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 106061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 106161d06d6bSBaptiste Daroussin 106261d06d6bSBaptiste Daroussin term_word(p, title); 106361d06d6bSBaptiste Daroussin term_flushln(p); 106461d06d6bSBaptiste Daroussin 106561d06d6bSBaptiste Daroussin /* 106661d06d6bSBaptiste Daroussin * Reset the terminal state for more output after the footer: 106761d06d6bSBaptiste Daroussin * Some output modes, in particular PostScript and PDF, print 106861d06d6bSBaptiste Daroussin * the header and the footer into a buffer such that it can be 106961d06d6bSBaptiste Daroussin * reused for multiple output pages, then go on to format the 107061d06d6bSBaptiste Daroussin * main text. 107161d06d6bSBaptiste Daroussin */ 107261d06d6bSBaptiste Daroussin 107361d06d6bSBaptiste Daroussin p->tcol->offset = 0; 107461d06d6bSBaptiste Daroussin p->flags = 0; 107561d06d6bSBaptiste Daroussin 107661d06d6bSBaptiste Daroussin free(title); 107761d06d6bSBaptiste Daroussin } 107861d06d6bSBaptiste Daroussin 107961d06d6bSBaptiste Daroussin static void 108061d06d6bSBaptiste Daroussin print_man_head(struct termp *p, const struct roff_meta *meta) 108161d06d6bSBaptiste Daroussin { 108261d06d6bSBaptiste Daroussin const char *volume; 108361d06d6bSBaptiste Daroussin char *title; 108461d06d6bSBaptiste Daroussin size_t vollen, titlen; 108561d06d6bSBaptiste Daroussin 108661d06d6bSBaptiste Daroussin assert(meta->title); 108761d06d6bSBaptiste Daroussin assert(meta->msec); 108861d06d6bSBaptiste Daroussin 108961d06d6bSBaptiste Daroussin volume = NULL == meta->vol ? "" : meta->vol; 109061d06d6bSBaptiste Daroussin vollen = term_strlen(p, volume); 109161d06d6bSBaptiste Daroussin 109261d06d6bSBaptiste Daroussin /* Top left corner: manual title and section. */ 109361d06d6bSBaptiste Daroussin 109461d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); 109561d06d6bSBaptiste Daroussin titlen = term_strlen(p, title); 109661d06d6bSBaptiste Daroussin 109761d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; 109861d06d6bSBaptiste Daroussin p->trailspace = 1; 109961d06d6bSBaptiste Daroussin p->tcol->offset = 0; 110061d06d6bSBaptiste Daroussin p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? 110161d06d6bSBaptiste Daroussin (p->maxrmargin - vollen + term_len(p, 1)) / 2 : 110261d06d6bSBaptiste Daroussin vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; 110361d06d6bSBaptiste Daroussin 110461d06d6bSBaptiste Daroussin term_word(p, title); 110561d06d6bSBaptiste Daroussin term_flushln(p); 110661d06d6bSBaptiste Daroussin 110761d06d6bSBaptiste Daroussin /* At the top in the middle: manual volume. */ 110861d06d6bSBaptiste Daroussin 110961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 111061d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 111161d06d6bSBaptiste Daroussin p->tcol->rmargin = p->tcol->offset + vollen + titlen < 111261d06d6bSBaptiste Daroussin p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin; 111361d06d6bSBaptiste Daroussin 111461d06d6bSBaptiste Daroussin term_word(p, volume); 111561d06d6bSBaptiste Daroussin term_flushln(p); 111661d06d6bSBaptiste Daroussin 111761d06d6bSBaptiste Daroussin /* Top right corner: title and section, again. */ 111861d06d6bSBaptiste Daroussin 111961d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 112061d06d6bSBaptiste Daroussin p->trailspace = 0; 112161d06d6bSBaptiste Daroussin if (p->tcol->rmargin + titlen <= p->maxrmargin) { 112261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 112361d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 112461d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 112561d06d6bSBaptiste Daroussin term_word(p, title); 112661d06d6bSBaptiste Daroussin term_flushln(p); 112761d06d6bSBaptiste Daroussin } 112861d06d6bSBaptiste Daroussin 112961d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOSPACE; 113061d06d6bSBaptiste Daroussin p->tcol->offset = 0; 113161d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 113261d06d6bSBaptiste Daroussin 113361d06d6bSBaptiste Daroussin /* 113461d06d6bSBaptiste Daroussin * Groff prints three blank lines before the content. 113561d06d6bSBaptiste Daroussin * Do the same, except in the temporary, undocumented 113661d06d6bSBaptiste Daroussin * mode imitating mdoc(7) output. 113761d06d6bSBaptiste Daroussin */ 113861d06d6bSBaptiste Daroussin 113961d06d6bSBaptiste Daroussin term_vspace(p); 114061d06d6bSBaptiste Daroussin if ( ! p->mdocstyle) { 114161d06d6bSBaptiste Daroussin term_vspace(p); 114261d06d6bSBaptiste Daroussin term_vspace(p); 114361d06d6bSBaptiste Daroussin } 114461d06d6bSBaptiste Daroussin free(title); 114561d06d6bSBaptiste Daroussin } 1146