Category : Assembly Language Source Code
Archive   : ASM4.ZIP
Filename : SWEEP.ASM

Output of file : SWEEP.ASM contained in archive : ASM4.ZIP
; SWEEP.ASM -- Runs program or command across subdirectories
; =========
; (C) Copyright Charles Petzold, 1985

CSEG Segment

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

; -----------------

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

  3 Responses to “Category : Assembly Language Source Code
Archive   : ASM4.ZIP
Filename : SWEEP.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: