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