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