/* TTY input line editing
 * Copyright 1991 Phil Karn, KA9Q
 */
#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

#define	CTLU	21
#define CTLR	18
#define	CTLZ	26
#define	DEL	0x7f

/* 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(sp,c)
struct session *sp;
char c;
{
	struct mbuf *bp;
	char *cp,*rp;

	switch(sp->ttystate.edit){
	case OFF:
		bp = ambufw(1);
		*bp->data = c;
		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 + bp->cnt;
		/* Perform cooked-mode line editing */
		switch(c & 0x7f){
		case '\r':	/* CR and LF both terminate the line */
		case '\n':
			if(sp->ttystate.crnl)
				*cp = '\n';
			else
				*cp = c;
			if(sp->ttystate.echo)
				fputs(Eol,Rawterm);

			bp->cnt += 1;
			sp->ttystate.line = NULLBUF;
			return bp;
		case DEL:
		case '\b':	/* Character delete */
			if(bp->cnt != 0){
				bp->cnt--;
				if(sp->ttystate.echo)
					fputs("\b \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(bp->cnt != 0){
				bp->cnt--;
				if(sp->ttystate.echo){
					fputs("\b \b",Rawterm);
				}
			}
			break;
		default:	/* Ordinary character */
			*cp = c;
			bp->cnt++;

			/* ^Z apparently hangs the terminal emulators under
			 * DoubleDos and Desqview. I REALLY HATE having to patch
			 * around other people's bugs like this!!!
			 */
			if(sp->ttystate.echo &&
#ifndef	AMIGA
			 c != CTLZ &&
#endif
			 bp->cnt < LINESIZE-1){
				putc(c,Rawterm);

			} else if(bp->cnt >= LINESIZE-1){
				putc('\007',Rawterm);	/* Beep */
				bp->cnt--;
			}
			break;
		}
		break;
	}
	return NULLBUF;
}
