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