home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / dirutl / dp13.arc / DP13.ASM next >
Encoding:
Assembly Source File  |  1987-02-04  |  29.5 KB  |  991 lines

  1.            PAGE   61,132
  2.  
  3.            TITLE  DataPath 1.3 - Not Copyrighted (nc) 1987 - GDC Software
  4.  
  5.            COMMENT *
  6.  
  7.    DATAPATH.COM -  This program attaches itself to MS-DOS or PC-DOS for
  8.            automatic search of specified subdirectories or disks for
  9.            a program's support ( help, overlay, etc.) files.  It will
  10.            support CP/M style calls ( CALL 0005h ) as well as normal
  11.            MS-DOS calls.  Detailed information on use and technical
  12.            information is in the file DATAPATH.DOC.
  13.  
  14.  
  15.     ASSEMBLY    -  MASM DATAPATH;
  16.            LINK DATAPATH;
  17.            EXE2BIN DATAPATH.EXE DATAPATH.COM
  18.  
  19.     AUTHOR    -  Bruce Dubbs
  20.            GDC Software
  21.            122 Valencia Dr.
  22.            Universal City, TX 78148
  23.  
  24.            THIS PROGRAM IS NOT COPYRIGHTED 1987.  IT IS RELEASED INTO
  25.            THE PUBLIC DOMAIN FOR WHATEVER USE YOU WANT.  IF YOU WANT
  26.            TO DISTRIBUTE THIS PROGRAM OR USE IT WITH ANY OTHER WAY,
  27.            AN ACKNOWLEDGEMENT WOULD BE NICE.                *
  28.  
  29.  
  30.            SUBTTL Basic Definitions and Setup
  31.            PAGE
  32.  
  33. NUL           EQU      00H
  34. LF           EQU      0AH
  35. CR           EQU      0DH
  36.  
  37. TRUE           EQU      0FFFFH
  38. FALSE           EQU      NOT TRUE
  39.  
  40.            .SALL               ; Supress MACRO listings
  41.  
  42. SUBTITLE       MACRO  STRING           ; Change the subtitle but
  43.                            ; don't display SUBTTL command
  44.            SUBTTL STRING
  45.            .LIST
  46.            PAGE
  47.            ENDM
  48.  
  49. PRINT           MACRO  STRING           ; Print a string
  50.            MOV      DX,OFFSET STRING
  51.            MOV      AH,9
  52.            INT      21H
  53.            ENDM
  54.  
  55.  
  56. CSEG           SEGMENT
  57.  
  58.            ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:NOTHING
  59.  
  60.            ORG      0
  61. XFER_ADDRESS       LABEL  BYTE
  62.  
  63.            ORG      80H
  64. DP_LENGTH       LABEL  BYTE
  65.  
  66.            ORG      81H
  67. DATAPATH       LABEL  BYTE
  68.  
  69.            ORG      100H
  70.  
  71. START:           JMP      INSTALL           ; Jump to installation
  72.            DW      64 DUP (?)
  73. STACK           LABEL  WORD
  74. WORK_AREA       DB      128 DUP (?)
  75. ID           DB      'DataPath 1.3'       ;                         1.3
  76.  
  77. ;------------------------------------------------------------------------------
  78.            .XLIST
  79.            SUBTITLE <BDOS redirection module>
  80.  
  81. BDOS           PROC   FAR
  82.  
  83. ; In a program designed to run under CP/M, a CALL to location 5h would call
  84. ; BDOS.  In MS-DOS, CP/M compatability is attempted by inserting a FAR CALL
  85. ; at location 5h.  From there the first instruction found is a far jump.  The
  86. ; function request was passed in register CL.
  87.  
  88. ; This routine rearranges the stack, and sets up for a proper INT 21h function
  89. ; request.
  90.  
  91. ; Note:  CL = 0 (TERMINATE) must be handled specially because the CS segment
  92. ;     is not compatable with a memory resident DataPath.
  93.  
  94.            CMP      CL,0               ; Terminate?
  95.            JNE      BDOS_2
  96.            JMP      CS:BDOS_ADDR
  97. BDOS_2:        POP      AX               ; Throw away 0Ah return addr
  98.            POP      AX               ; Now swap the top two words on
  99.            POP      CS:BDOS_TEMP           ;   the stack
  100.            PUSH   AX
  101.            PUSH   CS:BDOS_TEMP
  102.            MOV      AH,CL            ; Set the function
  103.            INT      21H               ;   and go do it
  104.            RET
  105.  
  106. BDOS_TEMP       DW      ?
  107. BDOS_ADDR       LABEL  DWORD
  108. BDOS_OFFSET       DW      ?
  109. BDOS_SEGMENT       DW      ?
  110.  
  111. BDOS           ENDP
  112.  
  113. ;------------------------------------------------------------------------------
  114.            .XLIST
  115.            SUBTITLE <Interrupt 24h (Abort) routine>
  116. ABORT           PROC   FAR
  117.  
  118. ;  This is the fatal error abort routine to check for open drive doors, etc.
  119. ;  It will be used only when we are searching for a file.  We will ignore
  120. ;  any error and return to the program with carry set.
  121.  
  122.            POP      AX               ; Discard the INT 24H return
  123.            POP      AX               ;   address and flags
  124.            POP      AX
  125.  
  126.            POP      AX               ; Restore user registers
  127.            POP      BX
  128.            POP      CX
  129.            POP      DX
  130.            POP      SI
  131.            POP      DI
  132.            POP      BP
  133.            POP      DS
  134.            POP      ES
  135.  
  136.            XCHG   BP,SP            ; Set the carry flag on the
  137.            OR      BYTE PTR 4[BP],1     ;   stack so it will be set
  138.            XCHG   BP,SP            ;   after the IRET
  139.            IRET
  140.  
  141. ABORT           ENDP
  142.  
  143. ;------------------------------------------------------------------------------
  144.            PAGE
  145.  
  146. ; The routines below set and restore the INT 24H fatal error handler.
  147. ; They use an INT 21H call that reenters DataPath.  The stack will grow a
  148. ; little, but the call is just passed to MS-DOS.
  149.  
  150. SET_ABORT:       PUSH   AX               ; Save registers
  151.            PUSH   BX
  152.            PUSH   ES
  153.            MOV      AX,3524H           ; Get INT 24H address
  154.            INT      21H
  155.            MOV      ABORT_OFFSET,BX      ;   and save it
  156.            MOV      ABORT_SEGMENT,ES
  157.            MOV      DX,OFFSET ABORT
  158.            MOV      AX,2524H           ; Set the interrupt address
  159.            INT      21H
  160.            POP      ES               ; Restore registers
  161.            POP      BX
  162.            POP      AX
  163.            RET
  164.  
  165. CLEAR_ABORT:       PUSH   AX               ; Save registers
  166.            PUSH   DX
  167.            PUSH   DS
  168.            LDS      DX,ABORT_ADDRESS     ; Reset address
  169.            MOV      AX,2524H           ; Set the interrupt address
  170.            INT      21H
  171.            POP      DS               ; Restore registers
  172.            POP      DX
  173.            POP      AX
  174.            RET
  175.  
  176. ABORT_ADDRESS       LABEL  DWORD
  177. ABORT_OFFSET       DW      ?
  178. ABORT_SEGMENT       DW      ?
  179.  
  180. ;------------------------------------------------------------------------------
  181.            .XLIST
  182.            SUBTITLE <Interrupt 21H intercept>
  183. ; When installed, DataPath intercepts all INT 21H call and works on three
  184. ; of them.
  185.  
  186. NEW_21:        PUSHF               ; Save flags
  187.            CMP      AH,0FH           ; Is the call 'OPEN' ?
  188.            JE      OPEN
  189.            CMP      AH,23H           ; Is the call 'FILE SIZE' ?
  190.            JE      OPEN
  191.            CMP      AH,0BDH           ; Is this 'our' function?
  192.            JE      OUR_FUNCTION
  193.            CMP      AH,3DH           ; Is it 'OPEN FILE HANDLE' ?
  194.            JNE      OLD
  195.            JMP      HANDLE
  196.  
  197. OLD:           POPF                ; Restore flags we called with
  198.            JMP      CS:OLD_21           ; Otherwise don't mess with the
  199.                            ;   interrupt
  200.  
  201. ; Check if caller is looking for DataPath
  202.  
  203. OUR_FUNCTION:       PUSH   ES               ; Save registers     1.2
  204.            PUSH   CX               ;            1.2
  205.            PUSH   SI               ;            1.2
  206.            PUSH   DI               ;            1.2
  207.  
  208.            PUSH   CS               ; Set destination to us
  209.            POP      ES               ;
  210.            MOV      DI,OFFSET ID           ; Point to our ID    1.2
  211.            MOV      CX,12            ;            1.2
  212.            REPE   CMPSB            ; See if ID is us    1.2
  213.  
  214.            POP      DI               ; Restore registers    1.2
  215.            POP      SI               ;            1.2
  216.            JCXZ   ID_OK            ; If zero, ID matches    1.2
  217.            POP      CX               ; Reset registers    1.2
  218.            POP      ES               ;            1.2
  219.            JMP      OLD               ; And continue to DOS    1.2
  220.  
  221. ID_OK:           POP      CX               ; Reset CX        1.2
  222.            ADD      SP,2               ; ES stays the same    1.2
  223.            NOT      BX               ; Invert BX to say we're here
  224.            POPF
  225.            IRET
  226.  
  227.  
  228. SAVE_SS        DW      ?               ; Stack Segment storage
  229. SAVE_SP        DW      ?               ; Stack Pointer storage
  230. OLD_21           LABEL  DWORD            ; Real INT 21H address
  231. OLD_21_OFFSET       DW      ?
  232. OLD_21_SEGMENT       DW      ?
  233. VERBOSE        DB      0FFH               ; TRUE
  234. WRITE_ENABLE       DB      0               ; FALSE
  235.            .XLIST
  236.            SUBTITLE <INT 21H Functions 'OPEN' and 'FILE SIZE'>
  237.  
  238. ; This procedure handles the old CP/M 'OPEN' routine.  If the call does not
  239. ; directly, a call to the routine 'FIND_FILE' checks any alternate paths.
  240. ; If the file is then found, the directory is changed to the found file's
  241. ; directory, the file is opened, and the directory is then changed back to
  242. ; the original directory.
  243.  
  244. FUNCTION       DB      ?               ; Calling function
  245. DRIVE_SPECIFIED    DB      ?
  246. CURRENT_DRIVE       DB      ?
  247. RESULT           DB      ?
  248. FCB_OFFSET       DW      ?
  249. FCB_SEGMENT       DW      ?
  250. FILENAME       DB      13 DUP (?)
  251.                            ; Flags are already pushed
  252. OPEN:           STI                   ; Reenable interrupts
  253.            MOV      CS:FUNCTION,AH       ; Save calling function
  254.            CALL   CS:OLD_21           ; Try to open the file
  255.            CMP      AL,0               ; Successful ?
  256.            JNE      OPEN_2           ; If not, try DataPath
  257.            IRET                ; Otherwise return
  258.  
  259. ; Search the DataPath
  260.  
  261. OPEN_2:        MOV      CS:SAVE_SS,SS        ; Save the stack
  262.            MOV      CS:SAVE_SP,SP
  263.            MOV      AX,CS            ; Set the stack
  264.            MOV      SS,AX
  265.            MOV      SP,OFFSET STACK
  266.            PUSH   BX               ; Save the registers
  267.            PUSH   CX
  268.            PUSH   DX
  269.            PUSH   SI
  270.            PUSH   DI
  271.            PUSH   DS
  272.            PUSH   ES
  273.            PAGE
  274.  
  275. ; Set up defaults and save FCB data.
  276.  
  277.            MOV      ES,AX            ; Set string destination seg
  278.            MOV      SI,DX
  279.            MOV      CS:ATTRIBUTES,0      ; Set default attributes
  280.            MOV      CS:FCB_OFFSET,DX     ; Save FCB address
  281.            MOV      CS:FCB_SEGMENT,DS
  282.  
  283.            CLD                   ; String increase
  284.            LODSB               ; Get 1st FCB char (bump SI)
  285.            CMP      AL,0FFH           ; Extended FCB ?
  286.            JNE      OPEN_4
  287.            MOV      AL,5[SI]           ; Get attributes
  288.            MOV      CS:ATTRIBUTES,AL     ;   and save
  289.            MOV      AL,6[SI]           ; Get drive specification
  290.            ADD      SI,7               ; Adjust to point to filename
  291.  
  292. ; Copy filename to a work area as an ASCII string.  Also check for wildcards.
  293. ; If a wildcard is found, don't search DataPath.
  294.  
  295. OPEN_4:        MOV      CS:DRIVE_SPECIFIED,AL; Save drive specification
  296.  
  297.            MOV      CX,8
  298.            MOV      DI,OFFSET FILENAME   ; Point to work area
  299.  
  300. OPEN_5:        LODSB               ; Transfer filename
  301.            CMP      AL,'?'
  302.            JE      OPEN_8A
  303.            CMP      AL,' '               ; Blanks terminate the string
  304.            JE      OPEN_6
  305.            STOSB
  306. OPEN_6:        LOOP   OPEN_5
  307.  
  308.            MOV      AL,'.'               ; Add a '.'
  309.            STOSB
  310.            MOV      CL,3
  311.  
  312. OPEN_7:        LODSB               ; Transfer extension to work
  313.            CMP      AL,'?'               ;    area
  314.            JE      OPEN_8A
  315.            CMP      AL,' '
  316.            JE      OPEN_8
  317.            STOSB
  318.            LOOP   OPEN_7
  319.  
  320. OPEN_8:        MOV      AL,NUL           ; Terminate ASCIIZ string
  321.            STOSB
  322.            PAGE
  323.  
  324.            PUSH   CS
  325.            POP      DS               ; DS points to us
  326.            MOV      RESULT,0FFH           ; Set default to not found
  327.            MOV      DX,OFFSET FILENAME   ; ES:DX points to filename
  328.            MOV      DI,DX
  329.            CALL   GET_LENGTH
  330.            CMP      CL,0
  331.            JE      OPEN_8A
  332.            CALL   FIND_PATH
  333.            JNC      OPEN_9           ; File not found
  334.  
  335. OPEN_8A:       JMP      OPEN_20
  336.  
  337. ; We found the file. We will now:
  338. ;  1.  Get the found drive.
  339. ;  2.  Get the current directory on the found drive.
  340. ;  3.  Set the found directory on the found drive.
  341. ;  4.  Set found drive in FCB.
  342. ;  5.  Open the file.
  343. ;  6.  Reset the current directory on the found drive.
  344. ;  7.  If the sspecified FCB drive was not zero, reset it.
  345.  
  346. OPEN_9:        MOV      AH,19H           ; Get current drive
  347.            INT      21H
  348.            INC      AL               ; Set 1=A, 2=B, etc
  349.            MOV      CURRENT_DRIVE,AL
  350.  
  351.            MOV      DI,OFFSET XFER_ADDRESS ; Get found drive
  352.            MOV      BX,DX
  353.            MOV      AL,1[BX]           ; Check if 2nd char is a ':'
  354.            CMP      AL,':'               ; If drive not specified,
  355.            JE      OPEN_10           ;   then get current drive
  356.  
  357.            MOV      AL,CURRENT_DRIVE
  358.            ADD      AL,'@'               ; Make ASCII
  359.            JMP      SHORT OPEN_11
  360.  
  361. OPEN_10:       MOV      AL,[BX]           ; Get found drive
  362. OPEN_11:       MOV      CL,AL            ; Save in CL and
  363.            STOSB               ;   memory
  364.            MOV      AX,'/:'              ; Add ':/' (stored backward)
  365.            STOSW
  366.  
  367.            MOV      SI,DI            ; Set up for 'Get Directory'
  368.            SUB      CL,'@'               ; Make drive numeric
  369.            MOV      DL,CL            ; Save in CL
  370.            MOV      AH,47H           ; Get current directory
  371.            INT      21H
  372.            JC      OPEN_20           ; Shouldn't happen
  373.            PAGE
  374.  
  375.            MOV      DI,END_PATH           ; Point to filename
  376.            DEC      DI               ; Point to end of path
  377.            MOV      AL,NUL           ; Make ASCIIZ string
  378.            STOSB
  379.  
  380.            MOV      DX,BX            ; Point to directory
  381.            MOV      AH,3BH
  382.            INT      21H               ; Set directory Path
  383.  
  384.            PUSH   DS
  385.            MOV      DX,FCB_OFFSET        ; Point to FCB
  386.            MOV      DS,FCB_SEGMENT
  387.            MOV      BX,DX
  388.            MOV      AL,[BX]           ; Get 1st char
  389.            CMP      AL,0FFH           ; Check for extended FCB
  390.            JNE      OPEN_14
  391.            ADD      BX,7               ; Point to drive specifier
  392. OPEN_14:       MOV      [BX],CL           ; Set drive specifier
  393.  
  394.            MOV      AH,CS:FUNCTION       ; Now open the file
  395.            PUSHF
  396.            CALL   CS:OLD_21
  397.            POP      DS
  398.            MOV      RESULT,AL           ; Save result
  399.  
  400.            MOV      DX,OFFSET XFER_ADDRESS
  401.            MOV      AH,3BH
  402.            INT      21H               ; Reset found directory
  403.  
  404.            MOV      AL,DRIVE_SPECIFIED   ; If drive was specified,
  405.            CMP      AL,0               ;   reset it
  406.            JNE      OPEN_16
  407.            MOV      AL,CURRENT_DRIVE     ; otherwise, use current drive
  408. OPEN_16:       MOV      BX,FCB_OFFSET        ; Point to FCB
  409.            MOV      DS,FCB_SEGMENT
  410.            MOV      AH,[BX]           ; Get 1st character
  411.            CMP      AH,0FFH           ; Check for extended FCB
  412.            JNE      OPEN_18
  413.            ADD      BX,7               ; Point to drive
  414. OPEN_18:       MOV      [BX],AL           ; Set drive
  415.            PAGE
  416.  
  417. OPEN_20:       POP      ES               ; Restore all registers
  418.            POP      DS
  419.            POP      DI
  420.            POP      SI
  421.            POP      DX
  422.            POP      CX
  423.            POP      BX
  424.  
  425. ; Note -- interrupts are automatically disabled for one instruction after
  426. ;      updating a segment register
  427.  
  428.            MOV      SS,CS:SAVE_SS
  429.            MOV      SP,CS:SAVE_SP
  430.            MOV      AH,CS:FUNCTION
  431.            MOV      AL,CS:RESULT           ; Return result of OPEN
  432.            IRET
  433.  
  434.            .XLIST
  435.            SUBTITLE <INT 21H Function to 'OPEN FILE HANDLE'>
  436.  
  437. ; This procedure handles the 'OPEN FILE HANDLE' routine.  If the call does
  438. ; not work directly, a call to the routine 'FIND_FILE' checks any alternate
  439. ; paths.  If the file is found, the file is then opened.
  440.  
  441. HANDLE:        CLI                   ; Enable hardware interrupts
  442.            MOV      CS:CALLER,AX           ; Save calling function
  443.            CALL   CS:OLD_21           ; Try the open as sent
  444.  
  445.            JC      HANDLE_0
  446.            JMP      HANDLE_4           ; Success
  447.  
  448. ; Try data paths
  449. HANDLE_0:       MOV      CS:SAVE_AX,AX        ; Save original error code
  450.            MOV      CS:SAVE_SS,SS        ; Save old SS:SP
  451.            MOV      CS:SAVE_SP,SP
  452.            MOV      AX,CS
  453.            MOV      SS,AX            ; SS <- CS
  454.            MOV      SP,OFFSET STACK      ; Set stack pointer
  455.            PUSH   BX               ; Save CPU state
  456.            PUSH   CX
  457.            PUSH   DX
  458.            PUSH   SI
  459.            PUSH   DI
  460.            PUSH   DS
  461.            PUSH   ES
  462.  
  463.            MOV      BX,DS
  464.            MOV      DS,AX            ; DS <- CS
  465.            MOV      ES,BX            ; ES <- OLD DS
  466.  
  467.            PAGE
  468.  
  469. ;  See if the caller:
  470. ;    1. Asked for a open to write, or
  471. ;    2. Has a path length not in the range of 1..80 bytes, or
  472. ;    3. Had any wildcards in the file name, or
  473. ;    4. Specified a directory or drive.
  474. ;  If any of the above are true, do not search extra paths.
  475.  
  476.  
  477.            CMP      WRITE_ENABLE,TRUE    ; See if read only
  478.            JE      HANDLE_1           ; Skip next if so
  479.  
  480.            MOV      AX,CALLER           ; Get calling function
  481.            CMP      AL,0               ; Open for read?
  482.            STC                   ; Set if error
  483.            JNE      HANDLE_3           ; If not, skip DataPath
  484.  
  485. HANDLE_1:       PUSH   BX
  486.            MOV      BX,DX
  487.            CMP      ES:BYTE PTR[BX+1],':'; if drive is specified,
  488.            JNE      HANDLE_2           ;    ignore it
  489.            ADD      DX,2
  490. HANDLE_2:       MOV      DI,DX            ; Set DI for SCASB instructions
  491.            POP      BX
  492.  
  493.            CALL   GET_LENGTH           ; Get length of filename
  494.            STC                   ; Set if error
  495.            CMP      CL,0               ; If zero, return
  496.            JE      HANDLE_3
  497.  
  498.            CALL   CHECK_WILD           ; Check for wildcard characters
  499.            JC      HANDLE_3           ; If present, return
  500.  
  501.            MOV      ATTRIBUTES,0111B     ; Match any attribute
  502.            CALL   FIND_PATH           ; Search for the file
  503.            JC      HANDLE_3
  504.  
  505.            MOV      AX,CALLER           ; No error, open the file
  506.            PUSHF
  507.            CALL   OLD_21
  508.            JC      HANDLE_3           ; Jump if we have an error
  509.            MOV      HANDLE_NUM,AX
  510.  
  511. HANDLE_3:       POP      ES               ; Restore all registers
  512.            POP      DS
  513.            POP      DI
  514.            POP      SI
  515.            POP      DX
  516.            POP      CX
  517.            POP      BX
  518.            MOV      AX,CS:SAVE_AX        ; This is original error code
  519.            MOV      SS,CS:SAVE_SS
  520.            MOV      SP,CS:SAVE_SP
  521.            JC      HANDLE_4
  522.            MOV      AX,CS:HANDLE_NUM     ; If no error, return the handle
  523.            PAGE
  524.  
  525. ; Insure the flags on the stack are set properly.
  526.  
  527. HANDLE_4:       XCHG   BP,SP            ; We want to index on SP
  528.            JC      HANDLE_6
  529.            AND      BYTE PTR 4[BP],0FEH  ; Clear carry on the stack
  530.            JMP      SHORT HANDLE_8       ;    or
  531. HANDLE_6:       OR      BYTE PTR 4[BP],1     ; Set carry on stack
  532. HANDLE_8:       XCHG   BP,SP            ; Reset registers
  533.            IRET                ; OK to return
  534.  
  535. CALLER           DW      ?
  536. HANDLE_NUM       DW      ?
  537. SAVE_AX        DW      ?
  538. ;------------------------------------------------------------------------------
  539.            .XLIST
  540.            SUBTITLE <Subroutines>
  541.  
  542. ;  Find the length of the path
  543.  
  544. GET_LENGTH:       CLD                   ; Strings increase
  545.            PUSH   DI               ; Save start location
  546.            MOV      AL,NUL
  547.            MOV      CX,80            ; Set max length of path
  548.            REPNE  SCASB            ; Find a NUL
  549.            SUB      CX,79            ; Get length of path
  550.            NEG      CX
  551.            MOV      CS:NAME_LENGTH,CX    ; Save the filename length
  552.            POP      DI
  553.            RET
  554. ;------------------------------------------------------------------------------
  555.  
  556. ;  Check for Drive, Directory, or wildcards ( ':', '\', '*', or '?' )
  557.  
  558. CHECK_WILD:       MOV      BX,OFFSET WILDCARDS  ; Point to exceptions
  559.            MOV      CX,4               ; There are 4 of them
  560.  
  561. C1:           PUSH   CX               ; Save the count
  562.            PUSH   DI               ; Save the start location
  563.            MOV      CX,NAME_LENGTH       ; Length to scan
  564.            MOV      AL,[BX]           ; Get a character
  565.            REPNE  SCASB            ; See if its there
  566.            CMP      CL,0               ; Set the flags
  567.            POP      DI               ; Reset start location
  568.            POP      CX               ; Reset count
  569.            JNE      C2               ; Found exception, no DataPath
  570.            INC      BX               ;  else, point to next char
  571.            LOOP   C1               ;    and check for it
  572.            CLC
  573.            RET                   ; Return OK
  574.  
  575. C2:           STC                   ; Error return
  576.            RET
  577.  
  578. NAME_LENGTH       DW      ?
  579. WILDCARDS       DB      ':\*?'
  580. ;------------------------------------------------------------------------------
  581.            PAGE
  582.  
  583. ; The subroutine FIND_PATH checks for the file in question along the
  584. ; supplementary DataPath.  The logic of the routine is as follows:
  585.  
  586. ;     1.  If the DataPath is exhausted, exit with carry set.
  587. ;     2.  Copy the next DataPath, delimited by a ';' to the working area.
  588. ;         a.  Insure it ends with a backslash.
  589. ;     3.  Execute DOS call to 'Find First Matching File'.
  590. ;         a.  If file is found, return with DS:DX pointing to the
  591. ;         path/filename for a subsequent Open call.
  592. ;         b.  Otherwise, goto step 1 above.
  593.  
  594. ;     Upon entry, ES:DX points to filename.
  595.  
  596. ATTRIBUTES       DB      ?
  597. END_PATH       DW      ?
  598. FILE_OFFSET       DW      ?
  599. FILE_SEGMENT       DW      ?
  600. LAST_PATH       DB      ?
  601.  
  602. FIND_PATH       PROC   NEAR
  603.            MOV      FILE_OFFSET,DX       ; Save file pointers
  604.            MOV      FILE_SEGMENT,ES
  605.  
  606.            CALL   SET_ABORT           ; Set our INT 24H handler
  607.            CALL   SET_DTA           ; Set Disk Transfer Address
  608.  
  609.            MOV      SI,OFFSET DATAPATH   ; Point to DataPath
  610.  
  611. ; Move the path to our work area
  612.  
  613.            MOV      AX,CS            ; Reset destination to us
  614.            MOV      ES,AX
  615.            MOV      LAST_PATH,FALSE      ; Not at last path yet
  616.  
  617. F1:           CMP      LAST_PATH,TRUE       ; Are we done?
  618.            JNE      F2               ; Continue if done
  619.            CALL   CLEAR_ABORT           ; All done, reset system
  620.            CALL   RESET_DTA
  621.            STC                   ; Set carry means not found
  622.            RET
  623.  
  624. F2:           MOV      CX,LENGTH WORK_AREA  ; Point to work area
  625.            MOV      DI,OFFSET WORK_AREA
  626.            MOV      AX,NUL           ; Start AX as two nuls
  627.  
  628.            PAGE
  629.  
  630. F3:           LODSB               ; Get a character
  631.            CMP      AL,';'               ; End of path?
  632.            JE      F6
  633.            CMP      AL,'$'               ; End of path and DataPath?
  634.            JE      F5
  635.            STOSB               ; Save the character in memory
  636.            MOV      AH,AL            ;   and here to check for '\'
  637.            LOOP   F3               ; Get next character
  638.  
  639. F5:           MOV      LAST_PATH,TRUE       ; Set last path flag
  640. F6:           CMP      AH,NUL           ; Check for zero length DataPath
  641.            JE      F7
  642.            MOV      AL,'\'               ; Is last character a backslash
  643.            CMP      AH,AL
  644.            JE      F7
  645.            STOSB               ; If not, make it a backslash
  646.  
  647. ; Add the filename to the path
  648.  
  649. F7:           MOV      END_PATH,DI           ; Save pointer to path end
  650.            PUSH   DS
  651.            PUSH   SI
  652.            MOV      SI,FILE_OFFSET
  653.            MOV      CX,NAME_LENGTH       ; Set the length
  654.            MOV      DS,FILE_SEGMENT      ; Point to original filename
  655.            REP      MOVSB            ; Transfer filename
  656.            MOVSB               ; Including the NUL
  657.            POP      SI
  658.            POP      DS
  659.  
  660. ; Find First Matching File
  661.  
  662.            MOV      DX,OFFSET WORK_AREA
  663.            MOV      AH,4EH           ; Find first
  664.            MOV      CH,0
  665.            MOV      CL,ATTRIBUTES        ; Match given attributes
  666.            INT      21H               ; Find the file
  667.            JC      F1               ; If not found, check next path
  668.  
  669.            CALL   CLEAR_ABORT           ; Successful return
  670.            CALL   RESET_DTA
  671.            CLC
  672.            RET
  673. FIND_PATH       ENDP
  674. ;------------------------------------------------------------------------------
  675.  
  676.            PAGE
  677.  
  678. ; Set Disk Transfer Address
  679.  
  680. SET_DTA:       MOV      AH,2FH           ; Save the old Disk Xfer Addr
  681.            INT      21H
  682.            MOV      DTA_OFFSET,BX
  683.            MOV      DTA_SEGMENT,ES
  684.            MOV      AH,1AH           ; Set our Disk Xfer Addr
  685.            MOV      DX,OFFSET XFER_ADDRESS
  686.            INT      21H
  687.            RET
  688.  
  689. ; Reset Disk Transfer Address
  690.  
  691. RESET_DTA:       PUSH   DS
  692.            PUSH   DX
  693.            LDS      DX,DTA           ; Point to old Disk Xfer Addr
  694.            MOV      AH,1AH
  695.            INT      21H               ; Reset it
  696.            POP      DX
  697.            POP      DS
  698.            RET
  699.  
  700. DTA           LABEL  DWORD
  701. DTA_OFFSET       DW      ?
  702. DTA_SEGMENT       DW      ?
  703. ;------------------------------------------------------------------------------
  704.            .XLIST
  705.            SUBTITLE <DataPath installation procedure>
  706.  
  707. ; Start of DataPath installation procedure
  708.  
  709. TRANSIENT       LABEL  WORD               ; Start of transient load
  710.  
  711. BAD_DOS_MSG       DB      'DataPath requires DOS 2.0 or above',CR,LF
  712.            DB      'DataPath NOT installed',CR,LF,'$'
  713. RESIDENT_FLAG       DB      0               ; False            1.2
  714. HELP           DB      0               ; False            1.2
  715.            PAGE
  716.  
  717. INSTALL:       MOV      AX,CS
  718.            MOV      DS,AX            ; INSURE DS IS SET
  719.  
  720. ; Check for DOS 2.0 or above
  721.  
  722.            MOV      AH,30H           ; Get DOS version
  723.            INT      21H
  724.            CMP      AL,2               ; Is it 2.0 or more?
  725.            JGE      INSTALL_1           ; Continue if OK
  726.  
  727.            PRINT  BAD_DOS_MSG
  728.            INT      20H               ; TERMINATE
  729.  
  730. INSTALL_1:       MOV      AX,3521H           ; GET OLD INT 21 ADDR
  731.            INT      21H
  732.            MOV      OLD_21_OFFSET,BX     ; SAVE IT
  733.            MOV      OLD_21_SEGMENT,ES
  734.  
  735. ; Check if DataPath is already installed by calling a special (our own)
  736. ; function of INT 21H.
  737.  
  738.            MOV      AH,0BDH           ; Our interrupt
  739.            MOV      SI,OFFSET ID           ; Point to name         1.2
  740.            XOR      BX,BX            ; Insure BX is zero
  741.            INT      21H               ; See if DataPath is there
  742.            INC      BX               ; If so, BX will now be zero
  743.            JNZ      INSTALL_3
  744.  
  745. ; DataPath is already there
  746.  
  747.            MOV      RESIDENT_FLAG,TRUE
  748.            JMP      SHORT INSTALL_4
  749.  
  750. ; Set new interrupt 21 address
  751.  
  752. INSTALL_3:       MOV      DX,OFFSET NEW_21     ; POINT TO OFFSET
  753.            MOV      AX,2521H           ; UPDATE THE INTERRUPT
  754.            INT      21H
  755.            PAGE
  756. ; Set the CP/M BDOS Entry Point for compatability
  757.  
  758.            MOV      BX,6
  759.            LES      BX,[BX]           ; GET ADDRESS OF CALL TO CP/M
  760.            MOV      AX,ES:1[BX]           ;   AND SAVE IT
  761.            MOV      BDOS_OFFSET,AX
  762.            MOV      AX,ES:3[BX]
  763.            MOV      BDOS_SEGMENT,AX
  764.  
  765.            MOV      DX,OFFSET BDOS
  766.            MOV      ES:1[BX],DX           ; SET OUR ADDRESS INTO MS-DOS
  767.            MOV      ES:3[BX],DS
  768.  
  769. ; If DataPath program is not resident OR a new DataPath is passed, then
  770. ;   transfer the new Datapath
  771.  
  772. INSTALL_4:       CALL   CHECK_SWITCHES
  773.            CMP      RESIDENT_FLAG,FALSE
  774.            JE      INSTALL_5
  775.            CMP      DP_LENGTH,0
  776.            JE      INSTALL_6
  777. INSTALL_5:       CALL   SET_DATAPATH
  778.  
  779. ; If a new DataPath is not passed, or we are in VERBOSE mode, display the
  780. ;   current DataPath
  781.  
  782.            CMP      HELP,TRUE           ; Always display if help    1.2
  783.            JE      INSTALL_6           ;   is set           1.2
  784.            CMP      ES:VERBOSE,TRUE
  785.            JE      INSTALL_6
  786.            CMP      DP_LENGTH,0
  787.            JNE      INSTALL_8
  788. INSTALL_6:       CALL   DISPLAY
  789.  
  790. ; Just terminate if we are already resident
  791.  
  792. INSTALL_8:       CMP      CS:RESIDENT_FLAG,TRUE
  793.            JNE      INSTALL_9
  794.            MOV      AX,4C00H           ; OK RETURN
  795.            INT      21H               ; TERMINATE
  796.  
  797. ; Exit but stay resident - set paragraphs to save
  798.  
  799. PARAS           =      ((TRANSIENT-XFER_ADDRESS) SHR 4) + 1 ;     1.2
  800.  
  801. INSTALL_9:       MOV      DX,PARAS           ; SET LENGTH TO RESERVE     1.2
  802.            MOV      AX,3100H
  803.            INT      21H               ; TERMINATE & STAY RESIDENT
  804.  
  805.            PAGE
  806.  
  807. ; Transfer the DataPath but do some pre-processing
  808.  
  809. SET_DATAPATH:       CMP      RESIDENT_FLAG,TRUE   ; IF RESIDENT THEN ES WAS SET
  810.            JE      SET_2            ;   BY INT 21H FUNCTION 'BD'h
  811.            PUSH   CS               ; ELSE SET TO CS
  812.            POP      ES
  813.            CMP      HELP,TRUE           ; IF HELP AND NOT RESIDENT, 1.2
  814.            JE      SET_9            ;   SET NULL DATAPATH       1.2
  815.  
  816. SET_2:           CLD                   ; INCREMENT STRINGS
  817.            CMP      HELP,TRUE           ; IF HELP SET, DON'T RESET  1.2
  818.            JE      SET_10           ;   DATAPATH           1.2
  819.            MOV      SI,OFFSET DATAPATH   ; POINT TO SOURCE CS:81
  820.            MOV      DI,SI            ; POINT TO DEST     ES:81
  821.            MOV      CL,DP_LENGTH           ; GET LENGTH OF PASSED STRING
  822.            CMP      CL,0               ; IF LENGTH IS 0, STORE NUL
  823.            JE      SET_9            ;   STRING
  824.            MOV      CH,0
  825.  
  826. SET_4:           LODSB               ; GET A CHARACTER
  827.            CMP      AL,' '               ; THROW AWAY NON PRINTING
  828.            JBE      SET_8            ;    CHARACTERS
  829.            CMP      AL,'z'               ; AND OTHER WEIRD CHARS
  830.            JA      SET_8
  831.            CALL   CHECK_ILLEGAL        ; CHECK FOR ILLEGAL PATHNAME 1.3
  832.            JC      SET_8            ;                1.3
  833.            CMP      AL,'a'               ; CONVERT CHARS TO UPPER CASE
  834.            JB      SET_7
  835.            AND      AL,0DFH
  836. SET_7:           STOSB               ; SAVE THE CHARACTER
  837. SET_8:           LOOP   SET_4
  838. SET_9:           MOV      AL,'$'               ; STORE A TERMINATING $
  839.            STOSB
  840. SET_10:        RET
  841.  
  842. CHECK_ILLEGAL       PROC   NEAR               ;              1.3
  843.            PUSH   CX               ; SAVE REGISTERS       1.3
  844.            PUSH   DI               ;              1.3
  845.            PUSH   ES               ;              1.3
  846.            PUSH   CS               ; SET ES=CS          1.3
  847.            POP      ES               ;              1.3
  848.            MOV      CX,10            ; CHECK 10 CHARACTERS      1.3
  849.            MOV      DI,OFFSET ILLEGAL_CHARS ;              1.3
  850.            REPNE SCASB               ; SEE IF WE HAVE ILLEGAL   1.3
  851.            CLC                   ; ASSUME CHAR OK       1.3
  852.            JNE      CHECK_ILLEGAL_1      ; JUMP IF NO MATCHES      1.3
  853.            STC                   ; CHAR IS ILLEGAL      1.3
  854. CHECK_ILLEGAL_1:   POP      ES               ; RESTORE REGISTERS      1.3
  855.            POP      DI               ;              1.3
  856.            POP      CX               ;              1.3
  857.            RET                   ;              1.3
  858. CHECK_ILLEGAL       ENDP                ;              1.3
  859.  
  860. ILLEGAL_CHARS       DB      '$"[]*?+=<>'         ;                          1.3
  861.  
  862.            .XLIST
  863.            SUBTITLE <Display Subroutine>
  864.  
  865. ; This procedure outputs DataPath info to the screen
  866.  
  867. DISPLAY        PROC   NEAR
  868.  
  869.            PRINT  INFO               ; Print heading
  870.            CMP      RESIDENT_FLAG,TRUE   ; If first time say installed
  871.            JE      DISPLAY_1
  872.            PRINT  INSTALLED
  873.  
  874. DISPLAY_1:       PRINT  CRLF
  875.            PRINT  NC               ; Print our name
  876.            PRINT  CRLF2            ; Skip a line
  877.            PRINT  VERBOSE_MSG           ; Print verbose status
  878.            CMP      ES:VERBOSE,TRUE
  879.            JE      DISPLAY_2
  880.            PRINT  OFF
  881.            JMP      SHORT DISPLAY_3
  882. DISPLAY_2:       PRINT  ON
  883.  
  884. DISPLAY_3:       PRINT  WRITE_ACCESS           ; Print open for write status
  885.            CMP      ES:WRITE_ENABLE,TRUE
  886.            JE      DISPLAY_4
  887.            PRINT  OFF
  888.            JMP      SHORT DISPLAY_5
  889. DISPLAY_4:       PRINT  ON
  890.  
  891. DISPLAY_5:       PRINT  CRLF               ; Skip a line
  892.  
  893.            PRINT  DATAPATH_MSG           ; Tell the current DataPath
  894.  
  895.            PUSH   DS
  896.            PUSH   ES
  897.            POP      DS               ; POINT TO DATAPATH
  898.            PRINT  DATAPATH
  899.            POP      DS
  900.  
  901.            PRINT  CRLF2
  902.            CMP      HELP,TRUE           ;              1.2
  903.            JNE      DISPLAY_6           ;              1.2
  904.            PRINT  USAGE            ;              1.2
  905.  
  906. DISPLAY_6:       RET
  907.  
  908. DISPLAY        ENDP
  909.            PAGE
  910.  
  911. INFO           DB      'DataPath version 1.3  $'                      ; 1.3
  912. INSTALLED       DB      'Installed$'
  913. NC           DB      '(nc) 1987 by GDC Software$'
  914. VERBOSE_MSG       DB      'Verbose mode is $'
  915. WRITE_ACCESS       DB      'Write access is $'
  916. ON           DB      'on',CR,LF,'$'                                 ; 1.2
  917. OFF           DB      'off',CR,LF,'$'                                ; 1.2
  918. DATAPATH_MSG       DB      'Current DataPath=$'
  919. CRLF2           DB      CR,LF
  920. CRLF           DB      CR,LF,'$'
  921. USAGE           DB      'DataPath usage:',CR,LF
  922.            DB      '  DataPath path1 [;path2...] [/V] [/Q] [/R] [/W]'
  923.            DB      ' [/H]',CR,LF
  924.            DB      '    where path1, path2... are the paths to '
  925.            DB      'search for files',CR,LF
  926.            DB      '          /V sets verbose mode [default]',CR,LF
  927.            DB      '          /Q sets quiet mode',CR,LF
  928.            DB      '          /R sets read only mode [default]',CR,LF
  929.            DB      '          /W allows opens for writing',CR,LF
  930.            DB      '          /H writes this message',CR,LF,'$'
  931.  
  932.            .XLIST
  933.            SUBTITLE <Check Switches Subroutine>
  934. ; This procedure checks for a /W, /R, /V, and /Q and sets the VERBOSE and
  935. ; WRITE_ENABLE flags accordingly.
  936.  
  937. CHECK_SWITCHES       PROC   NEAR
  938.  
  939.            CMP      RESIDENT_FLAG,TRUE   ; If resident ES is set to
  940.            JE      SWITCH_1           ; resident portion of DataPath
  941.            PUSH   CS               ; otherwise use CS
  942.            POP      ES
  943.  
  944. SWITCH_1:       CLD                   ; Scan for a '/'
  945.            MOV      AL,'/'
  946.            XOR      CX,CX
  947.            MOV      CL,DP_LENGTH
  948.            MOV      DI,OFFSET DATAPATH
  949.            PUSH   ES
  950.            PUSH   DS               ; Set ES to point to us
  951.            POP      ES
  952.            REPNZ  SCASB
  953.            POP      ES               ; Restore ES
  954.            JCXZ   SWITCH_9           ; All done -- return
  955.  
  956.            MOV      AL,[DI]           ; Get the character after the /
  957.            AND      AL,0DFH           ; Make upper case
  958.            MOV      WORD PTR[DI-1],'  '  ; Blank out /x
  959.  
  960.            CMP      AL,'V'               ; /V --> set VERBOSE
  961.            JNE      SWITCH_2
  962.            MOV      ES:VERBOSE,TRUE
  963.            JMP      SHORT SWITCH_1
  964.  
  965. SWITCH_2:       CMP      AL,'Q'               ; /Q --> clear VERBOSE
  966.            JNE      SWITCH_3
  967.            MOV      ES:VERBOSE,FALSE
  968.            JMP      SHORT SWITCH_1
  969.  
  970. SWITCH_3:       CMP      AL,'R'               ; /R --> Only work on files
  971.            JNE      SWITCH_4           ;    opened to read
  972.            MOV      ES:WRITE_ENABLE,FALSE
  973.            JMP      SHORT SWITCH_1
  974.  
  975. SWITCH_4:       CMP      AL,'W'               ; /W --> Work on files for
  976.            JNE      SWITCH_5           ;    read or write
  977.            MOV      ES:WRITE_ENABLE,TRUE
  978.            JMP      SHORT SWITCH_1
  979.  
  980. SWITCH_5:       CMP      AL,'H'               ; /H --> Type usage message 1.2
  981.            JNE      SWITCH_1
  982.            MOV      HELP,TRUE
  983.            JMP      SHORT SWITCH_1
  984.  
  985. SWITCH_9:       RET
  986.  
  987. CHECK_SWITCHES       ENDP
  988.  
  989. CSEG           ENDS
  990.            END      START
  991.