open.c revision 1.1.1.2 1 1.1.1.2 mrg /* Copyright (C) 2002-2020 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 mrg { NULL, 0}
157 1.1 mrg };
158 1.1 mrg
159 1.1 mrg static const st_option async_opt[] =
160 1.1 mrg {
161 1.1 mrg { "yes", ASYNC_YES},
162 1.1 mrg { "no", ASYNC_NO},
163 1.1 mrg { NULL, 0}
164 1.1 mrg };
165 1.1 mrg
166 1.1 mrg /* Given a unit, test to see if the file is positioned at the terminal
167 1.1 mrg point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
168 1.1 mrg This prevents us from changing the state from AFTER_ENDFILE to
169 1.1 mrg AT_ENDFILE. */
170 1.1 mrg
171 1.1 mrg static void
172 1.1 mrg test_endfile (gfc_unit *u)
173 1.1 mrg {
174 1.1 mrg if (u->endfile == NO_ENDFILE)
175 1.1 mrg {
176 1.1 mrg gfc_offset sz = ssize (u->s);
177 1.1 mrg if (sz == 0 || sz == stell (u->s))
178 1.1 mrg u->endfile = AT_ENDFILE;
179 1.1 mrg }
180 1.1 mrg }
181 1.1 mrg
182 1.1 mrg
183 1.1 mrg /* Change the modes of a file, those that are allowed * to be
184 1.1 mrg changed. */
185 1.1 mrg
186 1.1 mrg static void
187 1.1 mrg edit_modes (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
188 1.1 mrg {
189 1.1 mrg /* Complain about attempts to change the unchangeable. */
190 1.1 mrg
191 1.1 mrg if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
192 1.1 mrg u->flags.status != flags->status)
193 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
194 1.1 mrg "Cannot change STATUS parameter in OPEN statement");
195 1.1 mrg
196 1.1 mrg if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
197 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
198 1.1 mrg "Cannot change ACCESS parameter in OPEN statement");
199 1.1 mrg
200 1.1 mrg if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
201 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
202 1.1 mrg "Cannot change FORM parameter in OPEN statement");
203 1.1 mrg
204 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
205 1.1 mrg && opp->recl_in != u->recl)
206 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
207 1.1 mrg "Cannot change RECL parameter in OPEN statement");
208 1.1 mrg
209 1.1 mrg if (flags->action != ACTION_UNSPECIFIED && u->flags.action != flags->action)
210 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
211 1.1 mrg "Cannot change ACTION parameter in OPEN statement");
212 1.1 mrg
213 1.1 mrg if (flags->share != SHARE_UNSPECIFIED && u->flags.share != flags->share)
214 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
215 1.1 mrg "Cannot change SHARE parameter in OPEN statement");
216 1.1 mrg
217 1.1 mrg if (flags->cc != CC_UNSPECIFIED && u->flags.cc != flags->cc)
218 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
219 1.1 mrg "Cannot change CARRIAGECONTROL parameter in OPEN statement");
220 1.1 mrg
221 1.1 mrg /* Status must be OLD if present. */
222 1.1 mrg
223 1.1 mrg if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
224 1.1 mrg flags->status != STATUS_UNKNOWN)
225 1.1 mrg {
226 1.1 mrg if (flags->status == STATUS_SCRATCH)
227 1.1 mrg notify_std (&opp->common, GFC_STD_GNU,
228 1.1 mrg "OPEN statement must have a STATUS of OLD or UNKNOWN");
229 1.1 mrg else
230 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
231 1.1 mrg "OPEN statement must have a STATUS of OLD or UNKNOWN");
232 1.1 mrg }
233 1.1 mrg
234 1.1 mrg if (u->flags.form == FORM_UNFORMATTED)
235 1.1 mrg {
236 1.1 mrg if (flags->delim != DELIM_UNSPECIFIED)
237 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
238 1.1 mrg "DELIM parameter conflicts with UNFORMATTED form in "
239 1.1 mrg "OPEN statement");
240 1.1 mrg
241 1.1 mrg if (flags->blank != BLANK_UNSPECIFIED)
242 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
243 1.1 mrg "BLANK parameter conflicts with UNFORMATTED form in "
244 1.1 mrg "OPEN statement");
245 1.1 mrg
246 1.1 mrg if (flags->pad != PAD_UNSPECIFIED)
247 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
248 1.1 mrg "PAD parameter conflicts with UNFORMATTED form in "
249 1.1 mrg "OPEN statement");
250 1.1 mrg
251 1.1 mrg if (flags->decimal != DECIMAL_UNSPECIFIED)
252 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
253 1.1 mrg "DECIMAL parameter conflicts with UNFORMATTED form in "
254 1.1 mrg "OPEN statement");
255 1.1 mrg
256 1.1 mrg if (flags->encoding != ENCODING_UNSPECIFIED)
257 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
258 1.1 mrg "ENCODING parameter conflicts with UNFORMATTED form in "
259 1.1 mrg "OPEN statement");
260 1.1 mrg
261 1.1 mrg if (flags->round != ROUND_UNSPECIFIED)
262 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
263 1.1 mrg "ROUND parameter conflicts with UNFORMATTED form in "
264 1.1 mrg "OPEN statement");
265 1.1 mrg
266 1.1 mrg if (flags->sign != SIGN_UNSPECIFIED)
267 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
268 1.1 mrg "SIGN parameter conflicts with UNFORMATTED form in "
269 1.1 mrg "OPEN statement");
270 1.1 mrg }
271 1.1 mrg
272 1.1 mrg if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
273 1.1 mrg {
274 1.1 mrg /* Change the changeable: */
275 1.1 mrg if (flags->blank != BLANK_UNSPECIFIED)
276 1.1 mrg u->flags.blank = flags->blank;
277 1.1 mrg if (flags->delim != DELIM_UNSPECIFIED)
278 1.1 mrg u->flags.delim = flags->delim;
279 1.1 mrg if (flags->pad != PAD_UNSPECIFIED)
280 1.1 mrg u->flags.pad = flags->pad;
281 1.1 mrg if (flags->decimal != DECIMAL_UNSPECIFIED)
282 1.1 mrg u->flags.decimal = flags->decimal;
283 1.1 mrg if (flags->encoding != ENCODING_UNSPECIFIED)
284 1.1 mrg u->flags.encoding = flags->encoding;
285 1.1 mrg if (flags->async != ASYNC_UNSPECIFIED)
286 1.1 mrg u->flags.async = flags->async;
287 1.1 mrg if (flags->round != ROUND_UNSPECIFIED)
288 1.1 mrg u->flags.round = flags->round;
289 1.1 mrg if (flags->sign != SIGN_UNSPECIFIED)
290 1.1 mrg u->flags.sign = flags->sign;
291 1.1 mrg
292 1.1 mrg /* Reposition the file if necessary. */
293 1.1 mrg
294 1.1 mrg switch (flags->position)
295 1.1 mrg {
296 1.1 mrg case POSITION_UNSPECIFIED:
297 1.1 mrg case POSITION_ASIS:
298 1.1 mrg break;
299 1.1 mrg
300 1.1 mrg case POSITION_REWIND:
301 1.1 mrg if (sseek (u->s, 0, SEEK_SET) != 0)
302 1.1 mrg goto seek_error;
303 1.1 mrg
304 1.1 mrg u->current_record = 0;
305 1.1 mrg u->last_record = 0;
306 1.1 mrg
307 1.1 mrg test_endfile (u);
308 1.1 mrg break;
309 1.1 mrg
310 1.1 mrg case POSITION_APPEND:
311 1.1 mrg if (sseek (u->s, 0, SEEK_END) < 0)
312 1.1 mrg goto seek_error;
313 1.1 mrg
314 1.1 mrg if (flags->access != ACCESS_STREAM)
315 1.1 mrg u->current_record = 0;
316 1.1 mrg
317 1.1 mrg u->endfile = AT_ENDFILE; /* We are at the end. */
318 1.1 mrg break;
319 1.1 mrg
320 1.1 mrg seek_error:
321 1.1 mrg generate_error (&opp->common, LIBERROR_OS, NULL);
322 1.1 mrg break;
323 1.1 mrg }
324 1.1 mrg }
325 1.1 mrg
326 1.1 mrg unlock_unit (u);
327 1.1 mrg }
328 1.1 mrg
329 1.1 mrg
330 1.1 mrg /* Open an unused unit. */
331 1.1 mrg
332 1.1 mrg gfc_unit *
333 1.1 mrg new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
334 1.1 mrg {
335 1.1 mrg gfc_unit *u2;
336 1.1 mrg stream *s;
337 1.1 mrg char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
338 1.1 mrg
339 1.1 mrg /* Change unspecifieds to defaults. Leave (flags->action ==
340 1.1 mrg ACTION_UNSPECIFIED) alone so open_external() can set it based on
341 1.1 mrg what type of open actually works. */
342 1.1 mrg
343 1.1 mrg if (flags->access == ACCESS_UNSPECIFIED)
344 1.1 mrg flags->access = ACCESS_SEQUENTIAL;
345 1.1 mrg
346 1.1 mrg if (flags->form == FORM_UNSPECIFIED)
347 1.1 mrg flags->form = (flags->access == ACCESS_SEQUENTIAL)
348 1.1 mrg ? FORM_FORMATTED : FORM_UNFORMATTED;
349 1.1 mrg
350 1.1 mrg if (flags->async == ASYNC_UNSPECIFIED)
351 1.1 mrg flags->async = ASYNC_NO;
352 1.1 mrg
353 1.1 mrg if (flags->status == STATUS_UNSPECIFIED)
354 1.1 mrg flags->status = STATUS_UNKNOWN;
355 1.1 mrg
356 1.1 mrg if (flags->cc == CC_UNSPECIFIED)
357 1.1 mrg flags->cc = flags->form == FORM_UNFORMATTED ? CC_NONE : CC_LIST;
358 1.1 mrg else if (flags->form == FORM_UNFORMATTED && flags->cc != CC_NONE)
359 1.1 mrg {
360 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
361 1.1 mrg "CARRIAGECONTROL parameter conflicts with UNFORMATTED form in "
362 1.1 mrg "OPEN statement");
363 1.1 mrg goto fail;
364 1.1 mrg }
365 1.1 mrg
366 1.1 mrg /* Checks. */
367 1.1 mrg
368 1.1 mrg if (flags->delim != DELIM_UNSPECIFIED
369 1.1 mrg && flags->form == FORM_UNFORMATTED)
370 1.1 mrg {
371 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
372 1.1 mrg "DELIM parameter conflicts with UNFORMATTED form in "
373 1.1 mrg "OPEN statement");
374 1.1 mrg goto fail;
375 1.1 mrg }
376 1.1 mrg
377 1.1 mrg if (flags->blank == BLANK_UNSPECIFIED)
378 1.1 mrg flags->blank = BLANK_NULL;
379 1.1 mrg else
380 1.1 mrg {
381 1.1 mrg if (flags->form == FORM_UNFORMATTED)
382 1.1 mrg {
383 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
384 1.1 mrg "BLANK parameter conflicts with UNFORMATTED form in "
385 1.1 mrg "OPEN statement");
386 1.1 mrg goto fail;
387 1.1 mrg }
388 1.1 mrg }
389 1.1 mrg
390 1.1 mrg if (flags->pad == PAD_UNSPECIFIED)
391 1.1 mrg flags->pad = PAD_YES;
392 1.1 mrg else
393 1.1 mrg {
394 1.1 mrg if (flags->form == FORM_UNFORMATTED)
395 1.1 mrg {
396 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
397 1.1 mrg "PAD parameter conflicts with UNFORMATTED form in "
398 1.1 mrg "OPEN statement");
399 1.1 mrg goto fail;
400 1.1 mrg }
401 1.1 mrg }
402 1.1 mrg
403 1.1 mrg if (flags->decimal == DECIMAL_UNSPECIFIED)
404 1.1 mrg flags->decimal = DECIMAL_POINT;
405 1.1 mrg else
406 1.1 mrg {
407 1.1 mrg if (flags->form == FORM_UNFORMATTED)
408 1.1 mrg {
409 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
410 1.1 mrg "DECIMAL parameter conflicts with UNFORMATTED form "
411 1.1 mrg "in OPEN statement");
412 1.1 mrg goto fail;
413 1.1 mrg }
414 1.1 mrg }
415 1.1 mrg
416 1.1 mrg if (flags->encoding == ENCODING_UNSPECIFIED)
417 1.1 mrg flags->encoding = ENCODING_DEFAULT;
418 1.1 mrg else
419 1.1 mrg {
420 1.1 mrg if (flags->form == FORM_UNFORMATTED)
421 1.1 mrg {
422 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
423 1.1 mrg "ENCODING parameter conflicts with UNFORMATTED form in "
424 1.1 mrg "OPEN statement");
425 1.1 mrg goto fail;
426 1.1 mrg }
427 1.1 mrg }
428 1.1 mrg
429 1.1 mrg /* NB: the value for ROUND when it's not specified by the user does not
430 1.1 mrg have to be PROCESSOR_DEFINED; the standard says that it is
431 1.1 mrg processor dependent, and requires that it is one of the
432 1.1 mrg possible value (see F2003, 9.4.5.13). */
433 1.1 mrg if (flags->round == ROUND_UNSPECIFIED)
434 1.1 mrg flags->round = ROUND_PROCDEFINED;
435 1.1 mrg else
436 1.1 mrg {
437 1.1 mrg if (flags->form == FORM_UNFORMATTED)
438 1.1 mrg {
439 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
440 1.1 mrg "ROUND parameter conflicts with UNFORMATTED form in "
441 1.1 mrg "OPEN statement");
442 1.1 mrg goto fail;
443 1.1 mrg }
444 1.1 mrg }
445 1.1 mrg
446 1.1 mrg if (flags->sign == SIGN_UNSPECIFIED)
447 1.1 mrg flags->sign = SIGN_PROCDEFINED;
448 1.1 mrg else
449 1.1 mrg {
450 1.1 mrg if (flags->form == FORM_UNFORMATTED)
451 1.1 mrg {
452 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
453 1.1 mrg "SIGN parameter conflicts with UNFORMATTED form in "
454 1.1 mrg "OPEN statement");
455 1.1 mrg goto fail;
456 1.1 mrg }
457 1.1 mrg }
458 1.1 mrg
459 1.1 mrg if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
460 1.1 mrg {
461 1.1 mrg generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
462 1.1 mrg "ACCESS parameter conflicts with SEQUENTIAL access in "
463 1.1 mrg "OPEN statement");
464 1.1 mrg goto fail;
465 1.1 mrg }
466 1.1 mrg else
467 1.1 mrg if (flags->position == POSITION_UNSPECIFIED)
468 1.1 mrg flags->position = POSITION_ASIS;
469 1.1 mrg
470 1.1 mrg if (flags->access == ACCESS_DIRECT
471 1.1 mrg && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
472 1.1 mrg {
473 1.1 mrg generate_error (&opp->common, LIBERROR_MISSING_OPTION,
474 1.1 mrg "Missing RECL parameter in OPEN statement");
475 1.1 mrg goto fail;
476 1.1 mrg }
477 1.1 mrg
478 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
479 1.1 mrg {
480 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
481 1.1 mrg "RECL parameter is non-positive in OPEN statement");
482 1.1 mrg goto fail;
483 1.1 mrg }
484 1.1 mrg
485 1.1 mrg switch (flags->status)
486 1.1 mrg {
487 1.1 mrg case STATUS_SCRATCH:
488 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
489 1.1 mrg {
490 1.1 mrg opp->file = NULL;
491 1.1 mrg break;
492 1.1 mrg }
493 1.1 mrg
494 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
495 1.1 mrg "FILE parameter must not be present in OPEN statement");
496 1.1 mrg goto fail;
497 1.1 mrg
498 1.1 mrg case STATUS_OLD:
499 1.1 mrg case STATUS_NEW:
500 1.1 mrg case STATUS_REPLACE:
501 1.1 mrg case STATUS_UNKNOWN:
502 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
503 1.1 mrg break;
504 1.1 mrg
505 1.1 mrg opp->file = tmpname;
506 1.1 mrg opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d",
507 1.1 mrg (int) opp->common.unit);
508 1.1 mrg break;
509 1.1 mrg
510 1.1 mrg default:
511 1.1 mrg internal_error (&opp->common, "new_unit(): Bad status");
512 1.1 mrg }
513 1.1 mrg
514 1.1 mrg /* Make sure the file isn't already open someplace else.
515 1.1 mrg Do not error if opening file preconnected to stdin, stdout, stderr. */
516 1.1 mrg
517 1.1 mrg u2 = NULL;
518 1.1.1.2 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0
519 1.1.1.2 mrg && !(compile_options.allow_std & GFC_STD_F2018))
520 1.1 mrg u2 = find_file (opp->file, opp->file_len);
521 1.1 mrg if (u2 != NULL
522 1.1 mrg && (options.stdin_unit < 0 || u2->unit_number != options.stdin_unit)
523 1.1 mrg && (options.stdout_unit < 0 || u2->unit_number != options.stdout_unit)
524 1.1 mrg && (options.stderr_unit < 0 || u2->unit_number != options.stderr_unit))
525 1.1 mrg {
526 1.1 mrg unlock_unit (u2);
527 1.1 mrg generate_error (&opp->common, LIBERROR_ALREADY_OPEN, NULL);
528 1.1 mrg goto cleanup;
529 1.1 mrg }
530 1.1 mrg
531 1.1 mrg if (u2 != NULL)
532 1.1 mrg unlock_unit (u2);
533 1.1 mrg
534 1.1 mrg /* If the unit specified is preconnected with a file specified to be open,
535 1.1 mrg then clear the format buffer. */
536 1.1 mrg if ((opp->common.unit == options.stdin_unit ||
537 1.1 mrg opp->common.unit == options.stdout_unit ||
538 1.1 mrg opp->common.unit == options.stderr_unit)
539 1.1 mrg && (opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
540 1.1 mrg fbuf_destroy (u);
541 1.1 mrg
542 1.1 mrg /* Open file. */
543 1.1 mrg
544 1.1 mrg s = open_external (opp, flags);
545 1.1 mrg if (s == NULL)
546 1.1 mrg {
547 1.1 mrg char errbuf[256];
548 1.1 mrg char *path = fc_strdup (opp->file, opp->file_len);
549 1.1 mrg size_t msglen = opp->file_len + 22 + sizeof (errbuf);
550 1.1 mrg char *msg = xmalloc (msglen);
551 1.1 mrg snprintf (msg, msglen, "Cannot open file '%s': %s", path,
552 1.1 mrg gf_strerror (errno, errbuf, sizeof (errbuf)));
553 1.1 mrg generate_error (&opp->common, LIBERROR_OS, msg);
554 1.1 mrg free (msg);
555 1.1 mrg free (path);
556 1.1 mrg goto cleanup;
557 1.1 mrg }
558 1.1 mrg
559 1.1 mrg if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
560 1.1 mrg flags->status = STATUS_OLD;
561 1.1 mrg
562 1.1 mrg /* Create the unit structure. */
563 1.1 mrg
564 1.1 mrg if (u->unit_number != opp->common.unit)
565 1.1 mrg internal_error (&opp->common, "Unit number changed");
566 1.1 mrg u->s = s;
567 1.1 mrg u->flags = *flags;
568 1.1 mrg u->read_bad = 0;
569 1.1 mrg u->endfile = NO_ENDFILE;
570 1.1 mrg u->last_record = 0;
571 1.1 mrg u->current_record = 0;
572 1.1 mrg u->mode = READING;
573 1.1 mrg u->maxrec = 0;
574 1.1 mrg u->bytes_left = 0;
575 1.1 mrg u->saved_pos = 0;
576 1.1 mrg
577 1.1 mrg if (flags->position == POSITION_APPEND)
578 1.1 mrg {
579 1.1 mrg if (sseek (u->s, 0, SEEK_END) < 0)
580 1.1 mrg {
581 1.1 mrg generate_error (&opp->common, LIBERROR_OS, NULL);
582 1.1 mrg goto cleanup;
583 1.1 mrg }
584 1.1 mrg u->endfile = AT_ENDFILE;
585 1.1 mrg }
586 1.1 mrg
587 1.1 mrg /* Unspecified recl ends up with a processor dependent value. */
588 1.1 mrg
589 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
590 1.1 mrg {
591 1.1 mrg u->flags.has_recl = 1;
592 1.1 mrg u->recl = opp->recl_in;
593 1.1 mrg u->recl_subrecord = u->recl;
594 1.1 mrg u->bytes_left = u->recl;
595 1.1 mrg }
596 1.1 mrg else
597 1.1 mrg {
598 1.1 mrg u->flags.has_recl = 0;
599 1.1 mrg u->recl = default_recl;
600 1.1 mrg if (compile_options.max_subrecord_length)
601 1.1 mrg {
602 1.1 mrg u->recl_subrecord = compile_options.max_subrecord_length;
603 1.1 mrg }
604 1.1 mrg else
605 1.1 mrg {
606 1.1 mrg switch (compile_options.record_marker)
607 1.1 mrg {
608 1.1 mrg case 0:
609 1.1 mrg /* Fall through */
610 1.1 mrg case sizeof (GFC_INTEGER_4):
611 1.1 mrg u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
612 1.1 mrg break;
613 1.1 mrg
614 1.1 mrg case sizeof (GFC_INTEGER_8):
615 1.1 mrg u->recl_subrecord = max_offset - 16;
616 1.1 mrg break;
617 1.1 mrg
618 1.1 mrg default:
619 1.1 mrg runtime_error ("Illegal value for record marker");
620 1.1 mrg break;
621 1.1 mrg }
622 1.1 mrg }
623 1.1 mrg }
624 1.1 mrg
625 1.1 mrg /* If the file is direct access, calculate the maximum record number
626 1.1 mrg via a division now instead of letting the multiplication overflow
627 1.1 mrg later. */
628 1.1 mrg
629 1.1 mrg if (flags->access == ACCESS_DIRECT)
630 1.1 mrg u->maxrec = max_offset / u->recl;
631 1.1 mrg
632 1.1 mrg if (flags->access == ACCESS_STREAM)
633 1.1 mrg {
634 1.1 mrg u->maxrec = max_offset;
635 1.1 mrg /* F2018 (N2137) 12.10.2.26: If the connection is for stream
636 1.1 mrg access recl is assigned the value -2. */
637 1.1 mrg u->recl = -2;
638 1.1 mrg u->bytes_left = 1;
639 1.1 mrg u->strm_pos = stell (u->s) + 1;
640 1.1 mrg }
641 1.1 mrg
642 1.1 mrg u->filename = fc_strdup (opp->file, opp->file_len);
643 1.1 mrg
644 1.1 mrg /* Curiously, the standard requires that the
645 1.1 mrg position specifier be ignored for new files so a newly connected
646 1.1 mrg file starts out at the initial point. We still need to figure
647 1.1 mrg out if the file is at the end or not. */
648 1.1 mrg
649 1.1 mrg test_endfile (u);
650 1.1 mrg
651 1.1 mrg if (flags->status == STATUS_SCRATCH && opp->file != NULL)
652 1.1 mrg free (opp->file);
653 1.1 mrg
654 1.1 mrg if (flags->form == FORM_FORMATTED)
655 1.1 mrg {
656 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
657 1.1 mrg fbuf_init (u, u->recl);
658 1.1 mrg else
659 1.1 mrg fbuf_init (u, 0);
660 1.1 mrg }
661 1.1 mrg else
662 1.1 mrg u->fbuf = NULL;
663 1.1 mrg
664 1.1 mrg /* Check if asynchrounous. */
665 1.1 mrg if (flags->async == ASYNC_YES)
666 1.1 mrg init_async_unit (u);
667 1.1 mrg else
668 1.1 mrg u->au = NULL;
669 1.1 mrg
670 1.1 mrg return u;
671 1.1 mrg
672 1.1 mrg cleanup:
673 1.1 mrg
674 1.1 mrg /* Free memory associated with a temporary filename. */
675 1.1 mrg
676 1.1 mrg if (flags->status == STATUS_SCRATCH && opp->file != NULL)
677 1.1 mrg free (opp->file);
678 1.1 mrg
679 1.1 mrg fail:
680 1.1 mrg
681 1.1 mrg close_unit (u);
682 1.1 mrg return NULL;
683 1.1 mrg }
684 1.1 mrg
685 1.1 mrg
686 1.1 mrg /* Open a unit which is already open. This involves changing the
687 1.1 mrg modes or closing what is there now and opening the new file. */
688 1.1 mrg
689 1.1 mrg static void
690 1.1 mrg already_open (st_parameter_open *opp, gfc_unit *u, unit_flags *flags)
691 1.1 mrg {
692 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
693 1.1 mrg {
694 1.1 mrg edit_modes (opp, u, flags);
695 1.1 mrg return;
696 1.1 mrg }
697 1.1 mrg
698 1.1 mrg /* If the file is connected to something else, close it and open a
699 1.1 mrg new unit. */
700 1.1 mrg
701 1.1 mrg if (!compare_file_filename (u, opp->file, opp->file_len))
702 1.1 mrg {
703 1.1 mrg if (sclose (u->s) == -1)
704 1.1 mrg {
705 1.1 mrg unlock_unit (u);
706 1.1 mrg generate_error (&opp->common, LIBERROR_OS,
707 1.1 mrg "Error closing file in OPEN statement");
708 1.1 mrg return;
709 1.1 mrg }
710 1.1 mrg
711 1.1 mrg u->s = NULL;
712 1.1 mrg
713 1.1 mrg #if !HAVE_UNLINK_OPEN_FILE
714 1.1 mrg if (u->filename && u->flags.status == STATUS_SCRATCH)
715 1.1 mrg remove (u->filename);
716 1.1 mrg #endif
717 1.1 mrg free (u->filename);
718 1.1 mrg u->filename = NULL;
719 1.1 mrg
720 1.1 mrg u = new_unit (opp, u, flags);
721 1.1 mrg if (u != NULL)
722 1.1 mrg unlock_unit (u);
723 1.1 mrg return;
724 1.1 mrg }
725 1.1 mrg
726 1.1 mrg edit_modes (opp, u, flags);
727 1.1 mrg }
728 1.1 mrg
729 1.1 mrg
730 1.1 mrg /* Open file. */
731 1.1 mrg
732 1.1 mrg extern void st_open (st_parameter_open *opp);
733 1.1 mrg export_proto(st_open);
734 1.1 mrg
735 1.1 mrg void
736 1.1 mrg st_open (st_parameter_open *opp)
737 1.1 mrg {
738 1.1 mrg unit_flags flags;
739 1.1 mrg gfc_unit *u = NULL;
740 1.1 mrg GFC_INTEGER_4 cf = opp->common.flags;
741 1.1 mrg unit_convert conv;
742 1.1 mrg
743 1.1 mrg library_start (&opp->common);
744 1.1 mrg
745 1.1 mrg /* Decode options. */
746 1.1 mrg flags.readonly = !(cf & IOPARM_OPEN_HAS_READONLY) ? 0 : opp->readonly;
747 1.1 mrg
748 1.1 mrg flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
749 1.1 mrg find_option (&opp->common, opp->access, opp->access_len,
750 1.1 mrg access_opt, "Bad ACCESS parameter in OPEN statement");
751 1.1 mrg
752 1.1 mrg flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
753 1.1 mrg find_option (&opp->common, opp->action, opp->action_len,
754 1.1 mrg action_opt, "Bad ACTION parameter in OPEN statement");
755 1.1 mrg
756 1.1 mrg flags.cc = !(cf & IOPARM_OPEN_HAS_CC) ? CC_UNSPECIFIED :
757 1.1 mrg find_option (&opp->common, opp->cc, opp->cc_len,
758 1.1 mrg cc_opt, "Bad CARRIAGECONTROL parameter in OPEN statement");
759 1.1 mrg
760 1.1 mrg flags.share = !(cf & IOPARM_OPEN_HAS_SHARE) ? SHARE_UNSPECIFIED :
761 1.1 mrg find_option (&opp->common, opp->share, opp->share_len,
762 1.1 mrg share_opt, "Bad SHARE parameter in OPEN statement");
763 1.1 mrg
764 1.1 mrg flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
765 1.1 mrg find_option (&opp->common, opp->blank, opp->blank_len,
766 1.1 mrg blank_opt, "Bad BLANK parameter in OPEN statement");
767 1.1 mrg
768 1.1 mrg flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
769 1.1 mrg find_option (&opp->common, opp->delim, opp->delim_len,
770 1.1 mrg delim_opt, "Bad DELIM parameter in OPEN statement");
771 1.1 mrg
772 1.1 mrg flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
773 1.1 mrg find_option (&opp->common, opp->pad, opp->pad_len,
774 1.1 mrg pad_opt, "Bad PAD parameter in OPEN statement");
775 1.1 mrg
776 1.1 mrg flags.decimal = !(cf & IOPARM_OPEN_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
777 1.1 mrg find_option (&opp->common, opp->decimal, opp->decimal_len,
778 1.1 mrg decimal_opt, "Bad DECIMAL parameter in OPEN statement");
779 1.1 mrg
780 1.1 mrg flags.encoding = !(cf & IOPARM_OPEN_HAS_ENCODING) ? ENCODING_UNSPECIFIED :
781 1.1 mrg find_option (&opp->common, opp->encoding, opp->encoding_len,
782 1.1 mrg encoding_opt, "Bad ENCODING parameter in OPEN statement");
783 1.1 mrg
784 1.1 mrg flags.async = !(cf & IOPARM_OPEN_HAS_ASYNCHRONOUS) ? ASYNC_UNSPECIFIED :
785 1.1 mrg find_option (&opp->common, opp->asynchronous, opp->asynchronous_len,
786 1.1 mrg async_opt, "Bad ASYNCHRONOUS parameter in OPEN statement");
787 1.1 mrg
788 1.1 mrg flags.round = !(cf & IOPARM_OPEN_HAS_ROUND) ? ROUND_UNSPECIFIED :
789 1.1 mrg find_option (&opp->common, opp->round, opp->round_len,
790 1.1 mrg round_opt, "Bad ROUND parameter in OPEN statement");
791 1.1 mrg
792 1.1 mrg flags.sign = !(cf & IOPARM_OPEN_HAS_SIGN) ? SIGN_UNSPECIFIED :
793 1.1 mrg find_option (&opp->common, opp->sign, opp->sign_len,
794 1.1 mrg sign_opt, "Bad SIGN parameter in OPEN statement");
795 1.1 mrg
796 1.1 mrg flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
797 1.1 mrg find_option (&opp->common, opp->form, opp->form_len,
798 1.1 mrg form_opt, "Bad FORM parameter in OPEN statement");
799 1.1 mrg
800 1.1 mrg flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
801 1.1 mrg find_option (&opp->common, opp->position, opp->position_len,
802 1.1 mrg position_opt, "Bad POSITION parameter in OPEN statement");
803 1.1 mrg
804 1.1 mrg flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
805 1.1 mrg find_option (&opp->common, opp->status, opp->status_len,
806 1.1 mrg status_opt, "Bad STATUS parameter in OPEN statement");
807 1.1 mrg
808 1.1 mrg /* First, we check wether the convert flag has been set via environment
809 1.1 mrg variable. This overrides the convert tag in the open statement. */
810 1.1 mrg
811 1.1 mrg conv = get_unformatted_convert (opp->common.unit);
812 1.1 mrg
813 1.1 mrg if (conv == GFC_CONVERT_NONE)
814 1.1 mrg {
815 1.1 mrg /* Nothing has been set by environment variable, check the convert tag. */
816 1.1 mrg if (cf & IOPARM_OPEN_HAS_CONVERT)
817 1.1 mrg conv = find_option (&opp->common, opp->convert, opp->convert_len,
818 1.1 mrg convert_opt,
819 1.1 mrg "Bad CONVERT parameter in OPEN statement");
820 1.1 mrg else
821 1.1 mrg conv = compile_options.convert;
822 1.1 mrg }
823 1.1 mrg
824 1.1 mrg switch (conv)
825 1.1 mrg {
826 1.1 mrg case GFC_CONVERT_NATIVE:
827 1.1 mrg case GFC_CONVERT_SWAP:
828 1.1 mrg break;
829 1.1 mrg
830 1.1 mrg case GFC_CONVERT_BIG:
831 1.1 mrg conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
832 1.1 mrg break;
833 1.1 mrg
834 1.1 mrg case GFC_CONVERT_LITTLE:
835 1.1 mrg conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
836 1.1 mrg break;
837 1.1 mrg
838 1.1 mrg default:
839 1.1 mrg internal_error (&opp->common, "Illegal value for CONVERT");
840 1.1 mrg break;
841 1.1 mrg }
842 1.1 mrg
843 1.1 mrg flags.convert = conv;
844 1.1 mrg
845 1.1 mrg if (flags.position != POSITION_UNSPECIFIED
846 1.1 mrg && flags.access == ACCESS_DIRECT)
847 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
848 1.1 mrg "Cannot use POSITION with direct access files");
849 1.1 mrg
850 1.1 mrg if (flags.readonly
851 1.1 mrg && flags.action != ACTION_UNSPECIFIED && flags.action != ACTION_READ)
852 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
853 1.1 mrg "ACTION conflicts with READONLY in OPEN statement");
854 1.1 mrg
855 1.1 mrg if (flags.access == ACCESS_APPEND)
856 1.1 mrg {
857 1.1 mrg if (flags.position != POSITION_UNSPECIFIED
858 1.1 mrg && flags.position != POSITION_APPEND)
859 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
860 1.1 mrg "Conflicting ACCESS and POSITION flags in"
861 1.1 mrg " OPEN statement");
862 1.1 mrg
863 1.1 mrg notify_std (&opp->common, GFC_STD_GNU,
864 1.1 mrg "Extension: APPEND as a value for ACCESS in OPEN statement");
865 1.1 mrg flags.access = ACCESS_SEQUENTIAL;
866 1.1 mrg flags.position = POSITION_APPEND;
867 1.1 mrg }
868 1.1 mrg
869 1.1 mrg if (flags.position == POSITION_UNSPECIFIED)
870 1.1 mrg flags.position = POSITION_ASIS;
871 1.1 mrg
872 1.1 mrg if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
873 1.1 mrg {
874 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT))
875 1.1 mrg opp->common.unit = newunit_alloc ();
876 1.1 mrg else if (opp->common.unit < 0)
877 1.1 mrg {
878 1.1 mrg u = find_unit (opp->common.unit);
879 1.1 mrg if (u == NULL) /* Negative unit and no NEWUNIT-created unit found. */
880 1.1 mrg {
881 1.1 mrg generate_error (&opp->common, LIBERROR_BAD_OPTION,
882 1.1 mrg "Bad unit number in OPEN statement");
883 1.1 mrg library_end ();
884 1.1 mrg return;
885 1.1 mrg }
886 1.1 mrg }
887 1.1 mrg
888 1.1 mrg if (u == NULL)
889 1.1 mrg u = find_or_create_unit (opp->common.unit);
890 1.1 mrg if (u->s == NULL)
891 1.1 mrg {
892 1.1 mrg u = new_unit (opp, u, &flags);
893 1.1 mrg if (u != NULL)
894 1.1 mrg unlock_unit (u);
895 1.1 mrg }
896 1.1 mrg else
897 1.1 mrg already_open (opp, u, &flags);
898 1.1 mrg }
899 1.1 mrg
900 1.1 mrg if ((opp->common.flags & IOPARM_OPEN_HAS_NEWUNIT)
901 1.1 mrg && (opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
902 1.1 mrg *opp->newunit = opp->common.unit;
903 1.1 mrg
904 1.1 mrg library_end ();
905 1.1 mrg }
906