No announcement yet.

Program That Accesses Multiple Directories

  • Filter
  • Time
  • Show
Clear All
new posts

  • Program That Accesses Multiple Directories

    Greetings ...

    For years, I have been using a DOS program called SWEEP to help delete files in multiple directories. For example ....

    C:\FGF2006» Sweep if exist turkey*.txt del turkey*.txt

    This would delete any such files in directory FGF2006 plus all sub-directories within directory FGF2006

    Recently, I have found that Sweep does not work with certain files, or will not work on certain PC's.

    Has anyone concocted a PBCC program that would work the same way as SWEEP?

    UPDATE -- Since first posting this, I have thought up a program which should work without ever needing to go through the command prompt. Any input still appreciated.

    Thanx-A-Lot, Frank Ferrell
    Last edited by Frank Ferrell; 23 Jul 2008, 10:21 PM.

  • #2
    Originally posted by Frank Ferrell View Post
    Has anyone concocted a PBCC program that would work the same way as SWEEP?
    Sure. For example, my rm does nearly the same. In order to have anything done instead of just deleting a file you need to replace the "kill" by some command string, probably given at the command line. For reference purposes, here is the source code of
    ;	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
    ; 	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
    Hope this helps

    „Let the machine do the dirty work.“
    The Elements of Programming Style, Brian W. Kernighan, P. J. Plauger 1978


    • #3
      C:\DOS> del /S turkey*.txt
      Does not remove directories. But you could add ...
      C:\DOS> rmdir *.*
      .. to remove all EMPTY subdirectories under current.

      You can also do this with SHFileOperation FO_DELETE operation.
      Last edited by Michael Mattias; 24 Jul 2008, 09:30 AM.
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]


      • #4
        Greetings ...

        I'm stunned and embarrassed, as I wasn't aware of DEL's capacities, though I was familar with DOS's RD function.

        Yet, I am also very happy. DEL with /S WORKS !!!! Microsoft got one right for a change!

        Thanx-A-Whote-Lot, Frank
        Last edited by Frank Ferrell; 24 Jul 2008, 04:43 PM.


        • #5
          They changed/added a lot of commands with Win2k/ really isn't DOS though but CMD. The old DOS commands didn't have an /S switch except DIR. Had to use things like XCOPY, DELTREE, Creative use of BAT files, etc.
          Mobile Solutions
          Sys Analyst and Development


          • #6
            Greetings ...

            Sooo - Microsoft put all that in with Win 2k, eh? Imagine if they'd done that with DOS 3.30! Oh Well!

            Thanx-A-Lot, Frank


            • #7
              C:\DOS> del /?
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]


              • #8
                Command-line junkies might also be interested in this Microsoft site:

                Command Line Reference A-Z
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]