home *** CD-ROM | disk | FTP | other *** search
-
- ; 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
-
-