/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1987
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:writeinstall.c 12.0$ */
/* $ACIS:writeinstall.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/dist_atr/RCS/writeinstall.c,v $ */

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

/*
 * program to write out installation bitmap
 * so that zero blocks don't have to be written.
 * usage:
 * writeinstall input output
 */

#include <stdio.h>

#define BSIZE 512
#define BUFFSIZE (512*8)

int offset = 0;
int length = 4096 * BSIZE;

char bitmap[BSIZE];
int bitcnt;		/* byte index for bitcnt */
int input, output;
char outbuff[BUFFSIZE];
char *outptr = outbuff, *endptr = outbuff+BUFFSIZE;
char buff[BUFFSIZE];

int count, zerocount;
int vflg;
char *progname;

#define WRITE(fd, buff, len) if (write(fd, buff, len) != len) err("write error");

struct header {
char name[8];		/* BITMAP\0\0 */
int count;		/* number of bitmaps used */
int datacount;		/* number of data blocks written */
char filler[512 - 8 - 2 * sizeof (int)];
} header = { "BITMAP", 0 };
int zflg;


#ifdef __STDC__
void err(char *fmt, ...)
#else
err(fmt,d1,d2,d3)
char *fmt;
#endif __STDC__
{
	printf(fmt,((int *) &fmt)[1],((int *) &fmt)[2],((int *) &fmt)[3]);
	printf("\n");
	exit(1);
}

main(argc,argv)
char **argv;
{

	char *argp;
	int len;
	--argc; progname = *argv++;
	while (argc > 0 && *(argp = argv[0]) == '-')
		{
		++argv;
		--argc;
		switch(argp[1])
			{
		case 'v':
			++vflg;
			break;
		case 'o':
			offset = atoi(argp+2) * BSIZE;
			break;
		case 'l':
			length = atoi(argp+2) * BSIZE;
			break;
		case 'z':
			++zflg;
			break;
		default:
			usage();
			}
		}
	if (argc < (zflg ? 1 : 2))
		usage();
	if (zflg)
		{
		if ((output = creat(argv[0],0666)) < 0)
			err("can't open %s for output",argv[0]);
		writezeros();
		exit(0);
		}
	if ((input = open(argv[0],0)) < 0)
		err("can't open %s for input",argv[0]);
	if ((output = creat(argv[1],0666)) < 0)
		err("can't open %s for output",argv[1]);

	bitwrite();				/* write empty bit map! */
	
	/* we are now positioned to write the actual data */

	for (; length > 0; length -= len)
		{
		int map = 0;
		int l;
		int i;

		len = length > BUFFSIZE ? BUFFSIZE : length;
		
		if ((l = read(input, buff, len)) < 0)
			{
			done();
			err("read error on input");
			}

		if (l == 0)
			break;

		len = l;

		for (i=0; i< len/BSIZE; ++i)
			{
			if (iszero(buff + i * BSIZE, BSIZE))
				{
				if (vflg>1)
					printf("0");
				++zerocount;
				}
			else
				{
				if (vflg>1)
					printf("1");
				map |= 0x80 >> i;
				putbuff(buff + i * BSIZE);
				++count;
				}
			}
		bitmap[bitcnt++] = map;
		}
	done();
	if (vflg)
		printf("wrote %d non-zero blocks; %d zero blocks found\n",count,zerocount);
	exit(0);
}

usage()
{
	err("usage: %s -v -l{length} -o{offset} input output\nor\t%s -z -l{length} -o{offset} output\n",progname,progname);
}

putbuff(buff)
char *buff;
{
	bcopy(buff, outptr, BSIZE);
	outptr += BSIZE;

	if (outptr >= endptr)
		outflush();
}

outflush()
{
	int len = outptr-outbuff;
	if (len > 0)
		WRITE(output, outbuff, len);
	outptr = outbuff;
}

done()
{
	outflush();
	bitwrite();
}

bitwrite()
{
	header.count = bitcnt;		/* number of bit map entries */
	header.datacount = count;	/* number of data blocks written */
	lseek(output, offset, 0);
	WRITE(output, (char *) &header, sizeof header);
	lseek(output, offset+BSIZE, 0);
	WRITE(output, bitmap, sizeof bitmap);
}

iszero(buff,length)
char *buff;
{
	register int *p = (int *) buff;
	register int len = length/sizeof (int);

	for ( ; len > 0; --len)
		if (*p++)
			return(0);
	return(1);
}



writezeros()
{
	int len, l;

	lseek(output, offset, 0);
	for (;length > 0; length -= len)
		{
		len = length > BUFFSIZE ? BUFFSIZE : length;
		if ((l = write(output, buff, len)) != len)
			err("write error (write %d wrote %d)",len,l);
		}
}

