|
|
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.