nrelease - fix/improve livecd
[dragonfly.git] / contrib / mdocml / roff_term.c
1 /* $OpenBSD: roff_term.c,v 1.20 2020/09/03 17:37:06 schwarze Exp $ */
2 /*
3  * Copyright (c) 2010,2014,2015,2017-2020 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 "config.h"
18
19 #include <sys/types.h>
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "mandoc.h"
26 #include "roff.h"
27 #include "out.h"
28 #include "term.h"
29
30 #define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
31
32 typedef void    (*roff_term_pre_fp)(ROFF_TERM_ARGS);
33
34 static  void      roff_term_pre_br(ROFF_TERM_ARGS);
35 static  void      roff_term_pre_ce(ROFF_TERM_ARGS);
36 static  void      roff_term_pre_ft(ROFF_TERM_ARGS);
37 static  void      roff_term_pre_ll(ROFF_TERM_ARGS);
38 static  void      roff_term_pre_mc(ROFF_TERM_ARGS);
39 static  void      roff_term_pre_po(ROFF_TERM_ARGS);
40 static  void      roff_term_pre_sp(ROFF_TERM_ARGS);
41 static  void      roff_term_pre_ta(ROFF_TERM_ARGS);
42 static  void      roff_term_pre_ti(ROFF_TERM_ARGS);
43
44 static  const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
45         roff_term_pre_br,  /* br */
46         roff_term_pre_ce,  /* ce */
47         roff_term_pre_br,  /* fi */
48         roff_term_pre_ft,  /* ft */
49         roff_term_pre_ll,  /* ll */
50         roff_term_pre_mc,  /* mc */
51         roff_term_pre_br,  /* nf */
52         roff_term_pre_po,  /* po */
53         roff_term_pre_ce,  /* rj */
54         roff_term_pre_sp,  /* sp */
55         roff_term_pre_ta,  /* ta */
56         roff_term_pre_ti,  /* ti */
57 };
58
59
60 void
61 roff_term_pre(struct termp *p, const struct roff_node *n)
62 {
63         assert(n->tok < ROFF_MAX);
64         (*roff_term_pre_acts[n->tok])(p, n);
65 }
66
67 static void
68 roff_term_pre_br(ROFF_TERM_ARGS)
69 {
70         term_newln(p);
71         if (p->flags & TERMP_BRIND) {
72                 p->tcol->offset = p->tcol->rmargin;
73                 p->tcol->rmargin = p->maxrmargin;
74                 p->trailspace = 0;
75                 p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
76                 p->flags |= TERMP_NOSPACE;
77         }
78 }
79
80 static void
81 roff_term_pre_ce(ROFF_TERM_ARGS)
82 {
83         const struct roff_node  *nc1, *nc2;
84
85         roff_term_pre_br(p, n);
86         p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
87         nc1 = n->child->next;
88         while (nc1 != NULL) {
89                 nc2 = nc1;
90                 do {
91                         nc2 = nc2->next;
92                 } while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
93                     (nc2->flags & NODE_LINE) == 0));
94                 while (nc1 != nc2) {
95                         if (nc1->type == ROFFT_TEXT)
96                                 term_word(p, nc1->string);
97                         else
98                                 roff_term_pre(p, nc1);
99                         nc1 = nc1->next;
100                 }
101                 p->flags |= TERMP_NOSPACE;
102                 term_flushln(p);
103         }
104         p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
105 }
106
107 static void
108 roff_term_pre_ft(ROFF_TERM_ARGS)
109 {
110         const char      *cp;
111
112         cp = n->child->string;
113         switch (mandoc_font(cp, (int)strlen(cp))) {
114         case ESCAPE_FONTBOLD:
115         case ESCAPE_FONTCB:
116                 term_fontrepl(p, TERMFONT_BOLD);
117                 break;
118         case ESCAPE_FONTITALIC:
119         case ESCAPE_FONTCI:
120                 term_fontrepl(p, TERMFONT_UNDER);
121                 break;
122         case ESCAPE_FONTBI:
123                 term_fontrepl(p, TERMFONT_BI);
124                 break;
125         case ESCAPE_FONTPREV:
126                 term_fontlast(p);
127                 break;
128         case ESCAPE_FONTROMAN:
129         case ESCAPE_FONTCR:
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, pouse, polast;
163         int              ponew;
164
165         /* Revert the currently active page offset. */
166         p->tcol->offset -= pouse;
167
168         /* Determine the requested page offset. */
169         if (n->child != NULL &&
170             a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
171                 ponew = term_hen(p, &su);
172                 if (*n->child->string == '+' ||
173                     *n->child->string == '-')
174                         ponew += po;
175         } else
176                 ponew = polast;
177
178         /* Remeber both the previous and the newly requested offset. */
179         polast = po;
180         po = ponew;
181
182         /* Truncate to the range [-offset, 60], remember, and apply it. */
183         pouse = po >= 60 ? 60 :
184             po < -(int)p->tcol->offset ? -(int)p->tcol->offset : po;
185         p->tcol->offset += pouse;
186 }
187
188 static void
189 roff_term_pre_sp(ROFF_TERM_ARGS)
190 {
191         struct roffsu    su;
192         int              len;
193
194         if (n->child != NULL) {
195                 if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
196                         su.scale = 1.0;
197                 len = term_vspan(p, &su);
198         } else
199                 len = 1;
200
201         if (len < 0)
202                 p->skipvsp -= len;
203         else
204                 while (len--)
205                         term_vspace(p);
206
207         roff_term_pre_br(p, n);
208 }
209
210 static void
211 roff_term_pre_ta(ROFF_TERM_ARGS)
212 {
213         term_tab_set(p, NULL);
214         for (n = n->child; n != NULL; n = n->next)
215                 term_tab_set(p, n->string);
216 }
217
218 static void
219 roff_term_pre_ti(ROFF_TERM_ARGS)
220 {
221         struct roffsu    su;
222         const char      *cp;
223         const size_t     maxoff = 72;
224         int              len, sign;
225
226         roff_term_pre_br(p, n);
227
228         if (n->child == NULL)
229                 return;
230         cp = n->child->string;
231         if (*cp == '+') {
232                 sign = 1;
233                 cp++;
234         } else if (*cp == '-') {
235                 sign = -1;
236                 cp++;
237         } else
238                 sign = 0;
239
240         if (a2roffsu(cp, &su, SCALE_EM) == NULL)
241                 return;
242         len = term_hen(p, &su);
243
244         switch (sign) {
245         case 1:
246                 if (p->tcol->offset + len <= maxoff)
247                         p->ti = len;
248                 else if (p->tcol->offset < maxoff)
249                         p->ti = maxoff - p->tcol->offset;
250                 else
251                         p->ti = 0;
252                 break;
253         case -1:
254                 if ((size_t)len < p->tcol->offset)
255                         p->ti = -len;
256                 else
257                         p->ti = -p->tcol->offset;
258                 break;
259         default:
260                 if ((size_t)len > maxoff)
261                         len = maxoff;
262                 p->ti = len - p->tcol->offset;
263                 break;
264         }
265         p->tcol->offset += p->ti;
266 }