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-2024 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 #include <rts-real32.h>
28
29 #define SIGN(z) ((z) == 0 ? 0 : ((z) > 0 ? 1 : 0))
30 #define ERROR_CHAR '*'
31 #define POINT_CHAR '.'
32
33 void xsprintfmt (char *, const char *, ...);
34
35 FTNFILE _ffile[MAX_FILES];
36
37 char *action_default = "action_default";
38 char *action_read = "action_read";
39 char *action_write = "action_write";
40 char *action_readwrite = "action_readwrite";
41 char *form_formatted = "form_formatted";
42 char *form_unformatted = "form_unformatted";
43 char *disp_new = "disp_new";
44 char *disp_old = "disp_old";
45 char *disp_delete = "disp_delete";
46 char *disp_keep = "disp_keep";
47
48 // __scale__ is set by nP in formats.
49
50 int_4 __scale__ = 1;
51
52 void _fclose (int_4 k)
53 {
54 if (_ffile[k].unit != NULL) {
55 (void) fclose (_ffile[k].unit);
56 _ffile[k].unit = NULL;
57 }
58 }
59
60 static char *plusab (char *buf, char c)
61 {
62 char z[2];
63 z[0] = c;
64 z[1] = '\0';
65 bufcat (buf, z, RECLN);
66 return buf;
67 }
68
69 static char *plusto (char ch, char *buf)
70 {
71 memmove (&buf[1], &buf[0], strlen(buf) + 1);
72 buf[0] = ch;
73 return buf;
74 }
75
76 static char *leading_spaces (char *buf, int_4 width)
77 {
78 if (width > 0) {
79 int_4 j = ABS (width) - (int_4) strlen (buf);
80 while (--j >= 0) {
81 (void) plusto (' ', buf);
82 }
83 }
84 return buf;
85 }
86
87 static char *error_chars (char *buf, int_4 n)
88 {
89 int_4 k = (n != 0 ? ABS (n) : 1);
90 buf[k] = '\0';
91 while (--k >= 0) {
92 buf[k] = ERROR_CHAR;
93 }
94 return buf;
95 }
96
97 static char digchar (int_4 k)
98 {
99 char *tab = "0123456789abcdefghijklmnopqrstuvwxyz";
100 if (k >= 0 && k < (int_4) strlen (tab)) {
101 return tab[k];
102 } else {
103 return ERROR_CHAR;
104 }
105 }
106
107 // INTEGER*8
108
109 char *intnot (char *buf, int_8 k, int_4 width)
110 {
111 int_8 n = ABS (k);
112 buf[0] = '\0';
113 do {
114 (void) plusto (digchar (n % 10), buf);
115 n /= 10;
116 } while (n != 0);
117 if (k < 0) {
118 (void) plusto ('-', buf);
119 }
120 if (width > 0 && strlen (buf) > width) {
121 (void) error_chars (buf, width);
122 } else {
123 (void) leading_spaces (buf, width);
124 }
125 return buf;
126 }
127
128 // REAL*32
129
130 void xsprintfmt (char *buffer, const char *fmt, ...)
131 {
132 RECORD ibuff;
133 RECCLR (ibuff);
134 va_list ap;
135 va_start (ap, fmt);
136 vsprintf (ibuff, fmt, ap);
137 va_end (ap);
138 strcat (buffer, ibuff);
139 }
140
141 static int_4 special_value (char *s, real_32 u, int_4 sign)
142 {
143 if ((xisPinf (&u))) {
144 if (sign != 0) {
145 *s++ = '+';
146 }
147 strcpy (s, "Inf");
148 return 1;
149 } else if ((xisMinf (&u))) {
150 strcpy (s, "-Inf");
151 return 1;
152 } else if ((xisNaN (&u))) {
153 if (sign != 0) {
154 *s++ = '\?';
155 }
156 strcpy (s, "NaN");
157 return 1;
158 } else {
159 return 0;
160 }
161 }
162
163 char *xsubfixed (char *buffer, real_32 v, logical_4 sign, int_4 digs)
164 {
165 RECCLR (buffer);
166 if ((special_value (buffer, v, sign))) {
167 return buffer;
168 }
169 real_32 u = v;
170 digs = _min (_abs (digs), FLT256_DIG);
171 // Put sign and take abs value.
172 char *p = buffer;
173 if (xlt (u, X_0)) {
174 u = xneg (u);
175 *(p++) = '-';
176 } else if (sign) {
177 *(p++) = '+';
178 } else {
179 *(p++) = ' ';
180 }
181 // Round fraction
182 real_32 eps = xmul(X_1_OVER_2, xtenup (-digs));
183 u = xsum (u, eps);
184 //
185 int_4 before;
186 if (xlt (u, X_10)) {
187 before = 1;
188 } else if (xlt (u, X_100)) {
189 before = 2;
190 } else if (xlt (u, X_1000)) {
191 before = 3;
192 } else {
193 before = (int_4) ceil (xtodbl (xlog10 (u)));
194 }
195 // Integral part.
196 u = xdiv (u, xtenup (before));
197 while (xge (u, X_1)) {
198 u = xdiv (u, X_10);
199 before++;
200 }
201 for (int_4 k = 0; k < before; ++k) {
202 u = xmul (X_10, u);
203 int_4 dig;
204 u = xsfmod (u, &dig);
205 *(p++) = (char) '0' + dig;
206 }
207 // Fraction.
208 *(p++) = '.';
209 for (int_4 k = 0; k < digs; ++k) {
210 u = xmul (X_10, u);
211 int_4 dig;
212 u = xsfmod (u, &dig);
213 *(p++) = (char) '0' + dig;
214 }
215 return buffer;
216 }
217
218 char *xfixed (char *buf, real_32 x, int_4 width, int_4 digs, int_4 precision)
219 {
220 width = _abs (width);
221 digs = _min (abs (digs), precision);
222 xsubfixed (buf, x, FALSE, digs);
223 if (width > 0 && strlen (buf) > width) {
224 return error_chars (buf, width);
225 } else {
226 return leading_spaces (buf, width);
227 }
228 }
229
230 char *xfloat (char *buf, real_32 z, int_4 width, int_4 digs, int_4 expos, int_4 mult, int_4 precision, char sym)
231 {
232 buf[0] = '\0';
233 width = _abs (width);
234 digs = _min (abs (digs), precision);
235 expos = _abs (expos);
236 if (expos > 5) {
237 return error_chars (buf, width);
238 }
239 // Scientific notation mult = 1, Engineering notation mult = 3
240 mult = _max (1, mult);
241 // Default __scale__ is 1.
242 int_4 q = 1;
243 char *max = "1";
244 real_32 x = xabs (z), lwb, upb;
245 //
246 if (__scale__ < 0 || __scale__ > 3) {
247 __scale__ = 1;
248 }
249 if (mult == 1) {
250 if (__scale__ == 0) {
251 lwb = X_1_OVER_10;
252 upb = X_1;
253 q = 1;
254 max = "0.1";
255 } else if (__scale__ == 1) {
256 lwb = X_1;
257 upb = X_10;
258 q = 0;
259 max = "1";
260 } else if (__scale__ == 2) {
261 lwb = X_10;
262 upb = X_100;
263 q = -1;
264 max = "10";
265 } else if (__scale__ == 3) {
266 lwb = X_100;
267 upb = X_1000;
268 max = "100";
269 q = -2;
270 }
271 }
272 // Standardize.
273 int_4 p = 0;
274 if (xnot0 (&x)) {
275 p = (int_4) round (xtodbl (xlog10 (xabs(x)))) + q;
276 x = xdiv (x, xtenup (p));
277 if (xle (x, lwb)) {
278 x = xmul (x, X_10);
279 p--;
280 }
281 if (xge (x, upb)) {
282 x = xdiv (x, X_10);
283 p++;
284 }
285 while (p % mult != 0) {
286 x = xmul (x, X_10);
287 p--;
288 }
289 }
290 // Form number.
291 RECORD mant;
292 RECCLR (mant);
293 xsubfixed (mant, x, FALSE, digs);
294 // Correction of rounding issue by which |mant| equals UPB.
295 if (strchr (mant, '*') == NULL && xge (xabs (strtox (mant, NULL)), upb)) {
296 if (mant[0] == ' ' || mant[0] == '+') {
297 _srecordf (mant, "%c%s", mant[0], max);
298 } else {
299 _srecordf (mant, "%s", max);
300 }
301 if (digs > 0) {
302 plusab (mant, '.');
303 for (int_4 k = 0; k < digs; k++) {
304 plusab (mant, '0');
305 }
306 }
307 p++;
308 }
309 //
310 RECORD fmt;
311 if (xsgn (&z) < 0) {
312 mant[0] = '-';
313 }
314 _srecordf (fmt, "%%s%c%%+0%dd", sym, expos);
315 _srecordf (buf, fmt, mant, p);
316 if (width > 0 && (strchr (buf, '*') != NULL || strlen (buf) > width)) {
317 if (digs > 0) {
318 return xfloat (buf, z, width, digs - 1, expos, mult, precision, sym);
319 } else {
320 return error_chars (buf, width);
321 }
322 } else {
323 return leading_spaces (buf, width);
324 }
325 }
326
327 // Fortran IO
328
329 void _fcheck (char *where, int_4 unit, char *action, char *form)
330 {
331 RECORD str;
332 __scale__ = 1;
333 if (unit < 0 || unit >= MAX_FILES) {
334 _srecordf (str, "unit number %d is not valid", unit);
335 RTE (where, str);
336 }
337 if (action == NULL) {
338 // CLOSE, REWIND
339 return;
340 }
341 if (_ffile[unit].unit == NULL) {
342 // File was not opened yet.
343 RECORD mode, disp;
344 if (_ffile[unit].disp != NULL) {
345 strcpy (disp, _ffile[unit].disp);
346 } else {
347 strcpy (disp, disp_old);
348 }
349 if (_ffile[unit].action == action_default) {
350 _ffile[unit].action = action;
351 } else if (_ffile[unit].action == action_readwrite) {
352 action = action_readwrite;
353 } else if (_ffile[unit].action != action) {
354 _srecordf (str, "inconsistent action: %s", action);
355 RTE (where, str);
356 }
357 if (_ffile[unit].form == NULL) {
358 _ffile[unit].form = form;
359 } else if (_ffile[unit].form != form) {
360 _srecordf (str, "inconsistent formatting: %s", form);
361 RTE (where, str);
362 }
363 strcpy (mode, "UNKNOWN");
364 if (form == form_formatted && action == action_read) {
365 strcpy (mode, "r");
366 } else if (form == form_formatted && action == action_write) {
367 strcpy (mode, "w");
368 } else if (form == form_formatted && action == action_readwrite) {
369 if (EQUAL (disp, "disp_old")) {
370 strcpy (mode, "r+");
371 } else if (EQUAL (disp, "disp_new")) {
372 strcpy (mode, "w+");
373 }
374 } else if (form == form_unformatted && action == action_read) {
375 strcpy (mode, "rb");
376 } else if (form == form_unformatted && action == action_write) {
377 strcpy (mode, "wb");
378 } else if (form == form_unformatted && action == action_readwrite) {
379 if (EQUAL (disp, "disp_old")) {
380 strcpy (mode, "r+b");
381 } else if (EQUAL (disp, "disp_new")) {
382 strcpy (mode, "w+b");
383 }
384 } else {
385 _srecordf (str, "error: form=%s, action=%s, disp=%s", form, action, disp);
386 RTE (where, str);
387 }
388 if ((_ffile[unit].unit = fopen (_ffile[unit].name, mode)) == NULL) {
389 _srecordf (str, "cannot open unit %d: form=%s, action=%s, disp=%s", unit, form, action, disp);
390 RTE (where, str);
391 }
392 rewind (_ffile[unit].unit);
393 } else {
394 // File was opened.
395 if (action == action_read) {
396 if (_ffile[unit].action == action_write) {
397 _srecordf (str, "'unit %d' is not open for 'read'", unit);
398 RTE (where, str);
399 }
400 } else if (action == action_write) {
401 if (_ffile[unit].action == action_read) {
402 _srecordf (str, "'unit %d' is not open for 'write'", unit);
403 RTE (where, str);
404 }
405 }
406 if (_ffile[unit].form != form) {
407 if (form == form_formatted) {
408 _srecordf (str, "'unit %d' is not open for formatted IO", unit);
409 } else {
410 _srecordf (str, "'unit %d' is not open for unformatted IO", unit);
411 }
412 RTE (where, str);
413 }
414 }
415 }
416
417 void _fregister (char *where, int_4 unit, int_4 lrecl, char *fn, char *form, char *action, char *disp)
418 {
419 if (unit >= 0 && unit < MAX_FILES) {
420 int_4 len;
421 if (_ffile[unit].unit != NULL) {
422 RECORD err;
423 _srecordf (err, "'unit %d' already open", unit);
424 RTE (where, err);
425 }
426 if (lrecl <= 0 || lrecl > MAX_LRECL) {
427 lrecl = MAX_LRECL;
428 }
429 _ffile[unit] = (FTNFILE) {
430 .form = form,.action = action,.disp = disp,.lrecl = lrecl};
431 _ffile[unit].buff = (char *) f_malloc (lrecl + 1);
432 _ffile[unit].buff_init = FALSE;
433 _ffile[unit].buff_pos = 0;
434 if (fn == NULL) {
435 RECORD buf;
436 _ffile[unit].vers++;
437 _srecordf (buf, "ft%02df%03d", unit, _ffile[unit].vers);
438 len = strlen (buf) + 1;
439 _ffile[unit].name = (char *) f_malloc (len);
440 strcpy (_ffile[unit].name, buf);
441 } else {
442 len = strlen (fn) + 1;
443 _ffile[unit].name = (char *) f_malloc (len);
444 strcpy (_ffile[unit].name, fn);
445 }
446 } else {
447 RTE (where, "unit out of range");
448 }
449 }
450
451 void _funregister (char *where, int_4 unit)
452 {
453 if (unit >= 0 && unit < MAX_FILES) {
454 if (_ffile[unit].unit != NULL) {
455 _fclose (unit);
456 }
457 if (_ffile[unit].disp == disp_delete) {
458 remove (_ffile[unit].name);
459 }
460 if (_ffile[unit].name != NULL) {
461 free (_ffile[unit].name);
462 }
463 if (_ffile[unit].buff != NULL) {
464 free (_ffile[unit].buff);
465 }
466 _ffile[unit] = (FTNFILE) {
467 .unit = NULL,.name = NULL,.form = NULL,.action = NULL,.disp = NULL,.vers = 0,.buff = NULL,.buff_init = FALSE,.buff_pos = 0,.buff_len = 0};
468 } else {
469 RTE (where, "unit out of range");
470 }
471 }
472
473 void _skip_eol (FILE * f)
474 {
475 while (fgetc (f) != '\n');
476 }
477
478 void _ioerr (char *where, int_4 unit)
479 {
480 RECORD err;
481 _srecordf (err, "'unit %d' IO error", unit);
482 RTE (where, err);
483 }
484
485 void _ioerr_write (char *where, int_4 unit)
486 {
487 RECORD err;
488 _srecordf (err, "'unit %d' IO error while writing", unit);
489 RTE (where, err);
490 }
491
492 void _ioerr_read (char *where, int_4 unit)
493 {
494 RECORD err;
495 _srecordf (err, "'unit %d' IO error while reading", unit);
496 RTE (where, err);
497 }
498
499 void _ioend_read (char *where, int_4 unit)
500 {
501 RECORD err;
502 _srecordf (err, "'unit %d' end of file while reading", unit);
503 RTE (where, err);
504 }
505
506 void _fprintf_int_8 (char *str, char *fmt, int_8 elem)
507 {
508 int_4 len = 0;
509 if (fmt[0] == '%') {
510 fmt++;
511 }
512 if (isdigit (fmt[0])) {
513 len = strtol (fmt, NULL, 10);
514 }
515 intnot (str, elem, len);
516 }
517
518 void _fprintf_real_32 (char *buf, char *fmt, real_32 item, int_4 expw, int_4 precision)
519 {
520 int_4 dec = 0, len = 0, expos = 0;
521 if (fmt[0] == '%') {
522 fmt++;
523 }
524 char expo_char = fmt[strlen (fmt) - 1];
525 if (expo_char == 'n') {
526 expo_char = 'e';
527 } else if (expo_char == 'N') {
528 expo_char = 'E';
529 }
530 char *p1, *p2, *expo;
531 if (fmt[0] == '.') {
532 fmt++;
533 dec = strtol (fmt, &p2, 10);
534 } else {
535 len = strtol (fmt, &p1, 10);
536 dec = strtol (&p1[1], &p2, 10);
537 }
538 if (tolower (expo_char) == 'e') {
539 int_4 ee = strtol (&p2[1], &expo, 10);
540 expos = (ee == 0 ? expw : ee);
541 }
542 if (tolower (expo_char) == 'f') {
543 xfixed (buf, item, len, dec, precision);
544 } else if (tolower (expo[0]) == 'n') {
545 xfloat (buf, item, len, dec, expos, 3, precision, expo_char);
546 } else {
547 xfloat (buf, item, len, dec, expos, 1, precision, expo_char);
548 }
549 return;
550 }
551
552 int_4 _vifprintf (int_4 unit, char *fmt, void *elem, int_4 type, int_4 len)
553 {
554 FTNFILE *_f = &_ffile[unit];
555 if (fmt == NULL || strlen (fmt) == 0) {
556 return ERR;
557 }
558 if (strcmp (fmt, "\n") == 0) {
559 fprintf (_f->unit, "\n");
560 return 1;
561 }
562 if (fmt != NULL && type == NOTYPE) {
563 if (strcmp (fmt, "0") == 0) {
564 __scale__ = 0;
565 } else if (strcmp (fmt, "1") == 0) {
566 __scale__ = 1;
567 } else if (strcmp (fmt, "2") == 0) {
568 __scale__ = 2;
569 } else if (strcmp (fmt, "3") == 0) {
570 __scale__ = 3;
571 } else {
572 fprintf (_f->unit, fmt);
573 }
574 return 1;
575 }
576 //
577 char mod = tolower (fmt[strlen (fmt) - 1]);
578 if (mod == 's') {
579 if (type == NOTYPE) {
580 fprintf (_f->unit, fmt);
581 } else if (type == CHARACTER) {
582 fprintf (_f->unit, fmt, (char *) elem);
583 } else if (type == LOGICAL) {
584 fprintf (_f->unit, fmt, (*(int_4 *) elem ? 't' : 'f'));
585 } else if (type == INTEGER && len == 4) {
586 int_4 awid = len, width;
587 if (sscanf (fmt, "%%%ds", &width) == 1) {
588 awid = _abs (width);
589 }
590 int_4 sum = *(int_4 *) elem;
591 for (int_4 k = 0; k < len && k < awid; k++) {
592 char ch = sum % 256;
593 fprintf (_f->unit, "%c", ch);
594 sum /= 256;
595 }
596 } else {
597 return ERR;
598 }
599 return 1;
600 } else if (mod == 'c') {
601 if (type == LOGICAL) {
602 fprintf (_f->unit, fmt, (*(int_4 *) elem ? 't' : 'f'));
603 } else {
604 return ERR;
605 }
606 return 1;
607 } else if (mod == 'd') {
608 // INTEGER
609 if (type == INTEGER && len == 2) {
610 RECORD buf;
611 RECCLR (buf);
612 _fprintf_int_8 (buf, fmt, (int_8) *(int_2 *) elem);
613 fprintf (_f->unit, "%s", buf);
614 } else if (type == INTEGER && len == 4) {
615 RECORD buf;
616 RECCLR (buf);
617 _fprintf_int_8 (buf, fmt, (int_8) *(int_4 *) elem);
618 fprintf (_f->unit, "%s", buf);
619 } else if (type == INTEGER && len == 8) {
620 RECORD buf;
621 RECCLR (buf);
622 _fprintf_int_8 (buf, fmt, (int_8) *(int_8 *) elem);
623 fprintf (_f->unit, "%s", buf);
624 } else if (type == INTEGER && len == 16) {
625 RECORD buf;
626 RECCLR (buf);
627 _fprintf_int_8 (buf, fmt, (int_8) *(int_8 *) elem);
628 fprintf (_f->unit, "%s", buf);
629 } else {
630 return ERR;
631 }
632 return 1;
633 } else if (mod == 'e' || mod == 'n' || mod == 'f') {
634 // REAL and COMPLEX
635 RECORD str;
636 RECCLR (str);
637 if (type == INTEGER && len == 2) {
638 _fprintf_real_32 (str, fmt, flttox ((real_4) *(int_2 *) elem), 4, FLT_DIG);
639 fprintf (_f->unit, "%s", str);
640 } else if (type == INTEGER && len == 4) {
641 _fprintf_real_32 (str, fmt, dbltox ((real_8) *(int_4 *) elem), 4, FLT_DIG);
642 fprintf (_f->unit, "%s", str);
643 } else if (type == INTEGER && len == 8) {
644 _fprintf_real_32 (str, fmt, dbltox ((real_8) *(int_8 *) elem), 4, FLT_DIG);
645 fprintf (_f->unit, "%s", str);
646 } else if (type == REAL && len == 4) {
647 _fprintf_real_32 (str, fmt, flttox (*(real_4 *) elem), 4, FLT_DIG);
648 fprintf (_f->unit, "%s", str);
649 } else if (type == REAL && len == 8) {
650 _fprintf_real_32 (str, fmt, dbltox (*(real_8 *) elem), 4, DBL_DIG);
651 fprintf (_f->unit, "%s", str);
652 } else if (type == REAL && len == 16) {
653 _fprintf_real_32 (str, fmt, _quadtox (*(real_16 *) elem), 5, FLT128_DIG);
654 fprintf (_f->unit, "%s", str);
655 } else if (type == REAL && len == 32) {
656 _fprintf_real_32 (str, fmt, *(real_32 *) elem, 5, FLT256_DIG);
657 fprintf (_f->unit, "%s", str);
658 } else if (type == COMPLEX && len == 8) {
659 real_4 z = crealf (*(complex_8 *) elem);
660 _vifprintf (unit, fmt, &z, REAL, 4);
661 } else if (type == COMPLEX && len == -8) {
662 real_4 z = cimagf (*(complex_8 *) elem);
663 _vifprintf (unit, fmt, &z, REAL, 4);
664 } else if (type == COMPLEX && len == 16) {
665 real_8 z = creal (*(complex_16 *) elem);
666 _vifprintf (unit, fmt, &z, REAL, 8);
667 } else if (type == COMPLEX && len == -16) {
668 real_8 z = cimag (*(complex_16 *) elem);
669 _vifprintf (unit, fmt, &z, REAL, 8);
670 } else if (type == COMPLEX && len == 32) {
671 real_16 z = crealq (*(complex_32 *) elem);
672 _vifprintf (unit, fmt, &z, REAL, 16);
673 } else if (type == COMPLEX && len == -32) {
674 real_16 z = cimagq (*(complex_32 *) elem);
675 _vifprintf (unit, fmt, &z, REAL, 16);
676 } else if (type == COMPLEX && len == 64) {
677 real_32 z = cxre (*(complex_64 *) elem);
678 _vifprintf (unit, fmt, &z, REAL, 32);
679 } else if (type == COMPLEX && len == -64) {
680 real_32 z = cxim (*(complex_64 *) elem);
681 _vifprintf (unit, fmt, &z, REAL, 32);
682 } else {
683 return ERR;
684 }
685 return 1;
686 }
687 return ERR;
688 }
689
690 void _fscanf_real (char *str, FTNFILE * _f, int_4 width, int_4 buflen)
691 {
692 while (_f->buff_pos < buflen && _f->buff[_f->buff_pos] == ' ') {
693 _f->buff_pos++;
694 }
695 for (int_4 k = 0; k < width && _f->buff_pos < buflen && _f->buff[_f->buff_pos] != ' '; k++) {
696 str[k] = _f->buff[_f->buff_pos++];
697 str[k + 1] = '\0';
698 }
699 }
700
701 int_4 _vifscanf (int_4 unit, char *fmt, void *elem, int_4 type, int_4 len)
702 {
703 int_4 buflen, width, rc = 0, N = 0;
704 FTNFILE *_f = &_ffile[unit];
705 //printf ("\nscan '%s' %d '%s'\n", fmt, type, &_f->buff[_f->buff_pos]);
706 //fflush (stdout);
707 // Set to reinit on next call.
708 if (fmt == NULL) {
709 _f->buff_init = FALSE;
710 return 1;
711 }
712 // (Re)init if needed.
713 if (!_f->buff_init) {
714 (void) fgets (_f->buff, _f->lrecl, _f->unit);
715 buflen = _f->buff_len = strlen (_f->buff);
716 if (_f->buff[buflen - 1] == '\n') {
717 _f->buff[buflen - 1] = '\0';
718 _f->buff_len--;
719 }
720 _f->buff_init = TRUE;
721 _f->buff_pos = 0;
722 }
723 buflen = _f->buff_len;
724 // Reading newline just reinits the buffer.
725 if (strcmp (fmt, "\n") == 0) {
726 (void) fgets (_f->buff, _f->lrecl, _f->unit);
727 buflen = _f->buff_len = strlen (_f->buff);
728 if (_f->buff[buflen - 1] == '\n') {
729 _f->buff[buflen - 1] = '\0';
730 _f->buff_len--;
731 }
732 _f->buff_init = TRUE;
733 _f->buff_pos = 0;
734 return 1;
735 }
736 // Textual strings are skipped and not checked.
737 if (fmt != NULL && type == NOTYPE) {
738 int_4 awid = strlen (fmt);
739 if (_f->buff_pos + awid < buflen) {
740 _f->buff_pos += awid;
741 }
742 return 1;
743 }
744 // Fortran items A, D, E, F, I and Q.
745 char mod = fmt[strlen (fmt) - 1];
746 if (mod == 's' && sscanf (fmt, "%%%ds", &width) == 1) {
747 int_4 awid = _abs (width);
748 if (type == NOTYPE || elem == NULL) {
749 if (_f->buff_pos + awid > buflen) {
750 return ERR;
751 }
752 _f->buff_pos += awid; // Just skip it. Fortran would check.
753 return 1;
754 }
755 if (type == CHARACTER) {
756 char *str = (char *) elem;
757 for (int_4 k = 0; k < awid && _f->buff_pos < buflen; k++) {
758 str[k] = _f->buff[_f->buff_pos++];
759 }
760 // In VIF trailing space is cut.
761 for (int_4 k = strlen (str) - 1; k > 0 && str[k] == ' '; k--) {
762 str[k] = '\0';
763 }
764 } else if (type == INTEGER && len == 4) {
765 RECORD str;
766 int_4 k;
767 for (k = 0; k < awid && _f->buff_pos < buflen; k++) {
768 str[k] = _f->buff[_f->buff_pos++];
769 }
770 str[k] = '\0';
771 *(int_4 *) elem = _int4 (str);
772 }
773 return 1;
774 }
775 if (mod == 'c' && strcmp (fmt, "%c") == 0) {
776 RECORD nfmt;
777 if (len == 4) {
778 char ch;
779 _srecordf (nfmt, "%%c%%n");
780 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (char *) &ch, &N);
781 *(logical_4 *) elem = (ch == 't');
782 }
783 _f->buff_pos += N;
784 return rc;
785 }
786 if (mod == 'd' && strcmp (fmt, "%d") == 0) {
787 RECORD nfmt;
788 if (len == 2) {
789 int_4 i;
790 _srecordf (nfmt, "%%d%%n");
791 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) &i, &N);
792 *(int_2 *) elem = i;
793 } else if (len == 4) {
794 _srecordf (nfmt, "%%d%%n");
795 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) elem, &N);
796 } else if (len == 8) {
797 _srecordf (nfmt, "%%lld%%nn");
798 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_8 *) elem, &N);
799 }
800 _f->buff_pos += N;
801 return rc;
802 }
803 if (mod == 'd' && type == INTEGER && sscanf (fmt, "%%%dd", &width) == 1) {
804 RECORD nfmt;
805 int_4 awid = _abs (width);
806 if (_f->buff_pos + awid > buflen) {
807 return ERR;
808 }
809 if (len == 2) {
810 int_4 i;
811 _srecordf (nfmt, "%%%dd", width);
812 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) &i);
813 *(int_2 *) elem = i;
814 } else if (len == 4) {
815 _srecordf (nfmt, "%%%dd", width);
816 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) elem);
817 } else if (len == 8) {
818 _srecordf (nfmt, "%%%dlld", width);
819 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_8 *) elem);
820 }
821 _f->buff_pos += awid;
822 return rc;
823 }
824 // REAL, standard format
825 if (type == REAL && strcmp (fmt, "%e") == 0) {
826 if (len == 4) {
827 RECORD nfmt;
828 _srecordf (nfmt, "%%e%%n");
829 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_4 *) elem, &N);
830 _f->buff_pos += N;
831 return rc;
832 } else if (len == 8) {
833 RECORD nfmt;
834 _srecordf (nfmt, "%%le%%n");
835 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_8 *) elem, &N);
836 _f->buff_pos += N;
837 return rc;
838 } else if (len == 16) {
839 RECORD str;
840 RECCLR (str);
841 _fscanf_real (str, _f, RECLN - 1, buflen);
842 *(real_16 *) (elem) = _strtoquad (str, NULL);
843 return 1;
844 } else if (len == 32) {
845 RECORD str;
846 RECCLR (str);
847 _fscanf_real (str, _f, RECLN - 1, buflen);
848 *(real_32 *) (elem) = strtox (str, NULL);
849 return 1;
850 }
851 }
852 // REAL, format, note that only width can be specified.
853 if ((mod == 'e' || mod == 'f') && type == REAL && sscanf (fmt, "%%%d", &width) == 1) {
854 int_4 awid = _abs (width);
855 if (_f->buff_pos + awid > buflen) {
856 return ERR;
857 }
858 if (len == 4) {
859 rc = sscanf (&_f->buff[_f->buff_pos], fmt, (real_4 *) elem);
860 _f->buff_pos += width;
861 } else if (len == 8) {
862 RECORD nfmt;
863 _srecordf (nfmt, "%%%dl%c", width, mod);
864 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_8 *) elem);
865 _f->buff_pos += width;
866 } else if (len == 16) {
867 RECORD str;
868 RECCLR (str);
869 _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), buflen);
870 *(real_16 *) (elem) = _strtoquad (str, NULL);
871 return 1;
872 } else if (len == 32) {
873 RECORD str;
874 RECCLR (str);
875 _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), buflen);
876 *(real_32 *) (elem) = strtox (str, NULL);
877 return 1;
878 }
879 return rc;
880 }
881 // COMPLEX, standard
882 if (mod == 'e' && type == COMPLEX && strcmp (fmt, "%e") == 0) {
883 if (_abs (len) == 8) {
884 RECORD nfmt;
885 real_4 x;
886 complex_8 *z = (complex_8 *) elem;
887 _srecordf (nfmt, "%%e%%n");
888 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x, &N);
889 _f->buff_pos += N;
890 if (len > 0) {
891 *z = CMPLXF (x, 0);
892 } else {
893 *z = CMPLXF (crealf (*z), x);
894 }
895 return rc;
896 } else if (_abs (len) == 16) {
897 RECORD nfmt;
898 real_8 x;
899 complex_16 *z = (complex_16 *) elem;
900 _srecordf (nfmt, "%%le%%n");
901 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x, &N);
902 _f->buff_pos += N;
903 if (len > 0) {
904 *z = CMPLX (x, 0);
905 } else {
906 *z = CMPLX (creal (*z), x);
907 }
908 return rc;
909 } else if (_abs (len) == 32) {
910 RECORD str;
911 RECCLR (str);
912 complex_32 *z = (complex_32 *) elem;
913 _fscanf_real (str, _f, RECLN - 1, buflen);
914 if (len > 0) {
915 *z = CMPLXQ (_strtoquad (str, NULL), 0.0q);
916 } else {
917 *z = CMPLXQ (crealq (*z), _strtoquad (str, NULL));
918 }
919 return 1;
920 } else if (_abs (len) == 64) {
921 RECORD str;
922 RECCLR (str);
923 complex_64 *z = (complex_64 *) elem;
924 _fscanf_real (str, _f, RECLN - 1, buflen);
925 if (len > 0) {
926 z->re = strtox (str, NULL);
927 } else {
928 z->im = strtox (str, NULL);
929 }
930 return 1;
931 }
932 }
933 // COMPLEX, format, note that only width can be specified.
934 if ((mod == 'e' || mod == 'f') && type == COMPLEX && sscanf (fmt, "%%%de", &width) == 1) {
935 int_4 awid = _abs (width);
936 if (_f->buff_pos + awid > buflen) {
937 return ERR;
938 }
939 if (_abs (len) == 8) {
940 real_4 x;
941 complex_8 *z = (complex_8 *) elem;
942 rc = sscanf (&_f->buff[_f->buff_pos], fmt, &x);
943 _f->buff_pos += width;
944 if (len > 0) {
945 *z = CMPLXF (x, 0);
946 } else {
947 *z = CMPLXF (crealf (*z), x);
948 }
949 return rc;
950 } else if (_abs (len) == 16) {
951 real_8 x;
952 complex_16 *z = (complex_16 *) elem;
953 RECORD nfmt;
954 _srecordf (nfmt, "%%%dl%c", width, mod);
955 rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x);
956 _f->buff_pos += width;
957 if (len > 0) {
958 *z = CMPLX (x, 0);
959 } else {
960 *z = CMPLX (creal (*z), x);
961 }
962 return rc;
963 } else if (_abs (len) == 32) {
964 RECORD str;
965 RECCLR (str);
966 complex_32 *z = (complex_32 *) elem;
967 _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), buflen);
968 if (len > 0) {
969 *z = CMPLXQ (_strtoquad (str, NULL), 0.0q);
970 } else {
971 *z = CMPLXQ (crealq (*z), _strtoquad (str, NULL));
972 }
973 return 1;
974 } else if (_abs (len) == 64) {
975 RECORD str;
976 RECCLR (str);
977 complex_64 *z = (complex_64 *) elem;
978 _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), buflen);
979 if (len > 0) {
980 z->re = strtox (str, NULL);
981 } else {
982 z->im = strtox (str, NULL);
983 }
984 return 1;
985 }
986 }
987 // No conversion :-(
988 return ERR;
989 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|