#include #include #include #include #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" void del(Text *, Text *, int, int, Rune *, int); void delcol(Text *, Text *, int, int, Rune *, int); void cut(Text *, Text *, int, int, Rune *, int); void exit(Text *, Text *, int, int, Rune *, int); void get(Text *, Text *, int, int, Rune *, int); void go(Text *,Text *, int, int, Rune *, int); void google(Text *,Text *, int, int, Rune *, int); void new(Text*, Text *, int, int, Rune *, int); void newcol(Text*, Text *, int, int, Rune *, int); void paste(Text *, Text *, int, int, Rune *, int); void sort(Text *, Text *, int, int, Rune *, int); void stop(Text *, Text *, int, int, Rune *, int); void debug(Text *, Text *, int, int, Rune *, int); typedef struct Exectab Exectab; struct Exectab { Rune *name; void (*fn)(Text *, Text *, int, int, Rune *, int); int flag1; int flag2; }; Exectab exectab[] = { { L"Back", go, FALSE, XXX }, { L"Cut", cut, TRUE, TRUE }, { L"Debug", debug, XXX, XXX }, { L"Del", del, XXX, XXX }, { L"Delcol", delcol, FALSE, TRUE }, { L"Exit", exit, XXX, XXX }, { L"Get", get, XXX, XXX }, { L"Google", google, XXX, XXX }, { L"New", new, XXX, XXX }, { L"Newcol", newcol, XXX, XXX }, { L"Next", go, TRUE, XXX }, { L"Paste", paste, TRUE, XXX }, { L"Snarf", cut, TRUE, FALSE }, { L"Stop", stop, XXX, XXX }, { L"Sort", sort, XXX, XXX }, { nil, nil, 0, 0 }, }; static 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(isalnum(c)) return 1; return c=='<' || c=='|' || c=='>'; } void execute(Text *t, uint aq0, uint aq1, Text *) { uint q0, q1; Rune *r, *s; Exectab *e; int c, n; 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(q1rs.nr && isexecc(c=t->rs.r[q1]) && c!=':') q1++; while(q0>0 && isexecc(c=t->rs.r[q0-1]) && c!=':') q0--; if(q1 == q0) return; } } r = runemalloc(q1-q0); runemove(r, t->rs.r+q0, q1-q0); e = lookup(r, q1-q0); if(e){ s = skipbl(r, q1-q0, &n); s = findbl(s, n, &n); s = skipbl(s, n, &n); (*e->fn)(t, seltext, e->flag1, e->flag2, s, n); } free(r); } void newcol(Text *et, Text *, int, int, Rune *, int) { Column *c; c = rowadd(et->row, nil, -1); if(c) winsettag(coladd(c, nil, nil, -1)); } void delcol(Text *t, Text *, int, int, Rune *, int) { Column *c; c = t->col; if(c==nil || colclean(c)==0) return; rowclose(c->row, c, TRUE); } void del(Text *et, Text *, int flag1, int, Rune *, int) { if(et->w==nil) return; if(flag1 || winclean(et->w, FALSE)) colclose(et->col, et->w, TRUE); } void sort(Text *et, Text *, int, int, Rune *, int) { if(et->col) colsort(et->col); } void exit(Text *, Text *, int, int, Rune *, int) { sendul(cexit, 0); threadexits(nil); } void debug(Text *, Text *, int, int, Rune *, int) { Column *c; int i, j; for(j=0; jnw; i++){ fprint(2, "Col: %d; Win: %d\n", j, i); windebug(c->w[i]); } } } void stop(Text *t, Text *, int, int, Rune *, int) { if(t==nil || t->w==nil) return; pageabort(&t->w->page); } void get(Text *t, Text *, int, int, Rune *, int) { Window *w; int dohist; if(t==nil || t->w==nil) return; w = t->w; if(w->url.rs.nr == 0) return; dohist = FALSE; if(w->page.url==nil || runestreq(w->page.url->act, w->url.rs)==FALSE) dohist = TRUE; pageget(&w->page, &w->url.rs, nil, HGet, dohist); } void go(Text *et, Text *t, int isnext, int, Rune *, int) { if(et!=nil && et->w!=nil) t = et; if(t==nil || t->w==nil) return; wingohist(t->w, isnext); } void cut(Text *, Text *t, int dosnarf, int docut, Rune *, int) { Runestr rs; uint u; if(selpage){ if(dosnarf && !docut && !eqpt(selpage->top, selpage->bot)) pagesnarf(selpage); return; } if(t==nil){ /* can only happen if seltext == nil */ return; } if(t->q0 > t->q1){ u = t->q0; t->q0 = t->q1; t->q1 =u; } if(t->q0 == t->q1) return; if(dosnarf){ rs.nr = t->q1-t->q0; rs.r = runemalloc(rs.nr); runemove(rs.r, t->rs.r+t->q0, rs.nr); putsnarf(&rs); closerunestr(&rs); } if(docut){ textdelete(t, t->q0, t->q1); textsetselect(t, t->q0, t->q0); if(t->w) textscrdraw(t); }else if(dosnarf) /* Snarf command */ argtext = t; } void paste(Text *, Text *t, int selectall, int, Rune *, int) { Runestr rs; uint q1; if(t == nil) return; getsnarf(&rs); if(rs.nr == 0) return; cut(t, t, FALSE, TRUE, nil, 0); textinsert(t, t->q0, rs.r, rs.nr); q1 = t->q0+rs.nr; if(selectall) textsetselect(t, t->q0, q1); else textsetselect(t, q1, q1); if(t->w) textscrdraw(t); closerunestr(&rs); } typedef struct Expand Expand; struct Expand { uint q0; uint q1; Rune *name; int nname; int jump; union{ Text *at; Rune *ar; }; int (*agetc)(void*, uint); int a0; int a1; }; int expand(Text *t, uint q0, uint q1, Expand *e) { memset(e, 0, sizeof *e); /* 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(q0 == q1){ while(q1rs.nr && isalnum(t->rs.r[q1])) q1++; while(q0>0 && isalnum(t->rs.r[q0-1])) q0--; } e->q0 = q0; e->q1 = q1; return q1 > q0; } void look3(Text *t, uint q0, uint q1) { Expand e; Text *ct; Runestr rs; char buf[32]; Rune *r, c; uint p; int n; ct = seltext; if(ct == nil) ct = seltext = t; if(expand(t, q0, q1, &e) == FALSE) return; if(plumbsendfd >= 0){ /* send whitespace-delimited word to plumber */ 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=t->rs.r[q0-1])!=L' ' && c!=L'\t' && c!=L'\n') q0--; while(q1rs.nr && (c=t->rs.r[q1])!=L' ' && c!=L'\t' && c!=L'\n') q1++; if(q1 == q0) return; sprint(buf, "click=%d", p-q0); } } rs.r = runemalloc(q1-q0); runemove(rs.r, t->rs.r+q0, q1-q0); rs.nr = q1-q0; if(plumbrunestr(&rs, buf) >= 0){ closerunestr(&rs); return; } /* plumber failed to match; fall through */ } if(t == ct) textsetselect(ct, e.q1, e.q1); n = e.q1 - e.q0; r = runemalloc(n); runemove(r, t->rs.r+e.q0, n); if(search(ct, r, n) && e.jump) moveto(mousectl, addpt(frptofchar(ct, ct->p0), Pt(4, ct->font->height-4))); free(r); } int search(Text *ct, Rune *r, uint n) { uint q, nb, maxn; int around; Rune *s, *b, *c; if(n==0 || n>ct->rs.nr || 2*n>RBUFSIZE) return FALSE; maxn = max(n*2, RBUFSIZE); s = runemalloc(RBUFSIZE); b = s; nb = 0; b[nb] = 0; around = 0; q = ct->q1; for(;;){ if(q >= ct->rs.nr){ 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(nbrs.nr-q){ nb = ct->rs.nr-q; if(nb >= maxn) nb = maxn-1; runemove(s, ct->rs.r+q, 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); else{ ct->q0 = q; ct->q1 = q+n; } seltext = ct; free(s); return TRUE; } if(around && q>=ct->q1) break; --nb; b++; q++; } free(s); return FALSE; } Window* lookpage(Rune *s, int n) { int i, j; Window *w; Column *c; Page *p; /* avoid terminal slash on directories */ if(n>1 && s[n-1] == '/') --n; for(j=0; jnw; i++){ w = c->w[i]; p = &w->page; if(p->url && runeeq(p->url->src.r, p->url->src.nr, s, n)) if(w->col != nil) return w; } } return nil; } Window * openpage(Page *p, Runestr *rs) { Window *w; if(!validurl(rs->r)) return nil; w = lookpage(rs->r, rs->nr); if(w){ p = &w->page; if(!p->col->safe && Dy(p->r)==0) /* window is obscured by full-column window */ colgrow(p->col, p->col->w[0], 1); }else{ w = makenewwindow(p); winsettag(w); pageget(&w->page, rs, nil, HGet, TRUE); } return w; } void plumblook(Plumbmsg *m) { Runestr rs; if(m->ndata >= BUFSIZE){ fprint(2, "insanely long file name (%d bytes) in plumb message (%.32s...)\n", m->ndata, m->data); return; } if(m->data[0] == '\0') return; bytetorunestr(m->data, &rs); openpage(nil, &rs); closerunestr(&rs); } void new(Text *et, Text *, int, int, Rune *, int) { if(et->col != nil) winsettag(coladd(et->col, nil, nil, -1)); } void google(Text *, Text *, int, int, Rune *arg, int narg) { Runestr rs; Rune *s; s = ucvt(arg); rs.r = runesmprint("http://www.google.com/search?hl=en&ie=UTF-8&q=%.*S", narg, s); rs.nr = runestrlen(rs.r); openpage(nil, &rs); free(s); closerunestr(&rs); }