Reworked the posix and w32 exechelpers.
[gnupg.git] / common / estream.c
1 /* estream.c - Extended Stream I/O Library
2  * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 g10 Code GmbH
3  *
4  * This file is part of Libestream.
5  *
6  * Libestream is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License,
9  * or (at your option) any later version.
10  *
11  * Libestream is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Libestream; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * ALTERNATIVELY, Libestream may be distributed under the terms of the
20  * following license, in which case the provisions of this license are
21  * required INSTEAD OF the GNU General Public License. If you wish to
22  * allow use of your version of this file only under the terms of the
23  * GNU General Public License, and not to allow others to use your
24  * version of this file under the terms of the following license,
25  * indicate your decision by deleting this paragraph and the license
26  * below.
27  *
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions
30  * are met:
31  * 1. Redistributions of source code must retain the above copyright
32  *    notice, and the entire permission notice in its entirety,
33  *    including the disclaimer of warranties.
34  * 2. Redistributions in binary form must reproduce the above copyright
35  *    notice, this list of conditions and the following disclaimer in the
36  *    documentation and/or other materials provided with the distribution.
37  * 3. The name of the author may not be used to endorse or promote
38  *    products derived from this software without specific prior
39  *    written permission.
40  *
41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
42  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
45  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51  * OF THE POSSIBILITY OF SUCH DAMAGE.
52  */
53
54 #ifdef USE_ESTREAM_SUPPORT_H
55 # include <estream-support.h>
56 #endif
57
58 #ifdef HAVE_CONFIG_H
59 # include <config.h>
60 #endif
61
62 #if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
63 # define HAVE_W32_SYSTEM 1
64 # if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM)
65 #  define HAVE_W32CE_SYSTEM
66 # endif
67 #endif
68
69 #include <sys/types.h>
70 #include <sys/file.h>
71 #include <sys/stat.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <unistd.h>
76 #include <stdarg.h>
77 #include <fcntl.h>
78 #include <errno.h>
79 #include <stddef.h>
80 #include <assert.h>
81 #ifdef HAVE_W32_SYSTEM
82 # include <windows.h>
83 #endif
84 #ifdef HAVE_W32CE_SYSTEM
85 # include <gpg-error.h> /* ERRNO replacement.  */
86 #endif
87
88 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth.  */
89 # undef HAVE_PTH
90 # undef USE_GNU_PTH
91 #endif
92
93 #ifdef HAVE_PTH
94 # include <pth.h>
95 #endif
96
97 /* This is for the special hack to use estream.c in GnuPG.  */
98 #ifdef GNUPG_MAJOR_VERSION
99 # include "../common/util.h"
100 #endif
101
102 #ifndef HAVE_MKSTEMP
103 int mkstemp (char *template);
104 #endif
105
106 #ifndef HAVE_MEMRCHR
107 void *memrchr (const void *block, int c, size_t size);
108 #endif
109
110 #include <estream.h>
111 #include <estream-printf.h>
112
113 \f
114
115 #ifndef O_BINARY
116 #define O_BINARY 0
117 #endif
118
119 #ifdef HAVE_W32CE_SYSTEM
120 # define _set_errno(a)  gpg_err_set_errno ((a))
121 /* Setmode is missing in cegcc but available since CE 5.0.  */
122 int _setmode (int handle, int mode);
123 # define setmode(a,b)   _setmode ((a),(b))
124 #else
125 # define _set_errno(a)  do { errno = (a); } while (0)
126 #endif
127
128 #ifdef HAVE_W32_SYSTEM
129 # define IS_INVALID_FD(a)    ((void*)(a) == (void*)(-1)) /* ?? FIXME.  */
130 #else
131 # define IS_INVALID_FD(a)    ((a) == -1)
132 #endif
133
134
135 /* Generally used types.  */
136
137 typedef void *(*func_realloc_t) (void *mem, size_t size);
138 typedef void (*func_free_t) (void *mem);
139
140
141 \f
142
143 /* Buffer management layer.  */
144
145 #define BUFFER_BLOCK_SIZE  BUFSIZ
146 #define BUFFER_UNREAD_SIZE 16
147
148 \f
149
150 /* Locking.  */
151
152 #ifdef HAVE_PTH
153
154 typedef pth_mutex_t estream_mutex_t;
155 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
156 # define ESTREAM_MUTEX_LOCK(mutex)        \
157   pth_mutex_acquire (&(mutex), 0, NULL)
158 # define ESTREAM_MUTEX_UNLOCK(mutex)      \
159   pth_mutex_release (&(mutex))
160 # define ESTREAM_MUTEX_TRYLOCK(mutex)     \
161   ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
162 # define ESTREAM_MUTEX_INITIALIZE(mutex)  \
163   pth_mutex_init    (&(mutex))
164 #else
165
166 typedef void *estream_mutex_t;
167
168 static inline void
169 dummy_mutex_call_void (estream_mutex_t mutex)
170 {
171   (void)mutex;
172 }
173
174 static inline int
175 dummy_mutex_call_int (estream_mutex_t mutex)
176 {
177   (void)mutex;
178   return 0;
179 }
180
181 # define ESTREAM_MUTEX_INITIALIZER NULL
182 # define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex))
183 # define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex))
184 # define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex))
185 # define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex))
186 #endif
187
188 /* Primitive system I/O.  */
189
190 #ifdef HAVE_PTH
191 # define ESTREAM_SYS_READ  es_pth_read
192 # define ESTREAM_SYS_WRITE es_pth_write
193 # define ESTREAM_SYS_YIELD() pth_yield (NULL)
194 #else
195 # define ESTREAM_SYS_READ  read
196 # define ESTREAM_SYS_WRITE write
197 # define ESTREAM_SYS_YIELD() do { } while (0)
198 #endif
199
200
201 /* Misc definitions.  */
202
203 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
204
205 /* An internal stream object.  */
206
207 struct estream_internal
208 {
209   unsigned char buffer[BUFFER_BLOCK_SIZE];
210   unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
211   estream_mutex_t lock;          /* Lock. */
212   void *cookie;                  /* Cookie.                */
213   void *opaque;                  /* Opaque data.           */
214   unsigned int modeflags;        /* Flags for the backend. */
215   char *printable_fname;         /* Malloced filename for es_fname_get.  */
216   off_t offset;
217   es_cookie_read_function_t func_read;
218   es_cookie_write_function_t func_write;
219   es_cookie_seek_function_t func_seek;
220   es_cookie_close_function_t func_close;
221   int strategy;
222   es_syshd_t syshd;              /* A copy of the sytem handle.  */
223   struct
224   {
225     unsigned int err: 1;
226     unsigned int eof: 1;
227   } indicators;
228   unsigned int deallocate_buffer: 1;
229   unsigned int is_stdstream:1;   /* This is a standard stream.  */
230   unsigned int stdstream_fd:2;   /* 0, 1 or 2 for a standard stream.  */
231   unsigned int printable_fname_inuse: 1;  /* es_fname_get has been used.  */
232   size_t print_ntotal;           /* Bytes written from in print_writer. */
233 };
234
235
236 typedef struct estream_internal *estream_internal_t;
237
238 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
239 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
240 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
241
242 /* Stream list.  */
243
244 typedef struct estream_list *estream_list_t;
245
246 struct estream_list
247 {
248   estream_t car;
249   estream_list_t cdr;
250   estream_list_t *prev_cdr;
251 };
252
253 static estream_list_t estream_list;
254 static estream_mutex_t estream_list_lock;
255
256 #define ESTREAM_LIST_LOCK   ESTREAM_MUTEX_LOCK   (estream_list_lock)
257 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
258
259 /* File descriptors registered to be used as the standard file handles. */
260 static int custom_std_fds[3];
261 static unsigned char custom_std_fds_valid[3];
262
263
264 #ifndef EOPNOTSUPP
265 # define EOPNOTSUPP ENOSYS
266 #endif
267
268
269 /* Local prototypes.  */
270 static void fname_set_internal (estream_t stream, const char *fname, int quote);
271
272
273
274 \f
275 /* Macros.  */
276
277 /* Calculate array dimension.  */
278 #ifndef DIM
279 #define DIM(array) (sizeof (array) / sizeof (*array))
280 #endif
281
282 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
283
284
285 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
286    VARIABLE is zero.  */
287 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
288   do                                                           \
289     {                                                          \
290       tmp_variable = expression;                               \
291       if ((! variable) && tmp_variable)                        \
292         variable = tmp_variable;                               \
293     }                                                          \
294   while (0)
295
296
297 /* Malloc wrappers to overcome problems on some older OSes.  */
298 static void *
299 mem_alloc (size_t n)
300 {
301   if (!n)
302     n++;
303   return malloc (n);
304 }
305
306 static void *
307 mem_realloc (void *p, size_t n)
308 {
309   if (!p)
310     return mem_alloc (n);
311   return realloc (p, n);
312 }
313
314 static void
315 mem_free (void *p)
316 {
317   if (p)
318     free (p);
319 }
320
321 #ifdef HAVE_W32_SYSTEM
322 static int
323 map_w32_to_errno (DWORD w32_err)
324 {
325   switch (w32_err)
326     {
327     case 0:
328       return 0;
329
330     case ERROR_FILE_NOT_FOUND:
331       return ENOENT;
332
333     case ERROR_PATH_NOT_FOUND:
334       return ENOENT;
335
336     case ERROR_ACCESS_DENIED:
337       return EPERM;
338
339     case ERROR_INVALID_HANDLE:
340     case ERROR_INVALID_BLOCK:
341       return EINVAL;
342
343     case ERROR_NOT_ENOUGH_MEMORY:
344       return ENOMEM;
345       
346     case ERROR_NO_DATA:
347       return EPIPE;
348
349     default:
350       return EIO;
351     }
352 }
353 #endif /*HAVE_W32_SYSTEM*/
354
355 /*
356  * List manipulation.
357  */
358
359 /* Add STREAM to the list of registered stream objects.  If
360    WITH_LOCKED_LIST is true we assumed that the list of streams is
361    already locked.  */
362 static int
363 es_list_add (estream_t stream, int with_locked_list)
364 {
365   estream_list_t list_obj;
366   int ret;
367
368   list_obj = mem_alloc (sizeof (*list_obj));
369   if (! list_obj)
370     ret = -1;
371   else
372     {
373       if (!with_locked_list)
374         ESTREAM_LIST_LOCK;
375       list_obj->car = stream;
376       list_obj->cdr = estream_list;
377       list_obj->prev_cdr = &estream_list;
378       if (estream_list)
379         estream_list->prev_cdr = &list_obj->cdr;
380       estream_list = list_obj;
381       if (!with_locked_list)
382         ESTREAM_LIST_UNLOCK;
383       ret = 0;
384     }
385
386   return ret;
387 }
388
389 /* Remove STREAM from the list of registered stream objects.  */
390 static void
391 es_list_remove (estream_t stream, int with_locked_list)
392 {
393   estream_list_t list_obj;
394   
395   if (!with_locked_list)
396     ESTREAM_LIST_LOCK;
397   for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
398     if (list_obj->car == stream)
399       {
400         *list_obj->prev_cdr = list_obj->cdr;
401         if (list_obj->cdr)
402           list_obj->cdr->prev_cdr = list_obj->prev_cdr;
403         mem_free (list_obj);
404         break;
405       }
406   if (!with_locked_list)
407     ESTREAM_LIST_UNLOCK;
408 }
409
410 /* Type of an stream-iterator-function.  */
411 typedef int (*estream_iterator_t) (estream_t stream);
412
413 /* Iterate over list of registered streams, calling ITERATOR for each
414    of them.  */
415 static int
416 es_list_iterate (estream_iterator_t iterator)
417 {
418   estream_list_t list_obj;
419   int ret = 0;
420
421   ESTREAM_LIST_LOCK;
422   for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
423     ret |= (*iterator) (list_obj->car);
424   ESTREAM_LIST_UNLOCK;
425
426   return ret;
427 }
428
429
430 \f
431 /*
432  * I/O Helper
433  *
434  * Unfortunately our Pth emulation for Windows expects system handles
435  * for pth_read and pth_write.  We use a simple approach to fix this:
436  * If the function returns an error we fall back to a vanilla read or
437  * write, assuming that we do I/O on a plain file where the operation
438  * can't block.
439  */
440 #ifdef HAVE_PTH
441 static int
442 es_pth_read (int fd, void *buffer, size_t size)
443 {
444 # ifdef HAVE_W32_SYSTEM
445   int rc = pth_read (fd, buffer, size);
446   if (rc == -1 && errno == EINVAL)
447     rc = read (fd, buffer, size);
448   return rc;
449 # else /*!HAVE_W32_SYSTEM*/
450   return pth_read (fd, buffer, size);
451 # endif /* !HAVE_W32_SYSTEM*/
452 }
453
454 static int
455 es_pth_write (int fd, const void *buffer, size_t size)
456 {
457 # ifdef HAVE_W32_SYSTEM
458   int rc = pth_write (fd, buffer, size);
459   if (rc == -1 && errno == EINVAL)
460     rc = write (fd, buffer, size);
461   return rc;
462 # else /*!HAVE_W32_SYSTEM*/
463   return pth_write (fd, buffer, size);
464 # endif /* !HAVE_W32_SYSTEM*/
465 }
466 #endif /*HAVE_PTH*/
467
468 \f
469
470 static void
471 es_deinit (void)
472 {
473   /* Flush all streams. */
474   es_fflush (NULL);
475 }
476
477
478 /*
479  * Initialization.
480  */
481
482 static int
483 es_init_do (void)
484 {
485   static int initialized;
486
487   if (!initialized)
488     {
489 #ifdef HAVE_PTH
490       if (!pth_init () && errno != EPERM )
491         return -1;
492       if (pth_mutex_init (&estream_list_lock))
493         initialized = 1;
494 #else
495       initialized = 1;
496 #endif
497       atexit (es_deinit);  
498     }
499   return 0;
500 }
501
502 \f
503
504 /*
505  * I/O methods.
506  */
507
508 /* Implementation of Memory I/O.  */
509
510 /* Cookie for memory objects.  */
511 typedef struct estream_cookie_mem
512 {
513   unsigned int modeflags;       /* Open flags.  */
514   unsigned char *memory;        /* Allocated data buffer.  */
515   size_t memory_size;           /* Allocated size of MEMORY.  */
516   size_t memory_limit;          /* Caller supplied maximum allowed
517                                    allocation size or 0 for no limit.  */
518   size_t offset;                /* Current offset in MEMORY.  */
519   size_t data_len;              /* Used length of data in MEMORY.  */
520   size_t block_size;            /* Block size.  */
521   struct {
522     unsigned int grow: 1;       /* MEMORY is allowed to grow.  */
523   } flags;
524   func_realloc_t func_realloc;
525   func_free_t func_free;
526 } *estream_cookie_mem_t;
527
528
529 /* Create function for memory objects.  DATA is either NULL or a user
530    supplied buffer with the initial conetnt of the memory buffer.  If
531    DATA is NULL, DATA_N and DATA_LEN need to be 0 as well.  If DATA is
532    not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the
533    used length in DATA.  */
534 static int
535 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
536                     unsigned char *ES__RESTRICT data, size_t data_n,
537                     size_t data_len,
538                     size_t block_size, unsigned int grow,
539                     func_realloc_t func_realloc, func_free_t func_free,
540                     unsigned int modeflags,
541                     size_t memory_limit)
542 {
543   estream_cookie_mem_t mem_cookie;
544   int err;
545
546   if (!data && (data_n || data_len))
547     {
548       _set_errno (EINVAL);
549       return -1;
550     }
551
552   mem_cookie = mem_alloc (sizeof (*mem_cookie));
553   if (!mem_cookie)
554     err = -1;
555   else
556     {
557       mem_cookie->modeflags = modeflags;
558       mem_cookie->memory = data;
559       mem_cookie->memory_size = data_n;
560       mem_cookie->memory_limit = memory_limit;
561       mem_cookie->offset = 0;
562       mem_cookie->data_len = data_len;
563       mem_cookie->block_size = block_size;
564       mem_cookie->flags.grow = !!grow;
565       mem_cookie->func_realloc = func_realloc ? func_realloc : mem_realloc;
566       mem_cookie->func_free = func_free ? func_free : mem_free;
567       *cookie = mem_cookie;
568       err = 0;
569     }
570
571   return err;
572 }
573
574
575 /* Read function for memory objects.  */
576 static ssize_t
577 es_func_mem_read (void *cookie, void *buffer, size_t size)
578 {
579   estream_cookie_mem_t mem_cookie = cookie;
580   ssize_t ret;
581
582   if (size > mem_cookie->data_len - mem_cookie->offset)
583     size = mem_cookie->data_len - mem_cookie->offset;
584
585   if (size)
586     {
587       memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
588       mem_cookie->offset += size;
589     }
590   
591   ret = size;
592   return ret;
593 }
594
595
596 /* Write function for memory objects.  */
597 static ssize_t
598 es_func_mem_write (void *cookie, const void *buffer, size_t size)
599 {
600   estream_cookie_mem_t mem_cookie = cookie;
601   ssize_t ret;
602   size_t nleft;
603
604   if (!size)
605     return 0;  /* A flush is a NOP for memory objects.  */
606
607   if (mem_cookie->modeflags & O_APPEND)
608     {
609       /* Append to data.  */
610       mem_cookie->offset = mem_cookie->data_len;
611     }
612
613   assert (mem_cookie->memory_size >= mem_cookie->offset);
614   nleft = mem_cookie->memory_size - mem_cookie->offset;
615   
616   /* If we are not allowed to grow limit the size to the left space.  */
617   if (!mem_cookie->flags.grow && size > nleft)
618     size = nleft;
619
620   /* Enlarge the memory buffer if needed.  */
621   if (size > nleft)
622     {
623       unsigned char *newbuf;
624       size_t newsize;
625
626       if (!mem_cookie->memory_size)
627         newsize = size;  /* Not yet allocated.  */
628       else
629         newsize = mem_cookie->memory_size + (nleft - size);
630       if (newsize < mem_cookie->offset)
631         {
632           _set_errno (EINVAL);
633           return -1;
634         }
635
636       /* Round up to the next block length.  BLOCK_SIZE should always
637          be set; we check anyway.  */
638       if (mem_cookie->block_size)
639         {
640           newsize += mem_cookie->block_size - 1;
641           if (newsize < mem_cookie->offset)
642             {
643               _set_errno (EINVAL);
644               return -1;
645             }
646           newsize /= mem_cookie->block_size;
647           newsize *= mem_cookie->block_size;
648         }
649
650       /* Check for a total limit.  */
651       if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
652         {
653           _set_errno (ENOSPC);
654           return -1;
655         }
656       
657       newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
658       if (!newbuf)
659         return -1;
660       
661       mem_cookie->memory = newbuf;
662       mem_cookie->memory_size = newsize;
663
664       assert (mem_cookie->memory_size >= mem_cookie->offset);
665       nleft = mem_cookie->memory_size - mem_cookie->offset;
666       
667       assert (size <= nleft);
668     }
669       
670   memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
671   if (mem_cookie->offset + size > mem_cookie->data_len)
672     mem_cookie->data_len = mem_cookie->offset + size;
673   mem_cookie->offset += size;
674
675   ret = size;
676   return ret;
677 }
678
679
680 /* Seek function for memory objects.  */
681 static int
682 es_func_mem_seek (void *cookie, off_t *offset, int whence)
683 {
684   estream_cookie_mem_t mem_cookie = cookie;
685   off_t pos_new;
686
687   switch (whence)
688     {
689     case SEEK_SET:
690       pos_new = *offset;
691       break;
692
693     case SEEK_CUR:
694       pos_new = mem_cookie->offset += *offset;
695       break;
696
697     case SEEK_END:
698       pos_new = mem_cookie->data_len += *offset;
699       break;
700
701     default:
702       _set_errno (EINVAL);
703       return -1;
704     }
705
706   if (pos_new > mem_cookie->memory_size)
707     {
708       size_t newsize;
709       void *newbuf;
710
711       if (!mem_cookie->flags.grow)
712         {
713           _set_errno (ENOSPC);
714           return -1;
715         }
716
717       newsize = pos_new + mem_cookie->block_size - 1;
718       if (newsize < pos_new)
719         {
720           _set_errno (EINVAL);
721           return -1;
722         }
723       newsize /= mem_cookie->block_size;
724       newsize *= mem_cookie->block_size;
725
726       if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
727         {
728           _set_errno (ENOSPC);
729           return -1;
730         }
731       
732       newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
733       if (!newbuf)
734         return -1;
735
736       mem_cookie->memory = newbuf;
737       mem_cookie->memory_size = newsize;
738     }
739
740   if (pos_new > mem_cookie->data_len)
741     {
742       /* Fill spare space with zeroes.  */
743       memset (mem_cookie->memory + mem_cookie->data_len,
744               0, pos_new - mem_cookie->data_len);
745       mem_cookie->data_len = pos_new;
746     }
747
748   mem_cookie->offset = pos_new;
749   *offset = pos_new;
750
751   return 0;
752 }
753
754
755 /* Destroy function for memory objects.  */
756 static int
757 es_func_mem_destroy (void *cookie)
758 {
759   estream_cookie_mem_t mem_cookie = cookie;
760
761   if (cookie)
762     {
763       mem_cookie->func_free (mem_cookie->memory);
764       mem_free (mem_cookie);
765     }
766   return 0;
767 }
768
769
770 static es_cookie_io_functions_t estream_functions_mem =
771   {
772     es_func_mem_read,
773     es_func_mem_write,
774     es_func_mem_seek,
775     es_func_mem_destroy
776   };
777
778
779 \f
780 /* Implementation of file descriptor based I/O.  */
781
782 /* Cookie for fd objects.  */
783 typedef struct estream_cookie_fd
784 {
785   int fd;        /* The file descriptor we are using for actual output.  */
786   int no_close;  /* If set we won't close the file descriptor.  */
787 } *estream_cookie_fd_t;
788
789 /* Create function for fd objects.  */
790 static int
791 es_func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
792 {
793   estream_cookie_fd_t fd_cookie;
794   int err;
795
796   fd_cookie = mem_alloc (sizeof (*fd_cookie));
797   if (! fd_cookie)
798     err = -1;
799   else
800     {
801 #ifdef HAVE_DOSISH_SYSTEM
802       /* Make sure it is in binary mode if requested.  */
803       if ( (modeflags & O_BINARY) )
804         setmode (fd, O_BINARY);
805 #else
806       (void)modeflags;
807 #endif
808       fd_cookie->fd = fd;
809       fd_cookie->no_close = no_close;
810       *cookie = fd_cookie;
811       err = 0;
812     }
813   
814   return err;
815 }
816
817 /* Read function for fd objects.  */
818 static ssize_t
819 es_func_fd_read (void *cookie, void *buffer, size_t size)
820
821 {
822   estream_cookie_fd_t file_cookie = cookie;
823   ssize_t bytes_read;
824   
825   if (IS_INVALID_FD (file_cookie->fd))
826     {
827       ESTREAM_SYS_YIELD ();
828       bytes_read = 0;
829     }
830   else
831     {
832       do 
833         bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
834       while (bytes_read == -1 && errno == EINTR);
835     }
836
837   return bytes_read;
838 }
839
840 /* Write function for fd objects.  */
841 static ssize_t
842 es_func_fd_write (void *cookie, const void *buffer, size_t size)
843 {
844   estream_cookie_fd_t file_cookie = cookie;
845   ssize_t bytes_written;
846
847   if (IS_INVALID_FD (file_cookie->fd))
848     {
849       ESTREAM_SYS_YIELD ();
850       bytes_written = size; /* Yeah:  Success writing to the bit bucket.  */
851     }
852   else
853     {
854       do
855         bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
856       while (bytes_written == -1 && errno == EINTR);
857     }
858
859   return bytes_written;
860 }
861
862 /* Seek function for fd objects.  */
863 static int
864 es_func_fd_seek (void *cookie, off_t *offset, int whence)
865 {
866   estream_cookie_fd_t file_cookie = cookie;
867   off_t offset_new;
868   int err;
869
870   if (IS_INVALID_FD (file_cookie->fd))
871     {
872       _set_errno (ESPIPE);
873       err = -1;
874     }
875   else
876     {
877       offset_new = lseek (file_cookie->fd, *offset, whence);
878       if (offset_new == -1)
879         err = -1;
880       else
881         {
882           *offset = offset_new;
883           err = 0;
884         }
885     }
886
887   return err;
888 }
889
890 /* Destroy function for fd objects.  */
891 static int
892 es_func_fd_destroy (void *cookie)
893 {
894   estream_cookie_fd_t fd_cookie = cookie;
895   int err;
896
897   if (fd_cookie)
898     {
899       if (IS_INVALID_FD (fd_cookie->fd))
900         err = 0;
901       else
902         err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
903       mem_free (fd_cookie);
904     }
905   else
906     err = 0;
907
908   return err;
909 }
910
911
912 static es_cookie_io_functions_t estream_functions_fd =
913   {
914     es_func_fd_read,
915     es_func_fd_write,
916     es_func_fd_seek,
917     es_func_fd_destroy
918   };
919
920
921
922 \f
923 #ifdef HAVE_W32_SYSTEM
924 /* Implementation of W32 handle based I/O.  */
925
926 /* Cookie for fd objects.  */
927 typedef struct estream_cookie_w32
928 {
929   HANDLE hd;     /* The handle we are using for actual output.  */
930   int no_close;  /* If set we won't close the handle.  */
931 } *estream_cookie_w32_t;
932
933
934 /* Create function for w32 handle objects.  */
935 static int
936 es_func_w32_create (void **cookie, HANDLE hd,
937                     unsigned int modeflags, int no_close)
938 {
939   estream_cookie_w32_t w32_cookie;
940   int err;
941
942   w32_cookie = mem_alloc (sizeof (*w32_cookie));
943   if (!w32_cookie)
944     err = -1;
945   else
946     {
947       /* CR/LF translations are not supported when using the bare W32
948          API.  If that is really required we need to implemented that
949          in the upper layer.  */
950       (void)modeflags;
951
952       w32_cookie->hd = hd;
953       w32_cookie->no_close = no_close;
954       *cookie = w32_cookie;
955       err = 0;
956     }
957   
958   return err;
959 }
960
961 /* Read function for W32 handle objects.  */
962 static ssize_t
963 es_func_w32_read (void *cookie, void *buffer, size_t size)
964 {
965   estream_cookie_w32_t w32_cookie = cookie;
966   ssize_t bytes_read;
967   
968   if (w32_cookie->hd == INVALID_HANDLE_VALUE)
969     {
970       ESTREAM_SYS_YIELD ();
971       bytes_read = 0;
972     }
973   else
974     {
975       do
976         {
977 #ifdef HAVE_PTH
978           /* Note: Our pth_read actually uses HANDLE! */
979           bytes_read = pth_read ((int)w32_cookie->hd, buffer, size);
980 #else
981           DWORD nread, ec;
982           
983           if (!ReadFile (w32_cookie->hd, buffer, size, &nread, NULL))
984             {
985               ec = GetLastError ();
986               if (ec == ERROR_BROKEN_PIPE)
987                 bytes_read = 0; /* Like our pth_read we handle this as EOF.  */
988               else
989                 {
990                   _set_errno (map_w32_to_errno (ec));
991                   log_debug ("estream: ReadFile returned %d\n",
992                              (int)GetLastError ());
993                   bytes_read = -1;
994                 }
995             }
996           else
997             bytes_read = (int)nread;
998 #endif
999         }
1000       while (bytes_read == -1 && errno == EINTR);
1001     }
1002
1003   return bytes_read;
1004 }
1005
1006 /* Write function for W32 handle objects.  */
1007 static ssize_t
1008 es_func_w32_write (void *cookie, const void *buffer, size_t size)
1009 {
1010   estream_cookie_w32_t w32_cookie = cookie;
1011   ssize_t bytes_written;
1012
1013   if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1014     {
1015       ESTREAM_SYS_YIELD ();
1016       bytes_written = size; /* Yeah:  Success writing to the bit bucket.  */
1017     }
1018   else
1019     {
1020       do
1021         {
1022 #ifdef HAVE_PTH
1023           /* Note: Our pth_write actually uses HANDLE! */
1024           bytes_written = pth_write ((int)w32_cookie->hd, buffer, size);
1025 #else
1026           DWORD nwritten;
1027
1028           if (!WriteFile (w32_cookie->hd, buffer, size, &nwritten, NULL))
1029             {
1030               _set_errno (map_w32_to_errno (GetLastError ()));
1031               bytes_written = -1;
1032             }
1033           else
1034             bytes_written = (int)nwritten;
1035 #endif
1036         }
1037       while (bytes_written == -1 && errno == EINTR);
1038     }
1039
1040   return bytes_written;
1041 }
1042
1043 /* Seek function for W32 handle objects.  */
1044 static int
1045 es_func_w32_seek (void *cookie, off_t *offset, int whence)
1046 {
1047   estream_cookie_w32_t w32_cookie = cookie;
1048   DWORD method;
1049   LARGE_INTEGER distance, newoff;
1050
1051   if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1052     {
1053       _set_errno (ESPIPE);
1054       return -1;
1055     }
1056
1057   if (whence == SEEK_SET)
1058     {
1059       method = FILE_BEGIN;
1060       distance.QuadPart = (unsigned long long)(*offset);
1061     }
1062   else if (whence == SEEK_CUR)
1063     {
1064       method = FILE_CURRENT;
1065       distance.QuadPart = (long long)(*offset);
1066     }
1067   else if (whence == SEEK_END)
1068     {
1069       method = FILE_END;
1070       distance.QuadPart = (long long)(*offset);
1071     }
1072   else
1073     {
1074       _set_errno (EINVAL);
1075       return -1;
1076     }
1077 #ifdef HAVE_W32CE_SYSTEM
1078 # warning need to use SetFilePointer
1079 #else
1080   if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method))
1081     {
1082       _set_errno (map_w32_to_errno (GetLastError ()));
1083       return -1;
1084     }
1085 #endif
1086   *offset = (unsigned long long)newoff.QuadPart;
1087   return 0;
1088 }
1089
1090 /* Destroy function for W32 handle objects.  */
1091 static int
1092 es_func_w32_destroy (void *cookie)
1093 {
1094   estream_cookie_w32_t w32_cookie = cookie;
1095   int err;
1096
1097   if (w32_cookie)
1098     {
1099       if (w32_cookie->hd == INVALID_HANDLE_VALUE)
1100         err = 0;
1101       else if (w32_cookie->no_close)
1102         err = 0;
1103       else
1104         { 
1105           if (!CloseHandle (w32_cookie->hd))
1106             {
1107               _set_errno (map_w32_to_errno (GetLastError ()));
1108               err = -1;
1109             }
1110           else
1111             err = 0;
1112         }
1113       mem_free (w32_cookie);
1114     }
1115   else
1116     err = 0;
1117
1118   return err;
1119 }
1120
1121
1122 static es_cookie_io_functions_t estream_functions_w32 =
1123   {
1124     es_func_w32_read,
1125     es_func_w32_write,
1126     es_func_w32_seek,
1127     es_func_w32_destroy
1128   };
1129 #endif /*HAVE_W32_SYSTEM*/
1130
1131
1132
1133 \f
1134 /* Implementation of FILE* I/O.  */
1135
1136 /* Cookie for fp objects.  */
1137 typedef struct estream_cookie_fp
1138 {
1139   FILE *fp;      /* The file pointer we are using for actual output.  */
1140   int no_close;  /* If set we won't close the file pointer.  */
1141 } *estream_cookie_fp_t;
1142
1143
1144 /* Create function for FILE objects.  */
1145 static int
1146 es_func_fp_create (void **cookie, FILE *fp, 
1147                    unsigned int modeflags, int no_close)
1148 {
1149   estream_cookie_fp_t fp_cookie;
1150   int err;
1151
1152   fp_cookie = mem_alloc (sizeof *fp_cookie);
1153   if (!fp_cookie)
1154     err = -1;
1155   else
1156     {
1157 #ifdef HAVE_DOSISH_SYSTEM
1158       /* Make sure it is in binary mode if requested.  */
1159       if ( (modeflags & O_BINARY) )
1160         setmode (fileno (fp), O_BINARY);
1161 #else
1162       (void)modeflags;
1163 #endif
1164       fp_cookie->fp = fp;
1165       fp_cookie->no_close = no_close;
1166       *cookie = fp_cookie;
1167       err = 0;
1168     }
1169
1170   return err;
1171 }
1172
1173 /* Read function for FILE* objects.  */
1174 static ssize_t
1175 es_func_fp_read (void *cookie, void *buffer, size_t size)
1176
1177 {
1178   estream_cookie_fp_t file_cookie = cookie;
1179   ssize_t bytes_read;
1180
1181   if (file_cookie->fp)
1182     bytes_read = fread (buffer, 1, size, file_cookie->fp);
1183   else
1184     bytes_read = 0;
1185   if (!bytes_read && ferror (file_cookie->fp))
1186     return -1;
1187   return bytes_read;
1188 }
1189
1190 /* Write function for FILE* objects.  */
1191 static ssize_t
1192 es_func_fp_write (void *cookie, const void *buffer, size_t size)
1193 {
1194   estream_cookie_fp_t file_cookie = cookie;
1195   size_t bytes_written;
1196
1197   if (file_cookie->fp)
1198     {
1199 #ifdef HAVE_W32_SYSTEM
1200       /* Using an fwrite to stdout connected to the console fails with
1201          the error "Not enough space" for an fwrite size of >= 52KB
1202          (tested on Windows XP SP2).  To solve this we always chunk
1203          the writes up into smaller blocks.  */
1204       bytes_written = 0;
1205       while (bytes_written < size)
1206         {
1207           size_t cnt = size - bytes_written;
1208
1209           if (cnt > 32*1024)
1210             cnt = 32*1024;
1211           if (fwrite ((const char*)buffer + bytes_written,
1212                       cnt, 1, file_cookie->fp) != 1)
1213             break; /* Write error.  */
1214           bytes_written += cnt;
1215         }
1216 #else
1217       bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
1218 #endif
1219     }
1220   else
1221     bytes_written = size; /* Successfully written to the bit bucket.  */
1222   if (bytes_written != size)
1223     return -1;
1224   return bytes_written;
1225 }
1226
1227 /* Seek function for FILE* objects.  */
1228 static int
1229 es_func_fp_seek (void *cookie, off_t *offset, int whence)
1230 {
1231   estream_cookie_fp_t file_cookie = cookie;
1232   long int offset_new;
1233
1234   if (!file_cookie->fp)
1235     {
1236       _set_errno (ESPIPE);
1237       return -1; 
1238     }
1239
1240   if ( fseek (file_cookie->fp, (long int)*offset, whence) )
1241     {
1242       /* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */
1243       /*          errno,strerror (errno)); */
1244       return -1;
1245     }
1246
1247   offset_new = ftell (file_cookie->fp);
1248   if (offset_new == -1)
1249     {
1250       /* fprintf (stderr, "\nftell failed: errno=%d (%s)\n",  */
1251       /*          errno,strerror (errno)); */
1252       return -1;
1253     }
1254   *offset = offset_new;
1255   return 0;
1256 }
1257
1258 /* Destroy function for FILE* objects.  */
1259 static int
1260 es_func_fp_destroy (void *cookie)
1261 {
1262   estream_cookie_fp_t fp_cookie = cookie;
1263   int err;
1264
1265   if (fp_cookie)
1266     {
1267       if (fp_cookie->fp)
1268         {
1269           fflush (fp_cookie->fp);
1270           err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
1271         }
1272       else
1273         err = 0;
1274       mem_free (fp_cookie);
1275     }
1276   else
1277     err = 0;
1278
1279   return err;
1280 }
1281
1282
1283 static es_cookie_io_functions_t estream_functions_fp =
1284   {
1285     es_func_fp_read,
1286     es_func_fp_write,
1287     es_func_fp_seek,
1288     es_func_fp_destroy
1289   };
1290
1291
1292
1293 \f
1294 /* Implementation of file I/O.  */
1295
1296 /* Create function for fd objects.  */
1297 static int
1298 es_func_file_create (void **cookie, int *filedes,
1299                      const char *path, unsigned int modeflags)
1300 {
1301   estream_cookie_fd_t file_cookie;
1302   int err;
1303   int fd;
1304
1305   err = 0;
1306   fd = -1;
1307
1308   file_cookie = mem_alloc (sizeof (*file_cookie));
1309   if (! file_cookie)
1310     {
1311       err = -1;
1312       goto out;
1313     }
1314
1315   fd = open (path, modeflags, ES_DEFAULT_OPEN_MODE);
1316   if (fd == -1)
1317     {
1318       err = -1;
1319       goto out;
1320     }
1321 #ifdef HAVE_DOSISH_SYSTEM
1322   /* Make sure it is in binary mode if requested.  */
1323   if ( (modeflags & O_BINARY) )
1324     setmode (fd, O_BINARY);
1325 #endif
1326
1327   file_cookie->fd = fd;
1328   file_cookie->no_close = 0;
1329   *cookie = file_cookie;
1330   *filedes = fd;
1331
1332  out:
1333
1334   if (err)
1335     mem_free (file_cookie);
1336
1337   return err;
1338 }
1339
1340 \f
1341 static int
1342 es_convert_mode (const char *mode, unsigned int *modeflags)
1343 {
1344   unsigned int omode, oflags;
1345
1346   switch (*mode)
1347     {
1348     case 'r':
1349       omode = O_RDONLY;
1350       oflags = 0;
1351       break;
1352     case 'w':
1353       omode = O_WRONLY;
1354       oflags = O_TRUNC | O_CREAT;
1355       break;
1356     case 'a':
1357       omode = O_WRONLY;
1358       oflags = O_APPEND | O_CREAT;
1359       break;
1360     default:
1361       _set_errno (EINVAL);
1362       return -1;
1363     }
1364   for (mode++; *mode; mode++)
1365     {
1366       switch (*mode)
1367         {
1368         case '+':
1369           omode = O_RDWR;
1370           break;
1371         case 'b':
1372           oflags |= O_BINARY;
1373           break;
1374         case 'x':
1375           oflags |= O_EXCL;
1376           break;
1377         default: /* Ignore unknown flags.  */
1378           break; 
1379         }
1380     }
1381
1382   *modeflags = (omode | oflags);
1383   return 0;
1384 }
1385
1386 \f
1387
1388 /*
1389  * Low level stream functionality.
1390  */
1391
1392 static int
1393 es_fill (estream_t stream)
1394 {
1395   size_t bytes_read = 0;
1396   int err;
1397
1398   if (!stream->intern->func_read)
1399     {
1400       _set_errno (EOPNOTSUPP);
1401       err = -1;
1402     }
1403   else
1404     {
1405       es_cookie_read_function_t func_read = stream->intern->func_read;
1406       ssize_t ret;
1407
1408       ret = (*func_read) (stream->intern->cookie,
1409                           stream->buffer, stream->buffer_size);
1410       if (ret == -1)
1411         {
1412           bytes_read = 0;
1413           err = -1;
1414         }
1415       else
1416         {
1417           bytes_read = ret;
1418           err = 0;
1419         }
1420     }
1421
1422   if (err)
1423     stream->intern->indicators.err = 1;
1424   else if (!bytes_read)
1425     stream->intern->indicators.eof = 1;
1426
1427   stream->intern->offset += stream->data_len;
1428   stream->data_len = bytes_read;
1429   stream->data_offset = 0;
1430
1431   return err;
1432 }
1433
1434 static int
1435 es_flush (estream_t stream)
1436 {
1437   es_cookie_write_function_t func_write = stream->intern->func_write;
1438   int err;
1439
1440   assert (stream->flags.writing);
1441
1442   if (stream->data_offset)
1443     {
1444       size_t bytes_written;
1445       size_t data_flushed;
1446       ssize_t ret;
1447
1448       if (! func_write)
1449         {
1450           err = EOPNOTSUPP;
1451           goto out;
1452         }
1453
1454       /* Note: to prevent an endless loop caused by user-provided
1455          write-functions that pretend to have written more bytes than
1456          they were asked to write, we have to check for
1457          "(stream->data_offset - data_flushed) > 0" instead of
1458          "stream->data_offset - data_flushed".  */
1459       
1460       data_flushed = 0;
1461       err = 0;
1462       
1463       while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
1464         {
1465           ret = (*func_write) (stream->intern->cookie,
1466                                stream->buffer + data_flushed,
1467                                stream->data_offset - data_flushed);
1468           if (ret == -1)
1469             {
1470               bytes_written = 0;
1471               err = -1;
1472             }
1473           else
1474             bytes_written = ret;
1475
1476           data_flushed += bytes_written;
1477           if (err)
1478             break;
1479         }
1480
1481       stream->data_flushed += data_flushed;
1482       if (stream->data_offset == data_flushed)
1483         {
1484           stream->intern->offset += stream->data_offset;
1485           stream->data_offset = 0;
1486           stream->data_flushed = 0;
1487
1488           /* Propagate flush event.  */
1489           (*func_write) (stream->intern->cookie, NULL, 0);
1490         }
1491     }
1492   else
1493     err = 0;
1494
1495  out:
1496     
1497   if (err)
1498     stream->intern->indicators.err = 1;
1499
1500   return err;
1501 }
1502
1503 /* Discard buffered data for STREAM.  */
1504 static void
1505 es_empty (estream_t stream)
1506 {
1507   assert (!stream->flags.writing);
1508   stream->data_len = 0;
1509   stream->data_offset = 0;
1510   stream->unread_data_len = 0;
1511 }
1512
1513 /* Initialize STREAM.  */
1514 static void
1515 es_initialize (estream_t stream,
1516                void *cookie, es_syshd_t *syshd,
1517                es_cookie_io_functions_t functions,
1518                unsigned int modeflags)
1519 {
1520   stream->intern->cookie = cookie;
1521   stream->intern->opaque = NULL;
1522   stream->intern->offset = 0;
1523   stream->intern->func_read = functions.func_read;
1524   stream->intern->func_write = functions.func_write;
1525   stream->intern->func_seek = functions.func_seek;
1526   stream->intern->func_close = functions.func_close;
1527   stream->intern->strategy = _IOFBF;
1528   stream->intern->syshd = *syshd;
1529   stream->intern->print_ntotal = 0;
1530   stream->intern->indicators.err = 0;
1531   stream->intern->indicators.eof = 0;
1532   stream->intern->is_stdstream = 0;
1533   stream->intern->stdstream_fd = 0;
1534   stream->intern->deallocate_buffer = 0;
1535   stream->intern->printable_fname = NULL;
1536   stream->intern->printable_fname_inuse = 0;
1537
1538   stream->data_len = 0;
1539   stream->data_offset = 0;
1540   stream->data_flushed = 0;
1541   stream->unread_data_len = 0;
1542   /* Depending on the modeflags we set whether we start in writing or
1543      reading mode.  This is required in case we are working on a
1544      stream which is not seeekable (like stdout).  Without this
1545      pre-initialization we would do a seek at the first write call and
1546      as this will fail no utput will be delivered. */
1547   if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1548     stream->flags.writing = 1;
1549   else
1550     stream->flags.writing = 0;
1551 }
1552
1553 /* Deinitialize STREAM.  */
1554 static int
1555 es_deinitialize (estream_t stream)
1556 {
1557   es_cookie_close_function_t func_close;
1558   int err, tmp_err;
1559
1560   func_close = stream->intern->func_close;
1561
1562   err = 0;
1563   if (stream->flags.writing)
1564     SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1565   if (func_close)
1566     SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1567
1568   mem_free (stream->intern->printable_fname);
1569   stream->intern->printable_fname = NULL;
1570   stream->intern->printable_fname_inuse = 0;
1571
1572   return err;
1573 }
1574
1575 /* Create a new stream object, initialize it.  */
1576 static int
1577 es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
1578            es_cookie_io_functions_t functions, unsigned int modeflags,
1579            int with_locked_list)
1580 {
1581   estream_internal_t stream_internal_new;
1582   estream_t stream_new;
1583   int err;
1584
1585   stream_new = NULL;
1586   stream_internal_new = NULL;
1587
1588   stream_new = mem_alloc (sizeof (*stream_new));
1589   if (! stream_new)
1590     {
1591       err = -1;
1592       goto out;
1593     }
1594
1595   stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
1596   if (! stream_internal_new)
1597     {
1598       err = -1;
1599       goto out;
1600     }
1601
1602   stream_new->buffer = stream_internal_new->buffer;
1603   stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1604   stream_new->unread_buffer = stream_internal_new->unread_buffer;
1605   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1606   stream_new->intern = stream_internal_new;
1607
1608   ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
1609   es_initialize (stream_new, cookie, syshd, functions, modeflags);
1610
1611   err = es_list_add (stream_new, with_locked_list);
1612   if (err)
1613     goto out;
1614
1615   *stream = stream_new;
1616
1617  out:
1618
1619   if (err)
1620     {
1621       if (stream_new)
1622         {
1623           es_deinitialize (stream_new);
1624           mem_free (stream_new);
1625         }
1626     }
1627
1628   return err;
1629 }
1630
1631 /* Deinitialize a stream object and destroy it.  */
1632 static int
1633 do_close (estream_t stream, int with_locked_list)
1634 {
1635   int err;
1636
1637   if (stream)
1638     {
1639       es_list_remove (stream, with_locked_list);
1640       err = es_deinitialize (stream);
1641       mem_free (stream->intern);
1642       mem_free (stream);
1643     }
1644   else
1645     err = 0;
1646
1647   return err;
1648 }
1649
1650 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1651    unbuffered-mode, storing the amount of bytes read in
1652    *BYTES_READ.  */
1653 static int
1654 es_read_nbf (estream_t ES__RESTRICT stream,
1655              unsigned char *ES__RESTRICT buffer,
1656              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1657 {
1658   es_cookie_read_function_t func_read = stream->intern->func_read;
1659   size_t data_read;
1660   ssize_t ret;
1661   int err;
1662
1663   data_read = 0;
1664   err = 0;
1665
1666   while (bytes_to_read - data_read)
1667     {
1668       ret = (*func_read) (stream->intern->cookie,
1669                           buffer + data_read, bytes_to_read - data_read);
1670       if (ret == -1)
1671         {
1672           err = -1;
1673           break;
1674         }
1675       else if (ret)
1676         data_read += ret;
1677       else
1678         break;
1679     }
1680
1681   stream->intern->offset += data_read;
1682   *bytes_read = data_read;
1683
1684   return err;
1685 }
1686
1687 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1688    fully-buffered-mode, storing the amount of bytes read in
1689    *BYTES_READ.  */
1690 static int
1691 es_read_fbf (estream_t ES__RESTRICT stream,
1692              unsigned char *ES__RESTRICT buffer,
1693              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1694 {
1695   size_t data_available;
1696   size_t data_to_read;
1697   size_t data_read;
1698   int err;
1699
1700   data_read = 0;
1701   err = 0;
1702
1703   while ((bytes_to_read - data_read) && (! err))
1704     {
1705       if (stream->data_offset == stream->data_len)
1706         {
1707           /* Nothing more to read in current container, try to
1708              fill container with new data.  */
1709           err = es_fill (stream);
1710           if (! err)
1711             if (! stream->data_len)
1712               /* Filling did not result in any data read.  */
1713               break;
1714         }
1715
1716       if (! err)
1717         {
1718           /* Filling resulted in some new data.  */
1719
1720           data_to_read = bytes_to_read - data_read;
1721           data_available = stream->data_len - stream->data_offset;
1722           if (data_to_read > data_available)
1723             data_to_read = data_available;
1724
1725           memcpy (buffer + data_read,
1726                   stream->buffer + stream->data_offset, data_to_read);
1727           stream->data_offset += data_to_read;
1728           data_read += data_to_read;
1729         }
1730     }
1731
1732   *bytes_read = data_read;
1733
1734   return err;
1735 }
1736
1737 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1738    line-buffered-mode, storing the amount of bytes read in
1739    *BYTES_READ.  */
1740 static int
1741 es_read_lbf (estream_t ES__RESTRICT stream,
1742              unsigned char *ES__RESTRICT buffer,
1743              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1744 {
1745   int err;
1746
1747   err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1748
1749   return err;
1750 }
1751
1752 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1753    *the amount of bytes read in BYTES_READ.  */
1754 static int
1755 es_readn (estream_t ES__RESTRICT stream,
1756           void *ES__RESTRICT buffer_arg,
1757           size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1758 {
1759   unsigned char *buffer = (unsigned char *)buffer_arg;
1760   size_t data_read_unread, data_read;
1761   int err;
1762
1763   data_read_unread = 0;
1764   data_read = 0;
1765   err = 0;
1766
1767   if (stream->flags.writing)
1768     {
1769       /* Switching to reading mode -> flush output.  */
1770       err = es_flush (stream);
1771       if (err)
1772         goto out;
1773       stream->flags.writing = 0;
1774     }  
1775
1776   /* Read unread data first.  */
1777   while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1778     {
1779       buffer[data_read_unread]
1780         = stream->unread_buffer[stream->unread_data_len - 1];
1781       stream->unread_data_len--;
1782       data_read_unread++;
1783     }
1784
1785   switch (stream->intern->strategy)
1786     {
1787     case _IONBF:
1788       err = es_read_nbf (stream,
1789                          buffer + data_read_unread,
1790                          bytes_to_read - data_read_unread, &data_read);
1791       break;
1792     case _IOLBF:
1793       err = es_read_lbf (stream,
1794                          buffer + data_read_unread,
1795                          bytes_to_read - data_read_unread, &data_read);
1796       break;
1797     case _IOFBF:
1798       err = es_read_fbf (stream,
1799                          buffer + data_read_unread,
1800                          bytes_to_read - data_read_unread, &data_read);
1801       break;
1802     }
1803
1804  out:
1805
1806   if (bytes_read)
1807     *bytes_read = data_read_unread + data_read;
1808
1809   return err;
1810 }
1811
1812 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1813    amount of bytes successfully unread in *BYTES_UNREAD.  */
1814 static void
1815 es_unreadn (estream_t ES__RESTRICT stream,
1816             const unsigned char *ES__RESTRICT data, size_t data_n,
1817             size_t *ES__RESTRICT bytes_unread)
1818 {
1819   size_t space_left;
1820
1821   space_left = stream->unread_buffer_size - stream->unread_data_len;
1822
1823   if (data_n > space_left)
1824     data_n = space_left;
1825
1826   if (! data_n)
1827     goto out;
1828
1829   memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1830   stream->unread_data_len += data_n;
1831   stream->intern->indicators.eof = 0;
1832
1833  out:
1834
1835   if (bytes_unread)
1836     *bytes_unread = data_n;
1837 }
1838
1839 /* Seek in STREAM.  */
1840 static int
1841 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1842          off_t *ES__RESTRICT offset_new)
1843 {
1844   es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1845   int err, ret;
1846   off_t off;
1847
1848   if (! func_seek)
1849     {
1850       _set_errno (EOPNOTSUPP);
1851       err = -1;
1852       goto out;
1853     }
1854
1855   if (stream->flags.writing)
1856     {
1857       /* Flush data first in order to prevent flushing it to the wrong
1858          offset.  */
1859       err = es_flush (stream);
1860       if (err)
1861         goto out;
1862       stream->flags.writing = 0;
1863     }
1864
1865   off = offset;
1866   if (whence == SEEK_CUR)
1867     {
1868       off = off - stream->data_len + stream->data_offset;
1869       off -= stream->unread_data_len;
1870     }
1871   
1872   ret = (*func_seek) (stream->intern->cookie, &off, whence);
1873   if (ret == -1)
1874     {
1875       err = -1;
1876       goto out;
1877     }
1878
1879   err = 0;
1880   es_empty (stream);
1881
1882   if (offset_new)
1883     *offset_new = off;
1884
1885   stream->intern->indicators.eof = 0;
1886   stream->intern->offset = off;
1887
1888  out:
1889   
1890   if (err)
1891     stream->intern->indicators.err = 1;
1892
1893   return err;
1894 }
1895
1896 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1897    unbuffered-mode, storing the amount of bytes written in
1898    *BYTES_WRITTEN.  */
1899 static int
1900 es_write_nbf (estream_t ES__RESTRICT stream,
1901               const unsigned char *ES__RESTRICT buffer,
1902               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1903 {
1904   es_cookie_write_function_t func_write = stream->intern->func_write;
1905   size_t data_written;
1906   ssize_t ret;
1907   int err;
1908
1909   if (bytes_to_write && (! func_write))
1910     {
1911       err = EOPNOTSUPP;
1912       goto out;
1913     }  
1914
1915   data_written = 0;
1916   err = 0;
1917   
1918   while (bytes_to_write - data_written)
1919     {
1920       ret = (*func_write) (stream->intern->cookie,
1921                            buffer + data_written,
1922                            bytes_to_write - data_written);
1923       if (ret == -1)
1924         {
1925           err = -1;
1926           break;
1927         }
1928       else
1929         data_written += ret;
1930     }
1931
1932   stream->intern->offset += data_written;
1933   *bytes_written = data_written;
1934
1935  out:
1936
1937   return err;
1938 }
1939
1940 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1941    fully-buffered-mode, storing the amount of bytes written in
1942    *BYTES_WRITTEN.  */
1943 static int
1944 es_write_fbf (estream_t ES__RESTRICT stream,
1945               const unsigned char *ES__RESTRICT buffer,
1946               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1947 {
1948   size_t space_available;
1949   size_t data_to_write;
1950   size_t data_written;
1951   int err;
1952
1953   data_written = 0;
1954   err = 0;
1955
1956   while ((bytes_to_write - data_written) && (! err))
1957     {
1958       if (stream->data_offset == stream->buffer_size)
1959         /* Container full, flush buffer.  */
1960         err = es_flush (stream);
1961
1962       if (! err)
1963         {
1964           /* Flushing resulted in empty container.  */
1965           
1966           data_to_write = bytes_to_write - data_written;
1967           space_available = stream->buffer_size - stream->data_offset;
1968           if (data_to_write > space_available)
1969             data_to_write = space_available;
1970               
1971           memcpy (stream->buffer + stream->data_offset,
1972                   buffer + data_written, data_to_write);
1973           stream->data_offset += data_to_write;
1974           data_written += data_to_write;
1975         }
1976     }
1977
1978   *bytes_written = data_written;
1979
1980   return err;
1981 }
1982
1983
1984 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1985    line-buffered-mode, storing the amount of bytes written in
1986    *BYTES_WRITTEN.  */
1987 static int
1988 es_write_lbf (estream_t ES__RESTRICT stream,
1989               const unsigned char *ES__RESTRICT buffer,
1990               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1991 {
1992   size_t data_flushed = 0;
1993   size_t data_buffered = 0;
1994   unsigned char *nlp;
1995   int err = 0;
1996
1997   nlp = memrchr (buffer, '\n', bytes_to_write);
1998   if (nlp)
1999     {
2000       /* Found a newline, directly write up to (including) this
2001          character.  */
2002       err = es_flush (stream);
2003       if (!err)
2004         err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
2005     }
2006
2007   if (!err)
2008     {
2009       /* Write remaining data fully buffered.  */
2010       err = es_write_fbf (stream, buffer + data_flushed,
2011                           bytes_to_write - data_flushed, &data_buffered);
2012     }
2013
2014   *bytes_written = data_flushed + data_buffered;
2015   return err;
2016 }
2017
2018
2019 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
2020    amount of bytes written in BYTES_WRITTEN.  */
2021 static int
2022 es_writen (estream_t ES__RESTRICT stream,
2023            const void *ES__RESTRICT buffer,
2024            size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
2025 {
2026   size_t data_written;
2027   int err;
2028
2029   data_written = 0;
2030   err = 0;
2031   
2032   if (!stream->flags.writing)
2033     {
2034       /* Switching to writing mode -> discard input data and seek to
2035          position at which reading has stopped.  We can do this only
2036          if a seek function has been registered. */
2037       if (stream->intern->func_seek)
2038         {
2039           err = es_seek (stream, 0, SEEK_CUR, NULL);
2040           if (err)
2041             {
2042               if (errno == ESPIPE)
2043                 err = 0;
2044               else
2045                 goto out;
2046             }
2047         }
2048     }
2049
2050   switch (stream->intern->strategy)
2051     {
2052     case _IONBF:
2053       err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
2054       break;
2055
2056     case _IOLBF:
2057       err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
2058       break;
2059
2060     case _IOFBF:
2061       err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
2062       break;
2063     }
2064
2065  out:
2066     
2067   if (bytes_written)
2068     *bytes_written = data_written;
2069   if (data_written)
2070     if (!stream->flags.writing)
2071       stream->flags.writing = 1;
2072
2073   return err;
2074 }
2075
2076
2077 static int
2078 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
2079          size_t *ES__RESTRICT data_len)
2080 {
2081   int err;
2082
2083   if (stream->flags.writing)
2084     {
2085       /* Switching to reading mode -> flush output.  */
2086       err = es_flush (stream);
2087       if (err)
2088         goto out;
2089       stream->flags.writing = 0;
2090     }  
2091
2092   if (stream->data_offset == stream->data_len)
2093     {
2094       /* Refill container.  */
2095       err = es_fill (stream);
2096       if (err)
2097         goto out;
2098     }
2099   
2100   if (data)
2101     *data = stream->buffer + stream->data_offset;
2102   if (data_len)
2103     *data_len = stream->data_len - stream->data_offset;
2104   err = 0;
2105
2106  out:
2107
2108   return err;
2109 }
2110
2111
2112 /* Skip SIZE bytes of input data contained in buffer.  */
2113 static int
2114 es_skip (estream_t stream, size_t size)
2115 {
2116   int err;
2117
2118   if (stream->data_offset + size > stream->data_len)
2119     {
2120       _set_errno (EINVAL);
2121       err = -1;
2122     }
2123   else
2124     {
2125       stream->data_offset += size;
2126       err = 0;
2127     }
2128
2129   return err;
2130 }
2131
2132
2133 static int
2134 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
2135             char *ES__RESTRICT *ES__RESTRICT line,
2136             size_t *ES__RESTRICT line_length)
2137 {
2138   size_t space_left;
2139   size_t line_size;
2140   estream_t line_stream;
2141   char *line_new;
2142   void *line_stream_cookie;
2143   char *newline;
2144   unsigned char *data;
2145   size_t data_len;
2146   int err;
2147   es_syshd_t syshd;
2148
2149   line_new = NULL;
2150   line_stream = NULL;
2151   line_stream_cookie = NULL;
2152
2153   err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0,
2154                             BUFFER_BLOCK_SIZE, 1,
2155                             mem_realloc, mem_free, 
2156                             O_RDWR,
2157                             0);
2158   if (err)
2159     goto out;
2160
2161   memset (&syshd, 0, sizeof syshd);
2162   err = es_create (&line_stream, line_stream_cookie, &syshd,
2163                    estream_functions_mem, O_RDWR, 0);
2164   if (err)
2165     goto out;
2166
2167   space_left = max_length;
2168   line_size = 0;
2169   while (1)
2170     {
2171       if (max_length && (space_left == 1))
2172         break;
2173
2174       err = es_peek (stream, &data, &data_len);
2175       if (err || (! data_len))
2176         break;
2177
2178       if (data_len > (space_left - 1))
2179         data_len = space_left - 1;
2180
2181       newline = memchr (data, '\n', data_len);
2182       if (newline)
2183         {
2184           data_len = (newline - (char *) data) + 1;
2185           err = es_write (line_stream, data, data_len, NULL);
2186           if (! err)
2187             {
2188               space_left -= data_len;
2189               line_size += data_len;
2190               es_skip (stream, data_len);
2191               break;
2192             }
2193         }
2194       else
2195         {
2196           err = es_write (line_stream, data, data_len, NULL);
2197           if (! err)
2198             {
2199               space_left -= data_len;
2200               line_size += data_len;
2201               es_skip (stream, data_len);
2202             }
2203         }
2204       if (err)
2205         break;
2206     }
2207   if (err)
2208     goto out;
2209
2210   /* Complete line has been written to line_stream.  */
2211   
2212   if ((max_length > 1) && (! line_size))
2213     {
2214       stream->intern->indicators.eof = 1;
2215       goto out;
2216     }
2217
2218   err = es_seek (line_stream, 0, SEEK_SET, NULL);
2219   if (err)
2220     goto out;
2221
2222   if (! *line)
2223     {
2224       line_new = mem_alloc (line_size + 1);
2225       if (! line_new)
2226         {
2227           err = -1;
2228           goto out;
2229         }
2230     }
2231   else
2232     line_new = *line;
2233
2234   err = es_read (line_stream, line_new, line_size, NULL);
2235   if (err)
2236     goto out;
2237
2238   line_new[line_size] = '\0';
2239
2240   if (! *line)
2241     *line = line_new;
2242   if (line_length)
2243     *line_length = line_size;
2244
2245  out:
2246
2247   if (line_stream)
2248     do_close (line_stream, 0);
2249   else if (line_stream_cookie)
2250     es_func_mem_destroy (line_stream_cookie);
2251
2252   if (err)
2253     {
2254       if (! *line)
2255         mem_free (line_new);
2256       stream->intern->indicators.err = 1;
2257     }
2258
2259   return err;
2260 }
2261
2262
2263 /* Output fucntion used for estream_format.  */
2264 static int
2265 print_writer (void *outfncarg, const char *buf, size_t buflen)
2266 {
2267   estream_t stream = outfncarg;
2268   size_t nwritten;
2269   int rc;
2270
2271   nwritten = 0;
2272   rc = es_writen (stream, buf, buflen, &nwritten);
2273   stream->intern->print_ntotal += nwritten;
2274   return rc;
2275 }
2276
2277
2278 /* The core of our printf function.  This is called in locked state. */
2279 static int
2280 es_print (estream_t ES__RESTRICT stream,
2281           const char *ES__RESTRICT format, va_list ap)
2282 {
2283   int rc;
2284
2285   stream->intern->print_ntotal = 0;
2286   rc = estream_format (print_writer, stream, format, ap);
2287   if (rc)
2288     return -1;
2289   return (int)stream->intern->print_ntotal;
2290 }
2291
2292
2293 static void
2294 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
2295 {
2296   if (ind_err != -1)
2297     stream->intern->indicators.err = ind_err ? 1 : 0;
2298   if (ind_eof != -1)
2299     stream->intern->indicators.eof = ind_eof ? 1 : 0;
2300 }
2301
2302
2303 static int
2304 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
2305 {
2306   int ret = 0;
2307   
2308   if (ind_err)
2309     ret = stream->intern->indicators.err;
2310   else if (ind_eof)
2311     ret = stream->intern->indicators.eof;
2312
2313   return ret;
2314 }
2315
2316
2317 static int
2318 es_set_buffering (estream_t ES__RESTRICT stream,
2319                   char *ES__RESTRICT buffer, int mode, size_t size)
2320 {
2321   int err;
2322
2323   /* Flush or empty buffer depending on mode.  */
2324   if (stream->flags.writing)
2325     {
2326       err = es_flush (stream);
2327       if (err)
2328         goto out;
2329     }
2330   else
2331     es_empty (stream);
2332
2333   es_set_indicators (stream, -1, 0);
2334   
2335   /* Free old buffer in case that was allocated by this function.  */
2336   if (stream->intern->deallocate_buffer)
2337     {
2338       stream->intern->deallocate_buffer = 0;
2339       mem_free (stream->buffer);
2340       stream->buffer = NULL;
2341     }
2342
2343   if (mode == _IONBF)
2344     stream->buffer_size = 0;
2345   else
2346     {
2347       void *buffer_new;
2348       
2349       if (buffer)
2350         buffer_new = buffer;
2351       else
2352         {
2353           if (!size)
2354             size = BUFSIZ;
2355           buffer_new = mem_alloc (size);
2356           if (! buffer_new)
2357             {
2358               err = -1;
2359               goto out;
2360             }
2361         }
2362
2363       stream->buffer = buffer_new;
2364       stream->buffer_size = size;
2365       if (! buffer)
2366         stream->intern->deallocate_buffer = 1;
2367     }
2368   stream->intern->strategy = mode;
2369   err = 0;
2370
2371  out:
2372
2373   return err;
2374 }
2375
2376
2377 static off_t
2378 es_offset_calculate (estream_t stream)
2379 {
2380   off_t offset;
2381
2382   offset = stream->intern->offset + stream->data_offset;
2383   if (offset < stream->unread_data_len)
2384     /* Offset undefined.  */
2385     offset = 0;
2386   else
2387     offset -= stream->unread_data_len;
2388
2389   return offset;
2390 }
2391
2392
2393 static void
2394 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
2395                 void **ES__RESTRICT opaque_old)
2396 {
2397   if (opaque_old)
2398     *opaque_old = stream->intern->opaque;
2399   if (opaque_new)
2400     stream->intern->opaque = opaque_new;
2401 }
2402
2403
2404 \f
2405
2406 /* API.  */
2407
2408 int
2409 es_init (void)
2410 {
2411   int err;
2412
2413   err = es_init_do ();
2414
2415   return err;
2416 }
2417
2418
2419 \f
2420 estream_t
2421 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
2422 {
2423   unsigned int modeflags;
2424   int create_called;
2425   estream_t stream;
2426   void *cookie;
2427   int err;
2428   int fd;
2429   es_syshd_t syshd;
2430
2431   stream = NULL;
2432   cookie = NULL;
2433   create_called = 0;
2434
2435   err = es_convert_mode (mode, &modeflags);
2436   if (err)
2437     goto out;
2438   
2439   err = es_func_file_create (&cookie, &fd, path, modeflags);
2440   if (err)
2441     goto out;
2442   
2443   syshd.type = ES_SYSHD_FD;
2444   syshd.u.fd = fd;
2445
2446   create_called = 1;
2447   err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags, 0);
2448   if (err)
2449     goto out;
2450
2451   if (stream && path)
2452     fname_set_internal (stream, path, 1);
2453
2454  out:
2455   
2456   if (err && create_called)
2457     (*estream_functions_fd.func_close) (cookie);
2458
2459   return stream;
2460 }
2461
2462
2463 \f
2464 estream_t
2465 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
2466           unsigned int grow,
2467           func_realloc_t func_realloc, func_free_t func_free,
2468           const char *ES__RESTRICT mode)
2469 {
2470   unsigned int modeflags;
2471   int create_called;
2472   estream_t stream;
2473   void *cookie;
2474   int err;
2475   es_syshd_t syshd;
2476
2477   cookie = 0;
2478   stream = NULL;
2479   create_called = 0;
2480   
2481   err = es_convert_mode (mode, &modeflags);
2482   if (err)
2483     goto out;
2484
2485   err = es_func_mem_create (&cookie, data, data_n, data_len,
2486                             BUFFER_BLOCK_SIZE, grow, 
2487                             func_realloc, func_free, modeflags, 0);
2488   if (err)
2489     goto out;
2490   
2491   memset (&syshd, 0, sizeof syshd);
2492   create_called = 1;
2493   err = es_create (&stream, cookie, &syshd,
2494                    estream_functions_mem, modeflags, 0);
2495
2496  out:
2497
2498   if (err && create_called)
2499     (*estream_functions_mem.func_close) (cookie);
2500
2501   return stream;
2502 }
2503
2504
2505 \f
2506 estream_t
2507 es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
2508 {
2509   unsigned int modeflags;
2510   estream_t stream = NULL;
2511   void *cookie = NULL;
2512   es_syshd_t syshd;
2513
2514   /* Memory streams are always read/write.  We use MODE only to get
2515      the append flag.  */
2516   if (es_convert_mode (mode, &modeflags))
2517     return NULL;
2518   modeflags |= O_RDWR;
2519
2520   
2521   if (es_func_mem_create (&cookie, NULL, 0, 0,
2522                           BUFFER_BLOCK_SIZE, 1,
2523                           mem_realloc, mem_free, modeflags,
2524                           memlimit))
2525     return NULL;
2526   
2527   memset (&syshd, 0, sizeof syshd);
2528   if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags, 0))
2529     (*estream_functions_mem.func_close) (cookie);
2530
2531   return stream;
2532 }
2533
2534
2535 \f
2536 estream_t
2537 es_fopencookie (void *ES__RESTRICT cookie,
2538                 const char *ES__RESTRICT mode,
2539                 es_cookie_io_functions_t functions)
2540 {
2541   unsigned int modeflags;
2542   estream_t stream;
2543   int err;
2544   es_syshd_t syshd;
2545
2546   stream = NULL;
2547   modeflags = 0;
2548   
2549   err = es_convert_mode (mode, &modeflags);
2550   if (err)
2551     goto out;
2552
2553   memset (&syshd, 0, sizeof syshd);
2554   err = es_create (&stream, cookie, &syshd, functions, modeflags, 0);
2555   if (err)
2556     goto out;
2557
2558  out:
2559   return stream;
2560 }
2561
2562
2563 \f
2564 estream_t
2565 do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
2566 {
2567   unsigned int modeflags;
2568   int create_called;
2569   estream_t stream;
2570   void *cookie;
2571   int err;
2572   es_syshd_t syshd;
2573
2574   stream = NULL;
2575   cookie = NULL;
2576   create_called = 0;
2577
2578   err = es_convert_mode (mode, &modeflags);
2579   if (err)
2580     goto out;
2581
2582   err = es_func_fd_create (&cookie, filedes, modeflags, no_close);
2583   if (err)
2584     goto out;
2585
2586   syshd.type = ES_SYSHD_FD;
2587   syshd.u.fd = filedes;
2588   create_called = 1;
2589   err = es_create (&stream, cookie, &syshd, estream_functions_fd,
2590                    modeflags, with_locked_list);
2591
2592  out:
2593   if (err && create_called)
2594     (*estream_functions_fd.func_close) (cookie);
2595
2596   return stream;
2597 }
2598
2599 estream_t
2600 es_fdopen (int filedes, const char *mode)
2601 {
2602   return do_fdopen (filedes, mode, 0, 0);
2603 }
2604
2605 /* A variant of es_fdopen which does not close FILEDES at the end.  */
2606 estream_t
2607 es_fdopen_nc (int filedes, const char *mode)
2608 {
2609   return do_fdopen (filedes, mode, 1, 0);
2610 }
2611
2612
2613 \f
2614 estream_t
2615 do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
2616 {
2617   unsigned int modeflags;
2618   int create_called;
2619   estream_t stream;
2620   void *cookie;
2621   int err;
2622   es_syshd_t syshd;
2623
2624   stream = NULL;
2625   cookie = NULL;
2626   create_called = 0;
2627
2628   err = es_convert_mode (mode, &modeflags);
2629   if (err)
2630     goto out;
2631
2632   if (fp)
2633     fflush (fp);
2634   err = es_func_fp_create (&cookie, fp, modeflags, no_close);
2635   if (err)
2636     goto out;
2637
2638   syshd.type = ES_SYSHD_FD;
2639   syshd.u.fd = fp? fileno (fp): -1;
2640   create_called = 1;
2641   err = es_create (&stream, cookie, &syshd, estream_functions_fp,
2642                    modeflags, with_locked_list);
2643
2644  out:
2645
2646   if (err && create_called)
2647     (*estream_functions_fp.func_close) (cookie);
2648
2649   return stream;
2650 }
2651
2652   
2653 /* Create an estream from the stdio stream FP.  This mechanism is
2654    useful in case the stdio streams have special properties and may
2655    not be mixed with fd based functions.  This is for example the case
2656    under Windows where the 3 standard streams are associated with the
2657    console whereas a duped and fd-opened stream of one of this stream
2658    won't be associated with the console.  As this messes things up it
2659    is easier to keep on using the standard I/O stream as a backend for
2660    estream. */
2661 estream_t
2662 es_fpopen (FILE *fp, const char *mode)
2663 {
2664   return do_fpopen (fp, mode, 0, 0);
2665 }
2666
2667
2668 /* Same as es_fpopen but does not close  FP at the end.  */
2669 estream_t
2670 es_fpopen_nc (FILE *fp, const char *mode)
2671 {
2672   return do_fpopen (fp, mode, 1, 0);
2673 }
2674
2675
2676 \f
2677 #ifdef HAVE_W32_SYSTEM
2678 estream_t
2679 do_w32open (HANDLE hd, const char *mode,
2680             int no_close, int with_locked_list)
2681 {
2682   unsigned int modeflags;
2683   int create_called = 0;
2684   estream_t stream = NULL;
2685   void *cookie = NULL;
2686   int err;
2687   es_syshd_t syshd;
2688
2689   err = es_convert_mode (mode, &modeflags);
2690   if (err)
2691     goto leave;
2692
2693   err = es_func_w32_create (&cookie, hd, modeflags, no_close);
2694   if (err)
2695     goto leave;
2696
2697   syshd.type = ES_SYSHD_HANDLE;
2698   syshd.u.handle = hd;
2699   create_called = 1;
2700   err = es_create (&stream, cookie, &syshd, estream_functions_w32,
2701                    modeflags, with_locked_list);
2702
2703  leave:
2704   if (err && create_called)
2705     (*estream_functions_w32.func_close) (cookie);
2706
2707   return stream;
2708 }
2709 #endif /*HAVE_W32_SYSTEM*/
2710
2711 static estream_t
2712 do_sysopen (es_syshd_t *syshd, const char *mode, int no_close)
2713 {
2714   estream_t stream;
2715
2716   switch (syshd->type)
2717     {
2718     case ES_SYSHD_FD:
2719     case ES_SYSHD_SOCK:
2720       stream = do_fdopen (syshd->u.fd, mode, no_close, 0);
2721       break;
2722       
2723 #ifdef HAVE_W32_SYSTEM
2724     case ES_SYSHD_HANDLE:
2725       stream = do_w32open (syshd->u.handle, mode, no_close, 0);
2726       break;
2727 #endif
2728
2729     /* FIXME: Support RVIDs under Wince?  */
2730
2731     default:
2732       _set_errno (EINVAL);
2733       stream = NULL;
2734     }
2735   return stream;
2736 }
2737
2738 /* On POSIX systems this function is an alias for es_fdopen.  Under
2739    Windows it uses the bare W32 API and thus a HANDLE instead of a
2740    file descriptor.  */
2741 estream_t
2742 es_sysopen (es_syshd_t *syshd, const char *mode)
2743 {
2744   return do_sysopen (syshd, mode, 0);
2745 }
2746
2747 /* Same as es_sysopen but the handle/fd will not be closed by
2748    es_fclose.  */
2749 estream_t
2750 es_sysopen_nc (es_syshd_t *syshd, const char *mode)
2751 {
2752   return do_sysopen (syshd, mode, 1);
2753 }
2754
2755
2756
2757 /* Set custom standard descriptors to be used for stdin, stdout and
2758    stderr.  This function needs to be called before any of the
2759    standard streams are accessed.  */
2760 void
2761 _es_set_std_fd (int no, int fd)
2762 {
2763   ESTREAM_LIST_LOCK;
2764   if (no >= 0 && no < 3 && !custom_std_fds_valid[no])
2765     {
2766       custom_std_fds[no] = fd;
2767       custom_std_fds_valid[no] = 1;
2768     }
2769   ESTREAM_LIST_UNLOCK;
2770 }
2771
2772
2773 /* Return the stream used for stdin, stdout or stderr.  */
2774 estream_t
2775 _es_get_std_stream (int fd)
2776 {
2777   estream_list_t list_obj;
2778   estream_t stream = NULL;
2779
2780   fd %= 3; /* We only allow 0, 1 or 2 but we don't want to return an error. */
2781   ESTREAM_LIST_LOCK;
2782   for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
2783     if (list_obj->car->intern->is_stdstream
2784         && list_obj->car->intern->stdstream_fd == fd)
2785       {
2786         stream = list_obj->car;
2787         break;
2788       }
2789   if (!stream)
2790     {
2791       /* Standard stream not yet created.  We first try to create them
2792          from registered file descriptors.  */
2793       if (!fd && custom_std_fds_valid[0])
2794         stream = do_fdopen (custom_std_fds[0], "r", 1, 1);
2795       else if (fd == 1 && custom_std_fds_valid[1])
2796         stream = do_fdopen (custom_std_fds[1], "a", 1, 1);
2797       else if (custom_std_fds_valid[2])
2798         stream = do_fdopen (custom_std_fds[2], "a", 1, 1);
2799       
2800       if (!stream)
2801         {
2802           /* Second try is to use the standard C streams.  */
2803           if (!fd)
2804             stream = do_fpopen (stdin, "r", 1, 1);
2805           else if (fd == 1)
2806             stream = do_fpopen (stdout, "a", 1, 1);
2807           else
2808             stream = do_fpopen (stderr, "a", 1, 1);
2809         }
2810       
2811       if (!stream) 
2812         {
2813           /* Last try: Create a bit bucket.  */
2814           stream = do_fpopen (NULL, fd? "a":"r", 0, 1);
2815           if (!stream)
2816             {
2817               fprintf (stderr, "fatal: error creating a dummy estream"
2818                        " for %d: %s\n", fd, strerror (errno));
2819               abort();
2820             }
2821         }
2822
2823       stream->intern->is_stdstream = 1;
2824       stream->intern->stdstream_fd = fd;
2825       if (fd == 2)
2826         es_set_buffering (stream, NULL, _IOLBF, 0);
2827       fname_set_internal (stream, 
2828                           fd == 0? "[stdin]" :
2829                           fd == 1? "[stdout]" : "[stderr]", 0);
2830     }
2831   ESTREAM_LIST_UNLOCK;
2832   return stream;
2833 }
2834
2835
2836 estream_t
2837 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
2838             estream_t ES__RESTRICT stream)
2839 {
2840   int err;
2841
2842   if (path)
2843     {
2844       unsigned int modeflags;
2845       int create_called;
2846       void *cookie;
2847       int fd;
2848       es_syshd_t syshd;
2849
2850       cookie = NULL;
2851       create_called = 0;
2852       
2853       ESTREAM_LOCK (stream);
2854
2855       es_deinitialize (stream);
2856
2857       err = es_convert_mode (mode, &modeflags);
2858       if (err)
2859         goto leave;
2860       
2861       err = es_func_file_create (&cookie, &fd, path, modeflags);
2862       if (err)
2863         goto leave;
2864
2865       syshd.type = ES_SYSHD_FD;
2866       syshd.u.fd = fd;
2867       create_called = 1;
2868       es_initialize (stream, cookie, &syshd, estream_functions_fd, modeflags);
2869
2870     leave:
2871
2872       if (err)
2873         {
2874           if (create_called)
2875             es_func_fd_destroy (cookie);
2876       
2877           do_close (stream, 0);
2878           stream = NULL;
2879         }
2880       else
2881         {
2882           if (stream && path)
2883             fname_set_internal (stream, path, 1);
2884           ESTREAM_UNLOCK (stream);
2885         }
2886     }
2887   else
2888     {
2889       /* FIXME?  We don't support re-opening at the moment.  */
2890       _set_errno (EINVAL);
2891       es_deinitialize (stream);
2892       do_close (stream, 0);
2893       stream = NULL;
2894     }
2895
2896   return stream;
2897 }
2898
2899
2900 int
2901 es_fclose (estream_t stream)
2902 {
2903   int err;
2904
2905   err = do_close (stream, 0);
2906
2907   return err;
2908 }
2909
2910
2911 int
2912 es_fileno_unlocked (estream_t stream)
2913 {
2914   es_syshd_t syshd;
2915
2916   if (es_syshd (stream, &syshd))
2917     return -1;
2918   switch (syshd.type)
2919     {
2920     case ES_SYSHD_FD:   return syshd.u.fd;
2921     case ES_SYSHD_SOCK: return syshd.u.sock;
2922     default: 
2923       _set_errno (EINVAL);
2924       return -1;
2925     }
2926 }
2927
2928
2929 /* Return the handle of a stream which has been opened by es_sysopen.
2930    The caller needs to pass a structure which will be filled with the
2931    sys handle.  Return 0 on success or true on error and sets errno.
2932    This is the unlocked version.  */
2933 int
2934 es_syshd_unlocked (estream_t stream, es_syshd_t *syshd)
2935 {
2936   if (!stream || !syshd || stream->intern->syshd.type == ES_SYSHD_NONE)
2937     {
2938       if (syshd)
2939         syshd->type = ES_SYSHD_NONE;
2940       _set_errno (EINVAL);
2941       return -1;
2942     }
2943   
2944   *syshd = stream->intern->syshd;
2945   return 0;
2946 }
2947
2948
2949 void
2950 es_flockfile (estream_t stream)
2951 {
2952   ESTREAM_LOCK (stream);
2953 }
2954
2955
2956 int
2957 es_ftrylockfile (estream_t stream)
2958 {
2959   return ESTREAM_TRYLOCK (stream);
2960 }
2961
2962
2963 void
2964 es_funlockfile (estream_t stream)
2965 {
2966   ESTREAM_UNLOCK (stream);
2967 }
2968
2969
2970 int
2971 es_fileno (estream_t stream)
2972 {
2973   int ret;
2974
2975   ESTREAM_LOCK (stream);
2976   ret = es_fileno_unlocked (stream);
2977   ESTREAM_UNLOCK (stream);
2978
2979   return ret;
2980 }
2981
2982
2983 /* Return the handle of a stream which has been opened by es_sysopen.
2984    The caller needs to pass a structure which will be filled with the
2985    sys handle.  Return 0 on success or true on error and sets errno.
2986    This is the unlocked version.  */
2987 int
2988 es_syshd (estream_t stream, es_syshd_t *syshd)
2989 {
2990   int ret;
2991
2992   ESTREAM_LOCK (stream);
2993   ret = es_syshd_unlocked (stream, syshd);
2994   ESTREAM_UNLOCK (stream);
2995
2996   return ret;
2997 }
2998
2999
3000 int
3001 es_feof_unlocked (estream_t stream)
3002 {
3003   return es_get_indicator (stream, 0, 1);
3004 }
3005
3006
3007 int
3008 es_feof (estream_t stream)
3009 {
3010   int ret;
3011
3012   ESTREAM_LOCK (stream);
3013   ret = es_feof_unlocked (stream);
3014   ESTREAM_UNLOCK (stream);
3015
3016   return ret;
3017 }
3018
3019
3020 int
3021 es_ferror_unlocked (estream_t stream)
3022 {
3023   return es_get_indicator (stream, 1, 0);
3024 }
3025
3026
3027 int
3028 es_ferror (estream_t stream)
3029 {
3030   int ret;
3031
3032   ESTREAM_LOCK (stream);
3033   ret = es_ferror_unlocked (stream);
3034   ESTREAM_UNLOCK (stream);
3035
3036   return ret;
3037 }
3038
3039
3040 void
3041 es_clearerr_unlocked (estream_t stream)
3042 {
3043   es_set_indicators (stream, 0, 0);
3044 }
3045
3046
3047 void
3048 es_clearerr (estream_t stream)
3049 {
3050   ESTREAM_LOCK (stream);
3051   es_clearerr_unlocked (stream);
3052   ESTREAM_UNLOCK (stream);
3053 }
3054
3055
3056 static int
3057 do_fflush (estream_t stream)
3058 {
3059   int err;
3060   
3061   if (stream->flags.writing)
3062     err = es_flush (stream);
3063   else
3064     {
3065       es_empty (stream);
3066       err = 0;
3067     }
3068
3069   return err;
3070 }
3071
3072
3073 int
3074 es_fflush (estream_t stream)
3075 {
3076   int err;
3077   
3078   if (stream)
3079     {
3080       ESTREAM_LOCK (stream);
3081       err = do_fflush (stream);
3082       ESTREAM_UNLOCK (stream);
3083     }
3084   else
3085     err = es_list_iterate (do_fflush);
3086
3087   return err ? EOF : 0;
3088 }
3089
3090
3091 int
3092 es_fseek (estream_t stream, long int offset, int whence)
3093 {
3094   int err;
3095
3096   ESTREAM_LOCK (stream);
3097   err = es_seek (stream, offset, whence, NULL);
3098   ESTREAM_UNLOCK (stream);
3099
3100   return err;
3101 }
3102
3103
3104 int
3105 es_fseeko (estream_t stream, off_t offset, int whence)
3106 {
3107   int err;
3108   
3109   ESTREAM_LOCK (stream);
3110   err = es_seek (stream, offset, whence, NULL);
3111   ESTREAM_UNLOCK (stream);
3112
3113   return err;
3114 }
3115
3116
3117 long int
3118 es_ftell (estream_t stream)
3119 {
3120   long int ret;
3121   
3122   ESTREAM_LOCK (stream);
3123   ret = es_offset_calculate (stream);
3124   ESTREAM_UNLOCK (stream);
3125
3126   return ret;
3127 }
3128
3129
3130 off_t
3131 es_ftello (estream_t stream)
3132 {
3133   off_t ret = -1;
3134
3135   ESTREAM_LOCK (stream);
3136   ret = es_offset_calculate (stream);
3137   ESTREAM_UNLOCK (stream);
3138
3139   return ret;
3140 }
3141
3142
3143 void
3144 es_rewind (estream_t stream)
3145 {
3146   ESTREAM_LOCK (stream);
3147   es_seek (stream, 0L, SEEK_SET, NULL);
3148   es_set_indicators (stream, 0, -1);
3149   ESTREAM_UNLOCK (stream);
3150 }
3151
3152
3153 int
3154 _es_getc_underflow (estream_t stream)
3155 {
3156   int err;
3157   unsigned char c;
3158   size_t bytes_read;
3159
3160   err = es_readn (stream, &c, 1, &bytes_read);
3161
3162   return (err || (! bytes_read)) ? EOF : c;
3163 }
3164
3165
3166 int
3167 _es_putc_overflow (int c, estream_t stream)
3168 {
3169   unsigned char d = c;
3170   int err;
3171
3172   err = es_writen (stream, &d, 1, NULL);
3173
3174   return err ? EOF : c;
3175 }
3176
3177
3178 int
3179 es_fgetc (estream_t stream)
3180 {
3181   int ret;
3182   
3183   ESTREAM_LOCK (stream);
3184   ret = es_getc_unlocked (stream);
3185   ESTREAM_UNLOCK (stream);
3186
3187   return ret;
3188 }
3189
3190
3191 int
3192 es_fputc (int c, estream_t stream)
3193 {
3194   int ret;
3195   
3196   ESTREAM_LOCK (stream);
3197   ret = es_putc_unlocked (c, stream);
3198   ESTREAM_UNLOCK (stream);
3199
3200   return ret;
3201 }
3202
3203
3204 int
3205 es_ungetc (int c, estream_t stream)
3206 {
3207   unsigned char data = (unsigned char) c;
3208   size_t data_unread;
3209
3210   ESTREAM_LOCK (stream);
3211   es_unreadn (stream, &data, 1, &data_unread);
3212   ESTREAM_UNLOCK (stream);
3213
3214   return data_unread ? c : EOF;
3215 }
3216
3217
3218 int
3219 es_read (estream_t ES__RESTRICT stream,
3220          void *ES__RESTRICT buffer, size_t bytes_to_read,
3221          size_t *ES__RESTRICT bytes_read)
3222 {
3223   int err;
3224
3225   if (bytes_to_read)
3226     {
3227       ESTREAM_LOCK (stream);
3228       err = es_readn (stream, buffer, bytes_to_read, bytes_read);
3229       ESTREAM_UNLOCK (stream);
3230     }
3231   else
3232     err = 0;
3233
3234   return err;
3235 }
3236
3237
3238 int
3239 es_write (estream_t ES__RESTRICT stream,
3240           const void *ES__RESTRICT buffer, size_t bytes_to_write,
3241           size_t *ES__RESTRICT bytes_written)
3242 {
3243   int err;
3244
3245   if (bytes_to_write)
3246     {
3247       ESTREAM_LOCK (stream);
3248       err = es_writen (stream, buffer, bytes_to_write, bytes_written);
3249       ESTREAM_UNLOCK (stream);
3250     }
3251   else
3252     err = 0;
3253
3254   return err;
3255 }
3256
3257
3258 size_t
3259 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
3260           estream_t ES__RESTRICT stream)
3261 {
3262   size_t ret, bytes;
3263   int err;
3264
3265   if (size * nitems)
3266     {
3267       ESTREAM_LOCK (stream);
3268       err = es_readn (stream, ptr, size * nitems, &bytes);
3269       ESTREAM_UNLOCK (stream);
3270
3271       ret = bytes / size;
3272     }
3273   else
3274     ret = 0;
3275
3276   return ret;
3277 }
3278
3279
3280 size_t
3281 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
3282            estream_t ES__RESTRICT stream)
3283 {
3284   size_t ret, bytes;
3285   int err;
3286
3287   if (size * nitems)
3288     {
3289       ESTREAM_LOCK (stream);
3290       err = es_writen (stream, ptr, size * nitems, &bytes);
3291       ESTREAM_UNLOCK (stream);
3292
3293       ret = bytes / size;
3294     }
3295   else
3296     ret = 0;
3297
3298   return ret;
3299 }
3300
3301
3302 char *
3303 es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
3304 {
3305   unsigned char *s = (unsigned char*)buffer;
3306   int c;
3307    
3308   if (!length)
3309     return NULL;
3310      
3311   c = EOF;
3312   ESTREAM_LOCK (stream);
3313   while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n')
3314     {
3315       *s++ = c;
3316       length--;
3317     }
3318   ESTREAM_UNLOCK (stream);
3319
3320   if (c == EOF && s == (unsigned char*)buffer)
3321     return NULL; /* Nothing read.  */
3322
3323   if (c != EOF && length > 1)
3324     *s++ = c;
3325
3326   *s = 0;
3327   return buffer;
3328 }
3329
3330
3331 int
3332 es_fputs_unlocked (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
3333 {
3334   size_t length;
3335   int err;
3336
3337   length = strlen (s);
3338   err = es_writen (stream, s, length, NULL);
3339   return err ? EOF : 0;
3340 }
3341
3342 int
3343 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
3344 {
3345   size_t length;
3346   int err;
3347
3348   length = strlen (s);
3349   ESTREAM_LOCK (stream);
3350   err = es_writen (stream, s, length, NULL);
3351   ESTREAM_UNLOCK (stream);
3352
3353   return err ? EOF : 0;
3354 }
3355
3356
3357 ssize_t
3358 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
3359             estream_t ES__RESTRICT stream)
3360 {
3361   char *line = NULL;
3362   size_t line_n = 0;
3363   int err;
3364
3365   ESTREAM_LOCK (stream);
3366   err = doreadline (stream, 0, &line, &line_n);
3367   ESTREAM_UNLOCK (stream);
3368   if (err)
3369     goto out;
3370
3371   if (*n)
3372     {
3373       /* Caller wants us to use his buffer.  */
3374       
3375       if (*n < (line_n + 1))
3376         {
3377           /* Provided buffer is too small -> resize.  */
3378
3379           void *p;
3380
3381           p = mem_realloc (*lineptr, line_n + 1);
3382           if (! p)
3383             err = -1;
3384           else
3385             {
3386               if (*lineptr != p)
3387                 *lineptr = p;
3388             }
3389         }
3390
3391       if (! err)
3392         {
3393           memcpy (*lineptr, line, line_n + 1);
3394           if (*n != line_n)
3395             *n = line_n;
3396         }
3397       mem_free (line);
3398     }
3399   else
3400     {
3401       /* Caller wants new buffers.  */
3402       *lineptr = line;
3403       *n = line_n;
3404     }
3405
3406  out:
3407
3408   return err ? err : (ssize_t)line_n;
3409 }
3410
3411
3412
3413 /* Same as fgets() but if the provided buffer is too short a larger
3414    one will be allocated.  This is similar to getline. A line is
3415    considered a byte stream ending in a LF.
3416
3417    If MAX_LENGTH is not NULL, it shall point to a value with the
3418    maximum allowed allocation.  
3419
3420    Returns the length of the line. EOF is indicated by a line of
3421    length zero. A truncated line is indicated my setting the value at
3422    MAX_LENGTH to 0.  If the returned value is less then 0 not enough
3423    memory was enable or another error occurred; ERRNO is then set
3424    accordingly.
3425
3426    If a line has been truncated, the file pointer is moved forward to
3427    the end of the line so that the next read starts with the next
3428    line.  Note that MAX_LENGTH must be re-initialzied in this case.
3429
3430    The caller initially needs to provide the address of a variable,
3431    initialized to NULL, at ADDR_OF_BUFFER and don't change this value
3432    anymore with the following invocations.  LENGTH_OF_BUFFER should be
3433    the address of a variable, initialized to 0, which is also
3434    maintained by this function.  Thus, both paramaters should be
3435    considered the state of this function.
3436
3437    Note: The returned buffer is allocated with enough extra space to
3438    allow the caller to append a CR,LF,Nul.  The buffer should be
3439    released using es_free.
3440  */
3441 ssize_t
3442 es_read_line (estream_t stream, 
3443               char **addr_of_buffer, size_t *length_of_buffer,
3444               size_t *max_length)
3445 {
3446   int c;
3447   char  *buffer = *addr_of_buffer;
3448   size_t length = *length_of_buffer;
3449   size_t nbytes = 0;
3450   size_t maxlen = max_length? *max_length : 0;
3451   char *p;
3452
3453   if (!buffer)
3454     { 
3455       /* No buffer given - allocate a new one. */
3456       length = 256;
3457       buffer = mem_alloc (length);
3458       *addr_of_buffer = buffer;
3459       if (!buffer)
3460         {
3461           *length_of_buffer = 0;
3462           if (max_length)
3463             *max_length = 0;
3464           return -1;
3465         }
3466       *length_of_buffer = length;
3467     }
3468
3469   if (length < 4)
3470     {
3471       /* This should never happen. If it does, the function has been
3472          called with wrong arguments. */
3473       _set_errno (EINVAL);
3474       return -1;
3475     }
3476   length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
3477
3478   ESTREAM_LOCK (stream);
3479   p = buffer;
3480   while  ((c = es_getc_unlocked (stream)) != EOF)
3481     {
3482       if (nbytes == length)
3483         { 
3484           /* Enlarge the buffer. */
3485           if (maxlen && length > maxlen) 
3486             {
3487               /* We are beyond our limit: Skip the rest of the line. */
3488               while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
3489                 ;
3490               *p++ = '\n'; /* Always append a LF (we reserved some space). */
3491               nbytes++;
3492               if (max_length)
3493                 *max_length = 0; /* Indicate truncation. */
3494               break; /* the while loop. */
3495             }
3496           length += 3; /* Adjust for the reserved bytes. */
3497           length += length < 1024? 256 : 1024;
3498           *addr_of_buffer = mem_realloc (buffer, length);
3499           if (!*addr_of_buffer)
3500             {
3501               int save_errno = errno;
3502               mem_free (buffer); 
3503               *length_of_buffer = 0;
3504               if (max_length)
3505                 *max_length = 0;
3506               ESTREAM_UNLOCK (stream);
3507               _set_errno (save_errno);
3508               return -1;
3509             }
3510           buffer = *addr_of_buffer;
3511           *length_of_buffer = length;
3512           length -= 3; 
3513           p = buffer + nbytes;
3514         }
3515       *p++ = c;
3516       nbytes++;
3517       if (c == '\n')
3518         break;
3519     }
3520   *p = 0; /* Make sure the line is a string. */
3521   ESTREAM_UNLOCK (stream);
3522
3523   return nbytes;
3524 }
3525
3526 /* Wrapper around free() to match the memory allocation system used
3527    by estream.  Should be used for all buffers returned to the caller
3528    by libestream. */
3529 void
3530 es_free (void *a)
3531 {
3532   mem_free (a);
3533 }
3534
3535
3536 int
3537 es_vfprintf_unlocked (estream_t ES__RESTRICT stream,
3538                       const char *ES__RESTRICT format,
3539                       va_list ap)
3540 {
3541   return es_print (stream, format, ap);
3542 }
3543
3544
3545 int
3546 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
3547              va_list ap)
3548 {
3549   int ret;
3550   
3551   ESTREAM_LOCK (stream);
3552   ret = es_print (stream, format, ap);
3553   ESTREAM_UNLOCK (stream);
3554
3555   return ret;
3556 }
3557
3558
3559 int
3560 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
3561                      const char *ES__RESTRICT format, ...)
3562 {
3563   int ret;
3564   
3565   va_list ap;
3566   va_start (ap, format);
3567   ret = es_print (stream, format, ap);
3568   va_end (ap);
3569
3570   return ret;
3571 }
3572
3573
3574 int
3575 es_fprintf (estream_t ES__RESTRICT stream,
3576             const char *ES__RESTRICT format, ...)
3577 {
3578   int ret;
3579   
3580   va_list ap;
3581   va_start (ap, format);
3582   ESTREAM_LOCK (stream);
3583   ret = es_print (stream, format, ap);
3584   ESTREAM_UNLOCK (stream);
3585   va_end (ap);
3586
3587   return ret;
3588 }
3589
3590
3591 int
3592 es_printf_unlocked (const char *ES__RESTRICT format, ...)
3593 {
3594   int ret;
3595   
3596   va_list ap;
3597   va_start (ap, format);
3598   ret = es_print (es_stdout, format, ap);
3599   va_end (ap);
3600
3601   return ret;
3602 }
3603
3604
3605 int
3606 es_printf (const char *ES__RESTRICT format, ...)
3607 {
3608   int ret;
3609   estream_t stream = es_stdout;
3610   
3611   va_list ap;
3612   va_start (ap, format);
3613   ESTREAM_LOCK (stream);
3614   ret = es_print (stream, format, ap);
3615   ESTREAM_UNLOCK (stream);
3616   va_end (ap);
3617
3618   return ret;
3619 }
3620
3621
3622 /* A variant of asprintf.  The function returns the allocated buffer
3623    or NULL on error; ERRNO is set in the error case.  The caller
3624    should use es_free to release the buffer.  This function actually
3625    belongs into estream-printf but we put it here as a convenience
3626    and because es_free is required anyway.  */
3627 char *
3628 es_asprintf (const char *ES__RESTRICT format, ...)
3629 {
3630   int rc;
3631   va_list ap;
3632   char *buf;
3633
3634   va_start (ap, format);
3635   rc = estream_vasprintf (&buf, format, ap);
3636   va_end (ap);
3637   if (rc < 0)
3638     return NULL;
3639   return buf;
3640 }
3641
3642
3643 /* A variant of vasprintf.  The function returns the allocated buffer
3644    or NULL on error; ERRNO is set in the error case.  The caller
3645    should use es_free to release the buffer.  This function actually
3646    belongs into estream-printf but we put it here as a convenience
3647    and because es_free is required anyway.  */
3648 char * 
3649 es_vasprintf (const char *ES__RESTRICT format, va_list ap)
3650 {
3651   int rc;
3652   char *buf;
3653
3654   rc = estream_vasprintf (&buf, format, ap);
3655   if (rc < 0)
3656     return NULL;
3657   return buf;
3658 }
3659
3660
3661 static int
3662 tmpfd (void)
3663 {
3664 #ifdef HAVE_W32_SYSTEM
3665   int attempts, n;
3666 #ifdef HAVE_W32CE_SYSTEM
3667   wchar_t buffer[MAX_PATH+9+12+1];
3668 # define mystrlen(a) wcslen (a)
3669   wchar_t *name, *p;
3670 #else
3671   char buffer[MAX_PATH+9+12+1];
3672 # define mystrlen(a) strlen (a)
3673   char *name, *p;
3674 #endif
3675   HANDLE file;
3676   int pid = GetCurrentProcessId ();
3677   unsigned int value;
3678   int i;
3679   
3680   n = GetTempPath (MAX_PATH+1, buffer);
3681   if (!n || n > MAX_PATH || mystrlen (buffer) > MAX_PATH)
3682     {
3683       _set_errno (ENOENT);
3684       return -1;
3685     }
3686   p = buffer + mystrlen (buffer);
3687 #ifdef HAVE_W32CE_SYSTEM
3688   wcscpy (p, L"_estream");
3689 #else
3690   strcpy (p, "_estream");
3691 #endif
3692   p += 8;
3693   /* We try to create the directory but don't care about an error as
3694      it may already exist and the CreateFile would throw an error
3695      anyway.  */
3696   CreateDirectory (buffer, NULL);
3697   *p++ = '\\';
3698   name = p;
3699   for (attempts=0; attempts < 10; attempts++)
3700     {
3701       p = name;
3702       value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
3703       for (i=0; i < 8; i++)
3704         {
3705           *p++ = tohex (((value >> 28) & 0x0f));
3706           value <<= 4;
3707         }
3708 #ifdef HAVE_W32CE_SYSTEM
3709       wcscpy (p, L".tmp");
3710 #else
3711       strcpy (p, ".tmp");
3712 #endif
3713       file = CreateFile (buffer,
3714                          GENERIC_READ | GENERIC_WRITE,
3715                          0,
3716                          NULL,
3717                          CREATE_NEW,
3718                          FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
3719                          NULL);
3720       if (file != INVALID_HANDLE_VALUE)
3721         {
3722 #ifdef HAVE_W32CE_SYSTEM
3723           int fd = (int)file;
3724 #else
3725           int fd = _open_osfhandle ((long)file, 0);
3726           if (fd == -1)
3727             {
3728               CloseHandle (file);
3729               return -1;
3730             }
3731 #endif
3732           return fd;
3733         }
3734       Sleep (1); /* One ms as this is the granularity of GetTickCount.  */
3735     }
3736   _set_errno (ENOENT);
3737   return -1;
3738 #else /*!HAVE_W32_SYSTEM*/
3739   FILE *fp;
3740   int fp_fd;
3741   int fd;
3742
3743   fp = NULL;
3744   fd = -1;
3745   
3746   fp = tmpfile ();
3747   if (! fp)
3748     goto out;
3749
3750   fp_fd = fileno (fp);
3751   fd = dup (fp_fd);
3752
3753  out:
3754
3755   if (fp)
3756     fclose (fp);
3757
3758   return fd;
3759 #endif /*!HAVE_W32_SYSTEM*/
3760 }
3761
3762 estream_t
3763 es_tmpfile (void)
3764 {
3765   unsigned int modeflags;
3766   int create_called;
3767   estream_t stream;
3768   void *cookie;
3769   int err;
3770   int fd;
3771   es_syshd_t syshd;
3772
3773   create_called = 0;
3774   stream = NULL;
3775   modeflags = O_RDWR | O_TRUNC | O_CREAT;
3776   cookie = NULL;
3777   
3778   fd = tmpfd ();
3779   if (fd == -1)
3780     {
3781       err = -1;
3782       goto out;
3783     }
3784
3785   err = es_func_fd_create (&cookie, fd, modeflags, 0);
3786   if (err)
3787     goto out;
3788
3789   syshd.type = ES_SYSHD_FD;
3790   syshd.u.fd = fd;
3791   create_called = 1;
3792   err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags, 0);
3793
3794  out:
3795   if (err)
3796     {
3797       if (create_called)
3798         es_func_fd_destroy (cookie);
3799       else if (fd != -1)
3800         close (fd);
3801       stream = NULL;
3802     }
3803   
3804   return stream;
3805 }
3806
3807
3808 int
3809 es_setvbuf (estream_t ES__RESTRICT stream,
3810             char *ES__RESTRICT buf, int type, size_t size)
3811 {
3812   int err;
3813   
3814   if ((type == _IOFBF || type == _IOLBF || type == _IONBF)
3815       && (!buf || size || type == _IONBF))
3816     {
3817       ESTREAM_LOCK (stream);
3818       err = es_set_buffering (stream, buf, type, size);
3819       ESTREAM_UNLOCK (stream);
3820     }
3821   else
3822     {
3823       _set_errno (EINVAL);
3824       err = -1;
3825     }
3826
3827   return err;
3828 }
3829
3830
3831 void
3832 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
3833 {
3834   ESTREAM_LOCK (stream);
3835   es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3836   ESTREAM_UNLOCK (stream);
3837 }
3838
3839
3840 /* Put a stream into binary mode.  This is only needed for the
3841    standard streams if they are to be used in a binary way.  On Unix
3842    systems it is never needed but MSDOS based systems require such a
3843    call.  It needs to be called before any I/O is done on STREAM.  */
3844 void
3845 es_set_binary (estream_t stream)
3846 {
3847   ESTREAM_LOCK (stream);
3848   if (!(stream->intern->modeflags & O_BINARY))
3849     {
3850       stream->intern->modeflags |= O_BINARY;
3851 #ifdef HAVE_DOSISH_SYSTEM
3852       if (stream->intern->func_read == es_func_fd_read)
3853         {
3854           estream_cookie_fd_t fd_cookie = stream->intern->cookie;
3855
3856           if (!IS_INVALID_FD (fd_cookie->fd))
3857             setmode (fd_cookie->fd, O_BINARY);
3858         }
3859       else if (stream->intern->func_read == es_func_fp_read)
3860         {
3861           estream_cookie_fp_t fp_cookie = stream->intern->cookie;
3862
3863           if (fp_cookie->fp)
3864             setmode (fileno (fp_cookie->fp), O_BINARY);
3865         }
3866 #endif
3867     }
3868   ESTREAM_UNLOCK (stream);
3869 }
3870
3871
3872 void
3873 es_opaque_set (estream_t stream, void *opaque)
3874 {
3875   ESTREAM_LOCK (stream);
3876   es_opaque_ctrl (stream, opaque, NULL);
3877   ESTREAM_UNLOCK (stream);
3878 }
3879
3880
3881 void *
3882 es_opaque_get (estream_t stream)
3883 {
3884   void *opaque;
3885   
3886   ESTREAM_LOCK (stream);
3887   es_opaque_ctrl (stream, NULL, &opaque);
3888   ESTREAM_UNLOCK (stream);
3889
3890   return opaque;
3891 }
3892
3893
3894 static void
3895 fname_set_internal (estream_t stream, const char *fname, int quote)
3896 {
3897   if (stream->intern->printable_fname
3898       && !stream->intern->printable_fname_inuse)
3899     {
3900       mem_free (stream->intern->printable_fname);
3901       stream->intern->printable_fname = NULL;
3902     }
3903   if (stream->intern->printable_fname)
3904