;/*
; *                      Microsoft Confidential
; *                      Copyright (C) Microsoft Corporation 1987 - 1991
; *                      All Rights Reserved.
; */
PAGE	,132
TITLE	PARSE CODE AND CONTROL BLOCKS FOR KEYB.COM

;****************** START OF SPECIFICATIONS **************************
;
;  MODULE NAME: PARSER.ASM
;
;  DESCRIPTIVE NAME: PARSES THE COMMAND LINE PARAMETERS FOR KEYB.COM
;
;  FUNCTION: THE COMMAND LINE IN THE PSP IS PARSED FOR PARAMETERS.
;
;  ENTRY POINT: PARSE_PARAMETERS
;
;  INPUT: BP POINTS TO PARAMETER LIST
;	  DS & ES POINT TO PSP
;
;  AT EXIT:
;     PARAMETER LIST FILLED IN AS REQUIRED.
;
;  INTERNAL REFERENCES:
;
;     ROUTINES: SYSPARSE - PARSING CODE
;
;     DATA AREAS: PARMS - PARSE CONTROL BLOCK FOR SYSPARSE
;
;  EXTERNAL REFERENCES:
;
;     ROUTINES: N/A
;
;     DATA AREAS: PARAMETER LIST BLOCK TO BE FILLED.
;
;  NOTES:
;
;  REVISION HISTORY:
;	 A000 - DOS Version 3.40
;  3/24/88 AN003 - P3906 PARSER changes to return "bogus" parameter on the
;	       "Parameter value not allowed " message - CNS
;  5/12/88 AN004 - P4867 /ID:NON-Numeric hangs the sytem as a 1st positional
;
;
;                                                  
; MS-DOS 5.00 - NLS Support - KEYB Command
;
;
;****************** END OF SPECIFICATIONS ****************************

INCLUDE KEYBDCL.INC

ID_VALID	EQU	0
ID_INVALID	EQU	1
NO_ID		EQU	2

LANGUAGE_VALID	EQU	0
LANGUAGE_INVALID EQU	1
NO_LANGUAGE	EQU	2

NO_IDLANG	EQU	3

CODE_PAGE_VALID EQU	0
CODE_PAGE_INVALID EQU	1
NO_CODE_PAGE	EQU	2
VALID_SYNTAX	EQU	0
INVALID_SYNTAX	EQU	1

COMMAND_LINE_START EQU	81H
RC_EOL		EQU	-1
RC_NO_ERROR	EQU	0
RC_OP_MISSING	EQU	2
RC_NOT_IN_SW	EQU	3

;***CNS P4867 1st CHECK for /ID:ALPHA

RC_SW_FIRST	EQU	9

;***CNS P4867 1st CHECK for /ID:ALPHA

ERROR_COND	EQU	-1
NUMBER		EQU	1
STRING		EQU	3
FILE_SPEC	EQU	5
MAX_ID		EQU	999
LANG_LENGTH	EQU	2

INVALID_SWITCH	EQU	3
TOO_MANY	EQU	1
INVALID_PARAM	EQU	10
VALUE_DISALLOW	EQU	8


	PUBLIC	PARSE_PARAMETERS ; near procedure for parsing command line
	PUBLIC	CUR_PTR 	; near procedure for parsing command line
	PUBLIC	OLD_PTR 	; near procedure for parsing command line
	PUBLIC	ERR_PART	; near procedure for parsing command line

	EXTRN	BAD_ID:BYTE	; WGR to match old code
	EXTRN	FOURTH_PARM:BYTE ; WGR to match old code
	EXTRN	ONE_PARMID:BYTE	; WGR to match old code
	EXTRN	FTH_PARMID:BYTE	; WGR to match old code
	EXTRN	ALPHA:BYTE	; WGR to match old code

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Set assemble switches for parse code that is not required!!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DateSW		EQU	0
TimeSW		EQU	0
CmpxSW		EQU	0
DrvSW		EQU	0
QusSW		EQU	0
KeySW		EQU	0
Val1SW		EQU	0
Val2SW		EQU	0
Val3SW		EQU	0


CODE	SEGMENT PUBLIC 'CODE' BYTE
	ASSUME	CS:CODE,DS:CODE

	.XLIST
	INCLUDE	PARSE.ASM	; Parsing code
	.LIST


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PARM control blocks for KEYB
; Parsing command line as follows:
;
; KEYB [lang],[cp],[[d:][path]KEYBOARD.SYS][/ID:id][/e][/?]
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PARMS	LABEL	WORD
	DW	PARMSX
	DB	0		; no extra delimeters or EOLs.

PARMSX	LABEL	BYTE
	DB	0,3		; min,max positional operands
	DW	LANG		; pointer to control block
	DW	CP		; pointer to control block
	DW	FILE_NAME	; pointer to control block
	DB	3		; 3 switches
	DW	ID_VALUE	; pointer to control block
	dw	help_value	; pointer to control block
	dw	ext_value	; pointer to control block
	DB	0		; no keywords

LANG	LABEL	WORD
	DW	0A001H		; sstring or numeric value (optional)
	DW	0002H		; cap result by char table (sstring)
	DW	RESULT_BUF	; result
	DW	NOVALS		; no value checking done
	DB	0		; no keyword/switch synonyms

CP	LABEL	WORD
	DW	8001H		; numeric
	DW	0		; no functions
	DW	RESULT_BUF	; result
	DW	NOVALS		; no value checking done
	DB	0		; no keyword/switch synonyms

FILE_NAME LABEL WORD
	DW	0201H		; file spec
	DW	0001H		; cap by file table
	DW	RESULT_BUF	; result
	DW	NOVALS		; no value checking done
	DB	0		; no keyword/switch synonyms

ID_VALUE LABEL	WORD
	DW	8010H		; numeric
	DW	0		; no functions
	DW	RESULT_BUF	; result
	DW	NOVALS		; no value checking done
	DB	1		; 1 switch synonym
id_name:
	DB	"/ID",0 	; ID switch

help_value label	word
	dw	0		; no values
	dw	0		; no functions
	dw	RESULT_BUF	; result
	dw	novals		; no value checking done
	db	1		; 1 switch synonym
help_name:
	db	"/?",0		; /? switch

ext_value label	word
	dw	0		; no values
	dw	0		; no functions
	dw	result_buf	; result
	dw	novals		; no value checking done
	db	1		; 1 switch synonym
ext_name:
	db	"/E",0		; /e switch


NOVALS	LABEL	BYTE
	DB	0		; no value checking done

RESULT_BUF	LABEL BYTE
RESULT_TYPE	DB	0	; type returned (number, string, etc.)
		DB	?	; matched item tag (if applicable)
RESULT_SYN_PTR	DW	?	; synonym ptr (if applicable)
RESULT_VAL	DD	?	; value

LOOP_COUNT	DB	0	; keeps track of parameter position

;***CNS
CUR_PTR        DW	0	; keeps track of parameter position
OLD_PTR        DW	0	; keeps track of parameter position
ERR_PART       DW	0	; keeps track of parameter position
;***CNS
				;..and reports an error condition

	public	pswitches
pswitches	db	0	; bit 0, /?, bit 1 /e

TEMP_FILE_NAME DB	128 DUP(0) ; place for file name

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; PROCEDURE_NAME: PARSE_PARAMETERS
;
; FUNCTION:
; THIS PROCEDURE PARSES THE COMMAND LINE PARAMETERS IN THE PSP FOR
; KEYB.COM. THE PARAMETER LIST BLOCK IS FILLED IN ACCORDINGLY.
;
; AT ENTRY: AS ABOVE.
;
; AT EXIT:
;    AS ABOVE.
;
; AUTHOR: WGR
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PARSE_PARAMETERS       PROC	NEAR

	XOR	AX,AX				; setup default parameters.
	MOV	[BP].RET_CODE_1,NO_IDLANG
	MOV	[BP].RET_CODE_2,NO_CODE_PAGE
	MOV	[BP].RET_CODE_3,VALID_SYNTAX
	MOV	[BP].RET_CODE_4,NO_ID
	MOV	[BP].PATH_LENGTH,AX
	LEA	DI,PARMS			; setup parse blocks
	MOV	SI,COMMAND_LINE_START

	call	save_curptr

	XOR	CX,CX
	XOR	DX,DX
	CALL	SYSPARSE

kbs_10:
	cmp	ax,RC_EOL		; while not end of line and...
	jnz	kbs_11
	jmp	kbs_12
kbs_11:
	cmp	LOOP_COUNT,ERROR_COND	; parameters valid, do...
	jnz	kbs_13
	jmp	kbs_12

kbs_13:
	cmp	ax,RC_NOT_IN_SW		; invalid switch?
	jz	kbs_08
	cmp	ax,RC_SW_FIRST
	jnz	kbs_09

kbs_08:
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	; set invalid syntax flag.
	MOV	LOOP_COUNT,ERROR_COND		; set error flag to exit parse.

;***CNS
	MOV	ERR_PART,INVALID_SWITCH
	call	save_curptr
;***CNS

	jmp	kbs_10

kbs_09:

	cmp	RESULT_SYN_PTR,offset id_name	; was /id:xxx switch found?
	jnz	not_id_switch


	MOV	AX,WORD PTR RESULT_VAL+2 ; is it valid?
	OR	AX,AX
	jnz	kbs_01

	mov	ax,word ptr RESULT_VAL
	cmp	ax,MAX_ID
	jna	kbs_02

kbs_01:

	MOV	[BP].RET_CODE_1,ID_INVALID	; no...invalid id.
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	; syntax error.
	MOV	LOOP_COUNT,ERROR_COND		; set flag to exit parse
	mov	bad_id,1

	MOV	[ERR_PART],VALUE_DISALLOW	; SET ERROR TYPE FOR DISPLAY
	call	save_curptr

	jmp	short kbs_03

kbs_02:
	MOV	[BP].RET_CODE_4,ID_VALID ; yes...set return code 4.
	MOV	[BP].ID_PARM,AX
	mov	fourth_parm,1
	mov	fth_parmid,1

	jmp	short kbs_03


not_id_switch:
	cmp	RESULT_SYN_PTR,offset help_name	; was /? switch found?
	jnz	not_help_switch

	or	pswitches,1			; set flag for /?
	jmp	short kbs_03

not_help_switch:
	cmp	RESULT_SYN_PTR,offset ext_name
	jnz	kbs_07

	or	pswitches,2			; set flag for /e
	jmp	short kbs_03


kbs_07:
	INC	LOOP_COUNT		; positional encountered...
	cmp	LOOP_COUNT,1		; check for language
	jnz	kbs_04

	CALL	PROCESS_1ST_PARM

	call	save_curptr

	jmp	short kbs_03

kbs_04:
	cmp	LOOP_COUNT,2		; check for code page
	jnz	kbs_05

	CALL	 PROCESS_2ND_PARM

	call	save_curptr

	jmp	short kbs_03

kbs_05:
	cmp	LOOP_COUNT,3		; check for file name
	jnz	kbs_06

	CALL	PROCESS_3RD_PARM

	call	save_curptr

	jmp	short kbs_03

;	all other cases

kbs_06:
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	; too many parms

	call	save_curptr

	MOV	ERR_PART,TOO_MANY
	MOV	LOOP_COUNT,ERROR_COND	; set error flag to exit parse.
kbs_03:
	MOV	RESULT_TYPE,0		; reset result block.
	CALL	SYSPARSE		; parse next parameter.

	jmp	kbs_10

kbs_12:
	cmp	[bp].RET_CODE_4,ID_VALID
	jnz	kbs_14				; ensure that if switch was
	cmp	[bp].RET_CODE_1,LANGUAGE_VALID	; used, it was valid keyword
	jz	kbs_14

	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	 ; code was used..

;***CNS
	call	save_curptr
	MOV	ERR_PART,VALUE_DISALLOW
;***CNS

kbs_14:
	RET

PARSE_PARAMETERS       ENDP

save_curptr	proc	near

	PUSH	AX			;Save environment
	MOV	AX,CUR_PTR		;Set advancing ptr to end of argument
	MOV	OLD_PTR,AX		;after saving the beginning the string
	MOV	CUR_PTR,SI
	POP	AX			;Restore the environment
	ret

save_curptr	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; PROCEDURE_NAME: PROCESS_1ST_PARM
;
; FUNCTION:
; THIS PROCEDURE PROCESSES THE FIRST POSITIONAL PARAMETER. THIS SHOULD
; BE THE LANGUAGE ID OR THE KEYBOARD ID.
;
; AT ENTRY: PARSE RESULT BLOCK CONTAINS VALUES IF AX HAS NO ERROR.
;
; AT EXIT:
;    PARAMETER CONTROL BLOCK UPDATED FOR LANGUAGE ID.
;
; AUTHOR: WGR
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PROCESS_1ST_PARM       PROC    NEAR

	cmp	ax,RC_NO_ERROR		; error on parse?
	jng	kbs_23

	MOV	[BP].RET_CODE_1,LANGUAGE_INVALID ; yes...set invalid language
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	 ; and syntax error..
	MOV	LOOP_COUNT,ERROR_COND		 ; set flag to exit parse.
	MOV	ERR_PART,AX

	jmp	kbs_18

kbs_23:
	cmp	RESULT_TYPE,NUMBER	; was this a number (id?)
	jnz	kbs_24

	MOV	AX,WORD PTR RESULT_VAL+2 ; yes...check to see if
	OR	AX,AX			; within range.
	jnz	kbs_19

	MOV	AX,WORD PTR RESULT_VAL
	cmp	ax,max_id
	jna	kbs_17

kbs_19:
	MOV	[BP].RET_CODE_1,ID_INVALID	; no...invalid id.
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	; syntax error.
	MOV	LOOP_COUNT,ERROR_COND		; set flag to exit parse
	mov	bad_id,1

	jmp	short kbs_18

kbs_17:
	MOV	[BP].RET_CODE_1,ID_VALID	; valid id...set
	MOV	[BP].RET_CODE_4,ID_VALID	; valid id...set
	MOV	[BP].ID_PARM,AX			; and value moved into block
	MOV	LOOP_COUNT,4			; there should be no more parms
	mov	one_parmid,1

	jmp	short kbs_18

kbs_24:
	cmp	RESULT_TYPE,STRING	; must be a string then???
	jnz	kbs_26

	PUSH	SI
	PUSH	DI
	PUSH	CX
	PUSH	DS
	LDS	SI,RESULT_VAL		; get ptr to string
	MOV	DI,BP
	ADD	DI,LANGUAGE_PARM	; point to block for copy.
	MOV	CX,LANG_LENGTH		; maximum length = 2
	LODSB				; load AL with 1st char..

kbs_16:
	jcxz	kbs_15			; do twice, unless only 1 char
	or	al,al
	jz	kbs_15

	STOSB				; store
	DEC	CX			; dec count
	LODSB				; load

	jmp	kbs_16

kbs_15:

	or	cx,cx			; if there was less than 2 or..
	jnz	kbs_20
	or	al,al			;  greater than 2 chars, then..
	jz	kbs_21

kbs_20:
	MOV	[BP].RET_CODE_1,LANGUAGE_INVALID ; invalid.
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	; syntax error
	MOV	ERR_PART,INVALID_PARAM
	MOV	LOOP_COUNT,ERROR_COND		; set flag to exit parse.

	jmp	short kbs_22

kbs_21:
	MOV	[BP].RET_CODE_1,LANGUAGE_VALID	; valid language has been copied
	MOV	ALPHA,1				; language found

kbs_22:
	POP	DS
	POP	CX
	POP	DI
	POP	SI
	jmp	short kbs_18

;	omitted parameter...

kbs_26:
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	; invalid since further parameters.
kbs_18:
	RET

PROCESS_1ST_PARM       ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; PROCEDURE_NAME: PROCESS_2ND_PARM
;
; FUNCTION:
; THIS PROCEDURE PROCESSES THE 2ND POSITIONAL PARAMETER. THIS SHOULD
; BE THE CODE PAGE, IF REQUESTED.
;
; AT ENTRY: PARSE RESULT BLOCK CONTAINS VALUES IF AX HAS NO ERROR.
;
; AT EXIT:
;    PARAMETER CONTROL BLOCK UPDATED FOR CODE PAGE.
;
; AUTHOR: WGR
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PROCESS_2ND_PARM       PROC    NEAR

	cmp	ax,RC_NO_ERROR			; if parse error
	jle	kbs_32

	MOV	[BP].RET_CODE_2,CODE_PAGE_INVALID ; mark invalid..
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	; syntax error
	MOV	LOOP_COUNT,ERROR_COND		; set flag to exit parse
	MOV	ERR_PART,AX

	jmp	short kbs_31

kbs_32:

	cmp	RESULT_TYPE,NUMBER		; was parameter specified?
	jnz	kbs_30

	MOV	AX,WORD PTR RESULT_VAL+2	; yes..if code page not..
	OR	AX,AX

	jnz	kbs_27

	MOV	AX,WORD PTR RESULT_VAL		; valid..then

	cmp	ax,MAX_ID
	jna	kbs_28

kbs_27:
	MOV	[BP].RET_CODE_2,CODE_PAGE_INVALID ; mark invalid..
	MOV	[BP].RET_CODE_3,INVALID_SYNTAX	; syntax error
	MOV	LOOP_COUNT,ERROR_COND		; set flag to exit parse

	jmp	short kbs_31

kbs_28:
	MOV	[BP].RET_CODE_2,CODE_PAGE_VALID	; else...valid code page
	MOV	[BP].CODE_PAGE_PARM,AX		; move into parm

	jmp	short kbs_31

kbs_30:
	MOV	[BP].RET_CODE_2,NO_CODE_PAGE	; mark as not specified.
kbs_31:
	RET

PROCESS_2ND_PARM      ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; PROCEDURE_NAME: PROCESS_3RD_PARM
;
; FUNCTION:
; THIS PROCEDURE PROCESSES THE 3RD POSITIONAL PARAMETER. THIS SHOULD
; BE THE KEYBOARD DEFINITION FILE PATH, IF SPECIFIED.
;
; AT ENTRY: PARSE RESULT BLOCK CONTAINS VALUES IF AX HAS NO ERROR.
;
; AT EXIT:
;    PARAMETER CONTROL BLOCK UPDATED FOR FILE NAME.
;
; AUTHOR: WGR
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PROCESS_3RD_PARM       PROC    NEAR

	cmp	ax,RC_NO_ERROR		; if parse error, then...
	jle	kbs_33

	MOV	[BP].RET_CODE_3,INVALID_SYNTAX ; syntax error.
	MOV	LOOP_COUNT,ERROR_COND	; set flag to exit parse
	MOV	ERR_PART,AX

	jmp	short kbs_34

kbs_33:

	cmp	RESULT_TYPE,FILE_SPEC
	jnz	kbs_34

	PUSH	DS
	PUSH	SI
	PUSH	DI
	PUSH	CX
	LDS	SI,RESULT_VAL		; load offset of file name
	LEA	DI,TEMP_FILE_NAME
	MOV	[BP].PATH_OFFSET,DI	; copy to parameter block
	XOR	CX,CX
	LODSB				; count the length of the path.

kbs_35:
	or	al,al
	jz	kbs_36

	STOSB
	LODSB
	INC	CX
	jmp	short kbs_35

kbs_36:
	MOV	[BP].PATH_LENGTH,CX	; copy to parameter block
	POP	CX
	POP	DI
	POP	SI
	POP	DS
kbs_34:
	RET

PROCESS_3RD_PARM ENDP

CODE	ENDS
	END
