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