'===========================================================================
' Subject: FILE EXIST ROUTINE                 Date: 12-12-89 (00:00)       
'  Author: Randy Sharpe                       Code: QB, PDS                
'  Origin: harryst@castel.nl                Packet: DOS.ABC
'===========================================================================
'                    DOS Interrupt File Exist Routine
'                      Written for QuickBASIC 4.5
'                     Randy Sharpe  CIS 72425,1247
'                          December 12, 1989
'
'*****************************************************************************
'                   Include the data within the "***" 's in the
'                           top of your program
'      You may eliminate this block by instead adding the metacommand:
'      "$include qb.bi in your code, but it contains some extra goodies
'      you probably won't need.
'      If running within QuickBASIC environment, you must load quickbasic
'      using "/l qb.qlb"; this will load the "quick library" version of
'      qb.lib. When producing an exe file from OUTSIDE of QuickBASIC using
'      bc and link, be sure to "link-in" QB.LIB. Typically, this is
'      accomplished by typing the following on the LIBRARIES line when
'      prompted by LINK:
'
'              BCOM45 + QB (+ any other libs you may have)
'      This will link in the necessary object code for CALL INTERRUPT.
'      If producing an EXE from within QuickBASIC environment, all will
'      be handled automatically.
'
TYPE RegType
     ax    AS INTEGER    'AH/AL regs
     bx    AS INTEGER    'BH/BL regs
     cx    AS INTEGER    'CH/CL regs
     dx    AS INTEGER    'DH/DL regs
     bp    AS INTEGER    'base pointer
     si    AS INTEGER    'source index reg
     di    AS INTEGER    'destination index reg
     Flags AS INTEGER    'flags reg
END TYPE

DIM SHARED InRegs AS RegType, OutRegs AS RegType, True, False

DECLARE SUB DoesFileExist (FileExists!, FileName$)
DECLARE SUB INTERRUPT (IntNumber AS INTEGER, InRegs AS RegType, OutRegs AS RegType)

False = 0
True = NOT False

'****************************************************************************
'                               Main
'assign the filename string to search for-can contain path/drive
'such as c:\editor\test.txt-if you intend to allow * and ?, your code
'in DoesFileExist must be set up for multiple occurences
CLS
INPUT "Please Enter File Name To Search For: ", FileName$

CALL DoesFileExist(FileExists!, FileName$)

'test the exist Boolean to see if we found the file-this is normally
' where we test FileExists! and branch to either a get-file routine
' or error message-below code segment is for testing only
IF FileExists! THEN
   'CALL ReadFile(FileName$)              'call the file read routine
   PRINT FileName$; " Found"              'test purposes
ELSE
   'CALL FileNotFoundErrMsg(FileName$)    'call the error message routine
   PRINT FileName$; " Not Found"          'test purposes
END IF

SUB DoesFileExist (FileExists, FileName$)
'
'----------------------------------------------------------------------------
'
'  Input    : File name to search for in FileName$. This filename may contain
'             drive/path info, but will default to current if absent. It may
'             also contain wildcard and pattern match chars "*" and "?".
'  Process  : Does a DOS INT21, service 4E to find the first occurence (if
'             any) of file string contained in FileName$ in designated path &
'             dir (if you need to find all occurences, you must continue
'             all ensuing searches with INT21H, service 4FH). For a read, we
'             want it to exist, but for a write, we want to give a message if
'             it does exist to make sure user wants to overwrite it. For
'             technical reference for this interrupt, see Microsoft Basic
'             Language Reference.
'  Output   : Exist Boolean in FileExists
'  Coupling : Called by Main
'             Calls DOS Interrupt 21, service 4E
'  Note     : The following is a description of the carry-flag test:
'
'             The following data is returned by INT21 for found/not found:
'
'                 If file is not found:

'                 OutRegs.Flags :  FFFFF003H (-4093D)
'                  F    F    F    F    F    0    0    3
'                 1111 1111 1111 1111 1111 0000 0000 0011 <---this bit = CF
'By AND'ing with  0000 0000 0000 0000 0000 0000 0000 0001
'1H we can test   =======================================
'the carry bit    0000 0000 0000 0000 0000 0000 0000 0001 => bit is set when
'                                                            file not found
'                 If file is found:
'
'                 OutRegs.Flags =  FFFFF003H (-4094D)
'                  F    F    F    F    F    0    0    2
'                 1111 1111 1111 1111 1111 0000 0000 0010 <---this bit = CF
'By AND'ing 1H:   0000 0000 0000 0000 0000 0000 0000 0001
'                 =======================================
'                 0000 0000 0000 0000 0000 0000 0000 0000 => bit is reset when
'                                                            file is found
'
'If you desired to know further details about why file was not found, you
'could perform tests on OutRegs.ax. This would tell you if path not found,
'no such directory, etc.
'
'The above technique may be modified to perform any DOS interrupt, making
'it a powerful (and fast) alternative to other techniques such as SHELL
'
' A WORD ABOUT * and ? - This routine is designed only to give a "there/not
' there indication of a designated file. When using the wildcard and pattern
' match chars * and ?, you are typically doing some operation such as
' a directory or a group delete. As it stands, this routine will only tell
' you that a file does or doesn't exist. For example, if you ask for *.bas,
' it will say that there is or isn't some file with a bas extension. To list
' these files is beyond the scope of this routine, and requires the use
' of another DOS Interrupt 21 service (4FH) within a conditional loop.
'----------------------------------------------------------------------------

   'we will use the default Disk Transfer Area in PSP - you may set
   'your own if desired using INT21(1AH).

   'place a null onto end of the filenme for the DOS interrupt
   IntFileName$ = FileName$ + CHR$(0)

   'put interrupt service # 4E hex (78 dec) into ah, zeros into al
   InRegs.ax = &H4E00
   'put starting segment memory addr of filename into dh & offset addr into
   'dl reg using sadd fn
   InRegs.dx = SADD(IntFileName$)
   'search for "normal" file attributes only, no hidden, system, etc.
   InRegs.cx = &H0
   'call the interrupt
   CALL INTERRUPT(&H21, InRegs, OutRegs)

   'mask off all but carry flag bit of flag reg by 'ANDing' flag reg
   'with 0000000000000001 (1 hex)
   CarryFlag& = (OutRegs.Flags AND &H1)

   'a short-cut way to assign true/falseness, since CF will be 0 or 1
   FileExists! = CarryFlag& - 1

   'another way to test cary flag
   'IF CarryFlag& = 1 THEN
   '  FileExists = False
   'ELSE
   '  FileExists = True
   'END IF

END SUB
