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-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 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 // SLATEC message routine stubs.
186
187 int_4 _j4save (int_4 _p_ iwhich, int_4 _p_ ivalue, logical_4 _p_ iset)
188 {
189 // J4SAVE saves and recalls several global variables needed
190 // by the library error handling routines.
191 //
192 // Description of Parameters
193 // --Input--
194 // IWHICH - Index of item desired.
195 // = 1 Refers to current error number.
196 // = 2 Refers to current error control flag.
197 // = 3 Refers to current unit number to which error
198 // messages are to be sent. (0 means use standard.)
199 // = 4 Refers to the maximum number of times any
200 // message is to be printed (as set by XERMAX).
201 // = 5 Refers to the total number of units to which
202 // each error message is to be written.
203 // = 6 Refers to the 2nd unit for error messages
204 // = 7 Refers to the 3rd unit for error messages
205 // = 8 Refers to the 4th unit for error messages
206 // = 9 Refers to the 5th unit for error messages
207 // IVALUE - The value to be set for the IWHICH-th parameter,
208 // if ISET is .TRUE. .
209 // ISET - If ISET=.TRUE., the IWHICH-th parameter will BE
210 // given the value, IVALUE. If ISET=.FALSE., the
211 // IWHICH-th parameter will be unchanged, and IVALUE
212 // is a dummy parameter.
213 // --Output--
214 // The (old) value of the IWHICH-th parameter will be returned
215 // in the function value, J4SAVE.
216 //
217 static int_4 iparam[9] = {0, 2, 0, 10, 1, 0, 0, 0, 0};
218 int_4 curr = iparam[*iwhich - 1];
219 if (*iset) {
220 iparam[*iwhich - 1] = *ivalue;
221 }
222 return curr;
223 }
224
225 static int_4 __kontrl__ = 0;
226
227 int_4 _xerclr (void)
228 {
229 // This routine simply resets the current error number to zero.
230 // This may be necessary in order to determine that a certain
231 // error has occurred again since the last time NUMXER was
232 // referenced.
233 errno = 0;
234 return 0;
235 }
236
237 int_4 _xerdmp (void)
238 {
239 // XERDMP prints the error tables, then clears them.
240 return EXIT_SUCCESS;
241 }
242
243 int_4 _xermax (int_4 _p_ _max)
244 {
245 // XERMAX sets the maximum number of times any message is to be printed.
246 // That is, non-fatal messages are not to be printed after they have occurred
247 // MAX times. Such non-fatal messages may be printed less than MAX times even
248 // if they occur MAX times, if error suppression mode (KONTRL=0) is ever in
249 // MAX - the maximum number of times any one message is to be printed.
250 (void) _max;
251 return EXIT_SUCCESS;
252 }
253
254 int_4 _xgetf (int_4 _p_ kontrl)
255 {
256 // XGETF returns the current value of the error control flag
257 // in KONTRL. See subroutine XSETF for flag value meanings.
258 // (KONTRL is an output parameter only.)
259 //
260 *kontrl = __kontrl__;
261 return EXIT_SUCCESS;
262 }
263
264 int_4 _xsetf (int_4 _p_ kontrl)
265 {
266 // XSETF sets the error control flag value to KONTRL.
267 // (KONTRL is an input parameter only.)
268 // The following table shows how each message is treated,
269 // depending on the values of KONTRL and LEVEL. (See XERMSG
270 // for description of LEVEL.)
271
272 // If KONTRL is zero or negative, no information other than the
273 // message itself (including numeric values, if any) will be
274 // printed. If KONTRL is positive, introductory messages,
275 // trace-backs, etc., will be printed in addition to the message.
276
277 // ABS(KONTRL)
278 // LEVEL 0 1 2
279 // value
280 // 2 fatal fatal fatal
281
282 // 1 not printed printed fatal
283
284 // 0 not printed printed printed
285
286 // -1 not printed printed printed
287 // only only
288 // once once
289 __kontrl__ = *kontrl;
290 return 0;
291 }
292
293 int_4 _xgetun (int_4 _p_ iunit)
294 {
295 // XGETUN gets the (first) output file to which error messages
296 // are being sent. To find out if more than one file is being
297 // used, one must use the XGETUA routine.
298 (void) iunit;
299 return EXIT_SUCCESS;
300 }
301
302
303 int_4 xsetun (int_4 _p_ iunit)
304 {
305 // XSETUN sets the output file to which error messages are to
306 // be sent. Only one file will be used. See XSETUA for
307 // how to declare more than one file.
308 (void) iunit;
309 return EXIT_SUCCESS;
310 }
311
312 int_4 xsetua (int_4 _p_ iunita, int_4 _p_ n)
313 {
314 // XSETUA may be called to declare a list of up to five
315 // logical units, each of which is to receive a copy of
316 // each error message processed by this package.
317 // The purpose of XSETUA is to allow simultaneous printing
318 // of each error message on, say, a main output file,
319 // an interactive terminal, and other files such as graphics
320 // communication files.
321 (void) iunita;
322 (void) n;
323 return EXIT_SUCCESS;
324 }
325
326 int_4 _xgetua (int_4 _p_ iunita, int_4 _p_ n)
327 {
328 // XGETUA may be called to determine the unit number or numbers
329 // to which error messages are being sent.
330 // These unit numbers may have been set by a call to XSETUN,
331 // or a call to XSETUA, or may be a default value.
332 (void) iunita;
333 (void) n;
334 return EXIT_SUCCESS;
335 }
336
337 int_4 _xerprn (char _p_ prefix_, int_4 _p_ npref_, char _p_ messg_, int_4 _p_ nwrap_)
338 {
339 // This routine sends one or more lines to each of the (up to five)
340 // logical units to which error messages are to be sent. This routine
341 // is called several times by XERMSG, sometimes with a single line to
342 // print and sometimes with a (potentially very long) message that may
343 // wrap around into multiple lines.
344 //
345 // PREFIX Input argument of type CHARACTER. This argument contains
346 // characters to be put at the beginning of each line before
347 // the body of the message. No more than 16 characters of
348 // PREFIX will be used.
349 //
350 // NPREF Input argument of type INTEGER. This argument is the number
351 // of characters to use from PREFIX. If it is negative, the
352 // intrinsic function LEN is used to determine its length. If
353 // it is zero, PREFIX is not used. If it exceeds 16 or if
354 // LEN(PREFIX) exceeds 16, only the first 16 characters will be
355 // used. If NPREF is positive and the length of PREFIX is less
356 // than NPREF, a copy of PREFIX extended with blanks to length
357 // NPREF will be used.
358 //
359 // MESSG Input argument of type CHARACTER. This is the text of a
360 // message to be printed. If it is a long message, it will be
361 // broken into pieces for printing on multiple lines. Each line
362 // will start with the appropriate prefix and be followed by a
363 // piece of the message. NWRAP is the number of characters per
364 // piece; that is, after each NWRAP characters, we break and
365 // start a new line. In addition the characters '$$' embedded
366 // in MESSG are a sentinel for a new line. The counting of
367 // characters up to NWRAP starts over for each new line. The
368 // value of NWRAP typically used by XERMSG is 72 since many
369 // older error messages in the SLATEC Library are laid out to
370 // rely on wrap-around every 72 characters.
371 //
372 // NWRAP Input argument of type INTEGER. This gives the maximum size
373 // piece into which to break MESSG for printing on multiple
374 // lines. An embedded '$$' ends a line, and the count restarts
375 // at the following character. If a line break does not occur
376 // on a blank (it would split a word) that word is moved to the
377 // next line. Values of NWRAP less than 16 will be treated as
378 // 16. Values of NWRAP greater than 132 will be treated as 132.
379 // The actual line length will be NPREF + NWRAP after NPREF has
380 // been adjusted to fall between 0 and 16 and NWRAP has been
381 // adjusted to fall between 16 and 132.
382 (void) prefix_;
383 (void) npref_;
384 (void) messg_;
385 (void) nwrap_;
386 return EXIT_SUCCESS;
387 }
388
389 int_4 _xersve (char _p_ librar_, char _p_ subrou_, char _p_ messg_, int_4 _p_ kflag_, int_4 _p_ nerr_, int_4 _p_ level_, int_4 _p_ icount_)
390 {
391 // Record that an error has occurred and possibly dump and clear the tables.
392 (void) librar_;
393 (void) subrou_;
394 (void) messg_;
395 (void) kflag_;
396 (void) nerr_;
397 (void) level_;
398 (void) icount_;
399 return EXIT_SUCCESS;
400 }
401
402 int_4 _xermsg (char _p_ librar, char _p_ subrou, char _p_ messg, int_4 _p_ nerr, int_4 _p_ level)
403 {
404 // XERMSG processes a diagnostic message in a manner determined by the
405 // value of LEVEL and the current value of the library error control
406 // flag, KONTRL. See subroutine XSETF for details.
407
408 // LIBRAR A character constant (or character variable) with the name
409 // of the library. This will be 'SLATE' for the SLATEC
410 // ommon Math Library. The error handling package is
411 // general enough to be used by many libraries
412 // simultaneously, so it is desirable for the routine that
413 // detects and reports an error to identify the library name
414 // as well as the routine name.
415
416 // SUBROU A character constant (or character variable) with the name
417 // of the routine that detected the error. Usually it is the
418 // name of the routine that is calling XERMSG. There are
419 // some instances where a user callable library routine calls
420 // lower level subsidiary routines where the error is
421 // detected. In such cases it may be more informative to
422 // supply the name of the routine the user called rather than
423 // the name of the subsidiary routine that detected the
424 // error.
425
426 // MESSG A character constant (or character variable) with the text
427 // of the error or warning message. In the example below,
428 // the message is a character constant that contains a
429 // generic message.
430
431 // ALL XERMSG ('SLATEC', 'MMPY',
432 // *'THE ORDER OF THE MATRIX EXEEDS THE ROW DIMENSION',
433 // *3, 1)
434
435 // It is possible (and is sometimes desirable) to generate a
436 // specific message--e.g., one that contains actual numeric
437 // values. Specific numeric values can be converted into
438 // character strings using formatted WRITE statements into
439 // character variables. This is called standard Fortran
440 // internal file I/O and is exemplified in the first three
441 // lines of the following example. You can also catenate
442 // substrings of characters to construct the error message.
443 // Here is an example showing the use of both writing to
444 // an internal file and catenating character strings.
445
446 // CHARACTER*5 CHARN, CHARL
447 // WRITE (HARN,10) N
448 // WRITE (HARL,10) LDA
449 // 10 FORMAT(I5)
450 // ALL XERMSG ('SLATEC', 'MMPY', 'THE ORDER'//CHARN//
451 // * ' OF THE MATRIX EXEEDS ITS ROW DIMENSION OF'//
452 // * HARL, 3, 1)
453
454 // There are two subtleties worth mentioning. One is that
455 // the // for character catenation is used to construct the
456 // error message so that no single character constant is
457 // continued to the next line. This avoids confusion as to
458 // whether there are trailing blanks at the end of the line.
459 // The second is that by catenating the parts of the message
460 // as an actual argument rather than encoding the entire
461 // message into one large character variable, we avoid
462 // having to know how long the message will be in order to
463 // declare an adequate length for that large character
464 // variable. XERMSG calls XERPRN to print_4 the message using
465 // multiple lines if necessary. If the message is very long,
466 // XERPRN will break it into pieces of 72 characters (as
467 // requested by XERMSG) for printing on multiple lines.
468 // Also, XERMSG asks XERPRN to prefix each line with ' * '
469 // so that the total line length could be 76 characters.
470 // Note also that XERPRN scans the error message backwards
471 // to ignore trailing blanks. Another feature is that
472 // the substring '$$' is treated as a new line sentinel
473 // by XERPRN. If you want to construct a multiline
474 // message without having to count out multiples of 72
475 // characters, just use '$$' as a separator. '$$'
476 // obviously must occur within 72 characters of the
477 // start of each line to have its intended effect since
478 // XERPRN is asked to wrap around at 72 characters in
479 // addition to looking for '$$'.
480
481 // NERR An integer value that is chosen by the library routine's
482 // author. It must be in the range -99 to 999 (three
483 // printable digits). Each distinct error should have its
484 // own error number. These error numbers should be described
485 // in the machine readable documentation for the routine.
486 // The error numbers need be unique only within each routine,
487 // so it is reasonable for each routine to start enumerating
488 // errors from 1 and proceeding to the next integer.
489
490 // LEVEL An integer value in the range 0 to 2 that indicates the
491 // level (severity) of the error. Their meanings are
492
493 // -1 A warning message. This is used if it is not clear
494 // that there really is an error, but the user's attention
495 // may be needed. An attempt is made to only print_4 this
496 // message once.
497
498 // 0 A warning message. This is used if it is not clear
499 // that there really is an error, but the user's attention
500 // may be needed.
501
502 // 1 A recoverable error. This is used even if the error is
503 // so serious that the routine cannot return any useful
504 // answer. If the user has told the error package to
505 // return after recoverable errors, then XERMSG will
506 // return to the Library routine which can then return to
507 // the user's routine. The user may also permit the error
508 // package to terminate the program upon encountering a
509 // recoverable error.
510
511 // 2 A fatal error. XERMSG will not return to its caller
512 // after it receives a fatal error. This level should
513 // hardly ever be used; it is much better to allow the
514 // user a chance to recover. An example of one of the few
515 // cases in which it is permissible to declare a level 2
516 // error is a reverse communication Library routine that
517 // is likely to be called repeatedly until it integrates
518 // across some interval. If there is a serious error in
519 // the input such that another step cannot be taken and
520 // the Library routine is called again without the input
521 // error having been corrected by the caller, the Library
522 // routine will probably be called forever with improper
523 // input. In this case, it is reasonable to declare the
524 // error to be fatal.
525
526 // Each of the arguments to XERMSG is input; none will be modified by
527 // XERMSG. A routine may make multiple calls to XERMSG with warning
528 // level messages; however, after a call to XERMSG with a recoverable
529 // error, the routine should return to the user. Do not try to call
530 // XERMSG with a second recoverable error after the first recoverable
531 // error because the error package saves the error number. The user
532 // can retrieve this error number by calling another entry point_4 in
533 // the error handling package and then clear the error number when
534 // recovering from the error. Calling XERMSG in succession causes the
535 // old error number to be overwritten by the latest error number.
536 // This is considered harmless for error numbers associated with
537 // warning messages but must not be done for error numbers of serious
538 // errors. After a call to XERMSG with a recoverable error, the user
539 // must be given a chance to call NUMXER or XERLR to retrieve or
540 // clear the error number.
541 //
542
543 // Note that this stub ignores __kontrl__.
544 fprintf (stderr, "** slatec ** error: %s: %s: %s\n", _strlower (librar), _strlower (subrou), _strlower (messg));
545 errno = *nerr;
546 if (*level == 2) {
547 exit (EXIT_FAILURE);
548 }
549 return EXIT_FAILURE;
550 }
551
552 int_4 _xerbla(char _p_ srname, int_4 _p_ info)
553 {
554 // XERBLA is called by Level 2 and 3 BLAS routines if an input parameter
555 // is invalid.
556 //
557 // Parameters
558 // ==========
559 //
560 // SRNAME - CHARACTER*6.
561 // On entry, SRNAME specifies the name of the routine which
562 // called XERBLA.
563 //
564 // INFO - INTEGER.
565 // On entry, INFO specifies the position of the invalid
566 // parameter in the parameter-list of the calling routine.
567 //
568 RECORD msg;
569 _srecordf (msg, "** blas ** %6s: invalid parameter #%2d\n", srname, *info);
570 RTE ("xerbla", msg);
571 return EXIT_FAILURE;
572 }
573
574 int_4 _xerabt(char _p_ msg, int_4 _p_ nmessg)
575 {
576 //
577 // Latest revision - January 24, 1990 (JRD)
578 //
579 // ABSTRACT
580 // ***NOTE*** Machine dependent routine
581 // XERABT aborts the execution of the program.
582 // The error message causing the abort is given in the calling
583 // sequence in case one needs it for printing on a dayfile,
584 // for example.
585 //
586 // DESCRIPTION OF PARAMETERS
587 // MESSG and NMESSG are as in xerror, except that nmessg may
588 // be zero, in which case no message is being supplied.
589 //
590 // Written by Ron Jones, with SLATEC Common Math Library subcommittee
591 // latest revision --- 7 June 1978
592 //
593 if (*nmessg != 0) {
594 RTE (NO_TEXT, msg); // Does not return.
595 } else {
596 RTE (NO_TEXT, NO_TEXT); // Does not return.
597 }
598 return EXIT_FAILURE;
599 }
600
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|