/*
 *	Convert between files containing different-sized samples.
 *
 *	File format seems to be a 128-byte header followed by 8-bit samples
 *	where the origin is at 128.
 *
 *	Martin Guy, Canterbury, February 1990.
 */
#include <stdio.h>

#define HDRSIZE 128

usage()
{
	fputs("Usage: convert [-h] [-f]\n", stderr);
	fputs("-h\tRemove 128-byte header of .avl file\n", stderr);
	fputs("-h<n>\tRemove <n>-byte header from input file (default=128)\n", stderr);
	fputs("-[io][csf]\tInput/Output chars/shorts/floats (default = shorts)\n", stderr);
	exit(1);
}

/* I/O format stuff */
#define UCHAR	0	/* unsigned char, origin = 128 */
#define	SHORT	1	/* 16-bit signed integer */
#define FLOAT	2	/* 32-bit floating point */
/* input and output formats - default = 16-bit shorts */
static int input_format = SHORT;
static int output_format = SHORT;

main(argc, argv)
char **argv;
{
	int i,j;	/* dummy loop vars */

	for (i=1; i<argc; i++) {
		switch (argv[i][0]) {
		case '-':
			switch (argv[i][1]) {
			case 'h':	/* remove header */
			    {
				int hdrsize;	/* size of header to remove */

				switch (argv[i][2]) {
				case '\0':
					hdrsize = 128;
					break;
				case '0': case '1': case '2': case '3':
				case '4': case '5': case '6': case '7':
				case '8': case '9':
					hdrsize = atoi(&argv[i][2]);
					break;
				default:
					fputs("Invalid header size after -h flag\n", stderr);
					exit(1);
				}

				for (j=0; j<hdrsize; j++) {
					if (getchar() == EOF) {
						fputs("Premature EOF in header\n", stderr);
						exit(1);
					}
				}
			    }
				break;
			case 'i':	/* specify input file feature */
				switch (argv[i][2]) {
				case 'c':
					input_format = UCHAR;
					break;
				case 's':
					input_format = SHORT;
					break;
				case 'f':
					input_format = FLOAT;
					break;
				default:
					usage();
				}
				break;
			case 'o':	/* specify output file feature */
				switch (argv[i][2]) {
				case 'c':
					output_format = UCHAR;
					break;
				case 's':
					output_format = SHORT;
					break;
				case 'f':
					output_format = FLOAT;
					break;
				default:
					usage();
				}
				break;
			default:
				usage();	/* does not return */
			}
			break;
		default:
			usage();	/* does not return */
		}
	}

	switch (input_format) {
	case UCHAR:
		switch (output_format) {
		case SHORT: char_to_short(); break;
		case FLOAT: char_to_float(); break;
		case UCHAR: copy(); break;
		default: fputs("Can only convert char to short or float\n", stderr);
			exit(1);
		}
		break;
	case SHORT:
		switch (output_format) {
		case SHORT: copy(); break;
		case FLOAT: short_to_float(); break;
		default: fputs("Can only convert shorts to floats\n", stderr);
			exit(1);
		}
		break;
	case FLOAT:
		switch (output_format) {
		case SHORT: float_to_short(); break;
		case FLOAT: copy(); break;
		default: fputs("Can only convert floats to shorts\n", stderr);
			exit(1);
		}
		break;
	default:
		fprintf(stderr, "Internal error: Impossible input format %d.\n",
			input_format);
		exit(1);
	}

	exit(0);
}

/* Conversion functions */

/* no-op */
copy()
{
	int c;

	while ( (c = getchar()) != EOF) putchar(c);
}

char_to_float()
{
	register int sin;
	float sout;

	while ( (sin=getchar()) != EOF) {
		sout = (sin - 128) << 8;
		fwrite((char *) &sout, sizeof(sout), 1, stdout);
	}
}

char_to_short()
{
	register int sin;
	short sout;

	while ( (sin=getchar()) != EOF) {
		sout = (sin - 128) << 8;
		fwrite((char *) &sout, sizeof(sout), 1, stdout);
	}
}

short_to_float()
{
	short sin;
	float sout;

	while (fread((char *)&sin, sizeof(sin), 1, stdin) == 1) {
		sout = sin;
		fwrite((char *) &sout, sizeof(sout), 1, stdout);
	}
}

float_to_short()
{
	float sin;
	short sout;

	while (fread((char *)&sin, sizeof(sin), 1, stdin) == 1) {
		sout = sin;
		fwrite((char *) &sout, sizeof(sout), 1, stdout);
	}
}
