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