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