diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 402b8f6..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -6.out -*.6 diff --git a/6.out b/6.out deleted file mode 100755 index f7324da..0000000 Binary files a/6.out and /dev/null differ diff --git a/acme.6 b/acme.6 deleted file mode 100644 index a8b1bf3..0000000 Binary files a/acme.6 and /dev/null differ diff --git a/acme.c b/acme.c deleted file mode 100644 index 804a56c..0000000 --- a/acme.c +++ /dev/null @@ -1,955 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - /* for generating syms in mkfile only: */ - #include - #include "edit.h" - -void mousethread(void*); -void keyboardthread(void*); -void waitthread(void*); -void xfidallocthread(void*); -void newwindowthread(void*); -void plumbproc(void*); - -Reffont **fontcache; -int nfontcache; -char wdir[512] = "."; -Reffont *reffonts[2]; -int snarffd = -1; -int mainpid; -int plumbsendfd; -int plumbeditfd; - -enum{ - NSnarf = 1000 /* less than 1024, I/O buffer size */ -}; -Rune snarfrune[NSnarf+1]; - -char *fontnames[2]; - -Command *command; - -void acmeerrorinit(void); -void readfile(Column*, char*); -int shutdown(void*, char*); - -void -derror(Display*, char *errorstr) -{ - error(errorstr); -} - -void -threadmain(int argc, char *argv[]) -{ - int i; - char *p, *loadfile; - char buf[256]; - Column *c; - int ncol; - Display *d; - - rfork(RFENVG|RFNAMEG); - - ncol = -1; - - loadfile = nil; - ARGBEGIN{ - case 'a': - globalindent[AUTOINDENT] = TRUE; - break; - case 'b': - bartflag = TRUE; - break; - case 'c': - p = ARGF(); - if(p == nil) - goto Usage; - ncol = atoi(p); - if(ncol <= 0) - goto Usage; - break; - case 'f': - fontnames[0] = ARGF(); - if(fontnames[0] == nil) - goto Usage; - break; - case 'F': - fontnames[1] = ARGF(); - if(fontnames[1] == nil) - goto Usage; - break; - case 'i': - globalindent[SPACESINDENT] = TRUE; - break; - case 'l': - loadfile = ARGF(); - if(loadfile == nil) - goto Usage; - break; - default: - Usage: - fprint(2, "usage: acme [-aib] [-c ncol] [-f font] [-F fixedfont] [-l loadfile | file...]\n"); - exits("usage"); - }ARGEND - - if(fontnames[0] != nil) - fontnames[0] = estrdup(fontnames[0]); - else - if((fontnames[0] = getenv("font")) == nil) - fontnames[0] = estrdup("/lib/font/bit/vga/unicode.font"); - if(access(fontnames[0], 0) < 0){ - fprint(2, "acme: can't access %s: %r\n", fontnames[0]); - exits("font open"); - } - if(fontnames[1] == nil) - fontnames[1] = fontnames[0]; - fontnames[1] = estrdup(fontnames[1]); - - quotefmtinstall(); - cputype = getenv("cputype"); - objtype = getenv("objtype"); - home = getenv("home"); - p = getenv("tabstop"); - if(p != nil){ - maxtab = strtoul(p, nil, 0); - free(p); - } - if(maxtab == 0) - maxtab = 4; - if(loadfile) - rowloadfonts(loadfile); - putenv("font", fontnames[0]); - snarffd = open("/dev/snarf", OREAD|OCEXEC); - if(cputype){ - sprint(buf, "/acme/bin/%s", cputype); - bind(buf, "/bin", MBEFORE); - } - bind("/acme/bin", "/bin", MBEFORE); - getwd(wdir, sizeof wdir); - - if(geninitdraw(nil, derror, fontnames[0], "acme", nil, Refnone) < 0){ - fprint(2, "acme: can't open display: %r\n"); - exits("geninitdraw"); - } - d = display; - font = d->defaultfont; - - reffont.f = font; - reffonts[0] = &reffont; - incref(&reffont); /* one to hold up 'font' variable */ - incref(&reffont); /* one to hold up reffonts[0] */ - fontcache = emalloc(sizeof(Reffont*)); - nfontcache = 1; - fontcache[0] = &reffont; - - iconinit(); - timerinit(); - rxinit(); - - cwait = threadwaitchan(); - ccommand = chancreate(sizeof(Command**), 0); - ckill = chancreate(sizeof(Rune*), 0); - cxfidalloc = chancreate(sizeof(Xfid*), 0); - cxfidfree = chancreate(sizeof(Xfid*), 0); - cnewwindow = chancreate(sizeof(Channel*), 0); - cerr = chancreate(sizeof(char*), 0); - cedit = chancreate(sizeof(int), 0); - cexit = chancreate(sizeof(int), 0); - cwarn = chancreate(sizeof(void*), 1); - if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cnewwindow==nil || cerr==nil || cedit==nil || cexit==nil || cwarn==nil){ - fprint(2, "acme: can't create initial channels: %r\n"); - threadexitsall("channels"); - } - - mousectl = initmouse(nil, screen); - if(mousectl == nil){ - fprint(2, "acme: can't initialize mouse: %r\n"); - threadexitsall("mouse"); - } - mouse = mousectl; - keyboardctl = initkeyboard(nil); - if(keyboardctl == nil){ - fprint(2, "acme: can't initialize keyboard: %r\n"); - threadexitsall("keyboard"); - } - mainpid = getpid(); - plumbeditfd = plumbopen("edit", OREAD|OCEXEC); - if(plumbeditfd >= 0){ - cplumb = chancreate(sizeof(Plumbmsg*), 0); - proccreate(plumbproc, nil, STACK); - } - plumbsendfd = plumbopen("send", OWRITE|OCEXEC); - - fsysinit(); - - #define WPERCOL 8 - disk = diskinit(); - if(!loadfile || !rowload(&row, loadfile, TRUE)){ - rowinit(&row, screen->clipr); - if(ncol < 0){ - if(argc == 0) - ncol = 2; - else{ - ncol = (argc+(WPERCOL-1))/WPERCOL; - if(ncol < 2) - ncol = 2; - } - } - if(ncol == 0) - ncol = 2; - for(i=0; i=row.ncol) - readfile(c, argv[i]); - else - readfile(row.col[i/WPERCOL], argv[i]); - } - } - flushimage(display, 1); - - acmeerrorinit(); - threadcreate(keyboardthread, nil, STACK); - threadcreate(mousethread, nil, STACK); - threadcreate(waitthread, nil, STACK); - threadcreate(xfidallocthread, nil, STACK); - threadcreate(newwindowthread, nil, STACK); - - threadnotify(shutdown, 1); - recvul(cexit); - killprocs(); - threadexitsall(nil); -} - -void -readfile(Column *c, char *s) -{ - Window *w; - Rune rb[256]; - int nb, nr; - Runestr rs; - - w = coladd(c, nil, nil, -1); - cvttorunes(s, strlen(s), rb, &nb, &nr, nil); - rs = cleanrname((Runestr){rb, nr}); - winsetname(w, rs.r, rs.nr); - textload(&w->body, 0, s, 1); - w->body.file->mod = FALSE; - w->dirty = FALSE; - winsettag(w); - textscrdraw(&w->body); - textsetselect(&w->tag, w->tag.file->nc, w->tag.file->nc); - xfidlog(w, "new"); -} - -char *oknotes[] ={ - "delete", - "hangup", - "kill", - "exit", - nil -}; - -int dumping; - -int -shutdown(void*, char *msg) -{ - int i; - - killprocs(); - if(!dumping && strcmp(msg, "kill")!=0 && strcmp(msg, "exit")!=0 && getpid()==mainpid){ - dumping = TRUE; - rowdump(&row, nil); - } - for(i=0; oknotes[i]; i++) - if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0) - threadexitsall(msg); - print("acme: %s\n", msg); - abort(); -} - -void -killprocs(void) -{ - Command *c; - - fsysclose(); - for(c=command; c; c=c->next) - postnote(PNGROUP, c->pid, "hangup"); - remove(acmeerrorfile); -} - -static int errorfd; - -void -acmeerrorproc(void *) -{ - char *buf, *s; - int n; - - threadsetname("acmeerrorproc"); - buf = emalloc(8192+1); - while((n=read(errorfd, buf, 8192)) >= 0){ - buf[n] = '\0'; - s = estrdup(buf); - sendp(cerr, s); - } - free(buf); -} - -void -acmeerrorinit(void) -{ - int fd, pfd[2]; - char buf[64]; - - if(pipe(pfd) < 0) - error("can't create pipe"); - sprint(acmeerrorfile, "/srv/acme.%s.%d", user, mainpid); - fd = create(acmeerrorfile, OWRITE, 0666); - if(fd < 0){ - remove(acmeerrorfile); - fd = create(acmeerrorfile, OWRITE, 0666); - if(fd < 0) - error("can't create acmeerror file"); - } - sprint(buf, "%d", pfd[0]); - write(fd, buf, strlen(buf)); - close(fd); - /* reopen pfd[1] close on exec */ - sprint(buf, "/fd/%d", pfd[1]); - errorfd = open(buf, OREAD|OCEXEC); - if(errorfd < 0) - error("can't re-open acmeerror file"); - close(pfd[1]); - close(pfd[0]); - proccreate(acmeerrorproc, nil, STACK); -} - -void -plumbproc(void *) -{ - Plumbmsg *m; - - threadsetname("plumbproc"); - for(;;){ - m = plumbrecv(plumbeditfd); - if(m == nil) - threadexits(nil); - sendp(cplumb, m); - } -} - -void -keyboardthread(void *) -{ - Rune r; - Timer *timer; - Text *t; - enum { KTimer, KKey, NKALT }; - static Alt alts[NKALT+1]; - - alts[KTimer].c = nil; - alts[KTimer].v = nil; - alts[KTimer].op = CHANNOP; - alts[KKey].c = keyboardctl->c; - alts[KKey].v = &r; - alts[KKey].op = CHANRCV; - alts[NKALT].op = CHANEND; - - timer = nil; - typetext = nil; - threadsetname("keyboardthread"); - for(;;){ - switch(alt(alts)){ - case KTimer: - timerstop(timer); - t = typetext; - if(t!=nil && t->what==Tag){ - winlock(t->w, 'K'); - wincommit(t->w, t); - winunlock(t->w); - flushimage(display, 1); - } - alts[KTimer].c = nil; - alts[KTimer].op = CHANNOP; - break; - case KKey: - casekeyboard: - typetext = rowtype(&row, r, mouse->xy); - t = typetext; - if(t!=nil && t->col!=nil && !(r==Kdown || r==Kleft || r==Kright)) /* scrolling doesn't change activecol */ - activecol = t->col; - if(t!=nil && t->w!=nil) - t->w->body.file->curtext = &t->w->body; - if(timer != nil) - timercancel(timer); - if(t!=nil && t->what==Tag) { - timer = timerstart(500); - alts[KTimer].c = timer->c; - alts[KTimer].op = CHANRCV; - }else{ - timer = nil; - alts[KTimer].c = nil; - alts[KTimer].op = CHANNOP; - } - if(nbrecv(keyboardctl->c, &r) > 0) - goto casekeyboard; - flushimage(display, 1); - break; - } - } -} - -void -mousethread(void *) -{ - Text *t, *argt; - int but; - uint q0, q1; - Window *w; - Plumbmsg *pm; - Mouse m; - char *act; - enum { MResize, MMouse, MPlumb, MWarnings, NMALT }; - static Alt alts[NMALT+1]; - - threadsetname("mousethread"); - alts[MResize].c = mousectl->resizec; - alts[MResize].v = nil; - alts[MResize].op = CHANRCV; - alts[MMouse].c = mousectl->c; - alts[MMouse].v = &mousectl->Mouse; - alts[MMouse].op = CHANRCV; - alts[MPlumb].c = cplumb; - alts[MPlumb].v = ± - alts[MPlumb].op = CHANRCV; - alts[MWarnings].c = cwarn; - alts[MWarnings].v = nil; - alts[MWarnings].op = CHANRCV; - if(cplumb == nil) - alts[MPlumb].op = CHANNOP; - alts[NMALT].op = CHANEND; - - for(;;){ - qlock(&row); - flushwarnings(); - qunlock(&row); - flushimage(display, 1); - switch(alt(alts)){ - case MResize: - if(getwindow(display, Refnone) < 0) - error("attach to window"); - scrlresize(); - rowresize(&row, screen->clipr); - break; - case MPlumb: - if(strcmp(pm->type, "text") == 0){ - act = plumblookup(pm->attr, "action"); - if(act==nil || strcmp(act, "showfile")==0) - plumblook(pm); - else if(strcmp(act, "showdata")==0) - plumbshow(pm); - } - plumbfree(pm); - break; - case MWarnings: - break; - case MMouse: - /* - * Make a copy so decisions are consistent; mousectl changes - * underfoot. Can't just receive into m because this introduces - * another race; see /sys/src/libdraw/mouse.c. - */ - m = mousectl->Mouse; - qlock(&row); - t = rowwhich(&row, m.xy); - - if((t!=mousetext && t!=nil && t->w!=nil) && - (mousetext==nil || mousetext->w==nil || t->w->id!=mousetext->w->id)) { - xfidlog(t->w, "focus"); - } - - if(t!=mousetext && mousetext!=nil && mousetext->w!=nil){ - winlock(mousetext->w, 'M'); - mousetext->eq0 = ~0; - wincommit(mousetext->w, mousetext); - winunlock(mousetext->w); - } - mousetext = t; - if(t == nil) - goto Continue; - w = t->w; - if(t==nil || m.buttons==0) - goto Continue; - but = 0; - if(m.buttons == 1) - but = 1; - else if(m.buttons == 2) - but = 2; - else if(m.buttons == 4) - but = 3; - barttext = t; - if(t->what==Body && ptinrect(m.xy, t->scrollr)){ - if(but){ - winlock(w, 'M'); - t->eq0 = ~0; - textscroll(t, but); - winunlock(w); - } - goto Continue; - } - /* scroll buttons, wheels, etc. */ - if(t->what==Body && w != nil && (m.buttons & (8|16))){ - if(m.buttons & 8) - but = Kscrolloneup; - else - but = Kscrollonedown; - winlock(w, 'M'); - t->eq0 = ~0; - texttype(t, but); - winunlock(w); - goto Continue; - } - if(ptinrect(m.xy, t->scrollr)){ - if(but){ - if(t->what == Columntag) - rowdragcol(&row, t->col, but); - else if(t->what == Tag){ - coldragwin(t->col, t->w, but); - if(t->w) - barttext = &t->w->body; - } - if(t->col) - activecol = t->col; - } - goto Continue; - } - if(m.buttons){ - if(w) - winlock(w, 'M'); - t->eq0 = ~0; - if(w) - wincommit(w, t); - else - textcommit(t, TRUE); - if(m.buttons & 1){ - textselect(t); - if(w) - winsettag(w); - argtext = t; - seltext = t; - if(t->col) - activecol = t->col; /* button 1 only */ - if(t->w!=nil && t==&t->w->body) - activewin = t->w; - }else if(m.buttons & 2){ - if(textselect2(t, &q0, &q1, &argt)) - execute(t, q0, q1, FALSE, argt); - }else if(m.buttons & 4){ - if(textselect3(t, &q0, &q1)) - look3(t, q0, q1, FALSE); - } - if(w) - winunlock(w); - goto Continue; - } - Continue: - qunlock(&row); - break; - } - } -} - -/* - * There is a race between process exiting and our finding out it was ever created. - * This structure keeps a list of processes that have exited we haven't heard of. - */ -typedef struct Pid Pid; -struct Pid -{ - int pid; - char msg[ERRMAX]; - Pid *next; -}; - -void -waitthread(void *) -{ - Waitmsg *w; - Command *c, *lc; - uint pid; - int found, ncmd; - Rune *cmd; - char *err; - Text *t; - Pid *pids, *p, *lastp; - enum { WErr, WKill, WWait, WCmd, NWALT }; - Alt alts[NWALT+1]; - - threadsetname("waitthread"); - pids = nil; - alts[WErr].c = cerr; - alts[WErr].v = &err; - alts[WErr].op = CHANRCV; - alts[WKill].c = ckill; - alts[WKill].v = &cmd; - alts[WKill].op = CHANRCV; - alts[WWait].c = cwait; - alts[WWait].v = &w; - alts[WWait].op = CHANRCV; - alts[WCmd].c = ccommand; - alts[WCmd].v = &c; - alts[WCmd].op = CHANRCV; - alts[NWALT].op = CHANEND; - - command = nil; - for(;;){ - switch(alt(alts)){ - case WErr: - qlock(&row); - warning(nil, "%s", err); - free(err); - flushimage(display, 1); - qunlock(&row); - break; - case WKill: - found = FALSE; - ncmd = runestrlen(cmd); - for(c=command; c; c=c->next){ - /* -1 for blank */ - if(runeeq(c->name, c->nname-1, cmd, ncmd) == TRUE){ - if(postnote(PNGROUP, c->pid, "kill") < 0) - warning(nil, "kill %S: %r\n", cmd); - found = TRUE; - } - } - if(!found) - warning(nil, "Kill: no process %S\n", cmd); - free(cmd); - break; - case WWait: - pid = w->pid; - lc = nil; - for(c=command; c; c=c->next){ - if(c->pid == pid){ - if(lc) - lc->next = c->next; - else - command = c->next; - break; - } - lc = c; - } - qlock(&row); - t = &row.tag; - textcommit(t, TRUE); - if(c == nil){ - /* helper processes use this exit status */ - if(strncmp(w->msg, "libthread", 9) != 0){ - p = emalloc(sizeof(Pid)); - p->pid = pid; - strncpy(p->msg, w->msg, sizeof(p->msg)); - p->next = pids; - pids = p; - } - }else{ - if(search(t, c->name, c->nname)){ - textdelete(t, t->q0, t->q1, TRUE); - textsetselect(t, 0, 0); - } - if(w->msg[0]) - warning(c->md, "%s\n", w->msg); - flushimage(display, 1); - } - qunlock(&row); - free(w); - Freecmd: - if(c){ - if(c->iseditcmd) - sendul(cedit, 0); - free(c->text); - free(c->name); - fsysdelid(c->md); - free(c); - } - break; - case WCmd: - /* has this command already exited? */ - lastp = nil; - for(p=pids; p!=nil; p=p->next){ - if(p->pid == c->pid){ - if(p->msg[0]) - warning(c->md, "%s\n", p->msg); - if(lastp == nil) - pids = p->next; - else - lastp->next = p->next; - free(p); - goto Freecmd; - } - lastp = p; - } - c->next = command; - command = c; - qlock(&row); - t = &row.tag; - textcommit(t, TRUE); - textinsert(t, 0, c->name, c->nname, TRUE); - textsetselect(t, 0, 0); - flushimage(display, 1); - qunlock(&row); - break; - } - } -} - -void -xfidallocthread(void*) -{ - Xfid *xfree, *x; - enum { Alloc, Free, N }; - static Alt alts[N+1]; - - threadsetname("xfidallocthread"); - alts[Alloc].c = cxfidalloc; - alts[Alloc].v = nil; - alts[Alloc].op = CHANRCV; - alts[Free].c = cxfidfree; - alts[Free].v = &x; - alts[Free].op = CHANRCV; - alts[N].op = CHANEND; - - xfree = nil; - for(;;){ - switch(alt(alts)){ - case Alloc: - x = xfree; - if(x) - xfree = x->next; - else{ - x = emalloc(sizeof(Xfid)); - x->c = chancreate(sizeof(void(*)(Xfid*)), 0); - x->arg = x; - threadcreate(xfidctl, x->arg, STACK); - } - sendp(cxfidalloc, x); - break; - case Free: - x->next = xfree; - xfree = x; - break; - } - } -} - -/* this thread, in the main proc, allows fsysproc to get a window made without doing graphics */ -void -newwindowthread(void*) -{ - Window *w; - - threadsetname("newwindowthread"); - - for(;;){ - /* only fsysproc is talking to us, so synchronization is trivial */ - recvp(cnewwindow); - w = makenewwindow(nil); - winsettag(w); - xfidlog(w, "new"); - sendp(cnewwindow, w); - } -} - -Reffont* -rfget(int fix, int save, int setfont, char *name) -{ - Reffont *r; - Font *f; - int i; - - r = nil; - if(name == nil){ - name = fontnames[fix]; - r = reffonts[fix]; - } - if(r == nil){ - for(i=0; if->name) == 0){ - r = fontcache[i]; - goto Found; - } - f = openfont(display, name); - if(f == nil){ - warning(nil, "can't open font file %s: %r\n", name); - return nil; - } - r = emalloc(sizeof(Reffont)); - r->f = f; - fontcache = erealloc(fontcache, (nfontcache+1)*sizeof(Reffont*)); - fontcache[nfontcache++] = r; - } - Found: - if(save){ - incref(r); - if(reffonts[fix]) - rfclose(reffonts[fix]); - reffonts[fix] = r; - if(name != fontnames[fix]){ - free(fontnames[fix]); - fontnames[fix] = estrdup(name); - } - } - if(setfont){ - reffont.f = r->f; - incref(r); - rfclose(reffonts[0]); - font = r->f; - reffonts[0] = r; - incref(r); - iconinit(); - } - incref(r); - return r; -} - -void -rfclose(Reffont *r) -{ - int i; - - if(decref(r) == 0){ - for(i=0; i= nfontcache) - warning(nil, "internal error: can't find font in cache\n"); - else{ - nfontcache--; - memmove(fontcache+i, fontcache+i+1, (nfontcache-i)*sizeof(Reffont*)); - } - freefont(r->f); - free(r); - } -} - -Cursor boxcursor = { - {-7, -7}, - {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, - 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, - 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, - 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, - 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00} -}; - -void -iconinit(void) -{ - Rectangle r; - Image *tmp; - - tagcols[BACK] = display->white; - tagcols[HIGH] = allocimagemix(display, DBlack, 0xb53a38FF); - tagcols[BORD] = allocimagemix(display, DBlack, 0xb53a38FF); - tagcols[TEXT] = display->black; - tagcols[HTEXT] = display->white; - - textcols[BACK] = allocimagemix(display, DPaleyellow, DWhite); - textcols[HIGH] = allocimagemix(display, DBlack, 0xb53a38FF); - textcols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DWhite); - draw(textcols[BORD], Rect(1,1,2,2), display->black, nil, ZP); - draw(textcols[BORD], Rect(0,0,1,1), display->black, nil, ZP); - textcols[TEXT] = display->black; - textcols[HTEXT] = display->white; - - if(button){ - freeimage(button); - freeimage(modbutton); - freeimage(colbutton); - } - - r = Rect(0, 0, Scrollwid, font->height+1); - button = allocimage(display, r, screen->chan, 0, DNofill); - draw(button, r, tagcols[BORD], nil, r.min); - r.max.x -= 4; - fillellipse(button, (Point){r.min.x + 5, r.min.y + 7}, 3, 3, display->white, ZP); - r = button->r; - modbutton = allocimage(display, r, screen->chan, 0, DNofill); - draw(modbutton, r, tagcols[BORD], nil, r.min); - r = insetrect(r, 2); - fillellipse(modbutton, (Point){r.min.x + 3, r.min.y + 5}, 3, 3, display->black, ZP); - r = button->r; - colbutton = allocimagemix(display, DBlack, 0xb53a38FF); - but2col = allocimage(display, r, screen->chan, 1, 0x000000FF); - but3col = allocimagemix(display, DBlack, 0xb53a38FF); -} - -/* - * /dev/snarf updates when the file is closed, so we must open our own - * fd here rather than use snarffd - */ - -/* rio truncates larges snarf buffers, so this avoids using the - * service if the string is huge */ - -#define MAXSNARF 100*1024 - -void -putsnarf(void) -{ - int fd, i, n; - - if(snarffd<0 || snarfbuf.nc==0) - return; - if(snarfbuf.nc > MAXSNARF) - return; - fd = open("/dev/snarf", OWRITE); - if(fd < 0) - return; - for(i=0; i= NSnarf) - n = NSnarf; - bufread(&snarfbuf, i, snarfrune, n); - if(fprint(fd, "%.*S", n, snarfrune) < 0) - break; - } - close(fd); -} - -void -getsnarf() -{ - int nulls; - - if(snarfbuf.nc > MAXSNARF) - return; - if(snarffd < 0) - return; - seek(snarffd, 0, 0); - bufreset(&snarfbuf); - bufload(&snarfbuf, 0, snarffd, &nulls); -} diff --git a/addr.6 b/addr.6 deleted file mode 100644 index 2ac161d..0000000 Binary files a/addr.6 and /dev/null differ diff --git a/addr.c b/addr.c deleted file mode 100644 index 0637fab..0000000 --- a/addr.c +++ /dev/null @@ -1,291 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -enum -{ - None = 0, - Fore = '+', - Back = '-', -}; - -enum -{ - Char, - Line, -}; - -int -isaddrc(int r) -{ - if(r && utfrune("0123456789+-/$.#,;", r)!=nil) - return TRUE; - return FALSE; -} - -/* - * quite hard: could be almost anything but white space, but we are a little conservative, - * aiming for regular expressions of alphanumerics and no white space - */ -int -isregexc(int r) -{ - if(r == 0) - return FALSE; - if(isalnum(r)) - return TRUE; - if(utfrune("^+-.*?#,;[]()$", r)!=nil) - return TRUE; - return FALSE; -} - -// nlcounttopos starts at q0 and advances nl lines, -// being careful not to walk past the end of the text, -// and then nr chars, being careful not to walk past -// the end of the current line. -// It returns the final position. -long -nlcounttopos(Text *t, long q0, long nl, long nr) -{ - while(nl > 0 && q0 < t->file->nc) { - if(textreadc(t, q0++) == '\n') - nl--; - } - if(nl > 0) - return q0; - while(nr > 0 && q0 < t->file->nc && textreadc(t, q0) != '\n') { - q0++; - nr--; - } - return q0; -} - -Range -number(Mntdir *md, Text *t, Range r, int line, int dir, int size, int *evalp) -{ - uint q0, q1; - - if(size == Char){ - if(dir == Fore) - line = r.q1+line; - else if(dir == Back){ - if(r.q0==0 && line>0) - r.q0 = t->file->nc; - line = r.q0 - line; - } - if(line<0 || line>t->file->nc) - goto Rescue; - *evalp = TRUE; - return (Range){line, line}; - } - q0 = r.q0; - q1 = r.q1; - switch(dir){ - case None: - q0 = 0; - q1 = 0; - Forward: - while(line>0 && q1file->nc) - if(textreadc(t, q1++) == '\n' || q1==t->file->nc) - if(--line > 0) - q0 = q1; - if(line > 0) - goto Rescue; - break; - case Fore: - if(q1 > 0) - while(q1file->nc && textreadc(t, q1-1) != '\n') - q1++; - q0 = q1; - goto Forward; - case Back: - if(q0 < t->file->nc) - while(q0>0 && textreadc(t, q0-1)!='\n') - q0--; - q1 = q0; - while(line>0 && q0>0){ - if(textreadc(t, q0-1) == '\n'){ - if(--line >= 0) - q1 = q0; - } - --q0; - } - /* :1-1 is :0 = #0, but :1-2 is an error */ - if(line > 1) - goto Rescue; - while(q0>0 && textreadc(t, q0-1)!='\n') - --q0; - } - *evalp = TRUE; - return (Range){q0, q1}; - - Rescue: - if(md != nil) - warning(nil, "address out of range\n"); - *evalp = FALSE; - return r; -} - - -Range -regexp(Mntdir *md, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp) -{ - int found; - Rangeset sel; - int q; - - if(pat[0] == '\0' && rxnull()){ - warning(md, "no previous regular expression\n"); - *foundp = FALSE; - return r; - } - if(pat[0] && rxcompile(pat) == FALSE){ - *foundp = FALSE; - return r; - } - if(dir == Back) - found = rxbexecute(t, r.q0, &sel); - else{ - if(lim.q0 < 0) - q = Infinity; - else - q = lim.q1; - found = rxexecute(t, nil, r.q1, q, &sel); - } - if(!found && md==nil) - warning(nil, "no match for regexp\n"); - *foundp = found; - return sel.r[0]; -} - -Range -address(Mntdir *md, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp) -{ - int dir, size, npat; - int prevc, c, nc, n; - uint q; - Rune *pat; - Range r, nr; - - r = ar; - q = q0; - dir = None; - size = Line; - c = 0; - while(q < q1){ - prevc = c; - c = (*getc)(a, q++); - switch(c){ - default: - *qp = q-1; - return r; - case ';': - ar = r; - /* fall through */ - case ',': - if(prevc == 0) /* lhs defaults to 0 */ - r.q0 = 0; - if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */ - r.q1 = t->file->nc; - else{ - nr = address(md, t, lim, ar, a, q, q1, getc, evalp, &q); - r.q1 = nr.q1; - } - *qp = q; - return r; - case '+': - case '-': - if(*evalp && (prevc=='+' || prevc=='-')) - if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?') - r = number(md, t, r, 1, prevc, Line, evalp); /* do previous one */ - dir = c; - break; - case '.': - case '$': - if(q != q0+1){ - *qp = q-1; - return r; - } - if(*evalp) - if(c == '.') - r = ar; - else - r = (Range){t->file->nc, t->file->nc}; - if(q < q1) - dir = Fore; - else - dir = None; - break; - case '#': - if(q==q1 || (c=(*getc)(a, q++))<'0' || '9' -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -enum -{ - Slop = 100, /* room to grow with reallocation */ -}; - -static -void -sizecache(Buffer *b, uint n) -{ - if(n <= b->cmax) - return; - b->cmax = n+Slop; - b->c = runerealloc(b->c, b->cmax); -} - -static -void -addblock(Buffer *b, uint i, uint n) -{ - if(i > b->nbl) - error("internal error: addblock"); - - b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]); - if(i < b->nbl) - memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*)); - b->bl[i] = disknewblock(disk, n); - b->nbl++; -} - -static -void -delblock(Buffer *b, uint i) -{ - if(i >= b->nbl) - error("internal error: delblock"); - - diskrelease(disk, b->bl[i]); - b->nbl--; - if(i < b->nbl) - memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*)); - b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]); -} - -/* - * Move cache so b->cq <= q0 < b->cq+b->cnc. - * If at very end, q0 will fall on end of cache block. - */ - -static -void -flush(Buffer *b) -{ - if(b->cdirty || b->cnc==0){ - if(b->cnc == 0) - delblock(b, b->cbi); - else - diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc); - b->cdirty = FALSE; - } -} - -static -void -setcache(Buffer *b, uint q0) -{ - Block **blp, *bl; - uint i, q; - - if(q0 > b->nc) - error("internal error: setcache"); - /* - * flush and reload if q0 is not in cache. - */ - if(b->nc == 0 || (b->cq<=q0 && q0cq+b->cnc)) - return; - /* - * if q0 is at end of file and end of cache, continue to grow this block - */ - if(q0==b->nc && q0==b->cq+b->cnc && b->cnccq){ - q = 0; - i = 0; - }else{ - q = b->cq; - i = b->cbi; - } - blp = &b->bl[i]; - while(q+(*blp)->n <= q0 && q+(*blp)->n < b->nc){ - q += (*blp)->n; - i++; - blp++; - if(i >= b->nbl) - error("block not found"); - } - bl = *blp; - /* remember position */ - b->cbi = i; - b->cq = q; - sizecache(b, bl->n); - b->cnc = bl->n; - /*read block*/ - diskread(disk, bl, b->c, b->cnc); -} - -void -bufinsert(Buffer *b, uint q0, Rune *s, uint n) -{ - uint i, m, t, off; - - if(q0 > b->nc) - error("internal error: bufinsert"); - - while(n > 0){ - setcache(b, q0); - off = q0-b->cq; - if(b->cnc+n <= Maxblock){ - /* Everything fits in one block. */ - t = b->cnc+n; - m = n; - if(b->bl == nil){ /* allocate */ - if(b->cnc != 0) - error("internal error: bufinsert1 cnc!=0"); - addblock(b, 0, t); - b->cbi = 0; - } - sizecache(b, t); - runemove(b->c+off+m, b->c+off, b->cnc-off); - runemove(b->c+off, s, m); - b->cnc = t; - goto Tail; - } - /* - * We must make a new block. If q0 is at - * the very beginning or end of this block, - * just make a new block and fill it. - */ - if(q0==b->cq || q0==b->cq+b->cnc){ - if(b->cdirty) - flush(b); - m = min(n, Maxblock); - if(b->bl == nil){ /* allocate */ - if(b->cnc != 0) - error("internal error: bufinsert2 cnc!=0"); - i = 0; - }else{ - i = b->cbi; - if(q0 > b->cq) - i++; - } - addblock(b, i, m); - sizecache(b, m); - runemove(b->c, s, m); - b->cq = q0; - b->cbi = i; - b->cnc = m; - goto Tail; - } - /* - * Split the block; cut off the right side and - * let go of it. - */ - m = b->cnc-off; - if(m > 0){ - i = b->cbi+1; - addblock(b, i, m); - diskwrite(disk, &b->bl[i], b->c+off, m); - b->cnc -= m; - } - /* - * Now at end of block. Take as much input - * as possible and tack it on end of block. - */ - m = min(n, Maxblock-b->cnc); - sizecache(b, b->cnc+m); - runemove(b->c+b->cnc, s, m); - b->cnc += m; - Tail: - b->nc += m; - q0 += m; - s += m; - n -= m; - b->cdirty = TRUE; - } -} - -void -bufdelete(Buffer *b, uint q0, uint q1) -{ - uint m, n, off; - - if(!(q0<=q1 && q0<=b->nc && q1<=b->nc)) - error("internal error: bufdelete"); - while(q1 > q0){ - setcache(b, q0); - off = q0-b->cq; - if(q1 > b->cq+b->cnc) - n = b->cnc - off; - else - n = q1-q0; - m = b->cnc - (off+n); - if(m > 0) - runemove(b->c+off, b->c+off+n, m); - b->cnc -= n; - b->cdirty = TRUE; - q1 -= n; - b->nc -= n; - } -} - -static int -bufloader(void *v, uint q0, Rune *r, int nr) -{ - bufinsert(v, q0, r, nr); - return nr; -} - -uint -loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg) -{ - char *p; - Rune *r; - int l, m, n, nb, nr; - uint q1; - - p = emalloc((Maxblock+UTFmax+1)*sizeof p[0]); - r = runemalloc(Maxblock); - m = 0; - n = 1; - q1 = q0; - /* - * At top of loop, may have m bytes left over from - * last pass, possibly representing a partial rune. - */ - while(n > 0){ - n = read(fd, p+m, Maxblock); - if(n < 0){ - warning(nil, "read error in Buffer.load"); - break; - } - m += n; - p[m] = 0; - l = m; - if(n > 0) - l -= UTFmax; - cvttorunes(p, l, r, &nb, &nr, nulls); - memmove(p, p+nb, m-nb); - m -= nb; - q1 += (*f)(arg, q1, r, nr); - } - free(p); - free(r); - return q1-q0; -} - -uint -bufload(Buffer *b, uint q0, int fd, int *nulls) -{ - if(q0 > b->nc) - error("internal error: bufload"); - return loadfile(fd, q0, nulls, bufloader, b); -} - -void -bufread(Buffer *b, uint q0, Rune *s, uint n) -{ - uint m; - - if(!(q0<=b->nc && q0+n<=b->nc)) - error("bufread: internal error"); - - while(n > 0){ - setcache(b, q0); - m = min(n, b->cnc-(q0-b->cq)); - runemove(s, b->c+(q0-b->cq), m); - q0 += m; - s += m; - n -= m; - } -} - -void -bufreset(Buffer *b) -{ - int i; - - b->nc = 0; - b->cnc = 0; - b->cq = 0; - b->cdirty = 0; - b->cbi = 0; - /* delete backwards to avoid n² behavior */ - for(i=b->nbl-1; --i>=0; ) - delblock(b, i); -} - -void -bufclose(Buffer *b) -{ - bufreset(b); - free(b->c); - b->c = nil; - b->cnc = 0; - free(b->bl); - b->bl = nil; - b->nbl = 0; -} diff --git a/cols.6 b/cols.6 deleted file mode 100644 index 65fd31d..0000000 Binary files a/cols.6 and /dev/null differ diff --git a/cols.c b/cols.c deleted file mode 100644 index cfd29b0..0000000 --- a/cols.c +++ /dev/null @@ -1,551 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -void -colinit(Column *c, Rectangle r) -{ - Rectangle r1; - Text *t; - - draw(screen, r, display->white, nil, ZP); - c->r = r; - c->w = nil; - c->nw = 0; - t = &c->tag; - t->w = nil; - t->col = c; - r1 = r; - r1.max.y = r1.min.y + font->height; - textinit(t, fileaddtext(nil, t), r1, &reffont, tagcols); - t->what = Columntag; - r1.min.y = r1.max.y; - r1.max.y += Border; - draw(screen, r1, display->black, nil, ZP); - textinsert(t, 0, L"New Cut Paste Snarf Sort Zerox Delcol ", 38, TRUE); - textsetselect(t, t->file->nc, t->file->nc); - draw(screen, t->scrollr, colbutton, nil, colbutton->r.min); - c->safe = TRUE; -} - -Window* -coladd(Column *c, Window *w, Window *clone, int y) -{ - Rectangle r, r1; - Window *v; - int i, t; - - v = nil; - r = c->r; - r.min.y = c->tag.r.max.y+Border; - if(ynw>0){ /* steal half of last window by default */ - v = c->w[c->nw-1]; - y = v->body.r.min.y+Dy(v->body.r)/2; - } - /* look for window we'll land on */ - for(i=0; inw; i++){ - v = c->w[i]; - if(y < v->r.max.y) - break; - } - if(c->nw > 0){ - if(i < c->nw) - i++; /* new window will go after v */ - /* - * if v's too small, grow it first. - */ - if(!c->safe || v->body.maxlines<=3){ - colgrow(c, v, 1); - y = v->body.r.min.y+Dy(v->body.r)/2; - } - r = v->r; - if(i == c->nw) - t = c->r.max.y; - else - t = c->w[i]->r.min.y-Border; - r.max.y = t; - draw(screen, r, textcols[BACK], nil, ZP); - r1 = r; - y = min(y, t-(v->tag.font->height+v->body.font->height+Border+1)); - r1.max.y = min(y, v->body.r.min.y+v->body.nlines*v->body.font->height); - r1.min.y = winresize(v, r1, FALSE, FALSE); - r1.max.y = r1.min.y+Border; - draw(screen, r1, display->black, nil, ZP); - r.min.y = r1.max.y; - } - if(w == nil){ - w = emalloc(sizeof(Window)); - w->rdselfd = -1; - w->col = c; - draw(screen, r, textcols[BACK], nil, ZP); - wininit(w, clone, r); - }else{ - w->col = c; - winresize(w, r, FALSE, TRUE); - } - w->tag.col = c; - w->tag.row = c->row; - w->body.col = c; - w->body.row = c->row; - c->w = realloc(c->w, (c->nw+1)*sizeof(Window*)); - memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*)); - c->nw++; - c->w[i] = w; - savemouse(w); - /* near but not on the button */ - moveto(mousectl, addpt(w->tag.scrollr.max, Pt(3, 3))); - barttext = &w->body; - c->safe = TRUE; - return w; -} - -void -colclose(Column *c, Window *w, int dofree) -{ - Rectangle r; - int i, didmouse, up; - - /* w is locked */ - if(!c->safe) - colgrow(c, w, 1); - for(i=0; inw; i++) - if(c->w[i] == w) - goto Found; - error("can't find window"); - Found: - r = w->r; - w->tag.col = nil; - w->body.col = nil; - w->col = nil; - didmouse = restoremouse(w); - if(dofree){ - windelete(w); - winclose(w); - } - c->nw--; - memmove(c->w+i, c->w+i+1, (c->nw-i)*sizeof(Window*)); - c->w = realloc(c->w, c->nw*sizeof(Window*)); - if(c->nw == 0){ - draw(screen, r, display->white, nil, ZP); - return; - } - up = 0; - if(i == c->nw){ /* extend last window down */ - w = c->w[i-1]; - r.min.y = w->r.min.y; - r.max.y = c->r.max.y; - }else{ /* extend next window up */ - up = 1; - w = c->w[i]; - r.max.y = w->r.max.y; - } - draw(screen, r, textcols[BACK], nil, ZP); - if(c->safe) { - if(!didmouse && up) - w->showdel = TRUE; - winresize(w, r, FALSE, TRUE); - if(!didmouse && up) - movetodel(w); - } -} - -void -colcloseall(Column *c) -{ - int i; - Window *w; - - if(c == activecol) - activecol = nil; - textclose(&c->tag); - for(i=0; inw; i++){ - w = c->w[i]; - winclose(w); - } - c->nw = 0; - free(c->w); - free(c); - clearmouse(); -} - -void -colmousebut(Column *c) -{ - moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.max), 2)); -} - -void -colresize(Column *c, Rectangle r) -{ - int i, old, new; - Rectangle r1, r2; - Window *w; - - clearmouse(); - r1 = r; - r1.max.y = r1.min.y + c->tag.font->height; - textresize(&c->tag, r1, TRUE); - draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min); - r1.min.y = r1.max.y; - r1.max.y += Border; - draw(screen, r1, display->black, nil, ZP); - r1.max.y = r.max.y; - new = Dy(r) - c->nw*(Border + font->height); - old = Dy(c->r) - c->nw*(Border + font->height); - for(i=0; inw; i++){ - w = c->w[i]; - w->maxlines = 0; - if(i == c->nw-1) - r1.max.y = r.max.y; - else { - r1.max.y = r1.min.y; - if(new > 0 && old > 0 && Dy(w->r) > Border+font->height) - r1.max.y += (Dy(w->r)-Border-font->height)*new/old + Border + font->height; - } - r1.max.y = max(r1.max.y, r1.min.y + Border+font->height); - r2 = r1; - r2.max.y = r2.min.y+Border; - draw(screen, r2, display->black, nil, ZP); - r1.min.y = r2.max.y; - r1.min.y = winresize(w, r1, FALSE, i==c->nw-1); - } - c->r = r; -} - -static -int -colcmp(void *a, void *b) -{ - Rune *r1, *r2; - int i, nr1, nr2; - - r1 = (*(Window**)a)->body.file->name; - nr1 = (*(Window**)a)->body.file->nname; - r2 = (*(Window**)b)->body.file->name; - nr2 = (*(Window**)b)->body.file->nname; - for(i=0; inw == 0) - return; - clearmouse(); - rp = emalloc(c->nw*sizeof(Rectangle)); - wp = emalloc(c->nw*sizeof(Window*)); - memmove(wp, c->w, c->nw*sizeof(Window*)); - qsort(wp, c->nw, sizeof(Window*), colcmp); - for(i=0; inw; i++) - rp[i] = wp[i]->r; - r = c->r; - r.min.y = c->tag.r.max.y; - draw(screen, r, textcols[BACK], nil, ZP); - y = r.min.y; - for(i=0; inw; i++){ - w = wp[i]; - r.min.y = y; - if(i == c->nw-1) - r.max.y = c->r.max.y; - else - r.max.y = r.min.y+Dy(w->r)+Border; - r1 = r; - r1.max.y = r1.min.y+Border; - draw(screen, r1, display->black, nil, ZP); - r.min.y = r1.max.y; - y = winresize(w, r, FALSE, i==c->nw-1); - } - free(rp); - free(c->w); - c->w = wp; -} - -void -colgrow(Column *c, Window *w, int but) -{ - Rectangle r, cr; - int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h; - Window *v; - - for(i=0; inw; i++) - if(c->w[i] == w) - goto Found; - error("can't find window"); - - Found: - cr = c->r; - if(but < 0){ /* make sure window fills its own space properly */ - r = w->r; - if(i==c->nw-1 || c->safe==FALSE) - r.max.y = cr.max.y; - else - r.max.y = c->w[i+1]->r.min.y - Border; - winresize(w, r, FALSE, TRUE); - return; - } - cr.min.y = c->w[0]->r.min.y; - if(but == 3){ /* full size */ - if(i != 0){ - v = c->w[0]; - c->w[0] = w; - c->w[i] = v; - } - draw(screen, cr, textcols[BACK], nil, ZP); - winresize(w, cr, FALSE, TRUE); - for(i=1; inw; i++) - c->w[i]->body.maxlines = 0; - c->safe = FALSE; - return; - } - /* store old #lines for each window */ - onl = w->body.maxlines; - nl = emalloc(c->nw * sizeof(int)); - ny = emalloc(c->nw * sizeof(int)); - tot = 0; - for(j=0; jnw; j++){ - l = c->w[j]->body.maxlines; - nl[j] = l; - tot += l; - } - /* approximate new #lines for this window */ - if(but == 2){ /* as big as can be */ - memset(nl, 0, c->nw * sizeof(int)); - goto Pack; - } - nnl = min(onl + max(min(5, w->maxlines), onl/2), tot); - if(nnl < w->maxlines) - nnl = (w->maxlines+nnl)/2; - if(nnl == 0) - nnl = 2; - dnl = nnl - onl; - /* compute new #lines for each window */ - for(k=1; knw; k++){ - /* prune from later window */ - j = i+k; - if(jnw && nl[j]){ - l = min(dnl, max(1, nl[j]/2)); - nl[j] -= l; - nl[i] += l; - dnl -= l; - } - /* prune from earlier window */ - j = i-k; - if(j>=0 && nl[j]){ - l = min(dnl, max(1, nl[j]/2)); - nl[j] -= l; - nl[i] += l; - dnl -= l; - } - } - Pack: - /* pack everyone above */ - y1 = cr.min.y; - for(j=0; jw[j]; - r = v->r; - r.min.y = y1; - r.max.y = y1+Dy(v->tag.all); - if(nl[j]) - r.max.y += 1 + nl[j]*v->body.font->height; - if(!c->safe || !eqrect(v->r, r)){ - draw(screen, r, textcols[BACK], nil, ZP); - r.min.y = winresize(v, r, c->safe, FALSE); - }else - r.min.y = v->r.max.y; - r.max.y += Border; - draw(screen, r, display->black, nil, ZP); - y1 = r.max.y; - } - /* scan to see new size of everyone below */ - y2 = c->r.max.y; - for(j=c->nw-1; j>i; j--){ - v = c->w[j]; - r = v->r; - r.min.y = y2-Dy(v->tag.all); - if(nl[j]) - r.min.y -= 1 + nl[j]*v->body.font->height; - r.min.y -= Border; - ny[j] = r.min.y; - y2 = r.min.y; - } - /* compute new size of window */ - r = w->r; - r.min.y = y1; - r.max.y = y2; - h = w->body.font->height; - if(Dy(r) < Dy(w->tagtop)+1+h+Border) - r.max.y = r.min.y + Dy(w->tagtop)+1+h+Border; - /* draw window */ - draw(screen, r, textcols[BACK], nil, ZP); - r.max.y = winresize(w, r, c->safe, TRUE); - if(i < c->nw-1){ - r.min.y = r.max.y; - r.max.y += Border; - draw(screen, r, display->black, nil, ZP); - for(j=i+1; jnw; j++) - ny[j] -= (y2-r.max.y); - } - /* pack everyone below */ - y1 = r.max.y; - for(j=i+1; jnw; j++){ - v = c->w[j]; - r = v->r; - r.min.y = y1; - r.max.y = y1+Dy(v->tag.all); - if(nl[j]) - r.max.y += 1 + nl[j]*v->body.font->height; - draw(screen, r, textcols[BACK], nil, ZP); - y1 = winresize(v, r, c->safe, j==c->nw-1); - if(j < c->nw-1){ /* no border on last window */ - r.min.y = y1; - r.max.y += Border; - draw(screen, r, display->black, nil, ZP); - y1 = r.max.y; - } - } - free(nl); - free(ny); - c->safe = TRUE; - winmousebut(w); -} - -void -coldragwin(Column *c, Window *w, int but) -{ - Rectangle r; - int i, b; - Point p, op; - Window *v; - Column *nc; - - clearmouse(); - setcursor(mousectl, &boxcursor); - b = mouse->buttons; - op = mouse->xy; - while(mouse->buttons == b) - readmouse(mousectl); - setcursor(mousectl, nil); - if(mouse->buttons){ - while(mouse->buttons) - readmouse(mousectl); - return; - } - - for(i=0; inw; i++) - if(c->w[i] == w) - goto Found; - error("can't find window"); - - Found: - if(w->tagexpand) /* force recomputation of window tag size */ - w->taglines = 1; - p = mouse->xy; - if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){ - colgrow(c, w, but); - winmousebut(w); - return; - } - /* is it a flick to the right? */ - if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c) - p.x = op.x+Dx(w->r); /* yes: toss to next column */ - nc = rowwhichcol(c->row, p); - if(nc!=nil && nc!=c){ - colclose(c, w, FALSE); - coladd(nc, w, nil, p.y); - winmousebut(w); - return; - } - if(i==0 && c->nw==1) - return; /* can't do it */ - if((i>0 && p.yw[i-1]->r.min.y) || (inw-1 && p.y>w->r.max.y) - || (i==0 && p.y>w->r.max.y)){ - /* shuffle */ - colclose(c, w, FALSE); - coladd(c, w, nil, p.y); - winmousebut(w); - return; - } - if(i == 0) - return; - v = c->w[i-1]; - if(p.y < v->tag.all.max.y) - p.y = v->tag.all.max.y; - if(p.y > w->r.max.y-Dy(w->tag.all)-Border) - p.y = w->r.max.y-Dy(w->tag.all)-Border; - r = v->r; - r.max.y = p.y; - if(r.max.y > v->body.r.min.y){ - r.max.y -= (r.max.y-v->body.r.min.y)%v->body.font->height; - if(v->body.r.min.y == v->body.r.max.y) - r.max.y++; - } - draw(screen, r, textcols[BACK], nil, ZP); - r.min.y = winresize(v, r, c->safe, FALSE); - r.max.y = r.min.y+Border; - draw(screen, r, display->black, nil, ZP); - r.min.y = r.max.y; - if(i == c->nw-1) - r.max.y = c->r.max.y; - else - r.max.y = c->w[i+1]->r.min.y-Border; - if(!eqrect(w->r, r)){ - draw(screen, r, textcols[BACK], nil, ZP); - winresize(w, r, c->safe, TRUE); - } - c->safe = TRUE; - winmousebut(w); -} - -Text* -colwhich(Column *c, Point p) -{ - int i; - Window *w; - - if(!ptinrect(p, c->r)) - return nil; - if(ptinrect(p, c->tag.all)) - return &c->tag; - for(i=0; inw; i++){ - w = c->w[i]; - if(ptinrect(p, w->r)){ - if(ptinrect(p, w->tag.all)) - return &w->tag; - return &w->body; - } - /* scrollr drops below w->r on low windows */ - if(ptinrect(p, w->body.scrollr)) - return &w->body; - } - return nil; -} - -int -colclean(Column *c) -{ - int i, clean; - - clean = TRUE; - for(i=0; inw; i++) - clean &= winclean(c->w[i], TRUE); - return clean; -} diff --git a/dat.h b/dat.h deleted file mode 100644 index c94c3dc..0000000 --- a/dat.h +++ /dev/null @@ -1,570 +0,0 @@ -enum -{ - Qdir, - Qacme, - Qcons, - Qconsctl, - Qdraw, - Qeditout, - Qindex, - Qlabel, - Qlog, - Qnew, - - QWaddr, - QWbody, - QWctl, - QWdata, - QWeditout, - QWerrors, - QWevent, - QWrdsel, - QWwrsel, - QWtag, - QWxdata, - QMAX, -}; - -enum -{ - Blockincr = 256, - Maxblock = 8*1024, - NRange = 10, - Infinity = 0x7FFFFFFF, /* huge value for regexp address */ -}; - -typedef struct Block Block; -typedef struct Buffer Buffer; -typedef struct Command Command; -typedef struct Column Column; -typedef struct Dirlist Dirlist; -typedef struct Dirtab Dirtab; -typedef struct Disk Disk; -typedef struct Expand Expand; -typedef struct Fid Fid; -typedef struct File File; -typedef struct Elog Elog; -typedef struct Mntdir Mntdir; -typedef struct Range Range; -typedef struct Rangeset Rangeset; -typedef struct Reffont Reffont; -typedef struct Row Row; -typedef struct Runestr Runestr; -typedef struct Text Text; -typedef struct Timer Timer; -typedef struct Window Window; -typedef struct Xfid Xfid; - -struct Runestr -{ - Rune *r; - int nr; -}; - -struct Range -{ - int q0; - int q1; -}; - -struct Block -{ - vlong addr; /* disk address in bytes */ - union - { - uint n; /* number of used runes in block */ - Block *next; /* pointer to next in free list */ - }; -}; - -struct Disk -{ - int fd; - vlong addr; /* length of temp file */ - Block *free[Maxblock/Blockincr+1]; -}; - -Disk* diskinit(void); -Block* disknewblock(Disk*, uint); -void diskrelease(Disk*, Block*); -void diskread(Disk*, Block*, Rune*, uint); -void diskwrite(Disk*, Block**, Rune*, uint); - -struct Buffer -{ - uint nc; - Rune *c; /* cache */ - uint cnc; /* bytes in cache */ - uint cmax; /* size of allocated cache */ - uint cq; /* position of cache */ - int cdirty; /* cache needs to be written */ - uint cbi; /* index of cache Block */ - Block **bl; /* array of blocks */ - uint nbl; /* number of blocks */ -}; -void bufinsert(Buffer*, uint, Rune*, uint); -void bufdelete(Buffer*, uint, uint); -uint bufload(Buffer*, uint, int, int*); -void bufread(Buffer*, uint, Rune*, uint); -void bufclose(Buffer*); -void bufreset(Buffer*); - -struct Elog -{ - short type; /* Delete, Insert, Filename */ - uint q0; /* location of change (unused in f) */ - uint nd; /* number of deleted characters */ - uint nr; /* # runes in string or file name */ - Rune *r; -}; -void elogterm(File*); -void elogclose(File*); -void eloginsert(File*, int, Rune*, int); -void elogdelete(File*, int, int); -void elogreplace(File*, int, int, Rune*, int); -void elogapply(File*); - -struct File -{ - Buffer; /* the data */ - Buffer delta; /* transcript of changes */ - Buffer epsilon; /* inversion of delta for redo */ - Buffer *elogbuf; /* log of pending editor changes */ - Elog elog; /* current pending change */ - Rune *name; /* name of associated file */ - int nname; /* size of name */ - uvlong qidpath; /* of file when read */ - uint mtime; /* of file when read */ - int dev; /* of file when read */ - int unread; /* file has not been read from disk */ - int editclean; /* mark clean after edit command */ - - int seq; /* if seq==0, File acts like Buffer */ - int mod; - Text *curtext; /* most recently used associated text */ - Text **text; /* list of associated texts */ - int ntext; - int dumpid; /* used in dumping zeroxed windows */ -}; -File* fileaddtext(File*, Text*); -void fileclose(File*); -void filedelete(File*, uint, uint); -void filedeltext(File*, Text*); -void fileinsert(File*, uint, Rune*, uint); -uint fileload(File*, uint, int, int*); -void filemark(File*); -void filereset(File*); -void filesetname(File*, Rune*, int); -void fileundelete(File*, Buffer*, uint, uint); -void fileuninsert(File*, Buffer*, uint, uint); -void fileunsetname(File*, Buffer*); -void fileundo(File*, int, uint*, uint*); -uint fileredoseq(File*); - -enum /* Text.what */ -{ - Columntag, - Rowtag, - Tag, - Body, -}; - -struct Text -{ - File *file; - Frame; - Reffont *reffont; - uint org; - uint q0; - uint q1; - int what; - int tabstop; - Window *w; - Rectangle scrollr; - Rectangle lastsr; - Rectangle all; - Row *row; - Column *col; - - uint eq0; /* start of typing for ESC */ - uint cq0; /* cache position */ - int ncache; /* storage for insert */ - int ncachealloc; - Rune *cache; - int nofill; - int needundo; -}; - -uint textbacknl(Text*, uint, uint); -uint textbsinsert(Text*, uint, Rune*, uint, int, int*); -int textbswidth(Text*, Rune); -int textclickmatch(Text*, int, int, int, uint*); -void textclose(Text*); -void textcolumnate(Text*, Dirlist**, int); -void textcommit(Text*, int); -void textconstrain(Text*, uint, uint, uint*, uint*); -void textdelete(Text*, uint, uint, int); -void textstretchsel(Text*, uint*, uint*, int); -void textfill(Text*); -void textframescroll(Text*, int); -void textinit(Text*, File*, Rectangle, Reffont*, Image**); -void textinsert(Text*, uint, Rune*, uint, int); -uint textload(Text*, uint, char*, int); -Rune textreadc(Text*, uint); -void textredraw(Text*, Rectangle, Font*, Image*, int); -void textreset(Text*); -int textresize(Text*, Rectangle, int); -void textscrdraw(Text*); -void textscroll(Text*, int); -void textselect(Text*); -int textselect2(Text*, uint*, uint*, Text**); -int textselect23(Text*, uint*, uint*, Image*, int); -int textselect3(Text*, uint*, uint*); -void textsetorigin(Text*, uint, int); -void textsetselect(Text*, uint, uint); -void textshow(Text*, uint, uint, int); -void texttype(Text*, Rune); - -enum -{ - SPACESINDENT = 0, - AUTOINDENT, - NINDENT, -}; - -struct Window -{ - QLock; - Ref; - Text tag; - Text body; - Rectangle r; - uchar isdir; - uchar isscratch; - uchar filemenu; - uchar dirty; - uchar indent[NINDENT]; - uchar showdel; - int id; - Range addr; - Range limit; - uchar nopen[QMAX]; - uchar nomark; - uchar noscroll; - Range wrselrange; - int rdselfd; - Column *col; - Xfid *eventx; - char *events; - int nevents; - int owner; - int maxlines; - Dirlist **dlp; - int ndl; - int putseq; - int nincl; - Rune **incl; - Reffont *reffont; - QLock ctllock; - uint ctlfid; - char *dumpstr; - char *dumpdir; - int dumpid; - int utflastqid; - int utflastboff; - int utflastq; - int tagsafe; /* taglines is correct */ - int tagexpand; - int taglines; - Rectangle tagtop; -}; - -void wininit(Window*, Window*, Rectangle); -void winlock(Window*, int); -void winlock1(Window*, int); -void winunlock(Window*); -void wintype(Window*, Text*, Rune); -void winundo(Window*, int); -void winsetname(Window*, Rune*, int); -void winsettag(Window*); -void winsettag1(Window*); -void wincommit(Window*, Text*); -int winresize(Window*, Rectangle, int, int); -void winclose(Window*); -void windelete(Window*); -int winclean(Window*, int); -void windirfree(Window*); -void winevent(Window*, char*, ...); -void winmousebut(Window*); -void winaddincl(Window*, Rune*, int); -void wincleartag(Window*); -char *winctlprint(Window*, char*, int); - -struct Column -{ - Rectangle r; - Text tag; - Row *row; - Window **w; - int nw; - int safe; -}; - -void colinit(Column*, Rectangle); -Window* coladd(Column*, Window*, Window*, int); -void colclose(Column*, Window*, int); -void colcloseall(Column*); -void colresize(Column*, Rectangle); -Text* colwhich(Column*, Point); -void coldragwin(Column*, Window*, int); -void colgrow(Column*, Window*, int); -int colclean(Column*); -void colsort(Column*); -void colmousebut(Column*); - -struct Row -{ - QLock; - Rectangle r; - Text tag; - Column **col; - int ncol; - -}; - -void rowinit(Row*, Rectangle); -Column* rowadd(Row*, Column *c, int); -void rowclose(Row*, Column*, int); -Text* rowwhich(Row*, Point); -Column* rowwhichcol(Row*, Point); -void rowresize(Row*, Rectangle); -Text* rowtype(Row*, Rune, Point); -void rowdragcol(Row*, Column*, int but); -int rowclean(Row*); -void rowdump(Row*, char*); -int rowload(Row*, char*, int); -void rowloadfonts(char*); - -struct Timer -{ - int dt; - int cancel; - Channel *c; /* chan(int) */ - Timer *next; -}; - -struct Command -{ - int pid; - Rune *name; - int nname; - char *text; - char **av; - int iseditcmd; - Mntdir *md; - Command *next; -}; - -struct Dirtab -{ - char *name; - uchar type; - uint qid; - uint perm; -}; - -struct Mntdir -{ - int id; - int ref; - Rune *dir; - int ndir; - Mntdir *next; - int nincl; - Rune **incl; -}; - -struct Fid -{ - int fid; - int busy; - int open; - Qid qid; - Window *w; - Dirtab *dir; - Fid *next; - Mntdir *mntdir; - int nrpart; - uchar rpart[UTFmax]; - vlong logoff; // for putlog -}; - - -struct Xfid -{ - void *arg; /* args to xfidinit */ - Fcall; - Xfid *next; - Channel *c; /* chan(void(*)(Xfid*)) */ - Fid *f; - uchar *buf; - int flushed; -}; - -void xfidctl(void *); -void xfidflush(Xfid*); -void xfidopen(Xfid*); -void xfidclose(Xfid*); -void xfidread(Xfid*); -void xfidwrite(Xfid*); -void xfidctlwrite(Xfid*, Window*); -void xfideventread(Xfid*, Window*); -void xfideventwrite(Xfid*, Window*); -void xfidindexread(Xfid*); -void xfidutfread(Xfid*, Text*, uint, int); -int xfidruneread(Xfid*, Text*, uint, uint); -void xfidlogopen(Xfid*); -void xfidlogread(Xfid*); -void xfidlogflush(Xfid*); -void xfidlog(Window*, char*); - -struct Reffont -{ - Ref; - Font *f; - -}; -Reffont *rfget(int, int, int, char*); -void rfclose(Reffont*); - -struct Rangeset -{ - Range r[NRange]; -}; - -struct Dirlist -{ - Rune *r; - int nr; - int wid; -}; - -struct Expand -{ - uint q0; - uint q1; - Rune *name; - int nname; - char *bname; - int jump; - union{ - Text *at; - Rune *ar; - }; - int (*agetc)(void*, uint); - int a0; - int a1; -}; - -enum -{ - /* fbufalloc() guarantees room off end of BUFSIZE */ - BUFSIZE = Maxblock+IOHDRSZ, /* size from fbufalloc() */ - RBUFSIZE = BUFSIZE/sizeof(Rune), - EVENTSIZE = 256, - Scrollwid = 12, /* width of scroll bar */ - Scrollgap = 4, /* gap right of scroll bar */ - Margin = 4, /* margin around text */ - Border = 2, /* line between rows, cols, windows */ -}; - -#define QID(w,q) ((w<<8)|(q)) -#define WIN(q) ((((ulong)(q).path)>>8) & 0xFFFFFF) -#define FILE(q) ((q).path & 0xFF) - -enum -{ - FALSE, - TRUE, - XXX, -}; - -enum -{ - Empty = 0, - Null = '-', - Delete = 'd', - Insert = 'i', - Replace = 'r', - Filename = 'f', -}; - -enum /* editing */ -{ - Inactive = 0, - Inserting, - Collecting, -}; - -uint globalincref; -uint seq; -uint maxtab; /* size of a tab, in units of the '0' character */ - -Display *display; -Image *screen; -Font *font; -Mouse *mouse; -Mousectl *mousectl; -Keyboardctl *keyboardctl; -Reffont reffont; -Image *modbutton; -Image *colbutton; -Image *button; -Image *but2col; -Image *but3col; -Cursor boxcursor; -Row row; -int timerpid; -Disk *disk; -Text *seltext; -Text *argtext; -Text *mousetext; /* global because Text.close needs to clear it */ -Text *typetext; /* global because Text.close needs to clear it */ -Text *barttext; /* shared between mousetask and keyboardthread */ -int bartflag; -Window *activewin; -Column *activecol; -Buffer snarfbuf; -Rectangle nullrect; -int fsyspid; -char *user; -char *cputype; -char *objtype; -char *home; -char *fontnames[2]; -char acmeerrorfile[128]; -Image *tagcols[NCOL]; -Image *textcols[NCOL]; -int plumbsendfd; -int plumbeditfd; -char wdir[]; -int editing; -int messagesize; /* negotiated in 9P version setup */ -int globalindent[NINDENT]; -Rune *delcmd; /* what command deleted the window. eg, Del, Delete, Delmesg */ - -Channel *cplumb; /* chan(Plumbmsg*) */ -Channel *cwait; /* chan(Waitmsg) */ -Channel *ccommand; /* chan(Command*) */ -Channel *ckill; /* chan(Rune*) */ -Channel *cxfidalloc; /* chan(Xfid*) */ -Channel *cxfidfree; /* chan(Xfid*) */ -Channel *cnewwindow; /* chan(Channel*) */ -Channel *mouseexit0; /* chan(int) */ -Channel *mouseexit1; /* chan(int) */ -Channel *cexit; /* chan(int) */ -Channel *cerr; /* chan(char*) */ -Channel *cedit; /* chan(int) */ -Channel *cwarn; /* chan(void*)[1] (really chan(unit)[1]) */ - -#define STACK 8192 diff --git a/disk.6 b/disk.6 deleted file mode 100644 index e83384d..0000000 Binary files a/disk.6 and /dev/null differ diff --git a/disk.c b/disk.c deleted file mode 100644 index 355c742..0000000 --- a/disk.c +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -static Block *blist; - -int -tempfile(void) -{ - char buf[128]; - int i, fd; - - snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), user); - for(i='A'; i<='Z'; i++){ - buf[5] = i; - if(access(buf, AEXIST) == 0) - continue; - fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600); - if(fd >= 0) - return fd; - } - return -1; -} - -Disk* -diskinit() -{ - Disk *d; - - d = emalloc(sizeof(Disk)); - d->fd = tempfile(); - if(d->fd < 0){ - fprint(2, "acme: can't create temp file: %r\n"); - threadexitsall("diskinit"); - } - return d; -} - -static -uint -ntosize(uint n, uint *ip) -{ - uint size; - - if(n > Maxblock) - error("internal error: ntosize"); - size = n; - if(size & (Blockincr-1)) - size += Blockincr - (size & (Blockincr-1)); - /* last bucket holds blocks of exactly Maxblock */ - if(ip) - *ip = size/Blockincr; - return size * sizeof(Rune); -} - -Block* -disknewblock(Disk *d, uint n) -{ - uint i, j, size; - Block *b; - - size = ntosize(n, &i); - b = d->free[i]; - if(b) - d->free[i] = b->next; - else{ - /* allocate in chunks to reduce malloc overhead */ - if(blist == nil){ - blist = emalloc(100*sizeof(Block)); - for(j=0; j<100-1; j++) - blist[j].next = &blist[j+1]; - } - b = blist; - blist = b->next; - b->addr = d->addr; - if(d->addr+size < d->addr){ - error("temp file overflow"); - } - d->addr += size; - } - b->n = n; - return b; -} - -void -diskrelease(Disk *d, Block *b) -{ - uint i; - - ntosize(b->n, &i); - b->next = d->free[i]; - d->free[i] = b; -} - -void -diskwrite(Disk *d, Block **bp, Rune *r, uint n) -{ - int size, nsize; - Block *b; - - b = *bp; - size = ntosize(b->n, nil); - nsize = ntosize(n, nil); - if(size != nsize){ - diskrelease(d, b); - b = disknewblock(d, n); - *bp = b; - } - if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) - error("write error to temp file"); - b->n = n; -} - -void -diskread(Disk *d, Block *b, Rune *r, uint n) -{ - int tot, nr; - char *p; - - if(n > b->n) - error("internal error: diskread"); - - ntosize(b->n, nil); - n *= sizeof(Rune); - p = (char*)r; - for(tot = 0; tot < n; tot += nr){ - nr = pread(d->fd, p+tot, n-tot, b->addr+tot); - if(nr <= 0) - error("read error from temp file"); - } - if(tot != n) - error("read error from temp file"); -} diff --git a/ecmd.6 b/ecmd.6 deleted file mode 100644 index 84815ee..0000000 Binary files a/ecmd.6 and /dev/null differ diff --git a/ecmd.c b/ecmd.c deleted file mode 100644 index ebfa87e..0000000 --- a/ecmd.c +++ /dev/null @@ -1,1366 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "edit.h" -#include "fns.h" - -int Glooping; -int nest; -char Enoname[] = "no file name given"; - -Address addr; -File *menu; -Rangeset sel; -extern Text* curtext; -Rune *collection; -int ncollection; - -int append(File*, Cmd*, long); -int pdisplay(File*); -void pfilename(File*); -void looper(File*, Cmd*, int); -void filelooper(Text*, Cmd*, int); -void linelooper(File*, Cmd*); -Address lineaddr(long, Address, int); -int filematch(File*, String*); -File *tofile(String*); -Rune* cmdname(File *f, String *s, int); -void runpipe(Text*, int, Rune*, int, int); - -void -clearcollection(void) -{ - free(collection); - collection = nil; - ncollection = 0; -} - -void -resetxec(void) -{ - Glooping = nest = 0; - clearcollection(); -} - -void -mkaddr(Address *a, File *f) -{ - a->r.q0 = f->curtext->q0; - a->r.q1 = f->curtext->q1; - a->f = f; -} - -int -cmdexec(Text *t, Cmd *cp) -{ - int i; - Addr *ap; - File *f; - Window *w; - Address dot; - - if(t == nil) - w = nil; - else - w = t->w; - if(w==nil && (cp->addr==0 || cp->addr->type!='"') && - !utfrune("bBnqUXY!", cp->cmdc) && - !(cp->cmdc=='D' && cp->text)) - editerror("no current window"); - i = cmdlookup(cp->cmdc); /* will be -1 for '{' */ - f = nil; - if(t && t->w){ - t = &t->w->body; - f = t->file; - f->curtext = t; - } - if(i>=0 && cmdtab[i].defaddr != aNo){ - if((ap=cp->addr)==0 && cp->cmdc!='\n'){ - cp->addr = ap = newaddr(); - ap->type = '.'; - if(cmdtab[i].defaddr == aAll) - ap->type = '*'; - }else if(ap && ap->type=='"' && ap->next==0 && cp->cmdc!='\n'){ - ap->next = newaddr(); - ap->next->type = '.'; - if(cmdtab[i].defaddr == aAll) - ap->next->type = '*'; - } - if(cp->addr){ /* may be false for '\n' (only) */ - static Address none = {0,0,nil}; - if(f){ - mkaddr(&dot, f); - addr = cmdaddress(ap, dot, 0); - }else /* a " */ - addr = cmdaddress(ap, none, 0); - f = addr.f; - t = f->curtext; - } - } - switch(cp->cmdc){ - case '{': - mkaddr(&dot, f); - if(cp->addr != nil) - dot = cmdaddress(cp->addr, dot, 0); - for(cp = cp->cmd; cp; cp = cp->next){ - if(dot.r.q1 > t->file->nc) - editerror("dot extends past end of buffer during { command"); - t->q0 = dot.r.q0; - t->q1 = dot.r.q1; - cmdexec(t, cp); - } - break; - default: - if(i < 0) - editerror("unknown command %c in cmdexec", cp->cmdc); - i = (*cmdtab[i].fn)(t, cp); - return i; - } - return 1; -} - -char* -edittext(Window *w, int q, Rune *r, int nr) -{ - File *f; - - switch(editing){ - case Inactive: - return "permission denied"; - case Inserting: - f = w->body.file; - eloginsert(f, q, r, nr); - return nil; - case Collecting: - collection = runerealloc(collection, ncollection+nr+1); - runemove(collection+ncollection, r, nr); - ncollection += nr; - collection[ncollection] = '\0'; - return nil; - default: - return "unknown state in edittext"; - } -} - -/* string is known to be NUL-terminated */ -Rune* -filelist(Text *t, Rune *r, int nr) -{ - if(nr == 0) - return nil; - r = skipbl(r, nr, &nr); - clearcollection(); - if(r[0] != '<'){ - if((collection = runestrdup(r)) != nil) - ncollection += runestrlen(r); - }else - /* use < command to collect text */ - runpipe(t, '<', r+1, nr-1, Collecting); - return collection; -} - -int -a_cmd(Text *t, Cmd *cp) -{ - return append(t->file, cp, addr.r.q1); -} - -int -b_cmd(Text*, Cmd *cp) -{ - File *f; - - f = tofile(cp->text); - if(nest == 0) - pfilename(f); - curtext = f->curtext; - return TRUE; -} - -int -B_cmd(Text *t, Cmd *cp) -{ - Rune *list, *r, *s; - int nr; - - list = filelist(t, cp->text->r, cp->text->n); - if(list == nil) - editerror(Enoname); - r = list; - nr = runestrlen(r); - r = skipbl(r, nr, &nr); - if(nr == 0) - new(t, t, nil, 0, 0, r, 0); - else while(nr > 0){ - s = findbl(r, nr, &nr); - *s = '\0'; - new(t, t, nil, 0, 0, r, runestrlen(r)); - if(nr > 0) - r = skipbl(s+1, nr-1, &nr); - } - clearcollection(); - return TRUE; -} - -int -c_cmd(Text *t, Cmd *cp) -{ - elogreplace(t->file, addr.r.q0, addr.r.q1, cp->text->r, cp->text->n); - t->q0 = addr.r.q0; - t->q1 = addr.r.q0; - return TRUE; -} - -int -d_cmd(Text *t, Cmd*) -{ - if(addr.r.q1 > addr.r.q0) - elogdelete(t->file, addr.r.q0, addr.r.q1); - t->q0 = addr.r.q0; - t->q1 = addr.r.q0; - return TRUE; -} - -void -D1(Text *t) -{ - if(t->w->body.file->ntext>1 || winclean(t->w, FALSE)) - colclose(t->col, t->w, TRUE); -} - -int -D_cmd(Text *t, Cmd *cp) -{ - Rune *list, *r, *s, *n; - int nr, nn; - Window *w; - Runestr dir, rs; - char buf[128]; - - list = filelist(t, cp->text->r, cp->text->n); - if(list == nil){ - D1(t); - return TRUE; - } - dir = dirname(t, nil, 0); - r = list; - nr = runestrlen(r); - r = skipbl(r, nr, &nr); - do{ - s = findbl(r, nr, &nr); - *s = '\0'; - /* first time through, could be empty string, meaning delete file empty name */ - nn = runestrlen(r); - if(r[0]=='/' || nn==0 || dir.nr==0){ - rs.r = runestrdup(r); - rs.nr = nn; - }else{ - n = runemalloc(dir.nr+1+nn); - runemove(n, dir.r, dir.nr); - n[dir.nr] = '/'; - runemove(n+dir.nr+1, r, nn); - rs = cleanrname((Runestr){n, dir.nr+1+nn}); - } - w = lookfile(rs.r, rs.nr); - if(w == nil){ - snprint(buf, sizeof buf, "no such file %.*S", rs.nr, rs.r); - free(rs.r); - editerror(buf); - } - free(rs.r); - D1(&w->body); - if(nr > 0) - r = skipbl(s+1, nr-1, &nr); - }while(nr > 0); - clearcollection(); - free(dir.r); - return TRUE; -} - -static int -readloader(void *v, uint q0, Rune *r, int nr) -{ - if(nr > 0) - eloginsert(v, q0, r, nr); - return 0; -} - -int -e_cmd(Text *t, Cmd *cp) -{ - Rune *name; - File *f; - int i, isdir, q0, q1, fd, nulls, samename, allreplaced; - char *s, tmp[128]; - Dir *d; - - f = t->file; - q0 = addr.r.q0; - q1 = addr.r.q1; - if(cp->cmdc == 'e'){ - if(winclean(t->w, TRUE)==FALSE) - editerror(""); /* winclean generated message already */ - q0 = 0; - q1 = f->nc; - } - allreplaced = (q0==0 && q1==f->nc); - name = cmdname(f, cp->text, cp->cmdc=='e'); - if(name == nil) - editerror(Enoname); - i = runestrlen(name); - samename = runeeq(name, i, t->file->name, t->file->nname); - s = runetobyte(name, i); - free(name); - fd = open(s, OREAD); - if(fd < 0){ - snprint(tmp, sizeof tmp, "can't open %s: %r", s); - free(s); - editerror(tmp); - } - d = dirfstat(fd); - isdir = (d!=nil && (d->qid.type&QTDIR)); - free(d); - if(isdir){ - close(fd); - snprint(tmp, sizeof tmp, "%s is a directory", s); - free(s); - editerror(tmp); - } - elogdelete(f, q0, q1); - nulls = 0; - loadfile(fd, q1, &nulls, readloader, f); - free(s); - close(fd); - if(nulls) - warning(nil, "%s: NUL bytes elided\n", s); - else if(allreplaced && samename) - f->editclean = TRUE; - return TRUE; -} - -int -f_cmd(Text *t, Cmd *cp) -{ - Rune *name; - String *str; - String empty; - - if(cp->text == nil){ - empty.n = 0; - empty.r = L""; - str = ∅ - }else - str = cp->text; - name = cmdname(t->file, str, TRUE); - free(name); - pfilename(t->file); - return TRUE; -} - -int -g_cmd(Text *t, Cmd *cp) -{ - if(t->file != addr.f){ - warning(nil, "internal error: g_cmd f!=addr.f\n"); - return FALSE; - } - if(rxcompile(cp->re->r) == FALSE) - editerror("bad regexp in g command"); - if(rxexecute(t, nil, addr.r.q0, addr.r.q1, &sel) ^ cp->cmdc=='v'){ - t->q0 = addr.r.q0; - t->q1 = addr.r.q1; - return cmdexec(t, cp->cmd); - } - return TRUE; -} - -int -i_cmd(Text *t, Cmd *cp) -{ - return append(t->file, cp, addr.r.q0); -} - -void -copy(File *f, Address addr2) -{ - long p; - int ni; - Rune *buf; - - buf = fbufalloc(); - for(p=addr.r.q0; p RBUFSIZE) - ni = RBUFSIZE; - bufread(f, p, buf, ni); - eloginsert(addr2.f, addr2.r.q1, buf, ni); - } - fbuffree(buf); -} - -void -move(File *f, Address addr2) -{ - if(addr.f!=addr2.f || addr.r.q1<=addr2.r.q0){ - elogdelete(f, addr.r.q0, addr.r.q1); - copy(f, addr2); - }else if(addr.r.q0 >= addr2.r.q1){ - copy(f, addr2); - elogdelete(f, addr.r.q0, addr.r.q1); - }else if(addr.r.q0==addr2.r.q0 && addr.r.q1==addr2.r.q1){ - ; /* move to self; no-op */ - }else - editerror("move overlaps itself"); -} - -int -m_cmd(Text *t, Cmd *cp) -{ - Address dot, addr2; - - mkaddr(&dot, t->file); - addr2 = cmdaddress(cp->mtaddr, dot, 0); - if(cp->cmdc == 'm') - move(t->file, addr2); - else - copy(t->file, addr2); - return TRUE; -} - -int -p_cmd(Text *t, Cmd*) -{ - return pdisplay(t->file); -} - -int -s_cmd(Text *t, Cmd *cp) -{ - int i, j, k, c, m, n, nrp, didsub; - long p1, op, delta; - String *buf; - Rangeset *rp; - char *err; - Rune *rbuf; - - n = cp->num; - op= -1; - if(rxcompile(cp->re->r) == FALSE) - editerror("bad regexp in s command"); - nrp = 0; - rp = nil; - delta = 0; - didsub = FALSE; - for(p1 = addr.r.q0; p1<=addr.r.q1 && rxexecute(t, nil, p1, addr.r.q1, &sel); ){ - if(sel.r[0].q0 == sel.r[0].q1){ /* empty match? */ - if(sel.r[0].q0 == op){ - p1++; - continue; - } - p1 = sel.r[0].q1+1; - }else - p1 = sel.r[0].q1; - op = sel.r[0].q1; - if(--n>0) - continue; - nrp++; - rp = erealloc(rp, nrp*sizeof(Rangeset)); - rp[nrp-1] = sel; - } - rbuf = fbufalloc(); - buf = allocstring(0); - for(m=0; mn = 0; - buf->r[0] = L'\0'; - sel = rp[m]; - for(i = 0; itext->n; i++) - if((c = cp->text->r[i])=='\\' && itext->n-1){ - c = cp->text->r[++i]; - if('1'<=c && c<='9') { - j = c-'0'; - if(sel.r[j].q1-sel.r[j].q0>RBUFSIZE){ - err = "replacement string too long"; - goto Err; - } - bufread(t->file, sel.r[j].q0, rbuf, sel.r[j].q1-sel.r[j].q0); - for(k=0; kRBUFSIZE){ - err = "right hand side too long in substitution"; - goto Err; - } - bufread(t->file, sel.r[0].q0, rbuf, sel.r[0].q1-sel.r[0].q0); - for(k=0; kfile, sel.r[0].q0, sel.r[0].q1, buf->r, buf->n); - delta -= sel.r[0].q1-sel.r[0].q0; - delta += buf->n; - didsub = 1; - if(!cp->flag) - break; - } - free(rp); - freestring(buf); - fbuffree(rbuf); - if(!didsub && nest==0) - editerror("no substitution"); - t->q0 = addr.r.q0; - t->q1 = addr.r.q1; - return TRUE; - -Err: - free(rp); - freestring(buf); - fbuffree(rbuf); - editerror(err); - return FALSE; -} - -int -u_cmd(Text *t, Cmd *cp) -{ - int n, oseq, flag; - - n = cp->num; - flag = TRUE; - if(n < 0){ - n = -n; - flag = FALSE; - } - oseq = -1; - while(n-->0 && t->file->seq!=0 && t->file->seq!=oseq){ - oseq = t->file->seq; - undo(t, nil, nil, flag, 0, nil, 0); - } - return TRUE; -} - -int -w_cmd(Text *t, Cmd *cp) -{ - Rune *r; - File *f; - - f = t->file; - if(f->seq == seq) - editerror("can't write file with pending modifications"); - r = cmdname(f, cp->text, FALSE); - if(r == nil) - editerror("no name specified for 'w' command"); - putfile(f, addr.r.q0, addr.r.q1, r, runestrlen(r)); - /* r is freed by putfile */ - return TRUE; -} - -int -x_cmd(Text *t, Cmd *cp) -{ - if(cp->re) - looper(t->file, cp, cp->cmdc=='x'); - else - linelooper(t->file, cp); - return TRUE; -} - -int -X_cmd(Text *t, Cmd *cp) -{ - filelooper(t, cp, cp->cmdc=='X'); - return TRUE; -} - -void -runpipe(Text *t, int cmd, Rune *cr, int ncr, int state) -{ - Rune *r, *s; - int n; - Runestr dir; - Window *w; - - r = skipbl(cr, ncr, &n); - if(n == 0) - editerror("no command specified for %c", cmd); - w = nil; - if(state == Inserting){ - w = t->w; - t->q0 = addr.r.q0; - t->q1 = addr.r.q1; - if(cmd == '<' || cmd=='|') - elogdelete(t->file, t->q0, t->q1); - } - s = runemalloc(n+2); - s[0] = cmd; - runemove(s+1, r, n); - n++; - dir.r = nil; - dir.nr = 0; - if(t != nil) - dir = dirname(t, nil, 0); - if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ - free(dir.r); - dir.r = nil; - dir.nr = 0; - } - editing = state; - if(t!=nil && t->w!=nil) - incref(t->w); /* run will decref */ - run(w, runetobyte(s, n), dir.r, dir.nr, TRUE, nil, nil, TRUE); - free(s); - if(t!=nil && t->w!=nil) - winunlock(t->w); - qunlock(&row); - recvul(cedit); - qlock(&row); - editing = Inactive; - if(t!=nil && t->w!=nil) - winlock(t->w, 'M'); -} - -int -pipe_cmd(Text *t, Cmd *cp) -{ - runpipe(t, cp->cmdc, cp->text->r, cp->text->n, Inserting); - return TRUE; -} - -long -nlcount(Text *t, long q0, long q1, long *pnr) -{ - long nl, start; - Rune *buf; - int i, nbuf; - - buf = fbufalloc(); - nbuf = 0; - i = nl = 0; - start = q0; - while(q0 < q1){ - if(i == nbuf){ - nbuf = q1-q0; - if(nbuf > RBUFSIZE) - nbuf = RBUFSIZE; - bufread(t->file, q0, buf, nbuf); - i = 0; - } - if(buf[i++] == '\n'){ - start = q0+1; - nl++; - } - q0++; - } - fbuffree(buf); - if(pnr != nil) - *pnr = q0 - start; - return nl; -} - -enum { - PosnLine = 0, - PosnChars = 1, - PosnLineChars = 2, -}; - -void -printposn(Text *t, int mode) -{ - long l1, l2, r1, r2; - - if (t != nil && t->file != nil && t->file->name != nil) - warning(nil, "%.*S:", t->file->nname, t->file->name); - switch(mode) { - case PosnChars: - warning(nil, "#%d", addr.r.q0); - if(addr.r.q1 != addr.r.q0) - warning(nil, ",#%d", addr.r.q1); - warning(nil, "\n"); - return; - default: - case PosnLine: - l1 = 1+nlcount(t, 0, addr.r.q0, nil); - l2 = l1+nlcount(t, addr.r.q0, addr.r.q1, nil); - /* check if addr ends with '\n' */ - if(addr.r.q1>0 && addr.r.q1>addr.r.q0 && textreadc(t, addr.r.q1-1)=='\n') - --l2; - warning(nil, "%lud", l1); - if(l2 != l1) - warning(nil, ",%lud", l2); - warning(nil, "\n"); - return; - case PosnLineChars: - l1 = 1+nlcount(t, 0, addr.r.q0, &r1); - l2 = l1+nlcount(t, addr.r.q0, addr.r.q1, &r2); - if(l2 == l1) - r2 += r1; - warning(nil, "%lud+#%lud", l1, r1); - if(l2 != l1) - warning(nil, ",%lud+#%lud", l2, r2); - warning(nil, "\n"); - return; - } -} - -int -eq_cmd(Text *t, Cmd *cp) -{ - int mode; - - switch(cp->text->n){ - case 0: - mode = PosnLine; - break; - case 1: - if(cp->text->r[0] == '#'){ - mode = PosnChars; - break; - } - if(cp->text->r[0] == '+'){ - mode = PosnLineChars; - break; - } - default: - SET(mode); - editerror("newline expected"); - } - printposn(t, mode); - return TRUE; -} - -int -nl_cmd(Text *t, Cmd *cp) -{ - Address a; - File *f; - - f = t->file; - if(cp->addr == 0){ - /* First put it on newline boundaries */ - mkaddr(&a, f); - addr = lineaddr(0, a, -1); - a = lineaddr(0, a, 1); - addr.r.q1 = a.r.q1; - if(addr.r.q0==t->q0 && addr.r.q1==t->q1){ - mkaddr(&a, f); - addr = lineaddr(1, a, 1); - } - } - textshow(t, addr.r.q0, addr.r.q1, 1); - return TRUE; -} - -int -append(File *f, Cmd *cp, long p) -{ - if(cp->text->n > 0) - eloginsert(f, p, cp->text->r, cp->text->n); - f->curtext->q0 = p; - f->curtext->q1 = p; - return TRUE; -} - -int -pdisplay(File *f) -{ - long p1, p2; - int np; - Rune *buf; - - p1 = addr.r.q0; - p2 = addr.r.q1; - if(p2 > f->nc) - p2 = f->nc; - buf = fbufalloc(); - while(p1 < p2){ - np = p2-p1; - if(np>RBUFSIZE-1) - np = RBUFSIZE-1; - bufread(f, p1, buf, np); - buf[np] = L'\0'; - warning(nil, "%S", buf); - p1 += np; - } - fbuffree(buf); - f->curtext->q0 = addr.r.q0; - f->curtext->q1 = addr.r.q1; - return TRUE; -} - -void -pfilename(File *f) -{ - int dirty; - Window *w; - - w = f->curtext->w; - /* same check for dirty as in settag, but we know ncache==0 */ - dirty = !w->isdir && !w->isscratch && f->mod; - warning(nil, "%c%c%c %.*S\n", " '"[dirty], - '+', " ."[curtext!=nil && curtext->file==f], f->nname, f->name); -} - -void -loopcmd(File *f, Cmd *cp, Range *rp, long nrp) -{ - long i; - - for(i=0; icurtext->q0 = rp[i].q0; - f->curtext->q1 = rp[i].q1; - cmdexec(f->curtext, cp); - } -} - -void -looper(File *f, Cmd *cp, int xy) -{ - long p, op, nrp; - Range r, tr; - Range *rp; - - r = addr.r; - op= xy? -1 : r.q0; - nest++; - if(rxcompile(cp->re->r) == FALSE) - editerror("bad regexp in %c command", cp->cmdc); - nrp = 0; - rp = nil; - for(p = r.q0; p<=r.q1; ){ - if(!rxexecute(f->curtext, nil, p, r.q1, &sel)){ /* no match, but y should still run */ - if(xy || op>r.q1) - break; - tr.q0 = op, tr.q1 = r.q1; - p = r.q1+1; /* exit next loop */ - }else{ - if(sel.r[0].q0==sel.r[0].q1){ /* empty match? */ - if(sel.r[0].q0==op){ - p++; - continue; - } - p = sel.r[0].q1+1; - }else - p = sel.r[0].q1; - if(xy) - tr = sel.r[0]; - else - tr.q0 = op, tr.q1 = sel.r[0].q0; - } - op = sel.r[0].q1; - nrp++; - rp = erealloc(rp, nrp*sizeof(Range)); - rp[nrp-1] = tr; - } - loopcmd(f, cp->cmd, rp, nrp); - free(rp); - --nest; -} - -void -linelooper(File *f, Cmd *cp) -{ - long nrp, p; - Range r, linesel; - Address a, a3; - Range *rp; - - nest++; - nrp = 0; - rp = nil; - r = addr.r; - a3.f = f; - a3.r.q0 = a3.r.q1 = r.q0; - a = lineaddr(0, a3, 1); - linesel = a.r; - for(p = r.q0; p= r.q1) - break; - if(linesel.q1 >= r.q1) - linesel.q1 = r.q1; - if(linesel.q1 > linesel.q0) - if(linesel.q0>=a3.r.q1 && linesel.q1>a3.r.q1){ - a3.r = linesel; - nrp++; - rp = erealloc(rp, nrp*sizeof(Range)); - rp[nrp-1] = linesel; - continue; - } - break; - } - loopcmd(f, cp->cmd, rp, nrp); - free(rp); - --nest; -} - -struct Looper -{ - Cmd *cp; - int XY; - Window **w; - int nw; -} loopstruct; /* only one; X and Y can't nest */ - -void -alllooper(Window *w, void *v) -{ - Text *t; - struct Looper *lp; - Cmd *cp; - - lp = v; - cp = lp->cp; -// if(w->isscratch || w->isdir) -// return; - t = &w->body; - /* only use this window if it's the current window for the file */ - if(t->file->curtext != t) - return; -// if(w->nopen[QWevent] > 0) -// return; - /* no auto-execute on files without names */ - if(cp->re==nil && t->file->nname==0) - return; - if(cp->re==nil || filematch(t->file, cp->re)==lp->XY){ - lp->w = erealloc(lp->w, (lp->nw+1)*sizeof(Window*)); - lp->w[lp->nw++] = w; - } -} - -void -alllocker(Window *w, void *v) -{ - if(v) - incref(w); - else - winclose(w); -} - -void -filelooper(Text *t, Cmd *cp, int XY) -{ - int i; - Text *targ; - - if(Glooping++) - editerror("can't nest %c command", "YX"[XY]); - nest++; - - loopstruct.cp = cp; - loopstruct.XY = XY; - if(loopstruct.w) /* error'ed out last time */ - free(loopstruct.w); - loopstruct.w = nil; - loopstruct.nw = 0; - allwindows(alllooper, &loopstruct); - /* - * add a ref to all windows to keep safe windows accessed by X - * that would not otherwise have a ref to hold them up during - * the shenanigans. note this with globalincref so that any - * newly created windows start with an extra reference. - */ - allwindows(alllocker, (void*)1); - globalincref = 1; - /* - * Unlock the window running the X command. - * We'll need to lock and unlock each target window in turn. - */ - if(t && t->w) - winunlock(t->w); - for(i=0; ibody; - if(targ && targ->w) - winlock(targ->w, cp->cmdc); - cmdexec(targ, cp->cmd); - if(targ && targ->w) - winunlock(targ->w); - } - if(t && t->w) - winlock(t->w, cp->cmdc); - allwindows(alllocker, (void*)0); - globalincref = 0; - free(loopstruct.w); - loopstruct.w = nil; - - --Glooping; - --nest; -} - -void -nextmatch(File *f, String *r, long p, int sign) -{ - if(rxcompile(r->r) == FALSE) - editerror("bad regexp in command address"); - if(sign >= 0){ - if(!rxexecute(f->curtext, nil, p, 0x7FFFFFFFL, &sel)) - editerror("no match for regexp"); - if(sel.r[0].q0==sel.r[0].q1 && sel.r[0].q0==p){ - if(++p>f->nc) - p = 0; - if(!rxexecute(f->curtext, nil, p, 0x7FFFFFFFL, &sel)) - editerror("address"); - } - }else{ - if(!rxbexecute(f->curtext, p, &sel)) - editerror("no match for regexp"); - if(sel.r[0].q0==sel.r[0].q1 && sel.r[0].q1==p){ - if(--p<0) - p = f->nc; - if(!rxbexecute(f->curtext, p, &sel)) - editerror("address"); - } - } -} - -File *matchfile(String*); -Address charaddr(long, Address, int); -Address lineaddr(long, Address, int); - -Address -cmdaddress(Addr *ap, Address a, int sign) -{ - File *f = a.f; - Address a1, a2; - - do{ - switch(ap->type){ - case 'l': - case '#': - a = (*(ap->type=='#'?charaddr:lineaddr))(ap->num, a, sign); - break; - - case '.': - mkaddr(&a, f); - break; - - case '$': - a.r.q0 = a.r.q1 = f->nc; - break; - - case '\'': -editerror("can't handle '"); -// a.r = f->mark; - break; - - case '?': - sign = -sign; - if(sign == 0) - sign = -1; - /* fall through */ - case '/': - nextmatch(f, ap->re, sign>=0? a.r.q1 : a.r.q0, sign); - a.r = sel.r[0]; - break; - - case '"': - f = matchfile(ap->re); - mkaddr(&a, f); - break; - - case '*': - a.r.q0 = 0, a.r.q1 = f->nc; - return a; - - case ',': - case ';': - if(ap->left) - a1 = cmdaddress(ap->left, a, 0); - else - a1.f = a.f, a1.r.q0 = a1.r.q1 = 0; - if(ap->type == ';'){ - f = a1.f; - a = a1; - f->curtext->q0 = a1.r.q0; - f->curtext->q1 = a1.r.q1; - } - if(ap->next) - a2 = cmdaddress(ap->next, a, 0); - else - a2.f = a.f, a2.r.q0 = a2.r.q1 = f->nc; - if(a1.f != a2.f) - editerror("addresses in different files"); - a.f = a1.f, a.r.q0 = a1.r.q0, a.r.q1 = a2.r.q1; - if(a.r.q1 < a.r.q0) - editerror("addresses out of order"); - return a; - - case '+': - case '-': - sign = 1; - if(ap->type == '-') - sign = -1; - if(ap->next==0 || ap->next->type=='+' || ap->next->type=='-') - a = lineaddr(1L, a, sign); - break; - default: - error("cmdaddress"); - return a; - } - }while(ap = ap->next); /* assign = */ - return a; -} - -struct Tofile{ - File *f; - String *r; -}; - -void -alltofile(Window *w, void *v) -{ - Text *t; - struct Tofile *tp; - - tp = v; - if(tp->f != nil) - return; - if(w->isscratch || w->isdir) - return; - t = &w->body; - /* only use this window if it's the current window for the file */ - if(t->file->curtext != t) - return; -// if(w->nopen[QWevent] > 0) -// return; - if(runeeq(tp->r->r, tp->r->n, t->file->name, t->file->nname)) - tp->f = t->file; -} - -File* -tofile(String *r) -{ - struct Tofile t; - String rr; - - rr.r = skipbl(r->r, r->n, &rr.n); - t.f = nil; - t.r = &rr; - allwindows(alltofile, &t); - if(t.f == nil) - editerror("no such file\"%S\"", rr.r); - return t.f; -} - -void -allmatchfile(Window *w, void *v) -{ - struct Tofile *tp; - Text *t; - - tp = v; - if(w->isscratch || w->isdir) - return; - t = &w->body; - /* only use this window if it's the current window for the file */ - if(t->file->curtext != t) - return; -// if(w->nopen[QWevent] > 0) -// return; - if(filematch(w->body.file, tp->r)){ - if(tp->f != nil) - editerror("too many files match \"%S\"", tp->r->r); - tp->f = w->body.file; - } -} - -File* -matchfile(String *r) -{ - struct Tofile tf; - - tf.f = nil; - tf.r = r; - allwindows(allmatchfile, &tf); - - if(tf.f == nil) - editerror("no file matches \"%S\"", r->r); - return tf.f; -} - -int -filematch(File *f, String *r) -{ - char *buf; - Rune *rbuf; - Window *w; - int match, i, dirty; - Rangeset s; - - /* compile expr first so if we get an error, we haven't allocated anything */ - if(rxcompile(r->r) == FALSE) - editerror("bad regexp in file match"); - buf = fbufalloc(); - w = f->curtext->w; - /* same check for dirty as in settag, but we know ncache==0 */ - dirty = !w->isdir && !w->isscratch && f->mod; - snprint(buf, BUFSIZE, "%c%c%c %.*S\n", " '"[dirty], - '+', " ."[curtext!=nil && curtext->file==f], f->nname, f->name); - rbuf = bytetorune(buf, &i); - fbuffree(buf); - match = rxexecute(nil, rbuf, 0, i, &s); - free(rbuf); - return match; -} - -Address -charaddr(long l, Address addr, int sign) -{ - if(sign == 0) - addr.r.q0 = addr.r.q1 = l; - else if(sign < 0) - addr.r.q1 = addr.r.q0 -= l; - else if(sign > 0) - addr.r.q0 = addr.r.q1 += l; - if(addr.r.q0<0 || addr.r.q1>addr.f->nc) - editerror("address out of range"); - return addr; -} - -Address -lineaddr(long l, Address addr, int sign) -{ - int n; - int c; - File *f = addr.f; - Address a; - long p; - - a.f = f; - if(sign >= 0){ - if(l == 0){ - if(sign==0 || addr.r.q1==0){ - a.r.q0 = a.r.q1 = 0; - return a; - } - a.r.q0 = addr.r.q1; - p = addr.r.q1-1; - }else{ - if(sign==0 || addr.r.q1==0){ - p = 0; - n = 1; - }else{ - p = addr.r.q1-1; - n = textreadc(f->curtext, p++)=='\n'; - } - while(n < l){ - if(p >= f->nc) - editerror("address out of range"); - if(textreadc(f->curtext, p++) == '\n') - n++; - } - a.r.q0 = p; - } - while(p < f->nc && textreadc(f->curtext, p++)!='\n') - ; - a.r.q1 = p; - }else{ - p = addr.r.q0; - if(l == 0) - a.r.q1 = addr.r.q0; - else{ - for(n = 0; ncurtext, p-1); - if(c != '\n' || ++n != l) - p--; - } - } - a.r.q1 = p; - if(p > 0) - p--; - } - while(p > 0 && textreadc(f->curtext, p-1)!='\n') /* lines start after a newline */ - p--; - a.r.q0 = p; - } - return a; -} - -struct Filecheck -{ - File *f; - Rune *r; - int nr; -}; - -void -allfilecheck(Window *w, void *v) -{ - struct Filecheck *fp; - File *f; - - fp = v; - f = w->body.file; - if(w->body.file == fp->f) - return; - if(runeeq(fp->r, fp->nr, f->name, f->nname)) - warning(nil, "warning: duplicate file name \"%.*S\"\n", fp->nr, fp->r); -} - -Rune* -cmdname(File *f, String *str, int set) -{ - Rune *r, *s; - int n; - struct Filecheck fc; - Runestr newname; - - r = nil; - n = str->n; - s = str->r; - if(n == 0){ - /* no name; use existing */ - if(f->nname == 0) - return nil; - r = runemalloc(f->nname+1); - runemove(r, f->name, f->nname); - return r; - } - s = skipbl(s, n, &n); - if(n == 0) - goto Return; - - if(s[0] == '/'){ - r = runemalloc(n+1); - runemove(r, s, n); - }else{ - newname = dirname(f->curtext, runestrdup(s), n); - n = newname.nr; - r = runemalloc(n+1); /* NUL terminate */ - runemove(r, newname.r, n); - free(newname.r); - } - fc.f = f; - fc.r = r; - fc.nr = n; - allwindows(allfilecheck, &fc); - if(f->nname == 0) - set = TRUE; - - Return: - if(set && !runeeq(r, n, f->name, f->nname)){ - filemark(f); - f->mod = TRUE; - f->curtext->w->dirty = TRUE; - winsetname(f->curtext->w, r, n); - } - return r; -} diff --git a/edit.6 b/edit.6 deleted file mode 100644 index 5c8bc82..0000000 Binary files a/edit.6 and /dev/null differ diff --git a/edit.c b/edit.c deleted file mode 100644 index fa02247..0000000 --- a/edit.c +++ /dev/null @@ -1,679 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "edit.h" -#include "fns.h" - -static char linex[]="\n"; -static char wordx[]=" \t\n"; -struct cmdtab cmdtab[]={ -/* cmdc text regexp addr defcmd defaddr count token fn */ - '\n', 0, 0, 0, 0, aDot, 0, 0, nl_cmd, - 'a', 1, 0, 0, 0, aDot, 0, 0, a_cmd, - 'b', 0, 0, 0, 0, aNo, 0, linex, b_cmd, - 'c', 1, 0, 0, 0, aDot, 0, 0, c_cmd, - 'd', 0, 0, 0, 0, aDot, 0, 0, d_cmd, - 'e', 0, 0, 0, 0, aNo, 0, wordx, e_cmd, - 'f', 0, 0, 0, 0, aNo, 0, wordx, f_cmd, - 'g', 0, 1, 0, 'p', aDot, 0, 0, g_cmd, - 'i', 1, 0, 0, 0, aDot, 0, 0, i_cmd, - 'm', 0, 0, 1, 0, aDot, 0, 0, m_cmd, - 'p', 0, 0, 0, 0, aDot, 0, 0, p_cmd, - 'r', 0, 0, 0, 0, aDot, 0, wordx, e_cmd, - 's', 0, 1, 0, 0, aDot, 1, 0, s_cmd, - 't', 0, 0, 1, 0, aDot, 0, 0, m_cmd, - 'u', 0, 0, 0, 0, aNo, 2, 0, u_cmd, - 'v', 0, 1, 0, 'p', aDot, 0, 0, g_cmd, - 'w', 0, 0, 0, 0, aAll, 0, wordx, w_cmd, - 'x', 0, 1, 0, 'p', aDot, 0, 0, x_cmd, - 'y', 0, 1, 0, 'p', aDot, 0, 0, x_cmd, - '=', 0, 0, 0, 0, aDot, 0, linex, eq_cmd, - 'B', 0, 0, 0, 0, aNo, 0, linex, B_cmd, - 'D', 0, 0, 0, 0, aNo, 0, linex, D_cmd, - 'X', 0, 1, 0, 'f', aNo, 0, 0, X_cmd, - 'Y', 0, 1, 0, 'f', aNo, 0, 0, X_cmd, - '<', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd, - '|', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd, - '>', 0, 0, 0, 0, aDot, 0, linex, pipe_cmd, -/* deliberately unimplemented: - 'k', 0, 0, 0, 0, aDot, 0, 0, k_cmd, - 'n', 0, 0, 0, 0, aNo, 0, 0, n_cmd, - 'q', 0, 0, 0, 0, aNo, 0, 0, q_cmd, - '!', 0, 0, 0, 0, aNo, 0, linex, plan9_cmd, - */ - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -Cmd *parsecmd(int); -Addr *compoundaddr(void); -Addr *simpleaddr(void); -void freecmd(void); -void okdelim(int); - -Rune *cmdstartp; -Rune *cmdendp; -Rune *cmdp; -Channel *editerrc; - -String *lastpat; -int patset; - -List cmdlist; -List addrlist; -List stringlist; -Text *curtext; -int editing = Inactive; - -String* newstring(int); - -void -editthread(void*) -{ - Cmd *cmdp; - - threadsetname("editthread"); - while((cmdp=parsecmd(0)) != 0){ -// ocurfile = curfile; -// loaded = curfile && !curfile->unread; - if(cmdexec(curtext, cmdp) == 0) - break; - freecmd(); - } - sendp(editerrc, nil); -} - -void -allelogterm(Window *w, void*) -{ - elogterm(w->body.file); -} - -void -alleditinit(Window *w, void*) -{ - textcommit(&w->tag, TRUE); - textcommit(&w->body, TRUE); - w->body.file->editclean = FALSE; -} - -void -allupdate(Window *w, void*) -{ - Text *t; - int i; - File *f; - - t = &w->body; - f = t->file; - if(f->curtext != t) /* do curtext only */ - return; - if(f->elog.type == Null) - elogterm(f); - else if(f->elog.type != Empty){ - elogapply(f); - if(f->editclean){ - f->mod = FALSE; - for(i=0; intext; i++) - f->text[i]->w->dirty = FALSE; - } - } - textsetselect(t, t->q0, t->q1); - textscrdraw(t); - winsettag(w); -} - -void -editerror(char *fmt, ...) -{ - va_list arg; - char *s; - - va_start(arg, fmt); - s = vsmprint(fmt, arg); - va_end(arg); - freecmd(); - allwindows(allelogterm, nil); /* truncate the edit logs */ - sendp(editerrc, s); - threadexits(nil); -} - -void -editcmd(Text *ct, Rune *r, uint n) -{ - char *err; - - if(n == 0) - return; - if(2*n > RBUFSIZE){ - warning(nil, "string too long\n"); - return; - } - - allwindows(alleditinit, nil); - if(cmdstartp) - free(cmdstartp); - cmdstartp = runemalloc(n+2); - runemove(cmdstartp, r, n); - if(r[n] != '\n') - cmdstartp[n++] = '\n'; - cmdstartp[n] = '\0'; - cmdendp = cmdstartp+n; - cmdp = cmdstartp; - if(ct->w == nil) - curtext = nil; - else - curtext = &ct->w->body; - resetxec(); - if(editerrc == nil){ - editerrc = chancreate(sizeof(char*), 0); - lastpat = allocstring(0); - } - threadcreate(editthread, nil, STACK); - err = recvp(editerrc); - editing = Inactive; - if(err != nil){ - if(err[0] != '\0') - warning(nil, "Edit: %s\n", err); - free(err); - } - - /* update everyone whose edit log has data */ - allwindows(allupdate, nil); -} - -int -getch(void) -{ - if(*cmdp == *cmdendp) - return -1; - return *cmdp++; -} - -int -nextc(void) -{ - if(*cmdp == *cmdendp) - return -1; - return *cmdp; -} - -void -ungetch(void) -{ - if(--cmdp < cmdstartp) - error("ungetch"); -} - -long -getnum(int signok) -{ - long n; - int c, sign; - - n = 0; - sign = 1; - if(signok>1 && nextc()=='-'){ - sign = -1; - getch(); - } - if((c=nextc())<'0' || '9'= 0) - ungetch(); - return c; -} - -/* - * Check that list has room for one more element. - */ -void -growlist(List *l) -{ - if(l->listptr==0 || l->nalloc==0){ - l->nalloc = INCR; - l->listptr = emalloc(INCR*sizeof(void*)); - l->nused = 0; - }else if(l->nused == l->nalloc){ - l->listptr = erealloc(l->listptr, (l->nalloc+INCR)*sizeof(void*)); - memset(l->ptr+l->nalloc, 0, INCR*sizeof(void*)); - l->nalloc += INCR; - } -} - -/* - * Remove the ith element from the list - */ -void -dellist(List *l, int i) -{ - l->nused--; - memmove(&l->ptr[i], &l->ptr[i+1], (l->nused-i)*sizeof(void*)); -} - -/* - * Add a new element, whose position is i, to the list - */ -void -inslist(List *l, int i, void *v) -{ - growlist(l); - memmove(&l->ptr[i+1], &l->ptr[i], (l->nused-i)*sizeof(void*)); - l->ptr[i] = v; - l->nused++; -} - -void -listfree(List *l) -{ - free(l->listptr); - free(l); -} - -String* -allocstring(int n) -{ - String *s; - - s = emalloc(sizeof(String)); - s->n = n; - s->nalloc = n+10; - s->r = emalloc(s->nalloc*sizeof(Rune)); - s->r[n] = '\0'; - return s; -} - -void -freestring(String *s) -{ - free(s->r); - free(s); -} - -Cmd* -newcmd(void){ - Cmd *p; - - p = emalloc(sizeof(Cmd)); - inslist(&cmdlist, cmdlist.nused, p); - return p; -} - -String* -newstring(int n) -{ - String *p; - - p = allocstring(n); - inslist(&stringlist, stringlist.nused, p); - return p; -} - -Addr* -newaddr(void) -{ - Addr *p; - - p = emalloc(sizeof(Addr)); - inslist(&addrlist, addrlist.nused, p); - return p; -} - -void -freecmd(void) -{ - int i; - - while(cmdlist.nused > 0) - free(cmdlist.ucharptr[--cmdlist.nused]); - while(addrlist.nused > 0) - free(addrlist.ucharptr[--addrlist.nused]); - while(stringlist.nused>0){ - i = --stringlist.nused; - freestring(stringlist.stringptr[i]); - } -} - -void -okdelim(int c) -{ - if(c=='\\' || ('a'<=c && c<='z') - || ('A'<=c && c<='Z') || ('0'<=c && c<='9')) - editerror("bad delimiter %c\n", c); -} - -void -atnl(void) -{ - int c; - - cmdskipbl(); - c = getch(); - if(c != '\n') - editerror("newline expected (saw %C)", c); -} - -void -Straddc(String *s, int c) -{ - if(s->n+1 >= s->nalloc){ - s->nalloc += 10; - s->r = erealloc(s->r, s->nalloc*sizeof(Rune)); - } - s->r[s->n++] = c; - s->r[s->n] = '\0'; -} - -void -getrhs(String *s, int delim, int cmd) -{ - int c; - - while((c = getch())>0 && c!=delim && c!='\n'){ - if(c == '\\'){ - if((c=getch()) <= 0) - error("bad right hand side"); - if(c == '\n'){ - ungetch(); - c='\\'; - }else if(c == 'n') - c='\n'; - else if(c!=delim && (cmd=='s' || c!='\\')) /* s does its own */ - Straddc(s, '\\'); - } - Straddc(s, c); - } - ungetch(); /* let client read whether delimiter, '\n' or whatever */ -} - -String * -collecttoken(char *end) -{ - String *s = newstring(0); - int c; - - while((c=nextc())==' ' || c=='\t') - Straddc(s, getch()); /* blanks significant for getname() */ - while((c=getch())>0 && utfrune(end, c)==0) - Straddc(s, c); - if(c != '\n') - atnl(); - return s; -} - -String * -collecttext(void) -{ - String *s; - int begline, i, c, delim; - - s = newstring(0); - if(cmdskipbl()=='\n'){ - getch(); - i = 0; - do{ - begline = i; - while((c = getch())>0 && c!='\n') - i++, Straddc(s, c); - i++, Straddc(s, '\n'); - if(c < 0) - goto Return; - }while(s->r[begline]!='.' || s->r[begline+1]!='\n'); - s->r[s->n-2] = '\0'; - s->n -= 2; - }else{ - okdelim(delim = getch()); - getrhs(s, delim, 'a'); - if(nextc()==delim) - getch(); - atnl(); - } - Return: - return s; -} - -int -cmdlookup(int c) -{ - int i; - - for(i=0; cmdtab[i].cmdc; i++) - if(cmdtab[i].cmdc == c) - return i; - return -1; -} - -Cmd* -parsecmd(int nest) -{ - int i, c; - struct cmdtab *ct; - Cmd *cp, *ncp; - Cmd cmd; - - cmd.next = cmd.cmd = 0; - cmd.re = 0; - cmd.flag = cmd.num = 0; - cmd.addr = compoundaddr(); - if(cmdskipbl() == -1) - return 0; - if((c=getch())==-1) - return 0; - cmd.cmdc = c; - if(cmd.cmdc=='c' && nextc()=='d'){ /* sleazy two-character case */ - getch(); /* the 'd' */ - cmd.cmdc='c'|0x100; - } - i = cmdlookup(cmd.cmdc); - if(i >= 0){ - if(cmd.cmdc == '\n') - goto Return; /* let nl_cmd work it all out */ - ct = &cmdtab[i]; - if(ct->defaddr==aNo && cmd.addr) - editerror("command takes no address"); - if(ct->count) - cmd.num = getnum(ct->count); - if(ct->regexp){ - /* x without pattern -> .*\n, indicated by cmd.re==0 */ - /* X without pattern is all files */ - if((ct->cmdc!='x' && ct->cmdc!='X') || - ((c = nextc())!=' ' && c!='\t' && c!='\n')){ - cmdskipbl(); - if((c = getch())=='\n' || c<0) - editerror("no address"); - okdelim(c); - cmd.re = getregexp(c); - if(ct->cmdc == 's'){ - cmd.text = newstring(0); - getrhs(cmd.text, c, 's'); - if(nextc() == c){ - getch(); - if(nextc() == 'g') - cmd.flag = getch(); - } - - } - } - } - if(ct->addr && (cmd.mtaddr=simpleaddr())==0) - editerror("bad address"); - if(ct->defcmd){ - if(cmdskipbl() == '\n'){ - getch(); - cmd.cmd = newcmd(); - cmd.cmd->cmdc = ct->defcmd; - }else if((cmd.cmd = parsecmd(nest))==0) - error("defcmd"); - }else if(ct->text) - cmd.text = collecttext(); - else if(ct->token) - cmd.text = collecttoken(ct->token); - else - atnl(); - }else - switch(cmd.cmdc){ - case '{': - cp = 0; - do{ - if(cmdskipbl()=='\n') - getch(); - ncp = parsecmd(nest+1); - if(cp) - cp->next = ncp; - else - cmd.cmd = ncp; - }while(cp = ncp); - break; - case '}': - atnl(); - if(nest==0) - editerror("right brace with no left brace"); - return 0; - default: - editerror("unknown command %c", cmd.cmdc); - } - Return: - cp = newcmd(); - *cp = cmd; - return cp; -} - -String* -getregexp(int delim) -{ - String *buf, *r; - int i, c; - - buf = allocstring(0); - for(i=0; ; i++){ - if((c = getch())=='\\'){ - if(nextc()==delim) - c = getch(); - else if(nextc()=='\\'){ - Straddc(buf, c); - c = getch(); - } - }else if(c==delim || c=='\n') - break; - if(i >= RBUFSIZE) - editerror("regular expression too long"); - Straddc(buf, c); - } - if(c!=delim && c) - ungetch(); - if(buf->n > 0){ - patset = TRUE; - freestring(lastpat); - lastpat = buf; - }else - freestring(buf); - if(lastpat->n == 0) - editerror("no regular expression defined"); - r = newstring(lastpat->n); - runemove(r->r, lastpat->r, lastpat->n); /* newstring put \0 at end */ - return r; -} - -Addr * -simpleaddr(void) -{ - Addr addr; - Addr *ap, *nap; - - addr.next = 0; - addr.left = 0; - switch(cmdskipbl()){ - case '#': - addr.type = getch(); - addr.num = getnum(1); - break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - addr.num = getnum(1); - addr.type='l'; - break; - case '/': case '?': case '"': - addr.re = getregexp(addr.type = getch()); - break; - case '.': - case '$': - case '+': - case '-': - case '\'': - addr.type = getch(); - break; - default: - return 0; - } - if(addr.next = simpleaddr()) - switch(addr.next->type){ - case '.': - case '$': - case '\'': - if(addr.type!='"') - case '"': - editerror("bad address syntax"); - break; - case 'l': - case '#': - if(addr.type=='"') - break; - /* fall through */ - case '/': - case '?': - if(addr.type!='+' && addr.type!='-'){ - /* insert the missing '+' */ - nap = newaddr(); - nap->type='+'; - nap->next = addr.next; - addr.next = nap; - } - break; - case '+': - case '-': - break; - default: - error("simpleaddr"); - } - ap = newaddr(); - *ap = addr; - return ap; -} - -Addr * -compoundaddr(void) -{ - Addr addr; - Addr *ap, *next; - - addr.left = simpleaddr(); - if((addr.type = cmdskipbl())!=',' && addr.type!=';') - return addr.left; - getch(); - next = addr.next = compoundaddr(); - if(next && (next->type==',' || next->type==';') && next->left==0) - editerror("bad address syntax"); - ap = newaddr(); - *ap = addr; - return ap; -} diff --git a/edit.h b/edit.h deleted file mode 100644 index 2f5fa66..0000000 --- a/edit.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma varargck argpos editerror 1 - -typedef struct Addr Addr; -typedef struct Address Address; -typedef struct Cmd Cmd; -typedef struct List List; -typedef struct String String; - -struct String -{ - int n; /* excludes NUL */ - Rune *r; /* includes NUL */ - int nalloc; -}; - -struct Addr -{ - char type; /* # (char addr), l (line addr), / ? . $ + - , ; */ - union{ - String *re; - Addr *left; /* left side of , and ; */ - }; - ulong num; - Addr *next; /* or right side of , and ; */ -}; - -struct Address -{ - Range r; - File *f; -}; - -struct Cmd -{ - Addr *addr; /* address (range of text) */ - String *re; /* regular expression for e.g. 'x' */ - union{ - Cmd *cmd; /* target of x, g, {, etc. */ - String *text; /* text of a, c, i; rhs of s */ - Addr *mtaddr; /* address for m, t */ - }; - Cmd *next; /* pointer to next element in {} */ - short num; - ushort flag; /* whatever */ - ushort cmdc; /* command character; 'x' etc. */ -}; - -extern struct cmdtab{ - ushort cmdc; /* command character */ - uchar text; /* takes a textual argument? */ - uchar regexp; /* takes a regular expression? */ - uchar addr; /* takes an address (m or t)? */ - uchar defcmd; /* default command; 0==>none */ - uchar defaddr; /* default address */ - uchar count; /* takes a count e.g. s2/// */ - char *token; /* takes text terminated by one of these */ - int (*fn)(Text*, Cmd*); /* function to call with parse tree */ -}cmdtab[]; - -#define INCR 25 /* delta when growing list */ - -struct List -{ - int nalloc; - int nused; - union{ - void *listptr; - void* *ptr; - uchar* *ucharptr; - String* *stringptr; - }; -}; - -enum Defaddr{ /* default addresses */ - aNo, - aDot, - aAll, -}; - -int nl_cmd(Text*, Cmd*), a_cmd(Text*, Cmd*), b_cmd(Text*, Cmd*); -int c_cmd(Text*, Cmd*), d_cmd(Text*, Cmd*); -int B_cmd(Text*, Cmd*), D_cmd(Text*, Cmd*), e_cmd(Text*, Cmd*); -int f_cmd(Text*, Cmd*), g_cmd(Text*, Cmd*), i_cmd(Text*, Cmd*); -int k_cmd(Text*, Cmd*), m_cmd(Text*, Cmd*), n_cmd(Text*, Cmd*); -int p_cmd(Text*, Cmd*); -int s_cmd(Text*, Cmd*), u_cmd(Text*, Cmd*), w_cmd(Text*, Cmd*); -int x_cmd(Text*, Cmd*), X_cmd(Text*, Cmd*), pipe_cmd(Text*, Cmd*); -int eq_cmd(Text*, Cmd*); - -String *allocstring(int); -void freestring(String*); -String *getregexp(int); -Addr *newaddr(void); -Address cmdaddress(Addr*, Address, int); -int cmdexec(Text*, Cmd*); -void editerror(char*, ...); -int cmdlookup(int); -void resetxec(void); -void Straddc(String*, int); diff --git a/elog.6 b/elog.6 deleted file mode 100644 index df2a9c4..0000000 Binary files a/elog.6 and /dev/null differ diff --git a/elog.c b/elog.c deleted file mode 100644 index d00fc8d..0000000 --- a/elog.c +++ /dev/null @@ -1,353 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" -#include "edit.h" - -static char Wsequence[] = "warning: changes out of sequence\n"; -static int warned = FALSE; - -/* - * Log of changes made by editing commands. Three reasons for this: - * 1) We want addresses in commands to apply to old file, not file-in-change. - * 2) It's difficult to track changes correctly as things move, e.g. ,x m$ - * 3) This gives an opportunity to optimize by merging adjacent changes. - * It's a little bit like the Undo/Redo log in Files, but Point 3) argues for a - * separate implementation. To do this well, we use Replace as well as - * Insert and Delete - */ - -typedef struct Buflog Buflog; -struct Buflog -{ - short type; /* Replace, Filename */ - uint q0; /* location of change (unused in f) */ - uint nd; /* # runes to delete */ - uint nr; /* # runes in string or file name */ -}; - -enum -{ - Buflogsize = sizeof(Buflog)/sizeof(Rune), -}; - -/* - * Minstring shouldn't be very big or we will do lots of I/O for small changes. - * Maxstring is RBUFSIZE so we can fbufalloc() once and not realloc elog.r. - */ -enum -{ - Minstring = 16, /* distance beneath which we merge changes */ - Maxstring = RBUFSIZE, /* maximum length of change we will merge into one */ -}; - -void -eloginit(File *f) -{ - if(f->elog.type != Empty) - return; - f->elog.type = Null; - if(f->elogbuf == nil) - f->elogbuf = emalloc(sizeof(Buffer)); - if(f->elog.r == nil) - f->elog.r = fbufalloc(); - bufreset(f->elogbuf); -} - -void -elogclose(File *f) -{ - if(f->elogbuf){ - bufclose(f->elogbuf); - free(f->elogbuf); - f->elogbuf = nil; - } -} - -void -elogreset(File *f) -{ - f->elog.type = Null; - f->elog.nd = 0; - f->elog.nr = 0; -} - -void -elogterm(File *f) -{ - elogreset(f); - if(f->elogbuf) - bufreset(f->elogbuf); - f->elog.type = Empty; - fbuffree(f->elog.r); - f->elog.r = nil; - warned = FALSE; -} - -void -elogflush(File *f) -{ - Buflog b; - - b.type = f->elog.type; - b.q0 = f->elog.q0; - b.nd = f->elog.nd; - b.nr = f->elog.nr; - switch(f->elog.type){ - default: - warning(nil, "unknown elog type 0x%ux\n", f->elog.type); - break; - case Null: - break; - case Insert: - case Replace: - if(f->elog.nr > 0) - bufinsert(f->elogbuf, f->elogbuf->nc, f->elog.r, f->elog.nr); - /* fall through */ - case Delete: - bufinsert(f->elogbuf, f->elogbuf->nc, (Rune*)&b, Buflogsize); - break; - } - elogreset(f); -} - -void -elogreplace(File *f, int q0, int q1, Rune *r, int nr) -{ - uint gap; - - if(q0==q1 && nr==0) - return; - eloginit(f); - if(f->elog.type!=Null && q0elog.q0){ - if(warned++ == 0) - warning(nil, Wsequence); - elogflush(f); - } - /* try to merge with previous */ - gap = q0 - (f->elog.q0+f->elog.nd); /* gap between previous and this */ - if(f->elog.type==Replace && f->elog.nr+gap+nr 0){ - bufread(f, f->elog.q0+f->elog.nd, f->elog.r+f->elog.nr, gap); - f->elog.nr += gap; - } - f->elog.nd += gap + q1-q0; - runemove(f->elog.r+f->elog.nr, r, nr); - f->elog.nr += nr; - return; - } - } - elogflush(f); - f->elog.type = Replace; - f->elog.q0 = q0; - f->elog.nd = q1-q0; - f->elog.nr = nr; - if(nr > RBUFSIZE) - editerror("internal error: replacement string too large(%d)", nr); - runemove(f->elog.r, r, nr); -} - -void -eloginsert(File *f, int q0, Rune *r, int nr) -{ - int n; - - if(nr == 0) - return; - eloginit(f); - if(f->elog.type!=Null && q0elog.q0){ - if(warned++ == 0) - warning(nil, Wsequence); - elogflush(f); - } - /* try to merge with previous */ - if(f->elog.type==Insert && q0==f->elog.q0 && f->elog.nr+nrelog.r+f->elog.nr, r, nr); - f->elog.nr += nr; - return; - } - while(nr > 0){ - elogflush(f); - f->elog.type = Insert; - f->elog.q0 = q0; - n = nr; - if(n > RBUFSIZE) - n = RBUFSIZE; - f->elog.nr = n; - runemove(f->elog.r, r, n); - r += n; - nr -= n; - } -} - -void -elogdelete(File *f, int q0, int q1) -{ - if(q0 == q1) - return; - eloginit(f); - if(f->elog.type!=Null && q0elog.q0+f->elog.nd){ - if(warned++ == 0) - warning(nil, Wsequence); - elogflush(f); - } - /* try to merge with previous */ - if(f->elog.type==Delete && f->elog.q0+f->elog.nd==q0){ - f->elog.nd += q1-q0; - return; - } - elogflush(f); - f->elog.type = Delete; - f->elog.q0 = q0; - f->elog.nd = q1-q0; -} - -#define tracelog 0 -void -elogapply(File *f) -{ - Buflog b; - Rune *buf; - uint i, n, up, mod; - uint tq0, tq1; - Buffer *log; - Text *t; - int owner; - - elogflush(f); - log = f->elogbuf; - t = f->curtext; - - buf = fbufalloc(); - mod = FALSE; - - owner = 0; - if(t->w){ - owner = t->w->owner; - if(owner == 0) - t->w->owner = 'E'; - } - - /* - * The edit commands have already updated the selection in t->q0, t->q1, - * but using coordinates relative to the unmodified buffer. As we apply the log, - * we have to update the coordinates to be relative to the modified buffer. - * Textinsert and textdelete will do this for us; our only work is to apply the - * convention that an insertion at t->q0==t->q1 is intended to select the - * inserted text. - */ - - /* - * We constrain the addresses in here (with textconstrain()) because - * overlapping changes will generate bogus addresses. We will warn - * about changes out of sequence but proceed anyway; here we must - * keep things in range. - */ - - while(log->nc > 0){ - up = log->nc-Buflogsize; - bufread(log, up, (Rune*)&b, Buflogsize); - switch(b.type){ - default: - fprint(2, "elogapply: 0x%ux\n", b.type); - abort(); - break; - - case Replace: - if(tracelog) - warning(nil, "elog replace %d %d (%d %d)\n", - b.q0, b.q0+b.nd, t->q0, t->q1); - if(!mod){ - mod = TRUE; - filemark(f); - } - textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1); - textdelete(t, tq0, tq1, TRUE); - up -= b.nr; - for(i=0; i RBUFSIZE) - n = RBUFSIZE; - bufread(log, up+i, buf, n); - textinsert(t, tq0+i, buf, n, TRUE); - } - if(t->q0 == b.q0 && t->q1 == b.q0) - t->q1 += b.nr; - break; - - case Delete: - if(tracelog) - warning(nil, "elog delete %d %d (%d %d)\n", - b.q0, b.q0+b.nd, t->q0, t->q1); - if(!mod){ - mod = TRUE; - filemark(f); - } - textconstrain(t, b.q0, b.q0+b.nd, &tq0, &tq1); - textdelete(t, tq0, tq1, TRUE); - break; - - case Insert: - if(tracelog) - warning(nil, "elog insert %d %d (%d %d)\n", - b.q0, b.q0+b.nr, t->q0, t->q1); - if(!mod){ - mod = TRUE; - filemark(f); - } - textconstrain(t, b.q0, b.q0, &tq0, &tq1); - up -= b.nr; - for(i=0; i RBUFSIZE) - n = RBUFSIZE; - bufread(log, up+i, buf, n); - textinsert(t, tq0+i, buf, n, TRUE); - } - if(t->q0 == b.q0 && t->q1 == b.q0) - t->q1 += b.nr; - break; - -/* case Filename: - f->seq = u.seq; - fileunsetname(f, epsilon); - f->mod = u.mod; - up -= u.n; - free(f->name); - if(u.n == 0) - f->name = nil; - else - f->name = runemalloc(u.n); - bufread(delta, up, f->name, u.n); - f->nname = u.n; - break; -*/ - } - bufdelete(log, up, log->nc); - } - fbuffree(buf); - elogterm(f); - - /* - * Bad addresses will cause bufload to crash, so double check. - * If changes were out of order, we expect problems so don't complain further. - */ - if(t->q0 > f->nc || t->q1 > f->nc || t->q0 > t->q1){ - if(!warned) - warning(nil, "elogapply: can't happen %d %d %d\n", t->q0, t->q1, f->nc); - t->q1 = min(t->q1, f->nc); - t->q0 = min(t->q0, t->q1); - } - - if(t->w) - t->w->owner = owner; -} diff --git a/exec.6 b/exec.6 deleted file mode 100644 index 962bfa3..0000000 Binary files a/exec.6 and /dev/null differ diff --git a/exec.c b/exec.c deleted file mode 100644 index b2bc063..0000000 --- a/exec.c +++ /dev/null @@ -1,1499 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -Buffer snarfbuf; - -/* - * These functions get called as: - * - * fn(et, t, argt, flag1, flag1, flag2, s, n); - * - * Where the arguments are: - * - * et: the Text* in which the executing event (click) occurred - * t: the Text* containing the current selection (Edit, Cut, Snarf, Paste) - * argt: the Text* containing the argument for a 2-1 click. - * e->flag1: from Exectab entry - * e->flag2: from Exectab entry - * s: the command line remainder (e.g., "x" if executing "Dump x") - * n: length of s (s is *not* NUL-terminated) - */ - -void del(Text*, Text*, Text*, int, int, Rune*, int); -void delcol(Text*, Text*, Text*, int, int, Rune*, int); -void dump(Text*, Text*, Text*, int, int, Rune*, int); -void edit(Text*, Text*, Text*, int, int, Rune*, int); -void exit(Text*, Text*, Text*, int, int, Rune*, int); -void fontx(Text*, Text*, Text*, int, int, Rune*, int); -void get(Text*, Text*, Text*, int, int, Rune*, int); -void id(Text*, Text*, Text*, int, int, Rune*, int); -void incl(Text*, Text*, Text*, int, int, Rune*, int); -void indent(Text*, Text*, Text*, int, int, Rune*, int); -void kill(Text*, Text*, Text*, int, int, Rune*, int); -void local(Text*, Text*, Text*, int, int, Rune*, int); -void look(Text*, Text*, Text*, int, int, Rune*, int); -void newcol(Text*, Text*, Text*, int, int, Rune*, int); -void paste(Text*, Text*, Text*, int, int, Rune*, int); -void put(Text*, Text*, Text*, int, int, Rune*, int); -void putall(Text*, Text*, Text*, int, int, Rune*, int); -void sendx(Text*, Text*, Text*, int, int, Rune*, int); -void sort(Text*, Text*, Text*, int, int, Rune*, int); -void tab(Text*, Text*, Text*, int, int, Rune*, int); -void zeroxx(Text*, Text*, Text*, int, int, Rune*, int); - -typedef struct Exectab Exectab; -struct Exectab -{ - Rune *name; - void (*fn)(Text*, Text*, Text*, int, int, Rune*, int); - int mark; - int flag1; - int flag2; -}; - -Exectab exectab[] = { - { L"Cut", cut, TRUE, TRUE, TRUE }, - { L"Del", del, FALSE, FALSE, XXX }, - { L"Delcol", delcol, FALSE, XXX, XXX }, - { L"Delete", del, FALSE, TRUE, XXX }, - { L"Dump", dump, FALSE, TRUE, XXX }, - { L"Edit", edit, FALSE, XXX, XXX }, - { L"Exit", exit, FALSE, XXX, XXX }, - { L"Font", fontx, FALSE, XXX, XXX }, - { L"Get", get, FALSE, TRUE, XXX }, - { L"ID", id, FALSE, XXX, XXX }, - { L"Incl", incl, FALSE, XXX, XXX }, - { L"Indent", indent, FALSE, AUTOINDENT, XXX }, - { L"Kill", kill, FALSE, XXX, XXX }, - { L"Load", dump, FALSE, FALSE, XXX }, - { L"Local", local, FALSE, XXX, XXX }, - { L"Look", look, FALSE, XXX, XXX }, - { L"New", new, FALSE, XXX, XXX }, - { L"Newcol", newcol, FALSE, XXX, XXX }, - { L"Paste", paste, TRUE, TRUE, XXX }, - { L"Put", put, FALSE, XXX, XXX }, - { L"Putall", putall, FALSE, XXX, XXX }, - { L"Redo", undo, FALSE, FALSE, XXX }, - { L"Send", sendx, TRUE, XXX, XXX }, - { L"Snarf", cut, FALSE, TRUE, FALSE }, - { L"Sort", sort, FALSE, XXX, XXX }, - { L"Spaces", indent, FALSE, SPACESINDENT, XXX }, - { L"Tab", tab, FALSE, XXX, XXX }, - { L"Undo", undo, FALSE, TRUE, XXX }, - { L"Zerox", zeroxx, FALSE, XXX, XXX }, - { nil, nil, 0, 0, 0 }, -}; - -Exectab* -lookup(Rune *r, int n) -{ - Exectab *e; - int nr; - - r = skipbl(r, n, &n); - if(n == 0) - return nil; - findbl(r, n, &nr); - nr = n-nr; - for(e=exectab; e->name; e++) - if(runeeq(r, nr, e->name, runestrlen(e->name)) == TRUE) - return e; - return nil; -} - -int -isexecc(int c) -{ - if(isfilec(c)) - return 1; - return c=='<' || c=='|' || c=='>'; -} - -void -execute(Text *t, uint aq0, uint aq1, int external, Text *argt) -{ - uint q0, q1; - Rune *r, *s; - char *b, *a, *aa; - Exectab *e; - int c, n, f; - Runestr dir; - - q0 = aq0; - q1 = aq1; - if(q1 == q0){ /* expand to find word (actually file name) */ - /* if in selection, choose selection */ - if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ - q0 = t->q0; - q1 = t->q1; - }else{ - while(q1file->nc && isexecc(c=textreadc(t, q1)) && c!=':') - q1++; - while(q0>0 && isexecc(c=textreadc(t, q0-1)) && c!=':') - q0--; - if(q1 == q0) - return; - } - } - r = runemalloc(q1-q0); - bufread(t->file, q0, r, q1-q0); - free(delcmd); - delcmd = runesmprint("%.*S", q1-q0, r); - e = lookup(r, q1-q0); - if(!external && t->w!=nil && t->w->nopen[QWevent]>0){ - f = 0; - if(e) - f |= 1; - if(q0!=aq0 || q1!=aq1){ - bufread(t->file, aq0, r, aq1-aq0); - f |= 2; - } - aa = getbytearg(argt, TRUE, TRUE, &a); - if(a){ - if(strlen(a) > EVENTSIZE){ /* too big; too bad */ - free(r); - free(aa); - free(a); - warning(nil, "`argument string too long\n"); - return; - } - f |= 8; - } - c = 'x'; - if(t->what == Body) - c = 'X'; - n = aq1-aq0; - if(n <= EVENTSIZE) - winevent(t->w, "%c%d %d %d %d %.*S\n", c, aq0, aq1, f, n, n, r); - else - winevent(t->w, "%c%d %d %d 0 \n", c, aq0, aq1, f); - if(q0!=aq0 || q1!=aq1){ - n = q1-q0; - bufread(t->file, q0, r, n); - if(n <= EVENTSIZE) - winevent(t->w, "%c%d %d 0 %d %.*S\n", c, q0, q1, n, n, r); - else - winevent(t->w, "%c%d %d 0 0 \n", c, q0, q1); - } - if(a){ - winevent(t->w, "%c0 0 0 %d %s\n", c, utflen(a), a); - if(aa) - winevent(t->w, "%c0 0 0 %d %s\n", c, utflen(aa), aa); - else - winevent(t->w, "%c0 0 0 0 \n", c); - } - free(r); - free(aa); - free(a); - return; - } - if(e){ - if(e->mark && seltext!=nil) - if(seltext->what == Body){ - seq++; - filemark(seltext->w->body.file); - } - s = skipbl(r, q1-q0, &n); - s = findbl(s, n, &n); - s = skipbl(s, n, &n); - (*e->fn)(t, seltext, argt, e->flag1, e->flag2, s, n); - free(r); - return; - } - - b = runetobyte(r, q1-q0); - free(r); - dir = dirname(t, nil, 0); - if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ - free(dir.r); - dir.r = nil; - dir.nr = 0; - } - aa = getbytearg(argt, TRUE, TRUE, &a); - if(t->w) - incref(t->w); - run(t->w, b, dir.r, dir.nr, TRUE, aa, a, FALSE); -} - -char* -printarg(Text *argt, uint q0, uint q1) -{ - char *buf; - - if(argt->what!=Body || argt->file->name==nil) - return nil; - buf = emalloc(argt->file->nname+32); - if(q0 == q1) - sprint(buf, "%.*S:#%d", argt->file->nname, argt->file->name, q0); - else - sprint(buf, "%.*S:#%d,#%d", argt->file->nname, argt->file->name, q0, q1); - return buf; -} - -char* -getarg(Text *argt, int doaddr, int dofile, Rune **rp, int *nrp) -{ - int n; - Expand e; - char *a; - - *rp = nil; - *nrp = 0; - if(argt == nil) - return nil; - a = nil; - textcommit(argt, TRUE); - if(expand(argt, argt->q0, argt->q1, &e)){ - free(e.bname); - if(e.nname && dofile){ - e.name = runerealloc(e.name, e.nname+1); - if(doaddr) - a = printarg(argt, e.q0, e.q1); - *rp = e.name; - *nrp = e.nname; - return a; - } - free(e.name); - }else{ - e.q0 = argt->q0; - e.q1 = argt->q1; - } - n = e.q1 - e.q0; - *rp = runemalloc(n+1); - bufread(argt->file, e.q0, *rp, n); - if(doaddr) - a = printarg(argt, e.q0, e.q1); - *nrp = n; - return a; -} - -char* -getbytearg(Text *argt, int doaddr, int dofile, char **bp) -{ - Rune *r; - int n; - char *aa; - - *bp = nil; - aa = getarg(argt, doaddr, dofile, &r, &n); - if(r == nil) - return nil; - *bp = runetobyte(r, n); - free(r); - return aa; -} - -void -newcol(Text *et, Text*, Text*, int, int, Rune*, int) -{ - Column *c; - Window *w; - - c = rowadd(et->row, nil, -1); - if(c) { - w = coladd(c, nil, nil, -1); - winsettag(w); - xfidlog(w, "new"); - } -} - -void -delcol(Text *et, Text*, Text*, int, int, Rune*, int) -{ - int i; - Column *c; - Window *w; - - c = et->col; - if(c==nil || colclean(c)==0) - return; - for(i=0; inw; i++){ - w = c->w[i]; - if(w->nopen[QWevent]+w->nopen[QWaddr]+w->nopen[QWdata]+w->nopen[QWxdata] > 0){ - warning(nil, "can't delete column; %.*S is running an external command\n", w->body.file->nname, w->body.file->name); - return; - } - } - rowclose(et->col->row, et->col, TRUE); -} - -void -del(Text *et, Text*, Text *argt, int flag1, int, Rune *arg, int narg) -{ - Window *w; - char *name, *p; - Plumbmsg *pm; - - if(et->col==nil || et->w == nil) - return; - if(flag1 || et->w->body.file->ntext>1 || winclean(et->w, FALSE)){ - w = et->w; - name = getname(&w->body, argt, arg, narg, TRUE); - if(name && plumbsendfd >= 0){ - pm = emalloc(sizeof(Plumbmsg)); - pm->src = estrdup("acme"); - pm->dst = estrdup("close"); - pm->wdir = estrdup(name); - if(p = strrchr(pm->wdir, '/')) - *p = '\0'; - pm->type = estrdup("text"); - pm->attr = nil; - pm->data = estrdup(name); - pm->ndata = strlen(pm->data); - if(pm->ndata < messagesize-1024) - plumbsend(plumbsendfd, pm); - plumbfree(pm); - } - colclose(et->col, et->w, TRUE); - } -} - -void -sort(Text *et, Text*, Text*, int, int, Rune*, int) -{ - if(et->col) - colsort(et->col); -} - -uint -seqof(Window *w, int isundo) -{ - /* if it's undo, see who changed with us */ - if(isundo) - return w->body.file->seq; - /* if it's redo, see who we'll be sync'ed up with */ - return fileredoseq(w->body.file); -} - -void -undo(Text *et, Text*, Text*, int flag1, int, Rune*, int) -{ - int i, j; - Column *c; - Window *w; - uint seq; - - if(et==nil || et->w== nil) - return; - seq = seqof(et->w, flag1); - if(seq == 0){ - /* nothing to undo */ - return; - } - /* - * Undo the executing window first. Its display will update. other windows - * in the same file will not call show() and jump to a different location in the file. - * Simultaneous changes to other files will be chaotic, however. - */ - winundo(et->w, flag1); - for(i=0; inw; j++){ - w = c->w[j]; - if(w == et->w) - continue; - if(seqof(w, flag1) == seq) - winundo(w, flag1); - } - } -} - -char* -getname(Text *t, Text *argt, Rune *arg, int narg, int isput) -{ - char *s; - Rune *r; - int i, n, promote; - Runestr dir; - - getarg(argt, FALSE, TRUE, &r, &n); - promote = FALSE; - if(r == nil) - promote = TRUE; - else if(isput){ - /* if are doing a Put, want to synthesize name even for non-existent file */ - /* best guess is that file name doesn't contain a slash */ - promote = TRUE; - for(i=0; ifile->name, t->file->nname); - return s; - } - /* prefix with directory name if necessary */ - dir.r = nil; - dir.nr = 0; - if(n>0 && arg[0]!='/'){ - dir = dirname(t, nil, 0); - if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ - free(dir.r); - dir.r = nil; - dir.nr = 0; - } - } - if(dir.r){ - r = runemalloc(dir.nr+n+1); - runemove(r, dir.r, dir.nr); - free(dir.r); - if(dir.nr>0 && r[dir.nr]!='/' && n>0 && arg[0]!='/') - r[dir.nr++] = '/'; - runemove(r+dir.nr, arg, n); - n += dir.nr; - }else{ - r = runemalloc(n+1); - runemove(r, arg, n); - } - } - s = runetobyte(r, n); - free(r); - if(strlen(s) == 0){ - free(s); - s = nil; - } - return s; -} - -void -zeroxx(Text *et, Text *t, Text*, int, int, Rune*, int) -{ - Window *nw; - int c, locked; - - locked = FALSE; - if(t!=nil && t->w!=nil && t->w!=et->w){ - locked = TRUE; - c = 'M'; - if(et->w) - c = et->w->owner; - winlock(t->w, c); - } - if(t == nil) - t = et; - if(t==nil || t->w==nil) - return; - t = &t->w->body; - if(t->w->isdir) - warning(nil, "%.*S is a directory; Zerox illegal\n", t->file->nname, t->file->name); - else{ - nw = coladd(t->w->col, nil, t->w, -1); - /* ugly: fix locks so w->unlock works */ - winlock1(nw, t->w->owner); - xfidlog(nw, "zerox"); - } - if(locked) - winunlock(t->w); -} - -typedef struct TextAddr TextAddr; -struct TextAddr { - long lorigin; // line+rune for origin - long rorigin; - long lq0; // line+rune for q0 - long rq0; - long lq1; // line+rune for q1 - long rq1; -}; - -void -get(Text *et, Text *t, Text *argt, int flag1, int, Rune *arg, int narg) -{ - char *name; - Rune *r; - int i, n, dirty, samename, isdir; - TextAddr *addr, *a; - Window *w; - Text *u; - Dir *d; - long q0, q1; - - if(flag1) - if(et==nil || et->w==nil) - return; - if(!et->w->isdir && (et->w->body.file->nc>0 && !winclean(et->w, TRUE))) - return; - w = et->w; - t = &w->body; - name = getname(t, argt, arg, narg, FALSE); - if(name == nil){ - warning(nil, "no file name\n"); - return; - } - if(t->file->ntext>1){ - d = dirstat(name); - isdir = (d!=nil && (d->qid.type & QTDIR)); - free(d); - if(isdir){ - warning(nil, "%s is a directory; can't read with multiple windows on it\n", name); - return; - } - } - addr = emalloc((t->file->ntext)*sizeof(TextAddr)); - for(i=0; ifile->ntext; i++) { - a = &addr[i]; - u = t->file->text[i]; - a->lorigin = nlcount(u, 0, u->org, &a->rorigin); - a->lq0 = nlcount(u, 0, u->q0, &a->rq0); - a->lq1 = nlcount(u, u->q0, u->q1, &a->rq1); - } - r = bytetorune(name, &n); - for(i=0; ifile->ntext; i++){ - u = t->file->text[i]; - /* second and subsequent calls with zero an already empty buffer, but OK */ - textreset(u); - windirfree(u->w); - } - samename = runeeq(r, n, t->file->name, t->file->nname); - textload(t, 0, name, samename); - if(samename){ - t->file->mod = FALSE; - dirty = FALSE; - }else{ - t->file->mod = TRUE; - dirty = TRUE; - } - for(i=0; ifile->ntext; i++) - t->file->text[i]->w->dirty = dirty; - free(name); - free(r); - winsettag(w); - t->file->unread = FALSE; - for(i=0; ifile->ntext; i++){ - u = t->file->text[i]; - textsetselect(&u->w->tag, u->w->tag.file->nc, u->w->tag.file->nc); - if(samename) { - a = &addr[i]; - // warning(nil, "%d %d %d %d %d %d\n", a->lorigin, a->rorigin, a->lq0, a->rq0, a->lq1, a->rq1); - q0 = nlcounttopos(u, 0, a->lq0, a->rq0); - q1 = nlcounttopos(u, q0, a->lq1, a->rq1); - textsetselect(u, q0, q1); - q0 = nlcounttopos(u, 0, a->lorigin, a->rorigin); - textsetorigin(u, q0, FALSE); - } - textscrdraw(u); - } - free(addr); - xfidlog(w, "get"); -} - -void -putfile(File *f, int q0, int q1, Rune *namer, int nname) -{ - uint n, m; - Rune *r; - char *s, *name, *p; - int i, fd, q; - Dir *d, *d1; - Window *w; - Plumbmsg *pm; - int isapp; - - w = f->curtext->w; - name = runetobyte(namer, nname); - d = dirstat(name); - if(d!=nil && runeeq(namer, nname, f->name, f->nname)){ - /* f->mtime+1 because when talking over NFS it's often off by a second */ - if(f->dev!=d->dev || f->qidpath!=d->qid.path || f->mtime+1mtime){ - f->dev = d->dev; - f->qidpath = d->qid.path; - f->mtime = d->mtime; - if(f->unread) - warning(nil, "%s not written; file already exists\n", name); - else - warning(nil, "%s modified%s%s since last read\n", name, d->muid[0]?" by ":"", d->muid); - goto Rescue1; - } - } - fd = create(name, OWRITE, 0666); - if(fd < 0){ - warning(nil, "can't create file %s: %r\n", name); - goto Rescue1; - } - r = fbufalloc(); - s = fbufalloc(); - free(d); - d = dirfstat(fd); - isapp = (d!=nil && d->length>0 && (d->qid.type&QTAPPEND)); - if(isapp){ - warning(nil, "%s not written; file is append only\n", name); - goto Rescue2; - } - - for(q=q0; q (BUFSIZE-1)/UTFmax) - n = (BUFSIZE-1)/UTFmax; - bufread(f, q, r, n); - m = snprint(s, BUFSIZE, "%.*S", n, r); - if(write(fd, s, m) != m){ - warning(nil, "can't write file %s: %r\n", name); - goto Rescue2; - } - } - if(runeeq(namer, nname, f->name, f->nname)){ - if(q0!=0 || q1!=f->nc){ - f->mod = TRUE; - w->dirty = TRUE; - f->unread = TRUE; - }else{ - d1 = dirfstat(fd); - if(d1 != nil){ - free(d); - d = d1; - } - f->qidpath = d->qid.path; - f->dev = d->dev; - f->mtime = d->mtime; - f->mod = FALSE; - w->dirty = FALSE; - f->unread = FALSE; - } - for(i=0; intext; i++){ - f->text[i]->w->putseq = f->seq; - f->text[i]->w->dirty = w->dirty; - } - } - if(plumbsendfd >= 0){ - pm = emalloc(sizeof(Plumbmsg)); - pm->src = estrdup("acme"); - pm->dst = estrdup("put"); - pm->wdir = estrdup(name); - if(p = strrchr(pm->wdir, '/')) - *p = '\0'; - pm->type = estrdup("text"); - pm->attr = nil; - pm->data = estrdup(name); - pm->ndata = strlen(pm->data); - if(pm->ndata < messagesize-1024) - plumbsend(plumbsendfd, pm); - plumbfree(pm); - } - fbuffree(s); - fbuffree(r); - free(d); - free(namer); - free(name); - close(fd); - winsettag(w); - return; - - Rescue2: - fbuffree(s); - fbuffree(r); - close(fd); - /* fall through */ - - Rescue1: - free(d); - free(namer); - free(name); -} - -void -put(Text *et, Text*, Text *argt, int, int, Rune *arg, int narg) -{ - int nname; - Rune *namer; - Window *w; - File *f; - char *name; - - if(et==nil || et->w==nil || et->w->isdir) - return; - w = et->w; - f = w->body.file; - name = getname(&w->body, argt, arg, narg, TRUE); - if(name == nil){ - warning(nil, "no file name\n"); - return; - } - namer = bytetorune(name, &nname); - putfile(f, 0, f->nc, namer, nname); - xfidlog(w, "put"); - free(name); -} - -void -dump(Text *, Text *, Text *argt, int isdump, int, Rune *arg, int narg) -{ - char *name; - - if(narg) - name = runetobyte(arg, narg); - else - getbytearg(argt, FALSE, TRUE, &name); - if(isdump) - rowdump(&row, name); - else - rowload(&row, name, FALSE); - free(name); -} - -void -cut(Text *et, Text *t, Text*, int dosnarf, int docut, Rune*, int) -{ - uint q0, q1, n, locked, c; - Rune *r; - - /* - * if not executing a mouse chord (et != t) and snarfing (dosnarf) - * and executed Cut or Snarf in window tag (et->w != nil), - * then use the window body selection or the tag selection - * or do nothing at all. - */ - if(et!=t && dosnarf && et->w!=nil){ - if(et->w->body.q1>et->w->body.q0){ - t = &et->w->body; - if(docut) - filemark(t->file); /* seq has been incremented by execute */ - }else if(et->w->tag.q1>et->w->tag.q0) - t = &et->w->tag; - else - t = nil; - } - if(t == nil) /* no selection */ - return; - - locked = FALSE; - if(t->w!=nil && et->w!=t->w){ - locked = TRUE; - c = 'M'; - if(et->w) - c = et->w->owner; - winlock(t->w, c); - } - if(t->q0 == t->q1){ - if(locked) - winunlock(t->w); - return; - } - if(dosnarf){ - q0 = t->q0; - q1 = t->q1; - bufdelete(&snarfbuf, 0, snarfbuf.nc); - r = fbufalloc(); - while(q0 < q1){ - n = q1 - q0; - if(n > RBUFSIZE) - n = RBUFSIZE; - bufread(t->file, q0, r, n); - bufinsert(&snarfbuf, snarfbuf.nc, r, n); - q0 += n; - } - fbuffree(r); - putsnarf(); - } - if(docut){ - textdelete(t, t->q0, t->q1, TRUE); - textsetselect(t, t->q0, t->q0); - if(t->w){ - textscrdraw(t); - winsettag(t->w); - } - }else if(dosnarf) /* Snarf command */ - argtext = t; - if(locked) - winunlock(t->w); -} - -void -paste(Text *et, Text *t, Text*, int selectall, int tobody, Rune*, int) -{ - int c; - uint q, q0, q1, n; - Rune *r; - - /* if(tobody), use body of executing window (Paste or Send command) */ - if(tobody && et!=nil && et->w!=nil){ - t = &et->w->body; - filemark(t->file); /* seq has been incremented by execute */ - } - if(t == nil) - return; - - getsnarf(); - if(t==nil || snarfbuf.nc==0) - return; - if(t->w!=nil && et->w!=t->w){ - c = 'M'; - if(et->w) - c = et->w->owner; - winlock(t->w, c); - } - cut(t, t, nil, FALSE, TRUE, nil, 0); - q = 0; - q0 = t->q0; - q1 = t->q0+snarfbuf.nc; - r = fbufalloc(); - while(q0 < q1){ - n = q1 - q0; - if(n > RBUFSIZE) - n = RBUFSIZE; - if(r == nil) - r = runemalloc(n); - bufread(&snarfbuf, q, r, n); - textinsert(t, q0, r, n, TRUE); - q += n; - q0 += n; - } - fbuffree(r); - if(selectall) - textsetselect(t, t->q0, q1); - else - textsetselect(t, q1, q1); - if(t->w){ - textscrdraw(t); - winsettag(t->w); - } - if(t->w!=nil && et->w!=t->w) - winunlock(t->w); -} - -void -look(Text *et, Text *t, Text *argt, int, int, Rune *arg, int narg) -{ - Rune *r; - int n; - - if(et && et->w){ - t = &et->w->body; - if(narg > 0){ - search(t, arg, narg); - return; - } - getarg(argt, FALSE, FALSE, &r, &n); - if(r == nil){ - n = t->q1-t->q0; - r = runemalloc(n); - bufread(t->file, t->q0, r, n); - } - search(t, r, n); - free(r); - } -} - -void -sendx(Text *et, Text *t, Text*, int, int, Rune*, int) -{ - if(et->w==nil) - return; - t = &et->w->body; - if(t->q0 != t->q1) - cut(t, t, nil, TRUE, FALSE, nil, 0); - textsetselect(t, t->file->nc, t->file->nc); - paste(t, t, nil, TRUE, TRUE, nil, 0); - if(textreadc(t, t->file->nc-1) != '\n'){ - textinsert(t, t->file->nc, L"\n", 1, TRUE); - textsetselect(t, t->file->nc, t->file->nc); - } -} - -void -edit(Text *et, Text*, Text *argt, int, int, Rune *arg, int narg) -{ - Rune *r; - int len; - - if(et == nil) - return; - getarg(argt, FALSE, TRUE, &r, &len); - seq++; - if(r != nil){ - editcmd(et, r, len); - free(r); - }else - editcmd(et, arg, narg); -} - -void -exit(Text*, Text*, Text*, int, int, Rune*, int) -{ - if(rowclean(&row)){ - sendul(cexit, 0); - threadexits(nil); - } -} - -void -putall(Text*, Text*, Text*, int, int, Rune*, int) -{ - int i, j, e; - Window *w; - Column *c; - char *a; - - for(i=0; inw; j++){ - w = c->w[j]; - if(w->isscratch || w->isdir || w->body.file->nname==0) - continue; - if(w->nopen[QWevent] > 0) - continue; - a = runetobyte(w->body.file->name, w->body.file->nname); - e = access(a, 0); - if(w->body.file->mod || w->body.ncache) - if(e < 0) - warning(nil, "no auto-Put of %s: %r\n", a); - else{ - wincommit(w, &w->body); - put(&w->body, nil, nil, XXX, XXX, nil, 0); - } - free(a); - } - } -} - - -void -id(Text *et, Text*, Text*, int, int, Rune*, int) -{ - if(et && et->w) - warning(nil, "/mnt/acme/%d/\n", et->w->id); -} - -void -local(Text *et, Text*, Text *argt, int, int, Rune *arg, int narg) -{ - char *a, *aa; - Runestr dir; - - aa = getbytearg(argt, TRUE, TRUE, &a); - - dir = dirname(et, nil, 0); - if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ - free(dir.r); - dir.r = nil; - dir.nr = 0; - } - run(nil, runetobyte(arg, narg), dir.r, dir.nr, FALSE, aa, a, FALSE); -} - -void -kill(Text*, Text*, Text *argt, int, int, Rune *arg, int narg) -{ - Rune *a, *cmd, *r; - int na; - - getarg(argt, FALSE, FALSE, &r, &na); - if(r) - kill(nil, nil, nil, 0, 0, r, na); - /* loop condition: *arg is not a blank */ - for(;;){ - a = findbl(arg, narg, &na); - if(a == arg) - break; - cmd = runemalloc(narg-na+1); - runemove(cmd, arg, narg-na); - sendp(ckill, cmd); - arg = skipbl(a, na, &narg); - } -} - -void -fontx(Text *et, Text *t, Text *argt, int, int, Rune *arg, int narg) -{ - Rune *a, *r, *flag, *file; - int na, nf; - char *aa; - Reffont *newfont; - Dirlist *dp; - int i, fix; - - if(et==nil || et->w==nil) - return; - t = &et->w->body; - flag = nil; - file = nil; - /* loop condition: *arg is not a blank */ - nf = 0; - for(;;){ - a = findbl(arg, narg, &na); - if(a == arg) - break; - r = runemalloc(narg-na+1); - runemove(r, arg, narg-na); - if(runeeq(r, narg-na, L"fix", 3) || runeeq(r, narg-na, L"var", 3)){ - free(flag); - flag = r; - }else{ - free(file); - file = r; - nf = narg-na; - } - arg = skipbl(a, na, &narg); - } - getarg(argt, FALSE, TRUE, &r, &na); - if(r) - if(runeeq(r, na, L"fix", 3) || runeeq(r, na, L"var", 3)){ - free(flag); - flag = r; - }else{ - free(file); - file = r; - nf = na; - } - fix = 1; - if(flag) - fix = runeeq(flag, runestrlen(flag), L"fix", 3); - else if(file == nil){ - newfont = rfget(FALSE, FALSE, FALSE, nil); - if(newfont) - fix = strcmp(newfont->f->name, t->font->name)==0; - } - if(file){ - aa = runetobyte(file, nf); - newfont = rfget(fix, flag!=nil, FALSE, aa); - free(aa); - }else - newfont = rfget(fix, FALSE, FALSE, nil); - if(newfont){ - draw(screen, t->w->r, textcols[BACK], nil, ZP); - rfclose(t->reffont); - t->reffont = newfont; - t->font = newfont->f; - frinittick(t); - if(t->w->isdir){ - t->all.min.x++; /* force recolumnation; disgusting! */ - for(i=0; iw->ndl; i++){ - dp = t->w->dlp[i]; - aa = runetobyte(dp->r, dp->nr); - dp->wid = stringwidth(newfont->f, aa); - free(aa); - } - } - /* avoid shrinking of window due to quantization */ - colgrow(t->w->col, t->w, -1); - } - free(file); - free(flag); -} - -void -incl(Text *et, Text*, Text *argt, int, int, Rune *arg, int narg) -{ - Rune *a, *r; - Window *w; - int na, n, len; - - if(et==nil || et->w==nil) - return; - w = et->w; - n = 0; - getarg(argt, FALSE, TRUE, &r, &len); - if(r){ - n++; - winaddincl(w, r, len); - } - /* loop condition: *arg is not a blank */ - for(;;){ - a = findbl(arg, narg, &na); - if(a == arg) - break; - r = runemalloc(narg-na+1); - runemove(r, arg, narg-na); - n++; - winaddincl(w, r, narg-na); - arg = skipbl(a, na, &narg); - } - if(n==0 && w->nincl){ - for(n=w->nincl; --n>=0; ) - warning(nil, "%S ", w->incl[n]); - warning(nil, "\n"); - } -} - -enum { - IGlobal = -2, - IError = -1, -}; - -static int -indentval(Rune *s, int n, int type) -{ - static char *strs[] = { - [SPACESINDENT] "Spaces", - [AUTOINDENT] "Indent", - }; - - if(n < 2) - return IError; - if(runestrncmp(s, L"ON", n) == 0){ - globalindent[type] = TRUE; - warning(nil, "%s ON\n", strs[type]); - return IGlobal; - } - if(runestrncmp(s, L"OFF", n) == 0){ - globalindent[type] = FALSE; - warning(nil, "%s OFF\n", strs[type]); - return IGlobal; - } - if(runestrncmp(s, L"on", n) == 0) - return TRUE; - if(runestrncmp(s, L"off", n) == 0) - return FALSE; - return IError; -} - -static void -fixindent(Window *w, void *v) -{ - int t = *(int*)v; - w->indent[t] = globalindent[t]; -} - -void -indent(Text *et, Text*, Text *argt, int type, int, Rune *arg, int narg) -{ - Rune *a, *r; - Window *w; - int na, len, ival; - - w = nil; - if(et!=nil && et->w!=nil) - w = et->w; - ival = IError; - getarg(argt, FALSE, TRUE, &r, &len); - if(r!=nil && len>0) - ival = indentval(r, len, type); - else{ - a = findbl(arg, narg, &na); - if(a != arg) - ival = indentval(arg, narg-na, type); - } - if(ival == IGlobal) - allwindows(fixindent, &type); - else if(w != nil && ival >= 0) - w->indent[type] = ival; -} - -void -tab(Text *et, Text*, Text *argt, int, int, Rune *arg, int narg) -{ - Rune *a, *r; - Window *w; - int na, len, tab; - char *p; - - if(et==nil || et->w==nil) - return; - w = et->w; - getarg(argt, FALSE, TRUE, &r, &len); - tab = 0; - if(r!=nil && len>0){ - p = runetobyte(r, len); - if('0'<=p[0] && p[0]<='9') - tab = atoi(p); - free(p); - }else{ - a = findbl(arg, narg, &na); - if(a != arg){ - p = runetobyte(arg, narg-na); - if('0'<=p[0] && p[0]<='9') - tab = atoi(p); - free(p); - } - } - if(tab > 0){ - if(w->body.tabstop != tab){ - w->body.tabstop = tab; - winresize(w, w->r, FALSE, TRUE); - } - }else - warning(nil, "%.*S: Tab %d\n", w->body.file->nname, w->body.file->name, w->body.tabstop); -} - -void -runproc(void *argvp) -{ - /* args: */ - Window *win; - char *s; - Rune *rdir; - int ndir; - int newns; - char *argaddr; - char *arg; - Command *c; - Channel *cpid; - int iseditcmd; - /* end of args */ - char *e, *t, *name, *filename, *dir, **av, *news; - Rune r, **incl; - int ac, w, inarg, i, n, fd, nincl, winid; - int pipechar; - char buf[512]; - void **argv; - - argv = argvp; - win = argv[0]; - s = argv[1]; - rdir = argv[2]; - ndir = (uintptr)argv[3]; - newns = (uintptr)argv[4]; - argaddr = argv[5]; - arg = argv[6]; - c = argv[7]; - cpid = argv[8]; - iseditcmd = (uintptr)argv[9]; - free(argv); - - t = s; - while(*t==' ' || *t=='\n' || *t=='\t') - t++; - for(e=t; *e; e++) - if(*e==' ' || *e=='\n' || *e=='\t' ) - break; - name = emalloc((e-t)+2); - memmove(name, t, e-t); - name[e-t] = 0; - e = utfrrune(name, '/'); - if(e) - memmove(name, e+1, strlen(e+1)+1); /* strcpy but overlaps */ - strcat(name, " "); /* add blank here for ease in waittask */ - c->name = bytetorune(name, &c->nname); - free(name); - pipechar = 0; - if(*t=='<' || *t=='|' || *t=='>') - pipechar = *t++; - c->iseditcmd = iseditcmd; - c->text = s; - if(rdir != nil){ - dir = runetobyte(rdir, ndir); - chdir(dir); /* ignore error: probably app. window */ - free(dir); - } - if(newns){ - nincl = 0; - incl = nil; - if(win){ - filename = smprint("%.*S", win->body.file->nname, win->body.file->name); - nincl = win->nincl; - if(nincl > 0){ - incl = emalloc(nincl*sizeof(Rune*)); - for(i=0; iincl[i]); - incl[i] = runemalloc(n+1); - runemove(incl[i], win->incl[i], n); - } - } - winid = win->id; - }else{ - filename = nil; - winid = 0; - if(activewin) - winid = activewin->id; - } - rfork(RFNAMEG|RFENVG|RFFDG|RFNOTEG); - sprint(buf, "%d", winid); - putenv("winid", buf); - - if(filename){ - putenv("%", filename); - free(filename); - } - c->md = fsysmount(rdir, ndir, incl, nincl); - if(c->md == nil){ - fprint(2, "child: can't mount /dev/cons: %r\n"); - threadexits("mount"); - } - close(0); - if(winid>0 && (pipechar=='|' || pipechar=='>')){ - sprint(buf, "/mnt/acme/%d/rdsel", winid); - open(buf, OREAD); - }else - open("/dev/null", OREAD); - close(1); - if((winid>0 || iseditcmd) && (pipechar=='|' || pipechar=='<')){ - if(iseditcmd){ - if(winid > 0) - sprint(buf, "/mnt/acme/%d/editout", winid); - else - sprint(buf, "/mnt/acme/editout"); - }else - sprint(buf, "/mnt/acme/%d/wrsel", winid); - open(buf, OWRITE); - close(2); - open("/dev/cons", OWRITE); - }else{ - open("/dev/cons", OWRITE); - dup(1, 2); - } - }else{ - rfork(RFFDG|RFNOTEG); - fsysclose(); - close(0); - open("/dev/null", OREAD); - close(1); - open(acmeerrorfile, OWRITE); - dup(1, 2); - } - - if(win) - winclose(win); - - if(argaddr) - putenv("acmeaddr", argaddr); - if(strlen(t) > sizeof buf-10) /* may need to print into stack */ - goto Hard; - inarg = FALSE; - for(e=t; *e; e+=w){ - w = chartorune(&r, e); - if(r==' ' || r=='\t') - continue; - if(r < ' ') - goto Hard; - if(utfrune("#;&|^$=`'{}()<>[]*?^~`", r)) - goto Hard; - inarg = TRUE; - } - if(!inarg) - goto Fail; - - ac = 0; - av = nil; - inarg = FALSE; - for(e=t; *e; e+=w){ - w = chartorune(&r, e); - if(r==' ' || r=='\t'){ - inarg = FALSE; - *e = 0; - continue; - } - if(!inarg){ - inarg = TRUE; - av = realloc(av, (ac+1)*sizeof(char**)); - av[ac++] = e; - } - } - av = realloc(av, (ac+2)*sizeof(char**)); - av[ac++] = arg; - av[ac] = nil; - c->av = av; - procexec(cpid, av[0], av); - e = av[0]; - if(e[0]=='/' || (e[0]=='.' && e[1]=='/')) - goto Fail; - if(cputype){ - sprint(buf, "%s/%s", cputype, av[0]); - procexec(cpid, buf, av); - } - sprint(buf, "/bin/%s", av[0]); - procexec(cpid, buf, av); - goto Fail; - -Hard: - - /* - * ugly: set path = (. $cputype /bin) - * should honor $path if unusual. - */ - if(cputype){ - n = 0; - memmove(buf+n, ".", 2); - n += 2; - i = strlen(cputype)+1; - memmove(buf+n, cputype, i); - n += i; - memmove(buf+n, "/bin", 5); - n += 5; - fd = create("/env/path", OWRITE, 0666); - write(fd, buf, n); - close(fd); - } - - if(arg){ - news = emalloc(strlen(t) + 1 + 1 + strlen(arg) + 1 + 1); - if(news){ - sprint(news, "%s '%s'", t, arg); /* BUG: what if quote in arg? */ - free(s); - t = news; - c->text = news; - } - } - procexecl(cpid, "/bin/rc", "rc", "-c", t, nil); - - Fail: - /* procexec hasn't happened, so send a zero */ - sendul(cpid, 0); - threadexits(nil); -} - -void -runwaittask(void *v) -{ - Command *c; - Channel *cpid; - void **a; - - threadsetname("runwaittask"); - a = v; - c = a[0]; - cpid = a[1]; - free(a); - do - c->pid = recvul(cpid); - while(c->pid == ~0); - free(c->av); - if(c->pid != 0) /* successful exec */ - sendp(ccommand, c); - else{ - if(c->iseditcmd) - sendul(cedit, 0); - free(c->name); - free(c->text); - free(c); - } - chanfree(cpid); -} - -void -run(Window *win, char *s, Rune *rdir, int ndir, int newns, char *argaddr, char *xarg, int iseditcmd) -{ - void **arg; - Command *c; - Channel *cpid; - - if(s == nil) - return; - - arg = emalloc(10*sizeof(void*)); - c = emalloc(sizeof *c); - cpid = chancreate(sizeof(ulong), 0); - arg[0] = win; - arg[1] = s; - arg[2] = rdir; - arg[3] = (void*)ndir; - arg[4] = (void*)newns; - arg[5] = argaddr; - arg[6] = xarg; - arg[7] = c; - arg[8] = cpid; - arg[9] = (void*)iseditcmd; - proccreate(runproc, arg, STACK); - /* mustn't block here because must be ready to answer mount() call in run() */ - arg = emalloc(2*sizeof(void*)); - arg[0] = c; - arg[1] = cpid; - threadcreate(runwaittask, arg, STACK); -} diff --git a/file.6 b/file.6 deleted file mode 100644 index f016685..0000000 Binary files a/file.6 and /dev/null differ diff --git a/file.c b/file.c deleted file mode 100644 index 5d3b344..0000000 --- a/file.c +++ /dev/null @@ -1,310 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -/* - * Structure of Undo list: - * The Undo structure follows any associated data, so the list - * can be read backwards: read the structure, then read whatever - * data is associated (insert string, file name) and precedes it. - * The structure includes the previous value of the modify bit - * and a sequence number; successive Undo structures with the - * same sequence number represent simultaneous changes. - */ - -typedef struct Undo Undo; -struct Undo -{ - short type; /* Delete, Insert, Filename */ - short mod; /* modify bit */ - uint seq; /* sequence number */ - uint p0; /* location of change (unused in f) */ - uint n; /* # runes in string or file name */ -}; - -enum -{ - Undosize = sizeof(Undo)/sizeof(Rune), -}; - -File* -fileaddtext(File *f, Text *t) -{ - if(f == nil){ - f = emalloc(sizeof(File)); - f->unread = TRUE; - } - f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*)); - f->text[f->ntext++] = t; - f->curtext = t; - return f; -} - -void -filedeltext(File *f, Text *t) -{ - int i; - - for(i=0; intext; i++) - if(f->text[i] == t) - goto Found; - error("can't find text in filedeltext"); - - Found: - f->ntext--; - if(f->ntext == 0){ - fileclose(f); - return; - } - memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*)); - if(f->curtext == t) - f->curtext = f->text[0]; -} - -void -fileinsert(File *f, uint p0, Rune *s, uint ns) -{ - if(p0 > f->nc) - error("internal error: fileinsert"); - if(f->seq > 0) - fileuninsert(f, &f->delta, p0, ns); - bufinsert(f, p0, s, ns); - if(ns) - f->mod = TRUE; -} - -void -fileuninsert(File *f, Buffer *delta, uint p0, uint ns) -{ - Undo u; - - /* undo an insertion by deleting */ - u.type = Delete; - u.mod = f->mod; - u.seq = f->seq; - u.p0 = p0; - u.n = ns; - bufinsert(delta, delta->nc, (Rune*)&u, Undosize); -} - -void -filedelete(File *f, uint p0, uint p1) -{ - if(!(p0<=p1 && p0<=f->nc && p1<=f->nc)) - error("internal error: filedelete"); - if(f->seq > 0) - fileundelete(f, &f->delta, p0, p1); - bufdelete(f, p0, p1); - if(p1 > p0) - f->mod = TRUE; -} - -void -fileundelete(File *f, Buffer *delta, uint p0, uint p1) -{ - Undo u; - Rune *buf; - uint i, n; - - /* undo a deletion by inserting */ - u.type = Insert; - u.mod = f->mod; - u.seq = f->seq; - u.p0 = p0; - u.n = p1-p0; - buf = fbufalloc(); - for(i=p0; i RBUFSIZE) - n = RBUFSIZE; - bufread(f, i, buf, n); - bufinsert(delta, delta->nc, buf, n); - } - fbuffree(buf); - bufinsert(delta, delta->nc, (Rune*)&u, Undosize); - -} - -void -filesetname(File *f, Rune *name, int n) -{ - if(f->seq > 0) - fileunsetname(f, &f->delta); - free(f->name); - f->name = runemalloc(n); - runemove(f->name, name, n); - f->nname = n; - f->unread = TRUE; -} - -void -fileunsetname(File *f, Buffer *delta) -{ - Undo u; - - /* undo a file name change by restoring old name */ - u.type = Filename; - u.mod = f->mod; - u.seq = f->seq; - u.p0 = 0; /* unused */ - u.n = f->nname; - if(f->nname) - bufinsert(delta, delta->nc, f->name, f->nname); - bufinsert(delta, delta->nc, (Rune*)&u, Undosize); -} - -uint -fileload(File *f, uint p0, int fd, int *nulls) -{ - if(f->seq > 0) - error("undo in file.load unimplemented"); - return bufload(f, p0, fd, nulls); -} - -/* return sequence number of pending redo */ -uint -fileredoseq(File *f) -{ - Undo u; - Buffer *delta; - - delta = &f->epsilon; - if(delta->nc == 0) - return 0; - bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize); - return u.seq; -} - -void -fileundo(File *f, int isundo, uint *q0p, uint *q1p) -{ - Undo u; - Rune *buf; - uint i, j, n, up; - uint stop; - Buffer *delta, *epsilon; - - if(isundo){ - /* undo; reverse delta onto epsilon, seq decreases */ - delta = &f->delta; - epsilon = &f->epsilon; - stop = f->seq; - }else{ - /* redo; reverse epsilon onto delta, seq increases */ - delta = &f->epsilon; - epsilon = &f->delta; - stop = 0; /* don't know yet */ - } - - buf = fbufalloc(); - while(delta->nc > 0){ - up = delta->nc-Undosize; - bufread(delta, up, (Rune*)&u, Undosize); - if(isundo){ - if(u.seq < stop){ - f->seq = u.seq; - goto Return; - } - }else{ - if(stop == 0) - stop = u.seq; - if(u.seq > stop) - goto Return; - } - switch(u.type){ - default: - fprint(2, "undo: 0x%ux\n", u.type); - abort(); - break; - - case Delete: - f->seq = u.seq; - fileundelete(f, epsilon, u.p0, u.p0+u.n); - f->mod = u.mod; - bufdelete(f, u.p0, u.p0+u.n); - for(j=0; jntext; j++) - textdelete(f->text[j], u.p0, u.p0+u.n, FALSE); - *q0p = u.p0; - *q1p = u.p0; - break; - - case Insert: - f->seq = u.seq; - fileuninsert(f, epsilon, u.p0, u.n); - f->mod = u.mod; - up -= u.n; - for(i=0; i RBUFSIZE) - n = RBUFSIZE; - bufread(delta, up+i, buf, n); - bufinsert(f, u.p0+i, buf, n); - for(j=0; jntext; j++) - textinsert(f->text[j], u.p0+i, buf, n, FALSE); - } - *q0p = u.p0; - *q1p = u.p0+u.n; - break; - - case Filename: - f->seq = u.seq; - fileunsetname(f, epsilon); - f->mod = u.mod; - up -= u.n; - free(f->name); - if(u.n == 0) - f->name = nil; - else - f->name = runemalloc(u.n); - bufread(delta, up, f->name, u.n); - f->nname = u.n; - break; - } - bufdelete(delta, up, delta->nc); - } - if(isundo) - f->seq = 0; - Return: - fbuffree(buf); -} - -void -filereset(File *f) -{ - bufreset(&f->delta); - bufreset(&f->epsilon); - f->seq = 0; -} - -void -fileclose(File *f) -{ - free(f->name); - f->nname = 0; - f->name = nil; - free(f->text); - f->ntext = 0; - f->text = nil; - bufclose(f); - bufclose(&f->delta); - bufclose(&f->epsilon); - elogclose(f); - free(f); -} - -void -filemark(File *f) -{ - if(f->epsilon.nc) - bufdelete(&f->epsilon, 0, f->epsilon.nc); - f->seq = seq; -} diff --git a/fns.h b/fns.h deleted file mode 100644 index 02cc06d..0000000 --- a/fns.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma varargck argpos warning 2 - -void warning(Mntdir*, char*, ...); - -#define fbufalloc() emalloc(BUFSIZE) -#define fbuffree(x) free(x) - -void plumblook(Plumbmsg*m); -void plumbshow(Plumbmsg*m); -void putsnarf(void); -void getsnarf(void); -int tempfile(void); -void scrlresize(void); -Font* getfont(int, int, char*); -char* getarg(Text*, int, int, Rune**, int*); -char* getbytearg(Text*, int, int, char**); -void new(Text*, Text*, Text*, int, int, Rune*, int); -void undo(Text*, Text*, Text*, int, int, Rune*, int); -char* getname(Text*, Text*, Rune*, int, int); -void scrsleep(uint); -void savemouse(Window*); -int restoremouse(Window*); -void clearmouse(void); -void allwindows(void(*)(Window*, void*), void*); -uint loadfile(int, uint, int*, int(*)(void*, uint, Rune*, int), void*); -void movetodel(Window*); - -Window* errorwin(Mntdir*, int); -Window* errorwinforwin(Window*); -Runestr cleanrname(Runestr); -void run(Window*, char*, Rune*, int, int, char*, char*, int); -void fsysclose(void); -void setcurtext(Text*, int); -int isfilec(Rune); -void rxinit(void); -int rxnull(void); -Runestr dirname(Text*, Rune*, int); -void error(char*); -void cvttorunes(char*, int, Rune*, int*, int*, int*); -void* tmalloc(uint); -void tfree(void); -void killprocs(void); -void killtasks(void); -int runeeq(Rune*, uint, Rune*, uint); -int ALEF_tid(void); -void iconinit(void); -Timer* timerstart(int); -void timerstop(Timer*); -void timercancel(Timer*); -void timerinit(void); -void cut(Text*, Text*, Text*, int, int, Rune*, int); -void paste(Text*, Text*, Text*, int, int, Rune*, int); -void get(Text*, Text*, Text*, int, int, Rune*, int); -void put(Text*, Text*, Text*, int, int, Rune*, int); -void putfile(File*, int, int, Rune*, int); -void fontx(Text*, Text*, Text*, int, int, Rune*, int); -int isspace(Rune); -int isalnum(Rune); -void execute(Text*, uint, uint, int, Text*); -int search(Text*, Rune*, uint); -void look3(Text*, uint, uint, int); -void editcmd(Text*, Rune*, uint); -uint min(uint, uint); -uint max(uint, uint); -Window* lookfile(Rune*, int); -Window* lookid(int, int); -char* runetobyte(Rune*, int); -Rune* bytetorune(char*, int*); -void fsysinit(void); -Mntdir* fsysmount(Rune*, int, Rune**, int); -void fsysincid(Mntdir*); -void fsysdelid(Mntdir*); -Xfid* respond(Xfid*, Fcall*, char*); -int rxcompile(Rune*); -int rgetc(void*, uint); -int tgetc(void*, uint); -int isaddrc(int); -int isregexc(int); -void *emalloc(uint); -void *erealloc(void*, uint); -char *estrdup(char*); -Range address(Mntdir*, Text*, Range, Range, void*, uint, uint, int (*)(void*, uint), int*, uint*); -int rxexecute(Text*, Rune*, uint, uint, Rangeset*); -int rxbexecute(Text*, uint, Rangeset*); -Window* makenewwindow(Text *t); -int expand(Text*, uint, uint, Expand*); -Rune* skipbl(Rune*, int, int*); -Rune* findbl(Rune*, int, int*); -char* edittext(Window*, int, Rune*, int); -void flushwarnings(void); -long nlcount(Text*, long, long, long*); -long nlcounttopos(Text*, long, long, long); - -#define runemalloc(a) (Rune*)emalloc((a)*sizeof(Rune)) -#define runerealloc(a, b) (Rune*)erealloc((a), (b)*sizeof(Rune)) -#define runemove(a, b, c) memmove((a), (b), (c)*sizeof(Rune)) diff --git a/fsys.6 b/fsys.6 deleted file mode 100644 index 4a2fe83..0000000 Binary files a/fsys.6 and /dev/null differ diff --git a/fsys.c b/fsys.c deleted file mode 100644 index bd1214b..0000000 --- a/fsys.c +++ /dev/null @@ -1,749 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -static int cfd; -static int sfd; - -enum -{ - Nhash = 16, - DEBUG = 0 -}; - -static Fid *fids[Nhash]; - -Fid *newfid(int); - -static Xfid* fsysflush(Xfid*, Fid*); -static Xfid* fsysauth(Xfid*, Fid*); -static Xfid* fsysversion(Xfid*, Fid*); -static Xfid* fsysattach(Xfid*, Fid*); -static Xfid* fsyswalk(Xfid*, Fid*); -static Xfid* fsysopen(Xfid*, Fid*); -static Xfid* fsyscreate(Xfid*, Fid*); -static Xfid* fsysread(Xfid*, Fid*); -static Xfid* fsyswrite(Xfid*, Fid*); -static Xfid* fsysclunk(Xfid*, Fid*); -static Xfid* fsysremove(Xfid*, Fid*); -static Xfid* fsysstat(Xfid*, Fid*); -static Xfid* fsyswstat(Xfid*, Fid*); - -Xfid* (*fcall[Tmax])(Xfid*, Fid*) = -{ - [Tflush] = fsysflush, - [Tversion] = fsysversion, - [Tauth] = fsysauth, - [Tattach] = fsysattach, - [Twalk] = fsyswalk, - [Topen] = fsysopen, - [Tcreate] = fsyscreate, - [Tread] = fsysread, - [Twrite] = fsyswrite, - [Tclunk] = fsysclunk, - [Tremove]= fsysremove, - [Tstat] = fsysstat, - [Twstat] = fsyswstat, -}; - -char Eperm[] = "permission denied"; -char Eexist[] = "file does not exist"; -char Enotdir[] = "not a directory"; - -Dirtab dirtab[]= -{ - { ".", QTDIR, Qdir, 0500|DMDIR }, - { "acme", QTDIR, Qacme, 0500|DMDIR }, - { "cons", QTFILE, Qcons, 0600 }, - { "consctl", QTFILE, Qconsctl, 0000 }, - { "draw", QTDIR, Qdraw, 0000|DMDIR }, /* to suppress graphics progs started in acme */ - { "editout", QTFILE, Qeditout, 0200 }, - { "index", QTFILE, Qindex, 0400 }, - { "label", QTFILE, Qlabel, 0600 }, - { "log", QTFILE, Qlog, 0400 }, - { "new", QTDIR, Qnew, 0500|DMDIR }, - { nil, } -}; - -Dirtab dirtabw[]= -{ - { ".", QTDIR, Qdir, 0500|DMDIR }, - { "addr", QTFILE, QWaddr, 0600 }, - { "body", QTAPPEND, QWbody, 0600|DMAPPEND }, - { "ctl", QTFILE, QWctl, 0600 }, - { "data", QTFILE, QWdata, 0600 }, - { "editout", QTFILE, QWeditout, 0200 }, - { "errors", QTFILE, QWerrors, 0200 }, - { "event", QTFILE, QWevent, 0600 }, - { "rdsel", QTFILE, QWrdsel, 0400 }, - { "wrsel", QTFILE, QWwrsel, 0200 }, - { "tag", QTAPPEND, QWtag, 0600|DMAPPEND }, - { "xdata", QTFILE, QWxdata, 0600 }, - { nil, } -}; - -typedef struct Mnt Mnt; -struct Mnt -{ - QLock; - int id; - Mntdir *md; -}; - -Mnt mnt; - -Xfid* respond(Xfid*, Fcall*, char*); -int dostat(int, Dirtab*, uchar*, int, uint); -uint getclock(void); - -char *user = "Wile E. Coyote"; -int clockfd; -static int closing = 0; -int messagesize = Maxblock+IOHDRSZ; /* good start */ - -void fsysproc(void *); - -void -fsysinit(void) -{ - int p[2]; - - if(pipe(p) < 0) - error("can't create pipe"); - cfd = p[0]; - sfd = p[1]; - fmtinstall('F', fcallfmt); - clockfd = open("/dev/time", OREAD|OCEXEC); - user = getuser(); - proccreate(fsysproc, nil, STACK); -} - -void -fsysproc(void *) -{ - int n; - Xfid *x; - Fid *f; - Fcall t; - uchar *buf; - - x = nil; - for(;;){ - buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */ - n = read9pmsg(sfd, buf, messagesize); - if(n <= 0){ - if(closing) - break; - error("i/o error on server channel"); - } - if(x == nil){ - sendp(cxfidalloc, nil); - x = recvp(cxfidalloc); - } - x->buf = buf; - if(convM2S(buf, n, x) != n) - error("convert error in convM2S"); - if(DEBUG) - fprint(2, "%F\n", &x->Fcall); - if(fcall[x->type] == nil) - x = respond(x, &t, "bad fcall type"); - else{ - switch(x->type){ - case Tversion: - case Tauth: - case Tflush: - f = nil; - break; - case Tattach: - f = newfid(x->fid); - break; - default: - f = newfid(x->fid); - if(!f->busy){ - x->f = f; - x = respond(x, &t, "fid not in use"); - continue; - } - break; - } - x->f = f; - x = (*fcall[x->type])(x, f); - } - } -} - -Mntdir* -fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl) -{ - Mntdir *m; - int id; - - qlock(&mnt); - id = ++mnt.id; - m = emalloc(sizeof *m); - m->id = id; - m->dir = dir; - m->ref = 1; /* one for Command, one will be incremented in attach */ - m->ndir = ndir; - m->next = mnt.md; - m->incl = incl; - m->nincl = nincl; - mnt.md = m; - qunlock(&mnt); - return m; -} - -void -fsysincid(Mntdir *m) -{ - qlock(&mnt); - m->ref++; - qunlock(&mnt); -} - -void -fsysdelid(Mntdir *idm) -{ - Mntdir *m, *prev; - int i; - char buf[64]; - - if(idm == nil) - return; - qlock(&mnt); - if(--idm->ref > 0){ - qunlock(&mnt); - return; - } - prev = nil; - for(m=mnt.md; m; m=m->next){ - if(m == idm){ - if(prev) - prev->next = m->next; - else - mnt.md = m->next; - for(i=0; inincl; i++) - free(m->incl[i]); - free(m->incl); - free(m->dir); - free(m); - qunlock(&mnt); - return; - } - prev = m; - } - qunlock(&mnt); - sprint(buf, "fsysdelid: can't find id %d\n", idm->id); - sendp(cerr, estrdup(buf)); -} - -/* - * Called only in exec.c:/^run(), from a different FD group - */ -Mntdir* -fsysmount(Rune *dir, int ndir, Rune **incl, int nincl) -{ - char buf[256]; - Mntdir *m; - - /* close server side so don't hang if acme is half-exited */ - close(sfd); - m = fsysaddid(dir, ndir, incl, nincl); - sprint(buf, "%d", m->id); - if(mount(cfd, -1, "/mnt/acme", MREPL, buf) == -1){ - fsysdelid(m); - return nil; - } - bind("/mnt/acme", "/mnt/wsys", MREPL); - if(bind("/mnt/acme", "/dev", MBEFORE) == -1){ - fsysdelid(m); - return nil; - } - return m; -} - -void -fsysclose(void) -{ - closing = 1; - close(cfd); - close(sfd); -} - -Xfid* -respond(Xfid *x, Fcall *t, char *err) -{ - int n; - - if(err){ - t->type = Rerror; - t->ename = err; - }else - t->type = x->type+1; - t->fid = x->fid; - t->tag = x->tag; - if(x->buf == nil) - x->buf = emalloc(messagesize); - n = convS2M(t, x->buf, messagesize); - if(n <= 0) - error("convert error in convS2M"); - if(write(sfd, x->buf, n) != n) - error("write error in respond"); - free(x->buf); - x->buf = nil; - if(DEBUG) - fprint(2, "r: %F\n", t); - return x; -} - -static -Xfid* -fsysversion(Xfid *x, Fid*) -{ - Fcall t; - - if(x->msize < 256) - return respond(x, &t, "version: message size too small"); - messagesize = x->msize; - t.msize = messagesize; - t.version = "9P2000"; - if(strncmp(x->version, "9P", 2) != 0) - t.version = "unknown"; - return respond(x, &t, nil); -} - -static -Xfid* -fsysauth(Xfid *x, Fid*) -{ - Fcall t; - - return respond(x, &t, "acme: authentication not required"); -} - -static -Xfid* -fsysflush(Xfid *x, Fid*) -{ - sendp(x->c, xfidflush); - return nil; -} - -static -Xfid* -fsysattach(Xfid *x, Fid *f) -{ - Fcall t; - int id; - Mntdir *m; - - if(strcmp(x->uname, user) != 0) - return respond(x, &t, Eperm); - f->busy = TRUE; - f->open = FALSE; - f->qid.path = Qdir; - f->qid.type = QTDIR; - f->qid.vers = 0; - f->dir = dirtab; - f->nrpart = 0; - f->w = nil; - t.qid = f->qid; - f->mntdir = nil; - id = atoi(x->aname); - qlock(&mnt); - for(m=mnt.md; m; m=m->next) - if(m->id == id){ - f->mntdir = m; - m->ref++; - break; - } - if(m == nil) - sendp(cerr, estrdup("unknown id in attach")); - qunlock(&mnt); - return respond(x, &t, nil); -} - -static -Xfid* -fsyswalk(Xfid *x, Fid *f) -{ - Fcall t; - int c, i, j, id; - Qid q; - uchar type; - ulong path; - Fid *nf; - Dirtab *d, *dir; - Window *w; - char *err; - - nf = nil; - w = nil; - if(f->open) - return respond(x, &t, "walk of open file"); - if(x->fid != x->newfid){ - nf = newfid(x->newfid); - if(nf->busy) - return respond(x, &t, "newfid already in use"); - nf->busy = TRUE; - nf->open = FALSE; - nf->mntdir = f->mntdir; - if(f->mntdir) - f->mntdir->ref++; - nf->dir = f->dir; - nf->qid = f->qid; - nf->w = f->w; - nf->nrpart = 0; /* not open, so must be zero */ - if(nf->w) - incref(nf->w); - f = nf; /* walk f */ - } - - t.nwqid = 0; - err = nil; - dir = nil; - id = WIN(f->qid); - q = f->qid; - - if(x->nwname > 0){ - for(i=0; inwname; i++){ - if((q.type & QTDIR) == 0){ - err = Enotdir; - break; - } - - if(strcmp(x->wname[i], "..") == 0){ - type = QTDIR; - path = Qdir; - id = 0; - if(w){ - winclose(w); - w = nil; - } - Accept: - if(i == MAXWELEM){ - err = "name too long"; - break; - } - q.type = type; - q.vers = 0; - q.path = QID(id, path); - t.wqid[t.nwqid++] = q; - continue; - } - - /* is it a numeric name? */ - for(j=0; (c=x->wname[i][j]); j++) - if(c<'0' || '9'wname[i]); - qlock(&row); - w = lookid(id, FALSE); - if(w == nil){ - qunlock(&row); - break; - } - incref(w); /* we'll drop reference at end if there's an error */ - path = Qdir; - type = QTDIR; - qunlock(&row); - dir = dirtabw; - goto Accept; - - Regular: -// if(FILE(f->qid) == Qacme) /* empty directory */ -// break; - if(strcmp(x->wname[i], "new") == 0){ - if(w) - error("w set in walk to new"); - sendp(cnewwindow, nil); /* signal newwindowthread */ - w = recvp(cnewwindow); /* receive new window */ - incref(w); - type = QTDIR; - path = QID(w->id, Qdir); - id = w->id; - dir = dirtabw; - goto Accept; - } - - if(id == 0) - d = dirtab; - else - d = dirtabw; - d++; /* skip '.' */ - for(; d->name; d++) - if(strcmp(x->wname[i], d->name) == 0){ - path = d->qid; - type = d->type; - dir = d; - goto Accept; - } - - break; /* file not found */ - } - - if(i==0 && err == nil) - err = Eexist; - } - - if(err!=nil || t.nwqidnwname){ - if(nf){ - nf->busy = FALSE; - fsysdelid(nf->mntdir); - } - }else if(t.nwqid == x->nwname){ - if(w){ - f->w = w; - w = nil; /* don't drop the reference */ - } - if(dir) - f->dir = dir; - f->qid = q; - } - - if(w != nil) - winclose(w); - - return respond(x, &t, err); -} - -static -Xfid* -fsysopen(Xfid *x, Fid *f) -{ - Fcall t; - int m; - - /* can't truncate anything, so just disregard */ - x->mode &= ~(OTRUNC|OCEXEC); - /* can't execute or remove anything */ - if(x->mode==OEXEC || (x->mode&ORCLOSE)) - goto Deny; - switch(x->mode){ - default: - goto Deny; - case OREAD: - m = 0400; - break; - case OWRITE: - m = 0200; - break; - case ORDWR: - m = 0600; - break; - } - if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m) - goto Deny; - - sendp(x->c, xfidopen); - return nil; - - Deny: - return respond(x, &t, Eperm); -} - -static -Xfid* -fsyscreate(Xfid *x, Fid*) -{ - Fcall t; - - return respond(x, &t, Eperm); -} - -static -int -idcmp(void *a, void *b) -{ - return *(int*)a - *(int*)b; -} - -static -Xfid* -fsysread(Xfid *x, Fid *f) -{ - Fcall t; - uchar *b; - int i, id, n, o, e, j, k, *ids, nids; - Dirtab *d, dt; - Column *c; - uint clock, len; - char buf[16]; - - if(f->qid.type & QTDIR){ - if(FILE(f->qid) == Qacme){ /* empty dir */ - t.data = nil; - t.count = 0; - respond(x, &t, nil); - return x; - } - o = x->offset; - e = x->offset+x->count; - clock = getclock(); - b = emalloc(messagesize); - id = WIN(f->qid); - n = 0; - if(id > 0) - d = dirtabw; - else - d = dirtab; - d++; /* first entry is '.' */ - for(i=0; d->name!=nil && if->qid), d, b+n, x->count-n, clock); - if(len <= BIT16SZ) - break; - if(i >= o) - n += len; - d++; - } - if(id == 0){ - qlock(&row); - nids = 0; - ids = nil; - for(j=0; jnw; k++){ - ids = realloc(ids, (nids+1)*sizeof(int)); - ids[nids++] = c->w[k]->id; - } - } - qunlock(&row); - qsort(ids, nids, sizeof ids[0], idcmp); - j = 0; - dt.name = buf; - for(; jcount-n, clock); - if(len == 0) - break; - if(i >= o) - n += len; - j++; - } - free(ids); - } - t.data = (char*)b; - t.count = n; - respond(x, &t, nil); - free(b); - return x; - } - sendp(x->c, xfidread); - return nil; -} - -static -Xfid* -fsyswrite(Xfid *x, Fid*) -{ - sendp(x->c, xfidwrite); - return nil; -} - -static -Xfid* -fsysclunk(Xfid *x, Fid *f) -{ - fsysdelid(f->mntdir); - sendp(x->c, xfidclose); - return nil; -} - -static -Xfid* -fsysremove(Xfid *x, Fid*) -{ - Fcall t; - - return respond(x, &t, Eperm); -} - -static -Xfid* -fsysstat(Xfid *x, Fid *f) -{ - Fcall t; - - t.stat = emalloc(messagesize-IOHDRSZ); - t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock()); - x = respond(x, &t, nil); - free(t.stat); - return x; -} - -static -Xfid* -fsyswstat(Xfid *x, Fid*) -{ - Fcall t; - - return respond(x, &t, Eperm); -} - -Fid* -newfid(int fid) -{ - Fid *f, *ff, **fh; - - ff = nil; - fh = &fids[fid&(Nhash-1)]; - for(f=*fh; f; f=f->next) - if(f->fid == fid) - return f; - else if(ff==nil && f->busy==FALSE) - ff = f; - if(ff){ - ff->fid = fid; - return ff; - } - f = emalloc(sizeof *f); - f->fid = fid; - f->next = *fh; - *fh = f; - return f; -} - -uint -getclock() -{ - char buf[32]; - - buf[0] = '\0'; - pread(clockfd, buf, sizeof buf, 0); - return atoi(buf); -} - -int -dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock) -{ - Dir d; - - d.qid.path = QID(id, dir->qid); - d.qid.vers = 0; - d.qid.type = dir->type; - d.mode = dir->perm; - d.length = 0; /* would be nice to do better */ - d.name = dir->name; - d.uid = user; - d.gid = user; - d.muid = user; - d.atime = clock; - d.mtime = clock; - return convD2M(&d, buf, nbuf); -} diff --git a/logf.6 b/logf.6 deleted file mode 100644 index cacf009..0000000 Binary files a/logf.6 and /dev/null differ diff --git a/logf.c b/logf.c deleted file mode 100644 index 2ab464a..0000000 --- a/logf.c +++ /dev/null @@ -1,202 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -// State for global log file. -typedef struct Log Log; -struct Log -{ - QLock lk; - Rendez r; - - vlong start; // msg[0] corresponds to 'start' in the global sequence of events - - // queued events (nev=entries in ev, mev=capacity of p) - char **ev; - int nev; - int mev; - - // open acme/put files that need to read events - Fid **f; - int nf; - int mf; - - // active (blocked) reads waiting for events - Xfid **read; - int nread; - int mread; -}; - -static Log eventlog; - -void -xfidlogopen(Xfid *x) -{ - qlock(&eventlog.lk); - if(eventlog.nf >= eventlog.mf) { - eventlog.mf = eventlog.mf*2; - if(eventlog.mf == 0) - eventlog.mf = 8; - eventlog.f = erealloc(eventlog.f, eventlog.mf*sizeof eventlog.f[0]); - } - eventlog.f[eventlog.nf++] = x->f; - x->f->logoff = eventlog.start + eventlog.nev; - - qunlock(&eventlog.lk); -} - -void -xfidlogclose(Xfid *x) -{ - int i; - - qlock(&eventlog.lk); - for(i=0; if) { - eventlog.f[i] = eventlog.f[--eventlog.nf]; - break; - } - } - qunlock(&eventlog.lk); -} - -void -xfidlogread(Xfid *x) -{ - char *p; - int i; - Fcall fc; - - qlock(&eventlog.lk); - if(eventlog.nread >= eventlog.mread) { - eventlog.mread = eventlog.mread*2; - if(eventlog.mread == 0) - eventlog.mread = 8; - eventlog.read = erealloc(eventlog.read, eventlog.mread*sizeof eventlog.read[0]); - } - eventlog.read[eventlog.nread++] = x; - - if(eventlog.r.l == nil) - eventlog.r.l = &eventlog.lk; - x->flushed = FALSE; - while(x->f->logoff >= eventlog.start+eventlog.nev && !x->flushed) - rsleep(&eventlog.r); - - for(i=0; iflushed) { - qunlock(&eventlog.lk); - return; - } - - i = x->f->logoff - eventlog.start; - p = estrdup(eventlog.ev[i]); - x->f->logoff++; - qunlock(&eventlog.lk); - - fc.data = p; - fc.count = strlen(p); - respond(x, &fc, nil); - free(p); -} - -void -xfidlogflush(Xfid *x) -{ - int i; - Xfid *rx; - - qlock(&eventlog.lk); - for(i=0; itag == x->oldtag) { - rx->flushed = TRUE; - rwakeupall(&eventlog.r); - } - } - qunlock(&eventlog.lk); -} - -/* - * add a log entry for op on w. - * expected calls: - * - * op == "new" for each new window - * - caller of coladd or makenewwindow responsible for calling - * xfidlog after setting window name - * - exception: zerox - * - * op == "zerox" for new window created via zerox - * - called from zeroxx - * - * op == "get" for Get executed on window - * - called from get - * - * op == "put" for Put executed on window - * - called from put - * - * op == "del" for deleted window - * - called from winclose - * - * op == "focus" for window focus change - * - called from mousethread - */ -void -xfidlog(Window *w, char *op) -{ - int i, n; - vlong min; - File *f; - char *name; - - qlock(&eventlog.lk); - if(eventlog.nev >= eventlog.mev) { - // Remove and free any entries that all readers have read. - min = eventlog.start + eventlog.nev; - for(i=0; i eventlog.f[i]->logoff) - min = eventlog.f[i]->logoff; - } - if(min > eventlog.start) { - n = min - eventlog.start; - for(i=0; i= eventlog.mev) { - eventlog.mev = eventlog.mev*2; - if(eventlog.mev == 0) - eventlog.mev = 8; - eventlog.ev = erealloc(eventlog.ev, eventlog.mev*sizeof eventlog.ev[0]); - } - } - f = w->body.file; - name = runetobyte(f->name, f->nname); - if(name == nil) - name = estrdup(""); - eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name); - free(name); - if(eventlog.r.l == nil) - eventlog.r.l = &eventlog.lk; - rwakeupall(&eventlog.r); - qunlock(&eventlog.lk); -} diff --git a/look.6 b/look.6 deleted file mode 100644 index 30fa1d4..0000000 Binary files a/look.6 and /dev/null differ diff --git a/look.c b/look.c deleted file mode 100644 index 42b449c..0000000 --- a/look.c +++ /dev/null @@ -1,737 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -Window* openfile(Text*, Expand*); - -int nuntitled; - -void -look3(Text *t, uint q0, uint q1, int external) -{ - int n, c, f, expanded; - Text *ct; - Expand e; - Rune *r; - uint p; - Plumbmsg *m; - Runestr dir; - char buf[32]; - - ct = seltext; - if(ct == nil) - seltext = t; - expanded = expand(t, q0, q1, &e); - if(!external && t->w!=nil && t->w->nopen[QWevent]>0){ - /* send alphanumeric expansion to external client */ - if(expanded == FALSE) - return; - f = 0; - if((e.at!=nil && t->w!=nil) || (e.nname>0 && lookfile(e.name, e.nname)!=nil)) - f = 1; /* acme can do it without loading a file */ - if(q0!=e.q0 || q1!=e.q1) - f |= 2; /* second (post-expand) message follows */ - if(e.nname) - f |= 4; /* it's a file name */ - c = 'l'; - if(t->what == Body) - c = 'L'; - n = q1-q0; - if(n <= EVENTSIZE){ - r = runemalloc(n); - bufread(t->file, q0, r, n); - winevent(t->w, "%c%d %d %d %d %.*S\n", c, q0, q1, f, n, n, r); - free(r); - }else - winevent(t->w, "%c%d %d %d 0 \n", c, q0, q1, f, n); - if(q0==e.q0 && q1==e.q1) - return; - if(e.nname){ - n = e.nname; - if(e.a1 > e.a0) - n += 1+(e.a1-e.a0); - r = runemalloc(n); - runemove(r, e.name, e.nname); - if(e.a1 > e.a0){ - r[e.nname] = ':'; - bufread(e.at->file, e.a0, r+e.nname+1, e.a1-e.a0); - } - }else{ - n = e.q1 - e.q0; - r = runemalloc(n); - bufread(t->file, e.q0, r, n); - } - f &= ~2; - if(n <= EVENTSIZE) - winevent(t->w, "%c%d %d %d %d %.*S\n", c, e.q0, e.q1, f, n, n, r); - else - winevent(t->w, "%c%d %d %d 0 \n", c, e.q0, e.q1, f, n); - free(r); - goto Return; - } - if(plumbsendfd >= 0){ - /* send whitespace-delimited word to plumber */ - m = emalloc(sizeof(Plumbmsg)); - m->src = estrdup("acme"); - m->dst = nil; - dir = dirname(t, nil, 0); - if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ - free(dir.r); - dir.r = nil; - dir.nr = 0; - } - if(dir.nr == 0) - m->wdir = estrdup(wdir); - else - m->wdir = runetobyte(dir.r, dir.nr); - free(dir.r); - m->type = estrdup("text"); - m->attr = nil; - buf[0] = '\0'; - if(q1 == q0){ - if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ - q0 = t->q0; - q1 = t->q1; - }else{ - p = q0; - while(q0>0 && (c=tgetc(t, q0-1))!=' ' && c!='\t' && c!='\n') - q0--; - while(q1file->nc && (c=tgetc(t, q1))!=' ' && c!='\t' && c!='\n') - q1++; - if(q1 == q0){ - plumbfree(m); - goto Return; - } - sprint(buf, "click=%d", p-q0); - m->attr = plumbunpackattr(buf); - } - } - r = runemalloc(q1-q0); - bufread(t->file, q0, r, q1-q0); - m->data = runetobyte(r, q1-q0); - m->ndata = strlen(m->data); - free(r); - if(m->ndata= 0){ - plumbfree(m); - goto Return; - } - plumbfree(m); - /* plumber failed to match; fall through */ - } - - /* interpret alphanumeric string ourselves */ - if(expanded == FALSE) - return; - if(e.name || e.at) - openfile(t, &e); - else{ - if(t->w == nil) - return; - ct = &t->w->body; - if(t->w != ct->w) - winlock(ct->w, 'M'); - if(t == ct) - textsetselect(ct, e.q1, e.q1); - n = e.q1 - e.q0; - r = runemalloc(n); - bufread(t->file, e.q0, r, n); - if(search(ct, r, n) && e.jump) - moveto(mousectl, addpt(frptofchar(ct, ct->p0), Pt(4, ct->font->height-4))); - if(t->w != ct->w) - winunlock(ct->w); - free(r); - } - - Return: - free(e.name); - free(e.bname); -} - -int -plumbgetc(void *a, uint n) -{ - Rune *r; - - r = a; - if(n>runestrlen(r)) - return 0; - return r[n]; -} - -void -plumblook(Plumbmsg *m) -{ - Expand e; - char *addr; - - if(m->ndata >= BUFSIZE){ - warning(nil, "insanely long file name (%d bytes) in plumb message (%.32s...)\n", m->ndata, m->data); - return; - } - e.q0 = 0; - e.q1 = 0; - if(m->data[0] == '\0') - return; - e.ar = nil; - e.bname = m->data; - e.name = bytetorune(e.bname, &e.nname); - e.jump = TRUE; - e.a0 = 0; - e.a1 = 0; - addr = plumblookup(m->attr, "addr"); - if(addr != nil){ - e.ar = bytetorune(addr, &e.a1); - e.agetc = plumbgetc; - } - openfile(nil, &e); - free(e.name); - free(e.at); -} - -void -plumbshow(Plumbmsg *m) -{ - Window *w; - Rune rb[256], *r; - int nb, nr; - Runestr rs; - char *name, *p, namebuf[16]; - - w = makenewwindow(nil); - name = plumblookup(m->attr, "filename"); - if(name == nil){ - name = namebuf; - nuntitled++; - snprint(namebuf, sizeof namebuf, "Untitled-%d", nuntitled); - } - p = nil; - if(name[0]!='/' && m->wdir!=nil && m->wdir[0]!='\0'){ - nb = strlen(m->wdir) + 1 + strlen(name) + 1; - p = emalloc(nb); - snprint(p, nb, "%s/%s", m->wdir, name); - name = p; - } - cvttorunes(name, strlen(name), rb, &nb, &nr, nil); - free(p); - rs = cleanrname((Runestr){rb, nr}); - winsetname(w, rs.r, rs.nr); - r = runemalloc(m->ndata); - cvttorunes(m->data, m->ndata, r, &nb, &nr, nil); - textinsert(&w->body, 0, r, nr, TRUE); - free(r); - w->body.file->mod = FALSE; - w->dirty = FALSE; - winsettag(w); - textscrdraw(&w->body); - textsetselect(&w->tag, w->tag.file->nc, w->tag.file->nc); - xfidlog(w, "new"); -} - -int -search(Text *ct, Rune *r, uint n) -{ - uint q, nb, maxn; - int around; - Rune *s, *b, *c; - - if(n==0 || n>ct->file->nc) - return FALSE; - if(2*n > RBUFSIZE){ - warning(nil, "string too long\n"); - return FALSE; - } - maxn = max(2*n, RBUFSIZE); - s = fbufalloc(); - b = s; - nb = 0; - b[nb] = 0; - around = 0; - q = ct->q1; - for(;;){ - if(q >= ct->file->nc){ - q = 0; - around = 1; - nb = 0; - b[nb] = 0; - } - if(nb > 0){ - c = runestrchr(b, r[0]); - if(c == nil){ - q += nb; - nb = 0; - b[nb] = 0; - if(around && q>=ct->q1) - break; - continue; - } - q += (c-b); - nb -= (c-b); - b = c; - } - /* reload if buffer covers neither string nor rest of file */ - if(nbfile->nc-q){ - nb = ct->file->nc-q; - if(nb >= maxn) - nb = maxn-1; - bufread(ct->file, q, s, nb); - b = s; - b[nb] = '\0'; - } - /* this runeeq is fishy but the null at b[nb] makes it safe */ - if(runeeq(b, n, r, n)==TRUE){ - if(ct->w){ - textshow(ct, q, q+n, 1); - winsettag(ct->w); - }else{ - ct->q0 = q; - ct->q1 = q+n; - } - seltext = ct; - fbuffree(s); - return TRUE; - } - --nb; - b++; - q++; - if(around && q>=ct->q1) - break; - } - fbuffree(s); - return FALSE; -} - -int -isfilec(Rune r) -{ - if(isalnum(r)) - return TRUE; - if(runestrchr(L".-+/:@", r)) - return TRUE; - return FALSE; -} - -/* Runestr wrapper for cleanname */ -Runestr -cleanrname(Runestr rs) -{ - char *s; - int nb, nulls; - - s = runetobyte(rs.r, rs.nr); - cleanname(s); - cvttorunes(s, strlen(s), rs.r, &nb, &rs.nr, &nulls); - free(s); - return rs; -} - -Runestr -includefile(Rune *dir, Rune *file, int nfile) -{ - int m, n; - char *a; - Rune *r; - - m = runestrlen(dir); - a = emalloc((m+1+nfile)*UTFmax+1); - sprint(a, "%S/%.*S", dir, nfile, file); - n = access(a, 0); - free(a); - if(n < 0) - return (Runestr){nil, 0}; - r = runemalloc(m+1+nfile); - runemove(r, dir, m); - runemove(r+m, L"/", 1); - runemove(r+m+1, file, nfile); - free(file); - return cleanrname((Runestr){r, m+1+nfile}); -} - -static Rune *objdir; - -Runestr -includename(Text *t, Rune *r, int n) -{ - Window *w; - char buf[128]; - Runestr file; - int i; - - if(objdir==nil && objtype!=nil){ - sprint(buf, "/%s/include", objtype); - objdir = bytetorune(buf, &i); - objdir = runerealloc(objdir, i+1); - objdir[i] = '\0'; - } - - w = t->w; - if(n==0 || r[0]=='/' || w==nil) - goto Rescue; - if(n>2 && r[0]=='.' && r[1]=='/') - goto Rescue; - file.r = nil; - file.nr = 0; - for(i=0; inincl && file.r==nil; i++) - file = includefile(w->incl[i], r, n); - - if(file.r == nil) - file = includefile(L"/sys/include", r, n); - if(file.r==nil && objdir!=nil) - file = includefile(objdir, r, n); - if(file.r == nil) - goto Rescue; - return file; - - Rescue: - return (Runestr){r, n}; -} - -Runestr -dirname(Text *t, Rune *r, int n) -{ - Rune *b, c; - uint m, nt; - int slash; - Runestr tmp; - - b = nil; - if(t==nil || t->w==nil) - goto Rescue; - nt = t->w->tag.file->nc; - if(nt == 0) - goto Rescue; - if(n>=1 && r[0]=='/') - goto Rescue; - b = runemalloc(nt+n+1); - bufread(t->w->tag.file, 0, b, nt); - slash = -1; - for(m=0; mfile->nc && isfilec(c=textreadc(t, q1))){ - if(c == ':'){ - colon = q1; - break; - } - q1++; - } - while(q0>0 && (isfilec(c=textreadc(t, q0-1)) || isaddrc(c) || isregexc(c))){ - q0--; - if(colon<0 && c==':') - colon = q0; - } - /* - * if it looks like it might begin file: , consume address chars after : - * otherwise terminate expansion at : - */ - if(colon >= 0){ - q1 = colon; - if(colonfile->nc-1 && isaddrc(textreadc(t, colon+1))){ - q1 = colon+1; - while(q1file->nc && isaddrc(textreadc(t, q1))) - q1++; - } - } - if(q1 > q0) - if(colon >= 0){ /* stop at white space */ - for(amax=colon+1; amaxfile->nc; amax++) - if((c=textreadc(t, amax))==' ' || c=='\t' || c=='\n') - break; - }else - amax = t->file->nc; - } - amin = amax; - e->q0 = q0; - e->q1 = q1; - n = q1-q0; - if(n == 0) - return FALSE; - /* see if it's a file name */ - r = runemalloc(n); - bufread(t->file, q0, r, n); - /* first, does it have bad chars? */ - nname = -1; - for(i=0; ifile->nc && (i==n-1 || isaddrc(textreadc(t, q0+i+1)))) - amin = q0+i; - else - goto Isntfile; - nname = i; - } - } - if(nname == -1) - nname = n; - for(i=0; i, and turn that into an include - * file name if so. Should probably do it for "" too, but that's not - * restrictive enough syntax and checking for a #include earlier on the - * line would be silly. - */ - if(q0>0 && textreadc(t, q0-1)=='<' && q1file->nc && textreadc(t, q1)=='>'){ - rs = includename(t, r, nname); - r = rs.r; - nname = rs.nr; - } - else if(amin == q0) - goto Isfile; - else{ - rs = dirname(t, r, nname); - r = rs.r; - nname = rs.nr; - } - e->bname = runetobyte(r, nname); - /* if it's already a window name, it's a file */ - w = lookfile(r, nname); - if(w != nil) - goto Isfile; - /* if it's the name of a file, it's a file */ - if(access(e->bname, 0) < 0){ - free(e->bname); - e->bname = nil; - goto Isntfile; - } - - Isfile: - e->name = r; - e->nname = nname; - e->at = t; - e->a0 = amin+1; - eval = FALSE; - address(nil, nil, (Range){-1,-1}, (Range){0, 0}, t, e->a0, amax, tgetc, &eval, (uint*)&e->a1); - return TRUE; - - Isntfile: - free(r); - return FALSE; -} - -int -expand(Text *t, uint q0, uint q1, Expand *e) -{ - memset(e, 0, sizeof *e); - e->agetc = tgetc; - /* if in selection, choose selection */ - e->jump = TRUE; - if(q1==q0 && t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ - q0 = t->q0; - q1 = t->q1; - if(t->what == Tag) - e->jump = FALSE; - } - - if(expandfile(t, q0, q1, e)) - return TRUE; - - if(q0 == q1){ - while(q1file->nc && isalnum(textreadc(t, q1))) - q1++; - while(q0>0 && isalnum(textreadc(t, q0-1))) - q0--; - } - e->q0 = q0; - e->q1 = q1; - return q1 > q0; -} - -Window* -lookfile(Rune *s, int n) -{ - int i, j, k; - Window *w; - Column *c; - Text *t; - - /* avoid terminal slash on directories */ - if(n>1 && s[n-1] == '/') - --n; - for(j=0; jnw; i++){ - w = c->w[i]; - t = &w->body; - k = t->file->nname; - if(k>1 && t->file->name[k-1] == '/') - k--; - if(runeeq(t->file->name, k, s, n)){ - w = w->body.file->curtext->w; - if(w->col != nil) /* protect against race deleting w */ - return w; - } - } - } - return nil; -} - -Window* -lookid(int id, int dump) -{ - int i, j; - Window *w; - Column *c; - - for(j=0; jnw; i++){ - w = c->w[i]; - if(dump && w->dumpid == id) - return w; - if(!dump && w->id == id) - return w; - } - } - return nil; -} - - -Window* -openfile(Text *t, Expand *e) -{ - Range r; - Window *w, *ow; - int eval, i, n; - Rune *rp; - uint dummy; - - if(e->nname == 0){ - w = t->w; - if(w == nil) - return nil; - }else - w = lookfile(e->name, e->nname); - if(w){ - t = &w->body; - if(!t->col->safe && t->maxlines==0) /* window is obscured by full-column window */ - colgrow(t->col, t->col->w[0], 1); - }else{ - ow = nil; - if(t) - ow = t->w; - w = makenewwindow(t); - t = &w->body; - winsetname(w, e->name, e->nname); - textload(t, 0, e->bname, 1); - t->file->mod = FALSE; - t->w->dirty = FALSE; - winsettag(t->w); - textsetselect(&t->w->tag, t->w->tag.file->nc, t->w->tag.file->nc); - if(ow != nil){ - for(i=ow->nincl; --i>=0; ){ - n = runestrlen(ow->incl[i]); - rp = runemalloc(n); - runemove(rp, ow->incl[i], n); - winaddincl(w, rp, n); - } - for(i=0; i < NINDENT; i++) - w->indent[i] = ow->indent[i]; - }else - for(i=0; i < NINDENT; i++) - w->indent[i] = globalindent[i]; - xfidlog(w, "new"); - } - if(e->a1 == e->a0) - eval = FALSE; - else{ - eval = TRUE; - r = address(nil, t, (Range){-1, -1}, (Range){t->q0, t->q1}, e->at, e->a0, e->a1, e->agetc, &eval, &dummy); - if(eval == FALSE) - e->jump = FALSE; /* don't jump if invalid address */ - } - if(eval == FALSE){ - r.q0 = t->q0; - r.q1 = t->q1; - } - textshow(t, r.q0, r.q1, 1); - winsettag(t->w); - seltext = t; - if(e->jump) - moveto(mousectl, addpt(frptofchar(t, t->p0), Pt(4, font->height-4))); - return w; -} - -void -new(Text *et, Text *t, Text *argt, int flag1, int flag2, Rune *arg, int narg) -{ - int ndone; - Rune *a, *f; - int na, nf; - Expand e; - Runestr rs; - Window *w; - - getarg(argt, FALSE, TRUE, &a, &na); - if(a){ - new(et, t, nil, flag1, flag2, a, na); - if(narg == 0) - return; - } - /* loop condition: *arg is not a blank */ - for(ndone=0; ; ndone++){ - a = findbl(arg, narg, &na); - if(a == arg){ - if(ndone==0 && et->col!=nil) { - w = coladd(et->col, nil, nil, -1); - winsettag(w); - xfidlog(w, "new"); - } - break; - } - nf = narg-na; - f = runemalloc(nf); - runemove(f, arg, nf); - rs = dirname(et, f, nf); - f = rs.r; - nf = rs.nr; - memset(&e, 0, sizeof e); - e.name = f; - e.nname = nf; - e.bname = runetobyte(f, nf); - e.jump = TRUE; - openfile(et, &e); - free(f); - free(e.bname); - arg = skipbl(a, na, &narg); - } -} diff --git a/mkfile b/mkfile deleted file mode 100644 index 466e8e8..0000000 --- a/mkfile +++ /dev/null @@ -1,41 +0,0 @@ - syms - for(i in ????.c) $CC -aa $i >> syms diff --git a/regx.6 b/regx.6 deleted file mode 100644 index b4b7fbe..0000000 Binary files a/regx.6 and /dev/null differ diff --git a/regx.c b/regx.c deleted file mode 100644 index cedf11a..0000000 --- a/regx.c +++ /dev/null @@ -1,839 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -Rangeset sel; -Rune *lastregexp; - -/* - * Machine Information - */ -typedef struct Inst Inst; -struct Inst -{ - uint type; /* <= Runemax+1 ==> literal, otherwise action */ - union { - int sid; - int subid; - int class; - Inst *other; - Inst *right; - }; - union{ - Inst *left; - Inst *next; - }; -}; - -#define NPROG 1024 -Inst program[NPROG]; -Inst *progp; -Inst *startinst; /* First inst. of program; might not be program[0] */ -Inst *bstartinst; /* same for backwards machine */ -Channel *rechan; /* chan(Inst*) */ - -typedef struct Ilist Ilist; -struct Ilist -{ - Inst *inst; /* Instruction of the thread */ - Rangeset se; - uint startp; /* first char of match */ -}; - -#define NLIST 127 - -Ilist *tl, *nl; /* This list, next list */ -Ilist list[2][NLIST+1]; /* +1 for trailing null */ -static Rangeset sempty; - -/* - * Actions and Tokens - * - * 0x100xx are operators, value == precedence - * 0x200xx are tokens, i.e. operands for operators - */ -enum { - OPERATOR = Runemask+1, /* Bitmask of all operators */ - START = OPERATOR, /* Start, used for marker on stack */ - RBRA, /* Right bracket, ) */ - LBRA, /* Left bracket, ( */ - OR, /* Alternation, | */ - CAT, /* Concatentation, implicit operator */ - STAR, /* Closure, * */ - PLUS, /* a+ == aa* */ - QUEST, /* a? == a|nothing, i.e. 0 or 1 a's */ - - ANY = OPERATOR<<1, /* Any character but newline, . */ - NOP, /* No operation, internal use only */ - BOL, /* Beginning of line, ^ */ - EOL, /* End of line, $ */ - CCLASS, /* Character class, [] */ - NCCLASS, /* Negated character class, [^] */ - END, /* Terminate: match found */ - - ISATOR = OPERATOR, - ISAND = OPERATOR<<1, -}; - -/* - * Parser Information - */ -typedef struct Node Node; -struct Node -{ - Inst *first; - Inst *last; -}; - -#define NSTACK 20 -Node andstack[NSTACK]; -Node *andp; -int atorstack[NSTACK]; -int *atorp; -int lastwasand; /* Last token was operand */ -int cursubid; -int subidstack[NSTACK]; -int *subidp; -int backwards; -int nbra; -Rune *exprp; /* pointer to next character in source expression */ -#define DCLASS 10 /* allocation increment */ -int nclass; /* number active */ -int Nclass; /* high water mark */ -Rune **class; -int negateclass; - -int addinst(Ilist *l, Inst *inst, Rangeset *sep); -void newmatch(Rangeset*); -void bnewmatch(Rangeset*); -void pushand(Inst*, Inst*); -void pushator(int); -Node *popand(int); -int popator(void); -void startlex(Rune*); -int lex(void); -void operator(int); -void operand(int); -void evaluntil(int); -void optimize(Inst*); -void bldcclass(void); - -void -rxinit(void) -{ - rechan = chancreate(sizeof(Inst*), 0); - lastregexp = runemalloc(1); -} - -void -regerror(char *e) -{ - lastregexp[0] = 0; - warning(nil, "regexp: %s\n", e); - sendp(rechan, nil); - threadexits(nil); -} - -Inst * -newinst(int t) -{ - if(progp >= &program[NPROG]) - regerror("expression too long"); - progp->type = t; - progp->left = nil; - progp->right = nil; - return progp++; -} - -void -realcompile(void *arg) -{ - int token; - Rune *s; - - threadsetname("regcomp"); - s = arg; - startlex(s); - atorp = atorstack; - andp = andstack; - subidp = subidstack; - cursubid = 0; - lastwasand = FALSE; - /* Start with a low priority operator to prime parser */ - pushator(START-1); - while((token=lex()) != END){ - if((token&ISATOR) == OPERATOR) - operator(token); - else - operand(token); - } - /* Close with a low priority operator */ - evaluntil(START); - /* Force END */ - operand(END); - evaluntil(START); - if(nbra) - regerror("unmatched `('"); - --andp; /* points to first and only operand */ - sendp(rechan, andp->first); - threadexits(nil); -} - -/* r is null terminated */ -int -rxcompile(Rune *r) -{ - int i, nr; - Inst *oprogp; - - nr = runestrlen(r)+1; - if(runeeq(lastregexp, runestrlen(lastregexp)+1, r, nr)==TRUE) - return TRUE; - lastregexp[0] = 0; - for(i=0; itype = NCCLASS; /* UGH */ - i->class = nclass-1; /* UGH */ - } - pushand(i, i); - lastwasand = TRUE; -} - -void -operator(int t) -{ - if(t==RBRA && --nbra<0) - regerror("unmatched `)'"); - if(t==LBRA){ - cursubid++; /* silently ignored */ - nbra++; - if(lastwasand) - operator(CAT); - }else - evaluntil(t); - if(t!=RBRA) - pushator(t); - lastwasand = FALSE; - if(t==STAR || t==QUEST || t==PLUS || t==RBRA) - lastwasand = TRUE; /* these look like operands */ -} - -void -pushand(Inst *f, Inst *l) -{ - if(andp >= &andstack[NSTACK]) - error("operand stack overflow"); - andp->first = f; - andp->last = l; - andp++; -} - -void -pushator(int t) -{ - if(atorp >= &atorstack[NSTACK]) - error("operator stack overflow"); - *atorp++=t; - if(cursubid >= NRange) - *subidp++= -1; - else - *subidp++=cursubid; -} - -Node * -popand(int op) -{ - char buf[64]; - - if(andp <= &andstack[0]) - if(op){ - sprint(buf, "missing operand for %c", op); - regerror(buf); - }else - regerror("malformed regexp"); - return --andp; -} - -int -popator() -{ - if(atorp <= &atorstack[0]) - error("operator stack underflow"); - --subidp; - return *--atorp; -} - -void -evaluntil(int pri) -{ - Node *op1, *op2, *t; - Inst *inst1, *inst2; - - while(pri==RBRA || atorp[-1]>=pri){ - switch(popator()){ - case LBRA: - op1 = popand('('); - inst2 = newinst(RBRA); - inst2->subid = *subidp; - op1->last->next = inst2; - inst1 = newinst(LBRA); - inst1->subid = *subidp; - inst1->next = op1->first; - pushand(inst1, inst2); - return; /* must have been RBRA */ - default: - error("unknown regexp operator"); - break; - case OR: - op2 = popand('|'); - op1 = popand('|'); - inst2 = newinst(NOP); - op2->last->next = inst2; - op1->last->next = inst2; - inst1 = newinst(OR); - inst1->right = op1->first; - inst1->left = op2->first; - pushand(inst1, inst2); - break; - case CAT: - op2 = popand(0); - op1 = popand(0); - if(backwards && op2->first->type!=END){ - t = op1; - op1 = op2; - op2 = t; - } - op1->last->next = op2->first; - pushand(op1->first, op2->last); - break; - case STAR: - op2 = popand('*'); - inst1 = newinst(OR); - op2->last->next = inst1; - inst1->right = op2->first; - pushand(inst1, inst1); - break; - case PLUS: - op2 = popand('+'); - inst1 = newinst(OR); - op2->last->next = inst1; - inst1->right = op2->first; - pushand(op2->first, inst1); - break; - case QUEST: - op2 = popand('?'); - inst1 = newinst(OR); - inst2 = newinst(NOP); - inst1->left = inst2; - inst1->right = op2->first; - op2->last->next = inst2; - pushand(inst1, inst2); - break; - } - } -} - - -void -optimize(Inst *start) -{ - Inst *inst, *target; - - for(inst=start; inst->type!=END; inst++){ - target = inst->next; - while(target->type == NOP) - target = target->next; - inst->next = target; - } -} - -void -startlex(Rune *s) -{ - exprp = s; - nbra = 0; -} - - -int -lex(void){ - int c; - - c = *exprp++; - switch(c){ - case '\\': - if(*exprp) - if((c= *exprp++)=='n') - c='\n'; - break; - case 0: - c = END; - --exprp; /* In case we come here again */ - break; - case '*': - c = STAR; - break; - case '?': - c = QUEST; - break; - case '+': - c = PLUS; - break; - case '|': - c = OR; - break; - case '.': - c = ANY; - break; - case '(': - c = LBRA; - break; - case ')': - c = RBRA; - break; - case '^': - c = BOL; - break; - case '$': - c = EOL; - break; - case '[': - c = CCLASS; - bldcclass(); - break; - } - return c; -} - -int -nextrec(void) -{ - if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0)) - regerror("malformed `[]'"); - if(exprp[0] == '\\'){ - exprp++; - if(*exprp=='n'){ - exprp++; - return '\n'; - } - return *exprp++|(Runemask+1); - } - return *exprp++; -} - -void -bldcclass(void) -{ - int c1, c2, n, na; - Rune *classp; - - classp = runemalloc(DCLASS); - n = 0; - na = DCLASS; - /* we have already seen the '[' */ - if(*exprp == '^'){ - classp[n++] = '\n'; /* don't match newline in negate case */ - negateclass = TRUE; - exprp++; - }else - negateclass = FALSE; - while((c1 = nextrec()) != ']'){ - if(c1 == '-'){ - Error: - free(classp); - regerror("malformed `[]'"); - } - if(n+4 >= na){ /* 3 runes plus NUL */ - na += DCLASS; - classp = runerealloc(classp, na); - } - if(*exprp == '-'){ - exprp++; /* eat '-' */ - if((c2 = nextrec()) == ']') - goto Error; - classp[n+0] = Runemax; - classp[n+1] = c1 & Runemask; - classp[n+2] = c2 & Runemask; - n += 3; - }else - classp[n++] = c1 & Runemask; - } - classp[n] = 0; - if(nclass == Nclass){ - Nclass += DCLASS; - class = realloc(class, Nclass*sizeof(Rune*)); - } - class[nclass++] = classp; -} - -int -classmatch(int classno, int c, int negate) -{ - Rune *p; - - p = class[classno]; - while(*p){ - if(*p == Runemax){ - if(p[1]<=c && c<=p[2]) - return !negate; - p += 3; - }else if(*p++ == c) - return !negate; - } - return negate; -} - -/* - * Note optimization in addinst: - * *l must be pending when addinst called; if *l has been looked - * at already, the optimization is a bug. - */ -int -addinst(Ilist *l, Inst *inst, Rangeset *sep) -{ - Ilist *p; - - for(p = l; p->inst; p++){ - if(p->inst==inst){ - if((sep)->r[0].q0 < p->se.r[0].q0) - p->se= *sep; /* this would be bug */ - return 0; /* It's already there */ - } - } - p->inst = inst; - p->se= *sep; - (p+1)->inst = nil; - return 1; -} - -int -rxnull(void) -{ - return startinst==nil || bstartinst==nil; -} - -/* either t!=nil or r!=nil, and we match the string in the appropriate place */ -int -rxexecute(Text *t, Rune *r, uint startp, uint eof, Rangeset *rp) -{ - int flag; - Inst *inst; - Ilist *tlp; - uint p; - int nnl, ntl; - int nc, c; - int wrapped; - int startchar; - - flag = 0; - p = startp; - startchar = 0; - wrapped = 0; - nnl = 0; - if(startinst->typetype; - list[0][0].inst = list[1][0].inst = nil; - sel.r[0].q0 = -1; - if(t != nil) - nc = t->file->nc; - else - nc = runestrlen(r); - /* Execute machine once for each character */ - for(;;p++){ - doloop: - if(p>=eof || p>=nc){ - switch(wrapped++){ - case 0: /* let loop run one more click */ - case 2: - break; - case 1: /* expired; wrap to beginning */ - if(sel.r[0].q0>=0 || eof!=Infinity) - goto Return; - list[0][0].inst = list[1][0].inst = nil; - p = 0; - goto doloop; - default: - goto Return; - } - c = 0; - }else{ - if(((wrapped && p>=startp) || sel.r[0].q0>0) && nnl==0) - break; - if(t != nil) - c = textreadc(t, p); - else - c = r[p]; - } - /* fast check for first char */ - if(startchar && nnl==0 && c!=startchar) - continue; - tl = list[flag]; - nl = list[flag^=1]; - nl->inst = nil; - ntl = nnl; - nnl = 0; - if(sel.r[0].q0<0 && (!wrapped || p= NLIST){ - Overflow: - warning(nil, "regexp list overflow\n"); - sel.r[0].q0 = -1; - goto Return; - } - } - /* Execute machine until this list is empty */ - for(tlp = tl; inst = tlp->inst; tlp++){ /* assignment = */ - Switchstmt: - switch(inst->type){ - default: /* regular character */ - if(inst->type==c){ - Addinst: - if(addinst(nl, inst->next, &tlp->se)) - if(++nnl >= NLIST) - goto Overflow; - } - break; - case LBRA: - if(inst->subid>=0) - tlp->se.r[inst->subid].q0 = p; - inst = inst->next; - goto Switchstmt; - case RBRA: - if(inst->subid>=0) - tlp->se.r[inst->subid].q1 = p; - inst = inst->next; - goto Switchstmt; - case ANY: - if(c!='\n') - goto Addinst; - break; - case BOL: - if(p==0 || (t!=nil && textreadc(t, p-1)=='\n') || (r!=nil && r[p-1]=='\n')){ - Step: - inst = inst->next; - goto Switchstmt; - } - break; - case EOL: - if(c == '\n') - goto Step; - break; - case CCLASS: - if(c>=0 && classmatch(inst->class, c, 0)) - goto Addinst; - break; - case NCCLASS: - if(c>=0 && classmatch(inst->class, c, 1)) - goto Addinst; - break; - case OR: - /* evaluate right choice later */ - if(addinst(tlp, inst->right, &tlp->se)) - if(++ntl >= NLIST) - goto Overflow; - /* efficiency: advance and re-evaluate */ - inst = inst->left; - goto Switchstmt; - case END: /* Match! */ - tlp->se.r[0].q1 = p; - newmatch(&tlp->se); - break; - } - } - } - Return: - *rp = sel; - return sel.r[0].q0 >= 0; -} - -void -newmatch(Rangeset *sp) -{ - if(sel.r[0].q0<0 || sp->r[0].q0r[0].q0==sel.r[0].q0 && sp->r[0].q1>sel.r[0].q1)) - sel = *sp; -} - -int -rxbexecute(Text *t, uint startp, Rangeset *rp) -{ - int flag; - Inst *inst; - Ilist *tlp; - int p; - int nnl, ntl; - int c; - int wrapped; - int startchar; - - flag = 0; - nnl = 0; - wrapped = 0; - p = startp; - startchar = 0; - if(bstartinst->typetype; - list[0][0].inst = list[1][0].inst = nil; - sel.r[0].q0= -1; - /* Execute machine once for each character, including terminal NUL */ - for(;;--p){ - doloop: - if(p <= 0){ - switch(wrapped++){ - case 0: /* let loop run one more click */ - case 2: - break; - case 1: /* expired; wrap to end */ - if(sel.r[0].q0>=0) - goto Return; - list[0][0].inst = list[1][0].inst = nil; - p = t->file->nc; - goto doloop; - case 3: - default: - goto Return; - } - c = 0; - }else{ - if(((wrapped && p<=startp) || sel.r[0].q0>0) && nnl==0) - break; - c = textreadc(t, p-1); - } - /* fast check for first char */ - if(startchar && nnl==0 && c!=startchar) - continue; - tl = list[flag]; - nl = list[flag^=1]; - nl->inst = nil; - ntl = nnl; - nnl = 0; - if(sel.r[0].q0<0 && (!wrapped || p>startp)){ - /* Add first instruction to this list */ - /* the minus is so the optimizations in addinst work */ - sempty.r[0].q0 = -p; - if(addinst(tl, bstartinst, &sempty)) - if(++ntl >= NLIST){ - Overflow: - warning(nil, "regexp list overflow\n"); - sel.r[0].q0 = -1; - goto Return; - } - } - /* Execute machine until this list is empty */ - for(tlp = tl; inst = tlp->inst; tlp++){ /* assignment = */ - Switchstmt: - switch(inst->type){ - default: /* regular character */ - if(inst->type == c){ - Addinst: - if(addinst(nl, inst->next, &tlp->se)) - if(++nnl >= NLIST) - goto Overflow; - } - break; - case LBRA: - if(inst->subid>=0) - tlp->se.r[inst->subid].q0 = p; - inst = inst->next; - goto Switchstmt; - case RBRA: - if(inst->subid >= 0) - tlp->se.r[inst->subid].q1 = p; - inst = inst->next; - goto Switchstmt; - case ANY: - if(c != '\n') - goto Addinst; - break; - case BOL: - if(c=='\n' || p==0){ - Step: - inst = inst->next; - goto Switchstmt; - } - break; - case EOL: - if(pfile->nc && textreadc(t, p)=='\n') - goto Step; - break; - case CCLASS: - if(c>0 && classmatch(inst->class, c, 0)) - goto Addinst; - break; - case NCCLASS: - if(c>0 && classmatch(inst->class, c, 1)) - goto Addinst; - break; - case OR: - /* evaluate right choice later */ - if(addinst(tl, inst->right, &tlp->se)) - if(++ntl >= NLIST) - goto Overflow; - /* efficiency: advance and re-evaluate */ - inst = inst->left; - goto Switchstmt; - case END: /* Match! */ - tlp->se.r[0].q0 = -tlp->se.r[0].q0; /* minus sign */ - tlp->se.r[0].q1 = p; - bnewmatch(&tlp->se); - break; - } - } - } - Return: - *rp = sel; - return sel.r[0].q0 >= 0; -} - -void -bnewmatch(Rangeset *sp) -{ - int i; - - if(sel.r[0].q0<0 || sp->r[0].q0>sel.r[0].q1 || (sp->r[0].q0==sel.r[0].q1 && sp->r[0].q1r[i].q1; - sel.r[i].q1 = sp->r[i].q0; - } -} diff --git a/rows.6 b/rows.6 deleted file mode 100644 index cb11f6c..0000000 Binary files a/rows.6 and /dev/null differ diff --git a/rows.c b/rows.c deleted file mode 100644 index d3d4817..0000000 --- a/rows.c +++ /dev/null @@ -1,736 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -void -rowinit(Row *row, Rectangle r) -{ - Rectangle r1; - Text *t; - - draw(screen, r, display->white, nil, ZP); - row->r = r; - row->col = nil; - row->ncol = 0; - r1 = r; - r1.max.y = r1.min.y + font->height; - t = &row->tag; - textinit(t, fileaddtext(nil, t), r1, rfget(FALSE, FALSE, FALSE, nil), tagcols); - t->what = Rowtag; - t->row = row; - t->w = nil; - t->col = nil; - r1.min.y = r1.max.y; - r1.max.y += Border; - draw(screen, r1, display->black, nil, ZP); - textinsert(t, 0, L"Newcol Kill Putall Dump Exit ", 29, TRUE); - textsetselect(t, t->file->nc, t->file->nc); -} - -Column* -rowadd(Row *row, Column *c, int x) -{ - Rectangle r, r1; - Column *d; - int i; - - d = nil; - r = row->r; - r.min.y = row->tag.r.max.y+Border; - if(xncol>0){ /*steal 40% of last column by default */ - d = row->col[row->ncol-1]; - x = d->r.min.x + 3*Dx(d->r)/5; - } - /* look for column we'll land on */ - for(i=0; incol; i++){ - d = row->col[i]; - if(x < d->r.max.x) - break; - } - if(row->ncol > 0){ - if(i < row->ncol) - i++; /* new column will go after d */ - r = d->r; - if(Dx(r) < 100) - return nil; - draw(screen, r, display->white, nil, ZP); - r1 = r; - r1.max.x = min(x, r.max.x-50); - if(Dx(r1) < 50) - r1.max.x = r1.min.x+50; - colresize(d, r1); - r1.min.x = r1.max.x; - r1.max.x = r1.min.x+Border; - draw(screen, r1, display->black, nil, ZP); - r.min.x = r1.max.x; - } - if(c == nil){ - c = emalloc(sizeof(Column)); - colinit(c, r); - incref(&reffont); - }else - colresize(c, r); - c->row = row; - c->tag.row = row; - row->col = realloc(row->col, (row->ncol+1)*sizeof(Column*)); - memmove(row->col+i+1, row->col+i, (row->ncol-i)*sizeof(Column*)); - row->col[i] = c; - row->ncol++; - clearmouse(); - return c; -} - -void -rowresize(Row *row, Rectangle r) -{ - int i, dx, odx; - Rectangle r1, r2; - Column *c; - - dx = Dx(r); - odx = Dx(row->r); - row->r = r; - r1 = r; - r1.max.y = r1.min.y + font->height; - textresize(&row->tag, r1, TRUE); - r1.min.y = r1.max.y; - r1.max.y += Border; - draw(screen, r1, display->black, nil, ZP); - r.min.y = r1.max.y; - r1 = r; - r1.max.x = r1.min.x; - for(i=0; incol; i++){ - c = row->col[i]; - r1.min.x = r1.max.x; - if(i == row->ncol-1) - r1.max.x = r.max.x; - else - r1.max.x = r1.min.x+Dx(c->r)*dx/odx; - if(i > 0){ - r2 = r1; - r2.max.x = r2.min.x+Border; - draw(screen, r2, display->black, nil, ZP); - r1.min.x = r2.max.x; - } - colresize(c, r1); - } -} - -void -rowdragcol(Row *row, Column *c, int) -{ - Rectangle r; - int i, b, x; - Point p, op; - Column *d; - - clearmouse(); - setcursor(mousectl, &boxcursor); - b = mouse->buttons; - op = mouse->xy; - while(mouse->buttons == b) - readmouse(mousectl); - setcursor(mousectl, nil); - if(mouse->buttons){ - while(mouse->buttons) - readmouse(mousectl); - return; - } - - for(i=0; incol; i++) - if(row->col[i] == c) - goto Found; - error("can't find column"); - - Found: - p = mouse->xy; - if((abs(p.x-op.x)<5 && abs(p.y-op.y)<5)) - return; - if((i>0 && p.xcol[i-1]->r.min.x) || (incol-1 && p.x>c->r.max.x)){ - /* shuffle */ - x = c->r.min.x; - rowclose(row, c, FALSE); - if(rowadd(row, c, p.x) == nil) /* whoops! */ - if(rowadd(row, c, x) == nil) /* WHOOPS! */ - if(rowadd(row, c, -1)==nil){ /* shit! */ - rowclose(row, c, TRUE); - return; - } - colmousebut(c); - return; - } - if(i == 0) - return; - d = row->col[i-1]; - if(p.x < d->r.min.x+80+Scrollwid) - p.x = d->r.min.x+80+Scrollwid; - if(p.x > c->r.max.x-80-Scrollwid) - p.x = c->r.max.x-80-Scrollwid; - r = d->r; - r.max.x = c->r.max.x; - draw(screen, r, display->white, nil, ZP); - r.max.x = p.x; - colresize(d, r); - r = c->r; - r.min.x = p.x; - r.max.x = r.min.x; - r.max.x += Border; - draw(screen, r, display->black, nil, ZP); - r.min.x = r.max.x; - r.max.x = c->r.max.x; - colresize(c, r); - colmousebut(c); -} - -void -rowclose(Row *row, Column *c, int dofree) -{ - Rectangle r; - int i; - - for(i=0; incol; i++) - if(row->col[i] == c) - goto Found; - error("can't find column"); - Found: - r = c->r; - if(dofree) - colcloseall(c); - memmove(row->col+i, row->col+i+1, (row->ncol-i)*sizeof(Column*)); - row->ncol--; - row->col = realloc(row->col, row->ncol*sizeof(Column*)); - if(row->ncol == 0){ - draw(screen, r, display->white, nil, ZP); - return; - } - if(i == row->ncol){ /* extend last column right */ - c = row->col[i-1]; - r.min.x = c->r.min.x; - r.max.x = row->r.max.x; - }else{ /* extend next window left */ - c = row->col[i]; - r.max.x = c->r.max.x; - } - draw(screen, r, display->white, nil, ZP); - colresize(c, r); -} - -Column* -rowwhichcol(Row *row, Point p) -{ - int i; - Column *c; - - for(i=0; incol; i++){ - c = row->col[i]; - if(ptinrect(p, c->r)) - return c; - } - return nil; -} - -Text* -rowwhich(Row *row, Point p) -{ - Column *c; - - if(ptinrect(p, row->tag.all)) - return &row->tag; - c = rowwhichcol(row, p); - if(c) - return colwhich(c, p); - return nil; -} - -Text* -rowtype(Row *row, Rune r, Point p) -{ - Window *w; - Text *t; - - clearmouse(); - qlock(row); - if(bartflag) - t = barttext; - else - t = rowwhich(row, p); - if(t!=nil && !(t->what==Tag && ptinrect(p, t->scrollr))){ - w = t->w; - if(w == nil) - texttype(t, r); - else{ - winlock(w, 'K'); - wintype(w, t, r); - winunlock(w); - } - } - qunlock(row); - return t; -} - -int -rowclean(Row *row) -{ - int clean; - int i; - - clean = TRUE; - for(i=0; incol; i++) - clean &= colclean(row->col[i]); - return clean; -} - -void -rowdump(Row *row, char *file) -{ - int i, j, fd, m, n, start, dumped; - uint q0, q1; - Biobuf *b; - char *buf, *a, *fontname; - Rune *r; - Column *c; - Window *w, *w1; - Text *t; - - if(row->ncol == 0) - return; - buf = fbufalloc(); - if(file == nil){ - if(home == nil){ - warning(nil, "can't find file for dump: $home not defined\n"); - goto Rescue; - } - sprint(buf, "%s/acme.dump", home); - file = buf; - } - fd = create(file, OWRITE, 0600); - if(fd < 0){ - warning(nil, "can't open %s: %r\n", file); - goto Rescue; - } - b = emalloc(sizeof(Biobuf)); - Binit(b, fd, OWRITE); - r = fbufalloc(); - Bprint(b, "%s\n", wdir); - Bprint(b, "%s\n", fontnames[0]); - Bprint(b, "%s\n", fontnames[1]); - for(i=0; incol; i++){ - c = row->col[i]; - Bprint(b, "%11d", 100*(c->r.min.x-row->r.min.x)/Dx(row->r)); - if(i == row->ncol-1) - Bputc(b, '\n'); - else - Bputc(b, ' '); - } - for(i=0; incol; i++){ - c = row->col[i]; - for(j=0; jnw; j++) - c->w[j]->body.file->dumpid = 0; - } - for(i=0; incol; i++){ - c = row->col[i]; - for(j=0; jnw; j++){ - w = c->w[j]; - wincommit(w, &w->tag); - t = &w->body; - /* windows owned by others get special treatment */ - if(w->nopen[QWevent] > 0) - if(w->dumpstr == nil) - continue; - /* zeroxes of external windows are tossed */ - if(t->file->ntext > 1) - for(n=0; nfile->ntext; n++){ - w1 = t->file->text[n]->w; - if(w == w1) - continue; - if(w1->nopen[QWevent]) - goto Continue2; - } - fontname = ""; - if(t->reffont->f != font) - fontname = t->reffont->f->name; - if(t->file->nname) - a = runetobyte(t->file->name, t->file->nname); - else - a = emalloc(1); - if(t->file->dumpid){ - dumped = FALSE; - Bprint(b, "x%11d %11d %11d %11d %11d %s\n", i, t->file->dumpid, - w->body.q0, w->body.q1, - 100*(w->r.min.y-c->r.min.y)/Dy(c->r), - fontname); - }else if(w->dumpstr){ - dumped = FALSE; - Bprint(b, "e%11d %11d %11d %11d %11d %s\n", i, t->file->dumpid, - 0, 0, - 100*(w->r.min.y-c->r.min.y)/Dy(c->r), - fontname); - }else if((w->dirty==FALSE && access(a, 0)==0) || w->isdir){ - dumped = FALSE; - t->file->dumpid = w->id; - Bprint(b, "f%11d %11d %11d %11d %11d %s\n", i, w->id, - w->body.q0, w->body.q1, - 100*(w->r.min.y-c->r.min.y)/Dy(c->r), - fontname); - }else{ - dumped = TRUE; - t->file->dumpid = w->id; - Bprint(b, "F%11d %11d %11d %11d %11d %11d %s\n", i, j, - w->body.q0, w->body.q1, - 100*(w->r.min.y-c->r.min.y)/Dy(c->r), - w->body.file->nc, fontname); - } - free(a); - winctlprint(w, buf, 0); - Bwrite(b, buf, strlen(buf)); - m = min(RBUFSIZE, w->tag.file->nc); - bufread(w->tag.file, 0, r, m); - n = 0; - while(nfile->nc; - while(q0 < q1){ - n = q1 - q0; - if(n > BUFSIZE/UTFmax) - n = BUFSIZE/UTFmax; - bufread(t->file, q0, r, n); - Bprint(b, "%.*S", n, r); - q0 += n; - } - } - if(w->dumpstr){ - if(w->dumpdir) - Bprint(b, "%s\n%s\n", w->dumpdir, w->dumpstr); - else - Bprint(b, "\n%s\n", w->dumpstr); - } - Continue2:; - } - } - Bterm(b); - close(fd); - free(b); - fbuffree(r); - - Rescue: - fbuffree(buf); -} - -static -char* -rdline(Biobuf *b, int *linep) -{ - char *l; - - l = Brdline(b, '\n'); - if(l) - (*linep)++; - return l; -} - -/* - * Get font names from load file so we don't load fonts we won't use - */ -void -rowloadfonts(char *file) -{ - int i; - Biobuf *b; - char *l; - - b = Bopen(file, OREAD); - if(b == nil) - return; - /* current directory */ - l = Brdline(b, '\n'); - if(l == nil) - goto Return; - /* global fonts */ - for(i=0; i<2; i++){ - l = Brdline(b, '\n'); - if(l == nil) - goto Return; - l[Blinelen(b)-1] = 0; - if(*l && strcmp(l, fontnames[i])!=0){ - free(fontnames[i]); - fontnames[i] = estrdup(l); - } - } - Return: - Bterm(b); -} - -int -rowload(Row *row, char *file, int initing) -{ - int i, j, line, percent, y, nr, nfontr, n, ns, ndumped, dumpid, x, fd; - Biobuf *b, *bout; - char *buf, *l, *t, *fontname; - Rune *r, rune, *fontr; - Column *c, *c1, *c2; - uint q0, q1; - Rectangle r1, r2; - Window *w; - - buf = fbufalloc(); - if(file == nil){ - if(home == nil){ - warning(nil, "can't find file for load: $home not defined\n"); - goto Rescue1; - } - sprint(buf, "%s/acme.dump", home); - file = buf; - } - b = Bopen(file, OREAD); - if(b == nil){ - warning(nil, "can't open load file %s: %r\n", file); - goto Rescue1; - } - /* current directory */ - line = 0; - l = rdline(b, &line); - if(l == nil) - goto Rescue2; - l[Blinelen(b)-1] = 0; - if(chdir(l) < 0){ - warning(nil, "can't chdir %s\n", l); - goto Rescue2; - } - /* global fonts */ - for(i=0; i<2; i++){ - l = rdline(b, &line); - if(l == nil) - goto Rescue2; - l[Blinelen(b)-1] = 0; - if(*l && strcmp(l, fontnames[i])!=0) - rfget(i, TRUE, i==0 && initing, l); - } - if(initing && row->ncol==0) - rowinit(row, screen->clipr); - l = rdline(b, &line); - if(l == nil) - goto Rescue2; - j = Blinelen(b)/12; - if(j<=0 || j>10) - goto Rescue2; - for(i=0; i=100) - goto Rescue2; - x = row->r.min.x+percent*Dx(row->r)/100; - if(i < row->ncol){ - if(i == 0) - continue; - c1 = row->col[i-1]; - c2 = row->col[i]; - r1 = c1->r; - r2 = c2->r; - r1.max.x = x; - r2.min.x = x+Border; - if(Dx(r1) < 50 || Dx(r2) < 50) - continue; - draw(screen, Rpt(r1.min, r2.max), display->white, nil, ZP); - colresize(c1, r1); - colresize(c2, r2); - r2.min.x = x; - r2.max.x = x+Border; - draw(screen, r2, display->black, nil, ZP); - } - if(i >= row->ncol) - rowadd(row, nil, x); - } - for(;;){ - l = rdline(b, &line); - if(l == nil) - break; - dumpid = 0; - switch(l[0]){ - case 'e': - if(Blinelen(b) < 1+5*12+1) - goto Rescue2; - l = rdline(b, &line); /* ctl line; ignored */ - if(l == nil) - goto Rescue2; - l = rdline(b, &line); /* directory */ - if(l == nil) - goto Rescue2; - l[Blinelen(b)-1] = 0; - if(*l == '\0'){ - if(home == nil) - r = bytetorune("./", &nr); - else{ - t = emalloc(strlen(home)+1+1); - sprint(t, "%s/", home); - r = bytetorune(t, &nr); - free(t); - } - }else - r = bytetorune(l, &nr); - l = rdline(b, &line); /* command */ - if(l == nil) - goto Rescue2; - t = emalloc(Blinelen(b)+1); - memmove(t, l, Blinelen(b)); - run(nil, t, r, nr, TRUE, nil, nil, FALSE); - /* r is freed in run() */ - continue; - case 'f': - if(Blinelen(b) < 1+5*12+1) - goto Rescue2; - fontname = l+1+5*12; - ndumped = -1; - break; - case 'F': - if(Blinelen(b) < 1+6*12+1) - goto Rescue2; - fontname = l+1+6*12; - ndumped = atoi(l+1+5*12+1); - break; - case 'x': - if(Blinelen(b) < 1+5*12+1) - goto Rescue2; - fontname = l+1+5*12; - ndumped = -1; - dumpid = atoi(l+1+1*12); - break; - default: - goto Rescue2; - } - l[Blinelen(b)-1] = 0; - fontr = nil; - nfontr = 0; - if(*fontname) - fontr = bytetorune(fontname, &nfontr); - i = atoi(l+1+0*12); - j = atoi(l+1+1*12); - q0 = atoi(l+1+2*12); - q1 = atoi(l+1+3*12); - percent = atoi(l+1+4*12); - if(i<0 || i>10) - goto Rescue2; - if(i > row->ncol) - i = row->ncol; - c = row->col[i]; - y = c->r.min.y+(percent*Dy(c->r))/100; - if(yr.min.y || y>=c->r.max.y) - y = -1; - if(dumpid == 0) - w = coladd(c, nil, nil, y); - else - w = coladd(c, nil, lookid(dumpid, TRUE), y); - if(w == nil) - continue; - w->dumpid = j; - l = rdline(b, &line); - if(l == nil) - goto Rescue2; - l[Blinelen(b)-1] = 0; - /* convert 0xff in multiline tag back to \n */ - for(i=0; l[i]!=0; i++) - if((uchar)l[i] == 0xff) - l[i] = '\n'; - r = bytetorune(l+5*12, &nr); - ns = -1; - for(n=0; ntag, w->tag.file->nc, r+n+1, nr-(n+1), TRUE); - if(ndumped >= 0){ - /* simplest thing is to put it in a file and load that */ - sprint(buf, "/tmp/d%d.%.4sacme", getpid(), user); - fd = create(buf, OWRITE|ORCLOSE, 0600); - if(fd < 0){ - free(r); - warning(nil, "can't create temp file: %r\n"); - goto Rescue2; - } - bout = emalloc(sizeof(Biobuf)); - Binit(bout, fd, OWRITE); - for(n=0; nbody, 0, buf, 1); - close(fd); - w->body.file->mod = TRUE; - for(n=0; nbody.file->ntext; n++) - w->body.file->text[n]->w->dirty = TRUE; - winsettag(w); - }else if(dumpid==0 && r[ns+1]!='+' && r[ns+1]!='-') - get(&w->body, nil, nil, FALSE, XXX, nil, 0); - if(fontr){ - fontx(&w->body, nil, nil, 0, 0, fontr, nfontr); - free(fontr); - } - free(r); - if(q0>w->body.file->nc || q1>w->body.file->nc || q0>q1) - q0 = q1 = 0; - textshow(&w->body, q0, q1, 1); - w->maxlines = min(w->body.nlines, max(w->maxlines, w->body.maxlines)); - xfidlog(w, "new"); - } - Bterm(b); - fbuffree(buf); - return TRUE; - -Rescue2: - warning(nil, "bad load file %s:%d\n", file, line); - Bterm(b); -Rescue1: - fbuffree(buf); - return FALSE; -} - -void -allwindows(void (*f)(Window*, void*), void *arg) -{ - int i, j; - Column *c; - - for(i=0; inw; j++) - (*f)(c->w[j], arg); - } -} diff --git a/scrl.6 b/scrl.6 deleted file mode 100644 index ef913af..0000000 Binary files a/scrl.6 and /dev/null differ diff --git a/scrl.c b/scrl.c deleted file mode 100644 index 804ea35..0000000 --- a/scrl.c +++ /dev/null @@ -1,157 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -static Image *scrtmp; - -static -Rectangle -scrpos(Rectangle r, uint p0, uint p1, uint tot) -{ - Rectangle q; - int h; - - q = r; - h = q.max.y-q.min.y; - if(tot == 0) - return q; - if(tot > 1024*1024){ - tot>>=10; - p0>>=10; - p1>>=10; - } - if(p0 > 0) - q.min.y += h*p0/tot; - if(p1 < tot) - q.max.y -= h*(tot-p1)/tot; - if(q.max.y < q.min.y+2){ - if(q.min.y+2 <= r.max.y) - q.max.y = q.min.y+2; - else - q.min.y = q.max.y-2; - } - return q; -} - -void -scrlresize(void) -{ - freeimage(scrtmp); - scrtmp = allocimage(display, Rect(0, 0, 32, 3*Dy(screen->r)), screen->chan, 0, DNofill); - if(scrtmp == nil) - error("scroll alloc"); -} - -void -textscrdraw(Text *t) -{ - Rectangle r, r1, r2; - Image *b; - - if(t->w==nil || t!=&t->w->body) - return; - if(scrtmp == nil) - scrlresize(); - r = t->scrollr; - b = scrtmp; - r1 = r; - r1.min.x = 0; - r1.max.x = Dx(r); - r2 = scrpos(r1, t->org, t->org+t->nchars, t->file->nc); - if(!eqrect(r2, t->lastsr)){ - t->lastsr = r2; - /* move r1, r2 to (0,0) to avoid clipping */ - r2 = rectsubpt(r2, r1.min); - r1 = rectsubpt(r1, r1.min); - draw(b, r1, t->cols[BORD], nil, ZP); - r2.max.x++; - draw(b, r2, t->cols[TEXT], nil, ZP); - r2.min.x = r2.max.x-1; - draw(b, r2, t->cols[BORD], nil, ZP); - draw(t->b, r, b, nil, Pt(0, r1.min.y)); -/*flushimage(display, 1);/*BUG?*/ - } -} - -void -scrsleep(uint dt) -{ - Timer *timer; - static Alt alts[3]; - - timer = timerstart(dt); - alts[0].c = timer->c; - alts[0].v = nil; - alts[0].op = CHANRCV; - alts[1].c = mousectl->c; - alts[1].v = &mousectl->Mouse; - alts[1].op = CHANRCV; - alts[2].op = CHANEND; - for(;;) - switch(alt(alts)){ - case 0: - timerstop(timer); - return; - case 1: - timercancel(timer); - return; - } -} - -void -textscroll(Text *t, int but) -{ - uint p0, oldp0; - Rectangle s; - int y, my, h, first; - - s = insetrect(t->scrollr, 1); - h = s.max.y-s.min.y; - oldp0 = ~0; - first = TRUE; - do{ - flushimage(display, 1); - my = mouse->xy.y; - if(my < s.min.y) - my = s.min.y; - if(my >= s.max.y) - my = s.max.y; - if(but == 2){ - y = my; - p0 = (vlong)t->file->nc*(y-s.min.y)/h; - if(p0 >= t->q1) - p0 = textbacknl(t, p0, 2); - if(oldp0 != p0) - textsetorigin(t, p0, FALSE); - oldp0 = p0; - readmouse(mousectl); - continue; - } - if(but == 1) - p0 = textbacknl(t, t->org, (my-s.min.y)/t->font->height); - else - p0 = t->org+frcharofpt(t, Pt(s.max.x, my)); - if(oldp0 != p0) - textsetorigin(t, p0, TRUE); - oldp0 = p0; - /* debounce */ - if(first){ - flushimage(display, 1); - sleep(200); - nbrecv(mousectl->c, &mousectl->Mouse); - first = FALSE; - } - scrsleep(80); - }while(mouse->buttons & (1<<(but-1))); - while(mouse->buttons) - readmouse(mousectl); -} diff --git a/text.6 b/text.6 deleted file mode 100644 index a7c2b51..0000000 Binary files a/text.6 and /dev/null differ diff --git a/text.c b/text.c deleted file mode 100644 index 75d7a3a..0000000 --- a/text.c +++ /dev/null @@ -1,1484 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -Image *tagcols[NCOL]; -Image *textcols[NCOL]; - -enum{ - TABDIR = 3 /* width of tabs in directory windows */ -}; - -void -textinit(Text *t, File *f, Rectangle r, Reffont *rf, Image *cols[NCOL]) -{ - t->file = f; - t->all = r; - t->scrollr = r; - t->scrollr.max.x = r.min.x+Scrollwid; - t->lastsr = nullrect; - r.min.x += Scrollwid+Scrollgap; - t->eq0 = ~0; - t->ncache = 0; - t->reffont = rf; - t->tabstop = maxtab; - memmove(t->Frame.cols, cols, sizeof t->Frame.cols); - textredraw(t, r, rf->f, screen, -1); -} - -void -textredraw(Text *t, Rectangle r, Font *f, Image *b, int odx) -{ - int maxt; - Rectangle rr; - - frinit(t, r, f, b, t->Frame.cols); - rr = t->r; - rr.min.x -= Scrollwid+Scrollgap; /* back fill to scroll bar */ - draw(t->b, rr, t->cols[BACK], nil, ZP); - /* use no wider than 3-space tabs in a directory */ - maxt = maxtab; - if(t->what == Body){ - if(t->w->isdir) - maxt = min(TABDIR, maxtab); - else - maxt = t->tabstop; - } - t->maxtab = maxt*stringwidth(f, "0"); - if(t->what==Body && t->w->isdir && odx!=Dx(t->all)){ - if(t->maxlines > 0){ - textreset(t); - textcolumnate(t, t->w->dlp, t->w->ndl); - textshow(t, 0, 0, 1); - } - }else{ - textfill(t); - textsetselect(t, t->q0, t->q1); - } -} - -int -textresize(Text *t, Rectangle r, int fillfringe) -{ - int odx; - - if(Dy(r) <= 0) - r.max.y = r.min.y; - else if(!fillfringe) - r.max.y -= Dy(r)%t->font->height; - odx = Dx(t->all); - t->all = r; - t->scrollr = r; - t->scrollr.max.x = r.min.x+Scrollwid; - t->lastsr = nullrect; - r.min.x += Scrollwid+Scrollgap; - frclear(t, 0); - textredraw(t, r, t->font, t->b, odx); - if(fillfringe && t->r.max.y < t->all.max.y){ - /* draw background in bottom fringe of text window */ - r.min.x -= Scrollgap; - r.min.y = t->r.max.y; - r.max.y = t->all.max.y; - draw(screen, r, t->cols[BACK], nil, ZP); - } - return t->all.max.y; -} - -void -textclose(Text *t) -{ - free(t->cache); - frclear(t, 1); - filedeltext(t->file, t); - t->file = nil; - rfclose(t->reffont); - if(argtext == t) - argtext = nil; - if(typetext == t) - typetext = nil; - if(seltext == t) - seltext = nil; - if(mousetext == t) - mousetext = nil; - if(barttext == t) - barttext = nil; -} - -int -dircmp(void *a, void *b) -{ - Dirlist *da, *db; - int i, n; - - da = *(Dirlist**)a; - db = *(Dirlist**)b; - n = min(da->nr, db->nr); - i = memcmp(da->r, db->r, n*sizeof(Rune)); - if(i) - return i; - return da->nr - db->nr; -} - -void -textcolumnate(Text *t, Dirlist **dlp, int ndl) -{ - int i, j, w, colw, mint, maxt, ncol, nrow; - Dirlist *dl; - uint q1; - - if(t->file->ntext > 1) - return; - mint = stringwidth(t->font, "0"); - /* go for narrower tabs if set more than 3 wide */ - t->maxtab = min(maxtab, TABDIR)*mint; - maxt = t->maxtab; - colw = 0; - for(i=0; iwid; - if(maxt-w%maxt < mint || w%maxt==0) - w += mint; - if(w % maxt) - w += maxt-(w%maxt); - if(w > colw) - colw = w; - } - if(colw == 0) - ncol = 1; - else - ncol = max(1, Dx(t->r)/colw); - nrow = (ndl+ncol-1)/ncol; - - q1 = 0; - for(i=0; ifile, q1, dl->r, dl->nr); - q1 += dl->nr; - if(j+nrow >= ndl) - break; - w = dl->wid; - if(maxt-w%maxt < mint){ - fileinsert(t->file, q1, L"\t", 1); - q1++; - w += mint; - } - do{ - fileinsert(t->file, q1, L"\t", 1); - q1++; - w += maxt-(w%maxt); - }while(w < colw); - } - fileinsert(t->file, q1, L"\n", 1); - q1++; - } -} - -uint -textload(Text *t, uint q0, char *file, int setqid) -{ - Rune *rp; - Dirlist *dl, **dlp; - int fd, i, j, n, ndl, nulls; - uint q, q1; - Dir *d, *dbuf; - char *tmp; - Text *u; - - if(t->ncache!=0 || t->file->nc || t->w==nil || t!=&t->w->body) - error("text.load"); - if(t->w->isdir && t->file->nname==0){ - warning(nil, "empty directory name\n"); - return 0; - } - fd = open(file, OREAD); - if(fd < 0){ - warning(nil, "can't open %s: %r\n", file); - return 0; - } - d = dirfstat(fd); - if(d == nil){ - warning(nil, "can't fstat %s: %r\n", file); - goto Rescue; - } - nulls = FALSE; - if(d->qid.type & QTDIR){ - /* this is checked in get() but it's possible the file changed underfoot */ - if(t->file->ntext > 1){ - warning(nil, "%s is a directory; can't read with multiple windows on it\n", file); - goto Rescue; - } - t->w->isdir = TRUE; - t->w->filemenu = FALSE; - if(t->file->nname > 0 && t->file->name[t->file->nname-1] != '/'){ - rp = runemalloc(t->file->nname+1); - runemove(rp, t->file->name, t->file->nname); - rp[t->file->nname] = '/'; - winsetname(t->w, rp, t->file->nname+1); - free(rp); - } - dlp = nil; - ndl = 0; - dbuf = nil; - while((n=dirread(fd, &dbuf)) > 0){ - for(i=0; ir = bytetorune(tmp, &dl->nr); - dl->wid = stringwidth(t->font, tmp); - free(tmp); - ndl++; - dlp = realloc(dlp, ndl*sizeof(Dirlist*)); - dlp[ndl-1] = dl; - } - free(dbuf); - } - qsort(dlp, ndl, sizeof(Dirlist*), dircmp); - t->w->dlp = dlp; - t->w->ndl = ndl; - textcolumnate(t, dlp, ndl); - q1 = t->file->nc; - }else{ - t->w->isdir = FALSE; - t->w->filemenu = TRUE; - q1 = q0 + fileload(t->file, q0, fd, &nulls); - } - if(setqid){ - t->file->dev = d->dev; - t->file->mtime = d->mtime; - t->file->qidpath = d->qid.path; - } - close(fd); - rp = fbufalloc(); - for(q=q0; q RBUFSIZE) - n = RBUFSIZE; - bufread(t->file, q, rp, n); - if(q < t->org) - t->org += n; - else if(q <= t->org+t->nchars) - frinsert(t, rp, rp+n, q-t->org); - if(t->lastlinefull) - break; - } - fbuffree(rp); - for(i=0; ifile->ntext; i++){ - u = t->file->text[i]; - if(u != t){ - if(u->org > u->file->nc) /* will be 0 because of reset(), but safety first */ - u->org = 0; - textresize(u, u->all, TRUE); - textbacknl(u, u->org, 0); /* go to beginning of line */ - } - textsetselect(u, q0, q0); - } - if(nulls) - warning(nil, "%s: NUL bytes elided\n", file); - free(d); - return q1-q0; - - Rescue: - close(fd); - return 0; -} - -uint -textbsinsert(Text *t, uint q0, Rune *r, uint n, int tofile, int *nrp) -{ - Rune *bp, *tp, *up; - int i, initial; - - if(t->what == Tag){ /* can't happen but safety first: mustn't backspace over file name */ - Err: - textinsert(t, q0, r, n, tofile); - *nrp = n; - return q0; - } - bp = r; - for(i=0; i q0) - initial = q0; - q0 -= initial; - textdelete(t, q0, q0+initial, tofile); - } - n = up-tp; - textinsert(t, q0, tp, n, tofile); - free(tp); - *nrp = n; - return q0; - } - goto Err; -} - -void -textinsert(Text *t, uint q0, Rune *r, uint n, int tofile) -{ - int c, i; - Text *u; - - if(tofile && t->ncache != 0) - error("text.insert"); - if(n == 0) - return; - if(tofile){ - fileinsert(t->file, q0, r, n); - if(t->what == Body){ - t->w->dirty = TRUE; - t->w->utflastqid = -1; - } - if(t->file->ntext > 1) - for(i=0; ifile->ntext; i++){ - u = t->file->text[i]; - if(u != t){ - u->w->dirty = TRUE; /* always a body */ - textinsert(u, q0, r, n, FALSE); - textsetselect(u, u->q0, u->q1); - textscrdraw(u); - } - } - - } - if(q0 < t->q1) - t->q1 += n; - if(q0 < t->q0) - t->q0 += n; - if(q0 < t->org) - t->org += n; - else if(q0 <= t->org+t->nchars) - frinsert(t, r, r+n, q0-t->org); - if(t->w){ - c = 'i'; - if(t->what == Body) - c = 'I'; - if(n <= EVENTSIZE) - winevent(t->w, "%c%d %d 0 %d %.*S\n", c, q0, q0+n, n, n, r); - else - winevent(t->w, "%c%d %d 0 0 \n", c, q0, q0+n, n); - } -} - -void -typecommit(Text *t) -{ - if(t->w != nil) - wincommit(t->w, t); - else - textcommit(t, TRUE); -} - -void -textfill(Text *t) -{ - Rune *rp; - int i, n, m, nl; - - if(t->lastlinefull || t->nofill) - return; - if(t->ncache > 0) - typecommit(t); - rp = fbufalloc(); - do{ - n = t->file->nc-(t->org+t->nchars); - if(n == 0) - break; - if(n > 2000) /* educated guess at reasonable amount */ - n = 2000; - bufread(t->file, t->org+t->nchars, rp, n); - /* - * it's expensive to frinsert more than we need, so - * count newlines. - */ - nl = t->maxlines-t->nlines; - m = 0; - for(i=0; i= nl) - break; - } - } - frinsert(t, rp, rp+i, t->nchars); - }while(t->lastlinefull == FALSE); - fbuffree(rp); -} - -void -textdelete(Text *t, uint q0, uint q1, int tofile) -{ - uint n, p0, p1; - int i, c; - Text *u; - - if(tofile && t->ncache != 0) - error("text.delete"); - n = q1-q0; - if(n == 0) - return; - if(tofile){ - filedelete(t->file, q0, q1); - if(t->what == Body){ - t->w->dirty = TRUE; - t->w->utflastqid = -1; - } - if(t->file->ntext > 1) - for(i=0; ifile->ntext; i++){ - u = t->file->text[i]; - if(u != t){ - u->w->dirty = TRUE; /* always a body */ - textdelete(u, q0, q1, FALSE); - textsetselect(u, u->q0, u->q1); - textscrdraw(u); - } - } - } - if(q0 < t->q0) - t->q0 -= min(n, t->q0-q0); - if(q0 < t->q1) - t->q1 -= min(n, t->q1-q0); - if(q1 <= t->org) - t->org -= n; - else if(q0 < t->org+t->nchars){ - p1 = q1 - t->org; - if(p1 > t->nchars) - p1 = t->nchars; - if(q0 < t->org){ - t->org = q0; - p0 = 0; - }else - p0 = q0 - t->org; - frdelete(t, p0, p1); - textfill(t); - } - if(t->w){ - c = 'd'; - if(t->what == Body) - c = 'D'; - winevent(t->w, "%c%d %d 0 0 \n", c, q0, q1); - } -} - -void -textconstrain(Text *t, uint q0, uint q1, uint *p0, uint *p1) -{ - *p0 = min(q0, t->file->nc); - *p1 = min(q1, t->file->nc); -} - -Rune -textreadc(Text *t, uint q) -{ - Rune r; - - if(t->cq0<=q && qcq0+t->ncache) - r = t->cache[q-t->cq0]; - else - bufread(t->file, q, &r, 1); - return r; -} - -static int -spacesindentbswidth(Text *t) -{ - uint q, col; - Rune r; - - col = textbswidth(t, 0x15); - q = t->q0; - while(q > 0){ - r = textreadc(t, q-1); - if(r != ' ') - break; - q--; - if(--col % t->tabstop == 0) - break; - } - if(t->q0 == q) - return 1; - return t->q0-q; -} - -int -textbswidth(Text *t, Rune c) -{ - uint q, eq; - Rune r; - int skipping; - - /* there is known to be at least one character to erase */ - if(c == 0x08){ /* ^H: erase character */ - if(t->what == Body && t->w->indent[SPACESINDENT]) - return spacesindentbswidth(t); - return 1; - } - q = t->q0; - skipping = TRUE; - while(q > 0){ - r = textreadc(t, q-1); - if(r == '\n'){ /* eat at most one more character */ - if(q == t->q0) /* eat the newline */ - --q; - break; - } - if(c == 0x17){ - eq = isalnum(r); - if(eq && skipping) /* found one; stop skipping */ - skipping = FALSE; - else if(!eq && !skipping) - break; - } - --q; - } - return t->q0-q; -} - -int -textfilewidth(Text *t, uint q0, int oneelement) -{ - uint q; - Rune r; - - q = q0; - while(q > 0){ - r = textreadc(t, q-1); - if(r <= ' ') - break; - if(oneelement && r=='/') - break; - --q; - } - return q0-q; -} - -Rune* -textcomplete(Text *t) -{ - int i, nstr, npath; - uint q; - Rune tmp[200]; - Rune *str, *path; - Rune *rp; - Completion *c; - char *s, *dirs; - Runestr dir; - - /* control-f: filename completion; works back to white space or / */ - if(t->q0file->nc && textreadc(t, t->q0)>' ') /* must be at end of word */ - return nil; - nstr = textfilewidth(t, t->q0, TRUE); - str = runemalloc(nstr); - npath = textfilewidth(t, t->q0-nstr, FALSE); - path = runemalloc(npath); - - c = nil; - rp = nil; - dirs = nil; - - q = t->q0-nstr; - for(i=0; iq0-nstr-npath; - for(i=0; i0 && path[0]=='/') - dir = (Runestr){path, npath}; - else{ - dir = dirname(t, nil, 0); - if(dir.nr + 1 + npath > nelem(tmp)){ - free(dir.r); - goto Return; - } - if(dir.nr == 0){ - dir.nr = 1; - dir.r = runestrdup(L"."); - } - runemove(tmp, dir.r, dir.nr); - tmp[dir.nr] = '/'; - runemove(tmp+dir.nr+1, path, npath); - free(dir.r); - dir.r = tmp; - dir.nr += 1+npath; - dir = cleanrname(dir); - } - - s = smprint("%.*S", nstr, str); - dirs = smprint("%.*S", dir.nr, dir.r); - c = complete(dirs, s); - free(s); - if(c == nil){ - warning(nil, "error attempting completion: %r\n"); - goto Return; - } - - if(!c->advance){ - warning(nil, "%.*S%s%.*S*%s\n", - dir.nr, dir.r, - dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "", - nstr, str, - c->nmatch? "" : ": no matches in:"); - for(i=0; infile; i++) - warning(nil, " %s\n", c->filename[i]); - } - - if(c->advance) - rp = runesmprint("%s", c->string); - else - rp = nil; - Return: - freecompletion(c); - free(dirs); - free(str); - free(path); - return rp; -} - -void -texttype(Text *t, Rune r) -{ - uint q0, q1; - int nnb, nb, n, i; - int nr; - Rune rr; - Rune *rp; - Text *u; - - nr = 1; - rp = &r; - switch(r){ - case Kleft: - typecommit(t); - if(t->q0 > 0) - textshow(t, t->q0-1, t->q0-1, TRUE); - return; - case Kright: - typecommit(t); - if(t->q1 < t->file->nc) - textshow(t, t->q1+1, t->q1+1, TRUE); - return; - case Kdown: - n = t->maxlines/3; - goto case_Down; - case Kscrollonedown: - n = mousescrollsize(t->maxlines); - if(n <= 0) - n = 1; - goto case_Down; - case Kpgdown: - n = 2*t->maxlines/3; - case_Down: - q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height)); - if(t->what == Body) - textsetorigin(t, q0, TRUE); - return; - case Kup: - n = t->maxlines/3; - goto case_Up; - case Kscrolloneup: - n = mousescrollsize(t->maxlines); - goto case_Up; - case Kpgup: - n = 2*t->maxlines/3; - case_Up: - q0 = textbacknl(t, t->org, n); - if(t->what == Body) - textsetorigin(t, q0, TRUE); - return; - case Khome: - typecommit(t); - textshow(t, 0, 0, FALSE); - return; - case Kend: - typecommit(t); - textshow(t, t->file->nc, t->file->nc, FALSE); - return; - case 0x01: /* ^A: beginning of line */ - typecommit(t); - /* go to where ^U would erase, if not already at BOL */ - nnb = 0; - if(t->q0>0 && textreadc(t, t->q0-1)!='\n') - nnb = textbswidth(t, 0x15); - textshow(t, t->q0-nnb, t->q0-nnb, TRUE); - return; - case 0x05: /* ^E: end of line */ - typecommit(t); - q0 = t->q0; - while(q0file->nc && textreadc(t, q0)!='\n') - q0++; - textshow(t, q0, q0, TRUE); - return; - } - if(t->what == Body){ - seq++; - filemark(t->file); - } - if(t->q1 > t->q0){ - if(t->ncache != 0) - error("text.type"); - cut(t, t, nil, TRUE, TRUE, nil, 0); - t->eq0 = ~0; - } - textshow(t, t->q0, t->q0, 1); - switch(r){ - case 0x06: - case Kins: - rp = textcomplete(t); - if(rp == nil) - return; - nr = runestrlen(rp); - break; /* fall through to normal insertion case */ - case 0x1B: - if(t->eq0 != ~0) - textsetselect(t, t->eq0, t->q0); - if(t->ncache > 0) - typecommit(t); - return; - case 0x08: /* ^H: erase character */ - case 0x15: /* ^U: erase line */ - case 0x17: /* ^W: erase word */ - if(t->q0 == 0) /* nothing to erase */ - return; - nnb = textbswidth(t, r); - q1 = t->q0; - q0 = q1-nnb; - /* if selection is at beginning of window, avoid deleting invisible text */ - if(q0 < t->org){ - q0 = t->org; - nnb = q1-q0; - } - if(nnb <= 0) - return; - for(i=0; ifile->ntext; i++){ - u = t->file->text[i]; - u->nofill = TRUE; - nb = nnb; - n = u->ncache; - if(n > 0){ - if(q1 != u->cq0+n) - error("text.type backspace"); - if(n > nb) - n = nb; - u->ncache -= n; - textdelete(u, q1-n, q1, FALSE); - nb -= n; - } - if(u->eq0==q1 || u->eq0==~0) - u->eq0 = q0; - if(nb && u==t) - textdelete(u, q0, q0+nb, TRUE); - if(u != t) - textsetselect(u, u->q0, u->q1); - else - textsetselect(t, q0, q0); - u->nofill = FALSE; - } - for(i=0; ifile->ntext; i++) - textfill(t->file->text[i]); - return; - case '\t': - if(t->what == Body && t->w->indent[SPACESINDENT]){ - nnb = textbswidth(t, 0x15); - if(nnb == 1 && textreadc(t, t->q0-1) == '\n') - nnb = 0; - nnb = t->tabstop - nnb % t->tabstop; - rp = runemalloc(nnb); - for(nr = 0; nr < nnb; nr++) - rp[nr] = ' '; - } - break; - case '\n': - if(t->what == Body && t->w->indent[AUTOINDENT]){ - /* find beginning of previous line using backspace code */ - nnb = textbswidth(t, 0x15); /* ^U case */ - rp = runemalloc(nnb + 1); - nr = 0; - rp[nr++] = r; - for(i=0; iq0-nnb+i); - if(rr != ' ' && rr != '\t') - break; - rp[nr++] = rr; - } - } - break; /* fall through to normal code */ - } - /* otherwise ordinary character; just insert, typically in caches of all texts */ - for(i=0; ifile->ntext; i++){ - u = t->file->text[i]; - if(u->eq0 == ~0) - u->eq0 = t->q0; - if(u->ncache == 0) - u->cq0 = t->q0; - else if(t->q0 != u->cq0+u->ncache) - error("text.type cq1"); - textinsert(u, t->q0, rp, nr, FALSE); - if(u != t) - textsetselect(u, u->q0, u->q1); - if(u->ncache+nr > u->ncachealloc){ - u->ncachealloc += 10 + nr; - u->cache = runerealloc(u->cache, u->ncachealloc); - } - runemove(u->cache+u->ncache, rp, nr); - u->ncache += nr; - } - if(rp != &r) - free(rp); - textsetselect(t, t->q0+nr, t->q0+nr); - if(r=='\n' && t->w!=nil) - wincommit(t->w, t); -} - -void -textcommit(Text *t, int tofile) -{ - if(t->ncache == 0) - return; - if(tofile) - fileinsert(t->file, t->cq0, t->cache, t->ncache); - if(t->what == Body){ - t->w->dirty = TRUE; - t->w->utflastqid = -1; - } - t->ncache = 0; -} - -static Text *clicktext; -static uint clickmsec; -static int clickcount; -static Point clickpt; -static Text *selecttext; -static uint selectq; - -/* - * called from frame library - */ -void -framescroll(Frame *f, int dl) -{ - if(f != &selecttext->Frame) - error("frameselect not right frame"); - textframescroll(selecttext, dl); -} - -void -textframescroll(Text *t, int dl) -{ - uint q0; - - if(dl == 0){ - scrsleep(100); - return; - } - if(dl < 0){ - q0 = textbacknl(t, t->org, -dl); - if(selectq > t->org+t->p0) - textsetselect(t, t->org+t->p0, selectq); - else - textsetselect(t, selectq, t->org+t->p0); - }else{ - if(t->org+t->nchars == t->file->nc) - return; - q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height)); - if(selectq > t->org+t->p1) - textsetselect(t, t->org+t->p1, selectq); - else - textsetselect(t, selectq, t->org+t->p1); - } - textsetorigin(t, q0, TRUE); - flushimage(display, 1); -} - - -void -textselect(Text *t) -{ - uint q0, q1; - int b, x, y, dx, dy; - int state; - - selecttext = t; - /* - * To have double-clicking and chording, we double-click - * immediately if it might make sense. - */ - b = mouse->buttons; - q0 = t->q0; - q1 = t->q1; - dx = abs(clickpt.x - mouse->xy.x); - dy = abs(clickpt.y - mouse->xy.y); - clickpt = mouse->xy; - selectq = t->org+frcharofpt(t, mouse->xy); - clickcount++; - if(mouse->msec-clickmsec >= 500 || selecttext != t || clickcount > 3 || dx > 3 || dy > 3) - clickcount = 0; - if(clickcount >= 1 && selecttext==t && mouse->msec-clickmsec < 500){ - textstretchsel(t, &q0, &q1, clickcount); - textsetselect(t, q0, q1); - flushimage(display, 1); - x = mouse->xy.x; - y = mouse->xy.y; - /* stay here until something interesting happens */ - while(1){ - readmouse(mousectl); - dx = abs(mouse->xy.x - x); - dy = abs(mouse->xy.y - y); - if(mouse->buttons != b || dx >= 3 || dy >= 3) - break; - clickcount++; - clickmsec = mouse->msec; - } - mouse->xy.x = x; /* in case we're calling frselect */ - mouse->xy.y = y; - q0 = t->q0; /* may have changed */ - q1 = t->q1; - selectq = t->org+frcharofpt(t, mouse->xy);; - } - if(mouse->buttons == b && clickcount == 0){ - t->Frame.scroll = framescroll; - frselect(t, mousectl); - /* horrible botch: while asleep, may have lost selection altogether */ - if(selectq > t->file->nc) - selectq = t->org + t->p0; - t->Frame.scroll = nil; - if(selectq < t->org) - q0 = selectq; - else - q0 = t->org + t->p0; - if(selectq > t->org+t->nchars) - q1 = selectq; - else - q1 = t->org+t->p1; - } - if(q0 == q1){ - if(q0==t->q0 && mouse->msec-clickmsec<500) - textstretchsel(t, &q0, &q1, clickcount); - else - clicktext = t; - clickmsec = mouse->msec; - }else - clicktext = nil; - textsetselect(t, q0, q1); - flushimage(display, 1); - state = 0; /* undo when possible; +1 for cut, -1 for paste */ - while(mouse->buttons){ - mouse->msec = 0; - b = mouse->buttons; - if((b&1) && (b&6)){ - if(state==0 && t->what==Body){ - seq++; - filemark(t->w->body.file); - } - if(b & 2){ - if(state==-1 && t->what==Body){ - winundo(t->w, TRUE); - textsetselect(t, q0, t->q0); - state = 0; - }else if(state != 1){ - cut(t, t, nil, TRUE, TRUE, nil, 0); - state = 1; - } - }else{ - if(state==1 && t->what==Body){ - winundo(t->w, TRUE); - textsetselect(t, q0, t->q1); - state = 0; - }else if(state != -1){ - paste(t, t, nil, TRUE, FALSE, nil, 0); - state = -1; - } - } - textscrdraw(t); - clearmouse(); - } - flushimage(display, 1); - while(mouse->buttons == b) - readmouse(mousectl); - if(mouse->msec-clickmsec >= 500) - clicktext = nil; - } -} - -void -textshow(Text *t, uint q0, uint q1, int doselect) -{ - int qe; - int nl; - uint q; - - if(t->what != Body){ - if(doselect) - textsetselect(t, q0, q1); - return; - } - if(t->w!=nil && t->maxlines==0) - colgrow(t->col, t->w, 1); - if(doselect) - textsetselect(t, q0, q1); - qe = t->org+t->nchars; - if(t->org<=q0 && (q0file->nc+t->ncache))) - textscrdraw(t); - else{ - if(t->w->nopen[QWevent] > 0) - nl = 3*t->maxlines/4; - else - nl = t->maxlines/4; - q = textbacknl(t, q0, nl); - /* avoid going backwards if trying to go forwards - long lines! */ - if(!(q0>t->org && qorg)) - textsetorigin(t, q, TRUE); - while(q0 > t->org+t->nchars) - textsetorigin(t, t->org+1, FALSE); - } -} - -static -int -region(int a, int b) -{ - if(a < b) - return -1; - if(a == b) - return 0; - return 1; -} - -void -selrestore(Frame *f, Point pt0, uint p0, uint p1) -{ - if(p1<=f->p0 || p0>=f->p1){ - /* no overlap */ - frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]); - return; - } - if(p0>=f->p0 && p1<=f->p1){ - /* entirely inside */ - frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); - return; - } - - /* they now are known to overlap */ - - /* before selection */ - if(p0 < f->p0){ - frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]); - p0 = f->p0; - pt0 = frptofchar(f, p0); - } - /* after selection */ - if(p1 > f->p1){ - frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]); - p1 = f->p1; - } - /* inside selection */ - frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); -} - -void -textsetselect(Text *t, uint q0, uint q1) -{ - int p0, p1; - - /* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */ - t->q0 = q0; - t->q1 = q1; - /* compute desired p0,p1 from q0,q1 */ - p0 = q0-t->org; - p1 = q1-t->org; - if(p0 < 0) - p0 = 0; - if(p1 < 0) - p1 = 0; - if(p0 > t->nchars) - p0 = t->nchars; - if(p1 > t->nchars) - p1 = t->nchars; - if(p0==t->p0 && p1==t->p1) - return; - /* screen disagrees with desired selection */ - if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){ - /* no overlap or too easy to bother trying */ - frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0); - frdrawsel(t, frptofchar(t, p0), p0, p1, 1); - goto Return; - } - /* overlap; avoid unnecessary painting */ - if(p0 < t->p0){ - /* extend selection backwards */ - frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1); - }else if(p0 > t->p0){ - /* trim first part of selection */ - frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0); - } - if(p1 > t->p1){ - /* extend selection forwards */ - frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1); - }else if(p1 < t->p1){ - /* trim last part of selection */ - frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0); - } - - Return: - t->p0 = p0; - t->p1 = p1; -} - -/* - * Release the button in less than DELAY ms and it's considered a null selection - * if the mouse hardly moved, regardless of whether it crossed a char boundary. - */ -enum { - DELAY = 2, - MINMOVE = 4, -}; - -uint -xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */ -{ - uint p0, p1, q, tmp; - ulong msec; - Point mp, pt0, pt1, qt; - int reg, b; - - mp = mc->xy; - b = mc->buttons; - msec = mc->msec; - - /* remove tick */ - if(f->p0 == f->p1) - frtick(f, frptofchar(f, f->p0), 0); - p0 = p1 = frcharofpt(f, mp); - pt0 = frptofchar(f, p0); - pt1 = frptofchar(f, p1); - reg = 0; - frtick(f, pt0, 1); - do{ - q = frcharofpt(f, mc->xy); - if(p1 != q){ - if(p0 == p1) - frtick(f, pt0, 0); - if(reg != region(q, p0)){ /* crossed starting point; reset */ - if(reg > 0) - selrestore(f, pt0, p0, p1); - else if(reg < 0) - selrestore(f, pt1, p1, p0); - p1 = p0; - pt1 = pt0; - reg = region(q, p0); - if(reg == 0) - frdrawsel0(f, pt0, p0, p1, col, display->white); - } - qt = frptofchar(f, q); - if(reg > 0){ - if(q > p1) - frdrawsel0(f, pt1, p1, q, col, display->white); - - else if(q < p1) - selrestore(f, qt, q, p1); - }else if(reg < 0){ - if(q > p1) - selrestore(f, pt1, p1, q); - else - frdrawsel0(f, qt, q, p1, col, display->white); - } - p1 = q; - pt1 = qt; - } - if(p0 == p1) - frtick(f, pt0, 1); - flushimage(f->display, 1); - readmouse(mc); - }while(mc->buttons == b); - if(mc->msec-msec < DELAY && p0!=p1 - && abs(mp.x-mc->xy.x)xy.y) 0) - selrestore(f, pt0, p0, p1); - else if(reg < 0) - selrestore(f, pt1, p1, p0); - p1 = p0; - } - if(p1 < p0){ - tmp = p0; - p0 = p1; - p1 = tmp; - } - pt0 = frptofchar(f, p0); - if(p0 == p1) - frtick(f, pt0, 0); - selrestore(f, pt0, p0, p1); - /* restore tick */ - if(f->p0 == f->p1) - frtick(f, frptofchar(f, f->p0), 1); - flushimage(f->display, 1); - *p1p = p1; - return p0; -} - -int -textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask) -{ - uint p0, p1; - int buts; - - p0 = xselect(t, mousectl, high, &p1); - buts = mousectl->buttons; - if((buts & mask) == 0){ - *q0 = p0+t->org; - *q1 = p1+t->org; - } - - while(mousectl->buttons) - readmouse(mousectl); - return buts; -} - -int -textselect2(Text *t, uint *q0, uint *q1, Text **tp) -{ - int buts; - - *tp = nil; - buts = textselect23(t, q0, q1, but2col, 4); - if(buts & 4) - return 0; - if(buts & 1){ /* pick up argument */ - *tp = argtext; - return 1; - } - return 1; -} - -int -textselect3(Text *t, uint *q0, uint *q1) -{ - int h; - - h = (textselect23(t, q0, q1, but3col, 1|2) == 0); - return h; -} - -static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 }; -static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 }; -static Rune left2[] = { L'\n', 0 }; -static Rune left3[] = { L'\'', L'"', L'`', 0 }; - -static -Rune *left[] = { - left1, - left2, - left3, - nil -}; -static -Rune *right[] = { - right1, - left2, - left3, - nil -}; - -int -inmode(Rune r, int mode) -{ - return (mode == 1) ? isalnum(r) : r && !isspace(r); -} - -void -textstretchsel(Text *t, uint *q0, uint *q1, int mode) -{ - int c, i, lc, rc; - Rune *r, *l, *p, *x; - uint q; - - *q0 = t->q0; - *q1 = t->q1; - - if(mode){ - lc = *q0 > 0 ? textreadc(t, *q0-1) : '\n'; - rc = *q1 < t->file->nc ? textreadc(t, *q1) : '\n'; - for(i=0; left[i]; i++){ - l = left[i]; - r = right[i]; - x = runestrchr(l, lc); - if(x && r[x-l] == rc){ - *q0 -= *q0 > 0 && lc != '\n'; - *q1 += *q1 < t->file->nc; - return; - } - } - } - - for(i=0; left[i]!=nil; i++){ - q = *q0; - l = left[i]; - r = right[i]; - /* try matching character to left, looking right */ - if(q == 0) - c = '\n'; - else - c = textreadc(t, q-1); - p = runestrchr(l, c); - if(p != nil){ - if(textclickmatch(t, c, r[p-l], 1, &q)) - *q1 = q-(c!='\n'); - return; - } - /* try matching character to right, looking left */ - if(q == t->file->nc) - c = '\n'; - else - c = textreadc(t, q); - p = runestrchr(r, c); - if(p != nil){ - if(textclickmatch(t, c, l[p-r], -1, &q)){ - *q1 = *q0+(*q0file->nc && c=='\n'); - *q0 = q; - if(c!='\n' || q!=0 || textreadc(t, 0)=='\n') - (*q0)++; - } - return; - } - } - /* try filling out word to right */ - while(*q1file->nc && inmode(textreadc(t, *q1), mode)) - (*q1)++; - /* try filling out word to left */ - while(*q0>0 && inmode(textreadc(t, *q0-1), mode)) - (*q0)--; -} - -int -textclickmatch(Text *t, int cl, int cr, int dir, uint *q) -{ - Rune c; - int nest; - - nest = 1; - for(;;){ - if(dir > 0){ - if(*q == t->file->nc) - break; - c = textreadc(t, *q); - (*q)++; - }else{ - if(*q == 0) - break; - (*q)--; - c = textreadc(t, *q); - } - if(c == cr){ - if(--nest==0) - return 1; - }else if(c == cl) - nest++; - } - return cl=='\n' && nest==1; -} - -uint -textbacknl(Text *t, uint p, uint n) -{ - int i, j; - - /* look for start of this line if n==0 */ - if(n==0 && p>0 && textreadc(t, p-1)!='\n') - n = 1; - i = n; - while(i-->0 && p>0){ - --p; /* it's at a newline now; back over it */ - if(p == 0) - break; - /* at 128 chars, call it a line anyway */ - for(j=128; --j>0 && p>0; p--) - if(textreadc(t, p-1)=='\n') - break; - } - return p; -} - -void -textsetorigin(Text *t, uint org, int exact) -{ - int i, a, fixup; - Rune *r; - uint n; - - if(org>0 && !exact && textreadc(t, org-1) != '\n'){ - /* org is an estimate of the char posn; find a newline */ - /* don't try harder than 256 chars */ - for(i=0; i<256 && orgfile->nc; i++){ - if(textreadc(t, org) == '\n'){ - org++; - break; - } - org++; - } - } - a = org-t->org; - fixup = 0; - if(a>=0 && anchars){ - frdelete(t, 0, a); - fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */ - } - else if(a<0 && -anchars){ - n = t->org - org; - r = runemalloc(n); - bufread(t->file, org, r, n); - frinsert(t, r, r+n, 0); - free(r); - }else - frdelete(t, 0, t->nchars); - t->org = org; - textfill(t); - textscrdraw(t); - textsetselect(t, t->q0, t->q1); - if(fixup && t->p1 > t->p0) - frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1); -} - -void -textreset(Text *t) -{ - t->file->seq = 0; - t->eq0 = ~0; - /* do t->delete(0, t->nc, TRUE) without building backup stuff */ - textsetselect(t, t->org, t->org); - frdelete(t, 0, t->nchars); - t->org = 0; - t->q0 = 0; - t->q1 = 0; - filereset(t->file); - bufreset(t->file); -} diff --git a/time.6 b/time.6 deleted file mode 100644 index bba77e4..0000000 Binary files a/time.6 and /dev/null differ diff --git a/time.c b/time.c deleted file mode 100644 index dbe9f3c..0000000 --- a/time.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -static Channel* ctimer; /* chan(Timer*)[100] */ -static Timer *timer; - -static -uint -msec(void) -{ - return nsec()/1000000; -} - -void -timerstop(Timer *t) -{ - t->next = timer; - timer = t; -} - -void -timercancel(Timer *t) -{ - t->cancel = TRUE; -} - -static -void -timerproc(void*) -{ - int i, nt, na, dt, del; - Timer **t, *x; - uint old, new; - - threadsetname("timerproc"); - rfork(RFFDG); - t = nil; - na = 0; - nt = 0; - old = msec(); - for(;;){ - sleep(1); /* will sleep minimum incr */ - new = msec(); - dt = new-old; - old = new; - if(dt < 0) /* timer wrapped; go around, losing a tick */ - continue; - for(i=0; idt -= dt; - del = FALSE; - if(x->cancel){ - timerstop(x); - del = TRUE; - }else if(x->dt <= 0){ - /* - * avoid possible deadlock if client is - * now sending on ctimer - */ - if(nbsendul(x->c, 0) > 0) - del = TRUE; - } - if(del){ - memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]); - --nt; - --i; - } - } - if(nt == 0){ - x = recvp(ctimer); - gotit: - if(nt == na){ - na += 10; - t = realloc(t, na*sizeof(Timer*)); - if(t == nil) - error("timer realloc failed"); - } - t[nt++] = x; - old = msec(); - } - if(nbrecv(ctimer, &x) > 0) - goto gotit; - } -} - -void -timerinit(void) -{ - ctimer = chancreate(sizeof(Timer*), 100); - proccreate(timerproc, nil, STACK); -} - -Timer* -timerstart(int dt) -{ - Timer *t; - - t = timer; - if(t) - timer = timer->next; - else{ - t = emalloc(sizeof(Timer)); - t->c = chancreate(sizeof(int), 0); - } - t->next = nil; - t->dt = dt; - t->cancel = FALSE; - sendp(ctimer, t); - return t; -} diff --git a/util.6 b/util.6 deleted file mode 100644 index 9b6fcd2..0000000 Binary files a/util.6 and /dev/null differ diff --git a/util.c b/util.c deleted file mode 100644 index 48d799d..0000000 --- a/util.c +++ /dev/null @@ -1,485 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -static Point prevmouse; -static Window *mousew; - -void -cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls) -{ - uchar *q; - Rune *s; - int j, w; - - /* - * Always guaranteed that n bytes may be interpreted - * without worrying about partial runes. This may mean - * reading up to UTFmax-1 more bytes than n; the caller - * knows this. If n is a firm limit, the caller should - * set p[n] = 0. - */ - q = (uchar*)p; - s = r; - for(j=0; jfilemenu = FALSE; - winsetname(w, r, n); - xfidlog(w, "new"); - } - free(r); - for(i=nincl; --i>=0; ){ - n = runestrlen(incl[i]); - r = runemalloc(n); - runemove(r, incl[i], n); - winaddincl(w, r, n); - } - for(i=0; iindent[i] = globalindent[i]; - return w; -} - -/* make new window, if necessary; return with it locked */ -Window* -errorwin(Mntdir *md, int owner) -{ - Window *w; - - for(;;){ - if(md == nil) - w = errorwin1(nil, 0, nil, 0); - else - w = errorwin1(md->dir, md->ndir, md->incl, md->nincl); - winlock(w, owner); - if(w->col != nil) - break; - /* window was deleted too fast */ - winunlock(w); - } - return w; -} - -/* - * Incoming window should be locked. - * It will be unlocked and returned window - * will be locked in its place. - */ -Window* -errorwinforwin(Window *w) -{ - int i, n, nincl, owner; - Rune **incl; - Runestr dir; - Text *t; - - t = &w->body; - dir = dirname(t, nil, 0); - if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ - free(dir.r); - dir.r = nil; - dir.nr = 0; - } - incl = nil; - nincl = w->nincl; - if(nincl > 0){ - incl = emalloc(nincl*sizeof(Rune*)); - for(i=0; iincl[i]); - incl[i] = runemalloc(n+1); - runemove(incl[i], w->incl[i], n); - } - } - owner = w->owner; - winunlock(w); - for(;;){ - w = errorwin1(dir.r, dir.nr, incl, nincl); - winlock(w, owner); - if(w->col != nil) - break; - /* window deleted too fast */ - winunlock(w); - } - return w; -} - -typedef struct Warning Warning; - -struct Warning{ - Mntdir *md; - Buffer buf; - Warning *next; -}; - -static Warning *warnings; - -static -void -addwarningtext(Mntdir *md, Rune *r, int nr) -{ - Warning *warn; - - for(warn = warnings; warn; warn=warn->next){ - if(warn->md == md){ - bufinsert(&warn->buf, warn->buf.nc, r, nr); - return; - } - } - warn = emalloc(sizeof(Warning)); - warn->next = warnings; - warn->md = md; - if(md) - fsysincid(md); - warnings = warn; - bufinsert(&warn->buf, 0, r, nr); - nbsendp(cwarn, 0); -} - -/* called while row is locked */ -void -flushwarnings(void) -{ - Warning *warn, *next; - Window *w; - Text *t; - int owner, nr, q0, n; - Rune *r; - - for(warn=warnings; warn; warn=next) { - w = errorwin(warn->md, 'E'); - t = &w->body; - owner = w->owner; - if(owner == 0) - w->owner = 'E'; - wincommit(w, t); - /* - * Most commands don't generate much output. For instance, - * Edit ,>cat goes through /dev/cons and is already in blocks - * because of the i/o system, but a few can. Edit ,p will - * put the entire result into a single hunk. So it's worth doing - * this in blocks (and putting the text in a buffer in the first - * place), to avoid a big memory footprint. - */ - r = fbufalloc(); - q0 = t->file->nc; - for(n = 0; n < warn->buf.nc; n += nr){ - nr = warn->buf.nc - n; - if(nr > RBUFSIZE) - nr = RBUFSIZE; - bufread(&warn->buf, n, r, nr); - textbsinsert(t, t->file->nc, r, nr, TRUE, &nr); - } - textshow(t, q0, t->file->nc, 1); - free(r); - winsettag(t->w); - textscrdraw(t); - w->owner = owner; - w->dirty = FALSE; - winunlock(w); - bufclose(&warn->buf); - next = warn->next; - if(warn->md) - fsysdelid(warn->md); - free(warn); - } - warnings = nil; -} - -void -warning(Mntdir *md, char *s, ...) -{ - Rune *r; - va_list arg; - - va_start(arg, s); - r = runevsmprint(s, arg); - va_end(arg); - if(r == nil) - error("runevsmprint failed"); - addwarningtext(md, r, runestrlen(r)); - free(r); -} - -int -runeeq(Rune *s1, uint n1, Rune *s2, uint n2) -{ - if(n1 != n2) - return FALSE; - return memcmp(s1, s2, n1*sizeof(Rune)) == 0; -} - -uint -min(uint a, uint b) -{ - if(a < b) - return a; - return b; -} - -uint -max(uint a, uint b) -{ - if(a > b) - return a; - return b; -} - -char* -runetobyte(Rune *r, int n) -{ - char *s; - - if(r == nil) - return nil; - s = emalloc(n*UTFmax+1); - setmalloctag(s, getcallerpc(&r)); - snprint(s, n*UTFmax+1, "%.*S", n, r); - return s; -} - -Rune* -bytetorune(char *s, int *ip) -{ - Rune *r; - int nb, nr; - - nb = strlen(s); - r = runemalloc(nb+1); - cvttorunes(s, nb, r, &nb, &nr, nil); - r[nr] = '\0'; - *ip = nr; - return r; -} - -int -isspace(Rune c) -{ - return c == 0 || c == ' ' || c == '\t' || - c == '\n' || c == '\r' || c == '\v'; -} - -int -isalnum(Rune c) -{ - /* - * Hard to get absolutely right. Use what we know about ASCII - * and assume anything above the Latin control characters is - * potentially an alphanumeric. - * - * Treat 0xA0 (non-breaking space) as a special alphanumeric - * character [sape] - */ - if(c <= ' ') - return FALSE; - if(0x7F<=c && c<0xA0) - return FALSE; - if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) - return FALSE; - return TRUE; -} - -int -rgetc(void *v, uint n) -{ - return ((Rune*)v)[n]; -} - -int -tgetc(void *a, uint n) -{ - Text *t; - - t = a; - if(n >= t->file->nc) - return 0; - return textreadc(t, n); -} - -Rune* -skipbl(Rune *r, int n, int *np) -{ - while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){ - --n; - r++; - } - *np = n; - return r; -} - -Rune* -findbl(Rune *r, int n, int *np) -{ - while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){ - --n; - r++; - } - *np = n; - return r; -} - -void -savemouse(Window *w) -{ - prevmouse = mouse->xy; - mousew = w; -} - -int -restoremouse(Window *w) -{ - int did; - - did = 0; - if(mousew!=nil && mousew==w) { - moveto(mousectl, prevmouse); - did = 1; - } - mousew = nil; - return did; -} - -void -clearmouse() -{ - mousew = nil; -} - -char* -estrdup(char *s) -{ - char *t; - - t = strdup(s); - if(t == nil) - error("strdup failed"); - setmalloctag(t, getcallerpc(&s)); - return t; -} - -void* -emalloc(uint n) -{ - void *p; - - p = malloc(n); - if(p == nil) - error("malloc failed"); - setmalloctag(p, getcallerpc(&n)); - memset(p, 0, n); - return p; -} - -void* -erealloc(void *p, uint n) -{ - p = realloc(p, n); - if(p == nil) - error("realloc failed"); - setmalloctag(p, getcallerpc(&n)); - return p; -} - -/* - * Heuristic city. - */ -Window* -makenewwindow(Text *t) -{ - Column *c; - Window *w, *bigw, *emptyw; - Text *emptyb; - int i, y, el; - - if(activecol) - c = activecol; - else if(seltext && seltext->col) - c = seltext->col; - else if(t && t->col) - c = t->col; - else{ - if(row.ncol==0 && rowadd(&row, nil, -1)==nil) - error("can't make column"); - c = row.col[row.ncol-1]; - } - activecol = c; - if(t==nil || t->w==nil || c->nw==0) - return coladd(c, nil, nil, -1); - - /* find biggest window and biggest blank spot */ - emptyw = c->w[0]; - bigw = emptyw; - for(i=1; inw; i++){ - w = c->w[i]; - /* use >= to choose one near bottom of screen */ - if(w->body.maxlines >= bigw->body.maxlines) - bigw = w; - if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines) - emptyw = w; - } - emptyb = &emptyw->body; - el = emptyb->maxlines-emptyb->nlines; - /* if empty space is big, use it */ - if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2)) - y = emptyb->r.min.y+emptyb->nlines*font->height; - else{ - /* if this window is in column and isn't much smaller, split it */ - if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3) - bigw = t->w; - y = (bigw->r.min.y + bigw->r.max.y)/2; - } - w = coladd(c, nil, nil, y); - if(w->body.maxlines < 2) - colgrow(w->col, w, 1); - return w; -} diff --git a/wind.6 b/wind.6 deleted file mode 100644 index f04824e..0000000 Binary files a/wind.6 and /dev/null differ diff --git a/wind.c b/wind.c deleted file mode 100644 index 5f8c39f..0000000 --- a/wind.c +++ /dev/null @@ -1,698 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -int winid; - -void -wininit(Window *w, Window *clone, Rectangle r) -{ - Rectangle r1, br; - File *f; - Reffont *rf; - Rune *rp; - int nc, i; - - w->tag.w = w; - w->taglines = 1; - w->tagexpand = TRUE; - w->body.w = w; - w->id = ++winid; - incref(w); - if(globalincref) - incref(w); - w->ctlfid = ~0; - w->utflastqid = -1; - r1 = r; - r1.max.y = r1.min.y + font->height; - w->tagtop = r; - w->tagtop.max.y = r.min.y + font->height; - incref(&reffont); - f = fileaddtext(nil, &w->tag); - textinit(&w->tag, f, r1, &reffont, tagcols); - w->tag.what = Tag; - /* tag is a copy of the contents, not a tracked image */ - if(clone){ - textdelete(&w->tag, 0, w->tag.file->nc, TRUE); - nc = clone->tag.file->nc; - rp = runemalloc(nc); - bufread(clone->tag.file, 0, rp, nc); - textinsert(&w->tag, 0, rp, nc, TRUE); - free(rp); - filereset(w->tag.file); - textsetselect(&w->tag, nc, nc); - } - r1 = r; - r1.min.y += w->taglines*font->height + 1; - if(r1.max.y < r1.min.y) - r1.max.y = r1.min.y; - f = nil; - if(clone){ - f = clone->body.file; - w->body.org = clone->body.org; - w->isscratch = clone->isscratch; - rf = rfget(FALSE, FALSE, FALSE, clone->body.reffont->f->name); - }else - rf = rfget(FALSE, FALSE, FALSE, nil); - f = fileaddtext(f, &w->body); - w->body.what = Body; - textinit(&w->body, f, r1, rf, textcols); - r1.min.y -= 1; - r1.max.y = r1.min.y+1; - draw(screen, r1, tagcols[BORD], nil, ZP); - textscrdraw(&w->body); - w->r = r; - w->r.max.y = w->body.r.max.y; - br.min = w->tag.scrollr.min; - br.max.x = br.min.x + Dx(button->r); - br.max.y = br.min.y + Dy(button->r); - draw(screen, br, button, nil, button->r.min); - w->filemenu = TRUE; - w->maxlines = w->body.maxlines; - for(i=0; iindent[i] = globalindent[i]; - if(clone){ - w->dirty = clone->dirty; - for(i=0; iindent[i] = clone->indent[i]; - textsetselect(&w->body, clone->body.q0, clone->body.q1); - winsettag(w); - } -} - -int -tagrunepos(Window *w, Rune *s) -{ - int n; - Rune *r, *rr; - - if(s == nil) - return -1; - - n = w->tag.file->nc; - r = runemalloc(n+1); - bufread(w->tag.file, 0, r, n); - r[n] = L'\0'; - - rr = runestrstr(r, s); - if(rr == nil || rr == r) - return -1; - return rr - r; -} - -void -movetodel(Window *w) -{ - int n; - - n = tagrunepos(w, delcmd); - free(delcmd); - delcmd = nil; - if(n < 0) - return; - moveto(mousectl, addpt(frptofchar(&w->tag, n), Pt(4, w->tag.font->height-4))); -} - -/* - * Compute number of tag lines required - * to display entire tag text. - */ -int -wintaglines(Window *w, Rectangle r) -{ - int n; - Rune rune; - Point p; - - if(!w->tagexpand && !w->showdel) - return 1; - w->showdel = FALSE; - textresize(&w->tag, r, TRUE); - w->tagsafe = FALSE; - - if(!w->tagexpand) { - /* use just as many lines as needed to show the Del */ - n = tagrunepos(w, delcmd); - if(n < 0) - return 1; - p = subpt(frptofchar(&w->tag, n), w->tag.r.min); - return 1 + p.y / w->tag.font->height; - } - - /* can't use more than we have */ - if(w->tag.nlines >= w->tag.maxlines) - return w->tag.maxlines; - - /* if tag ends with \n, include empty line at end for typing */ - n = w->tag.nlines; - if(w->tag.file->nc > 0){ - bufread(w->tag.file, w->tag.file->nc-1, &rune, 1); - if(rune == '\n') - n++; - } - if(n == 0) - n = 1; - return n; -} - -int -winresize(Window *w, Rectangle r, int safe, int fillfringe) -{ - int oy, y, mouseintag, mouseinbody; - Point p; - Rectangle r1; - Image *b; - Rectangle br; - - mouseintag = ptinrect(mouse->xy, w->tag.all); - mouseinbody = ptinrect(mouse->xy, w->body.all); - - /* Tagtop is first line of tag. */ - w->tagtop = r; - w->tagtop.max.y = r.min.y+font->height; - - r1 = r; - r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height); - - /* If needed, recompute number of lines in tag. */ - if(!safe || !w->tagsafe || !eqrect(w->tag.r, r1)){ - w->taglines = wintaglines(w, r); - r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height); - } - if(Dy(r1) < font->height) - r1.max.y = r1.min.y+font->height; - /* If needed, resize & redraw tag. */ - y = r1.max.y; - if(!safe || !w->tagsafe || !eqrect(w->tag.r, r1)){ - textresize(&w->tag, r1, TRUE); - y = w->tag.r.max.y; - b = button; - if(w->body.file->mod && !w->isdir && !w->isscratch) - b = modbutton; - br.min = w->tag.scrollr.min; - br.max.x = br.min.x + Dx(b->r); - br.max.y = br.min.y + Dy(b->r); - draw(screen, br, b, nil, b->r.min); - - w->tagsafe = TRUE; - - /* If mouse is in tag, pull up as tag closes. */ - if(mouseintag && !ptinrect(mouse->xy, w->tag.all)){ - p = mouse->xy; - p.y = w->tag.all.max.y-3; - moveto(mousectl, p); - } - - /* If mouse is in body, push down as tag expands. */ - if(mouseinbody && ptinrect(mouse->xy, w->tag.all)){ - p = mouse->xy; - p.y = w->tag.all.max.y+3; - moveto(mousectl, p); - } - } - /* If needed, resize & redraw body. */ - r1 = r; - r1.min.y = y; - if(!safe || !eqrect(w->body.r, r1)){ - oy = y; - if(y+1+w->body.font->height <= r.max.y){ /* room for one line */ - r1.min.y = y; - r1.max.y = y+1; - draw(screen, r1, tagcols[BORD], nil, ZP); - y++; - r1.min.y = min(y, r.max.y); - r1.max.y = r.max.y; - }else{ - r1.min.y = y; - r1.max.y = y; - } - y = textresize(&w->body, r1, fillfringe); - w->r = r; - w->r.max.y = y; - textscrdraw(&w->body); - w->body.all.min.y = oy; - } - w->maxlines = min(w->body.nlines, max(w->maxlines, w->body.maxlines)); - return w->r.max.y; -} - -void -winlock1(Window *w, int owner) -{ - incref(w); - qlock(w); - w->owner = owner; -} - -void -winlock(Window *w, int owner) -{ - int i; - File *f; - - f = w->body.file; - for(i=0; intext; i++) - winlock1(f->text[i]->w, owner); -} - -void -winunlock(Window *w) -{ - int i; - File *f; - - /* - * subtle: loop runs backwards to avoid tripping over - * winclose indirectly editing f->text and freeing f - * on the last iteration of the loop. - */ - f = w->body.file; - for(i=f->ntext-1; i>=0; i--){ - w = f->text[i]->w; - w->owner = 0; - qunlock(w); - winclose(w); - } -} - -void -winmousebut(Window *w) -{ - moveto(mousectl, addpt(w->tag.scrollr.min, divpt(Pt(Dx(w->tag.scrollr), font->height), 2))); -} - -void -windirfree(Window *w) -{ - int i; - Dirlist *dl; - - if(w->isdir){ - for(i=0; indl; i++){ - dl = w->dlp[i]; - free(dl->r); - free(dl); - } - free(w->dlp); - } - w->dlp = nil; - w->ndl = 0; -} - -void -winclose(Window *w) -{ - int i; - - if(decref(w) == 0){ - xfidlog(w, "del"); - windirfree(w); - textclose(&w->tag); - textclose(&w->body); - if(activewin == w) - activewin = nil; - for(i=0; inincl; i++) - free(w->incl[i]); - free(w->incl); - free(w->events); - free(w); - } -} - -void -windelete(Window *w) -{ - Xfid *x; - - x = w->eventx; - if(x){ - w->nevents = 0; - free(w->events); - w->events = nil; - w->eventx = nil; - sendp(x->c, nil); /* wake him up */ - } -} - -void -winundo(Window *w, int isundo) -{ - Text *body; - int i; - File *f; - Window *v; - - w->utflastqid = -1; - body = &w->body; - fileundo(body->file, isundo, &body->q0, &body->q1); - textshow(body, body->q0, body->q1, 1); - f = body->file; - for(i=0; intext; i++){ - v = f->text[i]->w; - v->dirty = (f->seq != v->putseq); - if(v != w){ - v->body.q0 = v->body.p0+v->body.org; - v->body.q1 = v->body.p1+v->body.org; - } - } - winsettag(w); -} - -void -winsetname(Window *w, Rune *name, int n) -{ - Text *t; - Window *v; - int i; - - t = &w->body; - if(runeeq(t->file->name, t->file->nname, name, n) == TRUE) - return; - w->isscratch = FALSE; - if(n>=6 && runeeq(L"/guide", 6, name+(n-6), 6)) - w->isscratch = TRUE; - else if(n>=7 && runeeq(L"+Errors", 7, name+(n-7), 7)) - w->isscratch = TRUE; - filesetname(t->file, name, n); - for(i=0; ifile->ntext; i++){ - v = t->file->text[i]->w; - winsettag(v); - v->isscratch = w->isscratch; - } -} - -void -wintype(Window *w, Text *t, Rune r) -{ - int i; - - texttype(t, r); - if(t->what == Tag) - w->tagsafe = FALSE; - if(t->what == Body) - for(i=0; ifile->ntext; i++) - textscrdraw(t->file->text[i]); - winsettag(w); -} - -void -wincleartag(Window *w) -{ - int i, n; - Rune *r; - - /* w must be committed */ - n = w->tag.file->nc; - r = runemalloc(n); - bufread(w->tag.file, 0, r, n); - for(i=0; itag, i, n, TRUE); - free(r); - w->tag.file->mod = FALSE; - if(w->tag.q0 > i) - w->tag.q0 = i; - if(w->tag.q1 > i) - w->tag.q1 = i; - textsetselect(&w->tag, w->tag.q0, w->tag.q1); -} - -void -winsettag1(Window *w) -{ - int i, j, k, n, bar, dirty; - Rune *new, *old, *r; - Image *b; - uint q0, q1; - Rectangle br; - - /* there are races that get us here with stuff in the tag cache, so we take extra care to sync it */ - if(w->tag.ncache!=0 || w->tag.file->mod) - wincommit(w, &w->tag); /* check file name; also guarantees we can modify tag contents */ - old = runemalloc(w->tag.file->nc+1); - bufread(w->tag.file, 0, old, w->tag.file->nc); - old[w->tag.file->nc] = '\0'; - for(i=0; itag.file->nc; i++) - if(old[i]==' ' || old[i]=='\t') - break; - if(runeeq(old, i, w->body.file->name, w->body.file->nname) == FALSE){ - textdelete(&w->tag, 0, i, TRUE); - textinsert(&w->tag, 0, w->body.file->name, w->body.file->nname, TRUE); - free(old); - old = runemalloc(w->tag.file->nc+1); - bufread(w->tag.file, 0, old, w->tag.file->nc); - old[w->tag.file->nc] = '\0'; - w->tagsafe = FALSE; - } - new = runemalloc(w->body.file->nname+100); - i = 0; - runemove(new+i, w->body.file->name, w->body.file->nname); - i += w->body.file->nname; - runemove(new+i, L" Del Snarf", 10); - i += 10; - if(w->filemenu){ - if(w->body.file->delta.nc>0 || w->body.ncache){ - runemove(new+i, L" Undo", 5); - i += 5; - } - if(w->body.file->epsilon.nc > 0){ - runemove(new+i, L" Redo", 5); - i += 5; - } - dirty = w->body.file->nname && (w->body.ncache || w->body.file->seq!=w->putseq); - if(!w->isdir && dirty){ - runemove(new+i, L" Put", 4); - i += 4; - } - } - if(w->isdir){ - runemove(new+i, L" Get", 4); - i += 4; - } - runemove(new+i, L" |", 2); - i += 2; - r = runestrchr(old, '|'); - if(r) - k = r-old+1; - else{ - k = w->tag.file->nc; - if(w->body.file->seq == 0){ - runemove(new+i, L" Look ", 6); - i += 6; - } - } - - new[i] = 0; - /* replace tag if the new one is different */ - if(runeeq(new, i, old, k) == FALSE){ - n = k; - if(n > i) - n = i; - for(j=0; jtag.q0; - q1 = w->tag.q1; - textdelete(&w->tag, j, k, TRUE); - textinsert(&w->tag, j, new+j, i-j, TRUE); - /* try to preserve user selection */ - r = runestrchr(old, '|'); - if(r){ - bar = r-old; - if(q0 > bar){ - bar = (runestrchr(new, '|')-new)-bar; - w->tag.q0 = q0+bar; - w->tag.q1 = q1+bar; - } - } - w->tagsafe = FALSE; - } - free(old); - free(new); - w->tag.file->mod = FALSE; - n = w->tag.file->nc+w->tag.ncache; - if(w->tag.q0 > n) - w->tag.q0 = n; - if(w->tag.q1 > n) - w->tag.q1 = n; - textsetselect(&w->tag, w->tag.q0, w->tag.q1); - b = button; - if(!w->isdir && !w->isscratch && (w->body.file->mod || w->body.ncache)) - b = modbutton; - br.min = w->tag.scrollr.min; - br.max.x = br.min.x + Dx(b->r); - br.max.y = br.min.y + Dy(b->r); - draw(screen, br, b, nil, b->r.min); - if(w->tagsafe == FALSE) - winresize(w, w->r, TRUE, TRUE); -} - -void -winsettag(Window *w) -{ - int i; - File *f; - Window *v; - - f = w->body.file; - for(i=0; intext; i++){ - v = f->text[i]->w; - if(v->col->safe || v->body.maxlines>0) - winsettag1(v); - } -} - -void -wincommit(Window *w, Text *t) -{ - Rune *r; - int i; - File *f; - - textcommit(t, TRUE); - f = t->file; - if(f->ntext > 1) - for(i=0; intext; i++) - textcommit(f->text[i], FALSE); /* no-op for t */ - if(t->what == Body) - return; - r = runemalloc(w->tag.file->nc); - bufread(w->tag.file, 0, r, w->tag.file->nc); - for(i=0; itag.file->nc; i++) - if(r[i]==' ' || r[i]=='\t') - break; - if(runeeq(r, i, w->body.file->name, w->body.file->nname) == FALSE){ - seq++; - filemark(w->body.file); - w->body.file->mod = TRUE; - w->dirty = TRUE; - winsetname(w, r, i); - winsettag(w); - } - free(r); -} - -void -winaddincl(Window *w, Rune *r, int n) -{ - char *a; - Dir *d; - Runestr rs; - - a = runetobyte(r, n); - d = dirstat(a); - if(d == nil){ - if(a[0] == '/') - goto Rescue; - rs = dirname(&w->body, r, n); - r = rs.r; - n = rs.nr; - free(a); - a = runetobyte(r, n); - d = dirstat(a); - if(d == nil) - goto Rescue; - r = runerealloc(r, n+1); - r[n] = 0; - } - if((d->qid.type&QTDIR) == 0){ - free(d); - warning(nil, "%s: not a directory\n", a); - free(r); - free(a); - return; - } - free(a); - free(d); - w->nincl++; - w->incl = realloc(w->incl, w->nincl*sizeof(Rune*)); - memmove(w->incl+1, w->incl, (w->nincl-1)*sizeof(Rune*)); - w->incl[0] = runemalloc(n+1); - runemove(w->incl[0], r, n); - free(r); - return; - -Rescue: - warning(nil, "%s: %r\n", a); - free(r); - free(a); - return; -} - -int -winclean(Window *w, int conservative) -{ - if(w->isscratch || w->isdir) /* don't whine if it's a guide file, error window, etc. */ - return TRUE; - if(!conservative && w->nopen[QWevent]>0) - return TRUE; - if(w->dirty){ - if(w->body.file->nname) - warning(nil, "%.*S modified\n", w->body.file->nname, w->body.file->name); - else{ - if(w->body.file->nc < 100) /* don't whine if it's too small */ - return TRUE; - warning(nil, "unnamed file modified\n"); - } - w->dirty = FALSE; - return FALSE; - } - return TRUE; -} - -char* -winctlprint(Window *w, char *buf, int fonts) -{ - sprint(buf, "%11d %11d %11d %11d %11d ", w->id, w->tag.file->nc, - w->body.file->nc, w->isdir, w->dirty); - if(fonts) - return smprint("%s%11d %q %11d " , buf, Dx(w->body.r), - w->body.reffont->f->name, w->body.maxtab); - return buf; -} - -void -winevent(Window *w, char *fmt, ...) -{ - int n; - char *b; - Xfid *x; - va_list arg; - - if(w->nopen[QWevent] == 0) - return; - if(w->owner == 0) - error("no window owner"); - va_start(arg, fmt); - b = vsmprint(fmt, arg); - va_end(arg); - if(b == nil) - error("vsmprint failed"); - n = strlen(b); - w->events = erealloc(w->events, w->nevents+1+n); - w->events[w->nevents++] = w->owner; - memmove(w->events+w->nevents, b, n); - free(b); - w->nevents += n; - x = w->eventx; - if(x){ - w->eventx = nil; - sendp(x->c, nil); - } -} diff --git a/xfid.6 b/xfid.6 deleted file mode 100644 index 41a1232..0000000 Binary files a/xfid.6 and /dev/null differ diff --git a/xfid.c b/xfid.c deleted file mode 100644 index 162333d..0000000 --- a/xfid.c +++ /dev/null @@ -1,1100 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dat.h" -#include "fns.h" - -enum -{ - Ctlsize = 5*12 -}; - -char Edel[] = "deleted window"; -char Ebadctl[] = "ill-formed control message"; -char Ebadaddr[] = "bad address syntax"; -char Eaddr[] = "address out of range"; -char Einuse[] = "already in use"; -char Ebadevent[] = "bad event syntax"; -extern char Eperm[]; - -static -void -clampaddr(Window *w) -{ - if(w->addr.q0 < 0) - w->addr.q0 = 0; - if(w->addr.q1 < 0) - w->addr.q1 = 0; - if(w->addr.q0 > w->body.file->nc) - w->addr.q0 = w->body.file->nc; - if(w->addr.q1 > w->body.file->nc) - w->addr.q1 = w->body.file->nc; -} - -void -xfidctl(void *arg) -{ - Xfid *x; - void (*f)(Xfid*); - - threadsetname("xfidctlthread"); - x = arg; - for(;;){ - f = recvp(x->c); - (*f)(x); - flushimage(display, 1); - sendp(cxfidfree, x); - } -} - -void -xfidflush(Xfid *x) -{ - Fcall fc; - int i, j; - Window *w; - Column *c; - Xfid *wx; - - xfidlogflush(x); - - /* search windows for matching tag */ - qlock(&row); - for(j=0; jnw; i++){ - w = c->w[i]; - winlock(w, 'E'); - wx = w->eventx; - if(wx!=nil && wx->tag==x->oldtag){ - w->eventx = nil; - wx->flushed = TRUE; - sendp(wx->c, nil); - winunlock(w); - goto out; - } - winunlock(w); - } - } -out: - qunlock(&row); - respond(x, &fc, nil); -} - -void -xfidopen(Xfid *x) -{ - Fcall fc; - Window *w; - Text *t; - char *s; - Rune *r; - int m, n, q, q0, q1; - - w = x->f->w; - t = &w->body; - q = FILE(x->f->qid); - if(w){ - winlock(w, 'E'); - switch(q){ - case QWaddr: - if(w->nopen[q]++ == 0){ - w->addr = (Range){0,0}; - w->limit = (Range){-1,-1}; - } - break; - case QWdata: - case QWxdata: - w->nopen[q]++; - break; - case QWevent: - if(w->nopen[q]++ == 0){ - if(!w->isdir && w->col!=nil){ - w->filemenu = FALSE; - winsettag(w); - } - } - break; - case QWrdsel: - /* - * Use a temporary file. - * A pipe would be the obvious, but we can't afford the - * broken pipe notification. Using the code to read QWbody - * is n², which should probably also be fixed. Even then, - * though, we'd need to squirrel away the data in case it's - * modified during the operation, e.g. by |sort - */ - if(w->rdselfd >= 0){ - winunlock(w); - respond(x, &fc, Einuse); - return; - } - w->rdselfd = tempfile(); - if(w->rdselfd < 0){ - winunlock(w); - respond(x, &fc, "can't create temp file"); - return; - } - w->nopen[q]++; - q0 = t->q0; - q1 = t->q1; - r = fbufalloc(); - s = fbufalloc(); - while(q0 < q1){ - n = q1 - q0; - if(n > (BUFSIZE-1)/UTFmax) - n = (BUFSIZE-1)/UTFmax; - bufread(t->file, q0, r, n); - m = snprint(s, BUFSIZE, "%.*S", n, r); - if(write(w->rdselfd, s, m) != m){ - warning(nil, "can't write temp file for pipe command %r\n"); - break; - } - q0 += n; - } - fbuffree(s); - fbuffree(r); - break; - case QWwrsel: - w->nopen[q]++; - seq++; - filemark(t->file); - cut(t, t, nil, FALSE, TRUE, nil, 0); - w->wrselrange = (Range){t->q1, t->q1}; - w->nomark = TRUE; - break; - case QWeditout: - if(editing == FALSE){ - winunlock(w); - respond(x, &fc, Eperm); - return; - } - w->wrselrange = (Range){t->q1, t->q1}; - break; - } - winunlock(w); - } - else{ - switch(q){ - case Qlog: - xfidlogopen(x); - break; - } - } - fc.qid = x->f->qid; - fc.iounit = messagesize-IOHDRSZ; - x->f->open = TRUE; - respond(x, &fc, nil); -} - -void -xfidclose(Xfid *x) -{ - Fcall fc; - Window *w; - int q; - Text *t; - - w = x->f->w; - x->f->busy = FALSE; - if(x->f->open == FALSE){ - if(w != nil) - winclose(w); - respond(x, &fc, nil); - return; - } - - x->f->open = FALSE; - if(w){ - winlock(w, 'E'); - q = FILE(x->f->qid); - switch(q){ - case QWctl: - if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){ - w->ctlfid = ~0; - qunlock(&w->ctllock); - } - break; - case QWdata: - case QWxdata: - w->nomark = FALSE; - /* fall through */ - case QWaddr: - case QWevent: /* BUG: do we need to shut down Xfid? */ - if(--w->nopen[q] == 0){ - if(q == QWdata || q == QWxdata) - w->nomark = FALSE; - if(q==QWevent && !w->isdir && w->col!=nil){ - w->filemenu = TRUE; - winsettag(w); - } - if(q == QWevent){ - free(w->dumpstr); - free(w->dumpdir); - w->dumpstr = nil; - w->dumpdir = nil; - } - } - break; - case QWrdsel: - close(w->rdselfd); - w->rdselfd = -1; - break; - case QWwrsel: - w->nomark = FALSE; - t = &w->body; - /* before: only did this if !w->noscroll, but that didn't seem right in practice */ - textshow(t, min(w->wrselrange.q0, t->file->nc), - min(w->wrselrange.q1, t->file->nc), 1); - textscrdraw(t); - break; - } - winunlock(w); - winclose(w); - } - respond(x, &fc, nil); -} - -void -xfidread(Xfid *x) -{ - Fcall fc; - int n, q; - uint off; - char *b; - char buf[256]; - Window *w; - - q = FILE(x->f->qid); - w = x->f->w; - if(w == nil){ - fc.count = 0; - switch(q){ - case Qcons: - case Qlabel: - break; - case Qindex: - xfidindexread(x); - return; - case Qlog: - xfidlogread(x); - return; - default: - warning(nil, "unknown qid %d\n", q); - break; - } - respond(x, &fc, nil); - return; - } - winlock(w, 'F'); - if(w->col == nil){ - winunlock(w); - respond(x, &fc, Edel); - return; - } - off = x->offset; - switch(q){ - case QWaddr: - textcommit(&w->body, TRUE); - clampaddr(w); - sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1); - goto Readbuf; - - case QWbody: - xfidutfread(x, &w->body, w->body.file->nc, QWbody); - break; - - case QWctl: - b = winctlprint(w, buf, 1); - goto Readb; - - Readbuf: - b = buf; - Readb: - n = strlen(b); - if(off > n) - off = n; - if(off+x->count > n) - x->count = n-off; - fc.count = x->count; - fc.data = b+off; - respond(x, &fc, nil); - if(b != buf) - free(b); - break; - - case QWevent: - xfideventread(x, w); - break; - - case QWdata: - /* BUG: what should happen if q1 > q0? */ - if(w->addr.q0 > w->body.file->nc){ - respond(x, &fc, Eaddr); - break; - } - w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->nc); - w->addr.q1 = w->addr.q0; - break; - - case QWxdata: - /* BUG: what should happen if q1 > q0? */ - if(w->addr.q0 > w->body.file->nc){ - respond(x, &fc, Eaddr); - break; - } - w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1); - break; - - case QWtag: - xfidutfread(x, &w->tag, w->tag.file->nc, QWtag); - break; - - case QWrdsel: - seek(w->rdselfd, off, 0); - n = x->count; - if(n > BUFSIZE) - n = BUFSIZE; - b = fbufalloc(); - n = read(w->rdselfd, b, n); - if(n < 0){ - respond(x, &fc, "I/O error in temp file"); - break; - } - fc.count = n; - fc.data = b; - respond(x, &fc, nil); - fbuffree(b); - break; - - default: - sprint(buf, "unknown qid %d in read", q); - respond(x, &fc, nil); - } - winunlock(w); -} - -static Rune* -fullrunewrite(Xfid *x, int *inr) -{ - int q, cnt, c, nb, nr; - Rune *r; - - q = x->f->nrpart; - cnt = x->count; - if(q > 0){ - memmove(x->data+q, x->data, cnt); /* there's room; see fsysproc */ - memmove(x->data, x->f->rpart, q); - cnt += q; - x->f->nrpart = 0; - } - r = runemalloc(cnt); - cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil); - /* approach end of buffer */ - while(fullrune(x->data+nb, cnt-nb)){ - c = nb; - nb += chartorune(&r[nr], x->data+c); - if(r[nr]) - nr++; - } - if(nb < cnt){ - memmove(x->f->rpart, x->data+nb, cnt-nb); - x->f->nrpart = cnt-nb; - } - *inr = nr; - return r; -} - -void -xfidwrite(Xfid *x) -{ - Fcall fc; - int c, qid, nb, nr, eval; - char buf[64], *err; - Window *w; - Rune *r; - Range a; - Text *t; - uint q0, tq0, tq1; - - qid = FILE(x->f->qid); - w = x->f->w; - if(w){ - c = 'F'; - if(qid==QWtag || qid==QWbody) - c = 'E'; - winlock(w, c); - if(w->col == nil){ - winunlock(w); - respond(x, &fc, Edel); - return; - } - } - x->data[x->count] = 0; - switch(qid){ - case Qcons: - w = errorwin(x->f->mntdir, 'X'); - t=&w->body; - goto BodyTag; - - case Qlabel: - fc.count = x->count; - respond(x, &fc, nil); - break; - - case QWaddr: - x->data[x->count] = 0; - r = bytetorune(x->data, &nr); - t = &w->body; - wincommit(w, t); - eval = TRUE; - a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb); - free(r); - if(nb < nr){ - respond(x, &fc, Ebadaddr); - break; - } - if(!eval){ - respond(x, &fc, Eaddr); - break; - } - w->addr = a; - fc.count = x->count; - respond(x, &fc, nil); - break; - - case Qeditout: - case QWeditout: - r = fullrunewrite(x, &nr); - if(w) - err = edittext(w, w->wrselrange.q1, r, nr); - else - err = edittext(nil, 0, r, nr); - free(r); - if(err != nil){ - respond(x, &fc, err); - break; - } - fc.count = x->count; - respond(x, &fc, nil); - break; - - case QWerrors: - w = errorwinforwin(w); - t = &w->body; - goto BodyTag; - - case QWbody: - case QWwrsel: - t = &w->body; - goto BodyTag; - - case QWctl: - xfidctlwrite(x, w); - break; - - case QWdata: - a = w->addr; - t = &w->body; - wincommit(w, t); - if(a.q0>t->file->nc || a.q1>t->file->nc){ - respond(x, &fc, Eaddr); - break; - } - r = runemalloc(x->count); - cvttorunes(x->data, x->count, r, &nb, &nr, nil); - if(w->nomark == FALSE){ - seq++; - filemark(t->file); - } - q0 = a.q0; - if(a.q1 > q0){ - textdelete(t, q0, a.q1, TRUE); - w->addr.q1 = q0; - } - tq0 = t->q0; - tq1 = t->q1; - textinsert(t, q0, r, nr, TRUE); - if(tq0 >= q0) - tq0 += nr; - if(tq1 >= q0) - tq1 += nr; - textsetselect(t, tq0, tq1); - if(!t->w->noscroll) - textshow(t, q0, q0+nr, 0); - textscrdraw(t); - winsettag(w); - free(r); - w->addr.q0 += nr; - w->addr.q1 = w->addr.q0; - fc.count = x->count; - respond(x, &fc, nil); - break; - - case QWevent: - xfideventwrite(x, w); - break; - - case QWtag: - t = &w->tag; - goto BodyTag; - - BodyTag: - r = fullrunewrite(x, &nr); - if(nr > 0){ - wincommit(w, t); - if(qid == QWwrsel){ - q0 = w->wrselrange.q1; - if(q0 > t->file->nc) - q0 = t->file->nc; - }else - q0 = t->file->nc; - if(qid == QWtag) - textinsert(t, q0, r, nr, TRUE); - else{ - if(w->nomark == FALSE){ - seq++; - filemark(t->file); - } - q0 = textbsinsert(t, q0, r, nr, TRUE, &nr); - textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */ - if(qid!=QWwrsel && !t->w->noscroll) - textshow(t, q0+nr, q0+nr, 1); - textscrdraw(t); - } - winsettag(w); - if(qid == QWwrsel) - w->wrselrange.q1 += nr; - free(r); - } - fc.count = x->count; - respond(x, &fc, nil); - break; - - default: - sprint(buf, "unknown qid %d in write", qid); - respond(x, &fc, buf); - break; - } - if(w) - winunlock(w); -} - -void -xfidctlwrite(Xfid *x, Window *w) -{ - Fcall fc; - int i, m, n, nb, nr, nulls; - Rune *r; - char *err, *p, *pp, *q, *e; - int scrdraw, settag; - Text *t; - - err = nil; - e = x->data+x->count; - scrdraw = FALSE; - settag = FALSE; - r = emalloc(x->count*UTFmax+1); - x->data[x->count] = 0; - textcommit(&w->tag, TRUE); - for(n=0; ncount; n+=m){ - p = x->data+n; - if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */ - qlock(&w->ctllock); - w->ctlfid = x->f->fid; - m = 4; - }else - if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */ - w->ctlfid = ~0; - qunlock(&w->ctllock); - m = 6; - }else - if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */ - t = &w->body; - t->eq0 = ~0; - filereset(t->file); - t->file->mod = FALSE; - w->dirty = FALSE; - settag = TRUE; - m = 5; - }else - if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */ - t = &w->body; - /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */ - t->file->mod = TRUE; - w->dirty = TRUE; - settag = TRUE; - m = 5; - }else - if(strncmp(p, "show", 4) == 0){ /* show dot */ - t = &w->body; - textshow(t, t->q0, t->q1, 1); - m = 4; - }else - if(strncmp(p, "name ", 5) == 0){ /* set file name */ - pp = p+5; - m = 5; - q = memchr(pp, '\n', e-pp); - if(q==nil || q==pp){ - err = Ebadctl; - break; - } - *q = 0; - nulls = FALSE; - cvttorunes(pp, q-pp, r, &nb, &nr, &nulls); - if(nulls){ - err = "nulls in file name"; - break; - } - for(i=0; ibody.file); - winsetname(w, r, nr); - m += (q+1) - pp; - }else - if(strncmp(p, "font ", 5) == 0){ /* execute font command */ - pp = p+5; - m = 5; - q = memchr(pp, '\n', e-pp); - if(q==nil || q==pp){ - err = Ebadctl; - break; - } - *q = 0; - nulls = FALSE; - cvttorunes(pp, q-pp, r, &nb, &nr, &nulls); - if(nulls){ - err = "nulls in font string"; - break; - } - fontx(&w->body, nil, nil, FALSE, XXX, r, nr); - m += (q+1) - pp; - }else - if(strncmp(p, "dump ", 5) == 0){ /* set dump string */ - pp = p+5; - m = 5; - q = memchr(pp, '\n', e-pp); - if(q==nil || q==pp){ - err = Ebadctl; - break; - } - *q = 0; - nulls = FALSE; - cvttorunes(pp, q-pp, r, &nb, &nr, &nulls); - if(nulls){ - err = "nulls in dump string"; - break; - } - w->dumpstr = runetobyte(r, nr); - m += (q+1) - pp; - }else - if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */ - pp = p+8; - m = 8; - q = memchr(pp, '\n', e-pp); - if(q==nil || q==pp){ - err = Ebadctl; - break; - } - *q = 0; - nulls = FALSE; - cvttorunes(pp, q-pp, r, &nb, &nr, &nulls); - if(nulls){ - err = "nulls in dump directory string"; - break; - } - w->dumpdir = runetobyte(r, nr); - m += (q+1) - pp; - }else - if(strncmp(p, "delete", 6) == 0){ /* delete for sure */ - colclose(w->col, w, TRUE); - m = 6; - }else - if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */ - if(!winclean(w, TRUE)){ - err = "file dirty"; - break; - } - colclose(w->col, w, TRUE); - m = 3; - }else - if(strncmp(p, "get", 3) == 0){ /* get file */ - get(&w->body, nil, nil, FALSE, XXX, nil, 0); - m = 3; - }else - if(strncmp(p, "put", 3) == 0){ /* put file */ - put(&w->body, nil, nil, XXX, XXX, nil, 0); - m = 3; - }else - if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */ - textcommit(&w->body, TRUE); - clampaddr(w); - w->body.q0 = w->addr.q0; - w->body.q1 = w->addr.q1; - textsetselect(&w->body, w->body.q0, w->body.q1); - settag = TRUE; - m = 8; - }else - if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */ - w->addr.q0 = w->body.q0; - w->addr.q1 = w->body.q1; - m = 8; - }else - if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */ - textcommit(&w->body, TRUE); - clampaddr(w); - w->limit.q0 = w->addr.q0; - w->limit.q1 = w->addr.q1; - m = 10; - }else - if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */ - w->nomark = TRUE; - m = 6; - }else - if(strncmp(p, "mark", 4) == 0){ /* mark file */ - seq++; - filemark(w->body.file); - settag = TRUE; - m = 4; - }else - if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */ - w->filemenu = FALSE; - m = 6; - }else - if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */ - w->filemenu = TRUE; - m = 4; - }else - if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */ - w->noscroll = TRUE; - m = 8; - }else - if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */ - wincleartag(w); - settag = TRUE; - m = 8; - }else - if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */ - w->noscroll = FALSE; - m = 6; - }else - if(strncmp(p, "scratch", 7) == 0){ /* mark as a scratch file */ - w->isscratch = TRUE; - m = 7; - }else{ - err = Ebadctl; - break; - } - while(p[m] == '\n') - m++; - } - - free(r); - if(err) - n = 0; - fc.count = n; - respond(x, &fc, err); - if(settag) - winsettag(w); - if(scrdraw) - textscrdraw(&w->body); -} - -void -xfideventwrite(Xfid *x, Window *w) -{ - Fcall fc; - int m, n; - Rune *r; - char *err, *p, *q; - Text *t; - int c; - uint q0, q1; - - err = nil; - r = emalloc(x->count*UTFmax+1); - for(n=0; ncount; n+=m){ - p = x->data+n; - w->owner = *p++; /* disgusting */ - c = *p++; - while(*p == ' ') - p++; - q0 = strtoul(p, &q, 10); - if(q == p) - goto Rescue; - p = q; - while(*p == ' ') - p++; - q1 = strtoul(p, &q, 10); - if(q == p) - goto Rescue; - p = q; - while(*p == ' ') - p++; - if(*p++ != '\n') - goto Rescue; - m = p-(x->data+n); - if('a'<=c && c<='z') - t = &w->tag; - else if('A'<=c && c<='Z') - t = &w->body; - else - goto Rescue; - if(q0>t->file->nc || q1>t->file->nc || q0>q1) - goto Rescue; - - qlock(&row); /* just like mousethread */ - switch(c){ - case 'x': - case 'X': - execute(t, q0, q1, TRUE, nil); - break; - case 'l': - case 'L': - look3(t, q0, q1, TRUE); - break; - default: - qunlock(&row); - goto Rescue; - } - qunlock(&row); - - } - - Out: - free(r); - if(err) - n = 0; - fc.count = n; - respond(x, &fc, err); - return; - - Rescue: - err = Ebadevent; - goto Out; -} - -void -xfidutfread(Xfid *x, Text *t, uint q1, int qid) -{ - Fcall fc; - Window *w; - Rune *r; - char *b, *b1; - uint q, off, boff; - int m, n, nr, nb; - - w = t->w; - wincommit(w, t); - off = x->offset; - r = fbufalloc(); - b = fbufalloc(); - b1 = emalloc(x->count); - n = 0; - if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){ - boff = w->utflastboff; - q = w->utflastq; - }else{ - /* BUG: stupid code: scan from beginning */ - boff = 0; - q = 0; - } - w->utflastqid = qid; - while(qcount){ - /* - * Updating here avoids partial rune problem: we're always on a - * char boundary. The cost is we will usually do one more read - * than we really need, but that's better than being n^2. - */ - w->utflastboff = boff; - w->utflastq = q; - nr = q1-q; - if(nr > (BUFSIZE-1)/UTFmax) - nr = (BUFSIZE-1)/UTFmax; - bufread(t->file, q, r, nr); - nb = snprint(b, BUFSIZE, "%.*S", nr, r); - if(boff >= off){ - m = nb; - if(boff+m > off+x->count) - m = off+x->count - boff; - memmove(b1+n, b, m); - n += m; - }else if(boff+nb > off){ - if(n != 0) - error("bad count in utfrune"); - m = nb - (off-boff); - if(m > x->count) - m = x->count; - memmove(b1, b+(off-boff), m); - n += m; - } - boff += nb; - q += nr; - } - fbuffree(r); - fbuffree(b); - fc.count = n; - fc.data = b1; - respond(x, &fc, nil); - free(b1); -} - -int -xfidruneread(Xfid *x, Text *t, uint q0, uint q1) -{ - Fcall fc; - Window *w; - Rune *r, junk; - char *b, *b1; - uint q, boff; - int i, rw, m, n, nr, nb; - - w = t->w; - wincommit(w, t); - r = fbufalloc(); - b = fbufalloc(); - b1 = emalloc(x->count); - n = 0; - q = q0; - boff = 0; - while(qcount){ - nr = q1-q; - if(nr > (BUFSIZE-1)/UTFmax) - nr = (BUFSIZE-1)/UTFmax; - bufread(t->file, q, r, nr); - nb = snprint(b, BUFSIZE, "%.*S", nr, r); - m = nb; - if(boff+m > x->count){ - i = x->count - boff; - /* copy whole runes only */ - m = 0; - nr = 0; - while(m < i){ - rw = chartorune(&junk, b+m); - if(m+rw > i) - break; - m += rw; - nr++; - } - if(m == 0) - break; - } - memmove(b1+n, b, m); - n += m; - boff += nb; - q += nr; - } - fbuffree(r); - fbuffree(b); - fc.count = n; - fc.data = b1; - respond(x, &fc, nil); - free(b1); - return q-q0; -} - -void -xfideventread(Xfid *x, Window *w) -{ - Fcall fc; - char *b; - int i, n; - - i = 0; - x->flushed = FALSE; - while(w->nevents == 0){ - if(i){ - if(!x->flushed) - respond(x, &fc, "window shut down"); - return; - } - w->eventx = x; - winunlock(w); - recvp(x->c); - winlock(w, 'F'); - i++; - } - - n = w->nevents; - if(n > x->count) - n = x->count; - fc.count = n; - fc.data = w->events; - respond(x, &fc, nil); - b = w->events; - w->events = estrdup(w->events+n); - free(b); - w->nevents -= n; -} - -void -xfidindexread(Xfid *x) -{ - Fcall fc; - int i, j, m, n, nmax, isbuf, cnt, off; - Window *w; - char *b; - Rune *r; - Column *c; - - qlock(&row); - nmax = 0; - for(j=0; jnw; i++){ - w = c->w[i]; - nmax += Ctlsize + w->tag.file->nc*UTFmax + 1; - } - } - nmax++; - isbuf = (nmax<=RBUFSIZE); - if(isbuf) - b = (char*)x->buf; - else - b = emalloc(nmax); - r = fbufalloc(); - n = 0; - for(j=0; jnw; i++){ - w = c->w[i]; - /* only show the currently active window of a set */ - if(w->body.file->curtext != &w->body) - continue; - winctlprint(w, b+n, 0); - n += Ctlsize; - m = min(RBUFSIZE, w->tag.file->nc); - bufread(w->tag.file, 0, r, m); - m = n + snprint(b+n, nmax-n-1, "%.*S", m, r); - while(noffset; - cnt = x->count; - if(off > n) - off = n; - if(off+cnt > n) - cnt = n-off; - fc.count = cnt; - memmove(r, b+off, cnt); - fc.data = (char*)r; - if(!isbuf) - free(b); - respond(x, &fc, nil); - fbuffree(r); -}