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