├── sam.png ├── .gitignore ├── ssam ├── Makefile └── ssam.sh ├── deadpixi-sam.desktop ├── libXg ├── rune.c ├── cursorset.c ├── bscreenrect.c ├── clipr.c ├── rectclip.c ├── cursorswitch.c ├── Makefile ├── Gwin.h ├── string.c ├── border.c ├── texture.c ├── GwinP.h ├── balloc.c ├── wrbitmap.c ├── getrect.c ├── ldconvert.c ├── bitblt.c ├── libgint.h ├── arith.c └── menuhit.c ├── include ├── u.h ├── regexp.h ├── frame.h └── libg.h ├── doc ├── Makefile ├── samrc └── samrc.5 ├── LICENSE ├── libframe ├── Makefile ├── frstr.c ├── frinit.c ├── frdraw.c ├── frutil.c ├── frselect.c ├── frptofchar.c ├── frdelete.c ├── frbox.c └── frinsert.c ├── config.mk.def ├── samterm ├── Makefile ├── unix.c ├── flayer.h ├── io.c ├── scroll.c ├── samterm.h ├── rasp.c ├── menu.c └── flayer.c ├── sam ├── sys.c ├── errors.h ├── list.c ├── Makefile ├── parse.h ├── multi.c ├── error.c ├── string.c ├── buffer.c ├── unix.c ├── moveto.c ├── mesg.h ├── shell.c ├── address.c ├── rasp.c ├── io.c └── sam.h ├── Makefile └── sam.svg /sam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deadpixi/sam/HEAD/sam.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.o 3 | config.mk 4 | sam/sam 5 | samterm/samterm 6 | -------------------------------------------------------------------------------- /ssam/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | 3 | all: ssam 4 | 5 | ssam: ssam.sh 6 | cp $< $@ 7 | 8 | clean: 9 | rm -f ssam 10 | 11 | nuke: clean 12 | 13 | 14 | install: ssam 15 | mkdir -p $(BINDIR) 16 | cp ssam $(BINDIR) 17 | chmod +x $(BINDIR)/ssam 18 | 19 | 20 | uninstall: 21 | rm -f $(BINDIR)/ssam -------------------------------------------------------------------------------- /deadpixi-sam.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=sam 3 | GenericName=Text editor 4 | Comment=Multi-document text editor with structural regular expressions 5 | Icon=accessories-text-editor 6 | Exec=sam %F 7 | Terminal=false 8 | Type=Application 9 | Categories=Utility;TextEditor; 10 | StartupNotify=false 11 | MimeType=text/plain 12 | -------------------------------------------------------------------------------- /libXg/rune.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | 5 | int 6 | chartorune(wchar_t *rune, char *str) 7 | { 8 | int r = mbtowc(rune, str, strlen(str)); 9 | if (r < 0){ 10 | *rune = UNICODE_REPLACEMENT_CHAR; 11 | return 1; 12 | } 13 | return r; 14 | } 15 | -------------------------------------------------------------------------------- /libXg/cursorset.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | /* 7 | * Only allow cursor to move within screen Bitmap 8 | */ 9 | void 10 | cursorset(Point p) 11 | { 12 | /* motion will be relative to window origin */ 13 | p = sub(p, screen.r.min); 14 | XWarpPointer(_dpy, None, (Window)screen.id, 0, 0, 0, 0, p.x, p.y); 15 | } 16 | -------------------------------------------------------------------------------- /libXg/bscreenrect.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | /* 7 | * The screen data structure should always be up to date 8 | * (Not true in the Plan 9 library, which is why this 9 | * function exists). 10 | */ 11 | Rectangle 12 | bscreenrect(Rectangle *clipr) 13 | { 14 | if(clipr) 15 | *clipr = screen.clipr; 16 | return screen.r; 17 | } 18 | -------------------------------------------------------------------------------- /libXg/clipr.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | int 7 | clipr(Bitmap *d, Rectangle r) 8 | { 9 | if(rectclip(&r, d->r) == 0) 10 | return 0; 11 | d->clipr = r; 12 | if(r.min.x != d->r.min.x || 13 | r.min.y != d->r.min.y || 14 | r.max.x != d->r.max.x || 15 | r.max.y != d->r.max.y) 16 | d->flag |= CLIP; 17 | else 18 | d->flag &= ~CLIP; 19 | return 1; 20 | } 21 | -------------------------------------------------------------------------------- /include/u.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define utflen(s) (mbstowcs(NULL, (s), 0)) 17 | #define fullrune(s, n) (mbtowc(NULL, (s), (n)) >= 0) 18 | #define runetochar(s, r) (wctomb((s), (r))) 19 | #define runelen(r) (wctomb(NULL, (r))) 20 | #define UNICODE_REPLACEMENT_CHAR 0xfffd 21 | 22 | int chartorune(wchar_t *, char *); 23 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2014-2014 Rob King 2 | 3 | include ../config.mk 4 | 5 | all: 6 | 7 | install: sam.1 8 | mkdir -p "$(MANDIR)/man1" 9 | cp sam.1 "$(MANDIR)/man1" 10 | ln -sf "$(MANDIR)/man1/sam.1" "$(MANDIR)/man1/B.1" 11 | ln -sf "$(MANDIR)/man1/sam.1" "$(MANDIR)/man1/samterm.1" 12 | ln -sf "$(MANDIR)/man1/sam.1" "$(MANDIR)/man1/rsam.1" 13 | ln -sf "$(MANDIR)/man1/sam.1" "$(MANDIR)/man1/sam.save.1" 14 | mkdir -p "$(MANDIR)/man5" 15 | cp samrc.5 "$(MANDIR)/man5" 16 | 17 | uninstall: 18 | rm -f "$(MANDIR)/man1/sam.1" 19 | rm -f "$(MANDIR)/man1/B.1" 20 | rm -f "$(MANDIR)/man1/samterm.1" 21 | rm -f "$(MANDIR)/man1/rsam.1" 22 | rm -f "$(MANDIR)/man1/sam.save.1" 23 | rm -f "$(MANDIR)/man5/samrc.5" 24 | -------------------------------------------------------------------------------- /libXg/rectclip.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | 5 | int rectclip(Rectangle *rp, Rectangle b) /* first by reference, second by value */ 6 | { 7 | Rectangle *bp = &b; 8 | /* 9 | * Expand rectXrect() in line for speed 10 | */ 11 | if((rp->min.xmax.x && bp->min.xmax.x && 12 | rp->min.ymax.y && bp->min.ymax.y)==0) 13 | return 0; 14 | /* They must overlap */ 15 | if(rp->min.x < bp->min.x) 16 | rp->min.x = bp->min.x; 17 | if(rp->min.y < bp->min.y) 18 | rp->min.y = bp->min.y; 19 | if(rp->max.x > bp->max.x) 20 | rp->max.x = bp->max.x; 21 | if(rp->max.y > bp->max.y) 22 | rp->max.y = bp->max.y; 23 | return 1; 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The authors of this software are Rob Pike and Howard Trickey. 4 | * Copyright (c) 1998 by Lucent Technologies. 5 | * 6 | * Rob King made some changes. 7 | * Copyright (c) 2015 by Rob King. 8 | * 9 | * Permission to use, copy, modify, and distribute this software for any 10 | * purpose without fee is hereby granted, provided that this entire notice 11 | * is included in all copies of any software which is or includes a copy 12 | * or modification of this software and in all copies of the supporting 13 | * documentation for such software. 14 | * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 15 | * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY 16 | * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 17 | * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 18 | */ 19 | -------------------------------------------------------------------------------- /libframe/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 1998 Lucent Technologies - All rights reserved. 2 | # 3 | # Prototype Makefile for libframe 4 | # 5 | include ../config.mk 6 | 7 | # add -Iincludedir for any include directories that need to be searched 8 | # for posix header files (for UMIPS, add -I/usr/include/posix) 9 | INCS=-I../include 10 | 11 | 12 | # add name of library orderer - use ":" if none exists 13 | RANLIB=: 14 | 15 | # add name of library 16 | AR=ar 17 | 18 | CFLAGS+=-c $(INCS) $(STANDARDS) $(INCLUDES) 19 | 20 | LIB=libframe.a 21 | CC?=c99 22 | 23 | OBJ=frbox.o frdelete.o frdraw.o frinit.o frinsert.o frptofchar.o\ 24 | frselect.o frstr.o frutil.o 25 | 26 | all: $(LIB) 27 | 28 | $(LIB): $(OBJ) 29 | $(AR) rv $(LIB) $(OBJ) 30 | $(RANLIB) $(LIB) 31 | 32 | clean: 33 | rm -f *.o *.a 34 | 35 | nuke: clean 36 | rm -f $(LIB) 37 | 38 | install: $(LIB) 39 | 40 | uninstall: 41 | 42 | $(OBJ): ../include/u.h ../include/frame.h 43 | -------------------------------------------------------------------------------- /libframe/frstr.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | * The code here and elsewhere requires that strings not be gcalloc()ed 8 | */ 9 | 10 | #define CHUNK 16 11 | #define ROUNDUP(n) ((n+CHUNK)&~(CHUNK-1)) 12 | 13 | uint8_t * 14 | _frallocstr(unsigned n) 15 | { 16 | uint8_t *p; 17 | 18 | p = malloc(ROUNDUP(n)); 19 | if(p == 0) 20 | berror("out of memory"); 21 | return p; 22 | } 23 | 24 | void 25 | _frinsure(Frame *f, int bn, unsigned n) 26 | { 27 | Frbox *b; 28 | uint8_t *p; 29 | 30 | b = &f->box[bn]; 31 | if(b->nrune < 0) 32 | berror("_frinsure"); 33 | if(ROUNDUP(b->nrune) > n) /* > guarantees room for terminal NUL */ 34 | return; 35 | p = _frallocstr(n); 36 | b = &f->box[bn]; 37 | memmove(p, b->a.ptr, NBYTE(b)+1); 38 | free(b->a.ptr); 39 | b->a.ptr = p; 40 | } 41 | -------------------------------------------------------------------------------- /config.mk.def: -------------------------------------------------------------------------------- 1 | # config.mk - makefile configuration for sam 2 | # copyright 2015 Rob King 3 | 4 | # CC is the C compiler to use 5 | CC=gcc 6 | CFLAGS?= 7 | CFLAGS+=-std=c99 8 | 9 | # STANDARDS names the C preprocessor defines that need to 10 | # be present to get a more-or-less standard compilation 11 | # environment. 12 | # 13 | # Mac OS X users need to add -D_DARWIN_C_SOURCE here. 14 | STANDARDS=-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=500 15 | 16 | # DESTDIR is the root of the installation tree 17 | DESTDIR?=/usr/local 18 | 19 | # BINDIR is the directory where binaries go 20 | BINDIR?=$(DESTDIR)/bin 21 | 22 | # MANDIR is where manual pages go 23 | MANDIR?=$(DESTDIR)/share/man/ 24 | 25 | # Add additional include and library directories 26 | # BSD/Mac OS X users might need to add something like 27 | # INCLUDES=-I/usr/X11R6/include -I/usr/X11R6/include/freetype2 28 | # LDFLAGS=-L/usr/X11R6/lib 29 | INCLUDES=-I/usr/include/freetype2 30 | LDFLAGS= 31 | 32 | # Set this to your default remote shell. 33 | RXPATH=/usr/bin/ssh 34 | -------------------------------------------------------------------------------- /samterm/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 1998 Lucent Technologies - All rights reserved. 2 | # 3 | # Prototype Makefile for samterm 4 | # 5 | 6 | include ../config.mk 7 | 8 | # add -Iincludedir for any include directories that need to be searched 9 | # for posix header files (for UMIPS, add -I/usr/include/posix) 10 | INCS=-I../include 11 | 12 | # SAMTERM contains the name of the file containing the samterm 13 | # executable. 14 | SAMTERM=$(BINDIR)/samterm 15 | 16 | # set this if your X libraries are in different locations 17 | # or if you need extra libraries to load with X11 applications 18 | XLIBS=-lXt -lX11 -lXft -lXi 19 | 20 | CFLAGS+=$(INCS) $(STANDARDS) $(INCLUDES) 21 | 22 | LIBS=../libframe/libframe.a ../libXg/libXg.a 23 | CC?=c99 24 | 25 | OBJ=main.o flayer.o io.o menu.o mesg.o rasp.o samrc.o scroll.o unix.o 26 | 27 | all: samterm 28 | 29 | samterm: $(OBJ) $(LIBS) 30 | $(CC) -o samterm $(OBJ) $(LIBS) $(XLIBS) $(LDFLAGS) 31 | 32 | clean: 33 | rm -f *.o core samterm 34 | 35 | install: samterm 36 | cp samterm $(SAMTERM) 37 | 38 | uninstall: 39 | rm -f $(SAMTERM) 40 | 41 | $(OBJ): samterm.h flayer.h ../include/frame.h ../include/libg.h ../include/u.h ../sam/mesg.h 42 | -------------------------------------------------------------------------------- /sam/sys.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | 3 | #include 4 | #include 5 | 6 | #include "sam.h" 7 | 8 | static bool inerror = false; 9 | 10 | #define ERRLEN 63 11 | 12 | /* 13 | * A reasonable interface to the system calls 14 | */ 15 | 16 | void 17 | resetsys(void) 18 | { 19 | inerror = false; 20 | } 21 | 22 | void 23 | syserror(char *a) 24 | { 25 | char buf[ERRLEN + 1] = {0}; 26 | 27 | if(!inerror){ 28 | inerror = true; 29 | strncpy(buf, strerror(errno), ERRLEN); 30 | dprint(L"%s: ", a); 31 | error_s(Eio, buf); 32 | } 33 | } 34 | 35 | int 36 | Read(FILE *f, void *a, int n) 37 | { 38 | if (fread(a, 1, n, f) != n){ 39 | if (lastfile) 40 | lastfile->state = Readerr; 41 | if (downloaded) 42 | fprintf(stderr, "read error: %s\n", strerror(errno)); 43 | rescue(); 44 | exit(EXIT_FAILURE); 45 | } 46 | return n; 47 | } 48 | 49 | int 50 | Write(FILE *f, void *a, int n) 51 | { 52 | size_t m = fwrite(a, 1, n, f); 53 | if (m != n) 54 | syserror("write"); 55 | fflush(f); 56 | return m; 57 | } 58 | -------------------------------------------------------------------------------- /sam/errors.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | typedef enum Err{ 3 | /* error_s */ 4 | Eopen, 5 | Ecreate, 6 | Emenu, 7 | Emodified, 8 | Eio, 9 | /* error_c */ 10 | Eunk, 11 | Emissop, 12 | Edelim, 13 | /* error */ 14 | Efork, 15 | Eintr, 16 | Eaddress, 17 | Esearch, 18 | Epattern, 19 | Enewline, 20 | Eblank, 21 | Enopattern, 22 | EnestXY, 23 | Enolbrace, 24 | Enoaddr, 25 | Eoverlap, 26 | Enosub, 27 | Elongrhs, 28 | Ebadrhs, 29 | Erange, 30 | Esequence, 31 | Eorder, 32 | Enoname, 33 | Eleftpar, 34 | Erightpar, 35 | Ebadclass, 36 | Ebadregexp, 37 | Eoverflow, 38 | Enocmd, 39 | Epipe, 40 | Enofile, 41 | Etoolong, 42 | Echanges, 43 | Eempty, 44 | Efsearch, 45 | Emanyfiles, 46 | Elongtag, 47 | Esubexp, 48 | Etmpovfl, 49 | Eappend 50 | }Err; 51 | typedef enum Warn{ 52 | /* warn_s */ 53 | Wdupname, 54 | Wfile, 55 | Wdate, 56 | /* warn_ss */ 57 | Wdupfile, 58 | /* warn */ 59 | Wnulls, 60 | Wpwd, 61 | Wnotnewline, 62 | Wbadstatus, 63 | Wnottext 64 | }Warn; 65 | -------------------------------------------------------------------------------- /sam/list.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include "sam.h" 3 | 4 | /* 5 | * Check that list has room for one more element. 6 | */ 7 | void 8 | growlist(List *l) 9 | { 10 | if(l->listptr==0 || l->nalloc==0){ 11 | l->nalloc = INCR; 12 | l->listptr = emalloc(INCR*sizeof(l->g)); 13 | l->nused = 0; 14 | }else if(l->nused == l->nalloc){ 15 | l->listptr = erealloc(l->listptr, (l->nalloc+INCR)*sizeof(l->g)); 16 | memset((void*)(l->longptr+l->nalloc), 0, INCR*sizeof(l->g)); 17 | l->nalloc += INCR; 18 | } 19 | } 20 | 21 | /* 22 | * Remove the ith element from the list 23 | */ 24 | void 25 | dellist(List *l, int i) 26 | { 27 | memmove(&l->longptr[i], &l->longptr[i+1], (l->nused-(i+1))*sizeof(l->g)); 28 | l->nused--; 29 | } 30 | 31 | /* 32 | * Add a new element, whose position is i, to the list 33 | */ 34 | void 35 | inslist(List *l, int i, int64_t val) 36 | { 37 | growlist(l); 38 | memmove(&l->longptr[i+1], &l->longptr[i], (l->nused-i)*sizeof(l->g)); 39 | l->longptr[i] = val; 40 | l->nused++; 41 | } 42 | 43 | void 44 | listfree(List *l) 45 | { 46 | free(l->listptr); 47 | free(l); 48 | } 49 | -------------------------------------------------------------------------------- /libXg/cursorswitch.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | #include 7 | 8 | extern Window _topwindow; 9 | 10 | static Cursor arrow; 11 | static Cursor sweep; 12 | static Cursor crosshair; 13 | static Cursor pirate; 14 | static Cursor watch; 15 | static Cursor defcursor; 16 | 17 | void 18 | cursorswitch(unsigned int c) 19 | { 20 | Cursor i = defcursor; 21 | 22 | switch (c){ 23 | case ArrowCursor: i = arrow; break; 24 | case SweepCursor: i = sweep; break; 25 | case BullseyeCursor: i = crosshair; break; 26 | case DeadCursor: i = pirate; break; 27 | case LockCursor: i = watch; break; 28 | default: i = defcursor; break; 29 | } 30 | 31 | XDefineCursor(_dpy, _topwindow, i); 32 | } 33 | 34 | void 35 | initcursors(void) 36 | { 37 | sweep = XCreateFontCursor(_dpy, XC_sizing); 38 | crosshair = XCreateFontCursor(_dpy, XC_crosshair); 39 | pirate = XCreateFontCursor(_dpy, XC_pirate); 40 | watch = XCreateFontCursor(_dpy, XC_watch); 41 | arrow = XCreateFontCursor(_dpy, XC_left_ptr); 42 | defcursor = XCreateFontCursor(_dpy, XC_xterm); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /libXg/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 1998 Lucent Technologies - All rights reserved. 2 | # 3 | # Prototype Makefile for libXg 4 | # 5 | include ../config.mk 6 | 7 | # add -Iincludedir for any include directories that need to be searched 8 | INCS=-I../include 9 | 10 | # set this if your X libraries are in different locations 11 | # or if you need extra libraries to load with X11 applications 12 | XLIBS=-lXt -lXi 13 | 14 | # add name of library orderer - use ":" if none 15 | RANLIB=: 16 | 17 | # add name of librarian 18 | AR=ar 19 | 20 | # the name of the library 21 | LIB=libXg.a 22 | 23 | CFLAGS+=$(STANDARDS) $(INCS) $(INCLUDES) 24 | CC?=c99 25 | 26 | OBJS= arith.o balloc.o bitblt.o border.o bscreenrect.o\ 27 | clipr.o cursorset.o cursorswitch.o\ 28 | gcs.o getrect.o gwin.o ldconvert.o\ 29 | menuhit.o \ 30 | rectclip.o rune.o string.o texture.o\ 31 | wrbitmap.o xtbinit.o 32 | 33 | all install: $(LIB) 34 | uninstall: 35 | compile: $(LIB) 36 | test: $(LIB) test.o 37 | $(CC) -o $@ $? $(LIB) $(XLIBS) -lm $(LDFLAGS) 38 | echo try running test 39 | clean: 40 | rm -f *.o test *.a 41 | 42 | nuke: clean 43 | rm -f $(LIB) 44 | 45 | $(LIB): $(OBJS) 46 | $(AR) rv $(LIB) $(OBJS) 47 | $(RANLIB) $(LIB) 48 | 49 | $(LIB)(%.o): %.o 50 | 51 | $(OBJS): ../include/libg.h libgint.h 52 | -------------------------------------------------------------------------------- /libXg/Gwin.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #ifndef GWIN_H 3 | #define GWIN_H 4 | 5 | /* New resource names */ 6 | 7 | #define XtNscrollForwardR "scrollForwardR" 8 | #define XtCScrollForwardR "ScrollForwardR" 9 | #define XtNreshaped "reshaped" 10 | #define XtCReshaped "Reshaped" 11 | #define XtNgotchar "gotchar" 12 | #define XtCGotchar "Gotchar" 13 | #define XtNgotmouse "gotmouse" 14 | #define XtCGotmouse "Gotmouse" 15 | #define XtNp9font "p9font" 16 | #define XtCP9font "P9font" 17 | #define XtNcomposeMod "composeMod" 18 | #define XtCComposeMod "ComposeMod" 19 | 20 | /* External reference to the class record pointer */ 21 | extern WidgetClass gwinWidgetClass; 22 | 23 | /* Type definition for gwin widgets */ 24 | typedef struct _GwinRec *GwinWidget; 25 | 26 | /* Type definition for gwin resources */ 27 | typedef struct { 28 | int buttons; 29 | struct { 30 | int x; 31 | int y; 32 | } xy; 33 | uint64_t msec; 34 | } Gwinmouse; 35 | 36 | typedef void (*Reshapefunc)(int, int, int, int); 37 | typedef void (*Charfunc)(int, int, int, int, int, const char *); 38 | typedef void (*Mousefunc)(Gwinmouse*); 39 | 40 | /* Method declarations */ 41 | extern String GwinSelectionSwap(Widget, String); 42 | 43 | #endif /* GWIN_H */ 44 | -------------------------------------------------------------------------------- /samterm/unix.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | #include "flayer.h" 6 | #include "samterm.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | static char *fallbacks[] = { 16 | "*scrollForwardR: true", 17 | "*geometry: 740x780", 18 | NULL 19 | }; 20 | 21 | void 22 | getscreen(int argc, char **argv) 23 | { 24 | Rectangle r; 25 | 26 | signal(SIGINT, SIG_IGN); 27 | xtbinit(0, "Sam", &argc, argv, fallbacks); 28 | r = inset(screen.r, 4); 29 | bitblt(&screen, r.min, &screen, r, 0); 30 | } 31 | 32 | int 33 | screensize(int *w, int *h) 34 | { 35 | return scrpix(w,h); 36 | } 37 | 38 | void 39 | dumperrmsg(int count, int type, int count0, int c) 40 | { 41 | uint8_t *cp; 42 | int i; 43 | 44 | cp = (uint8_t *) rcvstring(); 45 | fprintf(stderr, "samterm: host mesg: count %d %ux %ux %ux %s...ignored\n", 46 | count, type, count0, c, cp); 47 | i = 0; 48 | while (*cp) { 49 | fprintf(stderr, "%x ", *cp); 50 | if (i++ >= 20) { 51 | fprintf(stderr, "\n"); 52 | i = 0; 53 | } 54 | cp++; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /libXg/string.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | #include "libgint.h" 6 | 7 | Point 8 | string(Bitmap *b, Point p, XftFont *ft, char *s, Fcode f) 9 | { 10 | size_t length = strlen(s); 11 | int x = p.x; 12 | int y = p.y; 13 | 14 | x = p.x; 15 | y = p.y; 16 | if (b->flag & SHIFT){ 17 | x -= b->r.min.x; 18 | y -= b->r.min.y; 19 | } 20 | y += ft->ascent; 21 | 22 | if (!b->fd) 23 | b->fd = XftDrawCreate(_dpy, (Drawable)(b->id), DefaultVisual(_dpy, DefaultScreen(_dpy)), DefaultColormap(_dpy, DefaultScreen(_dpy))); 24 | XftDrawStringUtf8(b->fd, &fontcolor, ft, x, y, (FcChar8 *)s, length); 25 | 26 | x += strwidth(ft, s); 27 | 28 | p.x = (b->flag & SHIFT) ? x + b->r.min.x : x; 29 | p.x = x + b->r.min.x; 30 | return p; 31 | } 32 | 33 | 34 | int64_t 35 | strwidth(XftFont *f, char *s) 36 | { 37 | XGlyphInfo extents = {0}; 38 | XftTextExtentsUtf8(_dpy, f, (FcChar8 *)s, strlen(s), &extents); 39 | 40 | return extents.xOff; 41 | } 42 | 43 | int64_t 44 | charwidth(XftFont *f, wchar_t r) 45 | { 46 | char chars[MB_LEN_MAX + 1] = {0}; 47 | 48 | if (runetochar(chars, r) < 0) 49 | return 0; 50 | 51 | return strwidth(f, chars); 52 | } 53 | -------------------------------------------------------------------------------- /libXg/border.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | 5 | extern uint64_t _borderpixel; 6 | 7 | void 8 | border(Bitmap *l, Rectangle r, int i, Fcode c, uint64_t bg) 9 | { 10 | if(i > 0){ 11 | bitblt2(l, r.min, 12 | l, Rect(r.min.x, r.min.y, r.max.x, r.min.y+i), c, _borderpixel, bg); 13 | bitblt2(l, Pt(r.min.x, r.max.y-i), 14 | l, Rect(r.min.x, r.max.y-i, r.max.x, r.max.y), c, _borderpixel, bg); 15 | bitblt2(l, Pt(r.min.x, r.min.y+i), 16 | l, Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i), c, _borderpixel, bg); 17 | bitblt2(l, Pt(r.max.x-i, r.min.y+i), 18 | l, Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i), c, _borderpixel, bg); 19 | }else if(i < 0){ 20 | bitblt2(l, Pt(r.min.x, r.min.y+i), 21 | l, Rect(r.min.x, r.min.y+i, r.max.x, r.min.y), c, _borderpixel, bg); 22 | bitblt2(l, Pt(r.min.x, r.max.y), 23 | l, Rect(r.min.x, r.max.y, r.max.x, r.max.y-i), c, _borderpixel, bg); 24 | bitblt2(l, Pt(r.min.x+i, r.min.y+i), 25 | l, Rect(r.min.x+i, r.min.y+i, r.min.x, r.max.y-i), c, _borderpixel, bg); 26 | bitblt2(l, Pt(r.max.x, r.min.y+i), 27 | l, Rect(r.max.x, r.min.y+i, r.max.x-i, r.max.y-i), c, _borderpixel, bg); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ssam/ssam.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | arg0=`basename "$0"` 3 | 4 | usage() 5 | { 6 | printf "usage: %s [-n] [-e script] [-f sfile] [file ...]\n" "$1" 7 | } 8 | 9 | flagn=0 10 | flage="" 11 | flagf="" 12 | 13 | while getopts ne:f:h OPT; do 14 | case "$OPT" in 15 | n) 16 | flagn=1 17 | ;; 18 | 19 | e) 20 | if [ -z "$OPTARG" ]; then 21 | usage "$arg0" 22 | exit 1 23 | fi 24 | flage="$OPTARG" 25 | ;; 26 | f) 27 | if [ -z "$OPTARG" ]; then 28 | usage "$arg0" 29 | exit 1 30 | fi 31 | flagf="$OPTARG" 32 | ;; 33 | h) 34 | usage "$arg0" 35 | exit 0 36 | ;; 37 | esac 38 | done 39 | shift `expr "$OPTIND" - 1` 40 | 41 | if [ -z "$TMPDIR" ]; then 42 | TMPDIR="/tmp" 43 | fi 44 | tmp="$TMPDIR/ssam.tmp.$USER.$$" 45 | 46 | trap 'result=$?; rm -f "$tmp"; exit $result' INT EXIT KILL 47 | cat "$@" >"$tmp" 48 | 49 | { 50 | # select entire file 51 | echo ',{' 52 | echo k 53 | echo '}' 54 | echo 0k 55 | 56 | # run scripts, print 57 | [ ! -z "$flagf" ] && cat "$flagf" 58 | [ ! -z "$flage" ] && echo "$flage" 59 | [ "$flagn" -eq 0 ] && echo ',' 60 | } | sam -d "$tmp" 2>/dev/null 61 | 62 | exit $? -------------------------------------------------------------------------------- /libXg/texture.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | void 7 | texture(Bitmap *d, Rectangle r, Bitmap *s, Fcode f) 8 | { 9 | int x, y, w, h, bfunc; 10 | GC g; 11 | 12 | x = r.min.x; 13 | y = r.min.y; 14 | if(d->flag&SHIFT){ 15 | x -= d->r.min.x; 16 | y -= d->r.min.y; 17 | } 18 | g = _getcopygc(f, d, s, &bfunc); 19 | if(d->flag&SHIFT){ 20 | XSetTSOrigin(_dpy, g, -d->r.min.x, -d->r.min.y); 21 | }else 22 | XSetTSOrigin(_dpy, g, 0, 0); 23 | w = Dx(r); 24 | h = Dy(r); 25 | if(bfunc == UseFillRectangle){ 26 | /* source isn't involved at all */ 27 | XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); 28 | }else if(bfunc == UseCopyArea){ 29 | XSetTile(_dpy, g, (Drawable)s->id); 30 | XSetFillStyle(_dpy, g, FillTiled); 31 | XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); 32 | XSetFillStyle(_dpy, g, FillSolid); 33 | }else{ 34 | if(s->ldepth != 0) 35 | berror("unsupported texture"); 36 | XSetStipple(_dpy, g, (Drawable)s->id); 37 | XSetFillStyle(_dpy, g, FillOpaqueStippled); 38 | XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); 39 | XSetFillStyle(_dpy, g, FillSolid); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 1998 Lucent Technologies - All rights reserved. 2 | # Changes Copyright (c) 2014-2015 Rob King 3 | # 4 | # master makefile for sam. configure sub-makefiles first. 5 | # 6 | 7 | MODE?=user 8 | 9 | all: config.mk lXg lframe samdir samtermdir docdir 10 | 11 | config.mk: 12 | cp config.mk.def config.mk 13 | 14 | lXg: 15 | cd libXg; $(MAKE) 16 | 17 | lframe: 18 | cd libframe; $(MAKE) 19 | 20 | docdir: 21 | cd doc; $(MAKE) 22 | 23 | samdir: 24 | cd sam; $(MAKE) 25 | 26 | samtermdir: 27 | cd samterm; $(MAKE) 28 | 29 | install: 30 | @xdg-desktop-menu install --mode $(MODE) deadpixi-sam.desktop || echo "unable to install desktop entry" 31 | cd libXg; $(MAKE) install 32 | cd libframe; $(MAKE) install 33 | cd sam; $(MAKE) install 34 | cd samterm; $(MAKE) install 35 | cd doc; $(MAKE) install 36 | cd ssam; $(MAKE) install 37 | 38 | uninstall: 39 | @xdg-desktop-menu uninstall --mode $(MODE) deadpixi-sam.desktop || echo "unable to uninstall desktop entry" 40 | cd libXg; $(MAKE) uninstall 41 | cd libframe; $(MAKE) uninstall 42 | cd sam; $(MAKE) uninstall 43 | cd samterm; $(MAKE) uninstall 44 | cd doc; $(MAKE) uninstall 45 | cd ssam; $(MAKE) uninstall 46 | 47 | clean: 48 | cd libXg; $(MAKE) clean 49 | cd libframe; $(MAKE) clean 50 | cd sam; $(MAKE) clean 51 | cd samterm; $(MAKE) clean 52 | cd ssam; $(MAKE) clean 53 | 54 | nuke: clean 55 | rm -f config.mk 56 | -------------------------------------------------------------------------------- /libXg/GwinP.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #ifndef GWINP_H 3 | #define GWINP_H 4 | 5 | #include "Gwin.h" 6 | 7 | /* Gwin is derived from Core */ 8 | 9 | /* Gwin instance part */ 10 | typedef struct { 11 | /* New resource fields */ 12 | Pixel foreground; 13 | Boolean forwardr; /* does right button scroll forward? */ 14 | Reshapefunc reshaped; /* Notify app of reshape */ 15 | Charfunc gotchar; /* Notify app of char arrival */ 16 | Mousefunc gotmouse; /* Notify app of mouse change */ 17 | String selection; /* Current selection */ 18 | Boolean selxfered; /* Has selection been swapped. */ 19 | int compose; 20 | } GwinPart; 21 | 22 | /* Full instance record */ 23 | typedef struct _GwinRec { 24 | CorePart core; 25 | GwinPart gwin; 26 | } GwinRec; 27 | 28 | /* New type for class methods */ 29 | typedef String (*SelSwapProc)(Widget, String); 30 | 31 | /* Class part */ 32 | typedef struct { 33 | SelSwapProc select_swap; 34 | XtPointer extension; 35 | } GwinClassPart; 36 | 37 | /* Full class record */ 38 | typedef struct _GwinClassRec { 39 | CoreClassPart core_class; 40 | GwinClassPart gwin_class; 41 | } GwinClassRec, *GwinWidgetClass; 42 | 43 | /* External definition for class record */ 44 | extern GwinClassRec gwinClassRec; 45 | 46 | #endif /* GWINP_H */ 47 | -------------------------------------------------------------------------------- /libXg/balloc.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | Bitmap* 7 | balloc(Rectangle r, int ldepth) 8 | { 9 | Bitmap *b; 10 | 11 | b = _balloc(r, ldepth); 12 | bitblt(b, r.min, b, r, Zero); 13 | return b; 14 | } 15 | 16 | Bitmap* 17 | _balloc(Rectangle r, int ldepth) 18 | { 19 | int id; 20 | Bitmap *b; 21 | int ld; 22 | Rectangle rx; 23 | 24 | b = (Bitmap *)calloc(1, sizeof(Bitmap)); 25 | if(b == 0) 26 | berror("balloc malloc"); 27 | if (ldepth == 0) 28 | ld = 0; 29 | else 30 | ld = screen.ldepth; 31 | rx = r; 32 | if (Dx(rx) == 0) 33 | rx.max.x++; 34 | if (Dy(rx) == 0) 35 | rx.max.y++; 36 | id = (int) XCreatePixmap(_dpy, (Drawable)screen.id, 37 | Dx(rx), Dy(rx), _ld2d[ld]); 38 | b->ldepth = ldepth; 39 | b->r = r; 40 | b->clipr = r; 41 | b->id = id; 42 | b->cache = 0; 43 | if(ldepth == 0) 44 | b->flag = DP1|BL1; 45 | else 46 | b->flag = screen.flag&BL1; 47 | if(r.min.x==0 && r.min.y ==0) 48 | b->flag |= ZORG; 49 | else 50 | b->flag |= SHIFT; 51 | return b; 52 | } 53 | 54 | void 55 | bfree(Bitmap *b) 56 | { 57 | if (b->fd) 58 | XftDrawDestroy(b->fd); 59 | XFreePixmap(_dpy, (Pixmap)b->id); 60 | free(b); 61 | } 62 | -------------------------------------------------------------------------------- /libframe/frinit.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | int tabwidth = 8; 7 | extern bool expandtabs; 8 | 9 | void 10 | frinit(Frame *f, Rectangle r, XftFont *ft, Bitmap *b, uint64_t bg) 11 | { 12 | int tabs = atoi(getenv("TABS") ? getenv("TABS") : ""); 13 | if (tabs < 0){ 14 | tabs = -tabs; 15 | expandtabs = true; 16 | } 17 | 18 | if (tabs > 0 && tabs <= 12) 19 | tabwidth = tabs; 20 | 21 | f->font = ft; 22 | /* ft->height is NOT CORRECT; we must use ascent + descent to 23 | clear the lowest edge of characters. - cks */ 24 | f->fheight = ft->ascent + ft->descent; 25 | f->maxtab = tabwidth*charwidth(ft, '0'); 26 | f->nbox = 0; 27 | f->nalloc = 0; 28 | f->nchars = 0; 29 | f->nlines = 0; 30 | f->p0 = 0; 31 | f->p1 = 0; 32 | f->box = 0; 33 | f->lastlinefull = 0; 34 | f->bg = bg; 35 | frsetrects(f, r, b); 36 | } 37 | 38 | void 39 | frsetrects(Frame *f, Rectangle r, Bitmap *b) 40 | { 41 | f->b = b; 42 | f->entire = r; 43 | f->r = r; 44 | f->r.max.y -= (r.max.y-r.min.y)%f->fheight; 45 | f->left = r.min.x+1; 46 | f->maxlines = (r.max.y-r.min.y)/f->fheight; 47 | } 48 | 49 | void 50 | frclear(Frame *f) 51 | { 52 | if(f->nbox) 53 | _frdelbox(f, 0, f->nbox-1); 54 | if(f->box) 55 | free(f->box); 56 | f->box = 0; 57 | } 58 | -------------------------------------------------------------------------------- /sam/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 1998 Lucent Technologies - All rights reserved. 2 | # 3 | # Prototype Makefile for sam 4 | # 5 | include ../config.mk 6 | 7 | # add -Iincludedir for any include directories that need to be searched 8 | # for posix header files (for UMIPS, add -I/usr/include/posix) 9 | INCS=-I../include 10 | 11 | # RSAMNAME and TERMNAME contain the names of the files containing the 12 | # sam and samterm executables, respectively. SAMDIR is the directory 13 | # where sam is to be installed. 14 | RSAMNAME=sam 15 | TERMNAME=samterm 16 | SAMDIR=$(BINDIR) 17 | 18 | # Set SHELLNAME and SHELLPATH to the name of a shell and the pathname 19 | # of its executable 20 | SHELLNAME=sh 21 | SHELLPATH=/bin/sh 22 | 23 | CFLAGS+=$(STANDARDS) $(INCS) $(INCLUDES) -DRXPATH='"$(RXPATH)"' 24 | 25 | CC?=c99 26 | 27 | OBJ=sam.o address.o buffer.o cmd.o error.o file.o io.o \ 28 | list.o mesg.o moveto.o multi.o rasp.o regexp.o shell.o \ 29 | string.o sys.o unix.o xec.o 30 | 31 | all: sam 32 | 33 | sam: $(OBJ) 34 | $(CC) -o sam $(OBJ) $(LDFLAGS) 35 | 36 | clean: 37 | rm -f *.o core sam 38 | 39 | nuke: clean 40 | rm -f sam 41 | 42 | install: sam 43 | mkdir -p $(SAMDIR) 44 | cp sam $(SAMDIR)/$(RSAMNAME) 45 | ln -f $(SAMDIR)/$(RSAMNAME) $(SAMDIR)/B 46 | 47 | uninstall: 48 | rm -f $(SAMDIR)/$(RSAMNAME) 49 | rm -f $(SAMDIR)/B 50 | 51 | $(OBJ): sam.h ../include/u.h errors.h mesg.h 52 | 53 | cmd.o: parse.h 54 | xec.o: parse.h 55 | 56 | unix.o: sam.h ../include/u.h errors.h mesg.h 57 | $(CC) -c $(CFLAGS) unix.c 58 | -------------------------------------------------------------------------------- /libframe/frdraw.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | void 7 | _frredraw(Frame *f, Point pt) 8 | { 9 | Frbox *b; 10 | int nb; 11 | for(nb=0,b=f->box; nbnbox; nb++, b++){ 12 | _frcklinewrap(f, &pt, b); 13 | if(b->nrune >= 0) 14 | string(f->b, pt, f->font, (char *)b->a.ptr, S^D); 15 | pt.x += b->wid; 16 | } 17 | } 18 | 19 | Point 20 | _frdraw(Frame *f, Point pt) 21 | { 22 | Frbox *b; 23 | int nb, n; 24 | for(b=f->box,nb=0; nbnbox; nb++, b++){ 25 | _frcklinewrap0(f, &pt, b); 26 | if(pt.y == f->r.max.y){ 27 | f->nchars -= _frstrlen(f, nb); 28 | _frdelbox(f, nb, f->nbox-1); 29 | break; 30 | } 31 | if(b->nrune > 0){ 32 | n = _frcanfit(f, pt, b); 33 | if(n == 0) 34 | berror("draw: _frcanfit==0"); 35 | if(n != b->nrune){ 36 | _frsplitbox(f, nb, n); 37 | b = &f->box[nb]; 38 | } 39 | pt.x += b->wid; 40 | }else{ 41 | if(b->a.b.bc == '\n') 42 | pt.x = f->left, pt.y+=f->fheight; 43 | else 44 | pt.x += _frnewwid(f, pt, b); 45 | } 46 | } 47 | return pt; 48 | } 49 | 50 | int 51 | _frstrlen(Frame *f, int nb) 52 | { 53 | int n; 54 | 55 | for(n=0; nbnbox; nb++) 56 | n += NRUNE(&f->box[nb]); 57 | return n; 58 | } 59 | -------------------------------------------------------------------------------- /samterm/flayer.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #undef None 3 | typedef enum Vis{ 4 | None=0, 5 | Some, 6 | All 7 | }Vis; 8 | 9 | enum{ 10 | Clicktime=1000 /* one second */ 11 | }; 12 | 13 | typedef struct Flayer Flayer; 14 | 15 | /* note that we track background color, but not foreground 16 | * all layers have the same foreground color 17 | */ 18 | struct Flayer 19 | { 20 | uint64_t bg; 21 | Frame f; 22 | int64_t origin; /* offset of first char in flayer */ 23 | int64_t p0, p1; 24 | int64_t click; /* time at which selection click occurred, in HZ */ 25 | wchar_t *(*textfn)(Flayer*, int64_t, uint64_t*); 26 | int user0; 27 | void *user1; 28 | Rectangle entire; 29 | Rectangle scroll; 30 | Vis visible; 31 | }; 32 | 33 | void flborder(Flayer*, bool); 34 | void flclose(Flayer*); 35 | void fldelete(Flayer*, int64_t, int64_t); 36 | void flfp0p1(Flayer*, uint64_t*, uint64_t*); 37 | void flinit(Flayer*, Rectangle, XftFont*, uint64_t bg); 38 | void flinsert(Flayer*, wchar_t*, wchar_t*, int64_t); 39 | void flnew(Flayer*, wchar_t *(*fn)(Flayer*, int64_t, uint64_t*), int, void*); 40 | int flprepare(Flayer*); 41 | Rectangle flrect(Flayer*, Rectangle); 42 | void flrefresh(Flayer*, Rectangle, int); 43 | void flreshape(Rectangle); 44 | bool flselect(Flayer*); 45 | void flsetselect(Flayer*, int64_t, int64_t); 46 | void flstart(Rectangle); 47 | void flupfront(Flayer*); 48 | Flayer *flwhich(Point); 49 | 50 | #define FLMARGIN 4 51 | #define FLSCROLLWID 12 52 | #define FLGAP 4 53 | -------------------------------------------------------------------------------- /libXg/wrbitmap.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | #include 6 | 7 | #include 8 | void 9 | wrbitmap(Bitmap *b, int miny, int maxy, unsigned char *data) 10 | { 11 | XImage *im; 12 | int w, h, inld, outld, l, offset, px; 13 | GC g; 14 | char *tdata; 15 | 16 | w = Dx(b->r); 17 | h = maxy - miny; 18 | inld = b->ldepth; 19 | outld = (b->ldepth == 0) ? 0 : screen.ldepth; 20 | px = 1<<(3-outld); /* pixels per byte */ 21 | /* set l to number of bytes of data per scan line */ 22 | if(b->r.min.x >= 0) 23 | offset = b->r.min.x % px; 24 | else 25 | offset = px - b->r.min.x % px; 26 | l = (-b->r.min.x+px-1)/px; 27 | if(b->r.max.x >= 0) 28 | l += (b->r.max.x+px-1)/px; 29 | else 30 | l -= b->r.max.x/px; 31 | l *= h; 32 | 33 | tdata = (char *)malloc(l); 34 | if (tdata == (char *) 0) 35 | berror("wrbitmap malloc"); 36 | if (inld == outld) 37 | memcpy((void*)tdata, (void*)data, l); 38 | else 39 | _ldconvert((char*)data, inld, tdata, outld, w, h); 40 | 41 | im = XCreateImage(_dpy, 0, 1 << outld, ZPixmap, 0, tdata, w, h, 8, 0); 42 | 43 | /* Botched interface to XCreateImage doesn't let you set these: */ 44 | im->bitmap_bit_order = MSBFirst; 45 | im->byte_order = MSBFirst; 46 | 47 | g = _getfillgc(S, b, ~0); 48 | XSetBackground(_dpy, g, b->flag&DP1 ? 0 : _bgpixel); 49 | XPutImage(_dpy, (Drawable)b->id, g, im, offset, 0, 0, miny - b->r.min.y, w-offset, h); 50 | XDestroyImage(im); 51 | } 52 | -------------------------------------------------------------------------------- /libXg/getrect.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | static void 7 | grabcursor(void) 8 | { 9 | raisewindow(); 10 | 11 | /* Grab X server with an limp wrist. */ 12 | while (XGrabPointer(_dpy, screen.id, False, 13 | ButtonPressMask|ButtonReleaseMask| 14 | ButtonMotionMask|StructureNotifyMask, 15 | GrabModeAsync, GrabModeAsync, None, None, CurrentTime) 16 | != GrabSuccess) 17 | sleep(2); 18 | 19 | /* Grab the keyboard too */ 20 | XSetInputFocus(_dpy, screen.id, RevertToParent, CurrentTime); 21 | } 22 | 23 | static void 24 | ungrabcursor(void) 25 | { 26 | XUngrabPointer(_dpy, CurrentTime); 27 | } 28 | 29 | Rectangle 30 | getrect(int but, Mouse *m){ 31 | Rectangle r, rc; 32 | 33 | but = 1<<(but-1); 34 | cursorswitch(SweepCursor); 35 | while(m->buttons) 36 | *m = emouse(); 37 | grabcursor(); 38 | while(!(m->buttons & but)){ 39 | *m = emouse(); 40 | if(m->buttons & (7^but)) 41 | goto Return; 42 | } 43 | r.min = m->xy; 44 | r.max = m->xy; 45 | do{ 46 | rc = rcanon(r); 47 | border(&screen, rc, 2, F&~D, _bgpixel); 48 | *m = emouse(); 49 | border(&screen, rc, 2, F&~D, _bgpixel); 50 | r.max = m->xy; 51 | }while(m->buttons & but); 52 | 53 | Return: 54 | cursorswitch(DefaultCursor); 55 | if(m->buttons & (7^but)){ 56 | rc.min.x = rc.max.x = 0; 57 | rc.min.y = rc.max.y = 0; 58 | while(m->buttons) 59 | *m = emouse(); 60 | } 61 | ungrabcursor(); 62 | return rc; 63 | } 64 | -------------------------------------------------------------------------------- /libXg/ldconvert.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | void 7 | _ldconvert(char *in, int inld, char *out, int outld, int w, int h) 8 | { 9 | int a, b, i, j, i1, j1, j2, mask; 10 | int ind, inl, outd, outl; 11 | int hh, ww; 12 | char *p, *q; 13 | 14 | i1 = 8 >> inld; 15 | j1 = 8 >> outld; 16 | ind = 1 << inld; 17 | outd = 1 << outld; 18 | inl = ((w << inld) + 7)/8; 19 | outl = ((w << outld) + 7)/8; 20 | b = 0; 21 | 22 | if (ind > outd) { 23 | mask = 256 - (256 >> outd); 24 | for (hh = 0; hh < h; hh++, in += inl, out += outl) 25 | for (p = in, q = out, ww = 0; ww < w; ww++) { 26 | for (j = j1; j > 0; ) { 27 | a = *p++; 28 | for (i = i1; i > 0; i--, j--) { 29 | b |= a & mask; 30 | a <<= ind; 31 | b <<= outd; 32 | } 33 | } 34 | *q++ = (b >> 8); 35 | } 36 | } else { 37 | j2 = 1 << (outld - inld); 38 | mask = 256 - (256 >> ind); 39 | for (hh = 0; hh < h; hh++, in += inl, out += outl) 40 | for (p = in, q = out, ww = 0; ww < w; ww++) { 41 | a = *p++; 42 | for (i = i1; i > 0; ) { 43 | for (j = j1; j > 0; j--, i--) { 44 | b |= a & mask; 45 | a <<= ind; 46 | b <<= outd; 47 | } 48 | for (j = j2; j > 0; j--) 49 | b |= (b << ind); 50 | *q++ = (b >> 8); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /include/regexp.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | 3 | typedef struct Resub Resub; 4 | typedef struct Reclass Reclass; 5 | typedef struct Reinst Reinst; 6 | typedef struct Reprog Reprog; 7 | 8 | /* 9 | * Sub expression matches 10 | */ 11 | struct Resub{ 12 | union 13 | { 14 | char *sp; 15 | wchar_t *rsp; 16 | }s; 17 | union 18 | { 19 | char *ep; 20 | wchar_t *rep; 21 | }e; 22 | }; 23 | 24 | /* 25 | * character class, each pair of rune's defines a range 26 | */ 27 | struct Reclass{ 28 | wchar_t *end; 29 | wchar_t spans[64]; 30 | }; 31 | 32 | /* 33 | * Machine instructions 34 | */ 35 | struct Reinst{ 36 | int type; 37 | union { 38 | Reclass *cp; /* class pointer */ 39 | wchar_t r; /* character */ 40 | int subid; /* sub-expression id for RBRA and LBRA */ 41 | Reinst *right; /* right child of OR */ 42 | }u1; 43 | union { /* regexp relies on these two being in the same union */ 44 | Reinst *left; /* left child of OR */ 45 | Reinst *next; /* next instruction for CAT & LBRA */ 46 | }u2; 47 | }; 48 | 49 | /* 50 | * Reprogram definition 51 | */ 52 | struct Reprog{ 53 | Reinst *startinst; /* start pc */ 54 | Reclass class[16]; /* .data */ 55 | Reinst firstinst[5]; /* .text */ 56 | }; 57 | 58 | extern Reprog *regcomp(char*); 59 | extern Reprog *regcomplit(char*); 60 | extern Reprog *regcompnl(char*); 61 | extern void regerror(char*); 62 | extern int regexec(Reprog*, char*, Resub*, int); 63 | extern void regsub(char*, char*, Resub*, int); 64 | extern int rregexec(Reprog*, wchar_t*, Resub*, int); 65 | extern void rregsub(wchar_t*, wchar_t*, Resub*, int); 66 | -------------------------------------------------------------------------------- /doc/samrc: -------------------------------------------------------------------------------- 1 | # This is samrc as I usually use it. 2 | 3 | # Control-A/E jumps to beginning/end of line 4 | bind C a command bol 5 | bind C e command eol 6 | 7 | # Control-H/L/J/K moves left/right/down/up 8 | bind C h command charleft 9 | bind C l command charright 10 | bind C j command linedown 11 | bind C k command lineup 12 | 13 | # Control-Space highlights recent text 14 | bind C space command escape 15 | 16 | # Escape jumps between command file and current file 17 | bind * Escape command jump 18 | 19 | # Control-U and Control-Shift-BackSpace deletes to beginning of line 20 | bind C u command delbol 21 | bind CS BackSpace command delbol 22 | 23 | # Control-W/BackSpace deletes previous word 24 | bind C w command delword 25 | bind C BackSpace command delword 26 | 27 | # Control-X/C/V/Q does cut/snarf/paste/exchange 28 | bind C x command cut 29 | bind C c command snarf 30 | bind C v command paste 31 | bind C q command exchange 32 | 33 | # Arrow keys and Page Up/Down work as expected 34 | bind * Up command lineup 35 | bind * Down command linedown 36 | bind * Left command charleft 37 | bind * Right command charright 38 | bind * Prior command scrollup 39 | bind * Next command scrolldown 40 | 41 | # All of the default movement key sequences were rebound as something else, 42 | # except for Control-D. Let's remove any special handling for that binding. 43 | unbind C d 44 | 45 | # Control-Z sends an undo command. 46 | bind C z command send u 47 | 48 | # Control-Return inserts a line below the current one 49 | bind C Return command send +-a/\n/ 50 | 51 | # Control-S writes the file, Control-Shift-S writes all files. 52 | bind C s command write 53 | bind CS s command send X w 54 | 55 | # Control-N does a search, Control-Shift-N does a look 56 | bind C n command search 57 | bind CS n command look 58 | 59 | # I like 12pt Go Regular 60 | font Go Regular:size=12 61 | 62 | # Use black for text and borders, and an angry fruit salad for backgrounds 63 | foreground black 64 | border black 65 | background white:seashell:lightgreen:oldlace:lightcyan:gainsboro:lightyellow:mintcream:snow:lightblue:thistle 66 | 67 | # Expand tabs and have tabstops every four columns 68 | tabs 4 69 | expandtabs true 70 | 71 | # Automatically indent lines 72 | autoindent true 73 | -------------------------------------------------------------------------------- /libXg/bitblt.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | void 7 | bitblt(Bitmap *d, Point p, Bitmap *s, Rectangle r, Fcode f) 8 | { 9 | bitblt2(d, p, s, r, f, _fgpixel, _bgpixel); 10 | } 11 | 12 | void 13 | bitblt2(Bitmap *d, Point p, Bitmap *s, Rectangle r, Fcode f, uint64_t fg, uint64_t bg) 14 | { 15 | int sx, sy, dx, dy, bfunc; 16 | GC g; 17 | uint64_t plane; 18 | Bitmap *btmp; 19 | 20 | if (fg == 0) 21 | fg = _fgpixel; 22 | 23 | if (bg == 0) 24 | bg = _bgpixel; 25 | 26 | if(Dx(r)<=0 || Dy(r)<=0) 27 | return; 28 | sx = r.min.x; 29 | sy = r.min.y; 30 | if(s->flag&SHIFT){ 31 | sx -= s->r.min.x; 32 | sy -= s->r.min.y; 33 | } 34 | dx = p.x; 35 | dy = p.y; 36 | if(d->flag&SHIFT){ 37 | dx -= d->r.min.x; 38 | dy -= d->r.min.y; 39 | } 40 | g = _getcopygc2(f, d, s, &bfunc, fg, bg); 41 | if(bfunc == UseCopyArea) 42 | XCopyArea(_dpy, (Drawable)s->id, (Drawable)d->id, g, 43 | sx, sy, Dx(r), Dy(r), dx, dy); 44 | else if(bfunc == UseFillRectangle){ 45 | XFillRectangle(_dpy, (Drawable)d->id, g, 46 | dx, dy, Dx(r), Dy(r)); 47 | }else{ 48 | /* bfunc == UseCopyPlane */ 49 | plane = _ld2dmask[s->ldepth]; 50 | plane &= ~(plane>>1); 51 | if(0/*f == S*/) 52 | XCopyPlane(_dpy, (Drawable)s->id, (Drawable)d->id, g, 53 | sx, sy, Dx(r), Dy(r), dx, dy, plane); 54 | else { 55 | /* 56 | * CopyPlane can only do func code S, 57 | * so copy src rect into a bitmap with the same depth 58 | * as the dest, then do the bitblt from the tmp. 59 | * This won't recurse again because we only get 60 | * UseCopyPlane with differing bitmap depths 61 | */ 62 | btmp = _balloc(Rect(0,0,Dx(r),Dy(r)), d->ldepth); 63 | XCopyPlane(_dpy, (Drawable)s->id, (Drawable)btmp->id, g, 64 | sx, sy, Dx(r), Dy(r), 0, 0, plane); 65 | bitblt(d, p, btmp, btmp->r, f); 66 | bfree(btmp); 67 | } 68 | } 69 | XFlush(_dpy); 70 | } 71 | -------------------------------------------------------------------------------- /sam/parse.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 4 | typedef struct Addr Addr; 5 | typedef struct Cmd Cmd; 6 | struct Addr 7 | { 8 | char type; /* # (char addr), l (line addr), / ? . $ + - , ; */ 9 | union{ 10 | String *re; 11 | Addr *aleft; /* left side of , and ; */ 12 | } g; 13 | Posn num; 14 | Addr *next; /* or right side of , and ; */ 15 | }; 16 | 17 | #define are g.re 18 | #define left g.aleft 19 | 20 | struct Cmd 21 | { 22 | Addr *addr; /* address (range of text) */ 23 | String *re; /* regular expression for e.g. 'x' */ 24 | union{ 25 | Cmd *cmd; /* target of x, g, {, etc. */ 26 | String *text; /* text of a, c, i; rhs of s */ 27 | Addr *addr; /* address for m, t */ 28 | } g; 29 | Cmd *next; /* pointer to next element in {} */ 30 | int16_t num; 31 | uint16_t flag; /* whatever */ 32 | uint16_t cmdc; /* command character; 'x' etc. */ 33 | }; 34 | 35 | #define ccmd g.cmd 36 | #define ctext g.text 37 | #define caddr g.addr 38 | 39 | extern struct cmdtab{ 40 | uint16_t cmdc; /* command character */ 41 | uint8_t text; /* takes a textual argument? */ 42 | uint8_t regexp; /* takes a regular expression? */ 43 | uint8_t addr; /* takes an address (m or t)? */ 44 | uint8_t defcmd; /* default command; 0==>none */ 45 | uint8_t defaddr; /* default address */ 46 | uint8_t count; /* takes a count e.g. s2/// */ 47 | wchar_t *token; /* takes text terminated by one of these */ 48 | bool (*fn)(File*, Cmd*); /* function to call with parse tree */ 49 | }cmdtab[]; 50 | 51 | enum Defaddr{ /* default addresses */ 52 | aNo, 53 | aDot, 54 | aAll 55 | }; 56 | 57 | bool nl_cmd(File*, Cmd*), a_cmd(File*, Cmd*), b_cmd(File*, Cmd*); 58 | bool c_cmd(File*, Cmd*), cd_cmd(File*, Cmd*), d_cmd(File*, Cmd*); 59 | bool D_cmd(File*, Cmd*), e_cmd(File*, Cmd*); 60 | bool f_cmd(File*, Cmd*), g_cmd(File*, Cmd*), i_cmd(File*, Cmd*); 61 | bool k_cmd(File*, Cmd*), m_cmd(File*, Cmd*), n_cmd(File*, Cmd*); 62 | bool p_cmd(File*, Cmd*), q_cmd(File*, Cmd*); 63 | bool P_cmd(File*, Cmd*), P_cmd(File*, Cmd*); 64 | bool s_cmd(File*, Cmd*), u_cmd(File*, Cmd*), w_cmd(File*, Cmd*); 65 | bool x_cmd(File*, Cmd*), X_cmd(File*, Cmd*), plan9_cmd(File*, Cmd*); 66 | bool eq_cmd(File*, Cmd*); 67 | 68 | 69 | String *getregexp(int); 70 | Addr *newaddr(void); 71 | Address address(Addr*, Address, int); 72 | int cmdexec(File*, Cmd*); 73 | -------------------------------------------------------------------------------- /sam/multi.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include "sam.h" 3 | 4 | #include 5 | 6 | List file; 7 | uint16_t tag; 8 | 9 | File * 10 | newfile(void) 11 | { 12 | File *f; 13 | 14 | inslist(&file, 0, (int64_t)(f = Fopen())); 15 | f->tag = tag++; 16 | if(downloaded) 17 | outTs(Hnewname, f->tag); 18 | /* already sorted; file name is "" */ 19 | return f; 20 | } 21 | 22 | int 23 | whichmenu(File *f) 24 | { 25 | int i; 26 | 27 | for(i=0; itag); 42 | dellist(&file, w); 43 | Fclose(f); 44 | } 45 | 46 | void 47 | sortname(File *f) 48 | { 49 | int i, cmp, w; 50 | int dupwarned; 51 | 52 | w = whichmenu(f); 53 | dupwarned = false; 54 | dellist(&file, w); 55 | if(f == cmd) 56 | i = 0; 57 | else for(i=0; iname, &file.filepptr[i]->name); 59 | if(cmp==0 && !dupwarned){ 60 | dupwarned = true; 61 | warn_S(Wdupname, &f->name); 62 | }else if(cmp<0 && (i>0 || cmd==0)) 63 | break; 64 | } 65 | inslist(&file, i, (int64_t)f); 66 | if(downloaded) 67 | outTsS(Hmovname, f->tag, &f->name); 68 | } 69 | 70 | void 71 | state(File *f, state_t cleandirty) 72 | { 73 | if(f == cmd) 74 | return; 75 | if(downloaded && whichmenu(f)>=0){ /* else flist or menu */ 76 | if(f->state==Dirty && cleandirty!=Dirty) 77 | outTs(Hclean, f->tag); 78 | else if(f->state!=Dirty && cleandirty==Dirty) 79 | outTs(Hdirty, f->tag); 80 | } 81 | f->state = cleandirty; 82 | } 83 | 84 | File * 85 | lookfile(String *s, bool fuzzy) 86 | { 87 | int i; 88 | File *b = NULL; 89 | char *sc = Strtoc(s); 90 | 91 | for(i=0; iname, s) == 0) 93 | return file.filepptr[i]; 94 | 95 | if (fuzzy){ 96 | char *ac = Strtoc(&file.filepptr[i]->name); 97 | if (strcmp(basename(sc), ac) == 0) 98 | return free(sc), free(ac), file.filepptr[i]; 99 | 100 | if (!b && strstr(ac, sc)) 101 | b = file.filepptr[i]; 102 | free(ac); 103 | } 104 | } 105 | 106 | free(sc); 107 | return b; 108 | } 109 | -------------------------------------------------------------------------------- /libframe/frutil.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | _frcanfit(Frame *f, Point pt, Frbox *b) 8 | { 9 | int left, w, nr; 10 | uint8_t *p; 11 | wchar_t r; 12 | 13 | left = f->r.max.x-pt.x; 14 | if(b->nrune < 0) 15 | return b->a.b.minwid <= left; 16 | if(left >= b->wid) 17 | return b->nrune; 18 | for(nr=0,p=b->a.ptr; *p; p+=w,nr++){ 19 | r = *p; 20 | w = chartorune(&r, (char*)p); 21 | left -= charwidth(f->font, r); 22 | if(left < 0) 23 | return nr; 24 | } 25 | berror("_frcanfit can't"); 26 | return 0; 27 | } 28 | 29 | void 30 | _frcklinewrap(Frame *f, Point *p, Frbox *b) 31 | { 32 | if((b->nrune<0? b->a.b.minwid : b->wid) > f->r.max.x-p->x){ 33 | p->x = f->left; 34 | p->y += f->fheight; 35 | } 36 | } 37 | 38 | void 39 | _frcklinewrap0(Frame *f, Point *p, Frbox *b) 40 | { 41 | if(_frcanfit(f, *p, b) == 0){ 42 | p->x = f->left; 43 | p->y += f->fheight; 44 | } 45 | } 46 | 47 | void 48 | _fradvance(Frame *f, Point *p, Frbox *b) 49 | { 50 | if(b->nrune<0 && b->a.b.bc=='\n'){ 51 | p->x = f->left; 52 | p->y += f->fheight; 53 | }else 54 | p->x += b->wid; 55 | } 56 | 57 | int 58 | _frnewwid(Frame *f, Point pt, Frbox *b) 59 | { 60 | int c, x; 61 | 62 | c = f->r.max.x; 63 | x = pt.x; 64 | if(b->nrune >= 0) 65 | return b->wid; 66 | if(b->a.b.bc == '\t'){ 67 | if(x+b->a.b.minwid > c) 68 | x = pt.x = f->left; 69 | x += f->maxtab; 70 | x -= (x-f->left)%f->maxtab; 71 | if(x-pt.xa.b.minwid || x>c) 72 | x = pt.x+b->a.b.minwid; 73 | b->wid = x-pt.x; 74 | } 75 | return b->wid; 76 | } 77 | 78 | void 79 | _frclean(Frame *f, Point pt, int n0, int n1) /* look for mergeable boxes */ 80 | { 81 | Frbox *b; 82 | int nb, c; 83 | 84 | c = f->r.max.x; 85 | for(nb=n0; nbbox[nb]; 87 | _frcklinewrap(f, &pt, b); 88 | while(b[0].nrune>=0 && nb=0 && pt.x+b[0].wid+b[1].widbox[nb]; 92 | } 93 | _fradvance(f, &pt, &f->box[nb]); 94 | } 95 | for(; nbnbox; nb++){ 96 | b = &f->box[nb]; 97 | _frcklinewrap(f, &pt, b); 98 | _fradvance(f, &pt, &f->box[nb]); 99 | } 100 | f->lastlinefull = false; 101 | if(pt.y >= f->r.max.y) 102 | f->lastlinefull = true; 103 | } 104 | -------------------------------------------------------------------------------- /libframe/frselect.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | void 7 | frselect(Frame *f, Mouse *m) /* when called, button 1 is down */ 8 | { 9 | uint64_t p0, p1, q; 10 | Point mp, pt0, pt1, qt; 11 | 12 | mp = m->xy; 13 | 14 | Again: 15 | f->modified = 0; 16 | frselectp(f, F&~D); 17 | p0 = p1 = frcharofpt(f, mp); 18 | pt0 = frptofchar(f, p0); 19 | pt1 = frptofchar(f, p1); 20 | frselectf(f, pt0, pt1, F&~D); 21 | do{ 22 | if(f->modified) /* special hack so 8½ can frselect in parallel */ 23 | goto Again; 24 | q = frcharofpt(f, m->xy); 25 | if(p1 != q){ 26 | if(p0 == p1) 27 | frselectf(f, pt0, pt1, F&~D); 28 | qt = frptofchar(f, q); 29 | if(p1 < q) 30 | frselectf(f, pt1, qt, F&~D); 31 | else 32 | frselectf(f, qt, pt1, F&~D); 33 | p1 = q; 34 | pt1 = qt; 35 | if(p0 == p1) 36 | frselectf(f, pt0, pt1, F&~D); 37 | } 38 | f->modified = 0; 39 | if(p0 < p1) 40 | f->p0 = p0, f->p1 = p1; 41 | else 42 | f->p0 = p1, f->p1 = p0; 43 | frgetmouse(); 44 | }while((m->buttons & 7) == 1); 45 | } 46 | /* it is assumed p0<=p1 and both were generated by frptofchar() */ 47 | void 48 | frselectf(Frame *f, Point p0, Point p1, Fcode c) 49 | { 50 | int n; 51 | Point q0, q1; 52 | 53 | if(p0.x == f->left) 54 | p0.x = f->r.min.x; 55 | if(p1.x == f->left) 56 | p1.x = f->r.min.x; 57 | q0 = p0; 58 | q1 = p1; 59 | q0.y += f->fheight; 60 | q1.y += f->fheight; 61 | n = (p1.y-p0.y)/f->fheight; 62 | if(f->b == 0) 63 | berror("frselectf b==0"); 64 | if(p0.y == f->r.max.y) 65 | return; 66 | if(n == 0){ 67 | if(p0.x == p1.x){ 68 | if(p0.x == f->r.min.x) 69 | q1.x++; 70 | else 71 | p0.x--; 72 | } 73 | bitblt2(f->b, p0, f->b, Rpt(p0, q1), c, 0, f->bg); 74 | }else{ 75 | if(p0.x >= f->r.max.x) 76 | p0.x = f->r.max.x-1; 77 | bitblt2(f->b, p0, f->b, Rect(p0.x, p0.y, f->r.max.x, q0.y), c, 0, f->bg); 78 | if(n > 1) 79 | bitblt2(f->b, Pt(f->r.min.x, q0.y), 80 | f->b, Rect(f->r.min.x, q0.y, f->r.max.x, p1.y), c, 0, f->bg); 81 | bitblt2(f->b, Pt(f->r.min.x, p1.y), 82 | f->b, Rect(f->r.min.x, p1.y, q1.x, q1.y), c, 0, f->bg); 83 | } 84 | } 85 | 86 | void 87 | frselectp(Frame *f, Fcode c) 88 | { 89 | Point pt0, pt1; 90 | 91 | pt0 = frptofchar(f, f->p0); 92 | pt1 = (f->p0==f->p1)? pt0 : frptofchar(f, f->p1); 93 | frselectf(f, pt0, pt1, c); 94 | } 95 | -------------------------------------------------------------------------------- /include/frame.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | 3 | typedef struct Frbox Frbox; 4 | typedef struct Frame Frame; 5 | 6 | struct Frbox 7 | { 8 | int64_t wid; /* in pixels */ 9 | int64_t nrune; /* <0 ==> negate and treat as break char */ 10 | union{ 11 | uint8_t *ptr; 12 | struct{ 13 | int16_t bc; /* break char */ 14 | int16_t minwid; 15 | } b; 16 | } a; 17 | }; 18 | 19 | /* note that we track background color, but not foreground 20 | * this is because the foreground color is the same for all frames 21 | */ 22 | struct Frame 23 | { 24 | uint64_t bg; /* background color */ 25 | XftFont *font; /* of chars in the frame */ 26 | Bitmap *b; /* on which frame appears */ 27 | Rectangle r; /* in which text appears */ 28 | Rectangle entire; /* of full frame */ 29 | Frbox *box; 30 | uint64_t p0, p1; /* selection */ 31 | int16_t left; /* left edge of text */ 32 | uint16_t nbox, nalloc; 33 | uint16_t maxtab; /* max size of tab, in pixels */ 34 | uint16_t fheight; /* font height, in pixels */ 35 | uint16_t nchars; /* # runes in frame */ 36 | uint16_t nlines; /* # lines with text */ 37 | uint16_t maxlines; /* total # lines in frame */ 38 | bool lastlinefull; /* last line fills frame */ 39 | bool modified; /* changed since frselect() */ 40 | }; 41 | 42 | uint64_t frcharofpt(Frame*, Point); 43 | Point frptofchar(Frame*, uint64_t); 44 | int frdelete(Frame*, uint64_t, uint64_t); 45 | void frinsert(Frame*, wchar_t*, wchar_t*, uint64_t); 46 | void frselect(Frame*, Mouse*); 47 | void frselectp(Frame*, Fcode); 48 | void frselectf(Frame*, Point, Point, Fcode); 49 | void frinit(Frame*, Rectangle, XftFont*, Bitmap*, uint64_t); 50 | void frsetrects(Frame*, Rectangle, Bitmap*); 51 | void frclear(Frame*); 52 | void frgetmouse(void); 53 | 54 | uint8_t *_frallocstr(unsigned); 55 | void _frinsure(Frame*, int, unsigned); 56 | Point _frdraw(Frame*, Point); 57 | void _frgrowbox(Frame*, int); 58 | void _frfreebox(Frame*, int, int); 59 | void _frmergebox(Frame*, int); 60 | void _frdelbox(Frame*, int, int); 61 | void _frsplitbox(Frame*, int, int); 62 | int _frfindbox(Frame*, int, uint64_t, uint64_t); 63 | void _frclosebox(Frame*, int, int); 64 | int _frcanfit(Frame*, Point, Frbox*); 65 | void _frcklinewrap(Frame*, Point*, Frbox*); 66 | void _frcklinewrap0(Frame*, Point*, Frbox*); 67 | void _fradvance(Frame*, Point*, Frbox*); 68 | int _frnewwid(Frame*, Point, Frbox*); 69 | void _frclean(Frame*, Point, int, int); 70 | void _frredraw(Frame*, Point); 71 | void _fraddbox(Frame*, int, int); 72 | Point _frptofcharptb(Frame*, uint64_t, Point, int); 73 | Point _frptofcharnb(Frame*, uint64_t, int); 74 | int _frstrlen(Frame*, int); 75 | 76 | extern int tabwidth; 77 | 78 | #define NRUNE(b) ((b)->nrune<0? 1 : (b)->nrune) 79 | #define NBYTE(b) strlen((char*)(b)->a.ptr) 80 | -------------------------------------------------------------------------------- /sam/error.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include "sam.h" 3 | 4 | static char *emsg[]={ 5 | /* error_s */ 6 | "can't open", 7 | "can't create", 8 | "not in menu:", 9 | "changes to", 10 | "I/O error:", 11 | /* error_c */ 12 | "unknown command", 13 | "no operand for", 14 | "bad delimiter", 15 | /* error */ 16 | "can't fork", 17 | "interrupt", 18 | "address", 19 | "search", 20 | "pattern", 21 | "newline expected", 22 | "blank expected", 23 | "pattern expected", 24 | "can't nest X or Y", 25 | "unmatched `}'", 26 | "command takes no address", 27 | "addresses overlap", 28 | "substitution", 29 | "& match too long", 30 | "bad \\ in rhs", 31 | "address range", 32 | "changes not in sequence", 33 | "addresses out of order", 34 | "no file name", 35 | "unmatched `('", 36 | "unmatched `)'", 37 | "malformed `[]'", 38 | "malformed regexp", 39 | "reg. exp. list overflow", 40 | "plan 9 command", 41 | "can't pipe", 42 | "no current file", 43 | "string too long", 44 | "changed files", 45 | "empty string", 46 | "file search", 47 | "non-unique match for \"\"", 48 | "tag match too long", 49 | "too many subexpressions", 50 | "temporary file too large", 51 | "file is append-only", 52 | }; 53 | static char *wmsg[]={ 54 | /* warn_s */ 55 | "duplicate file name", 56 | "no such file", 57 | "write might change good version of", 58 | /* warn_S */ 59 | "files might be aliased", 60 | /* warn */ 61 | "null characters elided; file will be different upon write", 62 | "can't run pwd", 63 | "last char not newline", 64 | "exit status not 0", 65 | "file is not text" 66 | }; 67 | 68 | void 69 | error(Err s) 70 | { 71 | char buf[512]; 72 | 73 | snprintf(buf, sizeof(buf) - 1, "?%s", emsg[s]); 74 | hiccough(buf); 75 | } 76 | 77 | void 78 | error_s(Err s, char *a) 79 | { 80 | char buf[512]; 81 | 82 | snprintf(buf, sizeof(buf) - 1, "?%s \"%s\"", emsg[s], a); 83 | hiccough(buf); 84 | } 85 | 86 | void 87 | error_c(Err s, int c) 88 | { 89 | char buf[512]; 90 | 91 | snprintf(buf, sizeof(buf) - 1, "?%s `%c'", emsg[s], c); 92 | hiccough(buf); 93 | } 94 | 95 | void 96 | warn(Warn s) 97 | { 98 | dprint(L"?warning: %s\n", wmsg[s]); 99 | } 100 | 101 | void 102 | warn_S(Warn s, String *a) 103 | { 104 | print_s(wmsg[s], a); 105 | } 106 | 107 | void 108 | warn_SS(Warn s, String *a, String *b) 109 | { 110 | print_ss(wmsg[s], a, b); 111 | } 112 | 113 | void 114 | warn_s(Warn s, char *a) 115 | { 116 | dprint(L"?warning: %s `%s'\n", wmsg[s], a); 117 | } 118 | 119 | void 120 | termwrite(wchar_t *p) 121 | { 122 | size_t l = wcslen(p); 123 | 124 | if(downloaded){ 125 | if(cmd) 126 | Finsert(cmd, tmprstr(p, l), cmdpt); 127 | else 128 | Strinsert(&cmdstr, tmprstr(p, l), cmdstr.n); 129 | cmdptadv += wcslen(p); 130 | }else 131 | fprintf(stderr, "%ls", p); 132 | } 133 | 134 | -------------------------------------------------------------------------------- /libframe/frptofchar.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | Point 7 | _frptofcharptb(Frame *f, uint64_t p, Point pt, int bn) 8 | { 9 | uint8_t *s; 10 | Frbox *b; 11 | int w, l; 12 | wchar_t r; 13 | 14 | for(b = &f->box[bn]; bnnbox; bn++,b++){ 15 | _frcklinewrap(f, &pt, b); 16 | if(p < (l=NRUNE(b))){ 17 | if(b->nrune > 0) 18 | for(s=b->a.ptr; p>0; s+=w, p--){ 19 | w = chartorune(&r, (char*)s); 20 | pt.x += charwidth(f->font, r); 21 | if(r==0 || pt.x>f->r.max.x) 22 | berror("frptofchar"); 23 | } 24 | break; 25 | } 26 | p -= l; 27 | _fradvance(f, &pt, b); 28 | } 29 | return pt; 30 | } 31 | 32 | Point 33 | frptofchar(Frame *f, uint64_t p) 34 | { 35 | return _frptofcharptb(f, p, Pt(f->left, f->r.min.y), 0); 36 | } 37 | 38 | Point 39 | _frptofcharnb(Frame *f, uint64_t p, int nb) /* doesn't do final _fradvance to next line */ 40 | { 41 | Point pt; 42 | int nbox; 43 | 44 | nbox = f->nbox; 45 | f->nbox = nb; 46 | pt = _frptofcharptb(f, p, Pt(f->left, f->r.min.y), 0); 47 | f->nbox = nbox; 48 | return pt; 49 | } 50 | 51 | static 52 | Point 53 | _frgrid(Frame *f, Point p) 54 | { 55 | p.y -= f->r.min.y; 56 | p.y -= p.y%f->fheight; 57 | p.y += f->r.min.y; 58 | if(p.x > f->r.max.x) 59 | p.x = f->r.max.x; 60 | return p; 61 | } 62 | 63 | uint64_t 64 | frcharofpt(Frame *f, Point pt) 65 | { 66 | Point qt; 67 | int w, bn, cstart; 68 | uint8_t *s; 69 | Frbox *b; 70 | uint64_t p; 71 | wchar_t r; 72 | 73 | pt = _frgrid(f, pt); 74 | qt.x = f->left; 75 | qt.y = f->r.min.y; 76 | for(b=f->box,bn=0,p=0; bnnbox && qt.y= pt.y) 79 | break; 80 | _fradvance(f, &qt, b); 81 | p += NRUNE(b); 82 | } 83 | for(; bnnbox && qt.x<=pt.x; bn++,b++){ 84 | _frcklinewrap(f, &qt, b); 85 | if(qt.y > pt.y) 86 | break; 87 | if(qt.x+b->wid > pt.x){ 88 | if(b->nrune < 0) 89 | _fradvance(f, &qt, b); 90 | else{ 91 | s = b->a.ptr; 92 | for(;;){ 93 | w = chartorune(&r, (char*)s); 94 | if(r == 0) 95 | berror("end of string in frcharofpt"); 96 | s += w; 97 | cstart = qt.x; 98 | qt.x += charwidth(f->font, r); 99 | if(qt.x > pt.x){ 100 | if(qt.x - pt.x < pt.x - cstart) 101 | p++; 102 | break; 103 | } 104 | p++; 105 | } 106 | } 107 | }else{ 108 | p += NRUNE(b); 109 | _fradvance(f, &qt, b); 110 | } 111 | } 112 | return p; 113 | } 114 | -------------------------------------------------------------------------------- /sam/string.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include "sam.h" 3 | 4 | #define MINSIZE 16 /* minimum number of chars allocated */ 5 | #define MAXSIZE 256 /* maximum number of chars for an empty string */ 6 | 7 | 8 | void 9 | Strinit(String *p) 10 | { 11 | p->s = emalloc(MINSIZE*RUNESIZE); 12 | p->n = 0; 13 | p->size = MINSIZE; 14 | } 15 | 16 | void 17 | Strinit0(String *p) 18 | { 19 | p->s = emalloc(MINSIZE*RUNESIZE); 20 | p->s[0] = 0; 21 | p->n = 1; 22 | p->size = MINSIZE; 23 | } 24 | 25 | void 26 | Strclose(String *p) 27 | { 28 | free(p->s); 29 | } 30 | 31 | void 32 | Strzero(String *p) 33 | { 34 | if(p->size > MAXSIZE){ 35 | p->s = erealloc(p->s, RUNESIZE*MAXSIZE); /* throw away the garbage */ 36 | p->size = MAXSIZE; 37 | } 38 | p->n = 0; 39 | } 40 | 41 | void 42 | Strdupl(String *p, wchar_t *s) /* copies the null */ 43 | { 44 | p->n = wcslen(s); 45 | Strinsure(p, p->n + 1); 46 | wmemmove(p->s, s, p->n); 47 | } 48 | 49 | void 50 | Strduplstr(String *p, String *q) /* will copy the null if there's one there */ 51 | { 52 | Strinsure(p, q->n); 53 | p->n = q->n; 54 | wmemmove(p->s, q->s, q->n); 55 | } 56 | 57 | void 58 | Straddc(String *p, wchar_t c) 59 | { 60 | Strinsure(p, p->n + 1); 61 | p->s[p->n++] = c; 62 | } 63 | 64 | void 65 | Strinsure(String *p, uint64_t n) 66 | { 67 | if(n > STRSIZE) 68 | error(Etoolong); 69 | 70 | if(p->size < n){ /* p needs to grow */ 71 | n += 100; 72 | p->s = erealloc(p->s, n * RUNESIZE); 73 | p->size = n; 74 | } 75 | } 76 | 77 | void 78 | Strinsert(String *p, String *q, Posn p0) 79 | { 80 | Strinsure(p, p->n+q->n); 81 | wmemmove(p->s + p0 + q->n, p->s + p0, p->n - p0); 82 | wmemmove(p->s + p0, q->s, q->n); 83 | p->n += q->n; 84 | } 85 | 86 | void 87 | Strdelete(String *p, Posn p1, Posn p2) 88 | { 89 | wmemmove(p->s + p1, p->s + p2, p->n - p2); 90 | p->n -= p2-p1; 91 | } 92 | 93 | int 94 | Strcmp(String *a, String *b) 95 | { 96 | return wcscmp(a->s, b->s); 97 | } 98 | 99 | char* 100 | Strtoc(String *s) 101 | { 102 | size_t l = s->n * MB_LEN_MAX; 103 | char *c = emalloc(l + 1); 104 | wchar_t ws[s->n + 1]; 105 | 106 | memset(ws, 0, sizeof(ws)); 107 | memset(c, 0, l + 1); 108 | wmemcpy(ws, s->s, s->n); 109 | ws[s->n] = 0; 110 | 111 | if (wcstombs(c, ws, l) == (size_t)-1) 112 | panic("encoding 1"); 113 | 114 | return c; 115 | } 116 | 117 | /* 118 | * Build very temporary String from wchar_t* 119 | */ 120 | String* 121 | tmprstr(wchar_t *r, int n) 122 | { 123 | static String p = {0}; 124 | 125 | p.s = r; 126 | p.n = n; 127 | p.size = n; 128 | return &p; 129 | } 130 | 131 | /* 132 | * Convert null-terminated char* into String 133 | */ 134 | String* 135 | tmpcstr(char *s) 136 | { 137 | String *p = emalloc(sizeof(String)); 138 | p->n = utflen(s); 139 | p->size = p->n + 1; 140 | p->s = calloc(p->size, sizeof(wchar_t)); 141 | if (mbstowcs(p->s, s, p->n) == (size_t)-1) 142 | panic("encoding 2"); 143 | 144 | return p; 145 | } 146 | 147 | void 148 | freetmpstr(String *s) 149 | { 150 | free(s->s); 151 | free(s); 152 | } 153 | -------------------------------------------------------------------------------- /libXg/libgint.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | /* internal libg implementation file - include after libg */ 3 | 4 | /* 5 | * include defs of standard library routines, if possible, 6 | * and string routines 7 | */ 8 | #ifdef _POSIX_SOURCE 9 | #include 10 | #include 11 | #endif /* _POSIX_SOURCE */ 12 | 13 | /* 14 | * use defines to rename X11 types Cursor, Font, Event 15 | */ 16 | 17 | #define Font xFont 18 | #define Event xEvent 19 | 20 | #if defined(v10) || defined(HPUX) 21 | typedef char* caddr_t; 22 | #endif 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #undef Font 31 | #undef Event 32 | 33 | /* keyboard info */ 34 | extern XkbDescPtr xkb; 35 | 36 | /* binding and chord management */ 37 | void freechords(void); 38 | void freebindings(void); 39 | 40 | /* Cursor initialization */ 41 | void initcursors(void); 42 | 43 | /* Return a GCs for solid filling/strings/etc., segments/points, and tiling */ 44 | extern GC _getfillgc(Fcode, Bitmap*, uint64_t); 45 | extern GC _getcopygc(Fcode, Bitmap*, Bitmap*, int*); 46 | extern GC _getfillgc2(Fcode, Bitmap*, uint64_t, uint64_t, uint64_t); 47 | extern GC _getcopygc2(Fcode, Bitmap*, Bitmap*, int*, uint64_t, uint64_t); 48 | extern GC _getgc(Bitmap*, uint64_t, XGCValues *); 49 | 50 | /* convert between different bitmap depths */ 51 | extern void _ldconvert(char *, int, char *, int, int, int); 52 | 53 | /* balloc without zero init (which uses a gc!) */ 54 | extern Bitmap *_balloc(Rectangle, int); 55 | 56 | /* X Display for this application's connection */ 57 | extern Display *_dpy; 58 | 59 | /* screen depth foreground and background for this application */ 60 | extern uint64_t _fgpixel, _bgpixel; 61 | extern XColor _fgcolor, _bgcolor; 62 | 63 | /* indexed by log depth (0 <= ld <= 5), to give depth and planemask */ 64 | extern int _ld2d[]; 65 | extern uint64_t _ld2dmask[]; 66 | 67 | /* libg.h defines: 68 | * extern Bitmap screen; -- Bitmap for application Window after xbinit() 69 | * extern Font *font; -- Font for application default font after xbinit() 70 | */ 71 | 72 | /* 73 | * Conventions: 74 | * The .id field of a Bitmap is an X Pixmap unless the Bitmap is screen, 75 | * in which case it is a Window. 76 | * The .id field of a Font is set to the X xFont. 77 | * 78 | * Coordinate conventions: libg bitmaps can have non (0,0) origins, 79 | * but not X Pixmaps, so we have to subtract the min point of a Bitmap 80 | * from coords in the Bitmap before using the point in the corresponding Pixmap. 81 | * The screen Bitmap, however, contains the rectangle in X coords of the 82 | * widget in which the application is started, relative to the window. 83 | * The origin may or may not be (0,0), but in any case, coordinates should 84 | * NOT be translated before using in X calls on the Window. 85 | */ 86 | 87 | /* values for bitmap flag field (see _getcopygc if change first two vals) */ 88 | enum { 89 | DP1= 0x1, /* depth == 1 (ldepth == 0) */ 90 | BL1= 0x2, /* black == 1 model */ 91 | SCR= 0x4, /* on screen */ 92 | ZORG= 0x8, /* r.min == Pt(0,0) */ 93 | SHIFT= 0x20, /* !SCR & !ZORG */ 94 | CLIP= 0x40 /* r != clipr */ 95 | }; 96 | 97 | /* values for return bltfunc arg of _getcopygc */ 98 | enum { 99 | UseCopyArea, 100 | UseCopyPlane, 101 | UseFillRectangle 102 | }; 103 | -------------------------------------------------------------------------------- /sam/buffer.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Rob King -- See LICENSE for details */ 2 | 3 | #include "sam.h" 4 | 5 | #define BUFFER_MIN 65535 6 | #define GAPSIZE(b) ((b)->ge - (b)->gs) 7 | 8 | typedef size_t pos_t; 9 | typedef struct Gapbuffer Gapbuffer; 10 | struct Gapbuffer{ 11 | size_t size; 12 | pos_t gs; 13 | pos_t ge; 14 | wchar_t *buf; 15 | }; 16 | 17 | static void 18 | movegap(Gapbuffer *b, pos_t p) 19 | { 20 | if (p == b->gs) 21 | return; 22 | else if (p < b->gs){ 23 | size_t d = b->gs - p; 24 | b->gs -= d; 25 | b->ge -= d; 26 | wmemmove(b->buf + b->ge, b->buf + b->gs, d); 27 | } else{ 28 | size_t d = p - b->gs; 29 | b->gs += d; 30 | b->ge += d; 31 | wmemmove(b->buf + b->gs - d, b->buf + b->ge - d, d); 32 | } 33 | } 34 | 35 | static void 36 | ensuregap(Gapbuffer *b, size_t l) 37 | { 38 | size_t ns = b->size + l + BUFFER_MIN; 39 | size_t es = b->size - b->ge; 40 | 41 | if (GAPSIZE(b) >= l) 42 | return; 43 | 44 | b->buf = realloc(b->buf, ns * RUNESIZE); 45 | if (!b->buf) 46 | panic("out of memory"); 47 | 48 | wmemmove(b->buf + (ns - es), b->buf + b->ge, es); 49 | b->ge = ns - es; 50 | b->size = ns; 51 | } 52 | 53 | static void 54 | deletebuffer(Gapbuffer *b, pos_t p, size_t l) 55 | { 56 | movegap(b, p); 57 | b->ge += l; 58 | } 59 | 60 | static size_t 61 | readbuffer(Gapbuffer *b, pos_t p, size_t l, wchar_t *c) 62 | { 63 | size_t r = 0; 64 | 65 | if (p < b->gs){ 66 | size_t d = b->gs - p; 67 | size_t t = l > d ? d : l; 68 | 69 | wmemcpy(c, b->buf + p, t); 70 | c += t; 71 | l -= t; 72 | r += t; 73 | 74 | wmemcpy(c, b->buf + b->ge, l); 75 | r += l; 76 | } else{ 77 | p += GAPSIZE(b); 78 | 79 | wmemcpy(c, b->buf + p, l); 80 | r = l; 81 | } 82 | 83 | return r; 84 | } 85 | 86 | static void 87 | insertbuffer(Gapbuffer *b, pos_t p, const wchar_t *s, size_t l) 88 | { 89 | ensuregap(b, l); 90 | movegap(b, p); 91 | wmemcpy(b->buf + b->gs, s, l); 92 | b->gs += l; 93 | } 94 | 95 | Buffer * 96 | Bopen(void) 97 | { 98 | Buffer *b = calloc(1, sizeof(Buffer)); 99 | if (!b) 100 | panic("out of memory"); 101 | 102 | b->gb = calloc(1, sizeof(Gapbuffer)); 103 | if (!b->gb) 104 | panic("out of memory"); 105 | 106 | b->gb->buf = calloc(1, BUFFER_MIN * RUNESIZE); 107 | if (!b->gb->buf) 108 | panic("out of memory"); 109 | 110 | b->gb->size = BUFFER_MIN; 111 | b->gb->gs = 0; 112 | b->gb->ge = BUFFER_MIN; 113 | 114 | return b; 115 | } 116 | 117 | void 118 | Bterm(Buffer *b) 119 | { 120 | if (b){ 121 | free(b->gb->buf); 122 | free(b->gb); 123 | free(b); 124 | } 125 | } 126 | 127 | /* XXX - modify at call sites to use the internal functions */ 128 | int 129 | Bread(Buffer *b, wchar_t *c, int l, Posn p) 130 | { 131 | if (p + l > b->nrunes) 132 | l = b->nrunes - p; 133 | 134 | if (l <= 0) 135 | return 0; 136 | 137 | size_t r = readbuffer(b->gb, p, l, c); 138 | return (int)r; 139 | } 140 | 141 | void 142 | Binsert(Buffer *b, String *s, Posn p) 143 | { 144 | if (s->n > 0){ 145 | insertbuffer(b->gb, (size_t)p, s->s, s->n); 146 | b->nrunes += s->n; 147 | } 148 | } 149 | 150 | void 151 | Bdelete(Buffer *b, Posn p1, Posn p2) 152 | { 153 | size_t l = p2 - p1; 154 | deletebuffer(b->gb, p1, l); 155 | b->nrunes -= l; 156 | } 157 | -------------------------------------------------------------------------------- /libframe/frdelete.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | frdelete(Frame *f, uint64_t p0, uint64_t p1) 8 | { 9 | Point pt0, pt1, ppt0; 10 | Frbox *b; 11 | int n0, n1, n; 12 | Rectangle r; 13 | int nn0; 14 | 15 | if(p0>=f->nchars || p0==p1 || f->b==0) 16 | return 0; 17 | if(p1 > f->nchars) 18 | p1 = f->nchars; 19 | n0 = _frfindbox(f, 0, (uint64_t)0, p0); 20 | n1 = _frfindbox(f, n0, p0, p1); 21 | pt0 = _frptofcharnb(f, p0, n0); 22 | pt1 = frptofchar(f, p1); 23 | if(f->p0!=p0 || f->p1!=p1) /* likely they ARE equal */ 24 | frselectp(f, F&~D); /* can do better some day */ 25 | frselectf(f, pt0, pt1, 0); 26 | if(n0 == f->nbox) 27 | berror("off end in frdelete"); 28 | nn0 = n0; 29 | ppt0 = pt0; 30 | _frfreebox(f, n0, n1-1); 31 | f->modified = true; 32 | 33 | /* 34 | * Invariants: 35 | * pt0 points to beginning, pt1 points to end 36 | * n0 is box containing beginning of stuff being deleted 37 | * n1, b are box containing beginning of stuff to be kept after deletion 38 | * region between pt0 and pt1 is clear 39 | */ 40 | b = &f->box[n1]; 41 | while(pt1.x!=pt0.x && n1nbox){ 42 | _frcklinewrap0(f, &pt0, b); 43 | _frcklinewrap(f, &pt1, b); 44 | if(b->nrune > 0){ 45 | n = _frcanfit(f, pt0, b); 46 | if(n==0) 47 | berror("_frcanfit==0"); 48 | if(n != b->nrune){ 49 | _frsplitbox(f, n1, n); 50 | b = &f->box[n1]; 51 | } 52 | r.min = pt1; 53 | r.max = pt1; 54 | r.max.x += b->wid; 55 | r.max.y += f->fheight; 56 | bitblt2(f->b, pt0, f->b, r, S, 0, f->bg); 57 | if(pt0.y == pt1.y) 58 | r.min.x = r.max.x-(pt1.x-pt0.x); 59 | bitblt2(f->b, r.min, f->b, r, 0, 0, f->bg); 60 | } 61 | _fradvance(f, &pt1, b); 62 | pt0.x += _frnewwid(f, pt0, b); 63 | f->box[n0++] = f->box[n1++]; 64 | b++; 65 | } 66 | if(pt1.y != pt0.y){ 67 | Point pt2; 68 | 69 | pt2 = _frptofcharptb(f, 32767, pt1, n1); 70 | if(pt2.y > f->r.max.y) 71 | berror("frptofchar in frdelete"); 72 | if(n1 < f->nbox){ 73 | int q0, q1, q2; 74 | 75 | q0 = pt0.y+f->fheight; 76 | q1 = pt1.y+f->fheight; 77 | q2 = pt2.y+f->fheight; 78 | bitblt2(f->b, pt0, f->b, Rect(pt1.x, pt1.y, f->r.max.x, q1), S, 0, f->bg); 79 | bitblt2(f->b, Pt(f->r.min.x, q0), f->b, Rect(f->r.min.x, q1, f->r.max.x, q2), S, 0, f->bg); 80 | frselectf(f, Pt(pt2.x, pt2.y-(pt1.y-pt0.y)), pt2, 0); 81 | }else 82 | frselectf(f, pt0, pt2, 0); 83 | } 84 | _frclosebox(f, n0, n1-1); 85 | if(nn0>0 && f->box[nn0-1].nrune>=0 && ppt0.x-f->box[nn0-1].wid>=(int)f->left){ 86 | --nn0; 87 | ppt0.x -= f->box[nn0].wid; 88 | } 89 | _frclean(f, ppt0, nn0, n0nbox-1? n0+1 : n0); 90 | if(f->p1 > p1) 91 | f->p1 -= p1-p0; 92 | else if(f->p1 > p0) 93 | f->p1 = p0; 94 | if(f->p0 > p1) 95 | f->p0 -= p1-p0; 96 | else if(f->p0 > p0) 97 | f->p0 = p0; 98 | frselectp(f, F&~D); 99 | f->nchars -= p1-p0; 100 | pt0 = frptofchar(f, f->nchars); 101 | n = f->nlines; 102 | f->nlines = (pt0.y-f->r.min.y)/f->fheight+(pt0.x>f->left); 103 | return n - f->nlines; 104 | } 105 | -------------------------------------------------------------------------------- /sam/unix.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include "sam.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NEEDVARARG 9 | #include 10 | #else 11 | #include 12 | #endif 13 | 14 | wchar_t samname[] = { '~', '~', 's', 'a', 'm', '~', '~', 0 }; 15 | 16 | static wchar_t l1[] = { '{', '[', '(', '<', 0253, 0}; 17 | static wchar_t l2[] = { '\n', 0}; 18 | static wchar_t l3[] = { '\'', '"', '`', 0}; 19 | wchar_t *left[]= { l1, l2, l3, 0}; 20 | 21 | static wchar_t r1[] = {'}', ']', ')', '>', 0273, 0}; 22 | static wchar_t r2[] = {'\n', 0}; 23 | static wchar_t r3[] = {'\'', '"', '`', 0}; 24 | wchar_t *right[]= { r1, r2, r3, 0}; 25 | 26 | void 27 | print_ss(char *s, String *a, String *b) 28 | { 29 | char *ap, *bp, *cp; 30 | wchar_t *rp; 31 | 32 | ap = emalloc(a->n+1); 33 | for (cp = ap, rp = a->s; *rp; rp++) 34 | cp += runetochar(cp, *rp); 35 | *cp = 0; 36 | bp = emalloc(b->n+1); 37 | for (cp = bp, rp = b->s; *rp; rp++) 38 | cp += runetochar(cp, *rp); 39 | *cp = 0; 40 | dprint(L"?warning: %s `%.*s' and `%.*s'\n", s, a->n, ap, b->n, bp); 41 | free(ap); 42 | free(bp); 43 | } 44 | 45 | void 46 | print_s(char *s, String *a) 47 | { 48 | char *ap, *cp; 49 | wchar_t *rp; 50 | 51 | ap = emalloc(a->n+1); 52 | for (cp = ap, rp = a->s; *rp; rp++) 53 | cp += runetochar(cp, *rp); 54 | *cp = 0; 55 | dprint(L"?warning: %s `%.*s'\n", s, a->n, ap); 56 | free(ap); 57 | } 58 | 59 | int 60 | statfile(char *name, uint64_t *dev, uint64_t *id, int64_t *time, int64_t *length, int64_t *appendonly) 61 | { 62 | struct stat dirb; 63 | 64 | if (stat(name, &dirb) == -1) 65 | return -1; 66 | if (dev) 67 | *dev = dirb.st_dev; 68 | if (id) 69 | *id = dirb.st_ino; 70 | if (time) 71 | *time = dirb.st_mtime; 72 | if (length) 73 | *length = dirb.st_size; 74 | if(appendonly) 75 | *appendonly = 0; 76 | return 1; 77 | } 78 | 79 | int 80 | statfd(int fd, uint64_t *dev, uint64_t *id, int64_t *time, int64_t *length, int64_t *appendonly) 81 | { 82 | struct stat dirb; 83 | 84 | if (fstat(fd, &dirb) == -1) 85 | return -1; 86 | if (dev) 87 | *dev = dirb.st_dev; 88 | if (id) 89 | *id = dirb.st_ino; 90 | if (time) 91 | *time = dirb.st_mtime; 92 | if (length) 93 | *length = dirb.st_size; 94 | if(appendonly) 95 | *appendonly = 0; 96 | return 1; 97 | } 98 | 99 | int 100 | newtmp(void) 101 | { 102 | FILE *f = tmpfile(); 103 | if (f) 104 | return fileno(f); 105 | panic("could not create tempfile!"); 106 | return -1; 107 | } 108 | 109 | void 110 | samerr(char *buf) 111 | { 112 | snprintf(buf, PATH_MAX, "%s/sam.err", getenv("HOME") ? getenv("HOME") : "/tmp"); 113 | } 114 | 115 | int 116 | waitfor(int pid) 117 | { 118 | int wm; 119 | int rpid; 120 | 121 | do; while((rpid = wait(&wm)) != pid && rpid != -1); 122 | return (WEXITSTATUS(wm)); 123 | } 124 | 125 | void* 126 | emalloc(uint64_t n) 127 | { 128 | void *p = calloc(1, n < sizeof(int)? sizeof(int) : n); 129 | if (!p) 130 | panic("malloc failed"); 131 | return p; 132 | } 133 | 134 | void* 135 | erealloc(void *p, uint64_t n) 136 | { 137 | p = realloc(p, n); 138 | if(!p) 139 | panic("realloc fails"); 140 | return p; 141 | } 142 | 143 | void 144 | dprint(wchar_t *z, ...) 145 | { 146 | va_list args; 147 | wchar_t buf[BLOCKSIZE + 1] = {0}; 148 | 149 | va_start(args, z); 150 | vswprintf(buf, BLOCKSIZE, z, args); 151 | termwrite(buf); 152 | va_end(args); 153 | } 154 | 155 | -------------------------------------------------------------------------------- /libXg/arith.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | 5 | Point 6 | add(Point a, Point b) 7 | { 8 | a.x += b.x; 9 | a.y += b.y; 10 | return a; 11 | } 12 | 13 | Point 14 | sub(Point a, Point b) 15 | { 16 | a.x -= b.x; 17 | a.y -= b.y; 18 | return a; 19 | } 20 | 21 | Rectangle 22 | inset(Rectangle r, int n) 23 | { 24 | r.min.x += n; 25 | r.min.y += n; 26 | r.max.x -= n; 27 | r.max.y -= n; 28 | return r; 29 | } 30 | 31 | Point 32 | divpt(Point a, int b) 33 | { 34 | a.x /= b; 35 | a.y /= b; 36 | return a; 37 | } 38 | 39 | Point 40 | mul(Point a, int b) 41 | { 42 | a.x *= b; 43 | a.y *= b; 44 | return a; 45 | } 46 | 47 | Rectangle 48 | rsubp(Rectangle r, Point p) 49 | { 50 | r.min.x -= p.x; 51 | r.min.y -= p.y; 52 | r.max.x -= p.x; 53 | r.max.y -= p.y; 54 | return r; 55 | } 56 | 57 | Rectangle 58 | raddp(Rectangle r, Point p) 59 | { 60 | r.min.x += p.x; 61 | r.min.y += p.y; 62 | r.max.x += p.x; 63 | r.max.y += p.y; 64 | return r; 65 | } 66 | 67 | Rectangle 68 | rmul(Rectangle r, int a) 69 | { 70 | if (a != 1) { 71 | r.min.x *= a; 72 | r.min.y *= a; 73 | r.max.x *= a; 74 | r.max.y *= a; 75 | } 76 | return r; 77 | } 78 | 79 | Rectangle 80 | rdiv(Rectangle r, int a) 81 | { 82 | if (a != 1) { 83 | r.min.x /= a; 84 | r.min.y /= a; 85 | r.max.x /= a; 86 | r.max.y /= a; 87 | } 88 | return r; 89 | } 90 | 91 | Rectangle 92 | rshift(Rectangle r, int a) 93 | { 94 | if (a > 0) { 95 | r.min.x <<= a; 96 | r.min.y <<= a; 97 | r.max.x <<= a; 98 | r.max.y <<= a; 99 | } 100 | else if (a < 0) { 101 | a = -a; 102 | r.min.x >>= a; 103 | r.min.y >>= a; 104 | r.max.x >>= a; 105 | r.max.y >>= a; 106 | } 107 | return r; 108 | } 109 | 110 | int 111 | eqpt(Point p, Point q) 112 | { 113 | return p.x==q.x && p.y==q.y; 114 | } 115 | 116 | int 117 | eqrect(Rectangle r, Rectangle s) 118 | { 119 | return r.min.x==s.min.x && r.max.x==s.max.x && 120 | r.min.y==s.min.y && r.max.y==s.max.y; 121 | } 122 | 123 | int 124 | rectXrect(Rectangle r, Rectangle s) 125 | { 126 | return r.min.x=s.min.x && r.min.x=s.min.y && r.min.y=r.min.x && p.x=r.min.y && p.ydot.r.p1 = p1; 10 | f->dot.r.p2 = p2; 11 | if(f->rasp){ 12 | telldot(f); 13 | outTsl(Hmoveto, f->tag, f->dot.r.p1); 14 | } 15 | } 16 | 17 | void 18 | telldot(File *f) 19 | { 20 | if(f->rasp == 0) 21 | panic("telldot"); 22 | if(f->dot.r.p1==f->tdot.p1 && f->dot.r.p2==f->tdot.p2) 23 | return; 24 | outTsll(Hsetdot, f->tag, f->dot.r.p1, f->dot.r.p2); 25 | f->tdot = f->dot.r; 26 | } 27 | 28 | void 29 | tellpat(void) 30 | { 31 | outTS(Hsetpat, &lastpat); 32 | patset = false; 33 | } 34 | 35 | #define CHARSHIFT 128 36 | 37 | void 38 | lookorigin(File *f, Posn p0, Posn ls, int64_t rl) 39 | { 40 | int nl, nc, c; 41 | Posn oldp0; 42 | 43 | if(p0 > f->nrunes) 44 | p0 = f->nrunes; 45 | oldp0 = p0; 46 | Fgetcset(f, p0); 47 | for(nl=nc=c=0; c!=-1 && nl=CHARSHIFT/2) 56 | p0-=CHARSHIFT/2; 57 | else 58 | p0 = 0; 59 | }else 60 | p0 = oldp0; 61 | 62 | outTsll(Horigin, f->tag, p0, rl); 63 | } 64 | 65 | int 66 | clickmatch(File *f, int cl, int cr, int dir) 67 | { 68 | int c; 69 | int nest = 1; 70 | 71 | while((c=(dir>0? Fgetc(f) : Fbgetc(f))) > 0) 72 | if(c == cr){ 73 | if(--nest==0) 74 | return 1; 75 | }else if(c == cl) 76 | nest++; 77 | return cl=='\n' && nest==1; 78 | } 79 | 80 | wchar_t* 81 | strrune(wchar_t *s, wchar_t c) 82 | { 83 | wchar_t c1; 84 | 85 | if(c == 0) { 86 | while(*s++) 87 | ; 88 | return s-1; 89 | } 90 | 91 | while((c1 = *s++)) 92 | if(c1 == c) 93 | return s-1; 94 | return 0; 95 | } 96 | 97 | void 98 | doubleclick(File *f, Posn p1) 99 | { 100 | int c, i; 101 | wchar_t *r, *l; 102 | 103 | if(p1 > f->nrunes) 104 | return; 105 | f->dot.r.p1 = f->dot.r.p2 = p1; 106 | for(i=0; left[i]; i++){ 107 | l = left[i]; 108 | r = right[i]; 109 | /* try left match */ 110 | if(p1 == 0){ 111 | Fgetcset(f, p1); 112 | c = '\n'; 113 | }else{ 114 | Fgetcset(f, p1-1); 115 | c = Fgetc(f); 116 | } 117 | if(c!=-1 && strrune(l, c)){ 118 | if(clickmatch(f, c, r[strrune(l, c)-l], 1)){ 119 | f->dot.r.p1 = p1; 120 | f->dot.r.p2 = f->getcp-(c!='\n'); 121 | } 122 | return; 123 | } 124 | /* try right match */ 125 | if(p1 == f->nrunes){ 126 | Fbgetcset(f, p1); 127 | c = '\n'; 128 | }else{ 129 | Fbgetcset(f, p1+1); 130 | c = Fbgetc(f); 131 | } 132 | if(c!=-1 && strrune(r, c)){ 133 | if(clickmatch(f, c, l[strrune(r, c)-r], -1)){ 134 | f->dot.r.p1 = f->getcp; 135 | if(c!='\n' || f->getcp!=0 || 136 | (Fgetcset(f, (Posn)0),Fgetc(f))=='\n') 137 | f->dot.r.p1++; 138 | f->dot.r.p2 = p1+(p1nrunes && c=='\n'); 139 | } 140 | return; 141 | } 142 | } 143 | /* try filling out word to right */ 144 | Fgetcset(f, p1); 145 | while((c=Fgetc(f))!=-1 && iswalnum(c)) 146 | f->dot.r.p2++; 147 | /* try filling out word to left */ 148 | Fbgetcset(f, p1); 149 | while((c=Fbgetc(f))!=-1 && iswalnum(c)) 150 | f->dot.r.p1--; 151 | } 152 | 153 | -------------------------------------------------------------------------------- /libframe/frbox.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #define SLOP 25 7 | 8 | void 9 | _fraddbox(Frame *f, int bn, int n) /* add n boxes after bn, shift the rest up, 10 | * box[bn+n]==box[bn] */ 11 | { 12 | int i; 13 | 14 | if(bn > f->nbox) 15 | berror("_fraddbox"); 16 | if(f->nbox+n > f->nalloc) 17 | _frgrowbox(f, n+SLOP); 18 | for(i=f->nbox; --i>=bn; ) 19 | f->box[i+n] = f->box[i]; 20 | f->nbox+=n; 21 | } 22 | 23 | void 24 | _frclosebox(Frame *f, int n0, int n1) /* inclusive */ 25 | { 26 | int i; 27 | 28 | if(n0>=f->nbox || n1>=f->nbox || n1nbox; i++) 32 | f->box[i-(n1-n0)] = f->box[i]; 33 | f->nbox -= n1-n0; 34 | } 35 | 36 | void 37 | _frdelbox(Frame *f, int n0, int n1) /* inclusive */ 38 | { 39 | if(n0>=f->nbox || n1>=f->nbox || n1=f->nbox || n1>=f->nbox) 53 | berror("_frfreebox"); 54 | n1++; 55 | for(i=n0; ibox[i].nrune >= 0) 57 | free(f->box[i].a.ptr); 58 | } 59 | 60 | void 61 | _frgrowbox(Frame *f, int delta) 62 | { 63 | f->nalloc += delta; 64 | f->box = realloc(f->box, f->nalloc*sizeof(Frbox)); 65 | if(f->box == 0) 66 | berror("_frgrowbox"); 67 | } 68 | 69 | static 70 | void 71 | dupbox(Frame *f, int bn) 72 | { 73 | uint8_t *p; 74 | 75 | if(f->box[bn].nrune < 0) 76 | berror("dupbox"); 77 | _fraddbox(f, bn, 1); 78 | if(f->box[bn].nrune >= 0){ 79 | p = _frallocstr(NBYTE(&f->box[bn])+1); 80 | strcpy((char*)p, (char*)f->box[bn].a.ptr); 81 | f->box[bn+1].a.ptr = p; 82 | } 83 | } 84 | 85 | static 86 | uint8_t* 87 | runeindex(uint8_t *p, int n) 88 | { 89 | int i, w; 90 | wchar_t rune; 91 | 92 | for(i=0; inrune<0 || b->nrunenrune -= n; 104 | runeindex(b->a.ptr, b->nrune)[0] = 0; 105 | b->wid = strwidth(f->font, (char *)b->a.ptr); 106 | } 107 | 108 | static 109 | void 110 | chopbox(Frame *f, Frbox *b, int n) /* drop first n chars; no allocation done */ 111 | { 112 | if(b->nrune<0 || b->nrunea.ptr, n); 116 | memmove(b->a.ptr, ri, strlen((char *)ri) + 1); 117 | b->nrune -= n; 118 | b->wid = strwidth(f->font, (char *)b->a.ptr); 119 | } 120 | 121 | void 122 | _frsplitbox(Frame *f, int bn, int n) 123 | { 124 | dupbox(f, bn); 125 | truncatebox(f, &f->box[bn], f->box[bn].nrune-n); 126 | chopbox(f, &f->box[bn+1], n); 127 | } 128 | 129 | void 130 | _frmergebox(Frame *f, int bn) /* merge bn and bn+1 */ 131 | { 132 | Frbox *b; 133 | 134 | b = &f->box[bn]; 135 | _frinsure(f, bn, NBYTE(&b[0])+NBYTE(&b[1])+1); 136 | strcpy((char*)runeindex(b[0].a.ptr, b[0].nrune), (char*)b[1].a.ptr); 137 | b[0].wid += b[1].wid; 138 | b[0].nrune += b[1].nrune; 139 | _frdelbox(f, bn+1, bn+1); 140 | } 141 | 142 | int 143 | _frfindbox(Frame *f, int bn, uint64_t p, uint64_t q) /* find box containing q and put q on a box boundary */ 144 | { 145 | Frbox *b; 146 | 147 | for(b = &f->box[bn]; bnnbox && p+NRUNE(b)<=q; bn++, b++) 148 | p += NRUNE(b); 149 | if(p != q) 150 | _frsplitbox(f, bn++, (int)(q-p)); 151 | return bn; 152 | } 153 | -------------------------------------------------------------------------------- /sam/mesg.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #define VERSION 16091 3 | 4 | #define TBLOCKSIZE 512 /* largest piece of text sent to terminal */ 5 | #define DATASIZE (MB_LEN_MAX * TBLOCKSIZE + 30) /* ... including protocol header stuff */ 6 | #define SNARFSIZE 16384 /* maximum length of exchanged snarf buffer */ 7 | /* 8 | * Messages originating at the terminal 9 | */ 10 | typedef enum Tmesg 11 | { 12 | Terror = -1, /* error */ 13 | Tversion, /* version */ 14 | Tstartcmdfile, /* terminal just opened command frame */ 15 | Tcheck, /* ask host to poke with Hcheck */ 16 | Trequest, /* request data to fill a hole */ 17 | Torigin, /* gimme an Horigin near here */ 18 | Tstartfile, /* terminal just opened a file's frame */ 19 | Tworkfile, /* set file to which commands apply */ 20 | Ttype, /* add some characters, but terminal already knows */ 21 | Tcut, 22 | Tpaste, 23 | Tsnarf, 24 | Tstartnewfile, /* terminal just opened a new frame */ 25 | Twrite, /* write file */ 26 | Tclose, /* terminal requests file close; check mod. status */ 27 | Tlook, /* search for literal current text */ 28 | Tsearch, /* search for last regular expression */ 29 | Tsend, /* pretend he typed stuff */ 30 | Tdclick, /* double click */ 31 | Tstartsnarf, /* initiate snarf buffer exchange */ 32 | Tsetsnarf, /* remember string in snarf buffer */ 33 | Tack, /* acknowledge Hack */ 34 | Texit, /* exit */ 35 | TMAX 36 | }Tmesg; 37 | /* 38 | * Messages originating at the host 39 | */ 40 | typedef enum Hmesg 41 | { 42 | Herror = -1, /* error */ 43 | Hversion, /* version */ 44 | Hbindname, /* attach name[0] to text in terminal */ 45 | Hcurrent, /* make named file the typing file */ 46 | Hnewname, /* create "" name in menu */ 47 | Hmovname, /* move file name in menu */ 48 | Hgrow, /* insert space in rasp */ 49 | Hcheck0, /* see below */ 50 | Hcheck, /* ask terminal to check whether it needs more data */ 51 | Hunlock, /* command is finished; user can do things */ 52 | Hdata, /* store this data in previously allocated space */ 53 | Horigin, /* set origin of file/frame in terminal */ 54 | Hunlockfile, /* unlock file in terminal */ 55 | Hsetdot, /* set dot in terminal */ 56 | Hgrowdata, /* Hgrow + Hdata folded together */ 57 | Hmoveto, /* scrolling, context search, etc. */ 58 | Hclean, /* named file is now 'clean' */ 59 | Hdirty, /* named file is now 'dirty' */ 60 | Hcut, /* remove space from rasp */ 61 | Hsetpat, /* set remembered regular expression */ 62 | Hdelname, /* delete file name from menu */ 63 | Hclose, /* close file and remove from menu */ 64 | Hsetsnarf, /* remember string in snarf buffer */ 65 | Hsnarflen, /* report length of implicit snarf */ 66 | Hack, /* request acknowledgement */ 67 | Hexit, 68 | HMAX 69 | }Hmesg; 70 | typedef struct Header{ 71 | uint8_t type; /* one of the above */ 72 | uint8_t count0; /* low bits of data size */ 73 | uint8_t count1; /* high bits of data size */ 74 | uint8_t data[1]; /* variable size */ 75 | }Header; 76 | /* 77 | * File transfer protocol schematic, a la Holzmann 78 | * 79 | * proc h 80 | * { pvar n = 0; 81 | * queue h[4]; 82 | * 83 | * do 84 | * :: (n < N) -> n++; t!Hgrow 85 | * :: (n == N) -> n++; t!Hcheck0 86 | * :: h?Trequest -> t!Hdata 87 | * :: h?Tcheck -> t!Hcheck 88 | * od 89 | * } 90 | * proc t 91 | * { queue t[4]; 92 | * do 93 | * :: t?Hgrow -> h!Trequest 94 | * :: t?Hdata -> skip 95 | * :: t?Hcheck0 -> h!Tcheck 96 | * :: t?Hcheck -> 97 | * if 98 | * :: break 99 | * :: h!Trequest; h!Tcheck 100 | * fi 101 | * od 102 | * } 103 | */ 104 | -------------------------------------------------------------------------------- /samterm/io.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | #include "flayer.h" 6 | #include "samterm.h" 7 | 8 | int cursorfd; 9 | int input; 10 | int got; 11 | int block; 12 | Keystroke keystroke; 13 | int reshaped; 14 | uint8_t *hostp; 15 | uint8_t *hoststop; 16 | uint8_t *externbase; 17 | uint8_t *externp; 18 | uint8_t *externstop; 19 | void panic(char*); 20 | 21 | void 22 | initio(void){ 23 | extern int exfd; 24 | 25 | einit(Emouse|Ekeyboard); 26 | estart(Ehost, 0, 0, false); 27 | if (exfd >= 0) 28 | estart(Eextern, exfd, 8192, true); 29 | } 30 | 31 | void 32 | frgetmouse(void) 33 | { 34 | mouse = emouse(); 35 | } 36 | 37 | void 38 | mouseunblock(void) 39 | { 40 | got &= ~Emouse; 41 | } 42 | 43 | void 44 | kbdblock(void) 45 | { /* ca suffit */ 46 | block = Ekeyboard|Eextern; 47 | } 48 | 49 | int 50 | button(int but) 51 | { 52 | frgetmouse(); 53 | return mouse.buttons&(1<<(but-1)); 54 | } 55 | 56 | void 57 | externload(Event *e) 58 | { 59 | externbase = malloc(e->n); 60 | if(externbase == 0) 61 | return; 62 | memmove(externbase, e->data, e->n); 63 | externp = externbase; 64 | externstop = externbase + e->n; 65 | got |= Eextern; 66 | } 67 | 68 | int 69 | waitforio(void) 70 | { 71 | uint64_t type; 72 | static Event e; 73 | 74 | if(got & ~block) 75 | return got & ~block; 76 | type = eread(~(got|block), &e); 77 | switch(type){ 78 | case Ehost: 79 | hostp = e.data; 80 | hoststop = hostp + e.n; 81 | block = 0; 82 | break; 83 | case Eextern: 84 | externload(&e); 85 | break; 86 | case Ekeyboard: 87 | keystroke = e.keystroke; 88 | break; 89 | case Emouse: 90 | mouse = e.mouse; 91 | break; 92 | } 93 | got |= type; 94 | return got; 95 | } 96 | 97 | int 98 | rcvchar(void) 99 | { 100 | int c; 101 | 102 | if(!(got & Ehost)) 103 | return -1; 104 | c = *hostp++; 105 | if(hostp == hoststop) 106 | got &= ~Ehost; 107 | return c; 108 | } 109 | 110 | char* 111 | rcvstring(void) 112 | { 113 | *hoststop = 0; 114 | got &= ~Ehost; 115 | return (char*)hostp; 116 | } 117 | 118 | int 119 | getch(void) 120 | { 121 | int c; 122 | 123 | while((c = rcvchar()) == -1){ 124 | block = ~Ehost; 125 | waitforio(); 126 | block = 0; 127 | } 128 | return c; 129 | } 130 | 131 | int 132 | externchar(void) 133 | { 134 | wchar_t r; 135 | 136 | loop: 137 | if(got & (Eextern & ~block)){ 138 | externp += chartorune(&r, (char*)externp); 139 | if(externp >= externstop){ 140 | got &= ~Eextern; 141 | free(externbase); 142 | } 143 | if(r == 0) 144 | goto loop; 145 | return r; 146 | } 147 | return -1; 148 | } 149 | 150 | Keystroke 151 | qpeekc(void) 152 | { 153 | return keystroke; 154 | } 155 | 156 | Keystroke 157 | kbdchar(void) 158 | { 159 | Keystroke k = {0}; 160 | static Event e; 161 | 162 | k.c = externchar(); 163 | if(k.c > 0) 164 | return k; 165 | if(got & Ekeyboard){ 166 | k = keystroke; 167 | memset(&keystroke, 0, sizeof(keystroke)); 168 | got &= ~Ekeyboard; 169 | return k; 170 | } 171 | while(ecanread(Eextern)){ 172 | eread(Eextern, &e); 173 | externload(&e); 174 | k.c = externchar(); 175 | if(k.c > 0) 176 | return k; 177 | } 178 | if(!ecankbd()){ 179 | k.c = -1; 180 | return k; 181 | } 182 | return ekbd(); 183 | } 184 | 185 | void 186 | ereshaped(Rectangle r) 187 | { 188 | reshaped = 1; 189 | } 190 | 191 | int 192 | RESHAPED(void) 193 | { 194 | if(reshaped){ 195 | screen.r = bscreenrect(&screen.clipr); 196 | reshaped = 0; 197 | return 1; 198 | } 199 | return 0; 200 | } 201 | 202 | void 203 | mouseexit(void) 204 | { 205 | exit(EXIT_SUCCESS); 206 | } 207 | -------------------------------------------------------------------------------- /samterm/scroll.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | #include "flayer.h" 6 | #include "samterm.h" 7 | 8 | extern Bitmap *darkgrey; 9 | extern Mouse mouse; 10 | 11 | Rectangle 12 | scrpos(Rectangle r, int64_t p0, int64_t p1, int64_t tot) 13 | { 14 | int64_t h; 15 | Rectangle q; 16 | 17 | q = inset(r, 1); 18 | h = q.max.y-q.min.y; 19 | if(tot == 0) 20 | return q; 21 | if(tot > 1024L*1024L) 22 | tot>>=10, p0>>=10, p1>>=10; 23 | if(p0 > 0) 24 | q.min.y += h*p0/tot; 25 | if(p1 < tot) 26 | q.max.y -= h*(tot-p1)/tot; 27 | if(q.max.y < q.min.y+2){ 28 | if(q.min.y+2 <= r.max.y) 29 | q.max.y = q.min.y+2; 30 | else 31 | q.min.y = q.max.y-2; 32 | } 33 | return q; 34 | } 35 | 36 | void 37 | scrflip(Flayer *l, Rectangle r) 38 | { 39 | if(rectclip(&r, l->scroll)) 40 | bitblt2(l->f.b, r.min, l->f.b, r, F&~D, 0, l->bg); 41 | } 42 | 43 | void 44 | scrdraw(Flayer *l, int64_t tot) 45 | { 46 | Rectangle r, r1, r2; 47 | Bitmap *b; 48 | static Bitmap *x; 49 | int h; 50 | 51 | if(l->f.b == 0) 52 | panic("scrdraw"); 53 | r = l->scroll; 54 | r.min.x += 1; /* border between margin and bar */ 55 | r1 = r; 56 | if(l->visible == All){ 57 | if(x == 0){ 58 | if (screensize(0, &h) == 0) 59 | h = 2048; 60 | x = balloc(Rect(0, 0, 32, h), l->f.b->ldepth); 61 | if(x == 0) 62 | panic("scrdraw balloc"); 63 | } 64 | b = x; 65 | r1.min.x = 0; 66 | r1.max.x = Dx(r); 67 | }else 68 | b = l->f.b; 69 | bitblt2(b, r1.min, b, r1, F, 0, l->bg); 70 | texture(b, inset(r1, 1), darkgrey, S); 71 | r2 = scrpos(r1, l->origin, l->origin+l->f.nchars, tot); 72 | bitblt2(b, r2.min, b, r2, 0, 0, l->bg); 73 | if(b!=l->f.b) 74 | bitblt2(l->f.b, r.min, b, r1, S, 0, l->bg); 75 | } 76 | 77 | void 78 | scroll(Flayer *l, int pbut, int but) 79 | { 80 | int in = 0, oin; 81 | int64_t tot = scrtotal(l); 82 | Rectangle scr, r, s, rt; 83 | int x, y, my, oy, h; 84 | int64_t p0; 85 | 86 | s = inset(l->scroll, 1); 87 | x = s.min.x+FLSCROLLWID/2; 88 | scr = scrpos(l->scroll, l->origin, l->origin+l->f.nchars, tot); 89 | r = scr; 90 | y = scr.min.y; 91 | my = mouse.xy.y; 92 | do{ 93 | oin = in; 94 | in = abs(x-mouse.xy.x)<=FLSCROLLWID/2; 95 | if(oin != in) 96 | scrflip(l, r); 97 | if(in){ 98 | oy = y; 99 | my = mouse.xy.y; 100 | if(my < s.min.y) 101 | my = s.min.y; 102 | if(my >= s.max.y) 103 | my = s.max.y; 104 | if(!eqpt(mouse.xy, Pt(x, my))) 105 | cursorset(Pt(x, my)); 106 | if(but == 1){ 107 | p0 = l->origin-frcharofpt(&l->f, Pt(s.max.x, my)); 108 | rt = scrpos(l->scroll, p0, p0+l->f.nchars, tot); 109 | y = rt.min.y; 110 | }else if(but == 2){ 111 | y = my; 112 | if(y > s.max.y-2) 113 | y = s.max.y-2; 114 | }else if(but == 3){ 115 | p0 = l->origin+frcharofpt(&l->f, Pt(s.max.x, my)); 116 | rt = scrpos(l->scroll, p0, p0+l->f.nchars, tot); 117 | y = rt.min.y; 118 | } 119 | if(y != oy){ 120 | scrflip(l, r); 121 | r = raddp(scr, Pt(0, y-scr.min.y)); 122 | scrflip(l, r); 123 | } 124 | } 125 | }while(button(pbut)); 126 | if(in){ 127 | h = s.max.y-s.min.y; 128 | scrflip(l, r); 129 | p0 = 0; 130 | if(but == 1) 131 | p0 = (int64_t)(my-s.min.y)/l->f.fheight+1; 132 | else if(but == 2){ 133 | if(tot > 1024L*1024L) 134 | p0 = ((tot>>10)*(y-s.min.y)/h)<<10; 135 | else 136 | p0 = tot*(y-s.min.y)/h; 137 | }else if(but == 3){ 138 | p0 = l->origin+frcharofpt(&l->f, Pt(s.max.x, my)); 139 | if(p0 > tot) 140 | p0 = tot; 141 | } 142 | scrorigin(l, but, p0); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /sam/shell.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include "sam.h" 3 | #include "parse.h" 4 | 5 | #include 6 | 7 | extern jmp_buf mainloop; 8 | 9 | char errfile[PATH_MAX + 1]; 10 | String plan9cmd; /* null terminated */ 11 | Buffer *plan9buf; 12 | void checkerrs(void); 13 | 14 | int 15 | plan9(File *f, int type, String *s, int nest) 16 | { 17 | int64_t l; 18 | int m; 19 | int pid, fd; 20 | int retcode; 21 | int pipe1[2], pipe2[2]; 22 | 23 | if(s->s[0]==0 && plan9cmd.s[0]==0) 24 | error(Enocmd); 25 | else if(s->s[0]) 26 | Strduplstr(&plan9cmd, s); 27 | if(downloaded) 28 | samerr(errfile); 29 | else 30 | strcpy(errfile, "/dev/tty"); 31 | if(type!='!' && pipe(pipe1)==-1) 32 | error(Epipe); 33 | if(type=='|') 34 | snarf(f, addr.r.p1, addr.r.p2, plan9buf, true); 35 | if(downloaded) 36 | remove(errfile); 37 | if((pid=fork()) == 0){ 38 | if(downloaded){ /* also put nasty fd's into errfile */ 39 | fd = creat(errfile, 0600L); 40 | if(fd < 0) 41 | fd = creat("/dev/null", 0600L); 42 | dup2(fd, 2); 43 | close(fd); 44 | /* 2 now points at err file */ 45 | if(type == '>') 46 | dup2(2, 1); 47 | else if(type=='!'){ 48 | dup2(2, 1); 49 | fd = open("/dev/null", 0); 50 | dup2(fd, 0); 51 | close(fd); 52 | } 53 | } 54 | if(type != '!') { 55 | if(type=='<' || type=='|') 56 | dup2(pipe1[1], 1); 57 | else if(type == '>') 58 | dup2(pipe1[0], 0); 59 | close(pipe1[0]); 60 | close(pipe1[1]); 61 | } 62 | if(type == '|'){ 63 | if(pipe(pipe2) == -1) 64 | exit(EXIT_FAILURE); 65 | if((pid = fork())==0){ 66 | /* 67 | * It's ok if we get SIGPIPE here 68 | */ 69 | close(pipe2[0]); 70 | io = fdopen(pipe2[1], "w"); 71 | if ((retcode = !setjmp(mainloop))){ /* assignment = */ 72 | char *c; 73 | for(l = 0; lnrunes; l+=m){ 74 | m = plan9buf->nrunes-l; 75 | if(m>BLOCKSIZE-1) 76 | m = BLOCKSIZE-1; 77 | Bread(plan9buf, genbuf, m, l); 78 | genbuf[m] = 0; 79 | c = Strtoc(tmprstr(genbuf, m+1)); 80 | Write(io, c, strlen(c)); 81 | free(c); 82 | } 83 | } 84 | exit(retcode? EXIT_FAILURE : EXIT_SUCCESS); 85 | } 86 | if(pid==-1){ 87 | fprintf(stderr, "Can't fork?!\n"); 88 | exit(EXIT_FAILURE); 89 | } 90 | dup2(pipe2[0], 0); 91 | close(pipe2[0]); 92 | close(pipe2[1]); 93 | } 94 | if(type=='<'){ 95 | close(0); /* so it won't read from terminal */ 96 | open("/dev/null", 0); 97 | } 98 | execl(shpath, sh, "-c", Strtoc(&plan9cmd), NULL); 99 | exit(EXIT_FAILURE); 100 | } 101 | if(pid == -1) 102 | error(Efork); 103 | if(type=='<' || type=='|'){ 104 | bool nulls; 105 | if(downloaded && addr.r.p1 != addr.r.p2) 106 | outTl(Hsnarflen, addr.r.p2-addr.r.p1); 107 | snarf(f, addr.r.p1, addr.r.p2, snarfbuf, false); 108 | Fdelete(f, addr.r.p1, addr.r.p2); 109 | close(pipe1[1]); 110 | io = fdopen(pipe1[0], "r"); 111 | f->tdot.p1 = -1; 112 | f->ndot.r.p2 = addr.r.p2+readio(f, &nulls, 0); 113 | f->ndot.r.p1 = addr.r.p2; 114 | closeio((Posn)-1); 115 | }else if(type=='>'){ 116 | close(pipe1[0]); 117 | io = fdopen(pipe1[1], "w"); 118 | bpipeok = true; 119 | writeio(f); 120 | bpipeok = false; 121 | closeio((Posn)-1); 122 | } 123 | retcode = waitfor(pid); 124 | if(type=='|' || type=='<') 125 | if(retcode!=0) 126 | warn(Wbadstatus); 127 | if(downloaded) 128 | checkerrs(); 129 | if(!nest) 130 | dprint(L"!\n"); 131 | return retcode; 132 | } 133 | 134 | void 135 | checkerrs(void) 136 | { 137 | char buf[256]; 138 | int f, n, nl; 139 | char *p; 140 | int64_t l; 141 | 142 | if(statfile(errfile, 0, 0, 0, &l, 0) > 0 && l != 0){ 143 | if((f=open((char *)errfile, 0)) != -1){ 144 | if((n=read(f, buf, sizeof buf-1)) > 0){ 145 | for(nl=0,p=buf; nl<3 && p<&buf[n]; p++) 146 | if(*p=='\n') 147 | nl++; 148 | *p = 0; 149 | dprint(L"%s", buf); 150 | if(p-buf < l-1) 151 | dprint(L"(sam: more in %s)\n", errfile); 152 | } 153 | close(f); 154 | } 155 | }else 156 | remove((char *)errfile); 157 | } 158 | -------------------------------------------------------------------------------- /sam.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /samterm/samterm.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #define SAMTERM 3 | 4 | #define RUNESIZE sizeof(wchar_t) 5 | #define MAXFILES 256 6 | #define NL 5 7 | 8 | enum{ 9 | Cescape = Csysmax + 1, /* highlight recently typed text */ 10 | Cscrolldown, /* scroll file down by screen */ 11 | Cscrollup, /* scroll file up by screen */ 12 | Cscrolldownline, /* scroll file down by line */ 13 | Cscrollupline, /* scroll file up by line */ 14 | Cjump, /* jump to/from command file */ 15 | Ccharright, /* move dot right by character */ 16 | Ccharleft, /* move dot left by character */ 17 | Clinedown, /* move dot down by line */ 18 | Clineup, /* move dot up by line */ 19 | Cdelword, /* delete word to left of dot */ 20 | Cdelbol, /* delete to beginning of line */ 21 | Cdelbs, /* delete character to left of dot */ 22 | Cdel, /* delete character to right of dot */ 23 | Csnarf, /* snarf dot */ 24 | Ccut, /* cut dot */ 25 | Cpaste, /* paste from snarf buffer */ 26 | Cexchange, /* exchange snarf buffer with OS */ 27 | Ceol, /* move to beginning of line */ 28 | Cbol, /* move to end of line */ 29 | Ctab, /* insert a possibly expanded tab */ 30 | Csend, /* send a command to the editor */ 31 | Cwrite, /* write the current file */ 32 | Clook, /* literal search */ 33 | Csearch, /* search for regex again */ 34 | Cmax /* invalid command */ 35 | }; 36 | 37 | enum{ 38 | Up, 39 | Down 40 | }; 41 | 42 | typedef struct Text Text; 43 | typedef struct Section Section; 44 | typedef struct Rasp Rasp; 45 | 46 | struct Section 47 | { 48 | int64_t nrunes; 49 | wchar_t *text; /* if null, we haven't got it */ 50 | Section *next; 51 | }; 52 | 53 | struct Rasp 54 | { 55 | int64_t nrunes; 56 | Section *sect; 57 | }; 58 | 59 | #define Untagged ((uint16_t)65535) 60 | 61 | struct Text 62 | { 63 | Rasp rasp; 64 | int16_t nwin; 65 | int16_t front; /* input window */ 66 | uint16_t tag; 67 | char lock; 68 | Flayer l[NL]; /* screen storage */ 69 | }; 70 | 71 | enum Resource 72 | { 73 | Eextern = 0x08, 74 | Ehost = 0x04, 75 | RHost = Ehost, 76 | RExtern = Eextern, 77 | RKeyboard = Ekeyboard, 78 | RMouse = Emouse 79 | }; 80 | 81 | extern Text *text[]; 82 | extern uint8_t *name[]; 83 | extern uint16_t tag[]; 84 | extern int nname; 85 | extern unsigned int cursor; 86 | extern Flayer *which; 87 | extern Flayer *work; 88 | extern Text cmd; 89 | extern wchar_t *scratch; 90 | extern int64_t nscralloc; 91 | extern char lock; 92 | extern bool hasunlocked; 93 | extern int64_t snarflen; 94 | extern Mouse mouse; 95 | extern bool modified; 96 | extern bool followfocus; 97 | 98 | wchar_t *stgettext(Flayer*, int64_t, uint64_t*); 99 | void *alloc(uint64_t n); 100 | 101 | void iconinit(void); 102 | void getscreen(int, char**); 103 | void initio(void); 104 | void setlock(void); 105 | void outcmd(void); 106 | void rinit(Rasp*); 107 | void startnewfile(int, Text*); 108 | void cursorset(Point); 109 | void getmouse(void); 110 | void mouseunblock(void); 111 | void kbdblock(void); 112 | int button(int but); 113 | int waitforio(void); 114 | int rcvchar(void); 115 | int getch(void); 116 | Keystroke qpeekc(void); 117 | Keystroke kbdchar(void); 118 | void mouseexit(void); 119 | void cut(Text*, int, bool, bool); 120 | void paste(Text*, int); 121 | void snarf(Text*, int); 122 | int center(Flayer*, int64_t); 123 | int xmenuhit(int, Menu*); 124 | void buttons(int); 125 | int getr(Rectangle*); 126 | void current(Flayer*); 127 | void duplicate(Flayer*, Rectangle, XftFont*, int); 128 | void startfile(Text*); 129 | void panic(char*); 130 | void closeup(Flayer*); 131 | void Strgrow(wchar_t**, int64_t*, int); 132 | int RESHAPED(void); 133 | void reshape(void); 134 | void rcv(void); 135 | void type(Flayer*); 136 | void menu2hit(void); 137 | void menu3hit(void); 138 | void scroll(Flayer*, int, int); 139 | void hcheck(int); 140 | void rclear(Rasp*); 141 | int whichmenu(int); 142 | void hcut(int, int64_t, int64_t); 143 | void horigin(int, int64_t, Flayer *); 144 | void hgrow(int, int64_t, int64_t, bool); 145 | int hdata(int, int64_t, uint8_t*, int); 146 | int hdatarune(int, int64_t, wchar_t*, int); 147 | wchar_t *rload(Rasp*, uint64_t, uint64_t, uint64_t*); 148 | void menuins(int, uint8_t*, Text*, int, int); 149 | void menudel(int); 150 | Text *sweeptext(int, int); 151 | void setpat(char*); 152 | bool haspat(void); 153 | void scrdraw(Flayer*, int64_t tot); 154 | int rcontig(Rasp*, uint64_t, uint64_t, bool); 155 | int rmissing(Rasp*, uint64_t, uint64_t); 156 | void rresize(Rasp *, int64_t, int64_t, int64_t); 157 | void rdata(Rasp*, int64_t, int64_t, wchar_t*); 158 | void rclean(Rasp*); 159 | void scrorigin(Flayer*, int, int64_t); 160 | int64_t scrtotal(Flayer*); 161 | void flnewlyvisible(Flayer*); 162 | char *rcvstring(void); 163 | void Strcpy(wchar_t*, wchar_t*); 164 | void Strncpy(wchar_t*, wchar_t*, int64_t); 165 | void flushtyping(bool); 166 | void dumperrmsg(int, int, int, int); 167 | int screensize(int*,int*); 168 | 169 | #include "../sam/mesg.h" 170 | 171 | void outTs(Tmesg, int); 172 | void outT0(Tmesg); 173 | void outTl(Tmesg, int64_t); 174 | void outTslS(Tmesg, int, int64_t, wchar_t*); 175 | void outTslll(Tmesg, int, int64_t, int64_t, int64_t); 176 | void outTsll(Tmesg, int, int64_t, int64_t); 177 | void outTsl(Tmesg, int, int64_t); 178 | void outTv(Tmesg, void*); 179 | void outstart(Tmesg); 180 | void outcopy(int, uint8_t*); 181 | void outshort(int); 182 | void outlong(int64_t); 183 | void outsend(void); 184 | int getlayer(const Flayer *l, const Text *t); 185 | void loadrcfile(FILE *); 186 | void installdefaultbindings(void); 187 | void installdefaultchords(void); 188 | -------------------------------------------------------------------------------- /samterm/rasp.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | #include "flayer.h" 6 | #include "samterm.h" 7 | 8 | void 9 | rinit(Rasp *r) 10 | { 11 | r->nrunes=0; 12 | r->sect=0; 13 | } 14 | 15 | void 16 | rclear(Rasp *r) 17 | { 18 | Section *s, *ns; 19 | 20 | for(s=r->sect; s; s=ns){ 21 | ns = s->next; 22 | free(s->text); 23 | free(s); 24 | } 25 | r->sect = 0; 26 | } 27 | 28 | Section* 29 | rsinsert(Rasp *r, Section *s) /* insert before s */ 30 | { 31 | Section *t; 32 | Section *u; 33 | 34 | t = alloc(sizeof(Section)); 35 | if(r->sect == s){ /* includes empty list case: r->sect==s==0 */ 36 | r->sect = t; 37 | t->next = s; 38 | }else{ 39 | u = r->sect; 40 | if(u == 0) 41 | panic("rsinsert 1"); 42 | do{ 43 | if(u->next == s){ 44 | t->next = s; 45 | u->next = t; 46 | goto Return; 47 | } 48 | u=u->next; 49 | }while(u); 50 | panic("rsinsert 2"); 51 | } 52 | Return: 53 | return t; 54 | } 55 | 56 | void 57 | rsdelete(Rasp *r, Section *s) 58 | { 59 | Section *t; 60 | 61 | if(s == 0) 62 | panic("rsdelete"); 63 | if(r->sect == s){ 64 | r->sect = s->next; 65 | goto Free; 66 | } 67 | for(t=r->sect; t; t=t->next) 68 | if(t->next == s){ 69 | t->next = s->next; 70 | Free: 71 | if(s->text) 72 | free(s->text); 73 | free(s); 74 | return; 75 | } 76 | panic("rsdelete 2"); 77 | } 78 | 79 | void 80 | splitsect(Rasp *r, Section *s, int64_t n0) 81 | { 82 | if(s == 0) 83 | panic("splitsect"); 84 | rsinsert(r, s->next); 85 | if(s->text == 0) 86 | s->next->text = 0; 87 | else{ 88 | s->next->text = alloc(RUNESIZE*(TBLOCKSIZE+1)); 89 | Strcpy(s->next->text, s->text+n0); 90 | s->text[n0] = 0; 91 | } 92 | s->next->nrunes = s->nrunes-n0; 93 | s->nrunes = n0; 94 | } 95 | 96 | Section * 97 | findsect(Rasp *r, Section *s, int64_t p, int64_t q) /* find sect containing q and put q on a sect boundary */ 98 | { 99 | if(s==0 && p!=q) 100 | panic("findsect"); 101 | for(; s && p+s->nrunes<=q; s=s->next) 102 | p += s->nrunes; 103 | if(p != q){ 104 | splitsect(r, s, q-p); 105 | s = s->next; 106 | } 107 | return s; 108 | } 109 | 110 | void 111 | rresize(Rasp *r, int64_t a, int64_t old, int64_t new) 112 | { 113 | Section *s, *t, *ns; 114 | 115 | s = findsect(r, r->sect, 0L, a); 116 | t = findsect(r, s, a, a+old); 117 | for(; s!=t; s=ns){ 118 | ns=s->next; 119 | rsdelete(r, s); 120 | } 121 | /* now insert the new piece before t */ 122 | if(new > 0){ 123 | ns=rsinsert(r, t); 124 | ns->nrunes=new; 125 | ns->text=0; 126 | } 127 | r->nrunes += new-old; 128 | } 129 | 130 | void 131 | rdata(Rasp *r, int64_t p0, int64_t p1, wchar_t *cp) 132 | { 133 | Section *s, *t, *ns; 134 | 135 | s = findsect(r, r->sect, 0L, p0); 136 | t = findsect(r, s, p0, p1); 137 | for(; s!=t; s=ns){ 138 | ns=s->next; 139 | if(s->text) 140 | panic("rdata"); 141 | rsdelete(r, s); 142 | } 143 | p1 -= p0; 144 | s = rsinsert(r, t); 145 | s->text = alloc(RUNESIZE*(TBLOCKSIZE+1)); 146 | memmove(s->text, cp, RUNESIZE*p1); 147 | s->text[p1] = 0; 148 | s->nrunes = p1; 149 | } 150 | 151 | void 152 | rclean(Rasp *r) 153 | { 154 | Section *s; 155 | 156 | for(s=r->sect; s; s=s->next) 157 | while(s->next && (s->text!=0)==(s->next->text!=0)){ 158 | if(s->text){ 159 | if(s->nrunes+s->next->nrunes>TBLOCKSIZE) 160 | break; 161 | Strcpy(s->text+s->nrunes, s->next->text); 162 | } 163 | s->nrunes += s->next->nrunes; 164 | rsdelete(r, s->next); 165 | } 166 | } 167 | 168 | void 169 | Strcpy(wchar_t *to, wchar_t *from) 170 | { 171 | do; while((*to++ = *from++)); 172 | } 173 | 174 | wchar_t* 175 | rload(Rasp *r, uint64_t p0, uint64_t p1, uint64_t *nrp) 176 | { 177 | Section *s; 178 | int64_t p; 179 | int n, nb; 180 | 181 | nb = 0; 182 | Strgrow(&scratch, &nscralloc, p1-p0+1); 183 | scratch[0] = 0; 184 | for(p=0,s=r->sect; s && p+s->nrunes<=p0; s=s->next) 185 | p += s->nrunes; 186 | while(ptext){ 194 | n = s->nrunes-(p0-p); 195 | if(n>p1-p0) /* all in this section */ 196 | n = p1-p0; 197 | memmove(scratch+nb, s->text+(p0-p), n*RUNESIZE); 198 | nb += n; 199 | scratch[nb] = 0; 200 | } 201 | p += s->nrunes; 202 | p0 = p; 203 | s = s->next; 204 | } 205 | if(nrp) 206 | *nrp = nb; 207 | return scratch; 208 | } 209 | 210 | int 211 | rmissing(Rasp *r, uint64_t p0, uint64_t p1) 212 | { 213 | Section *s; 214 | int64_t p; 215 | int n, nm=0; 216 | 217 | for(p=0,s=r->sect; s && p+s->nrunes<=p0; s=s->next) 218 | p += s->nrunes; 219 | while(ptext == 0){ 221 | n = s->nrunes-(p0-p); 222 | if(n > p1-p0) /* all in this section */ 223 | n = p1-p0; 224 | nm += n; 225 | } 226 | p += s->nrunes; 227 | p0 = p; 228 | s = s->next; 229 | } 230 | return nm; 231 | } 232 | 233 | int 234 | rcontig(Rasp *r, uint64_t p0, uint64_t p1, bool text) 235 | { 236 | Section *s; 237 | int64_t p, n; 238 | int np=0; 239 | 240 | for(p=0,s=r->sect; s && p+s->nrunes<=p0; s=s->next) 241 | p += s->nrunes; 242 | while(ptext!=0) : (s->text==0))){ 243 | n = s->nrunes-(p0-p); 244 | if(n > p1-p0) /* all in this section */ 245 | n = p1-p0; 246 | np += n; 247 | p += s->nrunes; 248 | p0 = p; 249 | s = s->next; 250 | } 251 | return np; 252 | } 253 | 254 | void 255 | Strgrow(wchar_t **s, int64_t *n, int want) /* can always toss the old data when called */ 256 | { 257 | if(*n >= want) 258 | return; 259 | free(*s); 260 | *s = alloc(RUNESIZE*want); 261 | *n = want; 262 | } 263 | -------------------------------------------------------------------------------- /sam/address.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include "sam.h" 3 | #include "parse.h" 4 | 5 | Address addr; 6 | String lastpat; 7 | bool patset; 8 | File *menu; 9 | 10 | File *matchfile(String*); 11 | Address charaddr(Posn, Address, int); 12 | 13 | Address 14 | address(Addr *ap, Address a, int sign) 15 | { 16 | File *f = a.f; 17 | Address a1, a2; 18 | 19 | do{ 20 | switch(ap->type){ 21 | case 'l': 22 | case '#': 23 | a = (*(ap->type=='#'?charaddr:lineaddr))(ap->num, a, sign); 24 | break; 25 | 26 | case '.': 27 | a = f->dot; 28 | break; 29 | 30 | case '$': 31 | a.r.p1 = a.r.p2 = f->nrunes; 32 | break; 33 | 34 | case '\'': 35 | a.r = f->mark; 36 | break; 37 | 38 | case '?': 39 | sign = -sign; 40 | if(sign == 0) 41 | sign = -1; 42 | /* fall through */ 43 | case '/': 44 | nextmatch(f, ap->are, sign>=0? a.r.p2 : a.r.p1, sign); 45 | a.r = sel.p[0]; 46 | break; 47 | 48 | case '"': 49 | a = matchfile(ap->are)->dot; 50 | f = a.f; 51 | if(f->state == Unread) 52 | load(f); 53 | break; 54 | 55 | case '*': 56 | a.r.p1 = 0, a.r.p2 = f->nrunes; 57 | return a; 58 | 59 | case ',': 60 | case ';': 61 | if(ap->left) 62 | a1 = address(ap->left, a, 0); 63 | else 64 | a1.f = a.f, a1.r.p1 = a1.r.p2 = 0; 65 | if(ap->type == ';'){ 66 | f = a1.f; 67 | f->dot = a = a1; 68 | } 69 | if(ap->next) 70 | a2 = address(ap->next, a, 0); 71 | else 72 | a2.f = a.f, a2.r.p1 = a2.r.p2 = f->nrunes; 73 | if(a1.f != a2.f) 74 | error(Eorder); 75 | a.f = a1.f, a.r.p1 = a1.r.p1, a.r.p2 = a2.r.p2; 76 | if(a.r.p2 < a.r.p1) 77 | error(Eorder); 78 | return a; 79 | 80 | case '+': 81 | case '-': 82 | sign = 1; 83 | if(ap->type == '-') 84 | sign = -1; 85 | if(ap->next==0 || ap->next->type=='+' || ap->next->type=='-') 86 | a = lineaddr(1L, a, sign); 87 | break; 88 | default: 89 | panic("address"); 90 | return a; 91 | } 92 | }while((ap = ap->next)); /* assign = */ 93 | return a; 94 | } 95 | 96 | void 97 | nextmatch(File *f, String *r, Posn p, int sign) 98 | { 99 | compile(r); 100 | if(sign >= 0){ 101 | if(!execute(f, p, INFINITY)) 102 | error(Esearch); 103 | if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p1==p){ 104 | if(++p>f->nrunes) 105 | p = 0; 106 | if(!execute(f, p, INFINITY)) 107 | panic("address"); 108 | } 109 | }else{ 110 | if(!bexecute(f, p)) 111 | error(Esearch); 112 | if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p2==p){ 113 | if(--p<0) 114 | p = f->nrunes; 115 | if(!bexecute(f, p)) 116 | panic("address"); 117 | } 118 | } 119 | } 120 | 121 | File * 122 | matchfile(String *r) 123 | { 124 | File *f; 125 | File *match = 0; 126 | int i; 127 | 128 | for(i = 0; iname); 150 | snprintf(buf, sizeof(buf) - 1, "%c%c%c %s\n", " '"[f->state==Dirty], 151 | "-+"[f->rasp!=0], " ."[f==curfile], c); 152 | free(c); 153 | t = tmpcstr(buf); 154 | Strduplstr(&genstr, t); 155 | freetmpstr(t); 156 | /* A little dirty... */ 157 | if(menu == 0) 158 | (menu=Fopen())->state=Clean; 159 | Bdelete(menu->buf, 0, menu->buf->nrunes); 160 | Binsert(menu->buf, &genstr, 0); 161 | menu->nrunes = menu->buf->nrunes; 162 | compile(r); 163 | return execute(menu, 0, menu->nrunes); 164 | } 165 | 166 | Address 167 | charaddr(Posn l, Address addr, int sign) 168 | { 169 | if(sign == 0) 170 | addr.r.p1 = addr.r.p2 = l; 171 | else if(sign < 0) 172 | addr.r.p2 = addr.r.p1-=l; 173 | else if(sign > 0) 174 | addr.r.p1 = addr.r.p2+=l; 175 | if(addr.r.p1<0 || addr.r.p2>addr.f->nrunes) 176 | error(Erange); 177 | return addr; 178 | } 179 | 180 | Address 181 | lineaddr(Posn l, Address addr, int sign) 182 | { 183 | int n; 184 | int c; 185 | File *f = addr.f; 186 | Address a; 187 | 188 | a.f = f; 189 | if(sign >= 0){ 190 | if(l == 0){ 191 | if(sign==0 || addr.r.p2==0){ 192 | a.r.p1 = a.r.p2 = 0; 193 | return a; 194 | } 195 | a.r.p1 = addr.r.p2; 196 | Fgetcset(f, addr.r.p2-1); 197 | }else{ 198 | if(sign==0 || addr.r.p2==0){ 199 | Fgetcset(f, (Posn)0); 200 | n = 1; 201 | }else{ 202 | Fgetcset(f, addr.r.p2-1); 203 | n = Fgetc(f)=='\n'; 204 | } 205 | for(; ngetcp; 213 | } 214 | do; while((c=Fgetc(f))!='\n' && c!=-1); 215 | a.r.p2 = f->getcp; 216 | }else{ 217 | Fbgetcset(f, addr.r.p1); 218 | if(l == 0) 219 | a.r.p2 = addr.r.p1; 220 | else{ 221 | c = 0; 222 | for(n = 0; ngetcp; 232 | if(c == '\n') 233 | a.r.p2++; /* lines start after a newline */ 234 | } 235 | do; while((c=Fbgetc(f))!='\n' && c!=-1); 236 | a.r.p1 = f->getcp; 237 | if(c == '\n') 238 | a.r.p1++; /* lines start after a newline */ 239 | } 240 | return a; 241 | } 242 | -------------------------------------------------------------------------------- /include/libg.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #ifndef _LIBG_H 3 | #define _LIBG_H 4 | 5 | /* 6 | * Like Plan9's libg.h, but suitable for inclusion on non-Plan9 machines 7 | */ 8 | 9 | #include 10 | 11 | enum{ EMAXMSG = 128+8192 }; /* max event size */ 12 | 13 | /* 14 | * Cursors 15 | */ 16 | 17 | enum{ 18 | DefaultCursor, 19 | ArrowCursor, 20 | BullseyeCursor, 21 | SweepCursor, 22 | DeadCursor, 23 | LockCursor 24 | }; 25 | 26 | /* 27 | * Types 28 | */ 29 | 30 | typedef struct Bitmap Bitmap; 31 | typedef struct Point Point; 32 | typedef struct Rectangle Rectangle; 33 | typedef struct Keystroke Keystroke; 34 | typedef struct Mouse Mouse; 35 | typedef struct Menu Menu; 36 | typedef struct Event Event; 37 | typedef struct RGB RGB; 38 | 39 | struct Point 40 | { 41 | int x; 42 | int y; 43 | }; 44 | 45 | struct Rectangle 46 | { 47 | Point min; 48 | Point max; 49 | }; 50 | 51 | struct Bitmap 52 | { 53 | Rectangle r; /* rectangle in data area, local coords */ 54 | Rectangle clipr; /* clipping region */ 55 | int ldepth; 56 | int id; /* as known by the X server */ 57 | Bitmap *cache; /* zero; distinguishes bitmap from layer */ 58 | XftDraw *fd; /* font drawable */ 59 | int flag; /* flag used by X implementation of libg */ 60 | }; 61 | 62 | struct Mouse 63 | { 64 | int buttons; /* bit array: LMR=124 */ 65 | Point xy; 66 | uint64_t msec; 67 | char *a; 68 | }; 69 | 70 | struct Keystroke 71 | { 72 | int k; 73 | int c; 74 | int t; 75 | Point p; 76 | const char *a; 77 | }; 78 | 79 | struct Menu 80 | { 81 | char **item; 82 | char *(*gen)(int); 83 | int lasthit; 84 | }; 85 | 86 | struct Event 87 | { 88 | Keystroke keystroke; 89 | Mouse mouse; 90 | int n; /* number of characters in mesage */ 91 | unsigned char data[EMAXMSG]; /* message from an arbitrary file descriptor */ 92 | }; 93 | 94 | struct RGB 95 | { 96 | uint64_t red; 97 | uint64_t green; 98 | uint64_t blue; 99 | }; 100 | 101 | enum{ 102 | Knone, /* invalid command type */ 103 | Kdefault, /* perform default command action */ 104 | Kraw, /* insert raw character code, subject to transformation (e.g. tab expansion) */ 105 | Kcommand, /* execute command (see below) */ 106 | Kend /* mark the end of a command list */ 107 | }; 108 | 109 | enum{ 110 | Cnone, /* no command */ 111 | Cdefault, /* default action */ 112 | Csysmax 113 | }; 114 | 115 | enum{ 116 | Tcurrent, /* command is sent to focused layer */ 117 | Tmouse /* command is sent to layer containing the mouse */ 118 | }; 119 | 120 | /* 121 | * Codes for bitblt etc. 122 | * 123 | * D 124 | * 0 1 125 | * --------- 126 | * 0 | 1 | 2 | 127 | * S |---|---| 128 | * 1 | 4 | 8 | 129 | * --------- 130 | * 131 | * Usually used as D|S; DorS is so tracebacks are readable. 132 | */ 133 | typedef 134 | enum Fcode 135 | { 136 | Zero = 0x0, 137 | DnorS = 0x1, 138 | DandnotS = 0x2, 139 | notS = 0x3, 140 | notDandS = 0x4, 141 | notD = 0x5, 142 | DxorS = 0x6, 143 | DnandS = 0x7, 144 | DandS = 0x8, 145 | DxnorS = 0x9, 146 | D = 0xA, 147 | DornotS = 0xB, 148 | S = 0xC, 149 | notDorS = 0xD, 150 | DorS = 0xE, 151 | F = 0xF 152 | } Fcode; 153 | 154 | /* 155 | * Miscellany 156 | */ 157 | 158 | typedef void (*Errfunc)(char *); 159 | 160 | extern void addlatin(char, char, int16_t); 161 | extern Point add(Point, Point); 162 | extern Point sub(Point, Point); 163 | extern Point mul(Point, int); 164 | extern Point divpt(Point, int); 165 | extern Rectangle rsubp(Rectangle, Point); 166 | extern Rectangle raddp(Rectangle, Point); 167 | extern Rectangle inset(Rectangle, int); 168 | extern Rectangle rmul(Rectangle, int); 169 | extern Rectangle rdiv(Rectangle, int); 170 | extern Rectangle rshift(Rectangle, int); 171 | extern Rectangle rcanon(Rectangle); 172 | extern Bitmap* balloc(Rectangle, int); 173 | extern void bfree(Bitmap*); 174 | extern int rectclip(Rectangle*, Rectangle); 175 | extern void xtbinit(Errfunc, char*, int*, char**, char**); 176 | extern void bclose(void); 177 | extern void berror(char*); 178 | extern void bitblt2(Bitmap*, Point, Bitmap*, Rectangle, Fcode, uint64_t, uint64_t); 179 | extern void bitblt(Bitmap*, Point, Bitmap*, Rectangle, Fcode); 180 | 181 | extern Point string(Bitmap*, Point, XftFont*, char*, Fcode); 182 | extern int64_t strwidth(XftFont*, char*); 183 | extern int64_t charwidth(XftFont*, wchar_t); 184 | extern void texture(Bitmap*, Rectangle, Bitmap*, Fcode); 185 | extern void wrbitmap(Bitmap*, int, int, unsigned char*); 186 | extern int ptinrect(Point, Rectangle); 187 | extern int rectXrect(Rectangle, Rectangle); 188 | extern int eqpt(Point, Point); 189 | extern int eqrect(Rectangle, Rectangle); 190 | extern void border(Bitmap*, Rectangle, int, Fcode, uint64_t); 191 | extern void cursorswitch(unsigned int); 192 | extern void cursorset(Point); 193 | extern Rectangle bscreenrect(Rectangle*); 194 | extern void bflush(void); 195 | 196 | extern int clipr(Bitmap*, Rectangle); 197 | extern int scrpix(int*,int*); 198 | extern uint64_t getbg(void); 199 | 200 | extern void einit(uint64_t); 201 | extern uint64_t estart(uint64_t, int, size_t, bool); 202 | 203 | extern uint64_t event(Event*); 204 | extern uint64_t eread(uint64_t, Event*); 205 | extern Mouse emouse(void); 206 | extern Keystroke ekbd(void); 207 | extern void pushkbd(int c); 208 | extern int ecanread(uint64_t); 209 | extern int ecanmouse(void); 210 | extern int ecankbd(void); 211 | extern void ereshaped(Rectangle); /* supplied by user */ 212 | 213 | extern int menuhit(int, Mouse*, Menu*); 214 | extern Rectangle getrect(int, Mouse*); 215 | 216 | extern void rdcolmap(Bitmap*, RGB*); 217 | extern void wrcolmap(Bitmap*, RGB*); 218 | extern void raisewindow(void); 219 | 220 | /* Extra functions supplied by libXg */ 221 | extern int snarfswap(char*, int, char**); 222 | 223 | enum{ 224 | Emouse = 1, 225 | Ekeyboard = 2 226 | }; 227 | 228 | extern Point Pt(int, int); 229 | extern Rectangle Rect(int, int, int, int); 230 | extern Rectangle Rpt(Point, Point); 231 | 232 | 233 | #define Dx(r) ((r).max.x-(r).min.x) 234 | #define Dy(r) ((r).max.y-(r).min.y) 235 | 236 | 237 | extern Bitmap screen; 238 | extern XftFont *font; 239 | extern XftColor fontcolor; 240 | extern XftColor bgcolor; 241 | 242 | #define BGSHORT(p) (((p)[0]<<0) | ((p)[1]<<8)) 243 | #define BGLONG(p) ((BGSHORT(p)<<0) | (BGSHORT(p+2)<<16)) 244 | #define BPSHORT(p, v) ((p)[0]=(v), (p)[1]=((v)>>8)) 245 | #define BPLONG(p, v) (BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16)) 246 | 247 | extern int installbinding(int, KeySym, int, int, const char *); 248 | extern int installchord(int, int, int, int, const char *); 249 | extern int removebinding(int, KeySym); 250 | extern int removechord(int, int); 251 | 252 | extern char foregroundspec[1024]; 253 | extern char backgroundspec[1024]; 254 | extern char borderspec[1024]; 255 | extern char fontspec[1024]; 256 | #endif 257 | -------------------------------------------------------------------------------- /libXg/menuhit.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include "libgint.h" 5 | 6 | enum 7 | { 8 | Margin = 3, /* outside to text */ 9 | Border = 2, /* outside to selection boxes */ 10 | Blackborder = 1, /* width of outlining border */ 11 | Vspacing = 1, /* extra spacing between lines of text */ 12 | Maxunscroll = 25, /* maximum #entries before scrolling turns on */ 13 | Nscroll = 20, /* number entries in scrolling part */ 14 | Scrollwid = 14, /* width of scroll bar */ 15 | Gap = 4 /* between text and scroll bar */ 16 | }; 17 | 18 | extern Bitmap *darkgrey; 19 | 20 | static int 21 | fontheight() { 22 | return font->ascent + font->descent; 23 | } 24 | 25 | /* 26 | * r is a rectangle holding the text elements. 27 | * return the rectangle, including its black edge, holding element i. 28 | */ 29 | static Rectangle 30 | menurect(Rectangle r, int i) 31 | { 32 | if(i < 0) 33 | return Rect(0, 0, 0, 0); 34 | r.min.y += (fontheight()+Vspacing)*i; 35 | r.max.y = r.min.y+fontheight()+Vspacing; 36 | return inset(r, Border-Margin); 37 | } 38 | 39 | /* 40 | * r is a rectangle holding the text elements. 41 | * return the element number containing p. 42 | */ 43 | static int 44 | menusel(Rectangle r, Point p) 45 | { 46 | if(!ptinrect(p, r)) 47 | return -1; 48 | return (p.y-r.min.y)/(fontheight()+Vspacing); 49 | } 50 | 51 | /* 52 | * menur is a rectangle holding all the highlightable text elements. 53 | * track mouse while inside the box, return what's selected when button 54 | * is raised, -1 as soon as it leaves box. 55 | * invariant: nothing is highlighted on entry or exit. 56 | */ 57 | static int 58 | menuscan(int but, Mouse *m, Rectangle menur, int lasti) 59 | { 60 | int i; 61 | Rectangle r; 62 | 63 | r = menurect(menur, lasti); 64 | bitblt(&screen, r.min, &screen, r, F&~D); 65 | *m = emouse(); 66 | while(m->buttons & (1<<(but-1))){ 67 | *m = emouse(); 68 | i = menusel(menur, m->xy); 69 | if(i == lasti) 70 | continue; 71 | bitblt(&screen, r.min, &screen, r, F&~D); 72 | if(i == -1) 73 | return i; 74 | r = menurect(menur, i); 75 | bitblt(&screen, r.min, &screen, r, F&~D); 76 | lasti = i; 77 | } 78 | return lasti; 79 | } 80 | 81 | void 82 | menupaint(Menu *menu, Rectangle textr, int off, int nitemdrawn) 83 | { 84 | int i; 85 | Point pt; 86 | Rectangle r; 87 | char *item; 88 | 89 | r = inset(textr, Border-Margin); 90 | bitblt(&screen, r.min, &screen, r, 0); 91 | pt = Pt(textr.min.x+textr.max.x, textr.min.y); 92 | for(i = 0; iitem? menu->item[i+off] : (*menu->gen)(i+off); 94 | string(&screen, 95 | Pt((pt.x-strwidth(font, item))/2, pt.y), 96 | font, item, S); 97 | } 98 | } 99 | 100 | static void 101 | menuscrollpaint(Rectangle scrollr, int off, int nitem, int nitemdrawn) 102 | { 103 | Rectangle r; 104 | 105 | bitblt(&screen, scrollr.min, &screen, scrollr, 0); 106 | r.min.x = scrollr.min.x; 107 | r.max.x = scrollr.max.x; 108 | r.min.y = scrollr.min.y + (Dy(scrollr)*off)/nitem; 109 | r.max.y = scrollr.min.y + (Dy(scrollr)*(off+nitemdrawn))/nitem; 110 | if(r.max.y < r.min.y+2) 111 | r.max.y = r.min.y+2; 112 | border(&screen, r, 1, F, _bgpixel); 113 | if(darkgrey) 114 | texture(&screen, inset(r, 1), darkgrey, S); 115 | } 116 | 117 | int 118 | menuhit(int but, Mouse *m, Menu *menu) 119 | { 120 | int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem; 121 | bool scrolling; 122 | Rectangle r, menur, sc, textr, scrollr; 123 | Bitmap *b; 124 | Point pt; 125 | char *item; 126 | extern unsigned int cursor; 127 | unsigned int oldcursor = cursor; 128 | 129 | cursorswitch(ArrowCursor); 130 | sc = screen.clipr; 131 | clipr(&screen, screen.r); 132 | maxwid = 0; 133 | for(nitem = 0; 134 | (item = menu->item? menu->item[nitem] : (*menu->gen)(nitem)); 135 | nitem++){ 136 | i = strwidth(font, item); 137 | if(i > maxwid) 138 | maxwid = i; 139 | } 140 | if(menu->lasthit<0 || menu->lasthit>=nitem) 141 | menu->lasthit = 0; 142 | screenitem = (Dy(screen.r)-10)/(fontheight()+Vspacing); 143 | if(nitem>Maxunscroll || nitem>screenitem){ 144 | scrolling = true; 145 | nitemdrawn = Nscroll; 146 | if(nitemdrawn > screenitem) 147 | nitemdrawn = screenitem; 148 | wid = maxwid + Gap + Scrollwid; 149 | off = menu->lasthit - nitemdrawn/2; 150 | if(off < 0) 151 | off = 0; 152 | if(off > nitem-nitemdrawn) 153 | off = nitem-nitemdrawn; 154 | lasti = menu->lasthit-off; 155 | }else{ 156 | scrolling = false; 157 | nitemdrawn = nitem; 158 | wid = maxwid; 159 | off = 0; 160 | lasti = menu->lasthit; 161 | } 162 | r = inset(Rect(0, 0, wid, nitemdrawn*(fontheight()+Vspacing)), -Margin); 163 | r = rsubp(r, Pt(wid/2, lasti*(fontheight()+Vspacing)+fontheight()/2)); 164 | r = raddp(r, m->xy); 165 | pt = Pt(0, 0); 166 | if(r.max.x>screen.r.max.x) 167 | pt.x = screen.r.max.x-r.max.x; 168 | if(r.max.y>screen.r.max.y) 169 | pt.y = screen.r.max.y-r.max.y; 170 | if(r.min.xbuttons & (1<<(but-1))){ 202 | lasti = menuscan(but, m, textr, lasti); 203 | if(lasti >= 0) 204 | break; 205 | while(!ptinrect(m->xy, textr) && (m->buttons & (1<<(but-1)))){ 206 | if(scrolling && ptinrect(m->xy, scrollr)){ 207 | noff = ((m->xy.y-scrollr.min.y)*nitem)/Dy(scrollr); 208 | noff -= nitemdrawn/2; 209 | if(noff < 0) 210 | noff = 0; 211 | if(noff > nitem-nitemdrawn) 212 | noff = nitem-nitemdrawn; 213 | if(noff != off){ 214 | off = noff; 215 | menupaint(menu, textr, off, nitemdrawn); 216 | menuscrollpaint(scrollr, off, nitem, nitemdrawn); 217 | } 218 | } 219 | *m = emouse(); 220 | } 221 | } 222 | bitblt(&screen, menur.min, b, menur, S); 223 | if(b != &screen) 224 | bfree(b); 225 | clipr(&screen, sc); 226 | if(lasti >= 0){ 227 | menu->lasthit = lasti+off; 228 | return cursorswitch(oldcursor), menu->lasthit; 229 | } 230 | cursorswitch(oldcursor); 231 | return -1; 232 | } 233 | -------------------------------------------------------------------------------- /sam/rasp.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include "sam.h" 3 | /* 4 | * GROWDATASIZE must be big enough that all errors go out as Hgrowdata's, 5 | * so they will be scrolled into visibility in the ~~sam~~ window (yuck!). 6 | */ 7 | #define GROWDATASIZE 50 /* if size is > this, send data with grow */ 8 | 9 | void rcut(List*, Posn, Posn); 10 | int rterm(List*, Posn); 11 | void rgrow(List*, Posn, Posn); 12 | 13 | void 14 | toterminal(File *f, int toterm) 15 | { 16 | Buffer *t = f->transcript; 17 | Posn n, p0, p1, p2, delta = 0, deltacmd = 0; 18 | Range r; 19 | union{ 20 | union Hdr g; 21 | wchar_t buf[8+GROWDATASIZE]; 22 | }hdr = {0}; 23 | Posn growpos, grown; 24 | 25 | growpos = 0; 26 | if(f->rasp == 0) 27 | return; 28 | if(f->marked) 29 | p0 = f->markp+sizeof(Mark)/RUNESIZE; 30 | else 31 | p0 = 0; 32 | grown = 0; 33 | noflush = true; 34 | while(Bread(t, (wchar_t*)&hdr, sizeof(hdr)/RUNESIZE, p0) > 0){ 35 | switch(hdr.g.cs.c){ 36 | default: 37 | fprintf(stderr, "char %c %.2x\n", hdr.g.cs.c, hdr.g.cs.c); 38 | panic("unknown in toterminal"); 39 | break; 40 | 41 | case 'd': 42 | if(grown){ 43 | outTsll(Hgrow, f->tag, growpos, grown); 44 | grown = 0; 45 | } 46 | p1 = hdr.g.cll.l; 47 | p2 = hdr.g.cll.l1; 48 | if(p2 <= p1) 49 | panic("toterminal delete 0"); 50 | if(f==cmd && p1tag, p1, p2-p1); 61 | rcut(f->rasp, p1, p2); 62 | delta -= p2-p1; 63 | break; 64 | 65 | case 'f': 66 | if(grown){ 67 | outTsll(Hgrow, f->tag, growpos, grown); 68 | grown = 0; 69 | } 70 | n = hdr.g.cs.s; 71 | p0 += sizeof(struct _cs)/RUNESIZE + n; 72 | break; 73 | 74 | case 'i': 75 | n = hdr.g.csl.s; 76 | p1 = hdr.g.csl.l; 77 | p0 += sizeof(struct _csl)/RUNESIZE + n; 78 | if(n <= 0) 79 | panic("toterminal insert 0"); 80 | if(f==cmd && p1GROWDATASIZE || !rterm(f->rasp, p1)){ 85 | rgrow(f->rasp, p1, n); 86 | if(grown && growpos+grown!=p1){ 87 | outTsll(Hgrow, f->tag, growpos, grown); 88 | grown = 0; 89 | } 90 | if(grown) 91 | grown += n; 92 | else{ 93 | growpos = p1; 94 | grown = n; 95 | } 96 | }else{ 97 | wchar_t *rp = hdr.buf + sizeof(hdr.g.csl) / RUNESIZE; 98 | if(grown){ 99 | outTsll(Hgrow, f->tag, growpos, grown); 100 | grown = 0; 101 | } 102 | 103 | rgrow(f->rasp, p1, n); 104 | r = rdata(f->rasp, p1, n); 105 | if(r.p1!=p1 || r.p2!=p1+n) 106 | panic("rdata in toterminal"); 107 | outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(rp, n)); 108 | } 109 | }else{ 110 | rgrow(f->rasp, p1, n); 111 | r = rdata(f->rasp, p1, n); 112 | if(r.p1!=p1 || r.p2!=p1+n) 113 | panic("rdata in toterminal"); 114 | } 115 | delta += n; 116 | break; 117 | } 118 | } 119 | if(grown) 120 | outTsll(Hgrow, f->tag, growpos, grown); 121 | if(toterm) 122 | outTs(Hcheck0, f->tag); 123 | outflush(); 124 | noflush = false; 125 | if(f == cmd){ 126 | cmdpt += deltacmd+cmdptadv; 127 | cmdptadv = 0; 128 | } 129 | } 130 | 131 | #define M 0x80000000L 132 | #define P(i) r->longptr[i] 133 | #define T(i) (P(i)&M) /* in terminal */ 134 | #define L(i) (P(i)&~M) /* length of this piece */ 135 | 136 | void 137 | rcut(List *r, Posn p1, Posn p2) 138 | { 139 | Posn p, x; 140 | int i; 141 | 142 | if(p1 == p2) 143 | panic("rcut 0"); 144 | for(p=0,i=0; inused && p+L(i)<=p1; p+=L(i++)) 145 | ; 146 | if(i == r->nused) 147 | panic("rcut 1"); 148 | if(pnused && p+L(i)<=p2){ 163 | p += L(i); 164 | dellist(r, i); 165 | } 166 | if(pnused) 168 | panic("rcut 2"); 169 | x = L(i)-(p2-p); 170 | if(T(i)) 171 | P(i) = x|M; 172 | else 173 | P(i) = x; 174 | } 175 | /* can we merge i and i-1 ? */ 176 | if(i>0 && inused && T(i-1)==T(i)){ 177 | x = L(i-1)+L(i); 178 | dellist(r, i--); 179 | if(T(i)) 180 | P(i)=x|M; 181 | else 182 | P(i)=x; 183 | } 184 | } 185 | 186 | void 187 | rgrow(List *r, Posn p1, Posn n) 188 | { 189 | Posn p; 190 | int i; 191 | 192 | if(n == 0) 193 | panic("rgrow 0"); 194 | for(p=0,i=0; inused && p+L(i)<=p1; p+=L(i++)) 195 | ; 196 | if(i == r->nused){ /* stick on end of file */ 197 | if(p!=p1) 198 | panic("rgrow 1"); 199 | if(i>0 && !T(i-1)) 200 | P(i-1)+=n; 201 | else 202 | inslist(r, i, n); 203 | }else if(!T(i)) /* goes in this empty piece */ 204 | P(i)+=n; 205 | else if(p==p1 && i>0 && !T(i-1)) /* special case; simplifies life */ 206 | P(i-1)+=n; 207 | else if(p==p1) 208 | inslist(r, i, n); 209 | else{ /* must break piece in terminal */ 210 | inslist(r, i+1, (L(i)-(p1-p))|M); 211 | inslist(r, i+1, n); 212 | P(i) = (p1-p)|M; 213 | } 214 | } 215 | 216 | int 217 | rterm(List *r, Posn p1) 218 | { 219 | Posn p; 220 | int i; 221 | 222 | for(p = 0,i = 0; inused && p+L(i)<=p1; p+=L(i++)) 223 | ; 224 | if(i==r->nused && (i==0 || !T(i-1))) 225 | return 0; 226 | return T(i); 227 | } 228 | 229 | Range 230 | rdata(List *r, Posn p1, Posn n) 231 | { 232 | Posn p; 233 | int i; 234 | Range rg; 235 | 236 | if(n==0) 237 | panic("rdata 0"); 238 | for(p = 0,i = 0; inused && p+L(i)<=p1; p+=L(i++)) 239 | ; 240 | if(i==r->nused) 241 | panic("rdata 1"); 242 | if(T(i)){ 243 | n-=L(i)-(p1-p); 244 | if(n<=0){ 245 | rg.p1 = rg.p2 = p1; 246 | return rg; 247 | } 248 | p+=L(i++); 249 | p1 = p; 250 | } 251 | if(T(i) || i==r->nused) 252 | panic("rdata 2"); 253 | if(p+L(i)nused-1 && T(i+1)){ 269 | P(i)=(n+=L(i+1))|M; 270 | dellist(r, i+1); 271 | } 272 | if(i>0 && T(i-1)){ 273 | P(i)=(n+L(i-1))|M; 274 | dellist(r, i-1); 275 | } 276 | return rg; 277 | } 278 | -------------------------------------------------------------------------------- /libframe/frinsert.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #define DELTA 25 7 | #define TMPSIZE 256 8 | static Frame frame; 9 | 10 | static 11 | Point 12 | bxscan(Frame *f, wchar_t *sp, wchar_t *ep, Point *ppt) 13 | { 14 | int w, c, nb, delta, nl, nr, rw; 15 | Frbox *b; 16 | char *s, tmp[TMPSIZE+3]; /* +3 for rune overflow */ 17 | uint8_t *p; 18 | 19 | frame.r = f->r; 20 | frame.b = f->b; 21 | frame.font = f->font; 22 | frame.fheight = f->font->ascent + f->font->descent; 23 | frame.maxtab = f->maxtab; 24 | frame.left = f->left; 25 | frame.nbox = 0; 26 | frame.nchars = 0; 27 | delta = DELTA; 28 | nl = 0; 29 | for(nb=0; spmaxlines; nb++,frame.nbox++){ 30 | if(nb == frame.nalloc){ 31 | _frgrowbox(&frame, delta); 32 | if(delta < 10000) 33 | delta *= 2; 34 | } 35 | b = &frame.box[nb]; 36 | c = *sp; 37 | if(c=='\t' || c=='\n'){ 38 | b->a.b.bc = c; 39 | b->wid = 5000; 40 | b->a.b.minwid = (c=='\n')? 0 : charwidth(frame.font, ' '); 41 | b->nrune = -1; 42 | if(c=='\n') 43 | nl++; 44 | frame.nchars++; 45 | sp++; 46 | }else{ 47 | s = tmp; 48 | nr = 0; 49 | w = 0; 50 | while(sp < ep){ 51 | c = *sp; 52 | if(c=='\t' || c=='\n') 53 | break; 54 | rw = runetochar(s, *sp); 55 | if(s+rw >= tmp+TMPSIZE) 56 | break; 57 | w += charwidth(frame.font, c); 58 | sp++; 59 | s += rw; 60 | nr++; 61 | } 62 | *s++ = 0; 63 | p = _frallocstr(s-tmp); 64 | b = &frame.box[nb]; 65 | b->a.ptr = p; 66 | memmove(p, tmp, s-tmp); 67 | b->wid = w; 68 | b->nrune = nr; 69 | frame.nchars += nr; 70 | } 71 | } 72 | _frcklinewrap0(f, ppt, &frame.box[0]); 73 | return _frdraw(&frame, *ppt); 74 | } 75 | 76 | static 77 | void 78 | chopframe(Frame *f, Point pt, uint64_t p, int bn) 79 | { 80 | Frbox *b; 81 | 82 | for(b = &f->box[bn]; ; b++){ 83 | if(b >= &f->box[f->nbox]) 84 | berror("endofframe"); 85 | _frcklinewrap(f, &pt, b); 86 | if(pt.y >= f->r.max.y) 87 | break; 88 | p += NRUNE(b); 89 | _fradvance(f, &pt, b); 90 | } 91 | f->nchars = p; 92 | f->nlines = f->maxlines; 93 | if(b<&f->box[f->nbox]) /* BUG */ 94 | _frdelbox(f, (int)(b-f->box), f->nbox-1); 95 | } 96 | 97 | void 98 | frinsert(Frame *f, wchar_t *sp, wchar_t *ep, uint64_t p0) 99 | { 100 | Point pt0, pt1, ppt0, ppt1, pt; 101 | Frbox *b; 102 | int n, n0, nn0, y; 103 | Rectangle r; 104 | static struct{ 105 | Point pt0, pt1; 106 | }*pts; 107 | static int nalloc=0; 108 | int npts; 109 | 110 | if(p0>f->nchars || sp==ep || f->b==0) 111 | return; 112 | n0 = _frfindbox(f, 0, 0, p0); 113 | nn0 = n0; 114 | pt0 = _frptofcharnb(f, p0, n0); 115 | ppt0 = pt0; 116 | pt1 = bxscan(f, sp, ep, &ppt0); 117 | ppt1 = pt1; 118 | if(n0 < f->nbox){ 119 | _frcklinewrap(f, &pt0, b = &f->box[n0]); /* for frselectf() */ 120 | _frcklinewrap0(f, &ppt1, b); 121 | } 122 | f->modified = true; 123 | /* 124 | * ppt0 and ppt1 are start and end of insertion as they will appear when 125 | * insertion is complete. pt0 is current location of insertion position 126 | * (p0); pt1 is terminal point (without line wrap) of insertion. 127 | */ 128 | if(p0==f->p0 && p0==f->p1) /* quite likely */ 129 | frselectf(f, pt0, pt0, F&~D); 130 | else 131 | frselectp(f, F&~D); 132 | /* 133 | * Find point where old and new x's line up 134 | * Invariants: 135 | * pt0 is where the next box (b, n0) is now 136 | * pt1 is where it will be after then insertion 137 | * If pt1 goes off the rectangle, we can toss everything from there on 138 | */ 139 | for(b = &f->box[n0],npts=0; 140 | pt1.x!=pt0.x && pt1.y!=f->r.max.y && n0nbox; b++,n0++,npts++){ 141 | _frcklinewrap(f, &pt0, b); 142 | _frcklinewrap0(f, &pt1, b); 143 | if(b->nrune > 0){ 144 | n = _frcanfit(f, pt1, b); 145 | if(n == 0) 146 | berror("_frcanfit==0"); 147 | if(n != b->nrune){ 148 | _frsplitbox(f, n0, n); 149 | b = &f->box[n0]; 150 | } 151 | } 152 | if(npts == nalloc){ 153 | pts = realloc(pts, (npts+DELTA)*sizeof(pts[0])); 154 | nalloc += DELTA; 155 | b = &f->box[n0]; 156 | } 157 | pts[npts].pt0 = pt0; 158 | pts[npts].pt1 = pt1; 159 | /* has a text box overflowed off the frame? */ 160 | if(pt1.y == f->r.max.y) 161 | break; 162 | _fradvance(f, &pt0, b); 163 | pt1.x += _frnewwid(f, pt1, b); 164 | } 165 | if(pt1.y > f->r.max.y) 166 | berror("frinsert pt1 too far"); 167 | if(pt1.y==f->r.max.y && n0nbox){ 168 | f->nchars -= _frstrlen(f, n0); 169 | _frdelbox(f, n0, f->nbox-1); 170 | } 171 | if(n0 == f->nbox) 172 | f->nlines = (pt1.y-f->r.min.y)/f->fheight+(pt1.x>f->left); 173 | else if(pt1.y!=pt0.y){ 174 | int q0, q1; 175 | 176 | y = f->r.max.y; 177 | q0 = pt0.y+f->fheight; 178 | q1 = pt1.y+f->fheight; 179 | f->nlines += (q1-q0)/f->fheight; 180 | if(f->nlines > f->maxlines) 181 | chopframe(f, ppt1, p0, nn0); 182 | if(pt1.y < y){ 183 | r = f->r; 184 | r.min.y = q0; 185 | r.max.y = y-(q1-q0); 186 | if(q1 < y) 187 | bitblt2(f->b, Pt(f->r.min.x, q1), f->b, r, S, 0, f->bg); 188 | r.min = pt0; 189 | r.max.y = q0; 190 | bitblt2(f->b, pt1, f->b, r, S, 0, f->bg); 191 | } 192 | } 193 | /* 194 | * Move the old stuff down to make room. The loop will move the stuff 195 | * between the insertion and the point where the x's lined up. 196 | * The bitblt2 above moved everything down after the point they lined up. 197 | */ 198 | for((y=pt1.y==f->r.max.y?pt1.y:0),b = &f->box[n0-1]; --npts>=0; --b){ 199 | pt = pts[npts].pt1; 200 | if(b->nrune > 0){ 201 | r.min = pts[npts].pt0; 202 | r.max = r.min; 203 | r.max.x += b->wid; 204 | r.max.y += f->fheight; 205 | bitblt2(f->b, pt, f->b, r, S, 0, f->bg); 206 | if(pt.y < y){ /* clear bit hanging off right */ 207 | r.min = pt; 208 | r.max = pt; 209 | r.min.x += b->wid; 210 | r.max.x = f->r.max.x; 211 | r.max.y += f->fheight; 212 | bitblt2(f->b, r.min, f->b, r, 0, 0, f->bg); 213 | } 214 | y = pt.y; 215 | }else{ 216 | r.min = pt; 217 | r.max = pt; 218 | r.max.x += b->wid; 219 | r.max.y += f->fheight; 220 | if(r.max.x >= f->r.max.x) 221 | r.max.x = f->r.max.x; 222 | bitblt2(f->b, r.min, f->b, r, 0, 0, f->bg); 223 | y = (pt.x == f->left)? pt.y : 0; 224 | } 225 | } 226 | frselectf(f, ppt0, ppt1, 0); 227 | _frredraw(&frame, ppt0); 228 | _fraddbox(f, nn0, frame.nbox); 229 | for(n=0; nbox[nn0+n] = frame.box[n]; 231 | if(nn0>0 && f->box[nn0-1].nrune>=0 && ppt0.x-f->box[nn0-1].wid>=(int)f->left){ 232 | --nn0; 233 | ppt0.x -= f->box[nn0].wid; 234 | } 235 | n0 += frame.nbox; 236 | _frclean(f, ppt0, nn0, n0nbox-1? n0+1 : n0); 237 | f->nchars += frame.nchars; 238 | if(f->p0 >= p0) 239 | f->p0 += frame.nchars; 240 | if(f->p0 > f->nchars) 241 | f->p0 = f->nchars; 242 | if(f->p1 >= p0) 243 | f->p1 += frame.nchars; 244 | if(f->p1 > f->nchars) 245 | f->p1 = f->nchars; 246 | frselectp(f, F&~D); 247 | } 248 | -------------------------------------------------------------------------------- /samterm/menu.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | #include "flayer.h" 6 | #include "samterm.h" 7 | 8 | uint8_t *name[MAXFILES]; /* first byte is ' ' or '\'': modified state */ 9 | Text *text[MAXFILES]; /* pointer to Text associated with file */ 10 | uint16_t tag[MAXFILES]; /* text[i].tag, even if text[i] not defined */ 11 | int nname; 12 | int mw; 13 | 14 | char *genmenu3(int); 15 | char *genmenu2(int); 16 | char *genmenu2c(int); 17 | 18 | extern uint64_t _bgpixel; 19 | 20 | enum Menu2 21 | { 22 | Cut, 23 | Paste, 24 | Snarf, 25 | Look, 26 | Exch, 27 | Search, 28 | NMENU2 = Search, 29 | Send = Search, 30 | NMENU2C 31 | }; 32 | 33 | enum Menu3 34 | { 35 | New, 36 | Zerox, 37 | Reshape, 38 | Close, 39 | Write, 40 | NMENU3 41 | }; 42 | 43 | char *menu2str[] = { 44 | "cut", 45 | "paste", 46 | "snarf", 47 | "look", 48 | "", 49 | 0, /* storage for last pattern */ 50 | }; 51 | 52 | char *menu3str[] = { 53 | "new", 54 | "zerox", 55 | "reshape", 56 | "close", 57 | "write", 58 | }; 59 | 60 | Menu menu2 = {0, genmenu2}; 61 | Menu menu2c ={0, genmenu2c}; 62 | Menu menu3 = {0, genmenu3}; 63 | 64 | void 65 | menu2hit(void) 66 | { 67 | Text *t=(Text *)which->user1; 68 | int w = which-t->l; 69 | int m; 70 | 71 | m = menuhit(2, &mouse, t==&cmd? &menu2c : &menu2); 72 | if(lock || t->lock) 73 | return; 74 | 75 | switch(m){ 76 | case Cut: 77 | cut(t, w, true, true); 78 | break; 79 | 80 | case Paste: 81 | paste(t, w); 82 | break; 83 | 84 | case Snarf: 85 | snarf(t, w); 86 | break; 87 | 88 | case Exch: 89 | snarf(t, w); 90 | outT0(Tstartsnarf); 91 | setlock(); 92 | break; 93 | 94 | case Look: 95 | outTsll(Tlook, t->tag, which->p0, which->p1); 96 | setlock(); 97 | break; 98 | 99 | case Search: 100 | outcmd(); 101 | if(t==&cmd) 102 | outTsll(Tsend, 0 /*ignored*/, which->p0, which->p1); 103 | else 104 | outT0(Tsearch); 105 | setlock(); 106 | break; 107 | } 108 | } 109 | 110 | void 111 | menu3hit(void) 112 | { 113 | Rectangle r; 114 | Flayer *l; 115 | int m, i; 116 | Text *t; 117 | 118 | mw = -1; 119 | switch(m = menuhit(3, &mouse, &menu3)){ 120 | case -1: 121 | break; 122 | 123 | case New: 124 | if(!lock) 125 | sweeptext(1, 0); 126 | break; 127 | 128 | case Zerox: 129 | case Reshape: 130 | if(!lock){ 131 | cursorswitch(BullseyeCursor); 132 | buttons(Down); 133 | if((mouse.buttons&4) && (l = flwhich(mouse.xy)) && getr(&r)) 134 | duplicate(l, r, l->f.font, m==Reshape); 135 | else 136 | cursorswitch(cursor); 137 | buttons(Up); 138 | } 139 | break; 140 | 141 | case Close: 142 | if(!lock){ 143 | cursorswitch(BullseyeCursor); 144 | buttons(Down); 145 | if((mouse.buttons&4) && (l = flwhich(mouse.xy)) && !lock){ 146 | t=(Text *)l->user1; 147 | if (t->nwin>1) 148 | closeup(l); 149 | else if(t!=&cmd) { 150 | outTs(Tclose, t->tag); 151 | setlock(); 152 | } 153 | } 154 | cursorswitch(cursor); 155 | buttons(Up); 156 | } 157 | break; 158 | 159 | case Write: 160 | if(!lock){ 161 | cursorswitch(BullseyeCursor); 162 | buttons(Down); 163 | if((mouse.buttons&4) && (l = flwhich(mouse.xy))){ 164 | outTs(Twrite, ((Text *)l->user1)->tag); 165 | setlock(); 166 | }else 167 | cursorswitch(cursor); 168 | buttons(Up); 169 | } 170 | break; 171 | 172 | default: 173 | if((t = text[m-NMENU3])){ 174 | i = t->front; 175 | if(t->nwin==0 || t->l[i].textfn==0) 176 | return; /* not ready yet; try again later */ 177 | if(t->nwin>1 && which==&t->l[i]) 178 | do 179 | if(++i==NL) 180 | i = 0; 181 | while(i!=t->front && t->l[i].textfn==0); 182 | current(&t->l[i]); 183 | if (followfocus) 184 | flupfront(&t->l[i]); 185 | }else if(!lock) 186 | sweeptext(0, tag[m-NMENU3]); 187 | break; 188 | } 189 | } 190 | 191 | 192 | Text * 193 | sweeptext(int new, int tag) 194 | { 195 | Rectangle r; 196 | Text *t; 197 | 198 | if(getr(&r) && (t = malloc(sizeof(Text)))){ 199 | memset((void*)t, 0, sizeof(Text)); 200 | current((Flayer *)0); 201 | flnew(&t->l[0], stgettext, 0, (char *)t); 202 | flinit(&t->l[0], r, font, getbg()); /*bnl*/ 203 | t->nwin = 1; 204 | rinit(&t->rasp); 205 | if(new) 206 | startnewfile(Tstartnewfile, t); 207 | else{ 208 | rinit(&t->rasp); 209 | t->tag = tag; 210 | startfile(t); 211 | } 212 | return t; 213 | } 214 | return 0; 215 | } 216 | 217 | int 218 | whichmenu(int tg) 219 | { 220 | int i; 221 | 222 | for(i=0; in; --i) 236 | name[i]=name[i-1], text[i]=text[i-1], tag[i]=tag[i-1]; 237 | text[n] = t; 238 | tag[n] = tg; 239 | name[n] = alloc(strlen((char*)s)+2); 240 | name[n][0] = m; 241 | strcpy((char*)name[n]+1, (char*)s); 242 | nname++; 243 | menu3.lasthit = n+NMENU3; 244 | } 245 | 246 | void 247 | menudel(int n) 248 | { 249 | int i; 250 | 251 | if(nname==0 || n>=nname || text[n]) 252 | panic("menudel"); 253 | free(name[n]); 254 | --nname; 255 | for(i = n; iuser1; 293 | char *p; 294 | if(n>=NMENU2+(menu2str[Search]!=0)) 295 | return 0; 296 | p = menu2str[n]; 297 | if((!lock && !t->lock) || n==Search || n==Look) 298 | return p; 299 | return paren(p); 300 | } 301 | char* 302 | genmenu2c(int n) 303 | { 304 | Text *t=(Text *)which->user1; 305 | char *p; 306 | if(n >= NMENU2C) 307 | return 0; 308 | if(n == Send) 309 | p="send"; 310 | else 311 | p = menu2str[n]; 312 | if(!lock && !t->lock) 313 | return p; 314 | return paren(p); 315 | } 316 | char * 317 | genmenu3(int n) 318 | { 319 | Text *t; 320 | int c, i, k, l, w; 321 | wchar_t r; 322 | char *p; 323 | 324 | if(n >= NMENU3+nname) 325 | return 0; 326 | if(n < NMENU3){ 327 | p = menu3str[n]; 328 | if(lock) 329 | p = paren(p); 330 | return p; 331 | } 332 | n -= NMENU3; 333 | if(n == 0) /* unless we've been fooled, this is cmd */ 334 | return (char *)&name[n][1]; 335 | if(mw == -1){ 336 | mw = 7; /* strlen("~~sam~~"); */ 337 | for(i=1; i mw) 340 | mw = w; 341 | } 342 | } 343 | if(mw > NBUF) 344 | mw = NBUF; 345 | t = text[n]; 346 | buf[0] = name[n][0]; 347 | buf[1] = '-'; 348 | buf[2] = ' '; 349 | buf[3] = ' '; 350 | if(t){ 351 | if(t->nwin == 1) 352 | buf[1] = '+'; 353 | else if(t->nwin > 1) 354 | buf[1] = '*'; 355 | if(work && t==(Text *)work->user1) { 356 | buf[2]= '.'; 357 | if(modified) 358 | buf[0] = '\''; 359 | } 360 | } 361 | l = utflen((char*)name[n]+1); 362 | if(l > NBUF-4-2){ 363 | i = 4; 364 | k = 1; 365 | while(i < NBUF/2){ 366 | k += chartorune(&r, (char*)name[n]+k); 367 | i++; 368 | } 369 | c = name[n][k]; 370 | name[n][k] = 0; 371 | strcpy((char*)buf+4, (char*)name[n]+1); 372 | name[n][k] = c; 373 | strcat((char*)buf, "..."); 374 | while((l-i) >= NBUF/2-4){ 375 | k += chartorune(&r, (char*)name[n]+k); 376 | i++; 377 | } 378 | strcat((char*)buf, (char*)name[n]+k); 379 | }else 380 | strcpy((char*)buf+4, (char*)name[n]+1); 381 | i = utflen((char*)buf); 382 | k = strlen((char*)buf); 383 | while(i 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "sam.h" 11 | 12 | #define NSYSFILE 3 13 | #define NOFILE 128 14 | 15 | #define MIN(x, y) ((x) < (y)? (x) : (y)) 16 | 17 | void 18 | checkqid(File *f) 19 | { 20 | int i, w; 21 | File *g; 22 | 23 | w = whichmenu(f); 24 | for(i=1; idev==g->dev && f->qid==g->qid) 29 | warn_SS(Wdupfile, &f->name, &g->name); 30 | } 31 | } 32 | 33 | void 34 | writef(File *f) 35 | { 36 | wchar_t c; 37 | Posn n; 38 | char *name; 39 | int i, samename, newfile; 40 | uint64_t dev, qid; 41 | int64_t mtime, appendonly, length; 42 | 43 | newfile = 0; 44 | samename = Strcmp(&genstr, &f->name) == 0; 45 | name = Strtoc(&f->name); 46 | i = statfile(name, &dev, &qid, &mtime, 0, 0); 47 | if(i == -1) 48 | newfile++; 49 | else if(samename && 50 | (f->dev!=dev || f->qid!=qid || f->datedev = dev; 52 | f->qid = qid; 53 | f->date = mtime; 54 | warn_S(Wdate, &genstr); 55 | return; 56 | } 57 | if(genc) 58 | free(genc); 59 | genc = Strtoc(&genstr); 60 | if ((io = fopen(genc, "w+")) == NULL) 61 | error_s(Ecreate, genc); 62 | dprint(L"%s: ", genc); 63 | if(statfd(fileno(io), 0, 0, 0, &length, &appendonly) > 0 && appendonly && length>0) 64 | error(Eappend); 65 | n = writeio(f); 66 | if(f->name.s[0]==0 || samename) 67 | state(f, addr.r.p1==0 && addr.r.p2==f->nrunes? Clean : Dirty); 68 | if(newfile) 69 | dprint(L"(new file) "); 70 | if(addr.r.p2>0 && Fchars(f, &c, addr.r.p2-1, addr.r.p2) && c!='\n') 71 | warn(Wnotnewline); 72 | closeio(n); 73 | if(f->name.s[0]==0 || samename){ 74 | if(statfile(name, &dev, &qid, &mtime, 0, 0) > 0){ 75 | f->dev = dev; 76 | f->qid = qid; 77 | f->date = mtime; 78 | checkqid(f); 79 | } 80 | } 81 | } 82 | 83 | Posn 84 | readio(File *f, bool *nulls, bool setdate) 85 | { 86 | uint64_t dev, qid; 87 | int64_t mtime; 88 | int olderr = errno; 89 | Posn nt = 0; 90 | 91 | wchar_t buf[2] = {0}; 92 | while (true){ 93 | buf[0] = fgetwc(io); 94 | if (buf[0] == WEOF){ 95 | if (errno == EILSEQ){ 96 | clearerr(io); 97 | fflush(io); 98 | fgetc(io); /* POSIX does not mandate that we advance here... */ 99 | buf[0] = UNICODE_REPLACEMENT_CHAR; 100 | errno = 0; 101 | } else 102 | break; 103 | } 104 | 105 | if (buf[0] == 0) 106 | *nulls = true; 107 | 108 | nt++; 109 | Finsert(f, tmprstr(buf, 1), addr.r.p2); 110 | } 111 | 112 | if (setdate){ 113 | if (statfd(fileno(io), &dev, &qid, &mtime, 0, 0) > 0){ 114 | f->dev = dev; 115 | f->qid = qid; 116 | f->date = mtime; 117 | checkqid(f); 118 | } 119 | } 120 | 121 | errno = olderr; 122 | return nt; 123 | } 124 | 125 | void 126 | flushio(void) 127 | { 128 | if (io) 129 | fflush(io); 130 | } 131 | 132 | Posn 133 | writeio(File *f) 134 | { 135 | int m, n; 136 | Posn p = addr.r.p1; 137 | char *c; 138 | 139 | while(p < addr.r.p2){ 140 | if(addr.r.p2-p>BLOCKSIZE) 141 | n = BLOCKSIZE; 142 | else 143 | n = addr.r.p2-p; 144 | if(Fchars(f, genbuf, p, p+n)!=n) 145 | panic("writef read"); 146 | c = Strtoc(tmprstr(genbuf, n)); 147 | m = strlen(c); 148 | if (m < n) 149 | panic("corrupted file"); 150 | if(Write(io, c, m) != m){ 151 | free(c); 152 | if(p > 0) 153 | p += n; 154 | break; 155 | } 156 | free(c); 157 | p += n; 158 | } 159 | return p-addr.r.p1; 160 | } 161 | void 162 | closeio(Posn p) 163 | { 164 | fclose(io); 165 | io = NULL; 166 | if(p >= 0) 167 | dprint(L"#%lu\n", p); 168 | } 169 | 170 | char exname[PATH_MAX + 1]; 171 | int remotefd0 = 0; 172 | int remotefd1 = 1; 173 | int exfd = -1; 174 | 175 | void 176 | bootterm(char *machine) 177 | { 178 | char fd[100]; 179 | int ph2t[2], pt2h[2]; 180 | 181 | snprintf(fd, sizeof(fd) - 1, "%d", exfd); 182 | 183 | if (machine){ 184 | dup2(remotefd0, 0); 185 | dup2(remotefd1, 1); 186 | close(remotefd0); 187 | close(remotefd1); 188 | if (exfd >= 0) 189 | execlp(samterm, samterm, "-r", machine, "-f", fd, "-n", exname, NULL); 190 | else 191 | execlp(samterm, samterm, "-r", machine, NULL); 192 | perror("couldn't exec samterm"); 193 | exit(EXIT_FAILURE); 194 | } 195 | 196 | if (pipe(ph2t)==-1 || pipe(pt2h)==-1) 197 | panic("pipe"); 198 | 199 | machine = machine? machine : "localhost"; 200 | switch (fork()){ 201 | case 0: 202 | dup2(ph2t[0], 0); 203 | dup2(pt2h[1], 1); 204 | close(ph2t[0]); 205 | close(ph2t[1]); 206 | close(pt2h[0]); 207 | close(pt2h[1]); 208 | if (exfd >= 0) 209 | execlp(samterm, samterm, "-r", machine, "-f", fd, "-n", exname, NULL); 210 | else 211 | execlp(samterm, samterm, "-r", machine, NULL); 212 | perror("couldn't exec samterm"); 213 | exit(EXIT_FAILURE); 214 | break; 215 | 216 | case -1: 217 | panic("can't fork samterm"); 218 | break; 219 | } 220 | 221 | dup2(pt2h[0], 0); 222 | dup2(ph2t[1], 1); 223 | close(ph2t[0]); 224 | close(ph2t[1]); 225 | close(pt2h[0]); 226 | close(pt2h[1]); 227 | } 228 | 229 | void 230 | connectto(char *machine) 231 | { 232 | int p1[2], p2[2]; 233 | char sockname[FILENAME_MAX + 1] = {0}; 234 | char rarg[FILENAME_MAX + 1] = {0}; 235 | 236 | snprintf(sockname, FILENAME_MAX, "%s/sam.remote.%s", 237 | getenv("RSAMSOCKETPATH")? getenv("RSAMSOCKETPATH") : "/tmp", 238 | getenv("USER")? getenv("USER") : getenv("LOGNAME")? getenv("LOGNAME") : "nemo"); 239 | 240 | snprintf(rarg, FILENAME_MAX, "%s:%s", sockname, exname); 241 | 242 | if(pipe(p1)<0 || pipe(p2)<0){ 243 | dprint(L"can't pipe\n"); 244 | exit(EXIT_FAILURE); 245 | } 246 | remotefd0 = p1[0]; 247 | remotefd1 = p2[1]; 248 | switch(fork()){ 249 | case 0: 250 | dup2(p2[0], 0); 251 | dup2(p1[1], 1); 252 | close(p1[0]); 253 | close(p1[1]); 254 | close(p2[0]); 255 | close(p2[1]); 256 | execlp(getenv("RSH") ? getenv("RSH") : RXPATH, 257 | getenv("RSH") ? getenv("RSH") : RXPATH, 258 | "-R", rarg, 259 | machine, rsamname, "-R", sockname, 260 | NULL); 261 | dprint(L"can't exec %s\n", RXPATH); 262 | exit(EXIT_FAILURE); 263 | 264 | case -1: 265 | dprint(L"can't fork\n"); 266 | exit(EXIT_FAILURE); 267 | } 268 | close(p1[1]); 269 | close(p2[0]); 270 | } 271 | 272 | void 273 | removesocket(void) 274 | { 275 | close(exfd); 276 | unlink(exname); 277 | exname[0] = 0; 278 | } 279 | 280 | bool 281 | canlocksocket(const char *machine) 282 | { 283 | int fd = -1; 284 | const char *path = getenv("SAMSOCKPATH")? getenv("SAMSOCKPATH") : getenv("HOME"); 285 | char lockpath[FILENAME_MAX + 1] = {0}; 286 | 287 | if (!path){ 288 | fputs("could not determine command socket path\n", stderr); 289 | return true; 290 | } 291 | 292 | snprintf(lockpath, PATH_MAX, "%s/.sam.%s.lock", path, machine? machine : "localhost"); 293 | fd = open(lockpath, O_CREAT | O_RDWR, 0644); 294 | if (fd < 0) 295 | return false; 296 | 297 | if (lockf(fd, F_TLOCK, 0) != 0) 298 | return close(fd), false; 299 | 300 | return true; 301 | } 302 | 303 | void 304 | opensocket(const char *machine) 305 | { 306 | struct sockaddr_un un = {0}; 307 | const char *path = getenv("SAMSOCKPATH")? getenv("SAMSOCKPATH") : getenv("HOME"); 308 | 309 | if (!canlocksocket(machine)){ 310 | fputs("could not lock socket\n", stderr); 311 | return; 312 | } 313 | 314 | if (!path){ 315 | fputs("could not determine command socket path\n", stderr); 316 | return; 317 | } 318 | 319 | snprintf(exname, PATH_MAX, "%s/.sam.%s", path, machine? machine : "localhost"); 320 | 321 | if (strlen(exname) >= sizeof(un.sun_path) - 1){ 322 | fputs("command socket path too long\n", stderr); 323 | return; 324 | } 325 | 326 | un.sun_family = AF_UNIX; 327 | strncpy(un.sun_path, exname, sizeof(un.sun_path) - 1); 328 | if ((exfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 329 | || bind(exfd, (struct sockaddr *)&un, sizeof(un)) < 0 330 | || listen(exfd, 10) < 0){ 331 | perror("could not open command socket"); 332 | exfd = -1; 333 | return; 334 | } 335 | 336 | atexit(removesocket); 337 | } 338 | 339 | void 340 | startup(char *machine, bool rflag, bool trylock) 341 | { 342 | if (!rflag && trylock) 343 | opensocket(machine); 344 | 345 | if (machine) 346 | connectto(machine); 347 | 348 | if (!rflag) 349 | bootterm(machine); 350 | 351 | downloaded = true; 352 | outTs(Hversion, VERSION); 353 | } 354 | -------------------------------------------------------------------------------- /doc/samrc.5: -------------------------------------------------------------------------------- 1 | .Dd $Mdocdate$ 2 | .Dt SAMRC 5 3 | .Os 4 | .Sh NAME 5 | .Nm samrc 6 | .Nd configure samterm 7 | .Sh SYNOPSIS 8 | .Pa ~/.samrc 9 | .Sh DESCRIPTION 10 | A 11 | .Nm 12 | file in the user's home directory can be used to configure the downloaded 13 | portion of the 14 | .Xr sam 1 15 | editor 16 | .Pq "that is, samterm" "." 17 | This file, 18 | if it exists, 19 | is read at startup. 20 | .Pp 21 | Each line begins with a configuration directive and some number of arguments. 22 | Lines whose first printing character is a 23 | .Dq "#" 24 | are considered comments and are ignored. 25 | The following configuration directives are supported: 26 | .Bl -tag 27 | .It bind 28 | Bind a key sequence to a command or a raw character. 29 | The forms are: 30 | .Bd -literal 31 | 32 | bind M K command C A 33 | bind M K command C 34 | bind M K raw C 35 | 36 | .Ed 37 | Where 38 | .Em M 39 | is a string describing a set of modifier keys 40 | .Po 41 | see 42 | .Sx "Modifier Keys" 43 | below 44 | .Pc "," 45 | .Em K 46 | is the name of a keyboard symbol suitable for passing to 47 | .Xr XStringToKeysym 3 "," 48 | .Em C 49 | is either a command name 50 | .Po 51 | for command bindings; 52 | see 53 | .Sx "Command Names" 54 | below 55 | .Pc 56 | or a literal or hexadecimal specification of a character, 57 | and 58 | .Em A 59 | is an arbitrary string to use as an argument to a bound command. 60 | .Pp 61 | Note that keyboard symbol names are implementation-defined and often case-sensitive, 62 | and that not all commands will make use of arguments. 63 | .It unbind 64 | Remove all bindings associated with a key sequence. 65 | The form is: 66 | .Bd -literal 67 | 68 | unbind M K 69 | 70 | .Ed 71 | where 72 | .Em M 73 | is a string describing a set of modifier keys and 74 | .Em K 75 | is the name of a keyboard symbol, 76 | as for 77 | .Dq bind 78 | above. 79 | The key sequence may be subsequently rebound. 80 | .It chord 81 | Bind a mouse chord to a command. 82 | The form is: 83 | .Bd -literal 84 | 85 | chord S1 S2 C T 86 | 87 | .Ed 88 | where 89 | .Em S1 90 | is a string describing the initial state of the mouse buttons 91 | .Po 92 | see 93 | .Sx "Mouse Button States" 94 | below 95 | .Pc "," 96 | .Em S2 97 | is a string describing the following state of the mouse buttons, 98 | .Em C 99 | is a command name, 100 | and 101 | .Em T 102 | is a target 103 | .Po 104 | see 105 | .Sx "Targets" 106 | below 107 | .Pc "." 108 | .It unchord 109 | Remove all bindings for a given mouse chord. 110 | The form is: 111 | .Bd -literal 112 | 113 | unchord S1 S2 114 | 115 | .Ed 116 | where 117 | .Em S1 118 | and 119 | .Em S2 120 | are strings describing the initial and following mouse button states. 121 | The chord may be subsequently rebound. 122 | .It foreground 123 | Names the color used to draw text. 124 | It is of the form: 125 | .Bd -literal 126 | 127 | foreground C 128 | 129 | .Ed 130 | where 131 | .Em C 132 | is a color name suitable for passing to 133 | .Xr XAllocNamedColor 3 "." 134 | .It background 135 | Names the color used to draw the background of files being edited. 136 | It is of the form: 137 | .Bd -literal 138 | 139 | background C 140 | 141 | .Ed 142 | where 143 | .Em C 144 | is a colon-separated list of color names as for the foreground directive. 145 | If more than one color is specified, 146 | files will cycle through these background colors. 147 | .It border 148 | Names the color used to draw file borders. 149 | It is of the form: 150 | .Bd -literal 151 | 152 | border C 153 | 154 | .Ed 155 | where 156 | .Em C 157 | is a color specification as for foreground. 158 | .It font 159 | Specifies the font used to draw text. 160 | It is of the form: 161 | .Bd -literal 162 | 163 | font F 164 | 165 | .Ed 166 | where 167 | .Em F 168 | is an 169 | .Xr fc-match 1 170 | compatible font pattern. 171 | .It tabs 172 | Specifies the width of tab characters in multiples of the width of the '0' character. 173 | It is of the form: 174 | .Bd -literal 175 | 176 | tabs N 177 | 178 | .Ed 179 | where 180 | .Em N 181 | is an integer between 1 and 12. 182 | .It expandtabs 183 | Determines if tabs should be automatically expanded into spaces. 184 | It is of the form: 185 | .Bd -literal 186 | 187 | expandtabs B 188 | 189 | .Ed 190 | where 191 | .Em B 192 | is the string 193 | .Dq true 194 | or 195 | .Dq false "." 196 | If 197 | .Dq true "," 198 | then tabs will be automatically expanded. 199 | .It autoindent 200 | Determines whether a line following a non-empty indented line is automatically indented. 201 | It is of the form: 202 | .Bd -literal 203 | 204 | autoindent B 205 | 206 | .Ed 207 | where 208 | .Em B 209 | is the string 210 | .Dq true 211 | or 212 | .Dq false "." 213 | If 214 | .Dq true "," 215 | then a new line after a non-empty indented line is automatically indented. 216 | .It snarfselection 217 | Indicates which X selection should be exchanged with 218 | .Nm 219 | upon execution of the 220 | .Em exchange 221 | command 222 | .Pq "either via the menu item or key binding" "." 223 | The forms are: 224 | .Bd -literal 225 | 226 | snarfselection primary 227 | snarfselection secondary 228 | snarfselection clipboard 229 | .Ed 230 | .It followfocus 231 | Determines window focus mode. 232 | It is of the form: 233 | .Bd -literal 234 | 235 | followfocus B 236 | 237 | .Ed 238 | where 239 | .Em B 240 | is the string 241 | .Dq true 242 | or 243 | .Dq false "." 244 | If 245 | .Dq true "," 246 | then the window focus mode is set to follow the mouse pointer. 247 | In this mode typing is directed to the window currently underneath the mouse pointer. 248 | .El 249 | .Ss Defaults 250 | The default keybindings and mouse chords are those documented in 251 | .Xr sam 1 "." 252 | The default foreground and border color is black, 253 | and the default background color is white. 254 | Tabs are not expanded by default, 255 | and tabstops are set at every eight characters. 256 | The default X selection is 257 | .Do primary 258 | .Dc "." 259 | The default window focus mode is "Click to focus". Typing is directed to the window which was last clicked. 260 | .Ss "Modifier Keys" 261 | The 262 | .Em bind 263 | directive expects a string describing the state of modifier keys. 264 | This string consists of one or more of 265 | .Dq "*" 266 | meaning any set of modifiers, 267 | .Dq "a" 268 | meaning Alt 269 | .Pq Mod1 "," 270 | .Dq "c" 271 | meaning Control, or 272 | .Dq "s" 273 | meaning Shift. 274 | .Pp 275 | For example, 276 | bind the "exchange" command to 277 | .Em Control-Shift-E "," 278 | the following directive could be used: 279 | .Bd -literal 280 | 281 | bind CS e command exchange 282 | 283 | .Ed 284 | .Ss "Command Names" 285 | The following names can be used for commands: 286 | .TS 287 | c | c | c 288 | - | - | - 289 | l | l | r. 290 | Name Meaning Default Binding 291 | escape Highlight recent text Escape 292 | scrolldown Scroll down by page PgDn, Down/Right 293 | scrollup Scroll up by page PgUp, Up/Left 294 | scrolldownline Scroll down by line None 295 | scrollupline Scroll up by line None 296 | jump Jump to/from command window Control-K 297 | charright Move dot one to the right Control-D 298 | charleft Move dot one to the left Control-S 299 | lineup Move dot up Control-E 300 | linedown Move dot down Control-X 301 | delbol Delete to BOL Control-U 302 | delword Delete prev. word Control-W 303 | delbs Delete prev. character BackSpace 304 | del Delete next character Delete 305 | cut Cut selection Control-Y 306 | snarf Snarf selection Control-C 307 | paste Paste snarf buffer Control-V 308 | exchange Exchange snarf buffer Control-Q 309 | eol Move to end of line None 310 | bol Move to beginning of line None 311 | tab Insert a tab Tab 312 | send Append to command window None 313 | write Write the current file to disk None 314 | look Find next literal string None 315 | search Find next regex None 316 | .TE 317 | .Pp 318 | Additionally, 319 | the command name 320 | .Dq none 321 | means that the given binding should perform no action 322 | .Pq "not even insert a character" "," 323 | and the command name 324 | .Dq default 325 | means that the given binding should perform whatever action was previously defined for it. 326 | .Pp 327 | For the 328 | .Em send 329 | command, 330 | the text to send is specified in the argument of the binding. 331 | For example, to bind 332 | .Em Control-Z 333 | to undo the last 10 changes, the following line binding could be used: 334 | .Bd -literal 335 | 336 | bind C z command send u10 337 | 338 | .Ed 339 | Note that the 340 | .Dq send 341 | command is analagous to the 342 | .Dq send 343 | menu item: 344 | the argument text is simply appended to the text in the command window. 345 | Thus, 346 | one should exercise caution if partially-completed commands exist in the command window. 347 | .Ss "Mouse Button States" 348 | Chords are described using two states: 349 | a beginning state and an end state. 350 | When the mouse buttons are in the beginning state and then switch to being in the end state, 351 | the chord is activated. 352 | .Pp 353 | States are described using button numbers between 1 and 5, 354 | corresponding to the buttons on the mouse numbered from the left 355 | .Pq "though this is up to your windowing system and may vary" "." 356 | For example, 357 | the string 358 | .Bd -literal 359 | 360 | 12 361 | 362 | .Ed 363 | means 364 | .Dq "buttons 1 and 2 are pressed". 365 | The special string 366 | .Dq "n" 367 | means 368 | .Dq "no buttons are pressed". 369 | Thus to bind the 370 | .Em cut 371 | command to the chord 372 | .Dq "hold button one, then click button two" 373 | the following configuration directive can be used: 374 | .Bd -literal 375 | 376 | chord 1 12 cut current 377 | 378 | .Ed 379 | .Ss "Targets" 380 | Mouse chords can send their commands to either the current file 381 | .Pq "i.e. the one receiving typed input" 382 | by specifying "current" as the target; 383 | or to the file under the mouse pointer by specifying "mouse" as the target. 384 | .Ss Ordering considerations 385 | Commands are executed in the order they are present in the 386 | .Nm 387 | file. 388 | Later commands will override earlier commands, 389 | meaning that in the case of duplicate binding or chord definitions, 390 | the last one wins. 391 | .Pp 392 | Note that this means that bindings defined with the 393 | .Dq any 394 | modifier set should be defined earlier in the file than those binding the same key with modifiers, 395 | since otherwise the 396 | .Dq any 397 | binding will always win. 398 | .Sh EXAMPLES 399 | An example 400 | .Nm 401 | file is provided in the sam source distribution as 402 | .Pa doc/samrc "." 403 | .Sh SEE ALSO 404 | .Xr sam 1 405 | -------------------------------------------------------------------------------- /sam/sam.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include "errors.h" 4 | 5 | /* 6 | * BLOCKSIZE is relatively small to keep memory consumption down. 7 | */ 8 | 9 | #define BLOCKSIZE 2048 10 | #define RUNESIZE sizeof(wchar_t) 11 | #define NDISC 5 12 | #define NBUFFILES 3+2*NDISC /* plan 9+undo+snarf+NDISC*(transcript+buf) */ 13 | #define NSUBEXP 10 14 | 15 | #define INFINITY 0x7FFFFFFFL 16 | #define INCR 25 17 | #define STRSIZE (2*BLOCKSIZE) 18 | 19 | typedef int64_t Posn; /* file position or address */ 20 | typedef uint64_t Mod; /* modification number */ 21 | 22 | typedef struct Address Address; 23 | typedef struct Block Block; 24 | typedef struct Buffer Buffer; 25 | typedef struct File File; 26 | typedef struct List List; 27 | typedef struct Mark Mark; 28 | typedef struct Range Range; 29 | typedef struct Rangeset Rangeset; 30 | typedef struct String String; 31 | 32 | typedef enum 33 | { 34 | Clean = ' ', 35 | Dirty = '\'', 36 | Unread = '-', 37 | Readerr = '~' 38 | } state_t; 39 | 40 | struct Range 41 | { 42 | Posn p1, p2; 43 | }; 44 | 45 | struct Rangeset 46 | { 47 | Range p[NSUBEXP]; 48 | }; 49 | 50 | struct Address 51 | { 52 | Range r; 53 | File *f; 54 | }; 55 | 56 | struct List 57 | { 58 | int nalloc; 59 | int nused; 60 | union{ 61 | void *listp; 62 | Block *blkp; 63 | int64_t *longp; 64 | uint8_t* *uint8_tp; 65 | String* *stringp; 66 | File* *filep; 67 | int64_t listv; 68 | }g; 69 | }; 70 | 71 | #define listptr g.listp 72 | #define blkptr g.blkp 73 | #define longptr g.longp 74 | #define uint8_tpptr g.uint8_tp 75 | #define stringpptr g.stringp 76 | #define filepptr g.filep 77 | #define listval g.listv 78 | 79 | struct String 80 | { 81 | int16_t n; 82 | int16_t size; 83 | wchar_t *s; 84 | }; 85 | 86 | struct Gapbuffer; 87 | struct Buffer 88 | { 89 | Posn nrunes; 90 | struct Gapbuffer *gb; 91 | }; 92 | 93 | #define NGETC 128 94 | 95 | struct File 96 | { 97 | Buffer *buf; /* cached disc storage */ 98 | Buffer *transcript; /* what's been done */ 99 | Posn markp; /* file pointer to start of latest change */ 100 | Mod mod; /* modification stamp */ 101 | Posn nrunes; /* total length of file */ 102 | Posn hiposn; /* highest address touched this Mod */ 103 | Address dot; /* current position */ 104 | Address ndot; /* new current position after update */ 105 | Range tdot; /* what terminal thinks is current range */ 106 | Range mark; /* tagged spot in text (don't confuse with Mark) */ 107 | List *rasp; /* map of what terminal's got */ 108 | String name; /* file name */ 109 | int16_t tag; /* for communicating with terminal */ 110 | state_t state; /* Clean, Dirty, Unread, or Readerr*/ 111 | bool closeok; /* ok to close file? */ 112 | bool deleted; /* delete at completion of command */ 113 | bool marked; /* file has been Fmarked at least once; once 114 | * set, this will never go off as undo doesn't 115 | * revert to the dawn of time */ 116 | int64_t dev; /* file system from which it was read */ 117 | int64_t qid; /* file from which it was read */ 118 | int64_t date; /* time stamp of plan9 file */ 119 | Posn cp1, cp2; /* Write-behind cache positions and */ 120 | String cache; /* string */ 121 | wchar_t getcbuf[NGETC]; 122 | char mbbuf[BUFSIZ]; /* partial character during read */ 123 | size_t mblen; /* number of bytes in partial character */ 124 | mbstate_t ps; /* state of multibyte decoding */ 125 | int ngetc; 126 | int getci; 127 | Posn getcp; 128 | }; 129 | 130 | struct Mark 131 | { 132 | Posn p; 133 | Range dot; 134 | Range mark; 135 | Mod m; 136 | int16_t s1; 137 | }; 138 | 139 | /* 140 | * The precedent to any message in the transcript. 141 | * The component structures must be an integral number of Runes long. 142 | */ 143 | union Hdr 144 | { 145 | struct _csl 146 | { 147 | int16_t c; 148 | int16_t s; 149 | int64_t l; 150 | }csl; 151 | struct _cs 152 | { 153 | int16_t c; 154 | int16_t s; 155 | }cs; 156 | struct _cll 157 | { 158 | int16_t c; 159 | int64_t l; 160 | int64_t l1; 161 | }cll; 162 | Mark mark; 163 | }; 164 | 165 | #define Fgetc(f) ((--(f)->ngetc<0)? Fgetcload(f, (f)->getcp) : (f)->getcbuf[(f)->getcp++, (f)->getci++]) 166 | #define Fbgetc(f) (((f)->getci<=0)? Fbgetcload(f, (f)->getcp) : (f)->getcbuf[--(f)->getcp, --(f)->getci]) 167 | 168 | void Bterm(Buffer*); 169 | void Bdelete(Buffer*, Posn, Posn); 170 | void Bflush(Buffer*); 171 | void Binsert(Buffer*, String*, Posn); 172 | Buffer *Bopen(void); 173 | int Bread(Buffer*, wchar_t*, int, Posn); 174 | int Fbgetcload(File*, Posn); 175 | int Fbgetcset(File*, Posn); 176 | int64_t Fchars(File*, wchar_t*, Posn, Posn); 177 | void Fclose(File*); 178 | void Fdelete(File*, Posn, Posn); 179 | int Fgetcload(File*, Posn); 180 | int Fgetcset(File*, Posn); 181 | void Finsert(File*, String*, Posn); 182 | File *Fopen(void); 183 | void Fsetname(File*, String*); 184 | void Fstart(void); 185 | int Fupdate(File*, int, int); 186 | int Read(FILE *, void*, int); 187 | int plan9(File*, int, String*, int); 188 | int Write(FILE *, void*, int); 189 | int bexecute(File*, Posn); 190 | void cd(String*); 191 | void closefiles(File*, String*); 192 | void closeio(Posn); 193 | void cmdloop(void); 194 | void cmdupdate(void); 195 | void compile(String*); 196 | void copy(File*, Address); 197 | File *current(File*); 198 | void delete(File*); 199 | void delfile(File*); 200 | void dellist(List*, int); 201 | void doubleclick(File*, Posn); 202 | void dprint(wchar_t *, ...); 203 | void edit(File*, int); 204 | void *emalloc(uint64_t); 205 | void *erealloc(void*, uint64_t); 206 | void error(Err); 207 | void error_c(Err, int); 208 | void error_s(Err, char*); 209 | int execute(File*, Posn, Posn); 210 | int filematch(File*, String*); 211 | void filename(File*); 212 | void freebufs(void); 213 | void freecmd(void); 214 | void freecmdlists(void); 215 | File *getfile(String*); 216 | int getname(File*, String*, bool); 217 | int64_t getnum(void); 218 | void hiccough(char*); 219 | void inslist(List*, int, int64_t); 220 | Address lineaddr(Posn, Address, int); 221 | void listfree(List*); 222 | void load(File*); 223 | File *lookfile(String*, bool); 224 | void lookorigin(File*, Posn, Posn, int64_t); 225 | int lookup(int); 226 | void move(File*, Address); 227 | void moveto(File*, Range); 228 | File *newfile(void); 229 | void nextmatch(File*, String*, Posn, int); 230 | int newtmp(void); 231 | void panic(char*); 232 | void printposn(File*, int); 233 | void print_ss(char*, String*, String*); 234 | void print_s(char*, String*); 235 | int rcv(void); 236 | Range rdata(List*, Posn, Posn); 237 | Posn readio(File*, bool*, bool); 238 | void rescue(void); 239 | void resetcmd(void); 240 | void resetsys(void); 241 | void resetxec(void); 242 | void rgrow(List*, Posn, Posn); 243 | void samerr(char*); 244 | void settempfile(void); 245 | void scram(void); 246 | int skipbl(void); 247 | void snarf(File*, Posn, Posn, Buffer*, bool); 248 | void sortname(File*); 249 | void startup(char*, bool, bool); 250 | void state(File*, state_t); 251 | int statfd(int, uint64_t*, uint64_t*, int64_t*, int64_t*, int64_t*); 252 | int statfile(char*, uint64_t*, uint64_t*, int64_t*, int64_t*, int64_t*); 253 | void Straddc(String*, wchar_t); 254 | void Strclose(String*); 255 | int Strcmp(String*, String*); 256 | void Strdelete(String*, Posn, Posn); 257 | void Strdupl(String*, wchar_t*); 258 | void Strduplstr(String*, String*); 259 | void Strinit(String*); 260 | void Strinit0(String*); 261 | void Strinsert(String*, String*, Posn); 262 | void Strinsure(String*, uint64_t); 263 | void Strzero(String*); 264 | int Strlen(wchar_t*); 265 | char *Strtoc(String*); 266 | void syserror(char*); 267 | void telldot(File*); 268 | void tellpat(void); 269 | String *tmpcstr(char*); 270 | String *tmprstr(wchar_t*, int); 271 | void freetmpstr(String*); 272 | void termcommand(void); 273 | void termwrite(wchar_t *); 274 | File *tofile(String*); 275 | void toterminal(File*, int); 276 | void trytoclose(File*); 277 | void trytoquit(void); 278 | int undo(void); 279 | void update(void); 280 | int waitfor(int); 281 | void warn(Warn); 282 | void warn_s(Warn, char*); 283 | void warn_SS(Warn, String*, String*); 284 | void warn_S(Warn, String*); 285 | int whichmenu(File*); 286 | void writef(File*); 287 | Posn writeio(File*); 288 | void flushio(void); 289 | bool canlocksocket(const char *); 290 | 291 | extern wchar_t samname[]; /* compiler dependent */ 292 | extern wchar_t *left[]; 293 | extern wchar_t *right[]; 294 | 295 | extern char *rsamname; /* globals */ 296 | extern char *samterm; 297 | extern char *sh; 298 | extern char *shpath; 299 | extern wchar_t genbuf[]; 300 | extern char *genc; 301 | extern FILE *io; 302 | extern bool patset; 303 | extern bool quitok; 304 | extern Address addr; 305 | extern Buffer *undobuf; 306 | extern Buffer *snarfbuf; 307 | extern Buffer *plan9buf; 308 | extern List file; 309 | extern List tempfile; 310 | extern File *cmd; 311 | extern File *curfile; 312 | extern File *lastfile; 313 | extern Mod modnum; 314 | extern Posn cmdpt; 315 | extern Posn cmdptadv; 316 | extern Rangeset sel; 317 | extern String cmdstr; 318 | extern String genstr; 319 | extern String lastpat; 320 | extern String lastregexp; 321 | extern String plan9cmd; 322 | extern bool downloaded; 323 | extern bool eof; 324 | extern bool bpipeok; 325 | extern bool panicking; 326 | extern wchar_t empty[]; 327 | extern int termlocked; 328 | extern bool noflush; 329 | 330 | #include "mesg.h" 331 | 332 | void outTs(Hmesg, int); 333 | void outT0(Hmesg); 334 | void outTl(Hmesg, int64_t); 335 | void outTslS(Hmesg, int, int64_t, String*); 336 | void outTS(Hmesg, String*); 337 | void outTsS(Hmesg, int, String*); 338 | void outTsllS(Hmesg, int, int64_t, int64_t, String*); 339 | void outTsll(Hmesg, int, int64_t, int64_t); 340 | void outTsl(Hmesg, int, int64_t); 341 | void outTsv(Hmesg, int, int64_t); 342 | void outstart(Hmesg); 343 | void outcopy(int, void*); 344 | void outshort(int); 345 | void outlong(int64_t); 346 | void outsend(void); 347 | void outflush(void); 348 | -------------------------------------------------------------------------------- /samterm/flayer.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ 2 | #include 3 | #include 4 | #include 5 | #include "flayer.h" 6 | #include "samterm.h" 7 | 8 | #define DELTA 10 9 | 10 | static Flayer **llist; /* front to back */ 11 | static int nllist; 12 | static int nlalloc; 13 | static Rectangle lDrect; 14 | 15 | extern Bitmap screen; 16 | extern Mouse mouse; 17 | 18 | extern uint64_t _bgpixel; 19 | 20 | Vis visibility(Flayer *); 21 | void newvisibilities(int); 22 | void llinsert(Flayer*); 23 | void lldelete(Flayer*); 24 | 25 | void 26 | flstart(Rectangle r) 27 | { 28 | lDrect = r; 29 | } 30 | 31 | void 32 | flnew(Flayer *l, wchar_t *(*fn)(Flayer*, int64_t, uint64_t*), int u0, void *u1) 33 | { 34 | if(nllist == nlalloc){ 35 | nlalloc += DELTA; 36 | llist = realloc(llist, nlalloc*sizeof(Flayer**)); 37 | if(llist == 0) 38 | panic("flnew"); 39 | } 40 | l->textfn = fn; 41 | l->user0 = u0; 42 | l->user1 = u1; 43 | l->bg = _bgpixel; 44 | llinsert(l); 45 | } 46 | 47 | Rectangle 48 | flrect(Flayer *l, Rectangle r) 49 | { 50 | rectclip(&r, lDrect); 51 | l->entire = r; 52 | l->scroll = inset(r, FLMARGIN); 53 | r.min.x = 54 | l->scroll.max.x = r.min.x+FLMARGIN+FLSCROLLWID+(FLGAP-FLMARGIN); 55 | return r; 56 | } 57 | 58 | void 59 | flinit(Flayer *l, Rectangle r, XftFont *ft, uint64_t bg) 60 | { 61 | lldelete(l); 62 | llinsert(l); 63 | l->visible = All; 64 | l->origin = l->p0 = l->p1 = 0; 65 | frinit(&l->f, inset(flrect(l, r), FLMARGIN), ft, &screen, bg); 66 | l->bg = bg; 67 | newvisibilities(1); 68 | bitblt2(&screen, l->entire.min, &screen, l->entire, 0, 0, l->bg); 69 | scrdraw(l, 0L); 70 | flborder(l, 0); 71 | } 72 | 73 | void 74 | flclose(Flayer *l) 75 | { 76 | if(l->visible == All) 77 | bitblt2(&screen, l->entire.min, &screen, l->entire, 0, _bgpixel, _bgpixel); 78 | else if(l->visible == Some){ 79 | if(l->f.b == 0) 80 | l->f.b = balloc(l->entire, screen.ldepth); 81 | if(l->f.b){ 82 | bitblt2(l->f.b, l->entire.min, l->f.b, l->entire, 0, _bgpixel, _bgpixel); 83 | flrefresh(l, l->entire, 0); 84 | } 85 | } 86 | frclear(&l->f); 87 | lldelete(l); 88 | if(l->f.b && l->visible!=All) 89 | bfree(l->f.b); 90 | l->textfn = 0; 91 | newvisibilities(1); 92 | } 93 | 94 | void 95 | flborder(Flayer *l, bool wide) 96 | { 97 | if(flprepare(l)){ 98 | border(l->f.b, l->entire, FLMARGIN, 0, l->bg); 99 | border(l->f.b, l->entire, wide? FLMARGIN : 1, F&~D, l->bg); 100 | if(l->visible==Some) 101 | flrefresh(l, l->entire, 0); 102 | } 103 | } 104 | 105 | Flayer * 106 | flwhich(Point p) 107 | { 108 | int i; 109 | 110 | if(p.x==0 && p.y==0) 111 | return nllist? llist[0] : 0; 112 | for(i=0; ientire)) 114 | return llist[i]; 115 | return 0; 116 | } 117 | 118 | void 119 | flupfront(Flayer *l) 120 | { 121 | int v = l->visible; 122 | 123 | lldelete(l); 124 | llinsert(l); 125 | if(v!=All) 126 | newvisibilities(0); 127 | } 128 | 129 | void 130 | newvisibilities(int redraw) 131 | /* if redraw false, we know it's a flupfront, and needn't 132 | * redraw anyone becoming partially covered */ 133 | { 134 | int i; 135 | Vis ov; 136 | Flayer *l; 137 | 138 | for(i = 0; ivisible; 141 | l->visible = visibility(l); 142 | #define V(a, b) (((a)<<2)|((b))) 143 | switch(V(ov, l->visible)){ 144 | case V(Some, None): 145 | if(l->f.b) 146 | bfree(l->f.b); 147 | case V(All, None): 148 | case V(All, Some): 149 | l->f.b = 0; 150 | frclear(&l->f); 151 | break; 152 | 153 | case V(Some, Some): 154 | if(l->f.b==0 && redraw) 155 | case V(None, Some): 156 | flprepare(l); 157 | if(l->f.b && redraw){ 158 | flrefresh(l, l->entire, 0); 159 | bfree(l->f.b); 160 | l->f.b = 0; 161 | frclear(&l->f); 162 | } 163 | case V(None, None): 164 | case V(All, All): 165 | break; 166 | 167 | case V(Some, All): 168 | if(l->f.b){ 169 | bitblt2(&screen, l->entire.min, l->f.b, l->entire, S, 0, l->bg); 170 | bfree(l->f.b); 171 | l->f.b = &screen; 172 | break; 173 | } 174 | case V(None, All): 175 | flprepare(l); 176 | break; 177 | } 178 | if(ov==None && l->visible!=None) 179 | flnewlyvisible(l); 180 | } 181 | } 182 | 183 | void 184 | llinsert(Flayer *l) 185 | { 186 | int i; 187 | for(i=nllist; i>0; --i) 188 | llist[i]=llist[i-1]; 189 | llist[0]=l; 190 | nllist++; 191 | } 192 | 193 | void 194 | lldelete(Flayer *l) 195 | { 196 | int i; 197 | 198 | for(i=0; if, sp, ep, p0-l->origin); 213 | scrdraw(l, scrtotal(l)); 214 | if(l->visible==Some) 215 | flrefresh(l, l->entire, 0); 216 | } 217 | } 218 | 219 | void 220 | fldelete(Flayer *l, int64_t p0, int64_t p1) 221 | { 222 | if(flprepare(l)){ 223 | p0 -= l->origin; 224 | if(p0 < 0) 225 | p0 = 0; 226 | p1 -= l->origin; 227 | if(p1<0) 228 | p1 = 0; 229 | frdelete(&l->f, p0, p1); 230 | scrdraw(l, scrtotal(l)); 231 | if(l->visible==Some) 232 | flrefresh(l, l->entire, 0); 233 | } 234 | } 235 | 236 | bool 237 | flselect(Flayer *l) 238 | { 239 | if(l->visible!=All) 240 | flupfront(l); 241 | if(mouse.msec-l->clickf.p0 == l->f.p1 && l->f.p0 == frcharofpt(&l->f, mouse.xy))) { 242 | l->click = 0; 243 | return true; 244 | } 245 | frselect(&l->f, &mouse); 246 | if(l->f.p0==l->f.p1) 247 | l->click = mouse.msec; 248 | else 249 | l->click = 0; 250 | l->p0 = l->f.p0+l->origin, l->p1 = l->f.p1+l->origin; 251 | return false; 252 | } 253 | 254 | void 255 | flsetselect(Flayer *l, int64_t p0, int64_t p1) 256 | { 257 | uint64_t fp0, fp1; 258 | 259 | l->click = 0; 260 | if(l->visible==None || !flprepare(l)){ 261 | l->p0 = p0, l->p1 = p1; 262 | return; 263 | } 264 | l->p0 = p0, l->p1 = p1; 265 | flfp0p1(l, &fp0, &fp1); 266 | if(fp0==l->f.p0 && fp1==l->f.p1) 267 | return; 268 | frselectp(&l->f, F&~D); 269 | l->f.p0 = fp0, l->f.p1 = fp1; 270 | frselectp(&l->f, F&~D); 271 | if(l->visible==Some) 272 | flrefresh(l, l->entire, 0); 273 | } 274 | 275 | void 276 | flfp0p1(Flayer *l, uint64_t *pp0, uint64_t *pp1) 277 | { 278 | int64_t p0 = l->p0-l->origin, p1 = l->p1-l->origin; 279 | 280 | if(p0 < 0) 281 | p0 = 0; 282 | if(p1 < 0) 283 | p1 = 0; 284 | if(p0 > l->f.nchars) 285 | p0 = l->f.nchars; 286 | if(p1 > l->f.nchars) 287 | p1 = l->f.nchars; 288 | *pp0 = p0; 289 | *pp1 = p1; 290 | } 291 | 292 | Rectangle 293 | rscale(Rectangle r, Point old, Point new) 294 | { 295 | r.min.x = r.min.x*new.x/old.x; 296 | r.min.y = r.min.y*new.y/old.y; 297 | r.max.x = r.max.x*new.x/old.x; 298 | r.max.y = r.max.y*new.y/old.y; 299 | return r; 300 | } 301 | 302 | void 303 | flreshape(Rectangle dr) 304 | { 305 | int i; 306 | Flayer *l; 307 | Frame *f; 308 | Rectangle r, olDrect; 309 | int move; 310 | 311 | olDrect = lDrect; 312 | lDrect = dr; 313 | move = 0; 314 | bitblt2(&screen, lDrect.min, &screen, lDrect, 0, 0, _bgpixel); 315 | 316 | for(i=0; if; 319 | if(move) 320 | r = raddp(rsubp(l->entire, olDrect.min), dr.min); 321 | else{ 322 | r = raddp(rscale(rsubp(l->entire, olDrect.min), 323 | sub(olDrect.max, olDrect.min), 324 | sub(dr.max, dr.min)), dr.min); 325 | if(l->visible==Some && f->b){ 326 | bfree(f->b); 327 | frclear(f); 328 | } 329 | f->b = 0; 330 | if(l->visible!=None) 331 | frclear(f); 332 | } 333 | if(!rectclip(&r, dr)) 334 | panic("flreshape"); 335 | if(r.max.x-r.min.x<100) 336 | r.min.x = dr.min.x; 337 | if(r.max.x-r.min.x<100) 338 | r.max.x = dr.max.x; 339 | if(r.max.y-r.min.y<2*FLMARGIN+f->fheight) 340 | r.min.y = dr.min.y; 341 | if(r.max.y-r.min.y<2*FLMARGIN+f->fheight) 342 | r.max.y = dr.max.y; 343 | if(!move) 344 | l->visible = None; 345 | frsetrects(f, inset(flrect(l, r), FLMARGIN), f->b); 346 | if(!move && f->b) 347 | scrdraw(l, scrtotal(l)); 348 | } 349 | newvisibilities(1); 350 | } 351 | 352 | int 353 | flprepare(Flayer *l) 354 | { 355 | Frame *f; 356 | uint64_t n; 357 | wchar_t *r; 358 | 359 | if(l->visible == None) 360 | return 0; 361 | f = &l->f; 362 | if(f->b == 0){ 363 | if(l->visible == All) 364 | f->b = &screen; 365 | else if((f->b = balloc(l->entire, screen.ldepth))==0) 366 | return 0; 367 | bitblt2(f->b, l->entire.min, f->b, l->entire, 0, 0, l->bg); 368 | border(f->b, l->entire, l==llist[0]? FLMARGIN : 1, F&~D, l->bg); 369 | n = f->nchars; 370 | frinit(f, f->entire, f->font, f->b, l->bg); 371 | r = (*l->textfn)(l, n, &n); 372 | frinsert(f, r, r+n, (uint64_t)0); 373 | frselectp(f, F&~D); 374 | flfp0p1(l, &l->f.p0, &l->f.p1); 375 | frselectp(f, F&~D); 376 | scrdraw(l, scrtotal(l)); 377 | } 378 | return 1; 379 | } 380 | 381 | static bool somevis, someinvis, justvis; 382 | 383 | Vis 384 | visibility(Flayer *l) 385 | { 386 | somevis = someinvis = false; 387 | justvis = true; 388 | flrefresh(l, l->entire, 0); 389 | justvis = false; 390 | if(!somevis) 391 | return None; 392 | if(!someinvis) 393 | return All; 394 | return Some; 395 | } 396 | 397 | void 398 | flrefresh(Flayer *l, Rectangle r, int i) 399 | { 400 | Flayer *t; 401 | Rectangle s; 402 | 403 | Top: 404 | if((t=llist[i++]) == l){ 405 | if(!justvis) 406 | bitblt2(&screen, r.min, l->f.b, r, S, 0, l->bg); 407 | somevis = true; 408 | }else{ 409 | if(!rectXrect(t->entire, r)) 410 | goto Top; /* avoid stacking unnecessarily */ 411 | if(t->entire.min.x>r.min.x){ 412 | s = r; 413 | s.max.x = t->entire.min.x; 414 | flrefresh(l, s, i); 415 | r.min.x = t->entire.min.x; 416 | } 417 | if(t->entire.min.y>r.min.y){ 418 | s = r; 419 | s.max.y = t->entire.min.y; 420 | flrefresh(l, s, i); 421 | r.min.y = t->entire.min.y; 422 | } 423 | if(t->entire.max.xentire.max.x; 426 | flrefresh(l, s, i); 427 | r.max.x = t->entire.max.x; 428 | } 429 | if(t->entire.max.yentire.max.y; 432 | flrefresh(l, s, i); 433 | r.max.y = t->entire.max.y; 434 | } 435 | /* remaining piece of r is blocked by t; forget about it */ 436 | someinvis = true; 437 | } 438 | } 439 | --------------------------------------------------------------------------------