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