xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/io/open.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1*4c3eb207Smrg /* Copyright (C) 2002-2020 Free Software Foundation, Inc.
2627f7eb2Smrg    Contributed by Andy Vaught
3627f7eb2Smrg    F2003 I/O support contributed by Jerry DeLisle
4627f7eb2Smrg 
5627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6627f7eb2Smrg 
7627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or modify
8627f7eb2Smrg it under the terms of the GNU General Public License as published by
9627f7eb2Smrg the Free Software Foundation; either version 3, or (at your option)
10627f7eb2Smrg any later version.
11627f7eb2Smrg 
12627f7eb2Smrg Libgfortran is distributed in the hope that it will be useful,
13627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15627f7eb2Smrg GNU General Public License for more details.
16627f7eb2Smrg 
17627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
18627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
19627f7eb2Smrg 3.1, as published by the Free Software Foundation.
20627f7eb2Smrg 
21627f7eb2Smrg You should have received a copy of the GNU General Public License and
22627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
23627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24627f7eb2Smrg <http://www.gnu.org/licenses/>.  */
25627f7eb2Smrg 
26627f7eb2Smrg #include "io.h"
27627f7eb2Smrg #include "fbuf.h"
28627f7eb2Smrg #include "unix.h"
29627f7eb2Smrg #include "async.h"
30627f7eb2Smrg 
31627f7eb2Smrg #ifdef HAVE_UNISTD_H
32627f7eb2Smrg #include <unistd.h>
33627f7eb2Smrg #endif
34627f7eb2Smrg 
35627f7eb2Smrg #include <string.h>
36627f7eb2Smrg #include <errno.h>
37627f7eb2Smrg 
38627f7eb2Smrg 
39627f7eb2Smrg static const st_option access_opt[] = {
40627f7eb2Smrg   {"sequential", ACCESS_SEQUENTIAL},
41627f7eb2Smrg   {"direct", ACCESS_DIRECT},
42627f7eb2Smrg   {"append", ACCESS_APPEND},
43627f7eb2Smrg   {"stream", ACCESS_STREAM},
44627f7eb2Smrg   {NULL, 0}
45627f7eb2Smrg };
46627f7eb2Smrg 
47627f7eb2Smrg static const st_option action_opt[] =
48627f7eb2Smrg {
49627f7eb2Smrg   { "read", ACTION_READ},
50627f7eb2Smrg   { "write", ACTION_WRITE},
51627f7eb2Smrg   { "readwrite", ACTION_READWRITE},
52627f7eb2Smrg   { NULL, 0}
53627f7eb2Smrg };
54627f7eb2Smrg 
55627f7eb2Smrg static const st_option share_opt[] =
56627f7eb2Smrg {
57627f7eb2Smrg   { "denyrw", SHARE_DENYRW },
58627f7eb2Smrg   { "denynone", SHARE_DENYNONE },
59627f7eb2Smrg   { NULL, 0}
60627f7eb2Smrg };
61627f7eb2Smrg 
62627f7eb2Smrg static const st_option cc_opt[] =
63627f7eb2Smrg {
64627f7eb2Smrg   { "list", CC_LIST },
65627f7eb2Smrg   { "fortran", CC_FORTRAN },
66627f7eb2Smrg   { "none", CC_NONE },
67627f7eb2Smrg   { NULL, 0}
68627f7eb2Smrg };
69627f7eb2Smrg 
70627f7eb2Smrg static const st_option blank_opt[] =
71627f7eb2Smrg {
72627f7eb2Smrg   { "null", BLANK_NULL},
73627f7eb2Smrg   { "zero", BLANK_ZERO},
74627f7eb2Smrg   { NULL, 0}
75627f7eb2Smrg };
76627f7eb2Smrg 
77627f7eb2Smrg static const st_option delim_opt[] =
78627f7eb2Smrg {
79627f7eb2Smrg   { "none", DELIM_NONE},
80627f7eb2Smrg   { "apostrophe", DELIM_APOSTROPHE},
81627f7eb2Smrg   { "quote", DELIM_QUOTE},
82627f7eb2Smrg   { NULL, 0}
83627f7eb2Smrg };
84627f7eb2Smrg 
85627f7eb2Smrg static const st_option form_opt[] =
86627f7eb2Smrg {
87627f7eb2Smrg   { "formatted", FORM_FORMATTED},
88627f7eb2Smrg   { "unformatted", FORM_UNFORMATTED},
89627f7eb2Smrg   { NULL, 0}
90627f7eb2Smrg };
91627f7eb2Smrg 
92627f7eb2Smrg static const st_option position_opt[] =
93627f7eb2Smrg {
94627f7eb2Smrg   { "asis", POSITION_ASIS},
95627f7eb2Smrg   { "rewind", POSITION_REWIND},
96627f7eb2Smrg   { "append", POSITION_APPEND},
97627f7eb2Smrg   { NULL, 0}
98627f7eb2Smrg };
99627f7eb2Smrg 
100627f7eb2Smrg static const st_option status_opt[] =
101627f7eb2Smrg {
102627f7eb2Smrg   { "unknown", STATUS_UNKNOWN},
103627f7eb2Smrg   { "old", STATUS_OLD},
104627f7eb2Smrg   { "new", STATUS_NEW},
105627f7eb2Smrg   { "replace", STATUS_REPLACE},
106627f7eb2Smrg   { "scratch", STATUS_SCRATCH},
107627f7eb2Smrg   { NULL, 0}
108627f7eb2Smrg };
109627f7eb2Smrg 
110627f7eb2Smrg static const st_option pad_opt[] =
111627f7eb2Smrg {
112627f7eb2Smrg   { "yes", PAD_YES},
113627f7eb2Smrg   { "no", PAD_NO},
114627f7eb2Smrg   { NULL, 0}
115627f7eb2Smrg };
116627f7eb2Smrg 
117627f7eb2Smrg static const st_option decimal_opt[] =
118627f7eb2Smrg {
119627f7eb2Smrg   { "point", DECIMAL_POINT},
120627f7eb2Smrg   { "comma", DECIMAL_COMMA},
121627f7eb2Smrg   { NULL, 0}
122627f7eb2Smrg };
123627f7eb2Smrg 
124627f7eb2Smrg static const st_option encoding_opt[] =
125627f7eb2Smrg {
126627f7eb2Smrg   { "utf-8", ENCODING_UTF8},
127627f7eb2Smrg   { "default", ENCODING_DEFAULT},
128627f7eb2Smrg   { NULL, 0}
129627f7eb2Smrg };
130627f7eb2Smrg 
131627f7eb2Smrg static const st_option round_opt[] =
132627f7eb2Smrg {
133627f7eb2Smrg   { "up", ROUND_UP},
134627f7eb2Smrg   { "down", ROUND_DOWN},
135627f7eb2Smrg   { "zero", ROUND_ZERO},
136627f7eb2Smrg   { "nearest", ROUND_NEAREST},
137627f7eb2Smrg   { "compatible", ROUND_COMPATIBLE},
138627f7eb2Smrg   { "processor_defined", ROUND_PROCDEFINED},
139627f7eb2Smrg   { NULL, 0}
140627f7eb2Smrg };
141627f7eb2Smrg 
142627f7eb2Smrg static const st_option sign_opt[] =
143627f7eb2Smrg {
144627f7eb2Smrg   { "plus", SIGN_PLUS},
145627f7eb2Smrg   { "suppress", SIGN_SUPPRESS},
146627f7eb2Smrg   { "processor_defined", SIGN_PROCDEFINED},
147627f7eb2Smrg   { NULL, 0}
148627f7eb2Smrg };
149627f7eb2Smrg 
150627f7eb2Smrg static const st_option convert_opt[] =
151627f7eb2Smrg {
152627f7eb2Smrg   { "native", GFC_CONVERT_NATIVE},
153627f7eb2Smrg   { "swap", GFC_CONVERT_SWAP},
154627f7eb2Smrg   { "big_endian", GFC_CONVERT_BIG},
155627f7eb2Smrg   { "little_endian", GFC_CONVERT_LITTLE},
156627f7eb2Smrg   { NULL, 0}
157627f7eb2Smrg };
158627f7eb2Smrg 
159627f7eb2Smrg static const st_option async_opt[] =
160627f7eb2Smrg {
161627f7eb2Smrg   { "yes", ASYNC_YES},
162627f7eb2Smrg   { "no", ASYNC_NO},
163627f7eb2Smrg   { NULL, 0}
164627f7eb2Smrg };
165627f7eb2Smrg 
166627f7eb2Smrg /* Given a unit, test to see if the file is positioned at the terminal
167627f7eb2Smrg    point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
168627f7eb2Smrg    This prevents us from changing the state from AFTER_ENDFILE to
169627f7eb2Smrg    AT_ENDFILE.  */
170627f7eb2Smrg 
171627f7eb2Smrg static void
test_endfile(gfc_unit * u)172627f7eb2Smrg test_endfile (gfc_unit *u)
173627f7eb2Smrg {
174627f7eb2Smrg   if (u->endfile == NO_ENDFILE)
175627f7eb2Smrg     {
176627f7eb2Smrg       gfc_offset sz = ssize (u->s);
177627f7eb2Smrg       if (sz == 0 || sz == stell (u->s))
178627f7eb2Smrg 	u->endfile = AT_ENDFILE;
179627f7eb2Smrg     }
180627f7eb2Smrg }
181627f7eb2Smrg 
182627f7eb2Smrg 
183627f7eb2Smrg /* Change the modes of a file, those that are allowed * to be
184627f7eb2Smrg    changed.  */
185627f7eb2Smrg 
186627f7eb2Smrg static void
edit_modes(st_parameter_open * opp,gfc_unit * u,unit_flags * flags)187627f7eb2Smrg edit_modes (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
188627f7eb2Smrg {
189627f7eb2Smrg   /* Complain about attempts to change the unchangeable.  */
190627f7eb2Smrg 
191627f7eb2Smrg   if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
192627f7eb2Smrg       u->flags.status != flags->status)
193627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
194627f7eb2Smrg 		    "Cannot change STATUS parameter in OPEN statement");
195627f7eb2Smrg 
196627f7eb2Smrg   if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
197627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
198627f7eb2Smrg 		    "Cannot change ACCESS parameter in OPEN statement");
199627f7eb2Smrg 
200627f7eb2Smrg   if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
201627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
202627f7eb2Smrg 		    "Cannot change FORM parameter in OPEN statement");
203627f7eb2Smrg 
204627f7eb2Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
205627f7eb2Smrg       && opp->recl_in != u->recl)
206627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
207627f7eb2Smrg 		    "Cannot change RECL parameter in OPEN statement");
208627f7eb2Smrg 
209627f7eb2Smrg   if (flags->action != ACTION_UNSPECIFIED && u->flags.action != flags->action)
210627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
211627f7eb2Smrg 		    "Cannot change ACTION parameter in OPEN statement");
212627f7eb2Smrg 
213627f7eb2Smrg   if (flags->share != SHARE_UNSPECIFIED && u->flags.share != flags->share)
214627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
215627f7eb2Smrg 		    "Cannot change SHARE parameter in OPEN statement");
216627f7eb2Smrg 
217627f7eb2Smrg   if (flags->cc != CC_UNSPECIFIED && u->flags.cc != flags->cc)
218627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
219627f7eb2Smrg 		  "Cannot change CARRIAGECONTROL parameter in OPEN statement");
220627f7eb2Smrg 
221627f7eb2Smrg   /* Status must be OLD if present.  */
222627f7eb2Smrg 
223627f7eb2Smrg   if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
224627f7eb2Smrg       flags->status != STATUS_UNKNOWN)
225627f7eb2Smrg     {
226627f7eb2Smrg       if (flags->status == STATUS_SCRATCH)
227627f7eb2Smrg 	notify_std (&opp->common, GFC_STD_GNU,
228627f7eb2Smrg 		    "OPEN statement must have a STATUS of OLD or UNKNOWN");
229627f7eb2Smrg       else
230627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_BAD_OPTION,
231627f7eb2Smrg 		    "OPEN statement must have a STATUS of OLD or UNKNOWN");
232627f7eb2Smrg     }
233627f7eb2Smrg 
234627f7eb2Smrg   if (u->flags.form == FORM_UNFORMATTED)
235627f7eb2Smrg     {
236627f7eb2Smrg       if (flags->delim != DELIM_UNSPECIFIED)
237627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
238627f7eb2Smrg 			"DELIM parameter conflicts with UNFORMATTED form in "
239627f7eb2Smrg 			"OPEN statement");
240627f7eb2Smrg 
241627f7eb2Smrg       if (flags->blank != BLANK_UNSPECIFIED)
242627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
243627f7eb2Smrg 			"BLANK parameter conflicts with UNFORMATTED form in "
244627f7eb2Smrg 			"OPEN statement");
245627f7eb2Smrg 
246627f7eb2Smrg       if (flags->pad != PAD_UNSPECIFIED)
247627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
248627f7eb2Smrg 			"PAD parameter conflicts with UNFORMATTED form in "
249627f7eb2Smrg 			"OPEN statement");
250627f7eb2Smrg 
251627f7eb2Smrg       if (flags->decimal != DECIMAL_UNSPECIFIED)
252627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
253627f7eb2Smrg 			"DECIMAL parameter conflicts with UNFORMATTED form in "
254627f7eb2Smrg 			"OPEN statement");
255627f7eb2Smrg 
256627f7eb2Smrg       if (flags->encoding != ENCODING_UNSPECIFIED)
257627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
258627f7eb2Smrg 			"ENCODING parameter conflicts with UNFORMATTED form in "
259627f7eb2Smrg 			"OPEN statement");
260627f7eb2Smrg 
261627f7eb2Smrg       if (flags->round != ROUND_UNSPECIFIED)
262627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
263627f7eb2Smrg 			"ROUND parameter conflicts with UNFORMATTED form in "
264627f7eb2Smrg 			"OPEN statement");
265627f7eb2Smrg 
266627f7eb2Smrg       if (flags->sign != SIGN_UNSPECIFIED)
267627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
268627f7eb2Smrg 			"SIGN parameter conflicts with UNFORMATTED form in "
269627f7eb2Smrg 			"OPEN statement");
270627f7eb2Smrg     }
271627f7eb2Smrg 
272627f7eb2Smrg   if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
273627f7eb2Smrg     {
274627f7eb2Smrg       /* Change the changeable:  */
275627f7eb2Smrg       if (flags->blank != BLANK_UNSPECIFIED)
276627f7eb2Smrg 	u->flags.blank = flags->blank;
277627f7eb2Smrg       if (flags->delim != DELIM_UNSPECIFIED)
278627f7eb2Smrg 	u->flags.delim = flags->delim;
279627f7eb2Smrg       if (flags->pad != PAD_UNSPECIFIED)
280627f7eb2Smrg 	u->flags.pad = flags->pad;
281627f7eb2Smrg       if (flags->decimal != DECIMAL_UNSPECIFIED)
282627f7eb2Smrg 	u->flags.decimal = flags->decimal;
283627f7eb2Smrg       if (flags->encoding != ENCODING_UNSPECIFIED)
284627f7eb2Smrg 	u->flags.encoding = flags->encoding;
285627f7eb2Smrg       if (flags->async != ASYNC_UNSPECIFIED)
286627f7eb2Smrg 	u->flags.async = flags->async;
287627f7eb2Smrg       if (flags->round != ROUND_UNSPECIFIED)
288627f7eb2Smrg 	u->flags.round = flags->round;
289627f7eb2Smrg       if (flags->sign != SIGN_UNSPECIFIED)
290627f7eb2Smrg 	u->flags.sign = flags->sign;
291627f7eb2Smrg 
292627f7eb2Smrg       /* Reposition the file if necessary.  */
293627f7eb2Smrg 
294627f7eb2Smrg       switch (flags->position)
295627f7eb2Smrg 	{
296627f7eb2Smrg 	case POSITION_UNSPECIFIED:
297627f7eb2Smrg 	case POSITION_ASIS:
298627f7eb2Smrg 	  break;
299627f7eb2Smrg 
300627f7eb2Smrg 	case POSITION_REWIND:
301627f7eb2Smrg 	  if (sseek (u->s, 0, SEEK_SET) != 0)
302627f7eb2Smrg 	    goto seek_error;
303627f7eb2Smrg 
304627f7eb2Smrg 	  u->current_record = 0;
305627f7eb2Smrg 	  u->last_record = 0;
306627f7eb2Smrg 
307627f7eb2Smrg 	  test_endfile (u);
308627f7eb2Smrg 	  break;
309627f7eb2Smrg 
310627f7eb2Smrg 	case POSITION_APPEND:
311627f7eb2Smrg 	  if (sseek (u->s, 0, SEEK_END) < 0)
312627f7eb2Smrg 	    goto seek_error;
313627f7eb2Smrg 
314627f7eb2Smrg 	  if (flags->access != ACCESS_STREAM)
315627f7eb2Smrg 	    u->current_record = 0;
316627f7eb2Smrg 
317627f7eb2Smrg 	  u->endfile = AT_ENDFILE;	/* We are at the end.  */
318627f7eb2Smrg 	  break;
319627f7eb2Smrg 
320627f7eb2Smrg 	seek_error:
321627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OS, NULL);
322627f7eb2Smrg 	  break;
323627f7eb2Smrg 	}
324627f7eb2Smrg     }
325627f7eb2Smrg 
326627f7eb2Smrg   unlock_unit (u);
327627f7eb2Smrg }
328627f7eb2Smrg 
329627f7eb2Smrg 
330627f7eb2Smrg /* Open an unused unit.  */
331627f7eb2Smrg 
332627f7eb2Smrg gfc_unit *
new_unit(st_parameter_open * opp,gfc_unit * u,unit_flags * flags)333627f7eb2Smrg new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
334627f7eb2Smrg {
335627f7eb2Smrg   gfc_unit *u2;
336627f7eb2Smrg   stream *s;
337627f7eb2Smrg   char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
338627f7eb2Smrg 
339627f7eb2Smrg   /* Change unspecifieds to defaults.  Leave (flags->action ==
340627f7eb2Smrg      ACTION_UNSPECIFIED) alone so open_external() can set it based on
341627f7eb2Smrg      what type of open actually works.  */
342627f7eb2Smrg 
343627f7eb2Smrg   if (flags->access == ACCESS_UNSPECIFIED)
344627f7eb2Smrg     flags->access = ACCESS_SEQUENTIAL;
345627f7eb2Smrg 
346627f7eb2Smrg   if (flags->form == FORM_UNSPECIFIED)
347627f7eb2Smrg     flags->form = (flags->access == ACCESS_SEQUENTIAL)
348627f7eb2Smrg       ? FORM_FORMATTED : FORM_UNFORMATTED;
349627f7eb2Smrg 
350627f7eb2Smrg   if (flags->async == ASYNC_UNSPECIFIED)
351627f7eb2Smrg     flags->async = ASYNC_NO;
352627f7eb2Smrg 
353627f7eb2Smrg   if (flags->status == STATUS_UNSPECIFIED)
354627f7eb2Smrg     flags->status = STATUS_UNKNOWN;
355627f7eb2Smrg 
356627f7eb2Smrg   if (flags->cc == CC_UNSPECIFIED)
357627f7eb2Smrg     flags->cc = flags->form == FORM_UNFORMATTED ? CC_NONE : CC_LIST;
358627f7eb2Smrg   else if (flags->form == FORM_UNFORMATTED && flags->cc != CC_NONE)
359627f7eb2Smrg     {
360627f7eb2Smrg       generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
361627f7eb2Smrg 	  "CARRIAGECONTROL parameter conflicts with UNFORMATTED form in "
362627f7eb2Smrg 	  "OPEN statement");
363627f7eb2Smrg       goto fail;
364627f7eb2Smrg     }
365627f7eb2Smrg 
366627f7eb2Smrg   /* Checks.  */
367627f7eb2Smrg 
368627f7eb2Smrg   if (flags->delim != DELIM_UNSPECIFIED
369627f7eb2Smrg       && flags->form == FORM_UNFORMATTED)
370627f7eb2Smrg     {
371627f7eb2Smrg       generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
372627f7eb2Smrg 		      "DELIM parameter conflicts with UNFORMATTED form in "
373627f7eb2Smrg 		      "OPEN statement");
374627f7eb2Smrg       goto fail;
375627f7eb2Smrg     }
376627f7eb2Smrg 
377627f7eb2Smrg   if (flags->blank == BLANK_UNSPECIFIED)
378627f7eb2Smrg     flags->blank = BLANK_NULL;
379627f7eb2Smrg   else
380627f7eb2Smrg     {
381627f7eb2Smrg       if (flags->form == FORM_UNFORMATTED)
382627f7eb2Smrg 	{
383627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
384627f7eb2Smrg 			  "BLANK parameter conflicts with UNFORMATTED form in "
385627f7eb2Smrg 			  "OPEN statement");
386627f7eb2Smrg 	  goto fail;
387627f7eb2Smrg 	}
388627f7eb2Smrg     }
389627f7eb2Smrg 
390627f7eb2Smrg   if (flags->pad == PAD_UNSPECIFIED)
391627f7eb2Smrg     flags->pad = PAD_YES;
392627f7eb2Smrg   else
393627f7eb2Smrg     {
394627f7eb2Smrg       if (flags->form == FORM_UNFORMATTED)
395627f7eb2Smrg 	{
396627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
397627f7eb2Smrg 			  "PAD parameter conflicts with UNFORMATTED form in "
398627f7eb2Smrg 			  "OPEN statement");
399627f7eb2Smrg 	  goto fail;
400627f7eb2Smrg 	}
401627f7eb2Smrg     }
402627f7eb2Smrg 
403627f7eb2Smrg   if (flags->decimal == DECIMAL_UNSPECIFIED)
404627f7eb2Smrg     flags->decimal = DECIMAL_POINT;
405627f7eb2Smrg   else
406627f7eb2Smrg     {
407627f7eb2Smrg       if (flags->form == FORM_UNFORMATTED)
408627f7eb2Smrg 	{
409627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
410627f7eb2Smrg 			  "DECIMAL parameter conflicts with UNFORMATTED form "
411627f7eb2Smrg 			  "in OPEN statement");
412627f7eb2Smrg 	  goto fail;
413627f7eb2Smrg 	}
414627f7eb2Smrg     }
415627f7eb2Smrg 
416627f7eb2Smrg   if (flags->encoding == ENCODING_UNSPECIFIED)
417627f7eb2Smrg     flags->encoding = ENCODING_DEFAULT;
418627f7eb2Smrg   else
419627f7eb2Smrg     {
420627f7eb2Smrg       if (flags->form == FORM_UNFORMATTED)
421627f7eb2Smrg 	{
422627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
423627f7eb2Smrg 			  "ENCODING parameter conflicts with UNFORMATTED form in "
424627f7eb2Smrg 			  "OPEN statement");
425627f7eb2Smrg 	  goto fail;
426627f7eb2Smrg 	}
427627f7eb2Smrg     }
428627f7eb2Smrg 
429627f7eb2Smrg   /* NB: the value for ROUND when it's not specified by the user does not
430627f7eb2Smrg          have to be PROCESSOR_DEFINED; the standard says that it is
431627f7eb2Smrg 	 processor dependent, and requires that it is one of the
432627f7eb2Smrg 	 possible value (see F2003, 9.4.5.13).  */
433627f7eb2Smrg   if (flags->round == ROUND_UNSPECIFIED)
434627f7eb2Smrg     flags->round = ROUND_PROCDEFINED;
435627f7eb2Smrg   else
436627f7eb2Smrg     {
437627f7eb2Smrg       if (flags->form == FORM_UNFORMATTED)
438627f7eb2Smrg 	{
439627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
440627f7eb2Smrg 			  "ROUND parameter conflicts with UNFORMATTED form in "
441627f7eb2Smrg 			  "OPEN statement");
442627f7eb2Smrg 	  goto fail;
443627f7eb2Smrg 	}
444627f7eb2Smrg     }
445627f7eb2Smrg 
446627f7eb2Smrg   if (flags->sign == SIGN_UNSPECIFIED)
447627f7eb2Smrg     flags->sign = SIGN_PROCDEFINED;
448627f7eb2Smrg   else
449627f7eb2Smrg     {
450627f7eb2Smrg       if (flags->form == FORM_UNFORMATTED)
451627f7eb2Smrg 	{
452627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
453627f7eb2Smrg 			  "SIGN parameter conflicts with UNFORMATTED form in "
454627f7eb2Smrg 			  "OPEN statement");
455627f7eb2Smrg 	  goto fail;
456627f7eb2Smrg 	}
457627f7eb2Smrg     }
458627f7eb2Smrg 
459627f7eb2Smrg   if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
460627f7eb2Smrg    {
461627f7eb2Smrg      generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
462627f7eb2Smrg                      "ACCESS parameter conflicts with SEQUENTIAL access in "
463627f7eb2Smrg                      "OPEN statement");
464627f7eb2Smrg      goto fail;
465627f7eb2Smrg    }
466627f7eb2Smrg   else
467627f7eb2Smrg    if (flags->position == POSITION_UNSPECIFIED)
468627f7eb2Smrg      flags->position = POSITION_ASIS;
469627f7eb2Smrg 
470627f7eb2Smrg   if (flags->access == ACCESS_DIRECT
471627f7eb2Smrg       && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
472627f7eb2Smrg     {
473627f7eb2Smrg       generate_error (&opp->common, LIBERROR_MISSING_OPTION,
474627f7eb2Smrg 		      "Missing RECL parameter in OPEN statement");
475627f7eb2Smrg       goto fail;
476627f7eb2Smrg     }
477627f7eb2Smrg 
478627f7eb2Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
479627f7eb2Smrg     {
480627f7eb2Smrg       generate_error (&opp->common, LIBERROR_BAD_OPTION,
481627f7eb2Smrg 		      "RECL parameter is non-positive in OPEN statement");
482627f7eb2Smrg       goto fail;
483627f7eb2Smrg     }
484627f7eb2Smrg 
485627f7eb2Smrg   switch (flags->status)
486627f7eb2Smrg     {
487627f7eb2Smrg     case STATUS_SCRATCH:
488627f7eb2Smrg       if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
489627f7eb2Smrg 	{
490627f7eb2Smrg 	  opp->file = NULL;
491627f7eb2Smrg 	  break;
492627f7eb2Smrg 	}
493627f7eb2Smrg 
494627f7eb2Smrg       generate_error (&opp->common, LIBERROR_BAD_OPTION,
495627f7eb2Smrg 		      "FILE parameter must not be present in OPEN statement");
496627f7eb2Smrg       goto fail;
497627f7eb2Smrg 
498627f7eb2Smrg     case STATUS_OLD:
499627f7eb2Smrg     case STATUS_NEW:
500627f7eb2Smrg     case STATUS_REPLACE:
501627f7eb2Smrg     case STATUS_UNKNOWN:
502627f7eb2Smrg       if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
503627f7eb2Smrg 	break;
504627f7eb2Smrg 
505627f7eb2Smrg       opp->file = tmpname;
506627f7eb2Smrg       opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d",
507627f7eb2Smrg 			       (int) opp->common.unit);
508627f7eb2Smrg       break;
509627f7eb2Smrg 
510627f7eb2Smrg     default:
511627f7eb2Smrg       internal_error (&opp->common, "new_unit(): Bad status");
512627f7eb2Smrg     }
513627f7eb2Smrg 
514627f7eb2Smrg   /* Make sure the file isn't already open someplace else.
515627f7eb2Smrg      Do not error if opening file preconnected to stdin, stdout, stderr.  */
516627f7eb2Smrg 
517627f7eb2Smrg   u2 = NULL;
518*4c3eb207Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0
519*4c3eb207Smrg       && !(compile_options.allow_std & GFC_STD_F2018))
520627f7eb2Smrg     u2 = find_file (opp->file, opp->file_len);
521627f7eb2Smrg   if (u2 != NULL
522627f7eb2Smrg       && (options.stdin_unit < 0 || u2->unit_number != options.stdin_unit)
523627f7eb2Smrg       && (options.stdout_unit < 0 || u2->unit_number != options.stdout_unit)
524627f7eb2Smrg       && (options.stderr_unit < 0 || u2->unit_number != options.stderr_unit))
525627f7eb2Smrg     {
526627f7eb2Smrg       unlock_unit (u2);
527627f7eb2Smrg       generate_error (&opp->common, LIBERROR_ALREADY_OPEN, NULL);
528627f7eb2Smrg       goto cleanup;
529627f7eb2Smrg     }
530627f7eb2Smrg 
531627f7eb2Smrg   if (u2 != NULL)
532627f7eb2Smrg     unlock_unit (u2);
533627f7eb2Smrg 
534627f7eb2Smrg   /* If the unit specified is preconnected with a file specified to be open,
535627f7eb2Smrg      then clear the format buffer.  */
536627f7eb2Smrg   if ((opp->common.unit == options.stdin_unit ||
537627f7eb2Smrg        opp->common.unit == options.stdout_unit ||
538627f7eb2Smrg        opp->common.unit == options.stderr_unit)
539627f7eb2Smrg       && (opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
540627f7eb2Smrg     fbuf_destroy (u);
541627f7eb2Smrg 
542627f7eb2Smrg   /* Open file.  */
543627f7eb2Smrg 
544627f7eb2Smrg   s = open_external (opp, flags);
545627f7eb2Smrg   if (s == NULL)
546627f7eb2Smrg     {
547627f7eb2Smrg       char errbuf[256];
548627f7eb2Smrg       char *path = fc_strdup (opp->file, opp->file_len);
549627f7eb2Smrg       size_t msglen = opp->file_len + 22 + sizeof (errbuf);
550627f7eb2Smrg       char *msg = xmalloc (msglen);
551627f7eb2Smrg       snprintf (msg, msglen, "Cannot open file '%s': %s", path,
552627f7eb2Smrg 		gf_strerror (errno, errbuf, sizeof (errbuf)));
553627f7eb2Smrg       generate_error (&opp->common, LIBERROR_OS, msg);
554627f7eb2Smrg       free (msg);
555627f7eb2Smrg       free (path);
556627f7eb2Smrg       goto cleanup;
557627f7eb2Smrg     }
558627f7eb2Smrg 
559627f7eb2Smrg   if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
560627f7eb2Smrg     flags->status = STATUS_OLD;
561627f7eb2Smrg 
562627f7eb2Smrg   /* Create the unit structure.  */
563627f7eb2Smrg 
564627f7eb2Smrg   if (u->unit_number != opp->common.unit)
565627f7eb2Smrg     internal_error (&opp->common, "Unit number changed");
566627f7eb2Smrg   u->s = s;
567627f7eb2Smrg   u->flags = *flags;
568627f7eb2Smrg   u->read_bad = 0;
569627f7eb2Smrg   u->endfile = NO_ENDFILE;
570627f7eb2Smrg   u->last_record = 0;
571627f7eb2Smrg   u->current_record = 0;
572627f7eb2Smrg   u->mode = READING;
573627f7eb2Smrg   u->maxrec = 0;
574627f7eb2Smrg   u->bytes_left = 0;
575627f7eb2Smrg   u->saved_pos = 0;
576627f7eb2Smrg 
577627f7eb2Smrg   if (flags->position == POSITION_APPEND)
578627f7eb2Smrg     {
579627f7eb2Smrg       if (sseek (u->s, 0, SEEK_END) < 0)
580627f7eb2Smrg 	{
581627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OS, NULL);
582627f7eb2Smrg 	  goto cleanup;
583627f7eb2Smrg 	}
584627f7eb2Smrg       u->endfile = AT_ENDFILE;
585627f7eb2Smrg     }
586627f7eb2Smrg 
587627f7eb2Smrg   /* Unspecified recl ends up with a processor dependent value.  */
588627f7eb2Smrg 
589627f7eb2Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
590627f7eb2Smrg     {
591627f7eb2Smrg       u->flags.has_recl = 1;
592627f7eb2Smrg       u->recl = opp->recl_in;
593627f7eb2Smrg       u->recl_subrecord = u->recl;
594627f7eb2Smrg       u->bytes_left = u->recl;
595627f7eb2Smrg     }
596627f7eb2Smrg   else
597627f7eb2Smrg     {
598627f7eb2Smrg       u->flags.has_recl = 0;
599627f7eb2Smrg       u->recl = default_recl;
600627f7eb2Smrg       if (compile_options.max_subrecord_length)
601627f7eb2Smrg 	{
602627f7eb2Smrg 	  u->recl_subrecord = compile_options.max_subrecord_length;
603627f7eb2Smrg 	}
604627f7eb2Smrg       else
605627f7eb2Smrg 	{
606627f7eb2Smrg 	  switch (compile_options.record_marker)
607627f7eb2Smrg 	    {
608627f7eb2Smrg 	    case 0:
609627f7eb2Smrg 	      /* Fall through */
610627f7eb2Smrg 	    case sizeof (GFC_INTEGER_4):
611627f7eb2Smrg 	      u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
612627f7eb2Smrg 	      break;
613627f7eb2Smrg 
614627f7eb2Smrg 	    case sizeof (GFC_INTEGER_8):
615627f7eb2Smrg 	      u->recl_subrecord = max_offset - 16;
616627f7eb2Smrg 	      break;
617627f7eb2Smrg 
618627f7eb2Smrg 	    default:
619627f7eb2Smrg 	      runtime_error ("Illegal value for record marker");
620627f7eb2Smrg 	      break;
621627f7eb2Smrg 	    }
622627f7eb2Smrg 	}
623627f7eb2Smrg     }
624627f7eb2Smrg 
625627f7eb2Smrg   /* If the file is direct access, calculate the maximum record number
626627f7eb2Smrg      via a division now instead of letting the multiplication overflow
627627f7eb2Smrg      later.  */
628627f7eb2Smrg 
629627f7eb2Smrg   if (flags->access == ACCESS_DIRECT)
630627f7eb2Smrg     u->maxrec = max_offset / u->recl;
631627f7eb2Smrg 
632627f7eb2Smrg   if (flags->access == ACCESS_STREAM)
633627f7eb2Smrg     {
634627f7eb2Smrg       u->maxrec = max_offset;
635627f7eb2Smrg       /* F2018 (N2137) 12.10.2.26: If the connection is for stream
636627f7eb2Smrg 	 access recl is assigned the value -2.  */
637627f7eb2Smrg       u->recl = -2;
638627f7eb2Smrg       u->bytes_left = 1;
639627f7eb2Smrg       u->strm_pos = stell (u->s) + 1;
640627f7eb2Smrg     }
641627f7eb2Smrg 
642627f7eb2Smrg   u->filename = fc_strdup (opp->file, opp->file_len);
643627f7eb2Smrg 
644627f7eb2Smrg   /* Curiously, the standard requires that the
645627f7eb2Smrg      position specifier be ignored for new files so a newly connected
646627f7eb2Smrg      file starts out at the initial point.  We still need to figure
647627f7eb2Smrg      out if the file is at the end or not.  */
648627f7eb2Smrg 
649627f7eb2Smrg   test_endfile (u);
650627f7eb2Smrg 
651627f7eb2Smrg   if (flags->status == STATUS_SCRATCH && opp->file != NULL)
652627f7eb2Smrg     free (opp->file);
653627f7eb2Smrg 
654627f7eb2Smrg   if (flags->form == FORM_FORMATTED)
655627f7eb2Smrg     {
656627f7eb2Smrg       if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
657627f7eb2Smrg         fbuf_init (u, u->recl);
658627f7eb2Smrg       else
659627f7eb2Smrg         fbuf_init (u, 0);
660627f7eb2Smrg     }
661627f7eb2Smrg   else
662627f7eb2Smrg     u->fbuf = NULL;
663627f7eb2Smrg 
664627f7eb2Smrg   /* Check if asynchrounous.  */
665627f7eb2Smrg   if (flags->async == ASYNC_YES)
666627f7eb2Smrg     init_async_unit (u);
667627f7eb2Smrg   else
668627f7eb2Smrg     u->au = NULL;
669627f7eb2Smrg 
670627f7eb2Smrg   return u;
671627f7eb2Smrg 
672627f7eb2Smrg  cleanup:
673627f7eb2Smrg 
674627f7eb2Smrg   /* Free memory associated with a temporary filename.  */
675627f7eb2Smrg 
676627f7eb2Smrg   if (flags->status == STATUS_SCRATCH && opp->file != NULL)
677627f7eb2Smrg     free (opp->file);
678627f7eb2Smrg 
679627f7eb2Smrg  fail:
680627f7eb2Smrg 
681627f7eb2Smrg   close_unit (u);
682627f7eb2Smrg   return NULL;
683627f7eb2Smrg }
684627f7eb2Smrg 
685627f7eb2Smrg 
686627f7eb2Smrg /* Open a unit which is already open.  This involves changing the
687627f7eb2Smrg    modes or closing what is there now and opening the new file.  */
688627f7eb2Smrg 
689627f7eb2Smrg static void
already_open(st_parameter_open * opp,gfc_unit * u,unit_flags * flags)690627f7eb2Smrg already_open (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
691627f7eb2Smrg {
692627f7eb2Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
693627f7eb2Smrg     {
694627f7eb2Smrg       edit_modes (opp, u, flags);
695627f7eb2Smrg       return;
696627f7eb2Smrg     }
697627f7eb2Smrg 
698627f7eb2Smrg   /* If the file is connected to something else, close it and open a
699627f7eb2Smrg      new unit.  */
700627f7eb2Smrg 
701627f7eb2Smrg   if (!compare_file_filename (u, opp->file, opp->file_len))
702627f7eb2Smrg     {
703627f7eb2Smrg       if (sclose (u->s) == -1)
704627f7eb2Smrg 	{
705627f7eb2Smrg 	  unlock_unit (u);
706627f7eb2Smrg 	  generate_error (&opp->common, LIBERROR_OS,
707627f7eb2Smrg 			  "Error closing file in OPEN statement");
708627f7eb2Smrg 	  return;
709627f7eb2Smrg 	}
710627f7eb2Smrg 
711627f7eb2Smrg       u->s = NULL;
712627f7eb2Smrg 
713627f7eb2Smrg #if !HAVE_UNLINK_OPEN_FILE
714627f7eb2Smrg       if (u->filename && u->flags.status == STATUS_SCRATCH)
715627f7eb2Smrg 	remove (u->filename);
716627f7eb2Smrg #endif
717627f7eb2Smrg       free (u->filename);
718627f7eb2Smrg       u->filename = NULL;
719627f7eb2Smrg 
720627f7eb2Smrg       u = new_unit (opp, u, flags);
721627f7eb2Smrg       if (u != NULL)
722627f7eb2Smrg       unlock_unit (u);
723627f7eb2Smrg       return;
724627f7eb2Smrg     }
725627f7eb2Smrg 
726627f7eb2Smrg   edit_modes (opp, u, flags);
727627f7eb2Smrg }
728627f7eb2Smrg 
729627f7eb2Smrg 
730627f7eb2Smrg /* Open file.  */
731627f7eb2Smrg 
732627f7eb2Smrg extern void st_open (st_parameter_open *opp);
733627f7eb2Smrg export_proto(st_open);
734627f7eb2Smrg 
735627f7eb2Smrg void
st_open(st_parameter_open * opp)736627f7eb2Smrg st_open (st_parameter_open *opp)
737627f7eb2Smrg {
738627f7eb2Smrg   unit_flags flags;
739627f7eb2Smrg   gfc_unit *u = NULL;
740627f7eb2Smrg   GFC_INTEGER_4 cf = opp->common.flags;
741627f7eb2Smrg   unit_convert conv;
742627f7eb2Smrg 
743627f7eb2Smrg   library_start (&opp->common);
744627f7eb2Smrg 
745627f7eb2Smrg   /* Decode options.  */
746627f7eb2Smrg   flags.readonly = !(cf & IOPARM_OPEN_HAS_READONLY) ? 0 : opp->readonly;
747627f7eb2Smrg 
748627f7eb2Smrg   flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
749627f7eb2Smrg     find_option (&opp->common, opp->access, opp->access_len,
750627f7eb2Smrg 		 access_opt, "Bad ACCESS parameter in OPEN statement");
751627f7eb2Smrg 
752627f7eb2Smrg   flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
753627f7eb2Smrg     find_option (&opp->common, opp->action, opp->action_len,
754627f7eb2Smrg 		 action_opt, "Bad ACTION parameter in OPEN statement");
755627f7eb2Smrg 
756627f7eb2Smrg   flags.cc = !(cf & IOPARM_OPEN_HAS_CC) ? CC_UNSPECIFIED :
757627f7eb2Smrg     find_option (&opp->common, opp->cc, opp->cc_len,
758627f7eb2Smrg 		 cc_opt, "Bad CARRIAGECONTROL parameter in OPEN statement");
759627f7eb2Smrg 
760627f7eb2Smrg   flags.share = !(cf & IOPARM_OPEN_HAS_SHARE) ? SHARE_UNSPECIFIED :
761627f7eb2Smrg     find_option (&opp->common, opp->share, opp->share_len,
762627f7eb2Smrg 		 share_opt, "Bad SHARE parameter in OPEN statement");
763627f7eb2Smrg 
764627f7eb2Smrg   flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
765627f7eb2Smrg     find_option (&opp->common, opp->blank, opp->blank_len,
766627f7eb2Smrg 		 blank_opt, "Bad BLANK parameter in OPEN statement");
767627f7eb2Smrg 
768627f7eb2Smrg   flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
769627f7eb2Smrg     find_option (&opp->common, opp->delim, opp->delim_len,
770627f7eb2Smrg 		 delim_opt, "Bad DELIM parameter in OPEN statement");
771627f7eb2Smrg 
772627f7eb2Smrg   flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
773627f7eb2Smrg     find_option (&opp->common, opp->pad, opp->pad_len,
774627f7eb2Smrg 		 pad_opt, "Bad PAD parameter in OPEN statement");
775627f7eb2Smrg 
776627f7eb2Smrg   flags.decimal = !(cf & IOPARM_OPEN_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
777627f7eb2Smrg     find_option (&opp->common, opp->decimal, opp->decimal_len,
778627f7eb2Smrg 		 decimal_opt, "Bad DECIMAL parameter in OPEN statement");
779627f7eb2Smrg 
780627f7eb2Smrg   flags.encoding = !(cf & IOPARM_OPEN_HAS_ENCODING) ? ENCODING_UNSPECIFIED :
781627f7eb2Smrg     find_option (&opp->common, opp->encoding, opp->encoding_len,
782627f7eb2Smrg 		 encoding_opt, "Bad ENCODING parameter in OPEN statement");
783627f7eb2Smrg 
784627f7eb2Smrg   flags.async = !(cf & IOPARM_OPEN_HAS_ASYNCHRONOUS) ? ASYNC_UNSPECIFIED :
785627f7eb2Smrg     find_option (&opp->common, opp->asynchronous, opp->asynchronous_len,
786627f7eb2Smrg 		 async_opt, "Bad ASYNCHRONOUS parameter in OPEN statement");
787627f7eb2Smrg 
788627f7eb2Smrg   flags.round = !(cf & IOPARM_OPEN_HAS_ROUND) ? ROUND_UNSPECIFIED :
789627f7eb2Smrg     find_option (&opp->common, opp->round, opp->round_len,
790627f7eb2Smrg 		 round_opt, "Bad ROUND parameter in OPEN statement");
791627f7eb2Smrg 
792627f7eb2Smrg   flags.sign = !(cf & IOPARM_OPEN_HAS_SIGN) ? SIGN_UNSPECIFIED :
793627f7eb2Smrg     find_option (&opp->common, opp->sign, opp->sign_len,
794627f7eb2Smrg 		 sign_opt, "Bad SIGN parameter in OPEN statement");
795627f7eb2Smrg 
796627f7eb2Smrg   flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
797627f7eb2Smrg     find_option (&opp->common, opp->form, opp->form_len,
798627f7eb2Smrg 		 form_opt, "Bad FORM parameter in OPEN statement");
799627f7eb2Smrg 
800627f7eb2Smrg   flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
801627f7eb2Smrg     find_option (&opp->common, opp->position, opp->position_len,
802627f7eb2Smrg 		 position_opt, "Bad POSITION parameter in OPEN statement");
803627f7eb2Smrg 
804627f7eb2Smrg   flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
805627f7eb2Smrg     find_option (&opp->common, opp->status, opp->status_len,
806627f7eb2Smrg 		 status_opt, "Bad STATUS parameter in OPEN statement");
807627f7eb2Smrg 
808627f7eb2Smrg   /* First, we check wether the convert flag has been set via environment
809627f7eb2Smrg      variable.  This overrides the convert tag in the open statement.  */
810627f7eb2Smrg 
811627f7eb2Smrg   conv = get_unformatted_convert (opp->common.unit);
812627f7eb2Smrg 
813627f7eb2Smrg   if (conv == GFC_CONVERT_NONE)
814627f7eb2Smrg     {
815627f7eb2Smrg       /* Nothing has been set by environment variable, check the convert tag.  */
816627f7eb2Smrg       if (cf & IOPARM_OPEN_HAS_CONVERT)
817627f7eb2Smrg 	conv = find_option (&opp->common, opp->convert, opp->convert_len,
818627f7eb2Smrg 			    convert_opt,
819627f7eb2Smrg 			    "Bad CONVERT parameter in OPEN statement");
820627f7eb2Smrg       else
821627f7eb2Smrg 	conv = compile_options.convert;
822627f7eb2Smrg     }
823627f7eb2Smrg 
824627f7eb2Smrg   switch (conv)
825627f7eb2Smrg     {
826627f7eb2Smrg     case GFC_CONVERT_NATIVE:
827627f7eb2Smrg     case GFC_CONVERT_SWAP:
828627f7eb2Smrg       break;
829627f7eb2Smrg 
830627f7eb2Smrg     case GFC_CONVERT_BIG:
831627f7eb2Smrg       conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
832627f7eb2Smrg       break;
833627f7eb2Smrg 
834627f7eb2Smrg     case GFC_CONVERT_LITTLE:
835627f7eb2Smrg       conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
836627f7eb2Smrg       break;
837627f7eb2Smrg 
838627f7eb2Smrg     default:
839627f7eb2Smrg       internal_error (&opp->common, "Illegal value for CONVERT");
840627f7eb2Smrg       break;
841627f7eb2Smrg     }
842627f7eb2Smrg 
843627f7eb2Smrg   flags.convert = conv;
844627f7eb2Smrg 
845627f7eb2Smrg   if (flags.position != POSITION_UNSPECIFIED
846627f7eb2Smrg       && flags.access == ACCESS_DIRECT)
847627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
848627f7eb2Smrg 		    "Cannot use POSITION with direct access files");
849627f7eb2Smrg 
850627f7eb2Smrg   if (flags.readonly
851627f7eb2Smrg       && flags.action != ACTION_UNSPECIFIED && flags.action != ACTION_READ)
852627f7eb2Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
853627f7eb2Smrg 		    "ACTION conflicts with READONLY in OPEN statement");
854627f7eb2Smrg 
855627f7eb2Smrg   if (flags.access == ACCESS_APPEND)
856627f7eb2Smrg     {
857627f7eb2Smrg       if (flags.position != POSITION_UNSPECIFIED
858627f7eb2Smrg 	  && flags.position != POSITION_APPEND)
859627f7eb2Smrg 	generate_error (&opp->common, LIBERROR_BAD_OPTION,
860627f7eb2Smrg 			"Conflicting ACCESS and POSITION flags in"
861627f7eb2Smrg 			" OPEN statement");
862627f7eb2Smrg 
863627f7eb2Smrg       notify_std (&opp->common, GFC_STD_GNU,
864627f7eb2Smrg 		  "Extension: APPEND as a value for ACCESS in OPEN statement");
865627f7eb2Smrg       flags.access = ACCESS_SEQUENTIAL;
866627f7eb2Smrg       flags.position = POSITION_APPEND;
867627f7eb2Smrg     }
868627f7eb2Smrg 
869627f7eb2Smrg   if (flags.position == POSITION_UNSPECIFIED)
870627f7eb2Smrg     flags.position = POSITION_ASIS;
871627f7eb2Smrg 
872627f7eb2Smrg   if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
873627f7eb2Smrg     {
874627f7eb2Smrg       if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT))
875627f7eb2Smrg 	opp->common.unit = newunit_alloc ();
876627f7eb2Smrg       else if (opp->common.unit < 0)
877627f7eb2Smrg 	{
878627f7eb2Smrg 	  u = find_unit (opp->common.unit);
879627f7eb2Smrg 	  if (u == NULL) /* Negative unit and no NEWUNIT-created unit found.  */
880627f7eb2Smrg 	    {
881627f7eb2Smrg 	      generate_error (&opp->common, LIBERROR_BAD_OPTION,
882627f7eb2Smrg 			      "Bad unit number in OPEN statement");
883627f7eb2Smrg 	      library_end ();
884627f7eb2Smrg 	      return;
885627f7eb2Smrg 	    }
886627f7eb2Smrg 	}
887627f7eb2Smrg 
888627f7eb2Smrg       if (u == NULL)
889627f7eb2Smrg 	u = find_or_create_unit (opp->common.unit);
890627f7eb2Smrg       if (u->s == NULL)
891627f7eb2Smrg 	{
892627f7eb2Smrg 	  u = new_unit (opp, u, &flags);
893627f7eb2Smrg 	  if (u != NULL)
894627f7eb2Smrg 	    unlock_unit (u);
895627f7eb2Smrg 	}
896627f7eb2Smrg       else
897627f7eb2Smrg 	already_open (opp, u, &flags);
898627f7eb2Smrg     }
899627f7eb2Smrg 
900627f7eb2Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT)
901627f7eb2Smrg       && (opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
902627f7eb2Smrg     *opp->newunit = opp->common.unit;
903627f7eb2Smrg 
904627f7eb2Smrg   library_end ();
905627f7eb2Smrg }
906