xref: /plan9/sys/src/cmd/sam/sam.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include "sam.h"
2*3e12c5d1SDavid du Colombier 
3*3e12c5d1SDavid du Colombier Rune	genbuf[BLOCKSIZE];
4*3e12c5d1SDavid du Colombier int	io;
5*3e12c5d1SDavid du Colombier int	panicking;
6*3e12c5d1SDavid du Colombier int	rescuing;
7*3e12c5d1SDavid du Colombier Mod	modnum;
8*3e12c5d1SDavid du Colombier String	genstr;
9*3e12c5d1SDavid du Colombier String	rhs;
10*3e12c5d1SDavid du Colombier String	wd;
11*3e12c5d1SDavid du Colombier String	cmdstr;
12*3e12c5d1SDavid du Colombier Rune	empty[] = { 0 };
13*3e12c5d1SDavid du Colombier char	*genc;
14*3e12c5d1SDavid du Colombier File	*curfile;
15*3e12c5d1SDavid du Colombier File	*flist;
16*3e12c5d1SDavid du Colombier File	*cmd;
17*3e12c5d1SDavid du Colombier jmp_buf	mainloop;
18*3e12c5d1SDavid du Colombier List tempfile;
19*3e12c5d1SDavid du Colombier int	quitok = TRUE;
20*3e12c5d1SDavid du Colombier int	downloaded;
21*3e12c5d1SDavid du Colombier int	dflag;
22*3e12c5d1SDavid du Colombier int	Rflag;
23*3e12c5d1SDavid du Colombier char	*machine;
24*3e12c5d1SDavid du Colombier char	*home;
25*3e12c5d1SDavid du Colombier int	bpipeok;
26*3e12c5d1SDavid du Colombier int	termlocked;
27*3e12c5d1SDavid du Colombier char	*samterm = SAMTERM;
28*3e12c5d1SDavid du Colombier char	*rsamname = RSAM;
29*3e12c5d1SDavid du Colombier 
30*3e12c5d1SDavid du Colombier void	usage(void);
31*3e12c5d1SDavid du Colombier 
32*3e12c5d1SDavid du Colombier void
33*3e12c5d1SDavid du Colombier main(int argc, char *argv[])
34*3e12c5d1SDavid du Colombier {
35*3e12c5d1SDavid du Colombier 	int i;
36*3e12c5d1SDavid du Colombier 	String *t;
37*3e12c5d1SDavid du Colombier 	char **ap, **arg;
38*3e12c5d1SDavid du Colombier 
39*3e12c5d1SDavid du Colombier 	arg = argv++;
40*3e12c5d1SDavid du Colombier 	ap = argv;
41*3e12c5d1SDavid du Colombier 	while(argc>1 && argv[0] && argv[0][0]=='-'){
42*3e12c5d1SDavid du Colombier 		switch(argv[0][1]){
43*3e12c5d1SDavid du Colombier 		case 'd':
44*3e12c5d1SDavid du Colombier 			dflag++;
45*3e12c5d1SDavid du Colombier 			break;
46*3e12c5d1SDavid du Colombier 
47*3e12c5d1SDavid du Colombier 		case 'r':
48*3e12c5d1SDavid du Colombier 			--argc, argv++;
49*3e12c5d1SDavid du Colombier 			if(argc == 1)
50*3e12c5d1SDavid du Colombier 				usage();
51*3e12c5d1SDavid du Colombier 			machine = *argv;
52*3e12c5d1SDavid du Colombier 			break;
53*3e12c5d1SDavid du Colombier 
54*3e12c5d1SDavid du Colombier 		case 'R':
55*3e12c5d1SDavid du Colombier 			Rflag++;
56*3e12c5d1SDavid du Colombier 			break;
57*3e12c5d1SDavid du Colombier 
58*3e12c5d1SDavid du Colombier 		case 't':
59*3e12c5d1SDavid du Colombier 			--argc, argv++;
60*3e12c5d1SDavid du Colombier 			if(argc == 1)
61*3e12c5d1SDavid du Colombier 				usage();
62*3e12c5d1SDavid du Colombier 			samterm = *argv;
63*3e12c5d1SDavid du Colombier 			break;
64*3e12c5d1SDavid du Colombier 
65*3e12c5d1SDavid du Colombier 		case 's':
66*3e12c5d1SDavid du Colombier 			--argc, argv++;
67*3e12c5d1SDavid du Colombier 			if(argc == 1)
68*3e12c5d1SDavid du Colombier 				usage();
69*3e12c5d1SDavid du Colombier 			rsamname = *argv;
70*3e12c5d1SDavid du Colombier 			break;
71*3e12c5d1SDavid du Colombier 
72*3e12c5d1SDavid du Colombier 		case 'g':	/* -geom -> pass to samterm */
73*3e12c5d1SDavid du Colombier 			*ap++ = *argv++;
74*3e12c5d1SDavid du Colombier 			*ap++ = *argv;
75*3e12c5d1SDavid du Colombier 			argc--;
76*3e12c5d1SDavid du Colombier 			break;
77*3e12c5d1SDavid du Colombier 
78*3e12c5d1SDavid du Colombier 		default:
79*3e12c5d1SDavid du Colombier 			dprint("sam: unknown flag %c\n", argv[1][1]);
80*3e12c5d1SDavid du Colombier 			exits("usage");
81*3e12c5d1SDavid du Colombier 		}
82*3e12c5d1SDavid du Colombier 		--argc, argv++;
83*3e12c5d1SDavid du Colombier 	}
84*3e12c5d1SDavid du Colombier 	Strinit(&cmdstr);
85*3e12c5d1SDavid du Colombier 	Strinit0(&lastpat);
86*3e12c5d1SDavid du Colombier 	Strinit0(&lastregexp);
87*3e12c5d1SDavid du Colombier 	Strinit0(&genstr);
88*3e12c5d1SDavid du Colombier 	Strinit0(&rhs);
89*3e12c5d1SDavid du Colombier 	Strinit0(&wd);
90*3e12c5d1SDavid du Colombier 	tempfile.listptr = emalloc(0);
91*3e12c5d1SDavid du Colombier 	Strinit0(&plan9cmd);
92*3e12c5d1SDavid du Colombier 	home = getenv(HOME);
93*3e12c5d1SDavid du Colombier 	if(home == 0)
94*3e12c5d1SDavid du Colombier 		home = "/";
95*3e12c5d1SDavid du Colombier 	if(!dflag)
96*3e12c5d1SDavid du Colombier 		startup(machine, Rflag, arg, ap);
97*3e12c5d1SDavid du Colombier 	Fstart();
98*3e12c5d1SDavid du Colombier 	notify(notifyf);
99*3e12c5d1SDavid du Colombier 	if(argc>1){
100*3e12c5d1SDavid du Colombier 		for(i=0; i<argc-1; i++)
101*3e12c5d1SDavid du Colombier 			if(!setjmp(mainloop)){
102*3e12c5d1SDavid du Colombier 				t = tmpcstr(argv[i]);
103*3e12c5d1SDavid du Colombier 				Straddc(t, '\0');
104*3e12c5d1SDavid du Colombier 				Strduplstr(&genstr, t);
105*3e12c5d1SDavid du Colombier 				freetmpstr(t);
106*3e12c5d1SDavid du Colombier 				Fsetname(newfile(), &genstr);
107*3e12c5d1SDavid du Colombier 			}
108*3e12c5d1SDavid du Colombier 	}else if(!downloaded)
109*3e12c5d1SDavid du Colombier 		newfile()->state = Clean;
110*3e12c5d1SDavid du Colombier 	modnum++;
111*3e12c5d1SDavid du Colombier 	if(file.nused)
112*3e12c5d1SDavid du Colombier 		current(file.filepptr[0]);
113*3e12c5d1SDavid du Colombier 	setjmp(mainloop);
114*3e12c5d1SDavid du Colombier 	cmdloop();
115*3e12c5d1SDavid du Colombier 	trytoquit();	/* if we already q'ed, quitok will be TRUE */
116*3e12c5d1SDavid du Colombier 	exits(0);
117*3e12c5d1SDavid du Colombier }
118*3e12c5d1SDavid du Colombier 
119*3e12c5d1SDavid du Colombier void
120*3e12c5d1SDavid du Colombier usage(void)
121*3e12c5d1SDavid du Colombier {
122*3e12c5d1SDavid du Colombier 	dprint("usage: sam [-d] [-t samterm] [-s sam name] -r machine\n");
123*3e12c5d1SDavid du Colombier 	exits("usage");
124*3e12c5d1SDavid du Colombier }
125*3e12c5d1SDavid du Colombier 
126*3e12c5d1SDavid du Colombier void
127*3e12c5d1SDavid du Colombier rescue(void)
128*3e12c5d1SDavid du Colombier {
129*3e12c5d1SDavid du Colombier 	int i, nblank = 0;
130*3e12c5d1SDavid du Colombier 	File *f;
131*3e12c5d1SDavid du Colombier 	char *c;
132*3e12c5d1SDavid du Colombier 	char buf[256];
133*3e12c5d1SDavid du Colombier 
134*3e12c5d1SDavid du Colombier 	if(rescuing++)
135*3e12c5d1SDavid du Colombier 		return;
136*3e12c5d1SDavid du Colombier 	io = -1;
137*3e12c5d1SDavid du Colombier 	for(i=0; i<file.nused; i++){
138*3e12c5d1SDavid du Colombier 		f = file.filepptr[i];
139*3e12c5d1SDavid du Colombier 		if(f==cmd || f->nrunes==0 || f->state!=Dirty)
140*3e12c5d1SDavid du Colombier 			continue;
141*3e12c5d1SDavid du Colombier 		if(io == -1){
142*3e12c5d1SDavid du Colombier 			sprint(buf, "%s/sam.save", home);
143*3e12c5d1SDavid du Colombier 			io = create(buf, 1, 0777);
144*3e12c5d1SDavid du Colombier 			if(io<0)
145*3e12c5d1SDavid du Colombier 				return;
146*3e12c5d1SDavid du Colombier 		}
147*3e12c5d1SDavid du Colombier 		if(f->name.s[0]){
148*3e12c5d1SDavid du Colombier 			c = Strtoc(&f->name);
149*3e12c5d1SDavid du Colombier 			strncpy(buf, c, sizeof buf-1);
150*3e12c5d1SDavid du Colombier 			buf[sizeof buf-1] = 0;
151*3e12c5d1SDavid du Colombier 			free(c);
152*3e12c5d1SDavid du Colombier 		}else
153*3e12c5d1SDavid du Colombier 			sprint(buf, "nameless.%d", nblank++);
154*3e12c5d1SDavid du Colombier 		fprint(io, "#!/bin/rc\n/sys/lib/samsave '%s' $* <<'---%s'\n", buf, buf);
155*3e12c5d1SDavid du Colombier 		addr.r.p1 = 0, addr.r.p2 = f->nrunes;
156*3e12c5d1SDavid du Colombier 		writeio(f);
157*3e12c5d1SDavid du Colombier 		fprint(io, "\n---%s\n", (char *)buf);
158*3e12c5d1SDavid du Colombier 	}
159*3e12c5d1SDavid du Colombier }
160*3e12c5d1SDavid du Colombier 
161*3e12c5d1SDavid du Colombier void
162*3e12c5d1SDavid du Colombier panic(char *s)
163*3e12c5d1SDavid du Colombier {
164*3e12c5d1SDavid du Colombier 	int wasd;
165*3e12c5d1SDavid du Colombier 
166*3e12c5d1SDavid du Colombier 	if(!panicking++ && !setjmp(mainloop)){
167*3e12c5d1SDavid du Colombier 		wasd = downloaded;
168*3e12c5d1SDavid du Colombier 		downloaded = 0;
169*3e12c5d1SDavid du Colombier 		dprint("sam: panic: %s: %r\n", s);
170*3e12c5d1SDavid du Colombier 		if(wasd)
171*3e12c5d1SDavid du Colombier 			fprint(2, "sam: panic: %s: %r\n", s);
172*3e12c5d1SDavid du Colombier 		rescue();
173*3e12c5d1SDavid du Colombier 		abort();
174*3e12c5d1SDavid du Colombier 	}
175*3e12c5d1SDavid du Colombier }
176*3e12c5d1SDavid du Colombier 
177*3e12c5d1SDavid du Colombier void
178*3e12c5d1SDavid du Colombier hiccough(char *s)
179*3e12c5d1SDavid du Colombier {
180*3e12c5d1SDavid du Colombier 	if(rescuing)
181*3e12c5d1SDavid du Colombier 		exits("rescue");
182*3e12c5d1SDavid du Colombier 	if(s)
183*3e12c5d1SDavid du Colombier 		dprint("%s\n", s);
184*3e12c5d1SDavid du Colombier 	resetcmd();
185*3e12c5d1SDavid du Colombier 	resetxec();
186*3e12c5d1SDavid du Colombier 	resetsys();
187*3e12c5d1SDavid du Colombier 	if(io > 0)
188*3e12c5d1SDavid du Colombier 		close(io);
189*3e12c5d1SDavid du Colombier 	if(undobuf->nrunes)
190*3e12c5d1SDavid du Colombier 		Bdelete(undobuf, (Posn)0, undobuf->nrunes);
191*3e12c5d1SDavid du Colombier 	update();
192*3e12c5d1SDavid du Colombier 	if(curfile && curfile->state==Unread)
193*3e12c5d1SDavid du Colombier 		curfile->state = Clean;
194*3e12c5d1SDavid du Colombier 	if(downloaded && curfile && curfile->state!=Unread)
195*3e12c5d1SDavid du Colombier 		outTs(Hcurrent, curfile->tag);
196*3e12c5d1SDavid du Colombier 	longjmp(mainloop, 1);
197*3e12c5d1SDavid du Colombier }
198*3e12c5d1SDavid du Colombier 
199*3e12c5d1SDavid du Colombier void
200*3e12c5d1SDavid du Colombier intr(void)
201*3e12c5d1SDavid du Colombier {
202*3e12c5d1SDavid du Colombier 	error(Eintr);
203*3e12c5d1SDavid du Colombier }
204*3e12c5d1SDavid du Colombier 
205*3e12c5d1SDavid du Colombier void
206*3e12c5d1SDavid du Colombier trytoclose(File *f)
207*3e12c5d1SDavid du Colombier {
208*3e12c5d1SDavid du Colombier 	char *t;
209*3e12c5d1SDavid du Colombier 
210*3e12c5d1SDavid du Colombier 	if(f == cmd)	/* possible? */
211*3e12c5d1SDavid du Colombier 		return;
212*3e12c5d1SDavid du Colombier 	if(f->state==Dirty && !f->closeok){
213*3e12c5d1SDavid du Colombier 		f->closeok = TRUE;
214*3e12c5d1SDavid du Colombier 		if(f->name.s[0]){
215*3e12c5d1SDavid du Colombier 			t = Strtoc(&f->name);
216*3e12c5d1SDavid du Colombier 			error_s(Emodified, t);
217*3e12c5d1SDavid du Colombier 			free(t);
218*3e12c5d1SDavid du Colombier 		}else
219*3e12c5d1SDavid du Colombier 			error_s(Emodified, "nameless file");
220*3e12c5d1SDavid du Colombier 	}
221*3e12c5d1SDavid du Colombier 	if(downloaded && f->rasp)
222*3e12c5d1SDavid du Colombier 		outTs(Hclose, f->tag);
223*3e12c5d1SDavid du Colombier 	delfile(f);
224*3e12c5d1SDavid du Colombier 	if(f == curfile)
225*3e12c5d1SDavid du Colombier 		current((File *)0);
226*3e12c5d1SDavid du Colombier }
227*3e12c5d1SDavid du Colombier 
228*3e12c5d1SDavid du Colombier void
229*3e12c5d1SDavid du Colombier trytoquit(void)
230*3e12c5d1SDavid du Colombier {
231*3e12c5d1SDavid du Colombier 	int c;
232*3e12c5d1SDavid du Colombier 	File *f;
233*3e12c5d1SDavid du Colombier 
234*3e12c5d1SDavid du Colombier 	if(!quitok)
235*3e12c5d1SDavid du Colombier 		for(c = 0; c<file.nused; c++){
236*3e12c5d1SDavid du Colombier 			f = file.filepptr[c];
237*3e12c5d1SDavid du Colombier 			if(f!=cmd && f->state==Dirty){
238*3e12c5d1SDavid du Colombier 				quitok = TRUE;
239*3e12c5d1SDavid du Colombier 				eof = FALSE;
240*3e12c5d1SDavid du Colombier 				error(Echanges);
241*3e12c5d1SDavid du Colombier 			}
242*3e12c5d1SDavid du Colombier 		}
243*3e12c5d1SDavid du Colombier }
244*3e12c5d1SDavid du Colombier 
245*3e12c5d1SDavid du Colombier void
246*3e12c5d1SDavid du Colombier load(File *f)
247*3e12c5d1SDavid du Colombier {
248*3e12c5d1SDavid du Colombier 	Address saveaddr;
249*3e12c5d1SDavid du Colombier 
250*3e12c5d1SDavid du Colombier 	Strduplstr(&genstr, &f->name);
251*3e12c5d1SDavid du Colombier 	filename(f);
252*3e12c5d1SDavid du Colombier 	if(f->name.s[0]){
253*3e12c5d1SDavid du Colombier 		saveaddr = addr;
254*3e12c5d1SDavid du Colombier 		edit(f, 'I');
255*3e12c5d1SDavid du Colombier 		addr = saveaddr;
256*3e12c5d1SDavid du Colombier 	}else
257*3e12c5d1SDavid du Colombier 		f->state = Clean;
258*3e12c5d1SDavid du Colombier 	Fupdate(f, TRUE, TRUE);
259*3e12c5d1SDavid du Colombier }
260*3e12c5d1SDavid du Colombier 
261*3e12c5d1SDavid du Colombier void
262*3e12c5d1SDavid du Colombier cmdupdate(void)
263*3e12c5d1SDavid du Colombier {
264*3e12c5d1SDavid du Colombier 	if(cmd && cmd->mod!=0){
265*3e12c5d1SDavid du Colombier 		Fupdate(cmd, FALSE, downloaded);
266*3e12c5d1SDavid du Colombier 		cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->nrunes;
267*3e12c5d1SDavid du Colombier 		telldot(cmd);
268*3e12c5d1SDavid du Colombier 	}
269*3e12c5d1SDavid du Colombier }
270*3e12c5d1SDavid du Colombier 
271*3e12c5d1SDavid du Colombier void
272*3e12c5d1SDavid du Colombier update(void)
273*3e12c5d1SDavid du Colombier {
274*3e12c5d1SDavid du Colombier 	int i, anymod;
275*3e12c5d1SDavid du Colombier 	File *f;
276*3e12c5d1SDavid du Colombier 
277*3e12c5d1SDavid du Colombier 	settempfile();
278*3e12c5d1SDavid du Colombier 	for(anymod = i=0; i<tempfile.nused; i++){
279*3e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
280*3e12c5d1SDavid du Colombier 		if(f==cmd)	/* cmd gets done in main() */
281*3e12c5d1SDavid du Colombier 			continue;
282*3e12c5d1SDavid du Colombier 		if(f->mod==modnum && Fupdate(f, FALSE, downloaded))
283*3e12c5d1SDavid du Colombier 			anymod++;
284*3e12c5d1SDavid du Colombier 		if(f->rasp)
285*3e12c5d1SDavid du Colombier 			telldot(f);
286*3e12c5d1SDavid du Colombier 	}
287*3e12c5d1SDavid du Colombier 	if(anymod)
288*3e12c5d1SDavid du Colombier 		modnum++;
289*3e12c5d1SDavid du Colombier }
290*3e12c5d1SDavid du Colombier 
291*3e12c5d1SDavid du Colombier File *
292*3e12c5d1SDavid du Colombier current(File *f)
293*3e12c5d1SDavid du Colombier {
294*3e12c5d1SDavid du Colombier 	return curfile = f;
295*3e12c5d1SDavid du Colombier }
296*3e12c5d1SDavid du Colombier 
297*3e12c5d1SDavid du Colombier void
298*3e12c5d1SDavid du Colombier edit(File *f, int cmd)
299*3e12c5d1SDavid du Colombier {
300*3e12c5d1SDavid du Colombier 	int empty = TRUE;
301*3e12c5d1SDavid du Colombier 	Posn p;
302*3e12c5d1SDavid du Colombier 	int nulls;
303*3e12c5d1SDavid du Colombier 
304*3e12c5d1SDavid du Colombier 	if(cmd == 'r')
305*3e12c5d1SDavid du Colombier 		Fdelete(f, addr.r.p1, addr.r.p2);
306*3e12c5d1SDavid du Colombier 	if(cmd=='e' || cmd=='I'){
307*3e12c5d1SDavid du Colombier 		Fdelete(f, (Posn)0, f->nrunes);
308*3e12c5d1SDavid du Colombier 		addr.r.p2 = f->nrunes;
309*3e12c5d1SDavid du Colombier 	}else if(f->nrunes!=0 || (f->name.s[0] && Strcmp(&genstr, &f->name)!=0))
310*3e12c5d1SDavid du Colombier 		empty = FALSE;
311*3e12c5d1SDavid du Colombier 	if((io = open(genc, OREAD))<0)
312*3e12c5d1SDavid du Colombier 		error_s(Eopen, genc);
313*3e12c5d1SDavid du Colombier 	p = readio(f, &nulls, empty);
314*3e12c5d1SDavid du Colombier 	closeio((cmd=='e' || cmd=='I')? -1 : p);
315*3e12c5d1SDavid du Colombier 	if(cmd == 'r')
316*3e12c5d1SDavid du Colombier 		f->ndot.r.p1 = addr.r.p2, f->ndot.r.p2 = addr.r.p2+p;
317*3e12c5d1SDavid du Colombier 	else
318*3e12c5d1SDavid du Colombier 		f->ndot.r.p1 = f->ndot.r.p2 = 0;
319*3e12c5d1SDavid du Colombier 	quitok = f->closeok = empty;
320*3e12c5d1SDavid du Colombier 	state(f, empty && !nulls? Clean : Dirty);
321*3e12c5d1SDavid du Colombier 	if(cmd == 'e')
322*3e12c5d1SDavid du Colombier 		filename(f);
323*3e12c5d1SDavid du Colombier }
324*3e12c5d1SDavid du Colombier 
325*3e12c5d1SDavid du Colombier int
326*3e12c5d1SDavid du Colombier getname(File *f, String *s, int save)
327*3e12c5d1SDavid du Colombier {
328*3e12c5d1SDavid du Colombier 	int c, i;
329*3e12c5d1SDavid du Colombier 
330*3e12c5d1SDavid du Colombier 	Strzero(&genstr);
331*3e12c5d1SDavid du Colombier 	if(genc){
332*3e12c5d1SDavid du Colombier 		free(genc);
333*3e12c5d1SDavid du Colombier 		genc = 0;
334*3e12c5d1SDavid du Colombier 	}
335*3e12c5d1SDavid du Colombier 	if(s==0 || (c = s->s[0])==0){		/* no name provided */
336*3e12c5d1SDavid du Colombier 		if(f)
337*3e12c5d1SDavid du Colombier 			Strduplstr(&genstr, &f->name);
338*3e12c5d1SDavid du Colombier 		else
339*3e12c5d1SDavid du Colombier 			Straddc(&genstr, '\0');
340*3e12c5d1SDavid du Colombier 		goto Return;
341*3e12c5d1SDavid du Colombier 	}
342*3e12c5d1SDavid du Colombier 	if(c!=' ' && c!='\t')
343*3e12c5d1SDavid du Colombier 		error(Eblank);
344*3e12c5d1SDavid du Colombier 	for(i=0; (c=s->s[i])==' ' || c=='\t'; i++)
345*3e12c5d1SDavid du Colombier 		;
346*3e12c5d1SDavid du Colombier 	while(s->s[i] > ' ')
347*3e12c5d1SDavid du Colombier 		Straddc(&genstr, s->s[i++]);
348*3e12c5d1SDavid du Colombier 	if(s->s[i])
349*3e12c5d1SDavid du Colombier 		error(Enewline);
350*3e12c5d1SDavid du Colombier 	Straddc(&genstr, '\0');
351*3e12c5d1SDavid du Colombier 	if(f && (save || f->name.s[0]==0)){
352*3e12c5d1SDavid du Colombier 		Fsetname(f, &genstr);
353*3e12c5d1SDavid du Colombier 		if(Strcmp(&f->name, &genstr)){
354*3e12c5d1SDavid du Colombier 			quitok = f->closeok = FALSE;
355*3e12c5d1SDavid du Colombier 			f->inumber = 0;
356*3e12c5d1SDavid du Colombier 			f->date = 0;
357*3e12c5d1SDavid du Colombier 			state(f, Dirty); /* if it's 'e', fix later */
358*3e12c5d1SDavid du Colombier 		}
359*3e12c5d1SDavid du Colombier 	}
360*3e12c5d1SDavid du Colombier     Return:
361*3e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
362*3e12c5d1SDavid du Colombier 	return genstr.n-1;	/* strlen(name) */
363*3e12c5d1SDavid du Colombier }
364*3e12c5d1SDavid du Colombier 
365*3e12c5d1SDavid du Colombier void
366*3e12c5d1SDavid du Colombier filename(File *f)
367*3e12c5d1SDavid du Colombier {
368*3e12c5d1SDavid du Colombier 	if(genc)
369*3e12c5d1SDavid du Colombier 		free(genc);
370*3e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
371*3e12c5d1SDavid du Colombier 	dprint("%c%c%c %s\n", " '"[f->state==Dirty],
372*3e12c5d1SDavid du Colombier 		"-+"[f->rasp!=0], " ."[f==curfile], genc);
373*3e12c5d1SDavid du Colombier }
374*3e12c5d1SDavid du Colombier 
375*3e12c5d1SDavid du Colombier void
376*3e12c5d1SDavid du Colombier undostep(File *f)
377*3e12c5d1SDavid du Colombier {
378*3e12c5d1SDavid du Colombier 	Buffer *t;
379*3e12c5d1SDavid du Colombier 	int changes;
380*3e12c5d1SDavid du Colombier 	Mark mark;
381*3e12c5d1SDavid du Colombier 
382*3e12c5d1SDavid du Colombier 	t = f->transcript;
383*3e12c5d1SDavid du Colombier 	changes = Fupdate(f, TRUE, TRUE);
384*3e12c5d1SDavid du Colombier 	Bread(t, (Rune*)&mark, (sizeof mark)/RUNESIZE, f->markp);
385*3e12c5d1SDavid du Colombier 	Bdelete(t, f->markp, t->nrunes);
386*3e12c5d1SDavid du Colombier 	f->markp = mark.p;
387*3e12c5d1SDavid du Colombier 	f->dot.r = mark.dot;
388*3e12c5d1SDavid du Colombier 	f->ndot.r = mark.dot;
389*3e12c5d1SDavid du Colombier 	f->mark = mark.mark;
390*3e12c5d1SDavid du Colombier 	f->mod = mark.m;
391*3e12c5d1SDavid du Colombier 	f->closeok = mark.s1!=Dirty;
392*3e12c5d1SDavid du Colombier 	if(mark.s1==Dirty)
393*3e12c5d1SDavid du Colombier 		quitok = FALSE;
394*3e12c5d1SDavid du Colombier 	if(f->state==Clean && mark.s1==Clean && changes)
395*3e12c5d1SDavid du Colombier 		state(f, Dirty);
396*3e12c5d1SDavid du Colombier 	else
397*3e12c5d1SDavid du Colombier 		state(f, mark.s1);
398*3e12c5d1SDavid du Colombier }
399*3e12c5d1SDavid du Colombier 
400*3e12c5d1SDavid du Colombier void
401*3e12c5d1SDavid du Colombier undo(void)
402*3e12c5d1SDavid du Colombier {
403*3e12c5d1SDavid du Colombier 	File *f;
404*3e12c5d1SDavid du Colombier 	int i;
405*3e12c5d1SDavid du Colombier 	Mod max;
406*3e12c5d1SDavid du Colombier 
407*3e12c5d1SDavid du Colombier 	if((max = curfile->mod)==0)
408*3e12c5d1SDavid du Colombier 		return;
409*3e12c5d1SDavid du Colombier 	settempfile();
410*3e12c5d1SDavid du Colombier 	for(i = 0; i<tempfile.nused; i++){
411*3e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
412*3e12c5d1SDavid du Colombier 		if(f!=cmd && f->mod==max)
413*3e12c5d1SDavid du Colombier 			undostep(f);
414*3e12c5d1SDavid du Colombier 	}
415*3e12c5d1SDavid du Colombier }
416*3e12c5d1SDavid du Colombier 
417*3e12c5d1SDavid du Colombier void
418*3e12c5d1SDavid du Colombier readcmd(String *s)
419*3e12c5d1SDavid du Colombier {
420*3e12c5d1SDavid du Colombier 	if(flist == 0)
421*3e12c5d1SDavid du Colombier 		(flist = Fopen())->state = Clean;
422*3e12c5d1SDavid du Colombier 	addr.r.p1 = 0, addr.r.p2 = flist->nrunes;
423*3e12c5d1SDavid du Colombier 	plan9(flist, '<', s, FALSE);
424*3e12c5d1SDavid du Colombier 	Fupdate(flist, FALSE, FALSE);
425*3e12c5d1SDavid du Colombier 	flist->mod = 0;
426*3e12c5d1SDavid du Colombier 	Strzero(&genstr);
427*3e12c5d1SDavid du Colombier 	Strinsure(&genstr, flist->nrunes);
428*3e12c5d1SDavid du Colombier 	Fchars(flist, genbuf, (Posn)0, flist->nrunes);
429*3e12c5d1SDavid du Colombier 	memmove(genstr.s, genbuf, flist->nrunes*RUNESIZE);
430*3e12c5d1SDavid du Colombier 	genstr.n = flist->nrunes;
431*3e12c5d1SDavid du Colombier 	Straddc(&genstr, '\0');
432*3e12c5d1SDavid du Colombier }
433*3e12c5d1SDavid du Colombier 
434*3e12c5d1SDavid du Colombier void
435*3e12c5d1SDavid du Colombier cd(String *str)
436*3e12c5d1SDavid du Colombier {
437*3e12c5d1SDavid du Colombier 	int i;
438*3e12c5d1SDavid du Colombier 	File *f;
439*3e12c5d1SDavid du Colombier 	String *t;
440*3e12c5d1SDavid du Colombier 
441*3e12c5d1SDavid du Colombier 	t = tmpcstr("/bin/pwd");
442*3e12c5d1SDavid du Colombier 	Straddc(t, '\0');
443*3e12c5d1SDavid du Colombier 	readcmd(t);
444*3e12c5d1SDavid du Colombier 	freetmpstr(t);
445*3e12c5d1SDavid du Colombier 	Strduplstr(&wd, &genstr);
446*3e12c5d1SDavid du Colombier 	if(wd.s[0] == 0){
447*3e12c5d1SDavid du Colombier 		wd.n = 0;
448*3e12c5d1SDavid du Colombier 		warn(Wpwd);
449*3e12c5d1SDavid du Colombier 	}else if(wd.s[wd.n-2] == '\n'){
450*3e12c5d1SDavid du Colombier 		--wd.n;
451*3e12c5d1SDavid du Colombier 		wd.s[wd.n-1]='/';
452*3e12c5d1SDavid du Colombier 	}
453*3e12c5d1SDavid du Colombier 	if(chdir(getname((File *)0, str, FALSE)? genc : home))
454*3e12c5d1SDavid du Colombier 		syserror("chdir");
455*3e12c5d1SDavid du Colombier 	settempfile();
456*3e12c5d1SDavid du Colombier 	for(i=0; i<tempfile.nused; i++){
457*3e12c5d1SDavid du Colombier 		f = tempfile.filepptr[i];
458*3e12c5d1SDavid du Colombier 		if(f!=cmd && f->name.s[0]!='/' && f->name.s[0]!=0){
459*3e12c5d1SDavid du Colombier 			Strinsert(&f->name, &wd, (Posn)0);
460*3e12c5d1SDavid du Colombier 			sortname(f);
461*3e12c5d1SDavid du Colombier 		}
462*3e12c5d1SDavid du Colombier 	}
463*3e12c5d1SDavid du Colombier }
464*3e12c5d1SDavid du Colombier 
465*3e12c5d1SDavid du Colombier int
466*3e12c5d1SDavid du Colombier loadflist(String *s)
467*3e12c5d1SDavid du Colombier {
468*3e12c5d1SDavid du Colombier 	int c, i;
469*3e12c5d1SDavid du Colombier 
470*3e12c5d1SDavid du Colombier 	c = s->s[0];
471*3e12c5d1SDavid du Colombier 	for(i = 0; s->s[i]==' ' || s->s[i]=='\t'; i++)
472*3e12c5d1SDavid du Colombier 		;
473*3e12c5d1SDavid du Colombier 	if((c==' ' || c=='\t') && s->s[i]!='\n'){
474*3e12c5d1SDavid du Colombier 		if(s->s[i]=='<'){
475*3e12c5d1SDavid du Colombier 			Strdelete(s, 0L, (long)i+1);
476*3e12c5d1SDavid du Colombier 			readcmd(s);
477*3e12c5d1SDavid du Colombier 		}else{
478*3e12c5d1SDavid du Colombier 			Strzero(&genstr);
479*3e12c5d1SDavid du Colombier 			while((c = s->s[i++]) && c!='\n')
480*3e12c5d1SDavid du Colombier 				Straddc(&genstr, c);
481*3e12c5d1SDavid du Colombier 			Straddc(&genstr, '\0');
482*3e12c5d1SDavid du Colombier 		}
483*3e12c5d1SDavid du Colombier 	}else{
484*3e12c5d1SDavid du Colombier 		if(c != '\n')
485*3e12c5d1SDavid du Colombier 			error(Eblank);
486*3e12c5d1SDavid du Colombier 		Strdupl(&genstr, empty);
487*3e12c5d1SDavid du Colombier 	}
488*3e12c5d1SDavid du Colombier 	if(genc)
489*3e12c5d1SDavid du Colombier 		free(genc);
490*3e12c5d1SDavid du Colombier 	genc = Strtoc(&genstr);
491*3e12c5d1SDavid du Colombier 	return genstr.s[0];
492*3e12c5d1SDavid du Colombier }
493*3e12c5d1SDavid du Colombier 
494*3e12c5d1SDavid du Colombier File *
495*3e12c5d1SDavid du Colombier readflist(int readall, int delete)
496*3e12c5d1SDavid du Colombier {
497*3e12c5d1SDavid du Colombier 	Posn i;
498*3e12c5d1SDavid du Colombier 	int c;
499*3e12c5d1SDavid du Colombier 	File *f;
500*3e12c5d1SDavid du Colombier 	String *t;
501*3e12c5d1SDavid du Colombier 
502*3e12c5d1SDavid du Colombier 	for(i=0,f=0; f==0 || readall || delete; i++){	/* ++ skips blank */
503*3e12c5d1SDavid du Colombier 		Strdelete(&genstr, (Posn)0, i);
504*3e12c5d1SDavid du Colombier 		for(i=0; (c = genstr.s[i])==' ' || c=='\t' || c=='\n'; i++)
505*3e12c5d1SDavid du Colombier 			;
506*3e12c5d1SDavid du Colombier 		if(i >= genstr.n)
507*3e12c5d1SDavid du Colombier 			break;
508*3e12c5d1SDavid du Colombier 		Strdelete(&genstr, (Posn)0, i);
509*3e12c5d1SDavid du Colombier 		for(i=0; (c=genstr.s[i]) && c!=' ' && c!='\t' && c!='\n'; i++)
510*3e12c5d1SDavid du Colombier 			;
511*3e12c5d1SDavid du Colombier 
512*3e12c5d1SDavid du Colombier 		if(i == 0)
513*3e12c5d1SDavid du Colombier 			break;
514*3e12c5d1SDavid du Colombier 		genstr.s[i] = 0;
515*3e12c5d1SDavid du Colombier 		t = tmprstr(genstr.s, i+1);
516*3e12c5d1SDavid du Colombier 		f = lookfile(t);
517*3e12c5d1SDavid du Colombier 		if(delete){
518*3e12c5d1SDavid du Colombier 			if(f == 0)
519*3e12c5d1SDavid du Colombier 				warn_S(Wfile, t);
520*3e12c5d1SDavid du Colombier 			else
521*3e12c5d1SDavid du Colombier 				trytoclose(f);
522*3e12c5d1SDavid du Colombier 		}else if(f==0 && readall)
523*3e12c5d1SDavid du Colombier 			Fsetname(f = newfile(), t);
524*3e12c5d1SDavid du Colombier 	}
525*3e12c5d1SDavid du Colombier 	return f;
526*3e12c5d1SDavid du Colombier }
527*3e12c5d1SDavid du Colombier 
528*3e12c5d1SDavid du Colombier File *
529*3e12c5d1SDavid du Colombier tofile(String *s)
530*3e12c5d1SDavid du Colombier {
531*3e12c5d1SDavid du Colombier 	File *f;
532*3e12c5d1SDavid du Colombier 
533*3e12c5d1SDavid du Colombier 	if(s->s[0] != ' ')
534*3e12c5d1SDavid du Colombier 		error(Eblank);
535*3e12c5d1SDavid du Colombier 	if(loadflist(s) == 0){
536*3e12c5d1SDavid du Colombier 		f = lookfile(&genstr);	/* empty string ==> nameless file */
537*3e12c5d1SDavid du Colombier 		if(f == 0)
538*3e12c5d1SDavid du Colombier 			error_s(Emenu, genc);
539*3e12c5d1SDavid du Colombier 	}else if((f=readflist(FALSE, FALSE)) == 0)
540*3e12c5d1SDavid du Colombier 		error_s(Emenu, genc);
541*3e12c5d1SDavid du Colombier 	return current(f);
542*3e12c5d1SDavid du Colombier }
543*3e12c5d1SDavid du Colombier 
544*3e12c5d1SDavid du Colombier File *
545*3e12c5d1SDavid du Colombier getfile(String *s)
546*3e12c5d1SDavid du Colombier {
547*3e12c5d1SDavid du Colombier 	File *f;
548*3e12c5d1SDavid du Colombier 
549*3e12c5d1SDavid du Colombier 	if(loadflist(s) == 0)
550*3e12c5d1SDavid du Colombier 		Fsetname(f = newfile(), &genstr);
551*3e12c5d1SDavid du Colombier 	else if((f=readflist(TRUE, FALSE)) == 0)
552*3e12c5d1SDavid du Colombier 		error(Eblank);
553*3e12c5d1SDavid du Colombier 	return current(f);
554*3e12c5d1SDavid du Colombier }
555*3e12c5d1SDavid du Colombier 
556*3e12c5d1SDavid du Colombier void
557*3e12c5d1SDavid du Colombier closefiles(File *f, String *s)
558*3e12c5d1SDavid du Colombier {
559*3e12c5d1SDavid du Colombier 	if(s->s[0] == 0){
560*3e12c5d1SDavid du Colombier 		if(f == 0)
561*3e12c5d1SDavid du Colombier 			error(Enofile);
562*3e12c5d1SDavid du Colombier 		trytoclose(f);
563*3e12c5d1SDavid du Colombier 		return;
564*3e12c5d1SDavid du Colombier 	}
565*3e12c5d1SDavid du Colombier 	if(s->s[0] != ' ')
566*3e12c5d1SDavid du Colombier 		error(Eblank);
567*3e12c5d1SDavid du Colombier 	if(loadflist(s) == 0)
568*3e12c5d1SDavid du Colombier 		error(Enewline);
569*3e12c5d1SDavid du Colombier 	readflist(FALSE, TRUE);
570*3e12c5d1SDavid du Colombier }
571*3e12c5d1SDavid du Colombier 
572*3e12c5d1SDavid du Colombier void
573*3e12c5d1SDavid du Colombier copy(File *f, Address addr2)
574*3e12c5d1SDavid du Colombier {
575*3e12c5d1SDavid du Colombier 	Posn p;
576*3e12c5d1SDavid du Colombier 	int ni;
577*3e12c5d1SDavid du Colombier 	for(p=addr.r.p1; p<addr.r.p2; p+=ni){
578*3e12c5d1SDavid du Colombier 		ni = addr.r.p2-p;
579*3e12c5d1SDavid du Colombier 		if(ni > BLOCKSIZE)
580*3e12c5d1SDavid du Colombier 			ni = BLOCKSIZE;
581*3e12c5d1SDavid du Colombier 		Fchars(f, genbuf, p, p+ni);
582*3e12c5d1SDavid du Colombier 		Finsert(addr2.f, tmprstr(genbuf, ni), addr2.r.p2);
583*3e12c5d1SDavid du Colombier 	}
584*3e12c5d1SDavid du Colombier 	addr2.f->ndot.r.p2 = addr2.r.p2+(f->dot.r.p2-f->dot.r.p1);
585*3e12c5d1SDavid du Colombier 	addr2.f->ndot.r.p1 = addr2.r.p2;
586*3e12c5d1SDavid du Colombier }
587*3e12c5d1SDavid du Colombier 
588*3e12c5d1SDavid du Colombier void
589*3e12c5d1SDavid du Colombier move(File *f, Address addr2)
590*3e12c5d1SDavid du Colombier {
591*3e12c5d1SDavid du Colombier 	if(addr.r.p2 <= addr2.r.p2){
592*3e12c5d1SDavid du Colombier 		Fdelete(f, addr.r.p1, addr.r.p2);
593*3e12c5d1SDavid du Colombier 		copy(f, addr2);
594*3e12c5d1SDavid du Colombier 	}else if(addr.r.p1 >= addr2.r.p2){
595*3e12c5d1SDavid du Colombier 		copy(f, addr2);
596*3e12c5d1SDavid du Colombier 		Fdelete(f, addr.r.p1, addr.r.p2);
597*3e12c5d1SDavid du Colombier 	}else
598*3e12c5d1SDavid du Colombier 		error(Eoverlap);
599*3e12c5d1SDavid du Colombier }
600*3e12c5d1SDavid du Colombier 
601*3e12c5d1SDavid du Colombier Posn
602*3e12c5d1SDavid du Colombier nlcount(File *f, Posn p0, Posn p1)
603*3e12c5d1SDavid du Colombier {
604*3e12c5d1SDavid du Colombier 	Posn nl = 0;
605*3e12c5d1SDavid du Colombier 
606*3e12c5d1SDavid du Colombier 	Fgetcset(f, p0);
607*3e12c5d1SDavid du Colombier 	while(p0++<p1)
608*3e12c5d1SDavid du Colombier 		if(Fgetc(f)=='\n')
609*3e12c5d1SDavid du Colombier 			nl++;
610*3e12c5d1SDavid du Colombier 	return nl;
611*3e12c5d1SDavid du Colombier }
612*3e12c5d1SDavid du Colombier 
613*3e12c5d1SDavid du Colombier void
614*3e12c5d1SDavid du Colombier printposn(File *f, int charsonly)
615*3e12c5d1SDavid du Colombier {
616*3e12c5d1SDavid du Colombier 	Posn l1, l2;
617*3e12c5d1SDavid du Colombier 
618*3e12c5d1SDavid du Colombier 	if(!charsonly){
619*3e12c5d1SDavid du Colombier 		l1 = 1+nlcount(f, (Posn)0, addr.r.p1);
620*3e12c5d1SDavid du Colombier 		l2 = l1+nlcount(f, addr.r.p1, addr.r.p2);
621*3e12c5d1SDavid du Colombier 		/* check if addr ends with '\n' */
622*3e12c5d1SDavid du Colombier 		if(addr.r.p2>0 && addr.r.p2>addr.r.p1 && (Fgetcset(f, addr.r.p2-1),Fgetc(f)=='\n'))
623*3e12c5d1SDavid du Colombier 			--l2;
624*3e12c5d1SDavid du Colombier 		dprint("%lud", l1);
625*3e12c5d1SDavid du Colombier 		if(l2 != l1)
626*3e12c5d1SDavid du Colombier 			dprint(",%lud", l2);
627*3e12c5d1SDavid du Colombier 		dprint("; ");
628*3e12c5d1SDavid du Colombier 	}
629*3e12c5d1SDavid du Colombier 	dprint("#%lud", addr.r.p1);
630*3e12c5d1SDavid du Colombier 	if(addr.r.p2 != addr.r.p1)
631*3e12c5d1SDavid du Colombier 		dprint(",#%lud", addr.r.p2);
632*3e12c5d1SDavid du Colombier 	dprint("\n");
633*3e12c5d1SDavid du Colombier }
634*3e12c5d1SDavid du Colombier 
635*3e12c5d1SDavid du Colombier void
636*3e12c5d1SDavid du Colombier settempfile(void)
637*3e12c5d1SDavid du Colombier {
638*3e12c5d1SDavid du Colombier 	if(tempfile.nalloc < file.nused){
639*3e12c5d1SDavid du Colombier 		free(tempfile.listptr);
640*3e12c5d1SDavid du Colombier 		tempfile.listptr = emalloc(sizeof(*tempfile.filepptr)*file.nused);
641*3e12c5d1SDavid du Colombier 		tempfile.nalloc = file.nused;
642*3e12c5d1SDavid du Colombier 	}
643*3e12c5d1SDavid du Colombier 	tempfile.nused = file.nused;
644*3e12c5d1SDavid du Colombier 	memmove(&tempfile.filepptr[0], &file.filepptr[0], file.nused*sizeof(File*));
645*3e12c5d1SDavid du Colombier }
646