rts-transput.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 _reset_ftnfile (FTNFILE *f)
   185  {
   186    if (f != NO_FTNFILE) {
   187      *f = (FTNFILE) {
   188        .unit = NO_FILE,
   189        .name = NO_TEXT,
   190        .form = NO_TEXT,
   191        .action = NO_TEXT,
   192        .disp = NO_TEXT,
   193        .vers = 0,
   194        .buff = NO_TEXT,
   195        .buff_init = FALSE,
   196        .buff_pos = 0,
   197        .buff_len = 0
   198      };
   199    }
   200  }
   201  
   202  void _funregister (char *where, int_4 unit)
   203  {
   204    FTNFILE *_f = &_ffile[unit];
   205    if (unit >= 0 && unit < MAX_FILES) {
   206      if (_f->unit != NO_FILE) {
   207        _fclose (unit);
   208      }
   209      if (_f->disp == disp_delete) {
   210        remove (_f->name);
   211      }
   212      if (_f->name != NO_TEXT) {
   213        free (_f->name);
   214      }
   215      if (_f->buff != NO_TEXT) {
   216        free (_f->buff);
   217      }
   218      _reset_ftnfile (_f);
   219    } else {
   220      RTE (where, "unit out of range");
   221    }
   222  }
   223  
   224  void _skip_eol (FILE * f)
   225  {
   226    while (fgetc (f) != '\n');
   227  }
   228  
   229  void _ioerr (char *where, int_4 unit)
   230  {
   231    NEW_RECORD (err);
   232    _srecordf (err, "'unit %d': IO error", unit);
   233    RTE (where, err);
   234  }
   235  
   236  void _ioerr_write (char *where, int_4 unit)
   237  {
   238    NEW_RECORD (err);
   239    _srecordf (err, "'unit %d': IO error while writing", unit);
   240    RTE (where, err);
   241  }
   242  
   243  void _ioerr_read (char *where, int_4 unit)
   244  {
   245    NEW_RECORD (err);
   246    _srecordf (err, "'unit %d': IO error while reading", unit);
   247    RTE (where, err);
   248  }
   249  
   250  void _ioend_read (char *where, int_4 unit)
   251  {
   252    NEW_RECORD (err);
   253    _srecordf (err, "'unit %d': end of file while reading", unit);
   254    RTE (where, err);
   255  }
   256  
   257  int_4 _init_file_buffer (int_4 unit)
   258  {
   259    FTNFILE *_f = &_ffile[unit];
   260    if (unit == 0) {
   261      if (_f->record < _f->records) {
   262        // String lengths are powers of 2 in VIF.
   263        int_4 len = 1;
   264        while (len <= _f->lrecl) {
   265          len *= 2;
   266        }
   267        _f->buff = &((_ffile[0].rewind)[_f->record * len]);
   268        _f->buff_init = TRUE;
   269        _f->buff_pos = 0;
   270        _f->buff_len = strlen (_f->buff);
   271        _f->record++;
   272        return 0;
   273      } else {
   274        _f->buff = NO_TEXT;
   275        _f->buff_init = FALSE;
   276        _f->buff_pos = 0;
   277        _f->buff_len = 0;
   278        return 1;
   279      }
   280    } else {
   281      if (_f->in_stream) {
   282        if (_f->record > 1) {
   283          char *q = _f->buff;
   284          while (q[0] != '\n') {
   285            q++;
   286          }
   287          _f->buff = &q[1];
   288        }
   289      } else {
   290        (void) fgets (_f->buff, _f->lrecl, _f->unit);
   291      }
   292      _f->buff_len = strlen (_f->buff);
   293      if (_f->buff[_f->buff_len - 1] == '\n') {
   294        _f->buff[_f->buff_len - 1] = '\0';
   295        _f->buff_len--;
   296      }
   297      _f->buff_init = TRUE;
   298      _f->buff_pos = 0;
   299      _f->record++;
   300      return 0;
   301    }
   302  }
   303  
   304  int_4 _rewind (char *where, int_4 unit)
   305  {
   306    FTNFILE *_f = &_ffile[unit];
   307    if (unit == 0) {
   308      _f->record = 0;
   309      _init_file_buffer (0);
   310    } else if (_f != NO_FTNFILE) {
   311      if (_f->in_stream) {
   312        _f->buff = _f->rewind;
   313      } else {
   314        rewind (_f->unit);
   315      }
   316      _f->buff_pos = 0;
   317      _f->record = 1;
   318    } 
   319    if (_f == NO_FTNFILE || errno != 0) {
   320      RECORD buf;
   321      _srecordf (buf, "cannot rewind unit %d", unit);
   322      RTE (where, buf);
   323    }
   324    return 0;
   325  }
   326  
   327  int_4 _set_record (char *where, int_4 unit, int_4 rec)
   328  {
   329    FTNFILE *_f = &_ffile[unit];
   330    if (unit == 0) {
   331      _f->record = rec - 1;
   332      _init_file_buffer (0);
   333    } else if (_f != NO_FTNFILE) {
   334      _rewind (where, unit);
   335      _init_file_buffer (unit);
   336      for (int_4 k = 1; k < rec; k++) {
   337        _init_file_buffer (unit);
   338      }
   339    }
   340    if (_f == NO_FTNFILE || errno != 0) {
   341      RECORD buf;
   342      _srecordf (buf, "cannot set record on unit %d", unit);
   343      RTE (where, buf);
   344    }
   345    return 0;
   346  }
   347  
   348  int_4 _backspace (char *where, int_4 unit)
   349  {
   350    FTNFILE *_f = &_ffile[unit];
   351    _set_record (where, unit, _f->record - 1);
   352    if (_f == NO_FTNFILE || errno != 0) {
   353      RECORD buf;
   354      _srecordf (buf, "cannot backspace unit %d", unit);
   355      RTE (where, buf);
   356    }
   357    return 0;
   358  }


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