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