home *** CD-ROM | disk | FTP | other *** search
- ; SWEEP.ASM -- Runs program or command across subdirectories
- ; =========
- ;
- ; (C) Copyright Charles Petzold, 1985
-
- CSEG Segment
- Assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
-
- Org 002Ch
- Environment Label Byte ; Segment of Environment is here
-
- Org 007Dh
- NewParam Label Byte ; Parameter to pass to COMMAND
-
- Org 0080h
- OldParam Label Byte ; Parameter passed to SWEEP
-
- Org 0100h
- Entry: Jmp Begin ; SWEEP.COM Entry Point
-
- ; Most Data (some more at end of program)
- ; ---------
-
- SweepMessage db 13,10,'>>> SWEEP >>> ' ; The SWEEP message
- CurrentDir db ?,':\' ; ? gets drive letter
-
- db '(C) Copyright Charles Petzold, 1985',1Ah
-
- DosVersMsg db 'Needs DOS 2.0 +$' ; Error Messages
- MemAllocMsg db 'Allocation Problem$'
- CommandMsg db 'SWEEP: COMMAND Problem$'
- AbnormalMsg db 'SWEEP: Abnormal Exit$'
-
- DosVersion dw ? ; Store DOS Version Number here
- BreakState db ? ; Store original break state here
-
- Comspec db 'COMSPEC=' ; String for Environment search
- CommandAsciiz dd ? ; Address of COMMAND.COM string
- ParamBlock dw ? ; Parameter block for EXEC call
- dw NewParam,?
- dw 5Ch,?
- dw 6Ch,?
-
- SearchAsciiZ db '*.*',0 ; Asciiz for Find call
- BackOneDir db '..',0 ; Asciiz for moving back one directory
- DtaPointer dw DtaAreaBegin ; For nested directory searches
- Direction db 0 ; Forward search initially
-
- ; Check DOS Version
- ; -----------------
-
- Begin: Mov AH,30h ; Check for DOS Version
- Int 21h
- Cmp AL,2 ; See if it's 2.0 or above
- Jae DosVersOK ; If so, we can proceed
-
- Mov DX,Offset DosVersMsg ; Otherwise error message
- ErrorExit: Mov AH,9 ; Print String function call
- Int 21h ; Do it
-
- Int 20h ; And exit prematurely
-
- DosVersOK: Xchg AL,AH ; Get Major Version in AH
- Mov [DosVersion],AX ; And save whole thing
-
- ; Un-allocate rest of memory
- ; --------------------------
-
- Mov SP,Offset StackTop ; Set new stack pointer
- Mov BX,Offset EndOfProgram ; This is beyond our needs
- Mov CL,4 ; Prepare for shift
- Shr BX,CL ; Convert to segment form
- Mov AH,4Ah ; Shrink allocated memory
- Int 21h ; By calling DOS
-
- Jnc MemAllocOK ; If no error, we can proceed
-
- Mov DX,Offset MemAllocMsg ; Otherwise set up for message
- Jmp ErrorExit ; Print it and terminate
-
- ; Search for Comspec in Environment
- ; ---------------------------------
-
- MemAllocOK: Push ES ; We'll be changing this
- Mov BX,Offset Environment ; Segment of Environment
- Mov ES,[BX] ; Set ES to it
- Assume ES:Nothing ; And tell the assembler
-
- Sub DI,DI ; Start at the beginning
- Mov SI,Offset ComSpec ; String to search for
- Cld ; Direction must be forward
-
- TryThis: Cmp Byte Ptr ES:[DI],0 ; See if points to zero
- Jz NoFindComSpec ; If so, we're dead in water
-
- Push SI ; Temporarily save these
- Push DI
-
- Mov CX,8 ; Search string has 8 chars
- Repz Cmpsb ; Do the string compare
-
- Pop DI ; Get back the registers
- Pop SI
-
- Jz FoundComspec ; If equals, we've found it
-
- Sub AL,AL ; Otherwise search for zero
- Mov CX,-1 ; For 'infinite' bytes
- Repnz Scasb ; Do the search
-
- Jmp TryThis ; And try the next string
-
- NoFindComSpec: Pop ES ; Get back ES on error
- Mov DX,Offset CommandMsg ; Set up error message
- Jmp ErrorExit ; And bow out gracefully
-
- FoundComspec: Add DI,8 ; so points after 'COMSPEC='
- Mov Word Ptr [CommandASCIIZ],DI ; Save the address
- Mov Word Ptr [CommandASCIIZ + 2],ES ; including segment
-
- ; Set up parameter block for EXEC call
- ; ------------------------------------
-
- Mov [ParamBlock],ES ; Segment of environment
- Mov [ParamBlock + 4],CS ; Segment of parameter
- Mov [ParamBlock + 8],CS ; Segment of 1st FCB
- Mov [ParamBlock + 12],CS ; Segment of 2nd FCB
-
- Pop ES ; Restores ES to this segment
- Assume ES:CSEG ; And make sure MASM knows
-
- ; Fix up new paramater for "/C" String
- ; ------------------------------------
-
- Mov AL,[OldParam] ; Get old character count
- Add AL,3 ; Three more characters in paramater
- Mov [NewParam],AL ; New number of characters
- Mov [NewParam + 1],' ' ; Next is a blank
- Mov Word Ptr [NewParam + 2],'C/' ; Then a /C
-
- ; Get the current break state, drive, and subdirectory
- ; ----------------------------------------------------
-
- Mov AX,3300h ; Get Break State
- Int 21h ; By calling DOS
- Mov [BreakState],DL ; Save it
-
- Sub DL,DL ; Set it to OFF
- Mov AX,3301h ; Set Break State
- Int 21h ; By calling DOS
-
- Mov DX,Offset Terminate ; For Ctrl-Break exits
- Mov AX,2523h ; Set Interrupt 23h vector
- Int 21h ; through DOS call
-
- Mov AH,19h ; Get current drive
- Int 21h ; By calling DOS
- Add AL,'A' ; Convert to letter
- Mov [CurrentDir],AL ; And save it
-
- Mov SI,Offset StartOffDir ; Repository of directory
- Sub DL,DL ; Indicate default drive
- Mov AH,47h ; Get current directory
- Int 21h ; By calling DOS
-
- ; Display SWEEP message with current drive and subdirectory
- ; ---------------------------------------------------------
-
- MainLoop: Mov SI,3 + Offset CurrentDir; Receives directory
- Sub DL,DL ; Indicate current drive
- Mov AH,47h ; Current directory call
- Int 21h ; Get it
-
- Mov SI,Offset SweepMessage ; String to display
- Cld ; Want direction forward
- DirPrintLoop: Lodsb ; Get the character
- Or AL,AL ; Check if it's zero
- Jz NoMoreDirPrint ; If so, branch out
- Mov DL,AL ; Otherwise set DL to it
- Mov AH,2 ; For Display Output
- Int 21h ; Display the character
- Jmp DirPrintLoop ; And loop around for the next
-
- NoMoreDirPrint: Mov CX,500 ; We'll hang out here awhile
-
- StatCheckLoop: Mov AH,0Bh ; Set up for keyboard status
- Int 21h ; Allow user to Break out
- Loop StatCheckLoop ; Do it a few more times
-
- Cmp [DosVersion],30Ah ; See if DOS is 3.1 or higher
- Jb LoadCommand ; If not, skip CR & LF
-
- Mov DL,13 ; Carriage Return
- Mov AH,2 ; Write to Display
- Int 21h ; by calling DOS
-
- Mov DL,10 ; Line Feed
- Mov AH,2 ; Write to Display
- Int 21h ; by calling DOS
-
- ; Load COMMAND.COM
- ; -----------------
-
- LoadCommand: Mov BX,Offset ParamBlock ; ES:BX = parameter block
- Lds DX,[CommandAsciiz] ; DS:DX = Asciiz of COMMAND
- Sub AL,AL ; EXEC type zero
- Mov AH,4Bh ; EXEC function call
- Int 21h ; Load command processor
-
- ; Return from COMMAND.COM
- ; -----------------------
-
- Mov AX,CS ; This is the current code segment
- Mov DS,AX ; Reset DS to this segment
- Mov ES,AX ; Reset ES to this segment
- Mov SS,AX ; Reset stack segment to it
- Mov SP,Offset StackTop ; And reset stack pointer also
-
- ; Avoid problems caused by commands that may change drive or directory
- ; --------------------------------------------------------------------
-
- PushF ; Save EXEC Error Flag
-
- Sub DL,DL ; Set Break State to OFF
- Mov AX,3301h ; Set Break State
- Int 21h ; By calling DOS
-
- Mov DL,[CurrentDir] ; Get original drive letter
- Sub DL,'A' ; Convert to number
- Mov AH,0Eh ; Select disk
- Int 21h ; Through DOS call
-
- PopF ; Get back EXEC Error Flag
-
- Mov DX,Offset CommandMsg ; Set up possible error message
- Jc ErrorExit2 ; And print if EXEC error
-
- Mov DX,2 + Offset CurrentDir; The pre-COMMAND directory
- Mov AH,3Bh ; Call to change directory
- Int 21h ; Do it
-
- Jnc NextLevel ; Continue if no error
-
- Mov DX,Offset AbnormalMsg ; Otherwise set up message
- ErrorExit2: Mov AH,9 ; Will print the string
- Int 21h ; Print it
-
- Jmp Terminate ; And get out of here
-
- ; Find first or next subdirectory level
- ; -------------------------------------
-
- NextLevel: Mov DX,[DTAPointer] ; Next nested DTA
- Mov AH,1Ah ; For DOS call to set DTA
- Int 21h ; Do it
-
- Cmp [Direction],0 ; Check if we're nesting
- Jnz FindNextFile ; If not, we're continuing
-
- Mov DX,Offset SearchAsciiZ ; We search for *.*
- Mov CX,10h ; Subdirectory attribute
- Mov AH,4Eh ; Find first file
- Int 21h ; by calling DOS
-
- Jmp Short TestMatch ; Hop around next section
-
- FindNextFile: Mov AH,4Fh ; Find next file
- Int 21h ; by calling DOS
-
- TestMatch: Jc NoMoreFiles ; If CY flag, at end of rope
-
- Mov BX,[DTAPointer] ; Our find stuff is here
- Test Byte Ptr [BX + 21],10h ; Test if directory attribute
- Jz FindNextFile ; If not, continue search
-
- Add BX,30 ; Now points to directory name
- Cmp Byte Ptr [BX],'.' ; Ignore "." and ".." entries
- Jz FindNextFile ; by continuing the search
-
- Mov DX,BX ; Now DX points to found dir
- Mov AH,3Bh ; Set up DOS function call
- Int 21h ; And change directory
-
- Add [DtaPointer],43 ; New DTA for new level
- Mov [Direction],0 ; I.E., Find first file
-
- Jmp MainLoop ; All ready to cycle through
-
- ; No More Files Found -- go back to previous level
- ; ------------------------------------------------
-
- NoMoreFiles: Cmp [DTAPointer],Offset DtaAreaBegin
- ; See if back at start
- Jz Terminate ; If so, that's all, folks
-
- Sub [DTAPointer],43 ; Back one for previous
- Mov [Direction],-1 ; I.E., will find next file
-
- Mov DX,Offset BackOneDir ; The string ".."
- Mov AH,3Bh ; Call to change directory
- Int 21h ; Change directory to father
-
- Jmp NextLevel ; And continue the search
-
- Terminate: Mov DX,Offset RestoreDir ; Original subdirectory
- Mov AH,3Bh ; Call to change directory
- Int 21h ; Do it
-
- Mov DL,[BreakState] ; Original break-state
- Mov AX,3301h ; Change the break-state
- Int 21h ; by calling DOS
-
- Int 20h ; Terminate program
-
- RestoreDir db '\' ; For eventual restore
- StartOffDir Label Byte ; Place for original directory
- StackBottom equ StartOffDir + 64 ; Stack area beyond that
- StackTop equ StackBottom + 100h ; The top of the stack
- DtaAreaBegin equ StackTop ; is also the DTA area
- DtaAreaEnd equ DtaAreaBegin + 32 * 43 ; Can have 32 DTAs of 43 bytes
- EndOfProgram equ DtaAreaEnd + 15 ; This is beyond our needs
-
- CSEG EndS ; End of the segment
- End Entry ; Denotes entry point