xref: /illumos-gate/usr/src/cmd/mandoc/term_ascii.c (revision 55fea89d)
14d131170SRobert Mustacchi /* $Id: term_ascii.c,v 1.66 2020/09/09 13:45:05 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
44d131170SRobert Mustacchi  * Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore  *
695c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore  *
10371584c2SYuri Pankov  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1195c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12371584c2SYuri Pankov  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1395c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore  */
1895c635efSGarrett D'Amore #include "config.h"
1995c635efSGarrett D'Amore 
2095c635efSGarrett D'Amore #include <sys/types.h>
2195c635efSGarrett D'Amore 
2295c635efSGarrett D'Amore #include <assert.h>
23260e9a87SYuri Pankov #if HAVE_WCHAR
246640c13bSYuri Pankov #include <langinfo.h>
25260e9a87SYuri Pankov #include <locale.h>
2695c635efSGarrett D'Amore #endif
2795c635efSGarrett D'Amore #include <stdint.h>
2895c635efSGarrett D'Amore #include <stdio.h>
2995c635efSGarrett D'Amore #include <stdlib.h>
306640c13bSYuri Pankov #include <string.h>
3195c635efSGarrett D'Amore #include <unistd.h>
32260e9a87SYuri Pankov #if HAVE_WCHAR
33260e9a87SYuri Pankov #include <wchar.h>
3495c635efSGarrett D'Amore #endif
3595c635efSGarrett D'Amore 
3695c635efSGarrett D'Amore #include "mandoc.h"
37260e9a87SYuri Pankov #include "mandoc_aux.h"
3895c635efSGarrett D'Amore #include "out.h"
3995c635efSGarrett D'Amore #include "term.h"
40371584c2SYuri Pankov #include "manconf.h"
4195c635efSGarrett D'Amore #include "main.h"
4295c635efSGarrett D'Amore 
43371584c2SYuri Pankov static	struct termp	 *ascii_init(enum termenc, const struct manoutput *);
44371584c2SYuri Pankov static	int		  ascii_hspan(const struct termp *,
4595c635efSGarrett D'Amore 				const struct roffsu *);
4695c635efSGarrett D'Amore static	size_t		  ascii_width(const struct termp *, int);
4795c635efSGarrett D'Amore static	void		  ascii_advance(struct termp *, size_t);
4895c635efSGarrett D'Amore static	void		  ascii_begin(struct termp *);
4995c635efSGarrett D'Amore static	void		  ascii_end(struct termp *);
5095c635efSGarrett D'Amore static	void		  ascii_endline(struct termp *);
5195c635efSGarrett D'Amore static	void		  ascii_letter(struct termp *, int);
52371584c2SYuri Pankov static	void		  ascii_setwidth(struct termp *, int, int);
5395c635efSGarrett D'Amore 
54260e9a87SYuri Pankov #if HAVE_WCHAR
5595c635efSGarrett D'Amore static	void		  locale_advance(struct termp *, size_t);
5695c635efSGarrett D'Amore static	void		  locale_endline(struct termp *);
5795c635efSGarrett D'Amore static	void		  locale_letter(struct termp *, int);
5895c635efSGarrett D'Amore static	size_t		  locale_width(const struct termp *, int);
5995c635efSGarrett D'Amore #endif
6095c635efSGarrett D'Amore 
61260e9a87SYuri Pankov 
6295c635efSGarrett D'Amore static struct termp *
ascii_init(enum termenc enc,const struct manoutput * outopts)63371584c2SYuri Pankov ascii_init(enum termenc enc, const struct manoutput *outopts)
6495c635efSGarrett D'Amore {
65371584c2SYuri Pankov #if HAVE_WCHAR
6695c635efSGarrett D'Amore 	char		*v;
67371584c2SYuri Pankov #endif
6895c635efSGarrett D'Amore 	struct termp	*p;
6995c635efSGarrett D'Amore 
70c66b8046SYuri Pankov 	p = mandoc_calloc(1, sizeof(*p));
71c66b8046SYuri Pankov 	p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
72c66b8046SYuri Pankov 	p->maxtcol = 1;
7395c635efSGarrett D'Amore 
74371584c2SYuri Pankov 	p->line = 1;
75260e9a87SYuri Pankov 	p->defrmargin = p->lastrmargin = 78;
76260e9a87SYuri Pankov 	p->fontq = mandoc_reallocarray(NULL,
77c66b8046SYuri Pankov 	     (p->fontsz = 8), sizeof(*p->fontq));
78260e9a87SYuri Pankov 	p->fontq[0] = p->fontl = TERMFONT_NONE;
7995c635efSGarrett D'Amore 
8095c635efSGarrett D'Amore 	p->begin = ascii_begin;
8195c635efSGarrett D'Amore 	p->end = ascii_end;
8295c635efSGarrett D'Amore 	p->hspan = ascii_hspan;
8395c635efSGarrett D'Amore 	p->type = TERMTYPE_CHAR;
8495c635efSGarrett D'Amore 
8595c635efSGarrett D'Amore 	p->enc = TERMENC_ASCII;
8695c635efSGarrett D'Amore 	p->advance = ascii_advance;
8795c635efSGarrett D'Amore 	p->endline = ascii_endline;
8895c635efSGarrett D'Amore 	p->letter = ascii_letter;
89260e9a87SYuri Pankov 	p->setwidth = ascii_setwidth;
9095c635efSGarrett D'Amore 	p->width = ascii_width;
9195c635efSGarrett D'Amore 
92260e9a87SYuri Pankov #if HAVE_WCHAR
93cec8643bSMichal Nowak 	if (enc != TERMENC_ASCII) {
94371584c2SYuri Pankov 
95371584c2SYuri Pankov 		/*
96371584c2SYuri Pankov 		 * Do not change any of this to LC_ALL.  It might break
97371584c2SYuri Pankov 		 * the formatting by subtly changing the behaviour of
98371584c2SYuri Pankov 		 * various functions, for example strftime(3).  As a
99371584c2SYuri Pankov 		 * worst case, it might even cause buffer overflows.
100371584c2SYuri Pankov 		 */
101371584c2SYuri Pankov 
102cec8643bSMichal Nowak 		v = enc == TERMENC_LOCALE ?
103371584c2SYuri Pankov 		    setlocale(LC_CTYPE, "") :
104a40ea1a7SYuri Pankov 		    setlocale(LC_CTYPE, UTF8_LOCALE);
1056640c13bSYuri Pankov 
1066640c13bSYuri Pankov 		/*
1076640c13bSYuri Pankov 		 * We only support UTF-8,
1086640c13bSYuri Pankov 		 * so revert to ASCII for anything else.
1096640c13bSYuri Pankov 		 */
1106640c13bSYuri Pankov 
1116640c13bSYuri Pankov 		if (v != NULL &&
1126640c13bSYuri Pankov 		    strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
1136640c13bSYuri Pankov 			v = setlocale(LC_CTYPE, "C");
1146640c13bSYuri Pankov 
1156640c13bSYuri Pankov 		if (v != NULL && MB_CUR_MAX > 1) {
116cec8643bSMichal Nowak 			p->enc = TERMENC_UTF8;
11795c635efSGarrett D'Amore 			p->advance = locale_advance;
11895c635efSGarrett D'Amore 			p->endline = locale_endline;
11995c635efSGarrett D'Amore 			p->letter = locale_letter;
12095c635efSGarrett D'Amore 			p->width = locale_width;
12195c635efSGarrett D'Amore 		}
12295c635efSGarrett D'Amore 	}
12395c635efSGarrett D'Amore #endif
12495c635efSGarrett D'Amore 
125371584c2SYuri Pankov 	if (outopts->mdoc) {
126371584c2SYuri Pankov 		p->mdocstyle = 1;
127371584c2SYuri Pankov 		p->defindent = 5;
128371584c2SYuri Pankov 	}
129371584c2SYuri Pankov 	if (outopts->indent)
130371584c2SYuri Pankov 		p->defindent = outopts->indent;
131371584c2SYuri Pankov 	if (outopts->width)
132371584c2SYuri Pankov 		p->defrmargin = outopts->width;
133371584c2SYuri Pankov 	if (outopts->synopsisonly)
134371584c2SYuri Pankov 		p->synopsisonly = 1;
135371584c2SYuri Pankov 
1366640c13bSYuri Pankov 	assert(p->defindent < UINT16_MAX);
1376640c13bSYuri Pankov 	assert(p->defrmargin < UINT16_MAX);
138371584c2SYuri Pankov 	return p;
13995c635efSGarrett D'Amore }
14095c635efSGarrett D'Amore 
14195c635efSGarrett D'Amore void *
ascii_alloc(const struct manoutput * outopts)142371584c2SYuri Pankov ascii_alloc(const struct manoutput *outopts)
14395c635efSGarrett D'Amore {
14495c635efSGarrett D'Amore 
145371584c2SYuri Pankov 	return ascii_init(TERMENC_ASCII, outopts);
14695c635efSGarrett D'Amore }
14795c635efSGarrett D'Amore 
14895c635efSGarrett D'Amore void *
utf8_alloc(const struct manoutput * outopts)149371584c2SYuri Pankov utf8_alloc(const struct manoutput *outopts)
15095c635efSGarrett D'Amore {
15195c635efSGarrett D'Amore 
152371584c2SYuri Pankov 	return ascii_init(TERMENC_UTF8, outopts);
15395c635efSGarrett D'Amore }
15495c635efSGarrett D'Amore 
15595c635efSGarrett D'Amore void *
locale_alloc(const struct manoutput * outopts)156371584c2SYuri Pankov locale_alloc(const struct manoutput *outopts)
157260e9a87SYuri Pankov {
158260e9a87SYuri Pankov 
159371584c2SYuri Pankov 	return ascii_init(TERMENC_LOCALE, outopts);
160260e9a87SYuri Pankov }
161260e9a87SYuri Pankov 
162260e9a87SYuri Pankov static void
ascii_setwidth(struct termp * p,int iop,int width)163371584c2SYuri Pankov ascii_setwidth(struct termp *p, int iop, int width)
164260e9a87SYuri Pankov {
165260e9a87SYuri Pankov 
166371584c2SYuri Pankov 	width /= 24;
167c66b8046SYuri Pankov 	p->tcol->rmargin = p->defrmargin;
168260e9a87SYuri Pankov 	if (iop > 0)
169260e9a87SYuri Pankov 		p->defrmargin += width;
170260e9a87SYuri Pankov 	else if (iop == 0)
171371584c2SYuri Pankov 		p->defrmargin = width ? (size_t)width : p->lastrmargin;
172371584c2SYuri Pankov 	else if (p->defrmargin > (size_t)width)
173260e9a87SYuri Pankov 		p->defrmargin -= width;
174260e9a87SYuri Pankov 	else
175260e9a87SYuri Pankov 		p->defrmargin = 0;
1766640c13bSYuri Pankov 	if (p->defrmargin > 1000)
1776640c13bSYuri Pankov 		p->defrmargin = 1000;
178c66b8046SYuri Pankov 	p->lastrmargin = p->tcol->rmargin;
179c66b8046SYuri Pankov 	p->tcol->rmargin = p->maxrmargin = p->defrmargin;
180260e9a87SYuri Pankov }
181260e9a87SYuri Pankov 
182260e9a87SYuri Pankov void
terminal_sepline(void * arg)183371584c2SYuri Pankov terminal_sepline(void *arg)
18495c635efSGarrett D'Amore {
185260e9a87SYuri Pankov 	struct termp	*p;
186260e9a87SYuri Pankov 	size_t		 i;
18795c635efSGarrett D'Amore 
188260e9a87SYuri Pankov 	p = (struct termp *)arg;
189371584c2SYuri Pankov 	(*p->endline)(p);
190260e9a87SYuri Pankov 	for (i = 0; i < p->defrmargin; i++)
191371584c2SYuri Pankov 		(*p->letter)(p, '-');
192371584c2SYuri Pankov 	(*p->endline)(p);
193371584c2SYuri Pankov 	(*p->endline)(p);
19495c635efSGarrett D'Amore }
19595c635efSGarrett D'Amore 
19695c635efSGarrett D'Amore static size_t
ascii_width(const struct termp * p,int c)19795c635efSGarrett D'Amore ascii_width(const struct termp *p, int c)
19895c635efSGarrett D'Amore {
199cec8643bSMichal Nowak 	return c != ASCII_BREAK;
20095c635efSGarrett D'Amore }
20195c635efSGarrett D'Amore 
20295c635efSGarrett D'Amore void
ascii_free(void * arg)20395c635efSGarrett D'Amore ascii_free(void *arg)
20495c635efSGarrett D'Amore {
20595c635efSGarrett D'Amore 
20695c635efSGarrett D'Amore 	term_free((struct termp *)arg);
20795c635efSGarrett D'Amore }
20895c635efSGarrett D'Amore 
20995c635efSGarrett D'Amore static void
ascii_letter(struct termp * p,int c)21095c635efSGarrett D'Amore ascii_letter(struct termp *p, int c)
21195c635efSGarrett D'Amore {
212260e9a87SYuri Pankov 
21395c635efSGarrett D'Amore 	putchar(c);
21495c635efSGarrett D'Amore }
21595c635efSGarrett D'Amore 
21695c635efSGarrett D'Amore static void
ascii_begin(struct termp * p)21795c635efSGarrett D'Amore ascii_begin(struct termp *p)
21895c635efSGarrett D'Amore {
21995c635efSGarrett D'Amore 
22095c635efSGarrett D'Amore 	(*p->headf)(p, p->argf);
22195c635efSGarrett D'Amore }
22295c635efSGarrett D'Amore 
22395c635efSGarrett D'Amore static void
ascii_end(struct termp * p)22495c635efSGarrett D'Amore ascii_end(struct termp *p)
22595c635efSGarrett D'Amore {
22695c635efSGarrett D'Amore 
22795c635efSGarrett D'Amore 	(*p->footf)(p, p->argf);
22895c635efSGarrett D'Amore }
22995c635efSGarrett D'Amore 
23095c635efSGarrett D'Amore static void
ascii_endline(struct termp * p)23195c635efSGarrett D'Amore ascii_endline(struct termp *p)
23295c635efSGarrett D'Amore {
23395c635efSGarrett D'Amore 
234371584c2SYuri Pankov 	p->line++;
2354d131170SRobert Mustacchi 	if ((int)p->tcol->offset > p->ti)
2364d131170SRobert Mustacchi 		p->tcol->offset -= p->ti;
2374d131170SRobert Mustacchi 	else
2384d131170SRobert Mustacchi 		p->tcol->offset = 0;
239c66b8046SYuri Pankov 	p->ti = 0;
24095c635efSGarrett D'Amore 	putchar('\n');
24195c635efSGarrett D'Amore }
24295c635efSGarrett D'Amore 
24395c635efSGarrett D'Amore static void
ascii_advance(struct termp * p,size_t len)24495c635efSGarrett D'Amore ascii_advance(struct termp *p, size_t len)
24595c635efSGarrett D'Amore {
246260e9a87SYuri Pankov 	size_t		i;
24795c635efSGarrett D'Amore 
2484d131170SRobert Mustacchi 	/*
2494d131170SRobert Mustacchi 	 * XXX We used to have "assert(len < UINT16_MAX)" here.
2504d131170SRobert Mustacchi 	 * that is not quite right because the input document
2514d131170SRobert Mustacchi 	 * can trigger that by merely providing large input.
2524d131170SRobert Mustacchi 	 * For now, simply truncate.
2534d131170SRobert Mustacchi 	 */
2544d131170SRobert Mustacchi 	if (len > 256)
2554d131170SRobert Mustacchi 		len = 256;
25695c635efSGarrett D'Amore 	for (i = 0; i < len; i++)
25795c635efSGarrett D'Amore 		putchar(' ');
25895c635efSGarrett D'Amore }
25995c635efSGarrett D'Amore 
260371584c2SYuri Pankov static int
ascii_hspan(const struct termp * p,const struct roffsu * su)26195c635efSGarrett D'Amore ascii_hspan(const struct termp *p, const struct roffsu *su)
26295c635efSGarrett D'Amore {
26395c635efSGarrett D'Amore 	double		 r;
26495c635efSGarrett D'Amore 
26595c635efSGarrett D'Amore 	switch (su->unit) {
266260e9a87SYuri Pankov 	case SCALE_BU:
267371584c2SYuri Pankov 		r = su->scale;
26895c635efSGarrett D'Amore 		break;
269260e9a87SYuri Pankov 	case SCALE_CM:
270371584c2SYuri Pankov 		r = su->scale * 240.0 / 2.54;
27195c635efSGarrett D'Amore 		break;
272260e9a87SYuri Pankov 	case SCALE_FS:
273371584c2SYuri Pankov 		r = su->scale * 65536.0;
27495c635efSGarrett D'Amore 		break;
275260e9a87SYuri Pankov 	case SCALE_IN:
276371584c2SYuri Pankov 		r = su->scale * 240.0;
27795c635efSGarrett D'Amore 		break;
278260e9a87SYuri Pankov 	case SCALE_MM:
279371584c2SYuri Pankov 		r = su->scale * 0.24;
28095c635efSGarrett D'Amore 		break;
281371584c2SYuri Pankov 	case SCALE_VS:
282260e9a87SYuri Pankov 	case SCALE_PC:
283371584c2SYuri Pankov 		r = su->scale * 40.0;
28495c635efSGarrett D'Amore 		break;
285260e9a87SYuri Pankov 	case SCALE_PT:
286371584c2SYuri Pankov 		r = su->scale * 10.0 / 3.0;
287260e9a87SYuri Pankov 		break;
288260e9a87SYuri Pankov 	case SCALE_EN:
289260e9a87SYuri Pankov 	case SCALE_EM:
290371584c2SYuri Pankov 		r = su->scale * 24.0;
29195c635efSGarrett D'Amore 		break;
292260e9a87SYuri Pankov 	default:
293260e9a87SYuri Pankov 		abort();
29495c635efSGarrett D'Amore 	}
295371584c2SYuri Pankov 	return r > 0.0 ? r + 0.01 : r - 0.01;
29695c635efSGarrett D'Amore }
29795c635efSGarrett D'Amore 
298260e9a87SYuri Pankov const char *
ascii_uc2str(int uc)299260e9a87SYuri Pankov ascii_uc2str(int uc)
300260e9a87SYuri Pankov {
301260e9a87SYuri Pankov 	static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
302260e9a87SYuri Pankov 	static const char *tab[] = {
303260e9a87SYuri Pankov 	"<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
304260e9a87SYuri Pankov 	"<BS>",	"\t",	"<LF>",	"<VT>",	"<FF>",	"<CR>",	"<SO>",	"<SI>",
305260e9a87SYuri Pankov 	"<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>",
306260e9a87SYuri Pankov 	"<CAN>","<EM>",	"<SUB>","<ESC>","<FS>",	"<GS>",	"<RS>",	"<US>",
307260e9a87SYuri Pankov 	" ",	"!",	"\"",	"#",	"$",	"%",	"&",	"'",
308260e9a87SYuri Pankov 	"(",	")",	"*",	"+",	",",	"-",	".",	"/",
309260e9a87SYuri Pankov 	"0",	"1",	"2",	"3",	"4",	"5",	"6",	"7",
310260e9a87SYuri Pankov 	"8",	"9",	":",	";",	"<",	"=",	">",	"?",
311260e9a87SYuri Pankov 	"@",	"A",	"B",	"C",	"D",	"E",	"F",	"G",
312260e9a87SYuri Pankov 	"H",	"I",	"J",	"K",	"L",	"M",	"N",	"O",
313260e9a87SYuri Pankov 	"P",	"Q",	"R",	"S",	"T",	"U",	"V",	"W",
314260e9a87SYuri Pankov 	"X",	"Y",	"Z",	"[",	"\\",	"]",	"^",	"_",
315260e9a87SYuri Pankov 	"`",	"a",	"b",	"c",	"d",	"e",	"f",	"g",
316260e9a87SYuri Pankov 	"h",	"i",	"j",	"k",	"l",	"m",	"n",	"o",
317260e9a87SYuri Pankov 	"p",	"q",	"r",	"s",	"t",	"u",	"v",	"w",
318260e9a87SYuri Pankov 	"x",	"y",	"z",	"{",	"|",	"}",	"~",	"<DEL>",
319260e9a87SYuri Pankov 	"<80>",	"<81>",	"<82>",	"<83>",	"<84>",	"<85>",	"<86>",	"<87>",
320260e9a87SYuri Pankov 	"<88>",	"<89>",	"<8A>",	"<8B>",	"<8C>",	"<8D>",	"<8E>",	"<8F>",
321260e9a87SYuri Pankov 	"<90>",	"<91>",	"<92>",	"<93>",	"<94>",	"<95>",	"<96>",	"<97>",
322c66b8046SYuri Pankov 	"<98>",	"<99>",	"<9A>",	"<9B>",	"<9C>",	"<9D>",	"<9E>",	"<9F>",
323cec8643bSMichal Nowak 	nbrsp,	"!",	"/\bc",	"-\bL",	"o\bx",	"=\bY",	"|",	"<section>",
324260e9a87SYuri Pankov 	"\"",	"(C)",	"_\ba",	"<<",	"~",	"",	"(R)",	"-",
3256640c13bSYuri Pankov 	"<degree>","+-","^2",	"^3",	"'","<micro>","<paragraph>",".",
3266640c13bSYuri Pankov 	",",	"^1",	"_\bo",	">>",	"1/4",	"1/2",	"3/4",	"?",
327260e9a87SYuri Pankov 	"`\bA",	"'\bA",	"^\bA",	"~\bA",	"\"\bA","o\bA",	"AE",	",\bC",
328260e9a87SYuri Pankov 	"`\bE",	"'\bE",	"^\bE",	"\"\bE","`\bI",	"'\bI",	"^\bI",	"\"\bI",
3296640c13bSYuri Pankov 	"Dh",	"~\bN",	"`\bO",	"'\bO",	"^\bO",	"~\bO",	"\"\bO","x",
330260e9a87SYuri Pankov 	"/\bO",	"`\bU",	"'\bU",	"^\bU",	"\"\bU","'\bY",	"Th",	"ss",
331260e9a87SYuri Pankov 	"`\ba",	"'\ba",	"^\ba",	"~\ba",	"\"\ba","o\ba",	"ae",	",\bc",
332260e9a87SYuri Pankov 	"`\be",	"'\be",	"^\be",	"\"\be","`\bi",	"'\bi",	"^\bi",	"\"\bi",
3336640c13bSYuri Pankov 	"dh",	"~\bn",	"`\bo",	"'\bo",	"^\bo",	"~\bo",	"\"\bo","/",
334260e9a87SYuri Pankov 	"/\bo",	"`\bu",	"'\bu",	"^\bu",	"\"\bu","'\by",	"th",	"\"\by",
335260e9a87SYuri Pankov 	"A",	"a",	"A",	"a",	"A",	"a",	"'\bC",	"'\bc",
336260e9a87SYuri Pankov 	"^\bC",	"^\bc",	"C",	"c",	"C",	"c",	"D",	"d",
337260e9a87SYuri Pankov 	"/\bD",	"/\bd",	"E",	"e",	"E",	"e",	"E",	"e",
338260e9a87SYuri Pankov 	"E",	"e",	"E",	"e",	"^\bG",	"^\bg",	"G",	"g",
339260e9a87SYuri Pankov 	"G",	"g",	",\bG",	",\bg",	"^\bH",	"^\bh",	"/\bH",	"/\bh",
340260e9a87SYuri Pankov 	"~\bI",	"~\bi",	"I",	"i",	"I",	"i",	"I",	"i",
341260e9a87SYuri Pankov 	"I",	"i",	"IJ",	"ij",	"^\bJ",	"^\bj",	",\bK",	",\bk",
342260e9a87SYuri Pankov 	"q",	"'\bL",	"'\bl",	",\bL",	",\bl",	"L",	"l",	"L",
343260e9a87SYuri Pankov 	"l",	"/\bL",	"/\bl",	"'\bN",	"'\bn",	",\bN",	",\bn",	"N",
344260e9a87SYuri Pankov 	"n",	"'n",	"Ng",	"ng",	"O",	"o",	"O",	"o",
345260e9a87SYuri Pankov 	"O",	"o",	"OE",	"oe",	"'\bR",	"'\br",	",\bR",	",\br",
346260e9a87SYuri Pankov 	"R",	"r",	"'\bS",	"'\bs",	"^\bS",	"^\bs",	",\bS",	",\bs",
347260e9a87SYuri Pankov 	"S",	"s",	",\bT",	",\bt",	"T",	"t",	"/\bT",	"/\bt",
348260e9a87SYuri Pankov 	"~\bU",	"~\bu",	"U",	"u",	"U",	"u",	"U",	"u",
349260e9a87SYuri Pankov 	"U",	"u",	"U",	"u",	"^\bW",	"^\bw",	"^\bY",	"^\by",
350260e9a87SYuri Pankov 	"\"\bY","'\bZ",	"'\bz",	"Z",	"z",	"Z",	"z",	"s",
351260e9a87SYuri Pankov 	"b",	"B",	"B",	"b",	"6",	"6",	"O",	"C",
352260e9a87SYuri Pankov 	"c",	"D",	"D",	"D",	"d",	"d",	"3",	"@",
353260e9a87SYuri Pankov 	"E",	"F",	",\bf",	"G",	"G",	"hv",	"I",	"/\bI",
354260e9a87SYuri Pankov 	"K",	"k",	"/\bl",	"l",	"W",	"N",	"n",	"~\bO",
355260e9a87SYuri Pankov 	"O",	"o",	"OI",	"oi",	"P",	"p",	"YR",	"2",
356260e9a87SYuri Pankov 	"2",	"SH",	"sh",	"t",	"T",	"t",	"T",	"U",
357260e9a87SYuri Pankov 	"u",	"Y",	"V",	"Y",	"y",	"/\bZ",	"/\bz",	"ZH",
358260e9a87SYuri Pankov 	"ZH",	"zh",	"zh",	"/\b2",	"5",	"5",	"ts",	"w",
359260e9a87SYuri Pankov 	"|",	"||",	"|=",	"!",	"DZ",	"Dz",	"dz",	"LJ",
360260e9a87SYuri Pankov 	"Lj",	"lj",	"NJ",	"Nj",	"nj",	"A",	"a",	"I",
361260e9a87SYuri Pankov 	"i",	"O",	"o",	"U",	"u",	"U",	"u",	"U",
362260e9a87SYuri Pankov 	"u",	"U",	"u",	"U",	"u",	"@",	"A",	"a",
363260e9a87SYuri Pankov 	"A",	"a",	"AE",	"ae",	"/\bG",	"/\bg",	"G",	"g",
364260e9a87SYuri Pankov 	"K",	"k",	"O",	"o",	"O",	"o",	"ZH",	"zh",
365260e9a87SYuri Pankov 	"j",	"DZ",	"Dz",	"dz",	"'\bG",	"'\bg",	"HV",	"W",
366260e9a87SYuri Pankov 	"`\bN",	"`\bn",	"A",	"a",	"'\bAE","'\bae","O",	"o"};
367260e9a87SYuri Pankov 
368260e9a87SYuri Pankov 	assert(uc >= 0);
369260e9a87SYuri Pankov 	if ((size_t)uc < sizeof(tab)/sizeof(tab[0]))
370371584c2SYuri Pankov 		return tab[uc];
371371584c2SYuri Pankov 	return mchars_uc2str(uc);
372260e9a87SYuri Pankov }
373260e9a87SYuri Pankov 
374260e9a87SYuri Pankov #if HAVE_WCHAR
37595c635efSGarrett D'Amore static size_t
locale_width(const struct termp * p,int c)37695c635efSGarrett D'Amore locale_width(const struct termp *p, int c)
37795c635efSGarrett D'Amore {
37895c635efSGarrett D'Amore 	int		rc;
37995c635efSGarrett D'Amore 
380260e9a87SYuri Pankov 	if (c == ASCII_NBRSP)
381260e9a87SYuri Pankov 		c = ' ';
382260e9a87SYuri Pankov 	rc = wcwidth(c);
383260e9a87SYuri Pankov 	if (rc < 0)
384260e9a87SYuri Pankov 		rc = 0;
385371584c2SYuri Pankov 	return rc;
38695c635efSGarrett D'Amore }
38795c635efSGarrett D'Amore 
38895c635efSGarrett D'Amore static void
locale_advance(struct termp * p,size_t len)38995c635efSGarrett D'Amore locale_advance(struct termp *p, size_t len)
39095c635efSGarrett D'Amore {
391260e9a87SYuri Pankov 	size_t		i;
39295c635efSGarrett D'Amore 
3934d131170SRobert Mustacchi 	/*
3944d131170SRobert Mustacchi 	 * XXX We used to have "assert(len < UINT16_MAX)" here.
3954d131170SRobert Mustacchi 	 * that is not quite right because the input document
3964d131170SRobert Mustacchi 	 * can trigger that by merely providing large input.
3974d131170SRobert Mustacchi 	 * For now, simply truncate.
3984d131170SRobert Mustacchi 	 */
3994d131170SRobert Mustacchi 	if (len > 256)
4004d131170SRobert Mustacchi 		len = 256;
40195c635efSGarrett D'Amore 	for (i = 0; i < len; i++)
40295c635efSGarrett D'Amore 		putwchar(L' ');
40395c635efSGarrett D'Amore }
40495c635efSGarrett D'Amore 
40595c635efSGarrett D'Amore static void
locale_endline(struct termp * p)40695c635efSGarrett D'Amore locale_endline(struct termp *p)
40795c635efSGarrett D'Amore {
40895c635efSGarrett D'Amore 
409371584c2SYuri Pankov 	p->line++;
4104d131170SRobert Mustacchi 	if ((int)p->tcol->offset > p->ti)
4114d131170SRobert Mustacchi 		p->tcol->offset -= p->ti;
412*55fea89dSDan Cross 	else
4134d131170SRobert Mustacchi 		p->tcol->offset = 0;
414c66b8046SYuri Pankov 	p->ti = 0;
41595c635efSGarrett D'Amore 	putwchar(L'\n');
41695c635efSGarrett D'Amore }
41795c635efSGarrett D'Amore 
41895c635efSGarrett D'Amore static void
locale_letter(struct termp * p,int c)41995c635efSGarrett D'Amore locale_letter(struct termp *p, int c)
42095c635efSGarrett D'Amore {
421260e9a87SYuri Pankov 
42295c635efSGarrett D'Amore 	putwchar(c);
42395c635efSGarrett D'Amore }
42495c635efSGarrett D'Amore #endif
425