2006-10-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / estream.c
blobe056cb7b4979f72ea97d41c3beb6e22a97891217
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 <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdarg.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <stddef.h>
41 #include <assert.h>
43 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */
44 #undef HAVE_PTH
45 #undef USE_GNU_PTH
46 #endif
48 #ifdef HAVE_PTH
49 # include <pth.h>
50 #endif
52 #ifndef HAVE_MKSTEMP
53 int mkstemp (char *template);
54 #endif
56 #ifndef HAVE_MEMRCHR
57 void *memrchr (const void *block, int c, size_t size);
58 #endif
60 #include <estream.h>
64 /* Generally used types. */
66 typedef void *(*func_realloc_t) (void *mem, size_t size);
67 typedef void (*func_free_t) (void *mem);
71 /* Buffer management layer. */
73 #define BUFFER_BLOCK_SIZE BUFSIZ
74 #define BUFFER_UNREAD_SIZE 16
78 /* Macros. */
80 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
81 (((size) + (block_size - 1)) / block_size)
85 /* Locking. */
87 #ifdef HAVE_PTH
89 typedef pth_mutex_t estream_mutex_t;
90 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
91 # define ESTREAM_MUTEX_LOCK(mutex) \
92 pth_mutex_acquire (&(mutex), 0, NULL)
93 # define ESTREAM_MUTEX_UNLOCK(mutex) \
94 pth_mutex_release (&(mutex))
95 # define ESTREAM_MUTEX_TRYLOCK(mutex) \
96 ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
97 # define ESTREAM_MUTEX_INITIALIZE(mutex) \
98 pth_mutex_init (&(mutex))
99 # define ESTREAM_THREADING_INIT() ((pth_init () == TRUE) ? 0 : -1)
101 #else
103 typedef void *estream_mutex_t;
104 # define ESTREAM_MUTEX_INITIALIZER NULL
105 # define ESTREAM_MUTEX_LOCK(mutex) (void) 0
106 # define ESTREAM_MUTEX_UNLOCK(mutex) (void) 0
107 # define ESTREAM_MUTEX_TRYLOCK(mutex) 0
108 # define ESTREAM_MUTEX_INITIALIZE(mutex) (void) 0
109 # define ESTREAM_THREADING_INIT() 0
111 #endif
113 /* Memory allocator functions. */
115 #define MEM_ALLOC malloc
116 #define MEM_REALLOC realloc
117 #define MEM_FREE free
119 /* Primitive system I/O. */
121 #ifdef HAVE_PTH
122 # define ESTREAM_SYS_READ pth_read
123 # define ESTREAM_SYS_WRITE pth_write
124 #else
125 # define ESTREAM_SYS_READ read
126 # define ESTREAM_SYS_WRITE write
127 #endif
129 /* Misc definitions. */
131 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
133 #define ES_FLAG_WRITING ES__FLAG_WRITING
135 /* An internal stream object. */
137 struct estream_internal
139 unsigned char buffer[BUFFER_BLOCK_SIZE];
140 unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
141 estream_mutex_t lock; /* Lock. */
142 void *cookie; /* Cookie. */
143 void *opaque; /* Opaque data. */
144 unsigned int flags; /* Flags. */
145 off_t offset;
146 es_cookie_read_function_t func_read;
147 es_cookie_write_function_t func_write;
148 es_cookie_seek_function_t func_seek;
149 es_cookie_close_function_t func_close;
150 int strategy;
151 int fd;
152 struct
154 unsigned int err: 1;
155 unsigned int eof: 1;
156 } indicators;
157 unsigned int deallocate_buffer: 1;
158 unsigned int print_err: 1; /* Error in print_fun_writer. */
159 int print_errno; /* Errno from print_fun_writer. */
160 size_t print_ntotal; /* Bytes written from in print_fun_writer. */
161 FILE *print_fp; /* Stdio stream used by print_fun_writer. */
165 typedef struct estream_internal *estream_internal_t;
167 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
168 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
169 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
171 /* Stream list. */
173 typedef struct estream_list *estream_list_t;
175 struct estream_list
177 estream_t car;
178 estream_list_t cdr;
179 estream_list_t *prev_cdr;
182 static estream_list_t estream_list;
183 #ifdef HAVE_PTH
184 static estream_mutex_t estream_list_lock = ESTREAM_MUTEX_INITIALIZER;
185 #endif
187 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
188 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
190 #ifndef EOPNOTSUPP
191 # define EOPNOTSUPP ENOSYS
192 #endif
197 /* Macros. */
199 /* Calculate array dimension. */
200 #define DIM(array) (sizeof (array) / sizeof (*array))
202 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
203 VARIABLE is zero. */
204 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
205 do \
207 tmp_variable = expression; \
208 if ((! variable) && tmp_variable) \
209 variable = tmp_variable; \
211 while (0)
214 * List manipulation.
217 /* Add STREAM to the list of registered stream objects. */
218 static int
219 es_list_add (estream_t stream)
221 estream_list_t list_obj;
222 int ret;
224 list_obj = MEM_ALLOC (sizeof (*list_obj));
225 if (! list_obj)
226 ret = -1;
227 else
229 ESTREAM_LIST_LOCK;
230 list_obj->car = stream;
231 list_obj->cdr = estream_list;
232 list_obj->prev_cdr = &estream_list;
233 if (estream_list)
234 estream_list->prev_cdr = &list_obj->cdr;
235 estream_list = list_obj;
236 ESTREAM_LIST_UNLOCK;
237 ret = 0;
240 return ret;
243 /* Remove STREAM from the list of registered stream objects. */
244 static void
245 es_list_remove (estream_t stream)
247 estream_list_t list_obj;
249 ESTREAM_LIST_LOCK;
250 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
251 if (list_obj->car == stream)
253 *list_obj->prev_cdr = list_obj->cdr;
254 if (list_obj->cdr)
255 list_obj->cdr->prev_cdr = list_obj->prev_cdr;
256 MEM_FREE (list_obj);
257 break;
259 ESTREAM_LIST_UNLOCK;
262 /* Type of an stream-iterator-function. */
263 typedef int (*estream_iterator_t) (estream_t stream);
265 /* Iterate over list of registered streams, calling ITERATOR for each
266 of them. */
267 static int
268 es_list_iterate (estream_iterator_t iterator)
270 estream_list_t list_obj;
271 int ret = 0;
273 ESTREAM_LIST_LOCK;
274 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
275 ret |= (*iterator) (list_obj->car);
276 ESTREAM_LIST_UNLOCK;
278 return ret;
284 * Initialization.
287 static int
288 es_init_do (void)
290 int err;
292 err = ESTREAM_THREADING_INIT ();
294 return err;
300 * I/O methods.
303 /* Implementation of Memory I/O. */
305 /* Cookie for memory objects. */
306 typedef struct estream_cookie_mem
308 unsigned int flags; /* Open flags. */
309 unsigned char *memory; /* Data. */
310 size_t memory_size; /* Size of MEMORY. */
311 size_t offset; /* Current offset in MEMORY. */
312 size_t data_len; /* Length of data in MEMORY. */
313 size_t block_size; /* Block size. */
314 unsigned int grow: 1; /* MEMORY is allowed to grow. */
315 unsigned int append_zero: 1; /* Append zero after data. */
316 unsigned int dont_free: 1; /* Append zero after data. */
317 char **ptr;
318 size_t *size;
319 func_realloc_t func_realloc;
320 func_free_t func_free;
321 } *estream_cookie_mem_t;
323 /* Create function for memory objects. */
324 static int
325 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
326 unsigned char *ES__RESTRICT data, size_t data_n,
327 size_t data_len,
328 size_t block_size, unsigned int grow,
329 unsigned int append_zero, unsigned int dont_free,
330 char **ptr, size_t *size,
331 func_realloc_t func_realloc, func_free_t func_free,
332 unsigned int flags)
334 estream_cookie_mem_t mem_cookie;
335 int err;
337 mem_cookie = MEM_ALLOC (sizeof (*mem_cookie));
338 if (! mem_cookie)
339 err = -1;
340 else
342 mem_cookie->flags = flags;
343 mem_cookie->memory = data;
344 mem_cookie->memory_size = data_n;
345 mem_cookie->offset = 0;
346 mem_cookie->data_len = data_len;
347 mem_cookie->block_size = block_size;
348 mem_cookie->grow = grow ? 1 : 0;
349 mem_cookie->append_zero = append_zero ? 1 : 0;
350 mem_cookie->dont_free = dont_free ? 1 : 0;
351 mem_cookie->ptr = ptr;
352 mem_cookie->size = size;
353 mem_cookie->func_realloc = func_realloc ? func_realloc : MEM_REALLOC;
354 mem_cookie->func_free = func_free ? func_free : MEM_FREE;
355 mem_cookie->offset = 0;
356 *cookie = mem_cookie;
357 err = 0;
360 return err;
363 /* Read function for memory objects. */
364 static ssize_t
365 es_func_mem_read (void *cookie, void *buffer, size_t size)
367 estream_cookie_mem_t mem_cookie = cookie;
368 ssize_t ret;
370 if (size > mem_cookie->data_len - mem_cookie->offset)
371 size = mem_cookie->data_len - mem_cookie->offset;
373 if (size)
375 memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
376 mem_cookie->offset += size;
379 ret = size;
381 return ret;
384 /* Write function for memory objects. */
385 static ssize_t
386 es_func_mem_write (void *cookie, const void *buffer, size_t size)
388 estream_cookie_mem_t mem_cookie = cookie;
389 func_realloc_t func_realloc = mem_cookie->func_realloc;
390 unsigned char *memory_new;
391 size_t newsize;
392 ssize_t ret;
393 int err;
395 if (size)
397 /* Regular write. */
399 if (mem_cookie->flags & O_APPEND)
400 /* Append to data. */
401 mem_cookie->offset = mem_cookie->data_len;
403 if (! mem_cookie->grow)
404 if (size > mem_cookie->memory_size - mem_cookie->offset)
405 size = mem_cookie->memory_size - mem_cookie->offset;
407 err = 0;
409 while (size > (mem_cookie->memory_size - mem_cookie->offset))
411 memory_new = (*func_realloc) (mem_cookie->memory,
412 mem_cookie->memory_size
413 + mem_cookie->block_size);
414 if (! memory_new)
416 err = -1;
417 break;
419 else
421 if (mem_cookie->memory != memory_new)
422 mem_cookie->memory = memory_new;
423 mem_cookie->memory_size += mem_cookie->block_size;
426 if (err)
427 goto out;
429 if (size)
431 memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
432 if (mem_cookie->offset + size > mem_cookie->data_len)
433 mem_cookie->data_len = mem_cookie->offset + size;
434 mem_cookie->offset += size;
437 else
439 /* Flush. */
441 err = 0;
442 if (mem_cookie->append_zero)
444 if (mem_cookie->data_len >= mem_cookie->memory_size)
446 newsize = BUFFER_ROUND_TO_BLOCK (mem_cookie->data_len + 1,
447 mem_cookie->block_size)
448 * mem_cookie->block_size;
450 memory_new = (*func_realloc) (mem_cookie->memory, newsize);
451 if (! memory_new)
453 err = -1;
454 goto out;
457 if (mem_cookie->memory != memory_new)
458 mem_cookie->memory = memory_new;
459 mem_cookie->memory_size = newsize;
462 mem_cookie->memory[mem_cookie->data_len + 1] = 0;
465 /* Return information to user if necessary. */
466 if (mem_cookie->ptr)
467 *mem_cookie->ptr = (char *) mem_cookie->memory;
468 if (mem_cookie->size)
469 *mem_cookie->size = mem_cookie->data_len;
472 out:
474 if (err)
475 ret = -1;
476 else
477 ret = size;
479 return ret;
482 /* Seek function for memory objects. */
483 static int
484 es_func_mem_seek (void *cookie, off_t *offset, int whence)
486 estream_cookie_mem_t mem_cookie = cookie;
487 off_t pos_new;
488 int err = 0;
490 switch (whence)
492 case SEEK_SET:
493 pos_new = *offset;
494 break;
496 case SEEK_CUR:
497 pos_new = mem_cookie->offset += *offset;
498 break;
500 case SEEK_END:
501 pos_new = mem_cookie->data_len += *offset;
502 break;
504 default:
505 /* Never reached. */
506 pos_new = 0;
509 if (pos_new > mem_cookie->memory_size)
511 /* Grow buffer if possible. */
513 if (mem_cookie->grow)
515 func_realloc_t func_realloc = mem_cookie->func_realloc;
516 size_t newsize;
517 void *p;
519 newsize = BUFFER_ROUND_TO_BLOCK (pos_new, mem_cookie->block_size);
520 p = (*func_realloc) (mem_cookie->memory, newsize);
521 if (! p)
523 err = -1;
524 goto out;
526 else
528 if (mem_cookie->memory != p)
529 mem_cookie->memory = p;
530 mem_cookie->memory_size = newsize;
533 else
535 errno = EINVAL;
536 err = -1;
537 goto out;
541 if (pos_new > mem_cookie->data_len)
542 /* Fill spare space with zeroes. */
543 memset (mem_cookie->memory + mem_cookie->data_len,
544 0, pos_new - mem_cookie->data_len);
546 mem_cookie->offset = pos_new;
547 *offset = pos_new;
549 out:
551 return err;
554 /* Destroy function for memory objects. */
555 static int
556 es_func_mem_destroy (void *cookie)
558 estream_cookie_mem_t mem_cookie = cookie;
559 func_free_t func_free = mem_cookie->func_free;
561 if (! mem_cookie->dont_free)
562 (*func_free) (mem_cookie->memory);
563 MEM_FREE (mem_cookie);
565 return 0;
568 static es_cookie_io_functions_t estream_functions_mem =
570 es_func_mem_read,
571 es_func_mem_write,
572 es_func_mem_seek,
573 es_func_mem_destroy
576 /* Implementation of fd I/O. */
578 /* Cookie for fd objects. */
579 typedef struct estream_cookie_fd
581 int fd;
582 } *estream_cookie_fd_t;
584 /* Create function for fd objects. */
585 static int
586 es_func_fd_create (void **cookie, int fd, unsigned int flags)
588 estream_cookie_fd_t fd_cookie;
589 int err;
591 fd_cookie = MEM_ALLOC (sizeof (*fd_cookie));
592 if (! fd_cookie)
593 err = -1;
594 else
596 fd_cookie->fd = fd;
597 *cookie = fd_cookie;
598 err = 0;
601 return err;
604 /* Read function for fd objects. */
605 static ssize_t
606 es_func_fd_read (void *cookie, void *buffer, size_t size)
609 estream_cookie_fd_t file_cookie = cookie;
610 ssize_t bytes_read;
613 bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
614 while (bytes_read == -1 && errno == EINTR);
616 return bytes_read;
619 /* Write function for fd objects. */
620 static ssize_t
621 es_func_fd_write (void *cookie, const void *buffer, size_t size)
624 estream_cookie_fd_t file_cookie = cookie;
625 ssize_t bytes_written;
628 bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
629 while (bytes_written == -1 && errno == EINTR);
631 return bytes_written;
634 /* Seek function for fd objects. */
635 static int
636 es_func_fd_seek (void *cookie, off_t *offset, int whence)
638 estream_cookie_fd_t file_cookie = cookie;
639 off_t offset_new;
640 int err;
642 offset_new = lseek (file_cookie->fd, *offset, whence);
643 if (offset_new == -1)
644 err = -1;
645 else
647 *offset = offset_new;
648 err = 0;
651 return err;
654 /* Destroy function for fd objects. */
655 static int
656 es_func_fd_destroy (void *cookie)
658 estream_cookie_fd_t fd_cookie = cookie;
659 int err;
661 if (fd_cookie)
663 err = close (fd_cookie->fd);
664 MEM_FREE (fd_cookie);
666 else
667 err = 0;
669 return err;
672 static es_cookie_io_functions_t estream_functions_fd =
674 es_func_fd_read,
675 es_func_fd_write,
676 es_func_fd_seek,
677 es_func_fd_destroy
680 /* Implementation of file I/O. */
682 /* Create function for file objects. */
683 static int
684 es_func_file_create (void **cookie, int *filedes,
685 const char *path, unsigned int flags)
687 estream_cookie_fd_t file_cookie;
688 int err;
689 int fd;
691 err = 0;
692 fd = -1;
694 file_cookie = MEM_ALLOC (sizeof (*file_cookie));
695 if (! file_cookie)
697 err = -1;
698 goto out;
701 fd = open (path, flags, ES_DEFAULT_OPEN_MODE);
702 if (fd == -1)
704 err = -1;
705 goto out;
708 file_cookie->fd = fd;
709 *cookie = file_cookie;
710 *filedes = fd;
712 out:
714 if (err)
715 MEM_FREE (file_cookie);
717 return err;
720 static es_cookie_io_functions_t estream_functions_file =
722 es_func_fd_read,
723 es_func_fd_write,
724 es_func_fd_seek,
725 es_func_fd_destroy
730 /* Stream primitives. */
732 static int
733 es_convert_mode (const char *mode, unsigned int *flags)
735 struct
737 const char *mode;
738 unsigned int flags;
739 } mode_flags[] = { { "r",
740 O_RDONLY },
741 { "rb",
742 O_RDONLY },
743 { "w",
744 O_WRONLY | O_TRUNC | O_CREAT },
745 { "wb",
746 O_WRONLY | O_TRUNC | O_CREAT },
747 { "a",
748 O_WRONLY | O_APPEND | O_CREAT },
749 { "ab",
750 O_WRONLY | O_APPEND | O_CREAT },
751 { "r+",
752 O_RDWR },
753 { "rb+",
754 O_RDWR },
755 { "r+b",
756 O_RDONLY | O_WRONLY },
757 { "w+",
758 O_RDWR | O_TRUNC | O_CREAT },
759 { "wb+",
760 O_RDWR | O_TRUNC | O_CREAT },
761 { "w+b",
762 O_RDWR | O_TRUNC | O_CREAT },
763 { "a+",
764 O_RDWR | O_CREAT | O_APPEND },
765 { "ab+",
766 O_RDWR | O_CREAT | O_APPEND },
767 { "a+b",
768 O_RDWR | O_CREAT | O_APPEND } };
769 unsigned int i;
770 int err;
772 for (i = 0; i < DIM (mode_flags); i++)
773 if (! strcmp (mode_flags[i].mode, mode))
774 break;
775 if (i == DIM (mode_flags))
777 errno = EINVAL;
778 err = -1;
780 else
782 err = 0;
783 *flags = mode_flags[i].flags;
786 return err;
792 * Low level stream functionality.
795 static int
796 es_fill (estream_t stream)
798 size_t bytes_read = 0;
799 int err;
801 if (!stream->intern->func_read)
803 errno = EOPNOTSUPP;
804 err = -1;
806 else
808 es_cookie_read_function_t func_read = stream->intern->func_read;
809 ssize_t ret;
811 ret = (*func_read) (stream->intern->cookie,
812 stream->buffer, stream->buffer_size);
813 if (ret == -1)
815 bytes_read = 0;
816 err = -1;
818 else
820 bytes_read = ret;
821 err = 0;
825 if (err)
826 stream->intern->indicators.err = 1;
827 else if (!bytes_read)
828 stream->intern->indicators.eof = 1;
830 stream->intern->offset += stream->data_len;
831 stream->data_len = bytes_read;
832 stream->data_offset = 0;
834 return err;
837 static int
838 es_flush (estream_t stream)
840 es_cookie_write_function_t func_write = stream->intern->func_write;
841 int err;
843 assert (stream->flags & ES_FLAG_WRITING);
845 if (stream->data_offset)
847 size_t bytes_written;
848 size_t data_flushed;
849 ssize_t ret;
851 if (! func_write)
853 err = EOPNOTSUPP;
854 goto out;
857 /* Note: to prevent an endless loop caused by user-provided
858 write-functions that pretend to have written more bytes than
859 they were asked to write, we have to check for
860 "(stream->data_offset - data_flushed) > 0" instead of
861 "stream->data_offset - data_flushed". */
863 data_flushed = 0;
864 err = 0;
866 while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
868 ret = (*func_write) (stream->intern->cookie,
869 stream->buffer + data_flushed,
870 stream->data_offset - data_flushed);
871 if (ret == -1)
873 bytes_written = 0;
874 err = -1;
876 else
877 bytes_written = ret;
879 data_flushed += bytes_written;
880 if (err)
881 break;
884 stream->data_flushed += data_flushed;
885 if (stream->data_offset == data_flushed)
887 stream->intern->offset += stream->data_offset;
888 stream->data_offset = 0;
889 stream->data_flushed = 0;
891 /* Propagate flush event. */
892 (*func_write) (stream->intern->cookie, NULL, 0);
895 else
896 err = 0;
898 out:
900 if (err)
901 stream->intern->indicators.err = 1;
903 return err;
906 /* Discard buffered data for STREAM. */
907 static void
908 es_empty (estream_t stream)
910 assert (! (stream->flags & ES_FLAG_WRITING));
911 stream->data_len = 0;
912 stream->data_offset = 0;
913 stream->unread_data_len = 0;
916 /* Initialize STREAM. */
917 static void
918 es_initialize (estream_t stream,
919 void *cookie, int fd, es_cookie_io_functions_t functions)
921 stream->intern->cookie = cookie;
922 stream->intern->opaque = NULL;
923 stream->intern->offset = 0;
924 stream->intern->func_read = functions.func_read;
925 stream->intern->func_write = functions.func_write;
926 stream->intern->func_seek = functions.func_seek;
927 stream->intern->func_close = functions.func_close;
928 stream->intern->strategy = _IOFBF;
929 stream->intern->fd = fd;
930 stream->intern->print_err = 0;
931 stream->intern->print_errno = 0;
932 stream->intern->print_ntotal = 0;
933 stream->intern->print_fp = NULL;
934 stream->intern->indicators.err = 0;
935 stream->intern->indicators.eof = 0;
936 stream->intern->deallocate_buffer = 0;
938 stream->data_len = 0;
939 stream->data_offset = 0;
940 stream->data_flushed = 0;
941 stream->unread_data_len = 0;
942 stream->flags = 0;
945 /* Deinitialize STREAM. */
946 static int
947 es_deinitialize (estream_t stream)
949 es_cookie_close_function_t func_close;
950 int err, tmp_err;
952 if (stream->intern->print_fp)
954 int save_errno = errno;
955 fclose (stream->intern->print_fp);
956 stream->intern->print_fp = NULL;
957 errno = save_errno;
960 func_close = stream->intern->func_close;
962 err = 0;
963 if (stream->flags & ES_FLAG_WRITING)
964 SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
965 if (func_close)
966 SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
969 return err;
972 /* Create a new stream object, initialize it. */
973 static int
974 es_create (estream_t *stream, void *cookie, int fd,
975 es_cookie_io_functions_t functions)
977 estream_internal_t stream_internal_new;
978 estream_t stream_new;
979 int err;
981 stream_new = NULL;
982 stream_internal_new = NULL;
984 stream_new = MEM_ALLOC (sizeof (*stream_new));
985 if (! stream_new)
987 err = -1;
988 goto out;
991 stream_internal_new = MEM_ALLOC (sizeof (*stream_internal_new));
992 if (! stream_internal_new)
994 err = -1;
995 goto out;
998 stream_new->buffer = stream_internal_new->buffer;
999 stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1000 stream_new->unread_buffer = stream_internal_new->unread_buffer;
1001 stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1002 stream_new->intern = stream_internal_new;
1004 ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
1005 es_initialize (stream_new, cookie, fd, functions);
1007 err = es_list_add (stream_new);
1008 if (err)
1009 goto out;
1011 *stream = stream_new;
1013 out:
1015 if (err)
1017 if (stream_new)
1019 es_deinitialize (stream_new);
1020 MEM_FREE (stream_new);
1024 return err;
1027 /* Deinitialize a stream object and destroy it. */
1028 static int
1029 es_destroy (estream_t stream)
1031 int err = 0;
1033 if (stream)
1035 es_list_remove (stream);
1036 err = es_deinitialize (stream);
1037 MEM_FREE (stream->intern);
1038 MEM_FREE (stream);
1041 return err;
1044 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1045 unbuffered-mode, storing the amount of bytes read in
1046 *BYTES_READ. */
1047 static int
1048 es_read_nbf (estream_t ES__RESTRICT stream,
1049 unsigned char *ES__RESTRICT buffer,
1050 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1052 es_cookie_read_function_t func_read = stream->intern->func_read;
1053 size_t data_read;
1054 ssize_t ret;
1055 int err;
1057 data_read = 0;
1058 err = 0;
1060 while (bytes_to_read - data_read)
1062 ret = (*func_read) (stream->intern->cookie,
1063 buffer + data_read, bytes_to_read - data_read);
1064 if (ret == -1)
1066 err = -1;
1067 break;
1069 else if (ret)
1070 data_read += ret;
1071 else
1072 break;
1075 stream->intern->offset += data_read;
1076 *bytes_read = data_read;
1078 return err;
1081 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1082 fully-buffered-mode, storing the amount of bytes read in
1083 *BYTES_READ. */
1084 static int
1085 es_read_fbf (estream_t ES__RESTRICT stream,
1086 unsigned char *ES__RESTRICT buffer,
1087 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1089 size_t data_available;
1090 size_t data_to_read;
1091 size_t data_read;
1092 int err;
1094 data_read = 0;
1095 err = 0;
1097 while ((bytes_to_read - data_read) && (! err))
1099 if (stream->data_offset == stream->data_len)
1101 /* Nothing more to read in current container, try to
1102 fill container with new data. */
1103 err = es_fill (stream);
1104 if (! err)
1105 if (! stream->data_len)
1106 /* Filling did not result in any data read. */
1107 break;
1110 if (! err)
1112 /* Filling resulted in some new data. */
1114 data_to_read = bytes_to_read - data_read;
1115 data_available = stream->data_len - stream->data_offset;
1116 if (data_to_read > data_available)
1117 data_to_read = data_available;
1119 memcpy (buffer + data_read,
1120 stream->buffer + stream->data_offset, data_to_read);
1121 stream->data_offset += data_to_read;
1122 data_read += data_to_read;
1126 *bytes_read = data_read;
1128 return err;
1131 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1132 line-buffered-mode, storing the amount of bytes read in
1133 *BYTES_READ. */
1134 static int
1135 es_read_lbf (estream_t ES__RESTRICT stream,
1136 unsigned char *ES__RESTRICT buffer,
1137 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1139 int err;
1141 err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1143 return err;
1146 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1147 *the amount of bytes read in BYTES_READ. */
1148 static int
1149 es_readn (estream_t ES__RESTRICT stream,
1150 void *ES__RESTRICT buffer_arg,
1151 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1153 unsigned char *buffer = (unsigned char *)buffer_arg;
1154 size_t data_read_unread, data_read;
1155 int err;
1157 data_read_unread = 0;
1158 data_read = 0;
1159 err = 0;
1161 if (stream->flags & ES_FLAG_WRITING)
1163 /* Switching to reading mode -> flush output. */
1164 err = es_flush (stream);
1165 if (err)
1166 goto out;
1167 stream->flags &= ~ES_FLAG_WRITING;
1170 /* Read unread data first. */
1171 while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1173 buffer[data_read_unread]
1174 = stream->unread_buffer[stream->unread_data_len - 1];
1175 stream->unread_data_len--;
1176 data_read_unread++;
1179 switch (stream->intern->strategy)
1181 case _IONBF:
1182 err = es_read_nbf (stream,
1183 buffer + data_read_unread,
1184 bytes_to_read - data_read_unread, &data_read);
1185 break;
1186 case _IOLBF:
1187 err = es_read_lbf (stream,
1188 buffer + data_read_unread,
1189 bytes_to_read - data_read_unread, &data_read);
1190 break;
1191 case _IOFBF:
1192 err = es_read_fbf (stream,
1193 buffer + data_read_unread,
1194 bytes_to_read - data_read_unread, &data_read);
1195 break;
1198 out:
1200 if (bytes_read)
1201 *bytes_read = data_read_unread + data_read;
1203 return err;
1206 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1207 amount of bytes succesfully unread in *BYTES_UNREAD. */
1208 static void
1209 es_unreadn (estream_t ES__RESTRICT stream,
1210 const unsigned char *ES__RESTRICT data, size_t data_n,
1211 size_t *ES__RESTRICT bytes_unread)
1213 size_t space_left;
1215 space_left = stream->unread_buffer_size - stream->unread_data_len;
1217 if (data_n > space_left)
1218 data_n = space_left;
1220 if (! data_n)
1221 goto out;
1223 memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1224 stream->unread_data_len += data_n;
1225 stream->intern->indicators.eof = 0;
1227 out:
1229 if (bytes_unread)
1230 *bytes_unread = data_n;
1233 /* Seek in STREAM. */
1234 static int
1235 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1236 off_t *ES__RESTRICT offset_new)
1238 es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1239 int err, ret;
1240 off_t off;
1242 if (! func_seek)
1244 errno = EOPNOTSUPP;
1245 err = -1;
1246 goto out;
1249 if (stream->flags & ES_FLAG_WRITING)
1251 /* Flush data first in order to prevent flushing it to the wrong
1252 offset. */
1253 err = es_flush (stream);
1254 if (err)
1255 goto out;
1256 stream->flags &= ~ES_FLAG_WRITING;
1259 off = offset;
1260 if (whence == SEEK_CUR)
1262 off = off - stream->data_len + stream->data_offset;
1263 off -= stream->unread_data_len;
1266 ret = (*func_seek) (stream->intern->cookie, &off, whence);
1267 if (ret == -1)
1269 err = -1;
1270 goto out;
1273 err = 0;
1274 es_empty (stream);
1276 if (offset_new)
1277 *offset_new = off;
1279 stream->intern->indicators.eof = 0;
1280 stream->intern->offset = off;
1282 out:
1284 if (err)
1285 stream->intern->indicators.err = 1;
1287 return err;
1290 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1291 unbuffered-mode, storing the amount of bytes written in
1292 *BYTES_WRITTEN. */
1293 static int
1294 es_write_nbf (estream_t ES__RESTRICT stream,
1295 const unsigned char *ES__RESTRICT buffer,
1296 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1298 es_cookie_write_function_t func_write = stream->intern->func_write;
1299 size_t data_written;
1300 ssize_t ret;
1301 int err;
1303 if (bytes_to_write && (! func_write))
1305 err = EOPNOTSUPP;
1306 goto out;
1309 data_written = 0;
1310 err = 0;
1312 while (bytes_to_write - data_written)
1314 ret = (*func_write) (stream->intern->cookie,
1315 buffer + data_written,
1316 bytes_to_write - data_written);
1317 if (ret == -1)
1319 err = -1;
1320 break;
1322 else
1323 data_written += ret;
1326 stream->intern->offset += data_written;
1327 *bytes_written = data_written;
1329 out:
1331 return err;
1334 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1335 fully-buffered-mode, storing the amount of bytes written in
1336 *BYTES_WRITTEN. */
1337 static int
1338 es_write_fbf (estream_t ES__RESTRICT stream,
1339 const unsigned char *ES__RESTRICT buffer,
1340 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1342 size_t space_available;
1343 size_t data_to_write;
1344 size_t data_written;
1345 int err;
1347 data_written = 0;
1348 err = 0;
1350 while ((bytes_to_write - data_written) && (! err))
1352 if (stream->data_offset == stream->buffer_size)
1353 /* Container full, flush buffer. */
1354 err = es_flush (stream);
1356 if (! err)
1358 /* Flushing resulted in empty container. */
1360 data_to_write = bytes_to_write - data_written;
1361 space_available = stream->buffer_size - stream->data_offset;
1362 if (data_to_write > space_available)
1363 data_to_write = space_available;
1365 memcpy (stream->buffer + stream->data_offset,
1366 buffer + data_written, data_to_write);
1367 stream->data_offset += data_to_write;
1368 data_written += data_to_write;
1372 *bytes_written = data_written;
1374 return err;
1378 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1379 line-buffered-mode, storing the amount of bytes written in
1380 *BYTES_WRITTEN. */
1381 static int
1382 es_write_lbf (estream_t ES__RESTRICT stream,
1383 const unsigned char *ES__RESTRICT buffer,
1384 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1386 size_t data_flushed = 0;
1387 size_t data_buffered = 0;
1388 unsigned char *nlp;
1389 int err = 0;
1391 nlp = memrchr (buffer, '\n', bytes_to_write);
1392 if (nlp)
1394 /* Found a newline, directly write up to (including) this
1395 character. */
1396 err = es_flush (stream);
1397 if (!err)
1398 err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1401 if (!err)
1403 /* Write remaining data fully buffered. */
1404 err = es_write_fbf (stream, buffer + data_flushed,
1405 bytes_to_write - data_flushed, &data_buffered);
1408 *bytes_written = data_flushed + data_buffered;
1409 return err;
1413 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1414 amount of bytes written in BYTES_WRITTEN. */
1415 static int
1416 es_writen (estream_t ES__RESTRICT stream,
1417 const void *ES__RESTRICT buffer,
1418 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1420 size_t data_written;
1421 int err;
1423 data_written = 0;
1424 err = 0;
1426 if (! (stream->flags & ES_FLAG_WRITING))
1428 /* Switching to writing mode -> discard input data and seek to
1429 position at which reading has stopped. We can do this only
1430 if a seek function has been registered. */
1431 if (stream->intern->func_seek)
1433 err = es_seek (stream, 0, SEEK_CUR, NULL);
1434 if (err)
1436 if (errno == ESPIPE)
1437 err = 0;
1438 else
1439 goto out;
1444 switch (stream->intern->strategy)
1446 case _IONBF:
1447 err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1448 break;
1450 case _IOLBF:
1451 err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1452 break;
1454 case _IOFBF:
1455 err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1456 break;
1459 out:
1461 if (bytes_written)
1462 *bytes_written = data_written;
1463 if (data_written)
1464 if (! (stream->flags & ES_FLAG_WRITING))
1465 stream->flags |= ES_FLAG_WRITING;
1467 return err;
1471 static int
1472 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1473 size_t *ES__RESTRICT data_len)
1475 int err;
1477 if (stream->flags & ES_FLAG_WRITING)
1479 /* Switching to reading mode -> flush output. */
1480 err = es_flush (stream);
1481 if (err)
1482 goto out;
1483 stream->flags &= ~ES_FLAG_WRITING;
1486 if (stream->data_offset == stream->data_len)
1488 /* Refill container. */
1489 err = es_fill (stream);
1490 if (err)
1491 goto out;
1494 if (data)
1495 *data = stream->buffer + stream->data_offset;
1496 if (data_len)
1497 *data_len = stream->data_len - stream->data_offset;
1498 err = 0;
1500 out:
1502 return err;
1506 /* Skip SIZE bytes of input data contained in buffer. */
1507 static int
1508 es_skip (estream_t stream, size_t size)
1510 int err;
1512 if (stream->data_offset + size > stream->data_len)
1514 errno = EINVAL;
1515 err = -1;
1517 else
1519 stream->data_offset += size;
1520 err = 0;
1523 return err;
1527 static int
1528 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
1529 char *ES__RESTRICT *ES__RESTRICT line,
1530 size_t *ES__RESTRICT line_length)
1532 size_t space_left;
1533 size_t line_size;
1534 estream_t line_stream;
1535 char *line_new;
1536 void *line_stream_cookie;
1537 char *newline;
1538 unsigned char *data;
1539 size_t data_len;
1540 int err;
1542 line_new = NULL;
1543 line_stream = NULL;
1544 line_stream_cookie = NULL;
1546 err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0, BUFFER_BLOCK_SIZE,
1547 1, 0, 0, NULL, 0, MEM_REALLOC, MEM_FREE, O_RDWR);
1548 if (err)
1549 goto out;
1551 err = es_create (&line_stream, line_stream_cookie, -1,
1552 estream_functions_mem);
1553 if (err)
1554 goto out;
1556 space_left = max_length;
1557 line_size = 0;
1558 while (1)
1560 if (max_length && (space_left == 1))
1561 break;
1563 err = es_peek (stream, &data, &data_len);
1564 if (err || (! data_len))
1565 break;
1567 if (data_len > (space_left - 1))
1568 data_len = space_left - 1;
1570 newline = memchr (data, '\n', data_len);
1571 if (newline)
1573 data_len = (newline - (char *) data) + 1;
1574 err = es_write (line_stream, data, data_len, NULL);
1575 if (! err)
1577 space_left -= data_len;
1578 line_size += data_len;
1579 es_skip (stream, data_len);
1580 break;
1583 else
1585 err = es_write (line_stream, data, data_len, NULL);
1586 if (! err)
1588 space_left -= data_len;
1589 line_size += data_len;
1590 es_skip (stream, data_len);
1593 if (err)
1594 break;
1596 if (err)
1597 goto out;
1599 /* Complete line has been written to line_stream. */
1601 if ((max_length > 1) && (! line_size))
1603 stream->intern->indicators.eof = 1;
1604 goto out;
1607 err = es_seek (line_stream, 0, SEEK_SET, NULL);
1608 if (err)
1609 goto out;
1611 if (! *line)
1613 line_new = MEM_ALLOC (line_size + 1);
1614 if (! line_new)
1616 err = -1;
1617 goto out;
1620 else
1621 line_new = *line;
1623 err = es_read (line_stream, line_new, line_size, NULL);
1624 if (err)
1625 goto out;
1627 line_new[line_size] = '\0';
1629 if (! *line)
1630 *line = line_new;
1631 if (line_length)
1632 *line_length = line_size;
1634 out:
1636 if (line_stream)
1637 es_destroy (line_stream);
1638 else if (line_stream_cookie)
1639 es_func_mem_destroy (line_stream_cookie);
1641 if (err)
1643 if (! *line)
1644 MEM_FREE (line_new);
1645 stream->intern->indicators.err = 1;
1648 return err;
1652 /* Helper for esprint. */
1653 #if defined(HAVE_FOPENCOOKIE) || defined(HAVE_FUNOPEN)
1654 static int
1655 print_fun_writer (void *cookie_arg, const char *buffer, size_t size)
1657 estream_t stream = cookie_arg;
1658 size_t nwritten;
1660 /* We don't return an error but let es_print check whether an error
1661 has occured. Internally we skip everything after an error. */
1662 if (!stream->intern->print_err)
1664 if (es_writen (stream, buffer, size, &nwritten))
1666 stream->intern->print_err = 1;
1667 stream->intern->print_errno = errno;
1669 else
1670 stream->intern->print_ntotal += nwritten;
1672 return 0;
1674 #endif /* HAVE_FOPENCOOKIE || HAVE_FUNOPEN */
1677 /* The core of our printf function. This is called in locked state. */
1678 static int
1679 es_print (estream_t ES__RESTRICT stream,
1680 const char *ES__RESTRICT format, va_list ap)
1682 #if defined(HAVE_FOPENCOOKIE) || defined(HAVE_FUNOPEN)
1684 if (!stream->intern->print_fp)
1686 #ifdef HAVE_FOPENCOOKIE
1688 cookie_io_functions_t io = { NULL };
1689 io.write = print_fun_writer;
1691 stream->intern->print_fp = fopencookie (stream, "w", io);
1693 #else /*!HAVE_FOPENCOOKIE*/
1694 stream->intern->print_fp = funopen (stream, NULL,
1695 print_fun_writer, NULL, NULL);
1696 #endif /*!HAVE_FOPENCOOKIE*/
1697 if (!stream->intern->print_fp)
1698 return -1;
1701 stream->intern->print_err = 0;
1702 stream->intern->print_errno = 0;
1703 stream->intern->print_ntotal = 0;
1705 if ( vfprintf (stream->intern->print_fp, format, ap) < 0
1706 || fflush (stream->intern->print_fp) )
1708 stream->intern->print_errno = errno;
1709 stream->intern->print_err = 1;
1710 fclose (stream->intern->print_fp);
1711 stream->intern->print_fp = NULL;
1713 if (stream->intern->print_err)
1715 errno = stream->intern->print_errno;
1716 return -1;
1719 return (int)stream->intern->print_ntotal;
1721 #else /* No funopen or fopencookie. */
1723 char data[BUFFER_BLOCK_SIZE];
1724 size_t bytes_read;
1725 size_t bytes_written;
1726 FILE *tmp_stream;
1727 int err;
1729 bytes_written = 0;
1730 tmp_stream = NULL;
1731 err = 0;
1733 tmp_stream = tmpfile ();
1734 if (! tmp_stream)
1736 err = errno;
1737 goto out;
1740 err = vfprintf (tmp_stream, format, ap);
1741 if (err < 0)
1742 goto out;
1744 err = fseek (tmp_stream, 0, SEEK_SET);
1745 if (err)
1746 goto out;
1748 while (1)
1750 bytes_read = fread (data, 1, sizeof (data), tmp_stream);
1751 if (ferror (tmp_stream))
1753 err = -1;
1754 break;
1757 err = es_writen (stream, data, bytes_read, NULL);
1758 if (err)
1759 break;
1760 else
1761 bytes_written += bytes_read;
1762 if (feof (tmp_stream))
1763 break;
1765 if (err)
1766 goto out;
1768 out:
1769 if (tmp_stream)
1770 fclose (tmp_stream);
1772 return err ? -1 : bytes_written;
1773 #endif /* no funopen or fopencookie */
1777 static void
1778 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1780 if (ind_err != -1)
1781 stream->intern->indicators.err = ind_err ? 1 : 0;
1782 if (ind_eof != -1)
1783 stream->intern->indicators.eof = ind_eof ? 1 : 0;
1787 static int
1788 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1790 int ret = 0;
1792 if (ind_err)
1793 ret = stream->intern->indicators.err;
1794 else if (ind_eof)
1795 ret = stream->intern->indicators.eof;
1797 return ret;
1801 static int
1802 es_set_buffering (estream_t ES__RESTRICT stream,
1803 char *ES__RESTRICT buffer, int mode, size_t size)
1805 int err;
1807 /* Flush or empty buffer depending on mode. */
1808 if (stream->flags & ES_FLAG_WRITING)
1810 err = es_flush (stream);
1811 if (err)
1812 goto out;
1814 else
1815 es_empty (stream);
1817 es_set_indicators (stream, -1, 0);
1819 /* Free old buffer in case that was allocated by this function. */
1820 if (stream->intern->deallocate_buffer)
1822 stream->intern->deallocate_buffer = 0;
1823 MEM_FREE (stream->buffer);
1824 stream->buffer = NULL;
1827 if (mode == _IONBF)
1828 stream->buffer_size = 0;
1829 else
1831 void *buffer_new;
1833 if (buffer)
1834 buffer_new = buffer;
1835 else
1837 buffer_new = MEM_ALLOC (size);
1838 if (! buffer_new)
1840 err = -1;
1841 goto out;
1845 stream->buffer = buffer_new;
1846 stream->buffer_size = size;
1847 if (! buffer)
1848 stream->intern->deallocate_buffer = 1;
1850 stream->intern->strategy = mode;
1851 err = 0;
1853 out:
1855 return err;
1859 static off_t
1860 es_offset_calculate (estream_t stream)
1862 off_t offset;
1864 offset = stream->intern->offset + stream->data_offset;
1865 if (offset < stream->unread_data_len)
1866 /* Offset undefined. */
1867 offset = 0;
1868 else
1869 offset -= stream->unread_data_len;
1871 return offset;
1875 static void
1876 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1877 void **ES__RESTRICT opaque_old)
1879 if (opaque_old)
1880 *opaque_old = stream->intern->opaque;
1881 if (opaque_new)
1882 stream->intern->opaque = opaque_new;
1886 static int
1887 es_get_fd (estream_t stream)
1889 return stream->intern->fd;
1894 /* API. */
1897 es_init (void)
1899 int err;
1901 err = es_init_do ();
1903 return err;
1906 estream_t
1907 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
1909 unsigned int flags;
1910 int create_called;
1911 estream_t stream;
1912 void *cookie;
1913 int err;
1914 int fd;
1916 stream = NULL;
1917 cookie = NULL;
1918 create_called = 0;
1920 err = es_convert_mode (mode, &flags);
1921 if (err)
1922 goto out;
1924 err = es_func_file_create (&cookie, &fd, path, flags);
1925 if (err)
1926 goto out;
1928 create_called = 1;
1929 err = es_create (&stream, cookie, fd, estream_functions_file);
1930 if (err)
1931 goto out;
1933 out:
1935 if (err && create_called)
1936 (*estream_functions_file.func_close) (cookie);
1938 return stream;
1942 estream_t
1943 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
1944 unsigned int grow,
1945 func_realloc_t func_realloc, func_free_t func_free,
1946 const char *ES__RESTRICT mode)
1948 unsigned int flags;
1949 int create_called;
1950 estream_t stream;
1951 void *cookie;
1952 int err;
1954 cookie = 0;
1955 stream = NULL;
1956 create_called = 0;
1958 err = es_convert_mode (mode, &flags);
1959 if (err)
1960 goto out;
1962 err = es_func_mem_create (&cookie, data, data_n, data_len,
1963 BUFFER_BLOCK_SIZE, grow, 0, 0,
1964 NULL, 0, func_realloc, func_free, flags);
1965 if (err)
1966 goto out;
1968 create_called = 1;
1969 err = es_create (&stream, cookie, -1, estream_functions_mem);
1971 out:
1973 if (err && create_called)
1974 (*estream_functions_mem.func_close) (cookie);
1976 return stream;
1980 estream_t
1981 es_open_memstream (char **ptr, size_t *size)
1983 unsigned int flags;
1984 int create_called;
1985 estream_t stream;
1986 void *cookie;
1987 int err;
1989 flags = O_RDWR;
1990 create_called = 0;
1991 stream = NULL;
1992 cookie = 0;
1994 err = es_func_mem_create (&cookie, NULL, 0, 0,
1995 BUFFER_BLOCK_SIZE, 1, 1, 1,
1996 ptr, size, MEM_REALLOC, MEM_FREE, flags);
1997 if (err)
1998 goto out;
2000 create_called = 1;
2001 err = es_create (&stream, cookie, -1, estream_functions_mem);
2003 out:
2005 if (err && create_called)
2006 (*estream_functions_mem.func_close) (cookie);
2008 return stream;
2012 estream_t
2013 es_fopencookie (void *ES__RESTRICT cookie,
2014 const char *ES__RESTRICT mode,
2015 es_cookie_io_functions_t functions)
2017 unsigned int flags;
2018 estream_t stream;
2019 int err;
2021 stream = NULL;
2022 flags = 0;
2024 err = es_convert_mode (mode, &flags);
2025 if (err)
2026 goto out;
2028 err = es_create (&stream, cookie, -1, functions);
2029 if (err)
2030 goto out;
2032 out:
2034 return stream;
2038 estream_t
2039 es_fdopen (int filedes, const char *mode)
2041 unsigned int flags;
2042 int create_called;
2043 estream_t stream;
2044 void *cookie;
2045 int err;
2047 stream = NULL;
2048 cookie = NULL;
2049 create_called = 0;
2051 err = es_convert_mode (mode, &flags);
2052 if (err)
2053 goto out;
2055 err = es_func_fd_create (&cookie, filedes, flags);
2056 if (err)
2057 goto out;
2059 create_called = 1;
2060 err = es_create (&stream, cookie, filedes, estream_functions_fd);
2062 out:
2064 if (err && create_called)
2065 (*estream_functions_fd.func_close) (cookie);
2067 return stream;
2071 estream_t
2072 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
2073 estream_t ES__RESTRICT stream)
2075 int err;
2077 if (path)
2079 unsigned int flags;
2080 int create_called;
2081 void *cookie;
2082 int fd;
2084 cookie = NULL;
2085 create_called = 0;
2087 ESTREAM_LOCK (stream);
2089 es_deinitialize (stream);
2091 err = es_convert_mode (mode, &flags);
2092 if (err)
2093 goto leave;
2095 err = es_func_file_create (&cookie, &fd, path, flags);
2096 if (err)
2097 goto leave;
2099 create_called = 1;
2100 es_initialize (stream, cookie, fd, estream_functions_file);
2102 leave:
2104 if (err)
2106 if (create_called)
2107 es_func_fd_destroy (cookie);
2109 es_destroy (stream);
2110 stream = NULL;
2112 else
2113 ESTREAM_UNLOCK (stream);
2115 else
2117 /* FIXME? We don't support re-opening at the moment. */
2118 errno = EINVAL;
2119 es_deinitialize (stream);
2120 es_destroy (stream);
2121 stream = NULL;
2124 return stream;
2129 es_fclose (estream_t stream)
2131 int err;
2133 err = es_destroy (stream);
2135 return err;
2139 es_fileno_unlocked (estream_t stream)
2141 return es_get_fd (stream);
2145 void
2146 es_flockfile (estream_t stream)
2148 ESTREAM_LOCK (stream);
2153 es_ftrylockfile (estream_t stream)
2155 return ESTREAM_TRYLOCK (stream);
2159 void
2160 es_funlockfile (estream_t stream)
2162 ESTREAM_UNLOCK (stream);
2167 es_fileno (estream_t stream)
2169 int ret;
2171 ESTREAM_LOCK (stream);
2172 ret = es_fileno_unlocked (stream);
2173 ESTREAM_UNLOCK (stream);
2175 return ret;
2180 es_feof_unlocked (estream_t stream)
2182 return es_get_indicator (stream, 0, 1);
2187 es_feof (estream_t stream)
2189 int ret;
2191 ESTREAM_LOCK (stream);
2192 ret = es_feof_unlocked (stream);
2193 ESTREAM_UNLOCK (stream);
2195 return ret;
2200 es_ferror_unlocked (estream_t stream)
2202 return es_get_indicator (stream, 1, 0);
2207 es_ferror (estream_t stream)
2209 int ret;
2211 ESTREAM_LOCK (stream);
2212 ret = es_ferror_unlocked (stream);
2213 ESTREAM_UNLOCK (stream);
2215 return ret;
2219 void
2220 es_clearerr_unlocked (estream_t stream)
2222 es_set_indicators (stream, 0, 0);
2226 void
2227 es_clearerr (estream_t stream)
2229 ESTREAM_LOCK (stream);
2230 es_clearerr_unlocked (stream);
2231 ESTREAM_UNLOCK (stream);
2236 es_fflush (estream_t stream)
2238 int err;
2240 if (stream)
2242 ESTREAM_LOCK (stream);
2243 if (stream->flags & ES_FLAG_WRITING)
2244 err = es_flush (stream);
2245 else
2247 es_empty (stream);
2248 err = 0;
2250 ESTREAM_UNLOCK (stream);
2252 else
2253 err = es_list_iterate (es_fflush);
2255 return err ? EOF : 0;
2260 es_fseek (estream_t stream, long int offset, int whence)
2262 int err;
2264 ESTREAM_LOCK (stream);
2265 err = es_seek (stream, offset, whence, NULL);
2266 ESTREAM_UNLOCK (stream);
2268 return err;
2273 es_fseeko (estream_t stream, off_t offset, int whence)
2275 int err;
2277 ESTREAM_LOCK (stream);
2278 err = es_seek (stream, offset, whence, NULL);
2279 ESTREAM_UNLOCK (stream);
2281 return err;
2285 long int
2286 es_ftell (estream_t stream)
2288 long int ret;
2290 ESTREAM_LOCK (stream);
2291 ret = es_offset_calculate (stream);
2292 ESTREAM_UNLOCK (stream);
2294 return ret;
2298 off_t
2299 es_ftello (estream_t stream)
2301 off_t ret = -1;
2303 ESTREAM_LOCK (stream);
2304 ret = es_offset_calculate (stream);
2305 ESTREAM_UNLOCK (stream);
2307 return ret;
2311 void
2312 es_rewind (estream_t stream)
2314 ESTREAM_LOCK (stream);
2315 es_seek (stream, 0L, SEEK_SET, NULL);
2316 es_set_indicators (stream, 0, -1);
2317 ESTREAM_UNLOCK (stream);
2322 _es_getc_underflow (estream_t stream)
2324 int err;
2325 unsigned char c;
2326 size_t bytes_read;
2328 err = es_readn (stream, &c, 1, &bytes_read);
2330 return (err || (! bytes_read)) ? EOF : c;
2335 _es_putc_overflow (int c, estream_t stream)
2337 unsigned char d = c;
2338 int err;
2340 err = es_writen (stream, &d, 1, NULL);
2342 return err ? EOF : c;
2347 es_fgetc (estream_t stream)
2349 int ret;
2351 ESTREAM_LOCK (stream);
2352 ret = es_getc_unlocked (stream);
2353 ESTREAM_UNLOCK (stream);
2355 return ret;
2360 es_fputc (int c, estream_t stream)
2362 int ret;
2364 ESTREAM_LOCK (stream);
2365 ret = es_putc_unlocked (c, stream);
2366 ESTREAM_UNLOCK (stream);
2368 return ret;
2373 es_ungetc (int c, estream_t stream)
2375 unsigned char data = (unsigned char) c;
2376 size_t data_unread;
2378 ESTREAM_LOCK (stream);
2379 es_unreadn (stream, &data, 1, &data_unread);
2380 ESTREAM_UNLOCK (stream);
2382 return data_unread ? c : EOF;
2387 es_read (estream_t ES__RESTRICT stream,
2388 void *ES__RESTRICT buffer, size_t bytes_to_read,
2389 size_t *ES__RESTRICT bytes_read)
2391 int err;
2393 if (bytes_to_read)
2395 ESTREAM_LOCK (stream);
2396 err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2397 ESTREAM_UNLOCK (stream);
2399 else
2400 err = 0;
2402 return err;
2407 es_write (estream_t ES__RESTRICT stream,
2408 const void *ES__RESTRICT buffer, size_t bytes_to_write,
2409 size_t *ES__RESTRICT bytes_written)
2411 int err;
2413 if (bytes_to_write)
2415 ESTREAM_LOCK (stream);
2416 err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2417 ESTREAM_UNLOCK (stream);
2419 else
2420 err = 0;
2422 return err;
2426 size_t
2427 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2428 estream_t ES__RESTRICT stream)
2430 size_t ret, bytes;
2431 int err;
2433 if (size * nitems)
2435 ESTREAM_LOCK (stream);
2436 err = es_readn (stream, ptr, size * nitems, &bytes);
2437 ESTREAM_UNLOCK (stream);
2439 ret = bytes / size;
2441 else
2442 ret = 0;
2444 return ret;
2448 size_t
2449 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2450 estream_t ES__RESTRICT stream)
2452 size_t ret, bytes;
2453 int err;
2455 if (size * nitems)
2457 ESTREAM_LOCK (stream);
2458 err = es_writen (stream, ptr, size * nitems, &bytes);
2459 ESTREAM_UNLOCK (stream);
2461 ret = bytes / size;
2463 else
2464 ret = 0;
2466 return ret;
2470 char *
2471 es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream)
2473 char *ret = NULL;
2475 if (n)
2477 int err;
2479 ESTREAM_LOCK (stream);
2480 err = doreadline (stream, n, &s, NULL);
2481 ESTREAM_UNLOCK (stream);
2482 if (! err)
2483 ret = s;
2486 return ret;
2491 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2493 size_t length;
2494 int err;
2496 length = strlen (s);
2497 ESTREAM_LOCK (stream);
2498 err = es_writen (stream, s, length, NULL);
2499 ESTREAM_UNLOCK (stream);
2501 return err ? EOF : 0;
2505 ssize_t
2506 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2507 estream_t ES__RESTRICT stream)
2509 char *line = NULL;
2510 size_t line_n = 0;
2511 int err;
2513 ESTREAM_LOCK (stream);
2514 err = doreadline (stream, 0, &line, &line_n);
2515 ESTREAM_UNLOCK (stream);
2516 if (err)
2517 goto out;
2519 if (*n)
2521 /* Caller wants us to use his buffer. */
2523 if (*n < (line_n + 1))
2525 /* Provided buffer is too small -> resize. */
2527 void *p;
2529 p = MEM_REALLOC (*lineptr, line_n + 1);
2530 if (! p)
2531 err = -1;
2532 else
2534 if (*lineptr != p)
2535 *lineptr = p;
2539 if (! err)
2541 memcpy (*lineptr, line, line_n + 1);
2542 if (*n != line_n)
2543 *n = line_n;
2545 MEM_FREE (line);
2547 else
2549 /* Caller wants new buffers. */
2550 *lineptr = line;
2551 *n = line_n;
2554 out:
2556 return err ? err : line_n;
2561 /* Same as fgets() but if the provided buffer is too short a larger
2562 one will be allocated. This is similar to getline. A line is
2563 considered a byte stream ending in a LF.
2565 If MAX_LENGTH is not NULL, it shall point to a value with the
2566 maximum allowed allocation.
2568 Returns the length of the line. EOF is indicated by a line of
2569 length zero. A truncated line is indicated my setting the value at
2570 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2571 memory was enable or another error occurred; ERRNO is then set
2572 accordingly.
2574 If a line has been truncated, the file pointer is moved forward to
2575 the end of the line so that the next read starts with the next
2576 line. Note that MAX_LENGTH must be re-initialzied in this case.
2578 The caller initially needs to provide the address of a variable,
2579 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2580 anymore with the following invocations. LENGTH_OF_BUFFER should be
2581 the address of a variable, initialized to 0, which is also
2582 maintained by this function. Thus, both paramaters should be
2583 considered the state of this function.
2585 Note: The returned buffer is allocated with enough extra space to
2586 allow the caller to append a CR,LF,Nul. The buffer should be
2587 released using es_free.
2589 ssize_t
2590 es_read_line (estream_t stream,
2591 char **addr_of_buffer, size_t *length_of_buffer,
2592 size_t *max_length)
2594 int c;
2595 char *buffer = *addr_of_buffer;
2596 size_t length = *length_of_buffer;
2597 size_t nbytes = 0;
2598 size_t maxlen = max_length? *max_length : 0;
2599 char *p;
2601 if (!buffer)
2603 /* No buffer given - allocate a new one. */
2604 length = 256;
2605 buffer = MEM_ALLOC (length);
2606 *addr_of_buffer = buffer;
2607 if (!buffer)
2609 *length_of_buffer = 0;
2610 if (max_length)
2611 *max_length = 0;
2612 return -1;
2614 *length_of_buffer = length;
2617 if (length < 4)
2619 /* This should never happen. If it does, the fucntion has been
2620 called with wrong arguments. */
2621 errno = EINVAL;
2622 return -1;
2624 length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2626 ESTREAM_LOCK (stream);
2627 p = buffer;
2628 while ((c = es_getc_unlocked (stream)) != EOF)
2630 if (nbytes == length)
2632 /* Enlarge the buffer. */
2633 if (maxlen && length > maxlen)
2635 /* We are beyond our limit: Skip the rest of the line. */
2636 while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
2638 *p++ = '\n'; /* Always append a LF (we reserved some space). */
2639 nbytes++;
2640 if (max_length)
2641 *max_length = 0; /* Indicate truncation. */
2642 break; /* the while loop. */
2644 length += 3; /* Adjust for the reserved bytes. */
2645 length += length < 1024? 256 : 1024;
2646 *addr_of_buffer = MEM_REALLOC (buffer, length);
2647 if (!*addr_of_buffer)
2649 int save_errno = errno;
2650 MEM_FREE (buffer);
2651 *length_of_buffer = *max_length = 0;
2652 ESTREAM_UNLOCK (stream);
2653 errno = save_errno;
2654 return -1;
2656 buffer = *addr_of_buffer;
2657 *length_of_buffer = length;
2658 length -= 3;
2659 p = buffer + nbytes;
2661 *p++ = c;
2662 nbytes++;
2663 if (c == '\n')
2664 break;
2666 *p = 0; /* Make sure the line is a string. */
2667 ESTREAM_UNLOCK (stream);
2669 return nbytes;
2672 /* Wrapper around free() to match the memory allocation system used
2673 by estream. Should be used for all buffers returned to the caller
2674 by libestream. */
2675 void
2676 es_free (void *a)
2678 if (a)
2679 MEM_FREE (a);
2684 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2685 va_list ap)
2687 int ret;
2689 ESTREAM_LOCK (stream);
2690 ret = es_print (stream, format, ap);
2691 ESTREAM_UNLOCK (stream);
2693 return ret;
2698 es_fprintf (estream_t ES__RESTRICT stream,
2699 const char *ES__RESTRICT format, ...)
2701 int ret;
2703 va_list ap;
2704 va_start (ap, format);
2705 ESTREAM_LOCK (stream);
2706 ret = es_print (stream, format, ap);
2707 ESTREAM_UNLOCK (stream);
2708 va_end (ap);
2710 return ret;
2713 static int
2714 tmpfd (void)
2716 FILE *fp;
2717 int fp_fd;
2718 int fd;
2720 fp = NULL;
2721 fd = -1;
2723 fp = tmpfile ();
2724 if (! fp)
2725 goto out;
2727 fp_fd = fileno (fp);
2728 fd = dup (fp_fd);
2730 out:
2732 if (fp)
2733 fclose (fp);
2735 return fd;
2738 estream_t
2739 es_tmpfile (void)
2741 unsigned int flags;
2742 int create_called;
2743 estream_t stream;
2744 void *cookie;
2745 int err;
2746 int fd;
2748 create_called = 0;
2749 stream = NULL;
2750 flags = O_RDWR | O_TRUNC | O_CREAT;
2751 cookie = NULL;
2753 fd = tmpfd ();
2754 if (fd == -1)
2756 err = -1;
2757 goto out;
2760 err = es_func_fd_create (&cookie, fd, flags);
2761 if (err)
2762 goto out;
2764 create_called = 1;
2765 err = es_create (&stream, cookie, fd, estream_functions_fd);
2767 out:
2769 if (err)
2771 if (create_called)
2772 es_func_fd_destroy (cookie);
2773 else if (fd != -1)
2774 close (fd);
2775 stream = NULL;
2778 return stream;
2783 es_setvbuf (estream_t ES__RESTRICT stream,
2784 char *ES__RESTRICT buf, int type, size_t size)
2786 int err;
2788 if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
2789 && (! ((! size) && (type != _IONBF))))
2791 ESTREAM_LOCK (stream);
2792 err = es_set_buffering (stream, buf, type, size);
2793 ESTREAM_UNLOCK (stream);
2795 else
2797 errno = EINVAL;
2798 err = -1;
2801 return err;
2805 void
2806 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
2808 ESTREAM_LOCK (stream);
2809 es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
2810 ESTREAM_UNLOCK (stream);
2813 void
2814 es_opaque_set (estream_t stream, void *opaque)
2816 ESTREAM_LOCK (stream);
2817 es_opaque_ctrl (stream, opaque, NULL);
2818 ESTREAM_UNLOCK (stream);
2822 void *
2823 es_opaque_get (estream_t stream)
2825 void *opaque;
2827 ESTREAM_LOCK (stream);
2828 es_opaque_ctrl (stream, NULL, &opaque);
2829 ESTREAM_UNLOCK (stream);
2831 return opaque;