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. */
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;
412 if (flags->position == POSITION_APPEND)
414 if (sseek (u->s, file_length (u->s)) == FAILURE)
415 generate_error (&opp->common, ERROR_OS, NULL);
416 u->endfile = AT_ENDFILE;
419 /* Unspecified recl ends up with a processor dependent value. */
421 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
423 u->flags.has_recl = 1;
424 u->recl = opp->recl_in;
425 u->recl_subrecord = u->recl;
426 u->bytes_left = u->recl;
430 u->flags.has_recl = 0;
431 u->recl = max_offset;
432 if (compile_options.max_subrecord_length)
434 u->recl_subrecord = compile_options.max_subrecord_length;
438 switch (compile_options.record_marker)
442 case sizeof (GFC_INTEGER_4):
443 u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
446 case sizeof (GFC_INTEGER_8):
447 u->recl_subrecord = max_offset - 16;
451 runtime_error ("Illegal value for record marker");
457 /* If the file is direct access, calculate the maximum record number
458 via a division now instead of letting the multiplication overflow
461 if (flags->access == ACCESS_DIRECT)
462 u->maxrec = max_offset / u->recl;
464 if (flags->access == ACCESS_STREAM)
466 u->maxrec = max_offset;
471 memmove (u->file, opp->file, opp->file_len);
472 u->file_len = opp->file_len;
474 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
475 free_mem (opp->file);
480 /* Free memory associated with a temporary filename. */
482 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
483 free_mem (opp->file);
492 /* Open a unit which is already open. This involves changing the
493 modes or closing what is there now and opening the new file. */
496 already_open (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
498 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
500 edit_modes (opp, u, flags);
504 /* If the file is connected to something else, close it and open a
507 if (!compare_file_filename (u, opp->file, opp->file_len))
509 #if !HAVE_UNLINK_OPEN_FILE
511 if (u->file && u->flags.status == STATUS_SCRATCH)
513 path = (char *) gfc_alloca (u->file_len + 1);
514 unpack_filename (path, u->file, u->file_len);
518 if (sclose (u->s) == FAILURE)
521 generate_error (&opp->common, ERROR_OS,
522 "Error closing file in OPEN statement");
532 #if !HAVE_UNLINK_OPEN_FILE
537 u = new_unit (opp, u, flags);
543 edit_modes (opp, u, flags);
549 extern void st_open (st_parameter_open *opp);
550 export_proto(st_open);
553 st_open (st_parameter_open *opp)
557 GFC_INTEGER_4 cf = opp->common.flags;
560 library_start (&opp->common);
562 /* Decode options. */
564 flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
565 find_option (&opp->common, opp->access, opp->access_len,
566 access_opt, "Bad ACCESS parameter in OPEN statement");
568 flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
569 find_option (&opp->common, opp->action, opp->action_len,
570 action_opt, "Bad ACTION parameter in OPEN statement");
572 flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
573 find_option (&opp->common, opp->blank, opp->blank_len,
574 blank_opt, "Bad BLANK parameter in OPEN statement");
576 flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
577 find_option (&opp->common, opp->delim, opp->delim_len,
578 delim_opt, "Bad DELIM parameter in OPEN statement");
580 flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
581 find_option (&opp->common, opp->pad, opp->pad_len,
582 pad_opt, "Bad PAD parameter in OPEN statement");
584 flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
585 find_option (&opp->common, opp->form, opp->form_len,
586 form_opt, "Bad FORM parameter in OPEN statement");
588 flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
589 find_option (&opp->common, opp->position, opp->position_len,
590 position_opt, "Bad POSITION parameter in OPEN statement");
592 flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
593 find_option (&opp->common, opp->status, opp->status_len,
594 status_opt, "Bad STATUS parameter in OPEN statement");
596 /* First, we check wether the convert flag has been set via environment
597 variable. This overrides the convert tag in the open statement. */
599 conv = get_unformatted_convert (opp->common.unit);
601 if (conv == CONVERT_NONE)
603 /* Nothing has been set by environment variable, check the convert tag. */
604 if (cf & IOPARM_OPEN_HAS_CONVERT)
605 conv = find_option (&opp->common, opp->convert, opp->convert_len,
607 "Bad CONVERT parameter in OPEN statement");
609 conv = compile_options.convert;
612 /* We use l8_to_l4_offset, which is 0 on little-endian machines
613 and 1 on big-endian machines. */
621 conv = l8_to_l4_offset ? CONVERT_NATIVE : CONVERT_SWAP;
625 conv = l8_to_l4_offset ? CONVERT_SWAP : CONVERT_NATIVE;
629 internal_error (&opp->common, "Illegal value for CONVERT");
633 flags.convert = conv;
635 if (opp->common.unit < 0)
636 generate_error (&opp->common, ERROR_BAD_OPTION,
637 "Bad unit number in OPEN statement");
639 if (flags.position != POSITION_UNSPECIFIED
640 && flags.access == ACCESS_DIRECT)
641 generate_error (&opp->common, ERROR_BAD_OPTION,
642 "Cannot use POSITION with direct access files");
644 if (flags.access == ACCESS_APPEND)
646 if (flags.position != POSITION_UNSPECIFIED
647 && flags.position != POSITION_APPEND)
648 generate_error (&opp->common, ERROR_BAD_OPTION,
649 "Conflicting ACCESS and POSITION flags in"
652 notify_std (&opp->common, GFC_STD_GNU,
653 "Extension: APPEND as a value for ACCESS in OPEN statement");
654 flags.access = ACCESS_SEQUENTIAL;
655 flags.position = POSITION_APPEND;
658 if (flags.position == POSITION_UNSPECIFIED)
659 flags.position = POSITION_ASIS;
661 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
663 u = find_or_create_unit (opp->common.unit);
667 u = new_unit (opp, u, &flags);
672 already_open (opp, u, &flags);