transput-unformatted.c

     
   1  //! @file transput-unformatted.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-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  //! Unformatted transput.
  25  
  26  #include "a68g.h"
  27  #include "a68g-genie.h"
  28  #include "a68g-prelude.h"
  29  #include "a68g-mp.h"
  30  #include "a68g-double.h"
  31  #include "a68g-conversion.h"
  32  #include "a68g-transput.h"
  33  
  34  
  35  //! @brief Skip new-lines and form-feeds.
  36  
  37  void skip_nl_ff (NODE_T * p, int *ch, A68G_REF ref_file)
  38  {
  39    A68G_FILE *f = FILE_DEREF (&ref_file);
  40    while ((*ch) != EOF_CHAR && IS_NL_FF (*ch)) {
  41      A68G_BOOL *z = (A68G_BOOL *) STACK_TOP;
  42      ADDR_T pop_sp = A68G_SP;
  43      unchar_scanner (p, f, (char) (*ch));
  44      if (*ch == NEWLINE_CHAR) {
  45        on_event_handler (p, LINE_END_MENDED (f), ref_file);
  46        A68G_SP = pop_sp;
  47        if (VALUE (z) == A68G_FALSE) {
  48          PUSH_REF (p, ref_file);
  49          genie_new_line (p);
  50        }
  51      } else if (*ch == FORMFEED_CHAR) {
  52        on_event_handler (p, PAGE_END_MENDED (f), ref_file);
  53        A68G_SP = pop_sp;
  54        if (VALUE (z) == A68G_FALSE) {
  55          PUSH_REF (p, ref_file);
  56          genie_new_page (p);
  57        }
  58      }
  59      (*ch) = char_scanner (f);
  60    }
  61  }
  62  
  63  
  64  //! @brief Scan an int from file.
  65  
  66  void scan_integer (NODE_T * p, A68G_REF ref_file)
  67  {
  68    A68G_FILE *f = FILE_DEREF (&ref_file);
  69    reset_transput_buffer (INPUT_BUFFER);
  70    int ch = char_scanner (f);
  71    while (ch != EOF_CHAR && (IS_SPACE (ch) || IS_NL_FF (ch))) {
  72      if (IS_NL_FF (ch)) {
  73        skip_nl_ff (p, &ch, ref_file);
  74      } else {
  75        ch = char_scanner (f);
  76      }
  77    }
  78    if (ch != EOF_CHAR && (ch == '+' || ch == '-')) {
  79      plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
  80      ch = char_scanner (f);
  81    }
  82    while (ch != EOF_CHAR && IS_DIGIT (ch)) {
  83      plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
  84      ch = char_scanner (f);
  85    }
  86    if (ch != EOF_CHAR) {
  87      unchar_scanner (p, f, (char) ch);
  88    }
  89  }
  90  
  91  
  92  //! @brief Scan a real from file.
  93  
  94  void scan_real (NODE_T * p, A68G_REF ref_file)
  95  {
  96    A68G_FILE *f = FILE_DEREF (&ref_file);
  97    char x_e = EXPONENT_CHAR;
  98    reset_transput_buffer (INPUT_BUFFER);
  99    int ch = char_scanner (f);
 100    while (ch != EOF_CHAR && (IS_SPACE (ch) || IS_NL_FF (ch))) {
 101      if (IS_NL_FF (ch)) {
 102        skip_nl_ff (p, &ch, ref_file);
 103      } else {
 104        ch = char_scanner (f);
 105      }
 106    }
 107    if (ch != EOF_CHAR && (ch == '+' || ch == '-')) {
 108      plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 109      ch = char_scanner (f);
 110    }
 111    while (ch != EOF_CHAR && IS_DIGIT (ch)) {
 112      plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 113      ch = char_scanner (f);
 114    }
 115    if (ch == EOF_CHAR || !(ch == POINT_CHAR || TO_UPPER (ch) == TO_UPPER (x_e))) {
 116      goto salida;
 117    }
 118    if (ch == POINT_CHAR) {
 119      plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 120      ch = char_scanner (f);
 121      while (ch != EOF_CHAR && IS_DIGIT (ch)) {
 122        plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 123        ch = char_scanner (f);
 124      }
 125    }
 126    if (ch == EOF_CHAR || TO_UPPER (ch) != TO_UPPER (x_e)) {
 127      goto salida;
 128    }
 129    if (TO_UPPER (ch) == TO_UPPER (x_e)) {
 130      plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 131      ch = char_scanner (f);
 132      while (ch != EOF_CHAR && ch == BLANK_CHAR) {
 133        ch = char_scanner (f);
 134      }
 135      if (ch != EOF_CHAR && (ch == '+' || ch == '-')) {
 136        plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 137        ch = char_scanner (f);
 138      }
 139      while (ch != EOF_CHAR && IS_DIGIT (ch)) {
 140        plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 141        ch = char_scanner (f);
 142      }
 143    }
 144  salida:if (ch != EOF_CHAR) {
 145      unchar_scanner (p, f, (char) ch);
 146    }
 147  }
 148  
 149  
 150  //! @brief Scan a bits from file.
 151  
 152  void scan_bits (NODE_T * p, A68G_REF ref_file)
 153  {
 154    A68G_FILE *f = FILE_DEREF (&ref_file);
 155    reset_transput_buffer (INPUT_BUFFER);
 156    int ch = char_scanner (f);
 157    while (ch != EOF_CHAR && (IS_SPACE (ch) || IS_NL_FF (ch))) {
 158      if (IS_NL_FF (ch)) {
 159        skip_nl_ff (p, &ch, ref_file);
 160      } else {
 161        ch = char_scanner (f);
 162      }
 163    }
 164    while (ch != EOF_CHAR && (ch == FLIP_CHAR || ch == FLOP_CHAR)) {
 165      plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 166      ch = char_scanner (f);
 167    }
 168    if (ch != EOF_CHAR) {
 169      unchar_scanner (p, f, (char) ch);
 170    }
 171  }
 172  
 173  
 174  //! @brief Scan a char from file.
 175  
 176  void scan_char (NODE_T * p, A68G_REF ref_file)
 177  {
 178    A68G_FILE *f = FILE_DEREF (&ref_file);
 179    reset_transput_buffer (INPUT_BUFFER);
 180    int ch = char_scanner (f);
 181    skip_nl_ff (p, &ch, ref_file);
 182    if (ch != EOF_CHAR) {
 183      plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 184    }
 185  }
 186  
 187  
 188  //! @brief Scan a string from file.
 189  
 190  void scan_string (NODE_T * p, char *term, A68G_REF ref_file)
 191  {
 192    A68G_FILE *f = FILE_DEREF (&ref_file);
 193    if (END_OF_FILE (f)) {
 194      reset_transput_buffer (INPUT_BUFFER);
 195      end_of_file_error (p, ref_file);
 196    } else {
 197      reset_transput_buffer (INPUT_BUFFER);
 198      int ch = char_scanner (f);
 199      BOOL_T siga = A68G_TRUE;
 200      while (siga) {
 201        if (ch == EOF_CHAR || END_OF_FILE (f)) {
 202          if (get_transput_buffer_index (INPUT_BUFFER) == 0) {
 203            end_of_file_error (p, ref_file);
 204          }
 205          siga = A68G_FALSE;
 206        } else if (IS_NL_FF (ch)) {
 207          ADDR_T pop_sp = A68G_SP;
 208          unchar_scanner (p, f, (char) ch);
 209          if (ch == NEWLINE_CHAR) {
 210            on_event_handler (p, LINE_END_MENDED (f), ref_file);
 211          } else if (ch == FORMFEED_CHAR) {
 212            on_event_handler (p, PAGE_END_MENDED (f), ref_file);
 213          }
 214          A68G_SP = pop_sp;
 215          siga = A68G_FALSE;
 216        } else if (term != NO_TEXT && strchr (term, ch) != NO_TEXT) {
 217          siga = A68G_FALSE;
 218          unchar_scanner (p, f, (char) ch);
 219        } else {
 220          plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
 221          ch = char_scanner (f);
 222        }
 223      }
 224    }
 225  }
 226  
 227  
 228  //! @brief Make temp file name.
 229  
 230  BOOL_T a68g_mkstemp (char *fn, int flags, mode_t permissions)
 231  {
 232  // "tmpnam" is not safe, "mkstemp" is Unix, so a68g brings its own tmpnam.
 233  #define TMP_SIZE 32
 234  #define TRIALS 32
 235    BUFFER tfilename;
 236    char *letters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 237    size_t len = strlen (letters);
 238    BOOL_T good_file = A68G_FALSE;
 239  // Next are prefixes to try.
 240  // First we try /tmp, and if that won't go, the current dir.
 241    char *prefix[] = { "/tmp/a68g_", "./a68g_", NO_TEXT };
 242    for (int i = 0; prefix[i] != NO_TEXT; i++) {
 243      for (int k = 0; k < TRIALS && good_file == A68G_FALSE; k++) {
 244        a68g_bufcpy (tfilename, prefix[i], BUFFER_SIZE);
 245        for (int j = 0; j < TMP_SIZE; j++) {
 246          int cindex;
 247          do {
 248            cindex = (int) (a68g_unif_rand () * len);
 249          } while (cindex < 0 || cindex >= len);
 250          char chars[2];
 251          chars[0] = letters[cindex];
 252          chars[1] = NULL_CHAR;
 253          a68g_bufcat (tfilename, chars, BUFFER_SIZE);
 254        }
 255        a68g_bufcat (tfilename, ".tmp", BUFFER_SIZE);
 256        errno = 0;
 257        FILE_T fd = open (tfilename, flags | O_EXCL, permissions);
 258        good_file = (BOOL_T) (fd != A68G_NO_FILE && errno == 0);
 259        if (good_file) {
 260          (void) close (fd);
 261        }
 262      }
 263    }
 264    if (good_file) {
 265      a68g_bufcpy (fn, tfilename, BUFFER_SIZE);
 266      return A68G_TRUE;
 267    } else {
 268      return A68G_FALSE;
 269    }
 270  #undef TMP_SIZE
 271  #undef TRIALS
 272  }
 273  
 274  
 275  //! @brief Open a file, or establish it.
 276  
 277  FILE_T open_physical_file (NODE_T * p, A68G_REF ref_file, int flags, mode_t permissions)
 278  {
 279    BOOL_T reading = (flags & ~O_BINARY) == A68G_READ_ACCESS;
 280    BOOL_T writing = (flags & ~O_BINARY) == A68G_WRITE_ACCESS;
 281    ABEND (reading == writing, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
 282    CHECK_REF (p, ref_file, M_REF_FILE);
 283    A68G_FILE *file = FILE_DEREF (&ref_file);
 284    CHECK_INIT (p, INITIALISED (file), M_FILE);
 285    if (!IS_NIL (STRING (file))) {
 286      if (writing) {
 287        A68G_REF z = *DEREF (A68G_REF, &STRING (file));
 288        A68G_ARRAY *arr; A68G_TUPLE *tup;
 289        GET_DESCRIPTOR (arr, tup, &z);
 290        UPB (tup) = LWB (tup) - 1;
 291      }
 292  // Associated file.
 293      TRANSPUT_BUFFER (file) = get_unblocked_transput_buffer (p);
 294      reset_transput_buffer (TRANSPUT_BUFFER (file));
 295      END_OF_FILE (file) = A68G_FALSE;
 296      FILE_ENTRY (file) = -1;
 297      return FD (file);
 298    } else if (IS_NIL (IDENTIFICATION (file))) {
 299  // No identification, so generate a unique identification..
 300      if (reading) {
 301        return A68G_NO_FILE;
 302      } else {
 303        BUFFER tfilename;
 304        BUFCLR (tfilename);
 305        BOOL_T write_mood = (flags & A68G_WRITE_ACCESS) != 0;
 306        if (write_mood) {
 307          flags |= (O_CREAT | O_TRUNC);
 308        }
 309        if (!a68g_mkstemp (tfilename, flags, permissions)) {
 310          diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NO_TEMP);
 311          exit_genie (p, A68G_RUNTIME_ERROR);
 312        }
 313        FD (file) = open (tfilename, flags, permissions);
 314        size_t len = 1 + strlen (tfilename);
 315        IDENTIFICATION (file) = heap_generator (p, M_C_STRING, len);
 316        BLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
 317        a68g_bufcpy (DEREF (char, &IDENTIFICATION (file)), tfilename, len);
 318        TRANSPUT_BUFFER (file) = get_unblocked_transput_buffer (p);
 319        reset_transput_buffer (TRANSPUT_BUFFER (file));
 320        END_OF_FILE (file) = A68G_FALSE;
 321        TMP_FILE (file) = A68G_TRUE;
 322        FILE_ENTRY (file) = store_file_entry (p, FD (file), tfilename, TMP_FILE (file));
 323        return FD (file);
 324      }
 325    } else {
 326  // Opening an identified file.
 327      A68G_REF ref_filename = IDENTIFICATION (file);
 328      CHECK_REF (p, ref_filename, M_ROWS);
 329      char *filename = DEREF (char, &ref_filename);
 330      BOOL_T write_mood = (flags & A68G_WRITE_ACCESS) != 0;
 331      if (write_mood) {
 332        // A68G creates a file when it does not exist.
 333        flags |= O_CREAT;
 334      }
 335      if (APPEND (file)) {
 336        // Append to the end upon opening for writing.
 337        if (write_mood) {
 338          flags |= O_APPEND;
 339        }
 340        APPEND (file) = A68G_FALSE;
 341      } else if (write_mood) {
 342        // Empty a file upon opening for writing.
 343        flags |= O_TRUNC;
 344      }
 345      if (OPEN_EXCLUSIVE (file)) {
 346        // Require that the file be non-existent.
 347        if (write_mood) {
 348          flags |= O_EXCL;
 349        }
 350        OPEN_EXCLUSIVE (file) = A68G_FALSE;
 351      }
 352      FD (file) = open (filename, flags, permissions);
 353      TRANSPUT_BUFFER (file) = get_unblocked_transput_buffer (p);
 354      reset_transput_buffer (TRANSPUT_BUFFER (file));
 355      END_OF_FILE (file) = A68G_FALSE;
 356      FILE_ENTRY (file) = store_file_entry (p, FD (file), filename, TMP_FILE (file));
 357      return FD (file);
 358    }
 359  }
 360  
 361  
 362  //! @brief Call PROC (REF FILE) VOID during transput.
 363  
 364  void genie_call_proc_ref_file_void (NODE_T * p, A68G_REF ref_file, A68G_PROCEDURE z)
 365  {
 366    ADDR_T pop_sp = A68G_SP, pop_fp = A68G_FP;
 367    MOID_T *u = M_PROC_REF_FILE_VOID;
 368    PUSH_REF (p, ref_file);
 369    genie_call_procedure (p, MOID (&z), u, u, &z, pop_sp, pop_fp);
 370    A68G_SP = pop_sp;              // Voiding
 371  }
 372  
 373  // Unformatted transput.
 374  
 375  
 376  //! @brief Hexadecimal value of digit.
 377  
 378  int char_value (int ch)
 379  {
 380    switch (ch) {
 381    case '0': {
 382        return 0;
 383      }
 384    case '1': {
 385        return 1;
 386      }
 387    case '2': {
 388        return 2;
 389      }
 390    case '3': {
 391        return 3;
 392      }
 393    case '4': {
 394        return 4;
 395      }
 396    case '5': {
 397        return 5;
 398      }
 399    case '6': {
 400        return 6;
 401      }
 402    case '7': {
 403        return 7;
 404      }
 405    case '8': {
 406        return 8;
 407      }
 408    case '9': {
 409        return 9;
 410      }
 411    case 'A':
 412    case 'a': {
 413        return 10;
 414      }
 415    case 'B':
 416    case 'b': {
 417        return 11;
 418      }
 419    case 'C':
 420    case 'c': {
 421        return 12;
 422      }
 423    case 'D':
 424    case 'd': {
 425        return 13;
 426      }
 427    case 'E':
 428    case 'e': {
 429        return 14;
 430      }
 431    case 'F':
 432    case 'f': {
 433        return 15;
 434      }
 435    default: {
 436        return -1;
 437      }
 438    }
 439  }
 440  
 441  
 442  //! @brief Convert string in input buffer to value of required mode.
 443  
 444  void genie_string_to_value (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
 445  {
 446    char *str = get_transput_buffer (INPUT_BUFFER);
 447    errno = 0;
 448  // end string, just in case.
 449    plusab_transput_buffer (p, INPUT_BUFFER, NULL_CHAR);
 450    if (mode == M_INT) {
 451      if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
 452        value_error (p, mode, ref_file);
 453      }
 454    } else if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
 455      if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
 456        value_error (p, mode, ref_file);
 457      }
 458    } else if (mode == M_REAL) {
 459      if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
 460        value_error (p, mode, ref_file);
 461      }
 462    } else if (mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
 463      if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
 464        value_error (p, mode, ref_file);
 465      }
 466    } else if (mode == M_BOOL) {
 467      if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
 468        value_error (p, mode, ref_file);
 469      }
 470    } else if (mode == M_BITS) {
 471      if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
 472        value_error (p, mode, ref_file);
 473      }
 474    } else if (mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
 475      if (genie_string_to_value_internal (p, mode, str, item) == A68G_FALSE) {
 476        value_error (p, mode, ref_file);
 477      }
 478    } else if (mode == M_CHAR) {
 479      A68G_CHAR *z = (A68G_CHAR *) item;
 480      if (str[0] == NULL_CHAR) {
 481  //      value_error (p, mode, ref_file);.
 482        VALUE (z) = NULL_CHAR;
 483        STATUS (z) = INIT_MASK;
 484      } else {
 485        size_t len = strlen (str);
 486        if (len == 0 || len > 1) {
 487          value_error (p, mode, ref_file);
 488        }
 489        VALUE (z) = str[0];
 490        STATUS (z) = INIT_MASK;
 491      }
 492    } else if (mode == M_STRING) {
 493      A68G_REF z;
 494      z = c_to_a_string (p, str, get_transput_buffer_index (INPUT_BUFFER) - 1);
 495      *(A68G_REF *) item = z;
 496    }
 497    if (errno != 0) {
 498      transput_error (p, ref_file, mode);
 499    }
 500  }
 501  
 502  
 503  //! @brief Read object from file.
 504  
 505  void genie_read_standard (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
 506  {
 507    A68G_FILE *f = FILE_DEREF (&ref_file);
 508    errno = 0;
 509    if (END_OF_FILE (f)) {
 510      end_of_file_error (p, ref_file);
 511    }
 512    if (mode == M_PROC_REF_FILE_VOID) {
 513      genie_call_proc_ref_file_void (p, ref_file, *(A68G_PROCEDURE *) item);
 514    } else if (mode == M_FORMAT) {
 515      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_FORMAT);
 516      exit_genie (p, A68G_RUNTIME_ERROR);
 517    } else if (mode == M_REF_SOUND) {
 518      read_sound (p, ref_file, DEREF (A68G_SOUND, (A68G_REF *) item));
 519    } else if (IS_REF (mode)) {
 520      CHECK_REF (p, *(A68G_REF *) item, mode);
 521      genie_read_standard (p, SUB (mode), ADDRESS ((A68G_REF *) item), ref_file);
 522    } else if (mode == M_INT || mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
 523      scan_integer (p, ref_file);
 524      genie_string_to_value (p, mode, item, ref_file);
 525    } else if (mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
 526      scan_real (p, ref_file);
 527      genie_string_to_value (p, mode, item, ref_file);
 528    } else if (mode == M_BOOL) {
 529      scan_char (p, ref_file);
 530      genie_string_to_value (p, mode, item, ref_file);
 531    } else if (mode == M_CHAR) {
 532      scan_char (p, ref_file);
 533      genie_string_to_value (p, mode, item, ref_file);
 534    } else if (mode == M_BITS || mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
 535      scan_bits (p, ref_file);
 536      genie_string_to_value (p, mode, item, ref_file);
 537    } else if (mode == M_STRING) {
 538      char *term = DEREF (char, &TERMINATOR (f));
 539      scan_string (p, term, ref_file);
 540      genie_string_to_value (p, mode, item, ref_file);
 541    } else if (IS_STRUCT (mode)) {
 542      for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
 543        genie_read_standard (p, MOID (q), &item[OFFSET (q)], ref_file);
 544      }
 545    } else if (IS_UNION (mode)) {
 546      A68G_UNION *z = (A68G_UNION *) item;
 547      if (!(STATUS (z) | INIT_MASK) || VALUE (z) == NULL) {
 548        diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE, mode);
 549        exit_genie (p, A68G_RUNTIME_ERROR);
 550      }
 551      genie_read_standard (p, (MOID_T *) (VALUE (z)), &item[A68G_UNION_SIZE], ref_file);
 552    } else if (IS_ROW (mode) || IS_FLEX (mode)) {
 553      MOID_T *deflexed = DEFLEX (mode);
 554      A68G_ARRAY *arr;
 555      A68G_TUPLE *tup;
 556      CHECK_INIT (p, INITIALISED ((A68G_REF *) item), mode);
 557      GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
 558      if (get_row_size (tup, DIM (arr)) > 0) {
 559        BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
 560        BOOL_T done = A68G_FALSE;
 561        initialise_internal_index (tup, DIM (arr));
 562        while (!done) {
 563          ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
 564          ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
 565          genie_read_standard (p, SUB (deflexed), &base_addr[elem_addr], ref_file);
 566          done = increment_internal_index (tup, DIM (arr));
 567        }
 568      }
 569    }
 570    if (errno != 0) {
 571      transput_error (p, ref_file, mode);
 572    }
 573  }
 574  
 575  
 576  //! @brief PROC ([] SIMPLIN) VOID read
 577  
 578  void genie_read (NODE_T * p)
 579  {
 580    A68G_REF row;
 581    POP_REF (p, &row);
 582    genie_stand_in (p);
 583    PUSH_REF (p, row);
 584    genie_read_file (p);
 585  }
 586  
 587  
 588  //! @brief Open for reading.
 589  
 590  void open_for_reading (NODE_T * p, A68G_REF ref_file)
 591  {
 592    A68G_FILE *file = FILE_DEREF (&ref_file);
 593    if (!OPENED (file)) {
 594      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
 595      exit_genie (p, A68G_RUNTIME_ERROR);
 596    }
 597    if (DRAW_MOOD (file)) {
 598      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
 599      exit_genie (p, A68G_RUNTIME_ERROR);
 600    }
 601    if (WRITE_MOOD (file)) {
 602      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
 603      exit_genie (p, A68G_RUNTIME_ERROR);
 604    }
 605    if (!GET (&CHANNEL (file))) {
 606      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "getting");
 607      exit_genie (p, A68G_RUNTIME_ERROR);
 608    }
 609    if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
 610      if (IS_NIL (STRING (file))) {
 611        if ((FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS, 0)) == A68G_NO_FILE) {
 612          open_error (p, ref_file, "getting");
 613        }
 614      } else {
 615        FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS, 0);
 616      }
 617      DRAW_MOOD (file) = A68G_FALSE;
 618      READ_MOOD (file) = A68G_TRUE;
 619      WRITE_MOOD (file) = A68G_FALSE;
 620      CHAR_MOOD (file) = A68G_TRUE;
 621    }
 622    if (!CHAR_MOOD (file)) {
 623      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "binary");
 624      exit_genie (p, A68G_RUNTIME_ERROR);
 625    }
 626  }
 627  
 628  
 629  //! @brief PROC (REF FILE, [] SIMPLIN) VOID get
 630  
 631  void genie_read_file (NODE_T * p)
 632  {
 633    A68G_REF row; A68G_ARRAY *arr; A68G_TUPLE *tup;
 634    POP_REF (p, &row);
 635    CHECK_REF (p, row, M_ROW_SIMPLIN);
 636    GET_DESCRIPTOR (arr, tup, &row);
 637    A68G_REF ref_file;
 638    POP_REF (p, &ref_file);
 639    CHECK_REF (p, ref_file, M_REF_FILE);
 640    A68G_FILE *file = FILE_DEREF (&ref_file);
 641    CHECK_INIT (p, INITIALISED (file), M_FILE);
 642    open_for_reading (p, ref_file);
 643  // Read.
 644    INT_T elems = ROW_SIZE (tup);
 645    if (elems <= 0) {
 646      return;
 647    }
 648    BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
 649    INT_T elem_index = 0;
 650    for (INT_T k = 0; k < elems; k++) {
 651      A68G_UNION *z = (A68G_UNION *) & base_address[elem_index];
 652      MOID_T *mode = (MOID_T *) (VALUE (z));
 653      BYTE_T *item = (BYTE_T *) & base_address[elem_index + A68G_UNION_SIZE];
 654      genie_read_standard (p, mode, item, ref_file);
 655      elem_index += SIZE (M_SIMPLIN);
 656    }
 657  }
 658  
 659  
 660  //! @brief Convert value to string.
 661  
 662  void genie_value_to_string (NODE_T * p, MOID_T * moid, BYTE_T * item, int mod)
 663  {
 664    if (moid == M_INT) {
 665      A68G_INT *z = (A68G_INT *) item;
 666      PUSH_UNION (p, M_INT);
 667      PUSH_VALUE (p, VALUE (z), A68G_INT);
 668      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_INT)));
 669      if (mod == FORMAT_ITEM_G) {
 670        PUSH_VALUE (p, A68G_INT_WIDTH + 1, A68G_INT);
 671        genie_whole (p);
 672      } else if (mod == FORMAT_ITEM_H) {
 673        PUSH_VALUE (p, A68G_REAL_WIDTH + A68G_EXP_WIDTH + 4, A68G_INT);
 674        PUSH_VALUE (p, A68G_REAL_WIDTH - 1, A68G_INT);
 675        PUSH_VALUE (p, A68G_EXP_WIDTH + 1, A68G_INT);
 676        PUSH_VALUE (p, 3, A68G_INT);
 677        genie_real (p);
 678      }
 679      return;
 680    }
 681    #if (A68G_LEVEL >= 3)
 682      if (moid == M_LONG_INT) {
 683        A68G_LONG_INT *z = (A68G_LONG_INT *) item;
 684        PUSH_UNION (p, M_LONG_INT);
 685        PUSH (p, z, SIZE (M_LONG_INT));
 686        INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_INT)));
 687        if (mod == FORMAT_ITEM_G) {
 688          PUSH_VALUE (p, A68G_LONG_WIDTH + 1, A68G_INT);
 689          genie_whole (p);
 690        } else if (mod == FORMAT_ITEM_H) {
 691          PUSH_VALUE (p, A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4, A68G_INT);
 692          PUSH_VALUE (p, A68G_LONG_REAL_WIDTH - 1, A68G_INT);
 693          PUSH_VALUE (p, A68G_LONG_EXP_WIDTH + 1, A68G_INT);
 694          PUSH_VALUE (p, 3, A68G_INT);
 695          genie_real (p);
 696        }
 697        return;
 698      }
 699      if (moid == M_LONG_REAL) {
 700        A68G_LONG_REAL *z = (A68G_LONG_REAL *) item;
 701        PUSH_UNION (p, M_LONG_REAL);
 702        PUSH_VALUE (p, VALUE (z), A68G_LONG_REAL);
 703        INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_REAL)));
 704        PUSH_VALUE (p, A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4, A68G_INT);
 705        PUSH_VALUE (p, A68G_LONG_REAL_WIDTH - 1, A68G_INT);
 706        PUSH_VALUE (p, A68G_LONG_EXP_WIDTH + 1, A68G_INT);
 707        if (mod == FORMAT_ITEM_G) {
 708          genie_float (p);
 709        } else if (mod == FORMAT_ITEM_H) {
 710          PUSH_VALUE (p, 3, A68G_INT);
 711          genie_real (p);
 712        }
 713        return;
 714      }
 715      if (moid == M_LONG_BITS) {
 716        A68G_LONG_BITS *z = (A68G_LONG_BITS *) item;
 717        char *s = stack_string (p, 8 + A68G_LONG_BITS_WIDTH);
 718        int n = 0;
 719        for (int w = 0; w <= 1; w++) {
 720          UNSIGNED_T bit = D_SIGN;
 721          for (int j = 0; j < A68G_BITS_WIDTH; j++) {
 722            if (w == 0) {
 723              s[n] = (char) ((HW (VALUE (z)) & bit) ? FLIP_CHAR : FLOP_CHAR);
 724            } else {
 725              s[n] = (char) ((LW (VALUE (z)) & bit) ? FLIP_CHAR : FLOP_CHAR);
 726            }
 727            bit >>= 1;
 728            n++;
 729          }
 730        }
 731        s[n] = NULL_CHAR;
 732        return;
 733      }
 734    #else
 735      if (moid == M_LONG_BITS || moid == M_LONG_LONG_BITS) {
 736        int bits = get_mp_bits_width (moid), word = get_mp_bits_words (moid);
 737        int pos = bits;
 738        char *str = stack_string (p, 8 + bits);
 739        ADDR_T pop_sp = A68G_SP;
 740        unt *row = stack_mp_bits (p, (MP_T *) item, moid);
 741        str[pos--] = NULL_CHAR;
 742        while (pos >= 0) {
 743          unt bit = 0x1;
 744          for (int j = 0; j < MP_BITS_BITS && pos >= 0; j++) {
 745            str[pos--] = (char) ((row[word - 1] & bit) ? FLIP_CHAR : FLOP_CHAR);
 746            bit <<= 1;
 747          }
 748          word--;
 749        }
 750        A68G_SP = pop_sp;
 751        return;
 752      }
 753    #endif
 754    if (moid == M_LONG_INT) {
 755      MP_T *z = (MP_T *) item;
 756      PUSH_UNION (p, M_LONG_INT);
 757      PUSH (p, z, SIZE (M_LONG_INT));
 758      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_INT)));
 759      if (mod == FORMAT_ITEM_G) {
 760        PUSH_VALUE (p, A68G_LONG_WIDTH + 1, A68G_INT);
 761        genie_whole (p);
 762      } else if (mod == FORMAT_ITEM_H) {
 763        PUSH_VALUE (p, A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4, A68G_INT);
 764        PUSH_VALUE (p, A68G_LONG_REAL_WIDTH - 1, A68G_INT);
 765        PUSH_VALUE (p, A68G_LONG_EXP_WIDTH + 1, A68G_INT);
 766        PUSH_VALUE (p, 3, A68G_INT);
 767        genie_real (p);
 768      }
 769      return;
 770    }
 771    if (moid == M_LONG_LONG_INT) {
 772      MP_T *z = (MP_T *) item;
 773      PUSH_UNION (p, M_LONG_LONG_INT);
 774      PUSH (p, z, SIZE (M_LONG_LONG_INT));
 775      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_LONG_INT)));
 776      if (mod == FORMAT_ITEM_G) {
 777        PUSH_VALUE (p, A68G_LONG_LONG_WIDTH + 1, A68G_INT);
 778        genie_whole (p);
 779      } else if (mod == FORMAT_ITEM_H) {
 780        PUSH_VALUE (p, A68G_LONG_LONG_REAL_WIDTH + A68G_LONG_LONG_EXP_WIDTH + 4, A68G_INT);
 781        PUSH_VALUE (p, A68G_LONG_LONG_REAL_WIDTH - 1, A68G_INT);
 782        PUSH_VALUE (p, A68G_LONG_LONG_EXP_WIDTH + 1, A68G_INT);
 783        PUSH_VALUE (p, 3, A68G_INT);
 784        genie_real (p);
 785      }
 786      return;
 787    }
 788    if (moid == M_REAL) {
 789      A68G_REAL *z = (A68G_REAL *) item;
 790      PUSH_UNION (p, M_REAL);
 791      PUSH_VALUE (p, VALUE (z), A68G_REAL);
 792      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_REAL)));
 793      PUSH_VALUE (p, A68G_REAL_WIDTH + A68G_EXP_WIDTH + 4, A68G_INT);
 794      PUSH_VALUE (p, A68G_REAL_WIDTH - 1, A68G_INT);
 795      PUSH_VALUE (p, A68G_EXP_WIDTH + 1, A68G_INT);
 796      if (mod == FORMAT_ITEM_G) {
 797        genie_float (p);
 798      } else if (mod == FORMAT_ITEM_H) {
 799        PUSH_VALUE (p, 3, A68G_INT);
 800        genie_real (p);
 801      }
 802      return;
 803    }
 804    if (moid == M_LONG_REAL) {
 805      MP_T *z = (MP_T *) item;
 806      PUSH_UNION (p, M_LONG_REAL);
 807      PUSH (p, z, (int) SIZE (M_LONG_REAL));
 808      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_REAL)));
 809      PUSH_VALUE (p, A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4, A68G_INT);
 810      PUSH_VALUE (p, A68G_LONG_REAL_WIDTH - 1, A68G_INT);
 811      PUSH_VALUE (p, A68G_LONG_EXP_WIDTH + 1, A68G_INT);
 812      if (mod == FORMAT_ITEM_G) {
 813        genie_float (p);
 814      } else if (mod == FORMAT_ITEM_H) {
 815        PUSH_VALUE (p, 3, A68G_INT);
 816        genie_real (p);
 817      }
 818      return;
 819    }
 820    if (moid == M_LONG_LONG_REAL) {
 821      MP_T *z = (MP_T *) item;
 822      PUSH_UNION (p, M_LONG_LONG_REAL);
 823      PUSH (p, z, (int) SIZE (M_LONG_LONG_REAL));
 824      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_LONG_LONG_REAL)));
 825      PUSH_VALUE (p, A68G_LONG_LONG_REAL_WIDTH + A68G_LONG_LONG_EXP_WIDTH + 4, A68G_INT);
 826      PUSH_VALUE (p, A68G_LONG_LONG_REAL_WIDTH - 1, A68G_INT);
 827      PUSH_VALUE (p, A68G_LONG_LONG_EXP_WIDTH + 1, A68G_INT);
 828      if (mod == FORMAT_ITEM_G) {
 829        genie_float (p);
 830      } else if (mod == FORMAT_ITEM_H) {
 831        PUSH_VALUE (p, 3, A68G_INT);
 832        genie_real (p);
 833      }
 834      return;
 835    }
 836    if (moid == M_BITS) {
 837      A68G_BITS *z = (A68G_BITS *) item;
 838      char *str = stack_string (p, 8 + A68G_BITS_WIDTH);
 839      UNSIGNED_T bit = 0x1;
 840      int j;
 841      for (j = 1; j < A68G_BITS_WIDTH; j++) {
 842        bit <<= 1;
 843      }
 844      for (j = 0; j < A68G_BITS_WIDTH; j++) {
 845        str[j] = (char) ((VALUE (z) & bit) ? FLIP_CHAR : FLOP_CHAR);
 846        bit >>= 1;
 847      }
 848      str[j] = NULL_CHAR;
 849      return;
 850    }
 851  }
 852  
 853  
 854  //! @brief Print object to file.
 855  
 856  void genie_write_standard (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
 857  {
 858    errno = 0;
 859    ABEND (mode == NO_MOID, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
 860    if (mode == M_PROC_REF_FILE_VOID) {
 861      genie_call_proc_ref_file_void (p, ref_file, *(A68G_PROCEDURE *) item);
 862    } else if (mode == M_FORMAT) {
 863      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_FORMAT);
 864      exit_genie (p, A68G_RUNTIME_ERROR);
 865    } else if (mode == M_SOUND) {
 866      write_sound (p, ref_file, (A68G_SOUND *) item);
 867    } else if (mode == M_INT || mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
 868      genie_value_to_string (p, mode, item, FORMAT_ITEM_G);
 869      add_string_from_stack_transput_buffer (p, UNFORMATTED_BUFFER);
 870    } else if (mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
 871      genie_value_to_string (p, mode, item, FORMAT_ITEM_G);
 872      add_string_from_stack_transput_buffer (p, UNFORMATTED_BUFFER);
 873    } else if (mode == M_BOOL) {
 874      A68G_BOOL *z = (A68G_BOOL *) item;
 875      char flipflop = (char) (VALUE (z) == A68G_TRUE ? FLIP_CHAR : FLOP_CHAR);
 876      plusab_transput_buffer (p, UNFORMATTED_BUFFER, flipflop);
 877    } else if (mode == M_CHAR) {
 878      A68G_CHAR *ch = (A68G_CHAR *) item;
 879      plusab_transput_buffer (p, UNFORMATTED_BUFFER, (char) VALUE (ch));
 880    } else if (mode == M_BITS || mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
 881      char *str = (char *) STACK_TOP;
 882      genie_value_to_string (p, mode, item, FORMAT_ITEM_G);
 883      add_string_transput_buffer (p, UNFORMATTED_BUFFER, str);
 884    } else if (mode == M_ROW_CHAR || mode == M_STRING) {
 885  // Handle these separately since this is faster than straightening.
 886      add_a_string_transput_buffer (p, UNFORMATTED_BUFFER, item);
 887    } else if (IS_UNION (mode)) {
 888      A68G_UNION *z = (A68G_UNION *) item;
 889      MOID_T *um = (MOID_T *) (VALUE (z));
 890      BYTE_T *ui = &item[A68G_UNION_SIZE];
 891      if (um == NO_MOID) {
 892        diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE, mode);
 893        exit_genie (p, A68G_RUNTIME_ERROR);
 894      }
 895      genie_write_standard (p, um, ui, ref_file);
 896    } else if (IS_STRUCT (mode)) {
 897      for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
 898        BYTE_T *elem = &item[OFFSET (q)];
 899        genie_check_initialisation (p, elem, MOID (q));
 900        genie_write_standard (p, MOID (q), elem, ref_file);
 901      }
 902    } else if (IS_ROW (mode) || IS_FLEX (mode)) {
 903      MOID_T *deflexed = DEFLEX (mode);
 904      A68G_ARRAY *arr;
 905      A68G_TUPLE *tup;
 906      CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
 907      GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
 908      if (get_row_size (tup, DIM (arr)) > 0) {
 909        BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
 910        BOOL_T done = A68G_FALSE;
 911        initialise_internal_index (tup, DIM (arr));
 912        while (!done) {
 913          ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
 914          ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
 915          BYTE_T *elem = &base_addr[elem_addr];
 916          genie_check_initialisation (p, elem, SUB (deflexed));
 917          genie_write_standard (p, SUB (deflexed), elem, ref_file);
 918          done = increment_internal_index (tup, DIM (arr));
 919        }
 920      }
 921    }
 922    if (errno != 0) {
 923      ABEND (IS_NIL (ref_file), ERROR_ACTION, error_specification ());
 924      transput_error (p, ref_file, mode);
 925    }
 926  }
 927  
 928  
 929  //! @brief PROC ([] SIMPLOUT) VOID print, write
 930  
 931  void genie_write (NODE_T * p)
 932  {
 933    A68G_REF row;
 934    POP_REF (p, &row);
 935    genie_stand_out (p);
 936    PUSH_REF (p, row);
 937    genie_write_file (p);
 938  }
 939  
 940  
 941  //! @brief Open for writing.
 942  
 943  void open_for_writing (NODE_T * p, A68G_REF ref_file)
 944  {
 945    A68G_FILE *file = FILE_DEREF (&ref_file);
 946    if (!OPENED (file)) {
 947      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
 948      exit_genie (p, A68G_RUNTIME_ERROR);
 949    }
 950    if (DRAW_MOOD (file)) {
 951      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
 952      exit_genie (p, A68G_RUNTIME_ERROR);
 953    }
 954    if (READ_MOOD (file)) {
 955      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "read");
 956      exit_genie (p, A68G_RUNTIME_ERROR);
 957    }
 958    if (!PUT (&CHANNEL (file))) {
 959      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "putting");
 960      exit_genie (p, A68G_RUNTIME_ERROR);
 961    }
 962    if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
 963      if (IS_NIL (STRING (file))) {
 964        if ((FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS, A68G_PROTECTION)) == A68G_NO_FILE) {
 965          open_error (p, ref_file, "putting");
 966        }
 967      } else {
 968        FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS, 0);
 969      }
 970      DRAW_MOOD (file) = A68G_FALSE;
 971      READ_MOOD (file) = A68G_FALSE;
 972      WRITE_MOOD (file) = A68G_TRUE;
 973      CHAR_MOOD (file) = A68G_TRUE;
 974    }
 975    if (!CHAR_MOOD (file)) {
 976      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "binary");
 977      exit_genie (p, A68G_RUNTIME_ERROR);
 978    }
 979  }
 980  
 981  
 982  //! @brief PROC (REF FILE, [] SIMPLOUT) VOID put
 983  
 984  void genie_write_file (NODE_T * p)
 985  {
 986    A68G_REF row; A68G_ARRAY *arr; A68G_TUPLE *tup;
 987    POP_REF (p, &row);
 988    CHECK_REF (p, row, M_ROW_SIMPLOUT);
 989    GET_DESCRIPTOR (arr, tup, &row);
 990    A68G_REF ref_file;
 991    POP_REF (p, &ref_file);
 992    CHECK_REF (p, ref_file, M_REF_FILE);
 993    A68G_FILE *file = FILE_DEREF (&ref_file);
 994    CHECK_INIT (p, INITIALISED (file), M_FILE);
 995    open_for_writing (p, ref_file);
 996  // Write.
 997    INT_T elems = ROW_SIZE (tup);
 998    if (elems <= 0) {
 999      return;
1000    }
1001    BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
1002    INT_T elem_index = 0;
1003    for (INT_T k = 0; k < elems; k++) {
1004      A68G_UNION *z = (A68G_UNION *) & (base_address[elem_index]);
1005      MOID_T *mode = (MOID_T *) (VALUE (z));
1006      BYTE_T *item = (BYTE_T *) & base_address[elem_index + A68G_UNION_SIZE];
1007      reset_transput_buffer (UNFORMATTED_BUFFER);
1008      genie_write_standard (p, mode, item, ref_file);
1009      write_purge_buffer (p, ref_file, UNFORMATTED_BUFFER);
1010      elem_index += SIZE (M_SIMPLOUT);
1011    }
1012  }
1013  
1014  
1015  //! @brief Read object binary from file.
1016  
1017  void genie_read_bin_standard (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
1018  {
1019    CHECK_REF (p, ref_file, M_REF_FILE);
1020    A68G_FILE *f = FILE_DEREF (&ref_file);
1021    errno = 0;
1022    if (END_OF_FILE (f)) {
1023      end_of_file_error (p, ref_file);
1024    }
1025    if (mode == M_PROC_REF_FILE_VOID) {
1026      genie_call_proc_ref_file_void (p, ref_file, *(A68G_PROCEDURE *) item);
1027    } else if (mode == M_FORMAT) {
1028      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_FORMAT);
1029      exit_genie (p, A68G_RUNTIME_ERROR);
1030    } else if (mode == M_REF_SOUND) {
1031      read_sound (p, ref_file, (A68G_SOUND *) ADDRESS ((A68G_REF *) item));
1032    } else if (IS_REF (mode)) {
1033      CHECK_REF (p, *(A68G_REF *) item, mode);
1034      genie_read_bin_standard (p, SUB (mode), ADDRESS ((A68G_REF *) item), ref_file);
1035    } else if (mode == M_INT) {
1036      A68G_INT *z = (A68G_INT *) item;
1037      ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1038      STATUS (z) = INIT_MASK;
1039    } else if (mode == M_LONG_INT) {
1040    #if (A68G_LEVEL >= 3)
1041      A68G_LONG_INT *z = (A68G_LONG_INT *) item;
1042      ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1043      STATUS (z) = INIT_MASK;
1044    #else
1045      MP_T *z = (MP_T *) item;
1046      ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1047      SET_INIT_MP (z);
1048    #endif
1049    } else if (mode == M_LONG_LONG_INT) {
1050      MP_T *z = (MP_T *) item;
1051      ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1052      SET_INIT_MP (z);
1053    } else if (mode == M_REAL) {
1054      A68G_REAL *z = (A68G_REAL *) item;
1055      ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1056      STATUS (z) = INIT_MASK;
1057    } else if (mode == M_LONG_REAL) {
1058      #if (A68G_LEVEL >= 3)
1059        A68G_LONG_REAL *z = (A68G_LONG_REAL *) item;
1060        ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1061        STATUS (z) = INIT_MASK;
1062      #else
1063        MP_T *z = (MP_T *) item;
1064        ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1065        SET_INIT_MP (z);
1066      #endif
1067    } else if (mode == M_LONG_LONG_REAL) {
1068      MP_T *z = (MP_T *) item;
1069      ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1070      SET_INIT_MP (z);
1071    } else if (mode == M_BOOL) {
1072      A68G_BOOL *z = (A68G_BOOL *) item;
1073      ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1074      STATUS (z) = INIT_MASK;
1075    } else if (mode == M_CHAR) {
1076      A68G_CHAR *z = (A68G_CHAR *) item;
1077      ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1078      STATUS (z) = INIT_MASK;
1079    } else if (mode == M_BITS) {
1080      A68G_BITS *z = (A68G_BITS *) item;
1081      ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1082      STATUS (z) = INIT_MASK;
1083    } else if (mode == M_LONG_BITS) {
1084      #if (A68G_LEVEL >= 3)
1085        A68G_LONG_BITS *z = (A68G_LONG_BITS *) item;
1086        ASSERT (io_read (FD (f), &(VALUE (z)), sizeof (VALUE (z))) != -1);
1087        STATUS (z) = INIT_MASK;
1088      #else
1089        MP_T *z = (MP_T *) item;
1090        ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1091        SET_INIT_MP (z);
1092      #endif
1093    } else if (mode == M_LONG_LONG_BITS) {
1094      MP_T *z = (MP_T *) item;
1095      ASSERT (io_read (FD (f), z, (size_t) SIZE (mode)) != -1);
1096      SET_INIT_MP (z);
1097    } else if (mode == M_ROW_CHAR || mode == M_STRING) {
1098      int len;
1099      ASSERT (io_read (FD (f), &(len), sizeof (len)) != -1);
1100      reset_transput_buffer (UNFORMATTED_BUFFER);
1101      for (int k = 0; k < len; k++) {
1102        char ch;
1103        ASSERT (io_read (FD (f), &(ch), sizeof (char)) != -1);
1104        plusab_transput_buffer (p, UNFORMATTED_BUFFER, ch);
1105      }
1106      *(A68G_REF *) item = c_to_a_string (p, get_transput_buffer (UNFORMATTED_BUFFER), DEFAULT_WIDTH);
1107    } else if (IS_UNION (mode)) {
1108      A68G_UNION *z = (A68G_UNION *) item;
1109      if (!(STATUS (z) | INIT_MASK) || VALUE (z) == NULL) {
1110        diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE, mode);
1111        exit_genie (p, A68G_RUNTIME_ERROR);
1112      }
1113      genie_read_bin_standard (p, (MOID_T *) (VALUE (z)), &item[A68G_UNION_SIZE], ref_file);
1114    } else if (IS_STRUCT (mode)) {
1115      for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
1116        genie_read_bin_standard (p, MOID (q), &item[OFFSET (q)], ref_file);
1117      }
1118    } else if (IS_ROW (mode) || IS_FLEX (mode)) {
1119      MOID_T *deflexed = DEFLEX (mode);
1120      A68G_ARRAY *arr; A68G_TUPLE *tup;
1121      CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
1122      GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
1123      if (get_row_size (tup, DIM (arr)) > 0) {
1124        BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
1125        BOOL_T done = A68G_FALSE;
1126        initialise_internal_index (tup, DIM (arr));
1127        while (!done) {
1128          ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
1129          ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
1130          genie_read_bin_standard (p, SUB (deflexed), &base_addr[elem_addr], ref_file);
1131          done = increment_internal_index (tup, DIM (arr));
1132        }
1133      }
1134    }
1135    if (errno != 0) {
1136      transput_error (p, ref_file, mode);
1137    }
1138  }
1139  
1140  
1141  //! @brief PROC ([] SIMPLIN) VOID read bin
1142  
1143  void genie_read_bin (NODE_T * p)
1144  {
1145    A68G_REF row;
1146    POP_REF (p, &row);
1147    genie_stand_back (p);
1148    PUSH_REF (p, row);
1149    genie_read_bin_file (p);
1150  }
1151  
1152  
1153  //! @brief PROC (REF FILE, [] SIMPLIN) VOID get bin
1154  
1155  void genie_read_bin_file (NODE_T * p)
1156  {
1157    A68G_REF row; A68G_ARRAY *arr; A68G_TUPLE *tup;
1158    POP_REF (p, &row);
1159    CHECK_REF (p, row, M_ROW_SIMPLIN);
1160    GET_DESCRIPTOR (arr, tup, &row);
1161    A68G_REF ref_file;
1162    POP_REF (p, &ref_file);
1163    ref_file = *(A68G_REF *) STACK_TOP;
1164    CHECK_REF (p, ref_file, M_REF_FILE);
1165    A68G_FILE *file = FILE_DEREF (&ref_file);
1166    CHECK_INIT (p, INITIALISED (file), M_FILE);
1167    if (!OPENED (file)) {
1168      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1169      exit_genie (p, A68G_RUNTIME_ERROR);
1170    }
1171    if (DRAW_MOOD (file)) {
1172      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1173      exit_genie (p, A68G_RUNTIME_ERROR);
1174    }
1175    if (WRITE_MOOD (file)) {
1176      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
1177      exit_genie (p, A68G_RUNTIME_ERROR);
1178    }
1179    if (!GET (&CHANNEL (file))) {
1180      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "getting");
1181      exit_genie (p, A68G_RUNTIME_ERROR);
1182    }
1183    if (!BIN (&CHANNEL (file))) {
1184      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "binary getting");
1185      exit_genie (p, A68G_RUNTIME_ERROR);
1186    }
1187    if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
1188      if ((FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS | O_BINARY, 0)) == A68G_NO_FILE) {
1189        open_error (p, ref_file, "binary getting");
1190      }
1191      DRAW_MOOD (file) = A68G_FALSE;
1192      READ_MOOD (file) = A68G_TRUE;
1193      WRITE_MOOD (file) = A68G_FALSE;
1194      CHAR_MOOD (file) = A68G_FALSE;
1195    }
1196    if (CHAR_MOOD (file)) {
1197      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "text");
1198      exit_genie (p, A68G_RUNTIME_ERROR);
1199    }
1200  // Read.
1201    INT_T elems = ROW_SIZE (tup);
1202    if (elems <= 0) {
1203      return;
1204    }
1205    BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
1206    INT_T elem_index = 0;
1207    for (INT_T k = 0; k < elems; k++) {
1208      A68G_UNION *z = (A68G_UNION *) & base_address[elem_index];
1209      MOID_T *mode = (MOID_T *) (VALUE (z));
1210      BYTE_T *item = (BYTE_T *) & base_address[elem_index + A68G_UNION_SIZE];
1211      genie_read_bin_standard (p, mode, item, ref_file);
1212      elem_index += SIZE (M_SIMPLIN);
1213    }
1214  }
1215  
1216  
1217  //! @brief Write object binary to file.
1218  
1219  void genie_write_bin_standard (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
1220  {
1221    CHECK_REF (p, ref_file, M_REF_FILE);
1222    A68G_FILE *f = FILE_DEREF (&ref_file);
1223    errno = 0;
1224    if (mode == M_PROC_REF_FILE_VOID) {
1225      genie_call_proc_ref_file_void (p, ref_file, *(A68G_PROCEDURE *) item);
1226    } else if (mode == M_FORMAT) {
1227      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_FORMAT);
1228      exit_genie (p, A68G_RUNTIME_ERROR);
1229    } else if (mode == M_SOUND) {
1230      write_sound (p, ref_file, (A68G_SOUND *) item);
1231    } else if (mode == M_INT) {
1232      ASSERT (io_write (FD (f), &(VALUE ((A68G_INT *) item)), sizeof (VALUE ((A68G_INT *) item))) != -1);
1233    } else if (mode == M_LONG_INT) {
1234      #if (A68G_LEVEL >= 3)
1235        ASSERT (io_write (FD (f), &(VALUE ((A68G_LONG_INT *) item)), sizeof (VALUE ((A68G_LONG_INT *) item))) != -1);
1236      #else
1237        ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1238      #endif
1239    } else if (mode == M_LONG_LONG_INT) {
1240      ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1241    } else if (mode == M_REAL) {
1242      ASSERT (io_write (FD (f), &(VALUE ((A68G_REAL *) item)), sizeof (VALUE ((A68G_REAL *) item))) != -1);
1243    } else if (mode == M_LONG_REAL) {
1244      #if (A68G_LEVEL >= 3)
1245        ASSERT (io_write (FD (f), &(VALUE ((A68G_LONG_REAL *) item)), sizeof (VALUE ((A68G_LONG_REAL *) item))) != -1);
1246      #else
1247        ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1248      #endif
1249    } else if (mode == M_LONG_LONG_REAL) {
1250      ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1251    } else if (mode == M_BOOL) {
1252      ASSERT (io_write (FD (f), &(VALUE ((A68G_BOOL *) item)), sizeof (VALUE ((A68G_BOOL *) item))) != -1);
1253    } else if (mode == M_CHAR) {
1254      ASSERT (io_write (FD (f), &(VALUE ((A68G_CHAR *) item)), sizeof (VALUE ((A68G_CHAR *) item))) != -1);
1255    } else if (mode == M_BITS) {
1256      ASSERT (io_write (FD (f), &(VALUE ((A68G_BITS *) item)), sizeof (VALUE ((A68G_BITS *) item))) != -1);
1257    } else if (mode == M_LONG_BITS) {
1258      #if (A68G_LEVEL >= 3)
1259        ASSERT (io_write (FD (f), &(VALUE ((A68G_LONG_BITS *) item)), sizeof (VALUE ((A68G_LONG_BITS *) item))) != -1);
1260      #else
1261        ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1262      #endif
1263    } else if (mode == M_LONG_LONG_BITS) {
1264      ASSERT (io_write (FD (f), (MP_T *) item, (size_t) SIZE (mode)) != -1);
1265    } else if (mode == M_ROW_CHAR || mode == M_STRING) {
1266      reset_transput_buffer (UNFORMATTED_BUFFER);
1267      add_a_string_transput_buffer (p, UNFORMATTED_BUFFER, item);
1268      int len = get_transput_buffer_index (UNFORMATTED_BUFFER);
1269      ASSERT (io_write (FD (f), &(len), sizeof (len)) != -1);
1270      WRITE (FD (f), get_transput_buffer (UNFORMATTED_BUFFER));
1271    } else if (IS_UNION (mode)) {
1272      A68G_UNION *z = (A68G_UNION *) item;
1273      genie_write_bin_standard (p, (MOID_T *) (VALUE (z)), &item[A68G_UNION_SIZE], ref_file);
1274    } else if (IS_STRUCT (mode)) {
1275      for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
1276        BYTE_T *elem = &item[OFFSET (q)];
1277        genie_check_initialisation (p, elem, MOID (q));
1278        genie_write_bin_standard (p, MOID (q), elem, ref_file);
1279      }
1280    } else if (IS_ROW (mode) || IS_FLEX (mode)) {
1281      MOID_T *deflexed = DEFLEX (mode);
1282      A68G_ARRAY *arr; A68G_TUPLE *tup;
1283      CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
1284      GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
1285      if (get_row_size (tup, DIM (arr)) > 0) {
1286        BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
1287        BOOL_T done = A68G_FALSE;
1288        initialise_internal_index (tup, DIM (arr));
1289        while (!done) {
1290          ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
1291          ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
1292          BYTE_T *elem = &base_addr[elem_addr];
1293          genie_check_initialisation (p, elem, SUB (deflexed));
1294          genie_write_bin_standard (p, SUB (deflexed), elem, ref_file);
1295          done = increment_internal_index (tup, DIM (arr));
1296        }
1297      }
1298    }
1299    if (errno != 0) {
1300      transput_error (p, ref_file, mode);
1301    }
1302  }
1303  
1304  
1305  //! @brief PROC ([] SIMPLOUT) VOID write bin, print bin
1306  
1307  void genie_write_bin (NODE_T * p)
1308  {
1309    A68G_REF row;
1310    POP_REF (p, &row);
1311    genie_stand_back (p);
1312    PUSH_REF (p, row);
1313    genie_write_bin_file (p);
1314  }
1315  
1316  
1317  //! @brief PROC (REF FILE, [] SIMPLOUT) VOID put bin
1318  
1319  void genie_write_bin_file (NODE_T * p)
1320  {
1321    A68G_REF row; A68G_ARRAY *arr; A68G_TUPLE *tup;
1322    POP_REF (p, &row);
1323    CHECK_REF (p, row, M_ROW_SIMPLOUT);
1324    GET_DESCRIPTOR (arr, tup, &row);
1325    A68G_REF ref_file;
1326    POP_REF (p, &ref_file);
1327    ref_file = *(A68G_REF *) STACK_TOP;
1328    CHECK_REF (p, ref_file, M_REF_FILE);
1329    A68G_FILE *file = FILE_DEREF (&ref_file);
1330    CHECK_INIT (p, INITIALISED (file), M_FILE);
1331    if (!OPENED (file)) {
1332      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1333      exit_genie (p, A68G_RUNTIME_ERROR);
1334    }
1335    if (DRAW_MOOD (file)) {
1336      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1337      exit_genie (p, A68G_RUNTIME_ERROR);
1338    }
1339    if (READ_MOOD (file)) {
1340      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "read");
1341      exit_genie (p, A68G_RUNTIME_ERROR);
1342    }
1343    if (!PUT (&CHANNEL (file))) {
1344      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "putting");
1345      exit_genie (p, A68G_RUNTIME_ERROR);
1346    }
1347    if (!BIN (&CHANNEL (file))) {
1348      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "binary putting");
1349      exit_genie (p, A68G_RUNTIME_ERROR);
1350    }
1351    if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
1352      if ((FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS | O_BINARY, A68G_PROTECTION)) == A68G_NO_FILE) {
1353        open_error (p, ref_file, "binary putting");
1354      }
1355      DRAW_MOOD (file) = A68G_FALSE;
1356      READ_MOOD (file) = A68G_FALSE;
1357      WRITE_MOOD (file) = A68G_TRUE;
1358      CHAR_MOOD (file) = A68G_FALSE;
1359    }
1360    if (CHAR_MOOD (file)) {
1361      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "text");
1362      exit_genie (p, A68G_RUNTIME_ERROR);
1363    }
1364    INT_T elems = ROW_SIZE (tup);
1365    if (elems <= 0) {
1366      return;
1367    }
1368    BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
1369    INT_T elem_index = 0;
1370    for (INT_T k = 0; k < elems; k++) {
1371      A68G_UNION *z = (A68G_UNION *) & base_address[elem_index];
1372      MOID_T *mode = (MOID_T *) (VALUE (z));
1373      BYTE_T *item = (BYTE_T *) & base_address[elem_index + A68G_UNION_SIZE];
1374      genie_write_bin_standard (p, mode, item, ref_file);
1375      elem_index += SIZE (M_SIMPLOUT);
1376    }
1377  }
1378  
1379  
1380  //! @brief PROC (NUMBER, INT) STRING rawout 
1381  
1382  void genie_rawout (NODE_T * p)
1383  {
1384    PUSH_STRING (p, rawout (p));
1385  }
1386  
1387  
1388  //! @brief PROC (NUMBER, INT) STRING whole
1389  
1390  void genie_whole (NODE_T * p)
1391  {
1392    PUSH_STRING (p, whole (p));
1393  }
1394  
1395  
1396  //! @brief PROC (NUMBER, INT, INT) STRING bits 
1397  
1398  void genie_bits (NODE_T * p)
1399  {
1400    PUSH_STRING (p, bits_to_string (p));
1401  }
1402  
1403  
1404  //! @brief PROC (NUMBER, INT, INT) STRING fixed
1405  
1406  void genie_fixed (NODE_T * p)
1407  {
1408    PUSH_STRING (p, fixed (p));
1409  }
1410  
1411  
1412  //! @brief PROC (NUMBER, INT, INT, INT) STRING eng
1413  
1414  void genie_real (NODE_T * p)
1415  {
1416    PUSH_STRING (p, real (p));
1417  }
1418  
1419  
1420  //! @brief PROC (NUMBER, INT, INT, INT) STRING float
1421  
1422  void genie_float (NODE_T * p)
1423  {
1424    PUSH_VALUE (p, 1, A68G_INT);
1425    genie_real (p);
1426  }
1427  
1428  // ALGOL68C routines.
1429  
1430  //! @def A68C_TRANSPUT
1431  
1432  //! @brief Generate Algol68C routines readint, getint, etcetera.
1433  
1434  #define A68C_TRANSPUT(n, m)\
1435   void genie_get_##n (NODE_T * p)\
1436    {\
1437      A68G_REF ref_file;\
1438      POP_REF (p, &ref_file);\
1439      CHECK_REF (p, ref_file, M_REF_FILE);\
1440      BYTE_T *z = STACK_TOP;\
1441      INCREMENT_STACK_POINTER (p, SIZE (MODE (m)));\
1442      ADDR_T pop_sp = A68G_SP;\
1443      open_for_reading (p, ref_file);\
1444      genie_read_standard (p, MODE (m), z, ref_file);\
1445      A68G_SP = pop_sp;\
1446    }\
1447    void genie_put_##n (NODE_T * p)\
1448    {\
1449      size_t size = SIZE (MODE (m)), sizf = SIZE (M_REF_FILE);\
1450      A68G_REF ref_file = * (A68G_REF *) STACK_OFFSET (- (size + sizf));\
1451      CHECK_REF (p, ref_file, M_REF_FILE);\
1452      reset_transput_buffer (UNFORMATTED_BUFFER);\
1453      open_for_writing (p, ref_file);\
1454      genie_write_standard (p, MODE (m), STACK_OFFSET (-size), ref_file);\
1455      write_purge_buffer (p, ref_file, UNFORMATTED_BUFFER);\
1456      DECREMENT_STACK_POINTER (p, size + sizf);\
1457    }\
1458    void genie_read_##n (NODE_T * p)\
1459    {\
1460      BYTE_T *z = STACK_TOP;\
1461      INCREMENT_STACK_POINTER (p, SIZE (MODE (m)));\
1462      ADDR_T pop_sp = A68G_SP;\
1463      open_for_reading (p, A68G (stand_in));\
1464      genie_read_standard (p, MODE (m), z, A68G (stand_in));\
1465      A68G_SP = pop_sp;\
1466    }\
1467    void genie_print_##n (NODE_T * p)\
1468    {\
1469      size_t size = SIZE (MODE (m));\
1470      reset_transput_buffer (UNFORMATTED_BUFFER);\
1471      open_for_writing (p, A68G (stand_out));\
1472      genie_write_standard (p, MODE (m), STACK_OFFSET (-size), A68G (stand_out));\
1473      write_purge_buffer (p, A68G (stand_out), UNFORMATTED_BUFFER);\
1474      DECREMENT_STACK_POINTER (p, size);\
1475    }
1476  
1477  A68C_TRANSPUT (int, INT);
1478  A68C_TRANSPUT (long_int, LONG_INT);
1479  A68C_TRANSPUT (long_mp_int, LONG_LONG_INT);
1480  A68C_TRANSPUT (real, REAL);
1481  A68C_TRANSPUT (long_real, LONG_REAL);
1482  A68C_TRANSPUT (long_mp_real, LONG_LONG_REAL);
1483  A68C_TRANSPUT (bits, BITS);
1484  A68C_TRANSPUT (long_bits, LONG_BITS);
1485  A68C_TRANSPUT (long_mp_bits, LONG_LONG_BITS);
1486  A68C_TRANSPUT (bool, BOOL);
1487  A68C_TRANSPUT (char, CHAR);
1488  A68C_TRANSPUT (string, STRING);
1489  
1490  #undef A68C_TRANSPUT
1491  
1492  #define A68C_TRANSPUT(n, s, m)\
1493   void genie_get_##n (NODE_T * p) {\
1494      A68G_REF ref_file;\
1495      POP_REF (p, &ref_file);\
1496      CHECK_REF (p, ref_file, M_REF_FILE);\
1497      PUSH_REF (p, ref_file);\
1498      genie_get_##s (p);\
1499      PUSH_REF (p, ref_file);\
1500      genie_get_##s (p);\
1501    }\
1502    void genie_put_##n (NODE_T * p) {\
1503      size_t size = SIZE (MODE (m)), sizf = SIZE (M_REF_FILE);\
1504      A68G_REF ref_file = * (A68G_REF *) STACK_OFFSET (- (size + sizf));\
1505      CHECK_REF (p, ref_file, M_REF_FILE);\
1506      reset_transput_buffer (UNFORMATTED_BUFFER);\
1507      open_for_writing (p, ref_file);\
1508      genie_write_standard (p, MODE (m), STACK_OFFSET (-size), ref_file);\
1509      write_purge_buffer (p, ref_file, UNFORMATTED_BUFFER);\
1510      DECREMENT_STACK_POINTER (p, size + sizf);\
1511    }\
1512    void genie_read_##n (NODE_T * p) {\
1513      genie_read_##s (p);\
1514      genie_read_##s (p);\
1515    }\
1516    void genie_print_##n (NODE_T * p) {\
1517      size_t size = SIZE (MODE (m));\
1518      reset_transput_buffer (UNFORMATTED_BUFFER);\
1519      open_for_writing (p, A68G (stand_out));\
1520      genie_write_standard (p, MODE (m), STACK_OFFSET (-size), A68G (stand_out));\
1521      write_purge_buffer (p, A68G (stand_out), UNFORMATTED_BUFFER);\
1522      DECREMENT_STACK_POINTER (p, size);\
1523    }
1524  
1525  A68C_TRANSPUT (complex, real, COMPLEX);
1526  A68C_TRANSPUT (mp_complex, long_real, LONG_COMPLEX);
1527  A68C_TRANSPUT (long_mp_complex, long_mp_real, LONG_LONG_COMPLEX);
1528  
1529  #undef A68C_TRANSPUT
1530  
1531  void genie_peek_char (NODE_T * p)
1532  {
1533    A68G_INT mode;
1534    POP_OBJECT (p, &mode, A68G_INT);
1535    CHECK_INIT (p, INITIALISED (&mode), M_INT);
1536    PUSH_VALUE (p, (char) peek_char (VALUE (&mode)), A68G_CHAR);
1537  }
1538  
1539  
1540  //! @brief PROC STRING read line
1541  
1542  void genie_read_line (NODE_T * p)
1543  {
1544    #if defined (HAVE_READLINE)
1545      char *line = readline ("");
1546      if (line != NO_TEXT && strlen (line) > 0) {
1547        add_history (line);
1548      }
1549      PUSH_REF (p, c_to_a_string (p, line, DEFAULT_WIDTH));
1550      a68g_free (line);
1551    #else
1552      genie_read_string (p);
1553      genie_stand_in (p);
1554      genie_new_line (p);
1555    #endif
1556  }
     

This website is archived by the National Library of the Netherlands.

© J.M. van der Veer   •   jmvdveer@algol68genie.nl