Category : Assembly Language Source Code
Archive   : ASM4.ZIP
Filename : SWEEP.ASM
Output of file : SWEEP.ASM contained in archive : ASM4.ZIP
; =========
;
; (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
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/