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