changeset 308:52600eee8dd6

Add "tee" command.
author Rob Landley <rob@landley.net>
date Thu, 03 Jul 2008 19:19:00 -0500
parents 937148640ac5
children 79a61cd58596
files lib/lib.c lib/lib.h toys/tee.c
diffstat 3 files changed, 92 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/lib/lib.c	Thu Jul 03 19:16:38 2008 -0500
+++ b/lib/lib.c	Thu Jul 03 19:19:00 2008 -0500
@@ -593,30 +593,40 @@
 	close(fd);
 }
 
-// Iterate through an array of files, opening each one (read only) and
-// calling a function on that filehandle and name.  The special filename
-// "-" means stdin.  An empty argument list calls function() on stdin.
-void loopfiles(char **argv, void (*function)(int fd, char *name))
+// Iterate through an array of files, opening each one and calling a function
+// on that filehandle and name.  The special filename "-" means stdin if
+// flags is O_RDONLY, stdout otherwise.  An empty argument list calls
+// function() on just stdin/stdout.
+//
+// Note: read only filehandles are automatically closed when function()
+// returns, but writeable filehandles must be close by function()
+void loopfiles_rw(char **argv, int flags, void (*function)(int fd, char *name))
 {
 	int fd;
 
 	// If no arguments, read from stdin.
-	if (!*argv) function(0, "-");
+	if (!*argv) function(flags ? 1 : 0, "-");
 	else do {
 		// Filename "-" means read from stdin.
 		// Inability to open a file prints a warning, but doesn't exit.
 
 		if (!strcmp(*argv,"-")) fd=0;
-		else if (0>(fd = open(*argv, O_RDONLY))) {
+		else if (0>(fd = open(*argv, flags, 0666))) {
 			perror_msg("%s", *argv);
 			toys.exitval = 1;
 			continue;
 		}
 		function(fd, *argv);
-		close(fd);
+		if (!flags) close(fd);
 	} while (*++argv);
 }
 
+// Call loopfiles_rw with O_RDONLY (common case).
+void loopfiles(char **argv, void (*function)(int fd, char *name))
+{
+	loopfiles_rw(argv, O_RDONLY, function);
+}
+
 // Slow, but small.
 
 char *get_rawline(int fd, long *plen, char end)
--- a/lib/lib.h	Thu Jul 03 19:16:38 2008 -0500
+++ b/lib/lib.h	Thu Jul 03 19:19:00 2008 -0500
@@ -86,6 +86,7 @@
 long atolx(char *c);
 off_t fdlength(int fd);
 char *xreadlink(char *name);
+void loopfiles_rw(char **argv, int flags, void (*function)(int fd, char *name));
 void loopfiles(char **argv, void (*function)(int fd, char *name));
 char *get_rawline(int fd, long *plen, char end);
 char *get_line(int fd);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/tee.c	Thu Jul 03 19:19:00 2008 -0500
@@ -0,0 +1,74 @@
+/* vi: set sw=4 ts=4:
+ *
+ * tee.c - cat to multiple outputs.
+ *
+ * Copyright 2008 Rob Landley <rob@landley.net>
+ *
+ * See http://www.opengroup.org/onlinepubs/009695399/utilities/tee.html
+
+USE_TEE(NEWTOY(tee, "ia", TOYFLAG_BIN))
+
+config TEE
+    bool "tee"
+    default y
+    help
+      usage: tee [-ai] [file...]
+
+      Copy stdin to each listed file, and also to stdout.
+      Filename "-" is a synonym for stdout.
+
+      -a	append to files.
+      -i	ignore SIGINT.
+*/
+
+#include "toys.h"
+
+DEFINE_GLOBALS(
+    void *outputs;
+)
+
+#define TT this.tee
+
+struct fd_list {
+    struct fd_list *next;
+    int fd;
+};
+
+// Open each output file, saving filehandles to a linked list.
+
+static void do_tee_open(int fd, char *name)
+{
+    struct fd_list *temp;
+
+    temp = xmalloc(sizeof(struct fd_list));
+    temp->next = TT.outputs;
+    temp->fd = fd;
+    TT.outputs = temp;
+}
+
+void tee_main(void)
+{
+    if (toys.optflags&2) signal(SIGINT, SIG_IGN);
+
+    // Open output files
+    loopfiles_rw(toys.optargs,
+        O_RDWR|O_CREAT|((toys.optflags&1)?O_APPEND:O_TRUNC), do_tee_open);
+
+    for (;;) {
+        struct fd_list *fdl;
+        int len;
+
+        // Read data from stdin
+        len = xread(0, toybuf, sizeof(toybuf));
+        if (len<1) break;
+
+        // Write data to each output file, plus stdout.
+        fdl = TT.outputs;
+        for (;;) {
+            if(len != writeall(fdl ? fdl->fd : 1, toybuf, len)) toys.exitval=1;
+            if (!fdl) break;
+            fdl = fdl->next;
+        }
+    }
+
+}