Home | History | Annotate | Line # | Download | only in dist
roff_term.c revision 1.1
      1 /*	Id: roff_term.c,v 1.14 2017/06/24 14:38:33 schwarze Exp  */
      2 /*
      3  * Copyright (c) 2010, 2014, 2015, 2017 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 <sys/types.h>
     18 
     19 #include <assert.h>
     20 #include <stddef.h>
     21 
     22 #include "mandoc.h"
     23 #include "roff.h"
     24 #include "out.h"
     25 #include "term.h"
     26 
     27 #define	ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
     28 
     29 typedef	void	(*roff_term_pre_fp)(ROFF_TERM_ARGS);
     30 
     31 static	void	  roff_term_pre_br(ROFF_TERM_ARGS);
     32 static	void	  roff_term_pre_ce(ROFF_TERM_ARGS);
     33 static	void	  roff_term_pre_ft(ROFF_TERM_ARGS);
     34 static	void	  roff_term_pre_ll(ROFF_TERM_ARGS);
     35 static	void	  roff_term_pre_mc(ROFF_TERM_ARGS);
     36 static	void	  roff_term_pre_po(ROFF_TERM_ARGS);
     37 static	void	  roff_term_pre_sp(ROFF_TERM_ARGS);
     38 static	void	  roff_term_pre_ta(ROFF_TERM_ARGS);
     39 static	void	  roff_term_pre_ti(ROFF_TERM_ARGS);
     40 
     41 static	const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
     42 	roff_term_pre_br,  /* br */
     43 	roff_term_pre_ce,  /* ce */
     44 	roff_term_pre_ft,  /* ft */
     45 	roff_term_pre_ll,  /* ll */
     46 	roff_term_pre_mc,  /* mc */
     47 	roff_term_pre_po,  /* po */
     48 	roff_term_pre_ce,  /* rj */
     49 	roff_term_pre_sp,  /* sp */
     50 	roff_term_pre_ta,  /* ta */
     51 	roff_term_pre_ti,  /* ti */
     52 };
     53 
     54 
     55 void
     56 roff_term_pre(struct termp *p, const struct roff_node *n)
     57 {
     58 	assert(n->tok < ROFF_MAX);
     59 	(*roff_term_pre_acts[n->tok])(p, n);
     60 }
     61 
     62 static void
     63 roff_term_pre_br(ROFF_TERM_ARGS)
     64 {
     65 	term_newln(p);
     66 	if (p->flags & TERMP_BRIND) {
     67 		p->tcol->offset = p->tcol->rmargin;
     68 		p->tcol->rmargin = p->maxrmargin;
     69 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
     70 	}
     71 }
     72 
     73 static void
     74 roff_term_pre_ce(ROFF_TERM_ARGS)
     75 {
     76 	const struct roff_node	*nc1, *nc2;
     77 	size_t			 len, lm;
     78 
     79 	roff_term_pre_br(p, n);
     80 	lm = p->tcol->offset;
     81 	nc1 = n->child->next;
     82 	while (nc1 != NULL) {
     83 		nc2 = nc1;
     84 		len = 0;
     85 		do {
     86 			if (nc2->type == ROFFT_TEXT) {
     87 				if (len)
     88 					len++;
     89 				len += term_strlen(p, nc2->string);
     90 			}
     91 			nc2 = nc2->next;
     92 		} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
     93 		    (nc2->flags & NODE_LINE) == 0));
     94 		p->tcol->offset = len >= p->tcol->rmargin ? 0 :
     95 		    lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len :
     96 		    n->tok == ROFF_rj ? p->tcol->rmargin - len :
     97 		    (lm + p->tcol->rmargin - len) / 2;
     98 		while (nc1 != nc2) {
     99 			if (nc1->type == ROFFT_TEXT)
    100 				term_word(p, nc1->string);
    101 			else
    102 				roff_term_pre(p, nc1);
    103 			nc1 = nc1->next;
    104 		}
    105 		p->flags |= TERMP_NOSPACE;
    106 		term_flushln(p);
    107 	}
    108 	p->tcol->offset = lm;
    109 }
    110 
    111 static void
    112 roff_term_pre_ft(ROFF_TERM_ARGS)
    113 {
    114 	switch (*n->child->string) {
    115 	case '4':
    116 	case '3':
    117 	case 'B':
    118 		term_fontrepl(p, TERMFONT_BOLD);
    119 		break;
    120 	case '2':
    121 	case 'I':
    122 		term_fontrepl(p, TERMFONT_UNDER);
    123 		break;
    124 	case 'P':
    125 		term_fontlast(p);
    126 		break;
    127 	case '1':
    128 	case 'C':
    129 	case 'R':
    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, polast;
    163 	int		 ponew;
    164 
    165 	if (n->child != NULL &&
    166 	    a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
    167 		ponew = term_hen(p, &su);
    168 		if (*n->child->string == '+' ||
    169 		    *n->child->string == '-')
    170 			ponew += po;
    171 	} else
    172 		ponew = polast;
    173 	polast = po;
    174 	po = ponew;
    175 
    176 	ponew = po - polast + (int)p->tcol->offset;
    177 	p->tcol->offset = ponew > 0 ? ponew : 0;
    178 }
    179 
    180 static void
    181 roff_term_pre_sp(ROFF_TERM_ARGS)
    182 {
    183 	struct roffsu	 su;
    184 	int		 len;
    185 
    186 	if (n->child != NULL) {
    187 		if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
    188 			su.scale = 1.0;
    189 		len = term_vspan(p, &su);
    190 	} else
    191 		len = 1;
    192 
    193 	if (len < 0)
    194 		p->skipvsp -= len;
    195 	else
    196 		while (len--)
    197 			term_vspace(p);
    198 
    199 	roff_term_pre_br(p, n);
    200 }
    201 
    202 static void
    203 roff_term_pre_ta(ROFF_TERM_ARGS)
    204 {
    205 	term_tab_set(p, NULL);
    206 	for (n = n->child; n != NULL; n = n->next)
    207 		term_tab_set(p, n->string);
    208 }
    209 
    210 static void
    211 roff_term_pre_ti(ROFF_TERM_ARGS)
    212 {
    213 	struct roffsu	 su;
    214 	const char	*cp;
    215 	int		 len, sign;
    216 
    217 	roff_term_pre_br(p, n);
    218 
    219 	if (n->child == NULL)
    220 		return;
    221 	cp = n->child->string;
    222 	if (*cp == '+') {
    223 		sign = 1;
    224 		cp++;
    225 	} else if (*cp == '-') {
    226 		sign = -1;
    227 		cp++;
    228 	} else
    229 		sign = 0;
    230 
    231 	if (a2roffsu(cp, &su, SCALE_EM) == NULL)
    232 		return;
    233 	len = term_hen(p, &su);
    234 
    235 	if (sign == 0) {
    236 		p->ti = len - p->tcol->offset;
    237 		p->tcol->offset = len;
    238 	} else if (sign == 1) {
    239 		p->ti = len;
    240 		p->tcol->offset += len;
    241 	} else if ((size_t)len < p->tcol->offset) {
    242 		p->ti = -len;
    243 		p->tcol->offset -= len;
    244 	} else {
    245 		p->ti = -p->tcol->offset;
    246 		p->tcol->offset = 0;
    247 	}
    248 }
    249