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