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