1 /* estream.c - Extended Stream I/O Library
2 * Copyright (C) 2004, 2006 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 * Lesser 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 #ifdef USE_ESTREAM_SUPPORT_H
23 # include <estream-support.h>
30 #include <sys/types.h>
43 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */
53 int mkstemp (char *template);
57 void *memrchr (const void *block
, int c
, size_t size
);
64 /* Generally used types. */
66 typedef void *(*func_realloc_t
) (void *mem
, size_t size
);
67 typedef void (*func_free_t
) (void *mem
);
71 /* Buffer management layer. */
73 #define BUFFER_BLOCK_SIZE BUFSIZ
74 #define BUFFER_UNREAD_SIZE 16
80 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
81 (((size) + (block_size - 1)) / block_size)
89 typedef pth_mutex_t estream_mutex_t
;
90 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
91 # define ESTREAM_MUTEX_LOCK(mutex) \
92 pth_mutex_acquire (&(mutex), 0, NULL)
93 # define ESTREAM_MUTEX_UNLOCK(mutex) \
94 pth_mutex_release (&(mutex))
95 # define ESTREAM_MUTEX_TRYLOCK(mutex) \
96 ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
97 # define ESTREAM_MUTEX_INITIALIZE(mutex) \
98 pth_mutex_init (&(mutex))
99 # define ESTREAM_THREADING_INIT() ((pth_init () == TRUE) ? 0 : -1)
103 typedef void *estream_mutex_t
;
104 # define ESTREAM_MUTEX_INITIALIZER NULL
105 # define ESTREAM_MUTEX_LOCK(mutex) (void) 0
106 # define ESTREAM_MUTEX_UNLOCK(mutex) (void) 0
107 # define ESTREAM_MUTEX_TRYLOCK(mutex) 0
108 # define ESTREAM_MUTEX_INITIALIZE(mutex) (void) 0
109 # define ESTREAM_THREADING_INIT() 0
113 /* Memory allocator functions. */
115 #define MEM_ALLOC malloc
116 #define MEM_REALLOC realloc
117 #define MEM_FREE free
119 /* Primitive system I/O. */
122 # define ESTREAM_SYS_READ pth_read
123 # define ESTREAM_SYS_WRITE pth_write
125 # define ESTREAM_SYS_READ read
126 # define ESTREAM_SYS_WRITE write
129 /* Misc definitions. */
131 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
133 #define ES_FLAG_WRITING ES__FLAG_WRITING
135 /* An internal stream object. */
137 struct estream_internal
139 unsigned char buffer
[BUFFER_BLOCK_SIZE
];
140 unsigned char unread_buffer
[BUFFER_UNREAD_SIZE
];
141 estream_mutex_t lock
; /* Lock. */
142 void *cookie
; /* Cookie. */
143 void *opaque
; /* Opaque data. */
144 unsigned int flags
; /* Flags. */
146 es_cookie_read_function_t func_read
;
147 es_cookie_write_function_t func_write
;
148 es_cookie_seek_function_t func_seek
;
149 es_cookie_close_function_t func_close
;
157 unsigned int deallocate_buffer
: 1;
158 unsigned int print_err
: 1; /* Error in print_fun_writer. */
159 int print_errno
; /* Errno from print_fun_writer. */
160 size_t print_ntotal
; /* Bytes written from in print_fun_writer. */
161 FILE *print_fp
; /* Stdio stream used by print_fun_writer. */
165 typedef struct estream_internal
*estream_internal_t
;
167 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
168 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
169 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
173 typedef struct estream_list
*estream_list_t
;
179 estream_list_t
*prev_cdr
;
182 static estream_list_t estream_list
;
184 static estream_mutex_t estream_list_lock
= ESTREAM_MUTEX_INITIALIZER
;
187 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
188 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
191 # define EOPNOTSUPP ENOSYS
199 /* Calculate array dimension. */
200 #define DIM(array) (sizeof (array) / sizeof (*array))
202 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
204 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
207 tmp_variable = expression; \
208 if ((! variable) && tmp_variable) \
209 variable = tmp_variable; \
217 /* Add STREAM to the list of registered stream objects. */
219 es_list_add (estream_t stream
)
221 estream_list_t list_obj
;
224 list_obj
= MEM_ALLOC (sizeof (*list_obj
));
230 list_obj
->car
= stream
;
231 list_obj
->cdr
= estream_list
;
232 list_obj
->prev_cdr
= &estream_list
;
234 estream_list
->prev_cdr
= &list_obj
->cdr
;
235 estream_list
= list_obj
;
243 /* Remove STREAM from the list of registered stream objects. */
245 es_list_remove (estream_t stream
)
247 estream_list_t list_obj
;
250 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
251 if (list_obj
->car
== stream
)
253 *list_obj
->prev_cdr
= list_obj
->cdr
;
255 list_obj
->cdr
->prev_cdr
= list_obj
->prev_cdr
;
262 /* Type of an stream-iterator-function. */
263 typedef int (*estream_iterator_t
) (estream_t stream
);
265 /* Iterate over list of registered streams, calling ITERATOR for each
268 es_list_iterate (estream_iterator_t iterator
)
270 estream_list_t list_obj
;
274 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
275 ret
|= (*iterator
) (list_obj
->car
);
292 err
= ESTREAM_THREADING_INIT ();
303 /* Implementation of Memory I/O. */
305 /* Cookie for memory objects. */
306 typedef struct estream_cookie_mem
308 unsigned int flags
; /* Open flags. */
309 unsigned char *memory
; /* Data. */
310 size_t memory_size
; /* Size of MEMORY. */
311 size_t offset
; /* Current offset in MEMORY. */
312 size_t data_len
; /* Length of data in MEMORY. */
313 size_t block_size
; /* Block size. */
314 unsigned int grow
: 1; /* MEMORY is allowed to grow. */
315 unsigned int append_zero
: 1; /* Append zero after data. */
316 unsigned int dont_free
: 1; /* Append zero after data. */
319 func_realloc_t func_realloc
;
320 func_free_t func_free
;
321 } *estream_cookie_mem_t
;
323 /* Create function for memory objects. */
325 es_func_mem_create (void *ES__RESTRICT
*ES__RESTRICT cookie
,
326 unsigned char *ES__RESTRICT data
, size_t data_n
,
328 size_t block_size
, unsigned int grow
,
329 unsigned int append_zero
, unsigned int dont_free
,
330 char **ptr
, size_t *size
,
331 func_realloc_t func_realloc
, func_free_t func_free
,
334 estream_cookie_mem_t mem_cookie
;
337 mem_cookie
= MEM_ALLOC (sizeof (*mem_cookie
));
342 mem_cookie
->flags
= flags
;
343 mem_cookie
->memory
= data
;
344 mem_cookie
->memory_size
= data_n
;
345 mem_cookie
->offset
= 0;
346 mem_cookie
->data_len
= data_len
;
347 mem_cookie
->block_size
= block_size
;
348 mem_cookie
->grow
= grow
? 1 : 0;
349 mem_cookie
->append_zero
= append_zero
? 1 : 0;
350 mem_cookie
->dont_free
= dont_free
? 1 : 0;
351 mem_cookie
->ptr
= ptr
;
352 mem_cookie
->size
= size
;
353 mem_cookie
->func_realloc
= func_realloc
? func_realloc
: MEM_REALLOC
;
354 mem_cookie
->func_free
= func_free
? func_free
: MEM_FREE
;
355 mem_cookie
->offset
= 0;
356 *cookie
= mem_cookie
;
363 /* Read function for memory objects. */
365 es_func_mem_read (void *cookie
, void *buffer
, size_t size
)
367 estream_cookie_mem_t mem_cookie
= cookie
;
370 if (size
> mem_cookie
->data_len
- mem_cookie
->offset
)
371 size
= mem_cookie
->data_len
- mem_cookie
->offset
;
375 memcpy (buffer
, mem_cookie
->memory
+ mem_cookie
->offset
, size
);
376 mem_cookie
->offset
+= size
;
384 /* Write function for memory objects. */
386 es_func_mem_write (void *cookie
, const void *buffer
, size_t size
)
388 estream_cookie_mem_t mem_cookie
= cookie
;
389 func_realloc_t func_realloc
= mem_cookie
->func_realloc
;
390 unsigned char *memory_new
;
399 if (mem_cookie
->flags
& O_APPEND
)
400 /* Append to data. */
401 mem_cookie
->offset
= mem_cookie
->data_len
;
403 if (! mem_cookie
->grow
)
404 if (size
> mem_cookie
->memory_size
- mem_cookie
->offset
)
405 size
= mem_cookie
->memory_size
- mem_cookie
->offset
;
409 while (size
> (mem_cookie
->memory_size
- mem_cookie
->offset
))
411 memory_new
= (*func_realloc
) (mem_cookie
->memory
,
412 mem_cookie
->memory_size
413 + mem_cookie
->block_size
);
421 if (mem_cookie
->memory
!= memory_new
)
422 mem_cookie
->memory
= memory_new
;
423 mem_cookie
->memory_size
+= mem_cookie
->block_size
;
431 memcpy (mem_cookie
->memory
+ mem_cookie
->offset
, buffer
, size
);
432 if (mem_cookie
->offset
+ size
> mem_cookie
->data_len
)
433 mem_cookie
->data_len
= mem_cookie
->offset
+ size
;
434 mem_cookie
->offset
+= size
;
442 if (mem_cookie
->append_zero
)
444 if (mem_cookie
->data_len
>= mem_cookie
->memory_size
)
446 newsize
= BUFFER_ROUND_TO_BLOCK (mem_cookie
->data_len
+ 1,
447 mem_cookie
->block_size
)
448 * mem_cookie
->block_size
;
450 memory_new
= (*func_realloc
) (mem_cookie
->memory
, newsize
);
457 if (mem_cookie
->memory
!= memory_new
)
458 mem_cookie
->memory
= memory_new
;
459 mem_cookie
->memory_size
= newsize
;
462 mem_cookie
->memory
[mem_cookie
->data_len
+ 1] = 0;
465 /* Return information to user if necessary. */
467 *mem_cookie
->ptr
= (char *) mem_cookie
->memory
;
468 if (mem_cookie
->size
)
469 *mem_cookie
->size
= mem_cookie
->data_len
;
482 /* Seek function for memory objects. */
484 es_func_mem_seek (void *cookie
, off_t
*offset
, int whence
)
486 estream_cookie_mem_t mem_cookie
= cookie
;
497 pos_new
= mem_cookie
->offset
+= *offset
;
501 pos_new
= mem_cookie
->data_len
+= *offset
;
509 if (pos_new
> mem_cookie
->memory_size
)
511 /* Grow buffer if possible. */
513 if (mem_cookie
->grow
)
515 func_realloc_t func_realloc
= mem_cookie
->func_realloc
;
519 newsize
= BUFFER_ROUND_TO_BLOCK (pos_new
, mem_cookie
->block_size
);
520 p
= (*func_realloc
) (mem_cookie
->memory
, newsize
);
528 if (mem_cookie
->memory
!= p
)
529 mem_cookie
->memory
= p
;
530 mem_cookie
->memory_size
= newsize
;
541 if (pos_new
> mem_cookie
->data_len
)
542 /* Fill spare space with zeroes. */
543 memset (mem_cookie
->memory
+ mem_cookie
->data_len
,
544 0, pos_new
- mem_cookie
->data_len
);
546 mem_cookie
->offset
= pos_new
;
554 /* Destroy function for memory objects. */
556 es_func_mem_destroy (void *cookie
)
558 estream_cookie_mem_t mem_cookie
= cookie
;
559 func_free_t func_free
= mem_cookie
->func_free
;
561 if (! mem_cookie
->dont_free
)
562 (*func_free
) (mem_cookie
->memory
);
563 MEM_FREE (mem_cookie
);
568 static es_cookie_io_functions_t estream_functions_mem
=
576 /* Implementation of fd I/O. */
578 /* Cookie for fd objects. */
579 typedef struct estream_cookie_fd
582 } *estream_cookie_fd_t
;
584 /* Create function for fd objects. */
586 es_func_fd_create (void **cookie
, int fd
, unsigned int flags
)
588 estream_cookie_fd_t fd_cookie
;
591 fd_cookie
= MEM_ALLOC (sizeof (*fd_cookie
));
604 /* Read function for fd objects. */
606 es_func_fd_read (void *cookie
, void *buffer
, size_t size
)
609 estream_cookie_fd_t file_cookie
= cookie
;
613 bytes_read
= ESTREAM_SYS_READ (file_cookie
->fd
, buffer
, size
);
614 while (bytes_read
== -1 && errno
== EINTR
);
619 /* Write function for fd objects. */
621 es_func_fd_write (void *cookie
, const void *buffer
, size_t size
)
624 estream_cookie_fd_t file_cookie
= cookie
;
625 ssize_t bytes_written
;
628 bytes_written
= ESTREAM_SYS_WRITE (file_cookie
->fd
, buffer
, size
);
629 while (bytes_written
== -1 && errno
== EINTR
);
631 return bytes_written
;
634 /* Seek function for fd objects. */
636 es_func_fd_seek (void *cookie
, off_t
*offset
, int whence
)
638 estream_cookie_fd_t file_cookie
= cookie
;
642 offset_new
= lseek (file_cookie
->fd
, *offset
, whence
);
643 if (offset_new
== -1)
647 *offset
= offset_new
;
654 /* Destroy function for fd objects. */
656 es_func_fd_destroy (void *cookie
)
658 estream_cookie_fd_t fd_cookie
= cookie
;
663 err
= close (fd_cookie
->fd
);
664 MEM_FREE (fd_cookie
);
672 static es_cookie_io_functions_t estream_functions_fd
=
680 /* Implementation of file I/O. */
682 /* Create function for file objects. */
684 es_func_file_create (void **cookie
, int *filedes
,
685 const char *path
, unsigned int flags
)
687 estream_cookie_fd_t file_cookie
;
694 file_cookie
= MEM_ALLOC (sizeof (*file_cookie
));
701 fd
= open (path
, flags
, ES_DEFAULT_OPEN_MODE
);
708 file_cookie
->fd
= fd
;
709 *cookie
= file_cookie
;
715 MEM_FREE (file_cookie
);
720 static es_cookie_io_functions_t estream_functions_file
=
730 /* Stream primitives. */
733 es_convert_mode (const char *mode
, unsigned int *flags
)
739 } mode_flags
[] = { { "r",
744 O_WRONLY
| O_TRUNC
| O_CREAT
},
746 O_WRONLY
| O_TRUNC
| O_CREAT
},
748 O_WRONLY
| O_APPEND
| O_CREAT
},
750 O_WRONLY
| O_APPEND
| O_CREAT
},
756 O_RDONLY
| O_WRONLY
},
758 O_RDWR
| O_TRUNC
| O_CREAT
},
760 O_RDWR
| O_TRUNC
| O_CREAT
},
762 O_RDWR
| O_TRUNC
| O_CREAT
},
764 O_RDWR
| O_CREAT
| O_APPEND
},
766 O_RDWR
| O_CREAT
| O_APPEND
},
768 O_RDWR
| O_CREAT
| O_APPEND
} };
772 for (i
= 0; i
< DIM (mode_flags
); i
++)
773 if (! strcmp (mode_flags
[i
].mode
, mode
))
775 if (i
== DIM (mode_flags
))
783 *flags
= mode_flags
[i
].flags
;
792 * Low level stream functionality.
796 es_fill (estream_t stream
)
798 size_t bytes_read
= 0;
801 if (!stream
->intern
->func_read
)
808 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
811 ret
= (*func_read
) (stream
->intern
->cookie
,
812 stream
->buffer
, stream
->buffer_size
);
826 stream
->intern
->indicators
.err
= 1;
827 else if (!bytes_read
)
828 stream
->intern
->indicators
.eof
= 1;
830 stream
->intern
->offset
+= stream
->data_len
;
831 stream
->data_len
= bytes_read
;
832 stream
->data_offset
= 0;
838 es_flush (estream_t stream
)
840 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
843 assert (stream
->flags
& ES_FLAG_WRITING
);
845 if (stream
->data_offset
)
847 size_t bytes_written
;
857 /* Note: to prevent an endless loop caused by user-provided
858 write-functions that pretend to have written more bytes than
859 they were asked to write, we have to check for
860 "(stream->data_offset - data_flushed) > 0" instead of
861 "stream->data_offset - data_flushed". */
866 while ((((ssize_t
) (stream
->data_offset
- data_flushed
)) > 0) && (! err
))
868 ret
= (*func_write
) (stream
->intern
->cookie
,
869 stream
->buffer
+ data_flushed
,
870 stream
->data_offset
- data_flushed
);
879 data_flushed
+= bytes_written
;
884 stream
->data_flushed
+= data_flushed
;
885 if (stream
->data_offset
== data_flushed
)
887 stream
->intern
->offset
+= stream
->data_offset
;
888 stream
->data_offset
= 0;
889 stream
->data_flushed
= 0;
891 /* Propagate flush event. */
892 (*func_write
) (stream
->intern
->cookie
, NULL
, 0);
901 stream
->intern
->indicators
.err
= 1;
906 /* Discard buffered data for STREAM. */
908 es_empty (estream_t stream
)
910 assert (! (stream
->flags
& ES_FLAG_WRITING
));
911 stream
->data_len
= 0;
912 stream
->data_offset
= 0;
913 stream
->unread_data_len
= 0;
916 /* Initialize STREAM. */
918 es_initialize (estream_t stream
,
919 void *cookie
, int fd
, es_cookie_io_functions_t functions
)
921 stream
->intern
->cookie
= cookie
;
922 stream
->intern
->opaque
= NULL
;
923 stream
->intern
->offset
= 0;
924 stream
->intern
->func_read
= functions
.func_read
;
925 stream
->intern
->func_write
= functions
.func_write
;
926 stream
->intern
->func_seek
= functions
.func_seek
;
927 stream
->intern
->func_close
= functions
.func_close
;
928 stream
->intern
->strategy
= _IOFBF
;
929 stream
->intern
->fd
= fd
;
930 stream
->intern
->print_err
= 0;
931 stream
->intern
->print_errno
= 0;
932 stream
->intern
->print_ntotal
= 0;
933 stream
->intern
->print_fp
= NULL
;
934 stream
->intern
->indicators
.err
= 0;
935 stream
->intern
->indicators
.eof
= 0;
936 stream
->intern
->deallocate_buffer
= 0;
938 stream
->data_len
= 0;
939 stream
->data_offset
= 0;
940 stream
->data_flushed
= 0;
941 stream
->unread_data_len
= 0;
945 /* Deinitialize STREAM. */
947 es_deinitialize (estream_t stream
)
949 es_cookie_close_function_t func_close
;
952 if (stream
->intern
->print_fp
)
954 int save_errno
= errno
;
955 fclose (stream
->intern
->print_fp
);
956 stream
->intern
->print_fp
= NULL
;
960 func_close
= stream
->intern
->func_close
;
963 if (stream
->flags
& ES_FLAG_WRITING
)
964 SET_UNLESS_NONZERO (err
, tmp_err
, es_flush (stream
));
966 SET_UNLESS_NONZERO (err
, tmp_err
, (*func_close
) (stream
->intern
->cookie
));
972 /* Create a new stream object, initialize it. */
974 es_create (estream_t
*stream
, void *cookie
, int fd
,
975 es_cookie_io_functions_t functions
)
977 estream_internal_t stream_internal_new
;
978 estream_t stream_new
;
982 stream_internal_new
= NULL
;
984 stream_new
= MEM_ALLOC (sizeof (*stream_new
));
991 stream_internal_new
= MEM_ALLOC (sizeof (*stream_internal_new
));
992 if (! stream_internal_new
)
998 stream_new
->buffer
= stream_internal_new
->buffer
;
999 stream_new
->buffer_size
= sizeof (stream_internal_new
->buffer
);
1000 stream_new
->unread_buffer
= stream_internal_new
->unread_buffer
;
1001 stream_new
->unread_buffer_size
= sizeof (stream_internal_new
->unread_buffer
);
1002 stream_new
->intern
= stream_internal_new
;
1004 ESTREAM_MUTEX_INITIALIZE (stream_new
->intern
->lock
);
1005 es_initialize (stream_new
, cookie
, fd
, functions
);
1007 err
= es_list_add (stream_new
);
1011 *stream
= stream_new
;
1019 es_deinitialize (stream_new
);
1020 MEM_FREE (stream_new
);
1027 /* Deinitialize a stream object and destroy it. */
1029 es_destroy (estream_t stream
)
1035 es_list_remove (stream
);
1036 err
= es_deinitialize (stream
);
1037 MEM_FREE (stream
->intern
);
1044 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1045 unbuffered-mode, storing the amount of bytes read in
1048 es_read_nbf (estream_t ES__RESTRICT stream
,
1049 unsigned char *ES__RESTRICT buffer
,
1050 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1052 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
1060 while (bytes_to_read
- data_read
)
1062 ret
= (*func_read
) (stream
->intern
->cookie
,
1063 buffer
+ data_read
, bytes_to_read
- data_read
);
1075 stream
->intern
->offset
+= data_read
;
1076 *bytes_read
= data_read
;
1081 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1082 fully-buffered-mode, storing the amount of bytes read in
1085 es_read_fbf (estream_t ES__RESTRICT stream
,
1086 unsigned char *ES__RESTRICT buffer
,
1087 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1089 size_t data_available
;
1090 size_t data_to_read
;
1097 while ((bytes_to_read
- data_read
) && (! err
))
1099 if (stream
->data_offset
== stream
->data_len
)
1101 /* Nothing more to read in current container, try to
1102 fill container with new data. */
1103 err
= es_fill (stream
);
1105 if (! stream
->data_len
)
1106 /* Filling did not result in any data read. */
1112 /* Filling resulted in some new data. */
1114 data_to_read
= bytes_to_read
- data_read
;
1115 data_available
= stream
->data_len
- stream
->data_offset
;
1116 if (data_to_read
> data_available
)
1117 data_to_read
= data_available
;
1119 memcpy (buffer
+ data_read
,
1120 stream
->buffer
+ stream
->data_offset
, data_to_read
);
1121 stream
->data_offset
+= data_to_read
;
1122 data_read
+= data_to_read
;
1126 *bytes_read
= data_read
;
1131 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1132 line-buffered-mode, storing the amount of bytes read in
1135 es_read_lbf (estream_t ES__RESTRICT stream
,
1136 unsigned char *ES__RESTRICT buffer
,
1137 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1141 err
= es_read_fbf (stream
, buffer
, bytes_to_read
, bytes_read
);
1146 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1147 *the amount of bytes read in BYTES_READ. */
1149 es_readn (estream_t ES__RESTRICT stream
,
1150 void *ES__RESTRICT buffer_arg
,
1151 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1153 unsigned char *buffer
= (unsigned char *)buffer_arg
;
1154 size_t data_read_unread
, data_read
;
1157 data_read_unread
= 0;
1161 if (stream
->flags
& ES_FLAG_WRITING
)
1163 /* Switching to reading mode -> flush output. */
1164 err
= es_flush (stream
);
1167 stream
->flags
&= ~ES_FLAG_WRITING
;
1170 /* Read unread data first. */
1171 while ((bytes_to_read
- data_read_unread
) && stream
->unread_data_len
)
1173 buffer
[data_read_unread
]
1174 = stream
->unread_buffer
[stream
->unread_data_len
- 1];
1175 stream
->unread_data_len
--;
1179 switch (stream
->intern
->strategy
)
1182 err
= es_read_nbf (stream
,
1183 buffer
+ data_read_unread
,
1184 bytes_to_read
- data_read_unread
, &data_read
);
1187 err
= es_read_lbf (stream
,
1188 buffer
+ data_read_unread
,
1189 bytes_to_read
- data_read_unread
, &data_read
);
1192 err
= es_read_fbf (stream
,
1193 buffer
+ data_read_unread
,
1194 bytes_to_read
- data_read_unread
, &data_read
);
1201 *bytes_read
= data_read_unread
+ data_read
;
1206 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1207 amount of bytes succesfully unread in *BYTES_UNREAD. */
1209 es_unreadn (estream_t ES__RESTRICT stream
,
1210 const unsigned char *ES__RESTRICT data
, size_t data_n
,
1211 size_t *ES__RESTRICT bytes_unread
)
1215 space_left
= stream
->unread_buffer_size
- stream
->unread_data_len
;
1217 if (data_n
> space_left
)
1218 data_n
= space_left
;
1223 memcpy (stream
->unread_buffer
+ stream
->unread_data_len
, data
, data_n
);
1224 stream
->unread_data_len
+= data_n
;
1225 stream
->intern
->indicators
.eof
= 0;
1230 *bytes_unread
= data_n
;
1233 /* Seek in STREAM. */
1235 es_seek (estream_t ES__RESTRICT stream
, off_t offset
, int whence
,
1236 off_t
*ES__RESTRICT offset_new
)
1238 es_cookie_seek_function_t func_seek
= stream
->intern
->func_seek
;
1249 if (stream
->flags
& ES_FLAG_WRITING
)
1251 /* Flush data first in order to prevent flushing it to the wrong
1253 err
= es_flush (stream
);
1256 stream
->flags
&= ~ES_FLAG_WRITING
;
1260 if (whence
== SEEK_CUR
)
1262 off
= off
- stream
->data_len
+ stream
->data_offset
;
1263 off
-= stream
->unread_data_len
;
1266 ret
= (*func_seek
) (stream
->intern
->cookie
, &off
, whence
);
1279 stream
->intern
->indicators
.eof
= 0;
1280 stream
->intern
->offset
= off
;
1285 stream
->intern
->indicators
.err
= 1;
1290 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1291 unbuffered-mode, storing the amount of bytes written in
1294 es_write_nbf (estream_t ES__RESTRICT stream
,
1295 const unsigned char *ES__RESTRICT buffer
,
1296 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1298 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1299 size_t data_written
;
1303 if (bytes_to_write
&& (! func_write
))
1312 while (bytes_to_write
- data_written
)
1314 ret
= (*func_write
) (stream
->intern
->cookie
,
1315 buffer
+ data_written
,
1316 bytes_to_write
- data_written
);
1323 data_written
+= ret
;
1326 stream
->intern
->offset
+= data_written
;
1327 *bytes_written
= data_written
;
1334 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1335 fully-buffered-mode, storing the amount of bytes written in
1338 es_write_fbf (estream_t ES__RESTRICT stream
,
1339 const unsigned char *ES__RESTRICT buffer
,
1340 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1342 size_t space_available
;
1343 size_t data_to_write
;
1344 size_t data_written
;
1350 while ((bytes_to_write
- data_written
) && (! err
))
1352 if (stream
->data_offset
== stream
->buffer_size
)
1353 /* Container full, flush buffer. */
1354 err
= es_flush (stream
);
1358 /* Flushing resulted in empty container. */
1360 data_to_write
= bytes_to_write
- data_written
;
1361 space_available
= stream
->buffer_size
- stream
->data_offset
;
1362 if (data_to_write
> space_available
)
1363 data_to_write
= space_available
;
1365 memcpy (stream
->buffer
+ stream
->data_offset
,
1366 buffer
+ data_written
, data_to_write
);
1367 stream
->data_offset
+= data_to_write
;
1368 data_written
+= data_to_write
;
1372 *bytes_written
= data_written
;
1378 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1379 line-buffered-mode, storing the amount of bytes written in
1382 es_write_lbf (estream_t ES__RESTRICT stream
,
1383 const unsigned char *ES__RESTRICT buffer
,
1384 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1386 size_t data_flushed
= 0;
1387 size_t data_buffered
= 0;
1391 nlp
= memrchr (buffer
, '\n', bytes_to_write
);
1394 /* Found a newline, directly write up to (including) this
1396 err
= es_flush (stream
);
1398 err
= es_write_nbf (stream
, buffer
, nlp
- buffer
+ 1, &data_flushed
);
1403 /* Write remaining data fully buffered. */
1404 err
= es_write_fbf (stream
, buffer
+ data_flushed
,
1405 bytes_to_write
- data_flushed
, &data_buffered
);
1408 *bytes_written
= data_flushed
+ data_buffered
;
1413 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1414 amount of bytes written in BYTES_WRITTEN. */
1416 es_writen (estream_t ES__RESTRICT stream
,
1417 const void *ES__RESTRICT buffer
,
1418 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1420 size_t data_written
;
1426 if (! (stream
->flags
& ES_FLAG_WRITING
))
1428 /* Switching to writing mode -> discard input data and seek to
1429 position at which reading has stopped. We can do this only
1430 if a seek function has been registered. */
1431 if (stream
->intern
->func_seek
)
1433 err
= es_seek (stream
, 0, SEEK_CUR
, NULL
);
1436 if (errno
== ESPIPE
)
1444 switch (stream
->intern
->strategy
)
1447 err
= es_write_nbf (stream
, buffer
, bytes_to_write
, &data_written
);
1451 err
= es_write_lbf (stream
, buffer
, bytes_to_write
, &data_written
);
1455 err
= es_write_fbf (stream
, buffer
, bytes_to_write
, &data_written
);
1462 *bytes_written
= data_written
;
1464 if (! (stream
->flags
& ES_FLAG_WRITING
))
1465 stream
->flags
|= ES_FLAG_WRITING
;
1472 es_peek (estream_t ES__RESTRICT stream
, unsigned char **ES__RESTRICT data
,
1473 size_t *ES__RESTRICT data_len
)
1477 if (stream
->flags
& ES_FLAG_WRITING
)
1479 /* Switching to reading mode -> flush output. */
1480 err
= es_flush (stream
);
1483 stream
->flags
&= ~ES_FLAG_WRITING
;
1486 if (stream
->data_offset
== stream
->data_len
)
1488 /* Refill container. */
1489 err
= es_fill (stream
);
1495 *data
= stream
->buffer
+ stream
->data_offset
;
1497 *data_len
= stream
->data_len
- stream
->data_offset
;
1506 /* Skip SIZE bytes of input data contained in buffer. */
1508 es_skip (estream_t stream
, size_t size
)
1512 if (stream
->data_offset
+ size
> stream
->data_len
)
1519 stream
->data_offset
+= size
;
1528 doreadline (estream_t ES__RESTRICT stream
, size_t max_length
,
1529 char *ES__RESTRICT
*ES__RESTRICT line
,
1530 size_t *ES__RESTRICT line_length
)
1534 estream_t line_stream
;
1536 void *line_stream_cookie
;
1538 unsigned char *data
;
1544 line_stream_cookie
= NULL
;
1546 err
= es_func_mem_create (&line_stream_cookie
, NULL
, 0, 0, BUFFER_BLOCK_SIZE
,
1547 1, 0, 0, NULL
, 0, MEM_REALLOC
, MEM_FREE
, O_RDWR
);
1551 err
= es_create (&line_stream
, line_stream_cookie
, -1,
1552 estream_functions_mem
);
1556 space_left
= max_length
;
1560 if (max_length
&& (space_left
== 1))
1563 err
= es_peek (stream
, &data
, &data_len
);
1564 if (err
|| (! data_len
))
1567 if (data_len
> (space_left
- 1))
1568 data_len
= space_left
- 1;
1570 newline
= memchr (data
, '\n', data_len
);
1573 data_len
= (newline
- (char *) data
) + 1;
1574 err
= es_write (line_stream
, data
, data_len
, NULL
);
1577 space_left
-= data_len
;
1578 line_size
+= data_len
;
1579 es_skip (stream
, data_len
);
1585 err
= es_write (line_stream
, data
, data_len
, NULL
);
1588 space_left
-= data_len
;
1589 line_size
+= data_len
;
1590 es_skip (stream
, data_len
);
1599 /* Complete line has been written to line_stream. */
1601 if ((max_length
> 1) && (! line_size
))
1603 stream
->intern
->indicators
.eof
= 1;
1607 err
= es_seek (line_stream
, 0, SEEK_SET
, NULL
);
1613 line_new
= MEM_ALLOC (line_size
+ 1);
1623 err
= es_read (line_stream
, line_new
, line_size
, NULL
);
1627 line_new
[line_size
] = '\0';
1632 *line_length
= line_size
;
1637 es_destroy (line_stream
);
1638 else if (line_stream_cookie
)
1639 es_func_mem_destroy (line_stream_cookie
);
1644 MEM_FREE (line_new
);
1645 stream
->intern
->indicators
.err
= 1;
1652 /* Helper for esprint. */
1653 #if defined(HAVE_FOPENCOOKIE) || defined(HAVE_FUNOPEN)
1655 print_fun_writer (void *cookie_arg
, const char *buffer
, size_t size
)
1657 estream_t stream
= cookie_arg
;
1660 /* We don't return an error but let es_print check whether an error
1661 has occured. Internally we skip everything after an error. */
1662 if (!stream
->intern
->print_err
)
1664 if (es_writen (stream
, buffer
, size
, &nwritten
))
1666 stream
->intern
->print_err
= 1;
1667 stream
->intern
->print_errno
= errno
;
1670 stream
->intern
->print_ntotal
+= nwritten
;
1674 #endif /* HAVE_FOPENCOOKIE || HAVE_FUNOPEN */
1677 /* The core of our printf function. This is called in locked state. */
1679 es_print (estream_t ES__RESTRICT stream
,
1680 const char *ES__RESTRICT format
, va_list ap
)
1682 #if defined(HAVE_FOPENCOOKIE) || defined(HAVE_FUNOPEN)
1684 if (!stream
->intern
->print_fp
)
1686 #ifdef HAVE_FOPENCOOKIE
1688 cookie_io_functions_t io
= { NULL
};
1689 io
.write
= print_fun_writer
;
1691 stream
->intern
->print_fp
= fopencookie (stream
, "w", io
);
1693 #else /*!HAVE_FOPENCOOKIE*/
1694 stream
->intern
->print_fp
= funopen (stream
, NULL
,
1695 print_fun_writer
, NULL
, NULL
);
1696 #endif /*!HAVE_FOPENCOOKIE*/
1697 if (!stream
->intern
->print_fp
)
1701 stream
->intern
->print_err
= 0;
1702 stream
->intern
->print_errno
= 0;
1703 stream
->intern
->print_ntotal
= 0;
1705 if ( vfprintf (stream
->intern
->print_fp
, format
, ap
) < 0
1706 || fflush (stream
->intern
->print_fp
) )
1708 stream
->intern
->print_errno
= errno
;
1709 stream
->intern
->print_err
= 1;
1710 fclose (stream
->intern
->print_fp
);
1711 stream
->intern
->print_fp
= NULL
;
1713 if (stream
->intern
->print_err
)
1715 errno
= stream
->intern
->print_errno
;
1719 return (int)stream
->intern
->print_ntotal
;
1721 #else /* No funopen or fopencookie. */
1723 char data
[BUFFER_BLOCK_SIZE
];
1725 size_t bytes_written
;
1733 tmp_stream
= tmpfile ();
1740 err
= vfprintf (tmp_stream
, format
, ap
);
1744 err
= fseek (tmp_stream
, 0, SEEK_SET
);
1750 bytes_read
= fread (data
, 1, sizeof (data
), tmp_stream
);
1751 if (ferror (tmp_stream
))
1757 err
= es_writen (stream
, data
, bytes_read
, NULL
);
1761 bytes_written
+= bytes_read
;
1762 if (feof (tmp_stream
))
1770 fclose (tmp_stream
);
1772 return err
? -1 : bytes_written
;
1773 #endif /* no funopen or fopencookie */
1778 es_set_indicators (estream_t stream
, int ind_err
, int ind_eof
)
1781 stream
->intern
->indicators
.err
= ind_err
? 1 : 0;
1783 stream
->intern
->indicators
.eof
= ind_eof
? 1 : 0;
1788 es_get_indicator (estream_t stream
, int ind_err
, int ind_eof
)
1793 ret
= stream
->intern
->indicators
.err
;
1795 ret
= stream
->intern
->indicators
.eof
;
1802 es_set_buffering (estream_t ES__RESTRICT stream
,
1803 char *ES__RESTRICT buffer
, int mode
, size_t size
)
1807 /* Flush or empty buffer depending on mode. */
1808 if (stream
->flags
& ES_FLAG_WRITING
)
1810 err
= es_flush (stream
);
1817 es_set_indicators (stream
, -1, 0);
1819 /* Free old buffer in case that was allocated by this function. */
1820 if (stream
->intern
->deallocate_buffer
)
1822 stream
->intern
->deallocate_buffer
= 0;
1823 MEM_FREE (stream
->buffer
);
1824 stream
->buffer
= NULL
;
1828 stream
->buffer_size
= 0;
1834 buffer_new
= buffer
;
1837 buffer_new
= MEM_ALLOC (size
);
1845 stream
->buffer
= buffer_new
;
1846 stream
->buffer_size
= size
;
1848 stream
->intern
->deallocate_buffer
= 1;
1850 stream
->intern
->strategy
= mode
;
1860 es_offset_calculate (estream_t stream
)
1864 offset
= stream
->intern
->offset
+ stream
->data_offset
;
1865 if (offset
< stream
->unread_data_len
)
1866 /* Offset undefined. */
1869 offset
-= stream
->unread_data_len
;
1876 es_opaque_ctrl (estream_t ES__RESTRICT stream
, void *ES__RESTRICT opaque_new
,
1877 void **ES__RESTRICT opaque_old
)
1880 *opaque_old
= stream
->intern
->opaque
;
1882 stream
->intern
->opaque
= opaque_new
;
1887 es_get_fd (estream_t stream
)
1889 return stream
->intern
->fd
;
1901 err
= es_init_do ();
1907 es_fopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
)
1920 err
= es_convert_mode (mode
, &flags
);
1924 err
= es_func_file_create (&cookie
, &fd
, path
, flags
);
1929 err
= es_create (&stream
, cookie
, fd
, estream_functions_file
);
1935 if (err
&& create_called
)
1936 (*estream_functions_file
.func_close
) (cookie
);
1943 es_mopen (unsigned char *ES__RESTRICT data
, size_t data_n
, size_t data_len
,
1945 func_realloc_t func_realloc
, func_free_t func_free
,
1946 const char *ES__RESTRICT mode
)
1958 err
= es_convert_mode (mode
, &flags
);
1962 err
= es_func_mem_create (&cookie
, data
, data_n
, data_len
,
1963 BUFFER_BLOCK_SIZE
, grow
, 0, 0,
1964 NULL
, 0, func_realloc
, func_free
, flags
);
1969 err
= es_create (&stream
, cookie
, -1, estream_functions_mem
);
1973 if (err
&& create_called
)
1974 (*estream_functions_mem
.func_close
) (cookie
);
1981 es_open_memstream (char **ptr
, size_t *size
)
1994 err
= es_func_mem_create (&cookie
, NULL
, 0, 0,
1995 BUFFER_BLOCK_SIZE
, 1, 1, 1,
1996 ptr
, size
, MEM_REALLOC
, MEM_FREE
, flags
);
2001 err
= es_create (&stream
, cookie
, -1, estream_functions_mem
);
2005 if (err
&& create_called
)
2006 (*estream_functions_mem
.func_close
) (cookie
);
2013 es_fopencookie (void *ES__RESTRICT cookie
,
2014 const char *ES__RESTRICT mode
,
2015 es_cookie_io_functions_t functions
)
2024 err
= es_convert_mode (mode
, &flags
);
2028 err
= es_create (&stream
, cookie
, -1, functions
);
2039 es_fdopen (int filedes
, const char *mode
)
2051 err
= es_convert_mode (mode
, &flags
);
2055 err
= es_func_fd_create (&cookie
, filedes
, flags
);
2060 err
= es_create (&stream
, cookie
, filedes
, estream_functions_fd
);
2064 if (err
&& create_called
)
2065 (*estream_functions_fd
.func_close
) (cookie
);
2072 es_freopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
,
2073 estream_t ES__RESTRICT stream
)
2087 ESTREAM_LOCK (stream
);
2089 es_deinitialize (stream
);
2091 err
= es_convert_mode (mode
, &flags
);
2095 err
= es_func_file_create (&cookie
, &fd
, path
, flags
);
2100 es_initialize (stream
, cookie
, fd
, estream_functions_file
);
2107 es_func_fd_destroy (cookie
);
2109 es_destroy (stream
);
2113 ESTREAM_UNLOCK (stream
);
2117 /* FIXME? We don't support re-opening at the moment. */
2119 es_deinitialize (stream
);
2120 es_destroy (stream
);
2129 es_fclose (estream_t stream
)
2133 err
= es_destroy (stream
);
2139 es_fileno_unlocked (estream_t stream
)
2141 return es_get_fd (stream
);
2146 es_flockfile (estream_t stream
)
2148 ESTREAM_LOCK (stream
);
2153 es_ftrylockfile (estream_t stream
)
2155 return ESTREAM_TRYLOCK (stream
);
2160 es_funlockfile (estream_t stream
)
2162 ESTREAM_UNLOCK (stream
);
2167 es_fileno (estream_t stream
)
2171 ESTREAM_LOCK (stream
);
2172 ret
= es_fileno_unlocked (stream
);
2173 ESTREAM_UNLOCK (stream
);
2180 es_feof_unlocked (estream_t stream
)
2182 return es_get_indicator (stream
, 0, 1);
2187 es_feof (estream_t stream
)
2191 ESTREAM_LOCK (stream
);
2192 ret
= es_feof_unlocked (stream
);
2193 ESTREAM_UNLOCK (stream
);
2200 es_ferror_unlocked (estream_t stream
)
2202 return es_get_indicator (stream
, 1, 0);
2207 es_ferror (estream_t stream
)
2211 ESTREAM_LOCK (stream
);
2212 ret
= es_ferror_unlocked (stream
);
2213 ESTREAM_UNLOCK (stream
);
2220 es_clearerr_unlocked (estream_t stream
)
2222 es_set_indicators (stream
, 0, 0);
2227 es_clearerr (estream_t stream
)
2229 ESTREAM_LOCK (stream
);
2230 es_clearerr_unlocked (stream
);
2231 ESTREAM_UNLOCK (stream
);
2236 es_fflush (estream_t stream
)
2242 ESTREAM_LOCK (stream
);
2243 if (stream
->flags
& ES_FLAG_WRITING
)
2244 err
= es_flush (stream
);
2250 ESTREAM_UNLOCK (stream
);
2253 err
= es_list_iterate (es_fflush
);
2255 return err
? EOF
: 0;
2260 es_fseek (estream_t stream
, long int offset
, int whence
)
2264 ESTREAM_LOCK (stream
);
2265 err
= es_seek (stream
, offset
, whence
, NULL
);
2266 ESTREAM_UNLOCK (stream
);
2273 es_fseeko (estream_t stream
, off_t offset
, int whence
)
2277 ESTREAM_LOCK (stream
);
2278 err
= es_seek (stream
, offset
, whence
, NULL
);
2279 ESTREAM_UNLOCK (stream
);
2286 es_ftell (estream_t stream
)
2290 ESTREAM_LOCK (stream
);
2291 ret
= es_offset_calculate (stream
);
2292 ESTREAM_UNLOCK (stream
);
2299 es_ftello (estream_t stream
)
2303 ESTREAM_LOCK (stream
);
2304 ret
= es_offset_calculate (stream
);
2305 ESTREAM_UNLOCK (stream
);
2312 es_rewind (estream_t stream
)
2314 ESTREAM_LOCK (stream
);
2315 es_seek (stream
, 0L, SEEK_SET
, NULL
);
2316 es_set_indicators (stream
, 0, -1);
2317 ESTREAM_UNLOCK (stream
);
2322 _es_getc_underflow (estream_t stream
)
2328 err
= es_readn (stream
, &c
, 1, &bytes_read
);
2330 return (err
|| (! bytes_read
)) ? EOF
: c
;
2335 _es_putc_overflow (int c
, estream_t stream
)
2337 unsigned char d
= c
;
2340 err
= es_writen (stream
, &d
, 1, NULL
);
2342 return err
? EOF
: c
;
2347 es_fgetc (estream_t stream
)
2351 ESTREAM_LOCK (stream
);
2352 ret
= es_getc_unlocked (stream
);
2353 ESTREAM_UNLOCK (stream
);
2360 es_fputc (int c
, estream_t stream
)
2364 ESTREAM_LOCK (stream
);
2365 ret
= es_putc_unlocked (c
, stream
);
2366 ESTREAM_UNLOCK (stream
);
2373 es_ungetc (int c
, estream_t stream
)
2375 unsigned char data
= (unsigned char) c
;
2378 ESTREAM_LOCK (stream
);
2379 es_unreadn (stream
, &data
, 1, &data_unread
);
2380 ESTREAM_UNLOCK (stream
);
2382 return data_unread
? c
: EOF
;
2387 es_read (estream_t ES__RESTRICT stream
,
2388 void *ES__RESTRICT buffer
, size_t bytes_to_read
,
2389 size_t *ES__RESTRICT bytes_read
)
2395 ESTREAM_LOCK (stream
);
2396 err
= es_readn (stream
, buffer
, bytes_to_read
, bytes_read
);
2397 ESTREAM_UNLOCK (stream
);
2407 es_write (estream_t ES__RESTRICT stream
,
2408 const void *ES__RESTRICT buffer
, size_t bytes_to_write
,
2409 size_t *ES__RESTRICT bytes_written
)
2415 ESTREAM_LOCK (stream
);
2416 err
= es_writen (stream
, buffer
, bytes_to_write
, bytes_written
);
2417 ESTREAM_UNLOCK (stream
);
2427 es_fread (void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2428 estream_t ES__RESTRICT stream
)
2435 ESTREAM_LOCK (stream
);
2436 err
= es_readn (stream
, ptr
, size
* nitems
, &bytes
);
2437 ESTREAM_UNLOCK (stream
);
2449 es_fwrite (const void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2450 estream_t ES__RESTRICT stream
)
2457 ESTREAM_LOCK (stream
);
2458 err
= es_writen (stream
, ptr
, size
* nitems
, &bytes
);
2459 ESTREAM_UNLOCK (stream
);
2471 es_fgets (char *ES__RESTRICT s
, int n
, estream_t ES__RESTRICT stream
)
2479 ESTREAM_LOCK (stream
);
2480 err
= doreadline (stream
, n
, &s
, NULL
);
2481 ESTREAM_UNLOCK (stream
);
2491 es_fputs (const char *ES__RESTRICT s
, estream_t ES__RESTRICT stream
)
2496 length
= strlen (s
);
2497 ESTREAM_LOCK (stream
);
2498 err
= es_writen (stream
, s
, length
, NULL
);
2499 ESTREAM_UNLOCK (stream
);
2501 return err
? EOF
: 0;
2506 es_getline (char *ES__RESTRICT
*ES__RESTRICT lineptr
, size_t *ES__RESTRICT n
,
2507 estream_t ES__RESTRICT stream
)
2513 ESTREAM_LOCK (stream
);
2514 err
= doreadline (stream
, 0, &line
, &line_n
);
2515 ESTREAM_UNLOCK (stream
);
2521 /* Caller wants us to use his buffer. */
2523 if (*n
< (line_n
+ 1))
2525 /* Provided buffer is too small -> resize. */
2529 p
= MEM_REALLOC (*lineptr
, line_n
+ 1);
2541 memcpy (*lineptr
, line
, line_n
+ 1);
2549 /* Caller wants new buffers. */
2556 return err
? err
: line_n
;
2561 /* Same as fgets() but if the provided buffer is too short a larger
2562 one will be allocated. This is similar to getline. A line is
2563 considered a byte stream ending in a LF.
2565 If MAX_LENGTH is not NULL, it shall point to a value with the
2566 maximum allowed allocation.
2568 Returns the length of the line. EOF is indicated by a line of
2569 length zero. A truncated line is indicated my setting the value at
2570 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2571 memory was enable or another error occurred; ERRNO is then set
2574 If a line has been truncated, the file pointer is moved forward to
2575 the end of the line so that the next read starts with the next
2576 line. Note that MAX_LENGTH must be re-initialzied in this case.
2578 The caller initially needs to provide the address of a variable,
2579 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2580 anymore with the following invocations. LENGTH_OF_BUFFER should be
2581 the address of a variable, initialized to 0, which is also
2582 maintained by this function. Thus, both paramaters should be
2583 considered the state of this function.
2585 Note: The returned buffer is allocated with enough extra space to
2586 allow the caller to append a CR,LF,Nul. The buffer should be
2587 released using es_free.
2590 es_read_line (estream_t stream
,
2591 char **addr_of_buffer
, size_t *length_of_buffer
,
2595 char *buffer
= *addr_of_buffer
;
2596 size_t length
= *length_of_buffer
;
2598 size_t maxlen
= max_length
? *max_length
: 0;
2603 /* No buffer given - allocate a new one. */
2605 buffer
= MEM_ALLOC (length
);
2606 *addr_of_buffer
= buffer
;
2609 *length_of_buffer
= 0;
2614 *length_of_buffer
= length
;
2619 /* This should never happen. If it does, the fucntion has been
2620 called with wrong arguments. */
2624 length
-= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2626 ESTREAM_LOCK (stream
);
2628 while ((c
= es_getc_unlocked (stream
)) != EOF
)
2630 if (nbytes
== length
)
2632 /* Enlarge the buffer. */
2633 if (maxlen
&& length
> maxlen
)
2635 /* We are beyond our limit: Skip the rest of the line. */
2636 while (c
!= '\n' && (c
=es_getc_unlocked (stream
)) != EOF
)
2638 *p
++ = '\n'; /* Always append a LF (we reserved some space). */
2641 *max_length
= 0; /* Indicate truncation. */
2642 break; /* the while loop. */
2644 length
+= 3; /* Adjust for the reserved bytes. */
2645 length
+= length
< 1024? 256 : 1024;
2646 *addr_of_buffer
= MEM_REALLOC (buffer
, length
);
2647 if (!*addr_of_buffer
)
2649 int save_errno
= errno
;
2651 *length_of_buffer
= *max_length
= 0;
2652 ESTREAM_UNLOCK (stream
);
2656 buffer
= *addr_of_buffer
;
2657 *length_of_buffer
= length
;
2659 p
= buffer
+ nbytes
;
2666 *p
= 0; /* Make sure the line is a string. */
2667 ESTREAM_UNLOCK (stream
);
2672 /* Wrapper around free() to match the memory allocation system used
2673 by estream. Should be used for all buffers returned to the caller
2684 es_vfprintf (estream_t ES__RESTRICT stream
, const char *ES__RESTRICT format
,
2689 ESTREAM_LOCK (stream
);
2690 ret
= es_print (stream
, format
, ap
);
2691 ESTREAM_UNLOCK (stream
);
2698 es_fprintf (estream_t ES__RESTRICT stream
,
2699 const char *ES__RESTRICT format
, ...)
2704 va_start (ap
, format
);
2705 ESTREAM_LOCK (stream
);
2706 ret
= es_print (stream
, format
, ap
);
2707 ESTREAM_UNLOCK (stream
);
2727 fp_fd
= fileno (fp
);
2750 flags
= O_RDWR
| O_TRUNC
| O_CREAT
;
2760 err
= es_func_fd_create (&cookie
, fd
, flags
);
2765 err
= es_create (&stream
, cookie
, fd
, estream_functions_fd
);
2772 es_func_fd_destroy (cookie
);
2783 es_setvbuf (estream_t ES__RESTRICT stream
,
2784 char *ES__RESTRICT buf
, int type
, size_t size
)
2788 if (((type
== _IOFBF
) || (type
== _IOLBF
) || (type
== _IONBF
))
2789 && (! ((! size
) && (type
!= _IONBF
))))
2791 ESTREAM_LOCK (stream
);
2792 err
= es_set_buffering (stream
, buf
, type
, size
);
2793 ESTREAM_UNLOCK (stream
);
2806 es_setbuf (estream_t ES__RESTRICT stream
, char *ES__RESTRICT buf
)
2808 ESTREAM_LOCK (stream
);
2809 es_set_buffering (stream
, buf
, buf
? _IOFBF
: _IONBF
, BUFSIZ
);
2810 ESTREAM_UNLOCK (stream
);
2814 es_opaque_set (estream_t stream
, void *opaque
)
2816 ESTREAM_LOCK (stream
);
2817 es_opaque_ctrl (stream
, opaque
, NULL
);
2818 ESTREAM_UNLOCK (stream
);
2823 es_opaque_get (estream_t stream
)
2827 ESTREAM_LOCK (stream
);
2828 es_opaque_ctrl (stream
, NULL
, &opaque
);
2829 ESTREAM_UNLOCK (stream
);