home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l040 / 11.ddi / WHEREIS.ZIP / IEXECDOS.ASM < prev    next >
Encoding:
Assembly Source File  |  1992-10-27  |  17.2 KB  |  584 lines

  1.  
  2. ;   FILENAME: IEXECDOS.ASM
  3. ;
  4. ;   Copyright (c) 1990, 1992 by Borland International, Inc.
  5. ;
  6. ;   DESCRIPTION: This module implements the routines that handle calling
  7. ;   DOS to perform a command on each file that is found by WHEREIS.
  8. ;   This module uses ideal mode syntax.
  9. ;
  10. ;   This module looks for the location of COMMAND.COM to enable the
  11. ;   running of the commands. Since many matching files may be found,
  12. ;   and COMMAND.COM is called to execute the given DOS command for each
  13. ;   file that is found, it is best if COMMAND.COM is located in a ramdisk.
  14. ;
  15. ;   ASSEMBLY INSTRUCTIONS: To assemble this module use the following
  16. ;   TASM command line.
  17. ;
  18. ;       TASM /m /dMDL=memorymodel iparam
  19. ;
  20. ;   /m in the above command line allows TASM to resolve jumps and other
  21. ;   operations to their shortest form and get rid of extra NOPs.
  22. ;   'memorymodel' in the above command line may be replaced by TINY, SMALL,
  23. ;   MEDIUM, COMPACT, LARGE or HUGE. If assembling this module to run on
  24. ;   a 286/386 machine, turn on the P286 directive in order to take advantage of
  25. ;   286/386 specific instructions. I.E.
  26. ;
  27. ;       TASM /m /dMDL=memorymodel /jP286 iparam
  28. ;
  29.  
  30. ;DO_SAMPLE_COMMAND equ 1      ; Enable this to execute a sample DIR command
  31. ;                             ;   when the command line is being parsed.
  32.  
  33. jumps
  34.  
  35. %tabsize 4
  36.  
  37. ifndef  MDL
  38.     display "Error: This module requires that you provide a memory model"
  39.     display "       definition on the command line. I.E. /dMDL=SMALL."
  40.     err ; Force a fatal error
  41. else
  42.  
  43.     ideal                           ; Use TASM's Ideal mode
  44. %   model   MDL,pascal              ; Define the memory model
  45.  
  46.     include "dos.inc"
  47.     include "idos.inc"
  48.     include "kbd.inc"
  49.     include "iwhglobl.inc"
  50.     include "imacros.mac"
  51.  
  52.     dataseg
  53. NO_COMMAND_GIVEN equ 0
  54. COMMAND_GIVEN    equ 1
  55.     DosCommandGiven   db NO_COMMAND_GIVEN
  56.  
  57. COMMAND_BUFFER_LENGTH equ 200
  58.     ; Stores the command given on command line
  59.     DosCommandBuffer  db COMMAND_BUFFER_LENGTH dup (?)
  60.  
  61. ; The DOS command in quotes will include some special escape sequences
  62. ; that will cause the name of the file to be inserted in various ways.
  63. ;
  64. ;  %1  - The full path, filename and  extension
  65. ;  %2  - Filename and extension (no path)
  66. ;  %3  - Only the path
  67. ;  %4  - Only the filename before the extension followed by a .
  68. ;  %5  - Only the extension, preceeded by a .
  69.  
  70.     ; This is placed at the start of COMMAND.COM command strings.
  71.     StartOfBuff       db '/C ',0
  72.  
  73.     ; Store the actual command that is executed. Any %x directives in
  74.     ; the above command buffer are converted to their actual values
  75.     ; as the above command is transfered into the following buffer.
  76.     ; 32 extra bytes are an overrun buffer.
  77.     CommandToDo       db COMMAND_BUFFER_LENGTH+32 dup (?)
  78.  
  79.     ; Needed for the call to execute COMMAND.COM
  80.     ParamBlock        dw 7 dup (0)
  81.  
  82.     ComspecTag        db 'COMSPEC=',0
  83.  
  84.     ; Pointer into the environment block for start of COMMAND.COM location
  85.     ComspecSeg        dw 0     ;Not changed from zero if no comspec found.
  86.     ComspecOfs        dw ?
  87.  
  88.     MakePascalString  NoComspecMssg,<"COMSPEC= not found in environment!",13,10>
  89.  
  90.     codeseg
  91.  
  92.     ; The environment block is a group of null terminated strings.
  93.     ; A string beginning with zero signals the end of the eviroment block.
  94.  
  95.     proc SearchEnvironment
  96.     ;   This routine searches for a variable in the environment block.
  97.     ;
  98.     ;   Input
  99.     ;       DS:SI - Points to a string like "NAME=" which is to be
  100.     ;               found in the environment. It should be an ASCIIZ string.
  101.     ;   Output
  102.     ;       If the variable is found,
  103.     ;           AL    -  0
  104.     ;           ES:DI -  Points to string after the = sign in the environment.
  105.     ;       If the variable is not found,
  106.     ;           AL is nonzero.
  107.     ;   Registers modified
  108.     ;       all
  109.  
  110.         cld       ;Set direction for scanning to increment
  111.  
  112.         ; Set ES:DI to environment block
  113.         push   ds
  114.         mov    ax,@data   ; Reset to our datasegment since the "NAME="
  115.                           ; might be in another segment.
  116.         mov    ds,ax
  117.         mov    es,[PspAddress]
  118.         mov    es,[es:psp.EnvironmentBlock]
  119.         xor    di,di
  120.         pop    ds
  121.     @@CheckEnvironmentEnd:
  122.         mov    bx,si               ;initialize BX pointer to name to find
  123.         mov    al,[byte es:di]
  124.         or     al,al
  125.         je     @@MatchFailed       ;jump if end is found
  126.  
  127.     @@CheckNextByte:
  128.  
  129.         mov    al,[bx]                  ;get character to match.
  130.  
  131.         or     al,al                    ;if end of name we are done!
  132.         jz     @@MatchCompleted         ;  (AL will be zero)
  133.  
  134.         cmp    al,[byte es:di]          ;compare to char in environment block
  135.         jne    @@FindNextString         ;jump if match failed
  136.         inc    bx
  137.         inc    di
  138.         jmp    @@CheckNextByte
  139.  
  140.     @@FindNextString:
  141.         xor    al,al                    ;scan forward in Environment Block
  142.         mov    cx,0FFFFh                ;for zero byte.
  143.         repnz  scasb
  144.         jmp    @@CheckEnvironmentEnd    ;go compare next string
  145.  
  146.     @@MatchFailed:
  147.         inc    al                       ;return al<>0 as failure flag
  148.  
  149.     @@MatchCompleted:                   ;all matched, return ES:DI pointing
  150.                                         ; to parameter. al = 0
  151.         ret
  152.     endp SearchEnvironment
  153.  
  154.  
  155. ifdef DO_SAMPLE_COMMAND
  156.     ; Show a sample of the proper way to call COMMAND.COM
  157.     dataseg
  158.     SampleCommand db 9,'/C DIR C:',13
  159.     codeseg
  160.     proc SampleDosCommand
  161.     ;   This routine calls COMMAND.COM to do the DIR command.
  162.     ;
  163.         mov     cx,seg SampleCommand
  164.         mov     dx,offset SampleCommand
  165.         call    DoDosCommand
  166.         ret
  167.     endp SampleDosCommand
  168. endif
  169.  
  170.     proc DoDosCommand
  171.     ;   This procedure executes the command string pointed at by DX:CX
  172.     ;   by giving it to COMMAND.COM.
  173.     ;   This routine is not reentrant because of local code segment
  174.     ;   data storage at end of routine.
  175.     ;
  176.     ;   Input
  177.     ;       None
  178.     ;   Output
  179.     ;       None
  180.     ;   Calling conventions
  181.     ;       NA
  182.     ;   Registers modified
  183.     ;       all
  184.  
  185.         push    ds
  186.         mov     ax,seg ParamBlock
  187.         mov     es,ax
  188.         mov     bx,offset ParamBlock
  189.  
  190.         mov     [word es:bx+4],cx   ; Load the location of the command tail
  191.         mov     [word es:bx+2],dx   ;   for the command.
  192.  
  193.         mov     [Orig_SS],SS
  194.         mov     [Orig_SP],SP
  195.  
  196.         mov     ax,[ComSpecSeg]
  197.         or      ax,ax
  198.         jz      @@Skip       ; Skip over EXEC if our segment is still zero.
  199.                              ; That means that no Comspec was found.
  200.  
  201.         mov     dx,[ComspecOfs]
  202.         mov     ds,ax
  203.         
  204.         mov     ax,4b00h
  205.         int     21h
  206.     @@Skip:
  207.         mov     ss,[Orig_SS]
  208.         mov     sp,[Orig_SP]
  209.         pop     ds
  210.         ret
  211.  
  212.     ; Preserves the location of our stack.
  213.     Orig_SS dw ?
  214.     Orig_SP dw ?
  215.     endp DoDosCommand
  216.  
  217.     proc ParseDosCommand
  218.     ;   This procedure initializes all variables and data structures
  219.     ;   used for executing the DOS command.
  220.     ;
  221.     ;   Input
  222.     ;       ES:DI - Points to DOS command which is surrounded by quotes.
  223.     ;               It is a pascal style string
  224.     ;   Output
  225.     ;       Carry set if a command has already been specified
  226.     ;   Calling conventions
  227.     ;       NA
  228.     ;   Registers modified
  229.     ;       all
  230.  
  231.         cmp     [DosCommandGiven],COMMAND_GIVEN
  232.         jne     @@FirstUse
  233.         stc     ; An error because a command was already specified
  234.         jmp     @@Exit
  235.  
  236.     @@FirstUse:
  237.         push    es di           ; Preserve pointer to DOS command
  238.         ; We need to find COMMAND.COM before we can know that we can
  239.         ; do a DOS command.
  240.          mov    si,offset ComspecTag     ;DS:SI string to match
  241.          call   SearchEnvironment        ;go search environment
  242.          or     al,al
  243.          jne    ComspecNotFound
  244.  
  245.          mov    [ComspecSeg],es          ; If it was found, ES:DI is stored.
  246.          mov    [ComspecOfs],di
  247.          jz     FreeExtraMemory
  248.  
  249.     ComspecNotFound:
  250.          call   WritePascalString,ds,offset NoComspecMssg
  251.  
  252.     FreeExtraMemory:
  253.         ; We need to give up extra memory.
  254.         mov     bx,zzzzzseg     ; Location of first segment of free memory
  255.         mov     ax,[PspAddress] ; PSP segment
  256.         sub     bx,ax           ; BX now contains paragraphs used
  257.                                 ;   by this program.
  258.         mov     es,ax
  259.         mov     ah,4ah
  260.         int     21h
  261.  
  262. ifdef DO_SAMPLE_COMMAND
  263.         call    SampleDosCommand
  264. endif
  265.         pop     di es           ; Restore pointer to DOS command
  266.  
  267.         ; Check if the final character is a quote and
  268.         ;   remove it if it is.
  269.         xor     bh,bh           ; Get length of string in BX
  270.         mov     bl,[es:di]
  271.  
  272.         mov     al,[es:di+bx]   ; Load last character of string
  273.         call    IsDelimiter
  274.         jnc     RemoveLeadingQuote
  275.  
  276.     RemoveTrailingQuote:
  277.         dec     [byte ES:DI]    ; Remove the trailing delimiter
  278.  
  279.     RemoveLeadingQuote:
  280.         push    es di           ; Preserve the location of the DOS command
  281.         mov     cx, 1           ; Remove the first character
  282.         mov     ax, 1           ; from the string
  283.         call    DeleteChar,es,di
  284.         pop     di es           ; Restore the location
  285.  
  286.         ; Copy the command to the DOS command buffer
  287.         xor     ah,ah
  288.         mov     al,[byte es:di]
  289.         inc     ax
  290.  
  291.         call    ByteCopy,es,di,seg DosCommandBuffer,Offset DosCommandBuffer
  292.  
  293.         ; Set flag so we know that a command was given.
  294.         mov     [DosCommandGiven],COMMAND_GIVEN
  295.         clc     ; No error
  296.     @@Exit:
  297.         ret
  298.     endp ParseDosCommand
  299.  
  300.  
  301.     dataseg
  302.     ; Local data area for ExecuteDosCommand
  303.  
  304.     ; The following act as pointers to the data for this invocation of
  305.     ; ExecuteDosCommand.
  306.     DirectoryPath dw ?
  307.     FileNameSeg   dw ?
  308.     FileName      dw ?
  309.  
  310.     codeseg
  311.     proc ExecuteDosCommand
  312.     ;   This procedure actual executes the DOS command, if given, for
  313.     ;   each file that is found.
  314.     ;
  315.     ;   Input
  316.     ;       ax:si - Offset of filename
  317.     ;       di - offset of currentdir
  318.     ;   Output
  319.     ;       none
  320.     ;   Calling conventions
  321.     ;       NA
  322.     ;   Registers modified
  323.     ;       all except es
  324.  
  325.         mov     [DirectoryPath],di
  326.         mov     [FileNameSeg],ax
  327.         mov     [FileName],si
  328.  
  329.         push    es
  330.         cmp     [DosCommandGiven],COMMAND_GIVEN
  331.         jne     @@Exit
  332.  
  333.         ; Blank out the buffer for the command to do.
  334.         cld     ; Autoincrement
  335.         mov     ax,seg CommandToDo
  336.         mov     es,ax
  337.         mov     di,offset CommandToDo
  338.         mov     cx,COMMAND_BUFFER_LENGTH
  339.         mov     al,0
  340.         rep stosb
  341.  
  342.         ; We need to go into a loop of copying from the input command
  343.         ; string until we find a %
  344.  
  345.         mov     di,offset CommandToDo        ; For results            es:di
  346.         xor     cl,cl                        ; Length of output string
  347.         inc     di                           ; Move over the leading length byte
  348.  
  349.         mov     si,offset StartOfBuff
  350.         call    CopyAsciizString             ; Copy the starting /C
  351.  
  352.         mov     si,offset DosCommandBuffer   ; For original command   ds:si
  353.         mov     ch,[si]                      ; Length of original string
  354.         inc     si                           ; Move over the leading length byte
  355.  
  356.  
  357.     @@ProcessChar:
  358.         or      ch,ch
  359.         jz      SourceExhausted
  360.         lodsb                   ; Load current byte
  361.         dec     ch              ; One less character to get
  362.  
  363.         cmp     al,'%'
  364.         je      @@ProcessSpecial
  365.     @@EmitChar:
  366.         stosb                   ; This route handles regular characters
  367.         inc     cl              ; Increment length of output string
  368.         cmp     cl,COMMAND_BUFFER_LENGTH-1
  369.         jae     SourceExhausted ; Force early termination if we run out of room!
  370.         jmp     @@ProcessChar
  371.  
  372.     @@ProcessSpecial:           ; We saw a % sign.
  373.         or      ch,ch
  374.         jz      @@EmitChar      ;Output because there is nothing more after it
  375.         lodsb
  376.         dec     ch
  377.         ; Try to recognize one of the %x directives:
  378.         cmp     al,'1'
  379.         je      Process1
  380.         cmp     al,'2'
  381.         je      Process2
  382.         cmp     al,'3'
  383.         je      Process3
  384.         cmp     al,'4'
  385.         je      Process4
  386.         cmp     al,'5'
  387.         je      Process5
  388.  
  389.         ; We don't recognize it, so output the %x unchanged.
  390.         mov     [byte es:di],'%'  ; Put out the % that got us here
  391.         inc     cl                ; Increment length of output string
  392.         inc     di
  393.         jmp     @@EmitChar        ; Output the character in AL
  394.  
  395.  
  396.     Process1:
  397.         call    EmitPath
  398.         cmp     cl,COMMAND_BUFFER_LENGTH-1
  399.         jae     SourceExhausted ; Force early termination if we run out of room!
  400.     Process2:
  401.         call    EmitFileRoot
  402.         cmp     cl,COMMAND_BUFFER_LENGTH-1
  403.         jae     SourceExhausted ; Force early termination if we run out of room!
  404.         jmp     Process5
  405.  
  406.     Process3:
  407.         call    EmitPath
  408.         jmp     @@ProcessChar
  409.  
  410.     Process4:
  411.         call    EmitFileRoot
  412.         call    EmitDot
  413.         jmp     @@ProcessChar
  414.  
  415.     Process5:
  416.         Call    EmitDot
  417.         call    EmitExtension
  418.         jmp     @@ProcessChar
  419.  
  420.     SourceExhausted:
  421.         ;We need to fill in the length byte, along with a 13 at the end.
  422.         mov     al,13
  423.         stosb
  424.         mov     [CommandToDo],cl     ; Fill in the length byte
  425.  
  426.         mov     cx,seg CommandToDo
  427.         mov     dx,offset CommandToDo
  428.         call    DoDosCommand
  429.  
  430.     @@Exit:
  431.         pop     es
  432.         ret
  433.     endp ExecuteDosCommand
  434.  
  435.  
  436.  
  437.     proc EmitPath
  438.     ; This routine writes the drive and path to the output command.com string
  439.  
  440.         push    si ds
  441.  
  442.         mov     si,offset Drive
  443.         call    CopyPascalString
  444.  
  445.         mov     si,[DirectoryPath]
  446.         cmp     [byte ds:si],'A'
  447.         jl      @@NoBackSlash
  448.         dec     si
  449.     @@NoBackSlash:
  450.         call    CopyAsciizString
  451.  
  452.         mov     ax,seg SwitchChar
  453.         mov     ds,ax
  454.         mov     si,offset SwitchChar
  455.         call    CopyPascalString
  456.  
  457.         pop     ds si
  458.         ret
  459.     endp EmitPath
  460.  
  461.  
  462.  
  463.     proc EmitFileRoot
  464.     ; This routine writes the part of the filename that is before the
  465.     ; extension to the output string that will be sent to COMMAND.COM
  466.  
  467.         push    si ds
  468.         mov     si,[FileName]
  469.         mov     ax,[FileNameSeg]
  470.         mov     ds,ax
  471.  
  472.         mov     al,'.'
  473.         call    CopyTerminatedString
  474.         pop     ds si
  475.         ret
  476.     endp EmitFileRoot
  477.  
  478.  
  479.  
  480.     proc EmitExtension
  481.     ; This routine writes the extension of the current file to the
  482.     ; output string that will be sent to COMMAND.COM
  483.  
  484.         push    si ds
  485.         mov     si,[FileName]
  486.         mov     ax,[FileNameSeg]
  487.         mov     ds,ax
  488.  
  489.         mov     al,'.'
  490.     @@CheckAgain:
  491.         mov     ah,[ds:si]
  492.         cmp     ah,al
  493.         je      @@DotFound
  494.         or      ah,ah
  495.         jz      @@Exit       ; Quit searching if a zero is found
  496.         inc     si
  497.         jmp     @@CheckAgain
  498.     @@DotFound:
  499.         inc     si
  500.         call    CopyAsciizString
  501.     @@Exit:
  502.         pop     ds si
  503.         ret
  504.     endp EmitExtension
  505.  
  506.  
  507.  
  508.     proc EmitDot
  509.     ; This routine outputs a . to the string to be sent to command.com.
  510.  
  511.         mov     [byte es:di],'.'  ; Put out the .
  512.         inc     cl
  513.         inc     di
  514.         ret
  515.     endp EmitDot
  516.  
  517.  
  518.     ; The following string copy routines are special for this module.
  519.     ; DS:SI point to the source string. (DS:SI are preserved.)
  520.     ; ES:DI Point to the destination string area. (ES:DI is not preserved.)
  521.     ; CL is updated for every byte output to ES:DI.
  522.  
  523.     proc CopyPascalString
  524.     ; Copy pascal type string to ES:DI, but omit the length byte.
  525.         xor     bx,bx
  526.         mov     al,[ds:si]
  527.         add     cl,al
  528.  
  529.     @@CopyChar:
  530.         mov     ah,[ds:si+1+bx]
  531.         mov     [es:di],ah
  532.         inc     di
  533.         inc     bx
  534.         dec     al
  535.         jnz     @@CopyChar
  536.  
  537.         ret
  538.     endp CopyPascalString
  539.  
  540.  
  541.  
  542.     proc CopyAsciizString
  543.     ; Copy a string that is terminated by a zero.
  544.         xor     al,al
  545.         call    CopyTerminatedString
  546.         ret
  547.     endp CopyAsciizString
  548.  
  549.  
  550.  
  551.     proc CopyTerminatedString
  552.     ; Copy a string terminated by any character.
  553.     ; al contains character to stop copy. Normally 0 for ASCIIZ strings
  554.     ; Note that the terminator is not copied.
  555.         xor     bx,bx
  556.  
  557.     @@CopyMoreChar:
  558.         mov     ah,[ds:si+bx]
  559.         cmp     ah,al
  560.         jz      @@AtEnd
  561.         mov     [es:di],ah
  562.         inc     di
  563.         inc     bx
  564.         inc     cl
  565.         jnz     @@CopyMoreChar
  566.     @@AtEnd:
  567.         ret
  568.     endp CopyTerminatedString
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575. segment zzzzzseg   ; Dummy final segment for calculating program size
  576.                    ; to release memory back to DOS.
  577. ends    zzzzzseg
  578.  
  579. endif   ; ifndef MDL
  580.  
  581. end
  582.  
  583.  
  584.