/* lbn2rx50.c */

/* convert sequential block image files to rx50 sector files */

/* rx50 sector order:        */
/* lbn 0 == track 1 sector 0 */
/* lbn 1 == track 1 sector 2 */
/*     2          1        4 */
/* ...                       */
/* lbn 5 == track 1 sector 1 */
/* lbn 6 == track 1 sector 3 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#define LBN_ORDER        0
#define RX50_ORDER       1
#define RX50_TRACKS      80
#define RX50_SECTORS     10
#define RX50_NUM_BLOCKS  800
#define RX50_SECTOR_SIZE 512

char image[RX50_SECTOR_SIZE*RX50_NUM_BLOCKS];

int interleave[] = { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 };

void usage(void)
{
	fprintf(stderr, "usage: lbn -b|-s input output\n");
}

void error(char *s)
{
	fprintf(stderr, "ERROR: %s\n", s);
	usage();
	exit(-1);
}

/* take the logical block number and convert to sector order */

int lbn2rx50(int lbn)
{
	int track;
	int sector;

	track = lbn/RX50_SECTORS;
	track = (track + 1)%RX50_TRACKS;


	sector = lbn%RX50_SECTORS;
	sector = (interleave[sector] + 2*(track - 1) + RX50_SECTORS)%RX50_SECTORS;

	return track*RX50_SECTORS + sector;
}

void transfer(int order, int fdin, int fdout)
{
	int src_lbn;
	int dst_lbn;
	int count;
	
	if (order == RX50_ORDER) {
		for (src_lbn = 0; src_lbn < RX50_NUM_BLOCKS; src_lbn++) {
			dst_lbn = lbn2rx50(src_lbn);
			count = read(fdin, &image[dst_lbn*RX50_SECTOR_SIZE], RX50_SECTOR_SIZE);
			if (count != RX50_SECTOR_SIZE)
				error("could not read input");
		}

		for (dst_lbn = 0; dst_lbn < RX50_NUM_BLOCKS; dst_lbn++) {
			count = write(fdout, &image[dst_lbn*RX50_SECTOR_SIZE], RX50_SECTOR_SIZE);
			if (count != RX50_SECTOR_SIZE)
				error("could not write output");
		}	
	} else {
		for (src_lbn = 0; src_lbn < RX50_NUM_BLOCKS; src_lbn++) { 
			count = read(fdin, &image[src_lbn*RX50_SECTOR_SIZE], RX50_SECTOR_SIZE);
			if (count != RX50_SECTOR_SIZE)
				error("could not read input");
		} 

		for (src_lbn = 0; src_lbn < RX50_NUM_BLOCKS; src_lbn++) {
			dst_lbn = lbn2rx50(src_lbn);
			count = write(fdout, &image[dst_lbn*RX50_SECTOR_SIZE], RX50_SECTOR_SIZE);
			if (count != RX50_SECTOR_SIZE)
				error("could not write output");
		}	 

	}
}


int main(int argc, char * const argv[])
{
	int order = -1;
	int c;
	int fdin, fdout;

	while (1) {
		c = getopt(argc, argv, "bs");
fprintf(stderr, "got option character %d\n", c);

		if (c == -1)
			break;

		switch (c) {

		case 'b':
			if (order == RX50_ORDER)
				error("-b or -s but not both");
			order = LBN_ORDER;
			break;

		case 's':
			if (order == LBN_ORDER)
				error("-b or -s but not both");
			order = RX50_ORDER;
			break;

		case '?':

		default:
			error("bad option");
			break;
		}
	}

	if (order == -1)
		error("must use -b or -s");

	fdin = 0;	/* stdin */
	fdout = 1;	/* stdout */

	if (optind < argc) {
fprintf(stderr, "input file name: %s\n", argv[optind]);
		if (!(fdin = open(argv[optind], O_RDONLY)))
			error("could not open input file");
		optind += 1;
	}
	if (optind < argc) {
fprintf(stderr, "output file name: %s\n", argv[optind]);
		if (!(fdout = open(argv[optind], O_WRONLY | O_CREAT | O_TRUNC, 0664)))
			error("could not open output file");
	}

	transfer(order, fdin, fdout);
}


