FCB:	EQU	5CH
RENAM:	EQU	23
OPEN:	EQU	15
CLOSE:	EQU	16
MAKE:	EQU	22
DELFIL:	EQU	19
RDBLK:	EQU	39
WRBLK:	EQU	40
SETDMA:	EQU	26
PRINTBUF:EQU	9
OUTCH:	EQU	2
INBUF:	EQU	10
RR:	EQU	33

PROMPT:	EQU	"*"

	ORG	100H
	PUT	100H

	MOV	SP,STACK
	MOV	DX,BREAK
	MOV	AX,2523H
	INT	33
	MOV	SI,BAK
	MOV	DI,FCB+9
	MOV	CX,3
	;File must not have .BAK extension
	REPE
	CMPB
	JZ	NOTBAK
	;Open input file
	MOV	AH,OPEN
	MOV	DX,FCB
	INT	33
	MOV	[HAVEOF],AL
	OR	AL,AL
	JZ	HAVFIL
	MOV	DX,NEWFIL
	MOV	AH,PRINTBUF
	INT	33
HAVFIL:
	MOV	SI,FCB
	MOV	DI,FCB2
	MOV	CX,9
	REP
	MOVB
	MOV	SI,BAK
	MOVW
	MOVB
	MOV	AH,DELFIL
	MOV	DX,FCB2
	INT	33
	MOV	AL,"$"
	MOV	DI,FCB2+9
	STOB
	STOB
	STOB
	MOV	AH,DELFIL
	INT	33
	;Create .$$$ file to make sure directory has room
	MOV	AH,MAKE
	INT	33
	OR	AL,AL
	JZ	SETUP
	MOV	DX,NODIR
	JMP	ERROR
NOTBAK:
	MOV	DX,NOBAK
	JMP	ERROR
TOOBIG:
	MOV	DX,TOBIG
	JMP	ERROR
NOTEOF:
	MOV	DX,NOEOF
	JMP	ERROR
SETUP:
	MOV	DX,START
	MOV	AH,SETDMA
	INT	33
	MOV	CX,[6]
	SUB	CX,80H
	MOV	[LAST],CX
	MOV	DI,START-1
	TEST	B,[HAVEOF],-1
	JNZ	SAVEND
	CALL	NUMRECS
	MOV	[FCB+RR],0
	MOV	DX,FCB
	MOV	AH,RDBLK
	INT	33
	CMP	AL,2
	JZ	TOOBIG
	JCXZ	SAVEND
	ROR	CX
	XCHG	CL,CH
	ADD	DI,CX		;Point to last byte
	DOWN
	MOV	AL,1AH
	REPNE
	SCAB
	JNZ	NOTEOF
	REPE
	SCAB
	INC	DI
SAVEND:
	CLD
	INC	DI
	MOV	B,[DI],1AH
	MOV	[ENDTXT],DI
	MOV	B,[COMBUF],128
	MOV	B,[EDITBUF],255
	MOV	[POINTER],START
	MOV	[CURRENT],1

COMMAND:
	MOV	SP,STACK
	MOV	AL,PROMPT
	CALL	OUT
	MOV	DX,COMBUF
	MOV	AH,INBUF
	INT	33
	MOV	AL,10
	CALL	OUT
	MOV	[PARAM2],0
	MOV	B,[QFLG],0
	MOV	SI,2+COMBUF
	CALL	GETNUM
	MOV	[PARAM1],DX
	CALL	SKIP1
	CMP	AL,","
	JNZ	CHKNXT
	INC	SI
CHKNXT:
	DEC	SI
	CALL	GETNUM
	MOV	[PARAM2],DX
	CALL	SKIP1
	CMP	AL,"?"
	JNZ	DISPATCH
	MOV	[QFLG],AL
	CALL	SKIP
DISPATCH:
	AND	AL,5FH
	MOV	DI,COMTAB
	MOV	CX,NUMCOM
	REPNE
	SCAB
	JNZ	COMERR
	MOV	BX,CX
	SHL	BX
	CALL	[BX+TABLE]
	JMP	COMMAND

SKIP:
	LODB
SKIP1:
	CMP	AL," "
	JZ	SKIP
	RET

COMERR:
	MOV	DX,BADCOM
	MOV	AH,PRINTBUF
	INT	33
	JP	COMMAND


GETNUM:
	CALL	SKIP
	CMP	AL,"."
	JZ	CURLIN
	CMP	AL,"#"
	JZ	MAXLIN
	MOV	DX,0
NUMLP:
	CMP	AL,"0"
	JB	RET
	CMP	AL,"9"
	JA	RET
	SUB	AL,"0"
	MOV	BX,DX
	SHL	DX
	SHL	DX
	ADD	DX,BX
	SHL	DX
	CBW
	ADD	DX,AX
	LODB
	JP	NUMLP

CURLIN:
	MOV	DX,[CURRENT]
	LODB
	RET
MAXLIN:
	MOV	DX,-1
	LODB
	RET


COMTAB:	DB	"SFDLIE",13

NUMCOM:	EQU	$-COMTAB

TABLE:
	DW	NOCOM	;No command--edit line
	DW	ENDED
	DW	INSERT
	DW	LIST
	DW	DELETE
	DW	COMERR
	DW	COMERR

FINDLIN:

; Inputs
;	BX = Line number to be located in buffer (0 means last line)
; Outputs:
;	DX = Actual line found
;	DI = Pointer to start of line DX
;	Zero set if BX = DX
; AL,CX destroyed. No other registers affected.

	MOV	DX,[CURRENT]
	MOV	DI,[POINTER]
	CMP	BX,DX
	JZ	RET
	JA	FINDIT
	MOV	DX,1
	MOV	DI,START
	CMP	BX,DX
	JZ	RET
FINDIT:
	MOV	CX,[ENDTXT]
	SUB	CX,DI
	MOV	AL,10
	OR	AL,AL		;Clear zero flag
FINLIN:
	JCXZ	RET
	REPNE
	SCAB
	INC	DX
	CMP	BX,DX
	JNZ	FINLIN
	RET


SHOWNUM:

; Inputs:
;	BX = Line number to be displayed
; Function:
;	Displays line number on terminal in 8-character
;	format, suppressing leading zeros.
; AX, CX, DX destroyed. No other registers affected.

	PUSH	BX
	MOV	AL," "
	CALL	OUT
	CALL	CONV10
	MOV	AL,":"
	CALL	OUT
	MOV	AL," "
	CALL	OUT
	POP	BX
	RET


CONV10:

;Inputs:
;	BX = Binary number to be displayed
; Function:
;	Ouputs binary number. Five digits with leading
;	zero suppression. Zero prints 5 blanks.

	XOR	AX,AX
	MOV	DL,AL
	MOV	CX,16
CONV:
	SHL	BX
	ADC	AL,AL
	DAA
	XCHG	AL,AH
	ADC	AL,AL
	DAA
	XCHG	AL,AH
	ADC	DL,DL
	LOOP	CONV
	MOV	BL,"0"-" "
	XCHG	AX,DX
	CALL	LDIG
	MOV	AL,DH
	CALL	DIGITS
	MOV	AL,DL
DIGITS:
	MOV	DH,AL
	SHR	AL
	SHR	AL
	SHR	AL
	SHR	AL
	CALL	LDIG
	MOV	AL,DH
LDIG:
	AND	AL,0FH
	JZ	ZERDIG
	MOV	BL,0
ZERDIG:
	ADD	AL,"0"
	SUB	AL,BL
	JMP	OUT


LIST:
	MOV	BX,[PARAM1]
	OR	BX,BX
	JNZ	CHKP2
	MOV	BX,[CURRENT]
	SUB	BX,10
	JA	CHKP2
	MOV	BX,1
CHKP2:
	CALL	FINDLIN
	JNZ	RET
	MOV	SI,DI
	MOV	DI,[PARAM2]
	INC	DI
	SUB	DI,BX
	JA	DISPLAY
	MOV	DI,21
	JP	DISPLAY


DISPONE:
	MOV	DI,1

DISPLAY:

; Inputs:
;	BX = Line number
;	SI = Pointer to text buffer
;	DI = No. of lines
; Function:
;	Ouputs specified no. of line to terminal, each
;	with leading line number.
; Outputs:
;	BX = Last line output.
; All registers destroyed.

	MOV	CX,[ENDTXT]
	SUB	CX,SI
	JZ	RET
	MOV	BP,[CURRENT]
DISPLN:
	PUSH	CX
	CALL	SHOWNUM
	POP	CX
OUTLN:
	LODB
	CALL	OUT
	CMP	AL,10
	LOOPNZ	OUTLN
	JCXZ	RET
	DEC	DI
	JZ	RET
	CMP	BX,BP
	LAHF
	INC	BX
	SAHF
	JZ	OUTLF
	CMP	BX,BP
	JNZ	DISPLN
OUTLF:
	MOV	AL,10
	CALL	OUT
	JP	DISPLN
RET:	RET


NOCOM:
	MOV	BX,[PARAM1]
	OR	BX,BX
	JNZ	HAVLIN
	MOV	BX,[CURRENT]
	INC	BX	;Default is current line plus one
HAVLIN:
	CALL	FINDLIN
	MOV	SI,DI
	MOV	[CURRENT],DX
	MOV	[POINTER],SI
	JNZ	RET
	CMP	SI,[ENDTXT]
	JZ	RET
	MOV	DI,2+EDITBUF
	MOV	CX,254
	MOV	DL,-1
LOADLP:
	LODB
	STOB
	INC	DL
	CMP	AL,13
	LOOPNZ	LOADLP
	MOV	[EDITBUF+1],DL
	MOV	[OLDLEN],DL
	MOV	SI,[POINTER]
	CALL	DISPONE
	CALL	SHOWNUM
	MOV	AH,INBUF	;Get input buffer
	MOV	DX,EDITBUF
	INT	33
	MOV	AL,10
	CALL	OUT
	MOV	CL,[EDITBUF+1]
	MOV	CH,0
	JCXZ	RET
	MOV	DL,[OLDLEN]
	MOV	DH,0
	MOV	SI,2+EDITBUF
	MOV	DI,[POINTER]

REPLACE:

; Inputs:
;	CX = Length of new text
;	DX = Length of original text
;	SI = Pointer to new text
;	DI = Pointer to old text in buffer
; Function:
;	New text replaces old text in buffer and buffer
;	size is adjusted. CX or DX may be zero.
; CX, SI, DI all destroyed. No other registers affected.

	CMP	CX,DX
	JZ	COPYIN
	PUSH	SI
	PUSH	DI
	PUSH	CX
	MOV	SI,DI
	ADD	SI,DX
	ADD	DI,CX
	MOV	AX,[ENDTXT]
	SUB	AX,DX
	ADD	AX,CX
	CMP	AX,[LAST]
	JAE	MEMERR
	XCHG	AX,[ENDTXT]
	MOV	CX,AX
	SUB	CX,SI
	CMP	SI,DI
	JA	DOMOV
	ADD	SI,CX
	ADD	DI,CX
	STD
DOMOV:
	INC	CX

	REP
	MOVB
	CLD
	POP	CX
	POP	DI
	POP	SI
COPYIN:
	REP
	MOVB
	RET

DELETE:
	MOV	BX,[PARAM1]
	OR	BX,BX
	JNZ	DELFIN1
	MOV	BX,[CURRENT]
DELFIN1:
	CALL	FINDLIN
	JNZ	RET
	MOV	[CURRENT],BX
	MOV	[POINTER],DI
	PUSH	DI
	MOV	BX,[PARAM2]
	OR	BX,BX
	JNZ	DELFIN2
	MOV	BX,DX
DELFIN2:
	INC	BX
	CALL	FINDLIN
	MOV	DX,DI
	POP	DI
	SUB	DX,DI
	XOR	CX,CX
	JP	REPLACE


GETTEXT:

; Inputs:
;	SI points into command line buffer
;	DI points to result buffer
; Function:
;	Moves [SI] to [DI] until ctrl-Z (1AH) or
;	RETURN (0DH) is found. Termination char not moved.
; Outputs:
;	AL = Termination character
;	CX = No of characters moved.
;	SI points one past termination character
;	DI points to next free location

	XOR	CX,CX

GETIT:
	LODB
	CMP	AL,1AH
	JZ	RET
	CMP	AL,0DH
	JZ	RET
	STOB
	INC	CX
	JP	GETIT

MEMERR:
	MOV	DX,MEMFUL
	MOV	AH,PRINTBUF
	INT	33
	JMP	COMMAND


INSERT:
	MOV	BX,[PARAM1]
	OR	BX,BX
	JNZ	INS
	MOV	BX,[CURRENT]
	INC	BX
INS:
	CALL	FINDLIN
	MOV	CX,[ENDTXT]		;Get End-of-text marker
	MOV	SI,CX
	SUB	CX,DI			;Calculate number of bytes to copy
	INC	CX
	MOV	DI,[LAST]
	DOWN
	REP
	MOVB
	XCHG	SI,DI
	UP
	INC	DI
	MOV	BP,SI
	MOV	BX,DX
INLP:
	CALL	SHOWNUM
	MOV	DX,EDITBUF
	MOV	AH,INBUF
	INT	33
	MOV	AL,10
	CALL	OUT
	MOV	SI,EDITBUF+2
	CMP	B,[SI],1AH
	JZ	ENDINS
	MOV	CL,[SI-1]
	MOV	CH,0
	MOV	DX,SI
	ADD	DX,CX
	INC	DX
	CMP	DX,BP	;Will it fit?
	JNC	MEMERR
	REP
	MOVB
	MOVB
	MOV	AL,10
	STOB
	INC	BX
	JP	INLP
ENDINS:
	MOV	[POINTER],DI
	MOV	[CURRENT],BX
	MOV	SI,BP
	INC	SI
	MOV	CX,[LAST]
	SUB	CX,BP
	REP
	MOVB
	DEC	DI
	MOV	[ENDTXT],DI
	RET

ENDED:
;Write text out to .$$$ file
	MOV	DI,[ENDTXT]
	MOV	CX,128
	MOV	AL,1AH
	REP
	STOB
	MOV	CX,[ENDTXT]
	CALL	NUMRECS
	INC	CX
	MOV	[FCB2+RR],0
	MOV	DX,FCB2
	MOV	AH,WRBLK
	INT	33
	OR	AL,AL
	JNZ	WRTERR
;Close .$$$ file
	MOV	AH,CLOSE
	INT	33
	MOV	SI,FCB
	LEA	DI,[SI+16]
	MOV	DX,SI
	MOV	CX,9
	REP
	MOVB
	MOV	SI,BAK
	MOVW
	MOVB
;Rename original file .BAK
	MOV	AH,RENAM
	INT	33
	MOV	SI,FCB
	MOV	DI,FCB2+16
	MOV	CX,6
	REP
	MOVW
;Rename .$$$ file to original name
	MOV	DX,FCB2
	INT	33
	JMP	0


WRTERR:
	MOV	DX,DSKFUL
ERROR:
	MOV	AH,PRINTBUF
	INT	33
	JMP	0

NUMRECS:
	SUB	CX,START
	AND	CL,80H
	ROL	CX
	XCHG	CL,CH
	RET

OUT:
	PUSH	DX
	XCHG	AX,DX
	MOV	AH,OUTCH
	INT	33
	XCHG	AX,DX
	POP	DX
	RET

BREAK:
	IRET


BAK:	DB	"BAK"
NOBAK:	DB	"Cannot edit .BAK file--rename file$"
NODIR:	DB	"No room in directory for file$"
TOBIG:	DB	"File too big to fit into memory$"
NOEOF:	DB	"No end-of-file mark found in file$"
DSKFUL:	DB	"Disk full--file write not completed$"
MEMFUL:	DB	13,10,"Memory full",13,10,"$"
BADCOM:	DB	"Entry error",13,10,"$"
NEWFIL:	DB	"New file",13,10,"$"
FCB2:	DS	36
PARAM1:	DS	2
PARAM2:	DS	2
QFLG:	DS	1
HAVEOF:	DS	1
OLDLEN:	DS	1
CURRENT:DS	2
POINTER:DS	2
LAST:	DS	2
ENDTXT:	DS	2
COMBUF:	DS	2+128
EDITBUF:DS	2+255
	DS	40
	ALIGN
STACK:
START:
