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