ref: ef88bf19c7f048b4bcf188a3d4767375d759edbc
parent: ff84152ce1d5225a887239d3c3788c6eb6d42c53
author: glenda <[email protected]>
date: Wed Oct 20 21:50:42 EDT 2021
Cleaning out acme files
--- a/acme.c
+++ /dev/null
@@ -1,1071 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#include "dat.h"
-#include "fns.h"
- /* for generating syms in mkfile only: */
- #include <bio.h>
- #include "edit.h"
-
-void mousethread(void*);
-void keyboardthread(void*);
-void waitthread(void*);
-void xfidallocthread(void*);
-void newwindowthread(void*);
-void plumbproc(void*);
-void themeload(char *s, int n);
-
-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] = getenv("font");
- if(fontnames[0] == nil)
- fontnames[0] = "/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[0] = estrdup(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<ncol; i++){
- c = rowadd(&row, nil, -1);
- if(c==nil && i==0)
- error("initializing columns");
- }
- c = row.col[row.ncol-1];
- if(argc == 0)
- readfile(c, wdir);
- else
- for(i=0; i<argc; i++){
- p = utfrrune(argv[i], '/');
- if((p!=nil && strcmp(p, "/guide")==0) || i/WPERCOL>=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();
- return 0;
-}
-
-void
-killprocs(void)
-{
- Command *c;
-
- fsysclose();
-// if(display)
-// flushimage(display, 1);
-
- 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; i<nfontcache; i++)
- if(strcmp(name, fontcache[i]->f->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; i++)
- if(r == fontcache[i])
- break;
- if(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}
-};
-
-static char *
-readall(int f, int *osz)
-{
- int bufsz, sz, n;
- char *s;
-
- bufsz = 1023;
- s = nil;
- for(sz = 0;; sz += n){
- if(bufsz-sz < 1024){
- bufsz *= 2;
- s = realloc(s, bufsz);
- }
- if((n = readn(f, s+sz, bufsz-sz-1)) < 1)
- break;
- }
- if(n < 0 || sz < 1){
- free(s);
- return nil;
- }
- s[sz] = 0;
- *osz = sz;
-
- return s;
-}
-
-void
-iconinit(void)
-{
- Rectangle r;
- Image *tmp;
-
- /* jgs3 - Apply the themes */
- int f, sz;
- char *s;
- if((f = open("/dev/theme", OREAD|OCEXEC)) >= 0){
- if((s = readall(f, &sz)) != nil)
- themeload(s, sz);
- free(s);
- close(f);
-
- /* Menu */
- tagcols[BACK] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colmenuback].rgb<<8|0xff);
- tagcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colmenuhigh].rgb<<8|0xff);
- tagcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colmenubord].rgb<<8|0xff);
- tagcols[TEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colmenutext].rgb<<8|0xff);
- tagcols[HTEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colmenuhtext].rgb<<8|0xff);
-
- /* Body */
- textcols[BACK] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colback].rgb<<8|0xff);
- textcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colhigh].rgb<<8|0xff);
- textcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colbord].rgb<<8|0xff);
- textcols[TEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Coltext].rgb<<8|0xff);
- textcols[HTEXT] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, theme[Colhtext].rgb<<8|0xff);
-
- } else {
- /* Blue */
- tagcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite);
- tagcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
- tagcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
- tagcols[TEXT] = display->black;
- tagcols[HTEXT] = display->black;
-
- /* Yellow */
- textcols[BACK] = allocimagemix(display, DPaleyellow, DWhite);
- textcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow);
- textcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DYellowgreen);
- textcols[TEXT] = display->black;
- textcols[HTEXT] = display->black;
- }
-
- if(button){
- freeimage(button);
- freeimage(modbutton);
- freeimage(colbutton);
- }
-
- r = Rect(0, 0, Scrollwid+2, font->height+1);
- button = allocimage(display, r, screen->chan, 0, DNofill);
- draw(button, r, tagcols[BACK], nil, r.min);
- r.max.x -= 2;
- border(button, r, 2, tagcols[BORD], ZP);
-
- r = button->r;
- modbutton = allocimage(display, r, screen->chan, 0, DNofill);
- draw(modbutton, r, tagcols[BACK], nil, r.min);
- r.max.x -= 2;
- border(modbutton, r, 2, tagcols[BORD], ZP);
- r = insetrect(r, 2);
- tmp = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedblue);
- draw(modbutton, r, tmp, nil, ZP);
- freeimage(tmp);
-
- r = button->r;
- colbutton = allocimage(display, r, screen->chan, 0, DPurpleblue);
-
- but2col = allocimage(display, r, screen->chan, 1, 0xAA0000FF);
- but3col = allocimage(display, r, screen->chan, 1, 0x006600FF);
-}
-
-/*
- * /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<snarfbuf.nc; i+=n){
- n = snarfbuf.nc-i;
- if(n >= 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);
-}
-
-/* jgs1 - functions to load colors on startup */
-void
-themeload(char *s, int n)
-{
- int i;
- char *t, *a[2], *e;
- Image *newc;
- u32int rgb;
-
- if((t = malloc(n+1)) == nil)
- return;
- memmove(t, s, n);
- t[n] = 0;
-
- for(s = t; s != nil && *s; s = e){
- if((e = strchr(s, '\n')) != nil)
- *e++ = 0;
- if(tokenize(s, a, 2) == 2){
- for(i = 0; i < nelem(theme); i++) {
- if(strcmp(theme[i].id, a[0]) == 0) {
- rgb = strtoul(a[1], nil, 16);
- if((newc = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1, rgb<<8 | 0xff)) != nil) {
- theme[i].rgb = rgb;
- }
- if(new != nil){
- freeimage(col[i]);
- col[i] = newc;
- }
- break;
- }
- }
- }
- }
- free(t);
-}
-
-char *
-themestring(int *n)
-{
- char *s, *t, *e;
- int i;
-
- if((t = malloc(512)) != nil){
- s = t;
- e = s+512;
- for(i = 0; i < nelem(theme); i++)
- s = seprint(s, e, "%s\t%06ux\n", theme[i].id, theme[i].rgb);
- *n = s - t;
- }
-
- return t;
-}
--- a/addr.c
+++ /dev/null
@@ -1,291 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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 && q1<t->file->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(q1<t->file->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'<c){
- *qp = q-1;
- return r;
- }
- size = Char;
- /* fall through */
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = c -'0';
- while(q<q1){
- nc = (*getc)(a, q++);
- if(nc<'0' || '9'<nc){
- q--;
- break;
- }
- n = n*10+(nc-'0');
- }
- if(*evalp)
- r = number(md, t, r, n, dir, size, evalp);
- dir = None;
- size = Line;
- break;
- case '?':
- dir = Back;
- /* fall through */
- case '/':
- npat = 0;
- pat = nil;
- while(q<q1){
- c = (*getc)(a, q++);
- switch(c){
- case '\n':
- --q;
- goto out;
- case '\\':
- pat = runerealloc(pat, npat+1);
- pat[npat++] = c;
- if(q == q1)
- goto out;
- c = (*getc)(a, q++);
- break;
- case '/':
- goto out;
- }
- pat = runerealloc(pat, npat+1);
- pat[npat++] = c;
- }
- out:
- pat = runerealloc(pat, npat+1);
- pat[npat] = 0;
- if(*evalp)
- r = regexp(md, t, lim, r, pat, dir, evalp);
- free(pat);
- dir = None;
- size = Line;
- break;
- }
- }
- if(*evalp && dir != None)
- r = number(md, t, r, 1, dir, Line, evalp); /* do previous one */
- *qp = q;
- return r;
-}
--- a/buff.c
+++ /dev/null
@@ -1,322 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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 && q0<b->cq+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->cnc<Maxblock)
- return;
- flush(b);
- /* find block */
- if(q0 < b->cq){
- 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;
-}
--- a/cols.c
+++ /dev/null
@@ -1,561 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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(y<r.min.y && c->nw>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; i<c->nw; 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);
- 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);
- }
- 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; i<c->nw; 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);
- if(!didmouse && up)
- movetodel(w);
- }
-}
-
-void
-colcloseall(Column *c)
-{
- int i;
- Window *w;
-
- if(c == activecol)
- activecol = nil;
- textclose(&c->tag);
- for(i=0; i<c->nw; 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);
- 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; i<c->nw; 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) > font->height)
- r1.max.y += (Dy(w->r)-font->height)*new/old + 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);
- }
- 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; i<nr1 && i<nr2; i++){
- if(*r1 != *r2)
- return *r1-*r2;
- r1++;
- r2++;
- }
- return nr1-nr2;
-}
-
-void
-colsort(Column *c)
-{
- int i, y;
- Rectangle r, r1, *rp;
- Window **wp, *w;
-
- if(c->nw == 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; i<c->nw; 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; i<c->nw; 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);
- }
- 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; i<c->nw; 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;
- winresize(w, r, FALSE);
- 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);
- for(i=1; i<c->nw; 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; j<c->nw; 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; k<c->nw; k++){
- /* prune from later window */
- j = i+k;
- if(j<c->nw && 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; j<i; 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;
- if(!c->safe || !eqrect(v->r, r)){
- draw(screen, r, textcols[BACK], nil, ZP);
- winresize(v, r, c->safe);
- }
- 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 = r.min.y+Dy(w->tag.all);
- h = w->body.font->height;
- if(y2-r.max.y >= 1+h+Border){
- r.max.y += 1;
- r.max.y += h*((y2-r.max.y)/h);
- }
- /* draw window */
- if(!c->safe || !eqrect(w->r, r)){
- draw(screen, r, textcols[BACK], nil, ZP);
- winresize(w, r, c->safe);
- }
- 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; j<c->nw; j++)
- ny[j] -= (y2-r.max.y);
- }
- /* pack everyone below */
- y1 = r.max.y;
- for(j=i+1; j<c->nw; 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;
- if(!c->safe || !eqrect(v->r, r)){
- draw(screen, r, textcols[BACK], nil, ZP);
- winresize(v, r, c->safe);
- }
- if(j < c->nw-1){ /* no border on last window */
- r.min.y = v->r.max.y;
- r.max.y = r.min.y + Border;
- draw(screen, r, display->black, nil, ZP);
- }
- y1 = r.max.y;
- }
- r = w->r;
- r.min.y = y1;
- r.max.y = c->r.max.y;
- draw(screen, r, textcols[BACK], nil, ZP);
- 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; i<c->nw; i++)
- if(c->w[i] == w)
- goto Found;
- error("can't find window");
-
- Found:
- 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.y<c->w[i-1]->r.min.y) || (i<c->nw-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++;
- }
- if(!eqrect(v->r, r)){
- draw(screen, r, textcols[BACK], nil, ZP);
- winresize(v, r, c->safe);
- }
- r.min.y = v->r.max.y;
- 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);
- }
- 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; i<c->nw; 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; i<c->nw; i++)
- clean &= winclean(c->w[i], TRUE);
- return clean;
-}
--- a/dat.h
+++ /dev/null
@@ -1,636 +1,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*, 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);
-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;
- uint noredraw;
- 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);
-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
-
-/* jgs1 - theme scructs */
-enum {
- Colrioback,
-
- /* the following group has to be in order, they are used by libframe */
- Colback,
- Colhigh,
- Colbord,
- Coltext,
- Colhtext,
-
- Coltitle,
- Colltitle,
- Colhold,
- Collhold,
- Colpalehold,
- Colpaletext,
- Colsize,
-
- /* menuhit */
- Colmenubar,
- Colmenuback,
- Colmenuhigh,
- Colmenubord,
- Colmenutext,
- Colmenuhtext,
-
- Numcolors
-};
-
-typedef struct Color Color;
-
-struct Color {
- char *id;
- union {
- u32int rgb;
- char *path;
- };
- int flags;
-};
-
-static Color theme[Numcolors] = {
- [Colrioback] = {"rioback", {0x777777}, 0},
- [Colback] = {"back", {0xffffff}, 0},
- [Colhigh] = {"high", {0xcccccc}, 0},
- [Colbord] = {"border", {0x999999}, 0},
- [Coltext] = {"text", {DBlack>>8}, 0},
- [Colhtext] = {"htext", {DBlack>>8}, 0},
- [Coltitle] = {"title", {DGreygreen>>8}, 0},
- [Colltitle] = {"ltitle", {DPalegreygreen>>8}, 0},
- [Colhold] = {"hold", {DMedblue>>8}, 0},
- [Collhold] = {"lhold", {DGreyblue>>8}, 0},
- [Colpalehold] = {"palehold", {DPalegreyblue>>8}, 0},
- [Colpaletext] = {"paletext", {0x666666}, 0},
- [Colsize] = {"size", {DRed>>8}, 0},
- [Colmenubar] = {"menubar", {DDarkgreen>>8}, 1},
- [Colmenuback] = {"menuback", {0xeaffea}, 1},
- [Colmenuhigh] = {"menuhigh", {DDarkgreen>>8}, 1},
- [Colmenubord] = {"menubord", {DMedgreen>>8}, 1},
- [Colmenutext] = {"menutext", {DBlack>>8}, 1},
- [Colmenuhtext] = {"menuhtext", {0xeaffea}, 1},
-};
-
-Image *col[Numcolors];
\ No newline at end of file
--- a/disk.c
+++ /dev/null
@@ -1,142 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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");
-}
--- a/ecmd.c
+++ /dev/null
@@ -1,1366 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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<addr.r.q1; p+=ni){
- ni = addr.r.q1-p;
- if(ni > 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; m<nrp; m++){
- buf->n = 0;
- buf->r[0] = L'\0';
- sel = rp[m];
- for(i = 0; i<cp->text->n; i++)
- if((c = cp->text->r[i])=='\\' && i<cp->text->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; k<sel.r[j].q1-sel.r[j].q0; k++)
- Straddc(buf, rbuf[k]);
- }else
- Straddc(buf, c);
- }else if(c!='&')
- Straddc(buf, c);
- else{
- if(sel.r[0].q1-sel.r[0].q0>RBUFSIZE){
- 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; k<sel.r[0].q1-sel.r[0].q0; k++)
- Straddc(buf, rbuf[k]);
- }
- elogreplace(t->file, 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; i<nrp; i++){
- f->curtext->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; p = a3.r.q1){
- a3.r.q0 = a3.r.q1;
- if(p!=r.q0 || linesel.q1==p){
- a = lineaddr(1, a3, 1);
- linesel = a.r;
- }
- if(linesel.q0 >= 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; i<loopstruct.nw; i++){
- targ = &loopstruct.w[i]->body;
- 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; n<l; ){ /* always runs once */
- if(p == 0){
- if(++n != l)
- editerror("address out of range");
- }else{
- c = textreadc(f->curtext, 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;
-}
--- a/edit.c
+++ /dev/null
@@ -1,679 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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; i<f->ntext; 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'<c) /* no number defaults to 1 */
- return sign;
- while('0'<=(c=getch()) && c<='9')
- n = n*10 + (c-'0');
- ungetch();
- return sign*n;
-}
-
-int
-cmdskipbl(void)
-{
- int c;
- do
- c = getch();
- while(c==' ' || c=='\t');
- if(c >= 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;
-}
--- a/edit.h
+++ /dev/null
@@ -1,99 +1,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);
--- a/elog.c
+++ /dev/null
@@ -1,353 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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 && q0<f->elog.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<Maxstring){
- if(gap < Minstring){
- if(gap > 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 && q0<f->elog.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+nr<Maxstring){
- runemove(f->elog.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 && q0<f->elog.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<b.nr; i+=n){
- n = b.nr - i;
- if(n > 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<b.nr; i+=n){
- n = b.nr - i;
- if(n > 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;
-}
--- a/exec.c
+++ /dev/null
@@ -1,1501 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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(q1<t->file->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, n);
- 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, n);
- }
- 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; i<c->nw; 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);
- else
- 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; i<row.ncol; i++){
- c = row.col[i];
- for(j=0; j<c->nw; 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; i<n; i++)
- if(r[i] == '/'){
- promote = FALSE;
- break;
- }
- if(promote){
- t = argt;
- arg = r;
- narg = n;
- }
- }
- if(promote){
- n = narg;
- if(n <= 0){
- s = runetobyte(t->file->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; i<t->file->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; i<t->file->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; i<t->file->ntext; i++)
- t->file->text[i]->w->dirty = dirty;
- free(name);
- free(r);
- winsettag(w);
- t->file->unread = FALSE;
- for(i=0; i<t->file->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+1<d->mtime){
- 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<q1; q+=n){
- n = q1 - q;
- if(n > (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; i<f->ntext; 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);
- else
- 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; i<row.ncol; i++){
- c = row.col[i];
- for(j=0; j<c->nw; 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; i<t->w->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, 1);
- }
- }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; i<nincl; i++){
- n = runestrlen(win->incl[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);
-}
--- a/file.c
+++ /dev/null
@@ -1,310 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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; i<f->ntext; 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<p1; i+=n){
- n = p1 - i;
- if(n > 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; j<f->ntext; 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<u.n; i+=n){
- n = u.n - i;
- if(n > RBUFSIZE)
- n = RBUFSIZE;
- bufread(delta, up+i, buf, n);
- bufinsert(f, u.p0+i, buf, n);
- for(j=0; j<f->ntext; 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;
-}
--- a/fns.h
+++ /dev/null
@@ -1,96 +1,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))
--- a/fsys.c
+++ /dev/null
@@ -1,749 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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; i<m->nincl; 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; i<x->nwname; 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'<c)
- goto Regular;
- /* yes: it's a directory */
- if(w) /* name has form 27/23; get out before losing w */
- break;
- id = atoi(x->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.nwqid<x->nwname){
- 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 && i<e; i+=len){
- len = dostat(WIN(x->f->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; j<row.ncol; j++){
- c = row.col[j];
- for(k=0; k<c->nw; 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(; j<nids && i<e; i+=len){
- k = ids[j];
- sprint(dt.name, "%d", k);
- dt.qid = QID(k, Qdir);
- dt.type = QTDIR;
- dt.perm = DMDIR|0700;
- len = dostat(k, &dt, b+n, x->count-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);
-}
--- a/logf.c
+++ /dev/null
@@ -1,202 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#include <libsec.h>
-#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; i<eventlog.nf; i++) {
- if(eventlog.f[i] == x->f) {
- 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; i<eventlog.nread; i++) {
- if(eventlog.read[i] == x) {
- eventlog.read[i] = eventlog.read[--eventlog.nread];
- break;
- }
- }
-
- if(x->flushed) {
- 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; i<eventlog.nread; i++) {
- rx = eventlog.read[i];
- if(rx->tag == 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.nf; i++) {
- if(min > eventlog.f[i]->logoff)
- min = eventlog.f[i]->logoff;
- }
- if(min > eventlog.start) {
- n = min - eventlog.start;
- for(i=0; i<n; i++)
- free(eventlog.ev[i]);
- eventlog.nev -= n;
- eventlog.start += n;
- memmove(eventlog.ev, eventlog.ev+n, eventlog.nev*sizeof eventlog.ev[0]);
- }
-
- // Otherwise grow.
- if(eventlog.nev >= 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);
-}
--- a/look.c
+++ /dev/null
@@ -1,737 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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(q1<t->file->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<messagesize-1024 && plumbsend(plumbsendfd, m) >= 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(nb<n && nb!=ct->file->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; i<w->nincl && 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; m<nt; m++){
- c = b[m];
- if(c == '/')
- slash = m;
- if(c==' ' || c=='\t')
- break;
- }
- if(slash < 0)
- goto Rescue;
- runemove(b+slash+1, r, n);
- free(r);
- return cleanrname((Runestr){b, slash+1+n});
-
- Rescue:
- free(b);
- tmp = (Runestr){r, n};
- if(r)
- return cleanrname(tmp);
- return tmp;
-}
-
-int
-expandfile(Text *t, uint q0, uint q1, Expand *e)
-{
- int i, n, nname, colon, eval;
- uint amin, amax;
- Rune *r, c;
- Window *w;
- Runestr rs;
-
- amax = q1;
- if(q1 == q0){
- colon = -1;
- while(q1<t->file->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(colon<t->file->nc-1 && isaddrc(textreadc(t, colon+1))){
- q1 = colon+1;
- while(q1<t->file->nc && isaddrc(textreadc(t, q1)))
- q1++;
- }
- }
- if(q1 > q0)
- if(colon >= 0){ /* stop at white space */
- for(amax=colon+1; amax<t->file->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; i<n; i++){
- c = r[i];
- if(c==':' && nname<0){
- if(q0+i+1<t->file->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<nname; i++)
- if(!isfilec(r[i]))
- goto Isntfile;
- /*
- * See if it's a file name in <>, 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)=='<' && q1<t->file->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(q1<t->file->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; j<row.ncol; j++){
- c = row.col[j];
- for(i=0; i<c->nw; 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; j<row.ncol; j++){
- c = row.col[j];
- for(i=0; i<c->nw; 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);
- }
-}
--- a/mkfile
+++ /dev/null
@@ -1,46 +1,0 @@
-</$objtype/mkfile
-BIN=/$objtype/bin
-
-TARG=acme-themes
-
-OFILES=\
- acme.$O\
- addr.$O\
- buff.$O\
- cols.$O\
- disk.$O\
- ecmd.$O\
- edit.$O\
- elog.$O\
- exec.$O\
- file.$O\
- fsys.$O\
- logf.$O\
- look.$O\
- regx.$O\
- rows.$O\
- scrl.$O\
- text.$O\
- time.$O\
- util.$O\
- wind.$O\
- xfid.$O\
-
-HFILES=dat.h\
- edit.h\
- fns.h\
-
-UPDATE=\
- mkfile\
- $HFILES\
- ${OFILES:%.$O=%.c}\
-
-</sys/src/cmd/mkone
-
-$O.out: /$objtype/lib/libframe.a /$objtype/lib/libdraw.a /$objtype/lib/libthread.a
-
-edit.$O ecmd.$O elog.$O: edit.h
-
-syms:V:
- $CC -a acme.c > syms
- for(i in ????.c) $CC -aa $i >> syms
--- a/regx.c
+++ /dev/null
@@ -1,839 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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; i<nclass; i++)
- free(class[i]);
- nclass = 0;
- progp = program;
- backwards = FALSE;
- bstartinst = nil;
- threadcreate(realcompile, r, STACK);
- startinst = recvp(rechan);
- if(startinst == nil)
- return FALSE;
- optimize(program);
- oprogp = progp;
- backwards = TRUE;
- threadcreate(realcompile, r, STACK);
- bstartinst = recvp(rechan);
- if(bstartinst == nil)
- return FALSE;
- optimize(oprogp);
- lastregexp = runerealloc(lastregexp, nr);
- runemove(lastregexp, r, nr);
- return TRUE;
-}
-
-void
-operand(int t)
-{
- Inst *i;
- if(lastwasand)
- operator(CAT); /* catenate is implicit */
- i = newinst(t);
- if(t == CCLASS){
- if(negateclass)
- i->type = 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->type<OPERATOR)
- startchar = startinst->type;
- 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<startp || startp==eof)){
- /* Add first instruction to this list */
- sempty.r[0].q0 = p;
- if(addinst(tl, startinst, &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(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].q0<sel.r[0].q0 ||
- (sp->r[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->type<OPERATOR)
- startchar = bstartinst->type;
- 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(p<t->file->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].q1<sel.r[0].q0))
- for(i = 0; i<NRange; i++){ /* note the reversal; q0<=q1 */
- sel.r[i].q0 = sp->r[i].q1;
- sel.r[i].q1 = sp->r[i].q0;
- }
-}
--- a/rows.c
+++ /dev/null
@@ -1,736 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <bio.h>
-#include <plumb.h>
-#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(x<r.min.x && row->ncol>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; i<row->ncol; 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);
- 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; i<row->ncol; 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; i<row->ncol; 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.x<row->col[i-1]->r.min.x) || (i<row->ncol-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; i<row->ncol; 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; i<row->ncol; 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; i<row->ncol; 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; i<row->ncol; 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; i<row->ncol; i++){
- c = row->col[i];
- for(j=0; j<c->nw; j++)
- c->w[j]->body.file->dumpid = 0;
- }
- for(i=0; i<row->ncol; i++){
- c = row->col[i];
- for(j=0; j<c->nw; 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; n<t->file->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(n<m) {
- start = n;
- while(n<m && r[n]!='\n')
- n++;
- Bprint(b, "%.*S", n-start, r+start);
- if(n<m) {
- Bputc(b, 0xff); // \n in tag becomes 0xff byte (invalid UTF)
- n++;
- }
- }
- Bprint(b, "\n");
- if(dumped){
- q0 = 0;
- q1 = t->file->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<j; i++){
- percent = atoi(l+i*12);
- if(percent<0 || percent>=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(y<c->r.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; n<nr; n++){
- if(r[n] == '/')
- ns = n;
- if(r[n] == ' ')
- break;
- }
- if(dumpid == 0)
- winsetname(w, r, n);
- for(; n<nr; n++)
- if(r[n] == '|')
- break;
- wincleartag(w);
- textinsert(&w->tag, 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; n<ndumped; n++){
- rune = Bgetrune(b);
- if(rune == '\n')
- line++;
- if(rune == (Rune)Beof){
- free(r);
- Bterm(bout);
- free(bout);
- close(fd);
- goto Rescue2;
- }
- Bputrune(bout, rune);
- }
- Bterm(bout);
- free(bout);
- textload(&w->body, 0, buf, 1);
- close(fd);
- w->body.file->mod = TRUE;
- for(n=0; n<w->body.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; i<row.ncol; i++){
- c = row.col[i];
- for(j=0; j<c->nw; j++)
- (*f)(c->w[j], arg);
- }
-}
--- a/scrl.c
+++ /dev/null
@@ -1,153 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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, screen->r.max.y), 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;
- draw(b, r1, t->cols[BORD], nil, ZP);
- draw(b, r2, t->cols[BACK], 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);
-}
--- a/text.c
+++ /dev/null
@@ -1,1461 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#include <complete.h>
-#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 odx;
-
- if(Dy(r) > 0)
- r.max.y -= Dy(r)%t->font->height;
- else
- r.max.y = r.min.y;
- 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);
- return r.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; i<ndl; i++){
- dl = dlp[i];
- w = dl->wid;
- 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; i<nrow; i++){
- for(j=i; j<ndl; j+=nrow){
- dl = dlp[j];
- fileinsert(t->file, 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; i<n; i++){
- dl = emalloc(sizeof(Dirlist));
- j = strlen(dbuf[i].name);
- tmp = emalloc(j+1+1);
- memmove(tmp, dbuf[i].name, j);
- if(dbuf[i].qid.type & QTDIR)
- tmp[j++] = '/';
- tmp[j] = '\0';
- dl->r = 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<q1; q+=n){
- n = q1-q;
- if(n > 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; i<t->file->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);
- 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<n; i++)
- if(*bp++ == '\b'){
- --bp;
- initial = 0;
- tp = runemalloc(n);
- runemove(tp, r, i);
- up = tp+i;
- for(; i<n; i++){
- *up = *bp++;
- if(*up == '\b')
- if(up == tp)
- initial++;
- else
- --up;
- else
- up++;
- }
- if(initial){
- if(initial > 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; i<t->file->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<n; ){
- if(rp[i++] == '\n'){
- m++;
- if(m >= 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; i<t->file->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 && q<t->cq0+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->q0<t->file->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; i<nstr; i++)
- str[i] = textreadc(t, q++);
- q = t->q0-nstr-npath;
- for(i=0; i<npath; i++)
- path[i] = textreadc(t, q++);
- /* is path rooted? if not, we need to make it relative to window path */
- if(npath>0 && 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; i<c->nfile; 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(q0<t->file->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; i<t->file->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; i<t->file->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; i<nnb; i++){
- rr = textreadc(t, t->q0-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; i<t->file->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, selectq, &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, selectq, &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 && (q0<qe || (q0==qe && qe==t->file->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 && q<t->org))
- 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)<MINMOVE
- && abs(mp.y-mc->xy.y)<MINMOVE) {
- if(reg > 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 mp, uint *q0, uint *q1, int mode)
-{
- int c, i;
- Rune *r, *l, *p;
- uint q;
-
- *q0 = mp;
- *q1 = mp;
- 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+(*q0<t->file->nc && c=='\n');
- *q0 = q;
- if(c!='\n' || q!=0 || textreadc(t, 0)=='\n')
- (*q0)++;
- }
- return;
- }
- }
- /* try filling out word to right */
- while(*q1<t->file->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 && org<t->file->nc; i++){
- if(textreadc(t, org) == '\n'){
- org++;
- break;
- }
- org++;
- }
- }
- a = org-t->org;
- fixup = 0;
- if(a>=0 && a<t->nchars){
- 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 && -a<t->nchars){
- 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);
-}
--- a/time.c
+++ /dev/null
@@ -1,120 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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; i<nt; i++){
- x = t[i];
- x->dt -= 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;
-}
--- a/util.c
+++ /dev/null
@@ -1,485 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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; j<n; j+=w){
- if(*q < Runeself){
- w = 1;
- *s = *q++;
- }else{
- w = chartorune(s, (char*)q);
- q += w;
- }
- if(*s)
- s++;
- else if(nulls)
- *nulls = TRUE;
- }
- *nb = (char*)q-p;
- *nr = s-r;
-}
-
-void
-error(char *s)
-{
- fprint(2, "acme: %s: %r\n", s);
- remove(acmeerrorfile);
- abort();
-}
-
-Window*
-errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
-{
- Window *w;
- Rune *r;
- int i, n;
-
- r = runemalloc(ndir+8);
- if(n = ndir){ /* assign = */
- runemove(r, dir, ndir);
- r[n++] = L'/';
- }
- runemove(r+n, L"+Errors", 7);
- n += 7;
- w = lookfile(r, n);
- if(w == nil){
- if(row.ncol == 0)
- if(rowadd(&row, nil, -1) == nil)
- error("can't create column to make error window");
- w = coladd(row.col[row.ncol-1], nil, nil, -1);
- w->filemenu = 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; i<NINDENT; i++)
- w->indent[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; i<nincl; i++){
- n = runestrlen(w->incl[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; i<c->nw; 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;
-}
--- a/wind.c
+++ /dev/null
@@ -1,697 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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; i<NINDENT; i++)
- w->indent[i] = globalindent[i];
- if(clone){
- w->dirty = clone->dirty;
- for(i=0; i<NINDENT; i++)
- w->indent[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;
- w->noredraw = 1;
- textresize(&w->tag, r);
- w->noredraw = 0;
- 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 oy, mouseintag, mouseinbody;
- Point p;
- Rectangle r1;
- int y;
- Image *b;
- Rectangle br;
-
- mouseintag = ptinrect(mouse->xy, w->tag.all);
- mouseinbody = ptinrect(mouse->xy, w->body.all);
-
- w->tagtop = r;
- w->tagtop.max.y = r.min.y+font->height;
-
- r1 = r;
- r1.max.y = r1.min.y + font->height;
- r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height);
-
- if(!safe || !w->tagsafe || !eqrect(w->tag.all, 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;
- y = r1.max.y;
- if(!safe || !eqrect(w->tag.r, r1)){
- textresize(&w->tag, r1);
- 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(!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);
- 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; i<f->ntext; 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; i<w->ndl; 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; i<w->nincl; 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; i<f->ntext; 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; i<t->file->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; i<t->file->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; i<n; i++)
- if(r[i]==' ' || r[i]=='\t')
- break;
- for(; i<n; i++)
- if(r[i] == '|')
- break;
- if(i == n)
- return;
- i++;
- textdelete(&w->tag, 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; i<w->tag.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; j<n; j++)
- if(old[j] != new[j])
- break;
- q0 = w->tag.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);
-}
-
-void
-winsettag(Window *w)
-{
- int i;
- File *f;
- Window *v;
-
- f = w->body.file;
- for(i=0; i<f->ntext; 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; i<f->ntext; 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; i<w->tag.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);
- }
-}
--- a/xfid.c
+++ /dev/null
@@ -1,1082 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#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; j<row.ncol; j++){
- c = row.col[j];
- for(i=0; i<c->nw; 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; n<x->count; 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; i<nr; i++)
- if(r[i] <= ' '){
- err = "bad character in file name";
- goto out;
- }
-out:
- seq++;
- filemark(w->body.file);
- winsetname(w, 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; n<x->count; 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(q<q1 && n<x->count){
- /*
- * 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(q<q1 && n<x->count){
- 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; j<row.ncol; j++){
- c = row.col[j];
- for(i=0; i<c->nw; 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; j<row.ncol; j++){
- c = row.col[j];
- for(i=0; i<c->nw; 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(n<m && b[n]!='\n')
- n++;
- b[n++] = '\n';
- }
- }
- qunlock(&row);
- off = x->offset;
- 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);
-}