1*0a6a1f1dSLionel Sambuc /* Id: term_ascii.c,v 1.21 2013/06/01 14:27:20 schwarze Exp */
2d65f6f70SBen Gras /*
392395e9cSLionel Sambuc * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4d65f6f70SBen Gras *
5d65f6f70SBen Gras * Permission to use, copy, modify, and distribute this software for any
6d65f6f70SBen Gras * purpose with or without fee is hereby granted, provided that the above
7d65f6f70SBen Gras * copyright notice and this permission notice appear in all copies.
8d65f6f70SBen Gras *
9d65f6f70SBen Gras * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10d65f6f70SBen Gras * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11d65f6f70SBen Gras * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12d65f6f70SBen Gras * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13d65f6f70SBen Gras * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14d65f6f70SBen Gras * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15d65f6f70SBen Gras * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16d65f6f70SBen Gras */
17d65f6f70SBen Gras #ifdef HAVE_CONFIG_H
18d65f6f70SBen Gras #include "config.h"
19d65f6f70SBen Gras #endif
20d65f6f70SBen Gras
21d65f6f70SBen Gras #include <sys/types.h>
22d65f6f70SBen Gras
23d65f6f70SBen Gras #include <assert.h>
2492395e9cSLionel Sambuc #ifdef USE_WCHAR
2592395e9cSLionel Sambuc # include <locale.h>
2692395e9cSLionel Sambuc #endif
27d65f6f70SBen Gras #include <stdint.h>
28d65f6f70SBen Gras #include <stdio.h>
29d65f6f70SBen Gras #include <stdlib.h>
30d65f6f70SBen Gras #include <unistd.h>
3192395e9cSLionel Sambuc #ifdef USE_WCHAR
3292395e9cSLionel Sambuc # include <wchar.h>
3392395e9cSLionel Sambuc #endif
34d65f6f70SBen Gras
35d65f6f70SBen Gras #include "mandoc.h"
36d65f6f70SBen Gras #include "out.h"
37d65f6f70SBen Gras #include "term.h"
38d65f6f70SBen Gras #include "main.h"
39d65f6f70SBen Gras
4092395e9cSLionel Sambuc /*
4192395e9cSLionel Sambuc * Sadly, this doesn't seem to be defined on systems even when they
4292395e9cSLionel Sambuc * support it. For the time being, remove it and let those compiling
4392395e9cSLionel Sambuc * the software decide for themselves what to use.
4492395e9cSLionel Sambuc */
4592395e9cSLionel Sambuc #if 0
4692395e9cSLionel Sambuc #if ! defined(__STDC_ISO_10646__)
4792395e9cSLionel Sambuc # undef USE_WCHAR
4892395e9cSLionel Sambuc #endif
4992395e9cSLionel Sambuc #endif
5092395e9cSLionel Sambuc
5192395e9cSLionel Sambuc static struct termp *ascii_init(enum termenc, char *);
52d65f6f70SBen Gras static double ascii_hspan(const struct termp *,
53d65f6f70SBen Gras const struct roffsu *);
5492395e9cSLionel Sambuc static size_t ascii_width(const struct termp *, int);
55d65f6f70SBen Gras static void ascii_advance(struct termp *, size_t);
56d65f6f70SBen Gras static void ascii_begin(struct termp *);
57d65f6f70SBen Gras static void ascii_end(struct termp *);
58d65f6f70SBen Gras static void ascii_endline(struct termp *);
5992395e9cSLionel Sambuc static void ascii_letter(struct termp *, int);
60d65f6f70SBen Gras
6192395e9cSLionel Sambuc #ifdef USE_WCHAR
6292395e9cSLionel Sambuc static void locale_advance(struct termp *, size_t);
6392395e9cSLionel Sambuc static void locale_endline(struct termp *);
6492395e9cSLionel Sambuc static void locale_letter(struct termp *, int);
6592395e9cSLionel Sambuc static size_t locale_width(const struct termp *, int);
6692395e9cSLionel Sambuc #endif
67d65f6f70SBen Gras
6892395e9cSLionel Sambuc static struct termp *
ascii_init(enum termenc enc,char * outopts)6992395e9cSLionel Sambuc ascii_init(enum termenc enc, char *outopts)
70d65f6f70SBen Gras {
7192395e9cSLionel Sambuc const char *toks[4];
72d65f6f70SBen Gras char *v;
7392395e9cSLionel Sambuc struct termp *p;
74d65f6f70SBen Gras
7592395e9cSLionel Sambuc p = mandoc_calloc(1, sizeof(struct termp));
76d65f6f70SBen Gras
77d65f6f70SBen Gras p->tabwidth = 5;
78d65f6f70SBen Gras p->defrmargin = 78;
79d65f6f70SBen Gras
80d65f6f70SBen Gras p->begin = ascii_begin;
81d65f6f70SBen Gras p->end = ascii_end;
82d65f6f70SBen Gras p->hspan = ascii_hspan;
83d65f6f70SBen Gras p->type = TERMTYPE_CHAR;
8492395e9cSLionel Sambuc
8592395e9cSLionel Sambuc p->enc = TERMENC_ASCII;
8692395e9cSLionel Sambuc p->advance = ascii_advance;
8792395e9cSLionel Sambuc p->endline = ascii_endline;
8892395e9cSLionel Sambuc p->letter = ascii_letter;
89d65f6f70SBen Gras p->width = ascii_width;
90d65f6f70SBen Gras
9192395e9cSLionel Sambuc #ifdef USE_WCHAR
9292395e9cSLionel Sambuc if (TERMENC_ASCII != enc) {
9392395e9cSLionel Sambuc v = TERMENC_LOCALE == enc ?
9492395e9cSLionel Sambuc setlocale(LC_ALL, "") :
95*0a6a1f1dSLionel Sambuc setlocale(LC_CTYPE, "en_US.UTF-8");
9692395e9cSLionel Sambuc if (NULL != v && MB_CUR_MAX > 1) {
9792395e9cSLionel Sambuc p->enc = enc;
9892395e9cSLionel Sambuc p->advance = locale_advance;
9992395e9cSLionel Sambuc p->endline = locale_endline;
10092395e9cSLionel Sambuc p->letter = locale_letter;
10192395e9cSLionel Sambuc p->width = locale_width;
10292395e9cSLionel Sambuc }
10392395e9cSLionel Sambuc }
10492395e9cSLionel Sambuc #endif
10592395e9cSLionel Sambuc
10692395e9cSLionel Sambuc toks[0] = "indent";
10792395e9cSLionel Sambuc toks[1] = "width";
10892395e9cSLionel Sambuc toks[2] = "mdoc";
10992395e9cSLionel Sambuc toks[3] = NULL;
110d65f6f70SBen Gras
111d65f6f70SBen Gras while (outopts && *outopts)
112d65f6f70SBen Gras switch (getsubopt(&outopts, UNCONST(toks), &v)) {
113d65f6f70SBen Gras case (0):
11492395e9cSLionel Sambuc p->defindent = (size_t)atoi(v);
11592395e9cSLionel Sambuc break;
11692395e9cSLionel Sambuc case (1):
117d65f6f70SBen Gras p->defrmargin = (size_t)atoi(v);
118d65f6f70SBen Gras break;
11992395e9cSLionel Sambuc case (2):
12092395e9cSLionel Sambuc /*
12192395e9cSLionel Sambuc * Temporary, undocumented mode
12292395e9cSLionel Sambuc * to imitate mdoc(7) output style.
12392395e9cSLionel Sambuc */
12492395e9cSLionel Sambuc p->mdocstyle = 1;
12592395e9cSLionel Sambuc p->defindent = 5;
12692395e9cSLionel Sambuc break;
127d65f6f70SBen Gras default:
128d65f6f70SBen Gras break;
129d65f6f70SBen Gras }
130d65f6f70SBen Gras
131d65f6f70SBen Gras /* Enforce a lower boundary. */
132d65f6f70SBen Gras if (p->defrmargin < 58)
133d65f6f70SBen Gras p->defrmargin = 58;
134d65f6f70SBen Gras
135d65f6f70SBen Gras return(p);
136d65f6f70SBen Gras }
137d65f6f70SBen Gras
13892395e9cSLionel Sambuc void *
ascii_alloc(char * outopts)13992395e9cSLionel Sambuc ascii_alloc(char *outopts)
14092395e9cSLionel Sambuc {
14192395e9cSLionel Sambuc
14292395e9cSLionel Sambuc return(ascii_init(TERMENC_ASCII, outopts));
14392395e9cSLionel Sambuc }
14492395e9cSLionel Sambuc
14592395e9cSLionel Sambuc void *
utf8_alloc(char * outopts)14692395e9cSLionel Sambuc utf8_alloc(char *outopts)
14792395e9cSLionel Sambuc {
14892395e9cSLionel Sambuc
14992395e9cSLionel Sambuc return(ascii_init(TERMENC_UTF8, outopts));
15092395e9cSLionel Sambuc }
15192395e9cSLionel Sambuc
15292395e9cSLionel Sambuc
15392395e9cSLionel Sambuc void *
locale_alloc(char * outopts)15492395e9cSLionel Sambuc locale_alloc(char *outopts)
15592395e9cSLionel Sambuc {
15692395e9cSLionel Sambuc
15792395e9cSLionel Sambuc return(ascii_init(TERMENC_LOCALE, outopts));
15892395e9cSLionel Sambuc }
159d65f6f70SBen Gras
160d65f6f70SBen Gras /* ARGSUSED */
161d65f6f70SBen Gras static size_t
ascii_width(const struct termp * p,int c)16292395e9cSLionel Sambuc ascii_width(const struct termp *p, int c)
163d65f6f70SBen Gras {
164d65f6f70SBen Gras
165d65f6f70SBen Gras return(1);
166d65f6f70SBen Gras }
167d65f6f70SBen Gras
168d65f6f70SBen Gras void
ascii_free(void * arg)169d65f6f70SBen Gras ascii_free(void *arg)
170d65f6f70SBen Gras {
171d65f6f70SBen Gras
172d65f6f70SBen Gras term_free((struct termp *)arg);
173d65f6f70SBen Gras }
174d65f6f70SBen Gras
175d65f6f70SBen Gras /* ARGSUSED */
176d65f6f70SBen Gras static void
ascii_letter(struct termp * p,int c)17792395e9cSLionel Sambuc ascii_letter(struct termp *p, int c)
178d65f6f70SBen Gras {
179d65f6f70SBen Gras
180d65f6f70SBen Gras putchar(c);
181d65f6f70SBen Gras }
182d65f6f70SBen Gras
183d65f6f70SBen Gras static void
ascii_begin(struct termp * p)184d65f6f70SBen Gras ascii_begin(struct termp *p)
185d65f6f70SBen Gras {
186d65f6f70SBen Gras
187d65f6f70SBen Gras (*p->headf)(p, p->argf);
188d65f6f70SBen Gras }
189d65f6f70SBen Gras
190d65f6f70SBen Gras static void
ascii_end(struct termp * p)191d65f6f70SBen Gras ascii_end(struct termp *p)
192d65f6f70SBen Gras {
193d65f6f70SBen Gras
194d65f6f70SBen Gras (*p->footf)(p, p->argf);
195d65f6f70SBen Gras }
196d65f6f70SBen Gras
197d65f6f70SBen Gras /* ARGSUSED */
198d65f6f70SBen Gras static void
ascii_endline(struct termp * p)199d65f6f70SBen Gras ascii_endline(struct termp *p)
200d65f6f70SBen Gras {
201d65f6f70SBen Gras
202d65f6f70SBen Gras putchar('\n');
203d65f6f70SBen Gras }
204d65f6f70SBen Gras
205d65f6f70SBen Gras /* ARGSUSED */
206d65f6f70SBen Gras static void
ascii_advance(struct termp * p,size_t len)207d65f6f70SBen Gras ascii_advance(struct termp *p, size_t len)
208d65f6f70SBen Gras {
209d65f6f70SBen Gras size_t i;
210d65f6f70SBen Gras
211d65f6f70SBen Gras for (i = 0; i < len; i++)
212d65f6f70SBen Gras putchar(' ');
213d65f6f70SBen Gras }
214d65f6f70SBen Gras
215d65f6f70SBen Gras /* ARGSUSED */
216d65f6f70SBen Gras static double
ascii_hspan(const struct termp * p,const struct roffsu * su)217d65f6f70SBen Gras ascii_hspan(const struct termp *p, const struct roffsu *su)
218d65f6f70SBen Gras {
219d65f6f70SBen Gras double r;
220d65f6f70SBen Gras
221d65f6f70SBen Gras /*
222d65f6f70SBen Gras * Approximate based on character width. These are generated
223d65f6f70SBen Gras * entirely by eyeballing the screen, but appear to be correct.
224d65f6f70SBen Gras */
225d65f6f70SBen Gras
226d65f6f70SBen Gras switch (su->unit) {
227d65f6f70SBen Gras case (SCALE_CM):
228d65f6f70SBen Gras r = 4 * su->scale;
229d65f6f70SBen Gras break;
230d65f6f70SBen Gras case (SCALE_IN):
231d65f6f70SBen Gras r = 10 * su->scale;
232d65f6f70SBen Gras break;
233d65f6f70SBen Gras case (SCALE_PC):
234d65f6f70SBen Gras r = (10 * su->scale) / 6;
235d65f6f70SBen Gras break;
236d65f6f70SBen Gras case (SCALE_PT):
237d65f6f70SBen Gras r = (10 * su->scale) / 72;
238d65f6f70SBen Gras break;
239d65f6f70SBen Gras case (SCALE_MM):
240d65f6f70SBen Gras r = su->scale / 1000;
241d65f6f70SBen Gras break;
242d65f6f70SBen Gras case (SCALE_VS):
243d65f6f70SBen Gras r = su->scale * 2 - 1;
244d65f6f70SBen Gras break;
245d65f6f70SBen Gras default:
246d65f6f70SBen Gras r = su->scale;
247d65f6f70SBen Gras break;
248d65f6f70SBen Gras }
249d65f6f70SBen Gras
250d65f6f70SBen Gras return(r);
251d65f6f70SBen Gras }
252d65f6f70SBen Gras
25392395e9cSLionel Sambuc #ifdef USE_WCHAR
25492395e9cSLionel Sambuc /* ARGSUSED */
25592395e9cSLionel Sambuc static size_t
locale_width(const struct termp * p,int c)25692395e9cSLionel Sambuc locale_width(const struct termp *p, int c)
25792395e9cSLionel Sambuc {
25892395e9cSLionel Sambuc int rc;
25992395e9cSLionel Sambuc
26092395e9cSLionel Sambuc return((rc = wcwidth(c)) < 0 ? 0 : rc);
26192395e9cSLionel Sambuc }
26292395e9cSLionel Sambuc
26392395e9cSLionel Sambuc /* ARGSUSED */
26492395e9cSLionel Sambuc static void
locale_advance(struct termp * p,size_t len)26592395e9cSLionel Sambuc locale_advance(struct termp *p, size_t len)
26692395e9cSLionel Sambuc {
26792395e9cSLionel Sambuc size_t i;
26892395e9cSLionel Sambuc
26992395e9cSLionel Sambuc for (i = 0; i < len; i++)
27092395e9cSLionel Sambuc putwchar(L' ');
27192395e9cSLionel Sambuc }
27292395e9cSLionel Sambuc
27392395e9cSLionel Sambuc /* ARGSUSED */
27492395e9cSLionel Sambuc static void
locale_endline(struct termp * p)27592395e9cSLionel Sambuc locale_endline(struct termp *p)
27692395e9cSLionel Sambuc {
27792395e9cSLionel Sambuc
27892395e9cSLionel Sambuc putwchar(L'\n');
27992395e9cSLionel Sambuc }
28092395e9cSLionel Sambuc
28192395e9cSLionel Sambuc /* ARGSUSED */
28292395e9cSLionel Sambuc static void
locale_letter(struct termp * p,int c)28392395e9cSLionel Sambuc locale_letter(struct termp *p, int c)
28492395e9cSLionel Sambuc {
28592395e9cSLionel Sambuc
28692395e9cSLionel Sambuc putwchar(c);
28792395e9cSLionel Sambuc }
28892395e9cSLionel Sambuc #endif
289