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