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