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