This occasionally comes in handy, so I'll add it to utils.
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 13 May 2005 17:44:45 +0000 (17:44 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 13 May 2005 17:44:45 +0000 (17:44 +0000)
git-svn-id: svn://svn.tartarus.org/sgt/utils@5776 cda61777-01e9-0310-a592-d414129be87e

reservoir/Makefile [new file with mode: 0644]
reservoir/reservoir [new file with mode: 0755]
reservoir/reservoir.but [new file with mode: 0644]

diff --git a/reservoir/Makefile b/reservoir/Makefile
new file mode 100644 (file)
index 0000000..b53b8f5
--- /dev/null
@@ -0,0 +1,41 @@
+# for `make release' and `make html'
+DESTDIR = .
+
+# for `make install'
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+SCRIPTDIR = $(PREFIX)/bin
+MANDIR = $(PREFIX)/man/man1
+INSTALL = install
+IPROG =#   flags for installing programs (default none)
+IDATA = -m 0644  # flags for installing data
+
+all: reservoir.1
+man: reservoir.1
+progs:;
+
+%.1: %.but
+       halibut --man=$@ $<
+
+clean:
+       rm -f *.1 *.html *.tar.gz
+
+html:
+       halibut --html=$(DESTDIR)/reservoir.html reservoir.but
+
+release: reservoir.1
+       mkdir -p reltmp/reservoir
+       ln -s ../../reservoir reltmp/reservoir
+       ln -s ../../reservoir.1 reltmp/reservoir
+       ln -s ../../reservoir.but reltmp/reservoir
+       ln -s ../../Makefile reltmp/reservoir
+       tar -C reltmp -chzf $(DESTDIR)/reservoir.tar.gz reservoir
+       rm -rf reltmp
+
+install: install-progs install-man
+install-progs:
+       mkdir -p $(SCRIPTDIR)
+       $(INSTALL) $(IPROG) reservoir $(SCRIPTDIR)/reservoir
+install-man: reservoir.1
+       mkdir -p $(MANDIR)
+       $(INSTALL) $(IDATA) reservoir.1 $(MANDIR)/reservoir.1
diff --git a/reservoir/reservoir b/reservoir/reservoir
new file mode 100755 (executable)
index 0000000..fe01ba1
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env perl
+
+# reservoir -- read stdin until EOF, and _then_ write it all to stdout.
+
+$usage =
+  "usage: reservoir [ -o file ]\n".
+  "where: -o file                open and write to file after end of input\n".
+  " also: reservoir --version    report version number\n" .
+  "       reservoir --help       display this help text\n" .
+  "       reservoir --licence    display (MIT) licence text\n";
+
+$licence =
+  "reservoir is copyright 2005 Simon Tatham.\n" .
+  "\n" .
+  "Permission is hereby granted, free of charge, to any person\n" .
+  "obtaining a copy of this software and associated documentation files\n" .
+  "(the \"Software\"), to deal in the Software without restriction,\n" .
+  "including without limitation the rights to use, copy, modify, merge,\n" .
+  "publish, distribute, sublicense, and/or sell copies of the Software,\n" .
+  "and to permit persons to whom the Software is furnished to do so,\n" .
+  "subject to the following conditions:\n" .
+  "\n" .
+  "The above copyright notice and this permission notice shall be\n" .
+  "included in all copies or substantial portions of the Software.\n" .
+  "\n" .
+  "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n" .
+  "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n" .
+  "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n" .
+  "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n" .
+  "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n" .
+  "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n" .
+  "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n" .
+  "SOFTWARE.\n";
+
+$outputfile = undef;
+
+while ($_=shift @ARGV) {
+  last if /^--$/;
+  unshift (@ARGV, $_), last unless /^-(.*)/;
+  $arg = $1;
+  if ($arg eq "-help") {
+    print STDERR $usage;
+    exit 0;
+  } elsif ($arg eq "-version") {
+    if ('$Revision: 4876 $' =~ /Revision:\s+(\d+)/) {
+       print "reservoir revision $1\n";
+    } else {
+       print "reservoir: unknown revision\n";
+    }
+    exit 0;
+  } elsif ($arg eq "-licence" or $arg eq "-license") {
+    print $licence;
+    exit 0;
+  } elsif ($arg =~ /^o(.*)$/) {
+    $outputfile = $1;
+    $outputfile = shift @ARGV if $outputfile eq "";
+    die "reservoir: expected file name after '-o'\n" if $outputfile eq "";
+  } else {
+    die "reservoir: unrecognised option '-$arg'\n";
+  }
+}
+
+die $usage if $#ARGV > 0;
+
+$data = '';
+
+$data .= $_ while <STDIN>;
+
+if (defined $outputfile) {
+    open OUT, ">$outputfile" or die "$outputfile: open: $!\n";
+    select OUT;
+}
+print $data;
diff --git a/reservoir/reservoir.but b/reservoir/reservoir.but
new file mode 100644 (file)
index 0000000..425983a
--- /dev/null
@@ -0,0 +1,102 @@
+\cfg{man-identity}{reservoir}{1}{2005-05-13}{Simon Tatham}{Simon Tatham}
+
+\title Man page for \cw{reservoir}
+
+\U NAME
+
+\cw{reservoir} - delay stage in a pipeline
+
+\U SYNOPSIS
+
+\c reservoir [ -o filename ]
+\e bbbbbbbbb   bb iiiiiiii
+
+\U DESCRIPTION
+
+\cw{reservoir}'s function is to read from its standard input until
+it sees end-of-file, then to write everything it has seen to its
+standard output.
+
+It behaves exactly like \cw{cat} with no arguments, except that it
+writes none of its outgoing data until all of its input has arrived.
+
+\U OPTIONS
+
+\dt \cw{-o} \e{filename}
+
+\dd Causes the output to be written to \e{filename} rather than to
+standard output. \e{filename} is not opened until after
+\cw{reservoir} detects end of file on its input.
+
+\U EXAMPLES
+
+If you have a program which filters its input in some way (for
+example, a base-64 decoder, or a \cw{tr}(1) command performing
+rot13), and you wish to copy a small amount of data into that
+program using a terminal emulator's paste function, it can be
+inconvenient to have the output interspersed with the echoed input
+so that you cannot select and copy the output as a whole.
+
+For example:
+
+\c $ tr a-zA-Z n-za-mN-ZA-M
+\e   bbbbbbbbbbbbbbbbbbbbbb
+\c Hello, world.
+\e bbbbbbbbbbbbb
+\c Uryyb, jbeyq.
+\c This is a test.
+\e bbbbbbbbbbbbbbb
+\c Guvf vf n grfg.
+
+If your terminal emulator pastes the text line by line, then to copy
+the transformed output requires you to separately select each line
+of the output. If the terminal pastes in larger chunks, you may not
+see the problem quite so quickly, but it will still appear
+eventually.
+
+You can solve this using \cw{reservoir}:
+
+\c $ tr a-zA-Z n-za-mN-ZA-M | reservoir
+\e   bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+\c Hello, world.
+\e bbbbbbbbbbbbb
+\c This is a test.
+\e bbbbbbbbbbbbbbb
+\c (now the user presses ^D)
+\e iiiiiiiiiiiiiiiiiiiiiiiii
+\c Uryyb, jbeyq.
+\c Guvf vf n grfg.
+
+A common reason why you might want to buffer data in a pipeline is
+in order to transform a file in place. For example, you cannot write
+
+\c $ tr a-zA-Z n-za-mN-ZA-M < temp.txt > temp.txt
+
+because the output redirection will destroy the contents of the file
+before its original contents can be read. \cw{reservoir} can help,
+because it does not begin writing output until after the input has
+all been read.
+
+You still cannot use output redirection, because the presence of the
+\cw{>} operator on your command line will cause the output file to
+be truncated to zero length \e{before} running \cw{reservoir}, so
+there is nothing \cw{reservoir} can do about this. Instead, you can
+use the \cw{-o} option provided by \cw{reservoir}:
+
+\c $ tr a-zA-Z n-za-mN-ZA-M < temp.txt | reservoir -o temp.txt
+
+Now \cw{reservoir} will not open \cw{temp.txt} for output until
+\e{after} the rest of the pipeline has finished reading data from it.
+
+(This is not a reliable means of editing files in place. If
+something goes wrong half way through writing the output, part of
+your data will be lost. Also, the file is not replaced atomically.
+This method is very convenient in non-critical situations, but is
+not recommended for critical or automated use.)
+
+\U LICENCE
+
+\cw{reservoir} is free software, distributed under the MIT licence. Type
+\cw{reservoir --licence} to see the full licence text.
+
+\versionid $Id$