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