rts-slatec.c

     
   1  //!@file rts-slatec.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-2024 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 SLATEC subprograms.
  25  
  26  //!@brief SLATEC stubs for VIF, adapted to C.
  27  // SLATEC common mathematical library, version 4.1, July 1993.
  28  //
  29  // SLATEC was developed at US government research laboratories 
  30  // and is in the public domain.
  31  // Repository: http://www.netlib.org/slatec/
  32  
  33  #include <vif.h>
  34  
  35  // d1mach yields machine-dependent parameters for the 
  36  // local machine environment.
  37  //
  38  // d1mach(1) = b**(emin-1), the smallest positive magnitude. 
  39  // d1mach(2) = b**emax*(1 - b**(-t)), the largest magnitude. 
  40  // d1mach(3) = b**(-t), the smallest relative spacing. 
  41  // d1mach(4) = b**(1-t), the largest relative spacing. 
  42  // d1mach(5) = log10(b) 
  43  
  44  real_4 _r1mach (int_4 *i)
  45  {
  46    switch (*i) {
  47  //    r1mach(1) = b**(emin-1), the smallest positive magnitude. 
  48    case 1: return FLT_MIN;
  49  //    r1mach(2) = b**emax*(1 - b**(-t)), the largest magnitude. 
  50    case 2: return FLT_MAX;
  51  //    r1mach(3) = b**(-t), the smallest relative spacing. 
  52    case 3: return 0.5 * FLT_EPSILON;
  53  //    r1mach(4) = b**(1-t), the largest relative spacing. 
  54    case 4: return FLT_EPSILON;
  55  //    r1mach(5) = log10(b) 
  56    case 5: return M_LOG10_2;
  57  //
  58    default: return 0.0;
  59    }
  60  }
  61   
  62  real_8 _d1mach (int_4 *i)
  63  {
  64    switch (*i) {
  65  //    d1mach(1) = b**(emin-1), the smallest positive magnitude. 
  66    case 1: return DBL_MIN;
  67  //    d1mach(2) = b**emax*(1 - b**(-t)), the largest magnitude. 
  68    case 2: return DBL_MAX;
  69  //    d1mach(3) = b**(-t), the smallest relative spacing. 
  70    case 3: return 0.5 * DBL_EPSILON;
  71  //    d1mach(4) = b**(1-t), the largest relative spacing. 
  72    case 4: return DBL_EPSILON;
  73  //    d1mach(5) = log10(b) 
  74    case 5: return M_LOG10_2;
  75  //
  76    default: return 0.0;
  77    }
  78  }
  79  
  80  real_8 _dmach (int_4 *i)
  81  {
  82    return _d1mach (i);
  83  }
  84   
  85  // i1mach yields machine-dependent parameters for the 
  86  // local machine environment.
  87  //
  88  // i/o unit numbers: 
  89  //  i1mach(1) = the standard input unit. 
  90  //  i1mach(2) = the standard output unit. 
  91  //  i1mach(3) = the standard punch unit. 
  92  //  i1mach(4) = the standard error message unit. 
  93  //
  94  // words: 
  95  //  i1mach(5) = the number of bits per int_4 storage unit. 
  96  //  i1mach(6) = the number of characters per int_4 storage unit. 
  97  //
  98  // integers: 
  99  //  assume int_4s are represented in the s-digit, base-a form 
 100  //
 101  //             sign (x(s-1)*a**(s-1) + ... + x(1)*a + x(0) ) 
 102  //
 103  //             where 0 .le. x(i) .lt. a for i=0,...,s-1. 
 104  //  i1mach(7) = a, the base. 
 105  //  i1mach(8) = s, the number of base-a digits. 
 106  //  i1mach(9) = a**s - 1, the largest magnitude. 
 107  //
 108  // floating-point_4 numbers: 
 109  //  assume floating-point_4 numbers are represented in the t-digit, 
 110  //  base-b form 
 111  //             sign (b**e)*((x(1)/b) + ... + (x(t)/b**t) ) 
 112  //
 113  //             where 0 .le. x(i) .lt. b for i=1,...,t, 
 114  //             0 .lt. x(1), and emin .le. e .le. emax. 
 115  //  i1mach(10) = b, the base. 
 116  //
 117  // single-precision: 
 118  //  i1mach(11) = t, the number of base-b digits. 
 119  //  i1mach(12) = emin, the smallest exponent e. 
 120  //  i1mach(13) = emax, the largest exponent e. 
 121  //
 122  // double-precision: 
 123  //  i1mach(14) = t, the number of base-b digits. 
 124  //  i1mach(15) = emin, the smallest exponent e. 
 125  //  i1mach(16) = emax, the largest exponent e. 
 126  
 127  int_4 _i1mach (int_4 *i) 
 128  {
 129    switch(*i) {
 130  //  i1mach(1) = the standard input unit. 
 131  //  i1mach(2) = the standard output unit. 
 132  //  i1mach(3) = the standard punch unit. 
 133  //  i1mach(4) = the standard error message unit. 
 134    case  1: return STDF_IN;
 135    case  2: return STDF_OUT;
 136    case  3: return STDF_PUN;
 137    case  4: return STDF_ERR;
 138  //  i1mach(5) = the number of bits per int_4 storage unit. 
 139  //  i1mach(6) = the number of characters per int_4 storage unit. 
 140    case  5: return CHAR_BIT * sizeof (int_4);
 141    case  6: return sizeof (int_4);
 142  //  i1mach(7) = a, the base. 
 143  //  i1mach(8) = s, the number of base-a digits. 
 144  //  i1mach(9) = a**s - 1, the largest magnitude. 
 145    case  7: return 2;
 146    case  8: return CHAR_BIT * sizeof (int_4) - 1;
 147    case  9: return INT_MAX;
 148  //  i1mach(10) = b, the base. 
 149    case 10: return FLT_RADIX;
 150  //  i1mach(11) = t, the number of base-b digits. 
 151  //  i1mach(12) = emin, the smallest exponent e. 
 152  //  i1mach(13) = emax, the largest exponent e. 
 153    case 11: return FLT_MANT_DIG;
 154    case 12: return FLT_MIN_EXP;
 155    case 13: return FLT_MAX_EXP;
 156  //  i1mach(14) = t, the number of base-b digits. 
 157  //  i1mach(15) = emin, the smallest exponent e. 
 158  //  i1mach(16) = emax, the largest exponent e. 
 159    case 14: return DBL_MANT_DIG;
 160    case 15: return DBL_MIN_EXP;
 161    case 16: return DBL_MAX_EXP;
 162  //
 163    default: return 0;
 164    }
 165  }
 166  
 167  // amach yields machine-dependent parameters for the local environment.
 168  //
 169  // subroutine amach(mode, i, i1, r1, d1)
 170  
 171  int_4 _amach (int_4 _p_ mode_, int_4 _p_ i_, int_4 _p_ i1_, real_4 _p_ r1_, real_8 _p_ d1_)
 172  {
 173    if (*mode_ == 0) {
 174      *i1_ = _i1mach(i_);
 175    }
 176    else if (*mode_ == 1) {
 177      *r1_ = _r1mach(i_);
 178    }
 179    else {
 180      *d1_ = _d1mach(i_);
 181    }
 182    return 0;
 183  }
 184  
 185  int_4 _xerclr (void)
 186  {
 187  // This routine simply resets the current error number to zero.
 188  // This may be necessary in order to determine that a certain
 189  // error has occurred again since the last time NUMXER was
 190  // referenced.
 191    errno = 0;
 192    return 0;
 193  }
 194  
 195  static int_4 _kontrl = 0;
 196  
 197  int_4 _xgetf (int_4 *kontrl)
 198  {
 199  // XGETF returns the current value of the error control flag
 200  // in KONTRL.  See subroutine XSETF for flag value meanings.
 201  // (KONTRL is an output parameter only.)
 202  //
 203    *kontrl = _kontrl;
 204    return 0;
 205  }
 206  
 207  int_4 _xsetf (int_4 *kontrl)
 208  {
 209  // XSETF sets the error control flag value to KONTRL.
 210  // (KONTRL is an input parameter only.)
 211  // The following table shows how each message is treated,
 212  // depending on the values of KONTRL and LEVEL.  (See XERMSG
 213  // for description of LEVEL.)
 214  
 215  // If KONTRL is zero or negative, no information other than the
 216  // message itself (including numeric values, if any) will be
 217  // printed.  If KONTRL is positive, introductory messages,
 218  // trace-backs, etc., will be printed in addition to the message.
 219  
 220  //   ABS(KONTRL)
 221  // LEVEL        0              1              2
 222  // value
 223  //  2        fatal          fatal          fatal
 224  
 225  //  1     not printed      printed         fatal
 226  
 227  //  0     not printed      printed        printed
 228  
 229  // -1     not printed      printed        printed
 230  //                       only           only
 231  //                       once           once
 232    _kontrl = *kontrl;
 233    return 0;
 234  }
 235  
 236  int_4 _xermsg (char *librar, char *subrou, char *messg, int_4 *nerr, int_4 *level)
 237  {
 238  // XERMSG processes a diagnostic message in a manner determined by the
 239  // value of LEVEL and the current value of the library error control
 240  // flag, KONTRL.  See subroutine XSETF for details.
 241  
 242  // LIBRAR   A character constant (or character variable) with the name
 243  //       of the library.  This will be 'SLATE' for the SLATEC
 244  //       ommon Math Library.  The error handling package is
 245  //       general enough to be used by many libraries
 246  //       simultaneously, so it is desirable for the routine that
 247  //       detects and reports an error to identify the library name
 248  //       as well as the routine name.
 249  
 250  // SUBROU   A character constant (or character variable) with the name
 251  //       of the routine that detected the error.  Usually it is the
 252  //       name of the routine that is calling XERMSG.  There are
 253  //       some instances where a user callable library routine calls
 254  //       lower level subsidiary routines where the error is
 255  //       detected.  In such cases it may be more informative to
 256  //       supply the name of the routine the user called rather than
 257  //       the name of the subsidiary routine that detected the
 258  //       error.
 259  
 260  // MESSG    A character constant (or character variable) with the text
 261  //       of the error or warning message.  In the example below,
 262  //       the message is a character constant that contains a
 263  //       generic message.
 264  
 265  //             ALL XERMSG ('SLATEC', 'MMPY',
 266  //            *'THE ORDER OF THE MATRIX EXEEDS THE ROW DIMENSION',
 267  //            *3, 1)
 268  
 269  //       It is possible (and is sometimes desirable) to generate a
 270  //       specific message--e.g., one that contains actual numeric
 271  //       values.  Specific numeric values can be converted into
 272  //       character strings using formatted WRITE statements into
 273  //       character variables.  This is called standard Fortran
 274  //       internal file I/O and is exemplified in the first three
 275  //       lines of the following example.  You can also catenate
 276  //       substrings of characters to construct the error message.
 277  //       Here is an example showing the use of both writing to
 278  //       an internal file and catenating character strings.
 279  
 280  //             CHARACTER*5 CHARN, CHARL
 281  //             WRITE (HARN,10) N
 282  //             WRITE (HARL,10) LDA
 283  //          10 FORMAT(I5)
 284  //             ALL XERMSG ('SLATEC', 'MMPY', 'THE ORDER'//CHARN//
 285  //            *   ' OF THE MATRIX EXEEDS ITS ROW DIMENSION OF'//
 286  //            *   HARL, 3, 1)
 287  
 288  //       There are two subtleties worth mentioning.  One is that
 289  //       the // for character catenation is used to construct the
 290  //       error message so that no single character constant is
 291  //       continued to the next line.  This avoids confusion as to
 292  //       whether there are trailing blanks at the end of the line.
 293  //       The second is that by catenating the parts of the message
 294  //       as an actual argument rather than encoding the entire
 295  //       message into one large character variable, we avoid
 296  //       having to know how long the message will be in order to
 297  //       declare an adequate length for that large character
 298  //       variable.  XERMSG calls XERPRN to print_4 the message using
 299  //       multiple lines if necessary.  If the message is very long,
 300  //       XERPRN will break it into pieces of 72 characters (as
 301  //       requested by XERMSG) for printing on multiple lines.
 302  //       Also, XERMSG asks XERPRN to prefix each line with ' *  '
 303  //       so that the total line length could be 76 characters.
 304  //       Note also that XERPRN scans the error message backwards
 305  //       to ignore trailing blanks.  Another feature is that
 306  //       the substring '$$' is treated as a new line sentinel
 307  //       by XERPRN.  If you want to construct a multiline
 308  //       message without having to count out multiples of 72
 309  //       characters, just use '$$' as a separator.  '$$'
 310  //       obviously must occur within 72 characters of the
 311  //       start of each line to have its intended effect since
 312  //       XERPRN is asked to wrap around at 72 characters in
 313  //       addition to looking for '$$'.
 314  
 315  // NERR     An integer value that is chosen by the library routine's
 316  //       author.  It must be in the range -99 to 999 (three
 317  //       printable digits).  Each distinct error should have its
 318  //       own error number.  These error numbers should be described
 319  //       in the machine readable documentation for the routine.
 320  //       The error numbers need be unique only within each routine,
 321  //       so it is reasonable for each routine to start enumerating
 322  //       errors from 1 and proceeding to the next integer.
 323  
 324  // LEVEL    An integer value in the range 0 to 2 that indicates the
 325  //       level (severity) of the error.  Their meanings are
 326  
 327  //      -1  A warning message.  This is used if it is not clear
 328  //          that there really is an error, but the user's attention
 329  //          may be needed.  An attempt is made to only print_4 this
 330  //          message once.
 331  
 332  //       0  A warning message.  This is used if it is not clear
 333  //          that there really is an error, but the user's attention
 334  //          may be needed.
 335  
 336  //       1  A recoverable error.  This is used even if the error is
 337  //          so serious that the routine cannot return any useful
 338  //          answer.  If the user has told the error package to
 339  //          return after recoverable errors, then XERMSG will
 340  //          return to the Library routine which can then return to
 341  //          the user's routine.  The user may also permit the error
 342  //          package to terminate the program upon encountering a
 343  //          recoverable error.
 344  
 345  //       2  A fatal error.  XERMSG will not return to its caller
 346  //          after it receives a fatal error.  This level should
 347  //          hardly ever be used; it is much better to allow the
 348  //          user a chance to recover.  An example of one of the few
 349  //          cases in which it is permissible to declare a level 2
 350  //          error is a reverse communication Library routine that
 351  //          is likely to be called repeatedly until it integrates
 352  //          across some interval.  If there is a serious error in
 353  //          the input such that another step cannot be taken and
 354  //          the Library routine is called again without the input
 355  //          error having been corrected by the caller, the Library
 356  //          routine will probably be called forever with improper
 357  //          input.  In this case, it is reasonable to declare the
 358  //          error to be fatal.
 359  
 360  // Each of the arguments to XERMSG is input; none will be modified by
 361  // XERMSG.  A routine may make multiple calls to XERMSG with warning
 362  // level messages; however, after a call to XERMSG with a recoverable
 363  // error, the routine should return to the user.  Do not try to call
 364  // XERMSG with a second recoverable error after the first recoverable
 365  // error because the error package saves the error number.  The user
 366  // can retrieve this error number by calling another entry point_4 in
 367  // the error handling package and then clear the error number when
 368  // recovering from the error. Calling XERMSG in succession causes the
 369  // old error number to be overwritten by the latest error number.
 370  // This is considered harmless for error numbers associated with
 371  // warning messages but must not be done for error numbers of serious
 372  // errors.  After a call to XERMSG with a recoverable error, the user
 373  // must be given a chance to call NUMXER or XERLR to retrieve or
 374  // clear the error number.
 375  //
 376  
 377  // Note that this stub ignores _kontrl.
 378    fprintf (stderr, "** slatec     ** error: %s: %s: %s\n", strlower (librar), strlower (subrou), strlower (messg));  
 379    errno = *nerr;
 380    if (*level == 2) {
 381      exit (EXIT_FAILURE);
 382    }
 383    return 0;
 384  }
     


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