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