1*45a5aec3SBaptiste Daroussin /* $Id: man_term.c,v 1.232 2019/07/23 17:53:35 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 361d06d6bSBaptiste Daroussin * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 47295610fSBaptiste 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" 30*45a5aec3SBaptiste Daroussin #include "mandoc.h" 3161d06d6bSBaptiste Daroussin #include "roff.h" 3261d06d6bSBaptiste Daroussin #include "man.h" 3361d06d6bSBaptiste Daroussin #include "out.h" 3461d06d6bSBaptiste Daroussin #include "term.h" 35*45a5aec3SBaptiste Daroussin #include "tag.h" 3661d06d6bSBaptiste Daroussin #include "main.h" 3761d06d6bSBaptiste Daroussin 3861d06d6bSBaptiste Daroussin #define MAXMARGINS 64 /* maximum number of indented scopes */ 3961d06d6bSBaptiste Daroussin 4061d06d6bSBaptiste Daroussin struct mtermp { 4161d06d6bSBaptiste Daroussin int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */ 4261d06d6bSBaptiste Daroussin int lmargincur; /* index of current margin */ 4361d06d6bSBaptiste Daroussin int lmarginsz; /* actual number of nested margins */ 4461d06d6bSBaptiste Daroussin size_t offset; /* default offset to visible page */ 4561d06d6bSBaptiste Daroussin int pardist; /* vert. space before par., unit: [v] */ 4661d06d6bSBaptiste Daroussin }; 4761d06d6bSBaptiste Daroussin 4861d06d6bSBaptiste Daroussin #define DECL_ARGS struct termp *p, \ 4961d06d6bSBaptiste Daroussin struct mtermp *mt, \ 5061d06d6bSBaptiste Daroussin struct roff_node *n, \ 5161d06d6bSBaptiste Daroussin const struct roff_meta *meta 5261d06d6bSBaptiste Daroussin 537295610fSBaptiste Daroussin struct man_term_act { 5461d06d6bSBaptiste Daroussin int (*pre)(DECL_ARGS); 5561d06d6bSBaptiste Daroussin void (*post)(DECL_ARGS); 5661d06d6bSBaptiste Daroussin int flags; 5761d06d6bSBaptiste Daroussin #define MAN_NOTEXT (1 << 0) /* Never has text children. */ 5861d06d6bSBaptiste Daroussin }; 5961d06d6bSBaptiste Daroussin 6061d06d6bSBaptiste Daroussin static void print_man_nodelist(DECL_ARGS); 6161d06d6bSBaptiste Daroussin static void print_man_node(DECL_ARGS); 6261d06d6bSBaptiste Daroussin static void print_man_head(struct termp *, 6361d06d6bSBaptiste Daroussin const struct roff_meta *); 6461d06d6bSBaptiste Daroussin static void print_man_foot(struct termp *, 6561d06d6bSBaptiste Daroussin const struct roff_meta *); 6661d06d6bSBaptiste Daroussin static void print_bvspace(struct termp *, 6761d06d6bSBaptiste Daroussin const struct roff_node *, int); 6861d06d6bSBaptiste Daroussin 6961d06d6bSBaptiste Daroussin static int pre_B(DECL_ARGS); 7061d06d6bSBaptiste Daroussin static int pre_DT(DECL_ARGS); 7161d06d6bSBaptiste Daroussin static int pre_HP(DECL_ARGS); 7261d06d6bSBaptiste Daroussin static int pre_I(DECL_ARGS); 7361d06d6bSBaptiste Daroussin static int pre_IP(DECL_ARGS); 7461d06d6bSBaptiste Daroussin static int pre_OP(DECL_ARGS); 7561d06d6bSBaptiste Daroussin static int pre_PD(DECL_ARGS); 7661d06d6bSBaptiste Daroussin static int pre_PP(DECL_ARGS); 7761d06d6bSBaptiste Daroussin static int pre_RS(DECL_ARGS); 7861d06d6bSBaptiste Daroussin static int pre_SH(DECL_ARGS); 7961d06d6bSBaptiste Daroussin static int pre_SS(DECL_ARGS); 807295610fSBaptiste Daroussin static int pre_SY(DECL_ARGS); 8161d06d6bSBaptiste Daroussin static int pre_TP(DECL_ARGS); 8261d06d6bSBaptiste Daroussin static int pre_UR(DECL_ARGS); 837295610fSBaptiste Daroussin static int pre_abort(DECL_ARGS); 8461d06d6bSBaptiste Daroussin static int pre_alternate(DECL_ARGS); 8561d06d6bSBaptiste Daroussin static int pre_ign(DECL_ARGS); 8661d06d6bSBaptiste Daroussin static int pre_in(DECL_ARGS); 8761d06d6bSBaptiste Daroussin static int pre_literal(DECL_ARGS); 8861d06d6bSBaptiste Daroussin 8961d06d6bSBaptiste Daroussin static void post_IP(DECL_ARGS); 9061d06d6bSBaptiste Daroussin static void post_HP(DECL_ARGS); 9161d06d6bSBaptiste Daroussin static void post_RS(DECL_ARGS); 9261d06d6bSBaptiste Daroussin static void post_SH(DECL_ARGS); 937295610fSBaptiste Daroussin static void post_SY(DECL_ARGS); 9461d06d6bSBaptiste Daroussin static void post_TP(DECL_ARGS); 9561d06d6bSBaptiste Daroussin static void post_UR(DECL_ARGS); 9661d06d6bSBaptiste Daroussin 97*45a5aec3SBaptiste Daroussin static void tag_man(struct termp *, struct roff_node *); 98*45a5aec3SBaptiste Daroussin 997295610fSBaptiste Daroussin static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = { 10061d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* TH */ 10161d06d6bSBaptiste Daroussin { pre_SH, post_SH, 0 }, /* SH */ 1027295610fSBaptiste Daroussin { pre_SS, post_SH, 0 }, /* SS */ 10361d06d6bSBaptiste Daroussin { pre_TP, post_TP, 0 }, /* TP */ 1047295610fSBaptiste Daroussin { pre_TP, post_TP, 0 }, /* TQ */ 1057295610fSBaptiste Daroussin { pre_abort, NULL, 0 }, /* LP */ 10661d06d6bSBaptiste Daroussin { pre_PP, NULL, 0 }, /* PP */ 1077295610fSBaptiste Daroussin { pre_abort, NULL, 0 }, /* P */ 10861d06d6bSBaptiste Daroussin { pre_IP, post_IP, 0 }, /* IP */ 10961d06d6bSBaptiste Daroussin { pre_HP, post_HP, 0 }, /* HP */ 11061d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* SM */ 11161d06d6bSBaptiste Daroussin { pre_B, NULL, 0 }, /* SB */ 11261d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* BI */ 11361d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* IB */ 11461d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* BR */ 11561d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* RB */ 11661d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* R */ 11761d06d6bSBaptiste Daroussin { pre_B, NULL, 0 }, /* B */ 11861d06d6bSBaptiste Daroussin { pre_I, NULL, 0 }, /* I */ 11961d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* IR */ 12061d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* RI */ 12161d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* RE */ 12261d06d6bSBaptiste Daroussin { pre_RS, post_RS, 0 }, /* RS */ 12361d06d6bSBaptiste Daroussin { pre_DT, NULL, 0 }, /* DT */ 12461d06d6bSBaptiste Daroussin { pre_ign, NULL, MAN_NOTEXT }, /* UC */ 12561d06d6bSBaptiste Daroussin { pre_PD, NULL, MAN_NOTEXT }, /* PD */ 12661d06d6bSBaptiste Daroussin { pre_ign, NULL, 0 }, /* AT */ 12761d06d6bSBaptiste Daroussin { pre_in, NULL, MAN_NOTEXT }, /* in */ 1287295610fSBaptiste Daroussin { pre_SY, post_SY, 0 }, /* SY */ 1297295610fSBaptiste Daroussin { NULL, NULL, 0 }, /* YS */ 13061d06d6bSBaptiste Daroussin { pre_OP, NULL, 0 }, /* OP */ 13161d06d6bSBaptiste Daroussin { pre_literal, NULL, 0 }, /* EX */ 13261d06d6bSBaptiste Daroussin { pre_literal, NULL, 0 }, /* EE */ 13361d06d6bSBaptiste Daroussin { pre_UR, post_UR, 0 }, /* UR */ 13461d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* UE */ 13561d06d6bSBaptiste Daroussin { pre_UR, post_UR, 0 }, /* MT */ 13661d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* ME */ 13761d06d6bSBaptiste Daroussin }; 1387295610fSBaptiste Daroussin static const struct man_term_act *man_term_act(enum roff_tok); 13961d06d6bSBaptiste Daroussin 14061d06d6bSBaptiste Daroussin 1417295610fSBaptiste Daroussin static const struct man_term_act * 1427295610fSBaptiste Daroussin man_term_act(enum roff_tok tok) 1437295610fSBaptiste Daroussin { 1447295610fSBaptiste Daroussin assert(tok >= MAN_TH && tok <= MAN_MAX); 1457295610fSBaptiste Daroussin return man_term_acts + (tok - MAN_TH); 1467295610fSBaptiste Daroussin } 1477295610fSBaptiste Daroussin 14861d06d6bSBaptiste Daroussin void 1497295610fSBaptiste Daroussin terminal_man(void *arg, const struct roff_meta *man) 15061d06d6bSBaptiste Daroussin { 1517295610fSBaptiste Daroussin struct mtermp mt; 15261d06d6bSBaptiste Daroussin struct termp *p; 153*45a5aec3SBaptiste Daroussin struct roff_node *n, *nc, *nn; 15461d06d6bSBaptiste Daroussin size_t save_defindent; 15561d06d6bSBaptiste Daroussin 15661d06d6bSBaptiste Daroussin p = (struct termp *)arg; 15761d06d6bSBaptiste Daroussin save_defindent = p->defindent; 15861d06d6bSBaptiste Daroussin if (p->synopsisonly == 0 && p->defindent == 0) 15961d06d6bSBaptiste Daroussin p->defindent = 7; 16061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin = p->defrmargin; 16161d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 16261d06d6bSBaptiste Daroussin term_tab_set(p, "T"); 16361d06d6bSBaptiste Daroussin term_tab_set(p, ".5i"); 16461d06d6bSBaptiste Daroussin 1657295610fSBaptiste Daroussin memset(&mt, 0, sizeof(mt)); 16661d06d6bSBaptiste Daroussin mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); 16761d06d6bSBaptiste Daroussin mt.offset = term_len(p, p->defindent); 16861d06d6bSBaptiste Daroussin mt.pardist = 1; 16961d06d6bSBaptiste Daroussin 17061d06d6bSBaptiste Daroussin n = man->first->child; 17161d06d6bSBaptiste Daroussin if (p->synopsisonly) { 172*45a5aec3SBaptiste Daroussin for (nn = NULL; n != NULL; n = n->next) { 173*45a5aec3SBaptiste Daroussin if (n->tok != MAN_SH) 174*45a5aec3SBaptiste Daroussin continue; 175*45a5aec3SBaptiste Daroussin nc = n->child->child; 176*45a5aec3SBaptiste Daroussin if (nc->type != ROFFT_TEXT) 177*45a5aec3SBaptiste Daroussin continue; 178*45a5aec3SBaptiste Daroussin if (strcmp(nc->string, "SYNOPSIS") == 0) 17961d06d6bSBaptiste Daroussin break; 180*45a5aec3SBaptiste Daroussin if (nn == NULL && strcmp(nc->string, "NAME") == 0) 181*45a5aec3SBaptiste Daroussin nn = n; 18261d06d6bSBaptiste Daroussin } 183*45a5aec3SBaptiste Daroussin if (n == NULL) 184*45a5aec3SBaptiste Daroussin n = nn; 185*45a5aec3SBaptiste Daroussin p->flags |= TERMP_NOSPACE; 186*45a5aec3SBaptiste Daroussin if (n != NULL && (n = n->child->next->child) != NULL) 187*45a5aec3SBaptiste Daroussin print_man_nodelist(p, &mt, n, man); 188*45a5aec3SBaptiste Daroussin term_newln(p); 18961d06d6bSBaptiste Daroussin } else { 1907295610fSBaptiste Daroussin term_begin(p, print_man_head, print_man_foot, man); 19161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 19261d06d6bSBaptiste Daroussin if (n != NULL) 1937295610fSBaptiste Daroussin print_man_nodelist(p, &mt, n, man); 19461d06d6bSBaptiste Daroussin term_end(p); 19561d06d6bSBaptiste Daroussin } 19661d06d6bSBaptiste Daroussin p->defindent = save_defindent; 19761d06d6bSBaptiste Daroussin } 19861d06d6bSBaptiste Daroussin 19961d06d6bSBaptiste Daroussin /* 20061d06d6bSBaptiste Daroussin * Printing leading vertical space before a block. 20161d06d6bSBaptiste Daroussin * This is used for the paragraph macros. 20261d06d6bSBaptiste Daroussin * The rules are pretty simple, since there's very little nesting going 20361d06d6bSBaptiste Daroussin * on here. Basically, if we're the first within another block (SS/SH), 20461d06d6bSBaptiste Daroussin * then don't emit vertical space. If we are (RS), then do. If not the 20561d06d6bSBaptiste Daroussin * first, print it. 20661d06d6bSBaptiste Daroussin */ 20761d06d6bSBaptiste Daroussin static void 20861d06d6bSBaptiste Daroussin print_bvspace(struct termp *p, const struct roff_node *n, int pardist) 20961d06d6bSBaptiste Daroussin { 21061d06d6bSBaptiste Daroussin int i; 21161d06d6bSBaptiste Daroussin 21261d06d6bSBaptiste Daroussin term_newln(p); 21361d06d6bSBaptiste Daroussin 2147295610fSBaptiste Daroussin if (n->body != NULL && n->body->child != NULL) 21561d06d6bSBaptiste Daroussin if (n->body->child->type == ROFFT_TBL) 21661d06d6bSBaptiste Daroussin return; 21761d06d6bSBaptiste Daroussin 21861d06d6bSBaptiste Daroussin if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) 2197295610fSBaptiste Daroussin if (n->prev == NULL) 22061d06d6bSBaptiste Daroussin return; 22161d06d6bSBaptiste Daroussin 22261d06d6bSBaptiste Daroussin for (i = 0; i < pardist; i++) 22361d06d6bSBaptiste Daroussin term_vspace(p); 22461d06d6bSBaptiste Daroussin } 22561d06d6bSBaptiste Daroussin 22661d06d6bSBaptiste Daroussin 22761d06d6bSBaptiste Daroussin static int 2287295610fSBaptiste Daroussin pre_abort(DECL_ARGS) 2297295610fSBaptiste Daroussin { 2307295610fSBaptiste Daroussin abort(); 2317295610fSBaptiste Daroussin } 2327295610fSBaptiste Daroussin 2337295610fSBaptiste Daroussin static int 23461d06d6bSBaptiste Daroussin pre_ign(DECL_ARGS) 23561d06d6bSBaptiste Daroussin { 23661d06d6bSBaptiste Daroussin return 0; 23761d06d6bSBaptiste Daroussin } 23861d06d6bSBaptiste Daroussin 23961d06d6bSBaptiste Daroussin static int 24061d06d6bSBaptiste Daroussin pre_I(DECL_ARGS) 24161d06d6bSBaptiste Daroussin { 24261d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 24361d06d6bSBaptiste Daroussin return 1; 24461d06d6bSBaptiste Daroussin } 24561d06d6bSBaptiste Daroussin 24661d06d6bSBaptiste Daroussin static int 24761d06d6bSBaptiste Daroussin pre_literal(DECL_ARGS) 24861d06d6bSBaptiste Daroussin { 24961d06d6bSBaptiste Daroussin term_newln(p); 25061d06d6bSBaptiste Daroussin 25161d06d6bSBaptiste Daroussin /* 25261d06d6bSBaptiste Daroussin * Unlike .IP and .TP, .HP does not have a HEAD. 25361d06d6bSBaptiste Daroussin * So in case a second call to term_flushln() is needed, 25461d06d6bSBaptiste Daroussin * indentation has to be set up explicitly. 25561d06d6bSBaptiste Daroussin */ 25661d06d6bSBaptiste Daroussin if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) { 25761d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 25861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 25961d06d6bSBaptiste Daroussin p->trailspace = 0; 26061d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 26161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 26261d06d6bSBaptiste Daroussin } 26361d06d6bSBaptiste Daroussin return 0; 26461d06d6bSBaptiste Daroussin } 26561d06d6bSBaptiste Daroussin 26661d06d6bSBaptiste Daroussin static int 26761d06d6bSBaptiste Daroussin pre_PD(DECL_ARGS) 26861d06d6bSBaptiste Daroussin { 26961d06d6bSBaptiste Daroussin struct roffsu su; 27061d06d6bSBaptiste Daroussin 27161d06d6bSBaptiste Daroussin n = n->child; 27261d06d6bSBaptiste Daroussin if (n == NULL) { 27361d06d6bSBaptiste Daroussin mt->pardist = 1; 27461d06d6bSBaptiste Daroussin return 0; 27561d06d6bSBaptiste Daroussin } 27661d06d6bSBaptiste Daroussin assert(n->type == ROFFT_TEXT); 27761d06d6bSBaptiste Daroussin if (a2roffsu(n->string, &su, SCALE_VS) != NULL) 27861d06d6bSBaptiste Daroussin mt->pardist = term_vspan(p, &su); 27961d06d6bSBaptiste Daroussin return 0; 28061d06d6bSBaptiste Daroussin } 28161d06d6bSBaptiste Daroussin 28261d06d6bSBaptiste Daroussin static int 28361d06d6bSBaptiste Daroussin pre_alternate(DECL_ARGS) 28461d06d6bSBaptiste Daroussin { 28561d06d6bSBaptiste Daroussin enum termfont font[2]; 28661d06d6bSBaptiste Daroussin struct roff_node *nn; 2877295610fSBaptiste Daroussin int i; 28861d06d6bSBaptiste Daroussin 28961d06d6bSBaptiste Daroussin switch (n->tok) { 29061d06d6bSBaptiste Daroussin case MAN_RB: 29161d06d6bSBaptiste Daroussin font[0] = TERMFONT_NONE; 29261d06d6bSBaptiste Daroussin font[1] = TERMFONT_BOLD; 29361d06d6bSBaptiste Daroussin break; 29461d06d6bSBaptiste Daroussin case MAN_RI: 29561d06d6bSBaptiste Daroussin font[0] = TERMFONT_NONE; 29661d06d6bSBaptiste Daroussin font[1] = TERMFONT_UNDER; 29761d06d6bSBaptiste Daroussin break; 29861d06d6bSBaptiste Daroussin case MAN_BR: 29961d06d6bSBaptiste Daroussin font[0] = TERMFONT_BOLD; 30061d06d6bSBaptiste Daroussin font[1] = TERMFONT_NONE; 30161d06d6bSBaptiste Daroussin break; 30261d06d6bSBaptiste Daroussin case MAN_BI: 30361d06d6bSBaptiste Daroussin font[0] = TERMFONT_BOLD; 30461d06d6bSBaptiste Daroussin font[1] = TERMFONT_UNDER; 30561d06d6bSBaptiste Daroussin break; 30661d06d6bSBaptiste Daroussin case MAN_IR: 30761d06d6bSBaptiste Daroussin font[0] = TERMFONT_UNDER; 30861d06d6bSBaptiste Daroussin font[1] = TERMFONT_NONE; 30961d06d6bSBaptiste Daroussin break; 31061d06d6bSBaptiste Daroussin case MAN_IB: 31161d06d6bSBaptiste Daroussin font[0] = TERMFONT_UNDER; 31261d06d6bSBaptiste Daroussin font[1] = TERMFONT_BOLD; 31361d06d6bSBaptiste Daroussin break; 31461d06d6bSBaptiste Daroussin default: 31561d06d6bSBaptiste Daroussin abort(); 31661d06d6bSBaptiste Daroussin } 3177295610fSBaptiste Daroussin for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) { 31861d06d6bSBaptiste Daroussin term_fontrepl(p, font[i]); 31961d06d6bSBaptiste Daroussin assert(nn->type == ROFFT_TEXT); 32061d06d6bSBaptiste Daroussin term_word(p, nn->string); 32161d06d6bSBaptiste Daroussin if (nn->flags & NODE_EOS) 32261d06d6bSBaptiste Daroussin p->flags |= TERMP_SENTENCE; 3237295610fSBaptiste Daroussin if (nn->next != NULL) 32461d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 32561d06d6bSBaptiste Daroussin } 32661d06d6bSBaptiste Daroussin return 0; 32761d06d6bSBaptiste Daroussin } 32861d06d6bSBaptiste Daroussin 32961d06d6bSBaptiste Daroussin static int 33061d06d6bSBaptiste Daroussin pre_B(DECL_ARGS) 33161d06d6bSBaptiste Daroussin { 33261d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 33361d06d6bSBaptiste Daroussin return 1; 33461d06d6bSBaptiste Daroussin } 33561d06d6bSBaptiste Daroussin 33661d06d6bSBaptiste Daroussin static int 33761d06d6bSBaptiste Daroussin pre_OP(DECL_ARGS) 33861d06d6bSBaptiste Daroussin { 33961d06d6bSBaptiste Daroussin term_word(p, "["); 3407295610fSBaptiste Daroussin p->flags |= TERMP_KEEP | TERMP_NOSPACE; 34161d06d6bSBaptiste Daroussin 3427295610fSBaptiste Daroussin if ((n = n->child) != NULL) { 34361d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 34461d06d6bSBaptiste Daroussin term_word(p, n->string); 34561d06d6bSBaptiste Daroussin } 3467295610fSBaptiste Daroussin if (n != NULL && n->next != NULL) { 34761d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 34861d06d6bSBaptiste Daroussin term_word(p, n->next->string); 34961d06d6bSBaptiste Daroussin } 35061d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 3517295610fSBaptiste Daroussin p->flags &= ~TERMP_KEEP; 35261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 35361d06d6bSBaptiste Daroussin term_word(p, "]"); 35461d06d6bSBaptiste Daroussin return 0; 35561d06d6bSBaptiste Daroussin } 35661d06d6bSBaptiste Daroussin 35761d06d6bSBaptiste Daroussin static int 35861d06d6bSBaptiste Daroussin pre_in(DECL_ARGS) 35961d06d6bSBaptiste Daroussin { 36061d06d6bSBaptiste Daroussin struct roffsu su; 36161d06d6bSBaptiste Daroussin const char *cp; 36261d06d6bSBaptiste Daroussin size_t v; 36361d06d6bSBaptiste Daroussin int less; 36461d06d6bSBaptiste Daroussin 36561d06d6bSBaptiste Daroussin term_newln(p); 36661d06d6bSBaptiste Daroussin 36761d06d6bSBaptiste Daroussin if (n->child == NULL) { 36861d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 36961d06d6bSBaptiste Daroussin return 0; 37061d06d6bSBaptiste Daroussin } 37161d06d6bSBaptiste Daroussin 37261d06d6bSBaptiste Daroussin cp = n->child->string; 37361d06d6bSBaptiste Daroussin less = 0; 37461d06d6bSBaptiste Daroussin 3757295610fSBaptiste Daroussin if (*cp == '-') 37661d06d6bSBaptiste Daroussin less = -1; 3777295610fSBaptiste Daroussin else if (*cp == '+') 37861d06d6bSBaptiste Daroussin less = 1; 37961d06d6bSBaptiste Daroussin else 38061d06d6bSBaptiste Daroussin cp--; 38161d06d6bSBaptiste Daroussin 38261d06d6bSBaptiste Daroussin if (a2roffsu(++cp, &su, SCALE_EN) == NULL) 38361d06d6bSBaptiste Daroussin return 0; 38461d06d6bSBaptiste Daroussin 38561d06d6bSBaptiste Daroussin v = term_hen(p, &su); 38661d06d6bSBaptiste Daroussin 38761d06d6bSBaptiste Daroussin if (less < 0) 38861d06d6bSBaptiste Daroussin p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset; 38961d06d6bSBaptiste Daroussin else if (less > 0) 39061d06d6bSBaptiste Daroussin p->tcol->offset += v; 39161d06d6bSBaptiste Daroussin else 39261d06d6bSBaptiste Daroussin p->tcol->offset = v; 39361d06d6bSBaptiste Daroussin if (p->tcol->offset > SHRT_MAX) 39461d06d6bSBaptiste Daroussin p->tcol->offset = term_len(p, p->defindent); 39561d06d6bSBaptiste Daroussin 39661d06d6bSBaptiste Daroussin return 0; 39761d06d6bSBaptiste Daroussin } 39861d06d6bSBaptiste Daroussin 39961d06d6bSBaptiste Daroussin static int 40061d06d6bSBaptiste Daroussin pre_DT(DECL_ARGS) 40161d06d6bSBaptiste Daroussin { 40261d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 40361d06d6bSBaptiste Daroussin term_tab_set(p, "T"); 40461d06d6bSBaptiste Daroussin term_tab_set(p, ".5i"); 40561d06d6bSBaptiste Daroussin return 0; 40661d06d6bSBaptiste Daroussin } 40761d06d6bSBaptiste Daroussin 40861d06d6bSBaptiste Daroussin static int 40961d06d6bSBaptiste Daroussin pre_HP(DECL_ARGS) 41061d06d6bSBaptiste Daroussin { 41161d06d6bSBaptiste Daroussin struct roffsu su; 41261d06d6bSBaptiste Daroussin const struct roff_node *nn; 41361d06d6bSBaptiste Daroussin int len; 41461d06d6bSBaptiste Daroussin 41561d06d6bSBaptiste Daroussin switch (n->type) { 41661d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 41761d06d6bSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 41861d06d6bSBaptiste Daroussin return 1; 4197295610fSBaptiste Daroussin case ROFFT_HEAD: 4207295610fSBaptiste Daroussin return 0; 42161d06d6bSBaptiste Daroussin case ROFFT_BODY: 42261d06d6bSBaptiste Daroussin break; 42361d06d6bSBaptiste Daroussin default: 4247295610fSBaptiste Daroussin abort(); 42561d06d6bSBaptiste Daroussin } 42661d06d6bSBaptiste Daroussin 4277295610fSBaptiste Daroussin if (n->child == NULL) 4287295610fSBaptiste Daroussin return 0; 4297295610fSBaptiste Daroussin 4307295610fSBaptiste Daroussin if ((n->child->flags & NODE_NOFILL) == 0) { 43161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 43261d06d6bSBaptiste Daroussin p->trailspace = 2; 43361d06d6bSBaptiste Daroussin } 43461d06d6bSBaptiste Daroussin 43561d06d6bSBaptiste Daroussin /* Calculate offset. */ 43661d06d6bSBaptiste Daroussin 43761d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 43861d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 43961d06d6bSBaptiste Daroussin len = term_hen(p, &su); 44061d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 44161d06d6bSBaptiste Daroussin len = -mt->offset; 44261d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 44361d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 44461d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 44561d06d6bSBaptiste Daroussin } else 44661d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 44761d06d6bSBaptiste Daroussin 44861d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 44961d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 45061d06d6bSBaptiste Daroussin return 1; 45161d06d6bSBaptiste Daroussin } 45261d06d6bSBaptiste Daroussin 45361d06d6bSBaptiste Daroussin static void 45461d06d6bSBaptiste Daroussin post_HP(DECL_ARGS) 45561d06d6bSBaptiste Daroussin { 45661d06d6bSBaptiste Daroussin switch (n->type) { 4577295610fSBaptiste Daroussin case ROFFT_BLOCK: 4587295610fSBaptiste Daroussin case ROFFT_HEAD: 4597295610fSBaptiste Daroussin break; 46061d06d6bSBaptiste Daroussin case ROFFT_BODY: 46161d06d6bSBaptiste Daroussin term_newln(p); 46261d06d6bSBaptiste Daroussin 46361d06d6bSBaptiste Daroussin /* 46461d06d6bSBaptiste Daroussin * Compatibility with a groff bug. 46561d06d6bSBaptiste Daroussin * The .HP macro uses the undocumented .tag request 46661d06d6bSBaptiste Daroussin * which causes a line break and cancels no-space 46761d06d6bSBaptiste Daroussin * mode even if there isn't any output. 46861d06d6bSBaptiste Daroussin */ 46961d06d6bSBaptiste Daroussin 47061d06d6bSBaptiste Daroussin if (n->child == NULL) 47161d06d6bSBaptiste Daroussin term_vspace(p); 47261d06d6bSBaptiste Daroussin 47361d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 47461d06d6bSBaptiste Daroussin p->trailspace = 0; 47561d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 47661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 47761d06d6bSBaptiste Daroussin break; 47861d06d6bSBaptiste Daroussin default: 4797295610fSBaptiste Daroussin abort(); 48061d06d6bSBaptiste Daroussin } 48161d06d6bSBaptiste Daroussin } 48261d06d6bSBaptiste Daroussin 48361d06d6bSBaptiste Daroussin static int 48461d06d6bSBaptiste Daroussin pre_PP(DECL_ARGS) 48561d06d6bSBaptiste Daroussin { 48661d06d6bSBaptiste Daroussin switch (n->type) { 48761d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 48861d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 48961d06d6bSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 49061d06d6bSBaptiste Daroussin break; 4917295610fSBaptiste Daroussin case ROFFT_HEAD: 4927295610fSBaptiste Daroussin return 0; 4937295610fSBaptiste Daroussin case ROFFT_BODY: 49461d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 49561d06d6bSBaptiste Daroussin break; 4967295610fSBaptiste Daroussin default: 4977295610fSBaptiste Daroussin abort(); 49861d06d6bSBaptiste Daroussin } 4997295610fSBaptiste Daroussin return 1; 50061d06d6bSBaptiste Daroussin } 50161d06d6bSBaptiste Daroussin 50261d06d6bSBaptiste Daroussin static int 50361d06d6bSBaptiste Daroussin pre_IP(DECL_ARGS) 50461d06d6bSBaptiste Daroussin { 50561d06d6bSBaptiste Daroussin struct roffsu su; 50661d06d6bSBaptiste Daroussin const struct roff_node *nn; 5077295610fSBaptiste Daroussin int len; 50861d06d6bSBaptiste Daroussin 50961d06d6bSBaptiste Daroussin switch (n->type) { 5107295610fSBaptiste Daroussin case ROFFT_BLOCK: 5117295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 5127295610fSBaptiste Daroussin return 1; 51361d06d6bSBaptiste Daroussin case ROFFT_HEAD: 51461d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 51561d06d6bSBaptiste Daroussin p->trailspace = 1; 51661d06d6bSBaptiste Daroussin break; 5177295610fSBaptiste Daroussin case ROFFT_BODY: 5187295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 5197295610fSBaptiste Daroussin break; 52061d06d6bSBaptiste Daroussin default: 5217295610fSBaptiste Daroussin abort(); 52261d06d6bSBaptiste Daroussin } 52361d06d6bSBaptiste Daroussin 52461d06d6bSBaptiste Daroussin /* Calculate the offset from the optional second argument. */ 52561d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 52661d06d6bSBaptiste Daroussin (nn = nn->next) != NULL && 52761d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 52861d06d6bSBaptiste Daroussin len = term_hen(p, &su); 52961d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 53061d06d6bSBaptiste Daroussin len = -mt->offset; 53161d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 53261d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 53361d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 53461d06d6bSBaptiste Daroussin } else 53561d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 53661d06d6bSBaptiste Daroussin 53761d06d6bSBaptiste Daroussin switch (n->type) { 53861d06d6bSBaptiste Daroussin case ROFFT_HEAD: 53961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 54061d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 541*45a5aec3SBaptiste Daroussin if (n->child != NULL) { 54261d06d6bSBaptiste Daroussin print_man_node(p, mt, n->child, meta); 543*45a5aec3SBaptiste Daroussin tag_man(p, n->child); 544*45a5aec3SBaptiste Daroussin } 54561d06d6bSBaptiste Daroussin return 0; 54661d06d6bSBaptiste Daroussin case ROFFT_BODY: 54761d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset + len; 54861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 54961d06d6bSBaptiste Daroussin break; 55061d06d6bSBaptiste Daroussin default: 5517295610fSBaptiste Daroussin abort(); 55261d06d6bSBaptiste Daroussin } 55361d06d6bSBaptiste Daroussin return 1; 55461d06d6bSBaptiste Daroussin } 55561d06d6bSBaptiste Daroussin 55661d06d6bSBaptiste Daroussin static void 55761d06d6bSBaptiste Daroussin post_IP(DECL_ARGS) 55861d06d6bSBaptiste Daroussin { 55961d06d6bSBaptiste Daroussin switch (n->type) { 5607295610fSBaptiste Daroussin case ROFFT_BLOCK: 5617295610fSBaptiste Daroussin break; 56261d06d6bSBaptiste Daroussin case ROFFT_HEAD: 56361d06d6bSBaptiste Daroussin term_flushln(p); 56461d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 56561d06d6bSBaptiste Daroussin p->trailspace = 0; 56661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 56761d06d6bSBaptiste Daroussin break; 56861d06d6bSBaptiste Daroussin case ROFFT_BODY: 56961d06d6bSBaptiste Daroussin term_newln(p); 57061d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 57161d06d6bSBaptiste Daroussin break; 57261d06d6bSBaptiste Daroussin default: 5737295610fSBaptiste Daroussin abort(); 57461d06d6bSBaptiste Daroussin } 57561d06d6bSBaptiste Daroussin } 57661d06d6bSBaptiste Daroussin 57761d06d6bSBaptiste Daroussin static int 57861d06d6bSBaptiste Daroussin pre_TP(DECL_ARGS) 57961d06d6bSBaptiste Daroussin { 58061d06d6bSBaptiste Daroussin struct roffsu su; 58161d06d6bSBaptiste Daroussin struct roff_node *nn; 5827295610fSBaptiste Daroussin int len; 58361d06d6bSBaptiste Daroussin 58461d06d6bSBaptiste Daroussin switch (n->type) { 5857295610fSBaptiste Daroussin case ROFFT_BLOCK: 5867295610fSBaptiste Daroussin if (n->tok == MAN_TP) 5877295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 5887295610fSBaptiste Daroussin return 1; 58961d06d6bSBaptiste Daroussin case ROFFT_HEAD: 59061d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRTRSP; 59161d06d6bSBaptiste Daroussin p->trailspace = 1; 59261d06d6bSBaptiste Daroussin break; 59361d06d6bSBaptiste Daroussin case ROFFT_BODY: 59461d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 59561d06d6bSBaptiste Daroussin break; 59661d06d6bSBaptiste Daroussin default: 5977295610fSBaptiste Daroussin abort(); 59861d06d6bSBaptiste Daroussin } 59961d06d6bSBaptiste Daroussin 60061d06d6bSBaptiste Daroussin /* Calculate offset. */ 60161d06d6bSBaptiste Daroussin 60261d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 60361d06d6bSBaptiste Daroussin nn->string != NULL && ! (NODE_LINE & nn->flags) && 60461d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 60561d06d6bSBaptiste Daroussin len = term_hen(p, &su); 60661d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 60761d06d6bSBaptiste Daroussin len = -mt->offset; 60861d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 60961d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 61061d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 61161d06d6bSBaptiste Daroussin } else 61261d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 61361d06d6bSBaptiste Daroussin 61461d06d6bSBaptiste Daroussin switch (n->type) { 61561d06d6bSBaptiste Daroussin case ROFFT_HEAD: 61661d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 61761d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 61861d06d6bSBaptiste Daroussin 61961d06d6bSBaptiste Daroussin /* Don't print same-line elements. */ 62061d06d6bSBaptiste Daroussin nn = n->child; 6217295610fSBaptiste Daroussin while (nn != NULL && (nn->flags & NODE_LINE) == 0) 62261d06d6bSBaptiste Daroussin nn = nn->next; 62361d06d6bSBaptiste Daroussin 624*45a5aec3SBaptiste Daroussin if (nn == NULL) 625*45a5aec3SBaptiste Daroussin return 0; 626*45a5aec3SBaptiste Daroussin 627*45a5aec3SBaptiste Daroussin if (nn->type == ROFFT_TEXT) 628*45a5aec3SBaptiste Daroussin tag_man(p, nn); 629*45a5aec3SBaptiste Daroussin else if (nn->child != NULL && 630*45a5aec3SBaptiste Daroussin nn->child->type == ROFFT_TEXT && 631*45a5aec3SBaptiste Daroussin (nn->tok == MAN_B || nn->tok == MAN_BI || 632*45a5aec3SBaptiste Daroussin nn->tok == MAN_BR || nn->tok == MAN_I || 633*45a5aec3SBaptiste Daroussin nn->tok == MAN_IB || nn->tok == MAN_IR)) 634*45a5aec3SBaptiste Daroussin tag_man(p, nn->child); 635*45a5aec3SBaptiste Daroussin 6367295610fSBaptiste Daroussin while (nn != NULL) { 63761d06d6bSBaptiste Daroussin print_man_node(p, mt, nn, meta); 63861d06d6bSBaptiste Daroussin nn = nn->next; 63961d06d6bSBaptiste Daroussin } 64061d06d6bSBaptiste Daroussin return 0; 64161d06d6bSBaptiste Daroussin case ROFFT_BODY: 64261d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset + len; 64361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 64461d06d6bSBaptiste Daroussin p->trailspace = 0; 64561d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP); 64661d06d6bSBaptiste Daroussin break; 64761d06d6bSBaptiste Daroussin default: 6487295610fSBaptiste Daroussin abort(); 64961d06d6bSBaptiste Daroussin } 65061d06d6bSBaptiste Daroussin return 1; 65161d06d6bSBaptiste Daroussin } 65261d06d6bSBaptiste Daroussin 65361d06d6bSBaptiste Daroussin static void 65461d06d6bSBaptiste Daroussin post_TP(DECL_ARGS) 65561d06d6bSBaptiste Daroussin { 65661d06d6bSBaptiste Daroussin switch (n->type) { 6577295610fSBaptiste Daroussin case ROFFT_BLOCK: 6587295610fSBaptiste Daroussin break; 65961d06d6bSBaptiste Daroussin case ROFFT_HEAD: 66061d06d6bSBaptiste Daroussin term_flushln(p); 66161d06d6bSBaptiste Daroussin break; 66261d06d6bSBaptiste Daroussin case ROFFT_BODY: 66361d06d6bSBaptiste Daroussin term_newln(p); 66461d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 66561d06d6bSBaptiste Daroussin break; 66661d06d6bSBaptiste Daroussin default: 6677295610fSBaptiste Daroussin abort(); 66861d06d6bSBaptiste Daroussin } 66961d06d6bSBaptiste Daroussin } 67061d06d6bSBaptiste Daroussin 67161d06d6bSBaptiste Daroussin static int 67261d06d6bSBaptiste Daroussin pre_SS(DECL_ARGS) 67361d06d6bSBaptiste Daroussin { 67461d06d6bSBaptiste Daroussin int i; 67561d06d6bSBaptiste Daroussin 67661d06d6bSBaptiste Daroussin switch (n->type) { 67761d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 67861d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 67961d06d6bSBaptiste Daroussin mt->offset = term_len(p, p->defindent); 68061d06d6bSBaptiste Daroussin 68161d06d6bSBaptiste Daroussin /* 68261d06d6bSBaptiste Daroussin * No vertical space before the first subsection 68361d06d6bSBaptiste Daroussin * and after an empty subsection. 68461d06d6bSBaptiste Daroussin */ 68561d06d6bSBaptiste Daroussin 68661d06d6bSBaptiste Daroussin do { 68761d06d6bSBaptiste Daroussin n = n->prev; 68861d06d6bSBaptiste Daroussin } while (n != NULL && n->tok >= MAN_TH && 6897295610fSBaptiste Daroussin man_term_act(n->tok)->flags & MAN_NOTEXT); 69061d06d6bSBaptiste Daroussin if (n == NULL || n->type == ROFFT_COMMENT || 69161d06d6bSBaptiste Daroussin (n->tok == MAN_SS && n->body->child == NULL)) 69261d06d6bSBaptiste Daroussin break; 69361d06d6bSBaptiste Daroussin 69461d06d6bSBaptiste Daroussin for (i = 0; i < mt->pardist; i++) 69561d06d6bSBaptiste Daroussin term_vspace(p); 69661d06d6bSBaptiste Daroussin break; 69761d06d6bSBaptiste Daroussin case ROFFT_HEAD: 69861d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 69961d06d6bSBaptiste Daroussin p->tcol->offset = term_len(p, 3); 70061d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset; 70161d06d6bSBaptiste Daroussin p->trailspace = mt->offset; 70261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 70361d06d6bSBaptiste Daroussin break; 70461d06d6bSBaptiste Daroussin case ROFFT_BODY: 70561d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 70661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 70761d06d6bSBaptiste Daroussin p->trailspace = 0; 70861d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 70961d06d6bSBaptiste Daroussin break; 71061d06d6bSBaptiste Daroussin default: 71161d06d6bSBaptiste Daroussin break; 71261d06d6bSBaptiste Daroussin } 71361d06d6bSBaptiste Daroussin return 1; 71461d06d6bSBaptiste Daroussin } 71561d06d6bSBaptiste Daroussin 71661d06d6bSBaptiste Daroussin static int 71761d06d6bSBaptiste Daroussin pre_SH(DECL_ARGS) 71861d06d6bSBaptiste Daroussin { 71961d06d6bSBaptiste Daroussin int i; 72061d06d6bSBaptiste Daroussin 72161d06d6bSBaptiste Daroussin switch (n->type) { 72261d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 72361d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 72461d06d6bSBaptiste Daroussin mt->offset = term_len(p, p->defindent); 72561d06d6bSBaptiste Daroussin 72661d06d6bSBaptiste Daroussin /* 72761d06d6bSBaptiste Daroussin * No vertical space before the first section 72861d06d6bSBaptiste Daroussin * and after an empty section. 72961d06d6bSBaptiste Daroussin */ 73061d06d6bSBaptiste Daroussin 73161d06d6bSBaptiste Daroussin do { 73261d06d6bSBaptiste Daroussin n = n->prev; 73361d06d6bSBaptiste Daroussin } while (n != NULL && n->tok >= MAN_TH && 7347295610fSBaptiste Daroussin man_term_act(n->tok)->flags & MAN_NOTEXT); 73561d06d6bSBaptiste Daroussin if (n == NULL || n->type == ROFFT_COMMENT || 73661d06d6bSBaptiste Daroussin (n->tok == MAN_SH && n->body->child == NULL)) 73761d06d6bSBaptiste Daroussin break; 73861d06d6bSBaptiste Daroussin 73961d06d6bSBaptiste Daroussin for (i = 0; i < mt->pardist; i++) 74061d06d6bSBaptiste Daroussin term_vspace(p); 74161d06d6bSBaptiste Daroussin break; 74261d06d6bSBaptiste Daroussin case ROFFT_HEAD: 74361d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 74461d06d6bSBaptiste Daroussin p->tcol->offset = 0; 74561d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset; 74661d06d6bSBaptiste Daroussin p->trailspace = mt->offset; 74761d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 74861d06d6bSBaptiste Daroussin break; 74961d06d6bSBaptiste Daroussin case ROFFT_BODY: 75061d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 75161d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 75261d06d6bSBaptiste Daroussin p->trailspace = 0; 75361d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 75461d06d6bSBaptiste Daroussin break; 75561d06d6bSBaptiste Daroussin default: 7567295610fSBaptiste Daroussin abort(); 75761d06d6bSBaptiste Daroussin } 75861d06d6bSBaptiste Daroussin return 1; 75961d06d6bSBaptiste Daroussin } 76061d06d6bSBaptiste Daroussin 76161d06d6bSBaptiste Daroussin static void 76261d06d6bSBaptiste Daroussin post_SH(DECL_ARGS) 76361d06d6bSBaptiste Daroussin { 76461d06d6bSBaptiste Daroussin switch (n->type) { 7657295610fSBaptiste Daroussin case ROFFT_BLOCK: 76661d06d6bSBaptiste Daroussin break; 7677295610fSBaptiste Daroussin case ROFFT_HEAD: 76861d06d6bSBaptiste Daroussin case ROFFT_BODY: 76961d06d6bSBaptiste Daroussin term_newln(p); 77061d06d6bSBaptiste Daroussin break; 77161d06d6bSBaptiste Daroussin default: 7727295610fSBaptiste Daroussin abort(); 77361d06d6bSBaptiste Daroussin } 77461d06d6bSBaptiste Daroussin } 77561d06d6bSBaptiste Daroussin 77661d06d6bSBaptiste Daroussin static int 77761d06d6bSBaptiste Daroussin pre_RS(DECL_ARGS) 77861d06d6bSBaptiste Daroussin { 77961d06d6bSBaptiste Daroussin struct roffsu su; 78061d06d6bSBaptiste Daroussin 78161d06d6bSBaptiste Daroussin switch (n->type) { 78261d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 78361d06d6bSBaptiste Daroussin term_newln(p); 78461d06d6bSBaptiste Daroussin return 1; 78561d06d6bSBaptiste Daroussin case ROFFT_HEAD: 78661d06d6bSBaptiste Daroussin return 0; 7877295610fSBaptiste Daroussin case ROFFT_BODY: 78861d06d6bSBaptiste Daroussin break; 7897295610fSBaptiste Daroussin default: 7907295610fSBaptiste Daroussin abort(); 79161d06d6bSBaptiste Daroussin } 79261d06d6bSBaptiste Daroussin 79361d06d6bSBaptiste Daroussin n = n->parent->head; 79461d06d6bSBaptiste Daroussin n->aux = SHRT_MAX + 1; 79561d06d6bSBaptiste Daroussin if (n->child == NULL) 79661d06d6bSBaptiste Daroussin n->aux = mt->lmargin[mt->lmargincur]; 79761d06d6bSBaptiste Daroussin else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL) 79861d06d6bSBaptiste Daroussin n->aux = term_hen(p, &su); 79961d06d6bSBaptiste Daroussin if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) 80061d06d6bSBaptiste Daroussin n->aux = -mt->offset; 80161d06d6bSBaptiste Daroussin else if (n->aux > SHRT_MAX) 80261d06d6bSBaptiste Daroussin n->aux = term_len(p, p->defindent); 80361d06d6bSBaptiste Daroussin 80461d06d6bSBaptiste Daroussin mt->offset += n->aux; 80561d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 80661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 80761d06d6bSBaptiste Daroussin 80861d06d6bSBaptiste Daroussin if (++mt->lmarginsz < MAXMARGINS) 80961d06d6bSBaptiste Daroussin mt->lmargincur = mt->lmarginsz; 81061d06d6bSBaptiste Daroussin 81161d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 81261d06d6bSBaptiste Daroussin return 1; 81361d06d6bSBaptiste Daroussin } 81461d06d6bSBaptiste Daroussin 81561d06d6bSBaptiste Daroussin static void 81661d06d6bSBaptiste Daroussin post_RS(DECL_ARGS) 81761d06d6bSBaptiste Daroussin { 81861d06d6bSBaptiste Daroussin switch (n->type) { 81961d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 82061d06d6bSBaptiste Daroussin case ROFFT_HEAD: 82161d06d6bSBaptiste Daroussin return; 8227295610fSBaptiste Daroussin case ROFFT_BODY: 82361d06d6bSBaptiste Daroussin break; 8247295610fSBaptiste Daroussin default: 8257295610fSBaptiste Daroussin abort(); 82661d06d6bSBaptiste Daroussin } 8277295610fSBaptiste Daroussin term_newln(p); 82861d06d6bSBaptiste Daroussin mt->offset -= n->parent->head->aux; 82961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 83061d06d6bSBaptiste Daroussin if (--mt->lmarginsz < MAXMARGINS) 83161d06d6bSBaptiste Daroussin mt->lmargincur = mt->lmarginsz; 83261d06d6bSBaptiste Daroussin } 83361d06d6bSBaptiste Daroussin 83461d06d6bSBaptiste Daroussin static int 8357295610fSBaptiste Daroussin pre_SY(DECL_ARGS) 8367295610fSBaptiste Daroussin { 8377295610fSBaptiste Daroussin const struct roff_node *nn; 8387295610fSBaptiste Daroussin int len; 8397295610fSBaptiste Daroussin 8407295610fSBaptiste Daroussin switch (n->type) { 8417295610fSBaptiste Daroussin case ROFFT_BLOCK: 8427295610fSBaptiste Daroussin if (n->prev == NULL || n->prev->tok != MAN_SY) 8437295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 8447295610fSBaptiste Daroussin return 1; 8457295610fSBaptiste Daroussin case ROFFT_HEAD: 8467295610fSBaptiste Daroussin case ROFFT_BODY: 8477295610fSBaptiste Daroussin break; 8487295610fSBaptiste Daroussin default: 8497295610fSBaptiste Daroussin abort(); 8507295610fSBaptiste Daroussin } 8517295610fSBaptiste Daroussin 8527295610fSBaptiste Daroussin nn = n->parent->head->child; 8537295610fSBaptiste Daroussin len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1; 8547295610fSBaptiste Daroussin 8557295610fSBaptiste Daroussin switch (n->type) { 8567295610fSBaptiste Daroussin case ROFFT_HEAD: 8577295610fSBaptiste Daroussin p->tcol->offset = mt->offset; 8587295610fSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 8597295610fSBaptiste Daroussin if (n->next->child == NULL || 8607295610fSBaptiste Daroussin (n->next->child->flags & NODE_NOFILL) == 0) 8617295610fSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 8627295610fSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 8637295610fSBaptiste Daroussin break; 8647295610fSBaptiste Daroussin case ROFFT_BODY: 8657295610fSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 8667295610fSBaptiste Daroussin p->tcol->offset = mt->offset + len; 8677295610fSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 8687295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 8697295610fSBaptiste Daroussin break; 8707295610fSBaptiste Daroussin default: 8717295610fSBaptiste Daroussin abort(); 8727295610fSBaptiste Daroussin } 8737295610fSBaptiste Daroussin return 1; 8747295610fSBaptiste Daroussin } 8757295610fSBaptiste Daroussin 8767295610fSBaptiste Daroussin static void 8777295610fSBaptiste Daroussin post_SY(DECL_ARGS) 8787295610fSBaptiste Daroussin { 8797295610fSBaptiste Daroussin switch (n->type) { 8807295610fSBaptiste Daroussin case ROFFT_BLOCK: 8817295610fSBaptiste Daroussin break; 8827295610fSBaptiste Daroussin case ROFFT_HEAD: 8837295610fSBaptiste Daroussin term_flushln(p); 8847295610fSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 8857295610fSBaptiste Daroussin break; 8867295610fSBaptiste Daroussin case ROFFT_BODY: 8877295610fSBaptiste Daroussin term_newln(p); 8887295610fSBaptiste Daroussin p->tcol->offset = mt->offset; 8897295610fSBaptiste Daroussin break; 8907295610fSBaptiste Daroussin default: 8917295610fSBaptiste Daroussin abort(); 8927295610fSBaptiste Daroussin } 8937295610fSBaptiste Daroussin } 8947295610fSBaptiste Daroussin 8957295610fSBaptiste Daroussin static int 89661d06d6bSBaptiste Daroussin pre_UR(DECL_ARGS) 89761d06d6bSBaptiste Daroussin { 89861d06d6bSBaptiste Daroussin return n->type != ROFFT_HEAD; 89961d06d6bSBaptiste Daroussin } 90061d06d6bSBaptiste Daroussin 90161d06d6bSBaptiste Daroussin static void 90261d06d6bSBaptiste Daroussin post_UR(DECL_ARGS) 90361d06d6bSBaptiste Daroussin { 90461d06d6bSBaptiste Daroussin if (n->type != ROFFT_BLOCK) 90561d06d6bSBaptiste Daroussin return; 90661d06d6bSBaptiste Daroussin 90761d06d6bSBaptiste Daroussin term_word(p, "<"); 90861d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 90961d06d6bSBaptiste Daroussin 9107295610fSBaptiste Daroussin if (n->child->child != NULL) 91161d06d6bSBaptiste Daroussin print_man_node(p, mt, n->child->child, meta); 91261d06d6bSBaptiste Daroussin 91361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 91461d06d6bSBaptiste Daroussin term_word(p, ">"); 91561d06d6bSBaptiste Daroussin } 91661d06d6bSBaptiste Daroussin 91761d06d6bSBaptiste Daroussin static void 91861d06d6bSBaptiste Daroussin print_man_node(DECL_ARGS) 91961d06d6bSBaptiste Daroussin { 9207295610fSBaptiste Daroussin const struct man_term_act *act; 92161d06d6bSBaptiste Daroussin int c; 92261d06d6bSBaptiste Daroussin 92361d06d6bSBaptiste Daroussin switch (n->type) { 92461d06d6bSBaptiste Daroussin case ROFFT_TEXT: 92561d06d6bSBaptiste Daroussin /* 92661d06d6bSBaptiste Daroussin * If we have a blank line, output a vertical space. 92761d06d6bSBaptiste Daroussin * If we have a space as the first character, break 92861d06d6bSBaptiste Daroussin * before printing the line's data. 92961d06d6bSBaptiste Daroussin */ 93061d06d6bSBaptiste Daroussin if (*n->string == '\0') { 93161d06d6bSBaptiste Daroussin if (p->flags & TERMP_NONEWLINE) 93261d06d6bSBaptiste Daroussin term_newln(p); 93361d06d6bSBaptiste Daroussin else 93461d06d6bSBaptiste Daroussin term_vspace(p); 93561d06d6bSBaptiste Daroussin return; 93661d06d6bSBaptiste Daroussin } else if (*n->string == ' ' && n->flags & NODE_LINE && 93761d06d6bSBaptiste Daroussin (p->flags & TERMP_NONEWLINE) == 0) 93861d06d6bSBaptiste Daroussin term_newln(p); 9397295610fSBaptiste Daroussin else if (n->flags & NODE_DELIMC) 9407295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 94161d06d6bSBaptiste Daroussin 94261d06d6bSBaptiste Daroussin term_word(p, n->string); 94361d06d6bSBaptiste Daroussin goto out; 94461d06d6bSBaptiste Daroussin case ROFFT_COMMENT: 94561d06d6bSBaptiste Daroussin return; 94661d06d6bSBaptiste Daroussin case ROFFT_EQN: 94761d06d6bSBaptiste Daroussin if ( ! (n->flags & NODE_LINE)) 94861d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 94961d06d6bSBaptiste Daroussin term_eqn(p, n->eqn); 95061d06d6bSBaptiste Daroussin if (n->next != NULL && ! (n->next->flags & NODE_LINE)) 95161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 95261d06d6bSBaptiste Daroussin return; 95361d06d6bSBaptiste Daroussin case ROFFT_TBL: 95461d06d6bSBaptiste Daroussin if (p->tbl.cols == NULL) 95561d06d6bSBaptiste Daroussin term_vspace(p); 95661d06d6bSBaptiste Daroussin term_tbl(p, n->span); 95761d06d6bSBaptiste Daroussin return; 95861d06d6bSBaptiste Daroussin default: 95961d06d6bSBaptiste Daroussin break; 96061d06d6bSBaptiste Daroussin } 96161d06d6bSBaptiste Daroussin 96261d06d6bSBaptiste Daroussin if (n->tok < ROFF_MAX) { 96361d06d6bSBaptiste Daroussin roff_term_pre(p, n); 96461d06d6bSBaptiste Daroussin return; 96561d06d6bSBaptiste Daroussin } 96661d06d6bSBaptiste Daroussin 9677295610fSBaptiste Daroussin act = man_term_act(n->tok); 9687295610fSBaptiste Daroussin if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) 96961d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 97061d06d6bSBaptiste Daroussin 97161d06d6bSBaptiste Daroussin c = 1; 9727295610fSBaptiste Daroussin if (act->pre != NULL) 9737295610fSBaptiste Daroussin c = (*act->pre)(p, mt, n, meta); 97461d06d6bSBaptiste Daroussin 9757295610fSBaptiste Daroussin if (c && n->child != NULL) 97661d06d6bSBaptiste Daroussin print_man_nodelist(p, mt, n->child, meta); 97761d06d6bSBaptiste Daroussin 9787295610fSBaptiste Daroussin if (act->post != NULL) 9797295610fSBaptiste Daroussin (*act->post)(p, mt, n, meta); 9807295610fSBaptiste Daroussin if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) 98161d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 98261d06d6bSBaptiste Daroussin 98361d06d6bSBaptiste Daroussin out: 98461d06d6bSBaptiste Daroussin /* 98561d06d6bSBaptiste Daroussin * If we're in a literal context, make sure that words 98661d06d6bSBaptiste Daroussin * together on the same line stay together. This is a 98761d06d6bSBaptiste Daroussin * POST-printing call, so we check the NEXT word. Since 98861d06d6bSBaptiste Daroussin * -man doesn't have nested macros, we don't need to be 98961d06d6bSBaptiste Daroussin * more specific than this. 99061d06d6bSBaptiste Daroussin */ 9917295610fSBaptiste Daroussin if (n->flags & NODE_NOFILL && 99261d06d6bSBaptiste Daroussin ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && 99361d06d6bSBaptiste Daroussin (n->next == NULL || n->next->flags & NODE_LINE)) { 99461d06d6bSBaptiste Daroussin p->flags |= TERMP_BRNEVER | TERMP_NOSPACE; 99561d06d6bSBaptiste Daroussin if (n->string != NULL && *n->string != '\0') 99661d06d6bSBaptiste Daroussin term_flushln(p); 99761d06d6bSBaptiste Daroussin else 99861d06d6bSBaptiste Daroussin term_newln(p); 99961d06d6bSBaptiste Daroussin p->flags &= ~TERMP_BRNEVER; 100061d06d6bSBaptiste Daroussin if (p->tcol->rmargin < p->maxrmargin && 100161d06d6bSBaptiste Daroussin n->parent->tok == MAN_HP) { 100261d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 100361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 100461d06d6bSBaptiste Daroussin } 100561d06d6bSBaptiste Daroussin } 10067295610fSBaptiste Daroussin if (n->flags & NODE_EOS) 100761d06d6bSBaptiste Daroussin p->flags |= TERMP_SENTENCE; 100861d06d6bSBaptiste Daroussin } 100961d06d6bSBaptiste Daroussin 101061d06d6bSBaptiste Daroussin static void 101161d06d6bSBaptiste Daroussin print_man_nodelist(DECL_ARGS) 101261d06d6bSBaptiste Daroussin { 101361d06d6bSBaptiste Daroussin while (n != NULL) { 101461d06d6bSBaptiste Daroussin print_man_node(p, mt, n, meta); 101561d06d6bSBaptiste Daroussin n = n->next; 101661d06d6bSBaptiste Daroussin } 101761d06d6bSBaptiste Daroussin } 101861d06d6bSBaptiste Daroussin 101961d06d6bSBaptiste Daroussin static void 102061d06d6bSBaptiste Daroussin print_man_foot(struct termp *p, const struct roff_meta *meta) 102161d06d6bSBaptiste Daroussin { 102261d06d6bSBaptiste Daroussin char *title; 102361d06d6bSBaptiste Daroussin size_t datelen, titlen; 102461d06d6bSBaptiste Daroussin 102561d06d6bSBaptiste Daroussin assert(meta->title); 102661d06d6bSBaptiste Daroussin assert(meta->msec); 102761d06d6bSBaptiste Daroussin assert(meta->date); 102861d06d6bSBaptiste Daroussin 102961d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 103061d06d6bSBaptiste Daroussin 103161d06d6bSBaptiste Daroussin if (meta->hasbody) 103261d06d6bSBaptiste Daroussin term_vspace(p); 103361d06d6bSBaptiste Daroussin 103461d06d6bSBaptiste Daroussin /* 103561d06d6bSBaptiste Daroussin * Temporary, undocumented option to imitate mdoc(7) output. 103661d06d6bSBaptiste Daroussin * In the bottom right corner, use the operating system 103761d06d6bSBaptiste Daroussin * instead of the title. 103861d06d6bSBaptiste Daroussin */ 103961d06d6bSBaptiste Daroussin 104061d06d6bSBaptiste Daroussin if ( ! p->mdocstyle) { 104161d06d6bSBaptiste Daroussin if (meta->hasbody) { 104261d06d6bSBaptiste Daroussin term_vspace(p); 104361d06d6bSBaptiste Daroussin term_vspace(p); 104461d06d6bSBaptiste Daroussin } 104561d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", 104661d06d6bSBaptiste Daroussin meta->title, meta->msec); 10477295610fSBaptiste Daroussin } else if (meta->os != NULL) { 104861d06d6bSBaptiste Daroussin title = mandoc_strdup(meta->os); 104961d06d6bSBaptiste Daroussin } else { 105061d06d6bSBaptiste Daroussin title = mandoc_strdup(""); 105161d06d6bSBaptiste Daroussin } 105261d06d6bSBaptiste Daroussin datelen = term_strlen(p, meta->date); 105361d06d6bSBaptiste Daroussin 105461d06d6bSBaptiste Daroussin /* Bottom left corner: operating system. */ 105561d06d6bSBaptiste Daroussin 105661d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 105761d06d6bSBaptiste Daroussin p->trailspace = 1; 105861d06d6bSBaptiste Daroussin p->tcol->offset = 0; 105961d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin > datelen ? 106061d06d6bSBaptiste Daroussin (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; 106161d06d6bSBaptiste Daroussin 106261d06d6bSBaptiste Daroussin if (meta->os) 106361d06d6bSBaptiste Daroussin term_word(p, meta->os); 106461d06d6bSBaptiste Daroussin term_flushln(p); 106561d06d6bSBaptiste Daroussin 106661d06d6bSBaptiste Daroussin /* At the bottom in the middle: manual date. */ 106761d06d6bSBaptiste Daroussin 106861d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 106961d06d6bSBaptiste Daroussin titlen = term_strlen(p, title); 107061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin > titlen ? 107161d06d6bSBaptiste Daroussin p->maxrmargin - titlen : 0; 107261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 107361d06d6bSBaptiste Daroussin 107461d06d6bSBaptiste Daroussin term_word(p, meta->date); 107561d06d6bSBaptiste Daroussin term_flushln(p); 107661d06d6bSBaptiste Daroussin 107761d06d6bSBaptiste Daroussin /* Bottom right corner: manual title and section. */ 107861d06d6bSBaptiste Daroussin 107961d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 108061d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 108161d06d6bSBaptiste Daroussin p->trailspace = 0; 108261d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 108361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 108461d06d6bSBaptiste Daroussin 108561d06d6bSBaptiste Daroussin term_word(p, title); 108661d06d6bSBaptiste Daroussin term_flushln(p); 108761d06d6bSBaptiste Daroussin 108861d06d6bSBaptiste Daroussin /* 108961d06d6bSBaptiste Daroussin * Reset the terminal state for more output after the footer: 109061d06d6bSBaptiste Daroussin * Some output modes, in particular PostScript and PDF, print 109161d06d6bSBaptiste Daroussin * the header and the footer into a buffer such that it can be 109261d06d6bSBaptiste Daroussin * reused for multiple output pages, then go on to format the 109361d06d6bSBaptiste Daroussin * main text. 109461d06d6bSBaptiste Daroussin */ 109561d06d6bSBaptiste Daroussin 109661d06d6bSBaptiste Daroussin p->tcol->offset = 0; 109761d06d6bSBaptiste Daroussin p->flags = 0; 109861d06d6bSBaptiste Daroussin 109961d06d6bSBaptiste Daroussin free(title); 110061d06d6bSBaptiste Daroussin } 110161d06d6bSBaptiste Daroussin 110261d06d6bSBaptiste Daroussin static void 110361d06d6bSBaptiste Daroussin print_man_head(struct termp *p, const struct roff_meta *meta) 110461d06d6bSBaptiste Daroussin { 110561d06d6bSBaptiste Daroussin const char *volume; 110661d06d6bSBaptiste Daroussin char *title; 110761d06d6bSBaptiste Daroussin size_t vollen, titlen; 110861d06d6bSBaptiste Daroussin 110961d06d6bSBaptiste Daroussin assert(meta->title); 111061d06d6bSBaptiste Daroussin assert(meta->msec); 111161d06d6bSBaptiste Daroussin 111261d06d6bSBaptiste Daroussin volume = NULL == meta->vol ? "" : meta->vol; 111361d06d6bSBaptiste Daroussin vollen = term_strlen(p, volume); 111461d06d6bSBaptiste Daroussin 111561d06d6bSBaptiste Daroussin /* Top left corner: manual title and section. */ 111661d06d6bSBaptiste Daroussin 111761d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); 111861d06d6bSBaptiste Daroussin titlen = term_strlen(p, title); 111961d06d6bSBaptiste Daroussin 112061d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; 112161d06d6bSBaptiste Daroussin p->trailspace = 1; 112261d06d6bSBaptiste Daroussin p->tcol->offset = 0; 112361d06d6bSBaptiste Daroussin p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? 112461d06d6bSBaptiste Daroussin (p->maxrmargin - vollen + term_len(p, 1)) / 2 : 112561d06d6bSBaptiste Daroussin vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; 112661d06d6bSBaptiste Daroussin 112761d06d6bSBaptiste Daroussin term_word(p, title); 112861d06d6bSBaptiste Daroussin term_flushln(p); 112961d06d6bSBaptiste Daroussin 113061d06d6bSBaptiste Daroussin /* At the top in the middle: manual volume. */ 113161d06d6bSBaptiste Daroussin 113261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 113361d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 113461d06d6bSBaptiste Daroussin p->tcol->rmargin = p->tcol->offset + vollen + titlen < 113561d06d6bSBaptiste Daroussin p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin; 113661d06d6bSBaptiste Daroussin 113761d06d6bSBaptiste Daroussin term_word(p, volume); 113861d06d6bSBaptiste Daroussin term_flushln(p); 113961d06d6bSBaptiste Daroussin 114061d06d6bSBaptiste Daroussin /* Top right corner: title and section, again. */ 114161d06d6bSBaptiste Daroussin 114261d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 114361d06d6bSBaptiste Daroussin p->trailspace = 0; 114461d06d6bSBaptiste Daroussin if (p->tcol->rmargin + titlen <= p->maxrmargin) { 114561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 114661d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 114761d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 114861d06d6bSBaptiste Daroussin term_word(p, title); 114961d06d6bSBaptiste Daroussin term_flushln(p); 115061d06d6bSBaptiste Daroussin } 115161d06d6bSBaptiste Daroussin 115261d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOSPACE; 115361d06d6bSBaptiste Daroussin p->tcol->offset = 0; 115461d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 115561d06d6bSBaptiste Daroussin 115661d06d6bSBaptiste Daroussin /* 115761d06d6bSBaptiste Daroussin * Groff prints three blank lines before the content. 115861d06d6bSBaptiste Daroussin * Do the same, except in the temporary, undocumented 115961d06d6bSBaptiste Daroussin * mode imitating mdoc(7) output. 116061d06d6bSBaptiste Daroussin */ 116161d06d6bSBaptiste Daroussin 116261d06d6bSBaptiste Daroussin term_vspace(p); 116361d06d6bSBaptiste Daroussin if ( ! p->mdocstyle) { 116461d06d6bSBaptiste Daroussin term_vspace(p); 116561d06d6bSBaptiste Daroussin term_vspace(p); 116661d06d6bSBaptiste Daroussin } 116761d06d6bSBaptiste Daroussin free(title); 116861d06d6bSBaptiste Daroussin } 1169*45a5aec3SBaptiste Daroussin 1170*45a5aec3SBaptiste Daroussin /* 1171*45a5aec3SBaptiste Daroussin * Skip leading whitespace, dashes, backslashes, and font escapes, 1172*45a5aec3SBaptiste Daroussin * then create a tag if the first following byte is a letter. 1173*45a5aec3SBaptiste Daroussin * Priority is high unless whitespace is present. 1174*45a5aec3SBaptiste Daroussin */ 1175*45a5aec3SBaptiste Daroussin static void 1176*45a5aec3SBaptiste Daroussin tag_man(struct termp *p, struct roff_node *n) 1177*45a5aec3SBaptiste Daroussin { 1178*45a5aec3SBaptiste Daroussin const char *cp, *arg; 1179*45a5aec3SBaptiste Daroussin int prio, sz; 1180*45a5aec3SBaptiste Daroussin 1181*45a5aec3SBaptiste Daroussin assert(n->type == ROFFT_TEXT); 1182*45a5aec3SBaptiste Daroussin cp = n->string; 1183*45a5aec3SBaptiste Daroussin prio = 1; 1184*45a5aec3SBaptiste Daroussin for (;;) { 1185*45a5aec3SBaptiste Daroussin switch (*cp) { 1186*45a5aec3SBaptiste Daroussin case ' ': 1187*45a5aec3SBaptiste Daroussin case '\t': 1188*45a5aec3SBaptiste Daroussin prio = INT_MAX; 1189*45a5aec3SBaptiste Daroussin /* FALLTHROUGH */ 1190*45a5aec3SBaptiste Daroussin case '-': 1191*45a5aec3SBaptiste Daroussin cp++; 1192*45a5aec3SBaptiste Daroussin break; 1193*45a5aec3SBaptiste Daroussin case '\\': 1194*45a5aec3SBaptiste Daroussin cp++; 1195*45a5aec3SBaptiste Daroussin switch (mandoc_escape(&cp, &arg, &sz)) { 1196*45a5aec3SBaptiste Daroussin case ESCAPE_FONT: 1197*45a5aec3SBaptiste Daroussin case ESCAPE_FONTROMAN: 1198*45a5aec3SBaptiste Daroussin case ESCAPE_FONTITALIC: 1199*45a5aec3SBaptiste Daroussin case ESCAPE_FONTBOLD: 1200*45a5aec3SBaptiste Daroussin case ESCAPE_FONTPREV: 1201*45a5aec3SBaptiste Daroussin case ESCAPE_FONTBI: 1202*45a5aec3SBaptiste Daroussin break; 1203*45a5aec3SBaptiste Daroussin case ESCAPE_SPECIAL: 1204*45a5aec3SBaptiste Daroussin if (sz != 1) 1205*45a5aec3SBaptiste Daroussin return; 1206*45a5aec3SBaptiste Daroussin switch (*arg) { 1207*45a5aec3SBaptiste Daroussin case '&': 1208*45a5aec3SBaptiste Daroussin case '-': 1209*45a5aec3SBaptiste Daroussin case 'e': 1210*45a5aec3SBaptiste Daroussin break; 1211*45a5aec3SBaptiste Daroussin default: 1212*45a5aec3SBaptiste Daroussin return; 1213*45a5aec3SBaptiste Daroussin } 1214*45a5aec3SBaptiste Daroussin break; 1215*45a5aec3SBaptiste Daroussin default: 1216*45a5aec3SBaptiste Daroussin return; 1217*45a5aec3SBaptiste Daroussin } 1218*45a5aec3SBaptiste Daroussin break; 1219*45a5aec3SBaptiste Daroussin default: 1220*45a5aec3SBaptiste Daroussin if (isalpha((unsigned char)*cp)) 1221*45a5aec3SBaptiste Daroussin tag_put(cp, prio, p->line); 1222*45a5aec3SBaptiste Daroussin return; 1223*45a5aec3SBaptiste Daroussin } 1224*45a5aec3SBaptiste Daroussin } 1225*45a5aec3SBaptiste Daroussin } 1226