Home | History | Annotate | Line # | Download | only in dist
      1 /* $OpenBSD: roff_term.c,v 1.20 2020/09/03 17:37:06 schwarze Exp $ */
      2 /*
      3  * Copyright (c) 2010,2014,2015,2017-2020 Ingo Schwarze <schwarze (at) openbsd.org>
      4  *
      5  * Permission to use, copy, modify, and distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  */
     17 #include "config.h"
     18 
     19 #include <sys/types.h>
     20 
     21 #include <assert.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 
     25 #include "mandoc.h"
     26 #include "roff.h"
     27 #include "out.h"
     28 #include "term.h"
     29 
     30 #define	ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
     31 
     32 typedef	void	(*roff_term_pre_fp)(ROFF_TERM_ARGS);
     33 
     34 static	void	  roff_term_pre_br(ROFF_TERM_ARGS);
     35 static	void	  roff_term_pre_ce(ROFF_TERM_ARGS);
     36 static	void	  roff_term_pre_ft(ROFF_TERM_ARGS);
     37 static	void	  roff_term_pre_ll(ROFF_TERM_ARGS);
     38 static	void	  roff_term_pre_mc(ROFF_TERM_ARGS);
     39 static	void	  roff_term_pre_po(ROFF_TERM_ARGS);
     40 static	void	  roff_term_pre_sp(ROFF_TERM_ARGS);
     41 static	void	  roff_term_pre_ta(ROFF_TERM_ARGS);
     42 static	void	  roff_term_pre_ti(ROFF_TERM_ARGS);
     43 
     44 static	const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
     45 	roff_term_pre_br,  /* br */
     46 	roff_term_pre_ce,  /* ce */
     47 	roff_term_pre_br,  /* fi */
     48 	roff_term_pre_ft,  /* ft */
     49 	roff_term_pre_ll,  /* ll */
     50 	roff_term_pre_mc,  /* mc */
     51 	roff_term_pre_br,  /* nf */
     52 	roff_term_pre_po,  /* po */
     53 	roff_term_pre_ce,  /* rj */
     54 	roff_term_pre_sp,  /* sp */
     55 	roff_term_pre_ta,  /* ta */
     56 	roff_term_pre_ti,  /* ti */
     57 };
     58 
     59 
     60 void
     61 roff_term_pre(struct termp *p, const struct roff_node *n)
     62 {
     63 	assert(n->tok < ROFF_MAX);
     64 	(*roff_term_pre_acts[n->tok])(p, n);
     65 }
     66 
     67 static void
     68 roff_term_pre_br(ROFF_TERM_ARGS)
     69 {
     70 	term_newln(p);
     71 	if (p->flags & TERMP_BRIND) {
     72 		p->tcol->offset = p->tcol->rmargin;
     73 		p->tcol->rmargin = p->maxrmargin;
     74 		p->trailspace = 0;
     75 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
     76 		p->flags |= TERMP_NOSPACE;
     77 	}
     78 }
     79 
     80 static void
     81 roff_term_pre_ce(ROFF_TERM_ARGS)
     82 {
     83 	const struct roff_node	*nc1, *nc2;
     84 
     85 	roff_term_pre_br(p, n);
     86 	p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
     87 	nc1 = n->child->next;
     88 	while (nc1 != NULL) {
     89 		nc2 = nc1;
     90 		do {
     91 			nc2 = nc2->next;
     92 		} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
     93 		    (nc2->flags & NODE_LINE) == 0));
     94 		while (nc1 != nc2) {
     95 			if (nc1->type == ROFFT_TEXT)
     96 				term_word(p, nc1->string);
     97 			else
     98 				roff_term_pre(p, nc1);
     99 			nc1 = nc1->next;
    100 		}
    101 		p->flags |= TERMP_NOSPACE;
    102 		term_flushln(p);
    103 	}
    104 	p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
    105 }
    106 
    107 static void
    108 roff_term_pre_ft(ROFF_TERM_ARGS)
    109 {
    110 	const char	*cp;
    111 
    112 	cp = n->child->string;
    113 	switch (mandoc_font(cp, (int)strlen(cp))) {
    114 	case ESCAPE_FONTBOLD:
    115 	case ESCAPE_FONTCB:
    116 		term_fontrepl(p, TERMFONT_BOLD);
    117 		break;
    118 	case ESCAPE_FONTITALIC:
    119 	case ESCAPE_FONTCI:
    120 		term_fontrepl(p, TERMFONT_UNDER);
    121 		break;
    122 	case ESCAPE_FONTBI:
    123 		term_fontrepl(p, TERMFONT_BI);
    124 		break;
    125 	case ESCAPE_FONTPREV:
    126 		term_fontlast(p);
    127 		break;
    128 	case ESCAPE_FONTROMAN:
    129 	case ESCAPE_FONTCR:
    130 		term_fontrepl(p, TERMFONT_NONE);
    131 		break;
    132 	default:
    133 		break;
    134 	}
    135 }
    136 
    137 static void
    138 roff_term_pre_ll(ROFF_TERM_ARGS)
    139 {
    140 	term_setwidth(p, n->child != NULL ? n->child->string : NULL);
    141 }
    142 
    143 static void
    144 roff_term_pre_mc(ROFF_TERM_ARGS)
    145 {
    146 	if (p->col) {
    147 		p->flags |= TERMP_NOBREAK;
    148 		term_flushln(p);
    149 		p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
    150 	}
    151 	if (n->child != NULL) {
    152 		p->mc = n->child->string;
    153 		p->flags |= TERMP_NEWMC;
    154 	} else
    155 		p->flags |= TERMP_ENDMC;
    156 }
    157 
    158 static void
    159 roff_term_pre_po(ROFF_TERM_ARGS)
    160 {
    161 	struct roffsu	 su;
    162 	static int	 po, pouse, polast;
    163 	int		 ponew;
    164 
    165 	/* Revert the currently active page offset. */
    166 	p->tcol->offset -= pouse;
    167 
    168 	/* Determine the requested page offset. */
    169 	if (n->child != NULL &&
    170 	    a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
    171 		ponew = term_hen(p, &su);
    172 		if (*n->child->string == '+' ||
    173 		    *n->child->string == '-')
    174 			ponew += po;
    175 	} else
    176 		ponew = polast;
    177 
    178 	/* Remeber both the previous and the newly requested offset. */
    179 	polast = po;
    180 	po = ponew;
    181 
    182 	/* Truncate to the range [-offset, 60], remember, and apply it. */
    183 	pouse = po >= 60 ? 60 :
    184 	    po < -(int)p->tcol->offset ? -(int)p->tcol->offset : po;
    185 	p->tcol->offset += pouse;
    186 }
    187 
    188 static void
    189 roff_term_pre_sp(ROFF_TERM_ARGS)
    190 {
    191 	struct roffsu	 su;
    192 	int		 len;
    193 
    194 	if (n->child != NULL) {
    195 		if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
    196 			su.scale = 1.0;
    197 		len = term_vspan(p, &su);
    198 	} else
    199 		len = 1;
    200 
    201 	if (len < 0)
    202 		p->skipvsp -= len;
    203 	else
    204 		while (len--)
    205 			term_vspace(p);
    206 
    207 	roff_term_pre_br(p, n);
    208 }
    209 
    210 static void
    211 roff_term_pre_ta(ROFF_TERM_ARGS)
    212 {
    213 	term_tab_set(p, NULL);
    214 	for (n = n->child; n != NULL; n = n->next)
    215 		term_tab_set(p, n->string);
    216 }
    217 
    218 static void
    219 roff_term_pre_ti(ROFF_TERM_ARGS)
    220 {
    221 	struct roffsu	 su;
    222 	const char	*cp;
    223 	const size_t	 maxoff = 72;
    224 	int		 len, sign;
    225 
    226 	roff_term_pre_br(p, n);
    227 
    228 	if (n->child == NULL)
    229 		return;
    230 	cp = n->child->string;
    231 	if (*cp == '+') {
    232 		sign = 1;
    233 		cp++;
    234 	} else if (*cp == '-') {
    235 		sign = -1;
    236 		cp++;
    237 	} else
    238 		sign = 0;
    239 
    240 	if (a2roffsu(cp, &su, SCALE_EM) == NULL)
    241 		return;
    242 	len = term_hen(p, &su);
    243 
    244 	switch (sign) {
    245 	case 1:
    246 		if (p->tcol->offset + len <= maxoff)
    247 			p->ti = len;
    248 		else if (p->tcol->offset < maxoff)
    249 			p->ti = maxoff - p->tcol->offset;
    250 		else
    251 			p->ti = 0;
    252 		break;
    253 	case -1:
    254 		if ((size_t)len < p->tcol->offset)
    255 			p->ti = -len;
    256 		else
    257 			p->ti = -p->tcol->offset;
    258 		break;
    259 	default:
    260 		if ((size_t)len > maxoff)
    261 			len = maxoff;
    262 		p->ti = len - p->tcol->offset;
    263 		break;
    264 	}
    265 	p->tcol->offset += p->ti;
    266 }
    267