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