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