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