Commit Diff


commit - ddbcd3c13f2159113bb7e9921a1bec13755c5d43
commit + d13b044d59619a52277c229eb37d38265690fb64
blob - f820f71c219debfb93731a6abbb6ea5fb284f4fc
blob + 65ec3ef2b2dce2eda370c789d62e7c02b6eadb74
--- compat/Makefile
+++ compat/Makefile
@@ -19,7 +19,8 @@ DISTFILES =	Makefile \
 		strlcpy.c \
 		strtonum.c \
 		tree.h \
-		vasprintf.c
+		vasprintf.c \
+		vis.c
 
 all:
 	false
@@ -27,6 +28,8 @@ all:
 dist: ${DISTFILES}
 	mkdir -p ${DESTDIR}/
 	${INSTALL} -m 0644 ${DISTFILES} ${DESTDIR}/
+	mkdir -p ${DESTDIR}/vis
+	${INSTALL} -m 0644 vis/vis.h ${DESTDIR}/vis
 
 .PHONY: all dist
 include ../config.mk
blob - /dev/null
blob + 59b7d6b81777229668dfbb0bb1aaaca8e126eb8c (mode 644)
--- /dev/null
+++ compat/vis/vis.h
@@ -0,0 +1,90 @@
+/*	$OpenBSD: vis.h,v 1.15 2015/07/20 01:52:27 millert Exp $	*/
+/*	$NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)vis.h	5.9 (Berkeley) 4/3/91
+ */
+
+#ifndef _VIS_H_
+#define	_VIS_H_
+
+/*
+ * to select alternate encoding format
+ */
+#define	VIS_OCTAL	0x01	/* use octal \ddd format */
+#define	VIS_CSTYLE	0x02	/* 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_WHITE	(VIS_SP | VIS_TAB | VIS_NL)
+#define	VIS_SAFE	0x20	/* only encode "unsafe" characters */
+#define	VIS_DQ		0x200	/* backslash-escape double quotes */
+#define	VIS_ALL		0x400	/* encode all characters */
+
+/*
+ * other
+ */
+#define	VIS_NOSLASH	0x40	/* inhibit printing '\' */
+#define	VIS_GLOB	0x100	/* encode glob(3) magics and '#' */
+
+/*
+ * unvis return codes
+ */
+#define	UNVIS_VALID	 1	/* character valid */
+#define	UNVIS_VALIDPUSH	 2	/* character valid, push back passed char */
+#define	UNVIS_NOCHAR	 3	/* valid sequence, no character produced */
+#define	UNVIS_SYNBAD	-1	/* unrecognized escape sequence */
+#define	UNVIS_ERROR	-2	/* decoder in unknown state (unrecoverable) */
+
+/*
+ * unvis flags
+ */
+#define	UNVIS_END	1	/* no more characters */
+
+#include <sys/cdefs.h>
+
+char	*vis(char *, int, int, int);
+int	strvis(char *, const char *, int);
+int	stravis(char **, const char *, int);
+int	strnvis(char *, const char *, size_t, int)
+		__attribute__ ((__bounded__(__string__,1,3)));
+int	strvisx(char *, const char *, size_t, int)
+		__attribute__ ((__bounded__(__string__,1,3)));
+int	strunvis(char *, const char *);
+int	unvis(char *, char, int *, int);
+ssize_t strnunvis(char *, const char *, size_t)
+		__attribute__ ((__bounded__(__string__,1,3)));
+
+#endif /* !_VIS_H_ */
blob - /dev/null
blob + 9ebdc7207f5acf508340c7b3737f3cf990c49b84 (mode 644)
--- /dev/null
+++ compat/vis.c
@@ -0,0 +1,272 @@
+/*	$OpenBSD: vis.c,v 1.26 2022/05/04 18:57:50 deraadt Exp $ */
+/*-
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <vis.h>
+
+static int
+isoctal(int c)
+{
+	u_char uc = c;
+
+	return uc >= '0' && uc <= '7';
+}
+
+static int
+isvisible(int c, int flag)
+{
+	int vis_sp = flag & VIS_SP;
+	int vis_tab = flag & VIS_TAB;
+	int vis_nl = flag & VIS_NL;
+	int vis_safe = flag & VIS_SAFE;
+	int vis_glob = flag & VIS_GLOB;
+	int vis_all = flag & VIS_ALL;
+	u_char uc = c;
+
+	if (c == '\\' || !vis_all) {
+		if ((u_int)c <= UCHAR_MAX && isascii(uc) &&
+		    ((c != '*' && c != '?' && c != '[' && c != '#') || !vis_glob) &&
+		    isgraph(uc))
+			return 1;
+		if (!vis_sp && c == ' ')
+			return 1;
+		if (!vis_tab && c == '\t')
+			return 1;
+		if (!vis_nl && c == '\n')
+			return 1;
+		if (vis_safe && (c == '\b' || c == '\007' || c == '\r' || isgraph(uc)))
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * vis - visually encode characters
+ */
+char *
+vis(char *dst, int c, int flag, int nextc)
+{
+	int vis_dq = flag & VIS_DQ;
+	int vis_noslash = flag & VIS_NOSLASH;
+	int vis_cstyle = flag & VIS_CSTYLE;
+	int vis_octal = flag & VIS_OCTAL;
+	int vis_glob = flag & VIS_GLOB;
+
+	if (isvisible(c, flag)) {
+		if ((c == '"' && vis_dq) ||
+		    (c == '\\' && !vis_noslash))
+			*dst++ = '\\';
+		*dst++ = c;
+		*dst = '\0';
+		return (dst);
+	}
+
+	if (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) == ' ') || vis_octal ||
+	    (vis_glob && (c == '*' || c == '?' || c == '[' || c == '#'))) {
+		*dst++ = '\\';
+		*dst++ = ((u_char)c >> 6 & 07) + '0';
+		*dst++ = ((u_char)c >> 3 & 07) + '0';
+		*dst++ = ((u_char)c & 07) + '0';
+		goto done;
+	}
+	if (!vis_noslash)
+		*dst++ = '\\';
+	if (c & 0200) {
+		c &= 0177;
+		*dst++ = 'M';
+	}
+	if (iscntrl((u_char)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
+ *	
+ *	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.
+ *	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
+strnvis(char *dst, const char *src, size_t siz, int flag)
+{
+	int vis_dq = flag & VIS_DQ;
+	int vis_noslash = flag & VIS_NOSLASH;
+	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, flag)) {
+			if ((c == '"' && vis_dq) ||
+			    (c == '\\' && !vis_noslash)) {
+				/* need space for the extra '\\' */
+				if (dst + 1 >= end) {
+					i = 2;
+					break;
+				}
+				*dst++ = '\\';
+			}
+			i = 1;
+			*dst++ = c;
+			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
+stravis(char **outp, const char *src, int flag)
+{
+	char *buf;
+	int len, serrno;
+
+	buf = reallocarray(NULL, 4, strlen(src) + 1);
+	if (buf == NULL)
+		return -1;
+	len = strvis(buf, src, flag);
+	serrno = errno;
+	*outp = realloc(buf, len + 1);
+	if (*outp == NULL) {
+		*outp = buf;
+		errno = serrno;
+	}
+	return (len);
+}
+
+int
+strvisx(char *dst, const char *src, size_t len, int flag)
+{
+	char 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);
+}
blob - 83332f998b3adf98066ee340ece5f5cb0088feb5
blob + 7ae1d5a7a1b485c7e396bb215c903e7b84c33c87
--- configure
+++ configure
@@ -120,6 +120,7 @@ echo "file config.log: writing..."
 
 NEED_GNU_SOURCE=0
 NEED_OPENBSD_SOURCE=0
+NEED_LIBBSD_OPENBSD_VIS=0
 
 COMPATS=
 COMP="${CC} ${CFLAGS} -Wno-unused -Werror"
@@ -190,6 +191,10 @@ runtest() {
 			fi
 			if [ "$4" = -D_OPENBSD_SOURCE ]; then
 				NEED_OPENBSD_SOURCE=1
+				return 0
+			fi
+			if [ "$4" = -DLIBBSD_OPENBSD_VIS ]; then
+				NEED_LIBBSD_OPENBSD_VIS=1
 				return 0
 			fi
 			if [ -n "$3" ]; then
@@ -284,6 +289,7 @@ runtest strlcpy		STRLCPY		|| true
 runtest strtonum	STRTONUM	-D_OPENBSD_SOURCE	|| true
 runtest tree_h		TREE_H		|| true
 runtest vasprintf	VASPRINTF	-D_GNU_SOURCE || true
+runtest vis		VIS		-DLIBBSD_OPENBSD_VIS	|| true
 
 deptest libevent2	LIBEVENT2	|| true
 
@@ -314,6 +320,10 @@ if [ ${HAVE_QUEUE_H} -eq 0 -o ${HAVE_IMSG} -eq 0 -o ${
 	CFLAGS="${CFLAGS} -I ${PWD}/compat"
 fi
 
+if [ ${HAVE_VIS} -eq 0 ]; then
+	CFLAGS="${CFLAGS} -I ${PWD}/compat/vis"
+fi
+
 if [ $HAVE_LIBEVENT2 -eq 1 ]; then
 	CFLAGS="$CFLAGS -DHAVE_LIBEVENT2=1"
 fi
@@ -324,6 +334,9 @@ fi
 if [ $NEED_OPENBSD_SOURCE = 1 ]; then
 	CFLAGS="$CFLAGS -D_OPENBSD_SOURCE"
 fi
+if [ $NEED_LIBBSD_OPENBSD_VIS = 1 ]; then
+	CFLAGS="$CFLAGS -DLIBBSD_OPENBSD_VIS"
+fi
 
 CFLAGS="${CFLAGS} ${CDIAGFLAGS}"
 
blob - ee214d5a44e1ad365a8d4c155fe1188d567e452a
blob + 9fd19e83b7c9097930bede923b3dfbdacafd9e04
--- have/Makefile
+++ have/Makefile
@@ -24,7 +24,8 @@ DISTFILES =	Makefile \
 		strlcpy.c \
 		strtonum.c \
 		tree_h.c \
-		vasprintf.c
+		vasprintf.c \
+		vis.c
 
 all:
 	false
blob - /dev/null
blob + 85a4307d23c00e101a1331ba094cfa8aaa167748 (mode 644)
--- /dev/null
+++ have/vis.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <vis.h>
+
+int
+main(void)
+{
+	char buf[128];
+
+	return strnvis(buf, "Hello, world!\n", sizeof(buf), 0);
+}