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  FTN_FILE _ffile[MAX_FTN_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    FTN_FILE *_f = _get_ftn_file (where, unit);
    46    NEW_RECORD (str);
    47    __scale__ = 1;
    48    if (unit < 0 || unit >= MAX_FTN_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    FTN_FILE *_f = _get_ftn_file (where, unit);
   147    if (unit >= 0 && unit < MAX_FTN_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] = (FTN_FILE) {
   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_ftn_file (FTN_FILE *f)
   185  {
   186    if (f != NO_FTN_FILE) {
   187      *f = (FTN_FILE) {
   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    FTN_FILE *_f = _get_ftn_file (where, unit);
   205    if (unit >= 0 && unit < MAX_FTN_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_ftn_file (_f);
   219    } else {
   220      RTE (where, "unit out of range");
   221    }
   222  }
   223  
   224  FTN_FILE *_get_ftn_file (char *where, int_4 unit)
   225  {
   226    if (unit < 0 || unit >= MAX_FTN_FILES) {
   227      RTE (where, "unit out of range");
   228      return NO_FTN_FILE;
   229    } else {
   230      return &(_ffile[unit]);
   231    }
   232  }
   233  
   234  void _skip_eol (FILE * f)
   235  {
   236    while (fgetc (f) != '\n');
   237  }
   238  
   239  void _ioerr (char *where, int_4 unit)
   240  {
   241    NEW_RECORD (err);
   242    _srecordf (err, "'unit %d': IO error", unit);
   243    RTE (where, err);
   244  }
   245  
   246  void _ioerr_write (char *where, int_4 unit)
   247  {
   248    NEW_RECORD (err);
   249    _srecordf (err, "'unit %d': IO error while writing", unit);
   250    RTE (where, err);
   251  }
   252  
   253  void _ioerr_read (char *where, int_4 unit)
   254  {
   255    NEW_RECORD (err);
   256    _srecordf (err, "'unit %d': IO error while reading", unit);
   257    RTE (where, err);
   258  }
   259  
   260  void _ioend_read (char *where, int_4 unit)
   261  {
   262    NEW_RECORD (err);
   263    _srecordf (err, "'unit %d': end of file while reading", unit);
   264    RTE (where, err);
   265  }
   266  
   267  int_4 _init_file_buffer (int_4 unit)
   268  {
   269    FTN_FILE *_f = _get_ftn_file (NO_TEXT, unit);
   270    if (unit == 0) {
   271      if (_f->record < _f->records) {
   272        // String lengths are powers of 2 in VIF.
   273        int_4 len = 1;
   274        while (len <= _f->lrecl) {
   275          len *= 2;
   276        }
   277        _f->buff = &((_ffile[0].rewind)[_f->record * len]);
   278        _f->buff_init = TRUE;
   279        _f->buff_pos = 0;
   280        _f->buff_len = strlen (_f->buff);
   281        _f->record++;
   282        return 0;
   283      } else {
   284        _f->buff = NO_TEXT;
   285        _f->buff_init = FALSE;
   286        _f->buff_pos = 0;
   287        _f->buff_len = 0;
   288        return 1;
   289      }
   290    } else {
   291      if (_f->in_stream) {
   292        if (_f->record > 1) {
   293          char *q = _f->buff;
   294          while (q[0] != '\n') {
   295            q++;
   296          }
   297          _f->buff = &q[1];
   298        }
   299      } else {
   300        (void) fgets (_f->buff, _f->lrecl, _f->unit);
   301      }
   302      _f->buff_len = strlen (_f->buff);
   303      if (_f->buff[_f->buff_len - 1] == '\n') {
   304        _f->buff[_f->buff_len - 1] = '\0';
   305        _f->buff_len--;
   306      }
   307      _f->buff_init = TRUE;
   308      _f->buff_pos = 0;
   309      _f->record++;
   310      return 0;
   311    }
   312  }
   313  
   314  int_4 _rewind (char *where, int_4 unit)
   315  {
   316    FTN_FILE *_f = _get_ftn_file (where, unit);
   317    if (unit == 0) {
   318      _f->record = 0;
   319      _init_file_buffer (0);
   320    } else if (_f != NO_FTN_FILE) {
   321      if (_f->in_stream) {
   322        _f->buff = _f->rewind;
   323      } else {
   324        rewind (_f->unit);
   325      }
   326      _f->buff_pos = 0;
   327      _f->record = 1;
   328    } 
   329    if (_f == NO_FTN_FILE || errno != 0) {
   330      RECORD buf;
   331      _srecordf (buf, "cannot rewind unit %d", unit);
   332      RTE (where, buf);
   333    }
   334    return 0;
   335  }
   336  
   337  int_4 _set_record (char *where, int_4 unit, int_4 rec)
   338  {
   339    FTN_FILE *_f = _get_ftn_file (where, unit);
   340    if (unit == 0) {
   341      _f->record = rec - 1;
   342      _init_file_buffer (0);
   343    } else if (_f != NO_FTN_FILE) {
   344      _rewind (where, unit);
   345      _init_file_buffer (unit);
   346      for (int_4 k = 1; k < rec; k++) {
   347        _init_file_buffer (unit);
   348      }
   349    }
   350    if (_f == NO_FTN_FILE || errno != 0) {
   351      RECORD buf;
   352      _srecordf (buf, "cannot set record on unit %d", unit);
   353      RTE (where, buf);
   354    }
   355    return 0;
   356  }
   357  
   358  int_4 _backspace (char *where, int_4 unit)
   359  {
   360    FTN_FILE *_f = _get_ftn_file (where, unit);
   361    _set_record (where, unit, _f->record - 1);
   362    if (_f == NO_FTN_FILE || errno != 0) {
   363      RECORD buf;
   364      _srecordf (buf, "cannot backspace unit %d", unit);
   365      RTE (where, buf);
   366    }
   367    return 0;
   368  }


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