📄 iparam.asm
字号:
; FILENAME: IPARAM.ASM
;
; Copyright (c) 1988, 1992 by Borland International, Inc.
;
; DESCRIPTION: This module implements two routines that manage the
; command line parameters passed to the program. The routine ParamCount
; returns the number of parameters passed to the program while the
; routine ParamString returns a pointer to the referenced parameter
; string. This module uses ideal mode syntax.
;
; ASSEMBLY INSTRUCTIONS: To assemble this module use the following
; TASM command line.
;
; TASM /m /dMDL=memorymodel iparam
;
; /m in the above command line allows TASM to resolve jumps and other
; operations to their shortest form and get rid of extra NOPs.
; 'memorymodel' in the above command line may be replaced by TINY, SMALL,
; MEDIUM, COMPACT, LARGE or HUGE. If assembling this module to run on
; a 286/386 machine, turn on the P286 directive in order to take advantage of
; 286/386 specific instructions. I.E.
;
; TASM /m /dMDL=memorymodel /jP286 iparam
;
; NOTE: This module requires that the main program declare and initialize
; the global variable PspAddress.
%tabsize 4
ifndef MDL
display "Error: This module requires that you provide a memory model"
display " definition on the command line. I.E. /dMDL=SMALL."
err ; Force a fatal error
else
ideal ; Use TASM's Ideal mode
% model MDL,pascal ; Define the memory model
include "dos.inc"
include "idos.inc"
include "kbd.inc"
include "iwhglobl.inc"
NotCalled equ 0FFh ; ParamCount was already called once
dataseg
; Declare variables to store the parsed parameters and parameter
; count.
ParmCount DB NotCalled ; ParamCount initializes this variable
; the first time it is called.
ParmList DB 7Fh DUP (0) ; Allocate enough space for a 127
; character command line
; global PspAddress:word ; Define extrn variable
codeseg
; global ParamCount:proc ; Public procs
; global ParamString:proc
; global LocateString:proc ; Declare external procs
; global FindBytePos:proc
; global FindAndReplace:proc
; global ByteCopy:proc
; global SkipSpaces:proc
proc IsDelimiter
; This routine checks the character in AL to see if it is a delimiter.
; Valid delimiters are '' "" []
;
; Input
; al - Character to check
; Output
; al contained a delimiter:
; al - matching delimiter
; Carry set
; al did not contain a delimiter
; Carry not set
; Calling conventions
; NA
; Registers modified
; al
cmp al,'"'
je ItIs
cmp al,"'"
je ItIs
cmp al,"]"
je ItIs
cmp al,"["
je ItIsSquare
jmp IsNot
ItIsSquare:
mov al,"]"
ItIs:
stc
ret
IsNot:
clc
ret
endp IsDelimiter
; Use the following pattern to look for trailing spaces.
label TrailingSpace word
db " ",0dh
proc ParamCount
; This routine returns the number of command line parameters passed to
; the program. Parameters are delimited by spaces or tabs. Double or
; single quotes can enclose parameters that include spaces or tabs
; inside them.
;
; While the function is parsing the command line it stores copies of
; each of the parameters in the modules data segment. The strings are
; stored in Turbo Pascal format. That is they are stored with a
; preceeding length byte. The first time the routine is called it also
; stores the result in the variable ParmCount in the modules data
; segment. Any subsequent calls simply return the contents of
; ParmCount.
;
; Input
; none
; Output
; al - Number of parameters
; Calling conventions
; NA
; Registers modified
; ax, bx, cx, DX, di, si, es, Flags
local SearchChar:byte=LocalSymbolSize ; Declare local variables
; Point es:di to location where the parsed parameters will be stored
mov ax, @data ; Using near data model
mov es, ax
; Check if the function was called previously. If it was we
; don't want to parse the command line again.
cmp [es:ParmCount], NotCalled
je FirstCall
jmp AlreadyCalled
FirstCall:
mov di, offset ParmList ; es:di now points to modules storage
push ds
; Note that we don't actually allocate any memory to store the
; DOS Psp. We simply use the STRUC declaration to determine
; the offsets of the fields in the memory allocated by DOS.
mov ds, [PspAddress] ; Load the segment address of the Psp
mov si, offset (Psp).CommandTail + 1
xor cx, cx ; Initialize cx
xor bx, bx ; Store # of parameters in bx
; Get the length of the DOS command line from the Psp.
mov cl, [ds:Psp.CommandTail.LengthByte]
; Check if the command line is empty and leave if it is.
cmp cl, 0
jne ReplaceTabs
jmp InitParmCount
ReplaceTabs:
; Convert any tabs in the command line to spaces in order to
; make the parsing simpler.
push cx ; Store value of cx & es:di because call to
push es ; FindAndReplace modifies them.
push di
; Push the address of the DOS command line
push ds
if (@Cpu and 100b) eq 100b
push offset (Psp).CommandTail + 1
else
mov ax, offset (Psp).CommandTail + 1
push ax
endif
; Define the bytes to search/replace
mov ax, (SPACE shl 8) + TAB
call FindAndReplace ; Replace all tabs with spaces
pop di es
; Restore previous values of cx & es:di
pop cx
; Now we need to trim the end of the string
mov ax,[TrailingSpace]
mov bx,cx
CheckForTrailing:
cmp ax,[si+bx-1]
jne StringTrimmed ; String trimmed, but some still left
; Space found at end, move the carriage return forward a byte
mov [byte ptr si+bx-1],0dh
dec cx
dec bx
cmp cl, 0
jne CheckForTrailing
StringTrimmed:
mov bx,0 ; Set it back to zero for counting
; parameters
jz InitParmCount ; If CL=0, then Z set.
; If end of string, Z not set!
; Skip any spaces at the beginning of the parameter list.
push es di ; Save registers that will be modified
push ds si ; Pass the address of the string
call SkipSpaces
pop si ds ; Update ds:si with start of next
; parameter
pop di es ; Restore es:di to point to location
; to store the next parameter
; Now parse the command line. Note that after each iteration of
; this loop ds:si points to the beginning of the next parameter
; and es:di points to location in the modules data segment where
; the next parameter will be stored.
ParseCmdLine:
inc bx ; Increment the parameter count
mov al,[si]
call IsDelimiter
jc HandleDelimiter
jmp WhiteSpace
HandleDelimiter:
mov [SearchChar], al
inc si ; Point to the next character in the parameter list
dec cx ; Adjust number of bytes left to check
jmp FindDelimiter
WhiteSpace:
mov al, SPACE
mov [SearchChar], al ; Use space, tab or eoln as delimiter
FindDelimiter:
push bx es di ; Store bx, es:di
; Push the address of the start of the next parameter for the call
; to FindBytePos
push ds
push si
; Find the end of the parameter. After the call to FindBytePos
; ax = the number of bytes searched and es:di is pointing to
; the byte after the last one checked. cx=# of bytes left to
; check in the command line string.
call FindBytePos
push es ; Move the pointer returned by
pop ds ; FindBytePos into ds:si
mov si, di
pop di es bx ; Restore es:di, bx
; Now copy the parameter into its storage location
CopyParameter:
mov dx, si ; Calculate the offset of the source
sub dx, ax ; string
dec dx
; If there was a delimiter other than a space, we want to make
; sure that we get the trailing delimiter too.
cmp [SearchChar],SPACE
jne BumpCopyCount
or cx,cx ; Check if CX=0 (If at end of arguments)
jnz StoreLength
BumpCopyCount:
inc al ; We need to copy and extra character
StoreLength:
push cx bx es si di ; Save the values of registers
; modified by the call to ByteCopy
mov [byte es:di], al ; Store length of parameter in
inc di ; the length byte
; Copy the array of characters
call ByteCopy,ds,dx,\ ; Source string
es,di ; Destination string
pop di si es bx cx ; Restore the previous values of the
; registers modified by ByteCopy
add di, ax ; Move pointer past end of parameter
inc di
cmp [byte ds:si], SPACE
jne NoWhiteSpace
; Now find the first character of the next parameter.
push es di ; Save registers that will be modified
push ds si ; Pass the address of the string
call SkipSpaces
pop si ds ; Update ds:si with start of next
; parameter
pop di es ; Restore es:di to point to location
; to store the next parameter
NoWhiteSpace:
jcxz InitParmCount
jmp ParseCmdLine ; Get the next parameter on the
; command line.
InitParmCount:
; Initialize ParmCount so the routine doesn't have to parse the
; command line more than once.
mov [byte es:ParmCount], bl
pop ds ; Restore the programs data segment
AlreadyCalled:
mov al, [byte es:ParmCount] ; Return the previously determined
ret
endp ParamCount
proc ParamString
; This routine returns a far pointer to the parameter referenced in
; al. Before looking for the parameter, the function calls ParamCount
; to assure that the parameter exists. This has the side-affect of
; assuring that ParamCount parses and copies the parameters into the
; modules data segment.
;
; Input
; al - Parameter to return
; Output
; al = Desired Parameter
; es:di - Far pointer to parameter
; al = 0 - Parameter doesn't exist
; Calling conventions
; NA
; Registers modified
; ax, bx, cx, di, si, es, Flags
; First check if the parameter exists
push ax ; Save index to desired parameter
call ParamCount
pop bx ; Restore index to desired parameter
cmp bl, al ; Check if the parameter exists
jg InvalidParameter
mov al, bl ; Pass parameter index in al
; Point to modules data segment
mov bx, @data ; Using near data model
mov es, bx ; Make es:si point to the data area
mov di, offset ParmList
call LocateString ; Determine the address of the string
jmp Exit
InvalidParameter:
xor al, al
Exit:
ret
endp ParamString
endif ; ifndef MDL
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -