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