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