1314817Sngie/*	$Id: term_ascii.c,v 1.20 2011/12/04 23:10:52 schwarze Exp $ */
2311966Sngie/*
3311966Sngie * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4311966Sngie *
5311966Sngie * Permission to use, copy, modify, and distribute this software for any
6311966Sngie * purpose with or without fee is hereby granted, provided that the above
7311966Sngie * copyright notice and this permission notice appear in all copies.
8311966Sngie *
9311966Sngie * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10311966Sngie * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11311966Sngie * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12311966Sngie * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13311966Sngie * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14311966Sngie * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15311966Sngie * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16311966Sngie */
17311966Sngie#ifdef HAVE_CONFIG_H
18311966Sngie#include "config.h"
19311966Sngie#endif
20311966Sngie
21311966Sngie#include <sys/types.h>
22311966Sngie
23311966Sngie#include <assert.h>
24311966Sngie#ifdef USE_WCHAR
25311966Sngie# include <locale.h>
26311966Sngie#endif
27311966Sngie#include <stdint.h>
28311966Sngie#include <stdio.h>
29311966Sngie#include <stdlib.h>
30311966Sngie#include <unistd.h>
31311966Sngie#ifdef USE_WCHAR
32311966Sngie# include <wchar.h>
33311966Sngie#endif
34311966Sngie
35311966Sngie#include "mandoc.h"
36311966Sngie#include "out.h"
37311966Sngie#include "term.h"
38311966Sngie#include "main.h"
39311966Sngie
40311966Sngie/*
41311966Sngie * Sadly, this doesn't seem to be defined on systems even when they
42311966Sngie * support it.  For the time being, remove it and let those compiling
43311966Sngie * the software decide for themselves what to use.
44311966Sngie */
45311966Sngie#if 0
46311966Sngie#if ! defined(__STDC_ISO_10646__)
47311966Sngie# undef USE_WCHAR
48311966Sngie#endif
49311966Sngie#endif
50311966Sngie
51314817Sngiestatic	struct termp	 *ascii_init(enum termenc, char *);
52311966Sngiestatic	double		  ascii_hspan(const struct termp *,
53311966Sngie				const struct roffsu *);
54311966Sngiestatic	size_t		  ascii_width(const struct termp *, int);
55311966Sngiestatic	void		  ascii_advance(struct termp *, size_t);
56311966Sngiestatic	void		  ascii_begin(struct termp *);
57311966Sngiestatic	void		  ascii_end(struct termp *);
58311966Sngiestatic	void		  ascii_endline(struct termp *);
59311966Sngiestatic	void		  ascii_letter(struct termp *, int);
60311966Sngie
61311966Sngie#ifdef	USE_WCHAR
62311966Sngiestatic	void		  locale_advance(struct termp *, size_t);
63311966Sngiestatic	void		  locale_endline(struct termp *);
64311966Sngiestatic	void		  locale_letter(struct termp *, int);
65311966Sngiestatic	size_t		  locale_width(const struct termp *, int);
66311966Sngie#endif
67311966Sngie
68311966Sngiestatic struct termp *
69311966Sngieascii_init(enum termenc enc, char *outopts)
70311966Sngie{
71311966Sngie	const char	*toks[4];
72311966Sngie	char		*v;
73311966Sngie	struct termp	*p;
74311966Sngie
75311966Sngie	p = mandoc_calloc(1, sizeof(struct termp));
76311966Sngie	p->enc = enc;
77311966Sngie
78311966Sngie	p->tabwidth = 5;
79311966Sngie	p->defrmargin = 78;
80311966Sngie
81311966Sngie	p->begin = ascii_begin;
82311966Sngie	p->end = ascii_end;
83311966Sngie	p->hspan = ascii_hspan;
84311966Sngie	p->type = TERMTYPE_CHAR;
85311966Sngie
86311966Sngie	p->enc = TERMENC_ASCII;
87311966Sngie	p->advance = ascii_advance;
88311966Sngie	p->endline = ascii_endline;
89311966Sngie	p->letter = ascii_letter;
90311966Sngie	p->width = ascii_width;
91311966Sngie
92311966Sngie#ifdef	USE_WCHAR
93311966Sngie	if (TERMENC_ASCII != enc) {
94311966Sngie		v = TERMENC_LOCALE == enc ?
95311966Sngie			setlocale(LC_ALL, "") :
96311966Sngie			setlocale(LC_CTYPE, "UTF-8");
97311966Sngie		if (NULL != v && MB_CUR_MAX > 1) {
98311966Sngie			p->enc = enc;
99311966Sngie			p->advance = locale_advance;
100311966Sngie			p->endline = locale_endline;
101311966Sngie			p->letter = locale_letter;
102311966Sngie			p->width = locale_width;
103311966Sngie		}
104311966Sngie	}
105311966Sngie#endif
106311966Sngie
107311966Sngie	toks[0] = "indent";
108311966Sngie	toks[1] = "width";
109311966Sngie	toks[2] = "mdoc";
110311966Sngie	toks[3] = NULL;
111311966Sngie
112311966Sngie	while (outopts && *outopts)
113311966Sngie		switch (getsubopt(&outopts, UNCONST(toks), &v)) {
114311966Sngie		case (0):
115311966Sngie			p->defindent = (size_t)atoi(v);
116311966Sngie			break;
117311966Sngie		case (1):
118311966Sngie			p->defrmargin = (size_t)atoi(v);
119311966Sngie			break;
120311966Sngie		case (2):
121311966Sngie			/*
122311966Sngie			 * Temporary, undocumented mode
123311966Sngie			 * to imitate mdoc(7) output style.
124311966Sngie			 */
125311966Sngie			p->mdocstyle = 1;
126311966Sngie			p->defindent = 5;
127311966Sngie			break;
128311966Sngie		default:
129311966Sngie			break;
130311966Sngie		}
131311966Sngie
132311966Sngie	/* Enforce a lower boundary. */
133311966Sngie	if (p->defrmargin < 58)
134311966Sngie		p->defrmargin = 58;
135311966Sngie
136311966Sngie	return(p);
137311966Sngie}
138311966Sngie
139311966Sngievoid *
140311966Sngieascii_alloc(char *outopts)
141311966Sngie{
142311966Sngie
143311966Sngie	return(ascii_init(TERMENC_ASCII, outopts));
144311966Sngie}
145311966Sngie
146311966Sngievoid *
147311966Sngieutf8_alloc(char *outopts)
148311966Sngie{
149311966Sngie
150311966Sngie	return(ascii_init(TERMENC_UTF8, outopts));
151311966Sngie}
152311966Sngie
153311966Sngie
154311966Sngievoid *
155311966Sngielocale_alloc(char *outopts)
156311966Sngie{
157311966Sngie
158311966Sngie	return(ascii_init(TERMENC_LOCALE, outopts));
159311966Sngie}
160311966Sngie
161311966Sngie/* ARGSUSED */
162311966Sngiestatic size_t
163311966Sngieascii_width(const struct termp *p, int c)
164311966Sngie{
165311966Sngie
166311966Sngie	return(1);
167311966Sngie}
168311966Sngie
169311966Sngievoid
170311966Sngieascii_free(void *arg)
171311966Sngie{
172311966Sngie
173311966Sngie	term_free((struct termp *)arg);
174311966Sngie}
175311966Sngie
176311966Sngie/* ARGSUSED */
177311966Sngiestatic void
178311966Sngieascii_letter(struct termp *p, int c)
179311966Sngie{
180311966Sngie
181311966Sngie	putchar(c);
182311966Sngie}
183311966Sngie
184311966Sngiestatic void
185311966Sngieascii_begin(struct termp *p)
186311966Sngie{
187311966Sngie
188311966Sngie	(*p->headf)(p, p->argf);
189311966Sngie}
190311966Sngie
191311966Sngiestatic void
192311966Sngieascii_end(struct termp *p)
193311966Sngie{
194311966Sngie
195311966Sngie	(*p->footf)(p, p->argf);
196311966Sngie}
197311966Sngie
198311966Sngie/* ARGSUSED */
199311966Sngiestatic void
200311966Sngieascii_endline(struct termp *p)
201311966Sngie{
202311966Sngie
203311966Sngie	putchar('\n');
204311966Sngie}
205311966Sngie
206311966Sngie/* ARGSUSED */
207311966Sngiestatic void
208311966Sngieascii_advance(struct termp *p, size_t len)
209311966Sngie{
210311966Sngie	size_t	 	i;
211311966Sngie
212311966Sngie	for (i = 0; i < len; i++)
213311966Sngie		putchar(' ');
214311966Sngie}
215311966Sngie
216311966Sngie/* ARGSUSED */
217311966Sngiestatic double
218311966Sngieascii_hspan(const struct termp *p, const struct roffsu *su)
219311966Sngie{
220311966Sngie	double		 r;
221311966Sngie
222311966Sngie	/*
223311966Sngie	 * Approximate based on character width.  These are generated
224311966Sngie	 * entirely by eyeballing the screen, but appear to be correct.
225311966Sngie	 */
226311966Sngie
227311966Sngie	switch (su->unit) {
228311966Sngie	case (SCALE_CM):
229311966Sngie		r = 4 * su->scale;
230311966Sngie		break;
231311966Sngie	case (SCALE_IN):
232311966Sngie		r = 10 * su->scale;
233311966Sngie		break;
234311966Sngie	case (SCALE_PC):
235311966Sngie		r = (10 * su->scale) / 6;
236311966Sngie		break;
237311966Sngie	case (SCALE_PT):
238311966Sngie		r = (10 * su->scale) / 72;
239311966Sngie		break;
240311966Sngie	case (SCALE_MM):
241311966Sngie		r = su->scale / 1000;
242311966Sngie		break;
243311966Sngie	case (SCALE_VS):
244311966Sngie		r = su->scale * 2 - 1;
245311966Sngie		break;
246311966Sngie	default:
247311966Sngie		r = su->scale;
248311966Sngie		break;
249311966Sngie	}
250311966Sngie
251311966Sngie	return(r);
252311966Sngie}
253311966Sngie
254311966Sngie#ifdef USE_WCHAR
255311966Sngie/* ARGSUSED */
256311966Sngiestatic size_t
257311966Sngielocale_width(const struct termp *p, int c)
258311966Sngie{
259311966Sngie	int		rc;
260311966Sngie
261311966Sngie	return((rc = wcwidth(c)) < 0 ? 0 : rc);
262311966Sngie}
263311966Sngie
264311966Sngie/* ARGSUSED */
265311966Sngiestatic void
266311966Sngielocale_advance(struct termp *p, size_t len)
267311966Sngie{
268311966Sngie	size_t	 	i;
269311966Sngie
270311966Sngie	for (i = 0; i < len; i++)
271311966Sngie		putwchar(L' ');
272311966Sngie}
273311966Sngie
274311966Sngie/* ARGSUSED */
275311966Sngiestatic void
276311966Sngielocale_endline(struct termp *p)
277311966Sngie{
278311966Sngie
279311966Sngie	putwchar(L'\n');
280311966Sngie}
281311966Sngie
282311966Sngie/* ARGSUSED */
283311966Sngiestatic void
284311966Sngielocale_letter(struct termp *p, int c)
285311966Sngie{
286311966Sngie
287311966Sngie	putwchar(c);
288311966Sngie}
289311966Sngie#endif
290311966Sngie