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  #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 != NO_FILE) {
  55      (void) fclose (_ffile[k].unit);
  56      _ffile[k].unit = NO_FILE;
  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 ((xis_pinf (&u))) {
 144      if (sign != 0) {
 145        *s++ = '+';
 146      }
 147      strcpy (s, "Inf");
 148      return 1;
 149    } else if ((xis_minf (&u))) {
 150      strcpy (s, "-Inf");
 151      return 1;
 152    } else if ((xis_nan (&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, '*') == NO_TEXT && xge (xabs (strtox (mant, NO_REF_TEXT)), 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, '*') != NO_TEXT || 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 == NO_TEXT) {
 338  // CLOSE, REWIND
 339      return;
 340    }
 341    if (_ffile[unit].unit == NO_FILE) {
 342  // File was not opened yet.
 343      RECORD mode, disp;
 344      RECCLR (mode);
 345      RECCLR (disp);
 346      if (_ffile[unit].disp != NO_TEXT) {
 347        strcpy (disp, _ffile[unit].disp);
 348      } else {
 349        strcpy (disp, disp_old);
 350      }
 351      if (_ffile[unit].action == action_default) {
 352        _ffile[unit].action = action;
 353      } else if (_ffile[unit].action == action_readwrite) {
 354        action = action_readwrite;
 355      } else if (_ffile[unit].action != action) {
 356        _srecordf (str, "inconsistent action: %s", action);
 357        RTE (where, str);
 358      }
 359      if (_ffile[unit].form == NO_TEXT) {
 360        _ffile[unit].form = form;
 361      } else if (_ffile[unit].form != form) {
 362        _srecordf (str, "inconsistent formatting: %s", form);
 363        RTE (where, str);
 364      }
 365      strcpy (mode, "UNKNOWN");
 366      if (form == form_formatted && action == action_read) {
 367        strcpy (mode, "r");
 368      } else if (form == form_formatted && action == action_write) {
 369        strcpy (mode, "w");
 370      } else if (form == form_formatted && action == action_readwrite) {
 371        if (EQUAL (disp, "disp_old")) {
 372          strcpy (mode, "r+");
 373        } else if (EQUAL (disp, "disp_new")) {
 374          strcpy (mode, "w+");
 375        }
 376      } else if (form == form_unformatted && action == action_read) {
 377        strcpy (mode, "rb");
 378      } else if (form == form_unformatted && action == action_write) {
 379        strcpy (mode, "wb");
 380      } else if (form == form_unformatted && action == action_readwrite) {
 381        if (EQUAL (disp, "disp_old")) {
 382          strcpy (mode, "r+b");
 383        } else if (EQUAL (disp, "disp_new")) {
 384          strcpy (mode, "w+b");
 385        }
 386      } else {
 387        _srecordf (str, "error: form=%s, action=%s, disp=%s", form, action, disp);
 388        RTE (where, str);
 389      }
 390      if (_ffile[unit].in_stream) {
 391        if ((_ffile[unit].unit = fmemopen (_ffile[unit].buff, strlen (_ffile[unit].buff) + 1, mode)) == NO_FILE) {
 392          _srecordf (str, "cannot open unit %d: form=%s, action=%s, disp=%s", unit, form, action, disp);
 393          RTE (where, str);
 394        }
 395      } else {
 396        if ((_ffile[unit].unit = fopen (_ffile[unit].name, mode)) == NO_FILE) {
 397          _srecordf (str, "cannot open unit %d: form=%s, action=%s, disp=%s", unit, form, action, disp);
 398          RTE (where, str);
 399        }
 400      }
 401      rewind (_ffile[unit].unit);
 402    } else {
 403  // File was opened.
 404      if (action == action_read) {
 405        if (_ffile[unit].action == action_write) {
 406          _srecordf (str, "'unit %d' is not open for 'read'", unit);
 407          RTE (where, str);
 408        }
 409      } else if (action == action_write) {
 410        if (_ffile[unit].action == action_read) {
 411          _srecordf (str, "'unit %d' is not open for 'write'", unit);
 412          RTE (where, str);
 413        }
 414      }
 415      if (_ffile[unit].form != form) {
 416        if (form == form_formatted) {
 417          _srecordf (str, "'unit %d' is not open for formatted IO", unit);
 418        } else {
 419          _srecordf (str, "'unit %d' is not open for unformatted IO", unit);
 420        }
 421        RTE (where, str);
 422      }
 423    }
 424  }
 425  
 426  void _fregister (char *where, int_4 unit, int_4 lrecl, char *fn, char *form, char *action, char *disp)
 427  {
 428    if (unit >= 0 && unit < MAX_FILES) {
 429      int_4 len;
 430      if (_ffile[unit].unit != NO_FILE) {
 431        RECORD err;
 432        _srecordf (err, "'unit %d' already open", unit);
 433        RTE (where, err);
 434      }
 435      if (lrecl <= 0 || lrecl > MAX_LRECL) {
 436        lrecl = MAX_LRECL;
 437      }
 438      _ffile[unit] = (FTNFILE) {
 439      .form = form,.action = action,.disp = disp,.lrecl = lrecl};
 440      _ffile[unit].buff = (char *) f_malloc (lrecl + 1);
 441      if (_ffile[unit].in_stream) {
 442        _ffile[unit].buff_init = TRUE;
 443        _ffile[unit].action = action_read;
 444      } else {
 445        _ffile[unit].buff_init = FALSE;
 446      }
 447      _ffile[unit].buff_pos = 0;
 448      if (fn == NO_TEXT) {
 449        RECORD buf;
 450        _ffile[unit].vers++;
 451        _srecordf (buf, "ft%02df%03d", unit, _ffile[unit].vers);
 452        len = strlen (buf) + 1;
 453        _ffile[unit].name = (char *) f_malloc (len);
 454        strcpy (_ffile[unit].name, buf);
 455      } else {
 456        len = strlen (fn) + 1;
 457        _ffile[unit].name = (char *) f_malloc (len);
 458        strcpy (_ffile[unit].name, fn);
 459      }
 460    } else {
 461      RTE (where, "unit out of range");
 462    }
 463  }
 464  
 465  void _funregister (char *where, int_4 unit)
 466  {
 467    if (unit >= 0 && unit < MAX_FILES) {
 468      if (_ffile[unit].unit != NO_FILE) {
 469        _fclose (unit);
 470      }
 471      if (_ffile[unit].disp == disp_delete) {
 472        remove (_ffile[unit].name);
 473      }
 474      if (_ffile[unit].name != NO_TEXT) {
 475        free (_ffile[unit].name);
 476      }
 477      if (_ffile[unit].buff != NO_TEXT) {
 478        free (_ffile[unit].buff);
 479      }
 480      _ffile[unit] = (FTNFILE) {
 481      .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};
 482    } else {
 483      RTE (where, "unit out of range");
 484    }
 485  }
 486  
 487  void _skip_eol (FILE * f)
 488  {
 489    while (fgetc (f) != '\n');
 490  }
 491  
 492  void _ioerr (char *where, int_4 unit)
 493  {
 494    RECORD err;
 495    _srecordf (err, "'unit %d' IO error", unit);
 496    RTE (where, err);
 497  }
 498  
 499  void _ioerr_write (char *where, int_4 unit)
 500  {
 501    RECORD err;
 502    _srecordf (err, "'unit %d' IO error while writing", unit);
 503    RTE (where, err);
 504  }
 505  
 506  void _ioerr_read (char *where, int_4 unit)
 507  {
 508    RECORD err;
 509    _srecordf (err, "'unit %d' IO error while reading", unit);
 510    RTE (where, err);
 511  }
 512  
 513  void _ioend_read (char *where, int_4 unit)
 514  {
 515    RECORD err;
 516    _srecordf (err, "'unit %d' end of file while reading", unit);
 517    RTE (where, err);
 518  }
 519  
 520  void _fprintf_int_8 (char *str, char *fmt, int_8 elem)
 521  {
 522    int_4 len = 0;
 523    if (fmt[0] == '%') {
 524      fmt++;
 525    }
 526    if (isdigit (fmt[0])) {
 527      len = strtol (fmt, NO_REF_TEXT, 10);
 528    }
 529    intnot (str, elem, len);
 530  }
 531  
 532  void _fprintf_real_32 (char *buf, char *fmt, real_32 item, int_4 expw, int_4 precision)
 533  {
 534    int_4 dec = 0, len = 0, expos = 0;
 535    if (fmt[0] == '%') {
 536      fmt++;
 537    }
 538    char expo_char = fmt[strlen (fmt) - 1];
 539    if (expo_char == 'n') {
 540      expo_char = 'e';
 541    } else if (expo_char == 'N') {
 542      expo_char = 'E';
 543    }
 544    char *p1, *p2, *expo;
 545    if (fmt[0] == '.') {
 546      fmt++;
 547      dec = strtol (fmt, &p2, 10);
 548    } else {
 549      len = strtol (fmt, &p1, 10);
 550      dec = strtol (&p1[1], &p2, 10);
 551    }
 552    if (tolower (expo_char) == 'e') {
 553      int_4 ee = strtol (&p2[1], &expo, 10);
 554      expos = (ee == 0 ? expw : ee);
 555    }
 556    if (tolower (expo_char) == 'f') {
 557      xfixed (buf, item, len, dec, precision);
 558    } else if (tolower (expo[0]) == 'n') {
 559      xfloat (buf, item, len, dec, expos, 3, precision, expo_char);
 560    } else {
 561      xfloat (buf, item, len, dec, expos, 1, precision, expo_char);
 562    }
 563    return;
 564  }
 565  
 566  int_4 _vifprintf (int_4 unit, char *fmt, void *elem, int_4 type, int_4 len)
 567  {
 568    FTNFILE *_f = &_ffile[unit];
 569    if (fmt == NO_TEXT || strlen (fmt) == 0) {
 570      return ERR;
 571    }
 572    if (strcmp (fmt, "\n") == 0) {
 573      fprintf (_f->unit, "\n");
 574      return 1;
 575    }
 576    if (fmt != NO_TEXT && type == NOTYPE) {
 577      if (strcmp (fmt, "0") == 0) {
 578        __scale__ = 0;
 579      } else if (strcmp (fmt, "1") == 0) {
 580        __scale__ = 1;
 581      } else if (strcmp (fmt, "2") == 0) {
 582        __scale__ = 2;
 583      } else if (strcmp (fmt, "3") == 0) {
 584        __scale__ = 3;
 585      } else {
 586        fprintf (_f->unit, fmt);
 587      }
 588      return 1;
 589    }
 590  // 
 591    char mod = tolower (fmt[strlen (fmt) - 1]);
 592    if (mod == 's') {
 593      if (type == NOTYPE) {
 594        fprintf (_f->unit, fmt);
 595        return 1;
 596      } else if (type == CHARACTER) {
 597        fprintf (_f->unit, fmt, (char *) elem);
 598        return 1;
 599      } else if (type == LOGICAL) {
 600        fprintf (_f->unit, fmt, (*(int_4 *) elem ? 't' : 'f'));
 601        return 1;
 602      } else if (type == INTEGER && len == 4) {
 603        int_4 awid = len, width;
 604        if (sscanf (fmt, "%%%ds", &width) == 1) {
 605          awid = _abs (width);
 606        }
 607        int_4 sum = *(int_4 *) elem;
 608        for (int_4 k = 0; k < len && k < awid; k++) {
 609          char ch = sum % (UCHAR_MAX + 1);
 610          fprintf (_f->unit, "%c", ch);
 611          sum /= (UCHAR_MAX + 1); 
 612        }
 613        return 1;
 614      } else if (type == REAL && len == 8) {
 615        int_4 awid = len, width;
 616        if (sscanf (fmt, "%%%ds", &width) == 1) {
 617          awid = _abs (width);
 618        }
 619        real_8 sum = *(real_8 *) elem;
 620        for (int_4 k = 0; k < len && k < awid; k++) {
 621          char ch = (int_4) fmod (sum, (UCHAR_MAX + 1));
 622          fprintf (_f->unit, "%c", ch);
 623          sum = floor (sum / (UCHAR_MAX + 1)); 
 624        }
 625        return 1;
 626      } else {
 627        return ERR;
 628      }
 629    } else if (mod == 'c') {
 630      if (type == LOGICAL) {
 631        fprintf (_f->unit, fmt, (*(int_4 *) elem ? 't' : 'f'));
 632      } else {
 633        return ERR;
 634      }
 635      return 1;
 636    } else if (mod == 'd') {
 637  // INTEGER
 638      if (type == INTEGER && len == 2) {
 639        RECORD buf;
 640        RECCLR (buf);
 641        _fprintf_int_8 (buf, fmt, (int_8) *(int_2 *) elem);
 642        fprintf (_f->unit, "%s", buf);
 643      } else if (type == INTEGER && len == 4) {
 644        RECORD buf;
 645        RECCLR (buf);
 646        _fprintf_int_8 (buf, fmt, (int_8) *(int_4 *) elem);
 647        fprintf (_f->unit, "%s", buf);
 648      } else if (type == INTEGER && len == 8) {
 649        RECORD buf;
 650        RECCLR (buf);
 651        _fprintf_int_8 (buf, fmt, (int_8) *(int_8 *) elem);
 652        fprintf (_f->unit, "%s", buf);
 653      } else if (type == INTEGER && len == 16) {
 654        RECORD buf;
 655        RECCLR (buf);
 656        _fprintf_int_8 (buf, fmt, (int_8) *(int_8 *) elem);
 657        fprintf (_f->unit, "%s", buf);
 658      } else {
 659        return ERR;
 660      }
 661      return 1;
 662    } else if (mod == 'e' || mod == 'n' || mod == 'f') {
 663  // REAL and COMPLEX
 664      RECORD str;
 665      RECCLR (str);
 666      if (type == INTEGER && len == 2) {
 667        _fprintf_real_32 (str, fmt, flttox ((real_4) *(int_2 *) elem), 4, FLT_DIG);
 668        fprintf (_f->unit, "%s", str);
 669      } else if (type == INTEGER && len == 4) {
 670        _fprintf_real_32 (str, fmt, dbltox ((real_8) *(int_4 *) elem), 4, FLT_DIG);
 671        fprintf (_f->unit, "%s", str);
 672      } else if (type == INTEGER && len == 8) {
 673        _fprintf_real_32 (str, fmt, dbltox ((real_8) *(int_8 *) elem), 4, FLT_DIG);
 674        fprintf (_f->unit, "%s", str);
 675      } else if (type == REAL && len == 4) {
 676        _fprintf_real_32 (str, fmt, flttox (*(real_4 *) elem), 4, FLT_DIG);
 677        fprintf (_f->unit, "%s", str);
 678      } else if (type == REAL && len == 8) {
 679        _fprintf_real_32 (str, fmt, dbltox (*(real_8 *) elem), 4, DBL_DIG);
 680        fprintf (_f->unit, "%s", str);
 681      } else if (type == REAL && len == 16) {
 682        _fprintf_real_32 (str, fmt, _quadtox (*(real_16 *) elem), 5, FLT128_DIG);
 683        fprintf (_f->unit, "%s", str);
 684      } else if (type == REAL && len == 32) {
 685        _fprintf_real_32 (str, fmt, *(real_32 *) elem, 5, FLT256_DIG);
 686        fprintf (_f->unit, "%s", str);
 687      } else if (type == COMPLEX && len == 8) {
 688        real_4 z = crealf (*(complex_8 *) elem);
 689        _vifprintf (unit, fmt, &z, REAL, 4);
 690      } else if (type == COMPLEX && len == -8) {
 691        real_4 z = cimagf (*(complex_8 *) elem);
 692        _vifprintf (unit, fmt, &z, REAL, 4);
 693      } else if (type == COMPLEX && len == 16) {
 694        real_8 z = creal (*(complex_16 *) elem);
 695        _vifprintf (unit, fmt, &z, REAL, 8);
 696      } else if (type == COMPLEX && len == -16) {
 697        real_8 z = cimag (*(complex_16 *) elem);
 698        _vifprintf (unit, fmt, &z, REAL, 8);
 699      } else if (type == COMPLEX && len == 32) {
 700        real_16 z = crealq (*(complex_32 *) elem);
 701        _vifprintf (unit, fmt, &z, REAL, 16);
 702      } else if (type == COMPLEX && len == -32) {
 703        real_16 z = cimagq (*(complex_32 *) elem);
 704        _vifprintf (unit, fmt, &z, REAL, 16);
 705      } else if (type == COMPLEX && len == 64) {
 706        real_32 z = cxre (*(complex_64 *) elem);
 707        _vifprintf (unit, fmt, &z, REAL, 32);
 708      } else if (type == COMPLEX && len == -64) {
 709        real_32 z = cxim (*(complex_64 *) elem);
 710        _vifprintf (unit, fmt, &z, REAL, 32);
 711      } else {
 712        return ERR;
 713      }
 714      return 1;
 715    }
 716    return ERR;
 717  }
 718  
 719  void _fscanf_real (char *str, FTNFILE * _f, int_4 width, int_4 buflen)
 720  {
 721    while (_f->buff_pos < buflen && _f->buff[_f->buff_pos] == ' ') {
 722      _f->buff_pos++;
 723    }
 724    for (int_4 k = 0; k < width && _f->buff_pos < buflen && _f->buff[_f->buff_pos] != ' '; k++) {
 725      str[k] = _f->buff[_f->buff_pos++];
 726      str[k + 1] = '\0';
 727    }
 728  }
 729  
 730  int_4 _vifscanf (int_4 unit, char *fmt, void *elem, int_4 type, int_4 len)
 731  {
 732    int_4 buflen, width, rc = 0, N = 0;
 733    FTNFILE *_f = &_ffile[unit];
 734  // Set to reinit on next call.
 735    if (fmt == NO_TEXT) {
 736      _f->buff_init = FALSE;
 737      return 1;
 738    }
 739  // (Re)init if needed.
 740    if (!_f->buff_init) {
 741      if (_f->in_stream) {
 742        if (_f->record > 0) {
 743          char *q = _f->buff;
 744          while (q[0] != '\n') {
 745            q++;
 746          }
 747          _f->buff = &q[1];
 748        }
 749      } else {
 750        (void) fgets (_f->buff, _f->lrecl, _f->unit);
 751      }
 752      buflen = _f->buff_len = strlen (_f->buff);
 753      if (_f->buff[buflen - 1] == '\n') {
 754        _f->buff[buflen - 1] = '\0';
 755        _f->buff_len--;
 756      }
 757      _f->buff_init = TRUE;
 758      _f->buff_pos = 0;
 759      _f->record++;
 760    }
 761    buflen = _f->buff_len;
 762  // Reading newline just reinits the buffer.
 763    if (strcmp (fmt, "\n") == 0) {
 764      if (_f->in_stream) {
 765        if (_f->record > 0) {
 766          char *q = _f->buff;
 767          while (q[0] != '\n') {
 768            q++;
 769          }
 770          _f->buff = &q[1];
 771        }
 772      } else {
 773        (void) fgets (_f->buff, _f->lrecl, _f->unit);
 774      }
 775      buflen = _f->buff_len = strlen (_f->buff);
 776      if (_f->buff[buflen - 1] == '\n') {
 777        _f->buff[buflen - 1] = '\0';
 778        _f->buff_len--;
 779      }
 780      _f->buff_init = TRUE;
 781      _f->buff_pos = 0;
 782      _f->record++;
 783      return 1;
 784    }
 785  // Textual strings are skipped and not checked.
 786    if (fmt != NO_TEXT && type == NOTYPE) {
 787      int_4 awid = strlen (fmt);
 788      if (_f->buff_pos + awid < buflen) {
 789        _f->buff_pos += awid;
 790      }
 791      return 1;
 792    }
 793  // Fortran items A, D, E, F, I and Q.
 794    char mod = fmt[strlen (fmt) - 1];
 795    if (mod == 's' && sscanf (fmt, "%%%ds", &width) == 1) {
 796      int_4 awid = _abs (width);
 797      if (type == NOTYPE || elem == NO_TEXT) {
 798        if (_f->buff_pos + awid > buflen) {
 799          return ERR;
 800        }
 801        _f->buff_pos += awid;     // Just skip it. Fortran would check.
 802        return 1;
 803      }
 804      if (type == CHARACTER) {
 805        char *str = (char *) elem;
 806        for (int_4 k = 0; k < awid && _f->buff_pos < buflen; k++) {
 807          str[k] = _f->buff[_f->buff_pos++];
 808        }
 809  // In VIF trailing space is cut.
 810        for (int_4 k = strlen (str) - 1; k > 0 && str[k] == ' '; k--) {
 811          str[k] = '\0';
 812        }
 813        return 1;
 814      } else if (type == INTEGER && len == 4) {
 815        RECORD str;
 816        int_4 k;
 817        for (k = 0; k < awid && _f->buff_pos < buflen; k++) {
 818          str[k] = _f->buff[_f->buff_pos++];
 819        }
 820        str[k] = '\0';
 821        *(int_4 *) elem = _str_to_int4 (str);
 822        return 1;
 823      } else if (type == REAL && len == 8) {
 824        RECORD str;
 825        int_4 k;
 826        for (k = 0; k < awid && _f->buff_pos < buflen; k++) {
 827          str[k] = _f->buff[_f->buff_pos++];
 828        }
 829        str[k] = '\0';
 830        *(real_8 *) elem = _str_to_real8 (str);
 831        return 1;
 832      }
 833      return 0;
 834    }
 835    if (mod == 'c' && strcmp (fmt, "%c") == 0) {
 836      RECORD nfmt;
 837      if (len == 4) {
 838        char ch;
 839        _srecordf (nfmt, "%%c%%n");
 840        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (char *) &ch, &N);
 841        *(logical_4 *) elem = (ch == 't');
 842      }
 843      _f->buff_pos += N;
 844      return rc;
 845    }
 846    if (mod == 'd' && strcmp (fmt, "%d") == 0) {
 847      RECORD nfmt;
 848      if (len == 2) {
 849        int_4 i;
 850        _srecordf (nfmt, "%%d%%n");
 851        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) &i, &N);
 852        *(int_2 *) elem = i;
 853      } else if (len == 4) {
 854        _srecordf (nfmt, "%%d%%n");
 855        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) elem, &N);
 856      } else if (len == 8) {
 857        _srecordf (nfmt, "%%lld%%nn");
 858        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_8 *) elem, &N);
 859      }
 860      _f->buff_pos += N;
 861      return rc;
 862    }
 863    if (mod == 'd' && type == INTEGER && sscanf (fmt, "%%%dd", &width) == 1) {
 864      RECORD nfmt;
 865      int_4 awid = _abs (width);
 866      if (_f->buff_pos + awid > buflen) {
 867        return ERR;
 868      }
 869  // Vintage Fortran reads blanks as zero.
 870      char *q = &_f->buff[_f->buff_pos];
 871      int_4 k = width - 1;
 872      while (k >= 0) {
 873        if (q[k] == ' ') {
 874          q[k] = '0';
 875        } else if (!isdigit(q[k])) {
 876          break;
 877        }
 878        k--;
 879      }
 880  //
 881      if (len == 2) {
 882        int_4 i;
 883        _srecordf (nfmt, "%%%dd", width);
 884        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) &i);
 885        *(int_2 *) elem = i;
 886      } else if (len == 4) {
 887        _srecordf (nfmt, "%%%dd", width);
 888        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) elem);
 889      } else if (len == 8) {
 890        _srecordf (nfmt, "%%%dlld", width);
 891        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_8 *) elem);
 892      }
 893      _f->buff_pos += awid;
 894      return rc;
 895    }
 896  // REAL, standard format
 897    if (type == REAL && strcmp (fmt, "%e") == 0) {
 898      if (len == 4) {
 899        RECORD nfmt;
 900        _srecordf (nfmt, "%%e%%n");
 901        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_4 *) elem, &N);
 902        _f->buff_pos += N;
 903        return rc;
 904      } else if (len == 8) {
 905        RECORD nfmt;
 906        _srecordf (nfmt, "%%le%%n");
 907        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_8 *) elem, &N);
 908        _f->buff_pos += N;
 909        return rc;
 910      } else if (len == 16) {
 911        RECORD str;
 912        RECCLR (str);
 913        _fscanf_real (str, _f, RECLN - 1, buflen);
 914        *(real_16 *) (elem) = _strtoquad (str, NO_REF_TEXT);
 915        return 1;
 916      } else if (len == 32) {
 917        RECORD str;
 918        RECCLR (str);
 919        _fscanf_real (str, _f, RECLN - 1, buflen);
 920        *(real_32 *) (elem) = strtox (str, NO_REF_TEXT);
 921        return 1;
 922      }
 923    }
 924  // REAL, format, note that only width can be specified.
 925    if ((mod == 'e' || mod == 'f') && type == REAL && sscanf (fmt, "%%%d", &width) == 1) {
 926      int_4 awid = _abs (width);
 927      if (_f->buff_pos + awid > buflen) {
 928        return ERR;
 929      }
 930      if (len == 4) {
 931        rc = sscanf (&_f->buff[_f->buff_pos], fmt, (real_4 *) elem);
 932        _f->buff_pos += width;
 933      } else if (len == 8) {
 934        RECORD nfmt;
 935        _srecordf (nfmt, "%%%dl%c", width, mod);
 936        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_8 *) elem);
 937        _f->buff_pos += width;
 938      } else if (len == 16) {
 939        RECORD str;
 940        RECCLR (str);
 941        _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), buflen);
 942        *(real_16 *) (elem) = _strtoquad (str, NO_REF_TEXT);
 943        return 1;
 944      } else if (len == 32) {
 945        RECORD str;
 946        RECCLR (str);
 947        _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), buflen);
 948        *(real_32 *) (elem) = strtox (str, NO_REF_TEXT);
 949        return 1;
 950      }
 951      return rc;
 952    }
 953  // COMPLEX, standard
 954    if (mod == 'e' && type == COMPLEX && strcmp (fmt, "%e") == 0) {
 955      if (_abs (len) == 8) {
 956        RECORD nfmt;
 957        real_4 x;
 958        complex_8 *z = (complex_8 *) elem;
 959        _srecordf (nfmt, "%%e%%n");
 960        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x, &N);
 961        _f->buff_pos += N;
 962        if (len > 0) {
 963          *z = CMPLXF (x, 0);
 964        } else {
 965          *z = CMPLXF (crealf (*z), x);
 966        }
 967        return rc;
 968      } else if (_abs (len) == 16) {
 969        RECORD nfmt;
 970        real_8 x;
 971        complex_16 *z = (complex_16 *) elem;
 972        _srecordf (nfmt, "%%le%%n");
 973        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x, &N);
 974        _f->buff_pos += N;
 975        if (len > 0) {
 976          *z = CMPLX (x, 0);
 977        } else {
 978          *z = CMPLX (creal (*z), x);
 979        }
 980        return rc;
 981      } else if (_abs (len) == 32) {
 982        RECORD str;
 983        RECCLR (str);
 984        complex_32 *z = (complex_32 *) elem;
 985        _fscanf_real (str, _f, RECLN - 1, buflen);
 986        if (len > 0) {
 987          *z = CMPLXQ (_strtoquad (str, NO_REF_TEXT), 0.0q);
 988        } else {
 989          *z = CMPLXQ (crealq (*z), _strtoquad (str, NO_REF_TEXT));
 990        }
 991        return 1;
 992      } else if (_abs (len) == 64) {
 993        RECORD str;
 994        RECCLR (str);
 995        complex_64 *z = (complex_64 *) elem;
 996        _fscanf_real (str, _f, RECLN - 1, buflen);
 997        if (len > 0) {
 998          z->re = strtox (str, NO_REF_TEXT);
 999        } else {
1000          z->im = strtox (str, NO_REF_TEXT);
1001        }
1002        return 1;
1003      }
1004    }
1005  // COMPLEX, format, note that only width can be specified.
1006    if ((mod == 'e' || mod == 'f') && type == COMPLEX && sscanf (fmt, "%%%de", &width) == 1) {
1007      int_4 awid = _abs (width);
1008      if (_f->buff_pos + awid > buflen) {
1009        return ERR;
1010      }
1011      if (_abs (len) == 8) {
1012        real_4 x;
1013        complex_8 *z = (complex_8 *) elem;
1014        rc = sscanf (&_f->buff[_f->buff_pos], fmt, &x);
1015        _f->buff_pos += width;
1016        if (len > 0) {
1017          *z = CMPLXF (x, 0);
1018        } else {
1019          *z = CMPLXF (crealf (*z), x);
1020        }
1021        return rc;
1022      } else if (_abs (len) == 16) {
1023        real_8 x;
1024        complex_16 *z = (complex_16 *) elem;
1025        RECORD nfmt;
1026        _srecordf (nfmt, "%%%dl%c", width, mod);
1027        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x);
1028        _f->buff_pos += width;
1029        if (len > 0) {
1030          *z = CMPLX (x, 0);
1031        } else {
1032          *z = CMPLX (creal (*z), x);
1033        }
1034        return rc;
1035      } else if (_abs (len) == 32) {
1036        RECORD str;
1037        RECCLR (str);
1038        complex_32 *z = (complex_32 *) elem;
1039        _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), buflen);
1040        if (len > 0) {
1041          *z = CMPLXQ (_strtoquad (str, NO_REF_TEXT), 0.0q);
1042        } else {
1043          *z = CMPLXQ (crealq (*z), _strtoquad (str, NO_REF_TEXT));
1044        }
1045        return 1;
1046      } else if (_abs (len) == 64) {
1047        RECORD str;
1048        RECCLR (str);
1049        complex_64 *z = (complex_64 *) elem;
1050        _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), buflen);
1051        if (len > 0) {
1052          z->re = strtox (str, NO_REF_TEXT);
1053        } else {
1054          z->im = strtox (str, NO_REF_TEXT);
1055        }
1056        return 1;
1057      }
1058    }
1059  // No conversion :-(
1060    return ERR;
1061  }
     


© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)