]>
Commit | Line | Data |
---|---|---|
a5544970 | 1 | /* Copyright (C) 2002-2019 Free Software Foundation, Inc. |
6de9cd9a | 2 | Contributed by Andy Vaught |
29dc5138 | 3 | Namelist transfer functions contributed by Paul Thomas |
10256cbe | 4 | F2003 I/O support contributed by Jerry DeLisle |
6de9cd9a | 5 | |
58fc89f6 | 6 | This file is part of the GNU Fortran runtime library (libgfortran). |
6de9cd9a DN |
7 | |
8 | Libgfortran is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
748086b7 | 10 | the Free Software Foundation; either version 3, or (at your option) |
6de9cd9a DN |
11 | any later version. |
12 | ||
13 | Libgfortran is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
748086b7 JJ |
18 | Under Section 7 of GPL version 3, you are granted additional |
19 | permissions described in the GCC Runtime Library Exception, version | |
20 | 3.1, as published by the Free Software Foundation. | |
21 | ||
22 | You should have received a copy of the GNU General Public License and | |
23 | a copy of the GCC Runtime Library Exception along with this program; | |
24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
25 | <http://www.gnu.org/licenses/>. */ | |
6de9cd9a DN |
26 | |
27 | ||
7fcb1804 | 28 | /* transfer.c -- Top level handling of data transfer statements. */ |
6de9cd9a | 29 | |
36ae8a61 | 30 | #include "io.h" |
92cbdb68 JB |
31 | #include "fbuf.h" |
32 | #include "format.h" | |
33 | #include "unix.h" | |
2b4c9065 | 34 | #include "async.h" |
6de9cd9a | 35 | #include <string.h> |
7812c78c | 36 | #include <errno.h> |
6de9cd9a DN |
37 | |
38 | ||
39 | /* Calling conventions: Data transfer statements are unlike other | |
7fcb1804 TS |
40 | library calls in that they extend over several calls. |
41 | ||
42 | The first call is always a call to st_read() or st_write(). These | |
43 | subroutines return no status unless a namelist read or write is | |
44 | being done, in which case there is the usual status. No further | |
45 | calls are necessary in this case. | |
46 | ||
47 | For other sorts of data transfer, there are zero or more data | |
48 | transfer statement that depend on the format of the data transfer | |
1ec601bf | 49 | statement. For READ (and for backwards compatibily: for WRITE), one has |
7fcb1804 TS |
50 | |
51 | transfer_integer | |
52 | transfer_logical | |
53 | transfer_character | |
cea93abb | 54 | transfer_character_wide |
7fcb1804 TS |
55 | transfer_real |
56 | transfer_complex | |
1ec601bf FXC |
57 | transfer_real128 |
58 | transfer_complex128 | |
e73d3ca6 | 59 | |
1ec601bf FXC |
60 | and for WRITE |
61 | ||
62 | transfer_integer_write | |
63 | transfer_logical_write | |
64 | transfer_character_write | |
65 | transfer_character_wide_write | |
66 | transfer_real_write | |
67 | transfer_complex_write | |
68 | transfer_real128_write | |
69 | transfer_complex128_write | |
70 | ||
71 | These subroutines do not return status. The *128 functions | |
72 | are in the file transfer128.c. | |
7fcb1804 TS |
73 | |
74 | The last call is a call to st_[read|write]_done(). While | |
75 | something can easily go wrong with the initial st_read() or | |
76 | st_write(), an error inhibits any data from actually being | |
77 | transferred. */ | |
6de9cd9a | 78 | |
5e805e44 | 79 | extern void transfer_integer (st_parameter_dt *, void *, int); |
7d7b8bfe RH |
80 | export_proto(transfer_integer); |
81 | ||
6eb6875d TK |
82 | extern void transfer_integer_write (st_parameter_dt *, void *, int); |
83 | export_proto(transfer_integer_write); | |
84 | ||
5e805e44 | 85 | extern void transfer_real (st_parameter_dt *, void *, int); |
7d7b8bfe RH |
86 | export_proto(transfer_real); |
87 | ||
6eb6875d TK |
88 | extern void transfer_real_write (st_parameter_dt *, void *, int); |
89 | export_proto(transfer_real_write); | |
90 | ||
5e805e44 | 91 | extern void transfer_logical (st_parameter_dt *, void *, int); |
7d7b8bfe RH |
92 | export_proto(transfer_logical); |
93 | ||
6eb6875d TK |
94 | extern void transfer_logical_write (st_parameter_dt *, void *, int); |
95 | export_proto(transfer_logical_write); | |
96 | ||
f622221a | 97 | extern void transfer_character (st_parameter_dt *, void *, gfc_charlen_type); |
7d7b8bfe RH |
98 | export_proto(transfer_character); |
99 | ||
f622221a | 100 | extern void transfer_character_write (st_parameter_dt *, void *, gfc_charlen_type); |
6eb6875d TK |
101 | export_proto(transfer_character_write); |
102 | ||
f622221a | 103 | extern void transfer_character_wide (st_parameter_dt *, void *, gfc_charlen_type, int); |
cea93abb JD |
104 | export_proto(transfer_character_wide); |
105 | ||
6eb6875d | 106 | extern void transfer_character_wide_write (st_parameter_dt *, |
f622221a | 107 | void *, gfc_charlen_type, int); |
6eb6875d TK |
108 | export_proto(transfer_character_wide_write); |
109 | ||
5e805e44 | 110 | extern void transfer_complex (st_parameter_dt *, void *, int); |
7d7b8bfe RH |
111 | export_proto(transfer_complex); |
112 | ||
6eb6875d TK |
113 | extern void transfer_complex_write (st_parameter_dt *, void *, int); |
114 | export_proto(transfer_complex_write); | |
115 | ||
5e805e44 JJ |
116 | extern void transfer_array (st_parameter_dt *, gfc_array_char *, int, |
117 | gfc_charlen_type); | |
18623fae JB |
118 | export_proto(transfer_array); |
119 | ||
6eb6875d TK |
120 | extern void transfer_array_write (st_parameter_dt *, gfc_array_char *, int, |
121 | gfc_charlen_type); | |
122 | export_proto(transfer_array_write); | |
123 | ||
e73d3ca6 PT |
124 | /* User defined derived type input/output. */ |
125 | extern void | |
126 | transfer_derived (st_parameter_dt *dtp, void *dtio_source, void *dtio_proc); | |
127 | export_proto(transfer_derived); | |
128 | ||
129 | extern void | |
130 | transfer_derived_write (st_parameter_dt *dtp, void *dtio_source, void *dtio_proc); | |
131 | export_proto(transfer_derived_write); | |
132 | ||
07b3bbf2 TK |
133 | static void us_read (st_parameter_dt *, int); |
134 | static void us_write (st_parameter_dt *, int); | |
135 | static void next_record_r_unf (st_parameter_dt *, int); | |
136 | static void next_record_w_unf (st_parameter_dt *, int); | |
137 | ||
09003779 | 138 | static const st_option advance_opt[] = { |
6de9cd9a DN |
139 | {"yes", ADVANCE_YES}, |
140 | {"no", ADVANCE_NO}, | |
4b6903ec | 141 | {NULL, 0} |
6de9cd9a DN |
142 | }; |
143 | ||
144 | ||
10256cbe JD |
145 | static const st_option decimal_opt[] = { |
146 | {"point", DECIMAL_POINT}, | |
147 | {"comma", DECIMAL_COMMA}, | |
148 | {NULL, 0} | |
149 | }; | |
150 | ||
379924dd JD |
151 | static const st_option round_opt[] = { |
152 | {"up", ROUND_UP}, | |
153 | {"down", ROUND_DOWN}, | |
154 | {"zero", ROUND_ZERO}, | |
155 | {"nearest", ROUND_NEAREST}, | |
156 | {"compatible", ROUND_COMPATIBLE}, | |
157 | {"processor_defined", ROUND_PROCDEFINED}, | |
158 | {NULL, 0} | |
159 | }; | |
160 | ||
10256cbe JD |
161 | |
162 | static const st_option sign_opt[] = { | |
163 | {"plus", SIGN_SP}, | |
164 | {"suppress", SIGN_SS}, | |
165 | {"processor_defined", SIGN_S}, | |
166 | {NULL, 0} | |
167 | }; | |
168 | ||
169 | static const st_option blank_opt[] = { | |
170 | {"null", BLANK_NULL}, | |
171 | {"zero", BLANK_ZERO}, | |
172 | {NULL, 0} | |
173 | }; | |
174 | ||
931149a6 JD |
175 | static const st_option delim_opt[] = { |
176 | {"apostrophe", DELIM_APOSTROPHE}, | |
177 | {"quote", DELIM_QUOTE}, | |
178 | {"none", DELIM_NONE}, | |
179 | {NULL, 0} | |
180 | }; | |
181 | ||
182 | static const st_option pad_opt[] = { | |
183 | {"yes", PAD_YES}, | |
184 | {"no", PAD_NO}, | |
185 | {NULL, 0} | |
186 | }; | |
187 | ||
2b4c9065 NK |
188 | static const st_option async_opt[] = { |
189 | {"yes", ASYNC_YES}, | |
190 | {"no", ASYNC_NO}, | |
191 | {NULL, 0} | |
192 | }; | |
193 | ||
6de9cd9a DN |
194 | typedef enum |
195 | { FORMATTED_SEQUENTIAL, UNFORMATTED_SEQUENTIAL, | |
91b30ee5 | 196 | FORMATTED_DIRECT, UNFORMATTED_DIRECT, FORMATTED_STREAM, UNFORMATTED_STREAM |
6de9cd9a DN |
197 | } |
198 | file_mode; | |
199 | ||
200 | ||
201 | static file_mode | |
5e805e44 | 202 | current_mode (st_parameter_dt *dtp) |
6de9cd9a DN |
203 | { |
204 | file_mode m; | |
205 | ||
91b30ee5 JD |
206 | m = FORM_UNSPECIFIED; |
207 | ||
5e805e44 | 208 | if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT) |
6de9cd9a | 209 | { |
5e805e44 | 210 | m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ? |
6de9cd9a DN |
211 | FORMATTED_DIRECT : UNFORMATTED_DIRECT; |
212 | } | |
91b30ee5 | 213 | else if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL) |
6de9cd9a | 214 | { |
5e805e44 | 215 | m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ? |
6de9cd9a DN |
216 | FORMATTED_SEQUENTIAL : UNFORMATTED_SEQUENTIAL; |
217 | } | |
91b30ee5 JD |
218 | else if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM) |
219 | { | |
220 | m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ? | |
221 | FORMATTED_STREAM : UNFORMATTED_STREAM; | |
222 | } | |
6de9cd9a DN |
223 | |
224 | return m; | |
225 | } | |
226 | ||
227 | ||
59011a60 | 228 | /* Mid level data transfer statements. */ |
7fcb1804 | 229 | |
59011a60 | 230 | /* Read sequential file - internal unit */ |
6de9cd9a | 231 | |
bf71e8f0 | 232 | static char * |
ea99ec5b | 233 | read_sf_internal (st_parameter_dt *dtp, size_t *length) |
6de9cd9a | 234 | { |
7812c78c | 235 | static char *empty_string[0]; |
1f10d710 | 236 | char *base = NULL; |
ea99ec5b | 237 | size_t lorig; |
59011a60 JD |
238 | |
239 | /* Zero size array gives internal unit len of 0. Nothing to read. */ | |
240 | if (dtp->internal_unit_len == 0 | |
241 | && dtp->u.p.current_unit->pad_status == PAD_NO) | |
242 | hit_eof (dtp); | |
6de9cd9a | 243 | |
1f10d710 JD |
244 | /* There are some cases with mixed DTIO where we have read a character |
245 | and saved it in the last character buffer, so we need to backup. */ | |
246 | if (unlikely (dtp->u.p.current_unit->child_dtio > 0 && | |
247 | dtp->u.p.current_unit->last_char != EOF - 1)) | |
248 | { | |
249 | dtp->u.p.current_unit->last_char = EOF - 1; | |
250 | sseek (dtp->u.p.current_unit->s, -1, SEEK_CUR); | |
251 | } | |
252 | ||
3f328462 JD |
253 | /* To support legacy code we have to scan the input string one byte |
254 | at a time because we don't know where an early comma may be and the | |
255 | requested length could go past the end of a comma shortened | |
256 | string. We only do this if -std=legacy was given at compile | |
257 | time. We also do not support this on kind=4 strings. */ | |
3f328462 | 258 | if (unlikely(compile_options.warn_std == 0)) // the slow legacy way. |
74db2a47 | 259 | { |
3f328462 JD |
260 | size_t n; |
261 | size_t tmp = 1; | |
262 | char *q; | |
263 | ||
264 | /* If we have seen an eor previously, return a length of 0. The | |
265 | caller is responsible for correctly padding the input field. */ | |
266 | if (dtp->u.p.sf_seen_eor) | |
267 | { | |
268 | *length = 0; | |
269 | /* Just return something that isn't a NULL pointer, otherwise the | |
270 | caller thinks an error occurred. */ | |
271 | return (char*) empty_string; | |
272 | } | |
273 | ||
274 | /* Get the first character of the string to establish the base | |
275 | address and check for comma or end-of-record condition. */ | |
276 | base = mem_alloc_r (dtp->u.p.current_unit->s, &tmp); | |
277 | if (tmp == 0) | |
278 | { | |
279 | dtp->u.p.sf_seen_eor = 1; | |
280 | *length = 0; | |
281 | return (char*) empty_string; | |
282 | } | |
283 | if (*base == ',') | |
284 | { | |
285 | dtp->u.p.current_unit->bytes_left--; | |
286 | *length = 0; | |
287 | return (char*) empty_string; | |
288 | } | |
289 | ||
290 | /* Now we scan the rest and deal with either an end-of-file | |
291 | condition or a comma, as needed. */ | |
292 | for (n = 1; n < *length; n++) | |
293 | { | |
294 | q = mem_alloc_r (dtp->u.p.current_unit->s, &tmp); | |
295 | if (tmp == 0) | |
296 | { | |
297 | hit_eof (dtp); | |
298 | return NULL; | |
299 | } | |
300 | if (*q == ',') | |
301 | { | |
302 | dtp->u.p.current_unit->bytes_left -= n; | |
303 | *length = n; | |
304 | break; | |
305 | } | |
306 | } | |
74db2a47 | 307 | } |
3f328462 | 308 | else // the fast way |
d10fb73e | 309 | { |
3f328462 JD |
310 | lorig = *length; |
311 | if (is_char4_unit(dtp)) | |
312 | { | |
313 | gfc_char4_t *p = (gfc_char4_t *) mem_alloc_r4 (dtp->u.p.current_unit->s, | |
314 | length); | |
315 | base = fbuf_alloc (dtp->u.p.current_unit, lorig); | |
316 | for (size_t i = 0; i < *length; i++, p++) | |
317 | base[i] = *p > 255 ? '?' : (unsigned char) *p; | |
318 | } | |
319 | else | |
320 | base = mem_alloc_r (dtp->u.p.current_unit->s, length); | |
321 | ||
322 | if (unlikely (lorig > *length)) | |
323 | { | |
324 | hit_eof (dtp); | |
325 | return NULL; | |
326 | } | |
59011a60 JD |
327 | } |
328 | ||
329 | dtp->u.p.current_unit->bytes_left -= *length; | |
330 | ||
c680ada5 JD |
331 | if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) || |
332 | dtp->u.p.current_unit->has_size) | |
333 | dtp->u.p.current_unit->size_used += (GFC_IO_INT) *length; | |
59011a60 JD |
334 | |
335 | return base; | |
336 | ||
337 | } | |
338 | ||
c7421e06 JD |
339 | /* When reading sequential formatted records we have a problem. We |
340 | don't know how long the line is until we read the trailing newline, | |
341 | and we don't want to read too much. If we read too much, we might | |
342 | have to do a physical seek backwards depending on how much data is | |
343 | present, and devices like terminals aren't seekable and would cause | |
344 | an I/O error. | |
345 | ||
346 | Given this, the solution is to read a byte at a time, stopping if | |
347 | we hit the newline. For small allocations, we use a static buffer. | |
348 | For larger allocations, we are forced to allocate memory on the | |
349 | heap. Hopefully this won't happen very often. */ | |
350 | ||
59011a60 JD |
351 | /* Read sequential file - external unit */ |
352 | ||
353 | static char * | |
ea99ec5b | 354 | read_sf (st_parameter_dt *dtp, size_t *length) |
59011a60 JD |
355 | { |
356 | static char *empty_string[0]; | |
ea99ec5b | 357 | size_t lorig, n; |
a2c037bd | 358 | int q, q2; |
ea99ec5b | 359 | int seen_comma; |
59011a60 JD |
360 | |
361 | /* If we have seen an eor previously, return a length of 0. The | |
362 | caller is responsible for correctly padding the input field. */ | |
363 | if (dtp->u.p.sf_seen_eor) | |
364 | { | |
365 | *length = 0; | |
366 | /* Just return something that isn't a NULL pointer, otherwise the | |
9b110be2 | 367 | caller thinks an error occurred. */ |
59011a60 | 368 | return (char*) empty_string; |
d10fb73e JD |
369 | } |
370 | ||
1f10d710 JD |
371 | /* There are some cases with mixed DTIO where we have read a character |
372 | and saved it in the last character buffer, so we need to backup. */ | |
373 | if (unlikely (dtp->u.p.current_unit->child_dtio > 0 && | |
374 | dtp->u.p.current_unit->last_char != EOF - 1)) | |
375 | { | |
376 | dtp->u.p.current_unit->last_char = EOF - 1; | |
377 | fbuf_seek (dtp->u.p.current_unit, -1, SEEK_CUR); | |
378 | } | |
379 | ||
7812c78c | 380 | n = seen_comma = 0; |
6de9cd9a | 381 | |
7812c78c JD |
382 | /* Read data into format buffer and scan through it. */ |
383 | lorig = *length; | |
bd72d66c | 384 | |
7812c78c JD |
385 | while (n < *length) |
386 | { | |
a2c037bd JB |
387 | q = fbuf_getc (dtp->u.p.current_unit); |
388 | if (q == EOF) | |
389 | break; | |
0ef33d44 FR |
390 | else if (dtp->u.p.current_unit->flags.cc != CC_NONE |
391 | && (q == '\n' || q == '\r')) | |
bd72d66c | 392 | { |
ee3eb6a4 | 393 | /* Unexpected end of line. Set the position. */ |
ee3eb6a4 | 394 | dtp->u.p.sf_seen_eor = 1; |
59afe4b4 TK |
395 | |
396 | /* If we see an EOR during non-advancing I/O, we need to skip | |
397 | the rest of the I/O statement. Set the corresponding flag. */ | |
5e805e44 JJ |
398 | if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar) |
399 | dtp->u.p.eor_condition = 1; | |
e73d3ca6 | 400 | |
8824fd4c | 401 | /* If we encounter a CR, it might be a CRLF. */ |
15877a88 | 402 | if (q == '\r') /* Probably a CRLF */ |
8824fd4c | 403 | { |
a2c037bd JB |
404 | /* See if there is an LF. */ |
405 | q2 = fbuf_getc (dtp->u.p.current_unit); | |
406 | if (q2 == '\n') | |
407 | dtp->u.p.sf_seen_eor = 2; | |
408 | else if (q2 != EOF) /* Oops, seek back. */ | |
409 | fbuf_seek (dtp->u.p.current_unit, -1, SEEK_CUR); | |
8824fd4c FXC |
410 | } |
411 | ||
59afe4b4 TK |
412 | /* Without padding, terminate the I/O statement without assigning |
413 | the value. With padding, the value still needs to be assigned, | |
414 | so we can just continue with a short read. */ | |
105b7136 | 415 | if (dtp->u.p.current_unit->pad_status == PAD_NO) |
6de9cd9a | 416 | { |
d74b97cc | 417 | generate_error (&dtp->common, LIBERROR_EOR, NULL); |
6de9cd9a DN |
418 | return NULL; |
419 | } | |
420 | ||
6de9cd9a | 421 | *length = n; |
ee3eb6a4 | 422 | goto done; |
6de9cd9a | 423 | } |
b14c7e14 JD |
424 | /* Short circuit the read if a comma is found during numeric input. |
425 | The flag is set to zero during character reads so that commas in | |
426 | strings are not ignored */ | |
a2c037bd | 427 | else if (q == ',') |
b14c7e14 JD |
428 | if (dtp->u.p.sf_read_comma == 1) |
429 | { | |
7812c78c | 430 | seen_comma = 1; |
2e444427 JD |
431 | notify_std (&dtp->common, GFC_STD_GNU, |
432 | "Comma in formatted numeric read."); | |
b14c7e14 JD |
433 | break; |
434 | } | |
6de9cd9a | 435 | n++; |
a2c037bd | 436 | } |
7812c78c | 437 | |
a2c037bd | 438 | *length = n; |
7812c78c JD |
439 | |
440 | /* A short read implies we hit EOF, unless we hit EOR, a comma, or | |
441 | some other stuff. Set the relevant flags. */ | |
442 | if (lorig > *length && !dtp->u.p.sf_seen_eor && !seen_comma) | |
443 | { | |
04b98fd2 | 444 | if (n > 0) |
26bda000 JD |
445 | { |
446 | if (dtp->u.p.advance_status == ADVANCE_NO) | |
447 | { | |
448 | if (dtp->u.p.current_unit->pad_status == PAD_NO) | |
449 | { | |
450 | hit_eof (dtp); | |
451 | return NULL; | |
452 | } | |
453 | else | |
454 | dtp->u.p.eor_condition = 1; | |
455 | } | |
456 | else | |
457 | dtp->u.p.at_eof = 1; | |
458 | } | |
59011a60 JD |
459 | else if (dtp->u.p.advance_status == ADVANCE_NO |
460 | || dtp->u.p.current_unit->pad_status == PAD_NO | |
461 | || dtp->u.p.current_unit->bytes_left | |
462 | == dtp->u.p.current_unit->recl) | |
463 | { | |
464 | hit_eof (dtp); | |
465 | return NULL; | |
466 | } | |
6de9cd9a | 467 | } |
d10fb73e JD |
468 | |
469 | done: | |
7812c78c JD |
470 | |
471 | dtp->u.p.current_unit->bytes_left -= n; | |
6de9cd9a | 472 | |
c680ada5 JD |
473 | if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) || |
474 | dtp->u.p.current_unit->has_size) | |
475 | dtp->u.p.current_unit->size_used += (GFC_IO_INT) n; | |
59afe4b4 | 476 | |
ae01ced5 JJ |
477 | /* We can't call fbuf_getptr before the loop doing fbuf_getc, because |
478 | fbuf_getc might reallocate the buffer. So return current pointer | |
479 | minus all the advances, which is n plus up to two characters | |
480 | of newline or comma. */ | |
481 | return fbuf_getptr (dtp->u.p.current_unit) | |
482 | - n - dtp->u.p.sf_seen_eor - seen_comma; | |
6de9cd9a DN |
483 | } |
484 | ||
485 | ||
7fcb1804 | 486 | /* Function for reading the next couple of bytes from the current |
f5e3ed2d | 487 | file, advancing the current position. We return NULL on end of record or |
15877a88 JB |
488 | end of file. This function is only for formatted I/O, unformatted uses |
489 | read_block_direct. | |
420aa7b8 | 490 | |
7fcb1804 TS |
491 | If the read is short, then it is because the current record does not |
492 | have enough data to satisfy the read request and the file was | |
493 | opened with PAD=YES. The caller must assume tailing spaces for | |
494 | short reads. */ | |
6de9cd9a | 495 | |
7812c78c | 496 | void * |
ea99ec5b | 497 | read_block_form (st_parameter_dt *dtp, size_t *nbytes) |
6de9cd9a DN |
498 | { |
499 | char *source; | |
ea99ec5b | 500 | size_t norig; |
6de9cd9a | 501 | |
15877a88 | 502 | if (!is_stream_io (dtp)) |
6de9cd9a | 503 | { |
15877a88 | 504 | if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes) |
6de9cd9a | 505 | { |
91b30ee5 JD |
506 | /* For preconnected units with default record length, set bytes left |
507 | to unit record length and proceed, otherwise error. */ | |
508 | if (dtp->u.p.current_unit->unit_number == options.stdin_unit | |
67c24a8b | 509 | && dtp->u.p.current_unit->recl == default_recl) |
d7445152 | 510 | dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; |
91b30ee5 | 511 | else |
54ffdb12 | 512 | { |
59011a60 JD |
513 | if (unlikely (dtp->u.p.current_unit->pad_status == PAD_NO) |
514 | && !is_internal_unit (dtp)) | |
91b30ee5 JD |
515 | { |
516 | /* Not enough data left. */ | |
d74b97cc | 517 | generate_error (&dtp->common, LIBERROR_EOR, NULL); |
7812c78c | 518 | return NULL; |
91b30ee5 JD |
519 | } |
520 | } | |
521 | ||
a5768d38 | 522 | if (is_internal_unit(dtp)) |
91b30ee5 | 523 | { |
a5768d38 JD |
524 | if (*nbytes > 0 && dtp->u.p.current_unit->bytes_left == 0) |
525 | { | |
526 | if (dtp->u.p.advance_status == ADVANCE_NO) | |
527 | { | |
528 | generate_error (&dtp->common, LIBERROR_EOR, NULL); | |
529 | return NULL; | |
530 | } | |
531 | } | |
532 | } | |
533 | else | |
534 | { | |
535 | if (unlikely (dtp->u.p.current_unit->bytes_left == 0)) | |
536 | { | |
537 | hit_eof (dtp); | |
538 | return NULL; | |
539 | } | |
54ffdb12 | 540 | } |
91b30ee5 | 541 | |
15877a88 | 542 | *nbytes = dtp->u.p.current_unit->bytes_left; |
6de9cd9a | 543 | } |
97cd182d | 544 | } |
6de9cd9a | 545 | |
97cd182d JD |
546 | if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED && |
547 | (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL || | |
548 | dtp->u.p.current_unit->flags.access == ACCESS_STREAM)) | |
549 | { | |
59011a60 JD |
550 | if (is_internal_unit (dtp)) |
551 | source = read_sf_internal (dtp, nbytes); | |
552 | else | |
553 | source = read_sf (dtp, nbytes); | |
554 | ||
97cd182d | 555 | dtp->u.p.current_unit->strm_pos += |
15877a88 | 556 | (gfc_offset) (*nbytes + dtp->u.p.sf_seen_eor); |
7812c78c | 557 | return source; |
97cd182d | 558 | } |
7812c78c JD |
559 | |
560 | /* If we reach here, we can assume it's direct access. */ | |
561 | ||
15877a88 | 562 | dtp->u.p.current_unit->bytes_left -= (gfc_offset) *nbytes; |
91b30ee5 | 563 | |
7812c78c JD |
564 | norig = *nbytes; |
565 | source = fbuf_read (dtp->u.p.current_unit, nbytes); | |
566 | fbuf_seek (dtp->u.p.current_unit, *nbytes, SEEK_CUR); | |
91b30ee5 | 567 | |
c680ada5 JD |
568 | if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) || |
569 | dtp->u.p.current_unit->has_size) | |
570 | dtp->u.p.current_unit->size_used += (GFC_IO_INT) *nbytes; | |
cacf2b96 | 571 | |
7812c78c | 572 | if (norig != *nbytes) |
74db2a47 | 573 | { |
7812c78c | 574 | /* Short read, this shouldn't happen. */ |
00c7a3c7 | 575 | if (dtp->u.p.current_unit->pad_status == PAD_NO) |
09861cbe | 576 | { |
d74b97cc | 577 | generate_error (&dtp->common, LIBERROR_EOR, NULL); |
97cd182d | 578 | source = NULL; |
09861cbe | 579 | } |
97cd182d | 580 | } |
6de9cd9a | 581 | |
7812c78c | 582 | dtp->u.p.current_unit->strm_pos += (gfc_offset) *nbytes; |
6de9cd9a | 583 | |
7812c78c | 584 | return source; |
6de9cd9a DN |
585 | } |
586 | ||
587 | ||
74db2a47 JD |
588 | /* Read a block from a character(kind=4) internal unit, to be transferred into |
589 | a character(kind=4) variable. Note: Portions of this code borrowed from | |
590 | read_sf_internal. */ | |
591 | void * | |
ea99ec5b | 592 | read_block_form4 (st_parameter_dt *dtp, size_t *nbytes) |
74db2a47 JD |
593 | { |
594 | static gfc_char4_t *empty_string[0]; | |
595 | gfc_char4_t *source; | |
ea99ec5b | 596 | size_t lorig; |
74db2a47 JD |
597 | |
598 | if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes) | |
599 | *nbytes = dtp->u.p.current_unit->bytes_left; | |
600 | ||
601 | /* Zero size array gives internal unit len of 0. Nothing to read. */ | |
602 | if (dtp->internal_unit_len == 0 | |
603 | && dtp->u.p.current_unit->pad_status == PAD_NO) | |
604 | hit_eof (dtp); | |
605 | ||
606 | /* If we have seen an eor previously, return a length of 0. The | |
607 | caller is responsible for correctly padding the input field. */ | |
608 | if (dtp->u.p.sf_seen_eor) | |
609 | { | |
610 | *nbytes = 0; | |
611 | /* Just return something that isn't a NULL pointer, otherwise the | |
9b110be2 | 612 | caller thinks an error occurred. */ |
74db2a47 JD |
613 | return empty_string; |
614 | } | |
615 | ||
616 | lorig = *nbytes; | |
617 | source = (gfc_char4_t *) mem_alloc_r4 (dtp->u.p.current_unit->s, nbytes); | |
618 | ||
619 | if (unlikely (lorig > *nbytes)) | |
620 | { | |
621 | hit_eof (dtp); | |
622 | return NULL; | |
623 | } | |
624 | ||
625 | dtp->u.p.current_unit->bytes_left -= *nbytes; | |
626 | ||
c680ada5 JD |
627 | if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) || |
628 | dtp->u.p.current_unit->has_size) | |
629 | dtp->u.p.current_unit->size_used += (GFC_IO_INT) *nbytes; | |
74db2a47 JD |
630 | |
631 | return source; | |
632 | } | |
633 | ||
634 | ||
07b3bbf2 TK |
635 | /* Reads a block directly into application data space. This is for |
636 | unformatted files. */ | |
0dc43461 JB |
637 | |
638 | static void | |
f9bfed22 | 639 | read_block_direct (st_parameter_dt *dtp, void *buf, size_t nbytes) |
0dc43461 | 640 | { |
7812c78c JD |
641 | ssize_t to_read_record; |
642 | ssize_t have_read_record; | |
643 | ssize_t to_read_subrecord; | |
644 | ssize_t have_read_subrecord; | |
8a7f7fb6 | 645 | int short_record; |
0dc43461 | 646 | |
8a7f7fb6 | 647 | if (is_stream_io (dtp)) |
0dc43461 | 648 | { |
e73d3ca6 | 649 | have_read_record = sread (dtp->u.p.current_unit->s, buf, |
f9bfed22 | 650 | nbytes); |
7812c78c | 651 | if (unlikely (have_read_record < 0)) |
cacf2b96 | 652 | { |
d74b97cc | 653 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
cacf2b96 JD |
654 | return; |
655 | } | |
656 | ||
e73d3ca6 | 657 | dtp->u.p.current_unit->strm_pos += (gfc_offset) have_read_record; |
8a7f7fb6 | 658 | |
f9bfed22 | 659 | if (unlikely ((ssize_t) nbytes != have_read_record)) |
07b3bbf2 | 660 | { |
b4c811bd TK |
661 | /* Short read, e.g. if we hit EOF. For stream files, |
662 | we have to set the end-of-file condition. */ | |
7812c78c | 663 | hit_eof (dtp); |
07b3bbf2 | 664 | } |
8a7f7fb6 | 665 | return; |
0dc43461 | 666 | } |
8a7f7fb6 | 667 | |
07b3bbf2 | 668 | if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT) |
835681c8 | 669 | { |
f9bfed22 | 670 | if (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes) |
07b3bbf2 TK |
671 | { |
672 | short_record = 1; | |
f9bfed22 JB |
673 | to_read_record = dtp->u.p.current_unit->bytes_left; |
674 | nbytes = to_read_record; | |
07b3bbf2 | 675 | } |
07b3bbf2 TK |
676 | else |
677 | { | |
678 | short_record = 0; | |
f9bfed22 | 679 | to_read_record = nbytes; |
07b3bbf2 TK |
680 | } |
681 | ||
682 | dtp->u.p.current_unit->bytes_left -= to_read_record; | |
683 | ||
7812c78c JD |
684 | to_read_record = sread (dtp->u.p.current_unit->s, buf, to_read_record); |
685 | if (unlikely (to_read_record < 0)) | |
07b3bbf2 | 686 | { |
d74b97cc | 687 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
07b3bbf2 TK |
688 | return; |
689 | } | |
690 | ||
e73d3ca6 | 691 | if (to_read_record != (ssize_t) nbytes) |
91b30ee5 | 692 | { |
b4c811bd TK |
693 | /* Short read, e.g. if we hit EOF. Apparently, we read |
694 | more than was written to the last record. */ | |
91b30ee5 JD |
695 | return; |
696 | } | |
07b3bbf2 | 697 | |
afab92d8 | 698 | if (unlikely (short_record)) |
07b3bbf2 | 699 | { |
d74b97cc | 700 | generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL); |
07b3bbf2 TK |
701 | } |
702 | return; | |
835681c8 JD |
703 | } |
704 | ||
07b3bbf2 TK |
705 | /* Unformatted sequential. We loop over the subrecords, reading |
706 | until the request has been fulfilled or the record has run out | |
707 | of continuation subrecords. */ | |
708 | ||
709 | /* Check whether we exceed the total record length. */ | |
710 | ||
f4072316 | 711 | if (dtp->u.p.current_unit->flags.has_recl |
743460ea | 712 | && ((gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left)) |
07b3bbf2 | 713 | { |
f9bfed22 | 714 | to_read_record = dtp->u.p.current_unit->bytes_left; |
07b3bbf2 TK |
715 | short_record = 1; |
716 | } | |
8a7f7fb6 TK |
717 | else |
718 | { | |
f9bfed22 | 719 | to_read_record = nbytes; |
8a7f7fb6 | 720 | short_record = 0; |
8a7f7fb6 | 721 | } |
07b3bbf2 | 722 | have_read_record = 0; |
8a7f7fb6 | 723 | |
07b3bbf2 | 724 | while(1) |
0dc43461 | 725 | { |
07b3bbf2 TK |
726 | if (dtp->u.p.current_unit->bytes_left_subrecord |
727 | < (gfc_offset) to_read_record) | |
728 | { | |
f9bfed22 | 729 | to_read_subrecord = dtp->u.p.current_unit->bytes_left_subrecord; |
07b3bbf2 | 730 | to_read_record -= to_read_subrecord; |
07b3bbf2 | 731 | } |
07b3bbf2 TK |
732 | else |
733 | { | |
734 | to_read_subrecord = to_read_record; | |
735 | to_read_record = 0; | |
736 | } | |
737 | ||
738 | dtp->u.p.current_unit->bytes_left_subrecord -= to_read_subrecord; | |
739 | ||
e73d3ca6 | 740 | have_read_subrecord = sread (dtp->u.p.current_unit->s, |
7812c78c | 741 | buf + have_read_record, to_read_subrecord); |
43b594b4 | 742 | if (unlikely (have_read_subrecord < 0)) |
07b3bbf2 | 743 | { |
d74b97cc | 744 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
07b3bbf2 TK |
745 | return; |
746 | } | |
747 | ||
748 | have_read_record += have_read_subrecord; | |
749 | ||
afab92d8 | 750 | if (unlikely (to_read_subrecord != have_read_subrecord)) |
07b3bbf2 | 751 | { |
b4c811bd TK |
752 | /* Short read, e.g. if we hit EOF. This means the record |
753 | structure has been corrupted, or the trailing record | |
754 | marker would still be present. */ | |
755 | ||
d74b97cc | 756 | generate_error (&dtp->common, LIBERROR_CORRUPT_FILE, NULL); |
07b3bbf2 TK |
757 | return; |
758 | } | |
759 | ||
760 | if (to_read_record > 0) | |
761 | { | |
afab92d8 | 762 | if (likely (dtp->u.p.current_unit->continued)) |
07b3bbf2 TK |
763 | { |
764 | next_record_r_unf (dtp, 0); | |
765 | us_read (dtp, 1); | |
766 | } | |
767 | else | |
768 | { | |
e08e57d0 TK |
769 | /* Let's make sure the file position is correctly pre-positioned |
770 | for the next read statement. */ | |
b4c811bd | 771 | |
e08e57d0 | 772 | dtp->u.p.current_unit->current_record = 0; |
b4c811bd | 773 | next_record_r_unf (dtp, 0); |
d74b97cc | 774 | generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL); |
07b3bbf2 TK |
775 | return; |
776 | } | |
777 | } | |
778 | else | |
779 | { | |
780 | /* Normal exit, the read request has been fulfilled. */ | |
781 | break; | |
782 | } | |
91b30ee5 | 783 | } |
0dc43461 | 784 | |
07b3bbf2 | 785 | dtp->u.p.current_unit->bytes_left -= have_read_record; |
afab92d8 | 786 | if (unlikely (short_record)) |
91b30ee5 | 787 | { |
d74b97cc | 788 | generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL); |
8a7f7fb6 | 789 | return; |
0dc43461 | 790 | } |
07b3bbf2 | 791 | return; |
0dc43461 JB |
792 | } |
793 | ||
794 | ||
7fcb1804 TS |
795 | /* Function for writing a block of bytes to the current file at the |
796 | current position, advancing the file pointer. We are given a length | |
797 | and return a pointer to a buffer that the caller must (completely) | |
798 | fill in. Returns NULL on error. */ | |
6de9cd9a DN |
799 | |
800 | void * | |
ea99ec5b | 801 | write_block (st_parameter_dt *dtp, size_t length) |
6de9cd9a DN |
802 | { |
803 | char *dest; | |
54ffdb12 | 804 | |
15877a88 | 805 | if (!is_stream_io (dtp)) |
6de9cd9a | 806 | { |
91b30ee5 | 807 | if (dtp->u.p.current_unit->bytes_left < (gfc_offset) length) |
54ffdb12 | 808 | { |
91b30ee5 JD |
809 | /* For preconnected units with default record length, set bytes left |
810 | to unit record length and proceed, otherwise error. */ | |
afab92d8 TK |
811 | if (likely ((dtp->u.p.current_unit->unit_number |
812 | == options.stdout_unit | |
813 | || dtp->u.p.current_unit->unit_number | |
814 | == options.stderr_unit) | |
67c24a8b | 815 | && dtp->u.p.current_unit->recl == default_recl)) |
91b30ee5 JD |
816 | dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; |
817 | else | |
818 | { | |
d74b97cc | 819 | generate_error (&dtp->common, LIBERROR_EOR, NULL); |
91b30ee5 JD |
820 | return NULL; |
821 | } | |
54ffdb12 | 822 | } |
6de9cd9a | 823 | |
91b30ee5 | 824 | dtp->u.p.current_unit->bytes_left -= (gfc_offset) length; |
97cd182d | 825 | } |
91b30ee5 | 826 | |
15877a88 | 827 | if (is_internal_unit (dtp)) |
91b30ee5 | 828 | { |
4a8d4422 | 829 | if (is_char4_unit(dtp)) /* char4 internel unit. */ |
746e6327 JD |
830 | { |
831 | gfc_char4_t *dest4; | |
832 | dest4 = mem_alloc_w4 (dtp->u.p.current_unit->s, &length); | |
833 | if (dest4 == NULL) | |
834 | { | |
835 | generate_error (&dtp->common, LIBERROR_END, NULL); | |
836 | return NULL; | |
837 | } | |
838 | return dest4; | |
839 | } | |
c7421e06 JD |
840 | else |
841 | dest = mem_alloc_w (dtp->u.p.current_unit->s, &length); | |
6de9cd9a | 842 | |
c7421e06 JD |
843 | if (dest == NULL) |
844 | { | |
845 | generate_error (&dtp->common, LIBERROR_END, NULL); | |
846 | return NULL; | |
847 | } | |
397bc09a | 848 | |
c7421e06 JD |
849 | if (unlikely (dtp->u.p.current_unit->endfile == AT_ENDFILE)) |
850 | generate_error (&dtp->common, LIBERROR_END, NULL); | |
15877a88 JB |
851 | } |
852 | else | |
853 | { | |
854 | dest = fbuf_alloc (dtp->u.p.current_unit, length); | |
855 | if (dest == NULL) | |
74db2a47 JD |
856 | { |
857 | generate_error (&dtp->common, LIBERROR_OS, NULL); | |
858 | return NULL; | |
859 | } | |
15877a88 | 860 | } |
e73d3ca6 | 861 | |
c680ada5 JD |
862 | if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) || |
863 | dtp->u.p.current_unit->has_size) | |
864 | dtp->u.p.current_unit->size_used += (GFC_IO_INT) length; | |
91b30ee5 | 865 | |
97cd182d | 866 | dtp->u.p.current_unit->strm_pos += (gfc_offset) length; |
6de9cd9a DN |
867 | |
868 | return dest; | |
869 | } | |
870 | ||
871 | ||
07b3bbf2 TK |
872 | /* High level interface to swrite(), taking care of errors. This is only |
873 | called for unformatted files. There are three cases to consider: | |
874 | Stream I/O, unformatted direct, unformatted sequential. */ | |
0dc43461 | 875 | |
f5e3ed2d | 876 | static bool |
82b8244c | 877 | write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes) |
0dc43461 | 878 | { |
07b3bbf2 | 879 | |
7812c78c JD |
880 | ssize_t have_written; |
881 | ssize_t to_write_subrecord; | |
07b3bbf2 TK |
882 | int short_record; |
883 | ||
07b3bbf2 TK |
884 | /* Stream I/O. */ |
885 | ||
97cd182d JD |
886 | if (is_stream_io (dtp)) |
887 | { | |
7812c78c JD |
888 | have_written = swrite (dtp->u.p.current_unit->s, buf, nbytes); |
889 | if (unlikely (have_written < 0)) | |
07b3bbf2 | 890 | { |
d74b97cc | 891 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
f5e3ed2d | 892 | return false; |
07b3bbf2 TK |
893 | } |
894 | ||
e73d3ca6 | 895 | dtp->u.p.current_unit->strm_pos += (gfc_offset) have_written; |
07b3bbf2 | 896 | |
f5e3ed2d | 897 | return true; |
97cd182d | 898 | } |
07b3bbf2 TK |
899 | |
900 | /* Unformatted direct access. */ | |
901 | ||
902 | if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT) | |
82b8244c | 903 | { |
afab92d8 | 904 | if (unlikely (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes)) |
54ffdb12 | 905 | { |
d74b97cc | 906 | generate_error (&dtp->common, LIBERROR_DIRECT_EOR, NULL); |
f5e3ed2d | 907 | return false; |
07b3bbf2 TK |
908 | } |
909 | ||
4152bc26 | 910 | if (buf == NULL && nbytes == 0) |
f5e3ed2d | 911 | return true; |
4152bc26 | 912 | |
e73d3ca6 | 913 | have_written = swrite (dtp->u.p.current_unit->s, buf, nbytes); |
7812c78c | 914 | if (unlikely (have_written < 0)) |
07b3bbf2 | 915 | { |
d74b97cc | 916 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
f5e3ed2d | 917 | return false; |
91b30ee5 JD |
918 | } |
919 | ||
7812c78c JD |
920 | dtp->u.p.current_unit->strm_pos += (gfc_offset) have_written; |
921 | dtp->u.p.current_unit->bytes_left -= (gfc_offset) have_written; | |
07b3bbf2 | 922 | |
f5e3ed2d | 923 | return true; |
91b30ee5 | 924 | } |
0dc43461 | 925 | |
07b3bbf2 TK |
926 | /* Unformatted sequential. */ |
927 | ||
928 | have_written = 0; | |
929 | ||
930 | if (dtp->u.p.current_unit->flags.has_recl | |
931 | && (gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left) | |
82b8244c | 932 | { |
07b3bbf2 TK |
933 | nbytes = dtp->u.p.current_unit->bytes_left; |
934 | short_record = 1; | |
935 | } | |
936 | else | |
937 | { | |
938 | short_record = 0; | |
82b8244c | 939 | } |
0dc43461 | 940 | |
07b3bbf2 TK |
941 | while (1) |
942 | { | |
943 | ||
944 | to_write_subrecord = | |
945 | (size_t) dtp->u.p.current_unit->bytes_left_subrecord < nbytes ? | |
946 | (size_t) dtp->u.p.current_unit->bytes_left_subrecord : nbytes; | |
947 | ||
948 | dtp->u.p.current_unit->bytes_left_subrecord -= | |
949 | (gfc_offset) to_write_subrecord; | |
950 | ||
e73d3ca6 | 951 | to_write_subrecord = swrite (dtp->u.p.current_unit->s, |
7812c78c JD |
952 | buf + have_written, to_write_subrecord); |
953 | if (unlikely (to_write_subrecord < 0)) | |
07b3bbf2 | 954 | { |
d74b97cc | 955 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
f5e3ed2d | 956 | return false; |
07b3bbf2 TK |
957 | } |
958 | ||
e73d3ca6 | 959 | dtp->u.p.current_unit->strm_pos += (gfc_offset) to_write_subrecord; |
07b3bbf2 TK |
960 | nbytes -= to_write_subrecord; |
961 | have_written += to_write_subrecord; | |
97cd182d | 962 | |
07b3bbf2 TK |
963 | if (nbytes == 0) |
964 | break; | |
82b8244c | 965 | |
07b3bbf2 TK |
966 | next_record_w_unf (dtp, 1); |
967 | us_write (dtp, 1); | |
968 | } | |
969 | dtp->u.p.current_unit->bytes_left -= have_written; | |
afab92d8 | 970 | if (unlikely (short_record)) |
07b3bbf2 | 971 | { |
d74b97cc | 972 | generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL); |
f5e3ed2d | 973 | return false; |
07b3bbf2 | 974 | } |
f5e3ed2d | 975 | return true; |
0dc43461 JB |
976 | } |
977 | ||
978 | ||
facb23dc | 979 | /* Reverse memcpy - used for byte swapping. */ |
6de9cd9a DN |
980 | |
981 | static void | |
facb23dc | 982 | reverse_memcpy (void *dest, const void *src, size_t n) |
6de9cd9a | 983 | { |
facb23dc JB |
984 | char *d, *s; |
985 | size_t i; | |
986 | ||
987 | d = (char *) dest; | |
988 | s = (char *) src + n - 1; | |
989 | ||
990 | /* Write with ascending order - this is likely faster | |
991 | on modern architectures because of write combining. */ | |
992 | for (i=0; i<n; i++) | |
993 | *(d++) = *(s--); | |
994 | } | |
995 | ||
996 | ||
997 | /* Utility function for byteswapping an array, using the bswap | |
998 | builtins if possible. dest and src can overlap completely, or then | |
999 | they must point to separate objects; partial overlaps are not | |
1000 | allowed. */ | |
1001 | ||
1002 | static void | |
1003 | bswap_array (void *dest, const void *src, size_t size, size_t nelems) | |
1004 | { | |
e73d3ca6 | 1005 | const char *ps; |
facb23dc JB |
1006 | char *pd; |
1007 | ||
1008 | switch (size) | |
181c9f4a | 1009 | { |
facb23dc JB |
1010 | case 1: |
1011 | break; | |
1012 | case 2: | |
1013 | for (size_t i = 0; i < nelems; i++) | |
1014 | ((uint16_t*)dest)[i] = __builtin_bswap16 (((uint16_t*)src)[i]); | |
1015 | break; | |
1016 | case 4: | |
1017 | for (size_t i = 0; i < nelems; i++) | |
1018 | ((uint32_t*)dest)[i] = __builtin_bswap32 (((uint32_t*)src)[i]); | |
1019 | break; | |
1020 | case 8: | |
1021 | for (size_t i = 0; i < nelems; i++) | |
1022 | ((uint64_t*)dest)[i] = __builtin_bswap64 (((uint64_t*)src)[i]); | |
1023 | break; | |
1024 | case 12: | |
1025 | ps = src; | |
1026 | pd = dest; | |
1027 | for (size_t i = 0; i < nelems; i++) | |
1028 | { | |
1029 | uint32_t tmp; | |
1030 | memcpy (&tmp, ps, 4); | |
1031 | *(uint32_t*)pd = __builtin_bswap32 (*(uint32_t*)(ps + 8)); | |
1032 | *(uint32_t*)(pd + 4) = __builtin_bswap32 (*(uint32_t*)(ps + 4)); | |
1033 | *(uint32_t*)(pd + 8) = __builtin_bswap32 (tmp); | |
1034 | ps += size; | |
1035 | pd += size; | |
1036 | } | |
1037 | break; | |
1038 | case 16: | |
1039 | ps = src; | |
1040 | pd = dest; | |
1041 | for (size_t i = 0; i < nelems; i++) | |
1042 | { | |
1043 | uint64_t tmp; | |
1044 | memcpy (&tmp, ps, 8); | |
1045 | *(uint64_t*)pd = __builtin_bswap64 (*(uint64_t*)(ps + 8)); | |
1046 | *(uint64_t*)(pd + 8) = __builtin_bswap64 (tmp); | |
1047 | ps += size; | |
1048 | pd += size; | |
1049 | } | |
1050 | break; | |
1051 | default: | |
1052 | pd = dest; | |
1053 | if (dest != src) | |
1054 | { | |
1055 | ps = src; | |
1056 | for (size_t i = 0; i < nelems; i++) | |
1057 | { | |
1058 | reverse_memcpy (pd, ps, size); | |
1059 | ps += size; | |
1060 | pd += size; | |
1061 | } | |
1062 | } | |
1063 | else | |
1064 | { | |
1065 | /* In-place byte swap. */ | |
1066 | for (size_t i = 0; i < nelems; i++) | |
1067 | { | |
1068 | char tmp, *low = pd, *high = pd + size - 1; | |
1069 | for (size_t j = 0; j < size/2; j++) | |
1070 | { | |
1071 | tmp = *low; | |
1072 | *low = *high; | |
1073 | *high = tmp; | |
1074 | low++; | |
1075 | high--; | |
1076 | } | |
1077 | pd += size; | |
1078 | } | |
1079 | } | |
181c9f4a | 1080 | } |
facb23dc JB |
1081 | } |
1082 | ||
cea93abb | 1083 | |
facb23dc JB |
1084 | /* Master function for unformatted reads. */ |
1085 | ||
1086 | static void | |
1087 | unformatted_read (st_parameter_dt *dtp, bt type, | |
1088 | void *dest, int kind, size_t size, size_t nelems) | |
1089 | { | |
e73d3ca6 PT |
1090 | if (type == BT_CLASS) |
1091 | { | |
1092 | int unit = dtp->u.p.current_unit->unit_number; | |
1093 | char tmp_iomsg[IOMSG_LEN] = ""; | |
1094 | char *child_iomsg; | |
1095 | gfc_charlen_type child_iomsg_len; | |
1096 | int noiostat; | |
1097 | int *child_iostat = NULL; | |
1098 | ||
1099 | /* Set iostat, intent(out). */ | |
1100 | noiostat = 0; | |
1101 | child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ? | |
1102 | dtp->common.iostat : &noiostat; | |
1103 | ||
1104 | /* Set iomsg, intent(inout). */ | |
1105 | if (dtp->common.flags & IOPARM_HAS_IOMSG) | |
1106 | { | |
1107 | child_iomsg = dtp->common.iomsg; | |
1108 | child_iomsg_len = dtp->common.iomsg_len; | |
1109 | } | |
1110 | else | |
1111 | { | |
1112 | child_iomsg = tmp_iomsg; | |
1113 | child_iomsg_len = IOMSG_LEN; | |
1114 | } | |
1115 | ||
1116 | /* Call the user defined unformatted READ procedure. */ | |
1117 | dtp->u.p.current_unit->child_dtio++; | |
1118 | dtp->u.p.ufdtio_ptr (dest, &unit, child_iostat, child_iomsg, | |
1119 | child_iomsg_len); | |
1120 | dtp->u.p.current_unit->child_dtio--; | |
1121 | return; | |
1122 | } | |
1123 | ||
facb23dc JB |
1124 | if (type == BT_CHARACTER) |
1125 | size *= GFC_SIZE_OF_CHAR_KIND(kind); | |
1126 | read_block_direct (dtp, dest, size * nelems); | |
cea93abb | 1127 | |
facb23dc JB |
1128 | if (unlikely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_SWAP) |
1129 | && kind != 1) | |
1130 | { | |
cea93abb | 1131 | /* Handle wide chracters. */ |
facb23dc JB |
1132 | if (type == BT_CHARACTER) |
1133 | { | |
1134 | nelems *= size; | |
1135 | size = kind; | |
1136 | } | |
cea93abb | 1137 | |
181c9f4a | 1138 | /* Break up complex into its constituent reals. */ |
facb23dc JB |
1139 | else if (type == BT_COMPLEX) |
1140 | { | |
1141 | nelems *= 2; | |
1142 | size /= 2; | |
1143 | } | |
1144 | bswap_array (dest, dest, size, nelems); | |
181c9f4a | 1145 | } |
6de9cd9a DN |
1146 | } |
1147 | ||
0dc43461 | 1148 | |
853c0ad7 JD |
1149 | /* Master function for unformatted writes. NOTE: For kind=10 the size is 16 |
1150 | bytes on 64 bit machines. The unused bytes are not initialized and never | |
1151 | used, which can show an error with memory checking analyzers like | |
e73d3ca6 | 1152 | valgrind. We us BT_CLASS to denote a User Defined I/O call. */ |
7fcb1804 | 1153 | |
6de9cd9a | 1154 | static void |
181c9f4a | 1155 | unformatted_write (st_parameter_dt *dtp, bt type, |
cea93abb | 1156 | void *source, int kind, size_t size, size_t nelems) |
6de9cd9a | 1157 | { |
e73d3ca6 PT |
1158 | if (type == BT_CLASS) |
1159 | { | |
1160 | int unit = dtp->u.p.current_unit->unit_number; | |
1161 | char tmp_iomsg[IOMSG_LEN] = ""; | |
1162 | char *child_iomsg; | |
1163 | gfc_charlen_type child_iomsg_len; | |
1164 | int noiostat; | |
1165 | int *child_iostat = NULL; | |
1166 | ||
1167 | /* Set iostat, intent(out). */ | |
1168 | noiostat = 0; | |
1169 | child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ? | |
1170 | dtp->common.iostat : &noiostat; | |
1171 | ||
1172 | /* Set iomsg, intent(inout). */ | |
1173 | if (dtp->common.flags & IOPARM_HAS_IOMSG) | |
1174 | { | |
1175 | child_iomsg = dtp->common.iomsg; | |
1176 | child_iomsg_len = dtp->common.iomsg_len; | |
1177 | } | |
1178 | else | |
1179 | { | |
1180 | child_iomsg = tmp_iomsg; | |
1181 | child_iomsg_len = IOMSG_LEN; | |
1182 | } | |
1183 | ||
1184 | /* Call the user defined unformatted WRITE procedure. */ | |
1185 | dtp->u.p.current_unit->child_dtio++; | |
1186 | dtp->u.p.ufdtio_ptr (source, &unit, child_iostat, child_iomsg, | |
1187 | child_iomsg_len); | |
1188 | dtp->u.p.current_unit->child_dtio--; | |
1189 | return; | |
1190 | } | |
1191 | ||
1192 | if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE) | |
e8189773 | 1193 | || kind == 1) |
181c9f4a | 1194 | { |
cea93abb JD |
1195 | size_t stride = type == BT_CHARACTER ? |
1196 | size * GFC_SIZE_OF_CHAR_KIND(kind) : size; | |
1197 | ||
1198 | write_buf (dtp, source, stride * nelems); | |
181c9f4a TK |
1199 | } |
1200 | else | |
1201 | { | |
facb23dc JB |
1202 | #define BSWAP_BUFSZ 512 |
1203 | char buffer[BSWAP_BUFSZ]; | |
181c9f4a | 1204 | char *p; |
facb23dc | 1205 | size_t nrem; |
cea93abb JD |
1206 | |
1207 | p = source; | |
1208 | ||
1209 | /* Handle wide chracters. */ | |
1210 | if (type == BT_CHARACTER && kind != 1) | |
1211 | { | |
1212 | nelems *= size; | |
1213 | size = kind; | |
1214 | } | |
e73d3ca6 | 1215 | |
181c9f4a TK |
1216 | /* Break up complex into its constituent reals. */ |
1217 | if (type == BT_COMPLEX) | |
1218 | { | |
1219 | nelems *= 2; | |
1220 | size /= 2; | |
e73d3ca6 | 1221 | } |
181c9f4a | 1222 | |
181c9f4a | 1223 | /* By now, all complex variables have been split into their |
80bcbc80 TB |
1224 | constituent reals. */ |
1225 | ||
facb23dc JB |
1226 | nrem = nelems; |
1227 | do | |
181c9f4a | 1228 | { |
facb23dc JB |
1229 | size_t nc; |
1230 | if (size * nrem > BSWAP_BUFSZ) | |
1231 | nc = BSWAP_BUFSZ / size; | |
1232 | else | |
1233 | nc = nrem; | |
1234 | ||
1235 | bswap_array (buffer, p, size, nc); | |
1236 | write_buf (dtp, buffer, size * nc); | |
1237 | p += size * nc; | |
1238 | nrem -= nc; | |
181c9f4a | 1239 | } |
facb23dc | 1240 | while (nrem > 0); |
181c9f4a | 1241 | } |
6de9cd9a DN |
1242 | } |
1243 | ||
1244 | ||
7fcb1804 | 1245 | /* Return a pointer to the name of a type. */ |
6de9cd9a DN |
1246 | |
1247 | const char * | |
1248 | type_name (bt type) | |
1249 | { | |
1250 | const char *p; | |
1251 | ||
1252 | switch (type) | |
1253 | { | |
1254 | case BT_INTEGER: | |
1255 | p = "INTEGER"; | |
1256 | break; | |
1257 | case BT_LOGICAL: | |
1258 | p = "LOGICAL"; | |
1259 | break; | |
1260 | case BT_CHARACTER: | |
1261 | p = "CHARACTER"; | |
1262 | break; | |
1263 | case BT_REAL: | |
1264 | p = "REAL"; | |
1265 | break; | |
1266 | case BT_COMPLEX: | |
1267 | p = "COMPLEX"; | |
1268 | break; | |
e73d3ca6 PT |
1269 | case BT_CLASS: |
1270 | p = "CLASS or DERIVED"; | |
1271 | break; | |
6de9cd9a | 1272 | default: |
5e805e44 | 1273 | internal_error (NULL, "type_name(): Bad type"); |
6de9cd9a DN |
1274 | } |
1275 | ||
1276 | return p; | |
1277 | } | |
1278 | ||
1279 | ||
7fcb1804 TS |
1280 | /* Write a constant string to the output. |
1281 | This is complicated because the string can have doubled delimiters | |
1282 | in it. The length in the format node is the true length. */ | |
6de9cd9a DN |
1283 | |
1284 | static void | |
5e805e44 | 1285 | write_constant_string (st_parameter_dt *dtp, const fnode *f) |
6de9cd9a DN |
1286 | { |
1287 | char c, delimiter, *p, *q; | |
e73d3ca6 | 1288 | int length; |
6de9cd9a DN |
1289 | |
1290 | length = f->u.string.length; | |
1291 | if (length == 0) | |
1292 | return; | |
1293 | ||
5e805e44 | 1294 | p = write_block (dtp, length); |
6de9cd9a DN |
1295 | if (p == NULL) |
1296 | return; | |
e73d3ca6 | 1297 | |
6de9cd9a DN |
1298 | q = f->u.string.p; |
1299 | delimiter = q[-1]; | |
1300 | ||
1301 | for (; length > 0; length--) | |
1302 | { | |
1303 | c = *p++ = *q++; | |
ec88bf8b | 1304 | if (c == delimiter && c != 'H' && c != 'h') |
7fcb1804 | 1305 | q++; /* Skip the doubled delimiter. */ |
6de9cd9a DN |
1306 | } |
1307 | } | |
1308 | ||
1309 | ||
7fcb1804 TS |
1310 | /* Given actual and expected types in a formatted data transfer, make |
1311 | sure they agree. If not, an error message is generated. Returns | |
1312 | nonzero if something went wrong. */ | |
6de9cd9a DN |
1313 | |
1314 | static int | |
5e805e44 | 1315 | require_type (st_parameter_dt *dtp, bt expected, bt actual, const fnode *f) |
6de9cd9a | 1316 | { |
d30fe1c5 JB |
1317 | #define BUFLEN 100 |
1318 | char buffer[BUFLEN]; | |
6de9cd9a DN |
1319 | |
1320 | if (actual == expected) | |
1321 | return 0; | |
1322 | ||
f983954d | 1323 | /* Adjust item_count before emitting error message. */ |
e73d3ca6 | 1324 | snprintf (buffer, BUFLEN, |
d30fe1c5 | 1325 | "Expected %s for item %d in formatted transfer, got %s", |
f983954d | 1326 | type_name (expected), dtp->u.p.item_count - 1, type_name (actual)); |
6de9cd9a | 1327 | |
5e805e44 | 1328 | format_error (dtp, f, buffer); |
6de9cd9a DN |
1329 | return 1; |
1330 | } | |
1331 | ||
1332 | ||
dc42a736 PT |
1333 | /* Check that the dtio procedure required for formatted IO is present. */ |
1334 | ||
1335 | static int | |
1336 | check_dtio_proc (st_parameter_dt *dtp, const fnode *f) | |
1337 | { | |
1338 | char buffer[BUFLEN]; | |
1339 | ||
1340 | if (dtp->u.p.fdtio_ptr != NULL) | |
1341 | return 0; | |
1342 | ||
1343 | snprintf (buffer, BUFLEN, | |
1344 | "Missing DTIO procedure or intrinsic type passed for item %d " | |
1345 | "in formatted transfer", | |
1346 | dtp->u.p.item_count - 1); | |
1347 | ||
1348 | format_error (dtp, f, buffer); | |
1349 | return 1; | |
1350 | } | |
1351 | ||
1352 | ||
32157107 TB |
1353 | static int |
1354 | require_numeric_type (st_parameter_dt *dtp, bt actual, const fnode *f) | |
1355 | { | |
1356 | #define BUFLEN 100 | |
1357 | char buffer[BUFLEN]; | |
1358 | ||
1359 | if (actual == BT_INTEGER || actual == BT_REAL || actual == BT_COMPLEX) | |
1360 | return 0; | |
1361 | ||
1362 | /* Adjust item_count before emitting error message. */ | |
e73d3ca6 | 1363 | snprintf (buffer, BUFLEN, |
32157107 TB |
1364 | "Expected numeric type for item %d in formatted transfer, got %s", |
1365 | dtp->u.p.item_count - 1, type_name (actual)); | |
1366 | ||
1367 | format_error (dtp, f, buffer); | |
1368 | return 1; | |
1369 | } | |
1370 | ||
5cdc4b0e JD |
1371 | static char * |
1372 | get_dt_format (char *p, gfc_charlen_type *length) | |
1373 | { | |
1374 | char delim = p[-1]; /* The delimiter is always the first character back. */ | |
1375 | char c, *q, *res; | |
1376 | gfc_charlen_type len = *length; /* This length already correct, less 'DT'. */ | |
1377 | ||
1378 | res = q = xmalloc (len + 2); | |
1379 | ||
1380 | /* Set the beginning of the string to 'DT', length adjusted below. */ | |
1381 | *q++ = 'D'; | |
1382 | *q++ = 'T'; | |
1383 | ||
1384 | /* The string may contain doubled quotes so scan and skip as needed. */ | |
1385 | for (; len > 0; len--) | |
1386 | { | |
1387 | c = *q++ = *p++; | |
1388 | if (c == delim) | |
1389 | p++; /* Skip the doubled delimiter. */ | |
1390 | } | |
1391 | ||
1392 | /* Adjust the string length by two now that we are done. */ | |
1393 | *length += 2; | |
1394 | ||
1395 | return res; | |
1396 | } | |
1397 | ||
32157107 | 1398 | |
7812c78c | 1399 | /* This function is in the main loop for a formatted data transfer |
7fcb1804 TS |
1400 | statement. It would be natural to implement this as a coroutine |
1401 | with the user program, but C makes that awkward. We loop, | |
8b6dba81 | 1402 | processing format elements. When we actually have to transfer |
7fcb1804 | 1403 | data instead of just setting flags, we return control to the user |
7812c78c | 1404 | program which calls a function that supplies the address and type |
7fcb1804 | 1405 | of the next element, then comes back here to process it. */ |
6de9cd9a DN |
1406 | |
1407 | static void | |
7812c78c JD |
1408 | formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind, |
1409 | size_t size) | |
6de9cd9a | 1410 | { |
94e2b58a | 1411 | int pos, bytes_used; |
5e805e44 | 1412 | const fnode *f; |
be0cc7e2 | 1413 | format_token t; |
a3b6aba2 | 1414 | int n; |
6de9cd9a DN |
1415 | int consume_data_flag; |
1416 | ||
7fcb1804 | 1417 | /* Change a complex data item into a pair of reals. */ |
6de9cd9a DN |
1418 | |
1419 | n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2); | |
1420 | if (type == BT_COMPLEX) | |
e5ef4b3b JB |
1421 | { |
1422 | type = BT_REAL; | |
1423 | size /= 2; | |
1424 | } | |
6de9cd9a | 1425 | |
59afe4b4 TK |
1426 | /* If there's an EOR condition, we simulate finalizing the transfer |
1427 | by doing nothing. */ | |
5e805e44 | 1428 | if (dtp->u.p.eor_condition) |
59afe4b4 TK |
1429 | return; |
1430 | ||
b14c7e14 JD |
1431 | /* Set this flag so that commas in reads cause the read to complete before |
1432 | the entire field has been read. The next read field will start right after | |
1433 | the comma in the stream. (Set to 0 for character reads). */ | |
105b7136 JD |
1434 | dtp->u.p.sf_read_comma = |
1435 | dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1; | |
d7445152 | 1436 | |
7812c78c JD |
1437 | for (;;) |
1438 | { | |
1439 | /* If reversion has occurred and there is another real data item, | |
1440 | then we have to move to the next record. */ | |
1441 | if (dtp->u.p.reversion_flag && n > 0) | |
1442 | { | |
1443 | dtp->u.p.reversion_flag = 0; | |
1444 | next_record (dtp, 0); | |
1445 | } | |
1446 | ||
1447 | consume_data_flag = 1; | |
1448 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) | |
1449 | break; | |
1450 | ||
1451 | f = next_format (dtp); | |
1452 | if (f == NULL) | |
1453 | { | |
1454 | /* No data descriptors left. */ | |
1455 | if (unlikely (n > 0)) | |
1456 | generate_error (&dtp->common, LIBERROR_FORMAT, | |
1457 | "Insufficient data descriptors in format after reversion"); | |
1458 | return; | |
1459 | } | |
1460 | ||
1461 | t = f->format; | |
1462 | ||
1463 | bytes_used = (int)(dtp->u.p.current_unit->recl | |
1464 | - dtp->u.p.current_unit->bytes_left); | |
1465 | ||
1466 | if (is_stream_io(dtp)) | |
1467 | bytes_used = 0; | |
1468 | ||
1469 | switch (t) | |
1470 | { | |
1471 | case FMT_I: | |
1472 | if (n == 0) | |
1473 | goto need_read_data; | |
1474 | if (require_type (dtp, BT_INTEGER, type, f)) | |
1475 | return; | |
1476 | read_decimal (dtp, f, p, kind); | |
1477 | break; | |
1478 | ||
1479 | case FMT_B: | |
1480 | if (n == 0) | |
1481 | goto need_read_data; | |
58fc89f6 | 1482 | if (!(compile_options.allow_std & GFC_STD_GNU) |
32157107 TB |
1483 | && require_numeric_type (dtp, type, f)) |
1484 | return; | |
1485 | if (!(compile_options.allow_std & GFC_STD_F2008) | |
7812c78c JD |
1486 | && require_type (dtp, BT_INTEGER, type, f)) |
1487 | return; | |
1488 | read_radix (dtp, f, p, kind, 2); | |
1489 | break; | |
1490 | ||
1491 | case FMT_O: | |
1492 | if (n == 0) | |
e73d3ca6 | 1493 | goto need_read_data; |
58fc89f6 | 1494 | if (!(compile_options.allow_std & GFC_STD_GNU) |
32157107 TB |
1495 | && require_numeric_type (dtp, type, f)) |
1496 | return; | |
1497 | if (!(compile_options.allow_std & GFC_STD_F2008) | |
7812c78c JD |
1498 | && require_type (dtp, BT_INTEGER, type, f)) |
1499 | return; | |
1500 | read_radix (dtp, f, p, kind, 8); | |
1501 | break; | |
1502 | ||
1503 | case FMT_Z: | |
1504 | if (n == 0) | |
1505 | goto need_read_data; | |
58fc89f6 | 1506 | if (!(compile_options.allow_std & GFC_STD_GNU) |
32157107 TB |
1507 | && require_numeric_type (dtp, type, f)) |
1508 | return; | |
1509 | if (!(compile_options.allow_std & GFC_STD_F2008) | |
7812c78c JD |
1510 | && require_type (dtp, BT_INTEGER, type, f)) |
1511 | return; | |
1512 | read_radix (dtp, f, p, kind, 16); | |
1513 | break; | |
1514 | ||
1515 | case FMT_A: | |
1516 | if (n == 0) | |
1517 | goto need_read_data; | |
1518 | ||
1519 | /* It is possible to have FMT_A with something not BT_CHARACTER such | |
1520 | as when writing out hollerith strings, so check both type | |
1521 | and kind before calling wide character routines. */ | |
1522 | if (type == BT_CHARACTER && kind == 4) | |
1523 | read_a_char4 (dtp, f, p, size); | |
1524 | else | |
1525 | read_a (dtp, f, p, size); | |
1526 | break; | |
1527 | ||
1528 | case FMT_L: | |
1529 | if (n == 0) | |
1530 | goto need_read_data; | |
1531 | read_l (dtp, f, p, kind); | |
1532 | break; | |
1533 | ||
1534 | case FMT_D: | |
1535 | if (n == 0) | |
1536 | goto need_read_data; | |
1537 | if (require_type (dtp, BT_REAL, type, f)) | |
1538 | return; | |
1539 | read_f (dtp, f, p, kind); | |
1540 | break; | |
1541 | ||
e73d3ca6 PT |
1542 | case FMT_DT: |
1543 | if (n == 0) | |
1544 | goto need_read_data; | |
dc42a736 PT |
1545 | |
1546 | if (check_dtio_proc (dtp, f)) | |
1547 | return; | |
e73d3ca6 PT |
1548 | if (require_type (dtp, BT_CLASS, type, f)) |
1549 | return; | |
1550 | int unit = dtp->u.p.current_unit->unit_number; | |
1551 | char dt[] = "DT"; | |
1552 | char tmp_iomsg[IOMSG_LEN] = ""; | |
1553 | char *child_iomsg; | |
1554 | gfc_charlen_type child_iomsg_len; | |
1555 | int noiostat; | |
1556 | int *child_iostat = NULL; | |
5cdc4b0e | 1557 | char *iotype; |
e73d3ca6 PT |
1558 | gfc_charlen_type iotype_len = f->u.udf.string_len; |
1559 | ||
1560 | /* Build the iotype string. */ | |
1561 | if (iotype_len == 0) | |
1562 | { | |
1563 | iotype_len = 2; | |
1564 | iotype = dt; | |
1565 | } | |
1566 | else | |
5cdc4b0e | 1567 | iotype = get_dt_format (f->u.udf.string, &iotype_len); |
e73d3ca6 PT |
1568 | |
1569 | /* Set iostat, intent(out). */ | |
1570 | noiostat = 0; | |
1571 | child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ? | |
1572 | dtp->common.iostat : &noiostat; | |
1573 | ||
1574 | /* Set iomsg, intent(inout). */ | |
1575 | if (dtp->common.flags & IOPARM_HAS_IOMSG) | |
1576 | { | |
1577 | child_iomsg = dtp->common.iomsg; | |
1578 | child_iomsg_len = dtp->common.iomsg_len; | |
1579 | } | |
1580 | else | |
1581 | { | |
1582 | child_iomsg = tmp_iomsg; | |
1583 | child_iomsg_len = IOMSG_LEN; | |
1584 | } | |
1585 | ||
1586 | /* Call the user defined formatted READ procedure. */ | |
1587 | dtp->u.p.current_unit->child_dtio++; | |
1f10d710 | 1588 | dtp->u.p.current_unit->last_char = EOF - 1; |
e73d3ca6 PT |
1589 | dtp->u.p.fdtio_ptr (p, &unit, iotype, f->u.udf.vlist, |
1590 | child_iostat, child_iomsg, | |
1591 | iotype_len, child_iomsg_len); | |
1592 | dtp->u.p.current_unit->child_dtio--; | |
1593 | ||
1594 | if (f->u.udf.string_len != 0) | |
1595 | free (iotype); | |
1596 | /* Note: vlist is freed in free_format_data. */ | |
1597 | break; | |
1598 | ||
7812c78c JD |
1599 | case FMT_E: |
1600 | if (n == 0) | |
1601 | goto need_read_data; | |
1602 | if (require_type (dtp, BT_REAL, type, f)) | |
1603 | return; | |
1604 | read_f (dtp, f, p, kind); | |
1605 | break; | |
1606 | ||
1607 | case FMT_EN: | |
1608 | if (n == 0) | |
1609 | goto need_read_data; | |
1610 | if (require_type (dtp, BT_REAL, type, f)) | |
1611 | return; | |
1612 | read_f (dtp, f, p, kind); | |
1613 | break; | |
1614 | ||
1615 | case FMT_ES: | |
1616 | if (n == 0) | |
1617 | goto need_read_data; | |
1618 | if (require_type (dtp, BT_REAL, type, f)) | |
1619 | return; | |
1620 | read_f (dtp, f, p, kind); | |
1621 | break; | |
1622 | ||
1623 | case FMT_F: | |
1624 | if (n == 0) | |
1625 | goto need_read_data; | |
1626 | if (require_type (dtp, BT_REAL, type, f)) | |
1627 | return; | |
1628 | read_f (dtp, f, p, kind); | |
1629 | break; | |
1630 | ||
1631 | case FMT_G: | |
1632 | if (n == 0) | |
1633 | goto need_read_data; | |
1634 | switch (type) | |
1635 | { | |
1636 | case BT_INTEGER: | |
1637 | read_decimal (dtp, f, p, kind); | |
1638 | break; | |
1639 | case BT_LOGICAL: | |
1640 | read_l (dtp, f, p, kind); | |
1641 | break; | |
1642 | case BT_CHARACTER: | |
1643 | if (kind == 4) | |
1644 | read_a_char4 (dtp, f, p, size); | |
1645 | else | |
1646 | read_a (dtp, f, p, size); | |
1647 | break; | |
1648 | case BT_REAL: | |
1649 | read_f (dtp, f, p, kind); | |
1650 | break; | |
1651 | default: | |
2b4c9065 NK |
1652 | internal_error (&dtp->common, |
1653 | "formatted_transfer (): Bad type"); | |
7812c78c JD |
1654 | } |
1655 | break; | |
1656 | ||
1657 | case FMT_STRING: | |
1658 | consume_data_flag = 0; | |
1659 | format_error (dtp, f, "Constant string in input format"); | |
1660 | return; | |
1661 | ||
1662 | /* Format codes that don't transfer data. */ | |
1663 | case FMT_X: | |
1664 | case FMT_TR: | |
1665 | consume_data_flag = 0; | |
1666 | dtp->u.p.skips += f->u.n; | |
1667 | pos = bytes_used + dtp->u.p.skips - 1; | |
1668 | dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1; | |
1669 | read_x (dtp, f->u.n); | |
1670 | break; | |
1671 | ||
1672 | case FMT_TL: | |
1673 | case FMT_T: | |
1674 | consume_data_flag = 0; | |
1675 | ||
1676 | if (f->format == FMT_TL) | |
1677 | { | |
1678 | /* Handle the special case when no bytes have been used yet. | |
1679 | Cannot go below zero. */ | |
1680 | if (bytes_used == 0) | |
1681 | { | |
1682 | dtp->u.p.pending_spaces -= f->u.n; | |
1683 | dtp->u.p.skips -= f->u.n; | |
1684 | dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips; | |
1685 | } | |
1686 | ||
1687 | pos = bytes_used - f->u.n; | |
1688 | } | |
1689 | else /* FMT_T */ | |
1690 | pos = f->u.n - 1; | |
1691 | ||
1692 | /* Standard 10.6.1.1: excessive left tabbing is reset to the | |
1693 | left tab limit. We do not check if the position has gone | |
1694 | beyond the end of record because a subsequent tab could | |
1695 | bring us back again. */ | |
1696 | pos = pos < 0 ? 0 : pos; | |
1697 | ||
1698 | dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used; | |
1699 | dtp->u.p.pending_spaces = dtp->u.p.pending_spaces | |
1700 | + pos - dtp->u.p.max_pos; | |
1701 | dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0 | |
1702 | ? 0 : dtp->u.p.pending_spaces; | |
1703 | if (dtp->u.p.skips == 0) | |
1704 | break; | |
1705 | ||
1706 | /* Adjust everything for end-of-record condition */ | |
1707 | if (dtp->u.p.sf_seen_eor && !is_internal_unit (dtp)) | |
1708 | { | |
1709 | dtp->u.p.current_unit->bytes_left -= dtp->u.p.sf_seen_eor; | |
1710 | dtp->u.p.skips -= dtp->u.p.sf_seen_eor; | |
1711 | bytes_used = pos; | |
d4fc6702 JD |
1712 | if (dtp->u.p.pending_spaces == 0) |
1713 | dtp->u.p.sf_seen_eor = 0; | |
7812c78c JD |
1714 | } |
1715 | if (dtp->u.p.skips < 0) | |
1716 | { | |
e73d3ca6 | 1717 | if (is_internal_unit (dtp)) |
4dadda8f | 1718 | sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR); |
7812c78c JD |
1719 | else |
1720 | fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR); | |
1721 | dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips; | |
1722 | dtp->u.p.skips = dtp->u.p.pending_spaces = 0; | |
1723 | } | |
1724 | else | |
1725 | read_x (dtp, dtp->u.p.skips); | |
1726 | break; | |
1727 | ||
1728 | case FMT_S: | |
1729 | consume_data_flag = 0; | |
1730 | dtp->u.p.sign_status = SIGN_S; | |
1731 | break; | |
1732 | ||
1733 | case FMT_SS: | |
1734 | consume_data_flag = 0; | |
1735 | dtp->u.p.sign_status = SIGN_SS; | |
1736 | break; | |
1737 | ||
1738 | case FMT_SP: | |
1739 | consume_data_flag = 0; | |
1740 | dtp->u.p.sign_status = SIGN_SP; | |
1741 | break; | |
1742 | ||
1743 | case FMT_BN: | |
1744 | consume_data_flag = 0 ; | |
1745 | dtp->u.p.blank_status = BLANK_NULL; | |
1746 | break; | |
1747 | ||
1748 | case FMT_BZ: | |
1749 | consume_data_flag = 0; | |
1750 | dtp->u.p.blank_status = BLANK_ZERO; | |
1751 | break; | |
1752 | ||
1753 | case FMT_DC: | |
1754 | consume_data_flag = 0; | |
1755 | dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA; | |
1756 | break; | |
1757 | ||
1758 | case FMT_DP: | |
1759 | consume_data_flag = 0; | |
1760 | dtp->u.p.current_unit->decimal_status = DECIMAL_POINT; | |
1761 | break; | |
74db2a47 | 1762 | |
379924dd JD |
1763 | case FMT_RC: |
1764 | consume_data_flag = 0; | |
1765 | dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE; | |
1766 | break; | |
1767 | ||
1768 | case FMT_RD: | |
1769 | consume_data_flag = 0; | |
1770 | dtp->u.p.current_unit->round_status = ROUND_DOWN; | |
1771 | break; | |
1772 | ||
1773 | case FMT_RN: | |
1774 | consume_data_flag = 0; | |
1775 | dtp->u.p.current_unit->round_status = ROUND_NEAREST; | |
1776 | break; | |
1777 | ||
1778 | case FMT_RP: | |
1779 | consume_data_flag = 0; | |
1780 | dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED; | |
1781 | break; | |
1782 | ||
1783 | case FMT_RU: | |
1784 | consume_data_flag = 0; | |
1785 | dtp->u.p.current_unit->round_status = ROUND_UP; | |
1786 | break; | |
1787 | ||
1788 | case FMT_RZ: | |
1789 | consume_data_flag = 0; | |
1790 | dtp->u.p.current_unit->round_status = ROUND_ZERO; | |
1791 | break; | |
7812c78c JD |
1792 | |
1793 | case FMT_P: | |
1794 | consume_data_flag = 0; | |
1795 | dtp->u.p.scale_factor = f->u.k; | |
1796 | break; | |
1797 | ||
1798 | case FMT_DOLLAR: | |
1799 | consume_data_flag = 0; | |
1800 | dtp->u.p.seen_dollar = 1; | |
1801 | break; | |
1802 | ||
1803 | case FMT_SLASH: | |
1804 | consume_data_flag = 0; | |
1805 | dtp->u.p.skips = dtp->u.p.pending_spaces = 0; | |
1806 | next_record (dtp, 0); | |
1807 | break; | |
1808 | ||
1809 | case FMT_COLON: | |
1810 | /* A colon descriptor causes us to exit this loop (in | |
1811 | particular preventing another / descriptor from being | |
1812 | processed) unless there is another data item to be | |
1813 | transferred. */ | |
1814 | consume_data_flag = 0; | |
1815 | if (n == 0) | |
1816 | return; | |
1817 | break; | |
1818 | ||
1819 | default: | |
1820 | internal_error (&dtp->common, "Bad format node"); | |
1821 | } | |
1822 | ||
1823 | /* Adjust the item count and data pointer. */ | |
1824 | ||
1825 | if ((consume_data_flag > 0) && (n > 0)) | |
1826 | { | |
1827 | n--; | |
1828 | p = ((char *) p) + size; | |
1829 | } | |
1830 | ||
1831 | dtp->u.p.skips = 0; | |
1832 | ||
1833 | pos = (int)(dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left); | |
1834 | dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos; | |
1835 | } | |
1836 | ||
1837 | return; | |
1838 | ||
1839 | /* Come here when we need a data descriptor but don't have one. We | |
1840 | push the current format node back onto the input, then return and | |
1841 | let the user program call us back with the data. */ | |
1842 | need_read_data: | |
1843 | unget_format (dtp, f); | |
1844 | } | |
1845 | ||
1846 | ||
1847 | static void | |
1848 | formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kind, | |
1849 | size_t size) | |
1850 | { | |
ea99ec5b | 1851 | gfc_offset pos, bytes_used; |
7812c78c JD |
1852 | const fnode *f; |
1853 | format_token t; | |
1854 | int n; | |
1855 | int consume_data_flag; | |
1856 | ||
1857 | /* Change a complex data item into a pair of reals. */ | |
1858 | ||
1859 | n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2); | |
1860 | if (type == BT_COMPLEX) | |
1861 | { | |
1862 | type = BT_REAL; | |
1863 | size /= 2; | |
1864 | } | |
1865 | ||
1866 | /* If there's an EOR condition, we simulate finalizing the transfer | |
1867 | by doing nothing. */ | |
1868 | if (dtp->u.p.eor_condition) | |
1869 | return; | |
1870 | ||
1871 | /* Set this flag so that commas in reads cause the read to complete before | |
1872 | the entire field has been read. The next read field will start right after | |
1873 | the comma in the stream. (Set to 0 for character reads). */ | |
1874 | dtp->u.p.sf_read_comma = | |
1875 | dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1; | |
f3ed1d02 | 1876 | |
6de9cd9a DN |
1877 | for (;;) |
1878 | { | |
5d3a9816 | 1879 | /* If reversion has occurred and there is another real data item, |
be0cc7e2 | 1880 | then we have to move to the next record. */ |
5e805e44 | 1881 | if (dtp->u.p.reversion_flag && n > 0) |
be0cc7e2 | 1882 | { |
5e805e44 JJ |
1883 | dtp->u.p.reversion_flag = 0; |
1884 | next_record (dtp, 0); | |
be0cc7e2 | 1885 | } |
5d3a9816 | 1886 | |
10256cbe | 1887 | consume_data_flag = 1; |
5e805e44 | 1888 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) |
6de9cd9a DN |
1889 | break; |
1890 | ||
5e805e44 | 1891 | f = next_format (dtp); |
6de9cd9a | 1892 | if (f == NULL) |
c4ee121a JD |
1893 | { |
1894 | /* No data descriptors left. */ | |
afab92d8 | 1895 | if (unlikely (n > 0)) |
d74b97cc | 1896 | generate_error (&dtp->common, LIBERROR_FORMAT, |
c4ee121a JD |
1897 | "Insufficient data descriptors in format after reversion"); |
1898 | return; | |
1899 | } | |
be0cc7e2 PT |
1900 | |
1901 | /* Now discharge T, TR and X movements to the right. This is delayed | |
b6f571b7 | 1902 | until a data producing format to suppress trailing spaces. */ |
e73d3ca6 | 1903 | |
be0cc7e2 | 1904 | t = f->format; |
5e805e44 | 1905 | if (dtp->u.p.mode == WRITING && dtp->u.p.skips != 0 |
b6f571b7 PT |
1906 | && ((n>0 && ( t == FMT_I || t == FMT_B || t == FMT_O |
1907 | || t == FMT_Z || t == FMT_F || t == FMT_E | |
1908 | || t == FMT_EN || t == FMT_ES || t == FMT_G | |
e73d3ca6 PT |
1909 | || t == FMT_L || t == FMT_A || t == FMT_D |
1910 | || t == FMT_DT)) | |
be0cc7e2 PT |
1911 | || t == FMT_STRING)) |
1912 | { | |
5e805e44 | 1913 | if (dtp->u.p.skips > 0) |
b6f571b7 | 1914 | { |
ea99ec5b | 1915 | gfc_offset tmp; |
5e805e44 | 1916 | write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces); |
ea99ec5b JB |
1917 | tmp = dtp->u.p.current_unit->recl |
1918 | - dtp->u.p.current_unit->bytes_left; | |
e73d3ca6 | 1919 | dtp->u.p.max_pos = |
6c540522 | 1920 | dtp->u.p.max_pos > tmp ? dtp->u.p.max_pos : tmp; |
6e9966e8 | 1921 | dtp->u.p.skips = 0; |
b6f571b7 | 1922 | } |
5e805e44 | 1923 | if (dtp->u.p.skips < 0) |
b6f571b7 | 1924 | { |
e73d3ca6 | 1925 | if (is_internal_unit (dtp)) |
4dadda8f | 1926 | sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR); |
15877a88 | 1927 | else |
7812c78c | 1928 | fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR); |
5e805e44 | 1929 | dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips; |
b6f571b7 | 1930 | } |
5e805e44 | 1931 | dtp->u.p.skips = dtp->u.p.pending_spaces = 0; |
be0cc7e2 | 1932 | } |
6de9cd9a | 1933 | |
ea99ec5b JB |
1934 | bytes_used = dtp->u.p.current_unit->recl |
1935 | - dtp->u.p.current_unit->bytes_left; | |
d40150cc JD |
1936 | |
1937 | if (is_stream_io(dtp)) | |
1938 | bytes_used = 0; | |
94e2b58a | 1939 | |
be0cc7e2 | 1940 | switch (t) |
6de9cd9a DN |
1941 | { |
1942 | case FMT_I: | |
1943 | if (n == 0) | |
1944 | goto need_data; | |
5e805e44 | 1945 | if (require_type (dtp, BT_INTEGER, type, f)) |
6de9cd9a | 1946 | return; |
7812c78c | 1947 | write_i (dtp, f, p, kind); |
6de9cd9a DN |
1948 | break; |
1949 | ||
1950 | case FMT_B: | |
1951 | if (n == 0) | |
1952 | goto need_data; | |
58fc89f6 | 1953 | if (!(compile_options.allow_std & GFC_STD_GNU) |
32157107 TB |
1954 | && require_numeric_type (dtp, type, f)) |
1955 | return; | |
1956 | if (!(compile_options.allow_std & GFC_STD_F2008) | |
751748ff | 1957 | && require_type (dtp, BT_INTEGER, type, f)) |
6de9cd9a | 1958 | return; |
7812c78c | 1959 | write_b (dtp, f, p, kind); |
6de9cd9a DN |
1960 | break; |
1961 | ||
1962 | case FMT_O: | |
1963 | if (n == 0) | |
e73d3ca6 | 1964 | goto need_data; |
58fc89f6 | 1965 | if (!(compile_options.allow_std & GFC_STD_GNU) |
32157107 TB |
1966 | && require_numeric_type (dtp, type, f)) |
1967 | return; | |
1968 | if (!(compile_options.allow_std & GFC_STD_F2008) | |
751748ff TB |
1969 | && require_type (dtp, BT_INTEGER, type, f)) |
1970 | return; | |
7812c78c | 1971 | write_o (dtp, f, p, kind); |
6de9cd9a DN |
1972 | break; |
1973 | ||
1974 | case FMT_Z: | |
1975 | if (n == 0) | |
1976 | goto need_data; | |
58fc89f6 | 1977 | if (!(compile_options.allow_std & GFC_STD_GNU) |
32157107 TB |
1978 | && require_numeric_type (dtp, type, f)) |
1979 | return; | |
1980 | if (!(compile_options.allow_std & GFC_STD_F2008) | |
751748ff TB |
1981 | && require_type (dtp, BT_INTEGER, type, f)) |
1982 | return; | |
7812c78c | 1983 | write_z (dtp, f, p, kind); |
6de9cd9a DN |
1984 | break; |
1985 | ||
1986 | case FMT_A: | |
1987 | if (n == 0) | |
1988 | goto need_data; | |
6de9cd9a | 1989 | |
cea93abb JD |
1990 | /* It is possible to have FMT_A with something not BT_CHARACTER such |
1991 | as when writing out hollerith strings, so check both type | |
1992 | and kind before calling wide character routines. */ | |
7812c78c JD |
1993 | if (type == BT_CHARACTER && kind == 4) |
1994 | write_a_char4 (dtp, f, p, size); | |
6de9cd9a | 1995 | else |
7812c78c | 1996 | write_a (dtp, f, p, size); |
6de9cd9a DN |
1997 | break; |
1998 | ||
1999 | case FMT_L: | |
2000 | if (n == 0) | |
2001 | goto need_data; | |
7812c78c | 2002 | write_l (dtp, f, p, kind); |
6de9cd9a DN |
2003 | break; |
2004 | ||
2005 | case FMT_D: | |
2006 | if (n == 0) | |
2007 | goto need_data; | |
5e805e44 | 2008 | if (require_type (dtp, BT_REAL, type, f)) |
6de9cd9a | 2009 | return; |
7812c78c | 2010 | write_d (dtp, f, p, kind); |
6de9cd9a DN |
2011 | break; |
2012 | ||
e73d3ca6 PT |
2013 | case FMT_DT: |
2014 | if (n == 0) | |
2015 | goto need_data; | |
2016 | int unit = dtp->u.p.current_unit->unit_number; | |
2017 | char dt[] = "DT"; | |
2018 | char tmp_iomsg[IOMSG_LEN] = ""; | |
2019 | char *child_iomsg; | |
2020 | gfc_charlen_type child_iomsg_len; | |
2021 | int noiostat; | |
2022 | int *child_iostat = NULL; | |
5cdc4b0e | 2023 | char *iotype; |
e73d3ca6 PT |
2024 | gfc_charlen_type iotype_len = f->u.udf.string_len; |
2025 | ||
2026 | /* Build the iotype string. */ | |
2027 | if (iotype_len == 0) | |
2028 | { | |
2029 | iotype_len = 2; | |
2030 | iotype = dt; | |
2031 | } | |
2032 | else | |
5cdc4b0e | 2033 | iotype = get_dt_format (f->u.udf.string, &iotype_len); |
e73d3ca6 PT |
2034 | |
2035 | /* Set iostat, intent(out). */ | |
2036 | noiostat = 0; | |
2037 | child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ? | |
2038 | dtp->common.iostat : &noiostat; | |
2039 | ||
2040 | /* Set iomsg, intent(inout). */ | |
2041 | if (dtp->common.flags & IOPARM_HAS_IOMSG) | |
2042 | { | |
2043 | child_iomsg = dtp->common.iomsg; | |
2044 | child_iomsg_len = dtp->common.iomsg_len; | |
2045 | } | |
2046 | else | |
2047 | { | |
2048 | child_iomsg = tmp_iomsg; | |
2049 | child_iomsg_len = IOMSG_LEN; | |
2050 | } | |
2051 | ||
dc42a736 PT |
2052 | if (check_dtio_proc (dtp, f)) |
2053 | return; | |
2054 | ||
e73d3ca6 PT |
2055 | /* Call the user defined formatted WRITE procedure. */ |
2056 | dtp->u.p.current_unit->child_dtio++; | |
dc42a736 | 2057 | |
e73d3ca6 PT |
2058 | dtp->u.p.fdtio_ptr (p, &unit, iotype, f->u.udf.vlist, |
2059 | child_iostat, child_iomsg, | |
2060 | iotype_len, child_iomsg_len); | |
2061 | dtp->u.p.current_unit->child_dtio--; | |
2062 | ||
2063 | if (f->u.udf.string_len != 0) | |
2064 | free (iotype); | |
2065 | /* Note: vlist is freed in free_format_data. */ | |
2066 | break; | |
2067 | ||
6de9cd9a DN |
2068 | case FMT_E: |
2069 | if (n == 0) | |
2070 | goto need_data; | |
5e805e44 | 2071 | if (require_type (dtp, BT_REAL, type, f)) |
6de9cd9a | 2072 | return; |
7812c78c | 2073 | write_e (dtp, f, p, kind); |
6de9cd9a DN |
2074 | break; |
2075 | ||
2076 | case FMT_EN: | |
2077 | if (n == 0) | |
2078 | goto need_data; | |
5e805e44 | 2079 | if (require_type (dtp, BT_REAL, type, f)) |
6de9cd9a | 2080 | return; |
7812c78c | 2081 | write_en (dtp, f, p, kind); |
6de9cd9a DN |
2082 | break; |
2083 | ||
2084 | case FMT_ES: | |
2085 | if (n == 0) | |
2086 | goto need_data; | |
5e805e44 | 2087 | if (require_type (dtp, BT_REAL, type, f)) |
6de9cd9a | 2088 | return; |
7812c78c | 2089 | write_es (dtp, f, p, kind); |
6de9cd9a DN |
2090 | break; |
2091 | ||
2092 | case FMT_F: | |
2093 | if (n == 0) | |
2094 | goto need_data; | |
5e805e44 | 2095 | if (require_type (dtp, BT_REAL, type, f)) |
6de9cd9a | 2096 | return; |
7812c78c | 2097 | write_f (dtp, f, p, kind); |
6de9cd9a DN |
2098 | break; |
2099 | ||
2100 | case FMT_G: | |
2101 | if (n == 0) | |
2102 | goto need_data; | |
7812c78c JD |
2103 | switch (type) |
2104 | { | |
6de9cd9a | 2105 | case BT_INTEGER: |
cea93abb | 2106 | write_i (dtp, f, p, kind); |
6de9cd9a DN |
2107 | break; |
2108 | case BT_LOGICAL: | |
74db2a47 | 2109 | write_l (dtp, f, p, kind); |
6de9cd9a DN |
2110 | break; |
2111 | case BT_CHARACTER: | |
cea93abb JD |
2112 | if (kind == 4) |
2113 | write_a_char4 (dtp, f, p, size); | |
2114 | else | |
2115 | write_a (dtp, f, p, size); | |
6de9cd9a DN |
2116 | break; |
2117 | case BT_REAL: | |
9355110f | 2118 | if (f->u.real.w == 0) |
7812c78c | 2119 | write_real_g0 (dtp, p, kind, f->u.real.d); |
9355110f | 2120 | else |
cea93abb | 2121 | write_d (dtp, f, p, kind); |
6de9cd9a DN |
2122 | break; |
2123 | default: | |
5e805e44 | 2124 | internal_error (&dtp->common, |
2b4c9065 | 2125 | "formatted_transfer (): Bad type"); |
7812c78c | 2126 | } |
6de9cd9a DN |
2127 | break; |
2128 | ||
2129 | case FMT_STRING: | |
10256cbe | 2130 | consume_data_flag = 0; |
5e805e44 | 2131 | write_constant_string (dtp, f); |
6de9cd9a DN |
2132 | break; |
2133 | ||
be0cc7e2 | 2134 | /* Format codes that don't transfer data. */ |
6de9cd9a DN |
2135 | case FMT_X: |
2136 | case FMT_TR: | |
22cbc707 | 2137 | consume_data_flag = 0; |
be0cc7e2 | 2138 | |
d40150cc JD |
2139 | dtp->u.p.skips += f->u.n; |
2140 | pos = bytes_used + dtp->u.p.skips - 1; | |
2141 | dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1; | |
740f04ef JD |
2142 | /* Writes occur just before the switch on f->format, above, so |
2143 | that trailing blanks are suppressed, unless we are doing a | |
2144 | non-advancing write in which case we want to output the blanks | |
2145 | now. */ | |
7812c78c | 2146 | if (dtp->u.p.advance_status == ADVANCE_NO) |
740f04ef | 2147 | { |
5e805e44 JJ |
2148 | write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces); |
2149 | dtp->u.p.skips = dtp->u.p.pending_spaces = 0; | |
740f04ef | 2150 | } |
6de9cd9a DN |
2151 | break; |
2152 | ||
be0cc7e2 PT |
2153 | case FMT_TL: |
2154 | case FMT_T: | |
22cbc707 JD |
2155 | consume_data_flag = 0; |
2156 | ||
be0cc7e2 | 2157 | if (f->format == FMT_TL) |
272c35bd JD |
2158 | { |
2159 | ||
2160 | /* Handle the special case when no bytes have been used yet. | |
2161 | Cannot go below zero. */ | |
2162 | if (bytes_used == 0) | |
2163 | { | |
2164 | dtp->u.p.pending_spaces -= f->u.n; | |
272c35bd JD |
2165 | dtp->u.p.skips -= f->u.n; |
2166 | dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips; | |
2167 | } | |
2168 | ||
2169 | pos = bytes_used - f->u.n; | |
2170 | } | |
be0cc7e2 | 2171 | else /* FMT_T */ |
7812c78c | 2172 | pos = f->u.n - dtp->u.p.pending_spaces - 1; |
be0cc7e2 PT |
2173 | |
2174 | /* Standard 10.6.1.1: excessive left tabbing is reset to the | |
2175 | left tab limit. We do not check if the position has gone | |
2176 | beyond the end of record because a subsequent tab could | |
2177 | bring us back again. */ | |
2178 | pos = pos < 0 ? 0 : pos; | |
2179 | ||
5e805e44 JJ |
2180 | dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used; |
2181 | dtp->u.p.pending_spaces = dtp->u.p.pending_spaces | |
2182 | + pos - dtp->u.p.max_pos; | |
8d917a24 JD |
2183 | dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0 |
2184 | ? 0 : dtp->u.p.pending_spaces; | |
6de9cd9a DN |
2185 | break; |
2186 | ||
2187 | case FMT_S: | |
10256cbe | 2188 | consume_data_flag = 0; |
5e805e44 | 2189 | dtp->u.p.sign_status = SIGN_S; |
6de9cd9a DN |
2190 | break; |
2191 | ||
2192 | case FMT_SS: | |
10256cbe | 2193 | consume_data_flag = 0; |
5e805e44 | 2194 | dtp->u.p.sign_status = SIGN_SS; |
6de9cd9a DN |
2195 | break; |
2196 | ||
2197 | case FMT_SP: | |
10256cbe | 2198 | consume_data_flag = 0; |
5e805e44 | 2199 | dtp->u.p.sign_status = SIGN_SP; |
6de9cd9a DN |
2200 | break; |
2201 | ||
2202 | case FMT_BN: | |
be0cc7e2 | 2203 | consume_data_flag = 0 ; |
5e805e44 | 2204 | dtp->u.p.blank_status = BLANK_NULL; |
6de9cd9a DN |
2205 | break; |
2206 | ||
2207 | case FMT_BZ: | |
10256cbe | 2208 | consume_data_flag = 0; |
5e805e44 | 2209 | dtp->u.p.blank_status = BLANK_ZERO; |
6de9cd9a DN |
2210 | break; |
2211 | ||
10256cbe JD |
2212 | case FMT_DC: |
2213 | consume_data_flag = 0; | |
105b7136 | 2214 | dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA; |
10256cbe JD |
2215 | break; |
2216 | ||
2217 | case FMT_DP: | |
2218 | consume_data_flag = 0; | |
105b7136 | 2219 | dtp->u.p.current_unit->decimal_status = DECIMAL_POINT; |
10256cbe JD |
2220 | break; |
2221 | ||
379924dd JD |
2222 | case FMT_RC: |
2223 | consume_data_flag = 0; | |
2224 | dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE; | |
2225 | break; | |
2226 | ||
2227 | case FMT_RD: | |
2228 | consume_data_flag = 0; | |
2229 | dtp->u.p.current_unit->round_status = ROUND_DOWN; | |
2230 | break; | |
2231 | ||
2232 | case FMT_RN: | |
2233 | consume_data_flag = 0; | |
2234 | dtp->u.p.current_unit->round_status = ROUND_NEAREST; | |
2235 | break; | |
2236 | ||
2237 | case FMT_RP: | |
2238 | consume_data_flag = 0; | |
2239 | dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED; | |
2240 | break; | |
2241 | ||
2242 | case FMT_RU: | |
2243 | consume_data_flag = 0; | |
2244 | dtp->u.p.current_unit->round_status = ROUND_UP; | |
2245 | break; | |
2246 | ||
2247 | case FMT_RZ: | |
2248 | consume_data_flag = 0; | |
2249 | dtp->u.p.current_unit->round_status = ROUND_ZERO; | |
2250 | break; | |
2251 | ||
6de9cd9a | 2252 | case FMT_P: |
10256cbe | 2253 | consume_data_flag = 0; |
5e805e44 | 2254 | dtp->u.p.scale_factor = f->u.k; |
6de9cd9a DN |
2255 | break; |
2256 | ||
2257 | case FMT_DOLLAR: | |
10256cbe | 2258 | consume_data_flag = 0; |
5e805e44 | 2259 | dtp->u.p.seen_dollar = 1; |
6de9cd9a DN |
2260 | break; |
2261 | ||
2262 | case FMT_SLASH: | |
10256cbe | 2263 | consume_data_flag = 0; |
5e805e44 JJ |
2264 | dtp->u.p.skips = dtp->u.p.pending_spaces = 0; |
2265 | next_record (dtp, 0); | |
6de9cd9a DN |
2266 | break; |
2267 | ||
2268 | case FMT_COLON: | |
7fcb1804 TS |
2269 | /* A colon descriptor causes us to exit this loop (in |
2270 | particular preventing another / descriptor from being | |
2271 | processed) unless there is another data item to be | |
2272 | transferred. */ | |
10256cbe | 2273 | consume_data_flag = 0; |
6de9cd9a DN |
2274 | if (n == 0) |
2275 | return; | |
2276 | break; | |
2277 | ||
2278 | default: | |
5e805e44 | 2279 | internal_error (&dtp->common, "Bad format node"); |
6de9cd9a DN |
2280 | } |
2281 | ||
7fcb1804 | 2282 | /* Adjust the item count and data pointer. */ |
6de9cd9a DN |
2283 | |
2284 | if ((consume_data_flag > 0) && (n > 0)) | |
7812c78c JD |
2285 | { |
2286 | n--; | |
2287 | p = ((char *) p) + size; | |
2288 | } | |
be0cc7e2 | 2289 | |
ea99ec5b | 2290 | pos = dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left; |
5e805e44 | 2291 | dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos; |
6de9cd9a DN |
2292 | } |
2293 | ||
2294 | return; | |
2295 | ||
f21edfd6 RH |
2296 | /* Come here when we need a data descriptor but don't have one. We |
2297 | push the current format node back onto the input, then return and | |
2298 | let the user program call us back with the data. */ | |
2299 | need_data: | |
5e805e44 | 2300 | unget_format (dtp, f); |
6de9cd9a DN |
2301 | } |
2302 | ||
f983954d JD |
2303 | /* This function is first called from data_init_transfer to initiate the loop |
2304 | over each item in the format, transferring data as required. Subsequent | |
2305 | calls to this function occur for each data item foound in the READ/WRITE | |
2306 | statement. The item_count is incremented for each call. Since the first | |
2307 | call is from data_transfer_init, the item_count is always one greater than | |
2308 | the actual count number of the item being transferred. */ | |
7812c78c | 2309 | |
18623fae | 2310 | static void |
5e805e44 JJ |
2311 | formatted_transfer (st_parameter_dt *dtp, bt type, void *p, int kind, |
2312 | size_t size, size_t nelems) | |
18623fae JB |
2313 | { |
2314 | size_t elem; | |
18623fae JB |
2315 | char *tmp; |
2316 | ||
2317 | tmp = (char *) p; | |
cea93abb JD |
2318 | size_t stride = type == BT_CHARACTER ? |
2319 | size * GFC_SIZE_OF_CHAR_KIND(kind) : size; | |
7812c78c JD |
2320 | if (dtp->u.p.mode == READING) |
2321 | { | |
2322 | /* Big loop over all the elements. */ | |
2323 | for (elem = 0; elem < nelems; elem++) | |
2324 | { | |
2325 | dtp->u.p.item_count++; | |
2326 | formatted_transfer_scalar_read (dtp, type, tmp + stride*elem, kind, size); | |
2327 | } | |
2328 | } | |
2329 | else | |
18623fae | 2330 | { |
7812c78c JD |
2331 | /* Big loop over all the elements. */ |
2332 | for (elem = 0; elem < nelems; elem++) | |
2333 | { | |
2334 | dtp->u.p.item_count++; | |
2335 | formatted_transfer_scalar_write (dtp, type, tmp + stride*elem, kind, size); | |
2336 | } | |
18623fae JB |
2337 | } |
2338 | } | |
2339 | ||
2b4c9065 NK |
2340 | /* Wrapper function for I/O of scalar types. If this should be an async I/O |
2341 | request, queue it. For a synchronous write on an async unit, perform the | |
2342 | wait operation and return an error. For all synchronous writes, call the | |
2343 | right transfer function. */ | |
2344 | ||
2345 | static void | |
2346 | wrap_scalar_transfer (st_parameter_dt *dtp, bt type, void *p, int kind, | |
2347 | size_t size, size_t n_elem) | |
2348 | { | |
2349 | if (dtp->u.p.current_unit && dtp->u.p.current_unit->au) | |
2350 | { | |
2351 | if (dtp->u.p.async) | |
2352 | { | |
2353 | transfer_args args; | |
2354 | args.scalar.transfer = dtp->u.p.transfer; | |
2355 | args.scalar.arg_bt = type; | |
2356 | args.scalar.data = p; | |
2357 | args.scalar.i = kind; | |
2358 | args.scalar.s1 = size; | |
2359 | args.scalar.s2 = n_elem; | |
2360 | enqueue_transfer (dtp->u.p.current_unit->au, &args, | |
2361 | AIO_TRANSFER_SCALAR); | |
2362 | return; | |
2363 | } | |
2364 | } | |
2365 | /* Come here if there was no asynchronous I/O to be scheduled. */ | |
2366 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) | |
2367 | return; | |
2368 | ||
2369 | dtp->u.p.transfer (dtp, type, p, kind, size, 1); | |
2370 | } | |
2371 | ||
18623fae | 2372 | |
6de9cd9a | 2373 | /* Data transfer entry points. The type of the data entity is |
7fcb1804 TS |
2374 | implicit in the subroutine call. This prevents us from having to |
2375 | share a common enum with the compiler. */ | |
6de9cd9a DN |
2376 | |
2377 | void | |
5e805e44 | 2378 | transfer_integer (st_parameter_dt *dtp, void *p, int kind) |
6de9cd9a | 2379 | { |
2b4c9065 | 2380 | wrap_scalar_transfer (dtp, BT_INTEGER, p, kind, kind, 1); |
6de9cd9a DN |
2381 | } |
2382 | ||
6eb6875d TK |
2383 | void |
2384 | transfer_integer_write (st_parameter_dt *dtp, void *p, int kind) | |
2385 | { | |
2386 | transfer_integer (dtp, p, kind); | |
2387 | } | |
6de9cd9a DN |
2388 | |
2389 | void | |
5e805e44 | 2390 | transfer_real (st_parameter_dt *dtp, void *p, int kind) |
6de9cd9a | 2391 | { |
e5ef4b3b | 2392 | size_t size; |
5e805e44 | 2393 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) |
6de9cd9a | 2394 | return; |
e5ef4b3b | 2395 | size = size_from_real_kind (kind); |
2b4c9065 | 2396 | wrap_scalar_transfer (dtp, BT_REAL, p, kind, size, 1); |
6de9cd9a DN |
2397 | } |
2398 | ||
6eb6875d TK |
2399 | void |
2400 | transfer_real_write (st_parameter_dt *dtp, void *p, int kind) | |
2401 | { | |
2402 | transfer_real (dtp, p, kind); | |
2403 | } | |
6de9cd9a DN |
2404 | |
2405 | void | |
5e805e44 | 2406 | transfer_logical (st_parameter_dt *dtp, void *p, int kind) |
6de9cd9a | 2407 | { |
2b4c9065 | 2408 | wrap_scalar_transfer (dtp, BT_LOGICAL, p, kind, kind, 1); |
6de9cd9a DN |
2409 | } |
2410 | ||
6eb6875d TK |
2411 | void |
2412 | transfer_logical_write (st_parameter_dt *dtp, void *p, int kind) | |
2413 | { | |
2414 | transfer_logical (dtp, p, kind); | |
2415 | } | |
6de9cd9a DN |
2416 | |
2417 | void | |
f622221a | 2418 | transfer_character (st_parameter_dt *dtp, void *p, gfc_charlen_type len) |
6de9cd9a | 2419 | { |
e5044336 FXC |
2420 | static char *empty_string[0]; |
2421 | ||
5e805e44 | 2422 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) |
6de9cd9a | 2423 | return; |
e5044336 FXC |
2424 | |
2425 | /* Strings of zero length can have p == NULL, which confuses the | |
2426 | transfer routines into thinking we need more data elements. To avoid | |
2427 | this, we give them a nice pointer. */ | |
2428 | if (len == 0 && p == NULL) | |
2429 | p = empty_string; | |
2430 | ||
cea93abb | 2431 | /* Set kind here to 1. */ |
2b4c9065 | 2432 | wrap_scalar_transfer (dtp, BT_CHARACTER, p, 1, len, 1); |
cea93abb JD |
2433 | } |
2434 | ||
6eb6875d | 2435 | void |
f622221a | 2436 | transfer_character_write (st_parameter_dt *dtp, void *p, gfc_charlen_type len) |
6eb6875d TK |
2437 | { |
2438 | transfer_character (dtp, p, len); | |
2439 | } | |
2440 | ||
cea93abb | 2441 | void |
f622221a | 2442 | transfer_character_wide (st_parameter_dt *dtp, void *p, gfc_charlen_type len, int kind) |
cea93abb JD |
2443 | { |
2444 | static char *empty_string[0]; | |
2445 | ||
2446 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) | |
2447 | return; | |
2448 | ||
2449 | /* Strings of zero length can have p == NULL, which confuses the | |
2450 | transfer routines into thinking we need more data elements. To avoid | |
2451 | this, we give them a nice pointer. */ | |
2452 | if (len == 0 && p == NULL) | |
2453 | p = empty_string; | |
2454 | ||
2455 | /* Here we pass the actual kind value. */ | |
2b4c9065 | 2456 | wrap_scalar_transfer (dtp, BT_CHARACTER, p, kind, len, 1); |
6de9cd9a DN |
2457 | } |
2458 | ||
6eb6875d | 2459 | void |
f622221a | 2460 | transfer_character_wide_write (st_parameter_dt *dtp, void *p, gfc_charlen_type len, int kind) |
6eb6875d TK |
2461 | { |
2462 | transfer_character_wide (dtp, p, len, kind); | |
2463 | } | |
6de9cd9a DN |
2464 | |
2465 | void | |
5e805e44 | 2466 | transfer_complex (st_parameter_dt *dtp, void *p, int kind) |
6de9cd9a | 2467 | { |
e5ef4b3b | 2468 | size_t size; |
5e805e44 | 2469 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) |
6de9cd9a | 2470 | return; |
e5ef4b3b | 2471 | size = size_from_complex_kind (kind); |
2b4c9065 | 2472 | wrap_scalar_transfer (dtp, BT_COMPLEX, p, kind, size, 1); |
18623fae JB |
2473 | } |
2474 | ||
6eb6875d TK |
2475 | void |
2476 | transfer_complex_write (st_parameter_dt *dtp, void *p, int kind) | |
2477 | { | |
2478 | transfer_complex (dtp, p, kind); | |
2479 | } | |
18623fae JB |
2480 | |
2481 | void | |
2b4c9065 NK |
2482 | transfer_array_inner (st_parameter_dt *dtp, gfc_array_char *desc, int kind, |
2483 | gfc_charlen_type charlen) | |
18623fae JB |
2484 | { |
2485 | index_type count[GFC_MAX_DIMENSIONS]; | |
2486 | index_type extent[GFC_MAX_DIMENSIONS]; | |
2487 | index_type stride[GFC_MAX_DIMENSIONS]; | |
a11930ba | 2488 | index_type stride0, rank, size, n; |
18623fae JB |
2489 | size_t tsize; |
2490 | char *data; | |
2491 | bt iotype; | |
2492 | ||
7fb43006 | 2493 | /* Adjust item_count before emitting error message. */ |
2b4c9065 | 2494 | |
5e805e44 | 2495 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) |
18623fae JB |
2496 | return; |
2497 | ||
a11930ba | 2498 | iotype = (bt) GFC_DESCRIPTOR_TYPE (desc); |
f622221a | 2499 | size = iotype == BT_CHARACTER ? (index_type) charlen : GFC_DESCRIPTOR_SIZE (desc); |
18623fae | 2500 | |
18623fae | 2501 | rank = GFC_DESCRIPTOR_RANK (desc); |
7fb43006 | 2502 | |
18623fae JB |
2503 | for (n = 0; n < rank; n++) |
2504 | { | |
2505 | count[n] = 0; | |
dfb55fdc TK |
2506 | stride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(desc,n); |
2507 | extent[n] = GFC_DESCRIPTOR_EXTENT(desc,n); | |
18623fae JB |
2508 | |
2509 | /* If the extent of even one dimension is zero, then the entire | |
4152bc26 JD |
2510 | array section contains zero elements, so we return after writing |
2511 | a zero array record. */ | |
87cd572d | 2512 | if (extent[n] <= 0) |
4152bc26 JD |
2513 | { |
2514 | data = NULL; | |
2515 | tsize = 0; | |
2516 | dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize); | |
2517 | return; | |
2518 | } | |
18623fae JB |
2519 | } |
2520 | ||
2521 | stride0 = stride[0]; | |
2522 | ||
dfb55fdc | 2523 | /* If the innermost dimension has a stride of 1, we can do the transfer |
18623fae | 2524 | in contiguous chunks. */ |
dfb55fdc | 2525 | if (stride0 == size) |
18623fae JB |
2526 | tsize = extent[0]; |
2527 | else | |
2528 | tsize = 1; | |
2529 | ||
2530 | data = GFC_DESCRIPTOR_DATA (desc); | |
2531 | ||
2532 | while (data) | |
2533 | { | |
5e805e44 | 2534 | dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize); |
dfb55fdc | 2535 | data += stride0 * tsize; |
18623fae JB |
2536 | count[0] += tsize; |
2537 | n = 0; | |
2538 | while (count[n] == extent[n]) | |
2539 | { | |
2540 | count[n] = 0; | |
dfb55fdc | 2541 | data -= stride[n] * extent[n]; |
18623fae JB |
2542 | n++; |
2543 | if (n == rank) | |
2544 | { | |
2545 | data = NULL; | |
2546 | break; | |
2547 | } | |
2548 | else | |
2549 | { | |
2550 | count[n]++; | |
dfb55fdc | 2551 | data += stride[n]; |
18623fae JB |
2552 | } |
2553 | } | |
2554 | } | |
6de9cd9a DN |
2555 | } |
2556 | ||
2b4c9065 NK |
2557 | void |
2558 | transfer_array (st_parameter_dt *dtp, gfc_array_char *desc, int kind, | |
2559 | gfc_charlen_type charlen) | |
2560 | { | |
2561 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) | |
2562 | return; | |
2563 | ||
2564 | if (dtp->u.p.current_unit && dtp->u.p.current_unit->au) | |
2565 | { | |
2566 | if (dtp->u.p.async) | |
2567 | { | |
2568 | transfer_args args; | |
2569 | size_t sz = sizeof (gfc_array_char) | |
2570 | + sizeof (descriptor_dimension) | |
2571 | * GFC_DESCRIPTOR_RANK (desc); | |
2572 | args.array.desc = xmalloc (sz); | |
2573 | NOTE ("desc = %p", (void *) args.array.desc); | |
2574 | memcpy (args.array.desc, desc, sz); | |
2575 | args.array.kind = kind; | |
2576 | args.array.charlen = charlen; | |
2577 | enqueue_transfer (dtp->u.p.current_unit->au, &args, | |
2578 | AIO_TRANSFER_ARRAY); | |
2579 | return; | |
2580 | } | |
2581 | } | |
2582 | /* Come here if there was no asynchronous I/O to be scheduled. */ | |
2583 | transfer_array_inner (dtp, desc, kind, charlen); | |
2584 | } | |
2585 | ||
2586 | ||
6eb6875d TK |
2587 | void |
2588 | transfer_array_write (st_parameter_dt *dtp, gfc_array_char *desc, int kind, | |
2589 | gfc_charlen_type charlen) | |
2590 | { | |
2591 | transfer_array (dtp, desc, kind, charlen); | |
2592 | } | |
6de9cd9a | 2593 | |
e73d3ca6 PT |
2594 | |
2595 | /* User defined input/output iomsg. */ | |
2596 | ||
2597 | #define IOMSG_LEN 256 | |
2598 | ||
2599 | void | |
2600 | transfer_derived (st_parameter_dt *parent, void *dtio_source, void *dtio_proc) | |
2601 | { | |
2602 | if (parent->u.p.current_unit) | |
2603 | { | |
2604 | if (parent->u.p.current_unit->flags.form == FORM_UNFORMATTED) | |
2605 | parent->u.p.ufdtio_ptr = (unformatted_dtio) dtio_proc; | |
2606 | else | |
2607 | parent->u.p.fdtio_ptr = (formatted_dtio) dtio_proc; | |
2608 | } | |
2b4c9065 | 2609 | wrap_scalar_transfer (parent, BT_CLASS, dtio_source, 0, 0, 1); |
e73d3ca6 PT |
2610 | } |
2611 | ||
2612 | ||
7fcb1804 | 2613 | /* Preposition a sequential unformatted file while reading. */ |
6de9cd9a DN |
2614 | |
2615 | static void | |
07b3bbf2 | 2616 | us_read (st_parameter_dt *dtp, int continued) |
6de9cd9a | 2617 | { |
7812c78c | 2618 | ssize_t n, nr; |
d67ab5ee TK |
2619 | GFC_INTEGER_4 i4; |
2620 | GFC_INTEGER_8 i8; | |
08656747 | 2621 | gfc_offset i; |
6de9cd9a | 2622 | |
d67ab5ee | 2623 | if (compile_options.record_marker == 0) |
07b3bbf2 | 2624 | n = sizeof (GFC_INTEGER_4); |
d67ab5ee TK |
2625 | else |
2626 | n = compile_options.record_marker; | |
2627 | ||
7812c78c JD |
2628 | nr = sread (dtp->u.p.current_unit->s, &i, n); |
2629 | if (unlikely (nr < 0)) | |
15877a88 JB |
2630 | { |
2631 | generate_error (&dtp->common, LIBERROR_BAD_US, NULL); | |
2632 | return; | |
2633 | } | |
7812c78c | 2634 | else if (nr == 0) |
7b7034ea | 2635 | { |
7812c78c | 2636 | hit_eof (dtp); |
7b7034ea JD |
2637 | return; /* end of file */ |
2638 | } | |
7812c78c | 2639 | else if (unlikely (n != nr)) |
6de9cd9a | 2640 | { |
d74b97cc | 2641 | generate_error (&dtp->common, LIBERROR_BAD_US, NULL); |
6de9cd9a DN |
2642 | return; |
2643 | } | |
2644 | ||
d74b97cc | 2645 | /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here. */ |
afab92d8 | 2646 | if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE)) |
d67ab5ee | 2647 | { |
07b3bbf2 | 2648 | switch (nr) |
d67ab5ee | 2649 | { |
d67ab5ee | 2650 | case sizeof(GFC_INTEGER_4): |
15877a88 | 2651 | memcpy (&i4, &i, sizeof (i4)); |
d67ab5ee TK |
2652 | i = i4; |
2653 | break; | |
2654 | ||
2655 | case sizeof(GFC_INTEGER_8): | |
15877a88 | 2656 | memcpy (&i8, &i, sizeof (i8)); |
d67ab5ee TK |
2657 | i = i8; |
2658 | break; | |
2659 | ||
2660 | default: | |
2661 | runtime_error ("Illegal value for record marker"); | |
2662 | break; | |
2663 | } | |
2664 | } | |
181c9f4a | 2665 | else |
facb23dc JB |
2666 | { |
2667 | uint32_t u32; | |
2668 | uint64_t u64; | |
07b3bbf2 | 2669 | switch (nr) |
d67ab5ee | 2670 | { |
d67ab5ee | 2671 | case sizeof(GFC_INTEGER_4): |
facb23dc JB |
2672 | memcpy (&u32, &i, sizeof (u32)); |
2673 | u32 = __builtin_bswap32 (u32); | |
2674 | memcpy (&i4, &u32, sizeof (i4)); | |
d67ab5ee TK |
2675 | i = i4; |
2676 | break; | |
2677 | ||
2678 | case sizeof(GFC_INTEGER_8): | |
facb23dc JB |
2679 | memcpy (&u64, &i, sizeof (u64)); |
2680 | u64 = __builtin_bswap64 (u64); | |
2681 | memcpy (&i8, &u64, sizeof (i8)); | |
d67ab5ee TK |
2682 | i = i8; |
2683 | break; | |
2684 | ||
2685 | default: | |
2686 | runtime_error ("Illegal value for record marker"); | |
2687 | break; | |
2688 | } | |
facb23dc | 2689 | } |
d67ab5ee | 2690 | |
07b3bbf2 TK |
2691 | if (i >= 0) |
2692 | { | |
2693 | dtp->u.p.current_unit->bytes_left_subrecord = i; | |
2694 | dtp->u.p.current_unit->continued = 0; | |
2695 | } | |
2696 | else | |
2697 | { | |
2698 | dtp->u.p.current_unit->bytes_left_subrecord = -i; | |
2699 | dtp->u.p.current_unit->continued = 1; | |
2700 | } | |
2701 | ||
2702 | if (! continued) | |
2703 | dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; | |
6de9cd9a DN |
2704 | } |
2705 | ||
2706 | ||
7fcb1804 TS |
2707 | /* Preposition a sequential unformatted file while writing. This |
2708 | amount to writing a bogus length that will be filled in later. */ | |
6de9cd9a DN |
2709 | |
2710 | static void | |
07b3bbf2 | 2711 | us_write (st_parameter_dt *dtp, int continued) |
6de9cd9a | 2712 | { |
7812c78c | 2713 | ssize_t nbytes; |
82b8244c | 2714 | gfc_offset dummy; |
6de9cd9a | 2715 | |
82b8244c | 2716 | dummy = 0; |
d67ab5ee TK |
2717 | |
2718 | if (compile_options.record_marker == 0) | |
07b3bbf2 | 2719 | nbytes = sizeof (GFC_INTEGER_4); |
d67ab5ee TK |
2720 | else |
2721 | nbytes = compile_options.record_marker ; | |
6de9cd9a | 2722 | |
7812c78c | 2723 | if (swrite (dtp->u.p.current_unit->s, &dummy, nbytes) != nbytes) |
d74b97cc | 2724 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
6de9cd9a | 2725 | |
b0c6db58 | 2726 | /* For sequential unformatted, if RECL= was not specified in the OPEN |
07b3bbf2 TK |
2727 | we write until we have more bytes than can fit in the subrecord |
2728 | markers, then we write a new subrecord. */ | |
bf1df0a0 | 2729 | |
07b3bbf2 TK |
2730 | dtp->u.p.current_unit->bytes_left_subrecord = |
2731 | dtp->u.p.current_unit->recl_subrecord; | |
2732 | dtp->u.p.current_unit->continued = continued; | |
6de9cd9a DN |
2733 | } |
2734 | ||
2735 | ||
7fcb1804 TS |
2736 | /* Position to the next record prior to transfer. We are assumed to |
2737 | be before the next record. We also calculate the bytes in the next | |
2738 | record. */ | |
6de9cd9a DN |
2739 | |
2740 | static void | |
5e805e44 | 2741 | pre_position (st_parameter_dt *dtp) |
6de9cd9a | 2742 | { |
5e805e44 | 2743 | if (dtp->u.p.current_unit->current_record) |
7fcb1804 | 2744 | return; /* Already positioned. */ |
6de9cd9a | 2745 | |
5e805e44 | 2746 | switch (current_mode (dtp)) |
6de9cd9a | 2747 | { |
91b30ee5 JD |
2748 | case FORMATTED_STREAM: |
2749 | case UNFORMATTED_STREAM: | |
15877a88 JB |
2750 | /* There are no records with stream I/O. If the position was specified |
2751 | data_transfer_init has already positioned the file. If no position | |
2752 | was specified, we continue from where we last left off. I.e. | |
2753 | there is nothing to do here. */ | |
91b30ee5 | 2754 | break; |
e73d3ca6 | 2755 | |
6de9cd9a | 2756 | case UNFORMATTED_SEQUENTIAL: |
5e805e44 | 2757 | if (dtp->u.p.mode == READING) |
07b3bbf2 | 2758 | us_read (dtp, 0); |
6de9cd9a | 2759 | else |
07b3bbf2 | 2760 | us_write (dtp, 0); |
6de9cd9a DN |
2761 | |
2762 | break; | |
2763 | ||
2764 | case FORMATTED_SEQUENTIAL: | |
2765 | case FORMATTED_DIRECT: | |
2766 | case UNFORMATTED_DIRECT: | |
5e805e44 | 2767 | dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; |
6de9cd9a DN |
2768 | break; |
2769 | } | |
2770 | ||
5e805e44 | 2771 | dtp->u.p.current_unit->current_record = 1; |
6de9cd9a DN |
2772 | } |
2773 | ||
2774 | ||
7fcb1804 TS |
2775 | /* Initialize things for a data transfer. This code is common for |
2776 | both reading and writing. */ | |
6de9cd9a DN |
2777 | |
2778 | static void | |
5e805e44 | 2779 | data_transfer_init (st_parameter_dt *dtp, int read_flag) |
6de9cd9a | 2780 | { |
7fcb1804 | 2781 | unit_flags u_flags; /* Used for creating a unit if needed. */ |
5e805e44 JJ |
2782 | GFC_INTEGER_4 cf = dtp->common.flags; |
2783 | namelist_info *ionml; | |
2b4c9065 NK |
2784 | async_unit *au; |
2785 | ||
2786 | NOTE ("data_transfer_init"); | |
6de9cd9a | 2787 | |
5e805e44 | 2788 | ionml = ((cf & IOPARM_DT_IONML_SET) != 0) ? dtp->u.p.ionml : NULL; |
d7445152 | 2789 | |
e1456843 | 2790 | memset (&dtp->u.p, 0, sizeof (dtp->u.p)); |
d7445152 | 2791 | |
5e805e44 JJ |
2792 | dtp->u.p.ionml = ionml; |
2793 | dtp->u.p.mode = read_flag ? READING : WRITING; | |
c4508d0a | 2794 | dtp->u.p.namelist_mode = 0; |
0ef33d44 FR |
2795 | dtp->u.p.cc.len = 0; |
2796 | ||
cb13c288 JD |
2797 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) |
2798 | return; | |
2799 | ||
5e805e44 | 2800 | dtp->u.p.current_unit = get_unit (dtp, 1); |
e73d3ca6 | 2801 | |
c04d4ede JB |
2802 | if (dtp->u.p.current_unit == NULL) |
2803 | { | |
2804 | /* This means we tried to access an external unit < 0 without | |
2805 | having opened it first with NEWUNIT=. */ | |
2806 | generate_error (&dtp->common, LIBERROR_BAD_OPTION, | |
9937c1eb JB |
2807 | "Unit number is negative and unit was not already " |
2808 | "opened with OPEN(NEWUNIT=...)"); | |
c04d4ede JB |
2809 | return; |
2810 | } | |
2811 | else if (dtp->u.p.current_unit->s == NULL) | |
c0d16890 | 2812 | { /* Open the unit with some default flags. */ |
2b4c9065 NK |
2813 | st_parameter_open opp; |
2814 | unit_convert conv; | |
2815 | NOTE ("Open the unit with some default flags."); | |
c0d16890 JD |
2816 | memset (&u_flags, '\0', sizeof (u_flags)); |
2817 | u_flags.access = ACCESS_SEQUENTIAL; | |
2818 | u_flags.action = ACTION_READWRITE; | |
2819 | ||
2820 | /* Is it unformatted? */ | |
2821 | if (!(cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT | |
2822 | | IOPARM_DT_IONML_SET))) | |
2823 | u_flags.form = FORM_UNFORMATTED; | |
2824 | else | |
2825 | u_flags.form = FORM_UNSPECIFIED; | |
2826 | ||
2827 | u_flags.delim = DELIM_UNSPECIFIED; | |
2828 | u_flags.blank = BLANK_UNSPECIFIED; | |
2829 | u_flags.pad = PAD_UNSPECIFIED; | |
2830 | u_flags.decimal = DECIMAL_UNSPECIFIED; | |
2831 | u_flags.encoding = ENCODING_UNSPECIFIED; | |
2832 | u_flags.async = ASYNC_UNSPECIFIED; | |
2833 | u_flags.round = ROUND_UNSPECIFIED; | |
2834 | u_flags.sign = SIGN_UNSPECIFIED; | |
0ef33d44 FR |
2835 | u_flags.share = SHARE_UNSPECIFIED; |
2836 | u_flags.cc = CC_UNSPECIFIED; | |
2837 | u_flags.readonly = 0; | |
c0d16890 JD |
2838 | |
2839 | u_flags.status = STATUS_UNKNOWN; | |
2840 | ||
2841 | conv = get_unformatted_convert (dtp->common.unit); | |
2842 | ||
2843 | if (conv == GFC_CONVERT_NONE) | |
2844 | conv = compile_options.convert; | |
2845 | ||
c0d16890 JD |
2846 | switch (conv) |
2847 | { | |
d7445152 JD |
2848 | case GFC_CONVERT_NATIVE: |
2849 | case GFC_CONVERT_SWAP: | |
2850 | break; | |
e73d3ca6 | 2851 | |
d7445152 | 2852 | case GFC_CONVERT_BIG: |
5675291d | 2853 | conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP; |
d7445152 | 2854 | break; |
e73d3ca6 | 2855 | |
d7445152 | 2856 | case GFC_CONVERT_LITTLE: |
5675291d | 2857 | conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE; |
d7445152 | 2858 | break; |
e73d3ca6 | 2859 | |
d7445152 JD |
2860 | default: |
2861 | internal_error (&opp.common, "Illegal value for CONVERT"); | |
2862 | break; | |
c0d16890 | 2863 | } |
5068c625 | 2864 | |
c0d16890 | 2865 | u_flags.convert = conv; |
5068c625 | 2866 | |
c0d16890 JD |
2867 | opp.common = dtp->common; |
2868 | opp.common.flags &= IOPARM_COMMON_MASK; | |
2869 | dtp->u.p.current_unit = new_unit (&opp, dtp->u.p.current_unit, &u_flags); | |
2870 | dtp->common.flags &= ~IOPARM_COMMON_MASK; | |
2871 | dtp->common.flags |= (opp.common.flags & IOPARM_COMMON_MASK); | |
2872 | if (dtp->u.p.current_unit == NULL) | |
2873 | return; | |
2874 | } | |
6de9cd9a | 2875 | |
c680ada5 JD |
2876 | if (dtp->u.p.current_unit->child_dtio == 0) |
2877 | { | |
2878 | if ((cf & IOPARM_DT_HAS_SIZE) != 0) | |
2879 | { | |
2880 | dtp->u.p.current_unit->has_size = true; | |
2881 | /* Initialize the count. */ | |
2882 | dtp->u.p.current_unit->size_used = 0; | |
2883 | } | |
2884 | else | |
2885 | dtp->u.p.current_unit->has_size = false; | |
2886 | } | |
7b39e3c2 JD |
2887 | else if (dtp->u.p.current_unit->internal_unit_kind > 0) |
2888 | dtp->u.p.unit_is_internal = 1; | |
c680ada5 | 2889 | |
2b4c9065 NK |
2890 | if ((cf & IOPARM_DT_HAS_ASYNCHRONOUS) != 0) |
2891 | { | |
2892 | int f; | |
2893 | f = find_option (&dtp->common, dtp->asynchronous, dtp->asynchronous_len, | |
2894 | async_opt, "Bad ASYNCHRONOUS in data transfer " | |
2895 | "statement"); | |
2896 | if (f == ASYNC_YES && dtp->u.p.current_unit->flags.async != ASYNC_YES) | |
2897 | { | |
2898 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, | |
2899 | "ASYNCHRONOUS transfer without " | |
2900 | "ASYHCRONOUS='YES' in OPEN"); | |
2901 | return; | |
2902 | } | |
2903 | dtp->u.p.async = f == ASYNC_YES; | |
2904 | } | |
2905 | ||
2906 | au = dtp->u.p.current_unit->au; | |
2907 | if (au) | |
2908 | { | |
2909 | if (dtp->u.p.async) | |
2910 | { | |
2911 | /* If this is an asynchronous I/O statement, collect errors and | |
2912 | return if there are any. */ | |
2913 | if (collect_async_errors (&dtp->common, au)) | |
2914 | return; | |
2915 | } | |
2916 | else | |
2917 | { | |
2918 | /* Synchronous statement: Perform a wait operation for any pending | |
2919 | asynchronous I/O. This needs to be done before all other error | |
2920 | checks. See F2008, 9.6.4.1. */ | |
2921 | if (async_wait (&(dtp->common), au)) | |
2922 | return; | |
2923 | } | |
2924 | } | |
2925 | ||
7fcb1804 | 2926 | /* Check the action. */ |
6de9cd9a | 2927 | |
5e805e44 | 2928 | if (read_flag && dtp->u.p.current_unit->flags.action == ACTION_WRITE) |
e08e57d0 | 2929 | { |
d74b97cc | 2930 | generate_error (&dtp->common, LIBERROR_BAD_ACTION, |
e08e57d0 TK |
2931 | "Cannot read from file opened for WRITE"); |
2932 | return; | |
2933 | } | |
6de9cd9a | 2934 | |
5e805e44 | 2935 | if (!read_flag && dtp->u.p.current_unit->flags.action == ACTION_READ) |
e08e57d0 | 2936 | { |
d74b97cc | 2937 | generate_error (&dtp->common, LIBERROR_BAD_ACTION, |
e08e57d0 TK |
2938 | "Cannot write to file opened for READ"); |
2939 | return; | |
2940 | } | |
6de9cd9a | 2941 | |
5e805e44 JJ |
2942 | dtp->u.p.first_item = 1; |
2943 | ||
7fcb1804 | 2944 | /* Check the format. */ |
6de9cd9a | 2945 | |
5e805e44 JJ |
2946 | if ((cf & IOPARM_DT_HAS_FORMAT) != 0) |
2947 | parse_format (dtp); | |
6de9cd9a | 2948 | |
5e805e44 JJ |
2949 | if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED |
2950 | && (cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT)) | |
2951 | != 0) | |
e08e57d0 | 2952 | { |
d74b97cc | 2953 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
e08e57d0 TK |
2954 | "Format present for UNFORMATTED data transfer"); |
2955 | return; | |
2956 | } | |
6de9cd9a | 2957 | |
5e805e44 | 2958 | if ((cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0 && dtp->u.p.ionml != NULL) |
6de9cd9a | 2959 | { |
5e805e44 | 2960 | if ((cf & IOPARM_DT_HAS_FORMAT) != 0) |
1ede59e4 JD |
2961 | { |
2962 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, | |
2963 | "A format cannot be specified with a namelist"); | |
2964 | return; | |
2965 | } | |
6de9cd9a | 2966 | } |
5e805e44 JJ |
2967 | else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED && |
2968 | !(cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT))) | |
e08e57d0 | 2969 | { |
d74b97cc | 2970 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
e08e57d0 | 2971 | "Missing format for FORMATTED data transfer"); |
1ede59e4 | 2972 | return; |
e08e57d0 | 2973 | } |
6de9cd9a | 2974 | |
5e805e44 JJ |
2975 | if (is_internal_unit (dtp) |
2976 | && dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED) | |
e08e57d0 | 2977 | { |
d74b97cc | 2978 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
e08e57d0 TK |
2979 | "Internal file cannot be accessed by UNFORMATTED " |
2980 | "data transfer"); | |
2981 | return; | |
2982 | } | |
6de9cd9a | 2983 | |
7812c78c | 2984 | /* Check the record or position number. */ |
6de9cd9a | 2985 | |
5e805e44 JJ |
2986 | if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT |
2987 | && (cf & IOPARM_DT_HAS_REC) == 0) | |
6de9cd9a | 2988 | { |
d74b97cc | 2989 | generate_error (&dtp->common, LIBERROR_MISSING_OPTION, |
6de9cd9a DN |
2990 | "Direct access data transfer requires record number"); |
2991 | return; | |
2992 | } | |
2993 | ||
b9983d61 | 2994 | if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL) |
6de9cd9a | 2995 | { |
b9983d61 JD |
2996 | if ((cf & IOPARM_DT_HAS_REC) != 0) |
2997 | { | |
2998 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, | |
2999 | "Record number not allowed for sequential access " | |
3000 | "data transfer"); | |
3001 | return; | |
3002 | } | |
6de9cd9a | 3003 | |
4bfbd309 JD |
3004 | if (compile_options.warn_std && |
3005 | dtp->u.p.current_unit->endfile == AFTER_ENDFILE) | |
b9983d61 JD |
3006 | { |
3007 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, | |
3008 | "Sequential READ or WRITE not allowed after " | |
3009 | "EOF marker, possibly use REWIND or BACKSPACE"); | |
3010 | return; | |
3011 | } | |
b9983d61 | 3012 | } |
c08de9db | 3013 | |
7fcb1804 | 3014 | /* Process the ADVANCE option. */ |
6de9cd9a | 3015 | |
5e805e44 JJ |
3016 | dtp->u.p.advance_status |
3017 | = !(cf & IOPARM_DT_HAS_ADVANCE) ? ADVANCE_UNSPECIFIED : | |
3018 | find_option (&dtp->common, dtp->advance, dtp->advance_len, advance_opt, | |
3019 | "Bad ADVANCE parameter in data transfer statement"); | |
6de9cd9a | 3020 | |
5e805e44 | 3021 | if (dtp->u.p.advance_status != ADVANCE_UNSPECIFIED) |
6de9cd9a | 3022 | { |
5e805e44 | 3023 | if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT) |
e08e57d0 | 3024 | { |
d74b97cc | 3025 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
d7445152 JD |
3026 | "ADVANCE specification conflicts with sequential " |
3027 | "access"); | |
e08e57d0 TK |
3028 | return; |
3029 | } | |
6de9cd9a | 3030 | |
5e805e44 | 3031 | if (is_internal_unit (dtp)) |
e08e57d0 | 3032 | { |
d74b97cc | 3033 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
e08e57d0 TK |
3034 | "ADVANCE specification conflicts with internal file"); |
3035 | return; | |
3036 | } | |
6de9cd9a | 3037 | |
5e805e44 JJ |
3038 | if ((cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT)) |
3039 | != IOPARM_DT_HAS_FORMAT) | |
e08e57d0 | 3040 | { |
d74b97cc | 3041 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
e08e57d0 TK |
3042 | "ADVANCE specification requires an explicit format"); |
3043 | return; | |
3044 | } | |
6de9cd9a DN |
3045 | } |
3046 | ||
1f10d710 JD |
3047 | /* Child IO is non-advancing and any ADVANCE= specifier is ignored. |
3048 | F2008 9.6.2.4 */ | |
3049 | if (dtp->u.p.current_unit->child_dtio > 0) | |
3050 | dtp->u.p.advance_status = ADVANCE_NO; | |
3051 | ||
6de9cd9a DN |
3052 | if (read_flag) |
3053 | { | |
108bc190 TK |
3054 | dtp->u.p.current_unit->previous_nonadvancing_write = 0; |
3055 | ||
5e805e44 | 3056 | if ((cf & IOPARM_EOR) != 0 && dtp->u.p.advance_status != ADVANCE_NO) |
e08e57d0 | 3057 | { |
d74b97cc | 3058 | generate_error (&dtp->common, LIBERROR_MISSING_OPTION, |
e08e57d0 TK |
3059 | "EOR specification requires an ADVANCE specification " |
3060 | "of NO"); | |
3061 | return; | |
3062 | } | |
6de9cd9a | 3063 | |
e73d3ca6 | 3064 | if ((cf & IOPARM_DT_HAS_SIZE) != 0 |
d7445152 | 3065 | && dtp->u.p.advance_status != ADVANCE_NO) |
e08e57d0 | 3066 | { |
d74b97cc | 3067 | generate_error (&dtp->common, LIBERROR_MISSING_OPTION, |
d7445152 JD |
3068 | "SIZE specification requires an ADVANCE " |
3069 | "specification of NO"); | |
e08e57d0 TK |
3070 | return; |
3071 | } | |
6de9cd9a DN |
3072 | } |
3073 | else | |
7fcb1804 | 3074 | { /* Write constraints. */ |
5e805e44 | 3075 | if ((cf & IOPARM_END) != 0) |
e08e57d0 | 3076 | { |
d74b97cc | 3077 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
d7445152 JD |
3078 | "END specification cannot appear in a write " |
3079 | "statement"); | |
e08e57d0 TK |
3080 | return; |
3081 | } | |
6de9cd9a | 3082 | |
5e805e44 | 3083 | if ((cf & IOPARM_EOR) != 0) |
e08e57d0 | 3084 | { |
d74b97cc | 3085 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
d7445152 JD |
3086 | "EOR specification cannot appear in a write " |
3087 | "statement"); | |
e08e57d0 TK |
3088 | return; |
3089 | } | |
6de9cd9a | 3090 | |
5e805e44 | 3091 | if ((cf & IOPARM_DT_HAS_SIZE) != 0) |
e08e57d0 | 3092 | { |
d74b97cc | 3093 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, |
d7445152 JD |
3094 | "SIZE specification cannot appear in a write " |
3095 | "statement"); | |
e08e57d0 TK |
3096 | return; |
3097 | } | |
6de9cd9a DN |
3098 | } |
3099 | ||
5e805e44 JJ |
3100 | if (dtp->u.p.advance_status == ADVANCE_UNSPECIFIED) |
3101 | dtp->u.p.advance_status = ADVANCE_YES; | |
6de9cd9a | 3102 | |
105b7136 JD |
3103 | /* Check the decimal mode. */ |
3104 | dtp->u.p.current_unit->decimal_status | |
d7445152 | 3105 | = !(cf & IOPARM_DT_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED : |
e1456843 | 3106 | find_option (&dtp->common, dtp->decimal, dtp->decimal_len, |
d7445152 JD |
3107 | decimal_opt, "Bad DECIMAL parameter in data transfer " |
3108 | "statement"); | |
3109 | ||
105b7136 JD |
3110 | if (dtp->u.p.current_unit->decimal_status == DECIMAL_UNSPECIFIED) |
3111 | dtp->u.p.current_unit->decimal_status = dtp->u.p.current_unit->flags.decimal; | |
d7445152 | 3112 | |
379924dd JD |
3113 | /* Check the round mode. */ |
3114 | dtp->u.p.current_unit->round_status | |
3115 | = !(cf & IOPARM_DT_HAS_ROUND) ? ROUND_UNSPECIFIED : | |
3116 | find_option (&dtp->common, dtp->round, dtp->round_len, | |
3117 | round_opt, "Bad ROUND parameter in data transfer " | |
3118 | "statement"); | |
3119 | ||
3120 | if (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED) | |
3121 | dtp->u.p.current_unit->round_status = dtp->u.p.current_unit->flags.round; | |
3122 | ||
105b7136 JD |
3123 | /* Check the sign mode. */ |
3124 | dtp->u.p.sign_status | |
d7445152 | 3125 | = !(cf & IOPARM_DT_HAS_SIGN) ? SIGN_UNSPECIFIED : |
e1456843 | 3126 | find_option (&dtp->common, dtp->sign, dtp->sign_len, sign_opt, |
d7445152 | 3127 | "Bad SIGN parameter in data transfer statement"); |
e73d3ca6 | 3128 | |
105b7136 | 3129 | if (dtp->u.p.sign_status == SIGN_UNSPECIFIED) |
d7445152 JD |
3130 | dtp->u.p.sign_status = dtp->u.p.current_unit->flags.sign; |
3131 | ||
105b7136 JD |
3132 | /* Check the blank mode. */ |
3133 | dtp->u.p.blank_status | |
d7445152 | 3134 | = !(cf & IOPARM_DT_HAS_BLANK) ? BLANK_UNSPECIFIED : |
e1456843 | 3135 | find_option (&dtp->common, dtp->blank, dtp->blank_len, |
d7445152 JD |
3136 | blank_opt, |
3137 | "Bad BLANK parameter in data transfer statement"); | |
e73d3ca6 | 3138 | |
105b7136 | 3139 | if (dtp->u.p.blank_status == BLANK_UNSPECIFIED) |
d7445152 | 3140 | dtp->u.p.blank_status = dtp->u.p.current_unit->flags.blank; |
264a5255 | 3141 | |
105b7136 JD |
3142 | /* Check the delim mode. */ |
3143 | dtp->u.p.current_unit->delim_status | |
d7445152 | 3144 | = !(cf & IOPARM_DT_HAS_DELIM) ? DELIM_UNSPECIFIED : |
e1456843 | 3145 | find_option (&dtp->common, dtp->delim, dtp->delim_len, |
105b7136 | 3146 | delim_opt, "Bad DELIM parameter in data transfer statement"); |
75b2dba9 | 3147 | |
105b7136 | 3148 | if (dtp->u.p.current_unit->delim_status == DELIM_UNSPECIFIED) |
75b2dba9 JD |
3149 | { |
3150 | if (ionml && dtp->u.p.current_unit->flags.delim == DELIM_UNSPECIFIED) | |
d520fea8 | 3151 | dtp->u.p.current_unit->delim_status = DELIM_QUOTE; |
75b2dba9 JD |
3152 | else |
3153 | dtp->u.p.current_unit->delim_status = dtp->u.p.current_unit->flags.delim; | |
3154 | } | |
d7445152 | 3155 | |
105b7136 JD |
3156 | /* Check the pad mode. */ |
3157 | dtp->u.p.current_unit->pad_status | |
d7445152 | 3158 | = !(cf & IOPARM_DT_HAS_PAD) ? PAD_UNSPECIFIED : |
e1456843 | 3159 | find_option (&dtp->common, dtp->pad, dtp->pad_len, pad_opt, |
d7445152 | 3160 | "Bad PAD parameter in data transfer statement"); |
75b2dba9 | 3161 | |
105b7136 JD |
3162 | if (dtp->u.p.current_unit->pad_status == PAD_UNSPECIFIED) |
3163 | dtp->u.p.current_unit->pad_status = dtp->u.p.current_unit->flags.pad; | |
7812c78c | 3164 | |
2b4c9065 NK |
3165 | /* Set up the subroutine that will handle the transfers. */ |
3166 | ||
3167 | if (read_flag) | |
3168 | { | |
3169 | if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED) | |
3170 | dtp->u.p.transfer = unformatted_read; | |
3171 | else | |
3172 | { | |
3173 | if ((cf & IOPARM_DT_LIST_FORMAT) != 0) | |
3174 | dtp->u.p.transfer = list_formatted_read; | |
3175 | else | |
3176 | dtp->u.p.transfer = formatted_transfer; | |
3177 | } | |
3178 | } | |
3179 | else | |
3180 | { | |
3181 | if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED) | |
3182 | dtp->u.p.transfer = unformatted_write; | |
3183 | else | |
3184 | { | |
3185 | if ((cf & IOPARM_DT_LIST_FORMAT) != 0) | |
3186 | dtp->u.p.transfer = list_formatted_write; | |
3187 | else | |
3188 | dtp->u.p.transfer = formatted_transfer; | |
3189 | } | |
3190 | } | |
3191 | ||
d0cbb206 | 3192 | if (au && dtp->u.p.async) |
2b4c9065 NK |
3193 | { |
3194 | NOTE ("enqueue_data_transfer"); | |
3195 | enqueue_data_transfer_init (au, dtp, read_flag); | |
3196 | } | |
3197 | else | |
3198 | { | |
3199 | NOTE ("invoking data_transfer_init_worker"); | |
3200 | data_transfer_init_worker (dtp, read_flag); | |
3201 | } | |
3202 | } | |
3203 | ||
3204 | void | |
3205 | data_transfer_init_worker (st_parameter_dt *dtp, int read_flag) | |
3206 | { | |
3207 | GFC_INTEGER_4 cf = dtp->common.flags; | |
3208 | ||
3209 | NOTE ("starting worker..."); | |
3210 | ||
3211 | if (read_flag && dtp->u.p.current_unit->flags.form != FORM_UNFORMATTED | |
3212 | && ((cf & IOPARM_DT_LIST_FORMAT) != 0) | |
3213 | && dtp->u.p.current_unit->child_dtio == 0) | |
3214 | dtp->u.p.current_unit->last_char = EOF - 1; | |
3215 | ||
7812c78c JD |
3216 | /* Check to see if we might be reading what we wrote before */ |
3217 | ||
3218 | if (dtp->u.p.mode != dtp->u.p.current_unit->mode | |
3219 | && !is_internal_unit (dtp)) | |
3220 | { | |
3221 | int pos = fbuf_reset (dtp->u.p.current_unit); | |
3222 | if (pos != 0) | |
3223 | sseek (dtp->u.p.current_unit->s, pos, SEEK_CUR); | |
3224 | sflush(dtp->u.p.current_unit->s); | |
3225 | } | |
3226 | ||
4c934d41 JD |
3227 | /* Check the POS= specifier: that it is in range and that it is used with a |
3228 | unit that has been connected for STREAM access. F2003 9.5.1.10. */ | |
e73d3ca6 | 3229 | |
4c934d41 JD |
3230 | if (((cf & IOPARM_DT_HAS_POS) != 0)) |
3231 | { | |
3232 | if (is_stream_io (dtp)) | |
7812c78c | 3233 | { |
e73d3ca6 | 3234 | |
7812c78c JD |
3235 | if (dtp->pos <= 0) |
3236 | { | |
3237 | generate_error (&dtp->common, LIBERROR_BAD_OPTION, | |
3238 | "POS=specifier must be positive"); | |
3239 | return; | |
3240 | } | |
e73d3ca6 | 3241 | |
7812c78c JD |
3242 | if (dtp->pos >= dtp->u.p.current_unit->maxrec) |
3243 | { | |
3244 | generate_error (&dtp->common, LIBERROR_BAD_OPTION, | |
3245 | "POS=specifier too large"); | |
3246 | return; | |
3247 | } | |
e73d3ca6 | 3248 | |
7812c78c | 3249 | dtp->rec = dtp->pos; |
e73d3ca6 | 3250 | |
7812c78c JD |
3251 | if (dtp->u.p.mode == READING) |
3252 | { | |
3253 | /* Reset the endfile flag; if we hit EOF during reading | |
3254 | we'll set the flag and generate an error at that point | |
3255 | rather than worrying about it here. */ | |
3256 | dtp->u.p.current_unit->endfile = NO_ENDFILE; | |
3257 | } | |
e73d3ca6 | 3258 | |
7812c78c JD |
3259 | if (dtp->pos != dtp->u.p.current_unit->strm_pos) |
3260 | { | |
3261 | fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode); | |
7812c78c JD |
3262 | if (sseek (dtp->u.p.current_unit->s, dtp->pos - 1, SEEK_SET) < 0) |
3263 | { | |
3264 | generate_error (&dtp->common, LIBERROR_OS, NULL); | |
3265 | return; | |
3266 | } | |
3267 | dtp->u.p.current_unit->strm_pos = dtp->pos; | |
3268 | } | |
3269 | } | |
4c934d41 | 3270 | else |
7812c78c JD |
3271 | { |
3272 | generate_error (&dtp->common, LIBERROR_BAD_OPTION, | |
3273 | "POS=specifier not allowed, " | |
3274 | "Try OPEN with ACCESS='stream'"); | |
3275 | return; | |
3276 | } | |
4c934d41 | 3277 | } |
e73d3ca6 | 3278 | |
d7445152 | 3279 | |
7fcb1804 | 3280 | /* Sanity checks on the record number. */ |
5e805e44 | 3281 | if ((cf & IOPARM_DT_HAS_REC) != 0) |
6de9cd9a | 3282 | { |
5e805e44 | 3283 | if (dtp->rec <= 0) |
6de9cd9a | 3284 | { |
d74b97cc | 3285 | generate_error (&dtp->common, LIBERROR_BAD_OPTION, |
5e805e44 | 3286 | "Record number must be positive"); |
6de9cd9a DN |
3287 | return; |
3288 | } | |
3289 | ||
5e805e44 | 3290 | if (dtp->rec >= dtp->u.p.current_unit->maxrec) |
6de9cd9a | 3291 | { |
d74b97cc | 3292 | generate_error (&dtp->common, LIBERROR_BAD_OPTION, |
5e805e44 | 3293 | "Record number too large"); |
6de9cd9a DN |
3294 | return; |
3295 | } | |
3296 | ||
7812c78c JD |
3297 | /* Make sure format buffer is reset. */ |
3298 | if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED) | |
3299 | fbuf_reset (dtp->u.p.current_unit); | |
55948b69 | 3300 | |
6de9cd9a | 3301 | |
0ef63495 TK |
3302 | /* Check whether the record exists to be read. Only |
3303 | a partial record needs to exist. */ | |
3304 | ||
35077d5a | 3305 | if (dtp->u.p.mode == READING && (dtp->rec - 1) |
3469bd86 | 3306 | * dtp->u.p.current_unit->recl >= ssize (dtp->u.p.current_unit->s)) |
0ef63495 | 3307 | { |
d74b97cc | 3308 | generate_error (&dtp->common, LIBERROR_BAD_OPTION, |
5e805e44 | 3309 | "Non-existing record number"); |
0ef63495 TK |
3310 | return; |
3311 | } | |
3312 | ||
55948b69 | 3313 | /* Position the file. */ |
4c934d41 | 3314 | if (sseek (dtp->u.p.current_unit->s, (gfc_offset) (dtp->rec - 1) |
e73d3ca6 PT |
3315 | * dtp->u.p.current_unit->recl, SEEK_SET) < 0) |
3316 | { | |
3317 | generate_error (&dtp->common, LIBERROR_OS, NULL); | |
3318 | return; | |
3319 | } | |
4c934d41 | 3320 | |
9f309df2 | 3321 | if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM) |
7812c78c JD |
3322 | { |
3323 | generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT, | |
3324 | "Record number not allowed for stream access " | |
3325 | "data transfer"); | |
3326 | return; | |
13926b24 | 3327 | } |
6de9cd9a DN |
3328 | } |
3329 | ||
159840cb | 3330 | /* Bugware for badly written mixed C-Fortran I/O. */ |
54d4b3bc JD |
3331 | if (!is_internal_unit (dtp)) |
3332 | flush_if_preconnected(dtp->u.p.current_unit->s); | |
159840cb | 3333 | |
5e805e44 | 3334 | dtp->u.p.current_unit->mode = dtp->u.p.mode; |
55948b69 | 3335 | |
beb6a65e JD |
3336 | /* Set the maximum position reached from the previous I/O operation. This |
3337 | could be greater than zero from a previous non-advancing write. */ | |
3338 | dtp->u.p.max_pos = dtp->u.p.current_unit->saved_pos; | |
6de9cd9a | 3339 | |
5e805e44 | 3340 | pre_position (dtp); |
e73d3ca6 | 3341 | |
7fcb1804 | 3342 | /* Make sure that we don't do a read after a nonadvancing write. */ |
6de9cd9a DN |
3343 | |
3344 | if (read_flag) | |
3345 | { | |
91b30ee5 | 3346 | if (dtp->u.p.current_unit->read_bad && !is_stream_io (dtp)) |
6de9cd9a | 3347 | { |
d74b97cc | 3348 | generate_error (&dtp->common, LIBERROR_BAD_OPTION, |
6de9cd9a DN |
3349 | "Cannot READ after a nonadvancing WRITE"); |
3350 | return; | |
3351 | } | |
3352 | } | |
3353 | else | |
3354 | { | |
5e805e44 JJ |
3355 | if (dtp->u.p.advance_status == ADVANCE_YES && !dtp->u.p.seen_dollar) |
3356 | dtp->u.p.current_unit->read_bad = 1; | |
6de9cd9a DN |
3357 | } |
3358 | ||
9cbecd06 JB |
3359 | if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED) |
3360 | { | |
3361 | #ifdef HAVE_USELOCALE | |
3362 | dtp->u.p.old_locale = uselocale (c_locale); | |
3363 | #else | |
3364 | __gthread_mutex_lock (&old_locale_lock); | |
3365 | if (!old_locale_ctr++) | |
3366 | { | |
3367 | old_locale = setlocale (LC_NUMERIC, NULL); | |
3368 | setlocale (LC_NUMERIC, "C"); | |
3369 | } | |
3370 | __gthread_mutex_unlock (&old_locale_lock); | |
3371 | #endif | |
3372 | /* Start the data transfer if we are doing a formatted transfer. */ | |
3373 | if ((cf & (IOPARM_DT_LIST_FORMAT | IOPARM_DT_HAS_NAMELIST_NAME)) == 0 | |
3374 | && dtp->u.p.ionml == NULL) | |
3375 | formatted_transfer (dtp, 0, NULL, 0, 0, 1); | |
3376 | } | |
6de9cd9a DN |
3377 | } |
3378 | ||
9cbecd06 | 3379 | |
965eec16 | 3380 | /* Initialize an array_loop_spec given the array descriptor. The function |
9370b3c0 TK |
3381 | returns the index of the last element of the array, and also returns |
3382 | starting record, where the first I/O goes to (necessary in case of | |
3383 | negative strides). */ | |
e73d3ca6 | 3384 | |
965eec16 | 3385 | gfc_offset |
9370b3c0 TK |
3386 | init_loop_spec (gfc_array_char *desc, array_loop_spec *ls, |
3387 | gfc_offset *start_record) | |
965eec16 JD |
3388 | { |
3389 | int rank = GFC_DESCRIPTOR_RANK(desc); | |
3390 | int i; | |
e73d3ca6 | 3391 | gfc_offset index; |
9370b3c0 | 3392 | int empty; |
965eec16 | 3393 | |
9370b3c0 | 3394 | empty = 0; |
965eec16 | 3395 | index = 1; |
9370b3c0 TK |
3396 | *start_record = 0; |
3397 | ||
965eec16 JD |
3398 | for (i=0; i<rank; i++) |
3399 | { | |
dfb55fdc TK |
3400 | ls[i].idx = GFC_DESCRIPTOR_LBOUND(desc,i); |
3401 | ls[i].start = GFC_DESCRIPTOR_LBOUND(desc,i); | |
3402 | ls[i].end = GFC_DESCRIPTOR_UBOUND(desc,i); | |
3403 | ls[i].step = GFC_DESCRIPTOR_STRIDE(desc,i); | |
e73d3ca6 | 3404 | empty = empty || (GFC_DESCRIPTOR_UBOUND(desc,i) |
dfb55fdc | 3405 | < GFC_DESCRIPTOR_LBOUND(desc,i)); |
9370b3c0 | 3406 | |
dfb55fdc | 3407 | if (GFC_DESCRIPTOR_STRIDE(desc,i) > 0) |
9370b3c0 | 3408 | { |
dfb55fdc TK |
3409 | index += (GFC_DESCRIPTOR_EXTENT(desc,i) - 1) |
3410 | * GFC_DESCRIPTOR_STRIDE(desc,i); | |
9370b3c0 TK |
3411 | } |
3412 | else | |
3413 | { | |
dfb55fdc TK |
3414 | index -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1) |
3415 | * GFC_DESCRIPTOR_STRIDE(desc,i); | |
3416 | *start_record -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1) | |
3417 | * GFC_DESCRIPTOR_STRIDE(desc,i); | |
9370b3c0 | 3418 | } |
965eec16 | 3419 | } |
9370b3c0 TK |
3420 | |
3421 | if (empty) | |
3422 | return 0; | |
3423 | else | |
3424 | return index; | |
965eec16 JD |
3425 | } |
3426 | ||
3427 | /* Determine the index to the next record in an internal unit array by | |
9370b3c0 | 3428 | by incrementing through the array_loop_spec. */ |
e73d3ca6 | 3429 | |
965eec16 | 3430 | gfc_offset |
9370b3c0 | 3431 | next_array_record (st_parameter_dt *dtp, array_loop_spec *ls, int *finished) |
965eec16 JD |
3432 | { |
3433 | int i, carry; | |
3434 | gfc_offset index; | |
e73d3ca6 | 3435 | |
965eec16 JD |
3436 | carry = 1; |
3437 | index = 0; | |
9370b3c0 | 3438 | |
5e805e44 | 3439 | for (i = 0; i < dtp->u.p.current_unit->rank; i++) |
965eec16 JD |
3440 | { |
3441 | if (carry) | |
3442 | { | |
3443 | ls[i].idx++; | |
3444 | if (ls[i].idx > ls[i].end) | |
3445 | { | |
3446 | ls[i].idx = ls[i].start; | |
3447 | carry = 1; | |
3448 | } | |
3449 | else | |
3450 | carry = 0; | |
3451 | } | |
d4feb3d3 | 3452 | index = index + (ls[i].idx - ls[i].start) * ls[i].step; |
965eec16 | 3453 | } |
d4feb3d3 | 3454 | |
9370b3c0 TK |
3455 | *finished = carry; |
3456 | ||
965eec16 JD |
3457 | return index; |
3458 | } | |
6de9cd9a | 3459 | |
07b3bbf2 TK |
3460 | |
3461 | ||
3462 | /* Skip to the end of the current record, taking care of an optional | |
3463 | record marker of size bytes. If the file is not seekable, we | |
3464 | read chunks of size MAX_READ until we get to the right | |
7fcb1804 | 3465 | position. */ |
6de9cd9a | 3466 | |
07b3bbf2 | 3467 | static void |
2563a16d | 3468 | skip_record (st_parameter_dt *dtp, gfc_offset bytes) |
07b3bbf2 | 3469 | { |
f9bfed22 | 3470 | ssize_t rlength, readb; |
581d2326 | 3471 | #define MAX_READ 4096 |
15877a88 | 3472 | char p[MAX_READ]; |
07b3bbf2 TK |
3473 | |
3474 | dtp->u.p.current_unit->bytes_left_subrecord += bytes; | |
3475 | if (dtp->u.p.current_unit->bytes_left_subrecord == 0) | |
3476 | return; | |
3477 | ||
7d5ee219 JB |
3478 | /* Direct access files do not generate END conditions, |
3479 | only I/O errors. */ | |
e73d3ca6 | 3480 | if (sseek (dtp->u.p.current_unit->s, |
7d5ee219 | 3481 | dtp->u.p.current_unit->bytes_left_subrecord, SEEK_CUR) < 0) |
07b3bbf2 | 3482 | { |
7d5ee219 | 3483 | /* Seeking failed, fall back to seeking by reading data. */ |
07b3bbf2 TK |
3484 | while (dtp->u.p.current_unit->bytes_left_subrecord > 0) |
3485 | { | |
e73d3ca6 | 3486 | rlength = |
f9bfed22 JB |
3487 | (MAX_READ < dtp->u.p.current_unit->bytes_left_subrecord) ? |
3488 | MAX_READ : dtp->u.p.current_unit->bytes_left_subrecord; | |
07b3bbf2 | 3489 | |
7812c78c JD |
3490 | readb = sread (dtp->u.p.current_unit->s, p, rlength); |
3491 | if (readb < 0) | |
07b3bbf2 | 3492 | { |
d74b97cc | 3493 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
07b3bbf2 TK |
3494 | return; |
3495 | } | |
3496 | ||
7812c78c | 3497 | dtp->u.p.current_unit->bytes_left_subrecord -= readb; |
07b3bbf2 | 3498 | } |
7d5ee219 | 3499 | return; |
07b3bbf2 | 3500 | } |
7d5ee219 | 3501 | dtp->u.p.current_unit->bytes_left_subrecord = 0; |
07b3bbf2 TK |
3502 | } |
3503 | ||
07b3bbf2 TK |
3504 | |
3505 | /* Advance to the next record reading unformatted files, taking | |
3506 | care of subrecords. If complete_record is nonzero, we loop | |
3507 | until all subrecords are cleared. */ | |
3508 | ||
3509 | static void | |
3510 | next_record_r_unf (st_parameter_dt *dtp, int complete_record) | |
3511 | { | |
3512 | size_t bytes; | |
3513 | ||
3514 | bytes = compile_options.record_marker == 0 ? | |
3515 | sizeof (GFC_INTEGER_4) : compile_options.record_marker; | |
3516 | ||
3517 | while(1) | |
3518 | { | |
3519 | ||
3520 | /* Skip over tail */ | |
3521 | ||
3522 | skip_record (dtp, bytes); | |
3523 | ||
3524 | if ( ! (complete_record && dtp->u.p.current_unit->continued)) | |
3525 | return; | |
3526 | ||
3527 | us_read (dtp, 1); | |
3528 | } | |
3529 | } | |
3530 | ||
15877a88 | 3531 | |
992b0aa1 | 3532 | static gfc_offset |
15877a88 JB |
3533 | min_off (gfc_offset a, gfc_offset b) |
3534 | { | |
3535 | return (a < b ? a : b); | |
3536 | } | |
3537 | ||
3538 | ||
07b3bbf2 TK |
3539 | /* Space to the next record for read mode. */ |
3540 | ||
6de9cd9a | 3541 | static void |
59011a60 | 3542 | next_record_r (st_parameter_dt *dtp, int done) |
6de9cd9a | 3543 | { |
07b3bbf2 | 3544 | gfc_offset record; |
15877a88 | 3545 | char p; |
7812c78c | 3546 | int cc; |
6de9cd9a | 3547 | |
5e805e44 | 3548 | switch (current_mode (dtp)) |
6de9cd9a | 3549 | { |
09861cbe | 3550 | /* No records in unformatted STREAM I/O. */ |
91b30ee5 JD |
3551 | case UNFORMATTED_STREAM: |
3552 | return; | |
e73d3ca6 | 3553 | |
6de9cd9a | 3554 | case UNFORMATTED_SEQUENTIAL: |
07b3bbf2 | 3555 | next_record_r_unf (dtp, 1); |
f4072316 | 3556 | dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; |
07b3bbf2 | 3557 | break; |
6de9cd9a DN |
3558 | |
3559 | case FORMATTED_DIRECT: | |
3560 | case UNFORMATTED_DIRECT: | |
0b4d979f | 3561 | skip_record (dtp, dtp->u.p.current_unit->bytes_left); |
6de9cd9a DN |
3562 | break; |
3563 | ||
09861cbe | 3564 | case FORMATTED_STREAM: |
6de9cd9a | 3565 | case FORMATTED_SEQUENTIAL: |
7812c78c JD |
3566 | /* read_sf has already terminated input because of an '\n', or |
3567 | we have hit EOF. */ | |
59011a60 | 3568 | if (dtp->u.p.sf_seen_eor) |
59afe4b4 | 3569 | { |
5e805e44 | 3570 | dtp->u.p.sf_seen_eor = 0; |
59afe4b4 TK |
3571 | break; |
3572 | } | |
6de9cd9a | 3573 | |
5e805e44 | 3574 | if (is_internal_unit (dtp)) |
59154ed2 | 3575 | { |
5e805e44 JJ |
3576 | if (is_array_io (dtp)) |
3577 | { | |
9370b3c0 TK |
3578 | int finished; |
3579 | ||
3580 | record = next_array_record (dtp, dtp->u.p.current_unit->ls, | |
3581 | &finished); | |
59011a60 JD |
3582 | if (!done && finished) |
3583 | hit_eof (dtp); | |
5e805e44 JJ |
3584 | |
3585 | /* Now seek to this record. */ | |
3586 | record = record * dtp->u.p.current_unit->recl; | |
7812c78c | 3587 | if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0) |
5e805e44 | 3588 | { |
d74b97cc | 3589 | generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL); |
5e805e44 JJ |
3590 | break; |
3591 | } | |
3592 | dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; | |
3593 | } | |
e73d3ca6 | 3594 | else |
5e805e44 | 3595 | { |
2563a16d | 3596 | gfc_offset bytes_left = dtp->u.p.current_unit->bytes_left; |
e73d3ca6 | 3597 | bytes_left = min_off (bytes_left, |
3469bd86 | 3598 | ssize (dtp->u.p.current_unit->s) |
7812c78c | 3599 | - stell (dtp->u.p.current_unit->s)); |
e73d3ca6 | 3600 | if (sseek (dtp->u.p.current_unit->s, |
7812c78c | 3601 | bytes_left, SEEK_CUR) < 0) |
15877a88 JB |
3602 | { |
3603 | generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL); | |
3604 | break; | |
3605 | } | |
3606 | dtp->u.p.current_unit->bytes_left | |
3607 | = dtp->u.p.current_unit->recl; | |
e73d3ca6 | 3608 | } |
5e805e44 | 3609 | break; |
59154ed2 | 3610 | } |
0ef33d44 | 3611 | else if (dtp->u.p.current_unit->flags.cc != CC_NONE) |
be0cc7e2 | 3612 | { |
7812c78c | 3613 | do |
be0cc7e2 | 3614 | { |
7812c78c JD |
3615 | errno = 0; |
3616 | cc = fbuf_getc (dtp->u.p.current_unit); | |
e73d3ca6 | 3617 | if (cc == EOF) |
7812c78c JD |
3618 | { |
3619 | if (errno != 0) | |
3620 | generate_error (&dtp->common, LIBERROR_OS, NULL); | |
6c1400dd JD |
3621 | else |
3622 | { | |
3623 | if (is_stream_io (dtp) | |
3624 | || dtp->u.p.current_unit->pad_status == PAD_NO | |
3625 | || dtp->u.p.current_unit->bytes_left | |
3626 | == dtp->u.p.current_unit->recl) | |
3627 | hit_eof (dtp); | |
3628 | } | |
7812c78c JD |
3629 | break; |
3630 | } | |
e73d3ca6 | 3631 | |
7812c78c JD |
3632 | if (is_stream_io (dtp)) |
3633 | dtp->u.p.current_unit->strm_pos++; | |
e73d3ca6 | 3634 | |
7812c78c | 3635 | p = (char) cc; |
f3ed1d02 | 3636 | } |
7812c78c | 3637 | while (p != '\n'); |
be0cc7e2 | 3638 | } |
6de9cd9a DN |
3639 | break; |
3640 | } | |
6de9cd9a DN |
3641 | } |
3642 | ||
3643 | ||
82b8244c | 3644 | /* Small utility function to write a record marker, taking care of |
d67ab5ee | 3645 | byte swapping and of choosing the correct size. */ |
82b8244c | 3646 | |
7812c78c | 3647 | static int |
82b8244c JB |
3648 | write_us_marker (st_parameter_dt *dtp, const gfc_offset buf) |
3649 | { | |
d67ab5ee TK |
3650 | size_t len; |
3651 | GFC_INTEGER_4 buf4; | |
3652 | GFC_INTEGER_8 buf8; | |
d67ab5ee TK |
3653 | |
3654 | if (compile_options.record_marker == 0) | |
07b3bbf2 | 3655 | len = sizeof (GFC_INTEGER_4); |
d67ab5ee TK |
3656 | else |
3657 | len = compile_options.record_marker; | |
3658 | ||
d74b97cc | 3659 | /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here. */ |
afab92d8 | 3660 | if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE)) |
d67ab5ee | 3661 | { |
07b3bbf2 | 3662 | switch (len) |
d67ab5ee | 3663 | { |
d67ab5ee TK |
3664 | case sizeof (GFC_INTEGER_4): |
3665 | buf4 = buf; | |
7812c78c | 3666 | return swrite (dtp->u.p.current_unit->s, &buf4, len); |
d67ab5ee TK |
3667 | break; |
3668 | ||
3669 | case sizeof (GFC_INTEGER_8): | |
3670 | buf8 = buf; | |
7812c78c | 3671 | return swrite (dtp->u.p.current_unit->s, &buf8, len); |
d67ab5ee TK |
3672 | break; |
3673 | ||
3674 | default: | |
3675 | runtime_error ("Illegal value for record marker"); | |
3676 | break; | |
3677 | } | |
3678 | } | |
3679 | else | |
3680 | { | |
facb23dc JB |
3681 | uint32_t u32; |
3682 | uint64_t u64; | |
07b3bbf2 | 3683 | switch (len) |
d67ab5ee | 3684 | { |
d67ab5ee TK |
3685 | case sizeof (GFC_INTEGER_4): |
3686 | buf4 = buf; | |
facb23dc JB |
3687 | memcpy (&u32, &buf4, sizeof (u32)); |
3688 | u32 = __builtin_bswap32 (u32); | |
3689 | return swrite (dtp->u.p.current_unit->s, &u32, len); | |
d67ab5ee TK |
3690 | break; |
3691 | ||
3692 | case sizeof (GFC_INTEGER_8): | |
3693 | buf8 = buf; | |
facb23dc JB |
3694 | memcpy (&u64, &buf8, sizeof (u64)); |
3695 | u64 = __builtin_bswap64 (u64); | |
3696 | return swrite (dtp->u.p.current_unit->s, &u64, len); | |
d67ab5ee TK |
3697 | break; |
3698 | ||
3699 | default: | |
3700 | runtime_error ("Illegal value for record marker"); | |
3701 | break; | |
3702 | } | |
3703 | } | |
3704 | ||
82b8244c JB |
3705 | } |
3706 | ||
07b3bbf2 TK |
3707 | /* Position to the next (sub)record in write mode for |
3708 | unformatted sequential files. */ | |
3709 | ||
3710 | static void | |
3711 | next_record_w_unf (st_parameter_dt *dtp, int next_subrecord) | |
3712 | { | |
f9bfed22 | 3713 | gfc_offset m, m_write, record_marker; |
07b3bbf2 TK |
3714 | |
3715 | /* Bytes written. */ | |
3716 | m = dtp->u.p.current_unit->recl_subrecord | |
3717 | - dtp->u.p.current_unit->bytes_left_subrecord; | |
07b3bbf2 | 3718 | |
07b3bbf2 TK |
3719 | if (compile_options.record_marker == 0) |
3720 | record_marker = sizeof (GFC_INTEGER_4); | |
3721 | else | |
3722 | record_marker = compile_options.record_marker; | |
3723 | ||
3724 | /* Seek to the head and overwrite the bogus length with the real | |
3725 | length. */ | |
3726 | ||
e73d3ca6 | 3727 | if (unlikely (sseek (dtp->u.p.current_unit->s, - m - record_marker, |
f9bfed22 | 3728 | SEEK_CUR) < 0)) |
07b3bbf2 TK |
3729 | goto io_error; |
3730 | ||
3731 | if (next_subrecord) | |
3732 | m_write = -m; | |
3733 | else | |
3734 | m_write = m; | |
3735 | ||
7812c78c | 3736 | if (unlikely (write_us_marker (dtp, m_write) < 0)) |
07b3bbf2 TK |
3737 | goto io_error; |
3738 | ||
3739 | /* Seek past the end of the current record. */ | |
3740 | ||
c033f5ae JB |
3741 | if (unlikely (sseek (dtp->u.p.current_unit->s, m, SEEK_CUR) < 0)) |
3742 | goto io_error; | |
3743 | ||
3744 | /* Write the length tail. If we finish a record containing | |
3745 | subrecords, we write out the negative length. */ | |
3746 | ||
3747 | if (dtp->u.p.current_unit->continued) | |
3748 | m_write = -m; | |
3749 | else | |
3750 | m_write = m; | |
3751 | ||
3752 | if (unlikely (write_us_marker (dtp, m_write) < 0)) | |
07b3bbf2 TK |
3753 | goto io_error; |
3754 | ||
3755 | return; | |
3756 | ||
3757 | io_error: | |
d74b97cc | 3758 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
07b3bbf2 TK |
3759 | return; |
3760 | ||
3761 | } | |
82b8244c | 3762 | |
7812c78c JD |
3763 | |
3764 | /* Utility function like memset() but operating on streams. Return | |
3765 | value is same as for POSIX write(). */ | |
3766 | ||
2563a16d JB |
3767 | static gfc_offset |
3768 | sset (stream *s, int c, gfc_offset nbyte) | |
7812c78c | 3769 | { |
581d2326 | 3770 | #define WRITE_CHUNK 256 |
7812c78c | 3771 | char p[WRITE_CHUNK]; |
2563a16d JB |
3772 | gfc_offset bytes_left; |
3773 | ssize_t trans; | |
7812c78c JD |
3774 | |
3775 | if (nbyte < WRITE_CHUNK) | |
3776 | memset (p, c, nbyte); | |
3777 | else | |
3778 | memset (p, c, WRITE_CHUNK); | |
3779 | ||
3780 | bytes_left = nbyte; | |
3781 | while (bytes_left > 0) | |
3782 | { | |
3783 | trans = (bytes_left < WRITE_CHUNK) ? bytes_left : WRITE_CHUNK; | |
3784 | trans = swrite (s, p, trans); | |
93ab3a3d | 3785 | if (trans <= 0) |
7812c78c JD |
3786 | return trans; |
3787 | bytes_left -= trans; | |
3788 | } | |
e73d3ca6 | 3789 | |
7812c78c JD |
3790 | return nbyte - bytes_left; |
3791 | } | |
3792 | ||
746e6327 | 3793 | |
0ef33d44 FR |
3794 | /* Finish up a record according to the legacy carriagecontrol type, based |
3795 | on the first character in the record. */ | |
3796 | ||
3797 | static void | |
3798 | next_record_cc (st_parameter_dt *dtp) | |
3799 | { | |
3800 | /* Only valid with CARRIAGECONTROL=FORTRAN. */ | |
3801 | if (dtp->u.p.current_unit->flags.cc != CC_FORTRAN) | |
3802 | return; | |
3803 | ||
3804 | fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END); | |
3805 | if (dtp->u.p.cc.len > 0) | |
3806 | { | |
f29876bb | 3807 | char *p = fbuf_alloc (dtp->u.p.current_unit, dtp->u.p.cc.len); |
0ef33d44 FR |
3808 | if (!p) |
3809 | generate_error (&dtp->common, LIBERROR_OS, NULL); | |
3810 | ||
3811 | /* Output CR for the first character with default CC setting. */ | |
3812 | *(p++) = dtp->u.p.cc.u.end; | |
3813 | if (dtp->u.p.cc.len > 1) | |
3814 | *p = dtp->u.p.cc.u.end; | |
3815 | } | |
3816 | } | |
3817 | ||
7fcb1804 | 3818 | /* Position to the next record in write mode. */ |
6de9cd9a DN |
3819 | |
3820 | static void | |
494ef4c2 | 3821 | next_record_w (st_parameter_dt *dtp, int done) |
6de9cd9a | 3822 | { |
2563a16d | 3823 | gfc_offset max_pos_off; |
6de9cd9a | 3824 | |
94e2b58a | 3825 | /* Zero counters for X- and T-editing. */ |
2563a16d | 3826 | max_pos_off = dtp->u.p.max_pos; |
5e805e44 | 3827 | dtp->u.p.max_pos = dtp->u.p.skips = dtp->u.p.pending_spaces = 0; |
94e2b58a | 3828 | |
5e805e44 | 3829 | switch (current_mode (dtp)) |
6de9cd9a | 3830 | { |
09861cbe | 3831 | /* No records in unformatted STREAM I/O. */ |
91b30ee5 JD |
3832 | case UNFORMATTED_STREAM: |
3833 | return; | |
3834 | ||
6de9cd9a | 3835 | case FORMATTED_DIRECT: |
5e805e44 | 3836 | if (dtp->u.p.current_unit->bytes_left == 0) |
6de9cd9a DN |
3837 | break; |
3838 | ||
7812c78c JD |
3839 | fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END); |
3840 | fbuf_flush (dtp->u.p.current_unit, WRITING); | |
e73d3ca6 PT |
3841 | if (sset (dtp->u.p.current_unit->s, ' ', |
3842 | dtp->u.p.current_unit->bytes_left) | |
7812c78c | 3843 | != dtp->u.p.current_unit->bytes_left) |
6de9cd9a DN |
3844 | goto io_error; |
3845 | ||
0fa1b65c | 3846 | break; |
6de9cd9a | 3847 | |
0fa1b65c | 3848 | case UNFORMATTED_DIRECT: |
fc8bc175 JD |
3849 | if (dtp->u.p.current_unit->bytes_left > 0) |
3850 | { | |
2563a16d | 3851 | gfc_offset length = dtp->u.p.current_unit->bytes_left; |
7812c78c | 3852 | if (sset (dtp->u.p.current_unit->s, 0, length) != length) |
15877a88 | 3853 | goto io_error; |
fc8bc175 | 3854 | } |
6de9cd9a DN |
3855 | break; |
3856 | ||
3857 | case UNFORMATTED_SEQUENTIAL: | |
07b3bbf2 | 3858 | next_record_w_unf (dtp, 0); |
f4072316 | 3859 | dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; |
6de9cd9a DN |
3860 | break; |
3861 | ||
09861cbe | 3862 | case FORMATTED_STREAM: |
6de9cd9a | 3863 | case FORMATTED_SEQUENTIAL: |
59154ed2 | 3864 | |
5e805e44 | 3865 | if (is_internal_unit (dtp)) |
59154ed2 | 3866 | { |
746e6327 | 3867 | char *p; |
2563a16d | 3868 | /* Internal unit, so must fit in memory. */ |
4135a21f | 3869 | size_t length, m; |
ea99ec5b | 3870 | size_t max_pos = max_pos_off; |
5e805e44 | 3871 | if (is_array_io (dtp)) |
59154ed2 | 3872 | { |
9370b3c0 TK |
3873 | int finished; |
3874 | ||
2563a16d | 3875 | length = dtp->u.p.current_unit->bytes_left; |
e73d3ca6 | 3876 | |
494ef4c2 JD |
3877 | /* If the farthest position reached is greater than current |
3878 | position, adjust the position and set length to pad out | |
3879 | whats left. Otherwise just pad whats left. | |
3880 | (for character array unit) */ | |
3881 | m = dtp->u.p.current_unit->recl | |
3882 | - dtp->u.p.current_unit->bytes_left; | |
3883 | if (max_pos > m) | |
3884 | { | |
2563a16d | 3885 | length = (max_pos - m); |
e73d3ca6 | 3886 | if (sseek (dtp->u.p.current_unit->s, |
7812c78c | 3887 | length, SEEK_CUR) < 0) |
15877a88 JB |
3888 | { |
3889 | generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL); | |
3890 | return; | |
3891 | } | |
ea99ec5b | 3892 | length = ((size_t) dtp->u.p.current_unit->recl - max_pos); |
494ef4c2 JD |
3893 | } |
3894 | ||
746e6327 JD |
3895 | p = write_block (dtp, length); |
3896 | if (p == NULL) | |
3897 | return; | |
3898 | ||
3899 | if (unlikely (is_char4_unit (dtp))) | |
3900 | { | |
3901 | gfc_char4_t *p4 = (gfc_char4_t *) p; | |
3902 | memset4 (p4, ' ', length); | |
59154ed2 | 3903 | } |
746e6327 JD |
3904 | else |
3905 | memset (p, ' ', length); | |
5e805e44 JJ |
3906 | |
3907 | /* Now that the current record has been padded out, | |
4135a21f JB |
3908 | determine where the next record in the array is. |
3909 | Note that this can return a negative value, so it | |
3910 | needs to be assigned to a signed value. */ | |
3911 | gfc_offset record = next_array_record | |
3912 | (dtp, dtp->u.p.current_unit->ls, &finished); | |
9370b3c0 | 3913 | if (finished) |
397bc09a | 3914 | dtp->u.p.current_unit->endfile = AT_ENDFILE; |
e73d3ca6 | 3915 | |
5e805e44 | 3916 | /* Now seek to this record */ |
4135a21f | 3917 | record = record * dtp->u.p.current_unit->recl; |
5e805e44 | 3918 | |
7812c78c | 3919 | if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0) |
844234fb | 3920 | { |
d74b97cc | 3921 | generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL); |
844234fb JD |
3922 | return; |
3923 | } | |
5e805e44 JJ |
3924 | |
3925 | dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; | |
59154ed2 JD |
3926 | } |
3927 | else | |
3928 | { | |
3929 | length = 1; | |
494ef4c2 JD |
3930 | |
3931 | /* If this is the last call to next_record move to the farthest | |
3932 | position reached and set length to pad out the remainder | |
3933 | of the record. (for character scaler unit) */ | |
3934 | if (done) | |
3935 | { | |
3936 | m = dtp->u.p.current_unit->recl | |
3937 | - dtp->u.p.current_unit->bytes_left; | |
3938 | if (max_pos > m) | |
3939 | { | |
2563a16d | 3940 | length = max_pos - m; |
e73d3ca6 | 3941 | if (sseek (dtp->u.p.current_unit->s, |
7812c78c | 3942 | length, SEEK_CUR) < 0) |
15877a88 JB |
3943 | { |
3944 | generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL); | |
3945 | return; | |
3946 | } | |
ea99ec5b | 3947 | length = (size_t) dtp->u.p.current_unit->recl |
2563a16d | 3948 | - max_pos; |
494ef4c2 JD |
3949 | } |
3950 | else | |
2563a16d | 3951 | length = dtp->u.p.current_unit->bytes_left; |
494ef4c2 | 3952 | } |
746e6327 | 3953 | if (length > 0) |
494ef4c2 | 3954 | { |
746e6327 JD |
3955 | p = write_block (dtp, length); |
3956 | if (p == NULL) | |
3957 | return; | |
3958 | ||
3959 | if (unlikely (is_char4_unit (dtp))) | |
3960 | { | |
3961 | gfc_char4_t *p4 = (gfc_char4_t *) p; | |
3962 | memset4 (p4, (gfc_char4_t) ' ', length); | |
3963 | } | |
3964 | else | |
3965 | memset (p, ' ', length); | |
494ef4c2 | 3966 | } |
59154ed2 | 3967 | } |
494ef4c2 | 3968 | } |
0ef33d44 FR |
3969 | /* Handle legacy CARRIAGECONTROL line endings. */ |
3970 | else if (dtp->u.p.current_unit->flags.cc == CC_FORTRAN) | |
3971 | next_record_cc (dtp); | |
59154ed2 JD |
3972 | else |
3973 | { | |
0ef33d44 FR |
3974 | /* Skip newlines for CC=CC_NONE. */ |
3975 | const int len = (dtp->u.p.current_unit->flags.cc == CC_NONE) | |
3976 | ? 0 | |
3c127520 | 3977 | #ifdef HAVE_CRLF |
0ef33d44 | 3978 | : 2; |
3c127520 | 3979 | #else |
0ef33d44 | 3980 | : 1; |
9e544d73 | 3981 | #endif |
0ef33d44 FR |
3982 | fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END); |
3983 | if (dtp->u.p.current_unit->flags.cc != CC_NONE) | |
3984 | { | |
f29876bb | 3985 | char *p = fbuf_alloc (dtp->u.p.current_unit, len); |
0ef33d44 FR |
3986 | if (!p) |
3987 | goto io_error; | |
7812c78c | 3988 | #ifdef HAVE_CRLF |
0ef33d44 | 3989 | *(p++) = '\r'; |
7812c78c | 3990 | #endif |
0ef33d44 FR |
3991 | *p = '\n'; |
3992 | } | |
09861cbe | 3993 | if (is_stream_io (dtp)) |
e32883d1 JD |
3994 | { |
3995 | dtp->u.p.current_unit->strm_pos += len; | |
35077d5a | 3996 | if (dtp->u.p.current_unit->strm_pos |
3469bd86 | 3997 | < ssize (dtp->u.p.current_unit->s)) |
7812c78c JD |
3998 | unit_truncate (dtp->u.p.current_unit, |
3999 | dtp->u.p.current_unit->strm_pos - 1, | |
4000 | &dtp->common); | |
e32883d1 | 4001 | } |
be0cc7e2 | 4002 | } |
6de9cd9a | 4003 | |
6de9cd9a DN |
4004 | break; |
4005 | ||
4006 | io_error: | |
d74b97cc | 4007 | generate_error (&dtp->common, LIBERROR_OS, NULL); |
6de9cd9a DN |
4008 | break; |
4009 | } | |
4010 | } | |
4011 | ||
7fcb1804 TS |
4012 | /* Position to the next record, which means moving to the end of the |
4013 | current record. This can happen under several different | |
4014 | conditions. If the done flag is not set, we get ready to process | |
4015 | the next record. */ | |
6de9cd9a DN |
4016 | |
4017 | void | |
5e805e44 | 4018 | next_record (st_parameter_dt *dtp, int done) |
6de9cd9a | 4019 | { |
7fcb1804 | 4020 | gfc_offset fp; /* File position. */ |
6de9cd9a | 4021 | |
5e805e44 | 4022 | dtp->u.p.current_unit->read_bad = 0; |
6de9cd9a | 4023 | |
5e805e44 | 4024 | if (dtp->u.p.mode == READING) |
59011a60 | 4025 | next_record_r (dtp, done); |
6de9cd9a | 4026 | else |
494ef4c2 | 4027 | next_record_w (dtp, done); |
6de9cd9a | 4028 | |
b89f743d JD |
4029 | fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode); |
4030 | ||
09861cbe JD |
4031 | if (!is_stream_io (dtp)) |
4032 | { | |
08810e52 JB |
4033 | /* Since we have changed the position, set it to unspecified so |
4034 | that INQUIRE(POSITION=) knows it needs to look into it. */ | |
16d962d9 | 4035 | if (done) |
08810e52 | 4036 | dtp->u.p.current_unit->flags.position = POSITION_UNSPECIFIED; |
16d962d9 | 4037 | |
09861cbe JD |
4038 | dtp->u.p.current_unit->current_record = 0; |
4039 | if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT) | |
4040 | { | |
7812c78c | 4041 | fp = stell (dtp->u.p.current_unit->s); |
09861cbe JD |
4042 | /* Calculate next record, rounding up partial records. */ |
4043 | dtp->u.p.current_unit->last_record = | |
b89f743d JD |
4044 | (fp + dtp->u.p.current_unit->recl) / |
4045 | dtp->u.p.current_unit->recl - 1; | |
09861cbe JD |
4046 | } |
4047 | else | |
4048 | dtp->u.p.current_unit->last_record++; | |
4049 | } | |
6de9cd9a DN |
4050 | |
4051 | if (!done) | |
5e805e44 | 4052 | pre_position (dtp); |
7812c78c | 4053 | |
89a862b4 | 4054 | smarkeor (dtp->u.p.current_unit->s); |
6de9cd9a DN |
4055 | } |
4056 | ||
4057 | ||
4058 | /* Finalize the current data transfer. For a nonadvancing transfer, | |
5615e8cd | 4059 | this means advancing to the next record. For internal units close the |
965eec16 | 4060 | stream associated with the unit. */ |
6de9cd9a DN |
4061 | |
4062 | static void | |
5e805e44 | 4063 | finalize_transfer (st_parameter_dt *dtp) |
6de9cd9a | 4064 | { |
5e805e44 | 4065 | GFC_INTEGER_4 cf = dtp->common.flags; |
59afe4b4 | 4066 | |
e73d3ca6 PT |
4067 | if ((dtp->u.p.ionml != NULL) |
4068 | && (cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0) | |
4069 | { | |
c4508d0a | 4070 | dtp->u.p.namelist_mode = 1; |
e73d3ca6 PT |
4071 | if ((cf & IOPARM_DT_NAMELIST_READ_MODE) != 0) |
4072 | namelist_read (dtp); | |
4073 | else | |
4074 | namelist_write (dtp); | |
4075 | } | |
4076 | ||
1f10d710 JD |
4077 | if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) |
4078 | *dtp->size = dtp->u.p.current_unit->size_used; | |
4079 | ||
4080 | if (dtp->u.p.eor_condition) | |
4081 | { | |
4082 | generate_error (&dtp->common, LIBERROR_EOR, NULL); | |
4083 | goto done; | |
4084 | } | |
4085 | ||
e73d3ca6 | 4086 | if (dtp->u.p.current_unit && (dtp->u.p.current_unit->child_dtio > 0)) |
bdff7e51 JD |
4087 | { |
4088 | if (cf & IOPARM_DT_HAS_FORMAT) | |
4089 | { | |
4090 | free (dtp->u.p.fmt); | |
4091 | free (dtp->format); | |
4092 | } | |
4093 | return; | |
4094 | } | |
e73d3ca6 | 4095 | |
5e805e44 | 4096 | if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK) |
217c4f53 JB |
4097 | { |
4098 | if (dtp->u.p.current_unit && current_mode (dtp) == UNFORMATTED_SEQUENTIAL) | |
4099 | dtp->u.p.current_unit->current_record = 0; | |
9cbecd06 | 4100 | goto done; |
217c4f53 | 4101 | } |
0e69bba9 | 4102 | |
5e805e44 JJ |
4103 | dtp->u.p.transfer = NULL; |
4104 | if (dtp->u.p.current_unit == NULL) | |
9cbecd06 | 4105 | goto done; |
6de9cd9a | 4106 | |
5e805e44 | 4107 | if ((cf & IOPARM_DT_LIST_FORMAT) != 0 && dtp->u.p.mode == READING) |
6de9cd9a | 4108 | { |
97cd182d | 4109 | finish_list_read (dtp); |
9cbecd06 | 4110 | goto done; |
6de9cd9a | 4111 | } |
97cd182d | 4112 | |
108bc190 TK |
4113 | if (dtp->u.p.mode == WRITING) |
4114 | dtp->u.p.current_unit->previous_nonadvancing_write | |
4115 | = dtp->u.p.advance_status == ADVANCE_NO; | |
4116 | ||
97cd182d | 4117 | if (is_stream_io (dtp)) |
09861cbe | 4118 | { |
108bc190 TK |
4119 | if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED |
4120 | && dtp->u.p.advance_status != ADVANCE_NO) | |
31de5c74 | 4121 | next_record (dtp, 1); |
2ea74407 | 4122 | |
9cbecd06 | 4123 | goto done; |
97cd182d JD |
4124 | } |
4125 | ||
4126 | dtp->u.p.current_unit->current_record = 0; | |
4127 | ||
97cd182d JD |
4128 | if (!is_internal_unit (dtp) && dtp->u.p.seen_dollar) |
4129 | { | |
7812c78c | 4130 | fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode); |
97cd182d | 4131 | dtp->u.p.seen_dollar = 0; |
9cbecd06 | 4132 | goto done; |
09861cbe | 4133 | } |
6de9cd9a | 4134 | |
beb6a65e JD |
4135 | /* For non-advancing I/O, save the current maximum position for use in the |
4136 | next I/O operation if needed. */ | |
54938c11 JD |
4137 | if (dtp->u.p.advance_status == ADVANCE_NO) |
4138 | { | |
6e9966e8 JD |
4139 | if (dtp->u.p.skips > 0) |
4140 | { | |
4141 | int tmp; | |
4142 | write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces); | |
4143 | tmp = (int)(dtp->u.p.current_unit->recl | |
4144 | - dtp->u.p.current_unit->bytes_left); | |
e73d3ca6 | 4145 | dtp->u.p.max_pos = |
6e9966e8 JD |
4146 | dtp->u.p.max_pos > tmp ? dtp->u.p.max_pos : tmp; |
4147 | dtp->u.p.skips = 0; | |
4148 | } | |
beb6a65e JD |
4149 | int bytes_written = (int) (dtp->u.p.current_unit->recl |
4150 | - dtp->u.p.current_unit->bytes_left); | |
4151 | dtp->u.p.current_unit->saved_pos = | |
4152 | dtp->u.p.max_pos > 0 ? dtp->u.p.max_pos - bytes_written : 0; | |
7812c78c | 4153 | fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode); |
9cbecd06 | 4154 | goto done; |
54938c11 | 4155 | } |
e73d3ca6 | 4156 | else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED |
7812c78c | 4157 | && dtp->u.p.mode == WRITING && !is_internal_unit (dtp)) |
e73d3ca6 | 4158 | fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END); |
54938c11 | 4159 | |
beb6a65e | 4160 | dtp->u.p.current_unit->saved_pos = 0; |
7f72e402 | 4161 | dtp->u.p.current_unit->last_char = EOF - 1; |
97cd182d | 4162 | next_record (dtp, 1); |
9cbecd06 JB |
4163 | |
4164 | done: | |
606778c6 JD |
4165 | |
4166 | if (dtp->u.p.unit_is_internal) | |
4167 | { | |
d5efbf3f JD |
4168 | /* The unit structure may be reused later so clear the |
4169 | internal unit kind. */ | |
4170 | dtp->u.p.current_unit->internal_unit_kind = 0; | |
4171 | ||
606778c6 JD |
4172 | fbuf_destroy (dtp->u.p.current_unit); |
4173 | if (dtp->u.p.current_unit | |
4174 | && (dtp->u.p.current_unit->child_dtio == 0) | |
4175 | && dtp->u.p.current_unit->s) | |
4176 | { | |
4177 | sclose (dtp->u.p.current_unit->s); | |
4178 | dtp->u.p.current_unit->s = NULL; | |
4179 | } | |
4180 | } | |
4181 | ||
9cbecd06 JB |
4182 | #ifdef HAVE_USELOCALE |
4183 | if (dtp->u.p.old_locale != (locale_t) 0) | |
4184 | { | |
4185 | uselocale (dtp->u.p.old_locale); | |
4186 | dtp->u.p.old_locale = (locale_t) 0; | |
4187 | } | |
4188 | #else | |
4189 | __gthread_mutex_lock (&old_locale_lock); | |
4190 | if (!--old_locale_ctr) | |
4191 | { | |
4192 | setlocale (LC_NUMERIC, old_locale); | |
4193 | old_locale = NULL; | |
4194 | } | |
4195 | __gthread_mutex_unlock (&old_locale_lock); | |
4196 | #endif | |
6de9cd9a DN |
4197 | } |
4198 | ||
8750f9cd JB |
4199 | /* Transfer function for IOLENGTH. It doesn't actually do any |
4200 | data transfer, it just updates the length counter. */ | |
4201 | ||
4202 | static void | |
e73d3ca6 | 4203 | iolength_transfer (st_parameter_dt *dtp, bt type __attribute__((unused)), |
e5ef4b3b | 4204 | void *dest __attribute__ ((unused)), |
e73d3ca6 | 4205 | int kind __attribute__((unused)), |
e5ef4b3b | 4206 | size_t size, size_t nelems) |
8750f9cd | 4207 | { |
5e805e44 | 4208 | if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0) |
f9bfed22 | 4209 | *dtp->iolength += (GFC_IO_INT) (size * nelems); |
8750f9cd JB |
4210 | } |
4211 | ||
4212 | ||
4213 | /* Initialize the IOLENGTH data transfer. This function is in essence | |
4214 | a very much simplified version of data_transfer_init(), because it | |
4215 | doesn't have to deal with units at all. */ | |
4216 | ||
4217 | static void | |
5e805e44 | 4218 | iolength_transfer_init (st_parameter_dt *dtp) |
8750f9cd | 4219 | { |
5e805e44 JJ |
4220 | if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0) |
4221 | *dtp->iolength = 0; | |
8750f9cd | 4222 | |
5e805e44 | 4223 | memset (&dtp->u.p, 0, sizeof (dtp->u.p)); |
8750f9cd JB |
4224 | |
4225 | /* Set up the subroutine that will handle the transfers. */ | |
4226 | ||
5e805e44 | 4227 | dtp->u.p.transfer = iolength_transfer; |
8750f9cd JB |
4228 | } |
4229 | ||
4230 | ||
4231 | /* Library entry point for the IOLENGTH form of the INQUIRE | |
4232 | statement. The IOLENGTH form requires no I/O to be performed, but | |
4233 | it must still be a runtime library call so that we can determine | |
4234 | the iolength for dynamic arrays and such. */ | |
4235 | ||
5e805e44 | 4236 | extern void st_iolength (st_parameter_dt *); |
7d7b8bfe RH |
4237 | export_proto(st_iolength); |
4238 | ||
8750f9cd | 4239 | void |
5e805e44 | 4240 | st_iolength (st_parameter_dt *dtp) |
8750f9cd | 4241 | { |
5e805e44 JJ |
4242 | library_start (&dtp->common); |
4243 | iolength_transfer_init (dtp); | |
8750f9cd JB |
4244 | } |
4245 | ||
5e805e44 | 4246 | extern void st_iolength_done (st_parameter_dt *); |
7d7b8bfe RH |
4247 | export_proto(st_iolength_done); |
4248 | ||
8750f9cd | 4249 | void |
5e805e44 | 4250 | st_iolength_done (st_parameter_dt *dtp __attribute__((unused))) |
8750f9cd | 4251 | { |
5e805e44 | 4252 | free_ionml (dtp); |
8750f9cd JB |
4253 | library_end (); |
4254 | } | |
4255 | ||
4256 | ||
7fcb1804 | 4257 | /* The READ statement. */ |
6de9cd9a | 4258 | |
5e805e44 | 4259 | extern void st_read (st_parameter_dt *); |
7d7b8bfe RH |
4260 | export_proto(st_read); |
4261 | ||
6de9cd9a | 4262 | void |
5e805e44 | 4263 | st_read (st_parameter_dt *dtp) |
6de9cd9a | 4264 | { |
5e805e44 | 4265 | library_start (&dtp->common); |
6de9cd9a | 4266 | |
5e805e44 | 4267 | data_transfer_init (dtp, 1); |
6de9cd9a DN |
4268 | } |
4269 | ||
5e805e44 | 4270 | extern void st_read_done (st_parameter_dt *); |
7d7b8bfe | 4271 | export_proto(st_read_done); |
6de9cd9a DN |
4272 | |
4273 | void | |
2b4c9065 | 4274 | st_read_done_worker (st_parameter_dt *dtp) |
6de9cd9a | 4275 | { |
5e805e44 | 4276 | finalize_transfer (dtp); |
e73d3ca6 | 4277 | |
5e805e44 | 4278 | free_ionml (dtp); |
241cbc7a | 4279 | |
4a8d4422 | 4280 | /* If this is a parent READ statement we do not need to retain the |
bf498b07 | 4281 | internal unit structure for child use. */ |
4a8d4422 JD |
4282 | if (dtp->u.p.current_unit != NULL |
4283 | && dtp->u.p.current_unit->child_dtio == 0) | |
4284 | { | |
7b39e3c2 | 4285 | if (dtp->u.p.unit_is_internal) |
8c098567 JD |
4286 | { |
4287 | if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0) | |
4288 | { | |
4289 | free (dtp->u.p.current_unit->filename); | |
4290 | dtp->u.p.current_unit->filename = NULL; | |
8c098567 JD |
4291 | if (dtp->u.p.current_unit->ls) |
4292 | free (dtp->u.p.current_unit->ls); | |
4293 | dtp->u.p.current_unit->ls = NULL; | |
4294 | } | |
4295 | newunit_free (dtp->common.unit); | |
4a8d4422 | 4296 | } |
7b39e3c2 | 4297 | if (dtp->u.p.unit_is_internal || dtp->u.p.format_not_saved) |
4a8d4422 JD |
4298 | { |
4299 | free_format_data (dtp->u.p.fmt); | |
4300 | free_format (dtp); | |
4301 | } | |
2b4c9065 NK |
4302 | } |
4303 | } | |
4304 | ||
4305 | void | |
4306 | st_read_done (st_parameter_dt *dtp) | |
4307 | { | |
4308 | if (dtp->u.p.current_unit) | |
4309 | { | |
4310 | if (dtp->u.p.current_unit->au) | |
4311 | { | |
4312 | if (dtp->common.flags & IOPARM_DT_HAS_ID) | |
4313 | *dtp->id = enqueue_done_id (dtp->u.p.current_unit->au, AIO_READ_DONE); | |
4314 | else | |
4315 | { | |
d0cbb206 TK |
4316 | if (dtp->u.p.async) |
4317 | enqueue_done (dtp->u.p.current_unit->au, AIO_READ_DONE); | |
2b4c9065 NK |
4318 | } |
4319 | } | |
4320 | else | |
4321 | st_read_done_worker (dtp); | |
4322 | ||
4a8d4422 JD |
4323 | unlock_unit (dtp->u.p.current_unit); |
4324 | } | |
e73d3ca6 | 4325 | |
6de9cd9a DN |
4326 | library_end (); |
4327 | } | |
4328 | ||
5e805e44 | 4329 | extern void st_write (st_parameter_dt *); |
2b4c9065 | 4330 | export_proto (st_write); |
6de9cd9a DN |
4331 | |
4332 | void | |
5e805e44 | 4333 | st_write (st_parameter_dt *dtp) |
6de9cd9a | 4334 | { |
5e805e44 JJ |
4335 | library_start (&dtp->common); |
4336 | data_transfer_init (dtp, 0); | |
6de9cd9a DN |
4337 | } |
4338 | ||
4339 | ||
4340 | void | |
2b4c9065 | 4341 | st_write_done_worker (st_parameter_dt *dtp) |
6de9cd9a | 4342 | { |
5e805e44 | 4343 | finalize_transfer (dtp); |
6de9cd9a | 4344 | |
e73d3ca6 | 4345 | if (dtp->u.p.current_unit != NULL |
e73d3ca6 | 4346 | && dtp->u.p.current_unit->child_dtio == 0) |
241cbc7a | 4347 | { |
4a8d4422 JD |
4348 | /* Deal with endfile conditions associated with sequential files. */ |
4349 | if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL) | |
4350 | switch (dtp->u.p.current_unit->endfile) | |
4351 | { | |
4352 | case AT_ENDFILE: /* Remain at the endfile record. */ | |
4353 | break; | |
241cbc7a | 4354 | |
4a8d4422 JD |
4355 | case AFTER_ENDFILE: |
4356 | dtp->u.p.current_unit->endfile = AT_ENDFILE; /* Just at it now. */ | |
4357 | break; | |
241cbc7a | 4358 | |
4a8d4422 JD |
4359 | case NO_ENDFILE: |
4360 | /* Get rid of whatever is after this record. */ | |
4361 | if (!is_internal_unit (dtp)) | |
4362 | unit_truncate (dtp->u.p.current_unit, | |
4363 | stell (dtp->u.p.current_unit->s), | |
4364 | &dtp->common); | |
4365 | dtp->u.p.current_unit->endfile = AT_ENDFILE; | |
4366 | break; | |
4367 | } | |
e73d3ca6 | 4368 | |
4a8d4422 | 4369 | free_ionml (dtp); |
54ffdb12 | 4370 | |
4a8d4422 | 4371 | /* If this is a parent WRITE statement we do not need to retain the |
bf498b07 | 4372 | internal unit structure for child use. */ |
7b39e3c2 | 4373 | if (dtp->u.p.unit_is_internal) |
4a8d4422 | 4374 | { |
8c098567 JD |
4375 | if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0) |
4376 | { | |
4377 | free (dtp->u.p.current_unit->filename); | |
4378 | dtp->u.p.current_unit->filename = NULL; | |
8c098567 JD |
4379 | if (dtp->u.p.current_unit->ls) |
4380 | free (dtp->u.p.current_unit->ls); | |
4381 | dtp->u.p.current_unit->ls = NULL; | |
4382 | } | |
4383 | newunit_free (dtp->common.unit); | |
4a8d4422 | 4384 | } |
7b39e3c2 | 4385 | if (dtp->u.p.unit_is_internal || dtp->u.p.format_not_saved) |
4a8d4422 JD |
4386 | { |
4387 | free_format_data (dtp->u.p.fmt); | |
4388 | free_format (dtp); | |
4389 | } | |
2b4c9065 NK |
4390 | } |
4391 | } | |
4392 | ||
4393 | extern void st_write_done (st_parameter_dt *); | |
4394 | export_proto(st_write_done); | |
4395 | ||
4396 | void | |
4397 | st_write_done (st_parameter_dt *dtp) | |
4398 | { | |
4399 | if (dtp->u.p.current_unit) | |
4400 | { | |
d0cbb206 | 4401 | if (dtp->u.p.current_unit->au && dtp->u.p.async) |
2b4c9065 NK |
4402 | { |
4403 | if (dtp->common.flags & IOPARM_DT_HAS_ID) | |
4404 | *dtp->id = enqueue_done_id (dtp->u.p.current_unit->au, | |
4405 | AIO_WRITE_DONE); | |
4406 | else | |
4407 | { | |
d0cbb206 TK |
4408 | /* We perform synchronous I/O on an asynchronous unit, so no need |
4409 | to enqueue AIO_READ_DONE. */ | |
4410 | if (dtp->u.p.async) | |
4411 | enqueue_done (dtp->u.p.current_unit->au, AIO_WRITE_DONE); | |
2b4c9065 NK |
4412 | } |
4413 | } | |
4414 | else | |
4415 | st_write_done_worker (dtp); | |
4416 | ||
4a8d4422 JD |
4417 | unlock_unit (dtp->u.p.current_unit); |
4418 | } | |
2b4c9065 | 4419 | |
6de9cd9a DN |
4420 | library_end (); |
4421 | } | |
4422 | ||
2b4c9065 NK |
4423 | /* Wait operation. We need to keep around the do-nothing version |
4424 | of st_wait for compatibility with previous versions, which had marked | |
4425 | the argument as unused (and thus liable to be removed). | |
4426 | ||
4427 | TODO: remove at next bump in version number. */ | |
10256cbe | 4428 | |
10256cbe JD |
4429 | void |
4430 | st_wait (st_parameter_wait *wtp __attribute__((unused))) | |
4431 | { | |
2b4c9065 NK |
4432 | return; |
4433 | } | |
4434 | ||
4435 | void | |
4436 | st_wait_async (st_parameter_wait *wtp) | |
4437 | { | |
4438 | gfc_unit *u = find_unit (wtp->common.unit); | |
4439 | if (ASYNC_IO && u->au) | |
4440 | { | |
4441 | if (wtp->common.flags & IOPARM_WAIT_HAS_ID) | |
4442 | async_wait_id (&(wtp->common), u->au, *wtp->id); | |
4443 | else | |
4444 | async_wait (&(wtp->common), u->au); | |
4445 | } | |
4446 | ||
4447 | unlock_unit (u); | |
10256cbe JD |
4448 | } |
4449 | ||
4450 | ||
29dc5138 PT |
4451 | /* Receives the scalar information for namelist objects and stores it |
4452 | in a linked list of namelist_info types. */ | |
6de9cd9a | 4453 | |
e73d3ca6 | 4454 | static void |
f29876bb | 4455 | set_nml_var (st_parameter_dt *dtp, void *var_addr, char *var_name, |
e73d3ca6 | 4456 | GFC_INTEGER_4 len, gfc_charlen_type string_length, |
7fb43006 | 4457 | dtype_type dtype, void *dtio_sub, void *vtable) |
6de9cd9a | 4458 | { |
29dc5138 PT |
4459 | namelist_info *t1 = NULL; |
4460 | namelist_info *nml; | |
88fdfd5a | 4461 | size_t var_name_len = strlen (var_name); |
29dc5138 | 4462 | |
1a0fd3d3 | 4463 | nml = (namelist_info*) xmalloc (sizeof (namelist_info)); |
29dc5138 | 4464 | |
6de9cd9a | 4465 | nml->mem_pos = var_addr; |
e73d3ca6 PT |
4466 | nml->dtio_sub = dtio_sub; |
4467 | nml->vtable = vtable; | |
29dc5138 | 4468 | |
1a0fd3d3 | 4469 | nml->var_name = (char*) xmalloc (var_name_len + 1); |
88fdfd5a JB |
4470 | memcpy (nml->var_name, var_name, var_name_len); |
4471 | nml->var_name[var_name_len] = '\0'; | |
29dc5138 PT |
4472 | |
4473 | nml->len = (int) len; | |
4474 | nml->string_length = (index_type) string_length; | |
4475 | ||
7fb43006 PT |
4476 | nml->var_rank = (int) (dtype.rank); |
4477 | nml->size = (index_type) (dtype.elem_len); | |
4478 | nml->type = (bt) (dtype.type); | |
29dc5138 PT |
4479 | |
4480 | if (nml->var_rank > 0) | |
3bc268e6 | 4481 | { |
29dc5138 | 4482 | nml->dim = (descriptor_dimension*) |
92e6f3a4 | 4483 | xmallocarray (nml->var_rank, sizeof (descriptor_dimension)); |
965eec16 | 4484 | nml->ls = (array_loop_spec*) |
92e6f3a4 | 4485 | xmallocarray (nml->var_rank, sizeof (array_loop_spec)); |
3bc268e6 VL |
4486 | } |
4487 | else | |
4488 | { | |
29dc5138 PT |
4489 | nml->dim = NULL; |
4490 | nml->ls = NULL; | |
3bc268e6 VL |
4491 | } |
4492 | ||
6de9cd9a DN |
4493 | nml->next = NULL; |
4494 | ||
5e805e44 JJ |
4495 | if ((dtp->common.flags & IOPARM_DT_IONML_SET) == 0) |
4496 | { | |
4497 | dtp->common.flags |= IOPARM_DT_IONML_SET; | |
4498 | dtp->u.p.ionml = nml; | |
4499 | } | |
6de9cd9a DN |
4500 | else |
4501 | { | |
5e805e44 | 4502 | for (t1 = dtp->u.p.ionml; t1->next; t1 = t1->next); |
29dc5138 | 4503 | t1->next = nml; |
6de9cd9a DN |
4504 | } |
4505 | } | |
4506 | ||
e73d3ca6 | 4507 | extern void st_set_nml_var (st_parameter_dt *dtp, void *, char *, |
7fb43006 | 4508 | GFC_INTEGER_4, gfc_charlen_type, dtype_type); |
e73d3ca6 PT |
4509 | export_proto(st_set_nml_var); |
4510 | ||
4511 | void | |
f29876bb | 4512 | st_set_nml_var (st_parameter_dt *dtp, void *var_addr, char *var_name, |
e73d3ca6 | 4513 | GFC_INTEGER_4 len, gfc_charlen_type string_length, |
7fb43006 | 4514 | dtype_type dtype) |
e73d3ca6 PT |
4515 | { |
4516 | set_nml_var (dtp, var_addr, var_name, len, string_length, | |
4517 | dtype, NULL, NULL); | |
4518 | } | |
4519 | ||
4520 | ||
4521 | /* Essentially the same as previous but carrying the dtio procedure | |
4522 | and the vtable as additional arguments. */ | |
4523 | extern void st_set_nml_dtio_var (st_parameter_dt *dtp, void *, char *, | |
7fb43006 | 4524 | GFC_INTEGER_4, gfc_charlen_type, dtype_type, |
e73d3ca6 PT |
4525 | void *, void *); |
4526 | export_proto(st_set_nml_dtio_var); | |
4527 | ||
4528 | ||
4529 | void | |
f29876bb | 4530 | st_set_nml_dtio_var (st_parameter_dt *dtp, void *var_addr, char *var_name, |
e73d3ca6 | 4531 | GFC_INTEGER_4 len, gfc_charlen_type string_length, |
7fb43006 | 4532 | dtype_type dtype, void *dtio_sub, void *vtable) |
e73d3ca6 PT |
4533 | { |
4534 | set_nml_var (dtp, var_addr, var_name, len, string_length, | |
4535 | dtype, dtio_sub, vtable); | |
4536 | } | |
4537 | ||
29dc5138 | 4538 | /* Store the dimensional information for the namelist object. */ |
5e805e44 | 4539 | extern void st_set_nml_var_dim (st_parameter_dt *, GFC_INTEGER_4, |
6520ecac JB |
4540 | index_type, index_type, |
4541 | index_type); | |
944e86ee | 4542 | export_proto(st_set_nml_var_dim); |
7d7b8bfe | 4543 | |
6de9cd9a | 4544 | void |
5e805e44 | 4545 | st_set_nml_var_dim (st_parameter_dt *dtp, GFC_INTEGER_4 n_dim, |
6520ecac JB |
4546 | index_type stride, index_type lbound, |
4547 | index_type ubound) | |
6de9cd9a | 4548 | { |
f29876bb | 4549 | namelist_info *nml; |
29dc5138 | 4550 | int n; |
6de9cd9a | 4551 | |
29dc5138 | 4552 | n = (int)n_dim; |
6de9cd9a | 4553 | |
5e805e44 | 4554 | for (nml = dtp->u.p.ionml; nml->next; nml = nml->next); |
6de9cd9a | 4555 | |
dfb55fdc | 4556 | GFC_DIMENSION_SET(nml->dim[n],lbound,ubound,stride); |
6de9cd9a | 4557 | } |
181c9f4a | 4558 | |
7812c78c JD |
4559 | |
4560 | /* Once upon a time, a poor innocent Fortran program was reading a | |
4561 | file, when suddenly it hit the end-of-file (EOF). Unfortunately | |
4562 | the OS doesn't tell whether we're at the EOF or whether we already | |
4563 | went past it. Luckily our hero, libgfortran, keeps track of this. | |
4564 | Call this function when you detect an EOF condition. See Section | |
4565 | 9.10.2 in F2003. */ | |
4566 | ||
4567 | void | |
f29876bb | 4568 | hit_eof (st_parameter_dt *dtp) |
7812c78c JD |
4569 | { |
4570 | dtp->u.p.current_unit->flags.position = POSITION_APPEND; | |
4571 | ||
4572 | if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL) | |
4573 | switch (dtp->u.p.current_unit->endfile) | |
4574 | { | |
4575 | case NO_ENDFILE: | |
4576 | case AT_ENDFILE: | |
4577 | generate_error (&dtp->common, LIBERROR_END, NULL); | |
83437e67 | 4578 | if (!is_internal_unit (dtp) && !dtp->u.p.namelist_mode) |
7812c78c JD |
4579 | { |
4580 | dtp->u.p.current_unit->endfile = AFTER_ENDFILE; | |
4581 | dtp->u.p.current_unit->current_record = 0; | |
4582 | } | |
4583 | else | |
4584 | dtp->u.p.current_unit->endfile = AT_ENDFILE; | |
4585 | break; | |
e73d3ca6 | 4586 | |
7812c78c JD |
4587 | case AFTER_ENDFILE: |
4588 | generate_error (&dtp->common, LIBERROR_ENDFILE, NULL); | |
4589 | dtp->u.p.current_unit->current_record = 0; | |
4590 | break; | |
4591 | } | |
4592 | else | |
4593 | { | |
4594 | /* Non-sequential files don't have an ENDFILE record, so we | |
4595 | can't be at AFTER_ENDFILE. */ | |
4596 | dtp->u.p.current_unit->endfile = AT_ENDFILE; | |
4597 | generate_error (&dtp->common, LIBERROR_END, NULL); | |
4598 | dtp->u.p.current_unit->current_record = 0; | |
4599 | } | |
4600 | } |