From 2bfaaf25614985ada5490d08e005b36f948d8186 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 3 Jul 2008 19:19:00 -0500 Subject: Add "tee" command. --- lib/lib.c | 24 ++++++++++++++------ lib/lib.h | 1 + toys/tee.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 toys/tee.c 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 + * + * 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; + } + } + +} -- cgit v1.2.3