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