rts-format.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 formatted 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  // __scale__ is set by nP in formats.
    36  
    37  int_4 __scale__ = 1;
    38  
    39  void _fclose (int_4 k)
    40  {
    41    if (_ffile[k].unit != NO_FILE) {
    42      (void) fclose (_ffile[k].unit);
    43      _ffile[k].unit = NO_FILE;
    44    }
    45  }
    46  
    47  static char *plusab (char *buf, char c)
    48  {
    49    char z[2];
    50    z[0] = c;
    51    z[1] = '\0';
    52    bufcat (buf, z, RECLN);
    53    return buf;
    54  }
    55  
    56  static char *plusto (char ch, char *buf)
    57  {
    58    memmove (&buf[1], &buf[0], strlen(buf) + 1);
    59    buf[0] = ch;
    60    return buf;
    61  }
    62  
    63  static char *leading_spaces (char *buf, int_4 width)
    64  {
    65    if (width > 0) {
    66      int_4 j = ABS (width) - (int_4) strlen (buf);
    67      while (--j >= 0) {
    68        (void) plusto (' ', buf);
    69      }
    70    }
    71    return buf;
    72  }
    73  
    74  static char *error_chars (char *buf, int_4 n)
    75  {
    76    int_4 k = (n != 0 ? ABS (n) : 1);
    77    buf[k] = '\0';
    78    while (--k >= 0) {
    79      buf[k] = ERROR_CHAR;
    80    }
    81    return buf;
    82  }
    83  
    84  static char digchar (int_4 k)
    85  {
    86    char *tab = "0123456789abcdefghijklmnopqrstuvwxyz";
    87    if (k >= 0 && k < (int_4) strlen (tab)) {
    88      return tab[k];
    89    } else {
    90      return ERROR_CHAR;
    91    }
    92  }
    93  
    94  // INTEGER*8
    95  
    96  char *intnot (char *buf, int_8 k, int_4 width)
    97  {
    98    int_8 n = ABS (k);
    99    buf[0] = '\0';
   100    do {
   101      (void) plusto (digchar (n % 10), buf);
   102      n /= 10;
   103    } while (n != 0);
   104    if (k < 0) {
   105      (void) plusto ('-', buf);
   106    }
   107    if (width > 0 && strlen (buf) > width) {
   108      (void) error_chars (buf, width);
   109    } else {
   110      (void) leading_spaces (buf, width);
   111    }
   112    return buf;
   113  }
   114  
   115  // REAL*32
   116  
   117  void xsprintfmt (char *buffer, const char *fmt, ...)
   118  {
   119    NEW_RECORD (ibuff);
   120    va_list ap;
   121    va_start (ap, fmt);
   122    vsprintf (ibuff, fmt, ap);
   123    va_end (ap);
   124    strcat (buffer, ibuff);
   125  }
   126  
   127  static int_4 special_value (char *s, real_32 u, int_4 sign)
   128  {
   129    if ((xis_pinf (&u))) {
   130      if (sign != 0) {
   131        *s++ = '+';
   132      }
   133      strcpy (s, "Inf");
   134      return 1;
   135    } else if ((xis_minf (&u))) {
   136      strcpy (s, "-Inf");
   137      return 1;
   138    } else if ((xis_nan (&u))) {
   139      if (sign != 0) {
   140        *s++ = '\?';
   141      }
   142      strcpy (s, "NaN");
   143      return 1;
   144    } else {
   145      return 0;
   146    }
   147  }
   148  
   149  char *xsubfixed (char *buffer, real_32 v, logical_4 sign, int_4 digs)
   150  {
   151    RECCLR (buffer);
   152    if ((special_value (buffer, v, sign))) {
   153      return buffer;
   154    }
   155    real_32 u = v;
   156    digs = _min (_abs (digs), FLT256_DIG);
   157  // Put sign and take abs value.
   158    char *p = buffer;
   159    if (xlt (u, X_0)) {
   160      u = xneg (u);
   161      *(p++) = '-';
   162    } else if (sign) {
   163      *(p++) = '+';
   164    } else {
   165      *(p++) = ' ';
   166    }
   167  // Round fraction
   168    real_32 eps = xmul(X_1_OVER_2, xtenup (-digs));
   169    u = xsum (u, eps);
   170  //
   171    int_4 before;
   172    if (xlt (u, X_10)) {
   173      before = 1;
   174    } else if (xlt (u, X_100)) {
   175      before = 2;
   176    } else if (xlt (u, X_1000)) {
   177      before = 3;
   178    } else {
   179      before = (int_4) ceil (xtodbl (xlog10 (u)));
   180    }
   181  //  Integral part.
   182    u = xdiv (u, xtenup (before));
   183    while (xge (u, X_1)) {
   184      u = xdiv (u, X_10);
   185      before++;
   186    }
   187    for (int_4 k = 0; k < before; ++k) {
   188      u = xmul (X_10, u);
   189      int_4 dig;
   190      u = xsfmod (u, &dig);
   191      *(p++) = (char) '0' + dig;
   192    }
   193  // Fraction.
   194    *(p++) = '.';
   195    for (int_4 k = 0; k < digs; ++k) {
   196      u = xmul (X_10, u);
   197      int_4 dig;
   198      u = xsfmod (u, &dig);
   199      *(p++) = (char) '0' + dig;
   200    }
   201    return buffer;
   202  }
   203  
   204  char *xfixed (char *buf, real_32 x, int_4 width, int_4 digs, int_4 precision)
   205  {
   206    width = _abs (width);
   207    digs = _min (abs (digs), precision);
   208    xsubfixed (buf, x, FALSE, digs);
   209    if (width > 0 && strlen (buf) > width) {
   210      return error_chars (buf, width);
   211    } else {
   212      return leading_spaces (buf, width);
   213    }
   214  }
   215  
   216  char *xfloat (char *buf, real_32 z, int_4 width, int_4 digs, int_4 expos, int_4 mult, int_4 precision, char sym)
   217  {
   218    buf[0] = '\0';
   219    width = _abs (width);
   220    digs = _min (abs (digs), precision);
   221    expos = _abs (expos);
   222    if (expos > 5) {
   223      return error_chars (buf, width);
   224    }
   225  // Scientific notation mult = 1, Engineering notation mult = 3
   226    mult = _max (1, mult);
   227  // Default __scale__ is 1.
   228    int_4 q = 1;
   229    char *max = "1";
   230    real_32 x = xabs (z), lwb, upb;
   231  //
   232    if (__scale__ < 0 || __scale__ > 3) {
   233      __scale__ = 1;
   234    }
   235    if (mult == 1) {
   236      if (__scale__ == 0) {
   237        lwb = X_1_OVER_10;
   238        upb = X_1;
   239        q = 1;
   240        max = "0.1";
   241      } else if (__scale__ == 1) {
   242        lwb = X_1;
   243        upb = X_10;
   244        q = 0;
   245        max = "1";
   246      } else if (__scale__ == 2) {
   247        lwb = X_10;
   248        upb = X_100;
   249        q = -1;
   250        max = "10";
   251      } else if (__scale__ == 3) {
   252        lwb = X_100;
   253        upb = X_1000;
   254        max = "100";
   255        q = -2;
   256      }
   257    }
   258  // Standardize.
   259    int_4 p = 0;
   260    if (xnot0 (&x)) {
   261      p = (int_4) round (xtodbl (xlog10 (xabs(x)))) + q;
   262      x = xdiv (x, xtenup (p));
   263      if (xle (x, lwb)) {
   264        x = xmul (x, X_10);
   265        p--;
   266      } 
   267      if (xge (x, upb)) {
   268        x = xdiv (x, X_10);
   269        p++;
   270      } 
   271      while (p % mult != 0) {
   272        x = xmul (x, X_10);
   273        p--;
   274      }
   275    }
   276  // Form number.
   277    NEW_RECORD (mant);
   278    xsubfixed (mant, x, FALSE, digs);
   279  // Correction of rounding issue by which |mant| equals UPB.
   280    if (strchr (mant, ERROR_CHAR) == NO_TEXT && xge (xabs (strtox (mant, NO_REF_TEXT)), upb)) {
   281      if (mant[0] == ' ' || mant[0] == '+') {
   282        _srecordf (mant, "%c%s", mant[0], max);
   283      } else {
   284        _srecordf (mant, "%s", max);
   285      }
   286      if (digs > 0) {
   287        plusab (mant, '.');
   288        for (int_4 k = 0; k < digs; k++) {
   289          plusab (mant, '0');
   290        }
   291      }
   292      p++;
   293    }
   294  //
   295    NEW_RECORD (fmt);
   296    if (xsgn (&z) < 0) {
   297      mant[0] = '-';
   298    }
   299  // In the distant past, exponents usually were double-digit at most.
   300    if (_abs (p) < 100) {
   301      expos = _min (3, expos);
   302    } else if (_abs (p) < 1000) {
   303      expos = _min (4, expos);
   304    }
   305    _srecordf (fmt, "%%s%c%%+0%dd", sym, expos);
   306    _srecordf (buf, fmt, mant, p);
   307    int_4 xs = strlen (buf) - width;
   308    if (width > 0 && (strchr (buf, ERROR_CHAR) != NO_TEXT || xs > 0)) {
   309      int_4 ndigs = digs - xs;
   310      if (ndigs >= 0) {
   311        return xfloat (buf, z, width, ndigs, expos, mult, precision, sym);
   312      } else {
   313        return error_chars (buf, width);
   314      }
   315    } else {
   316      return leading_spaces (buf, width);
   317    }
   318  }
   319  
   320  void _fprintf_int_8 (char *str, char *fmt, int_8 elem)
   321  {
   322    int_4 len = 0;
   323    if (fmt[0] == '%') {
   324      fmt++;
   325    }
   326    if (isdigit (fmt[0])) {
   327      len = strtol (fmt, NO_REF_TEXT, 10);
   328    }
   329    intnot (str, elem, len);
   330  }
   331  
   332  void _fprintf_real_32 (char *buf, char *fmt, real_32 item, int_4 expw, int_4 precision)
   333  {
   334    int_4 dec = 0, len = 0, expos = 0;
   335    if (fmt[0] == '%') {
   336      fmt++;
   337    }
   338    char expo_char = fmt[strlen (fmt) - 1];
   339    if (expo_char == 'n') {
   340      expo_char = 'e';
   341    } else if (expo_char == 'N') {
   342      expo_char = 'E';
   343    }
   344    char *p1, *p2, *expo;
   345    if (fmt[0] == '.') {
   346      fmt++;
   347      dec = strtol (fmt, &p2, 10);
   348    } else {
   349      len = strtol (fmt, &p1, 10);
   350      dec = strtol (&p1[1], &p2, 10);
   351    }
   352    if (tolower (expo_char) == 'e') {
   353      int_4 ee = strtol (&p2[1], &expo, 10);
   354      expos = (ee == 0 ? expw : ee);
   355    }
   356    if (tolower (expo_char) == 'f') {
   357      xfixed (buf, item, len, dec, precision);
   358    } else if (tolower (expo[0]) == 'n') {
   359      xfloat (buf, item, len, dec, expos, 3, precision, expo_char);
   360    } else {
   361      xfloat (buf, item, len, dec, expos, 1, precision, expo_char);
   362    }
   363    return;
   364  }
   365  
   366  int_4 _vif_printf (int_4 unit, char *fmt, void *elem, int_4 type, int_4 len)
   367  {
   368    FTN_FILE *_f = _get_ftn_file (NO_TEXT, unit);
   369    if (fmt == NO_TEXT) {
   370      return ERR;
   371    }
   372    if (fmt == FMT_TERM) {
   373      return 1;
   374    }
   375    if (strlen (fmt) == 0) {
   376      return 1;
   377    }
   378    if (strcmp (fmt, "\n") == 0) {
   379      fprintf (_f->unit, "\n");
   380      return 1;
   381    }
   382    if (fmt != NO_TEXT && type == NOTYPE) {
   383      if (strcmp (fmt, "0") == 0) {
   384        __scale__ = 0;
   385      } else if (strcmp (fmt, "1") == 0) {
   386        __scale__ = 1;
   387      } else if (strcmp (fmt, "2") == 0) {
   388        __scale__ = 2;
   389      } else if (strcmp (fmt, "3") == 0) {
   390        __scale__ = 3;
   391      } else {
   392        fprintf (_f->unit, "%s", fmt);
   393      }
   394      return 1;
   395    }
   396  // 
   397    char mod = tolower (fmt[strlen (fmt) - 1]);
   398    if (mod == 's') {
   399      if (type == NOTYPE) {
   400        fprintf (_f->unit, "%s", fmt);
   401        return 1;
   402      } else if (type == CHARACTER) {
   403        fprintf (_f->unit, fmt, (char *) elem);
   404        return 1;
   405      } else if (type == LOGICAL) {
   406        fprintf (_f->unit, fmt, (*(int_4 *) elem ? 't' : 'f'));
   407        return 1;
   408      } else if (type == INTEGER && len == 4) {
   409        int_4 awid = len, width;
   410        if (sscanf (fmt, "%%%ds", &width) == 1) {
   411          awid = _abs (width);
   412        }
   413        int_4 sum = *(int_4 *) elem;
   414        for (int_4 k = 0; k < len && k < awid; k++) {
   415          char ch = sum % (UCHAR_MAX + 1);
   416          fprintf (_f->unit, "%c", ch);
   417          sum /= (UCHAR_MAX + 1); 
   418        }
   419        return 1;
   420      } else if (type == REAL && len == 8) {
   421        int_4 awid = len, width;
   422        if (sscanf (fmt, "%%%ds", &width) == 1) {
   423          awid = _abs (width);
   424        }
   425        real_8 sum = *(real_8 *) elem;
   426        for (int_4 k = 0; k < len && k < awid; k++) {
   427          char ch = (int_4) fmod (sum, (UCHAR_MAX + 1));
   428          fprintf (_f->unit, "%c", ch);
   429          sum = floor (sum / (UCHAR_MAX + 1)); 
   430        }
   431        return 1;
   432      } else {
   433        return ERR;
   434      }
   435    } else if (mod == 'c') {
   436      if (type == LOGICAL) {
   437        fprintf (_f->unit, fmt, (*(int_4 *) elem ? 't' : 'f'));
   438      } else {
   439        return ERR;
   440      }
   441      return 1;
   442    } else if (mod == 'd') {
   443  // INTEGER
   444      if (type == INTEGER && len == 2) {
   445        NEW_RECORD (buf);
   446        _fprintf_int_8 (buf, fmt, (int_8) *(int_2 *) elem);
   447        fprintf (_f->unit, "%s", buf);
   448      } else if (type == INTEGER && len == 4) {
   449        NEW_RECORD (buf);
   450        _fprintf_int_8 (buf, fmt, (int_8) *(int_4 *) elem);
   451        fprintf (_f->unit, "%s", buf);
   452      } else if (type == INTEGER && len == 8) {
   453        NEW_RECORD (buf);
   454        _fprintf_int_8 (buf, fmt, (int_8) *(int_8 *) elem);
   455        fprintf (_f->unit, "%s", buf);
   456      } else if (type == INTEGER && len == 16) {
   457        NEW_RECORD (buf);
   458        _fprintf_int_8 (buf, fmt, (int_8) *(int_8 *) elem);
   459        fprintf (_f->unit, "%s", buf);
   460      } else {
   461        return ERR;
   462      }
   463      return 1;
   464    } else if (mod == 'e' || mod == 'n' || mod == 'f') {
   465  // REAL and COMPLEX
   466      NEW_RECORD (buf);
   467      if (type == INTEGER && len == 2) {
   468        _fprintf_real_32 (buf, fmt, flttox ((real_4) *(int_2 *) elem), 4, FLT_DIG);
   469        fprintf (_f->unit, "%s", buf);
   470      } else if (type == INTEGER && len == 4) {
   471        _fprintf_real_32 (buf, fmt, dbltox ((real_8) *(int_4 *) elem), 4, FLT_DIG);
   472        fprintf (_f->unit, "%s", buf);
   473      } else if (type == INTEGER && len == 8) {
   474        _fprintf_real_32 (buf, fmt, dbltox ((real_8) *(int_8 *) elem), 4, FLT_DIG);
   475        fprintf (_f->unit, "%s", buf);
   476      } else if (type == REAL && len == 4) {
   477        _fprintf_real_32 (buf, fmt, flttox (*(real_4 *) elem), 4, FLT_DIG);
   478        fprintf (_f->unit, "%s", buf);
   479      } else if (type == REAL && len == 8) {
   480        _fprintf_real_32 (buf, fmt, dbltox (*(real_8 *) elem), 4, DBL_DIG);
   481        fprintf (_f->unit, "%s", buf);
   482      } else if (type == REAL && len == 16) {
   483        _fprintf_real_32 (buf, fmt, quadtox (*(real_16 *) elem), 5, FLT128_DIG);
   484        fprintf (_f->unit, "%s", buf);
   485      } else if (type == REAL && len == 32) {
   486        _fprintf_real_32 (buf, fmt, *(real_32 *) elem, 5, FLT256_DIG);
   487        fprintf (_f->unit, "%s", buf);
   488      } else if (type == COMPLEX && len == 8) {
   489        real_4 z = crealf (*(complex_8 *) elem);
   490        _vif_printf (unit, fmt, &z, REAL, 4);
   491      } else if (type == COMPLEX && len == -8) {
   492        real_4 z = cimagf (*(complex_8 *) elem);
   493        _vif_printf (unit, fmt, &z, REAL, 4);
   494      } else if (type == COMPLEX && len == 16) {
   495        real_8 z = creal (*(complex_16 *) elem);
   496        _vif_printf (unit, fmt, &z, REAL, 8);
   497      } else if (type == COMPLEX && len == -16) {
   498        real_8 z = cimag (*(complex_16 *) elem);
   499        _vif_printf (unit, fmt, &z, REAL, 8);
   500      } else if (type == COMPLEX && len == 32) {
   501        real_16 z = crealq (*(complex_32 *) elem);
   502        _vif_printf (unit, fmt, &z, REAL, 16);
   503      } else if (type == COMPLEX && len == -32) {
   504        real_16 z = cimagq (*(complex_32 *) elem);
   505        _vif_printf (unit, fmt, &z, REAL, 16);
   506      } else if (type == COMPLEX && len == 64) {
   507        real_32 z = cxreal (*(complex_64 *) elem);
   508        _vif_printf (unit, fmt, &z, REAL, 32);
   509      } else if (type == COMPLEX && len == -64) {
   510        real_32 z = cximag (*(complex_64 *) elem);
   511        _vif_printf (unit, fmt, &z, REAL, 32);
   512      } else {
   513        return ERR;
   514      }
   515      return 1;
   516    }
   517    return ERR;
   518  }
   519  
   520  void _fscanf_real (char *str, FTN_FILE * _f, int_4 width, int_4 buflen)
   521  {
   522    while (_f->buff_pos < buflen && _f->buff[_f->buff_pos] == ' ') {
   523      _f->buff_pos++;
   524    }
   525    for (int_4 k = 0; k < width && _f->buff_pos < buflen && _f->buff[_f->buff_pos] != ' '; k++) {
   526      str[k] = _f->buff[_f->buff_pos++];
   527      str[k + 1] = '\0';
   528    }
   529  }
   530  
   531  int_4 _vif_scanf (int_4 unit, char *fmt, void *elem, int_4 type, int_4 len)
   532  {
   533    int_4 width = 0, rc = 0, N = 0;
   534    FTN_FILE *_f = _get_ftn_file (NO_TEXT, unit);
   535  // A NOP.
   536    if (fmt == FMT_TERM) {
   537      return 1;
   538    }
   539  // Re-init on next call.
   540    if (fmt == NO_TEXT) {
   541      _f->buff_init = FALSE;
   542      return 1;
   543    }
   544    if (strlen (fmt) == 0) {
   545      return 1;
   546    }
   547  // (Re)init if needed.
   548    if (!_f->buff_init) {
   549      _init_file_buffer (unit);
   550    } 
   551    if (strcmp (fmt, "\n") == 0) {
   552  // Reading newline just reinits the buffer.
   553      _init_file_buffer (unit);
   554      return 1;
   555    }
   556  // Textual strings are skipped and not checked.
   557    if (fmt != NO_TEXT && type == NOTYPE) {
   558      int_4 awid = strlen (fmt);
   559      if (_f->buff_pos + awid < _f->buff_len) {
   560        _f->buff_pos += awid;
   561      }
   562      return 1;
   563    }
   564  // Fortran items A, D, E, F, I and Q.
   565    char mod = fmt[strlen (fmt) - 1];
   566    if (mod == 's' && sscanf (fmt, "%%%ds", &width) == 1) {
   567      int_4 awid = _abs (width);
   568      if (type == NOTYPE || elem == NO_TEXT) {
   569        if (_f->buff_pos + awid > _f->buff_len) {
   570          return ERR;
   571        }
   572        _f->buff_pos += awid;     // Just skip it. Fortran would check.
   573        return 1;
   574      }
   575      if (type == CHARACTER) {
   576        char *str = (char *) elem;
   577        for (int_4 k = 0; k < awid && _f->buff_pos < _f->buff_len; k++) {
   578          str[k] = _f->buff[_f->buff_pos++];
   579        }
   580  // In VIF trailing space is cut.
   581        for (int_4 k = strlen (str) - 1; k > 0 && str[k] == ' '; k--) {
   582          str[k] = '\0';
   583        }
   584        return 1;
   585      } else if (type == INTEGER && len == 4) {
   586        NEW_RECORD (str);
   587        int_4 k;
   588        for (k = 0; k < awid && _f->buff_pos < _f->buff_len; k++) {
   589          str[k] = _f->buff[_f->buff_pos++];
   590        }
   591        str[k] = '\0';
   592        *(int_4 *) elem = _str_to_int4 (str);
   593        return 1;
   594      } else if (type == REAL && len == 8) {
   595        NEW_RECORD (str);
   596        int_4 k;
   597        for (k = 0; k < awid && _f->buff_pos < _f->buff_len; k++) {
   598          str[k] = _f->buff[_f->buff_pos++];
   599        }
   600        str[k] = '\0';
   601        *(real_8 *) elem = _str_to_real8 (str);
   602        return 1;
   603      }
   604      return 0;
   605    }
   606    if (mod == 'c' && strcmp (fmt, "%c") == 0) {
   607      NEW_RECORD (nfmt);
   608      if (len == 4) {
   609        char ch;
   610        _srecordf (nfmt, "%%c%%n");
   611        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (char *) &ch, &N);
   612        *(logical_4 *) elem = (ch == 't');
   613      }
   614      _f->buff_pos += N;
   615      return rc;
   616    }
   617    if (mod == 'd' && strcmp (fmt, "%d") == 0) {
   618      NEW_RECORD (nfmt);
   619      if (len == 2) {
   620        int_4 i;
   621        _srecordf (nfmt, "%%d%%n");
   622        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) &i, &N);
   623        *(int_2 *) elem = i;
   624      } else if (len == 4) {
   625        _srecordf (nfmt, "%%d%%n");
   626        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) elem, &N);
   627      } else if (len == 8) {
   628        _srecordf (nfmt, "%%lld%%nn");
   629        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_8 *) elem, &N);
   630      }
   631      _f->buff_pos += N;
   632      return rc;
   633    }
   634    if (mod == 'd' && type == INTEGER && sscanf (fmt, "%%%dd", &width) == 1) {
   635      NEW_RECORD (nfmt);
   636      int_4 awid = _abs (width);
   637      if (_f->buff_pos + awid > _f->buff_len) {
   638        return ERR;
   639      }
   640  // Vintage Fortran reads blanks as zero.
   641      char *q = &_f->buff[_f->buff_pos];
   642      int_4 k = width - 1;
   643      while (k >= 0) {
   644        if (q[k] == ' ') {
   645          q[k] = '0';
   646        } else if (!isdigit(q[k])) {
   647          break;
   648        }
   649        k--;
   650      }
   651  //
   652      if (len == 2) {
   653        int_4 i;
   654        _srecordf (nfmt, "%%%dd", width);
   655        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) &i);
   656        *(int_2 *) elem = i;
   657      } else if (len == 4) {
   658        _srecordf (nfmt, "%%%dd", width);
   659        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_4 *) elem);
   660      } else if (len == 8) {
   661        _srecordf (nfmt, "%%%dlld", width);
   662        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (int_8 *) elem);
   663      }
   664      _f->buff_pos += awid;
   665      return rc;
   666    }
   667  // REAL, standard format
   668    if (type == REAL && strcmp (fmt, "%e") == 0) {
   669      if (len == 4) {
   670        NEW_RECORD (nfmt);
   671        _srecordf (nfmt, "%%e%%n");
   672        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_4 *) elem, &N);
   673        _f->buff_pos += N;
   674        return rc;
   675      } else if (len == 8) {
   676        NEW_RECORD (nfmt);
   677        _srecordf (nfmt, "%%le%%n");
   678        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_8 *) elem, &N);
   679        _f->buff_pos += N;
   680        return rc;
   681      } else if (len == 16) {
   682        NEW_RECORD (str);
   683        _fscanf_real (str, _f, RECLN - 1, _f->buff_len);
   684        *(real_16 *) (elem) = _strtoquad (str, NO_REF_TEXT);
   685        return 1;
   686      } else if (len == 32) {
   687        NEW_RECORD (str);
   688        _fscanf_real (str, _f, RECLN - 1, _f->buff_len);
   689        *(real_32 *) (elem) = strtox (str, NO_REF_TEXT);
   690        return 1;
   691      }
   692    }
   693  // REAL, format, note that only width can be specified.
   694    if ((mod == 'e' || mod == 'f') && type == REAL && sscanf (fmt, "%%%d", &width) == 1) {
   695      int_4 awid = _abs (width);
   696      if (_f->buff_pos + awid > _f->buff_len) {
   697        return ERR;
   698      }
   699      if (len == 4) {
   700        rc = sscanf (&_f->buff[_f->buff_pos], fmt, (real_4 *) elem);
   701        _f->buff_pos += width;
   702      } else if (len == 8) {
   703        NEW_RECORD (nfmt);
   704        _srecordf (nfmt, "%%%dl%c", width, mod);
   705        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, (real_8 *) elem);
   706        _f->buff_pos += width;
   707      } else if (len == 16) {
   708        NEW_RECORD (str);
   709        _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), _f->buff_len);
   710        *(real_16 *) (elem) = _strtoquad (str, NO_REF_TEXT);
   711        return 1;
   712      } else if (len == 32) {
   713        NEW_RECORD (str);
   714        _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), _f->buff_len);
   715        *(real_32 *) (elem) = strtox (str, NO_REF_TEXT);
   716        return 1;
   717      }
   718      return rc;
   719    }
   720  // COMPLEX, standard
   721    if (mod == 'e' && type == COMPLEX && strcmp (fmt, "%e") == 0) {
   722      if (_abs (len) == 8) {
   723        NEW_RECORD (nfmt);
   724        real_4 x;
   725        complex_8 *z = (complex_8 *) elem;
   726        _srecordf (nfmt, "%%e%%n");
   727        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x, &N);
   728        _f->buff_pos += N;
   729        if (len > 0) {
   730          *z = CMPLXF (x, 0);
   731        } else {
   732          *z = CMPLXF (crealf (*z), x);
   733        }
   734        return rc;
   735      } else if (_abs (len) == 16) {
   736        NEW_RECORD (nfmt);
   737        real_8 x;
   738        complex_16 *z = (complex_16 *) elem;
   739        _srecordf (nfmt, "%%le%%n");
   740        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x, &N);
   741        _f->buff_pos += N;
   742        if (len > 0) {
   743          *z = CMPLX (x, 0);
   744        } else {
   745          *z = CMPLX (creal (*z), x);
   746        }
   747        return rc;
   748      } else if (_abs (len) == 32) {
   749        NEW_RECORD (str);
   750        complex_32 *z = (complex_32 *) elem;
   751        _fscanf_real (str, _f, RECLN - 1, _f->buff_len);
   752        if (len > 0) {
   753          *z = CMPLXQ (_strtoquad (str, NO_REF_TEXT), 0.0q);
   754        } else {
   755          *z = CMPLXQ (crealq (*z), _strtoquad (str, NO_REF_TEXT));
   756        }
   757        return 1;
   758      } else if (_abs (len) == 64) {
   759        NEW_RECORD (str);
   760        complex_64 *z = (complex_64 *) elem;
   761        _fscanf_real (str, _f, RECLN - 1, _f->buff_len);
   762        if (len > 0) {
   763          z->re = strtox (str, NO_REF_TEXT);
   764        } else {
   765          z->im = strtox (str, NO_REF_TEXT);
   766        }
   767        return 1;
   768      }
   769    }
   770  // COMPLEX, format, note that only width can be specified.
   771    if ((mod == 'e' || mod == 'f') && type == COMPLEX && sscanf (fmt, "%%%de", &width) == 1) {
   772      int_4 awid = _abs (width);
   773      if (_f->buff_pos + awid > _f->buff_len) {
   774        return ERR;
   775      }
   776      if (_abs (len) == 8) {
   777        real_4 x;
   778        complex_8 *z = (complex_8 *) elem;
   779        rc = sscanf (&_f->buff[_f->buff_pos], fmt, &x);
   780        _f->buff_pos += width;
   781        if (len > 0) {
   782          *z = CMPLXF (x, 0);
   783        } else {
   784          *z = CMPLXF (crealf (*z), x);
   785        }
   786        return rc;
   787      } else if (_abs (len) == 16) {
   788        real_8 x;
   789        complex_16 *z = (complex_16 *) elem;
   790        NEW_RECORD (nfmt);
   791        _srecordf (nfmt, "%%%dl%c", width, mod);
   792        rc = sscanf (&_f->buff[_f->buff_pos], nfmt, &x);
   793        _f->buff_pos += width;
   794        if (len > 0) {
   795          *z = CMPLX (x, 0);
   796        } else {
   797          *z = CMPLX (creal (*z), x);
   798        }
   799        return rc;
   800      } else if (_abs (len) == 32) {
   801        NEW_RECORD (str);
   802        complex_32 *z = (complex_32 *) elem;
   803        _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), _f->buff_len);
   804        if (len > 0) {
   805          *z = CMPLXQ (_strtoquad (str, NO_REF_TEXT), 0.0q);
   806        } else {
   807          *z = CMPLXQ (crealq (*z), _strtoquad (str, NO_REF_TEXT));
   808        }
   809        return 1;
   810      } else if (_abs (len) == 64) {
   811        NEW_RECORD (str);
   812        complex_64 *z = (complex_64 *) elem;
   813        _fscanf_real (str, _f, (awid > RECLN - 1 ? RECLN - 1 : awid), _f->buff_len);
   814        if (len > 0) {
   815          z->re = strtox (str, NO_REF_TEXT);
   816        } else {
   817          z->im = strtox (str, NO_REF_TEXT);
   818        }
   819        return 1;
   820      }
   821    }
   822  // No conversion :-(
   823    return ERR;
   824  }


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