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