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