;
;	IBM Confidential
;	Copyright (C) IBM Corporation 1991-1993
;       All Rights Reserved.
;
;
;Revision History
;================
;
; M029  02/15/91 SR     Bug #5699. In SysParse, reinitialize $P_FileSp_Char
;                       everytime because this is in the non-checksum region
;                       and can get corrupted without the checksum region
;                       getting corrupted. Yet another data structure that
;                       should have been in the checksum region but isnt.
;
; IBMDOS60 - WRA - 01/14/93 - Added preprocessor logic so that a JMP could
;			      be SHORT for most cases in $P_Check_Match_Flags.
;
; NOTE:   basesw must be set properly to allow the PARSER to access psdata.
;          - basesw undefined    means   CS seg. override for psdata access.
;          - basesw = 1          means   DS seg. override for psdata access &
;                                        DS must point to psdata.
;          - basesw = 0          means   ES seg. override for psdata access &
;                                        ES must point to psdata.
;
; IBMDOS60 - Tony I. - Various space saving hacks.


__TONYI__PARSE__ = 1	; Enable speed/space hacks


IFNDEF basesw                           ;AN022;
   psdata_seg EQU   CS                  ;AN022;
ELSE                                    ;AN022;
   IF  basesw                           ;AN022;IF "basesw  EQU  1" specified by caller THEN
       psdata_seg EQU   DS              ;AN022;
   ELSE                                 ;AN022;
       psdata_seg EQU   ES              ;AN022;ELSE only other choice is ES (basesw EQU 0)
   ENDIF                                ;AN022;
ENDIF                                   ;AN022;

ifndef incsw				 ; (tm03) Someone doesn't want to include psdata
   incsw equ	 1			 ; include psdata.inc (tm03)
endif					 ; (tm03)
if incsw				 ; If incsw = 1 then (tm03)
   include psdata.inc			 ;    include psdata.inc (tm03)
endif					 ; endif	     (tm03)
   PAGE 				 ;
IF1					 ;
ENDIF					 ;
;***********************************************************************
; SysParse;
;
;  Function : Parser Entry
;
;  Input: DS:SI -> command line
;         ES:DI -> parameter block
;         psdata_seg -> psdata.inc
;         CX = operand ordinal
;
;         Note:  ES is the segment containing all the control blocks defined
;                by the caller, except for the DOS COMMAND line parms, which
;                is in DS.
;
;  Output: CY = 1   error of caller, means invalid parameter block or
;                   invalid value list. But this parser does NOT implement
;                   this feature. Therefore CY always zero.
;
;          CY = 0   AX = return code
;                   BL = terminated delimiter code
;                   CX = new operand ordinal
;                   SI = set past scaned operand
;                   DX = selected result buffer
;
; Use:  $P_Skip_Delim, $P_Chk_EOL, $P_Chk_Delim, $P_Chk_DBCS
;       $P_Chk_Swtch, $P_Chk_Pos_Control, $P_Chk_Key_Control
;       $P_Chk_Sw_Control, $P_Fill_Result
;
; Vars: $P_Ordinal(RW), $P_RC(RW), $P_SI_Save(RW), $P_DX(R), $P_Terminator(R)
;       $P_SaveSI_Cmpx(W), $P_Flags(RW), $P_Found_SYNONYM(R), $P_Save_EOB(W)
;
;-------- Modification History -----------------------------------------
;
;  4/04/87 : Created by K. K,
;  4/28/87 : $P_Val_YH assemble error (tm01)
;          : JMP SHORT assemble error (tm02)
;  5/14/87 : Someone doesn't want to include psdata (tm03)
;  6/12/87 : $P_Bridge is missing when TimeSw equ 0 and (CmpxSw equ 1 or
;            DateSW equ 1)            (tm04)
;  6/12/87 : $P_SorD_Quote is missing when QusSw equ 0 and CmpxSW equ 1
;                                     (tm05) in PSDATA.INC
;  6/12/87 : $P_FileSp_Char and $P_FileSP_Len are missing
;            when FileSW equ 0 and DrvSW equ 1 (tm06) in PSDATA.INC
;  6/18/87 : $VAL1 and $VAL3, $VAL2 and $VAL3 can be used in the same
;            value-list block         (tm07)
;  6/20/87 : Add $P_SW to check if there's an omiting parameter after
;            switch (keyword) or not. If there is, backup si for next call
;            (tm08)
;  6/24/87 : Complex Item checking does not work correctly when CmpSW equ 1
;            and DateSW equ 0 and TimeSW equ 0 (tm09)
;  6/24/87 : New function flag $P_colon_is_not_necessary for switch
;            /+15 and /+:15 are allowed for user (tm10)
;  6/29/87 : ECS call changes DS register but it causes the address problem
;            in user's routines. $P_Chk_DBCS (tm11)
;  7/10/87 : Switch with no_match flag (0x0000H) does not work correctly
;                                         (tm12)
;  7/10/87 : Invalid switch/keyword does not work correctly
;                                         (tm13)
;  7/10/87 : Drive_only breaks 3 bytes after the result buffer
;                                         (tm14)
;  7/12/87 : Too_Many_Operands sets DX=0 as the PARSE result
;                                         (tm15)
;  7/24/87 : Negative lower bound on numeric ranges cause trouble

;  7/24/87 : Quoted strings being returned with quotes.

;  7/28/87 : Kerry S (;AN018;)
;            Non optional value on switch (match flags<>0 and <>1) not flagged
;            as an error when missing.  Solution: return error 2.  Modules
;            affected: $P_Chk_SW_Control.

;  7/29/87 : Kerry S (;AN019;)
;            Now allow the optional bit in match flags for switches.  This
;            allows the switch to be encountered with a value or without a
;            value and no error is returned.
;

;  8/28/87 : Ed K, Kerry S (;AN020;)
;  9/14/87   In PROC $P_Get_DecNum, when checking for field separators
;            within a date response, instead of checking just for the one
;            character defined by the COUNTRY DEPENDENT INFO, check for
;            all three chars, "-", "/", and ".". Change $P_Chk_Switch to allow
;            slashes in date strings when DateSw (assembler switch) is set.

;  9/1/87  : Kerry S (;AN021)
;            In PROC $P_String_Comp, when comparing the switch or keyword on
;            the command line with the string in the control block the
;            comparing was stopping at a colon (switch) or equal (keyword)
;            on the command line and assuming a match.  This allowed a shorter
;            string on the command line than in the synonym list in the control
;            block.  I put in a test for a null in the control block so the
;            string in the control block must be the same length as the string
;            preceeding the colon or equal on the command line.

;  8/28/87 : Kerry S (;AN022;)
;            All references to data in PSDATA.INC had CS overrides.  This caused
;            problems for people who included it themselves in a segment other
;            than CS.  Added switch to allow including PSDATA.INC in any
;            segment.

;  9/16/87 : Ed K (;AN023;) PTM1040
;            in $p_set_cdi PROC, it assumes CS points to psdata. Change Push CS
;            into PUSH PSDATA_SEG.  In $P_Get_DecNum PROC, fix AN020
;            forced both TIME and DATE to use the delims, "-","/",".".
;            Created FLag, in $P_time_Format PROC, to request the delim in
;            BL be used if TIME is being parsed.

;  9/24/87 : Ed K
;            Removed the include to STRUC.INC.  Replaced the STRUC macro
;            invocations with their normally expanded code; made comments
;            out of the STRUC macro invocation statements to maintain readability.

;  9/24/87 : Ed K (;AN024;) PTM1222
;            When no CONTROL for a keyword found, tried to fill in RESULT
;            pointed to by non-existant CONTROL.

; 10/15/87 : Ed K (;AN025;) PTM1672
;            A quoted text string can be framed only by double quote.  Remove
;            support to frame quoted text string with single quote.
;            (apostrophe) $P_SorD_Quote is removed from PSDATA.INC.
;            $P_SQuote EQU also removed from PSDATA.INC.  Any references to
;            single quote in PROC prologues are left as is for history reasons.

;            This fixes another bug, not mentioned in p1672, in that two
;            quote chars within a quoted string is supposed to be reported as
;            one quote character, but is reported as two quotes.  This changed
;            two instructions in PROC $P_Quoted_Str.

;            Also fixed are several JMP that caused a NOP, these changed to
;            have the SHORT operator to avoid the unneeded NOP.

;            The code and PSDATA.INC have been aligned for ease of reading.

; 10/26/87 : Ed K (;AN026;) PTM2041, DATE within SWITCH, BX reference to
;            psdata buffer should have psdata_seg.

; 10/27/87 : Ed K (;AN027;) PTM2042 comma between keywords implies
;            positional missing.

; 11/06/87 : Ed K (;AN028;) PTM 2315 Parser should not use line feed
;            as a line delimiter, should use carriage return.
;            Define switch: LFEOLSW, if on, accept LF as end of line char.

; 11/11/87 : Ed K (;AN029;) PTM 1651 GET RID OF WHITESPACE AROUND "=".

; 11/18/87 : Ed K (;AN030;) PTM 2551 If filename is just "", then
;            endless loop since SI is returned still pointing to start
;            of that parm.

; 11/19/87 : Ed K (;AN031;) PTM 2585 date & time getting bad values.
;            Vector to returned string has CS instead of Psdata_Seg, but
;            when tried to fix it on previous version, changed similar
;            but wrong place.

; 12/09/87 : Bill L (;AN032;) PTM 2772 colon and period are now valid
;            delimiters between hours, minutes, seconds for time. And period
;            and comma are valid delimiters between seconds and 100th second.

; 12/14/87 : Bill L (;AN033;) PTM 2722 if illegal delimiter characters
;            in a filespec, then flag an error.

; 12/22/87 : Bill L (;AN034;)       All local data to parser is now
;            indexed off of the psdata_seg equate instead of the DS register.
;            Using this method, DS can point to the segment of PSP or to psdata
;  -->       local parser data. Why were some references to local data changed
;            to do this before, but not all ?????

; 02/02/88 : Ed K (;AC035;) INSPECT utility, suggests optimizations.

; 02/05/88 : Ed K (;AN036;) P3372-UPPERCASE TRANSLATION, PSDATA_SEG HOSED.
;
; 02/08/88 : Ed K (;AN037;) P3410-AVOID POP OF CS, CHECK BASESW FIRST.

; 02/19/88 : Ed K (;AN038;) p3524 above noon and "am" should be error

; 02/23/88 : Ed K (;AN039;) p3518 accept "comma" and "period" as decimal
;            separator in TIME before hundredths field.
;
; 08/09/90 : SA M005    Prevented parser from recognizing '=' signs within
;                       strings as keywords.
;
;***********************************************************************
IF FarSW				 ;(Check if need far return)
SysParse proc far			 ;
ELSE					 ;
SysParse proc near			 ;
ENDIF					 ;(of FarSW)
        mov     psdata_seg:$P_Flags,0   ;AC034; Clear all internal flags
IF      TimeSw                          ;AN039; FOR TIME ONLY
        MOV    PSDATA_SEG:$P_ORIG_ORD,CX ;AN039; ORIGINAL ORDINAL FROM CX
        MOV    PSDATA_SEG:$P_ORIG_STACK,SP ;AN039; ORIGINAL VALUE OF STACK FROM SP
        MOV    PSDATA_SEG:$P_ORIG_SI,SI ;AN039; ORIGINAL START PARSE POINTER FROM SI
$P_REDO_TIME:                           ;AN039; try to parse time again
ENDIF                                   ;AN039; FOR TIME ONLY
	cld				       ; confirm forward direction
        mov     psdata_seg:$P_ordinal,cx      ;AC034; save operand ordinal
        mov     psdata_seg:$P_RC,$P_No_Error  ;AC034; Assume no error
        mov     psdata_seg:$P_Found_SYNONYM,0 ;AC034; initalize synonym pointer

        mov     word ptr psdata_seg:$P_DX,0   ;AC034; (tm15)

;M029 -- Begin changes
; The table of special chars $P_FileSp_Char should be initialized on every
;entry to SysParse. This is in the non-checksum region and any program that
;corrupts this table but does not corrupt the checksum region will leave
;command.com parsing in an inconsistent state.
; NB: The special characters string has been hardcoded here. If any change
;is made to it in psdata.inc, a corresponding change needs to be made here.
;
IF FileSW + DrvSW

        mov     word ptr psdata_seg:$P_FileSp_Char, ']['
        mov     word ptr psdata_seg:$P_FileSp_Char+2, '<|'
        mov     word ptr psdata_seg:$P_FileSp_Char+4, '+>'
        mov     word ptr psdata_seg:$P_FileSp_Char+6, ';='

ENDIF
;
;M029 -- End of changes
;

IF KeySW                                ;AN029;
;IN CASE THE USER PUT OPTIONAL WHITESPACE CHARS AROUND THE "=" USED IN
;KEYWORD DEFINITIONS, SCAN THE COMMAND LINE AND COMPRESS OUT ANY WHITESPACES
;NEXT TO "=" BEFORE STARTING THE USUAL PARSING.
       push      cx                     ;AN029;
       push      dx                     ;AN029;
       push      di                     ;AN029;

       push      si                     ;AN029; remember where command line starts
       mov       cx,-1                  ;AN029; init counter
$P_loc_eol:                             ;AN029;
          inc       cx                  ;AN029; bump counter of chars up to EOL
          lodsb                         ;AN029; get a char from command line
          CALL      $P_Chk_EOL          ;AN029; see if AL is EOL char
       jnz       $P_loc_EOL             ;AN029; not found that EOL char

       mov       psdata_seg:$P_count_to_EOL,cx ;AN029;AC034;; save count of chars up to EOL
       pop       si                     ;AN029; restore start of command line

;scan command string for combinations including "=",
;      and replace each with just the simple "="

;REPEAT UNTIL ONE PASS IS MADE WHEREIN NO CHANGES WERE MADE
$P_DO1:                            ;AN029;
       push si                     ;AN029; remember where string started
       MOV  CX,psdata_seg:$P_COUNT_TO_EOL ;AN029;AC034;; set  count to no. chars in string,
                                   ;AN029; not counting the EOL char
       XOR  BX,BX                  ;AN029;SET $P_REG_BL_DQ_SW TO "NOT IN QUOTES", AND...
                                   ;AN029;SET $P_REG_BH_CG_SW TO "NO CHANGES MADE"
;MAKE ONE PASS THRU THE STRING, LOOKING AT EACH CHARACTER
$P_DO2:                            ;AN029;
           cmp  BYTE PTR [SI],$P_double_quote ;AN029;
           JNE $P_IF3              ;AN029;
               NOT  $P_REG_BL_DQ_SW ;AN029;TOGGLE THE DOUBLE QUOTE STATE SWITCH
$P_IF3:                            ;AN029;
           OR   $P_REG_BL_DQ_SW,$P_REG_BL_DQ_SW ;AN029;IS THE DOUBLE QUOTE SWITCH SET?
           JNZ $P_IF5              ;AN029;
               mov  ax,word ptr [si] ;AN029; get pair to be checked out
               cmp  ax,$P_BL_EQ    ;AN029;" ="
               JE $P_LL6           ;AN029;
               cmp  ax,$P_EQ_BL    ;AN029;"= "
               JE $P_LL6           ;AN029;
               cmp  ax,$P_EQ_TB    ;AN029; "=<tab>"
               JE $P_LL6           ;AN029;
               cmp  ax,$P_TB_EQ    ;AN029;"<tab>="
               JNE $P_IF6          ;AN029;
$P_LL6:                            ;AN029;
                   mov  BYTE PTR [SI],$P_Keyword ;AN029; "="
                   inc  si         ;AN029;point to next char after the new "="
                   mov  di,si      ;AN029;move target right after new "="

                   push si         ;AN029;remember where i am, right after new "="
                   PUSH CX         ;AN029;SAVE CURRENT COUNT
                   inc  si         ;AN029;source is one beyond that
                   push es         ;AN029;remember the extra segment
                   push ds         ;AN029;temporarily, set source seg and
                   pop  es         ;AN029; target seg to the command line seg
                   rep  movsb      ;AN029;move chars left one position
                   pop  es         ;AN029;restore the extra segment
                   POP  CX         ;AN029;RESTORE CURRENT COUNT
                   pop  si         ;AN029;back to where I was

                   DEC  SI         ;AN029;LOOK AT FIRST CHAR JUST MOVED
                   MOV  $P_REG_BH_CG_SW,-1 ;AN029;set switch to say "a change was made"
                   DEC  psdata_seg:$P_COUNT_TO_EOL ;AN029;AC034;;because just threw away a char
                   dec  CX         ;AN029;DITTO
$P_IF6:                            ;AN029;
$P_IF5:                            ;AN029;
           inc  si                 ;AN029;bump index to look at next char in command string
           dec  CX                 ;AN029;one less char to look at
       JNLE $P_DO2                 ;AN029;
       pop  si                     ;AN029;remember where string started
       OR   $P_REG_BH_CG_SW,$P_REG_BH_CG_SW ;AN029;WAS "A CHANGE MADE"?
   JNZ $P_DO1                      ;AN029;
   pop  di                         ;AN029;
   pop  dx                         ;AN029;
   pop  cx                         ;AN029;

;NOW THAT ALL WHITESPACE SURROUNDING "=" HAVE BEEN COMPRESSED OUT,
;RESUME NORMAL PARSING...
ENDIF                                   ;AN029; KEYWORDS SUPPORTED?
	call	$P_Skip_Delim		 ; Move si to 1st non white space
	jnc	$P_Start		 ; If EOL is not encountered, do parse

;--------------------------- End of Line
	mov	ax,$P_RC_EOL		 ; set exit code to -1
	push	bx			 ;
	mov	bx,es:[di].$P_PARMSX_Address  ; Get the PARMSX address to
	cmp	cl,es:[bx].$P_MinP	 ; check ORDINAL to see if the minimum
	jae	$P_Fin			 ; positional found.

	mov	ax,$P_Op_Missing	 ; If no, set exit code to missing operand
$P_Fin: 				 ;
	pop	bx			 ;
	jmp	$P_Single_Exit		 ; return to the caller

;---------------------------
$P_Start:				 ;
	mov	psdata_seg:$P_SaveSI_Cmpx,si  ;AC034;  save ptr to command line for later use by complex,
	push	bx			 ; quoted string or file spec.
	push	di			 ;
	push	bp			 ;
        lea     bx,psdata_seg:$P_STRING_BUF ;AC034; set buffer to copy from command string
        test    psdata_seg:$P_Flags2,$P_Extra ;AC034; 3/9 extra delimiter encountered ?
	jne	$P_Pack_End		 ; 3/9 if yes, no need to copy

$P_Pack_Loop:				 ;
	lodsb				 ; Pick a operand from buffer
	call	$P_Chk_Switch		 ; Check switch character
        jc      $P_Pack_End_BY_EOL      ;AN020; if carry set found delimiter type slash, need backup si, else continue

	call	$P_Chk_EOL		 ; Check EOL character
	je	$P_Pack_End_BY_EOL	 ; need backup si

	call	$P_Chk_Delim		 ; Check delimiter
	jne	$P_PL01 		 ; If no, process next byte

        test    psdata_seg:$P_Flags2,$P_Extra ;AC034; 3/9 If yes and white spec,
	jne	$P_Pack_End_backup_si	 ; (tm08)

	call	$P_Skip_Delim		 ; skip subsequent white space,too
	jmp	short $P_Pack_End	 ; finish copy by placing NUL at end

$P_PAck_End_backup_si:			 ; (tm08)
	test	psdata_seg:$P_Flags2,$P_SW+$P_equ  ;AC034;  (tm08)
	je	$P_Pack_End		 ; (tm08)

	dec	si			 ; (tm08)
        jmp     short $P_Pack_End       ;AN025; (tm08)

$P_PL01:				 ;
	mov	psdata_seg:[bx],al	 ; move byte to STRING_BUF
	cmp	al,$P_Keyword		 ; if it is equal character,
	jne	$P_PL00 		 ; then

        or      psdata_seg:$P_Flags2,$P_equ ;AC034; remember it in flag
$P_PL00:				 ;
	inc	bx			 ; ready to see next byte
	call	$P_Chk_DBCS		 ; was it 1st byte of DBCS ?
	jnc	$P_Pack_Loop		 ; if no, process to next byte

	lodsb				 ; if yes, store
	mov	psdata_seg:[bx],al	 ;    2nd byte of DBCS
	inc	bx			 ; update pointer
	jmp	short $P_Pack_Loop	 ; process to next byte

$P_Pack_End_BY_EOL:			 ;
	dec	si			 ; backup si pointer
$P_Pack_End:				 ;
        mov     psdata_seg:$P_SI_Save,si     ;AC034; save next pointer, SI
	mov	byte ptr psdata_seg:[bx],$P_NULL  ; put NULL at the end
        mov     psdata_seg:$P_Save_EOB,bx    ;AC034; 3/17/87 keep the address for later use of complex
	mov	bx,es:[di].$P_PARMSX_Address  ; get PARMSX address
        lea     si,psdata_seg:$P_STRING_BUF  ;AC034;
	cmp	byte ptr psdata_seg:[si],$P_Switch  ; the operand begins w/ switch char ?
	je	$P_SW_Manager		      ; if yes, process as switch

        cmp     byte ptr psdata_seg:[si],$P_DQuote      ;M005;is it a string?
        je      $P_Positional_Manager                   ;M005;if so, process as one!

        test    psdata_seg:$P_Flags2,$P_equ   ;AC034; the operand includes equal char ?
	jne	$P_Key_manager		      ; if yes, process as keyword

$P_Positional_Manager:			 ; else process as positional
	mov	al,es:[bx].$P_MaxP	 ; get maxp
	xor	ah,ah			 ; ax = maxp
        cmp     psdata_seg:$P_ORDINAL,ax ;AC034; too many positional ?
	jae	$P_Too_Many_Error	 ; if yes, set exit code to too many

        mov     ax,psdata_seg:$P_ORDINAL ;AC034; see what the current ordinal
	shl	ax,1			 ; ax = ax*2
        inc     bx                      ;AC035; add '2' to
        inc     bx                      ;AC035;  BX reg
					 ; now bx points to 1st CONTROL
;(changed ;AC035;) add	   bx,2 	 ; now bx points to 1st CONTROL
	add	bx,ax			 ; now bx points to specified CONTROL address
	mov	bx,es:[bx]		 ; now bx points to specified CONTROL itself
	call	$P_Chk_Pos_Control	 ; Do process for positional
	jmp	short $P_Return_to_Caller  ; and return to the caller

$P_Too_Many_Error:			 ;
        mov     psdata_seg:$P_RC,$P_Too_Many ;AC034; set exit code
	jmp	short $P_Return_to_Caller  ; and return to the caller

ifdef __TONYI__PARSE__
;---------------------------------------------
; Factor out duplicate code...
;---------------------------------------------
ParseCommonCode1 proc near
	mov	al,es:[bx].$P_MaxP	;AN000; get maxp
	xor	ah,ah			;AN000; ax = maxp
	inc	ax			;AN000;
	shl	ax,1			;AN000; ax = (ax+1)*2
	add	bx,ax			;AN000; now bx points to maxs
	ret
ParseCommonCode1 endp
endif


$P_SW_Manager:				 ;
ifdef __TONYI__PARSE__
;-------------------------------------------
; Save some space.....
;-------------------------------------------
	call	ParseCommonCode1
else
	mov	al,es:[bx].$P_MaxP	;AN000; get maxp
	xor	ah,ah			;AN000; ax = maxp
	inc	ax			;AN000;
	shl	ax,1			;AN000; ax = (ax+1)*2
	add	bx,ax			;AN000; now bx points to maxs
endif

	mov	cl,es:[bx]		 ;
	xor	ch,ch			 ; cx = maxs
ifdef __TONYI__PARSE__
;-----------------------------
; Save 2 bytes....
;-----------------------------
	jcxz	$P_SW_Not_Found 	;AN000;
else
	or	cx,cx			 ; at least one switch ?
	je	$P_SW_Not_Found 	 ;
endif

	inc	bx			 ; now bx points to 1st CONTROL address

$P_SW_Mgr_Loop: 			 ;
	push	bx			 ;
	mov	bx,es:[bx]		 ; bx points to Switch CONTROL itself
	call	$P_Chk_SW_Control	 ; do process for switch
	pop	bx			 ;
	jnc	$P_Return_to_Caller	 ; if the CONTROL is for the switch, exit

        inc     bx                      ;AC035; add '2' to
        inc     bx                      ;AC035;  BX reg
					 ; else bx points to the next CONTROL
;(changed ;AC035;)  add     bx,2	 ; else bx points to the next CONTROL
	loop	$P_SW_Mgr_Loop		 ; and loop

$P_SW_Not_Found:			 ;
        mov     psdata_seg:$P_RC,$P_Not_In_SW ;AC034; here no CONTROL for the switch has
	jmp	short $P_Return_to_Caller0     ; not been found, means error.
;
$P_Key_Manager: 			 ;
ifdef __TONYI__PARSE__
;-------------------------------------------
; Save some space.....
;-------------------------------------------
	call	ParseCommonCode1
else
	mov	al,es:[bx].$P_MaxP	;AN000; get maxp
	xor	ah,ah			;AN000; ax = maxp
	inc	ax			;AN000;
	shl	ax,1			;AN000; ax = (ax+1)*2
	add	bx,ax			;AN000; now bx points to maxs
endif
	mov	al,es:[bx]		 ;
	xor	ah,ah			 ; ax = maxs
	shl	ax,1			 ;
	inc	ax			 ; ax = ax*2+1
	add	bx,ax			 ; now bx points to maxk
	mov	cl,es:[bx]		 ;
	xor	ch,ch			 ; cx = maxk
ifdef __TONYI__PARSE__
;------------------------------------------
; Save 2 bytes.....
;------------------------------------------
	jcxz	$P_Key_Not_Found	;AN000;
else
	or	cx,cx			;AN000; at least one keyword ?
	je	$P_Key_Not_Found	;AN000;
endif

	inc	bx			 ; now bx points to 1st CONTROL

$P_Key_Mgr_Loop:			 ;
	push	bx			 ;
	mov	bx,es:[bx]		 ; bx points to keyword CONTROL itself
	call	$P_Chk_Key_Control	 ; do process for keyword
	pop	bx			 ;
	jnc	$P_Return_to_Caller	 ; if the CONTROL is for the keyword, exit

        inc     bx                      ;AC035; add '2' to
        inc     bx                      ;AC035;  BX reg
					 ; else bx points to the next CONTROL
;(changed ;AC035;)  add     bx,2	 ; else bx points to the next CONTROL
	loop	$P_Key_Mgr_Loop 	 ; and loop

$P_Key_Not_Found:			 ;
        mov     psdata_seg:$P_RC,$P_Not_In_Key ;AC034; here no CONTROL for the keyword has
$P_Return_to_Caller0:			 ; not been found, means error.
$P_Return_to_Caller:			 ;
	pop	bp			 ;
	pop	di			 ;
	pop	bx			 ;
        mov     cx,psdata_seg:$P_Ordinal    ;AC034; return next ordinal
        mov     ax,psdata_seg:$P_RC         ;AC034; return exit code
        mov     si,psdata_seg:$P_SI_Save    ;AC034; return next operand pointer
        mov     dx,psdata_seg:$P_DX         ;AC034; return result buffer address
        mov     bl,psdata_seg:$P_Terminator ;AC034; return delimiter code found
$P_Single_Exit: 			 ;
	clc				 ;
	ret				 ;
SysParse endp				 ;
PAGE					 ;
;***********************************************************************
; $P_Chk_Pos_Control
;
; Function: Parse CONTROL block for a positional
;
; Input:     ES:BX -> CONTROL block
;            psdata_seg:SI -> $P_STRING_BUF
;
; Output:    None
;
; Use:   $P_Fill_Result, $P_Check_Match_Flags
;
; Vars: $P_Ordinal(W), $P_RC(W)
;***********************************************************************
$P_Chk_Pos_Control proc 		 ;
	push	ax			 ;
	mov	ax,es:[bx].$P_Match_Flag  ;
	test	ax,$P_Repeat		 ; repeat allowed ?
	jne	$P_CPC00		 ; then do not increment ORDINAL

        inc     psdata_seg:$P_ORDINAL   ;AC034; update the ordinal
$P_CPC00:				 ;
	cmp	byte ptr psdata_seg:[si],$P_NULL  ; no data ?
	jne	$P_CPC01		 ;

	test	ax,$P_Optional		 ; yes, then is it optional ?
	jne	$P_CPC02		 ;

        mov     psdata_seg:$P_RC,$P_Op_Missing ;AC034; no, then error        3/17/87
	jmp	short $P_CPC_Exit	 ;

$P_CPC02:				 ;
	push	ax			 ;
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR ($P_String AND 0FFH))
else
	mov	al,$P_String		;AN000; if it is optional return NULL
	mov	ah,$P_No_Tag		;AN000; no item tag indication
endif
	call	$P_Fill_Result		 ;
	pop	ax			 ;
	jmp	short $P_CPC_Exit	 ;

$P_CPC01:				 ;
	call	$P_Check_Match_Flags	 ;
$P_CPC_Exit:				 ;
	pop	ax			 ;
	ret				 ;
$P_Chk_Pos_Control endp 		 ;
PAGE					 ;
;***********************************************************************
; $P_Chk_Key_Control
;
; Function: Parse CONTROL block for a keyword
;
; Input:     ES:BX -> CONTROL block
;            psdata_seg:SI -> $P_STRING_BUF
;
; Output:    CY = 1 : not match
;
; Use:   $P_Fill_Result, $P_Search_KEYorSW, $P_Check_Match_Flags
;
; Vars: $P_RC(W), $P_SaveSI_Cmpx(W), $P_KEYorSW_Ptr(R), $P_Flags(W)
;***********************************************************************
$P_Chk_Key_Control proc 		 ;
IF	KeySW				 ;(Check if keyword is supported)
        or      psdata_seg:$P_Flags2,$P_Key_Cmp ;AC034; Indicate keyword for later string comparison
	call	$P_Search_KEYorSW	 ; Search the keyword in the CONTROL block
	jc	$P_Chk_Key_Err0 	 ; not found, then try next CONTROL

        and     psdata_seg:$P_Flags2,0ffh-$P_Key_Cmp ;AC034; reset the indicator previously set
;
	push	ax			      ; 	 keyword=
        mov     ax,psdata_seg:$P_KEYorSW_Ptr ;AC034;          ^       ^
	sub	ax,si			 ;  SI	   KEYorSW
        add     psdata_seg:$P_SaveSI_Cmpx,ax ;AC034; update for complex, quoted or file spec.
	pop	ax			 ;
;
        mov     si,psdata_seg:$P_KEYorSW_Ptr ;AC034; set si just after equal char
	cmp	byte ptr psdata_seg:[si],$P_NULL  ; any data after equal ?
	je	$P_Chk_Key_Err1 	 ; if no, syntax error

	call	$P_Check_Match_Flags	 ; else, process match flags
	clc				 ;
	jmp	short $P_Chk_Key_Exit	 ;

$P_Chk_Key_Err0:			 ;
	stc				 ; not found in keyword synonym list
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte. Do the RET here.
;-------------------------------------
	ret
else
	jmp	short $P_Chk_Key_Exit	;AN000;
endif

$P_Chk_Key_Err1:			 ;
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034; no parameter is not specified after "="
$P_Chk_Key_ErrExit:			 ;
	push	ax			 ;
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR ($P_String and 0FFH))
else
	mov	al,$P_String		 ; set
	mov	ah,$P_No_Tag		 ;    result
endif
	call	$P_Fill_Result		 ;	    buffer
	pop	ax			 ;
	clc				 ;
$P_Chk_Key_Exit:			 ;
	ret				 ;
ELSE					 ;(of IF KeySW)
	stc				 ;this logic works when the KeySW
	ret				 ;is reset.
ENDIF					 ;(of KeySW)
$P_Chk_Key_Control endp 		 ;
PAGE					 ;
;***********************************************************************
IF	KeySW+SwSW			 ;(Check if keyword or switch is supported)
; $P_Search_KEYorSW:
;
; Function: Seach specified keyword or switch from CONTROL
;
; Input:     ES:BX -> CONTROL block
;            psdata_seg:SI -> $P_STRING_BUF
;
; Output:    CY = 1 : not match
;
; Use:   $P_String_Comp, $P_MoveBP_NUL, $P_Found_SYNONYM
;***********************************************************************
$P_Search_KEYorSW proc			 ;
	push	bp			 ;
	push	cx			 ;
	mov	cl,es:[bx].$P_nid	 ; Get synonym count
	xor	ch,ch			 ; and set it to cx
ifdef __TONYI__PARSE__
;-------------------------------------
; Save 2 bytes....
;-------------------------------------
	jcxz	$P_KEYorSW_Not_Found	;AN000; then indicate not found by CY
else
	or	cx,cx			 ; No synonyms specified ?
	je	$P_KEYorSW_Not_Found	 ; then indicate not found by CY
endif

	lea	bp,es:[bx].$P_KEYorSW	 ; BP points to the 1st synonym
$P_KEYorSW_Loop:			 ;
	call	$P_String_Comp		 ; compare string in buffer w/ the synonym
	jnc	$P_KEYorSW_Found	 ; If match, set it to synonym pointer

	call	$P_MoveBP_NUL		 ; else, bp points to the next string
	loop	$P_KEYorSW_Loop 	 ; loop nid times
$P_KEYorSW_Not_Found:			 ;
	stc				 ; indicate not found in synonym list
	jmp	short $P_KEYorSW_Exit	 ; and exit

$P_KEYorSW_Found:			 ;
        mov     psdata_seg:$P_Found_SYNONYM,bp ;AC034; set synonym pointer
	clc				 ; indicate found
$P_KEYorSW_Exit:			 ;
	pop	cx			 ;
	pop	bp			 ;
	ret				 ;
$P_Search_KEYorSW endp			 ;
;***********************************************************************
; $P_MoveBP_NUL
;***********************************************************************
$P_MoveBP_NUL proc			 ;
$P_MBP_Loop:				 ;
	cmp	byte ptr es:[bp],$P_NULL  ; Increment BP that points
	je	$P_MBP_Exit		 ; to the synomym list

	inc	bp			 ; until
	jmp	short $P_MBP_Loop	 ; NULL encountered.

$P_MBP_Exit:				 ;
	inc	bp			 ; bp points to next to NULL
	ret				 ;
$P_MoveBP_NUL endp			 ;
ENDIF					 ;(of KeySW+SwSW)
PAGE					 ;
;***********************************************************************
; $P_Chk_SW_Control
;
; Function: Parse CONTROL block for a switch
;
; Input:     ES:BX -> CONTROL block
;            psdata_seg:SI -> $P_STRING_BUF
;
; Output:    CY = 1 : not match
;
; Use:   $P_Fill_Result, $P_Search_KEYorSW, $P_Check_Match_Flags
;
; Vars:  $P_SaveSI_Cmpx(W), $P_KEYorSW_Ptr(R), $P_Flags(W)
;***********************************************************************
$P_Chk_SW_Control proc			 ;


IF	SwSW				 ;(Check if switch is supported)
        or      psdata_seg:$P_Flags2,$P_Sw_Cmp ;AC034; Indicate switch for later string comparison
	call	$P_Search_KEYorSW	 ; Search the switch in the CONTROL block
	jc	$P_Chk_SW_Err0		 ; not found, then try next CONTROL

        and     psdata_seg:$P_Flags2,0ffh-$P_Sw_Cmp ;AC034; reset the indicator previously set
;
	push	ax			 ;		 /switch:
        mov     ax,psdata_seg:$P_KEYorSW_Ptr ;AC034;          ^       ^
	sub	ax,si			 ;  SI	   KEYorSW
        add     psdata_seg:$P_SaveSI_Cmpx,ax ;AC034; update for complex list
	pop	ax			 ;
;
        mov     si,psdata_seg:$P_KEYorSW_Ptr ;AC034; set si at the end or colon
	cmp	byte ptr psdata_seg:[si],$P_NULL  ; any data after colon
	jne	$P_CSW00		 ; if yes, process match flags

	cmp	byte ptr psdata_seg:[si-1],$P_Colon  ; if no, the switch terminated by colon ?
	jne	$P_Chk_if_data_required  ; if yes,

        mov     psdata_seg:$P_RC,$P_Syntax ;AC034; return syntax error
	jmp	short $P_Chk_SW_Exit	 ;

$P_Chk_if_data_required:                ;AN018; no data, no colon
        cmp     es:[bx].$P_Match_Flag,0 ;AN018; should have data? zero match flag means switch followed by nothing is OK
        je      $P_Chk_SW_Exit          ;AN018; match flags not zero so should have something if optional bit is not on

        test    es:[bx].$P_Match_Flag,$P_Optional ;AN019; see if no value is valid
        jnz     $P_Chk_SW_Exit          ;AN019; if so, then leave, else yell

        mov     psdata_seg:$P_RC,$P_Op_Missing ;AC034; return required operand missing
        jmp     short $P_Chk_SW_Exit    ;AN018;

$P_CSW00:				 ;
	call	$P_Check_Match_Flags	 ; process match flag
	clc				 ; indicate match
	jmp	short $P_Chk_SW_Single_Exit  ;

$P_Chk_SW_Err0: 			 ;
	stc				 ; not found in switch synonym list
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte. Do the RET here.
;-------------------------------------
	ret
else
	jmp	short $P_Chk_SW_Single_Exit  ;
endif

$P_Chk_SW_Exit: 			 ;
	push	ax			 ;
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR ($P_String and 0FFh))
else
	mov	al,$P_String		 ; set
	mov	ah,$P_No_Tag		 ;    result
endif
	call	$P_Fill_Result		 ;	    buffer
	pop	ax			 ;
	clc				 ;
$P_Chk_SW_Single_Exit:			 ;
	ret				 ;
ELSE					 ;(of IF SwSW)
	stc				 ; this logic works when the SwSW
	ret				 ; is reset.
ENDIF					 ;(of SwSW)
$P_Chk_SW_Control endp			 ;
PAGE					 ;
;***********************************************************************
; $P_Fill_Result
;
; Function: Fill the result buffer
;
; Input:    AH = Item tag
;           AL = type
;                 AL = 1: CX,DX has 32bit number (CX = high)
;                 AL = 2: DX has index(offset) into value list
;                 AL = 6: DL has driver # (1-A, 2-B, ... , 26 - Z)
;                 AL = 7: DX has year, CL has month and CH has date
;                 AL = 8: DL has hours, DH has minutes, CL has secondsn,
;                         amd CH has hundredths
;                 AL = else: psdata_seg:SI points to returned string buffer
;           ES:BX -> CONTROL block
;
; Output:   None
;
; Use:  $P_Do_CAPS_String, $P_Remove_Colon, $P_Found_SYNONYM
;
; Vars: $P_DX(W)
;***********************************************************************
$P_Fill_Result proc			 ;
	push	di			 ;
	mov	di,es:[bx].$P_Result_Buf  ; di points to result buffer
        mov     psdata_seg:$P_DX,di     ;AC034; set returned result address
	mov	es:[di].$P_Type,al	 ; store type
	mov	es:[di].$P_Item_Tag,ah	 ; store item tag
	push	ax			 ;
        mov     ax,psdata_seg:$P_Found_SYNONYM ;AC034; if yes,
	mov	es:[di].$P_SYNONYM_Ptr,ax  ;   then set it to the result
	pop	ax			 ;
$P_RLT04:				 ;
	cmp	al,$P_Number		 ; if number
	jne	$P_RLT00		 ;

$P_RLT02:				 ;
	mov	word ptr es:[di].$P_Picked_Val,dx  ; then store 32bit
	mov	word ptr es:[di+2].$P_Picked_Val,cx  ;	   number
	jmp	short $P_RLT_Exit	 ;

$P_RLT00:				 ;
	cmp	al,$P_List_Idx		 ; if list index
	jne	$P_RLT01		 ;

	mov	word ptr es:[di].$P_Picked_Val,dx  ; then store list index
	jmp	short $P_RLT_Exit	 ;

$P_RLT01:				 ;
	cmp	al,$P_Date_F		 ; Date format ?
	je	$P_RLT02		 ;

	cmp	al,$P_Time_F		 ; Time format ?
	je	$P_RLT02		 ;
;
	cmp	al,$P_Drive		 ; drive format ?
	jne	$P_RLT03		 ;

	mov	byte ptr es:[di].$P_Picked_Val,dl  ; store drive number
	jmp	short $P_RLT_Exit	 ;

$P_RLT03:				 ;
	cmp	al,$P_Complex		 ; complex format ?
	jne	$P_RLT05		 ;

        mov     ax,psdata_seg:$P_SaveSI_Cmpx ;AC034; then get pointer in command buffer
	inc	ax			 ; skip left Parentheses
	mov	word ptr es:[di].$P_Picked_Val,ax  ; store offset
	mov	word ptr es:[di+2].$P_Picked_Val,ds  ; store segment
	jmp	short $P_RLT_Exit	 ;

$P_RLT05:				 ;
;------------------------  AL = 3, 5, or 9
	mov	word ptr es:[di].$P_Picked_Val,si  ; store offset of STRING_BUF
        mov     word ptr es:[di+2].$P_Picked_Val,Psdata_Seg ;AN031; store segment of STRING_BUF
;
	push	ax			 ;
	test	byte ptr es:[bx].$P_Function_Flag,$P_CAP_File  ; need CAPS by file table?
	je	$P_RLT_CAP00		 ;

	mov	al,$P_DOSTBL_File	 ; use file upper case table
	jmp	short $P_RLT_CAP02	 ;

$P_RLT_CAP00:				 ;
	test	byte ptr es:[bx].$P_Function_Flag,$P_CAP_Char  ; need CAPS by char table ?
	je	$P_RLT_CAP01		 ;

	mov	al,$P_DOSTBL_Char	 ; use character upper case table
$P_RLT_CAP02:				 ;
	call	$P_Do_CAPS_String	 ;  process CAPS along the table
$P_RLT_CAP01:				 ;
	pop	ax			 ;
	test	byte ptr es:[bx].$P_Function_Flag,$P_Rm_Colon  ; removing colon at end ?
	je	$P_RLT_Exit		 ;

	call	$P_Remove_Colon 	 ; then process it.
$P_RLT_Exit:				 ;
	pop	di			 ;
	ret				 ;
$P_Fill_Result endp			 ;
PAGE					 ;
;***********************************************************************
; $P_Check_Match_Flags
;
; Function:  Check the mutch_flags and make the exit code and set the
;            result buffer
;
;           Check for types in this order:
;               Complex
;               Date
;               Time
;               Drive
;               Filespec
;               Quoted String
;               Simple String
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:       $P_Value, P$_SValue, $P_Simple_String, $P_Date_Format
;            $P_Time_Format, $P_Complex_Format, $P_File_Foemat
;	     $P_Drive_Format
;
; Note:
;
;	       IBMDOS60 - WRA - 01/14/93 - Added preprocessor logic so
;					     that a JMP could be SHORT
;					     for most cases.
;***********************************************************************
$P_Check_Match_Flags proc		 ;
        mov     psdata_seg:$P_err_flag,$P_NULL ;AN033;AC034;; clear filespec error flag.
	push	ax			 ;
	mov	ax,es:[bx].$P_Match_Flag  ; load match flag(16bit) to ax

        or      ax,ax                   ;AC035; test ax for zero
	jne	$P_Mat			 ; (tm12)

	push	ax			 ; (tm12)
	push	bx			 ; (tm12)
	push	dx			 ; (tm12)
	push	di			 ; (tm12)
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034; (tm12)
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR ($P_String and 0FFh))
else
	mov	ah,$P_No_Tag		 ; (tm12)
	mov	al,$P_String		 ; (tm12)
endif
	call	$P_Fill_Result		 ; (tm12)
	pop	di			 ; (tm12)
	pop	dx			 ; (tm12)
	pop	bx			 ; (tm12)
	pop	ax			 ; (tm12)
        jmp     short $P_Bridge         ;AC035; (tm12)

$P_Mat: 				 ; (tm12)

IF	CmpxSW				 ;(Check if complex item is supported)
	test	ax,$P_Cmpx_S		 ; Complex string
	je	$P_Match01		 ;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_Complex_Format	 ; do process
        cmp     psdata_seg:$P_RC,$P_Syntax ;AC034; if error, examine the next type
	jne	$P_Bridge		 ;

$P_Match01:				 ;
ENDIF					 ;(of CmpxSW)
IF	DateSW				 ;(Check if date format is supported)
	test	ax,$P_Date_S		 ; Date string
	je	$P_Match02		 ;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_Date_Format		 ; do process
        cmp     psdata_seg:$P_RC,$P_Syntax ;AC034; if error, examine the next type
	jne	$P_Bridge		 ;

$P_Match02:				 ;
ENDIF					 ;(of DateSW)
IF	TimeSW				 ;(Check if time format is supported)
	test	ax,$P_Time_S		 ; Time string
	je	$P_Match03		 ;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_Time_Format		 ; do process
        cmp     psdata_seg:$P_RC,$P_Syntax ;AC034; if error, examine the next type
	jne	$P_Bridge		 ; (tm09)

ENDIF					 ;(of TimeSW)  (tm04)
        jmp     short $P_Match03        ;AN025; (tm09)

$P_Bridge:
IF	DrvSW							 ;IBMDOS60;
	jmp	$P_Match_Exit		; (tm02)		 ;IBMDOS60;
ELSE								 ;IBMDOS60;
	jmp	SHORT $P_Match_Exit	;			 ;IBMDOS60;
ENDIF								 ;IBMDOS60;

$P_Match03:				 ;
IF	NumSW				 ;(Check if numeric value is supported)
	test	ax,$P_Num_Val		 ; Numeric value
	je	$P_Match04		 ;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_Value		 ; do process
        cmp     psdata_seg:$P_RC,$P_Syntax ;AC034; if error, examine the next type
	jne	$P_Match_Exit		 ;

$P_Match04:				 ;
	test	ax,$P_SNUM_Val		 ; Signed numeric value
	je	$P_Match05		 ;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_SValue		 ; do process
        cmp     psdata_seg:$P_RC,$P_Syntax ;AC034; if error, examine the next type
	jne	$P_Match_Exit		 ;

$P_Match05:				 ;
ENDIF					 ;(of NumSW)
IF	DrvSW				 ;(Check if drive only is supported)
	test	ax,$P_Drv_Only		 ; Drive only
	je	$P_Match06		 ;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_File_Format		 ; 1st, call file format
	call	$P_Drive_Format 	 ; check drive format, next
        cmp     psdata_seg:$P_RC,$P_Syntax ;AC034; if error, examinee the next type
	jne	$P_Match_Exit		 ;

$P_Match06:				 ;
ENDIF					 ;(of DrvSW)
IF	FileSW				 ;(Check if file spec is supported)
	test	ax,$P_File_Spc		 ; File spec
	je	$P_Match07		 ;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_File_Format		 ; do process
        cmp     psdata_seg:$P_RC,$P_Syntax ;AC034; if error, examine the next type
	jne	$P_Match_Exit		 ;

$P_Match07:				 ;
ENDIF					 ;(of FileSW)
IF	QusSW				 ;(Check if quoted string is supported)
	test	ax,$P_Qu_String 	 ; Quoted string
	je	$P_Match08		 ;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_Quoted_Format	 ; do process
        cmp     psdata_seg:$P_RC,$P_Syntax ;AC034; if error, examine the next type
	jne	$P_Match_Exit		 ;

$P_Match08:				 ;
ENDIF					 ;(of QusSW)
	test	ax,$P_Simple_S		 ; Simple string
        je      SHORT $P_Match_Exit     ;AC000;

        mov     psdata_seg:$P_RC,$P_No_Error ;AC034; assume no error
	call	$P_Simple_String	 ; do process
$P_Match09:				 ;
$P_Match_Exit:				 ;
        cmp     psdata_seg:$P_err_flag,$P_error_filespec ;AC034; bad filespec ?
        jne     $P_Match2_Exit          ;AN033; no, continue
        cmp     psdata_seg:$P_RC,$P_No_Error ;AN033;AC034;; check for other errors ?
        jne     $P_Match2_Exit          ;AN033; no, continue
        mov     psdata_seg:$P_RC,$P_Syntax ;AN033;AC034;; set error flag
$P_Match2_Exit:                         ;AN033;
	pop	ax			 ;
	ret				 ;
$P_Check_Match_Flags endp		 ;
PAGE					 ;
;***********************************************************************
; $P_Remove_Colon;
;
; Function: Remove colon at end
;
; Input:    psdata_seg:SI points to string buffer to be examineed
;
; Output:   None
;
; Use:  $P_Chk_DBCS
;***********************************************************************
$P_Remove_Colon proc			 ;
	push	ax			 ;
	push	si			 ;
$P_RCOL_Loop:				 ;
	mov	al,psdata_seg:[si]	 ; get character
	or	al,al			 ; end of string ?
	je	$P_RCOL_Exit		 ; if yes, just exit

	cmp	al,$P_Colon		 ; is it colon ?
	jne	$P_RCOL00		 ;

	cmp	byte ptr psdata_seg:[si+byte],$P_NULL  ; if so, next is NULL ?
	jne	$P_RCOL00		 ; no, then next char

	mov	byte ptr psdata_seg:[si],$P_NULL  ; yes, remove colon
	jmp	short $P_RCOL_Exit	 ; and exit.

$P_RCOL00:				 ;
	call	$P_Chk_DBCS		 ; if not colon, then check if
	jnc	$P_RCOL01		 ; DBCS leading byte.

	inc	si			 ; if yes, skip trailing byte
$P_RCOL01:				 ;
	inc	si			 ; si points to next byte
	jmp	short $P_RCOL_Loop	 ; loop until NULL encountered

$P_RCOL_Exit:				 ;
	pop	si			 ;
	pop	ax			 ;
	ret				 ;
$P_Remove_Colon endp			 ;
PAGE					 ;
;***********************************************************************
; $P_Do_CAPS_String;
;
; Function: Perform capitalization along with the file case map table
;           or character case map table.
;
; Input:    AL = 2 : Use character table
;           AL = 4 : Use file table
;           psdata_seg:SI points to string buffer to be capitalized
;
; Output:   None
;
; Use:  $P_Do_CAPS_Char, $P_Chk_DBCS
;***********************************************************************
$P_Do_CAPS_String proc			 ;
	push	si			 ;
	push	dx			 ;
	mov	dl,al			 ; save info id

$P_DCS_Loop:				 ;
	mov	al,psdata_seg:[si]	 ; load charater and
	call	$P_Chk_DBCS		 ; check if DBCS leading byte
	jc	$P_DCS00		 ; if yes, do not need CAPS

	or	al,al			 ; end of string ?
	je	$P_DCS_Exit		 ; then exit.

	call	$P_Do_CAPS_Char 	 ; Here a SBCS char need to be CAPS
	mov	psdata_seg:[si],al	 ; stored upper case char to buffer
	jmp	short $P_DCS01		 ; process nexit
$P_DCS00:				 ;
	inc	si			 ; skip DBCS leading and trailing byte
$P_DCS01:				 ;
	inc	si			 ; si point to next byte
	jmp	short $P_DCS_Loop	 ; loop until NULL encountered
$P_DCS_Exit:				 ;
	pop	dx			 ;
	pop	si			 ;
	ret				 ;
$P_Do_CAPS_String endp			 ;
PAGE					 ;
;***********************************************************************
; $P_Do_CAPS_Char;
;
; Function: Perform capitalization along with the file case map table
;           or character case map table.
;
; Input:    DL = 2 : Use character table
;           DL = 4 : Use file table
;           AL = character to be capitalized
;
; Output:   None
;
; Use:  INT 21h /w AH=65h
;***********************************************************************
$P_Do_CAPS_Char proc			 ;
	cmp	al,$P_ASCII80		 ; need upper case table ?
	jae	$P_DCC_Go		 ;

	cmp	al,"a"			 ; if no,
	jb	$P_CAPS_Ret		 ;   check if  "a" <= AL <= "z"

	cmp	al,"z"			 ;
	ja	$P_CAPS_Ret		 ;   if yes, make CAPS

	and	al,$P_Make_Upper	 ;   else do nothing.
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte. Do the RET here.
;-------------------------------------
	ret
else
	jmp	short $P_CAPS_Ret	 ;
endif

$P_DCC_Go:				 ;
	push	bx			 ;
	push	es			 ;
	push	di			 ;
IF	CAPSW				 ;(Check if uppercase conversion is supported)
        lea     di,psdata_seg:$P_File_CAP_Ptr ;AC034;
	cmp	dl,$P_DOSTBL_File	 ; Use file CAPS table ?
	je	$P_DCC00		 ;

ENDIF					 ;(of CAPSW)
        lea     di,psdata_seg:$P_Char_CAP_Ptr ;AC034; or use char CAPS table ?
$P_DCC00:				 ;
	cmp	psdata_seg:[di],dl	 ; already got table address ?
	je	$P_DCC01		 ; if no,

;In this next section, ES will be used to pass a 5 byte workarea to INT 21h,
; the GET COUNTYRY INFO call.  This usage of ES is required by the function
; call, regardless of what base register is currently be defined as PSDATA_SEG.
;BASESW EQU 0 means that ES is the psdata_seg reg.

IFDEF BASESW                            ;AN037; If BASESW has been defined, and
  IFE BASESW                            ;AN037; If ES is psdata base
        push    PSDATA_SEG              ;AN037; save current base reg
  ENDIF                                 ;AN037;
ENDIF                                   ;AN037;

	push	ax			 ; get CAPS table thru DOS call
	push	cx			 ;
	push	dx			 ;


        push    PSDATA_SEG              ;AC036; pass current base seg into
                                        ;(Note: this used to push CS.  BUG...
	pop	es			 ;   ES reg, required for
                                        ;get extended country information
ifdef __TONYI__PARSE__
;-------------------------------------
; Save 2 bytes....
;-------------------------------------
	xchg	ax,dx	; AL == DL	;AN000; upper case table
	mov	ah,$P_DOS_Get_TBL	;AN000; get extended CDI
	mov	bx,$P_DOSTBL_Def	;AN000; get active CON
	mov	cx,$P_DOSTBL_BL 	;AN000; buffer length
	mov	dx,bx			;AN000; get for default code page
else
	mov	ah,$P_DOS_Get_TBL	 ; get extended CDI
	mov	al,dl			 ; upper case table
	mov	bx,$P_DOSTBL_Def	 ; get active CON
	mov	cx,$P_DOSTBL_BL 	 ; buffer length
	mov	dx,$P_DOSTBL_Def	 ; get for default code page
                                        ;DI already set to point to buffer
endif
	int	21h			 ; es:di point to buffer that
                                        ;now has been filled in with info
	pop	dx			 ;
	pop	cx			 ;
	pop	ax			 ;
IFDEF BASESW                            ;AN037; If BASESW has been defined, and
  IFE BASESW                            ;AN037; If ES is psdata base
        pop     PSDATA_SEG              ;AN037; restore current base reg
  ENDIF                                 ;AN037;
ENDIF                                   ;AN037;
$P_DCC01:				 ;

;In this next section, ES will be used as the base of the XLAT table, provided
; by the previous GET COUNTRY INFO DOS call.  This usage of ES is made
; regardless of which base reg is currently the PSDATA_SEG reg.

IFDEF BASESW                            ;AN037; If BASESW has been defined, and
  IFE BASESW                            ;AN037; If ES is psdata base
        push    PSDATA_SEG              ;AN037; save current base reg
  ENDIF                                 ;AN037;
ENDIF                                   ;AN037;
ifdef __TONYI__PARSE__
;-------------------------------------
; Save 4 or 5 bytes....
;-------------------------------------
	.errnz	($P_DOS_TBL_Seg - $P_DOS_TBL_Off - 2)
	les	bx, dword ptr psdata_seg:[di+$P_DOS_TBL_Off]
else
	mov	bx,psdata_seg:[di+$P_DOS_TBL_Off]  ; get offset of table
	mov	es,psdata_seg:[di+$P_DOS_TBL_Seg]  ; get segment of table
endif
        inc     bx                      ;AC035; add '2' to
        inc     bx                      ;AC035;  BX reg
					 ; skip length field
	sub	al,$P_ASCII80		 ; make char to index
	xlat	es:[bx] 		 ; perform case map

IFDEF BASESW                            ;AN037; If BASESW has been defined, and
  IFE BASESW                            ;AN037; If ES is psdata base
        pop     PSDATA_SEG              ;AN037; restore current base reg
  ENDIF                                 ;AN037;
ENDIF                                   ;AN037;
	pop	di			 ;
	pop	es			 ;
	pop	bx			 ;
$P_CAPS_Ret:				 ;
	ret				 ;
$P_Do_CAPS_Char endp			 ;
PAGE					 ;
;***********************************************************************
IF	NumSW				 ;(Check if numeric value is supported)
; $P_Value / $P_SValue
;
; Function:  Make 32bit value from psdata_seg:SI and see value list
;            and make result buffer.
;            $P_SValue is an entry point for the signed value
;            and this will simply call $P_Value after the handling
;            of the sign character, "+" or "-"
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:  $P_Fill_Result, $P_Check_OVF
;
; Vars: $P_RC(W), $P_Flags(RW)
;***********************************************************************
$P_SValue proc				 ; when signed value here
	push	ax			 ;
        or      psdata_seg:$P_Flags2,$P_Signed      ;AC034; indicate a signed numeric
        and     psdata_seg:$P_Flags2,0ffh-$P_Neg  ;AC034; assume positive value
	mov	al,psdata_seg:[si]	 ; get sign
	cmp	al,$P_Plus		 ; "+" ?
	je	$P_SVal00		 ;

	cmp	al,$P_Minus		 ; "-" ?
	jne	$P_Sval01		 ; else

        or      psdata_seg:$P_Flags2,$P_Neg ;AC034; set this is negative value
$P_SVal00:				 ;
	inc	si			 ; skip sign char
$P_Sval01:				 ;
	call	$P_Value		 ; and process value
	pop	ax			 ;
	ret				 ;
$P_SValue endp				 ;
;***********************************************************************
$P_Value proc				 ;
	push	ax			 ;
	push	cx			 ;
	push	dx			 ;
	push	si			 ;
	xor	cx,cx			 ; cx = higher 16 bits
	xor	dx,dx			 ; dx = lower 16 bits
	push	bx			 ; save control pointer
$P_Value_Loop:				 ;
	mov	al,psdata_seg:[si]	 ; get character
	or	al,al			 ; end of line ?
	je	$P_Value00		 ;

	call	$P_0099 		 ; make asc(0..9) to bin(0..9)
	jc	$P_Value_Err0		 ;

	xor	ah,ah			 ;
	mov	bp,ax			 ; save binary number
ifdef __TONYI__PARSE__
;-------------------------------------
; Factor out common code...
;-------------------------------------
	call	DXCXtwiddle
else
	shl	dx,1			 ; to have 2*x
	rcl	cx,1			 ; shift left w/ carry
	call	$P_Check_OVF		 ; Overflow occurred ?
	jc	$P_Value_Err0		 ; then error, exit
endif

	mov	bx,dx			 ; save low(2*x)
	mov	ax,cx			 ; save high(2*x)
ifdef __TONYI__PARSE__
;-------------------------------------
; Factor out common code...
;-------------------------------------
	call	DXCXtwiddle
else
	shl	dx,1			 ; to have 4*x
	rcl	cx,1			 ; shift left w/ carry
	call	$P_Check_OVF		 ; Overflow occurred ?
	jc	$P_Value_Err0		 ; then error, exit
endif

ifdef __TONYI__PARSE__
;-------------------------------------
; Factor out common code...
;-------------------------------------
	call	DXCXtwiddle
else
	shl	dx,1			 ; to have 8*x
	rcl	cx,1			 ; shift left w/ carry
	call	$P_Check_OVF		 ; Overflow occurred ?
	jc	$P_Value_Err0		 ; then error, exit
endif

	add	dx,bx			 ; now have 10*x
	adc	cx,ax			 ; 32bit ADD
ifdef __TONYI__PARSE__
;-------------------------------------
; Factor out common code...
;-------------------------------------
	call	OVFLOWtwiddle
else
	call	$P_Check_OVF		 ; Overflow occurred ?
	jc	$P_Value_Err0		 ; then error, exit
endif

	add	dx,bp			 ; Add the current one degree decimal
	adc	cx,0			 ; if carry, add 1 to high 16bit
ifdef __TONYI__PARSE__
;-------------------------------------
; Factor out common code...
;-------------------------------------
	call	OVFLOWtwiddle
else
	call	$P_Check_OVF		 ; Overflow occurred ?
	jc	$P_Value_Err0		 ; then error, exit
endif

	inc	si			 ; update pointer
	jmp	short $P_Value_Loop	 ; loop until NULL encountered


ifdef __TONYI__PARSE__
;-------------------------------------
; Factor out common code...
;-------------------------------------
DXCXtwiddle proc near
	shl	dx,1			;AN000; to have 2*x
	rcl	cx,1			;AN000; shift left w/ carry
OVFLOWtwiddle label near
	call	$P_Check_OVF		;AN000; Overflow occurred ?
	jc	OopsTwiddle
	ret
OopsTwiddle:
	inc	sp	; Eat the return address
	inc	sp
;
; NOTE:  This falls into '$P_Value_Err0'
;
DXCXtwiddle endp
endif
;
$P_Value_Err0:				 ;
	pop	bx			 ;
	jmp	$P_Value_Err		 ; Bridge
;
$P_Value00:				 ;
	pop	bx			 ; restore control pointer
        test    psdata_seg:$P_Flags2,$P_Neg ;AC034; here cx,dx = 32bit value
	je	$P_Value01		 ; was it negative ?

	not	cx			 ; +
	not	dx			 ; |- Make 2's complement
	add	dx,1			 ; |
	adc	cx,0			 ; +
$P_Value01:				 ; / nval =0
	mov	si,es:[bx].$P_Value_List  ; si points to value list
	mov	al,es:[si]		 ; get nval
	cmp	al,$P_nval_None 	 ; no value list ?
	jne	$P_Value02		 ;

ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_Number)
else
	mov	al,$P_Number		 ; Set type
	mov	ah,$P_No_Tag		 ; No ITEM_TAG set
endif
	jmp	$P_Value_Exit		 ;

$P_Value02:				 ; / nval = 1
IF	Val1SW				 ;(Check if value list id #1 is supported)
	inc	si			 ;
	mov	al,es:[si]		 ; al = number of range
	cmp	al,$P_No_nrng		 ; (tm07)
	je	$P_Value03		 ; (tm07)

	inc	si			 ; si points to 1st item_tag
$P_Val02_Loop:				 ;
        test    psdata_seg:$P_Flags2,$P_Signed ;AC034;
	jne	$P_Val02_Sign		 ;

	cmp	cx,es:[si+$P_Val_XH]	 ; comp cx with XH
	jb	$P_Val02_Next		 ;

	ja	$P_Val_In		 ;

	cmp	dx,es:[si+$P_Val_XL]	 ; comp dx with XL
	jb	$P_Val02_Next		 ;

$P_Val_In:				 ;
	cmp	cx,es:[si+$P_Val_YH]	 ; comp cx with YH (tm01)
	ja	$P_Val02_Next		 ;

	jb	$P_Val_Found		 ;

	cmp	dx,es:[si+$P_Val_YL]	 ; comp dx with YL
	ja	$P_Val02_Next		 ;

	jmp	short $P_Val_Found	 ;

$P_Val02_Sign:				 ;
	cmp	cx,es:[si+$P_Val_XH]	 ; comp cx with XH
	jl	$P_Val02_Next		 ;

	jg	$P_SVal_In		 ;

	cmp	dx,es:[si+$P_Val_XL]	 ; comp dx with XL
	jl	$P_Val02_Next		 ;

$P_SVal_In:				 ;
	cmp	cx,es:[si+$P_Val_YH]	 ; comp cx with YH
	jg	$P_Val02_Next		 ;

	jl	$P_Val_Found		 ;

	cmp	dx,es:[si+$P_Val_YL]	 ; comp dx with YL
	jg	$P_Val02_Next		 ;

	jmp	short $P_Val_Found	 ;

$P_Val02_Next:				 ;
	add	si,$P_Len_Range 	 ;
	dec	al			 ; loop nrng times in AL
	jne	$P_Val02_Loop		 ;
                                        ; / Not found
        mov     psdata_seg:$P_RC,$P_Out_of_Range ;AC034;
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_Number)
else
	mov	al,$P_Number		 ;
	mov	ah,$P_No_Tag		 ; No ITEM_TAG set
endif
	jmp	short $P_Value_Exit	 ;

ENDIF					 ;(of Val1SW)
IF	Val1SW+Val2SW			 ;(Check if value list id #1 or #2 is supported)
$P_Val_Found:				 ;
	mov	al,$P_Number		 ;
	mov	ah,es:[si]		 ; found ITEM_TAG set
	jmp	short $P_Value_Exit	 ;

ENDIF					 ;(of Val1SW+Val2SW)
$P_Value03:				 ; / nval = 2
IF	Val2SW				 ;(Check if value list id #2 is supported)
	mov	ah,$P_Len_Range 	 ;
	mul	ah			 ;  Skip nrng field
	inc	ax			 ;
	add	si,ax			 ; si points to nnval
	mov	al,es:[si]		 ; get nnval
	inc	si			 ; si points to 1st item_tag
$P_Val03_Loop:				 ;
	cmp	cx,es:[si+$P_Val_XH]	 ; comp cx with XH
	jne	$P_Val03_Next		 ;

	cmp	dx,es:[si+$P_Val_XL]	 ; comp dx with XL
	je	$P_Val_Found		 ;

$P_Val03_Next:				 ;
	add	si,$P_Len_Value 	 ; points to next value choice
	dec	al			 ; loop nval times in AL
	jne	$P_Val03_Loop		 ;
					 ; / Not found
        mov     psdata_seg:$P_RC,$P_Not_in_Val ;AC034;
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_Number)
else
	mov	al,$P_Number		 ;
	mov	ah,$P_No_Tag		 ; No ITEM_TAG set
endif
	jmp	short $P_Value_Exit	 ;

ENDIF					 ;(of Val2SW)
$P_Value04:				 ; / nval = 3 or else
$P_Value_Err:				 ;
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034;
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_String)
else
	mov	al,$P_String		 ; Set type
	mov	ah,$P_No_Tag		 ; No ITEM_TAG set
endif
$P_Value_Exit:				 ;
	call	$P_Fill_Result		 ;
	pop	si			 ;
	pop	dx			 ;
	pop	cx			 ;
	pop	ax			 ;
	ret				 ;
$P_Value endp				 ;
PAGE					 ;
;***********************************************************************
; $P_Check_OVF
;
; Function:  Check if overflow is occurred with consideration of
;            signed or un-signed numeric value
;
; Input:     Flag register
;
; Output:    CY = 1  :  Overflow
;
; Vars:     $P_Flags(R)
;***********************************************************************
$P_Check_OVF proc			 ;
	pushf				 ;
        test    psdata_seg:$P_Flags2,$P_Neg ;AC034; is it negative value ?
	jne	$P_COVF 		 ; if no, check overflow

	popf				 ; by the CY bit
	ret				 ;

$P_COVF:				 ;
	popf				 ; else,
	jo	$P_COVF00		 ; check overflow by the OF

	clc				 ; indicate it with CY bit
	ret				 ; CY=0 means no overflow

$P_COVF00:				 ;
	stc				 ; and CY=1 means overflow
	ret				 ;
$P_Check_OVF endp			 ;
ENDIF					 ;(of FarSW)
;***********************************************************************
; $P_0099;
;
; Function:  Make ASCII 0-9 to Binary 0-9
;
; Input:     AL = character code
;
; Output:    CY = 1 : AL is not number
;            CY = 0 : AL contains binary value
;***********************************************************************
$P_0099 proc				 ;
	cmp	al,"0"			 ;
	jb	$P_0099Err		 ;  must be 0 =< al =< 9

	cmp	al,"9"			 ;
	ja	$P_0099Err		 ;  must be 0 =< al =< 9

	sub	al,"0"			 ; make char -> bin
	clc				 ; indicate no error
	ret				 ;

$P_0099Err:				 ;
	stc				 ; indicate error
	ret				 ;
$P_0099 endp				 ;
PAGE					 ;
;***********************************************************************
; $P_Simple_String
;
; Function:  See value list for the simple string
;            and make result buffer.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:  $P_Fill_Result, $P_String_Comp
;
; Vars: $P_RC(W)
;***********************************************************************
$P_Simple_String proc			 ;
	push	ax			 ;
	push	bx			 ;
	push	dx			 ;
	push	di			 ;
	mov	di,es:[bx].$P_Value_List  ; di points to value list
	mov	al,es:[di]		 ; get nval
	or	al,al			 ; no value list ?
	jne	$P_Sim00		 ; then

	mov	ah,$P_No_Tag		 ; No ITEM_TAG set
	jmp	short $P_Sim_Exit	 ; and set result buffer

$P_Sim00:				 ;
IF	Val3SW+KeySW			 ;(Check if keyword or value list id #3 is supported)
	cmp	al,$P_nval_String	 ; String choice list provided ?
	jne	$P_Sim01		 ; if no, syntax error

	inc	di			 ;
	mov	al,es:[di]		 ; al = nrng
	mov	ah,$P_Len_Range 	 ;
	mul	ah			 ;  Skip nrng field
	inc	ax			 ; ax = (nrng*9)+1
	add	di,ax			 ; di points to nnval
	mov	al,es:[di]		 ; get nnval
	mov	ah,$P_Len_Value 	 ;
	mul	ah			 ; Skip nnval field
	inc	ax			 ; ax = (nnval*5)+1
	add	di,ax			 ; di points to nstrval
	mov	al,es:[di]		 ; get nstrval
        inc     di                      ;AC035; add '2' to
        inc     di                      ;AC035;  DI reg
					 ; di points to 1st string in list
$P_Sim_Loop:				 ;
	mov	bp,es:[di]		 ; get string pointer
	call	$P_String_Comp		 ; compare it with operand
	jnc	$P_Sim_Found		 ; found on list ?

	add	di,$P_Len_String	 ; if no, point to next choice
	dec	al			 ; loop nstval times in AL
	jne	$P_Sim_Loop		 ;
					 ; / Not found
        mov     psdata_seg:$P_RC,$P_Not_In_Str ;AC034;
	mov	ah,$P_No_Tag		 ; No ITEM_TAG set
	jmp	short $P_Sim_Exit	 ;

$P_Sim_Found:				 ;
	mov	ah,es:[di-1]		 ; set item_tag
	mov	al,$P_List_Idx		 ;
	mov	dx,es:[di]		 ; get address of STRING
	jmp	short $P_Sim_Exit0	 ;
ENDIF					 ;(of Val3SW+KeySW)
$P_Sim01:				 ;
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034;
	mov	ah,$P_No_Tag		 ; No ITEM_TAG set
$P_Sim_Exit:				 ;
	mov	al,$P_String		 ; Set type
$P_Sim_Exit0:				 ;
	call	$P_Fill_Result		 ;
	pop	di			 ;
	pop	dx			 ;
	pop	bx			 ;
	pop	ax			 ;
	ret				 ;
$P_Simple_String endp			 ;
PAGE					 ;
;***********************************************************************
; $P_String_Comp:
;
; Function:  Compare two string
;
; Input:     psdata_seg:SI -> 1st string
;            ES:BP -> 2nd string  (Must be upper case)
;            ES:BX -> CONTROL block
;
; Output:    CY = 1 if not match
;
; Use:  $P_Chk_DBCS, $P_Do_CAPS_Char
;
; Vars: $P_KEYor_SW_Ptr(W), $P_Flags(R). $P_KEYorSW_Ptr
;***********************************************************************
$P_String_Comp proc			 ;
	push	ax			 ;
	push	bp			 ;
	push	dx			 ;
	push	si			 ;
	mov	dl,$P_DOSTBL_Char	 ; use character case map table
$P_SCOM_Loop:				 ;
	mov	al,psdata_seg:[si]	 ; get command character
	call	$P_Chk_DBCS		 ; DBCS ?
	jc	$P_SCOM00		 ; yes,DBCS

	call	$P_Do_CAPS_Char 	 ; else, upper case map before comparison
IF	KeySW+SwSW			 ;(Check if keyword or switch is supported)
        test    psdata_seg:$P_Flags2,$P_Key_Cmp ;AC034; keyword search ?
	je	$P_SCOM04		 ;

	cmp	al,$P_Keyword		 ; "=" is delimiter
	jne	$P_SCOM03		 ;IF "=" on command line AND  (bp+1=> char after the "=" in synonym list)

        cmp     byte ptr es:[bp+1],$P_NULL ;AN021;   at end of keyword string in the control block THEN
        jne     $P_SCOM_DIFFER          ;AN021;

	jmp	short $P_SCOM05 	 ;   keyword found in synonym list

$P_SCOM04:				 ;
        test    psdata_seg:$P_Flags2,$P_SW_Cmp ;AC034; switch search ?
	je	$P_SCOM03		 ;

	cmp	al,$P_Colon		 ; ":" is delimiter, at end of switch on command line
	jne	$P_SCOM03		 ; continue compares

        cmp     byte ptr es:[bp],$P_NULL ;AN021; IF at end of switch on command AND
        jne     $P_SCOM_DIFFER          ;AN021;   at end of switch string in the control block THEN

$P_SCOM05:				 ;   found a match
	inc	si			 ; si points to just after "=" or ":"
	jmp	short $P_SCOM_Same	 ; exit

$P_SCOM03:				 ;
ENDIF					 ;(of KeySW+SwSW)
	cmp	al,es:[bp]		 ; compare operand w/ a synonym
	jne	$P_SCOM_Differ0 	 ; if different, check ignore colon option

	or	al,al			 ; end of line
	je	$P_SCOM_Same		 ; if so, exit

	inc	si			 ; update operand pointer
	inc	bp			 ;	      and synonym pointer
	jmp	short $P_SCOM01 	 ; loop until NULL or "=" or ":" found in case

$P_SCOM00:				 ; Here al is DBCS leading byte
	cmp	al,es:[bp]		 ; compare leading byte
	jne	$P_SCOM_Differ		 ; if not match, say different

	inc	si			 ; else, load next byte
	mov	al,psdata_seg:[si]	 ; and
	inc	bp			 ;
	cmp	al,es:[bp]		 ; compare 2nd byte
	jne	$P_SCOM_Differ		 ; if not match, say different, too

	inc	si			 ; else update operand pointer
	inc	bp			 ;		   and synonym pointer
$P_SCOM01:				 ;
	jmp	short $P_SCOM_Loop	 ; loop until NULL or "=" or "/" found in case

$P_SCOM_Differ0:			 ;

IF	SwSW				 ;(tm10)
        test    psdata_seg:$P_Flags2,$P_SW ;AC034;(tm10)
	je	$P_not_applicable	 ;(tm10)

	test	es:[bx].$P_Function_Flag,$P_colon_is_not_necessary  ;(tm10)
	je	$P_not_applicable	 ;(tm10)

	cmp	byte ptr es:[bp],$P_NULL  ;(tm10)
        je      $P_SCOM_Same            ;AN025;(tm10)

$P_not_applicable:			 ;(tm10)
ENDIF					 ;(tm10)

	test	es:[bx].$P_Match_Flag,$P_Ig_Colon  ; ignore colon option specified ?
	je	$P_SCOM_Differ		 ; if no, say different.

	cmp	al,$P_Colon		 ; End up with ":" and
	jne	$P_SCOM02		 ;    subseqently

	cmp	byte ptr es:[bp],$P_NULL  ;	  NULL ?
	jne	$P_SCOM_Differ		 ; if no, say different

	jmp	short $p_SCOM_Same	 ; else, say same

$P_SCOM02:				 ;
	cmp	al,$P_NULL		 ; end up NULL and :
	jne	$P_SCOM_Differ		 ;

	cmp	byte ptr es:[bp],$P_Colon  ; if no, say different
	je	$p_SCOM_Same		 ; else, say same

$P_SCOM_Differ: 			 ;
	stc				 ; indicate not found
	jmp	short $P_SCOM_Exit	 ;

$P_SCOM_Same:				 ;
        mov     psdata_seg:$P_KEYorSW_Ptr,si ;AC034; for later use by keyword or switch
	clc				 ; indicate found
$P_SCOM_Exit:				 ;
	pop	si			 ;
	pop	dx			 ;
	pop	bp			 ;
	pop	ax			 ;
	ret				 ;
$P_String_Comp endp			 ;
PAGE					 ;
;***********************************************************************
IF	DateSW				 ;(Check if date format is supported)
; $P_Date_Format
;
; Function:  Convert a date string to DOS date format for int 21h
;            with format validation.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:  $P_Fill_Result, $P_Set_CDI, $P_Get_DecNum
;
; Vars: $P_RC(W), $P_1st_Val(RW), $P_2nd_Val(RW), $P_3rd_Val(RW)
;***********************************************************************
$P_Date_Format proc			 ;
	push	ax			 ;
	push	cx			 ;
	push	dx			 ;
	push	si			 ;
	push	bx			 ;
	push	si			 ;
	call	$P_Set_CDI		 ; set country dependent information before process
;                                       note: the country info is still needed
;                                       to determine the order of the fields,
;                                       but the separator char is no longer used.
	pop	si			 ;
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a few bytes....
;-------------------------------------
	xor	ax,ax
	mov	psdata_seg:$P_1st_Val,ax ;AC034; set initial value
	mov	psdata_seg:$P_2nd_Val,ax ;AC034; set initial value
	mov	psdata_seg:$P_3rd_Val,ax ;AC034; set initial value
else
        mov     psdata_seg:$P_1st_Val,0 ;AC034; set initial value
        mov     psdata_seg:$P_2nd_Val,0 ;AC034; set initial value
        mov     psdata_seg:$P_3rd_Val,0 ;AC034; set initial value
endif
	call	$P_Get_DecNum		 ; get 1st number
	jc	$P_DateF_Err0		 ;-----------------------+

        mov     psdata_seg:$P_1st_Val,ax ;AC034;              |
	or	bl,bl			 ; end of line ?	 |
	je	$P_DateF_YMD		 ;			 |

	call	$P_Get_DecNum		 ; get 2nd number	 |
	jc	$P_DateF_Error		 ;			 |

        mov     psdata_seg:$P_2nd_Val,ax ;AC034;              |
	or	bl,bl			 ; end of line ?	 |
	je	$P_DateF_YMD		 ;			 |

	call	$P_Get_DecNum		 ; get 3rd number	 |
$P_DateF_Err0:				 ; Bridge    <-----------+
	jc	$P_DateF_Error		 ;

        mov     psdata_seg:$P_3rd_Val,ax ;AC034;
	or	bl,bl			 ; end of line ?
	jne	$P_DateF_Error		 ;

$P_DateF_YMD:				 ;
        mov     bx,psdata_seg:$P_Country_Info.$P_CDI_DateF ;AC034; get date format
	cmp	bx,$P_Date_YMD		 ;
	je	$P_DateF00		 ;

        mov     ax,psdata_seg:$P_1st_Val ;AC034;
	or	ah,ah			 ;
	jne	$P_DateF_Error		 ;

	mov	cl,al			 ; set month
        mov     ax,psdata_seg:$P_2nd_Val ;AC034;
	or	ah,ah			 ; if overflow, error.
	jne	$P_DateF_Error		 ;

	mov	ch,al			 ; set date
        mov     dx,psdata_seg:$P_3rd_Val ;AC034; set year
	cmp	bx,$P_Date_DMY		 ; from here format = MDY
	jne	$P_DateF01		 ; if it is DMY

	xchg	ch,cl			 ;  then swap M <-> D
$P_DateF01:				 ;
	jmp	short $P_DateF02	 ;

$P_DateF00:				 ; / here format = YMD
        mov     dx,psdata_seg:$P_1st_Val ;AC034; set year
        mov     ax,psdata_seg:$P_2nd_Val ;AC034;
	or	ah,ah			 ; if overflow, error
	jne	$P_DateF_Error		 ;

	mov	cl,al			 ; set month
        mov     ax,psdata_seg:$P_3rd_Val ;AC034;
	or	ah,ah			 ; if overflow, error
	jne	$P_DateF_Error		 ;

	mov	ch,al			 ; set date
$P_DateF02:				 ;
	cmp	dx,100			 ; year is less that 100 ?
	jae	$P_DateF03		 ;

	add	dx,1900 		 ; set year 19xx
$P_DateF03:				 ;
	pop	bx			 ; recover CONTROL block
	pop	si			 ; recover string pointer
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_Date_F)
else
	mov	ah,$P_No_Tag		 ; set
	mov	al,$P_Date_F		 ;     result
endif
	call	$P_Fill_Result		 ;	      buffer
	jmp	short $P_Date_Format_Exit  ;	   to Date

$P_DateF_Error: 			 ;
	pop	bx			 ; recover CONTROL block
	pop	si			 ; recover string pointer
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte....
;-------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_String)
else
	mov	ah,$P_No_Tag		 ; set
	mov	al,$P_String		 ;     result
endif
	call	$P_Fill_Result		 ;	      buffer  to string
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034; indicate syntax error
$P_Date_Format_Exit:			 ;
	pop	dx			 ;
	pop	cx			 ;
	pop	ax			 ;
	ret				 ;
$P_Date_Format endp			 ;
ENDIF					 ;(of DateSW)
PAGE					 ;
;***********************************************************************
IF	TimeSW+DateSW			 ;(Check if time or date format is supported)
; $P_Set_CDI:
;
; Function: Read CDI from DOS if it has not been read yet
;
; Input:    None
;
; Output:   psdata_seg:SI -> CDI
;
; Use:  INT 21h w/ AH = 38h
;***********************************************************************
$P_Set_CDI proc 			 ;
        lea     si,psdata_seg:$P_Country_Info ;AC034;
	cmp	psdata_seg:[si].$P_CDI_DateF,$P_NeedToBeRead  ; already read ?
ifdef __TONYI__PARSE__
;-------------------------------------
; Save 2 bytes. Flip the condition.
;-------------------------------------
	jne	$P_Set_CDI_Exit
else
	je	$P_Read_CDI		 ;

	jmp	short $P_Set_CDI_Exit	 ; then do nothing
endif

$P_Read_CDI:				 ; else read CDI thru DOS
	push	ds			 ;
	push	dx			 ;
	push	ax			 ;
        push    PSDATA_SEG              ;AC023;
	pop	ds			 ; set segment register
	mov	ax,$P_DOS_Get_CDI	 ; get country information
	mov	dx,si			 ; set offset of CDI in local data area
	int	21h			 ;
	pop	ax			 ;
	pop	dx			 ;
	pop	ds			 ;
$P_Set_CDI_Exit:			 ;
	ret				 ;
$P_Set_CDI endp 			 ;
PAGE					 ;
;***********************************************************************
; $P_Get_DecNum:
;
; Function:  Read a chcrater code from psdata_seg:SI until specified delimiter
;            or NULL encountered. And make a decimal number.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;
; Output:    BL = delimiter code or NULL
;            AX = Decimal number
;            SI advanced to the next number
;            CY = 1 : Syntax error, AL = Latest examineed number
;
; Use:  $P_0099
;***********************************************************************
$P_Get_DecNum proc			 ;
	push	cx			 ;
	push	dx			 ;
	xor	cx,cx			 ; cx will have final value
$P_GetNum_Loop: 			 ;
	mov	al,psdata_seg:[si]	 ; load character
	or	al,al			 ; end of line ?
	je	$P_GetNum00		 ; if yes, exit

        cmp     psdata_seg:$P_Got_Time,0 ;AC034; ;is this numeric in a time field?    ;AC023
	je	$P_Do_Date_Delims	 ;no, go check out Date delimiters  ;AC023

; Determine which delimiter(s) to check for.  Colon & period  or period only
        cmp     bl,$P_colon_period      ;AN032; ;Time
        jne     $P_Do_Time_Delim1       ;AN032; ;only check for period

        cmp     al,$P_Colon             ;AN032; ;Is this a valid delimiter ?
        je      $P_GetNum01             ;AN032; ;yes, exit

$P_Do_Time_Delim1:			 ;
        cmp     al,$P_Period            ;;AC032;;AC023;Is this a valid delimiter ?
        je      $P_GetNum01             ;AC023; yes, exit

        jmp     short $P_Neither_Delims ;AN023;

$P_Do_Date_Delims:			 ;
;Regardless of the date delimiter character specified in the country
;dependent information, check for the presence of any one of these
;three field delimiters: "-", "/", or ".".
        cmp     al,$P_Minus             ;AN020;is this a date delimiter character?
        je      $P_GetNum01             ;AN020;if yes, exit

        cmp     al,$P_Slash             ;AN020;is this a date delimiter character?
        je      $P_GetNum01             ;AN020;if yes, exit

        cmp     al,$P_Period            ;AN020;is this a date delimiter character?
	je	$P_GetNum01		 ; if yes, exit

$P_Neither_Delims:                      ;AN023;

	call	$P_0099 		 ; convert it to binary
	jc	$P_GetNum_Exit		 ; if error exit

	mov	ah,0			 ;
	xchg	ax,cx			 ;
	mov	dx,10			 ;
	mul	dx			 ; ax = ax * 10
	or	dx,dx			 ; overflow
	jne	$P_GetNum02		 ; then exit

	add	ax,cx			 ;
	jc	$P_GetNum_Exit		 ;

	xchg	ax,cx			 ;
	inc	si			 ;
	jmp	short $P_GetNum_Loop	 ;

$P_GetNum00:				 ;
	mov	bl,al			 ; set bl to NULL
ifdef __TONYI__PARSE__
;-------------------------------------
; Merge point to save a byte.
;-------------------------------------
CLC_JMP_merge:
endif
	clc				 ; indicate no error
	jmp	short $P_GetNum_Exit	 ;

$P_GetNum01:				 ;
	inc	si			 ; si points to next number
ifdef __TONYI__PARSE__
;------------------------------------
; Save a byte....
;------------------------------------
	jmp	short CLC_JMP_merge
else
	clc				 ; indicate no error
	jmp	short $P_GetNum_Exit	 ;
endif

$P_GetNum02:				 ;
	stc				 ; indicate error
$P_GetNum_Exit: 			 ;
ifdef __TONYI__PARSE__
;------------------------------------
; Save a byte....
;------------------------------------
	xchg	ax,cx	; AX==CX, CX==(don't care)
else
	mov	ax,cx			 ;return value
endif
	pop	dx			 ;
	pop	cx			 ;
	ret				 ;
$P_Get_DecNum endp			 ;
ENDIF					 ;(of TimeSW+DateSW)
PAGE					 ;
;***********************************************************************
IF	TimeSW				 ;(Check if time format is supported)
; $P_Time_Format
;
; Function:  Convert a time string to DOS time format for int 21h
;            with format validation.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:  $P_Fill_Result, $P_Set_CDI, $P_Get_DecNum, $P_Time_2412
;
; Vars: $P_RC(W), $P_Flags(R), $P_1st_Val(RW), $P_2nd_Val(RW)
;       $P_3rd_Val(RW), $P_4th_Val(RW)
;***********************************************************************
$P_Time_Format proc			 ;
	push	ax			 ;
	push	cx			 ;
	push	dx			 ;
	push	si			 ;
	push	bx			 ;
	push	si			 ;
	call	$P_Set_CDI		 ; Set country independent
                                        ; information before process
	test	byte ptr psdata_seg:[si].$P_CDI_TimeF,1  ; 24 hour system
	pop	si			 ;
	jne	$P_TimeF00		 ; if no, means 12 hour system

	call	$P_Time_2412		 ; this routine handle "am" "pm"
$P_TimeF00:				 ;
ifdef __TONYI__PARSE__
;------------------------------------
; Save a few bytes....
;------------------------------------
	xor	ax,ax
	mov	psdata_seg:$P_1st_Val,ax ;AC034; set initial value
	mov	psdata_seg:$P_2nd_Val,ax ;AC034; set initial value
	mov	psdata_seg:$P_3rd_Val,ax ;AC034; set initial value
	mov	psdata_seg:$P_4th_Val,ax ;AC034; set initial value
else
        mov     psdata_seg:$P_1st_Val,0 ;AC034; set initial value
        mov     psdata_seg:$P_2nd_Val,0 ;AC034; set initial value
        mov     psdata_seg:$P_3rd_Val,0 ;AC034; set initial value
        mov     psdata_seg:$P_4th_Val,0 ;AC034; set initial value
endif
        mov     psdata_seg:$P_Got_Time,1 ;AN023;AC034;; use time delimiter
        mov     bl,$P_colon_period      ;AN032; flag, indicates use of
                                        ; delimiters between hours,
                                        ;  minutes,seconds
	call	$P_Get_DecNum		 ; get 1st number
	jc	$P_TimeF_Err0		 ;

        mov     psdata_seg:$P_1st_Val,ax ;AC034;
	or	bl,bl			 ; end of line ?
	je	$P_TimeF_Rlt		 ;

	call	$P_Get_DecNum		 ; get 2nd number
        jc      $P_TimeF_Err0           ;AC038; if OK

        mov     psdata_seg:$P_2nd_Val,ax ;AC034;
	or	bl,bl			 ; end of line ?
	je	$P_TimeF_Rlt		 ;
        mov     bl,$P_period_only       ;AN032; flag, which to decimal separator
	call	$P_Get_DecNum		 ; get 3rd number
        jc      $P_TimeF_Err0           ;AC039; if problem, bridge to error

        mov     psdata_seg:$P_3rd_Val,ax ;AC034;
	or	bl,bl			 ; end of line ?
        jne     $P_Time_4               ;AN039; NOT END OF LINE,
                                        ;AN039;   GO TO 4TH NUMBER
        test    psdata_seg:$P_Flags1,$P_Time_Again ;AN039; HAS TIME PARSE
                                        ;AN039;    BEEN REPEATED?
        jnz     $P_TimeF_Rlt            ;AN039; yes, this is really
                                        ;AN039;   the end of line
                                        ;AN039; no, time has not been repeated
        mov     si,psdata_seg:$P_SI_Save ;AN039; get where parser quit
                                         ;AN039;   in command line
        cmp     byte ptr [si-1],$P_Comma ;AN039; look at delimiter
                                        ;AN039;   from command line
        jne     $P_TimeF_Rlt            ;AN039; was not a comma, this is
                                        ;AN039;  really end of line
                                        ;AN039; is comma before hundredths,
                                        ;AN039;   redo TIME
        mov     byte ptr [si-1],$P_Period ;AN039; change that ambiguous
                                        ;AN039;    comma to a decimal point
                                        ;AN039;     parse can understand
        mov     psdata_seg:$P_Flags,0   ;AN039; Clear all internal flags
        or      psdata_seg:$P_Flags1,$P_Time_Again ;AN039; indicate TIME
                                        ;AN039; is being repeated
        mov     cx,psdata_seg:$P_ORIG_ORD ;AN039; ORIGINAL ORDINAL FROM CX
        mov     sp,psdata_seg:$P_ORIG_STACK ;AN039; ORIGINAL VALUE
                                         ;AN039;   OF STACK FROM SP
        mov     si,psdata_seg:$P_ORIG_SI ;AN039; ORIGINAL START
                                         ;AN039;   PARSE POINTER FROM SI
        jmp     $P_Redo_Time            ;AN039; go try TIME again
; ===============================================================
$P_Time_4:                              ;AN039; READY FOR 4TH (HUNDREDTHS) NUMBER
	call	$P_Get_DecNum		 ; get 4th number
$P_TimeF_Err0:				 ; Bridge
	jc	$P_TimeF_Error		 ;

        mov     psdata_seg:$P_4th_Val,ax ;AC034;
	or	bl,bl			 ; After hundredth, no data allowed
	jne	$P_TimeF_Error		 ; if some, then error

$P_TimeF_RLT:				 ;
        mov     ax,psdata_seg:$P_1st_Val ;AC034;
	or	ah,ah			 ; if overflow then error
	jne	$P_TimeF_Err		 ;

        test    psdata_seg:$P_Flags1,$P_Time12am ;AN038;if "am" specified
        jz      $P_Time_notAM           ;AN038;skip if no "AM" specified
                                        ;since "AM" was specified,
        cmp     al,12                   ;AN038: if hour specified as later than noon
        ja      $P_TimeF_Err            ;AN038; error if "AM" on more than noon
        jne     $P_Time_notAM           ;AN038; for noon exactly,

        xor     al,al                   ;AN038; set hour = zero
$P_Time_notAM:                          ;AN038;
        test    psdata_seg:$P_Flags2,$P_Time12 ;AC034; if 12 hour system and pm is specified
	je	$P_TimeSkip00		 ; then

        cmp     al,12                   ;AN038; if 12:00 o'clock already
        je      $P_TimeSkip00           ;AN038; it is PM already

	add	al,12			 ; add 12 hours to make it afternoon
	jc	$P_TimeF_Err		 ; if overflow then error

        cmp     al,24                   ;AN038; after adding 12, now cannot be >24
        ja      $P_TimeF_Err            ;AN038; if too big, error

$P_TimeSkip00:				 ;
	mov	dl,al			 ; set hour
        mov     ax,psdata_seg:$P_2nd_Val ;AC034;
	or	ah,ah			 ; if overflow then error
	jne	$P_TimeF_Err		 ;

	mov	dh,al			 ; set minute
        mov     ax,psdata_seg:$P_3rd_Val ;AC034;
	or	ah,ah			 ; if overflow then error
	jne	$P_TimeF_Err		 ;

	mov	cl,al			 ; set second
        mov     ax,psdata_seg:$P_4th_Val ;AC034;
	or	ah,ah			 ; if overflow then error
	jne	$P_TimeF_Err		 ;

	mov	ch,al			 ; set hundredth
	pop	bx			 ; recover CONTROL block
	pop	si			 ; recover string pointer
ifdef __TONYI__PARSE__
;------------------------------------
; Save a byte....
;------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_Time_F)
else
	mov	ah,$P_No_Tag		 ; set
	mov	al,$P_Time_F		 ;    result
endif
	call	$P_Fill_Result		 ;	    buffer
	jmp	short $P_Time_Format_Exit  ;	to time

$P_TimeF_Error: 			 ;
$P_TimeF_Err:				 ;
	pop	bx			 ; recover CONTROL block
	pop	si			 ; recover string pointer
ifdef __TONYI__PARSE__
;------------------------------------
; Save a byte....
;------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_String)
else
	mov	ah,$P_No_Tag		 ; set
	mov	al,$P_String		 ;     result
endif
	call	$P_Fill_Result		 ;	     buffer to string
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034; return syntax error
$P_Time_Format_Exit:			 ;
        mov     psdata_seg:$P_Got_Time,0 ;AN023;AC034;; finished with this time field
	pop	dx			 ;
	pop	cx			 ;
	pop	ax			 ;
	ret				 ;
$P_Time_Format endp			 ;
PAGE					 ;
;***********************************************************************
; $P_Time_2412:
;
; Function:  Remove "a", "p", "am", or "pm" from the end of stinrg
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;
; Output:    Set $P_Time12 flag when the string is terminated by "p"
;            or "pm"
;
; Vars:  $P_Flags(W)
;***********************************************************************
$P_Time_2412 proc			 ;
	push	ax			 ;
	push	si			 ;
$P_T12_Loop:				 ;
	mov	al,psdata_seg:[si]	 ; Move
	inc	si			 ;     si
	or	al,al			 ;	 to
	jne	$P_T12_Loop		 ;	   end of string

	mov	al,psdata_seg:[si-word]  ; get char just before NULL
	or	al,$P_Make_Lower	 ; lower case map
	cmp	al,"p"			 ; only "p" of "pm" ?
	je	$P_T1200		 ;

	cmp	al,"a"			 ; only "a" of "am" ?
	je	$P_T1201		 ;

	cmp	al,"m"			 ; "m" of "am" or "pm"
	jne	$P_T12_Exit		 ;

	dec	si			 ;
	mov	al,psdata_seg:[si-word]  ;
	or	al,$P_Make_lower	 ; lower case map
	cmp	al,"p"			 ; "p" of "pm" ?
	je	$P_T1200		 ;

	cmp	al,"a"			 ; "a" of "am" ?
	je	$P_T1201		 ; go process "a"

	jmp	short $P_T12_Exit	 ; no special chars found

$P_T1200:				 ; "P" found
        or      psdata_seg:$P_Flags2,$P_Time12 ;AC034; flag "PM" found
        jmp     short $P_Tclr_chr       ;AN038; go clear the special char

$P_T1201:				 ; "A" found
        or      psdata_seg:$P_Flags1,$P_Time12AM ;AN038; flag "AM" found
$P_Tclr_chr:                            ;AN038;
	mov	byte ptr psdata_seg:[si-2],$P_NULL  ; null out special char
$P_T12_Exit:				 ;
	pop	si			 ;
	pop	ax			 ;
	ret				 ;
$P_Time_2412 endp			 ;
ENDIF					 ;(of TimeSW)
PAGE					 ;
;***********************************************************************
IF	CmpxSW				 ;(Check if complex item is supported)
; $P_Complex_Format:
;
; Function:  Check if the input string is valid complex format.
;            And set the result buffer.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:  $P_Fill_Result, $P_Chk_DBCS, $P_Chk_EOL, $P_Skip_Delim
;       $P_Quoted_str, $P_Chk_DSQuote
;
; Vars: $P_RC(W), $P_SI_Save(W), $P_SaveSI_Cmpx(R), $P_Save_EOB(R)
;***********************************************************************
$P_Complex_Format proc			 ;
	push	ax			 ;
	push	bx			 ;
	push	si			 ;
        mov     bx,psdata_seg:$P_SaveSI_Cmpx ;AC034; bx points to user buffer
	cmp	byte ptr [bx],$P_Lparen  ; 1st char = left parentheses
	jne	$P_Cmpx_Err		 ;

	xor	ah,ah			 ; ah = parentheses counter
$P_Cmpx_Loop:				 ;
	mov	al,[bx] 		 ; load character from command buffer
	call	$P_Chk_EOL		 ; if it is one of EOL
	je	$P_CmpxErr0		 ; then error exit.

	cmp	al,$P_Lparen		 ; left parentheses ?
	jne	$P_Cmpx00		 ; then

        inc     ah                      ;AC035; add '1' to AH reg
					 ; increment parentheses counter
	jc	$P_CmpxErr0		 ; if overflow, error
$P_Cmpx00:				 ;
	cmp	al,$P_Rparen		 ; right parentheses ?
	jne	$P_Cmpx01		 ; then

        dec     ah                      ;AC035; subtract '1' from AH reg
					 ; decrement parentheses counter
	jc	$P_CmpxErr0		 ; if overflow error

	je	$P_Cmpx03		 ; ok, valid complex

$P_Cmpx01:				 ;
        cmp     al,$P_DQuote            ;AN025; double quotation mark?
	jne	$P_Cmpx04		 ; 3/17/KK

	mov	psdata_seg:[si],al	 ; here quoted string is found in the complex list.
	inc	si			 ;
	inc	bx			 ; bx points to 2nd character
	call	$P_Quoted_Str		 ; skip pointers until closing of quoted string
	jc	$P_CmpxErr0		 ; if error in quoted string syntax then exit

	jmp	short $P_Cmpx05 	 ;

$P_Cmpx04:				 ;
	call	$P_Chk_DBCS		 ; was it a lead byte of DBCS ?
	jnc	$P_Cmpx02		 ;

	mov	psdata_seg:[si],al	 ; then store 1st byte
	inc	si			 ;
	inc	bx			 ;
	mov	al,[bx] 		 ; load 2nd byte
$P_Cmpx02:				 ;
	mov	psdata_seg:[si],al	 ; store SBCS or 2nd byte of DBCS
$P_Cmpx05:				 ;
	inc	si			 ;
	inc	bx			 ;
	jmp	short $P_Cmpx_Loop	 ; loop
;----					 ;
$P_Cmpx03:				 ;
	mov	byte ptr psdata_seg:[si],al  ;
	mov	byte ptr psdata_seg:[si+byte],$P_NULL  ;
	mov	byte ptr [bx],$P_NULL	 ; replace right parentheses with NULL
	mov	si,bx			 ; skip whitespaces
	inc	si			 ;     after
	call	$P_Skip_Delim		 ;	  right parentheses
        mov     psdata_seg:$P_SI_Save,si ;AC034; save next pointer, SI
	jmp	short $P_Cmpx_Exit	 ;

$P_CmpxErr0:				 ;
        mov     si,psdata_seg:$P_Save_EOB ;AC034; if EOF encountered, restore
	mov	byte ptr psdata_seg:[si],$P_NULL  ; EOB mark
$P_Cmpx_Err:				 ;
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034;
$P_Cmpx_Exit:				 ;
ifdef __TONYI__PARSE__
;------------------------------------
; Save a byte....
;------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_Complex)
else
	mov	ah,$P_No_Tag		 ;
	mov	al,$P_Complex		 ;
endif
	pop	si			 ;
	pop	bx			 ;
	call	$P_Fill_Result		 ;
	pop	ax			 ;
	ret				 ;
$P_Complex_Format endp			 ;
ENDIF					 ;(of CpmxSW)
PAGE					 ;
;***********************************************************************
IF	QusSW				 ;(Check if quoted string is supported)
; $P_Quoted_Format:
;
; Function:  Check if the input string is valid quoted string format.
;            And set the result buffer.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:  $P_Fill_Result, $P_Chk_DBCS, $P_Chk_EOL, $P_Skip_Delim
;       $P_Chk_DSQuote, $P_Quoted_Str
;
; Vars: $P_RC(W), $P_SI_Save(W), $P_SaveSI_Cmpx(R),$P_Save_EOB(R)
;***********************************************************************
$P_Quoted_Format proc			 ;
	push	ax			 ;
	push	bx			 ;
	push	si			 ;
        mov     bx,psdata_seg:$P_SaveSI_Cmpx ;AC034; bx points to user buffer
	mov	al,byte ptr [bx]	 ; get 1st character
        cmp     al,$P_DQuote            ;AN025; double quotation mark?
	jne	$P_Qus_Err		 ; if no, error
	inc	bx			 ; bx points to 2nd character
	call	$P_Quoted_Str		 ; skip pointers to the closing of quoted string
	jc	$P_Qus_Err0		 ; if invali quoted string syntax, exit

	mov	byte ptr psdata_seg:[si+byte],$P_NULL  ; end up with NULL
	mov	si,bx			 ;
	inc	si			 ;
	call	$P_Skip_Delim		 ; skip whitespaces after closing quote
        mov     psdata_seg:$P_SI_Save,si ;AC034; save next pointer, SI
	jmp	short $P_Qus_Exit	 ;

$P_Qus_Err0:				 ;
        mov     si,psdata_seg:$P_Save_EOB ;AC034; if EOF encountered, restore
	mov	byte ptr psdata_seg:[si],$P_NULL  ; EOB mark
$P_Qus_Err:
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034; indicate syntax error
$P_Qus_Exit:				 ;
ifdef __TONYI__PARSE__
;------------------------------------
; Save a byte....
;------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_Quoted_String)
else
	mov	ah,$P_No_Tag		 ; set
	mov	al,$P_Quoted_String	 ;    result
endif
	pop	si			 ;	    buffer
	pop	bx			 ;		  to
	call	$P_Fill_Result		 ;		    quoted string
	pop	ax			 ;
	ret				 ;
$P_Quoted_Format endp			 ;
ENDIF					 ;(of QusSW)
PAGE					 ;
;***********************************************************************
; $P_Chk_DSQuote;
;
; Function: Check if AL is double quotation or single quotation
;
; Input:    AL = byte to be examineed
;
; Output:   ZF on if AL is single or double quotetaion
;
; Vars:  $P_SorD_Quote(W)
;***********************************************************************
IF	QusSW+CmpxSW			 ;(Check if quoted string or complex item is supported)
    PAGE				 ;
;***********************************************************************
; $P_Quoted_Str:
;
; Function:  Copy chracacter from ES:BX to psdata_seg:SI until closing single
;            (double) quotation found.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> Operand in command buffer
;
; Output:    CY on indicates EOF encounterd before closing quotation
;            BX and SI
;
;
; Vars: $P_SorD_Quote(R)
;***********************************************************************
$P_Quoted_Str proc			 ;
	push	ax			 ;
$P_Qus_Loop:				 ;
	mov	ax,[bx] 		 ; 3/17/87
	call	$P_Chk_EOL		 ;
	je	$P_Qustr_Err0		 ;
        cmp     al,$P_DQuote            ;AN025; double quote?
	jne	$P_Qus00		 ;
        cmp     ah,$P_DQuote            ;AN025; double quote?
	jne	$P_Qus02		 ;
        mov     byte ptr psdata_seg:[si],al ;AN025; save one of the quotes
ifdef __TONYI__PARSE__
;------------------------------------------------------
; Reshuffle for convenient merging a bit later
;------------------------------------------------------
	inc	bx			;AC035; add '2' to
INC_SI_BX_Qus_Loop:
	inc	si			;AC035; add '1' to SI reg
	inc	bx			;AC035;  BX reg
else
        inc     si                      ;AC035; add '1' to SI reg
        inc     bx                      ;AC035; add '2' to
        inc     bx                      ;AC035;  BX reg
endif
	jmp	short $P_Qus_Loop	 ;

$P_Qus00:				 ;
	call	$P_Chk_DBCS		 ; was it a lead byte of DBCS ?
	jnc	$P_Qus01		 ;

	mov	psdata_seg:[si],al	 ; store 1st byte
	inc	si			 ;
	inc	bx			 ;
	mov	al,[bx] 		 ; load 2nd byte
$P_Qus01:				 ;
	mov	psdata_seg:[si],al	 ; store SBCS or 2nd byte of DBCS
ifdef __TONYI__PARSE__
;------------------------------------------------------
; Save 2 bytes...
;------------------------------------------------------
	jmp	short INC_SI_BX_Qus_Loop
else
	inc	si			 ;
	inc	bx			 ;
	jmp	short $P_Qus_Loop	 ;
endif

$P_Qustr_Err0:				 ;
	stc				 ; indicate error
	jmp	short $P_Quoted_Str_Exit  ;

$P_Qus02:				 ;
	mov	byte ptr psdata_seg:[si],0  ;
	clc				 ; indicate no error
$P_Quoted_Str_Exit:			 ;
	pop	ax			 ;
	ret				 ;
$P_Quoted_Str endp			 ;
ENDIF					 ;(of QusSW+CmpxSW)
PAGE					 ;
;***********************************************************************
IF	FileSW+DrvSW			 ;(Check if file spec or drive only is supported)
; $P_File_Format;
;
; Function:  Check if the input string is valid file spec format.
;            And set the result buffer.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:  $P_Fill_Result, $P_Chk_DBCS, $P_FileSp_Chk
;
; Vars: $P_RC(W), $P_SI_Save(W), $P_Terminator(W), $P_SaveSI_Cmpx(R)
;       $P_SaveSI_Cmpx(R)
;***********************************************************************
$P_File_Format proc			 ;
	push	ax			 ;
	push	di			 ;
	push	si			 ;
        mov     di,psdata_seg:$P_SaveSI_cmpx ;AC034; get user buffer address
$P_FileF_Loop0: 			 ; / skip special characters
	mov	al,psdata_seg:[si]	 ; load character
	or	al,al			 ; end of line ?
	je	$P_FileF_Err		 ; if yes, error exit

	call	$P_FileSp_Chk		 ; else, check if file special character
	jne	$P_FileF03		 ; if yes,
        mov     psdata_seg:$P_err_flag,$P_error_filespec ;AN033;AC034;; set error flag- bad char.
        pop     si                      ;AN033;
        mov     byte ptr psdata_seg:[si],$P_NULL ;AN033;
        pop     di                      ;AN033;
        jmp     short $P_FileF02        ;AN033;
$P_FileF_Err:				 ;
	pop	si			 ;
	mov	byte ptr psdata_seg:[si],$P_NULL  ;
	pop	di			 ;
	test	es:[bx].$P_Match_Flag,$P_Optional  ; is it optional ?
	jne	$P_FileF02		 ;

        mov     psdata_seg:$P_RC,$P_Op_Missing ;AC034; 3/17/87
	jmp	short $P_FileF02	 ;

$P_FileF03:				 ;
	pop	ax			 ; discard save si
	push	si			 ; save new si
$P_FileF_Loop1: 			 ;
	mov	al,psdata_seg:[si]	 ; load character (not special char)
	or	al,al			 ; end of line ?
	je	$P_FileF_RLT		 ;

	call	$P_FileSp_Chk		 ; File special character ?
	je	$P_FileF00		 ;

	call	$P_Chk_DBCS		 ; no, then DBCS ?
	jnc	$P_FileF01		 ;
	inc	di			 ; if yes, skip next byte
	inc	si			 ;
$P_FileF01:				 ;
	inc	di			 ;
	inc	si			 ;
	jmp	short $P_FileF_Loop1	 ;
;
$P_FileF00:				 ;
        mov     psdata_seg:$P_Terminator,al ;AC034;
	mov	byte ptr psdata_seg:[si],$P_NULL  ; update end of string
	inc	di			 ;
        mov     psdata_seg:$P_SI_Save,di ;AC034; update next pointer in command line
$P_FileF_RLT:				 ;
	pop	si			 ;
	pop	di			 ;
$P_FileF02:				 ;

	pop	ax			 ; (tm14)
	test	ax,$P_File_Spc		 ; (tm14)
	je	$P_Drv_Only_Exit	 ; (tm14)

	push	ax			 ;  (tm14)

ifdef __TONYI__PARSE__
;------------------------------------
; Save a byte....
;------------------------------------
	mov	ax, (($P_No_Tag SHL 8) OR $P_File_Spec)
else
	mov	ah,$P_No_Tag		 ; set
	mov	al,$P_File_Spec 	 ;    result
endif
	call	$P_Fill_Result		 ;	    buffer to file spec
	pop	ax			 ;

$P_Drv_Only_Exit:			 ; (tm14)

	ret				 ;
$P_File_Format endp			 ;
PAGE					 ;
;***********************************************************************
; $P_FileSp_Chk
;
; Function:  Check if the input byte is one of file special characters
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            AL = character code to be examineed
;
; Output:    ZF = 1 , AL is one of special characters
;***********************************************************************
$P_FileSp_Chk proc			 ;
	push	bx			 ;
	push	cx			 ;
        lea     bx,psdata_seg:$P_FileSp_Char ;AC034; special character table
	mov	cx,$P_FileSp_Len	 ; load length of it
$P_FileSp_Loop: 			 ;
	cmp	al,psdata_seg:[bx]	 ; is it one of special character ?
	je	$P_FileSp_Exit		 ;

	inc	bx			 ;
	loop	$P_FileSp_Loop		 ;

	inc	cx			 ; reset ZF
$P_FileSp_Exit: 			 ;
	pop	cx			 ;
	pop	bx			 ;
	ret				 ;
$P_FileSp_Chk endp			 ;
ENDIF					 ;(of FileSW+DrvSW)
PAGE					 ;
;***********************************************************************
IF	DrvSW				 ;(Check if drive only is supported)
; $P_Drive_Format;
;
; Function:  Check if the input string is valid drive only format.
;            And set the result buffer.
;
; Input:     psdata_seg:SI -> $P_STRING_BUF
;            ES:BX -> CONTROL block
;
; Output:    None
;
; Use:  $P_Fill_Result, $P_Chk_DBCS
;
; Vars: $P_RC(W)
;***********************************************************************
$P_Drive_Format proc			 ;
	push	ax			 ;
	push	dx			 ;
	mov	al,psdata_seg:[si]	 ;
	or	al,al			 ; if null string
	je	$P_Drv_Exit		 ; do nothing

	call	$P_Chk_DBCS		 ; is it leading byte ?
	jc	$P_Drv_Err		 ;

	cmp	word ptr psdata_seg:[si+byte],$P_Colon	; "d", ":", 0  ?
	je	$P_DrvF00		 ;

	test	es:[bx].$P_Match_Flag,$P_Ig_Colon  ; colon can be ignored?
	je	$P_Drv_Err		 ;

	cmp	byte ptr psdata_seg:[si+byte],$P_NULL  ; "d", 0  ?
	jne	$P_Drv_Err		 ;

$P_DrvF00:				 ;
	or	al,$P_Make_Lower	 ; lower case
	cmp	al,"a"			 ; drive letter must
	jb	$P_Drv_Err		 ; in range of

	cmp	al,"z"			 ; "a" - "z"
	ja	$P_Drv_Err		 ; if no, error

	sub	al,"a"-1		 ; make text drive to binary drive
	mov	dl,al			 ; set
	mov	ah,$P_No_Tag		 ;    result
	mov	al,$P_Drive		 ;	    buffer
	call	$P_Fill_Result		 ;		  to drive
	jmp	short $P_Drv_Exit	 ;

$P_Drv_Err:				 ;
        mov     psdata_seg:$P_RC,$P_Syntax ;AC034;
$P_Drv_Exit:				 ;
	pop	dx			 ;
	pop	ax			 ;
	ret				 ;
$P_Drive_Format endp			 ;
ENDIF					 ;(of DrvSW)
PAGE					 ;
;***********************************************************************
; $P_Skip_Delim;
;
; Function: Skip delimiters specified in the PARMS list, white space
;           and comma.
;
; Input:    DS:SI -> Command String
;           ES:DI -> Parameter List
;
; Output:   CY = 1 if the end of line encounterd
;           CY = 0 then SI move to 1st non-delimiter character
;           AL = Last examineed character
;
; Use:      $P_Chk_EOL, $P_Chk_Delim,
;
; Vars:     $P_Flags(R)
;***********************************************************************
$P_Skip_Delim proc			 ;
$P_Skip_Delim_Loop:			 ;
	LODSB				 ;
	call	$P_Chk_EOL		 ; is it EOL character ?
	je	$P_Skip_Delim_CY	 ; if yes, exit w/ CY on

	call	$P_Chk_Delim		 ; is it one of delimiters ?
	jne	$P_Skip_Delim_NCY	 ; if no, exit w/ CY off

        test    psdata_seg:$P_Flags2,$P_Extra ;AC034; extra delim or comma found ?
	je	$P_Skip_Delim_Loop	 ; if no, loop

        test    psdata_seg:$P_Flags2,$P_SW+$P_equ ;AC034; /x , or xxx=zzz , (tm08)
	je	short $P_Exit_At_Extra	 ; no switch, no keyword (tm08)

	dec	si			 ; backup si for next call (tm08)
	jmp	short $P_Exit_At_Extra	 ; else exit w/ CY off

$P_Skip_Delim_CY:			 ;
	stc				 ; indicate EOL
	jmp	short $P_Skip_Delim_Exit  ;

$P_Skip_Delim_NCY:			 ;
	clc				 ; indicate non delim
$P_Skip_Delim_Exit:			 ; in this case, need
	dec	si			 ;  backup index pointer
	ret				 ;

$P_Exit_At_Extra:			 ;
	clc				 ; indicate extra delim
	ret				 ;
$P_Skip_Delim endp			 ;
PAGE					 ;
;***********************************************************************
; $P_Chk_EOL;
;
; Function: Check if AL is one of End of Line characters.
;
; Input:    AL = character code
;           ES:DI -> Parameter List
;
; Output:   ZF = 1 if one of End of Line characters
;**********************************************************************
$P_Chk_EOL proc 			 ;
	push	bx			 ;
	push	cx			 ;
	cmp	al,$P_CR		 ; Carriage return ?
	je	$P_Chk_EOL_Exit 	 ;

	cmp	al,$P_NULL		 ; zero ?
	je	$P_Chk_EOL_Exit 	 ;

IF LFEOLSW                              ;AN028; IF LF TO BE ACCEPTED AS EOL
	cmp	al,$P_LF		 ; Line feed ?
	je	$P_Chk_EOL_Exit 	 ;
ENDIF                                   ;AN028;

	cmp	byte ptr es:[di].$P_Num_Extra,$P_I_Have_EOL  ; EOL character specified ?
	jb	$P_Chk_EOL_Exit 	 ;

	xor	bx,bx			 ;
	mov	bl,es:[di].$P_Len_Extra_Delim  ; get length of delimiter list
	add	bx,$P_Len_PARMS 	 ; skip it
	cmp	byte ptr es:[bx+di],$P_I_Use_Default  ; No extra EOL character ?
	je	$P_Chk_EOL_NZ		 ;

	xor	cx,cx			 ; Get number of extra chcracter
	mov	cl,es:[bx+di]		 ;
$P_Chk_EOL_Loop:			 ;
	inc	bx			 ;
	cmp	al,es:[bx+di]		 ; Check extra EOL character
	je	$P_Chk_EOL_Exit 	 ;

	loop	$P_Chk_EOL_Loop 	 ;

$P_Chk_EOL_NZ:				 ;
	cmp	al,$P_CR		 ; reset ZF
$P_Chk_EOL_Exit:			 ;
	pop	cx			 ;
	pop	bx			 ;
	ret				 ;
$P_Chk_EOL endp 			 ;
PAGE					 ;
;***********************************************************************
; $P_Chk_Delim;
;
; Function: Check if AL is one of delimiter characters.
;           if AL+[si] is DBCS blank, it is replaced with two SBCS
;           blanks.
;
; Input:    AL = character code
;           DS:SI -> Next Character
;           ES:DI -> Parameter List
;
; Output:   ZF = 1 if one of delimiter characters
;           SI points to the next character
; Vars:  $P_Terminator(W), $P_Flags(W)
;***********************************************************************
$P_Chk_Delim proc			 ;
	push	bx			 ;
	push	cx			 ;
        mov     psdata_seg:$P_Terminator,$P_Space   ;AC034; Assume terminated by space
        and     psdata_seg:$P_Flags2,0ffh-$P_Extra ;AC034;
	cmp	al,$P_Space		 ; Space ?
	je	$P_Chk_Delim_Exit	 ;

	cmp	al,$P_TAB		 ; TAB ?
	je	$P_Chk_Delim_Exit	 ;

	cmp	al,$P_Comma		 ; Comma ?
	je	$P_Chk_Delim_Exit0	 ;

$P_Chk_Delim00: 			 ;
	cmp	al,$P_DBSP1		 ; 1st byte of DBCS Space ?
	jne	$P_Chk_Delim01		 ;

	cmp	byte ptr [si],$P_DBSP2	 ; 2nd byte of DBCS Space ?
	jne	$P_Chk_Delim01		 ;

	mov	al,$P_Space		 ;
	inc	si			 ; make si point to next character
	cmp	al,al			 ; Set ZF
	jmp	short $P_Chk_Delim_Exit  ;

$P_Chk_Delim01: 			 ;
	cmp	byte ptr es:[di].$P_Num_Extra,$P_I_Have_Delim  ; delimiter character specified ?
	jb	$P_Chk_Delim_Exit	 ;

	xor	cx,cx			 ;
	mov	cl,es:[di].$P_Len_Extra_Delim  ; get length of delimiter list
ifdef __TONYI__PARSE__
;------------------------------------
; Save 2 bytes....
;------------------------------------
	jcxz	$P_Chk_Delim_NZ 	;AN000;
else
	or	cx,cx			 ; No extra Delim character ?
	je	$P_Chk_Delim_NZ 	 ;
endif

	mov	bx,$P_Len_PARMS-1	 ; set bx to 1st extra delimiter
$P_Chk_Delim_Loop:			 ;
	inc	bx			 ;
	cmp	al,es:[bx+di]		 ; Check extra Delim character
	je	$P_Chk_Delim_Exit0	 ;

	loop	$P_Chk_Delim_Loop	 ; examine all extra delimiter

$P_Chk_Delim_NZ:			 ;
	cmp	al,$P_Space		 ; reset ZF
$P_Chk_Delim_Exit:			 ;
$P_ChkDfin:				 ;
	pop	cx			 ;
	pop	bx			 ;
	ret				 ;

$P_Chk_Delim_Exit0:			 ;
        mov     psdata_seg:$P_Terminator,al ;AC034; keep terminated delimiter
        test    psdata_seg:$P_Flags2,$P_Equ  ;AN027;AC034;; if terminating a key=
        jnz     $P_No_Set_Extra         ;AN027; then do not set the EXTRA bit

        or      psdata_seg:$P_Flags2,$P_Extra ;AC034; flag terminated extra delimiter or comma
$P_No_Set_Extra:                        ;AN027;
	cmp	al,al			 ; set ZF
	jmp	short $P_Chk_Delim_Exit  ;

$P_Chk_Delim endp			 ;
PAGE					 ;
;***********************************************************************
; $P_Chk_Switch;
;
; Function: Check if AL is the switch character not in first position of
;           $P_STRING_BUF
;
; Input:    AL = character code
;           BX = current pointer within $P_String_Buf
;           SI =>next char on command line (following the one in AL)
;
; Output:   CF = 1 (set)if AL is switch character, and not in first
;                position, and has no chance of being part of a date string,
;                i.e. should be treated as a delimiter.

;           CF = 0 (reset, cleared) if AL is not a switch char, is in the first
;                position, or is a slash but may be part of a date string, i.e.
;                should not be treated as a delimiter.
;
; Vars:  $P_Terminator(W)

; Use:   $P_0099
;***********************************************************************
$P_Chk_Switch proc			 ;
        LEA     BP,psdata_seg:$P_String_Buf ;AN020;AC034; BP=OFFSET of $P_String_Buf even in group addressing
	cmp	BX,BP			 ;
	je	$P_STRUC_L2		 ;
	    cmp     AL,$P_Switch	 ;
	    jne     $P_STRUC_L5 	 ;

                STC                     ;AN020;not in first position and is slash, now see if might be in date string
IF      DateSw                          ;AN020;caller looking for date, see if this may be part of one
                PUSH    AX              ;AN020;save input char
                MOV     AL,PSDATA_SEG:[BX-1] ;AN026;AL=char before the current char
                CALL    $P_0099         ;AN020;return carry set if not numeric
		jc	$P_STRUC_L7	 ;

                    MOV     AL,[SI]     ;AN020;AL=char after the current char
                    CALL    $P_0099     ;AN020;return carry set if not numeric
$P_STRUC_L7:				 ;
                POP     AX              ;AN020;restore AL to input char
ENDIF                                   ;AN020;DateSw
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte. Do the RET here.
;-------------------------------------
	ret
else
	    jmp     short $P_STRUC_L1	 ;
endif

$P_STRUC_L5:				 ;
                CLC                     ;AN020;not a slash
ifdef __TONYI__PARSE__
;-------------------------------------
; Save a byte. Do the RET here.
;-------------------------------------
	ret
else
	jmp	short $P_STRUC_L1	 ;
endif

$P_STRUC_L2:				 ;
	    cmp     AL,$P_Switch	 ;
	    jne     $P_STRUC_L12	 ;

                OR      psdata_seg:$P_Flags2,$P_SW ;AN020;AC034;;could be valid switch, first char and is slash
$P_STRUC_L12:				 ;
            CLC                         ;AN020;CF=0 indicating first char
$P_STRUC_L1:				 ;
	ret				 ;
$P_Chk_Switch endp			 ;
	PAGE				 ;
;**************************************************************************
; $P_Chk_DBCS:
;
;  Function: Check if a specified byte is in ranges of the DBCS lead bytes
;
;  Input:
;         AL    = Code to be examineed
;
;  Output:
;         If CF is on then a lead byte of DBCS
;
; Use: INT 21h w/AH=63
;
; Vars:  $P_DBCSEV_Seg(RW), $P_DBCSEV_Off(RW)
;***************************************************************************
$P_Chk_DBCS PROC			 ;
;
	PUSH	DS			 ;
	PUSH	SI			 ;
	PUSH	bx			 ; (tm11)
        CMP     psdata_seg:$P_DBCSEV_SEG,0 ;AC034; ALREADY SET ?
	JNE	$P_DBCS00		 ;

	PUSH	AX			 ;
	PUSH	ds			 ; (tm11)
	PUSH	CX			 ;
	PUSH	DX			 ;
	PUSH	DI			 ;
	PUSH	BP			 ;
	PUSH	ES			 ;
	XOR	SI,SI			 ;
	MOV	DS,SI			 ;
	MOV	AX,$P_DOS_GetEV 	 ; GET DBCS EV CALL
	INT	21H			 ;

	MOV	bx,DS			 ; (tm11)
	OR	bx,bx			 ; (tm11)
	POP	ES			 ;
	POP	BP			 ;
	POP	DI			 ;
	POP	DX			 ;
	POP	CX			 ;
	POP	ds			 ; (tm11)
	POP	AX			 ;
	JE	$P_NON_DBCS		 ;

$P_DBCS02:				 ;
        MOV     psdata_seg:$P_DBCSEV_OFF,SI ;AC034; save EV offset
        MOV     psdata_seg:$P_DBCSEV_SEG,bx ;AC034; save EV segment (tm11)
$P_DBCS00:				 ;
ifdef __TONYI__PARSE__
;------------------------------------
; Save a few bytes....
;------------------------------------
	.errnz	($P_DBCSEV_SEG - $P_DBCSEV_OFF - 2)
	lds	si, dword ptr psdata_seg:$P_DBCSEV_OFF
else
        MOV     SI,psdata_seg:$P_DBCSEV_OFF ;AC034; load EV offset
        MOV     DS,psdata_seg:$P_DBCSEV_SEG ;AC034; and segment
endif

$P_DBCS_LOOP:				 ;
	CMP	WORD PTR [SI],0 	 ; zero vector ?
	JE	$P_NON_DBCS		 ; then exit

	CMP	AL,[SI] 		 ;
	JB	$P_DBCS01		 ; Check if AL is in

	CMP	AL,[SI+BYTE]		 ;   range of
	JA	$P_DBCS01		 ;	the vector

	STC				 ; if yes, indicate DBCS and exit
	JMP	short $P_DBCS_EXIT	 ;

$P_DBCS01:				 ;
        INC     SI                      ;AC035; add '2' to
        INC     SI                      ;AC035;  SI reg
					 ; get next vector
	JMP	short $P_DBCS_LOOP	 ; loop until zero vector found

$P_NON_DBCS:				 ;
	CLC				 ; indicate SBCS
$P_DBCS_EXIT:				 ;
	POP	bx			 ; (tm11)
	POP	SI			 ;
	POP	DS			 ;
	RET				 ;
$P_Chk_DBCS ENDP			 ;
