aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2008-07-03 19:19:00 -0500
committerRob Landley <rob@landley.net>2008-07-03 19:19:00 -0500
commit2bfaaf25614985ada5490d08e005b36f948d8186 (patch)
tree50deab565a6c7da8638278c6f13e01e85881ddcd
parentdf92ef5e8e6cf62358b37f441952b7b5f310b20c (diff)
downloadtoybox-2bfaaf25614985ada5490d08e005b36f948d8186.tar.gz
Add "tee" command.
-rw-r--r--lib/lib.c24
-rw-r--r--lib/lib.h1
-rw-r--r--toys/tee.c74
3 files changed, 92 insertions, 7 deletions
diff --git a/lib/lib.c b/lib/lib.c
index 1aca9c8c..8467f866 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -593,30 +593,40 @@ void xpidfile(char *name)
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)
diff --git a/lib/lib.h b/lib/lib.h
index f8f52e66..db283cf3 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -86,6 +86,7 @@ char *itoa(int n);
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);
diff --git a/toys/tee.c b/toys/tee.c
new file mode 100644
index 00000000..8c8f3d5c
--- /dev/null
+++ b/toys/tee.c
@@ -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;
+ }
+ }
+
+}