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