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