home *** CD-ROM | disk | FTP | other *** search
/ Multimedia & CD-ROM 3 / mmcd03-jun1995-cd.iso / utils / various / utils-1 / bcopy.asm < prev    next >
Assembly Source File  |  1991-06-24  |  62KB  |  1,241 lines

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