PUBLIC  FParse, $Repeat, FParse0, LastLineUpdate, NoModeline, LastLastLine
PUBLIC	Switchmenu
EXTRN   .InCH:Near, .Msg:Near, .Error0:Near, .CLRMsg:Near

;---------------------------------------------------------------------------
TITLE Command Parser

Program SEGMENT PARA    PUBLIC  'code'
	ASSUME  CS:Program, DS:Program, ES:Program, SS:Program

	INCLUDE	FDEF.DEF

COMMENT *

IN:  ?
OUT:
	AL
	0	=>	no character available
	1	=>	character [20..FF]
	2	=>	ctrl character passed in DL [0..1Fh]
	3	=>	C-X, following charcter in DL
	4	=>	M- , second character in DL
	5	=>	M-X, third character in DL
*

;----------------------- Symbols -----------------------
;----------======== VARIABLES =========---------

WorkMsg		db	'[Time]'
NumMsg		db	'*** Not Number ***'
ArgErr		db	'*** Argument Error ***'
ArgOFMsg	db	'*** Argument Too Big ***'
EscMsg		db	'ESC- '
XMsg		db	'ESC-X '
C_UMsg		db	'CTL-U '
C_XMsg		db	'CTL-X '
Temp		db	'0'
NoModeLine	db	InitLastLine
LastNodeName	dw	Offset Root
LastLastLine	dw	Offset Text0Line

$RepeatType STRUC   
	Arg	dw	?
	AAX	dw	?
	ADL	db	?
$RepeatType ENDS

$Repeat $RepeatType	<0,?,?>

;----------------------- Program ------------------------
%OUT FParse () : Argument, AX, DL;

FParse  PROC    Near

	mov	CS:$Repeat.Arg, 0	; argument default is 0
	call    .InCH		   ; get a character from keyboard
	jnz	FParse0		 ; is there a character ?
		xor	AX, AX	  ; no => return 0-0
		ret

; --- Character ?
Level2:
FParse0:cmp	AL, ' '		 ; check if ctl- character
	jb	FParse1		 ; this is a normal character
	mov	DL, AL		  ; pass back in 0- DL, AL
	mov	AH, 1
	ret




; --- CTRL-?
FParse1:cmp	AL, 18h		 ; check if it is a CTL-X
	je	C_X
	cmp	AL, ESC			; check if it is an ESC
	je	ESCAPE
	cmp	AL, 15h			; check if it is a CTL-U
	jne	FParse2

	jmp	c_u

FParse2:
	cmp	AL, NUL
	jne	FP21
	jmp	RemapNUL		; for the stupid IBM PC definition
FP21:	mov	DL, AL			; we have a "normal" ctl-char
	mov	AH, 2			; pass back in 2- DL, AL
	ret




; --- CTRL-X ?

C_X:    call    .CLRMsg			; put a CTL-X Msg to screen
	mov	SI, Offset C_XMsg
	mov	CX, 6
	call    .Msg

C_X1:   call    .InCH			; wait to get a character
	jz	C_X1

	cmp	AL, CTL_G		; abort on C-G
	jne	C_X2
		call	.ClrMsg
		xor	AX, AX
		xor	DL, DL
		ret

C_X2:   push    AX			; clear screen, and pass back 3- DL,AL
	call    .CLRMsg
	pop	AX
	mov	AH, 3
	mov	DL, AL
	ret



; --- ESC ?
ESCAPE: call    .CLRMsg			; put ESC- to screen
	mov	SI, Offset EscMsg
	mov	CX, 5
	call    .Msg

ESCAPE1:call    .InCH			; wait until character <> ESC
	jz	ESCAPE1
	cmp	AL, ESC
	jz	ESCAPE1

	cmp	AL, CTL_G		; command cancelled with c-g ?
	jne	ESCAPE2

	call    .CLRMsg			; clear the screen
	xor	DL, DL
	xor	AX, AX
	ret

ESCAPE2:cmp	AL, 'X'			; is this esc-x ?
	je	Extended
	cmp	AL, 'x'
	je	Extended

	mov	DL, AL			; no, so check whether it is a number

	cmp	DL, '0'			; if it is not, jump to escape3
	jb	ESCAPE3
	cmp	DL, '9'
	ja	ESCAPE3

	 cmp	CS:$Repeat.Arg, 0	; if our argument not 0, we are in
	 jne	ESCArgErr		; recursive call = not allowed

ESCnumId:call    $GetArg		; we are not recursive, so get
					; the argument into $Arg, and one
					; argument into AL
		call    Level2		; call itself recursively to get
					; a second function. Arg is disabled.
		cmp	AX, 0FFFFh	; check whether the return signals
		je	ESCArgDiscErr	; an error through Arg ( recursive )
		cmp	CS:$Repeat.Arg, 0 ; check whether our Argument is 0
		je	ESCArgDiscErr	; which is also a 0

		cmp	AL, CTL_G	; check whether we have a CTL-G
		je	ESCArgDiscErr	; which would imply an error, too
		mov	CS:$Repeat.AAX, AX ; save our other values (for what?)
		mov	CS:$Repeat.ADL, DL

		call    .CLRMsg		; clear the screen
		mov	SI, Offset WorkMsg ; and tell us that we need time
		mov	CX, 6		; to complete a task
		call    .Msg
		mov	AX, CS:$Repeat.AAX ; return the values of AX, DL
		mov	DL, CS:$Repeat.ADL
		mov	AL, CS:$Repeat.ADL
		ret

	ESCArgDiscErr:
		mov	SI, Offset ArgErr ; display an error and return to
		mov	CX, 22		; the main calling routine
		call    .Error0
		xor	AX, AX
		ret

	ESCArgErr:
		mov	SI, Offset ArgErr ; display an error, and return from
		mov	CX, 22		; recursive call.
		call    .Msg
		call    .Error0
		mov	AX, 0FFFFh
		ret

ESCAPE3:push    DX			; this is just a normal ESC-?
	call    .CLRMsg			; so clear the screen and return the
	pop	DX			; character in 4- AL, DL
	mov	AL, DL
	mov	AH, 4
	ret

Extended:
	call    .CLRMsg		 	; this is an esc-x ?, so put an ESC-X
	mov	SI, Offset XMsg		; message to the screen
	mov	CX, 6
	call    .Msg

Extended1:
	call    .InCH			; get a character
	jz	Extended1
	cmp	AL, 7			; abort check
	jne	Extended2		; cancelled
	call	.CLRMsg
	xor	DL, DL
	sub	AX, AX
	ret
Extended2:
	push    AX			; pass back 5 - AL,DL
	call    .CLRMsg
	pop	AX
	mov	DL, AL
	mov	AH, 5
	ret

;-------------------------------------------------------------------------
C_U:    call    .CLRMsg			; use a CTL-U Argument
	mov	CX, 6			; first put a CTL-U to the screen
	mov	SI, Offset C_UMsg
	call    .Msg

c_u0:   call    .Inch			; get another character
	jz	c_u0

	cmp	AL, '0'			; if it is not a number, then error
	jb	c_uErr
	cmp	AL, '9'
	ja	c_uErr

	mov	DL, AL			; load DL with the first number
	cmp	CS:$Repeat.Arg, 0	; check whether we are in a recursive
	jne	c_u1			; call, and error if so

	jmp	ESCnumId		; otherwise, let esc-arg take over
c_u1:   jmp	ESCArgErr		; we had a recursive mistake

c_uErr: mov	SI, Offset NumMsg	; we had a CTL-U other than number
	mov	CX, 18			; which is an error
	call    .Error0
	sub	AX, AX			; and return nothing
	sub	DL, DL
	ret

FParse  ENDP

;-------------------------------------------------------------------------
%OUT $GetArg (DL,AL= First Number ) : CS:RepeatArg=Total Number

$Getarg PROC    Near
	mov	AX, CS:$Repeat.Arg
					; multiply by 10
	cmp	AX, 6000
	ja	ArgOF		   ; Argument Overflow
	add	AX, AX		  ; multiply old argument by 10
	mov	CS:$Repeat.Arg, AX
	add	AX, AX
	add	AX, AX
	add	CS:$Repeat.Arg, AX	; add new number
	xor	AH, AH
	mov	AL, DL
	sub	AL, '0'		 ; ASCII -> Word
	add	CS:$Repeat.Arg, AX	; and add new number to it

	add	AL, '0'		 ; and display it on screen, too
	mov	Byte Ptr CS:Temp, AL
	mov	SI, Offset Temp
	mov	CX, 1
	call    .Msg

$GAL:   call    .Inch		   ; get a number / command-start
	jz	$GAL

	cmp	AL, '0'		 ; return if we have our first non
	jb	$GAEx		   ; numerical argument
	cmp	AL, '9'
	ja	$GAEx
	mov	DL, AL		  ; input was number -> do it again
	jmp	$GetArg		 ; multiply by 10 etc.

$GaEx:  ret				; command was input

;-------------------------------------------------------------------------
%OUT ArgOF
ArgOF:  mov	SI, Offset ArgOFMsg
	mov	CX, 24
	call    .Msg
	call    .Error0
	mov	CS:$Repeat.Arg, 0
	pop	AX		; discard jump back "call $GetArg"
	xor	AX, AX
	ret

$GetArg ENDP

;---------------------------------------------------------------------------
; RemapNUL:
;
;	FN: remaps the NUL x character, since the stupid PC can't deal with
;	    it. Also defines the function keys
;	IN: -
;	OUT:Artificial Combination of AL/DL - AH
;
RemapNUL	PROC	NEAR
	call	.InCH			; there definitely is another one
	mov	BL, AL
	sub	BH, BH
	add	BX, BX
	mov	AX, CS:NULTable[BX]
	cmp	AH, MenuEntry/256
	je	SwitchMenu
	mov	DL, AL
	ret
RemapNUL	ENDP

;---------------------------------------------------------------------------
; Switchmenu:
;
;	FN:	switches to a new menu
;
;	IN:	AL: new menu number
;	OUT:	Updated Table
;		Updated Modeline
;
SwitchMenu	PROC	NEAR

	mov	AH, 64		; we want 60 bytes for table and 4 for textptr
	mul	AH		; -> AX holds entry to table
	mov	SI, AX
	add	SI, Offset Newtable
	mov	DI, Offset FN1
	mov	CX, 10

UpdateLoop1:
	mov	AX, CS:[SI]
	add	SI, 2
	mov	CS:[DI], AX
	add	DI, 2
	loop	UpdateLoop1

	mov	CX, 20		; dump PC has function keys not in contiguous
	mov	DI, Offset FN11	; area, so I have to reinitialize and continue
UpdateLoop2:
	mov	AX, CS:[SI]
	add	SI, 2
	mov	CS:[DI], AX
	add	DI, 2
	loop	UpdateLoop2
	
	mov	AX, CS:[SI+2]
	mov	CS:LastNodename, AX
	mov	SI, CS:[SI]		; this is the new text pointer
	call	LastLineUpdate
	sub	AX, AX
	ret

SwitchMenu	ENDP

;---------------------------------------------------------------------------
	number	db	'0'
LastLineUpdate	PROC	NEAR

	mov	CS:LastLastLine, SI
	push	ES
	mov	AX, ScreenSegment
	mov	ES, AX
	mov	DI, Offset LastLineStart+320

	cmp	CS:NoModeLine, TRUE
	je	LLEndupdate

	mov	AL, '1'
	mov	AH, lowintensity
	stosw
	mov	cs:number, AL

LL0:	mov	AL, CS:[SI]
	inc	SI
	cmp	AL, '$'
	je	LLEndUpdate
	cmp	AL, NUL
	jne	LL1

	mov	AL, ' '			; put up space between key descriptors
	mov	AH, nocolor
	stosw

	inc	cs:number
	mov	AL, cs:number
	mov	AH, lowintensity

	jmp	LL2
LL1:	mov	AH, Inverse
LL2:	stosw
	jmp	LL0
LLEndUpdate:
	mov	AX, ' '+nocolor*256
LLEUP1:	cmp	DI, Offset LastLineStart+320+158-20
	jae	LLEndEnd
	stosw
	jmp	LLEUP1
LLEndEnd:
	call	NodeNameUpdate
	pop	ES
	ret
LastLineUpdate	ENDP

;---------------------------------------------------------------------------
NodeNameUpdate	PROC	NEAR
	mov	SI, CS:LastNodename
	mov	CX, 11

NNL:	mov	AL, CS:[SI]
	inc	SI
	mov	AH, nocolor
	stosw
	cmp	DI, Offset LastLineStart+320+158
	ja	NNLR
	loop	NNL
nnlr:	ret
NodeNameUpdate	ENDP

T2	equ	2*256		; CTL-
T3	equ	3*256		; CTL-X -
T4	equ	4*256		; ESC-
T5	equ	5*256		; ESC-X -

T7	equ	7*256
MenuEntry	equ	T7

NulTable dw	0	; 0
dw	0		; 1
dw	0		; 2
dw	T2		; 3 ^@
dw	0		; 4
dw	0		; 5
dw	0		; 6
dw	0		; 7
dw	0		; 8
dw	0		; 9
dw	0		; 10
dw	0		; 11
dw	0		; 12
dw	0		; 13
dw	0		; 14
dw	T2+TAB		; 15 = Shift TAB
dw	0		; 16
dw	0		; 17
dw	0		; 18
dw	0		; 19
dw	0		; 20
dw	0		; 21
dw	0		; 22
dw	0		; 23
dw	0		; 24
dw	0		; 25
dw	0		; 26
dw	0		; 27
dw	0		; 28
dw	0		; 29
dw	0		; 30
dw	0		; 31
dw	0		; 32
dw	0		; 33
dw	0		; 34
dw	0		; 35
dw	0		; 36
dw	0		; 37
dw	0		; 38
dw	0		; 39
dw	0		; 40
dw	0		; 41
dw	0		; 42
dw	0		; 43
dw	T4+'Z'		; 44 = ALT-Z
dw	0		; 45
dw	0		; 46
dw	0		; 47
dw	0		; 48
dw	0		; 49
dw	0		; 50
dw	0		; 51
dw	0		; 52
dw	0		; 53
dw	0		; 54
dw	0		; 55
dw	0		; 56
dw	0		; 57
dw	0		; 
FN1 dw	T7+1		; 
dw	T7+2		; 60
dw	T7+3		; 
dw	T7+4		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 70
dw	T4+'<'		; 71 = Home
dw	T2+16		; 72 = Previous = Arrow
dw	T4+'V'		; 73 = PageUp
dw	0		; 
dw	T2+2		; 75 = Arrow <-
dw	0		; 
dw	T2+6		; 77 = Arrow ->
dw	0		; 
dw	T4+'>'		; 79 = End
dw	T2+14		; 80 = Next = Arrow
dw	T2+22		; 81 = PageDown
dw	0		; 
dw	0		; 
FN11 dw	T7+1		; 84 = F1
dw	T7+2		; 
dw	T7+3		; 
dw	T7+4		; 
dw	0		; 
dw	0		; 
dw	0		; 90
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 100
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 110
dw	0		; 
dw	0		; 
dw	0		; 
dw	T2+1Fh		; 114 = PrtSc = HELP
dw	T4+'B'		; 115 = CTRL- <- = Word Backward
dw	T4+'F'		; 116 = CTRL- -> = Word Forward
dw	0		; 
dw	T2+26		; 118 = CTRL-PGUP = ScrollUp
dw	0		; 
dw	0		; 120
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 
dw	0		; 130
dw	0		; 
dw	T4+'Z'		; 132 = CTRL - PageDown
dw	0		; 
dw	0		; 
dw	0		; 

;---------------------------------------------------------------------------
NewTable dw	Menuentry+1		; MAIN manu
dw	Menuentry+2
dw	Menuentry+3
dw	Menuentry+4
dw	5 dup (0)
dw	T5+'M'
dw	20 dup (0)
	dw	Offset Text0Line
	dw	Offset Root

dw	Menuentry+0			; EDIT Menu
dw	Menuentry+5			;	char
dw	Menuentry+6			;	word
dw	Menuentry+7			;	para
dw	Menuentry+8			;	global
dw	Menuentry+9			;	region
dw	24 dup (0)
	dw	Offset Text1Line
	dw	Offset Ch1

dw	Menuentry+0			; SEARCH menu
dw	T2+19				; ^S
dw	T2+18				; ^R
dw	T5+'S'
dw	T5+'Q'
dw	25 dup (0)
	dw	Offset Text2Line
	dw	Offset Ch2

dw	Menuentry+0			; FILE menu
dw	T3+19				; ^X ^S
dw	T3+23				; ^X ^W
dw	T3+22				; ^X ^V
dw	T3+'B'
dw	T3+'O'
dw	24 dup (0)
	dw	Offset Text3Line
	dw	Offset Ch3

dw	Menuentry+0			; Others
dw	T2+17
dw	T2+15
dw	T4+'Q'
dw	T3+26
dw	25 dup (0)
	dw	Offset Text4Line
	dw	Offset Ch4

dw	Menuentry+1			; EDIT-CHAR
dw	T2+6
dw	T2+2
dw	T2+4
dw	T2+8
dw	T2+20
dw	4 dup (0)
dw	Menuentry+1
dw	T2+14
dw	T2+16
dw	T2+11
dw	T2+7
dw	T2+7
dw	14 dup (0)
	dw	Offset Text5Line
	dw	Offset Ch5

dw	Menuentry+1			; word /sentence
dw	T4+'F'
dw	T4+'B'
dw	T4+'D'
dw	T4+8
dw	T4+'T'
dw	24 dup (0)				; word <> sentence
	dw	Offset Text5Line		; word is similar to char
	dw	Offset Ch6

dw	Menuentry+1
dw	29 dup (0)
	dw	Offset Text5Line		; paragraph is similar to char
	dw	Offset Ch7

dw	Menuentry+1				; so is screen file
dw	T2+22
dw	T3+'V'
dw	7 dup (0)
dw	Menuentry+1
dw	T4+'<'
dw	T4+'>'
dw	17 dup (0)
	dw	Offset Text5Line
	dw	Offset Ch8

dw	Menuentry+1				; REGION
dw	T2+0
dw	T3+24
dw	T2+23
dw	26 dup (0)
	dw	Offset Text9Line
	dw	Offset Ch9

dw	30 dup (0)
dw	Offset Text10Line
	dw	Offset Ch10
Text0Line	db	'EDIT  ', NUL
		db	'SEARCH', NUL
		db	'FILE  ', NUL
		db	'OTHERS', NUL
		db	'     ', NUL
		db	'     ', NUL
		db	'     ', NUL
		db	'     ', NUL
		db	'     ', NUL
		db	'MODELN', STR
Text1Line	db	' QUIT  ', NUL
		db	'CHAR/LN', NUL
		db	'WRD/SNT', NUL
		db	'PAR/PAG', NUL
		db	'SCR/FIL', NUL
		db	'REGION ', STR
Text2Line	db	'  QUIT  ', NUL
		db	'->search', NUL
		db	'<-search', NUL
		db	'replace ', NUL
		db	'?replace?', STR
Text3Line	db	' QUIT ', NUL
		db	' save ', NUL
		db	'write ', NUL
		db	'visit ', NUL
		db	'buffer', NUL
		db	'window', STR
Text4Line	db	' QUIT ', NUL
		db	'lit-ins', NUL
		db	'open-ln', NUL
		db	' fill ', NUL
		db	' ***QUIT TO DOS*** ', STR
Text5Line	db	' QUIT ', NUL
		db	'advance', NUL
		db	'retreat', NUL
		db	'->erase', NUL
		db	'<-erase', NUL
		db	' xchg  ', STR
Text9Line	db	'  QUIT  ', NUL
		db	'set mark', NUL
		db	'mark<>cur', NUL
		db	'!kill reg!', STR
Text10Line	db	'MAIN$'

Root	db	'===TOP===  '
Ch1	db	'/EDIT      '
Ch2	db	'/SEARCH    '
Ch3	db	'/FILE      '
Ch4	db	'/OTHER     '
Ch5	db	'/ED/CHR-LIN'
Ch6	db	'/ED/WRD-SNT'
Ch7	db	'/ED/PAR-PAG'
Ch8	db	'/ED/SCR-GLO'
CH9	db	'/ED/REGION '
CH10	db	' ILLEGAL   '

	PROGRAM ENDS
END
