123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #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 = { 'p' };
- 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;
- int32_t seq;
- Rune baddir[] = { '<', 'b', 'a', 'd', 'd', 'i', 'r', '>', '\n'};
- void usage(void);
- void main(int argc, char *argv[])
- {
- int i;
- String *t;
- char *termargs[10], **ap;
-
- ap = termargs;
- *ap++ = "samterm";
- ARGBEGIN{
- case 'd':
- dflag++;
- break;
- case 'r':
- machine = EARGF(usage());
- break;
- case 'R':
- Rflag++;
- break;
- case 't':
- samterm = EARGF(usage());
- break;
- case 's':
- rsamname = EARGF(usage());
- break;
- default:
- dprint("sam: unknown flag %c\n", ARGC());
- usage();
- /* options for samterm */
- case 'a':
- *ap++ = "-a";
- break;
- }ARGEND
- *ap = nil;
-
- Strinit(&cmdstr);
- Strinit0(&lastpat);
- Strinit0(&lastregexp);
- Strinit0(&genstr);
- Strinit0(&rhs);
- Strinit0(&curwd);
- Strinit0(&plan9cmd);
- home = getenv(HOME);
- disk = diskinit();
- if(home == 0)
- home = "/";
- if(!dflag)
- startup(machine, Rflag, termargs, argv);
- notify(notifyf);
- getcurwd();
- if(argc>0){
- for(i=0; i<argc; 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, (int32_t)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){
- if(tempfile.filepptr)
- free(tempfile.filepptr);
- tempfile.filepptr = emalloc(sizeof(File*)*file.nused);
- tempfile.nalloc = file.nused;
- }
- memmove(tempfile.filepptr, file.filepptr, sizeof(File*)*file.nused);
- tempfile.nused = file.nused;
- }
|