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-2026 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 = &(A68G (file_entries)[k]);
47 POS (fe) = NO_NODE;
48 IS_OPEN (fe) = A68G_FALSE;
49 IS_TMP (fe) = A68G_FALSE;
50 FD (fe) = A68G_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 = &(A68G (file_entries)[k]);
70 if (!IS_OPEN (fe)) {
71 size_t len = 1 + strlen (idf);
72 POS (fe) = p;
73 IS_OPEN (fe) = A68G_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 a68g_bufcpy (DEREF (char, &IDF (fe)), idf, len);
79 return k;
80 }
81 }
82 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_TOO_MANY_OPEN_FILES);
83 exit_genie (p, A68G_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 = &(A68G (file_entries)[k]);
93 if (IS_OPEN (fe)) {
94 // Close the file.
95 if (FD (fe) != A68G_NO_FILE && close (FD (fe)) == -1) {
96 init_file_entry (k);
97 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_CLOSE);
98 exit_genie (p, A68G_RUNTIME_ERROR);
99 }
100 IS_OPEN (fe) = A68G_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 = &(A68G (file_entries)[k]);
112 if (IS_OPEN (fe)) {
113 // Attempt to remove a temp file, but ignore failure.
114 if (FD (fe) != A68G_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 A68G_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_T size)
152 {
153 A68G_INT *k = (A68G_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_T cindex)
161 {
162 A68G_INT *k = (A68G_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_T get_transput_buffer_size (int n)
170 {
171 A68G_INT *k = (A68G_INT *) (ADDRESS (&ref_transput_buffer[n]));
172 return VALUE (k);
173 }
174
175 //! @brief Get char index for transput buffer.
176
177 INT_T get_transput_buffer_index (int n)
178 {
179 A68G_INT *k = (A68G_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, TRANSPUT_BUFFER_BLOCKED);
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) == TRANSPUT_BUFFER_BLOCKED) {
203 return k;
204 }
205 }
206 // Oops!
207 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_TOO_MANY_OPEN_FILES);
208 exit_genie (p, A68G_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_T 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 a68g_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 size_t 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 size_t 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 A68G_REF row = *(A68G_REF *) ref;
309 CHECK_INIT (p, INITIALISED (&row), M_ROWS);
310 A68G_ARRAY *arr; A68G_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 A68G_CHAR *ch = (A68G_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, A68G_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, A68G_REF ref_str, char *s)
350 {
351 size_t len_2 = strlen (s);
352 // left part.
353 CHECK_REF (p, ref_str, M_REF_STRING);
354 A68G_REF a = *DEREF (A68G_REF, &ref_str);
355 CHECK_INIT (p, INITIALISED (&a), M_STRING);
356 A68G_ARRAY *arr_1; A68G_TUPLE *tup_1;
357 GET_DESCRIPTOR (arr_1, tup_1, &a);
358 size_t len_1 = ROW_SIZE (tup_1);
359 // Sum string.
360 A68G_REF c = heap_generator (p, M_STRING, DESCRIPTOR_SIZE (1));
361 A68G_REF d = heap_generator_2 (p, M_STRING, len_1 + len_2, SIZE (M_CHAR));
362 // Calculate again in case garbage collection moved data.
363 // GC should not move volatile data, but there you are.
364 GET_DESCRIPTOR (arr_1, tup_1, &a);
365 // Make descriptor of new string.
366 A68G_ARRAY *arr_3; A68G_TUPLE *tup_3;
367 GET_DESCRIPTOR (arr_3, tup_3, &c);
368 DIM (arr_3) = 1;
369 SLICE (arr_3) = M_CHAR;
370 SLICE_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 A68G_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 (A68G_REF, &ref_str) = c;
394 }
395
396 //! @brief Purge buffer for file.
397
398 void write_purge_buffer (NODE_T * p, A68G_REF ref_file, int k)
399 {
400 A68G_FILE *file = FILE_DEREF (&ref_file);
401 if (IS_NIL (STRING (file))) {
402 if (!(FD (file) == A68G_STDOUT && A68G (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, size_t size)
416 {
417 char *new_str = (char *) STACK_TOP;
418 INCREMENT_STACK_POINTER (p, size);
419 if (A68G_SP > A68G (expr_stack_limit)) {
420 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_STACK_OVERFLOW);
421 exit_genie (p, A68G_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, A68G (stand_in));
434 }
435
436 //! @brief REF FILE standout
437
438 void genie_stand_out (NODE_T * p)
439 {
440 PUSH_REF (p, A68G (stand_out));
441 }
442
443 //! @brief REF FILE standback
444
445 void genie_stand_back (NODE_T * p)
446 {
447 PUSH_REF (p, A68G (stand_back));
448 }
449
450 //! @brief REF FILE standerror
451
452 void genie_stand_error (NODE_T * p)
453 {
454 PUSH_REF (p, A68G (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, A68G_CHAR);
462 }
463
464 //! @brief CHAR exp char
465
466 void genie_exp_char (NODE_T * p)
467 {
468 PUSH_VALUE (p, EXPONENT_CHAR, A68G_CHAR);
469 }
470
471 //! @brief CHAR flip char
472
473 void genie_flip_char (NODE_T * p)
474 {
475 PUSH_VALUE (p, FLIP_CHAR, A68G_CHAR);
476 }
477
478 //! @brief CHAR flop char
479
480 void genie_flop_char (NODE_T * p)
481 {
482 PUSH_VALUE (p, FLOP_CHAR, A68G_CHAR);
483 }
484
485 //! @brief CHAR eof char
486
487 void genie_eof_char (NODE_T * p)
488 {
489 PUSH_VALUE (p, EOF_CHAR, A68G_CHAR);
490 }
491
492 //! @brief CHAR null char
493
494 void genie_null_char (NODE_T * p)
495 {
496 PUSH_VALUE (p, NULL_CHAR, A68G_CHAR);
497 }
498
499 //! @brief CHAR blank
500
501 void genie_blank_char (NODE_T * p)
502 {
503 PUSH_VALUE (p, BLANK_CHAR, A68G_CHAR);
504 }
505
506 //! @brief CHAR newline char
507
508 void genie_newline_char (NODE_T * p)
509 {
510 PUSH_VALUE (p, NEWLINE_CHAR, A68G_CHAR);
511 }
512
513 //! @brief CHAR formfeed char
514
515 void genie_formfeed_char (NODE_T * p)
516 {
517 PUSH_VALUE (p, FORMFEED_CHAR, A68G_CHAR);
518 }
519
520 //! @brief CHAR tab char
521
522 void genie_tab_char (NODE_T * p)
523 {
524 PUSH_VALUE (p, TAB_CHAR, A68G_CHAR);
525 }
526
527 //! @brief CHANNEL standin channel
528
529 void genie_stand_in_channel (NODE_T * p)
530 {
531 PUSH_OBJECT (p, A68G (stand_in_channel), A68G_CHANNEL);
532 }
533
534 //! @brief CHANNEL standout channel
535
536 void genie_stand_out_channel (NODE_T * p)
537 {
538 PUSH_OBJECT (p, A68G (stand_out_channel), A68G_CHANNEL);
539 }
540
541 //! @brief CHANNEL stand draw channel
542
543 void genie_stand_draw_channel (NODE_T * p)
544 {
545 PUSH_OBJECT (p, A68G (stand_draw_channel), A68G_CHANNEL);
546 }
547
548 //! @brief CHANNEL standback channel
549
550 void genie_stand_back_channel (NODE_T * p)
551 {
552 PUSH_OBJECT (p, A68G (stand_back_channel), A68G_CHANNEL);
553 }
554
555 //! @brief CHANNEL standerror channel
556
557 void genie_stand_error_channel (NODE_T * p)
558 {
559 PUSH_OBJECT (p, A68G (stand_error_channel), A68G_CHANNEL);
560 }
561
562 //! @brief PROC STRING program idf
563
564 void genie_program_idf (NODE_T * p)
565 {
566 PUSH_REF (p, c_to_a_string (p, FILE_SOURCE_NAME (&A68G_JOB), DEFAULT_WIDTH));
567 }
568
569 // FILE and CHANNEL initialisations.
570
571 //! @brief Set_default_event_procedure.
572
573 void set_default_event_procedure (A68G_PROCEDURE * z)
574 {
575 STATUS (z) = INIT_MASK;
576 NODE (&(BODY (z))) = NO_NODE;
577 ENVIRON (z) = 0;
578 }
579
580 //! @brief Initialise channel.
581
582 void init_channel (A68G_CHANNEL * chan, BOOL_T r, BOOL_T s, BOOL_T g, BOOL_T p, BOOL_T b, BOOL_T d)
583 {
584 STATUS (chan) = INIT_MASK;
585 RESET (chan) = r;
586 SET (chan) = s;
587 GET (chan) = g;
588 PUT (chan) = p;
589 BIN (chan) = b;
590 DRAW (chan) = d;
591 COMPRESS (chan) = A68G_TRUE;
592 }
593
594 //! @brief Set default event handlers.
595
596 void set_default_event_procedures (A68G_FILE * f)
597 {
598 set_default_event_procedure (&(FILE_END_MENDED (f)));
599 set_default_event_procedure (&(PAGE_END_MENDED (f)));
600 set_default_event_procedure (&(LINE_END_MENDED (f)));
601 set_default_event_procedure (&(VALUE_ERROR_MENDED (f)));
602 set_default_event_procedure (&(OPEN_ERROR_MENDED (f)));
603 set_default_event_procedure (&(TRANSPUT_ERROR_MENDED (f)));
604 set_default_event_procedure (&(FORMAT_END_MENDED (f)));
605 set_default_event_procedure (&(FORMAT_ERROR_MENDED (f)));
606 }
607
608 //! @brief Set up a REF FILE object.
609
610 void init_file (NODE_T * p, A68G_REF * ref_file, A68G_CHANNEL c, FILE_T s, BOOL_T rm, BOOL_T wm, BOOL_T cm, char *env)
611 {
612 char *filename = (env == NO_TEXT ? NO_TEXT : getenv (env));
613 *ref_file = heap_generator (p, M_REF_FILE, SIZE (M_FILE));
614 BLOCK_GC_HANDLE (ref_file);
615 A68G_FILE *f = FILE_DEREF (ref_file);
616 STATUS (f) = INIT_MASK;
617 TERMINATOR (f) = nil_ref;
618 CHANNEL (f) = c;
619 if (filename != NO_TEXT && strlen (filename) > 0) {
620 size_t len = 1 + strlen (filename);
621 IDENTIFICATION (f) = heap_generator (p, M_C_STRING, len);
622 BLOCK_GC_HANDLE (&(IDENTIFICATION (f)));
623 a68g_bufcpy (DEREF (char, &IDENTIFICATION (f)), filename, len);
624 FD (f) = A68G_NO_FILE;
625 READ_MOOD (f) = A68G_FALSE;
626 WRITE_MOOD (f) = A68G_FALSE;
627 CHAR_MOOD (f) = A68G_FALSE;
628 DRAW_MOOD (f) = A68G_FALSE;
629 } else {
630 IDENTIFICATION (f) = nil_ref;
631 FD (f) = s;
632 READ_MOOD (f) = rm;
633 WRITE_MOOD (f) = wm;
634 CHAR_MOOD (f) = cm;
635 DRAW_MOOD (f) = A68G_FALSE;
636 }
637 TRANSPUT_BUFFER (f) = get_unblocked_transput_buffer (p);
638 reset_transput_buffer (TRANSPUT_BUFFER (f));
639 END_OF_FILE (f) = A68G_FALSE;
640 TMP_FILE (f) = A68G_FALSE;
641 OPENED (f) = A68G_TRUE;
642 APPEND (f) = A68G_FALSE;
643 OPEN_EXCLUSIVE (f) = A68G_FALSE;
644 FORMAT (f) = nil_format;
645 STRING (f) = nil_ref;
646 STRPOS (f) = 0;
647 FILE_ENTRY (f) = -1;
648 set_default_event_procedures (f);
649 }
650
651 //! @brief Initialise the transput RTL.
652
653 void genie_init_transput (NODE_T * p)
654 {
655 init_transput_buffers (p);
656 // Channels.
657 init_channel (&(A68G (stand_in_channel)), A68G_FALSE, A68G_FALSE, A68G_TRUE, A68G_FALSE, A68G_FALSE, A68G_FALSE);
658 init_channel (&(A68G (stand_out_channel)), A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_TRUE, A68G_FALSE, A68G_FALSE);
659 init_channel (&(A68G (stand_back_channel)), A68G_TRUE, A68G_TRUE, A68G_TRUE, A68G_TRUE, A68G_TRUE, A68G_FALSE);
660 init_channel (&(A68G (stand_error_channel)), A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_TRUE, A68G_FALSE, A68G_FALSE);
661 init_channel (&(A68G (associate_channel)), A68G_TRUE, A68G_TRUE, A68G_TRUE, A68G_TRUE, A68G_TRUE, A68G_FALSE);
662 init_channel (&(A68G (skip_channel)), A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_FALSE);
663 #if defined (HAVE_GNU_PLOTUTILS)
664 init_channel (&(A68G (stand_draw_channel)), A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_TRUE);
665 #else
666 init_channel (&(A68G (stand_draw_channel)), A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_FALSE, A68G_TRUE);
667 #endif
668 // Files.
669 init_file (p, &(A68G (stand_in)), A68G (stand_in_channel), A68G_STDIN, A68G_TRUE, A68G_FALSE, A68G_TRUE, "A68G_STANDIN");
670 init_file (p, &(A68G (stand_out)), A68G (stand_out_channel), A68G_STDOUT, A68G_FALSE, A68G_TRUE, A68G_TRUE, "A68G_STANDOUT");
671 init_file (p, &(A68G (stand_back)), A68G (stand_back_channel), A68G_NO_FILE, A68G_FALSE, A68G_FALSE, A68G_FALSE, NO_TEXT);
672 init_file (p, &(A68G (stand_error)), A68G (stand_error_channel), A68G_STDERR, A68G_FALSE, A68G_TRUE, A68G_TRUE, "A68G_STANDERROR");
673 init_file (p, &(A68G (skip_file)), A68G (skip_channel), A68G_NO_FILE, A68G_FALSE, A68G_FALSE, A68G_FALSE, NO_TEXT);
674 }
675
676 //! @brief PROC (REF FILE) STRING idf
677
678 void genie_idf (NODE_T * p)
679 {
680 A68G_REF ref_file;
681 POP_REF (p, &ref_file);
682 CHECK_REF (p, ref_file, M_REF_FILE);
683 ref_file = *(A68G_REF *) STACK_TOP;
684 A68G_REF ref_filename = IDENTIFICATION (FILE_DEREF (&ref_file));
685 CHECK_REF (p, ref_filename, M_ROWS);
686 char *filename = DEREF (char, &ref_filename);
687 PUSH_REF (p, c_to_a_string (p, filename, DEFAULT_WIDTH));
688 }
689
690 //! @brief PROC (REF FILE) STRING term
691
692 void genie_term (NODE_T * p)
693 {
694 A68G_REF ref_file;
695 POP_REF (p, &ref_file);
696 CHECK_REF (p, ref_file, M_REF_FILE);
697 ref_file = *(A68G_REF *) STACK_TOP;
698 A68G_REF ref_term = TERMINATOR (FILE_DEREF (&ref_file));
699 CHECK_REF (p, ref_term, M_ROWS);
700 char *term = DEREF (char, &ref_term);
701 PUSH_REF (p, c_to_a_string (p, term, DEFAULT_WIDTH));
702 }
703
704 //! @brief PROC (REF FILE, STRING) VOID make term
705
706 void genie_make_term (NODE_T * p)
707 {
708 A68G_REF ref_file, str;
709 POP_REF (p, &str);
710 POP_REF (p, &ref_file);
711 CHECK_REF (p, ref_file, M_REF_FILE);
712 ref_file = *(A68G_REF *) STACK_TOP;
713 A68G_FILE *file = FILE_DEREF (&ref_file);
714 // Don't check initialisation so we can "make term" before opening.
715 size_t size = a68g_string_size (p, str);
716 if (INITIALISED (&(TERMINATOR (file))) && !IS_NIL (TERMINATOR (file))) {
717 UNBLOCK_GC_HANDLE (&(TERMINATOR (file)));
718 }
719 TERMINATOR (file) = heap_generator (p, M_C_STRING, 1 + size);
720 BLOCK_GC_HANDLE (&(TERMINATOR (file)));
721 ASSERT (a_to_c_string (p, DEREF (char, &TERMINATOR (file)), str) != NO_TEXT);
722 }
723
724 //! @brief PROC (REF FILE) BOOL put possible
725
726 void genie_put_possible (NODE_T * p)
727 {
728 A68G_REF ref_file;
729 POP_REF (p, &ref_file);
730 CHECK_REF (p, ref_file, M_REF_FILE);
731 A68G_FILE *file = FILE_DEREF (&ref_file);
732 CHECK_INIT (p, INITIALISED (file), M_FILE);
733 PUSH_VALUE (p, PUT (&CHANNEL (file)), A68G_BOOL);
734 }
735
736 //! @brief PROC (REF FILE) BOOL get possible
737
738 void genie_get_possible (NODE_T * p)
739 {
740 A68G_REF ref_file;
741 POP_REF (p, &ref_file);
742 CHECK_REF (p, ref_file, M_REF_FILE);
743 A68G_FILE *file = FILE_DEREF (&ref_file);
744 CHECK_INIT (p, INITIALISED (file), M_FILE);
745 PUSH_VALUE (p, GET (&CHANNEL (file)), A68G_BOOL);
746 }
747
748 //! @brief PROC (REF FILE) BOOL bin possible
749
750 void genie_bin_possible (NODE_T * p)
751 {
752 A68G_REF ref_file;
753 POP_REF (p, &ref_file);
754 CHECK_REF (p, ref_file, M_REF_FILE);
755 A68G_FILE *file = FILE_DEREF (&ref_file);
756 CHECK_INIT (p, INITIALISED (file), M_FILE);
757 PUSH_VALUE (p, BIN (&CHANNEL (file)), A68G_BOOL);
758 }
759
760 //! @brief PROC (REF FILE) BOOL set possible
761
762 void genie_set_possible (NODE_T * p)
763 {
764 A68G_REF ref_file;
765 POP_REF (p, &ref_file);
766 CHECK_REF (p, ref_file, M_REF_FILE);
767 A68G_FILE *file = FILE_DEREF (&ref_file);
768 CHECK_INIT (p, INITIALISED (file), M_FILE);
769 PUSH_VALUE (p, SET (&CHANNEL (file)), A68G_BOOL);
770 }
771
772 //! @brief PROC (REF FILE) BOOL reidf possible
773
774 void genie_reidf_possible (NODE_T * p)
775 {
776 A68G_REF ref_file;
777 POP_REF (p, &ref_file);
778 CHECK_REF (p, ref_file, M_REF_FILE);
779 A68G_FILE *file = FILE_DEREF (&ref_file);
780 CHECK_INIT (p, INITIALISED (file), M_FILE);
781 PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
782 }
783
784 //! @brief PROC (REF FILE) BOOL reset possible
785
786 void genie_reset_possible (NODE_T * p)
787 {
788 A68G_REF ref_file;
789 POP_REF (p, &ref_file);
790 CHECK_REF (p, ref_file, M_REF_FILE);
791 A68G_FILE *file = FILE_DEREF (&ref_file);
792 CHECK_INIT (p, INITIALISED (file), M_FILE);
793 PUSH_VALUE (p, RESET (&CHANNEL (file)), A68G_BOOL);
794 }
795
796 //! @brief PROC (REF FILE) BOOL compressible
797
798 void genie_compressible (NODE_T * p)
799 {
800 A68G_REF ref_file;
801 A68G_FILE *file;
802 POP_REF (p, &ref_file);
803 CHECK_REF (p, ref_file, M_REF_FILE);
804 file = FILE_DEREF (&ref_file);
805 CHECK_INIT (p, INITIALISED (file), M_FILE);
806 PUSH_VALUE (p, COMPRESS (&CHANNEL (file)), A68G_BOOL);
807 }
808
809 //! @brief PROC (REF FILE) BOOL draw possible
810
811 void genie_draw_possible (NODE_T * p)
812 {
813 A68G_REF ref_file;
814 POP_REF (p, &ref_file);
815 CHECK_REF (p, ref_file, M_REF_FILE);
816 A68G_FILE *file = FILE_DEREF (&ref_file);
817 CHECK_INIT (p, INITIALISED (file), M_FILE);
818 PUSH_VALUE (p, DRAW (&CHANNEL (file)), A68G_BOOL);
819 }
820
821 //! @brief PROC (REF FILE, STRING, CHANNEL) INT open
822
823 void genie_open (NODE_T * p)
824 {
825 A68G_CHANNEL channel;
826 POP_OBJECT (p, &channel, A68G_CHANNEL);
827 A68G_REF ref_iden;
828 POP_REF (p, &ref_iden);
829 CHECK_REF (p, ref_iden, M_REF_STRING);
830 A68G_REF ref_file;
831 POP_REF (p, &ref_file);
832 CHECK_REF (p, ref_file, M_REF_FILE);
833 A68G_FILE *file = FILE_DEREF (&ref_file);
834 STATUS (file) = INIT_MASK;
835 FILE_ENTRY (file) = -1;
836 CHANNEL (file) = channel;
837 OPENED (file) = A68G_TRUE;
838 APPEND (file) = A68G_FALSE;
839 OPEN_EXCLUSIVE (file) = A68G_FALSE;
840 READ_MOOD (file) = A68G_FALSE;
841 WRITE_MOOD (file) = A68G_FALSE;
842 CHAR_MOOD (file) = A68G_FALSE;
843 DRAW_MOOD (file) = A68G_FALSE;
844 TMP_FILE (file) = A68G_FALSE;
845 size_t size = a68g_string_size (p, ref_iden);
846 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
847 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
848 }
849 IDENTIFICATION (file) = heap_generator (p, M_C_STRING, 1 + size);
850 BLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
851 ASSERT (a_to_c_string (p, DEREF (char, &IDENTIFICATION (file)), ref_iden) != NO_TEXT);
852 TERMINATOR (file) = nil_ref;
853 FORMAT (file) = nil_format;
854 FD (file) = A68G_NO_FILE;
855 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
856 UNBLOCK_GC_HANDLE (DEREF (A68G_REF, &STRING (file)));
857 }
858 STRING (file) = nil_ref;
859 STRPOS (file) = 0;
860 DEVICE_MADE (&DEVICE (file)) = A68G_FALSE;
861 STREAM (&DEVICE (file)) = NO_STREAM;
862 set_default_event_procedures (file);
863 {
864 struct stat status;
865 if (stat (DEREF (char, &IDENTIFICATION (file)), &status) == 0) {
866 PUSH_VALUE (p, (S_ISREG (ST_MODE (&status)) != 0 ? 0 : ENOENT), A68G_INT);
867 } else {
868 PUSH_VALUE (p, errno, A68G_INT);
869 }
870 errno = 0;
871 }
872 }
873
874 //! @brief PROC (REF FILE, STRING, CHANNEL) INT append
875
876 void genie_append (NODE_T * p)
877 {
878 A68G_CHANNEL channel;
879 POP_OBJECT (p, &channel, A68G_CHANNEL);
880 A68G_REF ref_iden;
881 POP_REF (p, &ref_iden);
882 CHECK_REF (p, ref_iden, M_REF_STRING);
883 A68G_REF ref_file;
884 POP_REF (p, &ref_file);
885 CHECK_REF (p, ref_file, M_REF_FILE);
886 A68G_FILE *file = FILE_DEREF (&ref_file);
887 STATUS (file) = INIT_MASK;
888 FILE_ENTRY (file) = -1;
889 CHANNEL (file) = channel;
890 OPENED (file) = A68G_TRUE;
891 APPEND (file) = A68G_TRUE;
892 OPEN_EXCLUSIVE (file) = A68G_FALSE;
893 READ_MOOD (file) = A68G_FALSE;
894 WRITE_MOOD (file) = A68G_FALSE;
895 CHAR_MOOD (file) = A68G_FALSE;
896 DRAW_MOOD (file) = A68G_FALSE;
897 TMP_FILE (file) = A68G_FALSE;
898 size_t size = a68g_string_size (p, ref_iden);
899 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
900 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
901 }
902 IDENTIFICATION (file) = heap_generator (p, M_C_STRING, 1 + size);
903 BLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
904 ASSERT (a_to_c_string (p, DEREF (char, &IDENTIFICATION (file)), ref_iden) != NO_TEXT);
905 TERMINATOR (file) = nil_ref;
906 FORMAT (file) = nil_format;
907 FD (file) = A68G_NO_FILE;
908 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
909 UNBLOCK_GC_HANDLE (DEREF (A68G_REF, &STRING (file)));
910 }
911 STRING (file) = nil_ref;
912 STRPOS (file) = 0;
913 DEVICE_MADE (&DEVICE (file)) = A68G_FALSE;
914 STREAM (&DEVICE (file)) = NO_STREAM;
915 set_default_event_procedures (file);
916 {
917 struct stat status;
918 if (stat (DEREF (char, &IDENTIFICATION (file)), &status) == 0) {
919 PUSH_VALUE (p, (S_ISREG (ST_MODE (&status)) != 0 ? 0 : ENOENT), A68G_INT);
920 } else {
921 PUSH_VALUE (p, errno, A68G_INT);
922 }
923 errno = 0;
924 }
925 }
926
927 //! @brief PROC (REF FILE, STRING, CHANNEL) INT establish
928
929 void genie_establish (NODE_T * p)
930 {
931 A68G_CHANNEL channel;
932 POP_OBJECT (p, &channel, A68G_CHANNEL);
933 A68G_REF ref_iden;
934 POP_REF (p, &ref_iden);
935 CHECK_REF (p, ref_iden, M_REF_STRING);
936 A68G_REF ref_file;
937 POP_REF (p, &ref_file);
938 CHECK_REF (p, ref_file, M_REF_FILE);
939 A68G_FILE *file = FILE_DEREF (&ref_file);
940 STATUS (file) = INIT_MASK;
941 FILE_ENTRY (file) = -1;
942 CHANNEL (file) = channel;
943 OPENED (file) = A68G_TRUE;
944 APPEND (file) = A68G_FALSE;
945 OPEN_EXCLUSIVE (file) = A68G_TRUE;
946 READ_MOOD (file) = A68G_FALSE;
947 WRITE_MOOD (file) = A68G_FALSE;
948 CHAR_MOOD (file) = A68G_FALSE;
949 DRAW_MOOD (file) = A68G_FALSE;
950 TMP_FILE (file) = A68G_FALSE;
951 if (!PUT (&CHANNEL (file))) {
952 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "putting");
953 exit_genie (p, A68G_RUNTIME_ERROR);
954 }
955 size_t size = a68g_string_size (p, ref_iden);
956 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
957 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
958 }
959 IDENTIFICATION (file) = heap_generator (p, M_C_STRING, 1 + size);
960 BLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
961 ASSERT (a_to_c_string (p, DEREF (char, &IDENTIFICATION (file)), ref_iden) != NO_TEXT);
962 TERMINATOR (file) = nil_ref;
963 FORMAT (file) = nil_format;
964 FD (file) = A68G_NO_FILE;
965 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
966 UNBLOCK_GC_HANDLE (DEREF (A68G_REF, &STRING (file)));
967 }
968 STRING (file) = nil_ref;
969 STRPOS (file) = 0;
970 DEVICE_MADE (&DEVICE (file)) = A68G_FALSE;
971 STREAM (&DEVICE (file)) = NO_STREAM;
972 set_default_event_procedures (file);
973 PUSH_VALUE (p, 0, A68G_INT);
974 }
975
976 //! @brief PROC (REF FILE, CHANNEL) INT create
977
978 void genie_create (NODE_T * p)
979 {
980 A68G_CHANNEL channel;
981 POP_OBJECT (p, &channel, A68G_CHANNEL);
982 A68G_REF ref_file;
983 POP_REF (p, &ref_file);
984 CHECK_REF (p, ref_file, M_REF_FILE);
985 A68G_FILE *file = FILE_DEREF (&ref_file);
986 STATUS (file) = INIT_MASK;
987 FILE_ENTRY (file) = -1;
988 CHANNEL (file) = channel;
989 OPENED (file) = A68G_TRUE;
990 APPEND (file) = A68G_FALSE;
991 OPEN_EXCLUSIVE (file) = A68G_FALSE;
992 READ_MOOD (file) = A68G_FALSE;
993 WRITE_MOOD (file) = A68G_FALSE;
994 CHAR_MOOD (file) = A68G_FALSE;
995 DRAW_MOOD (file) = A68G_FALSE;
996 TMP_FILE (file) = A68G_TRUE;
997 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
998 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
999 }
1000 IDENTIFICATION (file) = nil_ref;
1001 TERMINATOR (file) = nil_ref;
1002 FORMAT (file) = nil_format;
1003 FD (file) = A68G_NO_FILE;
1004 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
1005 UNBLOCK_GC_HANDLE (DEREF (A68G_REF, &STRING (file)));
1006 }
1007 STRING (file) = nil_ref;
1008 STRPOS (file) = 0;
1009 DEVICE_MADE (&DEVICE (file)) = A68G_FALSE;
1010 STREAM (&DEVICE (file)) = NO_STREAM;
1011 set_default_event_procedures (file);
1012 PUSH_VALUE (p, 0, A68G_INT);
1013 }
1014
1015 //! @brief PROC (REF FILE, REF STRING) VOID associate
1016
1017 void genie_associate (NODE_T * p)
1018 {
1019 A68G_REF ref_string;
1020 POP_REF (p, &ref_string);
1021 CHECK_REF (p, ref_string, M_REF_STRING);
1022 A68G_REF ref_file;
1023 POP_REF (p, &ref_file);
1024 CHECK_REF (p, ref_file, M_REF_FILE);
1025 if (IS_IN_HEAP (&ref_file) && !IS_IN_HEAP (&ref_string)) {
1026 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_SCOPE_DYNAMIC_1, M_REF_STRING);
1027 exit_genie (p, A68G_RUNTIME_ERROR);
1028 } else if (IS_IN_FRAME (&ref_file) && IS_IN_FRAME (&ref_string)) {
1029 if (REF_SCOPE (&ref_string) > REF_SCOPE (&ref_file)) {
1030 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_SCOPE_DYNAMIC_1, M_REF_STRING);
1031 exit_genie (p, A68G_RUNTIME_ERROR);
1032 }
1033 }
1034 A68G_FILE *file = FILE_DEREF (&ref_file);
1035 STATUS (file) = INIT_MASK;
1036 FILE_ENTRY (file) = -1;
1037 CHANNEL (file) = A68G (associate_channel);
1038 OPENED (file) = A68G_TRUE;
1039 APPEND (file) = A68G_FALSE;
1040 OPEN_EXCLUSIVE (file) = A68G_FALSE;
1041 READ_MOOD (file) = A68G_FALSE;
1042 WRITE_MOOD (file) = A68G_FALSE;
1043 CHAR_MOOD (file) = A68G_FALSE;
1044 DRAW_MOOD (file) = A68G_FALSE;
1045 TMP_FILE (file) = A68G_FALSE;
1046 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
1047 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
1048 }
1049 IDENTIFICATION (file) = nil_ref;
1050 TERMINATOR (file) = nil_ref;
1051 FORMAT (file) = nil_format;
1052 FD (file) = A68G_NO_FILE;
1053 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
1054 UNBLOCK_GC_HANDLE (DEREF (A68G_REF, &STRING (file)));
1055 }
1056 STRING (file) = ref_string;
1057 BLOCK_GC_HANDLE ((A68G_REF *) (&(STRING (file))));
1058 STRPOS (file) = 0;
1059 DEVICE_MADE (&DEVICE (file)) = A68G_FALSE;
1060 STREAM (&DEVICE (file)) = NO_STREAM;
1061 set_default_event_procedures (file);
1062 }
1063
1064 //! @brief PROC (REF FILE) VOID close
1065
1066 void genie_close (NODE_T * p)
1067 {
1068 A68G_REF ref_file;
1069 POP_REF (p, &ref_file);
1070 CHECK_REF (p, ref_file, M_REF_FILE);
1071 A68G_FILE *file = FILE_DEREF (&ref_file);
1072 CHECK_INIT (p, INITIALISED (file), M_FILE);
1073 if (!OPENED (file) || (!READ_MOOD (file) && !WRITE_MOOD (file) && !DRAW_MOOD (file))) {
1074 return;
1075 }
1076 DEVICE_MADE (&DEVICE (file)) = A68G_FALSE;
1077 #if defined (HAVE_GNU_PLOTUTILS)
1078 if (DEVICE_OPENED (&DEVICE (file))) {
1079 ASSERT (close_device (p, file) == A68G_TRUE);
1080 STREAM (&DEVICE (file)) = NO_STREAM;
1081 return;
1082 }
1083 #endif
1084 FD (file) = A68G_NO_FILE;
1085 OPENED (file) = A68G_FALSE;
1086 unblock_transput_buffer (TRANSPUT_BUFFER (file));
1087 set_default_event_procedures (file);
1088 free_file_entry (p, FILE_ENTRY (file));
1089 }
1090
1091 //! @brief PROC (REF FILE) VOID lock
1092
1093 void genie_lock (NODE_T * p)
1094 {
1095 A68G_REF ref_file;
1096 POP_REF (p, &ref_file);
1097 CHECK_REF (p, ref_file, M_REF_FILE);
1098 A68G_FILE *file = FILE_DEREF (&ref_file);
1099 CHECK_INIT (p, INITIALISED (file), M_FILE);
1100 if (!OPENED (file) || (!READ_MOOD (file) && !WRITE_MOOD (file) && !DRAW_MOOD (file))) {
1101 return;
1102 }
1103 DEVICE_MADE (&DEVICE (file)) = A68G_FALSE;
1104 #if defined (HAVE_GNU_PLOTUTILS)
1105 if (DEVICE_OPENED (&DEVICE (file))) {
1106 ASSERT (close_device (p, file) == A68G_TRUE);
1107 STREAM (&DEVICE (file)) = NO_STREAM;
1108 return;
1109 }
1110 #endif
1111 #if defined (BUILD_UNIX)
1112 errno = 0;
1113 ASSERT (fchmod (FD (file), (mode_t) 0x0) != -1);
1114 #endif
1115 if (FD (file) != A68G_NO_FILE && close (FD (file)) == -1) {
1116 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_LOCK);
1117 exit_genie (p, A68G_RUNTIME_ERROR);
1118 } else {
1119 FD (file) = A68G_NO_FILE;
1120 OPENED (file) = A68G_FALSE;
1121 unblock_transput_buffer (TRANSPUT_BUFFER (file));
1122 set_default_event_procedures (file);
1123 }
1124 free_file_entry (p, FILE_ENTRY (file));
1125 }
1126
1127 //! @brief PROC (REF FILE) VOID erase
1128
1129 void genie_erase (NODE_T * p)
1130 {
1131 A68G_REF ref_file;
1132 POP_REF (p, &ref_file);
1133 CHECK_REF (p, ref_file, M_REF_FILE);
1134 A68G_FILE *file = FILE_DEREF (&ref_file);
1135 CHECK_INIT (p, INITIALISED (file), M_FILE);
1136 if (!OPENED (file) || (!READ_MOOD (file) && !WRITE_MOOD (file) && !DRAW_MOOD (file))) {
1137 return;
1138 }
1139 DEVICE_MADE (&DEVICE (file)) = A68G_FALSE;
1140 #if defined (HAVE_GNU_PLOTUTILS)
1141 if (DEVICE_OPENED (&DEVICE (file))) {
1142 ASSERT (close_device (p, file) == A68G_TRUE);
1143 STREAM (&DEVICE (file)) = NO_STREAM;
1144 return;
1145 }
1146 #endif
1147 if (FD (file) != A68G_NO_FILE && close (FD (file)) == -1) {
1148 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_SCRATCH);
1149 exit_genie (p, A68G_RUNTIME_ERROR);
1150 } else {
1151 unblock_transput_buffer (TRANSPUT_BUFFER (file));
1152 set_default_event_procedures (file);
1153 }
1154 // Remove the file.
1155 if (!IS_NIL (IDENTIFICATION (file))) {
1156 char *filename;
1157 CHECK_INIT (p, INITIALISED (&(IDENTIFICATION (file))), M_ROWS);
1158 filename = DEREF (char, &IDENTIFICATION (file));
1159 if (remove (filename) != 0) {
1160 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_SCRATCH);
1161 exit_genie (p, A68G_RUNTIME_ERROR);
1162 }
1163 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
1164 IDENTIFICATION (file) = nil_ref;
1165 }
1166 init_file_entry (FILE_ENTRY (file));
1167 }
1168
1169 //! @brief PROC (REF FILE) VOID backspace
1170
1171 void genie_backspace (NODE_T * p)
1172 {
1173 ADDR_T pop_sp = A68G_SP;
1174 PUSH_VALUE (p, -1, A68G_INT);
1175 genie_set (p);
1176 A68G_SP = pop_sp;
1177 }
1178
1179 //! @brief PROC (REF FILE, INT) INT set
1180
1181 void genie_set (NODE_T * p)
1182 {
1183 A68G_INT pos;
1184 POP_OBJECT (p, &pos, A68G_INT);
1185 A68G_REF ref_file;
1186 POP_REF (p, &ref_file);
1187 CHECK_REF (p, ref_file, M_REF_FILE);
1188 A68G_FILE *file = FILE_DEREF (&ref_file);
1189 CHECK_INIT (p, INITIALISED (file), M_FILE);
1190 if (!OPENED (file)) {
1191 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1192 exit_genie (p, A68G_RUNTIME_ERROR);
1193 }
1194 if (!SET (&CHANNEL (file))) {
1195 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_CANT_SET);
1196 exit_genie (p, A68G_RUNTIME_ERROR);
1197 }
1198 if (!IS_NIL (STRING (file))) {
1199 A68G_REF z = *DEREF (A68G_REF, &STRING (file));
1200 // Circumvent buffering problems.
1201 STRPOS (file) -= get_transput_buffer_index (TRANSPUT_BUFFER (file));
1202 ASSERT (STRPOS (file) > 0);
1203 reset_transput_buffer (TRANSPUT_BUFFER (file));
1204 // Now set.
1205 CHECK_INT_ADDITION (p, STRPOS (file), VALUE (&pos));
1206 STRPOS (file) += VALUE (&pos);
1207 A68G_ARRAY *arr; A68G_TUPLE *tup;
1208 GET_DESCRIPTOR (arr, tup, &z);
1209 size_t size = ROW_SIZE (tup);
1210 if (size == 0 || STRPOS (file) < 0 || STRPOS (file) >= size) {
1211 A68G_BOOL res;
1212 on_event_handler (p, FILE_END_MENDED (FILE_DEREF (&ref_file)), ref_file);
1213 POP_OBJECT (p, &res, A68G_BOOL);
1214 if (VALUE (&res) == A68G_FALSE) {
1215 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_ENDED);
1216 exit_genie (p, A68G_RUNTIME_ERROR);
1217 }
1218 }
1219 PUSH_VALUE (p, STRPOS (file), A68G_INT);
1220 } else if (FD (file) == A68G_NO_FILE) {
1221 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_RESET);
1222 exit_genie (p, A68G_RUNTIME_ERROR);
1223 } else {
1224 errno = 0;
1225 a68g_off_t curpos = (a68g_off_t) lseek (FD (file), 0, SEEK_CUR);
1226 a68g_off_t maxpos = (a68g_off_t) lseek (FD (file), 0, SEEK_END);
1227 // Circumvent buffering problems.
1228 int reserve = get_transput_buffer_index (TRANSPUT_BUFFER (file));
1229 curpos -= (a68g_off_t) reserve;
1230 a68g_off_t res = (a68g_off_t) lseek (FD (file), -reserve, SEEK_CUR);
1231 ASSERT (res != (a68g_off_t) -1 && errno == 0);
1232 reset_transput_buffer (TRANSPUT_BUFFER (file));
1233 // Now set.
1234 CHECK_INT_ADDITION (p, curpos, VALUE (&pos));
1235 curpos += VALUE (&pos);
1236 if (curpos < 0 || curpos >= maxpos) {
1237 A68G_BOOL ret;
1238 on_event_handler (p, FILE_END_MENDED (FILE_DEREF (&ref_file)), ref_file);
1239 POP_OBJECT (p, &ret, A68G_BOOL);
1240 if (VALUE (&ret) == A68G_FALSE) {
1241 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_ENDED);
1242 exit_genie (p, A68G_RUNTIME_ERROR);
1243 }
1244 PUSH_VALUE (p, (INT_T) lseek (FD (file), 0, SEEK_CUR), A68G_INT);
1245 } else {
1246 res = lseek (FD (file), curpos, SEEK_SET);
1247 if (res == -1 || errno != 0) {
1248 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_SET);
1249 exit_genie (p, A68G_RUNTIME_ERROR);
1250 }
1251 PUSH_VALUE (p, (int) res, A68G_INT);
1252 }
1253 }
1254 }
1255
1256 //! @brief PROC (REF FILE) VOID reset
1257
1258 void genie_reset (NODE_T * p)
1259 {
1260 A68G_REF ref_file;
1261 POP_REF (p, &ref_file);
1262 CHECK_REF (p, ref_file, M_REF_FILE);
1263 A68G_FILE *file = FILE_DEREF (&ref_file);
1264 CHECK_INIT (p, INITIALISED (file), M_FILE);
1265 if (!OPENED (file)) {
1266 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1267 exit_genie (p, A68G_RUNTIME_ERROR);
1268 }
1269 if (!RESET (&CHANNEL (file))) {
1270 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_CANT_RESET);
1271 exit_genie (p, A68G_RUNTIME_ERROR);
1272 }
1273 if (IS_NIL (STRING (file))) {
1274 close_file_entry (p, FILE_ENTRY (file));
1275 } else {
1276 STRPOS (file) = 0;
1277 }
1278 READ_MOOD (file) = A68G_FALSE;
1279 WRITE_MOOD (file) = A68G_FALSE;
1280 CHAR_MOOD (file) = A68G_FALSE;
1281 DRAW_MOOD (file) = A68G_FALSE;
1282 FD (file) = A68G_NO_FILE;
1283 // set_default_event_procedures (file);.
1284 }
1285
1286 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on file end
1287
1288 void genie_on_file_end (NODE_T * p)
1289 {
1290 A68G_PROCEDURE z;
1291 POP_PROCEDURE (p, &z);
1292 A68G_REF ref_file;
1293 POP_REF (p, &ref_file);
1294 CHECK_REF (p, ref_file, M_REF_FILE);
1295 A68G_FILE *file = FILE_DEREF (&ref_file);
1296 CHECK_INIT (p, INITIALISED (file), M_FILE);
1297 FILE_END_MENDED (file) = z;
1298 }
1299
1300 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on page end
1301
1302 void genie_on_page_end (NODE_T * p)
1303 {
1304 A68G_PROCEDURE z;
1305 POP_PROCEDURE (p, &z);
1306 A68G_REF ref_file;
1307 POP_REF (p, &ref_file);
1308 CHECK_REF (p, ref_file, M_REF_FILE);
1309 A68G_FILE *file = FILE_DEREF (&ref_file);
1310 CHECK_INIT (p, INITIALISED (file), M_FILE);
1311 PAGE_END_MENDED (file) = z;
1312 }
1313
1314 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on line end
1315
1316 void genie_on_line_end (NODE_T * p)
1317 {
1318 A68G_PROCEDURE z;
1319 POP_PROCEDURE (p, &z);
1320 A68G_REF ref_file;
1321 POP_REF (p, &ref_file);
1322 CHECK_REF (p, ref_file, M_REF_FILE);
1323 A68G_FILE *file = FILE_DEREF (&ref_file);
1324 CHECK_INIT (p, INITIALISED (file), M_FILE);
1325 LINE_END_MENDED (file) = z;
1326 }
1327
1328 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on format end
1329
1330 void genie_on_format_end (NODE_T * p)
1331 {
1332 A68G_PROCEDURE z;
1333 POP_PROCEDURE (p, &z);
1334 A68G_REF ref_file;
1335 POP_REF (p, &ref_file);
1336 CHECK_REF (p, ref_file, M_REF_FILE);
1337 A68G_FILE *file = FILE_DEREF (&ref_file);
1338 CHECK_INIT (p, INITIALISED (file), M_FILE);
1339 FORMAT_END_MENDED (file) = z;
1340 }
1341
1342 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on format error
1343
1344 void genie_on_format_error (NODE_T * p)
1345 {
1346 A68G_PROCEDURE z;
1347 POP_PROCEDURE (p, &z);
1348 A68G_REF ref_file;
1349 POP_REF (p, &ref_file);
1350 CHECK_REF (p, ref_file, M_REF_FILE);
1351 A68G_FILE *file = FILE_DEREF (&ref_file);
1352 CHECK_INIT (p, INITIALISED (file), M_FILE);
1353 FORMAT_ERROR_MENDED (file) = z;
1354 }
1355
1356 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on value error
1357
1358 void genie_on_value_error (NODE_T * p)
1359 {
1360 A68G_PROCEDURE z;
1361 POP_PROCEDURE (p, &z);
1362 A68G_REF ref_file;
1363 POP_REF (p, &ref_file);
1364 CHECK_REF (p, ref_file, M_REF_FILE);
1365 A68G_FILE *file = FILE_DEREF (&ref_file);
1366 CHECK_INIT (p, INITIALISED (file), M_FILE);
1367 VALUE_ERROR_MENDED (file) = z;
1368 }
1369
1370 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on open error
1371
1372 void genie_on_open_error (NODE_T * p)
1373 {
1374 A68G_PROCEDURE z;
1375 POP_PROCEDURE (p, &z);
1376 A68G_REF ref_file;
1377 POP_REF (p, &ref_file);
1378 CHECK_REF (p, ref_file, M_REF_FILE);
1379 A68G_FILE *file = FILE_DEREF (&ref_file);
1380 CHECK_INIT (p, INITIALISED (file), M_FILE);
1381 OPEN_ERROR_MENDED (file) = z;
1382 }
1383
1384 //! @brief PROC (REF FILE, PROC (REF FILE) BOOL) VOID on transput error
1385
1386 void genie_on_transput_error (NODE_T * p)
1387 {
1388 A68G_PROCEDURE z;
1389 POP_PROCEDURE (p, &z);
1390 A68G_REF ref_file;
1391 POP_REF (p, &ref_file);
1392 CHECK_REF (p, ref_file, M_REF_FILE);
1393 A68G_FILE *file = FILE_DEREF (&ref_file);
1394 CHECK_INIT (p, INITIALISED (file), M_FILE);
1395 TRANSPUT_ERROR_MENDED (file) = z;
1396 }
1397
1398 //! @brief Invoke event routine.
1399
1400 void on_event_handler (NODE_T * p, A68G_PROCEDURE z, A68G_REF ref_file)
1401 {
1402 if (NODE (&(BODY (&z))) == NO_NODE) {
1403 // Default procedure.
1404 PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
1405 } else {
1406 ADDR_T pop_sp = A68G_SP, pop_fp = A68G_FP;
1407 PUSH_REF (p, ref_file);
1408 genie_call_event_routine (p, M_PROC_REF_FILE_BOOL, &z, pop_sp, pop_fp);
1409 }
1410 }
1411
1412 //! @brief Handle end-of-file event.
1413
1414 void end_of_file_error (NODE_T * p, A68G_REF ref_file)
1415 {
1416 on_event_handler (p, FILE_END_MENDED (FILE_DEREF (&ref_file)), ref_file);
1417 A68G_BOOL z;
1418 POP_OBJECT (p, &z, A68G_BOOL);
1419 if (VALUE (&z) == A68G_FALSE) {
1420 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_ENDED);
1421 exit_genie (p, A68G_RUNTIME_ERROR);
1422 }
1423 }
1424
1425 //! @brief Handle file-open-error event.
1426
1427 void open_error (NODE_T * p, A68G_REF ref_file, char *mode)
1428 {
1429 on_event_handler (p, OPEN_ERROR_MENDED (FILE_DEREF (&ref_file)), ref_file);
1430 A68G_BOOL z;
1431 POP_OBJECT (p, &z, A68G_BOOL);
1432 if (VALUE (&z) == A68G_FALSE) {
1433 CHECK_REF (p, ref_file, M_REF_FILE);
1434 A68G_FILE *file = FILE_DEREF (&ref_file);
1435 CHECK_INIT (p, INITIALISED (file), M_FILE);
1436 char *filename;
1437 if (!IS_NIL (IDENTIFICATION (file))) {
1438 filename = DEREF (char, &IDENTIFICATION (FILE_DEREF (&ref_file)));
1439 } else {
1440 filename = "(missing filename)";
1441 }
1442 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_CANNOT_OPEN_FOR, filename, mode);
1443 exit_genie (p, A68G_RUNTIME_ERROR);
1444 }
1445 }
1446
1447 //! @brief Handle value error event.
1448
1449 void value_error (NODE_T * p, MOID_T * m, A68G_REF ref_file)
1450 {
1451 A68G_FILE *f = FILE_DEREF (&ref_file);
1452 if (END_OF_FILE (f)) {
1453 end_of_file_error (p, ref_file);
1454 } else {
1455 on_event_handler (p, VALUE_ERROR_MENDED (f), ref_file);
1456 A68G_BOOL z;
1457 POP_OBJECT (p, &z, A68G_BOOL);
1458 if (VALUE (&z) == A68G_FALSE) {
1459 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_TRANSPUT, m);
1460 exit_genie (p, A68G_RUNTIME_ERROR);
1461 }
1462 }
1463 }
1464
1465 //! @brief Handle value_error event.
1466
1467 void value_sign_error (NODE_T * p, MOID_T * m, A68G_REF ref_file)
1468 {
1469 A68G_FILE *f = FILE_DEREF (&ref_file);
1470 if (END_OF_FILE (f)) {
1471 end_of_file_error (p, ref_file);
1472 } else {
1473 on_event_handler (p, VALUE_ERROR_MENDED (f), ref_file);
1474 A68G_BOOL z;
1475 POP_OBJECT (p, &z, A68G_BOOL);
1476 if (VALUE (&z) == A68G_FALSE) {
1477 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_TRANSPUT_SIGN, m);
1478 exit_genie (p, A68G_RUNTIME_ERROR);
1479 }
1480 }
1481 }
1482
1483 //! @brief Handle transput-error event.
1484
1485 void transput_error (NODE_T * p, A68G_REF ref_file, MOID_T * m)
1486 {
1487 on_event_handler (p, TRANSPUT_ERROR_MENDED (FILE_DEREF (&ref_file)), ref_file);
1488 A68G_BOOL z;
1489 POP_OBJECT (p, &z, A68G_BOOL);
1490 if (VALUE (&z) == A68G_FALSE) {
1491 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_TRANSPUT, m);
1492 exit_genie (p, A68G_RUNTIME_ERROR);
1493 }
1494 }
1495
1496 // Implementation of put and get.
1497
1498 //! @brief Get next char from file.
1499
1500 int char_scanner (A68G_FILE * f)
1501 {
1502 if (FD (f) == A68G_STDIN && A68G (stdin_is_raw)) {
1503 return peek_char (A68G_PEEK_READ);
1504 } else if (get_transput_buffer_index (TRANSPUT_BUFFER (f)) > 0) {
1505 // There are buffered characters.
1506 END_OF_FILE (f) = A68G_FALSE;
1507 return pop_char_transput_buffer (TRANSPUT_BUFFER (f));
1508 } else if (IS_NIL (STRING (f))) {
1509 // Fetch next CHAR from the FILE.
1510 char ch;
1511 ssize_t chars_read = io_read_conv (FD (f), &ch, 1);
1512 if (chars_read == 1) {
1513 END_OF_FILE (f) = A68G_FALSE;
1514 return ch;
1515 } else {
1516 END_OF_FILE (f) = A68G_TRUE;
1517 return EOF_CHAR;
1518 }
1519 } else {
1520 // File is associated with a STRING. Give next CHAR.
1521 // When we're outside the STRING give EOF_CHAR.
1522 A68G_REF z = *DEREF (A68G_REF, &STRING (f)); A68G_ARRAY *arr; A68G_TUPLE *tup;
1523 GET_DESCRIPTOR (arr, tup, &z);
1524 int k = STRPOS (f) + LWB (tup);
1525 if (ROW_SIZE (tup) <= 0 || k < LWB (tup) || k > UPB (tup)) {
1526 END_OF_FILE (f) = A68G_TRUE;
1527 return EOF_CHAR;
1528 } else {
1529 BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
1530 A68G_CHAR *ch = (A68G_CHAR *) & (base[INDEX_1_DIM (arr, tup, k)]);
1531 STRPOS (f)++;
1532 return VALUE (ch);
1533 }
1534 }
1535 }
1536
1537 //! @brief Push back look-ahead character to file.
1538
1539 void unchar_scanner (NODE_T * p, A68G_FILE * f, char ch)
1540 {
1541 END_OF_FILE (f) = A68G_FALSE;
1542 plusab_transput_buffer (p, TRANSPUT_BUFFER (f), ch);
1543 }
1544
1545 //! @brief PROC (REF FILE) BOOL eof
1546
1547 void genie_eof (NODE_T * p)
1548 {
1549 A68G_REF ref_file;
1550 POP_REF (p, &ref_file);
1551 CHECK_REF (p, ref_file, M_REF_FILE);
1552 A68G_FILE *file = FILE_DEREF (&ref_file);
1553 CHECK_INIT (p, INITIALISED (file), M_FILE);
1554 if (!OPENED (file)) {
1555 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1556 exit_genie (p, A68G_RUNTIME_ERROR);
1557 }
1558 if (DRAW_MOOD (file)) {
1559 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1560 exit_genie (p, A68G_RUNTIME_ERROR);
1561 }
1562 if (WRITE_MOOD (file)) {
1563 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
1564 exit_genie (p, A68G_RUNTIME_ERROR);
1565 } else if (READ_MOOD (file)) {
1566 int ch = char_scanner (file);
1567 PUSH_VALUE (p, (BOOL_T) ((ch == EOF_CHAR || END_OF_FILE (file)) ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1568 unchar_scanner (p, file, (char) ch);
1569 } else {
1570 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1571 exit_genie (p, A68G_RUNTIME_ERROR);
1572 }
1573 }
1574
1575 //! @brief PROC (REF FILE) BOOL eoln
1576
1577 void genie_eoln (NODE_T * p)
1578 {
1579 A68G_REF ref_file;
1580 POP_REF (p, &ref_file);
1581 CHECK_REF (p, ref_file, M_REF_FILE);
1582 A68G_FILE *file = FILE_DEREF (&ref_file);
1583 CHECK_INIT (p, INITIALISED (file), M_FILE);
1584 if (!OPENED (file)) {
1585 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1586 exit_genie (p, A68G_RUNTIME_ERROR);
1587 }
1588 if (DRAW_MOOD (file)) {
1589 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1590 exit_genie (p, A68G_RUNTIME_ERROR);
1591 }
1592 if (WRITE_MOOD (file)) {
1593 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
1594 exit_genie (p, A68G_RUNTIME_ERROR);
1595 } else if (READ_MOOD (file)) {
1596 int ch = char_scanner (file);
1597 if (END_OF_FILE (file)) {
1598 end_of_file_error (p, ref_file);
1599 }
1600 PUSH_VALUE (p, (BOOL_T) (ch == NEWLINE_CHAR ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1601 unchar_scanner (p, file, (char) ch);
1602 } else {
1603 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1604 exit_genie (p, A68G_RUNTIME_ERROR);
1605 }
1606 }
1607
1608 //! @brief PROC (REF FILE) VOID new line
1609
1610 void genie_new_line (NODE_T * p)
1611 {
1612 A68G_REF ref_file;
1613 POP_REF (p, &ref_file);
1614 CHECK_REF (p, ref_file, M_REF_FILE);
1615 A68G_FILE *file = FILE_DEREF (&ref_file);
1616 CHECK_INIT (p, INITIALISED (file), M_FILE);
1617 if (!OPENED (file)) {
1618 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1619 exit_genie (p, A68G_RUNTIME_ERROR);
1620 }
1621 if (DRAW_MOOD (file)) {
1622 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1623 exit_genie (p, A68G_RUNTIME_ERROR);
1624 }
1625 if (WRITE_MOOD (file)) {
1626 on_event_handler (p, LINE_END_MENDED (file), ref_file);
1627 if (IS_NIL (STRING (file))) {
1628 WRITE (FD (file), NEWLINE_STRING);
1629 } else {
1630 add_c_string_to_a_string (p, STRING (file), NEWLINE_STRING);
1631 }
1632 } else if (READ_MOOD (file)) {
1633 BOOL_T siga = A68G_TRUE;
1634 while (siga) {
1635 int ch;
1636 if (END_OF_FILE (file)) {
1637 end_of_file_error (p, ref_file);
1638 }
1639 ch = char_scanner (file);
1640 siga = (BOOL_T) ((ch != NEWLINE_CHAR) && (ch != EOF_CHAR) && !END_OF_FILE (file));
1641 }
1642 } else {
1643 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1644 exit_genie (p, A68G_RUNTIME_ERROR);
1645 }
1646 }
1647
1648 //! @brief PROC (REF FILE) VOID new page
1649
1650 void genie_new_page (NODE_T * p)
1651 {
1652 A68G_REF ref_file;
1653 POP_REF (p, &ref_file);
1654 CHECK_REF (p, ref_file, M_REF_FILE);
1655 A68G_FILE *file = FILE_DEREF (&ref_file);
1656 CHECK_INIT (p, INITIALISED (file), M_FILE);
1657 if (!OPENED (file)) {
1658 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1659 exit_genie (p, A68G_RUNTIME_ERROR);
1660 }
1661 if (DRAW_MOOD (file)) {
1662 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1663 exit_genie (p, A68G_RUNTIME_ERROR);
1664 }
1665 if (WRITE_MOOD (file)) {
1666 on_event_handler (p, PAGE_END_MENDED (file), ref_file);
1667 if (IS_NIL (STRING (file))) {
1668 WRITE (FD (file), "\f");
1669 } else {
1670 add_c_string_to_a_string (p, STRING (file), "\f");
1671 }
1672 } else if (READ_MOOD (file)) {
1673 BOOL_T siga = A68G_TRUE;
1674 while (siga) {
1675 if (END_OF_FILE (file)) {
1676 end_of_file_error (p, ref_file);
1677 }
1678 int ch = char_scanner (file);
1679 siga = (BOOL_T) ((ch != FORMFEED_CHAR) && (ch != EOF_CHAR) && !END_OF_FILE (file));
1680 }
1681 } else {
1682 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1683 exit_genie (p, A68G_RUNTIME_ERROR);
1684 }
1685 }
1686
1687 //! @brief PROC (REF FILE) VOID space
1688
1689 void genie_space (NODE_T * p)
1690 {
1691 A68G_REF ref_file;
1692 POP_REF (p, &ref_file);
1693 CHECK_REF (p, ref_file, M_REF_FILE);
1694 A68G_FILE *file = FILE_DEREF (&ref_file);
1695 CHECK_INIT (p, INITIALISED (file), M_FILE);
1696 if (!OPENED (file)) {
1697 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1698 exit_genie (p, A68G_RUNTIME_ERROR);
1699 }
1700 if (DRAW_MOOD (file)) {
1701 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1702 exit_genie (p, A68G_RUNTIME_ERROR);
1703 }
1704 if (WRITE_MOOD (file)) {
1705 WRITE (FD (file), " ");
1706 } else if (READ_MOOD (file)) {
1707 if (!END_OF_FILE (file)) {
1708 (void) char_scanner (file);
1709 }
1710 } else {
1711 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "undetermined");
1712 exit_genie (p, A68G_RUNTIME_ERROR);
1713 }
1714 }
1715
1716 //! @brief PROC (REF FILE) VOID raw
1717
1718 void genie_kbd_raw (NODE_T * p)
1719 {
1720 A68G_REF ref_file;
1721 POP_REF (p, &ref_file);
1722 CHECK_REF (p, ref_file, M_REF_FILE);
1723 A68G_FILE *file = FILE_DEREF (&ref_file);
1724 CHECK_INIT (p, INITIALISED (file), M_FILE);
1725 if (!OPENED (file)) {
1726 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1727 exit_genie (p, A68G_RUNTIME_ERROR);
1728 }
1729 if (DRAW_MOOD (file)) {
1730 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1731 exit_genie (p, A68G_RUNTIME_ERROR);
1732 }
1733 if (WRITE_MOOD (file)) {
1734 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
1735 exit_genie (p, A68G_RUNTIME_ERROR);
1736 }
1737 if (FD (file) == A68G_STDIN) {
1738 READ_MOOD (file) = A68G_TRUE;
1739 peek_char (A68G_PEEK_INIT);
1740 }
1741 }
1742
1743 //! @brief PROC (REF FILE) VOID cooked
1744
1745 void genie_kbd_cooked (NODE_T * p)
1746 {
1747 A68G_REF ref_file;
1748 POP_REF (p, &ref_file);
1749 CHECK_REF (p, ref_file, M_REF_FILE);
1750 A68G_FILE *file = FILE_DEREF (&ref_file);
1751 CHECK_INIT (p, INITIALISED (file), M_FILE);
1752 if (!OPENED (file)) {
1753 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1754 exit_genie (p, A68G_RUNTIME_ERROR);
1755 }
1756 if (DRAW_MOOD (file)) {
1757 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1758 exit_genie (p, A68G_RUNTIME_ERROR);
1759 }
1760 if (WRITE_MOOD (file)) {
1761 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
1762 exit_genie (p, A68G_RUNTIME_ERROR);
1763 }
1764 if (READ_MOOD (file)) {
1765 if (FD (file) == A68G_STDIN) {
1766 peek_char (A68G_PEEK_RESET);
1767 }
1768 }
1769 }
|
© 2002-2026 J.M. van der Veer (jmvdveer@xs4all.nl)
|