1 /* $Id: roff_term.c,v 1.19 2019/01/04 03:24:33 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2010,2014,2015,2017-2019 Ingo Schwarze <schwarze@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 <stdio.h> 21 #include <string.h> 22 23 #include "mandoc.h" 24 #include "roff.h" 25 #include "out.h" 26 #include "term.h" 27 28 #define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n 29 30 typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS); 31 32 static void roff_term_pre_br(ROFF_TERM_ARGS); 33 static void roff_term_pre_ce(ROFF_TERM_ARGS); 34 static void roff_term_pre_ft(ROFF_TERM_ARGS); 35 static void roff_term_pre_ll(ROFF_TERM_ARGS); 36 static void roff_term_pre_mc(ROFF_TERM_ARGS); 37 static void roff_term_pre_po(ROFF_TERM_ARGS); 38 static void roff_term_pre_sp(ROFF_TERM_ARGS); 39 static void roff_term_pre_ta(ROFF_TERM_ARGS); 40 static void roff_term_pre_ti(ROFF_TERM_ARGS); 41 42 static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = { 43 roff_term_pre_br, /* br */ 44 roff_term_pre_ce, /* ce */ 45 roff_term_pre_br, /* fi */ 46 roff_term_pre_ft, /* ft */ 47 roff_term_pre_ll, /* ll */ 48 roff_term_pre_mc, /* mc */ 49 roff_term_pre_br, /* nf */ 50 roff_term_pre_po, /* po */ 51 roff_term_pre_ce, /* rj */ 52 roff_term_pre_sp, /* sp */ 53 roff_term_pre_ta, /* ta */ 54 roff_term_pre_ti, /* ti */ 55 }; 56 57 58 void 59 roff_term_pre(struct termp *p, const struct roff_node *n) 60 { 61 assert(n->tok < ROFF_MAX); 62 (*roff_term_pre_acts[n->tok])(p, n); 63 } 64 65 static void 66 roff_term_pre_br(ROFF_TERM_ARGS) 67 { 68 term_newln(p); 69 if (p->flags & TERMP_BRIND) { 70 p->tcol->offset = p->tcol->rmargin; 71 p->tcol->rmargin = p->maxrmargin; 72 p->trailspace = 0; 73 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); 74 p->flags |= TERMP_NOSPACE; 75 } 76 } 77 78 static void 79 roff_term_pre_ce(ROFF_TERM_ARGS) 80 { 81 const struct roff_node *nc1, *nc2; 82 83 roff_term_pre_br(p, n); 84 p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT; 85 nc1 = n->child->next; 86 while (nc1 != NULL) { 87 nc2 = nc1; 88 do { 89 nc2 = nc2->next; 90 } while (nc2 != NULL && (nc2->type != ROFFT_TEXT || 91 (nc2->flags & NODE_LINE) == 0)); 92 while (nc1 != nc2) { 93 if (nc1->type == ROFFT_TEXT) 94 term_word(p, nc1->string); 95 else 96 roff_term_pre(p, nc1); 97 nc1 = nc1->next; 98 } 99 p->flags |= TERMP_NOSPACE; 100 term_flushln(p); 101 } 102 p->flags &= ~(TERMP_CENTER | TERMP_RIGHT); 103 } 104 105 static void 106 roff_term_pre_ft(ROFF_TERM_ARGS) 107 { 108 const char *cp; 109 110 cp = n->child->string; 111 switch (mandoc_font(cp, (int)strlen(cp))) { 112 case ESCAPE_FONTBOLD: 113 term_fontrepl(p, TERMFONT_BOLD); 114 break; 115 case ESCAPE_FONTITALIC: 116 term_fontrepl(p, TERMFONT_UNDER); 117 break; 118 case ESCAPE_FONTBI: 119 term_fontrepl(p, TERMFONT_BI); 120 break; 121 case ESCAPE_FONTPREV: 122 term_fontlast(p); 123 break; 124 case ESCAPE_FONTROMAN: 125 case ESCAPE_FONTCW: 126 term_fontrepl(p, TERMFONT_NONE); 127 break; 128 default: 129 break; 130 } 131 } 132 133 static void 134 roff_term_pre_ll(ROFF_TERM_ARGS) 135 { 136 term_setwidth(p, n->child != NULL ? n->child->string : NULL); 137 } 138 139 static void 140 roff_term_pre_mc(ROFF_TERM_ARGS) 141 { 142 if (p->col) { 143 p->flags |= TERMP_NOBREAK; 144 term_flushln(p); 145 p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE); 146 } 147 if (n->child != NULL) { 148 p->mc = n->child->string; 149 p->flags |= TERMP_NEWMC; 150 } else 151 p->flags |= TERMP_ENDMC; 152 } 153 154 static void 155 roff_term_pre_po(ROFF_TERM_ARGS) 156 { 157 struct roffsu su; 158 static int po, polast; 159 int ponew; 160 161 if (n->child != NULL && 162 a2roffsu(n->child->string, &su, SCALE_EM) != NULL) { 163 ponew = term_hen(p, &su); 164 if (*n->child->string == '+' || 165 *n->child->string == '-') 166 ponew += po; 167 } else 168 ponew = polast; 169 polast = po; 170 po = ponew; 171 172 ponew = po - polast + (int)p->tcol->offset; 173 p->tcol->offset = ponew > 0 ? ponew : 0; 174 } 175 176 static void 177 roff_term_pre_sp(ROFF_TERM_ARGS) 178 { 179 struct roffsu su; 180 int len; 181 182 if (n->child != NULL) { 183 if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL) 184 su.scale = 1.0; 185 len = term_vspan(p, &su); 186 } else 187 len = 1; 188 189 if (len < 0) 190 p->skipvsp -= len; 191 else 192 while (len--) 193 term_vspace(p); 194 195 roff_term_pre_br(p, n); 196 } 197 198 static void 199 roff_term_pre_ta(ROFF_TERM_ARGS) 200 { 201 term_tab_set(p, NULL); 202 for (n = n->child; n != NULL; n = n->next) 203 term_tab_set(p, n->string); 204 } 205 206 static void 207 roff_term_pre_ti(ROFF_TERM_ARGS) 208 { 209 struct roffsu su; 210 const char *cp; 211 int len, sign; 212 213 roff_term_pre_br(p, n); 214 215 if (n->child == NULL) 216 return; 217 cp = n->child->string; 218 if (*cp == '+') { 219 sign = 1; 220 cp++; 221 } else if (*cp == '-') { 222 sign = -1; 223 cp++; 224 } else 225 sign = 0; 226 227 if (a2roffsu(cp, &su, SCALE_EM) == NULL) 228 return; 229 len = term_hen(p, &su); 230 231 if (sign == 0) { 232 p->ti = len - p->tcol->offset; 233 p->tcol->offset = len; 234 } else if (sign == 1) { 235 p->ti = len; 236 p->tcol->offset += len; 237 } else if ((size_t)len < p->tcol->offset) { 238 p->ti = -len; 239 p->tcol->offset -= len; 240 } else { 241 p->ti = -p->tcol->offset; 242 p->tcol->offset = 0; 243 } 244 } 245