1 /* estream.c - Extended Stream I/O Library
2 * Copyright (C) 2004, 2005, 2006, 2007, 2009 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
98 typedef pth_mutex_t estream_mutex_t
;
99 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
100 # define ESTREAM_MUTEX_LOCK(mutex) \
101 pth_mutex_acquire (&(mutex), 0, NULL)
102 # define ESTREAM_MUTEX_UNLOCK(mutex) \
103 pth_mutex_release (&(mutex))
104 # define ESTREAM_MUTEX_TRYLOCK(mutex) \
105 ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
106 # define ESTREAM_MUTEX_INITIALIZE(mutex) \
107 pth_mutex_init (&(mutex))
110 typedef void *estream_mutex_t
;
113 dummy_mutex_call_void (estream_mutex_t mutex
)
119 dummy_mutex_call_int (estream_mutex_t mutex
)
125 # define ESTREAM_MUTEX_INITIALIZER NULL
126 # define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex))
127 # define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex))
128 # define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex))
129 # define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex))
132 /* Primitive system I/O. */
135 # define ESTREAM_SYS_READ es_pth_read
136 # define ESTREAM_SYS_WRITE es_pth_write
138 # define ESTREAM_SYS_READ read
139 # define ESTREAM_SYS_WRITE write
142 /* Misc definitions. */
144 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
146 /* An internal stream object. */
148 struct estream_internal
150 unsigned char buffer
[BUFFER_BLOCK_SIZE
];
151 unsigned char unread_buffer
[BUFFER_UNREAD_SIZE
];
152 estream_mutex_t lock
; /* Lock. */
153 void *cookie
; /* Cookie. */
154 void *opaque
; /* Opaque data. */
155 unsigned int modeflags
; /* Flags for the backend. */
157 es_cookie_read_function_t func_read
;
158 es_cookie_write_function_t func_write
;
159 es_cookie_seek_function_t func_seek
;
160 es_cookie_close_function_t func_close
;
168 unsigned int deallocate_buffer
: 1;
169 unsigned int print_err
: 1; /* Error in print_fun_writer. */
170 int print_errno
; /* Errno from print_fun_writer. */
171 size_t print_ntotal
; /* Bytes written from in print_fun_writer. */
172 FILE *print_fp
; /* Stdio stream used by print_fun_writer. */
176 typedef struct estream_internal
*estream_internal_t
;
178 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
179 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
180 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
184 typedef struct estream_list
*estream_list_t
;
190 estream_list_t
*prev_cdr
;
193 static estream_list_t estream_list
;
194 static estream_mutex_t estream_list_lock
;
196 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
197 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
200 # define EOPNOTSUPP ENOSYS
208 /* Calculate array dimension. */
210 #define DIM(array) (sizeof (array) / sizeof (*array))
213 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
216 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
218 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
221 tmp_variable = expression; \
222 if ((! variable) && tmp_variable) \
223 variable = tmp_variable; \
228 /* Malloc wrappers to overcome problems on some older OSes. */
238 mem_realloc (void *p
, size_t n
)
241 return mem_alloc (n
);
242 return realloc (p
, n
);
258 /* Add STREAM to the list of registered stream objects. */
260 es_list_add (estream_t stream
)
262 estream_list_t list_obj
;
265 list_obj
= mem_alloc (sizeof (*list_obj
));
271 list_obj
->car
= stream
;
272 list_obj
->cdr
= estream_list
;
273 list_obj
->prev_cdr
= &estream_list
;
275 estream_list
->prev_cdr
= &list_obj
->cdr
;
276 estream_list
= list_obj
;
284 /* Remove STREAM from the list of registered stream objects. */
286 es_list_remove (estream_t stream
)
288 estream_list_t list_obj
;
291 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
292 if (list_obj
->car
== stream
)
294 *list_obj
->prev_cdr
= list_obj
->cdr
;
296 list_obj
->cdr
->prev_cdr
= list_obj
->prev_cdr
;
303 /* Type of an stream-iterator-function. */
304 typedef int (*estream_iterator_t
) (estream_t stream
);
306 /* Iterate over list of registered streams, calling ITERATOR for each
309 es_list_iterate (estream_iterator_t iterator
)
311 estream_list_t list_obj
;
315 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
316 ret
|= (*iterator
) (list_obj
->car
);
327 * Unfortunately our Pth emulation for Windows expects system handles
328 * for pth_read and pth_write. We use a simple approach to fix this:
329 * If the function returns an error we fall back to a vanilla read or
330 * write, assuming that we do I/O on a plain file where the operation
335 es_pth_read (int fd
, void *buffer
, size_t size
)
337 # ifdef HAVE_W32_SYSTEM
338 int rc
= pth_read (fd
, buffer
, size
);
339 if (rc
== -1 && errno
== EINVAL
)
340 rc
= read (fd
, buffer
, size
);
342 # else /*!HAVE_W32_SYSTEM*/
343 return pth_read (fd
, buffer
, size
);
344 # endif /* !HAVE_W32_SYSTEM*/
348 es_pth_write (int fd
, const void *buffer
, size_t size
)
350 # ifdef HAVE_W32_SYSTEM
351 int rc
= pth_write (fd
, buffer
, size
);
352 if (rc
== -1 && errno
== EINVAL
)
353 rc
= write (fd
, buffer
, size
);
355 # else /*!HAVE_W32_SYSTEM*/
356 return pth_write (fd
, buffer
, size
);
357 # endif /* !HAVE_W32_SYSTEM*/
371 static int initialized
;
375 if (!pth_init () && errno
!= EPERM
)
377 if (pth_mutex_init (&estream_list_lock
))
390 /* Implementation of Memory I/O. */
392 /* Cookie for memory objects. */
393 typedef struct estream_cookie_mem
395 unsigned int modeflags
; /* Open flags. */
396 unsigned char *memory
; /* Allocated data buffer. */
397 size_t memory_size
; /* Allocated size of MEMORY. */
398 size_t memory_limit
; /* Caller supplied maximum allowed
399 allocation size or 0 for no limit. */
400 size_t offset
; /* Current offset in MEMORY. */
401 size_t data_len
; /* Used length of data in MEMORY. */
402 size_t block_size
; /* Block size. */
404 unsigned int grow
: 1; /* MEMORY is allowed to grow. */
406 func_realloc_t func_realloc
;
407 func_free_t func_free
;
408 } *estream_cookie_mem_t
;
411 /* Create function for memory objects. DATA is either NULL or a user
412 supplied buffer with the initial conetnt of the memory buffer. If
413 DATA is NULL, DATA_N and DATA_LEN need to be 0 as well. If DATA is
414 not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the
415 used length in DATA. */
417 es_func_mem_create (void *ES__RESTRICT
*ES__RESTRICT cookie
,
418 unsigned char *ES__RESTRICT data
, size_t data_n
,
420 size_t block_size
, unsigned int grow
,
421 func_realloc_t func_realloc
, func_free_t func_free
,
422 unsigned int modeflags
,
425 estream_cookie_mem_t mem_cookie
;
428 if (!data
&& (data_n
|| data_len
))
434 mem_cookie
= mem_alloc (sizeof (*mem_cookie
));
439 mem_cookie
->modeflags
= modeflags
;
440 mem_cookie
->memory
= data
;
441 mem_cookie
->memory_size
= data_n
;
442 mem_cookie
->memory_limit
= memory_limit
;
443 mem_cookie
->offset
= 0;
444 mem_cookie
->data_len
= data_len
;
445 mem_cookie
->block_size
= block_size
;
446 mem_cookie
->flags
.grow
= !!grow
;
447 mem_cookie
->func_realloc
= func_realloc
? func_realloc
: mem_realloc
;
448 mem_cookie
->func_free
= func_free
? func_free
: mem_free
;
449 *cookie
= mem_cookie
;
457 /* Read function for memory objects. */
459 es_func_mem_read (void *cookie
, void *buffer
, size_t size
)
461 estream_cookie_mem_t mem_cookie
= cookie
;
464 if (size
> mem_cookie
->data_len
- mem_cookie
->offset
)
465 size
= mem_cookie
->data_len
- mem_cookie
->offset
;
469 memcpy (buffer
, mem_cookie
->memory
+ mem_cookie
->offset
, size
);
470 mem_cookie
->offset
+= size
;
478 /* Write function for memory objects. */
480 es_func_mem_write (void *cookie
, const void *buffer
, size_t size
)
482 estream_cookie_mem_t mem_cookie
= cookie
;
487 return 0; /* A flush is a NOP for memory objects. */
489 if (mem_cookie
->modeflags
& O_APPEND
)
491 /* Append to data. */
492 mem_cookie
->offset
= mem_cookie
->data_len
;
495 assert (mem_cookie
->memory_size
>= mem_cookie
->offset
);
496 nleft
= mem_cookie
->memory_size
- mem_cookie
->offset
;
498 /* If we are not allowed to grow limit the size to the left space. */
499 if (!mem_cookie
->flags
.grow
&& size
> nleft
)
502 /* Enlarge the memory buffer if needed. */
505 unsigned char *newbuf
;
508 if (!mem_cookie
->memory_size
)
509 newsize
= size
; /* Not yet allocated. */
511 newsize
= mem_cookie
->memory_size
+ (nleft
- size
);
512 if (newsize
< mem_cookie
->offset
)
518 /* Round up to the next block length. BLOCK_SIZE should always
519 be set; we check anyway. */
520 if (mem_cookie
->block_size
)
522 newsize
+= mem_cookie
->block_size
- 1;
523 if (newsize
< mem_cookie
->offset
)
528 newsize
/= mem_cookie
->block_size
;
529 newsize
*= mem_cookie
->block_size
;
532 /* Check for a total limit. */
533 if (mem_cookie
->memory_limit
&& newsize
> mem_cookie
->memory_limit
)
539 newbuf
= mem_cookie
->func_realloc (mem_cookie
->memory
, newsize
);
543 mem_cookie
->memory
= newbuf
;
544 mem_cookie
->memory_size
= newsize
;
546 assert (mem_cookie
->memory_size
>= mem_cookie
->offset
);
547 nleft
= mem_cookie
->memory_size
- mem_cookie
->offset
;
549 assert (size
<= nleft
);
552 memcpy (mem_cookie
->memory
+ mem_cookie
->offset
, buffer
, size
);
553 if (mem_cookie
->offset
+ size
> mem_cookie
->data_len
)
554 mem_cookie
->data_len
= mem_cookie
->offset
+ size
;
555 mem_cookie
->offset
+= size
;
562 /* Seek function for memory objects. */
564 es_func_mem_seek (void *cookie
, off_t
*offset
, int whence
)
566 estream_cookie_mem_t mem_cookie
= cookie
;
576 pos_new
= mem_cookie
->offset
+= *offset
;
580 pos_new
= mem_cookie
->data_len
+= *offset
;
588 if (pos_new
> mem_cookie
->memory_size
)
593 if (!mem_cookie
->flags
.grow
)
599 newsize
= pos_new
+ mem_cookie
->block_size
- 1;
600 if (newsize
< pos_new
)
605 newsize
/= mem_cookie
->block_size
;
606 newsize
*= mem_cookie
->block_size
;
608 if (mem_cookie
->memory_limit
&& newsize
> mem_cookie
->memory_limit
)
614 newbuf
= mem_cookie
->func_realloc (mem_cookie
->memory
, newsize
);
618 mem_cookie
->memory
= newbuf
;
619 mem_cookie
->memory_size
= newsize
;
622 if (pos_new
> mem_cookie
->data_len
)
624 /* Fill spare space with zeroes. */
625 memset (mem_cookie
->memory
+ mem_cookie
->data_len
,
626 0, pos_new
- mem_cookie
->data_len
);
627 mem_cookie
->data_len
= pos_new
;
630 mem_cookie
->offset
= pos_new
;
637 /* Destroy function for memory objects. */
639 es_func_mem_destroy (void *cookie
)
641 estream_cookie_mem_t mem_cookie
= cookie
;
645 mem_cookie
->func_free (mem_cookie
->memory
);
646 mem_free (mem_cookie
);
652 static es_cookie_io_functions_t estream_functions_mem
=
662 /* Implementation of fd I/O. */
664 /* Cookie for fd objects. */
665 typedef struct estream_cookie_fd
667 int fd
; /* The file descriptor we are using for actual output. */
668 int no_close
; /* If set we won't close the file descriptor. */
669 } *estream_cookie_fd_t
;
671 /* Create function for fd objects. */
673 es_func_fd_create (void **cookie
, int fd
, unsigned int modeflags
, int no_close
)
675 estream_cookie_fd_t fd_cookie
;
678 fd_cookie
= mem_alloc (sizeof (*fd_cookie
));
683 #ifdef HAVE_DOSISH_SYSTEM
684 /* Make sure it is in binary mode if requested. */
685 if ( (modeflags
& O_BINARY
) )
686 setmode (fd
, O_BINARY
);
691 fd_cookie
->no_close
= no_close
;
699 /* Read function for fd objects. */
701 es_func_fd_read (void *cookie
, void *buffer
, size_t size
)
704 estream_cookie_fd_t file_cookie
= cookie
;
708 bytes_read
= ESTREAM_SYS_READ (file_cookie
->fd
, buffer
, size
);
709 while (bytes_read
== -1 && errno
== EINTR
);
714 /* Write function for fd objects. */
716 es_func_fd_write (void *cookie
, const void *buffer
, size_t size
)
719 estream_cookie_fd_t file_cookie
= cookie
;
720 ssize_t bytes_written
;
723 bytes_written
= ESTREAM_SYS_WRITE (file_cookie
->fd
, buffer
, size
);
724 while (bytes_written
== -1 && errno
== EINTR
);
726 return bytes_written
;
729 /* Seek function for fd objects. */
731 es_func_fd_seek (void *cookie
, off_t
*offset
, int whence
)
733 estream_cookie_fd_t file_cookie
= cookie
;
737 offset_new
= lseek (file_cookie
->fd
, *offset
, whence
);
738 if (offset_new
== -1)
742 *offset
= offset_new
;
749 /* Destroy function for fd objects. */
751 es_func_fd_destroy (void *cookie
)
753 estream_cookie_fd_t fd_cookie
= cookie
;
758 err
= fd_cookie
->no_close
? 0 : close (fd_cookie
->fd
);
759 mem_free (fd_cookie
);
768 static es_cookie_io_functions_t estream_functions_fd
=
779 /* Implementation of FILE* I/O. */
781 /* Cookie for fp objects. */
782 typedef struct estream_cookie_fp
784 FILE *fp
; /* The file pointer we are using for actual output. */
785 int no_close
; /* If set we won't close the file pointer. */
786 } *estream_cookie_fp_t
;
788 /* Create function for fd objects. */
790 es_func_fp_create (void **cookie
, FILE *fp
,
791 unsigned int modeflags
, int no_close
)
793 estream_cookie_fp_t fp_cookie
;
796 fp_cookie
= mem_alloc (sizeof *fp_cookie
);
801 #ifdef HAVE_DOSISH_SYSTEM
802 /* Make sure it is in binary mode if requested. */
803 if ( (modeflags
& O_BINARY
) )
804 setmode (fileno (fp
), O_BINARY
);
809 fp_cookie
->no_close
= no_close
;
817 /* Read function for FILE* objects. */
819 es_func_fp_read (void *cookie
, void *buffer
, size_t size
)
822 estream_cookie_fp_t file_cookie
= cookie
;
825 bytes_read
= fread (buffer
, 1, size
, file_cookie
->fp
);
826 if (!bytes_read
&& ferror (file_cookie
->fp
))
831 /* Write function for FILE* objects. */
833 es_func_fp_write (void *cookie
, const void *buffer
, size_t size
)
836 estream_cookie_fp_t file_cookie
= cookie
;
837 size_t bytes_written
;
839 bytes_written
= fwrite (buffer
, 1, size
, file_cookie
->fp
);
840 if (bytes_written
!= size
)
842 return bytes_written
;
845 /* Seek function for FILE* objects. */
847 es_func_fp_seek (void *cookie
, off_t
*offset
, int whence
)
849 estream_cookie_fp_t file_cookie
= cookie
;
852 if ( fseek (file_cookie
->fp
, (long int)*offset
, whence
) )
854 fprintf (stderr
, "\nfseek failed: errno=%d (%s)\n", errno
,strerror (errno
));
858 offset_new
= ftell (file_cookie
->fp
);
859 if (offset_new
== -1)
861 fprintf (stderr
, "\nftell failed: errno=%d (%s)\n", errno
,strerror (errno
));
864 *offset
= offset_new
;
868 /* Destroy function for fd objects. */
870 es_func_fp_destroy (void *cookie
)
872 estream_cookie_fp_t fp_cookie
= cookie
;
877 fflush (fp_cookie
->fp
);
878 err
= fp_cookie
->no_close
? 0 : fclose (fp_cookie
->fp
);
879 mem_free (fp_cookie
);
888 static es_cookie_io_functions_t estream_functions_fp
=
899 /* Implementation of file I/O. */
901 /* Create function for file objects. */
903 es_func_file_create (void **cookie
, int *filedes
,
904 const char *path
, unsigned int modeflags
)
906 estream_cookie_fd_t file_cookie
;
913 file_cookie
= mem_alloc (sizeof (*file_cookie
));
920 fd
= open (path
, modeflags
, ES_DEFAULT_OPEN_MODE
);
926 #ifdef HAVE_DOSISH_SYSTEM
927 /* Make sure it is in binary mode if requested. */
928 if ( (modeflags
& O_BINARY
) )
929 setmode (fd
, O_BINARY
);
932 file_cookie
->fd
= fd
;
933 file_cookie
->no_close
= 0;
934 *cookie
= file_cookie
;
940 mem_free (file_cookie
);
945 static es_cookie_io_functions_t estream_functions_file
=
955 es_convert_mode (const char *mode
, unsigned int *modeflags
)
957 unsigned int omode
, oflags
;
967 oflags
= O_TRUNC
| O_CREAT
;
971 oflags
= O_APPEND
| O_CREAT
;
977 for (mode
++; *mode
; mode
++)
990 default: /* Ignore unknown flags. */
995 *modeflags
= (omode
| oflags
);
1002 * Low level stream functionality.
1006 es_fill (estream_t stream
)
1008 size_t bytes_read
= 0;
1011 if (!stream
->intern
->func_read
)
1018 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
1021 ret
= (*func_read
) (stream
->intern
->cookie
,
1022 stream
->buffer
, stream
->buffer_size
);
1036 stream
->intern
->indicators
.err
= 1;
1037 else if (!bytes_read
)
1038 stream
->intern
->indicators
.eof
= 1;
1040 stream
->intern
->offset
+= stream
->data_len
;
1041 stream
->data_len
= bytes_read
;
1042 stream
->data_offset
= 0;
1048 es_flush (estream_t stream
)
1050 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1053 assert (stream
->flags
.writing
);
1055 if (stream
->data_offset
)
1057 size_t bytes_written
;
1058 size_t data_flushed
;
1067 /* Note: to prevent an endless loop caused by user-provided
1068 write-functions that pretend to have written more bytes than
1069 they were asked to write, we have to check for
1070 "(stream->data_offset - data_flushed) > 0" instead of
1071 "stream->data_offset - data_flushed". */
1076 while ((((ssize_t
) (stream
->data_offset
- data_flushed
)) > 0) && (! err
))
1078 ret
= (*func_write
) (stream
->intern
->cookie
,
1079 stream
->buffer
+ data_flushed
,
1080 stream
->data_offset
- data_flushed
);
1087 bytes_written
= ret
;
1089 data_flushed
+= bytes_written
;
1094 stream
->data_flushed
+= data_flushed
;
1095 if (stream
->data_offset
== data_flushed
)
1097 stream
->intern
->offset
+= stream
->data_offset
;
1098 stream
->data_offset
= 0;
1099 stream
->data_flushed
= 0;
1101 /* Propagate flush event. */
1102 (*func_write
) (stream
->intern
->cookie
, NULL
, 0);
1111 stream
->intern
->indicators
.err
= 1;
1116 /* Discard buffered data for STREAM. */
1118 es_empty (estream_t stream
)
1120 assert (!stream
->flags
.writing
);
1121 stream
->data_len
= 0;
1122 stream
->data_offset
= 0;
1123 stream
->unread_data_len
= 0;
1126 /* Initialize STREAM. */
1128 es_initialize (estream_t stream
,
1129 void *cookie
, int fd
, es_cookie_io_functions_t functions
,
1130 unsigned int modeflags
)
1132 stream
->intern
->cookie
= cookie
;
1133 stream
->intern
->opaque
= NULL
;
1134 stream
->intern
->offset
= 0;
1135 stream
->intern
->func_read
= functions
.func_read
;
1136 stream
->intern
->func_write
= functions
.func_write
;
1137 stream
->intern
->func_seek
= functions
.func_seek
;
1138 stream
->intern
->func_close
= functions
.func_close
;
1139 stream
->intern
->strategy
= _IOFBF
;
1140 stream
->intern
->fd
= fd
;
1141 stream
->intern
->print_err
= 0;
1142 stream
->intern
->print_errno
= 0;
1143 stream
->intern
->print_ntotal
= 0;
1144 stream
->intern
->print_fp
= NULL
;
1145 stream
->intern
->indicators
.err
= 0;
1146 stream
->intern
->indicators
.eof
= 0;
1147 stream
->intern
->deallocate_buffer
= 0;
1149 stream
->data_len
= 0;
1150 stream
->data_offset
= 0;
1151 stream
->data_flushed
= 0;
1152 stream
->unread_data_len
= 0;
1153 /* Depending on the modeflags we set whether we start in writing or
1154 reading mode. This is required in case we are working on a
1155 wronly stream which is not seeekable (like stdout). Without this
1156 pre-initialization we would do a seek at the first write call and
1157 as this will fail no utput will be delivered. */
1158 if ((modeflags
& O_WRONLY
) || (modeflags
& O_RDWR
) )
1159 stream
->flags
.writing
= 1;
1161 stream
->flags
.writing
= 0;
1164 /* Deinitialize STREAM. */
1166 es_deinitialize (estream_t stream
)
1168 es_cookie_close_function_t func_close
;
1171 if (stream
->intern
->print_fp
)
1173 int save_errno
= errno
;
1174 fclose (stream
->intern
->print_fp
);
1175 stream
->intern
->print_fp
= NULL
;
1179 func_close
= stream
->intern
->func_close
;
1182 if (stream
->flags
.writing
)
1183 SET_UNLESS_NONZERO (err
, tmp_err
, es_flush (stream
));
1185 SET_UNLESS_NONZERO (err
, tmp_err
, (*func_close
) (stream
->intern
->cookie
));
1191 /* Create a new stream object, initialize it. */
1193 es_create (estream_t
*stream
, void *cookie
, int fd
,
1194 es_cookie_io_functions_t functions
, unsigned int modeflags
)
1196 estream_internal_t stream_internal_new
;
1197 estream_t stream_new
;
1201 stream_internal_new
= NULL
;
1203 stream_new
= mem_alloc (sizeof (*stream_new
));
1210 stream_internal_new
= mem_alloc (sizeof (*stream_internal_new
));
1211 if (! stream_internal_new
)
1217 stream_new
->buffer
= stream_internal_new
->buffer
;
1218 stream_new
->buffer_size
= sizeof (stream_internal_new
->buffer
);
1219 stream_new
->unread_buffer
= stream_internal_new
->unread_buffer
;
1220 stream_new
->unread_buffer_size
= sizeof (stream_internal_new
->unread_buffer
);
1221 stream_new
->intern
= stream_internal_new
;
1223 ESTREAM_MUTEX_INITIALIZE (stream_new
->intern
->lock
);
1224 es_initialize (stream_new
, cookie
, fd
, functions
, modeflags
);
1226 err
= es_list_add (stream_new
);
1230 *stream
= stream_new
;
1238 es_deinitialize (stream_new
);
1239 mem_free (stream_new
);
1246 /* Deinitialize a stream object and destroy it. */
1248 es_destroy (estream_t stream
)
1254 es_list_remove (stream
);
1255 err
= es_deinitialize (stream
);
1256 mem_free (stream
->intern
);
1263 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1264 unbuffered-mode, storing the amount of bytes read in
1267 es_read_nbf (estream_t ES__RESTRICT stream
,
1268 unsigned char *ES__RESTRICT buffer
,
1269 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1271 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
1279 while (bytes_to_read
- data_read
)
1281 ret
= (*func_read
) (stream
->intern
->cookie
,
1282 buffer
+ data_read
, bytes_to_read
- data_read
);
1294 stream
->intern
->offset
+= data_read
;
1295 *bytes_read
= data_read
;
1300 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1301 fully-buffered-mode, storing the amount of bytes read in
1304 es_read_fbf (estream_t ES__RESTRICT stream
,
1305 unsigned char *ES__RESTRICT buffer
,
1306 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1308 size_t data_available
;
1309 size_t data_to_read
;
1316 while ((bytes_to_read
- data_read
) && (! err
))
1318 if (stream
->data_offset
== stream
->data_len
)
1320 /* Nothing more to read in current container, try to
1321 fill container with new data. */
1322 err
= es_fill (stream
);
1324 if (! stream
->data_len
)
1325 /* Filling did not result in any data read. */
1331 /* Filling resulted in some new data. */
1333 data_to_read
= bytes_to_read
- data_read
;
1334 data_available
= stream
->data_len
- stream
->data_offset
;
1335 if (data_to_read
> data_available
)
1336 data_to_read
= data_available
;
1338 memcpy (buffer
+ data_read
,
1339 stream
->buffer
+ stream
->data_offset
, data_to_read
);
1340 stream
->data_offset
+= data_to_read
;
1341 data_read
+= data_to_read
;
1345 *bytes_read
= data_read
;
1350 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1351 line-buffered-mode, storing the amount of bytes read in
1354 es_read_lbf (estream_t ES__RESTRICT stream
,
1355 unsigned char *ES__RESTRICT buffer
,
1356 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1360 err
= es_read_fbf (stream
, buffer
, bytes_to_read
, bytes_read
);
1365 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1366 *the amount of bytes read in BYTES_READ. */
1368 es_readn (estream_t ES__RESTRICT stream
,
1369 void *ES__RESTRICT buffer_arg
,
1370 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1372 unsigned char *buffer
= (unsigned char *)buffer_arg
;
1373 size_t data_read_unread
, data_read
;
1376 data_read_unread
= 0;
1380 if (stream
->flags
.writing
)
1382 /* Switching to reading mode -> flush output. */
1383 err
= es_flush (stream
);
1386 stream
->flags
.writing
= 0;
1389 /* Read unread data first. */
1390 while ((bytes_to_read
- data_read_unread
) && stream
->unread_data_len
)
1392 buffer
[data_read_unread
]
1393 = stream
->unread_buffer
[stream
->unread_data_len
- 1];
1394 stream
->unread_data_len
--;
1398 switch (stream
->intern
->strategy
)
1401 err
= es_read_nbf (stream
,
1402 buffer
+ data_read_unread
,
1403 bytes_to_read
- data_read_unread
, &data_read
);
1406 err
= es_read_lbf (stream
,
1407 buffer
+ data_read_unread
,
1408 bytes_to_read
- data_read_unread
, &data_read
);
1411 err
= es_read_fbf (stream
,
1412 buffer
+ data_read_unread
,
1413 bytes_to_read
- data_read_unread
, &data_read
);
1420 *bytes_read
= data_read_unread
+ data_read
;
1425 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1426 amount of bytes succesfully unread in *BYTES_UNREAD. */
1428 es_unreadn (estream_t ES__RESTRICT stream
,
1429 const unsigned char *ES__RESTRICT data
, size_t data_n
,
1430 size_t *ES__RESTRICT bytes_unread
)
1434 space_left
= stream
->unread_buffer_size
- stream
->unread_data_len
;
1436 if (data_n
> space_left
)
1437 data_n
= space_left
;
1442 memcpy (stream
->unread_buffer
+ stream
->unread_data_len
, data
, data_n
);
1443 stream
->unread_data_len
+= data_n
;
1444 stream
->intern
->indicators
.eof
= 0;
1449 *bytes_unread
= data_n
;
1452 /* Seek in STREAM. */
1454 es_seek (estream_t ES__RESTRICT stream
, off_t offset
, int whence
,
1455 off_t
*ES__RESTRICT offset_new
)
1457 es_cookie_seek_function_t func_seek
= stream
->intern
->func_seek
;
1468 if (stream
->flags
.writing
)
1470 /* Flush data first in order to prevent flushing it to the wrong
1472 err
= es_flush (stream
);
1475 stream
->flags
.writing
= 0;
1479 if (whence
== SEEK_CUR
)
1481 off
= off
- stream
->data_len
+ stream
->data_offset
;
1482 off
-= stream
->unread_data_len
;
1485 ret
= (*func_seek
) (stream
->intern
->cookie
, &off
, whence
);
1498 stream
->intern
->indicators
.eof
= 0;
1499 stream
->intern
->offset
= off
;
1504 stream
->intern
->indicators
.err
= 1;
1509 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1510 unbuffered-mode, storing the amount of bytes written in
1513 es_write_nbf (estream_t ES__RESTRICT stream
,
1514 const unsigned char *ES__RESTRICT buffer
,
1515 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1517 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1518 size_t data_written
;
1522 if (bytes_to_write
&& (! func_write
))
1531 while (bytes_to_write
- data_written
)
1533 ret
= (*func_write
) (stream
->intern
->cookie
,
1534 buffer
+ data_written
,
1535 bytes_to_write
- data_written
);
1542 data_written
+= ret
;
1545 stream
->intern
->offset
+= data_written
;
1546 *bytes_written
= data_written
;
1553 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1554 fully-buffered-mode, storing the amount of bytes written in
1557 es_write_fbf (estream_t ES__RESTRICT stream
,
1558 const unsigned char *ES__RESTRICT buffer
,
1559 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1561 size_t space_available
;
1562 size_t data_to_write
;
1563 size_t data_written
;
1569 while ((bytes_to_write
- data_written
) && (! err
))
1571 if (stream
->data_offset
== stream
->buffer_size
)
1572 /* Container full, flush buffer. */
1573 err
= es_flush (stream
);
1577 /* Flushing resulted in empty container. */
1579 data_to_write
= bytes_to_write
- data_written
;
1580 space_available
= stream
->buffer_size
- stream
->data_offset
;
1581 if (data_to_write
> space_available
)
1582 data_to_write
= space_available
;
1584 memcpy (stream
->buffer
+ stream
->data_offset
,
1585 buffer
+ data_written
, data_to_write
);
1586 stream
->data_offset
+= data_to_write
;
1587 data_written
+= data_to_write
;
1591 *bytes_written
= data_written
;
1597 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1598 line-buffered-mode, storing the amount of bytes written in
1601 es_write_lbf (estream_t ES__RESTRICT stream
,
1602 const unsigned char *ES__RESTRICT buffer
,
1603 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1605 size_t data_flushed
= 0;
1606 size_t data_buffered
= 0;
1610 nlp
= memrchr (buffer
, '\n', bytes_to_write
);
1613 /* Found a newline, directly write up to (including) this
1615 err
= es_flush (stream
);
1617 err
= es_write_nbf (stream
, buffer
, nlp
- buffer
+ 1, &data_flushed
);
1622 /* Write remaining data fully buffered. */
1623 err
= es_write_fbf (stream
, buffer
+ data_flushed
,
1624 bytes_to_write
- data_flushed
, &data_buffered
);
1627 *bytes_written
= data_flushed
+ data_buffered
;
1632 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1633 amount of bytes written in BYTES_WRITTEN. */
1635 es_writen (estream_t ES__RESTRICT stream
,
1636 const void *ES__RESTRICT buffer
,
1637 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1639 size_t data_written
;
1645 if (!stream
->flags
.writing
)
1647 /* Switching to writing mode -> discard input data and seek to
1648 position at which reading has stopped. We can do this only
1649 if a seek function has been registered. */
1650 if (stream
->intern
->func_seek
)
1652 err
= es_seek (stream
, 0, SEEK_CUR
, NULL
);
1655 if (errno
== ESPIPE
)
1663 switch (stream
->intern
->strategy
)
1666 err
= es_write_nbf (stream
, buffer
, bytes_to_write
, &data_written
);
1670 err
= es_write_lbf (stream
, buffer
, bytes_to_write
, &data_written
);
1674 err
= es_write_fbf (stream
, buffer
, bytes_to_write
, &data_written
);
1681 *bytes_written
= data_written
;
1683 if (!stream
->flags
.writing
)
1684 stream
->flags
.writing
= 1;
1691 es_peek (estream_t ES__RESTRICT stream
, unsigned char **ES__RESTRICT data
,
1692 size_t *ES__RESTRICT data_len
)
1696 if (stream
->flags
.writing
)
1698 /* Switching to reading mode -> flush output. */
1699 err
= es_flush (stream
);
1702 stream
->flags
.writing
= 0;
1705 if (stream
->data_offset
== stream
->data_len
)
1707 /* Refill container. */
1708 err
= es_fill (stream
);
1714 *data
= stream
->buffer
+ stream
->data_offset
;
1716 *data_len
= stream
->data_len
- stream
->data_offset
;
1725 /* Skip SIZE bytes of input data contained in buffer. */
1727 es_skip (estream_t stream
, size_t size
)
1731 if (stream
->data_offset
+ size
> stream
->data_len
)
1738 stream
->data_offset
+= size
;
1747 doreadline (estream_t ES__RESTRICT stream
, size_t max_length
,
1748 char *ES__RESTRICT
*ES__RESTRICT line
,
1749 size_t *ES__RESTRICT line_length
)
1753 estream_t line_stream
;
1755 void *line_stream_cookie
;
1757 unsigned char *data
;
1763 line_stream_cookie
= NULL
;
1765 err
= es_func_mem_create (&line_stream_cookie
, NULL
, 0, 0,
1766 BUFFER_BLOCK_SIZE
, 1,
1767 mem_realloc
, mem_free
,
1773 err
= es_create (&line_stream
, line_stream_cookie
, -1,
1774 estream_functions_mem
, O_RDWR
);
1778 space_left
= max_length
;
1782 if (max_length
&& (space_left
== 1))
1785 err
= es_peek (stream
, &data
, &data_len
);
1786 if (err
|| (! data_len
))
1789 if (data_len
> (space_left
- 1))
1790 data_len
= space_left
- 1;
1792 newline
= memchr (data
, '\n', data_len
);
1795 data_len
= (newline
- (char *) data
) + 1;
1796 err
= es_write (line_stream
, data
, data_len
, NULL
);
1799 space_left
-= data_len
;
1800 line_size
+= data_len
;
1801 es_skip (stream
, data_len
);
1807 err
= es_write (line_stream
, data
, data_len
, NULL
);
1810 space_left
-= data_len
;
1811 line_size
+= data_len
;
1812 es_skip (stream
, data_len
);
1821 /* Complete line has been written to line_stream. */
1823 if ((max_length
> 1) && (! line_size
))
1825 stream
->intern
->indicators
.eof
= 1;
1829 err
= es_seek (line_stream
, 0, SEEK_SET
, NULL
);
1835 line_new
= mem_alloc (line_size
+ 1);
1845 err
= es_read (line_stream
, line_new
, line_size
, NULL
);
1849 line_new
[line_size
] = '\0';
1854 *line_length
= line_size
;
1859 es_destroy (line_stream
);
1860 else if (line_stream_cookie
)
1861 es_func_mem_destroy (line_stream_cookie
);
1866 mem_free (line_new
);
1867 stream
->intern
->indicators
.err
= 1;
1874 /* Output fucntion used for estream_format. */
1876 print_writer (void *outfncarg
, const char *buf
, size_t buflen
)
1878 estream_t stream
= outfncarg
;
1883 rc
= es_writen (stream
, buf
, buflen
, &nwritten
);
1884 stream
->intern
->print_ntotal
+= nwritten
;
1889 /* The core of our printf function. This is called in locked state. */
1891 es_print (estream_t ES__RESTRICT stream
,
1892 const char *ES__RESTRICT format
, va_list ap
)
1896 stream
->intern
->print_ntotal
= 0;
1897 rc
= estream_format (print_writer
, stream
, format
, ap
);
1900 return (int)stream
->intern
->print_ntotal
;
1905 es_set_indicators (estream_t stream
, int ind_err
, int ind_eof
)
1908 stream
->intern
->indicators
.err
= ind_err
? 1 : 0;
1910 stream
->intern
->indicators
.eof
= ind_eof
? 1 : 0;
1915 es_get_indicator (estream_t stream
, int ind_err
, int ind_eof
)
1920 ret
= stream
->intern
->indicators
.err
;
1922 ret
= stream
->intern
->indicators
.eof
;
1929 es_set_buffering (estream_t ES__RESTRICT stream
,
1930 char *ES__RESTRICT buffer
, int mode
, size_t size
)
1934 /* Flush or empty buffer depending on mode. */
1935 if (stream
->flags
.writing
)
1937 err
= es_flush (stream
);
1944 es_set_indicators (stream
, -1, 0);
1946 /* Free old buffer in case that was allocated by this function. */
1947 if (stream
->intern
->deallocate_buffer
)
1949 stream
->intern
->deallocate_buffer
= 0;
1950 mem_free (stream
->buffer
);
1951 stream
->buffer
= NULL
;
1955 stream
->buffer_size
= 0;
1961 buffer_new
= buffer
;
1964 buffer_new
= mem_alloc (size
);
1972 stream
->buffer
= buffer_new
;
1973 stream
->buffer_size
= size
;
1975 stream
->intern
->deallocate_buffer
= 1;
1977 stream
->intern
->strategy
= mode
;
1987 es_offset_calculate (estream_t stream
)
1991 offset
= stream
->intern
->offset
+ stream
->data_offset
;
1992 if (offset
< stream
->unread_data_len
)
1993 /* Offset undefined. */
1996 offset
-= stream
->unread_data_len
;
2003 es_opaque_ctrl (estream_t ES__RESTRICT stream
, void *ES__RESTRICT opaque_new
,
2004 void **ES__RESTRICT opaque_old
)
2007 *opaque_old
= stream
->intern
->opaque
;
2009 stream
->intern
->opaque
= opaque_new
;
2014 es_get_fd (estream_t stream
)
2016 return stream
->intern
->fd
;
2028 err
= es_init_do ();
2034 es_fopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
)
2036 unsigned int modeflags
;
2047 err
= es_convert_mode (mode
, &modeflags
);
2051 err
= es_func_file_create (&cookie
, &fd
, path
, modeflags
);
2056 err
= es_create (&stream
, cookie
, fd
, estream_functions_file
, modeflags
);
2062 if (err
&& create_called
)
2063 (*estream_functions_file
.func_close
) (cookie
);
2070 es_mopen (unsigned char *ES__RESTRICT data
, size_t data_n
, size_t data_len
,
2072 func_realloc_t func_realloc
, func_free_t func_free
,
2073 const char *ES__RESTRICT mode
)
2075 unsigned int modeflags
;
2085 err
= es_convert_mode (mode
, &modeflags
);
2089 err
= es_func_mem_create (&cookie
, data
, data_n
, data_len
,
2090 BUFFER_BLOCK_SIZE
, grow
,
2091 func_realloc
, func_free
, modeflags
, 0);
2096 err
= es_create (&stream
, cookie
, -1, estream_functions_mem
, modeflags
);
2100 if (err
&& create_called
)
2101 (*estream_functions_mem
.func_close
) (cookie
);
2108 es_fopenmem (size_t memlimit
, const char *ES__RESTRICT mode
)
2110 unsigned int modeflags
;
2111 estream_t stream
= NULL
;
2112 void *cookie
= NULL
;
2114 /* Memory streams are always read/write. We use MODE only to get
2116 if (es_convert_mode (mode
, &modeflags
))
2118 modeflags
|= O_RDWR
;
2121 if (es_func_mem_create (&cookie
, NULL
, 0, 0,
2122 BUFFER_BLOCK_SIZE
, 1,
2123 mem_realloc
, mem_free
, modeflags
,
2127 if (es_create (&stream
, cookie
, -1, estream_functions_mem
, modeflags
))
2128 (*estream_functions_mem
.func_close
) (cookie
);
2136 es_fopencookie (void *ES__RESTRICT cookie
,
2137 const char *ES__RESTRICT mode
,
2138 es_cookie_io_functions_t functions
)
2140 unsigned int modeflags
;
2147 err
= es_convert_mode (mode
, &modeflags
);
2151 err
= es_create (&stream
, cookie
, -1, functions
, modeflags
);
2162 do_fdopen (int filedes
, const char *mode
, int no_close
)
2164 unsigned int modeflags
;
2174 err
= es_convert_mode (mode
, &modeflags
);
2178 err
= es_func_fd_create (&cookie
, filedes
, modeflags
, no_close
);
2183 err
= es_create (&stream
, cookie
, filedes
, estream_functions_fd
, modeflags
);
2187 if (err
&& create_called
)
2188 (*estream_functions_fd
.func_close
) (cookie
);
2194 es_fdopen (int filedes
, const char *mode
)
2196 return do_fdopen (filedes
, mode
, 0);
2199 /* A variant of es_fdopen which does not close FILEDES at the end. */
2201 es_fdopen_nc (int filedes
, const char *mode
)
2203 return do_fdopen (filedes
, mode
, 1);
2208 do_fpopen (FILE *fp
, const char *mode
, int no_close
)
2210 unsigned int modeflags
;
2220 err
= es_convert_mode (mode
, &modeflags
);
2225 err
= es_func_fp_create (&cookie
, fp
, modeflags
, no_close
);
2230 err
= es_create (&stream
, cookie
, fileno (fp
), estream_functions_fp
,
2235 if (err
&& create_called
)
2236 (*estream_functions_fp
.func_close
) (cookie
);
2242 /* Create an estream from the stdio stream FP. This mechanism is
2243 useful in case the stdio streams have special properties and may
2244 not be mixed with fd based functions. This is for example the case
2245 under Windows where the 3 standard streams are associated with the
2246 console whereas a duped and fd-opened stream of one of this stream
2247 won't be associated with the console. As this messes things up it
2248 is easier to keep on using the standard I/O stream as a backend for
2251 es_fpopen (FILE *fp
, const char *mode
)
2253 return do_fpopen (fp
, mode
, 0);
2257 /* Same as es_fpopen but does not close FP at the end. */
2259 es_fpopen_nc (FILE *fp
, const char *mode
)
2261 return do_fpopen (fp
, mode
, 1);
2266 es_freopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
,
2267 estream_t ES__RESTRICT stream
)
2273 unsigned int modeflags
;
2281 ESTREAM_LOCK (stream
);
2283 es_deinitialize (stream
);
2285 err
= es_convert_mode (mode
, &modeflags
);
2289 err
= es_func_file_create (&cookie
, &fd
, path
, modeflags
);
2294 es_initialize (stream
, cookie
, fd
, estream_functions_file
, modeflags
);
2301 es_func_fd_destroy (cookie
);
2303 es_destroy (stream
);
2307 ESTREAM_UNLOCK (stream
);
2311 /* FIXME? We don't support re-opening at the moment. */
2313 es_deinitialize (stream
);
2314 es_destroy (stream
);
2323 es_fclose (estream_t stream
)
2327 err
= es_destroy (stream
);
2333 es_fileno_unlocked (estream_t stream
)
2335 return es_get_fd (stream
);
2340 es_flockfile (estream_t stream
)
2342 ESTREAM_LOCK (stream
);
2347 es_ftrylockfile (estream_t stream
)
2349 return ESTREAM_TRYLOCK (stream
);
2354 es_funlockfile (estream_t stream
)
2356 ESTREAM_UNLOCK (stream
);
2361 es_fileno (estream_t stream
)
2365 ESTREAM_LOCK (stream
);
2366 ret
= es_fileno_unlocked (stream
);
2367 ESTREAM_UNLOCK (stream
);
2374 es_feof_unlocked (estream_t stream
)
2376 return es_get_indicator (stream
, 0, 1);
2381 es_feof (estream_t stream
)
2385 ESTREAM_LOCK (stream
);
2386 ret
= es_feof_unlocked (stream
);
2387 ESTREAM_UNLOCK (stream
);
2394 es_ferror_unlocked (estream_t stream
)
2396 return es_get_indicator (stream
, 1, 0);
2401 es_ferror (estream_t stream
)
2405 ESTREAM_LOCK (stream
);
2406 ret
= es_ferror_unlocked (stream
);
2407 ESTREAM_UNLOCK (stream
);
2414 es_clearerr_unlocked (estream_t stream
)
2416 es_set_indicators (stream
, 0, 0);
2421 es_clearerr (estream_t stream
)
2423 ESTREAM_LOCK (stream
);
2424 es_clearerr_unlocked (stream
);
2425 ESTREAM_UNLOCK (stream
);
2430 es_fflush (estream_t stream
)
2436 ESTREAM_LOCK (stream
);
2437 if (stream
->flags
.writing
)
2438 err
= es_flush (stream
);
2444 ESTREAM_UNLOCK (stream
);
2447 err
= es_list_iterate (es_fflush
);
2449 return err
? EOF
: 0;
2454 es_fseek (estream_t stream
, long int offset
, int whence
)
2458 ESTREAM_LOCK (stream
);
2459 err
= es_seek (stream
, offset
, whence
, NULL
);
2460 ESTREAM_UNLOCK (stream
);
2467 es_fseeko (estream_t stream
, off_t offset
, int whence
)
2471 ESTREAM_LOCK (stream
);
2472 err
= es_seek (stream
, offset
, whence
, NULL
);
2473 ESTREAM_UNLOCK (stream
);
2480 es_ftell (estream_t stream
)
2484 ESTREAM_LOCK (stream
);
2485 ret
= es_offset_calculate (stream
);
2486 ESTREAM_UNLOCK (stream
);
2493 es_ftello (estream_t stream
)
2497 ESTREAM_LOCK (stream
);
2498 ret
= es_offset_calculate (stream
);
2499 ESTREAM_UNLOCK (stream
);
2506 es_rewind (estream_t stream
)
2508 ESTREAM_LOCK (stream
);
2509 es_seek (stream
, 0L, SEEK_SET
, NULL
);
2510 es_set_indicators (stream
, 0, -1);
2511 ESTREAM_UNLOCK (stream
);
2516 _es_getc_underflow (estream_t stream
)
2522 err
= es_readn (stream
, &c
, 1, &bytes_read
);
2524 return (err
|| (! bytes_read
)) ? EOF
: c
;
2529 _es_putc_overflow (int c
, estream_t stream
)
2531 unsigned char d
= c
;
2534 err
= es_writen (stream
, &d
, 1, NULL
);
2536 return err
? EOF
: c
;
2541 es_fgetc (estream_t stream
)
2545 ESTREAM_LOCK (stream
);
2546 ret
= es_getc_unlocked (stream
);
2547 ESTREAM_UNLOCK (stream
);
2554 es_fputc (int c
, estream_t stream
)
2558 ESTREAM_LOCK (stream
);
2559 ret
= es_putc_unlocked (c
, stream
);
2560 ESTREAM_UNLOCK (stream
);
2567 es_ungetc (int c
, estream_t stream
)
2569 unsigned char data
= (unsigned char) c
;
2572 ESTREAM_LOCK (stream
);
2573 es_unreadn (stream
, &data
, 1, &data_unread
);
2574 ESTREAM_UNLOCK (stream
);
2576 return data_unread
? c
: EOF
;
2581 es_read (estream_t ES__RESTRICT stream
,
2582 void *ES__RESTRICT buffer
, size_t bytes_to_read
,
2583 size_t *ES__RESTRICT bytes_read
)
2589 ESTREAM_LOCK (stream
);
2590 err
= es_readn (stream
, buffer
, bytes_to_read
, bytes_read
);
2591 ESTREAM_UNLOCK (stream
);
2601 es_write (estream_t ES__RESTRICT stream
,
2602 const void *ES__RESTRICT buffer
, size_t bytes_to_write
,
2603 size_t *ES__RESTRICT bytes_written
)
2609 ESTREAM_LOCK (stream
);
2610 err
= es_writen (stream
, buffer
, bytes_to_write
, bytes_written
);
2611 ESTREAM_UNLOCK (stream
);
2621 es_fread (void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2622 estream_t ES__RESTRICT stream
)
2629 ESTREAM_LOCK (stream
);
2630 err
= es_readn (stream
, ptr
, size
* nitems
, &bytes
);
2631 ESTREAM_UNLOCK (stream
);
2643 es_fwrite (const void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2644 estream_t ES__RESTRICT stream
)
2651 ESTREAM_LOCK (stream
);
2652 err
= es_writen (stream
, ptr
, size
* nitems
, &bytes
);
2653 ESTREAM_UNLOCK (stream
);
2665 es_fgets (char *ES__RESTRICT buffer
, int length
, estream_t ES__RESTRICT stream
)
2667 unsigned char *s
= (unsigned char*)buffer
;
2674 ESTREAM_LOCK (stream
);
2675 while (length
> 1 && (c
= es_getc_unlocked (stream
)) != EOF
&& c
!= '\n')
2680 ESTREAM_UNLOCK (stream
);
2682 if (c
== EOF
&& s
== (unsigned char*)buffer
)
2683 return NULL
; /* Nothing read. */
2685 if (c
!= EOF
&& length
> 1)
2694 es_fputs (const char *ES__RESTRICT s
, estream_t ES__RESTRICT stream
)
2699 length
= strlen (s
);
2700 ESTREAM_LOCK (stream
);
2701 err
= es_writen (stream
, s
, length
, NULL
);
2702 ESTREAM_UNLOCK (stream
);
2704 return err
? EOF
: 0;
2709 es_getline (char *ES__RESTRICT
*ES__RESTRICT lineptr
, size_t *ES__RESTRICT n
,
2710 estream_t ES__RESTRICT stream
)
2716 ESTREAM_LOCK (stream
);
2717 err
= doreadline (stream
, 0, &line
, &line_n
);
2718 ESTREAM_UNLOCK (stream
);
2724 /* Caller wants us to use his buffer. */
2726 if (*n
< (line_n
+ 1))
2728 /* Provided buffer is too small -> resize. */
2732 p
= mem_realloc (*lineptr
, line_n
+ 1);
2744 memcpy (*lineptr
, line
, line_n
+ 1);
2752 /* Caller wants new buffers. */
2759 return err
? err
: line_n
;
2764 /* Same as fgets() but if the provided buffer is too short a larger
2765 one will be allocated. This is similar to getline. A line is
2766 considered a byte stream ending in a LF.
2768 If MAX_LENGTH is not NULL, it shall point to a value with the
2769 maximum allowed allocation.
2771 Returns the length of the line. EOF is indicated by a line of
2772 length zero. A truncated line is indicated my setting the value at
2773 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2774 memory was enable or another error occurred; ERRNO is then set
2777 If a line has been truncated, the file pointer is moved forward to
2778 the end of the line so that the next read starts with the next
2779 line. Note that MAX_LENGTH must be re-initialzied in this case.
2781 The caller initially needs to provide the address of a variable,
2782 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2783 anymore with the following invocations. LENGTH_OF_BUFFER should be
2784 the address of a variable, initialized to 0, which is also
2785 maintained by this function. Thus, both paramaters should be
2786 considered the state of this function.
2788 Note: The returned buffer is allocated with enough extra space to
2789 allow the caller to append a CR,LF,Nul. The buffer should be
2790 released using es_free.
2793 es_read_line (estream_t stream
,
2794 char **addr_of_buffer
, size_t *length_of_buffer
,
2798 char *buffer
= *addr_of_buffer
;
2799 size_t length
= *length_of_buffer
;
2801 size_t maxlen
= max_length
? *max_length
: 0;
2806 /* No buffer given - allocate a new one. */
2808 buffer
= mem_alloc (length
);
2809 *addr_of_buffer
= buffer
;
2812 *length_of_buffer
= 0;
2817 *length_of_buffer
= length
;
2822 /* This should never happen. If it does, the function has been
2823 called with wrong arguments. */
2827 length
-= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2829 ESTREAM_LOCK (stream
);
2831 while ((c
= es_getc_unlocked (stream
)) != EOF
)
2833 if (nbytes
== length
)
2835 /* Enlarge the buffer. */
2836 if (maxlen
&& length
> maxlen
)
2838 /* We are beyond our limit: Skip the rest of the line. */
2839 while (c
!= '\n' && (c
=es_getc_unlocked (stream
)) != EOF
)
2841 *p
++ = '\n'; /* Always append a LF (we reserved some space). */
2844 *max_length
= 0; /* Indicate truncation. */
2845 break; /* the while loop. */
2847 length
+= 3; /* Adjust for the reserved bytes. */
2848 length
+= length
< 1024? 256 : 1024;
2849 *addr_of_buffer
= mem_realloc (buffer
, length
);
2850 if (!*addr_of_buffer
)
2852 int save_errno
= errno
;
2854 *length_of_buffer
= 0;
2857 ESTREAM_UNLOCK (stream
);
2861 buffer
= *addr_of_buffer
;
2862 *length_of_buffer
= length
;
2864 p
= buffer
+ nbytes
;
2871 *p
= 0; /* Make sure the line is a string. */
2872 ESTREAM_UNLOCK (stream
);
2877 /* Wrapper around free() to match the memory allocation system used
2878 by estream. Should be used for all buffers returned to the caller
2888 es_vfprintf (estream_t ES__RESTRICT stream
, const char *ES__RESTRICT format
,
2893 ESTREAM_LOCK (stream
);
2894 ret
= es_print (stream
, format
, ap
);
2895 ESTREAM_UNLOCK (stream
);
2902 es_fprintf_unlocked (estream_t ES__RESTRICT stream
,
2903 const char *ES__RESTRICT format
, ...)
2908 va_start (ap
, format
);
2909 ret
= es_print (stream
, format
, ap
);
2917 es_fprintf (estream_t ES__RESTRICT stream
,
2918 const char *ES__RESTRICT format
, ...)
2923 va_start (ap
, format
);
2924 ESTREAM_LOCK (stream
);
2925 ret
= es_print (stream
, format
, ap
);
2926 ESTREAM_UNLOCK (stream
);
2936 #ifdef HAVE_W32_SYSTEM
2938 char buffer
[MAX_PATH
+9+12+1];
2941 int pid
= GetCurrentProcessId ();
2945 n
= GetTempPath (MAX_PATH
+1, buffer
);
2946 if (!n
|| n
> MAX_PATH
|| strlen (buffer
) > MAX_PATH
)
2951 p
= buffer
+ strlen (buffer
);
2952 strcpy (p
, "_estream");
2954 /* We try to create the directory but don't care about an error as
2955 it may already exist and the CreateFile would throw an error
2957 CreateDirectory (buffer
, NULL
);
2960 for (attempts
=0; attempts
< 10; attempts
++)
2963 value
= (GetTickCount () ^ ((pid
<<16) & 0xffff0000));
2964 for (i
=0; i
< 8; i
++)
2966 *p
++ = tohex (((value
>> 28) & 0x0f));
2970 file
= CreateFile (buffer
,
2971 GENERIC_READ
| GENERIC_WRITE
,
2975 FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_DELETE_ON_CLOSE
,
2977 if (file
!= INVALID_HANDLE_VALUE
)
2979 int fd
= _open_osfhandle ((long)file
, 0);
2987 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
2991 #else /*!HAVE_W32_SYSTEM*/
3003 fp_fd
= fileno (fp
);
3012 #endif /*!HAVE_W32_SYSTEM*/
3018 unsigned int modeflags
;
3027 modeflags
= O_RDWR
| O_TRUNC
| O_CREAT
;
3037 err
= es_func_fd_create (&cookie
, fd
, modeflags
, 0);
3042 err
= es_create (&stream
, cookie
, fd
, estream_functions_fd
, modeflags
);
3049 es_func_fd_destroy (cookie
);
3060 es_setvbuf (estream_t ES__RESTRICT stream
,
3061 char *ES__RESTRICT buf
, int type
, size_t size
)
3065 if (((type
== _IOFBF
) || (type
== _IOLBF
) || (type
== _IONBF
))
3066 && (! ((! size
) && (type
!= _IONBF
))))
3068 ESTREAM_LOCK (stream
);
3069 err
= es_set_buffering (stream
, buf
, type
, size
);
3070 ESTREAM_UNLOCK (stream
);
3083 es_setbuf (estream_t ES__RESTRICT stream
, char *ES__RESTRICT buf
)
3085 ESTREAM_LOCK (stream
);
3086 es_set_buffering (stream
, buf
, buf
? _IOFBF
: _IONBF
, BUFSIZ
);
3087 ESTREAM_UNLOCK (stream
);
3091 es_opaque_set (estream_t stream
, void *opaque
)
3093 ESTREAM_LOCK (stream
);
3094 es_opaque_ctrl (stream
, opaque
, NULL
);
3095 ESTREAM_UNLOCK (stream
);
3100 es_opaque_get (estream_t stream
)
3104 ESTREAM_LOCK (stream
);
3105 es_opaque_ctrl (stream
, NULL
, &opaque
);
3106 ESTREAM_UNLOCK (stream
);
3111 /* Print a BUFFER to STREAM while replacing all control characters and
3112 the characters in DELIMITERS by standard C escape sequences.
3113 Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
3114 the number of bytes actually written are stored at this
3117 es_write_sanitized (estream_t ES__RESTRICT stream
,
3118 const void * ES__RESTRICT buffer
, size_t length
,
3119 const char * delimiters
,
3120 size_t * ES__RESTRICT bytes_written
)
3122 const unsigned char *p
= buffer
;
3126 ESTREAM_LOCK (stream
);
3127 for (; length
; length
--, p
++, count
++)
3132 && (strchr (delimiters
, *p
) || *p
== '\\')))
3134 es_putc_unlocked ('\\', stream
);
3138 es_putc_unlocked ('n', stream
);
3141 else if (*p
== '\r')
3143 es_putc_unlocked ('r', stream
);
3146 else if (*p
== '\f')
3148 es_putc_unlocked ('f', stream
);
3151 else if (*p
== '\v')
3153 es_putc_unlocked ('v', stream
);
3156 else if (*p
== '\b')
3158 es_putc_unlocked ('b', stream
);
3163 es_putc_unlocked('0', stream
);
3168 es_fprintf_unlocked (stream
, "x%02x", *p
);
3174 es_putc_unlocked (*p
, stream
);
3180 *bytes_written
= count
;
3181 ret
= es_ferror_unlocked (stream
)? -1 : 0;
3182 ESTREAM_UNLOCK (stream
);
3188 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3189 RESERVED must be 0. Returns 0 on success or -1 on error. If
3190 BYTES_WRITTEN is not NULL the number of bytes actually written are
3191 stored at this address. */
3193 es_write_hexstring (estream_t ES__RESTRICT stream
,
3194 const void *ES__RESTRICT buffer
, size_t length
,
3195 int reserved
, size_t *ES__RESTRICT bytes_written
)
3198 const unsigned char *s
;
3203 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3208 ESTREAM_LOCK (stream
);
3210 for (s
= buffer
; length
; s
++, length
--)
3212 es_putc_unlocked ( tohex ((*s
>>4)&15), stream
);
3213 es_putc_unlocked ( tohex (*s
&15), stream
);
3218 *bytes_written
= count
;
3219 ret
= es_ferror_unlocked (stream
)? -1 : 0;
3221 ESTREAM_UNLOCK (stream
);
3230 #ifdef GNUPG_MAJOR_VERSION
3231 /* Special estream function to print an UTF8 string in the native
3232 encoding. The interface is the same as es_write_sanitized, however
3233 only one delimiter may be supported.
3235 THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3237 es_write_sanitized_utf8_buffer (estream_t stream
,
3238 const void *buffer
, size_t length
,
3239 const char *delimiters
, size_t *bytes_written
)
3241 const char *p
= buffer
;
3244 /* We can handle plain ascii simpler, so check for it first. */
3245 for (i
=0; i
< length
; i
++ )
3247 if ( (p
[i
] & 0x80) )
3252 int delim
= delimiters
? *delimiters
: 0;
3256 /*(utf8 conversion already does the control character quoting). */
3257 buf
= utf8_to_native (p
, length
, delim
);
3259 *bytes_written
= strlen (buf
);
3260 ret
= es_fputs (buf
, stream
);
3262 return ret
== EOF
? ret
: (int)i
;
3265 return es_write_sanitized (stream
, p
, length
, delimiters
, bytes_written
);
3267 #endif /*GNUPG_MAJOR_VERSION*/