gcc/testsuite/
[official-gcc.git] / libgfortran / io / open.c
blob06fd59415fe66fe1f2e6d41753db2286fdb0038b
1 /* Copyright (C) 2002-2014 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
3 F2003 I/O support contributed by Jerry DeLisle
5 This file is part of the GNU Fortran 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 3, or (at your option)
10 any later version.
12 Libgfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include "io.h"
27 #include "fbuf.h"
28 #include "unix.h"
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
34 #include <string.h>
35 #include <errno.h>
36 #include <stdlib.h>
39 static const st_option access_opt[] = {
40 {"sequential", ACCESS_SEQUENTIAL},
41 {"direct", ACCESS_DIRECT},
42 {"append", ACCESS_APPEND},
43 {"stream", ACCESS_STREAM},
44 {NULL, 0}
47 static const st_option action_opt[] =
49 { "read", ACTION_READ},
50 { "write", ACTION_WRITE},
51 { "readwrite", ACTION_READWRITE},
52 { NULL, 0}
55 static const st_option blank_opt[] =
57 { "null", BLANK_NULL},
58 { "zero", BLANK_ZERO},
59 { NULL, 0}
62 static const st_option delim_opt[] =
64 { "none", DELIM_NONE},
65 { "apostrophe", DELIM_APOSTROPHE},
66 { "quote", DELIM_QUOTE},
67 { NULL, 0}
70 static const st_option form_opt[] =
72 { "formatted", FORM_FORMATTED},
73 { "unformatted", FORM_UNFORMATTED},
74 { NULL, 0}
77 static const st_option position_opt[] =
79 { "asis", POSITION_ASIS},
80 { "rewind", POSITION_REWIND},
81 { "append", POSITION_APPEND},
82 { NULL, 0}
85 static const st_option status_opt[] =
87 { "unknown", STATUS_UNKNOWN},
88 { "old", STATUS_OLD},
89 { "new", STATUS_NEW},
90 { "replace", STATUS_REPLACE},
91 { "scratch", STATUS_SCRATCH},
92 { NULL, 0}
95 static const st_option pad_opt[] =
97 { "yes", PAD_YES},
98 { "no", PAD_NO},
99 { NULL, 0}
102 static const st_option decimal_opt[] =
104 { "point", DECIMAL_POINT},
105 { "comma", DECIMAL_COMMA},
106 { NULL, 0}
109 static const st_option encoding_opt[] =
111 { "utf-8", ENCODING_UTF8},
112 { "default", ENCODING_DEFAULT},
113 { NULL, 0}
116 static const st_option round_opt[] =
118 { "up", ROUND_UP},
119 { "down", ROUND_DOWN},
120 { "zero", ROUND_ZERO},
121 { "nearest", ROUND_NEAREST},
122 { "compatible", ROUND_COMPATIBLE},
123 { "processor_defined", ROUND_PROCDEFINED},
124 { NULL, 0}
127 static const st_option sign_opt[] =
129 { "plus", SIGN_PLUS},
130 { "suppress", SIGN_SUPPRESS},
131 { "processor_defined", SIGN_PROCDEFINED},
132 { NULL, 0}
135 static const st_option convert_opt[] =
137 { "native", GFC_CONVERT_NATIVE},
138 { "swap", GFC_CONVERT_SWAP},
139 { "big_endian", GFC_CONVERT_BIG},
140 { "little_endian", GFC_CONVERT_LITTLE},
141 { NULL, 0}
144 static const st_option async_opt[] =
146 { "yes", ASYNC_YES},
147 { "no", ASYNC_NO},
148 { NULL, 0}
151 /* Given a unit, test to see if the file is positioned at the terminal
152 point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
153 This prevents us from changing the state from AFTER_ENDFILE to
154 AT_ENDFILE. */
156 static void
157 test_endfile (gfc_unit * u)
159 if (u->endfile == NO_ENDFILE)
161 gfc_offset sz = ssize (u->s);
162 if (sz == 0 || sz == stell (u->s))
163 u->endfile = AT_ENDFILE;
168 /* Change the modes of a file, those that are allowed * to be
169 changed. */
171 static void
172 edit_modes (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
174 /* Complain about attempts to change the unchangeable. */
176 if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
177 u->flags.status != flags->status)
178 generate_error (&opp->common, LIBERROR_BAD_OPTION,
179 "Cannot change STATUS parameter in OPEN statement");
181 if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
182 generate_error (&opp->common, LIBERROR_BAD_OPTION,
183 "Cannot change ACCESS parameter in OPEN statement");
185 if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
186 generate_error (&opp->common, LIBERROR_BAD_OPTION,
187 "Cannot change FORM parameter in OPEN statement");
189 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
190 && opp->recl_in != u->recl)
191 generate_error (&opp->common, LIBERROR_BAD_OPTION,
192 "Cannot change RECL parameter in OPEN statement");
194 if (flags->action != ACTION_UNSPECIFIED && u->flags.action != flags->action)
195 generate_error (&opp->common, LIBERROR_BAD_OPTION,
196 "Cannot change ACTION parameter in OPEN statement");
198 /* Status must be OLD if present. */
200 if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
201 flags->status != STATUS_UNKNOWN)
203 if (flags->status == STATUS_SCRATCH)
204 notify_std (&opp->common, GFC_STD_GNU,
205 "OPEN statement must have a STATUS of OLD or UNKNOWN");
206 else
207 generate_error (&opp->common, LIBERROR_BAD_OPTION,
208 "OPEN statement must have a STATUS of OLD or UNKNOWN");
211 if (u->flags.form == FORM_UNFORMATTED)
213 if (flags->delim != DELIM_UNSPECIFIED)
214 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
215 "DELIM parameter conflicts with UNFORMATTED form in "
216 "OPEN statement");
218 if (flags->blank != BLANK_UNSPECIFIED)
219 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
220 "BLANK parameter conflicts with UNFORMATTED form in "
221 "OPEN statement");
223 if (flags->pad != PAD_UNSPECIFIED)
224 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
225 "PAD parameter conflicts with UNFORMATTED form in "
226 "OPEN statement");
228 if (flags->decimal != DECIMAL_UNSPECIFIED)
229 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
230 "DECIMAL parameter conflicts with UNFORMATTED form in "
231 "OPEN statement");
233 if (flags->encoding != ENCODING_UNSPECIFIED)
234 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
235 "ENCODING parameter conflicts with UNFORMATTED form in "
236 "OPEN statement");
238 if (flags->round != ROUND_UNSPECIFIED)
239 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
240 "ROUND parameter conflicts with UNFORMATTED form in "
241 "OPEN statement");
243 if (flags->sign != SIGN_UNSPECIFIED)
244 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
245 "SIGN parameter conflicts with UNFORMATTED form in "
246 "OPEN statement");
249 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
251 /* Change the changeable: */
252 if (flags->blank != BLANK_UNSPECIFIED)
253 u->flags.blank = flags->blank;
254 if (flags->delim != DELIM_UNSPECIFIED)
255 u->flags.delim = flags->delim;
256 if (flags->pad != PAD_UNSPECIFIED)
257 u->flags.pad = flags->pad;
258 if (flags->decimal != DECIMAL_UNSPECIFIED)
259 u->flags.decimal = flags->decimal;
260 if (flags->encoding != ENCODING_UNSPECIFIED)
261 u->flags.encoding = flags->encoding;
262 if (flags->async != ASYNC_UNSPECIFIED)
263 u->flags.async = flags->async;
264 if (flags->round != ROUND_UNSPECIFIED)
265 u->flags.round = flags->round;
266 if (flags->sign != SIGN_UNSPECIFIED)
267 u->flags.sign = flags->sign;
269 /* Reposition the file if necessary. */
271 switch (flags->position)
273 case POSITION_UNSPECIFIED:
274 case POSITION_ASIS:
275 break;
277 case POSITION_REWIND:
278 if (sseek (u->s, 0, SEEK_SET) != 0)
279 goto seek_error;
281 u->current_record = 0;
282 u->last_record = 0;
284 test_endfile (u);
285 break;
287 case POSITION_APPEND:
288 if (sseek (u->s, 0, SEEK_END) < 0)
289 goto seek_error;
291 if (flags->access != ACCESS_STREAM)
292 u->current_record = 0;
294 u->endfile = AT_ENDFILE; /* We are at the end. */
295 break;
297 seek_error:
298 generate_error (&opp->common, LIBERROR_OS, NULL);
299 break;
303 unlock_unit (u);
307 /* Open an unused unit. */
309 gfc_unit *
310 new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
312 gfc_unit *u2;
313 stream *s;
314 char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
316 /* Change unspecifieds to defaults. Leave (flags->action ==
317 ACTION_UNSPECIFIED) alone so open_external() can set it based on
318 what type of open actually works. */
320 if (flags->access == ACCESS_UNSPECIFIED)
321 flags->access = ACCESS_SEQUENTIAL;
323 if (flags->form == FORM_UNSPECIFIED)
324 flags->form = (flags->access == ACCESS_SEQUENTIAL)
325 ? FORM_FORMATTED : FORM_UNFORMATTED;
327 if (flags->async == ASYNC_UNSPECIFIED)
328 flags->async = ASYNC_NO;
330 if (flags->status == STATUS_UNSPECIFIED)
331 flags->status = STATUS_UNKNOWN;
333 /* Checks. */
335 if (flags->delim != DELIM_UNSPECIFIED
336 && flags->form == FORM_UNFORMATTED)
338 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
339 "DELIM parameter conflicts with UNFORMATTED form in "
340 "OPEN statement");
341 goto fail;
344 if (flags->blank == BLANK_UNSPECIFIED)
345 flags->blank = BLANK_NULL;
346 else
348 if (flags->form == FORM_UNFORMATTED)
350 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
351 "BLANK parameter conflicts with UNFORMATTED form in "
352 "OPEN statement");
353 goto fail;
357 if (flags->pad == PAD_UNSPECIFIED)
358 flags->pad = PAD_YES;
359 else
361 if (flags->form == FORM_UNFORMATTED)
363 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
364 "PAD parameter conflicts with UNFORMATTED form in "
365 "OPEN statement");
366 goto fail;
370 if (flags->decimal == DECIMAL_UNSPECIFIED)
371 flags->decimal = DECIMAL_POINT;
372 else
374 if (flags->form == FORM_UNFORMATTED)
376 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
377 "DECIMAL parameter conflicts with UNFORMATTED form "
378 "in OPEN statement");
379 goto fail;
383 if (flags->encoding == ENCODING_UNSPECIFIED)
384 flags->encoding = ENCODING_DEFAULT;
385 else
387 if (flags->form == FORM_UNFORMATTED)
389 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
390 "ENCODING parameter conflicts with UNFORMATTED form in "
391 "OPEN statement");
392 goto fail;
396 /* NB: the value for ROUND when it's not specified by the user does not
397 have to be PROCESSOR_DEFINED; the standard says that it is
398 processor dependent, and requires that it is one of the
399 possible value (see F2003, 9.4.5.13). */
400 if (flags->round == ROUND_UNSPECIFIED)
401 flags->round = ROUND_PROCDEFINED;
402 else
404 if (flags->form == FORM_UNFORMATTED)
406 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
407 "ROUND parameter conflicts with UNFORMATTED form in "
408 "OPEN statement");
409 goto fail;
413 if (flags->sign == SIGN_UNSPECIFIED)
414 flags->sign = SIGN_PROCDEFINED;
415 else
417 if (flags->form == FORM_UNFORMATTED)
419 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
420 "SIGN parameter conflicts with UNFORMATTED form in "
421 "OPEN statement");
422 goto fail;
426 if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
428 generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
429 "ACCESS parameter conflicts with SEQUENTIAL access in "
430 "OPEN statement");
431 goto fail;
433 else
434 if (flags->position == POSITION_UNSPECIFIED)
435 flags->position = POSITION_ASIS;
437 if (flags->access == ACCESS_DIRECT
438 && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
440 generate_error (&opp->common, LIBERROR_MISSING_OPTION,
441 "Missing RECL parameter in OPEN statement");
442 goto fail;
445 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
447 generate_error (&opp->common, LIBERROR_BAD_OPTION,
448 "RECL parameter is non-positive in OPEN statement");
449 goto fail;
452 switch (flags->status)
454 case STATUS_SCRATCH:
455 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
457 opp->file = NULL;
458 break;
461 generate_error (&opp->common, LIBERROR_BAD_OPTION,
462 "FILE parameter must not be present in OPEN statement");
463 goto fail;
465 case STATUS_OLD:
466 case STATUS_NEW:
467 case STATUS_REPLACE:
468 case STATUS_UNKNOWN:
469 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
470 break;
472 opp->file = tmpname;
473 opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d",
474 (int) opp->common.unit);
475 break;
477 default:
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. */
484 u2 = NULL;
485 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
486 u2 = find_file (opp->file, opp->file_len);
487 if (u2 != NULL
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))
492 unlock_unit (u2);
493 generate_error (&opp->common, LIBERROR_ALREADY_OPEN, NULL);
494 goto cleanup;
497 if (u2 != NULL)
498 unlock_unit (u2);
500 /* Open file. */
502 s = open_external (opp, flags);
503 if (s == NULL)
505 char *path, *msg;
506 size_t msglen;
507 path = (char *) gfc_alloca (opp->file_len + 1);
508 msglen = opp->file_len + 51;
509 msg = (char *) gfc_alloca (msglen);
510 unpack_filename (path, opp->file, opp->file_len);
512 switch (errno)
514 case ENOENT:
515 snprintf (msg, msglen, "File '%s' does not exist", path);
516 break;
518 case EEXIST:
519 snprintf (msg, msglen, "File '%s' already exists", path);
520 break;
522 case EACCES:
523 snprintf (msg, msglen,
524 "Permission denied trying to open file '%s'", path);
525 break;
527 case EISDIR:
528 snprintf (msg, msglen, "'%s' is a directory", path);
529 break;
531 default:
532 msg = NULL;
535 generate_error (&opp->common, LIBERROR_OS, msg);
536 goto cleanup;
539 if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
540 flags->status = STATUS_OLD;
542 /* Create the unit structure. */
544 u->file = xmalloc (opp->file_len);
545 if (u->unit_number != opp->common.unit)
546 internal_error (&opp->common, "Unit number changed");
547 u->s = s;
548 u->flags = *flags;
549 u->read_bad = 0;
550 u->endfile = NO_ENDFILE;
551 u->last_record = 0;
552 u->current_record = 0;
553 u->mode = READING;
554 u->maxrec = 0;
555 u->bytes_left = 0;
556 u->saved_pos = 0;
558 if (flags->position == POSITION_APPEND)
560 if (sseek (u->s, 0, SEEK_END) < 0)
562 generate_error (&opp->common, LIBERROR_OS, NULL);
563 goto cleanup;
565 u->endfile = AT_ENDFILE;
568 /* Unspecified recl ends up with a processor dependent value. */
570 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
572 u->flags.has_recl = 1;
573 u->recl = opp->recl_in;
574 u->recl_subrecord = u->recl;
575 u->bytes_left = u->recl;
577 else
579 u->flags.has_recl = 0;
580 u->recl = max_offset;
581 if (compile_options.max_subrecord_length)
583 u->recl_subrecord = compile_options.max_subrecord_length;
585 else
587 switch (compile_options.record_marker)
589 case 0:
590 /* Fall through */
591 case sizeof (GFC_INTEGER_4):
592 u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
593 break;
595 case sizeof (GFC_INTEGER_8):
596 u->recl_subrecord = max_offset - 16;
597 break;
599 default:
600 runtime_error ("Illegal value for record marker");
601 break;
606 /* If the file is direct access, calculate the maximum record number
607 via a division now instead of letting the multiplication overflow
608 later. */
610 if (flags->access == ACCESS_DIRECT)
611 u->maxrec = max_offset / u->recl;
613 if (flags->access == ACCESS_STREAM)
615 u->maxrec = max_offset;
616 u->recl = 1;
617 u->bytes_left = 1;
618 u->strm_pos = stell (u->s) + 1;
621 memmove (u->file, opp->file, opp->file_len);
622 u->file_len = opp->file_len;
624 /* Curiously, the standard requires that the
625 position specifier be ignored for new files so a newly connected
626 file starts out at the initial point. We still need to figure
627 out if the file is at the end or not. */
629 test_endfile (u);
631 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
632 free (opp->file);
634 if (flags->form == FORM_FORMATTED)
636 if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
637 fbuf_init (u, u->recl);
638 else
639 fbuf_init (u, 0);
641 else
642 u->fbuf = NULL;
646 return u;
648 cleanup:
650 /* Free memory associated with a temporary filename. */
652 if (flags->status == STATUS_SCRATCH && opp->file != NULL)
653 free (opp->file);
655 fail:
657 close_unit (u);
658 return NULL;
662 /* Open a unit which is already open. This involves changing the
663 modes or closing what is there now and opening the new file. */
665 static void
666 already_open (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
668 if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
670 edit_modes (opp, u, flags);
671 return;
674 /* If the file is connected to something else, close it and open a
675 new unit. */
677 if (!compare_file_filename (u, opp->file, opp->file_len))
679 #if !HAVE_UNLINK_OPEN_FILE
680 char *path = NULL;
681 if (u->file && u->flags.status == STATUS_SCRATCH)
683 path = (char *) gfc_alloca (u->file_len + 1);
684 unpack_filename (path, u->file, u->file_len);
686 #endif
688 if (sclose (u->s) == -1)
690 unlock_unit (u);
691 generate_error (&opp->common, LIBERROR_OS,
692 "Error closing file in OPEN statement");
693 return;
696 u->s = NULL;
697 free (u->file);
698 u->file = NULL;
699 u->file_len = 0;
701 #if !HAVE_UNLINK_OPEN_FILE
702 if (path != NULL)
703 unlink (path);
704 #endif
706 u = new_unit (opp, u, flags);
707 if (u != NULL)
708 unlock_unit (u);
709 return;
712 edit_modes (opp, u, flags);
716 /* Open file. */
718 extern void st_open (st_parameter_open *opp);
719 export_proto(st_open);
721 void
722 st_open (st_parameter_open *opp)
724 unit_flags flags;
725 gfc_unit *u = NULL;
726 GFC_INTEGER_4 cf = opp->common.flags;
727 unit_convert conv;
729 library_start (&opp->common);
731 /* Decode options. */
733 flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
734 find_option (&opp->common, opp->access, opp->access_len,
735 access_opt, "Bad ACCESS parameter in OPEN statement");
737 flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
738 find_option (&opp->common, opp->action, opp->action_len,
739 action_opt, "Bad ACTION parameter in OPEN statement");
741 flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
742 find_option (&opp->common, opp->blank, opp->blank_len,
743 blank_opt, "Bad BLANK parameter in OPEN statement");
745 flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
746 find_option (&opp->common, opp->delim, opp->delim_len,
747 delim_opt, "Bad DELIM parameter in OPEN statement");
749 flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
750 find_option (&opp->common, opp->pad, opp->pad_len,
751 pad_opt, "Bad PAD parameter in OPEN statement");
753 flags.decimal = !(cf & IOPARM_OPEN_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
754 find_option (&opp->common, opp->decimal, opp->decimal_len,
755 decimal_opt, "Bad DECIMAL parameter in OPEN statement");
757 flags.encoding = !(cf & IOPARM_OPEN_HAS_ENCODING) ? ENCODING_UNSPECIFIED :
758 find_option (&opp->common, opp->encoding, opp->encoding_len,
759 encoding_opt, "Bad ENCODING parameter in OPEN statement");
761 flags.async = !(cf & IOPARM_OPEN_HAS_ASYNCHRONOUS) ? ASYNC_UNSPECIFIED :
762 find_option (&opp->common, opp->asynchronous, opp->asynchronous_len,
763 async_opt, "Bad ASYNCHRONOUS parameter in OPEN statement");
765 flags.round = !(cf & IOPARM_OPEN_HAS_ROUND) ? ROUND_UNSPECIFIED :
766 find_option (&opp->common, opp->round, opp->round_len,
767 round_opt, "Bad ROUND parameter in OPEN statement");
769 flags.sign = !(cf & IOPARM_OPEN_HAS_SIGN) ? SIGN_UNSPECIFIED :
770 find_option (&opp->common, opp->sign, opp->sign_len,
771 sign_opt, "Bad SIGN parameter in OPEN statement");
773 flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
774 find_option (&opp->common, opp->form, opp->form_len,
775 form_opt, "Bad FORM parameter in OPEN statement");
777 flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
778 find_option (&opp->common, opp->position, opp->position_len,
779 position_opt, "Bad POSITION parameter in OPEN statement");
781 flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
782 find_option (&opp->common, opp->status, opp->status_len,
783 status_opt, "Bad STATUS parameter in OPEN statement");
785 /* First, we check wether the convert flag has been set via environment
786 variable. This overrides the convert tag in the open statement. */
788 conv = get_unformatted_convert (opp->common.unit);
790 if (conv == GFC_CONVERT_NONE)
792 /* Nothing has been set by environment variable, check the convert tag. */
793 if (cf & IOPARM_OPEN_HAS_CONVERT)
794 conv = find_option (&opp->common, opp->convert, opp->convert_len,
795 convert_opt,
796 "Bad CONVERT parameter in OPEN statement");
797 else
798 conv = compile_options.convert;
801 /* We use big_endian, which is 0 on little-endian machines
802 and 1 on big-endian machines. */
803 switch (conv)
805 case GFC_CONVERT_NATIVE:
806 case GFC_CONVERT_SWAP:
807 break;
809 case GFC_CONVERT_BIG:
810 conv = big_endian ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
811 break;
813 case GFC_CONVERT_LITTLE:
814 conv = big_endian ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
815 break;
817 default:
818 internal_error (&opp->common, "Illegal value for CONVERT");
819 break;
822 flags.convert = conv;
824 if (flags.position != POSITION_UNSPECIFIED
825 && flags.access == ACCESS_DIRECT)
826 generate_error (&opp->common, LIBERROR_BAD_OPTION,
827 "Cannot use POSITION with direct access files");
829 if (flags.access == ACCESS_APPEND)
831 if (flags.position != POSITION_UNSPECIFIED
832 && flags.position != POSITION_APPEND)
833 generate_error (&opp->common, LIBERROR_BAD_OPTION,
834 "Conflicting ACCESS and POSITION flags in"
835 " OPEN statement");
837 notify_std (&opp->common, GFC_STD_GNU,
838 "Extension: APPEND as a value for ACCESS in OPEN statement");
839 flags.access = ACCESS_SEQUENTIAL;
840 flags.position = POSITION_APPEND;
843 if (flags.position == POSITION_UNSPECIFIED)
844 flags.position = POSITION_ASIS;
846 if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
848 if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT))
849 opp->common.unit = get_unique_unit_number(opp);
850 else if (opp->common.unit < 0)
852 u = find_unit (opp->common.unit);
853 if (u == NULL) /* Negative unit and no NEWUNIT-created unit found. */
855 generate_error (&opp->common, LIBERROR_BAD_OPTION,
856 "Bad unit number in OPEN statement");
857 library_end ();
858 return;
862 if (u == NULL)
863 u = find_or_create_unit (opp->common.unit);
864 if (u->s == NULL)
866 u = new_unit (opp, u, &flags);
867 if (u != NULL)
868 unlock_unit (u);
870 else
871 already_open (opp, u, &flags);
874 if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT)
875 && (opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
876 *opp->newunit = opp->common.unit;
878 library_end ();