a68g-io.c

     
   1  //! @file a68g-io.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
   8  
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it 
  12  //! under the terms of the GNU General Public License as published by the 
  13  //! Free Software Foundation; either version 3 of the License, or 
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but 
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  //! more details. You should have received a copy of the GNU General Public 
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis
  23  //!
  24  //! Low-level input-output routines.
  25  
  26  #include "a68g.h"
  27  #include "a68g-prelude.h"
  28  
  29  //! @brief Initialise output to STDOUT.
  30  
  31  void init_tty (void)
  32  {
  33    A68 (chars_in_stderr) = 0;
  34    A68 (chars_in_stdout) = 0;
  35    A68 (halt_typing) = A68_FALSE;
  36    change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_INTERRUPT_MASK, A68_FALSE);
  37  }
  38  
  39  //! @brief Terminate current line on STDOUT.
  40  
  41  void io_close_tty_line (void)
  42  {
  43    if (A68 (chars_in_stderr) > 0) {
  44      A68 (chars_in_stderr) = 0;
  45      io_write_string (A68_STDERR, NEWLINE_STRING);
  46    }
  47    if (A68 (chars_in_stdout) > 0) {
  48      A68 (chars_in_stdout) = 0;
  49      io_write_string (A68_STDOUT, NEWLINE_STRING);
  50    }
  51  }
  52  
  53  //! @brief Get a char from STDIN.
  54  
  55  char get_stdin_char (void)
  56  {
  57    char ch[4];
  58    errno = 0;
  59    ssize_t j = io_read_conv (A68_STDIN, &(ch[0]), 1);
  60    ABEND (j < 0, ERROR_ACTION, __func__);
  61    return (char) (j == 1 ? ch[0] : EOF_CHAR);
  62  }
  63  
  64  //! @brief Read string from STDIN, until NEWLINE_STRING.
  65  
  66  char *read_string_from_tty (char *prompt)
  67  {
  68  #if defined (HAVE_READLINE)
  69    char *line = readline (prompt);
  70    if (line != NO_TEXT && (int) strlen (line) > 0) {
  71      add_history (line);
  72    }
  73    a68_bufcpy (A68 (input_line), line, BUFFER_SIZE);
  74    A68 (chars_in_stdout) = (int) strlen (A68 (input_line));
  75    a68_free (line);
  76    return A68 (input_line);
  77  #else
  78    int ch, k = 0, n;
  79    if (prompt != NO_TEXT) {
  80      io_close_tty_line ();
  81      io_write_string (A68_STDOUT, prompt);
  82    }
  83    ch = get_stdin_char ();
  84    while (ch != NEWLINE_CHAR && k < BUFFER_SIZE - 1) {
  85      if (ch == EOF_CHAR) {
  86        A68 (input_line)[0] = EOF_CHAR;
  87        A68 (input_line)[1] = NULL_CHAR;
  88        A68 (chars_in_stdout) = 1;
  89        return A68 (input_line);
  90      } else {
  91        A68 (input_line)[k++] = (char) ch;
  92        ch = get_stdin_char ();
  93      }
  94    }
  95    A68 (input_line)[k] = NULL_CHAR;
  96    n = (int) strlen (A68 (input_line));
  97    A68 (chars_in_stdout) = (ch == NEWLINE_CHAR ? 0 : (n > 0 ? n : 1));
  98    return A68 (input_line);
  99  #endif
 100  }
 101  
 102  //! @brief Write string to file.
 103  
 104  void io_write_string (FILE_T f, const char *z)
 105  {
 106    errno = 0;
 107    if (f != A68_STDOUT && f != A68_STDERR) {
 108  // Writing to file.
 109      ssize_t j = io_write_conv (f, z, strlen (z));
 110      ABEND (j < 0, ERROR_ACTION, __func__);
 111    } else {
 112  // Writing to TTY parts until end-of-string.
 113      int first = 0, k;
 114      do {
 115        k = first;
 116  // How far can we get?.
 117        while (z[k] != NULL_CHAR && z[k] != NEWLINE_CHAR) {
 118          k++;
 119        }
 120        if (k > first) {
 121  // Write these characters.
 122          int n = k - first;
 123          ssize_t j = io_write_conv (f, &(z[first]), (size_t) n);
 124          ABEND (j < 0, ERROR_ACTION, __func__);
 125          if (f == A68_STDERR) {
 126            A68 (chars_in_stderr) += n;
 127          } else {
 128            A68 (chars_in_stdout) += n;
 129          }
 130        }
 131        if (z[k] == NEWLINE_CHAR) {
 132  // Pretty-print newline.
 133          k++;
 134          first = k;
 135          ssize_t j = io_write_conv (f, NEWLINE_STRING, 1);
 136          ABEND (j < 0, ERROR_ACTION, __func__);
 137          if (f == A68_STDERR) {
 138            A68 (chars_in_stderr) = 0;
 139          } else {
 140            A68 (chars_in_stdout) = 0;
 141          }
 142        }
 143      } while (z[k] != NULL_CHAR);
 144    }
 145  }
 146  
 147  //! @brief Read bytes from file into buffer.
 148  
 149  ssize_t io_read (FILE_T fd, void *buf, size_t n)
 150  {
 151    size_t to_do = n;
 152    int restarts = 0;
 153    char *z = (char *) buf;
 154    while (to_do > 0) {
 155  #if defined (BUILD_WIN32)
 156      int bytes_read;
 157  #else
 158      ssize_t bytes_read;
 159  #endif
 160      errno = 0;
 161      bytes_read = read (fd, z, to_do);
 162      if (bytes_read < 0) {
 163        if (errno == EINTR) {
 164  // interrupt, retry.
 165          bytes_read = 0;
 166          if (restarts++ > MAX_RESTART) {
 167            return -1;
 168          }
 169        } else {
 170  // read error.
 171          return -1;
 172        }
 173      } else if (bytes_read == 0) {
 174        break;                    // EOF_CHAR
 175      }
 176      to_do -= (size_t) bytes_read;
 177      z += bytes_read;
 178    }
 179    return (ssize_t) n - (ssize_t) to_do; // return >= 0
 180  }
 181  
 182  //! @brief Writes n bytes from buffer to file.
 183  
 184  ssize_t io_write (FILE_T fd, const void *buf, size_t n)
 185  {
 186    size_t to_do = n;
 187    int restarts = 0;
 188    char *z = (char *) buf;
 189    while (to_do > 0) {
 190      ssize_t bytes_written;
 191      errno = 0;
 192      bytes_written = write (fd, z, to_do);
 193      if (bytes_written <= 0) {
 194        if (errno == EINTR) {
 195  // interrupt, retry.
 196          bytes_written = 0;
 197          if (restarts++ > MAX_RESTART) {
 198            return -1;
 199          }
 200        } else {
 201  // write error.
 202          return -1;
 203        }
 204      }
 205      to_do -= (size_t) bytes_written;
 206      z += bytes_written;
 207    }
 208    return (ssize_t) n;
 209  }
 210  
 211  //! @brief Read bytes from file into buffer.
 212  
 213  ssize_t io_read_conv (FILE_T fd, void *buf, size_t n)
 214  {
 215    size_t to_do = n;
 216    int restarts = 0;
 217    char *z = (char *) buf;
 218    while (to_do > 0) {
 219  #if defined (BUILD_WIN32)
 220      int bytes_read;
 221  #else
 222      ssize_t bytes_read;
 223  #endif
 224      errno = 0;
 225      bytes_read = read (fd, z, to_do);
 226      if (bytes_read < 0) {
 227        if (errno == EINTR) {
 228  // interrupt, retry.
 229          bytes_read = 0;
 230          if (restarts++ > MAX_RESTART) {
 231            return -1;
 232          }
 233        } else {
 234  // read error.
 235          return -1;
 236        }
 237      } else if (bytes_read == 0) {
 238        break;                    // EOF_CHAR
 239      }
 240      to_do -= (size_t) bytes_read;
 241      z += bytes_read;
 242    }
 243    return (ssize_t) n - (ssize_t) to_do;
 244  }
 245  
 246  //! @brief Writes n bytes from buffer to file.
 247  
 248  ssize_t io_write_conv (FILE_T fd, const void *buf, size_t n)
 249  {
 250    size_t to_do = n;
 251    int restarts = 0;
 252    char *z = (char *) buf;
 253    while (to_do > 0) {
 254      ssize_t bytes_written;
 255      errno = 0;
 256      bytes_written = write (fd, z, to_do);
 257      if (bytes_written <= 0) {
 258        if (errno == EINTR) {
 259  // interrupt, retry.
 260          bytes_written = 0;
 261          if (restarts++ > MAX_RESTART) {
 262            return -1;
 263          }
 264        } else {
 265  // write error.
 266          return -1;
 267        }
 268      }
 269      to_do -= (size_t) bytes_written;
 270      z += bytes_written;
 271    }
 272    return (ssize_t) n;
 273  }