home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Unsorted BBS Collection
/
thegreatunsorted.tar
/
thegreatunsorted
/
programming
/
asm_programming
/
GET.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-06-04
|
42KB
|
1,211 lines
TITLE GET
; Program SDL_GET.ASM (or just GET)
; Purpose Batch file enhancer for use with MASDIR
; Input Command line consisting of:
; Command letter (with optional E for extended)
; Optional prompt enclosed in double quotes
; Optional argument
; Output Number in DOS ERRORLEVEL and string in GET environment variable
BIOS_DATA SEGMENT AT 40H
ORG 84H
CRT_ROWS DB ?
ORG 87H
EGA_INFO DB ?
BIOS_DATA ENDS
DOSSEG
.MODEL small
PAGE 60,120
INCLUDE DOS.INC
.STACK 100h
.DATA
S1 SIZESTR @Filename ; If the name of this file is GET
S2 INSTR @Filename,<get> ; then the $ option will be omitted.
S3 INSTR @Filename,<GET> ; Any other file name will cause the
IF S1 eq 3 AND S2 eq 1 OR S3 eq 1 ; $ option to be assembled in.
GET equ <TRUE>
ENDIF
cr equ "}" ; Surrogate for CR
esc_s equ "~" ; Surrogate for Esc
ext equ "`" ; grave accent indicates that extended keys can be used
MaxSize equ 1000h ; MaxSize of moving text prompt.
help1 LABEL BYTE
DB 13,10
DB " GET -- Bob Stephan's Batch file enhancer -- a public domain utility",13,10
DB " Syntax: GET command argument",13,10
DB "Purpose Command Argument Environment Errorlevel Extended",13,10
DB "--------- ------- -------- --(GET=)--- --(Exit)-- --[E]---",13,10
DB 'Get character C[E] ["prompt"] [chars] Character ASCII dec. No Echo',13,10
DB 'Get yes/no aNswer N[E] ["prompt"] None Character ASCII dec. No Echo',13,10
DB 'Get string S[E] ["prompt"] None String Length No Echo',13,10
DB 'Moving Text(GetaKey)T[E] "Filespec" [chars] Character ASCII dec. No Echo',13,10
DB "Get DOS version D[E] None Major Vers. MajorMinor MinorEnv",13,10
DB "Get environment left E[E] None Bytes left Bytes left Bytes/10",13,10
DB "Get file size (DIR=0) F[E] Filespec Hex bytes Kilobytes Kb/10",13,10
DB "Get disk space K[E] [driveletter] Kilobytes Kilobytes Kb/10",13,10
DB "Get memory free M[E] None Kilobytes Kilobytes Kb/10",13,10
DB "Clear (Blank) Screen B[E] [New attribute] Current or last attr. HexAttr",13,10
DB "Check for printer P None 1=yes,0=no 1=yes,0=no None",13,10
DB "Get/set video mode V [New mode] Current or last mode None",13,10
DB "Check coprocessor 7 None 1=yes,0=no 1=yes,0=no None",13,10
DB "Check for ANSI.SYS A None 1=yes,0=no 1=yes,0=no None",13,10
DB "Get current directory Y[E] None Directory Level/Drive Drive",13,10
;DB "Hex clock since 1/1/80 $ None Days Days/255 None",13,10
DB "Surrogate [char] args: ",cr," is Carriage Return, "
DB esc_s," is Escape, ",ext," is Extended.$",13,10
guess DB 80 ; Prompt for string
actual DB 0
string DB 80 DUP (0)
extend DB 0 ; Flag for extended command
vid DB 3 ; Video mode
ans DB 27,"[6n$" ; ANSI string to get current position
overwrt DB 8,8,8,8," $"; Overwrite ANSI characters
delete DB 8,8,8,"$" ; Delete ANSI characters
what DB "GET=" ; Variable name
lwhat EQU $-what
prompt DW 0 ; Pointer to prompt
lprompt DW 0 ; Length of prompt
arg DW 0 ; Pointer to argument
larg DW 0 ; Length of argument
EGA_L DB 0
clock DB 'CLOCK$',00H
; Command table
IFNDEF GET
cmds DB "BCSVDMEKFP7AY$NT" ; Command character list
ELSE
cmds DB "BCSVDMEKFP7AYNT" ; Command character list (omit $ for GET)
ENDIF
lcmds EQU $-cmds ; and length of list
EVEN
table DW BlankScreen
DW GetChar ; Command procedure table
DW GetStr
DW DoVid
DW GetDOS
DW GetMem
DW GetEnvSz
DW GetDskSz
DW GetFilSz
DW VeriPrint
DW VeriCop
DW VerAnsi
DW GetDir
IFNDEF GET
DW Clock$ ; This calls the $ option.
ENDIF
DW aNswer ; Yes/No answer--CR=Yes,Esc gives 126
DW Moving
DW Help
;DW NoCmd
err1 DB "Invalid command",7,13,10,"$"
err2 DB "Out of environment space",7,13,10,"$"
err3 DB "Must have DOS Version 2.0 or higher",7,13,10,"$"
.CODE
start: mov ax,@DATA ; Starting execution address
mov ds,ax ; Initialize data segment
@GetVer ; Get DOS version
or al,al ; Is it 0?
jne DOSOK ; No? Continue
@DispStr err3 ; Yes? Quit for 1.x
int 20h
DOSOK: mov si,83h ; Starting point in PSP
mov ax,WORD PTR es:[5Dh] ; Load command characters
cmp al,' ' ; Is it space?
jne isarg ; If no argument, show help
call Help
isarg: cmp ah,'E' ; Extend flag?
jne noextend ; No? Continue
inc extend ; Yes? Turn on flag and adjust pointer
inc si
noextend: call GetArg ; Get argument from command line
push es ; Save and load DS into ES
mov bx,ds
mov es,bx
mov di,OFFSET cmds ; Load pointer to command table
mov cx,lcmds+1 ; Load length
repne scasb ; Find position of command character
pop es
sub di,(OFFSET cmds)+1 ; Point to procedure
shl di,1 ; Adjust for word addresses
call table[di] ; Call the selected procedure
push ax ; Save
push es
call DoEnviron ; Put result in environment string
or ax,ax ; Test for 0 before
pop es ; restore
pop ax
jz done
cmp BYTE PTR es:[5Dh],'E' ; Is it Environment command
je done ; Yes? Skip message
error2: @DispStr err2 ; Error message
mov al,0
done: @Exit ; Quit with AL as return code
; End of program - Start of procedures
; Procedure Blank Screen without changing color or attribute or number of lines
BlankScreen PROC
PUSH DS ; See if the number of active rows
MOV AX,BIOS_DATA ; is available in the BIOS data area.
MOV DS,AX ; This is the address of the segment.
ASSUME DS:BIOS_DATA ; Tell the assembler
MOV DH,CRT_ROWS ; Good only in later versions of DOS,
POP DS ; else it will be 0 (I hope).
ASSUME DS:@data ; Tell MASM we are back home.
CMP DH,18H ; 25 rows?
JLE ROWS_OK ; If less, don't use it.
SUB DH,18H ; Else get the difference from 25,
MOV BYTE PTR EGA_L,DH ; and save it for later use.
ROWS_OK:
MOV BH,0 ; Page number for setting cursor
MOV AH,8 ; Function to read attribute
INT 10H ; Read attribute in AH (char in al)
xor al,al ; This code borrowed from video proc
push ax ; Save last attribute
;cmp larg,1 ; How many digits in mode?
;jl gotattr ; None? Get out
MOV CX,LARG
JCXZ GOTATTR
mov bx,arg ; Load address of argument string
mov ax,es:WORD PTR [bx] ; Get address of mode string
DEC CX
JCXZ ONEDIG
DEC CX
JCXZ TWODIG
;je onedig ; One digit - skip the reverse
INC BX ; Load address of argument string
mov ax,es:WORD PTR [bx] ; Get address of mode string
TWODIG: xchg ah,al ; Reverse for two digits
sub ax,'00' ; Adjust from ASCII to numeric
cmp ah,09
jle InHex
sub ah,07
and ah,0Fh
InHex: cmp al,09
jle HexOk
sub al,07
and al,0Fh
HexOk: cmp extend,0
je NotHex
mov cl,4
shl ah,cl
add ah,al
jmp SHORT gotattr
NotHex: aad ; Convert to binary
JCXZ setattr
;SUB CX,CX
MOV CL,ES:BYTE PTR [BX-1]
MOV AH,CL
SUB CL,'0'
MOV CH,2
SUB CH,CL
ADD AH,CH
SHL AH,CL
ADD AH,AL
jmp SHORT GOTattr
onedig: sub al,'0' ; Convert to numeric
cmp al,09
jle setattr
sub al,7 ; Must be Hex
and al,0Fh
setattr:
xchg ah,al ; Attribute in AH
gotattr:SUB DX,DX ; Position for cursor
MOV CX,AX ; Attribute in AH, save in CX
MOV AH,2 ; Function for setting cursor, BH=page
INT 10H ; Set cursor position
MOV BX,CX ; Need attribute in BH
SUB CX,CX ; Position for scroll
MOV DX,184FH ; Lower right row, col to scroll
ADD DH,EGA_L ; Are there extra lines?
MOV AX,600H ; Function to clear(scroll) screen
INT 10H ; Bios call
pop ax ; Last or current attribute
xchg al,ah ; Set return to attribute
cmp extend,0
jne IsHex
call bintodec ; Put attribute in enviroment
jmp SHORT BlankEnd
IsHex: call BinToHex
BlankEnd:RET
BlankScreen ENDP
IFNDEF GET
; Procedure Clock$ ; Assembled only if filename not GET.
; Purpose Get days since 1-1-80 from CLOCK$ device (DOS).
; Input None
Clock$ PROC
mov ax,3d00h ; Call DOS to open a file
mov dx,offset Clock ; ASCIIZ name of CLOCK$ device
int 21h ; Call DOS
jc QuietExit ; If error, exit...else...
mov bx,ax ; Handle in AX, need in BX
mov dx,offset string ; Location of output
mov cx,0001 ; Length of output expected
mov ax,3f00h ; Function to read device
int 21h ; Call DOS
jc QuietExit ; If error, exit...else...
mov ax,word ptr string ; Number of days since 1-1-80
cmp ax,300 ; Take all dates except 300 in 1980.
;cmp ax,0D00h ; 1989 is early enough, else clock is
jle QuietExit ; not set, so don't use.
xchg al,ah ; Get digits in proper order, and
call BinToHex ; Convert number in AX to hex digits.
xor bx,bx ; Now have hex in string, length in actual
mov bl,byte ptr actual ; Number of hex digits, no leading 0's?
mov actual,5 ; If more than 2 bytes we want to split
mov si,bx ; it into two hex numbers for use by
mov bx,4
ByteLoop:
dec si ; DEBUG. We will make 5 bytes out of
mov ah,string[si] ; it, 2 and 2 separated by a space.
mov string[bx],ah ; We are now moving the 4th to the
cmp si,0 ; fifth place, and the third to the 4th.
jz DoneLoop
dec bx
cmp bx,2 ; Need to put space in 3rd positon
jne ByteLoop
mov string[bx],' '
dec si
DoneLoop: ; si is either 0 or 1.
dec bx ; if si is 0, bx is 3, 2, or 1 after dec
cmp bx,si ; if bx is 1, si is either 0 or 1
jz ClockEnd ; if bx is 2 or 3, si must be 0
cmp bx,2 ;
jne ZeroLoop ; either bx=3,si=0 or bx=1,si=0
mov string[bx],' '
Zero_1: dec bx ; We know that bx is 2
ZeroLoop: ; Now have to fill with leading zeros
mov string[bx],'0'
cmp bx,3 ; If 3, we still have to do ' '
jz DoneLoop ; so go back up there.
cmp bx,0 ; If not yet 0, do it again.
jg Zero_1
ClockEnd: ret
QuietExit: mov ax,4c00h ; Quietly exit with a zero return code.
int 21h
Clock$ ENDP
ENDIF
; Procedure aNswer
; Purpose get and answer to a yes/no type question.
; Input Allowable characters pointed to by "arg" (optional)
; Prompt pointed to by "prompt" (optional)
; Output Character in AX and in "string"
aNswer PROC
;mov bx,offset prompt ; Simulate the valid characters
;add bx,lprompt ; Length of prompt to find end.
MOV BX,60H ; Use DOS PSP FCB area for this???
mov arg,bx ; Tell GetChar where the args are,
mov larg,4 ; and how many...
mov word ptr es:[bx],'NY' ; Set up Y(es), N(o) characters
mov word ptr es:[bx+2],"}~" ; Set up CR and Esc surrogates
call GetChar ; Now use existing code
ret
aNswer ENDP
; Procedure GetChar
; Purpose Get a character from user
; Input Allowable characters pointed to by "arg" (optional)
; Prompt pointed to by "prompt" (optional)
; Output Character in AX and in "string"
GetChar PROC
call ShowPrmpt ; Display prompt if there is one
readkey: @GetKey 0,1 ; Get a key
CALL CheckChar
cmp al,0
jz readkey
charend: push AX
@DispCh 13,10 ; Better put in cr,lf...
pop AX
ret
GetChar ENDP
; Procedure CheckChar
; Purpose Check character from user
; Input Allowable characters pointed to by "arg" (optional)
; Character to check in AL
; Output Character in AX(al) and in "string"
; If AL is 0, bad character.
CheckChar PROC
cmp al,13 ; Is it carriage return?
jne notcr ; Yes? Continue
mov al,cr ; Call it whatever is in cr
; (use surrogate in character list
; if you want to accept CR)
notcr: cmp al,27 ; Is it Escape?
jne notesc ; Yes? Continue
mov al,Esc_s ; Call it tilde
notesc: or al,al ; Is it 0 for extended key?
je exkey ; Special case
mov bl,al ; Save a copy and swap
xchg ah,al
call UpCase ; Uppercase it
xchg ah,al ; Swap back
mov si,arg ; Load pointer and length of argument
mov cx,larg
jcxz gotchar ; If no argument, quit early
; Compare character to argument to see if it's valid
argcheck: mov ah,BYTE PTR es:[si] ; Get character
inc si ; Increment index
call UpCase ; Convert to uppercase
cmp ah,al ; Is it in argument?
je gotchar ; Yes? We're done
loop argcheck ; else check another
jmp SHORT BadChar ; and get another character
gotchar: push ax
cmp extend,0 ; Is extend flag set?
jne noecho ; Yes? Don't echo
cmp bl,cr ; Don't echo ~ (alias for CR)
je noecho
cmp bl,Esc_s ; Don't echo ~ (alias for Esc)
je noecho
@DispCh bl ; Display valid character
noecho: pop ax
mov string,al ; Put the character in string
mov actual,1 ; Length is one
jmp SHORT EndCheck
exkey: @GetKey 0,1 ; Get second key in AL
mov si,arg ; Load pointer to argument
cmp BYTE PTR es:[si],Ext ; Is argument grave accent?
; (use grave in character list if
; you want to accept extended keys)
je gotext ; Yes? Extended character
BadChar: @DispCh 7 ; No? Illegal, so ring bell
mov al,0 ; and get another
jmp short EndCheck
gotext: mov string[0],'`' ; Extended flag value is "`<char>"
mov string[1],al
mov actual,2 ; Length is 2
EndCheck: ret
CheckChar ENDP
; Procedure GetStr
; Purpose Get a string
; Input Prompt pointed to by prompt (optional)
; Output String in "string"; length to AX
GetStr PROC
call ShowPrmpt ; Display prompt if there is one
cmp extend,1 ; Extend flag true?
je password ; Yes? Then don't echo
@GetStr guess,0 ; Get string (null-terminated)
jmp SHORT gotstr ; Done
password: mov bx,OFFSET string ; Load offset of string buffer
mov cx,80 ; Maximum count
nextkey: @GetKey 0,1 ; Get key, no echo
cmp al,13 ; Is it carriage return
je gotpass ; Yes? Done
mov [bx],al ; No? Put key in buffer
inc bx ; Point to next
loop nextkey
gotpass: sub bx,OFFSET string ; Adjust pointer to get count
mov actual,bl ; Save count
gotstr: @DispCh 13,10
mov ax,bx ; Save string length
ret
GetStr ENDP
; Procedure GetDOS
; Purpose Get DOS version
; Input None
; Output Major or minor version in "string"; (major *10)+minor in AX
GetDOS PROC
@GetVer ; Get DOS version
mov string,al ; Put major in string
mov bh,al ; Save copy
mov al,ah ; Divide minor to get one digit
sub ah,ah ; Clear top
mov cl,10 ; Divide by 10
div cl
xchg al,bh ; Exchange major and minor
mul cl ; Multiply major by 10
add al,bh ; (Major*10)+Minor - 3.2 is now 32
cmp extend,1 ; Extend?
jne gotver ; No? Already got it
mov string,bh ; Save number
gotver: mov actual,1 ; Save length 1
add string,30h ; Convert to ASCII
ret
GetDOS ENDP
; Procedure GetEnvSz
; Purpose Get environment bytes available
; Input None
; Output Environment bytes available
GetEnvSz PROC
push es ; Save ES
call GetEnv ; Get the environment size
pop es ; Restore
sub ax,cx ; Subtract length used from total
; length to get length remaining
call BinToDec ; Convert to string
call Byticize ; Handle values too large for byte
ret
GetEnvSz ENDP
; Procedure GetFilSz
; Purpose Get the size of a specified file
; Input Filespec pointed to by "arg"
; Output File size in AX and String(Hex)
GetFilSz PROC
mov di,arg ; Point to start and end of arg
mov bx,larg
Call Open_Size ; Returns size in DX:AX, handle in BX
JC gotsize
;mov actual,0 ; Initial def is 0
PUSH DX
or dx,dx
jz just_ax
push ax
mov ax,dx
call BinToHex
pop ax
just_ax: call BinToHex
POP DX
or dx,dx
jnz @F
or ax,ax
jz gotsize2
@@: mov cX,10 ; Convert to kilobytes
floop: rcr dx,1
rcr ax,1
loop floop
;shr ax,cl
;or dx,dx
;jz gotsize2
inc ax ; Round up
jmp SHORT gotsize2
gotsize: call BinToDec ; Convert to string (decimal)
gotsize2:
call Byticize ; Handle large values
ret
GetFilSz ENDP
; Procedure Open_Size
; Purpose Get the size of a specified file and open for reading
; Called by GetFilSz and Moving
; Input Filespec pointed to by "arg"
; Output File size in DX:AX, Handle in BX
Open_Size PROC
;cmp arg,0 ; File name argument?
cmp di,0 ; File name argument?
jne isfile
call NoCmd
; Must be called with these args!
isfile: ; mov di,arg ; Point to start and end of arg
; mov bx,larg
mov BYTE PTR es:[bx+di],0 ; Make null-terminated
push ds
;@OpenFil arg,0,es ; Open file for reading
@OpenFil di,0,es ; Open file for reading
pop ds ; Handle now in AX unless error
jc ferror ; Error if carry
;notdir:
mov si,ax ; Save handle in SI for Moving
@GetFilSz ax ; Size in DX:AX
jc ferror ; Error if carry
ret
ferror: ;cmp ax,5 ; Access denied? Probably a directory
;jne nofile ; No file or some other error
;mov ax,0FFh ; Call directory size 255
;jmp SHORT gotsize ; DIR and error return size 0!
;nofile:
sub ax,ax ; Size of nothing is 0
stc
ret
Open_Size ENDP
; Procedure GetDskSz
; Purpose Get K remaining on specified disk
; Input Drive letter pointed to by "arg"
; Output Disk space remaining
GetDskSz PROC
;sub ax,ax ; Assume default drive
;cmp arg,0 ; Was there an argument?
MOV AX,ARG
OR AX,AX
je defdrive ; No? Got drive
MOV BX,AX
MOV AL,ES:BYTE PTR [BX ]
AND AL,5FH
;mov al,BYTE PTR es:6Dh ; Yes? Get drive letter
sub al,'A'-1 ; Convert to binary
defdrive: @ChkDrv al ; Get disk space
cmp ax,0FFFFh ; Is drive valid?
jne valid
call NoCmd
valid: mul bx ; Sectors = sectors/cluster * clusters
shr ax,1
;mul cx ; Bytes = bytes/sector * sectors
;mov cl,10 ; Convert to kilobytes
;shr ax,cl
;inc ax ; Round up
call BinToDec ; Convert to string
call Byticize ; Handle large values
ret
GetDskSz ENDP
; Procedure GetMem
; Purpose Get memory available
; Input None
; Output Available memory
GetMem PROC
int 12h ; Get memory available in K
mov bx,es ; Get memory used
mov cx,6 ; Convert to K
shr bx,cl
sub ax,bx ; Calculate how much is left
DEC AX ; Seems like we need 1 less???
;sub dx,dx ; Clear DX
;mov cx,1024 ; Multiply to get bytes
;mul cx
;mov cx,1000 ; Divide to get thousands (not K)
;div cx
call BinToDec ; Convert to string
call Byticize ; Handle large values
ret
GetMem ENDP
; Procedure VeriPrint
; Purpose See if LPT1 (PRN) is available
; Input None
; Output 1 for yes or 0 for no
VeriPrint PROC
mov ax,200h ; Check printer status
sub dx,dx ; for main parallel printer (port 0)
int 17h
xchg dx,ax ; Put 0 (for error) in AX
test dh,00101001b ; Are any error bits on?
jne printerr ; Yes? Leave 0
test dh,10010000b ; Are both operation bits on?
jz printerr ; No? Leave 0
inc ax ; Yes? Return 1
printerr: call BinToDec ; Convert to string
ret
VeriPrint ENDP
; Procedure DoVid
; Purpose Get current video mode and optionally set a new mode
; Input New video mode pointed to by "arg" (optional)
; Output Current video mode (before change)
DoVid PROC
mov ah,0Fh ; Get video mode
int 10h
cmp larg,1 ; How many digits in mode?
jl gotmode ; None? Get out
push ax ; Some? Save mode
mov bx,arg ; Load address of argument string
mov ax,es:WORD PTR [bx] ; Get address of mode string
je one ; One digit - skip the reverse
xchg ah,al ; Reverse for two digits
sub ax,'00' ; Adjust from ASCII to numeric
aad ; Convert to binary
jmp SHORT setmode
one: sub al,'0' ; Convert to numeric
setmode: sub ah,ah ; Set mode
int 10h
pop ax ; Restore
gotmode: cbw ; Extend to AX
call BinToDec ; Convert to string
ret
DoVid ENDP
; Procedure VeriCop
; Purpose Check for coprocessor
; Input None
; Output 1 for yes or 0 for no
VeriCop PROC
int 11h ; Check peripherals
test al,10b ; Coprocessor
mov ax,0 ; Assume no (don't change flags)
jz no87 ; No? Done
inc ax ; Yes? Set to 1
no87: call BinToDec ; Convert to string
ret
VeriCop ENDP
; Procedure VerAnsi
; Purpose Check for ANSI driver
; Input None
; Output 1 for yes or 0 for no
VerAnsi PROC
@DispStr ans ; Print ANSI string to get
; cursor position
mov ah,6 ; Check for key
mov dl,0FFh ; in buffer
int 21h
jnz ansi ; Done if ANSI
@DispStr overwrt ; Overwrite ANSI string
sub ax,ax ; 0 if not ANSI
jmp SHORT gotansi
ansi: mov ax,0C06h ; Clear returned ANSI keys
mov dl,0FFh ; out of buffer
int 21h
@DispStr delete ; Delete ANSI string
mov ax,1 ; Set 1 for true
gotansi: call BinToDec ; Convert to string
ret
VerAnsi ENDP
; Procedure GetDir
; Purpose Get the current directory or drive
; Input None
; Output Current directory or drive in "string"; level or drive number in AX
GetDir PROC NEAR
cmp extend,1 ; Extend flag true?
jne directry ; No? Get directory
@GetDrv ; Yes? Get drive
mov ah,al ; Copy
add ah,'A' ; Convert to drive letter
mov string,ah ; Put character in string
inc actual ; Length 1
cbw
ret
directry: mov si,OFFSET string ; Load address for string
mov BYTE PTR [si],"\" ; Insert backslash (DOS doesn't)
inc si ; Point to next
@GetDir si
sub cx,cx ; Count is zero
dec si ; Move pointer back to start
findback: lodsb ; Load
cmp al,"\" ; Is it backslash?
jne notslash ; No? Continue
inc dx ; Yes? Increment level counter
notslash: or al,al ; Is it 0?
loopne findback ; No? Repeat
neg cx ; Negate to get positive count
mov actual,cl ; Put level in variable
xchg ax,dx
ret
GetDir ENDP
; Procedure NoCmd
; Purpose Return error for invalid command
; Input None
; Output None
NoCmd PROC
@DispStr err1 ; Display error and quit
@Exit 0
NoCmd ENDP
; Procedure Byticize
; Purpose Adjust word values to fit in a byte
; Input Value in AX
; Output 255 for word values, else value (no extend) or value*10 (extend)
Byticize PROC
cmp extend,0 ; Is extend flag set?
je sizechk ; No? Check size
sub dx,dx ; Yes? Clear DX
mov bx,10 ; Divide by 10 to get 10-unit chunks
div bx
sizechk: or ah,ah ; Is it 255 or less?
je byteOK
mov al,0FFh ; No? Call it 255
byteok: ret
Byticize ENDP
; Procedure GetArg
; Purpose Parse command line for argument and prompt strings
; Input Command line
; Output Pointer to argument in "arg"; length (or 0 if none) in "larg"
; Pointer to prompt in "prompt"; length (or 0 if none) in "lprompt"
GetArg PROC
push ax
push es ; Swap ES and DS
push ds
pop es
pop ds
white: lodsb ; Load while white space
cmp al,' ' ; Is it space?
je white ; Throw away
cmp al,9 ; Is it tab?
je white ; Throw away
cmp al,'"' ; Is it quote?
je promptit ; Process
cmp al,13 ; Is it carriage return?
je gotarg ; Done
sub cx,cx
qdone: dec si ; Adjust
mov es:arg,si ; Save pointer to argument start
chars: lodsb ; Load while not white
cmp al,' ' ; Is it space?
je nomore ; Done
cmp al,9 ; Is it tab?
je nomore ; Done
cmp al,13 ; Is it carriage return?
loopne chars ; Throw away
nomore: not cx ; Adjust count
mov es:larg,cx ; Save length
jmp SHORT gotarg
promptit: mov di,si ; Save pointer to start
sub cx,cx ; Clear count
inprompt: lodsb ; Another
cmp al,13 ; Is it carriage return?
je oneq ; Yes? Treat one quote like character
cmp al,'"' ; Is it quote?
loopne inprompt ; No? Throw away
mov es:prompt,di ; Save prompt pointer
not cx
mov es:lprompt,cx ; and length
jmp SHORT white ; Get the argument
oneq: mov si,di ; Restore
mov cx,-1 ; Set count to -1
jmp SHORT qdone
gotarg: push es ; Swap ES and DS back
push ds
pop es
pop ds
pop ax
ret
GetArg ENDP
; Procedure ShowPrmpt
; Purpose If prompt, display it
; Input Pointer to prompt
; Output Prompt to screen
ShowPrmpt PROC
cmp prompt,0 ; Is there a prompt?
je noshow ; If not, continue
push ds ; Save and restore DS
@Write prompt,lprompt,,es ; DOS Write function
pop ds
noshow: ret
ShowPrmpt ENDP
; Procedure DoEnviron
; Purpose Convert a string to an environment variable
; Input String in "string", length in "actual"
; Output String in "GET" environment variable;
; AX has 0 for success, nonzero for failure
DoEnviron PROC
call GetEnv ; Get environment size, length, address
mov dx,ax ; Save size and length
mov bx,cx
; Find "GET="
sub di,di ; Point to start
sub al,al ; Search for zero
mov si, OFFSET what ; Point source at "GET="
findwh: repne scasb ; Search
cmp BYTE PTR es:[di],0 ; If double null, end of environment
je gotend
jcxz noroom ; Error if not found
push di ; Save
push cx
mov si,OFFSET what ; Load address and length of "what"
mov cx,lwhat ; for comparison
repe cmpsb ; Compare
mov si,di ; Make copy
pop cx ; Restore
pop di
jnz findwh
; Find end of "GET" variable
xchg di,si
repne scasb ; Find end of environment variable
xchg si,di ; Point source to next variable
; Calculate characters left to write
mov cx,bx ; Load total characters
sub cx,si ; Subtract finished to get left
; Move everything back to overwrite "GET="
movenv: push ds ; Save DS
mov ax,es ; Copy to ES
mov ds,ax
rep movsb ; Copy
mov BYTE PTR es:[di],0 ; Put null at end in case of error
pop ds ; Restore
; Check environment space
gotend: mov al,actual ; Load length of string
sub ah,ah ; Clear top
add ax,lwhat ; Add length of name
add ax,di ; Add position to get final length
cmp ax,dx ; Is it longer than environment?
jge noroom ; Yes? Quit
; Put GET= at end
mov si,OFFSET what ; Load address and length of what
mov cx,lwhat
rep movsb
; Put new string at end
mov si,OFFSET string ; Load address and length of string
mov cl,actual
rep movsb
mov WORD PTR es:[di],0 ; Put double null at end
sub ax,ax ; Return 0 for success
ret
noroom: inc ax ; Return nonzero for fail
ret
DoEnviron ENDP
; Procedure GetEnv
; Purpose Find and measure the environment
; Input None
; Output Segment of environment in ES, size in AX, length in CX
GetEnv PROC
mov dx,es:10h ; Load segment of COMMAND.COM
mov es,dx ; into ES
mov ax,es:2Ch ; Load COMMAND.COM's environment
or ax,ax ; Is it 0?
jnz secondry ; No? This is a secondary command
; and we have its environment in AX
dec dx ; Yes? This is original COMMAND.COM
mov es,dx ; so point ES to paragraph before PSP
add dx,es:03 ; Offset of environment is 3 bytes in
add dx,2 ; Adjust it back to PSP
mov ax,dx ; Put it in AX
secondry:
; Note:
; CodeView cannot debug the previous section of code, because the PSP
; addresses checked by the code are those passed from DOS to CodeView,
; not addresses passed from DOS to the program. To debug with CodeView,
; find the actual address of the environment:
; S 500:0 L FFFF "COMSPEC="
; When you find the actual address, hard code it into your program:
; mov ax,110Ch ; Debug line
; Comment the line out for final assembly after debugging.
mov si,ax ; Save a copy
sub dx,dx ; Clear DX for multiply
dec ax ; Get paragaraph before environment
mov es,ax ; Load into DS
mov ax,es:03 ; Size in paragraphs is at byte 4
mov cx,16 ; Multiply by 16
mul cx
mov es,si ; Restore environment address
sub di,di ; Point to start
mov cx,ax ; Load maximum count (size of
mov bx,ax ; environment) and save a copy
sub ax,ax ; Search for double null
null2: repne scasb ; Look for null
jz noerr ; If not out of space, continue
sub ax,ax ; else error (return 0)
jmp error2
noerr: cmp BYTE PTR es:[di],0 ; Is it double null?
jne null2 ; No? Look again
mov cx,di ; Yes? Save length in CX
mov ax,bx ; Reload size to AX
ret
GetEnv ENDP
; Procedure BinToDec
; Purpose Convert binary number in AX to string
; Input Value in AX
; Output Value string in "string"; length of string in "actual"
; AX contains number to be converted
BinToDec PROC
push ax
push es
sub cx,cx ; Clear counter
mov bx,10 ; Get ready to divide by 10
getdigit: sub dx,dx ; Clear top
div bx ; Remainder is last digit
add dl,'0' ; Convert to ASCII
push dx ; Put on stack
inc cx ; Count character
or ax,ax ; Is quotient 0?
jnz getdigit ; No? Get another
mov actual,cl ; Save number of digits
mov ax,ds ; Load DS to ES
mov es,ax
mov di,OFFSET string ; Load source
putdigit: pop ax ; Get a digit off stack
stosb ; Store it to string
loop putdigit
pop es
pop ax
ret
BinToDec ENDP
; Procedure BinToHex
; Purpose Convert binary number in AX to string in HEX
; Input Value in AX
; Output Value string in "string"; length of string in "actual"
; AX contains number to be converted
BinToHex PROC
push ax
push es
sub cx,cx ; Clear counter
mov bx,16 ; Get ready to divide by 16
hexdigit: sub dx,dx ; Clear top
div bx ; Remainder is last digit
add dl,'0' ; Convert to ASCII
cmp dl,58 ; May be ABCDEF
jb isnum
add dl,7
isnum: push dx ; Put on stack
inc cx ; Count character
or ax,ax ; Is quotient 0?
jnz hexdigit ; No? Get another
xor dh,dh
mov dl,actual ; Save number in string already, if any
add actual,cl ; Save number of digits
mov ax,ds ; Load DS to ES
mov es,ax
mov di,OFFSET string ; Load source
add di,dx
putdigith: pop ax ; Get a digit off stack
stosb ; Store it to string
loop putdigith
pop es
pop ax
ret
BinToHex ENDP
; Procedure UpCase
; Purpose Convert a character to uppercase
; Input Character in AH
; Output Converted character in AH
UpCase PROC
cmp ah,"a" ; Is character below lowercase?
jl ok ; If so, continue
; else
cmp ah,"z" ; Is character above lowercase?
jg ok ; If so, continue
; else
sub ah,20h ; Make it uppercase
ok: ret
UpCase ENDP
; Procedure Help
; Purpose Display syntax screens
; Input None
; Output Help to screen
Help PROC
mov larg,0
call BlankScreen
@DispStr help1 ; First screen
;@GetKey ; Pause
;@DispStr help2 ; Second screen
@Exit 0
Help ENDP
; Procedure Moving
; Purpose Display text in file in a moving display
; Input Filespec pointed to by "arg"
; Output User input character
Moving PROC
;cmp prompt,0 ; Is there a prompt?
;je BadFile ; If not, continue
mov di,prompt ; Point to start and end of arg
mov bx,lprompt
Call Open_Size ; Leaves handle in bx
or dx,dx ; Size in DX:AX
jz @f
mov ax,MaxSize ; Max size
@@: mov dx,offset moving_buffer ;
mov cx,ax ; File size from AX (<64k)
cmp cx,MaxSize
jle @f
mov cx,MaxSize
@@: mov ax,3f00h ; Read file bx, (cx chars)
int 21h
jc BadFile
cmp ax,0
jz BadFile
cmp ax,80
jb BadFile
mov bp,offset moving_buffer
add bp,ax
sub bp,79 ; offset of last line.
again: CALL GET_A_KEY ; This puts up moving message.
mov actual,0
call CheckChar ; Char in AL
sub ah,ah
CMP AL,0 ; Is there a key in AL?
JZ again ; If so, we are done here...
;jmp short got_a_key
ret
badfile: sub ax,ax ; Size of nothing is 0
;got_a_key: ;call BinToDec ; Convert to string
ret
Moving ENDP
; Procedure get_a_key
; Purpose Display moving message until a key is pressed
; Input None
; Output None
GET_A_KEY PROC
MOV DL,0FFH ; Indicat console input.
MOV AX,0C06H ; Clear keyboard buffer
INT 21H ; Executes function 06, console input
MOV DX,1800H ; Fixed cursor position 24,0
;SUB DH,1 ; Move the cursor up 1 row
;SUB DL,DL ; and to the left margin
PUSH CX
PUSH DX
SHARE_AGAIN:
MOV SI,OFFSET moving_buffer ; Output a line of message
SHARE_LOOP: ; starting at this location
POP DX ; DX has cursor position2
PUSH DX ; so save it each time.
MOV AH,02 ; using BIOS function 2
INT 10H ; Call BIOS
MOV DX,SI
MOV CX,79
mov bx,2
MOV AH,40H ; This does the writing.
INT 21H ; Call DOS standard error
PUSH DX
MOV DL,0FFH ; This checks for a key every char.
MOV AH,06H ; Now check the input status
INT 21H ; Is there a key pressed?
POP DX ; If so, AL will have key and
JNZ THATS_ALL ; zero flag will be clear.
INC DX ; else, show another line...
MOV SI,DX ; Save the location pointer
MOV AH,2CH ; Start timing loop...
INT 21H ; Hundredths of seconds in DL,
XCHG_LOOP:
XCHG DX,DI ; So save it for comparison.
TIME_LOOP:
MOV AH,2CH ; and get the time again.
INT 21H
CMP DX,DI
JB XCHG_LOOP
SUB DX,DI
CMP DX,15
JB TIME_LOOP
CMP SI,bp ; bp has the offset of the last segment
JB SHARE_LOOP ; of text, so start over if there.
; This is the slow way to get a key.
; MOV AH,0BH ; Now check the input status
; INT 21H ; Is there a key pressed?
; OR AL,AL ; If so, AL will be FFh
; JNZ THATS_ALL ; so we are done,
; But this doesn't actually get the key.
JMP SHORT SHARE_AGAIN
THATS_ALL: ; Function to get key (INKEY)
POP DX ; using DOS interrupt will be
POP CX ; handled by calling function.
KEYOK: RET
GET_A_KEY ENDP
.DATA
;guess DB 80 ; Prompt for string
;actual DB 0
;string DB 0,0
Moving_buffer db MaxSize dup(0)
END start ; End assembly