bill@qst1.tcc.com (Bill Cox) (07/04/88)
Posting-number: Volume 3, Issue 77 Submitted-by: "Bill Cox" <bill@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@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