2009-12-08 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / estream.c
1 /* estream.c - Extended Stream I/O Library
2  * Copyright (C) 2004, 2005, 2006, 2007, 2009 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
20 #ifdef USE_ESTREAM_SUPPORT_H
21 # include <estream-support.h>
22 #endif
23
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27
28 #if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
29 # define HAVE_W32_SYSTEM 1
30 #endif
31
32 #include <sys/types.h>
33 #include <sys/file.h>
34 #include <sys/stat.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <stdarg.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <stddef.h>
43 #include <assert.h>
44 #ifdef HAVE_W32_SYSTEM
45 # include <windows.h>
46 #endif
47
48 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth.  */
49 # undef HAVE_PTH
50 # undef USE_GNU_PTH
51 #endif
52
53 #ifdef HAVE_PTH
54 # include <pth.h>
55 #endif
56
57 /* This is for the special hack to use estream.c in GnuPG.  */
58 #ifdef GNUPG_MAJOR_VERSION
59 # include "../common/util.h"
60 #endif
61
62 #ifndef HAVE_MKSTEMP
63 int mkstemp (char *template);
64 #endif
65
66 #ifndef HAVE_MEMRCHR
67 void *memrchr (const void *block, int c, size_t size);
68 #endif
69
70 #include <estream.h>
71 #include <estream-printf.h>
72
73 \f
74
75 #ifndef O_BINARY
76 #define O_BINARY 0
77 #endif
78
79 /* Generally used types.  */
80
81 typedef void *(*func_realloc_t) (void *mem, size_t size);
82 typedef void (*func_free_t) (void *mem);
83
84
85 \f
86
87 /* Buffer management layer.  */
88
89 #define BUFFER_BLOCK_SIZE  BUFSIZ
90 #define BUFFER_UNREAD_SIZE 16
91
92 \f
93
94 /* Locking.  */
95
96 #ifdef HAVE_PTH
97
98 typedef pth_mutex_t estream_mutex_t;
99 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
100 # define ESTREAM_MUTEX_LOCK(mutex)        \
101   pth_mutex_acquire (&(mutex), 0, NULL)
102 # define ESTREAM_MUTEX_UNLOCK(mutex)      \
103   pth_mutex_release (&(mutex))
104 # define ESTREAM_MUTEX_TRYLOCK(mutex)     \
105   ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
106 # define ESTREAM_MUTEX_INITIALIZE(mutex)  \
107   pth_mutex_init    (&(mutex))
108 #else
109
110 typedef void *estream_mutex_t;
111
112 static inline void
113 dummy_mutex_call_void (estream_mutex_t mutex)
114 {
115   (void)mutex;
116 }
117
118 static inline int
119 dummy_mutex_call_int (estream_mutex_t mutex)
120 {
121   (void)mutex;
122   return 0;
123 }
124
125 # define ESTREAM_MUTEX_INITIALIZER NULL
126 # define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex))
127 # define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex))
128 # define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex))
129 # define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex))
130 #endif
131
132 /* Primitive system I/O.  */
133
134 #ifdef HAVE_PTH
135 # define ESTREAM_SYS_READ  es_pth_read
136 # define ESTREAM_SYS_WRITE es_pth_write
137 #else
138 # define ESTREAM_SYS_READ  read
139 # define ESTREAM_SYS_WRITE write
140 #endif
141
142 /* Misc definitions.  */
143
144 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
145
146 /* An internal stream object.  */
147
148 struct estream_internal
149 {
150   unsigned char buffer[BUFFER_BLOCK_SIZE];
151   unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
152   estream_mutex_t lock;          /* Lock. */
153   void *cookie;                  /* Cookie.                */
154   void *opaque;                  /* Opaque data.           */
155   unsigned int modeflags;        /* Flags for the backend. */
156   off_t offset;
157   es_cookie_read_function_t func_read;
158   es_cookie_write_function_t func_write;
159   es_cookie_seek_function_t func_seek;
160   es_cookie_close_function_t func_close;
161   int strategy;
162   int fd;
163   struct
164   {
165     unsigned int err: 1;
166     unsigned int eof: 1;
167   } indicators;
168   unsigned int deallocate_buffer: 1;
169   unsigned int print_err: 1;     /* Error in print_fun_writer.  */
170   int print_errno;               /* Errno from print_fun_writer.  */
171   size_t print_ntotal;           /* Bytes written from in print_fun_writer. */
172   FILE *print_fp;                /* Stdio stream used by print_fun_writer.  */
173 };
174
175
176 typedef struct estream_internal *estream_internal_t;
177
178 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
179 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
180 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
181
182 /* Stream list.  */
183
184 typedef struct estream_list *estream_list_t;
185
186 struct estream_list
187 {
188   estream_t car;
189   estream_list_t cdr;
190   estream_list_t *prev_cdr;
191 };
192
193 static estream_list_t estream_list;
194 static estream_mutex_t estream_list_lock;
195
196 #define ESTREAM_LIST_LOCK   ESTREAM_MUTEX_LOCK   (estream_list_lock)
197 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
198
199 #ifndef EOPNOTSUPP
200 # define EOPNOTSUPP ENOSYS
201 #endif
202
203
204 \f
205
206 /* Macros.  */
207
208 /* Calculate array dimension.  */
209 #ifndef DIM
210 #define DIM(array) (sizeof (array) / sizeof (*array))
211 #endif
212
213 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
214
215
216 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
217    VARIABLE is zero.  */
218 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
219   do                                                           \
220     {                                                          \
221       tmp_variable = expression;                               \
222       if ((! variable) && tmp_variable)                        \
223         variable = tmp_variable;                               \
224     }                                                          \
225   while (0)
226
227
228 /* Malloc wrappers to overcome problems on some older OSes.  */
229 static void *
230 mem_alloc (size_t n)
231 {
232   if (!n)
233     n++;
234   return malloc (n);
235 }
236
237 static void *
238 mem_realloc (void *p, size_t n)
239 {
240   if (!p)
241     return mem_alloc (n);
242   return realloc (p, n);
243 }
244
245 static void
246 mem_free (void *p)
247 {
248   if (p)
249     free (p);
250 }
251
252
253
254 /*
255  * List manipulation.
256  */
257
258 /* Add STREAM to the list of registered stream objects.  */
259 static int
260 es_list_add (estream_t stream)
261 {
262   estream_list_t list_obj;
263   int ret;
264
265   list_obj = mem_alloc (sizeof (*list_obj));
266   if (! list_obj)
267     ret = -1;
268   else
269     {
270       ESTREAM_LIST_LOCK;
271       list_obj->car = stream;
272       list_obj->cdr = estream_list;
273       list_obj->prev_cdr = &estream_list;
274       if (estream_list)
275         estream_list->prev_cdr = &list_obj->cdr;
276       estream_list = list_obj;
277       ESTREAM_LIST_UNLOCK;
278       ret = 0;
279     }
280
281   return ret;
282 }
283
284 /* Remove STREAM from the list of registered stream objects.  */
285 static void
286 es_list_remove (estream_t stream)
287 {
288   estream_list_t list_obj;
289   
290   ESTREAM_LIST_LOCK;
291   for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
292     if (list_obj->car == stream)
293       {
294         *list_obj->prev_cdr = list_obj->cdr;
295         if (list_obj->cdr)
296           list_obj->cdr->prev_cdr = list_obj->prev_cdr;
297         mem_free (list_obj);
298         break;
299       }
300   ESTREAM_LIST_UNLOCK;
301 }
302
303 /* Type of an stream-iterator-function.  */
304 typedef int (*estream_iterator_t) (estream_t stream);
305
306 /* Iterate over list of registered streams, calling ITERATOR for each
307    of them.  */
308 static int
309 es_list_iterate (estream_iterator_t iterator)
310 {
311   estream_list_t list_obj;
312   int ret = 0;
313
314   ESTREAM_LIST_LOCK;
315   for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
316     ret |= (*iterator) (list_obj->car);
317   ESTREAM_LIST_UNLOCK;
318
319   return ret;
320 }
321
322
323 \f
324 /*
325  * I/O Helper
326  *
327  * Unfortunately our Pth emulation for Windows expects system handles
328  * for pth_read and pth_write.  We use a simple approach to fix this:
329  * If the function returns an error we fall back to a vanilla read or
330  * write, assuming that we do I/O on a plain file where the operation
331  * can't block.
332  */
333 #ifdef HAVE_PTH
334 static int
335 es_pth_read (int fd, void *buffer, size_t size)
336 {
337 # ifdef HAVE_W32_SYSTEM
338   int rc = pth_read (fd, buffer, size);
339   if (rc == -1 && errno == EINVAL)
340     rc = read (fd, buffer, size);
341   return rc;
342 # else /*!HAVE_W32_SYSTEM*/
343   return pth_read (fd, buffer, size);
344 # endif /* !HAVE_W32_SYSTEM*/
345 }
346
347 static int
348 es_pth_write (int fd, const void *buffer, size_t size)
349 {
350 # ifdef HAVE_W32_SYSTEM
351   int rc = pth_write (fd, buffer, size);
352   if (rc == -1 && errno == EINVAL)
353     rc = write (fd, buffer, size);
354   return rc;
355 # else /*!HAVE_W32_SYSTEM*/
356   return pth_write (fd, buffer, size);
357 # endif /* !HAVE_W32_SYSTEM*/
358 }
359 #endif /*HAVE_PTH*/
360
361 \f
362
363 /*
364  * Initialization.
365  */
366
367 static int
368 es_init_do (void)
369 {
370 #ifdef HAVE_PTH
371   static int initialized;
372
373   if (!initialized)
374     {
375       if (!pth_init () && errno != EPERM )
376         return -1;
377       if (pth_mutex_init (&estream_list_lock))
378         initialized = 1;
379     }
380 #endif
381   return 0;
382 }
383
384 \f
385
386 /*
387  * I/O methods.
388  */
389
390 /* Implementation of Memory I/O.  */
391
392 /* Cookie for memory objects.  */
393 typedef struct estream_cookie_mem
394 {
395   unsigned int modeflags;       /* Open flags.  */
396   unsigned char *memory;        /* Allocated data buffer.  */
397   size_t memory_size;           /* Allocated size of MEMORY.  */
398   size_t memory_limit;          /* Caller supplied maximum allowed
399                                    allocation size or 0 for no limit.  */
400   size_t offset;                /* Current offset in MEMORY.  */
401   size_t data_len;              /* Used length of data in MEMORY.  */
402   size_t block_size;            /* Block size.  */
403   struct {
404     unsigned int grow: 1;       /* MEMORY is allowed to grow.  */
405   } flags;
406   func_realloc_t func_realloc;
407   func_free_t func_free;
408 } *estream_cookie_mem_t;
409
410
411 /* Create function for memory objects.  DATA is either NULL or a user
412    supplied buffer with the initial conetnt of the memory buffer.  If
413    DATA is NULL, DATA_N and DATA_LEN need to be 0 as well.  If DATA is
414    not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the
415    used length in DATA.  */
416 static int
417 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
418                     unsigned char *ES__RESTRICT data, size_t data_n,
419                     size_t data_len,
420                     size_t block_size, unsigned int grow,
421                     func_realloc_t func_realloc, func_free_t func_free,
422                     unsigned int modeflags,
423                     size_t memory_limit)
424 {
425   estream_cookie_mem_t mem_cookie;
426   int err;
427
428   if (!data && (data_n || data_len))
429     {
430       errno = EINVAL;
431       return -1;
432     }
433
434   mem_cookie = mem_alloc (sizeof (*mem_cookie));
435   if (!mem_cookie)
436     err = -1;
437   else
438     {
439       mem_cookie->modeflags = modeflags;
440       mem_cookie->memory = data;
441       mem_cookie->memory_size = data_n;
442       mem_cookie->memory_limit = memory_limit;
443       mem_cookie->offset = 0;
444       mem_cookie->data_len = data_len;
445       mem_cookie->block_size = block_size;
446       mem_cookie->flags.grow = !!grow;
447       mem_cookie->func_realloc = func_realloc ? func_realloc : mem_realloc;
448       mem_cookie->func_free = func_free ? func_free : mem_free;
449       *cookie = mem_cookie;
450       err = 0;
451     }
452
453   return err;
454 }
455
456
457 /* Read function for memory objects.  */
458 static ssize_t
459 es_func_mem_read (void *cookie, void *buffer, size_t size)
460 {
461   estream_cookie_mem_t mem_cookie = cookie;
462   ssize_t ret;
463
464   if (size > mem_cookie->data_len - mem_cookie->offset)
465     size = mem_cookie->data_len - mem_cookie->offset;
466
467   if (size)
468     {
469       memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
470       mem_cookie->offset += size;
471     }
472   
473   ret = size;
474   return ret;
475 }
476
477
478 /* Write function for memory objects.  */
479 static ssize_t
480 es_func_mem_write (void *cookie, const void *buffer, size_t size)
481 {
482   estream_cookie_mem_t mem_cookie = cookie;
483   ssize_t ret;
484   size_t nleft;
485
486   if (!size)
487     return 0;  /* A flush is a NOP for memory objects.  */
488
489   if (mem_cookie->modeflags & O_APPEND)
490     {
491       /* Append to data.  */
492       mem_cookie->offset = mem_cookie->data_len;
493     }
494
495   assert (mem_cookie->memory_size >= mem_cookie->offset);
496   nleft = mem_cookie->memory_size - mem_cookie->offset;
497   
498   /* If we are not allowed to grow limit the size to the left space.  */
499   if (!mem_cookie->flags.grow && size > nleft)
500     size = nleft;
501
502   /* Enlarge the memory buffer if needed.  */
503   if (size > nleft)
504     {
505       unsigned char *newbuf;
506       size_t newsize;
507
508       if (!mem_cookie->memory_size)
509         newsize = size;  /* Not yet allocated.  */
510       else
511         newsize = mem_cookie->memory_size + (nleft - size);
512       if (newsize < mem_cookie->offset)
513         {
514           errno = EINVAL;
515           return -1;
516         }
517
518       /* Round up to the next block length.  BLOCK_SIZE should always
519          be set; we check anyway.  */
520       if (mem_cookie->block_size)
521         {
522           newsize += mem_cookie->block_size - 1;
523           if (newsize < mem_cookie->offset)
524             {
525               errno = EINVAL;
526               return -1;
527             }
528           newsize /= mem_cookie->block_size;
529           newsize *= mem_cookie->block_size;
530         }
531
532       /* Check for a total limit.  */
533       if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
534         {
535           errno = ENOSPC;
536           return -1;
537         }
538       
539       newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
540       if (!newbuf)
541         return -1;
542       
543       mem_cookie->memory = newbuf;
544       mem_cookie->memory_size = newsize;
545
546       assert (mem_cookie->memory_size >= mem_cookie->offset);
547       nleft = mem_cookie->memory_size - mem_cookie->offset;
548       
549       assert (size <= nleft);
550     }
551       
552   memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
553   if (mem_cookie->offset + size > mem_cookie->data_len)
554     mem_cookie->data_len = mem_cookie->offset + size;
555   mem_cookie->offset += size;
556
557   ret = size;
558   return ret;
559 }
560
561
562 /* Seek function for memory objects.  */
563 static int
564 es_func_mem_seek (void *cookie, off_t *offset, int whence)
565 {
566   estream_cookie_mem_t mem_cookie = cookie;
567   off_t pos_new;
568
569   switch (whence)
570     {
571     case SEEK_SET:
572       pos_new = *offset;
573       break;
574
575     case SEEK_CUR:
576       pos_new = mem_cookie->offset += *offset;
577       break;
578
579     case SEEK_END:
580       pos_new = mem_cookie->data_len += *offset;
581       break;
582
583     default:
584       errno = EINVAL;
585       return -1;
586     }
587
588   if (pos_new > mem_cookie->memory_size)
589     {
590       size_t newsize;
591       void *newbuf;
592
593       if (!mem_cookie->flags.grow)
594         {
595           errno = ENOSPC;
596           return -1;
597         }
598
599       newsize = pos_new + mem_cookie->block_size - 1;
600       if (newsize < pos_new)
601         {
602           errno = EINVAL;
603           return -1;
604         }
605       newsize /= mem_cookie->block_size;
606       newsize *= mem_cookie->block_size;
607
608       if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
609         {
610           errno = ENOSPC;
611           return -1;
612         }
613       
614       newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
615       if (!newbuf)
616         return -1;
617
618       mem_cookie->memory = newbuf;
619       mem_cookie->memory_size = newsize;
620     }
621
622   if (pos_new > mem_cookie->data_len)
623     {
624       /* Fill spare space with zeroes.  */
625       memset (mem_cookie->memory + mem_cookie->data_len,
626               0, pos_new - mem_cookie->data_len);
627       mem_cookie->data_len = pos_new;
628     }
629
630   mem_cookie->offset = pos_new;
631   *offset = pos_new;
632
633   return 0;
634 }
635
636
637 /* Destroy function for memory objects.  */
638 static int
639 es_func_mem_destroy (void *cookie)
640 {
641   estream_cookie_mem_t mem_cookie = cookie;
642
643   if (cookie)
644     {
645       mem_cookie->func_free (mem_cookie->memory);
646       mem_free (mem_cookie);
647     }
648   return 0;
649 }
650
651
652 static es_cookie_io_functions_t estream_functions_mem =
653   {
654     es_func_mem_read,
655     es_func_mem_write,
656     es_func_mem_seek,
657     es_func_mem_destroy
658   };
659
660
661 \f
662 /* Implementation of fd I/O.  */
663
664 /* Cookie for fd objects.  */
665 typedef struct estream_cookie_fd
666 {
667   int fd;        /* The file descriptor we are using for actual output.  */
668   int no_close;  /* If set we won't close the file descriptor.  */
669 } *estream_cookie_fd_t;
670
671 /* Create function for fd objects.  */
672 static int
673 es_func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
674 {
675   estream_cookie_fd_t fd_cookie;
676   int err;
677
678   fd_cookie = mem_alloc (sizeof (*fd_cookie));
679   if (! fd_cookie)
680     err = -1;
681   else
682     {
683 #ifdef HAVE_DOSISH_SYSTEM
684       /* Make sure it is in binary mode if requested.  */
685       if ( (modeflags & O_BINARY) )
686         setmode (fd, O_BINARY);
687 #else
688       (void)modeflags;
689 #endif
690       fd_cookie->fd = fd;
691       fd_cookie->no_close = no_close;
692       *cookie = fd_cookie;
693       err = 0;
694     }
695   
696   return err;
697 }
698
699 /* Read function for fd objects.  */
700 static ssize_t
701 es_func_fd_read (void *cookie, void *buffer, size_t size)
702
703 {
704   estream_cookie_fd_t file_cookie = cookie;
705   ssize_t bytes_read;
706
707   do 
708     bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
709   while (bytes_read == -1 && errno == EINTR);
710
711   return bytes_read;
712 }
713
714 /* Write function for fd objects.  */
715 static ssize_t
716 es_func_fd_write (void *cookie, const void *buffer, size_t size)
717                            
718 {
719   estream_cookie_fd_t file_cookie = cookie;
720   ssize_t bytes_written;
721
722   do
723     bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
724   while (bytes_written == -1 && errno == EINTR);
725
726   return bytes_written;
727 }
728
729 /* Seek function for fd objects.  */
730 static int
731 es_func_fd_seek (void *cookie, off_t *offset, int whence)
732 {
733   estream_cookie_fd_t file_cookie = cookie;
734   off_t offset_new;
735   int err;
736
737   offset_new = lseek (file_cookie->fd, *offset, whence);
738   if (offset_new == -1)
739     err = -1;
740   else
741     {
742       *offset = offset_new;
743       err = 0;
744     }
745
746   return err;
747 }
748
749 /* Destroy function for fd objects.  */
750 static int
751 es_func_fd_destroy (void *cookie)
752 {
753   estream_cookie_fd_t fd_cookie = cookie;
754   int err;
755
756   if (fd_cookie)
757     {
758       err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
759       mem_free (fd_cookie);
760     }
761   else
762     err = 0;
763
764   return err;
765 }
766
767
768 static es_cookie_io_functions_t estream_functions_fd =
769   {
770     es_func_fd_read,
771     es_func_fd_write,
772     es_func_fd_seek,
773     es_func_fd_destroy
774   };
775
776
777
778 \f
779 /* Implementation of FILE* I/O.  */
780
781 /* Cookie for fp objects.  */
782 typedef struct estream_cookie_fp
783 {
784   FILE *fp;      /* The file pointer we are using for actual output.  */
785   int no_close;  /* If set we won't close the file pointer.  */
786 } *estream_cookie_fp_t;
787
788 /* Create function for fd objects.  */
789 static int
790 es_func_fp_create (void **cookie, FILE *fp, 
791                    unsigned int modeflags, int no_close)
792 {
793   estream_cookie_fp_t fp_cookie;
794   int err;
795
796   fp_cookie = mem_alloc (sizeof *fp_cookie);
797   if (!fp_cookie)
798     err = -1;
799   else
800     {
801 #ifdef HAVE_DOSISH_SYSTEM
802       /* Make sure it is in binary mode if requested.  */
803       if ( (modeflags & O_BINARY) )
804         setmode (fileno (fp), O_BINARY);
805 #else
806       (void)modeflags;
807 #endif
808       fp_cookie->fp = fp;
809       fp_cookie->no_close = no_close;
810       *cookie = fp_cookie;
811       err = 0;
812     }
813   
814   return err;
815 }
816
817 /* Read function for FILE* objects.  */
818 static ssize_t
819 es_func_fp_read (void *cookie, void *buffer, size_t size)
820
821 {
822   estream_cookie_fp_t file_cookie = cookie;
823   ssize_t bytes_read;
824
825   bytes_read = fread (buffer, 1, size, file_cookie->fp);
826   if (!bytes_read && ferror (file_cookie->fp))
827     return -1;
828   return bytes_read;
829 }
830
831 /* Write function for FILE* objects.  */
832 static ssize_t
833 es_func_fp_write (void *cookie, const void *buffer, size_t size)
834                            
835 {
836   estream_cookie_fp_t file_cookie = cookie;
837   size_t bytes_written;
838
839   bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
840   if (bytes_written != size)
841     return -1;
842   return bytes_written;
843 }
844
845 /* Seek function for FILE* objects.  */
846 static int
847 es_func_fp_seek (void *cookie, off_t *offset, int whence)
848 {
849   estream_cookie_fp_t file_cookie = cookie;
850   long int offset_new;
851
852   if ( fseek (file_cookie->fp, (long int)*offset, whence) )
853     {
854       fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", errno,strerror (errno));
855     return -1;
856     }
857
858   offset_new = ftell (file_cookie->fp);
859   if (offset_new == -1)
860     {
861       fprintf (stderr, "\nftell failed: errno=%d (%s)\n", errno,strerror (errno));
862     return -1;
863     }
864   *offset = offset_new;
865   return 0;
866 }
867
868 /* Destroy function for fd objects.  */
869 static int
870 es_func_fp_destroy (void *cookie)
871 {
872   estream_cookie_fp_t fp_cookie = cookie;
873   int err;
874
875   if (fp_cookie)
876     {
877       fflush (fp_cookie->fp);
878       err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
879       mem_free (fp_cookie);
880     }
881   else
882     err = 0;
883
884   return err;
885 }
886
887
888 static es_cookie_io_functions_t estream_functions_fp =
889   {
890     es_func_fp_read,
891     es_func_fp_write,
892     es_func_fp_seek,
893     es_func_fp_destroy
894   };
895
896
897
898 \f
899 /* Implementation of file I/O.  */
900
901 /* Create function for file objects.  */
902 static int
903 es_func_file_create (void **cookie, int *filedes,
904                      const char *path, unsigned int modeflags)
905 {
906   estream_cookie_fd_t file_cookie;
907   int err;
908   int fd;
909
910   err = 0;
911   fd = -1;
912
913   file_cookie = mem_alloc (sizeof (*file_cookie));
914   if (! file_cookie)
915     {
916       err = -1;
917       goto out;
918     }
919
920   fd = open (path, modeflags, ES_DEFAULT_OPEN_MODE);
921   if (fd == -1)
922     {
923       err = -1;
924       goto out;
925     }
926 #ifdef HAVE_DOSISH_SYSTEM
927   /* Make sure it is in binary mode if requested.  */
928   if ( (modeflags & O_BINARY) )
929     setmode (fd, O_BINARY);
930 #endif
931
932   file_cookie->fd = fd;
933   file_cookie->no_close = 0;
934   *cookie = file_cookie;
935   *filedes = fd;
936
937  out:
938
939   if (err)
940     mem_free (file_cookie);
941
942   return err;
943 }
944
945 static es_cookie_io_functions_t estream_functions_file =
946   {
947     es_func_fd_read,
948     es_func_fd_write,
949     es_func_fd_seek,
950     es_func_fd_destroy
951   };
952
953 \f
954 static int
955 es_convert_mode (const char *mode, unsigned int *modeflags)
956 {
957   unsigned int omode, oflags;
958
959   switch (*mode)
960     {
961     case 'r':
962       omode = O_RDONLY;
963       oflags = 0;
964       break;
965     case 'w':
966       omode = O_WRONLY;
967       oflags = O_TRUNC | O_CREAT;
968       break;
969     case 'a':
970       omode = O_WRONLY;
971       oflags = O_APPEND | O_CREAT;
972       break;
973     default:
974       errno = EINVAL;
975       return -1;
976     }
977   for (mode++; *mode; mode++)
978     {
979       switch (*mode)
980         {
981         case '+':
982           omode = O_RDWR;
983           break;
984         case 'b':
985           oflags |= O_BINARY;
986           break;
987         case 'x':
988           oflags |= O_EXCL;
989           break;
990         default: /* Ignore unknown flags.  */
991           break; 
992         }
993     }
994
995   *modeflags = (omode | oflags);
996   return 0;
997 }
998
999 \f
1000
1001 /*
1002  * Low level stream functionality.
1003  */
1004
1005 static int
1006 es_fill (estream_t stream)
1007 {
1008   size_t bytes_read = 0;
1009   int err;
1010
1011   if (!stream->intern->func_read)
1012     {
1013       errno = EOPNOTSUPP;
1014       err = -1;
1015     }
1016   else
1017     {
1018       es_cookie_read_function_t func_read = stream->intern->func_read;
1019       ssize_t ret;
1020
1021       ret = (*func_read) (stream->intern->cookie,
1022                           stream->buffer, stream->buffer_size);
1023       if (ret == -1)
1024         {
1025           bytes_read = 0;
1026           err = -1;
1027         }
1028       else
1029         {
1030           bytes_read = ret;
1031           err = 0;
1032         }
1033     }
1034
1035   if (err)
1036     stream->intern->indicators.err = 1;
1037   else if (!bytes_read)
1038     stream->intern->indicators.eof = 1;
1039
1040   stream->intern->offset += stream->data_len;
1041   stream->data_len = bytes_read;
1042   stream->data_offset = 0;
1043
1044   return err;
1045 }
1046
1047 static int
1048 es_flush (estream_t stream)
1049 {
1050   es_cookie_write_function_t func_write = stream->intern->func_write;
1051   int err;
1052
1053   assert (stream->flags.writing);
1054
1055   if (stream->data_offset)
1056     {
1057       size_t bytes_written;
1058       size_t data_flushed;
1059       ssize_t ret;
1060
1061       if (! func_write)
1062         {
1063           err = EOPNOTSUPP;
1064           goto out;
1065         }
1066
1067       /* Note: to prevent an endless loop caused by user-provided
1068          write-functions that pretend to have written more bytes than
1069          they were asked to write, we have to check for
1070          "(stream->data_offset - data_flushed) > 0" instead of
1071          "stream->data_offset - data_flushed".  */
1072       
1073       data_flushed = 0;
1074       err = 0;
1075       
1076       while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
1077         {
1078           ret = (*func_write) (stream->intern->cookie,
1079                                stream->buffer + data_flushed,
1080                                stream->data_offset - data_flushed);
1081           if (ret == -1)
1082             {
1083               bytes_written = 0;
1084               err = -1;
1085             }
1086           else
1087             bytes_written = ret;
1088
1089           data_flushed += bytes_written;
1090           if (err)
1091             break;
1092         }
1093
1094       stream->data_flushed += data_flushed;
1095       if (stream->data_offset == data_flushed)
1096         {
1097           stream->intern->offset += stream->data_offset;
1098           stream->data_offset = 0;
1099           stream->data_flushed = 0;
1100
1101           /* Propagate flush event.  */
1102           (*func_write) (stream->intern->cookie, NULL, 0);
1103         }
1104     }
1105   else
1106     err = 0;
1107
1108  out:
1109     
1110   if (err)
1111     stream->intern->indicators.err = 1;
1112
1113   return err;
1114 }
1115
1116 /* Discard buffered data for STREAM.  */
1117 static void
1118 es_empty (estream_t stream)
1119 {
1120   assert (!stream->flags.writing);
1121   stream->data_len = 0;
1122   stream->data_offset = 0;
1123   stream->unread_data_len = 0;
1124 }
1125
1126 /* Initialize STREAM.  */
1127 static void
1128 es_initialize (estream_t stream,
1129                void *cookie, int fd, es_cookie_io_functions_t functions,
1130                unsigned int modeflags)
1131 {
1132   stream->intern->cookie = cookie;
1133   stream->intern->opaque = NULL;
1134   stream->intern->offset = 0;
1135   stream->intern->func_read = functions.func_read;
1136   stream->intern->func_write = functions.func_write;
1137   stream->intern->func_seek = functions.func_seek;
1138   stream->intern->func_close = functions.func_close;
1139   stream->intern->strategy = _IOFBF;
1140   stream->intern->fd = fd;
1141   stream->intern->print_err = 0;
1142   stream->intern->print_errno = 0;
1143   stream->intern->print_ntotal = 0;
1144   stream->intern->print_fp = NULL;
1145   stream->intern->indicators.err = 0;
1146   stream->intern->indicators.eof = 0;
1147   stream->intern->deallocate_buffer = 0;
1148
1149   stream->data_len = 0;
1150   stream->data_offset = 0;
1151   stream->data_flushed = 0;
1152   stream->unread_data_len = 0;
1153   /* Depending on the modeflags we set whether we start in writing or
1154      reading mode.  This is required in case we are working on a
1155      wronly stream which is not seeekable (like stdout).  Without this
1156      pre-initialization we would do a seek at the first write call and
1157      as this will fail no utput will be delivered. */
1158   if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1159     stream->flags.writing = 1;
1160   else
1161     stream->flags.writing = 0;
1162 }
1163
1164 /* Deinitialize STREAM.  */
1165 static int
1166 es_deinitialize (estream_t stream)
1167 {
1168   es_cookie_close_function_t func_close;
1169   int err, tmp_err;
1170
1171   if (stream->intern->print_fp)
1172     {
1173       int save_errno = errno;
1174       fclose (stream->intern->print_fp);
1175       stream->intern->print_fp = NULL;
1176       errno = save_errno;
1177     }
1178
1179   func_close = stream->intern->func_close;
1180
1181   err = 0;
1182   if (stream->flags.writing)
1183     SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1184   if (func_close)
1185     SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1186
1187   
1188   return err;
1189 }
1190
1191 /* Create a new stream object, initialize it.  */
1192 static int
1193 es_create (estream_t *stream, void *cookie, int fd,
1194            es_cookie_io_functions_t functions, unsigned int modeflags)
1195 {
1196   estream_internal_t stream_internal_new;
1197   estream_t stream_new;
1198   int err;
1199
1200   stream_new = NULL;
1201   stream_internal_new = NULL;
1202
1203   stream_new = mem_alloc (sizeof (*stream_new));
1204   if (! stream_new)
1205     {
1206       err = -1;
1207       goto out;
1208     }
1209
1210   stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
1211   if (! stream_internal_new)
1212     {
1213       err = -1;
1214       goto out;
1215     }
1216
1217   stream_new->buffer = stream_internal_new->buffer;
1218   stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1219   stream_new->unread_buffer = stream_internal_new->unread_buffer;
1220   stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1221   stream_new->intern = stream_internal_new;
1222
1223   ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
1224   es_initialize (stream_new, cookie, fd, functions, modeflags);
1225
1226   err = es_list_add (stream_new);
1227   if (err)
1228     goto out;
1229
1230   *stream = stream_new;
1231
1232  out:
1233
1234   if (err)
1235     {
1236       if (stream_new)
1237         {
1238           es_deinitialize (stream_new);
1239           mem_free (stream_new);
1240         }
1241     }
1242
1243   return err;
1244 }
1245
1246 /* Deinitialize a stream object and destroy it.  */
1247 static int
1248 es_destroy (estream_t stream)
1249 {
1250   int err = 0;
1251
1252   if (stream)
1253     {
1254       es_list_remove (stream);
1255       err = es_deinitialize (stream);
1256       mem_free (stream->intern);
1257       mem_free (stream);
1258     }
1259
1260   return err;
1261 }
1262
1263 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1264    unbuffered-mode, storing the amount of bytes read in
1265    *BYTES_READ.  */
1266 static int
1267 es_read_nbf (estream_t ES__RESTRICT stream,
1268              unsigned char *ES__RESTRICT buffer,
1269              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1270 {
1271   es_cookie_read_function_t func_read = stream->intern->func_read;
1272   size_t data_read;
1273   ssize_t ret;
1274   int err;
1275
1276   data_read = 0;
1277   err = 0;
1278
1279   while (bytes_to_read - data_read)
1280     {
1281       ret = (*func_read) (stream->intern->cookie,
1282                           buffer + data_read, bytes_to_read - data_read);
1283       if (ret == -1)
1284         {
1285           err = -1;
1286           break;
1287         }
1288       else if (ret)
1289         data_read += ret;
1290       else
1291         break;
1292     }
1293
1294   stream->intern->offset += data_read;
1295   *bytes_read = data_read;
1296
1297   return err;
1298 }
1299
1300 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1301    fully-buffered-mode, storing the amount of bytes read in
1302    *BYTES_READ.  */
1303 static int
1304 es_read_fbf (estream_t ES__RESTRICT stream,
1305              unsigned char *ES__RESTRICT buffer,
1306              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1307 {
1308   size_t data_available;
1309   size_t data_to_read;
1310   size_t data_read;
1311   int err;
1312
1313   data_read = 0;
1314   err = 0;
1315
1316   while ((bytes_to_read - data_read) && (! err))
1317     {
1318       if (stream->data_offset == stream->data_len)
1319         {
1320           /* Nothing more to read in current container, try to
1321              fill container with new data.  */
1322           err = es_fill (stream);
1323           if (! err)
1324             if (! stream->data_len)
1325               /* Filling did not result in any data read.  */
1326               break;
1327         }
1328
1329       if (! err)
1330         {
1331           /* Filling resulted in some new data.  */
1332
1333           data_to_read = bytes_to_read - data_read;
1334           data_available = stream->data_len - stream->data_offset;
1335           if (data_to_read > data_available)
1336             data_to_read = data_available;
1337
1338           memcpy (buffer + data_read,
1339                   stream->buffer + stream->data_offset, data_to_read);
1340           stream->data_offset += data_to_read;
1341           data_read += data_to_read;
1342         }
1343     }
1344
1345   *bytes_read = data_read;
1346
1347   return err;
1348 }
1349
1350 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1351    line-buffered-mode, storing the amount of bytes read in
1352    *BYTES_READ.  */
1353 static int
1354 es_read_lbf (estream_t ES__RESTRICT stream,
1355              unsigned char *ES__RESTRICT buffer,
1356              size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1357 {
1358   int err;
1359
1360   err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1361
1362   return err;
1363 }
1364
1365 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1366    *the amount of bytes read in BYTES_READ.  */
1367 static int
1368 es_readn (estream_t ES__RESTRICT stream,
1369           void *ES__RESTRICT buffer_arg,
1370           size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1371 {
1372   unsigned char *buffer = (unsigned char *)buffer_arg;
1373   size_t data_read_unread, data_read;
1374   int err;
1375
1376   data_read_unread = 0;
1377   data_read = 0;
1378   err = 0;
1379
1380   if (stream->flags.writing)
1381     {
1382       /* Switching to reading mode -> flush output.  */
1383       err = es_flush (stream);
1384       if (err)
1385         goto out;
1386       stream->flags.writing = 0;
1387     }  
1388
1389   /* Read unread data first.  */
1390   while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1391     {
1392       buffer[data_read_unread]
1393         = stream->unread_buffer[stream->unread_data_len - 1];
1394       stream->unread_data_len--;
1395       data_read_unread++;
1396     }
1397
1398   switch (stream->intern->strategy)
1399     {
1400     case _IONBF:
1401       err = es_read_nbf (stream,
1402                          buffer + data_read_unread,
1403                          bytes_to_read - data_read_unread, &data_read);
1404       break;
1405     case _IOLBF:
1406       err = es_read_lbf (stream,
1407                          buffer + data_read_unread,
1408                          bytes_to_read - data_read_unread, &data_read);
1409       break;
1410     case _IOFBF:
1411       err = es_read_fbf (stream,
1412                          buffer + data_read_unread,
1413                          bytes_to_read - data_read_unread, &data_read);
1414       break;
1415     }
1416
1417  out:
1418
1419   if (bytes_read)
1420     *bytes_read = data_read_unread + data_read;
1421
1422   return err;
1423 }
1424
1425 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1426    amount of bytes succesfully unread in *BYTES_UNREAD.  */
1427 static void
1428 es_unreadn (estream_t ES__RESTRICT stream,
1429             const unsigned char *ES__RESTRICT data, size_t data_n,
1430             size_t *ES__RESTRICT bytes_unread)
1431 {
1432   size_t space_left;
1433
1434   space_left = stream->unread_buffer_size - stream->unread_data_len;
1435
1436   if (data_n > space_left)
1437     data_n = space_left;
1438
1439   if (! data_n)
1440     goto out;
1441
1442   memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1443   stream->unread_data_len += data_n;
1444   stream->intern->indicators.eof = 0;
1445
1446  out:
1447
1448   if (bytes_unread)
1449     *bytes_unread = data_n;
1450 }
1451
1452 /* Seek in STREAM.  */
1453 static int
1454 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1455          off_t *ES__RESTRICT offset_new)
1456 {
1457   es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1458   int err, ret;
1459   off_t off;
1460
1461   if (! func_seek)
1462     {
1463       errno = EOPNOTSUPP;
1464       err = -1;
1465       goto out;
1466     }
1467
1468   if (stream->flags.writing)
1469     {
1470       /* Flush data first in order to prevent flushing it to the wrong
1471          offset.  */
1472       err = es_flush (stream);
1473       if (err)
1474         goto out;
1475       stream->flags.writing = 0;
1476     }
1477
1478   off = offset;
1479   if (whence == SEEK_CUR)
1480     {
1481       off = off - stream->data_len + stream->data_offset;
1482       off -= stream->unread_data_len;
1483     }
1484   
1485   ret = (*func_seek) (stream->intern->cookie, &off, whence);
1486   if (ret == -1)
1487     {
1488       err = -1;
1489       goto out;
1490     }
1491
1492   err = 0;
1493   es_empty (stream);
1494
1495   if (offset_new)
1496     *offset_new = off;
1497
1498   stream->intern->indicators.eof = 0;
1499   stream->intern->offset = off;
1500
1501  out:
1502   
1503   if (err)
1504     stream->intern->indicators.err = 1;
1505
1506   return err;
1507 }
1508
1509 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1510    unbuffered-mode, storing the amount of bytes written in
1511    *BYTES_WRITTEN.  */
1512 static int
1513 es_write_nbf (estream_t ES__RESTRICT stream,
1514               const unsigned char *ES__RESTRICT buffer,
1515               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1516 {
1517   es_cookie_write_function_t func_write = stream->intern->func_write;
1518   size_t data_written;
1519   ssize_t ret;
1520   int err;
1521
1522   if (bytes_to_write && (! func_write))
1523     {
1524       err = EOPNOTSUPP;
1525       goto out;
1526     }  
1527
1528   data_written = 0;
1529   err = 0;
1530   
1531   while (bytes_to_write - data_written)
1532     {
1533       ret = (*func_write) (stream->intern->cookie,
1534                            buffer + data_written,
1535                            bytes_to_write - data_written);
1536       if (ret == -1)
1537         {
1538           err = -1;
1539           break;
1540         }
1541       else
1542         data_written += ret;
1543     }
1544
1545   stream->intern->offset += data_written;
1546   *bytes_written = data_written;
1547
1548  out:
1549
1550   return err;
1551 }
1552
1553 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1554    fully-buffered-mode, storing the amount of bytes written in
1555    *BYTES_WRITTEN.  */
1556 static int
1557 es_write_fbf (estream_t ES__RESTRICT stream,
1558               const unsigned char *ES__RESTRICT buffer,
1559               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1560 {
1561   size_t space_available;
1562   size_t data_to_write;
1563   size_t data_written;
1564   int err;
1565
1566   data_written = 0;
1567   err = 0;
1568
1569   while ((bytes_to_write - data_written) && (! err))
1570     {
1571       if (stream->data_offset == stream->buffer_size)
1572         /* Container full, flush buffer.  */
1573         err = es_flush (stream);
1574
1575       if (! err)
1576         {
1577           /* Flushing resulted in empty container.  */
1578           
1579           data_to_write = bytes_to_write - data_written;
1580           space_available = stream->buffer_size - stream->data_offset;
1581           if (data_to_write > space_available)
1582             data_to_write = space_available;
1583               
1584           memcpy (stream->buffer + stream->data_offset,
1585                   buffer + data_written, data_to_write);
1586           stream->data_offset += data_to_write;
1587           data_written += data_to_write;
1588         }
1589     }
1590
1591   *bytes_written = data_written;
1592
1593   return err;
1594 }
1595
1596
1597 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1598    line-buffered-mode, storing the amount of bytes written in
1599    *BYTES_WRITTEN.  */
1600 static int
1601 es_write_lbf (estream_t ES__RESTRICT stream,
1602               const unsigned char *ES__RESTRICT buffer,
1603               size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1604 {
1605   size_t data_flushed = 0;
1606   size_t data_buffered = 0;
1607   unsigned char *nlp;
1608   int err = 0;
1609
1610   nlp = memrchr (buffer, '\n', bytes_to_write);
1611   if (nlp)
1612     {
1613       /* Found a newline, directly write up to (including) this
1614          character.  */
1615       err = es_flush (stream);
1616       if (!err)
1617         err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1618     }
1619
1620   if (!err)
1621     {
1622       /* Write remaining data fully buffered.  */
1623       err = es_write_fbf (stream, buffer + data_flushed,
1624                           bytes_to_write - data_flushed, &data_buffered);
1625     }
1626
1627   *bytes_written = data_flushed + data_buffered;
1628   return err;
1629 }
1630
1631
1632 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1633    amount of bytes written in BYTES_WRITTEN.  */
1634 static int
1635 es_writen (estream_t ES__RESTRICT stream,
1636            const void *ES__RESTRICT buffer,
1637            size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1638 {
1639   size_t data_written;
1640   int err;
1641
1642   data_written = 0;
1643   err = 0;
1644   
1645   if (!stream->flags.writing)
1646     {
1647       /* Switching to writing mode -> discard input data and seek to
1648          position at which reading has stopped.  We can do this only
1649          if a seek function has been registered. */
1650       if (stream->intern->func_seek)
1651         {
1652           err = es_seek (stream, 0, SEEK_CUR, NULL);
1653           if (err)
1654             {
1655               if (errno == ESPIPE)
1656                 err = 0;
1657               else
1658                 goto out;
1659             }
1660         }
1661     }
1662
1663   switch (stream->intern->strategy)
1664     {
1665     case _IONBF:
1666       err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1667       break;
1668
1669     case _IOLBF:
1670       err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1671       break;
1672
1673     case _IOFBF:
1674       err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1675       break;
1676     }
1677
1678  out:
1679     
1680   if (bytes_written)
1681     *bytes_written = data_written;
1682   if (data_written)
1683     if (!stream->flags.writing)
1684       stream->flags.writing = 1;
1685
1686   return err;
1687 }
1688
1689
1690 static int
1691 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1692          size_t *ES__RESTRICT data_len)
1693 {
1694   int err;
1695
1696   if (stream->flags.writing)
1697     {
1698       /* Switching to reading mode -> flush output.  */
1699       err = es_flush (stream);
1700       if (err)
1701         goto out;
1702       stream->flags.writing = 0;
1703     }  
1704
1705   if (stream->data_offset == stream->data_len)
1706     {
1707       /* Refill container.  */
1708       err = es_fill (stream);
1709       if (err)
1710         goto out;
1711     }
1712   
1713   if (data)
1714     *data = stream->buffer + stream->data_offset;
1715   if (data_len)
1716     *data_len = stream->data_len - stream->data_offset;
1717   err = 0;
1718
1719  out:
1720
1721   return err;
1722 }
1723
1724
1725 /* Skip SIZE bytes of input data contained in buffer.  */
1726 static int
1727 es_skip (estream_t stream, size_t size)
1728 {
1729   int err;
1730
1731   if (stream->data_offset + size > stream->data_len)
1732     {
1733       errno = EINVAL;
1734       err = -1;
1735     }
1736   else
1737     {
1738       stream->data_offset += size;
1739       err = 0;
1740     }
1741
1742   return err;
1743 }
1744
1745
1746 static int
1747 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
1748             char *ES__RESTRICT *ES__RESTRICT line,
1749             size_t *ES__RESTRICT line_length)
1750 {
1751   size_t space_left;
1752   size_t line_size;
1753   estream_t line_stream;
1754   char *line_new;
1755   void *line_stream_cookie;
1756   char *newline;
1757   unsigned char *data;
1758   size_t data_len;
1759   int err;
1760
1761   line_new = NULL;
1762   line_stream = NULL;
1763   line_stream_cookie = NULL;
1764
1765   err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0,
1766                             BUFFER_BLOCK_SIZE, 1,
1767                             mem_realloc, mem_free, 
1768                             O_RDWR,
1769                             0);
1770   if (err)
1771     goto out;
1772
1773   err = es_create (&line_stream, line_stream_cookie, -1,
1774                    estream_functions_mem, O_RDWR);
1775   if (err)
1776     goto out;
1777
1778   space_left = max_length;
1779   line_size = 0;
1780   while (1)
1781     {
1782       if (max_length && (space_left == 1))
1783         break;
1784
1785       err = es_peek (stream, &data, &data_len);
1786       if (err || (! data_len))
1787         break;
1788
1789       if (data_len > (space_left - 1))
1790         data_len = space_left - 1;
1791
1792       newline = memchr (data, '\n', data_len);
1793       if (newline)
1794         {
1795           data_len = (newline - (char *) data) + 1;
1796           err = es_write (line_stream, data, data_len, NULL);
1797           if (! err)
1798             {
1799               space_left -= data_len;
1800               line_size += data_len;
1801               es_skip (stream, data_len);
1802               break;
1803             }
1804         }
1805       else
1806         {
1807           err = es_write (line_stream, data, data_len, NULL);
1808           if (! err)
1809             {
1810               space_left -= data_len;
1811               line_size += data_len;
1812               es_skip (stream, data_len);
1813             }
1814         }
1815       if (err)
1816         break;
1817     }
1818   if (err)
1819     goto out;
1820
1821   /* Complete line has been written to line_stream.  */
1822   
1823   if ((max_length > 1) && (! line_size))
1824     {
1825       stream->intern->indicators.eof = 1;
1826       goto out;
1827     }
1828
1829   err = es_seek (line_stream, 0, SEEK_SET, NULL);
1830   if (err)
1831     goto out;
1832
1833   if (! *line)
1834     {
1835       line_new = mem_alloc (line_size + 1);
1836       if (! line_new)
1837         {
1838           err = -1;
1839           goto out;
1840         }
1841     }
1842   else
1843     line_new = *line;
1844
1845   err = es_read (line_stream, line_new, line_size, NULL);
1846   if (err)
1847     goto out;
1848
1849   line_new[line_size] = '\0';
1850
1851   if (! *line)
1852     *line = line_new;
1853   if (line_length)
1854     *line_length = line_size;
1855
1856  out:
1857
1858   if (line_stream)
1859     es_destroy (line_stream);
1860   else if (line_stream_cookie)
1861     es_func_mem_destroy (line_stream_cookie);
1862
1863   if (err)
1864     {
1865       if (! *line)
1866         mem_free (line_new);
1867       stream->intern->indicators.err = 1;
1868     }
1869
1870   return err;
1871 }
1872
1873
1874 /* Output fucntion used for estream_format.  */
1875 static int
1876 print_writer (void *outfncarg, const char *buf, size_t buflen)
1877 {
1878   estream_t stream = outfncarg;
1879   size_t nwritten;
1880   int rc;
1881
1882   nwritten = 0;
1883   rc = es_writen (stream, buf, buflen, &nwritten);
1884   stream->intern->print_ntotal += nwritten;
1885   return rc;
1886 }
1887
1888
1889 /* The core of our printf function.  This is called in locked state. */
1890 static int
1891 es_print (estream_t ES__RESTRICT stream,
1892           const char *ES__RESTRICT format, va_list ap)
1893 {
1894   int rc;
1895
1896   stream->intern->print_ntotal = 0;
1897   rc = estream_format (print_writer, stream, format, ap);
1898   if (rc)
1899     return -1;
1900   return (int)stream->intern->print_ntotal;
1901 }
1902
1903
1904 static void
1905 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1906 {
1907   if (ind_err != -1)
1908     stream->intern->indicators.err = ind_err ? 1 : 0;
1909   if (ind_eof != -1)
1910     stream->intern->indicators.eof = ind_eof ? 1 : 0;
1911 }
1912
1913
1914 static int
1915 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1916 {
1917   int ret = 0;
1918   
1919   if (ind_err)
1920     ret = stream->intern->indicators.err;
1921   else if (ind_eof)
1922     ret = stream->intern->indicators.eof;
1923
1924   return ret;
1925 }
1926
1927
1928 static int
1929 es_set_buffering (estream_t ES__RESTRICT stream,
1930                   char *ES__RESTRICT buffer, int mode, size_t size)
1931 {
1932   int err;
1933
1934   /* Flush or empty buffer depending on mode.  */
1935   if (stream->flags.writing)
1936     {
1937       err = es_flush (stream);
1938       if (err)
1939         goto out;
1940     }
1941   else
1942     es_empty (stream);
1943
1944   es_set_indicators (stream, -1, 0);
1945   
1946   /* Free old buffer in case that was allocated by this function.  */
1947   if (stream->intern->deallocate_buffer)
1948     {
1949       stream->intern->deallocate_buffer = 0;
1950       mem_free (stream->buffer);
1951       stream->buffer = NULL;
1952     }
1953
1954   if (mode == _IONBF)
1955     stream->buffer_size = 0;
1956   else
1957     {
1958       void *buffer_new;
1959       
1960       if (buffer)
1961         buffer_new = buffer;
1962       else
1963         {
1964           buffer_new = mem_alloc (size);
1965           if (! buffer_new)
1966             {
1967               err = -1;
1968               goto out;
1969             }
1970         }
1971
1972       stream->buffer = buffer_new;
1973       stream->buffer_size = size;
1974       if (! buffer)
1975         stream->intern->deallocate_buffer = 1;
1976     }
1977   stream->intern->strategy = mode;
1978   err = 0;
1979
1980  out:
1981
1982   return err;
1983 }
1984
1985
1986 static off_t
1987 es_offset_calculate (estream_t stream)
1988 {
1989   off_t offset;
1990
1991   offset = stream->intern->offset + stream->data_offset;
1992   if (offset < stream->unread_data_len)
1993     /* Offset undefined.  */
1994     offset = 0;
1995   else
1996     offset -= stream->unread_data_len;
1997
1998   return offset;
1999 }
2000
2001
2002 static void
2003 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
2004                 void **ES__RESTRICT opaque_old)
2005 {
2006   if (opaque_old)
2007     *opaque_old = stream->intern->opaque;
2008   if (opaque_new)
2009     stream->intern->opaque = opaque_new;
2010 }
2011
2012
2013 static int
2014 es_get_fd (estream_t stream)
2015 {
2016   return stream->intern->fd;
2017 }
2018
2019 \f
2020
2021 /* API.  */
2022
2023 int
2024 es_init (void)
2025 {
2026   int err;
2027
2028   err = es_init_do ();
2029
2030   return err;
2031 }
2032
2033 estream_t
2034 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
2035 {
2036   unsigned int modeflags;
2037   int create_called;
2038   estream_t stream;
2039   void *cookie;
2040   int err;
2041   int fd;
2042
2043   stream = NULL;
2044   cookie = NULL;
2045   create_called = 0;
2046
2047   err = es_convert_mode (mode, &modeflags);
2048   if (err)
2049     goto out;
2050   
2051   err = es_func_file_create (&cookie, &fd, path, modeflags);
2052   if (err)
2053     goto out;
2054
2055   create_called = 1;
2056   err = es_create (&stream, cookie, fd, estream_functions_file, modeflags);
2057   if (err)
2058     goto out;
2059
2060  out:
2061   
2062   if (err && create_called)
2063     (*estream_functions_file.func_close) (cookie);
2064
2065   return stream;
2066 }
2067
2068
2069 estream_t
2070 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
2071           unsigned int grow,
2072           func_realloc_t func_realloc, func_free_t func_free,
2073           const char *ES__RESTRICT mode)
2074 {
2075   unsigned int modeflags;
2076   int create_called;
2077   estream_t stream;
2078   void *cookie;
2079   int err;
2080
2081   cookie = 0;
2082   stream = NULL;
2083   create_called = 0;
2084   
2085   err = es_convert_mode (mode, &modeflags);
2086   if (err)
2087     goto out;
2088
2089   err = es_func_mem_create (&cookie, data, data_n, data_len,
2090                             BUFFER_BLOCK_SIZE, grow, 
2091                             func_realloc, func_free, modeflags, 0);
2092   if (err)
2093     goto out;
2094   
2095   create_called = 1;
2096   err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags);
2097
2098  out:
2099
2100   if (err && create_called)
2101     (*estream_functions_mem.func_close) (cookie);
2102
2103   return stream;
2104 }
2105
2106
2107 estream_t
2108 es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
2109 {
2110   unsigned int modeflags;
2111   estream_t stream = NULL;
2112   void *cookie = NULL;
2113
2114   /* Memory streams are always read/write.  We use MODE only to get
2115      the append flag.  */
2116   if (es_convert_mode (mode, &modeflags))
2117     return NULL;
2118   modeflags |= O_RDWR;
2119
2120   
2121   if (es_func_mem_create (&cookie, NULL, 0, 0,
2122                           BUFFER_BLOCK_SIZE, 1,
2123                           mem_realloc, mem_free, modeflags,
2124                           memlimit))
2125     return NULL;
2126   
2127   if (es_create (&stream, cookie, -1, estream_functions_mem, modeflags))
2128     (*estream_functions_mem.func_close) (cookie);
2129
2130   return stream;
2131 }
2132
2133
2134
2135 estream_t
2136 es_fopencookie (void *ES__RESTRICT cookie,
2137                 const char *ES__RESTRICT mode,
2138                 es_cookie_io_functions_t functions)
2139 {
2140   unsigned int modeflags;
2141   estream_t stream;
2142   int err;
2143
2144   stream = NULL;
2145   modeflags = 0;
2146   
2147   err = es_convert_mode (mode, &modeflags);
2148   if (err)
2149     goto out;
2150
2151   err = es_create (&stream, cookie, -1, functions, modeflags);
2152   if (err)
2153     goto out;
2154
2155  out:
2156
2157   return stream;
2158 }
2159
2160
2161 estream_t
2162 do_fdopen (int filedes, const char *mode, int no_close)
2163 {
2164   unsigned int modeflags;
2165   int create_called;
2166   estream_t stream;
2167   void *cookie;
2168   int err;
2169
2170   stream = NULL;
2171   cookie = NULL;
2172   create_called = 0;
2173
2174   err = es_convert_mode (mode, &modeflags);
2175   if (err)
2176     goto out;
2177
2178   err = es_func_fd_create (&cookie, filedes, modeflags, no_close);
2179   if (err)
2180     goto out;
2181
2182   create_called = 1;
2183   err = es_create (&stream, cookie, filedes, estream_functions_fd, modeflags);
2184
2185  out:
2186
2187   if (err && create_called)
2188     (*estream_functions_fd.func_close) (cookie);
2189
2190   return stream;
2191 }
2192
2193 estream_t
2194 es_fdopen (int filedes, const char *mode)
2195 {
2196   return do_fdopen (filedes, mode, 0);
2197 }
2198
2199 /* A variant of es_fdopen which does not close FILEDES at the end.  */
2200 estream_t
2201 es_fdopen_nc (int filedes, const char *mode)
2202 {
2203   return do_fdopen (filedes, mode, 1);
2204 }
2205
2206
2207 estream_t
2208 do_fpopen (FILE *fp, const char *mode, int no_close)
2209 {
2210   unsigned int modeflags;
2211   int create_called;
2212   estream_t stream;
2213   void *cookie;
2214   int err;
2215
2216   stream = NULL;
2217   cookie = NULL;
2218   create_called = 0;
2219
2220   err = es_convert_mode (mode, &modeflags);
2221   if (err)
2222     goto out;
2223
2224   fflush (fp);
2225   err = es_func_fp_create (&cookie, fp, modeflags, no_close);
2226   if (err)
2227     goto out;
2228
2229   create_called = 1;
2230   err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
2231                    modeflags);
2232
2233  out:
2234
2235   if (err && create_called)
2236     (*estream_functions_fp.func_close) (cookie);
2237
2238   return stream;
2239 }
2240
2241   
2242 /* Create an estream from the stdio stream FP.  This mechanism is
2243    useful in case the stdio streams have special properties and may
2244    not be mixed with fd based functions.  This is for example the case
2245    under Windows where the 3 standard streams are associated with the
2246    console whereas a duped and fd-opened stream of one of this stream
2247    won't be associated with the console.  As this messes things up it
2248    is easier to keep on using the standard I/O stream as a backend for
2249    estream. */
2250 estream_t
2251 es_fpopen (FILE *fp, const char *mode)
2252 {
2253   return do_fpopen (fp, mode, 0);
2254 }
2255
2256
2257 /* Same as es_fpopen but does not close  FP at the end.  */
2258 estream_t
2259 es_fpopen_nc (FILE *fp, const char *mode)
2260 {
2261   return do_fpopen (fp, mode, 1);
2262 }
2263
2264
2265 estream_t
2266 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
2267             estream_t ES__RESTRICT stream)
2268 {
2269   int err;
2270
2271   if (path)
2272     {
2273       unsigned int modeflags;
2274       int create_called;
2275       void *cookie;
2276       int fd;
2277
2278       cookie = NULL;
2279       create_called = 0;
2280       
2281       ESTREAM_LOCK (stream);
2282
2283       es_deinitialize (stream);
2284
2285       err = es_convert_mode (mode, &modeflags);
2286       if (err)
2287         goto leave;
2288       
2289       err = es_func_file_create (&cookie, &fd, path, modeflags);
2290       if (err)
2291         goto leave;
2292
2293       create_called = 1;
2294       es_initialize (stream, cookie, fd, estream_functions_file, modeflags);
2295
2296     leave:
2297
2298       if (err)
2299         {
2300           if (create_called)
2301             es_func_fd_destroy (cookie);
2302       
2303           es_destroy (stream);
2304           stream = NULL;
2305         }
2306       else
2307         ESTREAM_UNLOCK (stream);
2308     }
2309   else
2310     {
2311       /* FIXME?  We don't support re-opening at the moment.  */
2312       errno = EINVAL;
2313       es_deinitialize (stream);
2314       es_destroy (stream);
2315       stream = NULL;
2316     }
2317
2318   return stream;
2319 }
2320
2321
2322 int
2323 es_fclose (estream_t stream)
2324 {
2325   int err;
2326
2327   err = es_destroy (stream);
2328
2329   return err;
2330 }
2331
2332 int
2333 es_fileno_unlocked (estream_t stream)
2334 {
2335   return es_get_fd (stream);
2336 }
2337
2338
2339 void
2340 es_flockfile (estream_t stream)
2341 {
2342   ESTREAM_LOCK (stream);
2343 }
2344
2345
2346 int
2347 es_ftrylockfile (estream_t stream)
2348 {
2349   return ESTREAM_TRYLOCK (stream);
2350 }
2351
2352
2353 void
2354 es_funlockfile (estream_t stream)
2355 {
2356   ESTREAM_UNLOCK (stream);
2357 }
2358
2359
2360 int
2361 es_fileno (estream_t stream)
2362 {
2363   int ret;
2364
2365   ESTREAM_LOCK (stream);
2366   ret = es_fileno_unlocked (stream);
2367   ESTREAM_UNLOCK (stream);
2368
2369   return ret;
2370 }
2371
2372
2373 int
2374 es_feof_unlocked (estream_t stream)
2375 {
2376   return es_get_indicator (stream, 0, 1);
2377 }
2378
2379
2380 int
2381 es_feof (estream_t stream)
2382 {
2383   int ret;
2384
2385   ESTREAM_LOCK (stream);
2386   ret = es_feof_unlocked (stream);
2387   ESTREAM_UNLOCK (stream);
2388
2389   return ret;
2390 }
2391
2392
2393 int
2394 es_ferror_unlocked (estream_t stream)
2395 {
2396   return es_get_indicator (stream, 1, 0);
2397 }
2398
2399
2400 int
2401 es_ferror (estream_t stream)
2402 {
2403   int ret;
2404
2405   ESTREAM_LOCK (stream);
2406   ret = es_ferror_unlocked (stream);
2407   ESTREAM_UNLOCK (stream);
2408
2409   return ret;
2410 }
2411
2412
2413 void
2414 es_clearerr_unlocked (estream_t stream)
2415 {
2416   es_set_indicators (stream, 0, 0);
2417 }
2418
2419
2420 void
2421 es_clearerr (estream_t stream)
2422 {
2423   ESTREAM_LOCK (stream);
2424   es_clearerr_unlocked (stream);
2425   ESTREAM_UNLOCK (stream);
2426 }
2427
2428
2429 int
2430 es_fflush (estream_t stream)
2431 {
2432   int err;
2433   
2434   if (stream)
2435     {
2436       ESTREAM_LOCK (stream);
2437       if (stream->flags.writing)
2438         err = es_flush (stream);
2439       else
2440         {
2441           es_empty (stream);
2442           err = 0;
2443         }
2444       ESTREAM_UNLOCK (stream);
2445     }
2446   else
2447     err = es_list_iterate (es_fflush);
2448
2449   return err ? EOF : 0;
2450 }
2451
2452
2453 int
2454 es_fseek (estream_t stream, long int offset, int whence)
2455 {
2456   int err;
2457
2458   ESTREAM_LOCK (stream);
2459   err = es_seek (stream, offset, whence, NULL);
2460   ESTREAM_UNLOCK (stream);
2461
2462   return err;
2463 }
2464
2465
2466 int
2467 es_fseeko (estream_t stream, off_t offset, int whence)
2468 {
2469   int err;
2470   
2471   ESTREAM_LOCK (stream);
2472   err = es_seek (stream, offset, whence, NULL);
2473   ESTREAM_UNLOCK (stream);
2474
2475   return err;
2476 }
2477
2478
2479 long int
2480 es_ftell (estream_t stream)
2481 {
2482   long int ret;
2483   
2484   ESTREAM_LOCK (stream);
2485   ret = es_offset_calculate (stream);
2486   ESTREAM_UNLOCK (stream);
2487
2488   return ret;
2489 }
2490
2491
2492 off_t
2493 es_ftello (estream_t stream)
2494 {
2495   off_t ret = -1;
2496
2497   ESTREAM_LOCK (stream);
2498   ret = es_offset_calculate (stream);
2499   ESTREAM_UNLOCK (stream);
2500
2501   return ret;
2502 }
2503
2504
2505 void
2506 es_rewind (estream_t stream)
2507 {
2508   ESTREAM_LOCK (stream);
2509   es_seek (stream, 0L, SEEK_SET, NULL);
2510   es_set_indicators (stream, 0, -1);
2511   ESTREAM_UNLOCK (stream);
2512 }
2513
2514
2515 int
2516 _es_getc_underflow (estream_t stream)
2517 {
2518   int err;
2519   unsigned char c;
2520   size_t bytes_read;
2521
2522   err = es_readn (stream, &c, 1, &bytes_read);
2523
2524   return (err || (! bytes_read)) ? EOF : c;
2525 }
2526
2527
2528 int
2529 _es_putc_overflow (int c, estream_t stream)
2530 {
2531   unsigned char d = c;
2532   int err;
2533
2534   err = es_writen (stream, &d, 1, NULL);
2535
2536   return err ? EOF : c;
2537 }
2538
2539
2540 int
2541 es_fgetc (estream_t stream)
2542 {
2543   int ret;
2544   
2545   ESTREAM_LOCK (stream);
2546   ret = es_getc_unlocked (stream);
2547   ESTREAM_UNLOCK (stream);
2548
2549   return ret;
2550 }
2551
2552
2553 int
2554 es_fputc (int c, estream_t stream)
2555 {
2556   int ret;
2557   
2558   ESTREAM_LOCK (stream);
2559   ret = es_putc_unlocked (c, stream);
2560   ESTREAM_UNLOCK (stream);
2561
2562   return ret;
2563 }
2564
2565
2566 int
2567 es_ungetc (int c, estream_t stream)
2568 {
2569   unsigned char data = (unsigned char) c;
2570   size_t data_unread;
2571
2572   ESTREAM_LOCK (stream);
2573   es_unreadn (stream, &data, 1, &data_unread);
2574   ESTREAM_UNLOCK (stream);
2575
2576   return data_unread ? c : EOF;
2577 }
2578
2579
2580 int
2581 es_read (estream_t ES__RESTRICT stream,
2582          void *ES__RESTRICT buffer, size_t bytes_to_read,
2583          size_t *ES__RESTRICT bytes_read)
2584 {
2585   int err;
2586
2587   if (bytes_to_read)
2588     {
2589       ESTREAM_LOCK (stream);
2590       err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2591       ESTREAM_UNLOCK (stream);
2592     }
2593   else
2594     err = 0;
2595
2596   return err;
2597 }
2598
2599
2600 int
2601 es_write (estream_t ES__RESTRICT stream,
2602           const void *ES__RESTRICT buffer, size_t bytes_to_write,
2603           size_t *ES__RESTRICT bytes_written)
2604 {
2605   int err;
2606
2607   if (bytes_to_write)
2608     {
2609       ESTREAM_LOCK (stream);
2610       err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2611       ESTREAM_UNLOCK (stream);
2612     }
2613   else
2614     err = 0;
2615
2616   return err;
2617 }
2618
2619
2620 size_t
2621 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2622           estream_t ES__RESTRICT stream)
2623 {
2624   size_t ret, bytes;
2625   int err;
2626
2627   if (size * nitems)
2628     {
2629       ESTREAM_LOCK (stream);
2630       err = es_readn (stream, ptr, size * nitems, &bytes);
2631       ESTREAM_UNLOCK (stream);
2632
2633       ret = bytes / size;
2634     }
2635   else
2636     ret = 0;
2637
2638   return ret;
2639 }
2640
2641
2642 size_t
2643 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2644            estream_t ES__RESTRICT stream)
2645 {
2646   size_t ret, bytes;
2647   int err;
2648
2649   if (size * nitems)
2650     {
2651       ESTREAM_LOCK (stream);
2652       err = es_writen (stream, ptr, size * nitems, &bytes);
2653       ESTREAM_UNLOCK (stream);
2654
2655       ret = bytes / size;
2656     }
2657   else
2658     ret = 0;
2659
2660   return ret;
2661 }
2662
2663
2664 char *
2665 es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
2666 {
2667   unsigned char *s = (unsigned char*)buffer;
2668   int c;
2669    
2670   if (!length)
2671     return NULL;
2672      
2673   c = EOF;
2674   ESTREAM_LOCK (stream);
2675   while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n')
2676     {
2677       *s++ = c;
2678       length--;
2679     }
2680   ESTREAM_UNLOCK (stream);
2681
2682   if (c == EOF && s == (unsigned char*)buffer)
2683     return NULL; /* Nothing read.  */
2684
2685   if (c != EOF && length > 1)
2686     *s++ = c;
2687
2688   *s = 0;
2689   return buffer;
2690 }
2691
2692
2693 int
2694 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2695 {
2696   size_t length;
2697   int err;
2698
2699   length = strlen (s);
2700   ESTREAM_LOCK (stream);
2701   err = es_writen (stream, s, length, NULL);
2702   ESTREAM_UNLOCK (stream);
2703
2704   return err ? EOF : 0;
2705 }
2706
2707
2708 ssize_t
2709 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2710             estream_t ES__RESTRICT stream)
2711 {
2712   char *line = NULL;
2713   size_t line_n = 0;
2714   int err;
2715
2716   ESTREAM_LOCK (stream);
2717   err = doreadline (stream, 0, &line, &line_n);
2718   ESTREAM_UNLOCK (stream);
2719   if (err)
2720     goto out;
2721
2722   if (*n)
2723     {
2724       /* Caller wants us to use his buffer.  */
2725       
2726       if (*n < (line_n + 1))
2727         {
2728           /* Provided buffer is too small -> resize.  */
2729
2730           void *p;
2731
2732           p = mem_realloc (*lineptr, line_n + 1);
2733           if (! p)
2734             err = -1;
2735           else
2736             {
2737               if (*lineptr != p)
2738                 *lineptr = p;
2739             }
2740         }
2741
2742       if (! err)
2743         {
2744           memcpy (*lineptr, line, line_n + 1);
2745           if (*n != line_n)
2746             *n = line_n;
2747         }
2748       mem_free (line);
2749     }
2750   else
2751     {
2752       /* Caller wants new buffers.  */
2753       *lineptr = line;
2754       *n = line_n;
2755     }
2756
2757  out:
2758
2759   return err ? err : (ssize_t)line_n;
2760 }
2761
2762
2763
2764 /* Same as fgets() but if the provided buffer is too short a larger
2765    one will be allocated.  This is similar to getline. A line is
2766    considered a byte stream ending in a LF.
2767
2768    If MAX_LENGTH is not NULL, it shall point to a value with the
2769    maximum allowed allocation.  
2770
2771    Returns the length of the line. EOF is indicated by a line of
2772    length zero. A truncated line is indicated my setting the value at
2773    MAX_LENGTH to 0.  If the returned value is less then 0 not enough
2774    memory was enable or another error occurred; ERRNO is then set
2775    accordingly.
2776
2777    If a line has been truncated, the file pointer is moved forward to
2778    the end of the line so that the next read starts with the next
2779    line.  Note that MAX_LENGTH must be re-initialzied in this case.
2780
2781    The caller initially needs to provide the address of a variable,
2782    initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2783    anymore with the following invocations.  LENGTH_OF_BUFFER should be
2784    the address of a variable, initialized to 0, which is also
2785    maintained by this function.  Thus, both paramaters should be
2786    considered the state of this function.
2787
2788    Note: The returned buffer is allocated with enough extra space to
2789    allow the caller to append a CR,LF,Nul.  The buffer should be
2790    released using es_free.
2791  */
2792 ssize_t
2793 es_read_line (estream_t stream, 
2794               char **addr_of_buffer, size_t *length_of_buffer,
2795               size_t *max_length)
2796 {
2797   int c;
2798   char  *buffer = *addr_of_buffer;
2799   size_t length = *length_of_buffer;
2800   size_t nbytes = 0;
2801   size_t maxlen = max_length? *max_length : 0;
2802   char *p;
2803
2804   if (!buffer)
2805     { 
2806       /* No buffer given - allocate a new one. */
2807       length = 256;
2808       buffer = mem_alloc (length);
2809       *addr_of_buffer = buffer;
2810       if (!buffer)
2811         {
2812           *length_of_buffer = 0;
2813           if (max_length)
2814             *max_length = 0;
2815           return -1;
2816         }
2817       *length_of_buffer = length;
2818     }
2819
2820   if (length < 4)
2821     {
2822       /* This should never happen. If it does, the function has been
2823          called with wrong arguments. */
2824       errno = EINVAL;
2825       return -1;
2826     }
2827   length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2828
2829   ESTREAM_LOCK (stream);
2830   p = buffer;
2831   while  ((c = es_getc_unlocked (stream)) != EOF)
2832     {
2833       if (nbytes == length)
2834         { 
2835           /* Enlarge the buffer. */
2836           if (maxlen && length > maxlen) 
2837             {
2838               /* We are beyond our limit: Skip the rest of the line. */
2839               while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
2840                 ;
2841               *p++ = '\n'; /* Always append a LF (we reserved some space). */
2842               nbytes++;
2843               if (max_length)
2844                 *max_length = 0; /* Indicate truncation. */
2845               break; /* the while loop. */
2846             }
2847           length += 3; /* Adjust for the reserved bytes. */
2848           length += length < 1024? 256 : 1024;
2849           *addr_of_buffer = mem_realloc (buffer, length);
2850           if (!*addr_of_buffer)
2851             {
2852               int save_errno = errno;
2853               mem_free (buffer); 
2854               *length_of_buffer = 0;
2855               if (max_length)
2856                 *max_length = 0;
2857               ESTREAM_UNLOCK (stream);
2858               errno = save_errno;
2859               return -1;
2860             }
2861           buffer = *addr_of_buffer;
2862           *length_of_buffer = length;
2863           length -= 3; 
2864           p = buffer + nbytes;
2865         }
2866       *p++ = c;
2867       nbytes++;
2868       if (c == '\n')
2869         break;
2870     }
2871   *p = 0; /* Make sure the line is a string. */
2872   ESTREAM_UNLOCK (stream);
2873
2874   return nbytes;
2875 }
2876
2877 /* Wrapper around free() to match the memory allocation system used
2878    by estream.  Should be used for all buffers returned to the caller
2879    by libestream. */
2880 void
2881 es_free (void *a)
2882 {
2883   mem_free (a);
2884 }
2885
2886
2887 int
2888 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2889              va_list ap)
2890 {
2891   int ret;
2892   
2893   ESTREAM_LOCK (stream);
2894   ret = es_print (stream, format, ap);
2895   ESTREAM_UNLOCK (stream);
2896
2897   return ret;
2898 }
2899
2900
2901 static int
2902 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
2903            const char *ES__RESTRICT format, ...)
2904 {
2905   int ret;
2906   
2907   va_list ap;
2908   va_start (ap, format);
2909   ret = es_print (stream, format, ap);
2910   va_end (ap);
2911
2912   return ret;
2913 }
2914
2915
2916 int
2917 es_fprintf (estream_t ES__RESTRICT stream,
2918             const char *ES__RESTRICT format, ...)
2919 {
2920   int ret;
2921   
2922   va_list ap;
2923   va_start (ap, format);
2924   ESTREAM_LOCK (stream);
2925   ret = es_print (stream, format, ap);
2926   ESTREAM_UNLOCK (stream);
2927   va_end (ap);
2928
2929   return ret;
2930 }
2931
2932 /* A variant of asprintf.  The function returns the allocated buffer
2933    or NULL on error; ERRNO is set in the error case.  The caller
2934    should use es_free to release the buffer.  This function actually
2935    belongs into estream-printf but we put it here as a convenience
2936    and because es_free is required anyway.  */
2937 char *
2938 es_asprintf (const char *ES__RESTRICT format, ...)
2939 {
2940   int rc;
2941   va_list ap;
2942   char *buf;
2943
2944   va_start (ap, format);
2945   rc = estream_vasprintf (&buf, format, ap);
2946   va_end (ap);
2947   if (rc < 0)
2948     return NULL;
2949   return buf;
2950 }
2951
2952
2953 /* A variant of vasprintf.  The function returns the allocated buffer
2954    or NULL on error; ERRNO is set in the error case.  The caller
2955    should use es_free to release the buffer.  This function actually
2956    belongs into estream-printf but we put it here as a convenience
2957    and because es_free is required anyway.  */
2958 char * 
2959 es_vasprintf (const char *ES__RESTRICT format, va_list ap)
2960 {
2961   int rc;
2962   char *buf;
2963
2964   rc = estream_vasprintf (&buf, format, ap);
2965   if (rc < 0)
2966     return NULL;
2967   return buf;
2968 }
2969
2970
2971 static int
2972 tmpfd (void)
2973 {
2974 #ifdef HAVE_W32_SYSTEM
2975   int attempts, n;
2976   char buffer[MAX_PATH+9+12+1];
2977   char *name, *p;
2978   HANDLE file;
2979   int pid = GetCurrentProcessId ();
2980   unsigned int value;
2981   int i;
2982   
2983   n = GetTempPath (MAX_PATH+1, buffer);
2984   if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
2985     {
2986       errno = ENOENT;
2987       return -1;
2988     }
2989   p = buffer + strlen (buffer);
2990   strcpy (p, "_estream");
2991   p += 8;
2992   /* We try to create the directory but don't care about an error as
2993      it may already exist and the CreateFile would throw an error
2994      anyway.  */
2995   CreateDirectory (buffer, NULL);
2996   *p++ = '\\';
2997   name = p;
2998   for (attempts=0; attempts < 10; attempts++)
2999     {
3000       p = name;
3001       value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
3002       for (i=0; i < 8; i++)
3003         {
3004           *p++ = tohex (((value >> 28) & 0x0f));
3005           value <<= 4;
3006         }
3007       strcpy (p, ".tmp");
3008       file = CreateFile (buffer,
3009                          GENERIC_READ | GENERIC_WRITE,
3010                          0,
3011                          NULL,
3012                          CREATE_NEW,
3013                          FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
3014                          NULL);
3015       if (file != INVALID_HANDLE_VALUE)
3016         {
3017           int fd = _open_osfhandle ((long)file, 0);
3018           if (fd == -1)
3019             {
3020               CloseHandle (file);
3021               return -1;
3022             }
3023           return fd;
3024         }
3025       Sleep (1); /* One ms as this is the granularity of GetTickCount.  */
3026     }
3027   errno = ENOENT;
3028   return -1;
3029 #else /*!HAVE_W32_SYSTEM*/
3030   FILE *fp;
3031   int fp_fd;
3032   int fd;
3033
3034   fp = NULL;
3035   fd = -1;
3036   
3037   fp = tmpfile ();
3038   if (! fp)
3039     goto out;
3040
3041   fp_fd = fileno (fp);
3042   fd = dup (fp_fd);
3043
3044  out:
3045
3046   if (fp)
3047     fclose (fp);
3048
3049   return fd;
3050 #endif /*!HAVE_W32_SYSTEM*/
3051 }
3052
3053 estream_t
3054 es_tmpfile (void)
3055 {
3056   unsigned int modeflags;
3057   int create_called;
3058   estream_t stream;
3059   void *cookie;
3060   int err;
3061   int fd;
3062
3063   create_called = 0;
3064   stream = NULL;
3065   modeflags = O_RDWR | O_TRUNC | O_CREAT;
3066   cookie = NULL;
3067   
3068   fd = tmpfd ();
3069   if (fd == -1)
3070     {
3071       err = -1;
3072       goto out;
3073     }
3074
3075   err = es_func_fd_create (&cookie, fd, modeflags, 0);
3076   if (err)
3077     goto out;
3078
3079   create_called = 1;
3080   err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags);
3081
3082  out:
3083
3084   if (err)
3085     {
3086       if (create_called)
3087         es_func_fd_destroy (cookie);
3088       else if (fd != -1)
3089         close (fd);
3090       stream = NULL;
3091     }
3092   
3093   return stream;
3094 }
3095
3096
3097 int
3098 es_setvbuf (estream_t ES__RESTRICT stream,
3099             char *ES__RESTRICT buf, int type, size_t size)
3100 {
3101   int err;
3102   
3103   if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
3104       && (! ((! size) && (type != _IONBF))))
3105     {
3106       ESTREAM_LOCK (stream);
3107       err = es_set_buffering (stream, buf, type, size);
3108       ESTREAM_UNLOCK (stream);
3109     }
3110   else
3111     {
3112       errno = EINVAL;
3113       err = -1;
3114     }
3115
3116   return err;
3117 }
3118
3119
3120 void
3121 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
3122 {
3123   ESTREAM_LOCK (stream);
3124   es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3125   ESTREAM_UNLOCK (stream);
3126 }
3127
3128 void
3129 es_opaque_set (estream_t stream, void *opaque)
3130 {
3131   ESTREAM_LOCK (stream);
3132   es_opaque_ctrl (stream, opaque, NULL);
3133   ESTREAM_UNLOCK (stream);
3134 }
3135
3136
3137 void *
3138 es_opaque_get (estream_t stream)
3139 {
3140   void *opaque;
3141   
3142   ESTREAM_LOCK (stream);
3143   es_opaque_ctrl (stream, NULL, &opaque);
3144   ESTREAM_UNLOCK (stream);
3145
3146   return opaque;
3147 }
3148
3149 /* Print a BUFFER to STREAM while replacing all control characters and
3150    the characters in DELIMITERS by standard C escape sequences.
3151    Returns 0 on success or -1 on error.  If BYTES_WRITTEN is not NULL
3152    the number of bytes actually written are stored at this
3153    address.  */
3154 int 
3155 es_write_sanitized (estream_t ES__RESTRICT stream,
3156                     const void * ES__RESTRICT buffer, size_t length,
3157                     const char * delimiters, 
3158                     size_t * ES__RESTRICT bytes_written)
3159 {
3160   const unsigned char *p = buffer;
3161   size_t count = 0;
3162   int ret;
3163
3164   ESTREAM_LOCK (stream);
3165   for (; length; length--, p++, count++)
3166     {
3167       if (*p < 0x20 
3168           || *p == 0x7f
3169           || (delimiters 
3170               && (strchr (delimiters, *p) || *p == '\\')))
3171         {
3172           es_putc_unlocked ('\\', stream);
3173           count++;
3174           if (*p == '\n')
3175             {
3176               es_putc_unlocked ('n', stream);
3177               count++;
3178             }
3179           else if (*p == '\r')
3180             {
3181               es_putc_unlocked ('r', stream);
3182               count++;
3183             }
3184           else if (*p == '\f')
3185             {
3186               es_putc_unlocked ('f', stream);
3187               count++;
3188             }
3189           else if (*p == '\v')
3190             {
3191               es_putc_unlocked ('v', stream);
3192               count++;
3193             }
3194           else if (*p == '\b')
3195             {
3196               es_putc_unlocked ('b', stream);
3197               count++;
3198             }
3199           else if (!*p)
3200             {
3201               es_putc_unlocked('0', stream);
3202               count++;
3203             }
3204           else
3205             {
3206               es_fprintf_unlocked (stream, "x%02x", *p);
3207               count += 3;
3208             }
3209         }
3210       else
3211         {
3212           es_putc_unlocked (*p, stream);
3213           count++;
3214         }
3215     }
3216
3217   if (bytes_written)
3218     *bytes_written = count;
3219   ret =  es_ferror_unlocked (stream)? -1 : 0;
3220   ESTREAM_UNLOCK (stream);
3221
3222   return ret;
3223 }
3224
3225
3226 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3227    RESERVED must be 0.  Returns 0 on success or -1 on error.  If
3228    BYTES_WRITTEN is not NULL the number of bytes actually written are
3229    stored at this address.  */
3230 int
3231 es_write_hexstring (estream_t ES__RESTRICT stream,
3232                     const void *ES__RESTRICT buffer, size_t length,
3233                     int reserved, size_t *ES__RESTRICT bytes_written )
3234 {
3235   int ret;
3236   const unsigned char *s;
3237   size_t count = 0;
3238
3239   (void)reserved;
3240
3241 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3242
3243   if (!length)
3244     return 0;
3245
3246   ESTREAM_LOCK (stream);
3247
3248   for (s = buffer; length; s++, length--)
3249     {
3250       es_putc_unlocked ( tohex ((*s>>4)&15), stream);
3251       es_putc_unlocked ( tohex (*s&15), stream);
3252       count += 2;
3253     }
3254
3255   if (bytes_written)
3256     *bytes_written = count;
3257   ret = es_ferror_unlocked (stream)? -1 : 0;
3258
3259   ESTREAM_UNLOCK (stream);
3260
3261   return ret;
3262
3263 #undef tohex
3264 }
3265
3266
3267
3268 #ifdef GNUPG_MAJOR_VERSION
3269 /* Special estream function to print an UTF8 string in the native
3270    encoding.  The interface is the same as es_write_sanitized, however
3271    only one delimiter may be supported. 
3272
3273    THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3274 int
3275 es_write_sanitized_utf8_buffer (estream_t stream,
3276                                 const void *buffer, size_t length, 
3277                                 const char *delimiters, size_t *bytes_written)
3278 {
3279   const char *p = buffer;
3280   size_t i;
3281
3282   /* We can handle plain ascii simpler, so check for it first. */
3283   for (i=0; i < length; i++ ) 
3284     {
3285       if ( (p[i] & 0x80) )
3286         break;
3287     }
3288   if (i < length)
3289     {
3290       int delim = delimiters? *delimiters : 0;
3291       char *buf;
3292       int ret;
3293
3294       /*(utf8 conversion already does the control character quoting). */
3295       buf = utf8_to_native (p, length, delim);
3296       if (bytes_written)
3297         *bytes_written = strlen (buf);
3298       ret = es_fputs (buf, stream);
3299       xfree (buf);
3300       return ret == EOF? ret : (int)i;
3301     }
3302   else
3303     return es_write_sanitized (stream, p, length, delimiters, bytes_written);
3304 }
3305 #endif /*GNUPG_MAJOR_VERSION*/