/* $Header:ftc.c 12.0$ */
/* $ACIS:ftc.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/RCS/ftc.c,v $ */

#ifndef lint
static char *rcsid = "$Header:ftc.c 12.0$";
#endif

/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
#include <stdio.h>
#include <sys/file.h>
#include <ctype.h>

/*
 * program to do tape copying with overlapped I/O synchronized
 * via pipes.
 * basic idea is to have two buffers in use and to be reading into
 * one while writing the other.
 */

int pipes1[2], pipes2[2];
#define READ 0
#define WRITE 1
int indes, outdes;
char *buffer;
int bufsize = 32 * 1024;
int pid;
char *progname;
int debug;
char *malloc();
int sflg;		/* print statistics */
int Bflg;		/* buffer entire blocksize */
int cflg = 0;
int read_count;
int read_length;

main(argc,argv) char **argv;
{
	register int i, j;

	progname = argv[0];
	while (argc > 1 && *argv[1] == '-' && argv[1][1])
		{
		++argv;
		--argc;
		switch(argv[0][1])
			{
		case 'B':		/* buffer entire blocks (for pipes) */
			++Bflg;
			break;
		case 's':		/* print statistics */
			++sflg;
			break;
		case 'd':		/* debug output */
			++debug;
			break;
		case 'c':
			cflg=O_CREAT;
			break;
		default:		/* specify buffer size in K */
			if (isdigit(argv[0][1]))
				bufsize = atoi(argv[0]+1) * 1024;
			}
		}
	if (argc < 3)
		err("usage: %s [-B] [-s] [-d] [-c] [-{buffsize}] indevice outdevice",progname);
	if ((buffer = malloc(bufsize)) == (char *) 0)
		err("cannot allocate buffer (%d bytes)",bufsize);
	if ((indes = myopen(argv[1],0)) < 0)
		err("open %s for input",argv[1]);
	if ((outdes = myopen(argv[2],O_WRONLY|O_TRUNC|cflg,0666)) < 0)
		err("open %s for output",argv[2]);
	if ((i = fork()) == 0)
		docopy(indes,outdes);	/* do the copy in child */
	else
		while ((j = wait((int *) 0)) != i && j != -1)
			;
	exit(0);
}

docopy(indes,outdes)
{

	pipe(pipes1);
	pipe(pipes2);

	put(pipes1[WRITE],'r');		/* prime it */
	put(pipes1[WRITE],'w');
	if ((pid = fork()) == 0)
		{
		close(pipes1[WRITE]);
		close(pipes2[READ]);
		do_io(pipes1[READ],pipes2[WRITE],indes,outdes);
		}
	else
		{
		close(pipes2[WRITE]);
		close(pipes1[READ]);
		do_io(pipes2[READ],pipes1[WRITE],indes,outdes);
		}

}

/*
 * wait for input byte on read pipe (which says that it is our turn to
 * read a block), then read a record. Then issue read permission to the
 * other process. Then read for write permission
 * byte on pipe and after done writing issue a write permission byte.
 */
do_io(readp,writep,indes,outdes)
{

	register int l;
	register int i;
	for (;;)
		{
		bzero(buffer, bufsize);		/* zero buffer */
		get(readp,'r');
		l = read(indes, buffer, bufsize);
		if (l == 0)
			{
			prstats();
			exit(0);
			}
		if (Bflg && l > 0 && l < bufsize)
			if ((i = readrest(indes, buffer+l, bufsize-l)) > 0)
				l += i;
		if (l < 0)
			i = getlength(buffer,bufsize);
		else
			i = l;
		put(writep,'r');
		get(readp,'w');
		++read_count;
		read_length += i;
		if (i > 0)
			if (write(outdes, buffer, i) != i)
				err("write");
		put(writep,'w');
		if (l < 0)
			{
			prstats();
			err("read");
			}
		}
}

get(fdes,flag)
{
	char c;

	if (read(fdes,&c,1) <= 0)
		err("eof on pipe");
	if (c != flag)
		err("expected %c got %c",flag,c);
}

put(fdes,flag)
char flag;
{
	write(fdes,&flag,1);
	if (pid)
		flag -= 'a'-'A';	/* parent */
	if (debug)
		write(1,&flag,1);
}
#include <stdio.h>

err(s,d1,d2,d3,d4)
char *s;
{
warn(s,d1,d2,d3,d4);
prstats();
exit(1);
}

warn(s,d1,d2,d3,d4)
char *s;
{
extern errno;

fflush(stdout);
fprintf(stderr,s,d1,d2,d3,d4);
if(errno > 0)
	{
	fprintf(stderr," - ");
	perror("");
	}
else
	fprintf(stderr,"\n");
}

myopen(file,how,mode)
register char *file;
int mode;
{
if (strcmp(file,"-") == 0)
	return(dup(how == 0 ? 0 : 1));
return(open(file,how,mode));
}

getlength(buffer,size)
register char *buffer;
register int size;
{
	register int *b = (int *) (buffer+size);

	while (*--b == 0 && (size -= sizeof (int)) > 0)
		;
	
	size = (size + 512 - 1) & ~(512-1);	/* round up to next block size */
	return(size);
}

prstats()
{
	if (sflg && (read_count || read_length))
		fprintf(stderr,"%s: %d records; %d bytes total\n",pid ? "parent" : "child ", read_count,read_length);
}

/*
 * read until either eof/error or we have read length bytes.
 */
readrest(fd, buff, length)
char *buff;
{
	int len = 0;
	int l;
	while (length > 0)
		{
		if ((l = read(fd, buff, length)) <= 0)
			break;
		length -= l;
		len += l;
		buff += l;
		}
	return(len > 0 ? len : l);
}
