rts-unformatted.c
1 //! @file rts-unformatted.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-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 //! Unformatted transput.
25
26 #include "a68g.h"
27 #include "a68g-genie.h"
28 #include "a68g-prelude.h"
29 #include "a68g-mp.h"
30 #include "a68g-double.h"
31 #include "a68g-transput.h"
32
33 //! @brief Skip new-lines and form-feeds.
34
35 void skip_nl_ff (NODE_T * p, int *ch, A68G_REF ref_file)
36 {
37 A68G_FILE *f = FILE_DEREF (&ref_file);
38 while ((*ch) != EOF_CHAR && IS_NL_FF (*ch)) {
39 A68G_BOOL *z = (A68G_BOOL *) STACK_TOP;
40 ADDR_T pop_sp = A68G_SP;
41 unchar_scanner (p, f, (char) (*ch));
42 if (*ch == NEWLINE_CHAR) {
43 on_event_handler (p, LINE_END_MENDED (f), ref_file);
44 A68G_SP = pop_sp;
45 if (VALUE (z) == A68G_FALSE) {
46 PUSH_REF (p, ref_file);
47 genie_new_line (p);
48 }
49 } else if (*ch == FORMFEED_CHAR) {
50 on_event_handler (p, PAGE_END_MENDED (f), ref_file);
51 A68G_SP = pop_sp;
52 if (VALUE (z) == A68G_FALSE) {
53 PUSH_REF (p, ref_file);
54 genie_new_page (p);
55 }
56 }
57 (*ch) = char_scanner (f);
58 }
59 }
60
61 //! @brief Scan an int from file.
62
63 void scan_integer (NODE_T * p, A68G_REF ref_file)
64 {
65 A68G_FILE *f = FILE_DEREF (&ref_file);
66 reset_transput_buffer (INPUT_BUFFER);
67 int ch = char_scanner (f);
68 while (ch != EOF_CHAR && (IS_SPACE (ch) || IS_NL_FF (ch))) {
69 if (IS_NL_FF (ch)) {
70 skip_nl_ff (p, &ch, ref_file);
71 } else {
72 ch = char_scanner (f);
73 }
74 }
75 if (ch != EOF_CHAR && (ch == '+' || ch == '-')) {
76 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
77 ch = char_scanner (f);
78 }
79 while (ch != EOF_CHAR && IS_DIGIT (ch)) {
80 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
81 ch = char_scanner (f);
82 }
83 if (ch != EOF_CHAR) {
84 unchar_scanner (p, f, (char) ch);
85 }
86 }
87
88 //! @brief Scan a real from file.
89
90 void scan_real (NODE_T * p, A68G_REF ref_file)
91 {
92 A68G_FILE *f = FILE_DEREF (&ref_file);
93 char x_e = EXPONENT_CHAR;
94 reset_transput_buffer (INPUT_BUFFER);
95 int ch = char_scanner (f);
96 while (ch != EOF_CHAR && (IS_SPACE (ch) || IS_NL_FF (ch))) {
97 if (IS_NL_FF (ch)) {
98 skip_nl_ff (p, &ch, ref_file);
99 } else {
100 ch = char_scanner (f);
101 }
102 }
103 if (ch != EOF_CHAR && (ch == '+' || ch == '-')) {
104 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
105 ch = char_scanner (f);
106 }
107 while (ch != EOF_CHAR && IS_DIGIT (ch)) {
108 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
109 ch = char_scanner (f);
110 }
111 if (ch == EOF_CHAR || !(ch == POINT_CHAR || TO_UPPER (ch) == TO_UPPER (x_e))) {
112 goto salida;
113 }
114 if (ch == POINT_CHAR) {
115 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
116 ch = char_scanner (f);
117 while (ch != EOF_CHAR && IS_DIGIT (ch)) {
118 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
119 ch = char_scanner (f);
120 }
121 }
122 if (ch == EOF_CHAR || TO_UPPER (ch) != TO_UPPER (x_e)) {
123 goto salida;
124 }
125 if (TO_UPPER (ch) == TO_UPPER (x_e)) {
126 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
127 ch = char_scanner (f);
128 while (ch != EOF_CHAR && ch == BLANK_CHAR) {
129 ch = char_scanner (f);
130 }
131 if (ch != EOF_CHAR && (ch == '+' || ch == '-')) {
132 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
133 ch = char_scanner (f);
134 }
135 while (ch != EOF_CHAR && IS_DIGIT (ch)) {
136 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
137 ch = char_scanner (f);
138 }
139 }
140 salida:if (ch != EOF_CHAR) {
141 unchar_scanner (p, f, (char) ch);
142 }
143 }
144
145 //! @brief Scan a bits from file.
146
147 void scan_bits (NODE_T * p, A68G_REF ref_file)
148 {
149 A68G_FILE *f = FILE_DEREF (&ref_file);
150 reset_transput_buffer (INPUT_BUFFER);
151 int ch = char_scanner (f);
152 while (ch != EOF_CHAR && (IS_SPACE (ch) || IS_NL_FF (ch))) {
153 if (IS_NL_FF (ch)) {
154 skip_nl_ff (p, &ch, ref_file);
155 } else {
156 ch = char_scanner (f);
157 }
158 }
159 while (ch != EOF_CHAR && (ch == FLIP_CHAR || ch == FLOP_CHAR)) {
160 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
161 ch = char_scanner (f);
162 }
163 if (ch != EOF_CHAR) {
164 unchar_scanner (p, f, (char) ch);
165 }
166 }
167
168 //! @brief Scan a char from file.
169
170 void scan_char (NODE_T * p, A68G_REF ref_file)
171 {
172 A68G_FILE *f = FILE_DEREF (&ref_file);
173 reset_transput_buffer (INPUT_BUFFER);
174 int ch = char_scanner (f);
175 skip_nl_ff (p, &ch, ref_file);
176 if (ch != EOF_CHAR) {
177 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
178 }
179 }
180
181 //! @brief Scan a string from file.
182
183 void scan_string (NODE_T * p, char *term, A68G_REF ref_file)
184 {
185 A68G_FILE *f = FILE_DEREF (&ref_file);
186 if (END_OF_FILE (f)) {
187 reset_transput_buffer (INPUT_BUFFER);
188 end_of_file_error (p, ref_file);
189 } else {
190 reset_transput_buffer (INPUT_BUFFER);
191 int ch = char_scanner (f);
192 BOOL_T siga = A68G_TRUE;
193 while (siga) {
194 if (ch == EOF_CHAR || END_OF_FILE (f)) {
195 if (get_transput_buffer_index (INPUT_BUFFER) == 0) {
196 end_of_file_error (p, ref_file);
197 }
198 siga = A68G_FALSE;
199 } else if (IS_NL_FF (ch)) {
200 ADDR_T pop_sp = A68G_SP;
201 unchar_scanner (p, f, (char) ch);
202 if (ch == NEWLINE_CHAR) {
203 on_event_handler (p, LINE_END_MENDED (f), ref_file);
204 } else if (ch == FORMFEED_CHAR) {
205 on_event_handler (p, PAGE_END_MENDED (f), ref_file);
206 }
207 A68G_SP = pop_sp;
208 siga = A68G_FALSE;
209 } else if (term != NO_TEXT && strchr (term, ch) != NO_TEXT) {
210 siga = A68G_FALSE;
211 unchar_scanner (p, f, (char) ch);
212 } else {
213 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
214 ch = char_scanner (f);
215 }
216 }
217 }
218 }
219
220 //! @brief Make temp file name.
221
222 BOOL_T a68g_mkstemp (char *fn, int flags, mode_t permissions)
223 {
224 // "tmpnam" is not safe, "mkstemp" is Unix, so a68g brings its own tmpnam.
225 #define TMP_SIZE 32
226 #define TRIALS 32
227 BUFFER tfilename;
228 char *letters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
229 size_t len = strlen (letters);
230 BOOL_T good_file = A68G_FALSE;
231 // Next are prefixes to try.
232 // First we try /tmp, and if that won't go, the current dir.
233 char *prefix[] = { "/tmp/a68g_", "./a68g_", NO_TEXT };
234 for (int i = 0; prefix[i] != NO_TEXT; i++) {
235 for (int k = 0; k < TRIALS && good_file == A68G_FALSE; k++) {
236 a68g_bufcpy (tfilename, prefix[i], BUFFER_SIZE);
237 for (int j = 0; j < TMP_SIZE; j++) {
238 int cindex;
239 do {
240 cindex = (int) (a68g_unif_rand () * len);
241 } while (cindex < 0 || cindex >= len);
242 char chars[2];
243 chars[0] = letters[cindex];
244 chars[1] = NULL_CHAR;
245 a68g_bufcat (tfilename, chars, BUFFER_SIZE);
246 }
247 a68g_bufcat (tfilename, ".tmp", BUFFER_SIZE);
248 errno = 0;
249 FILE_T fd = open (tfilename, flags | O_EXCL, permissions);
250 good_file = (BOOL_T) (fd != A68G_NO_FILE && errno == 0);
251 if (good_file) {
252 (void) close (fd);
253 }
254 }
255 }
256 if (good_file) {
257 a68g_bufcpy (fn, tfilename, BUFFER_SIZE);
258 return A68G_TRUE;
259 } else {
260 return A68G_FALSE;
261 }
262 #undef TMP_SIZE
263 #undef TRIALS
264 }
265
266 //! @brief Open a file, or establish it.
267
268 FILE_T open_physical_file (NODE_T * p, A68G_REF ref_file, int flags, mode_t permissions)
269 {
270 BOOL_T reading = (flags & ~O_BINARY) == A68G_READ_ACCESS;
271 BOOL_T writing = (flags & ~O_BINARY) == A68G_WRITE_ACCESS;
272 ABEND (reading == writing, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
273 CHECK_REF (p, ref_file, M_REF_FILE);
274 A68G_FILE *file = FILE_DEREF (&ref_file);
275 CHECK_INIT (p, INITIALISED (file), M_FILE);
276 if (!IS_NIL (STRING (file))) {
277 if (writing) {
278 A68G_REF z = *DEREF (A68G_REF, &STRING (file));
279 A68G_ARRAY *arr; A68G_TUPLE *tup;
280 GET_DESCRIPTOR (arr, tup, &z);
281 UPB (tup) = LWB (tup) - 1;
282 }
283 // Associated file.
284 TRANSPUT_BUFFER (file) = get_unblocked_transput_buffer (p);
285 reset_transput_buffer (TRANSPUT_BUFFER (file));
286 END_OF_FILE (file) = A68G_FALSE;
287 FILE_ENTRY (file) = -1;
288 return FD (file);
289 } else if (IS_NIL (IDENTIFICATION (file))) {
290 // No identification, so generate a unique identification..
291 if (reading) {
292 return A68G_NO_FILE;
293 } else {
294 BUFFER tfilename;
295 BUFCLR (tfilename);
296 BOOL_T write_mood = (flags & A68G_WRITE_ACCESS) != 0;
297 if (write_mood) {
298 flags |= (O_CREAT | O_TRUNC);
299 }
300 if (!a68g_mkstemp (tfilename, flags, permissions)) {
301 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NO_TEMP);
302 exit_genie (p, A68G_RUNTIME_ERROR);
303 }
304 FD (file) = open (tfilename, flags, permissions);
305 size_t len = 1 + strlen (tfilename);
306 IDENTIFICATION (file) = heap_generator (p, M_C_STRING, len);
307 BLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
308 a68g_bufcpy (DEREF (char, &IDENTIFICATION (file)), tfilename, len);
309 TRANSPUT_BUFFER (file) = get_unblocked_transput_buffer (p);
310 reset_transput_buffer (TRANSPUT_BUFFER (file));
311 END_OF_FILE (file) = A68G_FALSE;
312 TMP_FILE (file) = A68G_TRUE;
313 FILE_ENTRY (file) = store_file_entry (p, FD (file), tfilename, TMP_FILE (file));
314 return FD (file);
315 }
316 } else {
317 // Opening an identified file.
318 A68G_REF ref_filename = IDENTIFICATION (file);
319 CHECK_REF (p, ref_filename, M_ROWS);
320 char *filename = DEREF (char, &ref_filename);
321 BOOL_T write_mood = (flags & A68G_WRITE_ACCESS) != 0;
322 if (write_mood) {
323 // A68G creates a file when it does not exist.
324 flags |= O_CREAT;
325 }
326 if (APPEND (file)) {
327 // Append to the end upon opening for writing.
328 if (write_mood) {
329 flags |= O_APPEND;
330 }
331 APPEND (file) = A68G_FALSE;
332 } else if (write_mood) {
333 // Empty a file upon opening for writing.
334 flags |= O_TRUNC;
335 }
336 if (OPEN_EXCLUSIVE (file)) {
337 // Require that the file be non-existent.
338 if (write_mood) {
339 flags |= O_EXCL;
340 }
341 OPEN_EXCLUSIVE (file) = A68G_FALSE;
342 }
343 FD (file) = open (filename, flags, permissions);
344 TRANSPUT_BUFFER (file) = get_unblocked_transput_buffer (p);
345 reset_transput_buffer (TRANSPUT_BUFFER (file));
346 END_OF_FILE (file) = A68G_FALSE;
347 FILE_ENTRY (file) = store_file_entry (p, FD (file), filename, TMP_FILE (file));
348 return FD (file);
349 }
350 }
351
352 //! @brief Call PROC (REF FILE) VOID during transput.
353
354 void genie_call_proc_ref_file_void (NODE_T * p, A68G_REF ref_file, A68G_PROCEDURE z)
355 {
356 ADDR_T pop_sp = A68G_SP, pop_fp = A68G_FP;
357 MOID_T *u = M_PROC_REF_FILE_VOID;
358 PUSH_REF (p, ref_file);
359 genie_call_procedure (p, MOID (&z), u, u, &z, pop_sp, pop_fp);
360 A68G_SP = pop_sp; // Voiding
361 }
362
363 // Unformatted transput.
364
365 //! @brief Hexadecimal value of digit.
366
367 int char_value (int ch)
368 {
369 switch (ch) {
370 case '0': {
371 return 0;
372 }
373 case '1': {
374 return 1;
375 }
376 case '2': {
377 return 2;
378 }
379 case '3': {
380 return 3;
381 }
382 case '4': {
383 return 4;
384 }
385 case '5': {
386 return 5;
387 }
388 case '6': {
389 return 6;
390 }
391 case '7': {
392 return 7;
393 }
394 case '8': {
395 return 8;
396 }
397 case '9': {
398 return 9;
399 }
400 case 'A':
401 case 'a': {
402 return 10;
403 }
404 case 'B':
405 case 'b': {
406 return 11;
407 }
408 case 'C':
409 case 'c': {
410 return 12;
411 }
412 case 'D':
413 case 'd': {
414 return 13;
415 }
416 case 'E':
417 case 'e': {
418 return 14;
419 }
420 case 'F':
421 case 'f': {
422 return 15;
423 }
424 default: {
425 return -1;
426 }
427 }
428 }
429
430 //! @brief INT value of BITS denotation
431
432 UNSIGNED_T bits_to_int (NODE_T * p, char *str)
433 {
434 errno = 0;
435 char *radix = NO_TEXT, *end = NO_TEXT;
436 int base = (int) a68g_strtou (str, &radix, 10);
437 if (radix != NO_TEXT && TO_UPPER (radix[0]) == TO_UPPER (RADIX_CHAR) && errno == 0) {
438 UNSIGNED_T bits = 0;
439 if (base < 2 || base > 16) {
440 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, base);
441 exit_genie (p, A68G_RUNTIME_ERROR);
442 }
443 bits = a68g_strtou (&(radix[1]), &end, base);
444 if (end != NO_TEXT && end[0] == NULL_CHAR && errno == 0) {
445 return bits;
446 }
447 }
448 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, M_BITS);
449 exit_genie (p, A68G_RUNTIME_ERROR);
450 return 0;
451 }
452
453 //! @brief Convert string to required mode and store.
454
455 BOOL_T genie_string_to_value_internal (NODE_T * p, MOID_T * m, char *a, BYTE_T * item)
456 {
457 errno = 0;
458 // strto.. does not mind empty strings.
459 if (strlen (a) == 0) {
460 return A68G_FALSE;
461 }
462 if (m == M_INT) {
463 A68G_INT *z = (A68G_INT *) item;
464 char *end;
465 VALUE (z) = (INT_T) a68g_strtoi (a, &end, 10);
466 if (end[0] == NULL_CHAR && errno == 0) {
467 STATUS (z) = INIT_MASK;
468 return A68G_TRUE;
469 } else {
470 return A68G_FALSE;
471 }
472 }
473 if (m == M_REAL) {
474 A68G_REAL *z = (A68G_REAL *) item;
475 char *end;
476 VALUE (z) = strtod (a, &end);
477 if (end[0] == NULL_CHAR && errno == 0) {
478 STATUS (z) = INIT_MASK;
479 return A68G_TRUE;
480 } else {
481 return A68G_FALSE;
482 }
483 }
484 #if (A68G_LEVEL >= 3)
485 if (m == M_LONG_INT) {
486 A68G_LONG_INT *z = (A68G_LONG_INT *) item;
487 if (string_to_double_int (p, z, a) == A68G_FALSE) {
488 return A68G_FALSE;
489 }
490 STATUS (z) = INIT_MASK;
491 return A68G_TRUE;
492 }
493 if (m == M_LONG_REAL) {
494 A68G_LONG_REAL *z = (A68G_LONG_REAL *) item;
495 char *end;
496 // VALUE (z).f = strtoflt128 (a, &end);
497 VALUE (z).f = string_to_double (a, &end);
498 MATH_RTE (p, errno != 0, M_LONG_REAL, ERROR_MATH);
499 if (end[0] == NULL_CHAR && errno == 0) {
500 STATUS (z) = INIT_MASK;
501 return A68G_TRUE;
502 } else {
503 return A68G_FALSE;
504 }
505 }
506 if (m == M_LONG_BITS) {
507 A68G_LONG_BITS *z = (A68G_LONG_BITS *) item;
508 int ret = A68G_TRUE;
509 DOUBLE_NUM_T b;
510 set_lw (b, 0x0);
511 if (a[0] == FLIP_CHAR || a[0] == FLOP_CHAR) {
512 // [] BOOL denotation is "TTFFFFTFT ...".
513 if (strlen (a) > (size_t) A68G_LONG_BITS_WIDTH) {
514 errno = ERANGE;
515 ret = A68G_FALSE;
516 } else {
517 int n = 1;
518 UNSIGNED_T k = 0x1;
519 for (INT_T j = (INT_T) strlen (a) - 1; j >= 0; j--) {
520 if (a[j] == FLIP_CHAR) {
521 if (n <= A68G_LONG_BITS_WIDTH / 2) {
522 LW (b) |= k;
523 } else {
524 HW (b) |= k;
525 }
526 } else if (a[j] != FLOP_CHAR) {
527 ret = A68G_FALSE;
528 }
529 k <<= 1;
530 }
531 }
532 VALUE (z) = b;
533 } else {
534 // BITS denotation.
535 VALUE (z) = double_strtou (p, a);
536 }
537 return ret;
538 }
539 #else
540 if (m == M_LONG_BITS || m == M_LONG_LONG_BITS) {
541 int digits = DIGITS (m);
542 int status = A68G_TRUE;
543 ADDR_T pop_sp = A68G_SP;
544 MP_T *z = (MP_T *) item;
545 if (a[0] == FLIP_CHAR || a[0] == FLOP_CHAR) {
546 // [] BOOL denotation is "TTFFFFTFT ...".
547 if (strlen (a) > (size_t) A68G_BITS_WIDTH) {
548 errno = ERANGE;
549 status = A68G_FALSE;
550 } else {
551 MP_T *w = lit_mp (p, 1, 0, digits);
552 SET_MP_ZERO (z, digits);
553 for (INT_T j = (INT_T) strlen (a) - 1; j >= 0; j--) {
554 if (a[j] == FLIP_CHAR) {
555 (void) add_mp (p, z, z, w, digits);
556 } else if (a[j] != FLOP_CHAR) {
557 status = A68G_FALSE;
558 }
559 (void) mul_mp_digit (p, w, w, (MP_T) 2, digits);
560 }
561 }
562 } else {
563 // BITS denotation is also allowed.
564 mp_strtou (p, z, a, m);
565 }
566 A68G_SP = pop_sp;
567 if (errno != 0 || status == A68G_FALSE) {
568 return A68G_FALSE;
569 }
570 MP_STATUS (z) = (MP_T) INIT_MASK;
571 return A68G_TRUE;
572 }
573 #endif
574 if (m == M_LONG_INT || m == M_LONG_LONG_INT) {
575 int digits = DIGITS (m);
576 MP_T *z = (MP_T *) item;
577 if (strtomp (p, z, a, digits) == NaN_MP) {
578 return A68G_FALSE;
579 }
580 if (!check_mp_int (z, m)) {
581 errno = ERANGE;
582 return A68G_FALSE;
583 }
584 MP_STATUS (z) = (MP_T) INIT_MASK;
585 return A68G_TRUE;
586 }
587 if (m == M_LONG_REAL || m == M_LONG_LONG_REAL) {
588 int digits = DIGITS (m);
589 MP_T *z = (MP_T *) item;
590 if (strtomp (p, z, a, digits) == NaN_MP) {
591 return A68G_FALSE;
592 }
593 MP_STATUS (z) = (MP_T) INIT_MASK;
594 return A68G_TRUE;
595 }
596 if (m == M_BOOL) {
597 A68G_BOOL *z = (A68G_BOOL *) item;
598 char q = a[0], flip = FLIP_CHAR, flop = FLOP_CHAR;
599 if (q == flip || q == flop) {
600 VALUE (z) = (BOOL_T) (q == flip);
601 STATUS (z) = INIT_MASK;
602 return A68G_TRUE;
603 } else {
604 return A68G_FALSE;
605 }
606 }
607 if (m == M_BITS) {
608 A68G_BITS *z = (A68G_BITS *) item;
609 int status = A68G_TRUE;
610 if (a[0] == FLIP_CHAR || a[0] == FLOP_CHAR) {
611 // [] BOOL denotation is "TTFFFFTFT ...".
612 if (strlen (a) > (size_t) A68G_BITS_WIDTH) {
613 errno = ERANGE;
614 status = A68G_FALSE;
615 } else {
616 UNSIGNED_T k = 0x1;
617 VALUE (z) = 0;
618 for (INT_T j = (INT_T) strlen (a) - 1; j >= 0; j--) {
619 if (a[j] == FLIP_CHAR) {
620 VALUE (z) += k;
621 } else if (a[j] != FLOP_CHAR) {
622 status = A68G_FALSE;
623 }
624 k <<= 1;
625 }
626 }
627 } else {
628 // BITS denotation is also allowed.
629 VALUE (z) = bits_to_int (p, a);
630 }
631 if (errno != 0 || status == A68G_FALSE) {
632 return A68G_FALSE;
633 }
634 STATUS (z) = INIT_MASK;
635 return A68G_TRUE;
636 }
637 return A68G_FALSE;
638 }
639
640 //! @brief Convert string in input buffer to value of required mode.
641
642 void genie_string_to_value (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
643 {
644 char *str = get_transput_buffer (INPUT_BUFFER);
645 errno = 0;
646 // end string, just in case.
647 plusab_transput_buffer (p, INPUT_BUFFER, NULL_CHAR);
648 if (mode == M_INT) {
649 if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
650 value_error (p, mode, ref_file);
651 }
652 } else if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
653 if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
654 value_error (p, mode, ref_file);
655 }
656 } else if (mode == M_REAL) {
657 if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
658 value_error (p, mode, ref_file);
659 }
660 } else if (mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
661 if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
662 value_error (p, mode, ref_file);
663 }
664 } else if (mode == M_BOOL) {
665 if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
666 value_error (p, mode, ref_file);
667 }
668 } else if (mode == M_BITS) {
669 if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
670 value_error (p, mode, ref_file);
671 }
672 } else if (mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
673 if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
674 value_error (p, mode, ref_file);
675 }
676 } else if (mode == M_CHAR) {
677 A68G_CHAR *z = (A68G_CHAR *) item;
678 if (str[0] == NULL_CHAR) {
679 // value_error (p, mode, ref_file);.
680 VALUE (z) = NULL_CHAR;
681 STATUS (z) = INIT_MASK;
682 } else {
683 size_t len = strlen (str);
684 if (len == 0 || len > 1) {
685 value_error (p, mode, ref_file);
686 }
687 VALUE (z) = str[0];
688 STATUS (z) = INIT_MASK;
689 }
690 } else if (mode == M_STRING) {
691 A68G_REF z;
692 z = c_to_a_string (p, str, get_transput_buffer_index (INPUT_BUFFER) - 1);
693 *(A68G_REF *) item = z;
694 }
695 if (errno != 0) {
696 transput_error (p, ref_file, mode);
697 }
698 }
699
700 //! @brief Read object from file.
701
702 void genie_read_standard (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
703 {
704 A68G_FILE *f = FILE_DEREF (&ref_file);
705 errno = 0;
706 if (END_OF_FILE (f)) {
707 end_of_file_error (p, ref_file);
708 }
709 if (mode == M_PROC_REF_FILE_VOID) {
710 genie_call_proc_ref_file_void (p, ref_file, *(A68G_PROCEDURE *) item);
711 } else if (mode == M_FORMAT) {
712 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_FORMAT);
713 exit_genie (p, A68G_RUNTIME_ERROR);
714 } else if (mode == M_REF_SOUND) {
715 read_sound (p, ref_file, DEREF (A68G_SOUND, (A68G_REF *) item));
716 } else if (IS_REF (mode)) {
717 CHECK_REF (p, *(A68G_REF *) item, mode);
718 genie_read_standard (p, SUB (mode), ADDRESS ((A68G_REF *) item), ref_file);
719 } else if (mode == M_INT || mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
720 scan_integer (p, ref_file);
721 genie_string_to_value (p, mode, item, ref_file);
722 } else if (mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
723 scan_real (p, ref_file);
724 genie_string_to_value (p, mode, item, ref_file);
725 } else if (mode == M_BOOL) {
726 scan_char (p, ref_file);
727 genie_string_to_value (p, mode, item, ref_file);
728 } else if (mode == M_CHAR) {
729 scan_char (p, ref_file);
730 genie_string_to_value (p, mode, item, ref_file);
731 } else if (mode == M_BITS || mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
732 scan_bits (p, ref_file);
733 genie_string_to_value (p, mode, item, ref_file);
734 } else if (mode == M_STRING) {
735 char *term = DEREF (char, &TERMINATOR (f));
736 scan_string (p, term, ref_file);
737 genie_string_to_value (p, mode, item, ref_file);
738 } else if (IS_STRUCT (mode)) {
739 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
740 genie_read_standard (p, MOID (q), &item[OFFSET (q)], ref_file);
741 }
742 } else if (IS_UNION (mode)) {
743 A68G_UNION *z = (A68G_UNION *) item;
744 if (!(STATUS (z) | INIT_MASK) || VALUE (z) == NULL) {
745 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE, mode);
746 exit_genie (p, A68G_RUNTIME_ERROR);
747 }
748 genie_read_standard (p, (MOID_T *) (VALUE (z)), &item[A68G_UNION_SIZE], ref_file);
749 } else if (IS_ROW (mode) || IS_FLEX (mode)) {
750 MOID_T *deflexed = DEFLEX (mode);
751 A68G_ARRAY *arr;
752 A68G_TUPLE *tup;
753 CHECK_INIT (p, INITIALISED ((A68G_REF *) item), mode);
754 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
755 if (get_row_size (tup, DIM (arr)) > 0) {
756 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
757 BOOL_T done = A68G_FALSE;
758 initialise_internal_index (tup, DIM (arr));
759 while (!done) {
760 ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
761 ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
762 genie_read_standard (p, SUB (deflexed), &base_addr[elem_addr], ref_file);
763 done = increment_internal_index (tup, DIM (arr));
764 }
765 }
766 }
767 if (errno != 0) {
768 transput_error (p, ref_file, mode);
769 }
770 }
771
772 //! @brief PROC ([] SIMPLIN) VOID read
773
774 void genie_read (NODE_T * p)
775 {
776 A68G_REF row;
777 POP_REF (p, &row);
778 genie_stand_in (p);
779 PUSH_REF (p, row);
780 genie_read_file (p);
781 }
782
783 //! @brief Open for reading.
784
785 void open_for_reading (NODE_T * p, A68G_REF ref_file)
786 {
787 A68G_FILE *file = FILE_DEREF (&ref_file);
788 if (!OPENED (file)) {
789 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
790 exit_genie (p, A68G_RUNTIME_ERROR);
791 }
792 if (DRAW_MOOD (file)) {
793 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
794 exit_genie (p, A68G_RUNTIME_ERROR);
795 }
796 if (WRITE_MOOD (file)) {
797 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
798 exit_genie (p, A68G_RUNTIME_ERROR);
799 }
800 if (!GET (&CHANNEL (file))) {
801 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "getting");
802 exit_genie (p, A68G_RUNTIME_ERROR);
803 }
804 if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
805 if (IS_NIL (STRING (file))) {
806 if ((FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS, 0)) == A68G_NO_FILE) {
807 open_error (p, ref_file, "getting");
808 }
809 } else {
810 FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS, 0);
811 }
812 DRAW_MOOD (file) = A68G_FALSE;
813 READ_MOOD (file) = A68G_TRUE;
814 WRITE_MOOD (file) = A68G_FALSE;
815 CHAR_MOOD (file) = A68G_TRUE;
816 }
817 if (!CHAR_MOOD (file)) {
818 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "binary");
819 exit_genie (p, A68G_RUNTIME_ERROR);
820 }
821 }
822
823 //! @brief PROC (REF FILE, [] SIMPLIN) VOID get
824
825 void genie_read_file (NODE_T * p)
826 {
827 A68G_REF row; A68G_ARRAY *arr; A68G_TUPLE *tup;
828 POP_REF (p, &row);
829 CHECK_REF (p, row, M_ROW_SIMPLIN);
830 GET_DESCRIPTOR (arr, tup, &row);
831 int elems = ROW_SIZE (tup);
832 A68G_REF ref_file;
833 POP_REF (p, &ref_file);
834 CHECK_REF (p, ref_file, M_REF_FILE);
835 A68G_FILE *file = FILE_DEREF (&ref_file);
836 CHECK_INIT (p, INITIALISED (file), M_FILE);
837 open_for_reading (p, ref_file);
838 // Read.
839 if (elems <= 0) {
840 return;
841 }
842 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
843 int elem_index = 0;
844 for (int k = 0; k < elems; k++) {
845 A68G_UNION *z = (A68G_UNION *) & base_address[elem_index];
846 MOID_T *mode = (MOID_T *) (VALUE (z));
847 BYTE_T *item = (BYTE_T *) & base_address[elem_index + A68G_UNION_SIZE];
848 genie_read_standard (p, mode, item, ref_file);
849 elem_index += SIZE (M_SIMPLIN);
850 }
851 }
852
853 //! @brief Convert value to string.
854
855 void genie_value_to_string (NODE_T * p, MOID_T * moid, BYTE_T * item, int mod)
856 {
857 if (moid == M_INT) {
858 A68G_INT *z = (A68G_INT *) item;
859 PUSH_UNION (p, M_INT);
860 PUSH_VALUE (p, VALUE (z), A68G_INT);
861 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_INT)));
862 if (mod == FORMAT_ITEM_G) {
863 PUSH_VALUE (p, A68G_INT_WIDTH + 1, A68G_INT);
864 genie_whole (p);
865 } else if (mod == FORMAT_ITEM_H) {
866 PUSH_VALUE (p, A68G_REAL_WIDTH + A68G_EXP_WIDTH + 4, A68G_INT);
867 PUSH_VALUE (p, A68G_REAL_WIDTH - 1, A68G_INT);
868 PUSH_VALUE (p, A68G_EXP_WIDTH + 1, A68G_INT);
869 PUSH_VALUE (p, 3, A68G_INT);
870 genie_real (p);
871 }
872 return;
873 }
874 #if (A68G_LEVEL >= 3)
875 if (moid == M_LONG_INT) {
876 A68G_LONG_INT *z = (A68G_LONG_INT *) item;
877 PUSH_UNION (p, M_LONG_INT);
878 PUSH (p, z, SIZE (M_LONG_INT));
879 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_INT)));
880 if (mod == FORMAT_ITEM_G) {
881 PUSH_VALUE (p, A68G_LONG_WIDTH + 1, A68G_INT);
882 genie_whole (p);
883 } else if (mod == FORMAT_ITEM_H) {
884 PUSH_VALUE (p, A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4, A68G_INT);
885 PUSH_VALUE (p, A68G_LONG_REAL_WIDTH - 1, A68G_INT);
886 PUSH_VALUE (p, A68G_LONG_EXP_WIDTH + 1, A68G_INT);
887 PUSH_VALUE (p, 3, A68G_INT);
888 genie_real (p);
889 }
890 return;
891 }
892 if (moid == M_LONG_REAL) {
893 A68G_LONG_REAL *z = (A68G_LONG_REAL *) item;
894 PUSH_UNION (p, M_LONG_REAL);
895 PUSH_VALUE (p, VALUE (z), A68G_LONG_REAL);
896 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_REAL)));
897 PUSH_VALUE (p, A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4, A68G_INT);
898 PUSH_VALUE (p, A68G_LONG_REAL_WIDTH - 1, A68G_INT);
899 PUSH_VALUE (p, A68G_LONG_EXP_WIDTH + 1, A68G_INT);
900 if (mod == FORMAT_ITEM_G) {
901 genie_float (p);
902 } else if (mod == FORMAT_ITEM_H) {
903 PUSH_VALUE (p, 3, A68G_INT);
904 genie_real (p);
905 }
906 return;
907 }
908 if (moid == M_LONG_BITS) {
909 A68G_LONG_BITS *z = (A68G_LONG_BITS *) item;
910 char *s = stack_string (p, 8 + A68G_LONG_BITS_WIDTH);
911 int n = 0;
912 for (int w = 0; w <= 1; w++) {
913 UNSIGNED_T bit = D_SIGN;
914 for (int j = 0; j < A68G_BITS_WIDTH; j++) {
915 if (w == 0) {
916 s[n] = (char) ((HW (VALUE (z)) & bit) ? FLIP_CHAR : FLOP_CHAR);
917 } else {
918 s[n] = (char) ((LW (VALUE (z)) & bit) ? FLIP_CHAR : FLOP_CHAR);
919 }
920 bit >>= 1;
921 n++;
922 }
923 }
924 s[n] = NULL_CHAR;
925 return;
926 }
927 #else
928 if (moid == M_LONG_BITS || moid == M_LONG_LONG_BITS) {
929 int bits = get_mp_bits_width (moid), word = get_mp_bits_words (moid);
930 int pos = bits;
931 char *str = stack_string (p, 8 + bits);
932 ADDR_T pop_sp = A68G_SP;
933 unt *row = stack_mp_bits (p, (MP_T *) item, moid);
934 str[pos--] = NULL_CHAR;
935 while (pos >= 0) {
936 unt bit = 0x1;
937 for (int j = 0; j < MP_BITS_BITS && pos >= 0; j++) {
938 str[pos--] = (char) ((row[word - 1] & bit) ? FLIP_CHAR : FLOP_CHAR);
939 bit <<= 1;
940 }
941 word--;
942 }
943 A68G_SP = pop_sp;
944 return;
945 }
946 #endif
947 if (moid == M_LONG_INT) {
948 MP_T *z = (MP_T *) item;
949 PUSH_UNION (p, M_LONG_INT);
950 PUSH (p, z, SIZE (M_LONG_INT));
951 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_INT)));
952 if (mod == FORMAT_ITEM_G) {
953 PUSH_VALUE (p, A68G_LONG_WIDTH + 1, A68G_INT);
954 genie_whole (p);
955 } else if (mod == FORMAT_ITEM_H) {
956 PUSH_VALUE (p, A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4, A68G_INT);
957 PUSH_VALUE (p, A68G_LONG_REAL_WIDTH - 1, A68G_INT);
958 PUSH_VALUE (p, A68G_LONG_EXP_WIDTH + 1, A68G_INT);
959 PUSH_VALUE (p, 3, A68G_INT);
960 genie_real (p);
961 }
962 return;
963 }
964 if (moid == M_LONG_LONG_INT) {
965 MP_T *z = (MP_T *) item;
966 PUSH_UNION (p, M_LONG_LONG_INT);
967 PUSH (p, z, SIZE (M_LONG_LONG_INT));
968 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_LONG_INT)));
969 if (mod == FORMAT_ITEM_G) {
970 PUSH_VALUE (p, A68G_LONG_LONG_WIDTH + 1, A68G_INT);
971 genie_whole (p);
972 } else if (mod == FORMAT_ITEM_H) {
973 PUSH_VALUE (p, A68G_LONG_LONG_REAL_WIDTH + A68G_LONG_LONG_EXP_WIDTH + 4, A68G_INT);
974 PUSH_VALUE (p, A68G_LONG_LONG_REAL_WIDTH - 1, A68G_INT);
975 PUSH_VALUE (p, A68G_LONG_LONG_EXP_WIDTH + 1, A68G_INT);
976 PUSH_VALUE (p, 3, A68G_INT);
977 genie_real (p);
978 }
979 return;
980 }
981 if (moid == M_REAL) {
982 A68G_REAL *z = (A68G_REAL *) item;
983 PUSH_UNION (p, M_REAL);
984 PUSH_VALUE (p, VALUE (z), A68G_REAL);
985 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_REAL)));
986 PUSH_VALUE (p, A68G_REAL_WIDTH + A68G_EXP_WIDTH + 4, A68G_INT);
987 PUSH_VALUE (p, A68G_REAL_WIDTH - 1, A68G_INT);
988 PUSH_VALUE (p, A68G_EXP_WIDTH + 1, A68G_INT);
989 if (mod == FORMAT_ITEM_G) {
990 genie_float (p);
991 } else if (mod == FORMAT_ITEM_H) {
992 PUSH_VALUE (p, 3, A68G_INT);
993 genie_real (p);
994 }
995 return;
996 }
997 if (moid == M_LONG_REAL) {
998 MP_T *z = (MP_T *) item;
999 PUSH_UNION (p, M_LONG_REAL);
1000 PUSH (p, z, (int) SIZE (M_LONG_REAL));
1001 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_REAL)));
1002 PUSH_VALUE (p, A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4, A68G_INT);
1003 PUSH_VALUE (p, A68G_LONG_REAL_WIDTH - 1, A68G_INT);
1004 PUSH_VALUE (p, A68G_LONG_EXP_WIDTH + 1, A68G_INT);
1005 if (mod == FORMAT_ITEM_G) {
1006 genie_float (p);
1007 } else if (mod == FORMAT_ITEM_H) {
1008 PUSH_VALUE (p, 3, A68G_INT);
1009 genie_real (p);
1010 }
1011 return;
1012 }
1013 if (moid == M_LONG_LONG_REAL) {
1014 MP_T *z = (MP_T *) item;
1015 PUSH_UNION (p, M_LONG_LONG_REAL);
1016 PUSH (p, z, (int) SIZE (M_LONG_LONG_REAL));
1017 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_LONG_REAL)));
1018 PUSH_VALUE (p, A68G_LONG_LONG_REAL_WIDTH + A68G_LONG_LONG_EXP_WIDTH + 4, A68G_INT);
1019 PUSH_VALUE (p, A68G_LONG_LONG_REAL_WIDTH - 1, A68G_INT);
1020 PUSH_VALUE (p, A68G_LONG_LONG_EXP_WIDTH + 1, A68G_INT);
1021 if (mod == FORMAT_ITEM_G) {
1022 genie_float (p);
1023 } else if (mod == FORMAT_ITEM_H) {
1024 PUSH_VALUE (p, 3, A68G_INT);
1025 genie_real (p);
1026 }
1027 return;
1028 }
1029 if (moid == M_BITS) {
1030 A68G_BITS *z = (A68G_BITS *) item;
1031 char *str = stack_string (p, 8 + A68G_BITS_WIDTH);
1032 UNSIGNED_T bit = 0x1;
1033 int j;
1034 for (j = 1; j < A68G_BITS_WIDTH; j++) {
1035 bit <<= 1;
1036 }
1037 for (j = 0; j < A68G_BITS_WIDTH; j++) {
1038 str[j] = (char) ((VALUE (z) & bit) ? FLIP_CHAR : FLOP_CHAR);
1039 bit >>= 1;
1040 }
1041 str[j] = NULL_CHAR;
1042 return;
1043 }
1044 }
1045
1046 //! @brief Print object to file.
1047
1048 void genie_write_standard (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
1049 {
1050 errno = 0;
1051 ABEND (mode == NO_MOID, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
1052 if (mode == M_PROC_REF_FILE_VOID) {
1053 genie_call_proc_ref_file_void (p, ref_file, *(A68G_PROCEDURE *) item);
1054 } else if (mode == M_FORMAT) {
1055 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_FORMAT);
1056 exit_genie (p, A68G_RUNTIME_ERROR);
1057 } else if (mode == M_SOUND) {
1058 write_sound (p, ref_file, (A68G_SOUND *) item);
1059 } else if (mode == M_INT || mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
1060 genie_value_to_string (p, mode, item, FORMAT_ITEM_G);
1061 add_string_from_stack_transput_buffer (p, UNFORMATTED_BUFFER);
1062 } else if (mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
1063 genie_value_to_string (p, mode, item, FORMAT_ITEM_G);
1064 add_string_from_stack_transput_buffer (p, UNFORMATTED_BUFFER);
1065 } else if (mode == M_BOOL) {
1066 A68G_BOOL *z = (A68G_BOOL *) item;
1067 char flipflop = (char) (VALUE (z) == A68G_TRUE ? FLIP_CHAR : FLOP_CHAR);
1068 plusab_transput_buffer (p, UNFORMATTED_BUFFER, flipflop);
1069 } else if (mode == M_CHAR) {
1070 A68G_CHAR *ch = (A68G_CHAR *) item;
1071 plusab_transput_buffer (p, UNFORMATTED_BUFFER, (char) VALUE (ch));
1072 } else if (mode == M_BITS || mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
1073 char *str = (char *) STACK_TOP;
1074 genie_value_to_string (p, mode, item, FORMAT_ITEM_G);
1075 add_string_transput_buffer (p, UNFORMATTED_BUFFER, str);
1076 } else if (mode == M_ROW_CHAR || mode == M_STRING) {
1077 // Handle these separately since this is faster than straightening.
1078 add_a_string_transput_buffer (p, UNFORMATTED_BUFFER, item);
1079 } else if (IS_UNION (mode)) {
1080 A68G_UNION *z = (A68G_UNION *) item;
1081 MOID_T *um = (MOID_T *) (VALUE (z));
1082 BYTE_T *ui = &item[A68G_UNION_SIZE];
1083 if (um == NO_MOID) {
1084 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE, mode);
1085 exit_genie (p, A68G_RUNTIME_ERROR);
1086 }
1087 genie_write_standard (p, um, ui, ref_file);
1088 } else if (IS_STRUCT (mode)) {
1089 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
1090 BYTE_T *elem = &item[OFFSET (q)];
1091 genie_check_initialisation (p, elem, MOID (q));
1092 genie_write_standard (p, MOID (q), elem, ref_file);
1093 }
1094 } else if (IS_ROW (mode) || IS_FLEX (mode)) {
1095 MOID_T *deflexed = DEFLEX (mode);
1096 A68G_ARRAY *arr;
1097 A68G_TUPLE *tup;
1098 CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
1099 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
1100 if (get_row_size (tup, DIM (arr)) > 0) {
1101 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
1102 BOOL_T done = A68G_FALSE;
1103 initialise_internal_index (tup, DIM (arr));
1104 while (!done) {
1105 ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
1106 ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
1107 BYTE_T *elem = &base_addr[elem_addr];
1108 genie_check_initialisation (p, elem, SUB (deflexed));
1109 genie_write_standard (p, SUB (deflexed), elem, ref_file);
1110 done = increment_internal_index (tup, DIM (arr));
1111 }
1112 }
1113 }
1114 if (errno != 0) {
1115 ABEND (IS_NIL (ref_file), ERROR_ACTION, error_specification ());
1116 transput_error (p, ref_file, mode);
1117 }
1118 }
1119
1120 //! @brief PROC ([] SIMPLOUT) VOID print, write
1121
1122 void genie_write (NODE_T * p)
1123 {
1124 A68G_REF row;
1125 POP_REF (p, &row);
1126 genie_stand_out (p);
1127 PUSH_REF (p, row);
1128 genie_write_file (p);
1129 }
1130
1131 //! @brief Open for writing.
1132
1133 void open_for_writing (NODE_T * p, A68G_REF ref_file)
1134 {
1135 A68G_FILE *file = FILE_DEREF (&ref_file);
1136 if (!OPENED (file)) {
1137 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1138 exit_genie (p, A68G_RUNTIME_ERROR);
1139 }
1140 if (DRAW_MOOD (file)) {
1141 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1142 exit_genie (p, A68G_RUNTIME_ERROR);
1143 }
1144 if (READ_MOOD (file)) {
1145 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "read");
1146 exit_genie (p, A68G_RUNTIME_ERROR);
1147 }
1148 if (!PUT (&CHANNEL (file))) {
1149 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "putting");
1150 exit_genie (p, A68G_RUNTIME_ERROR);
1151 }
1152 if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
1153 if (IS_NIL (STRING (file))) {
1154 if ((FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS, A68G_PROTECTION)) == A68G_NO_FILE) {
1155 open_error (p, ref_file, "putting");
1156 }
1157 } else {
1158 FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS, 0);
1159 }
1160 DRAW_MOOD (file) = A68G_FALSE;
1161 READ_MOOD (file) = A68G_FALSE;
1162 WRITE_MOOD (file) = A68G_TRUE;
1163 CHAR_MOOD (file) = A68G_TRUE;
1164 }
1165 if (!CHAR_MOOD (file)) {
1166 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "binary");
1167 exit_genie (p, A68G_RUNTIME_ERROR);
1168 }
1169 }
1170
1171 //! @brief PROC (REF FILE, [] SIMPLOUT) VOID put
1172
1173 void genie_write_file (NODE_T * p)
1174 {
1175 A68G_REF row; A68G_ARRAY *arr; A68G_TUPLE *tup;
1176 POP_REF (p, &row);
1177 CHECK_REF (p, row, M_ROW_SIMPLOUT);
1178 GET_DESCRIPTOR (arr, tup, &row);
1179 int elems = ROW_SIZE (tup);
1180 A68G_REF ref_file;
1181 POP_REF (p, &ref_file);
1182 CHECK_REF (p, ref_file, M_REF_FILE);
1183 A68G_FILE *file = FILE_DEREF (&ref_file);
1184 CHECK_INIT (p, INITIALISED (file), M_FILE);
1185 open_for_writing (p, ref_file);
1186 // Write.
1187 if (elems <= 0) {
1188 return;
1189 }
1190 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
1191 int elem_index = 0;
1192 for (int k = 0; k < elems; k++) {
1193 A68G_UNION *z = (A68G_UNION *) & (base_address[elem_index]);
1194 MOID_T *mode = (MOID_T *) (VALUE (z));
1195 BYTE_T *item = (BYTE_T *) & base_address[elem_index + A68G_UNION_SIZE];
1196 reset_transput_buffer (UNFORMATTED_BUFFER);
1197 genie_write_standard (p, mode, item, ref_file);
1198 write_purge_buffer (p, ref_file, UNFORMATTED_BUFFER);
1199 elem_index += SIZE (M_SIMPLOUT);
1200 }
1201 }
1202
1203 //! @brief Read object binary from file.
1204
1205 void genie_read_bin_standard (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
1206 {
1207 CHECK_REF (p, ref_file, M_REF_FILE);
1208 A68G_FILE *f = FILE_DEREF (&ref_file);
1209 errno = 0;
1210 if (END_OF_FILE (f)) {
1211 end_of_file_error (p, ref_file);
1212 }
1213 if (mode == M_PROC_REF_FILE_VOID) {
1214 genie_call_proc_ref_file_void (p, ref_file, *(A68G_PROCEDURE *) item);
1215 } else if (mode == M_FORMAT) {
1216 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_FORMAT);
1217 exit_genie (p, A68G_RUNTIME_ERROR);
1218 } else if (mode == M_REF_SOUND) {
1219 read_sound (p, ref_file, (A68G_SOUND *) ADDRESS ((A68G_REF *) item));
1220 } else if (IS_REF (mode)) {
1221 CHECK_REF (p, *(A68G_REF *) item, mode);
1222 genie_read_bin_standard (p, SUB (mode), ADDRESS ((A68G_REF *) item), ref_file);
1223 } else if (mode == M_INT) {
1224 A68G_INT *z = (A68G_INT *) item;
1225 ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1226 STATUS (z) = INIT_MASK;
1227 } else if (mode == M_LONG_INT) {
1228 #if (A68G_LEVEL >= 3)
1229 A68G_LONG_INT *z = (A68G_LONG_INT *) item;
1230 ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1231 STATUS (z) = INIT_MASK;
1232 #else
1233 MP_T *z = (MP_T *) item;
1234 ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1235 MP_STATUS (z) = (MP_T) INIT_MASK;
1236 #endif
1237 } else if (mode == M_LONG_LONG_INT) {
1238 MP_T *z = (MP_T *) item;
1239 ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1240 MP_STATUS (z) = (MP_T) INIT_MASK;
1241 } else if (mode == M_REAL) {
1242 A68G_REAL *z = (A68G_REAL *) item;
1243 ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1244 STATUS (z) = INIT_MASK;
1245 } else if (mode == M_LONG_REAL) {
1246 #if (A68G_LEVEL >= 3)
1247 A68G_LONG_REAL *z = (A68G_LONG_REAL *) item;
1248 ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1249 STATUS (z) = INIT_MASK;
1250 #else
1251 MP_T *z = (MP_T *) item;
1252 ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1253 MP_STATUS (z) = (MP_T) INIT_MASK;
1254 #endif
1255 } else if (mode == M_LONG_LONG_REAL) {
1256 MP_T *z = (MP_T *) item;
1257 ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1258 MP_STATUS (z) = (MP_T) INIT_MASK;
1259 } else if (mode == M_BOOL) {
1260 A68G_BOOL *z = (A68G_BOOL *) item;
1261 ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1262 STATUS (z) = INIT_MASK;
1263 } else if (mode == M_CHAR) {
1264 A68G_CHAR *z = (A68G_CHAR *) item;
1265 ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1266 STATUS (z) = INIT_MASK;
1267 } else if (mode == M_BITS) {
1268 A68G_BITS *z = (A68G_BITS *) item;
1269 ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1270 STATUS (z) = INIT_MASK;
1271 } else if (mode == M_LONG_BITS) {
1272 #if (A68G_LEVEL >= 3)
1273 A68G_LONG_BITS *z = (A68G_LONG_BITS *) item;
1274 ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1275 STATUS (z) = INIT_MASK;
1276 #else
1277 MP_T *z = (MP_T *) item;
1278 ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1279 MP_STATUS (z) = (MP_T) INIT_MASK;
1280 #endif
1281 } else if (mode == M_LONG_LONG_BITS) {
1282 MP_T *z = (MP_T *) item;
1283 ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1284 MP_STATUS (z) = (MP_T) INIT_MASK;
1285 } else if (mode == M_ROW_CHAR || mode == M_STRING) {
1286 int len;
1287 ASSERT (io_read (FD (f), &(len), sizeof (len)) != -1);
1288 reset_transput_buffer (UNFORMATTED_BUFFER);
1289 for (int k = 0; k < len; k++) {
1290 char ch;
1291 ASSERT (io_read (FD (f), &(ch), sizeof (char)) != -1);
1292 plusab_transput_buffer (p, UNFORMATTED_BUFFER, ch);
1293 }
1294 *(A68G_REF *) item = c_to_a_string (p, get_transput_buffer (UNFORMATTED_BUFFER), DEFAULT_WIDTH);
1295 } else if (IS_UNION (mode)) {
1296 A68G_UNION *z = (A68G_UNION *) item;
1297 if (!(STATUS (z) | INIT_MASK) || VALUE (z) == NULL) {
1298 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE, mode);
1299 exit_genie (p, A68G_RUNTIME_ERROR);
1300 }
1301 genie_read_bin_standard (p, (MOID_T *) (VALUE (z)), &item[A68G_UNION_SIZE], ref_file);
1302 } else if (IS_STRUCT (mode)) {
1303 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
1304 genie_read_bin_standard (p, MOID (q), &item[OFFSET (q)], ref_file);
1305 }
1306 } else if (IS_ROW (mode) || IS_FLEX (mode)) {
1307 MOID_T *deflexed = DEFLEX (mode);
1308 A68G_ARRAY *arr; A68G_TUPLE *tup;
1309 CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
1310 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
1311 if (get_row_size (tup, DIM (arr)) > 0) {
1312 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
1313 BOOL_T done = A68G_FALSE;
1314 initialise_internal_index (tup, DIM (arr));
1315 while (!done) {
1316 ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
1317 ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
1318 genie_read_bin_standard (p, SUB (deflexed), &base_addr[elem_addr], ref_file);
1319 done = increment_internal_index (tup, DIM (arr));
1320 }
1321 }
1322 }
1323 if (errno != 0) {
1324 transput_error (p, ref_file, mode);
1325 }
1326 }
1327
1328 //! @brief PROC ([] SIMPLIN) VOID read bin
1329
1330 void genie_read_bin (NODE_T * p)
1331 {
1332 A68G_REF row;
1333 POP_REF (p, &row);
1334 genie_stand_back (p);
1335 PUSH_REF (p, row);
1336 genie_read_bin_file (p);
1337 }
1338
1339 //! @brief PROC (REF FILE, [] SIMPLIN) VOID get bin
1340
1341 void genie_read_bin_file (NODE_T * p)
1342 {
1343 A68G_REF row; A68G_ARRAY *arr; A68G_TUPLE *tup;
1344 POP_REF (p, &row);
1345 CHECK_REF (p, row, M_ROW_SIMPLIN);
1346 GET_DESCRIPTOR (arr, tup, &row);
1347 int elems = ROW_SIZE (tup);
1348 A68G_REF ref_file;
1349 POP_REF (p, &ref_file);
1350 ref_file = *(A68G_REF *) STACK_TOP;
1351 CHECK_REF (p, ref_file, M_REF_FILE);
1352 A68G_FILE *file = FILE_DEREF (&ref_file);
1353 CHECK_INIT (p, INITIALISED (file), M_FILE);
1354 if (!OPENED (file)) {
1355 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1356 exit_genie (p, A68G_RUNTIME_ERROR);
1357 }
1358 if (DRAW_MOOD (file)) {
1359 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1360 exit_genie (p, A68G_RUNTIME_ERROR);
1361 }
1362 if (WRITE_MOOD (file)) {
1363 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
1364 exit_genie (p, A68G_RUNTIME_ERROR);
1365 }
1366 if (!GET (&CHANNEL (file))) {
1367 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "getting");
1368 exit_genie (p, A68G_RUNTIME_ERROR);
1369 }
1370 if (!BIN (&CHANNEL (file))) {
1371 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "binary getting");
1372 exit_genie (p, A68G_RUNTIME_ERROR);
1373 }
1374 if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
1375 if ((FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS | O_BINARY, 0)) == A68G_NO_FILE) {
1376 open_error (p, ref_file, "binary getting");
1377 }
1378 DRAW_MOOD (file) = A68G_FALSE;
1379 READ_MOOD (file) = A68G_TRUE;
1380 WRITE_MOOD (file) = A68G_FALSE;
1381 CHAR_MOOD (file) = A68G_FALSE;
1382 }
1383 if (CHAR_MOOD (file)) {
1384 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "text");
1385 exit_genie (p, A68G_RUNTIME_ERROR);
1386 }
1387 // Read.
1388 if (elems <= 0) {
1389 return;
1390 }
1391 int elem_index = 0;
1392 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
1393 for (int k = 0; k < elems; k++) {
1394 A68G_UNION *z = (A68G_UNION *) & base_address[elem_index];
1395 MOID_T *mode = (MOID_T *) (VALUE (z));
1396 BYTE_T *item = (BYTE_T *) & base_address[elem_index + A68G_UNION_SIZE];
1397 genie_read_bin_standard (p, mode, item, ref_file);
1398 elem_index += SIZE (M_SIMPLIN);
1399 }
1400 }
1401
1402 //! @brief Write object binary to file.
1403
1404 void genie_write_bin_standard (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
1405 {
1406 CHECK_REF (p, ref_file, M_REF_FILE);
1407 A68G_FILE *f = FILE_DEREF (&ref_file);
1408 errno = 0;
1409 if (mode == M_PROC_REF_FILE_VOID) {
1410 genie_call_proc_ref_file_void (p, ref_file, *(A68G_PROCEDURE *) item);
1411 } else if (mode == M_FORMAT) {
1412 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_FORMAT);
1413 exit_genie (p, A68G_RUNTIME_ERROR);
1414 } else if (mode == M_SOUND) {
1415 write_sound (p, ref_file, (A68G_SOUND *) item);
1416 } else if (mode == M_INT) {
1417 ASSERT (io_write (FD (f), &(VALUE ((A68G_INT *) item)), sizeof (VALUE ((A68G_INT *) item))) != -1);
1418 } else if (mode == M_LONG_INT) {
1419 #if (A68G_LEVEL >= 3)
1420 ASSERT (io_write (FD (f), &(VALUE ((A68G_LONG_INT *) item)), sizeof (VALUE ((A68G_LONG_INT *) item))) != -1);
1421 #else
1422 ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1423 #endif
1424 } else if (mode == M_LONG_LONG_INT) {
1425 ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1426 } else if (mode == M_REAL) {
1427 ASSERT (io_write (FD (f), &(VALUE ((A68G_REAL *) item)), sizeof (VALUE ((A68G_REAL *) item))) != -1);
1428 } else if (mode == M_LONG_REAL) {
1429 #if (A68G_LEVEL >= 3)
1430 ASSERT (io_write (FD (f), &(VALUE ((A68G_LONG_REAL *) item)), sizeof (VALUE ((A68G_LONG_REAL *) item))) != -1);
1431 #else
1432 ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1433 #endif
1434 } else if (mode == M_LONG_LONG_REAL) {
1435 ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1436 } else if (mode == M_BOOL) {
1437 ASSERT (io_write (FD (f), &(VALUE ((A68G_BOOL *) item)), sizeof (VALUE ((A68G_BOOL *) item))) != -1);
1438 } else if (mode == M_CHAR) {
1439 ASSERT (io_write (FD (f), &(VALUE ((A68G_CHAR *) item)), sizeof (VALUE ((A68G_CHAR *) item))) != -1);
1440 } else if (mode == M_BITS) {
1441 ASSERT (io_write (FD (f), &(VALUE ((A68G_BITS *) item)), sizeof (VALUE ((A68G_BITS *) item))) != -1);
1442 } else if (mode == M_LONG_BITS) {
1443 #if (A68G_LEVEL >= 3)
1444 ASSERT (io_write (FD (f), &(VALUE ((A68G_LONG_BITS *) item)), sizeof (VALUE ((A68G_LONG_BITS *) item))) != -1);
1445 #else
1446 ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1447 #endif
1448 } else if (mode == M_LONG_LONG_BITS) {
1449 ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1450 } else if (mode == M_ROW_CHAR || mode == M_STRING) {
1451 reset_transput_buffer (UNFORMATTED_BUFFER);
1452 add_a_string_transput_buffer (p, UNFORMATTED_BUFFER, item);
1453 int len = get_transput_buffer_index (UNFORMATTED_BUFFER);
1454 ASSERT (io_write (FD (f), &(len), sizeof (len)) != -1);
1455 WRITE (FD (f), get_transput_buffer (UNFORMATTED_BUFFER));
1456 } else if (IS_UNION (mode)) {
1457 A68G_UNION *z = (A68G_UNION *) item;
1458 genie_write_bin_standard (p, (MOID_T *) (VALUE (z)), &item[A68G_UNION_SIZE], ref_file);
1459 } else if (IS_STRUCT (mode)) {
1460 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
1461 BYTE_T *elem = &item[OFFSET (q)];
1462 genie_check_initialisation (p, elem, MOID (q));
1463 genie_write_bin_standard (p, MOID (q), elem, ref_file);
1464 }
1465 } else if (IS_ROW (mode) || IS_FLEX (mode)) {
1466 MOID_T *deflexed = DEFLEX (mode);
1467 A68G_ARRAY *arr; A68G_TUPLE *tup;
1468 CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
1469 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
1470 if (get_row_size (tup, DIM (arr)) > 0) {
1471 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
1472 BOOL_T done = A68G_FALSE;
1473 initialise_internal_index (tup, DIM (arr));
1474 while (!done) {
1475 ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
1476 ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
1477 BYTE_T *elem = &base_addr[elem_addr];
1478 genie_check_initialisation (p, elem, SUB (deflexed));
1479 genie_write_bin_standard (p, SUB (deflexed), elem, ref_file);
1480 done = increment_internal_index (tup, DIM (arr));
1481 }
1482 }
1483 }
1484 if (errno != 0) {
1485 transput_error (p, ref_file, mode);
1486 }
1487 }
1488
1489 //! @brief PROC ([] SIMPLOUT) VOID write bin, print bin
1490
1491 void genie_write_bin (NODE_T * p)
1492 {
1493 A68G_REF row;
1494 POP_REF (p, &row);
1495 genie_stand_back (p);
1496 PUSH_REF (p, row);
1497 genie_write_bin_file (p);
1498 }
1499
1500 //! @brief PROC (REF FILE, [] SIMPLOUT) VOID put bin
1501
1502 void genie_write_bin_file (NODE_T * p)
1503 {
1504 A68G_REF row; A68G_ARRAY *arr; A68G_TUPLE *tup;
1505 POP_REF (p, &row);
1506 CHECK_REF (p, row, M_ROW_SIMPLOUT);
1507 GET_DESCRIPTOR (arr, tup, &row);
1508 int elems = ROW_SIZE (tup);
1509 A68G_REF ref_file;
1510 POP_REF (p, &ref_file);
1511 ref_file = *(A68G_REF *) STACK_TOP;
1512 CHECK_REF (p, ref_file, M_REF_FILE);
1513 A68G_FILE *file = FILE_DEREF (&ref_file);
1514 CHECK_INIT (p, INITIALISED (file), M_FILE);
1515 if (!OPENED (file)) {
1516 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1517 exit_genie (p, A68G_RUNTIME_ERROR);
1518 }
1519 if (DRAW_MOOD (file)) {
1520 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1521 exit_genie (p, A68G_RUNTIME_ERROR);
1522 }
1523 if (READ_MOOD (file)) {
1524 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "read");
1525 exit_genie (p, A68G_RUNTIME_ERROR);
1526 }
1527 if (!PUT (&CHANNEL (file))) {
1528 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "putting");
1529 exit_genie (p, A68G_RUNTIME_ERROR);
1530 }
1531 if (!BIN (&CHANNEL (file))) {
1532 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "binary putting");
1533 exit_genie (p, A68G_RUNTIME_ERROR);
1534 }
1535 if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
1536 if ((FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS | O_BINARY, A68G_PROTECTION)) == A68G_NO_FILE) {
1537 open_error (p, ref_file, "binary putting");
1538 }
1539 DRAW_MOOD (file) = A68G_FALSE;
1540 READ_MOOD (file) = A68G_FALSE;
1541 WRITE_MOOD (file) = A68G_TRUE;
1542 CHAR_MOOD (file) = A68G_FALSE;
1543 }
1544 if (CHAR_MOOD (file)) {
1545 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "text");
1546 exit_genie (p, A68G_RUNTIME_ERROR);
1547 }
1548 if (elems <= 0) {
1549 return;
1550 }
1551 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
1552 int elem_index = 0;
1553 for (int k = 0; k < elems; k++) {
1554 A68G_UNION *z = (A68G_UNION *) & base_address[elem_index];
1555 MOID_T *mode = (MOID_T *) (VALUE (z));
1556 BYTE_T *item = (BYTE_T *) & base_address[elem_index + A68G_UNION_SIZE];
1557 genie_write_bin_standard (p, mode, item, ref_file);
1558 elem_index += SIZE (M_SIMPLOUT);
1559 }
1560 }
1561
1562 // Next are formatting routines "whole", "fixed" and "float" for mode
1563 // INT, LONG INT and LONG LONG INT, and REAL, LONG REAL and LONG LONG REAL.
1564 // They are direct implementations of the routines described in the
1565 // Revised Report, although those were only meant as a specification.
1566
1567 //! @brief Generate a string of error chars.
1568
1569 char *error_chars (char *s, int n)
1570 {
1571 int k = (n != 0 ? ABS (n) : 1);
1572 s[k] = NULL_CHAR;
1573 while (--k >= 0) {
1574 s[k] = ERROR_CHAR;
1575 }
1576 return s;
1577 }
1578
1579 //! @brief Convert temporary C string to A68 string.
1580
1581 A68G_REF tmp_to_a68g_string (NODE_T * p, char *temp_string)
1582 {
1583 // no compaction allowed since temp_string might be up for garbage collecting ...
1584 return c_to_a_string (p, temp_string, DEFAULT_WIDTH);
1585 }
1586
1587 //! @brief Add c to str, assuming that "str" is large enough.
1588
1589 char *plusto (char c, char *str)
1590 {
1591 MOVE (&str[1], &str[0], strlen (str) + 1);
1592 str[0] = c;
1593 return str;
1594 }
1595
1596 //! @brief Add c to str, assuming that "str" is large enough.
1597
1598 char *string_plusab_char (char *str, char c, int strwid)
1599 {
1600 char z[2];
1601 z[0] = c;
1602 z[1] = NULL_CHAR;
1603 a68g_bufcat (str, z, strwid);
1604 return str;
1605 }
1606
1607 //! @brief Add leading spaces to str until length is width.
1608
1609 char *leading_spaces (char *str, int width)
1610 {
1611 int j = width - strlen (str);
1612 while (--j >= 0) {
1613 (void) plusto (BLANK_CHAR, str);
1614 }
1615 return str;
1616 }
1617
1618 //! @brief Convert int to char using a table.
1619
1620 char digchar (int k)
1621 {
1622 char *s = "0123456789abcdefghijklmnopqrstuvwxyz";
1623 if (k >= 0 && k < strlen (s)) {
1624 return s[k];
1625 } else {
1626 return ERROR_CHAR;
1627 }
1628 }
1629
1630 //! @brief Formatted string for HEX_NUMBER.
1631
1632 char *bits_to_string (NODE_T * p)
1633 {
1634 A68G_INT width, base;
1635 POP_OBJECT (p, &base, A68G_INT);
1636 POP_OBJECT (p, &width, A68G_INT);
1637 DECREMENT_STACK_POINTER (p, SIZE (M_HEX_NUMBER));
1638 CHECK_INT_SHORTEN (p, VALUE (&base));
1639 CHECK_INT_SHORTEN (p, VALUE (&width));
1640 MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
1641 ADDR_T pop_sp = A68G_SP;
1642 int length = ABS (VALUE (&width)), radix = ABS (VALUE (&base));
1643 if (radix < 2 || radix > 16) {
1644 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1645 exit_genie (p, A68G_RUNTIME_ERROR);
1646 }
1647 reset_transput_buffer (EDIT_BUFFER);
1648 #if (A68G_LEVEL <= 2)
1649 (void) mode;
1650 (void) length;
1651 (void) error_chars (get_transput_buffer (EDIT_BUFFER), VALUE (&width));
1652 #else
1653 {
1654 BOOL_T ret = A68G_TRUE;
1655 if (mode == M_BOOL) {
1656 UNSIGNED_T z = VALUE ((A68G_BOOL *) (STACK_OFFSET (A68G_UNION_SIZE)));
1657 ret = convert_radix (p, (UNSIGNED_T) z, radix, length);
1658 } else if (mode == M_CHAR) {
1659 INT_T z = VALUE ((A68G_CHAR *) (STACK_OFFSET (A68G_UNION_SIZE)));
1660 ret = convert_radix (p, (UNSIGNED_T) z, radix, length);
1661 } else if (mode == M_INT) {
1662 INT_T z = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
1663 ret = convert_radix (p, (UNSIGNED_T) z, radix, length);
1664 } else if (mode == M_REAL) {
1665 // A trick to copy a REAL into an unt without truncating
1666 UNSIGNED_T z;
1667 memcpy (&z, (void *) &VALUE ((A68G_REAL *) (STACK_OFFSET (A68G_UNION_SIZE))), 8);
1668 ret = convert_radix (p, z, radix, length);
1669 } else if (mode == M_BITS) {
1670 UNSIGNED_T z = VALUE ((A68G_BITS *) (STACK_OFFSET (A68G_UNION_SIZE)));
1671 ret = convert_radix (p, (UNSIGNED_T) z, radix, length);
1672 } else if (mode == M_LONG_INT) {
1673 DOUBLE_NUM_T z = VALUE ((A68G_LONG_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
1674 ret = convert_radix_double (p, z, radix, length);
1675 } else if (mode == M_LONG_REAL) {
1676 DOUBLE_NUM_T z = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
1677 ret = convert_radix_double (p, z, radix, length);
1678 } else if (mode == M_LONG_BITS) {
1679 DOUBLE_NUM_T z = VALUE ((A68G_LONG_BITS *) (STACK_OFFSET (A68G_UNION_SIZE)));
1680 ret = convert_radix_double (p, z, radix, length);
1681 }
1682 if (ret == A68G_FALSE) {
1683 errno = EDOM;
1684 PRELUDE_ERROR (A68G_TRUE, p, ERROR_OUT_OF_BOUNDS, mode);
1685 }
1686 }
1687 #endif
1688 A68G_SP = pop_sp;
1689 return get_transput_buffer (EDIT_BUFFER);
1690 }
1691
1692 //! @brief Standard string for LONG INT.
1693
1694 char *sub_whole_mp (NODE_T * p, MP_T * m, int digits, int width)
1695 {
1696 int len = 0;
1697 char *s = stack_string (p, 8 + width);
1698 s[0] = NULL_CHAR;
1699 ADDR_T pop_sp = A68G_SP;
1700 MP_T *n = nil_mp (p, digits);
1701 (void) move_mp (n, m, digits);
1702 do {
1703 if (len < width) {
1704 // Sic transit gloria mundi.
1705 int n_mod_10 = (MP_INT_T) MP_DIGIT (n, (int) (1 + MP_EXPONENT (n))) % 10;
1706 (void) plusto (digchar (n_mod_10), s);
1707 }
1708 len++;
1709 (void) over_mp_digit (p, n, n, (MP_T) 10, digits);
1710 } while (MP_DIGIT (n, 1) > 0);
1711 if (len > width) {
1712 (void) error_chars (s, width);
1713 }
1714 A68G_SP = pop_sp;
1715 return s;
1716 }
1717
1718 //! @brief Formatted string for NUMBER.
1719
1720 char *whole (NODE_T * p)
1721 {
1722 A68G_INT width;
1723 POP_OBJECT (p, &width, A68G_INT);
1724 CHECK_INT_SHORTEN (p, VALUE (&width));
1725 DECREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
1726 ADDR_T pop_sp = A68G_SP;
1727 MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
1728 //
1729 if (mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
1730 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
1731 PUSH_VALUE (p, VALUE (&width), A68G_INT);
1732 PUSH_VALUE (p, 0, A68G_INT);
1733 return fixed (p);
1734 } else if (mode == M_INT) {
1735 INT_T x = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
1736 int digits = DIGITS (M_LONG_LONG_INT);
1737 PUSH_UNION (p, (void *) M_LONG_LONG_INT);
1738 MP_T *z = nil_mp (p, digits);
1739 (void) int_to_mp (p, z, x, digits);
1740 PUSH_PRIMAL (p, VALUE (&width), INT);
1741 return whole (p);
1742 }
1743 #if (A68G_LEVEL >= 3)
1744 if (mode == M_LONG_INT) {
1745 DOUBLE_NUM_T x = VALUE ((A68G_LONG_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
1746 int digits = DIGITS (M_LONG_LONG_INT);
1747 PUSH_UNION (p, (void *) M_LONG_LONG_INT);
1748 MP_T *z = nil_mp (p, digits);
1749 (void) double_int_to_mp (p, z, x, digits);
1750 PUSH_PRIMAL (p, VALUE (&width), INT);
1751 return whole (p);
1752 }
1753 #endif
1754 if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
1755 int digits = DIGITS (mode);
1756 MP_T *n = (MP_T *) (STACK_OFFSET (A68G_UNION_SIZE));
1757 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
1758 if (MP_EXPONENT (n) >= (MP_T) digits) {
1759 int max_length = (mode == M_LONG_INT ? A68G_LONG_INT_WIDTH : A68G_LONG_LONG_INT_WIDTH);
1760 int length = (VALUE (&width) == 0 ? max_length : VALUE (&width));
1761 char *s = stack_string (p, 1 + length);
1762 (void) error_chars (s, length);
1763 A68G_SP = pop_sp;
1764 return s;
1765 }
1766 BOOL_T ltz = (BOOL_T) (MP_DIGIT (n, 1) < 0);
1767 int length = ABS (VALUE (&width)) - (ltz || VALUE (&width) > 0 ? 1 : 0);
1768 size_t size = (ltz ? 1 : (VALUE (&width) > 0 ? 1 : 0));
1769 MP_DIGIT (n, 1) = ABS (MP_DIGIT (n, 1));
1770 if (VALUE (&width) == 0) {
1771 MP_T *m = nil_mp (p, digits);
1772 (void) move_mp (m, n, digits);
1773 length = 0;
1774 while ((over_mp_digit (p, m, m, (MP_T) 10, digits), length++, MP_DIGIT (m, 1) != 0)) {
1775 ;
1776 }
1777 }
1778 size += length;
1779 int abs_width = ABS (VALUE (&width));
1780 size = 8 + MAX (size, abs_width);
1781 char *s = stack_string (p, size);
1782 a68g_bufcpy (s, sub_whole_mp (p, n, digits, length), size);
1783 if (length == 0 || strchr (s, ERROR_CHAR) != NO_TEXT) {
1784 (void) error_chars (s, abs_width);
1785 } else {
1786 if (ltz) {
1787 (void) plusto ('-', s);
1788 } else if (VALUE (&width) > 0) {
1789 (void) plusto ('+', s);
1790 }
1791 if (VALUE (&width) != 0) {
1792 (void) leading_spaces (s, abs_width);
1793 }
1794 }
1795 A68G_SP = pop_sp;
1796 return s;
1797 }
1798 ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
1799 return NO_TEXT;
1800 }
1801
1802 //! @brief Fetch next digit from LONG.
1803
1804 char choose_dig_mp (NODE_T * p, MP_T * y, int digits)
1805 {
1806 // Assuming positive "y".
1807 ADDR_T pop_sp = A68G_SP;
1808 (void) mul_mp_digit (p, y, y, (MP_T) 10, digits);
1809 int c = MP_EXPONENT (y) == 0 ? (MP_INT_T) MP_DIGIT (y, 1) : 0;
1810 if (c > 9) {
1811 c = 9;
1812 }
1813 MP_T *t = lit_mp (p, c, 0, digits);
1814 (void) sub_mp (p, y, y, t, digits);
1815 // Reset the stack to prevent overflow, there may be many digits.
1816 A68G_SP = pop_sp;
1817 return digchar (c);
1818 }
1819
1820 //! @brief Standard string for LONG.
1821
1822 char *sub_fixed_mp (NODE_T * p, MP_T * x, int digits, int width, int after)
1823 {
1824 ADDR_T pop_sp = A68G_SP;
1825 MP_T *y = nil_mp (p, digits);
1826 MP_T *s = nil_mp (p, digits);
1827 MP_T *t = nil_mp (p, digits);
1828 (void) ten_up_mp (p, t, -after, digits);
1829 (void) half_mp (p, t, t, digits);
1830 (void) add_mp (p, y, x, t, digits);
1831 int before = 0;
1832 // Not RR - argument reduction.
1833 while (MP_EXPONENT (y) > 1) {
1834 int k = (int) round (MP_EXPONENT (y) - 1);
1835 MP_EXPONENT (y) -= k;
1836 before += k * LOG_MP_RADIX;
1837 }
1838 // Follow RR again.
1839 SET_MP_ONE (s, digits);
1840 while ((sub_mp (p, t, y, s, digits), MP_DIGIT (t, 1) >= 0)) {
1841 before++;
1842 (void) div_mp_digit (p, y, y, (MP_T) 10, digits);
1843 }
1844 // Compose the number.
1845 if (before + after + (after > 0 ? 1 : 0) > width) {
1846 char *str = stack_string (p, width + 1);
1847 (void) error_chars (str, width);
1848 A68G_SP = pop_sp;
1849 return str;
1850 }
1851 int strwid = 8 + before + after;
1852 char *str = stack_string (p, strwid);
1853 str[0] = NULL_CHAR;
1854 int len = 0;
1855 for (int j = 0; j < before; j++) {
1856 char ch = (char) (len < A68G_LONG_LONG_REAL_WIDTH ? choose_dig_mp (p, y, digits) : '0');
1857 (void) string_plusab_char (str, ch, strwid);
1858 len++;
1859 }
1860 if (after > 0) {
1861 (void) string_plusab_char (str, POINT_CHAR, strwid);
1862 }
1863 for (int j = 0; j < after; j++) {
1864 char ch = (char) (len < A68G_LONG_LONG_REAL_WIDTH ? choose_dig_mp (p, y, digits) : '0');
1865 (void) string_plusab_char (str, ch, strwid);
1866 len++;
1867 }
1868 if (strlen (str) > width) {
1869 (void) error_chars (str, width);
1870 }
1871 A68G_SP = pop_sp;
1872 return str;
1873 }
1874
1875 //! @brief Formatted string for NUMBER.
1876
1877 char *fixed (NODE_T * p)
1878 {
1879 A68G_INT width, after;
1880 POP_OBJECT (p, &after, A68G_INT);
1881 POP_OBJECT (p, &width, A68G_INT);
1882 CHECK_INT_SHORTEN (p, VALUE (&after));
1883 CHECK_INT_SHORTEN (p, VALUE (&width));
1884 DECREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
1885 ADDR_T pop_sp = A68G_SP;
1886 MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
1887 if (mode == M_INT) {
1888 INT_T k = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
1889 PUSH_UNION (p, M_REAL);
1890 PUSH_VALUE (p, (REAL_T) k, A68G_REAL);
1891 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_REAL)));
1892 PUSH_VALUE (p, VALUE (&width), A68G_INT);
1893 PUSH_VALUE (p, VALUE (&after), A68G_INT);
1894 return fixed (p);
1895 } else if (mode == M_REAL) {
1896 REAL_T x = VALUE ((A68G_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
1897 if (!a68g_finite_real (x)) {
1898 char *s = stack_string (p, 8 + ABS (VALUE (&width)));
1899 A68G_SP = pop_sp;
1900 return error_chars (s, VALUE (&width));
1901 } else {
1902 int digits = DIGITS (M_LONG_LONG_REAL);
1903 PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
1904 MP_T *z = nil_mp (p, digits);
1905 #if (A68G_LEVEL >= 3)
1906 (void) double_to_mp (p, z, (DOUBLE_T) x, A68G_REAL_DIG, A68G_TRUE, digits);
1907 #else
1908 (void) real_to_mp (p, z, x, digits);
1909 #endif
1910 PUSH_PRIMAL (p, VALUE (&width), INT);
1911 PUSH_PRIMAL (p, VALUE (&after), INT);
1912 return fixed (p);
1913 }
1914 }
1915 #if (A68G_LEVEL >= 3)
1916 if (mode == M_LONG_INT) {
1917 DOUBLE_NUM_T x = VALUE ((A68G_LONG_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
1918 int digits = DIGITS (M_LONG_LONG_REAL);
1919 PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
1920 MP_T *z = nil_mp (p, digits);
1921 (void) double_int_to_mp (p, z, x, digits);
1922 PUSH_PRIMAL (p, VALUE (&width), INT);
1923 PUSH_PRIMAL (p, VALUE (&after), INT);
1924 return fixed (p);
1925 } else if (mode == M_LONG_REAL) {
1926 DOUBLE_T x = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE))).f;
1927 if (!a68g_finite_double (x)) {
1928 char *s = stack_string (p, 8 + ABS (VALUE (&width)));
1929 A68G_SP = pop_sp;
1930 return error_chars (s, VALUE (&width));
1931 } else {
1932 CHECK_DOUBLE_REAL (p, x);
1933 int digits = DIGITS (M_LONG_LONG_REAL);
1934 PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
1935 MP_T *z = nil_mp (p, digits);
1936 (void) double_to_mp (p, z, x, A68G_DOUBLE_DIG, A68G_TRUE, digits);
1937 PUSH_PRIMAL (p, VALUE (&width), INT);
1938 PUSH_PRIMAL (p, VALUE (&after), INT);
1939 return fixed (p);
1940 }
1941 }
1942 #endif
1943 if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
1944 if (mode == M_LONG_INT) {
1945 VALUE ((A68G_UNION *) STACK_TOP) = (void *) M_LONG_REAL;
1946 } else {
1947 VALUE ((A68G_UNION *) STACK_TOP) = (void *) M_LONG_LONG_REAL;
1948 }
1949 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
1950 PUSH_VALUE (p, VALUE (&width), A68G_INT);
1951 PUSH_VALUE (p, VALUE (&after), A68G_INT);
1952 return fixed (p);
1953 } else if (mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
1954 int digits = DIGITS (mode);
1955 MP_T *x = (MP_T *) (STACK_OFFSET (A68G_UNION_SIZE));
1956 if (((UNSIGNED_T) MP_STATUS (x) & NAN_MASK) != 0) {
1957 char *s = stack_string (p, 8 + ABS (VALUE (&width)));
1958 A68G_SP = pop_sp;
1959 return error_chars (s, VALUE (&width));
1960 } else {
1961 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
1962 BOOL_T ltz = (BOOL_T) (MP_DIGIT (x, 1) < 0);
1963 MP_DIGIT (x, 1) = ABS (MP_DIGIT (x, 1));
1964 int length = ABS (VALUE (&width)) - (ltz || VALUE (&width) > 0 ? 1 : 0);
1965 if (VALUE (&after) >= 0 && (length > VALUE (&after) || VALUE (&width) == 0)) {
1966 MP_T *z0 = nil_mp (p, digits);
1967 MP_T *z1 = nil_mp (p, digits);
1968 MP_T *t = nil_mp (p, digits);
1969 if (VALUE (&width) == 0) {
1970 length = (VALUE (&after) == 0 ? 1 : 0);
1971 (void) set_mp (z0, (MP_T) (MP_RADIX / 10), -1, digits);
1972 (void) set_mp (z1, (MP_T) 10, 0, digits);
1973 (void) pow_mp_int (p, z0, z0, VALUE (&after), digits);
1974 (void) pow_mp_int (p, z1, z1, length, digits);
1975 while ((div_mp_digit (p, t, z0, (MP_T) 2, digits), add_mp (p, t, x, t, digits), sub_mp (p, t, t, z1, digits), MP_DIGIT (t, 1) > 0)) {
1976 length++;
1977 (void) mul_mp_digit (p, z1, z1, (MP_T) 10, digits);
1978 }
1979 length += (VALUE (&after) == 0 ? 0 : VALUE (&after) + 1);
1980 }
1981 char *s = sub_fixed_mp (p, x, digits, length, VALUE (&after));
1982 if (strchr (s, ERROR_CHAR) == NO_TEXT) {
1983 if (length > strlen (s) && (s[0] != NULL_CHAR ? s[0] == POINT_CHAR : A68G_TRUE) && (MP_EXPONENT (x) < 0 || MP_DIGIT (x, 1) == 0)) {
1984 (void) plusto ('0', s);
1985 }
1986 if (ltz) {
1987 (void) plusto ('-', s);
1988 } else if (VALUE (&width) > 0) {
1989 (void) plusto ('+', s);
1990 }
1991 if (VALUE (&width) != 0) {
1992 (void) leading_spaces (s, ABS (VALUE (&width)));
1993 }
1994 A68G_SP = pop_sp;
1995 return s;
1996 } else if (VALUE (&after) > 0) {
1997 A68G_SP = pop_sp;
1998 MP_DIGIT (x, 1) = ltz ? -ABS (MP_DIGIT (x, 1)) : ABS (MP_DIGIT (x, 1));
1999 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
2000 PUSH_VALUE (p, VALUE (&width), A68G_INT);
2001 PUSH_VALUE (p, VALUE (&after) - 1, A68G_INT);
2002 return fixed (p);
2003 } else {
2004 A68G_SP = pop_sp;
2005 return error_chars (s, VALUE (&width));
2006 }
2007 } else {
2008 char *s = stack_string (p, 8 + ABS (VALUE (&width)));
2009 A68G_SP = pop_sp;
2010 return error_chars (s, VALUE (&width));
2011 }
2012 }
2013 }
2014 ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
2015 return NO_TEXT;
2016 }
2017
2018 //! @brief Scale LONG for formatting.
2019
2020 void standardize_mp (NODE_T * p, MP_T * y, int digits, int before, int after, int *q)
2021 {
2022 ADDR_T pop_sp = A68G_SP;
2023 MP_T *f = nil_mp (p, digits);
2024 MP_T *g = nil_mp (p, digits);
2025 MP_T *h = nil_mp (p, digits);
2026 MP_T *t = nil_mp (p, digits);
2027 ten_up_mp (p, g, before, digits);
2028 (void) div_mp_digit (p, h, g, (MP_T) 10, digits);
2029 // Speed huge exponents.
2030 if ((MP_EXPONENT (y) - MP_EXPONENT (g)) > 1) {
2031 (*q) += LOG_MP_RADIX * ((int) MP_EXPONENT (y) - (int) MP_EXPONENT (g) - 1);
2032 MP_EXPONENT (y) = MP_EXPONENT (g) + 1;
2033 }
2034 while ((sub_mp (p, t, y, g, digits), MP_DIGIT (t, 1) >= 0)) {
2035 (void) div_mp_digit (p, y, y, (MP_T) 10, digits);
2036 (*q)++;
2037 }
2038 if (MP_DIGIT (y, 1) != 0) {
2039 // Speed huge exponents.
2040 if ((MP_EXPONENT (y) - MP_EXPONENT (h)) < -1) {
2041 (*q) -= LOG_MP_RADIX * ((int) MP_EXPONENT (h) - (int) MP_EXPONENT (y) - 1);
2042 MP_EXPONENT (y) = MP_EXPONENT (h) - 1;
2043 }
2044 while ((sub_mp (p, t, y, h, digits), MP_DIGIT (t, 1) < 0)) {
2045 (void) mul_mp_digit (p, y, y, (MP_T) 10, digits);
2046 (*q)--;
2047 }
2048 }
2049 ten_up_mp (p, f, -after, digits);
2050 (void) div_mp_digit (p, t, f, (MP_T) 2, digits);
2051 (void) add_mp (p, t, y, t, digits);
2052 (void) sub_mp (p, t, t, g, digits);
2053 if (MP_DIGIT (t, 1) >= 0) {
2054 (void) move_mp (y, h, digits);
2055 (*q)++;
2056 }
2057 A68G_SP = pop_sp;
2058 }
2059
2060 //! @brief Formatted string for NUMBER.
2061
2062 char *real (NODE_T * p)
2063 {
2064 // POP arguments.
2065 A68G_INT width, after, expo, frmt;
2066 POP_OBJECT (p, &frmt, A68G_INT);
2067 POP_OBJECT (p, &expo, A68G_INT);
2068 POP_OBJECT (p, &after, A68G_INT);
2069 POP_OBJECT (p, &width, A68G_INT);
2070 CHECK_INT_SHORTEN (p, VALUE (&frmt));
2071 CHECK_INT_SHORTEN (p, VALUE (&expo));
2072 CHECK_INT_SHORTEN (p, VALUE (&after));
2073 CHECK_INT_SHORTEN (p, VALUE (&width));
2074 ADDR_T arg_sp = A68G_SP;
2075 DECREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
2076 MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
2077 ADDR_T pop_sp = A68G_SP;
2078 //
2079 if (mode == M_INT) {
2080 INT_T k = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
2081 PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
2082 int digits = DIGITS (M_LONG_LONG_REAL);
2083 MP_T *z = nil_mp (p, digits);
2084 int_to_mp (p, z, k, digits);
2085 PUSH_VALUE (p, VALUE (&width), A68G_INT);
2086 PUSH_VALUE (p, VALUE (&after), A68G_INT);
2087 PUSH_VALUE (p, VALUE (&expo), A68G_INT);
2088 PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
2089 return real (p);
2090 } else if (mode == M_REAL) {
2091 REAL_T x = VALUE ((A68G_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
2092 if (!a68g_finite_real (x)) {
2093 char *s = stack_string (p, 8 + ABS (VALUE (&width)));
2094 A68G_SP = pop_sp;
2095 return error_chars (s, VALUE (&width));
2096 } else {
2097 PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
2098 int digits = DIGITS (M_LONG_LONG_REAL);
2099 MP_T *z = nil_mp (p, digits);
2100 #if (A68G_LEVEL >= 3)
2101 (void) double_to_mp (p, z, (DOUBLE_T) x, A68G_REAL_DIG, A68G_TRUE, digits);
2102 #else
2103 (void) real_to_mp (p, z, x, digits);
2104 #endif
2105 PUSH_PRIMAL (p, VALUE (&width), INT);
2106 PUSH_PRIMAL (p, VALUE (&after), INT);
2107 PUSH_PRIMAL (p, VALUE (&expo), INT);
2108 PUSH_PRIMAL (p, VALUE (&frmt), INT);
2109 return real (p);
2110 }
2111 }
2112 #if (A68G_LEVEL >= 3)
2113 if (mode == M_LONG_INT) {
2114 DOUBLE_NUM_T k = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
2115 int digits = DIGITS (M_LONG_LONG_REAL);
2116 PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
2117 MP_T *z = nil_mp (p, digits);
2118 (void) double_int_to_mp (p, z, k, digits);
2119 PUSH_PRIMAL (p, VALUE (&width), INT);
2120 PUSH_PRIMAL (p, VALUE (&after), INT);
2121 PUSH_PRIMAL (p, VALUE (&expo), INT);
2122 PUSH_PRIMAL (p, VALUE (&frmt), INT);
2123 return real (p);
2124 } else if (mode == M_LONG_REAL) {
2125 DOUBLE_T x = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE))).f;
2126 if (!a68g_finite_double (x)) {
2127 char *s = stack_string (p, 8 + ABS (VALUE (&width)));
2128 A68G_SP = pop_sp;
2129 return error_chars (s, VALUE (&width));
2130 } else {
2131 CHECK_DOUBLE_REAL (p, x);
2132 int digits = DIGITS (M_LONG_LONG_REAL);
2133 PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
2134 MP_T *z = nil_mp (p, digits);
2135 (void) double_to_mp (p, z, (DOUBLE_T) x, A68G_DOUBLE_DIG, A68G_TRUE, digits);
2136 PUSH_PRIMAL (p, VALUE (&width), INT);
2137 PUSH_PRIMAL (p, VALUE (&after), INT);
2138 PUSH_PRIMAL (p, VALUE (&expo), INT);
2139 PUSH_PRIMAL (p, VALUE (&frmt), INT);
2140 return real (p);
2141 }
2142 }
2143 #endif
2144 if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
2145 A68G_SP = pop_sp;
2146 if (mode == M_LONG_INT) {
2147 VALUE ((A68G_UNION *) STACK_TOP) = (void *) M_LONG_REAL;
2148 } else {
2149 VALUE ((A68G_UNION *) STACK_TOP) = (void *) M_LONG_LONG_REAL;
2150 }
2151 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
2152 PUSH_VALUE (p, VALUE (&width), A68G_INT);
2153 PUSH_VALUE (p, VALUE (&after), A68G_INT);
2154 PUSH_VALUE (p, VALUE (&expo), A68G_INT);
2155 PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
2156 return real (p);
2157 } else if (mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
2158 int digits = DIGITS (mode);
2159 MP_T *x = (MP_T *) (STACK_OFFSET (A68G_UNION_SIZE));
2160 if (((UNSIGNED_T) MP_STATUS (x) & NAN_MASK) != 0) {
2161 char *s = stack_string (p, 8 + ABS (VALUE (&width)));
2162 A68G_SP = pop_sp;
2163 return error_chars (s, VALUE (&width));
2164 } else {
2165 CHECK_LONG_REAL (p, x, mode);
2166 BOOL_T ltz = (BOOL_T) (MP_DIGIT (x, 1) < 0);
2167 A68G_SP = arg_sp;
2168 MP_DIGIT (x, 1) = ABS (MP_DIGIT (x, 1));
2169 int before = ABS (VALUE (&width)) - ABS (VALUE (&expo)) - (VALUE (&after) != 0 ? VALUE (&after) + 1 : 0) - 2;
2170 if (SIGN (before) + SIGN (VALUE (&after)) > 0) {
2171 int q = 0;
2172 MP_T *z = nil_mp (p, digits);
2173 (void) move_mp (z, x, digits);
2174 standardize_mp (p, z, digits, before, VALUE (&after), &q);
2175 if (VALUE (&frmt) > 0) {
2176 while (q % VALUE (&frmt) != 0) {
2177 (void) mul_mp_digit (p, z, z, (MP_T) 10, digits);
2178 q--;
2179 if (VALUE (&after) > 0) {
2180 VALUE (&after)--;
2181 }
2182 }
2183 } else {
2184 ADDR_T sp1 = A68G_SP;
2185 MP_T *dif = nil_mp (p, digits);
2186 MP_T *lim = nil_mp (p, digits);
2187 (void) ten_up_mp (p, lim, -VALUE (&frmt) - 1, digits);
2188 (void) sub_mp (p, dif, z, lim, digits);
2189 while (MP_DIGIT (dif, 1) < 0) {
2190 (void) mul_mp_digit (p, z, z, (MP_T) 10, digits);
2191 q--;
2192 if (VALUE (&after) > 0) {
2193 VALUE (&after)--;
2194 }
2195 (void) sub_mp (p, dif, z, lim, digits);
2196 }
2197 (void) mul_mp_digit (p, lim, lim, (MP_T) 10, digits);
2198 (void) sub_mp (p, dif, z, lim, digits);
2199 while (MP_DIGIT (dif, 1) > 0) {
2200 (void) div_mp_digit (p, z, z, (MP_T) 10, digits);
2201 q++;
2202 if (VALUE (&after) > 0) {
2203 VALUE (&after)++;
2204 }
2205 (void) sub_mp (p, dif, z, lim, digits);
2206 }
2207 A68G_SP = sp1;
2208 }
2209 //
2210 int strwid = 8 + ABS (VALUE (&width));
2211 char *s = stack_string (p, strwid);
2212 // Mantissa.
2213 PUSH_UNION (p, mode);
2214 MP_DIGIT (z, 1) = (ltz ? -MP_DIGIT (z, 1) : MP_DIGIT (z, 1));
2215 size_t N_mp = SIZE (mode);
2216 PUSH (p, z, N_mp);
2217 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (mode)));
2218 PUSH_VALUE (p, SIGN (VALUE (&width)) * (ABS (VALUE (&width)) - ABS (VALUE (&expo)) - 1), A68G_INT);
2219 PUSH_VALUE (p, VALUE (&after), A68G_INT);
2220 a68g_bufcpy (s, fixed (p), strwid);
2221 // Exponent.
2222 PUSH_UNION (p, M_INT);
2223 PUSH_VALUE (p, q, A68G_INT);
2224 INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_INT)));
2225 PUSH_VALUE (p, VALUE (&expo), A68G_INT);
2226 (void) string_plusab_char (s, EXPONENT_CHAR, strwid);
2227 a68g_bufcat (s, whole (p), strwid);
2228 // Recursion when error chars.
2229 if (VALUE (&expo) == 0 || strchr (s, ERROR_CHAR) != NO_TEXT) {
2230 A68G_SP = arg_sp;
2231 // INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
2232 PUSH_VALUE (p, VALUE (&width), A68G_INT);
2233 PUSH_VALUE (p, VALUE (&after) != 0 ? VALUE (&after) - 1 : 0, A68G_INT);
2234 PUSH_VALUE (p, VALUE (&expo) > 0 ? VALUE (&expo) + 1 : VALUE (&expo) - 1, A68G_INT);
2235 PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
2236 return real (p);
2237 } else {
2238 A68G_SP = pop_sp;
2239 return s;
2240 }
2241 } else {
2242 char *s = stack_string (p, 8 + ABS (VALUE (&width)));
2243 A68G_SP = pop_sp;
2244 return error_chars (s, VALUE (&width));
2245 }
2246 }
2247 }
2248 ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
2249 return NO_TEXT;
2250 }
2251
2252 //! @brief PROC (NUMBER, INT) STRING whole
2253
2254 void genie_whole (NODE_T * p)
2255 {
2256 PUSH_STRING (p, whole (p));
2257 }
2258
2259 //! @brief PROC (NUMBER, INT, INT) STRING bits
2260
2261 void genie_bits (NODE_T * p)
2262 {
2263 PUSH_STRING (p, bits_to_string (p));
2264 }
2265
2266 //! @brief PROC (NUMBER, INT, INT) STRING fixed
2267
2268 void genie_fixed (NODE_T * p)
2269 {
2270 PUSH_STRING (p, fixed (p));
2271 }
2272
2273 //! @brief PROC (NUMBER, INT, INT, INT) STRING eng
2274
2275 void genie_real (NODE_T * p)
2276 {
2277 PUSH_STRING (p, real (p));
2278 }
2279
2280 //! @brief PROC (NUMBER, INT, INT, INT) STRING float
2281
2282 void genie_float (NODE_T * p)
2283 {
2284 PUSH_VALUE (p, 1, A68G_INT);
2285 genie_real (p);
2286 }
2287
2288 // ALGOL68C routines.
2289
2290 //! @def A68C_TRANSPUT
2291 //! @brief Generate Algol68C routines readint, getint, etcetera.
2292
2293 #define A68C_TRANSPUT(n, m)\
2294 void genie_get_##n (NODE_T * p)\
2295 {\
2296 A68G_REF ref_file;\
2297 POP_REF (p, &ref_file);\
2298 CHECK_REF (p, ref_file, M_REF_FILE);\
2299 BYTE_T *z = STACK_TOP;\
2300 INCREMENT_STACK_POINTER (p, SIZE (MODE (m)));\
2301 ADDR_T pop_sp = A68G_SP;\
2302 open_for_reading (p, ref_file);\
2303 genie_read_standard (p, MODE (m), z, ref_file);\
2304 A68G_SP = pop_sp;\
2305 }\
2306 void genie_put_##n (NODE_T * p)\
2307 {\
2308 size_t size = SIZE (MODE (m)), sizf = SIZE (M_REF_FILE);\
2309 A68G_REF ref_file = * (A68G_REF *) STACK_OFFSET (- (size + sizf));\
2310 CHECK_REF (p, ref_file, M_REF_FILE);\
2311 reset_transput_buffer (UNFORMATTED_BUFFER);\
2312 open_for_writing (p, ref_file);\
2313 genie_write_standard (p, MODE (m), STACK_OFFSET (-size), ref_file);\
2314 write_purge_buffer (p, ref_file, UNFORMATTED_BUFFER);\
2315 DECREMENT_STACK_POINTER (p, size + sizf);\
2316 }\
2317 void genie_read_##n (NODE_T * p)\
2318 {\
2319 BYTE_T *z = STACK_TOP;\
2320 INCREMENT_STACK_POINTER (p, SIZE (MODE (m)));\
2321 ADDR_T pop_sp = A68G_SP;\
2322 open_for_reading (p, A68G (stand_in));\
2323 genie_read_standard (p, MODE (m), z, A68G (stand_in));\
2324 A68G_SP = pop_sp;\
2325 }\
2326 void genie_print_##n (NODE_T * p)\
2327 {\
2328 size_t size = SIZE (MODE (m));\
2329 reset_transput_buffer (UNFORMATTED_BUFFER);\
2330 open_for_writing (p, A68G (stand_out));\
2331 genie_write_standard (p, MODE (m), STACK_OFFSET (-size), A68G (stand_out));\
2332 write_purge_buffer (p, A68G (stand_out), UNFORMATTED_BUFFER);\
2333 DECREMENT_STACK_POINTER (p, size);\
2334 }
2335
2336 A68C_TRANSPUT (int, INT);
2337 A68C_TRANSPUT (long_int, LONG_INT);
2338 A68C_TRANSPUT (long_mp_int, LONG_LONG_INT);
2339 A68C_TRANSPUT (real, REAL);
2340 A68C_TRANSPUT (long_real, LONG_REAL);
2341 A68C_TRANSPUT (long_mp_real, LONG_LONG_REAL);
2342 A68C_TRANSPUT (bits, BITS);
2343 A68C_TRANSPUT (long_bits, LONG_BITS);
2344 A68C_TRANSPUT (long_mp_bits, LONG_LONG_BITS);
2345 A68C_TRANSPUT (bool, BOOL);
2346 A68C_TRANSPUT (char, CHAR);
2347 A68C_TRANSPUT (string, STRING);
2348
2349 #undef A68C_TRANSPUT
2350
2351 #define A68C_TRANSPUT(n, s, m)\
2352 void genie_get_##n (NODE_T * p) {\
2353 A68G_REF ref_file;\
2354 POP_REF (p, &ref_file);\
2355 CHECK_REF (p, ref_file, M_REF_FILE);\
2356 PUSH_REF (p, ref_file);\
2357 genie_get_##s (p);\
2358 PUSH_REF (p, ref_file);\
2359 genie_get_##s (p);\
2360 }\
2361 void genie_put_##n (NODE_T * p) {\
2362 size_t size = SIZE (MODE (m)), sizf = SIZE (M_REF_FILE);\
2363 A68G_REF ref_file = * (A68G_REF *) STACK_OFFSET (- (size + sizf));\
2364 CHECK_REF (p, ref_file, M_REF_FILE);\
2365 reset_transput_buffer (UNFORMATTED_BUFFER);\
2366 open_for_writing (p, ref_file);\
2367 genie_write_standard (p, MODE (m), STACK_OFFSET (-size), ref_file);\
2368 write_purge_buffer (p, ref_file, UNFORMATTED_BUFFER);\
2369 DECREMENT_STACK_POINTER (p, size + sizf);\
2370 }\
2371 void genie_read_##n (NODE_T * p) {\
2372 genie_read_##s (p);\
2373 genie_read_##s (p);\
2374 }\
2375 void genie_print_##n (NODE_T * p) {\
2376 size_t size = SIZE (MODE (m));\
2377 reset_transput_buffer (UNFORMATTED_BUFFER);\
2378 open_for_writing (p, A68G (stand_out));\
2379 genie_write_standard (p, MODE (m), STACK_OFFSET (-size), A68G (stand_out));\
2380 write_purge_buffer (p, A68G (stand_out), UNFORMATTED_BUFFER);\
2381 DECREMENT_STACK_POINTER (p, size);\
2382 }
2383
2384 A68C_TRANSPUT (complex, real, COMPLEX);
2385 A68C_TRANSPUT (mp_complex, long_real, LONG_COMPLEX);
2386 A68C_TRANSPUT (long_mp_complex, long_mp_real, LONG_LONG_COMPLEX);
2387
2388 #undef A68C_TRANSPUT
2389
2390 //! @brief PROC STRING read line
2391
2392 void genie_read_line (NODE_T * p)
2393 {
2394 #if defined (HAVE_READLINE)
2395 char *line = readline ("");
2396 if (line != NO_TEXT && strlen (line) > 0) {
2397 add_history (line);
2398 }
2399 PUSH_REF (p, c_to_a_string (p, line, DEFAULT_WIDTH));
2400 a68g_free (line);
2401 #else
2402 genie_read_string (p);
2403 genie_stand_in (p);
2404 genie_new_line (p);
2405 #endif
2406 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|