Merge branch 'vendor/MDOCML'
[dragonfly.git] / contrib / mdocml / roff_term.c
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 }