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-5128
frist@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