1 /* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008
2 Free Software Foundation, Inc.
3 Contributed by Andy Vaught
4 F2003 I/O support contributed by Jerry DeLisle
6 This file is part of the GNU Fortran 95 runtime library (libgfortran).
8 Libgfortran is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 In addition to the permissions in the GNU General Public License, the
14 Free Software Foundation gives you unlimited permission to link the
15 compiled version of this file into combinations with other programs,
16 and to distribute those combinations without any restriction coming
17 from the use of this file. (The General Public License restrictions
18 do apply in other respects; for example, they cover modification of
19 the file, and distribution when not linked into a combine
22 Libgfortran is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with Libgfortran; see the file COPYING. If not, write to
29 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
30 Boston, MA 02110-1301, USA. */
38 static const st_option access_opt[] = {
39 {"sequential", ACCESS_SEQUENTIAL},
40 {"direct", ACCESS_DIRECT},
41 {"append", ACCESS_APPEND},
42 {"stream", ACCESS_STREAM},
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[] =
101 static const st_option decimal_opt[] =
103 { "point", DECIMAL_POINT},
104 { "comma", DECIMAL_COMMA},
108 static const st_option encoding_opt[] =
110 { "utf-8", ENCODING_UTF8},
111 { "default", ENCODING_DEFAULT},
115 static const st_option round_opt[] =
118 { "down", ROUND_DOWN},
119 { "zero", ROUND_ZERO},
120 { "nearest", ROUND_NEAREST},
121 { "compatible", ROUND_COMPATIBLE},
122 { "processor_defined", ROUND_PROCDEFINED},
126 static const st_option sign_opt[] =
128 { "plus", SIGN_PLUS},
129 { "suppress", SIGN_SUPPRESS},
130 { "processor_defined", SIGN_PROCDEFINED},
134 static const st_option convert_opt[] =
136 { "native", GFC_CONVERT_NATIVE},
137 { "swap", GFC_CONVERT_SWAP},
138 { "big_endian", GFC_CONVERT_BIG},
139 { "little_endian", GFC_CONVERT_LITTLE},
143 static const st_option async_opt[] =
150 /* Given a unit, test to see if the file is positioned at the terminal
151 point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
152 This prevents us from changing the state from AFTER_ENDFILE to
156 test_endfile (gfc_unit * u)
158 if (u->endfile == NO_ENDFILE && file_length (u->s) == file_position (u->s))
159 u->endfile = AT_ENDFILE;
163 /* Change the modes of a file, those that are allowed * to be
167 edit_modes (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
169 /* Complain about attempts to change the unchangeable. */
171 if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
172 u->flags.status != flags->status)
173 generate_error (&opp->common, LIBERROR_BAD_OPTION,
174 "Cannot change STATUS parameter in OPEN statement");
176 if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
177 generate_error (&opp->common, LIBERROR_BAD_OPTION,
178 "Cannot change ACCESS parameter in OPEN statement");
180 if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
181 generate_error (&opp->common, LIBERROR_BAD_OPTION,
182 "Cannot change FORM parameter in OPEN statement");
184 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
185 && opp->recl_in != u->recl)
186 generate_error (&opp->common, LIBERROR_BAD_OPTION,
187 "Cannot change RECL parameter in OPEN statement");
189 if (flags->action != ACTION_UNSPECIFIED && u->flags.action != flags->action)
190 generate_error (&opp->common, LIBERROR_BAD_OPTION,
191 "Cannot change ACTION parameter in OPEN statement");
193 /* Status must be OLD if present. */
195 if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
196 flags->status != STATUS_UNKNOWN)
198 if (flags->status == STATUS_SCRATCH)
199 notify_std (&opp->common, GFC_STD_GNU,
200 "OPEN statement must have a STATUS of OLD or UNKNOWN");
202 generate_error (&opp->common, LIBERROR_BAD_OPTION,
203 "OPEN statement must have a STATUS of OLD or UNKNOWN");
206 if (u->flags.form == FORM_UNFORMATTED)
208 if (flags->delim != DELIM_UNSPECIFIED)
209 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
210 "DELIM parameter conflicts with UNFORMATTED form in "
213 if (flags->blank != BLANK_UNSPECIFIED)
214 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
215 "BLANK parameter conflicts with UNFORMATTED form in "
218 if (flags->pad != PAD_UNSPECIFIED)
219 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
220 "PAD parameter conflicts with UNFORMATTED form in "
223 if (flags->decimal != DECIMAL_UNSPECIFIED)
224 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
225 "DECIMAL parameter conflicts with UNFORMATTED form in "
228 if (flags->encoding != ENCODING_UNSPECIFIED)
229 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
230 "ENCODING parameter conflicts with UNFORMATTED form in "
233 if (flags->round != ROUND_UNSPECIFIED)
234 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
235 "ROUND parameter conflicts with UNFORMATTED form in "
238 if (flags->sign != SIGN_UNSPECIFIED)
239 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
240 "SIGN parameter conflicts with UNFORMATTED form in "
244 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
246 /* Change the changeable: */
247 if (flags->blank != BLANK_UNSPECIFIED)
248 u->flags.blank = flags->blank;
249 if (flags->delim != DELIM_UNSPECIFIED)
250 u->flags.delim = flags->delim;
251 if (flags->pad != PAD_UNSPECIFIED)
252 u->flags.pad = flags->pad;
253 if (flags->decimal != DECIMAL_UNSPECIFIED)
254 u->flags.decimal = flags->decimal;
255 if (flags->encoding != ENCODING_UNSPECIFIED)
256 u->flags.encoding = flags->encoding;
257 if (flags->round != ROUND_UNSPECIFIED)
258 u->flags.round = flags->round;
259 if (flags->sign != SIGN_UNSPECIFIED)
260 u->flags.sign = flags->sign;
263 /* Reposition the file if necessary. */
265 switch (flags->position)
267 case POSITION_UNSPECIFIED:
271 case POSITION_REWIND:
272 if (sseek (u->s, 0) == FAILURE)
275 u->current_record = 0;
281 case POSITION_APPEND:
282 if (sseek (u->s, file_length (u->s)) == FAILURE)
285 if (flags->access != ACCESS_STREAM)
286 u->current_record = 0;
288 u->endfile = AT_ENDFILE; /* We are at the end. */
292 generate_error (&opp->common, LIBERROR_OS, NULL);
300 /* Open an unused unit. */
303 new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
307 char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
309 /* Change unspecifieds to defaults. Leave (flags->action ==
310 ACTION_UNSPECIFIED) alone so open_external() can set it based on
311 what type of open actually works. */
313 if (flags->access == ACCESS_UNSPECIFIED)
314 flags->access = ACCESS_SEQUENTIAL;
316 if (flags->form == FORM_UNSPECIFIED)
317 flags->form = (flags->access == ACCESS_SEQUENTIAL)
318 ? FORM_FORMATTED : FORM_UNFORMATTED;
321 if (flags->delim == DELIM_UNSPECIFIED)
322 flags->delim = DELIM_NONE;
325 if (flags->form == FORM_UNFORMATTED)
327 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
328 "DELIM parameter conflicts with UNFORMATTED form in "
334 if (flags->blank == BLANK_UNSPECIFIED)
335 flags->blank = BLANK_NULL;
338 if (flags->form == FORM_UNFORMATTED)
340 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
341 "BLANK parameter conflicts with UNFORMATTED form in "
347 if (flags->pad == PAD_UNSPECIFIED)
348 flags->pad = PAD_YES;
351 if (flags->form == FORM_UNFORMATTED)
353 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
354 "PAD parameter conflicts with UNFORMATTED form in "
360 if (flags->decimal == DECIMAL_UNSPECIFIED)
361 flags->decimal = DECIMAL_POINT;
364 if (flags->form == FORM_UNFORMATTED)
366 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
367 "DECIMAL parameter conflicts with UNFORMATTED form "
368 "in OPEN statement");
373 if (flags->encoding == ENCODING_UNSPECIFIED)
374 flags->encoding = ENCODING_DEFAULT;
377 if (flags->form == FORM_UNFORMATTED)
379 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
380 "ENCODING parameter conflicts with UNFORMATTED form in "
386 /* NB: the value for ROUND when it's not specified by the user does not
387 have to be PROCESSOR_DEFINED; the standard says that it is
388 processor dependent, and requires that it is one of the
389 possible value (see F2003, 9.4.5.13). */
390 if (flags->round == ROUND_UNSPECIFIED)
391 flags->round = ROUND_PROCDEFINED;
394 if (flags->form == FORM_UNFORMATTED)
396 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
397 "ROUND parameter conflicts with UNFORMATTED form in "
403 if (flags->sign == SIGN_UNSPECIFIED)
404 flags->sign = SIGN_PROCDEFINED;
407 if (flags->form == FORM_UNFORMATTED)
409 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
410 "SIGN parameter conflicts with UNFORMATTED form in "
416 if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
418 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
419 "ACCESS parameter conflicts with SEQUENTIAL access in "
424 if (flags->position == POSITION_UNSPECIFIED)
425 flags->position = POSITION_ASIS;
428 if (flags->status == STATUS_UNSPECIFIED)
429 flags->status = STATUS_UNKNOWN;
433 if (flags->access == ACCESS_DIRECT
434 && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
436 generate_error (&opp->common, LIBERROR_MISSING_OPTION,
437 "Missing RECL parameter in OPEN statement");
441 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
443 generate_error (&opp->common, LIBERROR_BAD_OPTION,
444 "RECL parameter is non-positive in OPEN statement");
448 switch (flags->status)
451 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
457 generate_error (&opp->common, LIBERROR_BAD_OPTION,
458 "FILE parameter must not be present in OPEN statement");
465 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
470 opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d",
471 (int) opp->common.unit);
473 opp->file_len = sprintf(opp->file, "fort.%d", (int) opp->common.unit);
478 internal_error (&opp->common, "new_unit(): Bad status");
481 /* Make sure the file isn't already open someplace else.
482 Do not error if opening file preconnected to stdin, stdout, stderr. */
485 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
486 u2 = find_file (opp->file, opp->file_len);
488 && (options.stdin_unit < 0 || u2->unit_number != options.stdin_unit)
489 && (options.stdout_unit < 0 || u2->unit_number != options.stdout_unit)
490 && (options.stderr_unit < 0 || u2->unit_number != options.stderr_unit))
493 generate_error (&opp->common, LIBERROR_ALREADY_OPEN, NULL);
502 s = open_external (opp, flags);
506 path = (char *) gfc_alloca (opp->file_len + 1);
507 msg = (char *) gfc_alloca (opp->file_len + 51);
508 unpack_filename (path, opp->file, opp->file_len);
513 sprintf (msg, "File '%s' does not exist", path);
517 sprintf (msg, "File '%s' already exists", path);
521 sprintf (msg, "Permission denied trying to open file '%s'", path);
525 sprintf (msg, "'%s' is a directory", path);
532 generate_error (&opp->common, LIBERROR_OS, msg);
536 if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
537 flags->status = STATUS_OLD;
539 /* Create the unit structure. */
541 u->file = get_mem (opp->file_len);
542 if (u->unit_number != opp->common.unit)
543 internal_error (&opp->common, "Unit number changed");
547 u->endfile = NO_ENDFILE;
549 u->current_record = 0;
555 if (flags->position == POSITION_APPEND)
557 if (sseek (u->s, file_length (u->s)) == FAILURE)
558 generate_error (&opp->common, LIBERROR_OS, NULL);
559 u->endfile = AT_ENDFILE;
562 /* Unspecified recl ends up with a processor dependent value. */
564 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
566 u->flags.has_recl = 1;
567 u->recl = opp->recl_in;
568 u->recl_subrecord = u->recl;
569 u->bytes_left = u->recl;
573 u->flags.has_recl = 0;
574 u->recl = max_offset;
575 if (compile_options.max_subrecord_length)
577 u->recl_subrecord = compile_options.max_subrecord_length;
581 switch (compile_options.record_marker)
585 case sizeof (GFC_INTEGER_4):
586 u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
589 case sizeof (GFC_INTEGER_8):
590 u->recl_subrecord = max_offset - 16;
594 runtime_error ("Illegal value for record marker");
600 /* If the file is direct access, calculate the maximum record number
601 via a division now instead of letting the multiplication overflow
604 if (flags->access == ACCESS_DIRECT)
605 u->maxrec = max_offset / u->recl;
607 if (flags->access == ACCESS_STREAM)
609 u->maxrec = max_offset;
614 memmove (u->file, opp->file, opp->file_len);
615 u->file_len = opp->file_len;
617 /* Curiously, the standard requires that the
618 position specifier be ignored for new files so a newly connected
619 file starts out at the initial point. We still need to figure
620 out if the file is at the end or not. */
624 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
625 free_mem (opp->file);
630 /* Free memory associated with a temporary filename. */
632 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
633 free_mem (opp->file);
642 /* Open a unit which is already open. This involves changing the
643 modes or closing what is there now and opening the new file. */
646 already_open (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
648 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
650 edit_modes (opp, u, flags);
654 /* If the file is connected to something else, close it and open a
657 if (!compare_file_filename (u, opp->file, opp->file_len))
659 #if !HAVE_UNLINK_OPEN_FILE
661 if (u->file && u->flags.status == STATUS_SCRATCH)
663 path = (char *) gfc_alloca (u->file_len + 1);
664 unpack_filename (path, u->file, u->file_len);
668 if (sclose (u->s) == FAILURE)
671 generate_error (&opp->common, LIBERROR_OS,
672 "Error closing file in OPEN statement");
682 #if !HAVE_UNLINK_OPEN_FILE
687 u = new_unit (opp, u, flags);
693 edit_modes (opp, u, flags);
699 extern void st_open (st_parameter_open *opp);
700 export_proto(st_open);
703 st_open (st_parameter_open *opp)
707 GFC_INTEGER_4 cf = opp->common.flags;
710 library_start (&opp->common);
712 /* Decode options. */
714 flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
715 find_option (&opp->common, opp->access, opp->access_len,
716 access_opt, "Bad ACCESS parameter in OPEN statement");
718 flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
719 find_option (&opp->common, opp->action, opp->action_len,
720 action_opt, "Bad ACTION parameter in OPEN statement");
722 flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
723 find_option (&opp->common, opp->blank, opp->blank_len,
724 blank_opt, "Bad BLANK parameter in OPEN statement");
726 flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
727 find_option (&opp->common, opp->delim, opp->delim_len,
728 delim_opt, "Bad DELIM parameter in OPEN statement");
730 flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
731 find_option (&opp->common, opp->pad, opp->pad_len,
732 pad_opt, "Bad PAD parameter in OPEN statement");
734 flags.decimal = !(cf & IOPARM_OPEN_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
735 find_option (&opp->common, opp->decimal, opp->decimal_len,
736 decimal_opt, "Bad DECIMAL parameter in OPEN statement");
738 flags.encoding = !(cf & IOPARM_OPEN_HAS_ENCODING) ? ENCODING_UNSPECIFIED :
739 find_option (&opp->common, opp->encoding, opp->encoding_len,
740 encoding_opt, "Bad ENCODING parameter in OPEN statement");
742 flags.round = !(cf & IOPARM_OPEN_HAS_ROUND) ? ROUND_UNSPECIFIED :
743 find_option (&opp->common, opp->round, opp->round_len,
744 round_opt, "Bad ROUND parameter in OPEN statement");
746 flags.sign = !(cf & IOPARM_OPEN_HAS_SIGN) ? SIGN_UNSPECIFIED :
747 find_option (&opp->common, opp->sign, opp->sign_len,
748 sign_opt, "Bad SIGN parameter in OPEN statement");
750 flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
751 find_option (&opp->common, opp->form, opp->form_len,
752 form_opt, "Bad FORM parameter in OPEN statement");
754 flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
755 find_option (&opp->common, opp->position, opp->position_len,
756 position_opt, "Bad POSITION parameter in OPEN statement");
758 flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
759 find_option (&opp->common, opp->status, opp->status_len,
760 status_opt, "Bad STATUS parameter in OPEN statement");
762 /* First, we check wether the convert flag has been set via environment
763 variable. This overrides the convert tag in the open statement. */
765 conv = get_unformatted_convert (opp->common.unit);
767 if (conv == GFC_CONVERT_NONE)
769 /* Nothing has been set by environment variable, check the convert tag. */
770 if (cf & IOPARM_OPEN_HAS_CONVERT)
771 conv = find_option (&opp->common, opp->convert, opp->convert_len,
773 "Bad CONVERT parameter in OPEN statement");
775 conv = compile_options.convert;
778 /* We use l8_to_l4_offset, which is 0 on little-endian machines
779 and 1 on big-endian machines. */
782 case GFC_CONVERT_NATIVE:
783 case GFC_CONVERT_SWAP:
786 case GFC_CONVERT_BIG:
787 conv = l8_to_l4_offset ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
790 case GFC_CONVERT_LITTLE:
791 conv = l8_to_l4_offset ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
795 internal_error (&opp->common, "Illegal value for CONVERT");
799 flags.convert = conv;
801 if (opp->common.unit < 0)
802 generate_error (&opp->common, LIBERROR_BAD_OPTION,
803 "Bad unit number in OPEN statement");
805 if (flags.position != POSITION_UNSPECIFIED
806 && flags.access == ACCESS_DIRECT)
807 generate_error (&opp->common, LIBERROR_BAD_OPTION,
808 "Cannot use POSITION with direct access files");
810 if (flags.access == ACCESS_APPEND)
812 if (flags.position != POSITION_UNSPECIFIED
813 && flags.position != POSITION_APPEND)
814 generate_error (&opp->common, LIBERROR_BAD_OPTION,
815 "Conflicting ACCESS and POSITION flags in"
818 notify_std (&opp->common, GFC_STD_GNU,
819 "Extension: APPEND as a value for ACCESS in OPEN statement");
820 flags.access = ACCESS_SEQUENTIAL;
821 flags.position = POSITION_APPEND;
824 if (flags.position == POSITION_UNSPECIFIED)
825 flags.position = POSITION_ASIS;
827 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
829 u = find_or_create_unit (opp->common.unit);
833 u = new_unit (opp, u, &flags);
838 already_open (opp, u, &flags);