        PAGE    60,132
	TITLE	DEBCOM1.ASM - PART1 DEBUGGER COMMANDS	PC DOS
;/*
; *                      Microsoft Confidential
; *                      Copyright (C) Microsoft Corporation 1991
; *                      All Rights Reserved.
; */
;======================= START OF SPECIFICATIONS =========================
;
; MODULE NAME: DECOM1.asm
;
; DESCRIPTIVE NAME: DEBUGGING TOOL
;
; FUNCTION: PROVIDES USERS WITH A TOOL FOR DEBUGGING PROGRAMS.
;
; ENTRY POINT: ANY CALLED ROUTINE
;
; INPUT: NA
;
; EXIT NORMAL: NA
;
; EXIT ERROR: NA
;
; INTERNAL REFERENCES:
;
; EXTERNAL REFERENCES:
;
;	ROUTINE: DEBCOM2 - CONTAINS ROUTINES CALLED BY DEBUG
;		 DEBCOM3 - CONTAINS ROUTINES CALLED BY DEBUG
;		 DEBASM  - CONTAINS ROUTINES CALLED BY DEBUG
;		 DEBUASM - CONTAINS ROUTINES CALLED BY DEBUG
;		 DEBMES  - CONTAINS ROUTINES CALLED BY DEBUG
;
; NOTES: THIS MODULE IS TO BE PREPPED BY SALUT WITH THE "PR" OPTIONS.
;	 LINK DEBUG+DEBCOM1+DEBCOM2+DEBCOM3+DEBASM+DEBUASM+DEBERR+
;	      DEBCONST+DEBDATA+DEBMES
;
; REVISION HISTORY:
;
;	AN000	VERSION 4.00 - REVISIONS MADE RELATE TO THE FOLLOWING:
;
;				- IMPLEMENT DBCS HANDLING	DMS:6/17/87
;				- IMPLEMENT MESSAGE RETRIEVER	DMS:6/17/87
;				- IMPLEMENT > 32MB SUPPORT	DMS:6/17/87
;
; COPYRIGHT: "MS DOS DEBUG UTILITY"
;	     "VERSION 4.00 (C) COPYRIGHT 1988 Microsoft"
;	     "LICENSED MATERIAL - PROPERTY OF Microsoft  "
;
;======================= END OF SPECIFICATIONS ===========================

; Routines to perform debugger commands except ASSEMble and UASSEMble

	IF1
           ;%out COMPONENT=DEBUG, MODULE=DEBCOM1
	ENDIF
.XLIST
.XCREF
	include syscall.inc		; cas -- missing equates
	include version.inc		; cas -- missing equates
	INCLUDE DOSSYM.INC
        INCLUDE debug.inc
.CREF
.LIST

CODE	SEGMENT PUBLIC BYTE
CODE	ENDS

CONST	SEGMENT PUBLIC BYTE
	EXTRN	SYNERR_PTR:BYTE
	EXTRN	DISPB:WORD,DSIZ:BYTE,DSSAVE:WORD
	IF	SYSVER
	    EXTRN   CIN:DWORD,PFLAG:BYTE
	ENDIF
CONST	ENDS

CSTACK	SEGMENT STACK
CSTACK	ENDS

DATA	SEGMENT PUBLIC BYTE
	EXTRN	DEFLEN:WORD,BYTEBUF:BYTE,DEFDUMP:BYTE
	EXTRN	ARG_BUF:BYTE,ARG_BUF_PTR:BYTE
	EXTRN	ONE_CHAR_BUF:BYTE,ONE_CHAR_BUF_PTR:WORD
DATA	ENDS

DG	GROUP	CODE,CONST,CSTACK,DATA

CODE	SEGMENT PUBLIC BYTE
ASSUME	CS:DG,DS:DG,ES:DG,SS:DG
	PUBLIC	HEXCHK,GETHEX1,PRINT,DSRANGE,ADDRESS,HEXIN,PERROR
	PUBLIC	GETHEX,GET_ADDRESS,GETEOL,GETHX,PERR
	PUBLIC	PERR,MOVE,DUMP,ENTERDATA,FILL,SEARCH,DEFAULT
ifdef JAPAN
	public	SETDUMPMODE
	extrn	test_lead:near
endif
	IF	SYSVER
	    PUBLIC  IN
	    EXTRN   DISPREG:NEAR,DEVIOCALL:NEAR
	ENDIF
	EXTRN	CRLF:NEAR,OUTDI:NEAR,OUTSI:NEAR,SCANP:NEAR
	EXTRN	SCANB:NEAR,BLANK:NEAR,TAB:NEAR,COMMAND:NEAR
	EXTRN	HEX:NEAR,BACKUP:NEAR
	EXTRN	PRINTF_CRLF:NEAR,HEX_ADDRESS_ONLY:NEAR,HEX_ADDRESS_STR:NEAR
	EXTRN	STD_PRINTF:NEAR
DEBCOM1:
; RANGE - Looks for parameters defining an address range.
; The first parameter is the starting address. The second parameter
; may specify the ending address, or it may be preceded by
; "L" and specify a length (4 digits max), or it may be
; omitted and a length of 128 bytes is assumed. Returns with
; segment in AX, displacement in DX, and length in CX.
DSRANGE:
	MOV	BP,[DSSAVE]		; Set default segment to DS
	MOV	[DEFLEN],128		; And default length to 128 bytes
RANGE:
	CALL	ADDRESS

	PUSH	AX			; Save segment
	PUSH	DX			; Save offset
	CALL	SCANP			; Get to next parameter

	MOV	AL,[SI]
	CMP	AL,UPPER_L		; Length indicator?
	JE	GETLEN

	MOV	DX,[DEFLEN]		; Default length
	CALL	HEXIN			; Second parameter present?

	JC	GETDEF			; If not, use default

	MOV	CX,4
	CALL	GETHEX			; Get ending address (same segment)

	MOV	CX,DX			; Low 16 bits of ending addr.
	POP	DX			; Low 16 bits of starting addr.
	SUB	CX,DX			; Compute range
	JAE	DSRNG2

DSRNG1:
	JMP	PERROR			; Negative range
DSRNG2:
	INC	CX			; Include last location
;	JCXZ	DSRNG1			; Wrap around error
;	Removing this instruction allows 0 FFFF to valid range
	POP	AX			; Restore segment
	RET
GETDEF:
	POP	CX			; get original offset
	PUSH	CX			; save it
	NEG	CX			; rest of segment
	JZ	RNGRET			; use default

	CMP	CX,DX			; more room in segment?
	JAE	RNGRET			; yes, use default

	JMP	short RNGRET1 		; no, length is in CX

GETLEN:
	INC	SI			; Skip over "L" to length
	MOV	CX,4			; Length may have 4 digits
	CALL	GETHEX			; Get the range

RNGRET:
	MOV	CX,DX			; Length
RNGRET1:
	POP	DX			; Offset
	MOV	AX,CX
	ADD	AX,DX
	JNC	OKRET

	CMP	AX,1
	JAE	DSRNG1			; Look for wrap error

OKRET:
	POP	AX			; Segment
	RET
DEFAULT:
; DI points to default address and CX has default length
	CALL	SCANP

	JZ	USEDEF			; Use default if no parameters

	MOV	[DEFLEN],CX
	CALL	RANGE

	JMP	GETEOL

USEDEF:
	MOV	SI,DI
	LODSW				; Get default displacement
	MOV	DX,AX
	LODSW				; Get default segment
	RET

ifdef JAPAN
;
;	Set Dump mode to Kanji or Ascii
;
dump_mode	db	0
dbcs_flag	db	0
dbcs_adj	db	0

SETDUMPMODE:
	call	scanp			; get parameter
	jz	dm_err			; if none
	lodsb
	cmp	al,'K'			; is it for Kanji mode
	jnz	@f			; no
	call	geteol
	mov	cs:dump_mode,1		; set Kanji mode
	jmp	short dm_ret
@@:
	cmp	al,'A'			; is it for Ascii mode
	jnz	@f			; no
	call	geteol
	mov	cs:dump_mode,0		; set Ascii mode
	jmp	short dm_ret
@@:
dm_err:
	jmp	PERR
dm_ret:
	ret
endif

; Dump an area of memory in both hex and ASCII
DUMP:
ifdef JAPAN
	mov	cs:dbcs_flag,0
	mov	cs:dbcs_adj,0
endif

	MOV	BP,[DSSAVE]
	MOV	CX,DISPB
	MOV	DI,OFFSET DG:DEFDUMP
	CALL	DEFAULT 		; Get range if specified

	MOV	DS,AX			; Set segment
	ASSUME	DS:NOTHING

	MOV	SI,DX			; SI has displacement in segment
	PUSH	SI			; save SI away
	MOV	AL,DSIZ
	XOR	AH,AH
	XOR	AX,-1
	AND	SI,AX			; convert to para number
	MOV	DI,OFFSET DG:ARG_BUF	; Build the output str in arg_buf
	CALL	OUTSI			; display location

	POP	SI			; get SI back
; Determine where the registers display should begin.
	MOV	AX,SI			; move offset
	MOV	AH,3			; spaces per byte
	AND	AL,DSIZ 		; convert to real offset
	MUL	AH			; 3 char positions per byte of output
	OR	AL,AL			; at beginning?
	JZ	INROW			; if so, then no movement.

	PUSH	CX
	MOV	CX,AX
	CALL	TAB

	POP	CX
INROW:
	PUSH	SI			; Save address for ASCII dump
BYTE0:
	CALL	BLANK			; Space between bytes
BYTE1:
	LODSB				; Get byte to dump
	CALL	HEX			; and display it

	POP	DX			; DX has start addr. for ASCII dump
	DEC	CX			; Drop loop count
	JZ	ASCII			; If through do ASCII dump

	MOV	AX,SI
	TEST	AL,DSIZ 		; On row boundary?
	JZ	ENDROW

	PUSH	DX			; Didn't need ASCII addr. yet
	TEST	AL,7			; On 8-byte boundary?
	JNZ	BYTE0

	MOV	AL,CHAR_MINUS		; Mark every 8 bytes with "-"
	STOSB
	JMP	SHORT BYTE1

ENDROW:
	CALL	ASCII			; Show it in ASCII

	MOV	DI,OFFSET DG:ARG_BUF	; Build the output str in arg_buf
	CALL	OUTSI			; Get the address at start of line

	JMP	INROW			; Loop until count is zero

; Produce a dump of the ascii text characters.	We take the current SI which
; contains the byte after the last one dumped.	From this we determine how
; many spaces we need to output to get to the ascii column.  Then we look at
; the beginning address of the dump to tsee how many spaces we need to indent.
ASCII:
	PUSH	CX			; Save count of remaining bytes
; Determine how many spaces to go until the ASCII column.
	MOV	AX,SI			; get offset of next byte
	DEC	AL
	AND	AL,DSIZ
	INC	AL
; AX now has the number of bytes that we have displayed:  1 to Dsiz+1.
; Compute characters remaining to be displayed.  We *always* put the ASCII
; dump in column 51 (or whereever)
	SUB	AL,10H			; get negative of number
	DEC	AL			;
	NEG	AL			; convert to positive
	CBW				; convert to word
; 3 character positions for each byte displayed.
	MOV	CX,AX
	SHL	AX,1
	ADD	CX,AX
; Compute indent for ascii dump
	MOV	AX,DX
	AND	AL,DSIZ
	XOR	AH,AH
	ADD	CX,AX
; Tab over
	CALL	TAB

; Set up for true dump
	MOV	CX,SI
	MOV	SI,DX
	SUB	CX,SI
ASCDMP:
	LODSB				; Get ASCII byte to dump

ifdef JAPAN
	cmp	cs:dbcs_flag,1
	jz	set_dbcs		; if it was lead byte
	cmp	cs:dbcs_flag,2
	jnz	@f			; if it was not tail byte
	mov	cs:dbcs_flag,0		; reset
@@:
	call	test_lead
	jnc	@f			; if this is not lead byte
	cmp	byte ptr [si],CHAR_BLANK
	jae	set_dbcs		; if tail byte is not control corde
	mov	al,CHAR_PERIOD
	jmp	short @f
set_dbcs:
	inc	cs:dbcs_flag
@@:
	cmp	cs:dump_mode,1
	jnz	@f			; if not Kanji mode
	cmp	cs:dbcs_adj,1
	jnz	kanjiprt		; if no need to adjust
	mov	al,' '			; tail byte is displayed already
	mov	cs:dbcs_adj,0
	jmp	short kanjiprt
@@:
endif

	CMP	AL,CHAR_RUBOUT
	JAE	NOPRT			; Don't print RUBOUT or above

ifdef JAPAN
kanjiprt:
endif

	CMP	AL,CHAR_BLANK
	JAE	PRIN			; print space through RUBOUT-1

NOPRT:
	MOV	AL,CHAR_PERIOD		; If unprintable character
PRIN:
	STOSB
	LOOP	ASCDMP			; CX times

ifdef JAPAN
	cmp	cs:dump_mode,1
	jnz	@f			; if not Kanji mode
	cmp	cs:dbcs_flag,1
	jnz	@f			; if not ended with lead byte
	mov	al,[si]			; get tail byte
	stosb
	mov	cs:dbcs_adj,1
@@:
endif

	MOV	AL,0
	STOSB
	PUSH	DS
	PUSH	CS
	POP	DS
	ASSUME	DS:DG

	CALL	HEX_ADDRESS_STR

	CALL	CRLF

	POP	DS
	ASSUME	DS:NOTHING

	POP	CX			; Restore overall dump len
	MOV	WORD PTR [DEFDUMP],SI
	MOV	WORD PTR [DEFDUMP+WORD],DS ; Save last address as def
	RET

	ASSUME	DS:DG
; Block move one area of memory to another Overlapping moves are performed
; correctly, i.e., so that a source byte is not overwritten until after it has
; been moved.
MOVE:
	CALL	DSRANGE 		; Get range of source area

	PUSH	CX			; Save length
	PUSH	AX			; Save segment
	PUSH	DX			; Save source displacement
	CALL	ADDRESS 		; Get destination address (sam

	CALL	GETEOL			; Check for errors

	POP	SI
	MOV	DI,DX			; Set dest. displacement
	POP	BX			; Source segment
	MOV	DS,BX
	MOV	ES,AX			; Destination segment
	POP	CX			; Length
	CMP	DI,SI			; Check direction of move
	SBB	AX,BX			; Extend the CMP to 32 bits
	JB	COPYLIST		; Move forward into lower mem.

; Otherwise, move backward. Figure end of source and destination
; areas and flip direction flag.
	DEC	CX
	ADD	SI,CX			; End of source area
	ADD	DI,CX			; End of destination area
	STD				; Reverse direction
	INC	CX
COPYLIST:
	MOVSB				; Do at least 1 - Range is 1-1
	DEC	CX
	REP	MOVSB			; Block move
RET1:
	RET

; Fill an area of memory with a list values. If the list
; is bigger than the area, don't use the whole list. If the
; list is smaller, repeat it as many times as necessary.
FILL:
	CALL	DSRANGE 		; Get range to fill

	PUSH	CX			; Save length
	PUSH	AX			; Save segment number
	PUSH	DX			; Save displacement
	CALL	LIST			; Get list of values to fill w

	POP	DI			; Displacement in segment
	POP	ES			; Segment
	POP	CX			; Length
	CMP	BX,CX			; BX is length of fill list
	MOV	SI,OFFSET DG:BYTEBUF	; List is in byte buffer
	JCXZ	BIGRNG

	JAE	COPYLIST		; If list is big, copy part of

BIGRNG:
	SUB	CX,BX			; How much bigger is area than
	XCHG	CX,BX			; CX=length of list
	PUSH	DI			; Save starting addr. of area
	REP	MOVSB			; Move list into area
	POP	SI
; The list has been copied into the beginning of the
; specified area of memory. SI is the first address
; of that area, DI is the end of the copy of the list
; plus one, which is where the list will begin to repeat.
; All we need to do now is copy [SI] to [DI] until the
; end of the memory area is reached. This will cause the
; list to repeat as many times as necessary.
	MOV	CX,BX			; Length of area minus list
	PUSH	ES			; Different index register
	POP	DS			; requires different segment r
	JMP	SHORT COPYLIST		; Do the block move

; Search a specified area of memory for given list of bytes.
; Print address of first byte of each match.
SEARCH:
	CALL	DSRANGE 		; Get area to be searched

	PUSH	CX			; Save count
	PUSH	AX			; Save segment number
	PUSH	DX			; Save displacement
	CALL	LIST			; Get search list

	DEC	BX			; No. of bytes in list-1
	POP	DI			; Displacement within segment
	POP	ES			; Segment
	POP	CX			; Length to be searched
	SUB	CX,BX			;  minus length of list
SCAN:
	MOV	SI,OFFSET DG:BYTEBUF	; List kept in byte buffer
	LODSB				; Bring first byte into AL
DOSCAN:
	SCASB				; Search for first byte
	LOOPNE	DOSCAN			; Do at least once by using LO

	JNZ	RET1			; Exit if not found

	PUSH	BX			; Length of list minus 1
	XCHG	BX,CX
	PUSH	DI			; Will resume search here
	REPE	CMPSB			; Compare rest of string
	MOV	CX,BX			; Area length back in CX
	POP	DI			; Next search location
	POP	BX			; Restore list length
	JNZ	TTEST			 ; Continue search if no match

	DEC	DI			; Match address
	CALL	OUTDI			; Print it

	INC	DI			; Restore search address
	CALL	HEX_ADDRESS_ONLY	; Print the addresss

	CALL	CRLF

TTEST:
	JCXZ	RET1

	JMP	SHORT SCAN		; Look for next occurrence

; Get the next parameter, which must be a hex number.
; CX is maximum number of digits the number may have.

;=========================================================================
; GETHX: This routine calculates the binary representation of an address
;	 entered in ASCII by a user.  GETHX has been modified to provide
;	 support for sector addresses > 32mb.  To do this the bx register
;	 has been added to provide a 32 bit address.  BX is the high word
;	 and DX is the low word.  For routines that rely on DX for a 16
;	 bit address, the use of BX will have no effect.
;
;	Date	   : 6/16/87
;=========================================================================

GETHX:
	CALL	SCANP
GETHX1:
	XOR	DX,DX			; Initialize the number
	xor	bx,bx			;an000;initialize high word for
					;      sector address
	CALL	HEXIN			; Get a hex digit

	JC	HXERR			; Must be one valid digit

	MOV	DL,AL			; First 4 bits in position
GETLP:
	INC	SI			; Next char in buffer
	DEC	CX			; Digit count
	CALL	HEXIN			; Get another hex digit?

	JC	RETHX			; All done if no more digits

	STC
	JCXZ	HXERR			; Too many digits?


	call	ADDRESS_32_BIT		;an000;multiply by 32
	JMP	SHORT GETLP		; Get more digits

GETHEX:
	CALL	GETHX			; Scan to next parameter

	JMP	SHORT GETHX2

GETHEX1:
	CALL	GETHX1
GETHX2:
	JC	PERROR
RETHX:
	CLC
HXERR:
	RET

; Check if next character in the input buffer is a hex digit
; and convert it to binary if it is. Carry set if not.
HEXIN:
	MOV	AL,[SI]
; Check if AL  is a hex digit and convert it to binary if it
; is. Carry set if not.
HEXCHK:
	SUB	AL,CHAR_ZERO		; Kill ASCII numeric bias
	JC	RET2

	CMP	AL,10
	CMC
	JNC	RET2			; OK if 0-9

	AND	AL,5FH
	SUB	AL,7			; Kill A-F bias
	CMP	AL,10
	JC	RET2

	CMP	AL,16
	CMC
RET2:
	RET

; Process one parameter when a list of bytes is
; required. Carry set if parameter bad. Called by LIST.
LISTITEM:
	CALL	SCANP			; Scan to parameter

	CALL	HEXIN			; Is it in hex?

	JC	STRINGCHK		; If not, could be a string

	MOV	CX,2			; Only 2 hex digits for bytes
	push	bx			;an000;save it - we stomp it
	CALL	GETHEX			; Get the byte value
	pop	bx			;an000;restore it

	MOV	[BX],DL 		; Add to list
	INC	BX
GRET:
	CLC				; Parameter was OK
	RET

STRINGCHK:
	MOV	AL,[SI] 		; Get first character of param
	CMP	AL,SINGLE_QUOTE 	; String?
	JZ	STRING

	CMP	AL,DOUBLE_QUOTE 	; Either quote is all right
	JZ	STRING

	STC				; Not string, not hex - bad
	RET
STRING:
	MOV	AH,AL			; Save for closing quote
	INC	SI
STRNGLP:
	LODSB				; Next char of string
	CMP	AL,CR			; Check for end of line
	JZ	PERR			; Must find a close quote

	CMP	AL,AH			; Check for close quote
	JNZ	STOSTRG 		; Add new character to list

	CMP	AH,[SI] 		; Two quotes in a row?
	JNZ	GRET			; If not, we're done

	INC	SI			; Yes - skip second one
STOSTRG:
	MOV	[BX],AL 		; Put new char in list
	INC	BX
	JMP	SHORT STRNGLP		; Get more characters

; Get a byte list for ENTER, FILL or SEARCH. Accepts any number
; of 2-digit hex values or character strings in either single
; (') or double (") quotes.
LIST:
	MOV	BX,OFFSET DG:BYTEBUF	; Put byte list in the byte buffer
LISTLP:
	CALL	LISTITEM		; Process a parameter

	JNC	LISTLP			; If OK, try for more

	SUB	BX,OFFSET DG:BYTEBUF	; BX now has no. of bytes in list
	JZ	PERROR			; List must not be empty

; Make sure there is nothing more on the line except for
; blanks and carriage return. If there is, it is an
; unrecognized parameter and an error.
GETEOL:
	CALL	SCANB			; Skip blanks

	JNZ	PERROR			; Better be a RETURN
RET3:
	RET

; Command error.  SI has been incremented beyond the command letter so it must
; decremented for the error pointer to work.
PERR:
	DEC	SI
; Syntax error.  SI points to character in the input buffer which caused
; error.  By subtracting from start of buffer, we will know how far to tab
; over to appear directly below it on the terminal.  Then print "^ Error".
PERROR:
	SUB	SI,OFFSET DG:(BYTEBUF-1) ; How many char processed so far?
	MOV	CX,SI			; Parameter for TAB in CX
	MOV	DI,OFFSET DG:ARG_BUF	;
	CALL	TAB			; Directly below bad char

	MOV	BYTE PTR [DI],0 	; nul terminate the tab
	MOV	DX,OFFSET DG:SYNERR_PTR ; Error message
; Print error message and abort to command level
PRINT:
	CALL	PRINTF_CRLF

	JMP	COMMAND

; Gets an address in Segment:Displacement format. Segment may be omitted
; and a default (kept in BP) will be used, or it may be a segment
; register (DS, ES, SS, CS). Returns with segment in AX, OFFSET in DX.
ADDRESS:
	CALL	GET_ADDRESS

	JC	PERROR

ADRERR:
	STC
	RET

GET_ADDRESS:
	CALL	SCANP

	MOV	AL,[SI+1]
	CMP	AL,UPPER_S
	JZ	SEGREG

	MOV	CX,4
	CALL	GETHX

	JC	ADRERR

	MOV	AX,BP			; Get default segment
	CMP	BYTE PTR [SI],CHAR_COLON
	JNZ	GETRET

	PUSH	DX
GETDISP:
	INC	SI			; Skip over ":"
	MOV	CX,4
	CALL	GETHX

	POP	AX
	JC	ADRERR

GETRET:
	CLC
	RET

SEGREG:
	MOV	AL,[SI]
	MOV	DI,OFFSET DG:SEGLET	; SEGLET  DB  "CSED"
	MOV	CX,4
	REPNE	SCASB
	JNZ	ADRERR

	INC	SI
	INC	SI
	SHL	CX,1
	MOV	BX,CX
	CMP	BYTE PTR [SI],CHAR_COLON
	JNZ	ADRERR

	PUSH	[BX+DSSAVE]
	JMP	SHORT GETDISP

SEGLET	DB	"CSED"			; First letter of each of the segregs: CS,SS,ES,DS

; Short form of ENTER command. A list of values from the
; command line are put into memory without using normal
; ENTER mode.
GETLIST:
	CALL	LIST			; Get the bytes to enter

	POP	DI			; Displacement within segment
	POP	ES			; Segment to enter into
	MOV	SI,OFFSET DG:BYTEBUF	; List of bytes is in byte buffer
	MOV	CX,BX			; Count of bytes
	REP	MOVSB			; Enter that byte list
	RET

; Enter values into memory at a specified address.  If the line contains
; nothing but the address we go into "enter mode", where the address and its
; current value are printed and the user may change it if desired.  To change,
; type in new value in hex.  Backspace works to correct errors.  If an illegal
; hex digit or too many digits are typed, the bell is sounded but it is
; otherwise ignored.  To go to the next byte (with or without change), hit
; space bar.  To back CLDto a previous address, type "-".  On every 8-byte
; boundary a new line is started and the address is printed.  To terminate
; command, type carriage return.
;  Alternatively, the list of bytes to be entered may be included on the
; original command line immediately following the address.  This is in regular
; LIST format so any number of hex values or strings in quotes may be entered.
ENTERDATA:
	MOV	BP,[DSSAVE]		; Set default segment to DS
	CALL	ADDRESS

	PUSH	AX			; Save for later
	PUSH	DX
	CALL	SCANB			; Any more parameters?

	JNZ	GETLIST 		; If not end-of-line get list

	POP	DI			; Displacement of ENTER
	POP	ES			; Segment
GETROW:
	CALL	OUTDI			; Print address of entry

	PUSH	DI
	PUSH	ES
	PUSH	DS
	POP	ES
	MOV	DI,OFFSET DG:ARG_BUF
	CALL	BLANK

	XOR	AL,AL
	STOSB
	CALL	HEX_ADDRESS_STR

	POP	ES
	POP	DI
GETBYTE:
	MOV	AL,ES:[DI]		; Get current value
	PUSH	DI
	PUSH	ES
	PUSH	DS
	POP	ES
	MOV	DI,OFFSET DG:ARG_BUF
	CALL	HEX			; And display it

	MOV	AL,CHAR_PERIOD
	STOSB
	XOR	AL,AL
	STOSB
	MOV	DX,OFFSET DG:ARG_BUF_PTR
	CALL	STD_PRINTF

	POP	ES
	POP	DI
LOOK_AGAIN:
	MOV	CX,2			; Max of 2 digits in new value
	MOV	DX,0			; Intial new value
GETDIG:
	CALL	INPT			; Get digit from user

	MOV	AH,AL			; Save
	CALL	HEXCHK			; Hex digit?

	XCHG	AH,AL			; Need original for echo
	JC	NOHEX			; If not, try special command

	MOV	DH,DL			; Rotate new value
	MOV	DL,AH			; And include new digit
	LOOP	GETDIG			; At most 2 digits

; We have two digits, so all we will accept now is a command.
DWAIT:
	CALL	INPT			; Get command character
NOHEX:
	CMP	AL,CHAR_BACKSPACE	; Backspace
	JZ	BS

	CMP	AL,CHAR_RUBOUT		; RUBOUT
	JZ	RUB

	CMP	AL,CHAR_MINUS		; Back up to previous address
	JZ	PREV

	CMP	AL,CR			; All done with command?
	JZ	EOL

	CMP	AL,CHAR_BLANK		; Go to next address
	JZ	NEXT

	MOV	AL,CHAR_BACKSPACE
	CALL	OUT_CHAR		; Back up over illegal character

	CALL	BACKUP

	JCXZ	DWAIT

	JMP	SHORT GETDIG

RUB:
	MOV	AL,CHAR_BACKSPACE
	CALL	OUT_char
BS:
	CMP	CL,2			; CX=2 means nothing typed yet
	JZ	PUTDOT			; Put back the dot we backed up over

	INC	CL			; Accept one more character
	MOV	DL,DH			; Rotate out last digit
	MOV	DH,CH			; Zero this digit
	CALL	BACKUP			; Physical backspace

	JMP	SHORT GETDIG		; Get more digits

PUTDOT:
	MOV	AL,CHAR_PERIOD
	CALL	OUT_CHAR

	JMP	LOOK_AGAIN

; If new value has been entered, convert it to binary and
; put into memory. Always bump pointer to next location
STORE:
	CMP	CL,2			; CX=2 means nothing typed yet
	JZ	NOSTO			; So no new value to store

; Rotate DH left 4 bits to combine with DL and make a byte value
	PUSH	CX
	MOV	CL,4
	SHL	DH,CL
	POP	CX
	OR	DL,DH			; Hex is now converted to binary
	MOV	ES:[DI],DL		; Store new value
NOSTO:
	INC	DI			; Prepare for next location
	RET

NEXT:
	CALL	STORE			; Enter new value

	INC	CX			; Leave a space plus two for
	INC	CX			;  each digit not entered
	PUSH	DI
	MOV	DI,OFFSET DG:ARG_BUF
	PUSH	ES
	PUSH	DS
	POP	ES
	CALL	TAB

	XOR	AL,AL
	STOSB
	MOV	DX,OFFSET DG:ARG_BUF_PTR
	CALL	STD_PRINTF

	POP	ES
	POP	DI
	MOV	AX,DI			; Next memory address
	AND	AL,7			; Check for 8-byte boundary
	JZ	NEWROW			; Take 8 per line

	JMP	GETBYTE

NEWROW:
	CALL	CRLF			; Terminate line

	JMP	GETROW			; Print address on new line

PREV:
	CALL	STORE			; Enter the new value

; DI has been bumped to next byte. Drop it 2 to go to previous addr
	DEC	DI
	DEC	DI
	JMP	SHORT NEWROW		; Terminate line after backing	 CLD

EOL:
	CALL	STORE			; Enter the new value

	JMP	CRLF			; CR/LF and terminate

; Console input of single character
	IF	SYSVER
INPT:					  ;*** change for build - label to inpt
	    PUSH    DS
	    PUSH    SI
	    LDS     SI,CS:[CIN]
	    MOV     AH,4
	    CALL    DEVIOCALL

	    POP     SI
	    POP     DS
	    CMP     AL,3
	    JNZ     NOTCNTC

	    INT     VEC_CTRL_BREAK	;23H

NOTCNTC:
	    CMP     AL,UPPER_P - CHAR_AT_SIGN
	    JZ	    PRINTON

	    CMP     AL,UPPER_N - CHAR_AT_SIGN
	    JZ	    PRINTOFF

	    CALL    OUT_CHAR

	    RET

PRINTOFF:
PRINTON:
	    NOT     [PFLAG]
	    JMP     SHORT IN

	ELSE
INPT:				; Change label for build
	    MOV     AH,Std_Con_Input ;OPTION=1, STANDARD CONSOLE INPUT
	    INT     21H

	    RET

	ENDIF
OUT_CHAR:
	PUSH	DI
	PUSH	DX
	PUSH	ES
	PUSH	DS
	POP	ES
	MOV	DI,OFFSET DG:ONE_CHAR_BUF
	STOSB
	MOV	AL,0
	STOSB
	MOV	DX,OFFSET DG:ONE_CHAR_BUF_PTR
	CALL	STD_PRINTF

	POP	ES
	POP	DX
	POP	DI
	RET

;=========================================================================
; ADDRESS_32_BIT: This routine will build an address for 32bit sector
;		  addressibility.  BX will be the high word, with DX being
;		  the low word.
;
;	Inputs : DX/BX - registers to contain 32bit sector address
;		 DX & BX are both initialized to 0 on first call to routine.
;
;	Outputs: DX/BX - registers to contain 32bit sector address
;
;	Date	  : 6/16/87
;=========================================================================

ADDRESS_32_BIT	proc	near			;an000;perform 32 bit address
						;      creation
	push	cx				;an000;save affected regs.
	mov	cx,04h				;an000;initialize to
						;      nibble shift
;	$do					;an000;while cx not= 0
$$DO1:
		cmp	cx,00h			;an000;are we done?
;		$leave	e			;an000;yes, quit loop
		JE $$EN1
		shl	bx,1			;an000;shift bx 1 bit
		shl	dx,1			;an000;shift dx 1 bit
;		$if	c			;an000;did low word carry
		JNC $$IF3
			or	bx,01h		;an000;set bit 0 of high word
;		$endif				;an000;
$$IF3:
		dec	cx			;an000;decrease counter
;	$enddo					;an000;end while loop
	JMP SHORT $$DO1
$$EN1:
	or	dl,	al			;an000;overlay low word
						;      bits 0-3 with next
						;      portion of the address
	pop	cx				;an000;restore affected regs.

	ret					;an000;return to caller

ADDRESS_32_BIT	endp				;an000;end proc



CODE	ENDS
	END	DEBCOM1
