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