06c6244014042e054f4a9548b4e52dc40b7e5970
[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   file_cookie->no_close = 0;
865   *cookie = file_cookie;
866   *filedes = fd;
867
868  out:
869
870   if (err)
871     ES_MEM_FREE (file_cookie);
872
873   return err;
874 }
875
876 static es_cookie_io_functions_t estream_functions_file =
877   {
878     es_func_fd_read,
879     es_func_fd_write,
880     es_func_fd_seek,
881     es_func_fd_destroy
882   };
883
884 \f
885
886 /* Stream primitives.  */
887
888 static int
889 es_convert_mode (const char *mode, unsigned int *modeflags)
890 {
891
892   /* FIXME: We need to allow all mode flags permutations.  */
893   struct
894   {
895     const char *mode;
896     unsigned int flags;
897   } mode_flags[] = { { "r",
898                        O_RDONLY },
899                      { "rb",
900                        O_RDONLY | O_BINARY },
901                      { "w",
902                        O_WRONLY | O_TRUNC | O_CREAT },
903                      { "wb",
904                        O_WRONLY | O_TRUNC | O_CREAT | O_BINARY },
905                      { "a",
906                        O_WRONLY | O_APPEND | O_CREAT },
907                      { "ab",
908                        O_WRONLY | O_APPEND | O_CREAT | O_BINARY },
909                      { "r+",
910                        O_RDWR },
911                      { "rb+",
912                        O_RDWR | O_BINARY },
913                      { "r+b",
914                        O_RDONLY | O_WRONLY | O_BINARY },
915                      { "w+",
916                        O_RDWR | O_TRUNC | O_CREAT },
917                      { "wb+",
918                        O_RDWR | O_TRUNC | O_CREAT | O_BINARY },
919                      { "w+b",
920                        O_RDWR | O_TRUNC | O_CREAT | O_BINARY },
921                      { "a+",
922                        O_RDWR | O_CREAT | O_APPEND },
923                      { "ab+",
924                        O_RDWR | O_CREAT | O_APPEND | O_BINARY },
925                      { "a+b",
926                        O_RDWR | O_CREAT | O_APPEND | O_BINARY }
927   };
928   unsigned int i;
929   int err; 
930
931   for (i = 0; i < DIM (mode_flags); i++)
932     if (! strcmp (mode_flags[i].mode, mode))
933       break;
934   if (i == DIM (mode_flags))
935     {
936       errno = EINVAL;
937       err = -1;
938     }
939   else
940     {
941       err = 0;
942       *modeflags = mode_flags[i].flags;
943     }
944
945   return err;
946 }
947
948 \f
949
950 /*
951  * Low level stream functionality.
952  */
953
954 static int
955 es_fill (estream_t stream)
956 {
957   size_t bytes_read = 0;
958   int err;
959
960   if (!stream->intern->func_read)
961     {
962       errno = EOPNOTSUPP;
963       err = -1;
964     }
965   else
966     {
967       es_cookie_read_function_t func_read = stream->intern->func_read;
968       ssize_t ret;
969
970       ret = (*func_read) (stream->intern->cookie,
971                           stream->buffer, stream->buffer_size);
972       if (ret == -1)
973         {
974           bytes_read = 0;
975           err = -1;
976         }
977       else
978         {
979           bytes_read = ret;
980           err = 0;
981         }
982     }
983
984   if (err)
985     stream->intern->indicators.err = 1;
986   else if (!bytes_read)
987     stream->intern->indicators.eof = 1;
988
989   stream->intern->offset += stream->data_len;
990   stream->data_len = bytes_read;
991   stream->data_offset = 0;
992
993   return err;
994 }
995
996 static int
997 es_flush (estream_t stream)
998 {
999   es_cookie_write_function_t func_write = stream->intern->func_write;
1000   int err;
1001
1002   assert (stream->flags.writing);
1003
1004   if (stream->data_offset)
1005     {
1006       size_t bytes_written;
1007       size_t data_flushed;
1008       ssize_t ret;
1009
1010       if (! func_write)
1011         {
1012           err = EOPNOTSUPP;
1013           goto out;
1014         }
1015
1016       /* Note: to prevent an endless loop caused by user-provided
1017          write-functions that pretend to have written more bytes than
1018          they were asked to write, we have to check for
1019          "(stream->data_offset - data_flushed) > 0" instead of
1020          "stream->data_offset - data_flushed".  */
1021       
1022       data_flushed = 0;
1023       err = 0;
1024       
1025       while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
1026         {
1027           ret = (*func_write) (stream->intern->cookie,
1028                                stream->buffer + data_flushed,
1029                                stream->data_offset - data_flushed);
1030           if (ret == -1)
1031             {
1032               bytes_written = 0;
1033               err = -1;
1034             }
1035           else
1036             bytes_written = ret;
1037
1038           data_flushed += bytes_written;
1039           if (err)
1040             break;
1041         }
1042
1043       stream->data_flushed += data_flushed;
1044       if (stream->data_offset == data_flushed)
1045         {
1046           stream->intern->offset += stream->data_offset;
1047           stream->data_offset = 0;
1048           stream->data_flushed = 0;
1049
1050           /* Propagate flush event.  */
1051           (*func_write) (stream->intern->cookie, NULL, 0);
1052         }
1053     }
1054   else
1055     err = 0;
1056
1057  out:
1058     
1059   if (err)
1060     stream->intern->indicators.err = 1;
1061
1062   return err;
1063 }
1064
1065 /* Discard buffered data for STREAM.  */
1066 static void
1067 es_empty (estream_t stream)
1068 {
1069   assert (!stream->flags.writing);
1070   stream->data_len = 0;
1071   stream->data_offset = 0;
1072   stream->unread_data_len = 0;
1073 }
1074
1075 /* Initialize STREAM.  */
1076 static void
1077 es_initialize (estream_t stream,
1078                void *cookie, int fd, es_cookie_io_functions_t functions,
1079                unsigned int modeflags)
1080 {
1081   stream->intern->cookie = cookie;
1082   stream->intern->opaque = NULL;
1083   stream->intern->offset = 0;
1084   stream->intern->func_read = functions.func_read;
1085   stream->intern->func_write = functions.func_write;
1086   stream->intern->func_seek = functions.func_seek;
1087   stream->intern->func_close = functions.func_close;
1088   stream->intern->strategy = _IOFBF;
1089   stream->intern->fd = fd;
1090   stream->intern->print_err = 0;
1091   stream->intern->print_errno = 0;
1092   stream->intern->print_ntotal = 0;
1093   stream->intern->print_fp = NULL;
1094   stream->intern->indicators.err = 0;
1095   stream->intern->indicators.eof = 0;
1096   stream->intern->deallocate_buffer = 0;
1097
1098   stream->data_len = 0;
1099   stream->data_offset = 0;
1100   stream->data_flushed = 0;
1101   stream->unread_data_len = 0;
1102   /* Depending on the modeflags we set whether we start in writing or
1103      reading mode.  This is required in case we are working on a
1104      wronly stream which is not seeekable (like stdout).  Without this
1105      pre-initialization we would do a seek at the first write call and
1106      as this will fail no utput will be delivered. */
1107   if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1108     stream->flags.writing = 1;
1109   else
1110     stream->flags.writing = 0;
1111 }
1112
1113 /* Deinitialize STREAM.  */
1114 static int
1115 es_deinitialize (estream_t stream)
1116 {
1117   es_cookie_close_function_t func_close;
1118   int err, tmp_err;
1119
1120   if (stream->intern->print_fp)
1121     {
1122       int save_errno = errno;
1123       fclose (stream->intern->print_fp);
1124       stream->intern->print_fp = NULL;
1125       errno = save_errno;
1126     }
1127
1128   func_close = stream->intern->func_close;
1129
1130   err = 0;
1131   if (stream->flags.writing)
1132     SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1133   if (func_close)
1134     SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1135
1136   
1137   return err;
1138 }
1139
1140 /* Create a new stream object, initialize it.  */
1141 static int
1142 es_create (estream_t *stream, void *cookie, int fd,
1143            es_cookie_io_functions_t functions, unsigned int modeflags)
1144 {
1145   estream_internal_t stream_internal_new;
1146   estream_t stream_new;
1147   int err;
1148
1149   stream_new = NULL;
1150   stream_internal_new = NULL;
1151
1152   stream_new = ES_MEM_ALLOC (sizeof (*stream_new));
1153   if (! stream_new)
1154     {
1155       err = -1;
1156       goto out;
1157     }
1158
1159   stream_internal_new = ES_MEM_ALLOC (sizeof (*stream_internal_new));
1160   if (! stream_internal_new)
1161     {
1162       err = -1;
1163       goto out;
1164     }
1165
1166   stream_new->buffer = stream_internal_new->buffer;
1167   stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1168   stream_new->unread_buffer = stream_internal_new->unread_buffer;
1169   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1170   stream_new->intern = stream_internal_new;
1171
1172   ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
1173   es_initialize (stream_new, cookie, fd, functions, modeflags);
1174
1175   err = es_list_add (stream_new);
1176   if (err)
1177     goto out;
1178
1179   *stream = stream_new;
1180
1181  out:
1182
1183   if (err)
1184     {
1185       if (stream_new)
1186         {
1187           es_deinitialize (stream_new);
1188           ES_MEM_FREE (stream_new);
1189         }
1190     }
1191
1192   return err;
1193 }
1194
1195 /* Deinitialize a stream object and destroy it.  */
1196 static int
1197 es_destroy (estream_t stream)
1198 {
1199   int err = 0;
1200
1201   if (stream)
1202     {
1203       es_list_remove (stream);
1204       err = es_deinitialize (stream);
1205       ES_MEM_FREE (stream->intern);
1206       ES_MEM_FREE (stream);
1207     }
1208
1209   return err;
1210 }
1211
1212 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1213    unbuffered-mode, storing the amount of bytes read in
1214    *BYTES_READ.  */
1215 static int
1216 es_read_nbf (estream_t ES__RESTRICT stream,
1217              unsigned char *ES__RESTRICT buffer,
1218              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1219 {
1220   es_cookie_read_function_t func_read = stream->intern->func_read;
1221   size_t data_read;
1222   ssize_t ret;
1223   int err;
1224
1225   data_read = 0;
1226   err = 0;
1227
1228   while (bytes_to_read - data_read)
1229     {
1230       ret = (*func_read) (stream->intern->cookie,
1231                           buffer + data_read, bytes_to_read - data_read);
1232       if (ret == -1)
1233         {
1234           err = -1;
1235           break;
1236         }
1237       else if (ret)
1238         data_read += ret;
1239       else
1240         break;
1241     }
1242
1243   stream->intern->offset += data_read;
1244   *bytes_read = data_read;
1245
1246   return err;
1247 }
1248
1249 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1250    fully-buffered-mode, storing the amount of bytes read in
1251    *BYTES_READ.  */
1252 static int
1253 es_read_fbf (estream_t ES__RESTRICT stream,
1254              unsigned char *ES__RESTRICT buffer,
1255              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1256 {
1257   size_t data_available;
1258   size_t data_to_read;
1259   size_t data_read;
1260   int err;
1261
1262   data_read = 0;
1263   err = 0;
1264
1265   while ((bytes_to_read - data_read) && (! err))
1266     {
1267       if (stream->data_offset == stream->data_len)
1268         {
1269           /* Nothing more to read in current container, try to
1270              fill container with new data.  */
1271           err = es_fill (stream);
1272           if (! err)
1273             if (! stream->data_len)
1274               /* Filling did not result in any data read.  */
1275               break;
1276         }
1277
1278       if (! err)
1279         {
1280           /* Filling resulted in some new data.  */
1281
1282           data_to_read = bytes_to_read - data_read;
1283           data_available = stream->data_len - stream->data_offset;
1284           if (data_to_read > data_available)
1285             data_to_read = data_available;
1286
1287           memcpy (buffer + data_read,
1288                   stream->buffer + stream->data_offset, data_to_read);
1289           stream->data_offset += data_to_read;
1290           data_read += data_to_read;
1291         }
1292     }
1293
1294   *bytes_read = data_read;
1295
1296   return err;
1297 }
1298
1299 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1300    line-buffered-mode, storing the amount of bytes read in
1301    *BYTES_READ.  */
1302 static int
1303 es_read_lbf (estream_t ES__RESTRICT stream,
1304              unsigned char *ES__RESTRICT buffer,
1305              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1306 {
1307   int err;
1308
1309   err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1310
1311   return err;
1312 }
1313
1314 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1315    *the amount of bytes read in BYTES_READ.  */
1316 static int
1317 es_readn (estream_t ES__RESTRICT stream,
1318           void *ES__RESTRICT buffer_arg,
1319           size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1320 {
1321   unsigned char *buffer = (unsigned char *)buffer_arg;
1322   size_t data_read_unread, data_read;
1323   int err;
1324
1325   data_read_unread = 0;
1326   data_read = 0;
1327   err = 0;
1328
1329   if (stream->flags.writing)
1330     {
1331       /* Switching to reading mode -> flush output.  */
1332       err = es_flush (stream);
1333       if (err)
1334         goto out;
1335       stream->flags.writing = 0;
1336     }  
1337
1338   /* Read unread data first.  */
1339   while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1340     {
1341       buffer[data_read_unread]
1342         = stream->unread_buffer[stream->unread_data_len - 1];
1343       stream->unread_data_len--;
1344       data_read_unread++;
1345     }
1346
1347   switch (stream->intern->strategy)
1348     {
1349     case _IONBF:
1350       err = es_read_nbf (stream,
1351                          buffer + data_read_unread,
1352                          bytes_to_read - data_read_unread, &data_read);
1353       break;
1354     case _IOLBF:
1355       err = es_read_lbf (stream,
1356                          buffer + data_read_unread,
1357                          bytes_to_read - data_read_unread, &data_read);
1358       break;
1359     case _IOFBF:
1360       err = es_read_fbf (stream,
1361                          buffer + data_read_unread,
1362                          bytes_to_read - data_read_unread, &data_read);
1363       break;
1364     }
1365
1366  out:
1367
1368   if (bytes_read)
1369     *bytes_read = data_read_unread + data_read;
1370
1371   return err;
1372 }
1373
1374 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1375    amount of bytes succesfully unread in *BYTES_UNREAD.  */
1376 static void
1377 es_unreadn (estream_t ES__RESTRICT stream,
1378             const unsigned char *ES__RESTRICT data, size_t data_n,
1379             size_t *ES__RESTRICT bytes_unread)
1380 {
1381   size_t space_left;
1382
1383   space_left = stream->unread_buffer_size - stream->unread_data_len;
1384
1385   if (data_n > space_left)
1386     data_n = space_left;
1387
1388   if (! data_n)
1389     goto out;
1390
1391   memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1392   stream->unread_data_len += data_n;
1393   stream->intern->indicators.eof = 0;
1394
1395  out:
1396
1397   if (bytes_unread)
1398     *bytes_unread = data_n;
1399 }
1400
1401 /* Seek in STREAM.  */
1402 static int
1403 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1404          off_t *ES__RESTRICT offset_new)
1405 {
1406   es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1407   int err, ret;
1408   off_t off;
1409
1410   if (! func_seek)
1411     {
1412       errno = EOPNOTSUPP;
1413       err = -1;
1414       goto out;
1415     }
1416
1417   if (stream->flags.writing)
1418     {
1419       /* Flush data first in order to prevent flushing it to the wrong
1420          offset.  */
1421       err = es_flush (stream);
1422       if (err)
1423         goto out;
1424       stream->flags.writing = 0;
1425     }
1426
1427   off = offset;
1428   if (whence == SEEK_CUR)
1429     {
1430       off = off - stream->data_len + stream->data_offset;
1431       off -= stream->unread_data_len;
1432     }
1433   
1434   ret = (*func_seek) (stream->intern->cookie, &off, whence);
1435   if (ret == -1)
1436     {
1437       err = -1;
1438       goto out;
1439     }
1440
1441   err = 0;
1442   es_empty (stream);
1443
1444   if (offset_new)
1445     *offset_new = off;
1446
1447   stream->intern->indicators.eof = 0;
1448   stream->intern->offset = off;
1449
1450  out:
1451   
1452   if (err)
1453     stream->intern->indicators.err = 1;
1454
1455   return err;
1456 }
1457
1458 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1459    unbuffered-mode, storing the amount of bytes written in
1460    *BYTES_WRITTEN.  */
1461 static int
1462 es_write_nbf (estream_t ES__RESTRICT stream,
1463               const unsigned char *ES__RESTRICT buffer,
1464               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1465 {
1466   es_cookie_write_function_t func_write = stream->intern->func_write;
1467   size_t data_written;
1468   ssize_t ret;
1469   int err;
1470
1471   if (bytes_to_write && (! func_write))
1472     {
1473       err = EOPNOTSUPP;
1474       goto out;
1475     }  
1476
1477   data_written = 0;
1478   err = 0;
1479   
1480   while (bytes_to_write - data_written)
1481     {
1482       ret = (*func_write) (stream->intern->cookie,
1483                            buffer + data_written,
1484                            bytes_to_write - data_written);
1485       if (ret == -1)
1486         {
1487           err = -1;
1488           break;
1489         }
1490       else
1491         data_written += ret;
1492     }
1493
1494   stream->intern->offset += data_written;
1495   *bytes_written = data_written;
1496
1497  out:
1498
1499   return err;
1500 }
1501
1502 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1503    fully-buffered-mode, storing the amount of bytes written in
1504    *BYTES_WRITTEN.  */
1505 static int
1506 es_write_fbf (estream_t ES__RESTRICT stream,
1507               const unsigned char *ES__RESTRICT buffer,
1508               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1509 {
1510   size_t space_available;
1511   size_t data_to_write;
1512   size_t data_written;
1513   int err;
1514
1515   data_written = 0;
1516   err = 0;
1517
1518   while ((bytes_to_write - data_written) && (! err))
1519     {
1520       if (stream->data_offset == stream->buffer_size)
1521         /* Container full, flush buffer.  */
1522         err = es_flush (stream);
1523
1524       if (! err)
1525         {
1526           /* Flushing resulted in empty container.  */
1527           
1528           data_to_write = bytes_to_write - data_written;
1529           space_available = stream->buffer_size - stream->data_offset;
1530           if (data_to_write > space_available)
1531             data_to_write = space_available;
1532               
1533           memcpy (stream->buffer + stream->data_offset,
1534                   buffer + data_written, data_to_write);
1535           stream->data_offset += data_to_write;
1536           data_written += data_to_write;
1537         }
1538     }
1539
1540   *bytes_written = data_written;
1541
1542   return err;
1543 }
1544
1545
1546 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1547    line-buffered-mode, storing the amount of bytes written in
1548    *BYTES_WRITTEN.  */
1549 static int
1550 es_write_lbf (estream_t ES__RESTRICT stream,
1551               const unsigned char *ES__RESTRICT buffer,
1552               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1553 {
1554   size_t data_flushed = 0;
1555   size_t data_buffered = 0;
1556   unsigned char *nlp;
1557   int err = 0;
1558
1559   nlp = memrchr (buffer, '\n', bytes_to_write);
1560   if (nlp)
1561     {
1562       /* Found a newline, directly write up to (including) this
1563          character.  */
1564       err = es_flush (stream);
1565       if (!err)
1566         err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1567     }
1568
1569   if (!err)
1570     {
1571       /* Write remaining data fully buffered.  */
1572       err = es_write_fbf (stream, buffer + data_flushed,
1573                           bytes_to_write - data_flushed, &data_buffered);
1574     }
1575
1576   *bytes_written = data_flushed + data_buffered;
1577   return err;
1578 }
1579
1580
1581 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1582    amount of bytes written in BYTES_WRITTEN.  */
1583 static int
1584 es_writen (estream_t ES__RESTRICT stream,
1585            const void *ES__RESTRICT buffer,
1586            size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1587 {
1588   size_t data_written;
1589   int err;
1590
1591   data_written = 0;
1592   err = 0;
1593   
1594   if (!stream->flags.writing)
1595     {
1596       /* Switching to writing mode -> discard input data and seek to
1597          position at which reading has stopped.  We can do this only
1598          if a seek function has been registered. */
1599       if (stream->intern->func_seek)
1600         {
1601           err = es_seek (stream, 0, SEEK_CUR, NULL);
1602           if (err)
1603             {
1604               if (errno == ESPIPE)
1605                 err = 0;
1606               else
1607                 goto out;
1608             }
1609         }
1610     }
1611
1612   switch (stream->intern->strategy)
1613     {
1614     case _IONBF:
1615       err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1616       break;
1617
1618     case _IOLBF:
1619       err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1620       break;
1621
1622     case _IOFBF:
1623       err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1624       break;
1625     }
1626
1627  out:
1628     
1629   if (bytes_written)
1630     *bytes_written = data_written;
1631   if (data_written)
1632     if (!stream->flags.writing)
1633       stream->flags.writing = 1;
1634
1635   return err;
1636 }
1637
1638
1639 static int
1640 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1641          size_t *ES__RESTRICT data_len)
1642 {
1643   int err;
1644
1645   if (stream->flags.writing)
1646     {
1647       /* Switching to reading mode -> flush output.  */
1648       err = es_flush (stream);
1649       if (err)
1650         goto out;
1651       stream->flags.writing = 0;
1652     }  
1653
1654   if (stream->data_offset == stream->data_len)
1655     {
1656       /* Refill container.  */
1657       err = es_fill (stream);
1658       if (err)
1659         goto out;
1660     }
1661   
1662   if (data)
1663     *data = stream->buffer + stream->data_offset;
1664   if (data_len)
1665     *data_len = stream->data_len - stream->data_offset;
1666   err = 0;
1667
1668  out:
1669
1670   return err;
1671 }
1672
1673
1674 /* Skip SIZE bytes of input data contained in buffer.  */
1675 static int
1676 es_skip (estream_t stream, size_t size)
1677 {
1678   int err;
1679
1680   if (stream->data_offset + size > stream->data_len)
1681     {
1682       errno = EINVAL;
1683       err = -1;
1684     }
1685   else
1686     {
1687       stream->data_offset += size;
1688       err = 0;
1689     }
1690
1691   return err;
1692 }
1693
1694
1695 static int
1696 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
1697              char *ES__RESTRICT *ES__RESTRICT line,
1698              size_t *ES__RESTRICT line_length)
1699 {
1700   size_t space_left;
1701   size_t line_size;
1702   estream_t line_stream;
1703   char *line_new;
1704   void *line_stream_cookie;
1705   char *newline;
1706   unsigned char *data;
1707   size_t data_len;
1708   int err;
1709
1710   line_new = NULL;
1711   line_stream = NULL;
1712   line_stream_cookie = NULL;
1713
1714   err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0, BUFFER_BLOCK_SIZE,
1715                             1, 0, 0, NULL, 0, ES_MEM_REALLOC, ES_MEM_FREE,
1716                             O_RDWR);
1717   if (err)
1718     goto out;
1719
1720   err = es_create (&line_stream, line_stream_cookie, -1,
1721                    estream_functions_mem, O_RDWR);
1722   if (err)
1723     goto out;
1724
1725   space_left = max_length;
1726   line_size = 0;
1727   while (1)
1728     {
1729       if (max_length && (space_left == 1))
1730         break;
1731
1732       err = es_peek (stream, &data, &data_len);
1733       if (err || (! data_len))
1734         break;
1735
1736       if (data_len > (space_left - 1))
1737         data_len = space_left - 1;
1738
1739       newline = memchr (data, '\n', data_len);
1740       if (newline)
1741         {
1742           data_len = (newline - (char *) data) + 1;
1743           err = es_write (line_stream, data, data_len, NULL);
1744           if (! err)
1745             {
1746               space_left -= data_len;
1747               line_size += data_len;
1748               es_skip (stream, data_len);
1749               break;
1750             }
1751         }
1752       else
1753         {
1754           err = es_write (line_stream, data, data_len, NULL);
1755           if (! err)
1756             {
1757               space_left -= data_len;
1758               line_size += data_len;
1759               es_skip (stream, data_len);
1760             }
1761         }
1762       if (err)
1763         break;
1764     }
1765   if (err)
1766     goto out;
1767
1768   /* Complete line has been written to line_stream.  */
1769   
1770   if ((max_length > 1) && (! line_size))
1771     {
1772       stream->intern->indicators.eof = 1;
1773       goto out;
1774     }
1775
1776   err = es_seek (line_stream, 0, SEEK_SET, NULL);
1777   if (err)
1778     goto out;
1779
1780   if (! *line)
1781     {
1782       line_new = ES_MEM_ALLOC (line_size + 1);
1783       if (! line_new)
1784         {
1785           err = -1;
1786           goto out;
1787         }
1788     }
1789   else
1790     line_new = *line;
1791
1792   err = es_read (line_stream, line_new, line_size, NULL);
1793   if (err)
1794     goto out;
1795
1796   line_new[line_size] = '\0';
1797
1798   if (! *line)
1799     *line = line_new;
1800   if (line_length)
1801     *line_length = line_size;
1802
1803  out:
1804
1805   if (line_stream)
1806     es_destroy (line_stream);
1807   else if (line_stream_cookie)
1808     es_func_mem_destroy (line_stream_cookie);
1809
1810   if (err)
1811     {
1812       if (! *line)
1813         ES_MEM_FREE (line_new);
1814       stream->intern->indicators.err = 1;
1815     }
1816
1817   return err;
1818 }
1819
1820
1821 /* Output fucntion used for estream_format.  */
1822 static int
1823 print_writer (void *outfncarg, const char *buf, size_t buflen)
1824 {
1825   estream_t stream = outfncarg;
1826   size_t nwritten;
1827   int rc;
1828
1829   nwritten = 0;
1830   rc = es_writen (stream, buf, buflen, &nwritten);
1831   stream->intern->print_ntotal += nwritten;
1832   return rc;
1833 }
1834
1835
1836 /* The core of our printf function.  This is called in locked state. */
1837 static int
1838 es_print (estream_t ES__RESTRICT stream,
1839           const char *ES__RESTRICT format, va_list ap)
1840 {
1841   int rc;
1842
1843   stream->intern->print_ntotal = 0;
1844   rc = estream_format (print_writer, stream, format, ap);
1845   if (rc)
1846     return -1;
1847   return (int)stream->intern->print_ntotal;
1848 }
1849
1850
1851 static void
1852 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1853 {
1854   if (ind_err != -1)
1855     stream->intern->indicators.err = ind_err ? 1 : 0;
1856   if (ind_eof != -1)
1857     stream->intern->indicators.eof = ind_eof ? 1 : 0;
1858 }
1859
1860
1861 static int
1862 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1863 {
1864   int ret = 0;
1865   
1866   if (ind_err)
1867     ret = stream->intern->indicators.err;
1868   else if (ind_eof)
1869     ret = stream->intern->indicators.eof;
1870
1871   return ret;
1872 }
1873
1874
1875 static int
1876 es_set_buffering (estream_t ES__RESTRICT stream,
1877                   char *ES__RESTRICT buffer, int mode, size_t size)
1878 {
1879   int err;
1880
1881   /* Flush or empty buffer depending on mode.  */
1882   if (stream->flags.writing)
1883     {
1884       err = es_flush (stream);
1885       if (err)
1886         goto out;
1887     }
1888   else
1889     es_empty (stream);
1890
1891   es_set_indicators (stream, -1, 0);
1892   
1893   /* Free old buffer in case that was allocated by this function.  */
1894   if (stream->intern->deallocate_buffer)
1895     {
1896       stream->intern->deallocate_buffer = 0;
1897       ES_MEM_FREE (stream->buffer);
1898       stream->buffer = NULL;
1899     }
1900
1901   if (mode == _IONBF)
1902     stream->buffer_size = 0;
1903   else
1904     {
1905       void *buffer_new;
1906       
1907       if (buffer)
1908         buffer_new = buffer;
1909       else
1910         {
1911           buffer_new = ES_MEM_ALLOC (size);
1912           if (! buffer_new)
1913             {
1914               err = -1;
1915               goto out;
1916             }
1917         }
1918
1919       stream->buffer = buffer_new;
1920       stream->buffer_size = size;
1921       if (! buffer)
1922         stream->intern->deallocate_buffer = 1;
1923     }
1924   stream->intern->strategy = mode;
1925   err = 0;
1926
1927  out:
1928
1929   return err;
1930 }
1931
1932
1933 static off_t
1934 es_offset_calculate (estream_t stream)
1935 {
1936   off_t offset;
1937
1938   offset = stream->intern->offset + stream->data_offset;
1939   if (offset < stream->unread_data_len)
1940     /* Offset undefined.  */
1941     offset = 0;
1942   else
1943     offset -= stream->unread_data_len;
1944
1945   return offset;
1946 }
1947
1948
1949 static void
1950 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1951                 void **ES__RESTRICT opaque_old)
1952 {
1953   if (opaque_old)
1954     *opaque_old = stream->intern->opaque;
1955   if (opaque_new)
1956     stream->intern->opaque = opaque_new;
1957 }
1958
1959
1960 static int
1961 es_get_fd (estream_t stream)
1962 {
1963   return stream->intern->fd;
1964 }
1965
1966 \f
1967
1968 /* API.  */
1969
1970 int
1971 es_init (void)
1972 {
1973   int err;
1974
1975   err = es_init_do ();
1976
1977   return err;
1978 }
1979
1980 estream_t
1981 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
1982 {
1983   unsigned int modeflags;
1984   int create_called;
1985   estream_t stream;
1986   void *cookie;
1987   int err;
1988   int fd;
1989
1990   stream = NULL;
1991   cookie = NULL;
1992   create_called = 0;
1993
1994   err = es_convert_mode (mode, &modeflags);
1995   if (err)
1996     goto out;
1997   
1998   err = es_func_file_create (&cookie, &fd, path, modeflags);
1999   if (err)
2000     goto out;
2001
2002   create_called = 1;
2003   err = es_create (&stream, cookie, fd, estream_functions_file, modeflags);
2004   if (err)
2005     goto out;
2006
2007  out:
2008   
2009   if (err && create_called)
2010     (*estream_functions_file.func_close) (cookie);
2011
2012   return stream;
2013 }
2014
2015
2016 estream_t
2017 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
2018           unsigned int grow,
2019           func_realloc_t func_realloc, func_free_t func_free,
2020           const char *ES__RESTRICT mode)
2021 {
2022   unsigned int modeflags;
2023   int create_called;
2024   estream_t stream;
2025   void *cookie;
2026   int err;
2027
2028   cookie = 0;
2029   stream = NULL;
2030   create_called = 0;
2031   
2032   err = es_convert_mode (mode, &modeflags);
2033   if (err)
2034     goto out;
2035
2036   err = es_func_mem_create (&cookie, data, data_n, data_len,
2037                             BUFFER_BLOCK_SIZE, grow, 0, 0,
2038                             NULL, 0, func_realloc, func_free, modeflags);
2039   if (err)
2040     goto out;
2041   
2042   create_called = 1;
2043   err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags);
2044
2045  out:
2046
2047   if (err && create_called)
2048     (*estream_functions_mem.func_close) (cookie);
2049
2050   return stream;
2051 }
2052
2053
2054 estream_t
2055 es_open_memstream (char **ptr, size_t *size)
2056 {
2057   unsigned int modeflags;
2058   int create_called;
2059   estream_t stream;
2060   void *cookie;
2061   int err;
2062
2063   modeflags = O_RDWR;
2064   create_called = 0;
2065   stream = NULL;
2066   cookie = 0;
2067   
2068   err = es_func_mem_create (&cookie, NULL, 0, 0,
2069                             BUFFER_BLOCK_SIZE, 1, 1, 1,
2070                             ptr, size, ES_MEM_REALLOC, ES_MEM_FREE, modeflags);
2071   if (err)
2072     goto out;
2073   
2074   create_called = 1;
2075   err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags);
2076
2077  out:
2078
2079   if (err && create_called)
2080     (*estream_functions_mem.func_close) (cookie);
2081
2082   return stream;
2083 }
2084
2085
2086 estream_t
2087 es_fopencookie (void *ES__RESTRICT cookie,
2088                 const char *ES__RESTRICT mode,
2089                 es_cookie_io_functions_t functions)
2090 {
2091   unsigned int modeflags;
2092   estream_t stream;
2093   int err;
2094
2095   stream = NULL;
2096   modeflags = 0;
2097   
2098   err = es_convert_mode (mode, &modeflags);
2099   if (err)
2100     goto out;
2101
2102   err = es_create (&stream, cookie, -1, functions, modeflags);
2103   if (err)
2104     goto out;
2105
2106  out:
2107
2108   return stream;
2109 }
2110
2111
2112 estream_t
2113 do_fdopen (int filedes, const char *mode, int no_close)
2114 {
2115   unsigned int modeflags;
2116   int create_called;
2117   estream_t stream;
2118   void *cookie;
2119   int err;
2120
2121   stream = NULL;
2122   cookie = NULL;
2123   create_called = 0;
2124
2125   err = es_convert_mode (mode, &modeflags);
2126   if (err)
2127     goto out;
2128
2129   err = es_func_fd_create (&cookie, filedes, modeflags, no_close);
2130   if (err)
2131     goto out;
2132
2133   create_called = 1;
2134   err = es_create (&stream, cookie, filedes, estream_functions_fd, modeflags);
2135
2136  out:
2137
2138   if (err && create_called)
2139     (*estream_functions_fd.func_close) (cookie);
2140
2141   return stream;
2142 }
2143
2144 estream_t
2145 es_fdopen (int filedes, const char *mode)
2146 {
2147   return do_fdopen (filedes, mode, 0);
2148 }
2149
2150 /* A variant of es_fdopen which does not close FILEDES at the end.  */
2151 estream_t
2152 es_fdopen_nc (int filedes, const char *mode)
2153 {
2154   return do_fdopen (filedes, mode, 1);
2155 }
2156
2157
2158 estream_t
2159 do_fpopen (FILE *fp, const char *mode, int no_close)
2160 {
2161   unsigned int modeflags;
2162   int create_called;
2163   estream_t stream;
2164   void *cookie;
2165   int err;
2166
2167   stream = NULL;
2168   cookie = NULL;
2169   create_called = 0;
2170
2171   err = es_convert_mode (mode, &modeflags);
2172   if (err)
2173     goto out;
2174
2175   fflush (fp);
2176   err = es_func_fp_create (&cookie, fp, modeflags, no_close);
2177   if (err)
2178     goto out;
2179
2180   create_called = 1;
2181   err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
2182                    modeflags);
2183
2184  out:
2185
2186   if (err && create_called)
2187     (*estream_functions_fp.func_close) (cookie);
2188
2189   return stream;
2190 }
2191
2192   
2193 /* Create an estream from the stdio stream FP.  This mechanism is
2194    useful in case the stdio streams have special properties and may
2195    not be mixed with fd based functions.  This is for example the case
2196    under Windows where the 3 standard streams are associated with the
2197    console whereas a duped and fd-opened stream of one of this stream
2198    won't be associated with the console.  As this messes things up it
2199    is easier to keep on using the standard I/O stream as a backend for
2200    estream. */
2201 estream_t
2202 es_fpopen (FILE *fp, const char *mode)
2203 {
2204   return do_fpopen (fp, mode, 0);
2205 }
2206
2207
2208 /* Same as es_fpopen but does not close  FP at the end.  */
2209 estream_t
2210 es_fpopen_nc (FILE *fp, const char *mode)
2211 {
2212   return do_fpopen (fp, mode, 1);
2213 }
2214
2215
2216 estream_t
2217 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
2218             estream_t ES__RESTRICT stream)
2219 {
2220   int err;
2221
2222   if (path)
2223     {
2224       unsigned int modeflags;
2225       int create_called;
2226       void *cookie;
2227       int fd;
2228
2229       cookie = NULL;
2230       create_called = 0;
2231       
2232       ESTREAM_LOCK (stream);
2233
2234       es_deinitialize (stream);
2235
2236       err = es_convert_mode (mode, &modeflags);
2237       if (err)
2238         goto leave;
2239       
2240       err = es_func_file_create (&cookie, &fd, path, modeflags);
2241       if (err)
2242         goto leave;
2243
2244       create_called = 1;
2245       es_initialize (stream, cookie, fd, estream_functions_file, modeflags);
2246
2247     leave:
2248
2249       if (err)
2250         {
2251           if (create_called)
2252             es_func_fd_destroy (cookie);
2253       
2254           es_destroy (stream);
2255           stream = NULL;
2256         }
2257       else
2258         ESTREAM_UNLOCK (stream);
2259     }
2260   else
2261     {
2262       /* FIXME?  We don't support re-opening at the moment.  */
2263       errno = EINVAL;
2264       es_deinitialize (stream);
2265       es_destroy (stream);
2266       stream = NULL;
2267     }
2268
2269   return stream;
2270 }
2271
2272
2273 int
2274 es_fclose (estream_t stream)
2275 {
2276   int err;
2277
2278   err = es_destroy (stream);
2279
2280   return err;
2281 }
2282
2283 int
2284 es_fileno_unlocked (estream_t stream)
2285 {
2286   return es_get_fd (stream);
2287 }
2288
2289
2290 void
2291 es_flockfile (estream_t stream)
2292 {
2293   ESTREAM_LOCK (stream);
2294 }
2295
2296
2297 int
2298 es_ftrylockfile (estream_t stream)
2299 {
2300   return ESTREAM_TRYLOCK (stream);
2301 }
2302
2303
2304 void
2305 es_funlockfile (estream_t stream)
2306 {
2307   ESTREAM_UNLOCK (stream);
2308 }
2309
2310
2311 int
2312 es_fileno (estream_t stream)
2313 {
2314   int ret;
2315
2316   ESTREAM_LOCK (stream);
2317   ret = es_fileno_unlocked (stream);
2318   ESTREAM_UNLOCK (stream);
2319
2320   return ret;
2321 }
2322
2323
2324 int
2325 es_feof_unlocked (estream_t stream)
2326 {
2327   return es_get_indicator (stream, 0, 1);
2328 }
2329
2330
2331 int
2332 es_feof (estream_t stream)
2333 {
2334   int ret;
2335
2336   ESTREAM_LOCK (stream);
2337   ret = es_feof_unlocked (stream);
2338   ESTREAM_UNLOCK (stream);
2339
2340   return ret;
2341 }
2342
2343
2344 int
2345 es_ferror_unlocked (estream_t stream)
2346 {
2347   return es_get_indicator (stream, 1, 0);
2348 }
2349
2350
2351 int
2352 es_ferror (estream_t stream)
2353 {
2354   int ret;
2355
2356   ESTREAM_LOCK (stream);
2357   ret = es_ferror_unlocked (stream);
2358   ESTREAM_UNLOCK (stream);
2359
2360   return ret;
2361 }
2362
2363
2364 void
2365 es_clearerr_unlocked (estream_t stream)
2366 {
2367   es_set_indicators (stream, 0, 0);
2368 }
2369
2370
2371 void
2372 es_clearerr (estream_t stream)
2373 {
2374   ESTREAM_LOCK (stream);
2375   es_clearerr_unlocked (stream);
2376   ESTREAM_UNLOCK (stream);
2377 }
2378
2379
2380 int
2381 es_fflush (estream_t stream)
2382 {
2383   int err;
2384   
2385   if (stream)
2386     {
2387       ESTREAM_LOCK (stream);
2388       if (stream->flags.writing)
2389         err = es_flush (stream);
2390       else
2391         {
2392           es_empty (stream);
2393           err = 0;
2394         }
2395       ESTREAM_UNLOCK (stream);
2396     }
2397   else
2398     err = es_list_iterate (es_fflush);
2399
2400   return err ? EOF : 0;
2401 }
2402
2403
2404 int
2405 es_fseek (estream_t stream, long int offset, int whence)
2406 {
2407   int err;
2408
2409   ESTREAM_LOCK (stream);
2410   err = es_seek (stream, offset, whence, NULL);
2411   ESTREAM_UNLOCK (stream);
2412
2413   return err;
2414 }
2415
2416
2417 int
2418 es_fseeko (estream_t stream, off_t offset, int whence)
2419 {
2420   int err;
2421   
2422   ESTREAM_LOCK (stream);
2423   err = es_seek (stream, offset, whence, NULL);
2424   ESTREAM_UNLOCK (stream);
2425
2426   return err;
2427 }
2428
2429
2430 long int
2431 es_ftell (estream_t stream)
2432 {
2433   long int ret;
2434   
2435   ESTREAM_LOCK (stream);
2436   ret = es_offset_calculate (stream);
2437   ESTREAM_UNLOCK (stream);
2438
2439   return ret;
2440 }
2441
2442
2443 off_t
2444 es_ftello (estream_t stream)
2445 {
2446   off_t ret = -1;
2447
2448   ESTREAM_LOCK (stream);
2449   ret = es_offset_calculate (stream);
2450   ESTREAM_UNLOCK (stream);
2451
2452   return ret;
2453 }
2454
2455
2456 void
2457 es_rewind (estream_t stream)
2458 {
2459   ESTREAM_LOCK (stream);
2460   es_seek (stream, 0L, SEEK_SET, NULL);
2461   es_set_indicators (stream, 0, -1);
2462   ESTREAM_UNLOCK (stream);
2463 }
2464
2465
2466 int
2467 _es_getc_underflow (estream_t stream)
2468 {
2469   int err;
2470   unsigned char c;
2471   size_t bytes_read;
2472
2473   err = es_readn (stream, &c, 1, &bytes_read);
2474
2475   return (err || (! bytes_read)) ? EOF : c;
2476 }
2477
2478
2479 int
2480 _es_putc_overflow (int c, estream_t stream)
2481 {
2482   unsigned char d = c;
2483   int err;
2484
2485   err = es_writen (stream, &d, 1, NULL);
2486
2487   return err ? EOF : c;
2488 }
2489
2490
2491 int
2492 es_fgetc (estream_t stream)
2493 {
2494   int ret;
2495   
2496   ESTREAM_LOCK (stream);
2497   ret = es_getc_unlocked (stream);
2498   ESTREAM_UNLOCK (stream);
2499
2500   return ret;
2501 }
2502
2503
2504 int
2505 es_fputc (int c, estream_t stream)
2506 {
2507   int ret;
2508   
2509   ESTREAM_LOCK (stream);
2510   ret = es_putc_unlocked (c, stream);
2511   ESTREAM_UNLOCK (stream);
2512
2513   return ret;
2514 }
2515
2516
2517 int
2518 es_ungetc (int c, estream_t stream)
2519 {
2520   unsigned char data = (unsigned char) c;
2521   size_t data_unread;
2522
2523   ESTREAM_LOCK (stream);
2524   es_unreadn (stream, &data, 1, &data_unread);
2525   ESTREAM_UNLOCK (stream);
2526
2527   return data_unread ? c : EOF;
2528 }
2529
2530
2531 int
2532 es_read (estream_t ES__RESTRICT stream,
2533          void *ES__RESTRICT buffer, size_t bytes_to_read,
2534          size_t *ES__RESTRICT bytes_read)
2535 {
2536   int err;
2537
2538   if (bytes_to_read)
2539     {
2540       ESTREAM_LOCK (stream);
2541       err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2542       ESTREAM_UNLOCK (stream);
2543     }
2544   else
2545     err = 0;
2546
2547   return err;
2548 }
2549
2550
2551 int
2552 es_write (estream_t ES__RESTRICT stream,
2553           const void *ES__RESTRICT buffer, size_t bytes_to_write,
2554           size_t *ES__RESTRICT bytes_written)
2555 {
2556   int err;
2557
2558   if (bytes_to_write)
2559     {
2560       ESTREAM_LOCK (stream);
2561       err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2562       ESTREAM_UNLOCK (stream);
2563     }
2564   else
2565     err = 0;
2566
2567   return err;
2568 }
2569
2570
2571 size_t
2572 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2573           estream_t ES__RESTRICT stream)
2574 {
2575   size_t ret, bytes;
2576   int err;
2577
2578   if (size * nitems)
2579     {
2580       ESTREAM_LOCK (stream);
2581       err = es_readn (stream, ptr, size * nitems, &bytes);
2582       ESTREAM_UNLOCK (stream);
2583
2584       ret = bytes / size;
2585     }
2586   else
2587     ret = 0;
2588
2589   return ret;
2590 }
2591
2592
2593 size_t
2594 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2595            estream_t ES__RESTRICT stream)
2596 {
2597   size_t ret, bytes;
2598   int err;
2599
2600   if (size * nitems)
2601     {
2602       ESTREAM_LOCK (stream);
2603       err = es_writen (stream, ptr, size * nitems, &bytes);
2604       ESTREAM_UNLOCK (stream);
2605
2606       ret = bytes / size;
2607     }
2608   else
2609     ret = 0;
2610
2611   return ret;
2612 }
2613
2614
2615 char *
2616 es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream)
2617 {
2618   char *ret = NULL;
2619   
2620   if (n)
2621     {
2622       int err;
2623       
2624       ESTREAM_LOCK (stream);
2625       err = doreadline (stream, n, &s, NULL);
2626       ESTREAM_UNLOCK (stream);
2627       if (! err)
2628         ret = s;
2629     }
2630   
2631   return ret;
2632 }
2633
2634
2635 int
2636 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2637 {
2638   size_t length;
2639   int err;
2640
2641   length = strlen (s);
2642   ESTREAM_LOCK (stream);
2643   err = es_writen (stream, s, length, NULL);
2644   ESTREAM_UNLOCK (stream);
2645
2646   return err ? EOF : 0;
2647 }
2648
2649
2650 ssize_t
2651 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2652             estream_t ES__RESTRICT stream)
2653 {
2654   char *line = NULL;
2655   size_t line_n = 0;
2656   int err;
2657
2658   ESTREAM_LOCK (stream);
2659   err = doreadline (stream, 0, &line, &line_n);
2660   ESTREAM_UNLOCK (stream);
2661   if (err)
2662     goto out;
2663
2664   if (*n)
2665     {
2666       /* Caller wants us to use his buffer.  */
2667       
2668       if (*n < (line_n + 1))
2669         {
2670           /* Provided buffer is too small -> resize.  */
2671
2672           void *p;
2673
2674           p = ES_MEM_REALLOC (*lineptr, line_n + 1);
2675           if (! p)
2676             err = -1;
2677           else
2678             {
2679               if (*lineptr != p)
2680                 *lineptr = p;
2681             }
2682         }
2683
2684       if (! err)
2685         {
2686           memcpy (*lineptr, line, line_n + 1);
2687           if (*n != line_n)
2688             *n = line_n;
2689         }
2690       ES_MEM_FREE (line);
2691     }
2692   else
2693     {
2694       /* Caller wants new buffers.  */
2695       *lineptr = line;
2696       *n = line_n;
2697     }
2698
2699  out:
2700
2701   return err ? err : line_n;
2702 }
2703
2704
2705
2706 /* Same as fgets() but if the provided buffer is too short a larger
2707    one will be allocated.  This is similar to getline. A line is
2708    considered a byte stream ending in a LF.
2709
2710    If MAX_LENGTH is not NULL, it shall point to a value with the
2711    maximum allowed allocation.  
2712
2713    Returns the length of the line. EOF is indicated by a line of
2714    length zero. A truncated line is indicated my setting the value at
2715    MAX_LENGTH to 0.  If the returned value is less then 0 not enough
2716    memory was enable or another error occurred; ERRNO is then set
2717    accordingly.
2718
2719    If a line has been truncated, the file pointer is moved forward to
2720    the end of the line so that the next read starts with the next
2721    line.  Note that MAX_LENGTH must be re-initialzied in this case.
2722
2723    The caller initially needs to provide the address of a variable,
2724    initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2725    anymore with the following invocations.  LENGTH_OF_BUFFER should be
2726    the address of a variable, initialized to 0, which is also
2727    maintained by this function.  Thus, both paramaters should be
2728    considered the state of this function.
2729
2730    Note: The returned buffer is allocated with enough extra space to
2731    allow the caller to append a CR,LF,Nul.  The buffer should be
2732    released using es_free.
2733  */
2734 ssize_t
2735 es_read_line (estream_t stream, 
2736               char **addr_of_buffer, size_t *length_of_buffer,
2737               size_t *max_length)
2738 {
2739   int c;
2740   char  *buffer = *addr_of_buffer;
2741   size_t length = *length_of_buffer;
2742   size_t nbytes = 0;
2743   size_t maxlen = max_length? *max_length : 0;
2744   char *p;
2745
2746   if (!buffer)
2747     { 
2748       /* No buffer given - allocate a new one. */
2749       length = 256;
2750       buffer = ES_MEM_ALLOC (length);
2751       *addr_of_buffer = buffer;
2752       if (!buffer)
2753         {
2754           *length_of_buffer = 0;
2755           if (max_length)
2756             *max_length = 0;
2757           return -1;
2758         }
2759       *length_of_buffer = length;
2760     }
2761
2762   if (length < 4)
2763     {
2764       /* This should never happen. If it does, the fucntion has been
2765          called with wrong arguments. */
2766       errno = EINVAL;
2767       return -1;
2768     }
2769   length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2770
2771   ESTREAM_LOCK (stream);
2772   p = buffer;
2773   while  ((c = es_getc_unlocked (stream)) != EOF)
2774     {
2775       if (nbytes == length)
2776         { 
2777           /* Enlarge the buffer. */
2778           if (maxlen && length > maxlen) 
2779             {
2780               /* We are beyond our limit: Skip the rest of the line. */
2781               while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
2782                 ;
2783               *p++ = '\n'; /* Always append a LF (we reserved some space). */
2784               nbytes++;
2785               if (max_length)
2786                 *max_length = 0; /* Indicate truncation. */
2787               break; /* the while loop. */
2788             }
2789           length += 3; /* Adjust for the reserved bytes. */
2790           length += length < 1024? 256 : 1024;
2791           *addr_of_buffer = ES_MEM_REALLOC (buffer, length);
2792           if (!*addr_of_buffer)
2793             {
2794               int save_errno = errno;
2795               ES_MEM_FREE (buffer); 
2796               *length_of_buffer = *max_length = 0;
2797               ESTREAM_UNLOCK (stream);
2798               errno = save_errno;
2799               return -1;
2800             }
2801           buffer = *addr_of_buffer;
2802           *length_of_buffer = length;
2803           length -= 3; 
2804           p = buffer + nbytes;
2805         }
2806       *p++ = c;
2807       nbytes++;
2808       if (c == '\n')
2809         break;
2810     }
2811   *p = 0; /* Make sure the line is a string. */
2812   ESTREAM_UNLOCK (stream);
2813
2814   return nbytes;
2815 }
2816
2817 /* Wrapper around free() to match the memory allocation system used
2818    by estream.  Should be used for all buffers returned to the caller
2819    by libestream. */
2820 void
2821 es_free (void *a)
2822 {
2823   if (a)
2824     ES_MEM_FREE (a);
2825 }
2826
2827
2828 int
2829 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2830              va_list ap)
2831 {
2832   int ret;
2833   
2834   ESTREAM_LOCK (stream);
2835   ret = es_print (stream, format, ap);
2836   ESTREAM_UNLOCK (stream);
2837
2838   return ret;
2839 }
2840
2841
2842 static int
2843 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
2844            const char *ES__RESTRICT format, ...)
2845 {
2846   int ret;
2847   
2848   va_list ap;
2849   va_start (ap, format);
2850   ret = es_print (stream, format, ap);
2851   va_end (ap);
2852
2853   return ret;
2854 }
2855
2856
2857 int
2858 es_fprintf (estream_t ES__RESTRICT stream,
2859             const char *ES__RESTRICT format, ...)
2860 {
2861   int ret;
2862   
2863   va_list ap;
2864   va_start (ap, format);
2865   ESTREAM_LOCK (stream);
2866   ret = es_print (stream, format, ap);
2867   ESTREAM_UNLOCK (stream);
2868   va_end (ap);
2869
2870   return ret;
2871 }
2872
2873 static int
2874 tmpfd (void)
2875 {
2876   FILE *fp;
2877   int fp_fd;
2878   int fd;
2879
2880   fp = NULL;
2881   fd = -1;
2882   
2883   fp = tmpfile ();
2884   if (! fp)
2885     goto out;
2886
2887   fp_fd = fileno (fp);
2888   fd = dup (fp_fd);
2889
2890  out:
2891
2892   if (fp)
2893     fclose (fp);
2894
2895   return fd;
2896 }
2897
2898 estream_t
2899 es_tmpfile (void)
2900 {
2901   unsigned int modeflags;
2902   int create_called;
2903   estream_t stream;
2904   void *cookie;
2905   int err;
2906   int fd;
2907
2908   create_called = 0;
2909   stream = NULL;
2910   modeflags = O_RDWR | O_TRUNC | O_CREAT;
2911   cookie = NULL;
2912   
2913   fd = tmpfd ();
2914   if (fd == -1)
2915     {
2916       err = -1;
2917       goto out;
2918     }
2919
2920   err = es_func_fd_create (&cookie, fd, modeflags, 0);
2921   if (err)
2922     goto out;
2923
2924   create_called = 1;
2925   err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags);
2926
2927  out:
2928
2929   if (err)
2930     {
2931       if (create_called)
2932         es_func_fd_destroy (cookie);
2933       else if (fd != -1)
2934         close (fd);
2935       stream = NULL;
2936     }
2937   
2938   return stream;
2939 }
2940
2941
2942 int
2943 es_setvbuf (estream_t ES__RESTRICT stream,
2944             char *ES__RESTRICT buf, int type, size_t size)
2945 {
2946   int err;
2947   
2948   if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
2949       && (! ((! size) && (type != _IONBF))))
2950     {
2951       ESTREAM_LOCK (stream);
2952       err = es_set_buffering (stream, buf, type, size);
2953       ESTREAM_UNLOCK (stream);
2954     }
2955   else
2956     {
2957       errno = EINVAL;
2958       err = -1;
2959     }
2960
2961   return err;
2962 }
2963
2964
2965 void
2966 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
2967 {
2968   ESTREAM_LOCK (stream);
2969   es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
2970   ESTREAM_UNLOCK (stream);
2971 }
2972
2973 void
2974 es_opaque_set (estream_t stream, void *opaque)
2975 {
2976   ESTREAM_LOCK (stream);
2977   es_opaque_ctrl (stream, opaque, NULL);
2978   ESTREAM_UNLOCK (stream);
2979 }
2980
2981
2982 void *
2983 es_opaque_get (estream_t stream)
2984 {
2985   void *opaque;
2986   
2987   ESTREAM_LOCK (stream);
2988   es_opaque_ctrl (stream, NULL, &opaque);
2989   ESTREAM_UNLOCK (stream);
2990
2991   return opaque;
2992 }
2993
2994 /* Print a BUFFER to STREAM while replacing all control characters and
2995    the characters in DELIMITERS by standard C escape sequences.
2996    Returns 0 on success or -1 on error.  If BYTES_WRITTEN is not NULL
2997    the number of bytes actually written are stored at this
2998    address.  */
2999 int 
3000 es_write_sanitized (estream_t ES__RESTRICT stream,
3001                     const void * ES__RESTRICT buffer, size_t length,
3002                     const char * delimiters, 
3003                     size_t * ES__RESTRICT bytes_written)
3004 {
3005   const unsigned char *p = buffer;
3006   size_t count = 0;
3007   int ret;
3008
3009   ESTREAM_LOCK (stream);
3010   for (; length; length--, p++, count++)
3011     {
3012       if (*p < 0x20 
3013           || (*p >= 0x7f && *p < 0xa0)
3014           || (delimiters 
3015               && (strchr (delimiters, *p) || *p == '\\')))
3016         {
3017           es_putc_unlocked ('\\', stream);
3018           count++;
3019           if (*p == '\n')
3020             {
3021               es_putc_unlocked ('n', stream);
3022               count++;
3023             }
3024           else if (*p == '\r')
3025             {
3026               es_putc_unlocked ('r', stream);
3027               count++;
3028             }
3029           else if (*p == '\f')
3030             {
3031               es_putc_unlocked ('f', stream);
3032               count++;
3033             }
3034           else if (*p == '\v')
3035             {
3036               es_putc_unlocked ('v', stream);
3037               count++;
3038             }
3039           else if (*p == '\b')
3040             {
3041               es_putc_unlocked ('b', stream);
3042               count++;
3043             }
3044           else if (!*p)
3045             {
3046               es_putc_unlocked('0', stream);
3047               count++;
3048             }
3049           else
3050             {
3051               es_fprintf_unlocked (stream, "x%02x", *p);
3052               count += 3;
3053             }
3054         }
3055       else
3056         {
3057           es_putc_unlocked (*p, stream);
3058           count++;
3059         }
3060     }
3061
3062   if (bytes_written)
3063     *bytes_written = count;
3064   ret =  es_ferror_unlocked (stream)? -1 : 0;
3065   ESTREAM_UNLOCK (stream);
3066
3067   return ret;
3068 }
3069
3070
3071 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3072    RESERVED must be 0.  Returns 0 on success or -1 on error.  If
3073    BYTES_WRITTEN is not NULL the number of bytes actually written are
3074    stored at this address.  */
3075 int
3076 es_write_hexstring (estream_t ES__RESTRICT stream,
3077                     const void *ES__RESTRICT buffer, size_t length,
3078                     int reserved, size_t *ES__RESTRICT bytes_written )
3079 {
3080   int ret;
3081   const unsigned char *s;
3082   size_t count = 0;
3083
3084 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3085
3086   if (!length)
3087     return 0;
3088
3089   ESTREAM_LOCK (stream);
3090
3091   for (s = buffer; length; s++, length--)
3092     {
3093       es_putc_unlocked ( tohex ((*s>>4)&15), stream);
3094       es_putc_unlocked ( tohex (*s&15), stream);
3095       count += 2;
3096     }
3097
3098   if (bytes_written)
3099     *bytes_written = count;
3100   ret = es_ferror_unlocked (stream)? -1 : 0;
3101
3102   ESTREAM_UNLOCK (stream);
3103
3104   return ret;
3105
3106 #undef tohex
3107 }
3108
3109
3110
3111 #ifdef GNUPG_MAJOR_VERSION
3112 /* Special estream function to print an UTF8 string in the native
3113    encoding.  The interface is the same as es_write_sanitized, however
3114    only one delimiter may be supported. 
3115
3116    THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3117 int
3118 es_write_sanitized_utf8_buffer (estream_t stream,
3119                                 const void *buffer, size_t length, 
3120                                 const char *delimiters, size_t *bytes_written)
3121 {
3122   const char *p = buffer;
3123   size_t i;
3124
3125   /* We can handle plain ascii simpler, so check for it first. */
3126   for (i=0; i < length; i++ ) 
3127     {
3128       if ( (p[i] & 0x80) )
3129         break;
3130     }
3131   if (i < length)
3132     {
3133       int delim = delimiters? *delimiters : 0;
3134       char *buf;
3135       int ret;
3136
3137       /*(utf8 conversion already does the control character quoting). */
3138       buf = utf8_to_native (p, length, delim);
3139       if (bytes_written)
3140         *bytes_written = strlen (buf);
3141       ret = es_fputs (buf, stream);
3142       xfree (buf);
3143       return i;
3144     }
3145   else
3146     return es_write_sanitized (stream, p, length, delimiters, bytes_written);
3147 }
3148 #endif /*GNUPG_MAJOR_VERSION*/