xref: /netbsd-src/external/bsd/mdocml/dist/term_ascii.c (revision 6167eca2d062f3691f8b22e3b8ea212d6dde852a)
1*6167eca2Schristos /*	Id: term_ascii.c,v 1.64 2018/11/28 14:23:06 schwarze Exp  */
26c26a9aaSjoerg /*
3c5f73b34Sjoerg  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
414e7489eSchristos  * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
56c26a9aaSjoerg  *
66c26a9aaSjoerg  * Permission to use, copy, modify, and distribute this software for any
76c26a9aaSjoerg  * purpose with or without fee is hereby granted, provided that the above
86c26a9aaSjoerg  * copyright notice and this permission notice appear in all copies.
96c26a9aaSjoerg  *
109ff1f2acSchristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
116c26a9aaSjoerg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
129ff1f2acSchristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
136c26a9aaSjoerg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
146c26a9aaSjoerg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
156c26a9aaSjoerg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
166c26a9aaSjoerg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176c26a9aaSjoerg  */
186c26a9aaSjoerg #include "config.h"
196c26a9aaSjoerg 
206c26a9aaSjoerg #include <sys/types.h>
216c26a9aaSjoerg 
226c26a9aaSjoerg #include <assert.h>
23fec65c98Schristos #if HAVE_WCHAR
24e207fad0Snakayama #include <langinfo.h>
25c5f73b34Sjoerg #include <locale.h>
26c5f73b34Sjoerg #endif
276c26a9aaSjoerg #include <stdint.h>
286c26a9aaSjoerg #include <stdio.h>
296c26a9aaSjoerg #include <stdlib.h>
30e207fad0Snakayama #include <string.h>
316c26a9aaSjoerg #include <unistd.h>
32fec65c98Schristos #if HAVE_WCHAR
33c5f73b34Sjoerg #include <wchar.h>
34c5f73b34Sjoerg #endif
356c26a9aaSjoerg 
36c0d9444aSjoerg #include "mandoc.h"
37fec65c98Schristos #include "mandoc_aux.h"
386c26a9aaSjoerg #include "out.h"
396c26a9aaSjoerg #include "term.h"
409ff1f2acSchristos #include "manconf.h"
416c26a9aaSjoerg #include "main.h"
426c26a9aaSjoerg 
439ff1f2acSchristos static	struct termp	 *ascii_init(enum termenc, const struct manoutput *);
449ff1f2acSchristos static	int		  ascii_hspan(const struct termp *,
4582361f10Sjoerg 				const struct roffsu *);
46c5f73b34Sjoerg static	size_t		  ascii_width(const struct termp *, int);
4782361f10Sjoerg static	void		  ascii_advance(struct termp *, size_t);
4882361f10Sjoerg static	void		  ascii_begin(struct termp *);
4982361f10Sjoerg static	void		  ascii_end(struct termp *);
506c26a9aaSjoerg static	void		  ascii_endline(struct termp *);
51c5f73b34Sjoerg static	void		  ascii_letter(struct termp *, int);
529ff1f2acSchristos static	void		  ascii_setwidth(struct termp *, int, int);
536c26a9aaSjoerg 
54fec65c98Schristos #if HAVE_WCHAR
55c5f73b34Sjoerg static	void		  locale_advance(struct termp *, size_t);
56c5f73b34Sjoerg static	void		  locale_endline(struct termp *);
57c5f73b34Sjoerg static	void		  locale_letter(struct termp *, int);
58c5f73b34Sjoerg static	size_t		  locale_width(const struct termp *, int);
59c5f73b34Sjoerg #endif
606c26a9aaSjoerg 
61fec65c98Schristos 
62c5f73b34Sjoerg static struct termp *
ascii_init(enum termenc enc,const struct manoutput * outopts)639ff1f2acSchristos ascii_init(enum termenc enc, const struct manoutput *outopts)
646c26a9aaSjoerg {
659ff1f2acSchristos #if HAVE_WCHAR
666c26a9aaSjoerg 	char		*v;
679ff1f2acSchristos #endif
68c5f73b34Sjoerg 	struct termp	*p;
696c26a9aaSjoerg 
7014e7489eSchristos 	p = mandoc_calloc(1, sizeof(*p));
7114e7489eSchristos 	p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
7214e7489eSchristos 	p->maxtcol = 1;
736c26a9aaSjoerg 
749ff1f2acSchristos 	p->line = 1;
75fec65c98Schristos 	p->defrmargin = p->lastrmargin = 78;
76fec65c98Schristos 	p->fontq = mandoc_reallocarray(NULL,
7714e7489eSchristos 	     (p->fontsz = 8), sizeof(*p->fontq));
78fec65c98Schristos 	p->fontq[0] = p->fontl = TERMFONT_NONE;
7982361f10Sjoerg 
806c26a9aaSjoerg 	p->begin = ascii_begin;
816c26a9aaSjoerg 	p->end = ascii_end;
8282361f10Sjoerg 	p->hspan = ascii_hspan;
8382361f10Sjoerg 	p->type = TERMTYPE_CHAR;
84c5f73b34Sjoerg 
85c5f73b34Sjoerg 	p->enc = TERMENC_ASCII;
86c5f73b34Sjoerg 	p->advance = ascii_advance;
87c5f73b34Sjoerg 	p->endline = ascii_endline;
88c5f73b34Sjoerg 	p->letter = ascii_letter;
89fec65c98Schristos 	p->setwidth = ascii_setwidth;
9082361f10Sjoerg 	p->width = ascii_width;
916c26a9aaSjoerg 
92fec65c98Schristos #if HAVE_WCHAR
93*6167eca2Schristos 	if (enc != TERMENC_ASCII) {
949ff1f2acSchristos 
959ff1f2acSchristos 		/*
969ff1f2acSchristos 		 * Do not change any of this to LC_ALL.  It might break
979ff1f2acSchristos 		 * the formatting by subtly changing the behaviour of
989ff1f2acSchristos 		 * various functions, for example strftime(3).  As a
999ff1f2acSchristos 		 * worst case, it might even cause buffer overflows.
1009ff1f2acSchristos 		 */
1019ff1f2acSchristos 
102*6167eca2Schristos 		v = enc == TERMENC_LOCALE ?
1039ff1f2acSchristos 		    setlocale(LC_CTYPE, "") :
1049508192eSchristos 		    setlocale(LC_CTYPE, UTF8_LOCALE);
105e207fad0Snakayama 
106e207fad0Snakayama 		/*
107e207fad0Snakayama 		 * We only support UTF-8,
108e207fad0Snakayama 		 * so revert to ASCII for anything else.
109e207fad0Snakayama 		 */
110e207fad0Snakayama 
111e207fad0Snakayama 		if (v != NULL &&
112e207fad0Snakayama 		    strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
113e207fad0Snakayama 			v = setlocale(LC_CTYPE, "C");
114e207fad0Snakayama 
115e207fad0Snakayama 		if (v != NULL && MB_CUR_MAX > 1) {
116*6167eca2Schristos 			p->enc = TERMENC_UTF8;
117c5f73b34Sjoerg 			p->advance = locale_advance;
118c5f73b34Sjoerg 			p->endline = locale_endline;
119c5f73b34Sjoerg 			p->letter = locale_letter;
120c5f73b34Sjoerg 			p->width = locale_width;
121c5f73b34Sjoerg 		}
122c5f73b34Sjoerg 	}
123c5f73b34Sjoerg #endif
124c5f73b34Sjoerg 
1259ff1f2acSchristos 	if (outopts->mdoc) {
126cf816816Sjoerg 		p->mdocstyle = 1;
127cf816816Sjoerg 		p->defindent = 5;
1289ff1f2acSchristos 	}
1299ff1f2acSchristos 	if (outopts->indent)
1309ff1f2acSchristos 		p->defindent = outopts->indent;
1319ff1f2acSchristos 	if (outopts->width)
1329ff1f2acSchristos 		p->defrmargin = outopts->width;
1339ff1f2acSchristos 	if (outopts->synopsisonly)
134fec65c98Schristos 		p->synopsisonly = 1;
1356c26a9aaSjoerg 
13614e7489eSchristos 	assert(p->defindent < UINT16_MAX);
13714e7489eSchristos 	assert(p->defrmargin < UINT16_MAX);
1389ff1f2acSchristos 	return p;
1396c26a9aaSjoerg }
1406c26a9aaSjoerg 
141c5f73b34Sjoerg void *
ascii_alloc(const struct manoutput * outopts)1429ff1f2acSchristos ascii_alloc(const struct manoutput *outopts)
143c5f73b34Sjoerg {
144c5f73b34Sjoerg 
1459ff1f2acSchristos 	return ascii_init(TERMENC_ASCII, outopts);
146c5f73b34Sjoerg }
147c5f73b34Sjoerg 
148c5f73b34Sjoerg void *
utf8_alloc(const struct manoutput * outopts)1499ff1f2acSchristos utf8_alloc(const struct manoutput *outopts)
150c5f73b34Sjoerg {
151c5f73b34Sjoerg 
1529ff1f2acSchristos 	return ascii_init(TERMENC_UTF8, outopts);
153c5f73b34Sjoerg }
154c5f73b34Sjoerg 
155c5f73b34Sjoerg void *
locale_alloc(const struct manoutput * outopts)1569ff1f2acSchristos locale_alloc(const struct manoutput *outopts)
157c5f73b34Sjoerg {
158c5f73b34Sjoerg 
1599ff1f2acSchristos 	return ascii_init(TERMENC_LOCALE, outopts);
160c5f73b34Sjoerg }
1616c26a9aaSjoerg 
162fec65c98Schristos static void
ascii_setwidth(struct termp * p,int iop,int width)1639ff1f2acSchristos ascii_setwidth(struct termp *p, int iop, int width)
164fec65c98Schristos {
165fec65c98Schristos 
1669ff1f2acSchristos 	width /= 24;
16714e7489eSchristos 	p->tcol->rmargin = p->defrmargin;
168fec65c98Schristos 	if (iop > 0)
169fec65c98Schristos 		p->defrmargin += width;
170fec65c98Schristos 	else if (iop == 0)
1719ff1f2acSchristos 		p->defrmargin = width ? (size_t)width : p->lastrmargin;
1729ff1f2acSchristos 	else if (p->defrmargin > (size_t)width)
173fec65c98Schristos 		p->defrmargin -= width;
174fec65c98Schristos 	else
175fec65c98Schristos 		p->defrmargin = 0;
17614e7489eSchristos 	if (p->defrmargin > 1000)
17714e7489eSchristos 		p->defrmargin = 1000;
17814e7489eSchristos 	p->lastrmargin = p->tcol->rmargin;
17914e7489eSchristos 	p->tcol->rmargin = p->maxrmargin = p->defrmargin;
180fec65c98Schristos }
181fec65c98Schristos 
182fec65c98Schristos void
terminal_sepline(void * arg)1839ff1f2acSchristos terminal_sepline(void *arg)
184fec65c98Schristos {
185fec65c98Schristos 	struct termp	*p;
186fec65c98Schristos 	size_t		 i;
187fec65c98Schristos 
188fec65c98Schristos 	p = (struct termp *)arg;
1899ff1f2acSchristos 	(*p->endline)(p);
190fec65c98Schristos 	for (i = 0; i < p->defrmargin; i++)
1919ff1f2acSchristos 		(*p->letter)(p, '-');
1929ff1f2acSchristos 	(*p->endline)(p);
1939ff1f2acSchristos 	(*p->endline)(p);
194fec65c98Schristos }
195fec65c98Schristos 
19682361f10Sjoerg static size_t
ascii_width(const struct termp * p,int c)197c5f73b34Sjoerg ascii_width(const struct termp *p, int c)
19882361f10Sjoerg {
199*6167eca2Schristos 	return c != ASCII_BREAK;
20082361f10Sjoerg }
20182361f10Sjoerg 
2026c26a9aaSjoerg void
ascii_free(void * arg)2036c26a9aaSjoerg ascii_free(void *arg)
2046c26a9aaSjoerg {
2056c26a9aaSjoerg 
2066c26a9aaSjoerg 	term_free((struct termp *)arg);
2076c26a9aaSjoerg }
2086c26a9aaSjoerg 
2096c26a9aaSjoerg static void
ascii_letter(struct termp * p,int c)210c5f73b34Sjoerg ascii_letter(struct termp *p, int c)
2116c26a9aaSjoerg {
2126c26a9aaSjoerg 
2136c26a9aaSjoerg 	putchar(c);
2146c26a9aaSjoerg }
2156c26a9aaSjoerg 
2166c26a9aaSjoerg static void
ascii_begin(struct termp * p)2176c26a9aaSjoerg ascii_begin(struct termp *p)
2186c26a9aaSjoerg {
2196c26a9aaSjoerg 
2206c26a9aaSjoerg 	(*p->headf)(p, p->argf);
2216c26a9aaSjoerg }
2226c26a9aaSjoerg 
2236c26a9aaSjoerg static void
ascii_end(struct termp * p)2246c26a9aaSjoerg ascii_end(struct termp *p)
2256c26a9aaSjoerg {
2266c26a9aaSjoerg 
2276c26a9aaSjoerg 	(*p->footf)(p, p->argf);
2286c26a9aaSjoerg }
2296c26a9aaSjoerg 
2306c26a9aaSjoerg static void
ascii_endline(struct termp * p)2316c26a9aaSjoerg ascii_endline(struct termp *p)
2326c26a9aaSjoerg {
2336c26a9aaSjoerg 
2349ff1f2acSchristos 	p->line++;
23514e7489eSchristos 	p->tcol->offset -= p->ti;
23614e7489eSchristos 	p->ti = 0;
2376c26a9aaSjoerg 	putchar('\n');
2386c26a9aaSjoerg }
2396c26a9aaSjoerg 
2406c26a9aaSjoerg static void
ascii_advance(struct termp * p,size_t len)2416c26a9aaSjoerg ascii_advance(struct termp *p, size_t len)
2426c26a9aaSjoerg {
2436c26a9aaSjoerg 	size_t		i;
2446c26a9aaSjoerg 
24514e7489eSchristos 	assert(len < UINT16_MAX);
2466c26a9aaSjoerg 	for (i = 0; i < len; i++)
2476c26a9aaSjoerg 		putchar(' ');
2486c26a9aaSjoerg }
24982361f10Sjoerg 
2509ff1f2acSchristos static int
ascii_hspan(const struct termp * p,const struct roffsu * su)25182361f10Sjoerg ascii_hspan(const struct termp *p, const struct roffsu *su)
25282361f10Sjoerg {
25382361f10Sjoerg 	double		 r;
25482361f10Sjoerg 
25582361f10Sjoerg 	switch (su->unit) {
256fec65c98Schristos 	case SCALE_BU:
2579ff1f2acSchristos 		r = su->scale;
25882361f10Sjoerg 		break;
259fec65c98Schristos 	case SCALE_CM:
2609ff1f2acSchristos 		r = su->scale * 240.0 / 2.54;
26182361f10Sjoerg 		break;
262fec65c98Schristos 	case SCALE_FS:
2639ff1f2acSchristos 		r = su->scale * 65536.0;
26482361f10Sjoerg 		break;
265fec65c98Schristos 	case SCALE_IN:
2669ff1f2acSchristos 		r = su->scale * 240.0;
26782361f10Sjoerg 		break;
268fec65c98Schristos 	case SCALE_MM:
2699ff1f2acSchristos 		r = su->scale * 0.24;
270fec65c98Schristos 		break;
271fec65c98Schristos 	case SCALE_VS:
2729ff1f2acSchristos 	case SCALE_PC:
2739ff1f2acSchristos 		r = su->scale * 40.0;
2749ff1f2acSchristos 		break;
2759ff1f2acSchristos 	case SCALE_PT:
2769ff1f2acSchristos 		r = su->scale * 10.0 / 3.0;
277fec65c98Schristos 		break;
278fec65c98Schristos 	case SCALE_EN:
279fec65c98Schristos 	case SCALE_EM:
2809ff1f2acSchristos 		r = su->scale * 24.0;
28182361f10Sjoerg 		break;
282fec65c98Schristos 	default:
283fec65c98Schristos 		abort();
28482361f10Sjoerg 	}
2859ff1f2acSchristos 	return r > 0.0 ? r + 0.01 : r - 0.01;
28682361f10Sjoerg }
28782361f10Sjoerg 
288fec65c98Schristos const char *
ascii_uc2str(int uc)289fec65c98Schristos ascii_uc2str(int uc)
290fec65c98Schristos {
291fec65c98Schristos 	static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
292fec65c98Schristos 	static const char *tab[] = {
293fec65c98Schristos 	"<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
294fec65c98Schristos 	"<BS>",	"\t",	"<LF>",	"<VT>",	"<FF>",	"<CR>",	"<SO>",	"<SI>",
295fec65c98Schristos 	"<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>",
296fec65c98Schristos 	"<CAN>","<EM>",	"<SUB>","<ESC>","<FS>",	"<GS>",	"<RS>",	"<US>",
297fec65c98Schristos 	" ",	"!",	"\"",	"#",	"$",	"%",	"&",	"'",
298fec65c98Schristos 	"(",	")",	"*",	"+",	",",	"-",	".",	"/",
299fec65c98Schristos 	"0",	"1",	"2",	"3",	"4",	"5",	"6",	"7",
300fec65c98Schristos 	"8",	"9",	":",	";",	"<",	"=",	">",	"?",
301fec65c98Schristos 	"@",	"A",	"B",	"C",	"D",	"E",	"F",	"G",
302fec65c98Schristos 	"H",	"I",	"J",	"K",	"L",	"M",	"N",	"O",
303fec65c98Schristos 	"P",	"Q",	"R",	"S",	"T",	"U",	"V",	"W",
304fec65c98Schristos 	"X",	"Y",	"Z",	"[",	"\\",	"]",	"^",	"_",
305fec65c98Schristos 	"`",	"a",	"b",	"c",	"d",	"e",	"f",	"g",
306fec65c98Schristos 	"h",	"i",	"j",	"k",	"l",	"m",	"n",	"o",
307fec65c98Schristos 	"p",	"q",	"r",	"s",	"t",	"u",	"v",	"w",
308fec65c98Schristos 	"x",	"y",	"z",	"{",	"|",	"}",	"~",	"<DEL>",
309fec65c98Schristos 	"<80>",	"<81>",	"<82>",	"<83>",	"<84>",	"<85>",	"<86>",	"<87>",
310fec65c98Schristos 	"<88>",	"<89>",	"<8A>",	"<8B>",	"<8C>",	"<8D>",	"<8E>",	"<8F>",
311fec65c98Schristos 	"<90>",	"<91>",	"<92>",	"<93>",	"<94>",	"<95>",	"<96>",	"<97>",
31214e7489eSchristos 	"<98>",	"<99>",	"<9A>",	"<9B>",	"<9C>",	"<9D>",	"<9E>",	"<9F>",
313*6167eca2Schristos 	nbrsp,	"!",	"/\bc",	"-\bL",	"o\bx",	"=\bY",	"|",	"<section>",
314fec65c98Schristos 	"\"",	"(C)",	"_\ba",	"<<",	"~",	"",	"(R)",	"-",
31514e7489eSchristos 	"<degree>","+-","^2",	"^3",	"'","<micro>","<paragraph>",".",
31614e7489eSchristos 	",",	"^1",	"_\bo",	">>",	"1/4",	"1/2",	"3/4",	"?",
317fec65c98Schristos 	"`\bA",	"'\bA",	"^\bA",	"~\bA",	"\"\bA","o\bA",	"AE",	",\bC",
318fec65c98Schristos 	"`\bE",	"'\bE",	"^\bE",	"\"\bE","`\bI",	"'\bI",	"^\bI",	"\"\bI",
31914e7489eSchristos 	"Dh",	"~\bN",	"`\bO",	"'\bO",	"^\bO",	"~\bO",	"\"\bO","x",
320fec65c98Schristos 	"/\bO",	"`\bU",	"'\bU",	"^\bU",	"\"\bU","'\bY",	"Th",	"ss",
321fec65c98Schristos 	"`\ba",	"'\ba",	"^\ba",	"~\ba",	"\"\ba","o\ba",	"ae",	",\bc",
322fec65c98Schristos 	"`\be",	"'\be",	"^\be",	"\"\be","`\bi",	"'\bi",	"^\bi",	"\"\bi",
32314e7489eSchristos 	"dh",	"~\bn",	"`\bo",	"'\bo",	"^\bo",	"~\bo",	"\"\bo","/",
324fec65c98Schristos 	"/\bo",	"`\bu",	"'\bu",	"^\bu",	"\"\bu","'\by",	"th",	"\"\by",
325fec65c98Schristos 	"A",	"a",	"A",	"a",	"A",	"a",	"'\bC",	"'\bc",
326fec65c98Schristos 	"^\bC",	"^\bc",	"C",	"c",	"C",	"c",	"D",	"d",
327fec65c98Schristos 	"/\bD",	"/\bd",	"E",	"e",	"E",	"e",	"E",	"e",
328fec65c98Schristos 	"E",	"e",	"E",	"e",	"^\bG",	"^\bg",	"G",	"g",
329fec65c98Schristos 	"G",	"g",	",\bG",	",\bg",	"^\bH",	"^\bh",	"/\bH",	"/\bh",
330fec65c98Schristos 	"~\bI",	"~\bi",	"I",	"i",	"I",	"i",	"I",	"i",
331fec65c98Schristos 	"I",	"i",	"IJ",	"ij",	"^\bJ",	"^\bj",	",\bK",	",\bk",
332fec65c98Schristos 	"q",	"'\bL",	"'\bl",	",\bL",	",\bl",	"L",	"l",	"L",
333fec65c98Schristos 	"l",	"/\bL",	"/\bl",	"'\bN",	"'\bn",	",\bN",	",\bn",	"N",
334fec65c98Schristos 	"n",	"'n",	"Ng",	"ng",	"O",	"o",	"O",	"o",
335fec65c98Schristos 	"O",	"o",	"OE",	"oe",	"'\bR",	"'\br",	",\bR",	",\br",
336fec65c98Schristos 	"R",	"r",	"'\bS",	"'\bs",	"^\bS",	"^\bs",	",\bS",	",\bs",
337fec65c98Schristos 	"S",	"s",	",\bT",	",\bt",	"T",	"t",	"/\bT",	"/\bt",
338fec65c98Schristos 	"~\bU",	"~\bu",	"U",	"u",	"U",	"u",	"U",	"u",
339fec65c98Schristos 	"U",	"u",	"U",	"u",	"^\bW",	"^\bw",	"^\bY",	"^\by",
340fec65c98Schristos 	"\"\bY","'\bZ",	"'\bz",	"Z",	"z",	"Z",	"z",	"s",
341fec65c98Schristos 	"b",	"B",	"B",	"b",	"6",	"6",	"O",	"C",
342fec65c98Schristos 	"c",	"D",	"D",	"D",	"d",	"d",	"3",	"@",
343fec65c98Schristos 	"E",	"F",	",\bf",	"G",	"G",	"hv",	"I",	"/\bI",
344fec65c98Schristos 	"K",	"k",	"/\bl",	"l",	"W",	"N",	"n",	"~\bO",
345fec65c98Schristos 	"O",	"o",	"OI",	"oi",	"P",	"p",	"YR",	"2",
346fec65c98Schristos 	"2",	"SH",	"sh",	"t",	"T",	"t",	"T",	"U",
347fec65c98Schristos 	"u",	"Y",	"V",	"Y",	"y",	"/\bZ",	"/\bz",	"ZH",
348fec65c98Schristos 	"ZH",	"zh",	"zh",	"/\b2",	"5",	"5",	"ts",	"w",
349fec65c98Schristos 	"|",	"||",	"|=",	"!",	"DZ",	"Dz",	"dz",	"LJ",
350fec65c98Schristos 	"Lj",	"lj",	"NJ",	"Nj",	"nj",	"A",	"a",	"I",
351fec65c98Schristos 	"i",	"O",	"o",	"U",	"u",	"U",	"u",	"U",
352fec65c98Schristos 	"u",	"U",	"u",	"U",	"u",	"@",	"A",	"a",
353fec65c98Schristos 	"A",	"a",	"AE",	"ae",	"/\bG",	"/\bg",	"G",	"g",
354fec65c98Schristos 	"K",	"k",	"O",	"o",	"O",	"o",	"ZH",	"zh",
355fec65c98Schristos 	"j",	"DZ",	"Dz",	"dz",	"'\bG",	"'\bg",	"HV",	"W",
356fec65c98Schristos 	"`\bN",	"`\bn",	"A",	"a",	"'\bAE","'\bae","O",	"o"};
357fec65c98Schristos 
358fec65c98Schristos 	assert(uc >= 0);
359fec65c98Schristos 	if ((size_t)uc < sizeof(tab)/sizeof(tab[0]))
3609ff1f2acSchristos 		return tab[uc];
3619ff1f2acSchristos 	return mchars_uc2str(uc);
362fec65c98Schristos }
363fec65c98Schristos 
364fec65c98Schristos #if HAVE_WCHAR
365c5f73b34Sjoerg static size_t
locale_width(const struct termp * p,int c)366c5f73b34Sjoerg locale_width(const struct termp *p, int c)
367c5f73b34Sjoerg {
368c5f73b34Sjoerg 	int		rc;
369c5f73b34Sjoerg 
370fec65c98Schristos 	if (c == ASCII_NBRSP)
371fec65c98Schristos 		c = ' ';
372fec65c98Schristos 	rc = wcwidth(c);
373fec65c98Schristos 	if (rc < 0)
374fec65c98Schristos 		rc = 0;
3759ff1f2acSchristos 	return rc;
376c5f73b34Sjoerg }
377c5f73b34Sjoerg 
378c5f73b34Sjoerg static void
locale_advance(struct termp * p,size_t len)379c5f73b34Sjoerg locale_advance(struct termp *p, size_t len)
380c5f73b34Sjoerg {
381c5f73b34Sjoerg 	size_t		i;
382c5f73b34Sjoerg 
38314e7489eSchristos 	assert(len < UINT16_MAX);
384c5f73b34Sjoerg 	for (i = 0; i < len; i++)
385c5f73b34Sjoerg 		putwchar(L' ');
386c5f73b34Sjoerg }
387c5f73b34Sjoerg 
388c5f73b34Sjoerg static void
locale_endline(struct termp * p)389c5f73b34Sjoerg locale_endline(struct termp *p)
390c5f73b34Sjoerg {
391c5f73b34Sjoerg 
3929ff1f2acSchristos 	p->line++;
39314e7489eSchristos 	p->tcol->offset -= p->ti;
39414e7489eSchristos 	p->ti = 0;
395c5f73b34Sjoerg 	putwchar(L'\n');
396c5f73b34Sjoerg }
397c5f73b34Sjoerg 
398c5f73b34Sjoerg static void
locale_letter(struct termp * p,int c)399c5f73b34Sjoerg locale_letter(struct termp *p, int c)
400c5f73b34Sjoerg {
401c5f73b34Sjoerg 
402c5f73b34Sjoerg 	putwchar(c);
403c5f73b34Sjoerg }
404c5f73b34Sjoerg #endif
405