2005-01-26 Moritz Schulte <moritz@g10code.com>
[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 USE_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   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, char *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 char *buffer, size_t size)
375 {
376   estream_cookie_mem_t mem_cookie = cookie;
377   func_realloc_t func_realloc = mem_cookie->func_realloc;
378   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, char *buffer, size_t size)
595
596 {
597   estream_cookie_fd_t file_cookie = cookie;
598   ssize_t bytes_read;
599
600   bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
601
602   return bytes_read;
603 }
604
605 /* Write function for fd objects.  */
606 static ssize_t
607 es_func_fd_write (void *cookie, const char *buffer, size_t size)
608                            
609 {
610   estream_cookie_fd_t file_cookie = cookie;
611   ssize_t bytes_written;
612
613   bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
614
615   return bytes_written;
616 }
617
618 /* Seek function for fd objects.  */
619 static int
620 es_func_fd_seek (void *cookie, off_t *offset, int whence)
621 {
622   estream_cookie_fd_t file_cookie = cookie;
623   off_t offset_new;
624   int err;
625
626   offset_new = lseek (file_cookie->fd, *offset, whence);
627   if (offset_new == -1)
628     err = -1;
629   else
630     {
631       *offset = offset_new;
632       err = 0;
633     }
634
635   return err;
636 }
637
638 /* Destroy function for fd objects.  */
639 static int
640 es_func_fd_destroy (void *cookie)
641 {
642   estream_cookie_fd_t fd_cookie = cookie;
643   int err;
644
645   if (fd_cookie)
646     {
647       err = close (fd_cookie->fd);
648       MEM_FREE (fd_cookie);
649     }
650   else
651     err = 0;
652
653   return err;
654 }
655
656 static es_cookie_io_functions_t estream_functions_fd =
657   {
658     es_func_fd_read,
659     es_func_fd_write,
660     es_func_fd_seek,
661     es_func_fd_destroy
662   };
663
664 /* Implementation of file I/O.  */
665
666 /* Create function for file objects.  */
667 static int
668 es_func_file_create (void **cookie, int *filedes,
669                      const char *path, unsigned int flags)
670 {
671   estream_cookie_fd_t file_cookie;
672   int err;
673   int fd;
674
675   err = 0;
676   fd = -1;
677
678   file_cookie = MEM_ALLOC (sizeof (*file_cookie));
679   if (! file_cookie)
680     {
681       err = -1;
682       goto out;
683     }
684
685   fd = open (path, flags, ES_DEFAULT_OPEN_MODE);
686   if (fd == -1)
687     {
688       err = -1;
689       goto out;
690     }
691
692   file_cookie->fd = fd;
693   *cookie = file_cookie;
694   *filedes = fd;
695
696  out:
697
698   if (err)
699     MEM_FREE (file_cookie);
700
701   return err;
702 }
703
704 static es_cookie_io_functions_t estream_functions_file =
705   {
706     es_func_fd_read,
707     es_func_fd_write,
708     es_func_fd_seek,
709     es_func_fd_destroy
710   };
711
712 \f
713
714 /* Stream primitives.  */
715
716 static int
717 es_convert_mode (const char *mode, unsigned int *flags)
718 {
719   struct
720   {
721     const char *mode;
722     unsigned int flags;
723   } mode_flags[] = { { "r",
724                        O_RDONLY },
725                      { "rb",
726                        O_RDONLY },
727                      { "w",
728                        O_WRONLY | O_TRUNC | O_CREAT },
729                      { "wb",
730                        O_WRONLY | O_TRUNC | O_CREAT },
731                      { "a",
732                        O_WRONLY | O_APPEND | O_CREAT },
733                      { "ab",
734                        O_WRONLY | O_APPEND | O_CREAT },
735                      { "r+",
736                        O_RDWR },
737                      { "rb+",
738                        O_RDWR },
739                      { "r+b",
740                        O_RDONLY | O_WRONLY },
741                      { "w+",
742                        O_RDWR | O_TRUNC | O_CREAT },
743                      { "wb+",
744                        O_RDWR | O_TRUNC | O_CREAT },
745                      { "w+b",
746                        O_RDWR | O_TRUNC | O_CREAT },
747                      { "a+",
748                        O_RDWR | O_CREAT | O_APPEND },
749                      { "ab+",
750                        O_RDWR | O_CREAT | O_APPEND },
751                      { "a+b",
752                        O_RDWR | O_CREAT | O_APPEND } };
753   unsigned int i;
754   int err; 
755
756   for (i = 0; i < DIM (mode_flags); i++)
757     if (! strcmp (mode_flags[i].mode, mode))
758       break;
759   if (i == DIM (mode_flags))
760     {
761       errno = EINVAL;
762       err = -1;
763     }
764   else
765     {
766       err = 0;
767       *flags = mode_flags[i].flags;
768     }
769
770   return err;
771 }
772
773 \f
774
775 /*
776  * Low level stream functionality.
777  */
778
779 static int
780 es_fill (estream_t stream)
781 {
782   size_t bytes_read = 0;
783   int err;
784
785   if (!stream->intern->func_read)
786     {
787       errno = EOPNOTSUPP;
788       err = -1;
789     }
790   else
791     {
792       es_cookie_read_function_t func_read = stream->intern->func_read;
793       ssize_t ret;
794
795       ret = (*func_read) (stream->intern->cookie,
796                           stream->buffer, stream->buffer_size);
797       if (ret == -1)
798         {
799           bytes_read = 0;
800           err = -1;
801         }
802       else
803         {
804           bytes_read = ret;
805           err = 0;
806         }
807     }
808
809   if (err)
810     stream->intern->indicators.err = 1;
811   else if (!bytes_read)
812     stream->intern->indicators.eof = 1;
813
814   stream->intern->offset += stream->data_len;
815   stream->data_len = bytes_read;
816   stream->data_offset = 0;
817
818   return err;
819 }
820
821 static int
822 es_flush (estream_t stream)
823 {
824   es_cookie_write_function_t func_write = stream->intern->func_write;
825   int err;
826
827   assert (stream->flags & ES_FLAG_WRITING);
828
829   if (stream->data_offset)
830     {
831       size_t bytes_written;
832       size_t data_flushed;
833       ssize_t ret;
834
835       if (! func_write)
836         {
837           err = EOPNOTSUPP;
838           goto out;
839         }
840
841       /* Note: to prevent an endless loop caused by user-provided
842          write-functions that pretend to have written more bytes than
843          they were asked to write, we have to check for
844          "(stream->data_offset - data_flushed) > 0" instead of
845          "stream->data_offset - data_flushed".  */
846       
847       data_flushed = 0;
848       err = 0;
849       
850       while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
851         {
852           ret = (*func_write) (stream->intern->cookie,
853                                stream->buffer + data_flushed,
854                                stream->data_offset - data_flushed);
855           if (ret == -1)
856             {
857               bytes_written = 0;
858               err = -1;
859             }
860           else
861             bytes_written = ret;
862
863           data_flushed += bytes_written;
864           if (err)
865             break;
866         }
867
868       stream->data_flushed += data_flushed;
869       if (stream->data_offset == data_flushed)
870         {
871           stream->intern->offset += stream->data_offset;
872           stream->data_offset = 0;
873           stream->data_flushed = 0;
874
875           /* Propagate flush event.  */
876           (*func_write) (stream->intern->cookie, NULL, 0);
877         }
878     }
879   else
880     err = 0;
881
882  out:
883     
884   if (err)
885     stream->intern->indicators.err = 1;
886
887   return err;
888 }
889
890 /* Discard buffered data for STREAM.  */
891 static void
892 es_empty (estream_t stream)
893 {
894   assert (! (stream->flags & ES_FLAG_WRITING));
895   stream->data_len = 0;
896   stream->data_offset = 0;
897   stream->unread_data_len = 0;
898 }
899
900 /* Initialize STREAM.  */
901 static void
902 es_initialize (estream_t stream,
903                void *cookie, int fd, es_cookie_io_functions_t functions)
904 {
905   stream->intern->cookie = cookie;
906   stream->intern->opaque = NULL;
907   stream->intern->offset = 0;
908   stream->intern->func_read = functions.func_read;
909   stream->intern->func_write = functions.func_write;
910   stream->intern->func_seek = functions.func_seek;
911   stream->intern->func_close = functions.func_close;
912   stream->intern->strategy = _IOFBF;
913   stream->intern->fd = fd;
914   stream->intern->indicators.err = 0;
915   stream->intern->indicators.eof = 0;
916   stream->intern->deallocate_buffer = 0;
917
918   stream->data_len = 0;
919   stream->data_offset = 0;
920   stream->data_flushed = 0;
921   stream->unread_data_len = 0;
922   stream->flags = 0;
923 }
924
925 /* Deinitialize STREAM.  */
926 static int
927 es_deinitialize (estream_t stream)
928 {
929   es_cookie_close_function_t func_close;
930   int err, tmp_err;
931
932   func_close = stream->intern->func_close;
933
934   err = 0;
935   if (stream->flags & ES_FLAG_WRITING)
936     SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
937   if (func_close)
938     SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
939   
940   return err;
941 }
942
943 /* Create a new stream object, initialize it.  */
944 static int
945 es_create (estream_t *stream, void *cookie, int fd,
946            es_cookie_io_functions_t functions)
947 {
948   estream_internal_t stream_internal_new;
949   estream_t stream_new;
950   int err;
951
952   stream_new = NULL;
953   stream_internal_new = NULL;
954
955   stream_new = MEM_ALLOC (sizeof (*stream_new));
956   if (! stream_new)
957     {
958       err = -1;
959       goto out;
960     }
961
962   stream_internal_new = MEM_ALLOC (sizeof (*stream_internal_new));
963   if (! stream_internal_new)
964     {
965       err = -1;
966       goto out;
967     }
968
969   stream_new->buffer = stream_internal_new->buffer;
970   stream_new->buffer_size = sizeof (stream_internal_new->buffer);
971   stream_new->unread_buffer = stream_internal_new->unread_buffer;
972   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
973   stream_new->intern = stream_internal_new;
974
975   ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
976   es_initialize (stream_new, cookie, fd, functions);
977
978   err = es_list_add (stream_new);
979   if (err)
980     goto out;
981
982   *stream = stream_new;
983
984  out:
985
986   if (err)
987     {
988       if (stream_new)
989         {
990           es_deinitialize (stream_new);
991           MEM_FREE (stream_new);
992         }
993     }
994
995   return err;
996 }
997
998 /* Deinitialize a stream object and destroy it.  */
999 static int
1000 es_destroy (estream_t stream)
1001 {
1002   int err = 0;
1003
1004   if (stream)
1005     {
1006       es_list_remove (stream);
1007       err = es_deinitialize (stream);
1008       MEM_FREE (stream->intern);
1009       MEM_FREE (stream);
1010     }
1011
1012   return err;
1013 }
1014
1015 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1016    unbuffered-mode, storing the amount of bytes read in
1017    *BYTES_READ.  */
1018 static int
1019 es_read_nbf (estream_t ES__RESTRICT stream,
1020              unsigned char *ES__RESTRICT buffer,
1021              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1022 {
1023   es_cookie_read_function_t func_read = stream->intern->func_read;
1024   size_t data_read;
1025   ssize_t ret;
1026   int err;
1027
1028   data_read = 0;
1029   err = 0;
1030
1031   while (bytes_to_read - data_read)
1032     {
1033       ret = (*func_read) (stream->intern->cookie,
1034                           buffer + data_read, bytes_to_read - data_read);
1035       if (ret == -1)
1036         {
1037           err = -1;
1038           break;
1039         }
1040       else if (ret)
1041         data_read += ret;
1042       else
1043         break;
1044     }
1045
1046   stream->intern->offset += data_read;
1047   *bytes_read = data_read;
1048
1049   return err;
1050 }
1051
1052 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1053    fully-buffered-mode, storing the amount of bytes read in
1054    *BYTES_READ.  */
1055 static int
1056 es_read_fbf (estream_t ES__RESTRICT stream,
1057              unsigned char *ES__RESTRICT buffer,
1058              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1059 {
1060   size_t data_available;
1061   size_t data_to_read;
1062   size_t data_read;
1063   int err;
1064
1065   data_read = 0;
1066   err = 0;
1067
1068   while ((bytes_to_read - data_read) && (! err))
1069     {
1070       if (stream->data_offset == stream->data_len)
1071         {
1072           /* Nothing more to read in current container, try to
1073              fill container with new data.  */
1074           err = es_fill (stream);
1075           if (! err)
1076             if (! stream->data_len)
1077               /* Filling did not result in any data read.  */
1078               break;
1079         }
1080
1081       if (! err)
1082         {
1083           /* Filling resulted in some new data.  */
1084
1085           data_to_read = bytes_to_read - data_read;
1086           data_available = stream->data_len - stream->data_offset;
1087           if (data_to_read > data_available)
1088             data_to_read = data_available;
1089
1090           memcpy (buffer + data_read,
1091                   stream->buffer + stream->data_offset, data_to_read);
1092           stream->data_offset += data_to_read;
1093           data_read += data_to_read;
1094         }
1095     }
1096
1097   *bytes_read = data_read;
1098
1099   return err;
1100 }
1101
1102 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1103    line-buffered-mode, storing the amount of bytes read in
1104    *BYTES_READ.  */
1105 static int
1106 es_read_lbf (estream_t ES__RESTRICT stream,
1107              unsigned char *ES__RESTRICT buffer,
1108              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1109 {
1110   int err;
1111
1112   err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1113
1114   return err;
1115 }
1116
1117 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1118    *the amount of bytes read in BYTES_READ.  */
1119 static int
1120 es_readn (estream_t ES__RESTRICT stream,
1121           unsigned char *ES__RESTRICT buffer,
1122           size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1123 {
1124   size_t data_read_unread, data_read;
1125   int err;
1126
1127   data_read_unread = 0;
1128   data_read = 0;
1129   err = 0;
1130
1131   if (stream->flags & ES_FLAG_WRITING)
1132     {
1133       /* Switching to reading mode -> flush output.  */
1134       err = es_flush (stream);
1135       if (err)
1136         goto out;
1137       stream->flags &= ~ES_FLAG_WRITING;
1138     }  
1139
1140   /* Read unread data first.  */
1141   while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1142     {
1143       buffer[data_read_unread]
1144         = stream->unread_buffer[stream->unread_data_len - 1];
1145       stream->unread_data_len--;
1146       data_read_unread++;
1147     }
1148
1149   switch (stream->intern->strategy)
1150     {
1151     case _IONBF:
1152       err = es_read_nbf (stream,
1153                          buffer + data_read_unread,
1154                          bytes_to_read - data_read_unread, &data_read);
1155       break;
1156     case _IOLBF:
1157       err = es_read_lbf (stream,
1158                          buffer + data_read_unread,
1159                          bytes_to_read - data_read_unread, &data_read);
1160       break;
1161     case _IOFBF:
1162       err = es_read_fbf (stream,
1163                          buffer + data_read_unread,
1164                          bytes_to_read - data_read_unread, &data_read);
1165       break;
1166     }
1167
1168  out:
1169
1170   if (bytes_read)
1171     *bytes_read = data_read_unread + data_read;
1172
1173   return err;
1174 }
1175
1176 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1177    amount of bytes succesfully unread in *BYTES_UNREAD.  */
1178 static void
1179 es_unreadn (estream_t ES__RESTRICT stream,
1180             const unsigned char *ES__RESTRICT data, size_t data_n,
1181             size_t *ES__RESTRICT bytes_unread)
1182 {
1183   size_t space_left;
1184
1185   space_left = stream->unread_buffer_size - stream->unread_data_len;
1186
1187   if (data_n > space_left)
1188     data_n = space_left;
1189
1190   if (! data_n)
1191     goto out;
1192
1193   memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1194   stream->unread_data_len += data_n;
1195   stream->intern->indicators.eof = 0;
1196
1197  out:
1198
1199   if (bytes_unread)
1200     *bytes_unread = data_n;
1201 }
1202
1203 /* Seek in STREAM.  */
1204 static int
1205 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1206          off_t *ES__RESTRICT offset_new)
1207 {
1208   es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1209   int err, ret;
1210   off_t off;
1211
1212   if (! func_seek)
1213     {
1214       errno = EOPNOTSUPP;
1215       err = -1;
1216       goto out;
1217     }
1218
1219   if (stream->flags & ES_FLAG_WRITING)
1220     {
1221       /* Flush data first in order to prevent flushing it to the wrong
1222          offset.  */
1223       err = es_flush (stream);
1224       if (err)
1225         goto out;
1226       stream->flags &= ~ES_FLAG_WRITING;
1227     }
1228
1229   off = offset;
1230   if (whence == SEEK_CUR)
1231     {
1232       off = off - stream->data_len + stream->data_offset;
1233       off -= stream->unread_data_len;
1234     }
1235   
1236   ret = (*func_seek) (stream->intern->cookie, &off, whence);
1237   if (ret == -1)
1238     {
1239       err = -1;
1240       goto out;
1241     }
1242
1243   err = 0;
1244   es_empty (stream);
1245
1246   if (offset_new)
1247     *offset_new = off;
1248
1249   stream->intern->indicators.eof = 0;
1250   stream->intern->offset = off;
1251
1252  out:
1253   
1254   if (err)
1255     stream->intern->indicators.err = 1;
1256
1257   return err;
1258 }
1259
1260 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1261    unbuffered-mode, storing the amount of bytes written in
1262    *BYTES_WRITTEN.  */
1263 static int
1264 es_write_nbf (estream_t ES__RESTRICT stream,
1265               const unsigned char *ES__RESTRICT buffer,
1266               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1267 {
1268   es_cookie_write_function_t func_write = stream->intern->func_write;
1269   size_t data_written;
1270   ssize_t ret;
1271   int err;
1272
1273   if (bytes_to_write && (! func_write))
1274     {
1275       err = EOPNOTSUPP;
1276       goto out;
1277     }  
1278
1279   data_written = 0;
1280   err = 0;
1281   
1282   while (bytes_to_write - data_written)
1283     {
1284       ret = (*func_write) (stream->intern->cookie,
1285                            buffer + data_written,
1286                            bytes_to_write - data_written);
1287       if (ret == -1)
1288         {
1289           err = -1;
1290           break;
1291         }
1292       else
1293         data_written += ret;
1294     }
1295
1296   stream->intern->offset += data_written;
1297   *bytes_written = data_written;
1298
1299  out:
1300
1301   return err;
1302 }
1303
1304 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1305    fully-buffered-mode, storing the amount of bytes written in
1306    *BYTES_WRITTEN.  */
1307 static int
1308 es_write_fbf (estream_t ES__RESTRICT stream,
1309               const unsigned char *ES__RESTRICT buffer,
1310               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1311 {
1312   size_t space_available;
1313   size_t data_to_write;
1314   size_t data_written;
1315   int err;
1316
1317   data_written = 0;
1318   err = 0;
1319
1320   while ((bytes_to_write - data_written) && (! err))
1321     {
1322       if (stream->data_offset == stream->buffer_size)
1323         /* Container full, flush buffer.  */
1324         err = es_flush (stream);
1325
1326       if (! err)
1327         {
1328           /* Flushing resulted in empty container.  */
1329           
1330           data_to_write = bytes_to_write - data_written;
1331           space_available = stream->buffer_size - stream->data_offset;
1332           if (data_to_write > space_available)
1333             data_to_write = space_available;
1334               
1335           memcpy (stream->buffer + stream->data_offset,
1336                   buffer + data_written, data_to_write);
1337           stream->data_offset += data_to_write;
1338           data_written += data_to_write;
1339         }
1340     }
1341
1342   *bytes_written = data_written;
1343
1344   return err;
1345 }
1346
1347
1348 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1349    line-buffered-mode, storing the amount of bytes written in
1350    *BYTES_WRITTEN.  */
1351 static int
1352 es_write_lbf (estream_t ES__RESTRICT stream,
1353               const unsigned char *ES__RESTRICT buffer,
1354               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1355 {
1356   size_t data_flushed = 0;
1357   size_t data_buffered = 0;
1358   unsigned char *nlp;
1359   int err = 0;
1360
1361   nlp = memrchr (buffer, '\n', bytes_to_write);
1362   if (nlp)
1363     {
1364       /* Found a newline, directly write up to (including) this
1365          character.  */
1366       err = es_flush (stream);
1367       if (!err)
1368         err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1369     }
1370
1371   if (!err)
1372     {
1373       /* Write remaining data fully buffered.  */
1374       err = es_write_fbf (stream, buffer + data_flushed,
1375                           bytes_to_write - data_flushed, &data_buffered);
1376     }
1377
1378   *bytes_written = data_flushed + data_buffered;
1379   return err;
1380 }
1381
1382
1383 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1384    amount of bytes written in BYTES_WRITTEN.  */
1385 static int
1386 es_writen (estream_t ES__RESTRICT stream,
1387            const unsigned char *ES__RESTRICT buffer,
1388            size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1389 {
1390   size_t data_written;
1391   int err;
1392
1393   data_written = 0;
1394   err = 0;
1395   
1396   if (! (stream->flags & ES_FLAG_WRITING))
1397     {
1398       /* Switching to writing mode -> discard input data and seek to
1399          position at which reading has stopped.  */
1400
1401       err = es_seek (stream, 0, SEEK_CUR, NULL);
1402       if (err)
1403         {
1404           if (errno == ESPIPE)
1405             err = 0;
1406           else
1407             goto out;
1408         }
1409     }
1410
1411   switch (stream->intern->strategy)
1412     {
1413     case _IONBF:
1414       err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1415       break;
1416
1417     case _IOLBF:
1418       err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1419       break;
1420
1421     case _IOFBF:
1422       err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1423       break;
1424     }
1425
1426  out:
1427     
1428   if (bytes_written)
1429     *bytes_written = data_written;
1430   if (data_written)
1431     if (! (stream->flags & ES_FLAG_WRITING))
1432       stream->flags |= ES_FLAG_WRITING;
1433
1434   return err;
1435 }
1436
1437
1438 static int
1439 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1440          size_t *ES__RESTRICT data_len)
1441 {
1442   int err;
1443
1444   if (stream->flags & ES_FLAG_WRITING)
1445     {
1446       /* Switching to reading mode -> flush output.  */
1447       err = es_flush (stream);
1448       if (err)
1449         goto out;
1450       stream->flags &= ~ES_FLAG_WRITING;
1451     }  
1452
1453   if (stream->data_offset == stream->data_len)
1454     {
1455       /* Refill container.  */
1456       err = es_fill (stream);
1457       if (err)
1458         goto out;
1459     }
1460   
1461   if (data)
1462     *data = stream->buffer + stream->data_offset;
1463   if (data_len)
1464     *data_len = stream->data_len - stream->data_offset;
1465   err = 0;
1466
1467  out:
1468
1469   return err;
1470 }
1471
1472
1473 /* Skip SIZE bytes of input data contained in buffer.  */
1474 static int
1475 es_skip (estream_t stream, size_t size)
1476 {
1477   int err;
1478
1479   if (stream->data_offset + size > stream->data_len)
1480     {
1481       errno = EINVAL;
1482       err = -1;
1483     }
1484   else
1485     {
1486       stream->data_offset += size;
1487       err = 0;
1488     }
1489
1490   return err;
1491 }
1492
1493
1494 static int
1495 es_read_line (estream_t ES__RESTRICT stream, size_t max_length,
1496               char *ES__RESTRICT *ES__RESTRICT line,
1497               size_t *ES__RESTRICT line_length)
1498 {
1499   size_t space_left;
1500   size_t line_size;
1501   estream_t line_stream;
1502   char *line_new;
1503   void *line_stream_cookie;
1504   char *newline;
1505   unsigned char *data;
1506   size_t data_len;
1507   int err;
1508
1509   line_new = NULL;
1510   line_stream = NULL;
1511   line_stream_cookie = NULL;
1512
1513   err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0, BUFFER_BLOCK_SIZE,
1514                             1, 0, 0, NULL, 0, MEM_REALLOC, MEM_FREE, O_RDWR);
1515   if (err)
1516     goto out;
1517
1518   err = es_create (&line_stream, line_stream_cookie, -1,
1519                    estream_functions_mem);
1520   if (err)
1521     goto out;
1522
1523   space_left = max_length;
1524   line_size = 0;
1525   while (1)
1526     {
1527       if (max_length && (space_left == 1))
1528         break;
1529
1530       err = es_peek (stream, &data, &data_len);
1531       if (err || (! data_len))
1532         break;
1533
1534       if (data_len > (space_left - 1))
1535         data_len = space_left - 1;
1536
1537       newline = memchr (data, '\n', data_len);
1538       if (newline)
1539         {
1540           data_len = (newline - (char *) data) + 1;
1541           err = es_write (line_stream, data, data_len, NULL);
1542           if (! err)
1543             {
1544               space_left -= data_len;
1545               line_size += data_len;
1546               es_skip (stream, data_len);
1547               break;
1548             }
1549         }
1550       else
1551         {
1552           err = es_write (line_stream, data, data_len, NULL);
1553           if (! err)
1554             {
1555               space_left -= data_len;
1556               line_size += data_len;
1557               es_skip (stream, data_len);
1558             }
1559         }
1560       if (err)
1561         break;
1562     }
1563   if (err)
1564     goto out;
1565
1566   /* Complete line has been written to line_stream.  */
1567   
1568   if ((max_length > 1) && (! line_size))
1569     {
1570       stream->intern->indicators.eof = 1;
1571       goto out;
1572     }
1573
1574   err = es_seek (line_stream, 0, SEEK_SET, NULL);
1575   if (err)
1576     goto out;
1577
1578   if (! *line)
1579     {
1580       line_new = MEM_ALLOC (line_size + 1);
1581       if (! line_new)
1582         {
1583           err = -1;
1584           goto out;
1585         }
1586     }
1587   else
1588     line_new = *line;
1589
1590   err = es_read (line_stream, line_new, line_size, NULL);
1591   if (err)
1592     goto out;
1593
1594   line_new[line_size] = '\0';
1595
1596   if (! *line)
1597     *line = line_new;
1598   if (line_length)
1599     *line_length = line_size;
1600
1601  out:
1602
1603   if (line_stream)
1604     es_destroy (line_stream);
1605   else if (line_stream_cookie)
1606     es_func_mem_destroy (line_stream_cookie);
1607
1608   if (err)
1609     {
1610       if (! *line)
1611         MEM_FREE (line_new);
1612       stream->intern->indicators.err = 1;
1613     }
1614
1615   return err;
1616 }
1617
1618
1619 static int
1620 es_print (estream_t ES__RESTRICT stream,
1621           const char *ES__RESTRICT format, va_list ap)
1622 {
1623   char data[BUFFER_BLOCK_SIZE];
1624   size_t bytes_written;
1625   size_t bytes_read;
1626   FILE *tmp_stream;
1627   int err;
1628
1629   bytes_written = 0;
1630   tmp_stream = NULL;
1631   err = 0;
1632   
1633   tmp_stream = tmpfile ();
1634   if (! tmp_stream)
1635     {
1636       err = errno;
1637       goto out;
1638     }
1639
1640   err = vfprintf (tmp_stream, format, ap);
1641   if (err < 0)
1642     goto out;
1643
1644   err = fseek (tmp_stream, 0, SEEK_SET);
1645   if (err)
1646     goto out;
1647
1648   while (1)
1649     {
1650       bytes_read = fread (data, 1, sizeof (data), tmp_stream);
1651       if (ferror (tmp_stream))
1652         {
1653           err = -1;
1654           break;
1655         }
1656
1657       err = es_writen (stream, data, bytes_read, NULL);
1658       if (err)
1659         break;
1660       else
1661         bytes_written += bytes_read;
1662       if (feof (tmp_stream))
1663         break;
1664     }
1665   if (err)
1666     goto out;
1667
1668  out:
1669
1670   if (tmp_stream)
1671     fclose (tmp_stream);
1672
1673   return err ? -1 : bytes_written;
1674 }
1675
1676
1677 static void
1678 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1679 {
1680   if (ind_err != -1)
1681     stream->intern->indicators.err = ind_err ? 1 : 0;
1682   if (ind_eof != -1)
1683     stream->intern->indicators.eof = ind_eof ? 1 : 0;
1684 }
1685
1686
1687 static int
1688 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1689 {
1690   int ret = 0;
1691   
1692   if (ind_err)
1693     ret = stream->intern->indicators.err;
1694   else if (ind_eof)
1695     ret = stream->intern->indicators.eof;
1696
1697   return ret;
1698 }
1699
1700
1701 static int
1702 es_set_buffering (estream_t ES__RESTRICT stream,
1703                   char *ES__RESTRICT buffer, int mode, size_t size)
1704 {
1705   int err;
1706
1707   /* Flush or empty buffer depending on mode.  */
1708   if (stream->flags & ES_FLAG_WRITING)
1709     {
1710       err = es_flush (stream);
1711       if (err)
1712         goto out;
1713     }
1714   else
1715     es_empty (stream);
1716
1717   es_set_indicators (stream, -1, 0);
1718   
1719   /* Free old buffer in case that was allocated by this function.  */
1720   if (stream->intern->deallocate_buffer)
1721     {
1722       stream->intern->deallocate_buffer = 0;
1723       MEM_FREE (stream->buffer);
1724       stream->buffer = NULL;
1725     }
1726
1727   if (mode == _IONBF)
1728     stream->buffer_size = 0;
1729   else
1730     {
1731       void *buffer_new;
1732       
1733       if (buffer)
1734         buffer_new = buffer;
1735       else
1736         {
1737           buffer_new = MEM_ALLOC (size);
1738           if (! buffer_new)
1739             {
1740               err = -1;
1741               goto out;
1742             }
1743         }
1744
1745       stream->buffer = buffer_new;
1746       stream->buffer_size = size;
1747       if (! buffer)
1748         stream->intern->deallocate_buffer = 1;
1749     }
1750   stream->intern->strategy = mode;
1751   err = 0;
1752
1753  out:
1754
1755   return err;
1756 }
1757
1758
1759 static off_t
1760 es_offset_calculate (estream_t stream)
1761 {
1762   off_t offset;
1763
1764   offset = stream->intern->offset + stream->data_offset;
1765   if (offset < stream->unread_data_len)
1766     /* Offset undefined.  */
1767     offset = 0;
1768   else
1769     offset -= stream->unread_data_len;
1770
1771   return offset;
1772 }
1773
1774
1775 static void
1776 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1777                 void **ES__RESTRICT opaque_old)
1778 {
1779   if (opaque_old)
1780     *opaque_old = stream->intern->opaque;
1781   if (opaque_new)
1782     stream->intern->opaque = opaque_new;
1783 }
1784
1785
1786 static int
1787 es_get_fd (estream_t stream)
1788 {
1789   return stream->intern->fd;
1790 }
1791
1792 \f
1793
1794 /* API.  */
1795
1796 int
1797 es_init (void)
1798 {
1799   int err;
1800
1801   err = es_init_do ();
1802
1803   return err;
1804 }
1805
1806 estream_t
1807 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
1808 {
1809   unsigned int flags;
1810   int create_called;
1811   estream_t stream;
1812   void *cookie;
1813   int err;
1814   int fd;
1815
1816   stream = NULL;
1817   cookie = NULL;
1818   create_called = 0;
1819
1820   err = es_convert_mode (mode, &flags);
1821   if (err)
1822     goto out;
1823   
1824   err = es_func_file_create (&cookie, &fd, path, flags);
1825   if (err)
1826     goto out;
1827
1828   create_called = 1;
1829   err = es_create (&stream, cookie, fd, estream_functions_file);
1830   if (err)
1831     goto out;
1832
1833  out:
1834   
1835   if (err && create_called)
1836     (*estream_functions_file.func_close) (cookie);
1837
1838   return stream;
1839 }
1840
1841
1842 estream_t
1843 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
1844           unsigned int grow,
1845           func_realloc_t func_realloc, func_free_t func_free,
1846           const char *ES__RESTRICT mode)
1847 {
1848   unsigned int flags;
1849   int create_called;
1850   estream_t stream;
1851   void *cookie;
1852   int err;
1853
1854   cookie = 0;
1855   stream = NULL;
1856   create_called = 0;
1857   
1858   err = es_convert_mode (mode, &flags);
1859   if (err)
1860     goto out;
1861
1862   err = es_func_mem_create (&cookie, data, data_n, data_len,
1863                             BUFFER_BLOCK_SIZE, grow, 0, 0,
1864                             NULL, 0, func_realloc, func_free, flags);
1865   if (err)
1866     goto out;
1867   
1868   create_called = 1;
1869   err = es_create (&stream, cookie, -1, estream_functions_mem);
1870
1871  out:
1872
1873   if (err && create_called)
1874     (*estream_functions_mem.func_close) (cookie);
1875
1876   return stream;
1877 }
1878
1879
1880 estream_t
1881 es_open_memstream (char **ptr, size_t *size)
1882 {
1883   unsigned int flags;
1884   int create_called;
1885   estream_t stream;
1886   void *cookie;
1887   int err;
1888
1889   flags = O_RDWR;
1890   create_called = 0;
1891   stream = NULL;
1892   cookie = 0;
1893   
1894   err = es_func_mem_create (&cookie, NULL, 0, 0,
1895                             BUFFER_BLOCK_SIZE, 1, 1, 1,
1896                             ptr, size, MEM_REALLOC, MEM_FREE, flags);
1897   if (err)
1898     goto out;
1899   
1900   create_called = 1;
1901   err = es_create (&stream, cookie, -1, estream_functions_mem);
1902
1903  out:
1904
1905   if (err && create_called)
1906     (*estream_functions_mem.func_close) (cookie);
1907
1908   return stream;
1909 }
1910
1911
1912 estream_t
1913 es_fopencookie (void *ES__RESTRICT cookie,
1914                 const char *ES__RESTRICT mode,
1915                 es_cookie_io_functions_t functions)
1916 {
1917   unsigned int flags;
1918   estream_t stream;
1919   int err;
1920
1921   stream = NULL;
1922   flags = 0;
1923   
1924   err = es_convert_mode (mode, &flags);
1925   if (err)
1926     goto out;
1927
1928   err = es_create (&stream, cookie, -1, functions);
1929   if (err)
1930     goto out;
1931
1932  out:
1933
1934   return stream;
1935 }
1936
1937
1938 estream_t
1939 es_fdopen (int filedes, const char *mode)
1940 {
1941   unsigned int flags;
1942   int create_called;
1943   estream_t stream;
1944   void *cookie;
1945   int err;
1946
1947   stream = NULL;
1948   cookie = NULL;
1949   create_called = 0;
1950
1951   err = es_convert_mode (mode, &flags);
1952   if (err)
1953     goto out;
1954
1955   err = es_func_fd_create (&cookie, filedes, flags);
1956   if (err)
1957     goto out;
1958
1959   create_called = 1;
1960   err = es_create (&stream, cookie, filedes, estream_functions_fd);
1961
1962  out:
1963
1964   if (err && create_called)
1965     (*estream_functions_fd.func_close) (cookie);
1966
1967   return stream;
1968 }
1969   
1970
1971 estream_t
1972 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
1973             estream_t ES__RESTRICT stream)
1974 {
1975   int err;
1976
1977   if (path)
1978     {
1979       unsigned int flags;
1980       int create_called;
1981       void *cookie;
1982       int fd;
1983
1984       cookie = NULL;
1985       create_called = 0;
1986       
1987       ESTREAM_LOCK (stream);
1988
1989       es_deinitialize (stream);
1990
1991       err = es_convert_mode (mode, &flags);
1992       if (err)
1993         goto leave;
1994       
1995       err = es_func_file_create (&cookie, &fd, path, flags);
1996       if (err)
1997         goto leave;
1998
1999       create_called = 1;
2000       es_initialize (stream, cookie, fd, estream_functions_file);
2001
2002     leave:
2003
2004       if (err)
2005         {
2006           if (create_called)
2007             es_func_fd_destroy (cookie);
2008       
2009           es_destroy (stream);
2010           stream = NULL;
2011         }
2012       else
2013         ESTREAM_UNLOCK (stream);
2014     }
2015   else
2016     {
2017       /* FIXME?  We don't support re-opening at the moment.  */
2018       errno = EINVAL;
2019       es_deinitialize (stream);
2020       es_destroy (stream);
2021       stream = NULL;
2022     }
2023
2024   return stream;
2025 }
2026
2027
2028 int
2029 es_fclose (estream_t stream)
2030 {
2031   int err;
2032
2033   err = es_destroy (stream);
2034
2035   return err;
2036 }
2037
2038 int
2039 es_fileno_unlocked (estream_t stream)
2040 {
2041   return es_get_fd (stream);
2042 }
2043
2044
2045 void
2046 es_flockfile (estream_t stream)
2047 {
2048   ESTREAM_LOCK (stream);
2049 }
2050
2051
2052 int
2053 es_ftrylockfile (estream_t stream)
2054 {
2055   return ESTREAM_TRYLOCK (stream);
2056 }
2057
2058
2059 void
2060 es_funlockfile (estream_t stream)
2061 {
2062   ESTREAM_UNLOCK (stream);
2063 }
2064
2065
2066 int
2067 es_fileno (estream_t stream)
2068 {
2069   int ret;
2070
2071   ESTREAM_LOCK (stream);
2072   ret = es_fileno_unlocked (stream);
2073   ESTREAM_UNLOCK (stream);
2074
2075   return ret;
2076 }
2077
2078
2079 int
2080 es_feof_unlocked (estream_t stream)
2081 {
2082   return es_get_indicator (stream, 0, 1);
2083 }
2084
2085
2086 int
2087 es_feof (estream_t stream)
2088 {
2089   int ret;
2090
2091   ESTREAM_LOCK (stream);
2092   ret = es_feof_unlocked (stream);
2093   ESTREAM_UNLOCK (stream);
2094
2095   return ret;
2096 }
2097
2098
2099 int
2100 es_ferror_unlocked (estream_t stream)
2101 {
2102   return es_get_indicator (stream, 1, 0);
2103 }
2104
2105
2106 int
2107 es_ferror (estream_t stream)
2108 {
2109   int ret;
2110
2111   ESTREAM_LOCK (stream);
2112   ret = es_ferror_unlocked (stream);
2113   ESTREAM_UNLOCK (stream);
2114
2115   return ret;
2116 }
2117
2118
2119 void
2120 es_clearerr_unlocked (estream_t stream)
2121 {
2122   es_set_indicators (stream, 0, 0);
2123 }
2124
2125
2126 void
2127 es_clearerr (estream_t stream)
2128 {
2129   ESTREAM_LOCK (stream);
2130   es_clearerr_unlocked (stream);
2131   ESTREAM_UNLOCK (stream);
2132 }
2133
2134
2135 int
2136 es_fflush (estream_t stream)
2137 {
2138   int err;
2139   
2140   if (stream)
2141     {
2142       ESTREAM_LOCK (stream);
2143       if (stream->flags & ES_FLAG_WRITING)
2144         err = es_flush (stream);
2145       else
2146         {
2147           es_empty (stream);
2148           err = 0;
2149         }
2150       ESTREAM_UNLOCK (stream);
2151     }
2152   else
2153     err = es_list_iterate (es_fflush);
2154
2155   return err ? EOF : 0;
2156 }
2157
2158
2159 int
2160 es_fseek (estream_t stream, long int offset, int whence)
2161 {
2162   int err;
2163
2164   ESTREAM_LOCK (stream);
2165   err = es_seek (stream, offset, whence, NULL);
2166   ESTREAM_UNLOCK (stream);
2167
2168   return err;
2169 }
2170
2171
2172 int
2173 es_fseeko (estream_t stream, off_t offset, int whence)
2174 {
2175   int err;
2176   
2177   ESTREAM_LOCK (stream);
2178   err = es_seek (stream, offset, whence, NULL);
2179   ESTREAM_UNLOCK (stream);
2180
2181   return err;
2182 }
2183
2184
2185 long int
2186 es_ftell (estream_t stream)
2187 {
2188   long int ret;
2189   
2190   ESTREAM_LOCK (stream);
2191   ret = es_offset_calculate (stream);
2192   ESTREAM_UNLOCK (stream);
2193
2194   return ret;
2195 }
2196
2197
2198 off_t
2199 es_ftello (estream_t stream)
2200 {
2201   off_t ret = -1;
2202
2203   ESTREAM_LOCK (stream);
2204   ret = es_offset_calculate (stream);
2205   ESTREAM_UNLOCK (stream);
2206
2207   return ret;
2208 }
2209
2210
2211 void
2212 es_rewind (estream_t stream)
2213 {
2214   ESTREAM_LOCK (stream);
2215   es_seek (stream, 0L, SEEK_SET, NULL);
2216   es_set_indicators (stream, 0, -1);
2217   ESTREAM_UNLOCK (stream);
2218 }
2219
2220
2221 int
2222 _es_getc_underflow (estream_t stream)
2223 {
2224   int err;
2225   unsigned char c;
2226   size_t bytes_read;
2227
2228   err = es_readn (stream, &c, 1, &bytes_read);
2229
2230   return (err || (! bytes_read)) ? EOF : c;
2231 }
2232
2233
2234 int
2235 _es_putc_overflow (int c, estream_t stream)
2236 {
2237   unsigned char d = c;
2238   int err;
2239
2240   err = es_writen (stream, &d, 1, NULL);
2241
2242   return err ? EOF : c;
2243 }
2244
2245
2246 int
2247 es_fgetc (estream_t stream)
2248 {
2249   int ret;
2250   
2251   ESTREAM_LOCK (stream);
2252   ret = es_getc_unlocked (stream);
2253   ESTREAM_UNLOCK (stream);
2254
2255   return ret;
2256 }
2257
2258
2259 int
2260 es_fputc (int c, estream_t stream)
2261 {
2262   int ret;
2263   
2264   ESTREAM_LOCK (stream);
2265   ret = es_putc_unlocked (c, stream);
2266   ESTREAM_UNLOCK (stream);
2267
2268   return ret;
2269 }
2270
2271
2272 int
2273 es_ungetc (int c, estream_t stream)
2274 {
2275   unsigned char data = (unsigned char) c;
2276   size_t data_unread;
2277
2278   ESTREAM_LOCK (stream);
2279   es_unreadn (stream, &data, 1, &data_unread);
2280   ESTREAM_UNLOCK (stream);
2281
2282   return data_unread ? c : EOF;
2283 }
2284
2285
2286 int
2287 es_read (estream_t ES__RESTRICT stream,
2288          char *ES__RESTRICT buffer, size_t bytes_to_read,
2289          size_t *ES__RESTRICT bytes_read)
2290 {
2291   int err;
2292
2293   if (bytes_to_read)
2294     {
2295       ESTREAM_LOCK (stream);
2296       err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2297       ESTREAM_UNLOCK (stream);
2298     }
2299   else
2300     err = 0;
2301
2302   return err;
2303 }
2304
2305
2306 int
2307 es_write (estream_t ES__RESTRICT stream,
2308           const char *ES__RESTRICT buffer, size_t bytes_to_write,
2309           size_t *ES__RESTRICT bytes_written)
2310 {
2311   int err;
2312
2313   if (bytes_to_write)
2314     {
2315       ESTREAM_LOCK (stream);
2316       err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2317       ESTREAM_UNLOCK (stream);
2318     }
2319   else
2320     err = 0;
2321
2322   return err;
2323 }
2324
2325
2326 size_t
2327 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2328           estream_t ES__RESTRICT stream)
2329 {
2330   size_t ret, bytes;
2331   int err;
2332
2333   if (size * nitems)
2334     {
2335       ESTREAM_LOCK (stream);
2336       err = es_readn (stream, ptr, size * nitems, &bytes);
2337       ESTREAM_UNLOCK (stream);
2338
2339       ret = bytes / size;
2340     }
2341   else
2342     ret = 0;
2343
2344   return ret;
2345 }
2346
2347
2348 size_t
2349 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2350            estream_t ES__RESTRICT stream)
2351 {
2352   size_t ret, bytes;
2353   int err;
2354
2355   if (size * nitems)
2356     {
2357       ESTREAM_LOCK (stream);
2358       err = es_writen (stream, ptr, size * nitems, &bytes);
2359       ESTREAM_UNLOCK (stream);
2360
2361       ret = bytes / size;
2362     }
2363   else
2364     ret = 0;
2365
2366   return ret;
2367 }
2368
2369
2370 char *
2371 es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream)
2372 {
2373   char *ret = NULL;
2374   
2375   if (n)
2376     {
2377       int err;
2378       
2379       ESTREAM_LOCK (stream);
2380       err = es_read_line (stream, n, &s, NULL);
2381       ESTREAM_UNLOCK (stream);
2382       if (! err)
2383         ret = s;
2384     }
2385   
2386   return ret;
2387 }
2388
2389
2390 int
2391 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2392 {
2393   size_t length;
2394   int err;
2395
2396   length = strlen (s);
2397   ESTREAM_LOCK (stream);
2398   err = es_writen (stream, s, length, NULL);
2399   ESTREAM_UNLOCK (stream);
2400
2401   return err ? EOF : 0;
2402 }
2403
2404
2405 ssize_t
2406 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2407             estream_t ES__RESTRICT stream)
2408 {
2409   char *line = NULL;
2410   size_t line_n = 0;
2411   int err;
2412
2413   ESTREAM_LOCK (stream);
2414   err = es_read_line (stream, 0, &line, &line_n);
2415   ESTREAM_UNLOCK (stream);
2416   if (err)
2417     goto out;
2418
2419   if (*n)
2420     {
2421       /* Caller wants us to use his buffer.  */
2422       
2423       if (*n < (line_n + 1))
2424         {
2425           /* Provided buffer is too small -> resize.  */
2426
2427           void *p;
2428
2429           p = MEM_REALLOC (*lineptr, line_n + 1);
2430           if (! p)
2431             err = -1;
2432           else
2433             {
2434               if (*lineptr != p)
2435                 *lineptr = p;
2436             }
2437         }
2438
2439       if (! err)
2440         {
2441           memcpy (*lineptr, line, line_n + 1);
2442           if (*n != line_n)
2443             *n = line_n;
2444         }
2445       MEM_FREE (line);
2446     }
2447   else
2448     {
2449       /* Caller wants new buffers.  */
2450       *lineptr = line;
2451       *n = line_n;
2452     }
2453
2454  out:
2455
2456   return err ? err : line_n;
2457 }
2458
2459
2460 int
2461 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2462              va_list ap)
2463 {
2464   int ret;
2465   
2466   ESTREAM_LOCK (stream);
2467   ret = es_print (stream, format, ap);
2468   ESTREAM_UNLOCK (stream);
2469
2470   return ret;
2471 }
2472
2473
2474 int
2475 es_fprintf (estream_t ES__RESTRICT stream,
2476             const char *ES__RESTRICT format, ...)
2477 {
2478   int ret;
2479   
2480   va_list ap;
2481   va_start (ap, format);
2482   ESTREAM_LOCK (stream);
2483   ret = es_print (stream, format, ap);
2484   ESTREAM_UNLOCK (stream);
2485   va_end (ap);
2486
2487   return ret;
2488 }
2489
2490 static int
2491 tmpfd (void)
2492 {
2493   FILE *fp;
2494   int fp_fd;
2495   int fd;
2496
2497   fp = NULL;
2498   fd = -1;
2499   
2500   fp = tmpfile ();
2501   if (! fp)
2502     goto out;
2503
2504   fp_fd = fileno (fp);
2505   fd = dup (fp_fd);
2506
2507  out:
2508
2509   if (fp)
2510     fclose (fp);
2511
2512   return fd;
2513 }
2514
2515 estream_t
2516 es_tmpfile (void)
2517 {
2518   unsigned int flags;
2519   int create_called;
2520   estream_t stream;
2521   void *cookie;
2522   int err;
2523   int fd;
2524
2525   create_called = 0;
2526   stream = NULL;
2527   flags = O_RDWR | O_TRUNC | O_CREAT;
2528   cookie = NULL;
2529   
2530   fd = tmpfd ();
2531   if (fd == -1)
2532     {
2533       err = -1;
2534       goto out;
2535     }
2536
2537   err = es_func_fd_create (&cookie, fd, flags);
2538   if (err)
2539     goto out;
2540
2541   create_called = 1;
2542   err = es_create (&stream, cookie, fd, estream_functions_fd);
2543
2544  out:
2545
2546   if (err)
2547     {
2548       if (create_called)
2549         es_func_fd_destroy (cookie);
2550       else if (fd != -1)
2551         close (fd);
2552       stream = NULL;
2553     }
2554   
2555   return stream;
2556 }
2557
2558
2559 int
2560 es_setvbuf (estream_t ES__RESTRICT stream,
2561             char *ES__RESTRICT buf, int type, size_t size)
2562 {
2563   int err;
2564   
2565   if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
2566       && (! ((! size) && (type != _IONBF))))
2567     {
2568       ESTREAM_LOCK (stream);
2569       err = es_set_buffering (stream, buf, type, size);
2570       ESTREAM_UNLOCK (stream);
2571     }
2572   else
2573     {
2574       errno = EINVAL;
2575       err = -1;
2576     }
2577
2578   return err;
2579 }
2580
2581
2582 void
2583 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
2584 {
2585   ESTREAM_LOCK (stream);
2586   es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
2587   ESTREAM_UNLOCK (stream);
2588 }
2589
2590 void
2591 es_opaque_set (estream_t stream, void *opaque)
2592 {
2593   ESTREAM_LOCK (stream);
2594   es_opaque_ctrl (stream, opaque, NULL);
2595   ESTREAM_UNLOCK (stream);
2596 }
2597
2598
2599 void *
2600 es_opaque_get (estream_t stream)
2601 {
2602   void *opaque;
2603   
2604   ESTREAM_LOCK (stream);
2605   es_opaque_ctrl (stream, NULL, &opaque);
2606   ESTREAM_UNLOCK (stream);
2607
2608   return opaque;
2609 }