Changed HTTP API.
[gnupg.git] / common / estream.c
1 /* estream.c - Extended Stream I/O Library
2  * Copyright (C) 2004, 2006 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  * Lesser 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #ifdef USE_ESTREAM_SUPPORT_H
23 # include <estream-support.h>
24 #endif
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include <sys/types.h>
31 #include <sys/file.h>
32 #include <sys/stat.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <stdarg.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <stddef.h>
40 #include <assert.h>
41
42 #ifdef HAVE_PTH
43 # include <pth.h>
44 #endif
45
46 #ifndef HAVE_MKSTEMP
47 int mkstemp (char *template);
48 #endif
49
50 #ifndef HAVE_MEMRCHR
51 void *memrchr (const void *block, int c, size_t size);
52 #endif
53
54 #include <estream.h>
55
56 \f
57
58 /* Generally used types.  */
59
60 typedef void *(*func_realloc_t) (void *mem, size_t size);
61 typedef void (*func_free_t) (void *mem);
62
63 \f
64
65 /* Buffer management layer.  */
66
67 #define BUFFER_BLOCK_SIZE  BUFSIZ
68 #define BUFFER_UNREAD_SIZE 16
69
70 \f
71
72 /* Macros.  */
73
74 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
75   (((size) + (block_size - 1)) / block_size)
76
77 \f
78
79 /* Locking.  */
80
81 #ifdef HAVE_PTH
82
83 typedef pth_mutex_t estream_mutex_t;
84 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
85 # define ESTREAM_MUTEX_LOCK(mutex)        \
86   pth_mutex_acquire (&(mutex), 0, NULL)
87 # define ESTREAM_MUTEX_UNLOCK(mutex)      \
88   pth_mutex_release (&(mutex))
89 # define ESTREAM_MUTEX_TRYLOCK(mutex)     \
90   ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
91 # define ESTREAM_MUTEX_INITIALIZE(mutex)  \
92   pth_mutex_init    (&(mutex))
93 # define ESTREAM_THREADING_INIT() ((pth_init () == TRUE) ? 0 : -1)
94
95 #else
96
97 typedef void *estream_mutex_t;
98 # define ESTREAM_MUTEX_INITIALIZER NULL
99 # define ESTREAM_MUTEX_LOCK(mutex) (void) 0
100 # define ESTREAM_MUTEX_UNLOCK(mutex) (void) 0
101 # define ESTREAM_MUTEX_TRYLOCK(mutex) 0
102 # define ESTREAM_MUTEX_INITIALIZE(mutex) (void) 0
103 # define ESTREAM_THREADING_INIT() 0
104
105 #endif
106
107 /* Memory allocator functions.  */
108
109 #define MEM_ALLOC   malloc
110 #define MEM_REALLOC realloc
111 #define MEM_FREE    free
112
113 /* Primitive system I/O.  */
114
115 #ifdef HAVE_PTH
116 # define ESTREAM_SYS_READ  pth_read
117 # define ESTREAM_SYS_WRITE pth_write
118 #else
119 # define ESTREAM_SYS_READ  read
120 # define ESTREAM_SYS_WRITE write
121 #endif
122
123 /* Misc definitions.  */
124
125 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
126
127 #define ES_FLAG_WRITING ES__FLAG_WRITING
128
129 /* An internal stream object.  */
130
131 struct estream_internal
132 {
133   unsigned char buffer[BUFFER_BLOCK_SIZE];
134   unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
135   estream_mutex_t lock;          /* Lock. */
136   void *cookie;                  /* Cookie.               */
137   void *opaque;                  /* Opaque data.          */
138   unsigned int flags;            /* Flags.                */
139   off_t offset;
140   es_cookie_read_function_t func_read;
141   es_cookie_write_function_t func_write;
142   es_cookie_seek_function_t func_seek;
143   es_cookie_close_function_t func_close;
144   int strategy;
145   int fd;
146   struct
147   {
148     unsigned int err: 1;
149     unsigned int eof: 1;
150   } indicators;
151   unsigned int deallocate_buffer: 1;
152 };
153
154 typedef struct estream_internal *estream_internal_t;
155
156 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
157 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
158 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
159
160 /* Stream list.  */
161
162 typedef struct estream_list *estream_list_t;
163
164 struct estream_list
165 {
166   estream_t car;
167   estream_list_t cdr;
168   estream_list_t *prev_cdr;
169 };
170
171 static estream_list_t estream_list;
172 #ifdef HAVE_PTH
173 static estream_mutex_t estream_list_lock = ESTREAM_MUTEX_INITIALIZER;
174 #endif
175
176 #define ESTREAM_LIST_LOCK   ESTREAM_MUTEX_LOCK   (estream_list_lock)
177 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
178
179 #ifndef EOPNOTSUPP
180 # define EOPNOTSUPP ENOSYS
181 #endif
182
183
184 \f
185
186 /* Macros.  */
187
188 /* Calculate array dimension.  */
189 #define DIM(array) (sizeof (array) / sizeof (*array))
190
191 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
192    VARIABLE is zero.  */
193 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
194   do                                                           \
195     {                                                          \
196       tmp_variable = expression;                               \
197       if ((! variable) && tmp_variable)                        \
198         variable = tmp_variable;                               \
199     }                                                          \
200   while (0)
201
202 /*
203  * List manipulation.
204  */
205
206 /* Add STREAM to the list of registered stream objects.  */
207 static int
208 es_list_add (estream_t stream)
209 {
210   estream_list_t list_obj;
211   int ret;
212
213   list_obj = MEM_ALLOC (sizeof (*list_obj));
214   if (! list_obj)
215     ret = -1;
216   else
217     {
218       ESTREAM_LIST_LOCK;
219       list_obj->car = stream;
220       list_obj->cdr = estream_list;
221       list_obj->prev_cdr = &estream_list;
222       if (estream_list)
223         estream_list->prev_cdr = &list_obj->cdr;
224       estream_list = list_obj;
225       ESTREAM_LIST_UNLOCK;
226       ret = 0;
227     }
228
229   return ret;
230 }
231
232 /* Remove STREAM from the list of registered stream objects.  */
233 static void
234 es_list_remove (estream_t stream)
235 {
236   estream_list_t list_obj;
237   
238   ESTREAM_LIST_LOCK;
239   for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
240     if (list_obj->car == stream)
241       {
242         *list_obj->prev_cdr = list_obj->cdr;
243         if (list_obj->cdr)
244           list_obj->cdr->prev_cdr = list_obj->prev_cdr;
245         MEM_FREE (list_obj);
246         break;
247       }
248   ESTREAM_LIST_UNLOCK;
249 }
250
251 /* Type of an stream-iterator-function.  */
252 typedef int (*estream_iterator_t) (estream_t stream);
253
254 /* Iterate over list of registered streams, calling ITERATOR for each
255    of them.  */
256 static int
257 es_list_iterate (estream_iterator_t iterator)
258 {
259   estream_list_t list_obj;
260   int ret = 0;
261
262   ESTREAM_LIST_LOCK;
263   for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
264     ret |= (*iterator) (list_obj->car);
265   ESTREAM_LIST_UNLOCK;
266
267   return ret;
268 }
269
270 \f
271
272 /*
273  * Initialization.
274  */
275
276 static int
277 es_init_do (void)
278 {
279   int err;
280
281   err = ESTREAM_THREADING_INIT ();
282
283   return err;
284 }
285
286 \f
287
288 /*
289  * I/O methods.
290  */
291
292 /* Implementation of Memory I/O.  */
293
294 /* Cookie for memory objects.  */
295 typedef struct estream_cookie_mem
296 {
297   unsigned int flags;           /* Open flags.  */
298   unsigned char *memory;        /* Data.  */
299   size_t memory_size;           /* Size of MEMORY.  */
300   size_t offset;                /* Current offset in MEMORY.  */
301   size_t data_len;              /* Length of data in MEMORY.  */
302   size_t block_size;            /* Block size.  */
303   unsigned int grow: 1;         /* MEMORY is allowed to grow.  */
304   unsigned int append_zero: 1;  /* Append zero after data.  */
305   unsigned int dont_free: 1;    /* Append zero after data.  */
306   char **ptr;
307   size_t *size;
308   func_realloc_t func_realloc;
309   func_free_t func_free;
310 } *estream_cookie_mem_t;
311
312 /* Create function for memory objects.  */
313 static int
314 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
315                     unsigned char *ES__RESTRICT data, size_t data_n,
316                     size_t data_len,
317                     size_t block_size, unsigned int grow,
318                     unsigned int append_zero, unsigned int dont_free,
319                     char **ptr, size_t *size,
320                     func_realloc_t func_realloc, func_free_t func_free,
321                     unsigned int flags)
322 {
323   estream_cookie_mem_t mem_cookie;
324   int err;
325
326   mem_cookie = MEM_ALLOC (sizeof (*mem_cookie));
327   if (! mem_cookie)
328     err = -1;
329   else
330     {
331       mem_cookie->flags = flags;
332       mem_cookie->memory = data;
333       mem_cookie->memory_size = data_n;
334       mem_cookie->offset = 0;
335       mem_cookie->data_len = data_len;
336       mem_cookie->block_size = block_size;
337       mem_cookie->grow = grow ? 1 : 0;
338       mem_cookie->append_zero = append_zero ? 1 : 0;
339       mem_cookie->dont_free = dont_free ? 1 : 0;
340       mem_cookie->ptr = ptr;
341       mem_cookie->size = size;
342       mem_cookie->func_realloc = func_realloc ? func_realloc : MEM_REALLOC;
343       mem_cookie->func_free = func_free ? func_free : MEM_FREE;
344       mem_cookie->offset = 0;
345       *cookie = mem_cookie;
346       err = 0;
347     }
348
349   return err;
350 }
351
352 /* Read function for memory objects.  */
353 static ssize_t
354 es_func_mem_read (void *cookie, void *buffer, size_t size)
355 {
356   estream_cookie_mem_t mem_cookie = cookie;
357   ssize_t ret;
358
359   if (size > mem_cookie->data_len - mem_cookie->offset)
360     size = mem_cookie->data_len - mem_cookie->offset;
361
362   if (size)
363     {
364       memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
365       mem_cookie->offset += size;
366     }
367   
368   ret = size;
369
370   return ret;
371 }
372
373 /* Write function for memory objects.  */
374 static ssize_t
375 es_func_mem_write (void *cookie, const void *buffer, size_t size)
376 {
377   estream_cookie_mem_t mem_cookie = cookie;
378   func_realloc_t func_realloc = mem_cookie->func_realloc;
379   unsigned char *memory_new;
380   size_t newsize;
381   ssize_t ret;
382   int err;
383
384   if (size)
385     {
386       /* Regular write.  */
387
388       if (mem_cookie->flags & O_APPEND)
389         /* Append to data.  */
390         mem_cookie->offset = mem_cookie->data_len;
391           
392       if (! mem_cookie->grow)
393         if (size > mem_cookie->memory_size - mem_cookie->offset)
394           size = mem_cookie->memory_size - mem_cookie->offset;
395
396       err = 0;
397
398       while (size > (mem_cookie->memory_size - mem_cookie->offset))
399         {
400           memory_new = (*func_realloc) (mem_cookie->memory,
401                                         mem_cookie->memory_size
402                                         + mem_cookie->block_size);
403           if (! memory_new)
404             {
405               err = -1;
406               break;
407             }
408           else
409             {
410               if (mem_cookie->memory != memory_new)
411                 mem_cookie->memory = memory_new;
412               mem_cookie->memory_size += mem_cookie->block_size;
413             }
414         }
415       if (err)
416         goto out;
417
418       if (size)
419         {
420           memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
421           if (mem_cookie->offset + size > mem_cookie->data_len)
422             mem_cookie->data_len = mem_cookie->offset + size;
423           mem_cookie->offset += size;
424         }
425     }
426   else
427     {
428       /* Flush.  */
429
430       err = 0;
431       if (mem_cookie->append_zero)
432         {
433           if (mem_cookie->data_len >= mem_cookie->memory_size)
434             {
435               newsize = BUFFER_ROUND_TO_BLOCK (mem_cookie->data_len + 1,
436                                                mem_cookie->block_size)
437                 * mem_cookie->block_size;
438           
439               memory_new = (*func_realloc) (mem_cookie->memory, newsize);
440               if (! memory_new)
441                 {
442                   err = -1;
443                   goto out;
444                 }
445
446               if (mem_cookie->memory != memory_new)
447                 mem_cookie->memory = memory_new;
448               mem_cookie->memory_size = newsize;
449             }
450
451           mem_cookie->memory[mem_cookie->data_len + 1] = 0;
452         }
453
454       /* Return information to user if necessary.  */
455       if (mem_cookie->ptr)
456         *mem_cookie->ptr = (char *) mem_cookie->memory;
457       if (mem_cookie->size)
458         *mem_cookie->size = mem_cookie->data_len;
459     }
460
461  out:
462
463   if (err)
464     ret = -1;
465   else
466     ret = size;
467
468   return ret;
469 }
470
471 /* Seek function for memory objects.  */
472 static int
473 es_func_mem_seek (void *cookie, off_t *offset, int whence)
474 {
475   estream_cookie_mem_t mem_cookie = cookie;
476   off_t pos_new;
477   int err = 0;
478
479   switch (whence)
480     {
481     case SEEK_SET:
482       pos_new = *offset;
483       break;
484
485     case SEEK_CUR:
486       pos_new = mem_cookie->offset += *offset;
487       break;
488
489     case SEEK_END:
490       pos_new = mem_cookie->data_len += *offset;
491       break;
492
493     default:
494       /* Never reached.  */
495       pos_new = 0;
496     }
497
498   if (pos_new > mem_cookie->memory_size)
499     {
500       /* Grow buffer if possible.  */
501
502       if (mem_cookie->grow)
503         {
504           func_realloc_t func_realloc = mem_cookie->func_realloc;
505           size_t newsize;
506           void *p;
507
508           newsize = BUFFER_ROUND_TO_BLOCK (pos_new, mem_cookie->block_size);
509           p = (*func_realloc) (mem_cookie->memory, newsize);
510           if (! p)
511             {
512               err = -1;
513               goto out;
514             }
515           else
516             {
517               if (mem_cookie->memory != p)
518                 mem_cookie->memory = p;
519               mem_cookie->memory_size = newsize;
520             }
521         }
522       else
523         {
524           errno = EINVAL;
525           err = -1;
526           goto out;
527         }
528     }
529
530   if (pos_new > mem_cookie->data_len)
531     /* Fill spare space with zeroes.  */
532     memset (mem_cookie->memory + mem_cookie->data_len,
533             0, pos_new - mem_cookie->data_len);
534
535   mem_cookie->offset = pos_new;
536   *offset = pos_new;
537
538  out:
539
540   return err;
541 }
542
543 /* Destroy function for memory objects.  */
544 static int
545 es_func_mem_destroy (void *cookie)
546 {
547   estream_cookie_mem_t mem_cookie = cookie;
548   func_free_t func_free = mem_cookie->func_free;
549
550   if (! mem_cookie->dont_free)
551     (*func_free) (mem_cookie->memory);
552   MEM_FREE (mem_cookie);
553
554   return 0;
555 }
556
557 static es_cookie_io_functions_t estream_functions_mem =
558   {
559     es_func_mem_read,
560     es_func_mem_write,
561     es_func_mem_seek,
562     es_func_mem_destroy
563   };
564
565 /* Implementation of fd I/O.  */
566
567 /* Cookie for fd objects.  */
568 typedef struct estream_cookie_fd
569 {
570   int fd;
571 } *estream_cookie_fd_t;
572
573 /* Create function for fd objects.  */
574 static int
575 es_func_fd_create (void **cookie, int fd, unsigned int flags)
576 {
577   estream_cookie_fd_t fd_cookie;
578   int err;
579
580   fd_cookie = MEM_ALLOC (sizeof (*fd_cookie));
581   if (! fd_cookie)
582     err = -1;
583   else
584     {
585       fd_cookie->fd = fd;
586       *cookie = fd_cookie;
587       err = 0;
588     }
589   
590   return err;
591 }
592
593 /* Read function for fd objects.  */
594 static ssize_t
595 es_func_fd_read (void *cookie, void *buffer, size_t size)
596
597 {
598   estream_cookie_fd_t file_cookie = cookie;
599   ssize_t bytes_read;
600
601   do 
602     bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
603   while (bytes_read == -1 && errno == EINTR);
604
605   return bytes_read;
606 }
607
608 /* Write function for fd objects.  */
609 static ssize_t
610 es_func_fd_write (void *cookie, const void *buffer, size_t size)
611                            
612 {
613   estream_cookie_fd_t file_cookie = cookie;
614   ssize_t bytes_written;
615
616   do
617     bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
618   while (bytes_written == -1 && errno == EINTR);
619
620   return bytes_written;
621 }
622
623 /* Seek function for fd objects.  */
624 static int
625 es_func_fd_seek (void *cookie, off_t *offset, int whence)
626 {
627   estream_cookie_fd_t file_cookie = cookie;
628   off_t offset_new;
629   int err;
630
631   offset_new = lseek (file_cookie->fd, *offset, whence);
632   if (offset_new == -1)
633     err = -1;
634   else
635     {
636       *offset = offset_new;
637       err = 0;
638     }
639
640   return err;
641 }
642
643 /* Destroy function for fd objects.  */
644 static int
645 es_func_fd_destroy (void *cookie)
646 {
647   estream_cookie_fd_t fd_cookie = cookie;
648   int err;
649
650   if (fd_cookie)
651     {
652       err = close (fd_cookie->fd);
653       MEM_FREE (fd_cookie);
654     }
655   else
656     err = 0;
657
658   return err;
659 }
660
661 static es_cookie_io_functions_t estream_functions_fd =
662   {
663     es_func_fd_read,
664     es_func_fd_write,
665     es_func_fd_seek,
666     es_func_fd_destroy
667   };
668
669 /* Implementation of file I/O.  */
670
671 /* Create function for file objects.  */
672 static int
673 es_func_file_create (void **cookie, int *filedes,
674                      const char *path, unsigned int flags)
675 {
676   estream_cookie_fd_t file_cookie;
677   int err;
678   int fd;
679
680   err = 0;
681   fd = -1;
682
683   file_cookie = MEM_ALLOC (sizeof (*file_cookie));
684   if (! file_cookie)
685     {
686       err = -1;
687       goto out;
688     }
689
690   fd = open (path, flags, ES_DEFAULT_OPEN_MODE);
691   if (fd == -1)
692     {
693       err = -1;
694       goto out;
695     }
696
697   file_cookie->fd = fd;
698   *cookie = file_cookie;
699   *filedes = fd;
700
701  out:
702
703   if (err)
704     MEM_FREE (file_cookie);
705
706   return err;
707 }
708
709 static es_cookie_io_functions_t estream_functions_file =
710   {
711     es_func_fd_read,
712     es_func_fd_write,
713     es_func_fd_seek,
714     es_func_fd_destroy
715   };
716
717 \f
718
719 /* Stream primitives.  */
720
721 static int
722 es_convert_mode (const char *mode, unsigned int *flags)
723 {
724   struct
725   {
726     const char *mode;
727     unsigned int flags;
728   } mode_flags[] = { { "r",
729                        O_RDONLY },
730                      { "rb",
731                        O_RDONLY },
732                      { "w",
733                        O_WRONLY | O_TRUNC | O_CREAT },
734                      { "wb",
735                        O_WRONLY | O_TRUNC | O_CREAT },
736                      { "a",
737                        O_WRONLY | O_APPEND | O_CREAT },
738                      { "ab",
739                        O_WRONLY | O_APPEND | O_CREAT },
740                      { "r+",
741                        O_RDWR },
742                      { "rb+",
743                        O_RDWR },
744                      { "r+b",
745                        O_RDONLY | O_WRONLY },
746                      { "w+",
747                        O_RDWR | O_TRUNC | O_CREAT },
748                      { "wb+",
749                        O_RDWR | O_TRUNC | O_CREAT },
750                      { "w+b",
751                        O_RDWR | O_TRUNC | O_CREAT },
752                      { "a+",
753                        O_RDWR | O_CREAT | O_APPEND },
754                      { "ab+",
755                        O_RDWR | O_CREAT | O_APPEND },
756                      { "a+b",
757                        O_RDWR | O_CREAT | O_APPEND } };
758   unsigned int i;
759   int err; 
760
761   for (i = 0; i < DIM (mode_flags); i++)
762     if (! strcmp (mode_flags[i].mode, mode))
763       break;
764   if (i == DIM (mode_flags))
765     {
766       errno = EINVAL;
767       err = -1;
768     }
769   else
770     {
771       err = 0;
772       *flags = mode_flags[i].flags;
773     }
774
775   return err;
776 }
777
778 \f
779
780 /*
781  * Low level stream functionality.
782  */
783
784 static int
785 es_fill (estream_t stream)
786 {
787   size_t bytes_read = 0;
788   int err;
789
790   if (!stream->intern->func_read)
791     {
792       errno = EOPNOTSUPP;
793       err = -1;
794     }
795   else
796     {
797       es_cookie_read_function_t func_read = stream->intern->func_read;
798       ssize_t ret;
799
800       ret = (*func_read) (stream->intern->cookie,
801                           stream->buffer, stream->buffer_size);
802       if (ret == -1)
803         {
804           bytes_read = 0;
805           err = -1;
806         }
807       else
808         {
809           bytes_read = ret;
810           err = 0;
811         }
812     }
813
814   if (err)
815     stream->intern->indicators.err = 1;
816   else if (!bytes_read)
817     stream->intern->indicators.eof = 1;
818
819   stream->intern->offset += stream->data_len;
820   stream->data_len = bytes_read;
821   stream->data_offset = 0;
822
823   return err;
824 }
825
826 static int
827 es_flush (estream_t stream)
828 {
829   es_cookie_write_function_t func_write = stream->intern->func_write;
830   int err;
831
832   assert (stream->flags & ES_FLAG_WRITING);
833
834   if (stream->data_offset)
835     {
836       size_t bytes_written;
837       size_t data_flushed;
838       ssize_t ret;
839
840       if (! func_write)
841         {
842           err = EOPNOTSUPP;
843           goto out;
844         }
845
846       /* Note: to prevent an endless loop caused by user-provided
847          write-functions that pretend to have written more bytes than
848          they were asked to write, we have to check for
849          "(stream->data_offset - data_flushed) > 0" instead of
850          "stream->data_offset - data_flushed".  */
851       
852       data_flushed = 0;
853       err = 0;
854       
855       while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
856         {
857           ret = (*func_write) (stream->intern->cookie,
858                                stream->buffer + data_flushed,
859                                stream->data_offset - data_flushed);
860           if (ret == -1)
861             {
862               bytes_written = 0;
863               err = -1;
864             }
865           else
866             bytes_written = ret;
867
868           data_flushed += bytes_written;
869           if (err)
870             break;
871         }
872
873       stream->data_flushed += data_flushed;
874       if (stream->data_offset == data_flushed)
875         {
876           stream->intern->offset += stream->data_offset;
877           stream->data_offset = 0;
878           stream->data_flushed = 0;
879
880           /* Propagate flush event.  */
881           (*func_write) (stream->intern->cookie, NULL, 0);
882         }
883     }
884   else
885     err = 0;
886
887  out:
888     
889   if (err)
890     stream->intern->indicators.err = 1;
891
892   return err;
893 }
894
895 /* Discard buffered data for STREAM.  */
896 static void
897 es_empty (estream_t stream)
898 {
899   assert (! (stream->flags & ES_FLAG_WRITING));
900   stream->data_len = 0;
901   stream->data_offset = 0;
902   stream->unread_data_len = 0;
903 }
904
905 /* Initialize STREAM.  */
906 static void
907 es_initialize (estream_t stream,
908                void *cookie, int fd, es_cookie_io_functions_t functions)
909 {
910   stream->intern->cookie = cookie;
911   stream->intern->opaque = NULL;
912   stream->intern->offset = 0;
913   stream->intern->func_read = functions.func_read;
914   stream->intern->func_write = functions.func_write;
915   stream->intern->func_seek = functions.func_seek;
916   stream->intern->func_close = functions.func_close;
917   stream->intern->strategy = _IOFBF;
918   stream->intern->fd = fd;
919   stream->intern->indicators.err = 0;
920   stream->intern->indicators.eof = 0;
921   stream->intern->deallocate_buffer = 0;
922
923   stream->data_len = 0;
924   stream->data_offset = 0;
925   stream->data_flushed = 0;
926   stream->unread_data_len = 0;
927   stream->flags = 0;
928 }
929
930 /* Deinitialize STREAM.  */
931 static int
932 es_deinitialize (estream_t stream)
933 {
934   es_cookie_close_function_t func_close;
935   int err, tmp_err;
936
937   func_close = stream->intern->func_close;
938
939   err = 0;
940   if (stream->flags & ES_FLAG_WRITING)
941     SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
942   if (func_close)
943     SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
944   
945   return err;
946 }
947
948 /* Create a new stream object, initialize it.  */
949 static int
950 es_create (estream_t *stream, void *cookie, int fd,
951            es_cookie_io_functions_t functions)
952 {
953   estream_internal_t stream_internal_new;
954   estream_t stream_new;
955   int err;
956
957   stream_new = NULL;
958   stream_internal_new = NULL;
959
960   stream_new = MEM_ALLOC (sizeof (*stream_new));
961   if (! stream_new)
962     {
963       err = -1;
964       goto out;
965     }
966
967   stream_internal_new = MEM_ALLOC (sizeof (*stream_internal_new));
968   if (! stream_internal_new)
969     {
970       err = -1;
971       goto out;
972     }
973
974   stream_new->buffer = stream_internal_new->buffer;
975   stream_new->buffer_size = sizeof (stream_internal_new->buffer);
976   stream_new->unread_buffer = stream_internal_new->unread_buffer;
977   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
978   stream_new->intern = stream_internal_new;
979
980   ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
981   es_initialize (stream_new, cookie, fd, functions);
982
983   err = es_list_add (stream_new);
984   if (err)
985     goto out;
986
987   *stream = stream_new;
988
989  out:
990
991   if (err)
992     {
993       if (stream_new)
994         {
995           es_deinitialize (stream_new);
996           MEM_FREE (stream_new);
997         }
998     }
999
1000   return err;
1001 }
1002
1003 /* Deinitialize a stream object and destroy it.  */
1004 static int
1005 es_destroy (estream_t stream)
1006 {
1007   int err = 0;
1008
1009   if (stream)
1010     {
1011       es_list_remove (stream);
1012       err = es_deinitialize (stream);
1013       MEM_FREE (stream->intern);
1014       MEM_FREE (stream);
1015     }
1016
1017   return err;
1018 }
1019
1020 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1021    unbuffered-mode, storing the amount of bytes read in
1022    *BYTES_READ.  */
1023 static int
1024 es_read_nbf (estream_t ES__RESTRICT stream,
1025              unsigned char *ES__RESTRICT buffer,
1026              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1027 {
1028   es_cookie_read_function_t func_read = stream->intern->func_read;
1029   size_t data_read;
1030   ssize_t ret;
1031   int err;
1032
1033   data_read = 0;
1034   err = 0;
1035
1036   while (bytes_to_read - data_read)
1037     {
1038       ret = (*func_read) (stream->intern->cookie,
1039                           buffer + data_read, bytes_to_read - data_read);
1040       if (ret == -1)
1041         {
1042           err = -1;
1043           break;
1044         }
1045       else if (ret)
1046         data_read += ret;
1047       else
1048         break;
1049     }
1050
1051   stream->intern->offset += data_read;
1052   *bytes_read = data_read;
1053
1054   return err;
1055 }
1056
1057 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1058    fully-buffered-mode, storing the amount of bytes read in
1059    *BYTES_READ.  */
1060 static int
1061 es_read_fbf (estream_t ES__RESTRICT stream,
1062              unsigned char *ES__RESTRICT buffer,
1063              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1064 {
1065   size_t data_available;
1066   size_t data_to_read;
1067   size_t data_read;
1068   int err;
1069
1070   data_read = 0;
1071   err = 0;
1072
1073   while ((bytes_to_read - data_read) && (! err))
1074     {
1075       if (stream->data_offset == stream->data_len)
1076         {
1077           /* Nothing more to read in current container, try to
1078              fill container with new data.  */
1079           err = es_fill (stream);
1080           if (! err)
1081             if (! stream->data_len)
1082               /* Filling did not result in any data read.  */
1083               break;
1084         }
1085
1086       if (! err)
1087         {
1088           /* Filling resulted in some new data.  */
1089
1090           data_to_read = bytes_to_read - data_read;
1091           data_available = stream->data_len - stream->data_offset;
1092           if (data_to_read > data_available)
1093             data_to_read = data_available;
1094
1095           memcpy (buffer + data_read,
1096                   stream->buffer + stream->data_offset, data_to_read);
1097           stream->data_offset += data_to_read;
1098           data_read += data_to_read;
1099         }
1100     }
1101
1102   *bytes_read = data_read;
1103
1104   return err;
1105 }
1106
1107 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1108    line-buffered-mode, storing the amount of bytes read in
1109    *BYTES_READ.  */
1110 static int
1111 es_read_lbf (estream_t ES__RESTRICT stream,
1112              unsigned char *ES__RESTRICT buffer,
1113              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1114 {
1115   int err;
1116
1117   err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1118
1119   return err;
1120 }
1121
1122 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1123    *the amount of bytes read in BYTES_READ.  */
1124 static int
1125 es_readn (estream_t ES__RESTRICT stream,
1126           void *ES__RESTRICT buffer_arg,
1127           size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1128 {
1129   unsigned char *buffer = (unsigned char *)buffer_arg;
1130   size_t data_read_unread, data_read;
1131   int err;
1132
1133   data_read_unread = 0;
1134   data_read = 0;
1135   err = 0;
1136
1137   if (stream->flags & ES_FLAG_WRITING)
1138     {
1139       /* Switching to reading mode -> flush output.  */
1140       err = es_flush (stream);
1141       if (err)
1142         goto out;
1143       stream->flags &= ~ES_FLAG_WRITING;
1144     }  
1145
1146   /* Read unread data first.  */
1147   while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1148     {
1149       buffer[data_read_unread]
1150         = stream->unread_buffer[stream->unread_data_len - 1];
1151       stream->unread_data_len--;
1152       data_read_unread++;
1153     }
1154
1155   switch (stream->intern->strategy)
1156     {
1157     case _IONBF:
1158       err = es_read_nbf (stream,
1159                          buffer + data_read_unread,
1160                          bytes_to_read - data_read_unread, &data_read);
1161       break;
1162     case _IOLBF:
1163       err = es_read_lbf (stream,
1164                          buffer + data_read_unread,
1165                          bytes_to_read - data_read_unread, &data_read);
1166       break;
1167     case _IOFBF:
1168       err = es_read_fbf (stream,
1169                          buffer + data_read_unread,
1170                          bytes_to_read - data_read_unread, &data_read);
1171       break;
1172     }
1173
1174  out:
1175
1176   if (bytes_read)
1177     *bytes_read = data_read_unread + data_read;
1178
1179   return err;
1180 }
1181
1182 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1183    amount of bytes succesfully unread in *BYTES_UNREAD.  */
1184 static void
1185 es_unreadn (estream_t ES__RESTRICT stream,
1186             const unsigned char *ES__RESTRICT data, size_t data_n,
1187             size_t *ES__RESTRICT bytes_unread)
1188 {
1189   size_t space_left;
1190
1191   space_left = stream->unread_buffer_size - stream->unread_data_len;
1192
1193   if (data_n > space_left)
1194     data_n = space_left;
1195
1196   if (! data_n)
1197     goto out;
1198
1199   memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1200   stream->unread_data_len += data_n;
1201   stream->intern->indicators.eof = 0;
1202
1203  out:
1204
1205   if (bytes_unread)
1206     *bytes_unread = data_n;
1207 }
1208
1209 /* Seek in STREAM.  */
1210 static int
1211 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1212          off_t *ES__RESTRICT offset_new)
1213 {
1214   es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1215   int err, ret;
1216   off_t off;
1217
1218   if (! func_seek)
1219     {
1220       errno = EOPNOTSUPP;
1221       err = -1;
1222       goto out;
1223     }
1224
1225   if (stream->flags & ES_FLAG_WRITING)
1226     {
1227       /* Flush data first in order to prevent flushing it to the wrong
1228          offset.  */
1229       err = es_flush (stream);
1230       if (err)
1231         goto out;
1232       stream->flags &= ~ES_FLAG_WRITING;
1233     }
1234
1235   off = offset;
1236   if (whence == SEEK_CUR)
1237     {
1238       off = off - stream->data_len + stream->data_offset;
1239       off -= stream->unread_data_len;
1240     }
1241   
1242   ret = (*func_seek) (stream->intern->cookie, &off, whence);
1243   if (ret == -1)
1244     {
1245       err = -1;
1246       goto out;
1247     }
1248
1249   err = 0;
1250   es_empty (stream);
1251
1252   if (offset_new)
1253     *offset_new = off;
1254
1255   stream->intern->indicators.eof = 0;
1256   stream->intern->offset = off;
1257
1258  out:
1259   
1260   if (err)
1261     stream->intern->indicators.err = 1;
1262
1263   return err;
1264 }
1265
1266 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1267    unbuffered-mode, storing the amount of bytes written in
1268    *BYTES_WRITTEN.  */
1269 static int
1270 es_write_nbf (estream_t ES__RESTRICT stream,
1271               const unsigned char *ES__RESTRICT buffer,
1272               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1273 {
1274   es_cookie_write_function_t func_write = stream->intern->func_write;
1275   size_t data_written;
1276   ssize_t ret;
1277   int err;
1278
1279   if (bytes_to_write && (! func_write))
1280     {
1281       err = EOPNOTSUPP;
1282       goto out;
1283     }  
1284
1285   data_written = 0;
1286   err = 0;
1287   
1288   while (bytes_to_write - data_written)
1289     {
1290       ret = (*func_write) (stream->intern->cookie,
1291                            buffer + data_written,
1292                            bytes_to_write - data_written);
1293       if (ret == -1)
1294         {
1295           err = -1;
1296           break;
1297         }
1298       else
1299         data_written += ret;
1300     }
1301
1302   stream->intern->offset += data_written;
1303   *bytes_written = data_written;
1304
1305  out:
1306
1307   return err;
1308 }
1309
1310 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1311    fully-buffered-mode, storing the amount of bytes written in
1312    *BYTES_WRITTEN.  */
1313 static int
1314 es_write_fbf (estream_t ES__RESTRICT stream,
1315               const unsigned char *ES__RESTRICT buffer,
1316               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1317 {
1318   size_t space_available;
1319   size_t data_to_write;
1320   size_t data_written;
1321   int err;
1322
1323   data_written = 0;
1324   err = 0;
1325
1326   while ((bytes_to_write - data_written) && (! err))
1327     {
1328       if (stream->data_offset == stream->buffer_size)
1329         /* Container full, flush buffer.  */
1330         err = es_flush (stream);
1331
1332       if (! err)
1333         {
1334           /* Flushing resulted in empty container.  */
1335           
1336           data_to_write = bytes_to_write - data_written;
1337           space_available = stream->buffer_size - stream->data_offset;
1338           if (data_to_write > space_available)
1339             data_to_write = space_available;
1340               
1341           memcpy (stream->buffer + stream->data_offset,
1342                   buffer + data_written, data_to_write);
1343           stream->data_offset += data_to_write;
1344           data_written += data_to_write;
1345         }
1346     }
1347
1348   *bytes_written = data_written;
1349
1350   return err;
1351 }
1352
1353
1354 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1355    line-buffered-mode, storing the amount of bytes written in
1356    *BYTES_WRITTEN.  */
1357 static int
1358 es_write_lbf (estream_t ES__RESTRICT stream,
1359               const unsigned char *ES__RESTRICT buffer,
1360               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1361 {
1362   size_t data_flushed = 0;
1363   size_t data_buffered = 0;
1364   unsigned char *nlp;
1365   int err = 0;
1366
1367   nlp = memrchr (buffer, '\n', bytes_to_write);
1368   if (nlp)
1369     {
1370       /* Found a newline, directly write up to (including) this
1371          character.  */
1372       err = es_flush (stream);
1373       if (!err)
1374         err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1375     }
1376
1377   if (!err)
1378     {
1379       /* Write remaining data fully buffered.  */
1380       err = es_write_fbf (stream, buffer + data_flushed,
1381                           bytes_to_write - data_flushed, &data_buffered);
1382     }
1383
1384   *bytes_written = data_flushed + data_buffered;
1385   return err;
1386 }
1387
1388
1389 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1390    amount of bytes written in BYTES_WRITTEN.  */
1391 static int
1392 es_writen (estream_t ES__RESTRICT stream,
1393            const void *ES__RESTRICT buffer,
1394            size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1395 {
1396   size_t data_written;
1397   int err;
1398
1399   data_written = 0;
1400   err = 0;
1401   
1402   if (! (stream->flags & ES_FLAG_WRITING))
1403     {
1404       /* Switching to writing mode -> discard input data and seek to
1405          position at which reading has stopped.  We can do this only
1406          if a seek function has been registered. */
1407       if (stream->intern->func_seek)
1408         {
1409           err = es_seek (stream, 0, SEEK_CUR, NULL);
1410           if (err)
1411             {
1412               if (errno == ESPIPE)
1413                 err = 0;
1414               else
1415                 goto out;
1416             }
1417         }
1418     }
1419
1420   switch (stream->intern->strategy)
1421     {
1422     case _IONBF:
1423       err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1424       break;
1425
1426     case _IOLBF:
1427       err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1428       break;
1429
1430     case _IOFBF:
1431       err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1432       break;
1433     }
1434
1435  out:
1436     
1437   if (bytes_written)
1438     *bytes_written = data_written;
1439   if (data_written)
1440     if (! (stream->flags & ES_FLAG_WRITING))
1441       stream->flags |= ES_FLAG_WRITING;
1442
1443   return err;
1444 }
1445
1446
1447 static int
1448 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1449          size_t *ES__RESTRICT data_len)
1450 {
1451   int err;
1452
1453   if (stream->flags & ES_FLAG_WRITING)
1454     {
1455       /* Switching to reading mode -> flush output.  */
1456       err = es_flush (stream);
1457       if (err)
1458         goto out;
1459       stream->flags &= ~ES_FLAG_WRITING;
1460     }  
1461
1462   if (stream->data_offset == stream->data_len)
1463     {
1464       /* Refill container.  */
1465       err = es_fill (stream);
1466       if (err)
1467         goto out;
1468     }
1469   
1470   if (data)
1471     *data = stream->buffer + stream->data_offset;
1472   if (data_len)
1473     *data_len = stream->data_len - stream->data_offset;
1474   err = 0;
1475
1476  out:
1477
1478   return err;
1479 }
1480
1481
1482 /* Skip SIZE bytes of input data contained in buffer.  */
1483 static int
1484 es_skip (estream_t stream, size_t size)
1485 {
1486   int err;
1487
1488   if (stream->data_offset + size > stream->data_len)
1489     {
1490       errno = EINVAL;
1491       err = -1;
1492     }
1493   else
1494     {
1495       stream->data_offset += size;
1496       err = 0;
1497     }
1498
1499   return err;
1500 }
1501
1502
1503 static int
1504 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
1505              char *ES__RESTRICT *ES__RESTRICT line,
1506              size_t *ES__RESTRICT line_length)
1507 {
1508   size_t space_left;
1509   size_t line_size;
1510   estream_t line_stream;
1511   char *line_new;
1512   void *line_stream_cookie;
1513   char *newline;
1514   unsigned char *data;
1515   size_t data_len;
1516   int err;
1517
1518   line_new = NULL;
1519   line_stream = NULL;
1520   line_stream_cookie = NULL;
1521
1522   err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0, BUFFER_BLOCK_SIZE,
1523                             1, 0, 0, NULL, 0, MEM_REALLOC, MEM_FREE, O_RDWR);
1524   if (err)
1525     goto out;
1526
1527   err = es_create (&line_stream, line_stream_cookie, -1,
1528                    estream_functions_mem);
1529   if (err)
1530     goto out;
1531
1532   space_left = max_length;
1533   line_size = 0;
1534   while (1)
1535     {
1536       if (max_length && (space_left == 1))
1537         break;
1538
1539       err = es_peek (stream, &data, &data_len);
1540       if (err || (! data_len))
1541         break;
1542
1543       if (data_len > (space_left - 1))
1544         data_len = space_left - 1;
1545
1546       newline = memchr (data, '\n', data_len);
1547       if (newline)
1548         {
1549           data_len = (newline - (char *) data) + 1;
1550           err = es_write (line_stream, data, data_len, NULL);
1551           if (! err)
1552             {
1553               space_left -= data_len;
1554               line_size += data_len;
1555               es_skip (stream, data_len);
1556               break;
1557             }
1558         }
1559       else
1560         {
1561           err = es_write (line_stream, data, data_len, NULL);
1562           if (! err)
1563             {
1564               space_left -= data_len;
1565               line_size += data_len;
1566               es_skip (stream, data_len);
1567             }
1568         }
1569       if (err)
1570         break;
1571     }
1572   if (err)
1573     goto out;
1574
1575   /* Complete line has been written to line_stream.  */
1576   
1577   if ((max_length > 1) && (! line_size))
1578     {
1579       stream->intern->indicators.eof = 1;
1580       goto out;
1581     }
1582
1583   err = es_seek (line_stream, 0, SEEK_SET, NULL);
1584   if (err)
1585     goto out;
1586
1587   if (! *line)
1588     {
1589       line_new = MEM_ALLOC (line_size + 1);
1590       if (! line_new)
1591         {
1592           err = -1;
1593           goto out;
1594         }
1595     }
1596   else
1597     line_new = *line;
1598
1599   err = es_read (line_stream, line_new, line_size, NULL);
1600   if (err)
1601     goto out;
1602
1603   line_new[line_size] = '\0';
1604
1605   if (! *line)
1606     *line = line_new;
1607   if (line_length)
1608     *line_length = line_size;
1609
1610  out:
1611
1612   if (line_stream)
1613     es_destroy (line_stream);
1614   else if (line_stream_cookie)
1615     es_func_mem_destroy (line_stream_cookie);
1616
1617   if (err)
1618     {
1619       if (! *line)
1620         MEM_FREE (line_new);
1621       stream->intern->indicators.err = 1;
1622     }
1623
1624   return err;
1625 }
1626
1627
1628 static int
1629 es_print (estream_t ES__RESTRICT stream,
1630           const char *ES__RESTRICT format, va_list ap)
1631 {
1632   char data[BUFFER_BLOCK_SIZE];
1633   size_t bytes_written;
1634   size_t bytes_read;
1635   FILE *tmp_stream;
1636   int err;
1637
1638   bytes_written = 0;
1639   tmp_stream = NULL;
1640   err = 0;
1641   
1642   tmp_stream = tmpfile ();
1643   if (! tmp_stream)
1644     {
1645       err = errno;
1646       goto out;
1647     }
1648
1649   err = vfprintf (tmp_stream, format, ap);
1650   if (err < 0)
1651     goto out;
1652
1653   err = fseek (tmp_stream, 0, SEEK_SET);
1654   if (err)
1655     goto out;
1656
1657   while (1)
1658     {
1659       bytes_read = fread (data, 1, sizeof (data), tmp_stream);
1660       if (ferror (tmp_stream))
1661         {
1662           err = -1;
1663           break;
1664         }
1665
1666       err = es_writen (stream, data, bytes_read, NULL);
1667       if (err)
1668         break;
1669       else
1670         bytes_written += bytes_read;
1671       if (feof (tmp_stream))
1672         break;
1673     }
1674   if (err)
1675     goto out;
1676
1677  out:
1678
1679   if (tmp_stream)
1680     fclose (tmp_stream);
1681
1682   return err ? -1 : bytes_written;
1683 }
1684
1685
1686 static void
1687 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1688 {
1689   if (ind_err != -1)
1690     stream->intern->indicators.err = ind_err ? 1 : 0;
1691   if (ind_eof != -1)
1692     stream->intern->indicators.eof = ind_eof ? 1 : 0;
1693 }
1694
1695
1696 static int
1697 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1698 {
1699   int ret = 0;
1700   
1701   if (ind_err)
1702     ret = stream->intern->indicators.err;
1703   else if (ind_eof)
1704     ret = stream->intern->indicators.eof;
1705
1706   return ret;
1707 }
1708
1709
1710 static int
1711 es_set_buffering (estream_t ES__RESTRICT stream,
1712                   char *ES__RESTRICT buffer, int mode, size_t size)
1713 {
1714   int err;
1715
1716   /* Flush or empty buffer depending on mode.  */
1717   if (stream->flags & ES_FLAG_WRITING)
1718     {
1719       err = es_flush (stream);
1720       if (err)
1721         goto out;
1722     }
1723   else
1724     es_empty (stream);
1725
1726   es_set_indicators (stream, -1, 0);
1727   
1728   /* Free old buffer in case that was allocated by this function.  */
1729   if (stream->intern->deallocate_buffer)
1730     {
1731       stream->intern->deallocate_buffer = 0;
1732       MEM_FREE (stream->buffer);
1733       stream->buffer = NULL;
1734     }
1735
1736   if (mode == _IONBF)
1737     stream->buffer_size = 0;
1738   else
1739     {
1740       void *buffer_new;
1741       
1742       if (buffer)
1743         buffer_new = buffer;
1744       else
1745         {
1746           buffer_new = MEM_ALLOC (size);
1747           if (! buffer_new)
1748             {
1749               err = -1;
1750               goto out;
1751             }
1752         }
1753
1754       stream->buffer = buffer_new;
1755       stream->buffer_size = size;
1756       if (! buffer)
1757         stream->intern->deallocate_buffer = 1;
1758     }
1759   stream->intern->strategy = mode;
1760   err = 0;
1761
1762  out:
1763
1764   return err;
1765 }
1766
1767
1768 static off_t
1769 es_offset_calculate (estream_t stream)
1770 {
1771   off_t offset;
1772
1773   offset = stream->intern->offset + stream->data_offset;
1774   if (offset < stream->unread_data_len)
1775     /* Offset undefined.  */
1776     offset = 0;
1777   else
1778     offset -= stream->unread_data_len;
1779
1780   return offset;
1781 }
1782
1783
1784 static void
1785 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1786                 void **ES__RESTRICT opaque_old)
1787 {
1788   if (opaque_old)
1789     *opaque_old = stream->intern->opaque;
1790   if (opaque_new)
1791     stream->intern->opaque = opaque_new;
1792 }
1793
1794
1795 static int
1796 es_get_fd (estream_t stream)
1797 {
1798   return stream->intern->fd;
1799 }
1800
1801 \f
1802
1803 /* API.  */
1804
1805 int
1806 es_init (void)
1807 {
1808   int err;
1809
1810   err = es_init_do ();
1811
1812   return err;
1813 }
1814
1815 estream_t
1816 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
1817 {
1818   unsigned int flags;
1819   int create_called;
1820   estream_t stream;
1821   void *cookie;
1822   int err;
1823   int fd;
1824
1825   stream = NULL;
1826   cookie = NULL;
1827   create_called = 0;
1828
1829   err = es_convert_mode (mode, &flags);
1830   if (err)
1831     goto out;
1832   
1833   err = es_func_file_create (&cookie, &fd, path, flags);
1834   if (err)
1835     goto out;
1836
1837   create_called = 1;
1838   err = es_create (&stream, cookie, fd, estream_functions_file);
1839   if (err)
1840     goto out;
1841
1842  out:
1843   
1844   if (err && create_called)
1845     (*estream_functions_file.func_close) (cookie);
1846
1847   return stream;
1848 }
1849
1850
1851 estream_t
1852 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
1853           unsigned int grow,
1854           func_realloc_t func_realloc, func_free_t func_free,
1855           const char *ES__RESTRICT mode)
1856 {
1857   unsigned int flags;
1858   int create_called;
1859   estream_t stream;
1860   void *cookie;
1861   int err;
1862
1863   cookie = 0;
1864   stream = NULL;
1865   create_called = 0;
1866   
1867   err = es_convert_mode (mode, &flags);
1868   if (err)
1869     goto out;
1870
1871   err = es_func_mem_create (&cookie, data, data_n, data_len,
1872                             BUFFER_BLOCK_SIZE, grow, 0, 0,
1873                             NULL, 0, func_realloc, func_free, flags);
1874   if (err)
1875     goto out;
1876   
1877   create_called = 1;
1878   err = es_create (&stream, cookie, -1, estream_functions_mem);
1879
1880  out:
1881
1882   if (err && create_called)
1883     (*estream_functions_mem.func_close) (cookie);
1884
1885   return stream;
1886 }
1887
1888
1889 estream_t
1890 es_open_memstream (char **ptr, size_t *size)
1891 {
1892   unsigned int flags;
1893   int create_called;
1894   estream_t stream;
1895   void *cookie;
1896   int err;
1897
1898   flags = O_RDWR;
1899   create_called = 0;
1900   stream = NULL;
1901   cookie = 0;
1902   
1903   err = es_func_mem_create (&cookie, NULL, 0, 0,
1904                             BUFFER_BLOCK_SIZE, 1, 1, 1,
1905                             ptr, size, MEM_REALLOC, MEM_FREE, flags);
1906   if (err)
1907     goto out;
1908   
1909   create_called = 1;
1910   err = es_create (&stream, cookie, -1, estream_functions_mem);
1911
1912  out:
1913
1914   if (err && create_called)
1915     (*estream_functions_mem.func_close) (cookie);
1916
1917   return stream;
1918 }
1919
1920
1921 estream_t
1922 es_fopencookie (void *ES__RESTRICT cookie,
1923                 const char *ES__RESTRICT mode,
1924                 es_cookie_io_functions_t functions)
1925 {
1926   unsigned int flags;
1927   estream_t stream;
1928   int err;
1929
1930   stream = NULL;
1931   flags = 0;
1932   
1933   err = es_convert_mode (mode, &flags);
1934   if (err)
1935     goto out;
1936
1937   err = es_create (&stream, cookie, -1, functions);
1938   if (err)
1939     goto out;
1940
1941  out:
1942
1943   return stream;
1944 }
1945
1946
1947 estream_t
1948 es_fdopen (int filedes, const char *mode)
1949 {
1950   unsigned int flags;
1951   int create_called;
1952   estream_t stream;
1953   void *cookie;
1954   int err;
1955
1956   stream = NULL;
1957   cookie = NULL;
1958   create_called = 0;
1959
1960   err = es_convert_mode (mode, &flags);
1961   if (err)
1962     goto out;
1963
1964   err = es_func_fd_create (&cookie, filedes, flags);
1965   if (err)
1966     goto out;
1967
1968   create_called = 1;
1969   err = es_create (&stream, cookie, filedes, estream_functions_fd);
1970
1971  out:
1972
1973   if (err && create_called)
1974     (*estream_functions_fd.func_close) (cookie);
1975
1976   return stream;
1977 }
1978   
1979
1980 estream_t
1981 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
1982             estream_t ES__RESTRICT stream)
1983 {
1984   int err;
1985
1986   if (path)
1987     {
1988       unsigned int flags;
1989       int create_called;
1990       void *cookie;
1991       int fd;
1992
1993       cookie = NULL;
1994       create_called = 0;
1995       
1996       ESTREAM_LOCK (stream);
1997
1998       es_deinitialize (stream);
1999
2000       err = es_convert_mode (mode, &flags);
2001       if (err)
2002         goto leave;
2003       
2004       err = es_func_file_create (&cookie, &fd, path, flags);
2005       if (err)
2006         goto leave;
2007
2008       create_called = 1;
2009       es_initialize (stream, cookie, fd, estream_functions_file);
2010
2011     leave:
2012
2013       if (err)
2014         {
2015           if (create_called)
2016             es_func_fd_destroy (cookie);
2017       
2018           es_destroy (stream);
2019           stream = NULL;
2020         }
2021       else
2022         ESTREAM_UNLOCK (stream);
2023     }
2024   else
2025     {
2026       /* FIXME?  We don't support re-opening at the moment.  */
2027       errno = EINVAL;
2028       es_deinitialize (stream);
2029       es_destroy (stream);
2030       stream = NULL;
2031     }
2032
2033   return stream;
2034 }
2035
2036
2037 int
2038 es_fclose (estream_t stream)
2039 {
2040   int err;
2041
2042   err = es_destroy (stream);
2043
2044   return err;
2045 }
2046
2047 int
2048 es_fileno_unlocked (estream_t stream)
2049 {
2050   return es_get_fd (stream);
2051 }
2052
2053
2054 void
2055 es_flockfile (estream_t stream)
2056 {
2057   ESTREAM_LOCK (stream);
2058 }
2059
2060
2061 int
2062 es_ftrylockfile (estream_t stream)
2063 {
2064   return ESTREAM_TRYLOCK (stream);
2065 }
2066
2067
2068 void
2069 es_funlockfile (estream_t stream)
2070 {
2071   ESTREAM_UNLOCK (stream);
2072 }
2073
2074
2075 int
2076 es_fileno (estream_t stream)
2077 {
2078   int ret;
2079
2080   ESTREAM_LOCK (stream);
2081   ret = es_fileno_unlocked (stream);
2082   ESTREAM_UNLOCK (stream);
2083
2084   return ret;
2085 }
2086
2087
2088 int
2089 es_feof_unlocked (estream_t stream)
2090 {
2091   return es_get_indicator (stream, 0, 1);
2092 }
2093
2094
2095 int
2096 es_feof (estream_t stream)
2097 {
2098   int ret;
2099
2100   ESTREAM_LOCK (stream);
2101   ret = es_feof_unlocked (stream);
2102   ESTREAM_UNLOCK (stream);
2103
2104   return ret;
2105 }
2106
2107
2108 int
2109 es_ferror_unlocked (estream_t stream)
2110 {
2111   return es_get_indicator (stream, 1, 0);
2112 }
2113
2114
2115 int
2116 es_ferror (estream_t stream)
2117 {
2118   int ret;
2119
2120   ESTREAM_LOCK (stream);
2121   ret = es_ferror_unlocked (stream);
2122   ESTREAM_UNLOCK (stream);
2123
2124   return ret;
2125 }
2126
2127
2128 void
2129 es_clearerr_unlocked (estream_t stream)
2130 {
2131   es_set_indicators (stream, 0, 0);
2132 }
2133
2134
2135 void
2136 es_clearerr (estream_t stream)
2137 {
2138   ESTREAM_LOCK (stream);
2139   es_clearerr_unlocked (stream);
2140   ESTREAM_UNLOCK (stream);
2141 }
2142
2143
2144 int
2145 es_fflush (estream_t stream)
2146 {
2147   int err;
2148   
2149   if (stream)
2150     {
2151       ESTREAM_LOCK (stream);
2152       if (stream->flags & ES_FLAG_WRITING)
2153         err = es_flush (stream);
2154       else
2155         {
2156           es_empty (stream);
2157           err = 0;
2158         }
2159       ESTREAM_UNLOCK (stream);
2160     }
2161   else
2162     err = es_list_iterate (es_fflush);
2163
2164   return err ? EOF : 0;
2165 }
2166
2167
2168 int
2169 es_fseek (estream_t stream, long int offset, int whence)
2170 {
2171   int err;
2172
2173   ESTREAM_LOCK (stream);
2174   err = es_seek (stream, offset, whence, NULL);
2175   ESTREAM_UNLOCK (stream);
2176
2177   return err;
2178 }
2179
2180
2181 int
2182 es_fseeko (estream_t stream, off_t offset, int whence)
2183 {
2184   int err;
2185   
2186   ESTREAM_LOCK (stream);
2187   err = es_seek (stream, offset, whence, NULL);
2188   ESTREAM_UNLOCK (stream);
2189
2190   return err;
2191 }
2192
2193
2194 long int
2195 es_ftell (estream_t stream)
2196 {
2197   long int ret;
2198   
2199   ESTREAM_LOCK (stream);
2200   ret = es_offset_calculate (stream);
2201   ESTREAM_UNLOCK (stream);
2202
2203   return ret;
2204 }
2205
2206
2207 off_t
2208 es_ftello (estream_t stream)
2209 {
2210   off_t ret = -1;
2211
2212   ESTREAM_LOCK (stream);
2213   ret = es_offset_calculate (stream);
2214   ESTREAM_UNLOCK (stream);
2215
2216   return ret;
2217 }
2218
2219
2220 void
2221 es_rewind (estream_t stream)
2222 {
2223   ESTREAM_LOCK (stream);
2224   es_seek (stream, 0L, SEEK_SET, NULL);
2225   es_set_indicators (stream, 0, -1);
2226   ESTREAM_UNLOCK (stream);
2227 }
2228
2229
2230 int
2231 _es_getc_underflow (estream_t stream)
2232 {
2233   int err;
2234   unsigned char c;
2235   size_t bytes_read;
2236
2237   err = es_readn (stream, &c, 1, &bytes_read);
2238
2239   return (err || (! bytes_read)) ? EOF : c;
2240 }
2241
2242
2243 int
2244 _es_putc_overflow (int c, estream_t stream)
2245 {
2246   unsigned char d = c;
2247   int err;
2248
2249   err = es_writen (stream, &d, 1, NULL);
2250
2251   return err ? EOF : c;
2252 }
2253
2254
2255 int
2256 es_fgetc (estream_t stream)
2257 {
2258   int ret;
2259   
2260   ESTREAM_LOCK (stream);
2261   ret = es_getc_unlocked (stream);
2262   ESTREAM_UNLOCK (stream);
2263
2264   return ret;
2265 }
2266
2267
2268 int
2269 es_fputc (int c, estream_t stream)
2270 {
2271   int ret;
2272   
2273   ESTREAM_LOCK (stream);
2274   ret = es_putc_unlocked (c, stream);
2275   ESTREAM_UNLOCK (stream);
2276
2277   return ret;
2278 }
2279
2280
2281 int
2282 es_ungetc (int c, estream_t stream)
2283 {
2284   unsigned char data = (unsigned char) c;
2285   size_t data_unread;
2286
2287   ESTREAM_LOCK (stream);
2288   es_unreadn (stream, &data, 1, &data_unread);
2289   ESTREAM_UNLOCK (stream);
2290
2291   return data_unread ? c : EOF;
2292 }
2293
2294
2295 int
2296 es_read (estream_t ES__RESTRICT stream,
2297          void *ES__RESTRICT buffer, size_t bytes_to_read,
2298          size_t *ES__RESTRICT bytes_read)
2299 {
2300   int err;
2301
2302   if (bytes_to_read)
2303     {
2304       ESTREAM_LOCK (stream);
2305       err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2306       ESTREAM_UNLOCK (stream);
2307     }
2308   else
2309     err = 0;
2310
2311   return err;
2312 }
2313
2314
2315 int
2316 es_write (estream_t ES__RESTRICT stream,
2317           const void *ES__RESTRICT buffer, size_t bytes_to_write,
2318           size_t *ES__RESTRICT bytes_written)
2319 {
2320   int err;
2321
2322   if (bytes_to_write)
2323     {
2324       ESTREAM_LOCK (stream);
2325       err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2326       ESTREAM_UNLOCK (stream);
2327     }
2328   else
2329     err = 0;
2330
2331   return err;
2332 }
2333
2334
2335 size_t
2336 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2337           estream_t ES__RESTRICT stream)
2338 {
2339   size_t ret, bytes;
2340   int err;
2341
2342   if (size * nitems)
2343     {
2344       ESTREAM_LOCK (stream);
2345       err = es_readn (stream, ptr, size * nitems, &bytes);
2346       ESTREAM_UNLOCK (stream);
2347
2348       ret = bytes / size;
2349     }
2350   else
2351     ret = 0;
2352
2353   return ret;
2354 }
2355
2356
2357 size_t
2358 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2359            estream_t ES__RESTRICT stream)
2360 {
2361   size_t ret, bytes;
2362   int err;
2363
2364   if (size * nitems)
2365     {
2366       ESTREAM_LOCK (stream);
2367       err = es_writen (stream, ptr, size * nitems, &bytes);
2368       ESTREAM_UNLOCK (stream);
2369
2370       ret = bytes / size;
2371     }
2372   else
2373     ret = 0;
2374
2375   return ret;
2376 }
2377
2378
2379 char *
2380 es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream)
2381 {
2382   char *ret = NULL;
2383   
2384   if (n)
2385     {
2386       int err;
2387       
2388       ESTREAM_LOCK (stream);
2389       err = doreadline (stream, n, &s, NULL);
2390       ESTREAM_UNLOCK (stream);
2391       if (! err)
2392         ret = s;
2393     }
2394   
2395   return ret;
2396 }
2397
2398
2399 int
2400 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2401 {
2402   size_t length;
2403   int err;
2404
2405   length = strlen (s);
2406   ESTREAM_LOCK (stream);
2407   err = es_writen (stream, s, length, NULL);
2408   ESTREAM_UNLOCK (stream);
2409
2410   return err ? EOF : 0;
2411 }
2412
2413
2414 ssize_t
2415 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2416             estream_t ES__RESTRICT stream)
2417 {
2418   char *line = NULL;
2419   size_t line_n = 0;
2420   int err;
2421
2422   ESTREAM_LOCK (stream);
2423   err = doreadline (stream, 0, &line, &line_n);
2424   ESTREAM_UNLOCK (stream);
2425   if (err)
2426     goto out;
2427
2428   if (*n)
2429     {
2430       /* Caller wants us to use his buffer.  */
2431       
2432       if (*n < (line_n + 1))
2433         {
2434           /* Provided buffer is too small -> resize.  */
2435
2436           void *p;
2437
2438           p = MEM_REALLOC (*lineptr, line_n + 1);
2439           if (! p)
2440             err = -1;
2441           else
2442             {
2443               if (*lineptr != p)
2444                 *lineptr = p;
2445             }
2446         }
2447
2448       if (! err)
2449         {
2450           memcpy (*lineptr, line, line_n + 1);
2451           if (*n != line_n)
2452             *n = line_n;
2453         }
2454       MEM_FREE (line);
2455     }
2456   else
2457     {
2458       /* Caller wants new buffers.  */
2459       *lineptr = line;
2460       *n = line_n;
2461     }
2462
2463  out:
2464
2465   return err ? err : line_n;
2466 }
2467
2468
2469
2470 /* Same as fgets() but if the provided buffer is too short a larger
2471    one will be allocated.  This is similar to getline. A line is
2472    considered a byte stream ending in a LF.
2473
2474    If MAX_LENGTH is not NULL, it shall point to a value with the
2475    maximum allowed allocation.  
2476
2477    Returns the length of the line. EOF is indicated by a line of
2478    length zero. A truncated line is indicated my setting the value at
2479    MAX_LENGTH to 0.  If the returned value is less then 0 not enough
2480    memory was enable or another error occurred; ERRNO is then set
2481    accordingly.
2482
2483    If a line has been truncated, the file pointer is moved forward to
2484    the end of the line so that the next read starts with the next
2485    line.  Note that MAX_LENGTH must be re-initialzied in this case.
2486
2487    The caller initially needs to provide the address of a variable,
2488    initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2489    anymore with the following invocations.  LENGTH_OF_BUFFER should be
2490    the address of a variable, initialized to 0, which is also
2491    maintained by this function.  Thus, both paramaters should be
2492    considered the state of this function.
2493
2494    Note: The returned buffer is allocated with enough extra space to
2495    allow the caller to append a CR,LF,Nul.  The buffer should be
2496    released using es_free.
2497  */
2498 ssize_t
2499 es_read_line (estream_t stream, 
2500               char **addr_of_buffer, size_t *length_of_buffer,
2501               size_t *max_length)
2502 {
2503   int c;
2504   char  *buffer = *addr_of_buffer;
2505   size_t length = *length_of_buffer;
2506   size_t nbytes = 0;
2507   size_t maxlen = max_length? *max_length : 0;
2508   char *p;
2509
2510   if (!buffer)
2511     { 
2512       /* No buffer given - allocate a new one. */
2513       length = 256;
2514       buffer = MEM_ALLOC (length);
2515       *addr_of_buffer = buffer;
2516       if (!buffer)
2517         {
2518           *length_of_buffer = 0;
2519           if (max_length)
2520             *max_length = 0;
2521           return -1;
2522         }
2523       *length_of_buffer = length;
2524     }
2525
2526   if (length < 4)
2527     {
2528       /* This should never happen. If it does, the fucntion has been
2529          called with wrong arguments. */
2530       errno = EINVAL;
2531       return -1;
2532     }
2533   length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2534
2535   ESTREAM_LOCK (stream);
2536   p = buffer;
2537   while  ((c = es_getc_unlocked (stream)) != EOF)
2538     {
2539       if (nbytes == length)
2540         { 
2541           /* Enlarge the buffer. */
2542           if (maxlen && length > maxlen) 
2543             {
2544               /* We are beyond our limit: Skip the rest of the line. */
2545               while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
2546                 ;
2547               *p++ = '\n'; /* Always append a LF (we reserved some space). */
2548               nbytes++;
2549               if (max_length)
2550                 *max_length = 0; /* Indicate truncation. */
2551               break; /* the while loop. */
2552             }
2553           length += 3; /* Adjust for the reserved bytes. */
2554           length += length < 1024? 256 : 1024;
2555           *addr_of_buffer = MEM_REALLOC (buffer, length);
2556           if (!*addr_of_buffer)
2557             {
2558               int save_errno = errno;
2559               MEM_FREE (buffer); 
2560               *length_of_buffer = *max_length = 0;
2561               ESTREAM_UNLOCK (stream);
2562               errno = save_errno;
2563               return -1;
2564             }
2565           buffer = *addr_of_buffer;
2566           *length_of_buffer = length;
2567           length -= 3; 
2568           p = buffer + nbytes;
2569         }
2570       *p++ = c;
2571       nbytes++;
2572       if (c == '\n')
2573         break;
2574     }
2575   *p = 0; /* Make sure the line is a string. */
2576   ESTREAM_UNLOCK (stream);
2577
2578   return nbytes;
2579 }
2580
2581 /* Wrapper around free() to match the memory allocation system used
2582    by estream.  Should be used for all buffers returned to the caller
2583    by libestream. */
2584 void
2585 es_free (void *a)
2586 {
2587   if (a)
2588     MEM_FREE (a);
2589 }
2590
2591
2592 int
2593 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2594              va_list ap)
2595 {
2596   int ret;
2597   
2598   ESTREAM_LOCK (stream);
2599   ret = es_print (stream, format, ap);
2600   ESTREAM_UNLOCK (stream);
2601
2602   return ret;
2603 }
2604
2605
2606 int
2607 es_fprintf (estream_t ES__RESTRICT stream,
2608             const char *ES__RESTRICT format, ...)
2609 {
2610   int ret;
2611   
2612   va_list ap;
2613   va_start (ap, format);
2614   ESTREAM_LOCK (stream);
2615   ret = es_print (stream, format, ap);
2616   ESTREAM_UNLOCK (stream);
2617   va_end (ap);
2618
2619   return ret;
2620 }
2621
2622 static int
2623 tmpfd (void)
2624 {
2625   FILE *fp;
2626   int fp_fd;
2627   int fd;
2628
2629   fp = NULL;
2630   fd = -1;
2631   
2632   fp = tmpfile ();
2633   if (! fp)
2634     goto out;
2635
2636   fp_fd = fileno (fp);
2637   fd = dup (fp_fd);
2638
2639  out:
2640
2641   if (fp)
2642     fclose (fp);
2643
2644   return fd;
2645 }
2646
2647 estream_t
2648 es_tmpfile (void)
2649 {
2650   unsigned int flags;
2651   int create_called;
2652   estream_t stream;
2653   void *cookie;
2654   int err;
2655   int fd;
2656
2657   create_called = 0;
2658   stream = NULL;
2659   flags = O_RDWR | O_TRUNC | O_CREAT;
2660   cookie = NULL;
2661   
2662   fd = tmpfd ();
2663   if (fd == -1)
2664     {
2665       err = -1;
2666       goto out;
2667     }
2668
2669   err = es_func_fd_create (&cookie, fd, flags);
2670   if (err)
2671     goto out;
2672
2673   create_called = 1;
2674   err = es_create (&stream, cookie, fd, estream_functions_fd);
2675
2676  out:
2677
2678   if (err)
2679     {
2680       if (create_called)
2681         es_func_fd_destroy (cookie);
2682       else if (fd != -1)
2683         close (fd);
2684       stream = NULL;
2685     }
2686   
2687   return stream;
2688 }
2689
2690
2691 int
2692 es_setvbuf (estream_t ES__RESTRICT stream,
2693             char *ES__RESTRICT buf, int type, size_t size)
2694 {
2695   int err;
2696   
2697   if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
2698       && (! ((! size) && (type != _IONBF))))
2699     {
2700       ESTREAM_LOCK (stream);
2701       err = es_set_buffering (stream, buf, type, size);
2702       ESTREAM_UNLOCK (stream);
2703     }
2704   else
2705     {
2706       errno = EINVAL;
2707       err = -1;
2708     }
2709
2710   return err;
2711 }
2712
2713
2714 void
2715 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
2716 {
2717   ESTREAM_LOCK (stream);
2718   es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
2719   ESTREAM_UNLOCK (stream);
2720 }
2721
2722 void
2723 es_opaque_set (estream_t stream, void *opaque)
2724 {
2725   ESTREAM_LOCK (stream);
2726   es_opaque_ctrl (stream, opaque, NULL);
2727   ESTREAM_UNLOCK (stream);
2728 }
2729
2730
2731 void *
2732 es_opaque_get (estream_t stream)
2733 {
2734   void *opaque;
2735   
2736   ESTREAM_LOCK (stream);
2737   es_opaque_ctrl (stream, NULL, &opaque);
2738   ESTREAM_UNLOCK (stream);
2739
2740   return opaque;
2741 }
2742