#include <stdio.h>
#include <string.h>
#include <unistd.h>

/*
 * quick hacked up code to debug HP-2100 tape images
 *
 * Copy ABS tape image from stdin to stdout
 * progress on stderr
 *
 * 2008.02.20 by Tim Riker <Tim@Rikers.org>
 */

/* to get timed slow writes use */
/* #define PACED_WRITES */
/* leading nuls to make emulators happy */
#define START_NULS 5
/* should not need any nulls between blocks */
#define MID_NULS 0
/* should only need 10 on the end, but lets do more */
#define END_NULS 20

#define MEM_SIZE 65536
#define BITMAP_SIZE (MEM_SIZE >> 3)
unsigned char bitmap[BITMAP_SIZE];
unsigned char bits[8] = {1,2,4,8,16,32,64,128};

int main(int argc, char *argv[]) {
	unsigned int c;
	int bytecount=0;
	int blocknum=0;
	int skipcount;
	int readcount;
	int size;
	int writecount,i;
	/* max char val + header bytes + footer bytes + nuls */
	unsigned char buffer[256+6+MID_NULS];
	short unsigned int csum;
	memset(bitmap,'\0',BITMAP_SIZE);
	memset(buffer,'\0',START_NULS);
	fwrite(buffer, 1, START_NULS, stdout);
	while (1) {
		unsigned short address;
		skipcount = 0;
		c = fgetc(stdin);
		if (c > 255) {
			return(-1);
		}
		while (c == '\0') {
			skipcount++;
			c = fgetc(stdin);
			if (c > 255) {
				int firstone = 0;
				int lastone = 0;
				memset(buffer,'\0',END_NULS);
				fwrite(buffer, 1, END_NULS, stdout);
				bytecount += skipcount;
				fprintf(stderr,"read %u, skip %u\n", bytecount, skipcount);
				fprintf(stderr,"Map:");
				for (i=0;i<MEM_SIZE;i++) {
					if (bitmap[i >> 3] & bits[i & 7]) {
						if (!lastone || lastone != i-1) {
							/* first one */
							fprintf(stderr," %05o", i);
							firstone=i;
						}
						lastone=i;
					} else {
						if (lastone && lastone == i-1) {
							if (firstone != lastone) {
								// last bit was set
								fprintf(stderr,"-%05o", i - 1);
							}
						}
					}
				}
				fprintf(stderr,"\n");
				return(0);
			}
		}
		bytecount += skipcount;
		/* <len><feed frame><addr_h><addr_l><"len" words><csum_h><csum_l><some amount of nuls> */
		size=c * 2 + 6;
		buffer[0]=c;
		if (fread(&buffer[1],1,size - 1,stdin) != size - 1) {
			return(-1);
		}
		csum=buffer[2]<<8|buffer[3];
		for (i=0;i<c;i++) {
			csum += buffer[i*2+4]<<8|buffer[i*2+5];
		}
		memset(&buffer[size],'\0',MID_NULS);
		bytecount+=size;
		address=buffer[2] << 8 | buffer[3];
		fprintf(stderr, "read %ub skip %ub, has %uw (%ub) addr %05o-%05o sum:%04x,%04x blk %u\n",
				bytecount, skipcount, c, size, address,
				(buffer[2] << 8 | buffer[3]) + c - 1,
				csum, buffer[c*2+4]<<8|buffer[c*2+5], blocknum);
		if (csum != (buffer[c*2+4]<<8|buffer[c*2+5])) {
			fprintf(stderr,"Error: bad checksum!\n");
			return(0);
		}
		for (i=0;i<c;i++) {
			/* track even bytes after <len><feedframe><addr_h><addr_l> and before <csum_h><csum_l> */
			if (bitmap[(address + i) >> 3] & bits[(address + i) & 7])
				fprintf(stderr,"wrote to %05o more than once (%05o,%1o,%02x)\n",
						address + i, (address + i) >> 3, (address + i) & 7, bitmap[(address + i) >> 3]);
			bitmap[(address + i) >> 3] |= bits[(address + i) & 7];
		}
#ifdef PACED_WRITES
		/* slow loop to account for broken ctsrts lines */
		for (i=0;i<size+MID_NULS;i++) {
			fputc(buffer[i],stdout);
			fflush(stdout);
			usleep(10000); /* works */
			/* usleep(1000);  too fast*/
		}
#else
		if (fwrite(buffer, 1, size+MID_NULS, stdout) != size + MID_NULS) {
			return(-1);
		}
		fflush(stdout);
#endif
		blocknum++;
	}
}
