1996-01-28 00:53:44 +00:00
|
|
|
/*
|
|
|
|
* tee - send a copy of stdin to a file as well as stdout.
|
|
|
|
*
|
1996-09-03 03:56:08 +00:00
|
|
|
* Version 1.1 and later by Devin Reade <gdr@myrias.ab.ca>
|
1996-01-28 00:53:44 +00:00
|
|
|
*
|
|
|
|
* tee originally appeared with Gno v1.x, but was fully buffered.
|
1996-09-09 06:12:16 +00:00
|
|
|
* This is a complete re-write which by default uses full buffering
|
|
|
|
* for the output file, but _no_ buffering on stdin and stdout.
|
|
|
|
* This buffering behavior can be changed slightly by the -b flag.
|
1996-09-03 03:56:08 +00:00
|
|
|
*
|
1996-09-09 06:12:16 +00:00
|
|
|
* $Id: tee.c,v 1.3 1996/09/09 06:12:16 gdr Exp $
|
1996-01-28 00:53:44 +00:00
|
|
|
*/
|
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
#include <sys/types.h>
|
1996-01-28 00:53:44 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "getopt.h"
|
|
|
|
|
|
|
|
#ifdef CHECK_STACK
|
1996-09-03 03:56:08 +00:00
|
|
|
void begin_stack_check(void);
|
|
|
|
int end_stack_check(void);
|
|
|
|
|
|
|
|
#define STACKSTART begin_stack_check()
|
|
|
|
#define STACKEND(n) { \
|
|
|
|
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check()); \
|
|
|
|
return n; \
|
|
|
|
}
|
1996-01-28 00:53:44 +00:00
|
|
|
#else
|
1996-09-03 03:56:08 +00:00
|
|
|
#define STACKSTART
|
|
|
|
#define STACKEND(n) return n
|
1996-01-28 00:53:44 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define BUFFERSIZE 512
|
|
|
|
#define USAGE { \
|
1996-09-03 03:56:08 +00:00
|
|
|
fprintf(stderr,"%s %s\nUsage:\t%s %s\n",argv[0],versionstr,argv[0], \
|
|
|
|
usagestr); \
|
|
|
|
STACKEND(-1); \
|
1996-01-28 00:53:44 +00:00
|
|
|
}
|
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
char *versionstr = "version 1.2 by Devin Reade";
|
|
|
|
char *usagestr = "[ -abiV ] filename\n\
|
1996-01-28 00:53:44 +00:00
|
|
|
\t-a\tappend to filename\n\
|
|
|
|
\t-i\tignore SIGINT\n";
|
|
|
|
|
|
|
|
char buf2[BUFFERSIZE];
|
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int c, b_flag;
|
1996-09-09 06:12:16 +00:00
|
|
|
char *mode;
|
1996-09-03 03:56:08 +00:00
|
|
|
FILE *fp, *fp2;
|
1996-09-09 06:12:16 +00:00
|
|
|
int characters;
|
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
extern int optind;
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
/*
|
|
|
|
* initialization
|
|
|
|
*/
|
|
|
|
STACKSTART;
|
|
|
|
mode = "w+";
|
|
|
|
b_flag = 0;
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
/*
|
|
|
|
* parse the command line
|
|
|
|
*/
|
|
|
|
while ((c = getopt(argc, argv, "abiV")) != EOF) {
|
|
|
|
switch (c) {
|
|
|
|
case 'a':
|
|
|
|
/* append to instead of truncate output file */
|
|
|
|
mode = "a+";
|
|
|
|
break;
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
case 'b':
|
|
|
|
/* do line buffering */
|
|
|
|
b_flag++;
|
|
|
|
break;
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
case 'i':
|
|
|
|
/* ignore SIGINT */
|
|
|
|
signal(SIGINT, SIG_IGN);
|
|
|
|
break;
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
case 'V':
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
default:
|
|
|
|
USAGE;
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((argc - optind) < 1) {
|
|
|
|
USAGE;
|
|
|
|
}
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
/*
|
|
|
|
* open the output file
|
|
|
|
*/
|
|
|
|
if ((fp = fopen(argv[optind], mode)) == NULL) {
|
|
|
|
perror("opening master file");
|
|
|
|
STACKEND(1);
|
|
|
|
}
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
/*
|
|
|
|
* loop until done with the first file
|
|
|
|
*/
|
|
|
|
if (b_flag) {
|
|
|
|
/* line buffering */
|
1996-09-09 06:12:16 +00:00
|
|
|
setvbuf(stdin, NULL, _IOLBF, 1024);
|
|
|
|
setvbuf(stdout, NULL, _IOLBF, 1024);
|
|
|
|
characters = BUFFERSIZE;
|
1996-09-03 03:56:08 +00:00
|
|
|
} else {
|
|
|
|
/* no buffering */
|
1996-09-09 06:12:16 +00:00
|
|
|
setvbuf(stdin, NULL, _IONBF, 0);
|
|
|
|
setvbuf(stdout, NULL, _IONBF, 0);
|
|
|
|
characters = 2; /* a value of 2 gives one character reads */
|
1996-09-03 03:56:08 +00:00
|
|
|
}
|
|
|
|
|
1996-09-09 06:12:16 +00:00
|
|
|
/* poll until EOF seen on input or an error occurs */
|
|
|
|
while (fgets(buf2, characters, stdin) != NULL &&
|
|
|
|
fputs(buf2, stdout) != EOF &&
|
|
|
|
fputs(buf2, fp) != EOF);
|
|
|
|
fflush(fp);
|
|
|
|
fflush(stdout);
|
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
/*
|
|
|
|
* make additional copies if necessary
|
|
|
|
*/
|
|
|
|
optind++;
|
|
|
|
if (argc <= optind) {
|
|
|
|
fclose(fp);
|
|
|
|
STACKEND(0);
|
|
|
|
}
|
|
|
|
while (argc > optind) {
|
|
|
|
size_t count;
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
/* rewind the master file */
|
|
|
|
rewind(fp);
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
/* open the new file */
|
|
|
|
if ((fp2 = fopen(argv[optind], mode)) == NULL) {
|
|
|
|
perror("opening duplicate file");
|
|
|
|
fclose(fp);
|
|
|
|
STACKEND(1);
|
|
|
|
}
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
/* make the copy */
|
|
|
|
while (!feof(fp) && !(ferror(fp))) {
|
|
|
|
count = fread(buf2, sizeof(char), BUFFERSIZE, fp);
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
if (count > 0) {
|
1996-09-09 06:12:16 +00:00
|
|
|
fwrite(buf2, sizeof(char), count, fp2);
|
|
|
|
|
|
|
|
if (ferror(fp2)) {
|
|
|
|
perror("writing duplicate file");
|
|
|
|
fclose(fp);
|
|
|
|
fclose(fp2);
|
|
|
|
STACKEND(1);
|
|
|
|
}
|
1996-01-28 00:53:44 +00:00
|
|
|
}
|
1996-09-03 03:56:08 +00:00
|
|
|
}
|
1996-09-09 06:12:16 +00:00
|
|
|
|
1996-09-03 03:56:08 +00:00
|
|
|
fclose(fp2);
|
|
|
|
if (ferror(fp)) {
|
|
|
|
perror("reading master file");
|
|
|
|
fclose(fp);
|
|
|
|
STACKEND(1);
|
|
|
|
}
|
|
|
|
optind++;
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
STACKEND(0);
|
1996-01-28 00:53:44 +00:00
|
|
|
}
|