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