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-2023 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_tty_line) = 0;
  34    A68 (halt_typing) = A68_FALSE;
  35    change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_INTERRUPT_MASK, A68_FALSE);
  36  }
  37  
  38  //! @brief Terminate current line on STDOUT.
  39  
  40  void io_close_tty_line (void)
  41  {
  42    if (A68 (chars_in_tty_line) > 0) {
  43      io_write_string (A68_STDOUT, NEWLINE_STRING);
  44    }
  45  }
  46  
  47  //! @brief Get a char from STDIN.
  48  
  49  char get_stdin_char (void)
  50  {
  51    char ch[4];
  52    errno = 0;
  53    ssize_t j = io_read_conv (A68_STDIN, &(ch[0]), 1);
  54    ABEND (j < 0, ERROR_ACTION, __func__);
  55    return (char) (j == 1 ? ch[0] : EOF_CHAR);
  56  }
  57  
  58  //! @brief Read string from STDIN, until NEWLINE_STRING.
  59  
  60  char *read_string_from_tty (char *prompt)
  61  {
  62  #if defined (HAVE_READLINE)
  63    char *line = readline (prompt);
  64    if (line != NO_TEXT && (int) strlen (line) > 0) {
  65      add_history (line);
  66    }
  67    bufcpy (A68 (input_line), line, BUFFER_SIZE);
  68    A68 (chars_in_tty_line) = (int) strlen (A68 (input_line));
  69    a68_free (line);
  70    return A68 (input_line);
  71  #else
  72    int ch, k = 0, n;
  73    if (prompt != NO_TEXT) {
  74      io_close_tty_line ();
  75      io_write_string (A68_STDOUT, prompt);
  76    }
  77    ch = get_stdin_char ();
  78    while (ch != NEWLINE_CHAR && k < BUFFER_SIZE - 1) {
  79      if (ch == EOF_CHAR) {
  80        A68 (input_line)[0] = EOF_CHAR;
  81        A68 (input_line)[1] = NULL_CHAR;
  82        A68 (chars_in_tty_line) = 1;
  83        return A68 (input_line);
  84      } else {
  85        A68 (input_line)[k++] = (char) ch;
  86        ch = get_stdin_char ();
  87      }
  88    }
  89    A68 (input_line)[k] = NULL_CHAR;
  90    n = (int) strlen (A68 (input_line));
  91    A68 (chars_in_tty_line) = (ch == NEWLINE_CHAR ? 0 : (n > 0 ? n : 1));
  92    return A68 (input_line);
  93  #endif
  94  }
  95  
  96  //! @brief Write string to file.
  97  
  98  void io_write_string (FILE_T f, const char *z)
  99  {
 100    errno = 0;
 101    if (f != A68_STDOUT && f != A68_STDERR) {
 102  // Writing to file.
 103      ssize_t j = io_write_conv (f, z, strlen (z));
 104      ABEND (j < 0, ERROR_ACTION, __func__);
 105    } else {
 106  // Writing to TTY parts until end-of-string.
 107      int first = 0, k;
 108      do {
 109        k = first;
 110  // How far can we get?.
 111        while (z[k] != NULL_CHAR && z[k] != NEWLINE_CHAR) {
 112          k++;
 113        }
 114        if (k > first) {
 115  // Write these characters.
 116          int n = k - first;
 117          ssize_t j = io_write_conv (f, &(z[first]), (size_t) n);
 118          ABEND (j < 0, ERROR_ACTION, __func__);
 119          A68 (chars_in_tty_line) += n;
 120        }
 121        if (z[k] == NEWLINE_CHAR) {
 122  // Pretty-print newline.
 123          k++;
 124          first = k;
 125          ssize_t j = io_write_conv (f, NEWLINE_STRING, 1);
 126          ABEND (j < 0, ERROR_ACTION, __func__);
 127          A68 (chars_in_tty_line) = 0;
 128        }
 129      } while (z[k] != NULL_CHAR);
 130    }
 131  }
 132  
 133  //! @brief Read bytes from file into buffer.
 134  
 135  ssize_t io_read (FILE_T fd, void *buf, size_t n)
 136  {
 137    size_t to_do = n;
 138    int restarts = 0;
 139    char *z = (char *) buf;
 140    while (to_do > 0) {
 141  #if defined (BUILD_WIN32)
 142      int bytes_read;
 143  #else
 144      ssize_t bytes_read;
 145  #endif
 146      errno = 0;
 147      bytes_read = read (fd, z, to_do);
 148      if (bytes_read < 0) {
 149        if (errno == EINTR) {
 150  // interrupt, retry.
 151          bytes_read = 0;
 152          if (restarts++ > MAX_RESTART) {
 153            return -1;
 154          }
 155        } else {
 156  // read error.
 157          return -1;
 158        }
 159      } else if (bytes_read == 0) {
 160        break;                    // EOF_CHAR
 161      }
 162      to_do -= (size_t) bytes_read;
 163      z += bytes_read;
 164    }
 165    return (ssize_t) n - (ssize_t) to_do; // return >= 0
 166  }
 167  
 168  //! @brief Writes n bytes from buffer to file.
 169  
 170  ssize_t io_write (FILE_T fd, const void *buf, size_t n)
 171  {
 172    size_t to_do = n;
 173    int restarts = 0;
 174    char *z = (char *) buf;
 175    while (to_do > 0) {
 176      ssize_t bytes_written;
 177      errno = 0;
 178      bytes_written = write (fd, z, to_do);
 179      if (bytes_written <= 0) {
 180        if (errno == EINTR) {
 181  // interrupt, retry.
 182          bytes_written = 0;
 183          if (restarts++ > MAX_RESTART) {
 184            return -1;
 185          }
 186        } else {
 187  // write error.
 188          return -1;
 189        }
 190      }
 191      to_do -= (size_t) bytes_written;
 192      z += bytes_written;
 193    }
 194    return (ssize_t) n;
 195  }
 196  
 197  //! @brief Read bytes from file into buffer.
 198  
 199  ssize_t io_read_conv (FILE_T fd, void *buf, size_t n)
 200  {
 201    size_t to_do = n;
 202    int restarts = 0;
 203    char *z = (char *) buf;
 204    while (to_do > 0) {
 205  #if defined (BUILD_WIN32)
 206      int bytes_read;
 207  #else
 208      ssize_t bytes_read;
 209  #endif
 210      errno = 0;
 211      bytes_read = read (fd, z, to_do);
 212      if (bytes_read < 0) {
 213        if (errno == EINTR) {
 214  // interrupt, retry.
 215          bytes_read = 0;
 216          if (restarts++ > MAX_RESTART) {
 217            return -1;
 218          }
 219        } else {
 220  // read error.
 221          return -1;
 222        }
 223      } else if (bytes_read == 0) {
 224        break;                    // EOF_CHAR
 225      }
 226      to_do -= (size_t) bytes_read;
 227      z += bytes_read;
 228    }
 229    return (ssize_t) n - (ssize_t) to_do;
 230  }
 231  
 232  //! @brief Writes n bytes from buffer to file.
 233  
 234  ssize_t io_write_conv (FILE_T fd, const void *buf, size_t n)
 235  {
 236    size_t to_do = n;
 237    int restarts = 0;
 238    char *z = (char *) buf;
 239    while (to_do > 0) {
 240      ssize_t bytes_written;
 241      errno = 0;
 242      bytes_written = write (fd, z, to_do);
 243      if (bytes_written <= 0) {
 244        if (errno == EINTR) {
 245  // interrupt, retry.
 246          bytes_written = 0;
 247          if (restarts++ > MAX_RESTART) {
 248            return -1;
 249          }
 250        } else {
 251  // write error.
 252          return -1;
 253        }
 254      }
 255      to_do -= (size_t) bytes_written;
 256      z += bytes_written;
 257    }
 258    return (ssize_t) n;
 259  }