home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Beijing Paradise BBS Backup
/
PARADISE.ISO
/
software
/
BBSDOORW
/
SHSUCD11.ZIP
/
SHSUCDX.ASM
< prev
next >
Wrap
Assembly Source File
|
1995-12-07
|
59KB
|
1,827 lines
; ***************************************************************************
;
; SHSUCDX.ASM Version 1.0
; John H. McCoy, December 1995
; Sam Houston St. Univ., TX 77341-2206
;
; SHSUCDX is an un-loadable CD-ROM redirector substitute for MSCDEX.
; Version 1.0 supports up to 10 CD drives. Each drive is single
; sector buffered and the last 10 directory entries are cached.
; This version fixes an incompatability with Netware VLM client,
; ignores associative files on MAC compatable disks and fixes a
; directory problem involving some CDs created on Unix systems.
;
; Approx 17K of RAM is needed to install SHSUCDX. The resident size
; for a single drive is less than 11K. Each additional drive increases
; the resident size by 2500 bytes. Multiple drivers are supported.
; The driver name, drive letter, drive unit and number of drives from
; each driver can be specified on the command line.
;
; SHSUCDX does not attempt to read the CD ROM until an access request
; is made. Thus, the CD drive does not have to be ready when the
; redirector is loaded. If more than 7 seconds elapse between access
; requests a media check is made. The buffers and cache are flushed
; and the CD is re-read only if the driver reports a media change.
;
; When SHSUCDX unloads it marks the drives it used as invalid.
;
; SHSUCDX has been run with MS-DOS 4, 5, 6 and 7 stand-alone, under
; Windows 3.1, and in a specific DOS window under OS2.
;
; A CD-ROM driver which supports the CD-ROM extensions must be loaded
; before loading SHSUCDX. By default, SHSUCDX looks for a driver
; named SHSU-CDN.
;
; usage: SHSUCDX [/D:DriverName[,[Drive][,[Unit][,[MaxDrives]]]]]
;
; DriverName 1 to 8 characters.
; Drive First drive letter to assign to drives attached to
; this driver.
; Unit First drive unit on this driver to be assigned to a
; drive letter. (Allowed range 0 to 99)
; MaxDrives Maximum number of drives on this driver that are to
; be assigned to drive letters.
;
; Note: The drive letter assigned to units of a second driver will
; always be higher than those assigned to the first driver and
; those assigned to a third driver will be higher than those
; assigned to the second.
;
; example: SHSUCDX
;
; SHSUCDX finds the first available drive letter and assigns it
; to device unit 0 of the default driver SHSU-CDN. If there is a
; second and/or third CD drive they are assigned to the next avail-
; able letters in sequence. Drive letters in use are skipped. The
; first CD supported by a driver is device unit 0 regardless of its
; SCSI address.
;
; example: SHSUCDX /D:CD001,F,,1 /D:SHSU-CDN,,1
;
; SHSUCDX assigns drive F to device unit 0 of the driver CD001.
; Units 1 and 2 of driver SHSU-CDN are then assigned to the next
; available letters.
;
; example: SHSUCDX /D:CD001,,1,1 /D:CD001,,4,1
;
; SHSUCDX assigns the first available drive letter to device unit 1
; of the driver CD001 and drive unit 4 to the next. This allows
; access to non-contiguous drive units without having to support
; un-needed units.
;
; unload: SHSUCDX [-u|/u]
;
; The following INT 2F, 15h functions are supported:
;
; 00 Get number of CD-ROM drives
; 01 Get CD-ROM drive device list
; 02 Get Copyright File Name
; 03 Get Abstract File Name
; 05 Read VTOC (1st only)
; 08 Absolute disk read
; 0B CDROM drive check
; 0C MSCDEX version
; 0D Get CD-ROM drive letters
; 0F Get directory Entry
; 10 Send device request
;
; SHSUCDX is a copyright reserved, free use program.
;
; (c)John H. McCoy, 1994,1995 Sam Houston St. Univ., TX 77341-2206
;
; ***************************************************************************
;
; Microsoft has not documented the redirector functions. I have borrowed
; from and am particularly indebted to the authors of:
;
; A CD-ROM redirector for HighSierra and ISO 9660 disks.
; Jim Harper, DDJ, March 1993
; Inside the ISO-9660 Filesystem Format
; William and Lynne Jolitz, DDJ, December 1992
; Undocumented DOS, Chapter 4.
; Andrew Schulman, et. al, Addison Wesley, 1990
;
; Written for MASM 6.0b. C functions compiled with MSC 5.1
; ***************************************************************************
;
; Modifications 3-4-94
; test redir not network bit on call
; set drive flags for physical network redir on install
; test for physical network redir before clearing root
option nokeyword:<name type length >
option expr16
; make offsets group relative instead of segment relative
.model small
fptr typedef far ptr
nptr typedef near ptr
include undoc.inc
True equ 1h
False equ 0h
AsciiNul equ 0
AsciiA equ 'A'
cr equ 0dh
lf equ 0ah
QMark equ '?'
UnknonwCDType equ 0
; redirector equates
REDIR equ 11h
InstallChk equ 00h
UnInstallCmd equ 04h
ChDir equ 05h
Close equ 06h
Flush equ 07h
Read equ 08h
Write equ 09h
GetSpace equ 0ch
SetAttr equ 0eh
GetAttr equ 0fh
Open equ 16h
FindFirst equ 1Bh
FindNext equ 1Ch
Seek equ 21h
PathName equ 23h
TOF equ 2dh ; truncate open file
EOpen equ 2eh
; CDS offsets
RootSlashOff equ 7
DriveOff equ 2
; MSCDEX equates
MSCDEX equ 15h
MSCDEX_Q equ 0DADAh
MSCDEX_R equ 0ADADh
;
MAXDRIVES equ 10
CACHESIZE equ 10
SECTORSIZE equ 2048
; declare protos, publics and externals
DoChDir proto near C
DoRead proto near C SFTp:fptr
DoGetSpace proto near C
DoGetAttr proto near C
DoOpen proto near C
DoClose proto near C SFTp:fptr
DoFindFirst proto near C
DoFindNext proto near C
DoSeek proto near C SFTp:fptr
InitDrive proto near C
ForUs proto near C DriveLetter: byte
SetDDD proto near C DriveLetter: byte
MsgOut proto near C msg:near ptr char
CdReadLong proto near C IOBuf:fptr,BlkNo:dword,NumBlks:word
CDMediaChanged proto near C
PathLook proto near C Dp:fptr, Pathp:fptr
ToHex proto near C Num:word
Main2F proto near
ParseCommandLine proto near
ClrRoot proto near
SetRoot proto near CDSx:fptr
PUBLIC C FN1p, DTApp, PSPp, SAttrp
PUBLIC C DosDp, SDBp, SFTpp
PUBLIC C DriveNo, DriveIndex, DeviceUnit, NoDrives
PUBLIC C CDSBase, CDSLen, CDSp
PUBLIC C Drive, IODatap
PUBLIC C _FLAGS,_AX,_BX,_CX,_DX,_SI,_DI,_ES,DataSeg
PUBLIC _DirCache, _IOData
DGROUP group _TEXT, _DATA, _BSS, C_COMMON, CONST, _INIT
; this is the way C wants it
_TEXT segment word PUBLIC 'CODE'
assume cs:DGROUP, ds:DGROUP
_TEXT ends
_DATA segment word PUBLIC 'DATA'
assume ds:DGROUP
_DATA ends
_BSS segment word PUBLIC 'BSS'
assume ds:DGROUP
_BSS ends
C_COMMON segment word PUBLIC 'BSS'
assume ds:DGROUP
C_COMMON ends
CONST segment word PUBLIC 'CONST'
assume ds:DGROUP
CONST ends
_INIT segment word PUBLIC 'INIT'
assume cs:DGROUP, ds:DGROUP
_INIT ends
EndOfCDX segment para STACK
byte "This STACK SEGMENT is here to satisfy loadhigh when using netx"
EndOfCDX ends
_DATA segment
byte "(c)John H. McCoy, 1994, Sam Houston St. Univ., TX 77341-2206"
align 2
local_stack word 128 dup ('ss')
top_stack word DGROUP:$
DevHeader fptr ?
DevStrategy fptr ?
DevInterrupt fptr ?
Old2F fptr ?
DataSeg word ?
_FLAGS word ?
_PSP word ?
_SP word ?
_SS word ?
_AX word ?
_BX word ?
_CX word ?
_DX word ?
_SI word ?
_DI word ?
_DS word ?
_ES word ?
PSPp fptr ?
FN1p fptr ?
SAttrp fptr ?
DosDp fptr ?
SDBp fptr ?
DTApp fptr ?
SFTpp fptr ?
CDSBase fptr ?
CdsLen word ? ; for this DOS version
CDSp fptr ? ; must be recalced for current drive
DrvEntLen word sizeof DrvEnt
IODatap word _IOData
DirCachep word _DirCache
align 1
Active byte 0h
FirstDriveNo byte 0
NoDrives byte MAXDRIVES
DriveNo byte ?
DeviceUnit byte ?
DriveIndex byte ?
ChainFlag byte False
rh_hdr byte 27 dup(?);
; ioctl in control blocks
IoCB_MediaChange byte 9
MediaChange byte ? ; 0 not changed
; 1 dont't know
; 0FFh media changed
IoCB_Status byte 6 ; ioctl get status subcommand
dword ? ; status bit 0 0 door closed
; 1 door open
; bit 1 0 door locked
; 1 door unlocked
; bit 4 0 data read only
; 1 data read and play audio
; bit 7 0 no prefetching
; 1 supports prefetching
; bit 9 0 HSG addressing only
; 1 HSG and RedBook audio addr
; bit 11 1 no CD in drive (best guess)
; ioctl out control blocks
IoCB_EjectCD byte 0 ; ioctl out eject subcommand
; Note!! It may be necessary to unlock a drive before the CD can be ejected.
IoCB_LockCD byte 1 ; ioctl out lock/unlock subcommand
byte 1 ; lock code
IoCB_UnLockCD byte 1 ; ioctl out lock/unlock subcommand
byte 0 ; unlock code
_DATA ends
_TEXT segment
New2F proc far
push ax
inc cs:Active
; is this call for us?
.if (((ah != REDIR) && (ah != MSCDEX)) || (cs:Active > 1))
dec cs:Active
pop ax
jmp cs:Old2F ; chain out
.endif
pop ax
; Handle REDIR install checks now, others after saving regs
.if ah == REDIR
.if al == InstallChk
push bp
mov bp, sp
.if [bp].frame.fr_Parm1 == MSCDEX_Q
mov [bp].frame.fr_Parm1, MSCDEX_R
.endif
mov ax,0ffh
pop bp
jmp Fexit
.elseif al == UnInstallCmd
.if bx == MSCDEX_Q
invoke ClrRoot
mov es, cs:_PSP ; tsr's psp
mov es:[16h], cx ; make unloader parent
mov es:[0ah], dx ; set terminate address
mov dx, ds
mov es:[0ah+2h], dx ; in psp
mov ah, 50h ; make TSR psp current psp
mov bx, es
int 21h
mov dx, word ptr cs:Old2F ; restore vector
mov ds, word ptr cs:Old2F[2]
mov ax, 252Fh
int 21h
mov ah,4ch ; normal terminate
int 21h ; will take us back to unloader
.else
dec cs:Active
jmp cs:Old2F ; chain out
.endif
.endif
.endif
; set up data addressing
mov cs:_DS, ds
push cs
pop ds
; save registers and switch to local stack
mov _AX, ax
mov _BX, bx
mov _CX, cx
mov _DX, dx
mov _SI, si
mov _DI, di
mov _ES, es
push bp
mov bp, sp
mov ax, [bp].frame.fr_Flags
mov _FLAGS, ax
mov _SP, sp
mov _SS, ss
cli
push cs
pop ss
mov sp, top_stack
sti
INVOKE Main2F
; switch back to callers stack and restore registers
cli
mov ss, _SS
mov sp, _SP
sti
mov bp, sp
mov ax, _FLAGS
mov [bp].frame.fr_Flags, ax
mov ax, _AX
mov bx, _BX
mov cx, _CX
mov dx, _DX
mov si, _SI
mov di, _DI
mov es, _ES
mov ds, _DS
pop bp
.if cs:ChainFlag
dec cs:Active
jmp cs:Old2F
.endif
Fexit:
dec cs:Active
iret
New2F endp
Main2F proc near
mov ChainFlag, False
mov ax, _AX
.if (ah == MSCDEX)
; Handle the MSCDEX calls
.if al == 00h ; get number of drive letters
mov al,NoDrives
cbw
mov _BX,ax
mov al,FirstDriveNo
cbw
mov _CX,ax
and _FLAGS, 0FFFEh ; A Ok
jmp MExit
.elseif al == 01h ; get drive device list
sub si, si
sub cx, cx
.while (cl< NoDrives)
mov ch, [si+Drive.Unit]
mov byte ptr es:[bx], ch
mov ax, word ptr [si+Drive.DevHdrp]
mov word ptr es:[bx+1], ax
mov ax, word ptr [si+Drive.DevHdrp+2]
mov word ptr es:[bx+3], ax
add si, sizeof DrvEnt
add bx, 5
inc cl
.endw
and _FLAGS, 0FFFEh ; A Ok
jmp MExit
.elseif al == 02h ; Get Copyright File Name
.if ( cl < 26 )
add cl, 'A'
invoke ForUs, cl ; sets DriveNo, DeviceUnit and DriveIndex
.if !(ax)
jmp @F
.endif
.endif
mov _AX, 015h ; error, invalid drive
or _FLAGS, 01h
jmp MExit
@@:
mov di, _BX
mov es, _ES
mov ax, sizeof DrvEnt
mul DriveIndex
lea bx, Drive.CopyRightID
add ax, bx
mov si, ax
mov cx, sizeof Drive.CopyRightID
cld
rep movsb
mov byte ptr es:[di], 0 ; make sure we have a 0
and _FLAGS, 0FFFEh ; A Ok
jmp MExit
.elseif al == 03h ; Get Abstract File Name
.if ( cl < 26 )
add cl, 'A'
invoke ForUs, cl ; sets DriveNo, DeviceUnit and DriveIndex
.if !(ax)
jmp @F
.endif
.endif
mov _AX, 015h ; error, invalid drive
or _FLAGS, 01h
jmp MExit
@@:
mov di, _BX
mov es, _ES
mov ax, sizeof DrvEnt
mul DriveIndex
lea bx, Drive.AbstractID
add ax, bx
mov si, ax
mov cx, sizeof Drive.AbstractID
cld
rep movsb
mov byte ptr es:[di], 0 ; make sure we have a 0
and _FLAGS, 0FFFEh ; A Ok
jmp MExit
.elseif al == 05h ; Read VTOC not complete! we only read first one
.if ( cl < 26 )
add cl, 'A'
invoke ForUs, cl ; sets DriveNo, DeviceUnit and DriveIndex
.if !(ax)
jmp @F
.endif
.endif
mov _AX, 015h ; error, invalid drive
or _FLAGS, 01h
jmp MExit
@@:
mov es, _ES
mov bx, _BX
invoke CdReadLong, es::bx, 10h, 1
.if (ax == 100h)
mov _AX, 01
and _FLAGS, 0FFFEh
.else
mov _AX, 021h ; drive not ready
or _FLAGS, 01h
.endif
jmp MExit
.elseif al == 08h ; Absolute disk read
.if ( cl < 26 )
add cl, 'A'
invoke ForUs, cl ; sets DriveNo, DeviceUnit and DriveIndex
.if !(ax)
jmp @F
.endif
.endif
mov _AX, 015h ; error, invalid drive
or _FLAGS, 01h
jmp MExit
@@:
.if (_DX == 0)
mov ax, 100h
.else
mov si, _SI
mov di, _DI
mov es, _ES
mov bx, _BX
invoke CdReadLong, es::bx,si::di,_DX
.endif
.if (ax == 100h)
mov _AX, 01
and _FLAGS, 0FFFEh
.else
mov _AX, 021h ; drive not ready
or _FLAGS, 01h
.endif
jmp MExit
.elseif al == 0Bh ; CDROM check
mov _BX, MSCDEX_R
.if ( cl < 26 )
add cl, 'A'
invoke ForUs, cl ; sets DriveNo, DeviceUnit and DriveIndex
.if !(ax)
jmp @F
.endif
.endif
mov _AX, 0h ; drive not supported by REDIR
jmp MExit
@@:
mov _AX, 0FFh
jmp MExit
.elseif al == 0Ch ; MSCDEX version
mov _BX, 0215h ; report ver 2.21
and _FLAGS, 0FFFEh ; A Ok
jmp MExit
.elseif al == 0Dh ; drive letters
mov ah, 0ffh
sub si, si
sub cx, cx
.while (cl< NoDrives)
mov ch, byte ptr [si+Drive.No]
mov byte ptr es:[bx], ch
add si, sizeof DrvEnt
inc bx
inc cl
.endw
and _FLAGS, 0FFFEh ; A Ok
jmp MExit
.elseif al == 0Fh ; Get Directory Entry
.if ( cl < 26 )
add cl, 'A'
invoke ForUs, cl ; sets DriveNo, DeviceUnit and DriveIndex
.if !(ax)
jmp @F
.endif
.endif
mov _AX, 015h ; error, invalid drive
or _FLAGS, 01h
jmp MExit
@@:
mov es, _ES
mov bx, _BX
mov si, _SI
mov di, _DI
and _FLAGS, 0FFFEh
invoke PathLook,si::di,es::bx
jmp MExit
.elseif al == 10h ; device request
.if ( cl < 26 )
add cl, 'A'
invoke SetDDD, cl ; sets DriveNo, DeviceUnit and DriveIndex
.if !(ax)
jmp @F
.endif
.endif
mov _AX, 015h ; error, invalid drive
or _FLAGS, 01h
jmp MExit
@@:
mov ax, sizeof DrvEnt
mul DriveIndex
mov bx, ax
mov ax, word ptr [bx+Drive.Strategyp]
mov word ptr DevStrategy, ax
mov ax, word ptr [bx+Drive.Strategyp+2]
mov word ptr DevStrategy+2, ax
mov ax, word ptr [bx+Drive.Interruptp]
mov word ptr DevInterrupt, ax
mov ax, word ptr [bx+Drive.Interruptp+2]
mov word ptr DevInterrupt+2, ax
push ds
mov es, _ES ; restore rh ptr
mov bx, _BX
mov ah, DeviceUnit
mov byte ptr es:rh.SubUnit[bx], ah
call cs:DevStrategy
call cs:DevInterrupt
pop ds ; in case device driver wiped out ds
mov es, _ES ; restore rh ptr
mov bx, _BX
.if (es:rh.Command[bx] == rhcmdIOCTL_In) ; on some drives we
les bx,es:rhIOCTL.CBPtr[bx] ; will miss media change
.if (byte ptr es:[bx] == 09h) ; if direct access checks
.if (byte ptr es:[bx+1] != 1) ; so, if media has changed
mov ax, sizeof DrvEnt ; set type to unknown to
mul DriveIndex ; force re-read on next
mov bx, ax ; non-direct access
mov word ptr [bx+Drive.Type], 0 ; 0 is type unknown
.endif
.endif
.endif
and _FLAGS, 0FFFEh ; A Ok from our perspective
jmp MExit
.else ; we don't support it
mov _AX,01h ; call it an error
or _FLAGS, 01h
jmp MExit
.endif
.endif
; handle redirector calls
.if (al == PathName)
mov ChainFlag, True
jmp MExit
.elseif (al == FindFirst || al == Open || al == EOpen || \
al == ChDir || al == GetAttr || al == TOF)
les di, FN1p
.if ((byte ptr es:[di+DriveOff] < 'A') || \
(byte ptr es:[di+DriveOff] > 'Z') )
mov ChainFlag, True
jmp MExit
.endif
invoke ForUs, byte ptr es:[di+DriveOff]
.if (ax == 0)
mov ax, _AX ; restores ax
.else
.if (ax == 1)
mov ChainFlag, True
.else
mov _AX, 015h ; drive not ready
.endif
jmp MExit
.endif
.if al == FindFirst
invoke DoFindFirst
.elseif al == Open || al == EOpen
mov al, DriveNo
cbw
mul CDSLen
les bx, CDSBase
add ax, bx
mov word ptr CDSp, ax
mov ax, es
mov word ptr CDSp+2, ax
mov bx, _BX
mov es, _ES
invoke DoOpen
.elseif al == ChDir
invoke DoChDir
.elseif al == GetAttr
invoke DoGetAttr
jmp MExit
.elseif al == TOF ; haven't got a clue about what to do
and _FLAGS, 0FFFEh ; just say we did it
mov _AX, 0h ; and flash 'em a smile
jmp MExit
.endif
.elseif al == FindNext
les di, SDBp ; get SDBp
mov al, byte ptr es:[di] ; SDBp->DriveLet (A - 0)
test al, 40h ; redir not network when set
jnz @F
mov ChainFlag, True ; not for us, chain out
jmp MExit
@@: and al, 01fh ; this part is actual drive letter
add al, 'A'
invoke ForUs, al
.if (ax == 0)
mov ax, _AX
.else
.if (ax == 1)
mov ChainFlag, True
.else
mov _AX, 015h ; drive not ready
.endif
jmp MExit
.endif
invoke DoFindNext
.elseif (al == Close || al == Read || al == Seek)
les di, SFTpp ; ptr to cur SFTp
les di, es:[di] ; SFTp
mov ax, es:[di].SFT.Flags
test al, 40h ; redir not network when set
jnz @F
mov ChainFlag, True ; not for us, chain out
jmp MExit
@@: and ax, 01fh
add al, 'A'
invoke ForUs, al
.if (ax == 0)
mov ax, _AX
mov es, _ES
mov di, _DI
.else
.if (ax == 1)
mov ChainFlag, True
.else
mov _AX, 015h ; drive not ready
.endif
jmp MExit
.endif
.if al == Read
invoke DoRead, es::di
.elseif al == Seek
invoke DoSeek, es::di
jmp MExit
.elseif al == Close
invoke DoClose, es::di
.endif
.elseif al == GetSpace ; es:di is curr CDSp
.if ((byte ptr es:[di+DriveOff] < 'A') || \
(byte ptr es:[di+DriveOff] > 'Z') )
mov ChainFlag, True
jmp MExit
.endif
invoke ForUs, es:[di+DriveOff]
.if (ax == 0)
invoke DoGetSpace
.else
.if (ax == 1)
mov ChainFlag, True
.else
mov _AX, 015h ; drive not ready
.endif
.endif
jmp MExit ; this calls not for me
.else
mov ChainFlag, True ; just chain out. Novell doesn't like
jmp MExit ; it if you call it an error
.endif
mov _AX, ax
MExit:
ret
Main2F endp
CdReadLong proc near C uses ds es bx si di, IOBufp: fptr,BlkNo: dword,NumBlks: word
mov ax, sizeof DrvEnt
mul DriveIndex
mov bx, ax
mov ax, word ptr [bx+Drive.Strategyp]
mov word ptr DevStrategy, ax
mov ax, word ptr [bx+Drive.Strategyp+2]
mov word ptr DevStrategy+2, ax
mov ax, word ptr [bx+Drive.Interruptp]
mov word ptr DevInterrupt, ax
mov ax, word ptr [bx+Drive.Interruptp+2]
mov word ptr DevInterrupt+2, ax
lea bx, rh_hdr
mov rh.Length[bx], 27
mov ah, DeviceUnit
mov rh.SubUnit[bx], ah
mov rh.Command[bx], rhcmdReadLong ; read long
mov ax, word ptr IOBufp
mov word ptr rhReadLong.Bufp[bx], ax
mov ax, word ptr IOBufp[2]
mov word ptr rhReadLong.Bufp[bx+2], ax
mov ax, word ptr BlkNo
mov word ptr rhReadLong.StartBlk[bx], ax
mov ax, word ptr BlkNo[2]
mov word ptr rhReadLong.StartBlk[bx+2], ax
mov ax, NumBlks
mov word ptr rhReadLong.Count[bx], ax
xor ax, ax ; zero for
mov rhReadLong.AddrMode[bx], al ; hsc addressing
mov rhReadLong.ReadMode[bx], al ; cooked mode
mov rhReadLong.ISize[bx], al
mov rhReadLong.ISkip[bx], al
push cs
pop es
call cs:DevStrategy
call cs:DevInterrupt
mov ax, word ptr cs:rh_hdr+rh.status
ret
CdReadLong endp
CdMediaChanged proc near C uses ds es bx si di
mov ax, sizeof DrvEnt
mul DriveIndex
mov bx, ax
mov ax, word ptr [bx+Drive.Strategyp]
mov word ptr DevStrategy, ax
mov ax, word ptr [bx+Drive.Strategyp+2]
mov word ptr DevStrategy+2, ax
mov ax, word ptr [bx+Drive.Interruptp]
mov word ptr DevInterrupt, ax
mov ax, word ptr [bx+Drive.Interruptp+2]
mov word ptr DevInterrupt+2, ax
mov bx, offset rh_hdr
mov rh.Length[bx], 26
mov ah, DeviceUnit
mov rh.SubUnit[bx], ah
mov rh.Command[bx], rhcmdIOCTL_In
mov ax, OFFSET IoCB_MediaChange
mov word ptr rhIOCTL.CBPtr[bx], ax
mov ax, SEG IoCB_MediaChange
mov word ptr rhIOCTL.CBPtr[bx+2], ax
mov word ptr rhIOCTL.BytesToTransfer[bx], size IoCB_MediaChange
xor ax, ax ; zero out other fields
mov rhIOCTL.MediaDesc[bx], al
mov rhIOCTL.StartSector[bx], ax
mov word ptr rhIOCTL.VolidPtr[bx], ax
mov word ptr rhIOCTL.VolidPtr[bx+2], ax
push cs
pop es
call cs:DevStrategy
call cs:DevInterrupt
mov al, cs:MediaChange ; use cs in case driver wiped out ds
cbw
ret
CdMediaChanged endp
ClrRoot proc near uses es bx ax cx dx si
sub si, si
sub cx, cx
.while (cl< cs:NoDrives)
mov ch, byte ptr cs:[si+Drive.No]
mov al, ch
cbw
mul cs:CDSLen
les bx, cs:CDSBase
add bx, ax
test es:[bx].CDS.Flags, 0C080h ; physical net redir drive ?
jz @F ; couldn't be our drive
mov ax, 0
mov es:[bx].CDS.Flags, ax ; clear drive flags
mov al, ch
add al, 'A'
mov es:[bx].CDS.CurrPath, al
mov al, ':'
mov es:[bx+1].CDS.CurrPath, al
mov al, '\'
mov es:[bx+2].CDS.CurrPath, al
mov al, 0
mov es:[bx+3].CDS.CurrPath, al
@@: add si, sizeof DrvEnt
inc cl
.endw
ret
ClrRoot endp
_TEXT ends
_INIT segment
ToHex proc near C public uses ax bx cx dx, Num:word
mov cl, 4
mov ch, 4
mov ah, 02h
mov dx, Num
.while ch > 0
rol dx, cl
mov bx, dx
and dx, 0fh
.if dl < 0Ah
add dl, '0'
.else
add dl, 'A' - 0Ah
.endif
int 21h
mov dx, bx
dec ch
.endw
ret
ToHex endp
; set up for one drive minimum
; drive table, cache and buffers are set up dynamically here at run time
align 2
Drive DrvEnt 1 dup (<>) ;MAXDRIVES dup (<>)
_DirCache DirEnt CACHESIZE dup (<>) ;MAXDRIVES*CACHESIZE dup (<>)
_IOData byte SECTORSIZE dup('B')
; insert filler so we don't wipe out INIT when whe init drive table and
; link up dir cache
if (MAXDRIVES-1)*(sizeof DrvEnt+CACHESIZE*sizeof DirEnt)-SECTORSIZE GT 0
byte (MAXDRIVES-1)*(sizeof DrvEnt+CACHESIZE*sizeof DirEnt)-SECTORSIZE dup (0)
endif
;============================================================================
; everything below this line is discarded after installing
; the redirector
; MSC pacifier
PUBLIC C _acrtused
_acrtused dw 1
; Credits
CopyrightMsg byte cr, lf
byte 'SHSUCDX Version 1.0',cr,lf
byte '(c)John H. McCoy, 1995, '
byte 'Sam Houston State University'
byte cr,lf, '$'
DrivesAssigned byte cr, lf
byte "SHSUCDX Installed.",cr,lf
byte " Drives Assigned",cr,lf
byte "Drive Driver Unit",cr,lf,'$'
UnInstalledMsg byte cr, lf
byte 'SHSUCDX un-installed and memory freed.'
byte cr, lf, '$'
CantUnInstallMsg byte cr, lf
byte 'SHSUCDX can''t un-install.'
byte cr, lf, '$'
CantInstallMsg byte ' SHSUCDX can''t install.',cr,lf,'$'
AlreadyInstalledMsg byte cr, lf, 'SHSUCDX or MSCDEX is already installed.$'
NoDrivesAvailMsg byte cr, lf,'Need More Drive Letters.$'
HighDriveMsg byte cr, lf,'Drive letter to high.$'
HighUnitMsg byte cr, lf,'Units specified don''t exist.$'
WrongDOSMsg byte cr, lf,'Must be DOS 3.3 - 7.xx.$'
CantFindCdMsg byte 'Can''t open CD driver $'
NotEnoughMemMsg byte 'Not enough memory. $'
CRLF byte cr, lf, '$'
DrvrEnt struct
Name byte 'SHSU-CDN'
byte 0
DrvrAddr fptr ?
Drive byte 0
Unit byte 0
NoWanted byte 0
DrvrEnt ends
NoDrivers byte ?
Drivers DrvrEnt MAXDRIVES dup (<>) ; one driver per drive is max
DriverIndex byte ?
FirstDeviceUnit byte ?
NoDeviceUnits byte ?
NoAvailUnits byte ?
NoUnitsWanted byte ?
LastDOSDrive byte ? ; 1 base
KeepSize word ?
ArgumentNotFound EQU 2 ; Unrecognized argument
NoArgumentsFound EQU 1 ; No argument in command line
ArgumentFound EQU 0 ; Ok argument in command line
UnInstallIt equ 2
DontInstallIt equ 1
InstallIt equ 0
InstallFlag byte 0
QuietFlag word 0
DosVer label word
osMajor byte ?
osMinor byte ?
IoctlInBuf byte 5 dup (0) ; get devhdr addr
IoctlOutBuf byte 2 ; reset CD
MsgOut proc near C public uses ax bx dx, msg:near ptr char
mov ah, 02h ; display ch function
mov bx, msg
mov dl, ds:[bx]
.while (dl != '$' && dl != 0)
int 21h
inc bx
mov dl, ds:[bx]
.endw
ret
MsgOut endp
DisplayDrives proc near
invoke MsgOut, addr DrivesAssigned
sub si, si
sub cx, cx
.while (cl< cs:NoDrives)
mov ah, 02h ; display ch function
mov dl, ' '
int 21h
int 21h
mov dl, byte ptr [si+Drive.Letter]
int 21h
mov dl, ':'
int 21h
mov dl, ' '
int 21h
int 21h
int 21h
sub bx, bx
.while (bx < 8)
mov dl, [si+bx+Drive.DriverName]
int 21h ; output driver name
inc bx
.endw
mov dl, ' '
int 21h
int 21h
mov dl, byte ptr [si+Drive.Unit]
.if (dl > 9) ; output drive unit
xor dh,dh
.while (dl > 9)
inc dh
sub dl, 10
.endw
xchg dl, dh
add dl, 30h
int 21h ; tens digit
xchg dl, dh
.endif
add dl, 30h
int 21h ; units digit
add si, sizeof DrvEnt
inc cl
invoke MsgOut, addr CRLF
.endw
ret
DisplayDrives endp
SetRoot proc near uses es ax bx cx di si , CDSx: fptr
les bx, CDSx
mov ax, 0C080h ; set physical network & redir bits
mov es:[bx].CDS.Flags, ax
; we don't set redirector address. Should we???
mov es:[bx].CDS.RootOff,RootSlashOff ; root \ in curr_path
; Set to CDS to CD root form \\D.\U.
mov al, '\'
mov es:[bx].CDS.CurrPath, al
mov es:[bx+1].CDS.CurrPath, al
mov al, cs:DriveNo
add al, 'A'
mov es:[bx+2].CDS.CurrPath, al
mov al, '.'
mov es:[bx+3].CDS.CurrPath, al
mov al, '\'
mov es:[bx+4].CDS.CurrPath, al
mov al, cs:DeviceUnit
add al, 'A'
mov es:[bx+5].CDS.CurrPath, al
mov al, '.'
mov es:[bx+6].CDS.CurrPath, al
mov al, 0
mov es:[bx+7].CDS.CurrPath, al
mov ax, sizeof DrvEnt
mul DriveIndex
mov bx, ax
mov al, DriveNo
mov [bx+Drive.No], al
add al, 'A'
mov [bx+Drive.Letter], al
mov al, DeviceUnit
mov [bx+Drive.Unit], al
mov ax, word ptr DevHeader
mov word ptr [bx+Drive.DevHdrp], ax
mov ax, word ptr DevHeader+2
mov word ptr [bx+Drive.DevHdrp+2], ax
mov word ptr [bx+Drive.Strategyp+2], ax
mov word ptr [bx+Drive.Interruptp+2], ax
mov ax, word ptr DevStrategy
mov word ptr [bx+Drive.Strategyp], ax
mov ax, word ptr DevInterrupt
mov word ptr [bx+Drive.Interruptp], ax
lea di, [bx+Drive.DriverName]
mov ax, ds
mov es, ax
lea si, [si+Drivers.Name]
mov cx, 4
cld
rep movsw ; ds:si->es:di
ret
SetRoot endp
InitDrive proc near C uses ax bx di si es
local DrvEntryp:nptr
local DirEntryp:nptr
local Bufp:nptr
local Ticks:word
; fill in drive entry first
mov ax, 0040h ; get clock ticks from 0040006Ch
mov es, ax
mov ax, es:[06Ch]
mov Ticks, ax
push ds
pop es
mov al, DriveIndex
cbw
mov bx, SectorSize
mul bx
add ax, word ptr IODatap
mov Bufp, ax ; addr of buffer for this drive
mov al, DriveIndex
cbw
mov bx, CACHESIZE
mul bx
mov bx, sizeof DirEnt
mul bx
add ax, DirCachep ; DirCache base ptr
mov DirEntryp, ax ; addr of first cache entry for this drive
mov ax, sizeof DrvEnt ; assume < 256
mul DriveIndex
add ax, offset Drive
mov bx, ax
mov ax, Bufp
mov [bx + DrvEnt.Bufp], ax
mov ax, UnknonwCDType
mov DrvEnt.Type[bx], ax
mov ax, 0FFFFh
mov word ptr DrvEnt.BufBlkNo[bx], ax
mov word ptr DrvEnt.BufBlkNo[bx+2], ax
mov ax, Ticks
mov DrvEnt.LastAccess[bx], ax
; link up cache for dir entries
mov ax, DirEntryp
mov DrvEnt.RootEnt.Forw[bx], ax
mov di, ax
mov si, ax
add si, sizeof DirEnt
mov DirEnt.Forw[di], si
lea ax, DrvEnt.RootEnt[bx]
mov DirEnt.Back[di], ax
mov cx, CACHESIZE
dec cx
.while (cx > 0)
mov DirEnt.Back[si], di
mov di, si
add si, sizeof DirEnt
mov DirEnt.Forw[di], si
dec cx
.endw
lea ax, DrvEnt.RootEnt[bx]
mov DirEnt.Forw[di], ax ; last entry points forw to root
mov DrvEnt.RootEnt.Back[bx], di ; root points back to last entry
ret
InitDrive endp
Init: PUBLIC Init
; set DS for addressing, move stack and save our psp address
mov ax, cs
mov ds, ax
mov ss, ax
mov sp, top_stack
mov DataSeg, ds
mov _PSP, es
; get command line parameters
invoke ParseCommandLine
.if (InstallFlag == UnInstallIt)
jmp UnInstall
.endif
; see if we are already installed
mov ax, MSCDEX_Q
push ax
mov ah, REDIR
mov al, InstallChk
int 2fh
pop bx
.if al == 0ffh ; redir installed, is it MSCDEX?
.if bx == MSCDEX_R
jmp AlreadyInstalled
.endif
.endif
; get DOS version
mov ah, 30h
int 21h
mov DosVer, ax
; get list of lists address thereby getting DOS seg
mov ah, 52h
int 21h ; es:bx is LOLp
mov word ptr DTApp+2, es ; set seg of DOS ptrs
mov word ptr PSPp+2, es
mov word ptr FN1p+2, es
mov word ptr SDBp+2, es
mov word ptr DosDp+2, es
mov word ptr SAttrp+2, es
mov word ptr SFTpp+2, es
mov ax, word ptr es:[bx].DOS_LOL.CDS
mov word ptr CDSBase, ax
mov ax, word ptr es:[bx].DOS_LOL.CDS+2
mov word ptr CDSBase+2, ax
; set version specific DOS parameters
.if osMajor ==3 && osMinor >= 30
mov CdsLen, 51h
mov si, 02ceh ; version 3.3+ offset
mov ax, si
add ax, 0ch
mov word ptr DTApp, ax
mov ax, si
add ax, 10h
mov word ptr PSPp, ax
mov ax, si
add ax, 92h
mov word ptr FN1p, ax
mov ax, si
add ax, 192h
mov word ptr SDBp, ax
mov ax, si
add ax, 1a7h
mov word ptr DosDp, ax
mov ax, si
add ax, 23ah
mov word ptr SAttrp, ax
mov ax, si
add ax, 268h
mov word ptr SFTpp, ax
.elseif osMajor >= 4 && osMajor <= 7 ; may need to check
; DOS seg [4] ==+01
mov CdsLen, 58h
mov si, 0320h ; version 4, 5, 6, & 7 offset
mov ax, si
add ax, 0ch
mov word ptr DTApp, ax
mov ax, si
add ax, 10h
mov ax, si
add ax, 9eh
mov word ptr FN1p, ax
mov ax, si
add ax, 19eh
mov word ptr SDBp, ax
mov ax, si
add ax, 1b3h
mov word ptr DosDp, ax
mov ax, si
add ax, 24dh
mov word ptr SAttrp, ax
mov ax, si
add ax, 27eh
mov word ptr SFTpp, ax
.else
jmp WrongDOS
.endif
; take advantage of the photo op
invoke MsgOut, addr CopyrightMsg
; find last available drive letter
mov ch, es:[bx].DOS_LOL.LastDrive
dec ch ; lol use 1 for 'A'
mov LastDOSDrive, ch
; assign drives
sub ax, ax
mov DriveIndex, al
mov DriverIndex, al
mov DriveNo, al
mov ah, NoDrivers
.while (al < ah) ; while DriverIndex < (NoDrivers)
; Open device driver and use IOCTL Input sub-command 0 to get
; the device header address.
mov ax, sizeof DrvrEnt
mul DriverIndex
add ax, offset Drivers.Name
mov dx, ax
sub al, al ; read only
mov ah, 3Dh
int 21h
jnc @f ; error when carry set
jmp CantFindCd
@@:mov bx, ax ; move handle to bx
mov ax, 4402h ; IOCTL input-get devhdr addr
mov cx, 5 ; dta has cmd code plus a fptr
lea dx, IoctlInBuf ; to device header
int 21h
; mov ax, 4403h ; IOCTL output-reset CD
; mov cx, 1 ; dta has cmd code only (1 byte)
; lea dx, IoctlOutBuf ; to device header
; int 21h
mov ah, 3eh ; close file handle in bx
int 21h
jnc @f ; error when carry set
jmp CantFindCd
@@:
les bx, dword ptr IoctlInBuf+1
mov word ptr DevHeader, bx
mov word ptr DevHeader+2, es
mov ax, es:[bx+6]
mov word ptr DevStrategy, ax
mov word ptr DevStrategy+2, es
mov ax, es:[bx+8]
mov word ptr DevInterrupt, ax
mov word ptr DevInterrupt+2, es
mov ax, sizeof DrvrEnt
mul DriverIndex
mov si, ax
mov al, [si + Drivers.Unit] ; first unit wanted
mov ah, es:[bx+21]
mov NoDeviceUnits, ah
.if (ah <= al)
invoke MsgOut, addr HighUnitMsg
jmp InitErrorExit
.endif
sub ah, al
mov NoAvailUnits, ah
mov DeviceUnit, al
mov al, [si + Drivers.NoWanted] ; units asked for
.if (al == 0) || ( al > NoAvailUnits)
mov al, NoAvailUnits
.endif
mov NoUnitsWanted, al
mov cl,[si + Drivers.Drive]
.if (cl < DriveNo)
mov cl, DriveNo
.endif
mov DriveNo, cl
mov ah, DriveIndex
; ah is DriveIndex al is NoUnitsWanted
.while (ah < MAXDRIVES) && (al > 0)
mov cl, DriveNo
call FindAvailDrive ; also sets CDSp for us
.if (cl != ch)
invoke MsgOut, addr NoDrivesAvailMsg
jmp InitErrorExit
.endif
mov DriveNo, cl
invoke SetRoot,CDSp ; uses CDSp, DevHeader, DriveIndex,
; DriveNo and DeviceUnit
inc DriveIndex
inc DriveNo
inc DeviceUnit
dec NoUnitsWanted
mov ah, DriveIndex
mov al, NoUnitsWanted
.endw
inc DriverIndex
mov al, DriverIndex
mov ah, NoDrivers
.endw
mov al, DriveIndex
.if (al == 0) ; then no drives were assigned
invoke MsgOut, addr HighDriveMsg
jmp InitErrorexit
.endif
mov NoDrives, al
; relocate buffers and init drive structs
mov cx, sizeof DrvEnt ; find Drive Table space needed
mov al, NoDrives
cbw
mul cx
add ax, offset Drive
mov DirCachep, ax ; relocate dir cache
mov cx, CACHESIZE ; find cache space needed
mov al, NoDrives
cbw
mul cx
mov cx, ax
mov ax, sizeof DirEnt
mul cx
add ax, DirCachep
mov IODatap, ax ; relocate IOData buffers
mov cx, SECTORSIZE ; find buffer space needed
mov al, NoDrives
cbw
mul cx
add ax, IODatap ; last byte to keep now in ax
add ax, 10Fh ; add 100h for psp and roundup
mov cl, 4
shr ax, cl ; program paragraphs to keep
mov KeepSize, ax
; get more space if we need it for buffers
mov bx, seg EndOfCDX
sub bx, _PSP
.if ax > bx
mov bx, ax
mov es, _PSP
mov ah, 04Ah ; modify block size
int 21h
jnc @F
invoke MsgOut, addr NotEnoughMemMsg
jmp InitErrorExit
@@:
.endif
; initialize drive table and link up dir cache
xor al, al
mov ah, NoDrives
mov DriveIndex, 0
.while al < ah
invoke InitDrive
inc DriveIndex
inc al
.endw
; Display drive assignments
mov al, Drive.No[0]
mov FirstDriveNo, al
invoke DisplayDrives
; capture 2F vector
mov ax, 352Fh
int 21h
mov word ptr Old2F ,bx
mov word ptr Old2F[2],es
mov dx, offset New2F
mov ax, 252Fh
int 21h
; release excess space and tsr
mov es, _PSP
sub ax, ax ;
xchg ax, es:[2Ch] ; zap evironment pointer in psp
or ax, ax ; ax := environment ptr
jz @f ; no environment if zero
mov es, ax
mov ah, 49h
int 21h ; and release environment
@@:
mov dx, KeepSize
mov ax,3100h
int 21h ; go TSR
mov ah, 4ch ; emergency exit in case we don't TSR
int 21h
UnInstall:
push bp
mov _SS, ss
mov _SP, sp
mov bx, MSCDEX_Q
mov cx, _PSP ; our psp
mov dx, offset UnInstalled ; uses ds:dx for successful return
mov ah, REDIR
mov al, UnInstallCmd
int 2fh
jmp CantUnInstall ; comes back here if unsuccessful
UnInstalled: ; or, here if successful
push cs
pop ds
mov ss, _SS
mov sp, _SP
pop bp
invoke MsgOut, addr UnInstalledMsg
jmp Initexit
CantUnInstall:
pop bp
push cs
pop ds
invoke MsgOut, addr CantUnInstallMsg
jmp Initexit
AlreadyInstalled:
invoke MsgOut, addr AlreadyInstalledMsg
invoke MsgOut, addr CantInstallMsg
jmp Initexit
CantFindCd:
invoke MsgOut, addr CantFindCdMsg
mov ax, sizeof DrvrEnt
mul DriverIndex
add ax, offset Drivers.Name
invoke MsgOut, ax
invoke MsgOut, addr CRLF
jmp InitErrorExit
WrongDOS:
invoke MsgOut, addr WrongDOSMsg
invoke MsgOut, addr CantInstallMsg
jmp InitExit
InitErrorExit:
.if DriveIndex > 0
mov al, DriveIndex
mov NoDrives, al
invoke ClrRoot
.endif
invoke MsgOut, addr CantInstallMsg
jmp InitExit
InitExit:
mov ah,4ch ; normal terminate
int 21h
FindAvailDrive proc near uses es bx
; Finds first available drive letter.
;
; Entry cl Starting letter for search
;
; Exit cl == ch Drive in cl is available
; cl != ch No drive available starting at specified drive
mov al, cl
cbw
mul CDSLen
les bx, CDSBase
add bx, ax ; es:bx FirstDriveNo CDSp
xor ch, ch
.while (cl <= LastDOSDrive)
test es:[bx].CDS.Flags, 0C000h ; drive in use ?
jnz @F
mov ch, cl
mov word ptr CDSp, bx ; set CDSp
mov word ptr CDSp+2, es
.break
@@: inc cl
add bx, CDSLen
.endw
ret
FindAvailDrive endp
ParseCommandLine proc near uses es
;* If driver is loaded from config.sys using device=drivername parms
;* then rhINIT points to the first character following the drivername
;* and a CR follows the last parm. When loaded by executing, the
;* command line is available in the PSP.(len +80h, 1st ch +81h, no CR)
sub ch, ch
mov di, 80h ; command line length psp +80h
mov cl, es:[di]
mov al, 'U' ; /U unInstall driver
call GetParm
.if ax == ArgumentFound
mov InstallFlag, UnInstallIt
jmp ParseExit
.endif
mov di, 80h ; command line length at psp +80h
sub ch, ch
mov cl, es:[di]
mov DriverIndex, 0
mov ax, ArgumentFound
.while ax == ArgumentFound
mov al, 'D' ; /D:drivername
call FindParm
.if ax == ArgumentFound
mov ax, sizeof DrvrEnt
mul DriverIndex
mov si, ax
mov dx, 8
call MoveName
mov al, es:[di]
.if cx == 0
jmp @F
.endif
.while (al != ',' && al != ' ')
inc di
mov al, es:[di]
dec cx
.if cx == 0 || al == '/'
jmp @F
.endif
.endw
dec cx
.if cx == 0
jmp @F
.endif
inc di
mov al, es:[di]
.if al == ' '
jmp @F
.elseif al != ',' ; check first driveno
.if (al >= 'a' && al <= 'z')
and al, 11011111y ; upper case it
.endif
.if (al >= 'A' && al <= 'Z')
sub al, 'A'
.else
jmp @F
.endif
mov [si+Drivers.Drive], al
dec cx
jcxz @F
inc di
mov al, es:[di]
.if al != ','
jmp @F
.endif
.endif
dec cx
jcxz @F
inc di
mov al, es:[di]
.if al != ',' ; check firstdeviceunit
.if (al >= '0' && al <= '9')
sub al, '0'
mov ah, es:[di+1] ; is it two digits?
.if (ah >= '0' && ah <= '9') ; ignore if not a digit
shl al,1 ; mul 1st digit by 10
mov ah, al
shl al,1
shl al,1
add al, ah
mov ah, es:[di+1] ; and add in 2nd digit
sub ah, '0'
add al, ah
dec cx
inc di
.endif
mov [si+Drivers.Unit], al
.else
jmp @F
.endif
dec cx
jcxz @F
inc di
.endif
dec cx
jcxz @F
inc di
mov al, es:[di]
.if al != ','
.if (al >= '0' && al <= '9')
sub al, '0'
mov [si+Drivers.NoWanted], al
.else
jmp @F
.endif
.endif
@@: inc DriverIndex
mov ax, ArgumentFound
dec di ; find parm needs ptr -1
.endif
.endw
mov al, DriverIndex
.if al ==0
inc al
.endif
mov NoDrivers, al
ParseExit:
ret
ParseCommandLine endp
MoveName proc near
sub bx, bx ; es:di points to 1st char
.repeat ; cx chars left on cmd line
mov al, es:[di] ; dx is length of name field
.if ((al == ',') || (cx == 0) || (al==' ') || (al == '/'))
mov byte ptr [si+bx+Drivers.Name], ' '
.else
.if (al >= 'a' && al <= 'z')
and al, 11011111y ; upper case it
.endif
mov byte ptr [si+bx+Drivers.Name], al
inc di
dec cx
.endif
inc bx
.until bx == dx
ret
MoveName endp
FindParm proc near
; al parm code we are to find /X: or -X:
; es:di first char on command line -1
; cx number of characters left on command line
GetNext: ; this code allows us to handle names
call GetParm ; like -C:NET-CD
cmp ax, ArgumentFound
jne NotFound
inc di ; found /X or -X, is next char a ':' ?
dec cl
mov al, es:[di]
cmp al, ':'
je FoundIt
loop GetNext
mov ax, ArgumentNotFound
ret
FoundIt:
inc di ; /X:name make di point @ name
dec cl
mov ax, ArgumentFound
NotFound:
ret
FindParm endp
;* GetParm - Scans command line for argument of form /X or -X where
;* X = specified ASCII character. Presumes that argument is preceded
;* by a '/' or a '-'. Comparisons are case insensitive.
;*
;* Params: ES:DI = Address of CommandLine -1
;* AL = Paramater character to scan for
;* CX = command line length
;*
;* Return: AX = One of the following codes:
;* NoArgumentsFound if empty command line
;* ArgumentFound if argument found
;* ArgumentNotFound if argument not as specified
;* ES:DI = Pointer to found argument
;* CX = chars left on command line including arg or 0
GetParm PROC NEAR
mov ah, NoArgumentsFound ; assume no /X style arguments
jcxz exit
.if (al >= 'a' && al <= 'z')
and al, 11011111y ; Make character upper case
.endif
; Find start of argument
loop1:
inc di ;
mov dl, es:[di] ; Get character from argument list
cmp dl, '/' ; Find option prefix '/'
je analyze
cmp dl, '-' ; or option prefix '-'
je analyze
loop loop1
jmp exit
; '/' or '-' prefix found. Compare command-line character
; with character specified in AL.
analyze:
inc di
dec cl
jcxz exit
mov ah, ArgumentFound ; Assume argument is okay
mov dl, es:[di]
.if (dl >= 'a' && dl <= 'z')
and dl, 11011111y ; Make character upper case
.endif
cmp dl, al
je exit ; specified char
mov ah, ArgumentNotFound ; Else signal bad argument,
loop loop1 ; continue scan
exit:
mov al, ah
cbw ; AX = return code
ret
GetParm ENDP
_INIT ends
end Init