v03i077: hold -- terminate a pipe with its input
Bill Cox
bill at qst1.tcc.com
Mon Jul 4 07:04:10 AEST 1988
Posting-number: Volume 3, Issue 77
Submitted-by: "Bill Cox" <bill at qst1.tcc.com>
Archive-name: hold2
[Is my memory going? I don't remember seeing a first version of this. ++bsa]
Here's an unpdated version of hold.c, that lets you terminate a pipe with its
input file, effectively putting the output back into the input file, as in
tail SYSLOG | hold SYSLOG
This version contains some fixes noticed by readers at ncoast.
To build it, simply
cc -O -o hold hold.c
It's been compiled and run under V7, SYSV, XENIX and MS-DOS in its present
form.
Questions/bugs/flames to Bill Cox, (714)631-4452 (voice)
or uunet!ccicpg!qst1!bill
RATIONALE: Why use hold?
Let's say you have the file tmp, which contains:
AA#AAAA
BBBB#BB
And you wish to change the '#'s to '~'s. If you
simply say sed 's/#/~/' tmp, you see
AA~AAAA
BBBB~BB
just as you would expect.
Now, enter sed 's/#/~/' tmp > tmp (in effect asking the shell to
over-write the input file with the output) then cat tmp. Surprise,
tmp is a null file!
Now, enter sed 's/#/~/' tmp | hold tmp; cat tmp
AA~AAAA
BBBB~BB
Just as you expect. Because hold creates a temporary file FOR YOU,
which doesn't appear as an output on the command line.
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: hold.c
# Wrapped by srcs at qst1 on Mon Jul 4 17:21:31 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'hold.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'hold.c'\"
else
echo shar: Extracting \"'hold.c'\" \(2960 characters\)
sed "s/^X//" >'hold.c' <<'END_OF_FILE'
X/*
X * hold terminate a pipe, gather stdin into a temporary,
X * then rename the temporary to the argument's name.
X *
X * Example: ... | hold filename
X * or: ... | hold > filename
X *
X */
X
X#ifdef MSDOS
X#include <io.h>
X#endif
X
X#include <stdio.h>
X#include <errno.h>
X#ifndef MSDOS
X#include <signal.h>
X#endif
XFILE *fp = NULL;
Xint stdoutf;
X
X#ifdef MSDOS
Xchar fname[11] = "holdXXXXXX";
X#endif
X#ifdef M_XENIX
Xchar fname[11] = "holdXXXXXX";
X#else
Xchar fname[20] = "/usr/tmp/holdXXXXXX";
X#endif
X
X
Xextern int errno; /* Declare global error value. */
X
X#ifndef MSDOS
X/* This routine gains control when a signal is trapped. It unlinks the
X * temporary file. This is necessary when a pipe gets broken.
X */
Xint Trap()
X{
Xunlink(fname); /* Ignore errors at this point, we are dead anyway. */
Xexit(1);
X}
X#endif
X
Xint main(argc, argv)
X int argc;
X char *argv[];
X{
X int c;
X
X stdoutf = 0;
X if (argc > 1)
X stdoutf = 1;
X
X if (argc > 2) {
X fprintf(stderr, "Usage: ... | hold filename\n");
X fprintf(stderr, " or ... | hold > filename\n");
X return(1);
X }
X#ifndef MSDOS
X /* Trap signals to remove file on. */
X signal(SIGHUP, Trap);
X signal(SIGINT, Trap);
X signal(SIGQUIT, Trap);
X signal(SIGTERM, Trap);
X#endif
X if ((fp = fopen(mktemp(fname), "w")) == NULL)
X errclean(2, "open %s", fname, 0);
X
X while ((c = getchar()) != EOF)
X fputc(c, fp);
X
X if (ferror(stdin) || ferror(fp))
X errclean(3, "copy stdin to %s", 0, fname);
X
X if (fclose(fp) != 0)
X errclean(4, "close %s", fname, 0);
X
X if (stdoutf) {
X if (rename(fname, argv[1]) != 0)
X errclean(5, "rename %s to %s", fname, argv[1]);
X }
X else {
X if ((fp = fopen(fname, "r")) == NULL)
X errclean(6, "open %s", fname, 0);
X
X while ((c = getc(fp)) != EOF)
X fputc(c, stdout);
X
X if (ferror(stdout) || ferror(fp))
X errclean(7, "copy %s to stdout", 0, fname);
X
X if (fclose(fp) != 0)
X errclean(8, "close %s", fname, 0);
X
X if (unlink(fname) != 0)
X errclean(9, "remove %s", fname, 0);
X }
X
X return(0);
X}
X
X
X#ifndef MSDOS
Xint rename(s1, s2) /* s2 = new name, s1 = existing name */
X char *s1, *s2;
X{
X /* assure that new name doesn't exist */
X if (unlink(s2) != 0 && errno != ENOENT) {
X errclean(10, "remove %s", s2, 0);
X return(1);
X }
X /* connect new name to existing file */
X if (link(s1, s2) != 0) {
X errclean(11, "link %s to %s", s1, s2);
X return(1);
X }
X /* remove old name for the file */
X if (unlink(s1) != 0) {
X errclean(12, "remove %s", s1, 0);
X return(1);
X }
X return(0);
X}
X#endif
X
X/*
X * errclean - output error message and exit to system
X */
Xerrclean(code, string, arg1, arg2)
X int code;
X char *string;
X char *arg1, *arg2;
X{
X char lstr[80];
X
X if (fp != NULL) {
X (void)unlink(fname);
X fp = NULL;
X }
X sprintf(lstr, "hold %2d: can't %s\n", code, string);
X fprintf(stderr, lstr, arg1, arg2);
X exit(code);
X}
X
END_OF_FILE
if test 2960 -ne `wc -c <'hold.c'`; then
echo shar: \"'hold.c'\" unpacked with wrong size!
fi
# end of 'hold.c'
fi
echo shar: End of shell archive.
exit 0
More information about the Comp.sources.misc
mailing list