rts-transput.c
1 //! @file rts-transput.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-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Transput routines.
25
26 #include "a68g.h"
27 #include "a68g-genie.h"
28 #include "a68g-prelude.h"
29 #include "a68g-transput.h"
30
31 // Transput - General routines and unformatted transput.
32 // But Eeyore wasn't listening. He was taking the balloon out, and putting
33 // it back again, as happy as could be ... Winnie the Pooh, A.A. Milne.
34 // - Revised Report on the Algorithmic Language Algol 68.
35
36 // File table handling
37 // In a table we record opened files.
38 // When execution ends, unclosed files are closed, and temps are removed.
39 // This keeps /tmp free of spurious files :-)
40
41 //! @brief Init a file entry.
42
43 void init_file_entry (int k)
44 {
45 if (k >= 0 && k < MAX_OPEN_FILES) {
46 FILE_ENTRY *fe = &(A68 (file_entries)[k]);
47 POS (fe) = NO_NODE;
48 IS_OPEN (fe) = A68_FALSE;
49 IS_TMP (fe) = A68_FALSE;
50 FD (fe) = A68_NO_FILE;
51 IDF (fe) = nil_ref;
52 }
53 }
54
55 //! @brief Initialise file entry table.
56
57 void init_file_entries (void)
58 {
59 for (int k = 0; k < MAX_OPEN_FILES; k++) {
60 init_file_entry (k);
61 }
62 }
63
64 //! @brief Store file for later closing when not explicitly closed.
65
66 int store_file_entry (NODE_T * p, FILE_T fd, char *idf, BOOL_T is_tmp)
67 {
68 for (int k = 0; k < MAX_OPEN_FILES; k++) {
69 FILE_ENTRY *fe = &(A68 (file_entries)[k]);
70 if (!IS_OPEN (fe)) {
71 int len = 1 + (int) strlen (idf);
72 POS (fe) = p;
73 IS_OPEN (fe) = A68_TRUE;
74 IS_TMP (fe) = is_tmp;
75 FD (fe) = fd;
76 IDF (fe) = heap_generator (p, M_C_STRING, len);
77 BLOCK_GC_HANDLE (&(IDF (fe)));
78 a68_bufcpy (DEREF (char, &IDF (fe)), idf, len);
79 return k;
80 }
81 }
82 diagnostic (A68_RUNTIME_ERROR, p, ERROR_TOO_MANY_OPEN_FILES);
83 exit_genie (p, A68_RUNTIME_ERROR);
84 return -1;
85 }
86
87 //! @brief Close file and delete temp file.
88
89 void close_file_entry (NODE_T * p, int k)
90 {
91 if (k >= 0 && k < MAX_OPEN_FILES) {
92 FILE_ENTRY *fe = &(A68 (file_entries)[k]);
93 if (IS_OPEN (fe)) {
94 // Close the file.
95 if (FD (fe) != A68_NO_FILE && close (FD (fe)) == -1) {
96 init_file_entry (k);
97 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_CLOSE);
98 exit_genie (p, A68_RUNTIME_ERROR);
99 }
100 IS_OPEN (fe) = A68_FALSE;
101 }
102 }
103 }
104
105 //! @brief Close file and delete temp file.
106
107 void free_file_entry (NODE_T * p, int k)
108 {
109 close_file_entry (p, k);
110 if (k >= 0 && k < MAX_OPEN_FILES) {
111 FILE_ENTRY *fe = &(A68 (file_entries)[k]);
112 if (IS_OPEN (fe)) {
113 // Attempt to remove a temp file, but ignore failure.
114 if (FD (fe) != A68_NO_FILE && IS_TMP (fe)) {
115 if (!IS_NIL (IDF (fe))) {
116 char *filename;
117 CHECK_INIT (p, INITIALISED (&(IDF (fe))), M_ROWS);
118 filename = DEREF (char, &IDF (fe));
119 if (filename != NO_TEXT) {
120 (void) remove (filename);
121 }
122 }
123 }
124 // Restore the fields.
125 if (!IS_NIL (IDF (fe))) {
126 UNBLOCK_GC_HANDLE (&(IDF (fe)));
127 }
128 init_file_entry (k);
129 }
130 }
131 }
132
133 //! @brief Close all files and delete all temp files.
134
135 void free_file_entries (void)
136 {
137 for (int k = 0; k < MAX_OPEN_FILES; k++) {
138 free_file_entry (NO_NODE, k);
139 }
140 }
141
142 // Strings in transput are of arbitrary size. For this, we have transput buffers.
143 // A transput buffer is a REF STRUCT (INT size, index, STRING buffer).
144 // It is in the heap, but cannot be gc'ed. If it is too small, we give up on
145 // it and make a larger one.
146
147 A68_REF ref_transput_buffer[MAX_TRANSPUT_BUFFER];
148
149 //! @brief Set max number of chars in a transput buffer.
150
151 void set_transput_buffer_size (int n, int size)
152 {
153 A68_INT *k = (A68_INT *) (ADDRESS (&ref_transput_buffer[n]));
154 STATUS (k) = INIT_MASK;
155 VALUE (k) = size;
156 }
157
158 //! @brief Set char index for transput buffer.
159
160 void set_transput_buffer_index (int n, int cindex)
161 {
162 A68_INT *k = (A68_INT *) (ADDRESS (&ref_transput_buffer[n]) + SIZE (M_INT));
163 STATUS (k) = INIT_MASK;
164 VALUE (k) = cindex;
165 }
166
167 //! @brief Get max number of chars in a transput buffer.
168
169 int get_transput_buffer_size (int n)
170 {
171 A68_INT *k = (A68_INT *) (ADDRESS (&ref_transput_buffer[n]));
172 return VALUE (k);
173 }
174
175 //! @brief Get char index for transput buffer.
176
177 int get_transput_buffer_index (int n)
178 {
179 A68_INT *k = (A68_INT *) (ADDRESS (&ref_transput_buffer[n]) + SIZE (M_INT));
180 return VALUE (k);
181 }
182
183 //! @brief Get char[] from transput buffer.
184
185 char *get_transput_buffer (int n)
186 {
187 return (char *) (ADDRESS (&ref_transput_buffer[n]) + 2 * SIZE (M_INT));
188 }
189
190 //! @brief Mark transput buffer as no longer in use.
191
192 void unblock_transput_buffer (int n)
193 {
194 set_transput_buffer_index (n, -1);
195 }
196
197 //! @brief Find first unused transput buffer (for opening a file).
198
199 int get_unblocked_transput_buffer (NODE_T * p)
200 {
201 for (int k = FIXED_TRANSPUT_BUFFERS; k < MAX_TRANSPUT_BUFFER; k++) {
202 if (get_transput_buffer_index (k) == -1) {
203 return k;
204 }
205 }
206 // Oops!
207 diagnostic (A68_RUNTIME_ERROR, p, ERROR_TOO_MANY_OPEN_FILES);
208 exit_genie (p, A68_RUNTIME_ERROR);
209 return -1;
210 }
211
212 //! @brief Empty contents of transput buffer.
213
214 void reset_transput_buffer (int n)
215 {
216 set_transput_buffer_index (n, 0);
217 (get_transput_buffer (n))[0] = NULL_CHAR;
218 }
219
220 //! @brief Initialise transput buffers before use.
221
222 void init_transput_buffers (NODE_T * p)
223 {
224 for (int k = 0; k < MAX_TRANSPUT_BUFFER; k++) {
225 ref_transput_buffer[k] = heap_generator (p, M_ROWS, 2 * SIZE (M_INT) + TRANSPUT_BUFFER_SIZE);
226 BLOCK_GC_HANDLE (&ref_transput_buffer[k]);
227 set_transput_buffer_size (k, TRANSPUT_BUFFER_SIZE);
228 reset_transput_buffer (k);
229 }
230 // Last buffers are available for FILE values.
231 for (int k = FIXED_TRANSPUT_BUFFERS; k < MAX_TRANSPUT_BUFFER; k++) {
232 unblock_transput_buffer (k);
233 }
234 }
235
236 //! @brief Make a transput buffer larger.
237
238 void enlarge_transput_buffer (NODE_T * p, int k, int size)
239 {
240 int n = get_transput_buffer_index (k);
241 char *sb_1 = get_transput_buffer (k), *sb_2;
242 UNBLOCK_GC_HANDLE (&ref_transput_buffer[k]);
243 ref_transput_buffer[k] = heap_generator (p, M_ROWS, 2 * SIZE (M_INT) + size);
244 BLOCK_GC_HANDLE (&ref_transput_buffer[k]);
245 set_transput_buffer_size (k, size);
246 set_transput_buffer_index (k, n);
247 sb_2 = get_transput_buffer (k);
248 a68_bufcpy (sb_2, sb_1, size);
249 }
250
251 //! @brief Add char to transput buffer; if the buffer is full, make it larger.
252
253 void plusab_transput_buffer (NODE_T * p, int k, char ch)
254 {
255 char *sb = get_transput_buffer (k);
256 int size = get_transput_buffer_size (k);
257 int n = get_transput_buffer_index (k);
258 if (n == size - 2) {
259 enlarge_transput_buffer (p, k, 10 * size);
260 plusab_transput_buffer (p, k, ch);
261 } else {
262 sb[n] = ch;
263 sb[n + 1] = NULL_CHAR;
264 set_transput_buffer_index (k, n + 1);
265 }
266 }
267
268 //! @brief Add char to transput buffer at the head; if the buffer is full, make it larger.
269
270 void plusto_transput_buffer (NODE_T * p, char ch, int k)
271 {
272 char *sb = get_transput_buffer (k);
273 int size = get_transput_buffer_size (k);
274 int n = get_transput_buffer_index (k);
275 if (n == size - 2) {
276 enlarge_transput_buffer (p, k, 10 * size);
277 plusto_transput_buffer (p, ch, k);
278 } else {
279 MOVE (&sb[1], &sb[0], (unt) size);
280 sb[0] = ch;
281 sb[n + 1] = NULL_CHAR;
282 set_transput_buffer_index (k, n + 1);
283 }
284 }
285
286 //! @brief Add chars to transput buffer.
287
288 void add_chars_transput_buffer (NODE_T * p, int k, int N, char *ch)
289 {
290 for (int j = 0; j < N; j++) {
291 plusab_transput_buffer (p, k, ch[j]);
292 }
293 }
294
295 //! @brief Add char[] to transput buffer.
296
297 void add_string_transput_buffer (NODE_T * p, int k, char *ch)
298 {
299 for (; ch[0] != NULL_CHAR; ch++) {
300 plusab_transput_buffer (p, k, ch[0]);
301 }
302 }
303
304 //! @brief Add A68 string to transput buffer.
305
306 void add_a_string_transput_buffer (NODE_T * p, int k, BYTE_T * ref)
307 {
308 A68_REF row = *(A68_REF *) ref;
309 CHECK_INIT (p, INITIALISED (&row), M_ROWS);
310 A68_ARRAY *arr; A68_TUPLE *tup;
311 GET_DESCRIPTOR (arr, tup, &row);
312 if (ROW_SIZE (tup) > 0) {
313 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
314 for (int i = LWB (tup); i <= UPB (tup); i++) {
315 int addr = INDEX_1_DIM (arr, tup, i);
316 A68_CHAR *ch = (A68_CHAR *) & (base_address[addr]);
317 CHECK_INIT (p, INITIALISED (ch), M_CHAR);
318 plusab_transput_buffer (p, k, (char) VALUE (ch));
319 }
320 }
321 }
322
323 //! @brief Pop A68 string and add to buffer.
324
325 void add_string_from_stack_transput_buffer (NODE_T * p, int k)
326 {
327 DECREMENT_STACK_POINTER (p, A68_REF_SIZE);
328 add_a_string_transput_buffer (p, k, STACK_TOP);
329 }
330
331 //! @brief Pop first character from transput buffer.
332
333 char pop_char_transput_buffer (int k)
334 {
335 char *sb = get_transput_buffer (k);
336 int n = get_transput_buffer_index (k);
337 if (n <= 0) {
338 return NULL_CHAR;
339 } else {
340 char ch = sb[0];
341 MOVE (&sb[0], &sb[1], n);
342 set_transput_buffer_index (k, n - 1);
343 return ch;
344 }
345 }
346
347 //! @brief Add C string to A68 string.
348
349 void add_c_string_to_a_string (NODE_T * p, A68_REF ref_str, char *s)
350 {
351 int len_2 = (int) strlen (s);
352 // left part.
353 CHECK_REF (p, ref_str, M_REF_STRING);
354 A68_REF a = *DEREF (A68_REF, &ref_str);
355 CHECK_INIT (p, INITIALISED (&a), M_STRING);
356 A68_ARRAY *arr_1; A68_TUPLE *tup_1;
357 GET_DESCRIPTOR (arr_1, tup_1, &a);
358 int len_1 = ROW_SIZE (tup_1);
359 // Sum string.
360 A68_REF c = heap_generator (p, M_STRING, DESCRIPTOR_SIZE (1));
361 A68_REF d = heap_generator_2 (p, M_STRING, len_1 + len_2, SIZE (M_CHAR));
362 // Calculate again since garbage collector might have moved data.
363 // Todo: GC should not move volatile data.
364 GET_DESCRIPTOR (arr_1, tup_1, &a);
365 // Make descriptor of new string.
366 A68_ARRAY *arr_3; A68_TUPLE *tup_3;
367 GET_DESCRIPTOR (arr_3, tup_3, &c);
368 DIM (arr_3) = 1;
369 MOID (arr_3) = M_CHAR;
370 ELEM_SIZE (arr_3) = SIZE (M_CHAR);
371 SLICE_OFFSET (arr_3) = 0;
372 FIELD_OFFSET (arr_3) = 0;
373 ARRAY (arr_3) = d;
374 LWB (tup_3) = 1;
375 UPB (tup_3) = len_1 + len_2;
376 SHIFT (tup_3) = LWB (tup_3);
377 SPAN (tup_3) = 1;
378 // add strings.
379 BYTE_T *b_1 = (ROW_SIZE (tup_1) > 0 ? DEREF (BYTE_T, &ARRAY (arr_1)) : NO_BYTE);
380 BYTE_T *b_3 = DEREF (BYTE_T, &ARRAY (arr_3));
381 int u = 0;
382 for (int v = LWB (tup_1); v <= UPB (tup_1); v++) {
383 MOVE ((BYTE_T *) & b_3[u], (BYTE_T *) & b_1[INDEX_1_DIM (arr_1, tup_1, v)], SIZE (M_CHAR));
384 u += SIZE (M_CHAR);
385 }
386 for (int v = 0; v < len_2; v++) {
387 A68_CHAR ch;
388 STATUS (&ch) = INIT_MASK;
389 VALUE (&ch) = s[v];
390 MOVE ((BYTE_T *) & b_3[u], (BYTE_T *) & ch, SIZE (M_CHAR));
391 u += SIZE (M_CHAR);
392 }
393 *DEREF (A68_REF, &ref_str) = c;
394 }
395
396 //! @brief Purge buffer for file.
397
398 void write_purge_buffer (NODE_T * p, A68_REF ref_file, int k)
399 {
400 A68_FILE *file = FILE_DEREF (&ref_file);
401 if (IS_NIL (STRING (file))) {
402 if (!(FD (file) == A68_STDOUT && A68 (halt_typing))) {
403 WRITE (FD (file), get_transput_buffer (k));
404 }
405 } else {
406 add_c_string_to_a_string (p, STRING (file), get_transput_buffer (k));
407 }
408 reset_transput_buffer (k);
409 }
410
411 // Routines that involve the A68 expression stack.
412
413 //! @brief Allocate a temporary string on the stack.
414
415 char *stack_string (NODE_T * p, int size)
416 {
417 char *new_str = (char *) STACK_TOP;
418 INCREMENT_STACK_POINTER (p, size);
419 if (A68_SP > A68 (expr_stack_limit)) {
420 diagnostic (A68_RUNTIME_ERROR, p, ERROR_STACK_OVERFLOW);
421 exit_genie (p, A68_RUNTIME_ERROR);
422 }
423 FILL (new_str, NULL_CHAR, size);
424 return new_str;
425 }
426
427 // Transput basic RTS routines.
428
429 //! @brief REF FILE standin
430
431 void genie_stand_in (NODE_T * p)
432 {
433 PUSH_REF (p, A68 (stand_in));
434 }
435
436 //! @brief REF FILE standout
437
438 void genie_stand_out (NODE_T * p)
439 {
440 PUSH_REF (p, A68 (stand_out));
441 }
442
443 //! @brief REF FILE standback
444
445 void genie_stand_back (NODE_T * p)
446 {
447 PUSH_REF (p, A68 (stand_back));
448 }
449
450 //! @brief REF FILE standerror
451
452 void genie_stand_error (NODE_T * p)
453 {
454 PUSH_REF (p, A68 (stand_error));
455 }
456
457 //! @brief CHAR error char
458
459 void genie_error_char (NODE_T * p)
460 {
461 PUSH_VALUE (p, ERROR_CHAR, A68_CHAR);
462 }
463
464 //! @brief CHAR exp char
465
466 void genie_exp_char (NODE_T * p)
467 {
468 PUSH_VALUE (p, EXPONENT_CHAR, A68_CHAR);
469 }
470
471 //! @brief CHAR flip char
472
473 void genie_flip_char (NODE_T * p)
474 {
475 PUSH_VALUE (p, FLIP_CHAR, A68_CHAR);
476 }
477
478 //! @brief CHAR flop char
479
480 void genie_flop_char (NODE_T * p)
481 {
482 PUSH_VALUE (p, FLOP_CHAR, A68_CHAR);
483 }
484
485 //! @brief CHAR null char
486
487 void genie_null_char (NODE_T * p)
488 {
489 PUSH_VALUE (p, NULL_CHAR, A68_CHAR);
490 }
491
492 //! @brief CHAR blank
493
494 void genie_blank_char (NODE_T * p)
495 {
496 PUSH_VALUE (p, BLANK_CHAR, A68_CHAR);
497 }
498
499 //! @brief CHAR newline char
500
501 void genie_newline_char (NODE_T * p)
502 {
503 PUSH_VALUE (p, NEWLINE_CHAR, A68_CHAR);
504 }
505
506 //! @brief CHAR formfeed char
507
508 void genie_formfeed_char (NODE_T * p)
509 {
510 PUSH_VALUE (p, FORMFEED_CHAR, A68_CHAR);
511 }
512
513 //! @brief CHAR tab char
514
515 void genie_tab_char (NODE_T * p)
516 {
517 PUSH_VALUE (p, TAB_CHAR, A68_CHAR);
518 }
519
520 //! @brief CHANNEL standin channel
521
522 void genie_stand_in_channel (NODE_T * p)
523 {
524 PUSH_OBJECT (p, A68 (stand_in_channel), A68_CHANNEL);
525 }
526
527 //! @brief CHANNEL standout channel
528
529 void genie_stand_out_channel (NODE_T * p)
530 {
531 PUSH_OBJECT (p, A68 (stand_out_channel), A68_CHANNEL);
532 }
533
534 //! @brief CHANNEL stand draw channel
535
536 void genie_stand_draw_channel (NODE_T * p)
537 {
538 PUSH_OBJECT (p, A68 (stand_draw_channel), A68_CHANNEL);
539 }
540
541 //! @brief CHANNEL standback channel
542
543 void genie_stand_back_channel (NODE_T * p)
544 {
545 PUSH_OBJECT (p, A68 (stand_back_channel), A68_CHANNEL);
546 }
547
548 //! @brief CHANNEL standerror channel
549
550 void genie_stand_error_channel (NODE_T * p)
551 {
552 PUSH_OBJECT (p, A68 (stand_error_channel), A68_CHANNEL);
553 }
554
555 //! @brief PROC STRING program idf
556
557 void genie_program_idf (NODE_T * p)
558 {
559 PUSH_REF (p, c_to_a_string (p, FILE_SOURCE_NAME (&A68_JOB), DEFAULT_WIDTH));
560 }
561
562 // FILE and CHANNEL initialisations.
563
564 //! @brief Set_default_event_procedure.
565
566 void set_default_event_procedure (A68_PROCEDURE * z)
567 {
568 STATUS (z) = INIT_MASK;
569 NODE (&(BODY (z))) = NO_NODE;
570 ENVIRON (z) = 0;
571 }
572
573 //! @brief Initialise channel.
574
575 void init_channel (A68_CHANNEL * chan, BOOL_T r, BOOL_T s, BOOL_T g, BOOL_T p, BOOL_T b, BOOL_T d)
576 {
577 STATUS (chan) = INIT_MASK;
578 RESET (chan) = r;
579 SET (chan) = s;
580 GET (chan) = g;
581 PUT (chan) = p;
582 BIN (chan) = b;
583 DRAW (chan) = d;
584 COMPRESS (chan) = A68_TRUE;
585 }
586
587 //! @brief Set default event handlers.
588
589 void set_default_event_procedures (A68_FILE * f)
590 {
591 set_default_event_procedure (&(FILE_END_MENDED (f)));
592 set_default_event_procedure (&(PAGE_END_MENDED (f)));
593 set_default_event_procedure (&(LINE_END_MENDED (f)));
594 set_default_event_procedure (&(VALUE_ERROR_MENDED (f)));
595 set_default_event_procedure (&(OPEN_ERROR_MENDED (f)));
596 set_default_event_procedure (&(TRANSPUT_ERROR_MENDED (f)));
597 set_default_event_procedure (&(FORMAT_END_MENDED (f)));
598 set_default_event_procedure (&(FORMAT_ERROR_MENDED (f)));
599 }
600
601 //! @brief Set up a REF FILE object.
602
603 void init_file (NODE_T * p, A68_REF * ref_file, A68_CHANNEL c, FILE_T s, BOOL_T rm, BOOL_T wm, BOOL_T cm, char *env)
604 {
605 char *filename = (env == NO_TEXT ? NO_TEXT : getenv (env));
606 *ref_file = heap_generator (p, M_REF_FILE, SIZE (M_FILE));
607 BLOCK_GC_HANDLE (ref_file);
608 A68_FILE *f = FILE_DEREF (ref_file);
609 STATUS (f) = INIT_MASK;
610 TERMINATOR (f) = nil_ref;
611 CHANNEL (f) = c;
612 if (filename != NO_TEXT && strlen (filename) > 0) {
613 int len = 1 + (int) strlen (filename);
614 IDENTIFICATION (f) = heap_generator (p, M_C_STRING, len);
615 BLOCK_GC_HANDLE (&(IDENTIFICATION (f)));
616 a68_bufcpy (DEREF (char, &IDENTIFICATION (f)), filename, len);
617 FD (f) = A68_NO_FILE;
618 READ_MOOD (f) = A68_FALSE;
619 WRITE_MOOD (f) = A68_FALSE;
620 CHAR_MOOD (f) = A68_FALSE;
621 DRAW_MOOD (f) = A68_FALSE;
622 } else {
623 IDENTIFICATION (f) = nil_ref;
624 FD (f) = s;
625 READ_MOOD (f) = rm;
626 WRITE_MOOD (f) = wm;
627 CHAR_MOOD (f) = cm;
628 DRAW_MOOD (f) = A68_FALSE;
629 }
630 TRANSPUT_BUFFER (f) = get_unblocked_transput_buffer (p);
631 reset_transput_buffer (TRANSPUT_BUFFER (f));
632 END_OF_FILE (f) = A68_FALSE;
633 TMP_FILE (f) = A68_FALSE;
634 OPENED (f) = A68_TRUE;
635 OPEN_EXCLUSIVE (f) = A68_FALSE;
636 FORMAT (f) = nil_format;
637 STRING (f) = nil_ref;
638 STRPOS (f) = 0;
639 FILE_ENTRY (f) = -1;
640 set_default_event_procedures (f);
641 }
642
643 //! @brief Initialise the transput RTL.
644
645 void genie_init_transput (NODE_T * p)
646 {
647 init_transput_buffers (p);
648 // Channels.
649 init_channel (&(A68 (stand_in_channel)), A68_FALSE, A68_FALSE, A68_TRUE, A68_FALSE, A68_FALSE, A68_FALSE);
650 init_channel (&(A68 (stand_out_channel)), A68_FALSE, A68_FALSE, A68_FALSE, A68_TRUE, A68_FALSE, A68_FALSE);
651 init_channel (&(A68 (stand_back_channel)), A68_TRUE, A68_TRUE, A68_TRUE, A68_TRUE, A68_TRUE, A68_FALSE);
652 init_channel (&(A68 (stand_error_channel)), A68_FALSE, A68_FALSE, A68_FALSE, A68_TRUE, A68_FALSE, A68_FALSE);
653 init_channel (&(A68 (associate_channel)), A68_TRUE, A68_TRUE, A68_TRUE, A68_TRUE, A68_TRUE, A68_FALSE);
654 init_channel (&(A68 (skip_channel)), A68_FALSE, A68_FALSE, A68_FALSE, A68_FALSE, A68_FALSE, A68_FALSE);
655 #if defined (HAVE_GNU_PLOTUTILS)
656 init_channel (&(A68 (stand_draw_channel)), A68_FALSE, A68_FALSE, A68_FALSE, A68_FALSE, A68_FALSE, A68_TRUE);
657 #else
658 init_channel (&(A68 (stand_draw_channel)), A68_FALSE, A68_FALSE, A68_FALSE, A68_FALSE, A68_FALSE, A68_TRUE);
659 #endif
660 // Files.
661 init_file (p, &(A68 (stand_in)), A68 (stand_in_channel), A68_STDIN, A68_TRUE, A68_FALSE, A68_TRUE, "A68_STANDIN");
662 init_file (p, &(A68 (stand_out)), A68 (stand_out_channel), A68_STDOUT, A68_FALSE, A68_TRUE, A68_TRUE, "A68_STANDOUT");
663 init_file (p, &(A68 (stand_back)), A68 (stand_back_channel), A68_NO_FILE, A68_FALSE, A68_FALSE, A68_FALSE, NO_TEXT);
664 init_file (p, &(A68 (stand_error)), A68 (stand_error_channel), A68_STDERR, A68_FALSE, A68_TRUE, A68_TRUE, "A68_STANDERROR");
665 init_file (p, &(A68 (skip_file)), A68 (skip_channel), A68_NO_FILE, A68_FALSE, A68_FALSE, A68_FALSE, NO_TEXT);
666 }
667
668 //! @brief PROC (REF FILE) STRING idf
669
670 void genie_idf (NODE_T * p)
671 {
672 A68_REF ref_file;
673 POP_REF (p, &ref_file);
674 CHECK_REF (p, ref_file, M_REF_FILE);
675 ref_file = *(A68_REF *) STACK_TOP;
676 A68_REF ref_filename = IDENTIFICATION (FILE_DEREF (&ref_file));
677 CHECK_REF (p, ref_filename, M_ROWS);
678 char *filename = DEREF (char, &ref_filename);
679 PUSH_REF (p, c_to_a_string (p, filename, DEFAULT_WIDTH));
680 }
681
682 //! @brief PROC (REF FILE) STRING term
683
684 void genie_term (NODE_T * p)
685 {
686 A68_REF ref_file;
687 POP_REF (p, &ref_file);
688 CHECK_REF (p, ref_file, M_REF_FILE);
689 ref_file = *(A68_REF *) STACK_TOP;
690 A68_REF ref_term = TERMINATOR (FILE_DEREF (&ref_file));
691 CHECK_REF (p, ref_term, M_ROWS);
692 char *term = DEREF (char, &ref_term);
693 PUSH_REF (p, c_to_a_string (p, term, DEFAULT_WIDTH));
694 }
695
696 //! @brief PROC (REF FILE, STRING) VOID make term
697
698 void genie_make_term (NODE_T * p)
699 {
700 A68_REF ref_file, str;
701 POP_REF (p, &str);
702 POP_REF (p, &ref_file);
703 CHECK_REF (p, ref_file, M_REF_FILE);
704 ref_file = *(A68_REF *) STACK_TOP;
705 A68_FILE *file = FILE_DEREF (&ref_file);
706 // Don't check initialisation so we can "make term" before opening.
707 int size = a68_string_size (p, str);
708 if (INITIALISED (&(TERMINATOR (file))) && !IS_NIL (TERMINATOR (file))) {
709 UNBLOCK_GC_HANDLE (&(TERMINATOR (file)));
710 }
711 TERMINATOR (file) = heap_generator (p, M_C_STRING, 1 + size);
712 BLOCK_GC_HANDLE (&(TERMINATOR (file)));
713 ASSERT (a_to_c_string (p, DEREF (char, &TERMINATOR (file)), str) != NO_TEXT);
714 }
715
716 //! @brief PROC (REF FILE) BOOL put possible
717
718 void genie_put_possible (NODE_T * p)
719 {
720 A68_REF ref_file;
721 POP_REF (p, &ref_file);
722 CHECK_REF (p, ref_file, M_REF_FILE);
723 A68_FILE *file = FILE_DEREF (&ref_file);
724 CHECK_INIT (p, INITIALISED (file), M_FILE);
725 PUSH_VALUE (p, PUT (&CHANNEL (file)), A68_BOOL);
726 }
727
728 //! @brief PROC (REF FILE) BOOL get possible
729
730 void genie_get_possible (NODE_T * p)
731 {
732 A68_REF ref_file;
733 POP_REF (p, &ref_file);
734 CHECK_REF (p, ref_file, M_REF_FILE);
735 A68_FILE *file = FILE_DEREF (&ref_file);
736 CHECK_INIT (p, INITIALISED (file), M_FILE);
737 PUSH_VALUE (p, GET (&CHANNEL (file)), A68_BOOL);
738 }
739
740 //! @brief PROC (REF FILE) BOOL bin possible
741
742 void genie_bin_possible (NODE_T * p)
743 {
744 A68_REF ref_file;
745 POP_REF (p, &ref_file);
746 CHECK_REF (p, ref_file, M_REF_FILE);
747 A68_FILE *file = FILE_DEREF (&ref_file);
748 CHECK_INIT (p, INITIALISED (file), M_FILE);
749 PUSH_VALUE (p, BIN (&CHANNEL (file)), A68_BOOL);
750 }
751
752 //! @brief PROC (REF FILE) BOOL set possible
753
754 void genie_set_possible (NODE_T * p)
755 {
756 A68_REF ref_file;
757 POP_REF (p, &ref_file);
758 CHECK_REF (p, ref_file, M_REF_FILE);
759 A68_FILE *file = FILE_DEREF (&ref_file);
760 CHECK_INIT (p, INITIALISED (file), M_FILE);
761 PUSH_VALUE (p, SET (&CHANNEL (file)), A68_BOOL);
762 }
763
764 //! @brief PROC (REF FILE) BOOL reidf possible
765
766 void genie_reidf_possible (NODE_T * p)
767 {
768 A68_REF ref_file;
769 POP_REF (p, &ref_file);
770 CHECK_REF (p, ref_file, M_REF_FILE);
771 A68_FILE *file = FILE_DEREF (&ref_file);
772 CHECK_INIT (p, INITIALISED (file), M_FILE);
773 PUSH_VALUE (p, A68_FALSE, A68_BOOL);
774 }
775
776 //! @brief PROC (REF FILE) BOOL reset possible
777
778 void genie_reset_possible (NODE_T * p)
779 {
780 A68_REF ref_file;
781 POP_REF (p, &ref_file);
782 CHECK_REF (p, ref_file, M_REF_FILE);
783 A68_FILE *file = FILE_DEREF (&ref_file);
784 CHECK_INIT (p, INITIALISED (file), M_FILE);
785 PUSH_VALUE (p, RESET (&CHANNEL (file)), A68_BOOL);
786 }
787
788 //! @brief PROC (REF FILE) BOOL compressible
789
790 void genie_compressible (NODE_T * p)
791 {
792 A68_REF ref_file;
793 A68_FILE *file;
794 POP_REF (p, &ref_file);
795 CHECK_REF (p, ref_file, M_REF_FILE);
796 file = FILE_DEREF (&ref_file);
797 CHECK_INIT (p, INITIALISED (file), M_FILE);
798 PUSH_VALUE (p, COMPRESS (&CHANNEL (file)), A68_BOOL);
799 }
800
801 //! @brief PROC (REF FILE) BOOL draw possible
802
803 void genie_draw_possible (NODE_T * p)
804 {
805 A68_REF ref_file;
806 POP_REF (p, &ref_file);
807 CHECK_REF (p, ref_file, M_REF_FILE);
808 A68_FILE *file = FILE_DEREF (&ref_file);
809 CHECK_INIT (p, INITIALISED (file), M_FILE);
810 PUSH_VALUE (p, DRAW (&CHANNEL (file)), A68_BOOL);
811 }
812
813 //! @brief PROC (REF FILE, STRING, CHANNEL) INT open
814
815 void genie_open (NODE_T * p)
816 {
817 A68_CHANNEL channel;
818 POP_OBJECT (p, &channel, A68_CHANNEL);
819 A68_REF ref_iden;
820 POP_REF (p, &ref_iden);
821 CHECK_REF (p, ref_iden, M_REF_STRING);
822 A68_REF ref_file;
823 POP_REF (p, &ref_file);
824 CHECK_REF (p, ref_file, M_REF_FILE);
825 A68_FILE *file = FILE_DEREF (&ref_file);
826 STATUS (file) = INIT_MASK;
827 FILE_ENTRY (file) = -1;
828 CHANNEL (file) = channel;
829 OPENED (file) = A68_TRUE;
830 OPEN_EXCLUSIVE (file) = A68_FALSE;
831 READ_MOOD (file) = A68_FALSE;
832 WRITE_MOOD (file) = A68_FALSE;
833 CHAR_MOOD (file) = A68_FALSE;
834 DRAW_MOOD (file) = A68_FALSE;
835 TMP_FILE (file) = A68_FALSE;
836 int size = a68_string_size (p, ref_iden);
837 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
838 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
839 }
840 IDENTIFICATION (file) = heap_generator (p, M_C_STRING, 1 + size);
841 BLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
842 ASSERT (a_to_c_string (p, DEREF (char, &IDENTIFICATION (file)), ref_iden) != NO_TEXT);
843 TERMINATOR (file) = nil_ref;
844 FORMAT (file) = nil_format;
845 FD (file) = A68_NO_FILE;
846 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
847 UNBLOCK_GC_HANDLE (DEREF (A68_REF, &STRING (file)));
848 }
849 STRING (file) = nil_ref;
850 STRPOS (file) = 0;
851 DEVICE_MADE (&DEVICE (file)) = A68_FALSE;
852 STREAM (&DEVICE (file)) = NO_STREAM;
853 set_default_event_procedures (file);
854 {
855 struct stat status;
856 if (stat (DEREF (char, &IDENTIFICATION (file)), &status) == 0) {
857 PUSH_VALUE (p, (S_ISREG (ST_MODE (&status)) != 0 ? 0 : 1), A68_INT);
858 } else {
859 PUSH_VALUE (p, 1, A68_INT);
860 }
861 errno = 0;
862 }
863 }
864
865 //! @brief PROC (REF FILE, STRING, CHANNEL) INT establish
866
867 void genie_establish (NODE_T * p)
868 {
869 A68_CHANNEL channel;
870 POP_OBJECT (p, &channel, A68_CHANNEL);
871 A68_REF ref_iden;
872 POP_REF (p, &ref_iden);
873 CHECK_REF (p, ref_iden, M_REF_STRING);
874 A68_REF ref_file;
875 POP_REF (p, &ref_file);
876 CHECK_REF (p, ref_file, M_REF_FILE);
877 A68_FILE *file = FILE_DEREF (&ref_file);
878 STATUS (file) = INIT_MASK;
879 FILE_ENTRY (file) = -1;
880 CHANNEL (file) = channel;
881 OPENED (file) = A68_TRUE;
882 OPEN_EXCLUSIVE (file) = A68_TRUE;
883 READ_MOOD (file) = A68_FALSE;
884 WRITE_MOOD (file) = A68_FALSE;
885 CHAR_MOOD (file) = A68_FALSE;
886 DRAW_MOOD (file) = A68_FALSE;
887 TMP_FILE (file) = A68_FALSE;
888 if (!PUT (&CHANNEL (file))) {
889 diagnostic (A68_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "putting");
890 exit_genie (p, A68_RUNTIME_ERROR);
891 }
892 int size = a68_string_size (p, ref_iden);
893 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
894 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
895 }
896 IDENTIFICATION (file) = heap_generator (p, M_C_STRING, 1 + size);
897 BLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
898 ASSERT (a_to_c_string (p, DEREF (char, &IDENTIFICATION (file)), ref_iden) != NO_TEXT);
899 TERMINATOR (file) = nil_ref;
900 FORMAT (file) = nil_format;
901 FD (file) = A68_NO_FILE;
902 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
903 UNBLOCK_GC_HANDLE (DEREF (A68_REF, &STRING (file)));
904 }
905 STRING (file) = nil_ref;
906 STRPOS (file) = 0;
907 DEVICE_MADE (&DEVICE (file)) = A68_FALSE;
908 STREAM (&DEVICE (file)) = NO_STREAM;
909 set_default_event_procedures (file);
910 PUSH_VALUE (p, 0, A68_INT);
911 }
912
913 //! @brief PROC (REF FILE, CHANNEL) INT create
914
915 void genie_create (NODE_T * p)
916 {
917 A68_CHANNEL channel;
918 POP_OBJECT (p, &channel, A68_CHANNEL);
919 A68_REF ref_file;
920 POP_REF (p, &ref_file);
921 CHECK_REF (p, ref_file, M_REF_FILE);
922 A68_FILE *file = FILE_DEREF (&ref_file);
923 STATUS (file) = INIT_MASK;
924 FILE_ENTRY (file) = -1;
925 CHANNEL (file) = channel;
926 OPENED (file) = A68_TRUE;
927 OPEN_EXCLUSIVE (file) = A68_FALSE;
928 READ_MOOD (file) = A68_FALSE;
929 WRITE_MOOD (file) = A68_FALSE;
930 CHAR_MOOD (file) = A68_FALSE;
931 DRAW_MOOD (file) = A68_FALSE;
932 TMP_FILE (file) = A68_TRUE;
933 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
934 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
935 }
936 IDENTIFICATION (file) = nil_ref;
937 TERMINATOR (file) = nil_ref;
938 FORMAT (file) = nil_format;
939 FD (file) = A68_NO_FILE;
940 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
941 UNBLOCK_GC_HANDLE (DEREF (A68_REF, &STRING (file)));
942 }
943 STRING (file) = nil_ref;
944 STRPOS (file) = 0;
945 DEVICE_MADE (&DEVICE (file)) = A68_FALSE;
946 STREAM (&DEVICE (file)) = NO_STREAM;
947 set_default_event_procedures (file);
948 PUSH_VALUE (p, 0, A68_INT);
949 }
950
951 //! @brief PROC (REF FILE, REF STRING) VOID associate
952
953 void genie_associate (NODE_T * p)
954 {
955 A68_REF ref_string;
956 POP_REF (p, &ref_string);
957 CHECK_REF (p, ref_string, M_REF_STRING);
958 A68_REF ref_file;
959 POP_REF (p, &ref_file);
960 CHECK_REF (p, ref_file, M_REF_FILE);
961 if (IS_IN_HEAP (&ref_file) && !IS_IN_HEAP (&ref_string)) {
962 diagnostic (A68_RUNTIME_ERROR, p, ERROR_SCOPE_DYNAMIC_1, M_REF_STRING);
963 exit_genie (p, A68_RUNTIME_ERROR);
964 } else if (IS_IN_FRAME (&ref_file) && IS_IN_FRAME (&ref_string)) {
965 if (REF_SCOPE (&ref_string) > REF_SCOPE (&ref_file)) {
966 diagnostic (A68_RUNTIME_ERROR, p, ERROR_SCOPE_DYNAMIC_1, M_REF_STRING);
967 exit_genie (p, A68_RUNTIME_ERROR);
968 }
969 }
970 A68_FILE *file = FILE_DEREF (&ref_file);
971 STATUS (file) = INIT_MASK;
972 FILE_ENTRY (file) = -1;
973 CHANNEL (file) = A68 (associate_channel);
974 OPENED (file) = A68_TRUE;
975 OPEN_EXCLUSIVE (file) = A68_FALSE;
976 READ_MOOD (file) = A68_FALSE;
977 WRITE_MOOD (file) = A68_FALSE;
978 CHAR_MOOD (file) = A68_FALSE;
979 DRAW_MOOD (file) = A68_FALSE;
980 TMP_FILE (file) = A68_FALSE;
981 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
982 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
983 }
984 IDENTIFICATION (file) = nil_ref;
985 TERMINATOR (file) = nil_ref;
986 FORMAT (file) = nil_format;
987 FD (file) = A68_NO_FILE;
988 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
989 UNBLOCK_GC_HANDLE (DEREF (A68_REF, &STRING (file)));
990 }
991 STRING (file) = ref_string;
992 BLOCK_GC_HANDLE ((A68_REF *) (&(STRING (file))));
993 STRPOS (file) = 0;
994 DEVICE_MADE (&DEVICE (file)) = A68_FALSE;
995 STREAM (&DEVICE (file)) = NO_STREAM;
996 set_default_event_procedures (file);
997 }
998
999 //! @brief PROC (REF FILE) VOID close
1000
1001 void genie_close (NODE_T * p)
1002 {
1003 A68_REF ref_file;
1004 POP_REF (p, &ref_file);
1005 CHECK_REF (p, ref_file, M_REF_FILE);
1006 A68_FILE *file = FILE_DEREF (&ref_file);
1007 CHECK_INIT (p, INITIALISED (file), M_FILE);
1008 if (!OPENED (file) || (!READ_MOOD (file) && !WRITE_MOOD (file) && !DRAW_MOOD (file))) {
1009 return;
1010 }
1011 DEVICE_MADE (&DEVICE (file)) = A68_FALSE;
1012 #if defined (HAVE_GNU_PLOTUTILS)
1013 if (DEVICE_OPENED (&DEVICE (file))) {
1014 ASSERT (close_device (p, file) == A68_TRUE);
1015 STREAM (&DEVICE (file)) = NO_STREAM;
1016 return;
1017 }
1018 #endif
1019 FD (file) = A68_NO_FILE;
1020 OPENED (file) = A68_FALSE;
1021 unblock_transput_buffer (TRANSPUT_BUFFER (file));
1022 set_default_event_procedures (file);
1023 free_file_entry (p, FILE_ENTRY (file));
1024 }
1025
1026 //! @brief PROC (REF FILE) VOID lock
1027
1028 void genie_lock (NODE_T * p)
1029 {
1030 A68_REF ref_file;
1031 POP_REF (p, &ref_file);
1032 CHECK_REF (p, ref_file, M_REF_FILE);
1033 A68_FILE *file = FILE_DEREF (&ref_file);
1034 CHECK_INIT (p, INITIALISED (file), M_FILE);
1035 if (!OPENED (file) || (!READ_MOOD (file) && !WRITE_MOOD (file) && !DRAW_MOOD (file))) {
1036 return;
1037 }
1038 DEVICE_MADE (&DEVICE (file)) = A68_FALSE;
1039 #if defined (HAVE_GNU_PLOTUTILS)
1040 if (DEVICE_OPENED (&DEVICE (file))) {
1041 ASSERT (close_device (p, file) == A68_TRUE);
1042 STREAM (&DEVICE (file)) = NO_STREAM;
1043 return;
1044 }
1045 #endif
1046 #if defined (BUILD_UNIX)
1047 errno = 0;
1048 ASSERT (fchmod (FD (file), (mode_t) 0x0) != -1);
1049 #endif
1050 if (FD (file) != A68_NO_FILE && close (FD (file)) == -1) {
1051 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_LOCK);
1052 exit_genie (p, A68_RUNTIME_ERROR);
1053 } else {
1054 FD (file) = A68_NO_FILE;
1055 OPENED (file) = A68_FALSE;
1056 unblock_transput_buffer (TRANSPUT_BUFFER (file));
1057 set_default_event_procedures (file);
1058 }
1059 free_file_entry (p, FILE_ENTRY (file));
1060 }
1061
1062 //! @brief PROC (REF FILE) VOID erase
1063
1064 void genie_erase (NODE_T * p)
1065 {
1066 A68_REF ref_file;
1067 POP_REF (p, &ref_file);
1068 CHECK_REF (p, ref_file, M_REF_FILE);
1069 A68_FILE *file = FILE_DEREF (&ref_file);
1070 CHECK_INIT (p, INITIALISED (file), M_FILE);
1071 if (!OPENED (file) || (!READ_MOOD (file) && !WRITE_MOOD (file) && !DRAW_MOOD (file))) {
1072 return;
1073 }
1074 DEVICE_MADE (&DEVICE (file)) = A68_FALSE;
1075 #if defined (HAVE_GNU_PLOTUTILS)
1076 if (DEVICE_OPENED (&DEVICE (file))) {
1077 ASSERT (close_device (p, file) == A68_TRUE);
1078 STREAM (&DEVICE (file)) = NO_STREAM;
1079 return;
1080 }
1081 #endif
1082 if (FD (file) != A68_NO_FILE && close (FD (file)) == -1) {
1083 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_SCRATCH);
1084 exit_genie (p, A68_RUNTIME_ERROR);
1085 } else {
1086 unblock_transput_buffer (TRANSPUT_BUFFER (file));
1087 set_default_event_procedures (file);
1088 }
1089 // Remove the file.
1090 if (!IS_NIL (IDENTIFICATION (file))) {
1091 char *filename;
1092 CHECK_INIT (p, INITIALISED (&(IDENTIFICATION (file))), M_ROWS);
1093 filename = DEREF (char, &IDENTIFICATION (file));
1094 if (remove (filename) != 0) {
1095 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_SCRATCH);
1096 exit_genie (p, A68_RUNTIME_ERROR);
1097 }
1098 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
1099 IDENTIFICATION (file) = nil_ref;
1100 }
1101 init_file_entry (FILE_ENTRY (file));
1102 }
1103
1104 //! @brief PROC (REF FILE) VOID backspace
1105
1106 void genie_backspace (NODE_T * p)
1107 {
1108 ADDR_T pop_sp = A68_SP;
1109 PUSH_VALUE (p, -1, A68_INT);
1110 genie_set (p);
1111 A68_SP = pop_sp;
1112 }
1113
1114 //! @brief PROC (REF FILE, INT) INT set
1115
1116 void genie_set (NODE_T * p)
1117 {
1118 A68_INT pos;
1119 POP_OBJECT (p, &pos, A68_INT);
1120 A68_REF ref_file;
1121 POP_REF (p, &ref_file);
1122 CHECK_REF (p, ref_file, M_REF_FILE);
1123 A68_FILE *file = FILE_DEREF (&ref_file);
1124 CHECK_INIT (p, INITIALISED (file), M_FILE);
1125 if (!OPENED (file)) {
1126 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1127 exit_genie (p, A68_RUNTIME_ERROR);
1128 }
1129 if (!SET (&CHANNEL (file))) {
1130 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_CANT_SET);
1131 exit_genie (p, A68_RUNTIME_ERROR);
1132 }
1133 if (!IS_NIL (STRING (file))) {
1134 A68_REF z = *DEREF (A68_REF, &STRING (file));
1135 int size;
1136 // Circumvent buffering problems.
1137 STRPOS (file) -= get_transput_buffer_index (TRANSPUT_BUFFER (file));
1138 ASSERT (STRPOS (file) > 0);
1139 reset_transput_buffer (TRANSPUT_BUFFER (file));
1140 // Now set.
1141 CHECK_INT_ADDITION (p, STRPOS (file), VALUE (&pos));
1142 STRPOS (file) += VALUE (&pos);
1143 A68_ARRAY *arr; A68_TUPLE *tup;
1144 GET_DESCRIPTOR (arr, tup, &z);
1145 size = ROW_SIZE (tup);
1146 if (size <= 0 || STRPOS (file) < 0 || STRPOS (file) >= size) {
1147 A68_BOOL res;
1148 on_event_handler (p, FILE_END_MENDED (FILE_DEREF (&ref_file)), ref_file);
1149 POP_OBJECT (p, &res, A68_BOOL);
1150 if (VALUE (&res) == A68_FALSE) {
1151 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ENDED);
1152 exit_genie (p, A68_RUNTIME_ERROR);
1153 }
1154 }
1155 PUSH_VALUE (p, STRPOS (file), A68_INT);
1156 } else if (FD (file) == A68_NO_FILE) {
1157 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_RESET);
1158 exit_genie (p, A68_RUNTIME_ERROR);
1159 } else {
1160 errno = 0;
1161 __off_t curpos = lseek (FD (file), 0, SEEK_CUR);
1162 __off_t maxpos = lseek (FD (file), 0, SEEK_END);
1163 // Circumvent buffering problems.
1164 int reserve = get_transput_buffer_index (TRANSPUT_BUFFER (file));
1165 curpos -= (__off_t) reserve;
1166 __off_t res = lseek (FD (file), -reserve, SEEK_CUR);
1167 ASSERT (res != -1 && errno == 0);
1168 reset_transput_buffer (TRANSPUT_BUFFER (file));
1169 // Now set.
1170 CHECK_INT_ADDITION (p, curpos, VALUE (&pos));
1171 curpos += VALUE (&pos);
1172 if (curpos < 0 || curpos >= maxpos) {
1173 A68_BOOL ret;
1174 on_event_handler (p, FILE_END_MENDED (FILE_DEREF (&ref_file)), ref_file);
1175 POP_OBJECT (p, &ret, A68_BOOL);
1176 if (VALUE (&ret) == A68_FALSE) {
1177 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ENDED);
1178 exit_genie (p, A68_RUNTIME_ERROR);
1179 }
1180 PUSH_VALUE (p, (int) lseek (FD (file), 0, SEEK_CUR), A68_INT);
1181 } else {
1182 res = lseek (FD (file), curpos, SEEK_SET);
1183 if (res == -1 || errno != 0) {
1184 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_SET);
1185 exit_genie (p, A68_RUNTIME_ERROR);
1186 }
1187 PUSH_VALUE (p, (int) res, A68_INT);
1188 }
1189 }
1190 }
1191
1192 //! @brief PROC (REF FILE) VOID reset
1193
1194 void genie_reset (NODE_T * p)
1195 {
1196 A68_REF ref_file;
1197 POP_REF (p, &ref_file);
1198 CHECK_REF (p, ref_file, M_REF_FILE);
1199 A68_FILE *file = FILE_DEREF (&ref_file);
1200 CHECK_INIT (p, INITIALISED (file), M_FILE);
1201 if (!OPENED (file)) {
1202 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1203 exit_genie (p, A68_RUNTIME_ERROR);
1204 }
1205 if (!RESET (&CHANNEL (file))) {
1206 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_CANT_RESET);
1207 exit_genie (p, A68_RUNTIME_ERROR);
1208 }
1209 if (IS_NIL (STRING (file))) {
1210 close_file_entry (p, FILE_ENTRY (file));
1211 } else {
1212 STRPOS (file) = 0;
1213 }
1214 READ_MOOD (file) = A68_FALSE;
1215 WRITE_MOOD (file) = A68_FALSE;
1216 CHAR_MOOD (file) = A68_FALSE;
1217 DRAW_MOOD (file) = A68_FALSE;
1218 FD (file) = A68_NO_FILE;
1219 // set_default_event_procedures (file);.
1220 }
1221
1222 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on file end
1223
1224 void genie_on_file_end (NODE_T * p)
1225 {
1226 A68_PROCEDURE z;
1227 POP_PROCEDURE (p, &z);
1228 A68_REF ref_file;
1229 POP_REF (p, &ref_file);
1230 CHECK_REF (p, ref_file, M_REF_FILE);
1231 A68_FILE *file = FILE_DEREF (&ref_file);
1232 CHECK_INIT (p, INITIALISED (file), M_FILE);
1233 FILE_END_MENDED (file) = z;
1234 }
1235
1236 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on page end
1237
1238 void genie_on_page_end (NODE_T * p)
1239 {
1240 A68_PROCEDURE z;
1241 POP_PROCEDURE (p, &z);
1242 A68_REF ref_file;
1243 POP_REF (p, &ref_file);
1244 CHECK_REF (p, ref_file, M_REF_FILE);
1245 A68_FILE *file = FILE_DEREF (&ref_file);
1246 CHECK_INIT (p, INITIALISED (file), M_FILE);
1247 PAGE_END_MENDED (file) = z;
1248 }
1249
1250 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on line end
1251
1252 void genie_on_line_end (NODE_T * p)
1253 {
1254 A68_PROCEDURE z;
1255 POP_PROCEDURE (p, &z);
1256 A68_REF ref_file;
1257 POP_REF (p, &ref_file);
1258 CHECK_REF (p, ref_file, M_REF_FILE);
1259 A68_FILE *file = FILE_DEREF (&ref_file);
1260 CHECK_INIT (p, INITIALISED (file), M_FILE);
1261 LINE_END_MENDED (file) = z;
1262 }
1263
1264 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on format end
1265
1266 void genie_on_format_end (NODE_T * p)
1267 {
1268 A68_PROCEDURE z;
1269 POP_PROCEDURE (p, &z);
1270 A68_REF ref_file;
1271 POP_REF (p, &ref_file);
1272 CHECK_REF (p, ref_file, M_REF_FILE);
1273 A68_FILE *file = FILE_DEREF (&ref_file);
1274 CHECK_INIT (p, INITIALISED (file), M_FILE);
1275 FORMAT_END_MENDED (file) = z;
1276 }
1277
1278 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on format error
1279
1280 void genie_on_format_error (NODE_T * p)
1281 {
1282 A68_PROCEDURE z;
1283 POP_PROCEDURE (p, &z);
1284 A68_REF ref_file;
1285 POP_REF (p, &ref_file);
1286 CHECK_REF (p, ref_file, M_REF_FILE);
1287 A68_FILE *file = FILE_DEREF (&ref_file);
1288 CHECK_INIT (p, INITIALISED (file), M_FILE);
1289 FORMAT_ERROR_MENDED (file) = z;
1290 }
1291
1292 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on value error
1293
1294 void genie_on_value_error (NODE_T * p)
1295 {
1296 A68_PROCEDURE z;
1297 POP_PROCEDURE (p, &z);
1298 A68_REF ref_file;
1299 POP_REF (p, &ref_file);
1300 CHECK_REF (p, ref_file, M_REF_FILE);
1301 A68_FILE *file = FILE_DEREF (&ref_file);
1302 CHECK_INIT (p, INITIALISED (file), M_FILE);
1303 VALUE_ERROR_MENDED (file) = z;
1304 }
1305
1306 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on open error
1307
1308 void genie_on_open_error (NODE_T * p)
1309 {
1310 A68_PROCEDURE z;
1311 POP_PROCEDURE (p, &z);
1312 A68_REF ref_file;
1313 POP_REF (p, &ref_file);
1314 CHECK_REF (p, ref_file, M_REF_FILE);
1315 A68_FILE *file = FILE_DEREF (&ref_file);
1316 CHECK_INIT (p, INITIALISED (file), M_FILE);
1317 OPEN_ERROR_MENDED (file) = z;
1318 }
1319
1320 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on transput error
1321
1322 void genie_on_transput_error (NODE_T * p)
1323 {
1324 A68_PROCEDURE z;
1325 POP_PROCEDURE (p, &z);
1326 A68_REF ref_file;
1327 POP_REF (p, &ref_file);
1328 CHECK_REF (p, ref_file, M_REF_FILE);
1329 A68_FILE *file = FILE_DEREF (&ref_file);
1330 CHECK_INIT (p, INITIALISED (file), M_FILE);
1331 TRANSPUT_ERROR_MENDED (file) = z;
1332 }
1333
1334 //! @brief Invoke event routine.
1335
1336 void on_event_handler (NODE_T * p, A68_PROCEDURE z, A68_REF ref_file)
1337 {
1338 if (NODE (&(BODY (&z))) == NO_NODE) {
1339 // Default procedure.
1340 PUSH_VALUE (p, A68_FALSE, A68_BOOL);
1341 } else {
1342 ADDR_T pop_sp = A68_SP, pop_fp = A68_FP;
1343 PUSH_REF (p, ref_file);
1344 genie_call_event_routine (p, M_PROC_REF_FILE_BOOL, &z, pop_sp, pop_fp);
1345 }
1346 }
1347
1348 //! @brief Handle end-of-file event.
1349
1350 void end_of_file_error (NODE_T * p, A68_REF ref_file)
1351 {
1352 on_event_handler (p, FILE_END_MENDED (FILE_DEREF (&ref_file)), ref_file);
1353 A68_BOOL z;
1354 POP_OBJECT (p, &z, A68_BOOL);
1355 if (VALUE (&z) == A68_FALSE) {
1356 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ENDED);
1357 exit_genie (p, A68_RUNTIME_ERROR);
1358 }
1359 }
1360
1361 //! @brief Handle file-open-error event.
1362
1363 void open_error (NODE_T * p, A68_REF ref_file, char *mode)
1364 {
1365 on_event_handler (p, OPEN_ERROR_MENDED (FILE_DEREF (&ref_file)), ref_file);
1366 A68_BOOL z;
1367 POP_OBJECT (p, &z, A68_BOOL);
1368 if (VALUE (&z) == A68_FALSE) {
1369 CHECK_REF (p, ref_file, M_REF_FILE);
1370 A68_FILE *file = FILE_DEREF (&ref_file);
1371 CHECK_INIT (p, INITIALISED (file), M_FILE);
1372 char *filename;
1373 if (!IS_NIL (IDENTIFICATION (file))) {
1374 filename = DEREF (char, &IDENTIFICATION (FILE_DEREF (&ref_file)));
1375 } else {
1376 filename = "(missing filename)";
1377 }
1378 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_CANNOT_OPEN_FOR, filename, mode);
1379 exit_genie (p, A68_RUNTIME_ERROR);
1380 }
1381 }
1382
1383 //! @brief Handle value error event.
1384
1385 void value_error (NODE_T * p, MOID_T * m, A68_REF ref_file)
1386 {
1387 A68_FILE *f = FILE_DEREF (&ref_file);
1388 if (END_OF_FILE (f)) {
1389 end_of_file_error (p, ref_file);
1390 } else {
1391 on_event_handler (p, VALUE_ERROR_MENDED (f), ref_file);
1392 A68_BOOL z;
1393 POP_OBJECT (p, &z, A68_BOOL);
1394 if (VALUE (&z) == A68_FALSE) {
1395 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_TRANSPUT, m);
1396 exit_genie (p, A68_RUNTIME_ERROR);
1397 }
1398 }
1399 }
1400
1401 //! @brief Handle value_error event.
1402
1403 void value_sign_error (NODE_T * p, MOID_T * m, A68_REF ref_file)
1404 {
1405 A68_FILE *f = FILE_DEREF (&ref_file);
1406 if (END_OF_FILE (f)) {
1407 end_of_file_error (p, ref_file);
1408 } else {
1409 on_event_handler (p, VALUE_ERROR_MENDED (f), ref_file);
1410 A68_BOOL z;
1411 POP_OBJECT (p, &z, A68_BOOL);
1412 if (VALUE (&z) == A68_FALSE) {
1413 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_TRANSPUT_SIGN, m);
1414 exit_genie (p, A68_RUNTIME_ERROR);
1415 }
1416 }
1417 }
1418
1419 //! @brief Handle transput-error event.
1420
1421 void transput_error (NODE_T * p, A68_REF ref_file, MOID_T * m)
1422 {
1423 on_event_handler (p, TRANSPUT_ERROR_MENDED (FILE_DEREF (&ref_file)), ref_file);
1424 A68_BOOL z;
1425 POP_OBJECT (p, &z, A68_BOOL);
1426 if (VALUE (&z) == A68_FALSE) {
1427 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_TRANSPUT, m);
1428 exit_genie (p, A68_RUNTIME_ERROR);
1429 }
1430 }
1431
1432 // Implementation of put and get.
1433
1434 //! @brief Get next char from file.
1435
1436 int char_scanner (A68_FILE * f)
1437 {
1438 if (get_transput_buffer_index (TRANSPUT_BUFFER (f)) > 0) {
1439 // There are buffered characters.
1440 END_OF_FILE (f) = A68_FALSE;
1441 return pop_char_transput_buffer (TRANSPUT_BUFFER (f));
1442 } else if (IS_NIL (STRING (f))) {
1443 // Fetch next CHAR from the FILE.
1444 char ch;
1445 ssize_t chars_read = io_read_conv (FD (f), &ch, 1);
1446 if (chars_read == 1) {
1447 END_OF_FILE (f) = A68_FALSE;
1448 return ch;
1449 } else {
1450 END_OF_FILE (f) = A68_TRUE;
1451 return EOF_CHAR;
1452 }
1453 } else {
1454 // File is associated with a STRING. Give next CHAR.
1455 // When we're outside the STRING give EOF_CHAR.
1456 A68_REF z = *DEREF (A68_REF, &STRING (f)); A68_ARRAY *arr; A68_TUPLE *tup;
1457 GET_DESCRIPTOR (arr, tup, &z);
1458 int k = STRPOS (f) + LWB (tup);
1459 if (ROW_SIZE (tup) <= 0 || k < LWB (tup) || k > UPB (tup)) {
1460 END_OF_FILE (f) = A68_TRUE;
1461 return EOF_CHAR;
1462 } else {
1463 BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
1464 A68_CHAR *ch = (A68_CHAR *) & (base[INDEX_1_DIM (arr, tup, k)]);
1465 STRPOS (f)++;
1466 return VALUE (ch);
1467 }
1468 }
1469 }
1470
1471 //! @brief Push back look-ahead character to file.
1472
1473 void unchar_scanner (NODE_T * p, A68_FILE * f, char ch)
1474 {
1475 END_OF_FILE (f) = A68_FALSE;
1476 plusab_transput_buffer (p, TRANSPUT_BUFFER (f), ch);
1477 }
1478
1479 //! @brief PROC (REF FILE) BOOL eof
1480
1481 void genie_eof (NODE_T * p)
1482 {
1483 A68_REF ref_file;
1484 POP_REF (p, &ref_file);
1485 CHECK_REF (p, ref_file, M_REF_FILE);
1486 A68_FILE *file = FILE_DEREF (&ref_file);
1487 CHECK_INIT (p, INITIALISED (file), M_FILE);
1488 if (!OPENED (file)) {
1489 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1490 exit_genie (p, A68_RUNTIME_ERROR);
1491 }
1492 if (DRAW_MOOD (file)) {
1493 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1494 exit_genie (p, A68_RUNTIME_ERROR);
1495 }
1496 if (WRITE_MOOD (file)) {
1497 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
1498 exit_genie (p, A68_RUNTIME_ERROR);
1499 } else if (READ_MOOD (file)) {
1500 int ch = char_scanner (file);
1501 PUSH_VALUE (p, (BOOL_T) ((ch == EOF_CHAR || END_OF_FILE (file)) ? A68_TRUE : A68_FALSE), A68_BOOL);
1502 unchar_scanner (p, file, (char) ch);
1503 } else {
1504 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1505 exit_genie (p, A68_RUNTIME_ERROR);
1506 }
1507 }
1508
1509 //! @brief PROC (REF FILE) BOOL eoln
1510
1511 void genie_eoln (NODE_T * p)
1512 {
1513 A68_REF ref_file;
1514 POP_REF (p, &ref_file);
1515 CHECK_REF (p, ref_file, M_REF_FILE);
1516 A68_FILE *file = FILE_DEREF (&ref_file);
1517 CHECK_INIT (p, INITIALISED (file), M_FILE);
1518 if (!OPENED (file)) {
1519 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1520 exit_genie (p, A68_RUNTIME_ERROR);
1521 }
1522 if (DRAW_MOOD (file)) {
1523 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1524 exit_genie (p, A68_RUNTIME_ERROR);
1525 }
1526 if (WRITE_MOOD (file)) {
1527 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
1528 exit_genie (p, A68_RUNTIME_ERROR);
1529 } else if (READ_MOOD (file)) {
1530 int ch = char_scanner (file);
1531 if (END_OF_FILE (file)) {
1532 end_of_file_error (p, ref_file);
1533 }
1534 PUSH_VALUE (p, (BOOL_T) (ch == NEWLINE_CHAR ? A68_TRUE : A68_FALSE), A68_BOOL);
1535 unchar_scanner (p, file, (char) ch);
1536 } else {
1537 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1538 exit_genie (p, A68_RUNTIME_ERROR);
1539 }
1540 }
1541
1542 //! @brief PROC (REF FILE) VOID new line
1543
1544 void genie_new_line (NODE_T * p)
1545 {
1546 A68_REF ref_file;
1547 POP_REF (p, &ref_file);
1548 CHECK_REF (p, ref_file, M_REF_FILE);
1549 A68_FILE *file = FILE_DEREF (&ref_file);
1550 CHECK_INIT (p, INITIALISED (file), M_FILE);
1551 if (!OPENED (file)) {
1552 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1553 exit_genie (p, A68_RUNTIME_ERROR);
1554 }
1555 if (DRAW_MOOD (file)) {
1556 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1557 exit_genie (p, A68_RUNTIME_ERROR);
1558 }
1559 if (WRITE_MOOD (file)) {
1560 on_event_handler (p, LINE_END_MENDED (file), ref_file);
1561 if (IS_NIL (STRING (file))) {
1562 WRITE (FD (file), NEWLINE_STRING);
1563 } else {
1564 add_c_string_to_a_string (p, STRING (file), NEWLINE_STRING);
1565 }
1566 } else if (READ_MOOD (file)) {
1567 BOOL_T siga = A68_TRUE;
1568 while (siga) {
1569 int ch;
1570 if (END_OF_FILE (file)) {
1571 end_of_file_error (p, ref_file);
1572 }
1573 ch = char_scanner (file);
1574 siga = (BOOL_T) ((ch != NEWLINE_CHAR) && (ch != EOF_CHAR) && !END_OF_FILE (file));
1575 }
1576 } else {
1577 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1578 exit_genie (p, A68_RUNTIME_ERROR);
1579 }
1580 }
1581
1582 //! @brief PROC (REF FILE) VOID new page
1583
1584 void genie_new_page (NODE_T * p)
1585 {
1586 A68_REF ref_file;
1587 POP_REF (p, &ref_file);
1588 CHECK_REF (p, ref_file, M_REF_FILE);
1589 A68_FILE *file = FILE_DEREF (&ref_file);
1590 CHECK_INIT (p, INITIALISED (file), M_FILE);
1591 if (!OPENED (file)) {
1592 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1593 exit_genie (p, A68_RUNTIME_ERROR);
1594 }
1595 if (DRAW_MOOD (file)) {
1596 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1597 exit_genie (p, A68_RUNTIME_ERROR);
1598 }
1599 if (WRITE_MOOD (file)) {
1600 on_event_handler (p, PAGE_END_MENDED (file), ref_file);
1601 if (IS_NIL (STRING (file))) {
1602 WRITE (FD (file), "\f");
1603 } else {
1604 add_c_string_to_a_string (p, STRING (file), "\f");
1605 }
1606 } else if (READ_MOOD (file)) {
1607 BOOL_T siga = A68_TRUE;
1608 while (siga) {
1609 if (END_OF_FILE (file)) {
1610 end_of_file_error (p, ref_file);
1611 }
1612 int ch = char_scanner (file);
1613 siga = (BOOL_T) ((ch != FORMFEED_CHAR) && (ch != EOF_CHAR) && !END_OF_FILE (file));
1614 }
1615 } else {
1616 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1617 exit_genie (p, A68_RUNTIME_ERROR);
1618 }
1619 }
1620
1621 //! @brief PROC (REF FILE) VOID space
1622
1623 void genie_space (NODE_T * p)
1624 {
1625 A68_REF ref_file;
1626 POP_REF (p, &ref_file);
1627 CHECK_REF (p, ref_file, M_REF_FILE);
1628 A68_FILE *file = FILE_DEREF (&ref_file);
1629 CHECK_INIT (p, INITIALISED (file), M_FILE);
1630 if (!OPENED (file)) {
1631 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1632 exit_genie (p, A68_RUNTIME_ERROR);
1633 }
1634 if (DRAW_MOOD (file)) {
1635 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1636 exit_genie (p, A68_RUNTIME_ERROR);
1637 }
1638 if (WRITE_MOOD (file)) {
1639 WRITE (FD (file), " ");
1640 } else if (READ_MOOD (file)) {
1641 if (!END_OF_FILE (file)) {
1642 (void) char_scanner (file);
1643 }
1644 } else {
1645 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1646 exit_genie (p, A68_RUNTIME_ERROR);
1647 }
1648 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|