1 /* estream.c - Extended Stream I/O Library
2 * Copyright (C) 2004, 2005, 2006, 2007 g10 Code GmbH
4 * This file is part of Libestream.
6 * Libestream is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License,
9 * or (at your option) any later version.
11 * Libestream is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Libestream; if not, see <http://www.gnu.org/licenses/>.
20 #ifdef USE_ESTREAM_SUPPORT_H
21 # include <estream-support.h>
28 #if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
29 # define HAVE_W32_SYSTEM 1
32 #include <sys/types.h>
44 #ifdef HAVE_W32_SYSTEM
48 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */
57 /* This is for the special hack to use estream.c in GnuPG. */
58 #ifdef GNUPG_MAJOR_VERSION
59 # include "../common/util.h"
63 int mkstemp (char *template);
67 void *memrchr (const void *block
, int c
, size_t size
);
71 #include <estream-printf.h>
79 /* Generally used types. */
81 typedef void *(*func_realloc_t
) (void *mem
, size_t size
);
82 typedef void (*func_free_t
) (void *mem
);
87 /* Buffer management layer. */
89 #define BUFFER_BLOCK_SIZE BUFSIZ
90 #define BUFFER_UNREAD_SIZE 16
96 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
104 typedef pth_mutex_t estream_mutex_t
;
105 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
106 # define ESTREAM_MUTEX_LOCK(mutex) \
107 pth_mutex_acquire (&(mutex), 0, NULL)
108 # define ESTREAM_MUTEX_UNLOCK(mutex) \
109 pth_mutex_release (&(mutex))
110 # define ESTREAM_MUTEX_TRYLOCK(mutex) \
111 ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
112 # define ESTREAM_MUTEX_INITIALIZE(mutex) \
113 pth_mutex_init (&(mutex))
116 typedef void *estream_mutex_t
;
119 dummy_mutex_call_void (estream_mutex_t mutex
)
125 dummy_mutex_call_int (estream_mutex_t mutex
)
131 # define ESTREAM_MUTEX_INITIALIZER NULL
132 # define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex))
133 # define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex))
134 # define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex))
135 # define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex))
138 /* Primitive system I/O. */
141 # define ESTREAM_SYS_READ pth_read
142 # define ESTREAM_SYS_WRITE pth_write
144 # define ESTREAM_SYS_READ read
145 # define ESTREAM_SYS_WRITE write
148 /* Misc definitions. */
150 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
152 /* An internal stream object. */
154 struct estream_internal
156 unsigned char buffer
[BUFFER_BLOCK_SIZE
];
157 unsigned char unread_buffer
[BUFFER_UNREAD_SIZE
];
158 estream_mutex_t lock
; /* Lock. */
159 void *cookie
; /* Cookie. */
160 void *opaque
; /* Opaque data. */
161 unsigned int modeflags
; /* Flags for the backend. */
163 es_cookie_read_function_t func_read
;
164 es_cookie_write_function_t func_write
;
165 es_cookie_seek_function_t func_seek
;
166 es_cookie_close_function_t func_close
;
174 unsigned int deallocate_buffer
: 1;
175 unsigned int print_err
: 1; /* Error in print_fun_writer. */
176 int print_errno
; /* Errno from print_fun_writer. */
177 size_t print_ntotal
; /* Bytes written from in print_fun_writer. */
178 FILE *print_fp
; /* Stdio stream used by print_fun_writer. */
182 typedef struct estream_internal
*estream_internal_t
;
184 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
185 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
186 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
190 typedef struct estream_list
*estream_list_t
;
196 estream_list_t
*prev_cdr
;
199 static estream_list_t estream_list
;
200 static estream_mutex_t estream_list_lock
;
202 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
203 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
206 # define EOPNOTSUPP ENOSYS
214 /* Calculate array dimension. */
216 #define DIM(array) (sizeof (array) / sizeof (*array))
219 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
222 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
224 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
227 tmp_variable = expression; \
228 if ((! variable) && tmp_variable) \
229 variable = tmp_variable; \
234 /* Malloc wrappers to overcvome problems on some older OSes. */
244 mem_realloc (void *p
, size_t n
)
247 return mem_alloc (n
);
248 return realloc (p
, n
);
264 /* Add STREAM to the list of registered stream objects. */
266 es_list_add (estream_t stream
)
268 estream_list_t list_obj
;
271 list_obj
= mem_alloc (sizeof (*list_obj
));
277 list_obj
->car
= stream
;
278 list_obj
->cdr
= estream_list
;
279 list_obj
->prev_cdr
= &estream_list
;
281 estream_list
->prev_cdr
= &list_obj
->cdr
;
282 estream_list
= list_obj
;
290 /* Remove STREAM from the list of registered stream objects. */
292 es_list_remove (estream_t stream
)
294 estream_list_t list_obj
;
297 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
298 if (list_obj
->car
== stream
)
300 *list_obj
->prev_cdr
= list_obj
->cdr
;
302 list_obj
->cdr
->prev_cdr
= list_obj
->prev_cdr
;
309 /* Type of an stream-iterator-function. */
310 typedef int (*estream_iterator_t
) (estream_t stream
);
312 /* Iterate over list of registered streams, calling ITERATOR for each
315 es_list_iterate (estream_iterator_t iterator
)
317 estream_list_t list_obj
;
321 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
322 ret
|= (*iterator
) (list_obj
->car
);
338 static int initialized
;
342 if (!pth_init () && errno
!= EPERM
)
344 if (pth_mutex_init (&estream_list_lock
))
357 /* Implementation of Memory I/O. */
359 /* Cookie for memory objects. */
360 typedef struct estream_cookie_mem
362 unsigned int modeflags
; /* Open flags. */
363 unsigned char *memory
; /* Allocated data buffer. */
364 size_t memory_size
; /* Allocated size of memory. */
365 size_t memory_limit
; /* Maximum allowed allocation size or
367 size_t offset
; /* Current offset in MEMORY. */
368 size_t data_len
; /* Length of data in MEMORY. */
369 size_t block_size
; /* Block size. */
371 unsigned int grow
: 1; /* MEMORY is allowed to grow. */
373 func_realloc_t func_realloc
;
374 func_free_t func_free
;
375 } *estream_cookie_mem_t
;
378 /* Create function for memory objects. */
380 es_func_mem_create (void *ES__RESTRICT
*ES__RESTRICT cookie
,
381 unsigned char *ES__RESTRICT data
, size_t data_n
,
383 size_t block_size
, unsigned int grow
,
384 func_realloc_t func_realloc
, func_free_t func_free
,
385 unsigned int modeflags
,
388 estream_cookie_mem_t mem_cookie
;
391 mem_cookie
= mem_alloc (sizeof (*mem_cookie
));
396 mem_cookie
->modeflags
= modeflags
;
397 mem_cookie
->memory
= data
;
398 mem_cookie
->memory_size
= data_n
;
399 mem_cookie
->memory_limit
= memory_limit
;
400 mem_cookie
->offset
= 0;
401 mem_cookie
->data_len
= data_len
;
402 mem_cookie
->block_size
= block_size
;
403 mem_cookie
->flags
.grow
= !!grow
;
404 mem_cookie
->func_realloc
= func_realloc
? func_realloc
: mem_realloc
;
405 mem_cookie
->func_free
= func_free
? func_free
: mem_free
;
406 *cookie
= mem_cookie
;
414 /* Read function for memory objects. */
416 es_func_mem_read (void *cookie
, void *buffer
, size_t size
)
418 estream_cookie_mem_t mem_cookie
= cookie
;
421 if (size
> mem_cookie
->data_len
- mem_cookie
->offset
)
422 size
= mem_cookie
->data_len
- mem_cookie
->offset
;
426 memcpy (buffer
, mem_cookie
->memory
+ mem_cookie
->offset
, size
);
427 mem_cookie
->offset
+= size
;
435 /* Write function for memory objects. */
437 es_func_mem_write (void *cookie
, const void *buffer
, size_t size
)
439 estream_cookie_mem_t mem_cookie
= cookie
;
443 return 0; /* A flush is a NOP for memory objects. */
445 if (mem_cookie
->modeflags
& O_APPEND
)
447 /* Append to data. */
448 mem_cookie
->offset
= mem_cookie
->data_len
;
451 if (!mem_cookie
->flags
.grow
)
453 /* We are not alloew to grow, thus limit the size to the left
454 space. FIXME: Does the grow flag an its semtics make sense
456 if (size
> mem_cookie
->memory_size
- mem_cookie
->offset
)
457 size
= mem_cookie
->memory_size
- mem_cookie
->offset
;
460 if (size
> (mem_cookie
->memory_size
- mem_cookie
->offset
))
462 unsigned char *newbuf
;
465 newsize
= mem_cookie
->memory_size
+ mem_cookie
->block_size
;
467 newsize
= mem_cookie
->offset
+ size
;
468 if (newsize
< mem_cookie
->offset
)
473 newsize
+= mem_cookie
->block_size
- 1;
474 if (newsize
< mem_cookie
->offset
)
479 newsize
/= mem_cookie
->block_size
;
480 newsize
*= mem_cookie
->block_size
;
482 if (mem_cookie
->memory_limit
&& newsize
> mem_cookie
->memory_limit
)
488 newbuf
= mem_cookie
->func_realloc (mem_cookie
->memory
, newsize
);
492 mem_cookie
->memory
= newbuf
;
493 mem_cookie
->memory_size
= newsize
;
495 assert (!(size
> (mem_cookie
->memory_size
- mem_cookie
->offset
)));
498 memcpy (mem_cookie
->memory
+ mem_cookie
->offset
, buffer
, size
);
499 if (mem_cookie
->offset
+ size
> mem_cookie
->data_len
)
500 mem_cookie
->data_len
= mem_cookie
->offset
+ size
;
501 mem_cookie
->offset
+= size
;
508 /* Seek function for memory objects. */
510 es_func_mem_seek (void *cookie
, off_t
*offset
, int whence
)
512 estream_cookie_mem_t mem_cookie
= cookie
;
522 pos_new
= mem_cookie
->offset
+= *offset
;
526 pos_new
= mem_cookie
->data_len
+= *offset
;
534 if (pos_new
> mem_cookie
->memory_size
)
539 if (!mem_cookie
->flags
.grow
)
546 newsize
= pos_new
+ mem_cookie
->block_size
- 1;
547 if (newsize
< pos_new
)
552 newsize
/= mem_cookie
->block_size
;
553 newsize
*= mem_cookie
->block_size
;
554 if (mem_cookie
->memory_limit
&& newsize
> mem_cookie
->memory_limit
)
560 newbuf
= mem_cookie
->func_realloc (mem_cookie
->memory
, newsize
);
564 mem_cookie
->memory
= newbuf
;
565 mem_cookie
->memory_size
= newsize
;
568 if (pos_new
> mem_cookie
->data_len
)
570 /* Fill spare space with zeroes. */
571 memset (mem_cookie
->memory
+ mem_cookie
->data_len
,
572 0, pos_new
- mem_cookie
->data_len
);
573 mem_cookie
->data_len
= pos_new
;
576 mem_cookie
->offset
= pos_new
;
583 /* Destroy function for memory objects. */
585 es_func_mem_destroy (void *cookie
)
587 estream_cookie_mem_t mem_cookie
= cookie
;
591 mem_cookie
->func_free (mem_cookie
->memory
);
592 mem_free (mem_cookie
);
598 static es_cookie_io_functions_t estream_functions_mem
=
608 /* Implementation of fd I/O. */
610 /* Cookie for fd objects. */
611 typedef struct estream_cookie_fd
613 int fd
; /* The file descriptor we are using for actual output. */
614 int no_close
; /* If set we won't close the file descriptor. */
615 } *estream_cookie_fd_t
;
617 /* Create function for fd objects. */
619 es_func_fd_create (void **cookie
, int fd
, unsigned int modeflags
, int no_close
)
621 estream_cookie_fd_t fd_cookie
;
624 fd_cookie
= mem_alloc (sizeof (*fd_cookie
));
629 #ifdef HAVE_DOSISH_SYSTEM
630 /* Make sure it is in binary mode if requested. */
631 if ( (modeflags
& O_BINARY
) )
632 setmode (fd
, O_BINARY
);
637 fd_cookie
->no_close
= no_close
;
645 /* Read function for fd objects. */
647 es_func_fd_read (void *cookie
, void *buffer
, size_t size
)
650 estream_cookie_fd_t file_cookie
= cookie
;
654 bytes_read
= ESTREAM_SYS_READ (file_cookie
->fd
, buffer
, size
);
655 while (bytes_read
== -1 && errno
== EINTR
);
660 /* Write function for fd objects. */
662 es_func_fd_write (void *cookie
, const void *buffer
, size_t size
)
665 estream_cookie_fd_t file_cookie
= cookie
;
666 ssize_t bytes_written
;
669 bytes_written
= ESTREAM_SYS_WRITE (file_cookie
->fd
, buffer
, size
);
670 while (bytes_written
== -1 && errno
== EINTR
);
672 return bytes_written
;
675 /* Seek function for fd objects. */
677 es_func_fd_seek (void *cookie
, off_t
*offset
, int whence
)
679 estream_cookie_fd_t file_cookie
= cookie
;
683 offset_new
= lseek (file_cookie
->fd
, *offset
, whence
);
684 if (offset_new
== -1)
688 *offset
= offset_new
;
695 /* Destroy function for fd objects. */
697 es_func_fd_destroy (void *cookie
)
699 estream_cookie_fd_t fd_cookie
= cookie
;
704 err
= fd_cookie
->no_close
? 0 : close (fd_cookie
->fd
);
705 mem_free (fd_cookie
);
714 static es_cookie_io_functions_t estream_functions_fd
=
725 /* Implementation of FILE* I/O. */
727 /* Cookie for fp objects. */
728 typedef struct estream_cookie_fp
730 FILE *fp
; /* The file pointer we are using for actual output. */
731 int no_close
; /* If set we won't close the file pointer. */
732 } *estream_cookie_fp_t
;
734 /* Create function for fd objects. */
736 es_func_fp_create (void **cookie
, FILE *fp
,
737 unsigned int modeflags
, int no_close
)
739 estream_cookie_fp_t fp_cookie
;
742 fp_cookie
= mem_alloc (sizeof *fp_cookie
);
747 #ifdef HAVE_DOSISH_SYSTEM
748 /* Make sure it is in binary mode if requested. */
749 if ( (modeflags
& O_BINARY
) )
750 setmode (fileno (fp
), O_BINARY
);
755 fp_cookie
->no_close
= no_close
;
763 /* Read function for FILE* objects. */
765 es_func_fp_read (void *cookie
, void *buffer
, size_t size
)
768 estream_cookie_fp_t file_cookie
= cookie
;
771 bytes_read
= fread (buffer
, 1, size
, file_cookie
->fp
);
772 if (!bytes_read
&& ferror (file_cookie
->fp
))
777 /* Write function for FILE* objects. */
779 es_func_fp_write (void *cookie
, const void *buffer
, size_t size
)
782 estream_cookie_fp_t file_cookie
= cookie
;
783 size_t bytes_written
;
785 bytes_written
= fwrite (buffer
, 1, size
, file_cookie
->fp
);
786 if (bytes_written
!= size
)
788 return bytes_written
;
791 /* Seek function for FILE* objects. */
793 es_func_fp_seek (void *cookie
, off_t
*offset
, int whence
)
795 estream_cookie_fp_t file_cookie
= cookie
;
798 if ( fseek (file_cookie
->fp
, (long int)*offset
, whence
) )
800 fprintf (stderr
, "\nfseek failed: errno=%d (%s)\n", errno
,strerror (errno
));
804 offset_new
= ftell (file_cookie
->fp
);
805 if (offset_new
== -1)
807 fprintf (stderr
, "\nftell failed: errno=%d (%s)\n", errno
,strerror (errno
));
810 *offset
= offset_new
;
814 /* Destroy function for fd objects. */
816 es_func_fp_destroy (void *cookie
)
818 estream_cookie_fp_t fp_cookie
= cookie
;
823 fflush (fp_cookie
->fp
);
824 err
= fp_cookie
->no_close
? 0 : fclose (fp_cookie
->fp
);
825 mem_free (fp_cookie
);
834 static es_cookie_io_functions_t estream_functions_fp
=
845 /* Implementation of file I/O. */
847 /* Create function for file objects. */
849 es_func_file_create (void **cookie
, int *filedes
,
850 const char *path
, unsigned int modeflags
)
852 estream_cookie_fd_t file_cookie
;
859 file_cookie
= mem_alloc (sizeof (*file_cookie
));
866 fd
= open (path
, modeflags
, ES_DEFAULT_OPEN_MODE
);
872 #ifdef HAVE_DOSISH_SYSTEM
873 /* Make sure it is in binary mode if requested. */
874 if ( (modeflags
& O_BINARY
) )
875 setmode (fd
, O_BINARY
);
878 file_cookie
->fd
= fd
;
879 file_cookie
->no_close
= 0;
880 *cookie
= file_cookie
;
886 mem_free (file_cookie
);
891 static es_cookie_io_functions_t estream_functions_file
=
901 /* Stream primitives. */
904 es_convert_mode (const char *mode
, unsigned int *modeflags
)
907 /* FIXME: We need to allow all mode flags permutations. */
912 } mode_flags
[] = { { "r",
915 O_RDONLY
| O_BINARY
},
917 O_WRONLY
| O_TRUNC
| O_CREAT
},
919 O_WRONLY
| O_TRUNC
| O_CREAT
| O_BINARY
},
921 O_WRONLY
| O_APPEND
| O_CREAT
},
923 O_WRONLY
| O_APPEND
| O_CREAT
| O_BINARY
},
929 O_RDONLY
| O_WRONLY
| O_BINARY
},
931 O_RDWR
| O_TRUNC
| O_CREAT
},
933 O_RDWR
| O_TRUNC
| O_CREAT
| O_BINARY
},
935 O_RDWR
| O_TRUNC
| O_CREAT
| O_BINARY
},
937 O_RDWR
| O_CREAT
| O_APPEND
},
939 O_RDWR
| O_CREAT
| O_APPEND
| O_BINARY
},
941 O_RDWR
| O_CREAT
| O_APPEND
| O_BINARY
}
946 for (i
= 0; i
< DIM (mode_flags
); i
++)
947 if (! strcmp (mode_flags
[i
].mode
, mode
))
949 if (i
== DIM (mode_flags
))
957 *modeflags
= mode_flags
[i
].flags
;
966 * Low level stream functionality.
970 es_fill (estream_t stream
)
972 size_t bytes_read
= 0;
975 if (!stream
->intern
->func_read
)
982 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
985 ret
= (*func_read
) (stream
->intern
->cookie
,
986 stream
->buffer
, stream
->buffer_size
);
1000 stream
->intern
->indicators
.err
= 1;
1001 else if (!bytes_read
)
1002 stream
->intern
->indicators
.eof
= 1;
1004 stream
->intern
->offset
+= stream
->data_len
;
1005 stream
->data_len
= bytes_read
;
1006 stream
->data_offset
= 0;
1012 es_flush (estream_t stream
)
1014 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1017 assert (stream
->flags
.writing
);
1019 if (stream
->data_offset
)
1021 size_t bytes_written
;
1022 size_t data_flushed
;
1031 /* Note: to prevent an endless loop caused by user-provided
1032 write-functions that pretend to have written more bytes than
1033 they were asked to write, we have to check for
1034 "(stream->data_offset - data_flushed) > 0" instead of
1035 "stream->data_offset - data_flushed". */
1040 while ((((ssize_t
) (stream
->data_offset
- data_flushed
)) > 0) && (! err
))
1042 ret
= (*func_write
) (stream
->intern
->cookie
,
1043 stream
->buffer
+ data_flushed
,
1044 stream
->data_offset
- data_flushed
);
1051 bytes_written
= ret
;
1053 data_flushed
+= bytes_written
;
1058 stream
->data_flushed
+= data_flushed
;
1059 if (stream
->data_offset
== data_flushed
)
1061 stream
->intern
->offset
+= stream
->data_offset
;
1062 stream
->data_offset
= 0;
1063 stream
->data_flushed
= 0;
1065 /* Propagate flush event. */
1066 (*func_write
) (stream
->intern
->cookie
, NULL
, 0);
1075 stream
->intern
->indicators
.err
= 1;
1080 /* Discard buffered data for STREAM. */
1082 es_empty (estream_t stream
)
1084 assert (!stream
->flags
.writing
);
1085 stream
->data_len
= 0;
1086 stream
->data_offset
= 0;
1087 stream
->unread_data_len
= 0;
1090 /* Initialize STREAM. */
1092 es_initialize (estream_t stream
,
1093 void *cookie
, int fd
, es_cookie_io_functions_t functions
,
1094 unsigned int modeflags
)
1096 stream
->intern
->cookie
= cookie
;
1097 stream
->intern
->opaque
= NULL
;
1098 stream
->intern
->offset
= 0;
1099 stream
->intern
->func_read
= functions
.func_read
;
1100 stream
->intern
->func_write
= functions
.func_write
;
1101 stream
->intern
->func_seek
= functions
.func_seek
;
1102 stream
->intern
->func_close
= functions
.func_close
;
1103 stream
->intern
->strategy
= _IOFBF
;
1104 stream
->intern
->fd
= fd
;
1105 stream
->intern
->print_err
= 0;
1106 stream
->intern
->print_errno
= 0;
1107 stream
->intern
->print_ntotal
= 0;
1108 stream
->intern
->print_fp
= NULL
;
1109 stream
->intern
->indicators
.err
= 0;
1110 stream
->intern
->indicators
.eof
= 0;
1111 stream
->intern
->deallocate_buffer
= 0;
1113 stream
->data_len
= 0;
1114 stream
->data_offset
= 0;
1115 stream
->data_flushed
= 0;
1116 stream
->unread_data_len
= 0;
1117 /* Depending on the modeflags we set whether we start in writing or
1118 reading mode. This is required in case we are working on a
1119 wronly stream which is not seeekable (like stdout). Without this
1120 pre-initialization we would do a seek at the first write call and
1121 as this will fail no utput will be delivered. */
1122 if ((modeflags
& O_WRONLY
) || (modeflags
& O_RDWR
) )
1123 stream
->flags
.writing
= 1;
1125 stream
->flags
.writing
= 0;
1128 /* Deinitialize STREAM. */
1130 es_deinitialize (estream_t stream
)
1132 es_cookie_close_function_t func_close
;
1135 if (stream
->intern
->print_fp
)
1137 int save_errno
= errno
;
1138 fclose (stream
->intern
->print_fp
);
1139 stream
->intern
->print_fp
= NULL
;
1143 func_close
= stream
->intern
->func_close
;
1146 if (stream
->flags
.writing
)
1147 SET_UNLESS_NONZERO (err
, tmp_err
, es_flush (stream
));
1149 SET_UNLESS_NONZERO (err
, tmp_err
, (*func_close
) (stream
->intern
->cookie
));
1155 /* Create a new stream object, initialize it. */
1157 es_create (estream_t
*stream
, void *cookie
, int fd
,
1158 es_cookie_io_functions_t functions
, unsigned int modeflags
)
1160 estream_internal_t stream_internal_new
;
1161 estream_t stream_new
;
1165 stream_internal_new
= NULL
;
1167 stream_new
= mem_alloc (sizeof (*stream_new
));
1174 stream_internal_new
= mem_alloc (sizeof (*stream_internal_new
));
1175 if (! stream_internal_new
)
1181 stream_new
->buffer
= stream_internal_new
->buffer
;
1182 stream_new
->buffer_size
= sizeof (stream_internal_new
->buffer
);
1183 stream_new
->unread_buffer
= stream_internal_new
->unread_buffer
;
1184 stream_new
->unread_buffer_size
= sizeof (stream_internal_new
->unread_buffer
);
1185 stream_new
->intern
= stream_internal_new
;
1187 ESTREAM_MUTEX_INITIALIZE (stream_new
->intern
->lock
);
1188 es_initialize (stream_new
, cookie
, fd
, functions
, modeflags
);
1190 err
= es_list_add (stream_new
);
1194 *stream
= stream_new
;
1202 es_deinitialize (stream_new
);
1203 mem_free (stream_new
);
1210 /* Deinitialize a stream object and destroy it. */
1212 es_destroy (estream_t stream
)
1218 es_list_remove (stream
);
1219 err
= es_deinitialize (stream
);
1220 mem_free (stream
->intern
);
1227 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1228 unbuffered-mode, storing the amount of bytes read in
1231 es_read_nbf (estream_t ES__RESTRICT stream
,
1232 unsigned char *ES__RESTRICT buffer
,
1233 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1235 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
1243 while (bytes_to_read
- data_read
)
1245 ret
= (*func_read
) (stream
->intern
->cookie
,
1246 buffer
+ data_read
, bytes_to_read
- data_read
);
1258 stream
->intern
->offset
+= data_read
;
1259 *bytes_read
= data_read
;
1264 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1265 fully-buffered-mode, storing the amount of bytes read in
1268 es_read_fbf (estream_t ES__RESTRICT stream
,
1269 unsigned char *ES__RESTRICT buffer
,
1270 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1272 size_t data_available
;
1273 size_t data_to_read
;
1280 while ((bytes_to_read
- data_read
) && (! err
))
1282 if (stream
->data_offset
== stream
->data_len
)
1284 /* Nothing more to read in current container, try to
1285 fill container with new data. */
1286 err
= es_fill (stream
);
1288 if (! stream
->data_len
)
1289 /* Filling did not result in any data read. */
1295 /* Filling resulted in some new data. */
1297 data_to_read
= bytes_to_read
- data_read
;
1298 data_available
= stream
->data_len
- stream
->data_offset
;
1299 if (data_to_read
> data_available
)
1300 data_to_read
= data_available
;
1302 memcpy (buffer
+ data_read
,
1303 stream
->buffer
+ stream
->data_offset
, data_to_read
);
1304 stream
->data_offset
+= data_to_read
;
1305 data_read
+= data_to_read
;
1309 *bytes_read
= data_read
;
1314 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1315 line-buffered-mode, storing the amount of bytes read in
1318 es_read_lbf (estream_t ES__RESTRICT stream
,
1319 unsigned char *ES__RESTRICT buffer
,
1320 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1324 err
= es_read_fbf (stream
, buffer
, bytes_to_read
, bytes_read
);
1329 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1330 *the amount of bytes read in BYTES_READ. */
1332 es_readn (estream_t ES__RESTRICT stream
,
1333 void *ES__RESTRICT buffer_arg
,
1334 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1336 unsigned char *buffer
= (unsigned char *)buffer_arg
;
1337 size_t data_read_unread
, data_read
;
1340 data_read_unread
= 0;
1344 if (stream
->flags
.writing
)
1346 /* Switching to reading mode -> flush output. */
1347 err
= es_flush (stream
);
1350 stream
->flags
.writing
= 0;
1353 /* Read unread data first. */
1354 while ((bytes_to_read
- data_read_unread
) && stream
->unread_data_len
)
1356 buffer
[data_read_unread
]
1357 = stream
->unread_buffer
[stream
->unread_data_len
- 1];
1358 stream
->unread_data_len
--;
1362 switch (stream
->intern
->strategy
)
1365 err
= es_read_nbf (stream
,
1366 buffer
+ data_read_unread
,
1367 bytes_to_read
- data_read_unread
, &data_read
);
1370 err
= es_read_lbf (stream
,
1371 buffer
+ data_read_unread
,
1372 bytes_to_read
- data_read_unread
, &data_read
);
1375 err
= es_read_fbf (stream
,
1376 buffer
+ data_read_unread
,
1377 bytes_to_read
- data_read_unread
, &data_read
);
1384 *bytes_read
= data_read_unread
+ data_read
;
1389 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1390 amount of bytes succesfully unread in *BYTES_UNREAD. */
1392 es_unreadn (estream_t ES__RESTRICT stream
,
1393 const unsigned char *ES__RESTRICT data
, size_t data_n
,
1394 size_t *ES__RESTRICT bytes_unread
)
1398 space_left
= stream
->unread_buffer_size
- stream
->unread_data_len
;
1400 if (data_n
> space_left
)
1401 data_n
= space_left
;
1406 memcpy (stream
->unread_buffer
+ stream
->unread_data_len
, data
, data_n
);
1407 stream
->unread_data_len
+= data_n
;
1408 stream
->intern
->indicators
.eof
= 0;
1413 *bytes_unread
= data_n
;
1416 /* Seek in STREAM. */
1418 es_seek (estream_t ES__RESTRICT stream
, off_t offset
, int whence
,
1419 off_t
*ES__RESTRICT offset_new
)
1421 es_cookie_seek_function_t func_seek
= stream
->intern
->func_seek
;
1432 if (stream
->flags
.writing
)
1434 /* Flush data first in order to prevent flushing it to the wrong
1436 err
= es_flush (stream
);
1439 stream
->flags
.writing
= 0;
1443 if (whence
== SEEK_CUR
)
1445 off
= off
- stream
->data_len
+ stream
->data_offset
;
1446 off
-= stream
->unread_data_len
;
1449 ret
= (*func_seek
) (stream
->intern
->cookie
, &off
, whence
);
1462 stream
->intern
->indicators
.eof
= 0;
1463 stream
->intern
->offset
= off
;
1468 stream
->intern
->indicators
.err
= 1;
1473 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1474 unbuffered-mode, storing the amount of bytes written in
1477 es_write_nbf (estream_t ES__RESTRICT stream
,
1478 const unsigned char *ES__RESTRICT buffer
,
1479 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1481 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1482 size_t data_written
;
1486 if (bytes_to_write
&& (! func_write
))
1495 while (bytes_to_write
- data_written
)
1497 ret
= (*func_write
) (stream
->intern
->cookie
,
1498 buffer
+ data_written
,
1499 bytes_to_write
- data_written
);
1506 data_written
+= ret
;
1509 stream
->intern
->offset
+= data_written
;
1510 *bytes_written
= data_written
;
1517 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1518 fully-buffered-mode, storing the amount of bytes written in
1521 es_write_fbf (estream_t ES__RESTRICT stream
,
1522 const unsigned char *ES__RESTRICT buffer
,
1523 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1525 size_t space_available
;
1526 size_t data_to_write
;
1527 size_t data_written
;
1533 while ((bytes_to_write
- data_written
) && (! err
))
1535 if (stream
->data_offset
== stream
->buffer_size
)
1536 /* Container full, flush buffer. */
1537 err
= es_flush (stream
);
1541 /* Flushing resulted in empty container. */
1543 data_to_write
= bytes_to_write
- data_written
;
1544 space_available
= stream
->buffer_size
- stream
->data_offset
;
1545 if (data_to_write
> space_available
)
1546 data_to_write
= space_available
;
1548 memcpy (stream
->buffer
+ stream
->data_offset
,
1549 buffer
+ data_written
, data_to_write
);
1550 stream
->data_offset
+= data_to_write
;
1551 data_written
+= data_to_write
;
1555 *bytes_written
= data_written
;
1561 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1562 line-buffered-mode, storing the amount of bytes written in
1565 es_write_lbf (estream_t ES__RESTRICT stream
,
1566 const unsigned char *ES__RESTRICT buffer
,
1567 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1569 size_t data_flushed
= 0;
1570 size_t data_buffered
= 0;
1574 nlp
= memrchr (buffer
, '\n', bytes_to_write
);
1577 /* Found a newline, directly write up to (including) this
1579 err
= es_flush (stream
);
1581 err
= es_write_nbf (stream
, buffer
, nlp
- buffer
+ 1, &data_flushed
);
1586 /* Write remaining data fully buffered. */
1587 err
= es_write_fbf (stream
, buffer
+ data_flushed
,
1588 bytes_to_write
- data_flushed
, &data_buffered
);
1591 *bytes_written
= data_flushed
+ data_buffered
;
1596 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1597 amount of bytes written in BYTES_WRITTEN. */
1599 es_writen (estream_t ES__RESTRICT stream
,
1600 const void *ES__RESTRICT buffer
,
1601 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1603 size_t data_written
;
1609 if (!stream
->flags
.writing
)
1611 /* Switching to writing mode -> discard input data and seek to
1612 position at which reading has stopped. We can do this only
1613 if a seek function has been registered. */
1614 if (stream
->intern
->func_seek
)
1616 err
= es_seek (stream
, 0, SEEK_CUR
, NULL
);
1619 if (errno
== ESPIPE
)
1627 switch (stream
->intern
->strategy
)
1630 err
= es_write_nbf (stream
, buffer
, bytes_to_write
, &data_written
);
1634 err
= es_write_lbf (stream
, buffer
, bytes_to_write
, &data_written
);
1638 err
= es_write_fbf (stream
, buffer
, bytes_to_write
, &data_written
);
1645 *bytes_written
= data_written
;
1647 if (!stream
->flags
.writing
)
1648 stream
->flags
.writing
= 1;
1655 es_peek (estream_t ES__RESTRICT stream
, unsigned char **ES__RESTRICT data
,
1656 size_t *ES__RESTRICT data_len
)
1660 if (stream
->flags
.writing
)
1662 /* Switching to reading mode -> flush output. */
1663 err
= es_flush (stream
);
1666 stream
->flags
.writing
= 0;
1669 if (stream
->data_offset
== stream
->data_len
)
1671 /* Refill container. */
1672 err
= es_fill (stream
);
1678 *data
= stream
->buffer
+ stream
->data_offset
;
1680 *data_len
= stream
->data_len
- stream
->data_offset
;
1689 /* Skip SIZE bytes of input data contained in buffer. */
1691 es_skip (estream_t stream
, size_t size
)
1695 if (stream
->data_offset
+ size
> stream
->data_len
)
1702 stream
->data_offset
+= size
;
1711 doreadline (estream_t ES__RESTRICT stream
, size_t max_length
,
1712 char *ES__RESTRICT
*ES__RESTRICT line
,
1713 size_t *ES__RESTRICT line_length
)
1717 estream_t line_stream
;
1719 void *line_stream_cookie
;
1721 unsigned char *data
;
1727 line_stream_cookie
= NULL
;
1729 err
= es_func_mem_create (&line_stream_cookie
, NULL
, 0, 0,
1730 BUFFER_BLOCK_SIZE
, 1,
1731 mem_realloc
, mem_free
,
1737 err
= es_create (&line_stream
, line_stream_cookie
, -1,
1738 estream_functions_mem
, O_RDWR
);
1742 space_left
= max_length
;
1746 if (max_length
&& (space_left
== 1))
1749 err
= es_peek (stream
, &data
, &data_len
);
1750 if (err
|| (! data_len
))
1753 if (data_len
> (space_left
- 1))
1754 data_len
= space_left
- 1;
1756 newline
= memchr (data
, '\n', data_len
);
1759 data_len
= (newline
- (char *) data
) + 1;
1760 err
= es_write (line_stream
, data
, data_len
, NULL
);
1763 space_left
-= data_len
;
1764 line_size
+= data_len
;
1765 es_skip (stream
, data_len
);
1771 err
= es_write (line_stream
, data
, data_len
, NULL
);
1774 space_left
-= data_len
;
1775 line_size
+= data_len
;
1776 es_skip (stream
, data_len
);
1785 /* Complete line has been written to line_stream. */
1787 if ((max_length
> 1) && (! line_size
))
1789 stream
->intern
->indicators
.eof
= 1;
1793 err
= es_seek (line_stream
, 0, SEEK_SET
, NULL
);
1799 line_new
= mem_alloc (line_size
+ 1);
1809 err
= es_read (line_stream
, line_new
, line_size
, NULL
);
1813 line_new
[line_size
] = '\0';
1818 *line_length
= line_size
;
1823 es_destroy (line_stream
);
1824 else if (line_stream_cookie
)
1825 es_func_mem_destroy (line_stream_cookie
);
1830 mem_free (line_new
);
1831 stream
->intern
->indicators
.err
= 1;
1838 /* Output fucntion used for estream_format. */
1840 print_writer (void *outfncarg
, const char *buf
, size_t buflen
)
1842 estream_t stream
= outfncarg
;
1847 rc
= es_writen (stream
, buf
, buflen
, &nwritten
);
1848 stream
->intern
->print_ntotal
+= nwritten
;
1853 /* The core of our printf function. This is called in locked state. */
1855 es_print (estream_t ES__RESTRICT stream
,
1856 const char *ES__RESTRICT format
, va_list ap
)
1860 stream
->intern
->print_ntotal
= 0;
1861 rc
= estream_format (print_writer
, stream
, format
, ap
);
1864 return (int)stream
->intern
->print_ntotal
;
1869 es_set_indicators (estream_t stream
, int ind_err
, int ind_eof
)
1872 stream
->intern
->indicators
.err
= ind_err
? 1 : 0;
1874 stream
->intern
->indicators
.eof
= ind_eof
? 1 : 0;
1879 es_get_indicator (estream_t stream
, int ind_err
, int ind_eof
)
1884 ret
= stream
->intern
->indicators
.err
;
1886 ret
= stream
->intern
->indicators
.eof
;
1893 es_set_buffering (estream_t ES__RESTRICT stream
,
1894 char *ES__RESTRICT buffer
, int mode
, size_t size
)
1898 /* Flush or empty buffer depending on mode. */
1899 if (stream
->flags
.writing
)
1901 err
= es_flush (stream
);
1908 es_set_indicators (stream
, -1, 0);
1910 /* Free old buffer in case that was allocated by this function. */
1911 if (stream
->intern
->deallocate_buffer
)
1913 stream
->intern
->deallocate_buffer
= 0;
1914 mem_free (stream
->buffer
);
1915 stream
->buffer
= NULL
;
1919 stream
->buffer_size
= 0;
1925 buffer_new
= buffer
;
1928 buffer_new
= mem_alloc (size
);
1936 stream
->buffer
= buffer_new
;
1937 stream
->buffer_size
= size
;
1939 stream
->intern
->deallocate_buffer
= 1;
1941 stream
->intern
->strategy
= mode
;
1951 es_offset_calculate (estream_t stream
)
1955 offset
= stream
->intern
->offset
+ stream
->data_offset
;
1956 if (offset
< stream
->unread_data_len
)
1957 /* Offset undefined. */
1960 offset
-= stream
->unread_data_len
;
1967 es_opaque_ctrl (estream_t ES__RESTRICT stream
, void *ES__RESTRICT opaque_new
,
1968 void **ES__RESTRICT opaque_old
)
1971 *opaque_old
= stream
->intern
->opaque
;
1973 stream
->intern
->opaque
= opaque_new
;
1978 es_get_fd (estream_t stream
)
1980 return stream
->intern
->fd
;
1992 err
= es_init_do ();
1998 es_fopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
)
2000 unsigned int modeflags
;
2011 err
= es_convert_mode (mode
, &modeflags
);
2015 err
= es_func_file_create (&cookie
, &fd
, path
, modeflags
);
2020 err
= es_create (&stream
, cookie
, fd
, estream_functions_file
, modeflags
);
2026 if (err
&& create_called
)
2027 (*estream_functions_file
.func_close
) (cookie
);
2034 es_mopen (unsigned char *ES__RESTRICT data
, size_t data_n
, size_t data_len
,
2036 func_realloc_t func_realloc
, func_free_t func_free
,
2037 const char *ES__RESTRICT mode
)
2039 unsigned int modeflags
;
2049 err
= es_convert_mode (mode
, &modeflags
);
2053 err
= es_func_mem_create (&cookie
, data
, data_n
, data_len
,
2054 BUFFER_BLOCK_SIZE
, grow
,
2055 func_realloc
, func_free
, modeflags
, 0);
2060 err
= es_create (&stream
, cookie
, -1, estream_functions_mem
, modeflags
);
2064 if (err
&& create_called
)
2065 (*estream_functions_mem
.func_close
) (cookie
);
2072 es_fopenmem (size_t memlimit
, const char *ES__RESTRICT mode
)
2074 unsigned int modeflags
;
2075 estream_t stream
= NULL
;
2076 void *cookie
= NULL
;
2078 /* Memory streams are always read/write. We use MODE only to get
2080 if (es_convert_mode (mode
, &modeflags
))
2082 modeflags
|= O_RDWR
;
2085 if (es_func_mem_create (&cookie
, NULL
, 0, 0,
2086 BUFFER_BLOCK_SIZE
, 1,
2087 mem_realloc
, mem_free
, modeflags
,
2091 if (es_create (&stream
, cookie
, -1, estream_functions_mem
, modeflags
))
2092 (*estream_functions_mem
.func_close
) (cookie
);
2100 es_fopencookie (void *ES__RESTRICT cookie
,
2101 const char *ES__RESTRICT mode
,
2102 es_cookie_io_functions_t functions
)
2104 unsigned int modeflags
;
2111 err
= es_convert_mode (mode
, &modeflags
);
2115 err
= es_create (&stream
, cookie
, -1, functions
, modeflags
);
2126 do_fdopen (int filedes
, const char *mode
, int no_close
)
2128 unsigned int modeflags
;
2138 err
= es_convert_mode (mode
, &modeflags
);
2142 err
= es_func_fd_create (&cookie
, filedes
, modeflags
, no_close
);
2147 err
= es_create (&stream
, cookie
, filedes
, estream_functions_fd
, modeflags
);
2151 if (err
&& create_called
)
2152 (*estream_functions_fd
.func_close
) (cookie
);
2158 es_fdopen (int filedes
, const char *mode
)
2160 return do_fdopen (filedes
, mode
, 0);
2163 /* A variant of es_fdopen which does not close FILEDES at the end. */
2165 es_fdopen_nc (int filedes
, const char *mode
)
2167 return do_fdopen (filedes
, mode
, 1);
2172 do_fpopen (FILE *fp
, const char *mode
, int no_close
)
2174 unsigned int modeflags
;
2184 err
= es_convert_mode (mode
, &modeflags
);
2189 err
= es_func_fp_create (&cookie
, fp
, modeflags
, no_close
);
2194 err
= es_create (&stream
, cookie
, fileno (fp
), estream_functions_fp
,
2199 if (err
&& create_called
)
2200 (*estream_functions_fp
.func_close
) (cookie
);
2206 /* Create an estream from the stdio stream FP. This mechanism is
2207 useful in case the stdio streams have special properties and may
2208 not be mixed with fd based functions. This is for example the case
2209 under Windows where the 3 standard streams are associated with the
2210 console whereas a duped and fd-opened stream of one of this stream
2211 won't be associated with the console. As this messes things up it
2212 is easier to keep on using the standard I/O stream as a backend for
2215 es_fpopen (FILE *fp
, const char *mode
)
2217 return do_fpopen (fp
, mode
, 0);
2221 /* Same as es_fpopen but does not close FP at the end. */
2223 es_fpopen_nc (FILE *fp
, const char *mode
)
2225 return do_fpopen (fp
, mode
, 1);
2230 es_freopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
,
2231 estream_t ES__RESTRICT stream
)
2237 unsigned int modeflags
;
2245 ESTREAM_LOCK (stream
);
2247 es_deinitialize (stream
);
2249 err
= es_convert_mode (mode
, &modeflags
);
2253 err
= es_func_file_create (&cookie
, &fd
, path
, modeflags
);
2258 es_initialize (stream
, cookie
, fd
, estream_functions_file
, modeflags
);
2265 es_func_fd_destroy (cookie
);
2267 es_destroy (stream
);
2271 ESTREAM_UNLOCK (stream
);
2275 /* FIXME? We don't support re-opening at the moment. */
2277 es_deinitialize (stream
);
2278 es_destroy (stream
);
2287 es_fclose (estream_t stream
)
2291 err
= es_destroy (stream
);
2297 es_fileno_unlocked (estream_t stream
)
2299 return es_get_fd (stream
);
2304 es_flockfile (estream_t stream
)
2306 ESTREAM_LOCK (stream
);
2311 es_ftrylockfile (estream_t stream
)
2313 return ESTREAM_TRYLOCK (stream
);
2318 es_funlockfile (estream_t stream
)
2320 ESTREAM_UNLOCK (stream
);
2325 es_fileno (estream_t stream
)
2329 ESTREAM_LOCK (stream
);
2330 ret
= es_fileno_unlocked (stream
);
2331 ESTREAM_UNLOCK (stream
);
2338 es_feof_unlocked (estream_t stream
)
2340 return es_get_indicator (stream
, 0, 1);
2345 es_feof (estream_t stream
)
2349 ESTREAM_LOCK (stream
);
2350 ret
= es_feof_unlocked (stream
);
2351 ESTREAM_UNLOCK (stream
);
2358 es_ferror_unlocked (estream_t stream
)
2360 return es_get_indicator (stream
, 1, 0);
2365 es_ferror (estream_t stream
)
2369 ESTREAM_LOCK (stream
);
2370 ret
= es_ferror_unlocked (stream
);
2371 ESTREAM_UNLOCK (stream
);
2378 es_clearerr_unlocked (estream_t stream
)
2380 es_set_indicators (stream
, 0, 0);
2385 es_clearerr (estream_t stream
)
2387 ESTREAM_LOCK (stream
);
2388 es_clearerr_unlocked (stream
);
2389 ESTREAM_UNLOCK (stream
);
2394 es_fflush (estream_t stream
)
2400 ESTREAM_LOCK (stream
);
2401 if (stream
->flags
.writing
)
2402 err
= es_flush (stream
);
2408 ESTREAM_UNLOCK (stream
);
2411 err
= es_list_iterate (es_fflush
);
2413 return err
? EOF
: 0;
2418 es_fseek (estream_t stream
, long int offset
, int whence
)
2422 ESTREAM_LOCK (stream
);
2423 err
= es_seek (stream
, offset
, whence
, NULL
);
2424 ESTREAM_UNLOCK (stream
);
2431 es_fseeko (estream_t stream
, off_t offset
, int whence
)
2435 ESTREAM_LOCK (stream
);
2436 err
= es_seek (stream
, offset
, whence
, NULL
);
2437 ESTREAM_UNLOCK (stream
);
2444 es_ftell (estream_t stream
)
2448 ESTREAM_LOCK (stream
);
2449 ret
= es_offset_calculate (stream
);
2450 ESTREAM_UNLOCK (stream
);
2457 es_ftello (estream_t stream
)
2461 ESTREAM_LOCK (stream
);
2462 ret
= es_offset_calculate (stream
);
2463 ESTREAM_UNLOCK (stream
);
2470 es_rewind (estream_t stream
)
2472 ESTREAM_LOCK (stream
);
2473 es_seek (stream
, 0L, SEEK_SET
, NULL
);
2474 es_set_indicators (stream
, 0, -1);
2475 ESTREAM_UNLOCK (stream
);
2480 _es_getc_underflow (estream_t stream
)
2486 err
= es_readn (stream
, &c
, 1, &bytes_read
);
2488 return (err
|| (! bytes_read
)) ? EOF
: c
;
2493 _es_putc_overflow (int c
, estream_t stream
)
2495 unsigned char d
= c
;
2498 err
= es_writen (stream
, &d
, 1, NULL
);
2500 return err
? EOF
: c
;
2505 es_fgetc (estream_t stream
)
2509 ESTREAM_LOCK (stream
);
2510 ret
= es_getc_unlocked (stream
);
2511 ESTREAM_UNLOCK (stream
);
2518 es_fputc (int c
, estream_t stream
)
2522 ESTREAM_LOCK (stream
);
2523 ret
= es_putc_unlocked (c
, stream
);
2524 ESTREAM_UNLOCK (stream
);
2531 es_ungetc (int c
, estream_t stream
)
2533 unsigned char data
= (unsigned char) c
;
2536 ESTREAM_LOCK (stream
);
2537 es_unreadn (stream
, &data
, 1, &data_unread
);
2538 ESTREAM_UNLOCK (stream
);
2540 return data_unread
? c
: EOF
;
2545 es_read (estream_t ES__RESTRICT stream
,
2546 void *ES__RESTRICT buffer
, size_t bytes_to_read
,
2547 size_t *ES__RESTRICT bytes_read
)
2553 ESTREAM_LOCK (stream
);
2554 err
= es_readn (stream
, buffer
, bytes_to_read
, bytes_read
);
2555 ESTREAM_UNLOCK (stream
);
2565 es_write (estream_t ES__RESTRICT stream
,
2566 const void *ES__RESTRICT buffer
, size_t bytes_to_write
,
2567 size_t *ES__RESTRICT bytes_written
)
2573 ESTREAM_LOCK (stream
);
2574 err
= es_writen (stream
, buffer
, bytes_to_write
, bytes_written
);
2575 ESTREAM_UNLOCK (stream
);
2585 es_fread (void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2586 estream_t ES__RESTRICT stream
)
2593 ESTREAM_LOCK (stream
);
2594 err
= es_readn (stream
, ptr
, size
* nitems
, &bytes
);
2595 ESTREAM_UNLOCK (stream
);
2607 es_fwrite (const void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2608 estream_t ES__RESTRICT stream
)
2615 ESTREAM_LOCK (stream
);
2616 err
= es_writen (stream
, ptr
, size
* nitems
, &bytes
);
2617 ESTREAM_UNLOCK (stream
);
2629 es_fgets (char *ES__RESTRICT buffer
, int length
, estream_t ES__RESTRICT stream
)
2631 unsigned char *s
= (unsigned char*)buffer
;
2638 ESTREAM_LOCK (stream
);
2639 while (length
> 1 && (c
= es_getc_unlocked (stream
)) != EOF
&& c
!= '\n')
2644 ESTREAM_UNLOCK (stream
);
2646 if (c
== EOF
&& s
== (unsigned char*)buffer
)
2647 return NULL
; /* Nothing read. */
2649 if (c
!= EOF
&& length
> 1)
2658 es_fputs (const char *ES__RESTRICT s
, estream_t ES__RESTRICT stream
)
2663 length
= strlen (s
);
2664 ESTREAM_LOCK (stream
);
2665 err
= es_writen (stream
, s
, length
, NULL
);
2666 ESTREAM_UNLOCK (stream
);
2668 return err
? EOF
: 0;
2673 es_getline (char *ES__RESTRICT
*ES__RESTRICT lineptr
, size_t *ES__RESTRICT n
,
2674 estream_t ES__RESTRICT stream
)
2680 ESTREAM_LOCK (stream
);
2681 err
= doreadline (stream
, 0, &line
, &line_n
);
2682 ESTREAM_UNLOCK (stream
);
2688 /* Caller wants us to use his buffer. */
2690 if (*n
< (line_n
+ 1))
2692 /* Provided buffer is too small -> resize. */
2696 p
= mem_realloc (*lineptr
, line_n
+ 1);
2708 memcpy (*lineptr
, line
, line_n
+ 1);
2716 /* Caller wants new buffers. */
2723 return err
? err
: line_n
;
2728 /* Same as fgets() but if the provided buffer is too short a larger
2729 one will be allocated. This is similar to getline. A line is
2730 considered a byte stream ending in a LF.
2732 If MAX_LENGTH is not NULL, it shall point to a value with the
2733 maximum allowed allocation.
2735 Returns the length of the line. EOF is indicated by a line of
2736 length zero. A truncated line is indicated my setting the value at
2737 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2738 memory was enable or another error occurred; ERRNO is then set
2741 If a line has been truncated, the file pointer is moved forward to
2742 the end of the line so that the next read starts with the next
2743 line. Note that MAX_LENGTH must be re-initialzied in this case.
2745 The caller initially needs to provide the address of a variable,
2746 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2747 anymore with the following invocations. LENGTH_OF_BUFFER should be
2748 the address of a variable, initialized to 0, which is also
2749 maintained by this function. Thus, both paramaters should be
2750 considered the state of this function.
2752 Note: The returned buffer is allocated with enough extra space to
2753 allow the caller to append a CR,LF,Nul. The buffer should be
2754 released using es_free.
2757 es_read_line (estream_t stream
,
2758 char **addr_of_buffer
, size_t *length_of_buffer
,
2762 char *buffer
= *addr_of_buffer
;
2763 size_t length
= *length_of_buffer
;
2765 size_t maxlen
= max_length
? *max_length
: 0;
2770 /* No buffer given - allocate a new one. */
2772 buffer
= mem_alloc (length
);
2773 *addr_of_buffer
= buffer
;
2776 *length_of_buffer
= 0;
2781 *length_of_buffer
= length
;
2786 /* This should never happen. If it does, the function has been
2787 called with wrong arguments. */
2791 length
-= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2793 ESTREAM_LOCK (stream
);
2795 while ((c
= es_getc_unlocked (stream
)) != EOF
)
2797 if (nbytes
== length
)
2799 /* Enlarge the buffer. */
2800 if (maxlen
&& length
> maxlen
)
2802 /* We are beyond our limit: Skip the rest of the line. */
2803 while (c
!= '\n' && (c
=es_getc_unlocked (stream
)) != EOF
)
2805 *p
++ = '\n'; /* Always append a LF (we reserved some space). */
2808 *max_length
= 0; /* Indicate truncation. */
2809 break; /* the while loop. */
2811 length
+= 3; /* Adjust for the reserved bytes. */
2812 length
+= length
< 1024? 256 : 1024;
2813 *addr_of_buffer
= mem_realloc (buffer
, length
);
2814 if (!*addr_of_buffer
)
2816 int save_errno
= errno
;
2818 *length_of_buffer
= *max_length
= 0;
2819 ESTREAM_UNLOCK (stream
);
2823 buffer
= *addr_of_buffer
;
2824 *length_of_buffer
= length
;
2826 p
= buffer
+ nbytes
;
2833 *p
= 0; /* Make sure the line is a string. */
2834 ESTREAM_UNLOCK (stream
);
2839 /* Wrapper around free() to match the memory allocation system used
2840 by estream. Should be used for all buffers returned to the caller
2850 es_vfprintf (estream_t ES__RESTRICT stream
, const char *ES__RESTRICT format
,
2855 ESTREAM_LOCK (stream
);
2856 ret
= es_print (stream
, format
, ap
);
2857 ESTREAM_UNLOCK (stream
);
2864 es_fprintf_unlocked (estream_t ES__RESTRICT stream
,
2865 const char *ES__RESTRICT format
, ...)
2870 va_start (ap
, format
);
2871 ret
= es_print (stream
, format
, ap
);
2879 es_fprintf (estream_t ES__RESTRICT stream
,
2880 const char *ES__RESTRICT format
, ...)
2885 va_start (ap
, format
);
2886 ESTREAM_LOCK (stream
);
2887 ret
= es_print (stream
, format
, ap
);
2888 ESTREAM_UNLOCK (stream
);
2898 #ifdef HAVE_W32_SYSTEM
2900 char buffer
[MAX_PATH
+9+12+1];
2903 int pid
= GetCurrentProcessId ();
2907 n
= GetTempPath (MAX_PATH
+1, buffer
);
2908 if (!n
|| n
> MAX_PATH
|| strlen (buffer
) > MAX_PATH
)
2913 p
= buffer
+ strlen (buffer
);
2914 strcpy (p
, "_estream");
2916 /* We try to create the directory but don't care about an error as
2917 it may already exist and the CreateFile would throw an error
2919 CreateDirectory (buffer
, NULL
);
2922 for (attempts
=0; attempts
< 10; attempts
++)
2925 value
= (GetTickCount () ^ ((pid
<<16) & 0xffff0000));
2926 for (i
=0; i
< 8; i
++)
2928 *p
++ = tohex (((value
>> 28) & 0x0f));
2932 file
= CreateFile (buffer
,
2933 GENERIC_READ
| GENERIC_WRITE
,
2937 FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_DELETE_ON_CLOSE
,
2939 if (file
!= INVALID_HANDLE_VALUE
)
2941 int fd
= _open_osfhandle ((long)file
, 0);
2949 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
2953 #else /*!HAVE_W32_SYSTEM*/
2965 fp_fd
= fileno (fp
);
2974 #endif /*!HAVE_W32_SYSTEM*/
2980 unsigned int modeflags
;
2989 modeflags
= O_RDWR
| O_TRUNC
| O_CREAT
;
2999 err
= es_func_fd_create (&cookie
, fd
, modeflags
, 0);
3004 err
= es_create (&stream
, cookie
, fd
, estream_functions_fd
, modeflags
);
3011 es_func_fd_destroy (cookie
);
3022 es_setvbuf (estream_t ES__RESTRICT stream
,
3023 char *ES__RESTRICT buf
, int type
, size_t size
)
3027 if (((type
== _IOFBF
) || (type
== _IOLBF
) || (type
== _IONBF
))
3028 && (! ((! size
) && (type
!= _IONBF
))))
3030 ESTREAM_LOCK (stream
);
3031 err
= es_set_buffering (stream
, buf
, type
, size
);
3032 ESTREAM_UNLOCK (stream
);
3045 es_setbuf (estream_t ES__RESTRICT stream
, char *ES__RESTRICT buf
)
3047 ESTREAM_LOCK (stream
);
3048 es_set_buffering (stream
, buf
, buf
? _IOFBF
: _IONBF
, BUFSIZ
);
3049 ESTREAM_UNLOCK (stream
);
3053 es_opaque_set (estream_t stream
, void *opaque
)
3055 ESTREAM_LOCK (stream
);
3056 es_opaque_ctrl (stream
, opaque
, NULL
);
3057 ESTREAM_UNLOCK (stream
);
3062 es_opaque_get (estream_t stream
)
3066 ESTREAM_LOCK (stream
);
3067 es_opaque_ctrl (stream
, NULL
, &opaque
);
3068 ESTREAM_UNLOCK (stream
);
3073 /* Print a BUFFER to STREAM while replacing all control characters and
3074 the characters in DELIMITERS by standard C escape sequences.
3075 Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
3076 the number of bytes actually written are stored at this
3079 es_write_sanitized (estream_t ES__RESTRICT stream
,
3080 const void * ES__RESTRICT buffer
, size_t length
,
3081 const char * delimiters
,
3082 size_t * ES__RESTRICT bytes_written
)
3084 const unsigned char *p
= buffer
;
3088 ESTREAM_LOCK (stream
);
3089 for (; length
; length
--, p
++, count
++)
3094 && (strchr (delimiters
, *p
) || *p
== '\\')))
3096 es_putc_unlocked ('\\', stream
);
3100 es_putc_unlocked ('n', stream
);
3103 else if (*p
== '\r')
3105 es_putc_unlocked ('r', stream
);
3108 else if (*p
== '\f')
3110 es_putc_unlocked ('f', stream
);
3113 else if (*p
== '\v')
3115 es_putc_unlocked ('v', stream
);
3118 else if (*p
== '\b')
3120 es_putc_unlocked ('b', stream
);
3125 es_putc_unlocked('0', stream
);
3130 es_fprintf_unlocked (stream
, "x%02x", *p
);
3136 es_putc_unlocked (*p
, stream
);
3142 *bytes_written
= count
;
3143 ret
= es_ferror_unlocked (stream
)? -1 : 0;
3144 ESTREAM_UNLOCK (stream
);
3150 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3151 RESERVED must be 0. Returns 0 on success or -1 on error. If
3152 BYTES_WRITTEN is not NULL the number of bytes actually written are
3153 stored at this address. */
3155 es_write_hexstring (estream_t ES__RESTRICT stream
,
3156 const void *ES__RESTRICT buffer
, size_t length
,
3157 int reserved
, size_t *ES__RESTRICT bytes_written
)
3160 const unsigned char *s
;
3165 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3170 ESTREAM_LOCK (stream
);
3172 for (s
= buffer
; length
; s
++, length
--)
3174 es_putc_unlocked ( tohex ((*s
>>4)&15), stream
);
3175 es_putc_unlocked ( tohex (*s
&15), stream
);
3180 *bytes_written
= count
;
3181 ret
= es_ferror_unlocked (stream
)? -1 : 0;
3183 ESTREAM_UNLOCK (stream
);
3192 #ifdef GNUPG_MAJOR_VERSION
3193 /* Special estream function to print an UTF8 string in the native
3194 encoding. The interface is the same as es_write_sanitized, however
3195 only one delimiter may be supported.
3197 THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3199 es_write_sanitized_utf8_buffer (estream_t stream
,
3200 const void *buffer
, size_t length
,
3201 const char *delimiters
, size_t *bytes_written
)
3203 const char *p
= buffer
;
3206 /* We can handle plain ascii simpler, so check for it first. */
3207 for (i
=0; i
< length
; i
++ )
3209 if ( (p
[i
] & 0x80) )
3214 int delim
= delimiters
? *delimiters
: 0;
3218 /*(utf8 conversion already does the control character quoting). */
3219 buf
= utf8_to_native (p
, length
, delim
);
3221 *bytes_written
= strlen (buf
);
3222 ret
= es_fputs (buf
, stream
);
3227 return es_write_sanitized (stream
, p
, length
, delimiters
, bytes_written
);
3229 #endif /*GNUPG_MAJOR_VERSION*/