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
;
117 # define ESTREAM_MUTEX_INITIALIZER NULL
118 # define ESTREAM_MUTEX_LOCK(mutex) (void) 0
119 # define ESTREAM_MUTEX_UNLOCK(mutex) (void) 0
120 # define ESTREAM_MUTEX_TRYLOCK(mutex) 0
121 # define ESTREAM_MUTEX_INITIALIZE(mutex) (void) 0
124 /* Primitive system I/O. */
127 # define ESTREAM_SYS_READ pth_read
128 # define ESTREAM_SYS_WRITE pth_write
130 # define ESTREAM_SYS_READ read
131 # define ESTREAM_SYS_WRITE write
134 /* Misc definitions. */
136 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
138 /* An internal stream object. */
140 struct estream_internal
142 unsigned char buffer
[BUFFER_BLOCK_SIZE
];
143 unsigned char unread_buffer
[BUFFER_UNREAD_SIZE
];
144 estream_mutex_t lock
; /* Lock. */
145 void *cookie
; /* Cookie. */
146 void *opaque
; /* Opaque data. */
147 unsigned int modeflags
; /* Flags for the backend. */
149 es_cookie_read_function_t func_read
;
150 es_cookie_write_function_t func_write
;
151 es_cookie_seek_function_t func_seek
;
152 es_cookie_close_function_t func_close
;
160 unsigned int deallocate_buffer
: 1;
161 unsigned int print_err
: 1; /* Error in print_fun_writer. */
162 int print_errno
; /* Errno from print_fun_writer. */
163 size_t print_ntotal
; /* Bytes written from in print_fun_writer. */
164 FILE *print_fp
; /* Stdio stream used by print_fun_writer. */
168 typedef struct estream_internal
*estream_internal_t
;
170 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
171 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
172 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
176 typedef struct estream_list
*estream_list_t
;
182 estream_list_t
*prev_cdr
;
185 static estream_list_t estream_list
;
187 /* Note that we can't use a static initialization with W32Pth, thus we
189 static estream_mutex_t estream_list_lock
;
192 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
193 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
196 # define EOPNOTSUPP ENOSYS
204 /* Calculate array dimension. */
206 #define DIM(array) (sizeof (array) / sizeof (*array))
209 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
212 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
214 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
217 tmp_variable = expression; \
218 if ((! variable) && tmp_variable) \
219 variable = tmp_variable; \
224 /* Malloc wrappers to overcvome problems on some older OSes. */
234 mem_realloc (void *p
, size_t n
)
237 return mem_alloc (n
);
238 return realloc (p
, n
);
254 /* Add STREAM to the list of registered stream objects. */
256 es_list_add (estream_t stream
)
258 estream_list_t list_obj
;
261 list_obj
= mem_alloc (sizeof (*list_obj
));
267 list_obj
->car
= stream
;
268 list_obj
->cdr
= estream_list
;
269 list_obj
->prev_cdr
= &estream_list
;
271 estream_list
->prev_cdr
= &list_obj
->cdr
;
272 estream_list
= list_obj
;
280 /* Remove STREAM from the list of registered stream objects. */
282 es_list_remove (estream_t stream
)
284 estream_list_t list_obj
;
287 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
288 if (list_obj
->car
== stream
)
290 *list_obj
->prev_cdr
= list_obj
->cdr
;
292 list_obj
->cdr
->prev_cdr
= list_obj
->prev_cdr
;
299 /* Type of an stream-iterator-function. */
300 typedef int (*estream_iterator_t
) (estream_t stream
);
302 /* Iterate over list of registered streams, calling ITERATOR for each
305 es_list_iterate (estream_iterator_t iterator
)
307 estream_list_t list_obj
;
311 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
312 ret
|= (*iterator
) (list_obj
->car
);
328 static int initialized
;
332 if (!pth_init () && errno
!= EPERM
)
334 if (pth_mutex_init (&estream_list_lock
))
347 /* Implementation of Memory I/O. */
349 /* Cookie for memory objects. */
350 typedef struct estream_cookie_mem
352 unsigned int modeflags
; /* Open flags. */
353 unsigned char *memory
; /* Allocated data buffer. */
354 size_t memory_size
; /* Allocated size of memory. */
355 size_t memory_limit
; /* Maximum allowed allocation size or
357 size_t offset
; /* Current offset in MEMORY. */
358 size_t data_len
; /* Length of data in MEMORY. */
359 size_t block_size
; /* Block size. */
361 unsigned int grow
: 1; /* MEMORY is allowed to grow. */
363 func_realloc_t func_realloc
;
364 func_free_t func_free
;
365 } *estream_cookie_mem_t
;
368 /* Create function for memory objects. */
370 es_func_mem_create (void *ES__RESTRICT
*ES__RESTRICT cookie
,
371 unsigned char *ES__RESTRICT data
, size_t data_n
,
373 size_t block_size
, unsigned int grow
,
374 func_realloc_t func_realloc
, func_free_t func_free
,
375 unsigned int modeflags
,
378 estream_cookie_mem_t mem_cookie
;
381 mem_cookie
= mem_alloc (sizeof (*mem_cookie
));
386 mem_cookie
->modeflags
= modeflags
;
387 mem_cookie
->memory
= data
;
388 mem_cookie
->memory_size
= data_n
;
389 mem_cookie
->memory_limit
= memory_limit
;
390 mem_cookie
->offset
= 0;
391 mem_cookie
->data_len
= data_len
;
392 mem_cookie
->block_size
= block_size
;
393 mem_cookie
->flags
.grow
= !!grow
;
394 mem_cookie
->func_realloc
= func_realloc
? func_realloc
: mem_realloc
;
395 mem_cookie
->func_free
= func_free
? func_free
: mem_free
;
396 *cookie
= mem_cookie
;
404 /* Read function for memory objects. */
406 es_func_mem_read (void *cookie
, void *buffer
, size_t size
)
408 estream_cookie_mem_t mem_cookie
= cookie
;
411 if (size
> mem_cookie
->data_len
- mem_cookie
->offset
)
412 size
= mem_cookie
->data_len
- mem_cookie
->offset
;
416 memcpy (buffer
, mem_cookie
->memory
+ mem_cookie
->offset
, size
);
417 mem_cookie
->offset
+= size
;
425 /* Write function for memory objects. */
427 es_func_mem_write (void *cookie
, const void *buffer
, size_t size
)
429 estream_cookie_mem_t mem_cookie
= cookie
;
433 return 0; /* A flush is a NOP for memory objects. */
435 if (mem_cookie
->modeflags
& O_APPEND
)
437 /* Append to data. */
438 mem_cookie
->offset
= mem_cookie
->data_len
;
441 if (!mem_cookie
->flags
.grow
)
443 /* We are not alloew to grow, thus limit the size to the left
444 space. FIXME: Does the grow flag an its semtics make sense
446 if (size
> mem_cookie
->memory_size
- mem_cookie
->offset
)
447 size
= mem_cookie
->memory_size
- mem_cookie
->offset
;
450 if (size
> (mem_cookie
->memory_size
- mem_cookie
->offset
))
452 unsigned char *newbuf
;
455 newsize
= mem_cookie
->memory_size
+ mem_cookie
->block_size
;
457 newsize
= mem_cookie
->offset
+ size
;
458 if (newsize
< mem_cookie
->offset
)
463 newsize
+= mem_cookie
->block_size
- 1;
464 if (newsize
< mem_cookie
->offset
)
469 newsize
/= mem_cookie
->block_size
;
470 newsize
*= mem_cookie
->block_size
;
472 if (mem_cookie
->memory_limit
&& newsize
> mem_cookie
->memory_limit
)
478 newbuf
= mem_cookie
->func_realloc (mem_cookie
->memory
, newsize
);
482 mem_cookie
->memory
= newbuf
;
483 mem_cookie
->memory_size
= newsize
;
485 assert (!(size
> (mem_cookie
->memory_size
- mem_cookie
->offset
)));
488 memcpy (mem_cookie
->memory
+ mem_cookie
->offset
, buffer
, size
);
489 if (mem_cookie
->offset
+ size
> mem_cookie
->data_len
)
490 mem_cookie
->data_len
= mem_cookie
->offset
+ size
;
491 mem_cookie
->offset
+= size
;
498 /* Seek function for memory objects. */
500 es_func_mem_seek (void *cookie
, off_t
*offset
, int whence
)
502 estream_cookie_mem_t mem_cookie
= cookie
;
512 pos_new
= mem_cookie
->offset
+= *offset
;
516 pos_new
= mem_cookie
->data_len
+= *offset
;
524 if (pos_new
> mem_cookie
->memory_size
)
529 if (!mem_cookie
->flags
.grow
)
536 newsize
= pos_new
+ mem_cookie
->block_size
- 1;
537 if (newsize
< pos_new
)
542 newsize
/= mem_cookie
->block_size
;
543 newsize
*= mem_cookie
->block_size
;
544 if (mem_cookie
->memory_limit
&& newsize
> mem_cookie
->memory_limit
)
550 newbuf
= mem_cookie
->func_realloc (mem_cookie
->memory
, newsize
);
554 mem_cookie
->memory
= newbuf
;
555 mem_cookie
->memory_size
= newsize
;
558 if (pos_new
> mem_cookie
->data_len
)
560 /* Fill spare space with zeroes. */
561 memset (mem_cookie
->memory
+ mem_cookie
->data_len
,
562 0, pos_new
- mem_cookie
->data_len
);
563 mem_cookie
->data_len
= pos_new
;
566 mem_cookie
->offset
= pos_new
;
573 /* Destroy function for memory objects. */
575 es_func_mem_destroy (void *cookie
)
577 estream_cookie_mem_t mem_cookie
= cookie
;
581 mem_cookie
->func_free (mem_cookie
->memory
);
582 mem_free (mem_cookie
);
588 static es_cookie_io_functions_t estream_functions_mem
=
598 /* Implementation of fd I/O. */
600 /* Cookie for fd objects. */
601 typedef struct estream_cookie_fd
603 int fd
; /* The file descriptor we are using for actual output. */
604 int no_close
; /* If set we won't close the file descriptor. */
605 } *estream_cookie_fd_t
;
607 /* Create function for fd objects. */
609 es_func_fd_create (void **cookie
, int fd
, unsigned int modeflags
, int no_close
)
611 estream_cookie_fd_t fd_cookie
;
614 fd_cookie
= mem_alloc (sizeof (*fd_cookie
));
619 #ifdef HAVE_DOSISH_SYSTEM
620 /* Make sure it is in binary mode if requested. */
621 if ( (modeflags
& O_BINARY
) )
622 setmode (fd
, O_BINARY
);
625 fd_cookie
->no_close
= no_close
;
633 /* Read function for fd objects. */
635 es_func_fd_read (void *cookie
, void *buffer
, size_t size
)
638 estream_cookie_fd_t file_cookie
= cookie
;
642 bytes_read
= ESTREAM_SYS_READ (file_cookie
->fd
, buffer
, size
);
643 while (bytes_read
== -1 && errno
== EINTR
);
648 /* Write function for fd objects. */
650 es_func_fd_write (void *cookie
, const void *buffer
, size_t size
)
653 estream_cookie_fd_t file_cookie
= cookie
;
654 ssize_t bytes_written
;
657 bytes_written
= ESTREAM_SYS_WRITE (file_cookie
->fd
, buffer
, size
);
658 while (bytes_written
== -1 && errno
== EINTR
);
660 return bytes_written
;
663 /* Seek function for fd objects. */
665 es_func_fd_seek (void *cookie
, off_t
*offset
, int whence
)
667 estream_cookie_fd_t file_cookie
= cookie
;
671 offset_new
= lseek (file_cookie
->fd
, *offset
, whence
);
672 if (offset_new
== -1)
676 *offset
= offset_new
;
683 /* Destroy function for fd objects. */
685 es_func_fd_destroy (void *cookie
)
687 estream_cookie_fd_t fd_cookie
= cookie
;
692 err
= fd_cookie
->no_close
? 0 : close (fd_cookie
->fd
);
693 mem_free (fd_cookie
);
702 static es_cookie_io_functions_t estream_functions_fd
=
713 /* Implementation of FILE* I/O. */
715 /* Cookie for fp objects. */
716 typedef struct estream_cookie_fp
718 FILE *fp
; /* The file pointer we are using for actual output. */
719 int no_close
; /* If set we won't close the file pointer. */
720 } *estream_cookie_fp_t
;
722 /* Create function for fd objects. */
724 es_func_fp_create (void **cookie
, FILE *fp
, unsigned int modeflags
, int no_close
)
726 estream_cookie_fp_t fp_cookie
;
729 fp_cookie
= mem_alloc (sizeof *fp_cookie
);
734 #ifdef HAVE_DOSISH_SYSTEM
735 /* Make sure it is in binary mode if requested. */
736 if ( (modeflags
& O_BINARY
) )
737 setmode (fileno (fp
), O_BINARY
);
740 fp_cookie
->no_close
= no_close
;
748 /* Read function for FILE* objects. */
750 es_func_fp_read (void *cookie
, void *buffer
, size_t size
)
753 estream_cookie_fp_t file_cookie
= cookie
;
756 bytes_read
= fread (buffer
, 1, size
, file_cookie
->fp
);
757 if (!bytes_read
&& ferror (file_cookie
->fp
))
762 /* Write function for FILE* objects. */
764 es_func_fp_write (void *cookie
, const void *buffer
, size_t size
)
767 estream_cookie_fp_t file_cookie
= cookie
;
768 size_t bytes_written
;
770 bytes_written
= fwrite (buffer
, 1, size
, file_cookie
->fp
);
771 if (bytes_written
!= size
)
773 return bytes_written
;
776 /* Seek function for FILE* objects. */
778 es_func_fp_seek (void *cookie
, off_t
*offset
, int whence
)
780 estream_cookie_fp_t file_cookie
= cookie
;
783 if ( fseek (file_cookie
->fp
, (long int)*offset
, whence
) )
785 fprintf (stderr
, "\nfseek failed: errno=%d (%s)\n", errno
,strerror (errno
));
789 offset_new
= ftell (file_cookie
->fp
);
790 if (offset_new
== -1)
792 fprintf (stderr
, "\nftell failed: errno=%d (%s)\n", errno
,strerror (errno
));
795 *offset
= offset_new
;
799 /* Destroy function for fd objects. */
801 es_func_fp_destroy (void *cookie
)
803 estream_cookie_fp_t fp_cookie
= cookie
;
808 fflush (fp_cookie
->fp
);
809 err
= fp_cookie
->no_close
? 0 : fclose (fp_cookie
->fp
);
810 mem_free (fp_cookie
);
819 static es_cookie_io_functions_t estream_functions_fp
=
830 /* Implementation of file I/O. */
832 /* Create function for file objects. */
834 es_func_file_create (void **cookie
, int *filedes
,
835 const char *path
, unsigned int modeflags
)
837 estream_cookie_fd_t file_cookie
;
844 file_cookie
= mem_alloc (sizeof (*file_cookie
));
851 fd
= open (path
, modeflags
, ES_DEFAULT_OPEN_MODE
);
857 #ifdef HAVE_DOSISH_SYSTEM
858 /* Make sure it is in binary mode if requested. */
859 if ( (modeflags
& O_BINARY
) )
860 setmode (fd
, O_BINARY
);
863 file_cookie
->fd
= fd
;
864 file_cookie
->no_close
= 0;
865 *cookie
= file_cookie
;
871 mem_free (file_cookie
);
876 static es_cookie_io_functions_t estream_functions_file
=
886 /* Stream primitives. */
889 es_convert_mode (const char *mode
, unsigned int *modeflags
)
892 /* FIXME: We need to allow all mode flags permutations. */
897 } mode_flags
[] = { { "r",
900 O_RDONLY
| O_BINARY
},
902 O_WRONLY
| O_TRUNC
| O_CREAT
},
904 O_WRONLY
| O_TRUNC
| O_CREAT
| O_BINARY
},
906 O_WRONLY
| O_APPEND
| O_CREAT
},
908 O_WRONLY
| O_APPEND
| O_CREAT
| O_BINARY
},
914 O_RDONLY
| O_WRONLY
| O_BINARY
},
916 O_RDWR
| O_TRUNC
| O_CREAT
},
918 O_RDWR
| O_TRUNC
| O_CREAT
| O_BINARY
},
920 O_RDWR
| O_TRUNC
| O_CREAT
| O_BINARY
},
922 O_RDWR
| O_CREAT
| O_APPEND
},
924 O_RDWR
| O_CREAT
| O_APPEND
| O_BINARY
},
926 O_RDWR
| O_CREAT
| O_APPEND
| O_BINARY
}
931 for (i
= 0; i
< DIM (mode_flags
); i
++)
932 if (! strcmp (mode_flags
[i
].mode
, mode
))
934 if (i
== DIM (mode_flags
))
942 *modeflags
= mode_flags
[i
].flags
;
951 * Low level stream functionality.
955 es_fill (estream_t stream
)
957 size_t bytes_read
= 0;
960 if (!stream
->intern
->func_read
)
967 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
970 ret
= (*func_read
) (stream
->intern
->cookie
,
971 stream
->buffer
, stream
->buffer_size
);
985 stream
->intern
->indicators
.err
= 1;
986 else if (!bytes_read
)
987 stream
->intern
->indicators
.eof
= 1;
989 stream
->intern
->offset
+= stream
->data_len
;
990 stream
->data_len
= bytes_read
;
991 stream
->data_offset
= 0;
997 es_flush (estream_t stream
)
999 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1002 assert (stream
->flags
.writing
);
1004 if (stream
->data_offset
)
1006 size_t bytes_written
;
1007 size_t data_flushed
;
1016 /* Note: to prevent an endless loop caused by user-provided
1017 write-functions that pretend to have written more bytes than
1018 they were asked to write, we have to check for
1019 "(stream->data_offset - data_flushed) > 0" instead of
1020 "stream->data_offset - data_flushed". */
1025 while ((((ssize_t
) (stream
->data_offset
- data_flushed
)) > 0) && (! err
))
1027 ret
= (*func_write
) (stream
->intern
->cookie
,
1028 stream
->buffer
+ data_flushed
,
1029 stream
->data_offset
- data_flushed
);
1036 bytes_written
= ret
;
1038 data_flushed
+= bytes_written
;
1043 stream
->data_flushed
+= data_flushed
;
1044 if (stream
->data_offset
== data_flushed
)
1046 stream
->intern
->offset
+= stream
->data_offset
;
1047 stream
->data_offset
= 0;
1048 stream
->data_flushed
= 0;
1050 /* Propagate flush event. */
1051 (*func_write
) (stream
->intern
->cookie
, NULL
, 0);
1060 stream
->intern
->indicators
.err
= 1;
1065 /* Discard buffered data for STREAM. */
1067 es_empty (estream_t stream
)
1069 assert (!stream
->flags
.writing
);
1070 stream
->data_len
= 0;
1071 stream
->data_offset
= 0;
1072 stream
->unread_data_len
= 0;
1075 /* Initialize STREAM. */
1077 es_initialize (estream_t stream
,
1078 void *cookie
, int fd
, es_cookie_io_functions_t functions
,
1079 unsigned int modeflags
)
1081 stream
->intern
->cookie
= cookie
;
1082 stream
->intern
->opaque
= NULL
;
1083 stream
->intern
->offset
= 0;
1084 stream
->intern
->func_read
= functions
.func_read
;
1085 stream
->intern
->func_write
= functions
.func_write
;
1086 stream
->intern
->func_seek
= functions
.func_seek
;
1087 stream
->intern
->func_close
= functions
.func_close
;
1088 stream
->intern
->strategy
= _IOFBF
;
1089 stream
->intern
->fd
= fd
;
1090 stream
->intern
->print_err
= 0;
1091 stream
->intern
->print_errno
= 0;
1092 stream
->intern
->print_ntotal
= 0;
1093 stream
->intern
->print_fp
= NULL
;
1094 stream
->intern
->indicators
.err
= 0;
1095 stream
->intern
->indicators
.eof
= 0;
1096 stream
->intern
->deallocate_buffer
= 0;
1098 stream
->data_len
= 0;
1099 stream
->data_offset
= 0;
1100 stream
->data_flushed
= 0;
1101 stream
->unread_data_len
= 0;
1102 /* Depending on the modeflags we set whether we start in writing or
1103 reading mode. This is required in case we are working on a
1104 wronly stream which is not seeekable (like stdout). Without this
1105 pre-initialization we would do a seek at the first write call and
1106 as this will fail no utput will be delivered. */
1107 if ((modeflags
& O_WRONLY
) || (modeflags
& O_RDWR
) )
1108 stream
->flags
.writing
= 1;
1110 stream
->flags
.writing
= 0;
1113 /* Deinitialize STREAM. */
1115 es_deinitialize (estream_t stream
)
1117 es_cookie_close_function_t func_close
;
1120 if (stream
->intern
->print_fp
)
1122 int save_errno
= errno
;
1123 fclose (stream
->intern
->print_fp
);
1124 stream
->intern
->print_fp
= NULL
;
1128 func_close
= stream
->intern
->func_close
;
1131 if (stream
->flags
.writing
)
1132 SET_UNLESS_NONZERO (err
, tmp_err
, es_flush (stream
));
1134 SET_UNLESS_NONZERO (err
, tmp_err
, (*func_close
) (stream
->intern
->cookie
));
1140 /* Create a new stream object, initialize it. */
1142 es_create (estream_t
*stream
, void *cookie
, int fd
,
1143 es_cookie_io_functions_t functions
, unsigned int modeflags
)
1145 estream_internal_t stream_internal_new
;
1146 estream_t stream_new
;
1150 stream_internal_new
= NULL
;
1152 stream_new
= mem_alloc (sizeof (*stream_new
));
1159 stream_internal_new
= mem_alloc (sizeof (*stream_internal_new
));
1160 if (! stream_internal_new
)
1166 stream_new
->buffer
= stream_internal_new
->buffer
;
1167 stream_new
->buffer_size
= sizeof (stream_internal_new
->buffer
);
1168 stream_new
->unread_buffer
= stream_internal_new
->unread_buffer
;
1169 stream_new
->unread_buffer_size
= sizeof (stream_internal_new
->unread_buffer
);
1170 stream_new
->intern
= stream_internal_new
;
1172 ESTREAM_MUTEX_INITIALIZE (stream_new
->intern
->lock
);
1173 es_initialize (stream_new
, cookie
, fd
, functions
, modeflags
);
1175 err
= es_list_add (stream_new
);
1179 *stream
= stream_new
;
1187 es_deinitialize (stream_new
);
1188 mem_free (stream_new
);
1195 /* Deinitialize a stream object and destroy it. */
1197 es_destroy (estream_t stream
)
1203 es_list_remove (stream
);
1204 err
= es_deinitialize (stream
);
1205 mem_free (stream
->intern
);
1212 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1213 unbuffered-mode, storing the amount of bytes read in
1216 es_read_nbf (estream_t ES__RESTRICT stream
,
1217 unsigned char *ES__RESTRICT buffer
,
1218 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1220 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
1228 while (bytes_to_read
- data_read
)
1230 ret
= (*func_read
) (stream
->intern
->cookie
,
1231 buffer
+ data_read
, bytes_to_read
- data_read
);
1243 stream
->intern
->offset
+= data_read
;
1244 *bytes_read
= data_read
;
1249 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1250 fully-buffered-mode, storing the amount of bytes read in
1253 es_read_fbf (estream_t ES__RESTRICT stream
,
1254 unsigned char *ES__RESTRICT buffer
,
1255 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1257 size_t data_available
;
1258 size_t data_to_read
;
1265 while ((bytes_to_read
- data_read
) && (! err
))
1267 if (stream
->data_offset
== stream
->data_len
)
1269 /* Nothing more to read in current container, try to
1270 fill container with new data. */
1271 err
= es_fill (stream
);
1273 if (! stream
->data_len
)
1274 /* Filling did not result in any data read. */
1280 /* Filling resulted in some new data. */
1282 data_to_read
= bytes_to_read
- data_read
;
1283 data_available
= stream
->data_len
- stream
->data_offset
;
1284 if (data_to_read
> data_available
)
1285 data_to_read
= data_available
;
1287 memcpy (buffer
+ data_read
,
1288 stream
->buffer
+ stream
->data_offset
, data_to_read
);
1289 stream
->data_offset
+= data_to_read
;
1290 data_read
+= data_to_read
;
1294 *bytes_read
= data_read
;
1299 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1300 line-buffered-mode, storing the amount of bytes read in
1303 es_read_lbf (estream_t ES__RESTRICT stream
,
1304 unsigned char *ES__RESTRICT buffer
,
1305 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1309 err
= es_read_fbf (stream
, buffer
, bytes_to_read
, bytes_read
);
1314 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1315 *the amount of bytes read in BYTES_READ. */
1317 es_readn (estream_t ES__RESTRICT stream
,
1318 void *ES__RESTRICT buffer_arg
,
1319 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1321 unsigned char *buffer
= (unsigned char *)buffer_arg
;
1322 size_t data_read_unread
, data_read
;
1325 data_read_unread
= 0;
1329 if (stream
->flags
.writing
)
1331 /* Switching to reading mode -> flush output. */
1332 err
= es_flush (stream
);
1335 stream
->flags
.writing
= 0;
1338 /* Read unread data first. */
1339 while ((bytes_to_read
- data_read_unread
) && stream
->unread_data_len
)
1341 buffer
[data_read_unread
]
1342 = stream
->unread_buffer
[stream
->unread_data_len
- 1];
1343 stream
->unread_data_len
--;
1347 switch (stream
->intern
->strategy
)
1350 err
= es_read_nbf (stream
,
1351 buffer
+ data_read_unread
,
1352 bytes_to_read
- data_read_unread
, &data_read
);
1355 err
= es_read_lbf (stream
,
1356 buffer
+ data_read_unread
,
1357 bytes_to_read
- data_read_unread
, &data_read
);
1360 err
= es_read_fbf (stream
,
1361 buffer
+ data_read_unread
,
1362 bytes_to_read
- data_read_unread
, &data_read
);
1369 *bytes_read
= data_read_unread
+ data_read
;
1374 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1375 amount of bytes succesfully unread in *BYTES_UNREAD. */
1377 es_unreadn (estream_t ES__RESTRICT stream
,
1378 const unsigned char *ES__RESTRICT data
, size_t data_n
,
1379 size_t *ES__RESTRICT bytes_unread
)
1383 space_left
= stream
->unread_buffer_size
- stream
->unread_data_len
;
1385 if (data_n
> space_left
)
1386 data_n
= space_left
;
1391 memcpy (stream
->unread_buffer
+ stream
->unread_data_len
, data
, data_n
);
1392 stream
->unread_data_len
+= data_n
;
1393 stream
->intern
->indicators
.eof
= 0;
1398 *bytes_unread
= data_n
;
1401 /* Seek in STREAM. */
1403 es_seek (estream_t ES__RESTRICT stream
, off_t offset
, int whence
,
1404 off_t
*ES__RESTRICT offset_new
)
1406 es_cookie_seek_function_t func_seek
= stream
->intern
->func_seek
;
1417 if (stream
->flags
.writing
)
1419 /* Flush data first in order to prevent flushing it to the wrong
1421 err
= es_flush (stream
);
1424 stream
->flags
.writing
= 0;
1428 if (whence
== SEEK_CUR
)
1430 off
= off
- stream
->data_len
+ stream
->data_offset
;
1431 off
-= stream
->unread_data_len
;
1434 ret
= (*func_seek
) (stream
->intern
->cookie
, &off
, whence
);
1447 stream
->intern
->indicators
.eof
= 0;
1448 stream
->intern
->offset
= off
;
1453 stream
->intern
->indicators
.err
= 1;
1458 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1459 unbuffered-mode, storing the amount of bytes written in
1462 es_write_nbf (estream_t ES__RESTRICT stream
,
1463 const unsigned char *ES__RESTRICT buffer
,
1464 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1466 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1467 size_t data_written
;
1471 if (bytes_to_write
&& (! func_write
))
1480 while (bytes_to_write
- data_written
)
1482 ret
= (*func_write
) (stream
->intern
->cookie
,
1483 buffer
+ data_written
,
1484 bytes_to_write
- data_written
);
1491 data_written
+= ret
;
1494 stream
->intern
->offset
+= data_written
;
1495 *bytes_written
= data_written
;
1502 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1503 fully-buffered-mode, storing the amount of bytes written in
1506 es_write_fbf (estream_t ES__RESTRICT stream
,
1507 const unsigned char *ES__RESTRICT buffer
,
1508 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1510 size_t space_available
;
1511 size_t data_to_write
;
1512 size_t data_written
;
1518 while ((bytes_to_write
- data_written
) && (! err
))
1520 if (stream
->data_offset
== stream
->buffer_size
)
1521 /* Container full, flush buffer. */
1522 err
= es_flush (stream
);
1526 /* Flushing resulted in empty container. */
1528 data_to_write
= bytes_to_write
- data_written
;
1529 space_available
= stream
->buffer_size
- stream
->data_offset
;
1530 if (data_to_write
> space_available
)
1531 data_to_write
= space_available
;
1533 memcpy (stream
->buffer
+ stream
->data_offset
,
1534 buffer
+ data_written
, data_to_write
);
1535 stream
->data_offset
+= data_to_write
;
1536 data_written
+= data_to_write
;
1540 *bytes_written
= data_written
;
1546 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1547 line-buffered-mode, storing the amount of bytes written in
1550 es_write_lbf (estream_t ES__RESTRICT stream
,
1551 const unsigned char *ES__RESTRICT buffer
,
1552 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1554 size_t data_flushed
= 0;
1555 size_t data_buffered
= 0;
1559 nlp
= memrchr (buffer
, '\n', bytes_to_write
);
1562 /* Found a newline, directly write up to (including) this
1564 err
= es_flush (stream
);
1566 err
= es_write_nbf (stream
, buffer
, nlp
- buffer
+ 1, &data_flushed
);
1571 /* Write remaining data fully buffered. */
1572 err
= es_write_fbf (stream
, buffer
+ data_flushed
,
1573 bytes_to_write
- data_flushed
, &data_buffered
);
1576 *bytes_written
= data_flushed
+ data_buffered
;
1581 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1582 amount of bytes written in BYTES_WRITTEN. */
1584 es_writen (estream_t ES__RESTRICT stream
,
1585 const void *ES__RESTRICT buffer
,
1586 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1588 size_t data_written
;
1594 if (!stream
->flags
.writing
)
1596 /* Switching to writing mode -> discard input data and seek to
1597 position at which reading has stopped. We can do this only
1598 if a seek function has been registered. */
1599 if (stream
->intern
->func_seek
)
1601 err
= es_seek (stream
, 0, SEEK_CUR
, NULL
);
1604 if (errno
== ESPIPE
)
1612 switch (stream
->intern
->strategy
)
1615 err
= es_write_nbf (stream
, buffer
, bytes_to_write
, &data_written
);
1619 err
= es_write_lbf (stream
, buffer
, bytes_to_write
, &data_written
);
1623 err
= es_write_fbf (stream
, buffer
, bytes_to_write
, &data_written
);
1630 *bytes_written
= data_written
;
1632 if (!stream
->flags
.writing
)
1633 stream
->flags
.writing
= 1;
1640 es_peek (estream_t ES__RESTRICT stream
, unsigned char **ES__RESTRICT data
,
1641 size_t *ES__RESTRICT data_len
)
1645 if (stream
->flags
.writing
)
1647 /* Switching to reading mode -> flush output. */
1648 err
= es_flush (stream
);
1651 stream
->flags
.writing
= 0;
1654 if (stream
->data_offset
== stream
->data_len
)
1656 /* Refill container. */
1657 err
= es_fill (stream
);
1663 *data
= stream
->buffer
+ stream
->data_offset
;
1665 *data_len
= stream
->data_len
- stream
->data_offset
;
1674 /* Skip SIZE bytes of input data contained in buffer. */
1676 es_skip (estream_t stream
, size_t size
)
1680 if (stream
->data_offset
+ size
> stream
->data_len
)
1687 stream
->data_offset
+= size
;
1696 doreadline (estream_t ES__RESTRICT stream
, size_t max_length
,
1697 char *ES__RESTRICT
*ES__RESTRICT line
,
1698 size_t *ES__RESTRICT line_length
)
1702 estream_t line_stream
;
1704 void *line_stream_cookie
;
1706 unsigned char *data
;
1712 line_stream_cookie
= NULL
;
1714 err
= es_func_mem_create (&line_stream_cookie
, NULL
, 0, 0,
1715 BUFFER_BLOCK_SIZE
, 1,
1716 mem_realloc
, mem_free
,
1722 err
= es_create (&line_stream
, line_stream_cookie
, -1,
1723 estream_functions_mem
, O_RDWR
);
1727 space_left
= max_length
;
1731 if (max_length
&& (space_left
== 1))
1734 err
= es_peek (stream
, &data
, &data_len
);
1735 if (err
|| (! data_len
))
1738 if (data_len
> (space_left
- 1))
1739 data_len
= space_left
- 1;
1741 newline
= memchr (data
, '\n', data_len
);
1744 data_len
= (newline
- (char *) data
) + 1;
1745 err
= es_write (line_stream
, data
, data_len
, NULL
);
1748 space_left
-= data_len
;
1749 line_size
+= data_len
;
1750 es_skip (stream
, data_len
);
1756 err
= es_write (line_stream
, data
, data_len
, NULL
);
1759 space_left
-= data_len
;
1760 line_size
+= data_len
;
1761 es_skip (stream
, data_len
);
1770 /* Complete line has been written to line_stream. */
1772 if ((max_length
> 1) && (! line_size
))
1774 stream
->intern
->indicators
.eof
= 1;
1778 err
= es_seek (line_stream
, 0, SEEK_SET
, NULL
);
1784 line_new
= mem_alloc (line_size
+ 1);
1794 err
= es_read (line_stream
, line_new
, line_size
, NULL
);
1798 line_new
[line_size
] = '\0';
1803 *line_length
= line_size
;
1808 es_destroy (line_stream
);
1809 else if (line_stream_cookie
)
1810 es_func_mem_destroy (line_stream_cookie
);
1815 mem_free (line_new
);
1816 stream
->intern
->indicators
.err
= 1;
1823 /* Output fucntion used for estream_format. */
1825 print_writer (void *outfncarg
, const char *buf
, size_t buflen
)
1827 estream_t stream
= outfncarg
;
1832 rc
= es_writen (stream
, buf
, buflen
, &nwritten
);
1833 stream
->intern
->print_ntotal
+= nwritten
;
1838 /* The core of our printf function. This is called in locked state. */
1840 es_print (estream_t ES__RESTRICT stream
,
1841 const char *ES__RESTRICT format
, va_list ap
)
1845 stream
->intern
->print_ntotal
= 0;
1846 rc
= estream_format (print_writer
, stream
, format
, ap
);
1849 return (int)stream
->intern
->print_ntotal
;
1854 es_set_indicators (estream_t stream
, int ind_err
, int ind_eof
)
1857 stream
->intern
->indicators
.err
= ind_err
? 1 : 0;
1859 stream
->intern
->indicators
.eof
= ind_eof
? 1 : 0;
1864 es_get_indicator (estream_t stream
, int ind_err
, int ind_eof
)
1869 ret
= stream
->intern
->indicators
.err
;
1871 ret
= stream
->intern
->indicators
.eof
;
1878 es_set_buffering (estream_t ES__RESTRICT stream
,
1879 char *ES__RESTRICT buffer
, int mode
, size_t size
)
1883 /* Flush or empty buffer depending on mode. */
1884 if (stream
->flags
.writing
)
1886 err
= es_flush (stream
);
1893 es_set_indicators (stream
, -1, 0);
1895 /* Free old buffer in case that was allocated by this function. */
1896 if (stream
->intern
->deallocate_buffer
)
1898 stream
->intern
->deallocate_buffer
= 0;
1899 mem_free (stream
->buffer
);
1900 stream
->buffer
= NULL
;
1904 stream
->buffer_size
= 0;
1910 buffer_new
= buffer
;
1913 buffer_new
= mem_alloc (size
);
1921 stream
->buffer
= buffer_new
;
1922 stream
->buffer_size
= size
;
1924 stream
->intern
->deallocate_buffer
= 1;
1926 stream
->intern
->strategy
= mode
;
1936 es_offset_calculate (estream_t stream
)
1940 offset
= stream
->intern
->offset
+ stream
->data_offset
;
1941 if (offset
< stream
->unread_data_len
)
1942 /* Offset undefined. */
1945 offset
-= stream
->unread_data_len
;
1952 es_opaque_ctrl (estream_t ES__RESTRICT stream
, void *ES__RESTRICT opaque_new
,
1953 void **ES__RESTRICT opaque_old
)
1956 *opaque_old
= stream
->intern
->opaque
;
1958 stream
->intern
->opaque
= opaque_new
;
1963 es_get_fd (estream_t stream
)
1965 return stream
->intern
->fd
;
1977 err
= es_init_do ();
1983 es_fopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
)
1985 unsigned int modeflags
;
1996 err
= es_convert_mode (mode
, &modeflags
);
2000 err
= es_func_file_create (&cookie
, &fd
, path
, modeflags
);
2005 err
= es_create (&stream
, cookie
, fd
, estream_functions_file
, modeflags
);
2011 if (err
&& create_called
)
2012 (*estream_functions_file
.func_close
) (cookie
);
2019 es_mopen (unsigned char *ES__RESTRICT data
, size_t data_n
, size_t data_len
,
2021 func_realloc_t func_realloc
, func_free_t func_free
,
2022 const char *ES__RESTRICT mode
)
2024 unsigned int modeflags
;
2034 err
= es_convert_mode (mode
, &modeflags
);
2038 err
= es_func_mem_create (&cookie
, data
, data_n
, data_len
,
2039 BUFFER_BLOCK_SIZE
, grow
,
2040 func_realloc
, func_free
, modeflags
, 0);
2045 err
= es_create (&stream
, cookie
, -1, estream_functions_mem
, modeflags
);
2049 if (err
&& create_called
)
2050 (*estream_functions_mem
.func_close
) (cookie
);
2057 es_fopenmem (size_t memlimit
, const char *ES__RESTRICT mode
)
2059 unsigned int modeflags
;
2060 estream_t stream
= NULL
;
2061 void *cookie
= NULL
;
2063 /* Memory streams are always read/write. We use MODE only to get
2065 if (es_convert_mode (mode
, &modeflags
))
2067 modeflags
|= O_RDWR
;
2070 if (es_func_mem_create (&cookie
, NULL
, 0, 0,
2071 BUFFER_BLOCK_SIZE
, 1,
2072 mem_realloc
, mem_free
, modeflags
,
2076 if (es_create (&stream
, cookie
, -1, estream_functions_mem
, modeflags
))
2077 (*estream_functions_mem
.func_close
) (cookie
);
2085 es_fopencookie (void *ES__RESTRICT cookie
,
2086 const char *ES__RESTRICT mode
,
2087 es_cookie_io_functions_t functions
)
2089 unsigned int modeflags
;
2096 err
= es_convert_mode (mode
, &modeflags
);
2100 err
= es_create (&stream
, cookie
, -1, functions
, modeflags
);
2111 do_fdopen (int filedes
, const char *mode
, int no_close
)
2113 unsigned int modeflags
;
2123 err
= es_convert_mode (mode
, &modeflags
);
2127 err
= es_func_fd_create (&cookie
, filedes
, modeflags
, no_close
);
2132 err
= es_create (&stream
, cookie
, filedes
, estream_functions_fd
, modeflags
);
2136 if (err
&& create_called
)
2137 (*estream_functions_fd
.func_close
) (cookie
);
2143 es_fdopen (int filedes
, const char *mode
)
2145 return do_fdopen (filedes
, mode
, 0);
2148 /* A variant of es_fdopen which does not close FILEDES at the end. */
2150 es_fdopen_nc (int filedes
, const char *mode
)
2152 return do_fdopen (filedes
, mode
, 1);
2157 do_fpopen (FILE *fp
, const char *mode
, int no_close
)
2159 unsigned int modeflags
;
2169 err
= es_convert_mode (mode
, &modeflags
);
2174 err
= es_func_fp_create (&cookie
, fp
, modeflags
, no_close
);
2179 err
= es_create (&stream
, cookie
, fileno (fp
), estream_functions_fp
,
2184 if (err
&& create_called
)
2185 (*estream_functions_fp
.func_close
) (cookie
);
2191 /* Create an estream from the stdio stream FP. This mechanism is
2192 useful in case the stdio streams have special properties and may
2193 not be mixed with fd based functions. This is for example the case
2194 under Windows where the 3 standard streams are associated with the
2195 console whereas a duped and fd-opened stream of one of this stream
2196 won't be associated with the console. As this messes things up it
2197 is easier to keep on using the standard I/O stream as a backend for
2200 es_fpopen (FILE *fp
, const char *mode
)
2202 return do_fpopen (fp
, mode
, 0);
2206 /* Same as es_fpopen but does not close FP at the end. */
2208 es_fpopen_nc (FILE *fp
, const char *mode
)
2210 return do_fpopen (fp
, mode
, 1);
2215 es_freopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
,
2216 estream_t ES__RESTRICT stream
)
2222 unsigned int modeflags
;
2230 ESTREAM_LOCK (stream
);
2232 es_deinitialize (stream
);
2234 err
= es_convert_mode (mode
, &modeflags
);
2238 err
= es_func_file_create (&cookie
, &fd
, path
, modeflags
);
2243 es_initialize (stream
, cookie
, fd
, estream_functions_file
, modeflags
);
2250 es_func_fd_destroy (cookie
);
2252 es_destroy (stream
);
2256 ESTREAM_UNLOCK (stream
);
2260 /* FIXME? We don't support re-opening at the moment. */
2262 es_deinitialize (stream
);
2263 es_destroy (stream
);
2272 es_fclose (estream_t stream
)
2276 err
= es_destroy (stream
);
2282 es_fileno_unlocked (estream_t stream
)
2284 return es_get_fd (stream
);
2289 es_flockfile (estream_t stream
)
2291 ESTREAM_LOCK (stream
);
2296 es_ftrylockfile (estream_t stream
)
2298 return ESTREAM_TRYLOCK (stream
);
2303 es_funlockfile (estream_t stream
)
2305 ESTREAM_UNLOCK (stream
);
2310 es_fileno (estream_t stream
)
2314 ESTREAM_LOCK (stream
);
2315 ret
= es_fileno_unlocked (stream
);
2316 ESTREAM_UNLOCK (stream
);
2323 es_feof_unlocked (estream_t stream
)
2325 return es_get_indicator (stream
, 0, 1);
2330 es_feof (estream_t stream
)
2334 ESTREAM_LOCK (stream
);
2335 ret
= es_feof_unlocked (stream
);
2336 ESTREAM_UNLOCK (stream
);
2343 es_ferror_unlocked (estream_t stream
)
2345 return es_get_indicator (stream
, 1, 0);
2350 es_ferror (estream_t stream
)
2354 ESTREAM_LOCK (stream
);
2355 ret
= es_ferror_unlocked (stream
);
2356 ESTREAM_UNLOCK (stream
);
2363 es_clearerr_unlocked (estream_t stream
)
2365 es_set_indicators (stream
, 0, 0);
2370 es_clearerr (estream_t stream
)
2372 ESTREAM_LOCK (stream
);
2373 es_clearerr_unlocked (stream
);
2374 ESTREAM_UNLOCK (stream
);
2379 es_fflush (estream_t stream
)
2385 ESTREAM_LOCK (stream
);
2386 if (stream
->flags
.writing
)
2387 err
= es_flush (stream
);
2393 ESTREAM_UNLOCK (stream
);
2396 err
= es_list_iterate (es_fflush
);
2398 return err
? EOF
: 0;
2403 es_fseek (estream_t stream
, long int offset
, int whence
)
2407 ESTREAM_LOCK (stream
);
2408 err
= es_seek (stream
, offset
, whence
, NULL
);
2409 ESTREAM_UNLOCK (stream
);
2416 es_fseeko (estream_t stream
, off_t offset
, int whence
)
2420 ESTREAM_LOCK (stream
);
2421 err
= es_seek (stream
, offset
, whence
, NULL
);
2422 ESTREAM_UNLOCK (stream
);
2429 es_ftell (estream_t stream
)
2433 ESTREAM_LOCK (stream
);
2434 ret
= es_offset_calculate (stream
);
2435 ESTREAM_UNLOCK (stream
);
2442 es_ftello (estream_t stream
)
2446 ESTREAM_LOCK (stream
);
2447 ret
= es_offset_calculate (stream
);
2448 ESTREAM_UNLOCK (stream
);
2455 es_rewind (estream_t stream
)
2457 ESTREAM_LOCK (stream
);
2458 es_seek (stream
, 0L, SEEK_SET
, NULL
);
2459 es_set_indicators (stream
, 0, -1);
2460 ESTREAM_UNLOCK (stream
);
2465 _es_getc_underflow (estream_t stream
)
2471 err
= es_readn (stream
, &c
, 1, &bytes_read
);
2473 return (err
|| (! bytes_read
)) ? EOF
: c
;
2478 _es_putc_overflow (int c
, estream_t stream
)
2480 unsigned char d
= c
;
2483 err
= es_writen (stream
, &d
, 1, NULL
);
2485 return err
? EOF
: c
;
2490 es_fgetc (estream_t stream
)
2494 ESTREAM_LOCK (stream
);
2495 ret
= es_getc_unlocked (stream
);
2496 ESTREAM_UNLOCK (stream
);
2503 es_fputc (int c
, estream_t stream
)
2507 ESTREAM_LOCK (stream
);
2508 ret
= es_putc_unlocked (c
, stream
);
2509 ESTREAM_UNLOCK (stream
);
2516 es_ungetc (int c
, estream_t stream
)
2518 unsigned char data
= (unsigned char) c
;
2521 ESTREAM_LOCK (stream
);
2522 es_unreadn (stream
, &data
, 1, &data_unread
);
2523 ESTREAM_UNLOCK (stream
);
2525 return data_unread
? c
: EOF
;
2530 es_read (estream_t ES__RESTRICT stream
,
2531 void *ES__RESTRICT buffer
, size_t bytes_to_read
,
2532 size_t *ES__RESTRICT bytes_read
)
2538 ESTREAM_LOCK (stream
);
2539 err
= es_readn (stream
, buffer
, bytes_to_read
, bytes_read
);
2540 ESTREAM_UNLOCK (stream
);
2550 es_write (estream_t ES__RESTRICT stream
,
2551 const void *ES__RESTRICT buffer
, size_t bytes_to_write
,
2552 size_t *ES__RESTRICT bytes_written
)
2558 ESTREAM_LOCK (stream
);
2559 err
= es_writen (stream
, buffer
, bytes_to_write
, bytes_written
);
2560 ESTREAM_UNLOCK (stream
);
2570 es_fread (void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2571 estream_t ES__RESTRICT stream
)
2578 ESTREAM_LOCK (stream
);
2579 err
= es_readn (stream
, ptr
, size
* nitems
, &bytes
);
2580 ESTREAM_UNLOCK (stream
);
2592 es_fwrite (const void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2593 estream_t ES__RESTRICT stream
)
2600 ESTREAM_LOCK (stream
);
2601 err
= es_writen (stream
, ptr
, size
* nitems
, &bytes
);
2602 ESTREAM_UNLOCK (stream
);
2614 es_fgets (char *ES__RESTRICT buffer
, int length
, estream_t ES__RESTRICT stream
)
2616 unsigned char *s
= (unsigned char*)buffer
;
2623 ESTREAM_LOCK (stream
);
2624 while (length
> 1 && (c
= es_getc_unlocked (stream
)) != EOF
&& c
!= '\n')
2629 ESTREAM_UNLOCK (stream
);
2631 if (c
== EOF
&& s
== (unsigned char*)buffer
)
2632 return NULL
; /* Nothing read. */
2634 if (c
!= EOF
&& length
> 1)
2643 es_fputs (const char *ES__RESTRICT s
, estream_t ES__RESTRICT stream
)
2648 length
= strlen (s
);
2649 ESTREAM_LOCK (stream
);
2650 err
= es_writen (stream
, s
, length
, NULL
);
2651 ESTREAM_UNLOCK (stream
);
2653 return err
? EOF
: 0;
2658 es_getline (char *ES__RESTRICT
*ES__RESTRICT lineptr
, size_t *ES__RESTRICT n
,
2659 estream_t ES__RESTRICT stream
)
2665 ESTREAM_LOCK (stream
);
2666 err
= doreadline (stream
, 0, &line
, &line_n
);
2667 ESTREAM_UNLOCK (stream
);
2673 /* Caller wants us to use his buffer. */
2675 if (*n
< (line_n
+ 1))
2677 /* Provided buffer is too small -> resize. */
2681 p
= mem_realloc (*lineptr
, line_n
+ 1);
2693 memcpy (*lineptr
, line
, line_n
+ 1);
2701 /* Caller wants new buffers. */
2708 return err
? err
: line_n
;
2713 /* Same as fgets() but if the provided buffer is too short a larger
2714 one will be allocated. This is similar to getline. A line is
2715 considered a byte stream ending in a LF.
2717 If MAX_LENGTH is not NULL, it shall point to a value with the
2718 maximum allowed allocation.
2720 Returns the length of the line. EOF is indicated by a line of
2721 length zero. A truncated line is indicated my setting the value at
2722 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2723 memory was enable or another error occurred; ERRNO is then set
2726 If a line has been truncated, the file pointer is moved forward to
2727 the end of the line so that the next read starts with the next
2728 line. Note that MAX_LENGTH must be re-initialzied in this case.
2730 The caller initially needs to provide the address of a variable,
2731 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2732 anymore with the following invocations. LENGTH_OF_BUFFER should be
2733 the address of a variable, initialized to 0, which is also
2734 maintained by this function. Thus, both paramaters should be
2735 considered the state of this function.
2737 Note: The returned buffer is allocated with enough extra space to
2738 allow the caller to append a CR,LF,Nul. The buffer should be
2739 released using es_free.
2742 es_read_line (estream_t stream
,
2743 char **addr_of_buffer
, size_t *length_of_buffer
,
2747 char *buffer
= *addr_of_buffer
;
2748 size_t length
= *length_of_buffer
;
2750 size_t maxlen
= max_length
? *max_length
: 0;
2755 /* No buffer given - allocate a new one. */
2757 buffer
= mem_alloc (length
);
2758 *addr_of_buffer
= buffer
;
2761 *length_of_buffer
= 0;
2766 *length_of_buffer
= length
;
2771 /* This should never happen. If it does, the function has been
2772 called with wrong arguments. */
2776 length
-= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2778 ESTREAM_LOCK (stream
);
2780 while ((c
= es_getc_unlocked (stream
)) != EOF
)
2782 if (nbytes
== length
)
2784 /* Enlarge the buffer. */
2785 if (maxlen
&& length
> maxlen
)
2787 /* We are beyond our limit: Skip the rest of the line. */
2788 while (c
!= '\n' && (c
=es_getc_unlocked (stream
)) != EOF
)
2790 *p
++ = '\n'; /* Always append a LF (we reserved some space). */
2793 *max_length
= 0; /* Indicate truncation. */
2794 break; /* the while loop. */
2796 length
+= 3; /* Adjust for the reserved bytes. */
2797 length
+= length
< 1024? 256 : 1024;
2798 *addr_of_buffer
= mem_realloc (buffer
, length
);
2799 if (!*addr_of_buffer
)
2801 int save_errno
= errno
;
2803 *length_of_buffer
= *max_length
= 0;
2804 ESTREAM_UNLOCK (stream
);
2808 buffer
= *addr_of_buffer
;
2809 *length_of_buffer
= length
;
2811 p
= buffer
+ nbytes
;
2818 *p
= 0; /* Make sure the line is a string. */
2819 ESTREAM_UNLOCK (stream
);
2824 /* Wrapper around free() to match the memory allocation system used
2825 by estream. Should be used for all buffers returned to the caller
2835 es_vfprintf (estream_t ES__RESTRICT stream
, const char *ES__RESTRICT format
,
2840 ESTREAM_LOCK (stream
);
2841 ret
= es_print (stream
, format
, ap
);
2842 ESTREAM_UNLOCK (stream
);
2849 es_fprintf_unlocked (estream_t ES__RESTRICT stream
,
2850 const char *ES__RESTRICT format
, ...)
2855 va_start (ap
, format
);
2856 ret
= es_print (stream
, format
, ap
);
2864 es_fprintf (estream_t ES__RESTRICT stream
,
2865 const char *ES__RESTRICT format
, ...)
2870 va_start (ap
, format
);
2871 ESTREAM_LOCK (stream
);
2872 ret
= es_print (stream
, format
, ap
);
2873 ESTREAM_UNLOCK (stream
);
2883 #ifdef HAVE_W32_SYSTEM
2885 char buffer
[MAX_PATH
+9+12+1];
2888 int pid
= GetCurrentProcessId ();
2892 n
= GetTempPath (MAX_PATH
+1, buffer
);
2893 if (!n
|| n
> MAX_PATH
|| strlen (buffer
) > MAX_PATH
)
2898 p
= buffer
+ strlen (buffer
);
2899 strcpy (p
, "_estream");
2901 /* We try to create the directory but don't care about an error as
2902 it may already exist and the CreateFile would throw an error
2904 CreateDirectory (buffer
, NULL
);
2907 for (attempts
=0; attempts
< 10; attempts
++)
2910 value
= (GetTickCount () ^ ((pid
<<16) & 0xffff0000));
2911 for (i
=0; i
< 8; i
++)
2913 *p
++ = tohex (((value
>> 28) & 0x0f));
2917 file
= CreateFile (buffer
,
2918 GENERIC_READ
| GENERIC_WRITE
,
2922 FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_DELETE_ON_CLOSE
,
2924 if (file
!= INVALID_HANDLE_VALUE
)
2926 int fd
= _open_osfhandle ((long)file
, 0);
2934 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
2938 #else /*!HAVE_W32_SYSTEM*/
2950 fp_fd
= fileno (fp
);
2959 #endif /*!HAVE_W32_SYSTEM*/
2965 unsigned int modeflags
;
2974 modeflags
= O_RDWR
| O_TRUNC
| O_CREAT
;
2984 err
= es_func_fd_create (&cookie
, fd
, modeflags
, 0);
2989 err
= es_create (&stream
, cookie
, fd
, estream_functions_fd
, modeflags
);
2996 es_func_fd_destroy (cookie
);
3007 es_setvbuf (estream_t ES__RESTRICT stream
,
3008 char *ES__RESTRICT buf
, int type
, size_t size
)
3012 if (((type
== _IOFBF
) || (type
== _IOLBF
) || (type
== _IONBF
))
3013 && (! ((! size
) && (type
!= _IONBF
))))
3015 ESTREAM_LOCK (stream
);
3016 err
= es_set_buffering (stream
, buf
, type
, size
);
3017 ESTREAM_UNLOCK (stream
);
3030 es_setbuf (estream_t ES__RESTRICT stream
, char *ES__RESTRICT buf
)
3032 ESTREAM_LOCK (stream
);
3033 es_set_buffering (stream
, buf
, buf
? _IOFBF
: _IONBF
, BUFSIZ
);
3034 ESTREAM_UNLOCK (stream
);
3038 es_opaque_set (estream_t stream
, void *opaque
)
3040 ESTREAM_LOCK (stream
);
3041 es_opaque_ctrl (stream
, opaque
, NULL
);
3042 ESTREAM_UNLOCK (stream
);
3047 es_opaque_get (estream_t stream
)
3051 ESTREAM_LOCK (stream
);
3052 es_opaque_ctrl (stream
, NULL
, &opaque
);
3053 ESTREAM_UNLOCK (stream
);
3058 /* Print a BUFFER to STREAM while replacing all control characters and
3059 the characters in DELIMITERS by standard C escape sequences.
3060 Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
3061 the number of bytes actually written are stored at this
3064 es_write_sanitized (estream_t ES__RESTRICT stream
,
3065 const void * ES__RESTRICT buffer
, size_t length
,
3066 const char * delimiters
,
3067 size_t * ES__RESTRICT bytes_written
)
3069 const unsigned char *p
= buffer
;
3073 ESTREAM_LOCK (stream
);
3074 for (; length
; length
--, p
++, count
++)
3077 || (*p
>= 0x7f && *p
< 0xa0)
3079 && (strchr (delimiters
, *p
) || *p
== '\\')))
3081 es_putc_unlocked ('\\', stream
);
3085 es_putc_unlocked ('n', stream
);
3088 else if (*p
== '\r')
3090 es_putc_unlocked ('r', stream
);
3093 else if (*p
== '\f')
3095 es_putc_unlocked ('f', stream
);
3098 else if (*p
== '\v')
3100 es_putc_unlocked ('v', stream
);
3103 else if (*p
== '\b')
3105 es_putc_unlocked ('b', stream
);
3110 es_putc_unlocked('0', stream
);
3115 es_fprintf_unlocked (stream
, "x%02x", *p
);
3121 es_putc_unlocked (*p
, stream
);
3127 *bytes_written
= count
;
3128 ret
= es_ferror_unlocked (stream
)? -1 : 0;
3129 ESTREAM_UNLOCK (stream
);
3135 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3136 RESERVED must be 0. Returns 0 on success or -1 on error. If
3137 BYTES_WRITTEN is not NULL the number of bytes actually written are
3138 stored at this address. */
3140 es_write_hexstring (estream_t ES__RESTRICT stream
,
3141 const void *ES__RESTRICT buffer
, size_t length
,
3142 int reserved
, size_t *ES__RESTRICT bytes_written
)
3145 const unsigned char *s
;
3148 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3153 ESTREAM_LOCK (stream
);
3155 for (s
= buffer
; length
; s
++, length
--)
3157 es_putc_unlocked ( tohex ((*s
>>4)&15), stream
);
3158 es_putc_unlocked ( tohex (*s
&15), stream
);
3163 *bytes_written
= count
;
3164 ret
= es_ferror_unlocked (stream
)? -1 : 0;
3166 ESTREAM_UNLOCK (stream
);
3175 #ifdef GNUPG_MAJOR_VERSION
3176 /* Special estream function to print an UTF8 string in the native
3177 encoding. The interface is the same as es_write_sanitized, however
3178 only one delimiter may be supported.
3180 THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3182 es_write_sanitized_utf8_buffer (estream_t stream
,
3183 const void *buffer
, size_t length
,
3184 const char *delimiters
, size_t *bytes_written
)
3186 const char *p
= buffer
;
3189 /* We can handle plain ascii simpler, so check for it first. */
3190 for (i
=0; i
< length
; i
++ )
3192 if ( (p
[i
] & 0x80) )
3197 int delim
= delimiters
? *delimiters
: 0;
3201 /*(utf8 conversion already does the control character quoting). */
3202 buf
= utf8_to_native (p
, length
, delim
);
3204 *bytes_written
= strlen (buf
);
3205 ret
= es_fputs (buf
, stream
);
3210 return es_write_sanitized (stream
, p
, length
, delimiters
, bytes_written
);
3212 #endif /*GNUPG_MAJOR_VERSION*/