/* atari.c */

/* Author:
 *	Guntram Blohm
 *	Buchenstrasse 19
 *	7904 Erbach, West Germany
 *	Tel. ++49-7305-6997
 *	sorry - no regular network connection
 */

/*
 * This file contains the 'standard' functions which are not supported
 * by Atari/Mark Williams, and some other TOS-only requirements.
 */
 
#include "config.h"
#include "vi.h"

#if TOS || MINT
#include <osbind.h>

# if !MINT /* MiNT's library is a little more complete :-) */

/* vi uses mode==0 only ... */
int access(file, mode)
	char *file;
{
	int fd=Fopen(file, 0);
	if (fd<0)
		return -1;
	Fclose(fd);
	return 0;
}

char *mktemp(template)
	char *template;
{
	return template;
}

# endif

# ifndef __GNUC__
char *getcwd(buf, size)
	char *buf;
{
	if (size < 2 + 64)
		return (char *)0;
	buf[0] = Dgetdrv() + 'A';
	buf[1] = ':';
	Dgetpath(buf + 2, 0);
	return buf;
}
# endif

/* read -- text mode, compress \r\n to \n
 * warning: might fail when maxlen==1 and at eol
 * ...no longer :-)  -nox
 */

int tread(fd, buf, maxlen)
	int fd;
	char *buf;
	int maxlen;
{
	int i, j, nread=read(fd, buf, (unsigned)maxlen);

	if (nread && buf[nread-1]=='\r')
	{
		if (--nread)
			lseek(fd, -1l, 1);
		else {
			if (read(fd, buf, 1) && *buf != '\n') {
				*buf = '\r';
				lseek(fd, -1l, 1);
			}
			return 1;
		}
	}
	for (i=j=0; j<nread; i++,j++)
	{	if (buf[j]=='\r' && buf[j+1]=='\n')
			j++;
		buf[i]=buf[j];
	}
	return i;
}

int twrite(fd, buf, maxlen)
	int fd;
	char *buf;
	int maxlen;
{
# if 1
	int i, j;
	/* uh, we can have that easier...  -nox */
	static char writbuf[BLKSIZE*2];

	for (i=j=0; j<maxlen; )
	{
		if ((writbuf[i++]=buf[j++])=='\n')
		{	writbuf[i-1]='\r';
			writbuf[i++]='\n';
		}
	}
	/* ...and make the result a little bit more reasonable too :-)  */
	if (!i || !(maxlen = write(fd, writbuf, (unsigned)i)))
		return 0;
	return j - i + maxlen;
}
# else
	int i, j, nwritten=0, hadnl=0;
	char writbuf[BLKSIZE];

	for (i=j=0; j<maxlen; )
	{
		if ((writbuf[i++]=buf[j++])=='\n')
		{	writbuf[i-1]='\r';
			if (i<BLKSIZE)
				writbuf[i++]='\n';
			else
				hadnl=1;
		}
		if (i==BLKSIZE)
		{
			write(fd, writbuf, (unsigned)i);
			i=0;
		}
		if (hadnl)
		{
			writbuf[i++]='\n';
			hadnl=0;
		}
	}
	if (i)
		write(fd, writbuf, (unsigned)i);
	return j;
}
# endif

/* The "timer" variable is used as a shadow of the system's timer.  Since the
 * system's timer can only be accessed in Supervisor mode, we are forced to
 * do a Supexec(gettime) to copy the system's timer in to the User-mode "timer"
 * variable.
 */
static long timer;
static void gettime()
{
	timer = *(long *)(0x4ba);
}
#endif /* TOS || MINT */

#if TOS
/* This function implements a read-with-timeout from the keyboard. */
/*ARGSUSED*/
int ttyread(buf, len, time)
	char	*buf;	/* where to store the gotten characters */
	int	len;	/* maximum number of characters to get -- ignored */
	int	time;	/* maximum time to allow for reading */
{
	int	pos=0;
	long	l;
	long	endtime;

	/* compute the ending time, in increments of 1/200th seconds */
	(void) Supexec(gettime);
	endtime = time * 20 + timer;

	/* wait until time runs out, or we get a keystroke */
	while (!pos && (!time || (timer-endtime) < 0))
	{
		if (Bconstat(2))
		{
			l = Bconin(2);
			buf[pos] = l;
			if (buf[pos++] == '\0')
			{
				buf[pos - 1] = '#';
				buf[pos++] = l >> 16;
			}
		}
		(void) Supexec(gettime);
	}
	return pos;
}

/* This function writes characters to the screen */
ttywrite(buf, len)
	char *buf;
	int len;
{
	while (len--)
		Bconout(2, *buf++);
}
#endif /* TOS */

#if MINT
extern int __mint;

# include <signal.h>
# include <setjmp.h>

static jmp_buf env;

/* ctputs(): same as tputs(), but recognizes #blink / #noblink to
   set the cursormode (have to do it this way because those are not
   available thru the ST's `VT52' emulator...) */

void ctputs(cp, affcnt, outfn)
	char	*cp;
	int	affcnt;
	int	(*outfn)();
{
	if (!strcmp(cp, "#blink")) {
		(void) Cursconf(2, 0);
		return;
	}
	if (!strcmp(cp, "#noblink")) {
		(void) Cursconf(3, 0);
		return;
	}
	tputs(cp, affcnt, outfn);
}

/* this turns those shifted cursor- / insert / home keys into
   something useful (without this, they would return digits...) */

static long fixkey(l)
	long	l;
{
	if (l < 0 || !(char) l)
		return l;
	switch ((unsigned char) (l >> 16)) {
		case 72:		/* shift- ^	-> PgUp */
			return 73l << 16;
		case 80:		/* shift- v	-> PgDn */
			return 81l << 16;
		case 71:		/* shift-Home	-> End */
			return 79l << 16;
		case 75:		/* shift- <-	-> ctrl- <- */
			return 115l << 16;
		case 77:		/* shift- ->	-> ctrl- -> */
			return 116l << 16;
		case 82:		/* shift-Insert	-> Printscreen */
			return 55l << 16;
	}
	return l;
}

/*ARGSUSED*/
static void dummy(signo)
	int	signo;
{
	longjmp(env, 1);
}

/* This function implements a read-with-timeout from the keyboard. */
/*ARGSUSED*/
int ttyread(buf, len, time)
	char	*buf;	/* where to store the gotten characters */
	int	len;	/* maximum number of characters to get -- ignored on terminals */
	int	time;	/* maximum time to allow for reading */
{
	int	pos=0;
	long	l;
	long	endtime;
	static	tty;	/* 'y' if reading from tty, or 'n' if not a tty */
	extern	int got_winch;	/* flag from our getsize() SIGWINCH handler */

	/* do we know whether this is a tty or not? */
	if (!tty)
		tty = (isatty(0) ? 'y' : 'n');

	if (tty != 'y')
		return read(0, buf, (unsigned) len);

	if (!__mint) {
		/* no MiNT -> eat cycles :-)  */

		/* compute the ending time, in increments of 1/200th seconds */
		(void) Supexec(gettime);
		endtime = time * 20 + timer;

		/* wait until time runs out, or we get a keystroke */
		while (!pos && (!time || (timer-endtime) < 0))
		{
			if (*o_stbios ? Bconstat(2) : Cconis())
			{
				l = fixkey(*o_stbios ? Bconin(2) : Crawcin());
				if (l < 0)
					return l;
				buf[pos] = l;
				if (buf[pos++] == '\0')
				{
					buf[pos-1] = '#';
					buf[pos++] = l >> 16;
				}
			}
			(void) Supexec(gettime);
		}
		return pos;
	}
	/* MiNT is there -> do it with alarm()
	   [yes MiNT also has select(), but as of MiNT version 0.94
	    that won't yet work over e.g. a serial line...] */

	/* arrange for timeout */
# if __GNUC__
	signal(SIGALRM, (void (*)()) dummy);
# else
	signal(SIGALRM, dummy);
# endif
	alarm(time);

	if (setjmp(env))
		return 0;
	do {
		l = fixkey(*o_stbios ? Bconin(2) : Crawcin());

		if (got_winch) {
			got_winch = 0;
			if (*o_lines != LINES || *o_columns != COLS) {
				*o_lines = LINES;
				*o_columns = COLS;
#ifndef CRUNCH
				if (!wset)
				{
					*o_window = LINES - 1;
				}
#endif
				if (mode != MODE_EX && mode != MODE_COLON)
					/* pretend the user hit ^L */
					buf[pos++] = ctrl('L');
			}
		}
		if (l > 0 && (buf[pos++]=l) == '\0')
		{
			buf[pos-1] = '#';
			buf[pos++] = l>>16;
		}
	} while (!pos);

	/* cancel the alarm */
	alarm(0);

	/* return the number of bytes read */
	return pos;
}

void ttywrite(buf, len)
	char	*buf;
	int	len;
{
	if (!*o_stbios) {
		write(1, buf, (unsigned) len);
		return;
	}
	while (len--)
		(void) Bconout(2, *buf++);
}
#endif /* MINT */
