rts-io.c
1 //! @file rts-io.c
2 //! @author J. Marcel van der Veer
3 //
4 //! @section Copyright
5 //
6 // This file is part of VIF - vintage FORTRAN compiler.
7 // Copyright 2020-2025 J. Marcel van der Veer <algol68g@xs4all.nl>.
8 //
9 //! @section License
10 //
11 // This program is free software; you can redistribute it and/or modify it
12 // under the terms of the GNU General Public License as published by the
13 // Free Software Foundation; either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 // more details. You should have received a copy of the GNU General Public
20 // License along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 //! @section Synopsis
23 //!
24 //! Runtime support for Fortran IO.
25
26 #include <vif.h>
27
28 FTNFILE _ffile[MAX_FILES];
29
30 char *action_default = "action_default";
31 char *action_read = "action_read";
32 char *action_write = "action_write";
33 char *action_readwrite = "action_readwrite";
34 char *form_formatted = "form_formatted";
35 char *form_unformatted = "form_unformatted";
36 char *disp_new = "disp_new";
37 char *disp_old = "disp_old";
38 char *disp_delete = "disp_delete";
39 char *disp_keep = "disp_keep";
40
41 // Fortran IO
42
43 void _fcheck (char *where, int_4 unit, char *action, char *form)
44 {
45 FTNFILE *_f = &_ffile[unit];
46 NEW_RECORD (str);
47 __scale__ = 1;
48 if (unit < 0 || unit >= MAX_FILES) {
49 _srecordf (str, "unit number %d is not valid", unit);
50 RTE (where, str);
51 }
52 if (action == NO_TEXT) {
53 // CLOSE, REWIND
54 return;
55 }
56 if (_f->unit == NO_FILE) {
57 // File was not opened yet.
58 NEW_RECORD (mode);
59 NEW_RECORD (disp);
60 if (_f->disp != NO_TEXT) {
61 RECCPY (disp, _f->disp);
62 } else {
63 RECCPY (disp, disp_old);
64 }
65 if (_f->action == action_default) {
66 _f->action = action;
67 } else if (_f->action == action_readwrite) {
68 action = action_readwrite;
69 } else if (_f->action != action) {
70 _srecordf (str, "inconsistent action: %s", action);
71 RTE (where, str);
72 }
73 if (_f->form == NO_TEXT) {
74 _f->form = form;
75 } else if (_f->form != form) {
76 _srecordf (str, "inconsistent formatting: %s", form);
77 RTE (where, str);
78 }
79 RECCPY (mode, "UNKNOWN");
80 if (form == form_formatted && action == action_read) {
81 RECCPY (mode, "r");
82 } else if (form == form_formatted && action == action_write) {
83 RECCPY (mode, "w");
84 } else if (form == form_formatted && action == action_readwrite) {
85 if (EQUAL (disp, "disp_old")) {
86 RECCPY (mode, "r+");
87 } else if (EQUAL (disp, "disp_new")) {
88 RECCPY (mode, "w+");
89 }
90 } else if (form == form_unformatted && action == action_read) {
91 RECCPY (mode, "rb");
92 } else if (form == form_unformatted && action == action_write) {
93 RECCPY (mode, "wb");
94 } else if (form == form_unformatted && action == action_readwrite) {
95 if (EQUAL (disp, "disp_old")) {
96 RECCPY (mode, "r+b");
97 } else if (EQUAL (disp, "disp_new")) {
98 RECCPY (mode, "w+b");
99 }
100 } else {
101 _srecordf (str, "error: form=%s, action=%s, disp=%s", form, action, disp);
102 RTE (where, str);
103 }
104 if (_f->in_stream) {
105 if ((_f->unit = fmemopen (_f->buff, strlen (_f->buff) + 1, mode)) == NO_FILE) {
106 _srecordf (str, "cannot open unit %d: form=%s, action=%s, disp=%s", unit, form, action, disp);
107 RTE (where, str);
108 }
109 } else {
110 if ((_f->unit = fopen (_f->name, mode)) == NO_FILE) {
111 _srecordf (str, "cannot open unit %d: form=%s, action=%s, disp=%s", unit, form, action, disp);
112 RTE (where, str);
113 }
114 }
115 _rewind (where, unit);
116 } else {
117 // File was opened.
118 if (action == action_read) {
119 if (unit == 0 && _f->record >= _f->records) {
120 _srecordf (str, "unit %d: reading past end-of-file", unit);
121 RTE (where, str);
122 }
123 if (_f->action == action_write) {
124 _srecordf (str, "unit %d: not open for 'read'", unit);
125 RTE (where, str);
126 }
127 } else if (action == action_write) {
128 if (_f->action == action_read) {
129 _srecordf (str, "unit %d: not open for 'write'", unit);
130 RTE (where, str);
131 }
132 }
133 if (_f->form != form) {
134 if (form == form_formatted) {
135 _srecordf (str, "unit %d: not open for formatted IO", unit);
136 } else {
137 _srecordf (str, "unit %d: not open for unformatted IO", unit);
138 }
139 RTE (where, str);
140 }
141 }
142 }
143
144 void _fregister (char *where, int_4 unit, int_4 lrecl, char *fn, char *form, char *action, char *disp)
145 {
146 FTNFILE *_f = &_ffile[unit];
147 if (unit >= 0 && unit < MAX_FILES) {
148 int_4 len;
149 if (_f->unit != NO_FILE) {
150 NEW_RECORD (err);
151 _srecordf (err, "'unit %d' already open", unit);
152 RTE (where, err);
153 }
154 if (lrecl <= 0 || lrecl > MAX_LRECL) {
155 lrecl = MAX_LRECL;
156 }
157 _ffile[unit] = (FTNFILE) {
158 .form = form,.action = action,.disp = disp,.lrecl = lrecl};
159 _f->buff = (char *) f_malloc (lrecl + 1);
160 if (_f->in_stream) {
161 _f->buff_init = TRUE;
162 _f->action = action_read;
163 } else {
164 _f->buff_init = FALSE;
165 }
166 _f->buff_pos = 0;
167 if (fn == NO_TEXT) {
168 NEW_RECORD (buf);
169 _f->vers++;
170 _srecordf (buf, "ft%02df%03d", unit, _f->vers);
171 len = strlen (buf) + 1;
172 _f->name = (char *) f_malloc (len);
173 strcpy (_f->name, buf);
174 } else {
175 len = strlen (fn) + 1;
176 _f->name = (char *) f_malloc (len);
177 strcpy (_f->name, fn);
178 }
179 } else {
180 RTE (where, "unit out of range");
181 }
182 }
183
184 void _funregister (char *where, int_4 unit)
185 {
186 FTNFILE *_f = &_ffile[unit];
187 if (unit >= 0 && unit < MAX_FILES) {
188 if (_f->unit != NO_FILE) {
189 _fclose (unit);
190 }
191 if (_f->disp == disp_delete) {
192 remove (_f->name);
193 }
194 if (_f->name != NO_TEXT) {
195 free (_f->name);
196 }
197 if (_f->buff != NO_TEXT) {
198 free (_f->buff);
199 }
200 *_f = (FTNFILE) {
201 .unit = NO_FILE,.name = NO_TEXT,.form = NO_TEXT,.action = NO_TEXT,.disp = NO_TEXT,.vers = 0,.buff = NO_TEXT,.buff_init = FALSE,.buff_pos = 0,.buff_len = 0};
202 } else {
203 RTE (where, "unit out of range");
204 }
205 }
206
207 void _skip_eol (FILE * f)
208 {
209 while (fgetc (f) != '\n');
210 }
211
212 void _ioerr (char *where, int_4 unit)
213 {
214 NEW_RECORD (err);
215 _srecordf (err, "'unit %d': IO error", unit);
216 RTE (where, err);
217 }
218
219 void _ioerr_write (char *where, int_4 unit)
220 {
221 NEW_RECORD (err);
222 _srecordf (err, "'unit %d': IO error while writing", unit);
223 RTE (where, err);
224 }
225
226 void _ioerr_read (char *where, int_4 unit)
227 {
228 NEW_RECORD (err);
229 _srecordf (err, "'unit %d': IO error while reading", unit);
230 RTE (where, err);
231 }
232
233 void _ioend_read (char *where, int_4 unit)
234 {
235 NEW_RECORD (err);
236 _srecordf (err, "'unit %d': end of file while reading", unit);
237 RTE (where, err);
238 }
239
240 int_4 _init_file_buffer (int_4 unit)
241 {
242 FTNFILE *_f = &_ffile[unit];
243 if (unit == 0) {
244 if (_f->record < _f->records) {
245 // String lengths are powers of 2 in VIF.
246 int_4 len = 1;
247 while (len <= _f->lrecl) {
248 len *= 2;
249 }
250 _f->buff = &((_ffile[0].rewind)[_f->record * len]);
251 _f->buff_init = TRUE;
252 _f->buff_pos = 0;
253 _f->buff_len = strlen (_f->buff);
254 _f->record++;
255 return 0;
256 } else {
257 _f->buff = NO_TEXT;
258 _f->buff_init = FALSE;
259 _f->buff_pos = 0;
260 _f->buff_len = 0;
261 return 1;
262 }
263 } else {
264 if (_f->in_stream) {
265 if (_f->record > 1) {
266 char *q = _f->buff;
267 while (q[0] != '\n') {
268 q++;
269 }
270 _f->buff = &q[1];
271 }
272 } else {
273 (void) fgets (_f->buff, _f->lrecl, _f->unit);
274 }
275 _f->buff_len = strlen (_f->buff);
276 if (_f->buff[_f->buff_len - 1] == '\n') {
277 _f->buff[_f->buff_len - 1] = '\0';
278 _f->buff_len--;
279 }
280 _f->buff_init = TRUE;
281 _f->buff_pos = 0;
282 _f->record++;
283 return 0;
284 }
285 }
286
287 int_4 _rewind (char *where, int_4 unit)
288 {
289 FTNFILE *_f = &_ffile[unit];
290 if (unit == 0) {
291 _f->record = 0;
292 _init_file_buffer (0);
293 } else if (_f != NO_FTNFILE) {
294 if (_f->in_stream) {
295 _f->buff = _f->rewind;
296 } else {
297 rewind (_f->unit);
298 }
299 _f->buff_pos = 0;
300 _f->record = 1;
301 }
302 if (_f == NO_FTNFILE || errno != 0) {
303 RECORD buf;
304 _srecordf (buf, "cannot rewind unit %d", unit);
305 RTE (where, buf);
306 }
307 return 0;
308 }
309
310 int_4 _set_record (char *where, int_4 unit, int_4 rec)
311 {
312 FTNFILE *_f = &_ffile[unit];
313 if (unit == 0) {
314 _f->record = rec - 1;
315 _init_file_buffer (0);
316 } else if (_f != NO_FTNFILE) {
317 _rewind (where, unit);
318 _init_file_buffer (unit);
319 for (int_4 k = 1; k < rec; k++) {
320 _init_file_buffer (unit);
321 }
322 }
323 if (_f == NO_FTNFILE || errno != 0) {
324 RECORD buf;
325 _srecordf (buf, "cannot set record on unit %d", unit);
326 RTE (where, buf);
327 }
328 return 0;
329 }
330
331 int_4 _backspace (char *where, int_4 unit)
332 {
333 FTNFILE *_f = &_ffile[unit];
334 _set_record (where, unit, _f->record - 1);
335 if (_f == NO_FTNFILE || errno != 0) {
336 RECORD buf;
337 _srecordf (buf, "cannot backspace unit %d", unit);
338 RTE (where, buf);
339 }
340 return 0;
341 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|