1*c1c95addSBrooks Davis /* $Id: roff_term.c,v 1.25 2023/04/28 19:11:04 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 36d38604fSBaptiste Daroussin * Copyright (c) 2010,2014,2015,2017-2020 Ingo Schwarze <schwarze@openbsd.org> 461d06d6bSBaptiste Daroussin * 561d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 661d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 761d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 861d06d6bSBaptiste Daroussin * 961d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1061d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1161d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1261d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1361d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1461d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1561d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1661d06d6bSBaptiste Daroussin */ 176d38604fSBaptiste Daroussin #include "config.h" 186d38604fSBaptiste Daroussin 1961d06d6bSBaptiste Daroussin #include <sys/types.h> 2061d06d6bSBaptiste Daroussin 2161d06d6bSBaptiste Daroussin #include <assert.h> 227295610fSBaptiste Daroussin #include <stdio.h> 237295610fSBaptiste Daroussin #include <string.h> 2461d06d6bSBaptiste Daroussin 2561d06d6bSBaptiste Daroussin #include "mandoc.h" 2661d06d6bSBaptiste Daroussin #include "roff.h" 2761d06d6bSBaptiste Daroussin #include "out.h" 2861d06d6bSBaptiste Daroussin #include "term.h" 2961d06d6bSBaptiste Daroussin 3061d06d6bSBaptiste Daroussin #define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n 3161d06d6bSBaptiste Daroussin 3261d06d6bSBaptiste Daroussin typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS); 3361d06d6bSBaptiste Daroussin 3461d06d6bSBaptiste Daroussin static void roff_term_pre_br(ROFF_TERM_ARGS); 3561d06d6bSBaptiste Daroussin static void roff_term_pre_ce(ROFF_TERM_ARGS); 3661d06d6bSBaptiste Daroussin static void roff_term_pre_ft(ROFF_TERM_ARGS); 3761d06d6bSBaptiste Daroussin static void roff_term_pre_ll(ROFF_TERM_ARGS); 3861d06d6bSBaptiste Daroussin static void roff_term_pre_mc(ROFF_TERM_ARGS); 3961d06d6bSBaptiste Daroussin static void roff_term_pre_po(ROFF_TERM_ARGS); 4061d06d6bSBaptiste Daroussin static void roff_term_pre_sp(ROFF_TERM_ARGS); 4161d06d6bSBaptiste Daroussin static void roff_term_pre_ta(ROFF_TERM_ARGS); 4261d06d6bSBaptiste Daroussin static void roff_term_pre_ti(ROFF_TERM_ARGS); 4361d06d6bSBaptiste Daroussin 4461d06d6bSBaptiste Daroussin static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = { 4561d06d6bSBaptiste Daroussin roff_term_pre_br, /* br */ 4661d06d6bSBaptiste Daroussin roff_term_pre_ce, /* ce */ 477295610fSBaptiste Daroussin roff_term_pre_br, /* fi */ 4861d06d6bSBaptiste Daroussin roff_term_pre_ft, /* ft */ 4961d06d6bSBaptiste Daroussin roff_term_pre_ll, /* ll */ 5061d06d6bSBaptiste Daroussin roff_term_pre_mc, /* mc */ 517295610fSBaptiste Daroussin roff_term_pre_br, /* nf */ 5261d06d6bSBaptiste Daroussin roff_term_pre_po, /* po */ 5361d06d6bSBaptiste Daroussin roff_term_pre_ce, /* rj */ 5461d06d6bSBaptiste Daroussin roff_term_pre_sp, /* sp */ 5561d06d6bSBaptiste Daroussin roff_term_pre_ta, /* ta */ 5661d06d6bSBaptiste Daroussin roff_term_pre_ti, /* ti */ 5761d06d6bSBaptiste Daroussin }; 5861d06d6bSBaptiste Daroussin 5961d06d6bSBaptiste Daroussin 6061d06d6bSBaptiste Daroussin void 6161d06d6bSBaptiste Daroussin roff_term_pre(struct termp *p, const struct roff_node *n) 6261d06d6bSBaptiste Daroussin { 6361d06d6bSBaptiste Daroussin assert(n->tok < ROFF_MAX); 6461d06d6bSBaptiste Daroussin (*roff_term_pre_acts[n->tok])(p, n); 6561d06d6bSBaptiste Daroussin } 6661d06d6bSBaptiste Daroussin 6761d06d6bSBaptiste Daroussin static void 6861d06d6bSBaptiste Daroussin roff_term_pre_br(ROFF_TERM_ARGS) 6961d06d6bSBaptiste Daroussin { 7061d06d6bSBaptiste Daroussin term_newln(p); 7161d06d6bSBaptiste Daroussin if (p->flags & TERMP_BRIND) { 7261d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin; 7361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin; 747295610fSBaptiste Daroussin p->trailspace = 0; 7561d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 767295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 7761d06d6bSBaptiste Daroussin } 7861d06d6bSBaptiste Daroussin } 7961d06d6bSBaptiste Daroussin 8061d06d6bSBaptiste Daroussin static void 8161d06d6bSBaptiste Daroussin roff_term_pre_ce(ROFF_TERM_ARGS) 8261d06d6bSBaptiste Daroussin { 8361d06d6bSBaptiste Daroussin const struct roff_node *nc1, *nc2; 8461d06d6bSBaptiste Daroussin 8561d06d6bSBaptiste Daroussin roff_term_pre_br(p, n); 867295610fSBaptiste Daroussin p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT; 8761d06d6bSBaptiste Daroussin nc1 = n->child->next; 8861d06d6bSBaptiste Daroussin while (nc1 != NULL) { 8961d06d6bSBaptiste Daroussin nc2 = nc1; 9061d06d6bSBaptiste Daroussin do { 9161d06d6bSBaptiste Daroussin nc2 = nc2->next; 9261d06d6bSBaptiste Daroussin } while (nc2 != NULL && (nc2->type != ROFFT_TEXT || 9361d06d6bSBaptiste Daroussin (nc2->flags & NODE_LINE) == 0)); 9461d06d6bSBaptiste Daroussin while (nc1 != nc2) { 9561d06d6bSBaptiste Daroussin if (nc1->type == ROFFT_TEXT) 9661d06d6bSBaptiste Daroussin term_word(p, nc1->string); 9761d06d6bSBaptiste Daroussin else 9861d06d6bSBaptiste Daroussin roff_term_pre(p, nc1); 9961d06d6bSBaptiste Daroussin nc1 = nc1->next; 10061d06d6bSBaptiste Daroussin } 10161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE; 10261d06d6bSBaptiste Daroussin term_flushln(p); 10361d06d6bSBaptiste Daroussin } 1047295610fSBaptiste Daroussin p->flags &= ~(TERMP_CENTER | TERMP_RIGHT); 10561d06d6bSBaptiste Daroussin } 10661d06d6bSBaptiste Daroussin 10761d06d6bSBaptiste Daroussin static void 10861d06d6bSBaptiste Daroussin roff_term_pre_ft(ROFF_TERM_ARGS) 10961d06d6bSBaptiste Daroussin { 1107295610fSBaptiste Daroussin const char *cp; 1117295610fSBaptiste Daroussin 1127295610fSBaptiste Daroussin cp = n->child->string; 1137295610fSBaptiste Daroussin switch (mandoc_font(cp, (int)strlen(cp))) { 1147295610fSBaptiste Daroussin case ESCAPE_FONTBOLD: 1156d38604fSBaptiste Daroussin case ESCAPE_FONTCB: 11661d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD); 11761d06d6bSBaptiste Daroussin break; 1187295610fSBaptiste Daroussin case ESCAPE_FONTITALIC: 1196d38604fSBaptiste Daroussin case ESCAPE_FONTCI: 12061d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER); 12161d06d6bSBaptiste Daroussin break; 1227295610fSBaptiste Daroussin case ESCAPE_FONTBI: 1237295610fSBaptiste Daroussin term_fontrepl(p, TERMFONT_BI); 1247295610fSBaptiste Daroussin break; 1257295610fSBaptiste Daroussin case ESCAPE_FONTPREV: 12661d06d6bSBaptiste Daroussin term_fontlast(p); 12761d06d6bSBaptiste Daroussin break; 1287295610fSBaptiste Daroussin case ESCAPE_FONTROMAN: 1296d38604fSBaptiste Daroussin case ESCAPE_FONTCR: 13061d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE); 13161d06d6bSBaptiste Daroussin break; 13261d06d6bSBaptiste Daroussin default: 13361d06d6bSBaptiste Daroussin break; 13461d06d6bSBaptiste Daroussin } 13561d06d6bSBaptiste Daroussin } 13661d06d6bSBaptiste Daroussin 13761d06d6bSBaptiste Daroussin static void 13861d06d6bSBaptiste Daroussin roff_term_pre_ll(ROFF_TERM_ARGS) 13961d06d6bSBaptiste Daroussin { 14061d06d6bSBaptiste Daroussin term_setwidth(p, n->child != NULL ? n->child->string : NULL); 14161d06d6bSBaptiste Daroussin } 14261d06d6bSBaptiste Daroussin 14361d06d6bSBaptiste Daroussin static void 14461d06d6bSBaptiste Daroussin roff_term_pre_mc(ROFF_TERM_ARGS) 14561d06d6bSBaptiste Daroussin { 14661d06d6bSBaptiste Daroussin if (p->col) { 14761d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK; 14861d06d6bSBaptiste Daroussin term_flushln(p); 14961d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE); 15061d06d6bSBaptiste Daroussin } 15161d06d6bSBaptiste Daroussin if (n->child != NULL) { 15261d06d6bSBaptiste Daroussin p->mc = n->child->string; 15361d06d6bSBaptiste Daroussin p->flags |= TERMP_NEWMC; 15461d06d6bSBaptiste Daroussin } else 15561d06d6bSBaptiste Daroussin p->flags |= TERMP_ENDMC; 15661d06d6bSBaptiste Daroussin } 15761d06d6bSBaptiste Daroussin 15861d06d6bSBaptiste Daroussin static void 15961d06d6bSBaptiste Daroussin roff_term_pre_po(ROFF_TERM_ARGS) 16061d06d6bSBaptiste Daroussin { 16161d06d6bSBaptiste Daroussin struct roffsu su; 1626d38604fSBaptiste Daroussin static int po, pouse, polast; 16361d06d6bSBaptiste Daroussin int ponew; 16461d06d6bSBaptiste Daroussin 1656d38604fSBaptiste Daroussin /* Revert the currently active page offset. */ 1666d38604fSBaptiste Daroussin p->tcol->offset -= pouse; 1676d38604fSBaptiste Daroussin 1686d38604fSBaptiste Daroussin /* Determine the requested page offset. */ 16961d06d6bSBaptiste Daroussin if (n->child != NULL && 17061d06d6bSBaptiste Daroussin a2roffsu(n->child->string, &su, SCALE_EM) != NULL) { 17161d06d6bSBaptiste Daroussin ponew = term_hen(p, &su); 17261d06d6bSBaptiste Daroussin if (*n->child->string == '+' || 17361d06d6bSBaptiste Daroussin *n->child->string == '-') 17461d06d6bSBaptiste Daroussin ponew += po; 17561d06d6bSBaptiste Daroussin } else 17661d06d6bSBaptiste Daroussin ponew = polast; 1776d38604fSBaptiste Daroussin 178*c1c95addSBrooks Davis /* Remember both the previous and the newly requested offset. */ 17961d06d6bSBaptiste Daroussin polast = po; 18061d06d6bSBaptiste Daroussin po = ponew; 18161d06d6bSBaptiste Daroussin 1826d38604fSBaptiste Daroussin /* Truncate to the range [-offset, 60], remember, and apply it. */ 1836d38604fSBaptiste Daroussin pouse = po >= 60 ? 60 : 1846d38604fSBaptiste Daroussin po < -(int)p->tcol->offset ? -(int)p->tcol->offset : po; 1856d38604fSBaptiste Daroussin p->tcol->offset += pouse; 18661d06d6bSBaptiste Daroussin } 18761d06d6bSBaptiste Daroussin 18861d06d6bSBaptiste Daroussin static void 18961d06d6bSBaptiste Daroussin roff_term_pre_sp(ROFF_TERM_ARGS) 19061d06d6bSBaptiste Daroussin { 19161d06d6bSBaptiste Daroussin struct roffsu su; 19261d06d6bSBaptiste Daroussin int len; 19361d06d6bSBaptiste Daroussin 19461d06d6bSBaptiste Daroussin if (n->child != NULL) { 19561d06d6bSBaptiste Daroussin if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL) 19661d06d6bSBaptiste Daroussin su.scale = 1.0; 19761d06d6bSBaptiste Daroussin len = term_vspan(p, &su); 19861d06d6bSBaptiste Daroussin } else 19961d06d6bSBaptiste Daroussin len = 1; 20061d06d6bSBaptiste Daroussin 20161d06d6bSBaptiste Daroussin if (len < 0) 20261d06d6bSBaptiste Daroussin p->skipvsp -= len; 20361d06d6bSBaptiste Daroussin else 20461d06d6bSBaptiste Daroussin while (len--) 20561d06d6bSBaptiste Daroussin term_vspace(p); 20661d06d6bSBaptiste Daroussin 20761d06d6bSBaptiste Daroussin roff_term_pre_br(p, n); 20861d06d6bSBaptiste Daroussin } 20961d06d6bSBaptiste Daroussin 21061d06d6bSBaptiste Daroussin static void 21161d06d6bSBaptiste Daroussin roff_term_pre_ta(ROFF_TERM_ARGS) 21261d06d6bSBaptiste Daroussin { 21361d06d6bSBaptiste Daroussin term_tab_set(p, NULL); 21461d06d6bSBaptiste Daroussin for (n = n->child; n != NULL; n = n->next) 21561d06d6bSBaptiste Daroussin term_tab_set(p, n->string); 21661d06d6bSBaptiste Daroussin } 21761d06d6bSBaptiste Daroussin 21861d06d6bSBaptiste Daroussin static void 21961d06d6bSBaptiste Daroussin roff_term_pre_ti(ROFF_TERM_ARGS) 22061d06d6bSBaptiste Daroussin { 22161d06d6bSBaptiste Daroussin struct roffsu su; 22261d06d6bSBaptiste Daroussin const char *cp; 2236d38604fSBaptiste Daroussin const size_t maxoff = 72; 22461d06d6bSBaptiste Daroussin int len, sign; 22561d06d6bSBaptiste Daroussin 22661d06d6bSBaptiste Daroussin roff_term_pre_br(p, n); 22761d06d6bSBaptiste Daroussin 22861d06d6bSBaptiste Daroussin if (n->child == NULL) 22961d06d6bSBaptiste Daroussin return; 23061d06d6bSBaptiste Daroussin cp = n->child->string; 23161d06d6bSBaptiste Daroussin if (*cp == '+') { 23261d06d6bSBaptiste Daroussin sign = 1; 23361d06d6bSBaptiste Daroussin cp++; 23461d06d6bSBaptiste Daroussin } else if (*cp == '-') { 23561d06d6bSBaptiste Daroussin sign = -1; 23661d06d6bSBaptiste Daroussin cp++; 23761d06d6bSBaptiste Daroussin } else 23861d06d6bSBaptiste Daroussin sign = 0; 23961d06d6bSBaptiste Daroussin 24061d06d6bSBaptiste Daroussin if (a2roffsu(cp, &su, SCALE_EM) == NULL) 24161d06d6bSBaptiste Daroussin return; 24261d06d6bSBaptiste Daroussin len = term_hen(p, &su); 24361d06d6bSBaptiste Daroussin 2446d38604fSBaptiste Daroussin switch (sign) { 2456d38604fSBaptiste Daroussin case 1: 2466d38604fSBaptiste Daroussin if (p->tcol->offset + len <= maxoff) 24761d06d6bSBaptiste Daroussin p->ti = len; 2486d38604fSBaptiste Daroussin else if (p->tcol->offset < maxoff) 2496d38604fSBaptiste Daroussin p->ti = maxoff - p->tcol->offset; 2506d38604fSBaptiste Daroussin else 2516d38604fSBaptiste Daroussin p->ti = 0; 2526d38604fSBaptiste Daroussin break; 2536d38604fSBaptiste Daroussin case -1: 2546d38604fSBaptiste Daroussin if ((size_t)len < p->tcol->offset) 25561d06d6bSBaptiste Daroussin p->ti = -len; 2566d38604fSBaptiste Daroussin else 25761d06d6bSBaptiste Daroussin p->ti = -p->tcol->offset; 2586d38604fSBaptiste Daroussin break; 2596d38604fSBaptiste Daroussin default: 2606d38604fSBaptiste Daroussin if ((size_t)len > maxoff) 2616d38604fSBaptiste Daroussin len = maxoff; 2626d38604fSBaptiste Daroussin p->ti = len - p->tcol->offset; 2636d38604fSBaptiste Daroussin break; 26461d06d6bSBaptiste Daroussin } 2656d38604fSBaptiste Daroussin p->tcol->offset += p->ti; 26661d06d6bSBaptiste Daroussin } 267