Fixed an fopen problem on Windows Vista.
[gnupg.git] / common / estream.c
blob214c2ff7d15320e32799a17fdf4e2fe3c03afa0d
1 /* estream.c - Extended Stream I/O Library
2 * Copyright (C) 2004, 2005, 2006, 2007 g10 Code GmbH
4 * This file is part of Libestream.
6 * Libestream is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License,
9 * or (at your option) any later version.
11 * Libestream is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Libestream; if not, see <http://www.gnu.org/licenses/>.
20 #ifdef USE_ESTREAM_SUPPORT_H
21 # include <estream-support.h>
22 #endif
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
28 #if defined(_WIN32) && !defined(HAVE_W32_SYSTEM)
29 # define HAVE_W32_SYSTEM 1
30 #endif
32 #include <sys/types.h>
33 #include <sys/file.h>
34 #include <sys/stat.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <stdarg.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <stddef.h>
43 #include <assert.h>
44 #ifdef HAVE_W32_SYSTEM
45 # include <windows.h>
46 #endif
48 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */
49 # undef HAVE_PTH
50 # undef USE_GNU_PTH
51 #endif
53 #ifdef HAVE_PTH
54 # include <pth.h>
55 #endif
57 /* This is for the special hack to use estream.c in GnuPG. */
58 #ifdef GNUPG_MAJOR_VERSION
59 # include "../common/util.h"
60 #endif
62 #ifndef HAVE_MKSTEMP
63 int mkstemp (char *template);
64 #endif
66 #ifndef HAVE_MEMRCHR
67 void *memrchr (const void *block, int c, size_t size);
68 #endif
70 #include <estream.h>
71 #include <estream-printf.h>
75 #ifndef O_BINARY
76 #define O_BINARY 0
77 #endif
79 /* Generally used types. */
81 typedef void *(*func_realloc_t) (void *mem, size_t size);
82 typedef void (*func_free_t) (void *mem);
87 /* Buffer management layer. */
89 #define BUFFER_BLOCK_SIZE BUFSIZ
90 #define BUFFER_UNREAD_SIZE 16
94 /* Macros. */
96 #define BUFFER_ROUND_TO_BLOCK(size, block_size) \
100 /* Locking. */
102 #ifdef HAVE_PTH
104 typedef pth_mutex_t estream_mutex_t;
105 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
106 # define ESTREAM_MUTEX_LOCK(mutex) \
107 pth_mutex_acquire (&(mutex), 0, NULL)
108 # define ESTREAM_MUTEX_UNLOCK(mutex) \
109 pth_mutex_release (&(mutex))
110 # define ESTREAM_MUTEX_TRYLOCK(mutex) \
111 ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
112 # define ESTREAM_MUTEX_INITIALIZE(mutex) \
113 pth_mutex_init (&(mutex))
114 #else
116 typedef void *estream_mutex_t;
118 static inline void
119 dummy_mutex_call_void (estream_mutex_t mutex)
121 (void)mutex;
124 static inline int
125 dummy_mutex_call_int (estream_mutex_t mutex)
127 (void)mutex;
128 return 0;
131 # define ESTREAM_MUTEX_INITIALIZER NULL
132 # define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex))
133 # define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex))
134 # define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex))
135 # define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex))
136 #endif
138 /* Primitive system I/O. */
140 #ifdef HAVE_PTH
141 # define ESTREAM_SYS_READ pth_read
142 # define ESTREAM_SYS_WRITE pth_write
143 #else
144 # define ESTREAM_SYS_READ read
145 # define ESTREAM_SYS_WRITE write
146 #endif
148 /* Misc definitions. */
150 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
152 /* An internal stream object. */
154 struct estream_internal
156 unsigned char buffer[BUFFER_BLOCK_SIZE];
157 unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
158 estream_mutex_t lock; /* Lock. */
159 void *cookie; /* Cookie. */
160 void *opaque; /* Opaque data. */
161 unsigned int modeflags; /* Flags for the backend. */
162 off_t offset;
163 es_cookie_read_function_t func_read;
164 es_cookie_write_function_t func_write;
165 es_cookie_seek_function_t func_seek;
166 es_cookie_close_function_t func_close;
167 int strategy;
168 int fd;
169 struct
171 unsigned int err: 1;
172 unsigned int eof: 1;
173 } indicators;
174 unsigned int deallocate_buffer: 1;
175 unsigned int print_err: 1; /* Error in print_fun_writer. */
176 int print_errno; /* Errno from print_fun_writer. */
177 size_t print_ntotal; /* Bytes written from in print_fun_writer. */
178 FILE *print_fp; /* Stdio stream used by print_fun_writer. */
182 typedef struct estream_internal *estream_internal_t;
184 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
185 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
186 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
188 /* Stream list. */
190 typedef struct estream_list *estream_list_t;
192 struct estream_list
194 estream_t car;
195 estream_list_t cdr;
196 estream_list_t *prev_cdr;
199 static estream_list_t estream_list;
200 static estream_mutex_t estream_list_lock;
202 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
203 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
205 #ifndef EOPNOTSUPP
206 # define EOPNOTSUPP ENOSYS
207 #endif
212 /* Macros. */
214 /* Calculate array dimension. */
215 #ifndef DIM
216 #define DIM(array) (sizeof (array) / sizeof (*array))
217 #endif
219 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
222 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
223 VARIABLE is zero. */
224 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
225 do \
227 tmp_variable = expression; \
228 if ((! variable) && tmp_variable) \
229 variable = tmp_variable; \
231 while (0)
234 /* Malloc wrappers to overcvome problems on some older OSes. */
235 static void *
236 mem_alloc (size_t n)
238 if (!n)
239 n++;
240 return malloc (n);
243 static void *
244 mem_realloc (void *p, size_t n)
246 if (!p)
247 return mem_alloc (n);
248 return realloc (p, n);
251 static void
252 mem_free (void *p)
254 if (p)
255 free (p);
261 * List manipulation.
264 /* Add STREAM to the list of registered stream objects. */
265 static int
266 es_list_add (estream_t stream)
268 estream_list_t list_obj;
269 int ret;
271 list_obj = mem_alloc (sizeof (*list_obj));
272 if (! list_obj)
273 ret = -1;
274 else
276 ESTREAM_LIST_LOCK;
277 list_obj->car = stream;
278 list_obj->cdr = estream_list;
279 list_obj->prev_cdr = &estream_list;
280 if (estream_list)
281 estream_list->prev_cdr = &list_obj->cdr;
282 estream_list = list_obj;
283 ESTREAM_LIST_UNLOCK;
284 ret = 0;
287 return ret;
290 /* Remove STREAM from the list of registered stream objects. */
291 static void
292 es_list_remove (estream_t stream)
294 estream_list_t list_obj;
296 ESTREAM_LIST_LOCK;
297 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
298 if (list_obj->car == stream)
300 *list_obj->prev_cdr = list_obj->cdr;
301 if (list_obj->cdr)
302 list_obj->cdr->prev_cdr = list_obj->prev_cdr;
303 mem_free (list_obj);
304 break;
306 ESTREAM_LIST_UNLOCK;
309 /* Type of an stream-iterator-function. */
310 typedef int (*estream_iterator_t) (estream_t stream);
312 /* Iterate over list of registered streams, calling ITERATOR for each
313 of them. */
314 static int
315 es_list_iterate (estream_iterator_t iterator)
317 estream_list_t list_obj;
318 int ret = 0;
320 ESTREAM_LIST_LOCK;
321 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
322 ret |= (*iterator) (list_obj->car);
323 ESTREAM_LIST_UNLOCK;
325 return ret;
331 * Initialization.
334 static int
335 es_init_do (void)
337 #ifdef HAVE_PTH
338 static int initialized;
340 if (!initialized)
342 if (!pth_init () && errno != EPERM )
343 return -1;
344 if (pth_mutex_init (&estream_list_lock))
345 initialized = 1;
347 #endif
348 return 0;
354 * I/O methods.
357 /* Implementation of Memory I/O. */
359 /* Cookie for memory objects. */
360 typedef struct estream_cookie_mem
362 unsigned int modeflags; /* Open flags. */
363 unsigned char *memory; /* Allocated data buffer. */
364 size_t memory_size; /* Allocated size of memory. */
365 size_t memory_limit; /* Maximum allowed allocation size or
366 0 for no limit. */
367 size_t offset; /* Current offset in MEMORY. */
368 size_t data_len; /* Length of data in MEMORY. */
369 size_t block_size; /* Block size. */
370 struct {
371 unsigned int grow: 1; /* MEMORY is allowed to grow. */
372 } flags;
373 func_realloc_t func_realloc;
374 func_free_t func_free;
375 } *estream_cookie_mem_t;
378 /* Create function for memory objects. */
379 static int
380 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
381 unsigned char *ES__RESTRICT data, size_t data_n,
382 size_t data_len,
383 size_t block_size, unsigned int grow,
384 func_realloc_t func_realloc, func_free_t func_free,
385 unsigned int modeflags,
386 size_t memory_limit)
388 estream_cookie_mem_t mem_cookie;
389 int err;
391 mem_cookie = mem_alloc (sizeof (*mem_cookie));
392 if (!mem_cookie)
393 err = -1;
394 else
396 mem_cookie->modeflags = modeflags;
397 mem_cookie->memory = data;
398 mem_cookie->memory_size = data_n;
399 mem_cookie->memory_limit = memory_limit;
400 mem_cookie->offset = 0;
401 mem_cookie->data_len = data_len;
402 mem_cookie->block_size = block_size;
403 mem_cookie->flags.grow = !!grow;
404 mem_cookie->func_realloc = func_realloc ? func_realloc : mem_realloc;
405 mem_cookie->func_free = func_free ? func_free : mem_free;
406 *cookie = mem_cookie;
407 err = 0;
410 return err;
414 /* Read function for memory objects. */
415 static ssize_t
416 es_func_mem_read (void *cookie, void *buffer, size_t size)
418 estream_cookie_mem_t mem_cookie = cookie;
419 ssize_t ret;
421 if (size > mem_cookie->data_len - mem_cookie->offset)
422 size = mem_cookie->data_len - mem_cookie->offset;
424 if (size)
426 memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
427 mem_cookie->offset += size;
430 ret = size;
431 return ret;
435 /* Write function for memory objects. */
436 static ssize_t
437 es_func_mem_write (void *cookie, const void *buffer, size_t size)
439 estream_cookie_mem_t mem_cookie = cookie;
440 ssize_t ret;
442 if (!size)
443 return 0; /* A flush is a NOP for memory objects. */
445 if (mem_cookie->modeflags & O_APPEND)
447 /* Append to data. */
448 mem_cookie->offset = mem_cookie->data_len;
451 if (!mem_cookie->flags.grow)
453 /* We are not alloew to grow, thus limit the size to the left
454 space. FIXME: Does the grow flag an its semtics make sense
455 at all? */
456 if (size > mem_cookie->memory_size - mem_cookie->offset)
457 size = mem_cookie->memory_size - mem_cookie->offset;
460 if (size > (mem_cookie->memory_size - mem_cookie->offset))
462 unsigned char *newbuf;
463 size_t newsize;
465 newsize = mem_cookie->memory_size + mem_cookie->block_size;
467 newsize = mem_cookie->offset + size;
468 if (newsize < mem_cookie->offset)
470 errno = EINVAL;
471 return -1;
473 newsize += mem_cookie->block_size - 1;
474 if (newsize < mem_cookie->offset)
476 errno = EINVAL;
477 return -1;
479 newsize /= mem_cookie->block_size;
480 newsize *= mem_cookie->block_size;
482 if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
484 errno = ENOSPC;
485 return -1;
488 newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
489 if (!newbuf)
490 return -1;
492 mem_cookie->memory = newbuf;
493 mem_cookie->memory_size = newsize;
495 assert (!(size > (mem_cookie->memory_size - mem_cookie->offset)));
498 memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
499 if (mem_cookie->offset + size > mem_cookie->data_len)
500 mem_cookie->data_len = mem_cookie->offset + size;
501 mem_cookie->offset += size;
503 ret = size;
504 return ret;
508 /* Seek function for memory objects. */
509 static int
510 es_func_mem_seek (void *cookie, off_t *offset, int whence)
512 estream_cookie_mem_t mem_cookie = cookie;
513 off_t pos_new;
515 switch (whence)
517 case SEEK_SET:
518 pos_new = *offset;
519 break;
521 case SEEK_CUR:
522 pos_new = mem_cookie->offset += *offset;
523 break;
525 case SEEK_END:
526 pos_new = mem_cookie->data_len += *offset;
527 break;
529 default:
530 errno = EINVAL;
531 return -1;
534 if (pos_new > mem_cookie->memory_size)
536 size_t newsize;
537 void *newbuf;
539 if (!mem_cookie->flags.grow)
541 errno = ENOSPC;
542 return -1;
546 newsize = pos_new + mem_cookie->block_size - 1;
547 if (newsize < pos_new)
549 errno = EINVAL;
550 return -1;
552 newsize /= mem_cookie->block_size;
553 newsize *= mem_cookie->block_size;
554 if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
556 errno = ENOSPC;
557 return -1;
560 newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
561 if (!newbuf)
562 return -1;
564 mem_cookie->memory = newbuf;
565 mem_cookie->memory_size = newsize;
568 if (pos_new > mem_cookie->data_len)
570 /* Fill spare space with zeroes. */
571 memset (mem_cookie->memory + mem_cookie->data_len,
572 0, pos_new - mem_cookie->data_len);
573 mem_cookie->data_len = pos_new;
576 mem_cookie->offset = pos_new;
577 *offset = pos_new;
579 return 0;
583 /* Destroy function for memory objects. */
584 static int
585 es_func_mem_destroy (void *cookie)
587 estream_cookie_mem_t mem_cookie = cookie;
589 if (cookie)
591 mem_cookie->func_free (mem_cookie->memory);
592 mem_free (mem_cookie);
594 return 0;
598 static es_cookie_io_functions_t estream_functions_mem =
600 es_func_mem_read,
601 es_func_mem_write,
602 es_func_mem_seek,
603 es_func_mem_destroy
608 /* Implementation of fd I/O. */
610 /* Cookie for fd objects. */
611 typedef struct estream_cookie_fd
613 int fd; /* The file descriptor we are using for actual output. */
614 int no_close; /* If set we won't close the file descriptor. */
615 } *estream_cookie_fd_t;
617 /* Create function for fd objects. */
618 static int
619 es_func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
621 estream_cookie_fd_t fd_cookie;
622 int err;
624 fd_cookie = mem_alloc (sizeof (*fd_cookie));
625 if (! fd_cookie)
626 err = -1;
627 else
629 #ifdef HAVE_DOSISH_SYSTEM
630 /* Make sure it is in binary mode if requested. */
631 if ( (modeflags & O_BINARY) )
632 setmode (fd, O_BINARY);
633 #else
634 (void)modeflags;
635 #endif
636 fd_cookie->fd = fd;
637 fd_cookie->no_close = no_close;
638 *cookie = fd_cookie;
639 err = 0;
642 return err;
645 /* Read function for fd objects. */
646 static ssize_t
647 es_func_fd_read (void *cookie, void *buffer, size_t size)
650 estream_cookie_fd_t file_cookie = cookie;
651 ssize_t bytes_read;
654 bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
655 while (bytes_read == -1 && errno == EINTR);
657 return bytes_read;
660 /* Write function for fd objects. */
661 static ssize_t
662 es_func_fd_write (void *cookie, const void *buffer, size_t size)
665 estream_cookie_fd_t file_cookie = cookie;
666 ssize_t bytes_written;
669 bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
670 while (bytes_written == -1 && errno == EINTR);
672 return bytes_written;
675 /* Seek function for fd objects. */
676 static int
677 es_func_fd_seek (void *cookie, off_t *offset, int whence)
679 estream_cookie_fd_t file_cookie = cookie;
680 off_t offset_new;
681 int err;
683 offset_new = lseek (file_cookie->fd, *offset, whence);
684 if (offset_new == -1)
685 err = -1;
686 else
688 *offset = offset_new;
689 err = 0;
692 return err;
695 /* Destroy function for fd objects. */
696 static int
697 es_func_fd_destroy (void *cookie)
699 estream_cookie_fd_t fd_cookie = cookie;
700 int err;
702 if (fd_cookie)
704 err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
705 mem_free (fd_cookie);
707 else
708 err = 0;
710 return err;
714 static es_cookie_io_functions_t estream_functions_fd =
716 es_func_fd_read,
717 es_func_fd_write,
718 es_func_fd_seek,
719 es_func_fd_destroy
725 /* Implementation of FILE* I/O. */
727 /* Cookie for fp objects. */
728 typedef struct estream_cookie_fp
730 FILE *fp; /* The file pointer we are using for actual output. */
731 int no_close; /* If set we won't close the file pointer. */
732 } *estream_cookie_fp_t;
734 /* Create function for fd objects. */
735 static int
736 es_func_fp_create (void **cookie, FILE *fp,
737 unsigned int modeflags, int no_close)
739 estream_cookie_fp_t fp_cookie;
740 int err;
742 fp_cookie = mem_alloc (sizeof *fp_cookie);
743 if (!fp_cookie)
744 err = -1;
745 else
747 #ifdef HAVE_DOSISH_SYSTEM
748 /* Make sure it is in binary mode if requested. */
749 if ( (modeflags & O_BINARY) )
750 setmode (fileno (fp), O_BINARY);
751 #else
752 (void)modeflags;
753 #endif
754 fp_cookie->fp = fp;
755 fp_cookie->no_close = no_close;
756 *cookie = fp_cookie;
757 err = 0;
760 return err;
763 /* Read function for FILE* objects. */
764 static ssize_t
765 es_func_fp_read (void *cookie, void *buffer, size_t size)
768 estream_cookie_fp_t file_cookie = cookie;
769 ssize_t bytes_read;
771 bytes_read = fread (buffer, 1, size, file_cookie->fp);
772 if (!bytes_read && ferror (file_cookie->fp))
773 return -1;
774 return bytes_read;
777 /* Write function for FILE* objects. */
778 static ssize_t
779 es_func_fp_write (void *cookie, const void *buffer, size_t size)
782 estream_cookie_fp_t file_cookie = cookie;
783 size_t bytes_written;
785 bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
786 if (bytes_written != size)
787 return -1;
788 return bytes_written;
791 /* Seek function for FILE* objects. */
792 static int
793 es_func_fp_seek (void *cookie, off_t *offset, int whence)
795 estream_cookie_fp_t file_cookie = cookie;
796 long int offset_new;
798 if ( fseek (file_cookie->fp, (long int)*offset, whence) )
800 fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", errno,strerror (errno));
801 return -1;
804 offset_new = ftell (file_cookie->fp);
805 if (offset_new == -1)
807 fprintf (stderr, "\nftell failed: errno=%d (%s)\n", errno,strerror (errno));
808 return -1;
810 *offset = offset_new;
811 return 0;
814 /* Destroy function for fd objects. */
815 static int
816 es_func_fp_destroy (void *cookie)
818 estream_cookie_fp_t fp_cookie = cookie;
819 int err;
821 if (fp_cookie)
823 fflush (fp_cookie->fp);
824 err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
825 mem_free (fp_cookie);
827 else
828 err = 0;
830 return err;
834 static es_cookie_io_functions_t estream_functions_fp =
836 es_func_fp_read,
837 es_func_fp_write,
838 es_func_fp_seek,
839 es_func_fp_destroy
845 /* Implementation of file I/O. */
847 /* Create function for file objects. */
848 static int
849 es_func_file_create (void **cookie, int *filedes,
850 const char *path, unsigned int modeflags)
852 estream_cookie_fd_t file_cookie;
853 int err;
854 int fd;
856 err = 0;
857 fd = -1;
859 file_cookie = mem_alloc (sizeof (*file_cookie));
860 if (! file_cookie)
862 err = -1;
863 goto out;
866 fd = open (path, modeflags, ES_DEFAULT_OPEN_MODE);
867 if (fd == -1)
869 err = -1;
870 goto out;
872 #ifdef HAVE_DOSISH_SYSTEM
873 /* Make sure it is in binary mode if requested. */
874 if ( (modeflags & O_BINARY) )
875 setmode (fd, O_BINARY);
876 #endif
878 file_cookie->fd = fd;
879 file_cookie->no_close = 0;
880 *cookie = file_cookie;
881 *filedes = fd;
883 out:
885 if (err)
886 mem_free (file_cookie);
888 return err;
891 static es_cookie_io_functions_t estream_functions_file =
893 es_func_fd_read,
894 es_func_fd_write,
895 es_func_fd_seek,
896 es_func_fd_destroy
900 static int
901 es_convert_mode (const char *mode, unsigned int *modeflags)
903 unsigned int omode, oflags;
905 switch (*mode)
907 case 'r':
908 omode = O_RDONLY;
909 oflags = 0;
910 break;
911 case 'w':
912 omode = O_WRONLY;
913 oflags = O_TRUNC | O_CREAT;
914 break;
915 case 'a':
916 omode = O_WRONLY;
917 oflags = O_APPEND | O_CREAT;
918 break;
919 default:
920 errno = EINVAL;
921 return -1;
923 for (mode++; *mode; mode++)
925 switch (*mode)
927 case '+':
928 omode = O_RDWR;
929 break;
930 case 'b':
931 oflags |= O_BINARY;
932 break;
933 case 'x':
934 oflags |= O_EXCL;
935 break;
936 default: /* Ignore unknown flags. */
937 break;
941 *modeflags = (omode | oflags);
942 return 0;
948 * Low level stream functionality.
951 static int
952 es_fill (estream_t stream)
954 size_t bytes_read = 0;
955 int err;
957 if (!stream->intern->func_read)
959 errno = EOPNOTSUPP;
960 err = -1;
962 else
964 es_cookie_read_function_t func_read = stream->intern->func_read;
965 ssize_t ret;
967 ret = (*func_read) (stream->intern->cookie,
968 stream->buffer, stream->buffer_size);
969 if (ret == -1)
971 bytes_read = 0;
972 err = -1;
974 else
976 bytes_read = ret;
977 err = 0;
981 if (err)
982 stream->intern->indicators.err = 1;
983 else if (!bytes_read)
984 stream->intern->indicators.eof = 1;
986 stream->intern->offset += stream->data_len;
987 stream->data_len = bytes_read;
988 stream->data_offset = 0;
990 return err;
993 static int
994 es_flush (estream_t stream)
996 es_cookie_write_function_t func_write = stream->intern->func_write;
997 int err;
999 assert (stream->flags.writing);
1001 if (stream->data_offset)
1003 size_t bytes_written;
1004 size_t data_flushed;
1005 ssize_t ret;
1007 if (! func_write)
1009 err = EOPNOTSUPP;
1010 goto out;
1013 /* Note: to prevent an endless loop caused by user-provided
1014 write-functions that pretend to have written more bytes than
1015 they were asked to write, we have to check for
1016 "(stream->data_offset - data_flushed) > 0" instead of
1017 "stream->data_offset - data_flushed". */
1019 data_flushed = 0;
1020 err = 0;
1022 while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
1024 ret = (*func_write) (stream->intern->cookie,
1025 stream->buffer + data_flushed,
1026 stream->data_offset - data_flushed);
1027 if (ret == -1)
1029 bytes_written = 0;
1030 err = -1;
1032 else
1033 bytes_written = ret;
1035 data_flushed += bytes_written;
1036 if (err)
1037 break;
1040 stream->data_flushed += data_flushed;
1041 if (stream->data_offset == data_flushed)
1043 stream->intern->offset += stream->data_offset;
1044 stream->data_offset = 0;
1045 stream->data_flushed = 0;
1047 /* Propagate flush event. */
1048 (*func_write) (stream->intern->cookie, NULL, 0);
1051 else
1052 err = 0;
1054 out:
1056 if (err)
1057 stream->intern->indicators.err = 1;
1059 return err;
1062 /* Discard buffered data for STREAM. */
1063 static void
1064 es_empty (estream_t stream)
1066 assert (!stream->flags.writing);
1067 stream->data_len = 0;
1068 stream->data_offset = 0;
1069 stream->unread_data_len = 0;
1072 /* Initialize STREAM. */
1073 static void
1074 es_initialize (estream_t stream,
1075 void *cookie, int fd, es_cookie_io_functions_t functions,
1076 unsigned int modeflags)
1078 stream->intern->cookie = cookie;
1079 stream->intern->opaque = NULL;
1080 stream->intern->offset = 0;
1081 stream->intern->func_read = functions.func_read;
1082 stream->intern->func_write = functions.func_write;
1083 stream->intern->func_seek = functions.func_seek;
1084 stream->intern->func_close = functions.func_close;
1085 stream->intern->strategy = _IOFBF;
1086 stream->intern->fd = fd;
1087 stream->intern->print_err = 0;
1088 stream->intern->print_errno = 0;
1089 stream->intern->print_ntotal = 0;
1090 stream->intern->print_fp = NULL;
1091 stream->intern->indicators.err = 0;
1092 stream->intern->indicators.eof = 0;
1093 stream->intern->deallocate_buffer = 0;
1095 stream->data_len = 0;
1096 stream->data_offset = 0;
1097 stream->data_flushed = 0;
1098 stream->unread_data_len = 0;
1099 /* Depending on the modeflags we set whether we start in writing or
1100 reading mode. This is required in case we are working on a
1101 wronly stream which is not seeekable (like stdout). Without this
1102 pre-initialization we would do a seek at the first write call and
1103 as this will fail no utput will be delivered. */
1104 if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1105 stream->flags.writing = 1;
1106 else
1107 stream->flags.writing = 0;
1110 /* Deinitialize STREAM. */
1111 static int
1112 es_deinitialize (estream_t stream)
1114 es_cookie_close_function_t func_close;
1115 int err, tmp_err;
1117 if (stream->intern->print_fp)
1119 int save_errno = errno;
1120 fclose (stream->intern->print_fp);
1121 stream->intern->print_fp = NULL;
1122 errno = save_errno;
1125 func_close = stream->intern->func_close;
1127 err = 0;
1128 if (stream->flags.writing)
1129 SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1130 if (func_close)
1131 SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1134 return err;
1137 /* Create a new stream object, initialize it. */
1138 static int
1139 es_create (estream_t *stream, void *cookie, int fd,
1140 es_cookie_io_functions_t functions, unsigned int modeflags)
1142 estream_internal_t stream_internal_new;
1143 estream_t stream_new;
1144 int err;
1146 stream_new = NULL;
1147 stream_internal_new = NULL;
1149 stream_new = mem_alloc (sizeof (*stream_new));
1150 if (! stream_new)
1152 err = -1;
1153 goto out;
1156 stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
1157 if (! stream_internal_new)
1159 err = -1;
1160 goto out;
1163 stream_new->buffer = stream_internal_new->buffer;
1164 stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1165 stream_new->unread_buffer = stream_internal_new->unread_buffer;
1166 stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1167 stream_new->intern = stream_internal_new;
1169 ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
1170 es_initialize (stream_new, cookie, fd, functions, modeflags);
1172 err = es_list_add (stream_new);
1173 if (err)
1174 goto out;
1176 *stream = stream_new;
1178 out:
1180 if (err)
1182 if (stream_new)
1184 es_deinitialize (stream_new);
1185 mem_free (stream_new);
1189 return err;
1192 /* Deinitialize a stream object and destroy it. */
1193 static int
1194 es_destroy (estream_t stream)
1196 int err = 0;
1198 if (stream)
1200 es_list_remove (stream);
1201 err = es_deinitialize (stream);
1202 mem_free (stream->intern);
1203 mem_free (stream);
1206 return err;
1209 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1210 unbuffered-mode, storing the amount of bytes read in
1211 *BYTES_READ. */
1212 static int
1213 es_read_nbf (estream_t ES__RESTRICT stream,
1214 unsigned char *ES__RESTRICT buffer,
1215 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1217 es_cookie_read_function_t func_read = stream->intern->func_read;
1218 size_t data_read;
1219 ssize_t ret;
1220 int err;
1222 data_read = 0;
1223 err = 0;
1225 while (bytes_to_read - data_read)
1227 ret = (*func_read) (stream->intern->cookie,
1228 buffer + data_read, bytes_to_read - data_read);
1229 if (ret == -1)
1231 err = -1;
1232 break;
1234 else if (ret)
1235 data_read += ret;
1236 else
1237 break;
1240 stream->intern->offset += data_read;
1241 *bytes_read = data_read;
1243 return err;
1246 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1247 fully-buffered-mode, storing the amount of bytes read in
1248 *BYTES_READ. */
1249 static int
1250 es_read_fbf (estream_t ES__RESTRICT stream,
1251 unsigned char *ES__RESTRICT buffer,
1252 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1254 size_t data_available;
1255 size_t data_to_read;
1256 size_t data_read;
1257 int err;
1259 data_read = 0;
1260 err = 0;
1262 while ((bytes_to_read - data_read) && (! err))
1264 if (stream->data_offset == stream->data_len)
1266 /* Nothing more to read in current container, try to
1267 fill container with new data. */
1268 err = es_fill (stream);
1269 if (! err)
1270 if (! stream->data_len)
1271 /* Filling did not result in any data read. */
1272 break;
1275 if (! err)
1277 /* Filling resulted in some new data. */
1279 data_to_read = bytes_to_read - data_read;
1280 data_available = stream->data_len - stream->data_offset;
1281 if (data_to_read > data_available)
1282 data_to_read = data_available;
1284 memcpy (buffer + data_read,
1285 stream->buffer + stream->data_offset, data_to_read);
1286 stream->data_offset += data_to_read;
1287 data_read += data_to_read;
1291 *bytes_read = data_read;
1293 return err;
1296 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1297 line-buffered-mode, storing the amount of bytes read in
1298 *BYTES_READ. */
1299 static int
1300 es_read_lbf (estream_t ES__RESTRICT stream,
1301 unsigned char *ES__RESTRICT buffer,
1302 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1304 int err;
1306 err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1308 return err;
1311 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1312 *the amount of bytes read in BYTES_READ. */
1313 static int
1314 es_readn (estream_t ES__RESTRICT stream,
1315 void *ES__RESTRICT buffer_arg,
1316 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1318 unsigned char *buffer = (unsigned char *)buffer_arg;
1319 size_t data_read_unread, data_read;
1320 int err;
1322 data_read_unread = 0;
1323 data_read = 0;
1324 err = 0;
1326 if (stream->flags.writing)
1328 /* Switching to reading mode -> flush output. */
1329 err = es_flush (stream);
1330 if (err)
1331 goto out;
1332 stream->flags.writing = 0;
1335 /* Read unread data first. */
1336 while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1338 buffer[data_read_unread]
1339 = stream->unread_buffer[stream->unread_data_len - 1];
1340 stream->unread_data_len--;
1341 data_read_unread++;
1344 switch (stream->intern->strategy)
1346 case _IONBF:
1347 err = es_read_nbf (stream,
1348 buffer + data_read_unread,
1349 bytes_to_read - data_read_unread, &data_read);
1350 break;
1351 case _IOLBF:
1352 err = es_read_lbf (stream,
1353 buffer + data_read_unread,
1354 bytes_to_read - data_read_unread, &data_read);
1355 break;
1356 case _IOFBF:
1357 err = es_read_fbf (stream,
1358 buffer + data_read_unread,
1359 bytes_to_read - data_read_unread, &data_read);
1360 break;
1363 out:
1365 if (bytes_read)
1366 *bytes_read = data_read_unread + data_read;
1368 return err;
1371 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1372 amount of bytes succesfully unread in *BYTES_UNREAD. */
1373 static void
1374 es_unreadn (estream_t ES__RESTRICT stream,
1375 const unsigned char *ES__RESTRICT data, size_t data_n,
1376 size_t *ES__RESTRICT bytes_unread)
1378 size_t space_left;
1380 space_left = stream->unread_buffer_size - stream->unread_data_len;
1382 if (data_n > space_left)
1383 data_n = space_left;
1385 if (! data_n)
1386 goto out;
1388 memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1389 stream->unread_data_len += data_n;
1390 stream->intern->indicators.eof = 0;
1392 out:
1394 if (bytes_unread)
1395 *bytes_unread = data_n;
1398 /* Seek in STREAM. */
1399 static int
1400 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1401 off_t *ES__RESTRICT offset_new)
1403 es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1404 int err, ret;
1405 off_t off;
1407 if (! func_seek)
1409 errno = EOPNOTSUPP;
1410 err = -1;
1411 goto out;
1414 if (stream->flags.writing)
1416 /* Flush data first in order to prevent flushing it to the wrong
1417 offset. */
1418 err = es_flush (stream);
1419 if (err)
1420 goto out;
1421 stream->flags.writing = 0;
1424 off = offset;
1425 if (whence == SEEK_CUR)
1427 off = off - stream->data_len + stream->data_offset;
1428 off -= stream->unread_data_len;
1431 ret = (*func_seek) (stream->intern->cookie, &off, whence);
1432 if (ret == -1)
1434 err = -1;
1435 goto out;
1438 err = 0;
1439 es_empty (stream);
1441 if (offset_new)
1442 *offset_new = off;
1444 stream->intern->indicators.eof = 0;
1445 stream->intern->offset = off;
1447 out:
1449 if (err)
1450 stream->intern->indicators.err = 1;
1452 return err;
1455 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1456 unbuffered-mode, storing the amount of bytes written in
1457 *BYTES_WRITTEN. */
1458 static int
1459 es_write_nbf (estream_t ES__RESTRICT stream,
1460 const unsigned char *ES__RESTRICT buffer,
1461 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1463 es_cookie_write_function_t func_write = stream->intern->func_write;
1464 size_t data_written;
1465 ssize_t ret;
1466 int err;
1468 if (bytes_to_write && (! func_write))
1470 err = EOPNOTSUPP;
1471 goto out;
1474 data_written = 0;
1475 err = 0;
1477 while (bytes_to_write - data_written)
1479 ret = (*func_write) (stream->intern->cookie,
1480 buffer + data_written,
1481 bytes_to_write - data_written);
1482 if (ret == -1)
1484 err = -1;
1485 break;
1487 else
1488 data_written += ret;
1491 stream->intern->offset += data_written;
1492 *bytes_written = data_written;
1494 out:
1496 return err;
1499 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1500 fully-buffered-mode, storing the amount of bytes written in
1501 *BYTES_WRITTEN. */
1502 static int
1503 es_write_fbf (estream_t ES__RESTRICT stream,
1504 const unsigned char *ES__RESTRICT buffer,
1505 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1507 size_t space_available;
1508 size_t data_to_write;
1509 size_t data_written;
1510 int err;
1512 data_written = 0;
1513 err = 0;
1515 while ((bytes_to_write - data_written) && (! err))
1517 if (stream->data_offset == stream->buffer_size)
1518 /* Container full, flush buffer. */
1519 err = es_flush (stream);
1521 if (! err)
1523 /* Flushing resulted in empty container. */
1525 data_to_write = bytes_to_write - data_written;
1526 space_available = stream->buffer_size - stream->data_offset;
1527 if (data_to_write > space_available)
1528 data_to_write = space_available;
1530 memcpy (stream->buffer + stream->data_offset,
1531 buffer + data_written, data_to_write);
1532 stream->data_offset += data_to_write;
1533 data_written += data_to_write;
1537 *bytes_written = data_written;
1539 return err;
1543 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1544 line-buffered-mode, storing the amount of bytes written in
1545 *BYTES_WRITTEN. */
1546 static int
1547 es_write_lbf (estream_t ES__RESTRICT stream,
1548 const unsigned char *ES__RESTRICT buffer,
1549 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1551 size_t data_flushed = 0;
1552 size_t data_buffered = 0;
1553 unsigned char *nlp;
1554 int err = 0;
1556 nlp = memrchr (buffer, '\n', bytes_to_write);
1557 if (nlp)
1559 /* Found a newline, directly write up to (including) this
1560 character. */
1561 err = es_flush (stream);
1562 if (!err)
1563 err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1566 if (!err)
1568 /* Write remaining data fully buffered. */
1569 err = es_write_fbf (stream, buffer + data_flushed,
1570 bytes_to_write - data_flushed, &data_buffered);
1573 *bytes_written = data_flushed + data_buffered;
1574 return err;
1578 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1579 amount of bytes written in BYTES_WRITTEN. */
1580 static int
1581 es_writen (estream_t ES__RESTRICT stream,
1582 const void *ES__RESTRICT buffer,
1583 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1585 size_t data_written;
1586 int err;
1588 data_written = 0;
1589 err = 0;
1591 if (!stream->flags.writing)
1593 /* Switching to writing mode -> discard input data and seek to
1594 position at which reading has stopped. We can do this only
1595 if a seek function has been registered. */
1596 if (stream->intern->func_seek)
1598 err = es_seek (stream, 0, SEEK_CUR, NULL);
1599 if (err)
1601 if (errno == ESPIPE)
1602 err = 0;
1603 else
1604 goto out;
1609 switch (stream->intern->strategy)
1611 case _IONBF:
1612 err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1613 break;
1615 case _IOLBF:
1616 err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1617 break;
1619 case _IOFBF:
1620 err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1621 break;
1624 out:
1626 if (bytes_written)
1627 *bytes_written = data_written;
1628 if (data_written)
1629 if (!stream->flags.writing)
1630 stream->flags.writing = 1;
1632 return err;
1636 static int
1637 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1638 size_t *ES__RESTRICT data_len)
1640 int err;
1642 if (stream->flags.writing)
1644 /* Switching to reading mode -> flush output. */
1645 err = es_flush (stream);
1646 if (err)
1647 goto out;
1648 stream->flags.writing = 0;
1651 if (stream->data_offset == stream->data_len)
1653 /* Refill container. */
1654 err = es_fill (stream);
1655 if (err)
1656 goto out;
1659 if (data)
1660 *data = stream->buffer + stream->data_offset;
1661 if (data_len)
1662 *data_len = stream->data_len - stream->data_offset;
1663 err = 0;
1665 out:
1667 return err;
1671 /* Skip SIZE bytes of input data contained in buffer. */
1672 static int
1673 es_skip (estream_t stream, size_t size)
1675 int err;
1677 if (stream->data_offset + size > stream->data_len)
1679 errno = EINVAL;
1680 err = -1;
1682 else
1684 stream->data_offset += size;
1685 err = 0;
1688 return err;
1692 static int
1693 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
1694 char *ES__RESTRICT *ES__RESTRICT line,
1695 size_t *ES__RESTRICT line_length)
1697 size_t space_left;
1698 size_t line_size;
1699 estream_t line_stream;
1700 char *line_new;
1701 void *line_stream_cookie;
1702 char *newline;
1703 unsigned char *data;
1704 size_t data_len;
1705 int err;
1707 line_new = NULL;
1708 line_stream = NULL;
1709 line_stream_cookie = NULL;
1711 err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0,
1712 BUFFER_BLOCK_SIZE, 1,
1713 mem_realloc, mem_free,
1714 O_RDWR,
1716 if (err)
1717 goto out;
1719 err = es_create (&line_stream, line_stream_cookie, -1,
1720 estream_functions_mem, O_RDWR);
1721 if (err)
1722 goto out;
1724 space_left = max_length;
1725 line_size = 0;
1726 while (1)
1728 if (max_length && (space_left == 1))
1729 break;
1731 err = es_peek (stream, &data, &data_len);
1732 if (err || (! data_len))
1733 break;
1735 if (data_len > (space_left - 1))
1736 data_len = space_left - 1;
1738 newline = memchr (data, '\n', data_len);
1739 if (newline)
1741 data_len = (newline - (char *) data) + 1;
1742 err = es_write (line_stream, data, data_len, NULL);
1743 if (! err)
1745 space_left -= data_len;
1746 line_size += data_len;
1747 es_skip (stream, data_len);
1748 break;
1751 else
1753 err = es_write (line_stream, data, data_len, NULL);
1754 if (! err)
1756 space_left -= data_len;
1757 line_size += data_len;
1758 es_skip (stream, data_len);
1761 if (err)
1762 break;
1764 if (err)
1765 goto out;
1767 /* Complete line has been written to line_stream. */
1769 if ((max_length > 1) && (! line_size))
1771 stream->intern->indicators.eof = 1;
1772 goto out;
1775 err = es_seek (line_stream, 0, SEEK_SET, NULL);
1776 if (err)
1777 goto out;
1779 if (! *line)
1781 line_new = mem_alloc (line_size + 1);
1782 if (! line_new)
1784 err = -1;
1785 goto out;
1788 else
1789 line_new = *line;
1791 err = es_read (line_stream, line_new, line_size, NULL);
1792 if (err)
1793 goto out;
1795 line_new[line_size] = '\0';
1797 if (! *line)
1798 *line = line_new;
1799 if (line_length)
1800 *line_length = line_size;
1802 out:
1804 if (line_stream)
1805 es_destroy (line_stream);
1806 else if (line_stream_cookie)
1807 es_func_mem_destroy (line_stream_cookie);
1809 if (err)
1811 if (! *line)
1812 mem_free (line_new);
1813 stream->intern->indicators.err = 1;
1816 return err;
1820 /* Output fucntion used for estream_format. */
1821 static int
1822 print_writer (void *outfncarg, const char *buf, size_t buflen)
1824 estream_t stream = outfncarg;
1825 size_t nwritten;
1826 int rc;
1828 nwritten = 0;
1829 rc = es_writen (stream, buf, buflen, &nwritten);
1830 stream->intern->print_ntotal += nwritten;
1831 return rc;
1835 /* The core of our printf function. This is called in locked state. */
1836 static int
1837 es_print (estream_t ES__RESTRICT stream,
1838 const char *ES__RESTRICT format, va_list ap)
1840 int rc;
1842 stream->intern->print_ntotal = 0;
1843 rc = estream_format (print_writer, stream, format, ap);
1844 if (rc)
1845 return -1;
1846 return (int)stream->intern->print_ntotal;
1850 static void
1851 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1853 if (ind_err != -1)
1854 stream->intern->indicators.err = ind_err ? 1 : 0;
1855 if (ind_eof != -1)
1856 stream->intern->indicators.eof = ind_eof ? 1 : 0;
1860 static int
1861 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1863 int ret = 0;
1865 if (ind_err)
1866 ret = stream->intern->indicators.err;
1867 else if (ind_eof)
1868 ret = stream->intern->indicators.eof;
1870 return ret;
1874 static int
1875 es_set_buffering (estream_t ES__RESTRICT stream,
1876 char *ES__RESTRICT buffer, int mode, size_t size)
1878 int err;
1880 /* Flush or empty buffer depending on mode. */
1881 if (stream->flags.writing)
1883 err = es_flush (stream);
1884 if (err)
1885 goto out;
1887 else
1888 es_empty (stream);
1890 es_set_indicators (stream, -1, 0);
1892 /* Free old buffer in case that was allocated by this function. */
1893 if (stream->intern->deallocate_buffer)
1895 stream->intern->deallocate_buffer = 0;
1896 mem_free (stream->buffer);
1897 stream->buffer = NULL;
1900 if (mode == _IONBF)
1901 stream->buffer_size = 0;
1902 else
1904 void *buffer_new;
1906 if (buffer)
1907 buffer_new = buffer;
1908 else
1910 buffer_new = mem_alloc (size);
1911 if (! buffer_new)
1913 err = -1;
1914 goto out;
1918 stream->buffer = buffer_new;
1919 stream->buffer_size = size;
1920 if (! buffer)
1921 stream->intern->deallocate_buffer = 1;
1923 stream->intern->strategy = mode;
1924 err = 0;
1926 out:
1928 return err;
1932 static off_t
1933 es_offset_calculate (estream_t stream)
1935 off_t offset;
1937 offset = stream->intern->offset + stream->data_offset;
1938 if (offset < stream->unread_data_len)
1939 /* Offset undefined. */
1940 offset = 0;
1941 else
1942 offset -= stream->unread_data_len;
1944 return offset;
1948 static void
1949 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1950 void **ES__RESTRICT opaque_old)
1952 if (opaque_old)
1953 *opaque_old = stream->intern->opaque;
1954 if (opaque_new)
1955 stream->intern->opaque = opaque_new;
1959 static int
1960 es_get_fd (estream_t stream)
1962 return stream->intern->fd;
1967 /* API. */
1970 es_init (void)
1972 int err;
1974 err = es_init_do ();
1976 return err;
1979 estream_t
1980 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
1982 unsigned int modeflags;
1983 int create_called;
1984 estream_t stream;
1985 void *cookie;
1986 int err;
1987 int fd;
1989 stream = NULL;
1990 cookie = NULL;
1991 create_called = 0;
1993 err = es_convert_mode (mode, &modeflags);
1994 if (err)
1995 goto out;
1997 err = es_func_file_create (&cookie, &fd, path, modeflags);
1998 if (err)
1999 goto out;
2001 create_called = 1;
2002 err = es_create (&stream, cookie, fd, estream_functions_file, modeflags);
2003 if (err)
2004 goto out;
2006 out:
2008 if (err && create_called)
2009 (*estream_functions_file.func_close) (cookie);
2011 return stream;
2015 estream_t
2016 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
2017 unsigned int grow,
2018 func_realloc_t func_realloc, func_free_t func_free,
2019 const char *ES__RESTRICT mode)
2021 unsigned int modeflags;
2022 int create_called;
2023 estream_t stream;
2024 void *cookie;
2025 int err;
2027 cookie = 0;
2028 stream = NULL;
2029 create_called = 0;
2031 err = es_convert_mode (mode, &modeflags);
2032 if (err)
2033 goto out;
2035 err = es_func_mem_create (&cookie, data, data_n, data_len,
2036 BUFFER_BLOCK_SIZE, grow,
2037 func_realloc, func_free, modeflags, 0);
2038 if (err)
2039 goto out;
2041 create_called = 1;
2042 err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags);
2044 out:
2046 if (err && create_called)
2047 (*estream_functions_mem.func_close) (cookie);
2049 return stream;
2053 estream_t
2054 es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
2056 unsigned int modeflags;
2057 estream_t stream = NULL;
2058 void *cookie = NULL;
2060 /* Memory streams are always read/write. We use MODE only to get
2061 the append flag. */
2062 if (es_convert_mode (mode, &modeflags))
2063 return NULL;
2064 modeflags |= O_RDWR;
2067 if (es_func_mem_create (&cookie, NULL, 0, 0,
2068 BUFFER_BLOCK_SIZE, 1,
2069 mem_realloc, mem_free, modeflags,
2070 memlimit))
2071 return NULL;
2073 if (es_create (&stream, cookie, -1, estream_functions_mem, modeflags))
2074 (*estream_functions_mem.func_close) (cookie);
2076 return stream;
2081 estream_t
2082 es_fopencookie (void *ES__RESTRICT cookie,
2083 const char *ES__RESTRICT mode,
2084 es_cookie_io_functions_t functions)
2086 unsigned int modeflags;
2087 estream_t stream;
2088 int err;
2090 stream = NULL;
2091 modeflags = 0;
2093 err = es_convert_mode (mode, &modeflags);
2094 if (err)
2095 goto out;
2097 err = es_create (&stream, cookie, -1, functions, modeflags);
2098 if (err)
2099 goto out;
2101 out:
2103 return stream;
2107 estream_t
2108 do_fdopen (int filedes, const char *mode, int no_close)
2110 unsigned int modeflags;
2111 int create_called;
2112 estream_t stream;
2113 void *cookie;
2114 int err;
2116 stream = NULL;
2117 cookie = NULL;
2118 create_called = 0;
2120 err = es_convert_mode (mode, &modeflags);
2121 if (err)
2122 goto out;
2124 err = es_func_fd_create (&cookie, filedes, modeflags, no_close);
2125 if (err)
2126 goto out;
2128 create_called = 1;
2129 err = es_create (&stream, cookie, filedes, estream_functions_fd, modeflags);
2131 out:
2133 if (err && create_called)
2134 (*estream_functions_fd.func_close) (cookie);
2136 return stream;
2139 estream_t
2140 es_fdopen (int filedes, const char *mode)
2142 return do_fdopen (filedes, mode, 0);
2145 /* A variant of es_fdopen which does not close FILEDES at the end. */
2146 estream_t
2147 es_fdopen_nc (int filedes, const char *mode)
2149 return do_fdopen (filedes, mode, 1);
2153 estream_t
2154 do_fpopen (FILE *fp, const char *mode, int no_close)
2156 unsigned int modeflags;
2157 int create_called;
2158 estream_t stream;
2159 void *cookie;
2160 int err;
2162 stream = NULL;
2163 cookie = NULL;
2164 create_called = 0;
2166 err = es_convert_mode (mode, &modeflags);
2167 if (err)
2168 goto out;
2170 fflush (fp);
2171 err = es_func_fp_create (&cookie, fp, modeflags, no_close);
2172 if (err)
2173 goto out;
2175 create_called = 1;
2176 err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
2177 modeflags);
2179 out:
2181 if (err && create_called)
2182 (*estream_functions_fp.func_close) (cookie);
2184 return stream;
2188 /* Create an estream from the stdio stream FP. This mechanism is
2189 useful in case the stdio streams have special properties and may
2190 not be mixed with fd based functions. This is for example the case
2191 under Windows where the 3 standard streams are associated with the
2192 console whereas a duped and fd-opened stream of one of this stream
2193 won't be associated with the console. As this messes things up it
2194 is easier to keep on using the standard I/O stream as a backend for
2195 estream. */
2196 estream_t
2197 es_fpopen (FILE *fp, const char *mode)
2199 return do_fpopen (fp, mode, 0);
2203 /* Same as es_fpopen but does not close FP at the end. */
2204 estream_t
2205 es_fpopen_nc (FILE *fp, const char *mode)
2207 return do_fpopen (fp, mode, 1);
2211 estream_t
2212 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
2213 estream_t ES__RESTRICT stream)
2215 int err;
2217 if (path)
2219 unsigned int modeflags;
2220 int create_called;
2221 void *cookie;
2222 int fd;
2224 cookie = NULL;
2225 create_called = 0;
2227 ESTREAM_LOCK (stream);
2229 es_deinitialize (stream);
2231 err = es_convert_mode (mode, &modeflags);
2232 if (err)
2233 goto leave;
2235 err = es_func_file_create (&cookie, &fd, path, modeflags);
2236 if (err)
2237 goto leave;
2239 create_called = 1;
2240 es_initialize (stream, cookie, fd, estream_functions_file, modeflags);
2242 leave:
2244 if (err)
2246 if (create_called)
2247 es_func_fd_destroy (cookie);
2249 es_destroy (stream);
2250 stream = NULL;
2252 else
2253 ESTREAM_UNLOCK (stream);
2255 else
2257 /* FIXME? We don't support re-opening at the moment. */
2258 errno = EINVAL;
2259 es_deinitialize (stream);
2260 es_destroy (stream);
2261 stream = NULL;
2264 return stream;
2269 es_fclose (estream_t stream)
2271 int err;
2273 err = es_destroy (stream);
2275 return err;
2279 es_fileno_unlocked (estream_t stream)
2281 return es_get_fd (stream);
2285 void
2286 es_flockfile (estream_t stream)
2288 ESTREAM_LOCK (stream);
2293 es_ftrylockfile (estream_t stream)
2295 return ESTREAM_TRYLOCK (stream);
2299 void
2300 es_funlockfile (estream_t stream)
2302 ESTREAM_UNLOCK (stream);
2307 es_fileno (estream_t stream)
2309 int ret;
2311 ESTREAM_LOCK (stream);
2312 ret = es_fileno_unlocked (stream);
2313 ESTREAM_UNLOCK (stream);
2315 return ret;
2320 es_feof_unlocked (estream_t stream)
2322 return es_get_indicator (stream, 0, 1);
2327 es_feof (estream_t stream)
2329 int ret;
2331 ESTREAM_LOCK (stream);
2332 ret = es_feof_unlocked (stream);
2333 ESTREAM_UNLOCK (stream);
2335 return ret;
2340 es_ferror_unlocked (estream_t stream)
2342 return es_get_indicator (stream, 1, 0);
2347 es_ferror (estream_t stream)
2349 int ret;
2351 ESTREAM_LOCK (stream);
2352 ret = es_ferror_unlocked (stream);
2353 ESTREAM_UNLOCK (stream);
2355 return ret;
2359 void
2360 es_clearerr_unlocked (estream_t stream)
2362 es_set_indicators (stream, 0, 0);
2366 void
2367 es_clearerr (estream_t stream)
2369 ESTREAM_LOCK (stream);
2370 es_clearerr_unlocked (stream);
2371 ESTREAM_UNLOCK (stream);
2376 es_fflush (estream_t stream)
2378 int err;
2380 if (stream)
2382 ESTREAM_LOCK (stream);
2383 if (stream->flags.writing)
2384 err = es_flush (stream);
2385 else
2387 es_empty (stream);
2388 err = 0;
2390 ESTREAM_UNLOCK (stream);
2392 else
2393 err = es_list_iterate (es_fflush);
2395 return err ? EOF : 0;
2400 es_fseek (estream_t stream, long int offset, int whence)
2402 int err;
2404 ESTREAM_LOCK (stream);
2405 err = es_seek (stream, offset, whence, NULL);
2406 ESTREAM_UNLOCK (stream);
2408 return err;
2413 es_fseeko (estream_t stream, off_t offset, int whence)
2415 int err;
2417 ESTREAM_LOCK (stream);
2418 err = es_seek (stream, offset, whence, NULL);
2419 ESTREAM_UNLOCK (stream);
2421 return err;
2425 long int
2426 es_ftell (estream_t stream)
2428 long int ret;
2430 ESTREAM_LOCK (stream);
2431 ret = es_offset_calculate (stream);
2432 ESTREAM_UNLOCK (stream);
2434 return ret;
2438 off_t
2439 es_ftello (estream_t stream)
2441 off_t ret = -1;
2443 ESTREAM_LOCK (stream);
2444 ret = es_offset_calculate (stream);
2445 ESTREAM_UNLOCK (stream);
2447 return ret;
2451 void
2452 es_rewind (estream_t stream)
2454 ESTREAM_LOCK (stream);
2455 es_seek (stream, 0L, SEEK_SET, NULL);
2456 es_set_indicators (stream, 0, -1);
2457 ESTREAM_UNLOCK (stream);
2462 _es_getc_underflow (estream_t stream)
2464 int err;
2465 unsigned char c;
2466 size_t bytes_read;
2468 err = es_readn (stream, &c, 1, &bytes_read);
2470 return (err || (! bytes_read)) ? EOF : c;
2475 _es_putc_overflow (int c, estream_t stream)
2477 unsigned char d = c;
2478 int err;
2480 err = es_writen (stream, &d, 1, NULL);
2482 return err ? EOF : c;
2487 es_fgetc (estream_t stream)
2489 int ret;
2491 ESTREAM_LOCK (stream);
2492 ret = es_getc_unlocked (stream);
2493 ESTREAM_UNLOCK (stream);
2495 return ret;
2500 es_fputc (int c, estream_t stream)
2502 int ret;
2504 ESTREAM_LOCK (stream);
2505 ret = es_putc_unlocked (c, stream);
2506 ESTREAM_UNLOCK (stream);
2508 return ret;
2513 es_ungetc (int c, estream_t stream)
2515 unsigned char data = (unsigned char) c;
2516 size_t data_unread;
2518 ESTREAM_LOCK (stream);
2519 es_unreadn (stream, &data, 1, &data_unread);
2520 ESTREAM_UNLOCK (stream);
2522 return data_unread ? c : EOF;
2527 es_read (estream_t ES__RESTRICT stream,
2528 void *ES__RESTRICT buffer, size_t bytes_to_read,
2529 size_t *ES__RESTRICT bytes_read)
2531 int err;
2533 if (bytes_to_read)
2535 ESTREAM_LOCK (stream);
2536 err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2537 ESTREAM_UNLOCK (stream);
2539 else
2540 err = 0;
2542 return err;
2547 es_write (estream_t ES__RESTRICT stream,
2548 const void *ES__RESTRICT buffer, size_t bytes_to_write,
2549 size_t *ES__RESTRICT bytes_written)
2551 int err;
2553 if (bytes_to_write)
2555 ESTREAM_LOCK (stream);
2556 err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2557 ESTREAM_UNLOCK (stream);
2559 else
2560 err = 0;
2562 return err;
2566 size_t
2567 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2568 estream_t ES__RESTRICT stream)
2570 size_t ret, bytes;
2571 int err;
2573 if (size * nitems)
2575 ESTREAM_LOCK (stream);
2576 err = es_readn (stream, ptr, size * nitems, &bytes);
2577 ESTREAM_UNLOCK (stream);
2579 ret = bytes / size;
2581 else
2582 ret = 0;
2584 return ret;
2588 size_t
2589 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2590 estream_t ES__RESTRICT stream)
2592 size_t ret, bytes;
2593 int err;
2595 if (size * nitems)
2597 ESTREAM_LOCK (stream);
2598 err = es_writen (stream, ptr, size * nitems, &bytes);
2599 ESTREAM_UNLOCK (stream);
2601 ret = bytes / size;
2603 else
2604 ret = 0;
2606 return ret;
2610 char *
2611 es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
2613 unsigned char *s = (unsigned char*)buffer;
2614 int c;
2616 if (!length)
2617 return NULL;
2619 c = EOF;
2620 ESTREAM_LOCK (stream);
2621 while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n')
2623 *s++ = c;
2624 length--;
2626 ESTREAM_UNLOCK (stream);
2628 if (c == EOF && s == (unsigned char*)buffer)
2629 return NULL; /* Nothing read. */
2631 if (c != EOF && length > 1)
2632 *s++ = c;
2634 *s = 0;
2635 return buffer;
2640 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2642 size_t length;
2643 int err;
2645 length = strlen (s);
2646 ESTREAM_LOCK (stream);
2647 err = es_writen (stream, s, length, NULL);
2648 ESTREAM_UNLOCK (stream);
2650 return err ? EOF : 0;
2654 ssize_t
2655 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2656 estream_t ES__RESTRICT stream)
2658 char *line = NULL;
2659 size_t line_n = 0;
2660 int err;
2662 ESTREAM_LOCK (stream);
2663 err = doreadline (stream, 0, &line, &line_n);
2664 ESTREAM_UNLOCK (stream);
2665 if (err)
2666 goto out;
2668 if (*n)
2670 /* Caller wants us to use his buffer. */
2672 if (*n < (line_n + 1))
2674 /* Provided buffer is too small -> resize. */
2676 void *p;
2678 p = mem_realloc (*lineptr, line_n + 1);
2679 if (! p)
2680 err = -1;
2681 else
2683 if (*lineptr != p)
2684 *lineptr = p;
2688 if (! err)
2690 memcpy (*lineptr, line, line_n + 1);
2691 if (*n != line_n)
2692 *n = line_n;
2694 mem_free (line);
2696 else
2698 /* Caller wants new buffers. */
2699 *lineptr = line;
2700 *n = line_n;
2703 out:
2705 return err ? err : line_n;
2710 /* Same as fgets() but if the provided buffer is too short a larger
2711 one will be allocated. This is similar to getline. A line is
2712 considered a byte stream ending in a LF.
2714 If MAX_LENGTH is not NULL, it shall point to a value with the
2715 maximum allowed allocation.
2717 Returns the length of the line. EOF is indicated by a line of
2718 length zero. A truncated line is indicated my setting the value at
2719 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2720 memory was enable or another error occurred; ERRNO is then set
2721 accordingly.
2723 If a line has been truncated, the file pointer is moved forward to
2724 the end of the line so that the next read starts with the next
2725 line. Note that MAX_LENGTH must be re-initialzied in this case.
2727 The caller initially needs to provide the address of a variable,
2728 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2729 anymore with the following invocations. LENGTH_OF_BUFFER should be
2730 the address of a variable, initialized to 0, which is also
2731 maintained by this function. Thus, both paramaters should be
2732 considered the state of this function.
2734 Note: The returned buffer is allocated with enough extra space to
2735 allow the caller to append a CR,LF,Nul. The buffer should be
2736 released using es_free.
2738 ssize_t
2739 es_read_line (estream_t stream,
2740 char **addr_of_buffer, size_t *length_of_buffer,
2741 size_t *max_length)
2743 int c;
2744 char *buffer = *addr_of_buffer;
2745 size_t length = *length_of_buffer;
2746 size_t nbytes = 0;
2747 size_t maxlen = max_length? *max_length : 0;
2748 char *p;
2750 if (!buffer)
2752 /* No buffer given - allocate a new one. */
2753 length = 256;
2754 buffer = mem_alloc (length);
2755 *addr_of_buffer = buffer;
2756 if (!buffer)
2758 *length_of_buffer = 0;
2759 if (max_length)
2760 *max_length = 0;
2761 return -1;
2763 *length_of_buffer = length;
2766 if (length < 4)
2768 /* This should never happen. If it does, the function has been
2769 called with wrong arguments. */
2770 errno = EINVAL;
2771 return -1;
2773 length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2775 ESTREAM_LOCK (stream);
2776 p = buffer;
2777 while ((c = es_getc_unlocked (stream)) != EOF)
2779 if (nbytes == length)
2781 /* Enlarge the buffer. */
2782 if (maxlen && length > maxlen)
2784 /* We are beyond our limit: Skip the rest of the line. */
2785 while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
2787 *p++ = '\n'; /* Always append a LF (we reserved some space). */
2788 nbytes++;
2789 if (max_length)
2790 *max_length = 0; /* Indicate truncation. */
2791 break; /* the while loop. */
2793 length += 3; /* Adjust for the reserved bytes. */
2794 length += length < 1024? 256 : 1024;
2795 *addr_of_buffer = mem_realloc (buffer, length);
2796 if (!*addr_of_buffer)
2798 int save_errno = errno;
2799 mem_free (buffer);
2800 *length_of_buffer = *max_length = 0;
2801 ESTREAM_UNLOCK (stream);
2802 errno = save_errno;
2803 return -1;
2805 buffer = *addr_of_buffer;
2806 *length_of_buffer = length;
2807 length -= 3;
2808 p = buffer + nbytes;
2810 *p++ = c;
2811 nbytes++;
2812 if (c == '\n')
2813 break;
2815 *p = 0; /* Make sure the line is a string. */
2816 ESTREAM_UNLOCK (stream);
2818 return nbytes;
2821 /* Wrapper around free() to match the memory allocation system used
2822 by estream. Should be used for all buffers returned to the caller
2823 by libestream. */
2824 void
2825 es_free (void *a)
2827 mem_free (a);
2832 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2833 va_list ap)
2835 int ret;
2837 ESTREAM_LOCK (stream);
2838 ret = es_print (stream, format, ap);
2839 ESTREAM_UNLOCK (stream);
2841 return ret;
2845 static int
2846 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
2847 const char *ES__RESTRICT format, ...)
2849 int ret;
2851 va_list ap;
2852 va_start (ap, format);
2853 ret = es_print (stream, format, ap);
2854 va_end (ap);
2856 return ret;
2861 es_fprintf (estream_t ES__RESTRICT stream,
2862 const char *ES__RESTRICT format, ...)
2864 int ret;
2866 va_list ap;
2867 va_start (ap, format);
2868 ESTREAM_LOCK (stream);
2869 ret = es_print (stream, format, ap);
2870 ESTREAM_UNLOCK (stream);
2871 va_end (ap);
2873 return ret;
2877 static int
2878 tmpfd (void)
2880 #ifdef HAVE_W32_SYSTEM
2881 int attempts, n;
2882 char buffer[MAX_PATH+9+12+1];
2883 char *name, *p;
2884 HANDLE file;
2885 int pid = GetCurrentProcessId ();
2886 unsigned int value;
2887 int i;
2889 n = GetTempPath (MAX_PATH+1, buffer);
2890 if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
2892 errno = ENOENT;
2893 return -1;
2895 p = buffer + strlen (buffer);
2896 strcpy (p, "_estream");
2897 p += 8;
2898 /* We try to create the directory but don't care about an error as
2899 it may already exist and the CreateFile would throw an error
2900 anyway. */
2901 CreateDirectory (buffer, NULL);
2902 *p++ = '\\';
2903 name = p;
2904 for (attempts=0; attempts < 10; attempts++)
2906 p = name;
2907 value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
2908 for (i=0; i < 8; i++)
2910 *p++ = tohex (((value >> 28) & 0x0f));
2911 value <<= 4;
2913 strcpy (p, ".tmp");
2914 file = CreateFile (buffer,
2915 GENERIC_READ | GENERIC_WRITE,
2917 NULL,
2918 CREATE_NEW,
2919 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
2920 NULL);
2921 if (file != INVALID_HANDLE_VALUE)
2923 int fd = _open_osfhandle ((long)file, 0);
2924 if (fd == -1)
2926 CloseHandle (file);
2927 return -1;
2929 return fd;
2931 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
2933 errno = ENOENT;
2934 return -1;
2935 #else /*!HAVE_W32_SYSTEM*/
2936 FILE *fp;
2937 int fp_fd;
2938 int fd;
2940 fp = NULL;
2941 fd = -1;
2943 fp = tmpfile ();
2944 if (! fp)
2945 goto out;
2947 fp_fd = fileno (fp);
2948 fd = dup (fp_fd);
2950 out:
2952 if (fp)
2953 fclose (fp);
2955 return fd;
2956 #endif /*!HAVE_W32_SYSTEM*/
2959 estream_t
2960 es_tmpfile (void)
2962 unsigned int modeflags;
2963 int create_called;
2964 estream_t stream;
2965 void *cookie;
2966 int err;
2967 int fd;
2969 create_called = 0;
2970 stream = NULL;
2971 modeflags = O_RDWR | O_TRUNC | O_CREAT;
2972 cookie = NULL;
2974 fd = tmpfd ();
2975 if (fd == -1)
2977 err = -1;
2978 goto out;
2981 err = es_func_fd_create (&cookie, fd, modeflags, 0);
2982 if (err)
2983 goto out;
2985 create_called = 1;
2986 err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags);
2988 out:
2990 if (err)
2992 if (create_called)
2993 es_func_fd_destroy (cookie);
2994 else if (fd != -1)
2995 close (fd);
2996 stream = NULL;
2999 return stream;
3004 es_setvbuf (estream_t ES__RESTRICT stream,
3005 char *ES__RESTRICT buf, int type, size_t size)
3007 int err;
3009 if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
3010 && (! ((! size) && (type != _IONBF))))
3012 ESTREAM_LOCK (stream);
3013 err = es_set_buffering (stream, buf, type, size);
3014 ESTREAM_UNLOCK (stream);
3016 else
3018 errno = EINVAL;
3019 err = -1;
3022 return err;
3026 void
3027 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
3029 ESTREAM_LOCK (stream);
3030 es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3031 ESTREAM_UNLOCK (stream);
3034 void
3035 es_opaque_set (estream_t stream, void *opaque)
3037 ESTREAM_LOCK (stream);
3038 es_opaque_ctrl (stream, opaque, NULL);
3039 ESTREAM_UNLOCK (stream);
3043 void *
3044 es_opaque_get (estream_t stream)
3046 void *opaque;
3048 ESTREAM_LOCK (stream);
3049 es_opaque_ctrl (stream, NULL, &opaque);
3050 ESTREAM_UNLOCK (stream);
3052 return opaque;
3055 /* Print a BUFFER to STREAM while replacing all control characters and
3056 the characters in DELIMITERS by standard C escape sequences.
3057 Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
3058 the number of bytes actually written are stored at this
3059 address. */
3060 int
3061 es_write_sanitized (estream_t ES__RESTRICT stream,
3062 const void * ES__RESTRICT buffer, size_t length,
3063 const char * delimiters,
3064 size_t * ES__RESTRICT bytes_written)
3066 const unsigned char *p = buffer;
3067 size_t count = 0;
3068 int ret;
3070 ESTREAM_LOCK (stream);
3071 for (; length; length--, p++, count++)
3073 if (*p < 0x20
3074 || *p == 0x7f
3075 || (delimiters
3076 && (strchr (delimiters, *p) || *p == '\\')))
3078 es_putc_unlocked ('\\', stream);
3079 count++;
3080 if (*p == '\n')
3082 es_putc_unlocked ('n', stream);
3083 count++;
3085 else if (*p == '\r')
3087 es_putc_unlocked ('r', stream);
3088 count++;
3090 else if (*p == '\f')
3092 es_putc_unlocked ('f', stream);
3093 count++;
3095 else if (*p == '\v')
3097 es_putc_unlocked ('v', stream);
3098 count++;
3100 else if (*p == '\b')
3102 es_putc_unlocked ('b', stream);
3103 count++;
3105 else if (!*p)
3107 es_putc_unlocked('0', stream);
3108 count++;
3110 else
3112 es_fprintf_unlocked (stream, "x%02x", *p);
3113 count += 3;
3116 else
3118 es_putc_unlocked (*p, stream);
3119 count++;
3123 if (bytes_written)
3124 *bytes_written = count;
3125 ret = es_ferror_unlocked (stream)? -1 : 0;
3126 ESTREAM_UNLOCK (stream);
3128 return ret;
3132 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3133 RESERVED must be 0. Returns 0 on success or -1 on error. If
3134 BYTES_WRITTEN is not NULL the number of bytes actually written are
3135 stored at this address. */
3137 es_write_hexstring (estream_t ES__RESTRICT stream,
3138 const void *ES__RESTRICT buffer, size_t length,
3139 int reserved, size_t *ES__RESTRICT bytes_written )
3141 int ret;
3142 const unsigned char *s;
3143 size_t count = 0;
3145 (void)reserved;
3147 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3149 if (!length)
3150 return 0;
3152 ESTREAM_LOCK (stream);
3154 for (s = buffer; length; s++, length--)
3156 es_putc_unlocked ( tohex ((*s>>4)&15), stream);
3157 es_putc_unlocked ( tohex (*s&15), stream);
3158 count += 2;
3161 if (bytes_written)
3162 *bytes_written = count;
3163 ret = es_ferror_unlocked (stream)? -1 : 0;
3165 ESTREAM_UNLOCK (stream);
3167 return ret;
3169 #undef tohex
3174 #ifdef GNUPG_MAJOR_VERSION
3175 /* Special estream function to print an UTF8 string in the native
3176 encoding. The interface is the same as es_write_sanitized, however
3177 only one delimiter may be supported.
3179 THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3181 es_write_sanitized_utf8_buffer (estream_t stream,
3182 const void *buffer, size_t length,
3183 const char *delimiters, size_t *bytes_written)
3185 const char *p = buffer;
3186 size_t i;
3188 /* We can handle plain ascii simpler, so check for it first. */
3189 for (i=0; i < length; i++ )
3191 if ( (p[i] & 0x80) )
3192 break;
3194 if (i < length)
3196 int delim = delimiters? *delimiters : 0;
3197 char *buf;
3198 int ret;
3200 /*(utf8 conversion already does the control character quoting). */
3201 buf = utf8_to_native (p, length, delim);
3202 if (bytes_written)
3203 *bytes_written = strlen (buf);
3204 ret = es_fputs (buf, stream);
3205 xfree (buf);
3206 return i;
3208 else
3209 return es_write_sanitized (stream, p, length, delimiters, bytes_written);
3211 #endif /*GNUPG_MAJOR_VERSION*/