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>
47 int mkstemp (char *template);
51 void *memrchr (const void *block
, int c
, size_t size
);
58 /* Generally used types. */
60 typedef void *(*func_realloc_t
) (void *mem
, size_t size
);
61 typedef void (*func_free_t
) (void *mem
);
65 /* Buffer management layer. */
67 #define BUFFER_BLOCK_SIZE BUFSIZ
68 #define BUFFER_UNREAD_SIZE 16
74 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
75 (((size) + (block_size - 1)) / block_size)
83 typedef pth_mutex_t estream_mutex_t
;
84 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
85 # define ESTREAM_MUTEX_LOCK(mutex) \
86 pth_mutex_acquire (&(mutex), 0, NULL)
87 # define ESTREAM_MUTEX_UNLOCK(mutex) \
88 pth_mutex_release (&(mutex))
89 # define ESTREAM_MUTEX_TRYLOCK(mutex) \
90 ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
91 # define ESTREAM_MUTEX_INITIALIZE(mutex) \
92 pth_mutex_init (&(mutex))
93 # define ESTREAM_THREADING_INIT() ((pth_init () == TRUE) ? 0 : -1)
97 typedef void *estream_mutex_t
;
98 # define ESTREAM_MUTEX_INITIALIZER NULL
99 # define ESTREAM_MUTEX_LOCK(mutex) (void) 0
100 # define ESTREAM_MUTEX_UNLOCK(mutex) (void) 0
101 # define ESTREAM_MUTEX_TRYLOCK(mutex) 0
102 # define ESTREAM_MUTEX_INITIALIZE(mutex) (void) 0
103 # define ESTREAM_THREADING_INIT() 0
107 /* Memory allocator functions. */
109 #define MEM_ALLOC malloc
110 #define MEM_REALLOC realloc
111 #define MEM_FREE free
113 /* Primitive system I/O. */
116 # define ESTREAM_SYS_READ pth_read
117 # define ESTREAM_SYS_WRITE pth_write
119 # define ESTREAM_SYS_READ read
120 # define ESTREAM_SYS_WRITE write
123 /* Misc definitions. */
125 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
127 #define ES_FLAG_WRITING ES__FLAG_WRITING
129 /* An internal stream object. */
131 struct estream_internal
133 unsigned char buffer
[BUFFER_BLOCK_SIZE
];
134 unsigned char unread_buffer
[BUFFER_UNREAD_SIZE
];
135 estream_mutex_t lock
; /* Lock. */
136 void *cookie
; /* Cookie. */
137 void *opaque
; /* Opaque data. */
138 unsigned int flags
; /* Flags. */
140 es_cookie_read_function_t func_read
;
141 es_cookie_write_function_t func_write
;
142 es_cookie_seek_function_t func_seek
;
143 es_cookie_close_function_t func_close
;
151 unsigned int deallocate_buffer
: 1;
154 typedef struct estream_internal
*estream_internal_t
;
156 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
157 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
158 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
162 typedef struct estream_list
*estream_list_t
;
168 estream_list_t
*prev_cdr
;
171 static estream_list_t estream_list
;
173 static estream_mutex_t estream_list_lock
= ESTREAM_MUTEX_INITIALIZER
;
176 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
177 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
180 # define EOPNOTSUPP ENOSYS
188 /* Calculate array dimension. */
189 #define DIM(array) (sizeof (array) / sizeof (*array))
191 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
193 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
196 tmp_variable = expression; \
197 if ((! variable) && tmp_variable) \
198 variable = tmp_variable; \
206 /* Add STREAM to the list of registered stream objects. */
208 es_list_add (estream_t stream
)
210 estream_list_t list_obj
;
213 list_obj
= MEM_ALLOC (sizeof (*list_obj
));
219 list_obj
->car
= stream
;
220 list_obj
->cdr
= estream_list
;
221 list_obj
->prev_cdr
= &estream_list
;
223 estream_list
->prev_cdr
= &list_obj
->cdr
;
224 estream_list
= list_obj
;
232 /* Remove STREAM from the list of registered stream objects. */
234 es_list_remove (estream_t stream
)
236 estream_list_t list_obj
;
239 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
240 if (list_obj
->car
== stream
)
242 *list_obj
->prev_cdr
= list_obj
->cdr
;
244 list_obj
->cdr
->prev_cdr
= list_obj
->prev_cdr
;
251 /* Type of an stream-iterator-function. */
252 typedef int (*estream_iterator_t
) (estream_t stream
);
254 /* Iterate over list of registered streams, calling ITERATOR for each
257 es_list_iterate (estream_iterator_t iterator
)
259 estream_list_t list_obj
;
263 for (list_obj
= estream_list
; list_obj
; list_obj
= list_obj
->cdr
)
264 ret
|= (*iterator
) (list_obj
->car
);
281 err
= ESTREAM_THREADING_INIT ();
292 /* Implementation of Memory I/O. */
294 /* Cookie for memory objects. */
295 typedef struct estream_cookie_mem
297 unsigned int flags
; /* Open flags. */
298 unsigned char *memory
; /* Data. */
299 size_t memory_size
; /* Size of MEMORY. */
300 size_t offset
; /* Current offset in MEMORY. */
301 size_t data_len
; /* Length of data in MEMORY. */
302 size_t block_size
; /* Block size. */
303 unsigned int grow
: 1; /* MEMORY is allowed to grow. */
304 unsigned int append_zero
: 1; /* Append zero after data. */
305 unsigned int dont_free
: 1; /* Append zero after data. */
308 func_realloc_t func_realloc
;
309 func_free_t func_free
;
310 } *estream_cookie_mem_t
;
312 /* Create function for memory objects. */
314 es_func_mem_create (void *ES__RESTRICT
*ES__RESTRICT cookie
,
315 unsigned char *ES__RESTRICT data
, size_t data_n
,
317 size_t block_size
, unsigned int grow
,
318 unsigned int append_zero
, unsigned int dont_free
,
319 char **ptr
, size_t *size
,
320 func_realloc_t func_realloc
, func_free_t func_free
,
323 estream_cookie_mem_t mem_cookie
;
326 mem_cookie
= MEM_ALLOC (sizeof (*mem_cookie
));
331 mem_cookie
->flags
= flags
;
332 mem_cookie
->memory
= data
;
333 mem_cookie
->memory_size
= data_n
;
334 mem_cookie
->offset
= 0;
335 mem_cookie
->data_len
= data_len
;
336 mem_cookie
->block_size
= block_size
;
337 mem_cookie
->grow
= grow
? 1 : 0;
338 mem_cookie
->append_zero
= append_zero
? 1 : 0;
339 mem_cookie
->dont_free
= dont_free
? 1 : 0;
340 mem_cookie
->ptr
= ptr
;
341 mem_cookie
->size
= size
;
342 mem_cookie
->func_realloc
= func_realloc
? func_realloc
: MEM_REALLOC
;
343 mem_cookie
->func_free
= func_free
? func_free
: MEM_FREE
;
344 mem_cookie
->offset
= 0;
345 *cookie
= mem_cookie
;
352 /* Read function for memory objects. */
354 es_func_mem_read (void *cookie
, void *buffer
, size_t size
)
356 estream_cookie_mem_t mem_cookie
= cookie
;
359 if (size
> mem_cookie
->data_len
- mem_cookie
->offset
)
360 size
= mem_cookie
->data_len
- mem_cookie
->offset
;
364 memcpy (buffer
, mem_cookie
->memory
+ mem_cookie
->offset
, size
);
365 mem_cookie
->offset
+= size
;
373 /* Write function for memory objects. */
375 es_func_mem_write (void *cookie
, const void *buffer
, size_t size
)
377 estream_cookie_mem_t mem_cookie
= cookie
;
378 func_realloc_t func_realloc
= mem_cookie
->func_realloc
;
379 unsigned char *memory_new
;
388 if (mem_cookie
->flags
& O_APPEND
)
389 /* Append to data. */
390 mem_cookie
->offset
= mem_cookie
->data_len
;
392 if (! mem_cookie
->grow
)
393 if (size
> mem_cookie
->memory_size
- mem_cookie
->offset
)
394 size
= mem_cookie
->memory_size
- mem_cookie
->offset
;
398 while (size
> (mem_cookie
->memory_size
- mem_cookie
->offset
))
400 memory_new
= (*func_realloc
) (mem_cookie
->memory
,
401 mem_cookie
->memory_size
402 + mem_cookie
->block_size
);
410 if (mem_cookie
->memory
!= memory_new
)
411 mem_cookie
->memory
= memory_new
;
412 mem_cookie
->memory_size
+= mem_cookie
->block_size
;
420 memcpy (mem_cookie
->memory
+ mem_cookie
->offset
, buffer
, size
);
421 if (mem_cookie
->offset
+ size
> mem_cookie
->data_len
)
422 mem_cookie
->data_len
= mem_cookie
->offset
+ size
;
423 mem_cookie
->offset
+= size
;
431 if (mem_cookie
->append_zero
)
433 if (mem_cookie
->data_len
>= mem_cookie
->memory_size
)
435 newsize
= BUFFER_ROUND_TO_BLOCK (mem_cookie
->data_len
+ 1,
436 mem_cookie
->block_size
)
437 * mem_cookie
->block_size
;
439 memory_new
= (*func_realloc
) (mem_cookie
->memory
, newsize
);
446 if (mem_cookie
->memory
!= memory_new
)
447 mem_cookie
->memory
= memory_new
;
448 mem_cookie
->memory_size
= newsize
;
451 mem_cookie
->memory
[mem_cookie
->data_len
+ 1] = 0;
454 /* Return information to user if necessary. */
456 *mem_cookie
->ptr
= (char *) mem_cookie
->memory
;
457 if (mem_cookie
->size
)
458 *mem_cookie
->size
= mem_cookie
->data_len
;
471 /* Seek function for memory objects. */
473 es_func_mem_seek (void *cookie
, off_t
*offset
, int whence
)
475 estream_cookie_mem_t mem_cookie
= cookie
;
486 pos_new
= mem_cookie
->offset
+= *offset
;
490 pos_new
= mem_cookie
->data_len
+= *offset
;
498 if (pos_new
> mem_cookie
->memory_size
)
500 /* Grow buffer if possible. */
502 if (mem_cookie
->grow
)
504 func_realloc_t func_realloc
= mem_cookie
->func_realloc
;
508 newsize
= BUFFER_ROUND_TO_BLOCK (pos_new
, mem_cookie
->block_size
);
509 p
= (*func_realloc
) (mem_cookie
->memory
, newsize
);
517 if (mem_cookie
->memory
!= p
)
518 mem_cookie
->memory
= p
;
519 mem_cookie
->memory_size
= newsize
;
530 if (pos_new
> mem_cookie
->data_len
)
531 /* Fill spare space with zeroes. */
532 memset (mem_cookie
->memory
+ mem_cookie
->data_len
,
533 0, pos_new
- mem_cookie
->data_len
);
535 mem_cookie
->offset
= pos_new
;
543 /* Destroy function for memory objects. */
545 es_func_mem_destroy (void *cookie
)
547 estream_cookie_mem_t mem_cookie
= cookie
;
548 func_free_t func_free
= mem_cookie
->func_free
;
550 if (! mem_cookie
->dont_free
)
551 (*func_free
) (mem_cookie
->memory
);
552 MEM_FREE (mem_cookie
);
557 static es_cookie_io_functions_t estream_functions_mem
=
565 /* Implementation of fd I/O. */
567 /* Cookie for fd objects. */
568 typedef struct estream_cookie_fd
571 } *estream_cookie_fd_t
;
573 /* Create function for fd objects. */
575 es_func_fd_create (void **cookie
, int fd
, unsigned int flags
)
577 estream_cookie_fd_t fd_cookie
;
580 fd_cookie
= MEM_ALLOC (sizeof (*fd_cookie
));
593 /* Read function for fd objects. */
595 es_func_fd_read (void *cookie
, void *buffer
, size_t size
)
598 estream_cookie_fd_t file_cookie
= cookie
;
602 bytes_read
= ESTREAM_SYS_READ (file_cookie
->fd
, buffer
, size
);
603 while (bytes_read
== -1 && errno
== EINTR
);
608 /* Write function for fd objects. */
610 es_func_fd_write (void *cookie
, const void *buffer
, size_t size
)
613 estream_cookie_fd_t file_cookie
= cookie
;
614 ssize_t bytes_written
;
617 bytes_written
= ESTREAM_SYS_WRITE (file_cookie
->fd
, buffer
, size
);
618 while (bytes_written
== -1 && errno
== EINTR
);
620 return bytes_written
;
623 /* Seek function for fd objects. */
625 es_func_fd_seek (void *cookie
, off_t
*offset
, int whence
)
627 estream_cookie_fd_t file_cookie
= cookie
;
631 offset_new
= lseek (file_cookie
->fd
, *offset
, whence
);
632 if (offset_new
== -1)
636 *offset
= offset_new
;
643 /* Destroy function for fd objects. */
645 es_func_fd_destroy (void *cookie
)
647 estream_cookie_fd_t fd_cookie
= cookie
;
652 err
= close (fd_cookie
->fd
);
653 MEM_FREE (fd_cookie
);
661 static es_cookie_io_functions_t estream_functions_fd
=
669 /* Implementation of file I/O. */
671 /* Create function for file objects. */
673 es_func_file_create (void **cookie
, int *filedes
,
674 const char *path
, unsigned int flags
)
676 estream_cookie_fd_t file_cookie
;
683 file_cookie
= MEM_ALLOC (sizeof (*file_cookie
));
690 fd
= open (path
, flags
, ES_DEFAULT_OPEN_MODE
);
697 file_cookie
->fd
= fd
;
698 *cookie
= file_cookie
;
704 MEM_FREE (file_cookie
);
709 static es_cookie_io_functions_t estream_functions_file
=
719 /* Stream primitives. */
722 es_convert_mode (const char *mode
, unsigned int *flags
)
728 } mode_flags
[] = { { "r",
733 O_WRONLY
| O_TRUNC
| O_CREAT
},
735 O_WRONLY
| O_TRUNC
| O_CREAT
},
737 O_WRONLY
| O_APPEND
| O_CREAT
},
739 O_WRONLY
| O_APPEND
| O_CREAT
},
745 O_RDONLY
| O_WRONLY
},
747 O_RDWR
| O_TRUNC
| O_CREAT
},
749 O_RDWR
| O_TRUNC
| O_CREAT
},
751 O_RDWR
| O_TRUNC
| O_CREAT
},
753 O_RDWR
| O_CREAT
| O_APPEND
},
755 O_RDWR
| O_CREAT
| O_APPEND
},
757 O_RDWR
| O_CREAT
| O_APPEND
} };
761 for (i
= 0; i
< DIM (mode_flags
); i
++)
762 if (! strcmp (mode_flags
[i
].mode
, mode
))
764 if (i
== DIM (mode_flags
))
772 *flags
= mode_flags
[i
].flags
;
781 * Low level stream functionality.
785 es_fill (estream_t stream
)
787 size_t bytes_read
= 0;
790 if (!stream
->intern
->func_read
)
797 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
800 ret
= (*func_read
) (stream
->intern
->cookie
,
801 stream
->buffer
, stream
->buffer_size
);
815 stream
->intern
->indicators
.err
= 1;
816 else if (!bytes_read
)
817 stream
->intern
->indicators
.eof
= 1;
819 stream
->intern
->offset
+= stream
->data_len
;
820 stream
->data_len
= bytes_read
;
821 stream
->data_offset
= 0;
827 es_flush (estream_t stream
)
829 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
832 assert (stream
->flags
& ES_FLAG_WRITING
);
834 if (stream
->data_offset
)
836 size_t bytes_written
;
846 /* Note: to prevent an endless loop caused by user-provided
847 write-functions that pretend to have written more bytes than
848 they were asked to write, we have to check for
849 "(stream->data_offset - data_flushed) > 0" instead of
850 "stream->data_offset - data_flushed". */
855 while ((((ssize_t
) (stream
->data_offset
- data_flushed
)) > 0) && (! err
))
857 ret
= (*func_write
) (stream
->intern
->cookie
,
858 stream
->buffer
+ data_flushed
,
859 stream
->data_offset
- data_flushed
);
868 data_flushed
+= bytes_written
;
873 stream
->data_flushed
+= data_flushed
;
874 if (stream
->data_offset
== data_flushed
)
876 stream
->intern
->offset
+= stream
->data_offset
;
877 stream
->data_offset
= 0;
878 stream
->data_flushed
= 0;
880 /* Propagate flush event. */
881 (*func_write
) (stream
->intern
->cookie
, NULL
, 0);
890 stream
->intern
->indicators
.err
= 1;
895 /* Discard buffered data for STREAM. */
897 es_empty (estream_t stream
)
899 assert (! (stream
->flags
& ES_FLAG_WRITING
));
900 stream
->data_len
= 0;
901 stream
->data_offset
= 0;
902 stream
->unread_data_len
= 0;
905 /* Initialize STREAM. */
907 es_initialize (estream_t stream
,
908 void *cookie
, int fd
, es_cookie_io_functions_t functions
)
910 stream
->intern
->cookie
= cookie
;
911 stream
->intern
->opaque
= NULL
;
912 stream
->intern
->offset
= 0;
913 stream
->intern
->func_read
= functions
.func_read
;
914 stream
->intern
->func_write
= functions
.func_write
;
915 stream
->intern
->func_seek
= functions
.func_seek
;
916 stream
->intern
->func_close
= functions
.func_close
;
917 stream
->intern
->strategy
= _IOFBF
;
918 stream
->intern
->fd
= fd
;
919 stream
->intern
->indicators
.err
= 0;
920 stream
->intern
->indicators
.eof
= 0;
921 stream
->intern
->deallocate_buffer
= 0;
923 stream
->data_len
= 0;
924 stream
->data_offset
= 0;
925 stream
->data_flushed
= 0;
926 stream
->unread_data_len
= 0;
930 /* Deinitialize STREAM. */
932 es_deinitialize (estream_t stream
)
934 es_cookie_close_function_t func_close
;
937 func_close
= stream
->intern
->func_close
;
940 if (stream
->flags
& ES_FLAG_WRITING
)
941 SET_UNLESS_NONZERO (err
, tmp_err
, es_flush (stream
));
943 SET_UNLESS_NONZERO (err
, tmp_err
, (*func_close
) (stream
->intern
->cookie
));
948 /* Create a new stream object, initialize it. */
950 es_create (estream_t
*stream
, void *cookie
, int fd
,
951 es_cookie_io_functions_t functions
)
953 estream_internal_t stream_internal_new
;
954 estream_t stream_new
;
958 stream_internal_new
= NULL
;
960 stream_new
= MEM_ALLOC (sizeof (*stream_new
));
967 stream_internal_new
= MEM_ALLOC (sizeof (*stream_internal_new
));
968 if (! stream_internal_new
)
974 stream_new
->buffer
= stream_internal_new
->buffer
;
975 stream_new
->buffer_size
= sizeof (stream_internal_new
->buffer
);
976 stream_new
->unread_buffer
= stream_internal_new
->unread_buffer
;
977 stream_new
->unread_buffer_size
= sizeof (stream_internal_new
->unread_buffer
);
978 stream_new
->intern
= stream_internal_new
;
980 ESTREAM_MUTEX_INITIALIZE (stream_new
->intern
->lock
);
981 es_initialize (stream_new
, cookie
, fd
, functions
);
983 err
= es_list_add (stream_new
);
987 *stream
= stream_new
;
995 es_deinitialize (stream_new
);
996 MEM_FREE (stream_new
);
1003 /* Deinitialize a stream object and destroy it. */
1005 es_destroy (estream_t stream
)
1011 es_list_remove (stream
);
1012 err
= es_deinitialize (stream
);
1013 MEM_FREE (stream
->intern
);
1020 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1021 unbuffered-mode, storing the amount of bytes read in
1024 es_read_nbf (estream_t ES__RESTRICT stream
,
1025 unsigned char *ES__RESTRICT buffer
,
1026 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1028 es_cookie_read_function_t func_read
= stream
->intern
->func_read
;
1036 while (bytes_to_read
- data_read
)
1038 ret
= (*func_read
) (stream
->intern
->cookie
,
1039 buffer
+ data_read
, bytes_to_read
- data_read
);
1051 stream
->intern
->offset
+= data_read
;
1052 *bytes_read
= data_read
;
1057 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1058 fully-buffered-mode, storing the amount of bytes read in
1061 es_read_fbf (estream_t ES__RESTRICT stream
,
1062 unsigned char *ES__RESTRICT buffer
,
1063 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1065 size_t data_available
;
1066 size_t data_to_read
;
1073 while ((bytes_to_read
- data_read
) && (! err
))
1075 if (stream
->data_offset
== stream
->data_len
)
1077 /* Nothing more to read in current container, try to
1078 fill container with new data. */
1079 err
= es_fill (stream
);
1081 if (! stream
->data_len
)
1082 /* Filling did not result in any data read. */
1088 /* Filling resulted in some new data. */
1090 data_to_read
= bytes_to_read
- data_read
;
1091 data_available
= stream
->data_len
- stream
->data_offset
;
1092 if (data_to_read
> data_available
)
1093 data_to_read
= data_available
;
1095 memcpy (buffer
+ data_read
,
1096 stream
->buffer
+ stream
->data_offset
, data_to_read
);
1097 stream
->data_offset
+= data_to_read
;
1098 data_read
+= data_to_read
;
1102 *bytes_read
= data_read
;
1107 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1108 line-buffered-mode, storing the amount of bytes read in
1111 es_read_lbf (estream_t ES__RESTRICT stream
,
1112 unsigned char *ES__RESTRICT buffer
,
1113 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1117 err
= es_read_fbf (stream
, buffer
, bytes_to_read
, bytes_read
);
1122 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1123 *the amount of bytes read in BYTES_READ. */
1125 es_readn (estream_t ES__RESTRICT stream
,
1126 void *ES__RESTRICT buffer_arg
,
1127 size_t bytes_to_read
, size_t *ES__RESTRICT bytes_read
)
1129 unsigned char *buffer
= (unsigned char *)buffer_arg
;
1130 size_t data_read_unread
, data_read
;
1133 data_read_unread
= 0;
1137 if (stream
->flags
& ES_FLAG_WRITING
)
1139 /* Switching to reading mode -> flush output. */
1140 err
= es_flush (stream
);
1143 stream
->flags
&= ~ES_FLAG_WRITING
;
1146 /* Read unread data first. */
1147 while ((bytes_to_read
- data_read_unread
) && stream
->unread_data_len
)
1149 buffer
[data_read_unread
]
1150 = stream
->unread_buffer
[stream
->unread_data_len
- 1];
1151 stream
->unread_data_len
--;
1155 switch (stream
->intern
->strategy
)
1158 err
= es_read_nbf (stream
,
1159 buffer
+ data_read_unread
,
1160 bytes_to_read
- data_read_unread
, &data_read
);
1163 err
= es_read_lbf (stream
,
1164 buffer
+ data_read_unread
,
1165 bytes_to_read
- data_read_unread
, &data_read
);
1168 err
= es_read_fbf (stream
,
1169 buffer
+ data_read_unread
,
1170 bytes_to_read
- data_read_unread
, &data_read
);
1177 *bytes_read
= data_read_unread
+ data_read
;
1182 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1183 amount of bytes succesfully unread in *BYTES_UNREAD. */
1185 es_unreadn (estream_t ES__RESTRICT stream
,
1186 const unsigned char *ES__RESTRICT data
, size_t data_n
,
1187 size_t *ES__RESTRICT bytes_unread
)
1191 space_left
= stream
->unread_buffer_size
- stream
->unread_data_len
;
1193 if (data_n
> space_left
)
1194 data_n
= space_left
;
1199 memcpy (stream
->unread_buffer
+ stream
->unread_data_len
, data
, data_n
);
1200 stream
->unread_data_len
+= data_n
;
1201 stream
->intern
->indicators
.eof
= 0;
1206 *bytes_unread
= data_n
;
1209 /* Seek in STREAM. */
1211 es_seek (estream_t ES__RESTRICT stream
, off_t offset
, int whence
,
1212 off_t
*ES__RESTRICT offset_new
)
1214 es_cookie_seek_function_t func_seek
= stream
->intern
->func_seek
;
1225 if (stream
->flags
& ES_FLAG_WRITING
)
1227 /* Flush data first in order to prevent flushing it to the wrong
1229 err
= es_flush (stream
);
1232 stream
->flags
&= ~ES_FLAG_WRITING
;
1236 if (whence
== SEEK_CUR
)
1238 off
= off
- stream
->data_len
+ stream
->data_offset
;
1239 off
-= stream
->unread_data_len
;
1242 ret
= (*func_seek
) (stream
->intern
->cookie
, &off
, whence
);
1255 stream
->intern
->indicators
.eof
= 0;
1256 stream
->intern
->offset
= off
;
1261 stream
->intern
->indicators
.err
= 1;
1266 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1267 unbuffered-mode, storing the amount of bytes written in
1270 es_write_nbf (estream_t ES__RESTRICT stream
,
1271 const unsigned char *ES__RESTRICT buffer
,
1272 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1274 es_cookie_write_function_t func_write
= stream
->intern
->func_write
;
1275 size_t data_written
;
1279 if (bytes_to_write
&& (! func_write
))
1288 while (bytes_to_write
- data_written
)
1290 ret
= (*func_write
) (stream
->intern
->cookie
,
1291 buffer
+ data_written
,
1292 bytes_to_write
- data_written
);
1299 data_written
+= ret
;
1302 stream
->intern
->offset
+= data_written
;
1303 *bytes_written
= data_written
;
1310 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1311 fully-buffered-mode, storing the amount of bytes written in
1314 es_write_fbf (estream_t ES__RESTRICT stream
,
1315 const unsigned char *ES__RESTRICT buffer
,
1316 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1318 size_t space_available
;
1319 size_t data_to_write
;
1320 size_t data_written
;
1326 while ((bytes_to_write
- data_written
) && (! err
))
1328 if (stream
->data_offset
== stream
->buffer_size
)
1329 /* Container full, flush buffer. */
1330 err
= es_flush (stream
);
1334 /* Flushing resulted in empty container. */
1336 data_to_write
= bytes_to_write
- data_written
;
1337 space_available
= stream
->buffer_size
- stream
->data_offset
;
1338 if (data_to_write
> space_available
)
1339 data_to_write
= space_available
;
1341 memcpy (stream
->buffer
+ stream
->data_offset
,
1342 buffer
+ data_written
, data_to_write
);
1343 stream
->data_offset
+= data_to_write
;
1344 data_written
+= data_to_write
;
1348 *bytes_written
= data_written
;
1354 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1355 line-buffered-mode, storing the amount of bytes written in
1358 es_write_lbf (estream_t ES__RESTRICT stream
,
1359 const unsigned char *ES__RESTRICT buffer
,
1360 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1362 size_t data_flushed
= 0;
1363 size_t data_buffered
= 0;
1367 nlp
= memrchr (buffer
, '\n', bytes_to_write
);
1370 /* Found a newline, directly write up to (including) this
1372 err
= es_flush (stream
);
1374 err
= es_write_nbf (stream
, buffer
, nlp
- buffer
+ 1, &data_flushed
);
1379 /* Write remaining data fully buffered. */
1380 err
= es_write_fbf (stream
, buffer
+ data_flushed
,
1381 bytes_to_write
- data_flushed
, &data_buffered
);
1384 *bytes_written
= data_flushed
+ data_buffered
;
1389 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1390 amount of bytes written in BYTES_WRITTEN. */
1392 es_writen (estream_t ES__RESTRICT stream
,
1393 const void *ES__RESTRICT buffer
,
1394 size_t bytes_to_write
, size_t *ES__RESTRICT bytes_written
)
1396 size_t data_written
;
1402 if (! (stream
->flags
& ES_FLAG_WRITING
))
1404 /* Switching to writing mode -> discard input data and seek to
1405 position at which reading has stopped. We can do this only
1406 if a seek function has been registered. */
1407 if (stream
->intern
->func_seek
)
1409 err
= es_seek (stream
, 0, SEEK_CUR
, NULL
);
1412 if (errno
== ESPIPE
)
1420 switch (stream
->intern
->strategy
)
1423 err
= es_write_nbf (stream
, buffer
, bytes_to_write
, &data_written
);
1427 err
= es_write_lbf (stream
, buffer
, bytes_to_write
, &data_written
);
1431 err
= es_write_fbf (stream
, buffer
, bytes_to_write
, &data_written
);
1438 *bytes_written
= data_written
;
1440 if (! (stream
->flags
& ES_FLAG_WRITING
))
1441 stream
->flags
|= ES_FLAG_WRITING
;
1448 es_peek (estream_t ES__RESTRICT stream
, unsigned char **ES__RESTRICT data
,
1449 size_t *ES__RESTRICT data_len
)
1453 if (stream
->flags
& ES_FLAG_WRITING
)
1455 /* Switching to reading mode -> flush output. */
1456 err
= es_flush (stream
);
1459 stream
->flags
&= ~ES_FLAG_WRITING
;
1462 if (stream
->data_offset
== stream
->data_len
)
1464 /* Refill container. */
1465 err
= es_fill (stream
);
1471 *data
= stream
->buffer
+ stream
->data_offset
;
1473 *data_len
= stream
->data_len
- stream
->data_offset
;
1482 /* Skip SIZE bytes of input data contained in buffer. */
1484 es_skip (estream_t stream
, size_t size
)
1488 if (stream
->data_offset
+ size
> stream
->data_len
)
1495 stream
->data_offset
+= size
;
1504 doreadline (estream_t ES__RESTRICT stream
, size_t max_length
,
1505 char *ES__RESTRICT
*ES__RESTRICT line
,
1506 size_t *ES__RESTRICT line_length
)
1510 estream_t line_stream
;
1512 void *line_stream_cookie
;
1514 unsigned char *data
;
1520 line_stream_cookie
= NULL
;
1522 err
= es_func_mem_create (&line_stream_cookie
, NULL
, 0, 0, BUFFER_BLOCK_SIZE
,
1523 1, 0, 0, NULL
, 0, MEM_REALLOC
, MEM_FREE
, O_RDWR
);
1527 err
= es_create (&line_stream
, line_stream_cookie
, -1,
1528 estream_functions_mem
);
1532 space_left
= max_length
;
1536 if (max_length
&& (space_left
== 1))
1539 err
= es_peek (stream
, &data
, &data_len
);
1540 if (err
|| (! data_len
))
1543 if (data_len
> (space_left
- 1))
1544 data_len
= space_left
- 1;
1546 newline
= memchr (data
, '\n', data_len
);
1549 data_len
= (newline
- (char *) data
) + 1;
1550 err
= es_write (line_stream
, data
, data_len
, NULL
);
1553 space_left
-= data_len
;
1554 line_size
+= data_len
;
1555 es_skip (stream
, data_len
);
1561 err
= es_write (line_stream
, data
, data_len
, NULL
);
1564 space_left
-= data_len
;
1565 line_size
+= data_len
;
1566 es_skip (stream
, data_len
);
1575 /* Complete line has been written to line_stream. */
1577 if ((max_length
> 1) && (! line_size
))
1579 stream
->intern
->indicators
.eof
= 1;
1583 err
= es_seek (line_stream
, 0, SEEK_SET
, NULL
);
1589 line_new
= MEM_ALLOC (line_size
+ 1);
1599 err
= es_read (line_stream
, line_new
, line_size
, NULL
);
1603 line_new
[line_size
] = '\0';
1608 *line_length
= line_size
;
1613 es_destroy (line_stream
);
1614 else if (line_stream_cookie
)
1615 es_func_mem_destroy (line_stream_cookie
);
1620 MEM_FREE (line_new
);
1621 stream
->intern
->indicators
.err
= 1;
1629 es_print (estream_t ES__RESTRICT stream
,
1630 const char *ES__RESTRICT format
, va_list ap
)
1632 char data
[BUFFER_BLOCK_SIZE
];
1633 size_t bytes_written
;
1642 tmp_stream
= tmpfile ();
1649 err
= vfprintf (tmp_stream
, format
, ap
);
1653 err
= fseek (tmp_stream
, 0, SEEK_SET
);
1659 bytes_read
= fread (data
, 1, sizeof (data
), tmp_stream
);
1660 if (ferror (tmp_stream
))
1666 err
= es_writen (stream
, data
, bytes_read
, NULL
);
1670 bytes_written
+= bytes_read
;
1671 if (feof (tmp_stream
))
1680 fclose (tmp_stream
);
1682 return err
? -1 : bytes_written
;
1687 es_set_indicators (estream_t stream
, int ind_err
, int ind_eof
)
1690 stream
->intern
->indicators
.err
= ind_err
? 1 : 0;
1692 stream
->intern
->indicators
.eof
= ind_eof
? 1 : 0;
1697 es_get_indicator (estream_t stream
, int ind_err
, int ind_eof
)
1702 ret
= stream
->intern
->indicators
.err
;
1704 ret
= stream
->intern
->indicators
.eof
;
1711 es_set_buffering (estream_t ES__RESTRICT stream
,
1712 char *ES__RESTRICT buffer
, int mode
, size_t size
)
1716 /* Flush or empty buffer depending on mode. */
1717 if (stream
->flags
& ES_FLAG_WRITING
)
1719 err
= es_flush (stream
);
1726 es_set_indicators (stream
, -1, 0);
1728 /* Free old buffer in case that was allocated by this function. */
1729 if (stream
->intern
->deallocate_buffer
)
1731 stream
->intern
->deallocate_buffer
= 0;
1732 MEM_FREE (stream
->buffer
);
1733 stream
->buffer
= NULL
;
1737 stream
->buffer_size
= 0;
1743 buffer_new
= buffer
;
1746 buffer_new
= MEM_ALLOC (size
);
1754 stream
->buffer
= buffer_new
;
1755 stream
->buffer_size
= size
;
1757 stream
->intern
->deallocate_buffer
= 1;
1759 stream
->intern
->strategy
= mode
;
1769 es_offset_calculate (estream_t stream
)
1773 offset
= stream
->intern
->offset
+ stream
->data_offset
;
1774 if (offset
< stream
->unread_data_len
)
1775 /* Offset undefined. */
1778 offset
-= stream
->unread_data_len
;
1785 es_opaque_ctrl (estream_t ES__RESTRICT stream
, void *ES__RESTRICT opaque_new
,
1786 void **ES__RESTRICT opaque_old
)
1789 *opaque_old
= stream
->intern
->opaque
;
1791 stream
->intern
->opaque
= opaque_new
;
1796 es_get_fd (estream_t stream
)
1798 return stream
->intern
->fd
;
1810 err
= es_init_do ();
1816 es_fopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
)
1829 err
= es_convert_mode (mode
, &flags
);
1833 err
= es_func_file_create (&cookie
, &fd
, path
, flags
);
1838 err
= es_create (&stream
, cookie
, fd
, estream_functions_file
);
1844 if (err
&& create_called
)
1845 (*estream_functions_file
.func_close
) (cookie
);
1852 es_mopen (unsigned char *ES__RESTRICT data
, size_t data_n
, size_t data_len
,
1854 func_realloc_t func_realloc
, func_free_t func_free
,
1855 const char *ES__RESTRICT mode
)
1867 err
= es_convert_mode (mode
, &flags
);
1871 err
= es_func_mem_create (&cookie
, data
, data_n
, data_len
,
1872 BUFFER_BLOCK_SIZE
, grow
, 0, 0,
1873 NULL
, 0, func_realloc
, func_free
, flags
);
1878 err
= es_create (&stream
, cookie
, -1, estream_functions_mem
);
1882 if (err
&& create_called
)
1883 (*estream_functions_mem
.func_close
) (cookie
);
1890 es_open_memstream (char **ptr
, size_t *size
)
1903 err
= es_func_mem_create (&cookie
, NULL
, 0, 0,
1904 BUFFER_BLOCK_SIZE
, 1, 1, 1,
1905 ptr
, size
, MEM_REALLOC
, MEM_FREE
, flags
);
1910 err
= es_create (&stream
, cookie
, -1, estream_functions_mem
);
1914 if (err
&& create_called
)
1915 (*estream_functions_mem
.func_close
) (cookie
);
1922 es_fopencookie (void *ES__RESTRICT cookie
,
1923 const char *ES__RESTRICT mode
,
1924 es_cookie_io_functions_t functions
)
1933 err
= es_convert_mode (mode
, &flags
);
1937 err
= es_create (&stream
, cookie
, -1, functions
);
1948 es_fdopen (int filedes
, const char *mode
)
1960 err
= es_convert_mode (mode
, &flags
);
1964 err
= es_func_fd_create (&cookie
, filedes
, flags
);
1969 err
= es_create (&stream
, cookie
, filedes
, estream_functions_fd
);
1973 if (err
&& create_called
)
1974 (*estream_functions_fd
.func_close
) (cookie
);
1981 es_freopen (const char *ES__RESTRICT path
, const char *ES__RESTRICT mode
,
1982 estream_t ES__RESTRICT stream
)
1996 ESTREAM_LOCK (stream
);
1998 es_deinitialize (stream
);
2000 err
= es_convert_mode (mode
, &flags
);
2004 err
= es_func_file_create (&cookie
, &fd
, path
, flags
);
2009 es_initialize (stream
, cookie
, fd
, estream_functions_file
);
2016 es_func_fd_destroy (cookie
);
2018 es_destroy (stream
);
2022 ESTREAM_UNLOCK (stream
);
2026 /* FIXME? We don't support re-opening at the moment. */
2028 es_deinitialize (stream
);
2029 es_destroy (stream
);
2038 es_fclose (estream_t stream
)
2042 err
= es_destroy (stream
);
2048 es_fileno_unlocked (estream_t stream
)
2050 return es_get_fd (stream
);
2055 es_flockfile (estream_t stream
)
2057 ESTREAM_LOCK (stream
);
2062 es_ftrylockfile (estream_t stream
)
2064 return ESTREAM_TRYLOCK (stream
);
2069 es_funlockfile (estream_t stream
)
2071 ESTREAM_UNLOCK (stream
);
2076 es_fileno (estream_t stream
)
2080 ESTREAM_LOCK (stream
);
2081 ret
= es_fileno_unlocked (stream
);
2082 ESTREAM_UNLOCK (stream
);
2089 es_feof_unlocked (estream_t stream
)
2091 return es_get_indicator (stream
, 0, 1);
2096 es_feof (estream_t stream
)
2100 ESTREAM_LOCK (stream
);
2101 ret
= es_feof_unlocked (stream
);
2102 ESTREAM_UNLOCK (stream
);
2109 es_ferror_unlocked (estream_t stream
)
2111 return es_get_indicator (stream
, 1, 0);
2116 es_ferror (estream_t stream
)
2120 ESTREAM_LOCK (stream
);
2121 ret
= es_ferror_unlocked (stream
);
2122 ESTREAM_UNLOCK (stream
);
2129 es_clearerr_unlocked (estream_t stream
)
2131 es_set_indicators (stream
, 0, 0);
2136 es_clearerr (estream_t stream
)
2138 ESTREAM_LOCK (stream
);
2139 es_clearerr_unlocked (stream
);
2140 ESTREAM_UNLOCK (stream
);
2145 es_fflush (estream_t stream
)
2151 ESTREAM_LOCK (stream
);
2152 if (stream
->flags
& ES_FLAG_WRITING
)
2153 err
= es_flush (stream
);
2159 ESTREAM_UNLOCK (stream
);
2162 err
= es_list_iterate (es_fflush
);
2164 return err
? EOF
: 0;
2169 es_fseek (estream_t stream
, long int offset
, int whence
)
2173 ESTREAM_LOCK (stream
);
2174 err
= es_seek (stream
, offset
, whence
, NULL
);
2175 ESTREAM_UNLOCK (stream
);
2182 es_fseeko (estream_t stream
, off_t offset
, int whence
)
2186 ESTREAM_LOCK (stream
);
2187 err
= es_seek (stream
, offset
, whence
, NULL
);
2188 ESTREAM_UNLOCK (stream
);
2195 es_ftell (estream_t stream
)
2199 ESTREAM_LOCK (stream
);
2200 ret
= es_offset_calculate (stream
);
2201 ESTREAM_UNLOCK (stream
);
2208 es_ftello (estream_t stream
)
2212 ESTREAM_LOCK (stream
);
2213 ret
= es_offset_calculate (stream
);
2214 ESTREAM_UNLOCK (stream
);
2221 es_rewind (estream_t stream
)
2223 ESTREAM_LOCK (stream
);
2224 es_seek (stream
, 0L, SEEK_SET
, NULL
);
2225 es_set_indicators (stream
, 0, -1);
2226 ESTREAM_UNLOCK (stream
);
2231 _es_getc_underflow (estream_t stream
)
2237 err
= es_readn (stream
, &c
, 1, &bytes_read
);
2239 return (err
|| (! bytes_read
)) ? EOF
: c
;
2244 _es_putc_overflow (int c
, estream_t stream
)
2246 unsigned char d
= c
;
2249 err
= es_writen (stream
, &d
, 1, NULL
);
2251 return err
? EOF
: c
;
2256 es_fgetc (estream_t stream
)
2260 ESTREAM_LOCK (stream
);
2261 ret
= es_getc_unlocked (stream
);
2262 ESTREAM_UNLOCK (stream
);
2269 es_fputc (int c
, estream_t stream
)
2273 ESTREAM_LOCK (stream
);
2274 ret
= es_putc_unlocked (c
, stream
);
2275 ESTREAM_UNLOCK (stream
);
2282 es_ungetc (int c
, estream_t stream
)
2284 unsigned char data
= (unsigned char) c
;
2287 ESTREAM_LOCK (stream
);
2288 es_unreadn (stream
, &data
, 1, &data_unread
);
2289 ESTREAM_UNLOCK (stream
);
2291 return data_unread
? c
: EOF
;
2296 es_read (estream_t ES__RESTRICT stream
,
2297 void *ES__RESTRICT buffer
, size_t bytes_to_read
,
2298 size_t *ES__RESTRICT bytes_read
)
2304 ESTREAM_LOCK (stream
);
2305 err
= es_readn (stream
, buffer
, bytes_to_read
, bytes_read
);
2306 ESTREAM_UNLOCK (stream
);
2316 es_write (estream_t ES__RESTRICT stream
,
2317 const void *ES__RESTRICT buffer
, size_t bytes_to_write
,
2318 size_t *ES__RESTRICT bytes_written
)
2324 ESTREAM_LOCK (stream
);
2325 err
= es_writen (stream
, buffer
, bytes_to_write
, bytes_written
);
2326 ESTREAM_UNLOCK (stream
);
2336 es_fread (void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2337 estream_t ES__RESTRICT stream
)
2344 ESTREAM_LOCK (stream
);
2345 err
= es_readn (stream
, ptr
, size
* nitems
, &bytes
);
2346 ESTREAM_UNLOCK (stream
);
2358 es_fwrite (const void *ES__RESTRICT ptr
, size_t size
, size_t nitems
,
2359 estream_t ES__RESTRICT stream
)
2366 ESTREAM_LOCK (stream
);
2367 err
= es_writen (stream
, ptr
, size
* nitems
, &bytes
);
2368 ESTREAM_UNLOCK (stream
);
2380 es_fgets (char *ES__RESTRICT s
, int n
, estream_t ES__RESTRICT stream
)
2388 ESTREAM_LOCK (stream
);
2389 err
= doreadline (stream
, n
, &s
, NULL
);
2390 ESTREAM_UNLOCK (stream
);
2400 es_fputs (const char *ES__RESTRICT s
, estream_t ES__RESTRICT stream
)
2405 length
= strlen (s
);
2406 ESTREAM_LOCK (stream
);
2407 err
= es_writen (stream
, s
, length
, NULL
);
2408 ESTREAM_UNLOCK (stream
);
2410 return err
? EOF
: 0;
2415 es_getline (char *ES__RESTRICT
*ES__RESTRICT lineptr
, size_t *ES__RESTRICT n
,
2416 estream_t ES__RESTRICT stream
)
2422 ESTREAM_LOCK (stream
);
2423 err
= doreadline (stream
, 0, &line
, &line_n
);
2424 ESTREAM_UNLOCK (stream
);
2430 /* Caller wants us to use his buffer. */
2432 if (*n
< (line_n
+ 1))
2434 /* Provided buffer is too small -> resize. */
2438 p
= MEM_REALLOC (*lineptr
, line_n
+ 1);
2450 memcpy (*lineptr
, line
, line_n
+ 1);
2458 /* Caller wants new buffers. */
2465 return err
? err
: line_n
;
2470 /* Same as fgets() but if the provided buffer is too short a larger
2471 one will be allocated. This is similar to getline. A line is
2472 considered a byte stream ending in a LF.
2474 If MAX_LENGTH is not NULL, it shall point to a value with the
2475 maximum allowed allocation.
2477 Returns the length of the line. EOF is indicated by a line of
2478 length zero. A truncated line is indicated my setting the value at
2479 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2480 memory was enable or another error occurred; ERRNO is then set
2483 If a line has been truncated, the file pointer is moved forward to
2484 the end of the line so that the next read starts with the next
2485 line. Note that MAX_LENGTH must be re-initialzied in this case.
2487 The caller initially needs to provide the address of a variable,
2488 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2489 anymore with the following invocations. LENGTH_OF_BUFFER should be
2490 the address of a variable, initialized to 0, which is also
2491 maintained by this function. Thus, both paramaters should be
2492 considered the state of this function.
2494 Note: The returned buffer is allocated with enough extra space to
2495 allow the caller to append a CR,LF,Nul. The buffer should be
2496 released using es_free.
2499 es_read_line (estream_t stream
,
2500 char **addr_of_buffer
, size_t *length_of_buffer
,
2504 char *buffer
= *addr_of_buffer
;
2505 size_t length
= *length_of_buffer
;
2507 size_t maxlen
= max_length
? *max_length
: 0;
2512 /* No buffer given - allocate a new one. */
2514 buffer
= MEM_ALLOC (length
);
2515 *addr_of_buffer
= buffer
;
2518 *length_of_buffer
= 0;
2523 *length_of_buffer
= length
;
2528 /* This should never happen. If it does, the fucntion has been
2529 called with wrong arguments. */
2533 length
-= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2535 ESTREAM_LOCK (stream
);
2537 while ((c
= es_getc_unlocked (stream
)) != EOF
)
2539 if (nbytes
== length
)
2541 /* Enlarge the buffer. */
2542 if (maxlen
&& length
> maxlen
)
2544 /* We are beyond our limit: Skip the rest of the line. */
2545 while (c
!= '\n' && (c
=es_getc_unlocked (stream
)) != EOF
)
2547 *p
++ = '\n'; /* Always append a LF (we reserved some space). */
2550 *max_length
= 0; /* Indicate truncation. */
2551 break; /* the while loop. */
2553 length
+= 3; /* Adjust for the reserved bytes. */
2554 length
+= length
< 1024? 256 : 1024;
2555 *addr_of_buffer
= MEM_REALLOC (buffer
, length
);
2556 if (!*addr_of_buffer
)
2558 int save_errno
= errno
;
2560 *length_of_buffer
= *max_length
= 0;
2561 ESTREAM_UNLOCK (stream
);
2565 buffer
= *addr_of_buffer
;
2566 *length_of_buffer
= length
;
2568 p
= buffer
+ nbytes
;
2575 *p
= 0; /* Make sure the line is a string. */
2576 ESTREAM_UNLOCK (stream
);
2581 /* Wrapper around free() to match the memory allocation system used
2582 by estream. Should be used for all buffers returned to the caller
2593 es_vfprintf (estream_t ES__RESTRICT stream
, const char *ES__RESTRICT format
,
2598 ESTREAM_LOCK (stream
);
2599 ret
= es_print (stream
, format
, ap
);
2600 ESTREAM_UNLOCK (stream
);
2607 es_fprintf (estream_t ES__RESTRICT stream
,
2608 const char *ES__RESTRICT format
, ...)
2613 va_start (ap
, format
);
2614 ESTREAM_LOCK (stream
);
2615 ret
= es_print (stream
, format
, ap
);
2616 ESTREAM_UNLOCK (stream
);
2636 fp_fd
= fileno (fp
);
2659 flags
= O_RDWR
| O_TRUNC
| O_CREAT
;
2669 err
= es_func_fd_create (&cookie
, fd
, flags
);
2674 err
= es_create (&stream
, cookie
, fd
, estream_functions_fd
);
2681 es_func_fd_destroy (cookie
);
2692 es_setvbuf (estream_t ES__RESTRICT stream
,
2693 char *ES__RESTRICT buf
, int type
, size_t size
)
2697 if (((type
== _IOFBF
) || (type
== _IOLBF
) || (type
== _IONBF
))
2698 && (! ((! size
) && (type
!= _IONBF
))))
2700 ESTREAM_LOCK (stream
);
2701 err
= es_set_buffering (stream
, buf
, type
, size
);
2702 ESTREAM_UNLOCK (stream
);
2715 es_setbuf (estream_t ES__RESTRICT stream
, char *ES__RESTRICT buf
)
2717 ESTREAM_LOCK (stream
);
2718 es_set_buffering (stream
, buf
, buf
? _IOFBF
: _IONBF
, BUFSIZ
);
2719 ESTREAM_UNLOCK (stream
);
2723 es_opaque_set (estream_t stream
, void *opaque
)
2725 ESTREAM_LOCK (stream
);
2726 es_opaque_ctrl (stream
, opaque
, NULL
);
2727 ESTREAM_UNLOCK (stream
);
2732 es_opaque_get (estream_t stream
)
2736 ESTREAM_LOCK (stream
);
2737 es_opaque_ctrl (stream
, NULL
, &opaque
);
2738 ESTREAM_UNLOCK (stream
);