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


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