xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/io/open.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1*b1e83836Smrg /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
2181254a7Smrg    Contributed by Andy Vaught
3181254a7Smrg    F2003 I/O support contributed by Jerry DeLisle
4181254a7Smrg 
5181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6181254a7Smrg 
7181254a7Smrg Libgfortran is free software; you can redistribute it and/or modify
8181254a7Smrg it under the terms of the GNU General Public License as published by
9181254a7Smrg the Free Software Foundation; either version 3, or (at your option)
10181254a7Smrg any later version.
11181254a7Smrg 
12181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
13181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15181254a7Smrg GNU General Public License for more details.
16181254a7Smrg 
17181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
18181254a7Smrg permissions described in the GCC Runtime Library Exception, version
19181254a7Smrg 3.1, as published by the Free Software Foundation.
20181254a7Smrg 
21181254a7Smrg You should have received a copy of the GNU General Public License and
22181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
23181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24181254a7Smrg <http://www.gnu.org/licenses/>.  */
25181254a7Smrg 
26181254a7Smrg #include "io.h"
27181254a7Smrg #include "fbuf.h"
28181254a7Smrg #include "unix.h"
29181254a7Smrg #include "async.h"
30181254a7Smrg 
31181254a7Smrg #ifdef HAVE_UNISTD_H
32181254a7Smrg #include <unistd.h>
33181254a7Smrg #endif
34181254a7Smrg 
35181254a7Smrg #include <string.h>
36181254a7Smrg #include <errno.h>
37181254a7Smrg 
38181254a7Smrg 
39181254a7Smrg static const st_option access_opt[] = {
40181254a7Smrg   {"sequential", ACCESS_SEQUENTIAL},
41181254a7Smrg   {"direct", ACCESS_DIRECT},
42181254a7Smrg   {"append", ACCESS_APPEND},
43181254a7Smrg   {"stream", ACCESS_STREAM},
44181254a7Smrg   {NULL, 0}
45181254a7Smrg };
46181254a7Smrg 
47181254a7Smrg static const st_option action_opt[] =
48181254a7Smrg {
49181254a7Smrg   { "read", ACTION_READ},
50181254a7Smrg   { "write", ACTION_WRITE},
51181254a7Smrg   { "readwrite", ACTION_READWRITE},
52181254a7Smrg   { NULL, 0}
53181254a7Smrg };
54181254a7Smrg 
55181254a7Smrg static const st_option share_opt[] =
56181254a7Smrg {
57181254a7Smrg   { "denyrw", SHARE_DENYRW },
58181254a7Smrg   { "denynone", SHARE_DENYNONE },
59181254a7Smrg   { NULL, 0}
60181254a7Smrg };
61181254a7Smrg 
62181254a7Smrg static const st_option cc_opt[] =
63181254a7Smrg {
64181254a7Smrg   { "list", CC_LIST },
65181254a7Smrg   { "fortran", CC_FORTRAN },
66181254a7Smrg   { "none", CC_NONE },
67181254a7Smrg   { NULL, 0}
68181254a7Smrg };
69181254a7Smrg 
70181254a7Smrg static const st_option blank_opt[] =
71181254a7Smrg {
72181254a7Smrg   { "null", BLANK_NULL},
73181254a7Smrg   { "zero", BLANK_ZERO},
74181254a7Smrg   { NULL, 0}
75181254a7Smrg };
76181254a7Smrg 
77181254a7Smrg static const st_option delim_opt[] =
78181254a7Smrg {
79181254a7Smrg   { "none", DELIM_NONE},
80181254a7Smrg   { "apostrophe", DELIM_APOSTROPHE},
81181254a7Smrg   { "quote", DELIM_QUOTE},
82181254a7Smrg   { NULL, 0}
83181254a7Smrg };
84181254a7Smrg 
85181254a7Smrg static const st_option form_opt[] =
86181254a7Smrg {
87181254a7Smrg   { "formatted", FORM_FORMATTED},
88181254a7Smrg   { "unformatted", FORM_UNFORMATTED},
89181254a7Smrg   { NULL, 0}
90181254a7Smrg };
91181254a7Smrg 
92181254a7Smrg static const st_option position_opt[] =
93181254a7Smrg {
94181254a7Smrg   { "asis", POSITION_ASIS},
95181254a7Smrg   { "rewind", POSITION_REWIND},
96181254a7Smrg   { "append", POSITION_APPEND},
97181254a7Smrg   { NULL, 0}
98181254a7Smrg };
99181254a7Smrg 
100181254a7Smrg static const st_option status_opt[] =
101181254a7Smrg {
102181254a7Smrg   { "unknown", STATUS_UNKNOWN},
103181254a7Smrg   { "old", STATUS_OLD},
104181254a7Smrg   { "new", STATUS_NEW},
105181254a7Smrg   { "replace", STATUS_REPLACE},
106181254a7Smrg   { "scratch", STATUS_SCRATCH},
107181254a7Smrg   { NULL, 0}
108181254a7Smrg };
109181254a7Smrg 
110181254a7Smrg static const st_option pad_opt[] =
111181254a7Smrg {
112181254a7Smrg   { "yes", PAD_YES},
113181254a7Smrg   { "no", PAD_NO},
114181254a7Smrg   { NULL, 0}
115181254a7Smrg };
116181254a7Smrg 
117181254a7Smrg static const st_option decimal_opt[] =
118181254a7Smrg {
119181254a7Smrg   { "point", DECIMAL_POINT},
120181254a7Smrg   { "comma", DECIMAL_COMMA},
121181254a7Smrg   { NULL, 0}
122181254a7Smrg };
123181254a7Smrg 
124181254a7Smrg static const st_option encoding_opt[] =
125181254a7Smrg {
126181254a7Smrg   { "utf-8", ENCODING_UTF8},
127181254a7Smrg   { "default", ENCODING_DEFAULT},
128181254a7Smrg   { NULL, 0}
129181254a7Smrg };
130181254a7Smrg 
131181254a7Smrg static const st_option round_opt[] =
132181254a7Smrg {
133181254a7Smrg   { "up", ROUND_UP},
134181254a7Smrg   { "down", ROUND_DOWN},
135181254a7Smrg   { "zero", ROUND_ZERO},
136181254a7Smrg   { "nearest", ROUND_NEAREST},
137181254a7Smrg   { "compatible", ROUND_COMPATIBLE},
138181254a7Smrg   { "processor_defined", ROUND_PROCDEFINED},
139181254a7Smrg   { NULL, 0}
140181254a7Smrg };
141181254a7Smrg 
142181254a7Smrg static const st_option sign_opt[] =
143181254a7Smrg {
144181254a7Smrg   { "plus", SIGN_PLUS},
145181254a7Smrg   { "suppress", SIGN_SUPPRESS},
146181254a7Smrg   { "processor_defined", SIGN_PROCDEFINED},
147181254a7Smrg   { NULL, 0}
148181254a7Smrg };
149181254a7Smrg 
150181254a7Smrg static const st_option convert_opt[] =
151181254a7Smrg {
152181254a7Smrg   { "native", GFC_CONVERT_NATIVE},
153181254a7Smrg   { "swap", GFC_CONVERT_SWAP},
154181254a7Smrg   { "big_endian", GFC_CONVERT_BIG},
155181254a7Smrg   { "little_endian", GFC_CONVERT_LITTLE},
156*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
157*b1e83836Smrg   /* Rather than write a special parsing routine, enumerate all the
158*b1e83836Smrg      possibilities here.  */
159*b1e83836Smrg   { "r16_ieee", GFC_CONVERT_R16_IEEE},
160*b1e83836Smrg   { "r16_ibm", GFC_CONVERT_R16_IBM},
161*b1e83836Smrg   { "native,r16_ieee", GFC_CONVERT_R16_IEEE},
162*b1e83836Smrg   { "native,r16_ibm", GFC_CONVERT_R16_IBM},
163*b1e83836Smrg   { "r16_ieee,native", GFC_CONVERT_R16_IEEE},
164*b1e83836Smrg   { "r16_ibm,native", GFC_CONVERT_R16_IBM},
165*b1e83836Smrg   { "swap,r16_ieee", GFC_CONVERT_R16_IEEE_SWAP},
166*b1e83836Smrg   { "swap,r16_ibm", GFC_CONVERT_R16_IBM_SWAP},
167*b1e83836Smrg   { "r16_ieee,swap", GFC_CONVERT_R16_IEEE_SWAP},
168*b1e83836Smrg   { "r16_ibm,swap", GFC_CONVERT_R16_IBM_SWAP},
169*b1e83836Smrg   { "big_endian,r16_ieee", GFC_CONVERT_R16_IEEE_BIG},
170*b1e83836Smrg   { "big_endian,r16_ibm", GFC_CONVERT_R16_IBM_BIG},
171*b1e83836Smrg   { "r16_ieee,big_endian", GFC_CONVERT_R16_IEEE_BIG},
172*b1e83836Smrg   { "r16_ibm,big_endian", GFC_CONVERT_R16_IBM_BIG},
173*b1e83836Smrg   { "little_endian,r16_ieee", GFC_CONVERT_R16_IEEE_LITTLE},
174*b1e83836Smrg   { "little_endian,r16_ibm", GFC_CONVERT_R16_IBM_LITTLE},
175*b1e83836Smrg   { "r16_ieee,little_endian", GFC_CONVERT_R16_IEEE_LITTLE},
176*b1e83836Smrg   { "r16_ibm,little_endian",  GFC_CONVERT_R16_IBM_LITTLE},
177*b1e83836Smrg #endif
178181254a7Smrg   { NULL, 0}
179181254a7Smrg };
180181254a7Smrg 
181181254a7Smrg static const st_option async_opt[] =
182181254a7Smrg {
183181254a7Smrg   { "yes", ASYNC_YES},
184181254a7Smrg   { "no", ASYNC_NO},
185181254a7Smrg   { NULL, 0}
186181254a7Smrg };
187181254a7Smrg 
188181254a7Smrg /* Given a unit, test to see if the file is positioned at the terminal
189181254a7Smrg    point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
190181254a7Smrg    This prevents us from changing the state from AFTER_ENDFILE to
191181254a7Smrg    AT_ENDFILE.  */
192181254a7Smrg 
193181254a7Smrg static void
test_endfile(gfc_unit * u)194181254a7Smrg test_endfile (gfc_unit *u)
195181254a7Smrg {
196181254a7Smrg   if (u->endfile == NO_ENDFILE)
197181254a7Smrg     {
198181254a7Smrg       gfc_offset sz = ssize (u->s);
199181254a7Smrg       if (sz == 0 || sz == stell (u->s))
200181254a7Smrg 	u->endfile = AT_ENDFILE;
201181254a7Smrg     }
202181254a7Smrg }
203181254a7Smrg 
204181254a7Smrg 
205181254a7Smrg /* Change the modes of a file, those that are allowed * to be
206181254a7Smrg    changed.  */
207181254a7Smrg 
208181254a7Smrg static void
edit_modes(st_parameter_open * opp,gfc_unit * u,unit_flags * flags)209181254a7Smrg edit_modes (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
210181254a7Smrg {
211181254a7Smrg   /* Complain about attempts to change the unchangeable.  */
212181254a7Smrg 
213181254a7Smrg   if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
214181254a7Smrg       u->flags.status != flags->status)
215181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
216181254a7Smrg 		    "Cannot change STATUS parameter in OPEN statement");
217181254a7Smrg 
218181254a7Smrg   if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
219181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
220181254a7Smrg 		    "Cannot change ACCESS parameter in OPEN statement");
221181254a7Smrg 
222181254a7Smrg   if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
223181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
224181254a7Smrg 		    "Cannot change FORM parameter in OPEN statement");
225181254a7Smrg 
226181254a7Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
227181254a7Smrg       && opp->recl_in != u->recl)
228181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
229181254a7Smrg 		    "Cannot change RECL parameter in OPEN statement");
230181254a7Smrg 
231181254a7Smrg   if (flags->action != ACTION_UNSPECIFIED && u->flags.action != flags->action)
232181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
233181254a7Smrg 		    "Cannot change ACTION parameter in OPEN statement");
234181254a7Smrg 
235181254a7Smrg   if (flags->share != SHARE_UNSPECIFIED && u->flags.share != flags->share)
236181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
237181254a7Smrg 		    "Cannot change SHARE parameter in OPEN statement");
238181254a7Smrg 
239181254a7Smrg   if (flags->cc != CC_UNSPECIFIED && u->flags.cc != flags->cc)
240181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
241181254a7Smrg 		  "Cannot change CARRIAGECONTROL parameter in OPEN statement");
242181254a7Smrg 
243181254a7Smrg   /* Status must be OLD if present.  */
244181254a7Smrg 
245181254a7Smrg   if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
246181254a7Smrg       flags->status != STATUS_UNKNOWN)
247181254a7Smrg     {
248181254a7Smrg       if (flags->status == STATUS_SCRATCH)
249181254a7Smrg 	notify_std (&opp->common, GFC_STD_GNU,
250181254a7Smrg 		    "OPEN statement must have a STATUS of OLD or UNKNOWN");
251181254a7Smrg       else
252181254a7Smrg 	generate_error (&opp->common, LIBERROR_BAD_OPTION,
253181254a7Smrg 		    "OPEN statement must have a STATUS of OLD or UNKNOWN");
254181254a7Smrg     }
255181254a7Smrg 
256181254a7Smrg   if (u->flags.form == FORM_UNFORMATTED)
257181254a7Smrg     {
258181254a7Smrg       if (flags->delim != DELIM_UNSPECIFIED)
259181254a7Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
260181254a7Smrg 			"DELIM parameter conflicts with UNFORMATTED form in "
261181254a7Smrg 			"OPEN statement");
262181254a7Smrg 
263181254a7Smrg       if (flags->blank != BLANK_UNSPECIFIED)
264181254a7Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
265181254a7Smrg 			"BLANK parameter conflicts with UNFORMATTED form in "
266181254a7Smrg 			"OPEN statement");
267181254a7Smrg 
268181254a7Smrg       if (flags->pad != PAD_UNSPECIFIED)
269181254a7Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
270181254a7Smrg 			"PAD parameter conflicts with UNFORMATTED form in "
271181254a7Smrg 			"OPEN statement");
272181254a7Smrg 
273181254a7Smrg       if (flags->decimal != DECIMAL_UNSPECIFIED)
274181254a7Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
275181254a7Smrg 			"DECIMAL parameter conflicts with UNFORMATTED form in "
276181254a7Smrg 			"OPEN statement");
277181254a7Smrg 
278181254a7Smrg       if (flags->encoding != ENCODING_UNSPECIFIED)
279181254a7Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
280181254a7Smrg 			"ENCODING parameter conflicts with UNFORMATTED form in "
281181254a7Smrg 			"OPEN statement");
282181254a7Smrg 
283181254a7Smrg       if (flags->round != ROUND_UNSPECIFIED)
284181254a7Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
285181254a7Smrg 			"ROUND parameter conflicts with UNFORMATTED form in "
286181254a7Smrg 			"OPEN statement");
287181254a7Smrg 
288181254a7Smrg       if (flags->sign != SIGN_UNSPECIFIED)
289181254a7Smrg 	generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
290181254a7Smrg 			"SIGN parameter conflicts with UNFORMATTED form in "
291181254a7Smrg 			"OPEN statement");
292181254a7Smrg     }
293181254a7Smrg 
294181254a7Smrg   if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
295181254a7Smrg     {
296181254a7Smrg       /* Change the changeable:  */
297181254a7Smrg       if (flags->blank != BLANK_UNSPECIFIED)
298181254a7Smrg 	u->flags.blank = flags->blank;
299181254a7Smrg       if (flags->delim != DELIM_UNSPECIFIED)
300181254a7Smrg 	u->flags.delim = flags->delim;
301181254a7Smrg       if (flags->pad != PAD_UNSPECIFIED)
302181254a7Smrg 	u->flags.pad = flags->pad;
303181254a7Smrg       if (flags->decimal != DECIMAL_UNSPECIFIED)
304181254a7Smrg 	u->flags.decimal = flags->decimal;
305181254a7Smrg       if (flags->encoding != ENCODING_UNSPECIFIED)
306181254a7Smrg 	u->flags.encoding = flags->encoding;
307181254a7Smrg       if (flags->async != ASYNC_UNSPECIFIED)
308181254a7Smrg 	u->flags.async = flags->async;
309181254a7Smrg       if (flags->round != ROUND_UNSPECIFIED)
310181254a7Smrg 	u->flags.round = flags->round;
311181254a7Smrg       if (flags->sign != SIGN_UNSPECIFIED)
312181254a7Smrg 	u->flags.sign = flags->sign;
313181254a7Smrg 
314181254a7Smrg       /* Reposition the file if necessary.  */
315181254a7Smrg 
316181254a7Smrg       switch (flags->position)
317181254a7Smrg 	{
318181254a7Smrg 	case POSITION_UNSPECIFIED:
319181254a7Smrg 	case POSITION_ASIS:
320181254a7Smrg 	  break;
321181254a7Smrg 
322181254a7Smrg 	case POSITION_REWIND:
323181254a7Smrg 	  if (sseek (u->s, 0, SEEK_SET) != 0)
324181254a7Smrg 	    goto seek_error;
325181254a7Smrg 
326181254a7Smrg 	  u->current_record = 0;
327181254a7Smrg 	  u->last_record = 0;
328181254a7Smrg 
329181254a7Smrg 	  test_endfile (u);
330181254a7Smrg 	  break;
331181254a7Smrg 
332181254a7Smrg 	case POSITION_APPEND:
333181254a7Smrg 	  if (sseek (u->s, 0, SEEK_END) < 0)
334181254a7Smrg 	    goto seek_error;
335181254a7Smrg 
336181254a7Smrg 	  if (flags->access != ACCESS_STREAM)
337181254a7Smrg 	    u->current_record = 0;
338181254a7Smrg 
339181254a7Smrg 	  u->endfile = AT_ENDFILE;	/* We are at the end.  */
340181254a7Smrg 	  break;
341181254a7Smrg 
342181254a7Smrg 	seek_error:
343181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OS, NULL);
344181254a7Smrg 	  break;
345181254a7Smrg 	}
346181254a7Smrg     }
347181254a7Smrg 
348181254a7Smrg   unlock_unit (u);
349181254a7Smrg }
350181254a7Smrg 
351181254a7Smrg 
352181254a7Smrg /* Open an unused unit.  */
353181254a7Smrg 
354181254a7Smrg gfc_unit *
new_unit(st_parameter_open * opp,gfc_unit * u,unit_flags * flags)355181254a7Smrg new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
356181254a7Smrg {
357181254a7Smrg   gfc_unit *u2;
358181254a7Smrg   stream *s;
359181254a7Smrg   char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
360181254a7Smrg 
361181254a7Smrg   /* Change unspecifieds to defaults.  Leave (flags->action ==
362181254a7Smrg      ACTION_UNSPECIFIED) alone so open_external() can set it based on
363181254a7Smrg      what type of open actually works.  */
364181254a7Smrg 
365181254a7Smrg   if (flags->access == ACCESS_UNSPECIFIED)
366181254a7Smrg     flags->access = ACCESS_SEQUENTIAL;
367181254a7Smrg 
368181254a7Smrg   if (flags->form == FORM_UNSPECIFIED)
369181254a7Smrg     flags->form = (flags->access == ACCESS_SEQUENTIAL)
370181254a7Smrg       ? FORM_FORMATTED : FORM_UNFORMATTED;
371181254a7Smrg 
372181254a7Smrg   if (flags->async == ASYNC_UNSPECIFIED)
373181254a7Smrg     flags->async = ASYNC_NO;
374181254a7Smrg 
375181254a7Smrg   if (flags->status == STATUS_UNSPECIFIED)
376181254a7Smrg     flags->status = STATUS_UNKNOWN;
377181254a7Smrg 
378181254a7Smrg   if (flags->cc == CC_UNSPECIFIED)
379181254a7Smrg     flags->cc = flags->form == FORM_UNFORMATTED ? CC_NONE : CC_LIST;
380181254a7Smrg   else if (flags->form == FORM_UNFORMATTED && flags->cc != CC_NONE)
381181254a7Smrg     {
382181254a7Smrg       generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
383181254a7Smrg 	  "CARRIAGECONTROL parameter conflicts with UNFORMATTED form in "
384181254a7Smrg 	  "OPEN statement");
385181254a7Smrg       goto fail;
386181254a7Smrg     }
387181254a7Smrg 
388181254a7Smrg   /* Checks.  */
389181254a7Smrg 
390181254a7Smrg   if (flags->delim != DELIM_UNSPECIFIED
391181254a7Smrg       && flags->form == FORM_UNFORMATTED)
392181254a7Smrg     {
393181254a7Smrg       generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
394181254a7Smrg 		      "DELIM parameter conflicts with UNFORMATTED form in "
395181254a7Smrg 		      "OPEN statement");
396181254a7Smrg       goto fail;
397181254a7Smrg     }
398181254a7Smrg 
399181254a7Smrg   if (flags->blank == BLANK_UNSPECIFIED)
400181254a7Smrg     flags->blank = BLANK_NULL;
401181254a7Smrg   else
402181254a7Smrg     {
403181254a7Smrg       if (flags->form == FORM_UNFORMATTED)
404181254a7Smrg 	{
405181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
406181254a7Smrg 			  "BLANK parameter conflicts with UNFORMATTED form in "
407181254a7Smrg 			  "OPEN statement");
408181254a7Smrg 	  goto fail;
409181254a7Smrg 	}
410181254a7Smrg     }
411181254a7Smrg 
412181254a7Smrg   if (flags->pad == PAD_UNSPECIFIED)
413181254a7Smrg     flags->pad = PAD_YES;
414181254a7Smrg   else
415181254a7Smrg     {
416181254a7Smrg       if (flags->form == FORM_UNFORMATTED)
417181254a7Smrg 	{
418181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
419181254a7Smrg 			  "PAD parameter conflicts with UNFORMATTED form in "
420181254a7Smrg 			  "OPEN statement");
421181254a7Smrg 	  goto fail;
422181254a7Smrg 	}
423181254a7Smrg     }
424181254a7Smrg 
425181254a7Smrg   if (flags->decimal == DECIMAL_UNSPECIFIED)
426181254a7Smrg     flags->decimal = DECIMAL_POINT;
427181254a7Smrg   else
428181254a7Smrg     {
429181254a7Smrg       if (flags->form == FORM_UNFORMATTED)
430181254a7Smrg 	{
431181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
432181254a7Smrg 			  "DECIMAL parameter conflicts with UNFORMATTED form "
433181254a7Smrg 			  "in OPEN statement");
434181254a7Smrg 	  goto fail;
435181254a7Smrg 	}
436181254a7Smrg     }
437181254a7Smrg 
438181254a7Smrg   if (flags->encoding == ENCODING_UNSPECIFIED)
439181254a7Smrg     flags->encoding = ENCODING_DEFAULT;
440181254a7Smrg   else
441181254a7Smrg     {
442181254a7Smrg       if (flags->form == FORM_UNFORMATTED)
443181254a7Smrg 	{
444181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
445181254a7Smrg 			  "ENCODING parameter conflicts with UNFORMATTED form in "
446181254a7Smrg 			  "OPEN statement");
447181254a7Smrg 	  goto fail;
448181254a7Smrg 	}
449181254a7Smrg     }
450181254a7Smrg 
451181254a7Smrg   /* NB: the value for ROUND when it's not specified by the user does not
452181254a7Smrg          have to be PROCESSOR_DEFINED; the standard says that it is
453181254a7Smrg 	 processor dependent, and requires that it is one of the
454181254a7Smrg 	 possible value (see F2003, 9.4.5.13).  */
455181254a7Smrg   if (flags->round == ROUND_UNSPECIFIED)
456181254a7Smrg     flags->round = ROUND_PROCDEFINED;
457181254a7Smrg   else
458181254a7Smrg     {
459181254a7Smrg       if (flags->form == FORM_UNFORMATTED)
460181254a7Smrg 	{
461181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
462181254a7Smrg 			  "ROUND parameter conflicts with UNFORMATTED form in "
463181254a7Smrg 			  "OPEN statement");
464181254a7Smrg 	  goto fail;
465181254a7Smrg 	}
466181254a7Smrg     }
467181254a7Smrg 
468181254a7Smrg   if (flags->sign == SIGN_UNSPECIFIED)
469181254a7Smrg     flags->sign = SIGN_PROCDEFINED;
470181254a7Smrg   else
471181254a7Smrg     {
472181254a7Smrg       if (flags->form == FORM_UNFORMATTED)
473181254a7Smrg 	{
474181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
475181254a7Smrg 			  "SIGN parameter conflicts with UNFORMATTED form in "
476181254a7Smrg 			  "OPEN statement");
477181254a7Smrg 	  goto fail;
478181254a7Smrg 	}
479181254a7Smrg     }
480181254a7Smrg 
481181254a7Smrg   if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
482181254a7Smrg    {
483181254a7Smrg      generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
484181254a7Smrg                      "ACCESS parameter conflicts with SEQUENTIAL access in "
485181254a7Smrg                      "OPEN statement");
486181254a7Smrg      goto fail;
487181254a7Smrg    }
488181254a7Smrg   else
489181254a7Smrg    if (flags->position == POSITION_UNSPECIFIED)
490181254a7Smrg      flags->position = POSITION_ASIS;
491181254a7Smrg 
492181254a7Smrg   if (flags->access == ACCESS_DIRECT
493181254a7Smrg       && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
494181254a7Smrg     {
495181254a7Smrg       generate_error (&opp->common, LIBERROR_MISSING_OPTION,
496181254a7Smrg 		      "Missing RECL parameter in OPEN statement");
497181254a7Smrg       goto fail;
498181254a7Smrg     }
499181254a7Smrg 
500181254a7Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
501181254a7Smrg     {
502181254a7Smrg       generate_error (&opp->common, LIBERROR_BAD_OPTION,
503181254a7Smrg 		      "RECL parameter is non-positive in OPEN statement");
504181254a7Smrg       goto fail;
505181254a7Smrg     }
506181254a7Smrg 
507181254a7Smrg   switch (flags->status)
508181254a7Smrg     {
509181254a7Smrg     case STATUS_SCRATCH:
510181254a7Smrg       if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
511181254a7Smrg 	{
512181254a7Smrg 	  opp->file = NULL;
513181254a7Smrg 	  break;
514181254a7Smrg 	}
515181254a7Smrg 
516181254a7Smrg       generate_error (&opp->common, LIBERROR_BAD_OPTION,
517181254a7Smrg 		      "FILE parameter must not be present in OPEN statement");
518181254a7Smrg       goto fail;
519181254a7Smrg 
520181254a7Smrg     case STATUS_OLD:
521181254a7Smrg     case STATUS_NEW:
522181254a7Smrg     case STATUS_REPLACE:
523181254a7Smrg     case STATUS_UNKNOWN:
524181254a7Smrg       if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
525181254a7Smrg 	break;
526181254a7Smrg 
527181254a7Smrg       opp->file = tmpname;
528181254a7Smrg       opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d",
529181254a7Smrg 			       (int) opp->common.unit);
530181254a7Smrg       break;
531181254a7Smrg 
532181254a7Smrg     default:
533181254a7Smrg       internal_error (&opp->common, "new_unit(): Bad status");
534181254a7Smrg     }
535181254a7Smrg 
536181254a7Smrg   /* Make sure the file isn't already open someplace else.
537181254a7Smrg      Do not error if opening file preconnected to stdin, stdout, stderr.  */
538181254a7Smrg 
539181254a7Smrg   u2 = NULL;
540fb8a8121Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0
541fb8a8121Smrg       && !(compile_options.allow_std & GFC_STD_F2018))
542181254a7Smrg     u2 = find_file (opp->file, opp->file_len);
543181254a7Smrg   if (u2 != NULL
544181254a7Smrg       && (options.stdin_unit < 0 || u2->unit_number != options.stdin_unit)
545181254a7Smrg       && (options.stdout_unit < 0 || u2->unit_number != options.stdout_unit)
546181254a7Smrg       && (options.stderr_unit < 0 || u2->unit_number != options.stderr_unit))
547181254a7Smrg     {
548181254a7Smrg       unlock_unit (u2);
549181254a7Smrg       generate_error (&opp->common, LIBERROR_ALREADY_OPEN, NULL);
550181254a7Smrg       goto cleanup;
551181254a7Smrg     }
552181254a7Smrg 
553181254a7Smrg   if (u2 != NULL)
554181254a7Smrg     unlock_unit (u2);
555181254a7Smrg 
556181254a7Smrg   /* If the unit specified is preconnected with a file specified to be open,
557181254a7Smrg      then clear the format buffer.  */
558181254a7Smrg   if ((opp->common.unit == options.stdin_unit ||
559181254a7Smrg        opp->common.unit == options.stdout_unit ||
560181254a7Smrg        opp->common.unit == options.stderr_unit)
561181254a7Smrg       && (opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
562181254a7Smrg     fbuf_destroy (u);
563181254a7Smrg 
564181254a7Smrg   /* Open file.  */
565181254a7Smrg 
566181254a7Smrg   s = open_external (opp, flags);
567181254a7Smrg   if (s == NULL)
568181254a7Smrg     {
569181254a7Smrg       char errbuf[256];
570181254a7Smrg       char *path = fc_strdup (opp->file, opp->file_len);
571181254a7Smrg       size_t msglen = opp->file_len + 22 + sizeof (errbuf);
572181254a7Smrg       char *msg = xmalloc (msglen);
573181254a7Smrg       snprintf (msg, msglen, "Cannot open file '%s': %s", path,
574181254a7Smrg 		gf_strerror (errno, errbuf, sizeof (errbuf)));
575181254a7Smrg       generate_error (&opp->common, LIBERROR_OS, msg);
576181254a7Smrg       free (msg);
577181254a7Smrg       free (path);
578181254a7Smrg       goto cleanup;
579181254a7Smrg     }
580181254a7Smrg 
581181254a7Smrg   if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
582181254a7Smrg     flags->status = STATUS_OLD;
583181254a7Smrg 
584181254a7Smrg   /* Create the unit structure.  */
585181254a7Smrg 
586181254a7Smrg   if (u->unit_number != opp->common.unit)
587181254a7Smrg     internal_error (&opp->common, "Unit number changed");
588181254a7Smrg   u->s = s;
589181254a7Smrg   u->flags = *flags;
590181254a7Smrg   u->read_bad = 0;
591181254a7Smrg   u->endfile = NO_ENDFILE;
592181254a7Smrg   u->last_record = 0;
593181254a7Smrg   u->current_record = 0;
594181254a7Smrg   u->mode = READING;
595181254a7Smrg   u->maxrec = 0;
596181254a7Smrg   u->bytes_left = 0;
597181254a7Smrg   u->saved_pos = 0;
598181254a7Smrg 
599181254a7Smrg   if (flags->position == POSITION_APPEND)
600181254a7Smrg     {
601181254a7Smrg       if (sseek (u->s, 0, SEEK_END) < 0)
602181254a7Smrg 	{
603181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OS, NULL);
604181254a7Smrg 	  goto cleanup;
605181254a7Smrg 	}
606181254a7Smrg       u->endfile = AT_ENDFILE;
607181254a7Smrg     }
608181254a7Smrg 
609181254a7Smrg   /* Unspecified recl ends up with a processor dependent value.  */
610181254a7Smrg 
611181254a7Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
612181254a7Smrg     {
613181254a7Smrg       u->flags.has_recl = 1;
614181254a7Smrg       u->recl = opp->recl_in;
615181254a7Smrg       u->recl_subrecord = u->recl;
616181254a7Smrg       u->bytes_left = u->recl;
617181254a7Smrg     }
618181254a7Smrg   else
619181254a7Smrg     {
620181254a7Smrg       u->flags.has_recl = 0;
621181254a7Smrg       u->recl = default_recl;
622181254a7Smrg       if (compile_options.max_subrecord_length)
623181254a7Smrg 	{
624181254a7Smrg 	  u->recl_subrecord = compile_options.max_subrecord_length;
625181254a7Smrg 	}
626181254a7Smrg       else
627181254a7Smrg 	{
628181254a7Smrg 	  switch (compile_options.record_marker)
629181254a7Smrg 	    {
630181254a7Smrg 	    case 0:
631181254a7Smrg 	      /* Fall through */
632181254a7Smrg 	    case sizeof (GFC_INTEGER_4):
633181254a7Smrg 	      u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
634181254a7Smrg 	      break;
635181254a7Smrg 
636181254a7Smrg 	    case sizeof (GFC_INTEGER_8):
637181254a7Smrg 	      u->recl_subrecord = max_offset - 16;
638181254a7Smrg 	      break;
639181254a7Smrg 
640181254a7Smrg 	    default:
641181254a7Smrg 	      runtime_error ("Illegal value for record marker");
642181254a7Smrg 	      break;
643181254a7Smrg 	    }
644181254a7Smrg 	}
645181254a7Smrg     }
646181254a7Smrg 
647181254a7Smrg   /* If the file is direct access, calculate the maximum record number
648181254a7Smrg      via a division now instead of letting the multiplication overflow
649181254a7Smrg      later.  */
650181254a7Smrg 
651181254a7Smrg   if (flags->access == ACCESS_DIRECT)
652181254a7Smrg     u->maxrec = max_offset / u->recl;
653181254a7Smrg 
654181254a7Smrg   if (flags->access == ACCESS_STREAM)
655181254a7Smrg     {
656181254a7Smrg       u->maxrec = max_offset;
657181254a7Smrg       /* F2018 (N2137) 12.10.2.26: If the connection is for stream
658181254a7Smrg 	 access recl is assigned the value -2.  */
659181254a7Smrg       u->recl = -2;
660181254a7Smrg       u->bytes_left = 1;
661181254a7Smrg       u->strm_pos = stell (u->s) + 1;
662181254a7Smrg     }
663181254a7Smrg 
664181254a7Smrg   u->filename = fc_strdup (opp->file, opp->file_len);
665181254a7Smrg 
666181254a7Smrg   /* Curiously, the standard requires that the
667181254a7Smrg      position specifier be ignored for new files so a newly connected
668181254a7Smrg      file starts out at the initial point.  We still need to figure
669181254a7Smrg      out if the file is at the end or not.  */
670181254a7Smrg 
671181254a7Smrg   test_endfile (u);
672181254a7Smrg 
673181254a7Smrg   if (flags->status == STATUS_SCRATCH && opp->file != NULL)
674181254a7Smrg     free (opp->file);
675181254a7Smrg 
676181254a7Smrg   if (flags->form == FORM_FORMATTED)
677181254a7Smrg     {
678181254a7Smrg       if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
679181254a7Smrg         fbuf_init (u, u->recl);
680181254a7Smrg       else
681181254a7Smrg         fbuf_init (u, 0);
682181254a7Smrg     }
683181254a7Smrg   else
684181254a7Smrg     u->fbuf = NULL;
685181254a7Smrg 
686181254a7Smrg   /* Check if asynchrounous.  */
687181254a7Smrg   if (flags->async == ASYNC_YES)
688181254a7Smrg     init_async_unit (u);
689181254a7Smrg   else
690181254a7Smrg     u->au = NULL;
691181254a7Smrg 
692181254a7Smrg   return u;
693181254a7Smrg 
694181254a7Smrg  cleanup:
695181254a7Smrg 
696181254a7Smrg   /* Free memory associated with a temporary filename.  */
697181254a7Smrg 
698181254a7Smrg   if (flags->status == STATUS_SCRATCH && opp->file != NULL)
699181254a7Smrg     free (opp->file);
700181254a7Smrg 
701181254a7Smrg  fail:
702181254a7Smrg 
703181254a7Smrg   close_unit (u);
704181254a7Smrg   return NULL;
705181254a7Smrg }
706181254a7Smrg 
707181254a7Smrg 
708181254a7Smrg /* Open a unit which is already open.  This involves changing the
709181254a7Smrg    modes or closing what is there now and opening the new file.  */
710181254a7Smrg 
711181254a7Smrg static void
already_open(st_parameter_open * opp,gfc_unit * u,unit_flags * flags)712181254a7Smrg already_open (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
713181254a7Smrg {
714181254a7Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
715181254a7Smrg     {
716181254a7Smrg       edit_modes (opp, u, flags);
717181254a7Smrg       return;
718181254a7Smrg     }
719181254a7Smrg 
720181254a7Smrg   /* If the file is connected to something else, close it and open a
721181254a7Smrg      new unit.  */
722181254a7Smrg 
723181254a7Smrg   if (!compare_file_filename (u, opp->file, opp->file_len))
724181254a7Smrg     {
725181254a7Smrg       if (sclose (u->s) == -1)
726181254a7Smrg 	{
727181254a7Smrg 	  unlock_unit (u);
728181254a7Smrg 	  generate_error (&opp->common, LIBERROR_OS,
729181254a7Smrg 			  "Error closing file in OPEN statement");
730181254a7Smrg 	  return;
731181254a7Smrg 	}
732181254a7Smrg 
733181254a7Smrg       u->s = NULL;
734181254a7Smrg 
735181254a7Smrg #if !HAVE_UNLINK_OPEN_FILE
736181254a7Smrg       if (u->filename && u->flags.status == STATUS_SCRATCH)
737181254a7Smrg 	remove (u->filename);
738181254a7Smrg #endif
739181254a7Smrg       free (u->filename);
740181254a7Smrg       u->filename = NULL;
741181254a7Smrg 
742181254a7Smrg       u = new_unit (opp, u, flags);
743181254a7Smrg       if (u != NULL)
744181254a7Smrg       unlock_unit (u);
745181254a7Smrg       return;
746181254a7Smrg     }
747181254a7Smrg 
748181254a7Smrg   edit_modes (opp, u, flags);
749181254a7Smrg }
750181254a7Smrg 
751181254a7Smrg 
752181254a7Smrg /* Open file.  */
753181254a7Smrg 
754181254a7Smrg extern void st_open (st_parameter_open *opp);
755181254a7Smrg export_proto(st_open);
756181254a7Smrg 
757181254a7Smrg void
st_open(st_parameter_open * opp)758181254a7Smrg st_open (st_parameter_open *opp)
759181254a7Smrg {
760181254a7Smrg   unit_flags flags;
761181254a7Smrg   gfc_unit *u = NULL;
762181254a7Smrg   GFC_INTEGER_4 cf = opp->common.flags;
763181254a7Smrg   unit_convert conv;
764181254a7Smrg 
765181254a7Smrg   library_start (&opp->common);
766181254a7Smrg 
767181254a7Smrg   /* Decode options.  */
768181254a7Smrg   flags.readonly = !(cf & IOPARM_OPEN_HAS_READONLY) ? 0 : opp->readonly;
769181254a7Smrg 
770181254a7Smrg   flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
771181254a7Smrg     find_option (&opp->common, opp->access, opp->access_len,
772181254a7Smrg 		 access_opt, "Bad ACCESS parameter in OPEN statement");
773181254a7Smrg 
774181254a7Smrg   flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
775181254a7Smrg     find_option (&opp->common, opp->action, opp->action_len,
776181254a7Smrg 		 action_opt, "Bad ACTION parameter in OPEN statement");
777181254a7Smrg 
778181254a7Smrg   flags.cc = !(cf & IOPARM_OPEN_HAS_CC) ? CC_UNSPECIFIED :
779181254a7Smrg     find_option (&opp->common, opp->cc, opp->cc_len,
780181254a7Smrg 		 cc_opt, "Bad CARRIAGECONTROL parameter in OPEN statement");
781181254a7Smrg 
782181254a7Smrg   flags.share = !(cf & IOPARM_OPEN_HAS_SHARE) ? SHARE_UNSPECIFIED :
783181254a7Smrg     find_option (&opp->common, opp->share, opp->share_len,
784181254a7Smrg 		 share_opt, "Bad SHARE parameter in OPEN statement");
785181254a7Smrg 
786181254a7Smrg   flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
787181254a7Smrg     find_option (&opp->common, opp->blank, opp->blank_len,
788181254a7Smrg 		 blank_opt, "Bad BLANK parameter in OPEN statement");
789181254a7Smrg 
790181254a7Smrg   flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
791181254a7Smrg     find_option (&opp->common, opp->delim, opp->delim_len,
792181254a7Smrg 		 delim_opt, "Bad DELIM parameter in OPEN statement");
793181254a7Smrg 
794181254a7Smrg   flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
795181254a7Smrg     find_option (&opp->common, opp->pad, opp->pad_len,
796181254a7Smrg 		 pad_opt, "Bad PAD parameter in OPEN statement");
797181254a7Smrg 
798181254a7Smrg   flags.decimal = !(cf & IOPARM_OPEN_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
799181254a7Smrg     find_option (&opp->common, opp->decimal, opp->decimal_len,
800181254a7Smrg 		 decimal_opt, "Bad DECIMAL parameter in OPEN statement");
801181254a7Smrg 
802181254a7Smrg   flags.encoding = !(cf & IOPARM_OPEN_HAS_ENCODING) ? ENCODING_UNSPECIFIED :
803181254a7Smrg     find_option (&opp->common, opp->encoding, opp->encoding_len,
804181254a7Smrg 		 encoding_opt, "Bad ENCODING parameter in OPEN statement");
805181254a7Smrg 
806181254a7Smrg   flags.async = !(cf & IOPARM_OPEN_HAS_ASYNCHRONOUS) ? ASYNC_UNSPECIFIED :
807181254a7Smrg     find_option (&opp->common, opp->asynchronous, opp->asynchronous_len,
808181254a7Smrg 		 async_opt, "Bad ASYNCHRONOUS parameter in OPEN statement");
809181254a7Smrg 
810181254a7Smrg   flags.round = !(cf & IOPARM_OPEN_HAS_ROUND) ? ROUND_UNSPECIFIED :
811181254a7Smrg     find_option (&opp->common, opp->round, opp->round_len,
812181254a7Smrg 		 round_opt, "Bad ROUND parameter in OPEN statement");
813181254a7Smrg 
814181254a7Smrg   flags.sign = !(cf & IOPARM_OPEN_HAS_SIGN) ? SIGN_UNSPECIFIED :
815181254a7Smrg     find_option (&opp->common, opp->sign, opp->sign_len,
816181254a7Smrg 		 sign_opt, "Bad SIGN parameter in OPEN statement");
817181254a7Smrg 
818181254a7Smrg   flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
819181254a7Smrg     find_option (&opp->common, opp->form, opp->form_len,
820181254a7Smrg 		 form_opt, "Bad FORM parameter in OPEN statement");
821181254a7Smrg 
822181254a7Smrg   flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
823181254a7Smrg     find_option (&opp->common, opp->position, opp->position_len,
824181254a7Smrg 		 position_opt, "Bad POSITION parameter in OPEN statement");
825181254a7Smrg 
826181254a7Smrg   flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
827181254a7Smrg     find_option (&opp->common, opp->status, opp->status_len,
828181254a7Smrg 		 status_opt, "Bad STATUS parameter in OPEN statement");
829181254a7Smrg 
830181254a7Smrg   /* First, we check wether the convert flag has been set via environment
831181254a7Smrg      variable.  This overrides the convert tag in the open statement.  */
832181254a7Smrg 
833181254a7Smrg   conv = get_unformatted_convert (opp->common.unit);
834181254a7Smrg 
835181254a7Smrg   if (conv == GFC_CONVERT_NONE)
836181254a7Smrg     {
837181254a7Smrg       /* Nothing has been set by environment variable, check the convert tag.  */
838181254a7Smrg       if (cf & IOPARM_OPEN_HAS_CONVERT)
839181254a7Smrg 	conv = find_option (&opp->common, opp->convert, opp->convert_len,
840181254a7Smrg 			    convert_opt,
841181254a7Smrg 			    "Bad CONVERT parameter in OPEN statement");
842181254a7Smrg       else
843181254a7Smrg 	conv = compile_options.convert;
844181254a7Smrg     }
845181254a7Smrg 
846*b1e83836Smrg   flags.convert = 0;
847*b1e83836Smrg 
848*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
849*b1e83836Smrg   flags.convert = conv & (GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
850*b1e83836Smrg   conv &= ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
851*b1e83836Smrg #endif
852*b1e83836Smrg 
853181254a7Smrg   switch (conv)
854181254a7Smrg     {
855181254a7Smrg     case GFC_CONVERT_NATIVE:
856181254a7Smrg     case GFC_CONVERT_SWAP:
857181254a7Smrg       break;
858181254a7Smrg 
859181254a7Smrg     case GFC_CONVERT_BIG:
860181254a7Smrg       conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
861181254a7Smrg       break;
862181254a7Smrg 
863181254a7Smrg     case GFC_CONVERT_LITTLE:
864181254a7Smrg       conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
865181254a7Smrg       break;
866181254a7Smrg 
867181254a7Smrg     default:
868181254a7Smrg       internal_error (&opp->common, "Illegal value for CONVERT");
869181254a7Smrg       break;
870181254a7Smrg     }
871181254a7Smrg 
872*b1e83836Smrg   flags.convert |= conv;
873181254a7Smrg 
874181254a7Smrg   if (flags.position != POSITION_UNSPECIFIED
875181254a7Smrg       && flags.access == ACCESS_DIRECT)
876181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
877181254a7Smrg 		    "Cannot use POSITION with direct access files");
878181254a7Smrg 
879181254a7Smrg   if (flags.readonly
880181254a7Smrg       && flags.action != ACTION_UNSPECIFIED && flags.action != ACTION_READ)
881181254a7Smrg     generate_error (&opp->common, LIBERROR_BAD_OPTION,
882181254a7Smrg 		    "ACTION conflicts with READONLY in OPEN statement");
883181254a7Smrg 
884181254a7Smrg   if (flags.access == ACCESS_APPEND)
885181254a7Smrg     {
886181254a7Smrg       if (flags.position != POSITION_UNSPECIFIED
887181254a7Smrg 	  && flags.position != POSITION_APPEND)
888181254a7Smrg 	generate_error (&opp->common, LIBERROR_BAD_OPTION,
889181254a7Smrg 			"Conflicting ACCESS and POSITION flags in"
890181254a7Smrg 			" OPEN statement");
891181254a7Smrg 
892181254a7Smrg       notify_std (&opp->common, GFC_STD_GNU,
893181254a7Smrg 		  "Extension: APPEND as a value for ACCESS in OPEN statement");
894181254a7Smrg       flags.access = ACCESS_SEQUENTIAL;
895181254a7Smrg       flags.position = POSITION_APPEND;
896181254a7Smrg     }
897181254a7Smrg 
898181254a7Smrg   if (flags.position == POSITION_UNSPECIFIED)
899181254a7Smrg     flags.position = POSITION_ASIS;
900181254a7Smrg 
901181254a7Smrg   if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
902181254a7Smrg     {
903181254a7Smrg       if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT))
904181254a7Smrg 	opp->common.unit = newunit_alloc ();
905181254a7Smrg       else if (opp->common.unit < 0)
906181254a7Smrg 	{
907181254a7Smrg 	  u = find_unit (opp->common.unit);
908181254a7Smrg 	  if (u == NULL) /* Negative unit and no NEWUNIT-created unit found.  */
909181254a7Smrg 	    {
910181254a7Smrg 	      generate_error (&opp->common, LIBERROR_BAD_OPTION,
911181254a7Smrg 			      "Bad unit number in OPEN statement");
912181254a7Smrg 	      library_end ();
913181254a7Smrg 	      return;
914181254a7Smrg 	    }
915181254a7Smrg 	}
916181254a7Smrg 
917181254a7Smrg       if (u == NULL)
918181254a7Smrg 	u = find_or_create_unit (opp->common.unit);
919181254a7Smrg       if (u->s == NULL)
920181254a7Smrg 	{
921181254a7Smrg 	  u = new_unit (opp, u, &flags);
922181254a7Smrg 	  if (u != NULL)
923181254a7Smrg 	    unlock_unit (u);
924181254a7Smrg 	}
925181254a7Smrg       else
926181254a7Smrg 	already_open (opp, u, &flags);
927181254a7Smrg     }
928181254a7Smrg 
929181254a7Smrg   if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT)
930181254a7Smrg       && (opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
931181254a7Smrg     *opp->newunit = opp->common.unit;
932181254a7Smrg 
933181254a7Smrg   library_end ();
934181254a7Smrg }
935