diff options
author | rsc <devnull@localhost> | 2003-09-30 17:47:44 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2003-09-30 17:47:44 +0000 |
commit | 84b1cb73b3f0837f5b959579818158fbb2b1b206 (patch) | |
tree | 7e27c119d2c2fe00a70a39985c3715b3d8ca363b | |
parent | a59ea66fa99f7b6f03eac71dc0713c33f912b6ab (diff) | |
download | plan9port-84b1cb73b3f0837f5b959579818158fbb2b1b206.tar.gz plan9port-84b1cb73b3f0837f5b959579818158fbb2b1b206.tar.bz2 plan9port-84b1cb73b3f0837f5b959579818158fbb2b1b206.zip |
Initial revision
31 files changed, 3409 insertions, 0 deletions
diff --git a/src/cmd/samterm/Make.Darwin-PowerMacintosh b/src/cmd/samterm/Make.Darwin-PowerMacintosh new file mode 100644 index 00000000..14b8d4e7 --- /dev/null +++ b/src/cmd/samterm/Make.Darwin-PowerMacintosh @@ -0,0 +1,6 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I${PREFIX}/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/cmd/samterm/Make.FreeBSD-386 b/src/cmd/samterm/Make.FreeBSD-386 new file mode 100644 index 00000000..087ed3ab --- /dev/null +++ b/src/cmd/samterm/Make.FreeBSD-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/cmd/samterm/Make.HP-UX-9000 b/src/cmd/samterm/Make.HP-UX-9000 new file mode 100644 index 00000000..edbdc111 --- /dev/null +++ b/src/cmd/samterm/Make.HP-UX-9000 @@ -0,0 +1,6 @@ +CC=cc +CFLAGS=-O -c -Ae -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/cmd/samterm/Make.Linux-386 b/src/cmd/samterm/Make.Linux-386 new file mode 100644 index 00000000..74b0252c --- /dev/null +++ b/src/cmd/samterm/Make.Linux-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/cmd/samterm/Make.NetBSD-386 b/src/cmd/samterm/Make.NetBSD-386 new file mode 100644 index 00000000..087ed3ab --- /dev/null +++ b/src/cmd/samterm/Make.NetBSD-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/cmd/samterm/Make.OSF1-alpha b/src/cmd/samterm/Make.OSF1-alpha new file mode 100644 index 00000000..3d45279b --- /dev/null +++ b/src/cmd/samterm/Make.OSF1-alpha @@ -0,0 +1,6 @@ +CC=cc +CFLAGS+=-g -c -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/cmd/samterm/Make.SunOS-sun4u b/src/cmd/samterm/Make.SunOS-sun4u new file mode 100644 index 00000000..c5fe67b8 --- /dev/null +++ b/src/cmd/samterm/Make.SunOS-sun4u @@ -0,0 +1,2 @@ +include Make.SunOS-sun4u-$(CC) +NAN=nan64.$O diff --git a/src/cmd/samterm/Make.SunOS-sun4u-cc b/src/cmd/samterm/Make.SunOS-sun4u-cc new file mode 100644 index 00000000..829301de --- /dev/null +++ b/src/cmd/samterm/Make.SunOS-sun4u-cc @@ -0,0 +1,6 @@ +CC=cc +CFLAGS+=-g -c -I. -O +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/cmd/samterm/Make.SunOS-sun4u-gcc b/src/cmd/samterm/Make.SunOS-sun4u-gcc new file mode 100644 index 00000000..5c415948 --- /dev/null +++ b/src/cmd/samterm/Make.SunOS-sun4u-gcc @@ -0,0 +1,6 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/cmd/samterm/Makefile b/src/cmd/samterm/Makefile new file mode 100644 index 00000000..1706b12b --- /dev/null +++ b/src/cmd/samterm/Makefile @@ -0,0 +1,94 @@ + +# this works in gnu make +SYSNAME:=${shell uname} +OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'} + +# this works in bsd make +SYSNAME!=uname +OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g' + +# the gnu rules will mess up bsd but not vice versa, +# hence the gnu rules come first. + +include Make.$(SYSNAME)-$(OBJTYPE) + +PREFIX=/usr/local + +NUKEFILES= + +TGZFILES= + +TARG=samterm +OFILES=\ + main.$O\ + icons.$O\ + menu.$O\ + mesg.$O\ + rasp.$O\ + scroll.$O\ + flayer.$O\ + io.$O\ + plan9.$O\ + +HFILES=\ + samterm.h\ + flayer.h\ + $(PREFIX)/include/frame.h\ + +all: $(TARG) + +install: + install -c -m 0755 samterm $(PREFIX)/bin/samterm + + +$(TARG): $(OFILES) + $(CC) -o $(TARG) $(OFILES) -L$(PREFIX)/lib -lframe -ldraw -lthread -l9 -lregexp9 -lbio -lfmt -lutf -L/usr/X11R6/lib -lX11 -lm -ldraw + + +.c.$O: + $(CC) $(CFLAGS) -I/usr/X11R6/include -I../sam -I$(PREFIX)/include $*.c + +%.$O: %.c + $(CC) $(CFLAGS) -I/usr/X11R6/include -I../sam -I$(PREFIX)/include $*.c + + +$(OFILES): $(HFILES) + +tgz: + rm -rf $(NAME)-$(VERSION) + mkdir $(NAME)-$(VERSION) + cp Makefile Make.* README LICENSE NOTICE *.[ch137] rpm.spec bundle.ports $(TGZFILES) $(NAME)-$(VERSION) + tar cf - $(NAME)-$(VERSION) | gzip >$(NAME)-$(VERSION).tgz + rm -rf $(NAME)-$(VERSION) + +clean: + rm -f $(OFILES) $(LIB) + +nuke: + rm -f $(OFILES) *.tgz *.rpm $(NUKEFILES) + +rpm: + make tgz + cp $(NAME)-$(VERSION).tgz /usr/src/RPM/SOURCES + rpm -ba rpm.spec + cp /usr/src/RPM/SRPMS/$(NAME)-$(VERSION)-1.src.rpm . + cp /usr/src/RPM/RPMS/i586/$(NAME)-$(VERSION)-1.i586.rpm . + scp *.rpm rsc@amsterdam.lcs.mit.edu:public_html/software + +PORTDIR=/usr/ports/$(PORTPLACE) + +ports: + make tgz + rm -rf $(PORTDIR) + mkdir $(PORTDIR) + cp $(NAME)-$(VERSION).tgz /usr/ports/distfiles + cat bundle.ports | (cd $(PORTDIR) && awk '$$1=="---" && $$3=="---" { ofile=$$2; next} {if(ofile) print >ofile}') + (cd $(PORTDIR); make makesum) + (cd $(PORTDIR); make) + (cd $(PORTDIR); /usr/local/bin/portlint) + rm -rf $(PORTDIR)/work + shar `find $(PORTDIR)` > ports.shar + (cd $(PORTDIR); tar cf - *) | gzip >$(NAME)-$(VERSION)-ports.tgz + scp *.tgz rsc@amsterdam.lcs.mit.edu:public_html/software + +.phony: all clean nuke install tgz rpm ports diff --git a/src/cmd/samterm/Makefile.MID b/src/cmd/samterm/Makefile.MID new file mode 100644 index 00000000..e65f98a6 --- /dev/null +++ b/src/cmd/samterm/Makefile.MID @@ -0,0 +1,22 @@ +TARG=samterm +OFILES=\ + main.$O\ + icons.$O\ + menu.$O\ + mesg.$O\ + rasp.$O\ + scroll.$O\ + flayer.$O\ + io.$O\ + plan9.$O\ + +HFILES=\ + samterm.h\ + flayer.h\ + $(PREFIX)/include/frame.h\ + +all: $(TARG) + +install: + install -c -m 0755 samterm $(PREFIX)/bin/samterm + diff --git a/src/cmd/samterm/flayer.c b/src/cmd/samterm/flayer.c new file mode 100644 index 00000000..c308993a --- /dev/null +++ b/src/cmd/samterm/flayer.c @@ -0,0 +1,485 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <mouse.h> +#include <cursor.h> +#include <keyboard.h> +#include <frame.h> +#include "flayer.h" +#include "samterm.h" + +#define DELTA 10 + +static Flayer **llist; /* front to back */ +static int nllist; +static int nlalloc; +static Rectangle lDrect; + +Vis visibility(Flayer *); +void newvisibilities(int); +void llinsert(Flayer*); +void lldelete(Flayer*); + +Image *maincols[NCOL]; +Image *cmdcols[NCOL]; + +void +flstart(Rectangle r) +{ + lDrect = r; + + /* Main text is yellowish */ + maincols[BACK] = allocimagemix(display, DPaleyellow, DWhite); + maincols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow); + maincols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DYellowgreen); + maincols[TEXT] = display->black; + maincols[HTEXT] = display->black; + + /* Command text is blueish */ + cmdcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite); + cmdcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen); + cmdcols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DPurpleblue); + cmdcols[TEXT] = display->black; + cmdcols[HTEXT] = display->black; +} + +void +flnew(Flayer *l, Rune *(*fn)(Flayer*, long, ulong*), int u0, void *u1) +{ + if(nllist == nlalloc){ + nlalloc += DELTA; + llist = realloc(llist, nlalloc*sizeof(Flayer**)); + if(llist == 0) + panic("flnew"); + } + l->textfn = fn; + l->user0 = u0; + l->user1 = u1; + l->lastsr = ZR; + llinsert(l); +} + +Rectangle +flrect(Flayer *l, Rectangle r) +{ + rectclip(&r, lDrect); + l->entire = r; + l->scroll = insetrect(r, FLMARGIN); + r.min.x = + l->scroll.max.x = r.min.x+FLMARGIN+FLSCROLLWID+(FLGAP-FLMARGIN); + return r; +} + +void +flinit(Flayer *l, Rectangle r, Font *ft, Image **cols) +{ + lldelete(l); + llinsert(l); + l->visible = All; + l->origin = l->p0 = l->p1 = 0; + frinit(&l->f, insetrect(flrect(l, r), FLMARGIN), ft, screen, cols); + l->f.maxtab = maxtab*stringwidth(ft, "0"); + newvisibilities(1); + draw(screen, l->entire, l->f.cols[BACK], nil, ZP); + scrdraw(l, 0L); + flborder(l, 0); +} + +void +flclose(Flayer *l) +{ + if(l->visible == All) + draw(screen, l->entire, display->white, nil, ZP); + else if(l->visible == Some){ + if(l->f.b == 0) + l->f.b = allocimage(display, l->entire, screen->chan, 0, DNofill); + if(l->f.b){ + draw(l->f.b, l->entire, display->white, nil, ZP); + flrefresh(l, l->entire, 0); + } + } + frclear(&l->f, 1); + lldelete(l); + if(l->f.b && l->visible!=All) + freeimage(l->f.b); + l->textfn = 0; + newvisibilities(1); +} + +void +flborder(Flayer *l, int wide) +{ + if(flprepare(l)){ + border(l->f.b, l->entire, FLMARGIN, l->f.cols[BACK], ZP); + border(l->f.b, l->entire, wide? FLMARGIN : 1, l->f.cols[BORD], ZP); + if(l->visible==Some) + flrefresh(l, l->entire, 0); + } +} + +Flayer * +flwhich(Point p) +{ + int i; + + if(p.x==0 && p.y==0) + return nllist? llist[0] : 0; + for(i=0; i<nllist; i++) + if(ptinrect(p, llist[i]->entire)) + return llist[i]; + return 0; +} + +void +flupfront(Flayer *l) +{ + int v = l->visible; + + lldelete(l); + llinsert(l); + if(v!=All) + newvisibilities(0); +} + +void +newvisibilities(int redraw) + /* if redraw false, we know it's a flupfront, and needn't + * redraw anyone becoming partially covered */ +{ + int i; + Vis ov; + Flayer *l; + + for(i = 0; i<nllist; i++){ + l = llist[i]; + l->lastsr = ZR; /* make sure scroll bar gets redrawn */ + ov = l->visible; + l->visible = visibility(l); +#define V(a, b) (((a)<<2)|((b))) + switch(V(ov, l->visible)){ + case V(Some, None): + if(l->f.b) + freeimage(l->f.b); + case V(All, None): + case V(All, Some): + l->f.b = 0; + frclear(&l->f, 0); + break; + + case V(Some, Some): + if(l->f.b==0 && redraw) + case V(None, Some): + flprepare(l); + if(l->f.b && redraw){ + flrefresh(l, l->entire, 0); + freeimage(l->f.b); + l->f.b = 0; + frclear(&l->f, 0); + } + case V(None, None): + case V(All, All): + break; + + case V(Some, All): + if(l->f.b){ + draw(screen, l->entire, l->f.b, nil, l->entire.min); + freeimage(l->f.b); + l->f.b = screen; + break; + } + case V(None, All): + flprepare(l); + break; + } + if(ov==None && l->visible!=None) + flnewlyvisible(l); + } +} + +void +llinsert(Flayer *l) +{ + int i; + for(i=nllist; i>0; --i) + llist[i]=llist[i-1]; + llist[0]=l; + nllist++; +} + +void +lldelete(Flayer *l) +{ + int i; + + for(i=0; i<nllist; i++) + if(llist[i]==l){ + --nllist; + for(; i<nllist; i++) + llist[i] = llist[i+1]; + return; + } + panic("lldelete"); +} + +void +flinsert(Flayer *l, Rune *sp, Rune *ep, long p0) +{ + if(flprepare(l)){ + frinsert(&l->f, sp, ep, p0-l->origin); + scrdraw(l, scrtotal(l)); + if(l->visible==Some) + flrefresh(l, l->entire, 0); + } +} + +void +fldelete(Flayer *l, long p0, long p1) +{ + if(flprepare(l)){ + p0 -= l->origin; + if(p0 < 0) + p0 = 0; + p1 -= l->origin; + if(p1<0) + p1 = 0; + frdelete(&l->f, p0, p1); + scrdraw(l, scrtotal(l)); + if(l->visible==Some) + flrefresh(l, l->entire, 0); + } +} + +int +flselect(Flayer *l) +{ + int ret = 0; + if(l->visible!=All) + flupfront(l); + frselect(&l->f, mousectl); + if(l->f.p0==l->f.p1){ + if(mousep->msec-l->click<Clicktime && l->f.p0+l->origin==l->p0){ + ret = 1; + l->click = 0; + }else + l->click = mousep->msec; + }else + l->click = 0; + l->p0 = l->f.p0+l->origin, l->p1 = l->f.p1+l->origin; + return ret; +} + +void +flsetselect(Flayer *l, long p0, long p1) +{ + ulong fp0, fp1; + + l->click = 0; + if(l->visible==None || !flprepare(l)){ + l->p0 = p0, l->p1 = p1; + return; + } + l->p0 = p0, l->p1 = p1; + flfp0p1(l, &fp0, &fp1); + if(fp0==l->f.p0 && fp1==l->f.p1) + return; + + if(fp1<=l->f.p0 || fp0>=l->f.p1 || l->f.p0==l->f.p1 || fp0==fp1){ + /* no overlap or trivial repainting */ + frdrawsel(&l->f, frptofchar(&l->f, l->f.p0), l->f.p0, l->f.p1, 0); + frdrawsel(&l->f, frptofchar(&l->f, fp0), fp0, fp1, 1); + goto Refresh; + } + /* the current selection and the desired selection overlap and are both non-empty */ + if(fp0 < l->f.p0){ + /* extend selection backwards */ + frdrawsel(&l->f, frptofchar(&l->f, fp0), fp0, l->f.p0, 1); + }else if(fp0 > l->f.p0){ + /* trim first part of selection */ + frdrawsel(&l->f, frptofchar(&l->f, l->f.p0), l->f.p0, fp0, 0); + } + if(fp1 > l->f.p1){ + /* extend selection forwards */ + frdrawsel(&l->f, frptofchar(&l->f, l->f.p1), l->f.p1, fp1, 1); + }else if(fp1 < l->f.p1){ + /* trim last part of selection */ + frdrawsel(&l->f, frptofchar(&l->f, fp1), fp1, l->f.p1, 0); + } + + Refresh: + l->f.p0 = fp0; + l->f.p1 = fp1; + if(l->visible==Some) + flrefresh(l, l->entire, 0); +} + +void +flfp0p1(Flayer *l, ulong *pp0, ulong *pp1) +{ + long p0 = l->p0-l->origin, p1 = l->p1-l->origin; + + if(p0 < 0) + p0 = 0; + if(p1 < 0) + p1 = 0; + if(p0 > l->f.nchars) + p0 = l->f.nchars; + if(p1 > l->f.nchars) + p1 = l->f.nchars; + *pp0 = p0; + *pp1 = p1; +} + +Rectangle +rscale(Rectangle r, Point old, Point new) +{ + r.min.x = r.min.x*new.x/old.x; + r.min.y = r.min.y*new.y/old.y; + r.max.x = r.max.x*new.x/old.x; + r.max.y = r.max.y*new.y/old.y; + return r; +} + +void +flresize(Rectangle dr) +{ + int i; + Flayer *l; + Frame *f; + Rectangle r, olDrect; + int move; + + olDrect = lDrect; + lDrect = dr; + move = 0; + /* no moving on rio; must repaint */ + if(0 && Dx(dr)==Dx(olDrect) && Dy(dr)==Dy(olDrect)) + move = 1; + else + draw(screen, lDrect, display->white, nil, ZP); + for(i=0; i<nllist; i++){ + l = llist[i]; + l->lastsr = ZR; + f = &l->f; + if(move) + r = rectaddpt(rectsubpt(l->entire, olDrect.min), dr.min); + else{ + r = rectaddpt(rscale(rectsubpt(l->entire, olDrect.min), + subpt(olDrect.max, olDrect.min), + subpt(dr.max, dr.min)), dr.min); + if(l->visible==Some && f->b){ + freeimage(f->b); + frclear(f, 0); + } + f->b = 0; + if(l->visible!=None) + frclear(f, 0); + } + if(!rectclip(&r, dr)) + panic("flresize"); + if(r.max.x-r.min.x<100) + r.min.x = dr.min.x; + if(r.max.x-r.min.x<100) + r.max.x = dr.max.x; + if(r.max.y-r.min.y<2*FLMARGIN+f->font->height) + r.min.y = dr.min.y; + if(r.max.y-r.min.y<2*FLMARGIN+f->font->height) + r.max.y = dr.max.y; + if(!move) + l->visible = None; + frsetrects(f, insetrect(flrect(l, r), FLMARGIN), f->b); + if(!move && f->b) + scrdraw(l, scrtotal(l)); + } + newvisibilities(1); +} + +int +flprepare(Flayer *l) +{ + Frame *f; + ulong n; + Rune *r; + + if(l->visible == None) + return 0; + f = &l->f; + if(f->b == 0){ + if(l->visible == All) + f->b = screen; + else if((f->b = allocimage(display, l->entire, screen->chan, 0, 0))==0) + return 0; + draw(f->b, l->entire, f->cols[BACK], nil, ZP); + border(f->b, l->entire, l==llist[0]? FLMARGIN : 1, f->cols[BORD], ZP); + n = f->nchars; + frinit(f, f->entire, f->font, f->b, 0); + f->maxtab = maxtab*stringwidth(f->font, "0"); + r = (*l->textfn)(l, n, &n); + frinsert(f, r, r+n, (ulong)0); + frdrawsel(f, frptofchar(f, f->p0), f->p0, f->p1, 0); + flfp0p1(l, &f->p0, &f->p1); + frdrawsel(f, frptofchar(f, f->p0), f->p0, f->p1, 1); + l->lastsr = ZR; + scrdraw(l, scrtotal(l)); + } + return 1; +} + +static int somevis, someinvis, justvis; + +Vis +visibility(Flayer *l) +{ + somevis = someinvis = 0; + justvis = 1; + flrefresh(l, l->entire, 0); + justvis = 0; + if(somevis==0) + return None; + if(someinvis==0) + return All; + return Some; +} + +void +flrefresh(Flayer *l, Rectangle r, int i) +{ + Flayer *t; + Rectangle s; + + Top: + if((t=llist[i++]) == l){ + if(!justvis) + draw(screen, r, l->f.b, nil, r.min); + somevis = 1; + }else{ + if(!rectXrect(t->entire, r)) + goto Top; /* avoid stacking unnecessarily */ + if(t->entire.min.x>r.min.x){ + s = r; + s.max.x = t->entire.min.x; + flrefresh(l, s, i); + r.min.x = t->entire.min.x; + } + if(t->entire.min.y>r.min.y){ + s = r; + s.max.y = t->entire.min.y; + flrefresh(l, s, i); + r.min.y = t->entire.min.y; + } + if(t->entire.max.x<r.max.x){ + s = r; + s.min.x = t->entire.max.x; + flrefresh(l, s, i); + r.max.x = t->entire.max.x; + } + if(t->entire.max.y<r.max.y){ + s = r; + s.min.y = t->entire.max.y; + flrefresh(l, s, i); + r.max.y = t->entire.max.y; + } + /* remaining piece of r is blocked by t; forget about it */ + someinvis = 1; + } +} diff --git a/src/cmd/samterm/flayer.h b/src/cmd/samterm/flayer.h new file mode 100644 index 00000000..41306f79 --- /dev/null +++ b/src/cmd/samterm/flayer.h @@ -0,0 +1,50 @@ +typedef enum Vis{ + None=0, + Some, + All, +}Vis; + +enum{ + Clicktime=1000, /* one second */ +}; + +typedef struct Flayer Flayer; + +struct Flayer +{ + Frame f; + long origin; /* offset of first char in flayer */ + long p0, p1; + long click; /* time at which selection click occurred, in HZ */ + Rune *(*textfn)(Flayer*, long, ulong*); + int user0; + void *user1; + Rectangle entire; + Rectangle scroll; + Rectangle lastsr; /* geometry of scrollbar when last drawn */ + Vis visible; +}; + +void flborder(Flayer*, int); +void flclose(Flayer*); +void fldelete(Flayer*, long, long); +void flfp0p1(Flayer*, ulong*, ulong*); +void flinit(Flayer*, Rectangle, Font*, Image**); +void flinsert(Flayer*, Rune*, Rune*, long); +void flnew(Flayer*, Rune *(*fn)(Flayer*, long, ulong*), int, void*); +int flprepare(Flayer*); +Rectangle flrect(Flayer*, Rectangle); +void flrefresh(Flayer*, Rectangle, int); +void flresize(Rectangle); +int flselect(Flayer*); +void flsetselect(Flayer*, long, long); +void flstart(Rectangle); +void flupfront(Flayer*); +Flayer *flwhich(Point); + +#define FLMARGIN 4 +#define FLSCROLLWID 12 +#define FLGAP 4 + +extern Image *maincols[NCOL]; +extern Image *cmdcols[NCOL]; diff --git a/src/cmd/samterm/io.c b/src/cmd/samterm/io.c new file mode 100644 index 00000000..dfdfd9ce --- /dev/null +++ b/src/cmd/samterm/io.c @@ -0,0 +1,293 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <mouse.h> +#include <cursor.h> +#include <keyboard.h> +#include <frame.h> +#include "flayer.h" +#include "samterm.h" + +int cursorfd; +int plumbfd = -1; +int input; +int got; +int block; +int kbdc; +int resized; +uchar *hostp; +uchar *hoststop; +uchar *plumbbase; +uchar *plumbp; +uchar *plumbstop; +Channel *plumbc; +Channel *hostc; +Mousectl *mousectl; +Mouse *mousep; +Keyboardctl *keyboardctl; +void panic(char*); + +void +initio(void) +{ + threadsetname("main"); + mousectl = initmouse(nil, display->image); + if(mousectl == nil){ + fprint(2, "samterm: mouse init failed: %r\n"); + threadexitsall("mouse"); + } + mousep = &mousectl->m; + keyboardctl = initkeyboard(nil); + if(keyboardctl == nil){ + fprint(2, "samterm: keyboard init failed: %r\n"); + threadexitsall("kbd"); + } + hoststart(); + if(plumbstart() < 0) + extstart(); +} + +void +getmouse(void) +{ + if(readmouse(mousectl) < 0) + panic("mouse"); +} + +void +mouseunblock(void) +{ + got &= ~(1<<RMouse); +} + +void +kbdblock(void) +{ /* ca suffit */ + block = (1<<RKeyboard)|(1<<RPlumb); +} + +int +button(int but) +{ + getmouse(); + return mousep->buttons&(1<<(but-1)); +} + +/* +void +externload(int i) +{ + plumbbase = malloc(plumbbuf[i].n); + if(plumbbase == 0) + return; + memmove(plumbbase, plumbbuf[i].data, plumbbuf[i].n); + plumbp = plumbbase; + plumbstop = plumbbase + plumbbuf[i].n; + got |= 1<<RPlumb; +} +*/ + +int +waitforio(void) +{ + Alt alts[NRes+1]; + Rune r; + int i; + ulong type; + +again: + + alts[RPlumb].c = plumbc; + alts[RPlumb].v = &i; + alts[RPlumb].op = CHANRCV; + if((block & (1<<RPlumb)) || plumbc == nil) + alts[RPlumb].op = CHANNOP; + + alts[RHost].c = hostc; + alts[RHost].v = &i; + alts[RHost].op = CHANRCV; + if(block & (1<<RHost)) + alts[RHost].op = CHANNOP; + + alts[RKeyboard].c = keyboardctl->c; + alts[RKeyboard].v = &r; + alts[RKeyboard].op = CHANRCV; + if(block & (1<<RKeyboard)) + alts[RKeyboard].op = CHANNOP; + + alts[RMouse].c = mousectl->c; + alts[RMouse].v = &mousectl->m; + alts[RMouse].op = CHANRCV; + if(block & (1<<RMouse)) + alts[RMouse].op = CHANNOP; + + alts[RResize].c = mousectl->resizec; + alts[RResize].v = nil; + alts[RResize].op = CHANRCV; + if(block & (1<<RResize)) + alts[RResize].op = CHANNOP; + + alts[NRes].op = CHANEND; + + if(got & ~block) + return got & ~block; + flushimage(display, 1); + type = alt(alts); + switch(type){ + case RHost: + hostp = hostbuf[i].data; + hoststop = hostbuf[i].data + hostbuf[i].n; + block = 0; + break; +/* + case RPlumb: + externload(i); + break; +*/ + case RKeyboard: + kbdc = r; + break; + case RMouse: + break; + case RResize: + resized = 1; + /* do the resize in line if we've finished initializing and we're not in a blocking state */ + if(hasunlocked && block==0 && RESIZED()) + resize(); + goto again; + } + got |= 1<<type; + return got; +} + +int +rcvchar(void) +{ + int c; + + if(!(got & (1<<RHost))) + return -1; + c = *hostp++; + if(hostp == hoststop) + got &= ~(1<<RHost); + return c; +} + +char* +rcvstring(void) +{ + *hoststop = 0; + got &= ~(1<<RHost); + return (char*)hostp; +} + +int +getch(void) +{ + int c; + + while((c = rcvchar()) == -1){ + block = ~(1<<RHost); + waitforio(); + block = 0; + } + return c; +} + +int +externchar(void) +{ + Rune r; + + loop: + if(got & ((1<<RPlumb) & ~block)){ + plumbp += chartorune(&r, (char*)plumbp); + if(plumbp >= plumbstop){ + got &= ~(1<<RPlumb); + free(plumbbase); + } + if(r == 0) + goto loop; + return r; + } + return -1; +} + +int kpeekc = -1; +int +ecankbd(void) +{ + Rune r; + + if(kpeekc >= 0) + return 1; + if(nbrecv(keyboardctl->c, &r) > 0){ + kpeekc = r; + return 1; + } + return 0; +} + +int +ekbd(void) +{ + int c; + Rune r; + + if(kpeekc >= 0){ + c = kpeekc; + kpeekc = -1; + return c; + } + if(recv(keyboardctl->c, &r) < 0){ + fprint(2, "samterm: keybard recv error: %r\n"); + panic("kbd"); + } + return r; +} + +int +kbdchar(void) +{ + int c, i; + + c = externchar(); + if(c > 0) + return c; + if(got & (1<<RKeyboard)){ + c = kbdc; + kbdc = -1; + got &= ~(1<<RKeyboard); + return c; + } +#if 0 + while(plumbc!=nil && nbrecv(plumbc, &i)>0){ + externload(i); + c = externchar(); + if(c > 0) + return c; + } +#endif + if(!ecankbd()) + return -1; + return ekbd(); +} + +int +qpeekc(void) +{ + return kbdc; +} + +int +RESIZED(void) +{ + if(resized){ + if(getwindow(display, Refnone) < 0) + panic("can't reattach to window"); + resized = 0; + return 1; + } + return 0; +} diff --git a/src/cmd/samterm/main.c b/src/cmd/samterm/main.c new file mode 100644 index 00000000..ef958d78 --- /dev/null +++ b/src/cmd/samterm/main.c @@ -0,0 +1,585 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <mouse.h> +#include <cursor.h> +#include <keyboard.h> +#include <frame.h> +#include "flayer.h" +#include "samterm.h" + +Text cmd; +Rune *scratch; +long nscralloc; +Cursor *cursor; +Flayer *which = 0; +Flayer *work = 0; +long snarflen; +long typestart = -1; +long typeend = -1; +long typeesc = -1; +long modified = 0; /* strange lookahead for menus */ +char hostlock = 1; +char hasunlocked = 0; +int maxtab = 8; + +void +threadmain(int argc, char *argv[]) +{ + int i, got, scr; + Text *t; + Rectangle r; + Flayer *nwhich; + + getscreen(argc, argv); + iconinit(); + initio(); + scratch = alloc(100*RUNESIZE); + nscralloc = 100; + r = screen->r; + r.max.y = r.min.y+Dy(r)/5; + flstart(screen->clipr); + rinit(&cmd.rasp); + flnew(&cmd.l[0], gettext, 1, &cmd); + flinit(&cmd.l[0], r, font, cmdcols); + cmd.nwin = 1; + which = &cmd.l[0]; + cmd.tag = Untagged; + outTs(Tversion, VERSION); + startnewfile(Tstartcmdfile, &cmd); + + got = 0; + for(;;got = waitforio()){ + if(hasunlocked && RESIZED()) + resize(); + if(got&(1<<RHost)) + rcv(); + if(got&(1<<RPlumb)){ + for(i=0; cmd.l[i].textfn==0; i++) + ; + current(&cmd.l[i]); + flsetselect(which, cmd.rasp.nrunes, cmd.rasp.nrunes); + type(which, RPlumb); + } + if(got&(1<<RKeyboard)) + if(which) + type(which, RKeyboard); + else + kbdblock(); + if(got&(1<<RMouse)){ + if(hostlock==2 || !ptinrect(mousep->xy, screen->r)){ + mouseunblock(); + continue; + } + nwhich = flwhich(mousep->xy); + scr = which && ptinrect(mousep->xy, which->scroll); + if(mousep->buttons) + flushtyping(1); + if(mousep->buttons&1){ + if(nwhich){ + if(nwhich!=which) + current(nwhich); + else if(scr) + scroll(which, 1); + else{ + t=(Text *)which->user1; + if(flselect(which)){ + outTsl(Tdclick, t->tag, which->p0); + t->lock++; + }else if(t!=&cmd) + outcmd(); + } + } + }else if((mousep->buttons&2) && which){ + if(scr) + scroll(which, 2); + else + menu2hit(); + }else if((mousep->buttons&4)){ + if(scr) + scroll(which, 3); + else + menu3hit(); + } + mouseunblock(); + } + } +} + + +void +resize(void) +{ + int i; + + flresize(screen->clipr); + for(i = 0; i<nname; i++) + if(text[i]) + hcheck(text[i]->tag); +} + +void +current(Flayer *nw) +{ + Text *t; + + if(which) + flborder(which, 0); + if(nw){ + flushtyping(1); + flupfront(nw); + flborder(nw, 1); + buttons(Up); + t = (Text *)nw->user1; + t->front = nw-&t->l[0]; + if(t != &cmd) + work = nw; + } + which = nw; +} + +void +closeup(Flayer *l) +{ + Text *t=(Text *)l->user1; + int m; + + m = whichmenu(t->tag); + if(m < 0) + return; + flclose(l); + if(l == which){ + which = 0; + current(flwhich(Pt(0, 0))); + } + if(l == work) + work = 0; + if(--t->nwin == 0){ + rclear(&t->rasp); + free((uchar *)t); + text[m] = 0; + }else if(l == &t->l[t->front]){ + for(m=0; m<NL; m++) /* find one; any one will do */ + if(t->l[m].textfn){ + t->front = m; + return; + } + panic("close"); + } +} + +Flayer * +findl(Text *t) +{ + int i; + for(i = 0; i<NL; i++) + if(t->l[i].textfn==0) + return &t->l[i]; + return 0; +} + +void +duplicate(Flayer *l, Rectangle r, Font *f, int close) +{ + Text *t=(Text *)l->user1; + Flayer *nl = findl(t); + Rune *rp; + ulong n; + + if(nl){ + flnew(nl, gettext, l->user0, (char *)t); + flinit(nl, r, f, l->f.cols); + nl->origin = l->origin; + rp = (*l->textfn)(l, l->f.nchars, &n); + flinsert(nl, rp, rp+n, l->origin); + flsetselect(nl, l->p0, l->p1); + if(close){ + flclose(l); + if(l==which) + which = 0; + }else + t->nwin++; + current(nl); + hcheck(t->tag); + } + setcursor(mousectl, cursor); +} + +void +buttons(int updown) +{ + while(((mousep->buttons&7)!=0) != updown) + getmouse(); +} + +int +getr(Rectangle *rp) +{ + Point p; + Rectangle r; + + *rp = getrect(3, mousectl); + if(rp->max.x && rp->max.x-rp->min.x<=5 && rp->max.y-rp->min.y<=5){ + p = rp->min; + r = cmd.l[cmd.front].entire; + *rp = screen->r; + if(cmd.nwin==1){ + if (p.y <= r.min.y) + rp->max.y = r.min.y; + else if (p.y >= r.max.y) + rp->min.y = r.max.y; + if (p.x <= r.min.x) + rp->max.x = r.min.x; + else if (p.x >= r.max.x) + rp->min.x = r.max.x; + } + } + return rectclip(rp, screen->r) && + rp->max.x-rp->min.x>100 && rp->max.y-rp->min.y>40; +} + +void +snarf(Text *t, int w) +{ + Flayer *l = &t->l[w]; + + if(l->p1>l->p0){ + snarflen = l->p1-l->p0; + outTsll(Tsnarf, t->tag, l->p0, l->p1); + } +} + +void +cut(Text *t, int w, int save, int check) +{ + long p0, p1; + Flayer *l; + + l = &t->l[w]; + p0 = l->p0; + p1 = l->p1; + if(p0 == p1) + return; + if(p0 < 0) + panic("cut"); + if(save) + snarf(t, w); + outTsll(Tcut, t->tag, p0, p1); + flsetselect(l, p0, p0); + t->lock++; + hcut(t->tag, p0, p1-p0); + if(check) + hcheck(t->tag); +} + +void +paste(Text *t, int w) +{ + if(snarflen){ + cut(t, w, 0, 0); + t->lock++; + outTsl(Tpaste, t->tag, t->l[w].p0); + } +} + +void +scrorigin(Flayer *l, int but, long p0) +{ + Text *t=(Text *)l->user1; + + switch(but){ + case 1: + outTsll(Torigin, t->tag, l->origin, p0); + break; + case 2: + outTsll(Torigin, t->tag, p0, 1L); + break; + case 3: + horigin(t->tag,p0); + } +} + +int +alnum(int c) +{ + /* + * Hard to get absolutely right. Use what we know about ASCII + * and assume anything above the Latin control characters is + * potentially an alphanumeric. + */ + if(c<=' ') + return 0; + if(0x7F<=c && c<=0xA0) + return 0; + if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) + return 0; + return 1; +} + +int +raspc(Rasp *r, long p) +{ + ulong n; + rload(r, p, p+1, &n); + if(n) + return scratch[0]; + return 0; +} + +long +ctlw(Rasp *r, long o, long p) +{ + int c; + + if(--p < o) + return o; + if(raspc(r, p)=='\n') + return p; + for(; p>=o && !alnum(c=raspc(r, p)); --p) + if(c=='\n') + return p+1; + for(; p>o && alnum(raspc(r, p-1)); --p) + ; + return p>=o? p : o; +} + +long +ctlu(Rasp *r, long o, long p) +{ + for(; p-1>=o && raspc(r, p-1)!='\n'; --p) + ; + return p>=o? p : o; +} + +int +center(Flayer *l, long a) +{ + Text *t; + + t = l->user1; + if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){ + if(a > t->rasp.nrunes) + a = t->rasp.nrunes; + outTsll(Torigin, t->tag, a, 2L); + return 1; + } + return 0; +} + +int +onethird(Flayer *l, long a) +{ + Text *t; + Rectangle s; + long lines; + + t = l->user1; + if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){ + if(a > t->rasp.nrunes) + a = t->rasp.nrunes; + s = insetrect(l->scroll, 1); + lines = ((s.max.y-s.min.y)/l->f.font->height+1)/3; + if (lines < 2) + lines = 2; + outTsll(Torigin, t->tag, a, lines); + return 1; + } + return 0; +} + +void +flushtyping(int clearesc) +{ + Text *t; + ulong n; + + if(clearesc) + typeesc = -1; + if(typestart == typeend) { + modified = 0; + return; + } + t = which->user1; + if(t != &cmd) + modified = 1; + rload(&t->rasp, typestart, typeend, &n); + scratch[n] = 0; + if(t==&cmd && typeend==t->rasp.nrunes && scratch[typeend-typestart-1]=='\n'){ + setlock(); + outcmd(); + } + outTslS(Ttype, t->tag, typestart, scratch); + typestart = -1; + typeend = -1; +} + +#define SCROLLKEY Kdown +#define BACKSCROLLKEY Kup +#define ESC 0x1B + +void +type(Flayer *l, int res) /* what a bloody mess this is */ +{ + Text *t = (Text *)l->user1; + Rune buf[100]; + Rune *p = buf; + int c, backspacing; + long a, a0; + int scrollkey; + + scrollkey = 0; + if(res == RKeyboard) + scrollkey = (qpeekc()==SCROLLKEY || qpeekc()==BACKSCROLLKEY); /* ICK */ + + if(hostlock || t->lock){ + kbdblock(); + return; + } + a = l->p0; + if(a!=l->p1 && !scrollkey){ + flushtyping(1); + cut(t, t->front, 1, 1); + return; /* it may now be locked */ + } + backspacing = 0; + while((c = kbdchar())>0){ + if(res == RKeyboard){ + if(c==SCROLLKEY || c==BACKSCROLLKEY || c==ESC) + break; + /* backspace, ctrl-u, ctrl-w, del */ + if(c=='\b' || c==0x15 || c==0x17 || c==0x7F){ + backspacing = 1; + break; + } + } + *p++ = c; + if(c == '\n' || p >= buf+sizeof(buf)/sizeof(buf[0])) + break; + } + if(p > buf){ + if(typestart < 0) + typestart = a; + if(typeesc < 0) + typeesc = a; + hgrow(t->tag, a, p-buf, 0); + t->lock++; /* pretend we Trequest'ed for hdatarune*/ + hdatarune(t->tag, a, buf, p-buf); + a += p-buf; + l->p0 = a; + l->p1 = a; + typeend = a; + if(c=='\n' || typeend-typestart>100) + flushtyping(0); + onethird(l, a); + } + if(c == SCROLLKEY){ + flushtyping(0); + center(l, l->origin+l->f.nchars+1); + /* backspacing immediately after outcmd(): sorry */ + }else if(c == BACKSCROLLKEY){ + flushtyping(0); + a0 = l->origin-l->f.nchars; + if(a0 < 0) + a0 = 0; + center(l, a0); + }else if(backspacing && !hostlock){ + if(l->f.p0>0 && a>0){ + switch(c){ + case '\b': + case 0x7F: /* del */ + l->p0 = a-1; + break; + case 0x15: /* ctrl-u */ + l->p0 = ctlu(&t->rasp, l->origin, a); + break; + case 0x17: /* ctrl-w */ + l->p0 = ctlw(&t->rasp, l->origin, a); + break; + } + l->p1 = a; + if(l->p1 != l->p0){ + /* cut locally if possible */ + if(typestart<=l->p0 && l->p1<=typeend){ + t->lock++; /* to call hcut */ + hcut(t->tag, l->p0, l->p1-l->p0); + /* hcheck is local because we know rasp is contiguous */ + hcheck(t->tag); + }else{ + flushtyping(0); + cut(t, t->front, 0, 1); + } + } + if(typeesc >= l->p0) + typeesc = l->p0; + if(typestart >= 0){ + if(typestart >= l->p0) + typestart = l->p0; + typeend = l->p0; + if(typestart == typeend){ + typestart = -1; + typeend = -1; + modified = 0; + } + } + } + }else{ + if(c==ESC && typeesc>=0){ + l->p0 = typeesc; + l->p1 = a; + flushtyping(1); + } + for(l=t->l; l<&t->l[NL]; l++) + if(l->textfn) + flsetselect(l, l->p0, l->p1); + } +} + + +void +outcmd(void){ + if(work) + outTsll(Tworkfile, ((Text *)work->user1)->tag, work->p0, work->p1); +} + +void +panic(char *s) +{ + panic1(display, s); +} + +void +panic1(Display *d, char *s) +{ + fprint(2, "samterm:panic: "); + perror(s); + abort(); +} + +Rune* +gettext(Flayer *l, long n, ulong *np) +{ + Text *t; + + t = l->user1; + rload(&t->rasp, l->origin, l->origin+n, np); + return scratch; +} + +long +scrtotal(Flayer *l) +{ + return ((Text *)l->user1)->rasp.nrunes; +} + +void* +alloc(ulong n) +{ + void *p; + + p = malloc(n); + if(p == 0) + panic("alloc"); + memset(p, 0, n); + return p; +} diff --git a/src/cmd/samterm/menu.c b/src/cmd/samterm/menu.c new file mode 100644 index 00000000..18070a8f --- /dev/null +++ b/src/cmd/samterm/menu.c @@ -0,0 +1,403 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <mouse.h> +#include <cursor.h> +#include <keyboard.h> +#include <frame.h> +#include "flayer.h" +#include "samterm.h" + +uchar **name; /* first byte is ' ' or '\'': modified state */ +Text **text; /* pointer to Text associated with file */ +ushort *tag; /* text[i].tag, even if text[i] not defined */ +int nname; +int mname; +int mw; + +char *genmenu3(int); +char *genmenu2(int); +char *genmenu2c(int); + +enum Menu2 +{ + Cut, + Paste, + Snarf, + Plumb, + Look, + Exch, + Search, + NMENU2 = Search, + Send = Search, + NMENU2C +}; + +enum Menu3 +{ + New, + Zerox, + Resize, + Close, + Write, + NMENU3 +}; + +char *menu2str[] = { + "cut", + "paste", + "snarf", + "plumb", + "look", + "<rio>", + 0, /* storage for last pattern */ +}; + +char *menu3str[] = { + "new", + "zerox", + "resize", + "close", + "write", +}; + +Menu menu2 = {0, genmenu2}; +Menu menu2c ={0, genmenu2c}; +Menu menu3 = {0, genmenu3}; + +void +menu2hit(void) +{ + Text *t=(Text *)which->user1; + int w = which-t->l; + int m; + + if(hversion==0 || plumbfd<0) + menu2str[Plumb] = "(plumb)"; + m = menuhit(2, mousectl, t==&cmd? &menu2c : &menu2, nil); + if(hostlock || t->lock) + return; + + switch(m){ + case Cut: + cut(t, w, 1, 1); + break; + + case Paste: + paste(t, w); + break; + + case Snarf: + snarf(t, w); + break; + + case Plumb: + if(hversion > 0) + outTsll(Tplumb, t->tag, which->p0, which->p1); + break; + + case Exch: + snarf(t, w); + outT0(Tstartsnarf); + setlock(); + break; + + case Look: + outTsll(Tlook, t->tag, which->p0, which->p1); + setlock(); + break; + + case Search: + outcmd(); + if(t==&cmd) + outTsll(Tsend, 0 /*ignored*/, which->p0, which->p1); + else + outT0(Tsearch); + setlock(); + break; + } +} + +void +menu3hit(void) +{ + Rectangle r; + Flayer *l; + int m, i; + Text *t; + + mw = -1; + m = menuhit(3, mousectl, &menu3, nil); + switch(m){ + case -1: + break; + + case New: + if(!hostlock) + sweeptext(1, 0); + break; + + case Zerox: + case Resize: + if(!hostlock){ + setcursor(mousectl, &bullseye); + buttons(Down); + if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && getr(&r)) + duplicate(l, r, l->f.font, m==Resize); + else + setcursor(mousectl, cursor); + buttons(Up); + } + break; + + case Close: + if(!hostlock){ + setcursor(mousectl, &bullseye); + buttons(Down); + if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && !hostlock){ + t=(Text *)l->user1; + if (t->nwin>1) + closeup(l); + else if(t!=&cmd) { + outTs(Tclose, t->tag); + setlock(); + } + } + setcursor(mousectl, cursor); + buttons(Up); + } + break; + + case Write: + if(!hostlock){ + setcursor(mousectl, &bullseye); + buttons(Down); + if((mousep->buttons&4) && (l = flwhich(mousep->xy))){ + outTs(Twrite, ((Text *)l->user1)->tag); + setlock(); + }else + setcursor(mousectl, cursor); + buttons(Up); + } + break; + + default: + if(t = text[m-NMENU3]){ + i = t->front; + if(t->nwin==0 || t->l[i].textfn==0) + return; /* not ready yet; try again later */ + if(t->nwin>1 && which==&t->l[i]) + do + if(++i==NL) + i = 0; + while(i!=t->front && t->l[i].textfn==0); + current(&t->l[i]); + }else if(!hostlock) + sweeptext(0, tag[m-NMENU3]); + break; + } +} + + +Text * +sweeptext(int new, int tag) +{ + Rectangle r; + Text *t; + + if(getr(&r) && (t = malloc(sizeof(Text)))){ + memset((void*)t, 0, sizeof(Text)); + current((Flayer *)0); + flnew(&t->l[0], gettext, 0, (char *)t); + flinit(&t->l[0], r, font, maincols); /*bnl*/ + t->nwin = 1; + rinit(&t->rasp); + if(new) + startnewfile(Tstartnewfile, t); + else{ + rinit(&t->rasp); + t->tag = tag; + startfile(t); + } + return t; + } + return 0; +} + +int +whichmenu(int tg) +{ + int i; + + for(i=0; i<nname; i++) + if(tag[i] == tg) + return i; + return -1; +} + +void +menuins(int n, uchar *s, Text *t, int m, int tg) +{ + int i; + + if(nname == mname){ + if(mname == 0) + mname = 32; + else + mname *= 2; + name = realloc(name, sizeof(name[0])*mname); + text = realloc(text, sizeof(text[0])*mname); + tag = realloc(tag, sizeof(tag[0])*mname); + if(name==nil || text==nil || tag==nil) + panic("realloc"); + } + for(i=nname; i>n; --i) + name[i]=name[i-1], text[i]=text[i-1], tag[i]=tag[i-1]; + text[n] = t; + tag[n] = tg; + name[n] = alloc(strlen((char*)s)+2); + name[n][0] = m; + strcpy((char*)name[n]+1, (char*)s); + nname++; + menu3.lasthit = n+NMENU3; +} + +void +menudel(int n) +{ + int i; + + if(nname==0 || n>=nname || text[n]) + panic("menudel"); + free(name[n]); + --nname; + for(i = n; i<nname; i++) + name[i]=name[i+1], text[i]=text[i+1], tag[i]=tag[i+1]; +} + +void +setpat(char *s) +{ + static char pat[17]; + + pat[0] = '/'; + strncpy(pat+1, s, 15); + menu2str[Search] = pat; +} + +#define NBUF 64 +static uchar buf[NBUF*UTFmax]={' ', ' ', ' ', ' '}; + +char * +paren(char *s) +{ + uchar *t = buf; + + *t++ = '('; + do; while(*t++ = *s++); + t[-1] = ')'; + *t = 0; + return (char *)buf; +} +char* +genmenu2(int n) +{ + Text *t=(Text *)which->user1; + char *p; + if(n>=NMENU2+(menu2str[Search]!=0)) + return 0; + p = menu2str[n]; + if(!hostlock && !t->lock || n==Search || n==Look) + return p; + return paren(p); +} +char* +genmenu2c(int n) +{ + Text *t=(Text *)which->user1; + char *p; + if(n >= NMENU2C) + return 0; + if(n == Send) + p="send"; + else + p = menu2str[n]; + if(!hostlock && !t->lock) + return p; + return paren(p); +} +char * +genmenu3(int n) +{ + Text *t; + int c, i, k, l, w; + Rune r; + char *p; + + if(n >= NMENU3+nname) + return 0; + if(n < NMENU3){ + p = menu3str[n]; + if(hostlock) + p = paren(p); + return p; + } + n -= NMENU3; + if(n == 0) /* unless we've been fooled, this is cmd */ + return (char *)&name[n][1]; + if(mw == -1){ + mw = 7; /* strlen("~~sam~~"); */ + for(i=1; i<nname; i++){ + w = utflen((char*)name[i]+1)+4; /* include "'+. " */ + if(w > mw) + mw = w; + } + } + if(mw > NBUF) + mw = NBUF; + t = text[n]; + buf[0] = name[n][0]; + buf[1] = '-'; + buf[2] = ' '; + buf[3] = ' '; + if(t){ + if(t->nwin == 1) + buf[1] = '+'; + else if(t->nwin > 1) + buf[1] = '*'; + if(work && t==(Text *)work->user1) { + buf[2]= '.'; + if(modified) + buf[0] = '\''; + } + } + l = utflen((char*)name[n]+1); + if(l > NBUF-4-2){ + i = 4; + k = 1; + while(i < NBUF/2){ + k += chartorune(&r, (char*)name[n]+k); + i++; + } + c = name[n][k]; + name[n][k] = 0; + strcpy((char*)buf+4, (char*)name[n]+1); + name[n][k] = c; + strcat((char*)buf, "..."); + while((l-i) >= NBUF/2-4){ + k += chartorune(&r, (char*)name[n]+k); + i++; + } + strcat((char*)buf, (char*)name[n]+k); + }else + strcpy((char*)buf+4, (char*)name[n]+1); + i = utflen((char*)buf); + k = strlen((char*)buf); + while(i<mw && k<sizeof buf-1){ + buf[k++] = ' '; + i++; + } + buf[k] = 0; + return (char *)buf; +} diff --git a/src/cmd/samterm/mesg.c b/src/cmd/samterm/mesg.c new file mode 100644 index 00000000..0971ee2e --- /dev/null +++ b/src/cmd/samterm/mesg.c @@ -0,0 +1,804 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <mouse.h> +#include <cursor.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; + +void inmesg(Hmesg, int); +int inshort(int); +long inlong(int); +long 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 state = 0; + static int count = 0; + static int i = 0; + static int errs = 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: + 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, t); /* for 64-bit pointers */ + setlock(); +} + +void +startnewfile(int type, Text *t) +{ + t->tag = Untagged; + outTv(type, 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); +} + +long +invlong(int n) +{ + long l; + + l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4]; + l = (l<<16) | (indata[n+3]<<8) | indata[n+2]; + l = (l<<16) | (indata[n+1]<<8) | indata[n]; + return l; +} + +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, void *l1) +{ + outstart(type); + outshort(s1); + outvlong(l1); + outsend(); +} + +void +outTv(Tmesg type, void *l1) +{ + outstart(type); + outvlong(l1); + 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(void *v) +{ + int i; + ulong l; + uchar buf[8]; + + l = (ulong) v; + for(i = 0; i < sizeof(buf); i++, l >>= 8) + buf[i] = l; + + 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; + 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); +} diff --git a/src/cmd/samterm/mkfile b/src/cmd/samterm/mkfile new file mode 100644 index 00000000..10151356 --- /dev/null +++ b/src/cmd/samterm/mkfile @@ -0,0 +1,9 @@ +all:V: Makefile Make.FreeBSD-386 Make.Linux-386 Make.HP-UX-9000 Make.OSF1-alpha \ + Make.SunOS-sun4u Make.SunOS-sun4u-cc Make.SunOS-sun4u-gcc \ + Make.NetBSD-386 Make.Darwin-PowerMacintosh + +Makefile:D: ../libutf/Makefile.TOP Makefile.MID ../libutf/Makefile.CMD ../libutf/Makefile.BOT + cat $prereq >$target + +Make.%: ../libutf/Make.% + cp $prereq $target diff --git a/src/cmd/samterm/plan9.c b/src/cmd/samterm/plan9.c new file mode 100644 index 00000000..d08349c0 --- /dev/null +++ b/src/cmd/samterm/plan9.c @@ -0,0 +1,296 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <mouse.h> +#include <cursor.h> +#include <keyboard.h> +#include <frame.h> +#include "flayer.h" +#include "samterm.h" + +static char exname[64]; + +void +getscreen(int argc, char **argv) +{ + char *t; + + USED(argc); + USED(argv); + if(initdraw(panic1, nil, "sam") < 0){ + fprint(2, "samterm: initimage: %r\n"); + threadexitsall("init"); + } + t = getenv("tabstop"); + if(t != nil) + maxtab = strtoul(t, nil, 0); + draw(screen, screen->clipr, display->white, nil, ZP); +} + +int +screensize(int *w, int *h) +{ + int fd, n; + char buf[5*12+1]; + + fd = open("/dev/screen", OREAD); + if(fd < 0) + return 0; + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if (n != sizeof(buf)-1) + return 0; + buf[n] = 0; + if (h) { + *h = atoi(buf+4*12)-atoi(buf+2*12); + if (*h < 0) + return 0; + } + if (w) { + *w = atoi(buf+3*12)-atoi(buf+1*12); + if (*w < 0) + return 0; + } + return 1; +} + +int +snarfswap(char *fromsam, int nc, char **tosam) +{ + char *s1; + int f, n, ss; + + f = open("/dev/snarf", 0); + if(f < 0) + return -1; + ss = SNARFSIZE; + if(hversion < 2) + ss = 4096; + *tosam = s1 = alloc(ss); + n = read(f, s1, ss-1); + close(f); + if(n < 0) + n = 0; + if (n == 0) { + *tosam = 0; + free(s1); + } else + s1[n] = 0; +/* + f = create("/dev/snarf", 1, 0666); + if(f >= 0){ + write(f, fromsam, nc); + close(f); + } +*/ + return n; +} + +void +dumperrmsg(int count, int type, int count0, int c) +{ + fprint(2, "samterm: host mesg: count %d %ux %ux %ux %s...ignored\n", + count, type, count0, c, rcvstring()); +} + +void +removeextern(void) +{ + remove(exname); +} + +Readbuf hostbuf[2]; +/* +Readbuf plumbbuf[2]; + +void +extproc(void *argv) +{ + Channel *c; + int i, n, which, *fdp; + void **arg; + + arg = argv; + c = arg[0]; + fdp = arg[1]; + + i = 0; + for(;;){ + i = 1-i; / * toggle * / + n = read(*fdp, plumbbuf[i].data, sizeof plumbbuf[i].data); + if(n <= 0){ + fprint(2, "samterm: extern read error: %r\n"); + threadexits("extern"); / * not a fatal error * / + } + plumbbuf[i].n = n; + which = i; + send(c, &which); + } +} +*/ + +void +extstart(void) +{ + char buf[32]; + int fd; + static int p[2]; + static void *arg[2]; + +return; + if(pipe(p) < 0) + return; + sprint(exname, "/srv/sam.%s", "rsc"/*getuser()*/); + fd = open(exname, 1, 0600);/* BUG was create */ + if(fd < 0){ /* assume existing guy is more important */ + Err: + close(p[0]); + close(p[1]); + return; + } + sprint(buf, "%d", p[0]); + if(write(fd, buf, strlen(buf)) <= 0) + goto Err; + close(fd); + /* + * leave p[0] open so if the file is removed the event + * library won't get an error + */ +#if 0 + plumbc = chancreate(sizeof(int), 0); + arg[0] = plumbc; + arg[1] = &p[1]; + proccreate(extproc, arg, 1024); +#endif + atexit(removeextern); +} + +#if 0 +int +plumbformat(int i) +{ + Plumbmsg *m; + char *addr, *data, *act; + int n; + + data = (char*)plumbbuf[i].data; + m = plumbunpack(data, plumbbuf[i].n); + if(m == nil) + return 0; + n = m->ndata; + if(n == 0){ + plumbfree(m); + return 0; + } + act = plumblookup(m->attr, "action"); + if(act!=nil && strcmp(act, "showfile")!=0){ + /* can't handle other cases yet */ + plumbfree(m); + return 0; + } + addr = plumblookup(m->attr, "addr"); + if(addr){ + if(addr[0] == '\0') + addr = nil; + else + addr = strdup(addr); /* copy to safe storage; we'll overwrite data */ + } + memmove(data, "B ", 2); /* we know there's enough room for this */ + memmove(data+2, m->data, n); + n += 2; + if(data[n-1] != '\n') + data[n++] = '\n'; + if(addr != nil){ + if(n+strlen(addr)+1+1 <= READBUFSIZE) + n += sprint(data+n, "%s\n", addr); + free(addr); + } + plumbbuf[i].n = n; + plumbfree(m); + return 1; +} + +void +plumbproc(void *argv) +{ + Channel *c; + int i, n, which, *fdp; + void **arg; + + arg = argv; + c = arg[0]; + fdp = arg[1]; + + i = 0; + for(;;){ + i = 1-i; /* toggle */ + n = read(*fdp, plumbbuf[i].data, READBUFSIZE); + if(n <= 0){ + fprint(2, "samterm: plumb read error: %r\n"); + threadexits("plumb"); /* not a fatal error */ + } + plumbbuf[i].n = n; + if(plumbformat(i)){ + which = i; + send(c, &which); + } + } +} + +int +plumbstart(void) +{ + static int fd; + static void *arg[2]; + + plumbfd = plumbopen("send", OWRITE|OCEXEC); /* not open is ok */ + fd = plumbopen("edit", OREAD|OCEXEC); + if(fd < 0) + return -1; + plumbc = chancreate(sizeof(int), 0); + if(plumbc == nil){ + close(fd); + return -1; + } + arg[0] =plumbc; + arg[1] = &fd; + proccreate(plumbproc, arg, 4096); + return 1; +} +#endif + +int +plumbstart(void) +{ + return -1; +} + +void +hostproc(void *arg) +{ + Channel *c; + int i, n, which; + + c = arg; + + i = 0; + for(;;){ + i = 1-i; /* toggle */ + n = read(0, hostbuf[i].data, sizeof hostbuf[i].data); + if(n <= 0){ + fprint(2, "samterm: host read error: %r\n"); + threadexitsall("host"); + } + hostbuf[i].n = n; + which = i; + send(c, &which); + } +} + +void +hoststart(void) +{ + hostc = chancreate(sizeof(int), 0); + proccreate(hostproc, hostc, 1024); +} diff --git a/src/cmd/samterm/samterm b/src/cmd/samterm/samterm Binary files differnew file mode 100755 index 00000000..c5333ecb --- /dev/null +++ b/src/cmd/samterm/samterm diff --git a/src/cmd/samterm/samterm.h b/src/cmd/samterm/samterm.h new file mode 100644 index 00000000..3018c92b --- /dev/null +++ b/src/cmd/samterm/samterm.h @@ -0,0 +1,177 @@ +#define SAMTERM + +#define RUNESIZE sizeof(Rune) +#define MAXFILES 256 +#define READBUFSIZE 8192 +#define NL 5 + +enum{ + Up, + Down +}; + +typedef struct Text Text; +typedef struct Section Section; +typedef struct Rasp Rasp; +typedef struct Readbuf Readbuf; + +struct Section +{ + long nrunes; + Rune *text; /* if null, we haven't got it */ + Section *next; +}; + +struct Rasp +{ + long nrunes; + Section *sect; +}; + +#define Untagged ((ushort)65535) + +struct Text +{ + Rasp rasp; + short nwin; + short front; /* input window */ + ushort tag; + char lock; + Flayer l[NL]; /* screen storage */ +}; + +struct Readbuf +{ + short n; /* # bytes in buf */ + uchar data[READBUFSIZE]; /* data bytes */ +}; + +enum Resource +{ + RHost, + RKeyboard, + RMouse, + RPlumb, + RResize, + NRes, +}; + +extern Text **text; +extern uchar **name; +extern ushort *tag; +extern int nname; +extern int mname; +extern Cursor bullseye; +extern Cursor deadmouse; +extern Cursor lockarrow; +extern Cursor *cursor; +extern Flayer *which; +extern Flayer *work; +extern Text cmd; +extern Rune *scratch; +extern long nscralloc; +extern char hostlock; +extern char hasunlocked; +extern long snarflen; +extern Mousectl* mousectl; +extern Keyboardctl* keyboardctl; +extern Mouse* mousep; +extern long modified; +extern int maxtab; +extern Readbuf hostbuf[2]; /* double buffer; it's synchronous communication */ +extern Readbuf plumbbuf[2]; /* double buffer; it's synchronous communication */ +extern Channel *plumbc; +extern Channel *hostc; +extern int hversion; +extern int plumbfd; + +Rune *gettext(Flayer*, long, ulong*); +void *alloc(ulong n); + +void iconinit(void); +void getscreen(int, char**); +void initio(void); +void setlock(void); +void outcmd(void); +void rinit(Rasp*); +void startnewfile(int, Text*); +void getmouse(void); +void mouseunblock(void); +void kbdblock(void); +void extstart(void); +void hoststart(void); +int plumbstart(void); +int button(int but); +int load(char*, int); +int waitforio(void); +int rcvchar(void); +int getch(void); +int kbdchar(void); +int qpeekc(void); +void cut(Text*, int, int, int); +void paste(Text*, int); +void snarf(Text*, int); +int center(Flayer*, long); +int xmenuhit(int, Menu*); +void buttons(int); +int getr(Rectangle*); +void current(Flayer*); +void duplicate(Flayer*, Rectangle, Font*, int); +void startfile(Text*); +void panic(char*); +void panic1(Display*, char*); +void closeup(Flayer*); +void Strgrow(Rune**, long*, int); +int RESIZED(void); +void resize(void); +void rcv(void); +void type(Flayer*, int); +void menu2hit(void); +void menu3hit(void); +void scroll(Flayer*, int); +void hcheck(int); +void rclear(Rasp*); +int whichmenu(int); +void hcut(int, long, long); +void horigin(int, long); +void hgrow(int, long, long, int); +int hdata(int, long, uchar*, int); +int hdatarune(int, long, Rune*, int); +Rune *rload(Rasp*, ulong, ulong, ulong*); +void menuins(int, uchar*, Text*, int, int); +void menudel(int); +Text *sweeptext(int, int); +void setpat(char*); +void scrdraw(Flayer*, long tot); +int rcontig(Rasp*, ulong, ulong, int); +int rmissing(Rasp*, ulong, ulong); +void rresize(Rasp *, long, long, long); +void rdata(Rasp*, long, long, Rune*); +void rclean(Rasp*); +void scrorigin(Flayer*, int, long); +long scrtotal(Flayer*); +void flnewlyvisible(Flayer*); +char *rcvstring(void); +void Strcpy(Rune*, Rune*); +void Strncpy(Rune*, Rune*, long); +void flushtyping(int); +void dumperrmsg(int, int, int, int); +int screensize(int*,int*); +void getmouse(void); + +#include "mesg.h" + +void outTs(Tmesg, int); +void outT0(Tmesg); +void outTl(Tmesg, long); +void outTslS(Tmesg, int, long, Rune*); +void outTsll(Tmesg, int, long, long); +void outTsl(Tmesg, int, long); +void outTsv(Tmesg, int, void*); +void outTv(Tmesg, void*); +void outstart(Tmesg); +void outcopy(int, uchar*); +void outshort(int); +void outlong(long); +void outvlong(void*); +void outsend(void); diff --git a/src/libframe/Make.Darwin-PowerMacintosh b/src/libframe/Make.Darwin-PowerMacintosh new file mode 100644 index 00000000..14b8d4e7 --- /dev/null +++ b/src/libframe/Make.Darwin-PowerMacintosh @@ -0,0 +1,6 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I${PREFIX}/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/libframe/Make.FreeBSD-386 b/src/libframe/Make.FreeBSD-386 new file mode 100644 index 00000000..087ed3ab --- /dev/null +++ b/src/libframe/Make.FreeBSD-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/libframe/Make.HP-UX-9000 b/src/libframe/Make.HP-UX-9000 new file mode 100644 index 00000000..edbdc111 --- /dev/null +++ b/src/libframe/Make.HP-UX-9000 @@ -0,0 +1,6 @@ +CC=cc +CFLAGS=-O -c -Ae -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/libframe/Make.Linux-386 b/src/libframe/Make.Linux-386 new file mode 100644 index 00000000..74b0252c --- /dev/null +++ b/src/libframe/Make.Linux-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/libframe/Make.NetBSD-386 b/src/libframe/Make.NetBSD-386 new file mode 100644 index 00000000..087ed3ab --- /dev/null +++ b/src/libframe/Make.NetBSD-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/libframe/Make.OSF1-alpha b/src/libframe/Make.OSF1-alpha new file mode 100644 index 00000000..3d45279b --- /dev/null +++ b/src/libframe/Make.OSF1-alpha @@ -0,0 +1,6 @@ +CC=cc +CFLAGS+=-g -c -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/libframe/Make.SunOS-sun4u b/src/libframe/Make.SunOS-sun4u new file mode 100644 index 00000000..c5fe67b8 --- /dev/null +++ b/src/libframe/Make.SunOS-sun4u @@ -0,0 +1,2 @@ +include Make.SunOS-sun4u-$(CC) +NAN=nan64.$O diff --git a/src/libframe/Make.SunOS-sun4u-cc b/src/libframe/Make.SunOS-sun4u-cc new file mode 100644 index 00000000..829301de --- /dev/null +++ b/src/libframe/Make.SunOS-sun4u-cc @@ -0,0 +1,6 @@ +CC=cc +CFLAGS+=-g -c -I. -O +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/libframe/Make.SunOS-sun4u-gcc b/src/libframe/Make.SunOS-sun4u-gcc new file mode 100644 index 00000000..5c415948 --- /dev/null +++ b/src/libframe/Make.SunOS-sun4u-gcc @@ -0,0 +1,6 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/libframe/frame.h b/src/libframe/frame.h new file mode 100644 index 00000000..9b8194b7 --- /dev/null +++ b/src/libframe/frame.h @@ -0,0 +1,85 @@ +typedef struct Frbox Frbox; +typedef struct Frame Frame; + +enum{ + BACK, + HIGH, + BORD, + TEXT, + HTEXT, + NCOL +}; + +#define FRTICKW 3 + +struct Frbox +{ + long wid; /* in pixels */ + long nrune; /* <0 ==> negate and treat as break char */ + uchar *ptr; + short bc; /* break char */ + short minwid; +}; + +struct Frame +{ + Font *font; /* of chars in the frame */ + Display *display; /* on which frame appears */ + Image *b; /* on which frame appears */ + Image *cols[NCOL]; /* text and background colors */ + Rectangle r; /* in which text appears */ + Rectangle entire; /* of full frame */ + void (*scroll)(Frame*, int); /* scroll function provided by application */ + Frbox *box; + ulong p0, p1; /* selection */ + ushort nbox, nalloc; + ushort maxtab; /* max size of tab, in pixels */ + ushort nchars; /* # runes in frame */ + ushort nlines; /* # lines with text */ + ushort maxlines; /* total # lines in frame */ + ushort lastlinefull; /* last line fills frame */ + ushort modified; /* changed since frselect() */ + Image *tick; /* typing tick */ + Image *tickback; /* saved image under tick */ + int ticked; /* flag: is tick onscreen? */ +}; + +ulong frcharofpt(Frame*, Point); +Point frptofchar(Frame*, ulong); +int frdelete(Frame*, ulong, ulong); +void frinsert(Frame*, Rune*, Rune*, ulong); +void frselect(Frame*, Mousectl*); +void frselectpaint(Frame*, Point, Point, Image*); +void frdrawsel(Frame*, Point, ulong, ulong, int); +void frdrawsel0(Frame*, Point, ulong, ulong, Image*, Image*); +void frinit(Frame*, Rectangle, Font*, Image*, Image**); +void frsetrects(Frame*, Rectangle, Image*); +void frclear(Frame*, int); + +uchar *_frallocstr(Frame*, unsigned); +void _frinsure(Frame*, int, unsigned); +Point _frdraw(Frame*, Point); +void _frgrowbox(Frame*, int); +void _frfreebox(Frame*, int, int); +void _frmergebox(Frame*, int); +void _frdelbox(Frame*, int, int); +void _frsplitbox(Frame*, int, int); +int _frfindbox(Frame*, int, ulong, ulong); +void _frclosebox(Frame*, int, int); +int _frcanfit(Frame*, Point, Frbox*); +void _frcklinewrap(Frame*, Point*, Frbox*); +void _frcklinewrap0(Frame*, Point*, Frbox*); +void _fradvance(Frame*, Point*, Frbox*); +int _frnewwid(Frame*, Point, Frbox*); +int _frnewwid0(Frame*, Point, Frbox*); +void _frclean(Frame*, Point, int, int); +void _frredraw(Frame*, Point); +void _fraddbox(Frame*, int, int); +Point _frptofcharptb(Frame*, ulong, Point, int); +Point _frptofcharnb(Frame*, ulong, int); +int _frstrlen(Frame*, int); +void frtick(Frame*, Point, int); +void frinittick(Frame*); + +#define NRUNE(b) ((b)->nrune<0? 1 : (b)->nrune) +#define NBYTE(b) strlen((char*)(b)->ptr) |