/*
 *	FILEIO.C
 *	Do reading and writing of things to and from the disk,
 *	and associated routines.
 *
 *	get_filename()	Prompt for Filename: and return reply.
 *	load_disk()	Load a 32-voice dump from disk
 *	save_disk()	Save a 32-voice dump to disk
 */

#include <stdio.h>
extern char *numerosuffix();

static char *adddx7();		/* add .DX7 suffix to filename */

/*
 *	Interact-um!  Prompt for a filename and return the reply as a pointer
 *	to a static buffer.  Useful for code thinking of calling *_disk.
 */
char *
get_filename()
{
	static char filename[64];	/* Yeeaah... */

	d_input("Filename: ", filename, sizeof(filename));

	return(filename);
}

/*
 *	Load a voice bank from disk into the internal buffer
 *	if dump is true, load a corrupt voice dump (with
 *	status byte and header in the file)
 */
load_disk(filename, buf, dump)
char *filename;		/* name of file to load */
char *buf;		/* pointer to 4096-byte buffer to fill */
int dump;		/* does it have the status and header atill attached? */
{
	register FILE *fp;
	register int ch;
	int nbytes;
	register int i;
	extern char *index();

	/* Null filename means don't do it (and impossible) */
	if (filename[0] == '\0') {
		m_str("Load aborted.");
		return;
	}

	fp = fopen(filename, "br");

	if (fp == NULL && index(filename, '.') == NULL) {
		fp = fopen(adddx7(filename), "br");
	}

	if (fp == NULL) {
		error("Cannot open \"%s\".", filename);
		return;
	}
	
	if (dump) {
		/* dispense with leading garbage */
		do {
			ch = getc(fp);
			if (ch == EOF) {
				error("No Status byte in file.  Try normal load.");
				return;
			}
		} while (ch != 0xF0);

		/* gobble header */
		for (i=0; i<5; i++) {
			if (getc(fp) == EOF) {
				error(
"File is truncated %d bytes after first status byte.", i);
				return;
			}
		}
		/* ready to go... */
	}

	/* gobble in 4096 bytes */
	nbytes = fread(buf, 1, 4096, fp);

	if (nbytes < 4096) {
		char buf[256];	/* message under construction */
		int nwhole = nbytes/32;		/* number of complete voices */
		int nextra = nbytes%32;
error("Voice data is truncated (%d byte%s out of 4096)",
			nbytes, nbytes == 1 ? "" : "s");
sprintf(buf, "That's only %d voice%s", nwhole, nwhole == 1 ? "" : "s");
		if (nextra > 0) {
			/* I really can't believe I'm doing this */
sprintf(buf + strlen(buf), " and %d out of 32 bytes of the %d%s voice.",
			nextra, nwhole+1, numerosuffix(nwhole+1));
		}		/* Phew! */
		error(buf);
	}

	for (i=0; i<nbytes; i++) {
		if (buf[i] & 0x80) {
			register int j;
			int nbad = 1;	/* how many set top bits */
			error("Voice dump has top bits set.  Stripping...");

			for (j=i ; j<nbytes; j++) {
				if (buf[i] == 0xF0) {
error("If this doesn't work, try dump format load.");
					break;
				}
			}

			for (j=i ; j<nbytes; j++) {
				if (buf[j] & 0x80) {
					buf[j] &= 0x7f;
					nbad++;
				}
			}
error("%d top bits cleared, starting at the %d%s byte.",
				nbad, i+1, numerosuffix(i+1));
			break;		/* We have processed the buffer */
		}
	}

	/*
	 *	Deal with checksum trailer if necessary/possible.
 	 */
	if (dump && nbytes == 4096) {
		int cs_in;	/* checksum from file */
		/* deal with trailer info */
		if ((cs_in = getc(fp)) == EOF) {
			error("No checksum present.");
		} else {
			if (cs_in != checksum(buf, 4096)) {
error("Warning: Checksum error on dump file.  Voice data may be corrupted.");
			}
		}
	}
	fclose(fp);

	disp_names(buf);
}

save_disk(filename, buf)
char *filename;		/* Name of file to dump in */
char *buf;		/* 4096-byte dump file */
{
	FILE *fp;
	int nwritten;	/* cache return value from fwrite */

	/* Null filename means don't do it (and impossible) */
	if (filename[0] == '\0') {
		m_str("Save aborted.");
		return;
	}

	/*
	 * Need to munge the filename thusly: If it doesn't contain a dot,
	 * tack a .DX7 on the end of it to encourage standard filename
	 * suffixes.  If they really want a null suffix they can call it
	 * "FILE." or something similarly enlightening.
	 */
	if (index(filename, '.') == NULL) {
		filename = adddx7(filename);	/* Wow!  String functions! */
		m_printf("Saving to \"%s\".", filename)
	}

	/* First, a mug-trap for the unwary */
	fp = fopen(filename, "br");
	if (fp != NULL) {
		/* File exists. */
		char answer[4];		/* Enough for "yes" */

		fclose(fp);

		/* Did we add a .dx7 suffix for them? */
		if (filename == adddx7(filename)) {
			m_printf("I assumed you meant \"%s\". \
If you want a null suffix, specify it with a trailing dot", filename);
		}
		d_input("File exists. Shall I overwrite it?", answer, 4);
		if (answer[0] != 'y' && answer[0] != 'Y') {
			m_str("Save aborted.");
			return;
		}
	}

	fp = fopen(filename, "bw");
	if (fp == NULL) {
		error("Cannot open \"%s\" for writing.", filename);
		return;
	}

	nwritten = fwrite(buf, 1, 4096, fp);
	if (nwritten != 4096) {
		m_printf("Write to file failed");
		if (nwritten > 0) {
		m_printf(", only %d byte%s out of 4096 actually written",
			nwritten, (nwritten > 1) ? "s" : "");
		}
		m_printf(".\n");
	}

	fclose(fp);
}

/*
 *	Add the suffix ".DX7" to a filename which doesn't contain a dot.
 */
static char *
adddx7(filename)
char *filename;
{
	static char buf[13];	/* 8-ch filename + .dx7 suffix + nul == 13 */

	strncpy(buf, filename, 8);
	strcat(buf, ".DX7");
}
