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