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