Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#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 <plumb.h>
#include "flayer.h"
#include "samterm.h"

#define HSIZE   3       /* Type + short count */
Header  h;
uchar   indata[DATASIZE+1];     /* room for NUL */
uchar   outdata[DATASIZE];
short   outcount;
int     hversion;
int     exiting;

void    inmesg(Hmesg, int);
int     inshort(int);
long    inlong(int);
vlong   invlong(int);
void    hsetdot(int, long, long);
void    hmoveto(int, long);
void    hsetsnarf(int);
void    hplumb(int);
void    clrlock(void);
int     snarfswap(char*, int, char**);

void
rcv(void)
{
        int c;
        static int count = 0, errs = 0, i = 0, state = 0;

        while((c=rcvchar()) != -1)
                switch(state){
                case 0:
                        h.type = c;
                        state++;
                        break;

                case 1:
                        h.count0 = c;
                        state++;
                        break;

                case 2:
                        h.count1 = c;
                        count = h.count0|(h.count1<<8);
                        i = 0;
                        if(count > DATASIZE){
                                if(++errs < 5){
                                        dumperrmsg(count, h.type, h.count0, c);
                                        state = 0;
                                        continue;
                                }
                                fprint(2, "type %d count %d\n", h.type, count);
                                panic("count>DATASIZE");
                        }
                        if(count == 0)
                                goto zerocount;
                        state++;
                        break;

                case 3:
                        indata[i++] = c;
                        if(i == count){
                zerocount:
                                indata[i] = 0;
                                inmesg(h.type, count);
                                state = count = 0;
                                continue;
                        }
                        break;
                }
}

Text *
whichtext(int tg)
{
        int i;

        for(i=0; i<nname; i++)
                if(tag[i] == tg)
                        return text[i];
        panic("whichtext");
        return 0;
}

void
inmesg(Hmesg type, int count)
{
        Text *t;
        int i, m;
        long l;
        Flayer *lp;

        m = inshort(0);
        l = inlong(2);
        switch(type){
        case -1:
                panic("rcv error");
        default:
                fprint(2, "type %d\n", type);
                panic("rcv unknown");

        case Hversion:
                hversion = m;
                break;

        case Hbindname:
                l = invlong(2);         /* for 64-bit pointers */
                if((i=whichmenu(m)) < 0)
                        break;
                /* in case of a race, a bindname may already have occurred */
                if((t=whichtext(m)) == 0)
                        t=(Text *)l;
                else    /* let the old one win; clean up the new one */
                        while(((Text *)l)->nwin>0)
                                closeup(&((Text *)l)->l[((Text *)l)->front]);
                text[i] = t;
                text[i]->tag = m;
                break;

        case Hcurrent:
                if(whichmenu(m)<0)
                        break;
                t = whichtext(m);
                i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag;
                if(t==0 && (t = sweeptext(0, m))==0)
                        break;
                if(t->l[t->front].textfn==0)
                        panic("Hcurrent");
                lp = &t->l[t->front];
                if(i){
                        flupfront(lp);
                        flborder(lp, 0);
                        work = lp;
                }else
                        current(lp);
                break;

        case Hmovname:
                if((m=whichmenu(m)) < 0)
                        break;
                t = text[m];
                l = tag[m];
                i = name[m][0];
                text[m] = 0;    /* suppress panic in menudel */
                menudel(m);
                if(t == &cmd)
                        m = 0;
                else{
                        if (nname>0 && text[0]==&cmd)
                                m = 1;
                        else m = 0;
                        for(; m<nname; m++)
                                if(strcmp((char*)indata+2, (char*)name[m]+1)<0)
                                        break;
                }
                menuins(m, indata+2, t, i, (int)l);
                break;

        case Hgrow:
                if(whichmenu(m) >= 0)
                        hgrow(m, l, inlong(6), 1);
                break;

        case Hnewname:
                menuins(0, (uchar *)"", (Text *)0, ' ', m);
                break;

        case Hcheck0:
                i = whichmenu(m);
                if(i>=0) {
                        t = text[i];
                        if(t)
                                t->lock++;
                        outTs(Tcheck, m);
                }
                break;

        case Hcheck:
                i = whichmenu(m);
                if(i>=0) {
                        t = text[i];
                        if(t && t->lock)
                                t->lock--;
                        hcheck(m);
                }
                break;

        case Hunlock:
                clrlock();
                break;

        case Hdata:
                if(whichmenu(m) >= 0)
                        l += hdata(m, l, indata+6, count-6);
        Checkscroll:
                if(m == cmd.tag){
                        for(i=0; i<NL; i++){
                                lp = &cmd.l[i];
                                if(lp->textfn)
                                        center(lp, l>=0? l : lp->p1);
                        }
                }
                break;

        case Horigin:
                if(whichmenu(m) >= 0)
                        horigin(m, l);
                break;

        case Hunlockfile:
                if(whichmenu(m)>=0 && (t = whichtext(m))->lock){
                        --t->lock;
                        l = -1;
                        goto Checkscroll;
                }
                break;

        case Hsetdot:
                if(whichmenu(m) >= 0)
                        hsetdot(m, l, inlong(6));
                break;

        case Hgrowdata:
                if(whichmenu(m)<0)
                        break;
                hgrow(m, l, inlong(6), 0);
                whichtext(m)->lock++;   /* fake the request */
                l += hdata(m, l, indata+10, count-10);
                goto Checkscroll;

        case Hmoveto:
                if(whichmenu(m)>=0)
                        hmoveto(m, l);
                break;

        case Hclean:
                if((m = whichmenu(m)) >= 0)
                        name[m][0] = ' ';
                break;

        case Hdirty:
                if((m = whichmenu(m))>=0)
                        name[m][0] = '\'';
                break;

        case Hdelname:
                if((m=whichmenu(m)) >= 0)
                        menudel(m);
                break;

        case Hcut:
                if(whichmenu(m) >= 0)
                        hcut(m, l, inlong(6));
                break;

        case Hclose:
                if(whichmenu(m)<0 || (t = whichtext(m))==0)
                        break;
                l = t->nwin;
                for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++)
                        if(lp->textfn){
                                closeup(lp);
                                --l;
                        }
                break;

        case Hsetpat:
                setpat((char *)indata);
                break;

        case Hsetsnarf:
                hsetsnarf(m);
                break;

        case Hsnarflen:
                snarflen = inlong(0);
                break;

        case Hack:
                outT0(Tack);
                break;

        case Hexit:
                exiting = 1;
                outT0(Texit);
                threadexitsall(nil);
                break;

        case Hplumb:
                hplumb(m);
                break;
        }
}

void
setlock(void)
{
        hostlock++;
        setcursor(mousectl, cursor = &lockarrow);
}

void
clrlock(void)
{
        hasunlocked = 1;
        if(hostlock > 0)
                hostlock--;
        if(hostlock == 0)
                setcursor(mousectl, cursor=(Cursor *)0);
}

void
startfile(Text *t)
{
        outTsv(Tstartfile, t->tag, (vlong)t);   /* for 64-bit pointers */
        setlock();
}

void
startnewfile(int type, Text *t)
{
        t->tag = Untagged;
        outTv(type, (vlong)t);                  /* for 64-bit pointers */
}

int
inshort(int n)
{
        return indata[n]|(indata[n+1]<<8);
}

long
inlong(int n)
{
        return indata[n]|(indata[n+1]<<8)|
                ((long)indata[n+2]<<16)|((long)indata[n+3]<<24);
}

vlong
invlong(int n)
{
        vlong v;

        v = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];
        v = (v<<16) | (indata[n+3]<<8) | indata[n+2];
        v = (v<<16) | (indata[n+1]<<8) | indata[n];
        return v;
}

void
outT0(Tmesg type)
{
        outstart(type);
        outsend();
}

void
outTl(Tmesg type, long l)
{
        outstart(type);
        outlong(l);
        outsend();
}

void
outTs(Tmesg type, int s)
{
        outstart(type);
        outshort(s);
        outsend();
}

void
outTss(Tmesg type, int s1, int s2)
{
        outstart(type);
        outshort(s1);
        outshort(s2);
        outsend();
}

void
outTsll(Tmesg type, int s1, long l1, long l2)
{
        outstart(type);
        outshort(s1);
        outlong(l1);
        outlong(l2);
        outsend();
}

void
outTsl(Tmesg type, int s1, long l1)
{
        outstart(type);
        outshort(s1);
        outlong(l1);
        outsend();
}

void
outTsv(Tmesg type, int s1, vlong v1)
{
        outstart(type);
        outshort(s1);
        outvlong(v1);
        outsend();
}

void
outTv(Tmesg type, vlong v1)
{
        outstart(type);
        outvlong(v1);
        outsend();
}

void
outTslS(Tmesg type, int s1, long l1, Rune *s)
{
        char buf[DATASIZE*3+1];
        char *c;

        outstart(type);
        outshort(s1);
        outlong(l1);
        c = buf;
        while(*s)
                c += runetochar(c, s++);
        *c++ = 0;
        outcopy(c-buf, (uchar *)buf);
        outsend();
}

void
outTsls(Tmesg type, int s1, long l1, int s2)
{
        outstart(type);
        outshort(s1);
        outlong(l1);
        outshort(s2);
        outsend();
}

void
outstart(Tmesg type)
{
        outdata[0] = type;
        outcount = 0;
}

void
outcopy(int count, uchar *data)
{
        while(count--)
                outdata[HSIZE+outcount++] = *data++;    
}

void
outshort(int s)
{
        uchar buf[2];

        buf[0]=s;
        buf[1]=s>>8;
        outcopy(2, buf);
}

void
outlong(long l)
{
        uchar buf[4];

        buf[0]=l;
        buf[1]=l>>8;
        buf[2]=l>>16;
        buf[3]=l>>24;
        outcopy(4, buf);
}

void
outvlong(vlong v)
{
        int i;
        uchar buf[8];

        for(i = 0; i < sizeof(buf); i++){
                buf[i] = v;
                v >>= 8;
        }

        outcopy(8, buf);
}

void
outsend(void)
{
        if(outcount>DATASIZE-HSIZE)
                panic("outcount>sizeof outdata");
        outdata[1]=outcount;
        outdata[2]=outcount>>8;
        if(write(1, (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)
                panic("write error");
}


void
hsetdot(int m, long p0, long p1)
{
        Text *t = whichtext(m);
        Flayer *l = &t->l[t->front];

        flushtyping(1);
        flsetselect(l, p0, p1);
}

void
horigin(int m, long p0)
{
        Text *t = whichtext(m);
        Flayer *l = &t->l[t->front];
        long a;
        ulong n;
        Rune *r;

        if(!flprepare(l)){
                l->origin = p0;
                return;
        }
        a = p0-l->origin;
        if(a>=0 && a<l->f.nchars)
                frdelete(&l->f, 0, a);
        else if(a<0 && -a<l->f.nchars){
                r = rload(&t->rasp, p0, l->origin, &n);
                frinsert(&l->f, r, r+n, 0);
        }else
                frdelete(&l->f, 0, l->f.nchars);
        l->origin = p0;
        scrdraw(l, t->rasp.nrunes);
        if(l->visible==Some)
                flrefresh(l, l->entire, 0);
        hcheck(m);
}

void
hmoveto(int m, long p0)
{
        Text *t = whichtext(m);
        Flayer *l = &t->l[t->front];

        if(p0<l->origin || p0-l->origin>l->f.nchars*9/10)
                outTsll(Torigin, m, p0, 2L);
}

void
hcheck(int m)
{
        Flayer *l;
        Text *t;
        int reqd = 0, i;
        long n, nl, a;
        Rune *r;

        if(m == Untagged)
                return;
        t = whichtext(m);
        if(t == 0)              /* possible in a half-built window */
                return;
        for(l = &t->l[0], i = 0; i<NL; i++, l++){
                if(l->textfn==0 || !flprepare(l))       /* BUG: don't
                                                           need this if BUG below
                                                           is fixed */
                        continue;
                a = t->l[i].origin;
                n = rcontig(&t->rasp, a, a+l->f.nchars, 1);
                if(n<l->f.nchars)       /* text missing in middle of screen */
                        a+=n;
                else{                   /* text missing at end of screen? */
        Again:
                        if(l->f.lastlinefull)
                                goto Checksel;  /* all's well */
                        a = t->l[i].origin+l->f.nchars;
                        n = t->rasp.nrunes-a;
                        if(n==0)
                                goto Checksel;
                        if(n>TBLOCKSIZE)
                                n = TBLOCKSIZE;
                        n = rcontig(&t->rasp, a, a+n, 1);
                        if(n>0){
                                rload(&t->rasp, a, a+n, 0);
                                nl = l->f.nchars;
                                r = scratch;
                                flinsert(l, r, r+n, l->origin+nl);
                                if(nl == l->f.nchars)   /* made no progress */
                                        goto Checksel;
                                goto Again;
                        }
                }
                if(!reqd){
                        n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);
                        if(n <= 0)
                                panic("hcheck request==0");
                        outTsls(Trequest, m, a, (int)n);
                        outTs(Tcheck, m);
                        t->lock++;      /* for the Trequest */
                        t->lock++;      /* for the Tcheck */
                        reqd++;
                }
            Checksel:
                flsetselect(l, l->p0, l->p1);
        }
}

void
flnewlyvisible(Flayer *l)
{
        hcheck(((Text *)l->user1)->tag);
}

void
hsetsnarf(int nc)
{
        char *s2;
        char *s1;
        int i;
        int n;

        setcursor(mousectl, &deadmouse);
        s2 = alloc(nc+1);
        for(i=0; i<nc; i++)
                s2[i] = getch();
        s2[nc] = 0;
        n = snarfswap(s2, nc, &s1);
        if(n >= 0){
                if(!s1)
                        n = 0;
                if(n > SNARFSIZE){
                        s1 = strdup("<snarf too long>");
                        if (!s1)
                                panic("strdup");
                        n = strlen(s1);
                }else{
                        s1 = realloc(s1, n+1);
                        if (!s1)
                                panic("realloc");
                        s1[n] = 0;
                }
                snarflen = n;
                outTs(Tsetsnarf, n);
                if(n>0 && write(1, s1, n)!=n)
                        panic("snarf write error");
                free(s1);
        }else
                outTs(Tsetsnarf, 0);
        free(s2);
        setcursor(mousectl, cursor);
}

void
hplumb(int nc)
{
        int i;
        char *s;
        Plumbmsg *m;

        s = alloc(nc);
        for(i=0; i<nc; i++)
                s[i] = getch();
        if(plumbfd > 0){
                m = plumbunpack(s, nc);
                if(m != 0)
                        plumbsend(plumbfd, m);
                plumbfree(m);
        }
        free(s);
}

void
hgrow(int m, long a, long new, int req)
{
        int i;
        Flayer *l;
        Text *t = whichtext(m);
        long o, b;

        if(new <= 0)
                panic("hgrow");
        rresize(&t->rasp, a, 0L, new);
        for(l = &t->l[0], i = 0; i<NL; i++, l++){
                if(l->textfn == 0)
                        continue;
                o = l->origin;
                b = a-o-rmissing(&t->rasp, o, a);
                if(a < o)
                        l->origin+=new;
                if(a < l->p0)
                        l->p0+=new;
                if(a < l->p1)
                        l->p1+=new;
                /* must prevent b temporarily becoming unsigned */
                if(!req || a<o || (b>0 && b>l->f.nchars) ||
                    (l->f.nchars==0 && a-o>0))
                        continue;
                if(new>TBLOCKSIZE)
                        new = TBLOCKSIZE;
                outTsls(Trequest, m, a, (int)new);
                t->lock++;
                req = 0;
        }
}

int
hdata1(Text *t, long a, Rune *r, int len)
{
        int i;
        Flayer *l;
        long o, b;

        for(l = &t->l[0], i=0; i<NL; i++, l++){
                if(l->textfn==0)
                        continue;
                o = l->origin;
                b = a-o-rmissing(&t->rasp, o, a);
                /* must prevent b temporarily becoming unsigned */
                if(a<o || (b>0 && b>l->f.nchars))
                        continue;
                flinsert(l, r, r+len, o+b);
        }
        rdata(&t->rasp, a, a+len, r);
        rclean(&t->rasp);
        return len;
}

int
hdata(int m, long a, uchar *s, int len)
{
        int i, w;
        Text *t = whichtext(m);
        Rune buf[DATASIZE], *r;

        if(t->lock)
                --t->lock;
        if(len == 0)
                return 0;
        r = buf;
        for(i=0; i<len; i+=w,s+=w)
                w = chartorune(r++, (char*)s);
        return hdata1(t, a, buf, r-buf);
}

int
hdatarune(int m, long a, Rune *r, int len)
{
        Text *t = whichtext(m);

        if(t->lock)
                --t->lock;
        if(len == 0)
                return 0;
        return hdata1(t, a, r, len);
}

void
hcut(int m, long a, long old)
{
        Flayer *l;
        Text *t = whichtext(m);
        int i;
        long o, b;

        if(t->lock)
                --t->lock;
        for(l = &t->l[0], i = 0; i<NL; i++, l++){
                if(l->textfn == 0)
                        continue;
                o = l->origin;
                b = a-o-rmissing(&t->rasp, o, a);
                /* must prevent b temporarily becoming unsigned */
                if((b<0 || b<l->f.nchars) && a+old>=o){
                        fldelete(l, b<0? o : o+b,
                            a+old-rmissing(&t->rasp, o, a+old));
                }
                if(a+old<o)
                        l->origin-=old;
                else if(a<=o)
                        l->origin = a;
                if(a+old<l->p0)
                        l->p0-=old;
                else if(a<=l->p0)
                        l->p0 = a;
                if(a+old<l->p1)
                        l->p1-=old;
                else if(a<=l->p1)
                        l->p1 = a;
        }
        rresize(&t->rasp, a, old, 0L);
        rclean(&t->rasp);
}