Commit | Line | Data |
---|---|---|
070c62a6 | 1 | /* $Id: term_ascii.c,v 1.27 2014/08/01 19:25:52 schwarze Exp $ */ |
80387638 | 2 | /* |
36342e81 | 3 | * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
070c62a6 | 4 | * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> |
80387638 SW |
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 | #ifdef HAVE_CONFIG_H | |
19 | #include "config.h" | |
20 | #endif | |
21 | ||
22 | #include <sys/types.h> | |
23 | ||
a4c7eb57 SW |
24 | #ifdef USE_WCHAR |
25 | # include <locale.h> | |
26 | #endif | |
80387638 SW |
27 | #include <stdint.h> |
28 | #include <stdio.h> | |
29 | #include <stdlib.h> | |
30 | #include <unistd.h> | |
a4c7eb57 SW |
31 | #ifdef USE_WCHAR |
32 | # include <wchar.h> | |
33 | #endif | |
80387638 SW |
34 | |
35 | #include "mandoc.h" | |
070c62a6 | 36 | #include "mandoc_aux.h" |
80387638 SW |
37 | #include "out.h" |
38 | #include "term.h" | |
39 | #include "main.h" | |
40 | ||
a4c7eb57 SW |
41 | /* |
42 | * Sadly, this doesn't seem to be defined on systems even when they | |
43 | * support it. For the time being, remove it and let those compiling | |
44 | * the software decide for themselves what to use. | |
45 | */ | |
46 | #if 0 | |
47 | #if ! defined(__STDC_ISO_10646__) | |
48 | # undef USE_WCHAR | |
49 | #endif | |
50 | #endif | |
51 | ||
52 | static struct termp *ascii_init(enum termenc, char *); | |
80387638 SW |
53 | static double ascii_hspan(const struct termp *, |
54 | const struct roffsu *); | |
a4c7eb57 | 55 | static size_t ascii_width(const struct termp *, int); |
80387638 SW |
56 | static void ascii_advance(struct termp *, size_t); |
57 | static void ascii_begin(struct termp *); | |
58 | static void ascii_end(struct termp *); | |
59 | static void ascii_endline(struct termp *); | |
a4c7eb57 | 60 | static void ascii_letter(struct termp *, int); |
070c62a6 | 61 | static void ascii_setwidth(struct termp *, int, size_t); |
80387638 | 62 | |
a4c7eb57 SW |
63 | #ifdef USE_WCHAR |
64 | static void locale_advance(struct termp *, size_t); | |
65 | static void locale_endline(struct termp *); | |
66 | static void locale_letter(struct termp *, int); | |
67 | static size_t locale_width(const struct termp *, int); | |
68 | #endif | |
80387638 | 69 | |
070c62a6 | 70 | |
a4c7eb57 SW |
71 | static struct termp * |
72 | ascii_init(enum termenc enc, char *outopts) | |
80387638 | 73 | { |
36342e81 | 74 | const char *toks[4]; |
80387638 | 75 | char *v; |
a4c7eb57 | 76 | struct termp *p; |
80387638 | 77 | |
a4c7eb57 | 78 | p = mandoc_calloc(1, sizeof(struct termp)); |
80387638 SW |
79 | |
80 | p->tabwidth = 5; | |
070c62a6 | 81 | p->defrmargin = p->lastrmargin = 78; |
80387638 | 82 | |
80387638 SW |
83 | p->begin = ascii_begin; |
84 | p->end = ascii_end; | |
80387638 | 85 | p->hspan = ascii_hspan; |
80387638 | 86 | p->type = TERMTYPE_CHAR; |
a4c7eb57 SW |
87 | |
88 | p->enc = TERMENC_ASCII; | |
89 | p->advance = ascii_advance; | |
90 | p->endline = ascii_endline; | |
91 | p->letter = ascii_letter; | |
070c62a6 | 92 | p->setwidth = ascii_setwidth; |
80387638 SW |
93 | p->width = ascii_width; |
94 | ||
a4c7eb57 SW |
95 | #ifdef USE_WCHAR |
96 | if (TERMENC_ASCII != enc) { | |
97 | v = TERMENC_LOCALE == enc ? | |
070c62a6 FF |
98 | setlocale(LC_ALL, "") : |
99 | setlocale(LC_CTYPE, "en_US.UTF-8"); | |
a4c7eb57 SW |
100 | if (NULL != v && MB_CUR_MAX > 1) { |
101 | p->enc = enc; | |
102 | p->advance = locale_advance; | |
103 | p->endline = locale_endline; | |
104 | p->letter = locale_letter; | |
105 | p->width = locale_width; | |
106 | } | |
107 | } | |
108 | #endif | |
109 | ||
36342e81 SW |
110 | toks[0] = "indent"; |
111 | toks[1] = "width"; | |
112 | toks[2] = "mdoc"; | |
113 | toks[3] = NULL; | |
80387638 SW |
114 | |
115 | while (outopts && *outopts) | |
116 | switch (getsubopt(&outopts, UNCONST(toks), &v)) { | |
070c62a6 | 117 | case 0: |
36342e81 SW |
118 | p->defindent = (size_t)atoi(v); |
119 | break; | |
070c62a6 | 120 | case 1: |
80387638 SW |
121 | p->defrmargin = (size_t)atoi(v); |
122 | break; | |
070c62a6 | 123 | case 2: |
36342e81 SW |
124 | /* |
125 | * Temporary, undocumented mode | |
126 | * to imitate mdoc(7) output style. | |
127 | */ | |
128 | p->mdocstyle = 1; | |
129 | p->defindent = 5; | |
130 | break; | |
80387638 SW |
131 | default: |
132 | break; | |
133 | } | |
134 | ||
135 | /* Enforce a lower boundary. */ | |
136 | if (p->defrmargin < 58) | |
137 | p->defrmargin = 58; | |
138 | ||
139 | return(p); | |
140 | } | |
141 | ||
a4c7eb57 SW |
142 | void * |
143 | ascii_alloc(char *outopts) | |
144 | { | |
145 | ||
146 | return(ascii_init(TERMENC_ASCII, outopts)); | |
147 | } | |
148 | ||
149 | void * | |
150 | utf8_alloc(char *outopts) | |
151 | { | |
152 | ||
153 | return(ascii_init(TERMENC_UTF8, outopts)); | |
154 | } | |
155 | ||
a4c7eb57 SW |
156 | void * |
157 | locale_alloc(char *outopts) | |
158 | { | |
159 | ||
160 | return(ascii_init(TERMENC_LOCALE, outopts)); | |
161 | } | |
80387638 | 162 | |
070c62a6 FF |
163 | static void |
164 | ascii_setwidth(struct termp *p, int iop, size_t width) | |
165 | { | |
166 | ||
167 | p->rmargin = p->defrmargin; | |
168 | if (0 < iop) | |
169 | p->defrmargin += width; | |
170 | else if (0 > iop) | |
171 | p->defrmargin -= width; | |
172 | else | |
173 | p->defrmargin = width ? width : p->lastrmargin; | |
174 | p->lastrmargin = p->rmargin; | |
175 | p->rmargin = p->maxrmargin = p->defrmargin; | |
176 | } | |
177 | ||
80387638 | 178 | static size_t |
a4c7eb57 | 179 | ascii_width(const struct termp *p, int c) |
80387638 SW |
180 | { |
181 | ||
182 | return(1); | |
183 | } | |
184 | ||
80387638 SW |
185 | void |
186 | ascii_free(void *arg) | |
187 | { | |
188 | ||
189 | term_free((struct termp *)arg); | |
190 | } | |
191 | ||
80387638 | 192 | static void |
a4c7eb57 | 193 | ascii_letter(struct termp *p, int c) |
80387638 | 194 | { |
070c62a6 | 195 | |
80387638 SW |
196 | putchar(c); |
197 | } | |
198 | ||
80387638 SW |
199 | static void |
200 | ascii_begin(struct termp *p) | |
201 | { | |
202 | ||
203 | (*p->headf)(p, p->argf); | |
204 | } | |
205 | ||
80387638 SW |
206 | static void |
207 | ascii_end(struct termp *p) | |
208 | { | |
209 | ||
210 | (*p->footf)(p, p->argf); | |
211 | } | |
212 | ||
80387638 SW |
213 | static void |
214 | ascii_endline(struct termp *p) | |
215 | { | |
216 | ||
217 | putchar('\n'); | |
218 | } | |
219 | ||
80387638 SW |
220 | static void |
221 | ascii_advance(struct termp *p, size_t len) | |
222 | { | |
070c62a6 | 223 | size_t i; |
80387638 | 224 | |
80387638 SW |
225 | for (i = 0; i < len; i++) |
226 | putchar(' '); | |
227 | } | |
228 | ||
80387638 SW |
229 | static double |
230 | ascii_hspan(const struct termp *p, const struct roffsu *su) | |
231 | { | |
232 | double r; | |
233 | ||
234 | /* | |
235 | * Approximate based on character width. These are generated | |
236 | * entirely by eyeballing the screen, but appear to be correct. | |
237 | */ | |
238 | ||
239 | switch (su->unit) { | |
070c62a6 FF |
240 | case SCALE_CM: |
241 | r = su->scale * 4.0; | |
80387638 | 242 | break; |
070c62a6 FF |
243 | case SCALE_IN: |
244 | r = su->scale * 10.0; | |
80387638 | 245 | break; |
070c62a6 FF |
246 | case SCALE_PC: |
247 | r = (su->scale * 10.0) / 6.0; | |
80387638 | 248 | break; |
070c62a6 FF |
249 | case SCALE_PT: |
250 | r = (su->scale * 10.0) / 72.0; | |
80387638 | 251 | break; |
070c62a6 FF |
252 | case SCALE_MM: |
253 | r = su->scale / 1000.0; | |
80387638 | 254 | break; |
070c62a6 FF |
255 | case SCALE_VS: |
256 | r = su->scale * 2.0 - 1.0; | |
80387638 SW |
257 | break; |
258 | default: | |
259 | r = su->scale; | |
260 | break; | |
261 | } | |
262 | ||
263 | return(r); | |
264 | } | |
265 | ||
a4c7eb57 | 266 | #ifdef USE_WCHAR |
a4c7eb57 SW |
267 | static size_t |
268 | locale_width(const struct termp *p, int c) | |
269 | { | |
270 | int rc; | |
271 | ||
070c62a6 FF |
272 | if (c == ASCII_NBRSP) |
273 | c = ' '; | |
274 | rc = wcwidth(c); | |
275 | if (rc < 0) | |
276 | rc = 0; | |
277 | return(rc); | |
a4c7eb57 SW |
278 | } |
279 | ||
a4c7eb57 SW |
280 | static void |
281 | locale_advance(struct termp *p, size_t len) | |
282 | { | |
070c62a6 | 283 | size_t i; |
a4c7eb57 SW |
284 | |
285 | for (i = 0; i < len; i++) | |
286 | putwchar(L' '); | |
287 | } | |
288 | ||
a4c7eb57 SW |
289 | static void |
290 | locale_endline(struct termp *p) | |
291 | { | |
292 | ||
293 | putwchar(L'\n'); | |
294 | } | |
295 | ||
a4c7eb57 SW |
296 | static void |
297 | locale_letter(struct termp *p, int c) | |
298 | { | |
070c62a6 | 299 | |
a4c7eb57 SW |
300 | putwchar(c); |
301 | } | |
302 | #endif |