1 /* Copyright (C) 2002, 2003, 2004, 2005
2 Free Software Foundation, Inc.
3 Contributed by Andy Vaught
5 This file is part of the GNU Fortran 95 runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 In addition to the permissions in the GNU General Public License, the
13 Free Software Foundation gives you unlimited permission to link the
14 compiled version of this file into combinations with other programs,
15 and to distribute those combinations without any restriction coming
16 from the use of this file. (The General Public License restrictions
17 do apply in other respects; for example, they cover modification of
18 the file, and distribution when not linked into a combine
21 Libgfortran is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with Libgfortran; see the file COPYING. If not, write to
28 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
29 Boston, MA 02110-1301, USA. */
35 #include "libgfortran.h"
39 static st_option access_opt
[] = {
40 {"sequential", ACCESS_SEQUENTIAL
},
41 {"direct", ACCESS_DIRECT
},
45 static st_option action_opt
[] =
47 { "read", ACTION_READ
},
48 { "write", ACTION_WRITE
},
49 { "readwrite", ACTION_READWRITE
},
53 static st_option blank_opt
[] =
55 { "null", BLANK_NULL
},
56 { "zero", BLANK_ZERO
},
60 static st_option delim_opt
[] =
62 { "none", DELIM_NONE
},
63 { "apostrophe", DELIM_APOSTROPHE
},
64 { "quote", DELIM_QUOTE
},
68 static st_option form_opt
[] =
70 { "formatted", FORM_FORMATTED
},
71 { "unformatted", FORM_UNFORMATTED
},
75 static st_option position_opt
[] =
77 { "asis", POSITION_ASIS
},
78 { "rewind", POSITION_REWIND
},
79 { "append", POSITION_APPEND
},
83 static st_option status_opt
[] =
85 { "unknown", STATUS_UNKNOWN
},
88 { "replace", STATUS_REPLACE
},
89 { "scratch", STATUS_SCRATCH
},
93 static st_option pad_opt
[] =
101 /* Given a unit, test to see if the file is positioned at the terminal
102 point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
103 This prevents us from changing the state from AFTER_ENDFILE to
107 test_endfile (gfc_unit
* u
)
109 if (u
->endfile
== NO_ENDFILE
&& file_length (u
->s
) == file_position (u
->s
))
110 u
->endfile
= AT_ENDFILE
;
114 /* Change the modes of a file, those that are allowed * to be
118 edit_modes (gfc_unit
* u
, unit_flags
* flags
)
120 /* Complain about attempts to change the unchangeable. */
122 if (flags
->status
!= STATUS_UNSPECIFIED
&&
123 u
->flags
.status
!= flags
->position
)
124 generate_error (ERROR_BAD_OPTION
,
125 "Cannot change STATUS parameter in OPEN statement");
127 if (flags
->access
!= ACCESS_UNSPECIFIED
&& u
->flags
.access
!= flags
->access
)
128 generate_error (ERROR_BAD_OPTION
,
129 "Cannot change ACCESS parameter in OPEN statement");
131 if (flags
->form
!= FORM_UNSPECIFIED
&& u
->flags
.form
!= flags
->form
)
132 generate_error (ERROR_BAD_OPTION
,
133 "Cannot change FORM parameter in OPEN statement");
135 if (ioparm
.recl_in
!= 0 && ioparm
.recl_in
!= u
->recl
)
136 generate_error (ERROR_BAD_OPTION
,
137 "Cannot change RECL parameter in OPEN statement");
139 if (flags
->action
!= ACTION_UNSPECIFIED
&& u
->flags
.access
!= flags
->access
)
140 generate_error (ERROR_BAD_OPTION
,
141 "Cannot change ACTION parameter in OPEN statement");
143 /* Status must be OLD if present. */
145 if (flags
->status
!= STATUS_UNSPECIFIED
&& flags
->status
!= STATUS_OLD
)
146 generate_error (ERROR_BAD_OPTION
,
147 "OPEN statement must have a STATUS of OLD");
149 if (u
->flags
.form
== FORM_UNFORMATTED
)
151 if (flags
->delim
!= DELIM_UNSPECIFIED
)
152 generate_error (ERROR_OPTION_CONFLICT
,
153 "DELIM parameter conflicts with UNFORMATTED form in "
156 if (flags
->blank
!= BLANK_UNSPECIFIED
)
157 generate_error (ERROR_OPTION_CONFLICT
,
158 "BLANK parameter conflicts with UNFORMATTED form in "
161 if (flags
->pad
!= PAD_UNSPECIFIED
)
162 generate_error (ERROR_OPTION_CONFLICT
,
163 "PAD paramter conflicts with UNFORMATTED form in "
167 if (ioparm
.library_return
== LIBRARY_OK
)
169 /* Change the changeable: */
170 if (flags
->blank
!= BLANK_UNSPECIFIED
)
171 u
->flags
.blank
= flags
->blank
;
172 if (flags
->delim
!= DELIM_UNSPECIFIED
)
173 u
->flags
.delim
= flags
->delim
;
174 if (flags
->pad
!= PAD_UNSPECIFIED
)
175 u
->flags
.pad
= flags
->pad
;
178 /* Reposition the file if necessary. */
180 switch (flags
->position
)
182 case POSITION_UNSPECIFIED
:
186 case POSITION_REWIND
:
187 if (sseek (u
->s
, 0) == FAILURE
)
190 u
->current_record
= 0;
193 test_endfile (u
); /* We might be at the end. */
196 case POSITION_APPEND
:
197 if (sseek (u
->s
, file_length (u
->s
)) == FAILURE
)
200 u
->current_record
= 0;
201 u
->endfile
= AT_ENDFILE
; /* We are at the end. */
205 generate_error (ERROR_OS
, NULL
);
211 /* Open an unused unit. */
214 new_unit (unit_flags
* flags
)
218 char tmpname
[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
220 /* Change unspecifieds to defaults. Leave (flags->action ==
221 ACTION_UNSPECIFIED) alone so open_external() can set it based on
222 what type of open actually works. */
224 if (flags
->access
== ACCESS_UNSPECIFIED
)
225 flags
->access
= ACCESS_SEQUENTIAL
;
227 if (flags
->form
== FORM_UNSPECIFIED
)
228 flags
->form
= (flags
->access
== ACCESS_SEQUENTIAL
)
229 ? FORM_FORMATTED
: FORM_UNFORMATTED
;
232 if (flags
->delim
== DELIM_UNSPECIFIED
)
233 flags
->delim
= DELIM_NONE
;
236 if (flags
->form
== FORM_UNFORMATTED
)
238 generate_error (ERROR_OPTION_CONFLICT
,
239 "DELIM parameter conflicts with UNFORMATTED form in "
245 if (flags
->blank
== BLANK_UNSPECIFIED
)
246 flags
->blank
= BLANK_NULL
;
249 if (flags
->form
== FORM_UNFORMATTED
)
251 generate_error (ERROR_OPTION_CONFLICT
,
252 "BLANK parameter conflicts with UNFORMATTED form in "
258 if (flags
->pad
== PAD_UNSPECIFIED
)
259 flags
->pad
= PAD_YES
;
262 if (flags
->form
== FORM_UNFORMATTED
)
264 generate_error (ERROR_OPTION_CONFLICT
,
265 "PAD paramter conflicts with UNFORMATTED form in "
271 if (flags
->position
!= POSITION_ASIS
&& flags
->access
== ACCESS_DIRECT
)
273 generate_error (ERROR_OPTION_CONFLICT
,
274 "ACCESS parameter conflicts with SEQUENTIAL access in "
279 if (flags
->position
== POSITION_UNSPECIFIED
)
280 flags
->position
= POSITION_ASIS
;
283 if (flags
->status
== STATUS_UNSPECIFIED
)
284 flags
->status
= STATUS_UNKNOWN
;
288 if (flags
->access
== ACCESS_DIRECT
&& ioparm
.recl_in
== 0)
290 generate_error (ERROR_MISSING_OPTION
,
291 "Missing RECL parameter in OPEN statement");
295 if (ioparm
.recl_in
!= 0 && ioparm
.recl_in
<= 0)
297 generate_error (ERROR_BAD_OPTION
,
298 "RECL parameter is non-positive in OPEN statement");
302 switch (flags
->status
)
305 if (ioparm
.file
== NULL
)
308 generate_error (ERROR_BAD_OPTION
,
309 "FILE parameter must not be present in OPEN statement");
316 if (ioparm
.file
!= NULL
)
319 ioparm
.file
= tmpname
;
320 ioparm
.file_len
= sprintf(ioparm
.file
, "fort.%d", ioparm
.unit
);
324 internal_error ("new_unit(): Bad status");
327 /* Make sure the file isn't already open someplace else.
328 Do not error if opening file preconnected to stdin, stdout, stderr. */
332 && (options
.stdin_unit
< 0 || u
->unit_number
!= options
.stdin_unit
)
333 && (options
.stdout_unit
< 0 || u
->unit_number
!= options
.stdout_unit
)
334 && (options
.stderr_unit
< 0 || u
->unit_number
!= options
.stderr_unit
))
336 generate_error (ERROR_ALREADY_OPEN
, NULL
);
342 s
= open_external (flags
);
345 generate_error (ERROR_OS
, NULL
);
349 if (flags
->status
== STATUS_NEW
|| flags
->status
== STATUS_REPLACE
)
350 flags
->status
= STATUS_OLD
;
352 /* Create the unit structure. */
354 u
= get_mem (sizeof (gfc_unit
) + ioparm
.file_len
);
355 memset (u
, '\0', sizeof (gfc_unit
) + ioparm
.file_len
);
357 u
->unit_number
= ioparm
.unit
;
361 if (flags
->position
== POSITION_APPEND
)
363 if (sseek (u
->s
, file_length (u
->s
)) == FAILURE
)
364 generate_error (ERROR_OS
, NULL
);
365 u
->endfile
= AT_ENDFILE
;
368 /* Unspecified recl ends up with a processor dependent value. */
370 u
->recl
= (ioparm
.recl_in
!= 0) ? ioparm
.recl_in
: g
.max_offset
;
372 u
->current_record
= 0;
374 /* If the file is direct access, calculate the maximum record number
375 via a division now instead of letting the multiplication overflow
378 if (flags
->access
== ACCESS_DIRECT
)
379 u
->maxrec
= g
.max_offset
/ u
->recl
;
381 memmove (u
->file
, ioparm
.file
, ioparm
.file_len
);
382 u
->file_len
= ioparm
.file_len
;
386 /* The file is now connected. Errors after this point leave the
387 file connected. Curiously, the standard requires that the
388 position specifier be ignored for new files so a newly connected
389 file starts out that the initial point. We still need to figure
390 out if the file is at the end or not. */
396 /* Free memory associated with a temporary filename. */
398 if (flags
->status
== STATUS_SCRATCH
)
399 free_mem (ioparm
.file
);
403 /* Open a unit which is already open. This involves changing the
404 modes or closing what is there now and opening the new file. */
407 already_open (gfc_unit
* u
, unit_flags
* flags
)
409 if (ioparm
.file
== NULL
)
411 edit_modes (u
, flags
);
415 /* If the file is connected to something else, close it and open a
418 if (!compare_file_filename (u
->s
, ioparm
.file
, ioparm
.file_len
))
422 generate_error (ERROR_OS
, "Error closing file in OPEN statement");
430 edit_modes (u
, flags
);
436 extern void st_open (void);
437 export_proto(st_open
);
447 /* Decode options. */
449 flags
.access
= (ioparm
.access
== NULL
) ? ACCESS_UNSPECIFIED
:
450 find_option (ioparm
.access
, ioparm
.access_len
, access_opt
,
451 "Bad ACCESS parameter in OPEN statement");
453 flags
.action
= (ioparm
.action
== NULL
) ? ACTION_UNSPECIFIED
:
454 find_option (ioparm
.action
, ioparm
.action_len
, action_opt
,
455 "Bad ACTION parameter in OPEN statement");
457 flags
.blank
= (ioparm
.blank
== NULL
) ? BLANK_UNSPECIFIED
:
458 find_option (ioparm
.blank
, ioparm
.blank_len
, blank_opt
,
459 "Bad BLANK parameter in OPEN statement");
461 flags
.delim
= (ioparm
.delim
== NULL
) ? DELIM_UNSPECIFIED
:
462 find_option (ioparm
.delim
, ioparm
.delim_len
, delim_opt
,
463 "Bad DELIM parameter in OPEN statement");
465 flags
.pad
= (ioparm
.pad
== NULL
) ? PAD_UNSPECIFIED
:
466 find_option (ioparm
.pad
, ioparm
.pad_len
, pad_opt
,
467 "Bad PAD parameter in OPEN statement");
469 flags
.form
= (ioparm
.form
== NULL
) ? FORM_UNSPECIFIED
:
470 find_option (ioparm
.form
, ioparm
.form_len
, form_opt
,
471 "Bad FORM parameter in OPEN statement");
473 flags
.position
= (ioparm
.position
== NULL
) ? POSITION_UNSPECIFIED
:
474 find_option (ioparm
.position
, ioparm
.position_len
, position_opt
,
475 "Bad POSITION parameter in OPEN statement");
477 flags
.status
= (ioparm
.status
== NULL
) ? STATUS_UNSPECIFIED
:
478 find_option (ioparm
.status
, ioparm
.status_len
, status_opt
,
479 "Bad STATUS parameter in OPEN statement");
482 generate_error (ERROR_BAD_OPTION
, "Bad unit number in OPEN statement");
484 if (flags
.position
!= POSITION_UNSPECIFIED
485 && flags
.access
== ACCESS_DIRECT
)
486 generate_error (ERROR_BAD_OPTION
,
487 "Cannot use POSITION with direct access files");
489 if (flags
.position
== POSITION_UNSPECIFIED
)
490 flags
.position
= POSITION_ASIS
;
492 if (ioparm
.library_return
!= LIBRARY_OK
)
498 u
= find_unit (ioparm
.unit
);
503 already_open (u
, &flags
);