*/
Are you blogging on PH? Get your free blog.
*/

View SOURCE\0CD.ASM

0cd CD-Rom Emulator v7.1 with Asm/Pascal sourcecode

Submitted By: WEBMASTER
Rating: (Not rated) (Rate It)


;??????????????????????????????????????????????????????????????????????????????
;?? RCS (Revision Control System) Version Log                                ??
;??????????????????????????????????????????????????????????????????????????????
;
; $Log: 0cd.asm $
; Revision 1.40  1995/12/06 22:13:29  Lasse
; Fixed so that -a was disabled if mscdex was loaded.
;
; Revision 1.39  1995/12/05 22:11:53  Lasse
; Adjusted the revision messages
;
; Revision 1.38  1995/12/05 22:00:45  Lasse
; Version 7.0; Removes data segment when going resident, shrinked down to
; 6.5 Kb of memory from 8.7 Kb. Also, fixed a bug when allocating more
; drives than available consecutively. Also, inserted rcs keywords in a
; message
;
; Revision 1.37  1995/12/05 09:05:14  Lasse
; Version 6.7; now co-exists with mscdex, and also enables audio through-
; put.
;
; Revision 1.36  1995/12/04 00:56:07  Lasse
; Version 6.6; Now works with worms too, and simulates the following new
; device requests:
;   Play
;   Stop
; also, the AudioStatus function has been augmented to react on the Play
; and Stop functions, and the HeadLocation function will return different
; values, as though the cd was playing or moving around.
; Also, the -a option will make 0cd simulate FakeCD.
;
; Revision 1.35  1995/12/03 02:35:45  Lasse
; Version 6.5; Fixed the root-directory subst problem which came back :(
;
; Revision 1.34  1995/11/26 09:46:54  Lasse
; Version 6.4; Fixed several bugs with the DiskFree function
;
; Revision 1.33  1995/11/16 06:36:22  Lasse
; Fixed a bug in the makecd program, and an inconsistency in 0cd
;
; Revision 1.32  1995/11/16 06:14:39  Lasse
; Put Decrunch into 0cd.asm for maximum distributability
;
; Revision 1.31  1995/11/16 06:04:28  Lasse
; Version 6.2
;
; Revision 1.30  1995/11/16 05:24:59  Lasse
; Commented all code; Done some minor cosmetic changes, tidied up the
; code a bit
;
; Revision 1.29  1995/11/14 22:04:22  Lasse
; If last character in directory was \ then redirection failed; fixed!
;
; Revision 1.28  1995/11/14 21:57:59  Lasse
; Removed the "Unmangling" of filename
;
; Revision 1.27  1995/11/14 21:46:19  Lasse
; Version 6.2; Fixed so that magic carpet works; Fixed so that DiskFree(d:)
; where d: is a cd-rom now returns correct data
;
; Revision 1.26  1995/11/14 19:50:33  Lasse
; Bug in previous revision concerning the drive letter in speed messages;
; fixed
;
; Revision 1.25  1995/11/14 19:48:43  Lasse
; Fixed so that speed message included correct drive letter
;
; Revision 1.24  1995/11/14 19:29:30  Lasse
; Version 6.1; Super speed emulation enabled
;
; Revision 1.23  1995/11/14 19:02:11  Lasse
; Updated the usage message, and renamed VTC to data
;
; Revision 1.22  1995/11/14 18:51:36  Lasse
; Version 6.0; Now simulates speed of cd-rom; Also read sector 16 (system
; data)
;
; Revision 1.21  1995/11/12 21:52:52  Lasse
; Version 5.0; fixed a couple of bugs with the audio track information
;
; Revision 1.20  1995/11/12 08:14:22  Lasse
; Version 4.1
;
; Revision 1.19  1995/11/12 08:09:58  Lasse
; Removed some old dummy-stuff
;
; Revision 1.18  1995/11/12 06:44:56  Lasse
; Audio Status now responds music paused; fix necessary for MechWarrior 2
;
; Revision 1.17  1995/11/12 03:39:43  Lasse
; Fixed the return to directory bug
;
; Revision 1.16  1995/11/12 03:24:55  Lasse
; Bug-fix; couldn't supply more than name.ext, no dir to run
;
; Revision 1.15  1995/11/12 03:21:29  Lasse
; Version 4; supply name of program to run
;
; Revision 1.14  1995/11/12 02:34:58  Lasse
; Fixed so that it reads audio data also
;
; Revision 1.13  1995/11/11 22:51:03  Lasse
; Fixed so cd-roms could be redirected to the root of a drive
;
; Revision 1.12  1995/11/11 22:48:52  Lasse
; Fixed a bug which caused strange symbols in 'dir' listings
;
; Revision 1.11  1995/11/11 22:39:32  Lasse
; Fixed so it didn't automatically write protect cd-roms unless the user
; asked for it
;
; Revision 1.10  1995/11/11 20:50:50  Lasse
; DiskFree function now clears carry flag
;
; Revision 1.9  1995/11/11 20:44:24  Lasse
; Version 3.1; added option to supply name of .vtc file
;
; Revision 1.8  1995/11/11 20:15:29  Lasse
; Returns dummy filenames, and uses CD0.VTC - CD7.VTC instead of DIR.VTC
; so that the same directory may be used for different cd's.
;
; Revision 1.7  1995/11/11 05:55:23  Lasse
; Fixed so it reads the VTOC into memory and returns it upon request.
;
; Revision 1.6  1995/11/10 23:14:47  Lasse
; Fixed the volume label bug that appeared in the last revision.
;
; Revision 1.5  1995/11/10 23:05:40  Lasse
; Fixed a bug when checking more than 8 drives past the first emulated
; cd-rom drive.
;
; Revision 1.4  1995/11/07 22:15:01  Lasse
; Version 2.0
;
; Revision 1.3  1995/11/07 22:13:19  Lasse
; Now saves current drive and directory and restores them when the sub-
; process exits. Also has self-installed check code now.
;
; Revision 1.2  1995/11/07 21:50:29  Lasse
; Moved all string procedures into 0cd.asm itself. Tidied up some of the
; code. Replace the uppercase functions. Fixed so that the GetDirEntry call
; to MSCDEX will go through (possibly returning garbage, but...) and some
; other stuff.
;
; Revision 1.1  1995/11/07 20:15:56  Lasse
; Initial revision
;
;
;??????????????????????????????????????????????????????????????????????????????
;?? Assembler options and directives                                         ??
;??????????????????????????????????????????????????????????????????????????????

ideal         ; IDEAL assembly mode

stacksize       = 60h    ; Size of stack (words)

p386            ; Select the processor
p387            ; Support for math coprocessor
model tiny, pascal            ; Always must be TINY model

;??????????????????????????????????????????????????????????????????????????????
;?? Initialized data segment                                                 ??
;??????????????????????????????????????????????????????????????????????????????

dataseg   ; Initialized data segment

MaxCDs  = 8
HookMsg db       '0cd: installed', 13, 10, 0
MSCDEX  db        '0cd error: mscdex already installed', 13, 10, 0
Installed       db     '0cd error: already installed', 13, 10, 0
NoRedirs        db      '0cd error: no redirections specified', 13, 10, 0
UnknownOp       db     '0cd error: unknown command line parameter: ', 0
InvOption       db     '0cd: invalid option ',0
TooManyCDs      db    '0cd error: cannot handle more than ',48+MaxCDs
        db      ' drives', 13, 10, 0
No66Msg db       '0cd error: int 66h not available', 13, 10, 0
NoDrives        db      '0cd error: no drives available', 13, 10, 0
NotRoom db       '0cd error: no more drive letters available', 13, 10, 0
CDSize  db        '0cd: host drive(s) and cd-rom(s) report host drive(s) size', 13, 10, 0
CD0     db   '0cd: host drive(s) and cd-rom(s) report 0 bytes free', 13, 10, 0
IsProt  db        '0cd: cd-rom(s) are write protected', 13, 10, 0
NotProt db       '0cd: cd-rom(s) are not write protected', 13, 10, 0
DataTooBig      db    '0cd error: data file is too big (>65535 bytes)', 13, 10, 0
DataNoMem       db     '0cd error: no memory for data file', 13, 10, 0
RunProg db       '0cd: program to run is ', 0
UnknownSpd      db    '0cd error: unknown speed option ', 0
InvDrive        db      '0cd warning: can only adjust drive letter before redirections', 13, 10, 0
SuccessMsg      db    '0cd: functions will succeed with dummy data', 13, 10, 0
FailMsg db       '0cd: functions will fail with no data', 13, 10, 0
AltMsg  db        '0cd: alternate simulation enabled', 13, 10, 0
TruMsg  db        '0cd: audio through-put enabled',       13,    100
NoMSCDEX        db      '0cd warning: no mscdex detected, audio through-put not enabled', 13, 10, 0
CoMsg   db '0cd: mscdex co-existance enabled',      13,   10,        0
UnknownMSC      db    '0cd error: unknown mscdex option   ',0
TooFew  db        '0cd error: not enough consecutive drive letters, use the /lx option', 13, 10, 0

UnknownSim      db    '0cd error: unknown simulation option       ',0
SimMsg1 db       '0cd: drive '
SimDrv  db        'E'
        db      ': simulates a ',0
SimMsg2 db       'physical drive', 13, 10, 0
SimMsg3 db       'substed drive', 13, 10, 0
SimMsg4 db       'remote or cd-rom drive', 13, 10, 0
SpeedMsg1       db     '0cd: drive '
SpeedDrv        db      'E'
        db      ': is a',0
SpeedMsg2       db     ' drive', 13, 10, 0
SingleMsg       db     ' single speed',0
DoubleMsg       db     ' double speed',0
TripleMsg       db     ' triple speed',0
QuadraMsg       db     ' quadra speed',0
SexaMsg db       ' sexa speed',0
OctaMsg db       'n octa speed',0
SuperMsg        db      ' super speed',0

ReadData1       db     '0cd: data for drive '
ReadData2       db     '?'
ReadData3       db     ': read into memory from ', 0

Prompt1 db       '0cd: mounted ', 0
Prompt2 db       ': in ', 0
DriveID db       0, 0
AnyRedir        db      0
CSEnv   db 'COMSPEC=',0
UsageMsg        db      '0cd usage: 0cd [options] <directory> [<directory> ... ]', 13, 10
        db      '0cd options: -q         = quiet; no messages except for error messages',     13, 10
        db      '             -0         = host and cd-rom drives report 0 bytes free', 13, 10
        db      '             -w         = cd-rom drives are write protected', 13, 10
        db      '             -dfilename = supply name of data file', 13, 10
        db      '             -rfilename = supply name of program to run',13,10
        db      '             -sx        = supply speed of drive (x=s, 1, 2, 3, 4, 6 or 8)', 13, 10
        db      '             -i0        = simulate physical drive', 13, 10
        db      '             -i1        = simulate substed drive', 13, 10
        db      '             -i2        = simulate remote or cd-rom drive (default)', 13, 10
        db      '             -f         = failure if no cd-rom data', 13, 10
        db      '             -a         = alternate simulation', 13, 10
        db      '             -mx        = mscdex co-existance level (x=0-3, default=0)', 13, 10
        db      '             -v         = show revision information', 13, 10, 0
CRLF    db  13, 10, 0

Line    db  30 dup (0)
PathName        db      128 dup (0)
DataName        db      128 dup (0)
RevMsg  db        '0cd: revision $Revision: 1.40 $', 13, 10
        db      '0cd: state $State: Exp $', 13, 10
        db      '0cd: source $Source: D:/ASM/PROJECTS/0CD/RCS/0cd.asm $', 13, 10
        db      '0cd: rcsfile $RCSfile: 0cd.asm $', 13, 10
        db      0
Label   EndOfData word

;??????????????????????????????????????????????????????????????????????????????
;?? Uninitialized data segment                                               ??
;??????????????????????????????????????????????????????????????????????????????

;??????????????????????????????????????????????????????????????????????????????
;?? Code segment                                                             ??
;??????????????????????????????????????????????????????????????????????????????

        assume  cs:@code,
                ds:@data,
                es:@data

codeseg   ; Code segment
 
;??????????????????????????????????????????????????????????????????????????????
;?? Macro declarations                                                       ??
;??????????????????????????????????????????????????????????????????????????????

macro   iCLC
        push    bp  ; Preserve BP register
        mov     bp,sp        ; Set BP to     stack pointer
        and     [word ptr bp+6],0fffeh       ; Modify flags on the stack
        pop     bp   ; Restore BP register
endm

macro   iSTC
        push    bp  ; Preserve BP register
        mov     bp,sp        ; Set BP to     stack pointer
        or      [word ptr bp+6],0001h ; Modify flags on the stack
        pop     bp   ; Restore BP register
endm

;??????????????????????????????????????????????????????????????????????????????
;?? Program initialization                                                   ??
;??????????????????????????????????????????????????????????????????????????????

        StartUpCode     ; Insert startup code
        mov     sp,offset TheStack   ; Fix stack pointers
        mov     bx,offset EndOfData  ; Get      end   of data    segment
        shr     bx,4 ; Make segment count
        add     bx,1 ; Make last segment count
        mov     ah,4ah       ; Fn 4ah = Resize memory block
        int     21h  ; Call dos interrupt
        push    cs  ; Point ds to
        pop     ds   ; data segment (after code)
        push    cs  ; Point es to
        pop     es   ; data segment (after code)

;??????????????????????????????????????????????????????????????????????????????
;?? User-code                                                                ??
;??????????????????????????????????????????????????????????????????????????????

        call    SaveDir
        call    GetCOMSPEC
        call    Init
        call    Report
        call    Hook
        call    MinMem
        call    Exec, cs offset ProgName, cs offset Params
        call    UnHook
        call    ReturnDir

;??????????????????????????????????????????????????????????????????????????????
;?? Exit program here, returning 0000h as ExitCode (ERRORLEVEL in DOS)       ??
;??????????????????????????????????????????????????????????????????????????????

        ExitCode        0000h   ; Return to        dos, clear up heap

;??????????????????????????????????????????????????????????????????????????????
;?? Procedure/function declarations                                          ??
;??????????????????????????????????????????????????????????????????????????????

; Code segment variables
OldDir  db        79 dup (0)
OldDrive        db      0

ProgName        db      128 dup (0)
Params  db        '/C '
RunName db       '0CDSTART.BAT',0
        db      115 dup (0)
SimType db       2
SimFlag dw       0100000010000000b
CoMSCDEX        db      0
FirstRealCD     db   0
AudioTru        db      0
AltSimul        db      0
DoFailure       db     0
CDPlaying       dw     0001h
CDPos   dw 0010h
CurSpeed        db      2
CurDelay        dw      6200
UnHookMsg       db     '0cd: removed', 13, 10, 0
InitMsg db       '0cd: version 7.1', 13, 10, 0
Inited  db        0
Datas   db 2*MaxCDs dup (0)
FirstID db       0
LastID  db        0
IsRun   db 0
RetZero db       0
WriteProt       db     0
Quiet   db 0
DriveCount      db    0
DriveSpeeds     dw   MaxCDs dup (0)
DeviceHdr       dw     -1, -1
        dw      0100100001000000b
        dw      Strategy
        dw      Strategy      ; No interrupt
        db      '0CD-CDx',0
        db      0,0

        dw      stacksize dup (0)     ; Set up space for stack
Label   TheStack   Word       ; Here begins the stack

; Strategy procedure
proc    Strategy    far
        ret          ; Return to  caller
endp

; MinMem procedure
proc    MinMem
        mov     ah,62h       ;      Dos   Fn 62h = Get PSP in        bx
        int     21h  ; Call dos interrupt
        mov     es,bx        ;       Store  in es     for  realloc
        mov     ah,4ah       ;      Dos   Fn 4ah = Realloc
        lea     bx,[HookMsg] ;        Get     offset of    data
        shr     bx,4 ;        Calculate       segments
        inc     bx   ;  Adjust for last   segment
        int     21h  ; Reallocate memory
        ret          ;    Return to   caller
endp

; GetCDData procedure
; returns segment in    es, or 0-segment if failure
proc    GetCDData
arg     @@DriveID:word
local   @@Handle:word, @@NewSeg:word, @@Size:word
uses    ax, bx, si
        mov     [@@NewSeg],0 ; No segment yet
        cmp     [byte ptr ds:DataName],0     ; Got a filename of datafile ?
        je      @@Exit        ; No --> @@Exit

        mov     ah,3dh       ; Dos Fn 3dh = Open file
        lea     dx,[DataName]        ; Filename in dx:dx
        mov     al,00h       ; Open mode    in al
        int     21h  ; Call DOS interrupt
        jc      @@Exit        ; Error -->     @@Exit
        mov     [@@Handle],ax        ; Save file handle

        mov     ax,4202h     ; Dos Fn 42  = LSeek
        mov     bx,[@@Handle]        ; Filehandle in bx
        xor     cx,cx        ; High 16 bits of position
        xor     dx,dx        ; Low 16 bits of position
        int     21h  ; Call DOS interrupt

        test    dx,dx       ; File larger than 64K ?
        jz      @@OkSize      ; No --> @@OkSize
        mov     ah,3eh       ; Dos Fn 3eh = Close file
        mov     bx,[@@Handle]        ; Filehandle in bx
        int     21h  ; Call DOS interrupt
        mov     [cs:Quiet],00h       ; Turn of quiet mode
        call    LStrWrite, offset DataTooBig        ; Write error msg
        call    CleanUp     ; Clean up
        ExitCode        0001h   ; Exit to DOS
@@OkSize:
        mov     [@@Size],ax  ; Save size       of file
        shr     ax,4 ; Divide by      16
        inc     ax   ; And add 1
        mov     bx,ax        ; Number of     segments in  bx
        mov     ah,48h       ; Dos Fn 48h = AllocMem
        int     21h  ; Call DOS interrupt
        jc      @@NoMem       ; Error -->    @@NoMem
        mov     es,ax        ; Segment in es
        mov     [@@NewSeg],ax        ; Store new     segment

        mov     ax,4200h     ; Dos Fn 42  = LSeek
        mov     bx,[@@Handle]        ; Filehandle in bx
        xor     cx,cx        ; High 16 bits of position
        xor     dx,dx        ; Low 16 bits of position
        int     21h  ; Call DOS interrupt

        mov     ah,3fh       ; Dos Fn 3fh = Read file
        mov     bx,[@@Handle]        ; Filehandle in bx
        push    ds  ; Save ds
        push    es  ; Put ds ...
        pop     ds   ; ... in es
        xor     dx,dx        ; High 16 bits of size in dx
        mov     cx,[@@Size]  ; Low 16 bits of size in cx
        int     21h  ; Call DOS interrupt
        pop     ds   ; Restore ds

        mov     al,[byte ptr @@DriveID]      ; Get driveletter
        mov     [ReadData2],al       ; Update message text
        call    LStrWrite, offset ReadData1 ; Write text
        call    LStrWrite, offset DataName  ; Write filename
        call    LStrWrite, offset CRLF            ; Newline
        mov     bx,[@@Handle]        ; Filehandle in bx
        mov     ah,3eh       ; Dos Fn 3eh = Close file
        int     21h  ; Call DOS interrupt
        jmp     @@Exit       ; Exit
@@NoMem:
        mov     bx,[@@Handle]        ; Filehandle in bx
        mov     ah,3eh       ; Dos Fn 3eh = Close file
        int     21h  ; Call DOS interrupt
        mov     [cs:Quiet],00h       ; Turn off quiet mode
        call    LStrWrite, offset DataNoMem ; Write error msg
        call    CleanUp     ; Clean up
        ExitCode        0001h   ; Exit to dos
@@Exit:
        lea     si,[Datas]   ; ds:si point to Datas
        mov     cx,[@@DriveID]       ; Get drive    letter
        sub     cl,[cs:FirstID]      ; Make 0-based
        cmp     cl,0 ; First drive ?
        je      @@DoExit      ; Yes --> @@DoExit
@@Loop:
        add     si,2 ; Next data      index
        dec     cl   ; One less to skip
        jnz     @@Loop       ; More --> @@Loop
@@DoExit:
        mov     es,[@@NewSeg]        ; Return segment in es
        mov     [ds:si],es   ; Save segment in Datas
        ret          ; Return to  caller
endp

; Report procedure
proc    Report
        cmp     [cs:CoMSCDEX],01h    ;   MSCDEX co-existance        ?
        jne     @@NoCoEXIST
        call    LStrWrite, offset CoMsg     ;    Write       message
@@NoCoExist:
        cmp     [cs:AudioTru],00h    ;   Audio      throughput ?
        je      @@NoTru       ;      No --> @@NoTru
        call    LStrWrite, offset TruMsg    ;   Write      message
@@NoTru:
        cmp     [cs:AltSimul],00h    ;   Alternate  simulation ?
        je      @@NoAlt       ;      No --> @@NoAlt
        call    LStrWrite, offset AltMsg    ;   Write      message
@@NoAlt:
        cmp     [cs:DoFailure],00h   ;  Failure   or success ?
        je      @@Success
        call    LStrWrite, offset FailMsg   ;  Write     message
        jmp     @@OkFail
@@Success:
        call    LStrWrite, offset SuccessMsg        ;       Write  message
@@OkFail:
        cmp     [cs:WriteProt],00h   ; Write-protected ?
        je      @@NotProt     ; No --> @@NotProt
        call    LStrWrite, offset IsProt    ; Write message
        jmp     @@Size       ; --> @@Size
@@NotProt:
        call    LStrWrite, offset NotProt   ; Write message
@@Size:
        cmp     [cs:RetZero],00h     ;    Zero disk   free ?
        je      @@NotZero     ;    No --> @@NotZero
        call    LStrWrite, offset CD0       ;      Write message
        jmp     @@Exit       ;      Exit
@@NotZero:
        call    LStrWrite, offset CDSize    ;   Write      message
@@Exit:
        call    LStrWrite, offset CRLF      ;     Write        an empty line
        ret          ;    Return to   caller
endp

; SaveDir procedure
proc    SaveDir
uses    ax, si, dx
        mov     ah,47h       ;      Dos   Fn 47h = GetCurDir
        lea     si,[OldDir+1]        ;       Destination in ds:si
        push    ds
        push    cs
        pop     ds
        mov     [byte ptr ds:si-1],'\'       ;      Make \ relative
        mov     dl,00h       ;      Set   to current drive
        int     21h  ; Call DOS interrupt
        pop     ds

        mov     ah,19h       ;      Dos   Fn 19h = GetCurDrive
        int     21h  ; Call DOS interrupt
        mov     [cs:OldDrive],al     ;    Save drive
        ret          ;    Return to   caller
endp

; ReturnDir     procedure
proc    ReturnDir
uses    ax, dx
        mov     ah,0eh       ;      Dos   Fn 0eh = SetCurDrive
        mov     dl,[cs:OldDrive]     ;    Drive       no in dl
        int     21h  ; Call DOS interrupt

        mov     ah,3bh       ;      Dos   Fn 3bh = SetCurDir
        lea     dx,[OldDir]  ; Directory        in ds:dx
        push    ds
        push    cs
        pop     ds
        int     21h  ; Call DOS interrupt
        pop     ds
        ret          ;    Return to   caller
endp

; LStrWrite procedure
proc    LStrWrite
arg     @@Str:word
        cmp     [cs:Quiet],1 ;        Quiet   mode ?
        je      @@Exit        ;       Yes    --> @@Exit
        cmp     [cs:Inited],0        ;       Already        shown version   ?
        jne     @@Ok ;        Yes     -->  @@Ok
        mov     [cs:Inited],1        ;       Set    version shown flag
        call    StrWrite, cs offset InitMsg ;        Show version message
@@Ok:
        call    StrWrite, [@@Str]   ;  Write     text
@@Exit:
        ret          ;    Return to   caller
endp

; Init procedure
proc    Init
        call    GetFirstDrive
        call    ReadDescription
        call    Needed
        call    CheckMSCDEX
        ret
endp

; GetCOMSPEC procedure
proc    GetCOMSPEC
uses    ax, si, di, es, ds
        mov     ah,62h       ;      Dos   Fn 62h = Get PSP
        int     21h  ; Call DOS interrupt
        mov     es,bx        ;       Segment        of PSP in es
        mov     es,[es:002ch]        ;       Get    environment segment
        xor     si,si        ;       Start  of environment
@@Loop:
        call    StrLIComp, es si, ds offset CSEnv, 8        ;       COMSPEC=xxx ?
        jc      @@Next        ;       No --> @@Next
        add     si,8 ;        Skip to xxx
        call    StrCopy, cs offset ProgName, es si  ; Save program name
        jmp     @@Exit       ;      Exit
@@Next:
        inc     si   ;  Next character
        cmp     [byte ptr es:si],0   ;  At end of string ?
        jne     @@Next       ;      No --> @@Next
        inc     si   ;  Skip end-of-string char
        cmp     [byte ptr es:si],0   ;  End       of environment ?
        jne     @@Loop       ;      No --> @@Loop
@@Exit:
        ret          ;    Return to   caller
endp

; Needed procedure
proc    Needed
        cmp     [AnyRedir],1 ;        Any     redirections at all ?
        je      @@Exit        ;       Yes    --> @@Exit
        call    LStrWrite, offset NoRedirs  ; Write    error message
        call    CleanUp     ;    Clean       up
        ExitCode        0001h   ;  Exit to   dos
@@Exit:
        call    CheckFile   ;  Check     for  program to run
        ret          ;    Return to   caller
endp

; CheckFile     procedure
proc    CheckFile
        mov     ax,3d00h     ;    Dos Fn 3d    = Open file
        push    ds
        push    cs
        pop     ds
        lea     dx,[RunName] ;        Filename in ds:dx
        int     21h  ; Call DOS interrupt
        pop     ds
        jc      @@NoFile      ;     Error        -->     @@NoFile
        mov     bx,ax        ;       Filehandle in bx
        mov     ah,3eh       ;      Dos   Fn 3eh = Close file
        int     21h  ; Call DOS interrupt
        call    LStrWrite, offset RunProg   ;  Show run message
        push    ds cs       ;      Save ds       and    put cs ...
        pop     ds   ;  ...       into ds
        call    LStrWrite, offset RunName   ;  Show name of program
        pop     ds   ;  Restore   ds
        call    LStrWrite, offset CRLF      ;     Newline
        jmp     @@Exit       ;      Exit
@@NoFile:
        mov     [byte ptr cs:Params],0       ;      No parameters to COMSPEC
@@Exit:
        ret          ;    Return to   caller
endp

; GetCDS procedure
; Returns pointer in    es:bx, and carry set if success, or 0:0      in es:bx and
; carry clear if failure
proc    GetCDS
arg     @@DriveID:word
uses    ax
        call    UpCase, [@@DriveID] ;        Make letter uppercase
        mov     [@@DriveID],ax       ;      Store in @@DriveID

        mov     ah,52h       ;      Dos   Fn 52h = Get DosSysVars
        int     21h  ; Call DOS interrupt
        add     bx,16h       ;      Skip to       CDS entry
        les     bx,[dword ptr es:bx] ;        Get     pointer to CDS in    es:bx
        mov     al,'A'       ;      First drive letter in  CDS
@@Loop:
        cmp     al,[byte ptr @@DriveID