/*
 * _read: like read, but takes a long instead of an int. Written by
 * Eric R. Smith and placed in the public domain.
 */

#include <fcntl.h>
#include <osbind.h>
#include <errno.h>
#include <ioctl.h>
#include <signal.h>
#include <unistd.h>
#include "lib.h"

#define CTRL(x) (x & 0x1f)
#define UNDEF -1

struct tchars __tchars = {
	CTRL('C'),		/* interrupt */
	CTRL('\\'),		/* quit */
	CTRL('Q'),		/* start */
	CTRL('S'),		/* stop */
	CTRL('D'),		/* EOF */
	'\r'			/* alternate end of line */
};

struct ltchars __ltchars = {
	CTRL('Z'),		/* suspend */
	CTRL('Y'),		/* suspend after read */
	CTRL('R'),		/* reprint */
	UNDEF,			/* flush output */
	UNDEF,			/* erase word */
	UNDEF			/* quote next char */
};

/*
 * BUGS: in tos, turning ECHO off but leaving RAW and CBREAK alone doesn't
 * work properly
 */

long
_read(fd, buf, size)
	int fd;
	void *buf;
	unsigned long size;
{
	char *foo;
	long r;
	extern int __mint;
	int indx;
	int flags;

	if (isatty(fd)) {
/* work around a bug in TOS; 4096 bytes should be plenty for terminal reads */
		if (size > 4096) size = 4096;
		indx = __OPEN_INDEX(fd);
		if (indx < 0 || indx >= __NHANDLES)
			indx = __NHANDLES - 1;
		flags = __open_stat[indx].flags;
	}
	else
		flags = -1;

	if ( (__mint > 0) || (flags  == -1) ||
	     ( ((flags & (RAW|CBREAK)) == 0) && (flags & ECHO) ) ) {
		r = Fread(fd, size, buf);

		if (r < 0) {
			errno = (int) -r;
			return -1;
		}

	/* watch out for TTYs */
		if (__mint == 0 && isatty(fd)) {
			foo = (char *)buf;
			if (*foo == 4)		 /* ^D for EOF?? */
				return 0;
			foo[r] = '\n';		/* %!#@ TOS doesn't put in the LF */
			Cconout('\n');		/* not quite right if fd != 0 */
			r++;
		}
	}
	else {
again:
		r = _console_read_byte(fd) & 0x00ff;
		if (flags & ECHO) {
			_console_write_byte(fd, (int)r);
		}
		if (flags & CRMOD) {
			if (r == '\r') r = '\n';
		}
		if (!(flags & RAW)) {
			if (r == __tchars.t_intrc) {
				raise(SIGINT);
				goto again;
			}
			else if (r == __tchars.t_quitc) {
				raise(SIGQUIT);
				goto again;
			}
		}
		*((char *)buf) = r;
		r = 1;
	}

	return r;
}

int
read(fd, buf, size)
	int fd;
	void *buf;
	unsigned size;
{
	return (int) _read(fd, buf, (unsigned long)size);
}
