/* $NetBSD: vis.c,v 1.83 2023/08/12 12:48:52 riastradh Exp $ */12/*-3* Copyright (c) 1989, 19934* The Regents of the University of California. All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. Neither the name of the University nor the names of its contributors15* may be used to endorse or promote products derived from this software16* without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE22* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF28* SUCH DAMAGE.29*/3031/*-32* Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.33* All rights reserved.34*35* Redistribution and use in source and binary forms, with or without36* modification, are permitted provided that the following conditions37* are met:38* 1. Redistributions of source code must retain the above copyright39* notice, this list of conditions and the following disclaimer.40* 2. Redistributions in binary form must reproduce the above copyright41* notice, this list of conditions and the following disclaimer in the42* documentation and/or other materials provided with the distribution.43*44* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS45* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED46* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR47* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS48* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR49* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF50* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS51* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN52* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)53* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE54* POSSIBILITY OF SUCH DAMAGE.55*/5657#include <sys/cdefs.h>58#if defined(LIBC_SCCS) && !defined(lint)59__RCSID("$NetBSD: vis.c,v 1.83 2023/08/12 12:48:52 riastradh Exp $");60#endif /* LIBC_SCCS and not lint */6162#include "namespace.h"63#include <sys/types.h>64#include <sys/param.h>6566#include <assert.h>67#include <vis.h>68#include <errno.h>69#include <stdint.h>70#include <stdlib.h>71#include <wchar.h>72#include <wctype.h>7374#ifdef __weak_alias75__weak_alias(strvisx,_strvisx)76#endif7778#if !HAVE_VIS || !HAVE_SVIS79#include <ctype.h>80#include <limits.h>81#include <stdio.h>82#include <string.h>8384#define _DIAGASSERT(x) assert(x)8586/*87* The reason for going through the trouble to deal with character encodings88* in vis(3), is that we use this to safe encode output of commands. This89* safe encoding varies depending on the character set. For example if we90* display ps output in French, we don't want to display French characters91* as M-foo.92*/9394static wchar_t *do_svis(wchar_t *, wint_t, int, wint_t, const wchar_t *);9596#undef BELL97#define BELL L'\a'9899#if defined(LC_C_LOCALE)100#define iscgraph(c) isgraph_l(c, LC_C_LOCALE)101#else102/* Keep it simple for now, no locale stuff */103#define iscgraph(c) isgraph(c)104#ifdef notyet105#include <locale.h>106static int107iscgraph(int c) {108int rv;109char *ol;110111ol = setlocale(LC_CTYPE, "C");112rv = isgraph(c);113if (ol)114setlocale(LC_CTYPE, ol);115return rv;116}117#endif118#endif119120#define ISGRAPH(flags, c) \121(((flags) & VIS_NOLOCALE) ? iscgraph(c) : iswgraph(c))122123#define iswoctal(c) (((u_char)(c)) >= L'0' && ((u_char)(c)) <= L'7')124#define iswwhite(c) (c == L' ' || c == L'\t' || c == L'\n')125#define iswsafe(c) (c == L'\b' || c == BELL || c == L'\r')126#define xtoa(c) L"0123456789abcdef"[c]127#define XTOA(c) L"0123456789ABCDEF"[c]128129#define MAXEXTRAS 30130131static const wchar_t char_shell[] = L"'`\";&<>()|{}]\\$!^~";132static const wchar_t char_glob[] = L"*?[#";133134#if !HAVE_NBTOOL_CONFIG_H135#ifndef __NetBSD__136/*137* On NetBSD MB_LEN_MAX is currently 32 which does not fit on any integer138* integral type and it is probably wrong, since currently the maximum139* number of bytes and character needs is 6. Until this is fixed, the140* loops below are using sizeof(uint64_t) - 1 instead of MB_LEN_MAX, and141* the assertion is commented out.142*/143#ifdef __FreeBSD__144/*145* On FreeBSD including <sys/systm.h> for CTASSERT only works in kernel146* mode.147*/148#ifndef CTASSERT149#define CTASSERT(x) _CTASSERT(x, __LINE__)150#define _CTASSERT(x, y) __CTASSERT(x, y)151#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]152#endif153#endif /* __FreeBSD__ */154CTASSERT(MB_LEN_MAX <= sizeof(uint64_t));155#endif /* !__NetBSD__ */156#endif157158/*159* This is do_hvis, for HTTP style (RFC 1808)160*/161static wchar_t *162do_hvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)163{164if (iswalnum(c)165/* safe */166|| c == L'$' || c == L'-' || c == L'_' || c == L'.' || c == L'+'167/* extra */168|| c == L'!' || c == L'*' || c == L'\'' || c == L'(' || c == L')'169|| c == L',')170dst = do_svis(dst, c, flags, nextc, extra);171else {172*dst++ = L'%';173*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);174*dst++ = xtoa((unsigned int)c & 0xf);175}176177return dst;178}179180/*181* This is do_mvis, for Quoted-Printable MIME (RFC 2045)182* NB: No handling of long lines or CRLF.183*/184static wchar_t *185do_mvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)186{187if ((c != L'\n') &&188/* Space at the end of the line */189((iswspace(c) && (nextc == L'\r' || nextc == L'\n')) ||190/* Out of range */191(!iswspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||192/* Specific char to be escaped */193wcschr(L"#$@[\\]^`{|}~", c) != NULL)) {194*dst++ = L'=';195*dst++ = XTOA(((unsigned int)c >> 4) & 0xf);196*dst++ = XTOA((unsigned int)c & 0xf);197} else198dst = do_svis(dst, c, flags, nextc, extra);199return dst;200}201202/*203* Output single byte of multibyte character.204*/205static wchar_t *206do_mbyte(wchar_t *dst, wint_t c, int flags, wint_t nextc, int iswextra)207{208if (flags & VIS_CSTYLE) {209switch (c) {210case L'\n':211*dst++ = L'\\'; *dst++ = L'n';212return dst;213case L'\r':214*dst++ = L'\\'; *dst++ = L'r';215return dst;216case L'\b':217*dst++ = L'\\'; *dst++ = L'b';218return dst;219case BELL:220*dst++ = L'\\'; *dst++ = L'a';221return dst;222case L'\v':223*dst++ = L'\\'; *dst++ = L'v';224return dst;225case L'\t':226*dst++ = L'\\'; *dst++ = L't';227return dst;228case L'\f':229*dst++ = L'\\'; *dst++ = L'f';230return dst;231case L' ':232*dst++ = L'\\'; *dst++ = L's';233return dst;234case L'\0':235*dst++ = L'\\'; *dst++ = L'0';236if (iswoctal(nextc)) {237*dst++ = L'0';238*dst++ = L'0';239}240return dst;241/* We cannot encode these characters in VIS_CSTYLE242* because they special meaning */243case L'n':244case L'r':245case L'b':246case L'a':247case L'v':248case L't':249case L'f':250case L's':251case L'0':252case L'M':253case L'^':254case L'$': /* vis(1) -l */255break;256default:257if (ISGRAPH(flags, c) && !iswoctal(c)) {258*dst++ = L'\\';259*dst++ = c;260return dst;261}262}263}264if (iswextra || ((c & 0177) == L' ') || (flags & VIS_OCTAL)) {265*dst++ = L'\\';266*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + L'0';267*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + L'0';268*dst++ = (c & 07) + L'0';269} else {270if ((flags & VIS_NOSLASH) == 0)271*dst++ = L'\\';272273if (c & 0200) {274c &= 0177;275*dst++ = L'M';276}277278if (iswcntrl(c)) {279*dst++ = L'^';280if (c == 0177)281*dst++ = L'?';282else283*dst++ = c + L'@';284} else {285*dst++ = L'-';286*dst++ = c;287}288}289290return dst;291}292293/*294* This is do_vis, the central code of vis.295* dst: Pointer to the destination buffer296* c: Character to encode297* flags: Flags word298* nextc: The character following 'c'299* extra: Pointer to the list of extra characters to be300* backslash-protected.301*/302static wchar_t *303do_svis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)304{305int iswextra, i, shft;306uint64_t bmsk, wmsk;307308iswextra = wcschr(extra, c) != NULL;309if (!iswextra && (ISGRAPH(flags, c) || iswwhite(c) ||310((flags & VIS_SAFE) && iswsafe(c)))) {311*dst++ = c;312return dst;313}314315/* See comment in istrsenvisx() output loop, below. */316wmsk = 0;317for (i = sizeof(wmsk) - 1; i >= 0; i--) {318shft = i * NBBY;319bmsk = (uint64_t)0xffLL << shft;320wmsk |= bmsk;321if ((c & wmsk) || i == 0)322dst = do_mbyte(dst, (wint_t)(323(uint64_t)(c & bmsk) >> shft),324flags, nextc, iswextra);325}326327return dst;328}329330typedef wchar_t *(*visfun_t)(wchar_t *, wint_t, int, wint_t, const wchar_t *);331332/*333* Return the appropriate encoding function depending on the flags given.334*/335static visfun_t336getvisfun(int flags)337{338if (flags & VIS_HTTPSTYLE)339return do_hvis;340if (flags & VIS_MIMESTYLE)341return do_mvis;342return do_svis;343}344345/*346* Expand list of extra characters to not visually encode.347*/348static wchar_t *349makeextralist(int flags, const char *src)350{351wchar_t *dst, *d;352size_t len;353const wchar_t *s;354mbstate_t mbstate;355356bzero(&mbstate, sizeof(mbstate));357len = strlen(src);358if ((dst = calloc(len + MAXEXTRAS, sizeof(*dst))) == NULL)359return NULL;360361memset(&mbstate, 0, sizeof(mbstate));362if ((flags & VIS_NOLOCALE)363|| mbsrtowcs(dst, &src, len, &mbstate) == (size_t)-1) {364size_t i;365for (i = 0; i < len; i++)366dst[i] = (wchar_t)(u_char)src[i];367d = dst + len;368} else369d = dst + wcslen(dst);370371if (flags & VIS_GLOB)372for (s = char_glob; *s; *d++ = *s++)373continue;374375if (flags & VIS_SHELL)376for (s = char_shell; *s; *d++ = *s++)377continue;378379if (flags & VIS_SP) *d++ = L' ';380if (flags & VIS_TAB) *d++ = L'\t';381if (flags & VIS_NL) *d++ = L'\n';382if (flags & VIS_DQ) *d++ = L'"';383if ((flags & VIS_NOSLASH) == 0) *d++ = L'\\';384*d = L'\0';385386return dst;387}388389/*390* istrsenvisx()391* The main internal function.392* All user-visible functions call this one.393*/394static int395istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,396int flags, const char *mbextra, int *cerr_ptr)397{398char mbbuf[MB_LEN_MAX];399wchar_t *dst, *src, *pdst, *psrc, *start, *extra;400size_t len, olen;401uint64_t bmsk, wmsk;402wint_t c;403visfun_t f;404int clen = 0, cerr, error = -1, i, shft;405char *mbdst, *mbwrite, *mdst;406size_t mbslength;407size_t maxolen;408mbstate_t mbstate;409410_DIAGASSERT(mbdstp != NULL);411_DIAGASSERT(mbsrc != NULL || mblength == 0);412_DIAGASSERT(mbextra != NULL);413414mbslength = mblength;415/*416* When inputing a single character, must also read in the417* next character for nextc, the look-ahead character.418*/419if (mbslength == 1)420mbslength++;421422/*423* Input (mbsrc) is a char string considered to be multibyte424* characters. The input loop will read this string pulling425* one character, possibly multiple bytes, from mbsrc and426* converting each to wchar_t in src.427*428* The vis conversion will be done using the wide char429* wchar_t string.430*431* This will then be converted back to a multibyte string to432* return to the caller.433*/434435/*436* Guarantee the arithmetic on input to calloc won't overflow.437*/438if (mbslength > (SIZE_MAX - 1)/16) {439errno = ENOMEM;440return -1;441}442443/* Allocate space for the wide char strings */444psrc = pdst = extra = NULL;445mdst = NULL;446if ((psrc = calloc(mbslength + 1, sizeof(*psrc))) == NULL)447return -1;448if ((pdst = calloc((16 * mbslength) + 1, sizeof(*pdst))) == NULL)449goto out;450if (*mbdstp == NULL) {451if ((mdst = calloc((16 * mbslength) + 1, sizeof(*mdst))) == NULL)452goto out;453*mbdstp = mdst;454}455456mbdst = *mbdstp;457dst = pdst;458src = psrc;459460if (flags & VIS_NOLOCALE) {461/* Do one byte at a time conversion */462cerr = 1;463} else {464/* Use caller's multibyte conversion error flag. */465cerr = cerr_ptr ? *cerr_ptr : 0;466}467468/*469* Input loop.470* Handle up to mblength characters (not bytes). We do not471* stop at NULs because we may be processing a block of data472* that includes NULs.473*/474memset(&mbstate, 0, sizeof(mbstate));475while (mbslength > 0) {476/* Convert one multibyte character to wchar_t. */477if (!cerr) {478clen = mbrtowc(src, mbsrc,479(mbslength < MB_LEN_MAX480? mbslength481: MB_LEN_MAX),482&mbstate);483assert(clen < 0 || (size_t)clen <= mbslength);484assert(clen <= MB_LEN_MAX);485}486if (cerr || clen < 0) {487/* Conversion error, process as a byte instead. */488*src = (wint_t)(u_char)*mbsrc;489clen = 1;490cerr = 1;491}492if (clen == 0) {493/*494* NUL in input gives 0 return value. process495* as single NUL byte and keep going.496*/497clen = 1;498}499/*500* Let n := MIN(mbslength, MB_LEN_MAX). We have:501*502* mbslength >= 1503* mbrtowc(..., n, &mbstate) <= n,504* by the contract of mbrtowc505*506* clen is either507* (a) mbrtowc(..., n, &mbstate), in which case508* clen <= n <= mbslength; or509* (b) 1, in which case clen = 1 <= mbslength.510*/511assert(clen > 0);512assert((size_t)clen <= mbslength);513/* Advance buffer character pointer. */514src++;515/* Advance input pointer by number of bytes read. */516mbsrc += clen;517/* Decrement input byte count. */518mbslength -= clen;519}520len = src - psrc;521src = psrc;522523/*524* In the single character input case, we will have actually525* processed two characters, c and nextc. Reset len back to526* just a single character.527*/528if (mblength < len)529len = mblength;530531/* Convert extra argument to list of characters for this mode. */532extra = makeextralist(flags, mbextra);533if (!extra) {534if (dlen && *dlen == 0) {535errno = ENOSPC;536goto out;537}538*mbdst = '\0'; /* can't create extra, return "" */539error = 0;540goto out;541}542543/* Look up which processing function to call. */544f = getvisfun(flags);545546/*547* Main processing loop.548* Call do_Xvis processing function one character at a time549* with next character available for look-ahead.550*/551for (start = dst; len > 0; len--) {552c = *src++;553dst = (*f)(dst, c, flags, len >= 1 ? *src : L'\0', extra);554if (dst == NULL) {555errno = ENOSPC;556goto out;557}558}559560/* Terminate the string in the buffer. */561*dst = L'\0';562563/*564* Output loop.565* Convert wchar_t string back to multibyte output string.566* If we have hit a multi-byte conversion error on input,567* output byte-by-byte here. Else use wctomb().568*/569len = wcslen(start);570if (dlen) {571maxolen = *dlen;572if (maxolen == 0) {573errno = ENOSPC;574goto out;575}576} else {577if (len > (SIZE_MAX - 1)/MB_LEN_MAX) {578errno = ENOSPC;579goto out;580}581maxolen = len*MB_LEN_MAX + 1;582}583olen = 0;584memset(&mbstate, 0, sizeof(mbstate));585for (dst = start; len > 0; len--) {586if (!cerr) {587/*588* If we have at least MB_CUR_MAX bytes in the buffer,589* we'll just do the conversion in-place into mbdst. We590* need to be a little more conservative when we get to591* the end of the buffer, as we may not have MB_CUR_MAX592* bytes but we may not need it.593*/594if (maxolen - olen > MB_CUR_MAX)595mbwrite = mbdst;596else597mbwrite = mbbuf;598clen = wcrtomb(mbwrite, *dst, &mbstate);599if (clen > 0 && mbwrite != mbdst) {600/*601* Don't break past our output limit, noting602* that maxolen includes the nul terminator so603* we can't write past maxolen - 1 here.604*/605if (olen + clen >= maxolen) {606errno = ENOSPC;607goto out;608}609610memcpy(mbdst, mbwrite, clen);611}612}613if (cerr || clen < 0) {614/*615* Conversion error, process as a byte(s) instead.616* Examine each byte and higher-order bytes for617* data. E.g.,618* 0x000000000000a264 -> a2 64619* 0x000000001f00a264 -> 1f 00 a2 64620*/621clen = 0;622wmsk = 0;623for (i = sizeof(wmsk) - 1; i >= 0; i--) {624shft = i * NBBY;625bmsk = (uint64_t)0xffLL << shft;626wmsk |= bmsk;627if ((*dst & wmsk) || i == 0) {628if (olen + clen + 1 >= maxolen) {629errno = ENOSPC;630goto out;631}632633mbdst[clen++] = (char)(634(uint64_t)(*dst & bmsk) >>635shft);636}637}638cerr = 1;639}640641/*642* We'll be dereferencing mbdst[clen] after this to write the643* nul terminator; the above paths should have checked for a644* possible overflow already.645*/646assert(olen + clen < maxolen);647648/* Advance output pointer by number of bytes written. */649mbdst += clen;650/* Advance buffer character pointer. */651dst++;652/* Incrment output character count. */653olen += clen;654}655656/* Terminate the output string. */657assert(olen < maxolen);658*mbdst = '\0';659660if (flags & VIS_NOLOCALE) {661/* Pass conversion error flag out. */662if (cerr_ptr)663*cerr_ptr = cerr;664}665666free(extra);667free(pdst);668free(psrc);669670return (int)olen;671out:672free(extra);673free(pdst);674free(psrc);675free(mdst);676return error;677}678679static int680istrsenvisxl(char **mbdstp, size_t *dlen, const char *mbsrc,681int flags, const char *mbextra, int *cerr_ptr)682{683return istrsenvisx(mbdstp, dlen, mbsrc,684mbsrc != NULL ? strlen(mbsrc) : 0, flags, mbextra, cerr_ptr);685}686687#endif688689#if !HAVE_SVIS690/*691* The "svis" variants all take an "extra" arg that is a pointer692* to a NUL-terminated list of characters to be encoded, too.693* These functions are useful e. g. to encode strings in such a694* way so that they are not interpreted by a shell.695*/696697char *698svis(char *mbdst, int c, int flags, int nextc, const char *mbextra)699{700char cc[2];701int ret;702703cc[0] = c;704cc[1] = nextc;705706ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, mbextra, NULL);707if (ret < 0)708return NULL;709return mbdst + ret;710}711712char *713snvis(char *mbdst, size_t dlen, int c, int flags, int nextc, const char *mbextra)714{715char cc[2];716int ret;717718cc[0] = c;719cc[1] = nextc;720721ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, mbextra, NULL);722if (ret < 0)723return NULL;724return mbdst + ret;725}726727int728strsvis(char *mbdst, const char *mbsrc, int flags, const char *mbextra)729{730return istrsenvisxl(&mbdst, NULL, mbsrc, flags, mbextra, NULL);731}732733int734strsnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags, const char *mbextra)735{736return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, mbextra, NULL);737}738739int740strsvisx(char *mbdst, const char *mbsrc, size_t len, int flags, const char *mbextra)741{742return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, mbextra, NULL);743}744745int746strsnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,747const char *mbextra)748{749return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, NULL);750}751752int753strsenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,754const char *mbextra, int *cerr_ptr)755{756return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, cerr_ptr);757}758#endif759760#if !HAVE_VIS761/*762* vis - visually encode characters763*/764char *765vis(char *mbdst, int c, int flags, int nextc)766{767char cc[2];768int ret;769770cc[0] = c;771cc[1] = nextc;772773ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, "", NULL);774if (ret < 0)775return NULL;776return mbdst + ret;777}778779char *780nvis(char *mbdst, size_t dlen, int c, int flags, int nextc)781{782char cc[2];783int ret;784785cc[0] = c;786cc[1] = nextc;787788ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, "", NULL);789if (ret < 0)790return NULL;791return mbdst + ret;792}793794/*795* strvis - visually encode characters from src into dst796*797* Dst must be 4 times the size of src to account for possible798* expansion. The length of dst, not including the trailing NULL,799* is returned.800*/801802int803strvis(char *mbdst, const char *mbsrc, int flags)804{805return istrsenvisxl(&mbdst, NULL, mbsrc, flags, "", NULL);806}807808int809strnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags)810{811return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, "", NULL);812}813814int815stravis(char **mbdstp, const char *mbsrc, int flags)816{817*mbdstp = NULL;818return istrsenvisxl(mbdstp, NULL, mbsrc, flags, "", NULL);819}820821/*822* strvisx - visually encode characters from src into dst823*824* Dst must be 4 times the size of src to account for possible825* expansion. The length of dst, not including the trailing NULL,826* is returned.827*828* Strvisx encodes exactly len characters from src into dst.829* This is useful for encoding a block of data.830*/831832int833strvisx(char *mbdst, const char *mbsrc, size_t len, int flags)834{835return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, "", NULL);836}837838int839strnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags)840{841return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", NULL);842}843844int845strenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,846int *cerr_ptr)847{848return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", cerr_ptr);849}850#endif851852853