1 /* Copyright (C) 2002, 2003, 2004, 2005, 2007
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. */
36 #include "libgfortran.h"
40 static const st_option access_opt[] = {
41 {"sequential", ACCESS_SEQUENTIAL},
42 {"direct", ACCESS_DIRECT},
43 {"append", ACCESS_APPEND},
44 {"stream", ACCESS_STREAM},
48 static const st_option action_opt[] =
50 { "read", ACTION_READ},
51 { "write", ACTION_WRITE},
52 { "readwrite", ACTION_READWRITE},
56 static const st_option blank_opt[] =
58 { "null", BLANK_NULL},
59 { "zero", BLANK_ZERO},
63 static const st_option delim_opt[] =
65 { "none", DELIM_NONE},
66 { "apostrophe", DELIM_APOSTROPHE},
67 { "quote", DELIM_QUOTE},
71 static const st_option form_opt[] =
73 { "formatted", FORM_FORMATTED},
74 { "unformatted", FORM_UNFORMATTED},
78 static const st_option position_opt[] =
80 { "asis", POSITION_ASIS},
81 { "rewind", POSITION_REWIND},
82 { "append", POSITION_APPEND},
86 static const st_option status_opt[] =
88 { "unknown", STATUS_UNKNOWN},
91 { "replace", STATUS_REPLACE},
92 { "scratch", STATUS_SCRATCH},
96 static const st_option pad_opt[] =
103 static const st_option convert_opt[] =
105 { "native", CONVERT_NATIVE},
106 { "swap", CONVERT_SWAP},
107 { "big_endian", CONVERT_BIG},
108 { "little_endian", CONVERT_LITTLE},
112 /* Change the modes of a file, those that are allowed * to be
116 edit_modes (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
118 /* Complain about attempts to change the unchangeable. */
120 if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
121 u->flags.status != flags->status)
122 generate_error (&opp->common, ERROR_BAD_OPTION,
123 "Cannot change STATUS parameter in OPEN statement");
125 if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
126 generate_error (&opp->common, ERROR_BAD_OPTION,
127 "Cannot change ACCESS parameter in OPEN statement");
129 if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
130 generate_error (&opp->common, ERROR_BAD_OPTION,
131 "Cannot change FORM parameter in OPEN statement");
133 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
134 && opp->recl_in != u->recl)
135 generate_error (&opp->common, ERROR_BAD_OPTION,
136 "Cannot change RECL parameter in OPEN statement");
138 if (flags->action != ACTION_UNSPECIFIED && u->flags.action != flags->action)
139 generate_error (&opp->common, ERROR_BAD_OPTION,
140 "Cannot change ACTION parameter in OPEN statement");
142 /* Status must be OLD if present. */
144 if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
145 flags->status != STATUS_UNKNOWN)
147 if (flags->status == STATUS_SCRATCH)
148 notify_std (&opp->common, GFC_STD_GNU,
149 "OPEN statement must have a STATUS of OLD or UNKNOWN");
151 generate_error (&opp->common, ERROR_BAD_OPTION,
152 "OPEN statement must have a STATUS of OLD or UNKNOWN");
155 if (u->flags.form == FORM_UNFORMATTED)
157 if (flags->delim != DELIM_UNSPECIFIED)
158 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
159 "DELIM parameter conflicts with UNFORMATTED form in "
162 if (flags->blank != BLANK_UNSPECIFIED)
163 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
164 "BLANK parameter conflicts with UNFORMATTED form in "
167 if (flags->pad != PAD_UNSPECIFIED)
168 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
169 "PAD parameter conflicts with UNFORMATTED form in "
173 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
175 /* Change the changeable: */
176 if (flags->blank != BLANK_UNSPECIFIED)
177 u->flags.blank = flags->blank;
178 if (flags->delim != DELIM_UNSPECIFIED)
179 u->flags.delim = flags->delim;
180 if (flags->pad != PAD_UNSPECIFIED)
181 u->flags.pad = flags->pad;
184 /* Reposition the file if necessary. */
186 switch (flags->position)
188 case POSITION_UNSPECIFIED:
192 case POSITION_REWIND:
193 if (sseek (u->s, 0) == FAILURE)
196 u->current_record = 0;
200 case POSITION_APPEND:
201 if (sseek (u->s, file_length (u->s)) == FAILURE)
204 if (flags->access != ACCESS_STREAM)
205 u->current_record = 0;
207 u->endfile = AT_ENDFILE; /* We are at the end. */
211 generate_error (&opp->common, ERROR_OS, NULL);
219 /* Open an unused unit. */
222 new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
226 char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
228 /* Change unspecifieds to defaults. Leave (flags->action ==
229 ACTION_UNSPECIFIED) alone so open_external() can set it based on
230 what type of open actually works. */
232 if (flags->access == ACCESS_UNSPECIFIED)
233 flags->access = ACCESS_SEQUENTIAL;
235 if (flags->form == FORM_UNSPECIFIED)
236 flags->form = (flags->access == ACCESS_SEQUENTIAL)
237 ? FORM_FORMATTED : FORM_UNFORMATTED;
240 if (flags->delim == DELIM_UNSPECIFIED)
241 flags->delim = DELIM_NONE;
244 if (flags->form == FORM_UNFORMATTED)
246 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
247 "DELIM parameter conflicts with UNFORMATTED form in "
253 if (flags->blank == BLANK_UNSPECIFIED)
254 flags->blank = BLANK_NULL;
257 if (flags->form == FORM_UNFORMATTED)
259 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
260 "BLANK parameter conflicts with UNFORMATTED form in "
266 if (flags->pad == PAD_UNSPECIFIED)
267 flags->pad = PAD_YES;
270 if (flags->form == FORM_UNFORMATTED)
272 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
273 "PAD parameter conflicts with UNFORMATTED form in "
279 if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
281 generate_error (&opp->common, ERROR_OPTION_CONFLICT,
282 "ACCESS parameter conflicts with SEQUENTIAL access in "
287 if (flags->position == POSITION_UNSPECIFIED)
288 flags->position = POSITION_ASIS;
291 if (flags->status == STATUS_UNSPECIFIED)
292 flags->status = STATUS_UNKNOWN;
296 if (flags->access == ACCESS_DIRECT
297 && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
299 generate_error (&opp->common, ERROR_MISSING_OPTION,
300 "Missing RECL parameter in OPEN statement");
304 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
306 generate_error (&opp->common, ERROR_BAD_OPTION,
307 "RECL parameter is non-positive in OPEN statement");
311 switch (flags->status)
314 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
320 generate_error (&opp->common, ERROR_BAD_OPTION,
321 "FILE parameter must not be present in OPEN statement");
328 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
332 opp->file_len = sprintf(opp->file, "fort.%d", (int) opp->common.unit);
336 internal_error (&opp->common, "new_unit(): Bad status");
339 /* Make sure the file isn't already open someplace else.
340 Do not error if opening file preconnected to stdin, stdout, stderr. */
343 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
344 u2 = find_file (opp->file, opp->file_len);
346 && (options.stdin_unit < 0 || u2->unit_number != options.stdin_unit)
347 && (options.stdout_unit < 0 || u2->unit_number != options.stdout_unit)
348 && (options.stderr_unit < 0 || u2->unit_number != options.stderr_unit))
351 generate_error (&opp->common, ERROR_ALREADY_OPEN, NULL);
360 s = open_external (opp, flags);
364 path = (char *) gfc_alloca (opp->file_len + 1);
365 msg = (char *) gfc_alloca (opp->file_len + 51);
366 unpack_filename (path, opp->file, opp->file_len);
371 st_sprintf (msg, "File '%s' does not exist", path);
375 st_sprintf (msg, "File '%s' already exists", path);
379 st_sprintf (msg, "Permission denied trying to open file '%s'", path);
383 st_sprintf (msg, "'%s' is a directory", path);
390 generate_error (&opp->common, ERROR_OS, msg);
394 if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
395 flags->status = STATUS_OLD;
397 /* Create the unit structure. */
399 u->file = get_mem (opp->file_len);
400 if (u->unit_number != opp->common.unit)
401 internal_error (&opp->common, "Unit number changed");
405 u->endfile = NO_ENDFILE;
407 u->current_record = 0;
413 if (flags->position == POSITION_APPEND)
415 if (sseek (u->s, file_length (u->s)) == FAILURE)
416 generate_error (&opp->common, ERROR_OS, NULL);
417 u->endfile = AT_ENDFILE;
420 /* Unspecified recl ends up with a processor dependent value. */
422 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
424 u->flags.has_recl = 1;
425 u->recl = opp->recl_in;
426 u->recl_subrecord = u->recl;
427 u->bytes_left = u->recl;
431 u->flags.has_recl = 0;
432 u->recl = max_offset;
433 if (compile_options.max_subrecord_length)
435 u->recl_subrecord = compile_options.max_subrecord_length;
439 switch (compile_options.record_marker)
443 case sizeof (GFC_INTEGER_4):
444 u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
447 case sizeof (GFC_INTEGER_8):
448 u->recl_subrecord = max_offset - 16;
452 runtime_error ("Illegal value for record marker");
458 /* If the file is direct access, calculate the maximum record number
459 via a division now instead of letting the multiplication overflow
462 if (flags->access == ACCESS_DIRECT)
463 u->maxrec = max_offset / u->recl;
465 if (flags->access == ACCESS_STREAM)
467 u->maxrec = max_offset;
472 memmove (u->file, opp->file, opp->file_len);
473 u->file_len = opp->file_len;
475 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
476 free_mem (opp->file);
481 /* Free memory associated with a temporary filename. */
483 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
484 free_mem (opp->file);
493 /* Open a unit which is already open. This involves changing the
494 modes or closing what is there now and opening the new file. */
497 already_open (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
499 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
501 edit_modes (opp, u, flags);
505 /* If the file is connected to something else, close it and open a
508 if (!compare_file_filename (u, opp->file, opp->file_len))
510 #if !HAVE_UNLINK_OPEN_FILE
512 if (u->file && u->flags.status == STATUS_SCRATCH)
514 path = (char *) gfc_alloca (u->file_len + 1);
515 unpack_filename (path, u->file, u->file_len);
519 if (sclose (u->s) == FAILURE)
522 generate_error (&opp->common, ERROR_OS,
523 "Error closing file in OPEN statement");
533 #if !HAVE_UNLINK_OPEN_FILE
538 u = new_unit (opp, u, flags);
544 edit_modes (opp, u, flags);
550 extern void st_open (st_parameter_open *opp);
551 export_proto(st_open);
554 st_open (st_parameter_open *opp)
558 GFC_INTEGER_4 cf = opp->common.flags;
561 library_start (&opp->common);
563 /* Decode options. */
565 flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
566 find_option (&opp->common, opp->access, opp->access_len,
567 access_opt, "Bad ACCESS parameter in OPEN statement");
569 flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
570 find_option (&opp->common, opp->action, opp->action_len,
571 action_opt, "Bad ACTION parameter in OPEN statement");
573 flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
574 find_option (&opp->common, opp->blank, opp->blank_len,
575 blank_opt, "Bad BLANK parameter in OPEN statement");
577 flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
578 find_option (&opp->common, opp->delim, opp->delim_len,
579 delim_opt, "Bad DELIM parameter in OPEN statement");
581 flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
582 find_option (&opp->common, opp->pad, opp->pad_len,
583 pad_opt, "Bad PAD parameter in OPEN statement");
585 flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
586 find_option (&opp->common, opp->form, opp->form_len,
587 form_opt, "Bad FORM parameter in OPEN statement");
589 flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
590 find_option (&opp->common, opp->position, opp->position_len,
591 position_opt, "Bad POSITION parameter in OPEN statement");
593 flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
594 find_option (&opp->common, opp->status, opp->status_len,
595 status_opt, "Bad STATUS parameter in OPEN statement");
597 /* First, we check wether the convert flag has been set via environment
598 variable. This overrides the convert tag in the open statement. */
600 conv = get_unformatted_convert (opp->common.unit);
602 if (conv == CONVERT_NONE)
604 /* Nothing has been set by environment variable, check the convert tag. */
605 if (cf & IOPARM_OPEN_HAS_CONVERT)
606 conv = find_option (&opp->common, opp->convert, opp->convert_len,
608 "Bad CONVERT parameter in OPEN statement");
610 conv = compile_options.convert;
613 /* We use l8_to_l4_offset, which is 0 on little-endian machines
614 and 1 on big-endian machines. */
622 conv = l8_to_l4_offset ? CONVERT_NATIVE : CONVERT_SWAP;
626 conv = l8_to_l4_offset ? CONVERT_SWAP : CONVERT_NATIVE;
630 internal_error (&opp->common, "Illegal value for CONVERT");
634 flags.convert = conv;
636 if (opp->common.unit < 0)
637 generate_error (&opp->common, ERROR_BAD_OPTION,
638 "Bad unit number in OPEN statement");
640 if (flags.position != POSITION_UNSPECIFIED
641 && flags.access == ACCESS_DIRECT)
642 generate_error (&opp->common, ERROR_BAD_OPTION,
643 "Cannot use POSITION with direct access files");
645 if (flags.access == ACCESS_APPEND)
647 if (flags.position != POSITION_UNSPECIFIED
648 && flags.position != POSITION_APPEND)
649 generate_error (&opp->common, ERROR_BAD_OPTION,
650 "Conflicting ACCESS and POSITION flags in"
653 notify_std (&opp->common, GFC_STD_GNU,
654 "Extension: APPEND as a value for ACCESS in OPEN statement");
655 flags.access = ACCESS_SEQUENTIAL;
656 flags.position = POSITION_APPEND;
659 if (flags.position == POSITION_UNSPECIFIED)
660 flags.position = POSITION_ASIS;
662 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
664 u = find_or_create_unit (opp->common.unit);
668 u = new_unit (opp, u, &flags);
673 already_open (opp, u, &flags);