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