]> git.cameronkatri.com Git - mandoc.git/blob - term_ascii.c
While all current callers pass valid data to ascii_hspan() only,
[mandoc.git] / term_ascii.c
1 /* $Id: term_ascii.c,v 1.32 2014/08/17 22:10:29 schwarze Exp $ */
2 /*
3 * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #if HAVE_WCHAR
23 #include <locale.h>
24 #endif
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #if HAVE_WCHAR
30 #include <wchar.h>
31 #endif
32
33 #include "mandoc.h"
34 #include "mandoc_aux.h"
35 #include "out.h"
36 #include "term.h"
37 #include "main.h"
38
39 static struct termp *ascii_init(enum termenc, char *);
40 static double ascii_hspan(const struct termp *,
41 const struct roffsu *);
42 static size_t ascii_width(const struct termp *, int);
43 static void ascii_advance(struct termp *, size_t);
44 static void ascii_begin(struct termp *);
45 static void ascii_end(struct termp *);
46 static void ascii_endline(struct termp *);
47 static void ascii_letter(struct termp *, int);
48 static void ascii_setwidth(struct termp *, int, size_t);
49
50 #if HAVE_WCHAR
51 static void locale_advance(struct termp *, size_t);
52 static void locale_endline(struct termp *);
53 static void locale_letter(struct termp *, int);
54 static size_t locale_width(const struct termp *, int);
55 #endif
56
57
58 static struct termp *
59 ascii_init(enum termenc enc, char *outopts)
60 {
61 const char *toks[4];
62 char *v;
63 struct termp *p;
64
65 p = mandoc_calloc(1, sizeof(struct termp));
66
67 p->tabwidth = 5;
68 p->defrmargin = p->lastrmargin = 78;
69
70 p->begin = ascii_begin;
71 p->end = ascii_end;
72 p->hspan = ascii_hspan;
73 p->type = TERMTYPE_CHAR;
74
75 p->enc = TERMENC_ASCII;
76 p->advance = ascii_advance;
77 p->endline = ascii_endline;
78 p->letter = ascii_letter;
79 p->setwidth = ascii_setwidth;
80 p->width = ascii_width;
81
82 #if HAVE_WCHAR
83 if (TERMENC_ASCII != enc) {
84 v = TERMENC_LOCALE == enc ?
85 setlocale(LC_ALL, "") :
86 setlocale(LC_CTYPE, "en_US.UTF-8");
87 if (NULL != v && MB_CUR_MAX > 1) {
88 p->enc = enc;
89 p->advance = locale_advance;
90 p->endline = locale_endline;
91 p->letter = locale_letter;
92 p->width = locale_width;
93 }
94 }
95 #endif
96
97 toks[0] = "indent";
98 toks[1] = "width";
99 toks[2] = "mdoc";
100 toks[3] = NULL;
101
102 while (outopts && *outopts)
103 switch (getsubopt(&outopts, UNCONST(toks), &v)) {
104 case 0:
105 p->defindent = (size_t)atoi(v);
106 break;
107 case 1:
108 p->defrmargin = (size_t)atoi(v);
109 break;
110 case 2:
111 /*
112 * Temporary, undocumented mode
113 * to imitate mdoc(7) output style.
114 */
115 p->mdocstyle = 1;
116 p->defindent = 5;
117 break;
118 default:
119 break;
120 }
121
122 /* Enforce a lower boundary. */
123 if (p->defrmargin < 58)
124 p->defrmargin = 58;
125
126 return(p);
127 }
128
129 void *
130 ascii_alloc(char *outopts)
131 {
132
133 return(ascii_init(TERMENC_ASCII, outopts));
134 }
135
136 void *
137 utf8_alloc(char *outopts)
138 {
139
140 return(ascii_init(TERMENC_UTF8, outopts));
141 }
142
143 void *
144 locale_alloc(char *outopts)
145 {
146
147 return(ascii_init(TERMENC_LOCALE, outopts));
148 }
149
150 static void
151 ascii_setwidth(struct termp *p, int iop, size_t width)
152 {
153
154 p->rmargin = p->defrmargin;
155 if (0 < iop)
156 p->defrmargin += width;
157 else if (0 > iop)
158 p->defrmargin -= width;
159 else
160 p->defrmargin = width ? width : p->lastrmargin;
161 p->lastrmargin = p->rmargin;
162 p->rmargin = p->maxrmargin = p->defrmargin;
163 }
164
165 static size_t
166 ascii_width(const struct termp *p, int c)
167 {
168
169 return(1);
170 }
171
172 void
173 ascii_free(void *arg)
174 {
175
176 term_free((struct termp *)arg);
177 }
178
179 static void
180 ascii_letter(struct termp *p, int c)
181 {
182
183 putchar(c);
184 }
185
186 static void
187 ascii_begin(struct termp *p)
188 {
189
190 (*p->headf)(p, p->argf);
191 }
192
193 static void
194 ascii_end(struct termp *p)
195 {
196
197 (*p->footf)(p, p->argf);
198 }
199
200 static void
201 ascii_endline(struct termp *p)
202 {
203
204 putchar('\n');
205 }
206
207 static void
208 ascii_advance(struct termp *p, size_t len)
209 {
210 size_t i;
211
212 for (i = 0; i < len; i++)
213 putchar(' ');
214 }
215
216 static double
217 ascii_hspan(const struct termp *p, const struct roffsu *su)
218 {
219 double r;
220
221 /*
222 * Approximate based on character width.
223 * None of these will be actually correct given that an inch on
224 * the screen depends on character size, terminal, etc., etc.
225 */
226 switch (su->unit) {
227 case SCALE_BU:
228 r = su->scale * 10.0 / 240.0;
229 break;
230 case SCALE_CM:
231 r = su->scale * 10.0 / 2.54;
232 break;
233 case SCALE_FS:
234 r = su->scale * 2730.666;
235 break;
236 case SCALE_IN:
237 r = su->scale * 10.0;
238 break;
239 case SCALE_MM:
240 r = su->scale / 100.0;
241 break;
242 case SCALE_PC:
243 r = su->scale * 10.0 / 6.0;
244 break;
245 case SCALE_PT:
246 r = su->scale * 10.0 / 72.0;
247 break;
248 case SCALE_VS:
249 r = su->scale * 2.0 - 1.0;
250 break;
251 case SCALE_EN:
252 /* FALLTHROUGH */
253 case SCALE_EM:
254 r = su->scale;
255 break;
256 default:
257 abort();
258 /* NOTREACHED */
259 }
260
261 return(r);
262 }
263
264 #if HAVE_WCHAR
265 static size_t
266 locale_width(const struct termp *p, int c)
267 {
268 int rc;
269
270 if (c == ASCII_NBRSP)
271 c = ' ';
272 rc = wcwidth(c);
273 if (rc < 0)
274 rc = 0;
275 return(rc);
276 }
277
278 static void
279 locale_advance(struct termp *p, size_t len)
280 {
281 size_t i;
282
283 for (i = 0; i < len; i++)
284 putwchar(L' ');
285 }
286
287 static void
288 locale_endline(struct termp *p)
289 {
290
291 putwchar(L'\n');
292 }
293
294 static void
295 locale_letter(struct termp *p, int c)
296 {
297
298 putwchar(c);
299 }
300 #endif