;
; Program to examine the environment and give return codes for BATCH inquiry
;
; Gerald Lotto	01/24/85
;
; Usage:
;       ENVRPT <var> [<val>]
; <var> is an environment variable with value
; <val> (optional)
;
; Valid return codes are:
;
;	0 - <var> is found to equal <val>
;	1 - <var> is found to not equal <val>
;	3 - <var> is not found
;	4 - Illegal arguments were given, i.e. ENVRPT (cr)
;
;	Revised:
;		DATE	INIT	REASON
;
;
	Title	ENVRPT

CSEG	SEGMENT	PARA 'CODE'

NULL	EQU	00H
SPACE	EQU	20H
CR	EQU	0DH
LF	EQU	0AH
ENVSIZE	EQU	800H				; This is maximum size
						; for my (modified) DOS
	ORG	2CH
ENVSEG	LABEL	WORD				; Segment of environment

	ORG	80H
DOSCMD	LABEL	BYTE				; Command line from DOS

	ORG	100H
ENVRPT	PROC	FAR
	ASSUME	CS:CSEG,DS:NOTHING,ES:NOTHING

	JMP	START

VALUE	DB	80H DUP(0)			; Internal work area for
						; storing translation string
START:	MOV	AX,CS
	MOV	DS,AX				; Ensure that DS and ES are
	MOV	ES,AX				; set up
	MOV	SI,OFFSET DOSCMD + 1		; Start of argument string
	MOV	CX,0000
	MOV	CL,BYTE PTR DOSCMD		; Length of argument string
 	CALL	GETWORD				; Get first argument

	CMP	BYTE PTR [DI],NULL		; Is it NULL?
	JZ	ERROR				; Yes, exit with code 4

	CALL	UPCASE				; Upper case it in place

	CALL	XLATE				; Get translation string
						; from environment in VALUE
	CMP	BYTE PTR CS:VALUE,NULL		; Is the translation NULL?
	JZ	NOTFOUND			; Yes, exit with code 3

	MOV	DI,OFFSET DS:VALUE		; Locate translation string
	MOV	AX,0200H			; DOS Print character

PRINT:	MOV	DL,BYTE PTR [DI]		; Get next char to print
	INT	21H				; Print it,
	INC	DI				; and move up one
	CMP	BYTE PTR [DI],NULL		; Is it the end?
	JNZ	PRINT				; No, go another round

	MOV	DL,CR				; Yes, follow by a carriage
	INT	21H				; return

	MOV	DL,LF				; and a line feed
	INT	21H

	ADD	SI,CX				; Position at the end of arg2
	MOV	BYTE PTR [SI],NULL		; and put a NULL there
	INC	CX				; Increase to count all chars
	STD					; Reverse direction
	REPZ	CMPS BYTE PTR DS:[SI],ES:[DI]	; and compare the strings

	CLD					; Go forward again
	JNZ	FALSEEXIT			; If the comparison failed,
						; exit with code 1
TRUEEXIT:
	MOV	AX,4C00H			; Otherwise exit with code 0
	INT	21H

FALSEEXIT:
	MOV	AX,4C01H			; This is the exit for a
	INT	21H				; non-match

NOTFOUND:
	MOV	AX,4C03H			; This is the exit for not
	INT	21H				; finding the requested
						; ENVIRONMENT variable
ERROR:
	MOV	AX,4C04H			; This is the exit for bad
	INT	21H				; arguments

ENVRPT	ENDP

;	Procedure GETWORD
;
;	Call with:
;	SI - Pointer in an ASCII string (Possible leading spaces)
;	CX - Length to end of string
;
;	Returns with:
;	DI - Pointer to first word now terminated with a null
;	SI, CX - Now point to next word and have remaining string length
;
;	Does not look back for data before SI
;	AX, BX, CX zapped, all other regs preserved
;
;	Thanks to Dan Tappan, this code was modified from OLDER.ASM
;
GETWORD	PROC
	CLD
	PUSH	SI
	PUSH	CX
	MOV	BX,CX
	MOV	AL,SPACE
	MOV	BYTE PTR [BX+SI],AL		; Put a space at the end
	MOV	DI,SI
	CMP	CX,+00				; Check length
	JLE	GOTWORD				; Return if NULL

	REPZ	SCASB				; Skip leading spaces

	CMP	CX,+00				; See if you ran out of string
	JG	READWORD			; If not, go to it

	MOV	DI,SI				; If so, back to the beginning
	JMP	GOTWORD				; and return

READWORD:	
	DEC	DI				; Back up to the first char
	NOT	CX				; Count back from -1
	PUSH	DI				; Save the start
	REPNZ	SCASB				; Find the next space

	DEC	DI				; Back up to the end
	MOV	SI,DI				; Save it,
	POP	DI				; and restore the pointer
						; to the start
GOTWORD:
	MOV	BYTE PTR [SI],00		; Terminate word with a null
	INC	SI				; Advance to next word
	POP	CX				; Original length
	POP	BX				; The original location
	SUB	BX,SI				; - the current location
	ADD	CX,BX				; + the overall length
	RET					; = the remaining length

GETWORD	ENDP

;	Procedure UPCASE
;
;	Call with:
;	DI - Pointer in an ASCII string terminated by a space (or less)
;
;	Returns with:
;	String UPPERCASED in place
;
;	AX zapped, all other regs preserved
;
UPCASE	PROC
	CLD	
	PUSH	SI
	MOV	SI,DI

NEXTBYTE:
	LODSB	
	AND	AL,07FH				; Strip hi bit
	CMP	AL,SPACE			; Is this the end?
	JLE	UPCASED				; Yes, we are done.

	CMP	AL,'a'				; Skip if it is less
	JL	NEXTBYTE			; then 'a'

	CMP	AL,'z'				; or if it is greater
	JG	NEXTBYTE			; then 'z'

	AND	AL,0DFH				; Else, UPPERCASE it
	MOV	BYTE PTR [SI-01],AL		; Replace it
	JMP	NEXTBYTE			; and grab the next one

UPCASED:
	POP	SI
	RET	

UPCASE	ENDP

;	Procedure XLATE
;
;	Call with:
;	DI - Pointer to an UPPERCASED string, null terminated
;
;	Returns with:
;	Translation of string in an internal data area, terminated
;	with a 00, '$'
;
;	AX zapped, all other regs preserved
;
XLATE	PROC
	CLD	
	PUSH	DS
	PUSH	SI
	PUSH	DI
	PUSH	CX
	MOV	SI,DI
	MOV	AX,WORD PTR ENVSEG		; From the PSP, DOS gives
	MOV	ES,AX				; the segment and offset of
	MOV	DI,00				; a copy of the environment
	MOV	CX,WORD PTR ENVSIZE		; Max size, see params up top
	LODS	BYTE PTR DS:[SI]		; Get the first char of arg

TESTMATCH:
	PUSH	AX				; and save it
	CMP	AL,BYTE PTR ES:[DI]		; Check against ENV string #1
	JZ	GOTMATCH			; Possible match

FAILED:
	MOV	AX,0000				; No match, search ENVIRONMENT
	REPNZ	SCAS BYTE PTR ES:[DI]		; for next NULL

	POP	AX				; Restore first char of arg
	CMP	CX,00				; Have we run out of space?
	JZ	TERMINATE			; Yes, stop looking

	CMP	BYTE PTR ES:[DI],NULL		; Are we at environment end?
	JNZ	TESTMATCH			; No, test next entry

	JMP	TERMINATE			; Yes, stop looking

GOTMATCH:
	INC	DI				; Step to next char in ENV
	REPZ	CMPS BYTE PTR DS:[SI],ES:[DI]	; Compare strings

	DEC	SI				; Back up to last character
	DEC	DI				; in arg and ENV strings
	CMP	BYTE PTR DS:[SI],NULL		; Are we at the end of arg?
	JNZ	FAILED				; No, try next ENV string
;
; Insert code to handle wildcards here
;
	CMP	BYTE PTR ES:[DI],'='		; End of the ENV string?
	JNZ	FAILED				; No, try next ENV string

	POP	AX				; We have a match, trash AX
	INC	DI
	PUSH	DI				; Save start of translation
	MOV	CX,0FFFFH			; Count backwards from -1
	MOV	AX,0000
	REPNZ	SCAS BYTE PTR ES:[DI]		; up to the next NULL

	NOT	CX
	DEC	CX				; Adjust count to + number
	POP	SI				; Start of translation string
	MOV	AX,ES				; Swap seg regs around for
	MOV	DS,AX				; MOVS with DS = ENVSEG
	MOV	AX,CS				; and ES = CS
	MOV	ES,AX
	MOV	DI,OFFSET CS:VALUE		; Point to the internal data
	REPZ	MOVS BYTE PTR ES:[DI],DS:[SI]	; area and copy translation

TERMINATE:
	MOV	BYTE PTR ES:[DI],NULL		; Terminate with a NULL
	POP	CX
	POP	DI
	POP	SI
	POP	DS
	RET	

XLATE	ENDP

CSEG	ENDS
	END	ENVRPT
