Merge remote-tracking branch 'origin/stable-2.0'
authorAndy Wingo <wingo@pobox.com>
Tue, 8 May 2012 20:43:04 +0000 (22:43 +0200)
committerAndy Wingo <wingo@pobox.com>
Tue, 8 May 2012 20:43:04 +0000 (22:43 +0200)
Conflicts:
libguile/ports.c
libguile/ports.h
libguile/read.c
libguile/vm-i-system.c

1  2 
configure.ac
libguile/fports.c
libguile/ports.c
libguile/ports.h
libguile/read.c
libguile/vm-i-system.c

diff --cc configure.ac
Simple merge
@@@ -211,12 -212,24 +212,24 @@@ SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 
    pt = SCM_PTAB_ENTRY (port);
  
    if (SCM_INPUT_PORT_P (port))
-     drained = scm_drain_input (port);
+     {
+       /* Drain pending input from PORT.  Don't use `scm_drain_input' since
+        it returns a string, whereas we want binary input here.  */
+       ndrained = pt->read_end - pt->read_pos;
+       if (pt->read_buf == pt->putback_buf)
+       ndrained += pt->saved_read_end - pt->saved_read_pos;
+       if (ndrained > 0)
+       {
+         drained = scm_gc_malloc_pointerless (ndrained, "file port");
+         scm_take_from_input_buffers (port, drained, ndrained);
+       }
+     }
    else
-     drained = scm_nullstr;
+     ndrained = 0;
  
    if (SCM_OUTPUT_PORT_P (port))
 -    scm_flush (port);
 +    scm_flush_unlocked (port);
  
    if (pt->read_buf == pt->putback_buf)
      {
@@@ -2047,183 -1903,192 +2047,185 @@@ SCM_DEFINE (scm_unread_string, "unread-
  }
  #undef FUNC_NAME
  
 -SCM_DEFINE (scm_seek, "seek", 3, 0, 0,
 -            (SCM fd_port, SCM offset, SCM whence),
 -          "Sets the current position of @var{fd_port} to the integer\n"
 -          "@var{offset}, which is interpreted according to the value of\n"
 -          "@var{whence}.\n"
 -          "\n"
 -          "One of the following variables should be supplied for\n"
 -          "@var{whence}:\n"
 -          "@defvar SEEK_SET\n"
 -          "Seek from the beginning of the file.\n"
 -          "@end defvar\n"
 -          "@defvar SEEK_CUR\n"
 -          "Seek from the current position.\n"
 -          "@end defvar\n"
 -          "@defvar SEEK_END\n"
 -          "Seek from the end of the file.\n"
 -          "@end defvar\n"
 -          "If @var{fd_port} is a file descriptor, the underlying system\n"
 -          "call is @code{lseek}.  @var{port} may be a string port.\n"
 -          "\n"
 -          "The value returned is the new position in the file.  This means\n"
 -          "that the current position of a port can be obtained using:\n"
 -          "@lisp\n"
 -          "(seek port 0 SEEK_CUR)\n"
 -          "@end lisp")
 -#define FUNC_NAME s_scm_seek
 -{
 -  int how;
  
 -  fd_port = SCM_COERCE_OUTPORT (fd_port);
 +\f
  
 -  how = scm_to_int (whence);
 -  if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
 -    SCM_OUT_OF_RANGE (3, whence);
 +/* Manipulating the buffers.  */
  
 -  if (SCM_OPPORTP (fd_port))
 -    {
 -      scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (fd_port);
 -      off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
 -      off_t_or_off64_t rv;
 +/* This routine does not take any locks, as it is usually called as part
 +   of a port implementation.  */
 +void
 +scm_port_non_buffer (scm_t_port *pt)
 +{
 +  pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
 +  pt->write_buf = pt->write_pos = &pt->shortbuf;
 +  pt->read_buf_size = pt->write_buf_size = 1;
 +  pt->write_end = pt->write_buf + pt->write_buf_size;
 +}
  
 -      if (!ptob->seek)
 -      SCM_MISC_ERROR ("port is not seekable", 
 -                        scm_cons (fd_port, SCM_EOL));
 -      else
 -      rv = ptob->seek (fd_port, off, how);
 -      return scm_from_off_t_or_off64_t (rv);
 -    }
 -  else /* file descriptor?.  */
 +/* this should only be called when the read buffer is empty.  it
 +   tries to refill the read buffer.  it returns the first char from
 +   the port, which is either EOF or *(pt->read_pos).  */
 +int
 +scm_fill_input_unlocked (SCM port)
 +{
 +  scm_t_port *pt = SCM_PTAB_ENTRY (port);
 +
 +  assert (pt->read_pos == pt->read_end);
 +
 +  if (pt->read_buf == pt->putback_buf)
      {
 -      off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
 -      off_t_or_off64_t rv;
 -      rv = lseek_or_lseek64 (scm_to_int (fd_port), off, how);
 -      if (rv == -1)
 -      SCM_SYSERROR;
 -      return scm_from_off_t_or_off64_t (rv);
 +      /* finished reading put-back chars.  */
 +      pt->read_buf = pt->saved_read_buf;
 +      pt->read_pos = pt->saved_read_pos;
 +      pt->read_end = pt->saved_read_end;
 +      pt->read_buf_size = pt->saved_read_buf_size;
 +      if (pt->read_pos < pt->read_end)
 +      return *(pt->read_pos);
      }
 +  return SCM_PORT_DESCRIPTOR (port)->fill_input (port);
  }
 -#undef FUNC_NAME
  
 -#ifndef O_BINARY
 -#define O_BINARY 0
 -#endif
 +int
 +scm_fill_input (SCM port)
 +{
 +  scm_i_pthread_mutex_t *lock;
 +  int ret;
 +  
 +  scm_c_lock_port (port, &lock);
 +  ret = scm_fill_input_unlocked (port);
 +  if (lock)
 +    scm_i_pthread_mutex_unlock (lock);
 +  
  
 -/* Mingw has ftruncate(), perhaps implemented above using chsize, but
 -   doesn't have the filename version truncate(), hence this code.  */
 -#if HAVE_FTRUNCATE && ! HAVE_TRUNCATE
 -static int
 -truncate (const char *file, off_t length)
 +  return ret;
 +}
 +
- /* move up to read_len chars from port's putback and/or read buffers
-    into memory starting at dest.  returns the number of chars moved.  */
++/* Move up to READ_LEN bytes from PORT's putback and/or read buffers
++   into memory starting at DEST.  Return the number of bytes moved.
++   PORT's line/column numbers are left unchanged.  */
 +size_t
 +scm_take_from_input_buffers (SCM port, char *dest, size_t read_len)
  {
 -  int ret, fdes;
 +  scm_t_port *pt = SCM_PTAB_ENTRY (port);
-   size_t chars_read = 0;
++  size_t bytes_read = 0;
 +  size_t from_buf = min (pt->read_end - pt->read_pos, read_len);
  
 -  fdes = open (file, O_BINARY | O_WRONLY);
 -  if (fdes == -1)
 -    return -1;
 +  if (from_buf > 0)
 +    {
 +      memcpy (dest, pt->read_pos, from_buf);
 +      pt->read_pos += from_buf;
-       chars_read += from_buf;
++      bytes_read += from_buf;
 +      read_len -= from_buf;
 +      dest += from_buf;
 +    }
  
 -  ret = ftruncate (fdes, length);
 -  if (ret == -1)
 +  /* if putback was active, try the real input buffer too.  */
 +  if (pt->read_buf == pt->putback_buf)
      {
 -      int save_errno = errno;
 -      close (fdes);
 -      errno = save_errno;
 -      return -1;
 +      from_buf = min (pt->saved_read_end - pt->saved_read_pos, read_len);
 +      if (from_buf > 0)
 +      {
 +        memcpy (dest, pt->saved_read_pos, from_buf);
 +        pt->saved_read_pos += from_buf;
-         chars_read += from_buf;
++        bytes_read += from_buf;
 +      }
      }
-   return chars_read;
 -  return close (fdes);
++  return bytes_read;
  }
 -#endif /* HAVE_FTRUNCATE && ! HAVE_TRUNCATE */
  
 -SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
 -            (SCM object, SCM length),
 -          "Truncate file @var{object} to @var{length} bytes.  @var{object}\n"
 -          "can be a filename string, a port object, or an integer file\n"
 -          "descriptor.\n"
 -          "The return value is unspecified.\n"
 -          "\n"
 -          "For a port or file descriptor @var{length} can be omitted, in\n"
 -          "which case the file is truncated at the current position (per\n"
 -          "@code{ftell} above).\n"
 +/* Clear a port's read buffers, returning the contents.  */
 +SCM_DEFINE (scm_drain_input, "drain-input", 1, 0, 0, 
 +            (SCM port),
 +          "This procedure clears a port's input buffers, similar\n"
 +          "to the way that force-output clears the output buffer.  The\n"
 +          "contents of the buffers are returned as a single string, e.g.,\n"
            "\n"
 -          "On most systems a file can be extended by giving a length\n"
 -          "greater than the current size, but this is not mandatory in the\n"
 -          "POSIX standard.")
 -#define FUNC_NAME s_scm_truncate_file
 +          "@lisp\n"
 +          "(define p (open-input-file ...))\n"
 +          "(drain-input p) => empty string, nothing buffered yet.\n"
 +          "(unread-char (read-char p) p)\n"
 +          "(drain-input p) => initial chars from p, up to the buffer size.\n"
 +          "@end lisp\n\n"
 +          "Draining the buffers may be useful for cleanly finishing\n"
 +          "buffered I/O so that the file descriptor can be used directly\n"
 +          "for further input.")
 +#define FUNC_NAME s_scm_drain_input
  {
 -  int rv;
 +  SCM result;
 +  char *data;
 +  scm_t_port *pt;
 +  long count;
  
 -  /* "object" can be a port, fdes or filename.
 +  SCM_VALIDATE_OPINPORT (1, port);
 +  pt = SCM_PTAB_ENTRY (port);
  
 -     Negative "length" makes no sense, but it's left to truncate() or
 -     ftruncate() to give back an error for that (normally EINVAL).
 -     */
 +  count = pt->read_end - pt->read_pos;
 +  if (pt->read_buf == pt->putback_buf)
 +    count += pt->saved_read_end - pt->saved_read_pos;
  
 -  if (SCM_UNBNDP (length))
 +  if (count)
      {
 -      /* must supply length if object is a filename.  */
 -      if (scm_is_string (object))
 -        SCM_MISC_ERROR("must supply length if OBJECT is a filename", SCM_EOL);
 -      
 -      length = scm_seek (object, SCM_INUM0, scm_from_int (SEEK_CUR));
 +      result = scm_i_make_string (count, &data, 0);
 +      scm_take_from_input_buffers (port, data, count);
      }
 +  else
 +    result = scm_nullstr;
 +  
 +  return result;
 +}
 +#undef FUNC_NAME
  
 -  object = SCM_COERCE_OUTPORT (object);
 -  if (scm_is_integer (object))
 -    {
 -      off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
 -      SCM_SYSCALL (rv = ftruncate_or_ftruncate64 (scm_to_int (object),
 -                                                  c_length));
 -    }
 -  else if (SCM_OPOUTPORTP (object))
 +void
 +scm_end_input_unlocked (SCM port)
 +{
 +  long offset;
 +  scm_t_port *pt = SCM_PTAB_ENTRY (port);
 +
 +  if (pt->read_buf == pt->putback_buf)
      {
 -      off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
 -      scm_t_port *pt = SCM_PTAB_ENTRY (object);
 -      scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
 -      
 -      if (!ptob->truncate)
 -      SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
 -      if (pt->rw_active == SCM_PORT_READ)
 -      scm_end_input (object);
 -      else if (pt->rw_active == SCM_PORT_WRITE)
 -      ptob->flush (object);
 -      
 -      ptob->truncate (object, c_length);
 -      rv = 0;
 +      offset = pt->read_end - pt->read_pos;
 +      pt->read_buf = pt->saved_read_buf;
 +      pt->read_pos = pt->saved_read_pos;
 +      pt->read_end = pt->saved_read_end;
 +      pt->read_buf_size = pt->saved_read_buf_size;
      }
    else
 -    {
 -      off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
 -      char *str = scm_to_locale_string (object);
 -      int eno;
 -      SCM_SYSCALL (rv = truncate_or_truncate64 (str, c_length));
 -      eno = errno;
 -      free (str);
 -      errno = eno;
 -    }
 -  if (rv == -1)
 -    SCM_SYSERROR;
 -  return SCM_UNSPECIFIED;
 +    offset = 0;
 +
 +  SCM_PORT_DESCRIPTOR (port)->end_input (port, offset);
  }
 -#undef FUNC_NAME
  
 -SCM_DEFINE (scm_port_line, "port-line", 1, 0, 0,
 -            (SCM port),
 -          "Return the current line number for @var{port}.\n"
 -          "\n"
 -          "The first line of a file is 0.  But you might want to add 1\n"
 -          "when printing line numbers, since starting from 1 is\n"
 -          "traditional in error messages, and likely to be more natural to\n"
 -          "non-programmers.")
 -#define FUNC_NAME s_scm_port_line
 +void
 +scm_end_input (SCM port)
  {
 -  port = SCM_COERCE_OUTPORT (port);
 -  SCM_VALIDATE_OPENPORT (1, port);
 -  return scm_from_long (SCM_LINUM (port));
 +  scm_i_pthread_mutex_t *lock;
 +  scm_c_lock_port (port, &lock);
 +  scm_end_input_unlocked (port);
 +  if (lock)
 +    scm_i_pthread_mutex_unlock (lock);
 +  
  }
 -#undef FUNC_NAME
  
 -SCM_DEFINE (scm_set_port_line_x, "set-port-line!", 2, 0, 0,
 -            (SCM port, SCM line),
 -          "Set the current line number for @var{port} to @var{line}.  The\n"
 -          "first line of a file is 0.")
 -#define FUNC_NAME s_scm_set_port_line_x
 +SCM_DEFINE (scm_force_output, "force-output", 0, 1, 0,
 +           (SCM port),
 +          "Flush the specified output port, or the current output port if @var{port}\n"
 +          "is omitted.  The current output buffer contents are passed to the\n"
 +          "underlying port implementation (e.g., in the case of fports, the\n"
 +          "data will be written to the file and the output buffer will be cleared.)\n"
 +          "It has no effect on an unbuffered port.\n\n"
 +          "The return value is unspecified.")
 +#define FUNC_NAME s_scm_force_output
  {
 -  port = SCM_COERCE_OUTPORT (port);
 -  SCM_VALIDATE_OPENPORT (1, port);
 -  SCM_PTAB_ENTRY (port)->line_number = scm_to_long (line);
 +  if (SCM_UNBNDP (port))
 +    port = scm_current_output_port ();
 +  else
 +    {
 +      port = SCM_COERCE_OUTPORT (port);
 +      SCM_VALIDATE_OPOUTPORT (1, port);
 +    }
 +  scm_flush_unlocked (port);
    return SCM_UNSPECIFIED;
  }
  #undef FUNC_NAME
@@@ -263,73 -257,41 +263,73 @@@ SCM_API SCM scm_set_current_warning_por
  SCM_API void scm_dynwind_current_input_port (SCM port);
  SCM_API void scm_dynwind_current_output_port (SCM port);
  SCM_API void scm_dynwind_current_error_port (SCM port);
 -SCM_API SCM scm_new_port_table_entry (scm_t_bits tag);
 -SCM_API void scm_grow_port_cbuf (SCM port, size_t requested);
 -SCM_API SCM scm_pt_size (void);
 -SCM_API SCM scm_pt_member (SCM member);
 -SCM_API void scm_port_non_buffer (scm_t_port *pt);
 -SCM_API int scm_revealed_count (SCM port);
 -SCM_API SCM scm_port_revealed (SCM port);
 -SCM_API SCM scm_set_port_revealed_x (SCM port, SCM rcount);
 +SCM_INTERNAL void scm_i_dynwind_current_load_port (SCM port);
 +
 +/* Mode bits.  */
 +SCM_INTERNAL long scm_i_mode_bits (SCM modes);
  SCM_API long scm_mode_bits (char *modes);
  SCM_API SCM scm_port_mode (SCM port);
 -SCM_API SCM scm_close_input_port (SCM port);
 -SCM_API SCM scm_close_output_port (SCM port);
 -SCM_API SCM scm_close_port (SCM port);
 -SCM_API SCM scm_port_for_each (SCM proc);
 -SCM_API void scm_c_port_for_each (void (*proc)(void *data, SCM p), void *data);
 +
 +/* Low-level constructors.  */
 +SCM_API SCM
 +scm_c_make_port_with_encoding (scm_t_bits tag,
 +                               unsigned long mode_bits,
 +                               const char *encoding,
 +                               scm_t_string_failed_conversion_handler handler,
 +                               scm_t_bits stream);
 +SCM_API SCM scm_c_make_port (scm_t_bits tag, unsigned long mode_bits,
 +                             scm_t_bits stream);
 +SCM_API SCM scm_new_port_table_entry (scm_t_bits tag);
 +
 +/* Predicates.  */
 +SCM_API SCM scm_port_p (SCM x);
  SCM_API SCM scm_input_port_p (SCM x);
  SCM_API SCM scm_output_port_p (SCM x);
 -SCM_API SCM scm_port_p (SCM x);
  SCM_API SCM scm_port_closed_p (SCM port);
  SCM_API SCM scm_eof_object_p (SCM x);
 -SCM_API SCM scm_force_output (SCM port);
 -SCM_API SCM scm_flush_all_ports (void);
 -SCM_API SCM scm_read_char (SCM port);
 -SCM_API scm_t_wchar scm_getc (SCM port);
 +
 +/* Closing ports.  */
 +SCM_API SCM scm_close_port (SCM port);
 +SCM_API SCM scm_close_input_port (SCM port);
 +SCM_API SCM scm_close_output_port (SCM port);
 +
 +/* Encoding characters to byte streams, and decoding byte streams to
 +   characters.  */
 +SCM_INTERNAL const char *scm_i_default_port_encoding (void);
 +SCM_INTERNAL void scm_i_set_default_port_encoding (const char *);
 +SCM_INTERNAL scm_t_iconv_descriptors *scm_i_port_iconv_descriptors (SCM port);
 +SCM_INTERNAL void scm_i_set_port_encoding_x (SCM port, const char *str);
 +SCM_API SCM scm_port_encoding (SCM port);
 +SCM_API SCM scm_set_port_encoding_x (SCM port, SCM encoding);
 +SCM_INTERNAL scm_t_string_failed_conversion_handler scm_i_get_conversion_strategy (SCM port);
 +SCM_INTERNAL void scm_i_set_conversion_strategy_x (SCM port, 
 +                                                 scm_t_string_failed_conversion_handler h);
 +SCM_API SCM scm_port_conversion_strategy (SCM port);
 +SCM_API SCM scm_set_port_conversion_strategy_x (SCM port, SCM behavior);
 +
 +/* Acquiring and releasing the port lock.  */
 +SCM_API void scm_dynwind_lock_port (SCM port);
 +SCM_INLINE int scm_c_lock_port (SCM port, scm_i_pthread_mutex_t **lock);
 +SCM_INLINE int scm_c_try_lock_port (SCM port, scm_i_pthread_mutex_t **lock);
 +
 +/* Input.  */
 +SCM_API int scm_get_byte_or_eof (SCM port);
 +SCM_INLINE int scm_get_byte_or_eof_unlocked (SCM port);
 +SCM_API int scm_peek_byte_or_eof (SCM port);
 +SCM_INLINE int scm_peek_byte_or_eof_unlocked (SCM port);
  SCM_API size_t scm_c_read (SCM port, void *buffer, size_t size);
 -SCM_API void scm_c_write (SCM port, const void *buffer, size_t size);
 -SCM_API void scm_lfwrite (const char *ptr, size_t size, SCM port);
 -SCM_INTERNAL void scm_lfwrite_substr (SCM str, size_t start, size_t end,
 -                                    SCM port);
 -SCM_API void scm_flush (SCM port);
 -SCM_API void scm_end_input (SCM port);
 -SCM_API int scm_fill_input (SCM port);
 +SCM_API size_t scm_c_read_unlocked (SCM port, void *buffer, size_t size);
 +SCM_API scm_t_wchar scm_getc (SCM port);
 +SCM_API scm_t_wchar scm_getc_unlocked (SCM port);
 +SCM_API SCM scm_read_char (SCM port);
 +
 +/* Pushback.  */
- SCM_INTERNAL void scm_unget_byte (int c, SCM port); 
- SCM_INTERNAL void scm_unget_byte_unlocked (int c, SCM port); 
+ SCM_API void scm_unget_byte (int c, SCM port);
++SCM_API void scm_unget_byte_unlocked (int c, SCM port);
  SCM_API void scm_ungetc (scm_t_wchar c, SCM port);
 +SCM_API void scm_ungetc_unlocked (scm_t_wchar c, SCM port);
  SCM_API void scm_ungets (const char *s, int n, SCM port);
 +SCM_API void scm_ungets_unlocked (const char *s, int n, SCM port);
  SCM_API SCM scm_peek_char (SCM port);
  SCM_API SCM scm_unread_char (SCM cobj, SCM port);
  SCM_API SCM scm_unread_string (SCM str, SCM port);
diff --cc libguile/read.c
@@@ -501,8 -501,7 +501,7 @@@ scm_read_string (int chr, SCM port
    long line = SCM_LINUM (port);
    int column = SCM_COL (port) - 1;
  
-   str = scm_i_make_string (READER_STRING_BUFFER_SIZE, NULL, 0);
 -  while ('"' != (c = scm_getc (port)))
 +  while ('"' != (c = scm_getc_unlocked (port)))
      {
        if (c == EOF)
          {
@@@ -604,15 -610,11 +610,11 @@@ scm_read_number (scm_t_wchar chr, SCM p
    long line = SCM_LINUM (port);
    int column = SCM_COL (port) - 1;
  
 -  scm_ungetc (chr, port);
 +  scm_ungetc_unlocked (chr, port);
-   overflow = read_complete_token (port, buffer, sizeof (buffer),
-                                   &overflow_buffer, &bytes_read);
+   buffer = read_complete_token (port, local_buffer, sizeof local_buffer,
+                               &bytes_read);
  
-   if (!overflow)
-     str = scm_from_stringn (buffer, bytes_read, pt->encoding, pt->ilseq_handler);
-   else
-     str = scm_from_stringn (overflow_buffer, bytes_read, pt->encoding,
-                             pt->ilseq_handler);
+   str = scm_from_stringn (buffer, bytes_read, pt->encoding, pt->ilseq_handler);
  
    result = scm_string_to_number (str, SCM_UNDEFINED);
    if (scm_is_false (result))
@@@ -643,16 -642,11 +642,11 @@@ scm_read_mixed_case_symbol (scm_t_wcha
    scm_t_port *pt = SCM_PTAB_ENTRY (port);
    SCM str;
  
 -  scm_ungetc (chr, port);
 +  scm_ungetc_unlocked (chr, port);
-   overflow = read_complete_token (port, buffer, READER_BUFFER_SIZE,
-                                   &overflow_buffer, &bytes_read);
+   buffer = read_complete_token (port, local_buffer, sizeof local_buffer,
+                               &bytes_read);
    if (bytes_read > 0)
-     {
-       if (!overflow)
-         ends_with_colon = buffer[bytes_read - 1] == ':';
-       else
-         ends_with_colon = overflow_buffer[bytes_read - 1] == ':';
-     }
+     ends_with_colon = buffer[bytes_read - 1] == ':';
  
    if (postfix && ends_with_colon && (bytes_read > 1))
      {
Simple merge