Merge remote-tracking branch 'origin/stable-2.0'
authorAndy Wingo <wingo@pobox.com>
Wed, 8 Feb 2012 10:48:08 +0000 (11:48 +0100)
committerAndy Wingo <wingo@pobox.com>
Wed, 8 Feb 2012 10:48:08 +0000 (11:48 +0100)
Conflicts:
GUILE-VERSION
libguile/gc-malloc.c
libguile/ports.c

34 files changed:
1  2 
configure.ac
doc/ref/compiler.texi
doc/ref/srfi-modules.texi
doc/ref/vm.texi
libguile/alist.c
libguile/array-map.c
libguile/arrays.c
libguile/bitvectors.c
libguile/continuations.c
libguile/control.c
libguile/filesys.c
libguile/foreign.c
libguile/foreign.h
libguile/gc-malloc.c
libguile/hashtab.c
libguile/init.c
libguile/ioext.c
libguile/load.c
libguile/numbers.c
libguile/ports.c
libguile/print.c
libguile/procprop.c
libguile/promises.c
libguile/socket.c
libguile/srfi-14.c
libguile/strings.c
libguile/struct.c
libguile/symbols.c
libguile/threads.c
m4/gnulib-cache.m4
meta/guile-2.2-uninstalled.pc.in
module/ice-9/boot-9.scm
module/language/tree-il/analyze.scm
test-suite/tests/tree-il.test

diff --cc configure.ac
Simple merge
Simple merge
Simple merge
diff --cc doc/ref/vm.texi
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -426,12 -941,9 +426,12 @@@ SCM_DEFINE (scm_hashq_ref, "hashq-ref"
  SCM_DEFINE (scm_hashq_set_x, "hashq-set!", 3, 0, 0,
              (SCM table, SCM key, SCM val),
            "Find the entry in @var{table} associated with @var{key}, and\n"
-           "store @var{value} there. Uses @code{eq?} for equality testing.")
+           "store @var{val} there. Uses @code{eq?} for equality testing.")
  #define FUNC_NAME s_scm_hashq_set_x
  {
 +  if (SCM_WEAK_TABLE_P (table))
 +    return scm_weak_table_putq_x (table, key, val);
 +
    return scm_hash_fn_set_x (table, key, val,
                            (scm_t_hash_fn) scm_ihashq,
                            (scm_t_assoc_fn) scm_sloppy_assq,
diff --cc libguile/init.c
Simple merge
Simple merge
diff --cc libguile/load.c
Simple merge
Simple merge
@@@ -2290,364 -2288,180 +2291,365 @@@ scm_c_write_unlocked (SCM port, const v
  }
  #undef FUNC_NAME
  
 -SCM_DEFINE (scm_set_port_encoding_x, "set-port-encoding!", 2, 0, 0,
 -          (SCM port, SCM enc),
 -          "Sets the character encoding that will be used to interpret all\n"
 -          "port I/O.  New ports are created with the encoding\n"
 -          "appropriate for the current locale if @code{setlocale} has \n"
 -          "been called or ISO-8859-1 otherwise\n"
 -          "and this procedure can be used to modify that encoding.\n")
 -#define FUNC_NAME s_scm_set_port_encoding_x
 +void
 +scm_c_write (SCM port, const void *ptr, size_t size)
  {
 -  char *enc_str;
 +  scm_i_pthread_mutex_t *lock;
 +  scm_c_lock_port (port, &lock);
 +  scm_c_write_unlocked (port, ptr, size);
 +  if (lock)
 +    scm_i_pthread_mutex_unlock (lock);
 +  
 +}
  
 -  SCM_VALIDATE_PORT (1, port);
 -  SCM_VALIDATE_STRING (2, enc);
 +/* scm_lfwrite
 + *
 + * This function differs from scm_c_write; it updates port line and
 + * column. */
 +void
 +scm_lfwrite_unlocked (const char *ptr, size_t size, SCM port)
 +{
 +  scm_t_port *pt = SCM_PTAB_ENTRY (port);
 +  scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port);
  
 -  enc_str = scm_to_locale_string (enc);
 -  scm_i_set_port_encoding_x (port, enc_str);
 -  free (enc_str);
 +  if (pt->rw_active == SCM_PORT_READ)
 +    scm_end_input_unlocked (port);
  
 -  return SCM_UNSPECIFIED;
 -}
 -#undef FUNC_NAME
 +  ptob->write (port, ptr, size);
  
 +  for (; size; ptr++, size--)
 +    update_port_lf ((scm_t_wchar) (unsigned char) *ptr, port);
  
 -/* This determines how conversions handle unconvertible characters.  */
 -SCM_GLOBAL_VARIABLE (scm_conversion_strategy, "%port-conversion-strategy");
 -static int scm_conversion_strategy_init = 0;
 +  if (pt->rw_random)
 +    pt->rw_active = SCM_PORT_WRITE;
 +}
  
 -scm_t_string_failed_conversion_handler
 -scm_i_get_conversion_strategy (SCM port)
 +void
 +scm_lfwrite (const char *ptr, size_t size, SCM port)
  {
 -  SCM encoding;
 +  scm_i_pthread_mutex_t *lock;
 +  scm_c_lock_port (port, &lock);
 +  scm_lfwrite_unlocked (ptr, size, port);
 +  if (lock)
 +    scm_i_pthread_mutex_unlock (lock);
    
 -  if (scm_is_false (port))
 -    {
 -      if (!scm_conversion_strategy_init
 -        || !scm_is_fluid (SCM_VARIABLE_REF (scm_conversion_strategy)))
 -      return SCM_FAILED_CONVERSION_QUESTION_MARK;
 -      else
 -      {
 -        encoding = scm_fluid_ref (SCM_VARIABLE_REF (scm_conversion_strategy));
 -        if (scm_is_false (encoding))
 -          return SCM_FAILED_CONVERSION_QUESTION_MARK;
 -        else 
 -          return (scm_t_string_failed_conversion_handler) scm_to_int (encoding);
 -      }
 -    }
 -  else
 -    {
 -      scm_t_port *pt;
 -      pt = SCM_PTAB_ENTRY (port);
 -      return pt->ilseq_handler;
 -    }
 -      
  }
  
 +/* Write STR to PORT from START inclusive to END exclusive.  */
  void
 -scm_i_set_conversion_strategy_x (SCM port, 
 -                               scm_t_string_failed_conversion_handler handler)
 +scm_lfwrite_substr (SCM str, size_t start, size_t end, SCM port)
 +{
 +  scm_t_port *pt = SCM_PTAB_ENTRY (port);
 +
 +  if (pt->rw_active == SCM_PORT_READ)
 +    scm_end_input_unlocked (port);
 +
 +  if (end == (size_t) -1)
 +    end = scm_i_string_length (str);
 +
 +  scm_display (scm_c_substring (str, start, end), port);
 +
 +  if (pt->rw_random)
 +    pt->rw_active = SCM_PORT_WRITE;
 +}
 +
 +
 +\f
 +
 +/* Querying and setting positions, and character availability.  */
 +
 +SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0, 
 +          (SCM port),
 +          "Return @code{#t} if a character is ready on input @var{port}\n"
 +          "and return @code{#f} otherwise.  If @code{char-ready?} returns\n"
 +          "@code{#t} then the next @code{read-char} operation on\n"
 +          "@var{port} is guaranteed not to hang.  If @var{port} is a file\n"
 +          "port at end of file then @code{char-ready?} returns @code{#t}.\n"
 +          "\n"
 +          "@code{char-ready?} exists to make it possible for a\n"
 +          "program to accept characters from interactive ports without\n"
 +          "getting stuck waiting for input.  Any input editors associated\n"
 +          "with such ports must make sure that characters whose existence\n"
 +          "has been asserted by @code{char-ready?} cannot be rubbed out.\n"
 +          "If @code{char-ready?} were to return @code{#f} at end of file,\n"
 +          "a port at end of file would be indistinguishable from an\n"
 +          "interactive port that has no ready characters.")
 +#define FUNC_NAME s_scm_char_ready_p
  {
 -  SCM strategy;
    scm_t_port *pt;
 -  
 -  strategy = scm_from_int ((int) handler);
 -  
 -  if (scm_is_false (port))
 -    {
 -      /* Set the default encoding for future ports.  */
 -      if (!scm_conversion_strategy_init
 -        || !scm_is_fluid (SCM_VARIABLE_REF (scm_conversion_strategy)))
 -      scm_misc_error (NULL, "tried to set conversion strategy fluid before it is initialized",
 -                       SCM_EOL);
 -      scm_fluid_set_x (SCM_VARIABLE_REF (scm_conversion_strategy), strategy);
 -    }
 +
 +  if (SCM_UNBNDP (port))
 +    port = scm_current_input_port ();
 +  /* It's possible to close the current input port, so validate even in
 +     this case. */
 +  SCM_VALIDATE_OPINPORT (1, port);
 +
 +  pt = SCM_PTAB_ENTRY (port);
 +
 +  /* if the current read buffer is filled, or the
 +     last pushed-back char has been read and the saved buffer is
 +     filled, result is true.  */
 +  if (pt->read_pos < pt->read_end 
 +      || (pt->read_buf == pt->putback_buf
 +        && pt->saved_read_pos < pt->saved_read_end))
 +    return SCM_BOOL_T;
    else
      {
 -      /* Set the character encoding for this port.  */
 -      pt = SCM_PTAB_ENTRY (port);
 -      pt->ilseq_handler = handler;
 +      scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port);
 +      
 +      if (ptob->input_waiting)
 +      return scm_from_bool(ptob->input_waiting (port));
 +      else
 +      return SCM_BOOL_T;
      }
  }
 +#undef FUNC_NAME
  
 -SCM_DEFINE (scm_port_conversion_strategy, "port-conversion-strategy",
 -          1, 0, 0, (SCM port),
 -          "Returns the behavior of the port when handling a character that\n"
 -          "is not representable in the port's current encoding.\n"
 -          "It returns the symbol @code{error} if unrepresentable characters\n"
 -          "should cause exceptions, @code{substitute} if the port should\n"
 -          "try to replace unrepresentable characters with question marks or\n"
 -          "approximate characters, or @code{escape} if unrepresentable\n"
 -          "characters should be converted to string escapes.\n"
 +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"
++          "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"
 -          "If @var{port} is @code{#f}, then the current default behavior\n"
 -          "will be returned.  New ports will have this default behavior\n"
 -          "when they are created.\n")
 -#define FUNC_NAME s_scm_port_conversion_strategy
 +          "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"
++          "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
  {
 -  scm_t_string_failed_conversion_handler h;
 +  int how;
  
 -  SCM_VALIDATE_OPPORT (1, port);
 +  fd_port = SCM_COERCE_OUTPORT (fd_port);
  
 -  if (!scm_is_false (port))
 +  how = scm_to_int (whence);
 +  if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
 +    SCM_OUT_OF_RANGE (3, whence);
 +
 +  if (SCM_OPPORTP (fd_port))
      {
 -      SCM_VALIDATE_OPPORT (1, port);
 +      scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (fd_port);
 +      off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
 +      off_t_or_off64_t rv;
 +
 +      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?.  */
 +    {
 +      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);
      }
 +}
 +#undef FUNC_NAME
  
 -  h = scm_i_get_conversion_strategy (port);
 -  if (h == SCM_FAILED_CONVERSION_ERROR)
 -    return scm_from_latin1_symbol ("error");
 -  else if (h == SCM_FAILED_CONVERSION_QUESTION_MARK)
 -    return scm_from_latin1_symbol ("substitute");
 -  else if (h == SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE)
 -    return scm_from_latin1_symbol ("escape");
 -  else
 -    abort ();
 +#ifndef O_BINARY
 +#define O_BINARY 0
 +#endif
 +
 +/* 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)
 +{
 +  int ret, fdes;
 +
 +  fdes = open (file, O_BINARY | O_WRONLY);
 +  if (fdes == -1)
 +    return -1;
 +
 +  ret = ftruncate (fdes, length);
 +  if (ret == -1)
 +    {
 +      int save_errno = errno;
 +      close (fdes);
 +      errno = save_errno;
 +      return -1;
 +    }
  
 -  /* Never gets here. */
 -  return SCM_UNDEFINED;
 +  return close (fdes);
  }
 -#undef FUNC_NAME
 +#endif /* HAVE_FTRUNCATE && ! HAVE_TRUNCATE */
  
 -SCM_DEFINE (scm_set_port_conversion_strategy_x, "set-port-conversion-strategy!",
 -          2, 0, 0, 
 -          (SCM port, SCM sym),
 -          "Sets the behavior of the interpreter when outputting a character\n"
 -          "that is not representable in the port's current encoding.\n"
 -          "@var{sym} can be either @code{'error}, @code{'substitute}, or\n"
 -          "@code{'escape}.  If it is @code{'error}, an error will be thrown\n"
 -          "when an unconvertible character is encountered.  If it is\n"
 -          "@code{'substitute}, then unconvertible characters will \n"
 -          "be replaced with approximate characters, or with question marks\n"
 -          "if no approximately correct character is available.\n"
 -          "If it is @code{'escape},\n"
 -          "it will appear as a hex escape when output.\n"
 +SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
 +            (SCM object, SCM length),
-           "Truncate @var{file} to @var{length} bytes.  @var{file} can be a\n"
-           "filename string, a port object, or an integer file descriptor.\n"
++          "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"
 -          "If @var{port} is an open port, the conversion error behavior\n"
 -          "is set for that port.  If it is @code{#f}, it is set as the\n"
 -          "default behavior for any future ports that get created in\n"
 -          "this thread.\n")
 -#define FUNC_NAME s_scm_set_port_conversion_strategy_x
 +          "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"
 +          "\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
  {
 -  SCM err;
 -  SCM qm;
 -  SCM esc;
 +  int rv;
  
 -  if (!scm_is_false (port))
 +  /* "object" can be a port, fdes or filename.
 +
 +     Negative "length" makes no sense, but it's left to truncate() or
 +     ftruncate() to give back an error for that (normally EINVAL).
 +     */
 +
 +  if (SCM_UNBNDP (length))
      {
 -      SCM_VALIDATE_OPPORT (1, port);
 +      /* 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));
      }
  
 -  err = scm_from_latin1_symbol ("error");
 -  if (scm_is_true (scm_eqv_p (sym, err)))
 +  object = SCM_COERCE_OUTPORT (object);
 +  if (scm_is_integer (object))
      {
 -      scm_i_set_conversion_strategy_x (port, SCM_FAILED_CONVERSION_ERROR);
 -      return SCM_UNSPECIFIED;
 +      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));
      }
 -
 -  qm = scm_from_latin1_symbol ("substitute");
 -  if (scm_is_true (scm_eqv_p (sym, qm)))
 +  else if (SCM_OPOUTPORTP (object))
      {
 -      scm_i_set_conversion_strategy_x (port, 
 -                                       SCM_FAILED_CONVERSION_QUESTION_MARK);
 -      return SCM_UNSPECIFIED;
 +      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_PORT_DESCRIPTOR (object);
 +      
 +      if (!ptob->truncate)
 +      SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
 +      if (pt->rw_active == SCM_PORT_READ)
 +      scm_end_input_unlocked (object);
 +      else if (pt->rw_active == SCM_PORT_WRITE)
 +      ptob->flush (object);
 +      
 +      ptob->truncate (object, c_length);
 +      rv = 0;
      }
 -
 -  esc = scm_from_latin1_symbol ("escape");
 -  if (scm_is_true (scm_eqv_p (sym, esc)))
 +  else
      {
 -      scm_i_set_conversion_strategy_x (port,
 -                                       SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE);
 -      return SCM_UNSPECIFIED;
 +      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;
 +}
 +#undef FUNC_NAME
  
 -  SCM_MISC_ERROR ("unknown conversion behavior ~s", scm_list_1 (sym));
 +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
 +{
 +  port = SCM_COERCE_OUTPORT (port);
 +  SCM_VALIDATE_OPENPORT (1, port);
 +  return scm_from_long (SCM_LINUM (port));
 +}
 +#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
 +{
 +  port = SCM_COERCE_OUTPORT (port);
 +  SCM_VALIDATE_OPENPORT (1, port);
 +  SCM_PTAB_ENTRY (port)->line_number = scm_to_long (line);
 +  return SCM_UNSPECIFIED;
 +}
 +#undef FUNC_NAME
 +
 +SCM_DEFINE (scm_port_column, "port-column", 1, 0, 0,
 +            (SCM port),
 +          "Return the current column number of @var{port}.\n"
 +          "If the number is\n"
 +          "unknown, the result is #f.  Otherwise, the result is a 0-origin integer\n"
 +          "- i.e. the first character of the first line is line 0, column 0.\n"
 +          "(However, when you display a file position, for example in an error\n"
 +          "message, we recommend you add 1 to get 1-origin integers.  This is\n"
 +          "because lines and column numbers traditionally start with 1, and that is\n"
 +          "what non-programmers will find most natural.)")
 +#define FUNC_NAME s_scm_port_column
 +{
 +  port = SCM_COERCE_OUTPORT (port);
 +  SCM_VALIDATE_OPENPORT (1, port);
 +  return scm_from_int (SCM_COL (port));
 +}
 +#undef FUNC_NAME
 +
 +SCM_DEFINE (scm_set_port_column_x, "set-port-column!", 2, 0, 0,
 +            (SCM port, SCM column),
 +          "Set the current column of @var{port}.  Before reading the first\n"
 +          "character on a line the column should be 0.")
 +#define FUNC_NAME s_scm_set_port_column_x
 +{
 +  port = SCM_COERCE_OUTPORT (port);
 +  SCM_VALIDATE_OPENPORT (1, port);
 +  SCM_PTAB_ENTRY (port)->column_number = scm_to_int (column);
 +  return SCM_UNSPECIFIED;
 +}
 +#undef FUNC_NAME
 +
 +SCM_DEFINE (scm_port_filename, "port-filename", 1, 0, 0,
 +            (SCM port),
 +          "Return the filename associated with @var{port}, or @code{#f}\n"
 +          "if no filename is associated with the port.")
 +#define FUNC_NAME s_scm_port_filename
 +{
 +  port = SCM_COERCE_OUTPORT (port);
 +  SCM_VALIDATE_OPENPORT (1, port);
 +  return SCM_FILENAME (port);
 +}
 +#undef FUNC_NAME
  
 +SCM_DEFINE (scm_set_port_filename_x, "set-port-filename!", 2, 0, 0,
 +            (SCM port, SCM filename),
 +          "Change the filename associated with @var{port}, using the current input\n"
 +          "port if none is specified.  Note that this does not change the port's\n"
 +          "source of data, but only the value that is returned by\n"
 +          "@code{port-filename} and reported in diagnostic output.")
 +#define FUNC_NAME s_scm_set_port_filename_x
 +{
 +  port = SCM_COERCE_OUTPORT (port);
 +  SCM_VALIDATE_OPENPORT (1, port);
 +  /* We allow the user to set the filename to whatever he likes.  */
 +  SCM_SET_FILENAME (port, filename);
    return SCM_UNSPECIFIED;
  }
  #undef FUNC_NAME
@@@ -2687,82 -2498,6 +2689,82 @@@ scm_port_print (SCM exp, SCM port, scm_
    return 1;
  }
  
-           "in the system at the time @var{port-for-each} is invoked.\n"
-           "Changes to the port table while @var{port-for-each} is running\n"
-           "have no effect as far as @var{port-for-each} is concerned.") 
 +
 +\f
 +
 +/* Iterating over all ports.  */
 +
 +struct for_each_data 
 +{
 +  void (*proc) (void *data, SCM p);
 +  void *data;
 +};
 +
 +static SCM
 +for_each_trampoline (void *data, SCM port, SCM result)
 +{
 +  struct for_each_data *d = data;
 +  
 +  d->proc (d->data, port);
 +
 +  return result;
 +}
 +
 +void
 +scm_c_port_for_each (void (*proc)(void *data, SCM p), void *data)
 +{
 +  struct for_each_data d;
 +  
 +  d.proc = proc;
 +  d.data = data;
 +
 +  scm_c_weak_set_fold (for_each_trampoline, &d, SCM_EOL,
 +                       scm_i_port_weak_set);
 +}
 +
 +static void
 +scm_for_each_trampoline (void *data, SCM port)
 +{
 +  scm_call_1 (SCM_PACK_POINTER (data), port);
 +}
 +
 +SCM_DEFINE (scm_port_for_each, "port-for-each", 1, 0, 0,
 +          (SCM proc),
 +          "Apply @var{proc} to each port in the Guile port table\n"
 +          "in turn.  The return value is unspecified.  More specifically,\n"
 +          "@var{proc} is applied exactly once to every port that exists\n"
++          "in the system at the time @code{port-for-each} is invoked.\n"
++          "Changes to the port table while @code{port-for-each} is running\n"
++          "have no effect as far as @code{port-for-each} is concerned.") 
 +#define FUNC_NAME s_scm_port_for_each
 +{
 +  SCM_VALIDATE_PROC (1, proc);
 +
 +  scm_c_port_for_each (scm_for_each_trampoline, SCM_UNPACK_POINTER (proc));
 +  
 +  return SCM_UNSPECIFIED;
 +}
 +#undef FUNC_NAME
 +
 +static void
 +flush_output_port (void *closure, SCM port)
 +{
 +  if (SCM_OPOUTPORTP (port))
 +    scm_flush_unlocked (port);
 +}
 +
 +SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
 +            (),
 +          "Equivalent to calling @code{force-output} on\n"
 +          "all open output ports.  The return value is unspecified.")
 +#define FUNC_NAME s_scm_flush_all_ports
 +{
 +  scm_c_port_for_each (&flush_output_port, NULL);
 +  return SCM_UNSPECIFIED;
 +}
 +#undef FUNC_NAME
 +
 +
  \f
  
  /* Void ports.   */
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge