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