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