home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / m / mastlkt.zip / DATAPATH.ASM < prev    next >
Assembly Source File  |  1987-02-24  |  32KB  |  1,044 lines

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