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 const st_option access_opt[] = {
40 {"sequential", ACCESS_SEQUENTIAL},
41 {"direct", ACCESS_DIRECT},
42 {"append", ACCESS_APPEND},
46 static const st_option action_opt[] =
48 { "read", ACTION_READ},
49 { "write", ACTION_WRITE},
50 { "readwrite", ACTION_READWRITE},
54 static const st_option blank_opt[] =
56 { "null", BLANK_NULL},
57 { "zero", BLANK_ZERO},
61 static const st_option delim_opt[] =
63 { "none", DELIM_NONE},
64 { "apostrophe", DELIM_APOSTROPHE},
65 { "quote", DELIM_QUOTE},
69 static const st_option form_opt[] =
71 { "formatted", FORM_FORMATTED},
72 { "unformatted", FORM_UNFORMATTED},
76 static const st_option position_opt[] =
78 { "asis", POSITION_ASIS},
79 { "rewind", POSITION_REWIND},
80 { "append", POSITION_APPEND},
84 static const st_option status_opt[] =
86 { "unknown", STATUS_UNKNOWN},
89 { "replace", STATUS_REPLACE},
90 { "scratch", STATUS_SCRATCH},
94 static const st_option pad_opt[] =
102 /* Given a unit, test to see if the file is positioned at the terminal
103 point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
104 This prevents us from changing the state from AFTER_ENDFILE to
108 test_endfile (gfc_unit * u)
110 if (u->endfile == NO_ENDFILE && file_length (u->s) == file_position (u->s))
111 u->endfile = AT_ENDFILE;
115 /* Change the modes of a file, those that are allowed * to be
119 edit_modes (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
121 /* Complain about attempts to change the unchangeable. */
123 if (flags->status != STATUS_UNSPECIFIED &&
124 u->flags.status != flags->status)
125 generate_error (&opp->common, ERROR_BAD_OPTION,
126 "Cannot change STATUS parameter in OPEN statement");
128 if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
129 generate_error (&opp->common, ERROR_BAD_OPTION,
130 "Cannot change ACCESS parameter in OPEN statement");
132 if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
133 generate_error (&opp->common, ERROR_BAD_OPTION,
134 "Cannot change FORM parameter in OPEN statement");
136 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
137 && opp->recl_in != u->recl)
138 generate_error (&opp->common, ERROR_BAD_OPTION,
139 "Cannot change RECL parameter in OPEN statement");
141 if (flags->action != ACTION_UNSPECIFIED && u->flags.access != flags->access)
142 generate_error (&opp->common, ERROR_BAD_OPTION,
143 "Cannot change ACTION parameter in OPEN statement");
145 /* Status must be OLD if present. */
147 if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD)
148 generate_error (&opp->common, ERROR_BAD_OPTION,
149 "OPEN statement must have a STATUS of OLD");
151 if (u->flags.form == FORM_UNFORMATTED)
153 if (flags->delim != DELIM_UNSPECIFIED)
154 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
155 "DELIM parameter conflicts with UNFORMATTED form in "
158 if (flags->blank != BLANK_UNSPECIFIED)
159 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
160 "BLANK parameter conflicts with UNFORMATTED form in "
163 if (flags->pad != PAD_UNSPECIFIED)
164 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
165 "PAD paramter conflicts with UNFORMATTED form in "
169 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
171 /* Change the changeable: */
172 if (flags->blank != BLANK_UNSPECIFIED)
173 u->flags.blank = flags->blank;
174 if (flags->delim != DELIM_UNSPECIFIED)
175 u->flags.delim = flags->delim;
176 if (flags->pad != PAD_UNSPECIFIED)
177 u->flags.pad = flags->pad;
180 /* Reposition the file if necessary. */
182 switch (flags->position)
184 case POSITION_UNSPECIFIED:
188 case POSITION_REWIND:
189 if (sseek (u->s, 0) == FAILURE)
192 u->current_record = 0;
195 test_endfile (u); /* We might be at the end. */
198 case POSITION_APPEND:
199 if (sseek (u->s, file_length (u->s)) == FAILURE)
202 u->current_record = 0;
203 u->endfile = AT_ENDFILE; /* We are at the end. */
207 generate_error (&opp->common, ERROR_OS, NULL);
215 /* Open an unused unit. */
218 new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
222 char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
224 /* Change unspecifieds to defaults. Leave (flags->action ==
225 ACTION_UNSPECIFIED) alone so open_external() can set it based on
226 what type of open actually works. */
228 if (flags->access == ACCESS_UNSPECIFIED)
229 flags->access = ACCESS_SEQUENTIAL;
231 if (flags->form == FORM_UNSPECIFIED)
232 flags->form = (flags->access == ACCESS_SEQUENTIAL)
233 ? FORM_FORMATTED : FORM_UNFORMATTED;
236 if (flags->delim == DELIM_UNSPECIFIED)
237 flags->delim = DELIM_NONE;
240 if (flags->form == FORM_UNFORMATTED)
242 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
243 "DELIM parameter conflicts with UNFORMATTED form in "
249 if (flags->blank == BLANK_UNSPECIFIED)
250 flags->blank = BLANK_NULL;
253 if (flags->form == FORM_UNFORMATTED)
255 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
256 "BLANK parameter conflicts with UNFORMATTED form in "
262 if (flags->pad == PAD_UNSPECIFIED)
263 flags->pad = PAD_YES;
266 if (flags->form == FORM_UNFORMATTED)
268 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
269 "PAD paramter conflicts with UNFORMATTED form in "
275 if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
277 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
278 "ACCESS parameter conflicts with SEQUENTIAL access in "
283 if (flags->position == POSITION_UNSPECIFIED)
284 flags->position = POSITION_ASIS;
287 if (flags->status == STATUS_UNSPECIFIED)
288 flags->status = STATUS_UNKNOWN;
292 if (flags->access == ACCESS_DIRECT
293 && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
295 generate_error (&opp->common, ERROR_MISSING_OPTION,
296 "Missing RECL parameter in OPEN statement");
300 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
302 generate_error (&opp->common, ERROR_BAD_OPTION,
303 "RECL parameter is non-positive in OPEN statement");
307 switch (flags->status)
310 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
316 generate_error (&opp->common, ERROR_BAD_OPTION,
317 "FILE parameter must not be present in OPEN statement");
324 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
328 opp->file_len = sprintf(opp->file, "fort.%d", opp->common.unit);
332 internal_error (&opp->common, "new_unit(): Bad status");
335 /* Make sure the file isn't already open someplace else.
336 Do not error if opening file preconnected to stdin, stdout, stderr. */
339 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
340 u2 = find_file (opp->file, opp->file_len);
342 && (options.stdin_unit < 0 || u->unit_number != options.stdin_unit)
343 && (options.stdout_unit < 0 || u->unit_number != options.stdout_unit)
344 && (options.stderr_unit < 0 || u->unit_number != options.stderr_unit))
347 generate_error (&opp->common, ERROR_ALREADY_OPEN, NULL);
356 s = open_external (opp, flags);
359 generate_error (&opp->common, ERROR_OS, NULL);
363 if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
364 flags->status = STATUS_OLD;
366 /* Create the unit structure. */
368 u->file = get_mem (opp->file_len);
369 if (u->unit_number != opp->common.unit)
370 internal_error (&opp->common, "Unit number changed");
374 u->endfile = NO_ENDFILE;
376 u->current_record = 0;
381 if (flags->position == POSITION_APPEND)
383 if (sseek (u->s, file_length (u->s)) == FAILURE)
384 generate_error (&opp->common, ERROR_OS, NULL);
385 u->endfile = AT_ENDFILE;
388 /* Unspecified recl ends up with a processor dependent value. */
390 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
391 u->recl = opp->recl_in;
393 u->recl = max_offset;
395 /* If the file is direct access, calculate the maximum record number
396 via a division now instead of letting the multiplication overflow
399 if (flags->access == ACCESS_DIRECT)
400 u->maxrec = max_offset / u->recl;
402 memmove (u->file, opp->file, opp->file_len);
403 u->file_len = opp->file_len;
405 /* Curiously, the standard requires that the
406 position specifier be ignored for new files so a newly connected
407 file starts out that the initial point. We still need to figure
408 out if the file is at the end or not. */
412 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
413 free_mem (opp->file);
418 /* Free memory associated with a temporary filename. */
420 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
421 free_mem (opp->file);
430 /* Open a unit which is already open. This involves changing the
431 modes or closing what is there now and opening the new file. */
434 already_open (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
436 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
438 edit_modes (opp, u, flags);
442 /* If the file is connected to something else, close it and open a
445 if (!compare_file_filename (u, opp->file, opp->file_len))
447 #if !HAVE_UNLINK_OPEN_FILE
449 if (u->file && u->flags.status == STATUS_SCRATCH)
451 path = (char *) gfc_alloca (u->file_len + 1);
452 unpack_filename (path, u->file, u->file_len);
456 if (sclose (u->s) == FAILURE)
459 generate_error (&opp->common, ERROR_OS,
460 "Error closing file in OPEN statement");
470 #if !HAVE_UNLINK_OPEN_FILE
475 u = new_unit (opp, u, flags);
481 edit_modes (opp, u, flags);
487 extern void st_open (st_parameter_open *opp);
488 export_proto(st_open);
491 st_open (st_parameter_open *opp)
495 GFC_INTEGER_4 cf = opp->common.flags;
497 library_start (&opp->common);
499 /* Decode options. */
501 flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
502 find_option (&opp->common, opp->access, opp->access_len,
503 access_opt, "Bad ACCESS parameter in OPEN statement");
505 flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
506 find_option (&opp->common, opp->action, opp->action_len,
507 action_opt, "Bad ACTION parameter in OPEN statement");
509 flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
510 find_option (&opp->common, opp->blank, opp->blank_len,
511 blank_opt, "Bad BLANK parameter in OPEN statement");
513 flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
514 find_option (&opp->common, opp->delim, opp->delim_len,
515 delim_opt, "Bad DELIM parameter in OPEN statement");
517 flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
518 find_option (&opp->common, opp->pad, opp->pad_len,
519 pad_opt, "Bad PAD parameter in OPEN statement");
521 flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
522 find_option (&opp->common, opp->form, opp->form_len,
523 form_opt, "Bad FORM parameter in OPEN statement");
525 flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
526 find_option (&opp->common, opp->position, opp->position_len,
527 position_opt, "Bad POSITION parameter in OPEN statement");
529 flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
530 find_option (&opp->common, opp->status, opp->status_len,
531 status_opt, "Bad STATUS parameter in OPEN statement");
533 if (opp->common.unit < 0)
534 generate_error (&opp->common, ERROR_BAD_OPTION,
535 "Bad unit number in OPEN statement");
537 if (flags.position != POSITION_UNSPECIFIED
538 && flags.access == ACCESS_DIRECT)
539 generate_error (&opp->common, ERROR_BAD_OPTION,
540 "Cannot use POSITION with direct access files");
542 if (flags.access == ACCESS_APPEND)
544 if (flags.position != POSITION_UNSPECIFIED
545 && flags.position != POSITION_APPEND)
546 generate_error (&opp->common, ERROR_BAD_OPTION,
547 "Conflicting ACCESS and POSITION flags in"
550 notify_std (GFC_STD_GNU,
551 "Extension: APPEND as a value for ACCESS in OPEN statement");
552 flags.access = ACCESS_SEQUENTIAL;
553 flags.position = POSITION_APPEND;
556 if (flags.position == POSITION_UNSPECIFIED)
557 flags.position = POSITION_ASIS;
559 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
561 u = find_or_create_unit (opp->common.unit);
565 u = new_unit (opp, u, &flags);
570 already_open (opp, u, &flags);