int s_cmd(File *f, Cmd *cp) { int i, j, c, n; Posn p1, op, didsub = 0, delta = 0; n = cp->num; op= -1; compile(cp->re); for(p1 = addr.r.p1; p1<=addr.r.p2 && execute(f, p1, addr.r.p2); ){ if(sel.p[0].p1==sel.p[0].p2){ /* empty match? */ if(sel.p[0].p1==op){ p1++; continue; } p1 = sel.p[0].p2+1; }else p1 = sel.p[0].p2; op = sel.p[0].p2; if(--n>0) continue; Strzero(&genstr); for(i = 0; i<cp->ctext->n; i++) if((c = cp->ctext->s[i])=='\\' && i<cp->ctext->n-1){ c = cp->ctext->s[++i]; if('1'<=c && c<='9') { j = c-'0'; if(sel.p[j].p2-sel.p[j].p1>BLOCKSIZE) error(Elongtag); bufread(&f->b, sel.p[j].p1, genbuf, sel.p[j].p2-sel.p[j].p1); Strinsert(&genstr, tmprstr(genbuf, (sel.p[j].p2-sel.p[j].p1)), genstr.n); }else Straddc(&genstr, c); }else if(c!='&') Straddc(&genstr, c); else{ if(sel.p[0].p2-sel.p[0].p1>BLOCKSIZE) error(Elongrhs); bufread(&f->b, sel.p[0].p1, genbuf, sel.p[0].p2-sel.p[0].p1); Strinsert(&genstr, tmprstr(genbuf, (int)(sel.p[0].p2-sel.p[0].p1)), genstr.n); } if(sel.p[0].p1!=sel.p[0].p2){ logdelete(f, sel.p[0].p1, sel.p[0].p2); delta-=sel.p[0].p2-sel.p[0].p1; } if(genstr.n){ loginsert(f, sel.p[0].p2, genstr.s, genstr.n); delta+=genstr.n; } didsub = 1; if(!cp->flag) break; } if(!didsub && nest==0) error(Enosub); f->ndot.r.p1 = addr.r.p1, f->ndot.r.p2 = addr.r.p2+delta; return TRUE; }
int append(File *f, Cmd *cp, Posn p) { if(cp->ctext->n>0 && cp->ctext->s[cp->ctext->n-1]==0) --cp->ctext->n; if(cp->ctext->n>0) loginsert(f, p, cp->ctext->s, cp->ctext->n); f->ndot.r.p1 = p; f->ndot.r.p2 = p+cp->ctext->n; return TRUE; }
void termwrite(char *s) { String *p; if(downloaded){ p = tmpcstr(s); if(cmd) loginsert(cmd, cmdpt, p->s, p->n); else Strinsert(&cmdstr, p, cmdstr.n); cmdptadv += p->n; free(p); }else Write(2, s, strlen(s)); }
int inmesg(Tmesg type) { Rune buf[1025]; char cbuf[64]; int i, m; short s; long l, l1; vlong v; File *f; Posn p0, p1, p; Range r; String *str; char *c, *wdir; Rune *rp; Plumbmsg *pm; if(type > TMAX) panic("inmesg"); journal(0, tname[type]); inp = indata; switch(type){ case -1: panic("rcv error"); default: fprint(2, "unknown type %d\n", type); panic("rcv unknown"); case Tversion: tversion = inshort(); journaln(0, tversion); break; case Tstartcmdfile: v = invlong(); /* for 64-bit pointers */ journaln(0, v); Strdupl(&genstr, samname); cmd = newfile(); cmd->unread = 0; outTsv(Hbindname, cmd->tag, v); outTs(Hcurrent, cmd->tag); logsetname(cmd, &genstr); cmd->rasp = listalloc('P'); cmd->mod = 0; if(cmdstr.n){ loginsert(cmd, 0L, cmdstr.s, cmdstr.n); Strdelete(&cmdstr, 0L, (Posn)cmdstr.n); } fileupdate(cmd, FALSE, TRUE); outT0(Hunlock); break; case Tcheck: /* go through whichfile to check the tag */ outTs(Hcheck, whichfile(inshort())->tag); break; case Trequest: f = whichfile(inshort()); p0 = inlong(); p1 = p0+inshort(); journaln(0, p0); journaln(0, p1-p0); if(f->unread) panic("Trequest: unread"); if(p1>f->b.nc) p1 = f->b.nc; if(p0>f->b.nc) /* can happen e.g. scrolling during command */ p0 = f->b.nc; if(p0 == p1){ i = 0; r.p1 = r.p2 = p0; }else{ r = rdata(f->rasp, p0, p1-p0); i = r.p2-r.p1; bufread(&f->b, r.p1, buf, i); } buf[i]=0; outTslS(Hdata, f->tag, r.p1, tmprstr(buf, i+1)); break; case Torigin: s = inshort(); l = inlong(); l1 = inlong(); journaln(0, l1); lookorigin(whichfile(s), l, l1); break; case Tstartfile: termlocked++; f = whichfile(inshort()); if(!f->rasp) /* this might be a duplicate message */ f->rasp = listalloc('P'); current(f); outTsv(Hbindname, f->tag, invlong()); /* for 64-bit pointers */ outTs(Hcurrent, f->tag); journaln(0, f->tag); if(f->unread) load(f); else{ if(f->b.nc>0){ rgrow(f->rasp, 0L, f->b.nc); outTsll(Hgrow, f->tag, 0L, f->b.nc); } outTs(Hcheck0, f->tag); moveto(f, f->dot.r); } break; case Tworkfile: i = inshort(); f = whichfile(i); current(f); f->dot.r.p1 = inlong(); f->dot.r.p2 = inlong(); f->tdot = f->dot.r; journaln(0, i); journaln(0, f->dot.r.p1); journaln(0, f->dot.r.p2); break; case Ttype: f = whichfile(inshort()); p0 = inlong(); journaln(0, p0); journal(0, (char*)inp); str = tmpcstr((char*)inp); i = str->n; loginsert(f, p0, str->s, str->n); if(fileupdate(f, FALSE, FALSE)) seq++; if(f==cmd && p0==f->b.nc-i && i>0 && str->s[i-1]=='\n'){ freetmpstr(str); termlocked++; termcommand(); }else freetmpstr(str); f->dot.r.p1 = f->dot.r.p2 = p0+i; /* terminal knows this already */ f->tdot = f->dot.r; break; case Tcut: f = whichfile(inshort()); p0 = inlong(); p1 = inlong(); journaln(0, p0); journaln(0, p1); logdelete(f, p0, p1); if(fileupdate(f, FALSE, FALSE)) seq++; f->dot.r.p1 = f->dot.r.p2 = p0; f->tdot = f->dot.r; /* terminal knows the value of dot already */ break; case Tpaste: f = whichfile(inshort()); p0 = inlong(); journaln(0, p0); for(l=0; l<snarfbuf.nc; l+=m){ m = snarfbuf.nc-l; if(m>BLOCKSIZE) m = BLOCKSIZE; bufread(&snarfbuf, l, genbuf, m); loginsert(f, p0, tmprstr(genbuf, m)->s, m); } if(fileupdate(f, FALSE, TRUE)) seq++; f->dot.r.p1 = p0; f->dot.r.p2 = p0+snarfbuf.nc; f->tdot.p1 = -1; /* force telldot to tell (arguably a BUG) */ telldot(f); outTs(Hunlockfile, f->tag); break; case Tsnarf: i = inshort(); p0 = inlong(); p1 = inlong(); snarf(whichfile(i), p0, p1, &snarfbuf, 0); break; case Tstartnewfile: v = invlong(); Strdupl(&genstr, empty); f = newfile(); f->rasp = listalloc('P'); outTsv(Hbindname, f->tag, v); logsetname(f, &genstr); outTs(Hcurrent, f->tag); current(f); load(f); break; case Twrite: termlocked++; i = inshort(); journaln(0, i); f = whichfile(i); addr.r.p1 = 0; addr.r.p2 = f->b.nc; if(f->name.s[0] == 0) error(Enoname); Strduplstr(&genstr, &f->name); writef(f); break; case Tclose: termlocked++; i = inshort(); journaln(0, i); f = whichfile(i); current(f); trytoclose(f); /* if trytoclose fails, will error out */ delete(f); break; case Tlook: f = whichfile(inshort()); termlocked++; p0 = inlong(); p1 = inlong(); journaln(0, p0); journaln(0, p1); setgenstr(f, p0, p1); for(l = 0; l<genstr.n; l++){ i = genstr.s[l]; if(utfrune(".*+?(|)\\[]^$", i)){ str = tmpcstr("\\"); Strinsert(&genstr, str, l++); freetmpstr(str); } } Straddc(&genstr, '\0'); nextmatch(f, &genstr, p1, 1); moveto(f, sel.p[0]); break; case Tsearch: termlocked++; if(curfile == 0) error(Enofile); if(lastpat.s[0] == 0) panic("Tsearch"); nextmatch(curfile, &lastpat, curfile->dot.r.p2, 1); moveto(curfile, sel.p[0]); break; case Tsend: termlocked++; inshort(); /* ignored */ p0 = inlong(); p1 = inlong(); setgenstr(cmd, p0, p1); bufreset(&snarfbuf); bufinsert(&snarfbuf, (Posn)0, genstr.s, genstr.n); outTl(Hsnarflen, genstr.n); if(genstr.s[genstr.n-1] != '\n') Straddc(&genstr, '\n'); loginsert(cmd, cmd->b.nc, genstr.s, genstr.n); fileupdate(cmd, FALSE, TRUE); cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->b.nc; telldot(cmd); termcommand(); break; case Tdclick: f = whichfile(inshort()); p1 = inlong(); doubleclick(f, p1); f->tdot.p1 = f->tdot.p2 = p1; telldot(f); outTs(Hunlockfile, f->tag); break; case Tstartsnarf: if (snarfbuf.nc <= 0) { /* nothing to export */ outTs(Hsetsnarf, 0); break; } c = 0; i = 0; m = snarfbuf.nc; if(m > SNARFSIZE) { m = SNARFSIZE; dprint("?warning: snarf buffer truncated\n"); } rp = malloc(m*sizeof(Rune)); if(rp){ bufread(&snarfbuf, 0, rp, m); c = Strtoc(tmprstr(rp, m)); free(rp); i = strlen(c); } outTs(Hsetsnarf, i); if(c){ Write(1, c, i); free(c); } else dprint("snarf buffer too long\n"); break; case Tsetsnarf: m = inshort(); if(m > SNARFSIZE) error(Etoolong); c = malloc(m+1); if(c){ for(i=0; i<m; i++) c[i] = rcvchar(); c[m] = 0; str = tmpcstr(c); free(c); bufreset(&snarfbuf); bufinsert(&snarfbuf, (Posn)0, str->s, str->n); freetmpstr(str); outT0(Hunlock); } break; case Tack: waitack = 0; break; case Tplumb: f = whichfile(inshort()); p0 = inlong(); p1 = inlong(); pm = emalloc(sizeof(Plumbmsg)); pm->src = strdup("sam"); pm->dst = 0; /* construct current directory */ c = Strtoc(&f->name); if(c[0] == '/') pm->wdir = c; else{ wdir = emalloc(1024); getwd(wdir, 1024); pm->wdir = emalloc(1024); snprint(pm->wdir, 1024, "%s/%s", wdir, c); cleanname(pm->wdir); free(wdir); free(c); } c = strrchr(pm->wdir, '/'); if(c) *c = '\0'; pm->type = strdup("text"); if(p1 > p0) pm->attr = nil; else{ p = p0; while(p0>0 && (i=filereadc(f, p0 - 1))!=' ' && i!='\t' && i!='\n') p0--; while(p1<f->b.nc && (i=filereadc(f, p1))!=' ' && i!='\t' && i!='\n') p1++; sprint(cbuf, "click=%ld", p-p0); pm->attr = plumbunpackattr(cbuf); } if(p0==p1 || p1-p0>=BLOCKSIZE){ plumbfree(pm); break; } setgenstr(f, p0, p1); pm->data = Strtoc(&genstr); pm->ndata = strlen(pm->data); c = plumbpack(pm, &i); if(c != 0){ outTs(Hplumb, i); Write(1, c, i); free(c); } plumbfree(pm); break; case Texit: exits(0); } return TRUE; }
Posn readio(File *f, int *nulls, int setdate, int toterm) { int n, b, w; Rune *r; Posn nt; Posn p = addr.r.p2; uint32_t dev; uint64_t qid; int32_t mtime; char buf[BLOCKSIZE+1], *s; *nulls = FALSE; b = 0; if(f->unread){ nt = bufload(f, 0, io, nulls); if(toterm) raspload(f); }else for(nt = 0; (n = read(io, buf+b, BLOCKSIZE-b))>0; nt+=(r-genbuf)){ n += b; b = 0; r = genbuf; s = buf; while(n > 0){ if((*r = *(uint8_t*)s) < Runeself){ if(*r) r++; else *nulls = TRUE; --n; s++; continue; } if(fullrune(s, n)){ w = chartorune(r, s); if(*r) r++; else *nulls = TRUE; n -= w; s += w; continue; } b = n; memmove(buf, s, b); break; } loginsert(f, p, genbuf, r-genbuf); } if(b) *nulls = TRUE; if(*nulls) warn(Wnulls); if(setdate){ if(statfd(io, &dev, &qid, &mtime, 0, 0) > 0){ f->dev = dev; f->qidpath = qid; f->mtime = mtime; checkqid(f); } } return nt; }