|
|
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@algol68genie.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 }
© 2001-2026 J.M. van der Veer
jmvdveer@algol68genie.nl