rts.c

     1  //! @file rts.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.
    25  
    26  #include <vif.h>
    27  #include <execinfo.h>
    28  
    29  static struct timeval start_time;
    30  
    31  void _vif_backtr (int_4 signal) 
    32  {
    33    void *array[10];
    34    (void) signal;
    35    fprintf (stderr, "\n** exception  ** f%d: signal %s: generating stack dump\n", 3501, sigabbrev_np (signal));
    36    size_t size = backtrace(array, 10);
    37    backtrace_symbols_fd(array, size, STDERR_FILENO);
    38    exit (EXIT_FAILURE);
    39  }
    40  
    41  void *f_malloc (size_t size)
    42  {
    43    void *p = malloc (size);
    44    if (p == NULL) {
    45      OVERFLOW (3502, "f_malloc");
    46    }
    47    memset (p, 0, size);
    48    return p;
    49  }
    50  
    51  void *f_realloc (void *q, size_t size)
    52  {
    53    void *p = realloc (q, size);
    54    if (p == NULL) {
    55      OVERFLOW (3503, "f_realloc");
    56    }
    57    return p;
    58  }
    59  
    60  char *f_stralloc (char *text)
    61  {
    62    if (text == NO_TEXT) {
    63      return NO_TEXT;
    64    } else {
    65      int_4 len = strlen (text) + 1;
    66      char *new = (char *) f_malloc (len);
    67      if (new == NO_TEXT) {
    68        OVERFLOW (3504, "f_stralloc");
    69      }
    70      return strcpy (new, text);
    71    }
    72  }
    73  
    74  char *f_strallocat (char *text, char *add)
    75  {
    76    if (text == NO_TEXT) {
    77      return f_stralloc (add);
    78    } else {
    79      int_4 len = strlen (text) + strlen (add) + 1;
    80      char *new = (char *) f_malloc (len);
    81      if (new == NO_TEXT) {
    82        OVERFLOW (3505, "f_strallocat");
    83      }
    84      return strcat (strcpy (new, text), add);
    85    }
    86  }
    87  
    88  char *_strlower (char *s)
    89  {
    90  // We use a circular buffer for collateral calls.
    91  #define BUFS 10
    92    static int_4 buf = 0;
    93    static RECORD zb[BUFS];
    94    if (buf == BUFS) {
    95      buf = 0;
    96    }
    97    char *z = (char *) &zb[buf++];
    98    strncpy (z, s, RECLN);
    99    for (int_4 k = 0; k < (int_4) strlen (z); k++) {
   100      z[k] = tolower (z[k]);
   101    }
   102    return z;
   103  #undef BUFS
   104  }
   105  
   106  char *_strupper (char *s)
   107  {
   108  // We use a circular buffer for collateral calls.
   109  #define BUFS 10
   110    static int_4 buf = 0;
   111    static RECORD zb[BUFS];
   112    if (buf == BUFS) {
   113      buf = 0;
   114    }
   115    char *z = (char *) &zb[buf++];
   116    strncpy (z, s, RECLN);
   117    for (int_4 k = 0; k < (int_4) strlen (z); k++) {
   118      z[k] = toupper (z[k]);
   119    }
   120    return z;
   121  #undef BUFS
   122  }
   123  
   124  void RTE (const char *where, const char *text)
   125  {
   126    fflush (stdout);
   127    fprintf (stderr, "runtime error");
   128    if (where != NO_TEXT) {
   129      fprintf (stderr, ": %s", where);
   130    }
   131    if (text != NO_TEXT) {
   132      fprintf (stderr, ": %s", text);
   133    }
   134    if ((where != NO_TEXT || text != NO_TEXT) && errno != 0) {
   135      fprintf (stderr, ": %s", strerror (errno));
   136    }
   137    fprintf (stderr, "\n");
   138    fflush (stderr);
   139    _vif_exit ();
   140    exit (EXIT_FAILURE);
   141  }
   142  
   143  void RTW (const char *where, const char *text)
   144  {
   145    if (where != NO_TEXT) {
   146      fprintf (stderr, "%s: ", where);
   147    }
   148    if (errno == 0) {
   149      fprintf (stderr, "runtime warning: %s.\n", text);
   150    } else {
   151      fprintf (stderr, "runtime warning: %s: %s.\n", text, strerror (errno));
   152    }
   153  }
   154  
   155  void _vif_init (void)
   156  {
   157    gettimeofday (&start_time, (struct timezone *) NULL);
   158    // signal (SIGSEGV, _vif_backtr);
   159    for (int_4 k = 0; k < MAX_FILES; k++) {
   160      _ffile[k] = (FTNFILE) {
   161        .unit = NO_FILE,
   162        .name = NO_TEXT,
   163        .form = NO_TEXT,
   164        .action = NO_TEXT,
   165        .disp = NO_TEXT,
   166        .vers = 0,
   167        .buff = NO_TEXT,
   168        .buff_init = FALSE,
   169        .buff_pos = 0,
   170        .buff_len = 0,
   171        .record = 1,
   172        .in_stream = FALSE
   173      };
   174    }
   175  }
   176  
   177  void _vif_exit (void)
   178  {
   179    for (int_4 k = 0; k < MAX_FILES; k++) {
   180      if (_ffile[k].unit == NO_FILE) {
   181        ;
   182      } else if (_ffile[k].unit == stdin) {
   183        ;
   184      } else if (_ffile[k].unit == stdout) {
   185        ;
   186      } else if (_ffile[k].unit == stderr) {
   187        ;
   188      } else {
   189        _fclose (k);
   190      }
   191    }
   192  }
   193  
   194  real_8 _seconds (void)
   195  {
   196    struct timeval t;
   197    gettimeofday (&t, (struct timezone *) NULL);
   198    t.tv_sec -= start_time.tv_sec;
   199    return (real_8) t.tv_sec + 1e-6 * (real_8) t.tv_usec;
   200  }
   201  
   202  void _cputim (real_8 *s)
   203  {
   204    static real_8 start_cpu_time = 0;
   205    real_8 hand = _seconds ();
   206    if (start_cpu_time < 0) {
   207      start_cpu_time = hand;
   208    }
   209    *s = hand - start_cpu_time;
   210  }
   211  
   212  void _cputyd (int_4 *i)
   213  {
   214  // Conform University of Nijmegen URC runtime library.
   215  // In a resolution of 100 us.
   216    static real_8 start_cpu_time = 0;
   217    real_8 hand = _seconds ();
   218    if (start_cpu_time < 0) {
   219      start_cpu_time = hand;
   220    }
   221    *i = (int_4) (10000 * (hand - start_cpu_time));
   222  }
   223  
   224  void _vif_freq (CALLS *c)
   225  {
   226    for (int_4 k = 0; c[k].name != NO_TEXT; k++) {
   227      printf ("%s %ld\n", c[k].name, c[k].calls);
   228    }
   229  }
   230  
   231  char *__strtok_r (char *s, const char *delim, char **save_ptr)
   232  {
   233  // Based on code from the GNU C library.
   234    char *end;
   235    if (s == NO_TEXT) {
   236      s = *save_ptr;
   237    }
   238    if (*s == '\0') {
   239      *save_ptr = s;
   240      return NO_TEXT;
   241    }
   242  // Scan leading delimiters.
   243    s += strspn (s, delim);
   244    if (*s == '\0') {
   245      *save_ptr = s;
   246      return NO_TEXT;
   247    }
   248  // Find the end of the token.
   249    end = s + strcspn (s, delim);
   250    if (*end == '\0') {
   251      *save_ptr = end;
   252      return s;
   253    }
   254  // Terminate the token and make *SAVE_PTR point_4 past it.
   255    *end = '\0';
   256    *save_ptr = end + 1;
   257    return s;
   258  }
   259  
   260  // CHARACTER*n
   261  
   262  int_4 _srecordf (char *s, const char *format, ...)
   263  {
   264    size_t N = RECLN;
   265    va_list ap;
   266    va_start (ap, format);
   267    int_4 vsnprintf (char *, size_t, const char *, va_list);
   268  // Print in new string, just in case 's' is also an argument!
   269    int_4 M = N + 16; // A bit longer so we trap too long prints.
   270    char *t = f_malloc (M);
   271    int_4 Np = vsnprintf (t, M, format, ap);
   272    va_end (ap);
   273    if (Np >= N) {
   274      free (t);
   275      RECORD str;
   276      sprintf (str, "_srecordf prints %d characters", Np);
   277      OVERFLOW (3506, str);
   278    } else {
   279      strcpy (s, t);
   280      free (t);
   281    }
   282    return Np;
   283  }
   284  
   285  int_4 _sys (char *s, char *cmd, char *dep, const char *format, ...)
   286  {
   287    char *t = NO_TEXT;
   288    int_4 Np = 0;
   289    size_t N = RECLN;
   290    if (format != NO_TEXT) {
   291      va_list ap;
   292      va_start (ap, format);
   293      int_4 vsnprintf (char *, size_t, const char *, va_list);
   294      // Print in new string, just in case 's' is also an argument!
   295      int_4 M = N + 16; // A bit longer so we trap too long prints.
   296      t = f_malloc (M);
   297      Np = vsnprintf (t, M, format, ap);
   298      va_end (ap);
   299    }
   300    if (Np >= N) {
   301      free (t);
   302      RECORD str;
   303      sprintf (str, "_sys prints %d characters", Np);
   304      OVERFLOW (3507, str);
   305    } else {
   306      NEW_RECORD (protect);
   307      if (t == NO_TEXT) {
   308        if (dep == NO_TEXT) {
   309          _srecordf (protect, "command -v %s > /dev/null && %s", cmd, cmd);
   310        } else {
   311          _srecordf (protect, "command -v %s > /dev/null && command -v %s > /dev/null && %s", cmd, dep, cmd);
   312        }
   313      } else {
   314        if (dep == NO_TEXT) {
   315          _srecordf (protect, "command -v %s > /dev/null && %s %s", cmd, cmd, t);
   316        } else {
   317          _srecordf (protect, "command -v %s > /dev/null && command -v %s > /dev/null && %s %s", cmd, dep, cmd, t);
   318        }
   319        free (t);
   320      }
   321      return system (protect);
   322    }
   323    return EXIT_FAILURE;
   324  }
   325  
   326  void _srand48 (int_4 *seed)
   327  {
   328    srand48 (*seed);  
   329  }
   330  
   331  real_8 _drand48 (void)
   332  {
   333    return drand48 ();
   334  }


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