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