1*c1c95addSBrooks Davis /* $Id: man_term.c,v 1.244 2023/11/13 19:13:01 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 3*c1c95addSBrooks Davis * Copyright (c) 2010-15,2017-20,2022-23 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. 176d38604fSBaptiste Daroussin * 186d38604fSBaptiste Daroussin * Plain text formatter for man(7), used by mandoc(1) 196d38604fSBaptiste 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" 386d38604fSBaptiste 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 *, 706d38604fSBaptiste 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); 77*c1c95addSBrooks Davis static int pre_MR(DECL_ARGS); 7861d06d6bSBaptiste Daroussin static int pre_OP(DECL_ARGS); 7961d06d6bSBaptiste Daroussin static int pre_PD(DECL_ARGS); 8061d06d6bSBaptiste Daroussin static int pre_PP(DECL_ARGS); 8161d06d6bSBaptiste Daroussin static int pre_RS(DECL_ARGS); 8261d06d6bSBaptiste Daroussin static int pre_SH(DECL_ARGS); 8361d06d6bSBaptiste Daroussin static int pre_SS(DECL_ARGS); 847295610fSBaptiste Daroussin static int pre_SY(DECL_ARGS); 8561d06d6bSBaptiste Daroussin static int pre_TP(DECL_ARGS); 8661d06d6bSBaptiste Daroussin static int pre_UR(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 */ 106*c1c95addSBrooks Davis { pre_PP, NULL, 0 }, /* LP */ 10761d06d6bSBaptiste Daroussin { pre_PP, NULL, 0 }, /* PP */ 108*c1c95addSBrooks Davis { pre_PP, 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 */ 124*c1c95addSBrooks Davis { pre_DT, NULL, MAN_NOTEXT }, /* DT */ 12561d06d6bSBaptiste Daroussin { pre_ign, NULL, MAN_NOTEXT }, /* UC */ 12661d06d6bSBaptiste Daroussin { pre_PD, NULL, MAN_NOTEXT }, /* PD */ 127*c1c95addSBrooks Davis { pre_ign, NULL, MAN_NOTEXT }, /* 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 */ 138*c1c95addSBrooks Davis { pre_MR, NULL, 0 }, /* MR */ 13961d06d6bSBaptiste Daroussin }; 1407295610fSBaptiste Daroussin static const struct man_term_act *man_term_act(enum roff_tok); 14161d06d6bSBaptiste Daroussin 14261d06d6bSBaptiste Daroussin 1437295610fSBaptiste Daroussin static const struct man_term_act * 1447295610fSBaptiste Daroussin man_term_act(enum roff_tok tok) 1457295610fSBaptiste Daroussin { 1467295610fSBaptiste Daroussin assert(tok >= MAN_TH && tok <= MAN_MAX); 1477295610fSBaptiste Daroussin return man_term_acts + (tok - MAN_TH); 1487295610fSBaptiste Daroussin } 1497295610fSBaptiste Daroussin 15061d06d6bSBaptiste Daroussin void 1517295610fSBaptiste Daroussin terminal_man(void *arg, const struct roff_meta *man) 15261d06d6bSBaptiste Daroussin { 1537295610fSBaptiste Daroussin struct mtermp mt; 15461d06d6bSBaptiste Daroussin struct termp *p; 15545a5aec3SBaptiste Daroussin struct roff_node *n, *nc, *nn; 15661d06d6bSBaptiste Daroussin 15761d06d6bSBaptiste Daroussin p = (struct termp *)arg; 15861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin = p->defrmargin; 15961d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 16061d06d6bSBaptiste Daroussin term_tab_set(p, "T"); 16161d06d6bSBaptiste Daroussin term_tab_set(p, ".5i"); 16261d06d6bSBaptiste Daroussin 1637295610fSBaptiste Daroussin memset(&mt, 0, sizeof(mt)); 164*c1c95addSBrooks Davis mt.lmargin[mt.lmargincur] = term_len(p, 7); 16561d06d6bSBaptiste Daroussin mt.offset = term_len(p, p->defindent); 16661d06d6bSBaptiste Daroussin mt.pardist = 1; 16761d06d6bSBaptiste Daroussin 16861d06d6bSBaptiste Daroussin n = man->first->child; 16961d06d6bSBaptiste Daroussin if (p->synopsisonly) { 17045a5aec3SBaptiste Daroussin for (nn = NULL; n != NULL; n = n->next) { 17145a5aec3SBaptiste Daroussin if (n->tok != MAN_SH) 17245a5aec3SBaptiste Daroussin continue; 17345a5aec3SBaptiste Daroussin nc = n->child->child; 17445a5aec3SBaptiste Daroussin if (nc->type != ROFFT_TEXT) 17545a5aec3SBaptiste Daroussin continue; 17645a5aec3SBaptiste Daroussin if (strcmp(nc->string, "SYNOPSIS") == 0) 17761d06d6bSBaptiste Daroussin break; 17845a5aec3SBaptiste Daroussin if (nn == NULL && strcmp(nc->string, "NAME") == 0) 17945a5aec3SBaptiste Daroussin nn = n; 18061d06d6bSBaptiste Daroussin } 18145a5aec3SBaptiste Daroussin if (n == NULL) 18245a5aec3SBaptiste Daroussin n = nn; 18345a5aec3SBaptiste Daroussin p->flags |= TERMP_NOSPACE; 18445a5aec3SBaptiste Daroussin if (n != NULL && (n = n->child->next->child) != NULL) 18545a5aec3SBaptiste Daroussin print_man_nodelist(p, &mt, n, man); 18645a5aec3SBaptiste Daroussin term_newln(p); 18761d06d6bSBaptiste Daroussin } else { 1887295610fSBaptiste Daroussin term_begin(p, print_man_head, print_man_foot, man); 18961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 19061d06d6bSBaptiste Daroussin if (n != NULL) 1917295610fSBaptiste Daroussin print_man_nodelist(p, &mt, n, man); 19261d06d6bSBaptiste Daroussin term_end(p); 19361d06d6bSBaptiste Daroussin } 19461d06d6bSBaptiste Daroussin } 19561d06d6bSBaptiste Daroussin 19661d06d6bSBaptiste Daroussin /* 19761d06d6bSBaptiste Daroussin * Printing leading vertical space before a block. 19861d06d6bSBaptiste Daroussin * This is used for the paragraph macros. 19961d06d6bSBaptiste Daroussin * The rules are pretty simple, since there's very little nesting going 20061d06d6bSBaptiste Daroussin * on here. Basically, if we're the first within another block (SS/SH), 20161d06d6bSBaptiste Daroussin * then don't emit vertical space. If we are (RS), then do. If not the 20261d06d6bSBaptiste Daroussin * first, print it. 20361d06d6bSBaptiste Daroussin */ 20461d06d6bSBaptiste Daroussin static void 2056d38604fSBaptiste Daroussin print_bvspace(struct termp *p, struct roff_node *n, int pardist) 20661d06d6bSBaptiste Daroussin { 2076d38604fSBaptiste Daroussin struct roff_node *nch; 20861d06d6bSBaptiste Daroussin int i; 20961d06d6bSBaptiste Daroussin 21061d06d6bSBaptiste Daroussin term_newln(p); 21161d06d6bSBaptiste Daroussin 2126d38604fSBaptiste Daroussin if (n->body != NULL && 2136d38604fSBaptiste Daroussin (nch = roff_node_child(n->body)) != NULL && 2146d38604fSBaptiste Daroussin nch->type == ROFFT_TBL) 21561d06d6bSBaptiste Daroussin return; 21661d06d6bSBaptiste Daroussin 2176d38604fSBaptiste Daroussin if (n->parent->tok != MAN_RS && roff_node_prev(n) == NULL) 21861d06d6bSBaptiste Daroussin return; 21961d06d6bSBaptiste Daroussin 22061d06d6bSBaptiste Daroussin for (i = 0; i < pardist; i++) 22161d06d6bSBaptiste Daroussin term_vspace(p); 22261d06d6bSBaptiste Daroussin } 22361d06d6bSBaptiste Daroussin 2247295610fSBaptiste Daroussin static int 22561d06d6bSBaptiste Daroussin pre_ign(DECL_ARGS) 22661d06d6bSBaptiste Daroussin { 22761d06d6bSBaptiste Daroussin return 0; 22861d06d6bSBaptiste Daroussin } 22961d06d6bSBaptiste Daroussin 23061d06d6bSBaptiste Daroussin static int 23161d06d6bSBaptiste Daroussin pre_I(DECL_ARGS) 23261d06d6bSBaptiste Daroussin { 23361d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 23461d06d6bSBaptiste Daroussin return 1; 23561d06d6bSBaptiste Daroussin } 23661d06d6bSBaptiste Daroussin 23761d06d6bSBaptiste Daroussin static int 23861d06d6bSBaptiste Daroussin pre_literal(DECL_ARGS) 23961d06d6bSBaptiste Daroussin { 24061d06d6bSBaptiste Daroussin term_newln(p); 24161d06d6bSBaptiste Daroussin 24261d06d6bSBaptiste Daroussin /* 24361d06d6bSBaptiste Daroussin * Unlike .IP and .TP, .HP does not have a HEAD. 24461d06d6bSBaptiste Daroussin * So in case a second call to term_flushln() is needed, 24561d06d6bSBaptiste Daroussin * indentation has to be set up explicitly. 24661d06d6bSBaptiste Daroussin */ 24761d06d6bSBaptiste Daroussin if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) { 24861d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 24961d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 25061d06d6bSBaptiste Daroussin p->trailspace = 0; 25161d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 25261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 25361d06d6bSBaptiste Daroussin } 25461d06d6bSBaptiste Daroussin return 0; 25561d06d6bSBaptiste Daroussin } 25661d06d6bSBaptiste Daroussin 25761d06d6bSBaptiste Daroussin static int 25861d06d6bSBaptiste Daroussin pre_PD(DECL_ARGS) 25961d06d6bSBaptiste Daroussin { 26061d06d6bSBaptiste Daroussin struct roffsu su; 26161d06d6bSBaptiste Daroussin 26261d06d6bSBaptiste Daroussin n = n->child; 26361d06d6bSBaptiste Daroussin if (n == NULL) { 26461d06d6bSBaptiste Daroussin mt->pardist = 1; 26561d06d6bSBaptiste Daroussin return 0; 26661d06d6bSBaptiste Daroussin } 26761d06d6bSBaptiste Daroussin assert(n->type == ROFFT_TEXT); 26861d06d6bSBaptiste Daroussin if (a2roffsu(n->string, &su, SCALE_VS) != NULL) 26961d06d6bSBaptiste Daroussin mt->pardist = term_vspan(p, &su); 27061d06d6bSBaptiste Daroussin return 0; 27161d06d6bSBaptiste Daroussin } 27261d06d6bSBaptiste Daroussin 27361d06d6bSBaptiste Daroussin static int 27461d06d6bSBaptiste Daroussin pre_alternate(DECL_ARGS) 27561d06d6bSBaptiste Daroussin { 27661d06d6bSBaptiste Daroussin enum termfont font[2]; 27761d06d6bSBaptiste Daroussin struct roff_node *nn; 2787295610fSBaptiste Daroussin int i; 27961d06d6bSBaptiste Daroussin 28061d06d6bSBaptiste Daroussin switch (n->tok) { 28161d06d6bSBaptiste Daroussin case MAN_RB: 28261d06d6bSBaptiste Daroussin font[0] = TERMFONT_NONE; 28361d06d6bSBaptiste Daroussin font[1] = TERMFONT_BOLD; 28461d06d6bSBaptiste Daroussin break; 28561d06d6bSBaptiste Daroussin case MAN_RI: 28661d06d6bSBaptiste Daroussin font[0] = TERMFONT_NONE; 28761d06d6bSBaptiste Daroussin font[1] = TERMFONT_UNDER; 28861d06d6bSBaptiste Daroussin break; 28961d06d6bSBaptiste Daroussin case MAN_BR: 29061d06d6bSBaptiste Daroussin font[0] = TERMFONT_BOLD; 29161d06d6bSBaptiste Daroussin font[1] = TERMFONT_NONE; 29261d06d6bSBaptiste Daroussin break; 29361d06d6bSBaptiste Daroussin case MAN_BI: 29461d06d6bSBaptiste Daroussin font[0] = TERMFONT_BOLD; 29561d06d6bSBaptiste Daroussin font[1] = TERMFONT_UNDER; 29661d06d6bSBaptiste Daroussin break; 29761d06d6bSBaptiste Daroussin case MAN_IR: 29861d06d6bSBaptiste Daroussin font[0] = TERMFONT_UNDER; 29961d06d6bSBaptiste Daroussin font[1] = TERMFONT_NONE; 30061d06d6bSBaptiste Daroussin break; 30161d06d6bSBaptiste Daroussin case MAN_IB: 30261d06d6bSBaptiste Daroussin font[0] = TERMFONT_UNDER; 30361d06d6bSBaptiste Daroussin font[1] = TERMFONT_BOLD; 30461d06d6bSBaptiste Daroussin break; 30561d06d6bSBaptiste Daroussin default: 30661d06d6bSBaptiste Daroussin abort(); 30761d06d6bSBaptiste Daroussin } 3087295610fSBaptiste Daroussin for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) { 30961d06d6bSBaptiste Daroussin term_fontrepl(p, font[i]); 31061d06d6bSBaptiste Daroussin assert(nn->type == ROFFT_TEXT); 31161d06d6bSBaptiste Daroussin term_word(p, nn->string); 31261d06d6bSBaptiste Daroussin if (nn->flags & NODE_EOS) 31361d06d6bSBaptiste Daroussin p->flags |= TERMP_SENTENCE; 3147295610fSBaptiste Daroussin if (nn->next != NULL) 31561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 31661d06d6bSBaptiste Daroussin } 31761d06d6bSBaptiste Daroussin return 0; 31861d06d6bSBaptiste Daroussin } 31961d06d6bSBaptiste Daroussin 32061d06d6bSBaptiste Daroussin static int 32161d06d6bSBaptiste Daroussin pre_B(DECL_ARGS) 32261d06d6bSBaptiste Daroussin { 32361d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 32461d06d6bSBaptiste Daroussin return 1; 32561d06d6bSBaptiste Daroussin } 32661d06d6bSBaptiste Daroussin 32761d06d6bSBaptiste Daroussin static int 328*c1c95addSBrooks Davis pre_MR(DECL_ARGS) 329*c1c95addSBrooks Davis { 330*c1c95addSBrooks Davis term_fontrepl(p, TERMFONT_NONE); 331*c1c95addSBrooks Davis n = n->child; 332*c1c95addSBrooks Davis if (n != NULL) { 333*c1c95addSBrooks Davis term_word(p, n->string); /* name */ 334*c1c95addSBrooks Davis p->flags |= TERMP_NOSPACE; 335*c1c95addSBrooks Davis } 336*c1c95addSBrooks Davis term_word(p, "("); 337*c1c95addSBrooks Davis p->flags |= TERMP_NOSPACE; 338*c1c95addSBrooks Davis if (n != NULL && (n = n->next) != NULL) { 339*c1c95addSBrooks Davis term_word(p, n->string); /* section */ 340*c1c95addSBrooks Davis p->flags |= TERMP_NOSPACE; 341*c1c95addSBrooks Davis } 342*c1c95addSBrooks Davis term_word(p, ")"); 343*c1c95addSBrooks Davis if (n != NULL && (n = n->next) != NULL) { 344*c1c95addSBrooks Davis p->flags |= TERMP_NOSPACE; 345*c1c95addSBrooks Davis term_word(p, n->string); /* suffix */ 346*c1c95addSBrooks Davis } 347*c1c95addSBrooks Davis return 0; 348*c1c95addSBrooks Davis } 349*c1c95addSBrooks Davis 350*c1c95addSBrooks Davis static int 35161d06d6bSBaptiste Daroussin pre_OP(DECL_ARGS) 35261d06d6bSBaptiste Daroussin { 35361d06d6bSBaptiste Daroussin term_word(p, "["); 3547295610fSBaptiste Daroussin p->flags |= TERMP_KEEP | TERMP_NOSPACE; 35561d06d6bSBaptiste Daroussin 3567295610fSBaptiste Daroussin if ((n = n->child) != NULL) { 35761d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 35861d06d6bSBaptiste Daroussin term_word(p, n->string); 35961d06d6bSBaptiste Daroussin } 3607295610fSBaptiste Daroussin if (n != NULL && n->next != NULL) { 36161d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 36261d06d6bSBaptiste Daroussin term_word(p, n->next->string); 36361d06d6bSBaptiste Daroussin } 36461d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 3657295610fSBaptiste Daroussin p->flags &= ~TERMP_KEEP; 36661d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 36761d06d6bSBaptiste Daroussin term_word(p, "]"); 36861d06d6bSBaptiste Daroussin return 0; 36961d06d6bSBaptiste Daroussin } 37061d06d6bSBaptiste Daroussin 37161d06d6bSBaptiste Daroussin static int 37261d06d6bSBaptiste Daroussin pre_in(DECL_ARGS) 37361d06d6bSBaptiste Daroussin { 37461d06d6bSBaptiste Daroussin struct roffsu su; 37561d06d6bSBaptiste Daroussin const char *cp; 37661d06d6bSBaptiste Daroussin size_t v; 37761d06d6bSBaptiste Daroussin int less; 37861d06d6bSBaptiste Daroussin 37961d06d6bSBaptiste Daroussin term_newln(p); 38061d06d6bSBaptiste Daroussin 38161d06d6bSBaptiste Daroussin if (n->child == NULL) { 38261d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 38361d06d6bSBaptiste Daroussin return 0; 38461d06d6bSBaptiste Daroussin } 38561d06d6bSBaptiste Daroussin 38661d06d6bSBaptiste Daroussin cp = n->child->string; 38761d06d6bSBaptiste Daroussin less = 0; 38861d06d6bSBaptiste Daroussin 3897295610fSBaptiste Daroussin if (*cp == '-') 39061d06d6bSBaptiste Daroussin less = -1; 3917295610fSBaptiste Daroussin else if (*cp == '+') 39261d06d6bSBaptiste Daroussin less = 1; 39361d06d6bSBaptiste Daroussin else 39461d06d6bSBaptiste Daroussin cp--; 39561d06d6bSBaptiste Daroussin 39661d06d6bSBaptiste Daroussin if (a2roffsu(++cp, &su, SCALE_EN) == NULL) 39761d06d6bSBaptiste Daroussin return 0; 39861d06d6bSBaptiste Daroussin 39961d06d6bSBaptiste Daroussin v = term_hen(p, &su); 40061d06d6bSBaptiste Daroussin 40161d06d6bSBaptiste Daroussin if (less < 0) 40261d06d6bSBaptiste Daroussin p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset; 40361d06d6bSBaptiste Daroussin else if (less > 0) 40461d06d6bSBaptiste Daroussin p->tcol->offset += v; 40561d06d6bSBaptiste Daroussin else 40661d06d6bSBaptiste Daroussin p->tcol->offset = v; 40761d06d6bSBaptiste Daroussin if (p->tcol->offset > SHRT_MAX) 40861d06d6bSBaptiste Daroussin p->tcol->offset = term_len(p, p->defindent); 40961d06d6bSBaptiste Daroussin 41061d06d6bSBaptiste Daroussin return 0; 41161d06d6bSBaptiste Daroussin } 41261d06d6bSBaptiste Daroussin 41361d06d6bSBaptiste Daroussin static int 41461d06d6bSBaptiste Daroussin pre_DT(DECL_ARGS) 41561d06d6bSBaptiste Daroussin { 41661d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 41761d06d6bSBaptiste Daroussin term_tab_set(p, "T"); 41861d06d6bSBaptiste Daroussin term_tab_set(p, ".5i"); 41961d06d6bSBaptiste Daroussin return 0; 42061d06d6bSBaptiste Daroussin } 42161d06d6bSBaptiste Daroussin 42261d06d6bSBaptiste Daroussin static int 42361d06d6bSBaptiste Daroussin pre_HP(DECL_ARGS) 42461d06d6bSBaptiste Daroussin { 42561d06d6bSBaptiste Daroussin struct roffsu su; 42661d06d6bSBaptiste Daroussin const struct roff_node *nn; 42761d06d6bSBaptiste Daroussin int len; 42861d06d6bSBaptiste Daroussin 42961d06d6bSBaptiste Daroussin switch (n->type) { 43061d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 43161d06d6bSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 43261d06d6bSBaptiste Daroussin return 1; 4337295610fSBaptiste Daroussin case ROFFT_HEAD: 4347295610fSBaptiste Daroussin return 0; 43561d06d6bSBaptiste Daroussin case ROFFT_BODY: 43661d06d6bSBaptiste Daroussin break; 43761d06d6bSBaptiste Daroussin default: 4387295610fSBaptiste Daroussin abort(); 43961d06d6bSBaptiste Daroussin } 44061d06d6bSBaptiste Daroussin 4417295610fSBaptiste Daroussin if (n->child == NULL) 4427295610fSBaptiste Daroussin return 0; 4437295610fSBaptiste Daroussin 4447295610fSBaptiste Daroussin if ((n->child->flags & NODE_NOFILL) == 0) { 44561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 44661d06d6bSBaptiste Daroussin p->trailspace = 2; 44761d06d6bSBaptiste Daroussin } 44861d06d6bSBaptiste Daroussin 44961d06d6bSBaptiste Daroussin /* Calculate offset. */ 45061d06d6bSBaptiste Daroussin 45161d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 45261d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 45361d06d6bSBaptiste Daroussin len = term_hen(p, &su); 45461d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 45561d06d6bSBaptiste Daroussin len = -mt->offset; 45661d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 45761d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 45861d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 45961d06d6bSBaptiste Daroussin } else 46061d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 46161d06d6bSBaptiste Daroussin 46261d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 46361d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 46461d06d6bSBaptiste Daroussin return 1; 46561d06d6bSBaptiste Daroussin } 46661d06d6bSBaptiste Daroussin 46761d06d6bSBaptiste Daroussin static void 46861d06d6bSBaptiste Daroussin post_HP(DECL_ARGS) 46961d06d6bSBaptiste Daroussin { 47061d06d6bSBaptiste Daroussin switch (n->type) { 4717295610fSBaptiste Daroussin case ROFFT_BLOCK: 4727295610fSBaptiste Daroussin case ROFFT_HEAD: 4737295610fSBaptiste Daroussin break; 47461d06d6bSBaptiste Daroussin case ROFFT_BODY: 47561d06d6bSBaptiste Daroussin term_newln(p); 47661d06d6bSBaptiste Daroussin 47761d06d6bSBaptiste Daroussin /* 47861d06d6bSBaptiste Daroussin * Compatibility with a groff bug. 47961d06d6bSBaptiste Daroussin * The .HP macro uses the undocumented .tag request 48061d06d6bSBaptiste Daroussin * which causes a line break and cancels no-space 48161d06d6bSBaptiste Daroussin * mode even if there isn't any output. 48261d06d6bSBaptiste Daroussin */ 48361d06d6bSBaptiste Daroussin 48461d06d6bSBaptiste Daroussin if (n->child == NULL) 48561d06d6bSBaptiste Daroussin term_vspace(p); 48661d06d6bSBaptiste Daroussin 48761d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 48861d06d6bSBaptiste Daroussin p->trailspace = 0; 48961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 49061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 49161d06d6bSBaptiste Daroussin break; 49261d06d6bSBaptiste Daroussin default: 4937295610fSBaptiste Daroussin abort(); 49461d06d6bSBaptiste Daroussin } 49561d06d6bSBaptiste Daroussin } 49661d06d6bSBaptiste Daroussin 49761d06d6bSBaptiste Daroussin static int 49861d06d6bSBaptiste Daroussin pre_PP(DECL_ARGS) 49961d06d6bSBaptiste Daroussin { 50061d06d6bSBaptiste Daroussin switch (n->type) { 50161d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 502*c1c95addSBrooks Davis mt->lmargin[mt->lmargincur] = term_len(p, 7); 50361d06d6bSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 50461d06d6bSBaptiste Daroussin break; 5057295610fSBaptiste Daroussin case ROFFT_HEAD: 5067295610fSBaptiste Daroussin return 0; 5077295610fSBaptiste Daroussin case ROFFT_BODY: 50861d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 50961d06d6bSBaptiste Daroussin break; 5107295610fSBaptiste Daroussin default: 5117295610fSBaptiste Daroussin abort(); 51261d06d6bSBaptiste Daroussin } 5137295610fSBaptiste Daroussin return 1; 51461d06d6bSBaptiste Daroussin } 51561d06d6bSBaptiste Daroussin 51661d06d6bSBaptiste Daroussin static int 51761d06d6bSBaptiste Daroussin pre_IP(DECL_ARGS) 51861d06d6bSBaptiste Daroussin { 51961d06d6bSBaptiste Daroussin struct roffsu su; 52061d06d6bSBaptiste Daroussin const struct roff_node *nn; 5217295610fSBaptiste Daroussin int len; 52261d06d6bSBaptiste Daroussin 52361d06d6bSBaptiste Daroussin switch (n->type) { 5247295610fSBaptiste Daroussin case ROFFT_BLOCK: 5257295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 5267295610fSBaptiste Daroussin return 1; 52761d06d6bSBaptiste Daroussin case ROFFT_HEAD: 52861d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 52961d06d6bSBaptiste Daroussin p->trailspace = 1; 53061d06d6bSBaptiste Daroussin break; 5317295610fSBaptiste Daroussin case ROFFT_BODY: 532*c1c95addSBrooks Davis p->flags |= TERMP_NOSPACE | TERMP_NONEWLINE; 5337295610fSBaptiste Daroussin break; 53461d06d6bSBaptiste Daroussin default: 5357295610fSBaptiste Daroussin abort(); 53661d06d6bSBaptiste Daroussin } 53761d06d6bSBaptiste Daroussin 53861d06d6bSBaptiste Daroussin /* Calculate the offset from the optional second argument. */ 53961d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 54061d06d6bSBaptiste Daroussin (nn = nn->next) != NULL && 54161d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 54261d06d6bSBaptiste Daroussin len = term_hen(p, &su); 54361d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 54461d06d6bSBaptiste Daroussin len = -mt->offset; 54561d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 54661d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 54761d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 54861d06d6bSBaptiste Daroussin } else 54961d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 55061d06d6bSBaptiste Daroussin 55161d06d6bSBaptiste Daroussin switch (n->type) { 55261d06d6bSBaptiste Daroussin case ROFFT_HEAD: 55361d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 55461d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 5556d38604fSBaptiste Daroussin if (n->child != NULL) 55661d06d6bSBaptiste Daroussin print_man_node(p, mt, n->child, meta); 55761d06d6bSBaptiste Daroussin return 0; 55861d06d6bSBaptiste Daroussin case ROFFT_BODY: 55961d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset + len; 56061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 56161d06d6bSBaptiste Daroussin break; 56261d06d6bSBaptiste Daroussin default: 5637295610fSBaptiste Daroussin abort(); 56461d06d6bSBaptiste Daroussin } 56561d06d6bSBaptiste Daroussin return 1; 56661d06d6bSBaptiste Daroussin } 56761d06d6bSBaptiste Daroussin 56861d06d6bSBaptiste Daroussin static void 56961d06d6bSBaptiste Daroussin post_IP(DECL_ARGS) 57061d06d6bSBaptiste Daroussin { 57161d06d6bSBaptiste Daroussin switch (n->type) { 5727295610fSBaptiste Daroussin case ROFFT_BLOCK: 5737295610fSBaptiste Daroussin break; 57461d06d6bSBaptiste Daroussin case ROFFT_HEAD: 57561d06d6bSBaptiste Daroussin term_flushln(p); 57661d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 57761d06d6bSBaptiste Daroussin p->trailspace = 0; 57861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 57961d06d6bSBaptiste Daroussin break; 58061d06d6bSBaptiste Daroussin case ROFFT_BODY: 58161d06d6bSBaptiste Daroussin term_newln(p); 58261d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 58361d06d6bSBaptiste Daroussin break; 58461d06d6bSBaptiste Daroussin default: 5857295610fSBaptiste Daroussin abort(); 58661d06d6bSBaptiste Daroussin } 58761d06d6bSBaptiste Daroussin } 58861d06d6bSBaptiste Daroussin 58961d06d6bSBaptiste Daroussin static int 59061d06d6bSBaptiste Daroussin pre_TP(DECL_ARGS) 59161d06d6bSBaptiste Daroussin { 59261d06d6bSBaptiste Daroussin struct roffsu su; 59361d06d6bSBaptiste Daroussin struct roff_node *nn; 5947295610fSBaptiste Daroussin int len; 59561d06d6bSBaptiste Daroussin 59661d06d6bSBaptiste Daroussin switch (n->type) { 5977295610fSBaptiste Daroussin case ROFFT_BLOCK: 5987295610fSBaptiste Daroussin if (n->tok == MAN_TP) 5997295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 6007295610fSBaptiste Daroussin return 1; 60161d06d6bSBaptiste Daroussin case ROFFT_HEAD: 60261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRTRSP; 60361d06d6bSBaptiste Daroussin p->trailspace = 1; 60461d06d6bSBaptiste Daroussin break; 60561d06d6bSBaptiste Daroussin case ROFFT_BODY: 606*c1c95addSBrooks Davis p->flags |= TERMP_NOSPACE | TERMP_NONEWLINE; 60761d06d6bSBaptiste Daroussin break; 60861d06d6bSBaptiste Daroussin default: 6097295610fSBaptiste Daroussin abort(); 61061d06d6bSBaptiste Daroussin } 61161d06d6bSBaptiste Daroussin 61261d06d6bSBaptiste Daroussin /* Calculate offset. */ 61361d06d6bSBaptiste Daroussin 61461d06d6bSBaptiste Daroussin if ((nn = n->parent->head->child) != NULL && 61561d06d6bSBaptiste Daroussin nn->string != NULL && ! (NODE_LINE & nn->flags) && 61661d06d6bSBaptiste Daroussin a2roffsu(nn->string, &su, SCALE_EN) != NULL) { 61761d06d6bSBaptiste Daroussin len = term_hen(p, &su); 61861d06d6bSBaptiste Daroussin if (len < 0 && (size_t)(-len) > mt->offset) 61961d06d6bSBaptiste Daroussin len = -mt->offset; 62061d06d6bSBaptiste Daroussin else if (len > SHRT_MAX) 62161d06d6bSBaptiste Daroussin len = term_len(p, p->defindent); 62261d06d6bSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 62361d06d6bSBaptiste Daroussin } else 62461d06d6bSBaptiste Daroussin len = mt->lmargin[mt->lmargincur]; 62561d06d6bSBaptiste Daroussin 62661d06d6bSBaptiste Daroussin switch (n->type) { 62761d06d6bSBaptiste Daroussin case ROFFT_HEAD: 62861d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 62961d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 63061d06d6bSBaptiste Daroussin 63161d06d6bSBaptiste Daroussin /* Don't print same-line elements. */ 63261d06d6bSBaptiste Daroussin nn = n->child; 6337295610fSBaptiste Daroussin while (nn != NULL && (nn->flags & NODE_LINE) == 0) 63461d06d6bSBaptiste Daroussin nn = nn->next; 63561d06d6bSBaptiste 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: 678*c1c95addSBrooks Davis mt->lmargin[mt->lmargincur] = term_len(p, 7); 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 6866d38604fSBaptiste Daroussin if ((n = roff_node_prev(n)) == NULL || 6876d38604fSBaptiste Daroussin (n->tok == MAN_SS && roff_node_child(n->body) == NULL)) 68861d06d6bSBaptiste Daroussin break; 68961d06d6bSBaptiste Daroussin 69061d06d6bSBaptiste Daroussin for (i = 0; i < mt->pardist; i++) 69161d06d6bSBaptiste Daroussin term_vspace(p); 69261d06d6bSBaptiste Daroussin break; 69361d06d6bSBaptiste Daroussin case ROFFT_HEAD: 69461d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 69561d06d6bSBaptiste Daroussin p->tcol->offset = term_len(p, 3); 69661d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset; 69761d06d6bSBaptiste Daroussin p->trailspace = mt->offset; 69861d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 69961d06d6bSBaptiste Daroussin break; 70061d06d6bSBaptiste Daroussin case ROFFT_BODY: 70161d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 70261d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 70361d06d6bSBaptiste Daroussin p->trailspace = 0; 70461d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 70561d06d6bSBaptiste Daroussin break; 70661d06d6bSBaptiste Daroussin default: 70761d06d6bSBaptiste Daroussin break; 70861d06d6bSBaptiste Daroussin } 70961d06d6bSBaptiste Daroussin return 1; 71061d06d6bSBaptiste Daroussin } 71161d06d6bSBaptiste Daroussin 71261d06d6bSBaptiste Daroussin static int 71361d06d6bSBaptiste Daroussin pre_SH(DECL_ARGS) 71461d06d6bSBaptiste Daroussin { 71561d06d6bSBaptiste Daroussin int i; 71661d06d6bSBaptiste Daroussin 71761d06d6bSBaptiste Daroussin switch (n->type) { 71861d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 719*c1c95addSBrooks Davis mt->lmargin[mt->lmargincur] = term_len(p, 7); 72061d06d6bSBaptiste Daroussin mt->offset = term_len(p, p->defindent); 72161d06d6bSBaptiste Daroussin 72261d06d6bSBaptiste Daroussin /* 72361d06d6bSBaptiste Daroussin * No vertical space before the first section 72461d06d6bSBaptiste Daroussin * and after an empty section. 72561d06d6bSBaptiste Daroussin */ 72661d06d6bSBaptiste Daroussin 7276d38604fSBaptiste Daroussin if ((n = roff_node_prev(n)) == NULL || 7286d38604fSBaptiste Daroussin (n->tok == MAN_SH && roff_node_child(n->body) == NULL)) 72961d06d6bSBaptiste Daroussin break; 73061d06d6bSBaptiste Daroussin 73161d06d6bSBaptiste Daroussin for (i = 0; i < mt->pardist; i++) 73261d06d6bSBaptiste Daroussin term_vspace(p); 73361d06d6bSBaptiste Daroussin break; 73461d06d6bSBaptiste Daroussin case ROFFT_HEAD: 73561d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 73661d06d6bSBaptiste Daroussin p->tcol->offset = 0; 73761d06d6bSBaptiste Daroussin p->tcol->rmargin = mt->offset; 73861d06d6bSBaptiste Daroussin p->trailspace = mt->offset; 73961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_BRIND; 74061d06d6bSBaptiste Daroussin break; 74161d06d6bSBaptiste Daroussin case ROFFT_BODY: 74261d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 74361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 74461d06d6bSBaptiste Daroussin p->trailspace = 0; 74561d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 74661d06d6bSBaptiste Daroussin break; 74761d06d6bSBaptiste Daroussin default: 7487295610fSBaptiste Daroussin abort(); 74961d06d6bSBaptiste Daroussin } 75061d06d6bSBaptiste Daroussin return 1; 75161d06d6bSBaptiste Daroussin } 75261d06d6bSBaptiste Daroussin 75361d06d6bSBaptiste Daroussin static void 75461d06d6bSBaptiste Daroussin post_SH(DECL_ARGS) 75561d06d6bSBaptiste Daroussin { 75661d06d6bSBaptiste Daroussin switch (n->type) { 7577295610fSBaptiste Daroussin case ROFFT_BLOCK: 75861d06d6bSBaptiste Daroussin break; 7597295610fSBaptiste Daroussin case ROFFT_HEAD: 76061d06d6bSBaptiste Daroussin case ROFFT_BODY: 76161d06d6bSBaptiste Daroussin term_newln(p); 76261d06d6bSBaptiste Daroussin break; 76361d06d6bSBaptiste Daroussin default: 7647295610fSBaptiste Daroussin abort(); 76561d06d6bSBaptiste Daroussin } 76661d06d6bSBaptiste Daroussin } 76761d06d6bSBaptiste Daroussin 76861d06d6bSBaptiste Daroussin static int 76961d06d6bSBaptiste Daroussin pre_RS(DECL_ARGS) 77061d06d6bSBaptiste Daroussin { 77161d06d6bSBaptiste Daroussin struct roffsu su; 77261d06d6bSBaptiste Daroussin 77361d06d6bSBaptiste Daroussin switch (n->type) { 77461d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 77561d06d6bSBaptiste Daroussin term_newln(p); 77661d06d6bSBaptiste Daroussin return 1; 77761d06d6bSBaptiste Daroussin case ROFFT_HEAD: 77861d06d6bSBaptiste Daroussin return 0; 7797295610fSBaptiste Daroussin case ROFFT_BODY: 78061d06d6bSBaptiste Daroussin break; 7817295610fSBaptiste Daroussin default: 7827295610fSBaptiste Daroussin abort(); 78361d06d6bSBaptiste Daroussin } 78461d06d6bSBaptiste Daroussin 78561d06d6bSBaptiste Daroussin n = n->parent->head; 78661d06d6bSBaptiste Daroussin n->aux = SHRT_MAX + 1; 78761d06d6bSBaptiste Daroussin if (n->child == NULL) 78861d06d6bSBaptiste Daroussin n->aux = mt->lmargin[mt->lmargincur]; 78961d06d6bSBaptiste Daroussin else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL) 79061d06d6bSBaptiste Daroussin n->aux = term_hen(p, &su); 79161d06d6bSBaptiste Daroussin if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) 79261d06d6bSBaptiste Daroussin n->aux = -mt->offset; 79361d06d6bSBaptiste Daroussin else if (n->aux > SHRT_MAX) 79461d06d6bSBaptiste Daroussin n->aux = term_len(p, p->defindent); 79561d06d6bSBaptiste Daroussin 79661d06d6bSBaptiste Daroussin mt->offset += n->aux; 79761d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 79861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 79961d06d6bSBaptiste Daroussin 80061d06d6bSBaptiste Daroussin if (++mt->lmarginsz < MAXMARGINS) 80161d06d6bSBaptiste Daroussin mt->lmargincur = mt->lmarginsz; 80261d06d6bSBaptiste Daroussin 803*c1c95addSBrooks Davis mt->lmargin[mt->lmargincur] = term_len(p, 7); 80461d06d6bSBaptiste Daroussin return 1; 80561d06d6bSBaptiste Daroussin } 80661d06d6bSBaptiste Daroussin 80761d06d6bSBaptiste Daroussin static void 80861d06d6bSBaptiste Daroussin post_RS(DECL_ARGS) 80961d06d6bSBaptiste Daroussin { 81061d06d6bSBaptiste Daroussin switch (n->type) { 81161d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 81261d06d6bSBaptiste Daroussin case ROFFT_HEAD: 81361d06d6bSBaptiste Daroussin return; 8147295610fSBaptiste Daroussin case ROFFT_BODY: 81561d06d6bSBaptiste Daroussin break; 8167295610fSBaptiste Daroussin default: 8177295610fSBaptiste Daroussin abort(); 81861d06d6bSBaptiste Daroussin } 8197295610fSBaptiste Daroussin term_newln(p); 82061d06d6bSBaptiste Daroussin mt->offset -= n->parent->head->aux; 82161d06d6bSBaptiste Daroussin p->tcol->offset = mt->offset; 82261d06d6bSBaptiste Daroussin if (--mt->lmarginsz < MAXMARGINS) 82361d06d6bSBaptiste Daroussin mt->lmargincur = mt->lmarginsz; 82461d06d6bSBaptiste Daroussin } 82561d06d6bSBaptiste Daroussin 82661d06d6bSBaptiste Daroussin static int 8277295610fSBaptiste Daroussin pre_SY(DECL_ARGS) 8287295610fSBaptiste Daroussin { 8297295610fSBaptiste Daroussin const struct roff_node *nn; 8307295610fSBaptiste Daroussin int len; 8317295610fSBaptiste Daroussin 8327295610fSBaptiste Daroussin switch (n->type) { 8337295610fSBaptiste Daroussin case ROFFT_BLOCK: 8346d38604fSBaptiste Daroussin if ((nn = roff_node_prev(n)) == NULL || nn->tok != MAN_SY) 8357295610fSBaptiste Daroussin print_bvspace(p, n, mt->pardist); 8367295610fSBaptiste Daroussin return 1; 8377295610fSBaptiste Daroussin case ROFFT_HEAD: 8387295610fSBaptiste Daroussin case ROFFT_BODY: 8397295610fSBaptiste Daroussin break; 8407295610fSBaptiste Daroussin default: 8417295610fSBaptiste Daroussin abort(); 8427295610fSBaptiste Daroussin } 8437295610fSBaptiste Daroussin 8447295610fSBaptiste Daroussin nn = n->parent->head->child; 8457295610fSBaptiste Daroussin len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1; 8467295610fSBaptiste Daroussin 8477295610fSBaptiste Daroussin switch (n->type) { 8487295610fSBaptiste Daroussin case ROFFT_HEAD: 8497295610fSBaptiste Daroussin p->tcol->offset = mt->offset; 8507295610fSBaptiste Daroussin p->tcol->rmargin = mt->offset + len; 8517295610fSBaptiste Daroussin if (n->next->child == NULL || 8527295610fSBaptiste Daroussin (n->next->child->flags & NODE_NOFILL) == 0) 8537295610fSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 8547295610fSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 8557295610fSBaptiste Daroussin break; 8567295610fSBaptiste Daroussin case ROFFT_BODY: 8577295610fSBaptiste Daroussin mt->lmargin[mt->lmargincur] = len; 8587295610fSBaptiste Daroussin p->tcol->offset = mt->offset + len; 8597295610fSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 8607295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 8617295610fSBaptiste Daroussin break; 8627295610fSBaptiste Daroussin default: 8637295610fSBaptiste Daroussin abort(); 8647295610fSBaptiste Daroussin } 8657295610fSBaptiste Daroussin return 1; 8667295610fSBaptiste Daroussin } 8677295610fSBaptiste Daroussin 8687295610fSBaptiste Daroussin static void 8697295610fSBaptiste Daroussin post_SY(DECL_ARGS) 8707295610fSBaptiste Daroussin { 8717295610fSBaptiste Daroussin switch (n->type) { 8727295610fSBaptiste Daroussin case ROFFT_BLOCK: 8737295610fSBaptiste Daroussin break; 8747295610fSBaptiste Daroussin case ROFFT_HEAD: 8757295610fSBaptiste Daroussin term_flushln(p); 8767295610fSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 8777295610fSBaptiste Daroussin break; 8787295610fSBaptiste Daroussin case ROFFT_BODY: 8797295610fSBaptiste Daroussin term_newln(p); 8807295610fSBaptiste Daroussin p->tcol->offset = mt->offset; 8817295610fSBaptiste Daroussin break; 8827295610fSBaptiste Daroussin default: 8837295610fSBaptiste Daroussin abort(); 8847295610fSBaptiste Daroussin } 8857295610fSBaptiste Daroussin } 8867295610fSBaptiste Daroussin 8877295610fSBaptiste Daroussin static int 88861d06d6bSBaptiste Daroussin pre_UR(DECL_ARGS) 88961d06d6bSBaptiste Daroussin { 89061d06d6bSBaptiste Daroussin return n->type != ROFFT_HEAD; 89161d06d6bSBaptiste Daroussin } 89261d06d6bSBaptiste Daroussin 89361d06d6bSBaptiste Daroussin static void 89461d06d6bSBaptiste Daroussin post_UR(DECL_ARGS) 89561d06d6bSBaptiste Daroussin { 89661d06d6bSBaptiste Daroussin if (n->type != ROFFT_BLOCK) 89761d06d6bSBaptiste Daroussin return; 89861d06d6bSBaptiste Daroussin 89961d06d6bSBaptiste Daroussin term_word(p, "<"); 90061d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 90161d06d6bSBaptiste Daroussin 9027295610fSBaptiste Daroussin if (n->child->child != NULL) 90361d06d6bSBaptiste Daroussin print_man_node(p, mt, n->child->child, meta); 90461d06d6bSBaptiste Daroussin 90561d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 90661d06d6bSBaptiste Daroussin term_word(p, ">"); 90761d06d6bSBaptiste Daroussin } 90861d06d6bSBaptiste Daroussin 90961d06d6bSBaptiste Daroussin static void 91061d06d6bSBaptiste Daroussin print_man_node(DECL_ARGS) 91161d06d6bSBaptiste Daroussin { 9127295610fSBaptiste Daroussin const struct man_term_act *act; 91361d06d6bSBaptiste Daroussin int c; 91461d06d6bSBaptiste Daroussin 915*c1c95addSBrooks Davis /* 916*c1c95addSBrooks Davis * In no-fill mode, break the output line at the beginning 917*c1c95addSBrooks Davis * of new input lines except after \c, and nowhere else. 918*c1c95addSBrooks Davis */ 919*c1c95addSBrooks Davis 920*c1c95addSBrooks Davis if (n->flags & NODE_NOFILL) { 921*c1c95addSBrooks Davis if (n->flags & NODE_LINE && 922*c1c95addSBrooks Davis (p->flags & TERMP_NONEWLINE) == 0) 923*c1c95addSBrooks Davis term_newln(p); 924*c1c95addSBrooks Davis p->flags |= TERMP_BRNEVER; 925*c1c95addSBrooks Davis } else { 926*c1c95addSBrooks Davis if (n->flags & NODE_LINE) 927*c1c95addSBrooks Davis term_tab_ref(p); 928*c1c95addSBrooks Davis p->flags &= ~TERMP_BRNEVER; 929*c1c95addSBrooks Davis } 930*c1c95addSBrooks Davis 9316d38604fSBaptiste Daroussin if (n->flags & NODE_ID) 9326d38604fSBaptiste Daroussin term_tag_write(n, p->line); 9336d38604fSBaptiste Daroussin 93461d06d6bSBaptiste Daroussin switch (n->type) { 93561d06d6bSBaptiste Daroussin case ROFFT_TEXT: 93661d06d6bSBaptiste Daroussin /* 93761d06d6bSBaptiste Daroussin * If we have a blank line, output a vertical space. 93861d06d6bSBaptiste Daroussin * If we have a space as the first character, break 93961d06d6bSBaptiste Daroussin * before printing the line's data. 94061d06d6bSBaptiste Daroussin */ 94161d06d6bSBaptiste Daroussin if (*n->string == '\0') { 94261d06d6bSBaptiste Daroussin if (p->flags & TERMP_NONEWLINE) 94361d06d6bSBaptiste Daroussin term_newln(p); 94461d06d6bSBaptiste Daroussin else 94561d06d6bSBaptiste Daroussin term_vspace(p); 94661d06d6bSBaptiste Daroussin return; 94761d06d6bSBaptiste Daroussin } else if (*n->string == ' ' && n->flags & NODE_LINE && 94861d06d6bSBaptiste Daroussin (p->flags & TERMP_NONEWLINE) == 0) 94961d06d6bSBaptiste Daroussin term_newln(p); 9507295610fSBaptiste Daroussin else if (n->flags & NODE_DELIMC) 9517295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 95261d06d6bSBaptiste Daroussin 95361d06d6bSBaptiste Daroussin term_word(p, n->string); 95461d06d6bSBaptiste Daroussin goto out; 95561d06d6bSBaptiste Daroussin case ROFFT_COMMENT: 95661d06d6bSBaptiste Daroussin return; 95761d06d6bSBaptiste Daroussin case ROFFT_EQN: 95861d06d6bSBaptiste Daroussin if ( ! (n->flags & NODE_LINE)) 95961d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 96061d06d6bSBaptiste Daroussin term_eqn(p, n->eqn); 96161d06d6bSBaptiste Daroussin if (n->next != NULL && ! (n->next->flags & NODE_LINE)) 96261d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 96361d06d6bSBaptiste Daroussin return; 96461d06d6bSBaptiste Daroussin case ROFFT_TBL: 96561d06d6bSBaptiste Daroussin if (p->tbl.cols == NULL) 966*c1c95addSBrooks Davis term_newln(p); 96761d06d6bSBaptiste Daroussin term_tbl(p, n->span); 96861d06d6bSBaptiste Daroussin return; 96961d06d6bSBaptiste Daroussin default: 97061d06d6bSBaptiste Daroussin break; 97161d06d6bSBaptiste Daroussin } 97261d06d6bSBaptiste Daroussin 97361d06d6bSBaptiste Daroussin if (n->tok < ROFF_MAX) { 97461d06d6bSBaptiste Daroussin roff_term_pre(p, n); 97561d06d6bSBaptiste Daroussin return; 97661d06d6bSBaptiste Daroussin } 97761d06d6bSBaptiste Daroussin 9787295610fSBaptiste Daroussin act = man_term_act(n->tok); 9797295610fSBaptiste Daroussin if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) 98061d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 98161d06d6bSBaptiste Daroussin 98261d06d6bSBaptiste Daroussin c = 1; 9837295610fSBaptiste Daroussin if (act->pre != NULL) 9847295610fSBaptiste Daroussin c = (*act->pre)(p, mt, n, meta); 98561d06d6bSBaptiste Daroussin 9867295610fSBaptiste Daroussin if (c && n->child != NULL) 98761d06d6bSBaptiste Daroussin print_man_nodelist(p, mt, n->child, meta); 98861d06d6bSBaptiste Daroussin 9897295610fSBaptiste Daroussin if (act->post != NULL) 9907295610fSBaptiste Daroussin (*act->post)(p, mt, n, meta); 9917295610fSBaptiste Daroussin if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM) 99261d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 99361d06d6bSBaptiste Daroussin 99461d06d6bSBaptiste Daroussin out: 995*c1c95addSBrooks Davis if (n->parent->tok == MAN_HP && n->parent->type == ROFFT_BODY && 996*c1c95addSBrooks Davis n->prev == NULL && n->flags & NODE_NOFILL) { 99761d06d6bSBaptiste Daroussin term_newln(p); 99861d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 99961d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 100061d06d6bSBaptiste Daroussin } 10017295610fSBaptiste Daroussin if (n->flags & NODE_EOS) 100261d06d6bSBaptiste Daroussin p->flags |= TERMP_SENTENCE; 100361d06d6bSBaptiste Daroussin } 100461d06d6bSBaptiste Daroussin 100561d06d6bSBaptiste Daroussin static void 100661d06d6bSBaptiste Daroussin print_man_nodelist(DECL_ARGS) 100761d06d6bSBaptiste Daroussin { 100861d06d6bSBaptiste Daroussin while (n != NULL) { 100961d06d6bSBaptiste Daroussin print_man_node(p, mt, n, meta); 101061d06d6bSBaptiste Daroussin n = n->next; 101161d06d6bSBaptiste Daroussin } 101261d06d6bSBaptiste Daroussin } 101361d06d6bSBaptiste Daroussin 101461d06d6bSBaptiste Daroussin static void 101561d06d6bSBaptiste Daroussin print_man_foot(struct termp *p, const struct roff_meta *meta) 101661d06d6bSBaptiste Daroussin { 101761d06d6bSBaptiste Daroussin char *title; 101861d06d6bSBaptiste Daroussin size_t datelen, titlen; 101961d06d6bSBaptiste Daroussin 102061d06d6bSBaptiste Daroussin assert(meta->title); 102161d06d6bSBaptiste Daroussin assert(meta->msec); 102261d06d6bSBaptiste Daroussin assert(meta->date); 102361d06d6bSBaptiste Daroussin 102461d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 102561d06d6bSBaptiste Daroussin 102661d06d6bSBaptiste Daroussin if (meta->hasbody) 102761d06d6bSBaptiste Daroussin term_vspace(p); 102861d06d6bSBaptiste Daroussin 102961d06d6bSBaptiste Daroussin /* 103061d06d6bSBaptiste Daroussin * Temporary, undocumented option to imitate mdoc(7) output. 103161d06d6bSBaptiste Daroussin * In the bottom right corner, use the operating system 103261d06d6bSBaptiste Daroussin * instead of the title. 103361d06d6bSBaptiste Daroussin */ 103461d06d6bSBaptiste Daroussin 103561d06d6bSBaptiste Daroussin if ( ! p->mdocstyle) { 103661d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", 103761d06d6bSBaptiste Daroussin meta->title, meta->msec); 10387295610fSBaptiste Daroussin } else if (meta->os != NULL) { 103961d06d6bSBaptiste Daroussin title = mandoc_strdup(meta->os); 104061d06d6bSBaptiste Daroussin } else { 104161d06d6bSBaptiste Daroussin title = mandoc_strdup(""); 104261d06d6bSBaptiste Daroussin } 104361d06d6bSBaptiste Daroussin datelen = term_strlen(p, meta->date); 104461d06d6bSBaptiste Daroussin 104561d06d6bSBaptiste Daroussin /* Bottom left corner: operating system. */ 104661d06d6bSBaptiste Daroussin 104761d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 104861d06d6bSBaptiste Daroussin p->trailspace = 1; 104961d06d6bSBaptiste Daroussin p->tcol->offset = 0; 105061d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin > datelen ? 105161d06d6bSBaptiste Daroussin (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; 105261d06d6bSBaptiste Daroussin 105361d06d6bSBaptiste Daroussin if (meta->os) 105461d06d6bSBaptiste Daroussin term_word(p, meta->os); 105561d06d6bSBaptiste Daroussin term_flushln(p); 105661d06d6bSBaptiste Daroussin 105761d06d6bSBaptiste Daroussin /* At the bottom in the middle: manual date. */ 105861d06d6bSBaptiste Daroussin 105961d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 106061d06d6bSBaptiste Daroussin titlen = term_strlen(p, title); 106161d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin > titlen ? 106261d06d6bSBaptiste Daroussin p->maxrmargin - titlen : 0; 106361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 106461d06d6bSBaptiste Daroussin 106561d06d6bSBaptiste Daroussin term_word(p, meta->date); 106661d06d6bSBaptiste Daroussin term_flushln(p); 106761d06d6bSBaptiste Daroussin 106861d06d6bSBaptiste Daroussin /* Bottom right corner: manual title and section. */ 106961d06d6bSBaptiste Daroussin 107061d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 107161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 107261d06d6bSBaptiste Daroussin p->trailspace = 0; 107361d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 107461d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 107561d06d6bSBaptiste Daroussin 107661d06d6bSBaptiste Daroussin term_word(p, title); 107761d06d6bSBaptiste Daroussin term_flushln(p); 107861d06d6bSBaptiste Daroussin 107961d06d6bSBaptiste Daroussin /* 108061d06d6bSBaptiste Daroussin * Reset the terminal state for more output after the footer: 108161d06d6bSBaptiste Daroussin * Some output modes, in particular PostScript and PDF, print 108261d06d6bSBaptiste Daroussin * the header and the footer into a buffer such that it can be 108361d06d6bSBaptiste Daroussin * reused for multiple output pages, then go on to format the 108461d06d6bSBaptiste Daroussin * main text. 108561d06d6bSBaptiste Daroussin */ 108661d06d6bSBaptiste Daroussin 108761d06d6bSBaptiste Daroussin p->tcol->offset = 0; 108861d06d6bSBaptiste Daroussin p->flags = 0; 108961d06d6bSBaptiste Daroussin 109061d06d6bSBaptiste Daroussin free(title); 109161d06d6bSBaptiste Daroussin } 109261d06d6bSBaptiste Daroussin 109361d06d6bSBaptiste Daroussin static void 109461d06d6bSBaptiste Daroussin print_man_head(struct termp *p, const struct roff_meta *meta) 109561d06d6bSBaptiste Daroussin { 109661d06d6bSBaptiste Daroussin const char *volume; 109761d06d6bSBaptiste Daroussin char *title; 109861d06d6bSBaptiste Daroussin size_t vollen, titlen; 109961d06d6bSBaptiste Daroussin 110061d06d6bSBaptiste Daroussin assert(meta->title); 110161d06d6bSBaptiste Daroussin assert(meta->msec); 110261d06d6bSBaptiste Daroussin 110361d06d6bSBaptiste Daroussin volume = NULL == meta->vol ? "" : meta->vol; 110461d06d6bSBaptiste Daroussin vollen = term_strlen(p, volume); 110561d06d6bSBaptiste Daroussin 110661d06d6bSBaptiste Daroussin /* Top left corner: manual title and section. */ 110761d06d6bSBaptiste Daroussin 110861d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); 110961d06d6bSBaptiste Daroussin titlen = term_strlen(p, title); 111061d06d6bSBaptiste Daroussin 111161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; 111261d06d6bSBaptiste Daroussin p->trailspace = 1; 111361d06d6bSBaptiste Daroussin p->tcol->offset = 0; 111461d06d6bSBaptiste Daroussin p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? 111561d06d6bSBaptiste Daroussin (p->maxrmargin - vollen + term_len(p, 1)) / 2 : 111661d06d6bSBaptiste Daroussin vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; 111761d06d6bSBaptiste Daroussin 111861d06d6bSBaptiste Daroussin term_word(p, title); 111961d06d6bSBaptiste Daroussin term_flushln(p); 112061d06d6bSBaptiste Daroussin 112161d06d6bSBaptiste Daroussin /* At the top in the middle: manual volume. */ 112261d06d6bSBaptiste Daroussin 112361d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 112461d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 112561d06d6bSBaptiste Daroussin p->tcol->rmargin = p->tcol->offset + vollen + titlen < 112661d06d6bSBaptiste Daroussin p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin; 112761d06d6bSBaptiste Daroussin 112861d06d6bSBaptiste Daroussin term_word(p, volume); 112961d06d6bSBaptiste Daroussin term_flushln(p); 113061d06d6bSBaptiste Daroussin 113161d06d6bSBaptiste Daroussin /* Top right corner: title and section, again. */ 113261d06d6bSBaptiste Daroussin 113361d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOBREAK; 113461d06d6bSBaptiste Daroussin p->trailspace = 0; 113561d06d6bSBaptiste Daroussin if (p->tcol->rmargin + titlen <= p->maxrmargin) { 113661d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 113761d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 113861d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 113961d06d6bSBaptiste Daroussin term_word(p, title); 114061d06d6bSBaptiste Daroussin term_flushln(p); 114161d06d6bSBaptiste Daroussin } 114261d06d6bSBaptiste Daroussin 114361d06d6bSBaptiste Daroussin p->flags &= ~TERMP_NOSPACE; 114461d06d6bSBaptiste Daroussin p->tcol->offset = 0; 114561d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 114661d06d6bSBaptiste Daroussin 114761d06d6bSBaptiste Daroussin /* 114861d06d6bSBaptiste Daroussin * Groff prints three blank lines before the content. 114961d06d6bSBaptiste Daroussin * Do the same, except in the temporary, undocumented 115061d06d6bSBaptiste Daroussin * mode imitating mdoc(7) output. 115161d06d6bSBaptiste Daroussin */ 115261d06d6bSBaptiste Daroussin 115361d06d6bSBaptiste Daroussin term_vspace(p); 115461d06d6bSBaptiste Daroussin free(title); 115561d06d6bSBaptiste Daroussin } 1156