home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol8n01.zip / BCOPY.ASM next >
Assembly Source File  |  1989-01-17  |  50KB  |  1,226 lines

  1.  
  2. ;=============================================================================
  3. ; BCOPY 1.0 Background copy utility
  4. ;=============================================================================
  5. CODE            SEGMENT PARA PUBLIC 'CODE'
  6.         ASSUME  CS:CODE
  7.  
  8.         ORG     80H
  9. COMMAND_TAIL    DB      ?
  10.         ORG     100H
  11. BEGIN:          JMP     INITIALIZE
  12.  
  13. PROGRAM         DB      "BCOPY 1.0 (c) 1989 Ziff Communications Co.",13,10
  14.         DB      "PC Magazine ",254," Douglas Boling",13,10
  15.                DB    "Usage: BCOPY [source [target]][/X][/U]$",26
  16.  
  17. ;-----------------------------------------------------------------------------
  18. ; Memory locations required for system overhead.
  19. ;-----------------------------------------------------------------------------
  20. INDOS           DD      0                       ;pointer to INDOS flag
  21. CEF_PTR         DD      0                       ;pointer to Critical err flag
  22. DOS_VERSION     DW      0                       ;DOS version number
  23.  
  24. COUNTER         DB      16                      ;request flag/timer
  25. DISKFLAG        DB      0                       ;disk access flag
  26. ACTIVE          DB      0                       ;background status flag
  27. REMOVE_FLAG     DB      0                       ;1 = uninstall when q empty
  28. RET_ADDR        DW      0                       ;saved return addr for calls
  29.  
  30. SOURCE_HNDL     DW      0                       ;Source file handle
  31. DEST_HNDL       DW      0                       ;Destination handle
  32.  
  33. EMS_FLAG        DB      0                       ;Use expanded memory
  34. EMS_HANDLE      DW      0                       ;EMS handle used
  35.  
  36. DATA_SEGMENT    DW      0                       ;segment of data buffer
  37. QUEUE_HEAD_PTR  DW      0                       ;pointer to first file in q
  38. FILE_COUNT      DB      0                       ;Number of files in queue
  39. DATA_BUFF_START DW      OFFSET DATA_BUFFER      ;pointer to start of buffer
  40. DATA_BUFF_END   DW      OFFSET END_OF_DATA      ;pointer to end of data buffer
  41.  
  42. INT8H           DD      0                       ;int 8h vector  (Timer)
  43. INT13H          DD      0                       ;int 13h vector (Disk)
  44. INT28H          DD      0                       ;int 28h vector (Idle)
  45.  
  46. SAVED_DTA       DD      0                       ;saved pointer to curr DTA
  47. SAVED_PSP       DW      0                       ;saved segment of curr PSP
  48. SS_REGISTER     DW      0                       ;SS register
  49. SP_REGISTER     DW      0                       ;SP register
  50.  
  51. ERRINFOARRAY    DW      6 DUP (0)               ;Saved extended error info
  52. ERRINFODS       DW      0
  53. ERRINFOES       DW      0
  54.         DW      3 DUP (0)               ;Reserved error table bytes
  55.  
  56. VECTOR1BH       DD      0                       ;int 1Bh vector (Break)
  57. VECTOR23H       DD      0                       ;int 23h vector (Ctrl-C)
  58. VECTOR24H       DD      0                       ;int 24h vector (Crit err)
  59.  
  60. ;=============================================================================
  61. ; TIMERINT receives control when an interrupt 8 is generated.
  62. ;=============================================================================
  63. TIMERINT        PROC    FAR
  64.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  65.         PUSHF                           ;call BIOS routine
  66.         CALL    INT8H
  67.         CLI                             ;make sure interrupts are off
  68.         CMP     CS:COUNTER,0            ;exit if timer not expired
  69.         JG      DECTIME
  70.         CMP     CS:ACTIVE,0             ;See if already active.
  71.         JNE     TIMER_EXIT
  72.         CMP     CS:DISKFLAG,0           ;check disk access status
  73.         JNE     TIMER_EXIT              ;exit if disk active.
  74.         PUSH    ES
  75.         PUSH    DI
  76.         LES     DI,INDOS                ;retrieve INDOS address
  77.         CMP     BYTE PTR ES:[DI],0      ;is the INDOS flag clear?
  78.         POP     DI
  79.         POP     ES
  80.         JNE     TIMER_EXIT
  81.         CMP     CS:FILE_COUNT,0         ;See if any files in queue
  82.         JNE     TIMER_CONTINUE
  83.         CMP     CS:REMOVE_FLAG,0        ;See if routine should be
  84.         JE      TIMER_EXIT              ;  removed from memory
  85.         CALL    REMOVE
  86.         JNC     TIMER_EXIT              ;If no error, exit. If error,
  87.         JMP     SHORT TIMER_SKIP_MAIN   ;  wait then try again.
  88. TIMER_CONTINUE:
  89.         CALL    MAIN                    ;yes, invoke background routine
  90. TIMER_SKIP_MAIN:
  91.         MOV     CS:COUNTER,17           ;Set sleep counter = 1 sec
  92. DECTIME:
  93.         DEC     CS:COUNTER              ;decrement wait counter
  94. TIMER_EXIT:
  95.         IRET
  96. TIMERINT        ENDP
  97.  
  98. ;=============================================================================
  99. ; IDLE receives control when an interrupt 28h is generated.
  100. ;=============================================================================
  101. IDLE            PROC    FAR
  102.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  103.         PUSHF                           ;call DOS routine
  104.         CALL    INT28H
  105.         CLI                             ;make sure interrupts are off
  106.         CMP     CS:FILE_COUNT,0         ;See if files in queue
  107.         JE      IDLE_EXIT               ;If not, exit.
  108.         CMP     CS:COUNTER,8            ;wait at least 1/2 sec between
  109.         JA      IDLE_EXIT               ;  calls.
  110.         CMP     CS:ACTIVE,0             ;See if already active.
  111.         JNE     IDLE_EXIT
  112.         CMP     CS:DISKFLAG,0           ;check disk access status
  113.         JNE     IDLE_EXIT               ;exit if flag is raised
  114.         PUSH    ES
  115.         PUSH    DI
  116.         LES     DI,CS:CEF_PTR           ;retrieve crit err flag adr
  117.         CMP     BYTE PTR ES:[DI],0      ;is DOS in crit error state?
  118.         POP     DI
  119.         POP     ES
  120.         JNE     IDLE_EXIT               ;yes, don't do anything
  121.         CALL    MAIN                    ;Call background routine.
  122.         MOV     CS:COUNTER,16           ;Set sleep counter
  123. IDLE_EXIT:
  124.         IRET
  125. IDLE            ENDP
  126.  
  127. ;=============================================================================
  128. ; DISKINT receives control when an interrupt 13h is generated.
  129. ;=============================================================================
  130. DISKINT         PROC    FAR
  131.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  132.         PUSHF                           ;save flags register
  133.         INC     CS:DISKFLAG             ;set disk access flag
  134.         POPF                            ;restore flags
  135.         PUSHF                           ;call BIOS routine
  136.         CALL    INT13H
  137.         PUSHF                           ;save flags again
  138.         DEC     CS:DISKFLAG             ;reset disk access flag
  139.         POPF                            ;restore flags
  140.         RET     2                       ;exit with flags intact
  141. DISKINT         ENDP
  142.  
  143. ;=============================================================================
  144. ; CRITICALERR receives control when an interrupt 24h is generated.
  145. ;=============================================================================
  146. CRITICALERR     PROC    FAR
  147.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  148.         XOR     AL,AL                   ;Default to ignore
  149.         CMP     CS:DOS_VERSION,30AH     ;See if before DOS 3.1
  150.         JL      CRITICAL1
  151.         ADD     AL,3
  152. CRITICAL1:
  153.         IRET
  154. CRITICALERR     ENDP
  155.  
  156. ;=============================================================================
  157. ; MAIN
  158. ;=============================================================================
  159. MAIN            PROC    NEAR
  160.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  161.         INC     CS:[ACTIVE]             ;set program status flag
  162.         CLI                             ;make sure interrupts are off
  163.         MOV     CS:SS_REGISTER,SS       ;save SS and SP registers
  164.         MOV     CS:SP_REGISTER,SP
  165.         PUSH    CS                      ;switch to internal stack
  166.         POP     SS
  167.         MOV     SP,OFFSET STACK_SPACE
  168.         STI                             ;enable interrupts
  169.         CALL    SAVE_REGS               ;save all registers
  170.         ASSUME  DS:CODE
  171. ;-----------------------------------------------------------------------------
  172. ;Point the interrupt 1Bh, 23h, and 24h vectors to internal handlers.
  173. ;-----------------------------------------------------------------------------
  174.         MOV     AX,351BH                ;get and save 1Bh vector
  175.         INT     21H
  176.         MOV     WORD PTR VECTOR1BH,BX
  177.         MOV     WORD PTR VECTOR1BH[2],ES
  178.         MOV     AX,251BH                ;point interrupt to IRET
  179.         MOV     DX,OFFSET IDLE_EXIT
  180.         INT     21H
  181.  
  182.         MOV     AX,3523H                ;get and save 23h vector
  183.         INT     21H
  184.         MOV     WORD PTR VECTOR23H,BX
  185.         MOV     WORD PTR VECTOR23H[2],ES
  186.         MOV     AX,2523H                ;point interrupt to IRET
  187.         MOV     DX,OFFSET IDLE_EXIT
  188.         INT     21H
  189.  
  190.         MOV     AX,3524H                ;get and save 24h vector
  191.         INT     21H
  192.         MOV     WORD PTR VECTOR24H,BX
  193.         MOV     WORD PTR VECTOR24H[2],ES
  194.         MOV     AX,2524H                ;point interrupt to internal
  195.         PUSH    CS
  196.         POP     DS
  197.         MOV     DX,OFFSET CRITICALERR   ;  critical error handler
  198.         INT     21H
  199. ;-----------------------------------------------------------------------------
  200. ;Save and switch to internal PSP
  201. ;-----------------------------------------------------------------------------
  202.         MOV     AH,51H                  ;Get current PSP
  203.         CALL    DOSPSPCALL              ;Beware DOS 2.0 - 3.0
  204.         MOV     SAVED_PSP,BX            ;save it
  205.         PUSH    CS
  206.         POP     BX
  207.         MOV     AH,50H                  ;Set internal PSP
  208.         CALL    DOSPSPCALL
  209. ;-----------------------------------------------------------------------------
  210. ;Save and switch to internal DTA
  211. ;-----------------------------------------------------------------------------
  212.         MOV     AH,2FH
  213.         INT     21H                     ;Get current DTA
  214.         MOV     WORD PTR SAVED_DTA,BX   ;save it
  215.         MOV     WORD PTR SAVED_DTA[2],ES
  216.         MOV     DX,OFFSET COMMAND_TAIL  ;use PSP for DTA
  217.         MOV     AH,1AH                  ;Set DTA
  218.         INT     21H
  219. ;-----------------------------------------------------------------------------
  220. ;If DOS >= 3.x, save extended error information.
  221. ;-----------------------------------------------------------------------------
  222.         CMP     WORD PTR DOS_VERSION,030AH
  223.         JB      SKIP_ERR_SAVE
  224.         PUSH    DS                      ;save DS
  225.         XOR     BX,BX                   ;clear BX for call
  226.         MOV     AH,59H                  ;Extended error info
  227.         INT     21H                     ;Call DOS
  228.         MOV     CS:ERRINFODS,DS         ;save returned ES
  229.         POP     DS                      ;Restore DS
  230.         PUSH    BX
  231.         MOV     BX,OFFSET ERRINFOARRAY  ;Save data in registers
  232.         MOV     [BX],AX                 ;  in this specific order.
  233.         POP     2[BX]
  234.         MOV     4[BX],CX
  235.         MOV     6[BX],DX
  236.         MOV     8[BX],SI
  237.         MOV     0AH[BX],DI
  238.         MOV     0EH[BX],ES
  239. SKIP_ERR_SAVE:
  240. ;-----------------------------------------------------------------------------
  241. ;If using EMS memory, save EMS mapping context and map our page.
  242. ;-----------------------------------------------------------------------------
  243.         CMP     EMS_FLAG,0
  244.         JE      EMS_SAVE_SKIP
  245.         MOV     AH,47H                  ;Save mapping context
  246.         MOV     DX,EMS_HANDLE
  247.         INT     67H
  248.         OR      AH,AH
  249.         JNE     JMP_CLEAN_UP
  250.         MOV     AX,4400H                ;Map page
  251.         XOR     BX,BX
  252.         MOV     DX,EMS_HANDLE
  253.         INT     67H
  254.         OR      AH,AH
  255.         JNE     JMP_CLEAN_UP
  256. EMS_SAVE_SKIP:
  257.         MOV     ES,DATA_SEGMENT
  258.         MOV     DS,DATA_SEGMENT
  259.         ASSUME  DS:NOTHING
  260. ;-----------------------------------------------------------------------------
  261. ;Check flags in queue to determine if starting a copy or in the middle of one.
  262. ;-----------------------------------------------------------------------------
  263.         MOV     SI,CS:QUEUE_HEAD_PTR    ;Get pointer to filename
  264.         MOV     AX,[SI+2]               ;Get source file flags
  265.         OR      AH,AH                   ;See if source file open
  266.         JNE     OPEN_DEST               ;Yes, check destination file
  267. ;-----------------------------------------------------------------------------
  268. ;Search for source file.
  269. ;-----------------------------------------------------------------------------
  270. FIND_SOURCE:
  271.         ADD     SI,6                    ;move pointer to filename
  272.         MOV     DX,SI                   ;Copy queue pointer
  273.         XOR     CX,CX                   ;Search for normal files.
  274.         MOV     AH,4EH                  ;assume find first
  275.         OR      AL,AL                   ;See if first search.
  276.         JE      FIND1ST                 ;Yes, find first.
  277.         INC     AH                      ;No, change cmd to find next.
  278. FIND1ST:
  279.         INT     21H                     ;Call DOS
  280.         JNC     OPEN_FILE
  281.         JMP     PURGE_FROM_QUEUE        ;If file not found, purge
  282. ;-----------------------------------------------------------------------------
  283. ;Attempt to open source file.
  284. ;-----------------------------------------------------------------------------
  285. OPEN_FILE:
  286.         XOR     DL,DL                   ;indicate source file
  287.         CALL    GETPATHFILE             ;combine path and filename
  288.         MOV     DX,CS:DATA_BUFF_START   ;point to filename
  289.         MOV     AX,3D00H                ;open, read only access
  290.         INT     21H
  291.         JNC     GOOD_OPEN
  292. ;error in file open.
  293.         CMP     AX,4                    ;See if too many open files.
  294.         JNE     OPEN1
  295. JMP_CLEAN_UP:
  296.         JMP     CLEAN_UP                ;If so, try again later
  297. OPEN1:
  298.         JMP     PURGE_FROM_QUEUE        ;Else, bad filename.
  299. GOOD_OPEN:
  300.         MOV     SOURCE_HNDL,AX          ;Save handle for source file
  301.         MOV     SI,CS:QUEUE_HEAD_PTR    ;Get queue ptr, indicate that
  302.         MOV     WORD PTR [SI+2],0101H   ;  1st file opened.
  303. ;-----------------------------------------------------------------------------
  304. ;Create destination file.
  305. ;  Note: open dest assumes SI points to the first entry in the queue.
  306. ;-----------------------------------------------------------------------------
  307. OPEN_DEST:
  308.         MOV     AX,[SI+4]               ;Get destination file flags
  309.         OR      AL,AL                   ;See if destination file open
  310.         JNE     READ_FILE               ;Dest file open, copy data.
  311.         CALL    GET_DEST_NAME           ;Gen filename from queue
  312.         MOV     AH,3CH                  ;create destination file
  313.         XOR     CX,CX                   ;normal attributes
  314.         INT     21H
  315.         JNC     GOOD_CREATE_DEST
  316. OPEN_DEST_ERR:
  317.         CMP     AX,4                    ;See if too many files
  318.         JE      JMP_CLEAN_UP            ;If so, wait till later
  319.         JMP     SHORT PURGE_FROM_QUEUE  ;If other error, purge file
  320. GOOD_CREATE_DEST:
  321.         MOV     CS:DEST_HNDL,AX         ;Save destination handle
  322.         MOV     SI,CS:QUEUE_HEAD_PTR    ;Get pointer to filename
  323.         MOV     BYTE PTR [SI+4],1       ;Set destination file open
  324. ;-----------------------------------------------------------------------------
  325. ;Files are open, read from destination file into data buffer.
  326. ;-----------------------------------------------------------------------------
  327. READ_FILE:
  328.         MOV     CX,CS:DATA_BUFF_END     ;Find end of buffer
  329.         SUB     CX,CS:DATA_BUFF_START   ;Get size of buffer
  330.         SUB     CX,4
  331.         MOV     BX,CS:SOURCE_HNDL       ;Get handle
  332.         MOV     DX,CS:DATA_BUFF_START   ;Point to data buffer
  333.         MOV     AH,3FH                  ;Read file
  334.         INT     21H                     ;Call DOS
  335.         JNC     WRITE_FILE              ;If no error, continue
  336.         MOV     DI,1                    ;If error, close files,
  337.         JMP     SHORT CLOSE_FILES       ;  erase dest, and purge.
  338. ;-----------------------------------------------------------------------------
  339. ;Write data to file.
  340. ;-----------------------------------------------------------------------------
  341. WRITE_FILE:
  342.         MOV     SI,CX                   ;Save num of bytes requested
  343.         MOV     CX,AX                   ;Write number of bytes read.
  344.         MOV     AH,40H                  ;Write file
  345.         MOV     BX,CS:DEST_HNDL         ;To destination
  346.         INT     21H                     ;Call DOS
  347.         JC      WRITE_BAD
  348.         XOR     DI,DI                   ;Use DI as disk full flag
  349.         CMP     AX,CX                   ;Make sure all bytes written
  350.         JE      CHECK_FOR_EOF           ;If not, disk full.
  351. WRITE_BAD:
  352.         INC     DI                      ;set flag to delete file
  353.         JMP     SHORT CLOSE_FILES
  354. ;-----------------------------------------------------------------------------
  355. ;If copy complete, close files
  356. ;-----------------------------------------------------------------------------
  357. CHECK_FOR_EOF:
  358.         CMP     SI,AX                   ;see if at end of file.
  359.         JE      CLEAN_UP                ;No, skip close
  360. CLOSE_FILES:
  361.         MOV     SI,CS:QUEUE_HEAD_PTR    ;Get queue ptr, indicate that
  362.         MOV     WORD PTR [SI+3],0       ;Indicate files closed.
  363.         MOV     BX,CS:SOURCE_HNDL
  364.         MOV     AH,3EH                  ;Close source file
  365.         INT     21H
  366.         MOV     BX,CS:DEST_HNDL
  367.         MOV     AH,3EH                  ;Close destination file
  368.         INT     21H
  369.         OR      DI,DI                   ;See if error during write.
  370.         JE      SHORT CLEAN_UP          ;  If so, delete and purge.
  371.         CALL    GET_DEST_NAME           ;Gen dest file name again
  372.         MOV     AH,41H                  ;Delete partial dest file
  373.         INT     21H                     ;  (DX still points to name.)
  374. ;-----------------------------------------------------------------------------
  375. ;Purge file name from queue.
  376. ;-----------------------------------------------------------------------------
  377. PURGE_FROM_QUEUE:
  378.         MOV     DI,CS:QUEUE_HEAD_PTR    ;Get queue pointer
  379.         MOV     SI,DS:[DI]              ;Get pointer to next file
  380. PURGE_FILE_LOOP:
  381.         CMP     WORD PTR DS:[SI],0FFFFH ;See if good file
  382.         JE      PURGE_DONE
  383.         MOV     CX,DS:[SI]              ;Compute length of entry
  384.         SUB     CX,SI
  385.         MOV     BX,DI                   ;save pointer to entry
  386.         REP     MOVSB                   ;Copy queue entry
  387.         MOV     DS:[BX],DI              ;Update pointer
  388.         JMP     PURGE_FILE_LOOP
  389. PURGE_DONE:
  390.         MOV     WORD PTR DS:[DI],0FFFFH ;copy end pointer
  391.         INC     DI
  392.         INC     DI
  393.         MOV     CS:DATA_BUFF_START,DI   ;Update start of data buffer.
  394.         DEC     CS:FILE_COUNT
  395. ;-----------------------------------------------------------------------------
  396. ;Clean up DOS for return to forground task. Start with extended error info.
  397. ;-----------------------------------------------------------------------------
  398. CLEAN_UP:
  399.         PUSH    CS
  400.         POP     DS
  401.         ASSUME  DS:CODE
  402.         CMP     WORD PTR DOS_VERSION,30AH
  403.         JB      SKIP_ERR_RESTORE
  404.         MOV     AX,5D0AH                ;Restore ext error info
  405.         MOV     DX,OFFSET ERRINFOARRAY  ;point to saved info
  406.         INT     21H
  407. SKIP_ERR_RESTORE:
  408. ;-----------------------------------------------------------------------------
  409. ;If using EMS memory, restore EMS mapping context.
  410. ;-----------------------------------------------------------------------------
  411.         CMP     EMS_FLAG,0
  412.         JE      EMS_RESTORE_SKIP
  413.         MOV     AH,48H                  ;Restore mapping context
  414.         MOV     DX,EMS_HANDLE
  415.         INT     67H
  416. EMS_RESTORE_SKIP:
  417. ;-----------------------------------------------------------------------------
  418. ;Restore PSP and DTA
  419. ;-----------------------------------------------------------------------------
  420.         MOV     BX,SAVED_PSP            ;save it
  421.         MOV     AH,50H                  ;Set PSP
  422.         CALL    DOSPSPCALL
  423.         PUSH    ES
  424.         LES     DX,[SAVED_DTA]
  425.         MOV     AH,1AH                  ;Set DTA
  426.         INT     21H
  427.         POP     ES
  428. ;-----------------------------------------------------------------------------
  429. ;Reset the displaced interrupt 1Bh, 23h, and 24h vectors.
  430. ;-----------------------------------------------------------------------------
  431.         PUSH    DS
  432.         MOV     AX,2524H                ;reset int 24h vector
  433.         LDS     DX,CS:[VECTOR24H]
  434.         INT     21H
  435.         MOV     AX,2523H                ;reset int 24h vector
  436.         LDS     DX,CS:[VECTOR23H]
  437.         INT     21H
  438.         MOV     AX,251BH                ;reset int 1Bh vector
  439.         LDS     DX,CS:[VECTOR1BH]
  440.         INT     21H
  441.         POP     DS
  442. ;-----------------------------------------------------------------------------
  443. ;Restore register values, switch back to original stack, and return to caller.
  444. ;-----------------------------------------------------------------------------
  445. MAIN_EXIT:
  446.         CALL    RESTORE_REGS            ;Restore registers
  447.         ASSUME  DS:NOTHING
  448.         CLI                             ;make sure interrupts are off
  449.         MOV     SS,CS:SS_REGISTER       ;switch to original stack
  450.         MOV     SP,CS:SP_REGISTER
  451.         STI                             ;interrupts on
  452.         DEC     CS:[ACTIVE]             ;clear program status flag
  453.         RET                             ;Return to interrupt routine
  454. MAIN            ENDP
  455.  
  456. ;-----------------------------------------------------------------------------
  457. ; GETPATHFILE copies the path from the queue and appends the filename from the
  458. ; DTA assumed to be at offset 80h.
  459. ;   Entry:  ES:SI - ASCIIZ path (can include filename.)
  460. ;           DL - 0 = Source file, always append filename from DTA.
  461. ;                1 = Destination file, append filename only if path specified.
  462. ;   Exit:   CF clear - file opened.
  463. ;           CF set   - error on file open.
  464. ;-----------------------------------------------------------------------------
  465. GETPATHFILE     PROC    NEAR
  466.         ASSUME  CS:CODE
  467.         PUSH    AX
  468.         MOV     CX,75                   ;Max length of string
  469.         MOV     DI,CS:DATA_BUFF_START   ;Copy name to data buffer
  470. GETPATHFILE0:
  471.         LODSB                           ;Get a byte
  472.         STOSB                           ;Store a byte
  473.         OR      AL,AL                   ;are we at the end?
  474.         JNE     GETPATHFILE0            ;No, loop back
  475.         OR      DL,DL                   ;See if source or dest file
  476.         JE      GETPATHFILE1
  477.         CMP     BYTE PTR ES:[DI-2],"\"  ;Is the a path specification?
  478.         JNE     GETPATHFILE_EXIT        ;No, don't append src filename
  479. GETPATHFILE1:
  480.         STD                             ;scan backwards
  481.         MOV     CX,15                   ;Find last \ in filename
  482.         MOV     AL,"\"
  483.         DEC     DI                      ;Back up before 0
  484.         REPNE   SCASB
  485.         CLD
  486.         INC     DI                      ;move DI past \
  487.         INC     DI
  488.         PUSH    DS
  489.         PUSH    CS
  490.         POP     DS
  491.         MOV     SI,OFFSET COMMAND_TAIL+1EH
  492.         MOV     CX,13                   ;copy filename found
  493.         REP     MOVSB
  494.         POP     DS
  495. GETPATHFILE_EXIT:
  496.         POP     AX
  497.         RET
  498. GETPATHFILE     ENDP
  499.  
  500. ;-----------------------------------------------------------------------------
  501. ; GET DEST NAME creates the destination file name from the queue.
  502. ;  Exit:  DX - points to fully specified destination filename.
  503. ;-----------------------------------------------------------------------------
  504. GET_DEST_NAME   PROC    NEAR
  505.         ASSUME  CS:CODE
  506.         MOV     DI,CS:QUEUE_HEAD_PTR    ;Get pointer to filename
  507.         ADD     DI,6                    ;point to file names
  508.         XOR     AL,AL                   ;search for end of 1st name
  509.         MOV     CX,75
  510.         REPNE   SCASB
  511.         MOV     SI,DI                   ;copy pointer
  512.         MOV     DL,1                    ;indicate destination file
  513.         CALL    GETPATHFILE
  514.         MOV     DX,CS:DATA_BUFF_START   ;point to filename
  515.         RET
  516. GET_DEST_NAME   ENDP
  517. ;-----------------------------------------------------------------------------
  518. ; DOSPSPCALL modifies critical error flag on PSP calls to DOS is using 2.x
  519. ;-----------------------------------------------------------------------------
  520. DOSPSPCALL      PROC    NEAR
  521.         ASSUME  CS:CODE
  522.         CMP     WORD PTR CS:[DOS_VERSION],30AH  ;See if DOS < 3.1
  523.         JAE     DOSPSPCALL_OK              ;no, just call DOS
  524.         PUSH    DS
  525.         PUSH    DI
  526.         LDS     DI,CS:CEF_PTR           ;retrieve crit err flag adr
  527.         INC     BYTE PTR [DI]           ;Set DOS in crit error state
  528.         POP     DI
  529.         POP     DS
  530.         INT     21H                     ;Call   DOS
  531.         PUSH    DS
  532.         PUSH    DI
  533.         LDS     DI,CS:CEF_PTR           ;retrieve crit err flag adr
  534.         DEC     BYTE PTR [DI]           ;Set DOS in crit error state
  535.         POP     DI
  536.         POP     DS
  537.         RET
  538. DOSPSPCALL_OK:
  539.         INT     21H                     ;Call DOS
  540.         RET
  541. DOSPSPCALL      ENDP
  542.  
  543. ;-----------------------------------------------------------------------------
  544. ; SAVEREGS saves all the registers used in the interrupt routines and sets DS.
  545. ;-----------------------------------------------------------------------------
  546. SAVE_REGS       PROC    NEAR
  547.         POP     CS:[RET_ADDR]           ;Get address to return to
  548.         PUSH    AX                      ;save all registers
  549.         PUSH    BX
  550.         PUSH    CX
  551.         PUSH    DX
  552.         PUSH    BP
  553.         PUSH    SI
  554.         PUSH    DI
  555.         PUSH    DS
  556.         PUSH    ES
  557.         PUSH    CS                      ;Set DS = CS
  558.         POP     DS
  559.         ASSUME  DS:CODE
  560.         JMP     WORD PTR [RET_ADDR]     ;Return
  561. SAVE_REGS       ENDP
  562.  
  563. ;-----------------------------------------------------------------------------
  564. ;RESTOREREGS restores register values.
  565. ;-----------------------------------------------------------------------------
  566. RESTORE_REGS    PROC    NEAR
  567.         POP     RET_ADDR                ;Save return address
  568.         POP     ES                      ;restore registers
  569.         POP     DS
  570.         ASSUME  DS:NOTHING
  571.         POP     DI
  572.         POP     SI
  573.         POP     BP
  574.         POP     DX
  575.         POP     CX
  576.         POP     BX
  577.         POP     AX
  578.         JMP     WORD PTR CS:[RET_ADDR]  ;Return
  579. RESTORE_REGS    ENDP
  580. ;-----------------------------------------------------------------------------
  581. ; REMOVE deallocates the memory block addressed by ES and restores the
  582. ; interrupt vectors displaced on installation.
  583. ;   Entry:  ES - segment to release
  584. ;   Exit:   CF clear - program uninstalled
  585. ;           CF set   - can't uninstall
  586. ;-----------------------------------------------------------------------------
  587. REMOVE          PROC    NEAR
  588.         ASSUME  CS:CODE
  589.         INC     CS:ACTIVE
  590.         CALL    SAVE_REGS               ;Save registers
  591.         ASSUME  DS:CODE
  592. ;
  593. ;Make sure none of the vectors has been altered.
  594. ;
  595.         MOV     AL,8                    ;check interrupt 8 vector
  596.         CALL    CHECKVECTOR
  597.         JNE     REMOVE_ERROR
  598.         MOV     AL,13H                  ;check interrupt 13h vector
  599.         CALL    CHECKVECTOR
  600.         JNE     REMOVE_ERROR
  601.         MOV     AL,28H                  ;check interrupt 28h vector
  602.         CALL    CHECKVECTOR
  603.         JNE     REMOVE_ERROR
  604. ;
  605. ;If using EMS memory, release it.
  606. ;
  607.         CMP     EMS_FLAG,0
  608.         JE      SKIP_REMOVE_EMS
  609.         MOV     AH,45H                  ;Deallocate pages
  610.         MOV     DX,EMS_HANDLE
  611.         INT     67H
  612.         OR      AH,AH
  613.         JNE     REMOVE_ERROR
  614. SKIP_REMOVE_EMS:
  615. ;
  616. ;Release the memory occupied by the program.
  617. ;
  618.         PUSH    CS
  619.         POP     ES
  620.         MOV     AH,49H                  ;free memory given to
  621.         INT     21H                     ;  original program block
  622.         JC      REMOVE_ERROR            ;branch on error
  623. ;
  624. ;Restore the interrupt 8, 13h, and 28h vectors.
  625. ;
  626.         PUSH    DS                      ;save DS
  627.         ASSUME  DS:NOTHING
  628.         MOV     AX,2508H                ;restore interrupt 8 vector
  629.         LDS     DX,ES:[INT8H]
  630.         INT     21H
  631.         MOV     AX,2513H                ;restore interrupt 13h vector
  632.         LDS     DX,ES:[INT13H]
  633.         INT     21H
  634.         MOV     AX,2528H                ;restore interrupt 28h vector
  635.         LDS     DX,ES:[INT28H]
  636.         INT     21H
  637.         POP     DS                      ;restore DS
  638.         ASSUME  DS:CODE
  639. ;
  640. ;Destroy the ASCII fingerprint that identifies the code and exit.
  641. ;
  642.         NOT     WORD PTR [BEGIN]        ;destroy fingerprint
  643.         CLC                             ;clear CF for exit
  644. REMOVE_EXIT:
  645.         DEC     ACTIVE
  646.         CALL    RESTORE_REGS
  647.         RET                             ;exit with CF intact
  648. ;
  649. ;The program can't be uninstalled.  Set CF and exit.
  650. ;
  651. REMOVE_ERROR:   STC
  652.         JMP     REMOVE_EXIT
  653. REMOVE          ENDP
  654.  
  655. ;-----------------------------------------------------------------------------
  656. ; CHECKVECTOR is called by REMOVE to compare the segment pointed to by an
  657. ; interrupt vector against a segment value supplied by the caller.
  658. ;   Entry:  AL - interrupt number
  659. ;   Exit:   ZF clear - segments do not match
  660. ;           ZF set   - segments match
  661. ;-----------------------------------------------------------------------------
  662. CHECKVECTOR     PROC    NEAR
  663.         PUSH    CS
  664.         POP     CX
  665.         MOV     AH,35H                  ;get vector
  666.         INT     21H
  667.         MOV     AX,ES                   ;transfer segment to AX
  668.         CMP     AX,CX                   ;compare
  669.         RET
  670. CHECKVECTOR     ENDP
  671.  
  672. ;-----------------------------------------------------------------------------
  673. ; FINALINSTALL is called to setup the data queue and to TSR.
  674. ;-----------------------------------------------------------------------------
  675. FINALINSTALL    PROC    NEAR
  676.     ASSUME  CS:CODE,DS:CODE,ES:CODE
  677.         MOV     DI,[QUEUE_HEAD_PTR]
  678.         MOV     ES,DATA_SEGMENT
  679.         MOV     SI,OFFSET END_OF_CODE   ;point to filenames
  680.         CALL    PUTINQUEUE              ;Load files in queue
  681.         MOV     DATA_BUFF_START,DI      ;Set start of data buffer
  682.         INC     FILE_COUNT              ;Inc file count
  683. ;
  684. ;Terminate and remain resident in memory.
  685. ;
  686.         DEC     ACTIVE                  ;allow background task
  687.         MOV     AX,3100H                ;terminate with ERRORLEVEL = 0
  688.         MOV     DX,(OFFSET END_OF_DATA-OFFSET CODE+15) SHR 4
  689.         CMP     EMS_FLAG,0
  690.         JE      FINAL_INSTALL1
  691.         MOV     DX,(OFFSET DATA_BUFFER-OFFSET CODE+15) SHR 4
  692. FINAL_INSTALL1:
  693.         INT     21H
  694. FINALINSTALL    ENDP
  695.  
  696. ;-----------------------------------------------------------------------------
  697. ; PUTINQUEUE is called copy the fully qualified filenames into the queue.
  698. ;  Entry:  ES:DI - Points to open entry in queue.
  699. ;          DS:SI - Points to entry to put in queue.
  700. ;-----------------------------------------------------------------------------
  701. PUTINQUEUE      PROC    NEAR
  702.         ASSUME  CS:CODE,DS:CODE
  703.         MOV     BX,DI                   ;save pointer
  704.         MOV     DX,2                    ;move two asciiz strings
  705.         ADD     DI,DX                   ;move past pointer
  706.         XOR     AX,AX
  707.         STOSW                           ;initialize file flags
  708.         STOSW
  709. COPY_LOOP1:
  710.         LODSB                           ;Copy filename
  711.         STOSB
  712.         CMP     AL,0
  713.         JNE     COPY_LOOP1
  714.         DEC     DL                      ;decriment name counter
  715.         JNE     COPY_LOOP1
  716.         MOV     ES:[BX],DI              ;point to next available
  717.         MOV     WORD PTR ES:[DI],0FFFFH ;  space in queue
  718.         INC     DI
  719.         INC     DI
  720.         RET
  721. PUTINQUEUE      ENDP
  722.  
  723. ;=============================================================================
  724. ; Buffer space to be used once the program is resident.
  725. ;=============================================================================
  726. PC              = $
  727. PC              = PC + 256
  728. STACK_SPACE     = PC                            ;stack for resident routine
  729. DATA_BUFFER     = PC                            ;Buffer for data
  730. PC              = PC + 4096
  731. END_OF_DATA     = PC
  732.  
  733. ;=============================================================================
  734. ; INITIALIZE
  735. ;=============================================================================
  736. ERRMSG1         DB      "Source file not found$"
  737. ERRMSG2         DB      "Bad target path$"
  738. ERRMSG3         DB      "Can't install$"
  739. ERRMSG4         DB      "Dup. file names$"
  740. ERRMSG5         DB      "Bad Switch$"
  741. ERRMSG6         DB      "(Already installed)$"
  742. ERRMSG7         DB      "EMS driver error$"
  743. ERRMSG8        DB    "Deinstall queued$"
  744.  
  745. OTHER_SEG       DW      0                       ;Segment of installed code
  746. ALRDY_INSTALLED DB      0                       ;bcopy already installed flag
  747. DEF_DISK        DB      ?                       ;Default disk drive
  748. EMS_HEADER      DB      "EMMXXXX0"              ;EMS driver header
  749.  
  750. INITIALIZE      PROC    NEAR
  751.         ASSUME CS:CODE, DS:CODE
  752.  
  753.         MOV     DX,OFFSET PROGRAM
  754.         CALL    MESSAGE
  755.         CLD                             ;clear DF
  756. ;-----------------------------------------------------------------------------
  757. ;Get DOS version.
  758. ;-----------------------------------------------------------------------------
  759.         MOV     AH,30H                  ;Get DOS version
  760.         INT     21H
  761.         XCHG    AL,AH                   ;Put version in proper order
  762.         MOV     DOS_VERSION,AX          ;Save DOS version
  763. ;-----------------------------------------------------------------------------
  764. ;Get default disk drive.
  765. ;-----------------------------------------------------------------------------
  766.         MOV     AH,19H                  ;Get default disk
  767.         INT     21H
  768.         INC     AL
  769.         MOV     DEF_DISK,AL
  770. ;-----------------------------------------------------------------------------
  771. ;See if a copy is already resident in memory. If no copy, install.
  772. ;-----------------------------------------------------------------------------
  773.         NOT     WORD PTR [BEGIN]        ;initialize fingerprint
  774.         MOV     BX,600H                 ;zero BX for start
  775.         MOV     AX,CS                   ;keep CS value in AX
  776. FIND_COPY:
  777.         INC     BX                      ;increment search segment value
  778.         MOV     ES,BX
  779.         CMP     AX,BX                   ;not installed if current
  780.         JE      FIND_COPY1              ;  segment is looped back to
  781.         MOV     SI,OFFSET BEGIN         ;search this segment for ASCII
  782.         MOV     DI,SI                   ;  fingerprint
  783.         MOV     CX,16
  784.         REPE    CMPSB
  785.         JNE     FIND_COPY               ;loop back if not found
  786.         INC     ALRDY_INSTALLED         ;Clear installed flag
  787.         MOV    DX,OFFSET ERRMSG6
  788.         CALL    MESSAGE
  789. FIND_COPY1:
  790.         INC     ES:[ACTIVE]             ;Don't let background active
  791.         MOV     OTHER_SEG,ES            ;save installed code segment
  792.         PUSH    CS
  793.         POP     ES
  794. ;-----------------------------------------------------------------------------
  795. ;Parse the command line for remove switch.
  796. ;-----------------------------------------------------------------------------
  797.         MOV     DI,OFFSET COMMAND_TAIL  ;Point SI to command line text
  798.         MOV     CL,[DI]                 ;Get length of command line.
  799.  
  800.         OR    CL,CL
  801.         JNZ    SWITCHES
  802.         JMP    TERMINATE
  803. SWITCHES:
  804.         XOR     CH,CH
  805.         INC     DI
  806.         PUSH    CX                      ;Save pointer for later use.
  807.         PUSH    DI
  808. SWITCHES1:
  809.         MOV     AL,"/"                  ;Put switch in AL
  810.         REPNE   SCASB                   ;Scan for cmd line switches
  811.         JNE     PARSE
  812.         MOV     AH,[DI]
  813.         AND     AH,0DFH                 ;Convert to caps
  814.         CMP     AH,"U"                  ;See if uninstall switch
  815.         JE      SWITCHES2
  816.         CMP     AH,"X"                  ;See if expanded memory switch
  817.         JE      SWITCHES3
  818.         MOV     DX,OFFSET ERRMSG5       ;Illegal switch
  819.         ADD     SP,4                    ;Clean up stack
  820.         JMP     DISP_ERROR
  821. SWITCHES2:
  822.         PUSH    ES
  823.         MOV     ES,OTHER_SEG
  824.         INC     ES:[REMOVE_FLAG]        ;Set uninstall flag
  825.         POP     ES
  826.         MOV    DX,OFFSET ERRMSG8
  827.         CALL    MESSAGE
  828.         JMP     SWITCHES1
  829. SWITCHES3:
  830.         CMP     ALRDY_INSTALLED,0
  831.         JE      SWITCHES4
  832.         MOV     DX,OFFSET ERRMSG5
  833.         CALL    MESSAGE
  834.         JMP     SWITCHES1
  835. SWITCHES4:
  836.         INC     EMS_FLAG                ;Set expanded memory flag
  837.         JMP     SWITCHES1
  838. ;-----------------------------------------------------------------------------
  839. ;Parse the command line and create a complete filespec.
  840. ;-----------------------------------------------------------------------------
  841. PARSE:        POP     SI                      ;Get back pointer to cmd line
  842.         POP     CX
  843.         MOV     DI,OFFSET END_OF_CODE   ;save fully specified name
  844.         CALL    PARSE_FILENAME          ;  in a safe place.
  845.         PUSH    DI                      ;save 2nd file pointer
  846.         DEC     SI
  847.         CALL    PARSE_FILENAME          ;process 2nd filename
  848.         POP     SI
  849. ;-----------------------------------------------------------------------------
  850. ;Verify that source file exists.
  851. ;-----------------------------------------------------------------------------
  852.         MOV     DX,OFFSET END_OF_CODE   ;point to source filename
  853.         MOV     CX,00                   ;normal file search
  854.         MOV     AH,4EH                  ;Find first
  855.         INT     21H
  856.         MOV     DX,SI                   ;get 2nd file pointer
  857.         JNC     VERIFY_DEST
  858.         MOV     DX,OFFSET ERRMSG1       ;File not found
  859.         JMP     DISP_ERROR              ;Print error msg and terminate
  860. ;-----------------------------------------------------------------------------
  861. ;Determine if the destination specification is a path or a complete filename.
  862. ;See if path by setting default path to destination.
  863. ;-----------------------------------------------------------------------------
  864. VERIFY_DEST:    PUSH    DX
  865.         MOV     DX,[SI]                 ;Get destination disk
  866.         MOV     SI,OFFSET END_OF_CODE + 300
  867.         MOV     [SI],DX                 ;Save current path in
  868.         MOV     BYTE PTR [SI+2],"\"     ;  safe place.
  869.         ADD     SI,3
  870.         SUB     DL,40H                  ;Convert to hex
  871.         MOV     AH,47H                  ;Get current directory
  872.         INT     21H
  873.         POP     DX
  874.         JC      VERIFY_ERROR
  875.         MOV     AH,3BH                  ;Set path to destination
  876.         INT     21H
  877.         JC      VERIFY1
  878.         MOV     DX,SI                   ;Point DX to saved path
  879.         SUB     DX,3
  880.         MOV     AH,3BH                  ;Restore path
  881.         INT     21H
  882.         CMP     BYTE PTR [DI-2],"\"
  883.         JE      VERIFY_DONE
  884.         MOV     WORD PTR [DI-1],005CH   ;Append \ to indicate path
  885.         JMP     SHORT VERIFY_DONE
  886. ;-----------------------------------------------------------------------------
  887. ;Try failed, search for file.
  888. ;-----------------------------------------------------------------------------
  889. VERIFY1:    MOV     CX,0                    ;Normal search
  890.         MOV     AH,4EH                  ;Find first
  891.         INT     21H
  892.         JNC     VERIFY_DONE             ;file found, were done.
  893.         CMP     AX,3                    ;check for bad path
  894.         JNE     VERIFY_DONE             ;path found, must be file
  895. VERIFY_ERROR:
  896.         MOV     DX,OFFSET ERRMSG2       ;bad path, print path
  897.         JMP     SHORT DISP_ERROR        ;  not found.
  898. VERIFY_DONE:
  899. ;-----------------------------------------------------------------------------
  900. ;Check to see if the filenames are the same.
  901. ;-----------------------------------------------------------------------------
  902.         MOV     SI,OFFSET END_OF_CODE
  903.         MOV     DI,DX
  904.         MOV     CX,DX                   ;Compute length of name
  905.         SUB     CX,SI
  906.         REPE    CMPSB                   ;compare strings
  907.         JE      SAME_NAMES
  908.         MOV     AX,005CH
  909.         CMP     [DI-2],AX               ;See if dest is path
  910.         JNE     COMPARE_NAMES1
  911.         MOV     DI,SI                   ;Scan source for \. If not
  912.         REPNE   SCASB                   ;  found, src and dest are
  913.         JE      COMPARE_NAMES1          ;  in the same directory.
  914. SAME_NAMES:
  915.         MOV     DX,OFFSET ERRMSG4       ;Same, print error message
  916.         JMP     SHORT DISP_ERROR
  917. COMPARE_NAMES1:
  918.         CMP     ALRDY_INSTALLED,0       ;see if bcopy installed
  919.         JE      INSTALL
  920. ;-----------------------------------------------------------------------------
  921. ;Add new file names to installed code's queue and terminate.
  922. ;-----------------------------------------------------------------------------
  923. LOAD_FILES:
  924.         MOV     SI,OFFSET END_OF_CODE   ;point to file names
  925.         PUSH    DS
  926.         MOV     DS,OTHER_SEG            ;point ES to installed code
  927.         ASSUME  DS:NOTHING
  928. LOAD_QUEUE1:
  929.         CMP     DS:[ACTIVE],1           ;Wait till background not
  930.         JNE     LOAD_QUEUE1             ;  active.
  931.         MOV     DI,DS:[QUEUE_HEAD_PTR]  ;Get start of queue.
  932.         MOV     ES,DS:[DATA_SEGMENT]
  933. LOAD_QUEUE2:
  934.         MOV     AX,0FFFFH
  935.         CMP     ES:[DI],AX              ;Is queue empty?
  936.         JE      LOAD_QUEUE3             ;yes, continue
  937.         MOV     DI,ES:[DI]              ;Get pointer to next file
  938.         JMP     LOAD_QUEUE2
  939. LOAD_QUEUE3:
  940.         POP     DS                      ;restore DS
  941.         ASSUME  DS:CODE
  942.         CALL    PUTINQUEUE              ;copy filenames into queue
  943.         MOV     ES,OTHER_SEG
  944.         MOV     ES:[DATA_BUFF_START],DI
  945.         INC     ES:FILE_COUNT
  946. ;-----------------------------------------------------------------------------
  947. ;Enable background task and terminate.
  948. ;-----------------------------------------------------------------------------
  949. TERMINATE:
  950.         DEC     ES:[ACTIVE]             ;enable background task.
  951.         MOV     AX,4C00H                ;Terminate with RC = 0.
  952.         INT     21H
  953.  
  954. ;=============================================================================
  955. ;Display error message and exit with Return Code = 1.
  956. ;=============================================================================
  957. DISP_ERROR:    CALL    MESSAGE
  958.         MOV     ES,OTHER_SEG            ;point ES to installed code
  959.         DEC     ES:[ACTIVE]             ;enable background task.
  960.         MOV     AX,4C01H                ;Exit RC = 1
  961.         INT     21H
  962.  
  963. ;=============================================================================
  964. ;Install. Get address of INDOS flag.
  965. ;=============================================================================
  966. INSTALL:
  967.         MOV     AH,34H                  ;get address from DOS
  968.         INT     21H
  969.         MOV     WORD PTR INDOS,BX       ;store it
  970.         MOV     WORD PTR INDOS[2],ES
  971. ;-----------------------------------------------------------------------------
  972. ;Find and save the address of the DOS critical error flag.
  973. ;-----------------------------------------------------------------------------
  974.         MOV     AX,3E80H                ;CMP opcode
  975.         MOV     CX,2000H                ;max search length
  976.         MOV     DI,BX                   ;start at INDOS address
  977. CEFS1:          REPNE   SCASW                   ;do the search
  978.         JCXZ    CEFS2                   ;branch if search failed
  979.         CMP     BYTE PTR ES:[DI+5],0BCH ;verify this is it
  980.         JE      CEFSFOUND               ;branch if it is
  981.         JMP     CEFS1                   ;resume loop if it's not
  982. CEFS2:          MOV     CX,2000H                ;search again
  983.         INC     BX                      ;search odd addresses this time
  984.         MOV     DI,BX
  985. CEFS3:          REPNE   SCASW                   ;look for the opcode
  986.         JCXZ    CEFSNOTFOUND            ;not found if loop expires
  987.         CMP     BYTE PTR ES:[DI+5],0BCH ;verify this is it
  988.         JE      CEFSFOUND
  989.         JMP     CEFS3
  990. CEFSNOTFOUND:
  991.         MOV     DX,OFFSET ERRMSG3       ;Critical error flag not found
  992.         JMP     SHORT DISP_ERROR
  993. CEFSFOUND:      MOV     AX,ES:[DI]              ;get flag offset address
  994.         MOV     WORD PTR CEF_PTR,AX     ;store it
  995.         MOV     WORD PTR CEF_PTR[2],ES
  996. ;-----------------------------------------------------------------------------
  997. ;Set up EMS memory if necessary.
  998. ;-----------------------------------------------------------------------------
  999.         PUSH    CS
  1000.         POP     DATA_SEGMENT            ;assume no ems memory
  1001.         CMP     EMS_FLAG,0
  1002.         JE      SKIP_EMS_SETUP
  1003. ;Test for the EMS driver.
  1004.         PUSH    ES                      ;Test for ems driver
  1005.         PUSH    DI
  1006.         MOV     AX,3567H                ;Get EMS vector
  1007.         INT     21H
  1008.         MOV     DI,0AH                  ;Using the segment from the
  1009.         MOV     SI,OFFSET EMS_HEADER    ;  67h vector, look at offset
  1010.         MOV     CX,8                    ;  0ah. Compare the next 8
  1011.         CLD                             ;  bytes with the expected
  1012.         REPE    CMPSB                   ;  EMS header. If  they are
  1013.         POP     DI                      ;  the same, EMS driver
  1014.         POP     ES                      ;  found.
  1015.         JE      EMS_FOUND
  1016. EMS_ERROR:
  1017.         MOV     DX,OFFSET ERRMSG7       ;EMS driver error
  1018.         JMP     DISP_ERROR
  1019. EMS_FOUND:
  1020.         STC
  1021.         MOV     AH,40H                  ;Check status
  1022.         INT     67H
  1023.         OR      AH,AH
  1024.         JNE     EMS_ERROR
  1025.         MOV     AH,41H                  ;Get page frame segment
  1026.         INT     67H
  1027.         OR      AH,AH
  1028.         JNE     EMS_ERROR
  1029.         MOV     DATA_SEGMENT,BX         ;Save seg of EMS page frame
  1030.         MOV     AH,43H                  ;Get page frame segment
  1031.         MOV     BX,1                    ;request 1 page
  1032.         INT     67H
  1033.         OR      AH,AH
  1034.         JNE     EMS_ERROR
  1035.         MOV     EMS_HANDLE,DX           ;Save EMS handle
  1036.         MOV     AX,4400H                ;Map page
  1037.         XOR     BX,BX                   ;map page 1
  1038.         MOV     DX,EMS_HANDLE           ;identify user
  1039.         INT     67H
  1040.         OR      AH,AH
  1041.         JNE     EMS_ERROR
  1042.         MOV     DATA_BUFF_END,4096      ;set buffer parameters
  1043.         MOV     DATA_BUFF_START,0
  1044. SKIP_EMS_SETUP:
  1045. ;-----------------------------------------------------------------------------
  1046. ;Initialize pointers needed for queue.
  1047. ;-----------------------------------------------------------------------------
  1048.         MOV     BX,DATA_BUFF_START      ;initialize queue
  1049.         MOV     QUEUE_HEAD_PTR,BX
  1050. ;-----------------------------------------------------------------------------
  1051. ;Set interrupt 8h, 13h, and 28h vectors to internal handlers.
  1052. ;-----------------------------------------------------------------------------
  1053.         MOV     AX,3508H                ;interrupt 8
  1054.         INT     21H
  1055.         MOV     WORD PTR INT8H,BX
  1056.         MOV     WORD PTR INT8H[2],ES
  1057.         MOV     AX,2508H
  1058.         MOV     DX,OFFSET TIMERINT
  1059.         INT     21H
  1060.  
  1061.         MOV     AX,3513H                ;interrupt 13h
  1062.         INT     21H
  1063.         MOV     WORD PTR INT13H,BX
  1064.         MOV     WORD PTR INT13H[2],ES
  1065.         MOV     AX,2513H
  1066.         MOV     DX,OFFSET DISKINT
  1067.         INT     21H
  1068.  
  1069.         MOV     AX,3528H                ;interrupt 28h
  1070.         INT     21H
  1071.         MOV     WORD PTR INT28H,BX
  1072.         MOV     WORD PTR INT28H[2],ES
  1073.         MOV     AX,2528H
  1074.         MOV     DX,OFFSET IDLE
  1075.         INT     21H
  1076. ;-----------------------------------------------------------------------------
  1077. ;Deallocate the program's environment block.
  1078. ;-----------------------------------------------------------------------------
  1079.         MOV     AX,DS:[2CH]             ;get environment segment
  1080.         MOV     ES,AX
  1081.         MOV     AH,49H                  ;free it
  1082. ;;;        INT     21H
  1083.         PUSH    CS                      ;reset ES to the code segment
  1084.         POP     ES
  1085.         JMP     FINALINSTALL            ;Jump to code above data area
  1086. INITIALIZE      ENDP
  1087.  
  1088. ;======================================================================
  1089. ; Send message to screen
  1090. ;----------------------------------------------------------------------
  1091. CRLF$        DB    13,10,"$"
  1092.  
  1093. MESSAGE        PROC    NEAR
  1094.         ASSUME  CS:CODE,DS:CODE
  1095.  
  1096.         MOV    AH,9
  1097.         INT    21H
  1098.         MOV    DX,OFFSET CRLF$
  1099.         MOV    AH,9
  1100.         INT    21H
  1101.         RET
  1102.  
  1103. MESSAGE        ENDP
  1104.  
  1105. ;======================================================================
  1106. ; PARSE_FILENAME  creates a proper pathname for a filename
  1107. ;   Entry:  SI - pointer to asciiz filename
  1108. ;           DI - pointer to buffer to hold resulting pathname
  1109. ;-----------------------------------------------------------------------------
  1110. PARSE_FILENAME  PROC    NEAR
  1111.         ASSUME  CS:CODE,DS:CODE,ES:CODE
  1112. PARSE0:
  1113.         CALL    SCANFORSEP              ;Scan till character found
  1114.         LAHF                            ;Save return flags
  1115.         CMP     AL,0DH                  ;See if carrage return or
  1116.         JE      PARSE01                 ;  command switch.
  1117.         CMP     AL,"/"
  1118.         JE      PARSE01
  1119.         SAHF
  1120.         JC      PARSE0
  1121.         JMP     SHORT PARSE02
  1122. PARSE01:
  1123.         MOV     WORD PTR [SI-1],0       ;If so, fake a null file name
  1124. PARSE02:
  1125. ;Look for disk specification
  1126.         DEC     SI                      ;backup to before 1st char
  1127.         CMP     BYTE PTR 1[SI],":"      ;see if disk specified
  1128.         JE      PARSE1
  1129.         MOV     AL,DEF_DISK             ;Get default disk
  1130.         MOV     DL,AL                   ;save default disk number
  1131.         ADD     AL,40H                  ;Convert to ascii
  1132.         MOV     AH,":"
  1133.         JMP     SHORT PARSE2
  1134. PARSE1:
  1135.         LODSW                           ;Get disk specified
  1136.         AND     AL,0DFH                 ;convert to caps
  1137.         MOV     DL,AL
  1138.         SUB     DL,40H                  ;convert to binary
  1139. PARSE2:
  1140.         STOSW                           ;Load disk specification
  1141. ;Look for directory specification.
  1142.         MOV     BX,DI                   ;save start of path
  1143.         MOV     AL,"\"
  1144.         CMP     BYTE PTR [SI],AL        ;See if starting from root
  1145.         JE      PARSE3                  ;yes, skip append of path
  1146.         STOSB                           ;Start at root
  1147.         PUSH    SI                      ;save current pointer
  1148.         MOV     SI,DI                   ;point to dest buffer
  1149.         MOV     AH,47H                  ;Get default path
  1150.         INT     21H
  1151.         MOV     CX,64                   ;Max 64 char in path
  1152.         MOV     AL,0
  1153.         REPNE   SCASB                   ;scan for end of path
  1154.         DEC     DI                      ;move back before zero
  1155.         POP     SI
  1156.         CMP     CX,63                   ;If no path, don't append an
  1157.         JGE     PARSE3                  ;  extra \.
  1158. PARSE21:
  1159.         CALL    SCANFORSEP              ;Get first char of name.
  1160.         JC      PARSE5                  ;If no name, skip append
  1161.         DEC     SI                      ;Backup so char can be reread
  1162.         MOV     AL,"\"                  ;If name, seperate from path
  1163.         STOSB                           ; with a \.
  1164. PARSE3:
  1165. ;Look for filename specification.
  1166.         MOV     CX,75                   ;max 75 characters in a name
  1167.         XOR     AH,AH                   ;Clear last char holder
  1168. PARSE4:
  1169.         CALL    SCANFORSEP              ;Get character, if seperator
  1170.         JC      PARSE5                  ;  char, exit.
  1171.         STOSB                           ;Good char, copy to dest.
  1172.         CMP     AX,".."                 ;See if last 2 chars are same
  1173.         JNE     PARSE41
  1174.         STD                             ;scan backwards
  1175.         SUB     DI,4                    ;First, backup past '\..'
  1176.         MOV     AL,"\"                  ;Look for directory sep
  1177.         PUSH    CX
  1178.         MOV     CX,DI                   ;compute length of path
  1179.         SUB     CX,BX
  1180.         REPNE   SCASB                   ;Now, past last directory
  1181.         POP     CX
  1182.         CLD                             ;scan forwards again
  1183.         INC     DI                      ;Move back past \
  1184. PARSE41:
  1185.         MOV     AH,AL                   ;save last character read.
  1186.         LOOP    PARSE4
  1187. PARSE5:
  1188.         XOR     AL,AL                   ;Terminate string with 0
  1189.         STOSB
  1190.         RET
  1191. PARSE_FILENAME  ENDP
  1192.  
  1193. ;-----------------------------------------------------------------------------
  1194. ; SCANFORSEP looks for file seperator characters.
  1195. ;   Entry:  DS:SI - pointer to character to compare
  1196. ;   Exit:   CF clear - good character
  1197. ;           CF set   - file seperator character detected
  1198. ;           AL - character read.
  1199. ;-----------------------------------------------------------------------------
  1200. SCANFORSEP      PROC    NEAR
  1201.         LODSB                           ;Get character
  1202.         CMP     AL," "                  ;Look for file delimiters
  1203.         JLE     SCANFOR1                ;  space, comma, semicolon,
  1204.         CMP     AL,","                  ;  equal sign, or tab. Or any
  1205.         JE      SCANFOR1                ;  characters with ASCII
  1206.         CMP     AL,";"                  ;  values less than 20 or
  1207.         JE      SCANFOR1                ;  greater than 127.
  1208.         CMP     AL,"="
  1209.         JE      SCANFOR1
  1210.         CMP     AL,"a"                  ;Convert all letters to caps
  1211.         JB      SCANFOR_END
  1212.         CMP     AL,"z"
  1213.         JA      SCANFOR_END
  1214.         AND     AL,0DFH                 ;convert to caps
  1215. SCANFOR_END:
  1216.         CLC                             ;clear flag
  1217.         RET
  1218. SCANFOR1:
  1219.         STC                             ;set found flag
  1220.         RET
  1221. SCANFORSEP      ENDP
  1222.  
  1223. END_OF_CODE     =       $
  1224. CODE            ENDS
  1225.         END     BEGIN
  1226.