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