# HG changeset patch # User Rob Landley # Date 1215130740 18000 # Node ID 52600eee8dd6554605cbbdfe5ed033a4402b947e # Parent 937148640ac512d0d794a1aa847511b8bef3d981 Add "tee" command. diff -r 937148640ac5 -r 52600eee8dd6 lib/lib.c --- 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) diff -r 937148640ac5 -r 52600eee8dd6 lib/lib.h --- 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); diff -r 937148640ac5 -r 52600eee8dd6 toys/tee.c --- /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 + * + * 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; + } + } + +}