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