Fixed an fopen problem on Windows Vista.
[gnupg.git] / common / estream.c
index 131ddc2..214c2ff 100644 (file)
@@ -14,9 +14,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with Libestream; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with Libestream; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifdef USE_ESTREAM_SUPPORT_H
 # include <config.h>
 #endif
 
+#if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
+# define HAVE_W32_SYSTEM 1
+#endif
+
 #include <sys/types.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <stddef.h>
 #include <assert.h>
+#ifdef HAVE_W32_SYSTEM
+# include <windows.h>
+#endif
 
 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth.  */
-#undef HAVE_PTH
-#undef USE_GNU_PTH
+# undef HAVE_PTH
+# undef USE_GNU_PTH
 #endif
 
 #ifdef HAVE_PTH
@@ -51,7 +56,7 @@
 
 /* This is for the special hack to use estream.c in GnuPG.  */
 #ifdef GNUPG_MAJOR_VERSION
-#include "../common/util.h"
+# include "../common/util.h"
 #endif
 
 #ifndef HAVE_MKSTEMP
@@ -67,17 +72,15 @@ void *memrchr (const void *block, int c, size_t size);
 
 \f
 
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
 /* Generally used types.  */
 
 typedef void *(*func_realloc_t) (void *mem, size_t size);
 typedef void (*func_free_t) (void *mem);
 
-#ifdef HAVE_FOPENCOOKIE
-typedef ssize_t my_funopen_hook_ret_t;
-#else
-typedef int     my_funopen_hook_ret_t;
-#endif
-
 
 \f
 
@@ -91,7 +94,6 @@ typedef int     my_funopen_hook_ret_t;
 /* Macros.  */
 
 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
-  (((size) + (block_size - 1)) / block_size)
 
 \f
 
@@ -112,18 +114,26 @@ typedef pth_mutex_t estream_mutex_t;
 #else
 
 typedef void *estream_mutex_t;
-# define ESTREAM_MUTEX_INITIALIZER NULL
-# define ESTREAM_MUTEX_LOCK(mutex) (void) 0
-# define ESTREAM_MUTEX_UNLOCK(mutex) (void) 0
-# define ESTREAM_MUTEX_TRYLOCK(mutex) 0
-# define ESTREAM_MUTEX_INITIALIZE(mutex) (void) 0
-#endif
 
-/* Memory allocator functions.  */
+static inline void
+dummy_mutex_call_void (estream_mutex_t mutex)
+{
+  (void)mutex;
+}
+
+static inline int
+dummy_mutex_call_int (estream_mutex_t mutex)
+{
+  (void)mutex;
+  return 0;
+}
 
-#define ES_MEM_ALLOC   malloc
-#define ES_MEM_REALLOC realloc
-#define ES_MEM_FREE    free
+# define ESTREAM_MUTEX_INITIALIZER NULL
+# define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex))
+# define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex))
+# define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex))
+# define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex))
+#endif
 
 /* Primitive system I/O.  */
 
@@ -139,8 +149,6 @@ typedef void *estream_mutex_t;
 
 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
 
-#define ES_FLAG_WRITING ES__FLAG_WRITING
-
 /* An internal stream object.  */
 
 struct estream_internal
@@ -148,9 +156,9 @@ struct estream_internal
   unsigned char buffer[BUFFER_BLOCK_SIZE];
   unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
   estream_mutex_t lock;                 /* Lock. */
-  void *cookie;                         /* Cookie.               */
-  void *opaque;                         /* Opaque data.          */
-  unsigned int flags;           /* Flags.                */
+  void *cookie;                         /* Cookie.                */
+  void *opaque;                         /* Opaque data.           */
+  unsigned int modeflags;       /* Flags for the backend. */
   off_t offset;
   es_cookie_read_function_t func_read;
   es_cookie_write_function_t func_write;
@@ -189,11 +197,7 @@ struct estream_list
 };
 
 static estream_list_t estream_list;
-#ifdef HAVE_PTH
-/* Note that we can't use a static initialization with W32Pth, thus we
-   do it in es_init. */
 static estream_mutex_t estream_list_lock;
-#endif
 
 #define ESTREAM_LIST_LOCK   ESTREAM_MUTEX_LOCK   (estream_list_lock)
 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
@@ -212,6 +216,9 @@ static estream_mutex_t estream_list_lock;
 #define DIM(array) (sizeof (array) / sizeof (*array))
 #endif
 
+#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
+
+
 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
    VARIABLE is zero.  */
 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
@@ -223,6 +230,33 @@ static estream_mutex_t estream_list_lock;
     }                                                          \
   while (0)
 
+
+/* Malloc wrappers to overcvome problems on some older OSes.  */
+static void *
+mem_alloc (size_t n)
+{
+  if (!n)
+    n++;
+  return malloc (n);
+}
+
+static void *
+mem_realloc (void *p, size_t n)
+{
+  if (!p)
+    return mem_alloc (n);
+  return realloc (p, n);
+}
+
+static void
+mem_free (void *p)
+{
+  if (p)
+    free (p);
+}
+
+
+
 /*
  * List manipulation.
  */
@@ -234,7 +268,7 @@ es_list_add (estream_t stream)
   estream_list_t list_obj;
   int ret;
 
-  list_obj = ES_MEM_ALLOC (sizeof (*list_obj));
+  list_obj = mem_alloc (sizeof (*list_obj));
   if (! list_obj)
     ret = -1;
   else
@@ -266,7 +300,7 @@ es_list_remove (estream_t stream)
        *list_obj->prev_cdr = list_obj->cdr;
        if (list_obj->cdr)
          list_obj->cdr->prev_cdr = list_obj->prev_cdr;
-       ES_MEM_FREE (list_obj);
+       mem_free (list_obj);
        break;
       }
   ESTREAM_LIST_UNLOCK;
@@ -305,7 +339,7 @@ es_init_do (void)
 
   if (!initialized)
     {
-      if (!pth_init ())
+      if (!pth_init () && errno != EPERM )
         return -1;
       if (pth_mutex_init (&estream_list_lock))
         initialized = 1;
@@ -325,54 +359,50 @@ es_init_do (void)
 /* Cookie for memory objects.  */
 typedef struct estream_cookie_mem
 {
-  unsigned int flags;          /* Open flags.  */
-  unsigned char *memory;       /* Data.  */
-  size_t memory_size;          /* Size of MEMORY.  */
+  unsigned int modeflags;      /* Open flags.  */
+  unsigned char *memory;       /* Allocated data buffer.  */
+  size_t memory_size;          /* Allocated size of memory.  */
+  size_t memory_limit;          /* Maximum allowed allocation size or
+                                   0 for no limit.  */
   size_t offset;               /* Current offset in MEMORY.  */
   size_t data_len;             /* Length of data in MEMORY.  */
   size_t block_size;           /* Block size.  */
-  unsigned int grow: 1;                /* MEMORY is allowed to grow.  */
-  unsigned int append_zero: 1; /* Append zero after data.  */
-  unsigned int dont_free: 1;   /* Append zero after data.  */
-  char **ptr;
-  size_t *size;
+  struct {
+    unsigned int grow: 1;      /* MEMORY is allowed to grow.  */
+  } flags;
   func_realloc_t func_realloc;
   func_free_t func_free;
 } *estream_cookie_mem_t;
 
+
 /* Create function for memory objects.  */
 static int
 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
                    unsigned char *ES__RESTRICT data, size_t data_n,
                    size_t data_len,
                    size_t block_size, unsigned int grow,
-                   unsigned int append_zero, unsigned int dont_free,
-                   char **ptr, size_t *size,
                    func_realloc_t func_realloc, func_free_t func_free,
-                   unsigned int flags)
+                   unsigned int modeflags,
+                    size_t memory_limit)
 {
   estream_cookie_mem_t mem_cookie;
   int err;
 
-  mem_cookie = ES_MEM_ALLOC (sizeof (*mem_cookie));
-  if (! mem_cookie)
+  mem_cookie = mem_alloc (sizeof (*mem_cookie));
+  if (!mem_cookie)
     err = -1;
   else
     {
-      mem_cookie->flags = flags;
+      mem_cookie->modeflags = modeflags;
       mem_cookie->memory = data;
       mem_cookie->memory_size = data_n;
+      mem_cookie->memory_limit = memory_limit;
       mem_cookie->offset = 0;
       mem_cookie->data_len = data_len;
       mem_cookie->block_size = block_size;
-      mem_cookie->grow = grow ? 1 : 0;
-      mem_cookie->append_zero = append_zero ? 1 : 0;
-      mem_cookie->dont_free = dont_free ? 1 : 0;
-      mem_cookie->ptr = ptr;
-      mem_cookie->size = size;
-      mem_cookie->func_realloc = func_realloc ? func_realloc : ES_MEM_REALLOC;
-      mem_cookie->func_free = func_free ? func_free : ES_MEM_FREE;
-      mem_cookie->offset = 0;
+      mem_cookie->flags.grow = !!grow;
+      mem_cookie->func_realloc = func_realloc ? func_realloc : mem_realloc;
+      mem_cookie->func_free = func_free ? func_free : mem_free;
       *cookie = mem_cookie;
       err = 0;
     }
@@ -380,6 +410,7 @@ es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
   return err;
 }
 
+
 /* Read function for memory objects.  */
 static ssize_t
 es_func_mem_read (void *cookie, void *buffer, size_t size)
@@ -397,115 +428,89 @@ es_func_mem_read (void *cookie, void *buffer, size_t size)
     }
   
   ret = size;
-
   return ret;
 }
 
+
 /* Write function for memory objects.  */
 static ssize_t
 es_func_mem_write (void *cookie, const void *buffer, size_t size)
 {
   estream_cookie_mem_t mem_cookie = cookie;
-  func_realloc_t func_realloc = mem_cookie->func_realloc;
-  unsigned char *memory_new;
-  size_t newsize;
   ssize_t ret;
-  int err;
-
-  if (size)
-    {
-      /* Regular write.  */
 
-      if (mem_cookie->flags & O_APPEND)
-       /* Append to data.  */
-       mem_cookie->offset = mem_cookie->data_len;
-         
-      if (! mem_cookie->grow)
-       if (size > mem_cookie->memory_size - mem_cookie->offset)
-         size = mem_cookie->memory_size - mem_cookie->offset;
+  if (!size)
+    return 0;  /* A flush is a NOP for memory objects.  */
 
-      err = 0;
-
-      while (size > (mem_cookie->memory_size - mem_cookie->offset))
-       {
-         memory_new = (*func_realloc) (mem_cookie->memory,
-                                       mem_cookie->memory_size
-                                       + mem_cookie->block_size);
-         if (! memory_new)
-           {
-             err = -1;
-             break;
-           }
-         else
-           {
-             if (mem_cookie->memory != memory_new)
-               mem_cookie->memory = memory_new;
-             mem_cookie->memory_size += mem_cookie->block_size;
-           }
-       }
-      if (err)
-       goto out;
-
-      if (size)
-       {
-         memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
-         if (mem_cookie->offset + size > mem_cookie->data_len)
-           mem_cookie->data_len = mem_cookie->offset + size;
-         mem_cookie->offset += size;
-       }
-    }
-  else
+  if (mem_cookie->modeflags & O_APPEND)
     {
-      /* Flush.  */
-
-      err = 0;
-      if (mem_cookie->append_zero)
-       {
-         if (mem_cookie->data_len >= mem_cookie->memory_size)
-           {
-             newsize = BUFFER_ROUND_TO_BLOCK (mem_cookie->data_len + 1,
-                                              mem_cookie->block_size)
-               * mem_cookie->block_size;
+      /* Append to data.  */
+      mem_cookie->offset = mem_cookie->data_len;
+    }
          
-             memory_new = (*func_realloc) (mem_cookie->memory, newsize);
-             if (! memory_new)
-               {
-                 err = -1;
-                 goto out;
-               }
-
-             if (mem_cookie->memory != memory_new)
-               mem_cookie->memory = memory_new;
-             mem_cookie->memory_size = newsize;
-           }
-
-         mem_cookie->memory[mem_cookie->data_len + 1] = 0;
-       }
-
-      /* Return information to user if necessary.  */
-      if (mem_cookie->ptr)
-       *mem_cookie->ptr = (char *) mem_cookie->memory;
-      if (mem_cookie->size)
-       *mem_cookie->size = mem_cookie->data_len;
+  if (!mem_cookie->flags.grow)
+    {
+      /* We are not alloew to grow, thus limit the size to the left
+         space.  FIXME: Does the grow flag an its semtics make sense
+         at all? */
+      if (size > mem_cookie->memory_size - mem_cookie->offset)
+        size = mem_cookie->memory_size - mem_cookie->offset;
     }
 
- out:
-
-  if (err)
-    ret = -1;
-  else
-    ret = size;
+  if (size > (mem_cookie->memory_size - mem_cookie->offset))
+    {
+      unsigned char *newbuf;
+      size_t newsize;
+      
+      newsize = mem_cookie->memory_size + mem_cookie->block_size;
+      
+      newsize = mem_cookie->offset + size;
+      if (newsize < mem_cookie->offset)
+        {
+          errno = EINVAL;
+          return -1;
+        }
+      newsize += mem_cookie->block_size - 1;
+      if (newsize < mem_cookie->offset)
+        {
+          errno = EINVAL;
+          return -1;
+        }
+      newsize /= mem_cookie->block_size;
+      newsize *= mem_cookie->block_size;
+      
+      if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
+        {
+          errno = ENOSPC;
+          return -1;
+        }
+      
+      newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
+      if (!newbuf)
+        return -1;
+      
+      mem_cookie->memory = newbuf;
+      mem_cookie->memory_size = newsize;
+      
+      assert (!(size > (mem_cookie->memory_size - mem_cookie->offset)));
+    }
+      
+  memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
+  if (mem_cookie->offset + size > mem_cookie->data_len)
+    mem_cookie->data_len = mem_cookie->offset + size;
+  mem_cookie->offset += size;
 
+  ret = size;
   return ret;
 }
 
+
 /* Seek function for memory objects.  */
 static int
 es_func_mem_seek (void *cookie, off_t *offset, int whence)
 {
   estream_cookie_mem_t mem_cookie = cookie;
   off_t pos_new;
-  int err = 0;
 
   switch (whence)
     {
@@ -522,69 +527,74 @@ es_func_mem_seek (void *cookie, off_t *offset, int whence)
       break;
 
     default:
-      /* Never reached.  */
-      pos_new = 0;
+      errno = EINVAL;
+      return -1;
     }
 
   if (pos_new > mem_cookie->memory_size)
     {
-      /* Grow buffer if possible.  */
+      size_t newsize;
+      void *newbuf;
 
-      if (mem_cookie->grow)
+      if (!mem_cookie->flags.grow)
        {
-         func_realloc_t func_realloc = mem_cookie->func_realloc;
-         size_t newsize;
-         void *p;
+         errno = ENOSPC;
+         return -1;
 
-         newsize = BUFFER_ROUND_TO_BLOCK (pos_new, mem_cookie->block_size);
-         p = (*func_realloc) (mem_cookie->memory, newsize);
-         if (! p)
-           {
-             err = -1;
-             goto out;
-           }
-         else
-           {
-             if (mem_cookie->memory != p)
-               mem_cookie->memory = p;
-             mem_cookie->memory_size = newsize;
-           }
-       }
-      else
-       {
-         errno = EINVAL;
-         err = -1;
-         goto out;
-       }
+        }
+
+      newsize = pos_new + mem_cookie->block_size - 1;
+      if (newsize < pos_new)
+        {
+          errno = EINVAL;
+          return -1;
+        }
+      newsize /= mem_cookie->block_size;
+      newsize *= mem_cookie->block_size;
+      if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
+        {
+          errno = ENOSPC;
+          return -1;
+        }
+      
+      newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
+      if (!newbuf)
+        return -1;
+
+      mem_cookie->memory = newbuf;
+      mem_cookie->memory_size = newsize;
     }
 
   if (pos_new > mem_cookie->data_len)
-    /* Fill spare space with zeroes.  */
-    memset (mem_cookie->memory + mem_cookie->data_len,
-           0, pos_new - mem_cookie->data_len);
+    {
+      /* Fill spare space with zeroes.  */
+      memset (mem_cookie->memory + mem_cookie->data_len,
+              0, pos_new - mem_cookie->data_len);
+      mem_cookie->data_len = pos_new;
+    }
 
   mem_cookie->offset = pos_new;
   *offset = pos_new;
 
- out:
-
-  return err;
+  return 0;
 }
 
+
 /* Destroy function for memory objects.  */
 static int
 es_func_mem_destroy (void *cookie)
 {
   estream_cookie_mem_t mem_cookie = cookie;
-  func_free_t func_free = mem_cookie->func_free;
-
-  if (! mem_cookie->dont_free)
-    (*func_free) (mem_cookie->memory);
-  ES_MEM_FREE (mem_cookie);
 
+  if (cookie)
+    {
+      mem_cookie->func_free (mem_cookie->memory);
+      mem_free (mem_cookie);
+    }
   return 0;
 }
 
+
 static es_cookie_io_functions_t estream_functions_mem =
   {
     es_func_mem_read,
@@ -593,27 +603,38 @@ static es_cookie_io_functions_t estream_functions_mem =
     es_func_mem_destroy
   };
 
+
+\f
 /* Implementation of fd I/O.  */
 
 /* Cookie for fd objects.  */
 typedef struct estream_cookie_fd
 {
-  int fd;
+  int fd;        /* The file descriptor we are using for actual output.  */
+  int no_close;  /* If set we won't close the file descriptor.  */
 } *estream_cookie_fd_t;
 
 /* Create function for fd objects.  */
 static int
-es_func_fd_create (void **cookie, int fd, unsigned int flags)
+es_func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
 {
   estream_cookie_fd_t fd_cookie;
   int err;
 
-  fd_cookie = ES_MEM_ALLOC (sizeof (*fd_cookie));
+  fd_cookie = mem_alloc (sizeof (*fd_cookie));
   if (! fd_cookie)
     err = -1;
   else
     {
+#ifdef HAVE_DOSISH_SYSTEM
+      /* Make sure it is in binary mode if requested.  */
+      if ( (modeflags & O_BINARY) )
+        setmode (fd, O_BINARY);
+#else
+      (void)modeflags;
+#endif
       fd_cookie->fd = fd;
+      fd_cookie->no_close = no_close;
       *cookie = fd_cookie;
       err = 0;
     }
@@ -680,8 +701,8 @@ es_func_fd_destroy (void *cookie)
 
   if (fd_cookie)
     {
-      err = close (fd_cookie->fd);
-      ES_MEM_FREE (fd_cookie);
+      err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
+      mem_free (fd_cookie);
     }
   else
     err = 0;
@@ -689,6 +710,7 @@ es_func_fd_destroy (void *cookie)
   return err;
 }
 
+
 static es_cookie_io_functions_t estream_functions_fd =
   {
     es_func_fd_read,
@@ -697,12 +719,135 @@ static es_cookie_io_functions_t estream_functions_fd =
     es_func_fd_destroy
   };
 
+
+
+\f
+/* Implementation of FILE* I/O.  */
+
+/* Cookie for fp objects.  */
+typedef struct estream_cookie_fp
+{
+  FILE *fp;      /* The file pointer we are using for actual output.  */
+  int no_close;  /* If set we won't close the file pointer.  */
+} *estream_cookie_fp_t;
+
+/* Create function for fd objects.  */
+static int
+es_func_fp_create (void **cookie, FILE *fp, 
+                   unsigned int modeflags, int no_close)
+{
+  estream_cookie_fp_t fp_cookie;
+  int err;
+
+  fp_cookie = mem_alloc (sizeof *fp_cookie);
+  if (!fp_cookie)
+    err = -1;
+  else
+    {
+#ifdef HAVE_DOSISH_SYSTEM
+      /* Make sure it is in binary mode if requested.  */
+      if ( (modeflags & O_BINARY) )
+        setmode (fileno (fp), O_BINARY);
+#else
+      (void)modeflags;
+#endif
+      fp_cookie->fp = fp;
+      fp_cookie->no_close = no_close;
+      *cookie = fp_cookie;
+      err = 0;
+    }
+  
+  return err;
+}
+
+/* Read function for FILE* objects.  */
+static ssize_t
+es_func_fp_read (void *cookie, void *buffer, size_t size)
+
+{
+  estream_cookie_fp_t file_cookie = cookie;
+  ssize_t bytes_read;
+
+  bytes_read = fread (buffer, 1, size, file_cookie->fp);
+  if (!bytes_read && ferror (file_cookie->fp))
+    return -1;
+  return bytes_read;
+}
+
+/* Write function for FILE* objects.  */
+static ssize_t
+es_func_fp_write (void *cookie, const void *buffer, size_t size)
+                          
+{
+  estream_cookie_fp_t file_cookie = cookie;
+  size_t bytes_written;
+
+  bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
+  if (bytes_written != size)
+    return -1;
+  return bytes_written;
+}
+
+/* Seek function for FILE* objects.  */
+static int
+es_func_fp_seek (void *cookie, off_t *offset, int whence)
+{
+  estream_cookie_fp_t file_cookie = cookie;
+  long int offset_new;
+
+  if ( fseek (file_cookie->fp, (long int)*offset, whence) )
+    {
+      fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", errno,strerror (errno));
+    return -1;
+    }
+
+  offset_new = ftell (file_cookie->fp);
+  if (offset_new == -1)
+    {
+      fprintf (stderr, "\nftell failed: errno=%d (%s)\n", errno,strerror (errno));
+    return -1;
+    }
+  *offset = offset_new;
+  return 0;
+}
+
+/* Destroy function for fd objects.  */
+static int
+es_func_fp_destroy (void *cookie)
+{
+  estream_cookie_fp_t fp_cookie = cookie;
+  int err;
+
+  if (fp_cookie)
+    {
+      fflush (fp_cookie->fp);
+      err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
+      mem_free (fp_cookie);
+    }
+  else
+    err = 0;
+
+  return err;
+}
+
+
+static es_cookie_io_functions_t estream_functions_fp =
+  {
+    es_func_fp_read,
+    es_func_fp_write,
+    es_func_fp_seek,
+    es_func_fp_destroy
+  };
+
+
+
+\f
 /* Implementation of file I/O.  */
 
 /* Create function for file objects.  */
 static int
 es_func_file_create (void **cookie, int *filedes,
-                    const char *path, unsigned int flags)
+                    const char *path, unsigned int modeflags)
 {
   estream_cookie_fd_t file_cookie;
   int err;
@@ -711,28 +856,34 @@ es_func_file_create (void **cookie, int *filedes,
   err = 0;
   fd = -1;
 
-  file_cookie = ES_MEM_ALLOC (sizeof (*file_cookie));
+  file_cookie = mem_alloc (sizeof (*file_cookie));
   if (! file_cookie)
     {
       err = -1;
       goto out;
     }
 
-  fd = open (path, flags, ES_DEFAULT_OPEN_MODE);
+  fd = open (path, modeflags, ES_DEFAULT_OPEN_MODE);
   if (fd == -1)
     {
       err = -1;
       goto out;
     }
+#ifdef HAVE_DOSISH_SYSTEM
+  /* Make sure it is in binary mode if requested.  */
+  if ( (modeflags & O_BINARY) )
+    setmode (fd, O_BINARY);
+#endif
 
   file_cookie->fd = fd;
+  file_cookie->no_close = 0;
   *cookie = file_cookie;
   *filedes = fd;
 
  out:
 
   if (err)
-    ES_MEM_FREE (file_cookie);
+    mem_free (file_cookie);
 
   return err;
 }
@@ -746,72 +897,49 @@ static es_cookie_io_functions_t estream_functions_file =
   };
 
 \f
-
-/* Stream primitives.  */
-
 static int
-es_convert_mode (const char *mode, unsigned int *flags)
+es_convert_mode (const char *mode, unsigned int *modeflags)
 {
+  unsigned int omode, oflags;
 
-  /* FIXME: We need to allow all mode flags permutations and for
-     binary mode we need to do a
-
-     #ifdef HAVE_DOSISH_SYSTEM
-       setmode (fd, O_BINARY);
-     #endif
-  */
-  struct
-  {
-    const char *mode;
-    unsigned int flags;
-  } mode_flags[] = { { "r",
-                      O_RDONLY },
-                    { "rb",
-                      O_RDONLY },
-                    { "w",
-                      O_WRONLY | O_TRUNC | O_CREAT },
-                    { "wb",
-                      O_WRONLY | O_TRUNC | O_CREAT },
-                    { "a",
-                      O_WRONLY | O_APPEND | O_CREAT },
-                    { "ab",
-                      O_WRONLY | O_APPEND | O_CREAT },
-                    { "r+",
-                      O_RDWR },
-                    { "rb+",
-                      O_RDWR },
-                    { "r+b",
-                      O_RDONLY | O_WRONLY },
-                    { "w+",
-                      O_RDWR | O_TRUNC | O_CREAT },
-                    { "wb+",
-                      O_RDWR | O_TRUNC | O_CREAT },
-                    { "w+b",
-                      O_RDWR | O_TRUNC | O_CREAT },
-                    { "a+",
-                      O_RDWR | O_CREAT | O_APPEND },
-                    { "ab+",
-                      O_RDWR | O_CREAT | O_APPEND },
-                    { "a+b",
-                      O_RDWR | O_CREAT | O_APPEND } };
-  unsigned int i;
-  int err; 
-
-  for (i = 0; i < DIM (mode_flags); i++)
-    if (! strcmp (mode_flags[i].mode, mode))
-      break;
-  if (i == DIM (mode_flags))
+  switch (*mode)
     {
+    case 'r':
+      omode = O_RDONLY;
+      oflags = 0;
+      break;
+    case 'w':
+      omode = O_WRONLY;
+      oflags = O_TRUNC | O_CREAT;
+      break;
+    case 'a':
+      omode = O_WRONLY;
+      oflags = O_APPEND | O_CREAT;
+      break;
+    default:
       errno = EINVAL;
-      err = -1;
+      return -1;
     }
-  else
+  for (mode++; *mode; mode++)
     {
-      err = 0;
-      *flags = mode_flags[i].flags;
+      switch (*mode)
+        {
+        case '+':
+          omode = O_RDWR;
+          break;
+        case 'b':
+          oflags |= O_BINARY;
+          break;
+        case 'x':
+          oflags |= O_EXCL;
+          break;
+        default: /* Ignore unknown flags.  */
+          break; 
+        }
     }
 
-  return err;
+  *modeflags = (omode | oflags);
+  return 0;
 }
 
 \f
@@ -868,7 +996,7 @@ es_flush (estream_t stream)
   es_cookie_write_function_t func_write = stream->intern->func_write;
   int err;
 
-  assert (stream->flags & ES_FLAG_WRITING);
+  assert (stream->flags.writing);
 
   if (stream->data_offset)
     {
@@ -935,7 +1063,7 @@ es_flush (estream_t stream)
 static void
 es_empty (estream_t stream)
 {
-  assert (! (stream->flags & ES_FLAG_WRITING));
+  assert (!stream->flags.writing);
   stream->data_len = 0;
   stream->data_offset = 0;
   stream->unread_data_len = 0;
@@ -944,7 +1072,8 @@ es_empty (estream_t stream)
 /* Initialize STREAM.  */
 static void
 es_initialize (estream_t stream,
-              void *cookie, int fd, es_cookie_io_functions_t functions)
+              void *cookie, int fd, es_cookie_io_functions_t functions,
+               unsigned int modeflags)
 {
   stream->intern->cookie = cookie;
   stream->intern->opaque = NULL;
@@ -967,7 +1096,15 @@ es_initialize (estream_t stream,
   stream->data_offset = 0;
   stream->data_flushed = 0;
   stream->unread_data_len = 0;
-  stream->flags = 0;
+  /* Depending on the modeflags we set whether we start in writing or
+     reading mode.  This is required in case we are working on a
+     wronly stream which is not seeekable (like stdout).  Without this
+     pre-initialization we would do a seek at the first write call and
+     as this will fail no utput will be delivered. */
+  if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
+    stream->flags.writing = 1;
+  else
+    stream->flags.writing = 0;
 }
 
 /* Deinitialize STREAM.  */
@@ -988,7 +1125,7 @@ es_deinitialize (estream_t stream)
   func_close = stream->intern->func_close;
 
   err = 0;
-  if (stream->flags & ES_FLAG_WRITING)
+  if (stream->flags.writing)
     SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
   if (func_close)
     SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
@@ -1000,7 +1137,7 @@ es_deinitialize (estream_t stream)
 /* Create a new stream object, initialize it.  */
 static int
 es_create (estream_t *stream, void *cookie, int fd,
-          es_cookie_io_functions_t functions)
+          es_cookie_io_functions_t functions, unsigned int modeflags)
 {
   estream_internal_t stream_internal_new;
   estream_t stream_new;
@@ -1009,14 +1146,14 @@ es_create (estream_t *stream, void *cookie, int fd,
   stream_new = NULL;
   stream_internal_new = NULL;
 
-  stream_new = ES_MEM_ALLOC (sizeof (*stream_new));
+  stream_new = mem_alloc (sizeof (*stream_new));
   if (! stream_new)
     {
       err = -1;
       goto out;
     }
 
-  stream_internal_new = ES_MEM_ALLOC (sizeof (*stream_internal_new));
+  stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
   if (! stream_internal_new)
     {
       err = -1;
@@ -1030,7 +1167,7 @@ es_create (estream_t *stream, void *cookie, int fd,
   stream_new->intern = stream_internal_new;
 
   ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
-  es_initialize (stream_new, cookie, fd, functions);
+  es_initialize (stream_new, cookie, fd, functions, modeflags);
 
   err = es_list_add (stream_new);
   if (err)
@@ -1045,7 +1182,7 @@ es_create (estream_t *stream, void *cookie, int fd,
       if (stream_new)
        {
          es_deinitialize (stream_new);
-         ES_MEM_FREE (stream_new);
+         mem_free (stream_new);
        }
     }
 
@@ -1062,8 +1199,8 @@ es_destroy (estream_t stream)
     {
       es_list_remove (stream);
       err = es_deinitialize (stream);
-      ES_MEM_FREE (stream->intern);
-      ES_MEM_FREE (stream);
+      mem_free (stream->intern);
+      mem_free (stream);
     }
 
   return err;
@@ -1186,13 +1323,13 @@ es_readn (estream_t ES__RESTRICT stream,
   data_read = 0;
   err = 0;
 
-  if (stream->flags & ES_FLAG_WRITING)
+  if (stream->flags.writing)
     {
       /* Switching to reading mode -> flush output.  */
       err = es_flush (stream);
       if (err)
        goto out;
-      stream->flags &= ~ES_FLAG_WRITING;
+      stream->flags.writing = 0;
     }  
 
   /* Read unread data first.  */
@@ -1274,14 +1411,14 @@ es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
       goto out;
     }
 
-  if (stream->flags & ES_FLAG_WRITING)
+  if (stream->flags.writing)
     {
       /* Flush data first in order to prevent flushing it to the wrong
         offset.  */
       err = es_flush (stream);
       if (err)
        goto out;
-      stream->flags &= ~ES_FLAG_WRITING;
+      stream->flags.writing = 0;
     }
 
   off = offset;
@@ -1451,7 +1588,7 @@ es_writen (estream_t ES__RESTRICT stream,
   data_written = 0;
   err = 0;
   
-  if (! (stream->flags & ES_FLAG_WRITING))
+  if (!stream->flags.writing)
     {
       /* Switching to writing mode -> discard input data and seek to
         position at which reading has stopped.  We can do this only
@@ -1489,8 +1626,8 @@ es_writen (estream_t ES__RESTRICT stream,
   if (bytes_written)
     *bytes_written = data_written;
   if (data_written)
-    if (! (stream->flags & ES_FLAG_WRITING))
-      stream->flags |= ES_FLAG_WRITING;
+    if (!stream->flags.writing)
+      stream->flags.writing = 1;
 
   return err;
 }
@@ -1502,13 +1639,13 @@ es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
 {
   int err;
 
-  if (stream->flags & ES_FLAG_WRITING)
+  if (stream->flags.writing)
     {
       /* Switching to reading mode -> flush output.  */
       err = es_flush (stream);
       if (err)
        goto out;
-      stream->flags &= ~ES_FLAG_WRITING;
+      stream->flags.writing = 0;
     }  
 
   if (stream->data_offset == stream->data_len)
@@ -1554,8 +1691,8 @@ es_skip (estream_t stream, size_t size)
 
 static int
 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
-             char *ES__RESTRICT *ES__RESTRICT line,
-             size_t *ES__RESTRICT line_length)
+            char *ES__RESTRICT *ES__RESTRICT line,
+            size_t *ES__RESTRICT line_length)
 {
   size_t space_left;
   size_t line_size;
@@ -1571,13 +1708,16 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
   line_stream = NULL;
   line_stream_cookie = NULL;
 
-  err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0, BUFFER_BLOCK_SIZE,
-                           1, 0, 0, NULL, 0, ES_MEM_REALLOC, ES_MEM_FREE, O_RDWR);
+  err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0,
+                            BUFFER_BLOCK_SIZE, 1,
+                            mem_realloc, mem_free, 
+                            O_RDWR,
+                            0);
   if (err)
     goto out;
 
   err = es_create (&line_stream, line_stream_cookie, -1,
-                  estream_functions_mem);
+                  estream_functions_mem, O_RDWR);
   if (err)
     goto out;
 
@@ -1638,7 +1778,7 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
 
   if (! *line)
     {
-      line_new = ES_MEM_ALLOC (line_size + 1);
+      line_new = mem_alloc (line_size + 1);
       if (! line_new)
        {
          err = -1;
@@ -1669,7 +1809,7 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
   if (err)
     {
       if (! *line)
-       ES_MEM_FREE (line_new);
+       mem_free (line_new);
       stream->intern->indicators.err = 1;
     }
 
@@ -1738,7 +1878,7 @@ es_set_buffering (estream_t ES__RESTRICT stream,
   int err;
 
   /* Flush or empty buffer depending on mode.  */
-  if (stream->flags & ES_FLAG_WRITING)
+  if (stream->flags.writing)
     {
       err = es_flush (stream);
       if (err)
@@ -1753,7 +1893,7 @@ es_set_buffering (estream_t ES__RESTRICT stream,
   if (stream->intern->deallocate_buffer)
     {
       stream->intern->deallocate_buffer = 0;
-      ES_MEM_FREE (stream->buffer);
+      mem_free (stream->buffer);
       stream->buffer = NULL;
     }
 
@@ -1767,7 +1907,7 @@ es_set_buffering (estream_t ES__RESTRICT stream,
        buffer_new = buffer;
       else
        {
-         buffer_new = ES_MEM_ALLOC (size);
+         buffer_new = mem_alloc (size);
          if (! buffer_new)
            {
              err = -1;
@@ -1839,7 +1979,7 @@ es_init (void)
 estream_t
 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
 {
-  unsigned int flags;
+  unsigned int modeflags;
   int create_called;
   estream_t stream;
   void *cookie;
@@ -1850,16 +1990,16 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
   cookie = NULL;
   create_called = 0;
 
-  err = es_convert_mode (mode, &flags);
+  err = es_convert_mode (mode, &modeflags);
   if (err)
     goto out;
   
-  err = es_func_file_create (&cookie, &fd, path, flags);
+  err = es_func_file_create (&cookie, &fd, path, modeflags);
   if (err)
     goto out;
 
   create_called = 1;
-  err = es_create (&stream, cookie, fd, estream_functions_file);
+  err = es_create (&stream, cookie, fd, estream_functions_file, modeflags);
   if (err)
     goto out;
 
@@ -1878,7 +2018,7 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
          func_realloc_t func_realloc, func_free_t func_free,
          const char *ES__RESTRICT mode)
 {
-  unsigned int flags;
+  unsigned int modeflags;
   int create_called;
   estream_t stream;
   void *cookie;
@@ -1888,18 +2028,18 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
   stream = NULL;
   create_called = 0;
   
-  err = es_convert_mode (mode, &flags);
+  err = es_convert_mode (mode, &modeflags);
   if (err)
     goto out;
 
   err = es_func_mem_create (&cookie, data, data_n, data_len,
-                           BUFFER_BLOCK_SIZE, grow, 0, 0,
-                           NULL, 0, func_realloc, func_free, flags);
+                           BUFFER_BLOCK_SIZE, grow, 
+                           func_realloc, func_free, modeflags, 0);
   if (err)
     goto out;
   
   create_called = 1;
-  err = es_create (&stream, cookie, -1, estream_functions_mem);
+  err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags);
 
  out:
 
@@ -1911,54 +2051,50 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
 
 
 estream_t
-es_open_memstream (char **ptr, size_t *size)
+es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
 {
-  unsigned int flags;
-  int create_called;
-  estream_t stream;
-  void *cookie;
-  int err;
+  unsigned int modeflags;
+  estream_t stream = NULL;
+  void *cookie = NULL;
+
+  /* Memory streams are always read/write.  We use MODE only to get
+     the append flag.  */
+  if (es_convert_mode (mode, &modeflags))
+    return NULL;
+  modeflags |= O_RDWR;
 
-  flags = O_RDWR;
-  create_called = 0;
-  stream = NULL;
-  cookie = 0;
   
-  err = es_func_mem_create (&cookie, NULL, 0, 0,
-                           BUFFER_BLOCK_SIZE, 1, 1, 1,
-                           ptr, size, ES_MEM_REALLOC, ES_MEM_FREE, flags);
-  if (err)
-    goto out;
+  if (es_func_mem_create (&cookie, NULL, 0, 0,
+                          BUFFER_BLOCK_SIZE, 1,
+                          mem_realloc, mem_free, modeflags,
+                          memlimit))
+    return NULL;
   
-  create_called = 1;
-  err = es_create (&stream, cookie, -1, estream_functions_mem);
-
- out:
-
-  if (err && create_called)
+  if (es_create (&stream, cookie, -1, estream_functions_mem, modeflags))
     (*estream_functions_mem.func_close) (cookie);
 
   return stream;
 }
 
 
+
 estream_t
 es_fopencookie (void *ES__RESTRICT cookie,
                const char *ES__RESTRICT mode,
                es_cookie_io_functions_t functions)
 {
-  unsigned int flags;
+  unsigned int modeflags;
   estream_t stream;
   int err;
 
   stream = NULL;
-  flags = 0;
+  modeflags = 0;
   
-  err = es_convert_mode (mode, &flags);
+  err = es_convert_mode (mode, &modeflags);
   if (err)
     goto out;
 
-  err = es_create (&stream, cookie, -1, functions);
+  err = es_create (&stream, cookie, -1, functions, modeflags);
   if (err)
     goto out;
 
@@ -1969,9 +2105,9 @@ es_fopencookie (void *ES__RESTRICT cookie,
 
 
 estream_t
-es_fdopen (int filedes, const char *mode)
+do_fdopen (int filedes, const char *mode, int no_close)
 {
-  unsigned int flags;
+  unsigned int modeflags;
   int create_called;
   estream_t stream;
   void *cookie;
@@ -1981,16 +2117,16 @@ es_fdopen (int filedes, const char *mode)
   cookie = NULL;
   create_called = 0;
 
-  err = es_convert_mode (mode, &flags);
+  err = es_convert_mode (mode, &modeflags);
   if (err)
     goto out;
 
-  err = es_func_fd_create (&cookie, filedes, flags);
+  err = es_func_fd_create (&cookie, filedes, modeflags, no_close);
   if (err)
     goto out;
 
   create_called = 1;
-  err = es_create (&stream, cookie, filedes, estream_functions_fd);
+  err = es_create (&stream, cookie, filedes, estream_functions_fd, modeflags);
 
  out:
 
@@ -1999,7 +2135,78 @@ es_fdopen (int filedes, const char *mode)
 
   return stream;
 }
+
+estream_t
+es_fdopen (int filedes, const char *mode)
+{
+  return do_fdopen (filedes, mode, 0);
+}
+
+/* A variant of es_fdopen which does not close FILEDES at the end.  */
+estream_t
+es_fdopen_nc (int filedes, const char *mode)
+{
+  return do_fdopen (filedes, mode, 1);
+}
+
+
+estream_t
+do_fpopen (FILE *fp, const char *mode, int no_close)
+{
+  unsigned int modeflags;
+  int create_called;
+  estream_t stream;
+  void *cookie;
+  int err;
+
+  stream = NULL;
+  cookie = NULL;
+  create_called = 0;
+
+  err = es_convert_mode (mode, &modeflags);
+  if (err)
+    goto out;
+
+  fflush (fp);
+  err = es_func_fp_create (&cookie, fp, modeflags, no_close);
+  if (err)
+    goto out;
+
+  create_called = 1;
+  err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
+                   modeflags);
+
+ out:
+
+  if (err && create_called)
+    (*estream_functions_fp.func_close) (cookie);
+
+  return stream;
+}
+
   
+/* Create an estream from the stdio stream FP.  This mechanism is
+   useful in case the stdio streams have special properties and may
+   not be mixed with fd based functions.  This is for example the case
+   under Windows where the 3 standard streams are associated with the
+   console whereas a duped and fd-opened stream of one of this stream
+   won't be associated with the console.  As this messes things up it
+   is easier to keep on using the standard I/O stream as a backend for
+   estream. */
+estream_t
+es_fpopen (FILE *fp, const char *mode)
+{
+  return do_fpopen (fp, mode, 0);
+}
+
+
+/* Same as es_fpopen but does not close  FP at the end.  */
+estream_t
+es_fpopen_nc (FILE *fp, const char *mode)
+{
+  return do_fpopen (fp, mode, 1);
+}
+
 
 estream_t
 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
@@ -2009,7 +2216,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
 
   if (path)
     {
-      unsigned int flags;
+      unsigned int modeflags;
       int create_called;
       void *cookie;
       int fd;
@@ -2021,16 +2228,16 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
 
       es_deinitialize (stream);
 
-      err = es_convert_mode (mode, &flags);
+      err = es_convert_mode (mode, &modeflags);
       if (err)
        goto leave;
       
-      err = es_func_file_create (&cookie, &fd, path, flags);
+      err = es_func_file_create (&cookie, &fd, path, modeflags);
       if (err)
        goto leave;
 
       create_called = 1;
-      es_initialize (stream, cookie, fd, estream_functions_file);
+      es_initialize (stream, cookie, fd, estream_functions_file, modeflags);
 
     leave:
 
@@ -2173,7 +2380,7 @@ es_fflush (estream_t stream)
   if (stream)
     {
       ESTREAM_LOCK (stream);
-      if (stream->flags & ES_FLAG_WRITING)
+      if (stream->flags.writing)
        err = es_flush (stream);
       else
        {
@@ -2401,22 +2608,31 @@ es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
 
 
 char *
-es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream)
+es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
 {
-  char *ret = NULL;
-  
-  if (n)
+  unsigned char *s = (unsigned char*)buffer;
+  int c;
+   
+  if (!length)
+    return NULL;
+     
+  c = EOF;
+  ESTREAM_LOCK (stream);
+  while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n')
     {
-      int err;
-      
-      ESTREAM_LOCK (stream);
-      err = doreadline (stream, n, &s, NULL);
-      ESTREAM_UNLOCK (stream);
-      if (! err)
-       ret = s;
+      *s++ = c;
+      length--;
     }
-  
-  return ret;
+  ESTREAM_UNLOCK (stream);
+
+  if (c == EOF && s == (unsigned char*)buffer)
+    return NULL; /* Nothing read.  */
+
+  if (c != EOF && length > 1)
+    *s++ = c;
+
+  *s = 0;
+  return buffer;
 }
 
 
@@ -2459,7 +2675,7 @@ es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
 
          void *p;
 
-         p = ES_MEM_REALLOC (*lineptr, line_n + 1);
+         p = mem_realloc (*lineptr, line_n + 1);
          if (! p)
            err = -1;
          else
@@ -2475,7 +2691,7 @@ es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
          if (*n != line_n)
            *n = line_n;
        }
-      ES_MEM_FREE (line);
+      mem_free (line);
     }
   else
     {
@@ -2535,7 +2751,7 @@ es_read_line (estream_t stream,
     { 
       /* No buffer given - allocate a new one. */
       length = 256;
-      buffer = ES_MEM_ALLOC (length);
+      buffer = mem_alloc (length);
       *addr_of_buffer = buffer;
       if (!buffer)
         {
@@ -2549,7 +2765,7 @@ es_read_line (estream_t stream,
 
   if (length < 4)
     {
-      /* This should never happen. If it does, the fucntion has been
+      /* This should never happen. If it does, the function has been
          called with wrong arguments. */
       errno = EINVAL;
       return -1;
@@ -2576,11 +2792,11 @@ es_read_line (estream_t stream,
             }
           length += 3; /* Adjust for the reserved bytes. */
           length += length < 1024? 256 : 1024;
-          *addr_of_buffer = ES_MEM_REALLOC (buffer, length);
+          *addr_of_buffer = mem_realloc (buffer, length);
           if (!*addr_of_buffer)
             {
               int save_errno = errno;
-              ES_MEM_FREE (buffer); 
+              mem_free (buffer); 
               *length_of_buffer = *max_length = 0;
               ESTREAM_UNLOCK (stream);
               errno = save_errno;
@@ -2608,8 +2824,7 @@ es_read_line (estream_t stream,
 void
 es_free (void *a)
 {
-  if (a)
-    ES_MEM_FREE (a);
+  mem_free (a);
 }
 
 
@@ -2658,9 +2873,66 @@ es_fprintf (estream_t ES__RESTRICT stream,
   return ret;
 }
 
+
 static int
 tmpfd (void)
 {
+#ifdef HAVE_W32_SYSTEM
+  int attempts, n;
+  char buffer[MAX_PATH+9+12+1];
+  char *name, *p;
+  HANDLE file;
+  int pid = GetCurrentProcessId ();
+  unsigned int value;
+  int i;
+  
+  n = GetTempPath (MAX_PATH+1, buffer);
+  if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
+    {
+      errno = ENOENT;
+      return -1;
+    }
+  p = buffer + strlen (buffer);
+  strcpy (p, "_estream");
+  p += 8;
+  /* We try to create the directory but don't care about an error as
+     it may already exist and the CreateFile would throw an error
+     anyway.  */
+  CreateDirectory (buffer, NULL);
+  *p++ = '\\';
+  name = p;
+  for (attempts=0; attempts < 10; attempts++)
+    {
+      p = name;
+      value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
+      for (i=0; i < 8; i++)
+        {
+          *p++ = tohex (((value >> 28) & 0x0f));
+          value <<= 4;
+        }
+      strcpy (p, ".tmp");
+      file = CreateFile (buffer,
+                         GENERIC_READ | GENERIC_WRITE,
+                         0,
+                         NULL,
+                         CREATE_NEW,
+                         FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+                         NULL);
+      if (file != INVALID_HANDLE_VALUE)
+        {
+          int fd = _open_osfhandle ((long)file, 0);
+          if (fd == -1)
+            {
+              CloseHandle (file);
+              return -1;
+            }
+          return fd;
+        }
+      Sleep (1); /* One ms as this is the granularity of GetTickCount.  */
+    }
+  errno = ENOENT;
+  return -1;
+#else /*!HAVE_W32_SYSTEM*/
   FILE *fp;
   int fp_fd;
   int fd;
@@ -2681,12 +2953,13 @@ tmpfd (void)
     fclose (fp);
 
   return fd;
+#endif /*!HAVE_W32_SYSTEM*/
 }
 
 estream_t
 es_tmpfile (void)
 {
-  unsigned int flags;
+  unsigned int modeflags;
   int create_called;
   estream_t stream;
   void *cookie;
@@ -2695,7 +2968,7 @@ es_tmpfile (void)
 
   create_called = 0;
   stream = NULL;
-  flags = O_RDWR | O_TRUNC | O_CREAT;
+  modeflags = O_RDWR | O_TRUNC | O_CREAT;
   cookie = NULL;
   
   fd = tmpfd ();
@@ -2705,12 +2978,12 @@ es_tmpfile (void)
       goto out;
     }
 
-  err = es_func_fd_create (&cookie, fd, flags);
+  err = es_func_fd_create (&cookie, fd, modeflags, 0);
   if (err)
     goto out;
 
   create_called = 1;
-  err = es_create (&stream, cookie, fd, estream_functions_fd);
+  err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags);
 
  out:
 
@@ -2798,7 +3071,7 @@ es_write_sanitized (estream_t ES__RESTRICT stream,
   for (; length; length--, p++, count++)
     {
       if (*p < 0x20 
-          || (*p >= 0x7f && *p < 0xa0)
+          || *p == 0x7f
           || (delimiters 
               && (strchr (delimiters, *p) || *p == '\\')))
         {
@@ -2869,6 +3142,8 @@ es_write_hexstring (estream_t ES__RESTRICT stream,
   const unsigned char *s;
   size_t count = 0;
 
+  (void)reserved;
+
 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
 
   if (!length)