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-2025 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  // These routines fail in principle when 'read' or 'write' are interrupted 
  27  // MAX_RESTART_AT_INTERRUPT times, for instance by SIGALRM.
  28  //
  29  // On platforms that support it, SIGALRM is used to implement a CPU time out 
  30  // on a running Algol 68 program. 
  31  //
  32  // The SIGALRM handler however implements BSD type restarting of primitive
  33  // system call interupted by it, which includes 'read' and 'write'. 
  34  // Consider however that non-responsive devices could make a68g 'hang'. 
  35  // In that case, specify option NORESTART, and SIGALRM will interrupt IO.
  36  // Current settings make these routines fail after 10 minutes of trying.
  37  
  38  #include "a68g.h"
  39  #include "a68g-prelude.h"
  40  
  41  //! @brief Initialise output to STDOUT.
  42  
  43  void init_tty (void)
  44  {
  45    A68G (chars_in_stderr) = 0;
  46    A68G (chars_in_stdout) = 0;
  47    A68G (halt_typing) = A68G_FALSE;
  48    change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_INTERRUPT_MASK, A68G_FALSE);
  49  }
  50  
  51  //! @brief Terminate current line on STDOUT.
  52  
  53  void io_close_tty_line (void)
  54  {
  55    if (A68G (chars_in_stderr) > 0) {
  56      A68G (chars_in_stderr) = 0;
  57      io_write_string (A68G_STDERR, NEWLINE_STRING);
  58    }
  59    if (A68G (chars_in_stdout) > 0) {
  60      A68G (chars_in_stdout) = 0;
  61      io_write_string (A68G_STDOUT, NEWLINE_STRING);
  62    }
  63  }
  64  
  65  //! @brief Get a char from STDIN.
  66  
  67  char get_stdin_char (void)
  68  {
  69    char ch[4];
  70    errno = 0;
  71    ssize_t j = io_read_conv (A68G_STDIN, &(ch[0]), 1);
  72    ABEND (j < 0, ERROR_ACTION, NO_TEXT);
  73    return (char) (j == 1 ? ch[0] : EOF_CHAR);
  74  }
  75  
  76  //! @brief Read string from STDIN, until NEWLINE_STRING.
  77  
  78  char *read_string_from_tty (char *prompt)
  79  {
  80    #if defined (HAVE_READLINE)
  81      char *line = readline (prompt);
  82      if (line != NO_TEXT && strlen (line) > 0) {
  83        add_history (line);
  84      }
  85      a68g_bufcpy (A68G (input_line), line, BUFFER_SIZE);
  86      A68G (chars_in_stdout) = strlen (A68G (input_line));
  87      a68g_free (line);
  88      return A68G (input_line);
  89    #else
  90      if (prompt != NO_TEXT) {
  91        io_close_tty_line ();
  92        io_write_string (A68G_STDOUT, prompt);
  93      }
  94      int ch = get_stdin_char (), k= 0;
  95      while (ch != NEWLINE_CHAR && k < BUFFER_SIZE - 1) {
  96        if (ch == EOF_CHAR) {
  97          A68G (input_line)[0] = EOF_CHAR;
  98          A68G (input_line)[1] = NULL_CHAR;
  99          A68G (chars_in_stdout) = 1;
 100          return A68G (input_line);
 101        } else {
 102          A68G (input_line)[k++] = (char) ch;
 103          ch = get_stdin_char ();
 104        }
 105      }
 106      A68G (input_line)[k] = NULL_CHAR;
 107      size_t n = strlen (A68G (input_line));
 108      A68G (chars_in_stdout) = (ch == NEWLINE_CHAR ? 0 : (n > 0 ? n : 1));
 109      return A68G (input_line);
 110    #endif
 111  }
 112  
 113  //! @brief Write string to file.
 114  
 115  void io_write_string (FILE_T f, const char *z)
 116  {
 117    errno = 0;
 118    if (f != A68G_STDOUT && f != A68G_STDERR) {
 119  // Writing to file.
 120      ssize_t j = io_write_conv (f, z, strlen (z));
 121      ABEND (j < 0, ERROR_ACTION, NO_TEXT);
 122    } else {
 123  // Writing to TTY parts until end-of-string.
 124      int first = 0, k;
 125      do {
 126        k = first;
 127  // How far can we get?.
 128        while (z[k] != NULL_CHAR && z[k] != NEWLINE_CHAR) {
 129          k++;
 130        }
 131        if (k > first) {
 132  // Write these characters.
 133          int n = k - first;
 134          ssize_t j = io_write_conv (f, &(z[first]), (size_t) n);
 135          ABEND (j < 0, ERROR_ACTION, NO_TEXT);
 136          if (f == A68G_STDERR) {
 137            A68G (chars_in_stderr) += n;
 138          } else {
 139            A68G (chars_in_stdout) += n;
 140          }
 141        }
 142        if (z[k] == NEWLINE_CHAR) {
 143  // Pretty-print newline.
 144          k++;
 145          first = k;
 146          ssize_t j = io_write_conv (f, NEWLINE_STRING, 1);
 147          ABEND (j < 0, ERROR_ACTION, NO_TEXT);
 148          if (f == A68G_STDERR) {
 149            A68G (chars_in_stderr) = 0;
 150          } else {
 151            A68G (chars_in_stdout) = 0;
 152          }
 153        }
 154      } while (z[k] != NULL_CHAR);
 155    }
 156  }
 157  
 158  //! @brief Read bytes from file into buffer.
 159  
 160  ssize_t io_read (FILE_T fd, void *buf, size_t n)
 161  {
 162    size_t to_do = n;
 163    int retry = 0;
 164    char *z = (char *) buf;
 165    while (to_do > 0) {
 166      #if defined (BUILD_WIN32)
 167        int bytes_read;
 168      #elif defined (BUILD_WIN64)
 169        ssize_t bytes_read;
 170      #else
 171        ssize_t bytes_read;
 172      #endif
 173      errno = 0;
 174      bytes_read = read (fd, z, to_do);
 175      if (bytes_read < 0) {
 176        if (errno == EINTR) {
 177  // interrupt, retry.
 178          bytes_read = 0;
 179          if (++retry > MAX_INTERRUPT_RESTART) {
 180            return -1;
 181          }
 182        } else {
 183  // read error.
 184          return -1;
 185        }
 186      } else if (bytes_read == 0) {
 187        break;                    // EOF_CHAR
 188      }
 189      to_do -= (size_t) bytes_read;
 190      z += bytes_read;
 191    }
 192    return (ssize_t) n - (ssize_t) to_do; // return >= 0
 193  }
 194  
 195  //! @brief Writes n bytes from buffer to file.
 196  
 197  ssize_t io_write (FILE_T fd, const void *buf, size_t n)
 198  {
 199    size_t to_do = n;
 200    int retry = 0;
 201    char *z = (char *) buf;
 202    while (to_do > 0) {
 203      ssize_t bytes_written;
 204      errno = 0;
 205      bytes_written = write (fd, z, to_do);
 206      if (bytes_written <= 0) {
 207        if (errno == EINTR) {
 208  // interrupt, retry.
 209          bytes_written = 0;
 210          if (++retry > MAX_INTERRUPT_RESTART) {
 211            return -1;
 212          }
 213        } else {
 214  // write error.
 215          return -1;
 216        }
 217      }
 218      to_do -= (size_t) bytes_written;
 219      z += bytes_written;
 220    }
 221    return (ssize_t) n;
 222  }
 223  
 224  //! @brief Read bytes from file into buffer.
 225  
 226  ssize_t io_read_conv (FILE_T fd, void *buf, size_t n)
 227  {
 228    size_t to_do = n;
 229    int retry = 0;
 230    char *z = (char *) buf;
 231    while (to_do > 0) {
 232      #if defined (BUILD_WIN32)
 233        int bytes_read;
 234      #elif defined (BUILD_WIN64)
 235        ssize_t bytes_read;
 236      #else
 237        ssize_t bytes_read;
 238      #endif
 239      errno = 0;
 240      bytes_read = read (fd, z, to_do);
 241      if (bytes_read < 0) {
 242        if (errno == EINTR) {
 243  // interrupt, retry.
 244          bytes_read = 0;
 245          if (++retry > MAX_INTERRUPT_RESTART) {
 246            return -1;
 247          }
 248        } else {
 249  // read error.
 250          return -1;
 251        }
 252      } else if (bytes_read == 0) {
 253        break;                    // EOF_CHAR
 254      }
 255      to_do -= (size_t) bytes_read;
 256      z += bytes_read;
 257    }
 258    return (ssize_t) n - (ssize_t) to_do;
 259  }
 260  
 261  //! @brief Writes n bytes from buffer to file.
 262  
 263  ssize_t io_write_conv (FILE_T fd, const void *buf, size_t n)
 264  {
 265    size_t to_do = n;
 266    int retry = 0;
 267    char *z = (char *) buf;
 268    while (to_do > 0) {
 269      ssize_t bytes_written;
 270      errno = 0;
 271      bytes_written = write (fd, z, to_do);
 272      if (bytes_written <= 0) {
 273        if (errno == EINTR) {
 274  // interrupt, retry.
 275          bytes_written = 0;
 276          if (++retry > MAX_INTERRUPT_RESTART) {
 277            return -1;
 278          }
 279        } else {
 280  // write error.
 281          return -1;
 282        }
 283      }
 284      to_do -= (size_t) bytes_written;
 285      z += bytes_written;
 286    }
 287    return (ssize_t) n;
 288  }
     


© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)