xref: /plan9/sys/src/cmd/sam/sam.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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 Mod	modnum;
83e12c5d1SDavid du Colombier String	genstr;
93e12c5d1SDavid du Colombier String	rhs;
103e12c5d1SDavid du Colombier String	wd;
113e12c5d1SDavid du Colombier String	cmdstr;
123e12c5d1SDavid du Colombier Rune	empty[] = { 0 };
133e12c5d1SDavid du Colombier char	*genc;
143e12c5d1SDavid du Colombier File	*curfile;
153e12c5d1SDavid du Colombier File	*flist;
163e12c5d1SDavid du Colombier File	*cmd;
173e12c5d1SDavid du Colombier jmp_buf	mainloop;
183e12c5d1SDavid du Colombier List tempfile;
193e12c5d1SDavid du Colombier int	quitok = TRUE;
203e12c5d1SDavid du Colombier int	downloaded;
213e12c5d1SDavid du Colombier int	dflag;
223e12c5d1SDavid du Colombier int	Rflag;
233e12c5d1SDavid du Colombier char	*machine;
243e12c5d1SDavid du Colombier char	*home;
253e12c5d1SDavid du Colombier int	bpipeok;
263e12c5d1SDavid du Colombier int	termlocked;
273e12c5d1SDavid du Colombier char	*samterm = SAMTERM;
283e12c5d1SDavid du Colombier char	*rsamname = RSAM;
293e12c5d1SDavid du Colombier 
30*219b2ee8SDavid du Colombier Rune	baddir[] = { '<', 'b', 'a', 'd', 'd', 'i', 'r', '>', '\n'};
31*219b2ee8SDavid du Colombier 
323e12c5d1SDavid du Colombier void	usage(void);
333e12c5d1SDavid du Colombier 
343e12c5d1SDavid du Colombier void
353e12c5d1SDavid du Colombier main(int argc, char *argv[])
363e12c5d1SDavid du Colombier {
373e12c5d1SDavid du Colombier 	int i;
383e12c5d1SDavid du Colombier 	String *t;
393e12c5d1SDavid du Colombier 	char **ap, **arg;
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier 	arg = argv++;
423e12c5d1SDavid du Colombier 	ap = argv;
433e12c5d1SDavid du Colombier 	while(argc>1 && argv[0] && argv[0][0]=='-'){
443e12c5d1SDavid du Colombier 		switch(argv[0][1]){
453e12c5d1SDavid du Colombier 		case 'd':
463e12c5d1SDavid du Colombier 			dflag++;
473e12c5d1SDavid du Colombier 			break;
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier 		case 'r':
503e12c5d1SDavid du Colombier 			--argc, argv++;
513e12c5d1SDavid du Colombier 			if(argc == 1)
523e12c5d1SDavid du Colombier 				usage();
533e12c5d1SDavid du Colombier 			machine = *argv;
543e12c5d1SDavid du Colombier 			break;
553e12c5d1SDavid du Colombier 
563e12c5d1SDavid du Colombier 		case 'R':
573e12c5d1SDavid du Colombier 			Rflag++;
583e12c5d1SDavid du Colombier 			break;
593e12c5d1SDavid du Colombier 
603e12c5d1SDavid du Colombier 		case 't':
613e12c5d1SDavid du Colombier 			--argc, argv++;
623e12c5d1SDavid du Colombier 			if(argc == 1)
633e12c5d1SDavid du Colombier 				usage();
643e12c5d1SDavid du Colombier 			samterm = *argv;
653e12c5d1SDavid du Colombier 			break;
663e12c5d1SDavid du Colombier 
673e12c5d1SDavid du Colombier 		case 's':
683e12c5d1SDavid du Colombier 			--argc, argv++;
693e12c5d1SDavid du Colombier 			if(argc == 1)
703e12c5d1SDavid du Colombier 				usage();
713e12c5d1SDavid du Colombier 			rsamname = *argv;
723e12c5d1SDavid du Colombier 			break;
733e12c5d1SDavid du Colombier 
743e12c5d1SDavid du Colombier 		default:
75bd389b36SDavid du Colombier 			dprint("sam: unknown flag %c\n", argv[0][1]);
763e12c5d1SDavid du Colombier 			exits("usage");
773e12c5d1SDavid du Colombier 		}
783e12c5d1SDavid du Colombier 		--argc, argv++;
793e12c5d1SDavid du Colombier 	}
803e12c5d1SDavid du Colombier 	Strinit(&cmdstr);
813e12c5d1SDavid du Colombier 	Strinit0(&lastpat);
823e12c5d1SDavid du Colombier 	Strinit0(&lastregexp);
833e12c5d1SDavid du Colombier 	Strinit0(&genstr);
843e12c5d1SDavid du Colombier 	Strinit0(&rhs);
853e12c5d1SDavid du Colombier 	Strinit0(&wd);
863e12c5d1SDavid du Colombier 	tempfile.listptr = emalloc(0);
873e12c5d1SDavid du Colombier 	Strinit0(&plan9cmd);
883e12c5d1SDavid du Colombier 	home = getenv(HOME);
893e12c5d1SDavid du Colombier 	if(home == 0)
903e12c5d1SDavid du Colombier 		home = "/";
913e12c5d1SDavid du Colombier 	if(!dflag)
923e12c5d1SDavid du Colombier 		startup(machine, Rflag, arg, ap);
933e12c5d1SDavid du Colombier 	Fstart();
943e12c5d1SDavid du Colombier 	notify(notifyf);
953e12c5d1SDavid du Colombier 	if(argc>1){
963e12c5d1SDavid du Colombier 		for(i=0; i<argc-1; i++)
973e12c5d1SDavid du Colombier 			if(!setjmp(mainloop)){
983e12c5d1SDavid du Colombier 				t = tmpcstr(argv[i]);
993e12c5d1SDavid du Colombier 				Straddc(t, '\0');
1003e12c5d1SDavid du Colombier 				Strduplstr(&genstr, t);
1013e12c5d1SDavid du Colombier 				freetmpstr(t);
1023e12c5d1SDavid du Colombier 				Fsetname(newfile(), &genstr);
1033e12c5d1SDavid du Colombier 			}
1043e12c5d1SDavid du Colombier 	}else if(!downloaded)
1053e12c5d1SDavid du Colombier 		newfile()->state = Clean;
1063e12c5d1SDavid du Colombier 	modnum++;
1073e12c5d1SDavid du Colombier 	if(file.nused)
1083e12c5d1SDavid du Colombier 		current(file.filepptr[0]);
1093e12c5d1SDavid du Colombier 	setjmp(mainloop);
1103e12c5d1SDavid du Colombier 	cmdloop();
1113e12c5d1SDavid du Colombier 	trytoquit();	/* if we already q'ed, quitok will be TRUE */
1123e12c5d1SDavid du Colombier 	exits(0);
1133e12c5d1SDavid du Colombier }
1143e12c5d1SDavid du Colombier 
1153e12c5d1SDavid du Colombier void
1163e12c5d1SDavid du Colombier usage(void)
1173e12c5d1SDavid du Colombier {
1183e12c5d1SDavid du Colombier 	dprint("usage: sam [-d] [-t samterm] [-s sam name] -r machine\n");
1193e12c5d1SDavid du Colombier 	exits("usage");
1203e12c5d1SDavid du Colombier }
1213e12c5d1SDavid du Colombier 
1223e12c5d1SDavid du Colombier void
1233e12c5d1SDavid du Colombier rescue(void)
1243e12c5d1SDavid du Colombier {
1253e12c5d1SDavid du Colombier 	int i, nblank = 0;
1263e12c5d1SDavid du Colombier 	File *f;
1273e12c5d1SDavid du Colombier 	char *c;
1283e12c5d1SDavid du Colombier 	char buf[256];
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier 	if(rescuing++)
1313e12c5d1SDavid du Colombier 		return;
1323e12c5d1SDavid du Colombier 	io = -1;
1333e12c5d1SDavid du Colombier 	for(i=0; i<file.nused; i++){
1343e12c5d1SDavid du Colombier 		f = file.filepptr[i];
1353e12c5d1SDavid du Colombier 		if(f==cmd || f->nrunes==0 || f->state!=Dirty)
1363e12c5d1SDavid du Colombier 			continue;
1373e12c5d1SDavid du Colombier 		if(io == -1){
1383e12c5d1SDavid du Colombier 			sprint(buf, "%s/sam.save", home);
1393e12c5d1SDavid du Colombier 			io = create(buf, 1, 0777);
1403e12c5d1SDavid du Colombier 			if(io<0)
1413e12c5d1SDavid du Colombier 				return;
1423e12c5d1SDavid du Colombier 		}
1433e12c5d1SDavid du Colombier 		if(f->name.s[0]){
1443e12c5d1SDavid du Colombier 			c = Strtoc(&f->name);
1453e12c5d1SDavid du Colombier 			strncpy(buf, c, sizeof buf-1);
1463e12c5d1SDavid du Colombier 			buf[sizeof buf-1] = 0;
1473e12c5d1SDavid du Colombier 			free(c);
1483e12c5d1SDavid du Colombier 		}else
1493e12c5d1SDavid du Colombier 			sprint(buf, "nameless.%d", nblank++);
150bd389b36SDavid du Colombier 		fprint(io, "#!%s '%s' $* <<'---%s'\n", SAMSAVECMD, buf, buf);
1513e12c5d1SDavid du Colombier 		addr.r.p1 = 0, addr.r.p2 = f->nrunes;
1523e12c5d1SDavid du Colombier 		writeio(f);
1533e12c5d1SDavid du Colombier 		fprint(io, "\n---%s\n", (char *)buf);
1543e12c5d1SDavid du Colombier 	}
1553e12c5d1SDavid du Colombier }
1563e12c5d1SDavid du Colombier 
1573e12c5d1SDavid du Colombier void
1583e12c5d1SDavid du Colombier panic(char *s)
1593e12c5d1SDavid du Colombier {
1603e12c5d1SDavid du Colombier 	int wasd;
1613e12c5d1SDavid du Colombier 
1623e12c5d1SDavid du Colombier 	if(!panicking++ && !setjmp(mainloop)){
1633e12c5d1SDavid du Colombier 		wasd = downloaded;
1643e12c5d1SDavid du Colombier 		downloaded = 0;
1653e12c5d1SDavid du Colombier 		dprint("sam: panic: %s: %r\n", s);
1663e12c5d1SDavid du Colombier 		if(wasd)
1673e12c5d1SDavid du Colombier 			fprint(2, "sam: panic: %s: %r\n", s);
1683e12c5d1SDavid du Colombier 		rescue();
1693e12c5d1SDavid du Colombier 		abort();
1703e12c5d1SDavid du Colombier 	}
1713e12c5d1SDavid du Colombier }
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier void
1743e12c5d1SDavid du Colombier hiccough(char *s)
1753e12c5d1SDavid du Colombier {
1763e12c5d1SDavid du Colombier 	if(rescuing)
1773e12c5d1SDavid du Colombier 		exits("rescue");
1783e12c5d1SDavid du Colombier 	if(s)
1793e12c5d1SDavid du Colombier 		dprint("%s\n", s);
1803e12c5d1SDavid du Colombier 	resetcmd();
1813e12c5d1SDavid du Colombier 	resetxec();
1823e12c5d1SDavid du Colombier 	resetsys();
1833e12c5d1SDavid du Colombier 	if(io > 0)
1843e12c5d1SDavid du Colombier 		close(io);
1853e12c5d1SDavid du Colombier 	if(undobuf->nrunes)
1863e12c5d1SDavid du Colombier 		Bdelete(undobuf, (Posn)0, undobuf->nrunes);
1873e12c5d1SDavid du Colombier 	update();
188*219b2ee8SDavid du Colombier 	if (curfile) {
189*219b2ee8SDavid du Colombier 		if (curfile->state==Unread)
1903e12c5d1SDavid du Colombier 			curfile->state = Clean;
191*219b2ee8SDavid du Colombier 		else if (downloaded)
1923e12c5d1SDavid du Colombier 			outTs(Hcurrent, curfile->tag);
193*219b2ee8SDavid du Colombier 	}
1943e12c5d1SDavid du Colombier 	longjmp(mainloop, 1);
1953e12c5d1SDavid du Colombier }
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier void
1983e12c5d1SDavid du Colombier intr(void)
1993e12c5d1SDavid du Colombier {
2003e12c5d1SDavid du Colombier 	error(Eintr);
2013e12c5d1SDavid du Colombier }
2023e12c5d1SDavid du Colombier 
2033e12c5d1SDavid du Colombier void
2043e12c5d1SDavid du Colombier trytoclose(File *f)
2053e12c5d1SDavid du Colombier {
2063e12c5d1SDavid du Colombier 	char *t;
207*219b2ee8SDavid du Colombier 	char buf[256];
2083e12c5d1SDavid du Colombier 
2093e12c5d1SDavid du Colombier 	if(f == cmd)	/* possible? */
2103e12c5d1SDavid du Colombier 		return;
211*219b2ee8SDavid du Colombier 	if(f->deleted)
212*219b2ee8SDavid du Colombier 		return;
2133e12c5d1SDavid du Colombier 	if(f->state==Dirty && !f->closeok){
2143e12c5d1SDavid du Colombier 		f->closeok = TRUE;
2153e12c5d1SDavid du Colombier 		if(f->name.s[0]){
2163e12c5d1SDavid du Colombier 			t = Strtoc(&f->name);
217*219b2ee8SDavid du Colombier 			strncpy(buf, t, sizeof buf-1);
2183e12c5d1SDavid du Colombier 			free(t);
2193e12c5d1SDavid du Colombier 		}else
220*219b2ee8SDavid du Colombier 			strcpy(buf, "nameless file");
221*219b2ee8SDavid du Colombier 		error_s(Emodified, buf);
2223e12c5d1SDavid du Colombier 	}
223*219b2ee8SDavid du Colombier 	f->deleted = TRUE;
2243e12c5d1SDavid du Colombier }
2253e12c5d1SDavid du Colombier 
2263e12c5d1SDavid du Colombier void
2273e12c5d1SDavid du Colombier trytoquit(void)
2283e12c5d1SDavid du Colombier {
2293e12c5d1SDavid du Colombier 	int c;
2303e12c5d1SDavid du Colombier 	File *f;
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier 	if(!quitok)
233*219b2ee8SDavid du Colombier {
2343e12c5d1SDavid du Colombier 		for(c = 0; c<file.nused; c++){
2353e12c5d1SDavid du Colombier 			f = file.filepptr[c];
2363e12c5d1SDavid du Colombier 			if(f!=cmd && f->state==Dirty){
2373e12c5d1SDavid du Colombier 				quitok = TRUE;
2383e12c5d1SDavid du Colombier 				eof = FALSE;
2393e12c5d1SDavid du Colombier 				error(Echanges);
2403e12c5d1SDavid du Colombier 			}
2413e12c5d1SDavid du Colombier 		}
2423e12c5d1SDavid du Colombier }
243*219b2ee8SDavid du Colombier }
2443e12c5d1SDavid du Colombier 
2453e12c5d1SDavid du Colombier void
2463e12c5d1SDavid du Colombier load(File *f)
2473e12c5d1SDavid du Colombier {
2483e12c5d1SDavid du Colombier 	Address saveaddr;
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier 	Strduplstr(&genstr, &f->name);
2513e12c5d1SDavid du Colombier 	filename(f);
2523e12c5d1SDavid du Colombier 	if(f->name.s[0]){
2533e12c5d1SDavid du Colombier 		saveaddr = addr;
2543e12c5d1SDavid du Colombier 		edit(f, 'I');
2553e12c5d1SDavid du Colombier 		addr = saveaddr;
2563e12c5d1SDavid du Colombier 	}else
2573e12c5d1SDavid du Colombier 		f->state = Clean;
2583e12c5d1SDavid du Colombier 	Fupdate(f, TRUE, TRUE);
2593e12c5d1SDavid du Colombier }
2603e12c5d1SDavid du Colombier 
2613e12c5d1SDavid du Colombier void
2623e12c5d1SDavid du Colombier cmdupdate(void)
2633e12c5d1SDavid du Colombier {
2643e12c5d1SDavid du Colombier 	if(cmd && cmd->mod!=0){
2653e12c5d1SDavid du Colombier 		Fupdate(cmd, FALSE, downloaded);
2663e12c5d1SDavid du Colombier 		cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->nrunes;
2673e12c5d1SDavid du Colombier 		telldot(cmd);
2683e12c5d1SDavid du Colombier 	}
2693e12c5d1SDavid du Colombier }
2703e12c5d1SDavid du Colombier 
2713e12c5d1SDavid du Colombier void
272*219b2ee8SDavid du Colombier delete(File *f)
273*219b2ee8SDavid du Colombier {
274*219b2ee8SDavid du Colombier 	if(downloaded && f->rasp)
275*219b2ee8SDavid du Colombier 		outTs(Hclose, f->tag);
276*219b2ee8SDavid du Colombier 	delfile(f);
277*219b2ee8SDavid du Colombier 	if(f == curfile)
278*219b2ee8SDavid du Colombier 		current(0);
279*219b2ee8SDavid du Colombier }
280*219b2ee8SDavid du Colombier 
281*219b2ee8SDavid du Colombier void
2823e12c5d1SDavid du Colombier update(void)
2833e12c5d1SDavid du Colombier {
2843e12c5d1SDavid du Colombier 	int i, anymod;
2853e12c5d1SDavid du Colombier 	File *f;
2863e12c5d1SDavid du Colombier 
2873e12c5d1SDavid du Colombier 	settempfile();
2883e12c5d1SDavid du Colombier 	for(anymod = i=0; i<tempfile.nused; i++){
2893e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
2903e12c5d1SDavid du Colombier 		if(f==cmd)	/* cmd gets done in main() */
2913e12c5d1SDavid du Colombier 			continue;
292*219b2ee8SDavid du Colombier 		if(f->deleted)
293*219b2ee8SDavid du Colombier 			delete(f);
2943e12c5d1SDavid du Colombier 		if(f->mod==modnum && Fupdate(f, FALSE, downloaded))
2953e12c5d1SDavid du Colombier 			anymod++;
2963e12c5d1SDavid du Colombier 		if(f->rasp)
2973e12c5d1SDavid du Colombier 			telldot(f);
2983e12c5d1SDavid du Colombier 	}
2993e12c5d1SDavid du Colombier 	if(anymod)
3003e12c5d1SDavid du Colombier 		modnum++;
3013e12c5d1SDavid du Colombier }
3023e12c5d1SDavid du Colombier 
3033e12c5d1SDavid du Colombier File *
3043e12c5d1SDavid du Colombier current(File *f)
3053e12c5d1SDavid du Colombier {
3063e12c5d1SDavid du Colombier 	return curfile = f;
3073e12c5d1SDavid du Colombier }
3083e12c5d1SDavid du Colombier 
3093e12c5d1SDavid du Colombier void
3103e12c5d1SDavid du Colombier edit(File *f, int cmd)
3113e12c5d1SDavid du Colombier {
3123e12c5d1SDavid du Colombier 	int empty = TRUE;
3133e12c5d1SDavid du Colombier 	Posn p;
3143e12c5d1SDavid du Colombier 	int nulls;
3153e12c5d1SDavid du Colombier 
3163e12c5d1SDavid du Colombier 	if(cmd == 'r')
3173e12c5d1SDavid du Colombier 		Fdelete(f, addr.r.p1, addr.r.p2);
3183e12c5d1SDavid du Colombier 	if(cmd=='e' || cmd=='I'){
3193e12c5d1SDavid du Colombier 		Fdelete(f, (Posn)0, f->nrunes);
3203e12c5d1SDavid du Colombier 		addr.r.p2 = f->nrunes;
3213e12c5d1SDavid du Colombier 	}else if(f->nrunes!=0 || (f->name.s[0] && Strcmp(&genstr, &f->name)!=0))
3223e12c5d1SDavid du Colombier 		empty = FALSE;
323*219b2ee8SDavid du Colombier 	if((io = open(genc, OREAD))<0) {
324*219b2ee8SDavid du Colombier 		if (curfile && curfile->state == Unread)
325*219b2ee8SDavid du Colombier 			curfile->state = Clean;
3263e12c5d1SDavid du Colombier 		error_s(Eopen, genc);
327*219b2ee8SDavid du Colombier 	}
3283e12c5d1SDavid du Colombier 	p = readio(f, &nulls, empty);
3293e12c5d1SDavid du Colombier 	closeio((cmd=='e' || cmd=='I')? -1 : p);
3303e12c5d1SDavid du Colombier 	if(cmd == 'r')
3313e12c5d1SDavid du Colombier 		f->ndot.r.p1 = addr.r.p2, f->ndot.r.p2 = addr.r.p2+p;
3323e12c5d1SDavid du Colombier 	else
3333e12c5d1SDavid du Colombier 		f->ndot.r.p1 = f->ndot.r.p2 = 0;
334*219b2ee8SDavid du Colombier 	f->closeok = empty;
335*219b2ee8SDavid du Colombier 	if (quitok)
336*219b2ee8SDavid du Colombier 		quitok = empty;
337*219b2ee8SDavid du Colombier 	else
338*219b2ee8SDavid du Colombier 		quitok = FALSE;
3393e12c5d1SDavid du Colombier 	state(f, empty && !nulls? Clean : Dirty);
3403e12c5d1SDavid du Colombier 	if(cmd == 'e')
3413e12c5d1SDavid du Colombier 		filename(f);
3423e12c5d1SDavid du Colombier }
3433e12c5d1SDavid du Colombier 
3443e12c5d1SDavid du Colombier int
3453e12c5d1SDavid du Colombier getname(File *f, String *s, int save)
3463e12c5d1SDavid du Colombier {
3473e12c5d1SDavid du Colombier 	int c, i;
3483e12c5d1SDavid du Colombier 
3493e12c5d1SDavid du Colombier 	Strzero(&genstr);
3503e12c5d1SDavid du Colombier 	if(genc){
3513e12c5d1SDavid du Colombier 		free(genc);
3523e12c5d1SDavid du Colombier 		genc = 0;
3533e12c5d1SDavid du Colombier 	}
3543e12c5d1SDavid du Colombier 	if(s==0 || (c = s->s[0])==0){		/* no name provided */
3553e12c5d1SDavid du Colombier 		if(f)
3563e12c5d1SDavid du Colombier 			Strduplstr(&genstr, &f->name);
3573e12c5d1SDavid du Colombier 		else
3583e12c5d1SDavid du Colombier 			Straddc(&genstr, '\0');
3593e12c5d1SDavid du Colombier 		goto Return;
3603e12c5d1SDavid du Colombier 	}
3613e12c5d1SDavid du Colombier 	if(c!=' ' && c!='\t')
3623e12c5d1SDavid du Colombier 		error(Eblank);
3633e12c5d1SDavid du Colombier 	for(i=0; (c=s->s[i])==' ' || c=='\t'; i++)
3643e12c5d1SDavid du Colombier 		;
3653e12c5d1SDavid du Colombier 	while(s->s[i] > ' ')
3663e12c5d1SDavid du Colombier 		Straddc(&genstr, s->s[i++]);
3673e12c5d1SDavid du Colombier 	if(s->s[i])
3683e12c5d1SDavid du Colombier 		error(Enewline);
3693e12c5d1SDavid du Colombier 	Straddc(&genstr, '\0');
3703e12c5d1SDavid du Colombier 	if(f && (save || f->name.s[0]==0)){
3713e12c5d1SDavid du Colombier 		Fsetname(f, &genstr);
3723e12c5d1SDavid du Colombier 		if(Strcmp(&f->name, &genstr)){
3733e12c5d1SDavid du Colombier 			quitok = f->closeok = FALSE;
374bd389b36SDavid du Colombier 			f->qid = 0;
3753e12c5d1SDavid du Colombier 			f->date = 0;
3763e12c5d1SDavid du Colombier 			state(f, Dirty); /* if it's 'e', fix later */
3773e12c5d1SDavid du Colombier 		}
3783e12c5d1SDavid du Colombier 	}
3793e12c5d1SDavid du Colombier     Return:
3803e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
3813e12c5d1SDavid du Colombier 	return genstr.n-1;	/* strlen(name) */
3823e12c5d1SDavid du Colombier }
3833e12c5d1SDavid du Colombier 
3843e12c5d1SDavid du Colombier void
3853e12c5d1SDavid du Colombier filename(File *f)
3863e12c5d1SDavid du Colombier {
3873e12c5d1SDavid du Colombier 	if(genc)
3883e12c5d1SDavid du Colombier 		free(genc);
3893e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
3903e12c5d1SDavid du Colombier 	dprint("%c%c%c %s\n", " '"[f->state==Dirty],
3913e12c5d1SDavid du Colombier 		"-+"[f->rasp!=0], " ."[f==curfile], genc);
3923e12c5d1SDavid du Colombier }
3933e12c5d1SDavid du Colombier 
3943e12c5d1SDavid du Colombier void
3953e12c5d1SDavid du Colombier undostep(File *f)
3963e12c5d1SDavid du Colombier {
3973e12c5d1SDavid du Colombier 	Buffer *t;
3983e12c5d1SDavid du Colombier 	int changes;
3993e12c5d1SDavid du Colombier 	Mark mark;
4003e12c5d1SDavid du Colombier 
4013e12c5d1SDavid du Colombier 	t = f->transcript;
4023e12c5d1SDavid du Colombier 	changes = Fupdate(f, TRUE, TRUE);
4033e12c5d1SDavid du Colombier 	Bread(t, (Rune*)&mark, (sizeof mark)/RUNESIZE, f->markp);
4043e12c5d1SDavid du Colombier 	Bdelete(t, f->markp, t->nrunes);
4053e12c5d1SDavid du Colombier 	f->markp = mark.p;
4063e12c5d1SDavid du Colombier 	f->dot.r = mark.dot;
4073e12c5d1SDavid du Colombier 	f->ndot.r = mark.dot;
4083e12c5d1SDavid du Colombier 	f->mark = mark.mark;
4093e12c5d1SDavid du Colombier 	f->mod = mark.m;
4103e12c5d1SDavid du Colombier 	f->closeok = mark.s1!=Dirty;
4113e12c5d1SDavid du Colombier 	if(mark.s1==Dirty)
4123e12c5d1SDavid du Colombier 		quitok = FALSE;
4133e12c5d1SDavid du Colombier 	if(f->state==Clean && mark.s1==Clean && changes)
4143e12c5d1SDavid du Colombier 		state(f, Dirty);
4153e12c5d1SDavid du Colombier 	else
4163e12c5d1SDavid du Colombier 		state(f, mark.s1);
4173e12c5d1SDavid du Colombier }
4183e12c5d1SDavid du Colombier 
419bd389b36SDavid du Colombier int
4203e12c5d1SDavid du Colombier undo(void)
4213e12c5d1SDavid du Colombier {
4223e12c5d1SDavid du Colombier 	File *f;
4233e12c5d1SDavid du Colombier 	int i;
4243e12c5d1SDavid du Colombier 	Mod max;
4253e12c5d1SDavid du Colombier 	if((max = curfile->mod)==0)
426bd389b36SDavid du Colombier 		return 0;
4273e12c5d1SDavid du Colombier 	settempfile();
4283e12c5d1SDavid du Colombier 	for(i = 0; i<tempfile.nused; i++){
4293e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
4303e12c5d1SDavid du Colombier 		if(f!=cmd && f->mod==max)
4313e12c5d1SDavid du Colombier 			undostep(f);
4323e12c5d1SDavid du Colombier 	}
433bd389b36SDavid du Colombier 	return 1;
4343e12c5d1SDavid du Colombier }
4353e12c5d1SDavid du Colombier 
436*219b2ee8SDavid du Colombier int
4373e12c5d1SDavid du Colombier readcmd(String *s)
4383e12c5d1SDavid du Colombier {
439*219b2ee8SDavid du Colombier 	int retcode;
440*219b2ee8SDavid du Colombier 
4413e12c5d1SDavid du Colombier 	if(flist == 0)
4423e12c5d1SDavid du Colombier 		(flist = Fopen())->state = Clean;
4433e12c5d1SDavid du Colombier 	addr.r.p1 = 0, addr.r.p2 = flist->nrunes;
444*219b2ee8SDavid du Colombier 	retcode = plan9(flist, '<', s, FALSE);
4453e12c5d1SDavid du Colombier 	Fupdate(flist, FALSE, FALSE);
4463e12c5d1SDavid du Colombier 	flist->mod = 0;
447bd389b36SDavid du Colombier 	if (flist->nrunes > BLOCKSIZE)
448bd389b36SDavid du Colombier 		error(Etoolong);
4493e12c5d1SDavid du Colombier 	Strzero(&genstr);
4503e12c5d1SDavid du Colombier 	Strinsure(&genstr, flist->nrunes);
4513e12c5d1SDavid du Colombier 	Fchars(flist, genbuf, (Posn)0, flist->nrunes);
4523e12c5d1SDavid du Colombier 	memmove(genstr.s, genbuf, flist->nrunes*RUNESIZE);
4533e12c5d1SDavid du Colombier 	genstr.n = flist->nrunes;
4543e12c5d1SDavid du Colombier 	Straddc(&genstr, '\0');
455*219b2ee8SDavid du Colombier 	return retcode;
4563e12c5d1SDavid du Colombier }
4573e12c5d1SDavid du Colombier 
4583e12c5d1SDavid du Colombier void
4593e12c5d1SDavid du Colombier cd(String *str)
4603e12c5d1SDavid du Colombier {
4613e12c5d1SDavid du Colombier 	int i;
4623e12c5d1SDavid du Colombier 	File *f;
4633e12c5d1SDavid du Colombier 	String *t;
4643e12c5d1SDavid du Colombier 
4653e12c5d1SDavid du Colombier 	t = tmpcstr("/bin/pwd");
4663e12c5d1SDavid du Colombier 	Straddc(t, '\0');
467*219b2ee8SDavid du Colombier 	if (flist) {
468*219b2ee8SDavid du Colombier 		Fclose(flist);
469*219b2ee8SDavid du Colombier 		flist = 0;
470*219b2ee8SDavid du Colombier 	}
471*219b2ee8SDavid du Colombier 	if (readcmd(t) != 0) {
472*219b2ee8SDavid du Colombier 		Strduplstr(&genstr, tmprstr(baddir, sizeof(baddir)/sizeof(Rune)));
473*219b2ee8SDavid du Colombier 		Straddc(&genstr, '\0');
474*219b2ee8SDavid du Colombier 	}
4753e12c5d1SDavid du Colombier 	freetmpstr(t);
4763e12c5d1SDavid du Colombier 	Strduplstr(&wd, &genstr);
4773e12c5d1SDavid du Colombier 	if(wd.s[0] == 0){
4783e12c5d1SDavid du Colombier 		wd.n = 0;
4793e12c5d1SDavid du Colombier 		warn(Wpwd);
4803e12c5d1SDavid du Colombier 	}else if(wd.s[wd.n-2] == '\n'){
4813e12c5d1SDavid du Colombier 		--wd.n;
4823e12c5d1SDavid du Colombier 		wd.s[wd.n-1]='/';
4833e12c5d1SDavid du Colombier 	}
4843e12c5d1SDavid du Colombier 	if(chdir(getname((File *)0, str, FALSE)? genc : home))
4853e12c5d1SDavid du Colombier 		syserror("chdir");
4863e12c5d1SDavid du Colombier 	settempfile();
4873e12c5d1SDavid du Colombier 	for(i=0; i<tempfile.nused; i++){
4883e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
4893e12c5d1SDavid du Colombier 		if(f!=cmd && f->name.s[0]!='/' && f->name.s[0]!=0){
4903e12c5d1SDavid du Colombier 			Strinsert(&f->name, &wd, (Posn)0);
4913e12c5d1SDavid du Colombier 			sortname(f);
4923e12c5d1SDavid du Colombier 		}
4933e12c5d1SDavid du Colombier 	}
4943e12c5d1SDavid du Colombier }
4953e12c5d1SDavid du Colombier 
4963e12c5d1SDavid du Colombier int
4973e12c5d1SDavid du Colombier loadflist(String *s)
4983e12c5d1SDavid du Colombier {
4993e12c5d1SDavid du Colombier 	int c, i;
5003e12c5d1SDavid du Colombier 
5013e12c5d1SDavid du Colombier 	c = s->s[0];
5023e12c5d1SDavid du Colombier 	for(i = 0; s->s[i]==' ' || s->s[i]=='\t'; i++)
5033e12c5d1SDavid du Colombier 		;
5043e12c5d1SDavid du Colombier 	if((c==' ' || c=='\t') && s->s[i]!='\n'){
5053e12c5d1SDavid du Colombier 		if(s->s[i]=='<'){
5063e12c5d1SDavid du Colombier 			Strdelete(s, 0L, (long)i+1);
5073e12c5d1SDavid du Colombier 			readcmd(s);
5083e12c5d1SDavid du Colombier 		}else{
5093e12c5d1SDavid du Colombier 			Strzero(&genstr);
5103e12c5d1SDavid du Colombier 			while((c = s->s[i++]) && c!='\n')
5113e12c5d1SDavid du Colombier 				Straddc(&genstr, c);
5123e12c5d1SDavid du Colombier 			Straddc(&genstr, '\0');
5133e12c5d1SDavid du Colombier 		}
5143e12c5d1SDavid du Colombier 	}else{
5153e12c5d1SDavid du Colombier 		if(c != '\n')
5163e12c5d1SDavid du Colombier 			error(Eblank);
5173e12c5d1SDavid du Colombier 		Strdupl(&genstr, empty);
5183e12c5d1SDavid du Colombier 	}
5193e12c5d1SDavid du Colombier 	if(genc)
5203e12c5d1SDavid du Colombier 		free(genc);
5213e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
5223e12c5d1SDavid du Colombier 	return genstr.s[0];
5233e12c5d1SDavid du Colombier }
5243e12c5d1SDavid du Colombier 
5253e12c5d1SDavid du Colombier File *
5263e12c5d1SDavid du Colombier readflist(int readall, int delete)
5273e12c5d1SDavid du Colombier {
5283e12c5d1SDavid du Colombier 	Posn i;
5293e12c5d1SDavid du Colombier 	int c;
5303e12c5d1SDavid du Colombier 	File *f;
5313e12c5d1SDavid du Colombier 	String *t;
5323e12c5d1SDavid du Colombier 
5333e12c5d1SDavid du Colombier 	for(i=0,f=0; f==0 || readall || delete; i++){	/* ++ skips blank */
5343e12c5d1SDavid du Colombier 		Strdelete(&genstr, (Posn)0, i);
5353e12c5d1SDavid du Colombier 		for(i=0; (c = genstr.s[i])==' ' || c=='\t' || c=='\n'; i++)
5363e12c5d1SDavid du Colombier 			;
5373e12c5d1SDavid du Colombier 		if(i >= genstr.n)
5383e12c5d1SDavid du Colombier 			break;
5393e12c5d1SDavid du Colombier 		Strdelete(&genstr, (Posn)0, i);
5403e12c5d1SDavid du Colombier 		for(i=0; (c=genstr.s[i]) && c!=' ' && c!='\t' && c!='\n'; i++)
5413e12c5d1SDavid du Colombier 			;
5423e12c5d1SDavid du Colombier 
5433e12c5d1SDavid du Colombier 		if(i == 0)
5443e12c5d1SDavid du Colombier 			break;
5453e12c5d1SDavid du Colombier 		genstr.s[i] = 0;
5463e12c5d1SDavid du Colombier 		t = tmprstr(genstr.s, i+1);
5473e12c5d1SDavid du Colombier 		f = lookfile(t);
5483e12c5d1SDavid du Colombier 		if(delete){
5493e12c5d1SDavid du Colombier 			if(f == 0)
5503e12c5d1SDavid du Colombier 				warn_S(Wfile, t);
5513e12c5d1SDavid du Colombier 			else
5523e12c5d1SDavid du Colombier 				trytoclose(f);
5533e12c5d1SDavid du Colombier 		}else if(f==0 && readall)
5543e12c5d1SDavid du Colombier 			Fsetname(f = newfile(), t);
5553e12c5d1SDavid du Colombier 	}
5563e12c5d1SDavid du Colombier 	return f;
5573e12c5d1SDavid du Colombier }
5583e12c5d1SDavid du Colombier 
5593e12c5d1SDavid du Colombier File *
5603e12c5d1SDavid du Colombier tofile(String *s)
5613e12c5d1SDavid du Colombier {
5623e12c5d1SDavid du Colombier 	File *f;
5633e12c5d1SDavid du Colombier 
5643e12c5d1SDavid du Colombier 	if(s->s[0] != ' ')
5653e12c5d1SDavid du Colombier 		error(Eblank);
5663e12c5d1SDavid du Colombier 	if(loadflist(s) == 0){
5673e12c5d1SDavid du Colombier 		f = lookfile(&genstr);	/* empty string ==> nameless file */
5683e12c5d1SDavid du Colombier 		if(f == 0)
5693e12c5d1SDavid du Colombier 			error_s(Emenu, genc);
5703e12c5d1SDavid du Colombier 	}else if((f=readflist(FALSE, FALSE)) == 0)
5713e12c5d1SDavid du Colombier 		error_s(Emenu, genc);
5723e12c5d1SDavid du Colombier 	return current(f);
5733e12c5d1SDavid du Colombier }
5743e12c5d1SDavid du Colombier 
5753e12c5d1SDavid du Colombier File *
5763e12c5d1SDavid du Colombier getfile(String *s)
5773e12c5d1SDavid du Colombier {
5783e12c5d1SDavid du Colombier 	File *f;
5793e12c5d1SDavid du Colombier 
5803e12c5d1SDavid du Colombier 	if(loadflist(s) == 0)
5813e12c5d1SDavid du Colombier 		Fsetname(f = newfile(), &genstr);
5823e12c5d1SDavid du Colombier 	else if((f=readflist(TRUE, FALSE)) == 0)
5833e12c5d1SDavid du Colombier 		error(Eblank);
5843e12c5d1SDavid du Colombier 	return current(f);
5853e12c5d1SDavid du Colombier }
5863e12c5d1SDavid du Colombier 
5873e12c5d1SDavid du Colombier void
5883e12c5d1SDavid du Colombier closefiles(File *f, String *s)
5893e12c5d1SDavid du Colombier {
5903e12c5d1SDavid du Colombier 	if(s->s[0] == 0){
5913e12c5d1SDavid du Colombier 		if(f == 0)
5923e12c5d1SDavid du Colombier 			error(Enofile);
5933e12c5d1SDavid du Colombier 		trytoclose(f);
5943e12c5d1SDavid du Colombier 		return;
5953e12c5d1SDavid du Colombier 	}
5963e12c5d1SDavid du Colombier 	if(s->s[0] != ' ')
5973e12c5d1SDavid du Colombier 		error(Eblank);
5983e12c5d1SDavid du Colombier 	if(loadflist(s) == 0)
5993e12c5d1SDavid du Colombier 		error(Enewline);
6003e12c5d1SDavid du Colombier 	readflist(FALSE, TRUE);
6013e12c5d1SDavid du Colombier }
6023e12c5d1SDavid du Colombier 
6033e12c5d1SDavid du Colombier void
6043e12c5d1SDavid du Colombier copy(File *f, Address addr2)
6053e12c5d1SDavid du Colombier {
6063e12c5d1SDavid du Colombier 	Posn p;
6073e12c5d1SDavid du Colombier 	int ni;
6083e12c5d1SDavid du Colombier 	for(p=addr.r.p1; p<addr.r.p2; p+=ni){
6093e12c5d1SDavid du Colombier 		ni = addr.r.p2-p;
6103e12c5d1SDavid du Colombier 		if(ni > BLOCKSIZE)
6113e12c5d1SDavid du Colombier 			ni = BLOCKSIZE;
6123e12c5d1SDavid du Colombier 		Fchars(f, genbuf, p, p+ni);
6133e12c5d1SDavid du Colombier 		Finsert(addr2.f, tmprstr(genbuf, ni), addr2.r.p2);
6143e12c5d1SDavid du Colombier 	}
6153e12c5d1SDavid du Colombier 	addr2.f->ndot.r.p2 = addr2.r.p2+(f->dot.r.p2-f->dot.r.p1);
6163e12c5d1SDavid du Colombier 	addr2.f->ndot.r.p1 = addr2.r.p2;
6173e12c5d1SDavid du Colombier }
6183e12c5d1SDavid du Colombier 
6193e12c5d1SDavid du Colombier void
6203e12c5d1SDavid du Colombier move(File *f, Address addr2)
6213e12c5d1SDavid du Colombier {
6223e12c5d1SDavid du Colombier 	if(addr.r.p2 <= addr2.r.p2){
6233e12c5d1SDavid du Colombier 		Fdelete(f, addr.r.p1, addr.r.p2);
6243e12c5d1SDavid du Colombier 		copy(f, addr2);
6253e12c5d1SDavid du Colombier 	}else if(addr.r.p1 >= addr2.r.p2){
6263e12c5d1SDavid du Colombier 		copy(f, addr2);
6273e12c5d1SDavid du Colombier 		Fdelete(f, addr.r.p1, addr.r.p2);
6283e12c5d1SDavid du Colombier 	}else
6293e12c5d1SDavid du Colombier 		error(Eoverlap);
6303e12c5d1SDavid du Colombier }
6313e12c5d1SDavid du Colombier 
6323e12c5d1SDavid du Colombier Posn
6333e12c5d1SDavid du Colombier nlcount(File *f, Posn p0, Posn p1)
6343e12c5d1SDavid du Colombier {
6353e12c5d1SDavid du Colombier 	Posn nl = 0;
6363e12c5d1SDavid du Colombier 
6373e12c5d1SDavid du Colombier 	Fgetcset(f, p0);
6383e12c5d1SDavid du Colombier 	while(p0++<p1)
6393e12c5d1SDavid du Colombier 		if(Fgetc(f)=='\n')
6403e12c5d1SDavid du Colombier 			nl++;
6413e12c5d1SDavid du Colombier 	return nl;
6423e12c5d1SDavid du Colombier }
6433e12c5d1SDavid du Colombier 
6443e12c5d1SDavid du Colombier void
6453e12c5d1SDavid du Colombier printposn(File *f, int charsonly)
6463e12c5d1SDavid du Colombier {
6473e12c5d1SDavid du Colombier 	Posn l1, l2;
6483e12c5d1SDavid du Colombier 
6493e12c5d1SDavid du Colombier 	if(!charsonly){
6503e12c5d1SDavid du Colombier 		l1 = 1+nlcount(f, (Posn)0, addr.r.p1);
6513e12c5d1SDavid du Colombier 		l2 = l1+nlcount(f, addr.r.p1, addr.r.p2);
6523e12c5d1SDavid du Colombier 		/* check if addr ends with '\n' */
6533e12c5d1SDavid du Colombier 		if(addr.r.p2>0 && addr.r.p2>addr.r.p1 && (Fgetcset(f, addr.r.p2-1),Fgetc(f)=='\n'))
6543e12c5d1SDavid du Colombier 			--l2;
6553e12c5d1SDavid du Colombier 		dprint("%lud", l1);
6563e12c5d1SDavid du Colombier 		if(l2 != l1)
6573e12c5d1SDavid du Colombier 			dprint(",%lud", l2);
6583e12c5d1SDavid du Colombier 		dprint("; ");
6593e12c5d1SDavid du Colombier 	}
6603e12c5d1SDavid du Colombier 	dprint("#%lud", addr.r.p1);
6613e12c5d1SDavid du Colombier 	if(addr.r.p2 != addr.r.p1)
6623e12c5d1SDavid du Colombier 		dprint(",#%lud", addr.r.p2);
6633e12c5d1SDavid du Colombier 	dprint("\n");
6643e12c5d1SDavid du Colombier }
6653e12c5d1SDavid du Colombier 
6663e12c5d1SDavid du Colombier void
6673e12c5d1SDavid du Colombier settempfile(void)
6683e12c5d1SDavid du Colombier {
6693e12c5d1SDavid du Colombier 	if(tempfile.nalloc < file.nused){
6703e12c5d1SDavid du Colombier 		free(tempfile.listptr);
6713e12c5d1SDavid du Colombier 		tempfile.listptr = emalloc(sizeof(*tempfile.filepptr)*file.nused);
6723e12c5d1SDavid du Colombier 		tempfile.nalloc = file.nused;
6733e12c5d1SDavid du Colombier 	}
6743e12c5d1SDavid du Colombier 	tempfile.nused = file.nused;
6753e12c5d1SDavid du Colombier 	memmove(&tempfile.filepptr[0], &file.filepptr[0], file.nused*sizeof(File*));
6763e12c5d1SDavid du Colombier }
677