|
|
1.1 root 1: #include "sam.h"
2: #include <setjmp.h>
3: #include <signal.h>
4:
5: typedef struct Patlist{
6: int nalloc;
7: int nused;
8: String **ptr;
9: }Patlist;
10:
11: uchar genbuf[BLOCKSIZE];
12: char *home;
13: int io;
14: int panicking;
15: int rescuing;
16: Mod modnum;
17: String genstr;
18: String rhs;
19: String wd;
20: String cmdstr;
21: int intr();
22: int rescue();
23: char *getenv();
24: File *current();
25: File *tofile();
26: File *getfile();
27: File *curfile;
28: File *flist;
29: File *cmd;
30: jmp_buf mainloop;
31: Filelist tempfile;
32: int quitok=TRUE;
33: Patlist globstr;
34: Patlist pattern;
35: int downloaded;
36: int dflag;
37: int Rflag;
38: int zflag;
39: char *machine;
40: int dounlock;
41:
42: main(argc, argv)
43: uchar *argv[];
44: {
45: register i;
46: int (*onintr)();
47: while(argc>1 && argv[1][0]=='-'){
48: switch(argv[1][1]){
49: case 'd':
50: dflag++;
51: break;
52: case 'r':
53: --argc, argv++;
54: if(argc==1){
55: dprint("usage: sam [-d] -r machine\n");
56: return 1;
57: }
58: machine=(char *)argv[1];
59: break;
60: case 'z':
61: zflag++;
62: break;
63: case 'R':
64: Rflag++;
65: break;
66: #ifdef SUN
67: case 't':
68: case 'x':
69: case '=':
70: case 'W':
71: sunarg(&argv, &argc);
72: break;
73: #endif
74: default:
75: dprint("sam: unknown flag %c\n", argv[1][1]);
76: return 1;
77: }
78: --argc, argv++;
79: }
80: allocinit();
81: Fstart();
82: strinit(&cmdstr);
83: strinit(&lastpat);
84: strinit(&lastregexp);
85: strinit(&genstr);
86: strinit(&rhs);
87: strinit(&wd);
88: gcnew(tempfile.ptr, 0);
89: strinit(&unixcmd);
90: straddc(&unixcmd, '\0');
91: home=getenv("HOME");
92: if(home==0)
93: home="/tmp";
94: if(!dflag){
95: if(machine)
96: #ifdef SUN
97: connectboot(machine,zflag); /* doesn't return */
98: #else
99: connectto(machine);
100: #endif
101: if(!Rflag){
102: if(!bootterm(zflag))
103: return 1;
104: }
105: rawmode(1);
106: if(machine)
107: join();
108: downloaded=1;
109: }
110: if(argc>1){
111: for(i=1; i<argc; i++)
112: if(!setjmp(mainloop)){
113: strdup(&genstr, argv[i]);
114: Fsetname(newfile());
115: }
116: }else if(!downloaded)
117: newfile()->state=Clean;
118: modnum++;
119: onintr=signal(SIGINT, intr);
120: if(onintr)
121: signal(SIGINT, onintr);
122: onintr=signal(SIGHUP, rescue);
123: if(onintr)
124: signal(SIGHUP, onintr);
125: if(file.nused)
126: current(file.ptr[0]);
127: (void)setjmp(mainloop);
128: cmdloop();
129: trytoquit(); /* if we already q'ed, quitok will be TRUE */
130: if(downloaded)
131: rawmode(0);
132: return 0;
133: }
134: panic(s)
135: char *s;
136: {
137: if(!panicking++ && !setjmp(mainloop)){
138: dprint("sam: panic: %s\n", s);
139: rescue();
140: }
141: abort();
142: }
143: rescue(){
144: register i, nblank=0;
145: register File *f;
146: uchar buf[128];
147: signal(SIGHUP, SIG_IGN);
148: if(rescuing++)
149: exit(1);
150: io= -1;
151: for(i=0; i<file.nused; i++){
152: f=file.ptr[i];
153: if(f==cmd || f->nbytes==0 || f->state!=Dirty)
154: continue;
155: if(io==-1){
156: strcpy(buf, (uchar *)home);
157: strcpy(buf+strlen(buf), (uchar *)"/sam.save");
158: io=creat((char *)buf, 0777);
159: if(io<0)
160: return;
161: }
162: strcpy(buf, f->name.s);
163: if(buf[0]==0)
164: sprint(buf, "nameless.%d", nblank++);
165: fprint(io, "/usr/jerq/lib/samsave '%s' $* <<'---%s'\n",
166: (char *)buf, (char *)buf);
167: addr.r.p1=0, addr.r.p2=f->nbytes;
168: writeio(f);
169: fprint(io, "\n---%s\n", (char *)buf);
170: }
171: if(panicking)
172: abort();
173: exit(0);
174: }
175: hiccough(s)
176: char *s;
177: {
178: if(rescuing)
179: exit(1);
180: if(s)
181: dprint("%s\n", s);
182: resetcmd();
183: resetxec();
184: compactok();
185: if(io>0)
186: close(io);
187: if(undobuf->nbytes)
188: Bdelete(undobuf, (Posn)0, undobuf->nbytes);
189: update();
190: if(curfile && curfile->state==Unread)
191: curfile->state=Clean;
192: dounlock=TRUE;
193: if(downloaded && curfile && curfile->state!=Unread)
194: outTs(Hcurrent, curfile->tag);
195: longjmp(mainloop, 1);
196: }
197: intr(){
198: signal(SIGINT, intr);
199: error(Eintr);
200: }
201: trytoclose(f)
202: register File *f;
203: {
204: if(f==cmd) /* possible? */
205: return;
206: if(f->state==Dirty && !f->closeok){
207: f->closeok=TRUE;
208: error_s(Emodified,
209: f->name.s[0]?(char *)f->name.s : "nameless file");
210: }
211: if(downloaded && f->rasp)
212: outTs(Hclose, f->tag);
213: delfile(f);
214: if(f==curfile)
215: current((File *)0);
216: }
217: trytoquit(){
218: register c;
219: register File *f;
220: extern int eof;
221: if(!quitok)
222: for(c=0; c<file.nused; c++){
223: f=file.ptr[c];
224: if(f!=cmd && f->state==Dirty){
225: quitok=TRUE;
226: eof=FALSE;
227: error(Echanges);
228: }
229: }
230: }
231: load(f)
232: register File *f;
233: {
234: Address saveaddr;
235: strdupstr(&genstr, &f->name);
236: filename(f);
237: if(f->name.s[0]){
238: saveaddr=addr;
239: edit(f, 'I');
240: addr=saveaddr;
241: }else
242: f->state=Clean;
243: Fupdate(f, FALSE, TRUE);
244: }
245: update(){
246: register i, anymod;
247: register File *f;
248: settempfile();
249: for(anymod=i=0; i<tempfile.nused; i++){
250: f=tempfile.ptr[i];
251: if(f==cmd) /* cmd gets done in main() */
252: continue;
253: if(f->mod==modnum && Fupdate(f, FALSE, downloaded))
254: anymod++;
255: if(f->rasp)
256: telldot(f);
257: }
258: if(anymod)
259: modnum++;
260: }
261: File *
262: current(f)
263: register File *f;
264: {
265: return curfile=f;
266: }
267: edit(f, cmd)
268: register File *f;
269: {
270: register empty=TRUE;
271: Posn p;
272: int nonascii;
273: if(cmd=='r')
274: Fdelete(f, addr.r.p1, addr.r.p2);
275: if(cmd=='e' || cmd=='I'){
276: Fdelete(f, (Posn)0, f->nbytes);
277: addr.r.p2=f->nbytes;
278: }else if(f->nbytes!=0 || (f->name.s[0] && strcmp(genstr.s, f->name.s)!=0))
279: empty=FALSE;
280: if((io=open((char *)genstr.s, 0))<0)
281: error_s(Eopen, (char *)genstr.s);
282: p=readio(f, &nonascii, empty);
283: closeio((cmd=='e' || cmd=='I')? -1 : p);
284: if(cmd=='r')
285: f->dot.r.p1=addr.r.p2, f->dot.r.p2=addr.r.p2+p;
286: else
287: f->dot.r.p1=f->dot.r.p2=0;
288: quitok=f->closeok=empty;
289: state(f, empty && !nonascii? Clean : Dirty);
290: if(cmd=='e')
291: filename(f);
292: }
293: getname(f, s, save)
294: register File *f;
295: register String *s;
296: {
297: register c, i;
298: strzero(&genstr);
299: if(s==0 || (c=s->s[0])==0){ /* no name provided */
300: if(f)
301: strdupstr(&genstr, &f->name);
302: else
303: straddc(&genstr, '\0');
304: goto Return;
305: }
306: if(c!=' ' && c!='\t')
307: error(Eblank);
308: for(i=0; (c=s->s[i])==' ' || c=='\t'; i++)
309: ;
310: while(s->s[i]>' ')
311: straddc(&genstr, s->s[i++]);
312: if(s->s[i])
313: error(Enewline);
314: straddc(&genstr, '\0');
315: if(f && (save || f->name.s[0]==0)){
316: Fsetname(f);
317: if(strcmp(f->name.s, genstr.s)){
318: quitok=f->closeok=FALSE;
319: f->inumber=0;
320: f->date=0;
321: state(f, Dirty); /* if it's 'e', fix later */
322: }
323: }
324: Return:
325: return genstr.n-1; /* strlen(name) */
326: }
327: filename(f)
328: register File *f;
329: {
330: dprint("%c%c%c %s\n", " '"[f->state==Dirty],
331: "-+"[f->rasp!=0], " ."[f==curfile], genstr.s);
332: }
333: undo()
334: {
335: register File *f;
336: register i;
337: Mod max;
338: if((max=curfile->mod)==0)
339: return;
340: settempfile();
341: for(i=0; i<tempfile.nused; i++){
342: f=tempfile.ptr[i];
343: if(f!=cmd && f->mod==max)
344: undostep(f);
345: }
346: }
347: undostep(f)
348: register File *f;
349: {
350: register Buffer *t;
351: register changes;
352: Mark mark;
353: t=f->transcript;
354: changes=Fupdate(f, TRUE, TRUE);
355: Bread(t, (uchar *)&mark, sizeof mark, f->markp);
356: Bdelete(t, f->markp, t->nbytes);
357: f->markp=mark.p;
358: f->dot.r=mark.dot;
359: f->mark=mark.mark;
360: f->mod=mark.m;
361: f->closeok=mark.s1!=Dirty;
362: if(mark.s1==Dirty)
363: quitok=FALSE;
364: if(f->state==Clean && mark.s1==Clean && changes)
365: state(f, Dirty);
366: else
367: state(f, mark.s1);
368: }
369: cd(str)
370: String *str;
371: {
372: register i;
373: register File *f;
374: readcmd(tempstr((uchar *)"/bin/pwd", 9));
375: strdupstr(&wd, &genstr);
376: if(wd.s[0]==0){
377: wd.n=0;
378: warn(Wpwd);
379: }else if(wd.s[wd.n-2]=='\n'){
380: --wd.n;
381: wd.s[wd.n-1]='/';
382: }
383: if(chdir(getname((File *)0, str, FALSE)? (char *)genstr.s : home))
384: syserror("chdir");
385: settempfile();
386: for(i=0; i<tempfile.nused; i++){
387: f=tempfile.ptr[i];
388: if(f!=cmd && f->name.s[0]!='/' && f->name.s[0]!=0){
389: strinsert(&f->name, &wd, (Posn)0);
390: sortname(f);
391: }
392: }
393: }
394: readcmd(s)
395: String *s;
396: {
397: if(flist==0)
398: (flist=Fopen())->state=Clean;
399: addr.r.p1=0, addr.r.p2=flist->nbytes;
400: Unix(flist, '<', s, FALSE);
401: Fupdate(flist, FALSE, FALSE);
402: flist->mod=0;
403: strzero(&genstr);
404: strinsure(&genstr, flist->nbytes);
405: Fchars(flist, genstr.s, (Posn)0, flist->nbytes);
406: genstr.n=flist->nbytes;
407: straddc(&genstr, '\0');
408: }
409: loadflist(s)
410: register String *s;
411: {
412: register c, i;
413: c=s->s[0];
414: for(i=0; s->s[i]==' ' || s->s[i]=='\t'; i++)
415: ;
416: if((c==' ' || c=='\t') && s->s[i]!='\n'){
417: if(s->s[i]=='<'){
418: strdelete(s, 0L, (long)i+1);
419: readcmd(s);
420: }else{
421: strzero(&genstr);
422: while((c=s->s[i++]) && c!='\n')
423: straddc(&genstr, c);
424: straddc(&genstr, '\0');
425: }
426: }else{
427: if(c!='\n')
428: error(Eblank);
429: strdup(&genstr, (uchar *)"");
430: }
431: return genstr.s[0];
432: }
433: File *
434: readflist(readall, delete)
435: {
436: register Posn i;
437: register c;
438: register File *f;
439: for(i=0,f=0; f==0 || readall || delete; ){
440: strdelete(&genstr, (Posn)0, i);
441: for(i=0; (c=genstr.s[i])==' ' || c=='\t' || c=='\n'; i++)
442: ;
443: if(i>=genstr.n)
444: break;
445: strdelete(&genstr, (Posn)0, i);
446: for(i=0; (c=genstr.s[i]) && c!=' ' && c!='\t' && c!='\n'; i++)
447: ;
448: if(i==0)
449: break;
450: genstr.s[i++]=0;
451: f=lookfile();
452: if(delete){
453: if(f==0)
454: warn_s(Wfile, (char *)genstr.s);
455: else
456: trytoclose(f);
457: }else if(f==0 && readall)
458: Fsetname(f=newfile());
459: }
460: return f;
461: }
462: File *
463: tofile(s)
464: String *s;
465: {
466: register File *f;
467: if(s->s[0]!=' ')
468: error(Eblank);
469: if(loadflist(s)==0)
470: f=lookfile(); /* empty string ==> nameless file */
471: else if((f=readflist(FALSE, FALSE))==0)
472: error_s(Emenu, (char *)genstr.s);
473: return current(f);
474: }
475: File *
476: getfile(s)
477: String *s;
478: {
479: register File *f;
480: if(loadflist(s)==0)
481: Fsetname(f=newfile());
482: else if((f=readflist(TRUE, FALSE))==0)
483: error(Eblank);
484: return current(f);
485: }
486: closefiles(f, s)
487: File *f;
488: register String *s;
489: {
490: if(s->s[0]==0){
491: if(f==0)
492: error(Enofile);
493: trytoclose(f);
494: return;
495: }
496: if(s->s[0]!=' ')
497: error(Eblank);
498: if(loadflist(s)==0)
499: error(Enewline);
500: readflist(FALSE, TRUE);
501: }
502: move(f, addr2)
503: register File *f;
504: Address addr2;
505: {
506: if(addr.r.p2<=addr2.r.p2){
507: Fdelete(f, addr.r.p1, addr.r.p2);
508: copy(f, addr2);
509: }else if(addr.r.p1>=addr2.r.p2){
510: copy(f, addr2);
511: Fdelete(f, addr.r.p1, addr.r.p2);
512: }else
513: error(Eoverlap);
514: }
515: copy(f, addr2)
516: register File *f;
517: Address addr2;
518: {
519: register Posn p;
520: register ni;
521: for(p=addr.r.p1; p<addr.r.p2; p+=ni){
522: ni=addr.r.p2-p;
523: if(ni>BLOCKSIZE)
524: ni=BLOCKSIZE;
525: Fchars(f, genbuf, p, p+ni);
526: Finsert(addr2.f, tempstr(genbuf, ni), addr2.r.p2);
527: }
528: addr2.f->dot.r.p2=addr2.r.p2+(f->dot.r.p2-f->dot.r.p1);
529: addr2.f->dot.r.p1=addr2.r.p2;
530: }
531: Posn
532: nlcount(f, p0, p1)
533: register File *f;
534: register Posn p0, p1;
535: {
536: register Posn nl=0;
537: Fgetcset(f, p0);
538: while(p0++<p1)
539: if(Fgetc(f)=='\n')
540: nl++;
541: return nl;
542: }
543: printposn(f, charsonly)
544: register File *f;
545: {
546: register Posn l1, l2;
547: if(!charsonly){
548: l1=1+nlcount(f, (Posn)0, addr.r.p1);
549: l2=l1+nlcount(f, addr.r.p1, addr.r.p2);
550: /* check if addr ends with '\n' */
551: if(addr.r.p2>0 && addr.r.p2>addr.r.p1 && (Fgetcset(f, addr.r.p2-1),Fgetc(f)=='\n'))
552: --l2;
553: dprint("%lud", l1);
554: if(l2!=l1)
555: dprint(",%lud", l2);
556: dprint("; ");
557: }
558: dprint("#%lud", addr.r.p1);
559: if(addr.r.p2!=addr.r.p1)
560: dprint(",#%lud", addr.r.p2);
561: dprint("\n");
562: }
563: settempfile(){
564: if(tempfile.nalloc<file.nused){
565: gcfree((uchar *)tempfile.ptr);
566: gcnew(tempfile.ptr, file.nused);
567: tempfile.nalloc=file.nused;
568: }
569: tempfile.nused=file.nused;
570: bcopy((uchar *)&file.ptr[0], (uchar *)&file.ptr[file.nused],
571: (uchar *)&tempfile.ptr[0], 1);
572: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.