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