2006-09-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / estream.c
blob77ba0876dd18404ac1a718e2561f55090c00f292
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,
19 * USA.
22 #ifdef USE_ESTREAM_SUPPORT_H
23 # include <estream-support.h>
24 #endif
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include <sys/types.h>
31 #include <sys/file.h>
32 #include <sys/stat.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <stdarg.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <stddef.h>
40 #include <assert.h>
42 #ifdef HAVE_PTH
43 # include <pth.h>
44 #endif
46 #ifndef HAVE_MKSTEMP
47 int mkstemp (char *template);
48 #endif
50 #ifndef HAVE_MEMRCHR
51 void *memrchr (const void *block, int c, size_t size);
52 #endif
54 #include <estream.h>
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
72 /* Macros. */
74 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
75 (((size) + (block_size - 1)) / block_size)
79 /* Locking. */
81 #ifdef HAVE_PTH
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)
95 #else
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
105 #endif
107 /* Memory allocator functions. */
109 #define MEM_ALLOC malloc
110 #define MEM_REALLOC realloc
111 #define MEM_FREE free
113 /* Primitive system I/O. */
115 #ifdef HAVE_PTH
116 # define ESTREAM_SYS_READ pth_read
117 # define ESTREAM_SYS_WRITE pth_write
118 #else
119 # define ESTREAM_SYS_READ read
120 # define ESTREAM_SYS_WRITE write
121 #endif
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. */
139 off_t offset;
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;
144 int strategy;
145 int fd;
146 struct
148 unsigned int err: 1;
149 unsigned int eof: 1;
150 } indicators;
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)
160 /* Stream list. */
162 typedef struct estream_list *estream_list_t;
164 struct estream_list
166 estream_t car;
167 estream_list_t cdr;
168 estream_list_t *prev_cdr;
171 static estream_list_t estream_list;
172 #ifdef HAVE_PTH
173 static estream_mutex_t estream_list_lock = ESTREAM_MUTEX_INITIALIZER;
174 #endif
176 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
177 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
179 #ifndef EOPNOTSUPP
180 # define EOPNOTSUPP ENOSYS
181 #endif
186 /* Macros. */
188 /* Calculate array dimension. */
189 #define DIM(array) (sizeof (array) / sizeof (*array))
191 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
192 VARIABLE is zero. */
193 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
194 do \
196 tmp_variable = expression; \
197 if ((! variable) && tmp_variable) \
198 variable = tmp_variable; \
200 while (0)
203 * List manipulation.
206 /* Add STREAM to the list of registered stream objects. */
207 static int
208 es_list_add (estream_t stream)
210 estream_list_t list_obj;
211 int ret;
213 list_obj = MEM_ALLOC (sizeof (*list_obj));
214 if (! list_obj)
215 ret = -1;
216 else
218 ESTREAM_LIST_LOCK;
219 list_obj->car = stream;
220 list_obj->cdr = estream_list;
221 list_obj->prev_cdr = &estream_list;
222 if (estream_list)
223 estream_list->prev_cdr = &list_obj->cdr;
224 estream_list = list_obj;
225 ESTREAM_LIST_UNLOCK;
226 ret = 0;
229 return ret;
232 /* Remove STREAM from the list of registered stream objects. */
233 static void
234 es_list_remove (estream_t stream)
236 estream_list_t list_obj;
238 ESTREAM_LIST_LOCK;
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;
243 if (list_obj->cdr)
244 list_obj->cdr->prev_cdr = list_obj->prev_cdr;
245 MEM_FREE (list_obj);
246 break;
248 ESTREAM_LIST_UNLOCK;
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
255 of them. */
256 static int
257 es_list_iterate (estream_iterator_t iterator)
259 estream_list_t list_obj;
260 int ret = 0;
262 ESTREAM_LIST_LOCK;
263 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
264 ret |= (*iterator) (list_obj->car);
265 ESTREAM_LIST_UNLOCK;
267 return ret;
273 * Initialization.
276 static int
277 es_init_do (void)
279 int err;
281 err = ESTREAM_THREADING_INIT ();
283 return err;
289 * I/O methods.
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. */
306 char **ptr;
307 size_t *size;
308 func_realloc_t func_realloc;
309 func_free_t func_free;
310 } *estream_cookie_mem_t;
312 /* Create function for memory objects. */
313 static int
314 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
315 unsigned char *ES__RESTRICT data, size_t data_n,
316 size_t data_len,
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,
321 unsigned int flags)
323 estream_cookie_mem_t mem_cookie;
324 int err;
326 mem_cookie = MEM_ALLOC (sizeof (*mem_cookie));
327 if (! mem_cookie)
328 err = -1;
329 else
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;
346 err = 0;
349 return err;
352 /* Read function for memory objects. */
353 static ssize_t
354 es_func_mem_read (void *cookie, void *buffer, size_t size)
356 estream_cookie_mem_t mem_cookie = cookie;
357 ssize_t ret;
359 if (size > mem_cookie->data_len - mem_cookie->offset)
360 size = mem_cookie->data_len - mem_cookie->offset;
362 if (size)
364 memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
365 mem_cookie->offset += size;
368 ret = size;
370 return ret;
373 /* Write function for memory objects. */
374 static ssize_t
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;
380 size_t newsize;
381 ssize_t ret;
382 int err;
384 if (size)
386 /* Regular write. */
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;
396 err = 0;
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);
403 if (! memory_new)
405 err = -1;
406 break;
408 else
410 if (mem_cookie->memory != memory_new)
411 mem_cookie->memory = memory_new;
412 mem_cookie->memory_size += mem_cookie->block_size;
415 if (err)
416 goto out;
418 if (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;
426 else
428 /* Flush. */
430 err = 0;
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);
440 if (! memory_new)
442 err = -1;
443 goto out;
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. */
455 if (mem_cookie->ptr)
456 *mem_cookie->ptr = (char *) mem_cookie->memory;
457 if (mem_cookie->size)
458 *mem_cookie->size = mem_cookie->data_len;
461 out:
463 if (err)
464 ret = -1;
465 else
466 ret = size;
468 return ret;
471 /* Seek function for memory objects. */
472 static int
473 es_func_mem_seek (void *cookie, off_t *offset, int whence)
475 estream_cookie_mem_t mem_cookie = cookie;
476 off_t pos_new;
477 int err = 0;
479 switch (whence)
481 case SEEK_SET:
482 pos_new = *offset;
483 break;
485 case SEEK_CUR:
486 pos_new = mem_cookie->offset += *offset;
487 break;
489 case SEEK_END:
490 pos_new = mem_cookie->data_len += *offset;
491 break;
493 default:
494 /* Never reached. */
495 pos_new = 0;
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;
505 size_t newsize;
506 void *p;
508 newsize = BUFFER_ROUND_TO_BLOCK (pos_new, mem_cookie->block_size);
509 p = (*func_realloc) (mem_cookie->memory, newsize);
510 if (! p)
512 err = -1;
513 goto out;
515 else
517 if (mem_cookie->memory != p)
518 mem_cookie->memory = p;
519 mem_cookie->memory_size = newsize;
522 else
524 errno = EINVAL;
525 err = -1;
526 goto out;
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;
536 *offset = pos_new;
538 out:
540 return err;
543 /* Destroy function for memory objects. */
544 static int
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);
554 return 0;
557 static es_cookie_io_functions_t estream_functions_mem =
559 es_func_mem_read,
560 es_func_mem_write,
561 es_func_mem_seek,
562 es_func_mem_destroy
565 /* Implementation of fd I/O. */
567 /* Cookie for fd objects. */
568 typedef struct estream_cookie_fd
570 int fd;
571 } *estream_cookie_fd_t;
573 /* Create function for fd objects. */
574 static int
575 es_func_fd_create (void **cookie, int fd, unsigned int flags)
577 estream_cookie_fd_t fd_cookie;
578 int err;
580 fd_cookie = MEM_ALLOC (sizeof (*fd_cookie));
581 if (! fd_cookie)
582 err = -1;
583 else
585 fd_cookie->fd = fd;
586 *cookie = fd_cookie;
587 err = 0;
590 return err;
593 /* Read function for fd objects. */
594 static ssize_t
595 es_func_fd_read (void *cookie, void *buffer, size_t size)
598 estream_cookie_fd_t file_cookie = cookie;
599 ssize_t bytes_read;
602 bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
603 while (bytes_read == -1 && errno == EINTR);
605 return bytes_read;
608 /* Write function for fd objects. */
609 static ssize_t
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. */
624 static int
625 es_func_fd_seek (void *cookie, off_t *offset, int whence)
627 estream_cookie_fd_t file_cookie = cookie;
628 off_t offset_new;
629 int err;
631 offset_new = lseek (file_cookie->fd, *offset, whence);
632 if (offset_new == -1)
633 err = -1;
634 else
636 *offset = offset_new;
637 err = 0;
640 return err;
643 /* Destroy function for fd objects. */
644 static int
645 es_func_fd_destroy (void *cookie)
647 estream_cookie_fd_t fd_cookie = cookie;
648 int err;
650 if (fd_cookie)
652 err = close (fd_cookie->fd);
653 MEM_FREE (fd_cookie);
655 else
656 err = 0;
658 return err;
661 static es_cookie_io_functions_t estream_functions_fd =
663 es_func_fd_read,
664 es_func_fd_write,
665 es_func_fd_seek,
666 es_func_fd_destroy
669 /* Implementation of file I/O. */
671 /* Create function for file objects. */
672 static int
673 es_func_file_create (void **cookie, int *filedes,
674 const char *path, unsigned int flags)
676 estream_cookie_fd_t file_cookie;
677 int err;
678 int fd;
680 err = 0;
681 fd = -1;
683 file_cookie = MEM_ALLOC (sizeof (*file_cookie));
684 if (! file_cookie)
686 err = -1;
687 goto out;
690 fd = open (path, flags, ES_DEFAULT_OPEN_MODE);
691 if (fd == -1)
693 err = -1;
694 goto out;
697 file_cookie->fd = fd;
698 *cookie = file_cookie;
699 *filedes = fd;
701 out:
703 if (err)
704 MEM_FREE (file_cookie);
706 return err;
709 static es_cookie_io_functions_t estream_functions_file =
711 es_func_fd_read,
712 es_func_fd_write,
713 es_func_fd_seek,
714 es_func_fd_destroy
719 /* Stream primitives. */
721 static int
722 es_convert_mode (const char *mode, unsigned int *flags)
724 struct
726 const char *mode;
727 unsigned int flags;
728 } mode_flags[] = { { "r",
729 O_RDONLY },
730 { "rb",
731 O_RDONLY },
732 { "w",
733 O_WRONLY | O_TRUNC | O_CREAT },
734 { "wb",
735 O_WRONLY | O_TRUNC | O_CREAT },
736 { "a",
737 O_WRONLY | O_APPEND | O_CREAT },
738 { "ab",
739 O_WRONLY | O_APPEND | O_CREAT },
740 { "r+",
741 O_RDWR },
742 { "rb+",
743 O_RDWR },
744 { "r+b",
745 O_RDONLY | O_WRONLY },
746 { "w+",
747 O_RDWR | O_TRUNC | O_CREAT },
748 { "wb+",
749 O_RDWR | O_TRUNC | O_CREAT },
750 { "w+b",
751 O_RDWR | O_TRUNC | O_CREAT },
752 { "a+",
753 O_RDWR | O_CREAT | O_APPEND },
754 { "ab+",
755 O_RDWR | O_CREAT | O_APPEND },
756 { "a+b",
757 O_RDWR | O_CREAT | O_APPEND } };
758 unsigned int i;
759 int err;
761 for (i = 0; i < DIM (mode_flags); i++)
762 if (! strcmp (mode_flags[i].mode, mode))
763 break;
764 if (i == DIM (mode_flags))
766 errno = EINVAL;
767 err = -1;
769 else
771 err = 0;
772 *flags = mode_flags[i].flags;
775 return err;
781 * Low level stream functionality.
784 static int
785 es_fill (estream_t stream)
787 size_t bytes_read = 0;
788 int err;
790 if (!stream->intern->func_read)
792 errno = EOPNOTSUPP;
793 err = -1;
795 else
797 es_cookie_read_function_t func_read = stream->intern->func_read;
798 ssize_t ret;
800 ret = (*func_read) (stream->intern->cookie,
801 stream->buffer, stream->buffer_size);
802 if (ret == -1)
804 bytes_read = 0;
805 err = -1;
807 else
809 bytes_read = ret;
810 err = 0;
814 if (err)
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;
823 return err;
826 static int
827 es_flush (estream_t stream)
829 es_cookie_write_function_t func_write = stream->intern->func_write;
830 int err;
832 assert (stream->flags & ES_FLAG_WRITING);
834 if (stream->data_offset)
836 size_t bytes_written;
837 size_t data_flushed;
838 ssize_t ret;
840 if (! func_write)
842 err = EOPNOTSUPP;
843 goto out;
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". */
852 data_flushed = 0;
853 err = 0;
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);
860 if (ret == -1)
862 bytes_written = 0;
863 err = -1;
865 else
866 bytes_written = ret;
868 data_flushed += bytes_written;
869 if (err)
870 break;
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);
884 else
885 err = 0;
887 out:
889 if (err)
890 stream->intern->indicators.err = 1;
892 return err;
895 /* Discard buffered data for STREAM. */
896 static void
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. */
906 static void
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;
927 stream->flags = 0;
930 /* Deinitialize STREAM. */
931 static int
932 es_deinitialize (estream_t stream)
934 es_cookie_close_function_t func_close;
935 int err, tmp_err;
937 func_close = stream->intern->func_close;
939 err = 0;
940 if (stream->flags & ES_FLAG_WRITING)
941 SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
942 if (func_close)
943 SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
945 return err;
948 /* Create a new stream object, initialize it. */
949 static int
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;
955 int err;
957 stream_new = NULL;
958 stream_internal_new = NULL;
960 stream_new = MEM_ALLOC (sizeof (*stream_new));
961 if (! stream_new)
963 err = -1;
964 goto out;
967 stream_internal_new = MEM_ALLOC (sizeof (*stream_internal_new));
968 if (! stream_internal_new)
970 err = -1;
971 goto out;
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);
984 if (err)
985 goto out;
987 *stream = stream_new;
989 out:
991 if (err)
993 if (stream_new)
995 es_deinitialize (stream_new);
996 MEM_FREE (stream_new);
1000 return err;
1003 /* Deinitialize a stream object and destroy it. */
1004 static int
1005 es_destroy (estream_t stream)
1007 int err = 0;
1009 if (stream)
1011 es_list_remove (stream);
1012 err = es_deinitialize (stream);
1013 MEM_FREE (stream->intern);
1014 MEM_FREE (stream);
1017 return err;
1020 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1021 unbuffered-mode, storing the amount of bytes read in
1022 *BYTES_READ. */
1023 static int
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;
1029 size_t data_read;
1030 ssize_t ret;
1031 int err;
1033 data_read = 0;
1034 err = 0;
1036 while (bytes_to_read - data_read)
1038 ret = (*func_read) (stream->intern->cookie,
1039 buffer + data_read, bytes_to_read - data_read);
1040 if (ret == -1)
1042 err = -1;
1043 break;
1045 else if (ret)
1046 data_read += ret;
1047 else
1048 break;
1051 stream->intern->offset += data_read;
1052 *bytes_read = data_read;
1054 return err;
1057 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1058 fully-buffered-mode, storing the amount of bytes read in
1059 *BYTES_READ. */
1060 static int
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;
1067 size_t data_read;
1068 int err;
1070 data_read = 0;
1071 err = 0;
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);
1080 if (! err)
1081 if (! stream->data_len)
1082 /* Filling did not result in any data read. */
1083 break;
1086 if (! err)
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;
1104 return err;
1107 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1108 line-buffered-mode, storing the amount of bytes read in
1109 *BYTES_READ. */
1110 static int
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)
1115 int err;
1117 err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1119 return err;
1122 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1123 *the amount of bytes read in BYTES_READ. */
1124 static int
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;
1131 int err;
1133 data_read_unread = 0;
1134 data_read = 0;
1135 err = 0;
1137 if (stream->flags & ES_FLAG_WRITING)
1139 /* Switching to reading mode -> flush output. */
1140 err = es_flush (stream);
1141 if (err)
1142 goto out;
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--;
1152 data_read_unread++;
1155 switch (stream->intern->strategy)
1157 case _IONBF:
1158 err = es_read_nbf (stream,
1159 buffer + data_read_unread,
1160 bytes_to_read - data_read_unread, &data_read);
1161 break;
1162 case _IOLBF:
1163 err = es_read_lbf (stream,
1164 buffer + data_read_unread,
1165 bytes_to_read - data_read_unread, &data_read);
1166 break;
1167 case _IOFBF:
1168 err = es_read_fbf (stream,
1169 buffer + data_read_unread,
1170 bytes_to_read - data_read_unread, &data_read);
1171 break;
1174 out:
1176 if (bytes_read)
1177 *bytes_read = data_read_unread + data_read;
1179 return err;
1182 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1183 amount of bytes succesfully unread in *BYTES_UNREAD. */
1184 static void
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)
1189 size_t space_left;
1191 space_left = stream->unread_buffer_size - stream->unread_data_len;
1193 if (data_n > space_left)
1194 data_n = space_left;
1196 if (! data_n)
1197 goto out;
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;
1203 out:
1205 if (bytes_unread)
1206 *bytes_unread = data_n;
1209 /* Seek in STREAM. */
1210 static int
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;
1215 int err, ret;
1216 off_t off;
1218 if (! func_seek)
1220 errno = EOPNOTSUPP;
1221 err = -1;
1222 goto out;
1225 if (stream->flags & ES_FLAG_WRITING)
1227 /* Flush data first in order to prevent flushing it to the wrong
1228 offset. */
1229 err = es_flush (stream);
1230 if (err)
1231 goto out;
1232 stream->flags &= ~ES_FLAG_WRITING;
1235 off = offset;
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);
1243 if (ret == -1)
1245 err = -1;
1246 goto out;
1249 err = 0;
1250 es_empty (stream);
1252 if (offset_new)
1253 *offset_new = off;
1255 stream->intern->indicators.eof = 0;
1256 stream->intern->offset = off;
1258 out:
1260 if (err)
1261 stream->intern->indicators.err = 1;
1263 return err;
1266 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1267 unbuffered-mode, storing the amount of bytes written in
1268 *BYTES_WRITTEN. */
1269 static int
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;
1276 ssize_t ret;
1277 int err;
1279 if (bytes_to_write && (! func_write))
1281 err = EOPNOTSUPP;
1282 goto out;
1285 data_written = 0;
1286 err = 0;
1288 while (bytes_to_write - data_written)
1290 ret = (*func_write) (stream->intern->cookie,
1291 buffer + data_written,
1292 bytes_to_write - data_written);
1293 if (ret == -1)
1295 err = -1;
1296 break;
1298 else
1299 data_written += ret;
1302 stream->intern->offset += data_written;
1303 *bytes_written = data_written;
1305 out:
1307 return err;
1310 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1311 fully-buffered-mode, storing the amount of bytes written in
1312 *BYTES_WRITTEN. */
1313 static int
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;
1321 int err;
1323 data_written = 0;
1324 err = 0;
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);
1332 if (! err)
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;
1350 return err;
1354 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1355 line-buffered-mode, storing the amount of bytes written in
1356 *BYTES_WRITTEN. */
1357 static int
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;
1364 unsigned char *nlp;
1365 int err = 0;
1367 nlp = memrchr (buffer, '\n', bytes_to_write);
1368 if (nlp)
1370 /* Found a newline, directly write up to (including) this
1371 character. */
1372 err = es_flush (stream);
1373 if (!err)
1374 err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1377 if (!err)
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;
1385 return err;
1389 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1390 amount of bytes written in BYTES_WRITTEN. */
1391 static int
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;
1397 int err;
1399 data_written = 0;
1400 err = 0;
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);
1410 if (err)
1412 if (errno == ESPIPE)
1413 err = 0;
1414 else
1415 goto out;
1420 switch (stream->intern->strategy)
1422 case _IONBF:
1423 err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1424 break;
1426 case _IOLBF:
1427 err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1428 break;
1430 case _IOFBF:
1431 err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1432 break;
1435 out:
1437 if (bytes_written)
1438 *bytes_written = data_written;
1439 if (data_written)
1440 if (! (stream->flags & ES_FLAG_WRITING))
1441 stream->flags |= ES_FLAG_WRITING;
1443 return err;
1447 static int
1448 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1449 size_t *ES__RESTRICT data_len)
1451 int err;
1453 if (stream->flags & ES_FLAG_WRITING)
1455 /* Switching to reading mode -> flush output. */
1456 err = es_flush (stream);
1457 if (err)
1458 goto out;
1459 stream->flags &= ~ES_FLAG_WRITING;
1462 if (stream->data_offset == stream->data_len)
1464 /* Refill container. */
1465 err = es_fill (stream);
1466 if (err)
1467 goto out;
1470 if (data)
1471 *data = stream->buffer + stream->data_offset;
1472 if (data_len)
1473 *data_len = stream->data_len - stream->data_offset;
1474 err = 0;
1476 out:
1478 return err;
1482 /* Skip SIZE bytes of input data contained in buffer. */
1483 static int
1484 es_skip (estream_t stream, size_t size)
1486 int err;
1488 if (stream->data_offset + size > stream->data_len)
1490 errno = EINVAL;
1491 err = -1;
1493 else
1495 stream->data_offset += size;
1496 err = 0;
1499 return err;
1503 static int
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)
1508 size_t space_left;
1509 size_t line_size;
1510 estream_t line_stream;
1511 char *line_new;
1512 void *line_stream_cookie;
1513 char *newline;
1514 unsigned char *data;
1515 size_t data_len;
1516 int err;
1518 line_new = NULL;
1519 line_stream = NULL;
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);
1524 if (err)
1525 goto out;
1527 err = es_create (&line_stream, line_stream_cookie, -1,
1528 estream_functions_mem);
1529 if (err)
1530 goto out;
1532 space_left = max_length;
1533 line_size = 0;
1534 while (1)
1536 if (max_length && (space_left == 1))
1537 break;
1539 err = es_peek (stream, &data, &data_len);
1540 if (err || (! data_len))
1541 break;
1543 if (data_len > (space_left - 1))
1544 data_len = space_left - 1;
1546 newline = memchr (data, '\n', data_len);
1547 if (newline)
1549 data_len = (newline - (char *) data) + 1;
1550 err = es_write (line_stream, data, data_len, NULL);
1551 if (! err)
1553 space_left -= data_len;
1554 line_size += data_len;
1555 es_skip (stream, data_len);
1556 break;
1559 else
1561 err = es_write (line_stream, data, data_len, NULL);
1562 if (! err)
1564 space_left -= data_len;
1565 line_size += data_len;
1566 es_skip (stream, data_len);
1569 if (err)
1570 break;
1572 if (err)
1573 goto out;
1575 /* Complete line has been written to line_stream. */
1577 if ((max_length > 1) && (! line_size))
1579 stream->intern->indicators.eof = 1;
1580 goto out;
1583 err = es_seek (line_stream, 0, SEEK_SET, NULL);
1584 if (err)
1585 goto out;
1587 if (! *line)
1589 line_new = MEM_ALLOC (line_size + 1);
1590 if (! line_new)
1592 err = -1;
1593 goto out;
1596 else
1597 line_new = *line;
1599 err = es_read (line_stream, line_new, line_size, NULL);
1600 if (err)
1601 goto out;
1603 line_new[line_size] = '\0';
1605 if (! *line)
1606 *line = line_new;
1607 if (line_length)
1608 *line_length = line_size;
1610 out:
1612 if (line_stream)
1613 es_destroy (line_stream);
1614 else if (line_stream_cookie)
1615 es_func_mem_destroy (line_stream_cookie);
1617 if (err)
1619 if (! *line)
1620 MEM_FREE (line_new);
1621 stream->intern->indicators.err = 1;
1624 return err;
1628 static int
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;
1634 size_t bytes_read;
1635 FILE *tmp_stream;
1636 int err;
1638 bytes_written = 0;
1639 tmp_stream = NULL;
1640 err = 0;
1642 tmp_stream = tmpfile ();
1643 if (! tmp_stream)
1645 err = errno;
1646 goto out;
1649 err = vfprintf (tmp_stream, format, ap);
1650 if (err < 0)
1651 goto out;
1653 err = fseek (tmp_stream, 0, SEEK_SET);
1654 if (err)
1655 goto out;
1657 while (1)
1659 bytes_read = fread (data, 1, sizeof (data), tmp_stream);
1660 if (ferror (tmp_stream))
1662 err = -1;
1663 break;
1666 err = es_writen (stream, data, bytes_read, NULL);
1667 if (err)
1668 break;
1669 else
1670 bytes_written += bytes_read;
1671 if (feof (tmp_stream))
1672 break;
1674 if (err)
1675 goto out;
1677 out:
1679 if (tmp_stream)
1680 fclose (tmp_stream);
1682 return err ? -1 : bytes_written;
1686 static void
1687 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1689 if (ind_err != -1)
1690 stream->intern->indicators.err = ind_err ? 1 : 0;
1691 if (ind_eof != -1)
1692 stream->intern->indicators.eof = ind_eof ? 1 : 0;
1696 static int
1697 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1699 int ret = 0;
1701 if (ind_err)
1702 ret = stream->intern->indicators.err;
1703 else if (ind_eof)
1704 ret = stream->intern->indicators.eof;
1706 return ret;
1710 static int
1711 es_set_buffering (estream_t ES__RESTRICT stream,
1712 char *ES__RESTRICT buffer, int mode, size_t size)
1714 int err;
1716 /* Flush or empty buffer depending on mode. */
1717 if (stream->flags & ES_FLAG_WRITING)
1719 err = es_flush (stream);
1720 if (err)
1721 goto out;
1723 else
1724 es_empty (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;
1736 if (mode == _IONBF)
1737 stream->buffer_size = 0;
1738 else
1740 void *buffer_new;
1742 if (buffer)
1743 buffer_new = buffer;
1744 else
1746 buffer_new = MEM_ALLOC (size);
1747 if (! buffer_new)
1749 err = -1;
1750 goto out;
1754 stream->buffer = buffer_new;
1755 stream->buffer_size = size;
1756 if (! buffer)
1757 stream->intern->deallocate_buffer = 1;
1759 stream->intern->strategy = mode;
1760 err = 0;
1762 out:
1764 return err;
1768 static off_t
1769 es_offset_calculate (estream_t stream)
1771 off_t offset;
1773 offset = stream->intern->offset + stream->data_offset;
1774 if (offset < stream->unread_data_len)
1775 /* Offset undefined. */
1776 offset = 0;
1777 else
1778 offset -= stream->unread_data_len;
1780 return offset;
1784 static void
1785 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1786 void **ES__RESTRICT opaque_old)
1788 if (opaque_old)
1789 *opaque_old = stream->intern->opaque;
1790 if (opaque_new)
1791 stream->intern->opaque = opaque_new;
1795 static int
1796 es_get_fd (estream_t stream)
1798 return stream->intern->fd;
1803 /* API. */
1806 es_init (void)
1808 int err;
1810 err = es_init_do ();
1812 return err;
1815 estream_t
1816 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
1818 unsigned int flags;
1819 int create_called;
1820 estream_t stream;
1821 void *cookie;
1822 int err;
1823 int fd;
1825 stream = NULL;
1826 cookie = NULL;
1827 create_called = 0;
1829 err = es_convert_mode (mode, &flags);
1830 if (err)
1831 goto out;
1833 err = es_func_file_create (&cookie, &fd, path, flags);
1834 if (err)
1835 goto out;
1837 create_called = 1;
1838 err = es_create (&stream, cookie, fd, estream_functions_file);
1839 if (err)
1840 goto out;
1842 out:
1844 if (err && create_called)
1845 (*estream_functions_file.func_close) (cookie);
1847 return stream;
1851 estream_t
1852 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
1853 unsigned int grow,
1854 func_realloc_t func_realloc, func_free_t func_free,
1855 const char *ES__RESTRICT mode)
1857 unsigned int flags;
1858 int create_called;
1859 estream_t stream;
1860 void *cookie;
1861 int err;
1863 cookie = 0;
1864 stream = NULL;
1865 create_called = 0;
1867 err = es_convert_mode (mode, &flags);
1868 if (err)
1869 goto out;
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);
1874 if (err)
1875 goto out;
1877 create_called = 1;
1878 err = es_create (&stream, cookie, -1, estream_functions_mem);
1880 out:
1882 if (err && create_called)
1883 (*estream_functions_mem.func_close) (cookie);
1885 return stream;
1889 estream_t
1890 es_open_memstream (char **ptr, size_t *size)
1892 unsigned int flags;
1893 int create_called;
1894 estream_t stream;
1895 void *cookie;
1896 int err;
1898 flags = O_RDWR;
1899 create_called = 0;
1900 stream = NULL;
1901 cookie = 0;
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);
1906 if (err)
1907 goto out;
1909 create_called = 1;
1910 err = es_create (&stream, cookie, -1, estream_functions_mem);
1912 out:
1914 if (err && create_called)
1915 (*estream_functions_mem.func_close) (cookie);
1917 return stream;
1921 estream_t
1922 es_fopencookie (void *ES__RESTRICT cookie,
1923 const char *ES__RESTRICT mode,
1924 es_cookie_io_functions_t functions)
1926 unsigned int flags;
1927 estream_t stream;
1928 int err;
1930 stream = NULL;
1931 flags = 0;
1933 err = es_convert_mode (mode, &flags);
1934 if (err)
1935 goto out;
1937 err = es_create (&stream, cookie, -1, functions);
1938 if (err)
1939 goto out;
1941 out:
1943 return stream;
1947 estream_t
1948 es_fdopen (int filedes, const char *mode)
1950 unsigned int flags;
1951 int create_called;
1952 estream_t stream;
1953 void *cookie;
1954 int err;
1956 stream = NULL;
1957 cookie = NULL;
1958 create_called = 0;
1960 err = es_convert_mode (mode, &flags);
1961 if (err)
1962 goto out;
1964 err = es_func_fd_create (&cookie, filedes, flags);
1965 if (err)
1966 goto out;
1968 create_called = 1;
1969 err = es_create (&stream, cookie, filedes, estream_functions_fd);
1971 out:
1973 if (err && create_called)
1974 (*estream_functions_fd.func_close) (cookie);
1976 return stream;
1980 estream_t
1981 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
1982 estream_t ES__RESTRICT stream)
1984 int err;
1986 if (path)
1988 unsigned int flags;
1989 int create_called;
1990 void *cookie;
1991 int fd;
1993 cookie = NULL;
1994 create_called = 0;
1996 ESTREAM_LOCK (stream);
1998 es_deinitialize (stream);
2000 err = es_convert_mode (mode, &flags);
2001 if (err)
2002 goto leave;
2004 err = es_func_file_create (&cookie, &fd, path, flags);
2005 if (err)
2006 goto leave;
2008 create_called = 1;
2009 es_initialize (stream, cookie, fd, estream_functions_file);
2011 leave:
2013 if (err)
2015 if (create_called)
2016 es_func_fd_destroy (cookie);
2018 es_destroy (stream);
2019 stream = NULL;
2021 else
2022 ESTREAM_UNLOCK (stream);
2024 else
2026 /* FIXME? We don't support re-opening at the moment. */
2027 errno = EINVAL;
2028 es_deinitialize (stream);
2029 es_destroy (stream);
2030 stream = NULL;
2033 return stream;
2038 es_fclose (estream_t stream)
2040 int err;
2042 err = es_destroy (stream);
2044 return err;
2048 es_fileno_unlocked (estream_t stream)
2050 return es_get_fd (stream);
2054 void
2055 es_flockfile (estream_t stream)
2057 ESTREAM_LOCK (stream);
2062 es_ftrylockfile (estream_t stream)
2064 return ESTREAM_TRYLOCK (stream);
2068 void
2069 es_funlockfile (estream_t stream)
2071 ESTREAM_UNLOCK (stream);
2076 es_fileno (estream_t stream)
2078 int ret;
2080 ESTREAM_LOCK (stream);
2081 ret = es_fileno_unlocked (stream);
2082 ESTREAM_UNLOCK (stream);
2084 return ret;
2089 es_feof_unlocked (estream_t stream)
2091 return es_get_indicator (stream, 0, 1);
2096 es_feof (estream_t stream)
2098 int ret;
2100 ESTREAM_LOCK (stream);
2101 ret = es_feof_unlocked (stream);
2102 ESTREAM_UNLOCK (stream);
2104 return ret;
2109 es_ferror_unlocked (estream_t stream)
2111 return es_get_indicator (stream, 1, 0);
2116 es_ferror (estream_t stream)
2118 int ret;
2120 ESTREAM_LOCK (stream);
2121 ret = es_ferror_unlocked (stream);
2122 ESTREAM_UNLOCK (stream);
2124 return ret;
2128 void
2129 es_clearerr_unlocked (estream_t stream)
2131 es_set_indicators (stream, 0, 0);
2135 void
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)
2147 int err;
2149 if (stream)
2151 ESTREAM_LOCK (stream);
2152 if (stream->flags & ES_FLAG_WRITING)
2153 err = es_flush (stream);
2154 else
2156 es_empty (stream);
2157 err = 0;
2159 ESTREAM_UNLOCK (stream);
2161 else
2162 err = es_list_iterate (es_fflush);
2164 return err ? EOF : 0;
2169 es_fseek (estream_t stream, long int offset, int whence)
2171 int err;
2173 ESTREAM_LOCK (stream);
2174 err = es_seek (stream, offset, whence, NULL);
2175 ESTREAM_UNLOCK (stream);
2177 return err;
2182 es_fseeko (estream_t stream, off_t offset, int whence)
2184 int err;
2186 ESTREAM_LOCK (stream);
2187 err = es_seek (stream, offset, whence, NULL);
2188 ESTREAM_UNLOCK (stream);
2190 return err;
2194 long int
2195 es_ftell (estream_t stream)
2197 long int ret;
2199 ESTREAM_LOCK (stream);
2200 ret = es_offset_calculate (stream);
2201 ESTREAM_UNLOCK (stream);
2203 return ret;
2207 off_t
2208 es_ftello (estream_t stream)
2210 off_t ret = -1;
2212 ESTREAM_LOCK (stream);
2213 ret = es_offset_calculate (stream);
2214 ESTREAM_UNLOCK (stream);
2216 return ret;
2220 void
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)
2233 int err;
2234 unsigned char c;
2235 size_t bytes_read;
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;
2247 int err;
2249 err = es_writen (stream, &d, 1, NULL);
2251 return err ? EOF : c;
2256 es_fgetc (estream_t stream)
2258 int ret;
2260 ESTREAM_LOCK (stream);
2261 ret = es_getc_unlocked (stream);
2262 ESTREAM_UNLOCK (stream);
2264 return ret;
2269 es_fputc (int c, estream_t stream)
2271 int ret;
2273 ESTREAM_LOCK (stream);
2274 ret = es_putc_unlocked (c, stream);
2275 ESTREAM_UNLOCK (stream);
2277 return ret;
2282 es_ungetc (int c, estream_t stream)
2284 unsigned char data = (unsigned char) c;
2285 size_t data_unread;
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)
2300 int err;
2302 if (bytes_to_read)
2304 ESTREAM_LOCK (stream);
2305 err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2306 ESTREAM_UNLOCK (stream);
2308 else
2309 err = 0;
2311 return err;
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)
2320 int err;
2322 if (bytes_to_write)
2324 ESTREAM_LOCK (stream);
2325 err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2326 ESTREAM_UNLOCK (stream);
2328 else
2329 err = 0;
2331 return err;
2335 size_t
2336 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2337 estream_t ES__RESTRICT stream)
2339 size_t ret, bytes;
2340 int err;
2342 if (size * nitems)
2344 ESTREAM_LOCK (stream);
2345 err = es_readn (stream, ptr, size * nitems, &bytes);
2346 ESTREAM_UNLOCK (stream);
2348 ret = bytes / size;
2350 else
2351 ret = 0;
2353 return ret;
2357 size_t
2358 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2359 estream_t ES__RESTRICT stream)
2361 size_t ret, bytes;
2362 int err;
2364 if (size * nitems)
2366 ESTREAM_LOCK (stream);
2367 err = es_writen (stream, ptr, size * nitems, &bytes);
2368 ESTREAM_UNLOCK (stream);
2370 ret = bytes / size;
2372 else
2373 ret = 0;
2375 return ret;
2379 char *
2380 es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream)
2382 char *ret = NULL;
2384 if (n)
2386 int err;
2388 ESTREAM_LOCK (stream);
2389 err = doreadline (stream, n, &s, NULL);
2390 ESTREAM_UNLOCK (stream);
2391 if (! err)
2392 ret = s;
2395 return ret;
2400 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2402 size_t length;
2403 int err;
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;
2414 ssize_t
2415 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2416 estream_t ES__RESTRICT stream)
2418 char *line = NULL;
2419 size_t line_n = 0;
2420 int err;
2422 ESTREAM_LOCK (stream);
2423 err = doreadline (stream, 0, &line, &line_n);
2424 ESTREAM_UNLOCK (stream);
2425 if (err)
2426 goto out;
2428 if (*n)
2430 /* Caller wants us to use his buffer. */
2432 if (*n < (line_n + 1))
2434 /* Provided buffer is too small -> resize. */
2436 void *p;
2438 p = MEM_REALLOC (*lineptr, line_n + 1);
2439 if (! p)
2440 err = -1;
2441 else
2443 if (*lineptr != p)
2444 *lineptr = p;
2448 if (! err)
2450 memcpy (*lineptr, line, line_n + 1);
2451 if (*n != line_n)
2452 *n = line_n;
2454 MEM_FREE (line);
2456 else
2458 /* Caller wants new buffers. */
2459 *lineptr = line;
2460 *n = line_n;
2463 out:
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
2481 accordingly.
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.
2498 ssize_t
2499 es_read_line (estream_t stream,
2500 char **addr_of_buffer, size_t *length_of_buffer,
2501 size_t *max_length)
2503 int c;
2504 char *buffer = *addr_of_buffer;
2505 size_t length = *length_of_buffer;
2506 size_t nbytes = 0;
2507 size_t maxlen = max_length? *max_length : 0;
2508 char *p;
2510 if (!buffer)
2512 /* No buffer given - allocate a new one. */
2513 length = 256;
2514 buffer = MEM_ALLOC (length);
2515 *addr_of_buffer = buffer;
2516 if (!buffer)
2518 *length_of_buffer = 0;
2519 if (max_length)
2520 *max_length = 0;
2521 return -1;
2523 *length_of_buffer = length;
2526 if (length < 4)
2528 /* This should never happen. If it does, the fucntion has been
2529 called with wrong arguments. */
2530 errno = EINVAL;
2531 return -1;
2533 length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2535 ESTREAM_LOCK (stream);
2536 p = buffer;
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). */
2548 nbytes++;
2549 if (max_length)
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;
2559 MEM_FREE (buffer);
2560 *length_of_buffer = *max_length = 0;
2561 ESTREAM_UNLOCK (stream);
2562 errno = save_errno;
2563 return -1;
2565 buffer = *addr_of_buffer;
2566 *length_of_buffer = length;
2567 length -= 3;
2568 p = buffer + nbytes;
2570 *p++ = c;
2571 nbytes++;
2572 if (c == '\n')
2573 break;
2575 *p = 0; /* Make sure the line is a string. */
2576 ESTREAM_UNLOCK (stream);
2578 return nbytes;
2581 /* Wrapper around free() to match the memory allocation system used
2582 by estream. Should be used for all buffers returned to the caller
2583 by libestream. */
2584 void
2585 es_free (void *a)
2587 if (a)
2588 MEM_FREE (a);
2593 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2594 va_list ap)
2596 int ret;
2598 ESTREAM_LOCK (stream);
2599 ret = es_print (stream, format, ap);
2600 ESTREAM_UNLOCK (stream);
2602 return ret;
2607 es_fprintf (estream_t ES__RESTRICT stream,
2608 const char *ES__RESTRICT format, ...)
2610 int ret;
2612 va_list ap;
2613 va_start (ap, format);
2614 ESTREAM_LOCK (stream);
2615 ret = es_print (stream, format, ap);
2616 ESTREAM_UNLOCK (stream);
2617 va_end (ap);
2619 return ret;
2622 static int
2623 tmpfd (void)
2625 FILE *fp;
2626 int fp_fd;
2627 int fd;
2629 fp = NULL;
2630 fd = -1;
2632 fp = tmpfile ();
2633 if (! fp)
2634 goto out;
2636 fp_fd = fileno (fp);
2637 fd = dup (fp_fd);
2639 out:
2641 if (fp)
2642 fclose (fp);
2644 return fd;
2647 estream_t
2648 es_tmpfile (void)
2650 unsigned int flags;
2651 int create_called;
2652 estream_t stream;
2653 void *cookie;
2654 int err;
2655 int fd;
2657 create_called = 0;
2658 stream = NULL;
2659 flags = O_RDWR | O_TRUNC | O_CREAT;
2660 cookie = NULL;
2662 fd = tmpfd ();
2663 if (fd == -1)
2665 err = -1;
2666 goto out;
2669 err = es_func_fd_create (&cookie, fd, flags);
2670 if (err)
2671 goto out;
2673 create_called = 1;
2674 err = es_create (&stream, cookie, fd, estream_functions_fd);
2676 out:
2678 if (err)
2680 if (create_called)
2681 es_func_fd_destroy (cookie);
2682 else if (fd != -1)
2683 close (fd);
2684 stream = NULL;
2687 return stream;
2692 es_setvbuf (estream_t ES__RESTRICT stream,
2693 char *ES__RESTRICT buf, int type, size_t size)
2695 int err;
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);
2704 else
2706 errno = EINVAL;
2707 err = -1;
2710 return err;
2714 void
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);
2722 void
2723 es_opaque_set (estream_t stream, void *opaque)
2725 ESTREAM_LOCK (stream);
2726 es_opaque_ctrl (stream, opaque, NULL);
2727 ESTREAM_UNLOCK (stream);
2731 void *
2732 es_opaque_get (estream_t stream)
2734 void *opaque;
2736 ESTREAM_LOCK (stream);
2737 es_opaque_ctrl (stream, NULL, &opaque);
2738 ESTREAM_UNLOCK (stream);
2740 return opaque;