frist@ccu.umanitoba.ca (03/16/90)
Here's a problem that has had me beating my head against the wall:
In SUN Pascal, how do you test to see if a file exists, before 'reset'ting
or 'rewrite'ing that file?
All other Pascal implementations I have used in the last 12 years have
either provided an explicit command (if exists(<filename>) then ...) or
provided a way of recovering from the error that occurs when you try to
open a non-existant file. Not so on SUN.
There are two possible approaches that I can see, and both involve calling
c subroutines from Pascal.
I. Use the c 'system' function to determine if the file is present.
system('ls <filename> > TEMPFILE');
Now, read in TEMPFILE. If TEMPFILE contains '<filename>:not found', then
the file doesn't exist.
I've actually gotten this to work, but there are two important cases
this approach misses.
A. If the filename contains an environment variable that is interpreted
by the shell as a path, the program would detect a mismatch between
the filename it sent to the system, and the name returned by 'ls'.
eg. system('ls $HOME/seq/seq1.data > TEMPFILE')`
would result in '/home/genrl/frist/seq/seq1.data' being written to
TEMPFILE. You could sleaze around this problem by ignoring the
filename in TEMPFILE and just looking for ':not found', but there
is a lot of potential for disaster in this approach.
II. Call the c 'fopen' procedure from Pascal, and try to determine if
the file was opened sucessfully. I have tried this without any success
so far, but it's possible that my very minimal knowledge of c has
prevented me from hitting the correct form. The following subroutine
compiles correctly in SUN Pascal, but generates an error:
const MAXLINE=132;
type CHARARRAY:array[1..MAXLINE] of char;
(* fopen and open are part of the standard c library *)
(* They must be declared in the highest scope of the main program.*)
function fopen(FILENAME:CHARARRAY;FILEMODE:char):char; external c;
function open(FILENAME:CHARARRAY;ACCESS:integer):integer; external c;
(* - - - - - - - - - - - - - - - - - - - - - - - - - - - *)
(* =true if file exists, =false if it doesn't *)
(* A comparable procedure is provided with ATT System V Pascal *)
function EXISTS(FILENAME:CHARARRAY):boolean;
var F:text;
begin (* EXISTS *)
F^:=fopen(FILENAME,'r');
if open(FILENAME,0)=-1 then EXISTS:=false
else EXISTS:=true
end; (* EXISTS *)
When I call EXISTS in a Pascal program, the program crashes at the fopen
statement, giving the message
(name unknown): Reference to an inactive file
This is surprising to me, since even in the event that a file is not
found, fopen should return the pointer value NULL. (What does this mean
to Pascal?) In any event, no error should be generated. Changing the type
of F from text to ^text generates the error
Segmentation fault
and again the program crashes.
I have tried a number of variations on this approach with no success. The
main problem is that the SUN Pascal documentation doesn't really go into
any detail about how types are reconciled between the two languages. For
example, as what type(s) should the fopen and open be declared?
Anyway, if anybody out there can figure this out, let me know. I have a
bunch of programs that depend on this procedure to protect against user
errors.
[[Ed's Note: I haven't tried this, or looked at it extensively, but the
STAT series of file routines for C might be another approach you might
consider. They are specifically designed to return file status (without
having to open/close or redirect output). -bdg]]
Brian Fristensky frist@ccu.umanitoba.ca
Assistant Professor
Dept. of Plant Science
University of Manitoba
Winnipeg, MB R3T 2N2 CANADA
Office phone: 204-474-6085
FAX: 204-275-5128frist@ccu.umanitoba.ca (03/22/90)
Last week, I posted the question
In SUN Pascal, how do you test to see if a file exists, before 'reset'ting
or 'rewrite'ing that file?
Many of the replies suggested calling the c access() procedure from
Pascal, while others sent c subroutines, or ideas for c subroutines, that
could be compiled separately and linked by the pc command. Below is what
I think is the simplest solution. Thanks a lot to all who replied to my
query.
const MAXLINE= 132;
type (* LINE simulates dynamic character strings in standard Pascal *)
CHARARRAY = packed array[1..MAXLINE] of char;
LINE = record
STR:CHARARRAY;
LEN:integer
end;
(* The c function access is found in sys/file.h. access must be declared in
the outermost scope of the Pascal program. See access (2) manual pages *)
function access(PATH:CHARARRAY; MODE:integer):integer; external c;
(* The following function may appear in any scope: *)
(* - - - - - - - - - - - - - - - - - - - - - - - - - - - *)
(* =true if file exists, =false if it doesn't *)
(* A comparable procedure is provided with ATT System V Pascal *)
(* A special thank you to Mark Foster, CIS Rearch Computing, Univ. of Penn.
and Glenn Gribble of Synaptics Inc. for showing me how to use access()
within Pascal programs. B.F. *)
function EXISTS(FILENAME:LINE):boolean;
const F_OK=0; (* checks if file exists *)
begin (* EXISTS *)
with FILENAME do begin
STR[LEN+1]:=chr(0); (* c strings terminate with null *)
if access(STR,F_OK)=-1 then EXISTS:=false
else EXISTS:=true
end (* with FILENAME *)
end; (* EXISTS *)
Brian Fristensky frist@ccu.umanitoba.ca
Assistant Professor
Dept. of Plant Science
University of Manitoba
Winnipeg, MB R3T 2N2 CANADA
Office phone: 204-474-6085
FAX: 204-275-5128