home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol12n22.zip / QPATH.ZIP / QPATH.ASM next >
Assembly Source File  |  1993-11-24  |  33KB  |  1,175 lines

  1.         page    66,132
  2. ;====================================================================
  3. ; QPATH.COM Looks for a program on an extra path string before 
  4. ; COMMAND.COM makes its standard search
  5. ;
  6. ;    QPATH [/E] [/D] [/U] [/X cmd,cmd,cmd]
  7. ;             
  8. ;
  9. ; where /U = Uninstall the program
  10. ;       /E = Enable extra path search
  11. ;       /D = Disable extra path search
  12. ;       /X = Spefify commands to disable
  13. ;
  14. ;====================================================================
  15. BUFFSIZE    equ    130
  16. DTASIZE        equ    2Ch
  17. QPATHSIZE    equ    offset qpathname_end - offset qpathname
  18. PATHSIZE    equ    offset pathname_end - offset pathname
  19.  
  20. REG_AL        equ    byte ptr ss:[bp+10h]
  21.  
  22. DTAPTR        equ    offset end_of_resident
  23. BUFFOFFSET    equ    DTAPTR + DTASIZE
  24. ENDOFBUFF    equ    BUFFOFFSET + BUFFSIZE
  25.  
  26. MUXINSTCHK    equ    0
  27. MUXENABLE    equ    1
  28. MUXDISABLE    equ    2
  29. MUXQUERY    equ    3
  30.         code    segment
  31.         assume    cs:code
  32.  
  33.         org    2ch
  34. env_segment    dw    ?            ;Word containing the segment
  35.                         ;  of the program's env. block.
  36.         org    80h
  37. command_tail    db    ?            ;Offset of the command tail.
  38.  
  39.         org    100h
  40.  
  41. begin:        jmp    initialize
  42. program        db    13,10,"QPATH 1.0 "
  43. copyright    db    "Copyright (c) 1993 Douglas Boling",10,13
  44. author        db    "First Published in PC Magazine Dec 7, 1993"
  45.         db    10,10,13,"$",1Ah
  46. endtag        =    $
  47. int21h        dd    -1            ;Int 21 vector (DOS Dispatch)
  48. int2fh        dd    -1            ;Int 2f vector (DOS Multiplex)
  49. xms_service    dd    -1            ;Entry pt to XMS driver
  50.  
  51. dos_version    dw    0            ;DOS Version number
  52. xms_flag      db    0            ;XMS driver present flag
  53. chk_path      db    1            ;Enable flag.
  54. main_active    db    0            ;Active flag
  55. multiplex_id    db    0dbh            ;Program ID for multiplex int
  56. api_tbl        dw    offset inst_chk        ;Jump table for app mux
  57.         dw    offset appenable    ;  interrupt functions.
  58.         dw    offset appdisable
  59.         dw    offset enablequery
  60. api_tblend     =    $
  61. qpathname    db    "QPATH="        ;QPATH env var name
  62. qpathname_end    =    $
  63. pathname    db    "PATH="            ;PATH env var name
  64. pathname_end    =    $
  65.         db    ';'            ;Needed for name sub
  66. pathptr        dd    ?
  67. qpathptr    dd    ?
  68. ;
  69. ;DOS state variables
  70. ;
  71. ret_addr    dw    0            ;Value used by Save Regs routine
  72. A20_state    dw    0            ;State of A20 flag
  73. saved_dta       dd      0                       ;saved pointer to curr DTA
  74. saved_psp       dw      0                       ;saved segment of curr PSP
  75. buff_ptr    dd    0            ;Ptr to working buff
  76. exbuff_ptr    dw    0            ;Ptr to exclude buffer
  77. command_ptr    dd    0            ;Ptr to cmd.com command
  78. intcmd_ptr    dd    0            ;Ptr to formatted cmd
  79.  
  80. int1bh        dd    -1            ;Int 1b vector (Break)
  81. int23h        dd    -1            ;Int 23 vector (Ctrl C)
  82. int24h        dd    -1            ;Int 24 vector (Crit Error)
  83.  
  84. errinfoarray:
  85. errAX           dw      0                       ;Saved extended error info
  86. errBX           dw      0
  87. errCX           dw      0
  88. errDX           dw      0
  89. errSI           dw      0
  90. errDI           dw      0
  91. errDS           dw      0
  92. errES           dw      0
  93.             dw      3 dup (0)               ;Reserved error table bytes
  94.  
  95. exts        db    ".BAT.EXE.COM",0
  96. extflag        db    0            ;Extension specified
  97. goflag        db    0            ;Prog found flag
  98. disablecmd    db    0            ;Disable cmd flag
  99.  
  100. ;====================================================================
  101. ; DOSINT processes calls to interrupt 21h
  102. ; Entry: AH - DOS function
  103. ;====================================================================
  104. dosint        proc    far
  105.         assume    cs:code,ds:nothing,es:nothing
  106.  
  107.         cmp    cs:goflag,0        ;See if we need to 
  108.         jne    dosint_1        ;  fool cmd.com
  109. goto_dosint:
  110.         jmp    cs:[int21h]             ;else pass the call on
  111. dosint_1:
  112.         cmp    ah,4bh            ;EXEC
  113.         je    dos_exec
  114.         cmp    ah,48h            ;Alloc Mem
  115.         je    dos_exec
  116.         cmp    ah,4eh            ;Find First
  117.         je    dos_ff
  118.         jmp    short goto_dosint
  119. dos_exec:
  120.         mov    cs:goflag,0        ;Stop fooling program
  121.         push    es
  122.         push    di
  123.         push    ds
  124.         push    si
  125.         mov    si,cs            ;Copy QPATH back over
  126.         mov    ds,si            ;  PATH=;
  127.         mov    si,offset qpathname
  128.         les    di,cs:qpathptr
  129.         movsw
  130.         movsw
  131.         movsw
  132.         lds    si,cs:pathptr
  133.         mov    di,ds            ;Validate path ptr
  134.         or    di,di
  135.         je    dos_exec1
  136.         mov    byte ptr [si],'P'    ;Restore PATH= from ~ATH=
  137. dos_exec1:
  138.         pop    si
  139.         pop    ds
  140.         pop    di
  141.         pop    es
  142.         jmp    cs:[int21h]             ;Pass the call on
  143. dos_ff:
  144.         dec    cs:goflag
  145.         cmp    cs:goflag,-2
  146.         je    dos_ff1
  147.         jmp    cs:[int21h]             ;Pass the call on
  148. dos_ff1:
  149.         push    bp
  150.         mov    bp,sp
  151.         or    word ptr ss:[bp+6],1    ;Set carry flag
  152.         pop    bp
  153.         mov    ax,12h            ;No more files
  154.         iret        
  155. dosint        endp
  156. ;====================================================================
  157. ; MUXINT processes calls to interrupt 2Fh
  158. ; Entry: AH - Device ID
  159. ;        AL - Command
  160. ;====================================================================
  161. muxint        proc    far
  162.         assume    cs:code,ds:nothing,es:nothing
  163.  
  164.         cmp    ah,0AEh            ;Command.com cmd hook
  165.         je    cmd_chk
  166.  
  167.         cmp    ah,cs:[multiplex_id]    ;Check for program ID
  168.         je    muxint_myapi        ;Its us, chk our cmds
  169. goto_muxint:
  170.         jmp    cs:[int2fh]             ;else pass the call on
  171. cmd_chk:
  172.         cmp    dx,-1            ;See if really cmd hook
  173.         jne    goto_muxint
  174.         or    al,al            ;See if chk or launch
  175.         jne    cmd_launch
  176.         call    main            ;Check cmd
  177.         cmp    cs:goflag,0
  178.         je    goto_muxint
  179.         iret
  180. cmd_launch:
  181.         cmp    cs:[disablecmd],0    ;See if disable cmd set
  182.         mov    cs:[disablecmd],0    ;Clear disable cmd flag
  183.         je    goto_muxint
  184.         mov    byte ptr ds:[si],0    ;Zero cmd length byte
  185.         iret
  186. muxint_myapi:
  187.         cmp    al,(offset api_tblend - offset api_tbl) shr 1
  188.         jae    muxint_iret
  189.         push    bx
  190.         mov    bl,al
  191.         xor    bh,bh
  192.         shl    bx,1
  193.         mov    ax,cs:[bx+offset api_tbl]
  194.         pop    bx
  195.         call    ax
  196. muxint_iret:
  197.         iret
  198. muxint        endp
  199. ;--------------------------------------------------------------------
  200. ;QPATH multiplex functions        
  201. ;--------------------------------------------------------------------
  202. my2fapi        proc    near
  203. inst_chk:
  204.         mov    ax,-1            ;Indicate QPATH installed
  205.         push    cs            ;ES = installed code segment
  206.         pop    es
  207.         ret
  208. appenable:
  209.         mov    cs:chk_path,1        ;Set enable flag
  210.         jmp    short enablequery
  211. appdisable:
  212.         mov    cs:chk_path,0        ;Clear enable flag
  213. enablequery:
  214.         xor    dx,dx
  215.         mov    dl,cs:chk_path        ;Get enable flag state
  216.         xor    ax,ax
  217.         ret
  218. my2fapi        endp
  219. ;====================================================================
  220. ; CRITICALERR receives control when an interrupt 24h is generated.
  221. ;====================================================================
  222. criterrint    proc    far
  223.         assume    cs:code,ds:nothing,es:nothing
  224.         mov    al,3            ;Set to Fail
  225. criterr_iret:
  226.         iret
  227. criterrint    endp
  228. ;--------------------------------------------------------------------
  229. ; MAIN - Saves regs, calls chk disable and chk path
  230. ;--------------------------------------------------------------------
  231. main        proc    near
  232.         assume    cs:code,ds:nothing,es:nothing
  233.         inc    cs:main_active        ;Check to see if active
  234.         jnz    main_exit
  235.         cmp    cs:chk_path,0        ;See if disabled
  236.         je    main_exit
  237. ;Save regs and critical pointers 
  238.         cld                ;Set string dir flag
  239.         mov    word ptr cs:[command_ptr],bx
  240.         mov    word ptr cs:[command_ptr+2],ds
  241.         mov    word ptr cs:[intcmd_ptr],si
  242.         mov    word ptr cs:[intcmd_ptr+2],ds
  243.         call    save_regs        ;Save register state
  244.         assume    ds:code
  245.  
  246.         call    chk_discmds        ;Check for disabled cmd
  247.         jc    main_restore        ;CF set, cmd disabled
  248.         cmp    goflag,0        ;See if already active
  249.         jne    main_restore
  250.         call    chkcmd            ;See if path specified
  251.         jc    main_restore
  252.         call    chkmypath        ;Check Quick path
  253. main_restore:
  254.         call    restore_regs        ;Restore register state
  255. main_exit:
  256.         dec    cs:main_active        
  257.         ret
  258. main        endp
  259.  
  260. ;--------------------------------------------------------------------
  261. ; CHK_DISCMDS - Checks list of disabled commands.
  262. ;--------------------------------------------------------------------
  263. chk_discmds    proc    near
  264.         assume    cs:code,ds:code
  265.         les    di,intcmd_ptr        ;Get ptr to formatted cmd
  266.         mov    si,exbuff_ptr        ;Get ptr to excluded cmds
  267.         xor    ax,ax
  268.         xor    cx,cx
  269.         mov    cl,es:[di]        ;Get length of cmd
  270.         inc    di
  271. chk_discmds_1:
  272.         lodsb                ;Get length of ex cmd
  273.         or    al,al
  274.         je    chk_discmds_exit
  275.         cmp    ax,cx            ;See if same length
  276.         jne    chk_discmds_2
  277.         push    si
  278.         push    di
  279.         repe    cmpsb
  280.         pop    di
  281.         pop    si
  282.         mov    cx,ax
  283.         je    chk_discmds_3
  284. chk_discmds_2:
  285.         add    si,ax            ;Point to next cmd
  286.         jmp    short chk_discmds_1
  287. chk_discmds_3:
  288.         mov    REG_AL,-1        ;Accept cmd
  289.         mov    cs:disablecmd,1        ;Set flag to catch next call
  290.         stc                ;Indicate cmd disabled
  291. chk_discmds_exit:
  292.         ret
  293. chk_discmds    endp
  294.  
  295. ;--------------------------------------------------------------------
  296. ; CHKMYPATH - searches list of directories for a file
  297. ;--------------------------------------------------------------------
  298. chkmypath    proc    near
  299.         assume    cs:code,ds:code
  300. ;Save necessary DOS state
  301.             cmp     xms_flag,0
  302.             je      skip_xms_save
  303.             mov     ah,7                    ;Get state of A20 line
  304.             call    [xms_service]
  305.             mov     A20_state,ax
  306. skip_xms_save:
  307. ;Point the interrupt 1Bh, 23h, and 24h vectors to internal handlers.
  308.         mov    al,1bh
  309.         mov    di,offset int1bh
  310.         mov    dx,offset criterr_iret
  311.         call    getandsetint
  312.         
  313.         mov    al,23h
  314.         mov    di,offset int23h
  315.         mov    dx,offset criterr_iret
  316.         call    getandsetint
  317.         
  318.         mov    al,24h
  319.         mov    di,offset int24h
  320.         mov    dx,offset criterrint
  321.         call    getandsetint
  322. ;Save extended error information
  323.             push    ds                      ;save DS
  324.             mov    ah,59h                  ;Extended error info
  325.             int    21h                     ;Call DOS
  326.             mov    cs:[errDS],ds           ;save returned DS
  327.             pop    ds                      ;Restore DS
  328.             push    bx
  329.             mov    bx,offset errinfoarray  ;Save data in registers
  330.             mov    [bx],ax                 ;  in this specific order.
  331.             pop    [bx+2]
  332.             mov    [bx+4],cx
  333.             mov    [bx+6],dx
  334.             mov    [bx+8],si
  335.             mov    [bx+10],di
  336.         mov    [bx+14],es
  337.         
  338. ;Save active PSP and DTA, then switch to my PSP and DTA
  339.         mov     ah,51h                  ;Get current PSP
  340.             int    21h
  341.             mov     saved_psp,bx            ;save it
  342.  
  343.         mov     ah,2fh
  344.             int     21h            ;Get current DTA
  345.             mov     word ptr saved_dta,bx    ;save it
  346.             mov     word ptr saved_dta+2,es
  347.         mov     dx,DTAPTR        ;Set DTA
  348.             push    cs
  349.             pop     bx            ;Set active PSP to us
  350.         call    setpspdta
  351. ;Do the work        
  352.         call    srchpath        ;Look for file
  353.         push    ax            ;Save found flag
  354.         or    al,al            
  355.         jne    chkmypath_2
  356.         mov    si,offset pathname    ;If program found in
  357.         mov    cx,PATHSIZE        ;  qpath, fake out
  358.         mov    word ptr [pathptr+2],0    ;  COMMAND.COM by subbing
  359.         call    getevar            ;  the QPATH for the PATH
  360.         cmp    byte ptr es:[di],0    ;  in the environment.
  361.         je    chkmypath_1
  362.         sub    di,PATHSIZE
  363.         mov    word ptr [pathptr],di    ;Save ptr to PATH var
  364.         mov    word ptr [pathptr+2],es ; in the environment.
  365.         mov    byte ptr es:[di],'~'    ;Change PATH= to ~ATH=
  366. chkmypath_1:
  367.         call    getqpath        
  368.         sub    di,QPATHSIZE        
  369.         mov    word ptr [qpathptr],di    
  370.         mov    word ptr [qpathptr+2],es
  371.         mov    si,offset pathname
  372.         movsw                ;Copy PATH=; over QPATH=
  373.         movsw
  374.         movsw
  375. chkmypath_2:
  376. ;Restore DOS state, start with DTA and PSP
  377.             push    ds
  378.             mov     bx,saved_psp            ;Get old PSP
  379.             lds     dx,saved_dta        ;Get old DTA
  380.             call    setpspdta        ;Set old PSP and DTA
  381.         pop    ds
  382.  
  383.             mov    ax,5d0ah                ;Restore ext error info
  384.             mov    dx,offset errinfoarray  ;point to Saved info
  385.             int    21h
  386.         
  387.             push    ds
  388.             mov    ax,2524h        ;Restore crit err int
  389.         lds    dx,int24h
  390.             int    21h
  391.             mov    ax,2523h        ;Restore ctl C int
  392.         lds    dx,int23h
  393.             int    21h
  394.             mov    ax,251bh        ;Restore break int
  395.         lds    dx,int1bh
  396.             int    21h        
  397.         pop    ds
  398.  
  399.         cmp    xms_flag,0        ;See if XMS driver present
  400.         je     skip_xmsrestore
  401.         mov    ah,5                    ;Assume local disable A20
  402.         cmp    A20_state,0
  403.         je     xms_restore_1
  404.         inc    ah                      ;Change to local enable A20
  405. xms_restore_1:
  406.         call    [xms_service]           ;Restore A20 line state
  407. skip_xmsrestore:
  408.         pop    ax
  409.         not    al
  410.         mov    goflag,al        ;Save found flag
  411. chkmypath_exit:
  412.         ret
  413. chkmypath    endp
  414. ;--------------------------------------------------------------------
  415. ; SRCHPATH - searches list of directories for a file
  416. ; Exit: AL = 0 if file found
  417. ;--------------------------------------------------------------------
  418. pathdirptr    equ    dword ptr ss:[bp-4]
  419. pathdiroff    equ    word ptr ss:[bp-4]
  420. pathdirseg    equ    word ptr ss:[bp-2]
  421. srchpath    proc    near
  422.         assume    cs:code,ds:code
  423.         push    bp
  424.         push    ds
  425.         mov    bp,sp
  426.         sub    sp,4
  427.         call    getqpath        ;Get ptr to QPATH data
  428. srchpath_1:
  429.         mov    pathdiroff,di        ;Save ptr to path dir
  430.         mov    pathdirseg,es
  431.         les    di,buff_ptr        ;Get ptr to work buff
  432.         lds    si,pathdirptr        ;Get ptr to curr path dir
  433.         assume    ds:nothing
  434.         mov    al,-1
  435.         cmp    byte ptr [si],0        ;See if end of path str
  436.         je    srchpath_exit
  437.         mov    ax,3b00h        ;Copy up to ';'
  438.         call    copystr            ;Copy path directory
  439.         cmp    byte ptr es:[di-1],'\'    ;See if term \
  440.         je    srchpath_2
  441.         mov    al,'\'
  442.         stosb                ;Append \
  443. srchpath_2:
  444.         lds    si,cs:[command_ptr]    ;Get ptr to filename
  445.         lodsw                ;Skip past size bytes
  446.         mov    ax,0d01h
  447.         call    copystr            ;Append to path
  448.         push    cs
  449.         pop    ds
  450.         assume    ds:code
  451.         call    findprog        ;See if prog name in dir
  452.         jnc    srchpath_exit        ;File found, exit
  453.         les    di,pathdirptr        ;Find next dir in
  454.  
  455.         mov    ah,';'            ;  the path.
  456.         call    findchar
  457.         jmp    short srchpath_1
  458. srchpath_exit:
  459.         mov    sp,bp
  460.         pop    ds
  461.         pop    bp
  462.         ret
  463. srchpath    endp
  464. ;--------------------------------------------------------------------
  465. ; FINDPROG - searches a directory for a COM EXE or BAT file.
  466. ; Entry: Program name loaded in working buffer.
  467. ;        ES:DI pointing to end of filename.
  468. ; Exit:  AL = 0 if file found
  469. ;--------------------------------------------------------------------
  470. findprog    proc    near
  471.         assume    cs:code,ds:code,es:code
  472.         push    bp
  473.         mov    bp,di
  474.         cmp    extflag,0        ;See if extension needed
  475.         jne    findprog_1
  476.         mov    ax,'*.'            ;Append .*
  477.         stosw
  478. findprog_1:
  479.         xor    ax,ax            ;Terminate filename with 0
  480.         stosb
  481.         
  482.         lds    dx,buff_ptr         ;DS:DX ptr to filename
  483.         mov    cx,7            ;Look for all kinds of files
  484.         mov    ah,4Eh            ;Find first file
  485.         int    21h
  486.         jc    findprog_exit
  487.         cmp    extflag,0        ;See if ext specified
  488.         jne    findprog_6
  489.         xor    cx,cx            ;Clear file found flag
  490. findprog_2:
  491.         mov    si,offset exts
  492.         mov    di,DTAPTR+1Eh        ;Point to found extension
  493.         mov    ah,'.'
  494.         call    findchar
  495.         dec    di
  496. findprog_21:
  497.         push    di
  498.         mov    bx,si            ;File found, compare extension
  499.         cmpsw                ;  found to allowable prog
  500.         jne    findprog_3        ;  extensions: COM EXE BAT.
  501.         cmpsw
  502. findprog_3:
  503.         pop    di
  504.         je    findprog_4        ;Found ext, cmp to last found.
  505.         mov    si,bx
  506.         add    si,4
  507.         cmp    byte ptr [si],0
  508.         jne    findprog_21
  509.         jmp    short findprog_41    ;If no more exts, search again.
  510. findprog_4:
  511.         cmp    cx,bx            ;See if higher priority than
  512.         ja    findprog_41        ;  prev found prog extension.
  513.         mov    cx,bx
  514. findprog_41:
  515.         mov    ah,4fh            ;Find Next file
  516.         int    21h
  517.         jnc    findprog_2
  518. findprog_5:
  519.         or    cx,cx            ;See if no prog files found.
  520.         stc
  521.         je    findprog_exit
  522.         mov    si,cx
  523.         mov    di,bp            ;Get ptr to end of filename
  524.         movsw                ;Append found extension.
  525.         movsw
  526.         xor    ax,ax            ;Set found flag and 
  527.         stosb                ;  zero terminate filename
  528. findprog_6:
  529.         clc
  530. findprog_exit:
  531.         pop    bp
  532.         ret
  533. findprog    endp
  534. ;--------------------------------------------------------------------
  535. ; GETQPATH - Returns a pointer to the QPATH env var
  536. ; Exit:  ES:DI Ptr to QPATH var data
  537. ;--------------------------------------------------------------------
  538. getqpath    proc    near
  539.         assume    cs:code,ds:code
  540.         mov    si,offset qpathname
  541.         mov    cx,QPATHSIZE
  542.         call    getevar
  543.         ret
  544. getqpath    endp
  545. ;--------------------------------------------------------------------
  546. ; GETEVAR - Returns a pointer to an envrironment variable
  547. ; Entry:  DS:SI Ptr to variable name
  548. ;            CX Length of variable name
  549. ; Exit:   ES:DI Ptr to variable data
  550. ;--------------------------------------------------------------------
  551. getevar        proc    near
  552.         assume    cs:code,ds:code
  553.         mov    es,saved_psp        ;Get Command.com seg
  554.         mov    es,es:[env_segment]    ;Get env seg
  555.         xor    di,di
  556. getevar_1:
  557.         push    si
  558.         push    cx
  559.         repe    cmpsb
  560.         pop    cx
  561.         pop    si
  562.         je    getevar_exit
  563.         xor    al,al            ;Find next env var
  564.         push    cx
  565.         mov    cx,200
  566.         repne    scasb
  567.         pop    cx
  568.         cmp    byte ptr es:[di],0    ;At end of env?
  569.         jne    getevar_1
  570. getevar_exit:
  571.         ret
  572. getevar        endp
  573. ;--------------------------------------------------------------------
  574. ; CHKCMD - Checks a command to see if includes a path spec
  575. ; Exit: CF - Set if path specified
  576. ;--------------------------------------------------------------------
  577. chkcmd        proc    near
  578.         assume    ds:nothing,es:nothing
  579.         mov    cs:extflag,0
  580.         push    ds
  581.         push    es
  582.         push    cs
  583.         pop    es
  584.         assume    es:code
  585.  
  586.         lds    si,command_ptr
  587.         cmp    byte ptr [si+3],':'    ;See if drive speced
  588.         je    chkcmd_error
  589.  
  590.         inc    si
  591.         xor    ch,ch
  592.         mov    cl,[si]            ;Get length of command
  593.         inc    si
  594. chkcmd_1:
  595.         lodsb
  596.         cmp    al,'\'
  597.         je    chkcmd_error
  598.         cmp    al,'.'            ;See if extension speced
  599.         jne    chkcmd_2
  600.         inc    cs:extflag
  601.         jmp    short chkcmd_3
  602. chkcmd_2:
  603.         call    isfilechar
  604.         jc    chkcmd_4
  605. chkcmd_3:
  606.         loop    chkcmd_1
  607. chkcmd_4:
  608.         clc
  609. chkcmd_exit:
  610.         pop    es
  611.         pop    ds
  612.         ret
  613. chkcmd_error:
  614.         stc
  615.         jmp    short chkcmd_exit
  616. chkcmd        endp
  617.  
  618. ;-----------------------------------------------------------------------------
  619. ; ISFILECHAR - Determines if a character is an allowable DOS filename char
  620. ; Entry:  AL - ASCII char to check
  621. ; Exit:   CF - Set if not an allowable filename char
  622. ;-----------------------------------------------------------------------------
  623. filechar_chars    db    "!#$%^&()-_{}~"        ;Valid filename chars
  624. filechar_endc    =    $
  625. isfilechar    proc near
  626.         assume    ds:nothing,es:code
  627.         push    cx
  628.         cmp    al,128            ;Check for graphics chars
  629.         jnc    isfilechar_exit
  630.         mov    cx,"09"            ;Check for numbers
  631.         call    inside
  632.         jnc    isfilechar_exit
  633.         push    ax
  634.         or    al,20h
  635.         mov    cx,"az"            ;Check for letters
  636.         call    inside
  637.         pop    ax
  638.         jnc    isfilechar_exit
  639.         push    di            ;Check for other chars
  640.         cld
  641.         mov    di,offset filechar_chars
  642.         mov    cx,offset filechar_endc - offset filechar_chars
  643.         repne    scasb
  644.         pop    di
  645.         je    isfilechar_exit
  646.         stc
  647. isfilechar_exit:
  648.         pop    cx
  649.         ret
  650. ;Simple routine to bounds check a character
  651. inside        proc    near
  652.         cmp    al,ch            ;See if char inside
  653.         jb    inside_exit        ;  char range indicated
  654.         cmp    cl,al            ;  by CL and CH
  655. inside_exit:
  656.         ret
  657. inside        endp
  658. isfilechar    endp
  659.  
  660. ;--------------------------------------------------------------------
  661. ; COPYSTR - Copies a string up to a character
  662. ; COPYNSTR - Copies a string (of N max bytes) up to a character
  663. ; Entry: DS:SI source string
  664. ;        ES:DI dest
  665. ;           AH Term char of string
  666. ;           AL If 1, copy only valid filename chars
  667. ; Exit:  DI,SI updated
  668. ;--------------------------------------------------------------------
  669. copystr        proc    near
  670.         push    bx
  671.         mov    bx,ax
  672. copystr_1:
  673.         lodsb
  674.         cmp    al,ah            ;See if end char
  675.         je    copystr_exit
  676.         or    al,al            ;See if end of string
  677.         je    copystr_exit
  678.         or    bl,bl
  679.         je    copystr_2
  680.         call    isfilechar        ;See if valid filename
  681.         jc    copystr_exit        ;  char
  682. copystr_2:
  683.         stosb
  684.         jmp    short copystr_1
  685. copystr_exit:
  686.         pop    bx
  687.         ret
  688. copystr        endp
  689. ;--------------------------------------------------------------------
  690. ; FINDCHAR - Scans an ASCIIZ string for a char
  691. ; Entry: ES:DI source string
  692. ;           AH search char
  693. ; Exit:     DI Points to char if found
  694. ;--------------------------------------------------------------------
  695. findchar    proc    near
  696.         mov    al,es:[di]
  697.         or    al,al
  698.         je    findchar_1
  699.         inc    di
  700.         cmp    al,ah
  701.         jne    findchar
  702. findchar_1:
  703.         ret
  704. findchar    endp
  705. ;--------------------------------------------------------------------
  706. ; GETANDSETINT - Gets and saves an interrupt then sets to new value
  707. ; Entry: AL - Interrupt number
  708. ;        DI - Ptr to dword save vector
  709. ;        DX - Offset of new routine
  710. ;--------------------------------------------------------------------
  711. getandsetint    proc    near
  712.         push    ax
  713.             mov    ah,35h            ;Get interrupt vector
  714.             int    21h
  715.             mov    word ptr [di],bx    ;Save old vector
  716.             mov    word ptr [di+2],es
  717.         pop    ax
  718.             mov    ah,25h            ;Set new vector
  719.             int    21h
  720.         ret
  721. getandsetint    endp        
  722. ;--------------------------------------------------------------------
  723. ; SETPSPDTA - Sets the Active PSP and current DTA
  724. ; Entry: BX - New PSP
  725. ;        DX - New DTA
  726. ;--------------------------------------------------------------------
  727. setpspdta    proc    near
  728.             mov     ah,50h                  ;Set internal PSP
  729.             int    21h
  730.             mov     dx,DTAPTR        ;use PSP for DTA
  731.             mov     ah,1ah            ;Set DTA
  732.             int     21h
  733.         ret
  734. setpspdta    endp
  735. ;--------------------------------------------------------------------
  736. ; SAVEREGS saves all the registers used in the interrupt routines and
  737. ; sets DS.
  738. ;--------------------------------------------------------------------
  739. save_regs       proc    near
  740.             pop     cs:[ret_addr]           ;Get address to return
  741.             push    ax                      ;save all registers
  742.             push    bx
  743.             push    cx
  744.             push    dx
  745.             push    bp
  746.             push    si
  747.             push    di
  748.             push    ds
  749.             push    es
  750.         mov    bp,sp            ;Set bp to stack frame
  751.             push    cs                      ;Set DS = CS
  752.             pop     ds
  753.             assume  ds:code
  754.             jmp     word ptr [ret_addr]     ;Return
  755. save_regs       endp
  756.  
  757. ;--------------------------------------------------------------------
  758. ;RESTOREREGS restores register values.
  759. ;--------------------------------------------------------------------
  760. restore_regs    proc    near
  761.             pop     ret_addr                ;Save return address
  762.             pop     es                      ;restore registers
  763.             pop     ds
  764.             assume  ds:nothing
  765.             pop     di
  766.             pop     si
  767.             pop     bp
  768.             pop     dx
  769.             pop     cx
  770.             pop     bx
  771.             pop     ax
  772.             jmp     word ptr cs:[ret_addr]  ;Return
  773. restore_regs    endp
  774.  
  775. final_install:
  776.         rep    movsb            ;copy exclude string
  777.         mov    main_active,-1        ;Enable installed code
  778.         int    21h            ;TSR
  779.  
  780.         even                ;Align stack on word boundry
  781. end_of_resident    =    $
  782.  
  783. ;--------------------------------------------------------------------
  784. ; Non-resident data.
  785. ;--------------------------------------------------------------------
  786. alrdy_installed    db    0            ;Installed flag
  787. other_seg    dw    0            ;Segment of installed code
  788.  
  789. infomsg0    db    13,10,"For help type QPATH /?$"
  790. infomsg1    db    "QPATH uninstalled$"
  791.  
  792. infomsg2    db    "QPATH $"
  793. infomsg2a    db    "disabled",13,10,"$"
  794. infomsg2b    db    "enabled",13,10,"$"
  795. infomsg3    db    "QPATH installed$"
  796.  
  797. errmsg0        db    "Need DOS 3.3 or greater$"
  798. errmsg1        db    "QPATH not installed$"
  799. errmsg2        db    13,10,"Syntax: QPATH [/D][/E][/U][/X cmd[, ...]]"
  800.         db    13,10,10
  801.         db         9,"/D = Disable",13,10
  802.         db         9,"/E = Enable",13,10
  803.         db         9,"/U = Uninstall",13,10
  804.         db         9,"/X = Exclude commands",13,10,"$"
  805. errmsg3        db    "Can",39,"t uninstall$"
  806. errmsg4        db    "Error using Int 2Fh$"
  807. errmsg5        db    "Can",39,"t disable commands once installed$"
  808. endmsg        db    13,10,"$"
  809.  
  810. cmd_switches    db    "udex"            ;Letters of valid commands.
  811. cmd_switch_end    =    $
  812. cmd_tbl        dw    offset remove        ;This jump table is used to
  813.         dw    offset disable        ;  call the routines that
  814.         dw    offset enable        ;  process the command line
  815.         dw    offset exclude
  816.  
  817. ;--------------------------------------------------------------------
  818. ; Initialization routine.
  819. ;--------------------------------------------------------------------
  820. initialize    proc    near
  821.         assume    cs:code,ds:code,es:code
  822.         cld
  823.         mov    dx,offset program       ;Display copyright message
  824.         call    printmsg
  825.         mov    ah,30h            ;Get DOS version
  826.         int    21h
  827.         xchg    al,ah            ;Swap major, minor numbers
  828.         mov    dx,offset errmsg0    ;Bad DOS version
  829.         cmp    ax,31eh            ;Run if DOS 3.3 or greater.
  830.         jb     disp_error
  831.         mov    dos_version,ax        ;Save version number
  832.         call    findinstalled        ;See if another copy in mem
  833.         jc    disp_error
  834.         mov    other_seg,es        ;Save seg of installed code
  835.         push    cs
  836.         pop    es
  837.         assume    es:code
  838.         call    parse_line        ;Parse command line
  839.         jc    disp_error
  840.         cmp    alrdy_installed,0    ;If not already installed,
  841.         je    install            ;  jump to install routine.
  842.         xor    al,al            ;Zero return code
  843. exit:
  844.         mov    ah,4Ch            ;Terminate 
  845.         int    21h
  846. disp_error:
  847.         assume    ds:nothing
  848.         call    printmsgcr        ;Print error message
  849.         mov    al,1
  850.         jmp    short exit
  851.  
  852. ;
  853. ;Install routine. Find segment of COMMAND.COM, hook into int 2Fh and TSR.
  854. ;
  855. install:
  856.         assume    ds:code
  857.         mov    ax,4300h                ;Look for HIMEM.SYS
  858.         int    2fh
  859.         or     al,al
  860.         je    noxms
  861.         inc    xms_flag
  862.         mov    ax,4310h                ;Get entry point for XMM
  863.         int    2fh
  864.         mov    word ptr [xms_service],bx
  865.         mov    word ptr [xms_service+2],es
  866.         push    cs
  867.         pop    es
  868. noxms:
  869.         mov    al,21h            ;Get and set int 21 (DOS)
  870.         mov    di,offset int21h
  871.         mov    dx,offset dosint
  872.         call    getandsetint
  873.         
  874.         mov    al,2fh            ;Get and set int 21 (DOS)
  875.         mov    di,offset int2fh
  876.         mov    dx,offset muxint
  877.         call    getandsetint
  878.  
  879.         push    ds            ;ES = DS
  880.         pop    es
  881.         mov    dx,offset infomsg3    ;Tell user we are
  882.         call    printmsgcr        ;  installing
  883.         mov    dx,ENDOFBUFF        ;Set ptr to exclude buffer.
  884.         mov    word ptr [buff_ptr], BUFFOFFSET
  885.         mov    word ptr [buff_ptr+2],cs
  886.         mov    word ptr [exbuff_ptr],dx
  887.         mov    cx,-1            ;Get size of exclude buff
  888.         mov    si,offset end_of_code
  889.         mov    di,si
  890.         xor    al,al
  891.         repne    scasb
  892.         not    cx
  893.         add    dx,cx            ;Add to end of res offset
  894.         add    dx,15            ;Compute installed size
  895.         push    cx
  896.         mov    cl,4
  897.         shr    dx,cl
  898.         pop    cx            ;Get back disabled cmds len
  899.         mov    ax,3100h
  900.         mov    di,exbuff_ptr        ;Get ptr for disabled cmds
  901.         jmp    final_install
  902. initialize    endp
  903.  
  904. DTAPTR        equ    offset end_of_resident
  905. BUFFOFFSET    equ    DTAPTR + DTASIZE
  906. ENDOFBUFF    equ    BUFFOFFSET + BUFFSIZE
  907.  
  908. ;--------------------------------------------------------------------
  909. ; FINDINSTALLED - Finds any installed copies of the program in memory.
  910. ; Exit: Sets the already installed flag
  911. ;       ES points to installed segment or CS if no copy found.
  912. ;       CF - Set if all Multiplex IDs used
  913. ;--------------------------------------------------------------------
  914. findinstalled    proc    near
  915.         assume    cs:code,ds:code
  916.         mov    cx,36            ;Try 36 different IDs.
  917. find_copy1:
  918.         xor    ax,ax            ;Zero ES
  919.         mov    es,ax
  920.         push    ds
  921.         push    cx
  922.         mov    ah,multiplex_id        ;Load ID.  Use Int 2Fh to
  923.         int    2fh            ;  reach installed code
  924.         pop    cx
  925.         pop    ds
  926.         or    al,al
  927.         je    find_copynf
  928.         mov    si,es            ;See if ES <> 0. If so,
  929.         or    si,si            ;  compare headers.
  930.         jne    find_copy3
  931. find_copy2:
  932.         inc    multiplex_id        ;ID used by another program.
  933.         loop    find_copy1        ;  Change and try again.
  934.         mov    dx,offset errmsg4    ;All IDs taken, print error
  935.         stc
  936.         jmp    find_copyexit1
  937. find_copy3:
  938.         push    cx
  939.         call    cmpheader        ;See if correct program by
  940.         pop    cx                      ;  comparing file headers.
  941.         jne    find_copy2
  942.         inc    alrdy_installed        ;Set installed flag
  943. find_copyexit:
  944.         clc
  945. find_copyexit1:
  946.         ret
  947. find_copynf:
  948.         push    cs
  949.         pop    es                      ;If AL not changed, prog not
  950.         jmp    short find_copyexit    ;  installed.
  951. findinstalled    endp
  952. ;--------------------------------------------------------------------
  953. ; CMPHEADER compares the first 16 bytes of this file with the segment
  954. ;           pointed to by ES.
  955. ; Entry:  DS - code segment
  956. ;         ES - pointer to segment to compare
  957. ; Exit:   ZF - 0 = segments match.
  958. ;--------------------------------------------------------------------
  959. cmpheader    proc    near
  960.         mov    si,offset begin+3    ;Compare 16 bytes of block
  961.         mov    di,si            ;  for ASCII fingerprint.
  962.         mov    cx,16
  963.         repe    cmpsb
  964.         ret
  965. cmpheader    endp
  966.  
  967. ;--------------------------------------------------------------------
  968. ; PRINTMSG prints the message pointed to by DX to the screen.
  969. ; Entry:  DX - pointer to ASCII message terminated by $
  970. ;--------------------------------------------------------------------
  971. printmsg    proc    near
  972.         assume    ds:nothing,es:nothing
  973.         push    ds
  974.         push    cs
  975.         pop    ds
  976.         assume    ds:code
  977.         mov    ah,9            ;Print message
  978.         int    21h
  979.         pop    ds
  980.         ret
  981. printmsg    endp
  982.  
  983. ;--------------------------------------------------------------------
  984. ; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the 
  985. ; message.
  986. ; Entry:  DX - pointer to ASCII message terminated by $
  987. ;--------------------------------------------------------------------
  988. printmsgcr    proc    near
  989.         assume    ds:nothing,es:nothing
  990.         push    dx
  991.         call    printmsg
  992.         mov    dx,offset endmsg
  993.         call    printmsg
  994.         pop    dx
  995.         ret
  996. printmsgcr    endp
  997.  
  998. ;--------------------------------------------------------------------
  999. ; PARSELINE Parses the command line
  1000. ;--------------------------------------------------------------------
  1001. parse_line    proc    near
  1002.         assume    cs:code,ds:code,es:code
  1003.         mov    si,offset command_tail    ;Point to command line
  1004.         lodsb
  1005.         or    al,al            ;See if any chars on line
  1006.         je    parse_end
  1007. parse_loop:
  1008.         call    scan4char            ;Get 1st character
  1009.         jc    parse_end              ;If CR exit
  1010.         cmp    al,"/"            ;Compare character to switch.
  1011.         jne    short parse_exit
  1012.         lodsb                ;Get command line switch
  1013.         or    al,20h            ;  switches.
  1014.         mov    di,offset cmd_switches
  1015.         mov    cx,offset cmd_switch_end - offset cmd_switches
  1016.         repne    scasb
  1017.         mov    dx,offset errmsg2    ;Syntax message
  1018.         jne    parse_exit
  1019.         mov    bx,offset cmd_switch_end - offset cmd_switches - 1
  1020.         sub    bx,cx            ;Copy index into list
  1021.         shl    bx,1            ;Convert to word offset
  1022.         call    cs:[bx+offset cmd_tbl]    ;Call command routine.
  1023.                 jnc    parse_loop        ;If no error, continue
  1024. parse_exit:
  1025.         ret
  1026. parse_end:
  1027.         clc
  1028.         jmp    short parse_exit
  1029. parse_line    endp
  1030.  
  1031. ;--------------------------------------------------------------------
  1032. ; ENABLE enables installed code
  1033. ;--------------------------------------------------------------------
  1034. enable        proc    near
  1035.         assume    ds:code,es:code
  1036.         cmp    alrdy_installed,0
  1037.         je    enable_2
  1038.  
  1039.         mov    ah,multiplex_id        ;Enable 
  1040.         mov    al,MUXENABLE
  1041.         int    2fh
  1042. enable_2:
  1043.         clc
  1044.         ret
  1045. enable        endp
  1046. ;--------------------------------------------------------------------
  1047. ; DISABLE disables installed code
  1048. ;--------------------------------------------------------------------
  1049. disable     proc    near
  1050.         assume    ds:code,es:code
  1051.         mov    chk_path,0
  1052.         cmp    alrdy_installed,0
  1053.         je    disable_2
  1054.         mov    ah,multiplex_id        ;Enable 
  1055.         mov    al,MUXDISABLE
  1056.         int    2fh
  1057. disable_2:
  1058.         clc
  1059.         ret
  1060. disable     endp
  1061. ;--------------------------------------------------------------------
  1062. ; EXCLUDE disables COMMAND.COM commands
  1063. ;--------------------------------------------------------------------
  1064. exclude     proc    near
  1065.         assume    ds:code,es:code
  1066.         mov    dx,offset errmsg5
  1067.         cmp    alrdy_installed,0    ;If installed, fail
  1068.         stc                ;  switch
  1069.         jne    exclude_exit
  1070.         mov    di,offset end_of_code    ;Set ex buff ptr
  1071. exclude_1:
  1072.         call    scan4char        ;Find first command
  1073.         jc    exclude_2
  1074.         dec    si            ;Back up to char
  1075.         mov    bx,di            ;Save start ptr
  1076.         inc    di
  1077.         mov    cx,"az"
  1078. exclude_10:
  1079.         lodsb                ;Copy command.  Convert
  1080.         call    inside            ;  to upper case during
  1081.         jc    exclude_11        ;  copy.
  1082.         and    al,0dfh            ;Make upper case
  1083. exclude_11:
  1084.         call    isfilechar
  1085.         jc    exclude_12
  1086.         stosb
  1087.         jmp    short exclude_10
  1088. exclude_12:
  1089.         mov    dx,di
  1090.         sub    dx,bx
  1091.         dec    dx
  1092.         mov    es:[bx],dl        ;Copy length of command
  1093.         cmp    al,','
  1094.         je    exclude_1
  1095. exclude_2:
  1096.         mov    byte ptr [di],0        ;Terminate string
  1097.         dec    si
  1098.         clc
  1099. exclude_exit:
  1100.         ret
  1101. exclude     endp
  1102. ;--------------------------------------------------------------------
  1103. ; REMOVE uninstalls the installed program from memory.
  1104. ;--------------------------------------------------------------------
  1105. remove        proc    near
  1106.         assume    ds:code,es:code
  1107.         push    ds
  1108.         push    es
  1109.         mov    dx,offset errmsg1    ;Not installed msg
  1110.         cmp    alrdy_installed,0    ;See if installed
  1111.         je    remove_exit
  1112.         mov    ax,3521h                ;Get DOS vector
  1113.         int    21h
  1114.         mov    ax,es            ;Check to make sure DOS
  1115.         cmp    ax,cs:[other_seg]    ;  vector not modified.
  1116.         jne    remove_error
  1117.  
  1118.         mov    ax,352fh                ;Get MUX vector
  1119.         int    21h
  1120.         mov    ax,es            ;Check to make sure MUX
  1121.         cmp    ax,cs:[other_seg]    ;  vector not modified.
  1122.         jne    remove_error
  1123.  
  1124.         lds    dx,es:[int21h]        ;Get old interrupt 21 vector
  1125.         mov    ax,2521h        ;Set interrupt
  1126.         int    21h
  1127.  
  1128.         lds    dx,es:[int2Fh]        ;Get old interrupt 2F vector
  1129.         mov    ax,252fh        ;Set interrupt
  1130.         int    21h
  1131.  
  1132.         mov    cx,es:[env_segment]
  1133.         mov    ah,49h            ;Free program memory block
  1134.         int    21h
  1135.         mov    es,cx            ;Free environment block
  1136.         mov    ah,49h
  1137.         int    21h
  1138.         mov    dx,offset infomsg1    ;Indicate uninstalled.
  1139. remove_exit:
  1140.         stc
  1141.         pop    es
  1142.         pop    ds
  1143.         ret
  1144. remove_error:
  1145.                  mov    dx,offset errmsg3    ;Can't remove error msg
  1146.         jmp    short remove_exit
  1147.  
  1148. remove        endp
  1149.  
  1150. ;--------------------------------------------------------------------
  1151. ; SCAN4CHAR scans a string to find the first character.
  1152. ; Entry:  SI - pointer to ASCII string
  1153. ; Exit:   AL - first nonspace character
  1154. ;         CF - set if carriage return found
  1155. ;--------------------------------------------------------------------
  1156. scan4char      proc near
  1157.         assume    ds:nothing,es:nothing
  1158. scan4loop:
  1159.         lodsb
  1160.         cmp    al,13            ;Check for carriage return.
  1161.         stc
  1162.         je    scan4_exit
  1163.         cmp    al,21h            ;Check for space or other
  1164.         jb    scan4loop        ;  'white' characters.
  1165. scan4_exit:
  1166.          ret
  1167. scan4char    endp
  1168.  
  1169. end_of_code    =    $
  1170.         db    0            ;Default end of ex buffer
  1171. code        ends
  1172. end        begin
  1173. 
  1174.  
  1175.