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