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