1*4d131170SRobert 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> 4*4d131170SRobert 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> 2595c635efSGarrett D'Amore #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 3395c635efSGarrett D'Amore #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 * 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) { 12695c635efSGarrett D'Amore p->mdocstyle = 1; 12795c635efSGarrett D'Amore 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) 134260e9a87SYuri Pankov p->synopsisonly = 1; 13595c635efSGarrett D'Amore 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 * 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 * 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 * 156371584c2SYuri Pankov locale_alloc(const struct manoutput *outopts) 15795c635efSGarrett D'Amore { 15895c635efSGarrett D'Amore 159371584c2SYuri Pankov return ascii_init(TERMENC_LOCALE, outopts); 16095c635efSGarrett D'Amore } 16195c635efSGarrett D'Amore 162260e9a87SYuri Pankov static void 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 183371584c2SYuri Pankov terminal_sepline(void *arg) 184260e9a87SYuri Pankov { 185260e9a87SYuri Pankov struct termp *p; 186260e9a87SYuri Pankov size_t i; 187260e9a87SYuri Pankov 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); 194260e9a87SYuri Pankov } 195260e9a87SYuri Pankov 19695c635efSGarrett D'Amore static size_t 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 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 21095c635efSGarrett D'Amore ascii_letter(struct termp *p, int c) 21195c635efSGarrett D'Amore { 21295c635efSGarrett D'Amore 21395c635efSGarrett D'Amore putchar(c); 21495c635efSGarrett D'Amore } 21595c635efSGarrett D'Amore 21695c635efSGarrett D'Amore static void 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 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 23195c635efSGarrett D'Amore ascii_endline(struct termp *p) 23295c635efSGarrett D'Amore { 23395c635efSGarrett D'Amore 234371584c2SYuri Pankov p->line++; 235*4d131170SRobert Mustacchi if ((int)p->tcol->offset > p->ti) 236c66b8046SYuri Pankov p->tcol->offset -= p->ti; 237*4d131170SRobert Mustacchi else 238*4d131170SRobert 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 24495c635efSGarrett D'Amore ascii_advance(struct termp *p, size_t len) 24595c635efSGarrett D'Amore { 24695c635efSGarrett D'Amore size_t i; 24795c635efSGarrett D'Amore 248*4d131170SRobert Mustacchi /* 249*4d131170SRobert Mustacchi * XXX We used to have "assert(len < UINT16_MAX)" here. 250*4d131170SRobert Mustacchi * that is not quite right because the input document 251*4d131170SRobert Mustacchi * can trigger that by merely providing large input. 252*4d131170SRobert Mustacchi * For now, simply truncate. 253*4d131170SRobert Mustacchi */ 254*4d131170SRobert Mustacchi if (len > 256) 255*4d131170SRobert 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 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; 280260e9a87SYuri Pankov break; 281260e9a87SYuri Pankov case SCALE_VS: 282371584c2SYuri Pankov case SCALE_PC: 283371584c2SYuri Pankov r = su->scale * 40.0; 284371584c2SYuri Pankov break; 285371584c2SYuri 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 * 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 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 38995c635efSGarrett D'Amore locale_advance(struct termp *p, size_t len) 39095c635efSGarrett D'Amore { 39195c635efSGarrett D'Amore size_t i; 39295c635efSGarrett D'Amore 393*4d131170SRobert Mustacchi /* 394*4d131170SRobert Mustacchi * XXX We used to have "assert(len < UINT16_MAX)" here. 395*4d131170SRobert Mustacchi * that is not quite right because the input document 396*4d131170SRobert Mustacchi * can trigger that by merely providing large input. 397*4d131170SRobert Mustacchi * For now, simply truncate. 398*4d131170SRobert Mustacchi */ 399*4d131170SRobert Mustacchi if (len > 256) 400*4d131170SRobert 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 40695c635efSGarrett D'Amore locale_endline(struct termp *p) 40795c635efSGarrett D'Amore { 40895c635efSGarrett D'Amore 409371584c2SYuri Pankov p->line++; 410*4d131170SRobert Mustacchi if ((int)p->tcol->offset > p->ti) 411c66b8046SYuri Pankov p->tcol->offset -= p->ti; 412*4d131170SRobert Mustacchi else 413*4d131170SRobert 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 41995c635efSGarrett D'Amore locale_letter(struct termp *p, int c) 42095c635efSGarrett D'Amore { 42195c635efSGarrett D'Amore 42295c635efSGarrett D'Amore putwchar(c); 42395c635efSGarrett D'Amore } 42495c635efSGarrett D'Amore #endif 425