#
/*	This is the second and final segment of the QMC Unix Editor - em */
#define EOF -1
#define LBSIZE	512
#define	SIGHUP	1
#define	SIGINTR	2
#define	SIGQUIT	3
#define UNIXBUFL 100
#define error	errfunc()		/*** was 'goto errlab' ***/
#define TABSET	7	/* this should be determined dynamically */

#define RAW	040
#define ECHO	010
#define OPEN	'/'
#define BELL	07
#define ESCAPE	033
#define SPACE	040
#define BACKSL	0134
#define RUBOUT	0177
#define CTRLA	01
#define CTRLB	02
#define CTRLC	03
#define CTRLD	04
#define CTRLE	05
#define CTRLF	06
#define CTRLH	010
#define CTRLI	011
#define CTRLQ	021
#define CTRLR	022
#define CTRLS	023
#define	CTRLV	026
#define CTRLW	027
#define CTRLX	030
#define CTRLZ	032

#define ITT	0100000

extern char	*linebp, *loc2, linebuf[LBSIZE], genbuf[LBSIZE],
			unixbuffer[UNIXBUFL];
extern int	onquit,onhup, peekc;
extern int	*zero, *addr1, *addr2;
extern int	*errlab;
extern int	lastc;
int	margin	LBSIZE - 40;
int	oflag;
char	*threshold, *savethresh;
char	*lnp,*gnp,*brp;
int	savetty, tty[3];


op(inglob)
{	register *a1;
	register char *lp, *sp;
	int seof, ch;
	int t, nl;
	extern getopen(), getnil();

	threshold = genbuf + margin;
	savethresh = 0;

	switch (ch = peekc = getchar()) {
		case BACKSL:
			t = 1;
			delete();
			addr2 = addr1;
			break;

		case ';':
		case '+':
			t = 0;
			break;

		case '-':
			t =1;
			break;

		default:
			goto normal;

	}

	peekc = 0;
	if(addr1 != addr2) error;
	oflag = 0;
	append(getnil, addr2 - t);
	addr1 = addr2 =- (t-1);
	setdot();
	nonzero();


normal:
	if(addr1 == zero) error;
	if ((seof = getchar()) == '\n') { loc2 = linebuf-1;
						seof = 0;}
		else compile(seof);
	setraw(); /* terminal into raw mode*/

	for ( a1 = addr1; a1 <= addr2; a1++) {
		if (seof) {if (execute(0,a1) == 0) continue;}
			else getline(*a1);
		puts("\\\r");
		lp = linebuf;
		sp = genbuf;
		inglob =| 01;
		while (lp < loc2){ putch(*lp); *sp++ = *lp++; }
		lnp = lp;
		gnp = sp;


		oflag = gopen(); /* open the current line */
		*a1 = putline(); /* write revised line */
			nl = append( getopen,a1);
			a1 =+ nl;
			addr2 =+ nl;
	}
	setcook(); /* terminal in cook mode */
	putchar('\n');
	if (inglob == 0) { putchar('?'); error;}
}

getnil()
{
	if(oflag == EOF) return EOF;
	linebuf[0] = '\0';
	oflag = EOF;
	return 0;
}

setraw()
{
	if(gtty(0,tty) == -1) error;
	savetty = tty[2];
	tty[2] =| RAW;
	stty(0, tty);
}

setcook()
{
	tty[2] = savetty;
	stty(0, tty);
}

inword(c)
{
	if (c < '0') return(0);
	if (c <= '9') return(1);
	c =& 0137;
	if (c < 'A') return(0);
	if (c <= 'Z') return(1);
	return(0);
}

rescan()
{	register char *lp, *sp;

	if(savethresh) { threshold = savethresh; savethresh = 0; }
	lp = linebuf;
	sp = genbuf;
	while(*lp++ = *sp++) if(lp>linebuf+LBSIZE) {
				*(--lp) = 0;
				return 0;
				}
}


gopen()
	/*leaves revised line in linebuf,
	returns 0 if more to follow, EOF if last line */
{	register char *lp, *sp, *rp;
	register char *br, *pr;
	int ch, tabs;
	int retcode, savint, pid, rpid;

	lp = lnp;
	sp = gnp;
	tabs = 0;
	for (rp = genbuf; rp < sp; rp++) if (*rp == CTRLI) tabs =+ TABSET;

	for(;;){
		switch (ch = getchar()) {

			case CTRLD:
			case ESCAPE:	/* close the line (see case '\n' also) */
			close:
				putb(lp);
				while(*sp++ = *lp++);
				rescan();
				return(EOF);

			case CTRLA:	/* verify line */
			verify: puts("\\\r");
				putch('\r');
				*sp = '\0';
				putb(genbuf);
				continue;

			case CTRLB:	/* back a word */
				if(sp == genbuf) goto backquery;

				while((*(--lp) = *(--sp)) == SPACE)
					if(sp < genbuf) goto out;
				if(inword(*sp)) {
					while(inword((*(--lp) = *(--sp))))
						 if(sp < genbuf) goto out;
					if(*sp == SPACE)
						while((*(--lp) = *(--sp)) == SPACE)
							if(sp < genbuf) goto out;
				}	
				else while(sp >= genbuf && !inword(*sp))
					if((*lp-- = *sp--) == CTRLI) tabs =- TABSET;
			out:	sp++;
				lp++;
				goto verify;

			case CTRLC:
			case CTRLQ: /* forward one char */
				if(*lp == 0) goto backquery;
				putch(*lp);
			forward:
				if(*lp == SPACE && sp + tabs > threshold) {
					putch('\r');
					ch = '\n'; putch(ch);
					lp++;
					*sp++ = ch;
					br = sp;
					break;
				}
				if(*lp == CTRLI) tabs =+ TABSET;
				*sp++ = *lp++;	/* one character */
				if(sp + tabs == threshold) putch(BELL);
				continue;


			case CTRLF:
			/* delete forward */
				while(*lp++);
				lp--;
				goto verify;

			case CTRLE:
				putb(lp);
				goto verify;

			case CTRLH:  help(); goto verify;

			case CTRLR:	/* margin release */
				if(threshold-genbuf<LBSIZE-40) {
					savethresh = threshold;
					threshold = genbuf+LBSIZE-40;
				}
				else goto backquery;
				continue;

			case CTRLS:	/* re-set to start of line */
				while(*sp++ = *lp++);
				rescan();
				lp = linebuf; sp = genbuf;
				tabs = 0;
				goto verify;

			case CTRLV:	/* verify spelling */
/***
				rp = sp;
				pr = unixbuffer+UNIXBUFL-2;
				*pr = 0;
				while(*(--rp) == SPACE);
				while(inword(*rp) && rp >= genbuf)
					*(--pr) = *rp--;
				if(*pr == 0) goto backquery;
				puts("!!");
				setcook();
				if((pid = fork()) == 0)
					{signal(SIGHUP, onhup);
					  signal(SIGQUIT, onquit);
					  execl("/bin/spell", "spell", pr, 0);
***/
					  puts("sorry, can't spell today");
/***
					  exit();
				}
				savint = signal(SIGINTR,1);
				while((rpid = wait(&retcode)) != pid
					 && rpid != -1);
				signal(SIGINTR, savint);
				setraw();
				puts("!!");
***/
				goto verify;


			case CTRLW:	/* forward one word */
				if(*lp == '\0') goto backquery;
				while(*lp == SPACE)
					putch(*sp++ = *lp++);
				if(inword(*lp)) {
					while(inword(*lp)) {
						putch(*sp++ = *lp++);
						if(sp+tabs==threshold) putch(BELL);
					}
					if(*lp == SPACE) {
						if(sp+tabs>threshold) {
							ch = '\n';
							lp++;
							*sp++ = ch;
							br = sp;
							putch('\r');
							putch('\n');
						}
						if(*lp == SPACE)
							while(*(lp+1) == SPACE)
							   putch(*sp++ = *lp++);
					}
				}
				else while(*lp && !inword(*lp)) {
					if(*lp == CTRLI) tabs =+ TABSET;
					putch(*sp++ = *lp++);
					if(sp+tabs==threshold) putch(BELL);
				}
				break;


			case CTRLZ:	/* delete a word */
				if(sp == genbuf) goto backquery;

				while(*(--sp) == SPACE) if(sp < genbuf) goto zout;
				if(inword(*sp)) {
					while(inword(*(--sp)))
						 if(sp < genbuf) goto zout;
					if(*sp == SPACE)
						while(*(--sp) == SPACE)
							if(sp < genbuf) goto zout;
				}	
				else while(sp >= genbuf && !inword(*sp))
					if(*sp-- == CTRLI) tabs =- TABSET;
			zout:	sp++;
				goto verify;

			case '@':	/*delete displayed line */
			/* delete backward */
				sp = genbuf;
				tabs = 0;
				goto verify;

			case RUBOUT:
				lastc = ('\n');
				puts("\\\r");
				setcook();
				error;

			case CTRLX:
				putch('#');
			case '#':
				if( sp == genbuf) goto backquery;
				if(*(--sp) == CTRLI) tabs =- TABSET;
				if( ch == CTRLX) goto verify;
				continue;

			case '\n':
			case '\r': /* split line, actually handled at
					end of switch block */
				ch = '\n';
				*sp++ = ch;
				br = sp;
				break;

			case BACKSL: /* special symbols */
				switch (ch = peekc = getchar()) {
				case '(':  ch = '{'; peekc = 0; break;
				case ')':  ch = '}'; peekc = 0; break;
				case '!':  ch = '|'; peekc = 0; break;
				case '^':  ch = '~'; peekc = 0; break;
				case '\'':  ch = '`'; peekc = 0; break;
				case BACKSL:
				case '#':
				case '@':  peekc = 0; break;

				default:  if(ch >= 'a' && ch <= 'z') {
						peekc = 0; ch =- 040;}
					else {
						*(--lp) = BACKSL;
						goto forward;
						}
				}

			default:	*(--lp) = ch;
					goto forward;
			}

		if (ch == '\n') { /* split line */
			if(*(br-1) != '\n') puts("!!");	/*debugging only */
			lnp = sp;
			while(*sp++ = *lp++); /*move the rest over */
			brp  = linebuf +(br - genbuf);
			lnp = linebuf + (lnp - br);
			rescan();
			*(brp-1) ='\0';
			return(0);
			}
		else continue;
	backquery: putch(BELL);	/***/
		} /* end of forloop block */
} /* end of gopen */



getopen()  /* calls gopen, deals with multiple lines etc. */
{	register char *lp, *sp;
	if (oflag == EOF) return EOF;

/* otherwise, multiple lines */

	lp = linebuf;
	sp = brp;
	while(*lp++ = *sp++); /*move it down */
	sp = genbuf;
	lp = linebuf;
	while (lp < lnp) *sp++ = *lp++;
	gnp = sp;
	/* should check whether empty line returned */
	oflag = gopen();
	return 0;
}

struct	{	char byte[];	};
putch(ch)
{
	write(1, &ch.byte[3], 1);
}

putb(ptr)	char *ptr;	/*display string */

{	register char *p;

	p = ptr;
	if(*p == '\0') return;
	while(*(++p));
	write(1,ptr,p-ptr);
}

help()
{	puts("\n");
	puts("	^A	display Again		^Q	next character");
	puts("	^B	backup word		^R	Release margin");
	puts("	ESCAPE				^S	re-scan from Start");
	puts("	or ^D	close line and exit	^V	verify spelling");
	puts("	^E	display to End		^W	next Word");
	puts("	^F	delete line Forward	^Z	delete word");
	puts("	^H	Help			# or ^X delete character");
	puts("	RUBOUT	exit unchanged		@	delete line backward\n");
	puts("	Other characters (including RETURN) inserted as typed");
}

