[comp.lang.pascal] FileExists

NORM%IONAACAD.BITNET@cunyvm.cuny.edu ( Norman Walsh) (02/12/91)

In order to write a FileExists() function, I recommend using either the
FindFirst method (and make sure it's a FILE not a directory or something)
or a GetFAttr (ditto about making sure it's a file) rather than trying
to open the file.  Too many things can go wrong trying to open the file.
Your pgm might be out of file handles or, if the file is read-only, you
have to diddle with the FileMode variable (make sure you put it back)
etc.

                                                        ndw

pp@wsinti01.info.win.tue.nl (Peter Peters) (02/13/91)

I have forgotten who was the initiator of this finfile message chain :-)
but here's my two cents....


What follows is a program that will test the protection/properties of
files/directories. I suppose the original question can be answered
by extracting the right piece of code.
Also a command line switch/pasrameter extraction unit uses-ed by the
program is included.


-------
Program FaTest;
(* check if file attribute of the parameter is set,
   return doserror 0 to indicate check is ok, doserror 1 if not ok *)

Uses
  Dos, TpOpt;

Var
  S        : SearchRec;
  FileAttr : Byte;
  FileName : String;

Procedure ProcessParameters;
Var
  Par : Char;
Begin
  Repeat
    Par := Getopt( 'rRhHsSvVdDaAfF' );
    Case UpCase(Par) Of
      'R' : FileAttr := FileAttr Or ReadOnly;
      'H' : FileAttr := FileAttr Or Hidden;
      'S' : FileAttr := FileAttr Or SysFile;
      'V' : FileAttr := FileAttr Or VolumeId;
      'D' : FileAttr := FileAttr Or Directory;
      'A' : FileAttr := FileAttr Or Archive;
      'F' : FileAttr := FileAttr Or (AnyFile And (Not Directory));
      '?'     : Halt(1);
    End;
  Until Par = EofChar;
  FileName := Argv[Optind];
End;

Begin
  FileAttr := 0;
  ProcessParameters;
  FindFirst (FileName,AnyFile,S);
  If (S.Attr And FileAttr) = 0 Then
    Halt(1);
End.
------
And the uses-ed unit :
------
Unit TPOpt;

Interface

Uses
  Dos;

Const
  EofChar  : Char = ^Z;                        (* End of file character *)
  MaxArg   = 15;

Type
  ArgRange = 0..MaxArg;

Var
  SwitChar : Char;                              (* Dos switch character *)
  OptErr   : Word;           (* Enable/Disable invalid switch detection *)
  OptInd   : Word;                                (* Current Argv index *)
  OptArg   : String;                             (* Argument for switch *)
  Argv     : Array[ArgRange] Of String;          (* Array of parameters *)
  Argc     : ArgRange;                      (* Number of parameters + 1 *)

Procedure ResetOptions;             (* (Re)Initialise option processing *)

Procedure SetEnvOpt ( EnvirOpt : String );    (* Set environment string *)

Function  GetOpt( Parm : String ) : Char;   (* Get a command line switch *)

Implementation

Var
  EnvOpt  : String;  (* Environment variable used as options/parameters *)
  Init    : Boolean;                     (* Initialisation done/needeed *)

Function GetSwitChar : Char;      (* Uses undocumented DOS function 37h *)
Var
  Regs : Registers;
Begin {getswitchar}
  Regs.ax := $3700;
  MsDos (Regs);
  GetSwitChar := Char(Regs.dl);
End {getswitchar};

Procedure SetEnvOpt{( EnvirOpt : String )};
Begin {setenvopt}
   EnvOpt := EnvirOpt;
End {setenvopt};

Function GetWord( Var Options : String ) : String;
Var
  OptS : String;
  Mn   : Byte;
Begin {getword}
  Repeat
    While (Length(Options) > 0) And (Options[1] = ' ') Do
      Delete(Options,1,1);
    Mn := Pos( ' ',Options+' ' );
    OptS := Copy( Options, 1, Mn-1 );
    Options := Copy( Options, Mn+1, 255 );
  Until (Options = '') Or (OptS <> '');
  GetWord := OptS;
End {getword};

Procedure ResetOptions;
Var
  i       : Byte;
  Options : String;
Begin {resetoptions}
  Argc := 0;
  Options := GetEnv( EnvOpt );
  Repeat
    OptArg := GetWord( Options );
    If OptArg[0] > #0 Then
      If OptArg[1] = SwitChar Then
        Begin
          Argv[Argc] := OptArg;
          If OptArg <> '' Then Inc( Argc );
        End {if};
  Until OptArg = '';
  For i := 1 To ParamCount Do
    Begin
      OptArg := ParamStr(i);
      If OptArg[0] > #0 Then
        If OptArg[1] = SwitChar Then
          Begin
            Argv[Argc] := OptArg;
            If OptArg <> '' Then Inc( Argc );
          End {if};
    End {for};
  Options := GetEnv( EnvOpt );
  Repeat
    OptArg := GetWord( Options );
    If OptArg[0] > #0 Then
      If OptArg[1] <> SwitChar Then
        Begin
          Argv[Argc] := OptArg;
          If OptArg <> '' Then Inc( Argc );
        End {if};
  Until OptArg = '';
  For i := 1 To ParamCount Do
    Begin
      OptArg := ParamStr(i);
      If OptArg[0] > #0 Then
        If OptArg[1] <> SwitChar Then
          Begin
            Argv[Argc] := OptArg;
            If OptArg <> '' Then Inc( Argc );
          End {if};
    End {for};
  For i := Argc To MaxArg Do
    Argv[i] := '';
  Init   := False;
  OptInd := 0;
  OptArg := '';
End {resetoptions};

Function GetOpt{( Parm : String ) : Char};
Var
  OptPos : Byte;
Begin {getopt}
  If Init Then ResetOptions;
  If (Optind < Argc) And (Argv[Optind,1] = SwitChar) Then
    Begin
      OptPos := Pos( Argv[Optind,2], Parm );
      If OptPos = 0 Then
        Begin
          If OptErr > 0 Then
            Writeln( ^M^J'Invalid switch : ', Copy( Argv[OptInd], 1, 2 ) );
          GetOpt := '?';
        End {if}
      Else
        Begin
          GetOpt := Argv[Optind,2];
          If (OptPos < Length( Parm )) And (Parm[OptPos+1] = ':') Then
            Begin
              OptArg := Copy( Argv[OptInd], 3, Length( Argv[OptInd] ) );
              If OptArg[1] = '=' Then
                Delete( OptArg, 1, 1 );
            End {if};
        End {else};
      Inc( OptInd );
    End {if}
  Else
    GetOpt := EofChar;
End {getopt};

Begin {main}
 SwitChar := GetSwitChar;
 OptErr   := 1;
 Init     := True;
 EnvOpt   := '';
End {main}.
------

Usage could be : (in a batch file)

fatest /f %1
if errorlevel 1 goto checkdir
echo "file %1 exists
goto exit
:checkdir
fatest /d %1
if errorlevel 1 goto noexist
echo "directory %1 exists"
goto exit
:noexist
echo "%1 is not a file or directory"
:exit


------

Use this stuff as you like, Mention my name if you redistribute it
or use it in a program.

-- 
| Peter Peters                              | UUCP  : pp@win.tue.nl     |
| Eindhoven University of Technology (TUE)  | PHONE : +31-(0)40-474120  |
| Dept. of Mathematics and Computer Science | TUE   : HG 8.82 / 4120    |
| Disclaimer : I said WHAT ???              | VHF   : pa0ppe            |

CDCKAB%EMUVM1.BITNET@cunyvm.cuny.edu ( Karl Brendel) (04/19/91)

In article <15647@dutrun.UUCP>, winfave@dutrun.uucp (Alexander
  Verbraeck) wrote:

>The FileExists function as posted in the "Cursor On/Off Code Plus"
>posting (originating from Dave Sisson) contains a slight but
>extremely boresome error, as far as I can see. My first attempt to
>write a FileExists function contained the same error, and it took me
>quite a while to find it. The original FE routing looked something
>like:

[...deleted...]

>afterward. What's the flaw? Not closing the file in FileExists, which
>occupies a DOS file handler when it exists. What's the solution? Either
>always closing the file between the {$I-} and {$I+} directives, or
>closing it after testing if IOresult reports that the file exists and
>THEN closing the file.
>I used the first method, resulting in the following function:
>
>function FileExists(fn:string) : boolean;
>
>var
>  f : text;
>
>begin
>  {$I-}
>    assign(f,fn);
>    reset(f);
>    close(f);
>    FileExists:=(IOresult=0);
>  {$I+}
>end;

(Alexander Verbraeck's posting provides an opportunity to discuss a
FileExists function. My posting should in no way be taken as a
criticism of his excellent discussion or of his particular coding.)

FileExists functions seem to be enjoying a spurt of popularity on
the net for some reason. :) As Alexander Verbraeck has pointed out,
some popular FileExists functions may have unexpected results. They
may also fail unexpectedly. E.g., if no file handles are available,
Reset will fail, and a Reset-based function will return False. (Does
one ever want to know if a file exists without caring if it can be
opened. Yes. One example is a network semaphore.)

Consider the use of FindFirst for a FileExists function. It works
without requiring a file handle, and can easily be used to check the
existance of directories, volume IDs, etc.:

uses DOS;

function FileExists(var fn : string; attr : word) : Boolean;
var
  sr : SearchRec;
begin {Exists}
  FindFirst(fn,attr,sr);
  FileExists := DosError = 0;
end; {Exists}

If you want this strictly for determining whether "real" files
exist, you can drop attr from the parameters and include an
appropriate value in the body of the function.

+====================================================================+
| Karl Brendel                           Centers for Disease Control |
| Internet: CDCKAB@EMUVM1.BITNET         Epidemiology Program Office |
| Bitnet: CDCKAB@EMUVM1                  Atlanta GA  30093       USA |
|                        Home of Epi Info 5.0                        |
+====================================================================+