open.c revision 1.1.1.3 1 1.1.1.3 mrg /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
2 1.1 mrg Contributed by Andy Vaught
3 1.1 mrg F2003 I/O support contributed by Jerry DeLisle
4 1.1 mrg
5 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran).
6 1.1 mrg
7 1.1 mrg Libgfortran is free software; you can redistribute it and/or modify
8 1.1 mrg it under the terms of the GNU General Public License as published by
9 1.1 mrg the Free Software Foundation; either version 3, or (at your option)
10 1.1 mrg any later version.
11 1.1 mrg
12 1.1 mrg Libgfortran is distributed in the hope that it will be useful,
13 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 mrg GNU General Public License for more details.
16 1.1 mrg
17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
18 1.1 mrg permissions described in the GCC Runtime Library Exception, version
19 1.1 mrg 3.1, as published by the Free Software Foundation.
20 1.1 mrg
21 1.1 mrg You should have received a copy of the GNU General Public License and
22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 1.1 mrg <http://www.gnu.org/licenses/>. */
25 1.1 mrg
26 1.1 mrg #include "io.h"
27 1.1 mrg #include "fbuf.h"
28 1.1 mrg #include "unix.h"
29 1.1 mrg #include "async.h"
30 1.1 mrg
31 1.1 mrg #ifdef HAVE_UNISTD_H
32 1.1 mrg #include <unistd.h>
33 1.1 mrg #endif
34 1.1 mrg
35 1.1 mrg #include <string.h>
36 1.1 mrg #include <errno.h>
37 1.1 mrg
38 1.1 mrg
39 1.1 mrg static const st_option access_opt[] = {
40 1.1 mrg {"sequential", ACCESS_SEQUENTIAL},
41 1.1 mrg {"direct", ACCESS_DIRECT},
42 1.1 mrg {"append", ACCESS_APPEND},
43 1.1 mrg {"stream", ACCESS_STREAM},
44 1.1 mrg {NULL, 0}
45 1.1 mrg };
46 1.1 mrg
47 1.1 mrg static const st_option action_opt[] =
48 1.1 mrg {
49 1.1 mrg { "read", ACTION_READ},
50 1.1 mrg { "write", ACTION_WRITE},
51 1.1 mrg { "readwrite", ACTION_READWRITE},
52 1.1 mrg { NULL, 0}
53 1.1 mrg };
54 1.1 mrg
55 1.1 mrg static const st_option share_opt[] =
56 1.1 mrg {
57 1.1 mrg { "denyrw", SHARE_DENYRW },
58 1.1 mrg { "denynone", SHARE_DENYNONE },
59 1.1 mrg { NULL, 0}
60 1.1 mrg };
61 1.1 mrg
62 1.1 mrg static const st_option cc_opt[] =
63 1.1 mrg {
64 1.1 mrg { "list", CC_LIST },
65 1.1 mrg { "fortran", CC_FORTRAN },
66 1.1 mrg { "none", CC_NONE },
67 1.1 mrg { NULL, 0}
68 1.1 mrg };
69 1.1 mrg
70 1.1 mrg static const st_option blank_opt[] =
71 1.1 mrg {
72 1.1 mrg { "null", BLANK_NULL},
73 1.1 mrg { "zero", BLANK_ZERO},
74 1.1 mrg { NULL, 0}
75 1.1 mrg };
76 1.1 mrg
77 1.1 mrg static const st_option delim_opt[] =
78 1.1 mrg {
79 1.1 mrg { "none", DELIM_NONE},
80 1.1 mrg { "apostrophe", DELIM_APOSTROPHE},
81 1.1 mrg { "quote", DELIM_QUOTE},
82 1.1 mrg { NULL, 0}
83 1.1 mrg };
84 1.1 mrg
85 1.1 mrg static const st_option form_opt[] =
86 1.1 mrg {
87 1.1 mrg { "formatted", FORM_FORMATTED},
88 1.1 mrg { "unformatted", FORM_UNFORMATTED},
89 1.1 mrg { NULL, 0}
90 1.1 mrg };
91 1.1 mrg
92 1.1 mrg static const st_option position_opt[] =
93 1.1 mrg {
94 1.1 mrg { "asis", POSITION_ASIS},
95 1.1 mrg { "rewind", POSITION_REWIND},
96 1.1 mrg { "append", POSITION_APPEND},
97 1.1 mrg { NULL, 0}
98 1.1 mrg };
99 1.1 mrg
100 1.1 mrg static const st_option status_opt[] =
101 1.1 mrg {
102 1.1 mrg { "unknown", STATUS_UNKNOWN},
103 1.1 mrg { "old", STATUS_OLD},
104 1.1 mrg { "new", STATUS_NEW},
105 1.1 mrg { "replace", STATUS_REPLACE},
106 1.1 mrg { "scratch", STATUS_SCRATCH},
107 1.1 mrg { NULL, 0}
108 1.1 mrg };
109 1.1 mrg
110 1.1 mrg static const st_option pad_opt[] =
111 1.1 mrg {
112 1.1 mrg { "yes", PAD_YES},
113 1.1 mrg { "no", PAD_NO},
114 1.1 mrg { NULL, 0}
115 1.1 mrg };
116 1.1 mrg
117 1.1 mrg static const st_option decimal_opt[] =
118 1.1 mrg {
119 1.1 mrg { "point", DECIMAL_POINT},
120 1.1 mrg { "comma", DECIMAL_COMMA},
121 1.1 mrg { NULL, 0}
122 1.1 mrg };
123 1.1 mrg
124 1.1 mrg static const st_option encoding_opt[] =
125 1.1 mrg {
126 1.1 mrg { "utf-8", ENCODING_UTF8},
127 1.1 mrg { "default", ENCODING_DEFAULT},
128 1.1 mrg { NULL, 0}
129 1.1 mrg };
130 1.1 mrg
131 1.1 mrg static const st_option round_opt[] =
132 1.1 mrg {
133 1.1 mrg { "up", ROUND_UP},
134 1.1 mrg { "down", ROUND_DOWN},
135 1.1 mrg { "zero", ROUND_ZERO},
136 1.1 mrg { "nearest", ROUND_NEAREST},
137 1.1 mrg { "compatible", ROUND_COMPATIBLE},
138 1.1 mrg { "processor_defined", ROUND_PROCDEFINED},
139 1.1 mrg { NULL, 0}
140 1.1 mrg };
141 1.1 mrg
142 1.1 mrg static const st_option sign_opt[] =
143 1.1 mrg {
144 1.1 mrg { "plus", SIGN_PLUS},
145 1.1 mrg { "suppress", SIGN_SUPPRESS},
146 1.1 mrg { "processor_defined", SIGN_PROCDEFINED},
147 1.1 mrg { NULL, 0}
148 1.1 mrg };
149 1.1 mrg
150 1.1 mrg static const st_option convert_opt[] =
151 1.1 mrg {
152 1.1 mrg { "native", GFC_CONVERT_NATIVE},
153 1.1 mrg { "swap", GFC_CONVERT_SWAP},
154 1.1 mrg { "big_endian", GFC_CONVERT_BIG},
155 1.1 mrg { "little_endian", GFC_CONVERT_LITTLE},
156 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17
157 1.1.1.3 mrg /* Rather than write a special parsing routine, enumerate all the
158 1.1.1.3 mrg possibilities here. */
159 1.1.1.3 mrg { "r16_ieee", GFC_CONVERT_R16_IEEE},
160 1.1.1.3 mrg { "r16_ibm", GFC_CONVERT_R16_IBM},
161 1.1.1.3 mrg { "native,r16_ieee", GFC_CONVERT_R16_IEEE},
162 1.1.1.3 mrg { "native,r16_ibm", GFC_CONVERT_R16_IBM},
163 1.1.1.3 mrg { "r16_ieee,native", GFC_CONVERT_R16_IEEE},
164 1.1.1.3 mrg { "r16_ibm,native", GFC_CONVERT_R16_IBM},
165 1.1.1.3 mrg { "swap,r16_ieee", GFC_CONVERT_R16_IEEE_SWAP},
166 1.1.1.3 mrg { "swap,r16_ibm", GFC_CONVERT_R16_IBM_SWAP},
167 1.1.1.3 mrg { "r16_ieee,swap", GFC_CONVERT_R16_IEEE_SWAP},
168 1.1.1.3 mrg { "r16_ibm,swap", GFC_CONVERT_R16_IBM_SWAP},
169 1.1.1.3 mrg { "big_endian,r16_ieee", GFC_CONVERT_R16_IEEE_BIG},
170 1.1.1.3 mrg { "big_endian,r16_ibm", GFC_CONVERT_R16_IBM_BIG},
171 1.1.1.3 mrg { "r16_ieee,big_endian", GFC_CONVERT_R16_IEEE_BIG},
172 1.1.1.3 mrg { "r16_ibm,big_endian", GFC_CONVERT_R16_IBM_BIG},
173 1.1.1.3 mrg { "little_endian,r16_ieee", GFC_CONVERT_R16_IEEE_LITTLE},
174 1.1.1.3 mrg { "little_endian,r16_ibm", GFC_CONVERT_R16_IBM_LITTLE},
175 1.1.1.3 mrg { "r16_ieee,little_endian", GFC_CONVERT_R16_IEEE_LITTLE},
176 1.1.1.3 mrg { "r16_ibm,little_endian", GFC_CONVERT_R16_IBM_LITTLE},
177 1.1.1.3 mrg #endif
178 1.1 mrg { NULL, 0}
179 1.1 mrg };
180 1.1 mrg
181 1.1 mrg static const st_option async_opt[] =
182 1.1 mrg {
183 1.1 mrg { "yes", ASYNC_YES},
184 1.1 mrg { "no", ASYNC_NO},
185 1.1 mrg { NULL, 0}
186 1.1 mrg };
187 1.1 mrg
188 1.1 mrg /* Given a unit, test to see if the file is positioned at the terminal
189 1.1 mrg point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
190 1.1 mrg This prevents us from changing the state from AFTER_ENDFILE to
191 1.1 mrg AT_ENDFILE. */
192 1.1 mrg
193 1.1 mrg static void
194 1.1 mrg test_endfile (gfc_unit *u)
195 1.1 mrg {
196 1.1 mrg if (u->endfile == NO_ENDFILE)
197 1.1 mrg {
198 1.1 mrg gfc_offset sz = ssize (u->s);
199 1.1 mrg if (sz == 0 || sz == stell (u->s))
200 1.1 mrg u->endfile = AT_ENDFILE;
201 1.1 mrg }
202 1.1 mrg }
203 1.1 mrg
204 1.1 mrg
205 1.1 mrg /* Change the modes of a file, those that are allowed * to be
206 1.1 mrg changed. */
207 1.1 mrg
208 1.1 mrg static void
209 1.1 mrg edit_modes (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
210 1.1 mrg {
211 1.1 mrg /* Complain about attempts to change the unchangeable. */
212 1.1 mrg
213 1.1 mrg if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
214 1.1 mrg u->flags.status != flags->status)
215 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
216 1.1 mrg "Cannot change STATUS parameter in OPEN statement");
217 1.1 mrg
218 1.1 mrg if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
219 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
220 1.1 mrg "Cannot change ACCESS parameter in OPEN statement");
221 1.1 mrg
222 1.1 mrg if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
223 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
224 1.1 mrg "Cannot change FORM parameter in OPEN statement");
225 1.1 mrg
226 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
227 1.1 mrg && opp->recl_in != u->recl)
228 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
229 1.1 mrg "Cannot change RECL parameter in OPEN statement");
230 1.1 mrg
231 1.1 mrg if (flags->action != ACTION_UNSPECIFIED && u->flags.action != flags->action)
232 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
233 1.1 mrg "Cannot change ACTION parameter in OPEN statement");
234 1.1 mrg
235 1.1 mrg if (flags->share != SHARE_UNSPECIFIED && u->flags.share != flags->share)
236 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
237 1.1 mrg "Cannot change SHARE parameter in OPEN statement");
238 1.1 mrg
239 1.1 mrg if (flags->cc != CC_UNSPECIFIED && u->flags.cc != flags->cc)
240 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
241 1.1 mrg "Cannot change CARRIAGECONTROL parameter in OPEN statement");
242 1.1 mrg
243 1.1 mrg /* Status must be OLD if present. */
244 1.1 mrg
245 1.1 mrg if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
246 1.1 mrg flags->status != STATUS_UNKNOWN)
247 1.1 mrg {
248 1.1 mrg if (flags->status == STATUS_SCRATCH)
249 1.1 mrg notify_std (&opp->common, GFC_STD_GNU,
250 1.1 mrg "OPEN statement must have a STATUS of OLD or UNKNOWN");
251 1.1 mrg else
252 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
253 1.1 mrg "OPEN statement must have a STATUS of OLD or UNKNOWN");
254 1.1 mrg }
255 1.1 mrg
256 1.1 mrg if (u->flags.form == FORM_UNFORMATTED)
257 1.1 mrg {
258 1.1 mrg if (flags->delim != DELIM_UNSPECIFIED)
259 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
260 1.1 mrg "DELIM parameter conflicts with UNFORMATTED form in "
261 1.1 mrg "OPEN statement");
262 1.1 mrg
263 1.1 mrg if (flags->blank != BLANK_UNSPECIFIED)
264 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
265 1.1 mrg "BLANK parameter conflicts with UNFORMATTED form in "
266 1.1 mrg "OPEN statement");
267 1.1 mrg
268 1.1 mrg if (flags->pad != PAD_UNSPECIFIED)
269 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
270 1.1 mrg "PAD parameter conflicts with UNFORMATTED form in "
271 1.1 mrg "OPEN statement");
272 1.1 mrg
273 1.1 mrg if (flags->decimal != DECIMAL_UNSPECIFIED)
274 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
275 1.1 mrg "DECIMAL parameter conflicts with UNFORMATTED form in "
276 1.1 mrg "OPEN statement");
277 1.1 mrg
278 1.1 mrg if (flags->encoding != ENCODING_UNSPECIFIED)
279 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
280 1.1 mrg "ENCODING parameter conflicts with UNFORMATTED form in "
281 1.1 mrg "OPEN statement");
282 1.1 mrg
283 1.1 mrg if (flags->round != ROUND_UNSPECIFIED)
284 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
285 1.1 mrg "ROUND parameter conflicts with UNFORMATTED form in "
286 1.1 mrg "OPEN statement");
287 1.1 mrg
288 1.1 mrg if (flags->sign != SIGN_UNSPECIFIED)
289 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
290 1.1 mrg "SIGN parameter conflicts with UNFORMATTED form in "
291 1.1 mrg "OPEN statement");
292 1.1 mrg }
293 1.1 mrg
294 1.1 mrg if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
295 1.1 mrg {
296 1.1 mrg /* Change the changeable: */
297 1.1 mrg if (flags->blank != BLANK_UNSPECIFIED)
298 1.1 mrg u->flags.blank = flags->blank;
299 1.1 mrg if (flags->delim != DELIM_UNSPECIFIED)
300 1.1 mrg u->flags.delim = flags->delim;
301 1.1 mrg if (flags->pad != PAD_UNSPECIFIED)
302 1.1 mrg u->flags.pad = flags->pad;
303 1.1 mrg if (flags->decimal != DECIMAL_UNSPECIFIED)
304 1.1 mrg u->flags.decimal = flags->decimal;
305 1.1 mrg if (flags->encoding != ENCODING_UNSPECIFIED)
306 1.1 mrg u->flags.encoding = flags->encoding;
307 1.1 mrg if (flags->async != ASYNC_UNSPECIFIED)
308 1.1 mrg u->flags.async = flags->async;
309 1.1 mrg if (flags->round != ROUND_UNSPECIFIED)
310 1.1 mrg u->flags.round = flags->round;
311 1.1 mrg if (flags->sign != SIGN_UNSPECIFIED)
312 1.1 mrg u->flags.sign = flags->sign;
313 1.1 mrg
314 1.1 mrg /* Reposition the file if necessary. */
315 1.1 mrg
316 1.1 mrg switch (flags->position)
317 1.1 mrg {
318 1.1 mrg case POSITION_UNSPECIFIED:
319 1.1 mrg case POSITION_ASIS:
320 1.1 mrg break;
321 1.1 mrg
322 1.1 mrg case POSITION_REWIND:
323 1.1 mrg if (sseek (u->s, 0, SEEK_SET) != 0)
324 1.1 mrg goto seek_error;
325 1.1 mrg
326 1.1 mrg u->current_record = 0;
327 1.1 mrg u->last_record = 0;
328 1.1 mrg
329 1.1 mrg test_endfile (u);
330 1.1 mrg break;
331 1.1 mrg
332 1.1 mrg case POSITION_APPEND:
333 1.1 mrg if (sseek (u->s, 0, SEEK_END) < 0)
334 1.1 mrg goto seek_error;
335 1.1 mrg
336 1.1 mrg if (flags->access != ACCESS_STREAM)
337 1.1 mrg u->current_record = 0;
338 1.1 mrg
339 1.1 mrg u->endfile = AT_ENDFILE; /* We are at the end. */
340 1.1 mrg break;
341 1.1 mrg
342 1.1 mrg seek_error:
343 1.1 mrg generate_error (&opp->common, LIBERROR_OS, NULL);
344 1.1 mrg break;
345 1.1 mrg }
346 1.1 mrg }
347 1.1 mrg
348 1.1 mrg unlock_unit (u);
349 1.1 mrg }
350 1.1 mrg
351 1.1 mrg
352 1.1 mrg /* Open an unused unit. */
353 1.1 mrg
354 1.1 mrg gfc_unit *
355 1.1 mrg new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
356 1.1 mrg {
357 1.1 mrg gfc_unit *u2;
358 1.1 mrg stream *s;
359 1.1 mrg char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
360 1.1 mrg
361 1.1 mrg /* Change unspecifieds to defaults. Leave (flags->action ==
362 1.1 mrg ACTION_UNSPECIFIED) alone so open_external() can set it based on
363 1.1 mrg what type of open actually works. */
364 1.1 mrg
365 1.1 mrg if (flags->access == ACCESS_UNSPECIFIED)
366 1.1 mrg flags->access = ACCESS_SEQUENTIAL;
367 1.1 mrg
368 1.1 mrg if (flags->form == FORM_UNSPECIFIED)
369 1.1 mrg flags->form = (flags->access == ACCESS_SEQUENTIAL)
370 1.1 mrg ? FORM_FORMATTED : FORM_UNFORMATTED;
371 1.1 mrg
372 1.1 mrg if (flags->async == ASYNC_UNSPECIFIED)
373 1.1 mrg flags->async = ASYNC_NO;
374 1.1 mrg
375 1.1 mrg if (flags->status == STATUS_UNSPECIFIED)
376 1.1 mrg flags->status = STATUS_UNKNOWN;
377 1.1 mrg
378 1.1 mrg if (flags->cc == CC_UNSPECIFIED)
379 1.1 mrg flags->cc = flags->form == FORM_UNFORMATTED ? CC_NONE : CC_LIST;
380 1.1 mrg else if (flags->form == FORM_UNFORMATTED && flags->cc != CC_NONE)
381 1.1 mrg {
382 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
383 1.1 mrg "CARRIAGECONTROL parameter conflicts with UNFORMATTED form in "
384 1.1 mrg "OPEN statement");
385 1.1 mrg goto fail;
386 1.1 mrg }
387 1.1 mrg
388 1.1 mrg /* Checks. */
389 1.1 mrg
390 1.1 mrg if (flags->delim != DELIM_UNSPECIFIED
391 1.1 mrg && flags->form == FORM_UNFORMATTED)
392 1.1 mrg {
393 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
394 1.1 mrg "DELIM parameter conflicts with UNFORMATTED form in "
395 1.1 mrg "OPEN statement");
396 1.1 mrg goto fail;
397 1.1 mrg }
398 1.1 mrg
399 1.1 mrg if (flags->blank == BLANK_UNSPECIFIED)
400 1.1 mrg flags->blank = BLANK_NULL;
401 1.1 mrg else
402 1.1 mrg {
403 1.1 mrg if (flags->form == FORM_UNFORMATTED)
404 1.1 mrg {
405 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
406 1.1 mrg "BLANK parameter conflicts with UNFORMATTED form in "
407 1.1 mrg "OPEN statement");
408 1.1 mrg goto fail;
409 1.1 mrg }
410 1.1 mrg }
411 1.1 mrg
412 1.1 mrg if (flags->pad == PAD_UNSPECIFIED)
413 1.1 mrg flags->pad = PAD_YES;
414 1.1 mrg else
415 1.1 mrg {
416 1.1 mrg if (flags->form == FORM_UNFORMATTED)
417 1.1 mrg {
418 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
419 1.1 mrg "PAD parameter conflicts with UNFORMATTED form in "
420 1.1 mrg "OPEN statement");
421 1.1 mrg goto fail;
422 1.1 mrg }
423 1.1 mrg }
424 1.1 mrg
425 1.1 mrg if (flags->decimal == DECIMAL_UNSPECIFIED)
426 1.1 mrg flags->decimal = DECIMAL_POINT;
427 1.1 mrg else
428 1.1 mrg {
429 1.1 mrg if (flags->form == FORM_UNFORMATTED)
430 1.1 mrg {
431 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
432 1.1 mrg "DECIMAL parameter conflicts with UNFORMATTED form "
433 1.1 mrg "in OPEN statement");
434 1.1 mrg goto fail;
435 1.1 mrg }
436 1.1 mrg }
437 1.1 mrg
438 1.1 mrg if (flags->encoding == ENCODING_UNSPECIFIED)
439 1.1 mrg flags->encoding = ENCODING_DEFAULT;
440 1.1 mrg else
441 1.1 mrg {
442 1.1 mrg if (flags->form == FORM_UNFORMATTED)
443 1.1 mrg {
444 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
445 1.1 mrg "ENCODING parameter conflicts with UNFORMATTED form in "
446 1.1 mrg "OPEN statement");
447 1.1 mrg goto fail;
448 1.1 mrg }
449 1.1 mrg }
450 1.1 mrg
451 1.1 mrg /* NB: the value for ROUND when it's not specified by the user does not
452 1.1 mrg have to be PROCESSOR_DEFINED; the standard says that it is
453 1.1 mrg processor dependent, and requires that it is one of the
454 1.1 mrg possible value (see F2003, 9.4.5.13). */
455 1.1 mrg if (flags->round == ROUND_UNSPECIFIED)
456 1.1 mrg flags->round = ROUND_PROCDEFINED;
457 1.1 mrg else
458 1.1 mrg {
459 1.1 mrg if (flags->form == FORM_UNFORMATTED)
460 1.1 mrg {
461 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
462 1.1 mrg "ROUND parameter conflicts with UNFORMATTED form in "
463 1.1 mrg "OPEN statement");
464 1.1 mrg goto fail;
465 1.1 mrg }
466 1.1 mrg }
467 1.1 mrg
468 1.1 mrg if (flags->sign == SIGN_UNSPECIFIED)
469 1.1 mrg flags->sign = SIGN_PROCDEFINED;
470 1.1 mrg else
471 1.1 mrg {
472 1.1 mrg if (flags->form == FORM_UNFORMATTED)
473 1.1 mrg {
474 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
475 1.1 mrg "SIGN parameter conflicts with UNFORMATTED form in "
476 1.1 mrg "OPEN statement");
477 1.1 mrg goto fail;
478 1.1 mrg }
479 1.1 mrg }
480 1.1 mrg
481 1.1 mrg if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
482 1.1 mrg {
483 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
484 1.1 mrg "ACCESS parameter conflicts with SEQUENTIAL access in "
485 1.1 mrg "OPEN statement");
486 1.1 mrg goto fail;
487 1.1 mrg }
488 1.1 mrg else
489 1.1 mrg if (flags->position == POSITION_UNSPECIFIED)
490 1.1 mrg flags->position = POSITION_ASIS;
491 1.1 mrg
492 1.1 mrg if (flags->access == ACCESS_DIRECT
493 1.1 mrg && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
494 1.1 mrg {
495 1.1 mrg generate_error (&opp->common, LIBERROR_MISSING_OPTION,
496 1.1 mrg "Missing RECL parameter in OPEN statement");
497 1.1 mrg goto fail;
498 1.1 mrg }
499 1.1 mrg
500 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
501 1.1 mrg {
502 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
503 1.1 mrg "RECL parameter is non-positive in OPEN statement");
504 1.1 mrg goto fail;
505 1.1 mrg }
506 1.1 mrg
507 1.1 mrg switch (flags->status)
508 1.1 mrg {
509 1.1 mrg case STATUS_SCRATCH:
510 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
511 1.1 mrg {
512 1.1 mrg opp->file = NULL;
513 1.1 mrg break;
514 1.1 mrg }
515 1.1 mrg
516 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
517 1.1 mrg "FILE parameter must not be present in OPEN statement");
518 1.1 mrg goto fail;
519 1.1 mrg
520 1.1 mrg case STATUS_OLD:
521 1.1 mrg case STATUS_NEW:
522 1.1 mrg case STATUS_REPLACE:
523 1.1 mrg case STATUS_UNKNOWN:
524 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
525 1.1 mrg break;
526 1.1 mrg
527 1.1 mrg opp->file = tmpname;
528 1.1 mrg opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d",
529 1.1 mrg (int) opp->common.unit);
530 1.1 mrg break;
531 1.1 mrg
532 1.1 mrg default:
533 1.1 mrg internal_error (&opp->common, "new_unit(): Bad status");
534 1.1 mrg }
535 1.1 mrg
536 1.1 mrg /* Make sure the file isn't already open someplace else.
537 1.1 mrg Do not error if opening file preconnected to stdin, stdout, stderr. */
538 1.1 mrg
539 1.1 mrg u2 = NULL;
540 1.1.1.2 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0
541 1.1.1.2 mrg && !(compile_options.allow_std & GFC_STD_F2018))
542 1.1 mrg u2 = find_file (opp->file, opp->file_len);
543 1.1 mrg if (u2 != NULL
544 1.1 mrg && (options.stdin_unit < 0 || u2->unit_number != options.stdin_unit)
545 1.1 mrg && (options.stdout_unit < 0 || u2->unit_number != options.stdout_unit)
546 1.1 mrg && (options.stderr_unit < 0 || u2->unit_number != options.stderr_unit))
547 1.1 mrg {
548 1.1 mrg unlock_unit (u2);
549 1.1 mrg generate_error (&opp->common, LIBERROR_ALREADY_OPEN, NULL);
550 1.1 mrg goto cleanup;
551 1.1 mrg }
552 1.1 mrg
553 1.1 mrg if (u2 != NULL)
554 1.1 mrg unlock_unit (u2);
555 1.1 mrg
556 1.1 mrg /* If the unit specified is preconnected with a file specified to be open,
557 1.1 mrg then clear the format buffer. */
558 1.1 mrg if ((opp->common.unit == options.stdin_unit ||
559 1.1 mrg opp->common.unit == options.stdout_unit ||
560 1.1 mrg opp->common.unit == options.stderr_unit)
561 1.1 mrg && (opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
562 1.1 mrg fbuf_destroy (u);
563 1.1 mrg
564 1.1 mrg /* Open file. */
565 1.1 mrg
566 1.1 mrg s = open_external (opp, flags);
567 1.1 mrg if (s == NULL)
568 1.1 mrg {
569 1.1 mrg char errbuf[256];
570 1.1 mrg char *path = fc_strdup (opp->file, opp->file_len);
571 1.1 mrg size_t msglen = opp->file_len + 22 + sizeof (errbuf);
572 1.1 mrg char *msg = xmalloc (msglen);
573 1.1 mrg snprintf (msg, msglen, "Cannot open file '%s': %s", path,
574 1.1 mrg gf_strerror (errno, errbuf, sizeof (errbuf)));
575 1.1 mrg generate_error (&opp->common, LIBERROR_OS, msg);
576 1.1 mrg free (msg);
577 1.1 mrg free (path);
578 1.1 mrg goto cleanup;
579 1.1 mrg }
580 1.1 mrg
581 1.1 mrg if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
582 1.1 mrg flags->status = STATUS_OLD;
583 1.1 mrg
584 1.1 mrg /* Create the unit structure. */
585 1.1 mrg
586 1.1 mrg if (u->unit_number != opp->common.unit)
587 1.1 mrg internal_error (&opp->common, "Unit number changed");
588 1.1 mrg u->s = s;
589 1.1 mrg u->flags = *flags;
590 1.1 mrg u->read_bad = 0;
591 1.1 mrg u->endfile = NO_ENDFILE;
592 1.1 mrg u->last_record = 0;
593 1.1 mrg u->current_record = 0;
594 1.1 mrg u->mode = READING;
595 1.1 mrg u->maxrec = 0;
596 1.1 mrg u->bytes_left = 0;
597 1.1 mrg u->saved_pos = 0;
598 1.1 mrg
599 1.1 mrg if (flags->position == POSITION_APPEND)
600 1.1 mrg {
601 1.1 mrg if (sseek (u->s, 0, SEEK_END) < 0)
602 1.1 mrg {
603 1.1 mrg generate_error (&opp->common, LIBERROR_OS, NULL);
604 1.1 mrg goto cleanup;
605 1.1 mrg }
606 1.1 mrg u->endfile = AT_ENDFILE;
607 1.1 mrg }
608 1.1 mrg
609 1.1 mrg /* Unspecified recl ends up with a processor dependent value. */
610 1.1 mrg
611 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
612 1.1 mrg {
613 1.1 mrg u->flags.has_recl = 1;
614 1.1 mrg u->recl = opp->recl_in;
615 1.1 mrg u->recl_subrecord = u->recl;
616 1.1 mrg u->bytes_left = u->recl;
617 1.1 mrg }
618 1.1 mrg else
619 1.1 mrg {
620 1.1 mrg u->flags.has_recl = 0;
621 1.1 mrg u->recl = default_recl;
622 1.1 mrg if (compile_options.max_subrecord_length)
623 1.1 mrg {
624 1.1 mrg u->recl_subrecord = compile_options.max_subrecord_length;
625 1.1 mrg }
626 1.1 mrg else
627 1.1 mrg {
628 1.1 mrg switch (compile_options.record_marker)
629 1.1 mrg {
630 1.1 mrg case 0:
631 1.1 mrg /* Fall through */
632 1.1 mrg case sizeof (GFC_INTEGER_4):
633 1.1 mrg u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
634 1.1 mrg break;
635 1.1 mrg
636 1.1 mrg case sizeof (GFC_INTEGER_8):
637 1.1 mrg u->recl_subrecord = max_offset - 16;
638 1.1 mrg break;
639 1.1 mrg
640 1.1 mrg default:
641 1.1 mrg runtime_error ("Illegal value for record marker");
642 1.1 mrg break;
643 1.1 mrg }
644 1.1 mrg }
645 1.1 mrg }
646 1.1 mrg
647 1.1 mrg /* If the file is direct access, calculate the maximum record number
648 1.1 mrg via a division now instead of letting the multiplication overflow
649 1.1 mrg later. */
650 1.1 mrg
651 1.1 mrg if (flags->access == ACCESS_DIRECT)
652 1.1 mrg u->maxrec = max_offset / u->recl;
653 1.1 mrg
654 1.1 mrg if (flags->access == ACCESS_STREAM)
655 1.1 mrg {
656 1.1 mrg u->maxrec = max_offset;
657 1.1 mrg /* F2018 (N2137) 12.10.2.26: If the connection is for stream
658 1.1 mrg access recl is assigned the value -2. */
659 1.1 mrg u->recl = -2;
660 1.1 mrg u->bytes_left = 1;
661 1.1 mrg u->strm_pos = stell (u->s) + 1;
662 1.1 mrg }
663 1.1 mrg
664 1.1 mrg u->filename = fc_strdup (opp->file, opp->file_len);
665 1.1 mrg
666 1.1 mrg /* Curiously, the standard requires that the
667 1.1 mrg position specifier be ignored for new files so a newly connected
668 1.1 mrg file starts out at the initial point. We still need to figure
669 1.1 mrg out if the file is at the end or not. */
670 1.1 mrg
671 1.1 mrg test_endfile (u);
672 1.1 mrg
673 1.1 mrg if (flags->status == STATUS_SCRATCH && opp->file != NULL)
674 1.1 mrg free (opp->file);
675 1.1 mrg
676 1.1 mrg if (flags->form == FORM_FORMATTED)
677 1.1 mrg {
678 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
679 1.1 mrg fbuf_init (u, u->recl);
680 1.1 mrg else
681 1.1 mrg fbuf_init (u, 0);
682 1.1 mrg }
683 1.1 mrg else
684 1.1 mrg u->fbuf = NULL;
685 1.1 mrg
686 1.1 mrg /* Check if asynchrounous. */
687 1.1 mrg if (flags->async == ASYNC_YES)
688 1.1 mrg init_async_unit (u);
689 1.1 mrg else
690 1.1 mrg u->au = NULL;
691 1.1 mrg
692 1.1 mrg return u;
693 1.1 mrg
694 1.1 mrg cleanup:
695 1.1 mrg
696 1.1 mrg /* Free memory associated with a temporary filename. */
697 1.1 mrg
698 1.1 mrg if (flags->status == STATUS_SCRATCH && opp->file != NULL)
699 1.1 mrg free (opp->file);
700 1.1 mrg
701 1.1 mrg fail:
702 1.1 mrg
703 1.1 mrg close_unit (u);
704 1.1 mrg return NULL;
705 1.1 mrg }
706 1.1 mrg
707 1.1 mrg
708 1.1 mrg /* Open a unit which is already open. This involves changing the
709 1.1 mrg modes or closing what is there now and opening the new file. */
710 1.1 mrg
711 1.1 mrg static void
712 1.1 mrg already_open (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
713 1.1 mrg {
714 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
715 1.1 mrg {
716 1.1 mrg edit_modes (opp, u, flags);
717 1.1 mrg return;
718 1.1 mrg }
719 1.1 mrg
720 1.1 mrg /* If the file is connected to something else, close it and open a
721 1.1 mrg new unit. */
722 1.1 mrg
723 1.1 mrg if (!compare_file_filename (u, opp->file, opp->file_len))
724 1.1 mrg {
725 1.1 mrg if (sclose (u->s) == -1)
726 1.1 mrg {
727 1.1 mrg unlock_unit (u);
728 1.1 mrg generate_error (&opp->common, LIBERROR_OS,
729 1.1 mrg "Error closing file in OPEN statement");
730 1.1 mrg return;
731 1.1 mrg }
732 1.1 mrg
733 1.1 mrg u->s = NULL;
734 1.1 mrg
735 1.1 mrg #if !HAVE_UNLINK_OPEN_FILE
736 1.1 mrg if (u->filename && u->flags.status == STATUS_SCRATCH)
737 1.1 mrg remove (u->filename);
738 1.1 mrg #endif
739 1.1 mrg free (u->filename);
740 1.1 mrg u->filename = NULL;
741 1.1 mrg
742 1.1 mrg u = new_unit (opp, u, flags);
743 1.1 mrg if (u != NULL)
744 1.1 mrg unlock_unit (u);
745 1.1 mrg return;
746 1.1 mrg }
747 1.1 mrg
748 1.1 mrg edit_modes (opp, u, flags);
749 1.1 mrg }
750 1.1 mrg
751 1.1 mrg
752 1.1 mrg /* Open file. */
753 1.1 mrg
754 1.1 mrg extern void st_open (st_parameter_open *opp);
755 1.1 mrg export_proto(st_open);
756 1.1 mrg
757 1.1 mrg void
758 1.1 mrg st_open (st_parameter_open *opp)
759 1.1 mrg {
760 1.1 mrg unit_flags flags;
761 1.1 mrg gfc_unit *u = NULL;
762 1.1 mrg GFC_INTEGER_4 cf = opp->common.flags;
763 1.1 mrg unit_convert conv;
764 1.1 mrg
765 1.1 mrg library_start (&opp->common);
766 1.1 mrg
767 1.1 mrg /* Decode options. */
768 1.1 mrg flags.readonly = !(cf & IOPARM_OPEN_HAS_READONLY) ? 0 : opp->readonly;
769 1.1 mrg
770 1.1 mrg flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
771 1.1 mrg find_option (&opp->common, opp->access, opp->access_len,
772 1.1 mrg access_opt, "Bad ACCESS parameter in OPEN statement");
773 1.1 mrg
774 1.1 mrg flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
775 1.1 mrg find_option (&opp->common, opp->action, opp->action_len,
776 1.1 mrg action_opt, "Bad ACTION parameter in OPEN statement");
777 1.1 mrg
778 1.1 mrg flags.cc = !(cf & IOPARM_OPEN_HAS_CC) ? CC_UNSPECIFIED :
779 1.1 mrg find_option (&opp->common, opp->cc, opp->cc_len,
780 1.1 mrg cc_opt, "Bad CARRIAGECONTROL parameter in OPEN statement");
781 1.1 mrg
782 1.1 mrg flags.share = !(cf & IOPARM_OPEN_HAS_SHARE) ? SHARE_UNSPECIFIED :
783 1.1 mrg find_option (&opp->common, opp->share, opp->share_len,
784 1.1 mrg share_opt, "Bad SHARE parameter in OPEN statement");
785 1.1 mrg
786 1.1 mrg flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
787 1.1 mrg find_option (&opp->common, opp->blank, opp->blank_len,
788 1.1 mrg blank_opt, "Bad BLANK parameter in OPEN statement");
789 1.1 mrg
790 1.1 mrg flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
791 1.1 mrg find_option (&opp->common, opp->delim, opp->delim_len,
792 1.1 mrg delim_opt, "Bad DELIM parameter in OPEN statement");
793 1.1 mrg
794 1.1 mrg flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
795 1.1 mrg find_option (&opp->common, opp->pad, opp->pad_len,
796 1.1 mrg pad_opt, "Bad PAD parameter in OPEN statement");
797 1.1 mrg
798 1.1 mrg flags.decimal = !(cf & IOPARM_OPEN_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
799 1.1 mrg find_option (&opp->common, opp->decimal, opp->decimal_len,
800 1.1 mrg decimal_opt, "Bad DECIMAL parameter in OPEN statement");
801 1.1 mrg
802 1.1 mrg flags.encoding = !(cf & IOPARM_OPEN_HAS_ENCODING) ? ENCODING_UNSPECIFIED :
803 1.1 mrg find_option (&opp->common, opp->encoding, opp->encoding_len,
804 1.1 mrg encoding_opt, "Bad ENCODING parameter in OPEN statement");
805 1.1 mrg
806 1.1 mrg flags.async = !(cf & IOPARM_OPEN_HAS_ASYNCHRONOUS) ? ASYNC_UNSPECIFIED :
807 1.1 mrg find_option (&opp->common, opp->asynchronous, opp->asynchronous_len,
808 1.1 mrg async_opt, "Bad ASYNCHRONOUS parameter in OPEN statement");
809 1.1 mrg
810 1.1 mrg flags.round = !(cf & IOPARM_OPEN_HAS_ROUND) ? ROUND_UNSPECIFIED :
811 1.1 mrg find_option (&opp->common, opp->round, opp->round_len,
812 1.1 mrg round_opt, "Bad ROUND parameter in OPEN statement");
813 1.1 mrg
814 1.1 mrg flags.sign = !(cf & IOPARM_OPEN_HAS_SIGN) ? SIGN_UNSPECIFIED :
815 1.1 mrg find_option (&opp->common, opp->sign, opp->sign_len,
816 1.1 mrg sign_opt, "Bad SIGN parameter in OPEN statement");
817 1.1 mrg
818 1.1 mrg flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
819 1.1 mrg find_option (&opp->common, opp->form, opp->form_len,
820 1.1 mrg form_opt, "Bad FORM parameter in OPEN statement");
821 1.1 mrg
822 1.1 mrg flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
823 1.1 mrg find_option (&opp->common, opp->position, opp->position_len,
824 1.1 mrg position_opt, "Bad POSITION parameter in OPEN statement");
825 1.1 mrg
826 1.1 mrg flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
827 1.1 mrg find_option (&opp->common, opp->status, opp->status_len,
828 1.1 mrg status_opt, "Bad STATUS parameter in OPEN statement");
829 1.1 mrg
830 1.1 mrg /* First, we check wether the convert flag has been set via environment
831 1.1 mrg variable. This overrides the convert tag in the open statement. */
832 1.1 mrg
833 1.1 mrg conv = get_unformatted_convert (opp->common.unit);
834 1.1 mrg
835 1.1 mrg if (conv == GFC_CONVERT_NONE)
836 1.1 mrg {
837 1.1 mrg /* Nothing has been set by environment variable, check the convert tag. */
838 1.1 mrg if (cf & IOPARM_OPEN_HAS_CONVERT)
839 1.1 mrg conv = find_option (&opp->common, opp->convert, opp->convert_len,
840 1.1 mrg convert_opt,
841 1.1 mrg "Bad CONVERT parameter in OPEN statement");
842 1.1 mrg else
843 1.1 mrg conv = compile_options.convert;
844 1.1 mrg }
845 1.1.1.3 mrg
846 1.1.1.3 mrg flags.convert = 0;
847 1.1.1.3 mrg
848 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17
849 1.1.1.3 mrg flags.convert = conv & (GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
850 1.1.1.3 mrg conv &= ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
851 1.1.1.3 mrg #endif
852 1.1.1.3 mrg
853 1.1 mrg switch (conv)
854 1.1 mrg {
855 1.1 mrg case GFC_CONVERT_NATIVE:
856 1.1 mrg case GFC_CONVERT_SWAP:
857 1.1 mrg break;
858 1.1 mrg
859 1.1 mrg case GFC_CONVERT_BIG:
860 1.1 mrg conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
861 1.1 mrg break;
862 1.1 mrg
863 1.1 mrg case GFC_CONVERT_LITTLE:
864 1.1 mrg conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
865 1.1 mrg break;
866 1.1 mrg
867 1.1 mrg default:
868 1.1 mrg internal_error (&opp->common, "Illegal value for CONVERT");
869 1.1 mrg break;
870 1.1 mrg }
871 1.1 mrg
872 1.1.1.3 mrg flags.convert |= conv;
873 1.1 mrg
874 1.1 mrg if (flags.position != POSITION_UNSPECIFIED
875 1.1 mrg && flags.access == ACCESS_DIRECT)
876 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
877 1.1 mrg "Cannot use POSITION with direct access files");
878 1.1 mrg
879 1.1 mrg if (flags.readonly
880 1.1 mrg && flags.action != ACTION_UNSPECIFIED && flags.action != ACTION_READ)
881 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
882 1.1 mrg "ACTION conflicts with READONLY in OPEN statement");
883 1.1 mrg
884 1.1 mrg if (flags.access == ACCESS_APPEND)
885 1.1 mrg {
886 1.1 mrg if (flags.position != POSITION_UNSPECIFIED
887 1.1 mrg && flags.position != POSITION_APPEND)
888 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
889 1.1 mrg "Conflicting ACCESS and POSITION flags in"
890 1.1 mrg " OPEN statement");
891 1.1 mrg
892 1.1 mrg notify_std (&opp->common, GFC_STD_GNU,
893 1.1 mrg "Extension: APPEND as a value for ACCESS in OPEN statement");
894 1.1 mrg flags.access = ACCESS_SEQUENTIAL;
895 1.1 mrg flags.position = POSITION_APPEND;
896 1.1 mrg }
897 1.1 mrg
898 1.1 mrg if (flags.position == POSITION_UNSPECIFIED)
899 1.1 mrg flags.position = POSITION_ASIS;
900 1.1 mrg
901 1.1 mrg if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
902 1.1 mrg {
903 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT))
904 1.1 mrg opp->common.unit = newunit_alloc ();
905 1.1 mrg else if (opp->common.unit < 0)
906 1.1 mrg {
907 1.1 mrg u = find_unit (opp->common.unit);
908 1.1 mrg if (u == NULL) /* Negative unit and no NEWUNIT-created unit found. */
909 1.1 mrg {
910 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
911 1.1 mrg "Bad unit number in OPEN statement");
912 1.1 mrg library_end ();
913 1.1 mrg return;
914 1.1 mrg }
915 1.1 mrg }
916 1.1 mrg
917 1.1 mrg if (u == NULL)
918 1.1 mrg u = find_or_create_unit (opp->common.unit);
919 1.1 mrg if (u->s == NULL)
920 1.1 mrg {
921 1.1 mrg u = new_unit (opp, u, &flags);
922 1.1 mrg if (u != NULL)
923 1.1 mrg unlock_unit (u);
924 1.1 mrg }
925 1.1 mrg else
926 1.1 mrg already_open (opp, u, &flags);
927 1.1 mrg }
928 1.1 mrg
929 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT)
930 1.1 mrg && (opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
931 1.1 mrg *opp->newunit = opp->common.unit;
932 1.1 mrg
933 1.1 mrg library_end ();
934 1.1 mrg }
935