V9/cmd/emacs/windows.c

Compare this file to the similar file:
Show the results in this format:

#include <termio.h>
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>

/* EMACS_MODES: c,!fill,tabstop=4 */

#define MWIND 6

int wproc[MWIND];
int wx[MWIND];
int wy[MWIND];
int wox[MWIND];
int woy[MWIND];
int wofrn[MWIND];
int wifrn[MWIND];
int wbase[MWIND];
int wmode[MWIND];
int wstate[MWIND];

char wrbuf[MWIND] [BUFSIZ];
int wcnt[MWIND];
int wptr[MWIND];
int wmore[MWIND];

#define MSNORM 0
#define MSESC 1
#define MSXWAIT 2
#define MSYWAIT 3

#define MRAW 1
#define MMORE 2
#define MMSCROLL 4
#define MECHO 8
#define MVSEND 16
#define WSCROLL 32
#define MOPENW 64
#define MWAIT 128

char *mdname[16] = {"RAW",
					"MORE",
					"ROLL",
					"ECHO",
					"VIRTUAL",
					"SCROLLING",
					"OPEN-WAIT",
					"MWAIT",
				};
int wlen[MWIND];

int talkf = 0;						/* 1 if we are xtalk */

int cwind,nwind;

int quote,squig;

int ic;
int rx,ry;

char ibuf[BUFSIZ];
char tibuf[BUFSIZ];

extern int SCRNLIN;
extern int SCRWID;
extern int mcol;
extern int mline;
extern int ttykill;
extern int ttyerase;
extern int ttyintr;
extern int errno;
extern char *getname();
extern char *homedir();
extern char *findtty();
extern char *getenv();

tdelay(num)

int num;
{
/* 	VMIN = 0  does not seem to work	
	

	struct termio td;
	
	ioctl(0,TCGETA, &td);
	td.c_cc[VMIN] = num;
	td.c_cc[VTIME] = 1;
	ioctl(0,TCSETA, &td);
*/
/*		THIS KLUDGE ALSO WORKS POORLY, so now do it with a user level timer 


	if (num == 0) fcntl(0,F_SETFL,O_RDWR+O_NDELAY);		
	else fcntl(0,F_SETFL,O_RDWR);
*/
}


alarming()
{
	return;
}

xclose(x)
int x;
{
	int i;
	
	for (i = x; i < 20; i++) close(i);
}

wput(i,cp,nc)
int i;
int nc;
char *cp;
{
	register int x;
	int maxln;
	
	maxln = wbase[i]+wlen[i];
	xgo(wx[i]+wbase[i],wy[i]);
	for (x = 0; x < nc; x++) {
		if (cp[x] == '\n') {
			clrl();
			mline++;
			mcol=0;
		} else xputc(cp[x]);
		if (mline>=maxln) {
			wroll(i);
		}
	}
}

/* wroll -- roll over window i */


wroll(i)
register int i;
{
	if ((wmode[i] & WSCROLL) || (vadjust(wbase[i],wbase[i]-1+wlen[i],-1)== 0)) {
		xgo(wbase[i],0);
		clrl();
	} else {
		mline--;
	}
}

wmfix(c)
register c;
{
	xgo(wx[c]+wbase[c],wy[c]);
	wroll(c);
	if (mline == wbase[c]) {
		wmore[c]  = wlen[c]-1;
	} else {
		wmore[c] = 0;
		wmode[c] |= MMSCROLL;
	}
	wmode[c] |= MWAIT;
	wmode[c] ^= MWAIT;
	wx[c]=mline-wbase[c];
	wy[c]=mcol;
}

main(argc,argv)

int argc;
char **argv;
{

	int c;
	char *cp,*tp;
	int status;
	int pipe1[2];
	int pipe2[2];
	int i;
	int x;
	ttystart();
	signal(SIGCLD,SIG_IGN);
	signal(SIGPIPE,SIG_IGN);
	tdelay(0);
	nwind = 1;
	wifrn[0]=0;
	wofrn[0]=0;
	wmode[0]=0;
	wx[0]=0;
	wy[0]=0;
	wbase[0]=0;
	wlen[0]=SCRNLIN-2;
	wmore[0] = wlen[0]-1;	
	
	if (**argv != 'w') {
		talkf = 1;					/* We are talk */
		talk(argv[1]);				/* start talking */
	}

	while (1) {		
		for (i = 0; i < nwind; i++) {
			
			if (wmode[i] & MOPENW) {

				wofrn[i] = open(wrbuf[i],1+O_NDELAY);
				if (wofrn[i] >= 0) {
					wmode[i] ^= MOPENW;
					prompt1("TALKING");
				} else {
					prompt1("WAITING");
				}
			} else if (wifrn[i]) {
				if (wcnt[i] == 0) {
					wcnt[i] = read(wifrn[i],wrbuf[i],BUFSIZ);
					wptr[i] = 0;
				}
				if (wcnt[i]) {
					x = wprot(i,wrbuf[i]+wptr[i],wcnt[i]);
					wptr[i] += wcnt[i]-x;
					wcnt[i] = x;
					if (i == cwind) {
						rx = wx[i]+wbase[i];
						ry = wy[i];
					}
				}
			}
		}
		xgo (SCRNLIN-2,0);
		for (i = 0; i < nwind; i++) {
			if (wmode[i]&MWAIT) {
				sputs("  MORE-");
				xputc(i+'0');
			}
		}
		clrl();
		if (squig) prompt1("~: ");
		else if (wmode[cwind] & MRAW) {
			mgo(wx[cwind]+wbase[cwind],wy[cwind]);
		} else {
			mgo (rx,ry);
		}
		fflush(stdout);		
		signal(SIGALRM,alarming);
		alarm(1);
		x = read(0,&c,1);
		alarm(0);
		if (x > 0) {
			if (squig) {
				squig = 0;
				unprompt();
				switch(c) {
				
				case '':
					abort();
				case '':
					rfrsh();
					break;
				case 'w':
					cwind++;
					if (cwind >= nwind) cwind = 0;
					if ((wmode[cwind] &MRAW) == 0) {
						rx = wx[cwind]+wbase[cwind];
						ry = wy[cwind];
						ic = 0;
					}
					break;
				
					
					
					
				case 't':
					cp = getname ("Talk to? ");
					if (cp) talk(cp);
					break;
				case 's':
					wsplit(cwind);
					break;

				case '?':
					wmode[cwind] |= MMORE;
					newin("/n1/warren/emacs/windows.help");
					break;
				case '<':
					cp = getname("Input from? ");
					newin(cp);
					break;
				case '>':
					if (wofrn[cwind]) close(wofrn[cwind]);
					tdelay(1);
					cp = getname("Output to? ");
					tdelay(0);
					wofrn[cwind] = open(cp,1+O_NDELAY);
					if (wofrn[cwind] < 0) prompt1("error code %d",errno);
					break;
				case '!':
					if (wifrn[cwind]) close(wifrn[cwind]);
					if (wofrn[cwind]) close(wofrn[cwind]);
					if (wproc[cwind]) {
						kill(wproc[cwind],9);
					};
					tdelay(1);
					cp = getname ("Command? ");
					tdelay(0);
					
					pipe(pipe1);
					pipe(pipe2);
					if ((wproc[cwind] = fork()) == 0) {
						close(0);
						dup(pipe1[0]);
						close(1);
						close(2);
						dup(pipe2[1]);
						dup(pipe2[1]);
						xclose(3);
						signal(SIGCLD,SIG_DFL);
						tp = getenv("TERM");
						*tp='v';
						tp[1]=0;
						execl("/bin/sh", "sh", "-c", cp , 0);
						exit(0);
					} else {
						close(pipe1[0]);
						close(pipe2[1]);
						wifrn[cwind] = pipe2[0];
						fcntl(pipe2[0],F_SETFL,O_RDONLY+O_NDELAY);
						wofrn[cwind] = pipe1[1];
					}
					break;
					
				case 'k':
					if (wproc[cwind]) kill(wproc[cwind],9);
					if (wofrn[cwind] ){
						close(wofrn[cwind]);
						wofrn[cwind] = 0;
					}
					if (wifrn[cwind]) {
						close(wifrn[cwind]);
						wifrn[cwind] = 0;
					}
					break;
				case 'v':
					wmode[cwind] ^= MVSEND;
					break;
				case 'd':
					xgo(SCRNLIN-1,0);
					xprintf("#%d,ifrn:%d,ofrn:%d,base:%d,len:%d,",
					cwind,wifrn[cwind],wofrn[cwind],wbase[cwind],wlen[cwind]);
					xprintf("pid:%o,mode:%o (",wproc[cwind],wmode[cwind]);
					for (x = 0; x < 16; x++) {
						if (wmode[cwind] & (1<<x)) {
							xprintf ("%s,",mdname[x]);
						}
					}
					xputc(')');
					clrl();
					break;
				case '0':
				case '1':
				case '2':
				case '3':
					c-='0';
					if (wmode[c]&MWAIT) {
						wmfix(c);
					}
					break;
				case 'm':
					wmode[cwind] ^= MMORE;
				case 'S':
					wmode[cwind] ^= WSCROLL;
					break;
				case 'r':
					wmode[cwind] ^= MRAW;
					break;
				case '~':
					goto defchar;
				case '.':
					for (i = 0; i < nwind; i++) {
						if (wproc[i]) kill (wproc[i],9); /* murder */
					}
					tdelay(1);
					die(0);			/* go away */
				}
			} else {
				
				if (c == '~') {
					squig++;
				} else {
defchar:					 /* implement modes here */

					if (wmode[cwind]&MWAIT) {
						wmfix(cwind);
					} else {
						if (wmode[cwind] & MMSCROLL) {
							wmore[cwind] = 0; /* input to this window */
						} else {
							wmore[cwind] = wlen[cwind]-1;
						}
					}
					if (wmode[cwind]&MRAW) {
						if (wofrn[cwind]) {
							write(wofrn[cwind],&c,1);
						}
					} else {
						if (quote)  goto deflt;
						if (c == ttyerase) {
							if (ic) ic--;
							if (wmode[cwind] & MVSEND) {
								wput(cwind,tibuf,ic);
								x = ry-mcol;
								if (x < 0) x=1;
								if (wofrn[cwind]) {
									write(wofrn[cwind],"",x);
									write(wofrn[cwind],"T",2);
								}
							}
						} else if (c == ttykill) {
							ic = 0;
							if (wofrn[cwind] && (wmode[cwind] & MVSEND)) {
								write(wofrn[cwind],"
T",3);
							}
						} else if ((c == 015) ||(c == '\n') || (c == 4)) {
							if (c == '\r') c = '\n';
							tibuf[ic++] = c;
							wput(cwind,tibuf,ic);
							rx = mline;
							wx[cwind] = mline-wbase[cwind];
							ry = wy[cwind]=mcol;
							if (wofrn[cwind]) {
								if (wmode[cwind] & MVSEND) {
									write(wofrn[cwind],&c,1);
								} else {
									write(wofrn[cwind],tibuf,ic);
								}
							}
							ic = 0;
							if ((c == 4) && talkf) die(0); /* exit */
						} else if (c == '\\') {
							quote++;
						} else if (c == ttyintr) {
							if (wproc[cwind]) signal(wproc[cwind],SIGINT);
						} else {
deflt:						tibuf[ic++] = c;
							quote = 0;
							if ((wmode[cwind] & MVSEND) && wofrn[cwind]) {
								write(wofrn[cwind],&c,1);
							}
						}
						wput(cwind,tibuf,ic);
						rx = mline;
						ry = mcol;
						clrl();
					}
				}
			}
		} else {
/*			sleep(1);*/
		}
	}
}
wsplit(w)

int w;
{	
	int x;
	
	wbase[nwind] = wbase[w]+1+(wlen[w]/2);
	wlen[nwind] = wlen[w]-wbase[nwind]+wbase[w];
	wlen[w]=wbase[nwind]-wbase[w]-1;
	xgo(wbase[w]+wlen[w],0);
	for (x = 0; x < SCRWID; x++) {
		xputc('-');
	}
	wx[nwind]=wy[nwind]=wifrn[nwind]=wofrn[nwind]=0;

	if (wx[w] >= wlen[w]) wx[w] = 0;

	wmore[w] = wlen[w]-1;
	wmore[nwind]=wlen[nwind]-1;
	nwind++;
}


wprot(w,cp,n)
int w;
char *cp;
int n;
{
	char wbuf[10];
	
	int i;

	if (wmode[w] & MWAIT) return(n);
	
	for (i = 0; (i < n); i++) {
		switch(wstate[w]) {
			
		case MSNORM:
			switch(cp[i]) {
				
			case '':
				if (wy[w]) wy[w]--;
				break;
			case '':
				if (wx[w]) wx[w]--;
				break;
			case '':
				wy[w]++;
				break;
			case '
':
				wy[w]=0;
				break;
			case '':
				xgo(wx[w]+wbase[w],wy[w]);
				sputs("EOF");
				if (talkf) die(0);
				break;
			case '':
			case '\n':
				xgo(wx[w]+wbase[w],wy[w]);
				if (cp[i] == '\n'){
					clrl();
					mcol=0;
				}
				mline++;
				if ((cp[i] == '\n') && (mline <wlen[w]+wbase[w])) clrl();
				goto wscroll;
			case '':
				beep();
				break;
			case '':
				wx[w]=wy[w]=0;
				break;
			case '':
				wstate[w]=MSESC;
				break;
			case '':
				break;
			default:
				xgo(wx[w]+wbase[w],wy[w]);
				xputc(cp[i]);
wscroll:		if (mline>=wbase[w]+wlen[w]) {
					if((wmode[w]&MMORE)&& (++wmore[w] >= (wlen[w]))) {
						wmode[w] |= MWAIT;
						wx[w]=mline-wbase[w];
						wy[w]=mcol;
						return(n-i);
					}
					wroll(w);
				}
				wx[w]=mline-wbase[w];
				wy[w]=mcol;
			}
			break;
		case MSESC:
			switch(cp[i]) {
			
			case 'Y':
				while (wx[w] < wlen[w]) {
					xgo(wx[w]+wbase[w],0);
					clrl();
					wx[w]++;
				}
				wx[w]=wy[w]=0;
				break;
			case 'T':
				xgo(wx[w]+wbase[w],wy[w]);
				clrl();
				break;
			case '?':
				if (wofrn[w]) {
					sprintf(wbuf,">%c%c",wlen[w]+' ',SCRWID+' ');
					write(wofrn[w],wbuf,4);
				}
				break;
			case '=':
				wstate[w] = MSXWAIT;
				break;
			}
			if (wstate[w] == MSESC) wstate[w] = MSNORM;
			break;
		case MSXWAIT:
			wx[w] = cp[i]-040;
			if (wx[w] >= wlen[w]) wx[w]=0;
			wstate[w]= MSYWAIT;
			break;
		case MSYWAIT:
			wy[w] = cp[i]-040;
			wstate[w] = MSNORM;
		}
	}
	return(0);
}

/* TALK stuff */

char	desttty[20] = "/dev/";

alert(tty)
	char *tty;
{
	
	/* Alerts the destination tty of an incoming "talk" */
	FILE *ttyfile;

	strcat(desttty, tty);
	if ((ttyfile = fopen(desttty, "w")) == NULL) {
		return(0);
	}

	fprintf(ttyfile, "%cTALK2 FROM %s (%s)...\n%c",
			7, getenv("LOGNAME"), getenv("LOGTTY"), 7);
	fclose(ttyfile);
	return(1);
}


talk(cp)
char *cp;
{
	char infifo[100];
	char outfifo[100];
	char *ttyp;
	int owind;

	
	owind = nwind;
	wsplit(cwind);			/* two windows */
	wmode[cwind] = MVSEND;
	wmode[owind] = MVSEND+MOPENW;
	
/* Find other user's terminal */

	ttyp = findtty(cp);
	if (*ttyp == NULL) {
		prompt1("talk: user %s not logged on.\n", cp);
		return;
	}

	/* Check for existence of .talk fifos */

	sprintf(infifo, "%s/.talk", getenv("HOME"));
	sprintf(wrbuf[owind], "%s/.talk", homedir(cp));

	if (access(infifo, 04) != 0) {
		prompt1("Type mknod $HOME/.talk p and try again");
		return;
	}
	wifrn[cwind] = open(infifo,0+O_NDELAY);

	/* alert the destination terminal */

	if (!alert(ttyp)) {
		prompt1("talk: cant alert tty: /dev/%s.\n", ttyp);
	}
	cwind = owind;
	rx = wbase[cwind];
	ry = 0;
}
newin(cp)

register char *cp;
{
	if (cp) {
		if (wifrn[cwind]) close(wifrn[cwind]);
					
		wifrn[cwind] = open(cp,0+O_NDELAY);
		if (wifrn[cwind] < 0) prompt1("error code %d",errno);
	}
}