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