Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / libguile / ports.c
index 6c763c1..c0e13f3 100644 (file)
@@ -328,6 +328,17 @@ SCM_DEFINE (scm_current_error_port, "current-error-port", 0, 0, 0,
 }
 #undef FUNC_NAME
 
+SCM
+scm_current_warning_port (void)
+{
+  static SCM cwp_var = SCM_BOOL_F;
+
+  if (scm_is_false (cwp_var))
+    cwp_var = scm_c_private_lookup ("guile", "current-warning-port");
+  
+  return scm_call_0 (scm_variable_ref (cwp_var));
+}
+
 SCM_DEFINE (scm_current_load_port, "current-load-port", 0, 0, 0,
            (),
            "Return the current-load-port.\n"
@@ -382,6 +393,19 @@ SCM_DEFINE (scm_set_current_error_port, "set-current-error-port", 1, 0, 0,
 }
 #undef FUNC_NAME
 
+
+SCM
+scm_set_current_warning_port (SCM port)
+{
+  static SCM cwp_var = SCM_BOOL_F;
+
+  if (scm_is_false (cwp_var))
+    cwp_var = scm_c_private_lookup ("guile", "current-warning-port");
+  
+  return scm_call_1 (scm_variable_ref (cwp_var), port);
+}
+
+
 void
 scm_dynwind_current_input_port (SCM port)
 #define FUNC_NAME NULL
@@ -582,9 +606,8 @@ scm_c_make_port_with_encoding (scm_t_bits tag, unsigned long mode_bits,
   SCM_SET_CELL_WORD_1 (ret, (scm_t_bits) entry);
   SCM_SET_CELL_WORD_2 (ret, (scm_t_bits) ptob);
 
-#if SCM_USE_PTHREAD_THREADS
-  scm_i_pthread_mutex_init (&entry->lock, scm_i_pthread_mutexattr_recursive);
-#endif
+  entry->lock = scm_gc_malloc_pointerless (sizeof (*entry->lock), "port lock");
+  scm_i_pthread_mutex_init (entry->lock, scm_i_pthread_mutexattr_recursive);
 
   entry->file_name = SCM_BOOL_F;
   entry->rw_active = SCM_PORT_NEITHER;
@@ -1098,6 +1121,38 @@ SCM_DEFINE (scm_set_port_conversion_strategy_x, "set-port-conversion-strategy!",
 
 \f
 
+/* The port lock.  */
+
+static void
+lock_port (void *mutex)
+{
+  scm_i_pthread_mutex_lock (mutex);
+}
+
+static void
+unlock_port (void *mutex)
+{
+  scm_i_pthread_mutex_unlock (mutex);
+}
+
+void
+scm_dynwind_lock_port (SCM port)
+#define FUNC_NAME "dynwind-lock-port"
+{
+  scm_i_pthread_mutex_t *lock;
+  SCM_VALIDATE_OPPORT (SCM_ARG1, port);
+  scm_c_lock_port (port, &lock);
+  if (lock)
+    {
+      scm_dynwind_unwind_handler (unlock_port, lock, SCM_F_WIND_EXPLICITLY);
+      scm_dynwind_rewind_handler (lock_port, lock, 0);
+    }
+}
+#undef FUNC_NAME
+
+
+\f
+
 /* Revealed counts --- an oddity inherited from SCSH.  */
 
 /* Find a port in the table and return its revealed count.
@@ -1106,11 +1161,13 @@ SCM_DEFINE (scm_set_port_conversion_strategy_x, "set-port-conversion-strategy!",
 int
 scm_revealed_count (SCM port)
 {
+  scm_i_pthread_mutex_t *lock;
   int ret;
   
-  scm_c_lock_port (port);
+  scm_c_lock_port (port, &lock);
   ret = SCM_REVEALED (port);
-  scm_c_unlock_port (port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
   
   return ret;
 }
@@ -1134,12 +1191,15 @@ SCM_DEFINE (scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
 #define FUNC_NAME s_scm_set_port_revealed_x
 {
   int r;
+  scm_i_pthread_mutex_t *lock;
+  
   port = SCM_COERCE_OUTPORT (port);
   SCM_VALIDATE_OPENPORT (1, port);
   r = scm_to_int (rcount);
-  scm_c_lock_port (port);
+  scm_c_lock_port (port, &lock);
   SCM_REVEALED (port) = r;
-  scm_c_unlock_port (port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
@@ -1149,15 +1209,17 @@ SCM_DEFINE (scm_adjust_port_revealed_x, "adjust-port-revealed!", 2, 0, 0,
            (SCM port, SCM addend),
            "Add @var{addend} to the revealed count of @var{port}.\n"
            "The return value is unspecified.")
-#define FUNC_NAME s_scm_set_port_revealed_x
+#define FUNC_NAME s_scm_adjust_port_revealed_x
 {
+  scm_i_pthread_mutex_t *lock;
   int a;
   port = SCM_COERCE_OUTPORT (port);
   SCM_VALIDATE_OPENPORT (1, port);
   a = scm_to_int (addend);
-  scm_c_lock_port (port);
+  scm_c_lock_port (port, &lock);
   SCM_REVEALED (port) += a;
-  scm_c_unlock_port (port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
@@ -1170,11 +1232,13 @@ SCM_DEFINE (scm_adjust_port_revealed_x, "adjust-port-revealed!", 2, 0, 0,
 int
 scm_get_byte_or_eof (SCM port)
 {
+  scm_i_pthread_mutex_t *lock;
   int ret;
 
-  scm_c_lock_port (port);
+  scm_c_lock_port (port, &lock);
   ret = scm_get_byte_or_eof_unlocked (port);
-  scm_c_unlock_port (port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
 
   return ret;
 }
@@ -1182,11 +1246,13 @@ scm_get_byte_or_eof (SCM port)
 int
 scm_peek_byte_or_eof (SCM port)
 {
+  scm_i_pthread_mutex_t *lock;
   int ret;
 
-  scm_c_lock_port (port);
+  scm_c_lock_port (port, &lock);
   ret = scm_peek_byte_or_eof_unlocked (port);
-  scm_c_unlock_port (port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
 
   return ret;
 }
@@ -1290,7 +1356,7 @@ scm_c_read_unlocked (SCM port, void *buffer, size_t size)
 
       /* Call scm_fill_input until we have all the bytes that we need,
         or we hit EOF. */
-      while (pt->read_buf_size && (scm_fill_input (port) != EOF))
+      while (pt->read_buf_size && (scm_fill_input_unlocked (port) != EOF))
        {
          pt->read_buf_size -= (pt->read_end - pt->read_pos);
          pt->read_pos = pt->read_buf = pt->read_end;
@@ -1314,7 +1380,7 @@ scm_c_read_unlocked (SCM port, void *buffer, size_t size)
         that a custom port implementation's entry points (in
         particular, fill_input) can rely on the buffer always being
         the same as they first set up. */
-      while (size && (scm_fill_input (port) != EOF))
+      while (size && (scm_fill_input_unlocked (port) != EOF))
        {
          n_available = min (size, pt->read_end - pt->read_pos);
          memcpy (buffer, pt->read_pos, n_available);
@@ -1332,11 +1398,14 @@ scm_c_read_unlocked (SCM port, void *buffer, size_t size)
 size_t
 scm_c_read (SCM port, void *buffer, size_t size)
 {
+  scm_i_pthread_mutex_t *lock;
   size_t ret;
 
-  scm_c_lock_port (port);
+  scm_c_lock_port (port, &lock);
   ret = scm_c_read_unlocked (port, buffer, size);
-  scm_c_unlock_port (port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+  
 
   return ret;
 }
@@ -1666,11 +1735,14 @@ scm_getc_unlocked (SCM port)
 scm_t_wchar
 scm_getc (SCM port)
 {
+  scm_i_pthread_mutex_t *lock;
   scm_t_wchar ret;
 
-  scm_c_lock_port (port);
+  scm_c_lock_port (port, &lock);
   ret = scm_getc_unlocked (port);
-  scm_c_unlock_port (port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+  
 
   return ret;
 }
@@ -1703,7 +1775,7 @@ SCM_DEFINE (scm_read_char, "read-char", 0, 1, 0,
 /* Pushback.  */
 
 void 
-scm_unget_byte (int c, SCM port)
+scm_unget_byte_unlocked (int c, SCM port)
 #define FUNC_NAME "scm_unget_byte"
 {
   scm_t_port *pt = SCM_PTAB_ENTRY (port);
@@ -1766,8 +1838,19 @@ scm_unget_byte (int c, SCM port)
 }
 #undef FUNC_NAME
 
+void 
+scm_unget_byte (int c, SCM port)
+{
+  scm_i_pthread_mutex_t *lock;
+  scm_c_lock_port (port, &lock);
+  scm_unget_byte_unlocked (c, port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+  
+}
+
 void
-scm_ungetc (scm_t_wchar c, SCM port)
+scm_ungetc_unlocked (scm_t_wchar c, SCM port)
 #define FUNC_NAME "scm_ungetc"
 {
   scm_t_port *pt = SCM_PTAB_ENTRY (port);
@@ -1794,7 +1877,7 @@ scm_ungetc (scm_t_wchar c, SCM port)
                        SCM_BOOL_F, SCM_MAKE_CHAR (c));
 
   for (i = len - 1; i >= 0; i--)
-    scm_unget_byte (result[i], port);
+    scm_unget_byte_unlocked (result[i], port);
 
   if (SCM_UNLIKELY (result != result_buf))
     free (result);
@@ -1811,9 +1894,19 @@ scm_ungetc (scm_t_wchar c, SCM port)
 }
 #undef FUNC_NAME
 
+void 
+scm_ungetc (scm_t_wchar c, SCM port)
+{
+  scm_i_pthread_mutex_t *lock;
+  scm_c_lock_port (port, &lock);
+  scm_ungetc_unlocked (c, port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+  
+}
 
 void 
-scm_ungets (const char *s, int n, SCM port)
+scm_ungets_unlocked (const char *s, int n, SCM port)
 {
   /* This is simple minded and inefficient, but unreading strings is
    * probably not a common operation, and remember that line and
@@ -1822,9 +1915,19 @@ scm_ungets (const char *s, int n, SCM port)
    * Please feel free to write an optimized version!
    */
   while (n--)
-    scm_ungetc (s[n], port);
+    scm_ungetc_unlocked (s[n], port);
 }
 
+void
+scm_ungets (const char *s, int n, SCM port)
+{
+  scm_i_pthread_mutex_t *lock;
+  scm_c_lock_port (port, &lock);
+  scm_ungets_unlocked (s, n, port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+  
+}
 
 SCM_DEFINE (scm_peek_char, "peek-char", 0, 1, 0,
            (SCM port),
@@ -1866,7 +1969,7 @@ SCM_DEFINE (scm_peek_char, "peek-char", 0, 1, 0,
   err = get_codepoint (port, &c, bytes, &len);
 
   for (i = len - 1; i >= 0; i--)
-    scm_unget_byte (bytes[i], port);
+    scm_unget_byte_unlocked (bytes[i], port);
 
   SCM_COL (port) = column;
   SCM_LINUM (port) = line;
@@ -1904,7 +2007,7 @@ SCM_DEFINE (scm_unread_char, "unread-char", 1, 1, 0,
 
   c = SCM_CHAR (cobj);
 
-  scm_ungetc (c, port);
+  scm_ungetc_unlocked (c, port);
   return cobj;
 }
 #undef FUNC_NAME
@@ -1926,7 +2029,7 @@ SCM_DEFINE (scm_unread_string, "unread-string", 2, 0, 0,
   n = scm_i_string_length (str);
 
   while (n--)
-    scm_ungetc (scm_i_string_ref (str, n), port);
+    scm_ungetc_unlocked (scm_i_string_ref (str, n), port);
   
   return str;
 }
@@ -1937,6 +2040,8 @@ SCM_DEFINE (scm_unread_string, "unread-string", 2, 0, 0,
 
 /* Manipulating the buffers.  */
 
+/* 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)
 {
@@ -1950,7 +2055,7 @@ scm_port_non_buffer (scm_t_port *pt)
    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 (SCM port)
+scm_fill_input_unlocked (SCM port)
 {
   scm_t_port *pt = SCM_PTAB_ENTRY (port);
 
@@ -1969,6 +2074,21 @@ scm_fill_input (SCM port)
   return SCM_PORT_DESCRIPTOR (port)->fill_input (port);
 }
 
+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);
+  
+
+  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.  */
 size_t
@@ -2044,7 +2164,7 @@ SCM_DEFINE (scm_drain_input, "drain-input", 1, 0, 0,
 #undef FUNC_NAME
 
 void
-scm_end_input (SCM port)
+scm_end_input_unlocked (SCM port)
 {
   long offset;
   scm_t_port *pt = SCM_PTAB_ENTRY (port);
@@ -2063,6 +2183,17 @@ scm_end_input (SCM port)
   SCM_PORT_DESCRIPTOR (port)->end_input (port, offset);
 }
 
+void
+scm_end_input (SCM 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);
+  
+}
+
 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"
@@ -2080,22 +2211,55 @@ SCM_DEFINE (scm_force_output, "force-output", 0, 1, 0,
       port = SCM_COERCE_OUTPORT (port);
       SCM_VALIDATE_OPOUTPORT (1, port);
     }
-  scm_flush (port);
+  scm_flush_unlocked (port);
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
 
 void
-scm_flush (SCM port)
+scm_flush_unlocked (SCM port)
 {
   SCM_PORT_DESCRIPTOR (port)->flush (port);
 }
 
+void
+scm_flush (SCM port)
+{
+  scm_i_pthread_mutex_t *lock;
+  scm_c_lock_port (port, &lock);
+  scm_flush_unlocked (port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+  
+}
+
 
 \f
 
 /* Output.  */
 
+void
+scm_putc (char c, SCM port)
+{
+  scm_i_pthread_mutex_t *lock;
+  scm_c_lock_port (port, &lock);
+  scm_putc_unlocked (c, port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+  
+}
+
+void
+scm_puts (const char *s, SCM port)
+{
+  scm_i_pthread_mutex_t *lock;
+  scm_c_lock_port (port, &lock);
+  scm_puts_unlocked (s, port);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+  
+}
+  
 /* scm_c_write
  *
  * Used by an application to write arbitrary number of bytes to an SCM
@@ -2106,7 +2270,7 @@ scm_flush (SCM port)
  * Warning: Doesn't update port line and column counts!
  */
 void
-scm_c_write (SCM port, const void *ptr, size_t size)
+scm_c_write_unlocked (SCM port, const void *ptr, size_t size)
 #define FUNC_NAME "scm_c_write"
 {
   scm_t_port *pt;
@@ -2118,7 +2282,7 @@ scm_c_write (SCM port, const void *ptr, size_t size)
   ptob = SCM_PORT_DESCRIPTOR (port);
 
   if (pt->rw_active == SCM_PORT_READ)
-    scm_end_input (port);
+    scm_end_input_unlocked (port);
 
   ptob->write (port, ptr, size);
 
@@ -2127,18 +2291,29 @@ scm_c_write (SCM port, const void *ptr, size_t size)
 }
 #undef FUNC_NAME
 
+void
+scm_c_write (SCM port, const void *ptr, size_t size)
+{
+  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_lfwrite
  *
  * This function differs from scm_c_write; it updates port line and
  * column. */
 void
-scm_lfwrite (const char *ptr, size_t size, SCM port)
+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);
 
   if (pt->rw_active == SCM_PORT_READ)
-    scm_end_input (port);
+    scm_end_input_unlocked (port);
 
   ptob->write (port, ptr, size);
 
@@ -2149,6 +2324,17 @@ scm_lfwrite (const char *ptr, size_t size, SCM port)
     pt->rw_active = SCM_PORT_WRITE;
 }
 
+void
+scm_lfwrite (const char *ptr, size_t size, SCM port)
+{
+  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);
+  
+}
+
 /* Write STR to PORT from START inclusive to END exclusive.  */
 void
 scm_lfwrite_substr (SCM str, size_t start, size_t end, SCM port)
@@ -2156,7 +2342,7 @@ 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 (port);
+    scm_end_input_unlocked (port);
 
   if (end == (size_t) -1)
     end = scm_i_string_length (str);
@@ -2356,7 +2542,7 @@ SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
       if (!ptob->truncate)
        SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
       if (pt->rw_active == SCM_PORT_READ)
-       scm_end_input (object);
+       scm_end_input_unlocked (object);
       else if (pt->rw_active == SCM_PORT_WRITE)
        ptob->flush (object);
       
@@ -2475,7 +2661,7 @@ SCM_DEFINE (scm_set_port_filename_x, "set-port-filename!", 2, 0, 0,
 void
 scm_print_port_mode (SCM exp, SCM port)
 {
-  scm_puts (SCM_CLOSEDP (exp)
+  scm_puts_unlocked (SCM_CLOSEDP (exp)
            ? "closed: "
            : (SCM_RDNG & SCM_CELL_WORD_0 (exp)
               ? (SCM_WRTNG & SCM_CELL_WORD_0 (exp)
@@ -2493,12 +2679,12 @@ scm_port_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
   char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
   if (!type)
     type = "port";
-  scm_puts ("#<", port);
+  scm_puts_unlocked ("#<", port);
   scm_print_port_mode (exp, port);
-  scm_puts (type, port);
-  scm_putc (' ', port);
+  scm_puts_unlocked (type, port);
+  scm_putc_unlocked (' ', port);
   scm_uintprint (SCM_CELL_WORD_1 (exp), 16, port);
-  scm_putc ('>', port);
+  scm_putc_unlocked ('>', port);
   return 1;
 }
 
@@ -2563,7 +2749,7 @@ static void
 flush_output_port (void *closure, SCM port)
 {
   if (SCM_OPOUTPORTP (port))
-    scm_flush (port);
+    scm_flush_unlocked (port);
 }
 
 SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
@@ -2652,15 +2838,20 @@ scm_init_ports ()
 #include "libguile/ports.x"
 
   /* Use Latin-1 as the default port encoding.  */
-  SCM_VARIABLE_SET (default_port_encoding_var, scm_make_fluid ());
-  scm_fluid_set_x (SCM_VARIABLE_REF (default_port_encoding_var), SCM_BOOL_F);
+  SCM_VARIABLE_SET (default_port_encoding_var,
+                    scm_make_fluid_with_default (SCM_BOOL_F));
   scm_port_encoding_init = 1;
 
-  SCM_VARIABLE_SET (scm_conversion_strategy, scm_make_fluid ());
-  scm_fluid_set_x (SCM_VARIABLE_REF (scm_conversion_strategy), 
-                  scm_from_int ((int) SCM_FAILED_CONVERSION_QUESTION_MARK));
+  SCM_VARIABLE_SET (scm_conversion_strategy,
+                    scm_make_fluid_with_default
+                    (scm_from_int ((int) SCM_FAILED_CONVERSION_QUESTION_MARK)));
   scm_conversion_strategy_init = 1;
   
+  /* These bindings are used when boot-9 turns `current-input-port' et
+     al into parameters.  They are then removed from the guile module.  */
+  scm_c_define ("%current-input-port-fluid", cur_inport_fluid);
+  scm_c_define ("%current-output-port-fluid", cur_outport_fluid);
+  scm_c_define ("%current-error-port-fluid", cur_errport_fluid);
 }
 
 /*