mirror of
https://gitlab.freedesktop.org/libbsd/libbsd.git
synced 2025-01-09 11:17:37 +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/strnstr.c
|
||||
src/unvis.c
|
||||
src/vis.c
|
||||
Copyright:
|
||||
Copyright © 1980, 1982, 1986, 1989-1994
|
||||
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
|
||||
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:
|
||||
include/bsd/sys/endian.h
|
||||
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
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
@ -27,7 +29,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)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
|
||||
@ -38,25 +39,34 @@
|
||||
/*
|
||||
* to select alternate encoding format
|
||||
*/
|
||||
#define VIS_OCTAL 0x01 /* use octal \ddd format */
|
||||
#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */
|
||||
#define VIS_OCTAL 0x0001 /* use octal \ddd format */
|
||||
#define VIS_CSTYLE 0x0002 /* use \[nrft0..] where appropriate */
|
||||
|
||||
/*
|
||||
* to alter set of characters encoded (default is to encode all
|
||||
* non-graphic except space, tab, and newline).
|
||||
*/
|
||||
#define VIS_SP 0x04 /* also encode space */
|
||||
#define VIS_TAB 0x08 /* also encode tab */
|
||||
#define VIS_NL 0x10 /* also encode newline */
|
||||
#define VIS_SP 0x0004 /* also encode space */
|
||||
#define VIS_TAB 0x0008 /* also encode tab */
|
||||
#define VIS_NL 0x0010 /* also encode newline */
|
||||
#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
|
||||
*/
|
||||
#define VIS_NOSLASH 0x40 /* inhibit printing '\' */
|
||||
#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */
|
||||
#define VIS_GLOB 0x100 /* encode glob(3) magics */
|
||||
#define VIS_NOSLASH 0x0040 /* inhibit printing '\' */
|
||||
#define VIS_HTTP1808 0x0080 /* http-style escape % hex hex */
|
||||
#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
|
||||
@ -70,7 +80,7 @@
|
||||
/*
|
||||
* unvis flags
|
||||
*/
|
||||
#define UNVIS_END 1 /* no more characters */
|
||||
#define UNVIS_END _VIS_END /* no more characters */
|
||||
|
||||
#ifdef LIBBSD_OVERLAY
|
||||
#include <sys/cdefs.h>
|
||||
@ -80,12 +90,33 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
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 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 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 strnunvis(char *, size_t, const char *);
|
||||
|
||||
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);
|
||||
__END_DECLS
|
||||
|
||||
|
201
man/unvis.3bsd
201
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
|
||||
.\" 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
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd $Mdocdate: May 31 2007 $
|
||||
.\" @(#)unvis.3 8.2 (Berkeley) 12/11/93
|
||||
.\"
|
||||
.Dd March 12, 2011
|
||||
.Dt UNVIS 3bsd
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm unvis ,
|
||||
.Nm strunvis ,
|
||||
.Nm strnunvis
|
||||
.Nm strnunvis ,
|
||||
.Nm strunvisx ,
|
||||
.Nm strnunvisx
|
||||
.Nd decode a visual representation of characters
|
||||
.Sh LIBRARY
|
||||
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
|
||||
@ -44,88 +48,91 @@
|
||||
.Xr libbsd 7
|
||||
for include usage.)
|
||||
.Ft int
|
||||
.Fn unvis "char *cp" "char c" "int *astate" "int flag"
|
||||
.Fn unvis "char *cp" "int c" "int *astate" "int flag"
|
||||
.Ft int
|
||||
.Fn strunvis "char *dst" "char *src"
|
||||
.Ft ssize_t
|
||||
.Fn strnunvis "char *dst" "char *src" "size_t size"
|
||||
.Fn strunvis "char *dst" "const char *src"
|
||||
.Ft int
|
||||
.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
|
||||
The
|
||||
.Fn unvis ,
|
||||
.Fn strunvis
|
||||
and
|
||||
.Fn strnunvis
|
||||
functions are used to decode a visual representation of characters,
|
||||
as produced by the
|
||||
.Fn strunvisx
|
||||
functions
|
||||
are used to decode a visual representation of characters, as produced
|
||||
by the
|
||||
.Xr vis 3bsd
|
||||
function, back into the original form.
|
||||
function, back into
|
||||
the original form.
|
||||
.Pp
|
||||
The
|
||||
.Fn unvis
|
||||
is called with successive characters in
|
||||
.Fa c
|
||||
until a valid
|
||||
sequence is recognized, at which time the decoded character is
|
||||
available at the character pointed to by
|
||||
.Fa cp .
|
||||
function is called with successive characters in
|
||||
.Ar c
|
||||
until a valid sequence is recognized, at which time the decoded
|
||||
character is available at the character pointed to by
|
||||
.Ar cp .
|
||||
.Pp
|
||||
The
|
||||
.Fn strunvis
|
||||
decodes the characters pointed to by
|
||||
.Fa src
|
||||
function decodes the characters pointed to by
|
||||
.Ar src
|
||||
into the buffer pointed to by
|
||||
.Fa 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.
|
||||
.Ar dst .
|
||||
The
|
||||
.Fn strunvis
|
||||
function simply copies
|
||||
.Fa src
|
||||
.Ar src
|
||||
to
|
||||
.Fa dst ,
|
||||
.Ar dst ,
|
||||
decoding any escape sequences along the way,
|
||||
and returns the number of characters placed into
|
||||
.Fa dst ,
|
||||
.Ar dst ,
|
||||
or \-1 if an
|
||||
invalid escape sequence was detected.
|
||||
The size of
|
||||
.Fa dst
|
||||
should be
|
||||
equal to the size of
|
||||
.Fa src
|
||||
.Ar dst
|
||||
should be equal to the size of
|
||||
.Ar src
|
||||
(that is, no expansion takes place during decoding).
|
||||
.Pp
|
||||
The
|
||||
.Fn strunvisx
|
||||
function does the same as the
|
||||
.Fn strunvis
|
||||
terminates the destination string with a trailing NUL byte;
|
||||
.Fn strnunvis
|
||||
does so if
|
||||
.Fa size
|
||||
is larger than 0.
|
||||
function,
|
||||
but it allows you to add a flag that specifies the style the string
|
||||
.Ar src
|
||||
is encoded with.
|
||||
Currently, the supported flags are:
|
||||
.Dv VIS_HTTPSTYLE
|
||||
and
|
||||
.Dv VIS_MIMESTYLE .
|
||||
.Pp
|
||||
The
|
||||
.Fn unvis
|
||||
function implements a state machine that can be used to decode an arbitrary
|
||||
stream of bytes.
|
||||
function implements a state machine that can be used to decode an
|
||||
arbitrary stream of bytes.
|
||||
All state associated with the bytes being decoded is stored outside the
|
||||
.Fn unvis
|
||||
function (that is, a pointer to the state is passed in), so
|
||||
calls decoding different streams can be freely intermixed.
|
||||
To start decoding a stream of bytes, first initialize an integer
|
||||
to zero.
|
||||
To start decoding a stream of bytes, first initialize an integer to zero.
|
||||
Call
|
||||
.Fn unvis
|
||||
with each successive byte, along with a pointer
|
||||
to this integer, and a pointer to a destination character.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn unvis
|
||||
function has several return codes that must be handled properly.
|
||||
They are:
|
||||
.Bl -tag -width UNVIS_VALIDPUSH
|
||||
.It Li \&0 (zero)
|
||||
.It Li \&0 No (zero)
|
||||
Another character is necessary; nothing has been recognized yet.
|
||||
.It Dv UNVIS_VALID
|
||||
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.
|
||||
This return code is necessary to indicate a logical break between characters.
|
||||
.It Dv UNVIS_SYNBAD
|
||||
An invalid escape sequence was detected, or the decoder is in an
|
||||
unknown state.
|
||||
An invalid escape sequence was detected, or the decoder is in an unknown state.
|
||||
The decoder is placed into the starting state.
|
||||
.El
|
||||
.Pp
|
||||
When all bytes in the stream have been processed, call
|
||||
.Fn unvis
|
||||
one more time with
|
||||
.Fa flag
|
||||
set to
|
||||
one more time with flag set to
|
||||
.Dv UNVIS_END
|
||||
to extract any remaining character (the character passed in is ignored).
|
||||
.Pp
|
||||
The
|
||||
.Fn strunvis
|
||||
function returns the number of bytes written (not counting
|
||||
the trailing NUL byte) or \-1 if an error occurred.
|
||||
.Fa flag
|
||||
argument is also used to specify the encoding style of the source.
|
||||
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
|
||||
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
|
||||
.Fn unvis .
|
||||
.Bd -literal -offset indent
|
||||
@ -177,25 +195,72 @@ again:
|
||||
case UNVIS_NOCHAR:
|
||||
break;
|
||||
case UNVIS_VALID:
|
||||
(void) putchar(out);
|
||||
(void)putchar(out);
|
||||
break;
|
||||
case UNVIS_VALIDPUSH:
|
||||
(void) putchar(out);
|
||||
(void)putchar(out);
|
||||
goto again;
|
||||
case UNVIS_SYNBAD:
|
||||
(void)fprintf(stderr, "bad sequence!\en");
|
||||
exit(1);
|
||||
errx(EXIT_FAILURE, "Bad character sequence!");
|
||||
}
|
||||
}
|
||||
if (unvis(&out, (char)0, &state, UNVIS_END) == UNVIS_VALID)
|
||||
(void) putchar(out);
|
||||
if (unvis(&out, '\e0', &state, UNVIS_END) == UNVIS_VALID)
|
||||
(void)putchar(out);
|
||||
.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
|
||||
.Xr unvis 1 ,
|
||||
.Xr vis 1 ,
|
||||
.Xr vis 3bsd
|
||||
.Rs
|
||||
.%A R. Fielding
|
||||
.%T Relative Uniform Resource Locators
|
||||
.%O RFC1808
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn unvis
|
||||
function first appeared in
|
||||
function
|
||||
first appeared in
|
||||
.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
|
||||
.\" 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
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd $Mdocdate: May 31 2007 $
|
||||
.\" @(#)vis.3 8.1 (Berkeley) 6/9/93
|
||||
.\"
|
||||
.Dd April 22, 2017
|
||||
.Dt VIS 3bsd
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm vis ,
|
||||
.Nm nvis ,
|
||||
.Nm strvis ,
|
||||
.Nm stravis ,
|
||||
.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
|
||||
.Sh LIBRARY
|
||||
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
|
||||
.Lb libbsd
|
||||
.Sh SYNOPSIS
|
||||
.In stdlib.h
|
||||
.In vis.h
|
||||
(See
|
||||
.Xr libbsd 7
|
||||
for include usage.)
|
||||
.Ft char *
|
||||
.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
|
||||
.Fn strvis "char *dst" "const char *src" "int flag"
|
||||
.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
|
||||
.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
|
||||
The
|
||||
.Fn vis
|
||||
function copies into
|
||||
function
|
||||
copies into
|
||||
.Fa dst
|
||||
a string which represents the character
|
||||
.Fa c .
|
||||
If
|
||||
.Fa c
|
||||
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.
|
||||
The maximum length of any encoding is four
|
||||
characters (not including the trailing NUL);
|
||||
bytes (not including the trailing
|
||||
.Dv NUL ) ;
|
||||
thus, when
|
||||
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
|
||||
NUL.
|
||||
The
|
||||
.Fa flag
|
||||
parameter is used for altering the default range of
|
||||
be four times the number of bytes encoded, plus one for the trailing
|
||||
.Dv NUL .
|
||||
The flag parameter is used for altering the default range of
|
||||
characters considered for encoding and for altering the visual
|
||||
representation.
|
||||
The additional character,
|
||||
@ -84,9 +118,11 @@ encoding format (explained below).
|
||||
.Pp
|
||||
The
|
||||
.Fn strvis ,
|
||||
.Fn strnvis
|
||||
.Fn stravis ,
|
||||
.Fn strnvis ,
|
||||
.Fn strvisx ,
|
||||
and
|
||||
.Fn strvisx
|
||||
.Fn strnvisx
|
||||
functions copy into
|
||||
.Fa dst
|
||||
a visual representation of
|
||||
@ -94,89 +130,153 @@ the string
|
||||
.Fa src .
|
||||
The
|
||||
.Fn strvis
|
||||
function encodes characters from
|
||||
.Fa src
|
||||
up to the first NUL.
|
||||
The
|
||||
and
|
||||
.Fn strnvis
|
||||
function encodes characters from
|
||||
functions encode characters from
|
||||
.Fa src
|
||||
up to the first NUL or the end of
|
||||
.Fa dst ,
|
||||
as indicated by
|
||||
.Fa size .
|
||||
up to the
|
||||
first
|
||||
.Dv NUL .
|
||||
The
|
||||
.Fn strvisx
|
||||
function encodes exactly
|
||||
and
|
||||
.Fn strnvisx
|
||||
functions encode exactly
|
||||
.Fa len
|
||||
characters from
|
||||
.Fa src
|
||||
(this
|
||||
is useful for encoding a block of data that may contain NULs).
|
||||
All three forms NUL terminate
|
||||
.Fa dst ,
|
||||
except for
|
||||
.Fn strnvis
|
||||
when
|
||||
.Fa size
|
||||
is zero, in which case
|
||||
.Fa dst
|
||||
is not touched.
|
||||
For
|
||||
.Fn strvis
|
||||
and
|
||||
.Fn strvisx ,
|
||||
the size of
|
||||
is useful for encoding a block of data that may contain
|
||||
.Dv NUL Ns 's ) .
|
||||
Both forms
|
||||
.Dv NUL
|
||||
terminate
|
||||
.Fa dst .
|
||||
The size of
|
||||
.Fa dst
|
||||
must be four times the number
|
||||
of characters encoded from
|
||||
of bytes encoded from
|
||||
.Fa src
|
||||
(plus one for the NUL).
|
||||
.Fn strvis
|
||||
(plus one for the
|
||||
.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
|
||||
.Fn strvisx
|
||||
return the number of characters in
|
||||
.Fa dst
|
||||
(not including the trailing NUL).
|
||||
.Fn strnvis
|
||||
returns the length that
|
||||
.Fa dst
|
||||
would become if it were of unlimited size (similar to
|
||||
.Xr snprintf 3
|
||||
or
|
||||
.Xr strlcpy 3bsd ) .
|
||||
This can be used to detect truncation but it also means that
|
||||
the return value of
|
||||
.Fn strnvis
|
||||
must not be used without checking it against
|
||||
.Fa size .
|
||||
.Fn strnvisx
|
||||
functions return \-1 and set
|
||||
.Va errno
|
||||
to
|
||||
.Dv ENOSPC .
|
||||
The
|
||||
.Fn strenvisx
|
||||
function takes an additional argument,
|
||||
.Fa cerr_ptr ,
|
||||
that is used to pass in and out a multibyte conversion error flag.
|
||||
This is useful when processing single characters at a time when
|
||||
it is possible that the locale may be set to something other
|
||||
than the locale of the characters in the input data.
|
||||
.Pp
|
||||
The functions
|
||||
.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
|
||||
The encoding is a unique, invertible representation composed entirely of
|
||||
graphic characters; it can be decoded back into the original form using
|
||||
the
|
||||
.Xr unvis 3bsd
|
||||
or
|
||||
.Xr unvis 3bsd ,
|
||||
.Xr strunvis 3bsd
|
||||
or
|
||||
.Xr strnunvis 3bsd
|
||||
functions.
|
||||
.Pp
|
||||
There are two parameters that can be controlled: the range of
|
||||
characters that are encoded, and the type
|
||||
of representation used.
|
||||
By default, all non-graphic characters
|
||||
except space, tab, and newline are encoded
|
||||
(see
|
||||
characters that are encoded (applies only to
|
||||
.Fn vis ,
|
||||
.Fn nvis ,
|
||||
.Fn strvis ,
|
||||
.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 ) .
|
||||
The following flags
|
||||
alter this:
|
||||
.Bl -tag -width VIS_WHITEX
|
||||
.It Dv VIS_DQ
|
||||
Also encode double quotes
|
||||
.It Dv VIS_GLOB
|
||||
Also encode magic characters recognized by
|
||||
.Xr glob 3
|
||||
.Pf ( Ql * ,
|
||||
Also encode the magic characters
|
||||
.Ql ( * ,
|
||||
.Ql \&? ,
|
||||
.Ql \&[ )
|
||||
.Ql \&[ ,
|
||||
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
|
||||
Also encode space.
|
||||
.It Dv VIS_TAB
|
||||
@ -185,34 +285,56 @@ Also encode tab.
|
||||
Also encode newline.
|
||||
.It Dv VIS_WHITE
|
||||
Synonym for
|
||||
.Dv VIS_SP
|
||||
\&|
|
||||
.Dv VIS_TAB
|
||||
\&|
|
||||
.Dv VIS_NL .
|
||||
.Dv VIS_SP | VIS_TAB | VIS_NL .
|
||||
.It Dv VIS_META
|
||||
Synonym for
|
||||
.Dv VIS_WHITE | VIS_GLOB | VIS_SHELL .
|
||||
.It Dv VIS_SAFE
|
||||
Only encode
|
||||
.Dq unsafe
|
||||
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.
|
||||
Currently this form allows space,
|
||||
tab, newline, backspace, bell, and return -- in addition
|
||||
to all graphic characters -- unencoded.
|
||||
Currently this form allows space, tab, newline, backspace, bell, and
|
||||
return \(em in addition to all graphic characters \(em unencoded.
|
||||
.El
|
||||
.Pp
|
||||
There are three forms of encoding.
|
||||
All forms use the backslash
|
||||
(The above flags have no effect for
|
||||
.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
|
||||
character to introduce a special
|
||||
sequence; two backslashes are used to represent a real backslash.
|
||||
to introduce a special
|
||||
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:
|
||||
.Bl -tag -width VIS_CSTYLE
|
||||
.It (default)
|
||||
Use an
|
||||
.Ql M
|
||||
to represent meta characters (characters with the 8th
|
||||
bit set), and use a caret
|
||||
bit set), and use caret
|
||||
.Ql ^
|
||||
to represent control characters (see
|
||||
.Xr iscntrl 3 ) .
|
||||
@ -256,27 +378,27 @@ space.
|
||||
.It Dv \e240
|
||||
Represents Meta-space.
|
||||
.El
|
||||
.Pp
|
||||
.It Dv VIS_CSTYLE
|
||||
Use C-style backslash sequences to represent standard non-printable
|
||||
characters.
|
||||
The following sequences are used to represent the indicated characters:
|
||||
.Bd -unfilled -offset indent
|
||||
.Li \ea Tn - BEL No (007)
|
||||
.Li \eb Tn - BS No (010)
|
||||
.Li \ef Tn - NP No (014)
|
||||
.Li \en Tn - NL No (012)
|
||||
.Li \er Tn - CR No (015)
|
||||
.Li \es Tn - SP No (040)
|
||||
.Li \et Tn - HT No (011)
|
||||
.Li \ev Tn - VT No (013)
|
||||
.Li \e0 Tn - NUL No (000)
|
||||
.Li \ea Tn \(em BEL No (007)
|
||||
.Li \eb Tn \(em BS No (010)
|
||||
.Li \ef Tn \(em NP No (014)
|
||||
.Li \en Tn \(em NL No (012)
|
||||
.Li \er Tn \(em CR No (015)
|
||||
.Li \es Tn \(em SP No (040)
|
||||
.Li \et Tn \(em HT No (011)
|
||||
.Li \ev Tn \(em VT No (013)
|
||||
.Li \e0 Tn \(em NUL No (000)
|
||||
.Ed
|
||||
.Pp
|
||||
When using this format, the
|
||||
.Fa nextc
|
||||
parameter is looked at to determine
|
||||
if a NUL character can be encoded as
|
||||
parameter is looked at to determine if a
|
||||
.Dv NUL
|
||||
character can be encoded as
|
||||
.Ql \e0
|
||||
instead of
|
||||
.Ql \e000 .
|
||||
@ -284,13 +406,36 @@ If
|
||||
.Fa nextc
|
||||
is an octal digit, the latter representation is used to
|
||||
avoid ambiguity.
|
||||
.Pp
|
||||
Non-printable characters without C-style
|
||||
backslash sequences use the default representation.
|
||||
.It Dv VIS_OCTAL
|
||||
Use a three digit octal sequence.
|
||||
The form is
|
||||
.Ql \eddd
|
||||
where
|
||||
.Ar d
|
||||
.Em d
|
||||
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
|
||||
.Pp
|
||||
There is one additional flag,
|
||||
@ -304,21 +449,112 @@ meta characters as
|
||||
.Ql M-C ) .
|
||||
With this flag set, the encoding is
|
||||
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
|
||||
.Xr unvis 1 ,
|
||||
.Xr vis 1 ,
|
||||
.Xr snprintf 3 ,
|
||||
.Xr strlcpy 3bsd ,
|
||||
.Xr glob 3 ,
|
||||
.\" .Xr multibyte 3 ,
|
||||
.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
|
||||
The
|
||||
.Fn vis ,
|
||||
.Fn strvis
|
||||
.Fn strvis ,
|
||||
and
|
||||
.Fn strvisx
|
||||
functions first appeared in
|
||||
.Bx 4.4 .
|
||||
The
|
||||
.Fn strnvis
|
||||
function first appeared in
|
||||
.Ox 2.9 .
|
||||
.Fn svis ,
|
||||
.Fn strsvis ,
|
||||
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;
|
||||
|
||||
pidfile_fileno;
|
||||
|
||||
nvis;
|
||||
snvis;
|
||||
stravis;
|
||||
strenvisx;
|
||||
strnunvisx;
|
||||
strsenvisx;
|
||||
strsnvis;
|
||||
strsnvisx;
|
||||
strsvis;
|
||||
strsvisx;
|
||||
svis;
|
||||
} LIBBSD_0.8;
|
||||
|
546
src/unvis.c
546
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
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
@ -27,10 +29,22 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <vis.h>
|
||||
|
||||
#ifdef __weak_alias
|
||||
__weak_alias(strnunvisx,_strnunvisx)
|
||||
#endif
|
||||
|
||||
#define _DIAGASSERT(x)
|
||||
|
||||
/*
|
||||
* decode driven by state machine
|
||||
*/
|
||||
@ -41,15 +55,128 @@
|
||||
#define S_CTRL 4 /* control char started (^) */
|
||||
#define S_OCTAL2 5 /* octal digit 2 */
|
||||
#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')
|
||||
#define ishex(c) \
|
||||
((((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '9') || \
|
||||
(((unsigned char)(c)) >= 'a' && ((unsigned char)(c)) <= 'f'))
|
||||
/*
|
||||
* RFC 1866
|
||||
*/
|
||||
static const struct nv {
|
||||
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
|
||||
@ -57,276 +184,367 @@
|
||||
int
|
||||
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 (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
switch (st) {
|
||||
case S_OCTAL2:
|
||||
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:
|
||||
*cp = 0;
|
||||
if (c == '\\') {
|
||||
*astate = S_START;
|
||||
return (0);
|
||||
if ((flag & VIS_NOESCAPE) == 0 && c == '\\') {
|
||||
*astate = SS(0, S_START);
|
||||
return UNVIS_NOCHAR;
|
||||
}
|
||||
if (flag & VIS_HTTPSTYLE && c == '%') {
|
||||
*astate = S_START | S_HTTP;
|
||||
return (0);
|
||||
if ((flag & VIS_HTTP1808) && c == '%') {
|
||||
*astate = SS(0, S_HEX1);
|
||||
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;
|
||||
return (UNVIS_VALID);
|
||||
return UNVIS_VALID;
|
||||
|
||||
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) {
|
||||
case '\\':
|
||||
*cp = c;
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
*cp = (c - '0');
|
||||
*astate = S_OCTAL2;
|
||||
return (0);
|
||||
*astate = SS(0, S_OCTAL2);
|
||||
return UNVIS_NOCHAR;
|
||||
case 'M':
|
||||
*cp = 0200;
|
||||
*astate = S_META;
|
||||
return (0);
|
||||
*cp = (char)0200;
|
||||
*astate = SS(0, S_META);
|
||||
return UNVIS_NOCHAR;
|
||||
case '^':
|
||||
*astate = S_CTRL;
|
||||
return (0);
|
||||
*astate = SS(0, S_CTRL);
|
||||
return UNVIS_NOCHAR;
|
||||
case 'n':
|
||||
*cp = '\n';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 'r':
|
||||
*cp = '\r';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 'b':
|
||||
*cp = '\b';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 'a':
|
||||
*cp = '\007';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 'v':
|
||||
*cp = '\v';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 't':
|
||||
*cp = '\t';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 'f':
|
||||
*cp = '\f';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 's':
|
||||
*cp = ' ';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 'E':
|
||||
*cp = '\033';
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
case 'x':
|
||||
*astate = SS(0, S_HEX);
|
||||
return UNVIS_NOCHAR;
|
||||
case '\n':
|
||||
/*
|
||||
* hidden newline
|
||||
*/
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_NOCHAR);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_NOCHAR;
|
||||
case '$':
|
||||
/*
|
||||
* hidden marker
|
||||
*/
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_NOCHAR);
|
||||
*astate = SS(0, S_GROUND);
|
||||
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:
|
||||
if (c == '-')
|
||||
*astate = S_META1;
|
||||
*astate = SS(0, S_META1);
|
||||
else if (c == '^')
|
||||
*astate = S_CTRL;
|
||||
else {
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_SYNBAD);
|
||||
}
|
||||
return (0);
|
||||
*astate = SS(0, S_CTRL);
|
||||
else
|
||||
goto bad;
|
||||
return UNVIS_NOCHAR;
|
||||
|
||||
case S_META1:
|
||||
*astate = S_GROUND;
|
||||
*astate = SS(0, S_GROUND);
|
||||
*cp |= c;
|
||||
return (UNVIS_VALID);
|
||||
return UNVIS_VALID;
|
||||
|
||||
case S_CTRL:
|
||||
if (c == '?')
|
||||
*cp |= 0177;
|
||||
else
|
||||
*cp |= c & 037;
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALID);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALID;
|
||||
|
||||
case S_OCTAL2: /* second possible octal digit */
|
||||
if (isoctal(c)) {
|
||||
if (isoctal(uc)) {
|
||||
/*
|
||||
* yes - and maybe a third
|
||||
*/
|
||||
*cp = (*cp << 3) + (c - '0');
|
||||
*astate = S_OCTAL3;
|
||||
return (0);
|
||||
*astate = SS(0, S_OCTAL3);
|
||||
return UNVIS_NOCHAR;
|
||||
}
|
||||
/*
|
||||
* no - done with current sequence, push back passed char
|
||||
*/
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_VALIDPUSH);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_VALIDPUSH;
|
||||
|
||||
case S_OCTAL3: /* third possible octal digit */
|
||||
*astate = S_GROUND;
|
||||
if (isoctal(c)) {
|
||||
*astate = SS(0, S_GROUND);
|
||||
if (isoctal(uc)) {
|
||||
*cp = (*cp << 3) + (c - '0');
|
||||
return (UNVIS_VALID);
|
||||
return UNVIS_VALID;
|
||||
}
|
||||
/*
|
||||
* we were done, push back passed char
|
||||
*/
|
||||
return (UNVIS_VALIDPUSH);
|
||||
return UNVIS_VALIDPUSH;
|
||||
|
||||
case S_HEX2: /* second mandatory hex digit */
|
||||
if (ishex(tolower(c))) {
|
||||
*cp = (isdigit(c) ? (*cp << 4) + (c - '0') : (*cp << 4) + (tolower(c) - 'a' + 10));
|
||||
case S_HEX:
|
||||
if (!isxdigit(uc))
|
||||
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;
|
||||
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:
|
||||
bad:
|
||||
/*
|
||||
* decoder in unknown state - (probably uninitialized)
|
||||
*/
|
||||
*astate = S_GROUND;
|
||||
return (UNVIS_SYNBAD);
|
||||
*astate = SS(0, S_GROUND);
|
||||
return UNVIS_SYNBAD;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* strunvis - decode src into dst
|
||||
* strnunvisx - decode src into dst
|
||||
*
|
||||
* Number of chars decoded into dst is returned, -1 on error.
|
||||
* Dst is null terminated.
|
||||
*/
|
||||
|
||||
int
|
||||
strunvis(char *dst, const char *src)
|
||||
strnunvisx(char *dst, size_t dlen, const char *src, int flag)
|
||||
{
|
||||
char c;
|
||||
char *start = dst;
|
||||
char t = '\0', *start = dst;
|
||||
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:
|
||||
switch (unvis(dst, c, &state, 0)) {
|
||||
switch (unvis(&t, c, &state, flag)) {
|
||||
case UNVIS_VALID:
|
||||
dst++;
|
||||
CHECKSPACE();
|
||||
*dst++ = t;
|
||||
break;
|
||||
case UNVIS_VALIDPUSH:
|
||||
dst++;
|
||||
CHECKSPACE();
|
||||
*dst++ = t;
|
||||
goto again;
|
||||
case 0:
|
||||
case UNVIS_NOCHAR:
|
||||
break;
|
||||
case UNVIS_SYNBAD:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
default:
|
||||
_DIAGASSERT(/*CONSTCOND*/0);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (unvis(&t, c, &state, UNVIS_END) == UNVIS_VALID) {
|
||||
CHECKSPACE();
|
||||
*dst++ = t;
|
||||
}
|
||||
CHECKSPACE();
|
||||
*dst = '\0';
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
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);
|
||||
return (int)(dst - start);
|
||||
}
|
||||
|
||||
int
|
||||
strunvisx(char *dst, const char *src, int flag)
|
||||
{
|
||||
char c;
|
||||
char *start = dst;
|
||||
int state = 0;
|
||||
|
||||
while ((c = *src++)) {
|
||||
again:
|
||||
switch (unvis(dst, c, &state, flag)) {
|
||||
case UNVIS_VALID:
|
||||
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)
|
||||
dst++;
|
||||
*dst = '\0';
|
||||
return (dst - start);
|
||||
return strnunvisx(dst, (size_t)~0, src, flag);
|
||||
}
|
||||
|
||||
int
|
||||
strunvis(char *dst, const char *src)
|
||||
{
|
||||
return strnunvisx(dst, (size_t)~0, src, 0);
|
||||
}
|
||||
|
||||
int
|
||||
strnunvis(char *dst, size_t dlen, const char *src)
|
||||
{
|
||||
return strnunvisx(dst, dlen, src, 0);
|
||||
}
|
||||
|
876
src/vis.c
876
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
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
@ -28,220 +29,717 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <vis.h>
|
||||
/*-
|
||||
* Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* 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) \
|
||||
(((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '7')
|
||||
#define isvisible(c) \
|
||||
(((unsigned int)(c) <= UCHAR_MAX && \
|
||||
isascii((unsigned char)(c)) && \
|
||||
(((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \
|
||||
(flag & VIS_GLOB) == 0) && \
|
||||
isgraph((unsigned char)(c))) || \
|
||||
((flag & VIS_SP) == 0 && (c) == ' ') || \
|
||||
((flag & VIS_TAB) == 0 && (c) == '\t') || \
|
||||
((flag & VIS_NL) == 0 && (c) == '\n') || \
|
||||
((flag & VIS_SAFE) && ((c) == '\b' || \
|
||||
(c) == '\007' || (c) == '\r' || \
|
||||
isgraph((unsigned char)(c)))))
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <vis.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#ifdef __weak_alias
|
||||
__weak_alias(strvisx,_strvisx)
|
||||
#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
|
||||
*/
|
||||
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) {
|
||||
/* Described in RFC 1808 */
|
||||
if (!(isalnum(c) /* alpha-numeric */
|
||||
/* safe */
|
||||
|| c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
|
||||
/* extra */
|
||||
|| c == '!' || c == '*' || c == '\'' || c == '('
|
||||
|| c == ')' || c == ',')) {
|
||||
*dst++ = '%';
|
||||
snprintf(dst, 4, (c < 16 ? "0%X" : "%X"), c);
|
||||
dst += 2;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
cc[0] = c;
|
||||
cc[1] = nextc;
|
||||
|
||||
if ((flag & VIS_GLOB) &&
|
||||
(c == '*' || c == '?' || c == '[' || c == '#'))
|
||||
;
|
||||
else if (isgraph(c) ||
|
||||
((flag & VIS_SP) == 0 && c == ' ') ||
|
||||
((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);
|
||||
}
|
||||
ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, "", NULL);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
return mbdst + ret;
|
||||
}
|
||||
|
||||
if (flag & VIS_CSTYLE) {
|
||||
switch(c) {
|
||||
case '\n':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'n';
|
||||
goto done;
|
||||
case '\r':
|
||||
*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);
|
||||
char *
|
||||
nvis(char *mbdst, size_t dlen, int c, int flags, int nextc)
|
||||
{
|
||||
char cc[2];
|
||||
int ret;
|
||||
|
||||
cc[0] = c;
|
||||
cc[1] = nextc;
|
||||
|
||||
ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, "", NULL);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
return mbdst + ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* Strnvis will write no more than siz-1 bytes (and will NULL terminate).
|
||||
* The number of bytes needed to fully encode the string is returned.
|
||||
*
|
||||
* Strvisx encodes exactly len bytes from src into dst.
|
||||
* Strvisx encodes exactly len characters from src into dst.
|
||||
* 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); )
|
||||
dst = vis(dst, c, flag, *++src);
|
||||
*dst = '\0';
|
||||
return (dst - start);
|
||||
int
|
||||
strvisx(char *mbdst, const char *mbsrc, size_t len, int flags)
|
||||
{
|
||||
return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, "", NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", cerr_ptr);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user