version 1.44, 2011/03/12 19:52:48 |
version 1.44.4.2, 2014/05/22 11:36:52 |
|
|
#if defined(LIBC_SCCS) && !defined(lint) |
#if defined(LIBC_SCCS) && !defined(lint) |
__RCSID("$NetBSD$"); |
__RCSID("$NetBSD$"); |
#endif /* LIBC_SCCS and not lint */ |
#endif /* LIBC_SCCS and not lint */ |
|
#ifdef __FBSDID |
|
__FBSDID("$FreeBSD$"); |
|
#define _DIAGASSERT(x) assert(x) |
|
#endif |
|
|
#include "namespace.h" |
#include "namespace.h" |
#include <sys/types.h> |
#include <sys/types.h> |
|
#include <sys/param.h> |
|
|
#include <assert.h> |
#include <assert.h> |
#include <vis.h> |
#include <vis.h> |
#include <errno.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
#include <wchar.h> |
|
#include <wctype.h> |
|
|
#ifdef __weak_alias |
#ifdef __weak_alias |
__weak_alias(strvisx,_strvisx) |
__weak_alias(strvisx,_strvisx) |
Line 78 __weak_alias(strvisx,_strvisx) |
|
Line 85 __weak_alias(strvisx,_strvisx) |
|
#include <stdio.h> |
#include <stdio.h> |
#include <string.h> |
#include <string.h> |
|
|
static char *do_svis(char *, size_t *, int, int, int, const char *); |
/* |
|
* The reason for going through the trouble to deal with character encodings |
|
* in vis(3), is that we use this to safe encode output of commands. This |
|
* safe encoding varies depending on the character set. For example if we |
|
* display ps output in French, we don't want to display French characters |
|
* as M-foo. |
|
*/ |
|
|
|
static wchar_t *do_svis(wchar_t *, wint_t, int, wint_t, const wchar_t *); |
|
|
#undef BELL |
#undef BELL |
#define BELL '\a' |
#define BELL L'\a' |
|
|
|
#define iswoctal(c) (((u_char)(c)) >= L'0' && ((u_char)(c)) <= L'7') |
|
#define iswwhite(c) (c == L' ' || c == L'\t' || c == L'\n') |
|
#define iswsafe(c) (c == L'\b' || c == BELL || c == L'\r') |
|
#define xtoa(c) L"0123456789abcdef"[c] |
|
#define XTOA(c) L"0123456789ABCDEF"[c] |
|
|
|
#define MAXEXTRAS 10 |
|
|
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') |
#if !HAVE_NBTOOL_CONFIG_H |
#define iswhite(c) (c == ' ' || c == '\t' || c == '\n') |
#ifndef __NetBSD__ |
#define issafe(c) (c == '\b' || c == BELL || c == '\r') |
/* |
#define xtoa(c) "0123456789abcdef"[c] |
* On NetBSD MB_LEN_MAX is currently 32 which does not fit on any integer |
#define XTOA(c) "0123456789ABCDEF"[c] |
* integral type and it is probably wrong, since currently the maximum |
|
* number of bytes and character needs is 6. Until this is fixed, the |
#define MAXEXTRAS 5 |
* loops below are using sizeof(uint64_t) - 1 instead of MB_LEN_MAX, and |
|
* the assertion is commented out. |
#define MAKEEXTRALIST(flag, extra, orig_str) \ |
*/ |
do { \ |
#ifdef __FreeBSD__ |
const char *orig = orig_str; \ |
/* |
const char *o = orig; \ |
* On FreeBSD including <sys/systm.h> for CTASSERT only works in kernel |
char *e; \ |
* mode. |
while (*o++) \ |
*/ |
continue; \ |
#ifndef CTASSERT |
extra = malloc((size_t)((o - orig) + MAXEXTRAS)); \ |
#define CTASSERT(x) _CTASSERT(x, __LINE__) |
if (!extra) break; \ |
#define _CTASSERT(x, y) __CTASSERT(x, y) |
for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ |
#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] |
continue; \ |
#endif |
e--; \ |
#endif /* __FreeBSD__ */ |
if (flag & VIS_SP) *e++ = ' '; \ |
CTASSERT(MB_LEN_MAX <= sizeof(uint64_t)); |
if (flag & VIS_TAB) *e++ = '\t'; \ |
#endif /* !__NetBSD__ */ |
if (flag & VIS_NL) *e++ = '\n'; \ |
#endif |
if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ |
|
*e = '\0'; \ |
|
} while (/*CONSTCOND*/0) |
|
|
|
/* |
/* |
* This is do_hvis, for HTTP style (RFC 1808) |
* This is do_hvis, for HTTP style (RFC 1808) |
*/ |
*/ |
static char * |
static wchar_t * |
do_hvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) |
do_hvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra) |
{ |
{ |
|
if (iswalnum(c) |
if ((isascii(c) && isalnum(c)) |
|
/* safe */ |
/* safe */ |
|| c == '$' || c == '-' || c == '_' || c == '.' || c == '+' |
|| c == L'$' || c == L'-' || c == L'_' || c == L'.' || c == L'+' |
/* extra */ |
/* extra */ |
|| c == '!' || c == '*' || c == '\'' || c == '(' || c == ')' |
|| c == L'!' || c == L'*' || c == L'\'' || c == L'(' || c == L')' |
|| c == ',') { |
|| c == L',') |
dst = do_svis(dst, dlen, c, flag, nextc, extra); |
dst = do_svis(dst, c, flags, nextc, extra); |
} else { |
else { |
if (dlen) { |
*dst++ = L'%'; |
if (*dlen < 3) |
|
return NULL; |
|
*dlen -= 3; |
|
} |
|
*dst++ = '%'; |
|
*dst++ = xtoa(((unsigned int)c >> 4) & 0xf); |
*dst++ = xtoa(((unsigned int)c >> 4) & 0xf); |
*dst++ = xtoa((unsigned int)c & 0xf); |
*dst++ = xtoa((unsigned int)c & 0xf); |
} |
} |
Line 142 do_hvis(char *dst, size_t *dlen, int c, |
|
Line 156 do_hvis(char *dst, size_t *dlen, int c, |
|
* This is do_mvis, for Quoted-Printable MIME (RFC 2045) |
* This is do_mvis, for Quoted-Printable MIME (RFC 2045) |
* NB: No handling of long lines or CRLF. |
* NB: No handling of long lines or CRLF. |
*/ |
*/ |
static char * |
static wchar_t * |
do_mvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) |
do_mvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra) |
{ |
{ |
if ((c != '\n') && |
if ((c != L'\n') && |
/* Space at the end of the line */ |
/* Space at the end of the line */ |
((isspace(c) && (nextc == '\r' || nextc == '\n')) || |
((iswspace(c) && (nextc == L'\r' || nextc == L'\n')) || |
/* Out of range */ |
/* Out of range */ |
(!isspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) || |
(!iswspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) || |
/* Specific char to be escaped */ |
/* Specific char to be escaped */ |
strchr("#$@[\\]^`{|}~", c) != NULL)) { |
wcschr(L"#$@[\\]^`{|}~", c) != NULL)) { |
if (dlen) { |
*dst++ = L'='; |
if (*dlen < 3) |
|
return NULL; |
|
*dlen -= 3; |
|
} |
|
*dst++ = '='; |
|
*dst++ = XTOA(((unsigned int)c >> 4) & 0xf); |
*dst++ = XTOA(((unsigned int)c >> 4) & 0xf); |
*dst++ = XTOA((unsigned int)c & 0xf); |
*dst++ = XTOA((unsigned int)c & 0xf); |
} else { |
} else |
dst = do_svis(dst, dlen, c, flag, nextc, extra); |
dst = do_svis(dst, c, flags, nextc, extra); |
} |
|
return dst; |
return dst; |
} |
} |
|
|
/* |
/* |
* This is do_vis, the central code of vis. |
* Output single byte of multibyte character. |
* dst: Pointer to the destination buffer |
|
* c: Character to encode |
|
* flag: Flag word |
|
* nextc: The character following 'c' |
|
* extra: Pointer to the list of extra characters to be |
|
* backslash-protected. |
|
*/ |
*/ |
static char * |
static wchar_t * |
do_svis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) |
do_mbyte(wchar_t *dst, wint_t c, int flags, wint_t nextc, int iswextra) |
{ |
{ |
int isextra; |
if (flags & VIS_CSTYLE) { |
size_t odlen = dlen ? *dlen : 0; |
|
|
|
isextra = strchr(extra, c) != NULL; |
|
#define HAVE(x) \ |
|
do { \ |
|
if (dlen) { \ |
|
if (*dlen < (x)) \ |
|
goto out; \ |
|
*dlen -= (x); \ |
|
} \ |
|
} while (/*CONSTCOND*/0) |
|
if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || |
|
((flag & VIS_SAFE) && issafe(c)))) { |
|
HAVE(1); |
|
*dst++ = c; |
|
return dst; |
|
} |
|
if (flag & VIS_CSTYLE) { |
|
HAVE(2); |
|
switch (c) { |
switch (c) { |
case '\n': |
case L'\n': |
*dst++ = '\\'; *dst++ = 'n'; |
*dst++ = L'\\'; *dst++ = L'n'; |
return dst; |
return dst; |
case '\r': |
case L'\r': |
*dst++ = '\\'; *dst++ = 'r'; |
*dst++ = L'\\'; *dst++ = L'r'; |
return dst; |
return dst; |
case '\b': |
case L'\b': |
*dst++ = '\\'; *dst++ = 'b'; |
*dst++ = L'\\'; *dst++ = L'b'; |
return dst; |
return dst; |
case BELL: |
case BELL: |
*dst++ = '\\'; *dst++ = 'a'; |
*dst++ = L'\\'; *dst++ = L'a'; |
return dst; |
return dst; |
case '\v': |
case L'\v': |
*dst++ = '\\'; *dst++ = 'v'; |
*dst++ = L'\\'; *dst++ = L'v'; |
return dst; |
return dst; |
case '\t': |
case L'\t': |
*dst++ = '\\'; *dst++ = 't'; |
*dst++ = L'\\'; *dst++ = L't'; |
return dst; |
return dst; |
case '\f': |
case L'\f': |
*dst++ = '\\'; *dst++ = 'f'; |
*dst++ = L'\\'; *dst++ = L'f'; |
return dst; |
return dst; |
case ' ': |
case L' ': |
*dst++ = '\\'; *dst++ = 's'; |
*dst++ = L'\\'; *dst++ = L's'; |
return dst; |
return dst; |
case '\0': |
case L'\0': |
*dst++ = '\\'; *dst++ = '0'; |
*dst++ = L'\\'; *dst++ = L'0'; |
if (isoctal(nextc)) { |
if (iswoctal(nextc)) { |
HAVE(2); |
*dst++ = L'0'; |
*dst++ = '0'; |
*dst++ = L'0'; |
*dst++ = '0'; |
|
} |
} |
return dst; |
return dst; |
default: |
default: |
if (isgraph(c)) { |
if (iswgraph(c)) { |
*dst++ = '\\'; *dst++ = c; |
*dst++ = L'\\'; |
|
*dst++ = c; |
return dst; |
return dst; |
} |
} |
if (dlen) |
|
*dlen = odlen; |
|
} |
} |
} |
} |
if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { |
if (iswextra || ((c & 0177) == L' ') || (flags & VIS_OCTAL)) { |
HAVE(4); |
*dst++ = L'\\'; |
*dst++ = '\\'; |
*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + L'0'; |
*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; |
*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + L'0'; |
*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; |
*dst++ = (c & 07) + L'0'; |
*dst++ = (c & 07) + '0'; |
|
} else { |
} else { |
if ((flag & VIS_NOSLASH) == 0) { |
if ((flags & VIS_NOSLASH) == 0) |
HAVE(1); |
*dst++ = L'\\'; |
*dst++ = '\\'; |
|
} |
|
|
|
if (c & 0200) { |
if (c & 0200) { |
HAVE(1); |
c &= 0177; |
c &= 0177; *dst++ = 'M'; |
*dst++ = L'M'; |
} |
} |
|
|
if (iscntrl(c)) { |
if (iswcntrl(c)) { |
HAVE(2); |
*dst++ = L'^'; |
*dst++ = '^'; |
|
if (c == 0177) |
if (c == 0177) |
*dst++ = '?'; |
*dst++ = L'?'; |
else |
else |
*dst++ = c + '@'; |
*dst++ = c + L'@'; |
} else { |
} else { |
HAVE(2); |
*dst++ = L'-'; |
*dst++ = '-'; *dst++ = c; |
*dst++ = c; |
} |
} |
} |
} |
|
|
|
return dst; |
|
} |
|
|
|
/* |
|
* This is do_vis, the central code of vis. |
|
* dst: Pointer to the destination buffer |
|
* c: Character to encode |
|
* flags: Flags word |
|
* nextc: The character following 'c' |
|
* extra: Pointer to the list of extra characters to be |
|
* backslash-protected. |
|
*/ |
|
static wchar_t * |
|
do_svis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra) |
|
{ |
|
int iswextra, i, shft; |
|
uint64_t bmsk, wmsk; |
|
|
|
iswextra = wcschr(extra, c) != NULL; |
|
if (!iswextra && (iswgraph(c) || iswwhite(c) || |
|
((flags & VIS_SAFE) && iswsafe(c)))) { |
|
*dst++ = c; |
|
return dst; |
|
} |
|
|
|
/* See comment in istrsenvisx() output loop, below. */ |
|
wmsk = 0; |
|
for (i = sizeof(wmsk) - 1; i >= 0; i--) { |
|
shft = i * NBBY; |
|
bmsk = (uint64_t)0xffLL << shft; |
|
wmsk |= bmsk; |
|
if ((c & wmsk) || i == 0) |
|
dst = do_mbyte(dst, (wint_t)( |
|
(uint64_t)(c & bmsk) >> shft), |
|
flags, nextc, iswextra); |
|
} |
|
|
return dst; |
return dst; |
out: |
|
*dlen = odlen; |
|
return NULL; |
|
} |
} |
|
|
typedef char *(*visfun_t)(char *, size_t *, int, int, int, const char *); |
typedef wchar_t *(*visfun_t)(wchar_t *, wint_t, int, wint_t, const wchar_t *); |
|
|
/* |
/* |
* Return the appropriate encoding function depending on the flags given. |
* Return the appropriate encoding function depending on the flags given. |
*/ |
*/ |
static visfun_t |
static visfun_t |
getvisfun(int flag) |
getvisfun(int flags) |
{ |
{ |
if (flag & VIS_HTTPSTYLE) |
if (flags & VIS_HTTPSTYLE) |
return do_hvis; |
return do_hvis; |
if (flag & VIS_MIMESTYLE) |
if (flags & VIS_MIMESTYLE) |
return do_mvis; |
return do_mvis; |
return do_svis; |
return do_svis; |
} |
} |
|
|
/* |
/* |
* isnvis - visually encode characters, also encoding the characters |
* Expand list of extra characters to not visually encode. |
* pointed to by `extra' |
|
*/ |
*/ |
static char * |
static wchar_t * |
isnvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) |
makeextralist(int flags, const char *src) |
{ |
{ |
char *nextra = NULL; |
wchar_t *dst, *d; |
visfun_t f; |
size_t len; |
|
|
_DIAGASSERT(dst != NULL); |
len = strlen(src); |
_DIAGASSERT(extra != NULL); |
if ((dst = calloc(len + MAXEXTRAS, sizeof(*dst))) == NULL) |
MAKEEXTRALIST(flag, nextra, extra); |
|
if (!nextra) { |
|
if (dlen && *dlen == 0) { |
|
errno = ENOSPC; |
|
return NULL; |
|
} |
|
*dst = '\0'; /* can't create nextra, return "" */ |
|
return dst; |
|
} |
|
f = getvisfun(flag); |
|
dst = (*f)(dst, dlen, c, flag, nextc, nextra); |
|
free(nextra); |
|
if (dst == NULL || (dlen && *dlen == 0)) { |
|
errno = ENOSPC; |
|
return NULL; |
return NULL; |
} |
|
*dst = '\0'; |
|
return dst; |
|
} |
|
|
|
char * |
if (mbstowcs(dst, src, len) == (size_t)-1) { |
svis(char *dst, int c, int flag, int nextc, const char *extra) |
size_t i; |
{ |
for (i = 0; i < len; i++) |
return isnvis(dst, NULL, c, flag, nextc, extra); |
dst[i] = (wint_t)(u_char)src[i]; |
} |
d = dst + len; |
|
} else |
|
d = dst + wcslen(dst); |
|
|
|
if (flags & VIS_GLOB) { |
|
*d++ = L'*'; |
|
*d++ = L'?'; |
|
*d++ = L'['; |
|
*d++ = L'#'; |
|
} |
|
|
|
if (flags & VIS_SP) *d++ = L' '; |
|
if (flags & VIS_TAB) *d++ = L'\t'; |
|
if (flags & VIS_NL) *d++ = L'\n'; |
|
if ((flags & VIS_NOSLASH) == 0) *d++ = L'\\'; |
|
*d = L'\0'; |
|
|
char * |
return dst; |
snvis(char *dst, size_t dlen, int c, int flag, int nextc, const char *extra) |
|
{ |
|
return isnvis(dst, &dlen, c, flag, nextc, extra); |
|
} |
} |
|
|
|
|
/* |
/* |
* strsvis, strsvisx - visually encode characters from src into dst |
* istrsenvisx() |
* |
* The main internal function. |
* Extra is a pointer to a \0-terminated list of characters to |
* All user-visible functions call this one. |
* be encoded, too. These functions are useful e. g. to |
|
* encode strings in such a way so that they are not interpreted |
|
* by a shell. |
|
* |
|
* Dst must be 4 times the size of src to account for possible |
|
* expansion. The length of dst, not including the trailing NULL, |
|
* is returned. |
|
* |
|
* Strsvisx encodes exactly len bytes from src into dst. |
|
* This is useful for encoding a block of data. |
|
*/ |
*/ |
static int |
static int |
istrsnvis(char *dst, size_t *dlen, const char *csrc, int flag, const char *extra) |
istrsenvisx(char *mbdst, size_t *dlen, const char *mbsrc, size_t mblength, |
|
int flags, const char *mbextra, int *cerr_ptr) |
{ |
{ |
int c; |
wchar_t *dst, *src, *pdst, *psrc, *start, *extra; |
char *start; |
size_t len, olen; |
char *nextra = NULL; |
uint64_t bmsk, wmsk; |
const unsigned char *src = (const unsigned char *)csrc; |
wint_t c; |
visfun_t f; |
visfun_t f; |
|
int clen = 0, cerr = 0, error = -1, i, shft; |
|
ssize_t mbslength, maxolen; |
|
|
|
_DIAGASSERT(mbdst != NULL); |
|
_DIAGASSERT(mbsrc != NULL); |
|
_DIAGASSERT(mbextra != NULL); |
|
|
|
/* |
|
* Input (mbsrc) is a char string considered to be multibyte |
|
* characters. The input loop will read this string pulling |
|
* one character, possibly multiple bytes, from mbsrc and |
|
* converting each to wchar_t in src. |
|
* |
|
* The vis conversion will be done using the wide char |
|
* wchar_t string. |
|
* |
|
* This will then be converted back to a multibyte string to |
|
* return to the caller. |
|
*/ |
|
|
|
/* Allocate space for the wide char strings */ |
|
psrc = pdst = extra = NULL; |
|
if (!mblength) |
|
mblength = strlen(mbsrc); |
|
if ((psrc = calloc(mblength + 1, sizeof(*psrc))) == NULL) |
|
return -1; |
|
if ((pdst = calloc((4 * mblength) + 1, sizeof(*pdst))) == NULL) |
|
goto out; |
|
dst = pdst; |
|
src = psrc; |
|
|
|
/* Use caller's multibyte conversion error flag. */ |
|
if (cerr_ptr) |
|
cerr = *cerr_ptr; |
|
|
|
/* |
|
* Input loop. |
|
* Handle up to mblength characters (not bytes). We do not |
|
* stop at NULs because we may be processing a block of data |
|
* that includes NULs. |
|
*/ |
|
mbslength = (ssize_t)mblength; |
|
/* |
|
* When inputing a single character, must also read in the |
|
* next character for nextc, the look-ahead character. |
|
*/ |
|
if (mbslength == 1) |
|
mbslength++; |
|
while (mbslength > 0) { |
|
/* Convert one multibyte character to wchar_t. */ |
|
if (!cerr) |
|
clen = mbtowc(src, mbsrc, MB_LEN_MAX); |
|
if (cerr || clen < 0) { |
|
/* Conversion error, process as a byte instead. */ |
|
*src = (wint_t)(u_char)*mbsrc; |
|
clen = 1; |
|
cerr = 1; |
|
} |
|
if (clen == 0) |
|
/* |
|
* NUL in input gives 0 return value. process |
|
* as single NUL byte and keep going. |
|
*/ |
|
clen = 1; |
|
/* Advance buffer character pointer. */ |
|
src++; |
|
/* Advance input pointer by number of bytes read. */ |
|
mbsrc += clen; |
|
/* Decrement input byte count. */ |
|
mbslength -= clen; |
|
} |
|
len = src - psrc; |
|
src = psrc; |
|
/* |
|
* In the single character input case, we will have actually |
|
* processed two characters, c and nextc. Reset len back to |
|
* just a single character. |
|
*/ |
|
if (mblength < len) |
|
len = mblength; |
|
|
_DIAGASSERT(dst != NULL); |
/* Convert extra argument to list of characters for this mode. */ |
_DIAGASSERT(src != NULL); |
extra = makeextralist(flags, mbextra); |
_DIAGASSERT(extra != NULL); |
if (!extra) { |
MAKEEXTRALIST(flag, nextra, extra); |
if (dlen && *dlen == 0) { |
if (!nextra) { |
errno = ENOSPC; |
*dst = '\0'; /* can't create nextra, return "" */ |
goto out; |
return 0; |
} |
|
*mbdst = '\0'; /* can't create extra, return "" */ |
|
error = 0; |
|
goto out; |
} |
} |
f = getvisfun(flag); |
|
for (start = dst; (c = *src++) != '\0'; /* empty */) { |
/* Look up which processing function to call. */ |
dst = (*f)(dst, dlen, c, flag, *src, nextra); |
f = getvisfun(flags); |
|
|
|
/* |
|
* Main processing loop. |
|
* Call do_Xvis processing function one character at a time |
|
* with next character available for look-ahead. |
|
*/ |
|
for (start = dst; len > 0; len--) { |
|
c = *src++; |
|
dst = (*f)(dst, c, flags, len >= 1 ? *src : L'\0', extra); |
if (dst == NULL) { |
if (dst == NULL) { |
errno = ENOSPC; |
errno = ENOSPC; |
return -1; |
goto out; |
} |
} |
} |
} |
free(nextra); |
|
if (dlen && *dlen == 0) { |
/* Terminate the string in the buffer. */ |
errno = ENOSPC; |
*dst = L'\0'; |
return -1; |
|
} |
/* |
*dst = '\0'; |
* Output loop. |
return (int)(dst - start); |
* Convert wchar_t string back to multibyte output string. |
|
* If we have hit a multi-byte conversion error on input, |
|
* output byte-by-byte here. Else use wctomb(). |
|
*/ |
|
len = wcslen(start); |
|
maxolen = dlen ? *dlen : (wcslen(start) * MB_LEN_MAX + 1); |
|
olen = 0; |
|
for (dst = start; len > 0; len--) { |
|
if (!cerr) |
|
clen = wctomb(mbdst, *dst); |
|
if (cerr || clen < 0) { |
|
/* |
|
* Conversion error, process as a byte(s) instead. |
|
* Examine each byte and higher-order bytes for |
|
* data. E.g., |
|
* 0x000000000000a264 -> a2 64 |
|
* 0x000000001f00a264 -> 1f 00 a2 64 |
|
*/ |
|
clen = 0; |
|
wmsk = 0; |
|
for (i = sizeof(wmsk) - 1; i >= 0; i--) { |
|
shft = i * NBBY; |
|
bmsk = (uint64_t)0xffLL << shft; |
|
wmsk |= bmsk; |
|
if ((*dst & wmsk) || i == 0) |
|
mbdst[clen++] = (char)( |
|
(uint64_t)(*dst & bmsk) >> |
|
shft); |
|
} |
|
cerr = 1; |
|
} |
|
/* If this character would exceed our output limit, stop. */ |
|
if (olen + clen > (size_t)maxolen) |
|
break; |
|
/* Advance output pointer by number of bytes written. */ |
|
mbdst += clen; |
|
/* Advance buffer character pointer. */ |
|
dst++; |
|
/* Incrment output character count. */ |
|
olen += clen; |
|
} |
|
|
|
/* Terminate the output string. */ |
|
*mbdst = '\0'; |
|
|
|
/* Pass conversion error flag out. */ |
|
if (cerr_ptr) |
|
*cerr_ptr = cerr; |
|
|
|
free(extra); |
|
free(pdst); |
|
free(psrc); |
|
|
|
return (int)olen; |
|
out: |
|
free(extra); |
|
free(pdst); |
|
free(psrc); |
|
return error; |
} |
} |
|
#endif |
|
|
int |
#if !HAVE_SVIS |
strsvis(char *dst, const char *csrc, int flag, const char *extra) |
/* |
|
* The "svis" variants all take an "extra" arg that is a pointer |
|
* to a NUL-terminated list of characters to be encoded, too. |
|
* These functions are useful e. g. to encode strings in such a |
|
* way so that they are not interpreted by a shell. |
|
*/ |
|
|
|
char * |
|
svis(char *mbdst, int c, int flags, int nextc, const char *mbextra) |
{ |
{ |
return istrsnvis(dst, NULL, csrc, flag, extra); |
char cc[2]; |
|
int ret; |
|
|
|
cc[0] = c; |
|
cc[1] = nextc; |
|
|
|
ret = istrsenvisx(mbdst, NULL, cc, 1, flags, mbextra, NULL); |
|
if (ret < 0) |
|
return NULL; |
|
return mbdst + ret; |
} |
} |
|
|
int |
char * |
strsnvis(char *dst, size_t dlen, const char *csrc, int flag, const char *extra) |
snvis(char *mbdst, size_t dlen, int c, int flags, int nextc, const char *mbextra) |
{ |
{ |
return istrsnvis(dst, &dlen, csrc, flag, extra); |
char cc[2]; |
|
int ret; |
|
|
|
cc[0] = c; |
|
cc[1] = nextc; |
|
|
|
ret = istrsenvisx(mbdst, &dlen, cc, 1, flags, mbextra, NULL); |
|
if (ret < 0) |
|
return NULL; |
|
return mbdst + ret; |
} |
} |
|
|
static int |
int |
istrsnvisx(char *dst, size_t *dlen, const char *csrc, size_t len, int flag, |
strsvis(char *mbdst, const char *mbsrc, int flags, const char *mbextra) |
const char *extra) |
|
{ |
{ |
unsigned char c; |
return istrsenvisx(mbdst, NULL, mbsrc, 0, flags, mbextra, NULL); |
char *start; |
} |
char *nextra = NULL; |
|
const unsigned char *src = (const unsigned char *)csrc; |
|
visfun_t f; |
|
|
|
_DIAGASSERT(dst != NULL); |
int |
_DIAGASSERT(src != NULL); |
strsnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags, const char *mbextra) |
_DIAGASSERT(extra != NULL); |
{ |
MAKEEXTRALIST(flag, nextra, extra); |
return istrsenvisx(mbdst, &dlen, mbsrc, 0, flags, mbextra, NULL); |
if (! nextra) { |
} |
if (dlen && *dlen == 0) { |
|
errno = ENOSPC; |
|
return -1; |
|
} |
|
*dst = '\0'; /* can't create nextra, return "" */ |
|
return 0; |
|
} |
|
|
|
f = getvisfun(flag); |
int |
for (start = dst; len > 0; len--) { |
strsvisx(char *mbdst, const char *mbsrc, size_t len, int flags, const char *mbextra) |
c = *src++; |
{ |
dst = (*f)(dst, dlen, c, flag, len > 1 ? *src : '\0', nextra); |
return istrsenvisx(mbdst, NULL, mbsrc, len, flags, mbextra, NULL); |
if (dst == NULL) { |
|
errno = ENOSPC; |
|
return -1; |
|
} |
|
} |
|
free(nextra); |
|
if (dlen && *dlen == 0) { |
|
errno = ENOSPC; |
|
return -1; |
|
} |
|
*dst = '\0'; |
|
return (int)(dst - start); |
|
} |
} |
|
|
int |
int |
strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) |
strsnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags, |
|
const char *mbextra) |
{ |
{ |
return istrsnvisx(dst, NULL, csrc, len, flag, extra); |
return istrsenvisx(mbdst, &dlen, mbsrc, len, flags, mbextra, NULL); |
} |
} |
|
|
int |
int |
strsnvisx(char *dst, size_t dlen, const char *csrc, size_t len, int flag, |
strsenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags, |
const char *extra) |
const char *mbextra, int *cerr_ptr) |
{ |
{ |
return istrsnvisx(dst, &dlen, csrc, len, flag, extra); |
return istrsenvisx(mbdst, &dlen, mbsrc, len, flags, mbextra, cerr_ptr); |
} |
} |
#endif |
#endif |
|
|
Line 455 strsnvisx(char *dst, size_t dlen, const |
|
Line 605 strsnvisx(char *dst, size_t dlen, const |
|
/* |
/* |
* vis - visually encode characters |
* vis - visually encode characters |
*/ |
*/ |
static char * |
char * |
invis(char *dst, size_t *dlen, int c, int flag, int nextc) |
vis(char *mbdst, int c, int flags, int nextc) |
{ |
{ |
char *extra = NULL; |
char cc[2]; |
unsigned char uc = (unsigned char)c; |
int ret; |
visfun_t f; |
|
|
|
_DIAGASSERT(dst != NULL); |
cc[0] = c; |
|
cc[1] = nextc; |
|
|
MAKEEXTRALIST(flag, extra, ""); |
ret = istrsenvisx(mbdst, NULL, cc, 1, flags, "", NULL); |
if (! extra) { |
if (ret < 0) |
if (dlen && *dlen == 0) { |
|
errno = ENOSPC; |
|
return NULL; |
|
} |
|
*dst = '\0'; /* can't create extra, return "" */ |
|
return dst; |
|
} |
|
f = getvisfun(flag); |
|
dst = (*f)(dst, dlen, uc, flag, nextc, extra); |
|
free(extra); |
|
if (dst == NULL || (dlen && *dlen == 0)) { |
|
errno = ENOSPC; |
|
return NULL; |
return NULL; |
} |
return mbdst + ret; |
*dst = '\0'; |
|
return dst; |
|
} |
} |
|
|
char * |
char * |
vis(char *dst, int c, int flag, int nextc) |
nvis(char *mbdst, size_t dlen, int c, int flags, int nextc) |
{ |
{ |
return invis(dst, NULL, c, flag, nextc); |
char cc[2]; |
} |
int ret; |
|
|
char * |
cc[0] = c; |
nvis(char *dst, size_t dlen, int c, int flag, int nextc) |
cc[1] = nextc; |
{ |
|
return invis(dst, &dlen, c, flag, nextc); |
|
} |
|
|
|
|
ret = istrsenvisx(mbdst, &dlen, cc, 1, flags, "", NULL); |
|
if (ret < 0) |
|
return NULL; |
|
return mbdst + ret; |
|
} |
|
|
/* |
/* |
* strvis, strvisx - visually encode characters from src into dst |
* strvis - visually encode characters from src into dst |
* |
* |
* Dst must be 4 times the size of src to account for possible |
* Dst must be 4 times the size of src to account for possible |
* expansion. The length of dst, not including the trailing NULL, |
* expansion. The length of dst, not including the trailing NULL, |
* is returned. |
* is returned. |
* |
|
* Strvisx encodes exactly len bytes from src into dst. |
|
* This is useful for encoding a block of data. |
|
*/ |
*/ |
static int |
|
istrnvis(char *dst, size_t *dlen, const char *src, int flag) |
|
{ |
|
char *extra = NULL; |
|
int rv; |
|
|
|
MAKEEXTRALIST(flag, extra, ""); |
|
if (!extra) { |
|
if (dlen && *dlen == 0) { |
|
errno = ENOSPC; |
|
return -1; |
|
} |
|
*dst = '\0'; /* can't create extra, return "" */ |
|
return 0; |
|
} |
|
rv = istrsnvis(dst, dlen, src, flag, extra); |
|
free(extra); |
|
return rv; |
|
} |
|
|
|
int |
int |
strvis(char *dst, const char *src, int flag) |
strvis(char *mbdst, const char *mbsrc, int flags) |
{ |
{ |
return istrnvis(dst, NULL, src, flag); |
return istrsenvisx(mbdst, NULL, mbsrc, 0, flags, "", NULL); |
} |
} |
|
|
int |
int |
strnvis(char *dst, size_t dlen, const char *src, int flag) |
strnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags) |
{ |
{ |
return istrnvis(dst, &dlen, src, flag); |
return istrsenvisx(mbdst, &dlen, mbsrc, 0, flags, "", NULL); |
} |
} |
|
|
static int |
/* |
istrnvisx(char *dst, size_t *dlen, const char *src, size_t len, int flag) |
* strvisx - visually encode characters from src into dst |
{ |
* |
char *extra = NULL; |
* Dst must be 4 times the size of src to account for possible |
int rv; |
* expansion. The length of dst, not including the trailing NULL, |
|
* is returned. |
|
* |
|
* Strvisx encodes exactly len characters from src into dst. |
|
* This is useful for encoding a block of data. |
|
*/ |
|
|
MAKEEXTRALIST(flag, extra, ""); |
int |
if (!extra) { |
strvisx(char *mbdst, const char *mbsrc, size_t len, int flags) |
if (dlen && *dlen == 0) { |
{ |
errno = ENOSPC; |
return istrsenvisx(mbdst, NULL, mbsrc, len, flags, "", NULL); |
return -1; |
|
} |
|
*dst = '\0'; /* can't create extra, return "" */ |
|
return 0; |
|
} |
|
rv = istrsnvisx(dst, dlen, src, len, flag, extra); |
|
free(extra); |
|
return rv; |
|
} |
} |
|
|
int |
int |
strvisx(char *dst, const char *src, size_t len, int flag) |
strnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags) |
{ |
{ |
return istrnvisx(dst, NULL, src, len, flag); |
return istrsenvisx(mbdst, &dlen, mbsrc, len, flags, "", NULL); |
} |
} |
|
|
int |
int |
strnvisx(char *dst, size_t dlen, const char *src, size_t len, int flag) |
strenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags, |
|
int *cerr_ptr) |
{ |
{ |
return istrnvisx(dst, &dlen, src, len, flag); |
return istrsenvisx(mbdst, &dlen, mbsrc, len, flags, "", cerr_ptr); |
} |
} |
|
|
#endif |
#endif |