xref: /plan9/sys/src/cmd/sam/sam.c (revision 73e742d79f6b0cfc24f3b01d7ade790955db63c2)
13e12c5d1SDavid du Colombier #include "sam.h"
23e12c5d1SDavid du Colombier 
33e12c5d1SDavid du Colombier Rune	genbuf[BLOCKSIZE];
43e12c5d1SDavid du Colombier int	io;
53e12c5d1SDavid du Colombier int	panicking;
63e12c5d1SDavid du Colombier int	rescuing;
73e12c5d1SDavid du Colombier String	genstr;
83e12c5d1SDavid du Colombier String	rhs;
97dd7cddfSDavid du Colombier String	curwd;
103e12c5d1SDavid du Colombier String	cmdstr;
113e12c5d1SDavid du Colombier Rune	empty[] = { 0 };
123e12c5d1SDavid du Colombier char	*genc;
133e12c5d1SDavid du Colombier File	*curfile;
143e12c5d1SDavid du Colombier File	*flist;
153e12c5d1SDavid du Colombier File	*cmd;
163e12c5d1SDavid du Colombier jmp_buf	mainloop;
17*73e742d7SDavid du Colombier List	tempfile = { 'p' };
183e12c5d1SDavid du Colombier int	quitok = TRUE;
193e12c5d1SDavid du Colombier int	downloaded;
203e12c5d1SDavid du Colombier int	dflag;
213e12c5d1SDavid du Colombier int	Rflag;
223e12c5d1SDavid du Colombier char	*machine;
233e12c5d1SDavid du Colombier char	*home;
243e12c5d1SDavid du Colombier int	bpipeok;
253e12c5d1SDavid du Colombier int	termlocked;
263e12c5d1SDavid du Colombier char	*samterm = SAMTERM;
273e12c5d1SDavid du Colombier char	*rsamname = RSAM;
287dd7cddfSDavid du Colombier File	*lastfile;
297dd7cddfSDavid du Colombier Disk	*disk;
307dd7cddfSDavid du Colombier long	seq;
313e12c5d1SDavid du Colombier 
32219b2ee8SDavid du Colombier Rune	baddir[] = { '<', 'b', 'a', 'd', 'd', 'i', 'r', '>', '\n'};
33219b2ee8SDavid du Colombier 
343e12c5d1SDavid du Colombier void	usage(void);
353e12c5d1SDavid du Colombier 
main(int argc,char * argv[])367dd7cddfSDavid du Colombier void main(int argc, char *argv[])
373e12c5d1SDavid du Colombier {
383e12c5d1SDavid du Colombier 	int i;
393e12c5d1SDavid du Colombier 	String *t;
40e7d29567SDavid du Colombier 	char *termargs[10], **ap;
413e12c5d1SDavid du Colombier 
42e7d29567SDavid du Colombier 	ap = termargs;
43e7d29567SDavid du Colombier 	*ap++ = "samterm";
44e7d29567SDavid du Colombier 	ARGBEGIN{
453e12c5d1SDavid du Colombier 	case 'd':
463e12c5d1SDavid du Colombier 		dflag++;
473e12c5d1SDavid du Colombier 		break;
483e12c5d1SDavid du Colombier 	case 'r':
49e7d29567SDavid du Colombier 		machine = EARGF(usage());
503e12c5d1SDavid du Colombier 		break;
513e12c5d1SDavid du Colombier 	case 'R':
523e12c5d1SDavid du Colombier 		Rflag++;
533e12c5d1SDavid du Colombier 		break;
543e12c5d1SDavid du Colombier 	case 't':
55e7d29567SDavid du Colombier 		samterm = EARGF(usage());
563e12c5d1SDavid du Colombier 		break;
573e12c5d1SDavid du Colombier 	case 's':
58e7d29567SDavid du Colombier 		rsamname = EARGF(usage());
593e12c5d1SDavid du Colombier 		break;
603e12c5d1SDavid du Colombier 	default:
61e7d29567SDavid du Colombier 		dprint("sam: unknown flag %c\n", ARGC());
62e7d29567SDavid du Colombier 		usage();
63e7d29567SDavid du Colombier 	/* options for samterm */
64e7d29567SDavid du Colombier 	case 'a':
65e7d29567SDavid du Colombier 		*ap++ = "-a";
66e7d29567SDavid du Colombier 		break;
67e7d29567SDavid du Colombier 	}ARGEND
68e7d29567SDavid du Colombier 	*ap = nil;
69e7d29567SDavid du Colombier 
703e12c5d1SDavid du Colombier 	Strinit(&cmdstr);
713e12c5d1SDavid du Colombier 	Strinit0(&lastpat);
723e12c5d1SDavid du Colombier 	Strinit0(&lastregexp);
733e12c5d1SDavid du Colombier 	Strinit0(&genstr);
743e12c5d1SDavid du Colombier 	Strinit0(&rhs);
757dd7cddfSDavid du Colombier 	Strinit0(&curwd);
763e12c5d1SDavid du Colombier 	Strinit0(&plan9cmd);
773e12c5d1SDavid du Colombier 	home = getenv(HOME);
787dd7cddfSDavid du Colombier 	disk = diskinit();
793e12c5d1SDavid du Colombier 	if(home == 0)
803e12c5d1SDavid du Colombier 		home = "/";
813e12c5d1SDavid du Colombier 	if(!dflag)
82e7d29567SDavid du Colombier 		startup(machine, Rflag, termargs, argv);
833e12c5d1SDavid du Colombier 	notify(notifyf);
847dd7cddfSDavid du Colombier 	getcurwd();
85e7d29567SDavid du Colombier 	if(argc>0){
86e7d29567SDavid du Colombier 		for(i=0; i<argc; i++){
873e12c5d1SDavid du Colombier 			if(!setjmp(mainloop)){
883e12c5d1SDavid du Colombier 				t = tmpcstr(argv[i]);
893e12c5d1SDavid du Colombier 				Straddc(t, '\0');
903e12c5d1SDavid du Colombier 				Strduplstr(&genstr, t);
913e12c5d1SDavid du Colombier 				freetmpstr(t);
927dd7cddfSDavid du Colombier 				fixname(&genstr);
937dd7cddfSDavid du Colombier 				logsetname(newfile(), &genstr);
947dd7cddfSDavid du Colombier 			}
953e12c5d1SDavid du Colombier 		}
963e12c5d1SDavid du Colombier 	}else if(!downloaded)
977dd7cddfSDavid du Colombier 		newfile();
987dd7cddfSDavid du Colombier 	seq++;
993e12c5d1SDavid du Colombier 	if(file.nused)
1003e12c5d1SDavid du Colombier 		current(file.filepptr[0]);
1013e12c5d1SDavid du Colombier 	setjmp(mainloop);
1023e12c5d1SDavid du Colombier 	cmdloop();
1033e12c5d1SDavid du Colombier 	trytoquit();	/* if we already q'ed, quitok will be TRUE */
1043e12c5d1SDavid du Colombier 	exits(0);
1053e12c5d1SDavid du Colombier }
1063e12c5d1SDavid du Colombier 
1073e12c5d1SDavid du Colombier void
usage(void)1083e12c5d1SDavid du Colombier usage(void)
1093e12c5d1SDavid du Colombier {
1103e12c5d1SDavid du Colombier 	dprint("usage: sam [-d] [-t samterm] [-s sam name] -r machine\n");
1113e12c5d1SDavid du Colombier 	exits("usage");
1123e12c5d1SDavid du Colombier }
1133e12c5d1SDavid du Colombier 
1143e12c5d1SDavid du Colombier void
rescue(void)1153e12c5d1SDavid du Colombier rescue(void)
1163e12c5d1SDavid du Colombier {
1173e12c5d1SDavid du Colombier 	int i, nblank = 0;
1183e12c5d1SDavid du Colombier 	File *f;
1193e12c5d1SDavid du Colombier 	char *c;
1203e12c5d1SDavid du Colombier 	char buf[256];
1213e12c5d1SDavid du Colombier 
1223e12c5d1SDavid du Colombier 	if(rescuing++)
1233e12c5d1SDavid du Colombier 		return;
1243e12c5d1SDavid du Colombier 	io = -1;
1253e12c5d1SDavid du Colombier 	for(i=0; i<file.nused; i++){
1263e12c5d1SDavid du Colombier 		f = file.filepptr[i];
1277dd7cddfSDavid du Colombier 		if(f==cmd || f->nc==0 || !fileisdirty(f))
1283e12c5d1SDavid du Colombier 			continue;
1293e12c5d1SDavid du Colombier 		if(io == -1){
1303e12c5d1SDavid du Colombier 			sprint(buf, "%s/sam.save", home);
1313e12c5d1SDavid du Colombier 			io = create(buf, 1, 0777);
1323e12c5d1SDavid du Colombier 			if(io<0)
1333e12c5d1SDavid du Colombier 				return;
1343e12c5d1SDavid du Colombier 		}
1353e12c5d1SDavid du Colombier 		if(f->name.s[0]){
1363e12c5d1SDavid du Colombier 			c = Strtoc(&f->name);
1373e12c5d1SDavid du Colombier 			strncpy(buf, c, sizeof buf-1);
1383e12c5d1SDavid du Colombier 			buf[sizeof buf-1] = 0;
1393e12c5d1SDavid du Colombier 			free(c);
1403e12c5d1SDavid du Colombier 		}else
1413e12c5d1SDavid du Colombier 			sprint(buf, "nameless.%d", nblank++);
142bd389b36SDavid du Colombier 		fprint(io, "#!%s '%s' $* <<'---%s'\n", SAMSAVECMD, buf, buf);
1437dd7cddfSDavid du Colombier 		addr.r.p1 = 0, addr.r.p2 = f->nc;
1443e12c5d1SDavid du Colombier 		writeio(f);
1453e12c5d1SDavid du Colombier 		fprint(io, "\n---%s\n", (char *)buf);
1463e12c5d1SDavid du Colombier 	}
1473e12c5d1SDavid du Colombier }
1483e12c5d1SDavid du Colombier 
1493e12c5d1SDavid du Colombier void
panic(char * s)1503e12c5d1SDavid du Colombier panic(char *s)
1513e12c5d1SDavid du Colombier {
1523e12c5d1SDavid du Colombier 	int wasd;
1533e12c5d1SDavid du Colombier 
1543e12c5d1SDavid du Colombier 	if(!panicking++ && !setjmp(mainloop)){
1553e12c5d1SDavid du Colombier 		wasd = downloaded;
1563e12c5d1SDavid du Colombier 		downloaded = 0;
1573e12c5d1SDavid du Colombier 		dprint("sam: panic: %s: %r\n", s);
1583e12c5d1SDavid du Colombier 		if(wasd)
1593e12c5d1SDavid du Colombier 			fprint(2, "sam: panic: %s: %r\n", s);
1603e12c5d1SDavid du Colombier 		rescue();
1613e12c5d1SDavid du Colombier 		abort();
1623e12c5d1SDavid du Colombier 	}
1633e12c5d1SDavid du Colombier }
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier void
hiccough(char * s)1663e12c5d1SDavid du Colombier hiccough(char *s)
1673e12c5d1SDavid du Colombier {
1687dd7cddfSDavid du Colombier 	File *f;
1697dd7cddfSDavid du Colombier 	int i;
1707dd7cddfSDavid du Colombier 
1713e12c5d1SDavid du Colombier 	if(rescuing)
1723e12c5d1SDavid du Colombier 		exits("rescue");
1733e12c5d1SDavid du Colombier 	if(s)
1743e12c5d1SDavid du Colombier 		dprint("%s\n", s);
1753e12c5d1SDavid du Colombier 	resetcmd();
1763e12c5d1SDavid du Colombier 	resetxec();
1773e12c5d1SDavid du Colombier 	resetsys();
1783e12c5d1SDavid du Colombier 	if(io > 0)
1793e12c5d1SDavid du Colombier 		close(io);
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 	/*
1827dd7cddfSDavid du Colombier 	 * back out any logged changes & restore old sequences
1837dd7cddfSDavid du Colombier 	 */
1847dd7cddfSDavid du Colombier 	for(i=0; i<file.nused; i++){
1857dd7cddfSDavid du Colombier 		f = file.filepptr[i];
1867dd7cddfSDavid du Colombier 		if(f==cmd)
1877dd7cddfSDavid du Colombier 			continue;
1887dd7cddfSDavid du Colombier 		if(f->seq==seq){
1897dd7cddfSDavid du Colombier 			bufdelete(&f->epsilon, 0, f->epsilon.nc);
1907dd7cddfSDavid du Colombier 			f->seq = f->prevseq;
1917dd7cddfSDavid du Colombier 			f->dot.r = f->prevdot;
1927dd7cddfSDavid du Colombier 			f->mark = f->prevmark;
1937dd7cddfSDavid du Colombier 			state(f, f->prevmod ? Dirty: Clean);
1947dd7cddfSDavid du Colombier 		}
1957dd7cddfSDavid du Colombier 	}
1967dd7cddfSDavid du Colombier 
1973e12c5d1SDavid du Colombier 	update();
198219b2ee8SDavid du Colombier 	if (curfile) {
1997dd7cddfSDavid du Colombier 		if (curfile->unread)
2007dd7cddfSDavid du Colombier 			curfile->unread = FALSE;
201219b2ee8SDavid du Colombier 		else if (downloaded)
2023e12c5d1SDavid du Colombier 			outTs(Hcurrent, curfile->tag);
203219b2ee8SDavid du Colombier 	}
2043e12c5d1SDavid du Colombier 	longjmp(mainloop, 1);
2053e12c5d1SDavid du Colombier }
2063e12c5d1SDavid du Colombier 
2073e12c5d1SDavid du Colombier void
intr(void)2083e12c5d1SDavid du Colombier intr(void)
2093e12c5d1SDavid du Colombier {
2103e12c5d1SDavid du Colombier 	error(Eintr);
2113e12c5d1SDavid du Colombier }
2123e12c5d1SDavid du Colombier 
2133e12c5d1SDavid du Colombier void
trytoclose(File * f)2143e12c5d1SDavid du Colombier trytoclose(File *f)
2153e12c5d1SDavid du Colombier {
2163e12c5d1SDavid du Colombier 	char *t;
217219b2ee8SDavid du Colombier 	char buf[256];
2183e12c5d1SDavid du Colombier 
2193e12c5d1SDavid du Colombier 	if(f == cmd)	/* possible? */
2203e12c5d1SDavid du Colombier 		return;
221219b2ee8SDavid du Colombier 	if(f->deleted)
222219b2ee8SDavid du Colombier 		return;
2237dd7cddfSDavid du Colombier 	if(fileisdirty(f) && !f->closeok){
2243e12c5d1SDavid du Colombier 		f->closeok = TRUE;
2253e12c5d1SDavid du Colombier 		if(f->name.s[0]){
2263e12c5d1SDavid du Colombier 			t = Strtoc(&f->name);
227219b2ee8SDavid du Colombier 			strncpy(buf, t, sizeof buf-1);
2283e12c5d1SDavid du Colombier 			free(t);
2293e12c5d1SDavid du Colombier 		}else
230219b2ee8SDavid du Colombier 			strcpy(buf, "nameless file");
231219b2ee8SDavid du Colombier 		error_s(Emodified, buf);
2323e12c5d1SDavid du Colombier 	}
233219b2ee8SDavid du Colombier 	f->deleted = TRUE;
2343e12c5d1SDavid du Colombier }
2353e12c5d1SDavid du Colombier 
2363e12c5d1SDavid du Colombier void
trytoquit(void)2373e12c5d1SDavid du Colombier trytoquit(void)
2383e12c5d1SDavid du Colombier {
2393e12c5d1SDavid du Colombier 	int c;
2403e12c5d1SDavid du Colombier 	File *f;
2413e12c5d1SDavid du Colombier 
2427dd7cddfSDavid du Colombier 	if(!quitok){
2433e12c5d1SDavid du Colombier 		for(c = 0; c<file.nused; c++){
2443e12c5d1SDavid du Colombier 			f = file.filepptr[c];
2457dd7cddfSDavid du Colombier 			if(f!=cmd && fileisdirty(f)){
2463e12c5d1SDavid du Colombier 				quitok = TRUE;
2473e12c5d1SDavid du Colombier 				eof = FALSE;
2483e12c5d1SDavid du Colombier 				error(Echanges);
2493e12c5d1SDavid du Colombier 			}
2503e12c5d1SDavid du Colombier 		}
2513e12c5d1SDavid du Colombier 	}
252219b2ee8SDavid du Colombier }
2533e12c5d1SDavid du Colombier 
2543e12c5d1SDavid du Colombier void
load(File * f)2553e12c5d1SDavid du Colombier load(File *f)
2563e12c5d1SDavid du Colombier {
2573e12c5d1SDavid du Colombier 	Address saveaddr;
2583e12c5d1SDavid du Colombier 
2593e12c5d1SDavid du Colombier 	Strduplstr(&genstr, &f->name);
2603e12c5d1SDavid du Colombier 	filename(f);
2613e12c5d1SDavid du Colombier 	if(f->name.s[0]){
2623e12c5d1SDavid du Colombier 		saveaddr = addr;
2633e12c5d1SDavid du Colombier 		edit(f, 'I');
2643e12c5d1SDavid du Colombier 		addr = saveaddr;
2657dd7cddfSDavid du Colombier 	}else{
2667dd7cddfSDavid du Colombier 		f->unread = 0;
2677dd7cddfSDavid du Colombier 		f->cleanseq = f->seq;
2687dd7cddfSDavid du Colombier 	}
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier 	fileupdate(f, TRUE, TRUE);
2713e12c5d1SDavid du Colombier }
2723e12c5d1SDavid du Colombier 
2733e12c5d1SDavid du Colombier void
cmdupdate(void)2743e12c5d1SDavid du Colombier cmdupdate(void)
2753e12c5d1SDavid du Colombier {
2767dd7cddfSDavid du Colombier 	if(cmd && cmd->seq!=0){
2777dd7cddfSDavid du Colombier 		fileupdate(cmd, FALSE, downloaded);
2787dd7cddfSDavid du Colombier 		cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->nc;
2793e12c5d1SDavid du Colombier 		telldot(cmd);
2803e12c5d1SDavid du Colombier 	}
2813e12c5d1SDavid du Colombier }
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier void
delete(File * f)284219b2ee8SDavid du Colombier delete(File *f)
285219b2ee8SDavid du Colombier {
286219b2ee8SDavid du Colombier 	if(downloaded && f->rasp)
287219b2ee8SDavid du Colombier 		outTs(Hclose, f->tag);
288219b2ee8SDavid du Colombier 	delfile(f);
289219b2ee8SDavid du Colombier 	if(f == curfile)
290219b2ee8SDavid du Colombier 		current(0);
291219b2ee8SDavid du Colombier }
292219b2ee8SDavid du Colombier 
293219b2ee8SDavid du Colombier void
update(void)2943e12c5d1SDavid du Colombier update(void)
2953e12c5d1SDavid du Colombier {
2963e12c5d1SDavid du Colombier 	int i, anymod;
2973e12c5d1SDavid du Colombier 	File *f;
2983e12c5d1SDavid du Colombier 
2993e12c5d1SDavid du Colombier 	settempfile();
3003e12c5d1SDavid du Colombier 	for(anymod = i=0; i<tempfile.nused; i++){
3013e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
3023e12c5d1SDavid du Colombier 		if(f==cmd)	/* cmd gets done in main() */
3033e12c5d1SDavid du Colombier 			continue;
3047dd7cddfSDavid du Colombier 		if(f->deleted) {
305219b2ee8SDavid du Colombier 			delete(f);
3067dd7cddfSDavid du Colombier 			continue;
3077dd7cddfSDavid du Colombier 		}
3087dd7cddfSDavid du Colombier 		if(f->seq==seq && fileupdate(f, FALSE, downloaded))
3093e12c5d1SDavid du Colombier 			anymod++;
3103e12c5d1SDavid du Colombier 		if(f->rasp)
3113e12c5d1SDavid du Colombier 			telldot(f);
3123e12c5d1SDavid du Colombier 	}
3133e12c5d1SDavid du Colombier 	if(anymod)
3147dd7cddfSDavid du Colombier 		seq++;
3153e12c5d1SDavid du Colombier }
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier File *
current(File * f)3183e12c5d1SDavid du Colombier current(File *f)
3193e12c5d1SDavid du Colombier {
3203e12c5d1SDavid du Colombier 	return curfile = f;
3213e12c5d1SDavid du Colombier }
3223e12c5d1SDavid du Colombier 
3233e12c5d1SDavid du Colombier void
edit(File * f,int cmd)3243e12c5d1SDavid du Colombier edit(File *f, int cmd)
3253e12c5d1SDavid du Colombier {
3263e12c5d1SDavid du Colombier 	int empty = TRUE;
3273e12c5d1SDavid du Colombier 	Posn p;
3283e12c5d1SDavid du Colombier 	int nulls;
3293e12c5d1SDavid du Colombier 
3303e12c5d1SDavid du Colombier 	if(cmd == 'r')
3317dd7cddfSDavid du Colombier 		logdelete(f, addr.r.p1, addr.r.p2);
3323e12c5d1SDavid du Colombier 	if(cmd=='e' || cmd=='I'){
3337dd7cddfSDavid du Colombier 		logdelete(f, (Posn)0, f->nc);
3347dd7cddfSDavid du Colombier 		addr.r.p2 = f->nc;
3357dd7cddfSDavid du Colombier 	}else if(f->nc!=0 || (f->name.s[0] && Strcmp(&genstr, &f->name)!=0))
3363e12c5d1SDavid du Colombier 		empty = FALSE;
337219b2ee8SDavid du Colombier 	if((io = open(genc, OREAD))<0) {
3387dd7cddfSDavid du Colombier 		if (curfile && curfile->unread)
3397dd7cddfSDavid du Colombier 			curfile->unread = FALSE;
3409a747e4fSDavid du Colombier 		error_r(Eopen, genc);
341219b2ee8SDavid du Colombier 	}
3427dd7cddfSDavid du Colombier 	p = readio(f, &nulls, empty, TRUE);
3433e12c5d1SDavid du Colombier 	closeio((cmd=='e' || cmd=='I')? -1 : p);
3443e12c5d1SDavid du Colombier 	if(cmd == 'r')
3453e12c5d1SDavid du Colombier 		f->ndot.r.p1 = addr.r.p2, f->ndot.r.p2 = addr.r.p2+p;
3463e12c5d1SDavid du Colombier 	else
3473e12c5d1SDavid du Colombier 		f->ndot.r.p1 = f->ndot.r.p2 = 0;
348219b2ee8SDavid du Colombier 	f->closeok = empty;
349219b2ee8SDavid du Colombier 	if (quitok)
350219b2ee8SDavid du Colombier 		quitok = empty;
351219b2ee8SDavid du Colombier 	else
352219b2ee8SDavid du Colombier 		quitok = FALSE;
3533e12c5d1SDavid du Colombier 	state(f, empty && !nulls? Clean : Dirty);
3547dd7cddfSDavid du Colombier 	if(empty && !nulls)
3557dd7cddfSDavid du Colombier 		f->cleanseq = f->seq;
3563e12c5d1SDavid du Colombier 	if(cmd == 'e')
3573e12c5d1SDavid du Colombier 		filename(f);
3583e12c5d1SDavid du Colombier }
3593e12c5d1SDavid du Colombier 
3603e12c5d1SDavid du Colombier int
getname(File * f,String * s,int save)3613e12c5d1SDavid du Colombier getname(File *f, String *s, int save)
3623e12c5d1SDavid du Colombier {
3633e12c5d1SDavid du Colombier 	int c, i;
3643e12c5d1SDavid du Colombier 
3653e12c5d1SDavid du Colombier 	Strzero(&genstr);
3663e12c5d1SDavid du Colombier 	if(genc){
3673e12c5d1SDavid du Colombier 		free(genc);
3683e12c5d1SDavid du Colombier 		genc = 0;
3693e12c5d1SDavid du Colombier 	}
3703e12c5d1SDavid du Colombier 	if(s==0 || (c = s->s[0])==0){		/* no name provided */
3713e12c5d1SDavid du Colombier 		if(f)
3723e12c5d1SDavid du Colombier 			Strduplstr(&genstr, &f->name);
3733e12c5d1SDavid du Colombier 		goto Return;
3743e12c5d1SDavid du Colombier 	}
3753e12c5d1SDavid du Colombier 	if(c!=' ' && c!='\t')
3763e12c5d1SDavid du Colombier 		error(Eblank);
3773e12c5d1SDavid du Colombier 	for(i=0; (c=s->s[i])==' ' || c=='\t'; i++)
3783e12c5d1SDavid du Colombier 		;
3793e12c5d1SDavid du Colombier 	while(s->s[i] > ' ')
3803e12c5d1SDavid du Colombier 		Straddc(&genstr, s->s[i++]);
3813e12c5d1SDavid du Colombier 	if(s->s[i])
3823e12c5d1SDavid du Colombier 		error(Enewline);
3837dd7cddfSDavid du Colombier 	fixname(&genstr);
3843e12c5d1SDavid du Colombier 	if(f && (save || f->name.s[0]==0)){
3857dd7cddfSDavid du Colombier 		logsetname(f, &genstr);
3863e12c5d1SDavid du Colombier 		if(Strcmp(&f->name, &genstr)){
3873e12c5d1SDavid du Colombier 			quitok = f->closeok = FALSE;
3887dd7cddfSDavid du Colombier 			f->qidpath = 0;
3897dd7cddfSDavid du Colombier 			f->mtime = 0;
3903e12c5d1SDavid du Colombier 			state(f, Dirty); /* if it's 'e', fix later */
3913e12c5d1SDavid du Colombier 		}
3923e12c5d1SDavid du Colombier 	}
3933e12c5d1SDavid du Colombier     Return:
3943e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
3957dd7cddfSDavid du Colombier 	i = genstr.n;
3967dd7cddfSDavid du Colombier 	if(i && genstr.s[i-1]==0)
3977dd7cddfSDavid du Colombier 		i--;
3987dd7cddfSDavid du Colombier 	return i;	/* strlen(name) */
3993e12c5d1SDavid du Colombier }
4003e12c5d1SDavid du Colombier 
4013e12c5d1SDavid du Colombier void
filename(File * f)4023e12c5d1SDavid du Colombier filename(File *f)
4033e12c5d1SDavid du Colombier {
4043e12c5d1SDavid du Colombier 	if(genc)
4053e12c5d1SDavid du Colombier 		free(genc);
4063e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
4077dd7cddfSDavid du Colombier 	dprint("%c%c%c %s\n", " '"[f->mod],
4083e12c5d1SDavid du Colombier 		"-+"[f->rasp!=0], " ."[f==curfile], genc);
4093e12c5d1SDavid du Colombier }
4103e12c5d1SDavid du Colombier 
4113e12c5d1SDavid du Colombier void
undostep(File * f,int isundo)4127dd7cddfSDavid du Colombier undostep(File *f, int isundo)
4133e12c5d1SDavid du Colombier {
4147dd7cddfSDavid du Colombier 	uint p1, p2;
4157dd7cddfSDavid du Colombier 	int mod;
4163e12c5d1SDavid du Colombier 
4177dd7cddfSDavid du Colombier 	mod = f->mod;
4187dd7cddfSDavid du Colombier 	fileundo(f, isundo, 1, &p1, &p2, TRUE);
4197dd7cddfSDavid du Colombier 	f->ndot = f->dot;
4207dd7cddfSDavid du Colombier 	if(f->mod){
4217dd7cddfSDavid du Colombier 		f->closeok = 0;
4227dd7cddfSDavid du Colombier 		quitok = 0;
4237dd7cddfSDavid du Colombier 	}else
4247dd7cddfSDavid du Colombier 		f->closeok = 1;
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 	if(f->mod != mod){
4277dd7cddfSDavid du Colombier 		f->mod = mod;
4287dd7cddfSDavid du Colombier 		if(mod)
4297dd7cddfSDavid du Colombier 			mod = Clean;
4303e12c5d1SDavid du Colombier 		else
4317dd7cddfSDavid du Colombier 			mod = Dirty;
4327dd7cddfSDavid du Colombier 		state(f, mod);
4337dd7cddfSDavid du Colombier 	}
4343e12c5d1SDavid du Colombier }
4353e12c5d1SDavid du Colombier 
436bd389b36SDavid du Colombier int
undo(int isundo)4377dd7cddfSDavid du Colombier undo(int isundo)
4383e12c5d1SDavid du Colombier {
4393e12c5d1SDavid du Colombier 	File *f;
4403e12c5d1SDavid du Colombier 	int i;
4413e12c5d1SDavid du Colombier 	Mod max;
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier 	max = undoseq(curfile, isundo);
4447dd7cddfSDavid du Colombier 	if(max == 0)
445bd389b36SDavid du Colombier 		return 0;
4463e12c5d1SDavid du Colombier 	settempfile();
4473e12c5d1SDavid du Colombier 	for(i = 0; i<tempfile.nused; i++){
4483e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
4497dd7cddfSDavid du Colombier 		if(f!=cmd && undoseq(f, isundo)==max)
4507dd7cddfSDavid du Colombier 			undostep(f, isundo);
4513e12c5d1SDavid du Colombier 	}
452bd389b36SDavid du Colombier 	return 1;
4533e12c5d1SDavid du Colombier }
4543e12c5d1SDavid du Colombier 
455219b2ee8SDavid du Colombier int
readcmd(String * s)4563e12c5d1SDavid du Colombier readcmd(String *s)
4573e12c5d1SDavid du Colombier {
458219b2ee8SDavid du Colombier 	int retcode;
459219b2ee8SDavid du Colombier 
4607dd7cddfSDavid du Colombier 	if(flist != 0)
4617dd7cddfSDavid du Colombier 		fileclose(flist);
4627dd7cddfSDavid du Colombier 	flist = fileopen();
4637dd7cddfSDavid du Colombier 
4647dd7cddfSDavid du Colombier 	addr.r.p1 = 0, addr.r.p2 = flist->nc;
465219b2ee8SDavid du Colombier 	retcode = plan9(flist, '<', s, FALSE);
4667dd7cddfSDavid du Colombier 	fileupdate(flist, FALSE, FALSE);
4677dd7cddfSDavid du Colombier 	flist->seq = 0;
4687dd7cddfSDavid du Colombier 	if (flist->nc > BLOCKSIZE)
469bd389b36SDavid du Colombier 		error(Etoolong);
4703e12c5d1SDavid du Colombier 	Strzero(&genstr);
4717dd7cddfSDavid du Colombier 	Strinsure(&genstr, flist->nc);
4727dd7cddfSDavid du Colombier 	bufread(flist, (Posn)0, genbuf, flist->nc);
4737dd7cddfSDavid du Colombier 	memmove(genstr.s, genbuf, flist->nc*RUNESIZE);
4747dd7cddfSDavid du Colombier 	genstr.n = flist->nc;
4753e12c5d1SDavid du Colombier 	Straddc(&genstr, '\0');
476219b2ee8SDavid du Colombier 	return retcode;
4773e12c5d1SDavid du Colombier }
4783e12c5d1SDavid du Colombier 
4793e12c5d1SDavid du Colombier void
getcurwd(void)4807dd7cddfSDavid du Colombier getcurwd(void)
4817dd7cddfSDavid du Colombier {
4827dd7cddfSDavid du Colombier 	String *t;
4837dd7cddfSDavid du Colombier 	char buf[256];
4847dd7cddfSDavid du Colombier 
4857dd7cddfSDavid du Colombier 	buf[0] = 0;
4867dd7cddfSDavid du Colombier 	getwd(buf, sizeof(buf));
4877dd7cddfSDavid du Colombier 	t = tmpcstr(buf);
4887dd7cddfSDavid du Colombier 	Strduplstr(&curwd, t);
4897dd7cddfSDavid du Colombier 	freetmpstr(t);
4907dd7cddfSDavid du Colombier 	if(curwd.n == 0)
4917dd7cddfSDavid du Colombier 		warn(Wpwd);
4927dd7cddfSDavid du Colombier 	else if(curwd.s[curwd.n-1] != '/')
4937dd7cddfSDavid du Colombier 		Straddc(&curwd, '/');
4947dd7cddfSDavid du Colombier }
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier void
cd(String * str)4973e12c5d1SDavid du Colombier cd(String *str)
4983e12c5d1SDavid du Colombier {
4997dd7cddfSDavid du Colombier 	int i, fd;
5007dd7cddfSDavid du Colombier 	char *s;
5013e12c5d1SDavid du Colombier 	File *f;
5027dd7cddfSDavid du Colombier 	String owd;
5033e12c5d1SDavid du Colombier 
5047dd7cddfSDavid du Colombier 	getcurwd();
5057dd7cddfSDavid du Colombier 	if(getname((File *)0, str, FALSE))
5067dd7cddfSDavid du Colombier 		s = genc;
5077dd7cddfSDavid du Colombier 	else
5087dd7cddfSDavid du Colombier 		s = home;
5097dd7cddfSDavid du Colombier 	if(chdir(s))
5103e12c5d1SDavid du Colombier 		syserror("chdir");
5117dd7cddfSDavid du Colombier 	fd = open("/dev/wdir", OWRITE);
5127dd7cddfSDavid du Colombier 	if(fd > 0)
5137dd7cddfSDavid du Colombier 		write(fd, s, strlen(s));
5147dd7cddfSDavid du Colombier 	dprint("!\n");
5157dd7cddfSDavid du Colombier 	Strinit(&owd);
5167dd7cddfSDavid du Colombier 	Strduplstr(&owd, &curwd);
5177dd7cddfSDavid du Colombier 	getcurwd();
5183e12c5d1SDavid du Colombier 	settempfile();
5193e12c5d1SDavid du Colombier 	for(i=0; i<tempfile.nused; i++){
5203e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
5213e12c5d1SDavid du Colombier 		if(f!=cmd && f->name.s[0]!='/' && f->name.s[0]!=0){
5227dd7cddfSDavid du Colombier 			Strinsert(&f->name, &owd, (Posn)0);
5237dd7cddfSDavid du Colombier 			fixname(&f->name);
5247dd7cddfSDavid du Colombier 			sortname(f);
5257dd7cddfSDavid du Colombier 		}else if(f != cmd && Strispre(&curwd, &f->name)){
5267dd7cddfSDavid du Colombier 			fixname(&f->name);
5273e12c5d1SDavid du Colombier 			sortname(f);
5283e12c5d1SDavid du Colombier 		}
5293e12c5d1SDavid du Colombier 	}
5307dd7cddfSDavid du Colombier 	Strclose(&owd);
5313e12c5d1SDavid du Colombier }
5323e12c5d1SDavid du Colombier 
5333e12c5d1SDavid du Colombier int
loadflist(String * s)5343e12c5d1SDavid du Colombier loadflist(String *s)
5353e12c5d1SDavid du Colombier {
5363e12c5d1SDavid du Colombier 	int c, i;
5373e12c5d1SDavid du Colombier 
5383e12c5d1SDavid du Colombier 	c = s->s[0];
5393e12c5d1SDavid du Colombier 	for(i = 0; s->s[i]==' ' || s->s[i]=='\t'; i++)
5403e12c5d1SDavid du Colombier 		;
5413e12c5d1SDavid du Colombier 	if((c==' ' || c=='\t') && s->s[i]!='\n'){
5423e12c5d1SDavid du Colombier 		if(s->s[i]=='<'){
5433e12c5d1SDavid du Colombier 			Strdelete(s, 0L, (long)i+1);
5443e12c5d1SDavid du Colombier 			readcmd(s);
5453e12c5d1SDavid du Colombier 		}else{
5463e12c5d1SDavid du Colombier 			Strzero(&genstr);
5473e12c5d1SDavid du Colombier 			while((c = s->s[i++]) && c!='\n')
5483e12c5d1SDavid du Colombier 				Straddc(&genstr, c);
5493e12c5d1SDavid du Colombier 			Straddc(&genstr, '\0');
5503e12c5d1SDavid du Colombier 		}
5513e12c5d1SDavid du Colombier 	}else{
5523e12c5d1SDavid du Colombier 		if(c != '\n')
5533e12c5d1SDavid du Colombier 			error(Eblank);
5543e12c5d1SDavid du Colombier 		Strdupl(&genstr, empty);
5553e12c5d1SDavid du Colombier 	}
5563e12c5d1SDavid du Colombier 	if(genc)
5573e12c5d1SDavid du Colombier 		free(genc);
5583e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
5593e12c5d1SDavid du Colombier 	return genstr.s[0];
5603e12c5d1SDavid du Colombier }
5613e12c5d1SDavid du Colombier 
5623e12c5d1SDavid du Colombier File *
readflist(int readall,int delete)5633e12c5d1SDavid du Colombier readflist(int readall, int delete)
5643e12c5d1SDavid du Colombier {
5653e12c5d1SDavid du Colombier 	Posn i;
5663e12c5d1SDavid du Colombier 	int c;
5673e12c5d1SDavid du Colombier 	File *f;
5687dd7cddfSDavid du Colombier 	String t;
5693e12c5d1SDavid du Colombier 
5707dd7cddfSDavid du Colombier 	Strinit(&t);
5713e12c5d1SDavid du Colombier 	for(i=0,f=0; f==0 || readall || delete; i++){	/* ++ skips blank */
5723e12c5d1SDavid du Colombier 		Strdelete(&genstr, (Posn)0, i);
5733e12c5d1SDavid du Colombier 		for(i=0; (c = genstr.s[i])==' ' || c=='\t' || c=='\n'; i++)
5743e12c5d1SDavid du Colombier 			;
5753e12c5d1SDavid du Colombier 		if(i >= genstr.n)
5763e12c5d1SDavid du Colombier 			break;
5773e12c5d1SDavid du Colombier 		Strdelete(&genstr, (Posn)0, i);
5783e12c5d1SDavid du Colombier 		for(i=0; (c=genstr.s[i]) && c!=' ' && c!='\t' && c!='\n'; i++)
5793e12c5d1SDavid du Colombier 			;
5803e12c5d1SDavid du Colombier 
5813e12c5d1SDavid du Colombier 		if(i == 0)
5823e12c5d1SDavid du Colombier 			break;
5833e12c5d1SDavid du Colombier 		genstr.s[i] = 0;
5847dd7cddfSDavid du Colombier 		Strduplstr(&t, tmprstr(genstr.s, i+1));
5857dd7cddfSDavid du Colombier 		fixname(&t);
5867dd7cddfSDavid du Colombier 		f = lookfile(&t);
5873e12c5d1SDavid du Colombier 		if(delete){
5883e12c5d1SDavid du Colombier 			if(f == 0)
5897dd7cddfSDavid du Colombier 				warn_S(Wfile, &t);
5903e12c5d1SDavid du Colombier 			else
5913e12c5d1SDavid du Colombier 				trytoclose(f);
5923e12c5d1SDavid du Colombier 		}else if(f==0 && readall)
5937dd7cddfSDavid du Colombier 			logsetname(f = newfile(), &t);
5943e12c5d1SDavid du Colombier 	}
5957dd7cddfSDavid du Colombier 	Strclose(&t);
5963e12c5d1SDavid du Colombier 	return f;
5973e12c5d1SDavid du Colombier }
5983e12c5d1SDavid du Colombier 
5993e12c5d1SDavid du Colombier File *
tofile(String * s)6003e12c5d1SDavid du Colombier tofile(String *s)
6013e12c5d1SDavid du Colombier {
6023e12c5d1SDavid du Colombier 	File *f;
6033e12c5d1SDavid du Colombier 
6043e12c5d1SDavid du Colombier 	if(s->s[0] != ' ')
6053e12c5d1SDavid du Colombier 		error(Eblank);
6063e12c5d1SDavid du Colombier 	if(loadflist(s) == 0){
6073e12c5d1SDavid du Colombier 		f = lookfile(&genstr);	/* empty string ==> nameless file */
6083e12c5d1SDavid du Colombier 		if(f == 0)
6093e12c5d1SDavid du Colombier 			error_s(Emenu, genc);
6103e12c5d1SDavid du Colombier 	}else if((f=readflist(FALSE, FALSE)) == 0)
6113e12c5d1SDavid du Colombier 		error_s(Emenu, genc);
6123e12c5d1SDavid du Colombier 	return current(f);
6133e12c5d1SDavid du Colombier }
6143e12c5d1SDavid du Colombier 
6153e12c5d1SDavid du Colombier File *
getfile(String * s)6163e12c5d1SDavid du Colombier getfile(String *s)
6173e12c5d1SDavid du Colombier {
6183e12c5d1SDavid du Colombier 	File *f;
6193e12c5d1SDavid du Colombier 
6203e12c5d1SDavid du Colombier 	if(loadflist(s) == 0)
6217dd7cddfSDavid du Colombier 		logsetname(f = newfile(), &genstr);
6223e12c5d1SDavid du Colombier 	else if((f=readflist(TRUE, FALSE)) == 0)
6233e12c5d1SDavid du Colombier 		error(Eblank);
6243e12c5d1SDavid du Colombier 	return current(f);
6253e12c5d1SDavid du Colombier }
6263e12c5d1SDavid du Colombier 
6273e12c5d1SDavid du Colombier void
closefiles(File * f,String * s)6283e12c5d1SDavid du Colombier closefiles(File *f, String *s)
6293e12c5d1SDavid du Colombier {
6303e12c5d1SDavid du Colombier 	if(s->s[0] == 0){
6313e12c5d1SDavid du Colombier 		if(f == 0)
6323e12c5d1SDavid du Colombier 			error(Enofile);
6333e12c5d1SDavid du Colombier 		trytoclose(f);
6343e12c5d1SDavid du Colombier 		return;
6353e12c5d1SDavid du Colombier 	}
6363e12c5d1SDavid du Colombier 	if(s->s[0] != ' ')
6373e12c5d1SDavid du Colombier 		error(Eblank);
6383e12c5d1SDavid du Colombier 	if(loadflist(s) == 0)
6393e12c5d1SDavid du Colombier 		error(Enewline);
6403e12c5d1SDavid du Colombier 	readflist(FALSE, TRUE);
6413e12c5d1SDavid du Colombier }
6423e12c5d1SDavid du Colombier 
6433e12c5d1SDavid du Colombier void
copy(File * f,Address addr2)6443e12c5d1SDavid du Colombier copy(File *f, Address addr2)
6453e12c5d1SDavid du Colombier {
6463e12c5d1SDavid du Colombier 	Posn p;
6473e12c5d1SDavid du Colombier 	int ni;
6483e12c5d1SDavid du Colombier 	for(p=addr.r.p1; p<addr.r.p2; p+=ni){
6493e12c5d1SDavid du Colombier 		ni = addr.r.p2-p;
6503e12c5d1SDavid du Colombier 		if(ni > BLOCKSIZE)
6513e12c5d1SDavid du Colombier 			ni = BLOCKSIZE;
6527dd7cddfSDavid du Colombier 		bufread(f, p, genbuf, ni);
6537dd7cddfSDavid du Colombier 		loginsert(addr2.f, addr2.r.p2, tmprstr(genbuf, ni)->s, ni);
6543e12c5d1SDavid du Colombier 	}
6553e12c5d1SDavid du Colombier 	addr2.f->ndot.r.p2 = addr2.r.p2+(f->dot.r.p2-f->dot.r.p1);
6563e12c5d1SDavid du Colombier 	addr2.f->ndot.r.p1 = addr2.r.p2;
6573e12c5d1SDavid du Colombier }
6583e12c5d1SDavid du Colombier 
6593e12c5d1SDavid du Colombier void
move(File * f,Address addr2)6603e12c5d1SDavid du Colombier move(File *f, Address addr2)
6613e12c5d1SDavid du Colombier {
6623e12c5d1SDavid du Colombier 	if(addr.r.p2 <= addr2.r.p2){
6637dd7cddfSDavid du Colombier 		logdelete(f, addr.r.p1, addr.r.p2);
6643e12c5d1SDavid du Colombier 		copy(f, addr2);
6653e12c5d1SDavid du Colombier 	}else if(addr.r.p1 >= addr2.r.p2){
6663e12c5d1SDavid du Colombier 		copy(f, addr2);
6677dd7cddfSDavid du Colombier 		logdelete(f, addr.r.p1, addr.r.p2);
6683e12c5d1SDavid du Colombier 	}else
6693e12c5d1SDavid du Colombier 		error(Eoverlap);
6703e12c5d1SDavid du Colombier }
6713e12c5d1SDavid du Colombier 
6723e12c5d1SDavid du Colombier Posn
nlcount(File * f,Posn p0,Posn p1)6733e12c5d1SDavid du Colombier nlcount(File *f, Posn p0, Posn p1)
6743e12c5d1SDavid du Colombier {
6753e12c5d1SDavid du Colombier 	Posn nl = 0;
6763e12c5d1SDavid du Colombier 
6777dd7cddfSDavid du Colombier 	while(p0 < p1)
6787dd7cddfSDavid du Colombier 		if(filereadc(f, p0++)=='\n')
6793e12c5d1SDavid du Colombier 			nl++;
6803e12c5d1SDavid du Colombier 	return nl;
6813e12c5d1SDavid du Colombier }
6823e12c5d1SDavid du Colombier 
6833e12c5d1SDavid du Colombier void
printposn(File * f,int charsonly)6843e12c5d1SDavid du Colombier printposn(File *f, int charsonly)
6853e12c5d1SDavid du Colombier {
6863e12c5d1SDavid du Colombier 	Posn l1, l2;
6873e12c5d1SDavid du Colombier 
6883e12c5d1SDavid du Colombier 	if(!charsonly){
6893e12c5d1SDavid du Colombier 		l1 = 1+nlcount(f, (Posn)0, addr.r.p1);
6903e12c5d1SDavid du Colombier 		l2 = l1+nlcount(f, addr.r.p1, addr.r.p2);
6913e12c5d1SDavid du Colombier 		/* check if addr ends with '\n' */
6927dd7cddfSDavid du Colombier 		if(addr.r.p2>0 && addr.r.p2>addr.r.p1 && filereadc(f, addr.r.p2-1)=='\n')
6933e12c5d1SDavid du Colombier 			--l2;
6943e12c5d1SDavid du Colombier 		dprint("%lud", l1);
6953e12c5d1SDavid du Colombier 		if(l2 != l1)
6963e12c5d1SDavid du Colombier 			dprint(",%lud", l2);
6973e12c5d1SDavid du Colombier 		dprint("; ");
6983e12c5d1SDavid du Colombier 	}
6993e12c5d1SDavid du Colombier 	dprint("#%lud", addr.r.p1);
7003e12c5d1SDavid du Colombier 	if(addr.r.p2 != addr.r.p1)
7013e12c5d1SDavid du Colombier 		dprint(",#%lud", addr.r.p2);
7023e12c5d1SDavid du Colombier 	dprint("\n");
7033e12c5d1SDavid du Colombier }
7043e12c5d1SDavid du Colombier 
7053e12c5d1SDavid du Colombier void
settempfile(void)7063e12c5d1SDavid du Colombier settempfile(void)
7073e12c5d1SDavid du Colombier {
7083e12c5d1SDavid du Colombier 	if(tempfile.nalloc < file.nused){
709*73e742d7SDavid du Colombier 		if(tempfile.filepptr)
710*73e742d7SDavid du Colombier 			free(tempfile.filepptr);
711*73e742d7SDavid du Colombier 		tempfile.filepptr = emalloc(sizeof(File*)*file.nused);
7123e12c5d1SDavid du Colombier 		tempfile.nalloc = file.nused;
7133e12c5d1SDavid du Colombier 	}
714*73e742d7SDavid du Colombier 	memmove(tempfile.filepptr, file.filepptr, sizeof(File*)*file.nused);
7153e12c5d1SDavid du Colombier 	tempfile.nused = file.nused;
7163e12c5d1SDavid du Colombier }
717