
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "regs.h"
#include "parity.h"
#include "asciibcd.h"
#include "chan.h"
#include "io.h"
#include "screen.h"

#define TAPESIZE 2000000

FILE *logfd;
unsigned char bsbuf[300];
char errstr[100];
char s[100];
extern int errno;
extern char errview[5][81];

char *
devstr(int dev)
{
	static char s[20];

	switch (dev) {

	case 0:
		return "Card reader";

	case 1:
		return "Card punch";

	case 2:
		return "Printer";

	default:
		sprintf(s, "Channel %c Tape %2d",
			(dev - 3)/10 + 'A', (dev - 3) % 10 + 1);
		return s;
	}
}

char *
parsedev(char *s, int *devp)
{
	char	c;
	int	dev;

	c = *s++;
	switch (c) {

	case 'r':
		dev = 0;
		iorw[dev] = 1;
		break;

	case 'u':
		dev = 1;
		iorw[dev] = 2;
		break;

	case 'p':
		dev = 2;
		iorw[dev] = 2;
		break;

	case 'a':
	case 'b':
	case 'c':
	case 'd':
	case 'e':
	case 'f':
	case 'g':
		dev = 10*(c - 'a') + 2;
		c = *s++;
		if (c >= '1' && c <= '9') {
			if (c == 1 && *s == '0') {
				dev += 10;
				s++;
			} else {
				dev += c - '0';
			}
			iorw[dev] = 3;
			break;
		}

	default:
		iochk = 1;
		run = 0;
		return (char *)0;
	}

	while (*s == ' ' || *s == '=')
		s++;

	*devp = dev;
	return s;
}

int
opendev(char *s, int dev)
{
	register i;
	int dot;

	if (*s == '@') {
		dorewind(dev);
		return 0;
	} else if (*s == '#') {
		if (dev <= 2) {
			iochk = 1;
			run = 0;
			return -1;
		}
		iorw[dev] = 1;
		return 0;
	}

	if (iofd[dev] != NULL) {
		fclose(iofd[dev]);
		iofd[dev] = NULL;
		iostr[dev][0] = '\0';
	}
	if (*s == '\0' || *s == '\n') {
		return 0;
	}

	dot = 0;
	i = 0;
doname:
	for (; i < MAXNAME; i++) {
		if ((iostr[dev][i] = *s++) == '\0')
			goto nlong;
		if (iostr[dev][i] == '\n') {
			iostr[dev][i] = '\0';
			goto nlong;
		}
		if (iostr[dev][i] == '@') {
			iostr[dev][i] = '\0';
			goto nlong;
		}
		if (iostr[dev][i] == '#') {
			if (dev <= 2) {
				iochk = 1;
				run = 0;
				iostr[dev][0] = '\0';
				return -1;
			}
			iorw[dev] = 1;
			iostr[dev][i] = '\0';
			goto nlong;
		}
		if (iostr[dev][i] == '.') {
			dot = 1;
		}
		if (iostr[dev][i] == '\\') {
			dot = 0;
		}
	}
	iochk = 1;
	run = 0;
	iostr[dev][0] = '\0';
	return -1;
nlong:
	if (!dot && dev <= 2) {
		if (dev < 2)
			s = ".cbn";
		else
			s = ".bcd";
		goto doname;
	}

	switch (iorw[dev]) {
	case 1:
		iofd[dev] = fopen(iostr[dev], "rb");
		break;

	case 2:
		iofd[dev] = fopen(iostr[dev], "wb");
		break;

	case 3:
		iofd[dev] = fopen(iostr[dev], "r+b");
		if (iofd[dev] == NULL)
			iofd[dev] = fopen(iostr[dev], "w+b");
		break;

	}
	if (iofd[dev] == NULL) {
		sprintf (errview[0], "%s: open failed: %s",
			 devstr(dev), strerror(errno));
		sprintf (errview[1], "filename: %s", iostr[dev]);
		iochk = 1;
		iostr[dev][0] = '\0';
		run = 0;
		return -1;
	}
	iopos[dev] = 0;
	iobin[dev] = 0;
	return 0;
}

int
mount(char *s)
{
	int dev;

	if (*s == '\n' || *s == '\0')
		return 0;
	if ((s = parsedev(s, &dev)) == (char *)0) {
		mounterr();
		return -1;
	}
	return opendev(s, dev);
}

void
mounterr()
{
    strcpy (errview[0], "mount file on unit: r=cr, u=pch, p=prt");
    strcpy (errview[1], "                    a-h=chan + 1-10=tape");
    strcpy (errview[2], "                    # fpt, @ rwd");
}

void
listmount()
{
	register i, j;

	screenposition(17,1);
	clearline();
	printf("\nChannel  Unit     R  File\n");
	if (iofd[0])
		printf("   A  Card Reader # %s\n", iostr[0]);
	if (iofd[1])
		printf("   A  Card Punch  * %s\n", iostr[1]);
	if (iofd[2])
		printf("   A  Printer     * %s\n", iostr[2]);
	for (i = 0; i < NUMCHAN; i++) {
		for (j = 1; j < 10; j++)
			if (iofd[i*10+j+2] != NULL)
				printf("   %c  Tape %2d     %c %s\n",
					'A' + i,
					j,
					iorw[10*i+j+2] == 1? '#' : ' ',
					iostr[i*10+j+2]);
	}
}

void
readrec(int dev, char *buf, int len)
{
	register i, j;
	int n;

	if (iofd[dev] == NULL) {
		iochk = 1;
		sprintf(errstr, "%s: No file mounted", devstr(dev));
		printerror(errstr);
		run = 0;
		return;
	}
	if ((iorw[dev] & 1) == 0) {
		iochk = 1;
		sprintf(errstr, "%s(%s): File is write-only",
			devstr(dev), iostr[dev]);
		printerror(errstr);
		run = 0;
		return;
	}
readmore:
	n = fread(buf, 1, len, iofd[dev]);
	if (n == 0) {
		buf[0] = (char)0217;
		for (i = 1; i < len; i++)
			buf[i] = 0;
		return;
	} else if (n < 0) {
		iochk = 1;
		sprintf(errstr, "%s(%s): Read error %d",
			devstr(dev), iostr[dev], errno);
		printerror(errstr);
		run = 0;
		return;
	}
	iopos[dev] += n;
	for (j = n; j < len; j++)
		buf[j] = 0;
	for (i = 0; i < n; i++) {
		if (buf[i] & 0200)
			break;
	}
	if (i == n)
		goto readmore;
	if (i > 0) {
		for (j = 0; i < n; )
			buf[j++] = buf[i++];
		n = fread(&buf[j], 1, len - j, iofd[dev]);
		if (n < 0) {
			iochk = 1;
			sprintf(errstr, "%s(%s): Read error %d",
				devstr(dev), iostr[dev], errno);
			printerror(errstr);
			run = 0;
			return;
		}
		iopos[dev] += n;
		for (j = j + n; j < len; j++)
			buf[j] = 0;
	}
	for (i = 1; i < n; i++) {
		if (buf[i] & 0200) {
			for (j = i; j < len; j++)
				buf[j] = 0;
			iopos[dev] = iopos[dev] - n + i;
			fseek(iofd[dev], iopos[dev], 0);
			break;
		}
	}
}

void
bsr(int ch)
{
	int	dev;
	register i;
	int n;

	dev = whatdev(ch);
	if (iofd[dev] == NULL) {
		iochk = 1;
		sprintf(errstr, "%s: No file mounted", devstr(dev));
		printerror(errstr);
		run = 0;
		return;
	}
	if ((iorw[dev] & 1) == 0) {
		iochk = 1;
		sprintf(errstr, "%s(%s): File is write-only",
			devstr(dev), iostr[dev]);
		printerror(errstr);
		run = 0;
		return;
	}
	while (iopos[dev] > 0) {
		if (iopos[dev] > sizeof bsbuf) {
			n = sizeof bsbuf;
			iopos[dev] -= sizeof bsbuf;
		} else {
			n = iopos[dev];
			iopos[dev] = 0;
		}
		fseek(iofd[dev], iopos[dev], 0);
		fread(bsbuf, 1, n, iofd[dev]);
		for (i = n - 1; i >= 0; i--) {
			if (bsbuf[i] & 0200) {
				iopos[dev] += i;
				fseek(iofd[dev], iopos[dev], 0);
				goto done;
			}
		}
	}
	fseek(iofd[dev], 0L, 0);
done:

#ifdef IODEBUG
sprintf(s, "bsr   %s                                %10ld",
	devstr(dev), iopos[dev]);
printerror(s);
#endif

	if (iopos[dev] == 0)
		cbot[ch] = 1;
}

void
bsf(int ch)
{
	int	dev;
	register i;
	int n;

	dev = whatdev(ch);
	if (iofd[dev] == NULL) {
		iochk = 1;
		sprintf(errstr, "%s: No file mounted", devstr(dev));
		printerror(errstr);
		run = 0;
		return;
	}
	if ((iorw[dev] & 1) == 0) {
		iochk = 1;
		sprintf(errstr, "%s(%s): File is write-only",
			devstr(dev), iostr[dev]);
		printerror(errstr);
		run = 0;
		return;
	}
	while (iopos[dev] > 0) {
		if (iopos[dev] > sizeof bsbuf) {
			n = sizeof bsbuf;
			iopos[dev] -= sizeof bsbuf;
		} else {
			n = iopos[dev];
			iopos[dev] = 0;
		}
		fseek(iofd[dev], iopos[dev], 0);
		fread(bsbuf, 1, n, iofd[dev]);
		for (i = n - 1; i >= 0; i--) {
			if (bsbuf[i] == 0217 &&
			    (i == n - 1 || bsbuf[i + 1] & 0200)) {
				iopos[dev] += i;
				fseek(iofd[dev], iopos[dev], 0);
				goto done;
			}
		}
	}
	fseek(iofd[dev], 0L, 0);
done:

#ifdef IODEBUG
sprintf(s, "bsf   %s                                %10ld",
	devstr(dev), iopos[dev]);
printerror(s);
#endif

	if (iopos[dev] == 0)
		cbot[ch] = 1;
}

void
writerec(int dev, char *buf, int len)
{
	int n;

	if (iofd[dev] == NULL) {
		if (dev == 2)
			return;
		iochk = 1;
		sprintf(errstr, "%s: No file mounted", devstr(dev));
		printerror(errstr);
		run = 0;
		return;
	}
	if ((iorw[dev] & 2) == 0) {
		iochk = 1;
		sprintf(errstr, "%s(%s): File is read-only",
			devstr(dev), iostr[dev]);
		printerror(errstr);
		run = 0;
		return;
	}
	buf[0] |= 0200;
	buf[len] = (char)0200;
	n = fwrite(buf, 1, len + 1, iofd[dev]);
	if (n != len + 1) {
		iochk = 1;
		if (n < 0)
			sprintf(errstr, "%s(%s): Write error %d",
				devstr(dev), iostr[dev], errno);
		else
			sprintf(errstr,
 "%s(%s): Out of disk space, wrote %d of %d bytes",
				devstr(dev), iostr[dev], n, len);
		printerror(errstr);
		run = 0;
		return;
	}
	iopos[dev] += len;
	fseek(iofd[dev], iopos[dev], 0);
	if (iopos[dev] > TAPESIZE)
		ceot[(dev - 3)/10] = 1;
}

void
dorewind(int dev)
{

	if (dev == 1 || dev == 2) {
		fflush(iofd[dev]);
		return;
	}
	if (iofd[dev] == NULL) {
	   iochk = 1;
	   run = 0;
	   sprintf (errstr, "rewind: dev %d is not open", dev);
	   return;
	}
	fseek(iofd[dev], 0L, 0);
	iopos[dev] = 0;
	iobin[dev] = 0;

#ifdef IODEBUG
sprintf(s, "rew   %s                                %10ld",
	devstr(dev), iopos[dev]);
printerror(s);
#endif

}

void
unload(int dev)
{

	if (iofd[dev] == NULL) {
	   return;
	}
	fclose(iofd[dev]);
	iofd[dev] = NULL;

#ifdef IODEBUG
sprintf(s, "rwunl %s                                %10ld",
	devstr(dev), iopos[dev]);
printerror(s);
#endif

}

int
dismount (char *s)
{
   int dev;

  if (*s == '\n' || *s == '\0')
	  return 1;
  if (parsedev(s, &dev) == (char *)0)
	  return -1;

   unload(dev);
   return 0;
}

void
wef(int ch)
{
	int dev;
	unsigned char tapemark[2];

	dev = whatdev(ch);
	if (dev < 3)
		return;

#ifdef IODEBUG
sprintf(s, "wef   %s                                %10ld",
	devstr(dev), iopos[dev]);
printerror(s);
#endif

	tapemark[0] = 017;
	writerec(dev, tapemark, 1);
}


void
bincard(char *cnvbuf, unsigned short *crcol)
{
	register i;

	for (i = 0; i < 80; i++)
		crcol[i] = ((unsigned short)(cnvbuf[2*i] & 077) << 6) |
			   (cnvbuf[2*i + 1] & 077);
}

void
cardbin(unsigned short *crcol, char *cnvbuf)
{
	register i;

	for (i = 0; i < 80; i++) {
		cnvbuf[2*i] = oddpar[(crcol[i] >> 6) & 077];
		cnvbuf[2*i + 1] = oddpar[crcol[i] & 077];
	}
	cnvbuf[0] |= 0200;
}

void
cardbcd(unsigned short *cbuf, unsigned char *bbuf, int len)
{
	register num;
	register row;

	for (; len; len--) {
		row = 00001;
		for (num = 10; --num; ) {
			if (*cbuf & row)
				break;
			row <<= 1;
		}
		if (num == 8 && (*cbuf & 00174) != 0) {
			row = 00004;
			for (num = 16; --num > 10; ) {
				if (*cbuf & row)
					break;
				row <<= 1;
			}
		} else if (num == 0 && *cbuf & 01000)
			num = 10;
		if ((*cbuf & 01000) && num != 10)
			num |= 020;
		else if (*cbuf & 02000)
			num |= 040;
		else if (*cbuf & 04000)
			num |= 060;
		else if (num == 0)
			num = 020;
		cbuf++;
		*bbuf++ = evenpar[num];
	}
}

void
logstr(char *s)
{

	fprintf(logfd, "%s\n", s);
}

void
ioinit()
{
	register i;

	for (i = 0; i < IODEV; i++) {
		iostr[i][0] = 0;
		iofd[i] = NULL;
		iopos[i] = 0;
		iorw[i] = 3;
		iobin[i] = 0;
	}
	iorw[0] = 1;
	iorw[1] = 2;
	iorw[2] = 2;
	logfd = fopen("printlog.lst", "w");
}

void
iofin()
{
	register i;

	for (i = 0; i < IODEV; i++) {
		if (iofd[i] != NULL)
			fclose(iofd[i]);
		iofd[i] = NULL;
	}
	fclose(logfd);
}
