home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / PJ8_3.ZIP / XCALL.ASM < prev    next >
Assembly Source File  |  1990-04-10  |  25KB  |  781 lines

  1. ;XCALL.ASM
  2. ;(C) COPYRIGHT 1989 DANIEL GREENBERG
  3. ;
  4. ;General-purpose interrupt 2EH utility.  
  5. ;
  6. ;This must be converted into a COM file.
  7. ;SS assumed equal to CS
  8. ;
  9. ;Syntax: 
  10. ;    xcall {command}
  11. ;command is passed to the root COMMAND.COM where it is processed
  12. ;regardless of the presence of a secondary COMMAND.COM.
  13. ;
  14.  
  15. code      segment para public 'code'
  16.      assume cs:code,ds:code
  17.     org 100h
  18. begin: jmp start
  19.  
  20. ;---------------------------------------------------------------------------
  21.  
  22. ;EQUATES
  23. version_two_one        equ  020ah
  24. version_two_one_one    equ  020bh
  25. version_three_zero    equ  0300h
  26. version_three_one    equ  030ah
  27. version_three_two    equ  0314h
  28. version_three_three    equ  031eh
  29. version_four_zero    equ  0400h
  30.  
  31. owner_id        equ  16h    ;Offset in PSP
  32.  
  33.  
  34. ;Following data structures delineate important COMMAND.COM variables, 
  35. ;by version:
  36.  
  37. command2x_data STRUC
  38. TwoE_caller_ip        dw  ?
  39. TwoE_caller_cs        dw  ?
  40. TwoE_caller_psp        dw  ?
  41. command_owner_id    dw  ?        ;If this COMMAND not root this variable
  42. command2x_data ENDS            ; holds PSP of calling COMMAND. Else 
  43.                     ; holds root COMMAND's own PSP.
  44.  
  45. command2_1_data STRUC
  46. command2x_structure    db  8 dup (?)    ;1st 8 bytes same as 2x structure
  47. unkwn            db  5 dup (?)
  48. batch_block_pointer2    dw  ?        ;Seg address of batch file data block,
  49.                     ;0000h = no batch file in progress
  50. batch_fileptr        dd  ?        ;Current file pointer in batch file
  51. comspec2        db  40 dup (?)    ;Path to disc copy of COMMAND.COM
  52. transient_command2    dd  ?        ;Transient COMMAND entry address
  53. more_unkwn        db  6 dup (?)
  54. exec_flag2        db  ?        ;01 = application launched
  55. still_more_unkwn    dw  ?
  56. echo_flag2        db  ?        ;0 = echo off
  57. twoE_flag2        dw  ?         ;0=no 2Eh in progress;81h=COMMAND reentered
  58.                     ; 2eh string at offset 81h; 0ffffh=2eh
  59.                     ; command processed, return 
  60.                     ; to caller pending.
  61. even_more_unkwn        db  6 dup (?)
  62. for_flag2        db  ?        ;01 = for loop in progress
  63. command2_1_data ENDS
  64.  
  65. command3_data STRUC            ;3.0 & 3.1 use same structure
  66. command_twox_structure    db  8 dup (?)    ;1st 8 bytes same structure as 2x
  67. exit_routine3        dd  ?        ;EXIT transfers control to this address
  68. unkwn3            db  5 dup (?)
  69. batch_block_pointer3    dw  ?        ;Seg address of batch file data block
  70.                     ; 0000h = no batch file in progress
  71. comspec3        db  64 dup (?)    ;Path to disc copy of COMMAND.COM
  72. comspec_address3    dw  ?        ;Offset of comspec string
  73. comspec_end_address3    dw  ?        ;Offset of end of comspec string
  74. transient_command3    dd  ?        ;Transient COMMAND entry address
  75. more_unkwn3        db  6 dup (?)
  76. exec_flag3_0        db  ?        ;01 = application launched
  77. still_more_unkwn3    dw  ?
  78. echo_flag3_0        db  ?        ;0 = echo off
  79. twoE_flag3_0        dw  ?        ;0=no 2Eh in progress;81h=COMMAND
  80.                     ; reentered,2eh string at offset 81h;
  81.                     ; 0ffffh=2eh command processed,return
  82.                     ; to caller pending.
  83. even_more_unkwn3    db  8 dup (?)    
  84. for_flag3_0        db  ?        ;01 = for loop in progress
  85. for_block_pointer3_0    dw  ?        ;Seg address of "for" process block
  86. command3_data ENDS
  87.  
  88. command3_2_data STRUC
  89. command_3_structure    db  91 dup (?)    ;1st 91 bytes same struc as 3.0 
  90. unkwn3_2        db  8 dup (?)
  91. exec_flag3_2        db  ?        ;01 = application launched
  92. more_unkwn3_2        db  2 dup (?)
  93. echo_flag3_2        db  ?        ;0 = echo off
  94. twoE_flag3_2        dw  ?        ; 0=no 2Eh in progress;81h=COMMAND
  95.                     ; reentered,2eh string at offset 81h;
  96.                     ; 0ffffh=2eh command processed,return
  97.                     ; to caller pending.    
  98. still_more_unkwn3_2    db  8 dup (?)
  99. for_flag3_2        db  ?        ;01 = for loop in progress
  100. for_block_pointer3_2    dw  ?        ;Seg address of "for" process block
  101. command3_2_data ENDS
  102.  
  103. command3_3_data STRUC
  104. com_three_structure    db  91 dup (?)    ;1st 91 bytes same struc as 3.0.
  105. unkwn3_3        db  8 dup (?)
  106. exec_flag3_3        db  ?        ;01 = application launched
  107. more_unkwn3_3        db  3 dup (?)    
  108. echo_flag3_3        db  ?        ;0 = echo off; 01 = echo on
  109. twoE_flag3_3        dw  ?        ;0=no 2Eh in progress;81h=COMMAND
  110.                     ; reentered,2eh string at offset 81h;
  111.                     ; 0ffffh=2eh command processed,return
  112.                     ; to caller pending.
  113. still_more_unkwn3_3    db  9 dup (?)
  114. for_flag3_3        db  ?        ;01 = for loop in progress
  115. for_block_pointer3_3    dw  ?        ;Seg address of "for" process block
  116. batch_counter3_3    dw  ?        ;Incremented on each nested batch "call" 
  117. command3_3_data ENDS
  118.  
  119. command4_0_data STRUC
  120. com_twox_data_structure    db  8 dup (?)    ;1st 8 bytes same structure as 2x
  121. exit_routine4_0        dd  ?        ;EXIT transfers control to this address
  122. unkwn4_0        db  5 dup (?)
  123. batch_block_pointer4_0    dw  ?        ;Seg address of batch file data block;
  124.                     ;  0000h = no batch file in progress
  125. comspec4_0        db  64 dup (?)    ;Path to disc copy of COMMAND.COM
  126. comspec_string_end4_0    dw  ?        ;Offset of end of comspec string
  127. transient_command4_0    dd  ?        ;Transient COMMAND entry address
  128. more_unkwn4_0        db  8 dup (?)
  129. Exec_flag4_0        db  ?        ;01 = application launched
  130. still_more_unkwn4_0    db  5 dup (?)
  131. echo_flag4_0        db  ?        ;0 = echo off; 01 = echo on
  132. twoE_flag_etc        dw  ?        ;0=no 2Eh in progress;81h=COMMAND
  133.                     ; reentered,2eh string at offset 81h;
  134.                     ; 0ffffh=2eh command processed,return
  135.                     ; to caller pending.
  136. even_more_unkwn4_0    db  9 dup (?)
  137. for_flag4_0        db  ?        ;01 = for loop in progress
  138. for_block_pointer4_0    dw  ?        ;Seg address of "for" process block
  139. batch_counter4_0    dw  ?        ;Incremented on each nested batch "call"
  140. command4_0_data ENDS
  141.  
  142. ;This structure delineates first 6 bytes of batch file data block (ver 3.3+):
  143. batch_block STRUC                
  144. unknown            db  ?
  145. prev_echo_flag        db  ?        ;0 = echo off; 01 = echo on
  146. previous_batch_blk    dw  ?        ;Calling batch file block, if any
  147. previous_for_blk    dw  ?        ;Calling for loop data block, if any
  148. batch_block ENDS            
  149.  
  150. for_flag_address    dw  ?
  151. batch_ptr_address    dw  ?
  152.  
  153.  
  154. ;We save COMMAND's info on previous 2Eh caller here. Later restore this to
  155. ;COMMAND.COM so on our exit COMMAND will return control to previous caller:
  156. previous_2e_psp        dw  ?
  157. previous_2e_ip        dw  ?
  158. previous_2e_cs        dw  ?
  159. previous_2e_flag    dw  ?
  160. twoE_flagoffset        dw  ?
  161.  
  162. ;We save COMMAND's flags and pointers here prior to 2Eh call and restore this
  163. ;info to COMMAND after call.  This allows COMMAND.COM to continue normal
  164. ;execution after our exit:
  165. old_batch_block     dw  ?        
  166. old_batch_fileptr    dd  ?        ;Used in DOS 2.x only
  167. old_batch_counter    dw  ?
  168. old_echo_flag        db  ?
  169. old_for_flag        db  ?        
  170. old_for_block        dw  ?        ;Not used in DOS 2.x
  171.  
  172. stk_ptr            dw  ?
  173. version            dw  ?
  174.  
  175. first            db  0        ;0=no previous active int 2eh
  176. error            db  0        ;0=ok, 1=error during xcalled batch file
  177.                     ; or for loop
  178.  
  179. batch_terminate_mes    db  0dh,0ah,"Cannot restore XCALL'ed batch file "
  180.             db  "after Ctrl-break or critical error.",0dh,0ah
  181.             db  "Batch file will be terminated.",0dh,0ah,"$"
  182.  
  183. ;Note on register usage: First subroutine sets es:di equal to segment:offset
  184. ;of data area for root COMMAND.COM.  After that, es:di are preserved across
  185. ;subroutines.
  186.  
  187. ;===============================================================================
  188. reduce_memory:
  189.     int 21h
  190.  
  191.     push di                ;di=offset of COMMAND's data area.
  192.     mov stk_ptr,sp            ;Save_stack
  193.  
  194.     int 2eh                ;Reenter root COMMAND.COM.
  195.  
  196.  
  197.     mov ax,cs            ;Restore registers & stack.
  198.     cli
  199.     mov ss,ax
  200.     mov sp,cs:stk_ptr
  201.     sti
  202.     mov ds,ax
  203.     pop di                
  204.     pop es                ;es:di=seg:offset of COMMAND's data area
  205.  
  206. ;------------------------------------------------------------------------------
  207.     call check_error        ;Hard error or ctrl-c during batch file?
  208.     cmp error,01            ;If so, need to flush disc buffers.
  209.     jnz x1
  210.     mov ah,0dh
  211.     int 21h                ;Disc reset.
  212.  
  213. x1:    call restore_batch_state    ;Restore previous batch file, if any.
  214.     call reset_for            ;Restore for loop, if necessary
  215.     cmp first,01 
  216.     jz x2
  217.  
  218.     call restore_previous_2e    ;Restore COMMAND's info on previous 
  219.     jmp x3                ; XCALL if any.  (This gurantees that
  220.                     ; COMMAND.COM will return control to
  221.                     ; previous XCALL after our exit.)
  222.  
  223. x2:    call reset_echo_flag        ;Restore echo state
  224.  
  225. x3:    mov ah,4ch            ;Return to COMMAND.COM.
  226.     int 21h
  227.  
  228.  
  229. ;------------------------------------------------------------------------------
  230. ;This routine determines if a ctrl-c or hard error occurred during an
  231. ;xcall'ed batch file or for loop.  If so, the interrupted batch and for blocks
  232. ;are released and COMMAND's pointers are set to zero. Call with ES=COMMAND seg.
  233. ;------------------------------------------------------------------------------
  234. check_error proc near
  235.     mov bx,batch_ptr_address    ;If COMMAND'S batch ptr clear, no error.
  236.     cmp word ptr es:[bx],0000h
  237.     jz check_for_flag
  238.  
  239.     mov error,01
  240.     cmp version,version_three_one
  241.     jge terminate_batch
  242.     mov dx,offset batch_terminate_mes  ;The only way xcall can gain
  243.     mov ah,9            ; control after a ctrl-c in
  244.     int 21h                ; batch file under 2.x-3.0 is if
  245.                     ; user answered no to "Terminate
  246.                     ; Batch file?"
  247. terminate_batch:    
  248.     mov bx,word ptr es:[bx]        ;Get batch block address.
  249.     cmp version,version_three_three
  250.     jge terminate_batch3_3    
  251.  
  252.     call release_command_block    ;Release batch block
  253.  
  254.     mov bx,batch_ptr_address    ;Clear COMMAND's batch blk ptr
  255.     mov word ptr es:[bx],0000h
  256.     jmp check_for_flag
  257.  
  258. terminate_batch3_3:
  259.     call release_batch_block3_3    ;Release batch block(s)
  260.  
  261. check_for_flag:
  262.     mov bx,for_flag_address        ;Get for flag offset
  263.     cmp byte ptr es:[bx],00h    ;If flag set there was an error
  264.     jz ce1
  265.     mov error,01
  266.     mov byte ptr es:[bx],00h    ;Clear for flag
  267.  
  268. ce1:    cmp version,version_three_zero    
  269.     jge check_for_block        ;Under versions 3.x, for block may be
  270.     ret                ;allocated, even if for flag clear.
  271.  
  272. check_for_block:
  273.     cmp word ptr es:[bx+1],0000h    ;Is for block clear?
  274.     jnz release_for_block
  275.     ret
  276.  
  277. release_for_block:            ;No, so deallocate block.
  278.     mov error,01
  279.     mov bx,word ptr es:[bx+1]    ;Get "for" block address
  280.     call release_command_block    ;Release for block
  281.     mov word ptr es:[bx+1],0000h    ;Clear for block pointer
  282.     ret
  283. check_error endp
  284.  
  285. ;------------------------------------------------------------------------------
  286. ;Release_command_block deallocates a memory block owned by COMMAND.COM.
  287. ;Call with BX=segment of block to release and ES=COMMAND.COM segment.
  288. ;------------------------------------------------------------------------------
  289. release_command_block proc near    
  290.     push bx
  291.     mov bx,es            ;es=COMMAND.COM's psp.
  292.     mov ah,50h            ;Set current psp to COMMAND's psp.
  293.     int 21h
  294.     pop bx                
  295.  
  296.     push es                
  297.  
  298.     mov es,bx            ;Deallocate memory block
  299.     mov ah,49h            
  300.     int 21h
  301.  
  302.     mov bx,cs
  303.     mov ah,50h            ;Reset psp.
  304.     int 21h
  305.  
  306.     pop es
  307.     ret
  308. release_command_block endp
  309.  
  310. ;------------------------------------------------------------------------------
  311. ;This procedure deallocates COMMAND's (3.3+) current batch block.  If the 
  312. ;current batch file was call'ed from another (previous) for loop or batch file,
  313. ;these too are deallocated.  This continues until chain of all calling batch
  314. ;and for processes have been deallocated.  Then psp and echo are reset.
  315. ;Call with BX=address of current batch data block for interrupted batch process
  316. ;and ES=COMMAND.COM segment.
  317. ;------------------------------------------------------------------------------
  318. release_batch_block3_3 proc near
  319.     push bx                ;Make current psp = COMMAND.COM
  320.     mov bx,es            
  321.     mov ah,50h            
  322.     int 21h
  323.     pop bx                
  324.  
  325. chk_calling_for:            ;Was this batch file called
  326.     push es             ; from a for loop?            
  327.     push di             
  328.     xor di,di
  329.     mov es,bx            ;Now es = current batch block.
  330.     mov bx,es:[di].previous_for_blk    
  331.     cmp bx,0000             ;bx=calling for loop, if any
  332.     jz lose_current_block        
  333.  
  334.     push es                ;Deallocate calling "for" block
  335.     mov es,bx
  336.     mov ah,49h             
  337.     int 21h 
  338.     pop es
  339.  
  340. ;Save info on echo & calling batch & then deallocate current batch block:
  341. lose_current_block:            
  342.     mov dl,byte ptr es:[di].prev_echo_flag    ;Save previous echo status.
  343.     mov bx,es:[di].previous_batch_blk    ;Save seg of previous batch blk
  344.  
  345.     mov ah,49h             ;Deallocate current batch block
  346.     int 21h 
  347.  
  348.     pop di                 ;es:di =COMMAND'S data area seg:offset
  349.     pop es 
  350.  
  351.     mov es:[di].batch_block_pointer3,bx    ;Set COMMAND batch ptr=previous
  352.                         ; (calling) batch file,if any.
  353.     dec word ptr es:[di].batch_counter3_3    ;Decrement COMMANDS's counter.
  354.     jnz chk_calling_for            ;If more left do them.
  355.  
  356.     mov byte ptr es:[di].echo_flag3_3,dl    ;Restore previous echo state.
  357.  
  358.     mov bx,cs            ;Reset psp.
  359.     mov ah,50h        
  360.     int 21h
  361.     ret
  362. release_batch_block3_3 endp
  363.  
  364. ;-------------------------------------------------------------------------------
  365. ;Restore_batch_state restores COMMAND.COM's batch block pointer. Call with
  366. ;ES = COMMAND'S seg & DI = offset of COMMAND's data area.
  367. ;-------------------------------------------------------------------------------
  368.  
  369. restore_batch_state proc near
  370.  
  371.     mov bx,batch_ptr_address    ;Reset COMMAND's batch ptr to what it
  372.     mov ax,old_batch_block        ; was before INT 2Eh
  373.     mov word ptr es:[bx],ax
  374.  
  375.     cmp version,version_three_zero
  376.     jae rbs_3x 
  377.  
  378.     mov ax,word ptr old_batch_fileptr  ;If version 2.x we also have to 
  379.     mov word ptr es:[bx+2],ax    ; restore the file pointer.
  380.     mov ax,word ptr old_batch_fileptr+2
  381.     mov word ptr es:[bx+4],ax
  382.     ret
  383.  
  384. rbs_3x:
  385.     cmp version,version_three_three
  386.     jb rbs1
  387.                     ;If 3.3+ we also have to restore the
  388.     mov ax,old_batch_counter    ; batch counter.
  389.     mov word ptr es:[di].batch_counter3_3,ax
  390.     
  391. rbs1: ret
  392.  
  393. restore_batch_state endp
  394.  
  395. ;-------------------------------------------------------------------------------
  396. ;Reset_for resets the for flag and (in versions 3.0+) the pointer to the for
  397. ;processing block.  Call with ES = COMMAND'S segment.
  398. ;-------------------------------------------------------------------------------
  399. reset_for proc near
  400.     mov al,byte ptr old_for_flag
  401.     mov bx,for_flag_address
  402.     mov byte ptr es:[bx],al
  403.     cmp version,version_three_zero    ;No for block in ver. 2.x
  404.     jge rf1
  405.     ret
  406.  
  407. rf1:     mov ax,old_for_block
  408.     mov word ptr es:[bx+1],ax
  409.     ret
  410. reset_for endp
  411.  
  412. ;-------------------------------------------------------------------------------
  413. ;Restore_previous_2e restores COMMAND'S info on previous 2Eh caller.  This
  414. ;allows COMMAND.COM to return control to previous caller on our exit. Call with
  415. ;ES:DI = seg:offset of COMMAND'S data area.
  416. ;-------------------------------------------------------------------------------
  417. restore_previous_2e proc near
  418.     mov ax,previous_2e_psp        ;Reset COMMAND 2eh info on caller's psp    
  419.     mov es:[di].twoe_caller_psp,ax
  420.     mov ax,previous_2e_ip
  421.     mov es:[di].twoe_caller_ip,ax    ;Reset COMMAND 2eh info on caller's ip
  422.     mov ax,previous_2e_cs
  423.     mov es:[di].twoe_caller_cs,ax    ;Reset COMMAND 2eh info on caller's cs
  424.     mov bx,twoE_flagoffset        ;Restore COMMAND 2eh flag.
  425.     mov ax,previous_2e_flag
  426.     mov word ptr es:[bx],ax
  427.     ret
  428. restore_previous_2e endp
  429.  
  430. ;-------------------------------------------------------------------------------
  431. ;Reset_echo_flag restores COMMAND's echo flag (2.1 - 3.2). to what it was 
  432. ;prior to INT 2Eh.  Call with ES:DI = seg:offset of COMMAND'S data area.
  433. ;-------------------------------------------------------------------------------
  434. reset_echo_flag proc near
  435.     cmp version,version_three_three
  436.     jge ref2
  437.     mov al,byte ptr old_echo_flag
  438.     cmp version,version_three_two 
  439.     jge ref_3_2 
  440.     cmp version,version_three_zero
  441.     jge ref_3_0
  442.  
  443. ;version 2 - restore echo to what it was prior to xcall:
  444.     mov byte ptr es:[di].echo_flag2,al
  445.     ret
  446.  
  447. ref_3_0:                    ;(For 3.0 & 3.1)
  448.     mov byte ptr es:[di].echo_flag3_0,al
  449.     ret
  450.  
  451. ref_3_2:
  452.     mov byte ptr es:[di].echo_flag3_2,al
  453.  
  454. ref2:
  455.     ret
  456. reset_echo_flag endp
  457.  
  458.  
  459. even
  460. stack_space        db  64 dup  (?)
  461. endhere            label byte    
  462.  
  463. ;==============================================================================
  464. ;ERROR ROUTINES
  465. error1mes        db "Requires DOS 2.1 or later.",0dh,0ah,"$"
  466. error2mes        db "Error: Interrupt 2Eh vector has been "
  467.             db "altered.",0dh,0ah,"$"
  468. error1:
  469.     mov dx,offset error1mes 
  470.     mov ah,09h 
  471.     int 21h 
  472.     int 20h
  473.  
  474. error2:
  475.     mov dx,offset error2mes 
  476.     mov ah,09h
  477.     int 21h
  478.  
  479.     mov ah,4ch            ;Terminate.
  480.     int 21h 
  481.  
  482.  
  483. ;==============================================================================
  484.  
  485. start label near 
  486.  
  487.     mov ah,30h            ;Get version.
  488.     int 21h
  489.     xchg ah,al
  490.     cmp ax,version_two_one         ;Exit if not 2.1 or later.
  491.     jb error1 
  492.  
  493.     mov version,ax
  494.  
  495.     call check_vector        ;Get 2eh vector - points to COMMAND?
  496.     jc error2            ;If not, exit.
  497.  
  498.     mov di,es:[bx+3]        ;Int 2eh vector offset + 3 = address 
  499.                     ; of COMMAND's data area.
  500.                     ;es:di now = COMMAND'S data area.
  501.  
  502.     call check_command_string    ;Check for redirection.
  503.     call save_previous_2eh        ;Check if another 2eh in progress    
  504.     call save_batch_state        ;Check if batch file in progress
  505.     call save_echo_state        ;Save contents of echo flag
  506.     call save_for_state        ;Check if for loop in progress
  507.  
  508.     mov si,80h            ;Point si to command string.
  509.  
  510.     mov sp,offset endhere        ;Move stack to safe area so we can
  511.                     ; reduce memory allocation.
  512.  
  513.     push es                ;Save COMMAND's segment
  514.     mov ax,cs            ;Set up to reduce memory allocation
  515.     mov es,ax
  516.     mov ah,04ah 
  517.     mov bx,(offset endhere-(offset begin-100h)+15)/16
  518.     jmp reduce_memory
  519.  
  520. ;===============================================================================
  521.  
  522. ;------------------------------------------------------------------------------
  523. ;Check_vector determines if the int 2Eh vector points to COMMAND.COM. If so, it
  524. ;returns ES:BX pointing to segment:offset of 2Eh handler, otherwise it sets 
  525. ;the carry flag.
  526. ;-------------------------------------------------------------------------------
  527. check_vector proc near
  528.     xor ax,ax            ;Get interrupt 2eh vector.
  529.     mov es,ax 
  530.     mov bx,2eh * 4
  531.     les bx,es:[bx]             ;es:bx = segment:offset.
  532.  
  533.     mov ax,es            ;Does 2eh vector point to COMMAND.COM?
  534.     cmp word ptr es:[owner_id],ax    ;  (COMMAND.COM owns itself.)
  535.     jz cv1
  536.     stc                ;If not, set carry.
  537.     ret
  538. cv1:     clc
  539.     ret
  540. check_vector endp
  541.  
  542. ;-------------------------------------------------------------------------------;Check_command_string removes first & last quotation marks from command
  543. ;string.  This lets xcall pass redirection request to COMMAND.COM. This
  544. ;routine saves DI & ES.
  545. ;-------------------------------------------------------------------------------
  546. check_command_string proc near        
  547.     push di
  548.     push es
  549.     mov ax,ds
  550.     mov es,ax
  551.  
  552.     xor ch,ch
  553.     mov cl,byte ptr ds:[080h]    ;Length of command tail stored at 80h
  554.     jcxz end_check            ;All done if no command tail
  555.     cld                ;Check for first quotation mark -
  556.     mov al,'"'            ; replace with null (20h) if present.
  557.     mov di,82h            ;Command tail starts at 82h.
  558.     repne scasb
  559.     jnz end_check
  560.     mov byte ptr [di-1],20h
  561.             
  562.     std                ;Change direction & check for
  563.     add di,cx            ; last quotation mark.
  564.     dec di
  565.     dec di
  566.     repne scasb
  567.     cld 
  568.     jnz end_check
  569.     mov byte ptr [di+1],20h
  570.  
  571. end_check:
  572.     pop es
  573.     pop di
  574.     ret
  575. check_command_string endp
  576.  
  577. ;------------------------------------------------------------------------------
  578. ;This routine determines if an Int 2Eh is already in progress and, if so,
  579. ;saves the offset and contents of COMMAND.COM's 2Eh flag and address 
  580. ;information on previous 2Eh caller.  If an int 2Eh is not in progress a flag 
  581. ;("first") is set to indicate this. Call with ES=COMMAND.COM segment and
  582. ;DI = offset of COMMAND's data area.
  583. ;------------------------------------------------------------------------------
  584. save_previous_2eh proc near
  585.     mov bx,es:[bx+27h]            ;Offset for Int 2eh vector + 27h =
  586.     cmp word ptr es:[bx],0000h    ; address of COMMAND's 2eh flag.  
  587.     jz sp1                ;Is it set?
  588.     mov ax,es:[bx]
  589.  
  590.     mov twoe_flagoffset,bx        ;Save address of 2eh flag.
  591.     mov previous_2e_flag,ax        ;Save contents of 2eh flag.
  592.     mov ax,es:[di].twoe_caller_psp    ;Save previous 2eh caller's psp.
  593.     mov previous_2e_psp,ax         
  594.     mov ax,es:[di].twoe_caller_ip    ;Save previous 2eh caller's ip.
  595.     mov previous_2e_ip,ax        
  596.     mov ax,es:[di].twoe_caller_cs    ;Save previous 2eh caller's cs.
  597.     mov previous_2e_cs,ax    
  598.     ret
  599.  
  600. sp1:    mov first,01            ;No, we are first 2eh caller.
  601.     ret
  602. save_previous_2eh endp
  603.  
  604. ;------------------------------------------------------------------------------
  605. ;Save_batch_state determines if a batch file is in progress and, if so,
  606. ;saves the offset and contents of COMMAND's batch file data block pointer.
  607. ;The pointer is then set to zero. Call with ES = COMMAND.COM segment &
  608. ;DI = offset of COMMAND's data area.
  609. ;------------------------------------------------------------------------------
  610. save_batch_state proc near
  611.     cmp version,version_three_zero
  612.     jae sbs1 
  613.  
  614. ;For 2.10 & 2.11:
  615.     mov bx,offset batch_block_pointer2  ;Save address of batch pointer
  616.     add bx,di
  617.     mov batch_ptr_address,bx
  618.                     ;Is a batch process pending?
  619.     cmp word ptr es:[bx],0000h
  620.     jz sbs_end
  621.     mov ax,word ptr es:[bx]
  622.     mov old_batch_block,ax        ;Save current batch pointer.
  623.     mov word ptr es:[bx],0000h    ;Zero block pointer.
  624.     mov ax,word ptr es:[di].batch_fileptr    ;Save batch fileptr.
  625.     mov word ptr old_batch_fileptr,ax
  626.     mov ax,word ptr es:[di].batch_fileptr+2
  627.     mov word ptr old_batch_fileptr+2,ax
  628.     mov word ptr es:[di].batch_fileptr,0000h  ;Zero batch fileptr.
  629.     mov word ptr es:[di].batch_fileptr+2,0000h 
  630.     ret
  631.  
  632. ;for version 3 and later:
  633. sbs1:        
  634.     mov bx,offset batch_block_pointer3  ;Save offset of batch pointer
  635.     add bx,di
  636.     mov batch_ptr_address,bx
  637.     cmp word ptr es:[bx],0000h    ;Batch process pending?
  638.     jz sbs_end
  639.     mov ax,es:[bx]    
  640.     mov old_batch_block,ax        ;Save current batch pointer.
  641.     mov word ptr es:[bx],0000h    ;Reset COMMAND's batch pointer.
  642.  
  643.     cmp version,version_three_three    ;If 3.3+ save "call" counter.
  644.     jb sbs_end 
  645.         
  646.     mov ax,word ptr es:[di].batch_counter3_3
  647.     mov old_batch_counter,ax
  648.                     ;Zero batch call counter.
  649.     mov word ptr es:[di].batch_counter3_3,0000h 
  650.  
  651. sbs_end:
  652.     ret
  653. save_batch_state endp
  654.  
  655.  
  656. ;------------------------------------------------------------------------------
  657. ;Save_echo_state saves the echo flag for versions 2.1 - 3.2. 
  658. ;Call with ES = COMMAND.COM segment & DI = offset of COMMAND's data area.
  659. ;------------------------------------------------------------------------------
  660. save_echo_state proc near
  661.     cmp version,version_three_three
  662.     jge ses4  
  663.     cmp version,version_three_two
  664.     jge ses2
  665.     cmp version,version_three_zero
  666.     jge ses1
  667.  
  668. ;for version 2.x:
  669.     mov cl,byte ptr es:[di].echo_flag2
  670.     jmp ses3
  671.  
  672. ses1:                    ;for 3.0 & 3.1
  673.     mov cl,byte ptr es:[di].echo_flag3_0
  674.     jmp ses3
  675.  
  676. ses2:                    ;for 3.2
  677.     mov cl,byte ptr es:[di].echo_flag3_2
  678.  
  679. ses3: 
  680.     mov old_echo_flag,cl
  681.  
  682. ses4:
  683.     ret
  684. save_echo_state endp
  685.  
  686. ;------------------------------------------------------------------------------
  687. ;Save_for_state saves the offset address of COMMAND's "for" block, checks if a 
  688. ;"for" loop is being executed and, if so, saves and then clears the for flag
  689. ;and the pointer to the for process block. Call with ES=COMMAND.COM segment
  690. ;and DI=offset of COMMAND's data area.
  691. ;------------------------------------------------------------------------------
  692.  
  693. save_for_state proc near
  694.     cmp version,version_four_zero
  695.     jge sf_4_0
  696.     cmp version,version_three_three
  697.     jge sf_3_3
  698.     cmp version,version_three_two
  699.     jge sf_3_2
  700.     cmp version,version_three_zero
  701.     jge sf_3_0
  702.     jmp sf_2_1    
  703.  
  704. sf_4_0:                    ;4.0 & 4.01 
  705.     mov ax,offset for_flag4_0    ;Get offset of for flag.
  706.     add ax,di
  707.     mov for_flag_address,ax
  708.  
  709.     mov cl,es:[di].for_flag4_0    ;Get contents of for flag.
  710.     cmp cl,00            ;If 0 then no for loop in progress.
  711.     jz sf2    
  712.     mov ax,es:[di].for_block_pointer4_0    ;Get for data block pointer.
  713.  
  714.     mov byte ptr es:[di].for_flag4_0,00h    ;Clear for flag & block pointer.
  715.     mov word ptr es:[di].for_block_pointer4_0,0000h
  716.  
  717. sf1:
  718.     mov old_for_flag,cl        ;Save for flag.
  719.     mov old_for_block,ax        ;Save for block.  
  720. sf2:    ret
  721.  
  722. sf_3_3:                    ;3.3 
  723.     mov ax,offset for_flag3_3    ;Get offset of for flag.
  724.     add ax,di
  725.     mov for_flag_address,ax
  726.  
  727.     mov cl,es:[di].for_flag3_3    ;Get contents of for flag.
  728.     cmp cl,00            ;If 0 then no for loop in progress.
  729.     jz sf2
  730.     mov ax,es:[di].for_block_pointer3_3    ;Get for data block pointer.
  731.  
  732.     mov byte ptr es:[di].for_flag3_3,00h    ;Clear for flag & block pointer
  733.     mov word ptr es:[di].for_block_pointer3_3,0000h
  734.     jmp sf1
  735.  
  736. sf_3_2:                    ;3.2
  737.     mov ax,offset for_flag3_2    ;Get offset of for flag.
  738.     add ax,di
  739.     mov for_flag_address,ax
  740.  
  741.     mov cl,es:[di].for_flag3_2    ;Get contents of for flag.
  742.     cmp cl,00h            ;If 0 then no for loop in progress.
  743.     jz sf2
  744.     mov ax,es:[di].for_block_pointer3_2    ;Get for data block pointer.
  745.  
  746.     mov byte ptr es:[di].for_flag3_2,00h    ;Clear for flag & block pointer.
  747.     mov word ptr es:[di].for_block_pointer3_2,0000h
  748.     jmp sf1
  749.  
  750. sf_3_0:                    ;3.0 & 3.1
  751.     mov ax,offset for_flag3_0    ;Get offset of for flag.
  752.     add ax,di
  753.     mov for_flag_address,ax
  754.     
  755.     mov cl,es:[di].for_flag3_0    ;Get contents of for flag
  756.     cmp cl,00h            ;If 0 then no for loop in
  757.     jz sf2
  758.     mov ax,es:[di].for_block_pointer3_0    ;Get for data block pointer.
  759.     
  760.     mov byte ptr es:[di].for_flag3_0,00h    ;Clear for flag & block pointer.
  761.     mov word ptr es:[di].for_block_pointer3_0,0000h
  762.     jmp sf1
  763.  
  764. sf_2_1:                    ;2.1 & 2.11
  765.     mov ax,offset for_flag2        ;Get offset of for flag.
  766.     add ax,di
  767.     mov for_flag_address,ax
  768.  
  769.     mov cl,es:[di].for_flag2    ;Get contents of for flag.
  770.     cmp cl,00h            ;If 0 then no for loop in progress.
  771.     jz sf2
  772.  
  773.     mov byte ptr es:[di].for_flag2,00h    ;Clear the for flag
  774.     xor ax,ax                ;No for data blk in ver 2.x.
  775.     jmp sf1
  776. save_for_state endp
  777.  
  778. code ends
  779.     end begin
  780.     END
  781.