1*6d38604fSBaptiste Daroussin /* $Id: man_term.c,v 1.236 2021/06/28 19:50:15 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 3*6d38604fSBaptiste Daroussin * Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org> 461d06d6bSBaptiste Daroussin * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 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. 17*6d38604fSBaptiste Daroussin * 18*6d38604fSBaptiste Daroussin * Plain text formatter for man(7), used by mandoc(1) 19*6d38604fSBaptiste Daroussin * for ASCII, UTF-8, PostScript, and PDF output. 2061d06d6bSBaptiste Daroussin */ 2161d06d6bSBaptiste Daroussin #include "config.h" 2261d06d6bSBaptiste Daroussin 2361d06d6bSBaptiste Daroussin #include <sys/types.h> 2461d06d6bSBaptiste Daroussin 2561d06d6bSBaptiste Daroussin #include <assert.h> 2661d06d6bSBaptiste Daroussin #include <ctype.h> 2761d06d6bSBaptiste Daroussin #include <limits.h> 2861d06d6bSBaptiste Daroussin #include <stdio.h> 2961d06d6bSBaptiste Daroussin #include <stdlib.h> 3061d06d6bSBaptiste Daroussin #include <string.h> 3161d06d6bSBaptiste Daroussin 3261d06d6bSBaptiste Daroussin #include "mandoc_aux.h" 3345a5aec3SBaptiste Daroussin #include "mandoc.h" 3461d06d6bSBaptiste Daroussin #include "roff.h" 3561d06d6bSBaptiste Daroussin #include "man.h" 3661d06d6bSBaptiste Daroussin #include "out.h" 3761d06d6bSBaptiste Daroussin #include "term.h" 38*6d38604fSBaptiste Daroussin #include "term_tag.h" 3961d06d6bSBaptiste Daroussin #include "main.h" 4061d06d6bSBaptiste Daroussin 4161d06d6bSBaptiste Daroussin #define MAXMARGINS 64 /* maximum number of indented scopes */ 4261d06d6bSBaptiste Daroussin 4361d06d6bSBaptiste Daroussin struct mtermp { 4461d06d6bSBaptiste Daroussin int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */ 4561d06d6bSBaptiste Daroussin int lmargincur; /* index of current margin */ 4661d06d6bSBaptiste Daroussin int lmarginsz; /* actual number of nested margins */ 4761d06d6bSBaptiste Daroussin size_t offset; /* default offset to visible page */ 4861d06d6bSBaptiste Daroussin int pardist; /* vert. space before par., unit: [v] */ 4961d06d6bSBaptiste Daroussin }; 5061d06d6bSBaptiste Daroussin 5161d06d6bSBaptiste Daroussin #define DECL_ARGS struct termp *p, \ 5261d06d6bSBaptiste Daroussin struct mtermp *mt, \ 5361d06d6bSBaptiste Daroussin struct roff_node *n, \ 5461d06d6bSBaptiste Daroussin const struct roff_meta *meta 5561d06d6bSBaptiste Daroussin 567295610fSBaptiste Daroussin struct man_term_act { 5761d06d6bSBaptiste Daroussin int (*pre)(DECL_ARGS); 5861d06d6bSBaptiste Daroussin void (*post)(DECL_ARGS); 5961d06d6bSBaptiste Daroussin int flags; 6061d06d6bSBaptiste Daroussin #define MAN_NOTEXT (1 << 0) /* Never has text children. */ 6161d06d6bSBaptiste Daroussin }; 6261d06d6bSBaptiste Daroussin 6361d06d6bSBaptiste Daroussin static void print_man_nodelist(DECL_ARGS); 6461d06d6bSBaptiste Daroussin static void print_man_node(DECL_ARGS); 6561d06d6bSBaptiste Daroussin static void print_man_head(struct termp *, 6661d06d6bSBaptiste Daroussin const struct roff_meta *); 6761d06d6bSBaptiste Daroussin static void print_man_foot(struct termp *, 6861d06d6bSBaptiste Daroussin const struct roff_meta *); 6961d06d6bSBaptiste Daroussin static void print_bvspace(struct termp *, 70*6d38604fSBaptiste Daroussin struct roff_node *, int); 7161d06d6bSBaptiste Daroussin 7261d06d6bSBaptiste Daroussin static int pre_B(DECL_ARGS); 7361d06d6bSBaptiste Daroussin static int pre_DT(DECL_ARGS); 7461d06d6bSBaptiste Daroussin static int pre_HP(DECL_ARGS); 7561d06d6bSBaptiste Daroussin static int pre_I(DECL_ARGS); 7661d06d6bSBaptiste Daroussin static int pre_IP(DECL_ARGS); 7761d06d6bSBaptiste Daroussin static int pre_OP(DECL_ARGS); 7861d06d6bSBaptiste Daroussin static int pre_PD(DECL_ARGS); 7961d06d6bSBaptiste Daroussin static int pre_PP(DECL_ARGS); 8061d06d6bSBaptiste Daroussin static int pre_RS(DECL_ARGS); 8161d06d6bSBaptiste Daroussin static int pre_SH(DECL_ARGS); 8261d06d6bSBaptiste Daroussin static int pre_SS(DECL_ARGS); 837295610fSBaptiste Daroussin static int pre_SY(DECL_ARGS); 8461d06d6bSBaptiste Daroussin static int pre_TP(DECL_ARGS); 8561d06d6bSBaptiste Daroussin static int pre_UR(DECL_ARGS); 867295610fSBaptiste Daroussin static int pre_abort(DECL_ARGS); 8761d06d6bSBaptiste Daroussin static int pre_alternate(DECL_ARGS); 8861d06d6bSBaptiste Daroussin static int pre_ign(DECL_ARGS); 8961d06d6bSBaptiste Daroussin static int pre_in(DECL_ARGS); 9061d06d6bSBaptiste Daroussin static int pre_literal(DECL_ARGS); 9161d06d6bSBaptiste Daroussin 9261d06d6bSBaptiste Daroussin static void post_IP(DECL_ARGS); 9361d06d6bSBaptiste Daroussin static void post_HP(DECL_ARGS); 9461d06d6bSBaptiste Daroussin static void post_RS(DECL_ARGS); 9561d06d6bSBaptiste Daroussin static void post_SH(DECL_ARGS); 967295610fSBaptiste Daroussin static void post_SY(DECL_ARGS); 9761d06d6bSBaptiste Daroussin static void post_TP(DECL_ARGS); 9861d06d6bSBaptiste Daroussin static void post_UR(DECL_ARGS); 9961d06d6bSBaptiste Daroussin 1007295610fSBaptiste Daroussin static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = { 10161d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* TH */ 10261d06d6bSBaptiste Daroussin { pre_SH, post_SH, 0 }, /* SH */ 1037295610fSBaptiste Daroussin { pre_SS, post_SH, 0 }, /* SS */ 10461d06d6bSBaptiste Daroussin { pre_TP, post_TP, 0 }, /* TP */ 1057295610fSBaptiste Daroussin { pre_TP, post_TP, 0 }, /* TQ */ 1067295610fSBaptiste Daroussin { pre_abort, NULL, 0 }, /* LP */ 10761d06d6bSBaptiste Daroussin { pre_PP, NULL, 0 }, /* PP */ 1087295610fSBaptiste Daroussin { pre_abort, NULL, 0 }, /* P */ 10961d06d6bSBaptiste Daroussin { pre_IP, post_IP, 0 }, /* IP */ 11061d06d6bSBaptiste Daroussin { pre_HP, post_HP, 0 }, /* HP */ 11161d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* SM */ 11261d06d6bSBaptiste Daroussin { pre_B, NULL, 0 }, /* SB */ 11361d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* BI */ 11461d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* IB */ 11561d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* BR */ 11661d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* RB */ 11761d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* R */ 11861d06d6bSBaptiste Daroussin { pre_B, NULL, 0 }, /* B */ 11961d06d6bSBaptiste Daroussin { pre_I, NULL, 0 }, /* I */ 12061d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* IR */ 12161d06d6bSBaptiste Daroussin { pre_alternate, NULL, 0 }, /* RI */ 12261d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* RE */ 12361d06d6bSBaptiste Daroussin { pre_RS, post_RS, 0 }, /* RS */ 12461d06d6bSBaptiste Daroussin { pre_DT, NULL, 0 }, /* DT */ 12561d06d6bSBaptiste Daroussin { pre_ign, NULL, MAN_NOTEXT }, /* UC */ 12661d06d6bSBaptiste Daroussin { pre_PD, NULL, MAN_NOTEXT }, /* PD */ 12761d06d6bSBaptiste Daroussin { pre_ign, NULL, 0 }, /* AT */ 12861d06d6bSBaptiste Daroussin { pre_in, NULL, MAN_NOTEXT }, /* in */ 1297295610fSBaptiste Daroussin { pre_SY, post_SY, 0 }, /* SY */ 1307295610fSBaptiste Daroussin { NULL, NULL, 0 }, /* YS */ 13161d06d6bSBaptiste Daroussin { pre_OP, NULL, 0 }, /* OP */ 13261d06d6bSBaptiste Daroussin { pre_literal, NULL, 0 }, /* EX */ 13361d06d6bSBaptiste Daroussin { pre_literal, NULL, 0 }, /* EE */ 13461d06d6bSBaptiste Daroussin { pre_UR, post_UR, 0 }, /* UR */ 13561d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* UE */ 13661d06d6bSBaptiste Daroussin { pre_UR, post_UR, 0 }, /* MT */ 13761d06d6bSBaptiste Daroussin { NULL, NULL, 0 }, /* ME */ 13861d06d6bSBaptiste Daroussin }; 1397295610fSBaptiste Daroussin static const struct man_term_act *man_term_act(enum roff_tok); 14061d06d6bSBaptiste Daroussin 14161d06d6bSBaptiste Daroussin 1427295610fSBaptiste Daroussin static const struct man_term_act * 1437295610fSBaptiste Daroussin man_term_act(enum roff_tok tok) 1447295610fSBaptiste Daroussin { 1457295610fSBaptiste Daroussin assert(tok >= MAN_TH && tok <= MAN_MAX); 1467295610fSBaptiste Daroussin return man_term_acts + (tok - MAN_TH); 1477295610fSBaptiste Daroussin } 1487295610fSBaptiste Daroussin 14961d06d6bSBaptiste Daroussin void 1507295610fSBaptiste Daroussin terminal_man(void *arg, const struct roff_meta *man) 15161d06d6bSBaptiste Daroussin { 1527295610fSBaptiste Daroussin struct mtermp mt; 15361d06d6bSBaptiste Daroussin struct termp *p; 15445a5aec3SBaptiste Daroussin struct roff_node *n, *nc, *nn; 15561d06d6bSBaptiste Daroussin size_t save_defindent; 15661d06d6bSBaptiste Daroussin 15761d06d6bSBaptiste Daroussin p = (struct termp *)arg; 15861d06d6bSBaptiste Daroussin save_defindent = p->defindent; 15961d06d6bSBaptiste Daroussin if (p->synopsisonly == 0 && p->defindent == 0) 16061d06d6bSBaptiste Daroussin p->defindent = 7; 16161d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin = p->defrmargin; 16261d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 16361d06d6bSBaptiste Daroussin term_tab_set(p, "T"); 16461d06d6bSBaptiste Daroussin term_tab_set(p, ".5i"); 16561d06d6bSBaptiste Daroussin 1667295610fSBaptiste Daroussin memset(&mt, 0, sizeof(mt)); 16761d06d6bSBaptiste Daroussin mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); 16861d06d6bSBaptiste Daroussin mt.offset = term_len(p, p->defindent); 16961d06d6bSBaptiste Daroussin mt.pardist = 1; 17061d06d6bSBaptiste Daroussin 17161d06d6bSBaptiste Daroussin n = man->first->child; 17261d06d6bSBaptiste Daroussin if (p->synopsisonly) { 17345a5aec3SBaptiste Daroussin for (nn = NULL; n != NULL; n = n->next) { 17445a5aec3SBaptiste Daroussin if (n->tok != MAN_SH) 17545a5aec3SBaptiste Daroussin continue; 17645a5aec3SBaptiste Daroussin nc = n->child->child; 17745a5aec3SBaptiste Daroussin if (nc->type != ROFFT_TEXT) 17845a5aec3SBaptiste Daroussin continue; 17945a5aec3SBaptiste Daroussin if (strcmp(nc->string, "SYNOPSIS") == 0) 18061d06d6bSBaptiste Daroussin break; 18145a5aec3SBaptiste Daroussin if (nn == NULL && strcmp(nc->string, "NAME") == 0) 18245a5aec3SBaptiste Daroussin nn = n; 18361d06d6bSBaptiste Daroussin } 18445a5aec3SBaptiste Daroussin if (n == NULL) 18545a5aec3SBaptiste Daroussin n = nn; 18645a5aec3SBaptiste Daroussin p->flags |= TERMP_NOSPACE; 18745a5aec3SBaptiste Daroussin if (n != NULL && (n = n->child->next->child) != NULL) 18845a5aec3SBaptiste Daroussin print_man_nodelist(p, &mt, n, man); 18945a5aec3SBaptiste Daroussin term_newln(p); 19061d06d6bSBaptiste Daroussin } else { 1917295610fSBaptiste Daroussin term_begin(p, print_man_head, print_man_foot, man); 19261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 19361d06d6bSBaptiste Daroussin if (n != NULL) 1947295610fSBaptiste Daroussin print_man_nodelist(p, &mt, n, man); 19561d06d6bSBaptiste Daroussin term_end(p); 19661d06d6bSBaptiste Daroussin } 19761d06d6bSBaptiste Daroussin p->defindent = save_defindent; 19861d06d6bSBaptiste Daroussin } 19961d06d6bSBaptiste Daroussin 20061d06d6bSBaptiste Daroussin /* 20161d06d6bSBaptiste Daroussin * Printing leading vertical space before a block. 20261d06d6bSBaptiste Daroussin * This is used for the paragraph macros. 20361d06d6bSBaptiste Daroussin * The rules are pretty simple, since there's very little nesting going 20461d06d6bSBaptiste Daroussin * on here. Basically, if we're the first within another block (SS/SH), 20561d06d6bSBaptiste Daroussin * then don't emit vertical space. If we are (RS), then do. If not the 20661d06d6bSBaptiste Daroussin * first, print it. 20761d06d6bSBaptiste Daroussin */ 20861d06d6bSBaptiste Daroussin static void 209*6d38604fSBaptiste Daroussin print_bvspace(struct termp *p, struct roff_node *n, int pardist) 21061d06d6bSBaptiste Daroussin { 211*6d38604fSBaptiste Daroussin struct roff_node *nch; 21261d06d6bSBaptiste Daroussin int i; 21361d06d6bSBaptiste Daroussin 21461d06d6bSBaptiste Daroussin term_newln(p); 21561d06d6bSBaptiste Daroussin 216*6d38604fSBaptiste Daroussin if (n->body != NULL && 217*6d38604fSBaptiste Daroussin (nch = roff_node_child(n->body)) != NULL && 218*6d38604fSBaptiste Daroussin nch->type == ROFFT_TBL) 21961d06d6bSBaptiste Daroussin return; 22061d06d6bSBaptiste Daroussin 221*6d38604fSBaptiste Daroussin if (n->parent->tok != MAN_RS && roff_node_prev(n) == NULL) 22261d06d6bSBaptiste Daroussin return; 22361d06d6bSBaptiste Daroussin 22461d06d6bSBaptiste Daroussin for (i = 0; i < pardist; i++) 22561d06d6bSBaptiste Daroussin term_vspace(p); 22661d06d6bSBaptiste Daroussin } 22761d06d6bSBaptiste Daroussin 22861d06d6bSBaptiste Daroussin 22961d06d6bSBaptiste Daroussin static int 2307295610fSBaptiste Daroussin pre_abort(DECL_ARGS) 2317295610fSBaptiste Daroussin { 2327295610fSBaptiste Daroussin abort(); 2337295610fSBaptiste Daroussin } 2347295610fSBaptiste Daroussin 2357295610fSBaptiste Daroussin static int 23661d06d6bSBaptiste Daroussin pre_ign(DECL_ARGS) 23761d06d6bSBaptiste Daroussin { 23861d06d6bSBaptiste Daroussin return 0; 23961d06d6bSBaptiste Daroussin } 24061d06d6bSBaptiste Daroussin 24161d06d6bSBaptiste Daroussin static int 24261d06d6bSBaptiste Daroussin pre_I(DECL_ARGS) 24361d06d6bSBaptiste Daroussin { 24461d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 24561d06d6bSBaptiste Daroussin return 1; 24661d06d6bSBaptiste Daroussin } 24761d06d6bSBaptiste Daroussin 24861d06d6bSBaptiste Daroussin static int 24961d06d6bSBaptiste Daroussin pre_literal(DECL_ARGS) 25061d06d6bSBaptiste Daroussin { 25161d06d6bSBaptiste Daroussin term_newln(p); 25261d06d6bSBaptiste Daroussin 25361d06d6bSBaptiste Daroussin /* 25461d06d6bSBaptiste Daroussin * Unlike .IP and .TP, .HP does not have a HEAD. 25561d06d6bSBaptiste Daroussin * So in case a second call to term_flushln() is needed, 25661d06d6bSBaptiste Daroussin * indentation has to be set up explicitly. 25761d06d6bSBaptiste Daroussin */ 25861d06d6bSBaptiste Daroussin if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) { 25961d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 26061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 26161d06d6bSBaptiste Daroussin p->trailspace = 0; 26261d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 26361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 26461d06d6bSBaptiste Daroussin } 26561d06d6bSBaptiste Daroussin return 0; 26661d06d6bSBaptiste Daroussin } 26761d06d6bSBaptiste Daroussin 26861d06d6bSBaptiste Daroussin static int 26961d06d6bSBaptiste Daroussin pre_PD(DECL_ARGS) 27061d06d6bSBaptiste Daroussin { 27161d06d6bSBaptiste Daroussin struct roffsu su; 27261d06d6bSBaptiste Daroussin 27361d06d6bSBaptiste Daroussin n = n->child; 27461d06d6bSBaptiste Daroussin if (n == NULL) { 27561d06d6bSBaptiste Daroussin mt->pardist = 1; 27661d06d6bSBaptiste Daroussin return 0; 27761d06d6bSBaptiste Daroussin } 27861d06d6bSBaptiste Daroussin assert(n->type == ROFFT_TEXT); 27961d06d6bSBaptiste Daroussin if (a2roffsu(n->string, &su, SCALE_VS) != NULL) 28061d06d6bSBaptiste Daroussin mt->pardist = term_vspan(p, &su); 28161d06d6bSBaptiste Daroussin return 0; 28261d06d6bSBaptiste Daroussin } 28361d06d6bSBaptiste Daroussin 28461d06d6bSBaptiste Daroussin static int 28561d06d6bSBaptiste Daroussin pre_alternate(DECL_ARGS) 28661d06d6bSBaptiste Daroussin { 28761d06d6bSBaptiste Daroussin enum termfont font[2]; 28861d06d6bSBaptiste Daroussin struct roff_node *nn; 2897295610fSBaptiste Daroussin int i; 29061d06d6bSBaptiste Daroussin 29161d06d6bSBaptiste Daroussin switch (n->tok) { 29261d06d6bSBaptiste Daroussin case MAN_RB: 29361d06d6bSBaptiste Daroussin font[0] = TERMFONT_NONE; 29461d06d6bSBaptiste Daroussin font[1] = TERMFONT_BOLD; 29561d06d6bSBaptiste Daroussin break; 29661d06d6bSBaptiste Daroussin case MAN_RI: 29761d06d6bSBaptiste Daroussin font[0] = TERMFONT_NONE; 29861d06d6bSBaptiste Daroussin font[1] = TERMFONT_UNDER; 29961d06d6bSBaptiste Daroussin break; 30061d06d6bSBaptiste Daroussin case MAN_BR: 30161d06d6bSBaptiste Daroussin font[0] = TERMFONT_BOLD; 30261d06d6bSBaptiste Daroussin font[1] = TERMFONT_NONE; 30361d06d6bSBaptiste Daroussin break; 30461d06d6bSBaptiste Daroussin case MAN_BI: 30561d06d6bSBaptiste Daroussin font[0] = TERMFONT_BOLD; 30661d06d6bSBaptiste Daroussin font[1] = TERMFONT_UNDER; 30761d06d6bSBaptiste Daroussin break; 30861d06d6bSBaptiste Daroussin case MAN_IR: 30961d06d6bSBaptiste Daroussin font[0] = TERMFONT_UNDER; 31061d06d6bSBaptiste Daroussin font[1] = TERMFONT_NONE; 31161d06d6bSBaptiste Daroussin break; 31261d06d6bSBaptiste Daroussin case MAN_IB: 31361d06d6bSBaptiste Daroussin font[0] = TERMFONT_UNDER; 31461d06d6bSBaptiste Daroussin font[1] = TERMFONT_BOLD; 31561d06d6bSBaptiste Daroussin break; 31661d06d6bSBaptiste Daroussin default: 31761d06d6bSBaptiste Daroussin abort(); 31861d06d6bSBaptiste Daroussin } 3197295610fSBaptiste Daroussin for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) { 32061d06d6bSBaptiste Daroussin term_fontrepl(p, font[i]); 32161d06d6bSBaptiste Daroussin assert(nn->type == ROFFT_TEXT); 32261d06d6bSBaptiste Daroussin term_word(p, nn->string); 32361d06d6bSBaptiste Daroussin if (nn->flags & NODE_EOS) 32461d06d6bSBaptiste Daroussin p->flags |= TERMP_SENTENCE; 3257295610fSBaptiste Daroussin if (nn->next != NULL) 32661d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 32761d06d6bSBaptiste Daroussin } 32861d06d6bSBaptiste Daroussin return 0; 32961d06d6bSBaptiste Daroussin } 33061d06d6bSBaptiste Daroussin 33161d06d6bSBaptiste Daroussin static int 33261d06d6bSBaptiste Daroussin pre_B(DECL_ARGS) 33361d06d6bSBaptiste Daroussin { 33461d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 33561d06d6bSBaptiste Daroussin return 1; 33661d06d6bSBaptiste Daroussin } 33761d06d6bSBaptiste Daroussin 33861d06d6bSBaptiste Daroussin static int 33961d06d6bSBaptiste Daroussin pre_OP(DECL_ARGS) 34061d06d6bSBaptiste Daroussin { 34161d06d6bSBaptiste Daroussin term_word(p, "["); 3427295610fSBaptiste Daroussin p->flags |= TERMP_KEEP | TERMP_NOSPACE; 34361d06d6bSBaptiste Daroussin 3447295610fSBaptiste Daroussin if ((n = n->child) != NULL) { 34561d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 34661d06d6bSBaptiste Daroussin term_word(p, n->string); 34761d06d6bSBaptiste Daroussin } 3487295610fSBaptiste Daroussin if (n != NULL && n->next != NULL) { 34961d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 35061d06d6bSBaptiste Daroussin term_word(p, n->next->string); 35161d06d6bSBaptiste Daroussin } 35261d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 3537295610fSBaptiste Daroussin p->flags &= ~TERMP_KEEP; 35461d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 35561d06d6bSBaptiste Daroussin term_word(p, "]"); 35661d06d6bSBaptiste Daroussin return 0; 35761d06d6bSBaptiste Daroussin } 35861d06d6bSBaptiste Daroussin 35961d06d6bSBaptiste Daroussin static int 36061d06d6bSBaptiste Daroussin pre_in(DECL_ARGS) 36161d06d6bSBaptiste Daroussin { 36261d06d6bSBaptiste Daroussin struct roffsu su; 36361d06d6bSBaptiste Daroussin const char *cp; 36461d06d6bSBaptiste Daroussin size_t v; 36561d06d6bSBaptiste Daroussin int less; 36661d06d6bSBaptiste Daroussin 36761d06d6bSBaptiste Daroussin term_newln(p); 36861d06d6bSBaptiste Daroussin 36961d06d6bSBaptiste Daroussin if (n->child == NULL) { 37061d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 37161d06d6bSBaptiste Daroussin return 0; 37261d06d6bSBaptiste Daroussin } 37361d06d6bSBaptiste Daroussin 37461d06d6bSBaptiste Daroussin cp = n->child->string; 37561d06d6bSBaptiste Daroussin less = 0; 37661d06d6bSBaptiste Daroussin 3777295610fSBaptiste Daroussin if (*cp == '-') 37861d06d6bSBaptiste Daroussin less = -1; 3797295610fSBaptiste Daroussin else if (*cp == '+') 38061d06d6bSBaptiste Daroussin less = 1; 38161d06d6bSBaptiste Daroussin else 38261d06d6bSBaptiste Daroussin cp--; 38361d06d6bSBaptiste Daroussin 38461d06d6bSBaptiste Daroussin if (a2roffsu(++cp, &su, SCALE_EN) == NULL) 38561d06d6bSBaptiste Daroussin return 0; 38661d06d6bSBaptiste Daroussin 38761d06d6bSBaptiste Daroussin v = term_hen(p, &su); 38861d06d6bSBaptiste Daroussin 38961d06d6bSBaptiste Daroussin if (less < 0) 39061d06d6bSBaptiste Daroussin p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset; 39161d06d6bSBaptiste Daroussin else if (less > 0) 39261d06d6bSBaptiste Daroussin p->tcol->offset += v; 39361d06d6bSBaptiste Daroussin else 39461d06d6bSBaptiste Daroussin p->tcol->offset = v; 39561d06d6bSBaptiste Daroussin if (p->tcol->offset > SHRT_MAX) 39661d06d6bSBaptiste Daroussin p->tcol->offset = term_len(p, p->defindent); 39761d06d6bSBaptiste Daroussin 39861d06d6bSBaptiste Daroussin return 0; 39961d06d6bSBaptiste Daroussin } 40061d06d6bSBaptiste Daroussin 40161d06d6bSBaptiste Daroussin static int 40261d06d6bSBaptiste Daroussin pre_DT(DECL_ARGS) 40361d06d6bSBaptiste Daroussin { 40461d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 40561d06d6bSBaptiste Daroussin term_tab_set(p, "T"); 40661d06d6bSBaptiste Daroussin term_tab_set(p, ".5i"); 40761d06d6bSBaptiste Daroussin return 0; 40861d06d6bSBaptiste Daroussin } 40961d06d6bSBaptiste Daroussin 41061d06d6bSBaptiste Daroussin static int 41161d06d6bSBaptiste Daroussin pre_HP(DECL_ARGS) 41261d06d6bSBaptiste Daroussin { 41361d06d6bSBaptiste Daroussin struct roffsu su; 41461d06d6bSBaptiste Daroussin const struct roff_node *nn; 41561d06d6bSBaptiste Daroussin int len; 41661d06d6bSBaptiste Daroussin 41761d06d6bSBaptiste Daroussin switch (n->type) { 41861d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 41961d06d6bSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 42061d06d6bSBaptiste Daroussin return 1; 4217295610fSBaptiste Daroussin case ROFFT_HEAD: 4227295610fSBaptiste Daroussin return 0; 42361d06d6bSBaptiste Daroussin case ROFFT_BODY: 42461d06d6bSBaptiste Daroussin break; 42561d06d6bSBaptiste Daroussin default: 4267295610fSBaptiste Daroussin abort(); 42761d06d6bSBaptiste Daroussin } 42861d06d6bSBaptiste Daroussin 4297295610fSBaptiste Daroussin if (n->child == NULL) 4307295610fSBaptiste Daroussin return 0; 4317295610fSBaptiste Daroussin 4327295610fSBaptiste Daroussin if ((n->child->flags & NODE_NOFILL) == 0) { 43361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 43461d06d6bSBaptiste Daroussin p->trailspace = 2; 43561d06d6bSBaptiste Daroussin } 43661d06d6bSBaptiste Daroussin 43761d06d6bSBaptiste Daroussin /* Calculate offset. */ 43861d06d6bSBaptiste Daroussin 43961d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 44061d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 44161d06d6bSBaptiste Daroussin len = term_hen(p, &su); 44261d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 44361d06d6bSBaptiste Daroussin len = -mt->offset; 44461d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 44561d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 44661d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 44761d06d6bSBaptiste Daroussin } else 44861d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 44961d06d6bSBaptiste Daroussin 45061d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 45161d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 45261d06d6bSBaptiste Daroussin return 1; 45361d06d6bSBaptiste Daroussin } 45461d06d6bSBaptiste Daroussin 45561d06d6bSBaptiste Daroussin static void 45661d06d6bSBaptiste Daroussin post_HP(DECL_ARGS) 45761d06d6bSBaptiste Daroussin { 45861d06d6bSBaptiste Daroussin switch (n->type) { 4597295610fSBaptiste Daroussin case ROFFT_BLOCK: 4607295610fSBaptiste Daroussin case ROFFT_HEAD: 4617295610fSBaptiste Daroussin break; 46261d06d6bSBaptiste Daroussin case ROFFT_BODY: 46361d06d6bSBaptiste Daroussin term_newln(p); 46461d06d6bSBaptiste Daroussin 46561d06d6bSBaptiste Daroussin /* 46661d06d6bSBaptiste Daroussin * Compatibility with a groff bug. 46761d06d6bSBaptiste Daroussin * The .HP macro uses the undocumented .tag request 46861d06d6bSBaptiste Daroussin * which causes a line break and cancels no-space 46961d06d6bSBaptiste Daroussin * mode even if there isn't any output. 47061d06d6bSBaptiste Daroussin */ 47161d06d6bSBaptiste Daroussin 47261d06d6bSBaptiste Daroussin if (n->child == NULL) 47361d06d6bSBaptiste Daroussin term_vspace(p); 47461d06d6bSBaptiste Daroussin 47561d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 47661d06d6bSBaptiste Daroussin p->trailspace = 0; 47761d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 47861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 47961d06d6bSBaptiste Daroussin break; 48061d06d6bSBaptiste Daroussin default: 4817295610fSBaptiste Daroussin abort(); 48261d06d6bSBaptiste Daroussin } 48361d06d6bSBaptiste Daroussin } 48461d06d6bSBaptiste Daroussin 48561d06d6bSBaptiste Daroussin static int 48661d06d6bSBaptiste Daroussin pre_PP(DECL_ARGS) 48761d06d6bSBaptiste Daroussin { 48861d06d6bSBaptiste Daroussin switch (n->type) { 48961d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 49061d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 49161d06d6bSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 49261d06d6bSBaptiste Daroussin break; 4937295610fSBaptiste Daroussin case ROFFT_HEAD: 4947295610fSBaptiste Daroussin return 0; 4957295610fSBaptiste Daroussin case ROFFT_BODY: 49661d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 49761d06d6bSBaptiste Daroussin break; 4987295610fSBaptiste Daroussin default: 4997295610fSBaptiste Daroussin abort(); 50061d06d6bSBaptiste Daroussin } 5017295610fSBaptiste Daroussin return 1; 50261d06d6bSBaptiste Daroussin } 50361d06d6bSBaptiste Daroussin 50461d06d6bSBaptiste Daroussin static int 50561d06d6bSBaptiste Daroussin pre_IP(DECL_ARGS) 50661d06d6bSBaptiste Daroussin { 50761d06d6bSBaptiste Daroussin struct roffsu su; 50861d06d6bSBaptiste Daroussin const struct roff_node *nn; 5097295610fSBaptiste Daroussin int len; 51061d06d6bSBaptiste Daroussin 51161d06d6bSBaptiste Daroussin switch (n->type) { 5127295610fSBaptiste Daroussin case ROFFT_BLOCK: 5137295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 5147295610fSBaptiste Daroussin return 1; 51561d06d6bSBaptiste Daroussin case ROFFT_HEAD: 51661d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 51761d06d6bSBaptiste Daroussin p->trailspace = 1; 51861d06d6bSBaptiste Daroussin break; 5197295610fSBaptiste Daroussin case ROFFT_BODY: 5207295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 5217295610fSBaptiste Daroussin break; 52261d06d6bSBaptiste Daroussin default: 5237295610fSBaptiste Daroussin abort(); 52461d06d6bSBaptiste Daroussin } 52561d06d6bSBaptiste Daroussin 52661d06d6bSBaptiste Daroussin /* Calculate the offset from the optional second argument. */ 52761d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 52861d06d6bSBaptiste Daroussin (nn = nn->next) != NULL && 52961d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 53061d06d6bSBaptiste Daroussin len = term_hen(p, &su); 53161d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 53261d06d6bSBaptiste Daroussin len = -mt->offset; 53361d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 53461d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 53561d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 53661d06d6bSBaptiste Daroussin } else 53761d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 53861d06d6bSBaptiste Daroussin 53961d06d6bSBaptiste Daroussin switch (n->type) { 54061d06d6bSBaptiste Daroussin case ROFFT_HEAD: 54161d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 54261d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 543*6d38604fSBaptiste Daroussin if (n->child != NULL) 54461d06d6bSBaptiste Daroussin print_man_node(p, mt, n->child, meta); 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 6247295610fSBaptiste Daroussin while (nn != NULL) { 62561d06d6bSBaptiste Daroussin print_man_node(p, mt, nn, meta); 62661d06d6bSBaptiste Daroussin nn = nn->next; 62761d06d6bSBaptiste Daroussin } 62861d06d6bSBaptiste Daroussin return 0; 62961d06d6bSBaptiste Daroussin case ROFFT_BODY: 63061d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset + len; 63161d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 63261d06d6bSBaptiste Daroussin p->trailspace = 0; 63361d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP); 63461d06d6bSBaptiste Daroussin break; 63561d06d6bSBaptiste Daroussin default: 6367295610fSBaptiste Daroussin abort(); 63761d06d6bSBaptiste Daroussin } 63861d06d6bSBaptiste Daroussin return 1; 63961d06d6bSBaptiste Daroussin } 64061d06d6bSBaptiste Daroussin 64161d06d6bSBaptiste Daroussin static void 64261d06d6bSBaptiste Daroussin post_TP(DECL_ARGS) 64361d06d6bSBaptiste Daroussin { 64461d06d6bSBaptiste Daroussin switch (n->type) { 6457295610fSBaptiste Daroussin case ROFFT_BLOCK: 6467295610fSBaptiste Daroussin break; 64761d06d6bSBaptiste Daroussin case ROFFT_HEAD: 64861d06d6bSBaptiste Daroussin term_flushln(p); 64961d06d6bSBaptiste Daroussin break; 65061d06d6bSBaptiste Daroussin case ROFFT_BODY: 65161d06d6bSBaptiste Daroussin term_newln(p); 65261d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 65361d06d6bSBaptiste Daroussin break; 65461d06d6bSBaptiste Daroussin default: 6557295610fSBaptiste Daroussin abort(); 65661d06d6bSBaptiste Daroussin } 65761d06d6bSBaptiste Daroussin } 65861d06d6bSBaptiste Daroussin 65961d06d6bSBaptiste Daroussin static int 66061d06d6bSBaptiste Daroussin pre_SS(DECL_ARGS) 66161d06d6bSBaptiste Daroussin { 66261d06d6bSBaptiste Daroussin int i; 66361d06d6bSBaptiste Daroussin 66461d06d6bSBaptiste Daroussin switch (n->type) { 66561d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 66661d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 66761d06d6bSBaptiste Daroussin mt->offset = term_len(p, p->defindent); 66861d06d6bSBaptiste Daroussin 66961d06d6bSBaptiste Daroussin /* 67061d06d6bSBaptiste Daroussin * No vertical space before the first subsection 67161d06d6bSBaptiste Daroussin * and after an empty subsection. 67261d06d6bSBaptiste Daroussin */ 67361d06d6bSBaptiste Daroussin 674*6d38604fSBaptiste Daroussin if ((n = roff_node_prev(n)) == NULL || 675*6d38604fSBaptiste Daroussin (n->tok == MAN_SS && roff_node_child(n->body) == NULL)) 67661d06d6bSBaptiste Daroussin break; 67761d06d6bSBaptiste Daroussin 67861d06d6bSBaptiste Daroussin for (i = 0; i < mt->pardist; i++) 67961d06d6bSBaptiste Daroussin term_vspace(p); 68061d06d6bSBaptiste Daroussin break; 68161d06d6bSBaptiste Daroussin case ROFFT_HEAD: 68261d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 68361d06d6bSBaptiste Daroussin p->tcol->offset = term_len(p, 3); 68461d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset; 68561d06d6bSBaptiste Daroussin p->trailspace = mt->offset; 68661d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 68761d06d6bSBaptiste Daroussin break; 68861d06d6bSBaptiste Daroussin case ROFFT_BODY: 68961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 69061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 69161d06d6bSBaptiste Daroussin p->trailspace = 0; 69261d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 69361d06d6bSBaptiste Daroussin break; 69461d06d6bSBaptiste Daroussin default: 69561d06d6bSBaptiste Daroussin break; 69661d06d6bSBaptiste Daroussin } 69761d06d6bSBaptiste Daroussin return 1; 69861d06d6bSBaptiste Daroussin } 69961d06d6bSBaptiste Daroussin 70061d06d6bSBaptiste Daroussin static int 70161d06d6bSBaptiste Daroussin pre_SH(DECL_ARGS) 70261d06d6bSBaptiste Daroussin { 70361d06d6bSBaptiste Daroussin int i; 70461d06d6bSBaptiste Daroussin 70561d06d6bSBaptiste Daroussin switch (n->type) { 70661d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 70761d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 70861d06d6bSBaptiste Daroussin mt->offset = term_len(p, p->defindent); 70961d06d6bSBaptiste Daroussin 71061d06d6bSBaptiste Daroussin /* 71161d06d6bSBaptiste Daroussin * No vertical space before the first section 71261d06d6bSBaptiste Daroussin * and after an empty section. 71361d06d6bSBaptiste Daroussin */ 71461d06d6bSBaptiste Daroussin 715*6d38604fSBaptiste Daroussin if ((n = roff_node_prev(n)) == NULL || 716*6d38604fSBaptiste Daroussin (n->tok == MAN_SH && roff_node_child(n->body) == NULL)) 71761d06d6bSBaptiste Daroussin break; 71861d06d6bSBaptiste Daroussin 71961d06d6bSBaptiste Daroussin for (i = 0; i < mt->pardist; i++) 72061d06d6bSBaptiste Daroussin term_vspace(p); 72161d06d6bSBaptiste Daroussin break; 72261d06d6bSBaptiste Daroussin case ROFFT_HEAD: 72361d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 72461d06d6bSBaptiste Daroussin p->tcol->offset = 0; 72561d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset; 72661d06d6bSBaptiste Daroussin p->trailspace = mt->offset; 72761d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 72861d06d6bSBaptiste Daroussin break; 72961d06d6bSBaptiste Daroussin case ROFFT_BODY: 73061d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 73161d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 73261d06d6bSBaptiste Daroussin p->trailspace = 0; 73361d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 73461d06d6bSBaptiste Daroussin break; 73561d06d6bSBaptiste Daroussin default: 7367295610fSBaptiste Daroussin abort(); 73761d06d6bSBaptiste Daroussin } 73861d06d6bSBaptiste Daroussin return 1; 73961d06d6bSBaptiste Daroussin } 74061d06d6bSBaptiste Daroussin 74161d06d6bSBaptiste Daroussin static void 74261d06d6bSBaptiste Daroussin post_SH(DECL_ARGS) 74361d06d6bSBaptiste Daroussin { 74461d06d6bSBaptiste Daroussin switch (n->type) { 7457295610fSBaptiste Daroussin case ROFFT_BLOCK: 74661d06d6bSBaptiste Daroussin break; 7477295610fSBaptiste Daroussin case ROFFT_HEAD: 74861d06d6bSBaptiste Daroussin case ROFFT_BODY: 74961d06d6bSBaptiste Daroussin term_newln(p); 75061d06d6bSBaptiste Daroussin break; 75161d06d6bSBaptiste Daroussin default: 7527295610fSBaptiste Daroussin abort(); 75361d06d6bSBaptiste Daroussin } 75461d06d6bSBaptiste Daroussin } 75561d06d6bSBaptiste Daroussin 75661d06d6bSBaptiste Daroussin static int 75761d06d6bSBaptiste Daroussin pre_RS(DECL_ARGS) 75861d06d6bSBaptiste Daroussin { 75961d06d6bSBaptiste Daroussin struct roffsu su; 76061d06d6bSBaptiste Daroussin 76161d06d6bSBaptiste Daroussin switch (n->type) { 76261d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 76361d06d6bSBaptiste Daroussin term_newln(p); 76461d06d6bSBaptiste Daroussin return 1; 76561d06d6bSBaptiste Daroussin case ROFFT_HEAD: 76661d06d6bSBaptiste Daroussin return 0; 7677295610fSBaptiste Daroussin case ROFFT_BODY: 76861d06d6bSBaptiste Daroussin break; 7697295610fSBaptiste Daroussin default: 7707295610fSBaptiste Daroussin abort(); 77161d06d6bSBaptiste Daroussin } 77261d06d6bSBaptiste Daroussin 77361d06d6bSBaptiste Daroussin n = n->parent->head; 77461d06d6bSBaptiste Daroussin n->aux = SHRT_MAX + 1; 77561d06d6bSBaptiste Daroussin if (n->child == NULL) 77661d06d6bSBaptiste Daroussin n->aux = mt->lmargin[mt->lmargincur]; 77761d06d6bSBaptiste Daroussin else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL) 77861d06d6bSBaptiste Daroussin n->aux = term_hen(p, &su); 77961d06d6bSBaptiste Daroussin if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) 78061d06d6bSBaptiste Daroussin n->aux = -mt->offset; 78161d06d6bSBaptiste Daroussin else if (n->aux > SHRT_MAX) 78261d06d6bSBaptiste Daroussin n->aux = term_len(p, p->defindent); 78361d06d6bSBaptiste Daroussin 78461d06d6bSBaptiste Daroussin mt->offset += n->aux; 78561d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 78661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 78761d06d6bSBaptiste Daroussin 78861d06d6bSBaptiste Daroussin if (++mt->lmarginsz < MAXMARGINS) 78961d06d6bSBaptiste Daroussin mt->lmargincur = mt->lmarginsz; 79061d06d6bSBaptiste Daroussin 79161d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); 79261d06d6bSBaptiste Daroussin return 1; 79361d06d6bSBaptiste Daroussin } 79461d06d6bSBaptiste Daroussin 79561d06d6bSBaptiste Daroussin static void 79661d06d6bSBaptiste Daroussin post_RS(DECL_ARGS) 79761d06d6bSBaptiste Daroussin { 79861d06d6bSBaptiste Daroussin switch (n->type) { 79961d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 80061d06d6bSBaptiste Daroussin case ROFFT_HEAD: 80161d06d6bSBaptiste Daroussin return; 8027295610fSBaptiste Daroussin case ROFFT_BODY: 80361d06d6bSBaptiste Daroussin break; 8047295610fSBaptiste Daroussin default: 8057295610fSBaptiste Daroussin abort(); 80661d06d6bSBaptiste Daroussin } 8077295610fSBaptiste Daroussin term_newln(p); 80861d06d6bSBaptiste Daroussin mt->offset -= n->parent->head->aux; 80961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 81061d06d6bSBaptiste Daroussin if (--mt->lmarginsz < MAXMARGINS) 81161d06d6bSBaptiste Daroussin mt->lmargincur = mt->lmarginsz; 81261d06d6bSBaptiste Daroussin } 81361d06d6bSBaptiste Daroussin 81461d06d6bSBaptiste Daroussin static int 8157295610fSBaptiste Daroussin pre_SY(DECL_ARGS) 8167295610fSBaptiste Daroussin { 8177295610fSBaptiste Daroussin const struct roff_node *nn; 8187295610fSBaptiste Daroussin int len; 8197295610fSBaptiste Daroussin 8207295610fSBaptiste Daroussin switch (n->type) { 8217295610fSBaptiste Daroussin case ROFFT_BLOCK: 822*6d38604fSBaptiste Daroussin if ((nn = roff_node_prev(n)) == NULL || nn->tok != MAN_SY) 8237295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 8247295610fSBaptiste Daroussin return 1; 8257295610fSBaptiste Daroussin case ROFFT_HEAD: 8267295610fSBaptiste Daroussin case ROFFT_BODY: 8277295610fSBaptiste Daroussin break; 8287295610fSBaptiste Daroussin default: 8297295610fSBaptiste Daroussin abort(); 8307295610fSBaptiste Daroussin } 8317295610fSBaptiste Daroussin 8327295610fSBaptiste Daroussin nn = n->parent->head->child; 8337295610fSBaptiste Daroussin len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1; 8347295610fSBaptiste Daroussin 8357295610fSBaptiste Daroussin switch (n->type) { 8367295610fSBaptiste Daroussin case ROFFT_HEAD: 8377295610fSBaptiste Daroussin p->tcol->offset = mt->offset; 8387295610fSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 8397295610fSBaptiste Daroussin if (n->next->child == NULL || 8407295610fSBaptiste Daroussin (n->next->child->flags & NODE_NOFILL) == 0) 8417295610fSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 8427295610fSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 8437295610fSBaptiste Daroussin break; 8447295610fSBaptiste Daroussin case ROFFT_BODY: 8457295610fSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 8467295610fSBaptiste Daroussin p->tcol->offset = mt->offset + len; 8477295610fSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 8487295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 8497295610fSBaptiste Daroussin break; 8507295610fSBaptiste Daroussin default: 8517295610fSBaptiste Daroussin abort(); 8527295610fSBaptiste Daroussin } 8537295610fSBaptiste Daroussin return 1; 8547295610fSBaptiste Daroussin } 8557295610fSBaptiste Daroussin 8567295610fSBaptiste Daroussin static void 8577295610fSBaptiste Daroussin post_SY(DECL_ARGS) 8587295610fSBaptiste Daroussin { 8597295610fSBaptiste Daroussin switch (n->type) { 8607295610fSBaptiste Daroussin case ROFFT_BLOCK: 8617295610fSBaptiste Daroussin break; 8627295610fSBaptiste Daroussin case ROFFT_HEAD: 8637295610fSBaptiste Daroussin term_flushln(p); 8647295610fSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 8657295610fSBaptiste Daroussin break; 8667295610fSBaptiste Daroussin case ROFFT_BODY: 8677295610fSBaptiste Daroussin term_newln(p); 8687295610fSBaptiste Daroussin p->tcol->offset = mt->offset; 8697295610fSBaptiste Daroussin break; 8707295610fSBaptiste Daroussin default: 8717295610fSBaptiste Daroussin abort(); 8727295610fSBaptiste Daroussin } 8737295610fSBaptiste Daroussin } 8747295610fSBaptiste Daroussin 8757295610fSBaptiste Daroussin static int 87661d06d6bSBaptiste Daroussin pre_UR(DECL_ARGS) 87761d06d6bSBaptiste Daroussin { 87861d06d6bSBaptiste Daroussin return n->type != ROFFT_HEAD; 87961d06d6bSBaptiste Daroussin } 88061d06d6bSBaptiste Daroussin 88161d06d6bSBaptiste Daroussin static void 88261d06d6bSBaptiste Daroussin post_UR(DECL_ARGS) 88361d06d6bSBaptiste Daroussin { 88461d06d6bSBaptiste Daroussin if (n->type != ROFFT_BLOCK) 88561d06d6bSBaptiste Daroussin return; 88661d06d6bSBaptiste Daroussin 88761d06d6bSBaptiste Daroussin term_word(p, "<"); 88861d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 88961d06d6bSBaptiste Daroussin 8907295610fSBaptiste Daroussin if (n->child->child != NULL) 89161d06d6bSBaptiste Daroussin print_man_node(p, mt, n->child->child, meta); 89261d06d6bSBaptiste Daroussin 89361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 89461d06d6bSBaptiste Daroussin term_word(p, ">"); 89561d06d6bSBaptiste Daroussin } 89661d06d6bSBaptiste Daroussin 89761d06d6bSBaptiste Daroussin static void 89861d06d6bSBaptiste Daroussin print_man_node(DECL_ARGS) 89961d06d6bSBaptiste Daroussin { 9007295610fSBaptiste Daroussin const struct man_term_act *act; 90161d06d6bSBaptiste Daroussin int c; 90261d06d6bSBaptiste Daroussin 903*6d38604fSBaptiste Daroussin if (n->flags & NODE_ID) 904*6d38604fSBaptiste Daroussin term_tag_write(n, p->line); 905*6d38604fSBaptiste Daroussin 90661d06d6bSBaptiste Daroussin switch (n->type) { 90761d06d6bSBaptiste Daroussin case ROFFT_TEXT: 90861d06d6bSBaptiste Daroussin /* 90961d06d6bSBaptiste Daroussin * If we have a blank line, output a vertical space. 91061d06d6bSBaptiste Daroussin * If we have a space as the first character, break 91161d06d6bSBaptiste Daroussin * before printing the line's data. 91261d06d6bSBaptiste Daroussin */ 91361d06d6bSBaptiste Daroussin if (*n->string == '\0') { 91461d06d6bSBaptiste Daroussin if (p->flags & TERMP_NONEWLINE) 91561d06d6bSBaptiste Daroussin term_newln(p); 91661d06d6bSBaptiste Daroussin else 91761d06d6bSBaptiste Daroussin term_vspace(p); 91861d06d6bSBaptiste Daroussin return; 91961d06d6bSBaptiste Daroussin } else if (*n->string == ' ' && n->flags & NODE_LINE && 92061d06d6bSBaptiste Daroussin (p->flags & TERMP_NONEWLINE) == 0) 92161d06d6bSBaptiste Daroussin term_newln(p); 9227295610fSBaptiste Daroussin else if (n->flags & NODE_DELIMC) 9237295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 92461d06d6bSBaptiste Daroussin 92561d06d6bSBaptiste Daroussin term_word(p, n->string); 92661d06d6bSBaptiste Daroussin goto out; 92761d06d6bSBaptiste Daroussin case ROFFT_COMMENT: 92861d06d6bSBaptiste Daroussin return; 92961d06d6bSBaptiste Daroussin case ROFFT_EQN: 93061d06d6bSBaptiste Daroussin if ( ! (n->flags & NODE_LINE)) 93161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 93261d06d6bSBaptiste Daroussin term_eqn(p, n->eqn); 93361d06d6bSBaptiste Daroussin if (n->next != NULL && ! (n->next->flags & NODE_LINE)) 93461d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 93561d06d6bSBaptiste Daroussin return; 93661d06d6bSBaptiste Daroussin case ROFFT_TBL: 93761d06d6bSBaptiste Daroussin if (p->tbl.cols == NULL) 93861d06d6bSBaptiste Daroussin term_vspace(p); 93961d06d6bSBaptiste Daroussin term_tbl(p, n->span); 94061d06d6bSBaptiste Daroussin return; 94161d06d6bSBaptiste Daroussin default: 94261d06d6bSBaptiste Daroussin break; 94361d06d6bSBaptiste Daroussin } 94461d06d6bSBaptiste Daroussin 94561d06d6bSBaptiste Daroussin if (n->tok < ROFF_MAX) { 94661d06d6bSBaptiste Daroussin roff_term_pre(p, n); 94761d06d6bSBaptiste Daroussin return; 94861d06d6bSBaptiste Daroussin } 94961d06d6bSBaptiste Daroussin 9507295610fSBaptiste Daroussin act = man_term_act(n->tok); 9517295610fSBaptiste Daroussin if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) 95261d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 95361d06d6bSBaptiste Daroussin 95461d06d6bSBaptiste Daroussin c = 1; 9557295610fSBaptiste Daroussin if (act->pre != NULL) 9567295610fSBaptiste Daroussin c = (*act->pre)(p, mt, n, meta); 95761d06d6bSBaptiste Daroussin 9587295610fSBaptiste Daroussin if (c && n->child != NULL) 95961d06d6bSBaptiste Daroussin print_man_nodelist(p, mt, n->child, meta); 96061d06d6bSBaptiste Daroussin 9617295610fSBaptiste Daroussin if (act->post != NULL) 9627295610fSBaptiste Daroussin (*act->post)(p, mt, n, meta); 9637295610fSBaptiste Daroussin if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) 96461d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 96561d06d6bSBaptiste Daroussin 96661d06d6bSBaptiste Daroussin out: 96761d06d6bSBaptiste Daroussin /* 96861d06d6bSBaptiste Daroussin * If we're in a literal context, make sure that words 96961d06d6bSBaptiste Daroussin * together on the same line stay together. This is a 97061d06d6bSBaptiste Daroussin * POST-printing call, so we check the NEXT word. Since 97161d06d6bSBaptiste Daroussin * -man doesn't have nested macros, we don't need to be 97261d06d6bSBaptiste Daroussin * more specific than this. 97361d06d6bSBaptiste Daroussin */ 9747295610fSBaptiste Daroussin if (n->flags & NODE_NOFILL && 97561d06d6bSBaptiste Daroussin ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && 97661d06d6bSBaptiste Daroussin (n->next == NULL || n->next->flags & NODE_LINE)) { 97761d06d6bSBaptiste Daroussin p->flags |= TERMP_BRNEVER | TERMP_NOSPACE; 97861d06d6bSBaptiste Daroussin if (n->string != NULL && *n->string != '\0') 97961d06d6bSBaptiste Daroussin term_flushln(p); 98061d06d6bSBaptiste Daroussin else 98161d06d6bSBaptiste Daroussin term_newln(p); 98261d06d6bSBaptiste Daroussin p->flags &= ~TERMP_BRNEVER; 98361d06d6bSBaptiste Daroussin if (p->tcol->rmargin < p->maxrmargin && 98461d06d6bSBaptiste Daroussin n->parent->tok == MAN_HP) { 98561d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 98661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 98761d06d6bSBaptiste Daroussin } 98861d06d6bSBaptiste Daroussin } 9897295610fSBaptiste Daroussin if (n->flags & NODE_EOS) 99061d06d6bSBaptiste Daroussin p->flags |= TERMP_SENTENCE; 99161d06d6bSBaptiste Daroussin } 99261d06d6bSBaptiste Daroussin 99361d06d6bSBaptiste Daroussin static void 99461d06d6bSBaptiste Daroussin print_man_nodelist(DECL_ARGS) 99561d06d6bSBaptiste Daroussin { 99661d06d6bSBaptiste Daroussin while (n != NULL) { 99761d06d6bSBaptiste Daroussin print_man_node(p, mt, n, meta); 99861d06d6bSBaptiste Daroussin n = n->next; 99961d06d6bSBaptiste Daroussin } 100061d06d6bSBaptiste Daroussin } 100161d06d6bSBaptiste Daroussin 100261d06d6bSBaptiste Daroussin static void 100361d06d6bSBaptiste Daroussin print_man_foot(struct termp *p, const struct roff_meta *meta) 100461d06d6bSBaptiste Daroussin { 100561d06d6bSBaptiste Daroussin char *title; 100661d06d6bSBaptiste Daroussin size_t datelen, titlen; 100761d06d6bSBaptiste Daroussin 100861d06d6bSBaptiste Daroussin assert(meta->title); 100961d06d6bSBaptiste Daroussin assert(meta->msec); 101061d06d6bSBaptiste Daroussin assert(meta->date); 101161d06d6bSBaptiste Daroussin 101261d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 101361d06d6bSBaptiste Daroussin 101461d06d6bSBaptiste Daroussin if (meta->hasbody) 101561d06d6bSBaptiste Daroussin term_vspace(p); 101661d06d6bSBaptiste Daroussin 101761d06d6bSBaptiste Daroussin /* 101861d06d6bSBaptiste Daroussin * Temporary, undocumented option to imitate mdoc(7) output. 101961d06d6bSBaptiste Daroussin * In the bottom right corner, use the operating system 102061d06d6bSBaptiste Daroussin * instead of the title. 102161d06d6bSBaptiste Daroussin */ 102261d06d6bSBaptiste Daroussin 102361d06d6bSBaptiste Daroussin if ( ! p->mdocstyle) { 102461d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", 102561d06d6bSBaptiste Daroussin meta->title, meta->msec); 10267295610fSBaptiste Daroussin } else if (meta->os != NULL) { 102761d06d6bSBaptiste Daroussin title = mandoc_strdup(meta->os); 102861d06d6bSBaptiste Daroussin } else { 102961d06d6bSBaptiste Daroussin title = mandoc_strdup(""); 103061d06d6bSBaptiste Daroussin } 103161d06d6bSBaptiste Daroussin datelen = term_strlen(p, meta->date); 103261d06d6bSBaptiste Daroussin 103361d06d6bSBaptiste Daroussin /* Bottom left corner: operating system. */ 103461d06d6bSBaptiste Daroussin 103561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 103661d06d6bSBaptiste Daroussin p->trailspace = 1; 103761d06d6bSBaptiste Daroussin p->tcol->offset = 0; 103861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin > datelen ? 103961d06d6bSBaptiste Daroussin (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; 104061d06d6bSBaptiste Daroussin 104161d06d6bSBaptiste Daroussin if (meta->os) 104261d06d6bSBaptiste Daroussin term_word(p, meta->os); 104361d06d6bSBaptiste Daroussin term_flushln(p); 104461d06d6bSBaptiste Daroussin 104561d06d6bSBaptiste Daroussin /* At the bottom in the middle: manual date. */ 104661d06d6bSBaptiste Daroussin 104761d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 104861d06d6bSBaptiste Daroussin titlen = term_strlen(p, title); 104961d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin > titlen ? 105061d06d6bSBaptiste Daroussin p->maxrmargin - titlen : 0; 105161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 105261d06d6bSBaptiste Daroussin 105361d06d6bSBaptiste Daroussin term_word(p, meta->date); 105461d06d6bSBaptiste Daroussin term_flushln(p); 105561d06d6bSBaptiste Daroussin 105661d06d6bSBaptiste Daroussin /* Bottom right corner: manual title and section. */ 105761d06d6bSBaptiste Daroussin 105861d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 105961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 106061d06d6bSBaptiste Daroussin p->trailspace = 0; 106161d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 106261d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 106361d06d6bSBaptiste Daroussin 106461d06d6bSBaptiste Daroussin term_word(p, title); 106561d06d6bSBaptiste Daroussin term_flushln(p); 106661d06d6bSBaptiste Daroussin 106761d06d6bSBaptiste Daroussin /* 106861d06d6bSBaptiste Daroussin * Reset the terminal state for more output after the footer: 106961d06d6bSBaptiste Daroussin * Some output modes, in particular PostScript and PDF, print 107061d06d6bSBaptiste Daroussin * the header and the footer into a buffer such that it can be 107161d06d6bSBaptiste Daroussin * reused for multiple output pages, then go on to format the 107261d06d6bSBaptiste Daroussin * main text. 107361d06d6bSBaptiste Daroussin */ 107461d06d6bSBaptiste Daroussin 107561d06d6bSBaptiste Daroussin p->tcol->offset = 0; 107661d06d6bSBaptiste Daroussin p->flags = 0; 107761d06d6bSBaptiste Daroussin 107861d06d6bSBaptiste Daroussin free(title); 107961d06d6bSBaptiste Daroussin } 108061d06d6bSBaptiste Daroussin 108161d06d6bSBaptiste Daroussin static void 108261d06d6bSBaptiste Daroussin print_man_head(struct termp *p, const struct roff_meta *meta) 108361d06d6bSBaptiste Daroussin { 108461d06d6bSBaptiste Daroussin const char *volume; 108561d06d6bSBaptiste Daroussin char *title; 108661d06d6bSBaptiste Daroussin size_t vollen, titlen; 108761d06d6bSBaptiste Daroussin 108861d06d6bSBaptiste Daroussin assert(meta->title); 108961d06d6bSBaptiste Daroussin assert(meta->msec); 109061d06d6bSBaptiste Daroussin 109161d06d6bSBaptiste Daroussin volume = NULL == meta->vol ? "" : meta->vol; 109261d06d6bSBaptiste Daroussin vollen = term_strlen(p, volume); 109361d06d6bSBaptiste Daroussin 109461d06d6bSBaptiste Daroussin /* Top left corner: manual title and section. */ 109561d06d6bSBaptiste Daroussin 109661d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); 109761d06d6bSBaptiste Daroussin titlen = term_strlen(p, title); 109861d06d6bSBaptiste Daroussin 109961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; 110061d06d6bSBaptiste Daroussin p->trailspace = 1; 110161d06d6bSBaptiste Daroussin p->tcol->offset = 0; 110261d06d6bSBaptiste Daroussin p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? 110361d06d6bSBaptiste Daroussin (p->maxrmargin - vollen + term_len(p, 1)) / 2 : 110461d06d6bSBaptiste Daroussin vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; 110561d06d6bSBaptiste Daroussin 110661d06d6bSBaptiste Daroussin term_word(p, title); 110761d06d6bSBaptiste Daroussin term_flushln(p); 110861d06d6bSBaptiste Daroussin 110961d06d6bSBaptiste Daroussin /* At the top in the middle: manual volume. */ 111061d06d6bSBaptiste Daroussin 111161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 111261d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 111361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->tcol->offset + vollen + titlen < 111461d06d6bSBaptiste Daroussin p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin; 111561d06d6bSBaptiste Daroussin 111661d06d6bSBaptiste Daroussin term_word(p, volume); 111761d06d6bSBaptiste Daroussin term_flushln(p); 111861d06d6bSBaptiste Daroussin 111961d06d6bSBaptiste Daroussin /* Top right corner: title and section, again. */ 112061d06d6bSBaptiste Daroussin 112161d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 112261d06d6bSBaptiste Daroussin p->trailspace = 0; 112361d06d6bSBaptiste Daroussin if (p->tcol->rmargin + titlen <= p->maxrmargin) { 112461d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 112561d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 112661d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 112761d06d6bSBaptiste Daroussin term_word(p, title); 112861d06d6bSBaptiste Daroussin term_flushln(p); 112961d06d6bSBaptiste Daroussin } 113061d06d6bSBaptiste Daroussin 113161d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOSPACE; 113261d06d6bSBaptiste Daroussin p->tcol->offset = 0; 113361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 113461d06d6bSBaptiste Daroussin 113561d06d6bSBaptiste Daroussin /* 113661d06d6bSBaptiste Daroussin * Groff prints three blank lines before the content. 113761d06d6bSBaptiste Daroussin * Do the same, except in the temporary, undocumented 113861d06d6bSBaptiste Daroussin * mode imitating mdoc(7) output. 113961d06d6bSBaptiste Daroussin */ 114061d06d6bSBaptiste Daroussin 114161d06d6bSBaptiste Daroussin term_vspace(p); 114261d06d6bSBaptiste Daroussin free(title); 114361d06d6bSBaptiste Daroussin } 1144