1*99db7d0eSSascha Wildner /* $Id: term_ascii.c,v 1.66 2020/09/09 13:45:05 schwarze Exp $ */
280387638SSascha Wildner /*
336342e81SSascha Wildner * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*99db7d0eSSascha Wildner * Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
580387638SSascha Wildner *
680387638SSascha Wildner * Permission to use, copy, modify, and distribute this software for any
780387638SSascha Wildner * purpose with or without fee is hereby granted, provided that the above
880387638SSascha Wildner * copyright notice and this permission notice appear in all copies.
980387638SSascha Wildner *
1054ba9607SSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1180387638SSascha Wildner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1254ba9607SSascha Wildner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1380387638SSascha Wildner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1480387638SSascha Wildner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1580387638SSascha Wildner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1680387638SSascha Wildner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1780387638SSascha Wildner */
1880387638SSascha Wildner #include "config.h"
1980387638SSascha Wildner
2080387638SSascha Wildner #include <sys/types.h>
2180387638SSascha Wildner
2254ba9607SSascha Wildner #include <assert.h>
2354ba9607SSascha Wildner #if HAVE_WCHAR
2454ba9607SSascha Wildner #include <langinfo.h>
25a4c7eb57SSascha Wildner #include <locale.h>
26a4c7eb57SSascha Wildner #endif
2780387638SSascha Wildner #include <stdint.h>
2880387638SSascha Wildner #include <stdio.h>
2980387638SSascha Wildner #include <stdlib.h>
3054ba9607SSascha Wildner #include <string.h>
3180387638SSascha Wildner #include <unistd.h>
3254ba9607SSascha Wildner #if HAVE_WCHAR
33a4c7eb57SSascha Wildner #include <wchar.h>
34a4c7eb57SSascha Wildner #endif
3580387638SSascha Wildner
3680387638SSascha Wildner #include "mandoc.h"
37070c62a6SFranco Fichtner #include "mandoc_aux.h"
3880387638SSascha Wildner #include "out.h"
3980387638SSascha Wildner #include "term.h"
4054ba9607SSascha Wildner #include "manconf.h"
4180387638SSascha Wildner #include "main.h"
4280387638SSascha Wildner
4354ba9607SSascha Wildner static struct termp *ascii_init(enum termenc, const struct manoutput *);
4454ba9607SSascha Wildner static int ascii_hspan(const struct termp *,
4580387638SSascha Wildner const struct roffsu *);
46a4c7eb57SSascha Wildner static size_t ascii_width(const struct termp *, int);
4780387638SSascha Wildner static void ascii_advance(struct termp *, size_t);
4880387638SSascha Wildner static void ascii_begin(struct termp *);
4980387638SSascha Wildner static void ascii_end(struct termp *);
5080387638SSascha Wildner static void ascii_endline(struct termp *);
51a4c7eb57SSascha Wildner static void ascii_letter(struct termp *, int);
5254ba9607SSascha Wildner static void ascii_setwidth(struct termp *, int, int);
5380387638SSascha Wildner
5454ba9607SSascha Wildner #if HAVE_WCHAR
55a4c7eb57SSascha Wildner static void locale_advance(struct termp *, size_t);
56a4c7eb57SSascha Wildner static void locale_endline(struct termp *);
57a4c7eb57SSascha Wildner static void locale_letter(struct termp *, int);
58a4c7eb57SSascha Wildner static size_t locale_width(const struct termp *, int);
59a4c7eb57SSascha Wildner #endif
6080387638SSascha Wildner
61070c62a6SFranco Fichtner
62a4c7eb57SSascha Wildner static struct termp *
ascii_init(enum termenc enc,const struct manoutput * outopts)6354ba9607SSascha Wildner ascii_init(enum termenc enc, const struct manoutput *outopts)
6480387638SSascha Wildner {
6554ba9607SSascha Wildner #if HAVE_WCHAR
6680387638SSascha Wildner char *v;
6754ba9607SSascha Wildner #endif
68a4c7eb57SSascha Wildner struct termp *p;
6980387638SSascha Wildner
7054ba9607SSascha Wildner p = mandoc_calloc(1, sizeof(*p));
7154ba9607SSascha Wildner p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
7254ba9607SSascha Wildner p->maxtcol = 1;
7380387638SSascha Wildner
7454ba9607SSascha Wildner p->line = 1;
75070c62a6SFranco Fichtner p->defrmargin = p->lastrmargin = 78;
7654ba9607SSascha Wildner p->fontq = mandoc_reallocarray(NULL,
7754ba9607SSascha Wildner (p->fontsz = 8), sizeof(*p->fontq));
7854ba9607SSascha Wildner p->fontq[0] = p->fontl = TERMFONT_NONE;
7980387638SSascha Wildner
8080387638SSascha Wildner p->begin = ascii_begin;
8180387638SSascha Wildner p->end = ascii_end;
8280387638SSascha Wildner p->hspan = ascii_hspan;
8380387638SSascha Wildner p->type = TERMTYPE_CHAR;
84a4c7eb57SSascha Wildner
85a4c7eb57SSascha Wildner p->enc = TERMENC_ASCII;
86a4c7eb57SSascha Wildner p->advance = ascii_advance;
87a4c7eb57SSascha Wildner p->endline = ascii_endline;
88a4c7eb57SSascha Wildner p->letter = ascii_letter;
89070c62a6SFranco Fichtner p->setwidth = ascii_setwidth;
9080387638SSascha Wildner p->width = ascii_width;
9180387638SSascha Wildner
9254ba9607SSascha Wildner #if HAVE_WCHAR
9354ba9607SSascha Wildner if (enc != TERMENC_ASCII) {
9454ba9607SSascha Wildner
9554ba9607SSascha Wildner /*
9654ba9607SSascha Wildner * Do not change any of this to LC_ALL. It might break
9754ba9607SSascha Wildner * the formatting by subtly changing the behaviour of
9854ba9607SSascha Wildner * various functions, for example strftime(3). As a
9954ba9607SSascha Wildner * worst case, it might even cause buffer overflows.
10054ba9607SSascha Wildner */
10154ba9607SSascha Wildner
10254ba9607SSascha Wildner v = enc == TERMENC_LOCALE ?
10354ba9607SSascha Wildner setlocale(LC_CTYPE, "") :
10454ba9607SSascha Wildner setlocale(LC_CTYPE, UTF8_LOCALE);
10554ba9607SSascha Wildner
10654ba9607SSascha Wildner /*
10754ba9607SSascha Wildner * We only support UTF-8,
10854ba9607SSascha Wildner * so revert to ASCII for anything else.
10954ba9607SSascha Wildner */
11054ba9607SSascha Wildner
11154ba9607SSascha Wildner if (v != NULL &&
11254ba9607SSascha Wildner strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
11354ba9607SSascha Wildner v = setlocale(LC_CTYPE, "C");
11454ba9607SSascha Wildner
11554ba9607SSascha Wildner if (v != NULL && MB_CUR_MAX > 1) {
11654ba9607SSascha Wildner p->enc = TERMENC_UTF8;
117a4c7eb57SSascha Wildner p->advance = locale_advance;
118a4c7eb57SSascha Wildner p->endline = locale_endline;
119a4c7eb57SSascha Wildner p->letter = locale_letter;
120a4c7eb57SSascha Wildner p->width = locale_width;
121a4c7eb57SSascha Wildner }
122a4c7eb57SSascha Wildner }
123a4c7eb57SSascha Wildner #endif
124a4c7eb57SSascha Wildner
12554ba9607SSascha Wildner if (outopts->mdoc) {
12636342e81SSascha Wildner p->mdocstyle = 1;
12736342e81SSascha Wildner p->defindent = 5;
12880387638SSascha Wildner }
12954ba9607SSascha Wildner if (outopts->indent)
13054ba9607SSascha Wildner p->defindent = outopts->indent;
13154ba9607SSascha Wildner if (outopts->width)
13254ba9607SSascha Wildner p->defrmargin = outopts->width;
13354ba9607SSascha Wildner if (outopts->synopsisonly)
13454ba9607SSascha Wildner p->synopsisonly = 1;
13580387638SSascha Wildner
13654ba9607SSascha Wildner assert(p->defindent < UINT16_MAX);
13754ba9607SSascha Wildner assert(p->defrmargin < UINT16_MAX);
13854ba9607SSascha Wildner return p;
13980387638SSascha Wildner }
14080387638SSascha Wildner
141a4c7eb57SSascha Wildner void *
ascii_alloc(const struct manoutput * outopts)14254ba9607SSascha Wildner ascii_alloc(const struct manoutput *outopts)
143a4c7eb57SSascha Wildner {
144a4c7eb57SSascha Wildner
14554ba9607SSascha Wildner return ascii_init(TERMENC_ASCII, outopts);
146a4c7eb57SSascha Wildner }
147a4c7eb57SSascha Wildner
148a4c7eb57SSascha Wildner void *
utf8_alloc(const struct manoutput * outopts)14954ba9607SSascha Wildner utf8_alloc(const struct manoutput *outopts)
150a4c7eb57SSascha Wildner {
151a4c7eb57SSascha Wildner
15254ba9607SSascha Wildner return ascii_init(TERMENC_UTF8, outopts);
153a4c7eb57SSascha Wildner }
154a4c7eb57SSascha Wildner
155a4c7eb57SSascha Wildner void *
locale_alloc(const struct manoutput * outopts)15654ba9607SSascha Wildner locale_alloc(const struct manoutput *outopts)
157a4c7eb57SSascha Wildner {
158a4c7eb57SSascha Wildner
15954ba9607SSascha Wildner return ascii_init(TERMENC_LOCALE, outopts);
160a4c7eb57SSascha Wildner }
16180387638SSascha Wildner
162070c62a6SFranco Fichtner static void
ascii_setwidth(struct termp * p,int iop,int width)16354ba9607SSascha Wildner ascii_setwidth(struct termp *p, int iop, int width)
164070c62a6SFranco Fichtner {
165070c62a6SFranco Fichtner
16654ba9607SSascha Wildner width /= 24;
16754ba9607SSascha Wildner p->tcol->rmargin = p->defrmargin;
16854ba9607SSascha Wildner if (iop > 0)
169070c62a6SFranco Fichtner p->defrmargin += width;
17054ba9607SSascha Wildner else if (iop == 0)
17154ba9607SSascha Wildner p->defrmargin = width ? (size_t)width : p->lastrmargin;
17254ba9607SSascha Wildner else if (p->defrmargin > (size_t)width)
173070c62a6SFranco Fichtner p->defrmargin -= width;
174070c62a6SFranco Fichtner else
17554ba9607SSascha Wildner p->defrmargin = 0;
17654ba9607SSascha Wildner if (p->defrmargin > 1000)
17754ba9607SSascha Wildner p->defrmargin = 1000;
17854ba9607SSascha Wildner p->lastrmargin = p->tcol->rmargin;
17954ba9607SSascha Wildner p->tcol->rmargin = p->maxrmargin = p->defrmargin;
18054ba9607SSascha Wildner }
18154ba9607SSascha Wildner
18254ba9607SSascha Wildner void
terminal_sepline(void * arg)18354ba9607SSascha Wildner terminal_sepline(void *arg)
18454ba9607SSascha Wildner {
18554ba9607SSascha Wildner struct termp *p;
18654ba9607SSascha Wildner size_t i;
18754ba9607SSascha Wildner
18854ba9607SSascha Wildner p = (struct termp *)arg;
18954ba9607SSascha Wildner (*p->endline)(p);
19054ba9607SSascha Wildner for (i = 0; i < p->defrmargin; i++)
19154ba9607SSascha Wildner (*p->letter)(p, '-');
19254ba9607SSascha Wildner (*p->endline)(p);
19354ba9607SSascha Wildner (*p->endline)(p);
194070c62a6SFranco Fichtner }
195070c62a6SFranco Fichtner
19680387638SSascha Wildner static size_t
ascii_width(const struct termp * p,int c)197a4c7eb57SSascha Wildner ascii_width(const struct termp *p, int c)
19880387638SSascha Wildner {
19954ba9607SSascha Wildner return c != ASCII_BREAK;
20080387638SSascha Wildner }
20180387638SSascha Wildner
20280387638SSascha Wildner void
ascii_free(void * arg)20380387638SSascha Wildner ascii_free(void *arg)
20480387638SSascha Wildner {
20580387638SSascha Wildner
20680387638SSascha Wildner term_free((struct termp *)arg);
20780387638SSascha Wildner }
20880387638SSascha Wildner
20980387638SSascha Wildner static void
ascii_letter(struct termp * p,int c)210a4c7eb57SSascha Wildner ascii_letter(struct termp *p, int c)
21180387638SSascha Wildner {
21280387638SSascha Wildner
21380387638SSascha Wildner putchar(c);
21480387638SSascha Wildner }
21580387638SSascha Wildner
21680387638SSascha Wildner static void
ascii_begin(struct termp * p)21780387638SSascha Wildner ascii_begin(struct termp *p)
21880387638SSascha Wildner {
21980387638SSascha Wildner
22080387638SSascha Wildner (*p->headf)(p, p->argf);
22180387638SSascha Wildner }
22280387638SSascha Wildner
22380387638SSascha Wildner static void
ascii_end(struct termp * p)22480387638SSascha Wildner ascii_end(struct termp *p)
22580387638SSascha Wildner {
22680387638SSascha Wildner
22780387638SSascha Wildner (*p->footf)(p, p->argf);
22880387638SSascha Wildner }
22980387638SSascha Wildner
23080387638SSascha Wildner static void
ascii_endline(struct termp * p)23180387638SSascha Wildner ascii_endline(struct termp *p)
23280387638SSascha Wildner {
23380387638SSascha Wildner
23454ba9607SSascha Wildner p->line++;
235*99db7d0eSSascha Wildner if ((int)p->tcol->offset > p->ti)
23654ba9607SSascha Wildner p->tcol->offset -= p->ti;
237*99db7d0eSSascha Wildner else
238*99db7d0eSSascha Wildner p->tcol->offset = 0;
23954ba9607SSascha Wildner p->ti = 0;
24080387638SSascha Wildner putchar('\n');
24180387638SSascha Wildner }
24280387638SSascha Wildner
24380387638SSascha Wildner static void
ascii_advance(struct termp * p,size_t len)24480387638SSascha Wildner ascii_advance(struct termp *p, size_t len)
24580387638SSascha Wildner {
24680387638SSascha Wildner size_t i;
24780387638SSascha Wildner
248*99db7d0eSSascha Wildner /*
249*99db7d0eSSascha Wildner * XXX We used to have "assert(len < UINT16_MAX)" here.
250*99db7d0eSSascha Wildner * that is not quite right because the input document
251*99db7d0eSSascha Wildner * can trigger that by merely providing large input.
252*99db7d0eSSascha Wildner * For now, simply truncate.
253*99db7d0eSSascha Wildner */
254*99db7d0eSSascha Wildner if (len > 256)
255*99db7d0eSSascha Wildner len = 256;
25680387638SSascha Wildner for (i = 0; i < len; i++)
25780387638SSascha Wildner putchar(' ');
25880387638SSascha Wildner }
25980387638SSascha Wildner
26054ba9607SSascha Wildner static int
ascii_hspan(const struct termp * p,const struct roffsu * su)26180387638SSascha Wildner ascii_hspan(const struct termp *p, const struct roffsu *su)
26280387638SSascha Wildner {
26380387638SSascha Wildner double r;
26480387638SSascha Wildner
26580387638SSascha Wildner switch (su->unit) {
26654ba9607SSascha Wildner case SCALE_BU:
26780387638SSascha Wildner r = su->scale;
26880387638SSascha Wildner break;
26954ba9607SSascha Wildner case SCALE_CM:
27054ba9607SSascha Wildner r = su->scale * 240.0 / 2.54;
27154ba9607SSascha Wildner break;
27254ba9607SSascha Wildner case SCALE_FS:
27354ba9607SSascha Wildner r = su->scale * 65536.0;
27454ba9607SSascha Wildner break;
27554ba9607SSascha Wildner case SCALE_IN:
27654ba9607SSascha Wildner r = su->scale * 240.0;
27754ba9607SSascha Wildner break;
27854ba9607SSascha Wildner case SCALE_MM:
27954ba9607SSascha Wildner r = su->scale * 0.24;
28054ba9607SSascha Wildner break;
28154ba9607SSascha Wildner case SCALE_VS:
28254ba9607SSascha Wildner case SCALE_PC:
28354ba9607SSascha Wildner r = su->scale * 40.0;
28454ba9607SSascha Wildner break;
28554ba9607SSascha Wildner case SCALE_PT:
28654ba9607SSascha Wildner r = su->scale * 10.0 / 3.0;
28754ba9607SSascha Wildner break;
28854ba9607SSascha Wildner case SCALE_EN:
28954ba9607SSascha Wildner case SCALE_EM:
29054ba9607SSascha Wildner r = su->scale * 24.0;
29154ba9607SSascha Wildner break;
29254ba9607SSascha Wildner default:
29354ba9607SSascha Wildner abort();
29454ba9607SSascha Wildner }
29554ba9607SSascha Wildner return r > 0.0 ? r + 0.01 : r - 0.01;
29680387638SSascha Wildner }
29780387638SSascha Wildner
29854ba9607SSascha Wildner const char *
ascii_uc2str(int uc)29954ba9607SSascha Wildner ascii_uc2str(int uc)
30054ba9607SSascha Wildner {
30154ba9607SSascha Wildner static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
30254ba9607SSascha Wildner static const char *tab[] = {
30354ba9607SSascha Wildner "<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
30454ba9607SSascha Wildner "<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>",
30554ba9607SSascha Wildner "<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>",
30654ba9607SSascha Wildner "<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>",
30754ba9607SSascha Wildner " ", "!", "\"", "#", "$", "%", "&", "'",
30854ba9607SSascha Wildner "(", ")", "*", "+", ",", "-", ".", "/",
30954ba9607SSascha Wildner "0", "1", "2", "3", "4", "5", "6", "7",
31054ba9607SSascha Wildner "8", "9", ":", ";", "<", "=", ">", "?",
31154ba9607SSascha Wildner "@", "A", "B", "C", "D", "E", "F", "G",
31254ba9607SSascha Wildner "H", "I", "J", "K", "L", "M", "N", "O",
31354ba9607SSascha Wildner "P", "Q", "R", "S", "T", "U", "V", "W",
31454ba9607SSascha Wildner "X", "Y", "Z", "[", "\\", "]", "^", "_",
31554ba9607SSascha Wildner "`", "a", "b", "c", "d", "e", "f", "g",
31654ba9607SSascha Wildner "h", "i", "j", "k", "l", "m", "n", "o",
31754ba9607SSascha Wildner "p", "q", "r", "s", "t", "u", "v", "w",
31854ba9607SSascha Wildner "x", "y", "z", "{", "|", "}", "~", "<DEL>",
31954ba9607SSascha Wildner "<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>",
32054ba9607SSascha Wildner "<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
32154ba9607SSascha Wildner "<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
32254ba9607SSascha Wildner "<98>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
32354ba9607SSascha Wildner nbrsp, "!", "/\bc", "-\bL", "o\bx", "=\bY", "|", "<section>",
32454ba9607SSascha Wildner "\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-",
32554ba9607SSascha Wildner "<degree>","+-","^2", "^3", "'","<micro>","<paragraph>",".",
32654ba9607SSascha Wildner ",", "^1", "_\bo", ">>", "1/4", "1/2", "3/4", "?",
32754ba9607SSascha Wildner "`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC",
32854ba9607SSascha Wildner "`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI",
32954ba9607SSascha Wildner "Dh", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x",
33054ba9607SSascha Wildner "/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss",
33154ba9607SSascha Wildner "`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc",
33254ba9607SSascha Wildner "`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi",
33354ba9607SSascha Wildner "dh", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","/",
33454ba9607SSascha Wildner "/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by",
33554ba9607SSascha Wildner "A", "a", "A", "a", "A", "a", "'\bC", "'\bc",
33654ba9607SSascha Wildner "^\bC", "^\bc", "C", "c", "C", "c", "D", "d",
33754ba9607SSascha Wildner "/\bD", "/\bd", "E", "e", "E", "e", "E", "e",
33854ba9607SSascha Wildner "E", "e", "E", "e", "^\bG", "^\bg", "G", "g",
33954ba9607SSascha Wildner "G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh",
34054ba9607SSascha Wildner "~\bI", "~\bi", "I", "i", "I", "i", "I", "i",
34154ba9607SSascha Wildner "I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk",
34254ba9607SSascha Wildner "q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L",
34354ba9607SSascha Wildner "l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N",
34454ba9607SSascha Wildner "n", "'n", "Ng", "ng", "O", "o", "O", "o",
34554ba9607SSascha Wildner "O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br",
34654ba9607SSascha Wildner "R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs",
34754ba9607SSascha Wildner "S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt",
34854ba9607SSascha Wildner "~\bU", "~\bu", "U", "u", "U", "u", "U", "u",
34954ba9607SSascha Wildner "U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by",
35054ba9607SSascha Wildner "\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s",
35154ba9607SSascha Wildner "b", "B", "B", "b", "6", "6", "O", "C",
35254ba9607SSascha Wildner "c", "D", "D", "D", "d", "d", "3", "@",
35354ba9607SSascha Wildner "E", "F", ",\bf", "G", "G", "hv", "I", "/\bI",
35454ba9607SSascha Wildner "K", "k", "/\bl", "l", "W", "N", "n", "~\bO",
35554ba9607SSascha Wildner "O", "o", "OI", "oi", "P", "p", "YR", "2",
35654ba9607SSascha Wildner "2", "SH", "sh", "t", "T", "t", "T", "U",
35754ba9607SSascha Wildner "u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH",
35854ba9607SSascha Wildner "ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w",
35954ba9607SSascha Wildner "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ",
36054ba9607SSascha Wildner "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I",
36154ba9607SSascha Wildner "i", "O", "o", "U", "u", "U", "u", "U",
36254ba9607SSascha Wildner "u", "U", "u", "U", "u", "@", "A", "a",
36354ba9607SSascha Wildner "A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g",
36454ba9607SSascha Wildner "K", "k", "O", "o", "O", "o", "ZH", "zh",
36554ba9607SSascha Wildner "j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W",
36654ba9607SSascha Wildner "`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"};
36754ba9607SSascha Wildner
36854ba9607SSascha Wildner assert(uc >= 0);
36954ba9607SSascha Wildner if ((size_t)uc < sizeof(tab)/sizeof(tab[0]))
37054ba9607SSascha Wildner return tab[uc];
37154ba9607SSascha Wildner return mchars_uc2str(uc);
37280387638SSascha Wildner }
37380387638SSascha Wildner
37454ba9607SSascha Wildner #if HAVE_WCHAR
375a4c7eb57SSascha Wildner static size_t
locale_width(const struct termp * p,int c)376a4c7eb57SSascha Wildner locale_width(const struct termp *p, int c)
377a4c7eb57SSascha Wildner {
378a4c7eb57SSascha Wildner int rc;
379a4c7eb57SSascha Wildner
380070c62a6SFranco Fichtner if (c == ASCII_NBRSP)
381070c62a6SFranco Fichtner c = ' ';
382070c62a6SFranco Fichtner rc = wcwidth(c);
383070c62a6SFranco Fichtner if (rc < 0)
384070c62a6SFranco Fichtner rc = 0;
38554ba9607SSascha Wildner return rc;
386a4c7eb57SSascha Wildner }
387a4c7eb57SSascha Wildner
388a4c7eb57SSascha Wildner static void
locale_advance(struct termp * p,size_t len)389a4c7eb57SSascha Wildner locale_advance(struct termp *p, size_t len)
390a4c7eb57SSascha Wildner {
391a4c7eb57SSascha Wildner size_t i;
392a4c7eb57SSascha Wildner
393*99db7d0eSSascha Wildner /*
394*99db7d0eSSascha Wildner * XXX We used to have "assert(len < UINT16_MAX)" here.
395*99db7d0eSSascha Wildner * that is not quite right because the input document
396*99db7d0eSSascha Wildner * can trigger that by merely providing large input.
397*99db7d0eSSascha Wildner * For now, simply truncate.
398*99db7d0eSSascha Wildner */
399*99db7d0eSSascha Wildner if (len > 256)
400*99db7d0eSSascha Wildner len = 256;
401a4c7eb57SSascha Wildner for (i = 0; i < len; i++)
402a4c7eb57SSascha Wildner putwchar(L' ');
403a4c7eb57SSascha Wildner }
404a4c7eb57SSascha Wildner
405a4c7eb57SSascha Wildner static void
locale_endline(struct termp * p)406a4c7eb57SSascha Wildner locale_endline(struct termp *p)
407a4c7eb57SSascha Wildner {
408a4c7eb57SSascha Wildner
40954ba9607SSascha Wildner p->line++;
410*99db7d0eSSascha Wildner if ((int)p->tcol->offset > p->ti)
41154ba9607SSascha Wildner p->tcol->offset -= p->ti;
412*99db7d0eSSascha Wildner else
413*99db7d0eSSascha Wildner p->tcol->offset = 0;
41454ba9607SSascha Wildner p->ti = 0;
415a4c7eb57SSascha Wildner putwchar(L'\n');
416a4c7eb57SSascha Wildner }
417a4c7eb57SSascha Wildner
418a4c7eb57SSascha Wildner static void
locale_letter(struct termp * p,int c)419a4c7eb57SSascha Wildner locale_letter(struct termp *p, int c)
420a4c7eb57SSascha Wildner {
421a4c7eb57SSascha Wildner
422a4c7eb57SSascha Wildner putwchar(c);
423a4c7eb57SSascha Wildner }
424a4c7eb57SSascha Wildner #endif
425