mirror of
https://gitlab.freedesktop.org/libbsd/libbsd.git
synced 2025-01-24 19:02:59 +01:00
Update vis/unvis modules from NetBSD
This commit is contained in:
parent
3efad64155
commit
2d7de186e9
11
COPYING
11
COPYING
@ -122,7 +122,6 @@ Files:
|
|||||||
src/strmode.c
|
src/strmode.c
|
||||||
src/strnstr.c
|
src/strnstr.c
|
||||||
src/unvis.c
|
src/unvis.c
|
||||||
src/vis.c
|
|
||||||
Copyright:
|
Copyright:
|
||||||
Copyright © 1980, 1982, 1986, 1989-1994
|
Copyright © 1980, 1982, 1986, 1989-1994
|
||||||
The Regents of the University of California. All rights reserved.
|
The Regents of the University of California. All rights reserved.
|
||||||
@ -315,6 +314,16 @@ License: BSD-2-clause-NetBSD
|
|||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Files:
|
||||||
|
src/vis.c
|
||||||
|
Copyright:
|
||||||
|
Copyright © 1989, 1993
|
||||||
|
The Regents of the University of California. All rights reserved.
|
||||||
|
.
|
||||||
|
Copyright © 1999, 2005 The NetBSD Foundation, Inc.
|
||||||
|
All rights reserved.
|
||||||
|
License: BSD-3-clause-Regents and BSD-2-clause-NetBSD
|
||||||
|
|
||||||
Files:
|
Files:
|
||||||
include/bsd/sys/endian.h
|
include/bsd/sys/endian.h
|
||||||
man/byteorder.3bsd
|
man/byteorder.3bsd
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
/* $NetBSD: vis.h,v 1.25 2017/04/23 01:57:36 christos Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1990, 1993
|
* Copyright (c) 1990, 1993
|
||||||
* The Regents of the University of California. All rights reserved.
|
* The Regents of the University of California. All rights reserved.
|
||||||
@ -27,7 +29,6 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)vis.h 8.1 (Berkeley) 6/2/93
|
* @(#)vis.h 8.1 (Berkeley) 6/2/93
|
||||||
* $FreeBSD: src/include/vis.h,v 1.11 2003/10/30 10:40:49 phk Exp $
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LIBBSD_VIS_H
|
#ifndef LIBBSD_VIS_H
|
||||||
@ -38,25 +39,34 @@
|
|||||||
/*
|
/*
|
||||||
* to select alternate encoding format
|
* to select alternate encoding format
|
||||||
*/
|
*/
|
||||||
#define VIS_OCTAL 0x01 /* use octal \ddd format */
|
#define VIS_OCTAL 0x0001 /* use octal \ddd format */
|
||||||
#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */
|
#define VIS_CSTYLE 0x0002 /* use \[nrft0..] where appropriate */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* to alter set of characters encoded (default is to encode all
|
* to alter set of characters encoded (default is to encode all
|
||||||
* non-graphic except space, tab, and newline).
|
* non-graphic except space, tab, and newline).
|
||||||
*/
|
*/
|
||||||
#define VIS_SP 0x04 /* also encode space */
|
#define VIS_SP 0x0004 /* also encode space */
|
||||||
#define VIS_TAB 0x08 /* also encode tab */
|
#define VIS_TAB 0x0008 /* also encode tab */
|
||||||
#define VIS_NL 0x10 /* also encode newline */
|
#define VIS_NL 0x0010 /* also encode newline */
|
||||||
#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
|
#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
|
||||||
#define VIS_SAFE 0x20 /* only encode "unsafe" characters */
|
#define VIS_SAFE 0x0020 /* only encode "unsafe" characters */
|
||||||
|
#define VIS_DQ 0x8000 /* also encode double quotes */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* other
|
* other
|
||||||
*/
|
*/
|
||||||
#define VIS_NOSLASH 0x40 /* inhibit printing '\' */
|
#define VIS_NOSLASH 0x0040 /* inhibit printing '\' */
|
||||||
#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */
|
#define VIS_HTTP1808 0x0080 /* http-style escape % hex hex */
|
||||||
#define VIS_GLOB 0x100 /* encode glob(3) magics */
|
#define VIS_HTTPSTYLE 0x0080 /* http-style escape % hex hex */
|
||||||
|
#define VIS_MIMESTYLE 0x0100 /* mime-style escape = HEX HEX */
|
||||||
|
#define VIS_HTTP1866 0x0200 /* http-style &#num; or &string; */
|
||||||
|
#define VIS_NOESCAPE 0x0400 /* don't decode `\' */
|
||||||
|
#define _VIS_END 0x0800 /* for unvis */
|
||||||
|
#define VIS_GLOB 0x1000 /* encode glob(3) magic characters */
|
||||||
|
#define VIS_SHELL 0x2000 /* encode shell special characters [not glob] */
|
||||||
|
#define VIS_META (VIS_WHITE | VIS_GLOB | VIS_SHELL)
|
||||||
|
#define VIS_NOLOCALE 0x4000 /* encode using the C locale */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* unvis return codes
|
* unvis return codes
|
||||||
@ -70,7 +80,7 @@
|
|||||||
/*
|
/*
|
||||||
* unvis flags
|
* unvis flags
|
||||||
*/
|
*/
|
||||||
#define UNVIS_END 1 /* no more characters */
|
#define UNVIS_END _VIS_END /* no more characters */
|
||||||
|
|
||||||
#ifdef LIBBSD_OVERLAY
|
#ifdef LIBBSD_OVERLAY
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
@ -80,12 +90,33 @@
|
|||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
char *vis(char *, int, int, int);
|
char *vis(char *, int, int, int);
|
||||||
|
char *nvis(char *, size_t, int, int, int);
|
||||||
|
|
||||||
|
char *svis(char *, int, int, int, const char *);
|
||||||
|
char *snvis(char *, size_t, int, int, int, const char *);
|
||||||
|
|
||||||
int strvis(char *, const char *, int);
|
int strvis(char *, const char *, int);
|
||||||
|
int stravis(char **, const char *, int);
|
||||||
|
int strnvis(char *, size_t, const char *, int);
|
||||||
|
|
||||||
|
int strsvis(char *, const char *, int, const char *);
|
||||||
|
int strsnvis(char *, size_t, const char *, int, const char *);
|
||||||
|
|
||||||
int strvisx(char *, const char *, size_t, int);
|
int strvisx(char *, const char *, size_t, int);
|
||||||
int strnvis(char *, const char *, size_t, int);
|
int strnvisx(char *, size_t, const char *, size_t, int);
|
||||||
|
int strenvisx(char *, size_t, const char *, size_t, int, int *);
|
||||||
|
|
||||||
|
int strsvisx(char *, const char *, size_t, int, const char *);
|
||||||
|
int strsnvisx(char *, size_t, const char *, size_t, int, const char *);
|
||||||
|
int strsenvisx(char *, size_t, const char *, size_t , int, const char *,
|
||||||
|
int *);
|
||||||
|
|
||||||
int strunvis(char *, const char *);
|
int strunvis(char *, const char *);
|
||||||
|
int strnunvis(char *, size_t, const char *);
|
||||||
|
|
||||||
int strunvisx(char *, const char *, int);
|
int strunvisx(char *, const char *, int);
|
||||||
ssize_t strnunvis(char *, const char *, size_t);
|
int strnunvisx(char *, size_t, const char *, int);
|
||||||
|
|
||||||
int unvis(char *, int, int *, int);
|
int unvis(char *, int, int *, int);
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
195
man/unvis.3bsd
195
man/unvis.3bsd
@ -1,4 +1,4 @@
|
|||||||
.\" $OpenBSD: unvis.3,v 1.15 2005/07/22 03:16:58 jaredy Exp $
|
.\" $NetBSD: unvis.3,v 1.29 2017/10/24 19:14:55 abhinav Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 1989, 1991, 1993
|
.\" Copyright (c) 1989, 1991, 1993
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
@ -27,13 +27,17 @@
|
|||||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: May 31 2007 $
|
.\" @(#)unvis.3 8.2 (Berkeley) 12/11/93
|
||||||
|
.\"
|
||||||
|
.Dd March 12, 2011
|
||||||
.Dt UNVIS 3bsd
|
.Dt UNVIS 3bsd
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm unvis ,
|
.Nm unvis ,
|
||||||
.Nm strunvis ,
|
.Nm strunvis ,
|
||||||
.Nm strnunvis
|
.Nm strnunvis ,
|
||||||
|
.Nm strunvisx ,
|
||||||
|
.Nm strnunvisx
|
||||||
.Nd decode a visual representation of characters
|
.Nd decode a visual representation of characters
|
||||||
.Sh LIBRARY
|
.Sh LIBRARY
|
||||||
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
|
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
|
||||||
@ -44,88 +48,91 @@
|
|||||||
.Xr libbsd 7
|
.Xr libbsd 7
|
||||||
for include usage.)
|
for include usage.)
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn unvis "char *cp" "char c" "int *astate" "int flag"
|
.Fn unvis "char *cp" "int c" "int *astate" "int flag"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn strunvis "char *dst" "char *src"
|
.Fn strunvis "char *dst" "const char *src"
|
||||||
.Ft ssize_t
|
.Ft int
|
||||||
.Fn strnunvis "char *dst" "char *src" "size_t size"
|
.Fn strnunvis "char *dst" "size_t dlen" "const char *src"
|
||||||
|
.Ft int
|
||||||
|
.Fn strunvisx "char *dst" "const char *src" "int flag"
|
||||||
|
.Ft int
|
||||||
|
.Fn strnunvisx "char *dst" "size_t dlen" "const char *src" "int flag"
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Fn unvis ,
|
.Fn unvis ,
|
||||||
.Fn strunvis
|
.Fn strunvis
|
||||||
and
|
and
|
||||||
.Fn strnunvis
|
.Fn strunvisx
|
||||||
functions are used to decode a visual representation of characters,
|
functions
|
||||||
as produced by the
|
are used to decode a visual representation of characters, as produced
|
||||||
|
by the
|
||||||
.Xr vis 3bsd
|
.Xr vis 3bsd
|
||||||
function, back into the original form.
|
function, back into
|
||||||
|
the original form.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
.Fn unvis
|
.Fn unvis
|
||||||
is called with successive characters in
|
function is called with successive characters in
|
||||||
.Fa c
|
.Ar c
|
||||||
until a valid
|
until a valid sequence is recognized, at which time the decoded
|
||||||
sequence is recognized, at which time the decoded character is
|
character is available at the character pointed to by
|
||||||
available at the character pointed to by
|
.Ar cp .
|
||||||
.Fa cp .
|
|
||||||
.Pp
|
.Pp
|
||||||
|
The
|
||||||
.Fn strunvis
|
.Fn strunvis
|
||||||
decodes the characters pointed to by
|
function decodes the characters pointed to by
|
||||||
.Fa src
|
.Ar src
|
||||||
into the buffer pointed to by
|
into the buffer pointed to by
|
||||||
.Fa dst .
|
.Ar dst .
|
||||||
.Pp
|
|
||||||
.Fn strnunvis
|
|
||||||
decodes the characters pointed to by
|
|
||||||
.Fa src
|
|
||||||
into the buffer pointed to by
|
|
||||||
.Fa dst ,
|
|
||||||
writing a maximum of
|
|
||||||
.Fa size
|
|
||||||
bytes.
|
|
||||||
The
|
The
|
||||||
.Fn strunvis
|
.Fn strunvis
|
||||||
function simply copies
|
function simply copies
|
||||||
.Fa src
|
.Ar src
|
||||||
to
|
to
|
||||||
.Fa dst ,
|
.Ar dst ,
|
||||||
decoding any escape sequences along the way,
|
decoding any escape sequences along the way,
|
||||||
and returns the number of characters placed into
|
and returns the number of characters placed into
|
||||||
.Fa dst ,
|
.Ar dst ,
|
||||||
or \-1 if an
|
or \-1 if an
|
||||||
invalid escape sequence was detected.
|
invalid escape sequence was detected.
|
||||||
The size of
|
The size of
|
||||||
.Fa dst
|
.Ar dst
|
||||||
should be
|
should be equal to the size of
|
||||||
equal to the size of
|
.Ar src
|
||||||
.Fa src
|
|
||||||
(that is, no expansion takes place during decoding).
|
(that is, no expansion takes place during decoding).
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Fn strunvisx
|
||||||
|
function does the same as the
|
||||||
.Fn strunvis
|
.Fn strunvis
|
||||||
terminates the destination string with a trailing NUL byte;
|
function,
|
||||||
.Fn strnunvis
|
but it allows you to add a flag that specifies the style the string
|
||||||
does so if
|
.Ar src
|
||||||
.Fa size
|
is encoded with.
|
||||||
is larger than 0.
|
Currently, the supported flags are:
|
||||||
|
.Dv VIS_HTTPSTYLE
|
||||||
|
and
|
||||||
|
.Dv VIS_MIMESTYLE .
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Fn unvis
|
.Fn unvis
|
||||||
function implements a state machine that can be used to decode an arbitrary
|
function implements a state machine that can be used to decode an
|
||||||
stream of bytes.
|
arbitrary stream of bytes.
|
||||||
All state associated with the bytes being decoded is stored outside the
|
All state associated with the bytes being decoded is stored outside the
|
||||||
.Fn unvis
|
.Fn unvis
|
||||||
function (that is, a pointer to the state is passed in), so
|
function (that is, a pointer to the state is passed in), so
|
||||||
calls decoding different streams can be freely intermixed.
|
calls decoding different streams can be freely intermixed.
|
||||||
To start decoding a stream of bytes, first initialize an integer
|
To start decoding a stream of bytes, first initialize an integer to zero.
|
||||||
to zero.
|
|
||||||
Call
|
Call
|
||||||
.Fn unvis
|
.Fn unvis
|
||||||
with each successive byte, along with a pointer
|
with each successive byte, along with a pointer
|
||||||
to this integer, and a pointer to a destination character.
|
to this integer, and a pointer to a destination character.
|
||||||
.Sh RETURN VALUES
|
|
||||||
The
|
The
|
||||||
.Fn unvis
|
.Fn unvis
|
||||||
function has several return codes that must be handled properly.
|
function has several return codes that must be handled properly.
|
||||||
They are:
|
They are:
|
||||||
.Bl -tag -width UNVIS_VALIDPUSH
|
.Bl -tag -width UNVIS_VALIDPUSH
|
||||||
.It Li \&0 (zero)
|
.It Li \&0 No (zero)
|
||||||
Another character is necessary; nothing has been recognized yet.
|
Another character is necessary; nothing has been recognized yet.
|
||||||
.It Dv UNVIS_VALID
|
.It Dv UNVIS_VALID
|
||||||
A valid character has been recognized and is available at the location
|
A valid character has been recognized and is available at the location
|
||||||
@ -140,30 +147,41 @@ however, the character currently passed in should be passed in again.
|
|||||||
A valid sequence was detected, but no character was produced.
|
A valid sequence was detected, but no character was produced.
|
||||||
This return code is necessary to indicate a logical break between characters.
|
This return code is necessary to indicate a logical break between characters.
|
||||||
.It Dv UNVIS_SYNBAD
|
.It Dv UNVIS_SYNBAD
|
||||||
An invalid escape sequence was detected, or the decoder is in an
|
An invalid escape sequence was detected, or the decoder is in an unknown state.
|
||||||
unknown state.
|
|
||||||
The decoder is placed into the starting state.
|
The decoder is placed into the starting state.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
When all bytes in the stream have been processed, call
|
When all bytes in the stream have been processed, call
|
||||||
.Fn unvis
|
.Fn unvis
|
||||||
one more time with
|
one more time with flag set to
|
||||||
.Fa flag
|
|
||||||
set to
|
|
||||||
.Dv UNVIS_END
|
.Dv UNVIS_END
|
||||||
to extract any remaining character (the character passed in is ignored).
|
to extract any remaining character (the character passed in is ignored).
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Fn strunvis
|
.Fa flag
|
||||||
function returns the number of bytes written (not counting
|
argument is also used to specify the encoding style of the source.
|
||||||
the trailing NUL byte) or \-1 if an error occurred.
|
If set to
|
||||||
|
.Dv VIS_HTTPSTYLE
|
||||||
|
or
|
||||||
|
.Dv VIS_HTTP1808 ,
|
||||||
|
.Fn unvis
|
||||||
|
will decode URI strings as specified in RFC 1808.
|
||||||
|
If set to
|
||||||
|
.Dv VIS_HTTP1866 ,
|
||||||
|
.Fn unvis
|
||||||
|
will decode entity references and numeric character references
|
||||||
|
as specified in RFC 1866.
|
||||||
|
If set to
|
||||||
|
.Dv VIS_MIMESTYLE ,
|
||||||
|
.Fn unvis
|
||||||
|
will decode MIME Quoted-Printable strings as specified in RFC 2045.
|
||||||
|
If set to
|
||||||
|
.Dv VIS_NOESCAPE ,
|
||||||
|
.Fn unvis
|
||||||
|
will not decode
|
||||||
|
.Ql \e
|
||||||
|
quoted characters.
|
||||||
.Pp
|
.Pp
|
||||||
The
|
|
||||||
.Fn strnunvis
|
|
||||||
function returns the number of bytes (not counting the trailing NUL byte)
|
|
||||||
that would be needed to fully convert the input string, or \-1 if an
|
|
||||||
error occurred.
|
|
||||||
.Sh EXAMPLES
|
|
||||||
The following code fragment illustrates a proper use of
|
The following code fragment illustrates a proper use of
|
||||||
.Fn unvis .
|
.Fn unvis .
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
@ -183,19 +201,66 @@ again:
|
|||||||
(void)putchar(out);
|
(void)putchar(out);
|
||||||
goto again;
|
goto again;
|
||||||
case UNVIS_SYNBAD:
|
case UNVIS_SYNBAD:
|
||||||
(void)fprintf(stderr, "bad sequence!\en");
|
errx(EXIT_FAILURE, "Bad character sequence!");
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unvis(&out, (char)0, &state, UNVIS_END) == UNVIS_VALID)
|
if (unvis(&out, '\e0', &state, UNVIS_END) == UNVIS_VALID)
|
||||||
(void)putchar(out);
|
(void)putchar(out);
|
||||||
.Ed
|
.Ed
|
||||||
|
.Sh ERRORS
|
||||||
|
The functions
|
||||||
|
.Fn strunvis ,
|
||||||
|
.Fn strnunvis ,
|
||||||
|
.Fn strunvisx ,
|
||||||
|
and
|
||||||
|
.Fn strnunvisx
|
||||||
|
will return \-1 on error and set
|
||||||
|
.Va errno
|
||||||
|
to:
|
||||||
|
.Bl -tag -width Er
|
||||||
|
.It Bq Er EINVAL
|
||||||
|
An invalid escape sequence was detected, or the decoder is in an unknown state.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
In addition the functions
|
||||||
|
.Fn strnunvis
|
||||||
|
and
|
||||||
|
.Fn strnunvisx
|
||||||
|
will can also set
|
||||||
|
.Va errno
|
||||||
|
on error to:
|
||||||
|
.Bl -tag -width Er
|
||||||
|
.It Bq Er ENOSPC
|
||||||
|
Not enough space to perform the conversion.
|
||||||
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr unvis 1 ,
|
.Xr unvis 1 ,
|
||||||
.Xr vis 1 ,
|
.Xr vis 1 ,
|
||||||
.Xr vis 3bsd
|
.Xr vis 3bsd
|
||||||
|
.Rs
|
||||||
|
.%A R. Fielding
|
||||||
|
.%T Relative Uniform Resource Locators
|
||||||
|
.%O RFC1808
|
||||||
|
.Re
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
The
|
The
|
||||||
.Fn unvis
|
.Fn unvis
|
||||||
function first appeared in
|
function
|
||||||
|
first appeared in
|
||||||
.Bx 4.4 .
|
.Bx 4.4 .
|
||||||
|
The
|
||||||
|
.Fn strnunvis
|
||||||
|
and
|
||||||
|
.Fn strnunvisx
|
||||||
|
functions appeared in
|
||||||
|
.Nx 6.0 .
|
||||||
|
.Sh BUGS
|
||||||
|
The names
|
||||||
|
.Dv VIS_HTTP1808
|
||||||
|
and
|
||||||
|
.Dv VIS_HTTP1866
|
||||||
|
are wrong.
|
||||||
|
Percent-encoding was defined in RFC 1738, the original RFC for URL.
|
||||||
|
RFC 1866 defines HTML 2.0, an application of SGML, from which it
|
||||||
|
inherits concepts of numeric character references and entity
|
||||||
|
references.
|
||||||
|
444
man/vis.3bsd
444
man/vis.3bsd
@ -1,4 +1,4 @@
|
|||||||
.\" $OpenBSD: vis.3,v 1.23 2005/08/28 19:51:27 millert Exp $
|
.\" $NetBSD: vis.3,v 1.49 2017/08/05 20:22:29 wiz Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 1989, 1991, 1993
|
.\" Copyright (c) 1989, 1991, 1993
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
@ -27,53 +27,87 @@
|
|||||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: May 31 2007 $
|
.\" @(#)vis.3 8.1 (Berkeley) 6/9/93
|
||||||
|
.\"
|
||||||
|
.Dd April 22, 2017
|
||||||
.Dt VIS 3bsd
|
.Dt VIS 3bsd
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm vis ,
|
.Nm vis ,
|
||||||
|
.Nm nvis ,
|
||||||
.Nm strvis ,
|
.Nm strvis ,
|
||||||
|
.Nm stravis ,
|
||||||
.Nm strnvis ,
|
.Nm strnvis ,
|
||||||
.Nm strvisx
|
.Nm strvisx ,
|
||||||
|
.Nm strnvisx ,
|
||||||
|
.Nm strenvisx ,
|
||||||
|
.Nm svis ,
|
||||||
|
.Nm snvis ,
|
||||||
|
.Nm strsvis ,
|
||||||
|
.Nm strsnvis ,
|
||||||
|
.Nm strsvisx ,
|
||||||
|
.Nm strsnvisx ,
|
||||||
|
.Nm strsenvisx
|
||||||
.Nd visually encode characters
|
.Nd visually encode characters
|
||||||
.Sh LIBRARY
|
.Sh LIBRARY
|
||||||
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
|
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
|
||||||
.Lb libbsd
|
.Lb libbsd
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.In stdlib.h
|
|
||||||
.In vis.h
|
.In vis.h
|
||||||
(See
|
(See
|
||||||
.Xr libbsd 7
|
.Xr libbsd 7
|
||||||
for include usage.)
|
for include usage.)
|
||||||
.Ft char *
|
.Ft char *
|
||||||
.Fn vis "char *dst" "int c" "int flag" "int nextc"
|
.Fn vis "char *dst" "int c" "int flag" "int nextc"
|
||||||
|
.Ft char *
|
||||||
|
.Fn nvis "char *dst" "size_t dlen" "int c" "int flag" "int nextc"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn strvis "char *dst" "const char *src" "int flag"
|
.Fn strvis "char *dst" "const char *src" "int flag"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn strnvis "char *dst" "const char *src" "size_t size" "int flag"
|
.Fn stravis "char **dst" "const char *src" "int flag"
|
||||||
|
.Ft int
|
||||||
|
.Fn strnvis "char *dst" "size_t dlen" "const char *src" "int flag"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn strvisx "char *dst" "const char *src" "size_t len" "int flag"
|
.Fn strvisx "char *dst" "const char *src" "size_t len" "int flag"
|
||||||
|
.Ft int
|
||||||
|
.Fn strnvisx "char *dst" "size_t dlen" "const char *src" "size_t len" "int flag"
|
||||||
|
.Ft int
|
||||||
|
.Fn strenvisx "char *dst" "size_t dlen" "const char *src" "size_t len" "int flag" "int *cerr_ptr"
|
||||||
|
.Ft char *
|
||||||
|
.Fn svis "char *dst" "int c" "int flag" "int nextc" "const char *extra"
|
||||||
|
.Ft char *
|
||||||
|
.Fn snvis "char *dst" "size_t dlen" "int c" "int flag" "int nextc" "const char *extra"
|
||||||
|
.Ft int
|
||||||
|
.Fn strsvis "char *dst" "const char *src" "int flag" "const char *extra"
|
||||||
|
.Ft int
|
||||||
|
.Fn strsnvis "char *dst" "size_t dlen" "const char *src" "int flag" "const char *extra"
|
||||||
|
.Ft int
|
||||||
|
.Fn strsvisx "char *dst" "const char *src" "size_t len" "int flag" "const char *extra"
|
||||||
|
.Ft int
|
||||||
|
.Fn strsnvisx "char *dst" "size_t dlen" "const char *src" "size_t len" "int flag" "const char *extra"
|
||||||
|
.Ft int
|
||||||
|
.Fn strsenvisx "char *dst" "size_t dlen" "const char *src" "size_t len" "int flag" "const char *extra" "int *cerr_ptr"
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Fn vis
|
.Fn vis
|
||||||
function copies into
|
function
|
||||||
|
copies into
|
||||||
.Fa dst
|
.Fa dst
|
||||||
a string which represents the character
|
a string which represents the character
|
||||||
.Fa c .
|
.Fa c .
|
||||||
If
|
If
|
||||||
.Fa c
|
.Fa c
|
||||||
needs no encoding, it is copied in unaltered.
|
needs no encoding, it is copied in unaltered.
|
||||||
The string is NUL terminated and a pointer to the end of the string is
|
The string is null terminated, and a pointer to the end of the string is
|
||||||
returned.
|
returned.
|
||||||
The maximum length of any encoding is four
|
The maximum length of any encoding is four
|
||||||
characters (not including the trailing NUL);
|
bytes (not including the trailing
|
||||||
|
.Dv NUL ) ;
|
||||||
thus, when
|
thus, when
|
||||||
encoding a set of characters into a buffer, the size of the buffer should
|
encoding a set of characters into a buffer, the size of the buffer should
|
||||||
be four times the number of characters encoded, plus one for the trailing
|
be four times the number of bytes encoded, plus one for the trailing
|
||||||
NUL.
|
.Dv NUL .
|
||||||
The
|
The flag parameter is used for altering the default range of
|
||||||
.Fa flag
|
|
||||||
parameter is used for altering the default range of
|
|
||||||
characters considered for encoding and for altering the visual
|
characters considered for encoding and for altering the visual
|
||||||
representation.
|
representation.
|
||||||
The additional character,
|
The additional character,
|
||||||
@ -84,9 +118,11 @@ encoding format (explained below).
|
|||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Fn strvis ,
|
.Fn strvis ,
|
||||||
.Fn strnvis
|
.Fn stravis ,
|
||||||
|
.Fn strnvis ,
|
||||||
|
.Fn strvisx ,
|
||||||
and
|
and
|
||||||
.Fn strvisx
|
.Fn strnvisx
|
||||||
functions copy into
|
functions copy into
|
||||||
.Fa dst
|
.Fa dst
|
||||||
a visual representation of
|
a visual representation of
|
||||||
@ -94,89 +130,153 @@ the string
|
|||||||
.Fa src .
|
.Fa src .
|
||||||
The
|
The
|
||||||
.Fn strvis
|
.Fn strvis
|
||||||
function encodes characters from
|
and
|
||||||
.Fa src
|
|
||||||
up to the first NUL.
|
|
||||||
The
|
|
||||||
.Fn strnvis
|
.Fn strnvis
|
||||||
function encodes characters from
|
functions encode characters from
|
||||||
.Fa src
|
.Fa src
|
||||||
up to the first NUL or the end of
|
up to the
|
||||||
.Fa dst ,
|
first
|
||||||
as indicated by
|
.Dv NUL .
|
||||||
.Fa size .
|
|
||||||
The
|
The
|
||||||
.Fn strvisx
|
.Fn strvisx
|
||||||
function encodes exactly
|
and
|
||||||
|
.Fn strnvisx
|
||||||
|
functions encode exactly
|
||||||
.Fa len
|
.Fa len
|
||||||
characters from
|
characters from
|
||||||
.Fa src
|
.Fa src
|
||||||
(this
|
(this
|
||||||
is useful for encoding a block of data that may contain NULs).
|
is useful for encoding a block of data that may contain
|
||||||
All three forms NUL terminate
|
.Dv NUL Ns 's ) .
|
||||||
.Fa dst ,
|
Both forms
|
||||||
except for
|
.Dv NUL
|
||||||
.Fn strnvis
|
terminate
|
||||||
when
|
.Fa dst .
|
||||||
.Fa size
|
The size of
|
||||||
is zero, in which case
|
|
||||||
.Fa dst
|
|
||||||
is not touched.
|
|
||||||
For
|
|
||||||
.Fn strvis
|
|
||||||
and
|
|
||||||
.Fn strvisx ,
|
|
||||||
the size of
|
|
||||||
.Fa dst
|
.Fa dst
|
||||||
must be four times the number
|
must be four times the number
|
||||||
of characters encoded from
|
of bytes encoded from
|
||||||
.Fa src
|
.Fa src
|
||||||
(plus one for the NUL).
|
(plus one for the
|
||||||
.Fn strvis
|
.Dv NUL ) .
|
||||||
|
Both
|
||||||
|
forms return the number of characters in
|
||||||
|
.Fa dst
|
||||||
|
(not including the trailing
|
||||||
|
.Dv NUL ) .
|
||||||
|
The
|
||||||
|
.Fn stravis
|
||||||
|
function allocates space dynamically to hold the string.
|
||||||
|
The
|
||||||
|
.Dq Nm n
|
||||||
|
versions of the functions also take an additional argument
|
||||||
|
.Fa dlen
|
||||||
|
that indicates the length of the
|
||||||
|
.Fa dst
|
||||||
|
buffer.
|
||||||
|
If
|
||||||
|
.Fa dlen
|
||||||
|
is not large enough to fit the converted string then the
|
||||||
|
.Fn strnvis
|
||||||
and
|
and
|
||||||
.Fn strvisx
|
.Fn strnvisx
|
||||||
return the number of characters in
|
functions return \-1 and set
|
||||||
.Fa dst
|
.Va errno
|
||||||
(not including the trailing NUL).
|
to
|
||||||
.Fn strnvis
|
.Dv ENOSPC .
|
||||||
returns the length that
|
The
|
||||||
.Fa dst
|
.Fn strenvisx
|
||||||
would become if it were of unlimited size (similar to
|
function takes an additional argument,
|
||||||
.Xr snprintf 3
|
.Fa cerr_ptr ,
|
||||||
or
|
that is used to pass in and out a multibyte conversion error flag.
|
||||||
.Xr strlcpy 3bsd ) .
|
This is useful when processing single characters at a time when
|
||||||
This can be used to detect truncation but it also means that
|
it is possible that the locale may be set to something other
|
||||||
the return value of
|
than the locale of the characters in the input data.
|
||||||
.Fn strnvis
|
.Pp
|
||||||
must not be used without checking it against
|
The functions
|
||||||
.Fa size .
|
.Fn svis ,
|
||||||
|
.Fn snvis ,
|
||||||
|
.Fn strsvis ,
|
||||||
|
.Fn strsnvis ,
|
||||||
|
.Fn strsvisx ,
|
||||||
|
.Fn strsnvisx ,
|
||||||
|
and
|
||||||
|
.Fn strsenvisx
|
||||||
|
correspond to
|
||||||
|
.Fn vis ,
|
||||||
|
.Fn nvis ,
|
||||||
|
.Fn strvis ,
|
||||||
|
.Fn strnvis ,
|
||||||
|
.Fn strvisx ,
|
||||||
|
.Fn strnvisx ,
|
||||||
|
and
|
||||||
|
.Fn strenvisx
|
||||||
|
but have an additional argument
|
||||||
|
.Fa extra ,
|
||||||
|
pointing to a
|
||||||
|
.Dv NUL
|
||||||
|
terminated list of characters.
|
||||||
|
These characters will be copied encoded or backslash-escaped into
|
||||||
|
.Fa dst .
|
||||||
|
These functions are useful e.g. to remove the special meaning
|
||||||
|
of certain characters to shells.
|
||||||
.Pp
|
.Pp
|
||||||
The encoding is a unique, invertible representation composed entirely of
|
The encoding is a unique, invertible representation composed entirely of
|
||||||
graphic characters; it can be decoded back into the original form using
|
graphic characters; it can be decoded back into the original form using
|
||||||
the
|
the
|
||||||
.Xr unvis 3bsd
|
.Xr unvis 3bsd ,
|
||||||
or
|
|
||||||
.Xr strunvis 3bsd
|
.Xr strunvis 3bsd
|
||||||
|
or
|
||||||
|
.Xr strnunvis 3bsd
|
||||||
functions.
|
functions.
|
||||||
.Pp
|
.Pp
|
||||||
There are two parameters that can be controlled: the range of
|
There are two parameters that can be controlled: the range of
|
||||||
characters that are encoded, and the type
|
characters that are encoded (applies only to
|
||||||
of representation used.
|
.Fn vis ,
|
||||||
By default, all non-graphic characters
|
.Fn nvis ,
|
||||||
except space, tab, and newline are encoded
|
.Fn strvis ,
|
||||||
(see
|
.Fn strnvis ,
|
||||||
|
.Fn strvisx ,
|
||||||
|
and
|
||||||
|
.Fn strnvisx ) ,
|
||||||
|
and the type of representation used.
|
||||||
|
By default, all non-graphic characters,
|
||||||
|
except space, tab, and newline are encoded (see
|
||||||
.Xr isgraph 3 ) .
|
.Xr isgraph 3 ) .
|
||||||
The following flags
|
The following flags
|
||||||
alter this:
|
alter this:
|
||||||
.Bl -tag -width VIS_WHITEX
|
.Bl -tag -width VIS_WHITEX
|
||||||
|
.It Dv VIS_DQ
|
||||||
|
Also encode double quotes
|
||||||
.It Dv VIS_GLOB
|
.It Dv VIS_GLOB
|
||||||
Also encode magic characters recognized by
|
Also encode the magic characters
|
||||||
.Xr glob 3
|
.Ql ( * ,
|
||||||
.Pf ( Ql * ,
|
|
||||||
.Ql \&? ,
|
.Ql \&? ,
|
||||||
.Ql \&[ )
|
.Ql \&[ ,
|
||||||
and
|
and
|
||||||
.Ql # .
|
.Ql # )
|
||||||
|
recognized by
|
||||||
|
.Xr glob 3 .
|
||||||
|
.It Dv VIS_SHELL
|
||||||
|
Also encode the meta characters used by shells (in addition to the glob
|
||||||
|
characters):
|
||||||
|
.Ql ( ' ,
|
||||||
|
.Ql ` ,
|
||||||
|
.Ql \&" ,
|
||||||
|
.Ql \&; ,
|
||||||
|
.Ql & ,
|
||||||
|
.Ql < ,
|
||||||
|
.Ql > ,
|
||||||
|
.Ql \&( ,
|
||||||
|
.Ql \&) ,
|
||||||
|
.Ql \&| ,
|
||||||
|
.Ql \&] ,
|
||||||
|
.Ql \e ,
|
||||||
|
.Ql $ ,
|
||||||
|
.Ql \&! ,
|
||||||
|
.Ql \&^ ,
|
||||||
|
and
|
||||||
|
.Ql ~ ) .
|
||||||
.It Dv VIS_SP
|
.It Dv VIS_SP
|
||||||
Also encode space.
|
Also encode space.
|
||||||
.It Dv VIS_TAB
|
.It Dv VIS_TAB
|
||||||
@ -185,34 +285,56 @@ Also encode tab.
|
|||||||
Also encode newline.
|
Also encode newline.
|
||||||
.It Dv VIS_WHITE
|
.It Dv VIS_WHITE
|
||||||
Synonym for
|
Synonym for
|
||||||
.Dv VIS_SP
|
.Dv VIS_SP | VIS_TAB | VIS_NL .
|
||||||
\&|
|
.It Dv VIS_META
|
||||||
.Dv VIS_TAB
|
Synonym for
|
||||||
\&|
|
.Dv VIS_WHITE | VIS_GLOB | VIS_SHELL .
|
||||||
.Dv VIS_NL .
|
|
||||||
.It Dv VIS_SAFE
|
.It Dv VIS_SAFE
|
||||||
Only encode
|
Only encode
|
||||||
.Dq unsafe
|
.Dq unsafe
|
||||||
characters.
|
characters.
|
||||||
These are control characters which may cause common terminals to perform
|
Unsafe means control characters which may cause common terminals to perform
|
||||||
unexpected functions.
|
unexpected functions.
|
||||||
Currently this form allows space,
|
Currently this form allows space, tab, newline, backspace, bell, and
|
||||||
tab, newline, backspace, bell, and return -- in addition
|
return \(em in addition to all graphic characters \(em unencoded.
|
||||||
to all graphic characters -- unencoded.
|
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
There are three forms of encoding.
|
(The above flags have no effect for
|
||||||
All forms use the backslash
|
.Fn svis ,
|
||||||
|
.Fn snvis ,
|
||||||
|
.Fn strsvis ,
|
||||||
|
.Fn strsnvis ,
|
||||||
|
.Fn strsvisx ,
|
||||||
|
and
|
||||||
|
.Fn strsnvisx .
|
||||||
|
When using these functions, place all graphic characters to be
|
||||||
|
encoded in an array pointed to by
|
||||||
|
.Fa extra .
|
||||||
|
In general, the backslash character should be included in this array, see the
|
||||||
|
warning on the use of the
|
||||||
|
.Dv VIS_NOSLASH
|
||||||
|
flag below).
|
||||||
|
.Pp
|
||||||
|
There are six forms of encoding.
|
||||||
|
All forms use the backslash character
|
||||||
.Ql \e
|
.Ql \e
|
||||||
character to introduce a special
|
to introduce a special
|
||||||
sequence; two backslashes are used to represent a real backslash.
|
sequence; two backslashes are used to represent a real backslash,
|
||||||
|
except
|
||||||
|
.Dv VIS_HTTPSTYLE
|
||||||
|
that uses
|
||||||
|
.Ql % ,
|
||||||
|
or
|
||||||
|
.Dv VIS_MIMESTYLE
|
||||||
|
that uses
|
||||||
|
.Ql = .
|
||||||
These are the visual formats:
|
These are the visual formats:
|
||||||
.Bl -tag -width VIS_CSTYLE
|
.Bl -tag -width VIS_CSTYLE
|
||||||
.It (default)
|
.It (default)
|
||||||
Use an
|
Use an
|
||||||
.Ql M
|
.Ql M
|
||||||
to represent meta characters (characters with the 8th
|
to represent meta characters (characters with the 8th
|
||||||
bit set), and use a caret
|
bit set), and use caret
|
||||||
.Ql ^
|
.Ql ^
|
||||||
to represent control characters (see
|
to represent control characters (see
|
||||||
.Xr iscntrl 3 ) .
|
.Xr iscntrl 3 ) .
|
||||||
@ -256,27 +378,27 @@ space.
|
|||||||
.It Dv \e240
|
.It Dv \e240
|
||||||
Represents Meta-space.
|
Represents Meta-space.
|
||||||
.El
|
.El
|
||||||
.Pp
|
|
||||||
.It Dv VIS_CSTYLE
|
.It Dv VIS_CSTYLE
|
||||||
Use C-style backslash sequences to represent standard non-printable
|
Use C-style backslash sequences to represent standard non-printable
|
||||||
characters.
|
characters.
|
||||||
The following sequences are used to represent the indicated characters:
|
The following sequences are used to represent the indicated characters:
|
||||||
.Bd -unfilled -offset indent
|
.Bd -unfilled -offset indent
|
||||||
.Li \ea Tn - BEL No (007)
|
.Li \ea Tn \(em BEL No (007)
|
||||||
.Li \eb Tn - BS No (010)
|
.Li \eb Tn \(em BS No (010)
|
||||||
.Li \ef Tn - NP No (014)
|
.Li \ef Tn \(em NP No (014)
|
||||||
.Li \en Tn - NL No (012)
|
.Li \en Tn \(em NL No (012)
|
||||||
.Li \er Tn - CR No (015)
|
.Li \er Tn \(em CR No (015)
|
||||||
.Li \es Tn - SP No (040)
|
.Li \es Tn \(em SP No (040)
|
||||||
.Li \et Tn - HT No (011)
|
.Li \et Tn \(em HT No (011)
|
||||||
.Li \ev Tn - VT No (013)
|
.Li \ev Tn \(em VT No (013)
|
||||||
.Li \e0 Tn - NUL No (000)
|
.Li \e0 Tn \(em NUL No (000)
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
When using this format, the
|
When using this format, the
|
||||||
.Fa nextc
|
.Fa nextc
|
||||||
parameter is looked at to determine
|
parameter is looked at to determine if a
|
||||||
if a NUL character can be encoded as
|
.Dv NUL
|
||||||
|
character can be encoded as
|
||||||
.Ql \e0
|
.Ql \e0
|
||||||
instead of
|
instead of
|
||||||
.Ql \e000 .
|
.Ql \e000 .
|
||||||
@ -284,13 +406,36 @@ If
|
|||||||
.Fa nextc
|
.Fa nextc
|
||||||
is an octal digit, the latter representation is used to
|
is an octal digit, the latter representation is used to
|
||||||
avoid ambiguity.
|
avoid ambiguity.
|
||||||
|
.Pp
|
||||||
|
Non-printable characters without C-style
|
||||||
|
backslash sequences use the default representation.
|
||||||
.It Dv VIS_OCTAL
|
.It Dv VIS_OCTAL
|
||||||
Use a three digit octal sequence.
|
Use a three digit octal sequence.
|
||||||
The form is
|
The form is
|
||||||
.Ql \eddd
|
.Ql \eddd
|
||||||
where
|
where
|
||||||
.Ar d
|
.Em d
|
||||||
represents an octal digit.
|
represents an octal digit.
|
||||||
|
.It Dv VIS_CSTYLE \&| Dv VIS_OCTAL
|
||||||
|
Same as
|
||||||
|
.Dv VIS_CSTYLE
|
||||||
|
except that non-printable characters without C-style
|
||||||
|
backslash sequences use a three digit octal sequence.
|
||||||
|
.It Dv VIS_HTTPSTYLE
|
||||||
|
Use URI encoding as described in RFC 1738.
|
||||||
|
The form is
|
||||||
|
.Ql %xx
|
||||||
|
where
|
||||||
|
.Em x
|
||||||
|
represents a lower case hexadecimal digit.
|
||||||
|
.It Dv VIS_MIMESTYLE
|
||||||
|
Use MIME Quoted-Printable encoding as described in RFC 2045, only don't
|
||||||
|
break lines and don't handle CRLF.
|
||||||
|
The form is
|
||||||
|
.Ql =XX
|
||||||
|
where
|
||||||
|
.Em X
|
||||||
|
represents an upper case hexadecimal digit.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
There is one additional flag,
|
There is one additional flag,
|
||||||
@ -304,21 +449,112 @@ meta characters as
|
|||||||
.Ql M-C ) .
|
.Ql M-C ) .
|
||||||
With this flag set, the encoding is
|
With this flag set, the encoding is
|
||||||
ambiguous and non-invertible.
|
ambiguous and non-invertible.
|
||||||
|
.Sh MULTIBYTE CHARACTER SUPPORT
|
||||||
|
These functions support multibyte character input.
|
||||||
|
The encoding conversion is influenced by the setting of the
|
||||||
|
.Ev LC_CTYPE
|
||||||
|
environment variable which defines the set of characters
|
||||||
|
that can be copied without encoding.
|
||||||
|
.Pp
|
||||||
|
If
|
||||||
|
.Dv VIS_NOLOCALE
|
||||||
|
is set, processing is done assuming the C locale and overriding
|
||||||
|
any other environment settings.
|
||||||
|
.Pp
|
||||||
|
When 8-bit data is present in the input,
|
||||||
|
.Ev LC_CTYPE
|
||||||
|
must be set to the correct locale or to the C locale.
|
||||||
|
If the locales of the data and the conversion are mismatched,
|
||||||
|
multibyte character recognition may fail and encoding will be performed
|
||||||
|
byte-by-byte instead.
|
||||||
|
.Pp
|
||||||
|
As noted above,
|
||||||
|
.Fa dst
|
||||||
|
must be four times the number of bytes processed from
|
||||||
|
.Fa src .
|
||||||
|
But note that each multibyte character can be up to
|
||||||
|
.Dv MB_LEN_MAX
|
||||||
|
bytes
|
||||||
|
.\" (see
|
||||||
|
.\" .Xr multibyte 3 )
|
||||||
|
so in terms of multibyte characters,
|
||||||
|
.Fa dst
|
||||||
|
must be four times
|
||||||
|
.Dv MB_LEN_MAX
|
||||||
|
times the number of characters processed from
|
||||||
|
.Fa src .
|
||||||
|
.Sh ENVIRONMENT
|
||||||
|
.Bl -tag -width ".Ev LC_CTYPE"
|
||||||
|
.It Ev LC_CTYPE
|
||||||
|
Specify the locale of the input data.
|
||||||
|
Set to C if the input data locale is unknown.
|
||||||
|
.El
|
||||||
|
.Sh ERRORS
|
||||||
|
The functions
|
||||||
|
.Fn nvis
|
||||||
|
and
|
||||||
|
.Fn snvis
|
||||||
|
will return
|
||||||
|
.Dv NULL
|
||||||
|
and the functions
|
||||||
|
.Fn strnvis ,
|
||||||
|
.Fn strnvisx ,
|
||||||
|
.Fn strsnvis ,
|
||||||
|
and
|
||||||
|
.Fn strsnvisx ,
|
||||||
|
will return \-1 when the
|
||||||
|
.Fa dlen
|
||||||
|
destination buffer size is not enough to perform the conversion while
|
||||||
|
setting
|
||||||
|
.Va errno
|
||||||
|
to:
|
||||||
|
.Bl -tag -width ".Bq Er ENOSPC"
|
||||||
|
.It Bq Er ENOSPC
|
||||||
|
The destination buffer size is not large enough to perform the conversion.
|
||||||
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr unvis 1 ,
|
.Xr unvis 1 ,
|
||||||
.Xr vis 1 ,
|
.Xr vis 1 ,
|
||||||
.Xr snprintf 3 ,
|
.Xr glob 3 ,
|
||||||
.Xr strlcpy 3bsd ,
|
.\" .Xr multibyte 3 ,
|
||||||
.Xr unvis 3bsd
|
.Xr unvis 3bsd
|
||||||
|
.Rs
|
||||||
|
.%A T. Berners-Lee
|
||||||
|
.%T Uniform Resource Locators (URL)
|
||||||
|
.%O "RFC 1738"
|
||||||
|
.Re
|
||||||
|
.Rs
|
||||||
|
.%T "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies"
|
||||||
|
.%O "RFC 2045"
|
||||||
|
.Re
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
The
|
The
|
||||||
.Fn vis ,
|
.Fn vis ,
|
||||||
.Fn strvis
|
.Fn strvis ,
|
||||||
and
|
and
|
||||||
.Fn strvisx
|
.Fn strvisx
|
||||||
functions first appeared in
|
functions first appeared in
|
||||||
.Bx 4.4 .
|
.Bx 4.4 .
|
||||||
The
|
The
|
||||||
.Fn strnvis
|
.Fn svis ,
|
||||||
function first appeared in
|
.Fn strsvis ,
|
||||||
.Ox 2.9 .
|
and
|
||||||
|
.Fn strsvisx
|
||||||
|
functions appeared in
|
||||||
|
.Nx 1.5 .
|
||||||
|
The buffer size limited versions of the functions
|
||||||
|
.Po Fn nvis ,
|
||||||
|
.Fn strnvis ,
|
||||||
|
.Fn strnvisx ,
|
||||||
|
.Fn snvis ,
|
||||||
|
.Fn strsnvis ,
|
||||||
|
and
|
||||||
|
.Fn strsnvisx Pc
|
||||||
|
appeared in
|
||||||
|
.Nx 6.0
|
||||||
|
and
|
||||||
|
.Fx 9.2 .
|
||||||
|
Multibyte character support was added in
|
||||||
|
.Nx 7.0
|
||||||
|
and
|
||||||
|
.Fx 9.2 .
|
||||||
|
@ -144,4 +144,16 @@ LIBBSD_0.9 {
|
|||||||
flopenat;
|
flopenat;
|
||||||
|
|
||||||
pidfile_fileno;
|
pidfile_fileno;
|
||||||
|
|
||||||
|
nvis;
|
||||||
|
snvis;
|
||||||
|
stravis;
|
||||||
|
strenvisx;
|
||||||
|
strnunvisx;
|
||||||
|
strsenvisx;
|
||||||
|
strsnvis;
|
||||||
|
strsnvisx;
|
||||||
|
strsvis;
|
||||||
|
strsvisx;
|
||||||
|
svis;
|
||||||
} LIBBSD_0.8;
|
} LIBBSD_0.8;
|
||||||
|
542
src/unvis.c
542
src/unvis.c
@ -1,3 +1,5 @@
|
|||||||
|
/* $NetBSD: unvis.c,v 1.44 2014/09/26 15:43:36 roy Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1989, 1993
|
* Copyright (c) 1989, 1993
|
||||||
* The Regents of the University of California. All rights reserved.
|
* The Regents of the University of California. All rights reserved.
|
||||||
@ -27,10 +29,22 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <vis.h>
|
#include <vis.h>
|
||||||
|
|
||||||
|
#ifdef __weak_alias
|
||||||
|
__weak_alias(strnunvisx,_strnunvisx)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _DIAGASSERT(x)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* decode driven by state machine
|
* decode driven by state machine
|
||||||
*/
|
*/
|
||||||
@ -41,15 +55,128 @@
|
|||||||
#define S_CTRL 4 /* control char started (^) */
|
#define S_CTRL 4 /* control char started (^) */
|
||||||
#define S_OCTAL2 5 /* octal digit 2 */
|
#define S_OCTAL2 5 /* octal digit 2 */
|
||||||
#define S_OCTAL3 6 /* octal digit 3 */
|
#define S_OCTAL3 6 /* octal digit 3 */
|
||||||
#define S_HEX2 7 /* hex digit 2 */
|
#define S_HEX 7 /* mandatory hex digit */
|
||||||
|
#define S_HEX1 8 /* http hex digit */
|
||||||
|
#define S_HEX2 9 /* http hex digit 2 */
|
||||||
|
#define S_MIME1 10 /* mime hex digit 1 */
|
||||||
|
#define S_MIME2 11 /* mime hex digit 2 */
|
||||||
|
#define S_EATCRNL 12 /* mime eating CRNL */
|
||||||
|
#define S_AMP 13 /* seen & */
|
||||||
|
#define S_NUMBER 14 /* collecting number */
|
||||||
|
#define S_STRING 15 /* collecting string */
|
||||||
|
|
||||||
#define S_HTTP 0x080 /* %HEXHEX escape */
|
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
|
||||||
|
#define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10))
|
||||||
|
#define XTOD(c) (isdigit(c) ? (c - '0') : ((c - 'A') + 10))
|
||||||
|
|
||||||
#define isoctal(c) \
|
/*
|
||||||
(((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '7')
|
* RFC 1866
|
||||||
#define ishex(c) \
|
*/
|
||||||
((((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '9') || \
|
static const struct nv {
|
||||||
(((unsigned char)(c)) >= 'a' && ((unsigned char)(c)) <= 'f'))
|
char name[7];
|
||||||
|
uint8_t value;
|
||||||
|
} nv[] = {
|
||||||
|
{ "AElig", 198 }, /* capital AE diphthong (ligature) */
|
||||||
|
{ "Aacute", 193 }, /* capital A, acute accent */
|
||||||
|
{ "Acirc", 194 }, /* capital A, circumflex accent */
|
||||||
|
{ "Agrave", 192 }, /* capital A, grave accent */
|
||||||
|
{ "Aring", 197 }, /* capital A, ring */
|
||||||
|
{ "Atilde", 195 }, /* capital A, tilde */
|
||||||
|
{ "Auml", 196 }, /* capital A, dieresis or umlaut mark */
|
||||||
|
{ "Ccedil", 199 }, /* capital C, cedilla */
|
||||||
|
{ "ETH", 208 }, /* capital Eth, Icelandic */
|
||||||
|
{ "Eacute", 201 }, /* capital E, acute accent */
|
||||||
|
{ "Ecirc", 202 }, /* capital E, circumflex accent */
|
||||||
|
{ "Egrave", 200 }, /* capital E, grave accent */
|
||||||
|
{ "Euml", 203 }, /* capital E, dieresis or umlaut mark */
|
||||||
|
{ "Iacute", 205 }, /* capital I, acute accent */
|
||||||
|
{ "Icirc", 206 }, /* capital I, circumflex accent */
|
||||||
|
{ "Igrave", 204 }, /* capital I, grave accent */
|
||||||
|
{ "Iuml", 207 }, /* capital I, dieresis or umlaut mark */
|
||||||
|
{ "Ntilde", 209 }, /* capital N, tilde */
|
||||||
|
{ "Oacute", 211 }, /* capital O, acute accent */
|
||||||
|
{ "Ocirc", 212 }, /* capital O, circumflex accent */
|
||||||
|
{ "Ograve", 210 }, /* capital O, grave accent */
|
||||||
|
{ "Oslash", 216 }, /* capital O, slash */
|
||||||
|
{ "Otilde", 213 }, /* capital O, tilde */
|
||||||
|
{ "Ouml", 214 }, /* capital O, dieresis or umlaut mark */
|
||||||
|
{ "THORN", 222 }, /* capital THORN, Icelandic */
|
||||||
|
{ "Uacute", 218 }, /* capital U, acute accent */
|
||||||
|
{ "Ucirc", 219 }, /* capital U, circumflex accent */
|
||||||
|
{ "Ugrave", 217 }, /* capital U, grave accent */
|
||||||
|
{ "Uuml", 220 }, /* capital U, dieresis or umlaut mark */
|
||||||
|
{ "Yacute", 221 }, /* capital Y, acute accent */
|
||||||
|
{ "aacute", 225 }, /* small a, acute accent */
|
||||||
|
{ "acirc", 226 }, /* small a, circumflex accent */
|
||||||
|
{ "acute", 180 }, /* acute accent */
|
||||||
|
{ "aelig", 230 }, /* small ae diphthong (ligature) */
|
||||||
|
{ "agrave", 224 }, /* small a, grave accent */
|
||||||
|
{ "amp", 38 }, /* ampersand */
|
||||||
|
{ "aring", 229 }, /* small a, ring */
|
||||||
|
{ "atilde", 227 }, /* small a, tilde */
|
||||||
|
{ "auml", 228 }, /* small a, dieresis or umlaut mark */
|
||||||
|
{ "brvbar", 166 }, /* broken (vertical) bar */
|
||||||
|
{ "ccedil", 231 }, /* small c, cedilla */
|
||||||
|
{ "cedil", 184 }, /* cedilla */
|
||||||
|
{ "cent", 162 }, /* cent sign */
|
||||||
|
{ "copy", 169 }, /* copyright sign */
|
||||||
|
{ "curren", 164 }, /* general currency sign */
|
||||||
|
{ "deg", 176 }, /* degree sign */
|
||||||
|
{ "divide", 247 }, /* divide sign */
|
||||||
|
{ "eacute", 233 }, /* small e, acute accent */
|
||||||
|
{ "ecirc", 234 }, /* small e, circumflex accent */
|
||||||
|
{ "egrave", 232 }, /* small e, grave accent */
|
||||||
|
{ "eth", 240 }, /* small eth, Icelandic */
|
||||||
|
{ "euml", 235 }, /* small e, dieresis or umlaut mark */
|
||||||
|
{ "frac12", 189 }, /* fraction one-half */
|
||||||
|
{ "frac14", 188 }, /* fraction one-quarter */
|
||||||
|
{ "frac34", 190 }, /* fraction three-quarters */
|
||||||
|
{ "gt", 62 }, /* greater than */
|
||||||
|
{ "iacute", 237 }, /* small i, acute accent */
|
||||||
|
{ "icirc", 238 }, /* small i, circumflex accent */
|
||||||
|
{ "iexcl", 161 }, /* inverted exclamation mark */
|
||||||
|
{ "igrave", 236 }, /* small i, grave accent */
|
||||||
|
{ "iquest", 191 }, /* inverted question mark */
|
||||||
|
{ "iuml", 239 }, /* small i, dieresis or umlaut mark */
|
||||||
|
{ "laquo", 171 }, /* angle quotation mark, left */
|
||||||
|
{ "lt", 60 }, /* less than */
|
||||||
|
{ "macr", 175 }, /* macron */
|
||||||
|
{ "micro", 181 }, /* micro sign */
|
||||||
|
{ "middot", 183 }, /* middle dot */
|
||||||
|
{ "nbsp", 160 }, /* no-break space */
|
||||||
|
{ "not", 172 }, /* not sign */
|
||||||
|
{ "ntilde", 241 }, /* small n, tilde */
|
||||||
|
{ "oacute", 243 }, /* small o, acute accent */
|
||||||
|
{ "ocirc", 244 }, /* small o, circumflex accent */
|
||||||
|
{ "ograve", 242 }, /* small o, grave accent */
|
||||||
|
{ "ordf", 170 }, /* ordinal indicator, feminine */
|
||||||
|
{ "ordm", 186 }, /* ordinal indicator, masculine */
|
||||||
|
{ "oslash", 248 }, /* small o, slash */
|
||||||
|
{ "otilde", 245 }, /* small o, tilde */
|
||||||
|
{ "ouml", 246 }, /* small o, dieresis or umlaut mark */
|
||||||
|
{ "para", 182 }, /* pilcrow (paragraph sign) */
|
||||||
|
{ "plusmn", 177 }, /* plus-or-minus sign */
|
||||||
|
{ "pound", 163 }, /* pound sterling sign */
|
||||||
|
{ "quot", 34 }, /* double quote */
|
||||||
|
{ "raquo", 187 }, /* angle quotation mark, right */
|
||||||
|
{ "reg", 174 }, /* registered sign */
|
||||||
|
{ "sect", 167 }, /* section sign */
|
||||||
|
{ "shy", 173 }, /* soft hyphen */
|
||||||
|
{ "sup1", 185 }, /* superscript one */
|
||||||
|
{ "sup2", 178 }, /* superscript two */
|
||||||
|
{ "sup3", 179 }, /* superscript three */
|
||||||
|
{ "szlig", 223 }, /* small sharp s, German (sz ligature) */
|
||||||
|
{ "thorn", 254 }, /* small thorn, Icelandic */
|
||||||
|
{ "times", 215 }, /* multiply sign */
|
||||||
|
{ "uacute", 250 }, /* small u, acute accent */
|
||||||
|
{ "ucirc", 251 }, /* small u, circumflex accent */
|
||||||
|
{ "ugrave", 249 }, /* small u, grave accent */
|
||||||
|
{ "uml", 168 }, /* umlaut (dieresis) */
|
||||||
|
{ "uuml", 252 }, /* small u, dieresis or umlaut mark */
|
||||||
|
{ "yacute", 253 }, /* small y, acute accent */
|
||||||
|
{ "yen", 165 }, /* yen sign */
|
||||||
|
{ "yuml", 255 }, /* small y, dieresis or umlaut mark */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* unvis - decode characters previously encoded by vis
|
* unvis - decode characters previously encoded by vis
|
||||||
@ -57,276 +184,367 @@
|
|||||||
int
|
int
|
||||||
unvis(char *cp, int c, int *astate, int flag)
|
unvis(char *cp, int c, int *astate, int flag)
|
||||||
{
|
{
|
||||||
|
unsigned char uc = (unsigned char)c;
|
||||||
|
unsigned char st, ia, is, lc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bottom 8 bits of astate hold the state machine state.
|
||||||
|
* Top 8 bits hold the current character in the http 1866 nv string decoding
|
||||||
|
*/
|
||||||
|
#define GS(a) ((a) & 0xff)
|
||||||
|
#define SS(a, b) (((uint32_t)(a) << 24) | (b))
|
||||||
|
#define GI(a) ((uint32_t)(a) >> 24)
|
||||||
|
|
||||||
|
_DIAGASSERT(cp != NULL);
|
||||||
|
_DIAGASSERT(astate != NULL);
|
||||||
|
st = GS(*astate);
|
||||||
|
|
||||||
if (flag & UNVIS_END) {
|
if (flag & UNVIS_END) {
|
||||||
if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
|
switch (st) {
|
||||||
*astate = S_GROUND;
|
case S_OCTAL2:
|
||||||
return (UNVIS_VALID);
|
case S_OCTAL3:
|
||||||
|
case S_HEX2:
|
||||||
|
*astate = SS(0, S_GROUND);
|
||||||
|
return UNVIS_VALID;
|
||||||
|
case S_GROUND:
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
default:
|
||||||
|
return UNVIS_SYNBAD;
|
||||||
}
|
}
|
||||||
return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (*astate & ~S_HTTP) {
|
switch (st) {
|
||||||
|
|
||||||
case S_GROUND:
|
case S_GROUND:
|
||||||
*cp = 0;
|
*cp = 0;
|
||||||
if (c == '\\') {
|
if ((flag & VIS_NOESCAPE) == 0 && c == '\\') {
|
||||||
*astate = S_START;
|
*astate = SS(0, S_START);
|
||||||
return (0);
|
return UNVIS_NOCHAR;
|
||||||
}
|
}
|
||||||
if (flag & VIS_HTTPSTYLE && c == '%') {
|
if ((flag & VIS_HTTP1808) && c == '%') {
|
||||||
*astate = S_START | S_HTTP;
|
*astate = SS(0, S_HEX1);
|
||||||
return (0);
|
return UNVIS_NOCHAR;
|
||||||
|
}
|
||||||
|
if ((flag & VIS_HTTP1866) && c == '&') {
|
||||||
|
*astate = SS(0, S_AMP);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
}
|
||||||
|
if ((flag & VIS_MIMESTYLE) && c == '=') {
|
||||||
|
*astate = SS(0, S_MIME1);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
}
|
}
|
||||||
*cp = c;
|
*cp = c;
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
|
|
||||||
case S_START:
|
case S_START:
|
||||||
if (*astate & S_HTTP) {
|
|
||||||
if (ishex(tolower(c))) {
|
|
||||||
*cp = isdigit(c) ? (c - '0') : (tolower(c) - 'a');
|
|
||||||
*astate = S_HEX2;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '\\':
|
case '\\':
|
||||||
*cp = c;
|
*cp = c;
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case '0': case '1': case '2': case '3':
|
case '0': case '1': case '2': case '3':
|
||||||
case '4': case '5': case '6': case '7':
|
case '4': case '5': case '6': case '7':
|
||||||
*cp = (c - '0');
|
*cp = (c - '0');
|
||||||
*astate = S_OCTAL2;
|
*astate = SS(0, S_OCTAL2);
|
||||||
return (0);
|
return UNVIS_NOCHAR;
|
||||||
case 'M':
|
case 'M':
|
||||||
*cp = 0200;
|
*cp = (char)0200;
|
||||||
*astate = S_META;
|
*astate = SS(0, S_META);
|
||||||
return (0);
|
return UNVIS_NOCHAR;
|
||||||
case '^':
|
case '^':
|
||||||
*astate = S_CTRL;
|
*astate = SS(0, S_CTRL);
|
||||||
return (0);
|
return UNVIS_NOCHAR;
|
||||||
case 'n':
|
case 'n':
|
||||||
*cp = '\n';
|
*cp = '\n';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case 'r':
|
case 'r':
|
||||||
*cp = '\r';
|
*cp = '\r';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case 'b':
|
case 'b':
|
||||||
*cp = '\b';
|
*cp = '\b';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case 'a':
|
case 'a':
|
||||||
*cp = '\007';
|
*cp = '\007';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case 'v':
|
case 'v':
|
||||||
*cp = '\v';
|
*cp = '\v';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case 't':
|
case 't':
|
||||||
*cp = '\t';
|
*cp = '\t';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case 'f':
|
case 'f':
|
||||||
*cp = '\f';
|
*cp = '\f';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case 's':
|
case 's':
|
||||||
*cp = ' ';
|
*cp = ' ';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
case 'E':
|
case 'E':
|
||||||
*cp = '\033';
|
*cp = '\033';
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
|
case 'x':
|
||||||
|
*astate = SS(0, S_HEX);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
case '\n':
|
case '\n':
|
||||||
/*
|
/*
|
||||||
* hidden newline
|
* hidden newline
|
||||||
*/
|
*/
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_NOCHAR);
|
return UNVIS_NOCHAR;
|
||||||
case '$':
|
case '$':
|
||||||
/*
|
/*
|
||||||
* hidden marker
|
* hidden marker
|
||||||
*/
|
*/
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_NOCHAR);
|
return UNVIS_NOCHAR;
|
||||||
|
default:
|
||||||
|
if (isgraph(c)) {
|
||||||
|
*cp = c;
|
||||||
|
*astate = SS(0, S_GROUND);
|
||||||
|
return UNVIS_VALID;
|
||||||
}
|
}
|
||||||
*astate = S_GROUND;
|
}
|
||||||
return (UNVIS_SYNBAD);
|
goto bad;
|
||||||
|
|
||||||
case S_META:
|
case S_META:
|
||||||
if (c == '-')
|
if (c == '-')
|
||||||
*astate = S_META1;
|
*astate = SS(0, S_META1);
|
||||||
else if (c == '^')
|
else if (c == '^')
|
||||||
*astate = S_CTRL;
|
*astate = SS(0, S_CTRL);
|
||||||
else {
|
else
|
||||||
*astate = S_GROUND;
|
goto bad;
|
||||||
return (UNVIS_SYNBAD);
|
return UNVIS_NOCHAR;
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
case S_META1:
|
case S_META1:
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
*cp |= c;
|
*cp |= c;
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
|
|
||||||
case S_CTRL:
|
case S_CTRL:
|
||||||
if (c == '?')
|
if (c == '?')
|
||||||
*cp |= 0177;
|
*cp |= 0177;
|
||||||
else
|
else
|
||||||
*cp |= c & 037;
|
*cp |= c & 037;
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
|
|
||||||
case S_OCTAL2: /* second possible octal digit */
|
case S_OCTAL2: /* second possible octal digit */
|
||||||
if (isoctal(c)) {
|
if (isoctal(uc)) {
|
||||||
/*
|
/*
|
||||||
* yes - and maybe a third
|
* yes - and maybe a third
|
||||||
*/
|
*/
|
||||||
*cp = (*cp << 3) + (c - '0');
|
*cp = (*cp << 3) + (c - '0');
|
||||||
*astate = S_OCTAL3;
|
*astate = SS(0, S_OCTAL3);
|
||||||
return (0);
|
return UNVIS_NOCHAR;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* no - done with current sequence, push back passed char
|
* no - done with current sequence, push back passed char
|
||||||
*/
|
*/
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_VALIDPUSH);
|
return UNVIS_VALIDPUSH;
|
||||||
|
|
||||||
case S_OCTAL3: /* third possible octal digit */
|
case S_OCTAL3: /* third possible octal digit */
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
if (isoctal(c)) {
|
if (isoctal(uc)) {
|
||||||
*cp = (*cp << 3) + (c - '0');
|
*cp = (*cp << 3) + (c - '0');
|
||||||
return (UNVIS_VALID);
|
return UNVIS_VALID;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* we were done, push back passed char
|
* we were done, push back passed char
|
||||||
*/
|
*/
|
||||||
return (UNVIS_VALIDPUSH);
|
return UNVIS_VALIDPUSH;
|
||||||
|
|
||||||
case S_HEX2: /* second mandatory hex digit */
|
case S_HEX:
|
||||||
if (ishex(tolower(c))) {
|
if (!isxdigit(uc))
|
||||||
*cp = (isdigit(c) ? (*cp << 4) + (c - '0') : (*cp << 4) + (tolower(c) - 'a' + 10));
|
goto bad;
|
||||||
|
/*FALLTHROUGH*/
|
||||||
|
case S_HEX1:
|
||||||
|
if (isxdigit(uc)) {
|
||||||
|
*cp = xtod(uc);
|
||||||
|
*astate = SS(0, S_HEX2);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* no - done with current sequence, push back passed char
|
||||||
|
*/
|
||||||
|
*astate = SS(0, S_GROUND);
|
||||||
|
return UNVIS_VALIDPUSH;
|
||||||
|
|
||||||
|
case S_HEX2:
|
||||||
*astate = S_GROUND;
|
*astate = S_GROUND;
|
||||||
return (UNVIS_VALID);
|
if (isxdigit(uc)) {
|
||||||
|
*cp = xtod(uc) | (*cp << 4);
|
||||||
|
return UNVIS_VALID;
|
||||||
|
}
|
||||||
|
return UNVIS_VALIDPUSH;
|
||||||
|
|
||||||
|
case S_MIME1:
|
||||||
|
if (uc == '\n' || uc == '\r') {
|
||||||
|
*astate = SS(0, S_EATCRNL);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
}
|
||||||
|
if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) {
|
||||||
|
*cp = XTOD(uc);
|
||||||
|
*astate = SS(0, S_MIME2);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
}
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
case S_MIME2:
|
||||||
|
if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) {
|
||||||
|
*astate = SS(0, S_GROUND);
|
||||||
|
*cp = XTOD(uc) | (*cp << 4);
|
||||||
|
return UNVIS_VALID;
|
||||||
|
}
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
case S_EATCRNL:
|
||||||
|
switch (uc) {
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
case '=':
|
||||||
|
*astate = SS(0, S_MIME1);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
default:
|
||||||
|
*cp = uc;
|
||||||
|
*astate = SS(0, S_GROUND);
|
||||||
|
return UNVIS_VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
case S_AMP:
|
||||||
|
*cp = 0;
|
||||||
|
if (uc == '#') {
|
||||||
|
*astate = SS(0, S_NUMBER);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
}
|
||||||
|
*astate = SS(0, S_STRING);
|
||||||
|
/*FALLTHROUGH*/
|
||||||
|
|
||||||
|
case S_STRING:
|
||||||
|
ia = *cp; /* index in the array */
|
||||||
|
is = GI(*astate); /* index in the string */
|
||||||
|
lc = is == 0 ? 0 : nv[ia].name[is - 1]; /* last character */
|
||||||
|
|
||||||
|
if (uc == ';')
|
||||||
|
uc = '\0';
|
||||||
|
|
||||||
|
for (; ia < __arraycount(nv); ia++) {
|
||||||
|
if (is != 0 && nv[ia].name[is - 1] != lc)
|
||||||
|
goto bad;
|
||||||
|
if (nv[ia].name[is] == uc)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ia == __arraycount(nv))
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
if (uc != 0) {
|
||||||
|
*cp = ia;
|
||||||
|
*astate = SS(is + 1, S_STRING);
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cp = nv[ia].value;
|
||||||
|
*astate = SS(0, S_GROUND);
|
||||||
|
return UNVIS_VALID;
|
||||||
|
|
||||||
|
case S_NUMBER:
|
||||||
|
if (uc == ';')
|
||||||
|
return UNVIS_VALID;
|
||||||
|
if (!isdigit(uc))
|
||||||
|
goto bad;
|
||||||
|
*cp += (*cp * 10) + uc - '0';
|
||||||
|
return UNVIS_NOCHAR;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
bad:
|
||||||
/*
|
/*
|
||||||
* decoder in unknown state - (probably uninitialized)
|
* decoder in unknown state - (probably uninitialized)
|
||||||
*/
|
*/
|
||||||
*astate = S_GROUND;
|
*astate = SS(0, S_GROUND);
|
||||||
return (UNVIS_SYNBAD);
|
return UNVIS_SYNBAD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* strunvis - decode src into dst
|
* strnunvisx - decode src into dst
|
||||||
*
|
*
|
||||||
* Number of chars decoded into dst is returned, -1 on error.
|
* Number of chars decoded into dst is returned, -1 on error.
|
||||||
* Dst is null terminated.
|
* Dst is null terminated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
strunvis(char *dst, const char *src)
|
strnunvisx(char *dst, size_t dlen, const char *src, int flag)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
char *start = dst;
|
char t = '\0', *start = dst;
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
|
||||||
while ((c = *src++)) {
|
_DIAGASSERT(src != NULL);
|
||||||
|
_DIAGASSERT(dst != NULL);
|
||||||
|
#define CHECKSPACE() \
|
||||||
|
do { \
|
||||||
|
if (dlen-- == 0) { \
|
||||||
|
errno = ENOSPC; \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
|
||||||
|
while ((c = *src++) != '\0') {
|
||||||
again:
|
again:
|
||||||
switch (unvis(dst, c, &state, 0)) {
|
switch (unvis(&t, c, &state, flag)) {
|
||||||
case UNVIS_VALID:
|
case UNVIS_VALID:
|
||||||
dst++;
|
CHECKSPACE();
|
||||||
|
*dst++ = t;
|
||||||
break;
|
break;
|
||||||
case UNVIS_VALIDPUSH:
|
case UNVIS_VALIDPUSH:
|
||||||
dst++;
|
CHECKSPACE();
|
||||||
|
*dst++ = t;
|
||||||
goto again;
|
goto again;
|
||||||
case 0:
|
case 0:
|
||||||
case UNVIS_NOCHAR:
|
case UNVIS_NOCHAR:
|
||||||
break;
|
break;
|
||||||
|
case UNVIS_SYNBAD:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
default:
|
default:
|
||||||
|
_DIAGASSERT(/*CONSTCOND*/0);
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unvis(&t, c, &state, UNVIS_END) == UNVIS_VALID) {
|
||||||
|
CHECKSPACE();
|
||||||
|
*dst++ = t;
|
||||||
|
}
|
||||||
|
CHECKSPACE();
|
||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
return (-1);
|
return (int)(dst - start);
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
|
|
||||||
dst++;
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t
|
|
||||||
strnunvis(char *dst, const char *src, size_t sz)
|
|
||||||
{
|
|
||||||
char c, p;
|
|
||||||
char *start = dst, *end = dst + sz - 1;
|
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
if (sz > 0)
|
|
||||||
*end = '\0';
|
|
||||||
while ((c = *src++)) {
|
|
||||||
again:
|
|
||||||
switch (unvis(&p, c, &state, 0)) {
|
|
||||||
case UNVIS_VALID:
|
|
||||||
if (dst < end)
|
|
||||||
*dst = p;
|
|
||||||
dst++;
|
|
||||||
break;
|
|
||||||
case UNVIS_VALIDPUSH:
|
|
||||||
if (dst < end)
|
|
||||||
*dst = p;
|
|
||||||
dst++;
|
|
||||||
goto again;
|
|
||||||
case 0:
|
|
||||||
case UNVIS_NOCHAR:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (dst <= end)
|
|
||||||
*dst = '\0';
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unvis(&p, c, &state, UNVIS_END) == UNVIS_VALID) {
|
|
||||||
if (dst < end)
|
|
||||||
*dst = p;
|
|
||||||
dst++;
|
|
||||||
}
|
|
||||||
if (dst <= end)
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst - start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
strunvisx(char *dst, const char *src, int flag)
|
strunvisx(char *dst, const char *src, int flag)
|
||||||
{
|
{
|
||||||
char c;
|
return strnunvisx(dst, (size_t)~0, src, flag);
|
||||||
char *start = dst;
|
}
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
while ((c = *src++)) {
|
int
|
||||||
again:
|
strunvis(char *dst, const char *src)
|
||||||
switch (unvis(dst, c, &state, flag)) {
|
{
|
||||||
case UNVIS_VALID:
|
return strnunvisx(dst, (size_t)~0, src, 0);
|
||||||
dst++;
|
|
||||||
break;
|
|
||||||
case UNVIS_VALIDPUSH:
|
|
||||||
dst++;
|
|
||||||
goto again;
|
|
||||||
case 0:
|
|
||||||
case UNVIS_NOCHAR:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return (-1);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
|
int
|
||||||
dst++;
|
strnunvis(char *dst, size_t dlen, const char *src)
|
||||||
*dst = '\0';
|
{
|
||||||
return (dst - start);
|
return strnunvisx(dst, dlen, src, 0);
|
||||||
}
|
}
|
||||||
|
874
src/vis.c
874
src/vis.c
@ -1,4 +1,5 @@
|
|||||||
/* $OpenBSD: vis.c,v 1.18 2005/08/29 18:38:41 otto Exp $ */
|
/* $NetBSD: vis.c,v 1.74 2017/11/27 16:37:21 christos Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1989, 1993
|
* Copyright (c) 1989, 1993
|
||||||
* The Regents of the University of California. All rights reserved.
|
* The Regents of the University of California. All rights reserved.
|
||||||
@ -28,220 +29,717 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
/*-
|
||||||
#include <limits.h>
|
* Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
|
||||||
#include <ctype.h>
|
* All rights reserved.
|
||||||
#include <string.h>
|
*
|
||||||
#include <stdio.h>
|
* Redistribution and use in source and binary forms, with or without
|
||||||
#include <vis.h>
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
#define isoctal(c) \
|
#include <sys/cdefs.h>
|
||||||
(((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '7')
|
#include <sys/types.h>
|
||||||
#define isvisible(c) \
|
#include <sys/param.h>
|
||||||
(((unsigned int)(c) <= UCHAR_MAX && \
|
|
||||||
isascii((unsigned char)(c)) && \
|
#include <assert.h>
|
||||||
(((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \
|
#include <vis.h>
|
||||||
(flag & VIS_GLOB) == 0) && \
|
#include <errno.h>
|
||||||
isgraph((unsigned char)(c))) || \
|
#include <stdlib.h>
|
||||||
((flag & VIS_SP) == 0 && (c) == ' ') || \
|
#include <wchar.h>
|
||||||
((flag & VIS_TAB) == 0 && (c) == '\t') || \
|
#include <wctype.h>
|
||||||
((flag & VIS_NL) == 0 && (c) == '\n') || \
|
|
||||||
((flag & VIS_SAFE) && ((c) == '\b' || \
|
#ifdef __weak_alias
|
||||||
(c) == '\007' || (c) == '\r' || \
|
__weak_alias(strvisx,_strvisx)
|
||||||
isgraph((unsigned char)(c)))))
|
#endif
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define _DIAGASSERT(x)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
#define BELL L'\a'
|
||||||
|
|
||||||
|
#if defined(LC_C_LOCALE)
|
||||||
|
#define iscgraph(c) isgraph_l(c, LC_C_LOCALE)
|
||||||
|
#else
|
||||||
|
/* Keep it simple for now, no locale stuff */
|
||||||
|
#define iscgraph(c) isgraph(c)
|
||||||
|
#ifdef notyet
|
||||||
|
#include <locale.h>
|
||||||
|
static int
|
||||||
|
iscgraph(int c) {
|
||||||
|
int rv;
|
||||||
|
char *ol;
|
||||||
|
|
||||||
|
ol = setlocale(LC_CTYPE, "C");
|
||||||
|
rv = isgraph(c);
|
||||||
|
if (ol)
|
||||||
|
setlocale(LC_CTYPE, ol);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ISGRAPH(flags, c) \
|
||||||
|
(((flags) & VIS_NOLOCALE) ? iscgraph(c) : iswgraph(c))
|
||||||
|
|
||||||
|
#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 30
|
||||||
|
|
||||||
|
static const wchar_t char_shell[] = L"'`\";&<>()|{}]\\$!^~";
|
||||||
|
static const wchar_t char_glob[] = L"*?[#";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On NetBSD and glibc MB_LEN_MAX is currently > 8 which does not fit on any
|
||||||
|
* integer integral type and it is probably wrong, since currently the maximum
|
||||||
|
* number of bytes and character needs is 6. Until this is fixed, the
|
||||||
|
* loops below are using sizeof(uint64_t) - 1 instead of MB_LEN_MAX, and
|
||||||
|
* the assertion is commented out.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
#ifndef CTASSERT
|
||||||
|
#define CTASSERT(x) _CTASSERT(x, __LINE__)
|
||||||
|
#define _CTASSERT(x, y) __CTASSERT(x, y)
|
||||||
|
#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CTASSERT(MB_LEN_MAX <= sizeof(uint64_t));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is do_hvis, for HTTP style (RFC 1808)
|
||||||
|
*/
|
||||||
|
static wchar_t *
|
||||||
|
do_hvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
|
||||||
|
{
|
||||||
|
if (iswalnum(c)
|
||||||
|
/* safe */
|
||||||
|
|| c == L'$' || c == L'-' || c == L'_' || c == L'.' || c == L'+'
|
||||||
|
/* extra */
|
||||||
|
|| c == L'!' || c == L'*' || c == L'\'' || c == L'(' || c == L')'
|
||||||
|
|| c == L',')
|
||||||
|
dst = do_svis(dst, c, flags, nextc, extra);
|
||||||
|
else {
|
||||||
|
*dst++ = L'%';
|
||||||
|
*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
|
||||||
|
*dst++ = xtoa((unsigned int)c & 0xf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is do_mvis, for Quoted-Printable MIME (RFC 2045)
|
||||||
|
* NB: No handling of long lines or CRLF.
|
||||||
|
*/
|
||||||
|
static wchar_t *
|
||||||
|
do_mvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
|
||||||
|
{
|
||||||
|
if ((c != L'\n') &&
|
||||||
|
/* Space at the end of the line */
|
||||||
|
((iswspace(c) && (nextc == L'\r' || nextc == L'\n')) ||
|
||||||
|
/* Out of range */
|
||||||
|
(!iswspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
|
||||||
|
/* Specific char to be escaped */
|
||||||
|
wcschr(L"#$@[\\]^`{|}~", c) != NULL)) {
|
||||||
|
*dst++ = L'=';
|
||||||
|
*dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
|
||||||
|
*dst++ = XTOA((unsigned int)c & 0xf);
|
||||||
|
} else
|
||||||
|
dst = do_svis(dst, c, flags, nextc, extra);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output single byte of multibyte character.
|
||||||
|
*/
|
||||||
|
static wchar_t *
|
||||||
|
do_mbyte(wchar_t *dst, wint_t c, int flags, wint_t nextc, int iswextra)
|
||||||
|
{
|
||||||
|
if (flags & VIS_CSTYLE) {
|
||||||
|
switch (c) {
|
||||||
|
case L'\n':
|
||||||
|
*dst++ = L'\\'; *dst++ = L'n';
|
||||||
|
return dst;
|
||||||
|
case L'\r':
|
||||||
|
*dst++ = L'\\'; *dst++ = L'r';
|
||||||
|
return dst;
|
||||||
|
case L'\b':
|
||||||
|
*dst++ = L'\\'; *dst++ = L'b';
|
||||||
|
return dst;
|
||||||
|
case BELL:
|
||||||
|
*dst++ = L'\\'; *dst++ = L'a';
|
||||||
|
return dst;
|
||||||
|
case L'\v':
|
||||||
|
*dst++ = L'\\'; *dst++ = L'v';
|
||||||
|
return dst;
|
||||||
|
case L'\t':
|
||||||
|
*dst++ = L'\\'; *dst++ = L't';
|
||||||
|
return dst;
|
||||||
|
case L'\f':
|
||||||
|
*dst++ = L'\\'; *dst++ = L'f';
|
||||||
|
return dst;
|
||||||
|
case L' ':
|
||||||
|
*dst++ = L'\\'; *dst++ = L's';
|
||||||
|
return dst;
|
||||||
|
case L'\0':
|
||||||
|
*dst++ = L'\\'; *dst++ = L'0';
|
||||||
|
if (iswoctal(nextc)) {
|
||||||
|
*dst++ = L'0';
|
||||||
|
*dst++ = L'0';
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
/* We cannot encode these characters in VIS_CSTYLE
|
||||||
|
* because they special meaning */
|
||||||
|
case L'n':
|
||||||
|
case L'r':
|
||||||
|
case L'b':
|
||||||
|
case L'a':
|
||||||
|
case L'v':
|
||||||
|
case L't':
|
||||||
|
case L'f':
|
||||||
|
case L's':
|
||||||
|
case L'0':
|
||||||
|
case L'M':
|
||||||
|
case L'^':
|
||||||
|
case L'$': /* vis(1) -l */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (ISGRAPH(flags, c) && !iswoctal(c)) {
|
||||||
|
*dst++ = L'\\';
|
||||||
|
*dst++ = c;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iswextra || ((c & 0177) == L' ') || (flags & VIS_OCTAL)) {
|
||||||
|
*dst++ = L'\\';
|
||||||
|
*dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + L'0';
|
||||||
|
*dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + L'0';
|
||||||
|
*dst++ = (c & 07) + L'0';
|
||||||
|
} else {
|
||||||
|
if ((flags & VIS_NOSLASH) == 0)
|
||||||
|
*dst++ = L'\\';
|
||||||
|
|
||||||
|
if (c & 0200) {
|
||||||
|
c &= 0177;
|
||||||
|
*dst++ = L'M';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iswcntrl(c)) {
|
||||||
|
*dst++ = L'^';
|
||||||
|
if (c == 0177)
|
||||||
|
*dst++ = L'?';
|
||||||
|
else
|
||||||
|
*dst++ = c + L'@';
|
||||||
|
} else {
|
||||||
|
*dst++ = L'-';
|
||||||
|
*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 && (ISGRAPH(flags, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
static visfun_t
|
||||||
|
getvisfun(int flags)
|
||||||
|
{
|
||||||
|
if (flags & VIS_HTTPSTYLE)
|
||||||
|
return do_hvis;
|
||||||
|
if (flags & VIS_MIMESTYLE)
|
||||||
|
return do_mvis;
|
||||||
|
return do_svis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expand list of extra characters to not visually encode.
|
||||||
|
*/
|
||||||
|
static wchar_t *
|
||||||
|
makeextralist(int flags, const char *src)
|
||||||
|
{
|
||||||
|
wchar_t *dst, *d;
|
||||||
|
size_t len;
|
||||||
|
const wchar_t *s;
|
||||||
|
|
||||||
|
len = strlen(src);
|
||||||
|
if ((dst = calloc(len + MAXEXTRAS, sizeof(*dst))) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((flags & VIS_NOLOCALE) || mbstowcs(dst, src, len) == (size_t)-1) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
dst[i] = (wchar_t)(u_char)src[i];
|
||||||
|
d = dst + len;
|
||||||
|
} else
|
||||||
|
d = dst + wcslen(dst);
|
||||||
|
|
||||||
|
if (flags & VIS_GLOB)
|
||||||
|
for (s = char_glob; *s; *d++ = *s++)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (flags & VIS_SHELL)
|
||||||
|
for (s = char_shell; *s; *d++ = *s++)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (flags & VIS_SP) *d++ = L' ';
|
||||||
|
if (flags & VIS_TAB) *d++ = L'\t';
|
||||||
|
if (flags & VIS_NL) *d++ = L'\n';
|
||||||
|
if (flags & VIS_DQ) *d++ = L'"';
|
||||||
|
if ((flags & VIS_NOSLASH) == 0) *d++ = L'\\';
|
||||||
|
*d = L'\0';
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* istrsenvisx()
|
||||||
|
* The main internal function.
|
||||||
|
* All user-visible functions call this one.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,
|
||||||
|
int flags, const char *mbextra, int *cerr_ptr)
|
||||||
|
{
|
||||||
|
wchar_t *dst, *src, *pdst, *psrc, *start, *extra;
|
||||||
|
size_t len, olen;
|
||||||
|
uint64_t bmsk, wmsk;
|
||||||
|
wint_t c;
|
||||||
|
visfun_t f;
|
||||||
|
int clen = 0, cerr, error = -1, i, shft;
|
||||||
|
char *mbdst, *mdst;
|
||||||
|
ssize_t mbslength, maxolen;
|
||||||
|
|
||||||
|
_DIAGASSERT(mbdstp != NULL);
|
||||||
|
_DIAGASSERT(mbsrc != NULL || mblength == 0);
|
||||||
|
_DIAGASSERT(mbextra != NULL);
|
||||||
|
|
||||||
|
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++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
mdst = NULL;
|
||||||
|
if ((psrc = calloc(mbslength + 1, sizeof(*psrc))) == NULL)
|
||||||
|
return -1;
|
||||||
|
if ((pdst = calloc((16 * mbslength) + 1, sizeof(*pdst))) == NULL)
|
||||||
|
goto out;
|
||||||
|
if (*mbdstp == NULL) {
|
||||||
|
if ((mdst = calloc((16 * mbslength) + 1, sizeof(*mdst))) == NULL)
|
||||||
|
goto out;
|
||||||
|
*mbdstp = mdst;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbdst = *mbdstp;
|
||||||
|
dst = pdst;
|
||||||
|
src = psrc;
|
||||||
|
|
||||||
|
if (flags & VIS_NOLOCALE) {
|
||||||
|
/* Do one byte at a time conversion */
|
||||||
|
cerr = 1;
|
||||||
|
} else {
|
||||||
|
/* Use caller's multibyte conversion error flag. */
|
||||||
|
cerr = cerr_ptr ? *cerr_ptr : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Convert extra argument to list of characters for this mode. */
|
||||||
|
extra = makeextralist(flags, mbextra);
|
||||||
|
if (!extra) {
|
||||||
|
if (dlen && *dlen == 0) {
|
||||||
|
errno = ENOSPC;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*mbdst = '\0'; /* can't create extra, return "" */
|
||||||
|
error = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look up which processing function to call. */
|
||||||
|
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) {
|
||||||
|
errno = ENOSPC;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Terminate the string in the buffer. */
|
||||||
|
*dst = L'\0';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output loop.
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
if (flags & VIS_NOLOCALE) {
|
||||||
|
/* 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);
|
||||||
|
free(mdst);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
istrsenvisxl(char **mbdstp, size_t *dlen, const char *mbsrc,
|
||||||
|
int flags, const char *mbextra, int *cerr_ptr)
|
||||||
|
{
|
||||||
|
return istrsenvisx(mbdstp, dlen, mbsrc,
|
||||||
|
mbsrc != NULL ? strlen(mbsrc) : 0, flags, mbextra, cerr_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
snvis(char *mbdst, size_t dlen, int c, int flags, int nextc, const char *mbextra)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strsvis(char *mbdst, const char *mbsrc, int flags, const char *mbextra)
|
||||||
|
{
|
||||||
|
return istrsenvisxl(&mbdst, NULL, mbsrc, flags, mbextra, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strsnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags, const char *mbextra)
|
||||||
|
{
|
||||||
|
return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, mbextra, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strsvisx(char *mbdst, const char *mbsrc, size_t len, int flags, const char *mbextra)
|
||||||
|
{
|
||||||
|
return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, mbextra, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strsnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
|
||||||
|
const char *mbextra)
|
||||||
|
{
|
||||||
|
return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strsenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
|
||||||
|
const char *mbextra, int *cerr_ptr)
|
||||||
|
{
|
||||||
|
return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, cerr_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vis - visually encode characters
|
* vis - visually encode characters
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
vis(char *dst, int c, int flag, int nextc)
|
vis(char *mbdst, int c, int flags, int nextc)
|
||||||
{
|
{
|
||||||
c = (unsigned char)c;
|
char cc[2];
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (flag & VIS_HTTPSTYLE) {
|
cc[0] = c;
|
||||||
/* Described in RFC 1808 */
|
cc[1] = nextc;
|
||||||
if (!(isalnum(c) /* alpha-numeric */
|
|
||||||
/* safe */
|
ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, "", NULL);
|
||||||
|| c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
|
if (ret < 0)
|
||||||
/* extra */
|
return NULL;
|
||||||
|| c == '!' || c == '*' || c == '\'' || c == '('
|
return mbdst + ret;
|
||||||
|| c == ')' || c == ',')) {
|
|
||||||
*dst++ = '%';
|
|
||||||
snprintf(dst, 4, (c < 16 ? "0%X" : "%X"), c);
|
|
||||||
dst += 2;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flag & VIS_GLOB) &&
|
char *
|
||||||
(c == '*' || c == '?' || c == '[' || c == '#'))
|
nvis(char *mbdst, size_t dlen, int c, int flags, int nextc)
|
||||||
;
|
{
|
||||||
else if (isgraph(c) ||
|
char cc[2];
|
||||||
((flag & VIS_SP) == 0 && c == ' ') ||
|
int ret;
|
||||||
((flag & VIS_TAB) == 0 && c == '\t') ||
|
|
||||||
((flag & VIS_NL) == 0 && c == '\n') ||
|
|
||||||
((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
|
|
||||||
*dst++ = c;
|
|
||||||
if (c == '\\' && (flag & VIS_NOSLASH) == 0)
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag & VIS_CSTYLE) {
|
cc[0] = c;
|
||||||
switch(c) {
|
cc[1] = nextc;
|
||||||
case '\n':
|
|
||||||
*dst++ = '\\';
|
ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, "", NULL);
|
||||||
*dst++ = 'n';
|
if (ret < 0)
|
||||||
goto done;
|
return NULL;
|
||||||
case '\r':
|
return mbdst + ret;
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'r';
|
|
||||||
goto done;
|
|
||||||
case '\b':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'b';
|
|
||||||
goto done;
|
|
||||||
case '\a':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'a';
|
|
||||||
goto done;
|
|
||||||
case '\v':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'v';
|
|
||||||
goto done;
|
|
||||||
case '\t':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 't';
|
|
||||||
goto done;
|
|
||||||
case '\f':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'f';
|
|
||||||
goto done;
|
|
||||||
case ' ':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 's';
|
|
||||||
goto done;
|
|
||||||
case '\0':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = '0';
|
|
||||||
if (isoctal(nextc)) {
|
|
||||||
*dst++ = '0';
|
|
||||||
*dst++ = '0';
|
|
||||||
}
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (((c & 0177) == ' ') || isgraph(c) || (flag & VIS_OCTAL)) {
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = ((unsigned char)c >> 6 & 07) + '0';
|
|
||||||
*dst++ = ((unsigned char)c >> 3 & 07) + '0';
|
|
||||||
*dst++ = ((unsigned char)c & 07) + '0';
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((flag & VIS_NOSLASH) == 0)
|
|
||||||
*dst++ = '\\';
|
|
||||||
if (c & 0200) {
|
|
||||||
c &= 0177;
|
|
||||||
*dst++ = 'M';
|
|
||||||
}
|
|
||||||
if (iscntrl(c)) {
|
|
||||||
*dst++ = '^';
|
|
||||||
if (c == 0177)
|
|
||||||
*dst++ = '?';
|
|
||||||
else
|
|
||||||
*dst++ = c + '@';
|
|
||||||
} else {
|
|
||||||
*dst++ = '-';
|
|
||||||
*dst++ = c;
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* strvis, strnvis, 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 NUL,
|
* expansion. The length of dst, not including the trailing NULL,
|
||||||
|
* is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
strvis(char *mbdst, const char *mbsrc, int flags)
|
||||||
|
{
|
||||||
|
return istrsenvisxl(&mbdst, NULL, mbsrc, flags, "", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags)
|
||||||
|
{
|
||||||
|
return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, "", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
stravis(char **mbdstp, const char *mbsrc, int flags)
|
||||||
|
{
|
||||||
|
*mbdstp = NULL;
|
||||||
|
return istrsenvisxl(mbdstp, NULL, mbsrc, flags, "", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* strvisx - visually encode characters from src into dst
|
||||||
|
*
|
||||||
|
* 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.
|
* is returned.
|
||||||
*
|
*
|
||||||
* Strnvis will write no more than siz-1 bytes (and will NULL terminate).
|
* Strvisx encodes exactly len characters from src into dst.
|
||||||
* The number of bytes needed to fully encode the string is returned.
|
|
||||||
*
|
|
||||||
* Strvisx encodes exactly len bytes from src into dst.
|
|
||||||
* This is useful for encoding a block of data.
|
* This is useful for encoding a block of data.
|
||||||
*/
|
*/
|
||||||
int
|
|
||||||
strvis(char *dst, const char *src, int flag)
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
char *start;
|
|
||||||
|
|
||||||
for (start = dst; (c = *src); )
|
int
|
||||||
dst = vis(dst, c, flag, *++src);
|
strvisx(char *mbdst, const char *mbsrc, size_t len, int flags)
|
||||||
*dst = '\0';
|
{
|
||||||
return (dst - start);
|
return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, "", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
strnvis(char *dst, const char *src, size_t siz, int flag)
|
strnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags)
|
||||||
{
|
{
|
||||||
char *start, *end;
|
return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", NULL);
|
||||||
char tbuf[5];
|
|
||||||
int c, i;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
|
|
||||||
if (isvisible(c)) {
|
|
||||||
i = 1;
|
|
||||||
*dst++ = c;
|
|
||||||
if (c == '\\' && (flag & VIS_NOSLASH) == 0) {
|
|
||||||
/* need space for the extra '\\' */
|
|
||||||
if (dst < end)
|
|
||||||
*dst++ = '\\';
|
|
||||||
else {
|
|
||||||
dst--;
|
|
||||||
i = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
src++;
|
|
||||||
} else {
|
|
||||||
i = vis(tbuf, c, flag, *++src) - tbuf;
|
|
||||||
if (dst + i <= end) {
|
|
||||||
memcpy(dst, tbuf, i);
|
|
||||||
dst += i;
|
|
||||||
} else {
|
|
||||||
src--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (siz > 0)
|
|
||||||
*dst = '\0';
|
|
||||||
if (dst + i > end) {
|
|
||||||
/* adjust return value for truncation */
|
|
||||||
while ((c = *src))
|
|
||||||
dst += vis(tbuf, c, flag, *++src) - tbuf;
|
|
||||||
}
|
|
||||||
return (dst - start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
strvisx(char *dst, 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)
|
||||||
{
|
{
|
||||||
int c;
|
return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", cerr_ptr);
|
||||||
char *start;
|
|
||||||
|
|
||||||
for (start = dst; len > 1; len--) {
|
|
||||||
c = *src;
|
|
||||||
dst = vis(dst, c, flag, *++src);
|
|
||||||
}
|
|
||||||
if (len)
|
|
||||||
dst = vis(dst, *src, flag, '\0');
|
|
||||||
*dst = '\0';
|
|
||||||
|
|
||||||
return (dst - start);
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user