For years I have looked for a way to stop this with
a Ctrl Break with no sucess. It just keeps going like the energize bunny. Anyone have an answer ?
Thanks.
; WHERE.ASM -- FAST File Finder Andrew Kennedy 2004
;
; Works thru WinXP SP2
;
; MUST USE tasm31.exe and tlink51.exe to compile !!
;
; WON'T FIND FILES WITH MORE THAN A 3 CHAR EXTENSION !!
;
; Lengthened path to 128 characters
; Change to drive to search floppies
;
; ** Speed is slow if booted to DOS, so load a
; disk cache program like smartdrv !!
;
lf equ 0ah ; ASCII line feed
cr equ 0dh ; ASCII carriage return
ff equ 0ch ; ASCII form feed
tab equ 09h
eom equ '$' ; end of message flag
; Program Segment Prefix
default_fcb equ 05ch
command equ 80h
default_dta equ 080h
; This is the format for the DOS Data Transfer Area
; searches for a file match in directories.
DTA STRUC
RESERVED db 21 dup (?)
ATTRIBUTE db 0
TIME dw 0
DATE dw 0
DTA_SIZE dd 0
NAME_FOUND db 13 dup (?)
DTA ENDS
cseg segment para public 'CODE'
assume cs:cseg,ds:data,es:data,ss:stak
; This is the main program that sets up the initial conditions for
; SDIR which, in turn, does a recursive search.
;
; Reads: PATH_NAME
; Writes: FILE_NAME
; Calls: SDIR
whereis proc far
push ds ; save final return
xor ax,ax
push ax
mov bp,sp ; save pointer to final return
; in case we want to exit
; inside recursive routine
mov ax,data ; make data segment addressable
mov es,ax ; via ES
call clr_screen
call infile ; get name of search target
mov ax,data ; make data segment addressable
mov ds,ax ; via DS
jnc short whereis2 ; jump if filename was ok
; filename was missing,
mov dx,offset msg1 ; print error message and exit
mov ah,9
int 21h
ret
whereis2:
mov di,offset PATH_NAME
xor al,al ; Search for the zero at the end
cld ; of PATH_NAME
mov cx,128 ; Max path length
repnz scasb
mov bx,di
dec bx ; DS:BX points to end of PATH_NAME
mov dx,0 ; Tell SDIR this is first
call SDIR ; Now do the recursive search
mov ax,match_count ; were any matches found?
or ax,ax
jz whereis8 ; no,jump
ret ; yes,just exit
whereis8:
mov dx,offset msg2 ; no, print "no match"
mov ah,9
int 21h
ret
; this is a special crash
; exit, which may be taken
; from inside recursed proc.
whereis9:
mov sp,bp
ret
whereis endp
clr_screen proc near ; clear screen using direct video writes
; faster than DOS functions
push ax
push es
mov ax,0b800h ; Start at memory 0b800
mov es,ax
xor di,di
mov cx,2000
mov ax,0720h ; Black bg, white fg, 20h = space char
rep stosw
pop ax
pop es
ret
clr_screen endp
; This procedure searches all the files in the current directory
; looking for a match. It also prints the full name for each match.
;
; DS:BX Pointer to end of current path name
; DS:DX Old disk transfer area (DTA)
;
; Reads: Disk Transfer Area (DTA)
; Writes: Disk Transfer Area (DTA)
; Calls: BUILD_NAME, FMATCH, PNAME
; NMATCH, BUILD_STAR_NAME, SSUB
SDIR PROC NEAR
PUSH SI ; Need to restore on exit
PUSH DX
CALL BUILD_NAME ; Build the absolute search name
CALL FMATCH ; See if there is a match here
JC sdir2 ; No match, check subdirectories
CALL PNAME ; Write name of match.
sdir1:
CALL NMATCH ; Find the next match
JC sdir2 ; No match, search sub-directories
CALL PNAME ; Match, write absolute name
JMP sdir1 ; Look for the next matching name
sdir2: ; No match, so try sub-directories.
POP DX ; Restore DTA
PUSH DX
CALL BUILD_STAR_NAME ; Search for all directories
CALL FMATCH ; Get first entry
JC SDIR5 ; There are no entries
MOV SI,DX ; Put address of DTA into SI
TEST [SI].ATTRIBUTE,10H ; Is it a directory entry?
JNZ SDIR4 ; Yes, then search sub-directory
SDIR3:
CALL NMATCH ; No, then find the next match
JC SDIR5 ; There are no more entries
TEST [SI].ATTRIBUTE,10H ; Is this a directory?
JZ SDIR3 ; No, then try again
SDIR4:
CMP [SI].NAME_FOUND,'.' ; Is this a . or .. directory?
JE SDIR3 ; Yes, skip to next directory
CALL SSUB ; Search the sub-directory
PUSH AX ; Now reset the DTA
MOV AH,1AH
INT 21H
POP AX
JMP SDIR3
SDIR5:
POP DX
POP SI
RET
SDIR ENDP
; This procedure searches the subdirectory whose name is in the DTA
;
; DS:BX End of the current path name
; DS:[DX].NAME_FOUND Name of subdirectory for search
; Reads: PATH_NAME
; Writes: PATH_NAME
; Calls: SDIR
SSUB PROC NEAR
PUSH DI
PUSH SI
PUSH AX
PUSH BX
CLD ; Set for increment
MOV SI,DX ; Put address of DTA into SI
ADD SI,OFFSET NAME_FOUND ; Set to start of sub-directory name
MOV DI,BX ; DS:DI -- 0 at end of path name
ssub1: ; Copy sub-directory to path name
LODSB ; Copy one character
STOSB
OR AL,AL ; Was it a 0?
JNZ ssub1 ; No, keep copying
MOV BX,DI ; Set BX to end of new path name
STD ; Set flag for decrement
STOSB ; Store a 0 at end of string
MOV AL,'\'
STOSB ; Place '\' at end of path name
CALL SDIR ; Search this new path
POP BX ; Restore the old end-of-path
MOV BYTE PTR [BX],0 ; And store a zero here
POP AX
POP SI
POP DI
RET
SSUB ENDP
; This procedure prints the matched name after the path name
;
; DS:DX Pointer to current disk transfer area
;
; Reads: PATH_NAME, NAME_FOUND (in DTA)
; Calls: pasciiz, CRLF
PNAME PROC NEAR
PUSH AX
PUSH DX
MOV DX,OFFSET PATH_NAME
MOV AL,[BX] ; Save character at end of path
MOV BYTE PTR [BX],0 ; Set for end of string
CALL pasciiz
MOV [BX],AL ; Restore character
POP DX ; Recover old pointer
PUSH DX
ADD DX,OFFSET NAME_FOUND
CALL pasciiz
CALL CRLF
; pause at each screenful of files found
inc match_count ; count names displayed
push ax
push bx
mov ax,match_count
mov dx,0
mov cx,18h ; 18h = 24 decimal
div cx ; ax/cx
and dx,dx ; any bits set to 1 indicate a remainder,
jnz PNAME9 ; so pause and display a message
mov dx,offset Press_a_Key1
mov ah,09h
int 21h
mov ah,08h
int 21h
mov dx,offset Press_a_Key2
mov ah,09h
int 21h
PNAME9:
pop bx
pop ax
POP DX
POP AX
RET
PNAME ENDP
; This procedure builds an absolute search name from PATH_NAME
; followed by FILE_NAME.
;
; Reads: FILE_NAME
; Calls: BUILD to build the name
BUILD_NAME PROC NEAR
PUSH SI
MOV SI,OFFSET FILE_NAME
CALL BUILD
POP SI
RET
BUILD_NAME ENDP
BUILD_STAR_NAME PROC NEAR
PUSH SI
MOV SI,OFFSET STAR_NAME
CALL BUILD
POP SI
RET
BUILD_STAR_NAME ENDP
; This procedure appends the string at DS:SI to PATH_NAME in
; PATH_NAME. It knows where the path name ends from knowing how
; long PATH_NAME is.
;
; DS:SI Name of file
; DS:BX End of PATH_NAME
;
; Reads: DS:SI
; Writes: PATH_NAME
BUILD PROC NEAR
PUSH AX
PUSH DI
MOV DI,BX
CLD ; Set direction for increment
build1:
LODSB ; Copy one character of name
STOSB
OR AL,AL ; End of string yet?
JNZ build1 ; No, keep copying
POP DI
POP AX
RET
BUILD ENDP
; This procedure finds the first match between the name given by
; DS:DX and the directory entries found in the directory PATH_NAME.
;
; DS:DX Pointer to current disk transfer area
; Returns:
; CF 0 A match was found
; 1 No match found
; AX Error code returned:
; 2 File not found
; 18 No more files
; DS:DX Pointer to new disk transfer area
;
; Reads: PATH_NAME
; Writes: dbuff
FMATCH PROC NEAR
PUSH CX
CMP DX,0 ; First one?
JA allocate ; No, then allocate space
MOV DX,OFFSET dbuff-TYPE DTA
allocate:
add dx,type DTA ; no, then allocate room for new DTA
; Bitfields for file attributes:
;Bit(s) Description (Table 01420)
; 7 shareable (Novell NetWare)
; 7 pending deleted files (Novell DOS, OpenDOS)
; 6 unused
; 5 archive
; 4 directory
; 3 volume label
; execute-only (Novell NetWare)
; 2 system
; 1 hidden
; 0 read-only
mov cx,00010111b ; search for ALL files and dirs
MOV AH,1AH ; Set disk transfer address
INT 21H
PUSH DX ; Need DX for address of search name
MOV DX,OFFSET PATH_NAME
MOV AH,4EH ; Call for "find first match"
INT 21H
POP DX
POP CX
RET ; Return with carry flag info
FMATCH ENDP
; Get next match for filename
; (very similar to Get first match routine)
; Returns:
; CF 0 A match was found
; 1 No match found
; AX Error code returned:
; 2 File not found
; 18 No more files
;
; Reads: PATH_NAME
; Writes: dbuff
NMATCH PROC NEAR
PUSH CX
PUSH DX
MOV DX,OFFSET PATH_NAME
MOV CX,10H ; Attribute for files and directories
MOV AH,4FH ; Call for "Find next match"
INT 21H
POP DX
POP CX
RET ; Return with carry flag intact
NMATCH ENDP
; Send CRLF sequence to the screen.
CRLF PROC NEAR
PUSH AX
PUSH DX
MOV AH,02
MOV DL,0AH
INT 21H
MOV DL,0DH
INT 21H
POP DX
POP AX
RET
CRLF ENDP
; Display ASCIIZ string
; Call with DS:DX = string addr
pasciiz PROC NEAR
PUSH AX
PUSH DX
PUSH SI
CLD ; Set direction for increment
MOV SI,DX ; Set up pointer to string
MOV AH,2
pasciiz1:
LODSB ; Get character
or al,al ; if zero,all done
jz pasciiz2
MOV DL,AL
INT 21H ; Write one character
jmp pasciiz1 ; loop till string exhausted
pasciiz2:
POP SI
POP DX
POP AX
RET
pasciiz ENDP
infile proc near ; process name of input file
; DS:SI <- addr command line
mov si,offset command
; ES:DI <- addr filespec buffer
mov di,offset FILE_NAME
cld
lodsb ; any command line present?
or al,al ; return error status if not.
jz infile4
infile1: ; scan over leading blanks
lodsb ; to file name
cmp al,cr ; if we hit carriage return
jz infile4 ; filename is missing.
cmp al,20h ; is this a blank?
jz infile1 ; if so keep scanning.
xor ah,ah ; reset "." found flag
; found first char of name
infile2:
cmp al,'\' ; if slash,reset "." flag
jne infile22
xor ah,ah
infile22: ; check if extension specified
cmp al,'.'
jne infile24
inc ah
infile24:
stosb ; move last char. to output
; file name buffer.
lodsb ; check next character, found
cmp al,cr ; carriage return yet?
je infile3 ; yes,exit with success code
cmp al,'/' ; or if we hit a switch delimiter
jne infile26
infile25:
lodsb ; get the switch char and save it
or al,20h ; force to lower case
mov byte ptr es:switch,al
jmp infile3 ; then jump to finish up
infile26:
cmp al,20h ; is this a blank?
jne infile2 ; if not keep moving chars.
infile27:
lodsb ; search up to end, in case of switch
cmp al,'/'
je infile25 ; found switch,go save it
cmp al,cr
jne infile27 ; otherwise, fscan until CR found
infile3: ; found end of input name
or ah,ah ; was "." found?
jnz infile35 ; yes,jump
mov al,'.' ; no,force ext to wildcard
stosb
mov al,'*'
stosb
infile35:
xor al,al ; store trailing null byte
stosb ; exit with CY=0 as success flag
clc
ret
infile4: ; exit with carry =1
stc ; for error flag
ret
infile endp
cseg ends
data segment para public 'DATA'
STAR_NAME db '*.*',0
PATH_NAME db '\',0
db 131 dup (0) ; Space for 128 character path name
FILE_NAME db 13 dup (0) ; Save room for full DOS file name
msg1 db cr,lf
db ' WHERE Fast File Finder (c) Copyright Andrew Kennedy 2004'
db cr,lf
db cr,lf
db ' WHERE *.asm'
db cr,lf
db cr,lf,eom
msg2 db cr,lf
db 'No match found.'
db cr,lf,eom
Press_a_Key1 db '-- Press a key --',eom
Press_a_Key2 db cr,' ',cr,eom
match_count dw 0 ; number of filenames matching
; input filespec
switch db 0 ; char following / saved here
dbuff equ $ ; this starts the scratch area
; which will be used as search
; buffers. It is right under
; the stack, which is made very
; large to give it room.
data ends
stak segment para stack 'STACK' ; large stack for increased speed
db 32768 dup (?)
stak ends
end whereis
Under DOS, the system Control-Break handler is supposed to set an internal flag that causes the Ctrl-Break to be interpreted as Ctrl-C. Testing under Windows 2000 Ctrl-Break has no effect, but Ctrl-C behaves normally, terminating the program if Ctrl-C is pressed during a system I/O operation. Terminating a program in this way is not generally good, because the program has no chance to clean up after itself. This is why DOS provided an easy method of installing a Control-C handler, so the program could be notified before it was terminated. Since Ctrl-Break is apparently ignored by Windows, I think the program would need to install its own keyboard handler to intercept the Ctrl-Break directly. This would have the beneficial side affect of allowing you to detect Ctrl-Break at any time, instead of only during system I/O operations (or other system operations if BREAK = ON).
You really should try to use code tags for posting anything other than very short pieces of code.
Quote from: MichaelW on April 03, 2006, 02:42:45 AM
I think the program would need to install its own keyboard handler to intercept the Ctrl-Break directly. This would have the beneficial side affect of allowing you to detect Ctrl-Break at any time, instead of only during system I/O operations (or other system operations if BREAK = ON).
You really should try to use code tags for posting anything other than very short pieces of code.
I forgot the reason for using code tags. All the code shows up in all my posts.
I found this macro but can't figure out where to put it so it compiles correctly. It has a problem with the
model directive.
I would like to get the code converted to this style.
.model small
.stack 200h
.data
.code
CtrlBreak MACRO addr
MOV AX,3301h
IFDIFI <addr>,<DX>
MOV DL,1
INT 21h ; BREAK ON
LEA DX,[&addr]
ELSE
PUSH DX
MOV DL,1
INT 21h ; BREAK ON
POP DX
ENDIF
IF @MODEL NE 1
PUSH DS
MOV AX,CS
MOV DS,AX
MOV AX,2523h
INT 21h
POP DS
ELSE
MOV AX,2523h
INT 21h ;set int vector
ENDIF
ENDM CtrlBreak
.data
.code
start:
mov ax,@data
mov ds,ax
CtrlBreak Break_Handler
mov ax,4c00h
int 21h
Break_Handler:
; do cleanup here Not sure what that involves ?
You can just modify your previous post with the "modify" button instead of posting it again. You can do it with all your posts if you want to.
Andy,
The macro seems to work correctly, but I don't think it will allow you to use Ctrl-Break to stop the running program. On my Windows 2000 system Ctrl-Break does not cause the Ctrl-C handler to be called, and I don't see any option in the program properties that will change this behavior. Ctrl-Break might work correctly under Windows 9x, but if it does not under Windows 2000, it probably will not under Windows XP. Despite the misleading name, the operation labeled BREAK ON does not enable Ctrl-Break checking. When the Ctrl-C Check Flag (Microsoft's name for the flag that is controlled by Function 3301h) is clear (the default unless the flag was set from config.sys), the system checks for Ctrl-C only while processing character I/O functions. When the Ctrl-C Check Flag is set, Ctrl-C checking is extended to other I/O functions (per Microsoft this includes disk operations).
So by setting this flag you could reasonably use Ctrl-C to stop the running program. Another simpler method would be to call one of the BIOS functions that checks for a key (without waiting) somewhere near the top of your SDIR procedure. If the function indicates that the user has pressed a key (any key), you could display a Yes/No prompt, and let the user decide whether to continue or exit.
BTW, no cleanup is necessary for either the Ctrl-C (Interrupt 23h) or Critical Error (Interrupt 24h) handlers, because DOS restores these vectors (and only these vectors) when the program terminates, using values that are stored in the PSP.