1 /* estream.c - Extended Stream I/O Library
2 * Copyright (C) 2004, 2005, 2006, 2007 g10 Code GmbH
4 * This file is part of Libestream.
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.
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.
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/>.
20 #ifdef USE_ESTREAM_SUPPORT_H
21 # include <estream-support.h>
28 #if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
29 # define HAVE_W32_SYSTEM 1
32 #include <sys/types.h>
44 #ifdef HAVE_W32_SYSTEM
48 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */
57 /* This is for the special hack to use estream.c in GnuPG. */
58 #ifdef GNUPG_MAJOR_VERSION
59 # include "../common/util.h"
63 int mkstemp (char *template);
67 void *memrchr (const void *block
, int c
, size_t size
);
71 #include <estream-printf.h>
79 /* Generally used types. */
81 typedef void *(*func_realloc_t
) (void *mem
, size_t size
);
82 typedef void (*func_free_t
) (void *mem
);
87 /* Buffer management layer. */
89 #define BUFFER_BLOCK_SIZE BUFSIZ
90 #define BUFFER_UNREAD_SIZE 16
96 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
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))
116 typedef void *estream_mutex_t
;
119 dummy_mutex_call_void (estream_mutex_t mutex
)
125 dummy_mutex_call_int (estream_mutex_t mutex
)
131 # define ESTREAM_MUTEX_INITIALIZER NULL
132 # define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex))
133 # define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex))
134 # define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex))
135 # define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex))
138 /* Primitive system I/O. */
141 # define ESTREAM_SYS_READ pth_read
142 # define ESTREAM_SYS_WRITE pth_write
144 # define ESTREAM_SYS_READ read
145 # define ESTREAM_SYS_WRITE write
148 /* Misc definitions. */
150 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
152 /* An internal stream object. */
154 struct estream_internal
156 unsigned char buffer
[BUFFER_BLOCK_SIZE
];
157 unsigned char unread_buffer
[BUFFER_UNREAD_SIZE
];
158 estream_mutex_t lock
; /* Lock. */
159 void *cookie
; /* Cookie. */
160 void *opaque
; /* Opaque data. */
161 unsigned int modeflags
; /* Flags for the backend. */
163 es_cookie_read_function_t func_read
;
164 es_cookie_write_function_t func_write
;
165 es_cookie_seek_function_t func_seek
;
166 es_cookie_close_function_t func_close
;
174 unsigned int deallocate_buffer
: 1;
175 unsigned int print_err
: 1; /* Error in print_fun_writer. */
176 int print_errno
; /* Errno from print_fun_writer. */
177 size_t print_ntotal
; /* Bytes written from in print_fun_writer. */
178 FILE *print_fp
; /* Stdio stream used by print_fun_writer. */
182 typedef struct estream_internal
*estream_internal_t
;
184 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
185 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
186 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
190 typedef struct estream_list
*estream_list_t
;
196 estream_list_t
*prev_cdr
;
199 static estream_list_t estream_list
;
200 static estream_mutex_t estream_list_lock
;
202 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
203 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
206 # define EOPNOTSUPP ENOSYS
214 /* Calculate array dimension. */
216 #define DIM(array) (sizeof (array) / sizeof (*array))
219 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
222 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
224 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
227 tmp_variable = expression; \
228 if ((! variable) && tmp_variable) \
229 variable = tmp_variable; \
234 /* Malloc wrappers to overcvome problems on some older OSes. */
244 mem_realloc (void *p
, size_t n
)
247 return mem_alloc (n
);
248 return realloc (p
, n
);
264 /* Add STREAM to the list of registered stream objects. */
266 es_list_add (estream_t stream
)
268 estream_list_t list_obj
;
271 list_obj
= mem_alloc (sizeof (*list_obj
));
277 list_obj
->car
= stream
;
278 list_obj
->cdr
= estream_list
;
279 list_obj
->prev_cdr
= &estream_list
;
281 estream_list
->prev_cdr
= &list_obj
->cdr
;
282 estream_list
= list_obj
;
290 /* Remove STREAM from the list of registered stream objects. */
292 es_list_remove (estream_t stream
)
294 estream_list_t list_obj
;
297 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
298 if (list_obj
->car
== stream
)
300 *list_obj
->prev_cdr
= list_obj
->cdr
;
302 list_obj
->cdr
->prev_cdr
= list_obj
->prev_cdr
;
309 /* Type of an stream-iterator-function. */
310 typedef int (*estream_iterator_t
) (estream_t stream
);
312 /* Iterate over list of registered streams, calling ITERATOR for each
315 es_list_iterate (estream_iterator_t iterator
)
317 estream_list_t list_obj
;
321 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
322 ret
|= (*iterator
) (list_obj
->car
);
338 static int initialized
;
342 if (!pth_init () && errno
!= EPERM
)
344 if (pth_mutex_init (&estream_list_lock
))
357 /* Implementation of Memory I/O. */
359 /* Cookie for memory objects. */
360 typedef struct estream_cookie_mem
362 unsigned int modeflags
; /* Open flags. */
363 unsigned char *memory
; /* Allocated data buffer. */
364 size_t memory_size
; /* Allocated size of memory. */
365 size_t memory_limit
; /* Maximum allowed allocation size or
367 size_t offset
; /* Current offset in MEMORY. */
368 size_t data_len
; /* Length of data in MEMORY. */
369 size_t block_size
; /* Block size. */
371 unsigned int grow
: 1; /* MEMORY is allowed to grow. */
373 func_realloc_t func_realloc
;
374 func_free_t func_free
;
375 } *estream_cookie_mem_t
;
378 /* Create function for memory objects. */
380 es_func_mem_create (void *ES__RESTRICT
*ES__RESTRICT cookie
,
381 unsigned char *ES__RESTRICT data
, size_t data_n
,
383 size_t block_size
, unsigned int grow
,
384 func_realloc_t func_realloc
, func_free_t func_free
,
385 unsigned int modeflags
,
388 estream_cookie_mem_t mem_cookie
;
391 mem_cookie
= mem_alloc (sizeof (*mem_cookie
));
396 mem_cookie
->modeflags
= modeflags
;
397 mem_cookie
->memory
= data
;
398 mem_cookie
->memory_size
= data_n
;
399 mem_cookie
->memory_limit
= memory_limit
;
400 mem_cookie
->offset
= 0;
401 mem_cookie
->data_len
= data_len
;
402 mem_cookie
->block_size
= block_size
;
403 mem_cookie
->flags
.grow
= !!grow
;
404 mem_cookie
->func_realloc
= func_realloc
? func_realloc
: mem_realloc
;
405 mem_cookie
->func_free
= func_free
? func_free
: mem_free
;
406 *cookie
= mem_cookie
;
414 /* Read function for memory objects. */
416 es_func_mem_read (void *cookie
, void *buffer
, size_t size
)
418 estream_cookie_mem_t mem_cookie
= cookie
;
421 if (size
> mem_cookie
->data_len
- mem_cookie
->offset
)
422 size
= mem_cookie
->data_len
- mem_cookie
->offset
;
426 memcpy (buffer
, mem_cookie
->memory
+ mem_cookie
->offset
, size
);
427 mem_cookie
->offset
+= size
;
435 /* Write function for memory objects. */
437 es_func_mem_write (void *cookie
, const void *buffer
, size_t size
)
439 estream_cookie_mem_t mem_cookie
= cookie
;
443 return 0; /* A flush is a NOP for memory objects. */
445 if (mem_cookie
->modeflags
& O_APPEND
)
447 /* Append to data. */
448 mem_cookie
->offset
= mem_cookie
->data_len
;
451 if (!mem_cookie
->flags
.grow
)
453 /* We are not alloew to grow, thus limit the size to the left
454 space. FIXME: Does the grow flag an its semtics make sense
456 if (size
> mem_cookie
->memory_size
- mem_cookie
->offset
)
457 size
= mem_cookie
->memory_size
- mem_cookie
->offset
;
460 if (size
> (mem_cookie
->memory_size
- mem_cookie
->offset
))
462 unsigned char *newbuf
;
465 newsize
= mem_cookie
->memory_size
+ mem_cookie
->block_size
;
467 newsize
= mem_cookie
->offset
+ size
;
468 if (newsize
< mem_cookie
->offset
)
473 newsize
+= mem_cookie
->block_size
- 1;
474 if (newsize
< mem_cookie
->offset
)
479 newsize
/= mem_cookie
->block_size
;
480 newsize
*= mem_cookie
->block_size
;
482 if (mem_cookie
->memory_limit
&& newsize
> mem_cookie
->memory_limit
)
488 newbuf
= mem_cookie
->func_realloc (mem_cookie
->memory
, newsize
);
492 mem_cookie
->memory
= newbuf
;
493 mem_cookie
->memory_size
= newsize
;
495 assert (!(size
> (mem_cookie
->memory_size
- mem_cookie
->offset
)));
498 memcpy (mem_cookie
->memory
+ mem_cookie
->offset
, buffer
, size
);
499 if (mem_cookie
->offset
+ size
> mem_cookie
->data_len
)
500 mem_cookie
->data_len
= mem_cookie
->offset
+ size
;
501 mem_cookie
->offset
+= size
;
508 /* Seek function for memory objects. */
510 es_func_mem_seek (void *cookie
, off_t
*offset
, int whence
)
512 estream_cookie_mem_t mem_cookie
= cookie
;
522 pos_new
= mem_cookie
->offset
+= *offset
;
526 pos_new
= mem_cookie
->data_len
+= *offset
;
534 if (pos_new
> mem_cookie
->memory_size
)
539 if (!mem_cookie
->flags
.grow
)
546 newsize
= pos_new
+ mem_cookie
->block_size
- 1;
547 if (newsize
< pos_new
)
552 newsize
/= mem_cookie
->block_size
;
553 newsize
*= mem_cookie
->block_size
;
554 if (mem_cookie
->memory_limit
&& newsize
> mem_cookie
->memory_limit
)
560 newbuf
= mem_cookie
->func_realloc (mem_cookie
->memory
, newsize
);
564 mem_cookie
->memory
= newbuf
;
565 mem_cookie
->memory_size
= newsize
;
568 if (pos_new
> mem_cookie
->data_len
)
570 /* Fill spare space with zeroes. */
571 memset (mem_cookie
->memory
+ mem_cookie
->data_len
,
572 0, pos_new
- mem_cookie
->data_len
);
573 mem_cookie
->data_len
= pos_new
;
576 mem_cookie
->offset
= pos_new
;
583 /* Destroy function for memory objects. */
585 es_func_mem_destroy (void *cookie
)
587 estream_cookie_mem_t mem_cookie
= cookie
;
591 mem_cookie
->func_free (mem_cookie
->memory
);
592 mem_free (mem_cookie
);
598 static es_cookie_io_functions_t estream_functions_mem
=
608 /* Implementation of fd I/O. */
610 /* Cookie for fd objects. */
611 typedef struct estream_cookie_fd
613 int fd
; /* The file descriptor we are using for actual output. */
614 int no_close
; /* If set we won't close the file descriptor. */
615 } *estream_cookie_fd_t
;
617 /* Create function for fd objects. */
619 es_func_fd_create (void **cookie
, int fd
, unsigned int modeflags
, int no_close
)
621 estream_cookie_fd_t fd_cookie
;
624 fd_cookie
= mem_alloc (sizeof (*fd_cookie
));
629 #ifdef HAVE_DOSISH_SYSTEM
630 /* Make sure it is in binary mode if requested. */
631 if ( (modeflags
& O_BINARY
) )
632 setmode (fd
, O_BINARY
);
637 fd_cookie
->no_close
= no_close
;
645 /* Read function for fd objects. */
647 es_func_fd_read (void *cookie
, void *buffer
, size_t size
)
650 estream_cookie_fd_t file_cookie
= cookie
;
654 bytes_read
= ESTREAM_SYS_READ (file_cookie
->fd
, buffer
, size
);
655 while (bytes_read
== -1 && errno
== EINTR
);
660 /* Write function for fd objects. */
662 es_func_fd_write (void *cookie
, const void *buffer
, size_t size
)
665 estream_cookie_fd_t file_cookie
= cookie
;
666 ssize_t bytes_written
;
669 bytes_written
= ESTREAM_SYS_WRITE (file_cookie
->fd
, buffer
, size
);
670 while (bytes_written
== -1 && errno
== EINTR
);
672 return bytes_written
;
675 /* Seek function for fd objects. */
677 es_func_fd_seek (void *cookie
, off_t
*offset
, int whence
)
679 estream_cookie_fd_t file_cookie
= cookie
;
683 offset_new
= lseek (file_cookie
->fd
, *offset
, whence
);
684 if (offset_new
== -1)
688 *offset
= offset_new
;
695 /* Destroy function for fd objects. */
697 es_func_fd_destroy (void *cookie
)
699 estream_cookie_fd_t fd_cookie
= cookie
;
704 err
= fd_cookie
->no_close
? 0 : close (fd_cookie
->fd
);
705 mem_free (fd_cookie
);
714 static es_cookie_io_functions_t estream_functions_fd
=
725 /* Implementation of FILE* I/O. */
727 /* Cookie for fp objects. */
728 typedef struct estream_cookie_fp
730 FILE *fp
; /* The file pointer we are using for actual output. */
731 int no_close
; /* If set we won't close the file pointer. */
732 } *estream_cookie_fp_t
;
734 /* Create function for fd objects. */
736 es_func_fp_create (void **cookie
, FILE *fp
,
737 unsigned int modeflags
, int no_close
)
739 estream_cookie_fp_t fp_cookie
;
742 fp_cookie
= mem_alloc (sizeof *fp_cookie
);
747 #ifdef HAVE_DOSISH_SYSTEM
748 /* Make sure it is in binary mode if requested. */
749 if ( (modeflags
& O_BINARY
) )
750 setmode (fileno (fp
), O_BINARY
);
755 fp_cookie
->no_close
= no_close
;
763 /* Read function for FILE* objects. */
765 es_func_fp_read (void *cookie
, void *buffer
, size_t size
)
768 estream_cookie_fp_t file_cookie
= cookie
;
771 bytes_read
= fread (buffer
, 1, size
, file_cookie
->fp
);
772 if (!bytes_read
&& ferror (file_cookie
->fp
))
777 /* Write function for FILE* objects. */
779 es_func_fp_write (void *cookie
, const void *buffer
, size_t size
)
782 estream_cookie_fp_t file_cookie
= cookie
;
783 size_t bytes_written
;
785 bytes_written
= fwrite (buffer
, 1, size
, file_cookie
->fp
);
786 if (bytes_written
!= size
)
788 return bytes_written
;
791 /* Seek function for FILE* objects. */
793 es_func_fp_seek (void *cookie
, off_t
*offset
, int whence
)
795 estream_cookie_fp_t file_cookie
= cookie
;
798 if ( fseek (file_cookie
->fp
, (long int)*offset
, whence
) )
800 fprintf (stderr
, "\nfseek failed: errno=%d (%s)\n", errno
,strerror (errno
));
804 offset_new
= ftell (file_cookie
->fp
);
805 if (offset_new
== -1)
807 fprintf (stderr
, "\nftell failed: errno=%d (%s)\n", errno
,strerror (errno
));
810 *offset
= offset_new
;
814 /* Destroy function for fd objects. */
816 es_func_fp_destroy (void *cookie
)
818 estream_cookie_fp_t fp_cookie
= cookie
;
823 fflush (fp_cookie
->fp
);
824 err
= fp_cookie
->no_close
? 0 : fclose (fp_cookie
->fp
);
825 mem_free (fp_cookie
);
834 static es_cookie_io_functions_t estream_functions_fp
=
845 /* Implementation of file I/O. */
847 /* Create function for file objects. */
849 es_func_file_create (void **cookie
, int *filedes
,
850 const char *path
, unsigned int modeflags
)
852 estream_cookie_fd_t file_cookie
;
859 file_cookie
= mem_alloc (sizeof (*file_cookie
));
866 fd
= open (path
, modeflags
, ES_DEFAULT_OPEN_MODE
);
872 #ifdef HAVE_DOSISH_SYSTEM
873 /* Make sure it is in binary mode if requested. */
874 if ( (modeflags
& O_BINARY
) )
875 setmode (fd
, O_BINARY
);
878 file_cookie
->fd
= fd
;
879 file_cookie
->no_close
= 0;
880 *cookie
= file_cookie
;
886 mem_free (file_cookie
);
891 static es_cookie_io_functions_t estream_functions_file
=
901 es_convert_mode (const char *mode
, unsigned int *modeflags
)
903 unsigned int omode
, oflags
;
913 oflags
= O_TRUNC
| O_CREAT
;
917 oflags
= O_APPEND
| O_CREAT
;
923 for (mode
++; *mode
; mode
++)
936 default: /* Ignore unknown flags. */
941 *modeflags
= (omode
| oflags
);
948 * Low level stream functionality.
952 es_fill (estream_t stream
)
954 size_t bytes_read
= 0;
957 if (!stream
->intern
->func_read
)
964 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
967 ret
= (*func_read
) (stream
->intern
->cookie
,
968 stream
->buffer
, stream
->buffer_size
);
982 stream
->intern
->indicators
.err
= 1;
983 else if (!bytes_read
)
984 stream
->intern
->indicators
.eof
= 1;
986 stream
->intern
->offset
+= stream
->data_len
;
987 stream
->data_len
= bytes_read
;
988 stream
->data_offset
= 0;
994 es_flush (estream_t stream
)
996 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
999 assert (stream
->flags
.writing
);
1001 if (stream
->data_offset
)
1003 size_t bytes_written
;
1004 size_t data_flushed
;
1013 /* Note: to prevent an endless loop caused by user-provided
1014 write-functions that pretend to have written more bytes than
1015 they were asked to write, we have to check for
1016 "(stream->data_offset - data_flushed) > 0" instead of
1017 "stream->data_offset - data_flushed". */
1022 while ((((ssize_t
) (stream
->data_offset
- data_flushed
)) > 0) && (! err
))
1024 ret
= (*func_write
) (stream
->intern
->cookie
,
1025 stream
->buffer
+ data_flushed
,
1026 stream
->data_offset
- data_flushed
);
1033 bytes_written
= ret
;
1035 data_flushed
+= bytes_written
;
1040 stream
->data_flushed
+= data_flushed
;
1041 if (stream
->data_offset
== data_flushed
)
1043 stream
->intern
->offset
+= stream
->data_offset
;
1044 stream
->data_offset
= 0;
1045 stream
->data_flushed
= 0;
1047 /* Propagate flush event. */
1048 (*func_write
) (stream
->intern
->cookie
, NULL
, 0);
1057 stream
->intern
->indicators
.err
= 1;
1062 /* Discard buffered data for STREAM. */
1064 es_empty (estream_t stream
)
1066 assert (!stream
->flags
.writing
);
1067 stream
->data_len
= 0;
1068 stream
->data_offset
= 0;
1069 stream
->unread_data_len
= 0;
1072 /* Initialize STREAM. */
1074 es_initialize (estream_t stream
,
1075 void *cookie
, int fd
, es_cookie_io_functions_t functions
,
1076 unsigned int modeflags
)
1078 stream
->intern
->cookie
= cookie
;
1079 stream
->intern
->opaque
= NULL
;
1080 stream
->intern
->offset
= 0;
1081 stream
->intern
->func_read
= functions
.func_read
;
1082 stream
->intern
->func_write
= functions
.func_write
;
1083 stream
->intern
->func_seek
= functions
.func_seek
;
1084 stream
->intern
->func_close
= functions
.func_close
;
1085 stream
->intern
->strategy
= _IOFBF
;
1086 stream
->intern
->fd
= fd
;
1087 stream
->intern
->print_err
= 0;
1088 stream
->intern
->print_errno
= 0;
1089 stream
->intern
->print_ntotal
= 0;
1090 stream
->intern
->print_fp
= NULL
;
1091 stream
->intern
->indicators
.err
= 0;
1092 stream
->intern
->indicators
.eof
= 0;
1093 stream
->intern
->deallocate_buffer
= 0;
1095 stream
->data_len
= 0;
1096 stream
->data_offset
= 0;
1097 stream
->data_flushed
= 0;
1098 stream
->unread_data_len
= 0;
1099 /* Depending on the modeflags we set whether we start in writing or
1100 reading mode. This is required in case we are working on a
1101 wronly stream which is not seeekable (like stdout). Without this
1102 pre-initialization we would do a seek at the first write call and
1103 as this will fail no utput will be delivered. */
1104 if ((modeflags
& O_WRONLY
) || (modeflags
& O_RDWR
) )
1105 stream
->flags
.writing
= 1;
1107 stream
->flags
.writing
= 0;
1110 /* Deinitialize STREAM. */
1112 es_deinitialize (estream_t stream
)
1114 es_cookie_close_function_t func_close
;
1117 if (stream
->intern
->print_fp
)
1119 int save_errno
= errno
;
1120 fclose (stream
->intern
->print_fp
);
1121 stream
->intern
->print_fp
= NULL
;
1125 func_close
= stream
->intern
->func_close
;
1128 if (stream
->flags
.writing
)
1129 SET_UNLESS_NONZERO (err
, tmp_err
, es_flush (stream
));
1131 SET_UNLESS_NONZERO (err
, tmp_err
, (*func_close
) (stream
->intern
->cookie
));
1137 /* Create a new stream object, initialize it. */
1139 es_create (estream_t
*stream
, void *cookie
, int fd
,
1140 es_cookie_io_functions_t functions
, unsigned int modeflags
)
1142 estream_internal_t stream_internal_new
;
1143 estream_t stream_new
;
1147 stream_internal_new
= NULL
;
1149 stream_new
= mem_alloc (sizeof (*stream_new
));
1156 stream_internal_new
= mem_alloc (sizeof (*stream_internal_new
));
1157 if (! stream_internal_new
)
1163 stream_new
->buffer
= stream_internal_new
->buffer
;
1164 stream_new
->buffer_size
= sizeof (stream_internal_new
->buffer
);
1165 stream_new
->unread_buffer
= stream_internal_new
->unread_buffer
;
1166 stream_new
->unread_buffer_size
= sizeof (stream_internal_new
->unread_buffer
);
1167 stream_new
->intern
= stream_internal_new
;
1169 ESTREAM_MUTEX_INITIALIZE (stream_new
->intern
->lock
);
1170 es_initialize (stream_new
, cookie
, fd
, functions
, modeflags
);
1172 err
= es_list_add (stream_new
);
1176 *stream
= stream_new
;
1184 es_deinitialize (stream_new
);
1185 mem_free (stream_new
);
1192 /* Deinitialize a stream object and destroy it. */
1194 es_destroy (estream_t stream
)
1200 es_list_remove (stream
);
1201 err
= es_deinitialize (stream
);
1202 mem_free (stream
->intern
);
1209 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1210 unbuffered-mode, storing the amount of bytes read in
1213 es_read_nbf (estream_t ES__RESTRICT stream
,
1214 unsigned char *ES__RESTRICT buffer
,
1215 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1217 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
1225 while (bytes_to_read
- data_read
)
1227 ret
= (*func_read
) (stream
->intern
->cookie
,
1228 buffer
+ data_read
, bytes_to_read
- data_read
);
1240 stream
->intern
->offset
+= data_read
;
1241 *bytes_read
= data_read
;
1246 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1247 fully-buffered-mode, storing the amount of bytes read in
1250 es_read_fbf (estream_t ES__RESTRICT stream
,
1251 unsigned char *ES__RESTRICT buffer
,
1252 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1254 size_t data_available
;
1255 size_t data_to_read
;
1262 while ((bytes_to_read
- data_read
) && (! err
))
1264 if (stream
->data_offset
== stream
->data_len
)
1266 /* Nothing more to read in current container, try to
1267 fill container with new data. */
1268 err
= es_fill (stream
);
1270 if (! stream
->data_len
)
1271 /* Filling did not result in any data read. */
1277 /* Filling resulted in some new data. */
1279 data_to_read
= bytes_to_read
- data_read
;
1280 data_available
= stream
->data_len
- stream
->data_offset
;
1281 if (data_to_read
> data_available
)
1282 data_to_read
= data_available
;
1284 memcpy (buffer
+ data_read
,
1285 stream
->buffer
+ stream
->data_offset
, data_to_read
);
1286 stream
->data_offset
+= data_to_read
;
1287 data_read
+= data_to_read
;
1291 *bytes_read
= data_read
;
1296 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1297 line-buffered-mode, storing the amount of bytes read in
1300 es_read_lbf (estream_t ES__RESTRICT stream
,
1301 unsigned char *ES__RESTRICT buffer
,
1302 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1306 err
= es_read_fbf (stream
, buffer
, bytes_to_read
, bytes_read
);
1311 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1312 *the amount of bytes read in BYTES_READ. */
1314 es_readn (estream_t ES__RESTRICT stream
,
1315 void *ES__RESTRICT buffer_arg
,
1316 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1318 unsigned char *buffer
= (unsigned char *)buffer_arg
;
1319 size_t data_read_unread
, data_read
;
1322 data_read_unread
= 0;
1326 if (stream
->flags
.writing
)
1328 /* Switching to reading mode -> flush output. */
1329 err
= es_flush (stream
);
1332 stream
->flags
.writing
= 0;
1335 /* Read unread data first. */
1336 while ((bytes_to_read
- data_read_unread
) && stream
->unread_data_len
)
1338 buffer
[data_read_unread
]
1339 = stream
->unread_buffer
[stream
->unread_data_len
- 1];
1340 stream
->unread_data_len
--;
1344 switch (stream
->intern
->strategy
)
1347 err
= es_read_nbf (stream
,
1348 buffer
+ data_read_unread
,
1349 bytes_to_read
- data_read_unread
, &data_read
);
1352 err
= es_read_lbf (stream
,
1353 buffer
+ data_read_unread
,
1354 bytes_to_read
- data_read_unread
, &data_read
);
1357 err
= es_read_fbf (stream
,
1358 buffer
+ data_read_unread
,
1359 bytes_to_read
- data_read_unread
, &data_read
);
1366 *bytes_read
= data_read_unread
+ data_read
;
1371 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1372 amount of bytes succesfully unread in *BYTES_UNREAD. */
1374 es_unreadn (estream_t ES__RESTRICT stream
,
1375 const unsigned char *ES__RESTRICT data
, size_t data_n
,
1376 size_t *ES__RESTRICT bytes_unread
)
1380 space_left
= stream
->unread_buffer_size
- stream
->unread_data_len
;
1382 if (data_n
> space_left
)
1383 data_n
= space_left
;
1388 memcpy (stream
->unread_buffer
+ stream
->unread_data_len
, data
, data_n
);
1389 stream
->unread_data_len
+= data_n
;
1390 stream
->intern
->indicators
.eof
= 0;
1395 *bytes_unread
= data_n
;
1398 /* Seek in STREAM. */
1400 es_seek (estream_t ES__RESTRICT stream
, off_t offset
, int whence
,
1401 off_t
*ES__RESTRICT offset_new
)
1403 es_cookie_seek_function_t func_seek
= stream
->intern
->func_seek
;
1414 if (stream
->flags
.writing
)
1416 /* Flush data first in order to prevent flushing it to the wrong
1418 err
= es_flush (stream
);
1421 stream
->flags
.writing
= 0;
1425 if (whence
== SEEK_CUR
)
1427 off
= off
- stream
->data_len
+ stream
->data_offset
;
1428 off
-= stream
->unread_data_len
;
1431 ret
= (*func_seek
) (stream
->intern
->cookie
, &off
, whence
);
1444 stream
->intern
->indicators
.eof
= 0;
1445 stream
->intern
->offset
= off
;
1450 stream
->intern
->indicators
.err
= 1;
1455 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1456 unbuffered-mode, storing the amount of bytes written in
1459 es_write_nbf (estream_t ES__RESTRICT stream
,
1460 const unsigned char *ES__RESTRICT buffer
,
1461 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1463 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1464 size_t data_written
;
1468 if (bytes_to_write
&& (! func_write
))
1477 while (bytes_to_write
- data_written
)
1479 ret
= (*func_write
) (stream
->intern
->cookie
,
1480 buffer
+ data_written
,
1481 bytes_to_write
- data_written
);
1488 data_written
+= ret
;
1491 stream
->intern
->offset
+= data_written
;
1492 *bytes_written
= data_written
;
1499 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1500 fully-buffered-mode, storing the amount of bytes written in
1503 es_write_fbf (estream_t ES__RESTRICT stream
,
1504 const unsigned char *ES__RESTRICT buffer
,
1505 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1507 size_t space_available
;
1508 size_t data_to_write
;
1509 size_t data_written
;
1515 while ((bytes_to_write
- data_written
) && (! err
))
1517 if (stream
->data_offset
== stream
->buffer_size
)
1518 /* Container full, flush buffer. */
1519 err
= es_flush (stream
);
1523 /* Flushing resulted in empty container. */
1525 data_to_write
= bytes_to_write
- data_written
;
1526 space_available
= stream
->buffer_size
- stream
->data_offset
;
1527 if (data_to_write
> space_available
)
1528 data_to_write
= space_available
;
1530 memcpy (stream
->buffer
+ stream
->data_offset
,
1531 buffer
+ data_written
, data_to_write
);
1532 stream
->data_offset
+= data_to_write
;
1533 data_written
+= data_to_write
;
1537 *bytes_written
= data_written
;
1543 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1544 line-buffered-mode, storing the amount of bytes written in
1547 es_write_lbf (estream_t ES__RESTRICT stream
,
1548 const unsigned char *ES__RESTRICT buffer
,
1549 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1551 size_t data_flushed
= 0;
1552 size_t data_buffered
= 0;
1556 nlp
= memrchr (buffer
, '\n', bytes_to_write
);
1559 /* Found a newline, directly write up to (including) this
1561 err
= es_flush (stream
);
1563 err
= es_write_nbf (stream
, buffer
, nlp
- buffer
+ 1, &data_flushed
);
1568 /* Write remaining data fully buffered. */
1569 err
= es_write_fbf (stream
, buffer
+ data_flushed
,
1570 bytes_to_write
- data_flushed
, &data_buffered
);
1573 *bytes_written
= data_flushed
+ data_buffered
;
1578 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1579 amount of bytes written in BYTES_WRITTEN. */
1581 es_writen (estream_t ES__RESTRICT stream
,
1582 const void *ES__RESTRICT buffer
,
1583 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1585 size_t data_written
;
1591 if (!stream
->flags
.writing
)
1593 /* Switching to writing mode -> discard input data and seek to
1594 position at which reading has stopped. We can do this only
1595 if a seek function has been registered. */
1596 if (stream
->intern
->func_seek
)
1598 err
= es_seek (stream
, 0, SEEK_CUR
, NULL
);
1601 if (errno
== ESPIPE
)
1609 switch (stream
->intern
->strategy
)
1612 err
= es_write_nbf (stream
, buffer
, bytes_to_write
, &data_written
);
1616 err
= es_write_lbf (stream
, buffer
, bytes_to_write
, &data_written
);
1620 err
= es_write_fbf (stream
, buffer
, bytes_to_write
, &data_written
);
1627 *bytes_written
= data_written
;
1629 if (!stream
->flags
.writing
)
1630 stream
->flags
.writing
= 1;
1637 es_peek (estream_t ES__RESTRICT stream
, unsigned char **ES__RESTRICT data
,
1638 size_t *ES__RESTRICT data_len
)
1642 if (stream
->flags
.writing
)
1644 /* Switching to reading mode -> flush output. */
1645 err
= es_flush (stream
);
1648 stream
->flags
.writing
= 0;
1651 if (stream
->data_offset
== stream
->data_len
)
1653 /* Refill container. */
1654 err
= es_fill (stream
);
1660 *data
= stream
->buffer
+ stream
->data_offset
;
1662 *data_len
= stream
->data_len
- stream
->data_offset
;
1671 /* Skip SIZE bytes of input data contained in buffer. */
1673 es_skip (estream_t stream
, size_t size
)
1677 if (stream
->data_offset
+ size
> stream
->data_len
)
1684 stream
->data_offset
+= size
;
1693 doreadline (estream_t ES__RESTRICT stream
, size_t max_length
,
1694 char *ES__RESTRICT
*ES__RESTRICT line
,
1695 size_t *ES__RESTRICT line_length
)
1699 estream_t line_stream
;
1701 void *line_stream_cookie
;
1703 unsigned char *data
;
1709 line_stream_cookie
= NULL
;
1711 err
= es_func_mem_create (&line_stream_cookie
, NULL
, 0, 0,
1712 BUFFER_BLOCK_SIZE
, 1,
1713 mem_realloc
, mem_free
,
1719 err
= es_create (&line_stream
, line_stream_cookie
, -1,
1720 estream_functions_mem
, O_RDWR
);
1724 space_left
= max_length
;
1728 if (max_length
&& (space_left
== 1))
1731 err
= es_peek (stream
, &data
, &data_len
);
1732 if (err
|| (! data_len
))
1735 if (data_len
> (space_left
- 1))
1736 data_len
= space_left
- 1;
1738 newline
= memchr (data
, '\n', data_len
);
1741 data_len
= (newline
- (char *) data
) + 1;
1742 err
= es_write (line_stream
, data
, data_len
, NULL
);
1745 space_left
-= data_len
;
1746 line_size
+= data_len
;
1747 es_skip (stream
, data_len
);
1753 err
= es_write (line_stream
, data
, data_len
, NULL
);
1756 space_left
-= data_len
;
1757 line_size
+= data_len
;
1758 es_skip (stream
, data_len
);
1767 /* Complete line has been written to line_stream. */
1769 if ((max_length
> 1) && (! line_size
))
1771 stream
->intern
->indicators
.eof
= 1;
1775 err
= es_seek (line_stream
, 0, SEEK_SET
, NULL
);
1781 line_new
= mem_alloc (line_size
+ 1);
1791 err
= es_read (line_stream
, line_new
, line_size
, NULL
);
1795 line_new
[line_size
] = '\0';
1800 *line_length
= line_size
;
1805 es_destroy (line_stream
);
1806 else if (line_stream_cookie
)
1807 es_func_mem_destroy (line_stream_cookie
);
1812 mem_free (line_new
);
1813 stream
->intern
->indicators
.err
= 1;
1820 /* Output fucntion used for estream_format. */
1822 print_writer (void *outfncarg
, const char *buf
, size_t buflen
)
1824 estream_t stream
= outfncarg
;
1829 rc
= es_writen (stream
, buf
, buflen
, &nwritten
);
1830 stream
->intern
->print_ntotal
+= nwritten
;
1835 /* The core of our printf function. This is called in locked state. */
1837 es_print (estream_t ES__RESTRICT stream
,
1838 const char *ES__RESTRICT format
, va_list ap
)
1842 stream
->intern
->print_ntotal
= 0;
1843 rc
= estream_format (print_writer
, stream
, format
, ap
);
1846 return (int)stream
->intern
->print_ntotal
;
1851 es_set_indicators (estream_t stream
, int ind_err
, int ind_eof
)
1854 stream
->intern
->indicators
.err
= ind_err
? 1 : 0;
1856 stream
->intern
->indicators
.eof
= ind_eof
? 1 : 0;
1861 es_get_indicator (estream_t stream
, int ind_err
, int ind_eof
)
1866 ret
= stream
->intern
->indicators
.err
;
1868 ret
= stream
->intern
->indicators
.eof
;
1875 es_set_buffering (estream_t ES__RESTRICT stream
,
1876 char *ES__RESTRICT buffer
, int mode
, size_t size
)
1880 /* Flush or empty buffer depending on mode. */
1881 if (stream
->flags
.writing
)
1883 err
= es_flush (stream
);
1890 es_set_indicators (stream
, -1, 0);
1892 /* Free old buffer in case that was allocated by this function. */
1893 if (stream
->intern
->deallocate_buffer
)
1895 stream
->intern
->deallocate_buffer
= 0;
1896 mem_free (stream
->buffer
);
1897 stream
->buffer
= NULL
;
1901 stream
->buffer_size
= 0;
1907 buffer_new
= buffer
;
1910 buffer_new
= mem_alloc (size
);
1918 stream
->buffer
= buffer_new
;
1919 stream
->buffer_size
= size
;
1921 stream
->intern
->deallocate_buffer
= 1;
1923 stream
->intern
->strategy
= mode
;
1933 es_offset_calculate (estream_t stream
)
1937 offset
= stream
->intern
->offset
+ stream
->data_offset
;
1938 if (offset
< stream
->unread_data_len
)
1939 /* Offset undefined. */
1942 offset
-= stream
->unread_data_len
;
1949 es_opaque_ctrl (estream_t ES__RESTRICT stream
, void *ES__RESTRICT opaque_new
,
1950 void **ES__RESTRICT opaque_old
)
1953 *opaque_old
= stream
->intern
->opaque
;
1955 stream
->intern
->opaque
= opaque_new
;
1960 es_get_fd (estream_t stream
)
1962 return stream
->intern
->fd
;
1974 err
= es_init_do ();
1980 es_fopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
)
1982 unsigned int modeflags
;
1993 err
= es_convert_mode (mode
, &modeflags
);
1997 err
= es_func_file_create (&cookie
, &fd
, path
, modeflags
);
2002 err
= es_create (&stream
, cookie
, fd
, estream_functions_file
, modeflags
);
2008 if (err
&& create_called
)
2009 (*estream_functions_file
.func_close
) (cookie
);
2016 es_mopen (unsigned char *ES__RESTRICT data
, size_t data_n
, size_t data_len
,
2018 func_realloc_t func_realloc
, func_free_t func_free
,
2019 const char *ES__RESTRICT mode
)
2021 unsigned int modeflags
;
2031 err
= es_convert_mode (mode
, &modeflags
);
2035 err
= es_func_mem_create (&cookie
, data
, data_n
, data_len
,
2036 BUFFER_BLOCK_SIZE
, grow
,
2037 func_realloc
, func_free
, modeflags
, 0);
2042 err
= es_create (&stream
, cookie
, -1, estream_functions_mem
, modeflags
);
2046 if (err
&& create_called
)
2047 (*estream_functions_mem
.func_close
) (cookie
);
2054 es_fopenmem (size_t memlimit
, const char *ES__RESTRICT mode
)
2056 unsigned int modeflags
;
2057 estream_t stream
= NULL
;
2058 void *cookie
= NULL
;
2060 /* Memory streams are always read/write. We use MODE only to get
2062 if (es_convert_mode (mode
, &modeflags
))
2064 modeflags
|= O_RDWR
;
2067 if (es_func_mem_create (&cookie
, NULL
, 0, 0,
2068 BUFFER_BLOCK_SIZE
, 1,
2069 mem_realloc
, mem_free
, modeflags
,
2073 if (es_create (&stream
, cookie
, -1, estream_functions_mem
, modeflags
))
2074 (*estream_functions_mem
.func_close
) (cookie
);
2082 es_fopencookie (void *ES__RESTRICT cookie
,
2083 const char *ES__RESTRICT mode
,
2084 es_cookie_io_functions_t functions
)
2086 unsigned int modeflags
;
2093 err
= es_convert_mode (mode
, &modeflags
);
2097 err
= es_create (&stream
, cookie
, -1, functions
, modeflags
);
2108 do_fdopen (int filedes
, const char *mode
, int no_close
)
2110 unsigned int modeflags
;
2120 err
= es_convert_mode (mode
, &modeflags
);
2124 err
= es_func_fd_create (&cookie
, filedes
, modeflags
, no_close
);
2129 err
= es_create (&stream
, cookie
, filedes
, estream_functions_fd
, modeflags
);
2133 if (err
&& create_called
)
2134 (*estream_functions_fd
.func_close
) (cookie
);
2140 es_fdopen (int filedes
, const char *mode
)
2142 return do_fdopen (filedes
, mode
, 0);
2145 /* A variant of es_fdopen which does not close FILEDES at the end. */
2147 es_fdopen_nc (int filedes
, const char *mode
)
2149 return do_fdopen (filedes
, mode
, 1);
2154 do_fpopen (FILE *fp
, const char *mode
, int no_close
)
2156 unsigned int modeflags
;
2166 err
= es_convert_mode (mode
, &modeflags
);
2171 err
= es_func_fp_create (&cookie
, fp
, modeflags
, no_close
);
2176 err
= es_create (&stream
, cookie
, fileno (fp
), estream_functions_fp
,
2181 if (err
&& create_called
)
2182 (*estream_functions_fp
.func_close
) (cookie
);
2188 /* Create an estream from the stdio stream FP. This mechanism is
2189 useful in case the stdio streams have special properties and may
2190 not be mixed with fd based functions. This is for example the case
2191 under Windows where the 3 standard streams are associated with the
2192 console whereas a duped and fd-opened stream of one of this stream
2193 won't be associated with the console. As this messes things up it
2194 is easier to keep on using the standard I/O stream as a backend for
2197 es_fpopen (FILE *fp
, const char *mode
)
2199 return do_fpopen (fp
, mode
, 0);
2203 /* Same as es_fpopen but does not close FP at the end. */
2205 es_fpopen_nc (FILE *fp
, const char *mode
)
2207 return do_fpopen (fp
, mode
, 1);
2212 es_freopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
,
2213 estream_t ES__RESTRICT stream
)
2219 unsigned int modeflags
;
2227 ESTREAM_LOCK (stream
);
2229 es_deinitialize (stream
);
2231 err
= es_convert_mode (mode
, &modeflags
);
2235 err
= es_func_file_create (&cookie
, &fd
, path
, modeflags
);
2240 es_initialize (stream
, cookie
, fd
, estream_functions_file
, modeflags
);
2247 es_func_fd_destroy (cookie
);
2249 es_destroy (stream
);
2253 ESTREAM_UNLOCK (stream
);
2257 /* FIXME? We don't support re-opening at the moment. */
2259 es_deinitialize (stream
);
2260 es_destroy (stream
);
2269 es_fclose (estream_t stream
)
2273 err
= es_destroy (stream
);
2279 es_fileno_unlocked (estream_t stream
)
2281 return es_get_fd (stream
);
2286 es_flockfile (estream_t stream
)
2288 ESTREAM_LOCK (stream
);
2293 es_ftrylockfile (estream_t stream
)
2295 return ESTREAM_TRYLOCK (stream
);
2300 es_funlockfile (estream_t stream
)
2302 ESTREAM_UNLOCK (stream
);
2307 es_fileno (estream_t stream
)
2311 ESTREAM_LOCK (stream
);
2312 ret
= es_fileno_unlocked (stream
);
2313 ESTREAM_UNLOCK (stream
);
2320 es_feof_unlocked (estream_t stream
)
2322 return es_get_indicator (stream
, 0, 1);
2327 es_feof (estream_t stream
)
2331 ESTREAM_LOCK (stream
);
2332 ret
= es_feof_unlocked (stream
);
2333 ESTREAM_UNLOCK (stream
);
2340 es_ferror_unlocked (estream_t stream
)
2342 return es_get_indicator (stream
, 1, 0);
2347 es_ferror (estream_t stream
)
2351 ESTREAM_LOCK (stream
);
2352 ret
= es_ferror_unlocked (stream
);
2353 ESTREAM_UNLOCK (stream
);
2360 es_clearerr_unlocked (estream_t stream
)
2362 es_set_indicators (stream
, 0, 0);
2367 es_clearerr (estream_t stream
)
2369 ESTREAM_LOCK (stream
);
2370 es_clearerr_unlocked (stream
);
2371 ESTREAM_UNLOCK (stream
);
2376 es_fflush (estream_t stream
)
2382 ESTREAM_LOCK (stream
);
2383 if (stream
->flags
.writing
)
2384 err
= es_flush (stream
);
2390 ESTREAM_UNLOCK (stream
);
2393 err
= es_list_iterate (es_fflush
);
2395 return err
? EOF
: 0;
2400 es_fseek (estream_t stream
, long int offset
, int whence
)
2404 ESTREAM_LOCK (stream
);
2405 err
= es_seek (stream
, offset
, whence
, NULL
);
2406 ESTREAM_UNLOCK (stream
);
2413 es_fseeko (estream_t stream
, off_t offset
, int whence
)
2417 ESTREAM_LOCK (stream
);
2418 err
= es_seek (stream
, offset
, whence
, NULL
);
2419 ESTREAM_UNLOCK (stream
);
2426 es_ftell (estream_t stream
)
2430 ESTREAM_LOCK (stream
);
2431 ret
= es_offset_calculate (stream
);
2432 ESTREAM_UNLOCK (stream
);
2439 es_ftello (estream_t stream
)
2443 ESTREAM_LOCK (stream
);
2444 ret
= es_offset_calculate (stream
);
2445 ESTREAM_UNLOCK (stream
);
2452 es_rewind (estream_t stream
)
2454 ESTREAM_LOCK (stream
);
2455 es_seek (stream
, 0L, SEEK_SET
, NULL
);
2456 es_set_indicators (stream
, 0, -1);
2457 ESTREAM_UNLOCK (stream
);
2462 _es_getc_underflow (estream_t stream
)
2468 err
= es_readn (stream
, &c
, 1, &bytes_read
);
2470 return (err
|| (! bytes_read
)) ? EOF
: c
;
2475 _es_putc_overflow (int c
, estream_t stream
)
2477 unsigned char d
= c
;
2480 err
= es_writen (stream
, &d
, 1, NULL
);
2482 return err
? EOF
: c
;
2487 es_fgetc (estream_t stream
)
2491 ESTREAM_LOCK (stream
);
2492 ret
= es_getc_unlocked (stream
);
2493 ESTREAM_UNLOCK (stream
);
2500 es_fputc (int c
, estream_t stream
)
2504 ESTREAM_LOCK (stream
);
2505 ret
= es_putc_unlocked (c
, stream
);
2506 ESTREAM_UNLOCK (stream
);
2513 es_ungetc (int c
, estream_t stream
)
2515 unsigned char data
= (unsigned char) c
;
2518 ESTREAM_LOCK (stream
);
2519 es_unreadn (stream
, &data
, 1, &data_unread
);
2520 ESTREAM_UNLOCK (stream
);
2522 return data_unread
? c
: EOF
;
2527 es_read (estream_t ES__RESTRICT stream
,
2528 void *ES__RESTRICT buffer
, size_t bytes_to_read
,
2529 size_t *ES__RESTRICT bytes_read
)
2535 ESTREAM_LOCK (stream
);
2536 err
= es_readn (stream
, buffer
, bytes_to_read
, bytes_read
);
2537 ESTREAM_UNLOCK (stream
);
2547 es_write (estream_t ES__RESTRICT stream
,
2548 const void *ES__RESTRICT buffer
, size_t bytes_to_write
,
2549 size_t *ES__RESTRICT bytes_written
)
2555 ESTREAM_LOCK (stream
);
2556 err
= es_writen (stream
, buffer
, bytes_to_write
, bytes_written
);
2557 ESTREAM_UNLOCK (stream
);
2567 es_fread (void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2568 estream_t ES__RESTRICT stream
)
2575 ESTREAM_LOCK (stream
);
2576 err
= es_readn (stream
, ptr
, size
* nitems
, &bytes
);
2577 ESTREAM_UNLOCK (stream
);
2589 es_fwrite (const void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2590 estream_t ES__RESTRICT stream
)
2597 ESTREAM_LOCK (stream
);
2598 err
= es_writen (stream
, ptr
, size
* nitems
, &bytes
);
2599 ESTREAM_UNLOCK (stream
);
2611 es_fgets (char *ES__RESTRICT buffer
, int length
, estream_t ES__RESTRICT stream
)
2613 unsigned char *s
= (unsigned char*)buffer
;
2620 ESTREAM_LOCK (stream
);
2621 while (length
> 1 && (c
= es_getc_unlocked (stream
)) != EOF
&& c
!= '\n')
2626 ESTREAM_UNLOCK (stream
);
2628 if (c
== EOF
&& s
== (unsigned char*)buffer
)
2629 return NULL
; /* Nothing read. */
2631 if (c
!= EOF
&& length
> 1)
2640 es_fputs (const char *ES__RESTRICT s
, estream_t ES__RESTRICT stream
)
2645 length
= strlen (s
);
2646 ESTREAM_LOCK (stream
);
2647 err
= es_writen (stream
, s
, length
, NULL
);
2648 ESTREAM_UNLOCK (stream
);
2650 return err
? EOF
: 0;
2655 es_getline (char *ES__RESTRICT
*ES__RESTRICT lineptr
, size_t *ES__RESTRICT n
,
2656 estream_t ES__RESTRICT stream
)
2662 ESTREAM_LOCK (stream
);
2663 err
= doreadline (stream
, 0, &line
, &line_n
);
2664 ESTREAM_UNLOCK (stream
);
2670 /* Caller wants us to use his buffer. */
2672 if (*n
< (line_n
+ 1))
2674 /* Provided buffer is too small -> resize. */
2678 p
= mem_realloc (*lineptr
, line_n
+ 1);
2690 memcpy (*lineptr
, line
, line_n
+ 1);
2698 /* Caller wants new buffers. */
2705 return err
? err
: line_n
;
2710 /* Same as fgets() but if the provided buffer is too short a larger
2711 one will be allocated. This is similar to getline. A line is
2712 considered a byte stream ending in a LF.
2714 If MAX_LENGTH is not NULL, it shall point to a value with the
2715 maximum allowed allocation.
2717 Returns the length of the line. EOF is indicated by a line of
2718 length zero. A truncated line is indicated my setting the value at
2719 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2720 memory was enable or another error occurred; ERRNO is then set
2723 If a line has been truncated, the file pointer is moved forward to
2724 the end of the line so that the next read starts with the next
2725 line. Note that MAX_LENGTH must be re-initialzied in this case.
2727 The caller initially needs to provide the address of a variable,
2728 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2729 anymore with the following invocations. LENGTH_OF_BUFFER should be
2730 the address of a variable, initialized to 0, which is also
2731 maintained by this function. Thus, both paramaters should be
2732 considered the state of this function.
2734 Note: The returned buffer is allocated with enough extra space to
2735 allow the caller to append a CR,LF,Nul. The buffer should be
2736 released using es_free.
2739 es_read_line (estream_t stream
,
2740 char **addr_of_buffer
, size_t *length_of_buffer
,
2744 char *buffer
= *addr_of_buffer
;
2745 size_t length
= *length_of_buffer
;
2747 size_t maxlen
= max_length
? *max_length
: 0;
2752 /* No buffer given - allocate a new one. */
2754 buffer
= mem_alloc (length
);
2755 *addr_of_buffer
= buffer
;
2758 *length_of_buffer
= 0;
2763 *length_of_buffer
= length
;
2768 /* This should never happen. If it does, the function has been
2769 called with wrong arguments. */
2773 length
-= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2775 ESTREAM_LOCK (stream
);
2777 while ((c
= es_getc_unlocked (stream
)) != EOF
)
2779 if (nbytes
== length
)
2781 /* Enlarge the buffer. */
2782 if (maxlen
&& length
> maxlen
)
2784 /* We are beyond our limit: Skip the rest of the line. */
2785 while (c
!= '\n' && (c
=es_getc_unlocked (stream
)) != EOF
)
2787 *p
++ = '\n'; /* Always append a LF (we reserved some space). */
2790 *max_length
= 0; /* Indicate truncation. */
2791 break; /* the while loop. */
2793 length
+= 3; /* Adjust for the reserved bytes. */
2794 length
+= length
< 1024? 256 : 1024;
2795 *addr_of_buffer
= mem_realloc (buffer
, length
);
2796 if (!*addr_of_buffer
)
2798 int save_errno
= errno
;
2800 *length_of_buffer
= *max_length
= 0;
2801 ESTREAM_UNLOCK (stream
);
2805 buffer
= *addr_of_buffer
;
2806 *length_of_buffer
= length
;
2808 p
= buffer
+ nbytes
;
2815 *p
= 0; /* Make sure the line is a string. */
2816 ESTREAM_UNLOCK (stream
);
2821 /* Wrapper around free() to match the memory allocation system used
2822 by estream. Should be used for all buffers returned to the caller
2832 es_vfprintf (estream_t ES__RESTRICT stream
, const char *ES__RESTRICT format
,
2837 ESTREAM_LOCK (stream
);
2838 ret
= es_print (stream
, format
, ap
);
2839 ESTREAM_UNLOCK (stream
);
2846 es_fprintf_unlocked (estream_t ES__RESTRICT stream
,
2847 const char *ES__RESTRICT format
, ...)
2852 va_start (ap
, format
);
2853 ret
= es_print (stream
, format
, ap
);
2861 es_fprintf (estream_t ES__RESTRICT stream
,
2862 const char *ES__RESTRICT format
, ...)
2867 va_start (ap
, format
);
2868 ESTREAM_LOCK (stream
);
2869 ret
= es_print (stream
, format
, ap
);
2870 ESTREAM_UNLOCK (stream
);
2880 #ifdef HAVE_W32_SYSTEM
2882 char buffer
[MAX_PATH
+9+12+1];
2885 int pid
= GetCurrentProcessId ();
2889 n
= GetTempPath (MAX_PATH
+1, buffer
);
2890 if (!n
|| n
> MAX_PATH
|| strlen (buffer
) > MAX_PATH
)
2895 p
= buffer
+ strlen (buffer
);
2896 strcpy (p
, "_estream");
2898 /* We try to create the directory but don't care about an error as
2899 it may already exist and the CreateFile would throw an error
2901 CreateDirectory (buffer
, NULL
);
2904 for (attempts
=0; attempts
< 10; attempts
++)
2907 value
= (GetTickCount () ^ ((pid
<<16) & 0xffff0000));
2908 for (i
=0; i
< 8; i
++)
2910 *p
++ = tohex (((value
>> 28) & 0x0f));
2914 file
= CreateFile (buffer
,
2915 GENERIC_READ
| GENERIC_WRITE
,
2919 FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_DELETE_ON_CLOSE
,
2921 if (file
!= INVALID_HANDLE_VALUE
)
2923 int fd
= _open_osfhandle ((long)file
, 0);
2931 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
2935 #else /*!HAVE_W32_SYSTEM*/
2947 fp_fd
= fileno (fp
);
2956 #endif /*!HAVE_W32_SYSTEM*/
2962 unsigned int modeflags
;
2971 modeflags
= O_RDWR
| O_TRUNC
| O_CREAT
;
2981 err
= es_func_fd_create (&cookie
, fd
, modeflags
, 0);
2986 err
= es_create (&stream
, cookie
, fd
, estream_functions_fd
, modeflags
);
2993 es_func_fd_destroy (cookie
);
3004 es_setvbuf (estream_t ES__RESTRICT stream
,
3005 char *ES__RESTRICT buf
, int type
, size_t size
)
3009 if (((type
== _IOFBF
) || (type
== _IOLBF
) || (type
== _IONBF
))
3010 && (! ((! size
) && (type
!= _IONBF
))))
3012 ESTREAM_LOCK (stream
);
3013 err
= es_set_buffering (stream
, buf
, type
, size
);
3014 ESTREAM_UNLOCK (stream
);
3027 es_setbuf (estream_t ES__RESTRICT stream
, char *ES__RESTRICT buf
)
3029 ESTREAM_LOCK (stream
);
3030 es_set_buffering (stream
, buf
, buf
? _IOFBF
: _IONBF
, BUFSIZ
);
3031 ESTREAM_UNLOCK (stream
);
3035 es_opaque_set (estream_t stream
, void *opaque
)
3037 ESTREAM_LOCK (stream
);
3038 es_opaque_ctrl (stream
, opaque
, NULL
);
3039 ESTREAM_UNLOCK (stream
);
3044 es_opaque_get (estream_t stream
)
3048 ESTREAM_LOCK (stream
);
3049 es_opaque_ctrl (stream
, NULL
, &opaque
);
3050 ESTREAM_UNLOCK (stream
);
3055 /* Print a BUFFER to STREAM while replacing all control characters and
3056 the characters in DELIMITERS by standard C escape sequences.
3057 Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
3058 the number of bytes actually written are stored at this
3061 es_write_sanitized (estream_t ES__RESTRICT stream
,
3062 const void * ES__RESTRICT buffer
, size_t length
,
3063 const char * delimiters
,
3064 size_t * ES__RESTRICT bytes_written
)
3066 const unsigned char *p
= buffer
;
3070 ESTREAM_LOCK (stream
);
3071 for (; length
; length
--, p
++, count
++)
3076 && (strchr (delimiters
, *p
) || *p
== '\\')))
3078 es_putc_unlocked ('\\', stream
);
3082 es_putc_unlocked ('n', stream
);
3085 else if (*p
== '\r')
3087 es_putc_unlocked ('r', stream
);
3090 else if (*p
== '\f')
3092 es_putc_unlocked ('f', stream
);
3095 else if (*p
== '\v')
3097 es_putc_unlocked ('v', stream
);
3100 else if (*p
== '\b')
3102 es_putc_unlocked ('b', stream
);
3107 es_putc_unlocked('0', stream
);
3112 es_fprintf_unlocked (stream
, "x%02x", *p
);
3118 es_putc_unlocked (*p
, stream
);
3124 *bytes_written
= count
;
3125 ret
= es_ferror_unlocked (stream
)? -1 : 0;
3126 ESTREAM_UNLOCK (stream
);
3132 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3133 RESERVED must be 0. Returns 0 on success or -1 on error. If
3134 BYTES_WRITTEN is not NULL the number of bytes actually written are
3135 stored at this address. */
3137 es_write_hexstring (estream_t ES__RESTRICT stream
,
3138 const void *ES__RESTRICT buffer
, size_t length
,
3139 int reserved
, size_t *ES__RESTRICT bytes_written
)
3142 const unsigned char *s
;
3147 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3152 ESTREAM_LOCK (stream
);
3154 for (s
= buffer
; length
; s
++, length
--)
3156 es_putc_unlocked ( tohex ((*s
>>4)&15), stream
);
3157 es_putc_unlocked ( tohex (*s
&15), stream
);
3162 *bytes_written
= count
;
3163 ret
= es_ferror_unlocked (stream
)? -1 : 0;
3165 ESTREAM_UNLOCK (stream
);
3174 #ifdef GNUPG_MAJOR_VERSION
3175 /* Special estream function to print an UTF8 string in the native
3176 encoding. The interface is the same as es_write_sanitized, however
3177 only one delimiter may be supported.
3179 THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3181 es_write_sanitized_utf8_buffer (estream_t stream
,
3182 const void *buffer
, size_t length
,
3183 const char *delimiters
, size_t *bytes_written
)
3185 const char *p
= buffer
;
3188 /* We can handle plain ascii simpler, so check for it first. */
3189 for (i
=0; i
< length
; i
++ )
3191 if ( (p
[i
] & 0x80) )
3196 int delim
= delimiters
? *delimiters
: 0;
3200 /*(utf8 conversion already does the control character quoting). */
3201 buf
= utf8_to_native (p
, length
, delim
);
3203 *bytes_written
= strlen (buf
);
3204 ret
= es_fputs (buf
, stream
);
3209 return es_write_sanitized (stream
, p
, length
, delimiters
, bytes_written
);
3211 #endif /*GNUPG_MAJOR_VERSION*/