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