News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Stop this program during a search

Started by skywalker, April 03, 2006, 01:56:35 AM

Previous topic - Next topic

skywalker

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
             


MichaelW

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.




eschew obfuscation

skywalker

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 ?



Mincho Georgiev

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.

MichaelW

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.

eschew obfuscation