Import mdocml-1.13.1
[dragonfly.git] / contrib / mdocml / term_ascii.c
CommitLineData
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
52static struct termp *ascii_init(enum termenc, char *);
80387638
SW
53static double ascii_hspan(const struct termp *,
54 const struct roffsu *);
a4c7eb57 55static size_t ascii_width(const struct termp *, int);
80387638
SW
56static void ascii_advance(struct termp *, size_t);
57static void ascii_begin(struct termp *);
58static void ascii_end(struct termp *);
59static void ascii_endline(struct termp *);
a4c7eb57 60static void ascii_letter(struct termp *, int);
070c62a6 61static void ascii_setwidth(struct termp *, int, size_t);
80387638 62
a4c7eb57
SW
63#ifdef USE_WCHAR
64static void locale_advance(struct termp *, size_t);
65static void locale_endline(struct termp *);
66static void locale_letter(struct termp *, int);
67static size_t locale_width(const struct termp *, int);
68#endif
80387638 69
070c62a6 70
a4c7eb57
SW
71static struct termp *
72ascii_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
142void *
143ascii_alloc(char *outopts)
144{
145
146 return(ascii_init(TERMENC_ASCII, outopts));
147}
148
149void *
150utf8_alloc(char *outopts)
151{
152
153 return(ascii_init(TERMENC_UTF8, outopts));
154}
155
a4c7eb57
SW
156void *
157locale_alloc(char *outopts)
158{
159
160 return(ascii_init(TERMENC_LOCALE, outopts));
161}
80387638 162
070c62a6
FF
163static void
164ascii_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 178static size_t
a4c7eb57 179ascii_width(const struct termp *p, int c)
80387638
SW
180{
181
182 return(1);
183}
184
80387638
SW
185void
186ascii_free(void *arg)
187{
188
189 term_free((struct termp *)arg);
190}
191
80387638 192static void
a4c7eb57 193ascii_letter(struct termp *p, int c)
80387638 194{
070c62a6 195
80387638
SW
196 putchar(c);
197}
198
80387638
SW
199static void
200ascii_begin(struct termp *p)
201{
202
203 (*p->headf)(p, p->argf);
204}
205
80387638
SW
206static void
207ascii_end(struct termp *p)
208{
209
210 (*p->footf)(p, p->argf);
211}
212
80387638
SW
213static void
214ascii_endline(struct termp *p)
215{
216
217 putchar('\n');
218}
219
80387638
SW
220static void
221ascii_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
229static double
230ascii_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
267static size_t
268locale_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
280static void
281locale_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
289static void
290locale_endline(struct termp *p)
291{
292
293 putwchar(L'\n');
294}
295
a4c7eb57
SW
296static void
297locale_letter(struct termp *p, int c)
298{
070c62a6 299
a4c7eb57
SW
300 putwchar(c);
301}
302#endif