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