home *** CD-ROM | disk | FTP | other *** search
- ; This is version 1.01 of HILOAD
- ;
- ; See accompanying .DOC file for theory of
- ; operation and instructions
- ;
- ; No guarantees, but the author would appreciate
- ; information on bugs.
- ;
- ; Larry Shannon 18 Jun 89
- ;
- ; Equates
- ;
- CR EQU 0D
- LF EQU 0A
- SPACE EQU 020
- MON EQU MOV ; Common typo
- ONE EQU 1
- TWO EQU 2
- DOLLAR EQU 024
- ZERO EQU 0
- BELL EQU 07
- ;.....
- ;
- ; Macros
- ;
- PRINT MACRO ; Usage: print MSG1
- PUSH AX ; All registers preserved
- PUSH DX
- MOV AH,9
- LEA DX, #1
- INT 021
- POP DX
- POP AX
- #EM
- ;
- PRINT$ MACRO ; Usage: print$,"MESSAGE"
- PUSH AX ; Prints at current cursor position
- PUSH DX
- JMP >M1
- M0:
- DB #1
- DB "$"
- M1:
- MOV AH,9 ; All registers preserved
- LEA DX,M0
- INT 021
- POP DX
- POP AX
- #EM
- ;
- QUIT MACRO ; Usage: quit 0
- MOV AH,04C ; Must give some value
- MOV AL,#1
- INT 021
- #EM
- ;
- NEWLINE MACRO ; Equivalent to CR,LF
- PUSH AX ; Scrolls if off screen
- PUSH DX
- JMP > M1
- M0:
- DB 0D,0A,'$'
- M1:
- LEA DX,M0
- MOV AH,9
- INT 021
- POP DX
- POP AX
- #EM
- ;
- SPLIT MACRO AAM 16 #EM ; Be careful with these with
- ; ; Nec v-20/v-30 chips!
- UNSPLIT MACRO ; This macro will effectively
- PUSH CX ; Do the same thing, and should be
- MOV CX,4 ; Compatible with all pc's
- ROL AH,CL
- AND AH,0F0
- OR AL,AH
- POP CX
- #EM
- ;
- HEX_TO_PRNT MACRO ; Changes an 8-bit register quantity
- OR #1,030 ; From 0-f to the ascii equivalent
- CMP #1,039 ; Register must be in form 00 to 0f
- ;
- IF A ADD #1,7
- #EM
- ;
- PRINT_REG MACRO ; Used to print a register (or any 16-bit
- JMP > M1 ; Quantity) at the current cursor position
- M0:
- DB 5 DUP ('$')
- M1:
- PUSH AX ; Usage - print_reg AX
- MOV AX,#1 ; Prints the 16-bit quantity in hex
- XCHG AH,AL
- PUSH AX
- MAKE_HEX_ASCII
- XCHG AH,AL
- MOV W[M0],AX
- POP AX
- XCHG AH,AL
- MAKE_HEX_ASCII
- XCHG AH,AL
- MOV W[M0+2],AX
- PRINT M0
- POP AX
- #EM
- ;
- PRINT_32_DEC MACRO ; Macro to print a 32-bit hex number
- PUSH AX ; As a decimal string
- PUSH DX ; Enter with si pointing to two-word
- PUSH DI ; (four byte) quantity to be converted
- MOV DX,W[SI] ; Most significant word first
- MOV AX,W[SI+2] ; Prints at current cursor position
- JMP > M1 ; All registers restored
- M0:
- DB 11 DUP ('$')
- M1:
- LEA DI,M0
- ADD DI,9
- CALL LARGE_HEX_TO_ASCII
- MOV DX,DI
- MOV AH,9
- INT 021
- POP DI
- POP DX
- POP AX
- #EM
- ;
- REG_TO_PRINT MACRO ; Converts a 16-bit quantity to ascii
- PUSH AX ; And puts the resultant string in a
- PUSH BX ; Place pointed to by ds:si
- MOV BX,#1 ; All registers restored
- MOV AL,BH
- CALL HEX2PRNT
- MOV [SI],AX
- MOV AL,BL
- CALL HEX2PRNT
- MOV [SI+2],AX
- POP BX
- POP AX
- #EM
- ;
- MAKE_CAP MACRO ; Makes letters capitals
- CMP #1,061 ; Useage make_cap AH
- JB > M1 ; Ah contains a candidate ascii letter
- CMP #1,07A ; From A-Z or a-z
- JA > M1 ; Returns A-Z
- AND #1,0DF
- M1:
- NOP
- #EM
- ;
- MAKE_HEX_ASCII MACRO ; Makes al in hex into two ascii
- SPLIT ; Characters in ah:al
- HEX_TO_PRNT AH
- HEX_TO_PRNT AL
- #EM
- ;.....
- ;
- ; Data and strings
- ;
- ;
- ORG 0100
- ;
- ;
- HILOAD: JMP LONG > L0
-
- LOAD_BLOCK DW 0,0
- FILE_STRING DB 65 DUP('$')
- TAIL_PTR DW 0
- FILE_PTR DW 0
- OLD_INT_27 DW 0,0
- OLD_INT_21 DW 0,0
- START_ADDR DW 0100,0
- TAIL_BFR DB 127 DUP ('020')
- SW2127 DB 0
- TEMPWRDS DW 0,0
- BAR DB 40 DUP ('*'),'$'
- RESET_MSG DB CR,LF,'Resetting ICA area',CR,LF,'$'
- DEFAULT_ENV DB 'HILOAD',0
- INT_MSG DB 'Interupt '
- INT_NUM DB 0,0,'H is now located at '
- INT_SEG DB 0,0,0,0,':'
- INT_OFF DB 0,0,0,0,CR,LF,'$'
- TEMP DW 0
- LOAD_POINT DW 0,0
- LP_PLUS_BYTES DW 0,0
- INT_ADDR_1 DW 0
- INT_ADDR_2 DW 0
- ;
- NEW_INT21:
- CMP AH,031 ; New address for int 21h
- JE > Z21 ; Is it TSR termination?
- CMP AX,02521 ; Setting vector for int 21h?
- JE > Z25 ; If so, save it
- CMP AX,03521 ; Request for int 21h address?
- JE > Z35 ; If so, give him original address
- CS JMP D[OLD_INT_21] ; Otherwise, do real int 21h
- Z25:
- CS MOV OLD_INT_21,DX ; Here we save int 21h address info
- CS MOV OLD_INT_21+2,DS
- IRET ; And return to caller
- Z35:
- CS MOV BX,[OLD_INT_21] ; Here we give him original address
- CS MOV ES,[OLD_INT_21+2]
- IRET ; And return to caller
- Z21:
- CS MOV SW2127,0 ; Exiting via int 21 - set switch for
- JMP > Z22 ; Storage return handling
- ;.....
- ;
- NEW_INT27:
- CS MOV SW2127,1 ; Trap for int 27h - set switch
- Z22:
- MOV AX,CS ; Get our code segment
- MOV BX,DX ; Save return size info
- MOV DS,AX ; Set up local addressability
- MOV ES,AX ; Make sure other registers are
- MOV SS,AX ; What they should be
- MOV DX,[OLD_INT_27] ; Find original address of int 27h
- MOV AX,[OLD_INT_27+2] ; Segment portion
- MOV ES,0 ; Addressing bottom page
- ES MOV W[09C],DX ; Store vector addresses directly
- ES MOV W[09E],AX ; Since int 21h cannot be used to do
- MOV DX,[OLD_INT_21] ; The job - we've trapped it above!
- MOV AX,[OLD_INT_21 + 2] ; Do the same with int 21h
- MOV ES,0
- ES MOV W[084],DX ; And store its address in the
- ES MOV W[086],AX ; Proper place in the table
- NEWLINE ; Space a line
- PRINT$ 'Saved bytes = ' ; Start of message
- CMP SW2127,1 ; See how we terminated; 1=int 27h so
- JE > Q2 ; Returns bytes - int 21h returns para-
- MOV AX,BX ; Graphs - here we're converting
- XOR DX,DX ; Paragraphs to bytes by multiplying
- MOV CX,4 ; By 4 (shift left 4 places)
- Q1:
- RCL AX,1 ; Have to allow for greater than 64k
- PUSHF ; Save flags with state of carry bit
- ROL DX,1
- POPF ; Get flags back
- ADC DX,0 ; Add in and include carry
- LOOP Q1 ; Carry on
- JMP > Q3
- Q2:
- MOV AX,BX ; Size info in bx - do setup for
- XOR DX,DX ; Conversion
- Q3:
- MOV TEMPWRDS,DX ; Temporarily store upper and lower
- MOV TEMPWRDS + 2,AX ; Halves of return size info (32 bits)
- PUSH DX ; Save dx
- MOV DX,[LOAD_POINT] ; Get where we started
- MOV LP_PLUS_BYTES,DX ; Put it here
- POP DX ; Retrieve dx
- ADD LP_PLUS_BYTES,DX ; Add size info
- MOV LP_PLUS_BYTES+2,AX ; Store upper half here
- LEA SI,TEMPWRDS ; Point to temporary storage
- PRINT_32_DEC ; Print out size in bytes
- NEWLINE ; Do new line
- MOV DX,[TEMPWRDS] ; Get back size info
- MOV AX,[TEMPWRDS+2]
- CLC ; Clear the carry
- MOV CX,4 ; We're going to convert to a 32-bit
- Q7:
- SHR DX,1 ; Number here and store it in
- PUSHF ; The ica area
- RCR AX,1
- POPF
- LOOP Q7
- MOV ES,040 ; Point to segment of ica
- ES MOV BX,[0F0] ; Get what was there
- ADD DX,BX ; Add new size
- ES MOV [0F0],DX ; And put it back
- ES MOV BX,[0F2] ; Get old lower half
- ADD AX,BX ; Add new bytes saved data
- INC AX ; Allow for truncation
- ES MOV [0F2],AX ; And put it back
-
- NEWLINE ; Start of trap info
- PRINT$ 'This TSR traps the following interrupts:'
- NEWLINE ; Some spaces
- NEWLINE
- ;
- ; Here is where we look to see what interrupts are trapped
- ;
- MOV CX,0FF ; Look at 256 interrupts
- MOV AX,03500 ; Set up call
- H1:
- PUSH CX ; Save registers
- PUSH AX
- INT 021 ; Get interrupt addresses
- MOV AX,BX ; Ax is offset
- MOV DX,ES ; Dx:ax is addr of interrupt
- MOV INT_ADDR_1,AX ; Store offset away
- MOV INT_ADDR_2,DX ; Store segment
- CALL ADD_SEG_OFF ; Convert to 32-bit number
- XCHG BX,DX ; Now bx:cx is int addr
- XCHG CX,AX ; In 32-bit form
- MOV DX,[LOAD_POINT] ; Where do we start
- XOR AX,AX ; No offset from start
- CALL ADD_SEG_OFF ; Make 32-bitter
- CALL CMP_32 ; Is int address beyond start point?
- JNC > H2 ; If below, can't be us - get out
- MOV DX,[LP_PLUS_BYTES]
- MOV AX,[LP_PLUS_BYTES + 2] ; Dx:ax now address of end of pgm
- CALL ADD_SEG_OFF ; Make 32-bits
- CALL CMP_32 ; Compare them
- JC > H2 ; If greater - beyond me
- POP AX ; We got one - retrieve interrupt
- PUSH AX ; And save function and int number
- CALL HEX2PRNT ; Get interrupt number in ascii
- LEA SI,INT_NUM ; Point to proper place
- MOV W[SI],AX ; Store it
- LEA SI,INT_SEG ; Point to place
- REG_TO_PRINT [INT_ADDR_2] ; Get segment in ascii
- LEA SI,INT_OFF ; Point to place
- REG_TO_PRINT [INT_ADDR_1] ; Print offset in ascii
- PRINT INT_MSG ; Print whole message
- H2:
- POP AX ; Get registers back
- INC AX
- POP CX
- DEC CX
- JCXZ > H3 ; Are we done?
- JMP LONG H1 ; No - go back for more
- H3:
- QUIT 0 ; We're done - exit
- ;.....
- ;
- ;=======================================================================
- ; Main program starts here
- ;=======================================================================
- ;
- L0:
- NEWLINE ; Give us some space
- PRINT BAR ; Print banner bar
- NEWLINE ; Another space
- MOV AH,[080] ; See if any comand tail
- CMP AH,1
- JA > L1
- L00:
- MOV ES,040 ; If no tail, reset ica
- ES MOV W[0F0],0
- ES MOV W[0F2],0
- PRINT RESET_MSG ; Write message
- QUIT 0 ; And get out - normal exit
- L1:
- MOV DI,080 ; Point to command tail
- L22:
- INC DI
- MOV AH,[DI]
- CMP AH,020 ; Bumping past the spaces here
- JE L22
- MOV FILE_PTR,DI ; Point to file name
- L222:
- MOV AH,[DI]
- CMP AH,SPACE
- JE > L555
- CMP AH,CR
- JE > L555
- INC DI
- JMP L222
- MOV AL,CR ; Look for carriage return
- MOV CX,0100 ; Look for a long time!
- CLD
- REPNE SCASB
- JCXZ L00 ; Get out if no find one
- DEC DI
- L555:
- MOV TAIL_PTR,DI ; Save pointer to command tail
- PUSH DI
- LEA BX,TAIL_BFR ; Point to command tail (saved)
- L16:
- MOV AH,[DI] ; Get element
- CMP AH,CR ; End of tail?
- JE > L17
- MOV [BX],AH ; Stuff it away
- INC DI ; Bump pointers
- INC BX
- JMP L16 ; Do again
- L17:
- MOV B[BX],CR ; Terminate tail
- POP DI
- LEA BX,FILE_STRING ; Point to buffer to store file name
- MOV DI,[FILE_PTR] ; Get pointer to program in command tail
- L33:
- MOV AH,[DI] ; Build the name, char by char
- MAKE_CAP AH ; Make sure all caps
- MOV [BX],AH ; Stuff it away
- INC BX ; Bump pointers
- INC DI
- CMP DI,[TAIL_PTR] ; Are we done?
- JB L33 ; If not, carry on
- MOV W[BX],'C.' ; Stick in ".COM" extension
- MOV W[BX+2],'MO' ; Reversed - that's the way intel works
- MOV B[BX+4],0 ; End with 0 to make asciiz string
- LEA DX,FILE_STRING ; Point dx to the file
- MOV AH,04E ; Find file
- MOV CX,027 ; File attribute byte - this works
- INT 021 ; Do it
- JC > L77 ; Did we find it?
- JMP LONG L78 ; Got it! go process it
- L77:
- NEWLINE ; Couldn't find file
- NEWLINE
- PRINT$ 'Cant find file ' ; So say so
- MOV B[DI-1],'$' ; Put in string delimiter and print
- PRINT FILE_STRING ; What we were looking for
- PRINT$ ' ...ABORTING' ; Sorry charlie
- NEWLINE
- NEWLINE
- QUIT 3 ; Quit with error level = 3
- L78:
- MOV AL,' ' ; Looking for a space
- MOV CX,100 ; Up to 256 bytes back
- STD ; Scan backwards
- REPNE SCASB ; And search
- LEA DX,FILE_STRING ; Ok, now at start of file string
- PUSH DI ; Save pointer
- MOV B[DI-1],0 ; Make asciiz string
- PUSH BX
- PUSH CX
- MOV AH,030 ; Check dos version level
- INT 021
- POP CX
- POP BX
- CMP AL,2 ; At least version 2?
- JAE > V1
- NEWLINE ; If not, dump out
- PRINT$ 'Requires DOS 2.0 or above ... ABORTING'
- NEWLINE
- QUIT 2 ; Bad dos version - error level = 2
- V1:
- CMP AL,3 ; Version 3.0 or above?
- JAE > V2 ; If it is, we're ok
- LEA SI,DEFAULT_ENV ; Set up default envir var name
- JMP > V3
- V2:
- CALL WHOAMI ; Find out this programs'name
- V3:
- CALL GET_ENV_VAR ; Get the environment value
- JC > L88 ; Did we get a match?
- JMP LONG L888 ; Yes, we did
- L88:
- NEWLINE ; No we didn't
- PRINT$ 'No address given ... ABORTING'
- QUIT 1 ; Bad environment variable - error
- L888:
- PUSH DS
- PUSH ES
- POP DS
- CALL ASC_2_NUMS ; Convert the ascii to hex values
- POP DS
- MOV START_ADDR+2,AX ; That's our starting address
- MOV ES,040
- ES ADD AX,[0F0] ; Add the last loads' space
- ES ADD AX,[0F2]
- ADD AX,010 ; Allow for psp
- MOV LOAD_BLOCK,AX ; This is out new loading address
- SUB AX,010 ; Remove psp allowance
- NEWLINE ; Starting load message
- PRINT$ 'Loading '
- POP DI
- MOV B[DI-1],'$' ; Make printable
- PRINT FILE_STRING ; And print it
- PRINT$ 'at segment '
- PRINT_REG AX ; Print segment address
- LEA BX,LOAD_BLOCK ; Where we load
- PUSH ES
- PUSH DS
- POP ES
- MOV AH,04B ; Dos exec function
- MOV AL,3 ; Load but don't execute
- INT 021 ; Do it
- POP ES
- MOV AX,[LOAD_BLOCK] ; Loading address again
- SUB AX,010 ; Allow for psp
- MOV START_ADDR + 2,AX ; Stuff it away
- MOV LOAD_POINT,AX ; And here
- MOV LP_PLUS_BYTES,AX ; And here, too
- MOV ES,AX ; Segment of where tsr is loaded
- MOV CX,0100 ; Going to transfer 256 bytes
- XOR SI,SI ; Of the psp (we're using the one
- XOR DI,DI ; We got from dos)
- CLD ; Set direction flag
- REP MOVSB ; Transfer it
- MOV DI,081 ; Point to com tail in new psp
- LEA SI,TAIL_BFR
- XOR AL,AL ; Count of command tail length
- L98:
- MOV AH,[SI]
- CMP AH,CR ; Any command tail at all?
- JE > L99
- ES MOV [DI],AH ; If so, start transferring the
- INC AL ; Tsr's command tail - he might
- INC DI ; Need it
- INC SI
- JMP L98
- L99:
- MOV B[SI],'$' ; Again, for dos int 21h printing
- NEWLINE
- PRINT$ 'Command tail = ' ; Printing out the supplied
- PRINT TAIL_BFR ; Command tail
- MOV B[SI],CR ; Terminate
- ES MOV B[DI],CR ; Terminate new tail
- ES MOV [080],AL ; Put in count
- ES MOV B[081],SPACE ; And normal space
- ;
- ; Here we start revectoring the appropriate interrupts
- ;
- MOV AH,035 ; The 'gimme address' function
- MOV AL,027 ; For interrupt 27h
- INT 021 ; Go get it
- MOV AX,ES ; Its segment
- MOV OLD_INT_27,BX ; Store offset value
- MOV (OLD_INT_27 + 2),AX ; Store segment value
- LEA DX,NEW_INT27 ; Where we're going to point to
- MOV AH,025 ; Tell dos about it
- MOV AL,027 ; For int 27h
- INT 021 ; Do it
- MOV AH,035 ; Get address function again
- MOV AL,021 ; This time for int 21h
- INT 021 ; Do it
- MOV AX,ES
- MOV OLD_INT_21,BX ; Save offset
- MOV (OLD_INT_21 + 2),AX ; And segment
- LEA DX,NEW_INT21 ; Point to my routine
- MOV AH,025 ; And tell dos
- MOV AL,021
- INT 021
- MOV AX,[START_ADDR+2] ; Get address of routine
- MOV ES,AX ; Set up registers
- MOV DS,AX ; But don't change stack reg (ss)!!
- CS JMP D[START_ADDR] ; And execute the program
- ;...
- ;
- ; This is the end of the regular program. We exit when the TSR executes
- ; and INT 27H or an INT 21H with function 31H.
- ;
- ; The following are the various subroutines used
- ;
- ; routine to compare two 32-bit quantities
- ; if BX:CX > DX:AX, carry bit is set
- ; if BX:CX < DX:AX, carry bit is cleared
- ; if BX:CX = DX:AX, zero flag is set
- ;
- ; all registers unchanged
- ;
- CMP_32:
- CMP BX,DX
- JAE > L0
- JMP > L1
- L0:
- JA > L2
- CMP CX,AX
- JB > L1
- L2:
- STC
- RET
- L1:
- CLC
- RET
- ;.....
- ;
- ; Routine to form 32-bit sum of (typically) a segment and offset pair
- ;
- ; enter with "segment" value in DX, "offset" in AX
- ; returns with sum in DX:AX
- ;
- ; all other registers restored
- ;
- ADD_SEG_OFF:
- PUSH BX,CX
- XOR BX,BX
- MOV CX,4
- L0:
- SHL BX,1
- SHL DX,1
- ADC BX,0
- LOOP L0
- ADD AX,DX
- ADC BX,0
- MOV DX,BX
- POP CX,BX
- RET
- ;.....
- ;
- ; Routine to convert a HEX digit to a two byte word containing the
- ; equivalent ASCII characters
- ;
- ; Enter with the byte to be converted in AL
- ; Return with the ASCII string in AX in 'backwords' format
- ; i.e., an AL value of 47 would return AX = 3734
- ; so a MOV W[SI],AX for example would store the values
- ; in memory in the proper order
- ;
- ; All other registers restored
- ;
- ; This is essentially identical to the macro MAKE_HEX_ASCII
- ; except the macro does not interchange AH and AL
- ;
- HEX2PRNT:
- XOR AH,AH ; Zero out upper half
- AAM 16 ; Split into two
- ADD AX,03030 ; Make ASCII
- CMP AH,039 ; Check for a - f
- IF A ADD AH,7
- CMP AL,039
- IF A ADD AL,7
- XCHG AH,AL ; Put in proper order
- RET ; For a MOV innstruction
- ;.....
- ;
- ; Routine to find out the program name.
- ; no parameters on entry.
- ; return with SI pointing to a string containing the file name
- ; with no extent or period.
- ; the string is terminated with a 0.
- ; all registers (except SI) are restored
- ;
- WHOAMI:
- JMP > L0
- MY_NAME:
- DB 9 DUP (0)
- L0:
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH ES
- PUSH DI
- MOV BX,[02C] ; Get seg addr of env
- MOV ES,BX ; Put in es
- XOR DI,DI ; Zero out di
- XOR AX,AX ; Looking for double zeros
- MOV CX,08000 ; Max environment length = 32k
- CLD ; Set direction flag
- L3:
- REPNE SCASB ; Look for zero
- ES MOV BX,W[DI-1]
- CMP BX,0 ; Got two bytes of zero?
- JNE L3
- MOV AL,'.'
- REPNE SCASB ; Looking for extent
- MOV BX,DI ; Save end of string pointer
- L6:
- ES MOV AL,[DI]
- CMP AL,'\'
- JE > L7
- CMP AL,0
- JE > L7
- DEC DI
- JMP L6
- L7:
- MOV SI,DI
- INC SI ; Point to first byte of asciiz
- LEA DI,MY_NAME ; Will store it in this segment
- L2:
- ES MOV AH,[SI]
- CMP AH,'.'
- JE > L1
- MAKE_CAP AH ; Make sure all names are capitals
- MOV [DI],AH
- INC DI
- INC SI
- JMP L2
- L1:
- LEA SI,MY_NAME
- POP DI
- POP ES
- POP CX
- POP BX
- POP AX
- RET
- ;.....
- ;
- ; Routine to find a match between a given string and an environment
- ; variable.
- ;
- ; Enter with DS:SI pointing to a string, terminated by a 0,
- ; which contains the string to be matched.
- ;
- ; Returns with SI pointing to the end of the matching
- ; string in in the environment.
- ;
- ; The environment variables are of the form NAME=string
- ; This routine returns SI pointing to the string, just
- ; after the equal sign.
- ;
- ; ES points to the environment segment on return
- ;
- ; If a matching string is found, the carry bit will be
- ; clear. If no match is found, the carry will be set.
- ;
- ; All other registers are restored; SI not guaranteed.
- ;
- GET_ENV_VAR:
- JMP > L0
- STRING_COUNT:
- DW 0
- L0:
- PUSH AX
- PUSH CX
- PUSH DI
- XOR CX,CX ; Zero out counter
- PUSH SI ; Save pointer
- L1:
- MOV AL,[SI]
- CMP AL,0 ; At end of string?
- JE > L2
- INC SI ; Bump pointer
- INC CX ; Bump counter
- JMP L1
- L2:
- CS MOV STRING_COUNT,CX ; Save counter
- POP SI ; Restore pointer
- CALL GET_ENV_LENGTH ; Get length of environment
- MOV CX,AX ; Set up count
- XOR DI,DI ; Start at beginning
- MOV AX,[02C] ; Environment segment
- MOV ES,AX
- CLD ; Scan forward
- MOV AL,[SI] ; Look for first letter
- L3:
- REPNE SCASB ; Scan for it
- DEC DI ; Back off to point to match
- JCXZ > L99 ; Get out if not there
- PUSH CX ; Save counter
- CS MOV CX,[STRING_COUNT]
- PUSH SI ; Save my old place
- REPE CMPSB ; See if they're all equal
- POP SI ; Restore my place
- JZ > L4
- POP CX ; No match, so carry on
- JMP L3
- L99:
- STC ; Set the carry
- JMP > L5
- L4:
- POP CX ; Clear stack
- MOV SI,DI ; Put pointer in si
- INC SI ; Skip past equal sign
- CLC ; Clear carry
- L5:
- POP DI
- POP CX
- POP AX
- RET
- ;.....
- ;
- ; Routine to find length of environment
- ;
- ; IF CARRY IS CLEAR, RESULT RETURNED IN AX
- ; IF CARRY IS SET, ERROR CONDITION
- ;
- ; IN EITHER EVENT, ALL REGISTERS OTHER THAN AX ARE RESTORED
- ;
- GET_ENV_LENGTH:
- PUSH CX
- PUSH ES
- PUSH DI
- MOV AX,[02C] ; Get segment of environment
- MOV ES,AX
- XOR DI,DI ; Start at beginning of env
- MOV CX,08000 ; Maximum env string = 32k
- L9:
- ES MOV AX,W[DI]
- CMP AX,0
- JE > L0
- INC DI
- LOOP L9
- JCXZ >L1 ; If cx=0, we're in big trouble
- L0:
- MOV AX,DI ; Si is length of env - put it in ax
- CLC ; Clear carry bit - result ok
- JMP > L2
- L1:
- STC ; Set the carry - error
- L2:
- POP DI
- POP ES
- POP CX
- RET
- ;.....
- ;
- ; Routine to convert a 2-digit ASCII pair into a hex number e.g.,
- ; convert 3741 into 7A.
- ;
- ; Enter with the ASCII pair in AX, return with the hex digit
- ; in AL
- ;
- ; If all is well, the carry bit is clear
- ; If the carry bit is set, at least one of the proposed digits
- ; was not in the range (0-9) snd (A-F) (Routine accepts small
- ; letters and makes them caps)
- ;
- ; All other registers unaffected.
- ;
- ASC_2_HEX:
- XCHG AH,AL
- CMP AH,039
- JBE > L0
- AND AH,0DF ; Make caps
- CMP AH,'F'
- JA > L3
- SUB AH,7
- L0:
- CMP AH,030
- JB > L3
- CMP AL,039
- JBE > L1
- AND AL,0DF
- CMP AL,'F'
- JA > L3
- SUB AL,7
- L1:
- CMP AL,030
- JB > L3
- SUB AX,03030
- UNSPLIT
- CLC
- RET
- L3:
- STC
- RET
- ;.....
- ;
- ; Routine to convert a 4-digit ASCII number representation into a
- ; 4-digit hex number e.g., 31374230 -> 17B0
- ;
- ; Enter with DS:SI pointing to the string.
- ; Return with the number in AX, in the proper order
- ; i.e., 31374230 -> AH = 17, AL = B0
- ;
- ; Carry bit set indicates bad ASCII number (out of range) see above
- ;
- ASC_2_NUMS:
- PUSH BX
- MOV AX,W[SI]
- CALL ASC_2_HEX
- JC > L1
- MOV BX,AX
- MOV AX,W[SI+2]
- CALL ASC_2_HEX
- JC > L1
- MOV AH,BL
- POP BX
- CLC
- L1:
- RET
- ;.....
- ;
- ; Routine to convert a 32-bit number to a decimal ASCII string enter
- ; with the number to be converted in DX:AX and DI pointing to the last
- ; byte of the result string area. Return with DI pointing to first
- ; non-zero character of resultant conversion.
- ;
- ; BX, CX, and SI unchanged
- ;
- ; This routine was cribbed from FREE by Art Merrill - I don't really
- ; understand it all, but it works!
- ;
- LARGE_HEX_TO_ASCII:
- PUSH BX
- PUSH CX
- XCHG CX,DX
- MOV BX,10
- L1:
- CMP CX,0
- JE > L2
- XCHG AX,CX
- XOR DX,DX
- DIV BX
- XCHG AX,CX
- DIV BX
- OR DL,030
- MOV [DI],DL
- DEC DI
- JMP L1
- L2:
- XOR DX,DX
- DIV BX
- OR DL,030
- MOV [DI],DL
- DEC DI
- CMP AX,0
- JNE L2
- INC DI ; Back up pointer to first char
- POP CX
- POP BX
- RET
- ;
- end
-