/* TTY input line editing
 * Copyright 1991 Phil Karn, KA9Q
 * split screen by G. J. van der Grinten, PA0GRI
 */
#include <stdio.h>
#ifdef __TURBOC__
#include <conio.h>
#endif
#include <ctype.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

static int  Lastsize = 1;
static char Lastline[LINESIZE+1] = "\n";
#define	CTLU	21		/* delete current line in total */
#define	CTLR	18		/* reprint current line */
#define	CTLZ	26		/* EOF char in dos */
#define	CTLW	23		/* erase last word including preceding space */
#define	CTLB	02		/* use as F3 in dos but no editing */
#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.
 * Control-W added by g1emm again.... for word delete.
 * Control-B/Function key 3 added by g1emm for line repeat.
 */

struct mbuf *
ttydriv(sp,c)
struct session *sp;
char c;
{
	struct mbuf *bp;
	char *cp,*rp;
	int cnt;

	switch(sp->ttystate.edit){
	case OFF:
		bp = ambufw(1);
		*bp->data = c;
		bp->cnt = 1;
		if(sp->ttystate.echo){
			if(sp->split){
				sp->tsavex = wherex();
				sp->tsavey = wherey();
				window(1,24,80,25);
				gotoxy(sp->bsavex,sp->bsavey);
				highvideo();
				putch(c);
				normvideo();
				cputs("_\b");
				sp->bsavex = wherex();
				sp->bsavey = wherey();
				window(1,1,80,23);
				gotoxy(sp->tsavex,sp->tsavey);
			} else {
				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){
				if(sp->split){
					highvideo();
					rp = bp->data;
					while(rp < cp) {
						putch(*rp++);
					}
					normvideo();
					clreol();
					cputs(Eol);
					clreol();
					sp->tsavex = wherex();
					sp->tsavey = wherey();
					window(1,24,80,25);
					clrscr();
					cputs("_\b");
					sp->bsavex = wherex();
					sp->bsavey = wherey();
					window(1,1,80,23);
					gotoxy(sp->tsavex,sp->tsavey);
				} else {
					fputs(Eol,Rawterm);
				}
			}
			bp->cnt += 1;
			sp->ttystate.line = NULLBUF;
			Lastsize = bp->cnt;
			memcpy(Lastline, bp->data, Lastsize);			
			return bp;
		case DEL:
		case '\b':	/* Character delete */
			if(bp->cnt != 0){
				bp->cnt--;
				if(sp->ttystate.echo){
					if(sp->split){
						sp->tsavex = wherex();
						sp->tsavey = wherey();
						window(1,24,80,25);
						gotoxy(sp->bsavex,sp->bsavey);
						cputs(" \b\b_\b");
						sp->bsavex = wherex();
						sp->bsavey = wherey();
						window(1,1,80,23);
						gotoxy(sp->tsavex,sp->tsavey);
					} else {
						fputs("\b \b",Rawterm);
					}
				}
			}
			break;
		case CTLR:	/* print line buffer */
			if(sp->ttystate.echo){
				if(sp->split) {
					sp->tsavex = wherex();
					sp->tsavey = wherey();
					window(1,24,80,25);
					gotoxy(sp->bsavex,sp->bsavey);
					clrscr();
					rp = bp->data;
					while (rp < cp)
						putch(*rp++) ;
					cputs("_\b");
					sp->bsavex = wherex();
					sp->bsavey = wherey();
					window(1,1,80,23);
					gotoxy(sp->tsavex,sp->tsavey);
				} else {
					fprintf(Rawterm,"^R%s",Eol) ;
					rp = bp->data;
					while (rp < cp)
						putc(*rp++,Rawterm) ;
				}
			}
			break ;
		case CTLU:	/* Line kill */
			if(sp->split) {
				sp->tsavex = wherex();
				sp->tsavey = wherey();
				window(1,24,80,25);
				gotoxy(sp->bsavex,sp->bsavey);
				cputs(" \b");
				while(bp->cnt != 0){
					cputs("\b \b");
					bp->cnt--;
				}
				cputs("_\b");
				sp->bsavex = wherex();
				sp->bsavey = wherey();
				window(1,1,80,23);
				gotoxy(sp->tsavex,sp->tsavey);
			} else {
				while(bp->cnt != 0){
					bp->cnt--;
					if(sp->ttystate.echo)
						fputs("\b \b",Rawterm);
				}
			}
			break;
		case CTLB:	/* Use last line to finish current */
			cnt = bp->cnt;		/* save count so far */

			while(bp->cnt != 0){
				bp->cnt--;
				if(sp->ttystate.echo)
					fputs("\b \b", Rawterm);
			}
			bp->cnt = cnt;

                        if(bp->cnt < (Lastsize-1)){
                                memcpy(bp->data+bp->cnt, &Lastline[bp->cnt], (Lastsize-1) - bp->cnt);
                                bp->cnt = Lastsize-1;
			}

			*(bp->data + bp->cnt) = '\0';	/* make it a string */
			if(sp->ttystate.echo)
				fputs(bp->data, Rawterm);	/* repaint line */
			break ;
		case CTLW:	/* erase word */
			cnt = 0 ;	/* we haven't seen a printable char yet */
			while(bp->cnt != 0){
				*(bp->data + bp->cnt--) = '\n';
				if(sp->ttystate.echo)
					fputs("\b \b", Rawterm);
				if (isspace((int)*(bp->data + bp->cnt))) {
					if (cnt)
						break ;
				} else {
					cnt = 1 ;
				}
			}
			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){
				if(sp->split) {
					sp->tsavex = wherex();
					sp->tsavey = wherey();
					window(1,24,80,25);
					gotoxy(sp->bsavex,sp->bsavey);
					putch(c);
					cputs("_\b");
					sp->bsavex = wherex();
					sp->bsavey = wherey();
					window(1,1,80,23);
					gotoxy(sp->tsavex,sp->tsavey);
				} else {
					putc(c,Rawterm);
				}

			} else if(bp->cnt >= LINESIZE-1){
				putc('\007',Rawterm);	/* Beep */
				bp->cnt--;
			}
			break;
		}
		break;
	}
	return NULLBUF;
}
