/* TTY input line editing
 * Copyright 1991 Phil Karn, KA9Q
 *
 * ATARI Version by David Nash - dnash@chaos.demon.co.uk
 */
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "session.h"
#include "tty.h"
#include "socket.h"

extern FILE *Rawterm;

#define	OFF	0
#define	ON	1

#define	LINESIZE	256

#ifndef ATARI
#define	CTLU	21
#define CTLR	18
#define	CTLZ	26
#define LEFT	75
#define RIGHT	77
#define UP		72
#define DOWN	80
#define HOME	71
#define END		334
#define BS		0x7f
#define DEL		83
#else
#define	CTLU	21
#define CTLR	18
#define	CTLZ	26
#define LEFT	330
#define RIGHT	332
#define UP		327
#define DOWN	335
#define HOME	326
#define END		334
#define	BS		0x7f
#define DEL		338
#endif

/* Accept characters from the incoming tty buffer and process them
 * (if in cooked mode) or just pass them directly (if in raw mode).
 *
 * Echoing (if enabled) is direct to the raw terminal. This requires
 * recording (if enabled) of locally typed info to be done by the session
 * itself so that edited output instead of raw input is recorded.
 */
 
struct mbuf *ttydriv(
	struct session *sp,
	int c )
{
	struct mbuf *bp;
	char *cp,*rp, cc;
	int dif, i;
	cc = c % 256;

	switch(sp->ttystate.edit) {
	case OFF:
		bp = ambufw(1);
		*bp->data = cc;
		bp->cnt = 1;

		if(sp->ttystate.echo)
			putc(c,Rawterm);

		return bp;

	case ON:
		if(sp->ttystate.line == NULLBUF)
			sp->ttystate.line = ambufw(LINESIZE);

		bp  = sp->ttystate.line;
		cp  = bp->data + sp->cur_pos;
		dif = bp->cnt - sp->cur_pos;

		/* Perform cooked-mode line editing */

		switch(c) {
		case '\r':									/* CR & LF both terminate line 	*/
		case '\n':
			if(sp->ttystate.crnl)
				*(cp + dif) = '\n';
			else
				*(cp + dif) = cc;
				
			if(sp->ttystate.echo)
				fputs(Eol,Rawterm);
				
			bp->cnt += 1;
			sp->ttystate.line = NULLBUF;
			return bp;

		case DEL:
#if 0
			if (dif == 0)
				break;

			/* Forward a character */

			sp->cur_pos++;
			dif--;
			cp++;
			putc(' ', Rawterm);
#endif
			if (sp->cur_pos < bp->cnt)	{
				sp->cur_pos++;
			}	
			/* Now drop through to delete backwards */

		case BS:
		case '\b':	/* Character delete */
			if(sp->cur_pos)	{
				bp->cnt--;
				sp->cur_pos--;

				if(sp->ttystate.echo)
					fputs("\b \b",Rawterm);

				if (dif)	{
					memmove(cp - 1, cp, dif);
					if(sp->ttystate.echo)	{
						for (i = 0; i < dif; i++)
							putc(*(cp + i - 1), Rawterm);
						putc(' ', Rawterm);
						for (i = 0; i <= dif; i++)
							fputs("\b", Rawterm);
					}
				}
			}
			break;

		case CTLR:									/* print line buffer 				*/
			if(sp->ttystate.echo)
				{
				fprintf(Rawterm,"^R%s",Eol);
				rp = bp->data;
				while (rp < cp)
					putc(*rp++,Rawterm);
				}
			break ;
		case CTLU:									/* Line kill 							*/
			while (dif--)
				putc(' ', Rawterm);
				
			while(bp->cnt != 0)	{
				bp->cnt--;

				if(sp->ttystate.echo)
					fputs("\b \b",Rawterm);
			}

			sp->cur_pos = 0;
			break;

		case LEFT:		/* Cursor left */
			if (sp->cur_pos > 0)	{
				sp->cur_pos--;
				fputs("\b",Rawterm);
			}
			break;

		case RIGHT:	/* Cursor right */
			if (sp->cur_pos < bp->cnt)	{
				sp->cur_pos++;
				
				if(sp->ttystate.echo)
					putc(*cp, Rawterm);
			}
			break;

		case HOME:									/* Back to start of line 			*/
			while (sp->cur_pos) {
				sp->cur_pos--;
				
				if(sp->ttystate.echo)
					fputs("\b", Rawterm);
			}
			break;

		case END:									/* Go to end of line 				*/
			for (i = 0; i < dif; i++) {
				if(sp->ttystate.echo)
					putc(*(cp + i), Rawterm);
					
				sp->cur_pos++;
			}
			break;

		case UP:										/* Previous line 						*/
			break;

		case DOWN:									/* Next line 							*/
			break;

		default:										/* Ordinary character 				*/
			if (dif)
				memmove(cp + 1, cp, dif);
			*cp = cc;
			bp->cnt++;
			sp->cur_pos++;

			if (sp->ttystate.echo && bp->cnt < LINESIZE-1) {
				putc(cc,Rawterm);
				if (dif) {
					for (i = 0; i < dif; i++)
						putc(*(cp + i + 1), Rawterm);
					for (i = 0; i < dif; i++)
						fputs("\b", Rawterm);
				}
			}
			else if(bp->cnt >= LINESIZE-1) {
				putc('\007',Rawterm);			/* Beep 									*/
				bp->cnt--;
			}
			break;
		}
		break;
	}
	return NULLBUF;
}
