3 Rune genbuf[BLOCKSIZE];
26 char *samterm = SAMTERM;
27 char *rsamname = RSAM;
32 Rune baddir[] = { '<', 'b', 'a', 'd', 'd', 'i', 'r', '>', '\n'};
36 int main(int argc, char *argv[])
42 { // libfmt-2.0 uses %lu where we need %lud
43 extern int __flagfmt(Fmt*);
44 fmtinstall('u', __flagfmt);
49 while(argc>1 && argv[0] && argv[0][0]=='-'){
80 case 'x': /* x11 option - strip the x */
81 strcpy(*argv+1, *argv+2);
88 dprint("sam: unknown flag %c\n", argv[0][1]);
95 Strinit0(&lastregexp);
99 tempfile.listptr = emalloc(1); /* so it can be freed later */
106 startup(machine, Rflag, arg, ap);
110 for(i=0; i<argc-1; i++){
111 if(!setjmp(mainloop)){
112 t = tmpcstr(argv[i]);
114 Strduplstr(&genstr, t);
117 logsetname(newfile(), &genstr);
120 }else if(!downloaded)
124 current(file.filepptr[0]);
127 trytoquit(); /* if we already q'ed, quitok will be TRUE */
134 dprint("usage: sam [-d] [-t samterm] [-s sam name] -r machine\n");
149 for(i=0; i<file.nused; i++){
150 f = file.filepptr[i];
151 if(f==cmd || f->b.nc==0 || !fileisdirty(f))
154 sprint(buf, "%s/sam.save", home);
155 io = create(buf, 1, 0777);
160 c = Strtoc(&f->name);
161 strncpy(buf, c, sizeof buf-1);
162 buf[sizeof buf-1] = 0;
165 sprint(buf, "nameless.%d", nblank++);
166 fprint(io, "#!%s '%s' $* <<'---%s'\n", SAMSAVECMD, buf, buf);
167 addr.r.p1 = 0, addr.r.p2 = f->b.nc;
169 fprint(io, "\n---%s\n", (char *)buf);
178 if(!panicking++ && !setjmp(mainloop)){
181 dprint("sam: panic: %s: %r\n", s);
183 fprint(2, "sam: panic: %s: %r\n", s);
206 * back out any logged changes & restore old sequences
208 for(i=0; i<file.nused; i++){
209 f = file.filepptr[i];
213 bufdelete(&f->epsilon, 0, f->epsilon.nc);
215 f->dot.r = f->prevdot;
216 f->mark = f->prevmark;
217 state(f, f->prevmod ? Dirty: Clean);
224 curfile->unread = FALSE;
226 outTs(Hcurrent, curfile->tag);
228 longjmp(mainloop, 1);
243 if(f == cmd) /* possible? */
247 if(fileisdirty(f) && !f->closeok){
250 t = Strtoc(&f->name);
251 strncpy(buf, t, sizeof buf-1);
254 strcpy(buf, "nameless file");
255 error_s(Emodified, buf);
267 for(c = 0; c<file.nused; c++){
268 f = file.filepptr[c];
269 if(f!=cmd && fileisdirty(f)){
283 Strduplstr(&genstr, &f->name);
291 f->cleanseq = f->seq;
294 fileupdate(f, TRUE, TRUE);
300 if(cmd && cmd->seq!=0){
301 fileupdate(cmd, FALSE, downloaded);
302 cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->b.nc;
310 if(downloaded && f->rasp)
311 outTs(Hclose, f->tag);
324 for(anymod = i=0; i<tempfile.nused; i++){
325 f = tempfile.filepptr[i];
326 if(f==cmd) /* cmd gets done in main() */
332 if(f->seq==seq && fileupdate(f, FALSE, downloaded))
348 edit(File *f, int cmd)
355 logdelete(f, addr.r.p1, addr.r.p2);
356 if(cmd=='e' || cmd=='I'){
357 logdelete(f, (Posn)0, f->b.nc);
359 }else if(f->b.nc!=0 || (f->name.s[0] && Strcmp(&genstr, &f->name)!=0))
361 if((io = open(genc, OREAD))<0) {
362 if (curfile && curfile->unread)
363 curfile->unread = FALSE;
364 error_r(Eopen, genc);
366 p = readio(f, &nulls, empty, TRUE);
367 closeio((cmd=='e' || cmd=='I')? -1 : p);
369 f->ndot.r.p1 = addr.r.p2, f->ndot.r.p2 = addr.r.p2+p;
371 f->ndot.r.p1 = f->ndot.r.p2 = 0;
377 state(f, empty && !nulls? Clean : Dirty);
379 f->cleanseq = f->seq;
385 getname(File *f, String *s, int save)
394 if(s==0 || (c = s->s[0])==0){ /* no name provided */
396 Strduplstr(&genstr, &f->name);
399 if(c!=' ' && c!='\t')
401 for(i=0; (c=s->s[i])==' ' || c=='\t'; i++)
404 Straddc(&genstr, s->s[i++]);
408 if(f && (save || f->name.s[0]==0)){
409 logsetname(f, &genstr);
410 if(Strcmp(&f->name, &genstr)){
411 quitok = f->closeok = FALSE;
414 state(f, Dirty); /* if it's 'e', fix later */
418 genc = Strtoc(&genstr);
420 if(i && genstr.s[i-1]==0)
422 return i; /* strlen(name) */
430 genc = Strtoc(&genstr);
431 dprint("%c%c%c %s\n", " '"[f->mod],
432 "-+"[f->rasp!=0], " ."[f==curfile], genc);
436 undostep(File *f, int isundo)
442 fileundo(f, isundo, 1, &p1, &p2, TRUE);
467 max = undoseq(curfile, isundo);
471 for(i = 0; i<tempfile.nused; i++){
472 f = tempfile.filepptr[i];
473 if(f!=cmd && undoseq(f, isundo)==max)
488 addr.r.p1 = 0, addr.r.p2 = flist->b.nc;
489 retcode = plan9(flist, '<', s, FALSE);
490 fileupdate(flist, FALSE, FALSE);
492 if (flist->b.nc > BLOCKSIZE)
495 Strinsure(&genstr, flist->b.nc);
496 bufread(&flist->b, (Posn)0, genbuf, flist->b.nc);
497 memmove(genstr.s, genbuf, flist->b.nc*RUNESIZE);
498 genstr.n = flist->b.nc;
499 Straddc(&genstr, '\0');
510 getwd(buf, sizeof(buf));
512 Strduplstr(&curwd, t);
516 else if(curwd.s[curwd.n-1] != '/')
517 Straddc(&curwd, '/');
529 if(getname((File *)0, str, FALSE))
535 fd = open("/dev/wdir", OWRITE);
537 write(fd, s, strlen(s));
540 Strduplstr(&owd, &curwd);
543 for(i=0; i<tempfile.nused; i++){
544 f = tempfile.filepptr[i];
545 if(f!=cmd && f->name.s[0]!='/' && f->name.s[0]!=0){
546 Strinsert(&f->name, &owd, (Posn)0);
549 }else if(f != cmd && Strispre(&curwd, &f->name)){
563 for(i = 0; s->s[i]==' ' || s->s[i]=='\t'; i++)
565 if((c==' ' || c=='\t') && s->s[i]!='\n'){
567 Strdelete(s, 0L, (long)i+1);
571 while((c = s->s[i++]) && c!='\n')
573 Straddc(&genstr, '\0');
578 Strdupl(&genstr, empty);
582 genc = Strtoc(&genstr);
587 readflist(int readall, int delete)
595 for(i=0,f=0; f==0 || readall || delete; i++){ /* ++ skips blank */
596 Strdelete(&genstr, (Posn)0, i);
597 for(i=0; (c = genstr.s[i])==' ' || c=='\t' || c=='\n'; i++)
601 Strdelete(&genstr, (Posn)0, i);
602 for(i=0; (c=genstr.s[i]) && c!=' ' && c!='\t' && c!='\n'; i++)
608 Strduplstr(&t, tmprstr(genstr.s, i+1));
616 }else if(f==0 && readall)
617 logsetname(f = newfile(), &t);
630 if(loadflist(s) == 0){
631 f = lookfile(&genstr); /* empty string ==> nameless file */
633 error_s(Emenu, genc);
634 }else if((f=readflist(FALSE, FALSE)) == 0)
635 error_s(Emenu, genc);
644 if(loadflist(s) == 0)
645 logsetname(f = newfile(), &genstr);
646 else if((f=readflist(TRUE, FALSE)) == 0)
652 closefiles(File *f, String *s)
662 if(loadflist(s) == 0)
664 readflist(FALSE, TRUE);
668 copy(File *f, Address addr2)
672 for(p=addr.r.p1; p<addr.r.p2; p+=ni){
676 bufread(&f->b, p, genbuf, ni);
677 loginsert(addr2.f, addr2.r.p2, tmprstr(genbuf, ni)->s, ni);
679 addr2.f->ndot.r.p2 = addr2.r.p2+(f->dot.r.p2-f->dot.r.p1);
680 addr2.f->ndot.r.p1 = addr2.r.p2;
684 move(File *f, Address addr2)
686 if(addr.r.p2 <= addr2.r.p2){
687 logdelete(f, addr.r.p1, addr.r.p2);
689 }else if(addr.r.p1 >= addr2.r.p2){
691 logdelete(f, addr.r.p1, addr.r.p2);
697 nlcount(File *f, Posn p0, Posn p1)
702 if(filereadc(f, p0++)=='\n')
708 printposn(File *f, int charsonly)
713 l1 = 1+nlcount(f, (Posn)0, addr.r.p1);
714 l2 = l1+nlcount(f, addr.r.p1, addr.r.p2);
715 /* check if addr ends with '\n' */
716 if(addr.r.p2>0 && addr.r.p2>addr.r.p1 && filereadc(f, addr.r.p2-1)=='\n')
723 dprint("#%lud", addr.r.p1);
724 if(addr.r.p2 != addr.r.p1)
725 dprint(",#%lud", addr.r.p2);
732 if(tempfile.nalloc < file.nused){
733 free(tempfile.listptr);
734 tempfile.listptr = emalloc(sizeof(*tempfile.filepptr)*file.nused);
735 tempfile.nalloc = file.nused;
737 tempfile.nused = file.nused;
738 memmove(&tempfile.filepptr[0], &file.filepptr[0], file.nused*sizeof(File*));