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