Updated FSF's address.
[gnupg.git] / common / estream.c
1 /* estream.c - Extended stream I/O/ Library
2  * Copyright (C) 2004 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.  */
1406
1407       err = es_seek (stream, 0, SEEK_CUR, NULL);
1408       if (err)
1409         {
1410           if (errno == ESPIPE)
1411             err = 0;
1412           else
1413             goto out;
1414         }
1415     }
1416
1417   switch (stream->intern->strategy)
1418     {
1419     case _IONBF:
1420       err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1421       break;
1422
1423     case _IOLBF:
1424       err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1425       break;
1426
1427     case _IOFBF:
1428       err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1429       break;
1430     }
1431
1432  out:
1433     
1434   if (bytes_written)
1435     *bytes_written = data_written;
1436   if (data_written)
1437     if (! (stream->flags & ES_FLAG_WRITING))
1438       stream->flags |= ES_FLAG_WRITING;
1439
1440   return err;
1441 }
1442
1443
1444 static int
1445 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1446          size_t *ES__RESTRICT data_len)
1447 {
1448   int err;
1449
1450   if (stream->flags & ES_FLAG_WRITING)
1451     {
1452       /* Switching to reading mode -> flush output.  */
1453       err = es_flush (stream);
1454       if (err)
1455         goto out;
1456       stream->flags &= ~ES_FLAG_WRITING;
1457     }  
1458
1459   if (stream->data_offset == stream->data_len)
1460     {
1461       /* Refill container.  */
1462       err = es_fill (stream);
1463       if (err)
1464         goto out;
1465     }
1466   
1467   if (data)
1468     *data = stream->buffer + stream->data_offset;
1469   if (data_len)
1470     *data_len = stream->data_len - stream->data_offset;
1471   err = 0;
1472
1473  out:
1474
1475   return err;
1476 }
1477
1478
1479 /* Skip SIZE bytes of input data contained in buffer.  */
1480 static int
1481 es_skip (estream_t stream, size_t size)
1482 {
1483   int err;
1484
1485   if (stream->data_offset + size > stream->data_len)
1486     {
1487       errno = EINVAL;
1488       err = -1;
1489     }
1490   else
1491     {
1492       stream->data_offset += size;
1493       err = 0;
1494     }
1495
1496   return err;
1497 }
1498
1499
1500 static int
1501 es_read_line (estream_t ES__RESTRICT stream, size_t max_length,
1502               char *ES__RESTRICT *ES__RESTRICT line,
1503               size_t *ES__RESTRICT line_length)
1504 {
1505   size_t space_left;
1506   size_t line_size;
1507   estream_t line_stream;
1508   char *line_new;
1509   void *line_stream_cookie;
1510   char *newline;
1511   unsigned char *data;
1512   size_t data_len;
1513   int err;
1514
1515   line_new = NULL;
1516   line_stream = NULL;
1517   line_stream_cookie = NULL;
1518
1519   err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0, BUFFER_BLOCK_SIZE,
1520                             1, 0, 0, NULL, 0, MEM_REALLOC, MEM_FREE, O_RDWR);
1521   if (err)
1522     goto out;
1523
1524   err = es_create (&line_stream, line_stream_cookie, -1,
1525                    estream_functions_mem);
1526   if (err)
1527     goto out;
1528
1529   space_left = max_length;
1530   line_size = 0;
1531   while (1)
1532     {
1533       if (max_length && (space_left == 1))
1534         break;
1535
1536       err = es_peek (stream, &data, &data_len);
1537       if (err || (! data_len))
1538         break;
1539
1540       if (data_len > (space_left - 1))
1541         data_len = space_left - 1;
1542
1543       newline = memchr (data, '\n', data_len);
1544       if (newline)
1545         {
1546           data_len = (newline - (char *) data) + 1;
1547           err = es_write (line_stream, data, data_len, NULL);
1548           if (! err)
1549             {
1550               space_left -= data_len;
1551               line_size += data_len;
1552               es_skip (stream, data_len);
1553               break;
1554             }
1555         }
1556       else
1557         {
1558           err = es_write (line_stream, data, data_len, NULL);
1559           if (! err)
1560             {
1561               space_left -= data_len;
1562               line_size += data_len;
1563               es_skip (stream, data_len);
1564             }
1565         }
1566       if (err)
1567         break;
1568     }
1569   if (err)
1570     goto out;
1571
1572   /* Complete line has been written to line_stream.  */
1573   
1574   if ((max_length > 1) && (! line_size))
1575     {
1576       stream->intern->indicators.eof = 1;
1577       goto out;
1578     }
1579
1580   err = es_seek (line_stream, 0, SEEK_SET, NULL);
1581   if (err)
1582     goto out;
1583
1584   if (! *line)
1585     {
1586       line_new = MEM_ALLOC (line_size + 1);
1587       if (! line_new)
1588         {
1589           err = -1;
1590           goto out;
1591         }
1592     }
1593   else
1594     line_new = *line;
1595
1596   err = es_read (line_stream, line_new, line_size, NULL);
1597   if (err)
1598     goto out;
1599
1600   line_new[line_size] = '\0';
1601
1602   if (! *line)
1603     *line = line_new;
1604   if (line_length)
1605     *line_length = line_size;
1606
1607  out:
1608
1609   if (line_stream)
1610     es_destroy (line_stream);
1611   else if (line_stream_cookie)
1612     es_func_mem_destroy (line_stream_cookie);
1613
1614   if (err)
1615     {
1616       if (! *line)
1617         MEM_FREE (line_new);
1618       stream->intern->indicators.err = 1;
1619     }
1620
1621   return err;
1622 }
1623
1624
1625 static int
1626 es_print (estream_t ES__RESTRICT stream,
1627           const char *ES__RESTRICT format, va_list ap)
1628 {
1629   char data[BUFFER_BLOCK_SIZE];
1630   size_t bytes_written;
1631   size_t bytes_read;
1632   FILE *tmp_stream;
1633   int err;
1634
1635   bytes_written = 0;
1636   tmp_stream = NULL;
1637   err = 0;
1638   
1639   tmp_stream = tmpfile ();
1640   if (! tmp_stream)
1641     {
1642       err = errno;
1643       goto out;
1644     }
1645
1646   err = vfprintf (tmp_stream, format, ap);
1647   if (err < 0)
1648     goto out;
1649
1650   err = fseek (tmp_stream, 0, SEEK_SET);
1651   if (err)
1652     goto out;
1653
1654   while (1)
1655     {
1656       bytes_read = fread (data, 1, sizeof (data), tmp_stream);
1657       if (ferror (tmp_stream))
1658         {
1659           err = -1;
1660           break;
1661         }
1662
1663       err = es_writen (stream, data, bytes_read, NULL);
1664       if (err)
1665         break;
1666       else
1667         bytes_written += bytes_read;
1668       if (feof (tmp_stream))
1669         break;
1670     }
1671   if (err)
1672     goto out;
1673
1674  out:
1675
1676   if (tmp_stream)
1677     fclose (tmp_stream);
1678
1679   return err ? -1 : bytes_written;
1680 }
1681
1682
1683 static void
1684 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1685 {
1686   if (ind_err != -1)
1687     stream->intern->indicators.err = ind_err ? 1 : 0;
1688   if (ind_eof != -1)
1689     stream->intern->indicators.eof = ind_eof ? 1 : 0;
1690 }
1691
1692
1693 static int
1694 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1695 {
1696   int ret = 0;
1697   
1698   if (ind_err)
1699     ret = stream->intern->indicators.err;
1700   else if (ind_eof)
1701     ret = stream->intern->indicators.eof;
1702
1703   return ret;
1704 }
1705
1706
1707 static int
1708 es_set_buffering (estream_t ES__RESTRICT stream,
1709                   char *ES__RESTRICT buffer, int mode, size_t size)
1710 {
1711   int err;
1712
1713   /* Flush or empty buffer depending on mode.  */
1714   if (stream->flags & ES_FLAG_WRITING)
1715     {
1716       err = es_flush (stream);
1717       if (err)
1718         goto out;
1719     }
1720   else
1721     es_empty (stream);
1722
1723   es_set_indicators (stream, -1, 0);
1724   
1725   /* Free old buffer in case that was allocated by this function.  */
1726   if (stream->intern->deallocate_buffer)
1727     {
1728       stream->intern->deallocate_buffer = 0;
1729       MEM_FREE (stream->buffer);
1730       stream->buffer = NULL;
1731     }
1732
1733   if (mode == _IONBF)
1734     stream->buffer_size = 0;
1735   else
1736     {
1737       void *buffer_new;
1738       
1739       if (buffer)
1740         buffer_new = buffer;
1741       else
1742         {
1743           buffer_new = MEM_ALLOC (size);
1744           if (! buffer_new)
1745             {
1746               err = -1;
1747               goto out;
1748             }
1749         }
1750
1751       stream->buffer = buffer_new;
1752       stream->buffer_size = size;
1753       if (! buffer)
1754         stream->intern->deallocate_buffer = 1;
1755     }
1756   stream->intern->strategy = mode;
1757   err = 0;
1758
1759  out:
1760
1761   return err;
1762 }
1763
1764
1765 static off_t
1766 es_offset_calculate (estream_t stream)
1767 {
1768   off_t offset;
1769
1770   offset = stream->intern->offset + stream->data_offset;
1771   if (offset < stream->unread_data_len)
1772     /* Offset undefined.  */
1773     offset = 0;
1774   else
1775     offset -= stream->unread_data_len;
1776
1777   return offset;
1778 }
1779
1780
1781 static void
1782 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1783                 void **ES__RESTRICT opaque_old)
1784 {
1785   if (opaque_old)
1786     *opaque_old = stream->intern->opaque;
1787   if (opaque_new)
1788     stream->intern->opaque = opaque_new;
1789 }
1790
1791
1792 static int
1793 es_get_fd (estream_t stream)
1794 {
1795   return stream->intern->fd;
1796 }
1797
1798 \f
1799
1800 /* API.  */
1801
1802 int
1803 es_init (void)
1804 {
1805   int err;
1806
1807   err = es_init_do ();
1808
1809   return err;
1810 }
1811
1812 estream_t
1813 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
1814 {
1815   unsigned int flags;
1816   int create_called;
1817   estream_t stream;
1818   void *cookie;
1819   int err;
1820   int fd;
1821
1822   stream = NULL;
1823   cookie = NULL;
1824   create_called = 0;
1825
1826   err = es_convert_mode (mode, &flags);
1827   if (err)
1828     goto out;
1829   
1830   err = es_func_file_create (&cookie, &fd, path, flags);
1831   if (err)
1832     goto out;
1833
1834   create_called = 1;
1835   err = es_create (&stream, cookie, fd, estream_functions_file);
1836   if (err)
1837     goto out;
1838
1839  out:
1840   
1841   if (err && create_called)
1842     (*estream_functions_file.func_close) (cookie);
1843
1844   return stream;
1845 }
1846
1847
1848 estream_t
1849 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
1850           unsigned int grow,
1851           func_realloc_t func_realloc, func_free_t func_free,
1852           const char *ES__RESTRICT mode)
1853 {
1854   unsigned int flags;
1855   int create_called;
1856   estream_t stream;
1857   void *cookie;
1858   int err;
1859
1860   cookie = 0;
1861   stream = NULL;
1862   create_called = 0;
1863   
1864   err = es_convert_mode (mode, &flags);
1865   if (err)
1866     goto out;
1867
1868   err = es_func_mem_create (&cookie, data, data_n, data_len,
1869                             BUFFER_BLOCK_SIZE, grow, 0, 0,
1870                             NULL, 0, func_realloc, func_free, flags);
1871   if (err)
1872     goto out;
1873   
1874   create_called = 1;
1875   err = es_create (&stream, cookie, -1, estream_functions_mem);
1876
1877  out:
1878
1879   if (err && create_called)
1880     (*estream_functions_mem.func_close) (cookie);
1881
1882   return stream;
1883 }
1884
1885
1886 estream_t
1887 es_open_memstream (char **ptr, size_t *size)
1888 {
1889   unsigned int flags;
1890   int create_called;
1891   estream_t stream;
1892   void *cookie;
1893   int err;
1894
1895   flags = O_RDWR;
1896   create_called = 0;
1897   stream = NULL;
1898   cookie = 0;
1899   
1900   err = es_func_mem_create (&cookie, NULL, 0, 0,
1901                             BUFFER_BLOCK_SIZE, 1, 1, 1,
1902                             ptr, size, MEM_REALLOC, MEM_FREE, flags);
1903   if (err)
1904     goto out;
1905   
1906   create_called = 1;
1907   err = es_create (&stream, cookie, -1, estream_functions_mem);
1908
1909  out:
1910
1911   if (err && create_called)
1912     (*estream_functions_mem.func_close) (cookie);
1913
1914   return stream;
1915 }
1916
1917
1918 estream_t
1919 es_fopencookie (void *ES__RESTRICT cookie,
1920                 const char *ES__RESTRICT mode,
1921                 es_cookie_io_functions_t functions)
1922 {
1923   unsigned int flags;
1924   estream_t stream;
1925   int err;
1926
1927   stream = NULL;
1928   flags = 0;
1929   
1930   err = es_convert_mode (mode, &flags);
1931   if (err)
1932     goto out;
1933
1934   err = es_create (&stream, cookie, -1, functions);
1935   if (err)
1936     goto out;
1937
1938  out:
1939
1940   return stream;
1941 }
1942
1943
1944 estream_t
1945 es_fdopen (int filedes, const char *mode)
1946 {
1947   unsigned int flags;
1948   int create_called;
1949   estream_t stream;
1950   void *cookie;
1951   int err;
1952
1953   stream = NULL;
1954   cookie = NULL;
1955   create_called = 0;
1956
1957   err = es_convert_mode (mode, &flags);
1958   if (err)
1959     goto out;
1960
1961   err = es_func_fd_create (&cookie, filedes, flags);
1962   if (err)
1963     goto out;
1964
1965   create_called = 1;
1966   err = es_create (&stream, cookie, filedes, estream_functions_fd);
1967
1968  out:
1969
1970   if (err && create_called)
1971     (*estream_functions_fd.func_close) (cookie);
1972
1973   return stream;
1974 }
1975   
1976
1977 estream_t
1978 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
1979             estream_t ES__RESTRICT stream)
1980 {
1981   int err;
1982
1983   if (path)
1984     {
1985       unsigned int flags;
1986       int create_called;
1987       void *cookie;
1988       int fd;
1989
1990       cookie = NULL;
1991       create_called = 0;
1992       
1993       ESTREAM_LOCK (stream);
1994
1995       es_deinitialize (stream);
1996
1997       err = es_convert_mode (mode, &flags);
1998       if (err)
1999         goto leave;
2000       
2001       err = es_func_file_create (&cookie, &fd, path, flags);
2002       if (err)
2003         goto leave;
2004
2005       create_called = 1;
2006       es_initialize (stream, cookie, fd, estream_functions_file);
2007
2008     leave:
2009
2010       if (err)
2011         {
2012           if (create_called)
2013             es_func_fd_destroy (cookie);
2014       
2015           es_destroy (stream);
2016           stream = NULL;
2017         }
2018       else
2019         ESTREAM_UNLOCK (stream);
2020     }
2021   else
2022     {
2023       /* FIXME?  We don't support re-opening at the moment.  */
2024       errno = EINVAL;
2025       es_deinitialize (stream);
2026       es_destroy (stream);
2027       stream = NULL;
2028     }
2029
2030   return stream;
2031 }
2032
2033
2034 int
2035 es_fclose (estream_t stream)
2036 {
2037   int err;
2038
2039   err = es_destroy (stream);
2040
2041   return err;
2042 }
2043
2044 int
2045 es_fileno_unlocked (estream_t stream)
2046 {
2047   return es_get_fd (stream);
2048 }
2049
2050
2051 void
2052 es_flockfile (estream_t stream)
2053 {
2054   ESTREAM_LOCK (stream);
2055 }
2056
2057
2058 int
2059 es_ftrylockfile (estream_t stream)
2060 {
2061   return ESTREAM_TRYLOCK (stream);
2062 }
2063
2064
2065 void
2066 es_funlockfile (estream_t stream)
2067 {
2068   ESTREAM_UNLOCK (stream);
2069 }
2070
2071
2072 int
2073 es_fileno (estream_t stream)
2074 {
2075   int ret;
2076
2077   ESTREAM_LOCK (stream);
2078   ret = es_fileno_unlocked (stream);
2079   ESTREAM_UNLOCK (stream);
2080
2081   return ret;
2082 }
2083
2084
2085 int
2086 es_feof_unlocked (estream_t stream)
2087 {
2088   return es_get_indicator (stream, 0, 1);
2089 }
2090
2091
2092 int
2093 es_feof (estream_t stream)
2094 {
2095   int ret;
2096
2097   ESTREAM_LOCK (stream);
2098   ret = es_feof_unlocked (stream);
2099   ESTREAM_UNLOCK (stream);
2100
2101   return ret;
2102 }
2103
2104
2105 int
2106 es_ferror_unlocked (estream_t stream)
2107 {
2108   return es_get_indicator (stream, 1, 0);
2109 }
2110
2111
2112 int
2113 es_ferror (estream_t stream)
2114 {
2115   int ret;
2116
2117   ESTREAM_LOCK (stream);
2118   ret = es_ferror_unlocked (stream);
2119   ESTREAM_UNLOCK (stream);
2120
2121   return ret;
2122 }
2123
2124
2125 void
2126 es_clearerr_unlocked (estream_t stream)
2127 {
2128   es_set_indicators (stream, 0, 0);
2129 }
2130
2131
2132 void
2133 es_clearerr (estream_t stream)
2134 {
2135   ESTREAM_LOCK (stream);
2136   es_clearerr_unlocked (stream);
2137   ESTREAM_UNLOCK (stream);
2138 }
2139
2140
2141 int
2142 es_fflush (estream_t stream)
2143 {
2144   int err;
2145   
2146   if (stream)
2147     {
2148       ESTREAM_LOCK (stream);
2149       if (stream->flags & ES_FLAG_WRITING)
2150         err = es_flush (stream);
2151       else
2152         {
2153           es_empty (stream);
2154           err = 0;
2155         }
2156       ESTREAM_UNLOCK (stream);
2157     }
2158   else
2159     err = es_list_iterate (es_fflush);
2160
2161   return err ? EOF : 0;
2162 }
2163
2164
2165 int
2166 es_fseek (estream_t stream, long int offset, int whence)
2167 {
2168   int err;
2169
2170   ESTREAM_LOCK (stream);
2171   err = es_seek (stream, offset, whence, NULL);
2172   ESTREAM_UNLOCK (stream);
2173
2174   return err;
2175 }
2176
2177
2178 int
2179 es_fseeko (estream_t stream, off_t offset, int whence)
2180 {
2181   int err;
2182   
2183   ESTREAM_LOCK (stream);
2184   err = es_seek (stream, offset, whence, NULL);
2185   ESTREAM_UNLOCK (stream);
2186
2187   return err;
2188 }
2189
2190
2191 long int
2192 es_ftell (estream_t stream)
2193 {
2194   long int ret;
2195   
2196   ESTREAM_LOCK (stream);
2197   ret = es_offset_calculate (stream);
2198   ESTREAM_UNLOCK (stream);
2199
2200   return ret;
2201 }
2202
2203
2204 off_t
2205 es_ftello (estream_t stream)
2206 {
2207   off_t ret = -1;
2208
2209   ESTREAM_LOCK (stream);
2210   ret = es_offset_calculate (stream);
2211   ESTREAM_UNLOCK (stream);
2212
2213   return ret;
2214 }
2215
2216
2217 void
2218 es_rewind (estream_t stream)
2219 {
2220   ESTREAM_LOCK (stream);
2221   es_seek (stream, 0L, SEEK_SET, NULL);
2222   es_set_indicators (stream, 0, -1);
2223   ESTREAM_UNLOCK (stream);
2224 }
2225
2226
2227 int
2228 _es_getc_underflow (estream_t stream)
2229 {
2230   int err;
2231   unsigned char c;
2232   size_t bytes_read;
2233
2234   err = es_readn (stream, &c, 1, &bytes_read);
2235
2236   return (err || (! bytes_read)) ? EOF : c;
2237 }
2238
2239
2240 int
2241 _es_putc_overflow (int c, estream_t stream)
2242 {
2243   unsigned char d = c;
2244   int err;
2245
2246   err = es_writen (stream, &d, 1, NULL);
2247
2248   return err ? EOF : c;
2249 }
2250
2251
2252 int
2253 es_fgetc (estream_t stream)
2254 {
2255   int ret;
2256   
2257   ESTREAM_LOCK (stream);
2258   ret = es_getc_unlocked (stream);
2259   ESTREAM_UNLOCK (stream);
2260
2261   return ret;
2262 }
2263
2264
2265 int
2266 es_fputc (int c, estream_t stream)
2267 {
2268   int ret;
2269   
2270   ESTREAM_LOCK (stream);
2271   ret = es_putc_unlocked (c, stream);
2272   ESTREAM_UNLOCK (stream);
2273
2274   return ret;
2275 }
2276
2277
2278 int
2279 es_ungetc (int c, estream_t stream)
2280 {
2281   unsigned char data = (unsigned char) c;
2282   size_t data_unread;
2283
2284   ESTREAM_LOCK (stream);
2285   es_unreadn (stream, &data, 1, &data_unread);
2286   ESTREAM_UNLOCK (stream);
2287
2288   return data_unread ? c : EOF;
2289 }
2290
2291
2292 int
2293 es_read (estream_t ES__RESTRICT stream,
2294          void *ES__RESTRICT buffer, size_t bytes_to_read,
2295          size_t *ES__RESTRICT bytes_read)
2296 {
2297   int err;
2298
2299   if (bytes_to_read)
2300     {
2301       ESTREAM_LOCK (stream);
2302       err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2303       ESTREAM_UNLOCK (stream);
2304     }
2305   else
2306     err = 0;
2307
2308   return err;
2309 }
2310
2311
2312 int
2313 es_write (estream_t ES__RESTRICT stream,
2314           const void *ES__RESTRICT buffer, size_t bytes_to_write,
2315           size_t *ES__RESTRICT bytes_written)
2316 {
2317   int err;
2318
2319   if (bytes_to_write)
2320     {
2321       ESTREAM_LOCK (stream);
2322       err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2323       ESTREAM_UNLOCK (stream);
2324     }
2325   else
2326     err = 0;
2327
2328   return err;
2329 }
2330
2331
2332 size_t
2333 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2334           estream_t ES__RESTRICT stream)
2335 {
2336   size_t ret, bytes;
2337   int err;
2338
2339   if (size * nitems)
2340     {
2341       ESTREAM_LOCK (stream);
2342       err = es_readn (stream, ptr, size * nitems, &bytes);
2343       ESTREAM_UNLOCK (stream);
2344
2345       ret = bytes / size;
2346     }
2347   else
2348     ret = 0;
2349
2350   return ret;
2351 }
2352
2353
2354 size_t
2355 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2356            estream_t ES__RESTRICT stream)
2357 {
2358   size_t ret, bytes;
2359   int err;
2360
2361   if (size * nitems)
2362     {
2363       ESTREAM_LOCK (stream);
2364       err = es_writen (stream, ptr, size * nitems, &bytes);
2365       ESTREAM_UNLOCK (stream);
2366
2367       ret = bytes / size;
2368     }
2369   else
2370     ret = 0;
2371
2372   return ret;
2373 }
2374
2375
2376 char *
2377 es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream)
2378 {
2379   char *ret = NULL;
2380   
2381   if (n)
2382     {
2383       int err;
2384       
2385       ESTREAM_LOCK (stream);
2386       err = es_read_line (stream, n, &s, NULL);
2387       ESTREAM_UNLOCK (stream);
2388       if (! err)
2389         ret = s;
2390     }
2391   
2392   return ret;
2393 }
2394
2395
2396 int
2397 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2398 {
2399   size_t length;
2400   int err;
2401
2402   length = strlen (s);
2403   ESTREAM_LOCK (stream);
2404   err = es_writen (stream, s, length, NULL);
2405   ESTREAM_UNLOCK (stream);
2406
2407   return err ? EOF : 0;
2408 }
2409
2410
2411 ssize_t
2412 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2413             estream_t ES__RESTRICT stream)
2414 {
2415   char *line = NULL;
2416   size_t line_n = 0;
2417   int err;
2418
2419   ESTREAM_LOCK (stream);
2420   err = es_read_line (stream, 0, &line, &line_n);
2421   ESTREAM_UNLOCK (stream);
2422   if (err)
2423     goto out;
2424
2425   if (*n)
2426     {
2427       /* Caller wants us to use his buffer.  */
2428       
2429       if (*n < (line_n + 1))
2430         {
2431           /* Provided buffer is too small -> resize.  */
2432
2433           void *p;
2434
2435           p = MEM_REALLOC (*lineptr, line_n + 1);
2436           if (! p)
2437             err = -1;
2438           else
2439             {
2440               if (*lineptr != p)
2441                 *lineptr = p;
2442             }
2443         }
2444
2445       if (! err)
2446         {
2447           memcpy (*lineptr, line, line_n + 1);
2448           if (*n != line_n)
2449             *n = line_n;
2450         }
2451       MEM_FREE (line);
2452     }
2453   else
2454     {
2455       /* Caller wants new buffers.  */
2456       *lineptr = line;
2457       *n = line_n;
2458     }
2459
2460  out:
2461
2462   return err ? err : line_n;
2463 }
2464
2465
2466 int
2467 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2468              va_list ap)
2469 {
2470   int ret;
2471   
2472   ESTREAM_LOCK (stream);
2473   ret = es_print (stream, format, ap);
2474   ESTREAM_UNLOCK (stream);
2475
2476   return ret;
2477 }
2478
2479
2480 int
2481 es_fprintf (estream_t ES__RESTRICT stream,
2482             const char *ES__RESTRICT format, ...)
2483 {
2484   int ret;
2485   
2486   va_list ap;
2487   va_start (ap, format);
2488   ESTREAM_LOCK (stream);
2489   ret = es_print (stream, format, ap);
2490   ESTREAM_UNLOCK (stream);
2491   va_end (ap);
2492
2493   return ret;
2494 }
2495
2496 static int
2497 tmpfd (void)
2498 {
2499   FILE *fp;
2500   int fp_fd;
2501   int fd;
2502
2503   fp = NULL;
2504   fd = -1;
2505   
2506   fp = tmpfile ();
2507   if (! fp)
2508     goto out;
2509
2510   fp_fd = fileno (fp);
2511   fd = dup (fp_fd);
2512
2513  out:
2514
2515   if (fp)
2516     fclose (fp);
2517
2518   return fd;
2519 }
2520
2521 estream_t
2522 es_tmpfile (void)
2523 {
2524   unsigned int flags;
2525   int create_called;
2526   estream_t stream;
2527   void *cookie;
2528   int err;
2529   int fd;
2530
2531   create_called = 0;
2532   stream = NULL;
2533   flags = O_RDWR | O_TRUNC | O_CREAT;
2534   cookie = NULL;
2535   
2536   fd = tmpfd ();
2537   if (fd == -1)
2538     {
2539       err = -1;
2540       goto out;
2541     }
2542
2543   err = es_func_fd_create (&cookie, fd, flags);
2544   if (err)
2545     goto out;
2546
2547   create_called = 1;
2548   err = es_create (&stream, cookie, fd, estream_functions_fd);
2549
2550  out:
2551
2552   if (err)
2553     {
2554       if (create_called)
2555         es_func_fd_destroy (cookie);
2556       else if (fd != -1)
2557         close (fd);
2558       stream = NULL;
2559     }
2560   
2561   return stream;
2562 }
2563
2564
2565 int
2566 es_setvbuf (estream_t ES__RESTRICT stream,
2567             char *ES__RESTRICT buf, int type, size_t size)
2568 {
2569   int err;
2570   
2571   if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
2572       && (! ((! size) && (type != _IONBF))))
2573     {
2574       ESTREAM_LOCK (stream);
2575       err = es_set_buffering (stream, buf, type, size);
2576       ESTREAM_UNLOCK (stream);
2577     }
2578   else
2579     {
2580       errno = EINVAL;
2581       err = -1;
2582     }
2583
2584   return err;
2585 }
2586
2587
2588 void
2589 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
2590 {
2591   ESTREAM_LOCK (stream);
2592   es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
2593   ESTREAM_UNLOCK (stream);
2594 }
2595
2596 void
2597 es_opaque_set (estream_t stream, void *opaque)
2598 {
2599   ESTREAM_LOCK (stream);
2600   es_opaque_ctrl (stream, opaque, NULL);
2601   ESTREAM_UNLOCK (stream);
2602 }
2603
2604
2605 void *
2606 es_opaque_get (estream_t stream)
2607 {
2608   void *opaque;
2609   
2610   ESTREAM_LOCK (stream);
2611   es_opaque_ctrl (stream, NULL, &opaque);
2612   ESTREAM_UNLOCK (stream);
2613
2614   return opaque;
2615 }