]> git.cameronkatri.com Git - mandoc.git/blob - term_ascii.c
3b1a36f6cd96aef1bcbf31082c9369edc36fd79c
[mandoc.git] / term_ascii.c
1 /* $Id: term_ascii.c,v 1.36 2014/10/26 18:12:28 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[5];
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] = "synopsis";
101 toks[4] = NULL;
102
103 while (outopts && *outopts)
104 switch (getsubopt(&outopts, UNCONST(toks), &v)) {
105 case 0:
106 p->defindent = (size_t)atoi(v);
107 break;
108 case 1:
109 p->defrmargin = (size_t)atoi(v);
110 break;
111 case 2:
112 /*
113 * Temporary, undocumented mode
114 * to imitate mdoc(7) output style.
115 */
116 p->mdocstyle = 1;
117 p->defindent = 5;
118 break;
119 case 3:
120 p->synopsisonly = 1;
121 break;
122 default:
123 break;
124 }
125
126 /* Enforce a lower boundary. */
127 if (p->defrmargin < 58)
128 p->defrmargin = 58;
129
130 return(p);
131 }
132
133 void *
134 ascii_alloc(char *outopts)
135 {
136
137 return(ascii_init(TERMENC_ASCII, outopts));
138 }
139
140 void *
141 utf8_alloc(char *outopts)
142 {
143
144 return(ascii_init(TERMENC_UTF8, outopts));
145 }
146
147 void *
148 locale_alloc(char *outopts)
149 {
150
151 return(ascii_init(TERMENC_LOCALE, outopts));
152 }
153
154 static void
155 ascii_setwidth(struct termp *p, int iop, size_t width)
156 {
157
158 p->rmargin = p->defrmargin;
159 if (0 < iop)
160 p->defrmargin += width;
161 else if (0 > iop)
162 p->defrmargin -= width;
163 else
164 p->defrmargin = width ? width : p->lastrmargin;
165 p->lastrmargin = p->rmargin;
166 p->rmargin = p->maxrmargin = p->defrmargin;
167 }
168
169 static size_t
170 ascii_width(const struct termp *p, int c)
171 {
172
173 return(1);
174 }
175
176 void
177 ascii_free(void *arg)
178 {
179
180 term_free((struct termp *)arg);
181 }
182
183 static void
184 ascii_letter(struct termp *p, int c)
185 {
186
187 putchar(c);
188 }
189
190 static void
191 ascii_begin(struct termp *p)
192 {
193
194 (*p->headf)(p, p->argf);
195 }
196
197 static void
198 ascii_end(struct termp *p)
199 {
200
201 (*p->footf)(p, p->argf);
202 }
203
204 static void
205 ascii_endline(struct termp *p)
206 {
207
208 putchar('\n');
209 }
210
211 static void
212 ascii_advance(struct termp *p, size_t len)
213 {
214 size_t i;
215
216 for (i = 0; i < len; i++)
217 putchar(' ');
218 }
219
220 static double
221 ascii_hspan(const struct termp *p, const struct roffsu *su)
222 {
223 double r;
224
225 /*
226 * Approximate based on character width.
227 * None of these will be actually correct given that an inch on
228 * the screen depends on character size, terminal, etc., etc.
229 */
230 switch (su->unit) {
231 case SCALE_BU:
232 r = su->scale * 10.0 / 240.0;
233 break;
234 case SCALE_CM:
235 r = su->scale * 10.0 / 2.54;
236 break;
237 case SCALE_FS:
238 r = su->scale * 2730.666;
239 break;
240 case SCALE_IN:
241 r = su->scale * 10.0;
242 break;
243 case SCALE_MM:
244 r = su->scale / 100.0;
245 break;
246 case SCALE_PC:
247 r = su->scale * 10.0 / 6.0;
248 break;
249 case SCALE_PT:
250 r = su->scale * 10.0 / 72.0;
251 break;
252 case SCALE_VS:
253 r = su->scale * 2.0 - 1.0;
254 break;
255 case SCALE_EN:
256 /* FALLTHROUGH */
257 case SCALE_EM:
258 r = su->scale;
259 break;
260 default:
261 abort();
262 /* NOTREACHED */
263 }
264
265 return(r);
266 }
267
268 const char *
269 ascii_uc2str(int uc)
270 {
271 static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
272 static const char *tab[] = {
273 "<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
274 "<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>",
275 "<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>",
276 "<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>",
277 " ", "!", "\"", "#", "$", "%", "&", "'",
278 "(", ")", "*", "+", ",", "-", ".", "/",
279 "0", "1", "2", "3", "4", "5", "6", "7",
280 "8", "9", ":", ";", "<", "=", ">", "?",
281 "@", "A", "B", "C", "D", "E", "F", "G",
282 "H", "I", "J", "K", "L", "M", "N", "O",
283 "P", "Q", "R", "S", "T", "U", "V", "W",
284 "X", "Y", "Z", "[", "\\", "]", "^", "_",
285 "`", "a", "b", "c", "d", "e", "f", "g",
286 "h", "i", "j", "k", "l", "m", "n", "o",
287 "p", "q", "r", "s", "t", "u", "v", "w",
288 "x", "y", "z", "{", "|", "}", "~", "<DEL>",
289 "<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>",
290 "<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
291 "<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
292 "<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
293 nbrsp, "!", "c", "GBP", "$?", "Y=", "|", "<sec>",
294 "\"", "(C)", "a.", "<<", "<not>","", "(R)", "-",
295 "<deg>","+-", "^2", "^3", "'", "<my>", "<par>","*",
296 ",", "^1", "o.", ">>", "1/4", "1/2", "3/4", "?",
297 "A", "A", "A", "A", "Ae", "Aa", "AE", "C",
298 "E", "E", "E", "E", "I", "I", "I", "I",
299 "D", "N", "O", "O", "O", "O", "Oe", "*",
300 "Oe", "U", "U", "U", "Ue", "Y", "Th", "ss",
301 "a", "a", "a", "a", "ae", "aa", "ae", "c",
302 "e", "e", "e", "e", "i", "i", "i", "i",
303 "d", "n", "o", "o", "o", "o", "oe", "/",
304 "oe", "u", "u", "u", "ue", "y", "th", "y",
305 "A", "a", "A", "a", "A", "a", "C", "c",
306 "C", "c", "C", "c", "C", "c", "D", "d",
307 "D", "d", "E", "e", "E", "e", "E", "e",
308 "E", "e", "E", "e", "G", "g", "G", "g",
309 "G", "g", "G", "g", "H", "h", "H", "h",
310 "I", "i", "I", "i", "I", "i", "I", "i",
311 "I", "i", "IJ", "ij", "J", "j", "K", "k",
312 "q", "L", "l", "L", "l", "L", "l", "L",
313 "l", "L", "l", "N", "n", "N", "n", "N",
314 "n", "'n", "Ng", "ng", "O", "o", "O", "o",
315 "O", "o", "OE", "oe", "R", "r", "R", "r",
316 "R", "r", "S", "s", "S", "s", "S", "s",
317 "S", "s", "T", "t", "T", "t", "T", "t",
318 "U", "u", "U", "u", "U", "u", "U", "u",
319 "U", "u", "U", "u", "W", "w", "Y", "y",
320 "Y", "Z", "z", "Z", "z", "Z", "z", "s",
321 "b", "B", "B", "b", "6", "6", "O", "C",
322 "c", "D", "D", "D", "d", "d", "3", "@",
323 "E", "F", "f", "G", "G", "hv", "I", "I",
324 "K", "k", "l", "l", "W", "N", "n", "O",
325 "O", "o", "OI", "oi", "P", "p", "YR", "2",
326 "2", "SH", "sh", "t", "T", "t", "T", "U",
327 "u", "Y", "V", "Y", "y", "Z", "z", "ZH",
328 "ZH", "zh", "zh", "2", "5", "5", "ts", "w",
329 "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ",
330 "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I",
331 "i", "O", "o", "U", "u", "U", "u", "U",
332 "u", "U", "u", "U", "u", "@", "A", "a",
333 "A", "a", "AE", "ae", "G", "g", "G", "g",
334 "K", "k", "O", "o", "O", "o", "ZH", "zh",
335 "j", "DZ", "D", "dz", "G", "g", "HV", "W",
336 "N", "n", "A", "a", "AE", "ae", "O", "o"};
337
338 if (uc < 0)
339 return("<?>");
340 if ((size_t)uc < sizeof(tab)/sizeof(tab[0]))
341 return(tab[uc]);
342 return(mchars_uc2str(uc));
343 }
344
345 #if HAVE_WCHAR
346 static size_t
347 locale_width(const struct termp *p, int c)
348 {
349 int rc;
350
351 if (c == ASCII_NBRSP)
352 c = ' ';
353 rc = wcwidth(c);
354 if (rc < 0)
355 rc = 0;
356 return(rc);
357 }
358
359 static void
360 locale_advance(struct termp *p, size_t len)
361 {
362 size_t i;
363
364 for (i = 0; i < len; i++)
365 putwchar(L' ');
366 }
367
368 static void
369 locale_endline(struct termp *p)
370 {
371
372 putwchar(L'\n');
373 }
374
375 static void
376 locale_letter(struct termp *p, int c)
377 {
378
379 putwchar(c);
380 }
381 #endif