levee: A very small vi editor
authorAlan Cox <alan@linux.intel.com>
Sat, 3 Jan 2015 00:18:41 +0000 (00:18 +0000)
committerAlan Cox <alan@linux.intel.com>
Sat, 3 Jan 2015 00:18:41 +0000 (00:18 +0000)
Still a bit large but with some clean up and tweaking ought to be ok on bigger
boxes, if a bit tight on a 48K bank.

31 files changed:
Applications/levee/Makefile [new file with mode: 0644]
Applications/levee/beep.c [new file with mode: 0644]
Applications/levee/blockio.c [new file with mode: 0644]
Applications/levee/display.c [new file with mode: 0644]
Applications/levee/doscall.c [new file with mode: 0644]
Applications/levee/editcor.c [new file with mode: 0644]
Applications/levee/exec.c [new file with mode: 0644]
Applications/levee/extern.h [new file with mode: 0644]
Applications/levee/find.c [new file with mode: 0644]
Applications/levee/flexcall.c [new file with mode: 0644]
Applications/levee/gemcall.c [new file with mode: 0644]
Applications/levee/globals.c [new file with mode: 0644]
Applications/levee/grep.h [new file with mode: 0644]
Applications/levee/insert.c [new file with mode: 0644]
Applications/levee/levee [new file with mode: 0644]
Applications/levee/levee.bin [new file with mode: 0644]
Applications/levee/levee.h [new file with mode: 0644]
Applications/levee/lv.doc [new file with mode: 0644]
Applications/levee/main.c [new file with mode: 0644]
Applications/levee/misc.c [new file with mode: 0644]
Applications/levee/modify.c [new file with mode: 0644]
Applications/levee/move.c [new file with mode: 0644]
Applications/levee/proto.h [new file with mode: 0644]
Applications/levee/readme.os2 [new file with mode: 0644]
Applications/levee/rmxcall.c [new file with mode: 0644]
Applications/levee/tc [new file with mode: 0644]
Applications/levee/termcap.i [new file with mode: 0644]
Applications/levee/ucsd.c [new file with mode: 0644]
Applications/levee/undo.c [new file with mode: 0644]
Applications/levee/unixcall.c [new file with mode: 0644]
Applications/levee/wildargs.c [new file with mode: 0644]

diff --git a/Applications/levee/Makefile b/Applications/levee/Makefile
new file mode 100644 (file)
index 0000000..246658b
--- /dev/null
@@ -0,0 +1,16 @@
+CSRCS = beep.c blockio.c display.c doscall.c editcor.c exec.c find.c
+CSRCS += flexcall.c gemcall.c globals.c insert.c main.c misc.c modify.c
+CSRCS += move.c rmxcall.c ucsd.c undo.c unixcall.c wildargs.c
+
+OBJS = $(SRCS,.c=.rel)
+
+levee: $(OBJS)
+       fcc -o levee $(OBJS)
+
+$(OBJS): $(SRCS)
+
+.c.rel:
+       fcc -Os -c $(@:.rel=.c)
+
+clean:
+       rm -rf $(OBJS) *.lst *.sym *.map *.noi *.lk *.ihx *.tmp *~ *.rel *.asm
diff --git a/Applications/levee/beep.c b/Applications/levee/beep.c
new file mode 100644 (file)
index 0000000..9083f65
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+
+#if ST
+#include <atari\osbind.h>
+
+char sound[] = {
+       0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00,
+       0xF8,0x10,0x10,0x10,0x00,0x20,0x03
+};
+
+#define SADDR  0xFF8800L
+
+typedef char srdef[4];
+
+srdef *SOUND = (srdef *)SADDR;
+
+main()
+{
+    register i;
+    long ssp;
+
+    ssp = Super(0L);
+    for (i=0; i<sizeof(sound); i++) {
+       (*SOUND)[0] = i;
+       (*SOUND)[2] = sound[i];
+    }
+    Super(ssp);
+}
+#endif /*ST*/
diff --git a/Applications/levee/blockio.c b/Applications/levee/blockio.c
new file mode 100644 (file)
index 0000000..f4bc3f6
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+#include <stdio.h>
+#include <unistd.h>
+/* read in a file -- return TRUE -- read file
+                           FALSE-- file too big
+*/
+
+int PROC addfile(FILE *f, int start, int endd, int *size)
+{
+    register int chunk;
+
+    chunk = read(fileno(f), core+start, (endd-start)-1);
+
+    *size = chunk;
+    return chunk < (endd-start)-1;
+}
+
+
+/* write out a file -- return TRUE if ok. */
+
+bool PROC putfile(FILE *f, int start, int endd)
+{
+    write(fileno(f), core+start, endd-start);
+}
diff --git a/Applications/levee/display.c b/Applications/levee/display.c
new file mode 100644 (file)
index 0000000..cdede2a
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+
+#include <string.h>
+#include <unistd.h>
+/* do a gotoXY -- allowing -1 for same row/column */
+
+#if TERMCAP | ST
+
+#define MAXCOLS 160
+
+#if TERMCAP
+#include "termcap.i"
+#endif
+
+#else /*!(TERMCAP | ST)*/
+
+#define MAXCOLS COLS
+
+#endif
+
+PROC
+mvcur(int y, int x)
+{
+    static char gt[30];
+   
+    if (y == -1)
+       y = curpos.y;
+    else
+       curpos.y = y;
+    if (y >= LINES)
+       y = LINES-1;
+    if (x == -1)
+       x = curpos.x;
+    else
+       curpos.x = x;
+    if (x >= COLS)
+       x = COLS-1;
+
+#if ZTERM
+    zgoto(x,y);
+#endif
+
+#if ANSI
+    {  register char *p = gt;          /* make a ansi gotoXY string */
+       *p++ = 033;
+       *p++ = '[';
+       numtoa(p,1+y); p += strlen(p);
+       *p++ = ';';
+       numtoa(p,1+x); p += strlen(p);
+       *p++ = 'H';
+       WRITE_TEXT(1, gt, (p-gt));
+    }
+#endif
+
+#if VT52
+    CM[2] = y+32;
+    CM[3] = x+32;
+    strput(CM);
+#endif
+
+#if TERMCAP
+    tgoto(gt,y,x);
+    strput(gt);
+#endif
+}
+
+PROC numtoa(char *str, int num)
+{
+    int i = 10;                        /* I sure hope that str is 10 bytes long... */
+    bool neg = (num < 0);
+
+    if (neg)
+       num = -num;
+
+    str[--i] = 0;
+    do{
+       str[--i] = (num%10)+'0';
+       num /= 10;
+    }while (num > 0);
+    if (neg)
+       str[--i] = '-';
+    moveleft(&str[i], str, 10-i);
+}
+
+PROC
+printi(int num)
+{
+    char nb[10];
+    register int size;
+    
+    numtoa(nb,num);
+    size = min(strlen(nb),COLS-curpos.x);
+    if (size > 0) {
+       zwrite(nb, size);
+       curpos.x += size;
+    }
+}
+
+PROC
+println(void)
+{
+    strput("\n\r");
+    curpos.x = 0;
+    curpos.y = min(curpos.y+1, LINES-1);
+}
+
+/* print a character out in a readable form --
+ *    ^<x> for control-<x>
+ *    spaces for <tab>
+ *    normal for everything else
+ */
+
+static char hexdig[] = "0123456789ABCDEF";
+
+int PROC
+format(char *out, unsigned c)
+/* format: put a displayable version of c into out */
+{
+    if (c >= ' ' && c < '\7f') {
+       out[0] = c;
+       return 1;
+    }
+    else if (c == '\t' && !list) {
+       register int i;
+       int size;
+
+       for (i = size = tabsize - (curpos.x % tabsize);i > 0;)
+           out[--i] = ' ';
+       return size;
+    }
+    else if (c < 128) {
+       out[0] = '^';
+       out[1] = c^64;
+       return 2;
+    }
+    else {
+#if MSDOS
+       out[0] = c;
+       return 1;
+#else
+       out[0] = '\\';
+       out[1] = hexdig[(c>>4)&017];
+       out[2] = hexdig[c&017];
+       return 3;
+#endif
+    }
+}
+
+PROC
+printch(char c)
+{
+    register int size;
+    char buf[MAXCOLS];
+
+    size = min(format(buf,c),COLS-curpos.x);
+    if (size > 0) {
+       zwrite(buf, size);
+       curpos.x += size;
+    }
+}
+
+PROC
+prints(char *s)
+{
+    int size,oxp = curpos.x;
+    char buf[MAXCOLS+1];
+    register bi = 0;
+
+    while (*s && curpos.x < COLS) {
+       size = format(&buf[bi],*s++);
+       bi += size;
+       curpos.x += size;
+    }
+    size = min(bi,COLS-oxp);
+    if (size > 0)
+       zwrite(buf, size);
+}
+
+PROC
+writeline(int y,int x,int start)
+{
+    int endd,oxp;
+    register size;
+    char buf[MAXCOLS+1];
+    register bi = 0;
+    
+    endd = fseekeol(start);
+    if (start==0 || core[start-1] == EOL)
+       mvcur(y, 0);
+    else
+       mvcur(y, x);
+    oxp = curpos.x;
+
+    while (start < endd && curpos.x < COLS) {
+       size = format(&buf[bi],core[start++]);
+       bi += size;
+       curpos.x += size;
+    }
+    if (list) {
+       buf[bi++] = '$';
+       curpos.x++;
+    }
+    size = min(bi,COLS-oxp);
+    if (size > 0) {
+       zwrite(buf, size);
+    }
+    if (curpos.x < COLS)
+       strput(CE);
+}
+
+/* redraw && refresh the screen */
+
+PROC
+refresh(int y,int x,int start,int endd, bool rest)
+{
+    int sp;
+    
+#if ST
+    /* turn the cursor off */
+    asm(" clr.l  -(sp)     ");
+    asm(" move.w #21,-(sp) ");
+    asm(" trap   #14       ");
+    asm(" addq.l #6,sp     ");
+#endif
+    sp = start;
+    while (sp <= endd) {
+       writeline(y, x, sp);
+       sp = 1+fseekeol(sp);
+       y++;
+       x = 0;
+    }
+    if (rest && sp >= bufmax)
+       while (y<LINES-1) { /* fill screen with ~ */
+           mvcur(y, 0);
+           printch('~'); strput(CE);
+           y++;
+       }
+#if ST
+    /* turn the cursor back on */
+    asm(" clr.w  -(sp)     ");
+    asm(" move.w #1,-(sp)  ");
+    asm(" move.w #21,-(sp) ");
+    asm(" trap   #14       ");
+    asm(" addq.l #6,sp     ");
+#endif
+}
+
+/* redraw everything */
+
+PROC
+redisplay(bool flag)
+{
+    if (flag)
+       clrprompt();
+    refresh(0, 0, ptop, pend, TRUE);
+}
+    
+PROC
+scrollback(int curr)
+{
+    mvcur(0,0);                /* move to the top line */
+    do {
+       ptop = bseekeol(ptop-1);
+       strput(UpS);
+       writeline(0, 0, ptop);
+    } while (ptop > curr);
+    setend();
+}
+
+PROC
+scrollforward(int curr)
+{
+    do {
+       writeline(LINES-1, 0, pend+1);
+       strput("\n");
+       pend = fseekeol(pend+1);
+       ptop = fseekeol(ptop)+1;
+    } while (pend < curr);
+}
+
+/* find if the number of lines between top && bottom is less than dofscroll */
+
+bool PROC
+ok_to_scroll(int top, int bottom)
+{
+    int nl, i;
+    
+    nl = dofscroll;
+    i = top;
+    do
+       i += 1+scan(bufmax-i,'=',EOL, &core[i]);
+    while (--nl > 0 && i < bottom);
+    return(nl>0);
+}
+
+PROC
+clrprompt(void)
+{
+    mvcur(LINES-1,0);
+    strput(CE);
+}
+
+PROC
+prompt(bool toot, char *s)
+{
+    if (toot)
+       error();
+    clrprompt();
+    prints(s);
+}
diff --git a/Applications/levee/doscall.c b/Applications/levee/doscall.c
new file mode 100644 (file)
index 0000000..e65e5e4
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * dos interface for levee (Microsoft C)
+ */
+#include "levee.h"
+
+#if MSDOS
+#include <glob.h>
+#include <dos.h>
+
+int PROC
+min(a,b)
+int a,b;
+{
+    return (a>b) ? b : a;
+}
+
+int PROC
+max(a,b)
+int a,b;
+{
+    return (a<b) ? b : a;
+}
+
+PROC
+strput(s)
+char *s;
+{
+    write(1, s, strlen(s));
+}
+
+/* get a key, mapping certain control sequences
+ */
+PROC
+getKey()
+{
+    register c;
+    extern char _far crawcin();
+
+    c = crawcin();
+
+    if (c == 0 || c == 0xe0)
+       switch (c=crawcin()) {
+       case 'K': return LTARROW;
+       case 'M': return RTARROW;
+       case 'H': return UPARROW;
+       case 'P': return DNARROW;
+       case 'I': return 'U'-'@';       /* page-up */
+       case 'Q': return 'D'-'@';       /* page-down */
+       default : return 0;
+       }
+    return c;
+}
+
+
+/* don't allow interruptions to happen
+ */
+PROC
+nointr()
+{
+    extern void _cdecl _interrupt _far ignore_ctrlc();
+    _dos_setvect(0x23, ignore_ctrlc);
+} /* nointr */
+
+
+/* have ^C do what it usually does
+ */
+PROC
+allowintr()
+{
+    extern void _cdecl _interrupt _far intr_on_ctrlc();
+    _dos_setvect(0x23, intr_on_ctrlc);
+} /* allowintr */
+
+
+/*
+ * basename() returns the filename part of a pathname
+ */
+char *
+basename(s)
+register char *s;
+{
+    register char *p = s;
+    
+    for (p = s+strlen(s); p > s; --p)
+       if (p[-1] == '/' || p[-1] == '\\' || p[-1] == ':')
+           return p;
+    return s;
+} /* basename */
+
+
+/*
+ * glob() expands a wildcard, via calls to _dos_findfirst/_next()
+ * and pathname retention.
+ */
+char *
+glob(path, dta)
+char *path;
+struct glob_t *dta;
+{
+    static char path_bfr[256];         /* full pathname to return */
+    static char *file_part;            /* points at file - for filling */
+    static char isdotpattern;          /* looking for files starting with . */
+    static char isdotordotdot;         /* special case . or .. */
+    static struct glob_t *dta_bfr;     /* pointer to desired dta */
+    static struct find_t dird;         /* DOS dta */
+
+    register st;                       /* status from _dos_findxxx */
+
+    if (path) {
+       /* when we start searching, save the path part of the filename in
+        * a safe place.
+        */
+       strcpy(path_bfr, path);
+       file_part = basename(path_bfr);
+
+       /* set up initial parameters for DosFindFirst()
+        */
+       dta_bfr = dta;
+       
+       if (isdotpattern = (*file_part == '.'))
+           /* _dos_findfirst() magically expands . and .. into their
+            * directory names.  Admittedly, there are cases where
+            * this can be useful, but this is not one of them. So,
+            * if we find that we're matching . and .., we just
+            * special-case ourselves into oblivion to get around
+            * this particular bit of DOS silliness.
+            */
+           isdotordotdot = (file_part[1] == 0 || file_part[1] == '.');
+       else
+           isdotordotdot = 0;
+
+       st = _dos_findfirst(path, 0x16, &dird);
+    }
+    else
+       st = _dos_findnext(&dird);
+
+    while (st == 0) {
+       /* Unless the pattern has a leading ., don't include any file
+        * that starts with .
+        */
+       if (dird.name[0] == '.' && !isdotpattern)
+           st = _dos_findnext(&dird);
+       else {
+           /* found a file - affix the path leading to it, then return
+            * a pointer to the (static) buffer holding the path+the name.
+            */
+           strlwr(dird.name);          /* DOS & OS/2 are case-insensitive */
+
+           if (dta_bfr) {
+               dta_bfr->wr_time = dird.wr_time;
+               dta_bfr->wr_date = dird.wr_date;
+               if (isdotordotdot)
+                   strcpy(dta_bfr->name, file_part);
+               else {
+                   strncpy(dta_bfr->name, dird.name, sizeof(dta_bfr->name)-1);
+                   dta_bfr->name[sizeof(dta_bfr->name)-1] = 0;
+               }
+               dta_bfr->size   = dird.size;
+               dta_bfr->attrib = dird.attrib;
+           }
+           if (!isdotordotdot)
+               strcpy(file_part, dird.name);
+           return path_bfr;
+       }
+    }
+    /* nothing matched
+     */
+    if (path && isdotordotdot) {
+       /* must be at root, so statting dot will most likely fail.  Fake a
+        * dta.
+        */
+       if (dta_bfr) {
+           memset(dta_bfr, 0, sizeof *dta_bfr);
+           dta_bfr->attrib = 0x10;
+           dta_bfr->name[0] = '.';
+       }
+       return path_bfr;
+    }
+    return (char*)0;
+} /* glob */
+#endif /*MSDOS*/
diff --git a/Applications/levee/editcor.c b/Applications/levee/editcor.c
new file mode 100644 (file)
index 0000000..d692fb0
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+
+#include <string.h>
+#include <ctype.h>    
+/* do some undoable modification */
+
+/* These variables make docommand nonrecursive */
+
+bool   ok;
+int    newend,         /* end position after change */
+       disp,           /* start redisplay here */
+       newc,           /* new cursor position for wierd cmds */
+       endY;           /* final yp for endp */
+
+/* move a line of text right || left */
+
+PROC
+adjuster(bool sleft, int endd, int sw)
+{
+    bool noerror;
+    int np, ts,
+       ip,
+       ss, adjp,
+       DLEnum;
+
+    if (sw == -1)
+       sw = shiftwidth;
+    if (sleft)
+       sw = -sw;
+    curr = bseekeol(curr);
+    ip = curr;
+    noerror = TRUE;
+    do {
+       DLEnum = sw + findDLE(ip, &np, bufmax,0);
+       if (DLEnum >= 0 && DLEnum <= COLS && core[np] != EOL && np < bufmax) {
+           ts = DLEnum / tabsize;
+           ss = DLEnum % tabsize;
+           adjp = ts+ss+ip;
+           if (np-adjp < 0) {  /* expand the buf */
+               moveright(&core[np], &core[adjp], bufmax-np);
+               insert_to_undo(&undo, adjp, adjp - np);
+           }
+           else
+               delete_to_undo(&undo, adjp, np - adjp);
+
+           endd += (adjp-np);
+           noerror = move_to_undo(&undo, ip, ts+ss);
+           fillchar(&core[ip], ts, TAB);
+           fillchar(&core[ip+ts], ss, 32);
+       }
+       else if (np > ip) {     /* remove the indent code */
+           noerror = delete_to_undo(&undo, ip, np-ip);
+           endd += (ip - np);
+       }
+       ip = 1 + fseekeol(ip);
+    } while (noerror && ip < endd);
+    if (!noerror)
+       error();
+    newc = skipws(curr);
+    disp = curr;
+    newend = endd;
+    endY = setY(min(newend, pend));
+}
+
+/* join <count> lines together */
+
+PROC
+join(int count)
+{
+    bool ok;
+    int lp, first;
+    
+    if (lend < bufmax) {       /* are we in the buffer? */
+       disp = lend;                            /* start redraw here */
+       newc = lend;
+       do {                                    /* join until.. */
+           first = lend;
+           lp = skipws(1+first);
+           ok = delete_to_undo(&undo, 1+first, lp-(1+first));
+           if (ok) {
+               ok = move_to_undo(&undo, first, 1);
+               core[first] = ' ';              /* spaces between lines */
+           }
+           count--;
+           lend = fseekeol(first);
+       } while (ok && count > 0);
+       endY = MAGICNUMBER;
+       newend = lend;
+       if (!ok)
+           error();
+    }
+    else
+       error();
+}
+
+PROC
+squiggle(int endp, char c, bool dorepl)
+{
+    int i;
+    
+    if (endp >= curr) {
+       ok = move_to_undo(&undo,curr,endp-curr+1);
+       if (ok) {
+           for (i = curr;i<=endp;i++) {
+               if (!dorepl) {          /* squiggle it to uc - lc */
+                   if (core[i] >='A' && core[i] <='Z')
+                       core[i] += 32;
+                   else if (core[i]>='a' && core[i]<='z')
+                       core[i] -= 32;
+               }
+               else
+                   core[i] = c;
+           }
+           newend = min(endp+1,lend);
+       }
+    }
+}
+
+PROC
+bigreplace(void)
+{
+    int len, tsiz;
+    
+    tsiz = lend-curr;
+    if (move_to_undo(&undo, curr, tsiz))
+       if (SIZE - bufmax > tsiz) {     /* enough room for temp copy? */
+           moveleft(&core[curr], &core[bufmax],lend-curr);
+           if (line(core, curr, lend, &len) != ESC)
+               error();
+           newend = curr+len;
+           moveright(&core[bufmax+len], &core[newend], lend-newend);
+       }
+}
+
+bool PROC
+put(bool before)
+{
+    endY = setY(curr);
+    if (!before)
+       if (yank.lines)
+           curr = min(lend+1,bufmax);
+       else
+           curr = min(curr+1, lend);
+    else if (yank.lines)
+       curr = lstart;
+    newc = disp = curr;
+    return(putback(curr, &newend));
+}
+
+PROC
+gcount(void)
+{
+    count = 0;
+    while (count>=0 && ch >= '0' && ch <='9') {
+       count = (count*10) + (ch-'0');
+       readchar();             /* get a char to replace the one we dumped */
+    }
+}
+
+PROC
+docommand(cmdtype cmd)
+{
+    cmdtype movecmd;   /* movement command for y, d, c */
+    char    cmdch;
+    int     oldc;      /* old count */
+    int     endp;      /* end position before change */
+    extern bool s_wrapped;
+
+    resetX();                          /* un-derange the cursor */
+    oldc = newc = -1;
+    endY = yp;
+    newend = disp = curr;
+    ok = TRUE;                         /* so far everything is working */
+    cmdch = ch;
+    if (cmd != UNDO_C && cmd != YANK_C) {
+       if (macro<0)
+           zerostack(&undo);
+       if (redoing != TRUE) {
+           rcp = rcb;          /* point at start of redo buffer */
+           if (count > 1) {    /* put in a count? */
+               numtoa(rcb,count);
+               rcp += strlen(rcb);
+           }
+           *rcp++ = cmdch;     /* the command char goes in... */
+           xerox = TRUE;       /* hoist the magical flags */
+       }
+    }
+
+    if (cmd <= YANK_C) {
+       readchar();
+       if (ch >= '0' && ch <= '9') {
+           oldc = count;
+           gcount();                           /* get a new count */
+           if (cmd == ADJUST_C)                /* special for >>,<< wierdness */
+               swap(&count, &oldc);            /* reverse sw & count */
+           else
+               count = count*max(oldc,1);      /* combine them */
+       }
+       if (ch == cmdch) {              /* diddle lines */
+           yank.lines = TRUE;
+           endp = nextline(TRUE, curr, count);
+           curr = bseekeol(curr);
+           disp = curr;
+       }
+       else {                          /* diddle 'things' */
+           yank.lines = FALSE;
+           movecmd = movemap[ch];
+
+           if (ok = (findCP(curr,&endp,movecmd) == LEGALMOVE)) {
+               if (curr > endp) {
+                   swap(&curr,&endp);
+                   ok = (cmd != CHANGE_C);
+               }
+               if (adjcurr[movecmd])
+                   curr++;
+               if (adjendp[movecmd])
+                   endp++;
+           }
+           if (!ok) {
+               if (ch != ESC)
+                   error();
+               goto killredo;
+           }
+       }
+       
+       endY = setY(endp);
+       newend = curr;
+       disp = curr;
+       switch (cmd) {
+           case DELETE_C:
+               ok = deletion(curr, endp);
+               break;
+           case ADJUST_C:
+               adjuster((cmdch == '<'), endp-1, oldc);
+               break;
+           case CHANGE_C:
+               if (endp <= pend+1) {
+                   mvcur(setY(endp-1), setX(endp-1));
+                   printch('$');
+                   mvcur(yp, xp);
+               }
+               if (deletion(curr, endp))
+                   ok = ((newend = insertion(1, 0, &disp, &endY, TRUE)) >= 0);
+               else
+                   ok = FALSE;
+               break;
+           case YANK_C:
+               if (!doyank(curr, endp))
+                   error();
+               return 0;       /* xerox will not be true, nor will redoing */
+       }
+
+    }
+    else {
+       endp = curr;
+       endY = yp;
+
+       switch (cmd) {
+           case I_AT_NONWHITE:
+           case A_AT_END:
+           case APPEND_C:
+           case INSERT_C:              /* variations on insert */
+               if (cmd != INSERT_C) {
+                   if (cmd == APPEND_C)
+                       curr = min(curr+1, lend);
+                   else if (cmd == A_AT_END)
+                       curr = lend;
+                   else /* if (cmd == I_AT_NONWHITE) */
+                       curr = skipws(lstart);
+                   xp = setX(curr);
+                   mvcur(yp,xp);
+               }
+               newend = insertion(count, 0, &disp, &endY, TRUE);
+               ok = (newend >= 0);
+               break;
+           case OPEN_C:
+           case OPENUP_C:
+               newend = insertion(1,setstep[ (cmd==OPENUP_C)&1 ],
+                                               &disp,&endY,TRUE)-1;
+               ok = (newend >= 0);
+               break;
+           case REPLACE_C:
+           case TWIDDLE_C:
+               if (cmd == REPLACE_C) {
+                   if ((cmdch = readchar()) == ESC)
+                       goto killredo;
+               }
+               if (findCP(curr, &endp, GO_RIGHT) == LEGALMOVE)
+                   squiggle(endp-1, cmdch, (cmd==REPLACE_C));
+               break;
+           case PUT_BEFORE:
+           case PUT_AFTER:
+               ok = put(cmd==PUT_AFTER);
+               break;
+           case BIG_REPL_C:
+               bigreplace();
+               break;
+           case RESUBST_C:
+               ok = FALSE;
+               if (dst[0] != 0) {
+                   newend = chop(curr, &lend, TRUE, &ok);
+                   if (newend >= 0) {
+                       endY = setY(newend+strlen(dst));
+                       ok = TRUE;
+                   }
+               }
+               break;
+           case JOIN_C:
+               join(count);            /* join lines */
+               break;
+           case UNDO_C:                        /* undo last modification */
+               ok = fixcore(&newend) >= 0;
+               disp = newend;
+               endY = MAGICNUMBER;
+               break;
+       }
+    }
+
+    if (ok) {
+       setpos((newc<0)?newend:newc);
+       setend();
+       if (curr < ptop || curr > pend) {
+           yp = settop(12);
+           redisplay(TRUE);
+       }
+       else {
+           yp = setY(curr);
+           if (endY != setY(newend))   /* shuffled lines */
+               refresh(setY(disp), setX(disp), disp, pend, TRUE);
+           else                        /* refresh to end position */
+               refresh(setY(disp), setX(disp), disp, newend, FALSE);
+       }
+       if (curr >= bufmax && bufmax > 0) {     /* adjust off end of buffer */
+           setpos(bufmax-1);
+           yp = setY(curr);
+       }
+       if (s_wrapped) {
+           prompt(FALSE, "search wrapped around end of buffer");
+           s_wrapped = 0;
+       }
+       else
+           clrprompt();
+       modified = TRUE;
+    }
+    else {
+       error();
+killredo:
+       rcb[0] = 0;
+    }
+    mvcur(yp, xp);
+    if (xerox)
+       *rcp = 0;       /* terminate the redo */
+    redoing = FALSE;
+    xerox = FALSE;
+    core[bufmax] = EOL;
+}
+
+/* Initialize && execute a macro */
+
+PROC
+exmacro(void)
+{
+    int mp;
+
+    mp = lookup(ch);
+    if (mp > 0) {
+       if (macro<0)
+           zerostack(&undo);
+       insertmacro(mbuffer[mp].m_text, count);
+    }
+    else
+       error();
+}
+
+/* redraw the screen w.r.t. the cursor */
+
+PROC
+zdraw(char code)
+{
+    int nl = ERR,
+       np = (count>0)?to_index(count):curr;
+
+    if (movemap[code] == CR_FWD)
+       nl = 0;
+    else if (movemap[code] == CR_BACK)
+       nl = LINES-1;
+    else if (code == '.')
+       nl = LINES / 2;
+    if (nl >= 0) {
+       curr = np;
+       yp = settop(nl);
+       redisplay(TRUE);
+       mvcur(yp,xp);
+    }
+    else
+       error();
+}
+
+/* start up a built-in macro */
+
+PROC
+macrocommand(void)
+{
+    if (count > 1)
+       numtoa(gcb,count);
+    else
+       gcb[0] = 0;
+    switch (ch) { /* which macro? */
+       case 'x':                       /* x out characters */
+           strcat(gcb,"dl"); break;
+       case 'X':                       /* ... backwards */
+           strcat(gcb,"dh"); break;
+       case 's':                       /* substitute over chars */
+           strcat(gcb,"cl"); break;
+       case 'D':                       /* delete to end of line */
+           strcat(gcb,"d$"); break;
+       case 'C':                       /* change ... */
+           strcat(gcb,"c$"); break;
+       case 'Y':                       /* yank ... */
+           strcat(gcb,"y$"); break;
+       case 0x06: /* ^F */             /* scroll up one page */
+           strcpy(gcb,"22\x04"); break; /* 22^D */
+       case 0x02: /* ^B */             /* ... down one page */
+           strcpy(gcb,"22\x15"); break; /* 22^U */
+       case 0x05: /* ^E */             /* scroll up one line */
+           strcpy(gcb,"1\x04"); break; /* 1^D */
+       case 0x19: /* ^Y */             /* ... down one line */
+           strcpy(gcb,"1\x15"); break; /* 1^U */
+       default:
+            error();
+            return 0;
+       break;
+    }
+    if (macro<0)
+       zerostack(&undo);
+    insertmacro(gcb, 1);
+}
+
+/* scroll the window up || down */
+
+PROC
+scroll(bool down)
+{
+    int i;
+
+    if (count <= 0)
+       count = dofscroll;
+    strput(CURoff);
+    if (down) {
+       curr = min(bufmax-1, nextline(TRUE, curr, count));
+       i = min(bufmax-1, nextline(TRUE, pend, count));
+       if (i > pend)
+           scrollforward(i);
+    }
+    else {
+       curr = bseekeol(max(0,nextline(FALSE, curr, count)));
+       i = bseekeol(max(0,nextline(FALSE, ptop, count)));
+       if (i < ptop)
+           if (canUPSCROLL)
+               scrollback(i);
+           else {
+               ptop = i;
+               setend();
+               redisplay(TRUE);
+           }
+    }
+    strput(CURon);
+    setpos(skipws(curr));      /* initialize new position - first nonwhite */
+    yp = setY(curr);
+    mvcur(yp, xp);             /* go there */
+}
+
+exec_type PROC
+editcore(void)
+{
+    cmdtype cmd;
+    extern bool s_wrapped;
+    
+    /* rcb[0] = 0; rcp = rcb; */
+
+    if (diddled) {
+       setpos(skipws(curr));           /* set cursor x position.. */
+       yp = settop(LINES / 2);         /* Y position */
+    }
+    if (diddled || zotscreen)          /* redisplay? */
+       redisplay(FALSE);
+    mvcur(yp, xp);                     /* and move the cursor */
+
+    for (;;) {
+       s_wrapped = 0;
+       ch = readchar();                        /* get a char */
+       gcount();                       /* ... a possible count */
+       switch (cmd = movemap[ch]) {
+         case FILE_C:
+           wr_stat();                  /* write file stats */
+           mvcur(yp, xp);
+           break;
+
+         case WINDOW_UP:
+         case WINDOW_DOWN:
+           scroll(cmd==WINDOW_UP);             /* scroll the window */
+           break;
+
+         case REDRAW_C:                        /* redraw the window */
+           redisplay(TRUE);
+           mvcur(yp, xp);
+           break;
+
+         case MARKER_C:                        /* set a marker */
+           ch = tolower(readchar());
+           if (ch >= 'a' && ch <= 'z')
+               contexts[ch-'`'] = curr;
+           else if (ch != ESC)
+               error();
+           break;
+
+         case REDO_C:
+           if (rcb[0] != 0) {
+               zerostack(&undo);
+               insertmacro(rcb, 1);
+               redoing = TRUE;
+           }
+           break;
+
+         case REWINDOW:
+           zdraw(readchar());          /* shift the window */
+           break;
+
+         case DEBUG_C:                 /* debugging stuff -- unused */
+           break;
+
+         case ZZ_C:                    /* shortcut for :xit */
+           ch = readchar();
+           if (ch == 'Z')
+               insertmacro(":x\r", 1);
+           else if (ch != ESC)
+               error();
+           break;
+
+         case EDIT_C:          /* drop into line mode */
+           return E_EDIT;
+
+         case COLIN_C:         /* do one exec mode command */
+           return E_VISUAL;
+
+         case HARDMACRO:
+           macrocommand();             /* 'hard-wired' macros */
+           break;
+
+         case SOFTMACRO:
+           exmacro();          /* run a macro */
+           break;
+
+         case INSMACRO:                /* macro for insert mode */
+         case BAD_COMMAND:
+           error();
+           break;
+
+         default:
+           if (cmd < DELETE_C)
+               movearound(cmd);
+           else /*if (cmd < HARDMACRO)*/
+               docommand(cmd);
+           break;
+       }
+       lastexec = 0;
+    }
+    /* never exits here */
+}
diff --git a/Applications/levee/exec.c b/Applications/levee/exec.c
new file mode 100644 (file)
index 0000000..916e9f4
--- /dev/null
@@ -0,0 +1,1078 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * do a newline and set flags.
+ */
+#define exprintln()    (zotscreen=YES),println()
+
+PROC
+plural(int num, char *string)
+{
+    printi(num);
+    prints(string);
+    if (num != 1)
+       printch('s');
+} /* plural */
+
+
+PROC
+clrmsg(void)
+{
+    mvcur(-1,0);
+    strput(CE);
+} /* clrmsg */
+
+
+PROC
+errmsg(char *msg)
+{
+    mvcur(-1,0);
+    prints(msg);
+    strput(CE);
+} /* errmsg */
+
+
+/* get a space-delimited token */
+char *execstr;                 /* if someone calls getarg in the       */
+                               /* wrong place, death will come...      */
+char *PROC
+getarg(void)
+{
+    char *rv;
+    rv = execstr;
+    while (*execstr && !isspace(*execstr))
+       ++execstr;
+    if (*execstr) {
+       *execstr++ = 0;
+       while (isspace(*execstr))
+           ++execstr;
+    }
+    return (*rv) ? rv : NULL;
+} /* getarg */
+
+
+PROC
+version()
+/* version: print which version of levee we are... */
+{
+    errmsg("levee ");prints(ED_NOTICE);printch(ED_REVISION);
+} /* version */
+
+
+PROC
+args(void)
+/* args: print the argument list */
+{
+    register i;
+    mvcur(-1,0);
+    for (i=0; i < argc; i++) {
+       if (curpos.x+strlen(argv[i]) >= COLS)
+           exprintln();
+       else if (i > 0)
+           printch(' ');
+       if (pc == i) {                  /* highlight the current filename.. */
+#if ST|FLEXOS
+           strput("\033p");
+#else
+           printch('[');
+#endif
+           prints(argv[i]);
+#if ST|FLEXOS
+           strput("\033q");
+#else
+           printch(']');
+#endif
+       }
+       else
+           prints(argv[i]);
+    }
+} /* args */
+    
+PROC
+setcmd(void)
+{
+    bool no,b;
+    int len,i;
+    register char *arg;
+    char *num;
+    register struct variable *vp;
+    
+    if (arg = getarg()) {
+       do {
+           if (*arg != 0) {
+               if (num = strchr(arg, '=')) {
+                   b = NO;
+                   *num++ = 0;
+               }
+               else {                          /* set [no]opt */
+                   b = YES;
+                   if (arg[0]=='n' && arg[1]=='o') {
+                       arg += 2;
+                       no = NO;
+                   }
+                   else
+                       no = YES;
+               }
+               for(vp=vars;vp->u && strcmp(arg,vp->v_name)
+                                 && strcmp(arg,vp->v_abbr); vp++)
+                   ;
+               if (!vp->u || vp->v_flags & V_CONST) {
+                   errmsg("Can't set ");
+                   prints(arg);
+               }
+               else {
+                   int j;
+                    
+                    if (b)
+                       if (vp->v_tipe == VBOOL)
+                           vp->u->valu = no;
+                       else
+                           goto badsettype;
+                   else if (vp->v_tipe == VSTR) {
+                       if (vp->u->strp)
+                           free(vp->u->strp);
+                       vp->u->strp = (*num) ? strdup(num) : NULL;
+                   }
+                   else
+                       if (*num && (j=atoi(num)) >= 0)
+                           vp->u->valu = j;
+                       else {
+                 badsettype:
+                           errmsg("bad set type");
+                           continue;
+                       }
+                   diddled |= vp->v_flags & V_DISPLAY;
+               }
+           }
+       } while (arg = getarg());
+    }
+    else {
+       version(); exprintln();
+       for(vp=vars;vp->u;vp++) {
+           switch (vp->v_tipe) {
+               case VBOOL:
+                   if (!vp->u->valu)
+                       prints("no");
+                   prints(vp->v_name);
+                   break;
+               case VSTR:
+                   if (!vp->u->strp)
+                       prints("no ");
+                   prints(vp->v_name);
+                   if (vp->u->strp) {
+                       mvcur(-1,10);
+                       prints("= ");
+                       prints(vp->u->strp);
+                   }
+                   break;
+               default:
+                   prints(vp->v_name);
+                   mvcur(-1,10);
+                   prints("= ");
+                   printi(vp->u->valu);
+                   break;
+           }
+           exprintln();
+       }
+    }
+} /* setcmd */
+
+
+/* print a macro */
+PROC
+printone(int i)
+{
+    if (i >= 0) {
+       exprintln();
+       printch(mbuffer[i].token);
+       mvcur(-1,3);
+       if (movemap[mbuffer[i].token] == INSMACRO)
+           prints("!= ");
+       else
+           prints(" = ");
+       prints(mbuffer[i].m_text);
+    }
+} /* printone */
+
+
+/* print all the macros */
+PROC
+printall(void)
+{
+    int i;
+    for (i = 0; i < MAXMACROS; i++)
+       if (mbuffer[i].token != 0)
+           printone(i);
+} /* printall */
+
+
+/* :map ch text */
+PROC
+map(bool insert)
+{
+    register char *macro, c;
+    int i;
+               /* get the macro */
+    if ((macro=getarg()) == NULL) {
+       printall();
+       return 1;
+    }
+    if (strlen(macro) > 1) {
+       errmsg("macros must be one character");
+       return 0;
+    }
+    c = macro[0];
+    if (*execstr == 0)
+       printone(lookup(c));
+    else {
+       if ((i = lookup(0)) < 0)
+           errmsg("macro table full");
+       else if (c == ESC || c == ':') {
+           errmsg("can't map ");
+           printch(c);
+       }
+       else if (*execstr != 0) {
+           undefine(lookup(c));
+           mbuffer[i].token = c;
+           mbuffer[i].m_text = strdup(execstr);
+           mbuffer[i].oldmap = movemap[c];
+           if (insert)
+               movemap[c] = INSMACRO;
+           else
+               movemap[c] = SOFTMACRO;
+       }
+    }
+} /* map */
+
+
+PROC
+undefine(int i)
+{
+    register char *p;
+    if (i >= 0) {
+       movemap[mbuffer[i].token] = mbuffer[i].oldmap;
+       mbuffer[i].token = 0;
+       p = mbuffer[i].m_text;
+       free(p);
+       mbuffer[i].m_text = 0;
+    }
+} /* undefine */
+
+
+PROC
+unmap(void)
+{
+    int i;
+    register char *arg;
+    
+    if (arg=getarg()) {
+       if (strlen(arg) == 1) {
+           undefine(lookup(*arg));
+           return YES;
+       }
+       if (strcmp(arg,"all") == 0) {
+           for (i = 0; i < MAXMACROS; i++)
+               if (mbuffer[i].token != 0)
+                       undefine(i);
+           return YES;
+       }
+    }
+    return NO;
+} /* unmap */
+
+
+/* return argument # of a filename */
+int PROC
+findarg(char *name)
+{
+    int j;
+    for (j = 0; j < argc; j++)
+       if (strcmp(argv[j],name) == 0)
+           return j;
+    return -1;
+} /* findarg */
+
+
+/* add a filename to the arglist */
+int PROC
+addarg(char *name)
+{
+    int where;
+    if ((where = findarg(name)) < 0)
+       return doaddwork(name, &argc, &argv);
+    return where;
+} /* addarg */
+
+
+/* get a file name argument (substitute alt file for #) */
+char * PROC
+getname(void)
+{
+    extern int wilderr;
+#if ST
+    extern int mapslash;
+    register char *p;
+#endif
+    register char *name;
+    if (name = getarg()) {
+       if (strcmp(name,"#") == 0)
+           if (*altnm)
+               name = altnm;
+           else {
+               errmsg("no alt name");
+               wilderr++;
+               return NULL;
+           }
+#if ST
+       if (mapslash)
+           for (p=name; *p; p++)
+               if (*p == '/')
+                   *p = '\\';
+#endif
+    }
+    return name;
+} /* getname */
+
+
+/* CAUTION: these make exec not quite recursive */
+int  high,low;         /* low && high end of command range */
+bool affirm;           /* cmd! */
+/* s/[src]/dst[/options] */
+/* s& */
+PROC
+cutandpaste(void)
+{
+    bool askme  = NO,
+        printme= NO,
+        glob   = NO;
+    int newcurr = -1;
+    int oldcurr = curr;
+    int  num;
+    char delim;
+    register char *ip;
+    register char *dp;
+    
+    zerostack(&undo);
+    ip = execstr;
+    if (*ip != '&') {
+       delim = *ip;
+       ip = makepat(1+ip,delim);                       /* get search */
+       if (ip == NULL)
+           goto splat;
+       dp = dst;
+       while (*ip && *ip != delim) {
+           if (*ip == '\\' && ip[1] != 0)
+               *dp++ = *ip++;
+           *dp++ = *ip++;
+       }
+       *dp = 0;
+       if (*ip == delim) {
+           while (*++ip)
+               switch (*ip) {
+                   case 'q':
+                   case 'c': askme = YES;      break;
+                   case 'g': glob = YES;       break;
+                   case 'p': printme= YES;     break;
+               }
+       }
+    }
+    if (*lastpatt == 0) {
+splat: errmsg("bad substitute");
+       return 0;
+    }
+    fixupline(bseekeol(curr));
+    num = 0;
+    do {
+       low = chop(low, &high, NO, &askme);
+       if (low > -1) {
+           diddled = YES;
+           num++;
+           if (printme) {
+               exprintln();
+               writeline(-1,-1,bseekeol(low));
+           }
+           if (newcurr < 0)
+               newcurr = low;
+           if (!glob)
+               low = 1+fseekeol(low);
+       }
+    } while (low >= 0);
+    if (num > 0) {
+       exprintln();
+       plural(num," substitution");
+    }
+    fixupline((newcurr > -1) ? newcurr : oldcurr);
+} /* cutandpaste */
+
+
+PROC
+inputf(char *fname, bool newbuf)
+{
+    int onright,       /* text moved right for :read */
+       fsize;          /* bytes read in */
+    register FILE *f;
+
+
+    if (newbuf)
+       readonly = NO;
+
+    zerostack(&undo);
+    if (newbuf) {
+       modified = NO;
+       low = 0;
+       high = SIZE;
+    }
+    else {             /* append stuff to the buffer */
+       fixupline(bseekeol(curr));
+       onright = bufmax-low;
+#if MSDOS
+       high = SIZE;
+       high -= onright;
+#else
+       high = (SIZE-onright);
+#endif
+       if (onright > 0)
+           moveright(&core[low], &core[high], onright);
+    }
+    printch('"');
+    prints(fname);
+    prints("\" ");
+    if ((f=fopen(fname, "r")) == NULL) {
+       prints("[No such file]");
+       fsize = 0;
+       if (newbuf)
+           newfile = YES;
+    }
+    else {
+       if (addfile(f, low, high, &fsize))
+           plural(fsize," byte");
+       else if (fsize < 0) {
+           prints("[read error]");
+           fsize = 0;
+       }
+       else {
+           prints("[overflow]");
+           readonly = YES;
+       }
+       fclose(f);
+       if (newbuf)
+           newfile = NO;
+    }
+    if (newbuf) {
+       fillchar(contexts, sizeof(contexts), -1);
+       bufmax = fsize;
+    }
+    else {
+       insert_to_undo(&undo, low, fsize);
+       modified = YES;
+       if (onright > 0)
+           moveleft(&core[high], &core[low+fsize], onright);
+    }
+    if (*startcmd) {
+       count = 1;
+       if (*findparse(startcmd,&curr,low) != 0 || curr < 0)
+           curr = low;
+       *startcmd = 0;
+    }
+    else
+       curr = low;
+    diddled = YES;
+} /* inputf */
+
+
+/* Change a file's name (for autocopy). */
+PROC
+backup(char *name)
+{
+    char back[80];
+    char *p;
+
+    strcpy(back, name);
+#if UNIX
+    strcat(back, "~");
+#else
+    p = strrchr(basename(back), '.');
+    if (p)
+       strcpy(1+p, ",bkp");
+    else
+       strcat(back, ".bkp");
+#endif
+    
+    unlink(back);
+    rename(name, back);
+} /* backup */
+
+
+bool PROC
+outputf(char *fname)
+{
+    bool whole;
+    register FILE *f;
+    int status;
+    zerostack(&undo);          /* undo doesn't survive past write */
+    if (high < 0)
+       high = (low < 0) ? bufmax : (1+fseekeol(low));
+    if (low < 0)
+       low  = 0;
+    printch('"');
+    prints(fname);
+    prints("\" ");
+    whole = (low == 0 && high >= bufmax-1);
+    if (whole && autocopy)
+       backup(fname);
+    if (f=fopen(fname, "w")) {
+       status = putfile(f, low, high);
+       fclose(f);
+       if (status) {
+           plural(high-low," byte");
+           if (whole)
+               modified = NO;
+           return(YES);
+       }
+       else {
+           prints("[write error]");
+           unlink(fname);
+       }
+    }
+    else
+       prints(fisro);
+    return(NO);
+} /* outputf */
+
+
+PROC
+oktoedit(int writeold)
+/* check and see if it is ok to edit a new file */
+/* writeold;   automatically write out changes? */
+{
+    if (modified && !affirm)
+       if (readonly) {
+           errmsg(fisro);
+           return NO;
+       }
+       else if (writeold && *filenm) {
+           if (!outputf(filenm))
+               return NO;
+           printch(',');
+       }
+       else {
+           errmsg(fismod);
+           return NO;
+       }
+    return YES;
+} /* oktoedit */
+
+
+/* write out all || part of a file */
+bool PROC
+writefile(void)
+{
+    register char *name;
+    
+    if ((name=getname()) == NULL)
+       name = filenm;
+    if (*name) {
+       if (outputf(name)) {
+           addarg(name);
+           return YES;
+       }
+       else
+           strcpy(altnm, name);
+    }
+    else
+       errmsg("no file to write");
+    return NO;
+}
+
+
+PROC
+editfile(void)
+{
+    register char *name = NULL;        /* file to edit */
+    char **myargv;
+    int myargc;
+    int i, newpc;
+    if ((name = getarg()) && *name == '+') {
+       strcpy(startcmd, (name[1])?(1+name):"$");
+       name = getarg();
+    }
+    myargc=0;
+    if (name)
+       do {
+           if (!expandargs(name, &myargc, &myargv))
+               return 0;
+       } while (name=getarg());
+    if (myargc == 0) {
+       if (*filenm)
+           name = filenm;
+       else
+           errmsg("no file to edit");
+    }
+    else if ((newpc = addarg(myargv[0])) >= 0) {
+       name = argv[pc = newpc];
+       for (i=1; i < myargc && doaddwork(myargv[i], &argc, &argv) >= 0; i++)
+           ;
+    }
+    killargs(&myargc, &myargv);
+    if (name && oktoedit(NO))
+       doinput(name);
+}
+
+
+PROC
+doinput(char *name)
+{
+    inputf(name, YES);
+    strcpy(altnm, filenm);
+    strcpy(filenm, name);
+}
+
+
+PROC
+toedit(int count)
+{
+    if (count > 1) {
+       printi(count);
+       prints(" files to edit; ");
+    }
+}
+
+
+PROC
+readfile(void)
+{
+    register char *name;
+    
+    if (name=getarg())
+       inputf(name,NO);
+    else
+       errmsg("no file to read");
+}
+
+
+PROC
+nextfile(bool prev)
+{
+    register char *name = NULL;
+    int newpc=pc,
+       what,
+       myargc=0;
+    char **myargv;
+    bool newlist = NO;
+    
+    if (prev == 0)
+       while (name=getarg())
+           if (!expandargs(name, &myargc, &myargv))
+               return 0;
+    
+    if (oktoedit(autowrite)) {
+       if (prev || (myargc == 1 && strcmp(myargv[0],"-") == 0)) {
+           if (pc > 0) {
+               newpc = pc-1;
+           }
+           else {
+               prints("(no prev files)");
+               goto killem;
+           }
+       }
+       else if (myargc == 0) {
+           if (pc < argc-1) {
+               newpc = 1+pc;
+           }
+           else {
+               prints("(no more files)");
+               goto killem;
+           }
+       }
+       else if (myargc > 1 || (newpc = findarg(myargv[0])) < 0) {
+           toedit(myargc);
+           newpc = 0;
+           newlist++;
+       }
+       doinput(newlist ? myargv[0] : argv[newpc]);
+       pc = newpc;
+       if (newlist) {
+           killargs(&argc, &argv);
+           argc = myargc;
+           argv = myargv;
+       }
+       else
+    killem: if (!prev)
+               killargs(&myargc, &myargv);
+    }
+}
+
+
+/*
+ * set up low, high; set dot to low
+ */
+PROC
+fixupline(int dft)
+{
+    if (low < 0)
+       low = dft;
+    if (high < 0)
+       high = fseekeol(low)+1;
+    else if (high < low) {             /* flip high & low */
+       int tmp;
+       tmp = high;
+       high = low;
+       low = tmp;
+    }
+    if (low >= ptop && low < pend) {
+       setpos(skipws(low));
+       yp = setY(curr);
+    }
+    else {
+       curr = low;
+       diddled = YES;
+    }
+}
+
+
+PROC
+whatline(void)
+{
+    printi(to_line((low < 0) ? (bufmax-1) : low));
+    if (high >= 0) {
+       printch(',');
+       printi(to_line(high));
+    }
+}
+
+
+PROC
+print(void)
+{
+    do {
+       exprintln();
+       writeline(-1, 0, low);
+       low = fseekeol(low) + 1;
+    } while (low < high);
+    exprintln();
+}
+
+/* move to different line */
+/* execute lines from a :sourced || .lvrc file */
+
+
+bool PROC
+do_file(char *fname, exec_type *mode, bool *noquit)
+{
+    char line[120];
+    register FILE *fp;
+    
+    if ((fp = fopen(fname,"r")) != NULL) {
+       indirect = YES;
+       while (fgets(line,120,fp) && indirect) {
+           strtok(line, "\n");
+           if (*line != 0)
+               exec(line,mode,noquit);
+       }
+       indirect = YES;
+       fclose(fp);
+       return YES;
+    }
+    return NO;
+}
+
+
+PROC doins(bool flag)
+{
+    int i;
+    curr = low;
+    exprintln();
+    low = insertion(1,setstep[flag],&i,&i,NO)-1;
+    if (low >= 0)
+       curr = low;
+    diddled = YES;
+}
+
+
+/* figure out a address range for a command */
+char * PROC findbounds(char *ip)
+{
+    ip = findparse(ip, &low, curr);    /* get the low address */
+    if (low >= 0) {
+       low = bseekeol(low);            /* at start of line */
+       if (*ip == ',') {               /* high address? */
+           ip++;
+           count = 0;
+           ip = findparse(ip, &high, curr);
+           if (high >= 0) {
+               high = fseekeol(high);
+               return(ip);
+           }
+       }
+       else
+           return(ip);
+    }
+    return(0);
+}
+
+
+/* parse the command line for lineranges && a command */
+PROC parse(char *inp)
+{
+    int j,k;
+    char cmd[80];
+    low = high = ERR;
+    affirm = 0;
+    if (*inp == '%') {
+       moveright(inp, 2+inp, 1+strlen(inp));
+       inp[0]='1';
+       inp[1]=',';
+       inp[2]='$';
+    }
+    while (isspace(*inp))
+       ++inp;
+    if (strchr(".$-+0123456789?/`'", *inp))
+       if (!(inp=findbounds(inp))) {
+           errmsg("bad address");
+           return ERR;
+       }
+    while (isspace(*inp))
+       ++inp;
+    j = 0;
+    while (isalpha(*inp))
+       cmd[j++] = *inp++;
+    if (*inp == '!') {
+       if (j == 0)
+           cmd[j++] = '!';
+       else
+           affirm++;
+       inp++;
+    }
+    else if (*inp == '=' && j == 0)
+       cmd[j++] = '=';
+    while (isspace(*inp))
+       ++inp;
+    execstr = inp;
+    if (j==0)
+       return EX_CR;
+    for (k=0; excmds[k]; k++)
+       if (strncmp(cmd, excmds[k], j) == 0)
+           return k;
+    return ERR;
+}
+
+
+/* inner loop of execmode */
+PROC
+exec(char *cmd, exec_type *mode, bool *noquit)
+{
+    int  what;
+    bool ok;
+    
+    what = parse(cmd);
+    ok = YES;
+    if (diddled) {
+       lstart = bseekeol(curr);
+       lend = fseekeol(curr);
+    }
+    switch (what) {
+       case EX_QUIT:                           /* :quit */
+           if (affirm || what == lastexec || !modified)
+               *noquit = NO;
+           else
+               errmsg(fismod);
+           break;
+       case EX_READ:                           /* :read */
+           clrmsg();
+           readfile();
+           break;
+       case EX_EDIT:                           /* :read, :edit */
+           clrmsg();
+           editfile();
+           break;
+       case EX_WRITE:
+       case EX_WQ :                            /* :write, :wq */
+           clrmsg();
+           if (readonly && !affirm)
+               prints(fisro);
+           else if (writefile() && what==EX_WQ)
+               *noquit = NO;
+           break;
+       case EX_PREV:
+       case EX_NEXT:                           /* :next */
+           clrmsg();
+           nextfile(what==EX_PREV);
+           break;
+       case EX_SUBS:                           /* :substitute */
+           cutandpaste();
+           break;
+       case EX_SOURCE:                         /* :source */
+           if ((cmd = getarg()) && !do_file(cmd, mode, noquit)) {
+               errmsg("cannot open ");
+               prints(cmd);
+           }
+           break;
+       case EX_XIT:
+           clrmsg();
+           if (modified)
+               if (readonly) {
+                   prints(fisro);
+                   break;
+               }
+               else if (!writefile())
+                   break;
+
+           if (!affirm && (argc-pc > 1)) {     /* any more files to edit? */
+               printch('(');
+               plural(argc-pc-1," more file");
+               prints(" to edit)");
+           }
+           else
+               *noquit = NO;
+           break;
+       case EX_MAP:
+           map(affirm);
+           break;
+       case EX_UNMAP:
+           ok = unmap();
+           break;
+       case EX_FILE:                           /* :file */
+           if (cmd=getarg()) {         /* :file name */
+               strcpy(altnm, filenm);
+               strcpy(filenm, cmd);
+               pc = addarg(filenm);
+           }
+           wr_stat();
+           break;
+       case EX_SET:                            /* :set */
+           setcmd();
+           break;
+       case EX_CR:
+       case EX_PR:                             /* :print */
+           fixupline(bseekeol(curr));
+           if (what == EX_PR)
+               print();
+           break;
+       case EX_LINE:                           /* := */
+           whatline();
+           break;
+       case EX_DELETE:
+       case EX_YANK:                           /* :delete, :yank */
+           yank.lines = YES;
+           fixupline(lstart);
+           zerostack(&undo);
+           if (what == EX_DELETE)
+               ok = deletion(low,high);
+           else
+               ok = doyank(low,high);
+           diddled = YES;
+           break;
+       case EX_PUT:                            /* :put */
+           fixupline(lstart);
+           zerostack(&undo);
+           ok = putback(low, &high);
+           diddled = YES;
+           break;
+       case EX_VI:                             /* :visual */
+           *mode = E_VISUAL;
+           if (*execstr) {
+               clrmsg();
+               nextfile(NO);
+           }
+           break;
+       case EX_EX:
+           *mode = E_EDIT;                     /* :execmode */
+           break;
+       case EX_INSERT:
+       case EX_OPEN:                           /* :insert, :open */
+           if (indirect)
+               ok = NO;                /* kludge, kludge, kludge!!!!!!!!!! */
+           else {
+               zerostack(&undo);
+               fixupline(lstart);
+               doins(what == EX_OPEN);
+           }
+           break;
+       case EX_CHANGE:                         /* :change */
+           if (indirect)
+               ok = NO;                /* kludge, kludge, kludge!!!!!!!!!! */
+           else {
+               zerostack(&undo);
+               yank.lines = YES;
+               fixupline(lstart);
+               if (deletion(low,high))
+                   doins(YES);
+               else
+                   ok = NO;
+           }
+           break;
+       case EX_UNDO:                           /* :undo */
+           low = fixcore(&high);
+           if (low >= 0) {
+               diddled = YES;
+               curr = low;
+           }
+           else ok = NO;
+           break;
+       case EX_ARGS:                           /* :args */
+           args();
+           break;
+       case EX_VERSION:                        /* version */
+           version();
+           break;
+       case EX_ESCAPE:                 /* shell escape hack */
+           zotscreen = YES;
+           exprintln();
+           if (*execstr) {
+#if ZTERM
+               zclose();
+#endif
+#if FLEXOS|UNIX
+               fixcon();
+#else
+               allowintr();
+#endif
+//FIXME!!              system(execstr);
+#if FLEXOS|UNIX
+               initcon();
+#else
+               nointr();
+#endif
+           }
+           else
+               prints("incomplete shell escape.");
+           break;
+       case EX_REWIND:
+           clrmsg();
+           if (argc > 0 && oktoedit(autowrite)) {
+               pc = 0;
+               doinput(argv[0]);
+           }
+           break;
+       default:
+           prints(":not an editor command.");
+           break;
+    }
+    lastexec = what;
+    if (!ok) {
+       errmsg(excmds[what]);
+       prints(" error");
+    }
+}
diff --git a/Applications/levee/extern.h b/Applications/levee/extern.h
new file mode 100644 (file)
index 0000000..4d0d61a
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef GLOBALS_D
+#define GLOBALS_D
+extern
+char lastchar,         /* Last character read via peekc */
+     ch;               /* Global command char */
+extern
+exec_type mode;                        /* editor init state */
+extern
+int lastexec;                  /* last exec mode command */
+
+extern
+int contexts['z'-'`'+1];       /* Labels */
+               /* C O N S T A N T S */
+extern
+bool adjcurr[PARA_BACK+1],
+     adjendp[PARA_BACK+1];
+               /* A R G U M E N T S */
+extern
+char startcmd[];       /* initial command after read */
+extern
+char **argv;           /* Arguments */
+extern
+int  argc,             /* # arguments */
+     pc;               /* Index into arguments */
+               /* M A C R O   S T U F F */
+extern
+struct macrecord mbuffer[];
+extern
+struct tmacro mcr[];           /* A place for executing macros */
+                       /* S E A R C H   S T U F F */
+extern
+char dst[],                    /* last replacement pattern */
+     lastpatt[],               /* last search pattern */
+     pattern[];
+extern
+int RE_start[9],               /* start of substitute argument */
+    RE_size [9],               /* size of substitute argument */
+    lastp;                     /* last character matched in search */
+extern
+struct undostack undo;         /* To undo a command */
+               /* R A N D O M   S T R I N G S */
+               
+extern
+char instring[],               /* Latest input */
+     filenm[],                 /* Filename */
+     altnm[],                  /* Alternate filename */
+     gcb[];                    /* Command buffer for mutations of insert */
+       
+extern
+char undobuf[],
+     undotmp[],
+     yankbuf[];
+extern
+int uread,                     /* reading from the undo stack */
+    uwrite;                    /* writing to the undo stack */
+                           /* B U F F E R S */
+extern
+char rcb[], *rcp,              /* last modification command */
+     core[];                   /* data space */
+                   
+extern
+struct ybuf yank;              /* last deleted/yanked text */
+/* STATIC INITIALIZATIONS: */
+/* ttydef stuff */
+#if ST | TERMCAP
+extern int LINES, COLS;
+#endif
+#if TERMCAP
+extern bool CA, canUPSCROLL;
+extern char FkL,
+           CurRT,
+           CurLT,
+           CurDN,
+           CurUP;
+#endif /*TERMCAP*/
+extern char *TERMNAME,
+           *HO,
+           *UP,
+           *CE,
+           *CL,
+           *OL,
+           *BELL,
+           *CM,
+           *UpS,
+           *CURoff,
+           *CURon;
+
+extern
+char erasechar,
+     eraseline;
+
+extern
+char ED_NOTICE[],              /* Editor version */
+     ED_REVISION,              /* Small revisions & corrections */
+     fismod[],                 /* File is modified message */
+     fisro[];                  /* permission denied message */
+     
+extern
+char *excmds[],
+     wordset[],
+     spaces[];
+extern
+struct variable vars[];
+extern
+int autowrite,
+    autocopy,
+    overwrite,
+    beautify,
+    autoindent,
+    dofscroll,
+    shiftwidth,
+    tabsize,
+    list,
+    wrapscan,
+    bell,
+    magic;
+/*extern 
+char *suffix;  */
+/* For movement routines */
+extern
+int setstep[];
+/* Where the last diddling left us */
+extern
+struct coord curpos;
+    
+    /* initialize the buffer */
+extern
+int curr,              /* Global cursor pos */
+    lstart, lend,      /* Start & end of current line */
+    count,             /* Latest count */
+    xp, yp,            /* Cursor window position */
+    bufmax,            /* End of file here */
+    ptop, pend;                /* Top & bottom of CRT window */
+extern
+bool modified,         /* File has been modified */
+     readonly,         /* is this file readonly? */
+     needchar,         /* Peekc flag */
+     deranged,         /* Up-arrow || down-arrow left xpos in Oz. */
+     indirect,         /* Reading from an indirect file?? */
+     redoing,          /* doing a redo? */
+     xerox,            /* making a redo buffer? */
+     newfile,          /* Editing a new file? */
+     newline,          /* Last insert/delete included a EOL */
+     lineonly,         /* Dumb terminal? */
+     zotscreen,                /* do more after command in execmode */
+     diddled;          /* force redraw when I enter editcore */
+     
+extern
+int macro;    /* Index into MCR macro execution stack */
+extern
+char nlsearch;
+/* movement, command codes */
+extern
+cmdtype movemap[];
+#endif /*GLOBALS_D*/
+#ifndef EXTERN_D
+#define EXTERN_D
+#define wc(ch) (scan(65,'=',(ch),wordset)<65)
+
+#if SYS5
+#define fillchar(p,l,c)        memset((p),(c),(l))
+#define index(s,c)     strchr((s),(c))
+#else /*!SYS5*/
+#if ST
+#define fillchar(p,l,c)        blkfill((p),(c),(l))
+#endif /*ST*/
+#endif /*SYS5*/
+               /* non int functions to be found elsewhere */
+               
+#if 0
+extern findstates findCP();
+extern exec_type editcore();
+extern char line(), peekc(), readchar();
+extern bool getline();
+extern char *findparse(),*makepat();
+extern bool putfile();
+extern bool doyank(), deletion(), putback();
+extern bool pushb(),pushi(),pushmem(),uputcmd(),
+           delete_to_undo(),move_to_undo();
+#endif
+
+#endif /*EXTERN_D*/
diff --git a/Applications/levee/find.c b/Applications/levee/find.c
new file mode 100644 (file)
index 0000000..1e9e263
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+#include "grep.h"
+#include <ctype.h>
+#include <string.h>
+
+static int arg;                /* arguments inside of a RE */
+
+int PROC
+REmatch(char *pattern, int start, int end)
+{
+    register char *endp = &core[end];
+
+    if (!*pattern)
+       return -1;
+    arg = 0;
+    while (start <= end && !amatch(pattern, &core[start], endp))
+       start++;
+    return start;
+}
+
+int PROC
+omatch(char *pattern, char **cp, char *endp)
+{
+    register flag;
+    extern int ignorecase;
+
+    switch (*pattern) {
+      case LEND:
+         return (**cp == EOL);
+      case LSTART:
+         return (*cp == core) || (*(*cp-1) == EOL);
+      case TOKENB:
+         return (*cp == core) || !isalnum(*(*cp-1));
+      case TOKENE:
+         return !isalnum(**cp);
+      case LITCHAR:
+#ifdef TOUPPER_FTN
+#undef toupper
+#endif
+         if (ignorecase)
+             flag = (toupper(**cp) == toupper(*(pattern+1)));
+         else
+             flag = (**cp == *(pattern+1));
+         break;
+      case ANY:
+         flag = (**cp != EOL);
+         break;
+      case CCL:
+         flag = locate(pattern,*cp);
+         break;
+      case NCCL:
+         flag = !locate(pattern,*cp);
+         break;
+      case ARGSTART:
+         RE_start[arg] = (*cp)-core;
+         return TRUE;
+      case ARGEND:
+         RE_size[arg] = ((*cp)-core) - RE_start[arg];
+         ++arg;
+         return TRUE;
+      default:
+         return TRUE;
+    }
+
+    if (*cp <= endp && flag) {
+       (*cp)++;
+       return TRUE;
+    }
+    return FALSE;
+}
+       
+int PROC
+amatch(char *pattern, char *start, char *endp)
+{
+    int sarg = arg;    /* save old arg match count for errors */
+
+    while (*pattern) {
+       if (*pattern == CLOSURE) {
+       /*      Find the longest closure possible and work backwards trying
+        *      to match the rest of the pattern.
+        */
+           char *oldstart = start;
+
+           ++pattern;  /* skip over the closure token */
+           while (start <= endp && omatch(pattern,&start,endp))
+                ;
+       /*      start points at the character that failed the search.
+        *      Try to match the rest of the pattern against it, working
+        *      back down the line if failure
+        */
+           patsize(&pattern);
+           while (start >= oldstart)
+               if (amatch(pattern,start--,endp))
+                   return TRUE;
+           arg = sarg;
+           return FALSE;
+       }
+       else {
+           if (!omatch(pattern,&start,endp)) {
+               arg = sarg;
+               return FALSE;
+           }
+           patsize(&pattern);
+       }
+    }
+    lastp = start-core;
+    return TRUE;
+}
+
+/*  increment pattern by the size of the token being scanned
+ */
+PROC
+patsize(char **pattern)
+{
+    register count;
+    
+    switch (**pattern) {
+      case LITCHAR:
+       *pattern += 2;
+       break;
+      case CCL:
+      case NCCL:
+       count = *(++*pattern) & 0xff;
+       *pattern += 1+count;
+       break;
+      default:
+       (*pattern)++;
+       break;
+    }
+}
+
+PROC
+locate(char *pattern, char *linep)
+/* locate: find a character in a closure */
+{
+    register char *p = 1+pattern;
+    register int count;
+    
+    if ((count = (*p++)&0xff) == 0)
+       return FALSE;
+    while (count--)
+       if (*p++ == *linep)
+           return TRUE;
+    return FALSE;
+}
+char *p;
+
+PROC
+concatch(char c)
+{
+    if (p < &pattern[MAXPAT-1])
+       *p++ = c;
+}
+
+char PROC
+esc(char **s)
+{
+    if (**s != ESCAPE || *(1+*s) == 0)
+       return **s;
+    ++(*s);
+    switch (**s) {
+      case 't': return TAB;
+      case 'n': return EOL;
+    }
+    return **s;
+}
+
+char * PROC
+dodash(char *src)
+
+/* parse the innards of a [] */
+{
+    int k;
+    register char *start = src;
+    char cs[128];
+
+    fillchar(cs,sizeof(cs),FALSE);
+    while (*src && *src != CCLEND) {
+       if (*src == DASH && src>start && src[1] != CCLEND && src[-1]<src[1]) {
+           for ( k = src[-1]; k <= src[1]; k++)
+               cs[k] = TRUE;
+           src++;
+       }
+       else
+           cs[esc(&src)] = TRUE;
+       src++;
+    }
+    for (k=0; k < sizeof(cs); k++)
+       if (cs[k])
+           concatch((char)k);
+    return src;
+}
+
+char * PROC badccl(char *src)
+/* a [] was encountered. is it a CCL (match one of the included
+ *  characters); or is it a NCCL (match all but the included characters)?
+ */
+{
+    register char *jstart;
+
+    if (*src == NEGATE) {
+       concatch(NCCL);
+       ++src;
+    }
+    else
+       concatch(CCL);
+    jstart = p;
+    concatch(0);               /* this will be the length of the pattern */
+    src = dodash(src);
+    *jstart = (p-jstart)-1;
+    return src;
+}
+
+       /* patterns that cannot be closed */
+char badclose[] = { LSTART, LEND, CLOSURE, 0 };
+
+char * PROC makepat(char *string, char delim)
+/* make up the pattern string for find -- ripped from 'Software Tools' */
+{
+    register char *cp;
+    register char *oldcp;
+    char *start = string;
+    int inarg = FALSE;
+
+    for(arg=0;arg<9;++arg)
+       RE_start[arg] = RE_size[arg] = (-1);
+    arg = 0;
+    p = pattern;
+    
+    while ((*string != delim) && (*string != 0)) {
+       oldcp = cp;
+       cp = p;
+       
+       if (!magic)             /* kludge for nonmagical patterns */
+           goto normal;
+       if (*string == ANY)
+           concatch(ANY);
+       else if ((*string == LSTART) && (string == start))
+           concatch(LSTART);
+       else if ((*string == LEND) && (string[1] == delim || string[1] == 0))
+           concatch(LEND);
+       else if (*string == CCL)
+           string = badccl(1+string);
+       else if ((*string == CLOSURE) && (p > pattern)) {
+           cp = oldcp;
+           if (strchr(badclose, *cp) || p >= &pattern[MAXPAT-1])
+               return NULL;
+           moveright(cp,1+cp,(int)(p-cp));
+           *cp = CLOSURE;
+           p++;
+       }
+       else if (*string == ESCAPE) {
+           if (string[1] == ARGSTART || string[1] == ARGEND) {
+               if (string[1] == ARGEND)
+                   if (!inarg)
+                       goto normal;
+               if (string[1] == ARGSTART) {
+                   if (inarg)
+                       goto normal;
+                   if (++arg > 9)
+                       return NULL;
+               }
+               inarg = !inarg;
+           }
+           else if (string[1] != TOKENB && string[1] != TOKENE)
+               goto normal;
+           ++string;
+           concatch(*string);
+       }
+       else {
+     normal:concatch(LITCHAR);
+           concatch(esc(&string));
+       }
+       if (*string)
+           string++;
+    }
+    if (inarg)
+       concatch(ARGEND);
+    if (p > pattern) {         /* new pattern was created */
+       strncpy(lastpatt,start,(int)(string-start));
+       lastpatt[string-start] = 0;
+       concatch(0);
+       if (p-pattern >= MAXPAT)
+           return NULL;
+    }
+    return (*string == delim)?(string+1):(string);
+}
+
+PROC
+findfwd(char *pattern, int start, int endp)
+/* look for a regular expression forward */
+{
+    int ep;
+
+     while (start < endp) {
+        ep = fseekeol(start);
+        if ((start = REmatch(pattern, start, ep)) <= ep)
+            return start;
+     }
+     return ERR;
+ }
+
+PROC
+findback(char *pattern, int start, int endp)
+/* look for a regular expression backwards */
+{
+    int ep,i, j;
+
+     while (start > endp) {
+        ep = bseekeol(start);
+        if ((j = REmatch(pattern, ep, start)) <= start)
+             {
+             i = j;
+             while((j=REmatch(pattern, i+1, start)) <= start)
+                 {
+                 i = j;
+                 }
+            return i;
+             }
+        start = ep-1;
+     }
+     return ERR;
+ }
+
+bool s_wrapped = 0;
+
+char * PROC
+search(char *pat, int *start)
+/* get a token for find & find it in the buffer
+ */
+{
+    bool forwd;
+    int  pos;
+    char *p;
+
+    forwd = ((nlsearch = *pat) == '/');
+    if ((p=makepat(pat+1,*pat)) == NULL) {
+       *start = ERR;
+       return pat;
+    }
+    do {
+       if (forwd) {
+           pos = findfwd(pattern, (*start)+1, bufmax-1);
+           if ((pos == ERR) && wrapscan) {
+               s_wrapped = 1;
+               pos = findfwd(pattern, 0, (*start)-1);
+           }
+       }
+       else {
+           pos = findback(pattern, (*start)-1, 0);
+           if ((pos == ERR) && wrapscan) {
+               s_wrapped = 1;
+               pos = findback(pattern, bufmax-1, (*start)+1);
+           }
+       }
+       *start = pos;
+    } while (--count > 0 && *start != ERR);
+    return p;
+}
+
+char * PROC
+findparse(char *src, int *idx, int start) /* driver for ?, /, && : lineranges */
+{
+    int addr = start;
+    char c;
+
+    s_wrapped = 0;
+
+    switch (*src) {
+       case '/':
+       case '?':
+           /* get a token for find & find it in the buffer */
+           src = search(src,&addr);
+       break;
+       case '0': case '1': case '2': case '3': case '4':
+       case '5': case '6': case '7': case '8': case '9':
+           /* fabricate a count */
+           count = 0;
+           while (*src >= '0' && *src <= '9')
+               count = (count*10) + *(src++) - '0';
+               
+           addr = to_index(count);
+       break;
+       case '$':
+           addr = bufmax-1;
+           src++;
+       break;
+       case '.' :
+           src++;
+       break;
+       case '`':
+       case '\'':
+           addr = getcontext(*(src+1), (*src == '\''));
+           src += 2;
+       break;
+    }
+
+    while (addr>=0 && (*src =='+' || *src == '-')) {
+       c = *(src++);
+       /* skip delimiter */
+       if (*src == '/' || *src == '?') {
+           count = 1;
+           if ((src = search(src,&addr)) == NULL)
+               break;
+       }
+       else {
+           if (*src >= '0' && *src <= '9') {
+               /* fabricate a count */
+               count = 0;
+               while (*src >= '0' && *src <= '9')
+                   count = (count*10) + *(src++) - '0';
+           }
+           else
+               count = -1;             /* for naked + & - */
+           if (count == 0)             /* +0 goes to beginning of line */
+               addr = bseekeol(addr);
+           else {
+               addr = nextline((c=='+'), addr, count);
+               if (c=='-' && addr > 0)
+                   addr = bseekeol(addr);
+           }
+           if (addr >= bufmax)
+               addr = -1;
+       }
+    }
+    *idx = addr;
+    return(src);
+}
+
+int PROC
+nextline(bool advance, int dest, int count)
+{
+    if (advance)
+       do {
+           dest = fseekeol(dest) + 1;
+           count--;
+       } while (count>0 && dest<bufmax);
+    else
+       do {
+           dest = bseekeol(dest) - 1;
+           count--;
+       } while (count>0 && dest>=0);
+    return(dest);
+}
+
+int PROC
+fseekeol(int origin)
+{
+    return(origin + scan(bufmax-origin-1,'=',EOL,&core[origin]));
+}
+
+int PROC
+bseekeol(int origin)
+{
+    return(origin + scan(-origin,'=',EOL,&core[origin-1]));
+}
+
+/* get something from the context table */
+
+int PROC
+getcontext(char c, bool begline)
+{
+    int i;
+    
+    if (c == '\'')
+       c = '`';
+    if (c >= '`' && c <= 'z')
+       i = contexts[c-'`'];
+    else
+       i = -1;
+    if (begline && i>=0)
+       return(bseekeol(i));
+    return(i);
+}
diff --git a/Applications/levee/flexcall.c b/Applications/levee/flexcall.c
new file mode 100644 (file)
index 0000000..0f3f013
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * flexos interface for levee (Metaware C)
+ */
+#include "levee.h"
+
+#if FLEXOS
+#include <flexos.h>
+#include <ctype.h>
+
+static int oldkmode;
+static int oldsmode;
+
+int
+min(a,b)
+{
+    return (a>b) ? b : a;
+}
+
+int
+max(a,b)
+{
+    return (a<b) ? b : a;
+}
+
+strput(s)
+char *s;
+{
+    s_write(0x01, 1L, s, (long)strlen(s), 0L);
+}
+
+char *
+basename(s)
+ char *s;
+{
+    char *strrchr();
+    register char *p;
+
+    if ((p=strrchr(s,'/')) || (p=strrchr(s,'\\')) || (p = strrchr(s,':')))
+       return 1+p;
+    return s;
+}
+
+getKey()
+{
+    char c;
+
+    s_read(0x0101, 0L, &c, 1L, 0L);
+    return c;
+}
+
+initcon()
+{
+    CONSOLE tty;
+
+    s_get(T_CON, 1L, &tty, SSIZE(tty));
+    oldkmode = tty.con_kmode;
+    oldsmode = tty.con_smode;
+    tty.con_kmode = 0x0667;
+    tty.con_smode = 0;
+    s_set(T_CON, 1L, &tty, SSIZE(tty));
+}
+
+fixcon()
+{
+    CONSOLE tty;
+
+    s_get(T_CON, 1L, &tty, SSIZE(tty));
+    tty.con_kmode = oldkmode;
+    tty.con_smode = oldsmode;
+    s_set(T_CON, 1L, &tty, SSIZE(tty));
+}
+
+char *
+strdup(s)
+char *s;
+{
+    char *malloc();
+    char *p;
+
+    if (p=malloc(strlen(s)+1))
+       strcpy(p, s);
+    return p;
+}
+
+getpid()
+{
+    PROCESS myself;
+
+    s_get(T_PDEF, 0L, &myself, SSIZE(myself));
+
+    return myself.ps_pid;
+}
+
+strlwr(s)
+char *s;
+{
+    while (*s) {
+       if (isupper(*s))
+           *s += 32;
+       s++;
+    }
+}
+#endif
diff --git a/Applications/levee/gemcall.c b/Applications/levee/gemcall.c
new file mode 100644 (file)
index 0000000..c63a252
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Gemdos (Atari ST) bindings for levee (Alcyon/Sozobon C)
+ */
+#include "levee.h"
+
+#if ST
+#include <atari\osbind.h>
+
+strput(s)
+register char *s;
+{
+    write(1, s, strlen(s));
+}
+
+
+zwrite(s,len)
+char *s;
+{
+    write(1, s, len);
+}
+
+
+min(a,b)
+register int a, b;
+{
+    return (a<b)?a:b;
+}
+
+
+max(a,b)
+register int a, b;
+{
+    return (a>b)?a:b;
+}
+
+
+unsigned
+getKey()
+/* get input from the keyboard. All odd keys (function keys, et al) that
+ * do not produce a character have their scancode orred with $80 and returned.
+ */
+{
+    unsigned c;
+    long key;
+
+    c = (key = Crawcin()) & 0xff;
+    if (!c)
+       c = (((unsigned)(key>>16))|0x80) & 0xff;
+    return c;
+} /* getKey */
+#endif /*ST*/
diff --git a/Applications/levee/globals.c b/Applications/levee/globals.c
new file mode 100644 (file)
index 0000000..c4f49dc
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/* global declarations */
+
+#include "levee.h"
+#define GLOBALS
+
+char lastchar,         /* Last character read via peekc */
+     ch;               /* Global command char */
+
+exec_type mode;                        /* editor init state */
+int lastexec = 0;              /* last exec command */
+
+int contexts['z'-'`'+1];       /* Labels */
+
+               /* C O N S T A N T S */
+
+bool adjcurr[PARA_BACK+1],
+     adjendp[PARA_BACK+1];
+
+               /* A R G U M E N T S */
+char startcmd[80] = "";        /* initial command after read */
+char **argv;           /* Arguments */
+int  argc=0,           /* # arguments */
+     pc=0;             /* Index into arguments */
+#if 0
+struct stat thisfile;  /* status on current file, for writeout... */
+#endif
+
+               /* M A C R O   S T U F F */
+struct macrecord mbuffer[MAXMACROS];
+struct tmacro mcr[NMACROS];            /* A place for executing macros */
+
+               /* S E A R C H   S T U F F */
+char dst[80] = "",                     /* last replacement pattern */
+     lastpatt[80] = "",                        /* last search pattern */
+     pattern[MAXPAT] = "";             /* encoded last pattern */
+
+int RE_start[9],                       /* start of substitution arguments */
+    RE_size [9],                       /* size of substitution arguments */
+    lastp;                             /* end of last pattern */
+
+struct undostack undo;                 /* To undo a command */
+
+
+               /* R A N D O M   S T R I N G S */
+
+char instring[80],     /* Latest input */
+     filenm[80] = "",  /* Filename */
+     altnm[80] = "";   /* Alternate filename */
+char gcb[16];          /* Command buffer for mutations of insert */
+
+char undobuf[40];
+char undotmp[40];
+char yankbuf[40];
+
+HANDLE uread,          /* reading from the undo stack */
+       uwrite;         /* writing to the undo stack */
+
+                           /* B U F F E R S */
+char rcb[256];         /* last modification command */
+char *rcp;             /* this points at the end of the redo */
+char core[SIZE+1];     /* data space */
+
+struct ybuf yank;      /* last deleted/yanked text */
+
+
+/* STATIC INITIALIZATIONS: */
+
+/* ttydef stuff */
+
+#if ST | TERMCAP
+int LINES, COLS;
+#endif
+
+#if ZTERM
+char *TERMNAME = "zterm",
+     *HO  = "\001",    /* goto top of screen */
+     *UP  = "\002",    /* move up 1 line? */
+     *CE  = "\003",    /* clear to end of line */
+     *CL  = "\004",    /* clearscreen */
+     *OL  = "\005",    /* open current line down */
+     *UpS = "\006",    /* scroll up 1 line */
+     *BELL= "\007",    /* ring the bell */
+     *CM  = "yes",     /* cursor movement exists */
+     *CURoff,
+     *CURon;
+#endif /*ZTERM*/
+
+#if ANSI
+#if MSDOS
+char *TERMNAME = "braindamaged ansi",
+#else
+char *TERMNAME = "hardwired ansi",
+#endif
+     *HO  = "\033[H",
+     *UP  = "\033[A",
+     *CE  = "\033[K",
+     *CL  = "\033[H\033[J",
+#if MSDOS
+     *OL  = NULL,
+     *UpS = NULL,
+#else
+     *OL  = "\033[L",
+     *UpS = "\033[L",
+#endif
+     *BELL= "\007",
+     *CM  = "\033[%d;%dH",
+     *CURoff,
+     *CURon;
+#endif /*ANSI*/
+
+#if VT52
+#if ST
+char *TERMNAME = "Atari ST",
+#else
+#if FLEXOS
+char *TERMNAME = "Flexos console",
+#else
+char *TERMNAME = "hardwired vt52",
+#endif /*FLEXOS*/
+#endif /*ST*/
+     *HO  = "\033H",
+     *UP  = "\033A",
+     *CE  = "\033K",
+     *CL  = "\033E",
+     *OL  = "\033L",
+     *BELL= "\007",
+     *CM  = "\033Y??",
+#if FLEXOS
+     *UpS = NULL,      /* Reverse scrolling is painfully slow */
+#else
+     *UpS = "\033I",
+#endif
+     *CURoff= "\033f",
+     *CURon = "\033e";
+#endif /*VT52*/
+
+#if TERMCAP
+bool CA, canUPSCROLL;
+char FkL, CurRT, CurLT, CurUP, CurDN;
+
+char *TERMNAME,                /* will be set in termcap handling */
+     *HO,
+     *UP,
+     *CE,
+     *CL,
+     *OL,
+     *BELL,
+     *CM,
+     *UpS,
+     *CURoff,
+     *CURon;
+#endif /*TERMCAP*/
+
+char erasechar = ERASE,                        /* our erase character */
+     eraseline = DEL;                  /* and line-kill character */
+
+char ED_NOTICE[]  = "(c)3.4",          /* Editor version */
+     ED_REVISION = 'm',                        /* Small revisions & corrections */
+     fismod[] = "File is modified",    /* File is modified message */
+     fisro[] = "File is readonly";     /* when you can't write the file */
+
+char *excmds[] = {
+       "print",        /* lines to screen */
+       "quit",         /* quit editor */
+       "read",         /* add file to buffer */
+       "edit",         /* replace buffer with file */
+       "write",        /* write out file */
+       "wq",           /* write file and quit */
+       "next",         /* make new arglist or traverse this one */
+       "substitute",   /* pattern */
+       "xit",          /* write changes and quit */
+       "file",         /* show/set file name */
+       "set",          /* options */
+       "rm",           /* a file */
+       "previous",     /* back up in arglist */
+       "delete",       /* lines from buffer */
+       "=",            /* tell line number */
+       "yank",         /* lines from buffer */
+       "put",          /* back yanked lines */
+       "visual",       /* go to visual mode */
+       "exec",         /* go to exec mode */
+       "insert",       /* text below current line */
+       "open",         /* insert text above current line */
+       "change",       /* lines */
+       "undo",         /* last change */
+       "!",            /* shell escape */
+       "map",          /* keyboard macro */
+       "unmap",        /* keyboard macro */
+       "source",       /* read commands from file */
+       "version",      /* print version # */
+       "args",         /* print argument list */
+       "rewind",       /* rewind argument list */
+       NULL
+};
+
+char wordset[] = "0123456789$_#ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+char spaces[] = { TAB,EOL,' ',0 };
+
+int shiftwidth = 4,
+#if TERMCAP | ST
+    dofscroll,
+#else
+    dofscroll  = LINES/2,
+#endif
+    tabsize    = 8;
+int autoindent = YES,
+    autocopy   = NO,
+    autowrite  = YES,
+    wrapscan   = YES,
+    overwrite  = YES,
+    beautify   = YES,
+    list       = NO,
+    magic      = YES,
+    bell       = YES,
+#if ST
+    mapslash,
+#endif
+    ignorecase = NO;
+
+struct variable vars[]={
+    {"terminal",  "",  VSTR,   V_CONST,        (void*)&TERMNAME   },
+    {"shiftwidth","sw",        VINT,   0,              (void*)&shiftwidth },
+    {"scroll",   "",   VINT,   0,              (void*)&dofscroll  },
+    {"tabsize",   "ts",        VINT,   V_DISPLAY,      (void*)&tabsize    },
+    {"autoindent","ai",        VBOOL,  0,              (void*)&autoindent },
+    {"autocopy",  "ac",        VBOOL,  0,              (void*)&autocopy   },
+    {"autowrite", "aw",        VBOOL,  0,              (void*)&autowrite  },
+    {"wrapscan",  "ws",        VBOOL,  0,              (void*)&wrapscan   },
+    {"overwrite", "ow",        VBOOL,  0,              (void*)&overwrite  },
+    {"beautify",  "be",        VBOOL,  0,              (void*)&beautify   },
+    {"list",     "",   VBOOL,  V_DISPLAY,      (void*)&list       },
+    {"magic",    "",   VBOOL,  0,              (void*)&magic      },
+    {"ignorecase","ic",        VBOOL,  0,              (void*)&ignorecase },
+    {"bell",      "",  VBOOL,  0,              (void*)&bell       },
+#if ST
+    {"mapslash",  "ms", VBOOL, 0,              (void*)&mapslash   },
+#endif
+    {NULL}
+};
+
+/* For movement routines */
+int setstep[2] = {-1,1};
+
+/* Where the last diddling left us */
+struct coord curpos={0, 0};
+
+    /* initialize the buffer */
+int  bufmax = 0,               /* End of file here */
+     lstart = 0, lend = 0,     /* Start & end of current line */
+     ptop   = 0, pend = 0,     /* Top & bottom of CRT window */
+     curr   = 0,               /* Global cursor pos */
+     xp     = 0, yp   = 0,     /* Cursor window position */
+     count  = 0;               /* Latest count */
+
+bool modified= NO,             /* File has been modified */
+     readonly= NO,             /* is this file readonly? */
+     needchar= YES,            /* Peekc flag */
+     deranged= NO,             /* Up-arrow || down-arrow left xpos in Oz. */
+     indirect= NO,             /* Reading from an indirect file?? */
+     redoing = NO,             /* doing a redo? */
+     xerox   = NO,             /* making a redo buffer? */
+     newfile = YES,            /* Editing a new file? */
+     newline = NO,             /* Last insert/delete included a EOL */
+     lineonly= NO,             /* Dumb terminal? */
+     zotscreen=NO,             /* ask for [more] in execmode */
+     diddled = NO;             /* force new window in editcore */
+
+int  macro = -1;               /* Index into MCR */
+char nlsearch = 0;             /* for N and n'ing... */
+
+/* movement, command codes */
+
+cmdtype movemap[256]={
+    /*^@*/ BAD_COMMAND,
+    /*^A*/ DEBUG_C,
+    /*^B*/ HARDMACRO,
+    /*^C*/ BAD_COMMAND,
+    /*^D*/ WINDOW_UP,
+    /*^E*/ HARDMACRO,
+    /*^F*/ HARDMACRO,
+    /*^G*/ FILE_C,
+    /*^H*/ GO_LEFT,            /* also leftarrow  */
+    /*^I*/ REDRAW_C,
+    /*^J*/ GO_DOWN,            /* also downarrow  */
+    /*^K*/ GO_UP,              /* also uparrow    */
+    /*^L*/ GO_RIGHT,           /* also rightarrow */
+    /*^M*/ CR_FWD,
+    /*^N*/ BAD_COMMAND,
+    /*^O*/ BAD_COMMAND,
+    /*^P*/ BAD_COMMAND,
+    /*^Q*/ BAD_COMMAND,
+    /*^R*/ BAD_COMMAND,
+    /*^S*/ BAD_COMMAND,
+    /*^T*/ BAD_COMMAND,
+    /*^U*/ WINDOW_DOWN,
+    /*^V*/ BAD_COMMAND,
+    /*^W*/ BAD_COMMAND,
+    /*^X*/ BAD_COMMAND,
+    /*^Y*/ HARDMACRO,
+    /*^Z*/ BAD_COMMAND,
+    /*^[*/ BAD_COMMAND,
+    /*^\*/ BAD_COMMAND,
+    /*^]*/ BAD_COMMAND,
+    /*^^*/ BAD_COMMAND,
+    /*^_*/ BAD_COMMAND,
+    /*  */ GO_RIGHT,
+    /*! */ BAD_COMMAND,
+    /*" */ BAD_COMMAND,
+    /*# */ BAD_COMMAND,
+    /*$ */ TO_EOL,
+    /*% */ MATCHEXPR,
+    /*& */ RESUBST_C,
+    /*\ */ TO_MARK_LINE,
+    /*( */ SENT_BACK,
+    /*) */ SENT_FWD,
+    /** */ BAD_COMMAND,
+    /*+ */ CR_FWD,
+    /*, */ BAD_COMMAND,
+    /*- */ CR_BACK,
+    /*. */ REDO_C,
+    /*/ */ PATT_FWD,
+    /*0 */ BAD_COMMAND,
+    /*1 */ BAD_COMMAND,
+    /*2 */ BAD_COMMAND,
+    /*3 */ BAD_COMMAND,
+    /*4 */ BAD_COMMAND,
+    /*5 */ BAD_COMMAND,
+    /*6 */ BAD_COMMAND,
+    /*7 */ BAD_COMMAND,
+    /*8 */ BAD_COMMAND,
+    /*9 */ BAD_COMMAND,
+    /*: */ COLIN_C,
+    /*; */ BAD_COMMAND,
+    /*< */ ADJUST_C,
+    /*= */ BAD_COMMAND,
+    /*> */ ADJUST_C,
+    /*? */ PATT_BACK,
+    /*@ */ BAD_COMMAND,
+    /*A */ A_AT_END,
+    /*B */ BACK_WD,
+    /*C */ HARDMACRO,
+    /*D */ HARDMACRO,
+    /*E */ BAD_COMMAND,
+    /*F */ BACK_CHAR,
+    /*G */ GLOBAL_LINE,
+    /*H */ PAGE_BEGIN,
+    /*I */ I_AT_NONWHITE,
+    /*J */ JOIN_C,
+    /*K */ BAD_COMMAND,
+    /*L */ PAGE_END,
+    /*M */ PAGE_MIDDLE,
+    /*N */ BSEARCH,
+    /*O */ OPENUP_C,
+    /*P */ PUT_AFTER,
+    /*Q */ EDIT_C,
+    /*R */ BIG_REPL_C,
+    /*S */ BAD_COMMAND,
+    /*T */ BACKTO_CHAR,
+    /*U */ BAD_COMMAND,
+    /*V */ BAD_COMMAND,
+    /*W */ FORWD,
+    /*X */ HARDMACRO,
+    /*Y */ HARDMACRO,
+    /*Z */ ZZ_C,
+    /*[ */ BAD_COMMAND,
+    /*\ */ BAD_COMMAND,
+    /*] */ BAD_COMMAND,
+    /*^ */ NOTWHITE,
+    /*_ */ BAD_COMMAND,
+    /*` */ TO_MARK,
+    /*a */ APPEND_C,
+    /*b */ BACK_WD,
+    /*c */ CHANGE_C,
+    /*d */ DELETE_C,
+    /*e */ FORWD,
+    /*f */ TO_CHAR,
+    /*g */ BAD_COMMAND,
+    /*h */ GO_LEFT,
+    /*i */ INSERT_C,
+    /*j */ GO_DOWN,
+    /*k */ GO_UP,
+    /*l */ GO_RIGHT,
+    /*m */ MARKER_C,
+    /*n */ FSEARCH,
+    /*o */ OPEN_C,
+    /*p */ PUT_BEFORE,
+    /*q */ BAD_COMMAND,
+    /*r */ REPLACE_C,
+    /*s */ HARDMACRO,
+    /*t */ UPTO_CHAR,
+    /*u */ UNDO_C,
+    /*v */ BTO_WD,
+    /*w */ TO_WD,
+    /*x */ HARDMACRO,
+    /*y */ YANK_C,
+    /*z */ REWINDOW,
+    /*{ */ PARA_BACK,
+    /*| */ TO_COL,
+    /*} */ PARA_FWD,
+    /*~ */ TWIDDLE_C,
+    /*^?*/ BAD_COMMAND,
+    /*80*/ BAD_COMMAND,
+    /*81*/ BAD_COMMAND,
+    /*82*/ BAD_COMMAND,
+    /*83*/ BAD_COMMAND,
+    /*84*/ BAD_COMMAND,
+    /*85*/ BAD_COMMAND,
+    /*x6*/ BAD_COMMAND,
+    /*x7*/ BAD_COMMAND,
+    /*x8*/ BAD_COMMAND,
+    /*x9*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND,
+    /*xx*/ BAD_COMMAND
+    };
diff --git a/Applications/levee/grep.h b/Applications/levee/grep.h
new file mode 100644 (file)
index 0000000..fca8841
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#define LEND   '$'
+#define LSTART '^'
+#define LITCHAR        'c'
+#define ANY    '.'
+#define CCL    '['
+#define NCCL   '!'
+#define DASH   '-'
+#define CCLEND ']'
+#define        NEGATE  '^'
+#define CLOSURE        '*'
+#define ESCAPE '\\'
+#define        TOKENB  '<'
+#define        TOKENE  '>'
+
+#define ARGSTART '('
+#define ARGEND ')'
+#define AMPERSAND '&'
diff --git a/Applications/levee/insert.c b/Applications/levee/insert.c
new file mode 100644 (file)
index 0000000..65b483a
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+#include <string.h>
+
+int PROC
+insertion(int count, int openflag, int *dp, int *yp, bool visual)
+{
+    char cmd, c;
+    int rp;            /* number of spaces to diddle */
+    int        ts, ss;         /* tabs && spaces to insert */
+    register cp;       /* current position */
+    int i;             /* random index */
+    int        endd;           /* last open place */
+    register rsize;    /* size of upper buffer */
+    int        currDLE = 0;    /* what DLE is now */
+    int        len;            /* full insert size */
+    bool Dflag;
+
+    if (openflag != 0) {       /* opening a line above || below */
+       if (openflag<0 && bufmax>0 && curr<bufmax) {
+           curr = 1+lend;
+           if (visual)
+               strput("\n");
+       }
+       else {                  /* open above current line */
+           (*yp)--;
+           curr = lstart;
+       }
+       if (autoindent)
+           currDLE = findDLE(lstart, &i, skipws(lstart),0);
+       if (visual)
+#if VT52
+           if (OL) {
+#else
+           if (OL && (*yp) < LINES-2) {
+#endif
+               strput(OL);
+               (*yp)++;
+               curpos.y = *yp;
+           }
+           else {
+               mvcur(1+(*yp), 0);
+               strput(CE);
+           }
+       mvcur(-1, currDLE);
+    }
+    else {
+       if (autoindent)
+           currDLE = findDLE(lstart, &i, curr, 0);
+       if (curr == i) {
+           if (!delete_to_undo(&undo, lstart, i-lstart))
+               return(-1);
+           curr = lstart;
+       }
+    }
+
+    rsize = (bufmax-curr);             /* amount of stuff above curr */
+    endd = SIZE - rsize;               /* split the buffer */
+    if (rsize > 0)
+       moveright(&core[curr], &core[endd], rsize);
+
+    cp = curr;
+    do {                               /* Insert loop */
+       Dflag = (cp==0 || core[cp-1]==EOL);
+       do {
+           if (Dflag)
+               while ((cmd=peekc()) == 0x14 || cmd == 0x04) {  /* handle ^T, ^D */
+                   if (readchar() == 0x14)
+                       currDLE = min(COLS,currDLE+shiftwidth);
+                   else
+                       currDLE = max(0,currDLE-shiftwidth);
+                   mvcur(-1, currDLE);
+               }
+       } while (!(c = line(core, cp, endd-1, &len)));
+       if (Dflag && (len > 0 || c == ESC)) {
+           /* makeDLE : optimize leading whitespace for insert */
+           currDLE = findDLE(cp, &rp, cp+len, currDLE);
+           if (rp > cp) {
+               len -= (rp-cp);
+               moveleft(&core[rp], &core[cp], len);    /* squash whitespace */
+           }
+           if (currDLE > 0) {                          /* create DLE indent */
+               ts = currDLE / tabsize;
+               ss = currDLE % tabsize;
+               moveright(&core[cp], &core[cp+ts+ss], len);
+               len += (ts+ss);
+               fillchar(&core[cp   ], ts, TAB);
+               fillchar(&core[cp+ts], ss, 32);
+           }
+       }
+       cp += len;
+       if (c == EOL) {         /* Diddle-Diddle */
+           core[cp++] = EOL;           /* add in a \n */
+           strput(CE);                         /* clear this line */
+           println();
+           if (visual) {
+#if RMX
+               /* at OL at bottom kludge... */
+               if (OL && (*yp) < LINES-2) {
+#else
+               if (OL) {
+#endif
+                   strput(OL);
+                   (*yp)++;
+               }
+               else
+                   strput(CE);
+           }
+           if (!autoindent)            /* reset currDLE? */
+               currDLE = 0;
+           mvcur(-1, currDLE);
+       }
+    } while (c != ESC && cp <= endd-INSSIZE);
+    *dp = cp;                                  /* start display here */
+
+    if (count > 1) {                           /* repeated insertion */
+       len = cp-curr;
+       if ((count-1)*len < endd-cp)
+           for (i = 1;i <count;i++) {
+               moveright(&core[cp-len], &core[cp], len);
+               cp += len;
+           }
+    }
+
+    if (openflag != 0          /* open or insert at end of buffer */
+           || (rsize < 1 && cp > curr && core[cp-1] != EOL))
+       core[cp++] = EOL;
+    len = cp-curr;
+
+    if (rsize > 0)     /* if not at end of buffer, stitch things together */
+       moveleft(&core[endd], &core[cp], rsize);
+    insert_to_undo(&undo, curr, len);
+    core[bufmax] = EOL;
+    return(cp);
+}
diff --git a/Applications/levee/levee b/Applications/levee/levee
new file mode 100644 (file)
index 0000000..ea0fc9d
Binary files /dev/null and b/Applications/levee/levee differ
diff --git a/Applications/levee/levee.bin b/Applications/levee/levee.bin
new file mode 100644 (file)
index 0000000..d428380
Binary files /dev/null and b/Applications/levee/levee.bin differ
diff --git a/Applications/levee/levee.h b/Applications/levee/levee.h
new file mode 100644 (file)
index 0000000..292eaa2
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1980-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *                       Levee v3.C
+ *   C version for Unix/Atari ST/MS-DOS/OS-2/FlexOs/iRMX/etc
+ *            Pascal version for UCSD Pascal 4.X
+ *
+ *     written fall 82' - now (approx) by David L. Parsons.
+ *
+ *               many patches, suggestions,
+ *             and impractical design goals by:
+ *                     Jim Bolland,
+ *                     John Plocher,
+ *                     John Tainter
+ */
+#ifndef LEVEE_D
+
+#define LEVEE_D
+#define        TOUPPER_FTN     /* defined if the libraries support toupper as */
+                       /* a function call */
+
+#ifndef TRUE
+#define        TRUE    (1)     /* Nobody defines TRUE & FALSE, so I will do */
+#define        FALSE   (0)     /* it myself */
+#endif
+
+#define        HANDLE  int     /* default file handle type */
+
+#define PROC           /* for magic function types (MSDOS) */
+
+/*
+ * Compilation defines for different systems.
+ * Choose only one from each group.
+ */
+/* system you are compiling Levee on */
+#define ST     0
+#define RMX    0
+#define UNIX   1
+#define MSDOS  0
+#define        FLEXOS  0
+
+/* do your libraries follow system V standards? */
+#define SYS5   1
+
+/* what sort of terminal are you emulating? */
+#define VT52   1               /* this must be nonzero for the Atari ST */
+#define TERMCAP        0
+#define ZTERM  0
+#define ANSI   0
+
+#if ST
+
+#include <stdio.h>
+
+#define        void    int     /* Alcyon C don't know void */
+
+/* extractions from osbind.h */
+#define OPEN_OLD(n)            gemdos(0x3d,n,/*open mode*/0)
+#define OPEN_NEW(n)            gemdos(0x3c,n,/*permissions*/0)
+#define CLOSE_FILE(f)          gemdos(0x3e,f)
+#define SEEK_POSITION(f,o,m)   gemdos(0x42,(long)(o),f,m)
+#define READ_TEXT(f,b,c)       gemdos(0x3f,f,(long)(c),b)
+#define WRITE_TEXT(f,b,c)      gemdos(0x40,f,(long)(c),b)
+
+extern char *malloc();
+extern long gemdos();
+
+#endif /*ST*/
+
+#if RMX
+#include <:inc:stdio.h>
+#include <:inc:udi.h>
+
+#define OPEN_OLD(n)            open(n, /*open mode*/0)
+#define OPEN_NEW(n)            creat(n,/*permissions*/0)
+#define CLOSE_FILE(f)          close(f)
+#define SEEK_POSITION(f,o,m)   lseek((f),(long)(o),(m))
+#define READ_TEXT(f,p,c)       read((f),(p),(unsigned)(c))
+#define WRITE_TEXT(f,p,c)      write((f),(p),(unsigned)(c))
+
+#define zwrite(p,s)    write(1,(p), (unsigned)(s))
+
+#endif /*RMX*/
+
+#if MSDOS
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#define OPEN_OLD(n)            open(n, O_RDONLY|O_BINARY)
+#define OPEN_NEW(n)            open(n, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666)
+#define CLOSE_FILE(f)          close(f)
+#define SEEK_POSITION(f,o,m)   lseek(f, (long)(o), (m))
+#define READ_TEXT(f,p,c)       read(f, p, (int)(c))
+#define WRITE_TEXT(f,p,c)      write(f, p, (int)(c))
+
+#define zwrite(p,s)    WRITE_TEXT(fileno(stdout), p, s)
+
+#undef PROC
+#define PROC   _fastcall
+
+#include "proto.h"
+
+#endif /*MSDOS*/
+
+#if UNIX
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#define OPEN_OLD(n)            open(n, O_RDONLY)
+#define OPEN_NEW(n)            open(n, O_WRONLY|O_CREAT|O_TRUNC, 0666)
+#define CLOSE_FILE(f)          close(f)
+#define SEEK_POSITION(f,o,m)   lseek(f, (long)(o), (m))
+#define READ_TEXT(f,p,c)       read(f, p, (int)(c))
+#define WRITE_TEXT(f,p,c)      write(f, p, (int)(c))
+
+#define zwrite(p,s)    WRITE_TEXT(fileno(stdout), p, s)
+
+#endif /*MSDOS*/
+
+#if FLEXOS
+
+#undef TOUPPER_FTN                     /* Nope, gotta do macro */
+
+#include <stdio.h>
+
+#define OPEN_OLD(n)            s_open(m,0x08)          /* note reversed parameters! */
+#define OPEN_NEW(n)            s_create(0,0,n,0,0/*mode*/,0)
+#define CLOSE_FILE(f)          s_close(0,f)            /* Full close on handle */
+#define SEEK_POSITION(f,o,m)   s_seek((m&03)<<9, f, o)
+#define        READ_TEXT(f,p,c)        s_read(0x0100,(long)(f),p,(long)(c),0L)
+#define        WRITE_TEXT(f,p,c)       s_write(0x0101,(long)(f),p,(long)(c),0L)
+
+#define        zwrite(p,s)             s_write(0x0101, 1L, p, (long)(s),0L)
+
+#define        unlink(n)               s_delete(0, n)
+#define        rename(a,b)             s_rename(0, a, b)
+
+/* OPEN_OLD mode flags */
+
+#undef HANDLE
+#define        HANDLE  long
+
+#endif /*FLEXOS*/
+
+#define bool int
+
+/* ttydef stuff */
+#if !(ST | TERMCAP)
+
+#ifndef LINES
+#define LINES  25
+#endif  /*LINES*/
+#define COLS   79
+
+#endif
+
+#define        YES     1
+#define        NO      0
+
+#define UPARROW        11
+#define DNARROW        10
+#define LTARROW        erase
+#define RTARROW        12
+
+#if !TERMCAP
+#define CA     TRUE
+#define canUPSCROLL !(MSDOS|FLEXOS)
+#endif
+
+/* nospecific stuff */
+#define MAGICNUMBER  42
+#define hell_freezes_over  FALSE
+#define BUGS   7       /* sometime when you least expect it.. */
+
+#define DW     23      /* Delete Word */
+#define EOL    10      /* End Of Line */
+#define DLE    16      /* Space compression lead-in */
+#define ESC    27      /* Escape */
+
+/* hardwired line kill and erase character for non-unix machines */
+#define DEL    21      /* ^U */
+#if RMX
+#define ERASE  127
+#else
+#define ERASE  8       /* ^H */
+#endif
+
+#define TAB    9
+    
+       /* variable types */
+#define VBOOL  0
+#define VINT   1
+#define VSTR   2
+
+#define ERR    (-1)
+
+               /* Undostack commands */
+#define U_ADDC 'A'
+#define U_MOVEC        'M'
+#define U_DELC 'D'
+
+               /* magic things for find */
+#define MAXPAT ((int)300)
+
+               /* exec mode commands */
+#define        EX_CR           (ERR-1)
+#define EX_PR          0
+#define EX_QUIT                1
+#define EX_READ                2
+#define EX_EDIT                3
+#define EX_WRITE       4
+#define EX_WQ          5
+#define EX_NEXT        6
+#define EX_SUBS        7
+#define EX_XIT         8
+#define EX_FILE        9
+#define EX_SET         10
+#define EX_RM          11
+#define EX_PREV        12
+#define EX_DELETE      13
+#define EX_LINE                14
+#define EX_YANK                15
+#define EX_PUT         16
+#define EX_VI          17
+#define EX_EX          18
+#define EX_INSERT      19
+#define EX_OPEN                20
+#define EX_CHANGE      21
+#define EX_UNDO                22
+#define EX_ESCAPE      23
+#define EX_MAP         24
+#define EX_UNMAP       25
+#define EX_SOURCE      26
+#define EX_VERSION     27
+#define EX_ARGS                28
+#define        EX_REWIND       29
+
+               /* movement return states */
+#define LEGALMOVE      0
+#define BADMOVE                1
+#define ESCAPED                2
+#define findstates char
+
+               /* command codes */
+#define BAD_COMMAND    0
+               /*visual movement*/
+#define GO_RIGHT       1
+#define GO_LEFT                2
+#define GO_UP          3
+#define GO_DOWN                4
+#define FORWD          5
+#define TO_WD          6
+#define BACK_WD                7
+#define BTO_WD         8
+#define NOTWHITE       9
+#define TO_COL         10
+#define TO_EOL         11
+#define MATCHEXPR      12
+#define TO_CHAR                13
+#define UPTO_CHAR      14
+#define BACK_CHAR      15
+#define BACKTO_CHAR    16
+#define SENT_FWD       17
+#define SENT_BACK      18
+#define PAGE_BEGIN     19
+#define PAGE_END       20
+#define PAGE_MIDDLE    21
+#define CR_FWD         22
+#define CR_BACK                23
+#define PATT_FWD       24
+#define PATT_BACK      25
+#define FSEARCH                26
+#define BSEARCH                27
+#define GLOBAL_LINE    28
+#define TO_MARK                29
+#define TO_MARK_LINE   30
+#define PARA_FWD       31
+#define PARA_BACK      32
+               /*modifications*/
+#define DELETE_C       40
+#define ADJUST_C       41
+#define CHANGE_C       42
+#define YANK_C         43
+#define INSERT_C       44
+#define APPEND_C       45
+#define I_AT_NONWHITE  46
+#define A_AT_END       47
+#define OPEN_C         48
+#define OPENUP_C       49
+#define REPLACE_C      50
+#define TWIDDLE_C      51
+#define RESUBST_C      52
+#define JOIN_C         53
+#define UNDO_C         54
+#define BIG_REPL_C     55
+#define PUT_BEFORE     56
+#define PUT_AFTER      57
+               /*everything else*/
+#define HARDMACRO      70
+#define REWINDOW       71
+#define ZZ_C           72
+#define DEBUG_C                73
+#define FILE_C         74
+#define WINDOW_UP      75
+#define WINDOW_DOWN    76
+#define REDRAW_C       77
+#define MARKER_C       78
+#define REDO_C         79
+#define EDIT_C         80
+#define COLIN_C                81
+                   /*macros*/
+#define SOFTMACRO      100
+#define INSMACRO       101
+#define cmdtype                char
+
+               /* exec mode states */
+#define E_VISUAL 0
+#define E_INIT  1
+#define E_EDIT  2
+#define exec_type      char
+
+               /* various sizes */
+#define INSSIZE         ((int)80)              /* Insert string size */
+#define FSIZE   ((int)39)              /* File string size */
+#ifndef SIZE
+# define SIZE   ((int)4096)            /* Edit buffer size */
+#endif
+
+#define SBUFSIZE  ((int)512)           /* Incore yank buffer size */
+#define MAXMACROS 32                   /* Maximum # of macros */
+#define NMACROS          9                     /* Nexting level for macros */
+
+#define PAGESIZE ((int)512)            /* Bytes per block */
+
+struct coord {         /* Screen Coordinate */
+    int x,y;
+};
+
+struct ybuf {          /* Yank Buffer */
+    int size;                          /* Bytes yanked */
+    bool lines,                                /* Yanked whole lines? */
+       has_eol;                        /* Yanked a EOL? */
+    char stuff[SBUFSIZE];              /* The stuff */
+};
+
+struct undostack {     /* Undo Stack Descriptor */
+    int blockp,                                /* block address of core block */
+       ptr;                            /* offset within coreblock */
+    int coreblock[PAGESIZE];           /* core block */
+};
+
+union optionrec {      /* Black Magic Option Structure */
+    int valu;                          /* if integer, the value */
+    char *strp;                                /* or if string, a pointer to it */
+};
+
+struct macrecord {     /* Macro Descriptor */
+    char token;                                /* Character mapped */
+    cmdtype oldmap;                    /* Old value in movemap */
+    char *m_text;                      /* Replacement text */
+};
+                   
+struct tmacro {                /* For running a macro */
+    char *mtext,       /* Pointer to macro text */
+        *ip;           /* Pointer into macro text */
+    int  m_iter;       /* Number of times to execute */
+};
+
+#define V_CONST        1       /* this option cannot be modified */
+#define V_DISPLAY 2    /* this option affects the display */
+
+struct variable {      /* Settable Variable Record */
+    char *v_name;              /* full name */
+    char *v_abbr;              /* abbreviated name */
+    int v_tipe;                        /* what kind of variable */
+    int v_flags;               /* special attributes... */
+    union optionrec *u;                /* pointer to it */
+};
+
+#include "proto.h"
+
+#endif /*LEVEE_D*/
diff --git a/Applications/levee/lv.doc b/Applications/levee/lv.doc
new file mode 100644 (file)
index 0000000..0922341
--- /dev/null
@@ -0,0 +1,873 @@
+    Levee.                                     A Screen Oriented Editor.
+
+    USAGE
+       lv [+address] [file ...]
+
+    SYNOPSIS
+       Levee is a screen oriented  editor based on the  Unix editor
+    "vi".  It provides a terse,  powerful way to enter and edit text
+    (however,  if you want a word-processor,  you're better off with
+    WordStar.)
+
+    DESCRIPTION
+       Levee is a moded editor.  It operates in 3 modes  -- visual,
+    command, and insert.  Most of the editing work is done is visual
+    mode,  file reading and  writing is  done in  command mode,  and
+    insert mode does what you would expect.
+       When you enter Levee,  you may specify  an  address to start
+    editing at.  These addresses  are in the same  format as command
+    mode addresses,  except that a naked + will put  you at the very
+    end of the file.
+
+      Levee is copyright (c) 1982-1997 by David L. Parsons. (see
+      the notice at the end of this document for distribution terms)
+
+\f    Levee.                                    A Screen Oriented Editor.
+    COMMANDS
+
+    Command mode commands:
+
+           These commands are used for  editing new files,  writing
+       modified files,  changing options, doing substitutions,  and
+       a subset of  the visual commands.  They take as  input whole
+       lines,  terminated  by  return (to execute),  or  escape (to
+       abort.)
+           
+           Command mode is reached by typing ":" or "Q" from visual
+       mode.  If you enter command  mode by typing ":",  Levee will
+       execute  one  command,   then return  to  visual  mode after
+       prompting you  with  "[more]".   If you type anything except
+       a space or return, Levee will accept another command, and so
+       forth.  If,  however, you enter command mode via "Q",  Levee
+       will  remain in  command mode  until  you enter the "visual"
+       command.
+
+                       A NOTE ON COMMAND SYNTAX
+           A command may be preceded by an optional line-range.  If
+       you do not provide a line-range,  Levee will use the default
+       line-range shown by the command.  A line-range is one or two
+       address specifications in the following format:
+       
+               (.|$|'x|#) [ (+|-) (/patt/|?patt?|#) ]
+
+                   .  => current line.
+                   $  => last line.
+                   'x => the line with mark x on it.
+                   #  => line #.
+           
+           For example, ".-5,.+5p" will print every line within ten
+       lines of the current line.  "$-5" is the fifth line from the
+       end of the file,  and "/end/+2"  is the second line past the
+       next  occurrence  of  the  pattern "end".  Patterns  may  be
+       regular expressions (see below.)
+           
+           Also,  a naked line-range will  set the current  line to
+       the first line in the range  and print all the lines in that
+       range. "1,10" sets the current line to 1,  then prints lines
+       1 to 10.
+
+           If you specify a non-existent line in a range, the comm-
+       and will abort and Levee will tell you "bad address".
+
+    Regular expressions:
+           Levee gives  special meanings to  some characters during
+       a pattern match.  The character "." will match any one char,
+       the character "*" will match zero or  more occurances of the
+       previous char ( so, a* will match 'a','aa','aaa', etc, or it
+       will match nothing at all). If a pattern begins with "^", it
+       will  only match  at the  beginning of a line,  and patterns
+       ending with a "$" will only match at the end of a line.
+
+\f    Levee.                                    A Screen Oriented Editor.
+           Brackets ('[]') have special meaning as well.  They mean
+       match any one of the characters inside the brackets. '[abc]'
+       will  match  'a', 'b', or 'c'.  You may  specify  a range of
+       characters inside brackets by using a dash (-). '[a-z]' will
+       match any lowercase alphabetic character.  If ^ is the first
+       character  in  the  bracket,  it means match  any  character
+       except those in the brackets.   '[^abc]' will match anything
+       except 'a','b', or 'c'.
+
+           Backslash takes away  special  meaning  for these chars,
+       but '\t' specifies  a  tab,  and \( & \)  delimit  arguments
+       inside a pattern (used only by :substitute.)    The patterns
+       \< and \> have special  meaning,  too;  they match the start
+       and end of alpha-numeric tokens.
+
+           If you  turn off  the editor variable  'magic',  none of
+       the above  characters will  have special  meaning  inside of
+       a pattern (see 'set').
+
+           Some example patterns:
+
+               ^end$           Find a line that is just 'end'.
+               [Ee][Nn][Dd]    Find a 'end', ignoring case.
+               [A-Za-z][A-Za-z0-9]* Find the next identifier.
+               (\*.*\*)        Find the next one-line pascal
+                               comment.
+               \<the\>         Find the next occurance of `the'.
+
+\f    Levee.                                    A Screen Oriented Editor.
+
+---------------
+    args
+       show the current argument list, if one exists. The file that you
+    are currently editing will be framed by '[' and ']'.
+
+---------------
+    (.,.) change
+       delete lines, then enter insert mode.
+
+---------------
+    (.,.) delete
+       delete lines. Deleted lines are stored in a Yank Buffer for
+    later putback with "put".
+
+---------------
+    edit[!] [file]
+       Discard the current file and start editing a new one. If
+    changes were made to the current file, you must enter "edit!"
+    to force Levee to discard the changes. If you do not specify
+    a filename, Levee will try to reedit the current filename.
+
+       When Levee reads in a new file, it will tell you how many
+    bytes it read in, or [overflow] if the file is larger than the
+    internal buffer (currently 32760 bytes.)
+
+---------------
+    execmode
+       Remain in command mode until you use the "visual" command.
+    
+---------------
+    file [name]
+       Echo what the current filename is, its status, and the current
+    line. If you provide it with a name, it will change the filename
+    to that.
+
+---------------
+    (.) insert
+       Insert text above the current line. If you specify a line number,
+    Levee will make that the current line, then insert above it.
+
+       Commands within insert mode:
+           ^W   => back over the last word you entered.
+           ^H   => back over one character.
+           ^U   => back over all input on this line.
+           ^V   => escape the next character typed.
+                   ^V^H will put a ^H into the file.
+           ESC  => exit insert mode.
+           ^D   => If at start of line, reduce indentation 'shiftwidth'
+                   columns.
+           ^T   => If at start of line, increase indentation
+                   'shiftwidth' columns.
+
+       When in insert mode, Levee will not allow you to enter any control
+    characters except return and tab.  Return ends input on this line and
+    opens a new line for input.
+
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+    map[!] [key [text]]
+       Define/list macros.  There are 3 forms of map:
+
+           1) map.         This lists all the active macros.
+           2) map (key).   This shows the macro associated with (key),
+                           if any.
+           3) map (key) (text)
+                           This maps (key) to (text). You may map any
+                           key except ":" and escape. In the normal
+                           form (map), the macro will be effective
+                           in visual mode, but in the alternate form,
+                           (map!), the macro will be effective in
+                           insert and command modes.
+
+       For example, if you map!ped return to "hello world", every time
+    you entered a return in command or visual mode, the string "hello
+    world" would pop up.
+
+---------------
+    next [file ...]
+       Edit the next file in the arglist, or edit a new arglist. Levee
+    takes its initial arglist off the command line when you execute it.
+    If "autowrite" is set, Levee will write out the changes to the
+    current file before editing the next one.
+
+---------------
+    (.) open
+       Insert below the current line. Otherwise just like insert.
+
+---------------
+    previous
+       Edit the previous file in the arglist. Otherwise, like next.
+
+---------------
+    (.,.) print
+       Display lines without changing the current line.
+
+---------------
+    (.) put
+       Put the contents of the yank buffer back on the line below
+    the current line. If you specify a line, it resets the current
+    line, then puts the yank buffer back. The yank buffer is filled
+    by the delete, change, or yank commands. Put does not destroy
+    the yank buffer, so you may put back text multiple times.
+
+---------------
+    quit[!]
+       Exit Levee. If you want to discard changes, use "quit!"
+
+---------------
+    (.) read [file]
+       put the contents of 'file' after the current line.
+
+---------------
+    rm file
+       Delete 'file' from disk.
+
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+    set [option=value]
+       Set a tunable variable. Levee has a dozen or so user-definable
+    variables which you can twiddle via this command. There are boolean,
+    integer, and string variables that you can set. A string or integer
+    variable is set by 'set xxx=yyy', a boolean variable is set via
+    'set xxx' or 'set noxxx'.
+
+       Here are the settable variables (and abbreviations):
+           tabsize     (ts)    tab stop.
+           shiftwidth  (sw)    columns to shift on ^D, ^T, >>, or <<
+           scroll              number of lines to scroll on ^D, ^U
+           autoindent  (ai)    supply indentation during insert mode.
+           autowrite   (aw)    write out changes before :next, :prev
+           autocopy    (ac)    make backup copies of before writing.
+           list                display tabs as ^I, end of line as $.
+           magic               use regular expressions in searches.
+           suffix              if the filename does not have a . in
+                               it, supply the suffix. (this is the
+                               only string variable.)
+           overwrite   (ow)    destroy old file first, then write.
+           beautify    (be)    When set, Levee will not allow insert
+                               of any control character except tab
+                               and return unless you escape it with
+                               ctrl-V.
+           wrapscan            searches wrap around end of buffer.
+           ignorecase  (ic)    Ignore the case of alphabetic characters
+                               during searches.
+           mapslash            (ST version only) Map '/' in filenames to
+                               '\'.  If the environment contains `mapslash'
+                               when levee is called, this variable will
+                               default to true, otherwise it defaults to
+                               false. (See the documentation for the
+                               Teeny-shell on how the teeny-shell interprets
+                               `mapslash')
+           lines (li)          (ST version only) How many lines on the display.
+                               This is primarily for running levee through
+                               the serial port - put set li=xx into your
+                               LVRC for a xx line terminal.
+           cols (co)           (ST version only) How many columns on the
+                               display.  Like the lines variable, it's for
+                               running levee through the serial port.
+           
+       You may set multiple variables on one line, as in 'set ws noai'.
+    To see the current settings of these variables, :set -- without any
+    arguments -- will show the current settings.
+
+       At startup, Levee looks in the environment variable LVRC for
+    a list of variables to set (GEMDOS/MS-DOS). LVRC is one line
+    of the form 'option=value ...'. If you have a LVRC defined that
+    is 'ts=4 ow nows', Levee will set tabsize to 4, turn on overwrite,
+    and turn off wrapscan.
+
+       If you are using RMX, Levee looks in the file ":home:r?lvrc"
+    for initialization. If you are using Osy/SWOs, Levee looks in the
+    file "*.lvrc". The format of these files are different from the
+    LVRC variable -- see "source" for more information.
+
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+    source file
+       Take command mode commands from 'file'. These commands can be
+    any legal command, except "visual". If a error happens during
+    execution of 'file', Levee abandons that level of source'ing.
+
+       In Osy/SWOs, there are a few differences in insert mode from
+    within a sourced file. No character has special meaning except a
+    line  containing nothing but a period, which terminates insert mode.
+    For example:
+
+           :commands
+               .
+               .
+           :insert
+               blah blah blah blah blah blah
+               blah blah blah blah blah blah
+               blah blah blah blah blah blah
+           .
+           :more commands
+
+       If you are running Levee under any other operating system,
+    you cannot do a insert from a :source file.
+
+NOTE:  If you are running Levee on RMX or Osy/SWOs, it will read
+    ":home:r?lvrc" or "*.lvrc" at startup. These can consist of any
+    legal command mode instruction, just like any other source file.
+           
+---------------
+    (.,.)substitute(delim)patt(delim)repl(delim)[qcpg]
+    (.,.)substitute&
+       Search for patt and replace it with repl. Levee will look for
+    patt once on each line and replace it with repl. The delimiter
+    may be any ascii character.
+
+       The pattern is a regular expression, just like a search
+    pattern.
+
+       You may include parts of the pattern in the replacement string;
+    A '&' in the replacement pattern copies in the whole source pattern,
+    so if you do a 'sub/this/& and that/g', every instance of 'this'
+    will be replaced with 'this and that'.  Also, you may pull parts of
+    the pattern out by using the \( and \) argument meta-characters.
+    Arguments gotten by \( & \) are put into the replacement string
+    everywhere you do a \1..\9 [ \1 is the first argument you set up
+    with \( & \) ]. So, if you want to reverse the order of two substrings,
+    you can do 'sub/\(string1\)\(string2\)/\2\1/'.
+
+       substitute& redoes the last substitution.
+
+       Options:
+           q,c  => before doing the substitute, display the affected
+                   line and wait for you to type a character. If you
+                   type 'y', it will do the substitution. 'q' aborts
+                   the substitute,  'a'  does the rest of the change
+                   without prompting, and 'n' does not do it.
+           p    => print the affected lines after the change.
+           g    => do the change globally. That is, do it for every
+                   occurence  of patt on a  line,  rather than just
+                   once.
+       
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+    undo
+       Undo the last modification to the file (except :edit, :next, :rm,
+    or :write.) You can only undo the last change to a file -- undo counts
+    as a change. :undo followed by :undo does nothing to the file.
+
+---------------
+    unmap (key)
+       Undefine a macro (see map).
+
+---------------
+    visual [list]
+       If you entered command mode by "Q" or "execmode", return to
+    visual mode.  If you provide an argument list, it also does a
+    `:next' on that list.
+
+---------------
+    version
+       Show which version of levee this is.
+
+---------------
+    (.,.) write [file]
+       Write lines to a file. If you write the everything to 'file',
+    the filename is set to 'file', and if you do not specify a file,
+    Levee will write to the filename.
+
+---------------
+    (.,.) wq [file]
+       Write to a file, then quit.
+
+---------------
+    (.,.) yank
+       Yank lines from the file into the yank buffer, for later
+    putback with "put".
+
+---------------
+    xit[!]
+       Write changes to the current file, then exit. If there are
+    more files in the arglist, use "xit!"
+
+---------------
+    ![command]
+       Execute command.
+
+       Example:
+           !ls    => does a 'ls'.
+
+       This command is available only under GEMDOS, MSDOS, and RMX.
+
+---------------
+    ($)=
+       Give the line number of the addressed line. /end/= gives you
+    the line number of the next line with a 'end' on it.
+
+---------------
+\f    Levee.                                    A Screen Oriented Editor.
+    Visual mode commands.
+           Visual mode commands move you around  and modify the file.
+       There are movement commands to move the cursor by a variety of
+       objects.
+
+           In the description,  a (#)  means a optional  count.  If a
+       command has a optional count,  it will tell you what the count
+       does in parenthesis.  A (*) means that the command can be used
+       in the delete, yank, and change commands.
+
+           Counts are made up by  entering digits.  If you type '45',
+       the count will be set to 45. To cancel a count, type ESC.
+
+           This section discusses 'whitespace' occasionally.
+       Whitespace is tabs, spaces, and end of line.
+
+    How the display works.
+       
+           Characters  are  displayed  on  the  screen  as  you would
+       expect,  except that  nonprinting characters are  shown as ^x,
+       and tabs  expand to  spaces ( unless you  set the option list,
+       then they show as ^I.)  When sitting on a control character or
+       tab, the cursor is placed on the FIRST character displayed. If
+       you move the cursor to  any other part of them ( via j or k --
+       see below), any changes will start at the next character.
+       
+           Levee  does  not  display a end of  file marker, but lines
+       past the end of the file are denoted by ~ lines.
+
+           If list is  set,  tabs  display as ^I, and the end of line
+       displays as $.
+
+           If a  line is too long for the screen,  it will  just dis-
+       appear off the end of the screen.
+
+           Levee will handle any screen resolution and any monospaced
+       font you hand it ( if you are running in low resolution, Levee
+       will give you a 25x40 window, for example.)
+
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+       ^A
+    Show a debugging message at the bottom of the screen. This is not at
+    all useful unless you are debugging the editor. Ignore it.
+
+---------------
+       (#)^D
+    Scroll the screen down a half screen. If a count is specified, scroll
+    down the specified number of lines.
+
+---------------
+       ^E
+    Scroll down 1 line (shorthand for 1^D )
+
+---------------
+       ^G
+    Show file statistics. Exactly like ':file'.
+
+(*)------------
+       (#)^H
+    Move the cursor left one (count) chars.
+
+---------------
+       ^I
+    Redraw the screen.
+
+(*)------------
+       (#)^J
+    Move down one (count) lines. When you use ^J and ^K (below) to move
+    up or down lines, the cursor will remain in the same column, even if
+    it is in the middle of a tabstop or past the end of a line.
+
+(*)------------
+       (#)^K
+    Move up one (count) lines.
+
+(*)------------
+       (#)^L
+    Move right one (count) characters.
+
+(*)------------
+       (#)^M
+    Move to the first nonwhite space on the next line. If a count is specified,
+    move to the first nonwhite count lines down.
+
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+       (#)^U
+    Scroll the screen up a half page. If a count is specified, scroll up
+    count lines.
+
+---------------
+       ^Y
+    Scroll the screen up 1 line (shorthand for 1^U.)
+
+---------------
+       (#)a
+    Insert text AFTER the cursor. If you give a count, the insertion will
+    be repeated count times ( 40i-ESC will give you a line of 40 dashes).
+
+    The commands in insert mode are the same for visual and command mode.
+
+(*)------------
+       (#)b
+    Move to the beginning of the last word (the count'th word back).
+    A word is a collection of alphanumeric characters (a-z0-9$_#) or
+    any other nonwhite character (i.e. anything but space, tab, eoln).
+
+---------------
+       c
+    Change a object. Change deletes an object, then enters insert mode without
+    redrawing the screen. When you tell it the object to be changed, Levee
+    puts a '$' on the last character of the object. You cannot change
+    backwards.
+
+    The object may be any visual mode command marked with a '(*)'. For
+    example, 'c4l' will change the next 4 characters on the line to something
+    else. (4cl does the same thing -- 4c4l changes the next 16 characters on
+    this line.)
+
+    'cc' will change whole lines.
+
+    When changing, deleting, or yanking a object, it will be placed into
+    a yank buffer, where it can be retrieved by the 'p' or 'P' commands.
+    
+---------------
+       (#)d
+    Delete an object. Like 'cc', 'dd' effects whole lines.
+
+(*)------------
+       (#)e
+    Move to the end of the current word.
+
+(*)------------
+       (#)f(x)
+    Find the next (count'th) occurance of a character on the current line.
+    For example, if the cursor is sitting on the first character of the
+    line 'abcdef', typing "ff" will put the cursor on the 'f'.
+    
+(*)------------
+       (#)h
+    Move left one (count) characters. Exactly like ^H.
+
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+       (#)i
+    Start inserting characters at the cursor. If you specify a count,
+    the insertion will be duplicated count times.
+
+(*)------------
+       (#)j
+    Move down one (count) lines. Exactly like ^J.
+
+(*)------------
+       (#)k
+    Move up one (count) lines. Exactly like ^K.
+
+(*)------------
+       (#)l
+    Move right one (count) character. Exactly like ^L.
+
+---------------
+       m(x)
+    Set the marker (x). There are 26 markers available (a-z). You may
+    move to a marker by use of the ' or ` commands.
+
+(*)------------
+       n
+    Find the next occurance of a search pattern. When you do a search with
+    a / or ? command, Levee will remember the pattern and the direction you
+    searched in. 'n' will search in the same direction for the pattern, 'N'
+    searches in the opposite direction.
+
+---------------
+       o
+    Open a line below the current line for insertion.
+
+---------------
+       p
+    Put yanked/deleted text back after the cursor. Text is yanked
+    by the delete (d,x,X,D), change (c,C,s,S), and yank (y,Y) commands.
+
+---------------
+       (#)r(x)
+    Replace characters (up to end of line) with (x). '4ra' will change the
+    next 4 characters after the cursor into 'aaaa'.
+
+---------------
+       (#)s
+    change one (count) characters. Shorthand for (#)cl.
+
+(*)------------
+       (#)t(x)
+    Move up to a character on the current line. If you are on the first
+    character of the line 'abcdef' and you type 'tf', you will end up sitting
+    on the 'e'.
+
+---------------
+       u
+    Undo last modification. You can undo ANY modification command except
+    :edit, :next, :rm, or :write. (Just like :undo).
+
+\f    Levee.                                    A Screen Oriented Editor.
+(*)------------
+       (#)v
+    Move back to the very end of the previous (count'th) word.
+    See 'b' for the definition of a word.
+
+(*)------------
+       (#)w
+    Move up to the very beginning of the next (count'th) word.
+
+---------------
+       (#)x
+    Delete one (count) characters forward. Shorthand for (#)dl.
+
+---------------
+       y
+    Yank an object for later use by put. 'yy' yanks whole lines.
+
+---------------
+       A
+    Append text at the end of the line. Shorthand for $a.
+
+(*)------------
+       (#)B
+    Move to the beginning of the current word. Exactly like 'b'.
+
+    NOTE: this is incorrect. the capitalized word movement commands should,
+    and will in the future, be used for movement by space-delimited words.
+
+---------------
+       C
+    Change to the end of the line. Shorthand for c$.
+
+---------------
+       D
+    Delete to the end of the line. Shorthand for d$.
+
+(*)------------
+       (#)F(x)
+    Move to the first (count'th) previous occurance of a character on the
+    current line. If you are sitting at the end of the line 'abcdef', typing
+    "Fa" will move you back to the 'a' at the start of the line.
+
+(*)------------
+       (#)G
+    Goto line. If you specify a count, Levee will move to that line, and if
+    there is no count, Levee moves to the absolute end of the file.
+
+    To get to the start of the file, type "1G". To the end, just "G".
+
+(*)------------
+       H
+    Move to the first nonwhite character at the top of the screen.
+
+---------------
+       I
+    Insert at the end of the current line. Shorthand for $i.
+
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+       (#)J
+    Join two (count+1) lines together. Joining appends the second line at
+    the end of the first, putting a space between them. If the first line
+    ends in whitespace, Levee will not put in a space.
+
+(*)------------
+       L
+    Move to the last nonwhite character on the last line of the screen.
+
+(*)------------
+       M
+    Move to the first nonwhite character in the middle of the screen.
+
+---------------
+       O
+    Open a line above the current line. Otherwise works just like 'o'.
+
+---------------
+       P
+    Put back the yank buffer at the cursor. Otherwise works just like 'p'.
+
+---------------
+       Q
+    Enter and remain in command mode. Just like the command :exec. To get
+    back to visual mode, you must enter the command ':visual'.
+
+---------------
+       R
+    Replace mode. A limited subset of insert mode that overwrites characters
+    up to end of line. All of the normal insert mode commands apply.
+    If you overwrite a character, then back over it with ^H,^U, or ^W, it
+    will reappear after you exit Replace mode.
+
+    Escape exits replace mode.
+
+    NOTE: due to a bug, entering a <return> in Replace mode will drop you
+    back into visual mode with an error. The replacements you have made
+    will remain.
+
+---------------
+       S
+    Change characters backwards. Shorthand for (#)ch.
+
+(*)------------
+       (#)T(x)
+    Move back to character on current line. If you are on the last character
+    of the line 'abcdef', typing "Ta" will move you back to the 'b'.
+
+(*)------------
+       (#)W
+    Move to end of word. Exactly like 'e'.
+
+---------------
+       (#)X
+    Delete characters backwards. Shorthand for (#)dh.
+
+\f    Levee.                                    A Screen Oriented Editor.
+---------------
+       Y
+    Yank to end of line. Shorthand for y$.
+
+---------------
+       ZZ
+    Write changes to current file and exit if last file in arglist.
+    Exactly like :xit.
+
+(*)------------
+       (#)$
+    Move to end of line. If you give a count, move to the end of the (count-1)
+    line down (so 2$ moves you to the end of the next line.).
+
+(*)------------
+       %
+    Find matching bracket, parenthesis, or squiggly bracket. If you are not
+    sitting on a '[]{}()', Levee will search forward for one of them on the
+    current line, then match whatever it finds.
+
+(*)------------
+       ^
+    Move to the first nonwhite character on the current line.
+
+(*)------------
+       &
+    Redo last substitution command.
+
+(*)------------
+       (#){
+    Move to the beginning of the count'th paragraph back. A paragraph is
+    delimited by a blank line.
+
+(*)------------
+       (#)}
+    Move to the end of the count'th paragraph forward.
+
+(*)------------
+       (#)(
+    Move to the beginning of the count'th sentence back. A sentence is
+    delimited by a ., a !, or a ? followed by a space, a tab, or end of line.
+
+(*)------------
+       (#))
+    Move to the end of the count'th sentence forward.
+
+(*)------------
+       (#)-
+    Move to the (count'th) previous line, first nonwhite.
+
+(*)------------
+       (#)+
+    Move to the (count'th) next line, first nonwhite.
+
+---------------
+       (#)~
+    Change the case of the next count characters. Upper case becomes lowercase,
+    lowercase becomes uppercase.
+
+\f    Levee.                                    A Screen Oriented Editor.
+(*)------------
+       `(x)
+    Move to the exact position of mark (x). There is a special mark for some
+    of the visual mode move ment commands -- '' will move you to where you
+    were before the last (,),',`,G,/,?,n,N command.
+
+---------------
+       :
+    Execute one command mode command. When the command is done, it will return
+    to visual mode if it produces one line of output, but if it scrolls the
+    screen, Levee will prompt [more] before returning to visual mode. If you
+    type a : in response to the [more] prompt, Levee will remain in command
+    mode for one more command.
+
+---------------
+       (#)<(#)
+    Shift one (count) objects left. If you specify a second count, Levee will
+    shift the object left that many columns -- if you do not, they will be sh
+    shifted shiftwidth columns.
+
+    This is a nondestructive shift. If the shift would carry past the left
+    margin, the objects will be moved up to the left margin but no farther.
+
+    Like the other object movement commands, '<<' will affect whole lines.
+
+---------------
+       (#)>(#)
+    Shift one (count) objects right. Just like <, except it will not shift
+    objects past the right margin of the screen. If you do shift an object
+    past the right margin of the screen, all of its indent will be removed
+    and it will end up by the left margin.
+
+---------------
+       .
+    Repeat last modification command. (except undo)
+
+(*)------------
+       ?
+    Search for pattern backwards. Escape aborts the search pattern, and a
+    empty pattern means search for the last pattern again.
+
+(*)------------
+       /
+    Search for pattern forwards. Otherwise like ?.
+
+(*)------------
+       (#)|
+    Move to specified column. If you don't have a count, move to column 0.
+
+\f    Levee.                                    A Screen Oriented Editor.
+
+
+    LIMITATIONS
+       Levee can only edit files up to 256000 characters long. ^M is used
+    as its internal line separator, so inserting ^M will have interesting
+    consequences.
+
+    BUGS
+       Probably infinite.
+
+    AUTHOR
+                       David L. Parsons (orc)
+
+           Testing, suggestions, and impractical design goals by:
+                           Jim Bolland.
+                           John Tainter.
+                           John Plocher.
+
+\f    Levee.                                    A Screen Oriented Editor.
+
+    COPYRIGHT
+  
+   Copyright (c) 1982-1997 David L Parsons
+   All rights reserved.
+  
+   Redistribution and use in source and binary forms are permitted
+   provided that the above copyright notice and this paragraph are
+   duplicated in all such forms and that any documentation,
+   advertising materials, and other materials related to such
+   distribution and use acknowledge that the software was developed
+   by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+   to endorse or promote products derived from this software without
+   specific prior written permission.  THIS SOFTWARE IS PROVIDED
+   AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+   WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+   FITNESS FOR A PARTICULAR PURPOSE.
+\f    Levee.                                    A Screen Oriented Editor.
+                           I N D E X
+       Are you kidding?
diff --git a/Applications/levee/main.c b/Applications/levee/main.c
new file mode 100644 (file)
index 0000000..9e2fd73
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "levee.h"
+#include "extern.h"
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if (SYS5 & !ST)       /* if system 5 compatable, it has signals */
+#include <signal.h>
+#endif
+
+#if RMX
+    extern alien token rq$get$task$tokens();   /* for unique files */
+#endif
+
+PROC
+int stamp(char *s, char *template)
+/* make a unique temporary file */
+{
+#if RMX
+    token dummy;
+
+    strcpy(s, ":work:");
+    strcat(s, template);
+    numtoa(&s[strlen(s)], rq$get$task$tokens(0,&dummy));
+#else
+    char *p;
+
+#if UNIX
+    strcpy(s, "/tmp/");
+#endif
+
+#if FLEXOS
+    s[0] = 0;
+#endif
+
+#if MSDOS
+    if (p=getenv("TMP")) {
+       strcpy(s, p);
+       if (s[strlen(s)-1] != '\\')
+           strcat(s, "\\");
+    }
+    else
+       s[0] = 0;
+#endif
+#if ST
+    if (p=getenv("_TMP")) {
+       strcpy(s, p);
+       if (s[strlen(s)-1] != '\\')
+           strcat(s, "\\");
+    }
+    else
+       s[0] = 0;
+#endif
+    strcat(s, template);
+    numtoa(&s[strlen(s)], getpid());
+#endif
+}
+
+#if RMX|UNIX
+PROC void
+ctrlc(void)
+/* ctrlc: RMX control-C handler */
+{
+    count = 0; /* clear count, eh? */
+}
+#endif
+
+#if RMX
+PROC
+void settty(void)
+/* settty: set up the terminal for raw input */
+{
+    unsigned dummy;
+    /* transparent mode? */
+    dq$special(1,&fileno(stdin),&dummy);
+    
+    /* turn off control character assignments */
+    strput("\033]T:C15=0,C18=0,C20=0,C21=0,C23=0\033\\");
+}
+#endif
+
+PROC
+void initialize(int count, char **args)
+/* initialize: set up everything I can in levee */
+{
+    int i;
+#if RMX
+    int xmode = E_INIT, xquit;
+#else
+#if ST
+    extern int mapslash;
+#endif
+#endif
+
+#if 0
+    signal(SIGINT, ctrlc);
+#else
+/*    signal(SIGINT, SIG_IGN); */
+#endif
+    initcon();
+
+#if RMX
+    exception(0);
+    dq$trap$cc(ctrlc,&i);
+#endif
+
+#if ZTERM
+    zconfig();
+#endif /*ZTERM*/
+
+#if ST
+    screensz(&LINES, &COLS);
+    dofscroll = LINES/2;
+#endif
+
+#if RMX
+#if TERMCAP
+    {  FILE *tcf;
+       extern char termcap[];
+
+       if (tcf=fopen(":termcap:","rb")) {
+           fgets(termcap,200,tcf);             /* get a line... */
+           termcap[strlen(termcap)-1] = 0;     /* erase \n at eof */
+           fclose(tcf);                        /* close the file */
+       }
+    }
+#endif /*TERMCAP*/
+    settty();
+#endif /*RMX*/
+
+#if TERMCAP
+    tc_init();
+#endif
+
+    version(); strput(".  Copyright (c) 1983-1989 by David Parsons");
+
+    if (!CA || HO[0] == 0) {
+       lineonly = TRUE;
+        mvcur(0, 0);
+        strput(CE);
+       prints("(line mode)");
+    }
+    else
+       lineonly = FALSE;
+
+    /* initialize macro table */
+    for (i = 0;i < MAXMACROS;i++)
+       mbuffer[i].token = 0;
+    core[0] = EOL;
+       
+    yank.size = ERR;           /* no yanks yet */
+    
+    undo.blockp = undo.ptr = 0;
+    
+    fillchar(adjcurr, sizeof(adjcurr), 0);
+    fillchar(adjendp, sizeof(adjendp), 0);
+    
+    adjcurr[BTO_WD]    =       /* more practical to just leave dynamic */
+    adjcurr[SENT_BACK] =
+    adjendp[BTO_WD]    =
+    adjendp[FORWD]     =
+    adjendp[MATCHEXPR] =
+    adjendp[PATT_BACK] =
+    adjendp[TO_CHAR]   =
+    adjendp[UPTO_CHAR] =
+    adjendp[PAGE_BEGIN]        =
+    adjendp[PAGE_MIDDLE]=
+    adjendp[PAGE_END]  = TRUE;
+
+    fillchar(contexts, sizeof(contexts), -1);
+
+    stamp(undobuf, "$un");
+    stamp(yankbuf, "$ya");
+    stamp(undotmp, "$tm");
+    
+    mvcur(LINES-1,0);
+#if ST
+    mapslash = getenv("mapslash") != 0L;
+#endif
+#if RMX
+    do_file(":lvrc:", &xmode, &xquit);
+#else /*!RMX   system has a environment.. */
+    {  char *p;
+       extern char *execstr;   /* [exec.c] */
+
+       if (p=getenv("LVRC")) {
+           strcpy(instring,p);
+           execstr = instring;
+           setcmd();
+       }
+    }
+#endif
+
+    ++args, --count;
+    if (count > 0 && **args == '+') {
+       char *p = *args;
+       strcpy(startcmd, p[1] ? (1+p) : "$");
+       ++args, --count;
+    }
+    argc = 0;
+    while (count-- > 0)
+       expandargs(*args++, &argc, &argv);
+    if (argc > 0) {
+       strcpy(filenm, argv[0]);
+       if (argc > 1)
+           toedit(argc);
+       inputf(filenm,TRUE);
+    }
+    else
+       filenm[0] = 0;
+}
+
+bool PROC
+execmode(exec_type emode)
+{
+    bool more,                 /* used [more] at end of line */
+        noquit;                /* quit flag for :q, :xit, :wq */
+    exec_type mode;
+
+    zotscreen = diddled = FALSE;
+    noquit = TRUE;
+
+    if (lineonly)
+       println();
+
+    mode=emode;
+    do {
+       prompt(FALSE,":");
+       if (getline(instring))
+           exec(instring, &mode, &noquit);
+       indirect = FALSE;
+       if (mode == E_VISUAL && zotscreen && noquit) {  /*ask for more*/
+           prints(" [more]");
+           if ((ch=peekc()) == 13 || ch == ' ' || ch == ':')
+               readchar();
+           more = (ch != ' ' && ch != 13);
+       }
+       else
+           more = (mode == E_EDIT);
+       if (mode != E_VISUAL && curpos.x > 0)
+           println();
+       else
+           mvcur(-1,0);
+    } while (more && noquit);
+    if (zotscreen)
+       clrprompt();
+    return noquit;
+}
+
+#if ST
+long _STKSIZ = 4096;
+long _BLKSIZ = 4096;
+#endif
+
+void main(int argc, char *argv[])
+{
+    initialize(argc, argv);
+
+    diddled = TRUE;    /* force screen redraw when we enter editcore() */
+    if (lineonly)
+       while (execmode(E_EDIT))
+           prints("(no visual mode)");
+    else
+       while (execmode(editcore()))
+            /* do nada */;
+
+    unlink(undobuf);
+    unlink(yankbuf);
+
+#if ZTERM
+    zclose();
+#endif
+
+    fixcon();
+
+#if RMX
+    strputs("\033]T:C15=3,C18=13,C20=5,C21=6,C23=4\033\\\n");
+    dq$special(2,&fileno(stdin),&curr);
+#else
+    println();
+#endif
+    exit(0);
+}
diff --git a/Applications/levee/misc.c b/Applications/levee/misc.c
new file mode 100644 (file)
index 0000000..fb7e532
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+
+bool PROC
+getline(char *str)
+{
+    int len;
+    char flag;
+    
+    flag = line(str, 0, COLS-curpos.x, &len);
+    str[len] = 0;
+    strput(CE);
+    return (flag == EOL);
+} /* getline */
+
+
+char PROC
+readchar(void)
+{
+    ch = peekc();              /* get the peeked character */
+    needchar = TRUE;           /* force a read on next readchar/peekc */
+    if (xerox) {               /* save this character for redo */
+       if (rcp >= &rcb[256-1]) /* oops, buffer overflow */
+           error();
+       else                    /* concat it at the end of rcb^ */
+           *rcp++ = ch;
+    }
+    return ch;
+} /* readchar */
+
+
+/* look at next input character without actually using it */
+char PROC
+peekc(void)
+{
+    if (needchar) {                            /* if buffer is empty, */
+       if (macro >= 0) {                       /* if a macro */
+           lastchar = *mcr[macro].ip;
+           mcr[macro].ip++;
+           if (*mcr[macro].ip == 0) {
+               if (--mcr[macro].m_iter > 0)
+                   mcr[macro].ip = mcr[macro].mtext;
+               else
+                   --macro;
+           }
+       }
+       else                            /* else get one from the keyboard */
+           lastchar = getKey();
+        needchar = FALSE;
+    }
+    return lastchar;
+} /* peekc */
+
+
+/* find the amount of leading whitespace between start && limit.
+   endd is the last bit of whitespace found.
+*/
+int PROC
+findDLE(int start, int *endd, int limit, int dle)
+{
+    while ((core[start] == '\t' || core[start] == ' ') && start < limit) {
+       if (core[start] == '\t')
+           dle = tabsize * (1+(dle/tabsize));
+       else
+           dle++;
+       start++;
+    }
+    *endd = start;
+    return dle;
+} /* findDLE */
+
+
+int PROC
+skipws(int loc)
+{
+    while ((core[loc] == '\t' || core[loc] == ' ') && loc <= bufmax)
+       loc++;
+    return(loc);
+} /* skipws */
+
+
+int PROC
+setX(int cp)
+{
+    int top, xp;
+    
+    top = bseekeol(cp);
+    xp = 0;
+    while (top < cp) {
+       switch (cclass(core[top])) {
+           case 0 : xp++; break;
+           case 1 : xp += 2; break;
+           case 2 : xp = tabsize*(1+(xp/tabsize)); break;
+           case 3 : xp += 3; break;
+       }
+       top++;
+    }
+    return(xp);
+} /* setX */
+
+
+int PROC
+setY(int cp)
+{
+    int yp, ix;
+    
+    ix = ptop;
+    yp = -1;
+    cp = min(cp,bufmax-1);
+    do {
+       yp++;
+       ix = 1+fseekeol(ix);
+    } while (ix <= cp);
+    return(yp);
+} /* setY */
+
+
+int PROC
+to_line(int cp)
+{
+    int tdx,line;
+    tdx = 0;
+    line = 0;
+    while (tdx <= cp) {
+       tdx = 1+fseekeol(tdx);
+       line++;
+    }
+    return(line);
+} /* to_line */
+
+
+int PROC
+to_index(int line)
+{
+    int cp = 0;
+    while (cp < bufmax && line > 1) {
+       cp = 1+fseekeol(cp);
+       line--;
+    }
+    return(cp);
+} /* to_index */
+    
+PROC
+void swap(int *a, int *b)
+{
+    int c;
+    
+    c = *a;
+    *a = *b;
+    *b = c;
+} /* swap */
+
+
+int PROC
+#if ST
+cclass(int c)
+{
+    if (c >= ' ' && c < '\7f')
+       return 0;
+    if (c == '\t' && !list)
+       return 2;
+    if (c >= 0)
+       return 1;
+    return 3;
+} /* cclass */
+#else
+cclass(unsigned char c)
+{
+    if (c == '\t' && !list)
+       return 2;
+    if (c == '\7f' || c < ' ')
+       return 1;
+#if MSDOS==0
+    if (c & 0x80)
+       return 3;
+#endif
+    return 0;
+} /* cclass */
+#endif
+
+#if ST
+/*
+ * wildly machine-dependent code to make a beep
+ */
+#include <atari\osbind.h>
+
+static char sound[] = {
+       0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00,
+       0xF8,0x10,0x10,0x10,0x00,0x20,0x03
+};
+
+#define SADDR  0xFF8800L
+
+typedef char srdef[4];
+
+static srdef *SOUND = (srdef *)SADDR;
+
+static
+beeper(void)
+{
+    register i;
+    for (i=0; i<sizeof(sound); i++) {
+       (*SOUND)[0] = i;
+       (*SOUND)[2] = sound[i];
+    }
+} /* beeper */
+#endif /*ST*/
+
+
+PROC
+error()
+{
+    indirect = FALSE;
+    macro = -1;
+    if (xerox)
+       rcb[0] = 0;
+    xerox = FALSE;
+#if ST
+    Supexec(beeper);
+#else
+    if (bell)
+       strput(BELL);
+#endif /*ST*/
+} /* error */
+
+
+/* the dirty work to start up a macro */
+PROC insertmacro(char *cmdstr, int count)
+{
+    if (macro >= NMACROS)
+       error();
+    else if (*cmdstr != 0) {
+       macro++;
+       mcr[macro].mtext = cmdstr;      /* point at the text */
+       mcr[macro].ip = cmdstr;         /* starting index */
+       mcr[macro].m_iter = count;      /* # times to do the macro */
+    }
+} /* insertmacro */
+
+
+int PROC lookup(char c)
+{
+    int ix = MAXMACROS;
+    
+    while (--ix >= 0 && mbuffer[ix].token != c)
+       ;
+    return ix;
+} /* lookup */
+
+
+PROC
+void fixmarkers(int base, int offset)
+{
+    char c;
+    
+    for (c = 0;c<'z'-'`';c++)
+       if (contexts[c] > base)
+           if (contexts[c]+offset < base || contexts[c]+offset >= bufmax)
+               contexts[c] = -1;
+           else
+               contexts[c] += offset;
+} /* fixmarkers */
+
+
+PROC
+void wr_stat(void)
+{
+    clrprompt();
+    if (filenm[0] != 0) {
+       printch('"');
+       prints(filenm);
+       prints("\" ");
+       if (newfile)
+           prints("<New file> ");
+    }
+    else
+       prints("No file");
+    printch(' ');
+    if (readonly)
+       prints("<readonly> ");
+    else if (modified)
+       prints("<Modified> ");
+    if (bufmax > 0) {
+       prints(" line ");
+       printi(to_line(curr));
+       prints(" -");
+       printi((int)((long)(curr*100L)/(long)bufmax));
+       prints("%-");
+    }
+    else
+       prints("-empty-");
+} /* wr_stat */
+
+
+static int  tabptr,
+           tabstack[20],
+           ixp;
+       
+PROC
+void back_up(char c)
+{
+    switch (cclass(c)) {
+       case 0: ixp--; break;
+       case 1: ixp -= 2; break;
+       case 2: ixp = tabstack[--tabptr]; break;
+       case 3: ixp -= 3; break;
+    }
+    mvcur(-1,ixp);
+} /* back_up */
+
+
+/*
+ *  put input into buf[] || instring[].
+ *  return states are:
+ *     0 : backed over beginning
+ *    ESC : ended with an ESC
+ *    EOL : ended with an '\r'
+ */
+char PROC
+line(char *s, int start, int endd, int *size)
+{
+    int col0,
+       ip;
+    char c;
+    
+    col0 = ixp = curpos.x;
+    ip = start;
+    tabptr = 0;
+    while (1) {
+       c = readchar();
+       if (movemap[c] == INSMACRO)     /* map!ped macro */
+           insertmacro(mbuffer[lookup(c)].m_text, 1);
+       else if (c == DW) {
+           while (!wc(s[ip-1]) && ip > start)
+               back_up(s[--ip]);
+           while (wc(s[ip-1]) && ip > start)
+               back_up(s[--ip]);
+       }
+       else if (c == eraseline) {
+           ip = start;
+           tabptr = 0;
+           mvcur(-1,ixp=col0);
+       }
+       else if (c==erasechar) {
+           if (ip>start)
+               back_up(s[--ip]);
+           else {
+               *size = 0;
+               return(0);
+           }
+       }
+       else if (c=='\n' || c=='\r' || c==ESC) {
+           *size = (ip-start);
+            return (c==ESC) ? ESC : EOL;
+       }
+       else if ((!beautify) || c == TAB || c == 0x16           /* ^V */
+                            || (c >= ' ' && c <= '~')) {
+           if (ip < endd) {
+               if (c == 0x16)
+                   c = readchar();
+               switch (cclass(c)) {
+                   case 0 : ixp++; break;
+                   case 1 : ixp += 2; break;
+                   case 2 :
+                       tabstack[tabptr++] = ixp;
+                       ixp = tabsize*(1+(ixp/tabsize));
+                       break;
+                   case 3 : ixp += 3; break;
+               }
+               s[ip++] = c;
+               printch(c);
+           }
+           else
+               error();
+       }
+        else
+           error();
+    }
+} /* line */
+
+
+/* move to core[loc] */
+PROC
+void setpos(int loc)
+{
+    lstart = bseekeol(loc);
+    lend = fseekeol(loc);
+    xp = setX(loc);
+    curr = loc;
+} /* setpos */
+
+
+PROC
+void resetX(void)
+{
+    if (deranged) {
+       xp = setX(curr);
+       mvcur(-1, xp);
+       deranged = FALSE;
+    }
+} /* resetX */
+
+
+/* set end of window */
+PROC
+void setend(void)
+{
+    int bottom, count;
+    
+    bottom = ptop;
+    count = LINES-1;
+    while (bottom < bufmax && count > 0) {
+       bottom = 1+fseekeol(bottom);
+       count--;
+    }
+    pend = bottom-1;           /* last char before eol || eof */
+} /* setend */
+
+
+/*  set top of window
+ *  return the number of lines actually between curr && ptop.
+ */
+int PROC
+settop(int lines)
+{
+    int top, yp;
+    
+    top = curr;
+    yp = -1;
+    do {
+       yp++;
+       top = bseekeol(top) - 1;
+       lines--;
+    } while (top >= 0 && lines > 0);
+    ptop = top+1;                      /* tah-dah */
+    setend();
+    return(yp);
+} /* settop */
diff --git a/Applications/levee/modify.c b/Applications/levee/modify.c
new file mode 100644 (file)
index 0000000..71ad4b0
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+#include "grep.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+/* modification commands that can be accessed by either editcore || execmode */
+
+/* put stuff into the yank buffer */
+
+bool PROC
+doyank(int low, int high)
+{
+    HANDLE f;
+    register sz;
+    
+    yank.size = high - low;
+    moveleft(&core[low], yank.stuff, min(yank.size, SBUFSIZE));
+    if (yank.size > SBUFSIZE) {
+       if ((f=OPEN_NEW(yankbuf)) >= 0) {
+           low += SBUFSIZE;
+           sz = WRITE_TEXT(f, core+low, high-low);
+           CLOSE_FILE(f);
+           if (sz == high-low)
+               return TRUE;
+       }
+       yank.size = -1;
+       return FALSE;
+    }
+    return TRUE;
+}
+
+bool PROC
+deletion(int low, int high)
+{
+    if (doyank(low, high))             /* fill yank buffer */
+       return delete_to_undo(&undo, low, high-low);
+    return FALSE;
+}
+
+/* move stuff from the yank buffer into core */
+
+bool PROC
+putback(int start, int *newend)
+{
+    int siz, st;
+    HANDLE f;
+    
+    if (yank.size+bufmax < SIZE && yank.size > 0) {
+       *newend = start + yank.size;
+       if (start < bufmax)
+           moveright(&core[start], &core[start+yank.size], bufmax-start);
+       moveleft(yank.stuff, &core[start], min(SBUFSIZE, yank.size));
+       if (yank.size > SBUFSIZE) {
+           siz = yank.size - SBUFSIZE;
+           if ((f=OPEN_OLD(yankbuf)) >= 0) {
+               st = READ_TEXT(f, &core[start+SBUFSIZE], siz);
+               CLOSE_FILE(f);
+               if (st == siz)
+                   goto succeed;
+           }
+           moveleft(&core[start+yank.size], &core[start], bufmax-start);
+           *newend = -1;
+           return FALSE;
+       }
+    succeed:
+       insert_to_undo(&undo, start, yank.size);
+       return TRUE;
+    }
+    return FALSE;
+}
+
+#define DSIZE 1024
+
+int PROC
+makedest(char *str, int start, int ssize, int size)
+/* makedest: make the replacement string for an regular expression */
+{
+    register char *fr = dst;
+    register char *to = str;
+    int as, asize, c;
+
+    while (*fr && size >= 0) {
+       if (*fr == AMPERSAND) { /* & copies in the pattern that we matched */
+           if ((size -= ssize) < 0)
+               return -1;
+           moveleft(&core[start],to,ssize);
+           to += ssize;
+           fr++;
+       }
+       else if (*fr == ESCAPE) {       /* \1 .. \9 do arguments */
+           c = fr[1];
+           fr += 2;
+           if (c >= '1' && c <= '9') {
+               if ((as = RE_start[c-'1']) < 0)
+                   continue;
+               asize = RE_size [c-'1'];
+               if ((size -= asize) < 0)
+                   return -1;
+               moveleft(&core[as],to,asize);
+               to += asize;
+           }
+           else
+               *to++ = c;
+       }
+       else {
+           *to++ = *fr++;
+           --size;
+       }
+    }
+    return to-str;
+}
+
+int PROC
+chop(int start, int *endd, bool visual, bool *query)
+{
+    int i,retval;
+    char c;
+/*>>>>
+    bool ok;
+  <<<<*/
+    char dest[DSIZE];
+    register int len, dlen;
+    
+    retval = -1;
+    /*dlen = strlen(dst);*/
+restart:
+    count = 1;
+    i = findfwd(pattern, start, *endd);
+    if (i != ERR) {
+       if (*query) {
+           /*>>>> don't delete -- keep for future use
+           if (visual) {
+               mvcur(yp,setX(i));puts("?\b");
+           }
+           else {
+           <<<<*/
+               println();
+               writeline(-1,-1,bseekeol(i));
+               println();
+               mvcur(-1,setX(i));
+               prints("^?");
+           /*>>>>
+           }
+           <<<<*/
+           do
+               c = tolower(readchar());
+           while (c!='y'&&c!='n'&&c!='q'&&c!='a');
+           if (c == 'n') {
+               start = i+1;
+               goto restart;
+           }
+           else if (c == 'q')
+               return retval;
+           else if (c == 'a')
+               *query = FALSE;
+       }
+       len = lastp-i;
+       dlen = makedest(dest, i, len, DSIZE);
+       if (dlen >= 0 && bufmax-(int)(len+dlen) < SIZE
+                     && delete_to_undo(&undo, i, len)) {
+           modified = TRUE;
+           if (dlen > 0) {
+               moveright(&core[i], &core[i+dlen], bufmax-i);
+               insert_to_undo(&undo,i,dlen);
+               moveleft(dest,&core[i],dlen);
+           }
+           *endd += (dlen-len);
+           retval = i+dlen;
+       }
+    }
+    return retval;
+}
diff --git a/Applications/levee/move.c b/Applications/levee/move.c
new file mode 100644 (file)
index 0000000..cc0bfd0
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+#include <ctype.h>
+#include <string.h>
+
+/* driver for movement commands */
+
+findstates PROC
+findCP(int curp, int *newpos, cmdtype cmd)
+{
+    static char chars[2] = {'/','?'};
+    char tsearch;
+
+    *newpos = ERR;
+    switch (cmd) {                     /* move around */
+    
+    case GO_LEFT:
+       *newpos = max(lstart, curp-max(count,1));
+       break;
+
+    case GO_RIGHT:
+       *newpos = min(lend, curp+max(count,1));
+       break;
+
+    case GO_UP:
+    case GO_DOWN:
+       *newpos = nextline(cmd==GO_DOWN, curp, count);
+       if (*newpos >= 0 && *newpos < bufmax)
+           *newpos = findcol(*newpos,xp);
+       break;
+
+    case FORWD:
+    case TO_WD:
+    case BACK_WD:
+    case BTO_WD:
+       *newpos = moveword(curp,(cmd <= TO_WD),(cmd==TO_WD || cmd==BTO_WD));
+       break;
+
+    case NOTWHITE:
+       *newpos = skipws(bseekeol(curp));
+       break;
+
+    case TO_COL:
+       *newpos = findcol(curp, count);
+       break;
+
+    case TO_EOL:
+       while ( (count-- > 1) && (curp < bufmax) )
+           curp = 1+fseekeol(curp);
+       *newpos = fseekeol(curp);
+       break;
+
+    case PARA_FWD:
+       do
+           curp = findfwd("^*[\ 2 \t$",curp+1,bufmax-1);
+       while (curp != ERR && --count > 0);
+       *newpos = (curp==ERR)?bufmax:curp;
+       break;
+
+    case PARA_BACK:
+       do
+           curp = findback("^*[\ 2 \t$",curp-1,0);
+       while (curp != ERR && --count > 0);
+       *newpos = (curp==ERR)?0:curp;
+       break;
+
+    case SENT_FWD:
+    case SENT_BACK:
+       *newpos = sentence(curp, cmd==SENT_FWD);
+       break;
+
+    case MATCHEXPR:
+       *newpos = match(curp);
+       break;
+
+    case TO_CHAR:
+    case UPTO_CHAR:
+    case BACK_CHAR:
+    case BACKTO_CHAR:
+       ch = readchar();
+       if (ch == ESC)
+           return ESCAPED;
+       if (cmd<=UPTO_CHAR) {
+           *newpos = fchar(curp,*newpos);
+           if (cmd==UPTO_CHAR && *newpos>=0)
+               *newpos = max(curp, *newpos-1);
+       }
+       else {
+           *newpos = bchar(curp,*newpos);
+           if (cmd==BACKTO_CHAR && *newpos>=0)
+               *newpos = min(curp, *newpos+1);
+       }
+       break;
+
+    case PAGE_BEGIN:
+       *newpos = ptop;
+       break;
+
+    case PAGE_END:
+       *newpos = pend;
+       break;
+
+    case PAGE_MIDDLE:
+       curp = ptop;
+       count = 12;
+       while (count-- > 0 && curp < bufmax)
+          curp = 1+fseekeol(curp);
+       *newpos = skipws(curp);
+       break;
+
+    case GLOBAL_LINE:
+       if (count <= 0)
+           *newpos = bufmax-1;
+       else
+           *newpos = to_index(count);
+       break;
+
+    case TO_MARK:
+    case TO_MARK_LINE:
+       *newpos = getcontext((char)tolower(readchar()), cmd==TO_MARK_LINE);
+       break;
+
+    case CR_FWD:
+    case CR_BACK:
+       curp = nextline(cmd==CR_FWD, curp, count);
+       if (cmd==CR_BACK && curp > 0)
+           curp = bseekeol(curp);
+       *newpos = skipws(curp);
+       break;
+
+    case PATT_FWD:
+    case PATT_BACK:                    /* search for pattern */
+    case FSEARCH:
+    case BSEARCH:
+       clrprompt();
+       if (cmd == PATT_FWD || cmd == PATT_BACK) {
+           printch(tsearch = instring[0] = chars[cmd-PATT_FWD]);
+           if (!getline(&instring[1]))
+               return ESCAPED; /* needs to skip later tests */
+       }
+       else {
+           if (!nlsearch)
+               return BADMOVE;
+           tsearch = nlsearch;
+           printch(instring[0] = (cmd==FSEARCH)?nlsearch:((nlsearch=='?')?'/':'?') );
+           prints(lastpatt);
+           instring[1] = 0;
+       }
+       if (*findparse(instring, newpos, curp)) { /* croaked patt */
+           *newpos = ERR;
+           prompt(TRUE,"bad pattern");
+       }
+       else if (*newpos == ERR)
+           prompt(FALSE,"no match");
+       nlsearch = tsearch;     /* fixup for N, n */
+       break;
+    }
+    if ( ((*newpos) >= 0) && ((*newpos) <= bufmax) )
+       return LEGALMOVE;
+    return BADMOVE;
+}
+
+/* this procedure handles all movement in visual mode */
+
+PROC
+movearound(cmdtype cmd)
+{
+    int cp;
+    
+    switch (findCP(curr, &cp, cmd)) {
+       case LEGALMOVE:
+           if (cp < bufmax) {
+               if (cmd >= PATT_FWD)            /* absolute move */
+                   contexts[0] = curr; /* so save old position... */
+               curr = cp;                      /* goto new position */
+               if (cmd==GO_UP || cmd==GO_DOWN) /* reset Xpos */
+                   deranged = TRUE;
+               else
+                   xp = setX(cp);              /* just reset XP */
+               if (cp < lstart || cp > lend) {
+                   lstart = bseekeol(curr);
+                   lend   = fseekeol(curr);
+                   if (curr < ptop) {
+                       if (canUPSCROLL && ok_to_scroll(curr, ptop)) {
+                           scrollback(curr);
+                           yp = 0;
+                       }
+                       else {
+                           yp = settop(LINES / 2);
+                           redisplay(TRUE);
+                       }
+                   }
+                   else if (curr > pend) {
+                       if (ok_to_scroll(pend, curr)) {
+                           scrollforward(curr);
+                           yp = LINES-2;
+                       }
+                       else {
+                           yp = settop(LINES / 2);
+                           redisplay(TRUE);
+                       }
+                   }
+                   else
+                       yp = setY(curr);
+               }
+           }
+           else
+               error();
+       break;
+       case BADMOVE:
+           error();
+       break;
+    }
+    mvcur(yp, xp);
+}
+    
+int PROC
+findcol(int ip, int col)
+{
+    int tcol, endd;
+    
+    ip = bseekeol(ip);                 /* start search here */
+    endd = fseekeol(ip);               /* end search here */
+
+    tcol = 0;
+    while (tcol < col && ip < endd)
+       switch (cclass(core[ip++])) {
+           case 0: tcol++;    break;
+           case 1: tcol += 2; break;
+           case 3: tcol += 3; break;
+           case 2: tcol = tabsize*(1+(tcol/tabsize)); break;
+       }
+    return(ip);
+}
+
+char dstpatt[]="[](){}", srcpatt[]="][)(}{";
+
+/* find matching [], (), {} */
+
+int PROC
+match(int p)
+{
+    char srcchar, dstchar;
+    int lev, step;
+    
+    while((lev = scan(6,'=',core[p],srcpatt)) >= 6 && core[p] != EOL)
+       p++;
+    if (lev < 6) {
+       srcchar = srcpatt[lev];
+       dstchar = dstpatt[lev];
+       step = setstep[lev&1];
+       lev = 0;
+       while (p >= 0 && p < bufmax) {
+           p += step;
+           if (core[p] == srcchar)
+               lev++;
+           else if (core[p] == dstchar)
+               if(--lev < 0)
+                   return p;
+       }
+    }
+    return (-1);
+}
+
+char * PROC
+class(char c)
+/* find the character class of a char -- for word movement */
+{
+    if (strchr(wordset,c))
+       return wordset;
+    else if (strchr(spaces,c))
+       return spaces;
+    else
+       return (char*)NULL;
+}
+
+int PROC
+skip(char *chars, int cp, int step)
+/* skip past characters in a character class */
+{
+    while (cp >= 0 && cp < bufmax && strchr(chars,core[cp]))
+       cp += step;
+    return cp;
+}
+
+int PROC
+tow(int cp, int step)
+/* skip to the start of the next word */
+{
+    while (cp >= 0 && cp < bufmax
+                && !(strchr(wordset,core[cp]) || strchr(spaces,core[cp])))
+       cp += step;
+    return cp;
+}
+
+int PROC
+moveword(int cp, bool forwd, bool toword)
+/* word movement */
+{
+    int step;
+    register char *ccl;
+    
+    step = setstep[forwd];     /* set direction to move.. */
+    if (!toword)
+       cp += step;             /* advance one character */
+    count = max(1,count);
+    ccl = class(core[cp]);
+    if (toword && ccl == spaces) {     /* skip to start of word */
+       count--;
+       cp = skip(spaces,cp,step);
+       ccl = class(core[cp]);
+    }
+
+    while (cp >= 0 && cp < bufmax && count-- > 0) {
+       if (ccl == spaces) {
+           cp = skip(spaces,cp,step);
+           ccl = class(core[cp]);
+       }
+       cp = (ccl)?skip(ccl,cp,step):tow(cp,step);
+       ccl = class(core[cp]);
+    }
+    if (toword) {                              /* past whitespace? */
+       if (ccl == spaces)
+           cp = skip(spaces,cp,step);
+       return cp;
+    }
+    return cp-step;                            /* sit on last character. */
+}
+
+/* find a character forward on current line */
+
+int PROC
+fchar(int pos, int npos)
+{
+    do
+       pos += scan(lend-pos-1,'=',ch, &core[pos+1]) + 1;
+    while (--count>0 && pos<lend);
+    if (pos<lend)
+       return(pos);
+    return(npos);
+}
+
+/* find a character backward on the current line */
+
+int PROC
+bchar(int pos, int npos)
+{
+    do
+       pos += scan(-pos+lstart+1,'=',ch, &core[pos-1]) - 1;
+    while (--count>0 && pos>=lstart);
+    if (pos>=lstart)
+       return(pos);
+    return(npos);
+}
+
+/* look for the end of a sentence forward */
+
+int PROC
+ahead(int i)
+{
+    char c;
+
+    do {
+       if ((c=core[i]) == '.' || c == '?' || c == '!')
+           if (i == bufmax-1 || (c=core[1+i]) == TAB || c == EOL || c == ' ')
+               return i;
+
+    } while (++i < bufmax);
+    return -1;
+}
+
+/* look for the end of a sentence backwards. */
+
+int PROC
+back(int i)
+{
+    char c;
+
+    do {
+       if ((c=core[i]) == '.' || c == '?' || c == '!')
+           if ((c=core[1+i]) == TAB || c == EOL || c == ' ')
+               return i;
+
+    } while (--i >= 0);
+    return -1;
+}
+
+/* find the end of the next/last sentence.
+    Sentences are delimited by ., !, or ? followed by a space.
+*/
+
+int PROC
+sentence(int start, bool forwd)
+{
+    do {
+       if (forwd)
+           start = ahead(start+1);
+       else
+           start = back(start-1);
+    } while (--count > 0 && start >= 0);
+    return start;
+}
diff --git a/Applications/levee/proto.h b/Applications/levee/proto.h
new file mode 100644 (file)
index 0000000..72707af
--- /dev/null
@@ -0,0 +1,164 @@
+/*                                     
+** levee function prototypes           
+** (generated by cl -Gms -Ox -nologo -I../tools -Zg)  
+*/                                     
+#ifndef _PROTO_D                       
+#define _PROTO_D                       
+char  *PROC badccl(char  *src);
+char  *PROC class(char  c);
+char  *PROC dodash(char  *src);
+char  *PROC findbounds(char  *ip);
+char  *PROC findparse(char  *src,int  *idx,int  start);
+char  *PROC getarg(void);
+char  *PROC getname(void);
+char  *PROC makepat(char  *string,char  delim);
+char  *PROC search(char  *pat,int  *start);
+char  *basename(char  *s);
+char  *glob(char  *path,struct  glob_t *dta);
+char  PROC editcore(void);
+char  PROC esc(char  * *s);
+char  PROC findCP(int  curp,int  *newpos,char  cmd);
+char  PROC line(char  *s,int  start,int  endd,int  *size);
+char  PROC peekc(void);
+char  PROC readchar(void);
+int  PROC REmatch(char  *pattern,int  start,int  end);
+int  PROC addarg(char  *name);
+int  PROC addfile(FILE *f,int  start,int  endd,int  *size);
+int  PROC adjuster(int  sleft,int  endd,int  sw);
+int  PROC ahead(int  i);
+int  PROC allowintr(void);
+int  PROC amatch(char  *pattern,char  *start,char  *endp);
+int  PROC args(void);
+int  PROC back(int  i);
+void PROC back_up(char  c);
+int  PROC backup(char  *name);
+int  PROC bchar(int  pos,int  npos);
+int  PROC bigreplace(void);
+int  PROC bseekeol(int  origin);
+int  PROC cclass(unsigned char  c);
+int  PROC chop(int  start,int  *endd,int  visual,int  *query);
+int  PROC clrmsg(void);
+int  PROC clrprompt(void);
+int  PROC concatch(char  c);
+int  PROC copyover(struct  undostack *save_undo,int  *curp);
+int  PROC cutandpaste(void);
+int  PROC delete_to_undo(struct  undostack *u,int  start,int  lump);
+int  PROC deletion(int  low,int  high);
+int  PROC do_file(char  *fname,char  *mode,int  *noquit);
+int  PROC doaddwork(char  *token,int  *argcp,char  * * *argvp);
+int  PROC docommand(char  cmd);
+int  PROC doinput(char  *name);
+int  PROC doins(int  flag);
+int  PROC doyank(int  low,int  high);
+int  PROC editfile(void);
+int  PROC errmsg(char  *msg);
+int  PROC error(void);
+int  PROC exec(char  *cmd,char  *mode, int *noquit);
+int  PROC execmode(char  emode);
+int  PROC exmacro(void);
+int  PROC expandargs(char  *name,int  *argcp,char  * * *argvp);
+int  PROC fchar(int  pos,int  npos);
+int  PROC findDLE(int  start,int  *endd,int  limit,int  dle);
+int  PROC findarg(char  *name);
+int  PROC findback(char  *pattern,int  start,int  endp);
+int  PROC findcol(int  ip,int  col);
+int  PROC findfwd(char  *pattern,int  start,int  endp);
+int  PROC fixcore(int  *topp);
+void PROC fixmarkers(int  base,int  offset);
+int  PROC fixupline(int  dft);
+int  PROC format(char  *out,unsigned short  c);
+int  PROC fseekeol(int  origin);
+int  PROC gcount(void);
+int  PROC getKey(void);
+int  PROC getcontext(char  c,int  begline);
+int  PROC getline(char  *str);
+void PROC initialize(int  count,char  * *args);
+int  PROC inputf(char  *fname,int  newbuf);
+int  PROC insert_to_undo(struct  undostack *u,int  start,int  size);
+int  PROC insertion(int  count,int  openflag,int  *dp,int  *yp,int  visual);
+int  PROC insertmacro(char  *cmdstr,int  count);
+int  PROC join(int  count);
+int  PROC killargs(int  *argcp,char  * * *argvp);
+int  PROC locate(char  *pattern,char  *linep);
+int  PROC lookup(char  c);
+int  PROC macrocommand(void);
+int  PROC makedest(char  *str,int  start,int  ssize,int  size);
+int  PROC map(int  insert);
+int  PROC match(int  p);
+int  PROC max(int  a,int  b);
+int  PROC min(int  a,int  b);
+int  PROC move_to_undo(struct  undostack *u,int  start,int  lump);
+int  PROC movearound(char  cmd);
+int  PROC moveleft(char  *src,char  *dest,int  length);
+int  PROC moveright(char  *src,char  *dest,int  length);
+int  PROC moveword(int  cp,int  forwd,int  toword);
+int  PROC mvcur(int  y,int  x);
+int  PROC nextfile(int  prev);
+int  PROC nextline(int  advance,int  dest,int  count);
+int  PROC nointr(void);
+int  PROC numtoa(char  *str,int  num);
+int  PROC ok_to_scroll(int  top,int  bottom);
+int  PROC oktoedit(int  writeold);
+int  PROC omatch(char  *pattern,char  * *cp,char  *endp);
+int  PROC outputf(char  *fname);
+int  PROC parse(char  *inp);
+int  PROC patsize(char  * *pattern);
+int  PROC plural(int  num,char  *string);
+int  PROC popblock(struct  undostack *u);
+int  PROC popmem(struct  undostack *u,int  start,int  size);
+int  PROC popw(struct  undostack *u,int  *i);
+int  PROC print(void);
+int  PROC printall(void);
+int  PROC printch(char  c);
+int  PROC printi(int  num);
+int  PROC println(void);
+int  PROC printone(int  i);
+int  PROC prints(char  *s);
+int  PROC prompt(int  toot,char  *s);
+int  PROC pushblock(struct  undostack *u);
+int  PROC pushmem(struct  undostack *u,int  start,int  size);
+int  PROC pushw(struct  undostack *u,int  i);
+int  PROC put(int  before);
+int  PROC putback(int  start,int  *newend);
+int  PROC putfile(FILE *f,int  start,int  endd);
+int  PROC putin(struct  undostack *save_undo,int  *curp);
+int  PROC readfile(void);
+int  PROC redisplay(int  flag);
+int  PROC refresh(int  y,int  x,int  start,int  endd,int  rest);
+void PROC resetX(void);
+int  PROC scan(int  length,char  tst,char  ch,char  *src);
+int  PROC scroll(int  down);
+int  PROC scrollback(int  curr);
+int  PROC scrollforward(int  curr);
+int  PROC sentence(int  start,int  forwd);
+int  PROC setX(int  cp);
+int  PROC setY(int  cp);
+int  PROC setcmd(void);
+void PROC setend(void);
+void PROC setpos(int  loc);
+int  PROC settop(int  lines);
+int  PROC skip(char  *chars,int  cp,int  step);
+int  PROC skipws(int  loc);
+int  PROC squiggle(int  endp,char  c,int  dorepl);
+int  PROC stamp(char  *s,char  *template);
+int  PROC strput(char  *s);
+void PROC swap(int  *a,int  *b);
+int  PROC takeout(struct  undostack *save_undo,int  *curp);
+int  PROC to_index(int  line);
+int  PROC to_line(int  cp);
+int  PROC toedit(int  count);
+int  PROC tow(int  cp,int  step);
+int  PROC undefine(int  i);
+int  PROC unmap(void);
+int  PROC uputcmd(struct  undostack *u,int  size,int  start,char  cmd);
+int  PROC version(void);
+int  PROC whatline(void);
+void PROC wr_stat(void);
+int  PROC writefile(void);
+int  PROC writeline(int  y,int  x,int  start);
+int  PROC zdraw(char  code);
+int  PROC zerostack(struct  undostack *u);
+void main(int  argc,char  * *argv);
+void PROC initcon(void);
+void PROC fixcon(void);
+#endif  /*_PROTO_D*/                   
diff --git a/Applications/levee/readme.os2 b/Applications/levee/readme.os2
new file mode 100644 (file)
index 0000000..c1ec005
--- /dev/null
@@ -0,0 +1,7 @@
+If you wish to have your copy of Levee as a family mode application, all
+you need to do is bind it.  It's already set up as a family mode application-
+there are some small differences for input (dos lv sees ^C and treats it
+like an ordinary character; os2 lv never sees ^C, because it's eaten by trap
+handlers) and redirectability (os2 lv uses getch() - a microsoft library
+function; dos vi uses dos function 0x07 - "get raw character from stdin,
+whatever that may be") but these shouldn't be a problem.
diff --git a/Applications/levee/rmxcall.c b/Applications/levee/rmxcall.c
new file mode 100644 (file)
index 0000000..b9f2371
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * iRMX interface for levee (Intel C)
+ */
+#include "levee.h"
+#if RMX
+
+extern char FkL, CurRT, CurLT, CurUP, CurDN;
+
+extern alien rq$s$write$move();
+
+strput(s)
+/* strput: write a string to stdout */
+char *s;
+{
+    int dummy;
+
+    if (s)
+       rq$s$write$move(fileno(stdout), s, strlen(s), &dummy);
+}
+
+char
+getKey()
+/* getKey: read a character from stdin */
+{
+    char c,sw;
+    unsigned dummy;
+
+    read(0,&c,1);
+
+    if (c == FkL) {    /* (single character) function key lead-in */
+       dq$special(3,&fileno(stdin),&dummy);    /* grab a raw-mode character */
+       if (read(0,&sw,1) == 1)
+           if (sw == CurLT)
+               c = LTARROW;
+           else if (sw == CurRT)
+               c = RTARROW;
+           else if (sw == CurUP)
+               c = UPARROW;
+           else if (sw == CurDN)
+               c = DNARROW;
+           else
+               c = sw | 0x80;
+       dq$special(1,&fileno(stdin),&dummy);    /* back into transparent mode */
+    }
+#if 0
+    else if (c == 0x7f)        /* good old dos kludge... */
+       return erase;
+#endif
+    return c;
+}
+
+int max(a,b)
+int a,b;
+{
+    return (a>b)?a:b;
+}
+
+int min(a,b)
+int a,b;
+{
+    return (a>b)?b:a;
+}
+
+extern alien token rq$c$create$command$connection(),
+                  rq$c$delete$command$connection(),
+                  rq$c$send$command();
+
+int system(s)
+/* system: do a shell escape */
+char *s;
+{
+    char *string();
+    unsigned cp, error, status, dummy;
+
+    cp = rq$c$create$command$connection(fileno(stdin),fileno(stdout),0,&error);
+    if (!error) {
+       rq$c$send$command(cp,string(s),&status,&error);
+       rq$c$delete$command$connection(cp,&dummy);
+    }
+    return error?(error|0x8000):(status&0x7fff);
+}
+#endif
diff --git a/Applications/levee/tc b/Applications/levee/tc
new file mode 100644 (file)
index 0000000..770fbb9
--- /dev/null
@@ -0,0 +1,32 @@
+    if (!(ttytype = getenv("TERM"))) {
+       S1("TERM not set");
+       exit(6);
+    }
+    if (tgetent(tc, ttytype) != 1) {
+       sprintf(Msg, "Can't load %s", ttytype);
+       S;
+       exit(7);
+    }
+    ospeed = newmode.c_cflag & CBAUD;
+    LI = tgetnum("li") - 1;
+    CO = tgetnum("co");
+    if (!(s = Tgetstr("pc")))
+       PC = '\0';
+    else
+       PC = *s;
+
+    CD = Tgetstr("cd");
+    CE = Tgetstr("ce");
+    CL = Tgetstr("cl");
+    CM = Tgetstr("cm");
+    SE = Tgetstr("se");
+    SO = Tgetstr("so");
+#ifdef linux
+    CF = Tgetstr("vi");
+    CN = Tgetstr("ve");
+#else
+    CF = Tgetstr("CF");
+    CN = Tgetstr("CN");
+#endif
+    if (CF && !CN)
+       CN = Tgetstr("CO");
diff --git a/Applications/levee/termcap.i b/Applications/levee/termcap.i
new file mode 100644 (file)
index 0000000..312f534
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Termcap handlers
+ *
+ * Routines included:
+ *   tc_init() -- set up all the terminal stuff levee will need.
+ *  *xtract() -- get a field out of the termcap entry.
+ *  *parseit() -- parse a termcap field.
+ *   tgoto()   -- put a gotoXY string into a buffer.
+ *  * -> internal routine.
+ */
+
+#if RMX | MSDOS                /* default to ANSI.SYS termcap */
+char termcap[200] = "Ansi subset:CM=\033[%d;%dH,Y,1,1:\
+CE=\033[K:CL=\033[H\033[J:LINES=24:COLS=79:HO=\033[H:FkL=\033:\
+CurR=C:CurL=D:CurU=A:CurD=B";
+#endif
+
+char *
+parseit(char *ptr, char **savearea)
+{
+    char *p = *savearea;
+    char *op = *savearea;
+    int tmp;
+
+    while (*ptr && *ptr != ':') {
+       if (*ptr == '\\' && ptr[1]) {
+           ++ptr;
+           switch (*ptr) {
+             case 'E':
+               *p++ = '\033';
+               break;
+             case '0': case '1': case '2': case '3': case '4':
+             case '5': case '6': case '7': case '8': case '9':
+                 tmp = 0;
+                 while (*ptr >= '0' && *ptr <= '9')
+                     tmp = (tmp*8)+(*ptr++ - '0');
+                 *p++ = tmp;
+                 --ptr;
+             default:
+                 *p++ = *ptr;
+           }
+       }
+       else *p++ = *ptr;
+       ++ptr;
+    }
+    *p++ = 0;
+    *savearea = p;
+    return op;
+} /* parseit */
+
+char *
+xtract(char *ptr, char name[], char **savearea)
+/* get something from the termcap
+ *
+ * arguments: tcentry -- the termcap entry
+ *            what    -- the field we want to get (NULL means first field)
+ *            savearea-- pointer to static buffer for parsed fields.
+ */
+{
+    int size;
+
+    if (!ptr)
+       return NULL;
+
+    if (!name) /* return first field of entry -- terminal name? */
+       return parseit(ptr,savearea);
+
+    size = strlen(name);
+    /*
+     * always skip the first (terminal name) field
+     */
+    while (*ptr) {
+       while (*ptr && *ptr != ':') {
+           if (*ptr == '\\')
+               ptr++;
+           ptr++;
+       }
+       if (*ptr)
+           ptr++;
+       if (*ptr && strncmp(name,ptr,size) == 0 && ptr[size] == '=')
+           return parseit(&ptr[1+size],savearea);
+       puts("\r");
+    }
+    return NULL;
+} /* xtract */
+
+char
+charext(char *tc, char *what, char **savearea)
+/* get a character field from the termcap */
+{
+    char *p = xtract(tc,what,savearea);
+    if (p)
+       return *p;
+    return 0;
+} /* charext */
+
+/* internal variables just for termcap */
+static int _Xfirst, _xpad, _ypad;
+
+void tc_init(void)
+/* get the termcap stuff and go berserk parsing it */
+/* if anything horrid goes wrong, levee will crash */
+{
+#if RMX
+    char *p = termcap;
+#else
+    char *getenv();
+    char *p = getenv("TERMCAP");
+#endif
+    char *lp, *ptr;
+
+#if MSDOS
+    if (!p)
+       p = termcap;
+#endif
+#if !(RMX|MSDOS)
+    if (!p) {
+       puts("lv: no termcap\n");
+       exit(1);
+    }
+#endif
+    lp = Malloc(strlen(p)+1);
+    if (!lp) {
+       puts("lv: out of memory\n");
+       exit(1);
+    }
+
+    TERMNAME = xtract(p,NULL,&lp);
+    CM   = xtract(p,"CM",&lp);
+    HO   = xtract(p,"HO",&lp);
+    UP   = xtract(p,"UP",&lp);
+    CE   = xtract(p,"CE",&lp);
+    CL   = xtract(p,"CL",&lp);
+    BELL = xtract(p,"BELL",&lp);
+    if (!BELL)
+       BELL = "\007";
+    OL   = xtract(p,"OL",&lp);
+    UpS  = xtract(p,"UpS",&lp);
+    CURon= xtract(p,"CURon",&lp);
+    CURoff=xtract(p,"CURoff",&lp);
+
+    FkL  = charext(p,"FkL",&lp);
+    CurRT= charext(p,"CurR",&lp);
+    CurLT= charext(p,"CurL",&lp);
+    CurUP= charext(p,"CurU",&lp);
+    CurDN= charext(p,"CurD",&lp);
+
+    canUPSCROLL = (UpS != NULL);
+    CA = (CM != NULL);
+
+    if ((LINES=atoi(ptr=xtract(p,"LINES",&lp))) <= 0) {
+       puts("lv: bad termcap");
+       exit(1);
+    }
+    dofscroll = LINES/2;
+    if ((COLS=atoi(ptr=xtract(p,"COLS",&lp))-1) <= 0 || COLS >= MAXCOLS) {
+       puts("lv: bad termcap");
+       exit(1);
+    }
+
+    _ypad = _xpad = 0;
+    _Xfirst = 1;
+
+    p = CM;
+
+    while (*p && *p != ',')
+       p++;
+    if (!*p)
+       return;
+    *p++ = 0;
+    if (*p != ',')
+       _Xfirst = (*p++ == 'X');
+    if (!*p)
+       return;
+    ++p;
+    while (*p && *p != ',')
+       _xpad = (_xpad*10) + (*p++ - '0');
+    if (!*p)
+       return;
+    ++p;
+    while (*p)
+       _ypad = (_ypad*10) + (*p++ - '0');
+}
+
+#define tgoto(s,y,x)   (_Xfirst?sprintf(s,CM,x+_xpad,y+_ypad):\
+                               sprintf(s,CM,y+_ypad,x+_xpad))
diff --git a/Applications/levee/ucsd.c b/Applications/levee/ucsd.c
new file mode 100644 (file)
index 0000000..805e262
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+
+#ifndef moveleft
+
+PROC
+moveleft(char *src, char *dest, int length)
+{
+    while (--length >= 0)
+       *(dest++) = *(src++);
+}
+
+#endif /*moveleft*/
+
+#ifndef moveright
+
+PROC
+moveright(char *src, char *dest, int length)
+{
+    src = &src[length];
+    dest = &dest[length];
+    while (--length >= 0)
+       *(--dest) = *(--src);
+}
+
+#endif /*moveright*/
+
+#ifndef fillchar
+
+PROC
+fillchar(char *src,int length, char ch)
+{
+    while (--length >= 0)
+       *(src++) = ch;
+}
+
+#endif
+
+int PROC
+scan(int length, char tst, char ch, char *src)
+{
+    register inc,l;
+    
+    if (length < 0)
+       inc = -1;
+    else
+       inc = 1;
+    if (tst == '!') {
+       for(l = ((int)inc)*length; l > 0; l--,src += (long)inc)
+           if (*src != ch)
+               break;
+    }
+    else {
+       for(l = ((int)inc)*length; l > 0; l--,src += (long)inc)
+           if (*src == ch)
+               break;
+    }
+    return length-(inc*l);
+}
diff --git a/Applications/levee/undo.c b/Applications/levee/undo.c
new file mode 100644 (file)
index 0000000..23c9665
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+#include <unistd.h>
+#include <string.h>
+
+#define BUFSZ  sizeof(undo.coreblock)
+#define AVAIL(x)       ((x)<<1)
+#define INDEX(x)       ((1+x)>>1)
+
+bool PROC
+pushblock(struct undostack *u)
+{
+    if (u->blockp == 0)
+       if ((uwrite = OPEN_NEW(undobuf)) < 0)
+           return FALSE;
+    if (BUFSZ == WRITE_TEXT(uwrite, (void *)u->coreblock, BUFSZ)) {
+       u->blockp++;
+       u->ptr = 0;
+       return TRUE;
+    }
+    return FALSE;
+}
+
+bool PROC
+pushw(struct undostack *u, int i)
+{
+    if (u->ptr >= PAGESIZE && !pushblock(u))
+       return FALSE;
+    u->coreblock[u->ptr++] = i;
+    return TRUE;
+}
+
+bool PROC
+pushmem(struct undostack *u, int start, int size)
+{
+    int chunk;
+    bool ok;
+
+    ok = TRUE;
+    while (ok && size > 0) {
+       chunk = min(size, AVAIL(PAGESIZE-u->ptr));
+       moveleft(&core[start], (char*)&u->coreblock[u->ptr], chunk);
+       size -= chunk;
+       start += chunk;
+       if (size > 0)
+           ok = pushblock(u);
+       else
+           u->ptr += INDEX(chunk);
+    }
+    return ok;
+}
+
+PROC
+zerostack(struct undostack *u)
+{
+    if (u->blockp > 0)
+       CLOSE_FILE(uwrite);
+    u->blockp = 0;                      /* initialize the stack */
+    u->ptr = 0;
+}
+
+bool PROC
+uputcmd(struct undostack *u, int size, int start, char cmd)
+{
+    return(pushw(u, size) && pushw(u, start) && pushw(u, cmd));
+}
+
+PROC
+insert_to_undo(struct undostack *u, int start, int size)
+{
+    if (uputcmd(u, size, start, U_DELC)) {
+       fixmarkers(start, size);
+       bufmax += size;
+    }
+    else
+       error();
+}
+
+/* delete stuff from the buffer && put it into the undo stack */
+
+bool PROC
+delete_to_undo(struct undostack *u, int start, int lump)
+{
+    if (lump <= 0)
+       return TRUE;
+    else if (pushmem(u,start,lump) && uputcmd(u,lump,start,U_ADDC)) {
+       moveleft(&core[start+lump], &core[start], bufmax-(start+lump));
+       bufmax -= lump;
+       fixmarkers(start,-lump);
+       return TRUE;
+    }
+    else
+       return FALSE;
+}
+
+/* copy stuff into the undo buffer */
+
+bool PROC
+move_to_undo(struct undostack *u, int start, int lump)
+{
+    return pushmem(u, start, lump) && uputcmd(u,lump,start,U_MOVEC);
+}
+
+bool PROC
+popblock(struct undostack *u)
+{
+    if (u->blockp > 0) {
+       if (SEEK_POSITION(uread, (long)((--u->blockp)*BUFSZ), 0) < 0)
+           return FALSE;
+       if (BUFSZ == READ_TEXT(uread, (void *)u->coreblock, BUFSZ)) {
+           u->ptr = PAGESIZE;
+           return TRUE;
+       }
+    }
+    return FALSE;
+}
+
+bool PROC
+popw(struct undostack *u, int *i)
+{
+    if (u->ptr < 1 && !popblock(u))
+       return FALSE;
+    *i = u->coreblock[--u->ptr];
+    return TRUE;
+}
+
+bool PROC
+popmem(struct undostack *u, int start, int size)
+{
+    int chunk, loc;
+    bool ok;
+
+    loc = start+size;          /* running backwards */
+    ok = TRUE;
+    while (ok && size > 0) {
+       chunk = min(size, AVAIL(u->ptr));
+       size -= chunk;
+       loc -= chunk;
+       moveleft((char*)&u->coreblock[u->ptr-INDEX(chunk)], &core[loc], chunk);
+       if (size > 0)
+           ok = popblock(u);
+       else
+           u->ptr -= INDEX(chunk);
+    }
+    return(ok);
+}
+       
+/* delete (I)nserted text */
+
+bool PROC
+takeout(struct undostack *save_undo, int *curp)
+{
+    int lump;
+
+    return popw(&undo,curp) && popw(&undo,&lump)
+                           && delete_to_undo(save_undo,*curp,lump);
+}
+
+bool PROC
+copyover(struct undostack *save_undo, int *curp)
+{
+    int lump;
+    
+    return popw(&undo, curp) && popw(&undo, &lump)
+                            && move_to_undo(save_undo, *curp, lump)
+                            && popmem(&undo, *curp, lump);
+}
+
+bool PROC
+putin(struct undostack *save_undo, int *curp)
+{
+    int lump;
+    
+    if (popw(&undo,curp) && popw(&undo,&lump) && (bufmax+lump < SIZE)) {
+       insert_to_undo(save_undo, *curp, lump);
+       moveright(&core[*curp], &core[*curp+lump], bufmax-*curp);
+       if (popmem(&undo, *curp, lump))
+           return TRUE;
+       else
+           moveleft(&core[*curp+lump], &core[*curp], bufmax-*curp);
+    }
+    return FALSE;
+}
+
+/* driver for undo -- returns last address modified || -1 if error */
+
+int PROC
+fixcore(int *topp)
+{
+    int curp;
+    static struct undostack save_undo;
+    bool closeio, ok;
+    int cch;
+    
+    if (undo.blockp > 0 || undo.ptr > 0) {
+       closeio = (undo.blockp > 0);
+       if (closeio) {                  /* save diskfile */
+           CLOSE_FILE(uwrite);         /* close current undo file */
+           rename(undobuf,undotmp);
+           uread = OPEN_OLD(undotmp);  /* reopen it for reading */
+           if (uread < 0)
+               return -1;
+       }
+       *topp = SIZE+1;
+       curp = -MAGICNUMBER;
+       save_undo.blockp = save_undo.ptr = 0;
+       ok = TRUE;
+       while (ok && popw(&undo,&cch)) {
+            switch (cch) {
+             case U_ADDC : ok = putin(&save_undo, &curp); break;
+             case U_MOVEC: ok = copyover(&save_undo, &curp); break;
+             case U_DELC : ok = takeout(&save_undo, &curp); break;
+           }
+           if (curp < *topp)
+               *topp = curp;
+       }
+       if (curp >= 0)
+           memcpy(&undo, &save_undo, sizeof(undo));
+       if (closeio) {
+           CLOSE_FILE(uread);          /* Zap old buffer */
+           unlink(undotmp);
+       }
+       if (!ok)
+           error();
+       return(curp);
+    }
+    return ERR;
+}
diff --git a/Applications/levee/unixcall.c b/Applications/levee/unixcall.c
new file mode 100644 (file)
index 0000000..01715d2
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Unix interface for levee
+ */
+#include "levee.h"
+#include "extern.h"
+#include <termios.h>
+#ifdef GCC
+#include <ioctls.h>
+#endif
+#include <string.h>
+#include <unistd.h>
+
+int
+min(int a, int b)
+{
+    return (a>b) ? b : a;
+}
+
+int
+max(int a,int b)
+{
+    return (a<b) ? b : a;
+}
+
+strput(char *s)
+{
+    if (s)
+       write(1, s, strlen(s));
+}
+
+
+#ifndef GCC
+char *basename(char *s)
+{
+    register char *p;
+
+    if (p=strrchr(s,'/'))
+       return 1+p;
+    return s;
+}
+#endif
+
+
+static int ioset = 0;
+static struct termios old;
+
+void initcon(void)
+{
+    struct termios new;
+
+    if (!ioset) {
+       tcgetattr(0, &old);
+        /*ioctl(0, TCGETS, &old);*/    /* get editing keys */
+
+        erasechar = old.c_cc[VERASE];
+        eraseline = old.c_cc[VKILL];
+
+        memcpy(&new, &old, sizeof(new));
+
+       new.c_iflag &= ~(IXOFF|IXANY|ICRNL|INLCR);
+       new.c_lflag &= ~(ICANON|ISIG|ECHO);
+       new.c_oflag = 0;
+
+       tcsetattr(0, TCSANOW, &new);
+        /*ioctl(0, TCSETS, &new);*/
+        ioset=1;
+    }
+}
+
+void fixcon(void)
+{
+    if (ioset) {
+        tcsetattr(0, TCSANOW, &old);
+         /*ioctl(0, TCSETS, &old);*/
+/*   More or less blind attempt to fix console corruption.
+     T. Huld 1998-05-19
+         ioctl(0, TCSETA, &old);
+*/
+         ioset = 0;
+    }
+}
+
+int getKey(void)
+{
+    unsigned char c;
+
+    read(0,&c,1);
+    return c;
+}
diff --git a/Applications/levee/wildargs.c b/Applications/levee/wildargs.c
new file mode 100644 (file)
index 0000000..dc0bed3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.  THIS SOFTWARE IS PROVIDED
+ * AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * wildcard filename expanders for levee.
+ */
+#include "levee.h"
+#if !(RMX|UNIX)
+# include <glob.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+int wilderr, wildcard;
+
+PROC
+expandargs(char *name, int *argcp, char ***argvp)
+{
+#if RMX|UNIX
+    wilderr = doaddwork(name, argcp, argvp) < 0;
+#else
+    register char *p;
+
+    wilderr = 0;
+
+    if (p=glob(name, (char*)0)) {
+       do {
+           if (doaddwork(p, argcp, argvp) < 0) {
+               wilderr++;
+               break;
+           }
+       } while (p=glob((char*)0, (char*)0));
+    }
+    else if (doaddwork(name, argcp, argvp) < 0)
+       wilderr++;
+#endif /*!RMX*/
+    if (wilderr)
+       killargs(argcp, argvp);
+    return !wilderr;
+}
+
+#define QUANTUM        10
+
+PROC
+doaddwork(char *token,int *argcp, char ***argvp)
+{
+    char **ap = *argvp;
+    int ac = *argcp;
+    int size;
+
+    if ( ac%QUANTUM == 0) {    /* realloc more memory! */
+       size = (QUANTUM+ac)*sizeof(char**);
+       ap = (ac == 0)?malloc(size):realloc(ap, size);
+       if (!ap) {
+           *argcp = 0;
+           goto memfail;
+       }
+    }
+    if (ap[ac] = strdup(token)) {
+#if ST|RMX|FLEXOS
+       strlwr(ap[ac]);         /* monocase filesystem */
+#endif
+       *argvp = ap;
+       return (*argcp)++;
+    }
+memfail:
+    errmsg("no memory");
+    return -1;
+}
+
+PROC
+killargs(int *argcp, char ***argvp)
+{
+    int i;
+
+    for (i=(*argcp)-1; i >= 0; i--)
+       free((*argvp)[i]);
+    if (*argcp)
+       free(*argvp);
+    *argcp = 0;
+    *argvp = 0L;
+}