Add cat -v.
diff --git a/lib/lib.h b/lib/lib.h
index 013e491..6a398c1 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -4,6 +4,9 @@
  * Copyright 2006 Rob Landley <rob@landley.net>
  */
 
+// libc generally has this, but the headers are screwed up
+ssize_t getline(char **lineptr, size_t *n, FILE *stream);
+
 // llist.c
 void llist_free(void *list, void (*freeit)(void *data));
 void *llist_pop(void *list);  // actually void **list, but the compiler's dumb
diff --git a/toys.h b/toys.h
index 67cc275..31ce206 100644
--- a/toys.h
+++ b/toys.h
@@ -45,4 +45,4 @@
 
 // One big temporary buffer, for use by applets (not library functions).
 
-char buf[4096];
+char toybuf[4096];
diff --git a/toys/Config.in b/toys/Config.in
index 59271dd..3828ab5 100644
--- a/toys/Config.in
+++ b/toys/Config.in
@@ -1,5 +1,18 @@
 menu "Toys"
 
+config CATV
+	bool "catv"
+	default n
+	help
+	  usage: catv [-evt] [filename...]
+
+	  Display nonprinting characters as escape sequences.  Use M-x for
+	  high ascii characters (>127), and ^x for other nonprinting chars.
+
+	  -e	Mark each newline with $
+	  -t	Show tabs as ^I
+	  -v	Don't use ^x or M-x escapes.
+
 config DF
 	bool "df (disk free)"
 	default n
diff --git a/toys/catv.c b/toys/catv.c
new file mode 100644
index 0000000..3a36de6
--- /dev/null
+++ b/toys/catv.c
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cat -v implementation for toybox
+ *
+ * Copyright (C) 2006 Rob Landley <rob@landley.net>
+ */
+
+/* See "Cat -v considered harmful" at
+ * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz */
+
+#include "toys.h"
+
+int catv_main(void)
+{
+	int retval = 0, fd;
+	char **argv = toys.optargs;
+
+	toys.optflags^=4;
+
+	// Loop through files.
+
+	do {
+		// Read from stdin if there's nothing else to do.
+
+		fd = 0;
+		if (*argv && 0>(fd = xopen(*argv, O_RDONLY, 0))) retval = EXIT_FAILURE;
+		else for(;;) {
+			int i, res;
+
+			res = reread(fd, toybuf, sizeof(toybuf));
+			if (res < 0) retval = EXIT_FAILURE;
+			if (res < 1) break;
+			for (i=0; i<res; i++) {
+				char c=toybuf[i];
+
+				if (c > 126 && (toys.optflags & 4)) {
+					if (c == 127) {
+						printf("^?");
+						continue;
+					} else {
+						printf("M-");
+						c -= 128;
+					}
+				}
+				if (c < 32) {
+					if (c == 10) {
+					   if (toys.optflags & 1) putchar('$');
+					} else if (toys.optflags & (c==9 ? 2 : 4)) {
+						printf("^%c", c+'@');
+						continue;
+					}
+				}
+				putchar(c);
+			}
+		}
+		if (CFG_TOYS_FREE && fd) close(fd);
+	} while (*++argv);
+
+	return retval;
+}
diff --git a/toys/toylist.h b/toys/toylist.h
index ef42749..6c5059f 100644
--- a/toys/toylist.h
+++ b/toys/toylist.h
@@ -53,6 +53,7 @@
 
 // The rest of these are alphabetical, for binary search.
 
+USE_CATV(NEWTOY(catv, "vte", TOYFLAG_NOFORK|TOYFLAG_USR|TOYFLAG_BIN))
 USE_TOYSH(NEWTOY(cd, NULL, TOYFLAG_NOFORK))
 USE_DF(NEWTOY(df, "Pkt*a", TOYFLAG_USR|TOYFLAG_SBIN))
 USE_TOYSH(NEWTOY(exit, NULL, TOYFLAG_NOFORK))