Commit 04250f6a7c3e2d22a9861b82615329e1dc328c93

Guillem Jover 2009-10-24T00:15:57

Add strnvis and strnunvis functions Taken from OpenBSD.

diff --git a/Versions b/Versions
index 271839d..3e99cf4 100644
--- a/Versions
+++ b/Versions
@@ -44,5 +44,8 @@ LIBBSD_0.1 {
 
 LIBBSD_0.2 {
     strtonum;
+
+    strnvis;
+    strnunvis;
 } LIBBSD_0.1;
 
diff --git a/include/vis.h b/include/vis.h
index 84de6fc..835d2d6 100644
--- a/include/vis.h
+++ b/include/vis.h
@@ -78,8 +78,10 @@ __BEGIN_DECLS
 char	*vis(char *, int, int, int);
 int	strvis(char *, const char *, int);
 int	strvisx(char *, const char *, size_t, int);
+int	strnvis(char *, const char *, size_t, int);
 int	strunvis(char *, const char *);
 int	strunvisx(char *, const char *, int);
+ssize_t strnunvis(char *, const char *, size_t);
 int	unvis(char *, int, int *, int);
 __END_DECLS
 
diff --git a/src/unvis.c b/src/unvis.c
index 66d74a5..188edca 100644
--- a/src/unvis.c
+++ b/src/unvis.c
@@ -257,6 +257,47 @@ strunvis(char *dst, const char *src)
 	return (dst - start);
 }
 
+ssize_t
+strnunvis(char *dst, const char *src, size_t sz)
+{
+	char c, p;
+	char *start = dst, *end = dst + sz - 1;
+	int state = 0;
+
+	if (sz > 0)
+		*end = '\0';
+	while ((c = *src++)) {
+	again:
+		switch (unvis(&p, c, &state, 0)) {
+		case UNVIS_VALID:
+			if (dst < end)
+				*dst = p;
+			dst++;
+			break;
+		case UNVIS_VALIDPUSH:
+			if (dst < end)
+				*dst = p;
+			dst++;
+			goto again;
+		case 0:
+		case UNVIS_NOCHAR:
+			break;
+		default:
+			if (dst <= end)
+				*dst = '\0';
+			return (-1);
+		}
+	}
+	if (unvis(&p, c, &state, UNVIS_END) == UNVIS_VALID) {
+		if (dst < end)
+			*dst = p;
+		dst++;
+	}
+	if (dst <= end)
+		*dst = '\0';
+	return (dst - start);
+}
+
 int
 strunvisx(char *dst, const char *src, int flag)
 {
diff --git a/src/vis.c b/src/vis.c
index 4ad31d5..189fde8 100644
--- a/src/vis.c
+++ b/src/vis.c
@@ -1,3 +1,4 @@
+/*	$OpenBSD: vis.c,v 1.18 2005/08/29 18:38:41 otto Exp $ */
 /*-
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,10 +31,20 @@
 #include <sys/types.h>
 #include <limits.h>
 #include <ctype.h>
-#include <stdio.h>
+#include <string.h>
 #include <vis.h>
 
 #define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define	isvisible(c)							\
+	(((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) &&		\
+	(((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') ||	\
+		(flag & VIS_GLOB) == 0) && isgraph((u_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((u_char)(c)))))
 
 /*
  * vis - visually encode characters
@@ -149,12 +160,15 @@ done:
 }
 
 /*
- * strvis, strvisx - visually encode characters from src into 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 NUL,
  *	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.
  */
@@ -174,6 +188,49 @@ strvis(dst, src, flag)
 }
 
 int
+strnvis(char *dst, const char *src, size_t siz, int flag)
+{
+	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);
+}
+
 strvisx(dst, src, len, flag)
 	char *dst;
 	const char *src;