diff options
Diffstat (limited to 'src/cmd/sam/sam.c')
-rw-r--r-- | src/cmd/sam/sam.c | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/src/cmd/sam/sam.c b/src/cmd/sam/sam.c new file mode 100644 index 00000000..81ccaf78 --- /dev/null +++ b/src/cmd/sam/sam.c @@ -0,0 +1,739 @@ +#include "sam.h" + +Rune genbuf[BLOCKSIZE]; +int io; +int panicking; +int rescuing; +String genstr; +String rhs; +String curwd; +String cmdstr; +Rune empty[] = { 0 }; +char *genc; +File *curfile; +File *flist; +File *cmd; +jmp_buf mainloop; +List tempfile; +int quitok = TRUE; +int downloaded; +int dflag; +int Rflag; +char *machine; +char *home; +int bpipeok; +int termlocked; +char *samterm = SAMTERM; +char *rsamname = RSAM; +File *lastfile; +Disk *disk; +long seq; + +Rune baddir[] = { '<', 'b', 'a', 'd', 'd', 'i', 'r', '>', '\n'}; + +void usage(void); + +int main(int argc, char *argv[]) +{ + int i; + String *t; + char **ap, **arg; + + { // libfmt-2.0 uses %lu where we need %lud + extern int __flagfmt(Fmt*); + fmtinstall('u', __flagfmt); + } + + arg = argv++; + ap = argv; + while(argc>1 && argv[0] && argv[0][0]=='-'){ + switch(argv[0][1]){ + case 'd': + dflag++; + break; + + case 'r': + --argc, argv++; + if(argc == 1) + usage(); + machine = *argv; + break; + + case 'R': + Rflag++; + break; + + case 't': + --argc, argv++; + if(argc == 1) + usage(); + samterm = *argv; + break; + + case 's': + --argc, argv++; + if(argc == 1) + usage(); + rsamname = *argv; + break; + + case 'x': /* x11 option - strip the x */ + strcpy(*argv+1, *argv+2); + *ap++ = *argv++; + *ap++ = *argv; + argc--; + break; + + default: + dprint("sam: unknown flag %c\n", argv[0][1]); + exits("usage"); + } + --argc, argv++; + } + Strinit(&cmdstr); + Strinit0(&lastpat); + Strinit0(&lastregexp); + Strinit0(&genstr); + Strinit0(&rhs); + Strinit0(&curwd); + tempfile.listptr = emalloc(1); /* so it can be freed later */ + Strinit0(&plan9cmd); + home = getenv(HOME); + disk = diskinit(); + if(home == 0) + home = "/"; + if(!dflag) + startup(machine, Rflag, arg, ap); + notify(notifyf); + getcurwd(); + if(argc>1){ + for(i=0; i<argc-1; i++){ + if(!setjmp(mainloop)){ + t = tmpcstr(argv[i]); + Straddc(t, '\0'); + Strduplstr(&genstr, t); + freetmpstr(t); + fixname(&genstr); + logsetname(newfile(), &genstr); + } + } + }else if(!downloaded) + newfile(); + seq++; + if(file.nused) + current(file.filepptr[0]); + setjmp(mainloop); + cmdloop(); + trytoquit(); /* if we already q'ed, quitok will be TRUE */ + exits(0); +} + +void +usage(void) +{ + dprint("usage: sam [-d] [-t samterm] [-s sam name] -r machine\n"); + exits("usage"); +} + +void +rescue(void) +{ + int i, nblank = 0; + File *f; + char *c; + char buf[256]; + + if(rescuing++) + return; + io = -1; + for(i=0; i<file.nused; i++){ + f = file.filepptr[i]; + if(f==cmd || f->_.nc==0 || !fileisdirty(f)) + continue; + if(io == -1){ + sprint(buf, "%s/sam.save", home); + io = create(buf, 1, 0777); + if(io<0) + return; + } + if(f->name.s[0]){ + c = Strtoc(&f->name); + strncpy(buf, c, sizeof buf-1); + buf[sizeof buf-1] = 0; + free(c); + }else + sprint(buf, "nameless.%d", nblank++); + fprint(io, "#!%s '%s' $* <<'---%s'\n", SAMSAVECMD, buf, buf); + addr.r.p1 = 0, addr.r.p2 = f->_.nc; + writeio(f); + fprint(io, "\n---%s\n", (char *)buf); + } +} + +void +panic(char *s) +{ + int wasd; + + if(!panicking++ && !setjmp(mainloop)){ + wasd = downloaded; + downloaded = 0; + dprint("sam: panic: %s: %r\n", s); + if(wasd) + fprint(2, "sam: panic: %s: %r\n", s); + rescue(); + abort(); + } +} + +void +hiccough(char *s) +{ + File *f; + int i; + + if(rescuing) + exits("rescue"); + if(s) + dprint("%s\n", s); + resetcmd(); + resetxec(); + resetsys(); + if(io > 0) + close(io); + + /* + * back out any logged changes & restore old sequences + */ + for(i=0; i<file.nused; i++){ + f = file.filepptr[i]; + if(f==cmd) + continue; + if(f->seq==seq){ + bufdelete(&f->epsilon, 0, f->epsilon.nc); + f->seq = f->prevseq; + f->dot.r = f->prevdot; + f->mark = f->prevmark; + state(f, f->prevmod ? Dirty: Clean); + } + } + + update(); + if (curfile) { + if (curfile->unread) + curfile->unread = FALSE; + else if (downloaded) + outTs(Hcurrent, curfile->tag); + } + longjmp(mainloop, 1); +} + +void +intr(void) +{ + error(Eintr); +} + +void +trytoclose(File *f) +{ + char *t; + char buf[256]; + + if(f == cmd) /* possible? */ + return; + if(f->deleted) + return; + if(fileisdirty(f) && !f->closeok){ + f->closeok = TRUE; + if(f->name.s[0]){ + t = Strtoc(&f->name); + strncpy(buf, t, sizeof buf-1); + free(t); + }else + strcpy(buf, "nameless file"); + error_s(Emodified, buf); + } + f->deleted = TRUE; +} + +void +trytoquit(void) +{ + int c; + File *f; + + if(!quitok){ + for(c = 0; c<file.nused; c++){ + f = file.filepptr[c]; + if(f!=cmd && fileisdirty(f)){ + quitok = TRUE; + eof = FALSE; + error(Echanges); + } + } + } +} + +void +load(File *f) +{ + Address saveaddr; + + Strduplstr(&genstr, &f->name); + filename(f); + if(f->name.s[0]){ + saveaddr = addr; + edit(f, 'I'); + addr = saveaddr; + }else{ + f->unread = 0; + f->cleanseq = f->seq; + } + + fileupdate(f, TRUE, TRUE); +} + +void +cmdupdate(void) +{ + if(cmd && cmd->seq!=0){ + fileupdate(cmd, FALSE, downloaded); + cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->_.nc; + telldot(cmd); + } +} + +void +delete(File *f) +{ + if(downloaded && f->rasp) + outTs(Hclose, f->tag); + delfile(f); + if(f == curfile) + current(0); +} + +void +update(void) +{ + int i, anymod; + File *f; + + settempfile(); + for(anymod = i=0; i<tempfile.nused; i++){ + f = tempfile.filepptr[i]; + if(f==cmd) /* cmd gets done in main() */ + continue; + if(f->deleted) { + delete(f); + continue; + } + if(f->seq==seq && fileupdate(f, FALSE, downloaded)) + anymod++; + if(f->rasp) + telldot(f); + } + if(anymod) + seq++; +} + +File * +current(File *f) +{ + return curfile = f; +} + +void +edit(File *f, int cmd) +{ + int empty = TRUE; + Posn p; + int nulls; + + if(cmd == 'r') + logdelete(f, addr.r.p1, addr.r.p2); + if(cmd=='e' || cmd=='I'){ + logdelete(f, (Posn)0, f->_.nc); + addr.r.p2 = f->_.nc; + }else if(f->_.nc!=0 || (f->name.s[0] && Strcmp(&genstr, &f->name)!=0)) + empty = FALSE; + if((io = open(genc, OREAD))<0) { + if (curfile && curfile->unread) + curfile->unread = FALSE; + error_r(Eopen, genc); + } + p = readio(f, &nulls, empty, TRUE); + closeio((cmd=='e' || cmd=='I')? -1 : p); + if(cmd == 'r') + f->ndot.r.p1 = addr.r.p2, f->ndot.r.p2 = addr.r.p2+p; + else + f->ndot.r.p1 = f->ndot.r.p2 = 0; + f->closeok = empty; + if (quitok) + quitok = empty; + else + quitok = FALSE; + state(f, empty && !nulls? Clean : Dirty); + if(empty && !nulls) + f->cleanseq = f->seq; + if(cmd == 'e') + filename(f); +} + +int +getname(File *f, String *s, int save) +{ + int c, i; + + Strzero(&genstr); + if(genc){ + free(genc); + genc = 0; + } + if(s==0 || (c = s->s[0])==0){ /* no name provided */ + if(f) + Strduplstr(&genstr, &f->name); + goto Return; + } + if(c!=' ' && c!='\t') + error(Eblank); + for(i=0; (c=s->s[i])==' ' || c=='\t'; i++) + ; + while(s->s[i] > ' ') + Straddc(&genstr, s->s[i++]); + if(s->s[i]) + error(Enewline); + fixname(&genstr); + if(f && (save || f->name.s[0]==0)){ + logsetname(f, &genstr); + if(Strcmp(&f->name, &genstr)){ + quitok = f->closeok = FALSE; + f->qidpath = 0; + f->mtime = 0; + state(f, Dirty); /* if it's 'e', fix later */ + } + } + Return: + genc = Strtoc(&genstr); + i = genstr.n; + if(i && genstr.s[i-1]==0) + i--; + return i; /* strlen(name) */ +} + +void +filename(File *f) +{ + if(genc) + free(genc); + genc = Strtoc(&genstr); + dprint("%c%c%c %s\n", " '"[f->mod], + "-+"[f->rasp!=0], " ."[f==curfile], genc); +} + +void +undostep(File *f, int isundo) +{ + uint p1, p2; + int mod; + + mod = f->mod; + fileundo(f, isundo, 1, &p1, &p2, TRUE); + f->ndot = f->dot; + if(f->mod){ + f->closeok = 0; + quitok = 0; + }else + f->closeok = 1; + + if(f->mod != mod){ + f->mod = mod; + if(mod) + mod = Clean; + else + mod = Dirty; + state(f, mod); + } +} + +int +undo(int isundo) +{ + File *f; + int i; + Mod max; + + max = undoseq(curfile, isundo); + if(max == 0) + return 0; + settempfile(); + for(i = 0; i<tempfile.nused; i++){ + f = tempfile.filepptr[i]; + if(f!=cmd && undoseq(f, isundo)==max) + undostep(f, isundo); + } + return 1; +} + +int +readcmd(String *s) +{ + int retcode; + + if(flist != 0) + fileclose(flist); + flist = fileopen(); + + addr.r.p1 = 0, addr.r.p2 = flist->_.nc; + retcode = plan9(flist, '<', s, FALSE); + fileupdate(flist, FALSE, FALSE); + flist->seq = 0; + if (flist->_.nc > BLOCKSIZE) + error(Etoolong); + Strzero(&genstr); + Strinsure(&genstr, flist->_.nc); + bufread(flist, (Posn)0, genbuf, flist->_.nc); + memmove(genstr.s, genbuf, flist->_.nc*RUNESIZE); + genstr.n = flist->_.nc; + Straddc(&genstr, '\0'); + return retcode; +} + +void +getcurwd(void) +{ + String *t; + char buf[256]; + + buf[0] = 0; + getwd(buf, sizeof(buf)); + t = tmpcstr(buf); + Strduplstr(&curwd, t); + freetmpstr(t); + if(curwd.n == 0) + warn(Wpwd); + else if(curwd.s[curwd.n-1] != '/') + Straddc(&curwd, '/'); +} + +void +cd(String *str) +{ + int i, fd; + char *s; + File *f; + String owd; + + getcurwd(); + if(getname((File *)0, str, FALSE)) + s = genc; + else + s = home; + if(chdir(s)) + syserror("chdir"); + fd = open("/dev/wdir", OWRITE); + if(fd > 0) + write(fd, s, strlen(s)); + dprint("!\n"); + Strinit(&owd); + Strduplstr(&owd, &curwd); + getcurwd(); + settempfile(); + for(i=0; i<tempfile.nused; i++){ + f = tempfile.filepptr[i]; + if(f!=cmd && f->name.s[0]!='/' && f->name.s[0]!=0){ + Strinsert(&f->name, &owd, (Posn)0); + fixname(&f->name); + sortname(f); + }else if(f != cmd && Strispre(&curwd, &f->name)){ + fixname(&f->name); + sortname(f); + } + } + Strclose(&owd); +} + +int +loadflist(String *s) +{ + int c, i; + + c = s->s[0]; + for(i = 0; s->s[i]==' ' || s->s[i]=='\t'; i++) + ; + if((c==' ' || c=='\t') && s->s[i]!='\n'){ + if(s->s[i]=='<'){ + Strdelete(s, 0L, (long)i+1); + readcmd(s); + }else{ + Strzero(&genstr); + while((c = s->s[i++]) && c!='\n') + Straddc(&genstr, c); + Straddc(&genstr, '\0'); + } + }else{ + if(c != '\n') + error(Eblank); + Strdupl(&genstr, empty); + } + if(genc) + free(genc); + genc = Strtoc(&genstr); + return genstr.s[0]; +} + +File * +readflist(int readall, int delete) +{ + Posn i; + int c; + File *f; + String t; + + Strinit(&t); + for(i=0,f=0; f==0 || readall || delete; i++){ /* ++ skips blank */ + Strdelete(&genstr, (Posn)0, i); + for(i=0; (c = genstr.s[i])==' ' || c=='\t' || c=='\n'; i++) + ; + if(i >= genstr.n) + break; + Strdelete(&genstr, (Posn)0, i); + for(i=0; (c=genstr.s[i]) && c!=' ' && c!='\t' && c!='\n'; i++) + ; + + if(i == 0) + break; + genstr.s[i] = 0; + Strduplstr(&t, tmprstr(genstr.s, i+1)); + fixname(&t); + f = lookfile(&t); + if(delete){ + if(f == 0) + warn_S(Wfile, &t); + else + trytoclose(f); + }else if(f==0 && readall) + logsetname(f = newfile(), &t); + } + Strclose(&t); + return f; +} + +File * +tofile(String *s) +{ + File *f; + + if(s->s[0] != ' ') + error(Eblank); + if(loadflist(s) == 0){ + f = lookfile(&genstr); /* empty string ==> nameless file */ + if(f == 0) + error_s(Emenu, genc); + }else if((f=readflist(FALSE, FALSE)) == 0) + error_s(Emenu, genc); + return current(f); +} + +File * +getfile(String *s) +{ + File *f; + + if(loadflist(s) == 0) + logsetname(f = newfile(), &genstr); + else if((f=readflist(TRUE, FALSE)) == 0) + error(Eblank); + return current(f); +} + +void +closefiles(File *f, String *s) +{ + if(s->s[0] == 0){ + if(f == 0) + error(Enofile); + trytoclose(f); + return; + } + if(s->s[0] != ' ') + error(Eblank); + if(loadflist(s) == 0) + error(Enewline); + readflist(FALSE, TRUE); +} + +void +copy(File *f, Address addr2) +{ + Posn p; + int ni; + for(p=addr.r.p1; p<addr.r.p2; p+=ni){ + ni = addr.r.p2-p; + if(ni > BLOCKSIZE) + ni = BLOCKSIZE; + bufread(f, p, genbuf, ni); + loginsert(addr2.f, addr2.r.p2, tmprstr(genbuf, ni)->s, ni); + } + addr2.f->ndot.r.p2 = addr2.r.p2+(f->dot.r.p2-f->dot.r.p1); + addr2.f->ndot.r.p1 = addr2.r.p2; +} + +void +move(File *f, Address addr2) +{ + if(addr.r.p2 <= addr2.r.p2){ + logdelete(f, addr.r.p1, addr.r.p2); + copy(f, addr2); + }else if(addr.r.p1 >= addr2.r.p2){ + copy(f, addr2); + logdelete(f, addr.r.p1, addr.r.p2); + }else + error(Eoverlap); +} + +Posn +nlcount(File *f, Posn p0, Posn p1) +{ + Posn nl = 0; + + while(p0 < p1) + if(filereadc(f, p0++)=='\n') + nl++; + return nl; +} + +void +printposn(File *f, int charsonly) +{ + Posn l1, l2; + + if(!charsonly){ + l1 = 1+nlcount(f, (Posn)0, addr.r.p1); + l2 = l1+nlcount(f, addr.r.p1, addr.r.p2); + /* check if addr ends with '\n' */ + if(addr.r.p2>0 && addr.r.p2>addr.r.p1 && filereadc(f, addr.r.p2-1)=='\n') + --l2; + dprint("%lud", l1); + if(l2 != l1) + dprint(",%lud", l2); + dprint("; "); + } + dprint("#%lud", addr.r.p1); + if(addr.r.p2 != addr.r.p1) + dprint(",#%lud", addr.r.p2); + dprint("\n"); +} + +void +settempfile(void) +{ + if(tempfile.nalloc < file.nused){ + free(tempfile.listptr); + tempfile.listptr = emalloc(sizeof(*tempfile.filepptr)*file.nused); + tempfile.nalloc = file.nused; + } + tempfile.nused = file.nused; + memmove(&tempfile.filepptr[0], &file.filepptr[0], file.nused*sizeof(File*)); +} |