V9/jtools/src/sam/sam.c

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

#include "sam.h"
#include <setjmp.h>
#include <signal.h>

typedef struct Patlist{
	int	nalloc;
	int	nused;
	String	**ptr;
}Patlist;

uchar	genbuf[BLOCKSIZE];
char	*home;
int	io;
int	panicking;
int	rescuing;
Mod	modnum;
String	genstr;
String	rhs;
String	wd;
String	cmdstr;
int	intr();
int	rescue();
char	*getenv();
File	*current();
File	*tofile();
File	*getfile();
File	*curfile;
File	*flist;
File	*cmd;
jmp_buf	mainloop;
Filelist tempfile;
int	quitok=TRUE;
Patlist	globstr;
Patlist	pattern;
int	downloaded;
int	dflag;
int	Rflag;
int	zflag;
char	*machine;
int	dounlock;

main(argc, argv)
	uchar *argv[];
{
	register i;
	int (*onintr)();
	while(argc>1 && argv[1][0]=='-'){
		switch(argv[1][1]){
		case 'd':
			dflag++;
			break;
		case 'r':
			--argc, argv++;
			if(argc==1){
				dprint("usage: sam [-d] -r machine\n");
				return 1;
			}
			machine=(char *)argv[1];
			break;
		case 'z':
			zflag++;
			break;
		case 'R':
			Rflag++;
			break;
#ifdef SUN
		case 't':
		case 'x':
		case '=':
		case 'W':
			sunarg(&argv, &argc);
			break;
#endif
		default:
			dprint("sam: unknown flag %c\n", argv[1][1]);
			return 1;
		}
		--argc, argv++;
	}
	allocinit();
	Fstart();
	strinit(&cmdstr);
	strinit(&lastpat);
	strinit(&lastregexp);
	strinit(&genstr);
	strinit(&rhs);
	strinit(&wd);
	gcnew(tempfile.ptr, 0);
	strinit(&unixcmd);
	straddc(&unixcmd, '\0');
	home=getenv("HOME");
	if(home==0)
		home="/tmp";
	if(!dflag){
		if(machine)
#ifdef SUN
			connectboot(machine,zflag); /* doesn't return */
#else
			connectto(machine);
#endif
		if(!Rflag){
			if(!bootterm(zflag))
				return 1;
		}
		rawmode(1);
		if(machine)
			join();
		downloaded=1;
	}
	if(argc>1){
		for(i=1; i<argc; i++)
			if(!setjmp(mainloop)){
				strdup(&genstr, argv[i]);
				Fsetname(newfile());
			}
	}else if(!downloaded)
		newfile()->state=Clean;
	modnum++;
	onintr=signal(SIGINT, intr);
	if(onintr)
		signal(SIGINT, onintr);
	onintr=signal(SIGHUP, rescue);
	if(onintr)
		signal(SIGHUP, onintr);
	if(file.nused)
		current(file.ptr[0]);
	(void)setjmp(mainloop);
	cmdloop();
	trytoquit();	/* if we already q'ed, quitok will be TRUE */
	if(downloaded)
		rawmode(0);
	return 0;
}
panic(s)
	char *s;
{
	if(!panicking++ && !setjmp(mainloop)){
		dprint("sam: panic: %s\n", s);
		rescue();
	}
	abort();
}
rescue(){
	register i, nblank=0;
	register File *f;
	uchar buf[128];
	signal(SIGHUP, SIG_IGN);
	if(rescuing++)
		exit(1);
	io= -1;
	for(i=0; i<file.nused; i++){
		f=file.ptr[i];
		if(f==cmd || f->nbytes==0 || f->state!=Dirty)
			continue;
		if(io==-1){
			strcpy(buf, (uchar *)home);
			strcpy(buf+strlen(buf), (uchar *)"/sam.save");
			io=creat((char *)buf, 0777);
			if(io<0)
				return;
		}
		strcpy(buf, f->name.s);
		if(buf[0]==0)
			sprint(buf, "nameless.%d", nblank++);
		fprint(io, "/usr/jerq/lib/samsave '%s' $* <<'---%s'\n",
			(char *)buf, (char *)buf);
		addr.r.p1=0, addr.r.p2=f->nbytes;
		writeio(f);
		fprint(io, "\n---%s\n", (char *)buf);
	}
	if(panicking)
		abort();
	exit(0);
}
hiccough(s)
	char *s;
{
	if(rescuing)
		exit(1);
	if(s)
		dprint("%s\n", s);
	resetcmd();
	resetxec();
	compactok();
	if(io>0)
		close(io);
	if(undobuf->nbytes)
		Bdelete(undobuf, (Posn)0, undobuf->nbytes);
	update();
	if(curfile && curfile->state==Unread)
		curfile->state=Clean;
	dounlock=TRUE;
	if(downloaded && curfile && curfile->state!=Unread)
		outTs(Hcurrent, curfile->tag);
	longjmp(mainloop, 1);
}
intr(){
	signal(SIGINT, intr);
	error(Eintr);
}
trytoclose(f)
	register File *f;
{
	if(f==cmd)	/* possible? */
		return;
	if(f->state==Dirty && !f->closeok){
		f->closeok=TRUE;
		error_s(Emodified,
		    f->name.s[0]?(char *)f->name.s : "nameless file");
	}
	if(downloaded && f->rasp)
		outTs(Hclose, f->tag);
	delfile(f);
	if(f==curfile)
		current((File *)0);
}
trytoquit(){
	register c;
	register File *f;
	extern int eof;
	if(!quitok)
		for(c=0; c<file.nused; c++){
			f=file.ptr[c];
			if(f!=cmd && f->state==Dirty){
				quitok=TRUE;
				eof=FALSE;
				error(Echanges);
			}
		}
}
load(f)
	register File *f;
{
	Address saveaddr;
	strdupstr(&genstr, &f->name);
	filename(f);
	if(f->name.s[0]){
		saveaddr=addr;
		edit(f, 'I');
		addr=saveaddr;
	}else
		f->state=Clean;
	Fupdate(f, FALSE, TRUE);
}
update(){
	register i, anymod;
	register File *f;
	settempfile();
	for(anymod=i=0; i<tempfile.nused; i++){
		f=tempfile.ptr[i];
		if(f==cmd)	/* cmd gets done in main() */
			continue;
		if(f->mod==modnum && Fupdate(f, FALSE, downloaded))
			anymod++;
		if(f->rasp)
			telldot(f);
	}
	if(anymod)
		modnum++;
}
File *
current(f)
	register File *f;
{
	return curfile=f;
}
edit(f, cmd)
	register File *f;
{
	register empty=TRUE;
	Posn p;
	int nonascii;
	if(cmd=='r')
		Fdelete(f, addr.r.p1, addr.r.p2);
	if(cmd=='e' || cmd=='I'){
		Fdelete(f, (Posn)0, f->nbytes);
		addr.r.p2=f->nbytes;
	}else if(f->nbytes!=0 || (f->name.s[0] && strcmp(genstr.s, f->name.s)!=0))
		empty=FALSE;
	if((io=open((char *)genstr.s, 0))<0)
		error_s(Eopen, (char *)genstr.s);
	p=readio(f, &nonascii, empty);
	closeio((cmd=='e' || cmd=='I')? -1 : p);
	if(cmd=='r')
		f->dot.r.p1=addr.r.p2, f->dot.r.p2=addr.r.p2+p;
	else
		f->dot.r.p1=f->dot.r.p2=0;
	quitok=f->closeok=empty;
	state(f, empty && !nonascii? Clean : Dirty);
	if(cmd=='e')
		filename(f);
}
getname(f, s, save)
	register File *f;
	register String *s;
{
	register c, i;
	strzero(&genstr);
	if(s==0 || (c=s->s[0])==0){		/* no name provided */
		if(f)
			strdupstr(&genstr, &f->name);
		else
			straddc(&genstr, '\0');
		goto Return;
	}
	if(c!=' ' && c!='\t')
		error(Eblank);
	for(i=0; (c=s->s[i])==' ' || c=='\t'; i++)
		;
	while(s->s[i]>' ')
		straddc(&genstr, s->s[i++]);
	if(s->s[i])
		error(Enewline);
	straddc(&genstr, '\0');
	if(f && (save || f->name.s[0]==0)){
		Fsetname(f);
		if(strcmp(f->name.s, genstr.s)){
			quitok=f->closeok=FALSE;
			f->inumber=0;
			f->date=0;
			state(f, Dirty); /* if it's 'e', fix later */
		}
	}
    Return:
	return genstr.n-1;	/* strlen(name) */
}
filename(f)
	register File *f;
{
	dprint("%c%c%c %s\n", " '"[f->state==Dirty],
		"-+"[f->rasp!=0], " ."[f==curfile], genstr.s);
}
undo()
{
	register File *f;
	register i;
	Mod max;
	if((max=curfile->mod)==0)
		return;
	settempfile();
	for(i=0; i<tempfile.nused; i++){
		f=tempfile.ptr[i];
		if(f!=cmd && f->mod==max)
			undostep(f);
	}
}
undostep(f)
	register File *f;
{
	register Buffer *t;
	register changes;
	Mark mark;
	t=f->transcript;
	changes=Fupdate(f, TRUE, TRUE);
	Bread(t, (uchar *)&mark, sizeof mark, f->markp);
	Bdelete(t, f->markp, t->nbytes);
	f->markp=mark.p;
	f->dot.r=mark.dot;
	f->mark=mark.mark;
	f->mod=mark.m;
	f->closeok=mark.s1!=Dirty;
	if(mark.s1==Dirty)
		quitok=FALSE;
	if(f->state==Clean && mark.s1==Clean && changes)
		state(f, Dirty);
	else
		state(f, mark.s1);
}
cd(str)
	String *str;
{
	register i;
	register File *f;
	readcmd(tempstr((uchar *)"/bin/pwd", 9));
	strdupstr(&wd, &genstr);
	if(wd.s[0]==0){
		wd.n=0;
		warn(Wpwd);
	}else if(wd.s[wd.n-2]=='\n'){
		--wd.n;
		wd.s[wd.n-1]='/';
	}
	if(chdir(getname((File *)0, str, FALSE)? (char *)genstr.s : home))
		syserror("chdir");
	settempfile();
	for(i=0; i<tempfile.nused; i++){
		f=tempfile.ptr[i];
		if(f!=cmd && f->name.s[0]!='/' && f->name.s[0]!=0){
			strinsert(&f->name, &wd, (Posn)0);
			sortname(f);
		}
	}
}
readcmd(s)
	String *s;
{
	if(flist==0)
		(flist=Fopen())->state=Clean;
	addr.r.p1=0, addr.r.p2=flist->nbytes;
	Unix(flist, '<', s, FALSE);
	Fupdate(flist, FALSE, FALSE);
	flist->mod=0;
	strzero(&genstr);
	strinsure(&genstr, flist->nbytes);
	Fchars(flist, genstr.s, (Posn)0, flist->nbytes);
	genstr.n=flist->nbytes;
	straddc(&genstr, '\0');
}
loadflist(s)
	register String *s;
{
	register c, i;
	c=s->s[0];
	for(i=0; s->s[i]==' ' || s->s[i]=='\t'; i++)
		;
	if((c==' ' || c=='\t') && s->s[i]!='\n'){
		if(s->s[i]=='<'){
			strdelete(s, 0L, (long)i+1);
			readcmd(s);
		}else{
			strzero(&genstr);
			while((c=s->s[i++]) && c!='\n')
				straddc(&genstr, c);
			straddc(&genstr, '\0');
		}
	}else{
		if(c!='\n')
			error(Eblank);
		strdup(&genstr, (uchar *)"");
	}
	return genstr.s[0];
}
File *
readflist(readall, delete)
{
	register Posn i;
	register c;
	register File *f;
	for(i=0,f=0; f==0 || readall || delete; ){
		strdelete(&genstr, (Posn)0, i);
		for(i=0; (c=genstr.s[i])==' ' || c=='\t' || c=='\n'; i++)
			;
		if(i>=genstr.n)
			break;
		strdelete(&genstr, (Posn)0, i);
		for(i=0; (c=genstr.s[i]) && c!=' ' && c!='\t' && c!='\n'; i++)
			;
		if(i==0)
			break;
		genstr.s[i++]=0;
		f=lookfile();
		if(delete){
			if(f==0)
				warn_s(Wfile, (char *)genstr.s);
			else
				trytoclose(f);
		}else if(f==0 && readall)
			Fsetname(f=newfile());
	}
	return f;
}
File *
tofile(s)
	String *s;
{
	register File *f;
	if(s->s[0]!=' ')
		error(Eblank);
	if(loadflist(s)==0)
		f=lookfile();	/* empty string ==> nameless file */
	else if((f=readflist(FALSE, FALSE))==0)
		error_s(Emenu, (char *)genstr.s);
	return current(f);
}
File *
getfile(s)
	String *s;
{
	register File *f;
	if(loadflist(s)==0)
		Fsetname(f=newfile());
	else if((f=readflist(TRUE, FALSE))==0)
		error(Eblank);
	return current(f);
}
closefiles(f, s)
	File *f;
	register String *s;
{
	if(s->s[0]==0){
		if(f==0)
			error(Enofile);
		trytoclose(f);
		return;
	}
	if(s->s[0]!=' ')
		error(Eblank);
	if(loadflist(s)==0)
		error(Enewline);
	readflist(FALSE, TRUE);
}
move(f, addr2)
	register File *f;
	Address addr2;
{
	if(addr.r.p2<=addr2.r.p2){
		Fdelete(f, addr.r.p1, addr.r.p2);
		copy(f, addr2);
	}else if(addr.r.p1>=addr2.r.p2){
		copy(f, addr2);
		Fdelete(f, addr.r.p1, addr.r.p2);
	}else
		error(Eoverlap);
}
copy(f, addr2)
	register File *f;
	Address addr2;
{
	register Posn p;
	register ni;
	for(p=addr.r.p1; p<addr.r.p2; p+=ni){
		ni=addr.r.p2-p;
		if(ni>BLOCKSIZE)
			ni=BLOCKSIZE;
		Fchars(f, genbuf, p, p+ni);
		Finsert(addr2.f, tempstr(genbuf, ni), addr2.r.p2);
	}
	addr2.f->dot.r.p2=addr2.r.p2+(f->dot.r.p2-f->dot.r.p1);
	addr2.f->dot.r.p1=addr2.r.p2;
}
Posn
nlcount(f, p0, p1)
	register File *f;
	register Posn p0, p1;
{
	register Posn nl=0;
	Fgetcset(f, p0);
	while(p0++<p1)
		if(Fgetc(f)=='\n')
			nl++;
	return nl;
}
printposn(f, charsonly)
	register File *f;
{
	register Posn l1, l2;
	if(!charsonly){
		l1=1+nlcount(f, (Posn)0, addr.r.p1);
		l2=l1+nlcount(f, addr.r.p1, addr.r.p2);
		/* check if addr ends with '\n' */
		if(addr.r.p2>0 && addr.r.p2>addr.r.p1 && (Fgetcset(f, addr.r.p2-1),Fgetc(f)=='\n'))
			--l2;
		dprint("%lud", l1);
		if(l2!=l1)
			dprint(",%lud", l2);
		dprint("; ");
	}
	dprint("#%lud", addr.r.p1);
	if(addr.r.p2!=addr.r.p1)
		dprint(",#%lud", addr.r.p2);
	dprint("\n");
}
settempfile(){
	if(tempfile.nalloc<file.nused){
		gcfree((uchar *)tempfile.ptr);
		gcnew(tempfile.ptr, file.nused);
		tempfile.nalloc=file.nused;
	}
	tempfile.nused=file.nused;
	bcopy((uchar *)&file.ptr[0], (uchar *)&file.ptr[file.nused],
		(uchar *)&tempfile.ptr[0], 1);
}