From 673c74694c7f0c1d4a9a501058bd4a29593a8afd Mon Sep 17 00:00:00 2001
From: David Schmenk <dschmenk@gmail.com>
Date: Tue, 18 Nov 2014 16:13:35 -0800
Subject: [PATCH] Port original PLASMA editor over

---
 src/makefile          |    7 +-
 src/toolsrc/codegen.c |   11 +-
 src/toolsrc/ed.pla    | 1503 +++++++++++++++++++++++++++++++++++++++++
 src/toolsrc/lex.c     |    2 +-
 4 files changed, 1517 insertions(+), 6 deletions(-)
 create mode 100755 src/toolsrc/ed.pla

diff --git a/src/makefile b/src/makefile
index b8fbc84..f14c102 100644
--- a/src/makefile
+++ b/src/makefile
@@ -5,6 +5,7 @@ PLVM01  = A1PLASMA\#060280
 PLVM02	= PLASMA.SYSTEM\#FF2000
 PLVM03	= SOS.INTERP\#050000
 CMD     = CMD\#FF2000
+ED      = ED\#FF2000
 ROD     = ROD\#FE1000
 SIEVE   = SIEVE\#FE1000
 HELLO   = HELLO\#FE1000
@@ -32,7 +33,7 @@ TXTTYPE	= .TXT
 #SYSTYPE	= \#FF2000
 #TXTTYPE	= \#040000
 
-all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03) $(CMD) $(PROFILE) $(ROD) $(SIEVE) $(HGR1)
+all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03) $(CMD) $(PROFILE) $(ED) $(ROD) $(SIEVE) $(HGR1)
 
 clean:
 	-rm *FE1000 *FF2000 $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03)
@@ -81,6 +82,10 @@ test:	samplesrc/test.pla samplesrc/testlib.pla $(PLVM) $(PLASM)
 	acme --setpc 4094 -o $(TESTLIB) samplesrc/testlib.a
 	./$(PLVM) TEST
 
+$(ED): toolsrc/ed.pla $(PLVM02) $(PLASM)
+	./$(PLASM) -A < toolsrc/ed.pla > toolsrc/ed.a
+	acme --setpc 8192 -o $(ED) toolsrc/ed.a
+
 $(ROD): samplesrc/rod.pla $(PLVM02) $(PLASM)
 	./$(PLASM) -AM < samplesrc/rod.pla > samplesrc/rod.a
 	acme --setpc 4094 -o $(ROD) samplesrc/rod.a
diff --git a/src/toolsrc/codegen.c b/src/toolsrc/codegen.c
index 5f14805..cf9fa2a 100755
--- a/src/toolsrc/codegen.c
+++ b/src/toolsrc/codegen.c
@@ -388,10 +388,13 @@ void emit_trailer(void)
 }
 void emit_moddep(char *name, int len)
 {
-    if (name)
-        emit_dci(name, len);
-    else
-        printf("\t%s\t$00\t\t\t; END OF MODULE DEPENDENCIES\n", DB);
+    if (outflags & MODULE)
+    {
+        if (name)
+            emit_dci(name, len);
+        else
+            printf("\t%s\t$00\t\t\t; END OF MODULE DEPENDENCIES\n", DB);
+    }
 }
 void emit_sysflags(int val)
 {
diff --git a/src/toolsrc/ed.pla b/src/toolsrc/ed.pla
new file mode 100755
index 0000000..910dbc5
--- /dev/null
+++ b/src/toolsrc/ed.pla
@@ -0,0 +1,1503 @@
+//
+// Global constants
+//
+const false         = 0
+const true          = !false
+//
+// Hardware constants
+//
+const csw           = $0036
+const speaker       = $C030
+const showgraphics  = $C050
+const showtext      = $C051
+const showfull      = $C052
+const showmix       = $C053
+const showpage1     = $C054
+const showpage2     = $C055
+const showlores     = $C056
+const showhires     = $C057
+const pushbttn1     = $C061
+const pushbttn2     = $C062
+const pushbttn3     = $C063
+const keyboard      = $C000
+const keystrobe     = $C010
+const keyenter      = $8D
+const keyspace      = $A0
+const keyarrowup    = $8B
+const keyarrowdown  = $8A
+const keyarrowleft  = $88
+const keyarrowright = $95
+const keyescape     = $9B
+const keyctrla      = $81
+const keyctrlb      = $82
+const keyctrlc      = $83
+const keyctrld      = $84
+const keyctrle      = $85
+const keyctrlf      = $86
+const keyctrli      = $89
+const keyctrlk      = $8B
+const keyctrll      = $8C
+const keyctrln      = $8E
+const keyctrlo      = $8F
+const keyctrlp      = $90
+const keyctrlq      = $91
+const keyctrlr      = $92
+const keyctrls      = $93
+const keyctrlt      = $94
+const keyctrlu      = $95
+const keyctrlv      = $96
+const keyctrlw      = $97
+const keyctrlx      = $98
+const keyctrlz      = $9A
+const keydelete     = $FF
+const getbuff       = $01FF
+//
+// Data and text buffer constants
+//
+const machid        = $BF98
+const maxlines      = 1500
+const maxfill       = 1524
+const iobuffer      = $0800
+const databuff      = $0C00
+const strlinbuf     = $1000
+const strheapmap    = $1F00
+const strheapmsz    = 224 // $E0 = 28K is memory@16 bytes per bit map, 128 bytes per 8 bit map, 1K bytes per 8 byte map
+const maxlnlen      = 79
+const strheap       = $4800
+const strheasz      = $7000
+const pgjmp         = 16
+const changed       = 1
+const insmode       = 2
+const showcurs      = 4
+const uppercase     = 8
+const shiftlock     = 128
+//
+// Argument buffer
+//
+word	          = $EEEE
+byte              = 32 // buffer length
+byte[32] argbuff  = ""
+//
+// Text screen row address array
+//
+word txtscrn      = $0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780
+word              = $0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8
+word              = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0
+//
+// Editor variables
+//
+byte nullstr      = ""
+byte version      = "PLASMA ][ EDITOR VERSION 0.9 "
+byte errorstr     = "ERROR: $"
+byte okstr        = "OK"
+byte outofmem     = "OUT OF MEMORY!"
+byte losechng     = "LOSE CHANGES TO FILE (Y/N)?"
+byte untitled     = "UNTITLED"
+byte[64] txtfile  = "UNTITLED.PLA"
+byte flags        = 0
+byte flash        = 0
+word numlines     = 0
+word cutbuf       = 0
+byte perr, cursx, cursy, scrnleft, curscol, underchr, curschr
+word keyin, cursrow, scrntop, cursptr
+//
+// Predeclared functions
+//
+predef cmdmode
+//
+// Utility functions
+//
+// Defines for ASM routines
+//
+asm equates
+INTERP	=	$03D0
+LCRDEN 	=	$C080
+LCWTEN	=	$C081
+ROMEN	=	$C082
+LCRWEN 	=	$C083
+LCBNK2	=	$00
+LCBNK1	=	$08
+	!SOURCE	"vmsrc/plvmzp.inc"
+end
+//
+// CALL 6502 ROUTINE
+// CALL(ADDR, AREG, XREG, YREG, STATUS)
+//
+asm call
+REGVALS	=	SRC
+        PHP
+        LDA     ESTKL+4,X
+        STA     TMPL
+        LDA     ESTKH+4,X
+        STA     TMPH
+        LDA     ESTKL,X
+        PHA
+        LDA     ESTKL+1,X
+        TAY
+        LDA     ESTKL+3,X
+        PHA
+        LDA     ESTKL+2,X
+        INX
+        INX
+        INX
+	INX
+        STX     ESP
+        TAX
+        PLA
+        BIT     ROMEN
+        PLP
+        JSR     JMPTMP
+        PHP
+        BIT     LCRDEN+LCBNK2
+        STA     REGVALS+0
+        STX     REGVALS+1
+        STY     REGVALS+2
+        PLA
+        STA     REGVALS+3
+        LDX     ESP
+        LDA     #<REGVALS
+        LDY     #>REGVALS
+        STA     ESTKL,X
+        STY     ESTKH,X
+        PLP
+        RTS
+JMPTMP	JMP	(TMP)
+end
+//
+// CALL PRODOS
+// SYSCALL(CMD, PARAMS)
+//
+asm syscall
+	LDA	ESTKL,X
+	LDY	ESTKH,X
+	STA	PARAMS
+	STY	PARAMS+1
+	INX
+	LDA	ESTKL,X
+	STA	CMD
+	JSR	$BF00
+CMD:	!BYTE	00
+PARAMS:	!WORD	0000
+	LDY    	#$00
+	STA	ESTKL,X
+	STY	ESTKH,X
+	RTS
+end
+// SET MEMORY TO VALUE
+// MEMSET(ADDR, SIZE, VALUE)
+//   With optimizations from Peter Ferrie
+//
+asm memset
+	LDY     #$00
+	LDA     ESTKL+2,X
+	STA     DSTL
+	LDA     ESTKH+2,X
+	STA     DSTH
+	INC     ESTKL+1,X
+	INC     ESTKH+1,X
+SETMLPL	CLC
+	LDA     ESTKL,X
+SETMLPH	DEC     ESTKL+1,X
+	BNE     +
+	DEC     ESTKH+1,X
+	BEQ     SETMEX
++	STA     (DST),Y
+	INY
+	BNE	+
+	INC     DSTH
++	BCS	SETMLPL
+	SEC
+	LDA     ESTKH,X
+	BCS	SETMLPH
+SETMEX	INX
+	INX
+	RTS
+end
+//
+// COPY MEMORY
+// MEMCPY(DSTADDR, SRCADDR, SIZE)
+//
+asm memcpy
+	INX
+	INX
+	LDA	ESTKL-2,X
+	ORA	ESTKH-2,X
+	BEQ	CPYMEX
+	LDA	ESTKL-1,X
+	CMP	ESTKL,X
+	LDA	ESTKH-1,X
+	SBC	ESTKH,X
+ 	BCC	REVCPY
+;
+; FORWARD COPY
+;
+	LDA	ESTKL,X
+	STA 	DSTL
+	LDA	ESTKH,X
+	STA 	DSTH
+	LDA	ESTKL-1,X
+	STA 	SRCL
+	LDA	ESTKH-1,X
+	STA 	SRCH
+	INC 	ESTKH-2,X
+	LDY	#$00
+FORCPYLP LDA	(SRC),Y
+	STA	(DST),Y
+	INY
+	BNE	+
+	INC	DSTH
+	INC	SRCH
++	DEC 	ESTKL-2,X
+	BNE	FORCPYLP
+	DEC	ESTKH-2,X
+	BNE	FORCPYLP
+	RTS
+;
+; REVERSE COPY
+;
+REVCPY	;CLC
+	LDA 	ESTKL-2,X
+	ADC	ESTKL,X
+	STA	DSTL
+	LDA	ESTKH-2,X
+	ADC	ESTKH,X
+	STA	DSTH
+	CLC
+	LDA 	ESTKL-2,X
+	ADC	ESTKL-1,X
+	STA	SRCL
+	LDA	ESTKH-2,X
+	ADC	ESTKH-1,X
+	STA	SRCH
+	INC 	ESTKH-2,X
+	DEC	DSTH
+	DEC	SRCH
+	LDY	#$FF
+REVCPYLP LDA	(SRC),Y
+	STA	(DST),Y
+	DEY
+	CPY	#$FF
+	BNE	+
+	DEC	DSTH
+	DEC	SRCH
++	DEC 	ESTKL-2,X
+	BNE	REVCPYLP
+	DEC	ESTKH-2,X
+	BNE	REVCPYLP
+CPYMEX	RTS
+end
+//
+// CHAR OUT
+// COUT(CHAR)
+//
+asm cout
+	LDA	ESTKL,X
+	ORA 	#$80
+	BIT	ROMEN
+	JSR	$FDED
+	BIT	LCRDEN+LCBNK2
+	RTS
+end
+//
+// CHAR IN
+// RDKEY()
+//
+asm cin
+	BIT	ROMEN
+	JSR	$FD0C
+	BIT	LCRDEN+LCBNK2
+	DEX
+	LDY	#$00
+	STA	ESTKL,X
+	STY	ESTKH,X
+	RTS
+end
+//
+// PRINT STRING
+// PRSTR(STR)
+//
+asm prstr
+	LDY	#$00
+	LDA     ESTKL,X
+	STA     SRCL
+	LDA     ESTKH,X
+	STA     SRCH
+	LDA     (SRC),Y
+	STA     TMP
+	BEQ     ++
+	BIT	ROMEN
+-	INY
+	LDA	(SRC),Y
+	ORA	#$80
+	JSR	$FDED
+	CPY	TMP
+	BNE	-
+	BIT	LCRDEN+LCBNK2
+++	RTS
+end
+//
+// READ STRING
+// STR = RDSTR(PROMPTCHAR)
+//
+asm rdstr
+        LDA     ESTKL,X
+        STA     $33
+        STX     ESP
+        BIT     ROMEN
+        JSR     $FD6A
+	BIT	LCRDEN+LCBNK2
+        STX     $01FF
+-       LDA     $01FF,X
+        AND     #$7F
+        STA     $01FF,X
+        DEX
+        BPL     -
+        LDX     ESP
+        LDA     #$FF
+        STA     ESTKL,X
+        LDA     #$01
+        STA     ESTKH,X
+	RTS
+end
+//
+// EXIT
+//
+asm exit
+        JSR	$BF00
+        !BYTE	$65
+        !WORD	EXITTBL
+EXITTBL:
+        !BYTE	4
+        !BYTE	0
+end
+//def toupper_11(c)
+//   if c >= 'a'
+//       if c <= 'z'
+//           return c - $20
+//       fin
+//   fin
+//   return c
+//end
+asm toupper
+        LDA     ESTKL,X
+	AND     #$7F
+        CMP     #'a'
+        BCC     +
+        CMP     #'z'+1
+        BCS     +
+        SEC
+        SBC     #$20
++       STA     ESTKL,X
+	RTS
+end
+asm clrhibit(strptr)
+        LDA     ESTKL,X
+        STA     SRCL
+        LDA     ESTKH,X
+        STA     SRCH
+        LDY     #$00
+        LDA     (SRC),Y
+        BEQ     +
+        TAY
+CLHILP  LDA     (SRC),Y
+        AND     #$7F
+        STA     (SRC),Y
+        DEY
+        BNE     CLHILP
++	RTS
+end
+asm sethibit(strptr)
+        LDA     ESTKL,X
+        STA     SRCL
+        LDA     ESTKH,X
+        STA     SRCH
+        LDY     #$00
+        LDA     (SRC),Y
+        BEQ     +
+        TAY
+STHILP  LDA     (SRC),Y
+        ORA     #$80
+        STA     (SRC),Y
+        DEY
+        BNE     STHILP
++	RTS
+end
+asm cpyln(srcstr, dststr)
+        LDA     ESTKL,X
+        STA     DSTL
+        LDA     ESTKH,X
+        STA     DSTH
+	INX
+        LDA     ESTKL,X
+        STA     SRCL
+        LDA     ESTKH,X
+        STA     SRCH
+        LDY     #$00
+        LDA     (SRC),Y
+        TAY
+        LDA     #$00
+        INY
+        STA     (DST),Y
+        DEY
+        BEQ     ++
+CPLNLP  LDA     (SRC),Y
+        CMP     #$20
+        BCS     +
+        ADC     #$60
++       AND     #$7F
+        STA     (DST),Y
+        DEY
+        BNE     CPLNLP
+        LDA     (SRC),Y
+++      STA     (DST),Y
+	RTS
+end
+//
+// ProDOS routines
+//
+def getpfx(path)
+    byte params[3]
+
+    ^path    = 0
+    params.0 = 1
+    params:1 = path
+    perr     = syscall($C7, @params)
+    return path
+end
+def setpfx(path)
+    byte params[3]
+
+    params.0 = 1
+    params:1 = path
+    perr     = syscall($C6, @params)
+    return path
+end
+def open(path, buff)
+    byte params[6]
+
+    params.0 = 3
+    params:1 = path
+    params:3 = buff
+    params.5 = 0
+    perr     = syscall($C8, @params)
+    return params.5
+end
+def close(refnum)
+    byte params[2]
+
+    params.0 = 1
+    params.1 = refnum
+    perr     = syscall($CC, @params)
+    return perr
+end
+def read(refnum, buff, len)
+    byte params[8]
+
+    params.0 = 4
+    params.1 = refnum
+    params:2 = buff
+    params:4 = len
+    params:6 = 0
+    perr     = syscall($CA, @params)
+    return params:6
+end
+def write(refnum, buff, len)
+    byte params[8]
+
+    params.0 = 4
+    params.1 = refnum
+    params:2 = buff
+    params:4 = len
+    params:6 = 0
+    perr     = syscall($CB, @params)
+    return params:6
+end
+def create(path, access, type, aux)
+    byte params[12]
+
+    params.0  = 7
+    params:1  = path
+    params.3  = access
+    params.4  = type
+    params:5  = aux
+    params.7  = $1
+    params:8  = 0
+    params:10 = 0
+    perr      = syscall($C0, @params)
+    return perr
+end
+def destroy(path)
+    byte params[12]
+
+    params.0 = 1
+    params:1 = path
+    perr     = syscall($C1, @params)
+    return perr
+end
+def newline(refnum, emask, nlchar)
+    byte params[4]
+
+    params.0 = 3
+    params.1 = refnum
+    params.2 = emask
+    params.3 = nlchar
+    perr     = syscall($C9, @params)
+    return perr
+end
+
+//=====================================
+//
+//            Editor
+//
+//=====================================
+
+def crout
+    cout($0D)
+end
+def bell
+    return call($FBDD, 0, 0, 0, 0)
+end
+//
+// Memory management routines
+//
+def strcpy(srcstr, dststr)
+    byte strlen
+
+    strlen = ^srcstr
+    while (srcstr).[strlen] == $8D or (srcstr).[strlen] == $A0
+        strlen = strlen - 1
+    loop
+    ^dststr = strlen
+    memcpy(dststr + 1, srcstr + 1, strlen)
+end
+def heapaddr(ofst, mask)
+    word addr
+
+    addr = (ofst << 7) + strheap
+    while !(mask & 1)
+        addr = addr + 16
+        mask = mask >> 1
+    loop
+    return addr
+end
+def sizemask(size)
+    if size <= 16
+        return $01
+    elsif size <= 32
+        return $03
+    elsif size <= 48
+        return $07
+    elsif size <= 64
+        return $0F
+    elsif size <= 80
+        return $1F
+    fin
+    return 0
+end
+def heapalloc(size)
+    byte szmask, i
+    word mapmask
+
+    szmask = sizemask(size)
+    for i = strheapmsz - 1 downto 0
+        if strheapmap.[i] <> $FF
+            mapmask = szmask
+            repeat
+                if strheapmap.[i] & mapmask
+                    mapmask = mapmask << 1
+                else
+                    strheapmap.[i] = strheapmap.[i] | mapmask
+                    return heapaddr(i, mapmask)
+                fin
+            until mapmask & $100
+        fin
+    next
+    bell()
+    prstr(@outofmem)
+    return 0
+end
+def freestr(strptr)
+    byte mask, ofst
+
+    if strptr and strptr <> @nullstr
+        mask = sizemask(^strptr + 1)
+        ofst = (strptr - strheap) >> 4
+        mask = mask << (ofst & $07)
+        ofst = ofst >> 3
+        strheapmap.[ofst] = strheapmap.[ofst] & ~mask
+    fin
+end
+def newstr(strptr)
+    byte strlen
+    word newptr
+
+    strlen = ^strptr
+    while (strptr).[strlen] == $8D or (strptr).[strlen] == $A0
+        strlen = strlen - 1
+    loop
+    if strlen == 0
+        return @nullstr
+    fin
+    newptr = heapalloc(strlen + 1)
+    if newptr
+        memcpy(newptr, strptr, strlen + 1)
+        ^newptr = strlen
+        return newptr
+    fin
+    return @nullstr
+end
+def inittxtbuf
+    word i
+
+    memset(strheapmap, strheapmsz, 0)
+    memset(strlinbuf, maxfill * 2, @nullstr)
+    numlines   = 1
+    cursrow    = 0
+    curscol    = 0
+    cursx      = 0
+    cursy      = 0
+    scrnleft   = 0
+    scrntop    = 0
+    cutbuf     = 0
+end
+//
+// Case conversion/printing routines
+//
+def caseconv(chr)
+    if flags & uppercase
+        if chr & $E0 == $E0
+            chr = chr - $E0
+        fin
+    fin
+    return chr
+end
+def strupper(strptr)
+    byte i, chr
+
+    for i = ^strptr downto 1
+        chr = (strptr).[i]
+        if chr & $E0 == $E0
+            (strptr).[i] = chr - $E0
+        fin
+    next
+end
+def strlower(strptr)
+    byte i, chr
+
+    for i = ^strptr downto 1
+        chr = (strptr).[i]
+        if chr & $E0 == $00
+            (strptr).[i] = chr + $E0
+        fin
+    next
+end
+def txtupper
+    word i, strptr
+
+    flags = flags | uppercase
+    for i = numlines - 1 downto 0
+        strupper(strlinbuf:[i])
+    next
+end
+def txtlower
+    word i, strptr
+
+    flags = flags & ~uppercase
+    for i = numlines - 1 downto 0
+        strlower(strlinbuf:[i])
+    next
+end
+def prbyte(h)
+    cout('$')
+    return call($FDDA, h, 0, 0, 0)
+end
+def prword(h)
+    cout('$')
+    return call($F941, h >> 8, h, 0, 0)
+end
+def print(i)
+    byte numstr[7]
+    byte place, sign
+
+    place = 6
+    if i < 0
+        sign = 1
+        i    = -i
+    else
+        sign = 0
+    fin
+    while i >= 10
+        numstr[place] = i % 10 + '0'
+        i             = i / 10
+        place         = place - 1
+    loop
+    numstr[place] = i + '0'
+    place         = place - 1
+    if sign
+        numstr[place] = '-'
+        place         = place - 1
+    fin
+    numstr[place] = 6 - place
+    return prstr(@numstr[place])
+end
+def nametostr(namestr, len, strptr)
+    ^strptr = len
+    return memcpy(strptr + 1, namestr, len)
+end
+//
+// File routines
+//
+def readtxt(filename)
+    byte txtbuf[81], refnum, i, j
+
+    refnum = open(filename, iobuffer)
+    if refnum
+        newline(refnum, $7F, $0D)
+        repeat
+            txtbuf = read(refnum, @txtbuf + 1, maxlnlen)
+            if txtbuf
+                sethibit(@txtbuf)
+                if flags & uppercase; strupper(@txtbuf); fin
+                strlinbuf:[numlines] = newstr(@txtbuf)
+                numlines = numlines + 1
+            fin
+            if !(numlines & $0F); cout('.'); fin
+        until txtbuf == 0 or numlines == maxlines
+        close(refnum)
+	//
+	// Make sure there is a blank line at the end of the buffer
+	//
+	if numlines < maxlines and strlinbuf:[numlines - 1] <> @nullstr
+	    strlinbuf:[numlines] = @nullstr
+	    numlines = numlines + 1
+	fin
+    fin
+end
+def writetxt(filename)
+    byte txtbuf[81], refnum
+    byte j, chr
+    word i, strptr
+
+    destroy(filename)
+    create(filename, $C3, $04, $00) // full access, TXT file
+    refnum = open(filename, iobuffer)
+    if refnum == 0
+        return
+    fin
+    //
+    // Remove blank lines at end of text.
+    //
+    while numlines > 1 and strlinbuf:[numlines - 1] == @nullstr; numlines = numlines - 1; loop
+    //
+    // Write all the text line to the file.
+    //
+    for i = 0 to numlines - 1
+        cpyln(strlinbuf:[i], @txtbuf)
+        txtbuf = txtbuf + 1
+        txtbuf[txtbuf] = $0D
+        write(refnum, @txtbuf + 1, txtbuf)
+        if !(i & $0F); cout('.'); fin
+    next
+    return close(refnum)
+end
+//
+// Screen routines
+//
+def clrscrn
+    return call($FC58, 0, 0, 0, 0)
+end
+def drawrow(row, ofst, strptr)
+    byte numchars
+    word scrnptr
+
+    scrnptr = txtscrn[row]
+    if ofst >= ^strptr
+        numchars = 0
+    else
+        numchars = ^strptr - ofst
+    fin
+    if numchars >= 40
+        numchars = 40
+    else
+        memset(scrnptr + numchars, 40 - numchars, $A0A0)
+    fin
+    return memcpy(scrnptr, strptr + ofst + 1, numchars)
+end
+def drawscrn(toprow, ofst)
+    byte row, numchars
+    word numchars, strptr, scrnptr
+
+    if ofst
+        for row = 0 to 23
+            strptr   = strlinbuf:[toprow + row]
+	    scrnptr  = txtscrn[row]
+	    if ofst >= ^strptr
+	        numchars = 0
+	    else
+                numchars = ^strptr - ofst
+	    fin
+	    if numchars >= 40
+                numchars = 40
+	    else
+	        memset(scrnptr + numchars, 40 - numchars, $A0A0)
+       	    fin
+	    memcpy(scrnptr, strptr + ofst + 1, numchars)
+        next
+    else
+        for row = 0 to 23
+            strptr   = strlinbuf:[toprow + row]
+	    scrnptr  = txtscrn[row]
+	    numchars = ^strptr
+	    if numchars >= 40
+                numchars = 40
+	    else
+	        memset(scrnptr + numchars, 40 - numchars, $A0A0)
+       	    fin
+	    memcpy(scrnptr, strptr + 1, numchars)
+        next
+    fin
+end
+def cursoff
+    if flags & showcurs
+        ^cursptr = underchr
+        flags = flags & ~showcurs
+    fin
+end
+def curson
+    if !(flags & showcurs)
+        cursptr  = txtscrn[cursy] + cursx
+        underchr = ^cursptr
+        ^cursptr = curschr
+        flags = flags | showcurs
+    fin
+end
+def cursflash
+    if flags & showcurs
+        if flash == 0
+            ^cursptr = curschr
+        elsif flash == 128
+            ^cursptr = underchr
+        fin
+        flash = flash + 1
+    fin
+end
+def redraw
+    cursoff
+    drawscrn(scrntop, scrnleft)
+    curson
+end
+def curshome
+    cursoff
+    cursrow  = 0
+    curscol  = 0
+    cursx    = 0
+    cursy    = 0
+    scrnleft = 0
+    scrntop  = 0
+    drawscrn(scrntop, scrnleft)
+    return curson
+end
+def cursend
+    cursoff
+    if numlines > 23
+        cursrow  = numlines - 1
+        cursy    = 23
+        scrntop  = cursrow - 23
+    else
+        cursrow  = numlines - 1
+        cursy    = numlines - 1
+        scrntop  = 0
+    fin
+    curscol  = 0
+    cursx    = 0
+    scrnleft = 0
+    drawscrn(scrntop, scrnleft)
+    return curson
+end
+def cursup
+    if cursrow > 0
+        cursoff
+        cursrow = cursrow - 1
+        if cursy > 0
+            cursy = cursy - 1
+        else
+            scrntop = cursrow
+            drawscrn(scrntop, scrnleft)
+        fin
+        curson
+    fin
+end
+def pgup
+    byte i
+
+    for i = pgjmp downto 0
+        cursup
+    next
+end
+def cursdown
+    if cursrow < numlines - 1
+        cursoff
+        cursrow = cursrow + 1
+        if cursy < 23
+            cursy = cursy + 1
+        else
+            scrntop = cursrow - 23
+            drawscrn(scrntop, scrnleft)
+        fin
+        curson
+    fin
+end
+def pgdown
+    byte i
+
+    for i = pgjmp downto 0
+        cursdown
+    next
+end
+def cursleft
+    if curscol > 0
+        cursoff
+        curscol = curscol - 1
+        if cursx > 0
+            cursx = cursx - 1
+        else
+            scrnleft = curscol
+            drawscrn(scrntop, scrnleft)
+        fin
+        curson
+    fin
+end
+def pgleft
+    byte i
+
+    for i = 7 downto 0
+        cursleft
+    next
+end
+def cursright
+    if curscol < 80
+        cursoff
+        curscol = curscol + 1
+        if cursx < 39
+            cursx = cursx + 1
+        else
+            scrnleft = curscol - 39
+            drawscrn(scrntop, scrnleft)
+        fin
+        curson
+    fin
+end
+def pgright
+    byte i
+
+    for i = 7 downto 0
+        cursright
+    next
+end
+//
+// Keyboard routines
+//
+def keyin2e
+    repeat
+        cursflash
+    until ^keyboard >= 128
+    return ^keystrobe
+end
+def keyin2
+    byte key
+
+    repeat
+        cursflash
+        key = ^keyboard
+        if key == keyctrll
+            ^keystrobe
+            flags = flags ^ shiftlock
+            key   = 0
+        fin
+    until key >= 128
+    ^keystrobe
+    if key == keyctrln
+        key = $DB // [
+    elsif key == keyctrlp
+        key = $DF // _
+    elsif key == keyctrlb
+        key = $DC // \
+    elsif key == keyarrowleft
+        if ^pushbttn3 < 128
+            key = $FF
+        fin
+    elsif key >= $C0 and flags < shiftlock
+        if ^pushbttn3 < 128
+            if key == $C0
+                key = $D0 // P
+            elsif key == $DD
+                key = $CD // M
+            elsif key == $DE
+                key = $CE // N
+            fin
+        else
+           key = key | $E0
+        fin
+    fin
+    return key
+end
+//
+// Printer routines
+//
+def printtxt(slot)
+    byte txtbuf[80]
+    word i, scrncsw
+
+    scrncsw = *(csw)
+    *(csw)  = $C000 | (slot << 8)
+    for i = 0 to numlines - 1
+        cpyln(strlinbuf:[i], @txtbuf)
+        prstr(@txtbuf)
+        crout
+    next
+    *(csw) = scrncsw
+end
+def openline(row)
+    if numlines < maxlines
+        memcpy(@strlinbuf:[row + 1], @strlinbuf:[row], (numlines - row) * 2)
+        strlinbuf:[row] = @nullstr
+        numlines = numlines + 1
+        flags = flags | changed
+        return 1
+    fin
+    bell
+    return 0
+end
+def cutline
+    freestr(cutbuf)
+    cutbuf = strlinbuf:[cursrow]
+    memcpy(@strlinbuf:[cursrow], @strlinbuf:[cursrow + 1], (numlines - cursrow) * 2)
+    if numlines > 1
+        numlines = numlines - 1
+    fin
+    flags = flags | changed
+    if cursrow == numlines
+        cursup
+    fin
+    return redraw
+end
+def pasteline
+    if cutbuf and numlines < maxlines
+        memcpy(@strlinbuf:[cursrow + 1], @strlinbuf:[cursrow], (numlines - cursrow) * 2)
+        strlinbuf:[cursrow] = newstr(cutbuf)
+        numlines = numlines + 1
+        flags = flags | changed
+        redraw
+    else
+        bell
+    fin
+end
+def joinline
+    byte joinstr[80], joinlen
+
+    if cursrow < numlines - 1
+        strcpy(strlinbuf:[cursrow], @joinstr)
+        joinlen = joinstr + ^(strlinbuf:[cursrow + 1])
+        if joinlen < 80
+            memcpy(@joinstr + joinstr + 1, strlinbuf:[cursrow + 1] + 1, ^(strlinbuf:[cursrow + 1]))
+            joinstr = joinlen
+            freestr(strlinbuf:[cursrow])
+            strlinbuf:[cursrow] = newstr(@joinstr)
+            freestr(strlinbuf:[cursrow + 1])
+            numlines = numlines - 1
+            memcpy(@strlinbuf:[cursrow + 1], @strlinbuf:[cursrow + 2], (numlines - cursrow) * 2)
+            flags = flags | changed
+            redraw
+        else
+            bell
+        fin
+    fin
+end
+def splitline
+    byte splitstr[80], splitlen
+
+    if openline(cursrow + 1)
+        if curscol
+            splitlen = ^(strlinbuf:[cursrow])
+            if curscol < splitlen - 1
+                memcpy(@splitstr + 1, strlinbuf:[cursrow] + curscol + 1, splitlen - curscol)
+                splitstr = splitlen - curscol
+                strlinbuf:[cursrow + 1] = newstr(@splitstr)
+                memcpy(@splitstr + 1, strlinbuf:[cursrow] + 1, curscol)
+                splitstr = curscol
+                freestr(strlinbuf:[cursrow])
+                strlinbuf:[cursrow] = newstr(@splitstr)
+            fin
+        else
+            strlinbuf:[cursrow + 1] = strlinbuf:[cursrow]
+            strlinbuf:[cursrow]     = @nullstr
+        fin
+        curscol  = 0
+        cursx    = 0
+        scrnleft = 0
+        redraw
+        cursdown
+    fin
+end
+def editkey(key)
+    if key >= keyspace
+        return true
+    elsif key == keydelete
+        return true
+    elsif key == keyctrld
+        return true
+    elsif key == keyctrlr
+        return true
+    fin
+    return false
+end
+def editline(key)
+    byte editstr[80]
+    word undoline
+
+    if (editkey(key))
+        flags = flags | changed
+        memset(@editstr, 80, $A0A0)
+        strcpy(strlinbuf:[cursrow], @editstr)
+        undoline = strlinbuf:[cursrow]
+        strlinbuf:[cursrow] = @editstr
+        repeat
+            if key >= keyspace
+                if key == keydelete
+                    if curscol > 0
+                        if curscol <= editstr
+                            memcpy(@editstr[curscol], @editstr[curscol + 1], editstr - curscol)
+                            editstr = editstr - 1
+                        fin
+                        curscol = curscol - 1
+                        cursoff
+                        if cursx > 0
+                            cursx = cursx - 1
+                            drawrow(cursy, scrnleft, @editstr)
+                        else
+                            scrnleft = scrnleft - 1
+                            drawscrn(scrntop, scrnleft)
+                        fin
+                        curson
+                    fin
+                elsif curscol < maxlnlen
+                    curscol = curscol + 1
+                    cursx   = cursx   + 1
+                    if flags & insmode
+                        if editstr < maxlnlen or editstr.maxlnlen == $A0
+                            editstr = editstr + 1
+                            if curscol >= editstr
+                                editstr = curscol
+                            else
+                                memcpy(@editstr[curscol + 1], @editstr[curscol], editstr - curscol)
+                            fin
+                        else
+                            curscol = curscol - 1
+                            cursx   = cursx   - 1
+                            key     = editstr[curscol]
+                            bell
+                        fin
+                    else
+                        if curscol > editstr
+                            editstr = curscol
+                        fin
+                    fin
+                    editstr[curscol] = caseconv(key)
+                    cursoff
+                    if cursx <= 39
+                        drawrow(cursy, scrnleft, @editstr)
+                    else
+                        scrnleft = scrnleft + 1
+                        cursx    = 39
+                        drawscrn(scrntop, scrnleft)
+                    fin
+                    curson
+                else
+                    bell
+                fin
+            elsif key == keyctrld
+                if curscol < editstr
+                    strcpy(@editstr, undoline)
+                    memcpy(@editstr[curscol + 1], @editstr[curscol + 2], editstr - curscol)
+                    editstr = editstr - 1
+                    cursoff
+                    drawrow(cursy, scrnleft, @editstr)
+                    curson
+                fin
+            elsif key == keyctrlr
+                strcpy(undoline, @editstr)
+                cursoff
+                drawrow(cursy, scrnleft, @editstr)
+                curson
+            fin
+            key = keyin()
+        until not editkey(key)
+        if editstr
+            strlinbuf:[cursrow] = newstr(@editstr)
+        else
+            strlinbuf:[cursrow] = @nullstr
+        fin
+        freestr(undoline)
+    fin
+    return key
+end
+def editmode
+    repeat
+        when editline(keyin())
+            is keyarrowup
+                cursup; break
+            is keyarrowdown
+                cursdown; break
+            is keyarrowleft
+                cursleft; break
+            is keyarrowright
+                cursright; break
+            is keyctrlw
+                pgup; break
+            is keyctrlz
+                pgdown; break
+            is keyctrla
+                pgleft; break
+            is keyctrls
+                pgright; break
+            is keyctrlq
+                curshome; break
+            is keyctrle
+                cursend; break
+            is keyctrlx
+                cutline; break
+            is keyctrlv
+                pasteline; break
+            is keyctrlf
+	        if numlines < maxlines and cursrow == numlines - 1
+                    strlinbuf:[numlines] = @nullstr
+		    numlines = numlines + 1
+		fin
+	        cursdown
+            is keyctrlo
+                openline(cursrow)
+                redraw
+		break
+            is keyenter
+                if flags & insmode
+                    splitline
+                else
+                    openline(cursrow + 1)
+                    cursdown
+                    redraw
+                fin
+		break
+            is keyctrlt
+                joinline; break
+            is keyctrli
+                if flags & insmode
+                    flags = flags & ~insmode
+                    curschr = ' '
+                else
+                    flags = flags | insmode
+                    curschr = '+'
+                fin
+		break
+            is keyctrlc
+                if flags & uppercase
+                    txtlower
+                else
+                    txtupper
+                fin
+                redraw
+		break
+            is keyescape
+                cursoff
+                cmdmode
+                redraw
+		break
+        wend
+    until false
+end
+//
+// Command mode
+//
+def prfiles(optpath)
+    byte path[64]
+    byte refnum
+    byte firstblk
+    byte entrylen, entriesblk
+    byte i, type, len
+    word entry, filecnt
+
+    if ^optpath
+        strcpy(optpath, @path)
+    else
+        getpfx(@path)
+        prstr(@path)
+        crout
+    fin
+    refnum = open(@path, iobuffer)
+    if perr
+        return perr
+    fin
+    firstblk = 1
+    repeat
+        if read(refnum, databuff, 512) == 512
+            entry = databuff + 4
+            if firstblk
+                entrylen   = databuff.$23
+                entriesblk = databuff.$24
+                filecnt    = databuff:$25
+                entry      = entry + entrylen
+            fin
+            for i = firstblk to entriesblk
+                type = ^entry
+                if type <> 0
+                    len = type & $0F
+                    ^entry = len
+                    prstr(entry)
+                    if type & $F0 == $D0 // Is it a directory?
+                        cout('/')
+                        len = len + 1
+                    fin
+                    for len = 20 - len downto 1
+                        cout(' ')
+                    next
+                    filecnt = filecnt - 1
+                fin
+                entry = entry + entrylen
+            next
+            firstblk = 0
+        else
+            filecnt = 0
+        fin
+    until filecnt == 0
+    close(refnum)
+    crout
+    return 0
+end
+def striplead(strptr, chr)
+    while ^strptr and ^(strptr + 1) == chr
+        memcpy(strptr + 1, strptr + 2, ^strptr)
+        ^strptr = ^strptr - 1
+    loop
+end
+def parsecmd(strptr)
+    byte cmd
+
+    cmd = 0
+    striplead(strptr, ' ')
+    if ^strptr
+        cmd = ^(strptr + 1)
+        memcpy(strptr + 1, strptr + 2, ^strptr)
+        ^strptr = ^strptr - 1
+    fin
+    if ^strptr
+        striplead(strptr, ' ')
+    fin
+    return cmd
+end
+def chkchng
+    if flags & changed
+        prstr(@losechng)
+        if toupper(keyin()) == 'N'
+            crout
+            return false
+        fin
+        crout
+    fin
+    return true
+end
+def quit
+    if chkchng
+        exit
+    fin
+end
+def cmdmode
+    byte slot
+    word cmdptr
+
+    clrscrn
+    prstr(@version)
+    crout
+    while true
+        prstr(@txtfile)
+        cmdptr = rdstr($BA)
+        when toupper(parsecmd(cmdptr))
+            is 'A'
+                readtxt(cmdptr)
+                flags = flags | changed
+		break
+            is 'R'
+                if chkchng
+                    inittxtbuf
+		    numlines = 0
+                    strcpy(cmdptr, @txtfile)
+                    readtxt(@txtfile)
+		    if numlines == 0; numlines = 1; fin
+                    flags = flags & ~changed
+                fin
+		break
+            is 'W'
+                if ^cmdptr
+                    strcpy(cmdptr, @txtfile)
+                fin
+                writetxt(@txtfile)
+                //if flags & changed; fin
+                flags = flags & ~changed
+		break
+            is 'C'
+                prfiles(cmdptr); break
+            is 'P'
+                setpfx(cmdptr); break
+            is 'H'
+                if ^cmdptr
+                    slot = cmdptr.1 - '0'
+                else
+                    slot = 1
+                fin
+                printtxt(slot)
+		break
+            is 'Q'
+                quit
+            is 'E'
+            is 0
+                return
+            is 'N'
+                if chkchng
+                    inittxtbuf
+                    strcpy(@untitled, @txtfile)
+                fin
+		break
+            otherwise
+                bell
+                cout('?')
+                crout
+        wend
+        if perr
+            prstr(@errorstr)
+            call($FDDA, perr, 0, 0, 0)
+        else
+            prstr(@okstr)
+        fin
+        crout
+    loop
+end
+//
+// Init editor
+//
+if !(^machid & $80)
+    flags = uppercase | shiftlock
+    keyin = @keyin2
+else
+    keyin = @keyin2e
+fin
+inittxtbuf
+if argbuff
+    strcpy(@argbuff, @txtfile)
+    prstr(@txtfile)
+    numlines = 0
+    readtxt(@txtfile)
+fin
+curschr  = '+'
+flags = flags | insmode
+drawscrn(scrntop, scrnleft)
+curson
+editmode
+done
diff --git a/src/toolsrc/lex.c b/src/toolsrc/lex.c
index c6ab6e0..3878fa7 100755
--- a/src/toolsrc/lex.c
+++ b/src/toolsrc/lex.c
@@ -34,7 +34,7 @@ t_token keywords[] = {
     IMPORT_TOKEN,	    'I', 'M', 'P', 'O', 'R', 'T',
     RETURN_TOKEN,           'R', 'E', 'T', 'U', 'R', 'N',
     END_TOKEN,              'E', 'N', 'D',
-    EXIT_TOKEN,	            'E', 'X', 'I', 'T',
+//    EXIT_TOKEN,	            'E', 'X', 'I', 'T',
     DONE_TOKEN,	            'D', 'O', 'N', 'E',
     LOGIC_NOT_TOKEN,        'N', 'O', 'T',
     LOGIC_AND_TOKEN,        'A', 'N', 'D',