Translate the oktext (yes/no).
[gnupg.git] / common / estream.c
blobee6c51af81b4513b22acafd9f6f09e79efb93393
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
901 /* Stream primitives. */
903 static int
904 es_convert_mode (const char *mode, unsigned int *modeflags)
907 /* FIXME: We need to allow all mode flags permutations. */
908 struct
910 const char *mode;
911 unsigned int flags;
912 } mode_flags[] = { { "r",
913 O_RDONLY },
914 { "rb",
915 O_RDONLY | O_BINARY },
916 { "w",
917 O_WRONLY | O_TRUNC | O_CREAT },
918 { "wb",
919 O_WRONLY | O_TRUNC | O_CREAT | O_BINARY },
920 { "a",
921 O_WRONLY | O_APPEND | O_CREAT },
922 { "ab",
923 O_WRONLY | O_APPEND | O_CREAT | O_BINARY },
924 { "r+",
925 O_RDWR },
926 { "rb+",
927 O_RDWR | O_BINARY },
928 { "r+b",
929 O_RDONLY | O_WRONLY | O_BINARY },
930 { "w+",
931 O_RDWR | O_TRUNC | O_CREAT },
932 { "wb+",
933 O_RDWR | O_TRUNC | O_CREAT | O_BINARY },
934 { "w+b",
935 O_RDWR | O_TRUNC | O_CREAT | O_BINARY },
936 { "a+",
937 O_RDWR | O_CREAT | O_APPEND },
938 { "ab+",
939 O_RDWR | O_CREAT | O_APPEND | O_BINARY },
940 { "a+b",
941 O_RDWR | O_CREAT | O_APPEND | O_BINARY }
943 unsigned int i;
944 int err;
946 for (i = 0; i < DIM (mode_flags); i++)
947 if (! strcmp (mode_flags[i].mode, mode))
948 break;
949 if (i == DIM (mode_flags))
951 errno = EINVAL;
952 err = -1;
954 else
956 err = 0;
957 *modeflags = mode_flags[i].flags;
960 return err;
966 * Low level stream functionality.
969 static int
970 es_fill (estream_t stream)
972 size_t bytes_read = 0;
973 int err;
975 if (!stream->intern->func_read)
977 errno = EOPNOTSUPP;
978 err = -1;
980 else
982 es_cookie_read_function_t func_read = stream->intern->func_read;
983 ssize_t ret;
985 ret = (*func_read) (stream->intern->cookie,
986 stream->buffer, stream->buffer_size);
987 if (ret == -1)
989 bytes_read = 0;
990 err = -1;
992 else
994 bytes_read = ret;
995 err = 0;
999 if (err)
1000 stream->intern->indicators.err = 1;
1001 else if (!bytes_read)
1002 stream->intern->indicators.eof = 1;
1004 stream->intern->offset += stream->data_len;
1005 stream->data_len = bytes_read;
1006 stream->data_offset = 0;
1008 return err;
1011 static int
1012 es_flush (estream_t stream)
1014 es_cookie_write_function_t func_write = stream->intern->func_write;
1015 int err;
1017 assert (stream->flags.writing);
1019 if (stream->data_offset)
1021 size_t bytes_written;
1022 size_t data_flushed;
1023 ssize_t ret;
1025 if (! func_write)
1027 err = EOPNOTSUPP;
1028 goto out;
1031 /* Note: to prevent an endless loop caused by user-provided
1032 write-functions that pretend to have written more bytes than
1033 they were asked to write, we have to check for
1034 "(stream->data_offset - data_flushed) > 0" instead of
1035 "stream->data_offset - data_flushed". */
1037 data_flushed = 0;
1038 err = 0;
1040 while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
1042 ret = (*func_write) (stream->intern->cookie,
1043 stream->buffer + data_flushed,
1044 stream->data_offset - data_flushed);
1045 if (ret == -1)
1047 bytes_written = 0;
1048 err = -1;
1050 else
1051 bytes_written = ret;
1053 data_flushed += bytes_written;
1054 if (err)
1055 break;
1058 stream->data_flushed += data_flushed;
1059 if (stream->data_offset == data_flushed)
1061 stream->intern->offset += stream->data_offset;
1062 stream->data_offset = 0;
1063 stream->data_flushed = 0;
1065 /* Propagate flush event. */
1066 (*func_write) (stream->intern->cookie, NULL, 0);
1069 else
1070 err = 0;
1072 out:
1074 if (err)
1075 stream->intern->indicators.err = 1;
1077 return err;
1080 /* Discard buffered data for STREAM. */
1081 static void
1082 es_empty (estream_t stream)
1084 assert (!stream->flags.writing);
1085 stream->data_len = 0;
1086 stream->data_offset = 0;
1087 stream->unread_data_len = 0;
1090 /* Initialize STREAM. */
1091 static void
1092 es_initialize (estream_t stream,
1093 void *cookie, int fd, es_cookie_io_functions_t functions,
1094 unsigned int modeflags)
1096 stream->intern->cookie = cookie;
1097 stream->intern->opaque = NULL;
1098 stream->intern->offset = 0;
1099 stream->intern->func_read = functions.func_read;
1100 stream->intern->func_write = functions.func_write;
1101 stream->intern->func_seek = functions.func_seek;
1102 stream->intern->func_close = functions.func_close;
1103 stream->intern->strategy = _IOFBF;
1104 stream->intern->fd = fd;
1105 stream->intern->print_err = 0;
1106 stream->intern->print_errno = 0;
1107 stream->intern->print_ntotal = 0;
1108 stream->intern->print_fp = NULL;
1109 stream->intern->indicators.err = 0;
1110 stream->intern->indicators.eof = 0;
1111 stream->intern->deallocate_buffer = 0;
1113 stream->data_len = 0;
1114 stream->data_offset = 0;
1115 stream->data_flushed = 0;
1116 stream->unread_data_len = 0;
1117 /* Depending on the modeflags we set whether we start in writing or
1118 reading mode. This is required in case we are working on a
1119 wronly stream which is not seeekable (like stdout). Without this
1120 pre-initialization we would do a seek at the first write call and
1121 as this will fail no utput will be delivered. */
1122 if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1123 stream->flags.writing = 1;
1124 else
1125 stream->flags.writing = 0;
1128 /* Deinitialize STREAM. */
1129 static int
1130 es_deinitialize (estream_t stream)
1132 es_cookie_close_function_t func_close;
1133 int err, tmp_err;
1135 if (stream->intern->print_fp)
1137 int save_errno = errno;
1138 fclose (stream->intern->print_fp);
1139 stream->intern->print_fp = NULL;
1140 errno = save_errno;
1143 func_close = stream->intern->func_close;
1145 err = 0;
1146 if (stream->flags.writing)
1147 SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1148 if (func_close)
1149 SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1152 return err;
1155 /* Create a new stream object, initialize it. */
1156 static int
1157 es_create (estream_t *stream, void *cookie, int fd,
1158 es_cookie_io_functions_t functions, unsigned int modeflags)
1160 estream_internal_t stream_internal_new;
1161 estream_t stream_new;
1162 int err;
1164 stream_new = NULL;
1165 stream_internal_new = NULL;
1167 stream_new = mem_alloc (sizeof (*stream_new));
1168 if (! stream_new)
1170 err = -1;
1171 goto out;
1174 stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
1175 if (! stream_internal_new)
1177 err = -1;
1178 goto out;
1181 stream_new->buffer = stream_internal_new->buffer;
1182 stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1183 stream_new->unread_buffer = stream_internal_new->unread_buffer;
1184 stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1185 stream_new->intern = stream_internal_new;
1187 ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
1188 es_initialize (stream_new, cookie, fd, functions, modeflags);
1190 err = es_list_add (stream_new);
1191 if (err)
1192 goto out;
1194 *stream = stream_new;
1196 out:
1198 if (err)
1200 if (stream_new)
1202 es_deinitialize (stream_new);
1203 mem_free (stream_new);
1207 return err;
1210 /* Deinitialize a stream object and destroy it. */
1211 static int
1212 es_destroy (estream_t stream)
1214 int err = 0;
1216 if (stream)
1218 es_list_remove (stream);
1219 err = es_deinitialize (stream);
1220 mem_free (stream->intern);
1221 mem_free (stream);
1224 return err;
1227 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1228 unbuffered-mode, storing the amount of bytes read in
1229 *BYTES_READ. */
1230 static int
1231 es_read_nbf (estream_t ES__RESTRICT stream,
1232 unsigned char *ES__RESTRICT buffer,
1233 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1235 es_cookie_read_function_t func_read = stream->intern->func_read;
1236 size_t data_read;
1237 ssize_t ret;
1238 int err;
1240 data_read = 0;
1241 err = 0;
1243 while (bytes_to_read - data_read)
1245 ret = (*func_read) (stream->intern->cookie,
1246 buffer + data_read, bytes_to_read - data_read);
1247 if (ret == -1)
1249 err = -1;
1250 break;
1252 else if (ret)
1253 data_read += ret;
1254 else
1255 break;
1258 stream->intern->offset += data_read;
1259 *bytes_read = data_read;
1261 return err;
1264 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1265 fully-buffered-mode, storing the amount of bytes read in
1266 *BYTES_READ. */
1267 static int
1268 es_read_fbf (estream_t ES__RESTRICT stream,
1269 unsigned char *ES__RESTRICT buffer,
1270 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1272 size_t data_available;
1273 size_t data_to_read;
1274 size_t data_read;
1275 int err;
1277 data_read = 0;
1278 err = 0;
1280 while ((bytes_to_read - data_read) && (! err))
1282 if (stream->data_offset == stream->data_len)
1284 /* Nothing more to read in current container, try to
1285 fill container with new data. */
1286 err = es_fill (stream);
1287 if (! err)
1288 if (! stream->data_len)
1289 /* Filling did not result in any data read. */
1290 break;
1293 if (! err)
1295 /* Filling resulted in some new data. */
1297 data_to_read = bytes_to_read - data_read;
1298 data_available = stream->data_len - stream->data_offset;
1299 if (data_to_read > data_available)
1300 data_to_read = data_available;
1302 memcpy (buffer + data_read,
1303 stream->buffer + stream->data_offset, data_to_read);
1304 stream->data_offset += data_to_read;
1305 data_read += data_to_read;
1309 *bytes_read = data_read;
1311 return err;
1314 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1315 line-buffered-mode, storing the amount of bytes read in
1316 *BYTES_READ. */
1317 static int
1318 es_read_lbf (estream_t ES__RESTRICT stream,
1319 unsigned char *ES__RESTRICT buffer,
1320 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1322 int err;
1324 err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1326 return err;
1329 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1330 *the amount of bytes read in BYTES_READ. */
1331 static int
1332 es_readn (estream_t ES__RESTRICT stream,
1333 void *ES__RESTRICT buffer_arg,
1334 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1336 unsigned char *buffer = (unsigned char *)buffer_arg;
1337 size_t data_read_unread, data_read;
1338 int err;
1340 data_read_unread = 0;
1341 data_read = 0;
1342 err = 0;
1344 if (stream->flags.writing)
1346 /* Switching to reading mode -> flush output. */
1347 err = es_flush (stream);
1348 if (err)
1349 goto out;
1350 stream->flags.writing = 0;
1353 /* Read unread data first. */
1354 while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1356 buffer[data_read_unread]
1357 = stream->unread_buffer[stream->unread_data_len - 1];
1358 stream->unread_data_len--;
1359 data_read_unread++;
1362 switch (stream->intern->strategy)
1364 case _IONBF:
1365 err = es_read_nbf (stream,
1366 buffer + data_read_unread,
1367 bytes_to_read - data_read_unread, &data_read);
1368 break;
1369 case _IOLBF:
1370 err = es_read_lbf (stream,
1371 buffer + data_read_unread,
1372 bytes_to_read - data_read_unread, &data_read);
1373 break;
1374 case _IOFBF:
1375 err = es_read_fbf (stream,
1376 buffer + data_read_unread,
1377 bytes_to_read - data_read_unread, &data_read);
1378 break;
1381 out:
1383 if (bytes_read)
1384 *bytes_read = data_read_unread + data_read;
1386 return err;
1389 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1390 amount of bytes succesfully unread in *BYTES_UNREAD. */
1391 static void
1392 es_unreadn (estream_t ES__RESTRICT stream,
1393 const unsigned char *ES__RESTRICT data, size_t data_n,
1394 size_t *ES__RESTRICT bytes_unread)
1396 size_t space_left;
1398 space_left = stream->unread_buffer_size - stream->unread_data_len;
1400 if (data_n > space_left)
1401 data_n = space_left;
1403 if (! data_n)
1404 goto out;
1406 memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1407 stream->unread_data_len += data_n;
1408 stream->intern->indicators.eof = 0;
1410 out:
1412 if (bytes_unread)
1413 *bytes_unread = data_n;
1416 /* Seek in STREAM. */
1417 static int
1418 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1419 off_t *ES__RESTRICT offset_new)
1421 es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1422 int err, ret;
1423 off_t off;
1425 if (! func_seek)
1427 errno = EOPNOTSUPP;
1428 err = -1;
1429 goto out;
1432 if (stream->flags.writing)
1434 /* Flush data first in order to prevent flushing it to the wrong
1435 offset. */
1436 err = es_flush (stream);
1437 if (err)
1438 goto out;
1439 stream->flags.writing = 0;
1442 off = offset;
1443 if (whence == SEEK_CUR)
1445 off = off - stream->data_len + stream->data_offset;
1446 off -= stream->unread_data_len;
1449 ret = (*func_seek) (stream->intern->cookie, &off, whence);
1450 if (ret == -1)
1452 err = -1;
1453 goto out;
1456 err = 0;
1457 es_empty (stream);
1459 if (offset_new)
1460 *offset_new = off;
1462 stream->intern->indicators.eof = 0;
1463 stream->intern->offset = off;
1465 out:
1467 if (err)
1468 stream->intern->indicators.err = 1;
1470 return err;
1473 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1474 unbuffered-mode, storing the amount of bytes written in
1475 *BYTES_WRITTEN. */
1476 static int
1477 es_write_nbf (estream_t ES__RESTRICT stream,
1478 const unsigned char *ES__RESTRICT buffer,
1479 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1481 es_cookie_write_function_t func_write = stream->intern->func_write;
1482 size_t data_written;
1483 ssize_t ret;
1484 int err;
1486 if (bytes_to_write && (! func_write))
1488 err = EOPNOTSUPP;
1489 goto out;
1492 data_written = 0;
1493 err = 0;
1495 while (bytes_to_write - data_written)
1497 ret = (*func_write) (stream->intern->cookie,
1498 buffer + data_written,
1499 bytes_to_write - data_written);
1500 if (ret == -1)
1502 err = -1;
1503 break;
1505 else
1506 data_written += ret;
1509 stream->intern->offset += data_written;
1510 *bytes_written = data_written;
1512 out:
1514 return err;
1517 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1518 fully-buffered-mode, storing the amount of bytes written in
1519 *BYTES_WRITTEN. */
1520 static int
1521 es_write_fbf (estream_t ES__RESTRICT stream,
1522 const unsigned char *ES__RESTRICT buffer,
1523 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1525 size_t space_available;
1526 size_t data_to_write;
1527 size_t data_written;
1528 int err;
1530 data_written = 0;
1531 err = 0;
1533 while ((bytes_to_write - data_written) && (! err))
1535 if (stream->data_offset == stream->buffer_size)
1536 /* Container full, flush buffer. */
1537 err = es_flush (stream);
1539 if (! err)
1541 /* Flushing resulted in empty container. */
1543 data_to_write = bytes_to_write - data_written;
1544 space_available = stream->buffer_size - stream->data_offset;
1545 if (data_to_write > space_available)
1546 data_to_write = space_available;
1548 memcpy (stream->buffer + stream->data_offset,
1549 buffer + data_written, data_to_write);
1550 stream->data_offset += data_to_write;
1551 data_written += data_to_write;
1555 *bytes_written = data_written;
1557 return err;
1561 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1562 line-buffered-mode, storing the amount of bytes written in
1563 *BYTES_WRITTEN. */
1564 static int
1565 es_write_lbf (estream_t ES__RESTRICT stream,
1566 const unsigned char *ES__RESTRICT buffer,
1567 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1569 size_t data_flushed = 0;
1570 size_t data_buffered = 0;
1571 unsigned char *nlp;
1572 int err = 0;
1574 nlp = memrchr (buffer, '\n', bytes_to_write);
1575 if (nlp)
1577 /* Found a newline, directly write up to (including) this
1578 character. */
1579 err = es_flush (stream);
1580 if (!err)
1581 err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1584 if (!err)
1586 /* Write remaining data fully buffered. */
1587 err = es_write_fbf (stream, buffer + data_flushed,
1588 bytes_to_write - data_flushed, &data_buffered);
1591 *bytes_written = data_flushed + data_buffered;
1592 return err;
1596 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1597 amount of bytes written in BYTES_WRITTEN. */
1598 static int
1599 es_writen (estream_t ES__RESTRICT stream,
1600 const void *ES__RESTRICT buffer,
1601 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1603 size_t data_written;
1604 int err;
1606 data_written = 0;
1607 err = 0;
1609 if (!stream->flags.writing)
1611 /* Switching to writing mode -> discard input data and seek to
1612 position at which reading has stopped. We can do this only
1613 if a seek function has been registered. */
1614 if (stream->intern->func_seek)
1616 err = es_seek (stream, 0, SEEK_CUR, NULL);
1617 if (err)
1619 if (errno == ESPIPE)
1620 err = 0;
1621 else
1622 goto out;
1627 switch (stream->intern->strategy)
1629 case _IONBF:
1630 err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1631 break;
1633 case _IOLBF:
1634 err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1635 break;
1637 case _IOFBF:
1638 err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1639 break;
1642 out:
1644 if (bytes_written)
1645 *bytes_written = data_written;
1646 if (data_written)
1647 if (!stream->flags.writing)
1648 stream->flags.writing = 1;
1650 return err;
1654 static int
1655 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1656 size_t *ES__RESTRICT data_len)
1658 int err;
1660 if (stream->flags.writing)
1662 /* Switching to reading mode -> flush output. */
1663 err = es_flush (stream);
1664 if (err)
1665 goto out;
1666 stream->flags.writing = 0;
1669 if (stream->data_offset == stream->data_len)
1671 /* Refill container. */
1672 err = es_fill (stream);
1673 if (err)
1674 goto out;
1677 if (data)
1678 *data = stream->buffer + stream->data_offset;
1679 if (data_len)
1680 *data_len = stream->data_len - stream->data_offset;
1681 err = 0;
1683 out:
1685 return err;
1689 /* Skip SIZE bytes of input data contained in buffer. */
1690 static int
1691 es_skip (estream_t stream, size_t size)
1693 int err;
1695 if (stream->data_offset + size > stream->data_len)
1697 errno = EINVAL;
1698 err = -1;
1700 else
1702 stream->data_offset += size;
1703 err = 0;
1706 return err;
1710 static int
1711 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
1712 char *ES__RESTRICT *ES__RESTRICT line,
1713 size_t *ES__RESTRICT line_length)
1715 size_t space_left;
1716 size_t line_size;
1717 estream_t line_stream;
1718 char *line_new;
1719 void *line_stream_cookie;
1720 char *newline;
1721 unsigned char *data;
1722 size_t data_len;
1723 int err;
1725 line_new = NULL;
1726 line_stream = NULL;
1727 line_stream_cookie = NULL;
1729 err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0,
1730 BUFFER_BLOCK_SIZE, 1,
1731 mem_realloc, mem_free,
1732 O_RDWR,
1734 if (err)
1735 goto out;
1737 err = es_create (&line_stream, line_stream_cookie, -1,
1738 estream_functions_mem, O_RDWR);
1739 if (err)
1740 goto out;
1742 space_left = max_length;
1743 line_size = 0;
1744 while (1)
1746 if (max_length && (space_left == 1))
1747 break;
1749 err = es_peek (stream, &data, &data_len);
1750 if (err || (! data_len))
1751 break;
1753 if (data_len > (space_left - 1))
1754 data_len = space_left - 1;
1756 newline = memchr (data, '\n', data_len);
1757 if (newline)
1759 data_len = (newline - (char *) data) + 1;
1760 err = es_write (line_stream, data, data_len, NULL);
1761 if (! err)
1763 space_left -= data_len;
1764 line_size += data_len;
1765 es_skip (stream, data_len);
1766 break;
1769 else
1771 err = es_write (line_stream, data, data_len, NULL);
1772 if (! err)
1774 space_left -= data_len;
1775 line_size += data_len;
1776 es_skip (stream, data_len);
1779 if (err)
1780 break;
1782 if (err)
1783 goto out;
1785 /* Complete line has been written to line_stream. */
1787 if ((max_length > 1) && (! line_size))
1789 stream->intern->indicators.eof = 1;
1790 goto out;
1793 err = es_seek (line_stream, 0, SEEK_SET, NULL);
1794 if (err)
1795 goto out;
1797 if (! *line)
1799 line_new = mem_alloc (line_size + 1);
1800 if (! line_new)
1802 err = -1;
1803 goto out;
1806 else
1807 line_new = *line;
1809 err = es_read (line_stream, line_new, line_size, NULL);
1810 if (err)
1811 goto out;
1813 line_new[line_size] = '\0';
1815 if (! *line)
1816 *line = line_new;
1817 if (line_length)
1818 *line_length = line_size;
1820 out:
1822 if (line_stream)
1823 es_destroy (line_stream);
1824 else if (line_stream_cookie)
1825 es_func_mem_destroy (line_stream_cookie);
1827 if (err)
1829 if (! *line)
1830 mem_free (line_new);
1831 stream->intern->indicators.err = 1;
1834 return err;
1838 /* Output fucntion used for estream_format. */
1839 static int
1840 print_writer (void *outfncarg, const char *buf, size_t buflen)
1842 estream_t stream = outfncarg;
1843 size_t nwritten;
1844 int rc;
1846 nwritten = 0;
1847 rc = es_writen (stream, buf, buflen, &nwritten);
1848 stream->intern->print_ntotal += nwritten;
1849 return rc;
1853 /* The core of our printf function. This is called in locked state. */
1854 static int
1855 es_print (estream_t ES__RESTRICT stream,
1856 const char *ES__RESTRICT format, va_list ap)
1858 int rc;
1860 stream->intern->print_ntotal = 0;
1861 rc = estream_format (print_writer, stream, format, ap);
1862 if (rc)
1863 return -1;
1864 return (int)stream->intern->print_ntotal;
1868 static void
1869 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1871 if (ind_err != -1)
1872 stream->intern->indicators.err = ind_err ? 1 : 0;
1873 if (ind_eof != -1)
1874 stream->intern->indicators.eof = ind_eof ? 1 : 0;
1878 static int
1879 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1881 int ret = 0;
1883 if (ind_err)
1884 ret = stream->intern->indicators.err;
1885 else if (ind_eof)
1886 ret = stream->intern->indicators.eof;
1888 return ret;
1892 static int
1893 es_set_buffering (estream_t ES__RESTRICT stream,
1894 char *ES__RESTRICT buffer, int mode, size_t size)
1896 int err;
1898 /* Flush or empty buffer depending on mode. */
1899 if (stream->flags.writing)
1901 err = es_flush (stream);
1902 if (err)
1903 goto out;
1905 else
1906 es_empty (stream);
1908 es_set_indicators (stream, -1, 0);
1910 /* Free old buffer in case that was allocated by this function. */
1911 if (stream->intern->deallocate_buffer)
1913 stream->intern->deallocate_buffer = 0;
1914 mem_free (stream->buffer);
1915 stream->buffer = NULL;
1918 if (mode == _IONBF)
1919 stream->buffer_size = 0;
1920 else
1922 void *buffer_new;
1924 if (buffer)
1925 buffer_new = buffer;
1926 else
1928 buffer_new = mem_alloc (size);
1929 if (! buffer_new)
1931 err = -1;
1932 goto out;
1936 stream->buffer = buffer_new;
1937 stream->buffer_size = size;
1938 if (! buffer)
1939 stream->intern->deallocate_buffer = 1;
1941 stream->intern->strategy = mode;
1942 err = 0;
1944 out:
1946 return err;
1950 static off_t
1951 es_offset_calculate (estream_t stream)
1953 off_t offset;
1955 offset = stream->intern->offset + stream->data_offset;
1956 if (offset < stream->unread_data_len)
1957 /* Offset undefined. */
1958 offset = 0;
1959 else
1960 offset -= stream->unread_data_len;
1962 return offset;
1966 static void
1967 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1968 void **ES__RESTRICT opaque_old)
1970 if (opaque_old)
1971 *opaque_old = stream->intern->opaque;
1972 if (opaque_new)
1973 stream->intern->opaque = opaque_new;
1977 static int
1978 es_get_fd (estream_t stream)
1980 return stream->intern->fd;
1985 /* API. */
1988 es_init (void)
1990 int err;
1992 err = es_init_do ();
1994 return err;
1997 estream_t
1998 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
2000 unsigned int modeflags;
2001 int create_called;
2002 estream_t stream;
2003 void *cookie;
2004 int err;
2005 int fd;
2007 stream = NULL;
2008 cookie = NULL;
2009 create_called = 0;
2011 err = es_convert_mode (mode, &modeflags);
2012 if (err)
2013 goto out;
2015 err = es_func_file_create (&cookie, &fd, path, modeflags);
2016 if (err)
2017 goto out;
2019 create_called = 1;
2020 err = es_create (&stream, cookie, fd, estream_functions_file, modeflags);
2021 if (err)
2022 goto out;
2024 out:
2026 if (err && create_called)
2027 (*estream_functions_file.func_close) (cookie);
2029 return stream;
2033 estream_t
2034 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
2035 unsigned int grow,
2036 func_realloc_t func_realloc, func_free_t func_free,
2037 const char *ES__RESTRICT mode)
2039 unsigned int modeflags;
2040 int create_called;
2041 estream_t stream;
2042 void *cookie;
2043 int err;
2045 cookie = 0;
2046 stream = NULL;
2047 create_called = 0;
2049 err = es_convert_mode (mode, &modeflags);
2050 if (err)
2051 goto out;
2053 err = es_func_mem_create (&cookie, data, data_n, data_len,
2054 BUFFER_BLOCK_SIZE, grow,
2055 func_realloc, func_free, modeflags, 0);
2056 if (err)
2057 goto out;
2059 create_called = 1;
2060 err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags);
2062 out:
2064 if (err && create_called)
2065 (*estream_functions_mem.func_close) (cookie);
2067 return stream;
2071 estream_t
2072 es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
2074 unsigned int modeflags;
2075 estream_t stream = NULL;
2076 void *cookie = NULL;
2078 /* Memory streams are always read/write. We use MODE only to get
2079 the append flag. */
2080 if (es_convert_mode (mode, &modeflags))
2081 return NULL;
2082 modeflags |= O_RDWR;
2085 if (es_func_mem_create (&cookie, NULL, 0, 0,
2086 BUFFER_BLOCK_SIZE, 1,
2087 mem_realloc, mem_free, modeflags,
2088 memlimit))
2089 return NULL;
2091 if (es_create (&stream, cookie, -1, estream_functions_mem, modeflags))
2092 (*estream_functions_mem.func_close) (cookie);
2094 return stream;
2099 estream_t
2100 es_fopencookie (void *ES__RESTRICT cookie,
2101 const char *ES__RESTRICT mode,
2102 es_cookie_io_functions_t functions)
2104 unsigned int modeflags;
2105 estream_t stream;
2106 int err;
2108 stream = NULL;
2109 modeflags = 0;
2111 err = es_convert_mode (mode, &modeflags);
2112 if (err)
2113 goto out;
2115 err = es_create (&stream, cookie, -1, functions, modeflags);
2116 if (err)
2117 goto out;
2119 out:
2121 return stream;
2125 estream_t
2126 do_fdopen (int filedes, const char *mode, int no_close)
2128 unsigned int modeflags;
2129 int create_called;
2130 estream_t stream;
2131 void *cookie;
2132 int err;
2134 stream = NULL;
2135 cookie = NULL;
2136 create_called = 0;
2138 err = es_convert_mode (mode, &modeflags);
2139 if (err)
2140 goto out;
2142 err = es_func_fd_create (&cookie, filedes, modeflags, no_close);
2143 if (err)
2144 goto out;
2146 create_called = 1;
2147 err = es_create (&stream, cookie, filedes, estream_functions_fd, modeflags);
2149 out:
2151 if (err && create_called)
2152 (*estream_functions_fd.func_close) (cookie);
2154 return stream;
2157 estream_t
2158 es_fdopen (int filedes, const char *mode)
2160 return do_fdopen (filedes, mode, 0);
2163 /* A variant of es_fdopen which does not close FILEDES at the end. */
2164 estream_t
2165 es_fdopen_nc (int filedes, const char *mode)
2167 return do_fdopen (filedes, mode, 1);
2171 estream_t
2172 do_fpopen (FILE *fp, const char *mode, int no_close)
2174 unsigned int modeflags;
2175 int create_called;
2176 estream_t stream;
2177 void *cookie;
2178 int err;
2180 stream = NULL;
2181 cookie = NULL;
2182 create_called = 0;
2184 err = es_convert_mode (mode, &modeflags);
2185 if (err)
2186 goto out;
2188 fflush (fp);
2189 err = es_func_fp_create (&cookie, fp, modeflags, no_close);
2190 if (err)
2191 goto out;
2193 create_called = 1;
2194 err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
2195 modeflags);
2197 out:
2199 if (err && create_called)
2200 (*estream_functions_fp.func_close) (cookie);
2202 return stream;
2206 /* Create an estream from the stdio stream FP. This mechanism is
2207 useful in case the stdio streams have special properties and may
2208 not be mixed with fd based functions. This is for example the case
2209 under Windows where the 3 standard streams are associated with the
2210 console whereas a duped and fd-opened stream of one of this stream
2211 won't be associated with the console. As this messes things up it
2212 is easier to keep on using the standard I/O stream as a backend for
2213 estream. */
2214 estream_t
2215 es_fpopen (FILE *fp, const char *mode)
2217 return do_fpopen (fp, mode, 0);
2221 /* Same as es_fpopen but does not close FP at the end. */
2222 estream_t
2223 es_fpopen_nc (FILE *fp, const char *mode)
2225 return do_fpopen (fp, mode, 1);
2229 estream_t
2230 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
2231 estream_t ES__RESTRICT stream)
2233 int err;
2235 if (path)
2237 unsigned int modeflags;
2238 int create_called;
2239 void *cookie;
2240 int fd;
2242 cookie = NULL;
2243 create_called = 0;
2245 ESTREAM_LOCK (stream);
2247 es_deinitialize (stream);
2249 err = es_convert_mode (mode, &modeflags);
2250 if (err)
2251 goto leave;
2253 err = es_func_file_create (&cookie, &fd, path, modeflags);
2254 if (err)
2255 goto leave;
2257 create_called = 1;
2258 es_initialize (stream, cookie, fd, estream_functions_file, modeflags);
2260 leave:
2262 if (err)
2264 if (create_called)
2265 es_func_fd_destroy (cookie);
2267 es_destroy (stream);
2268 stream = NULL;
2270 else
2271 ESTREAM_UNLOCK (stream);
2273 else
2275 /* FIXME? We don't support re-opening at the moment. */
2276 errno = EINVAL;
2277 es_deinitialize (stream);
2278 es_destroy (stream);
2279 stream = NULL;
2282 return stream;
2287 es_fclose (estream_t stream)
2289 int err;
2291 err = es_destroy (stream);
2293 return err;
2297 es_fileno_unlocked (estream_t stream)
2299 return es_get_fd (stream);
2303 void
2304 es_flockfile (estream_t stream)
2306 ESTREAM_LOCK (stream);
2311 es_ftrylockfile (estream_t stream)
2313 return ESTREAM_TRYLOCK (stream);
2317 void
2318 es_funlockfile (estream_t stream)
2320 ESTREAM_UNLOCK (stream);
2325 es_fileno (estream_t stream)
2327 int ret;
2329 ESTREAM_LOCK (stream);
2330 ret = es_fileno_unlocked (stream);
2331 ESTREAM_UNLOCK (stream);
2333 return ret;
2338 es_feof_unlocked (estream_t stream)
2340 return es_get_indicator (stream, 0, 1);
2345 es_feof (estream_t stream)
2347 int ret;
2349 ESTREAM_LOCK (stream);
2350 ret = es_feof_unlocked (stream);
2351 ESTREAM_UNLOCK (stream);
2353 return ret;
2358 es_ferror_unlocked (estream_t stream)
2360 return es_get_indicator (stream, 1, 0);
2365 es_ferror (estream_t stream)
2367 int ret;
2369 ESTREAM_LOCK (stream);
2370 ret = es_ferror_unlocked (stream);
2371 ESTREAM_UNLOCK (stream);
2373 return ret;
2377 void
2378 es_clearerr_unlocked (estream_t stream)
2380 es_set_indicators (stream, 0, 0);
2384 void
2385 es_clearerr (estream_t stream)
2387 ESTREAM_LOCK (stream);
2388 es_clearerr_unlocked (stream);
2389 ESTREAM_UNLOCK (stream);
2394 es_fflush (estream_t stream)
2396 int err;
2398 if (stream)
2400 ESTREAM_LOCK (stream);
2401 if (stream->flags.writing)
2402 err = es_flush (stream);
2403 else
2405 es_empty (stream);
2406 err = 0;
2408 ESTREAM_UNLOCK (stream);
2410 else
2411 err = es_list_iterate (es_fflush);
2413 return err ? EOF : 0;
2418 es_fseek (estream_t stream, long int offset, int whence)
2420 int err;
2422 ESTREAM_LOCK (stream);
2423 err = es_seek (stream, offset, whence, NULL);
2424 ESTREAM_UNLOCK (stream);
2426 return err;
2431 es_fseeko (estream_t stream, off_t offset, int whence)
2433 int err;
2435 ESTREAM_LOCK (stream);
2436 err = es_seek (stream, offset, whence, NULL);
2437 ESTREAM_UNLOCK (stream);
2439 return err;
2443 long int
2444 es_ftell (estream_t stream)
2446 long int ret;
2448 ESTREAM_LOCK (stream);
2449 ret = es_offset_calculate (stream);
2450 ESTREAM_UNLOCK (stream);
2452 return ret;
2456 off_t
2457 es_ftello (estream_t stream)
2459 off_t ret = -1;
2461 ESTREAM_LOCK (stream);
2462 ret = es_offset_calculate (stream);
2463 ESTREAM_UNLOCK (stream);
2465 return ret;
2469 void
2470 es_rewind (estream_t stream)
2472 ESTREAM_LOCK (stream);
2473 es_seek (stream, 0L, SEEK_SET, NULL);
2474 es_set_indicators (stream, 0, -1);
2475 ESTREAM_UNLOCK (stream);
2480 _es_getc_underflow (estream_t stream)
2482 int err;
2483 unsigned char c;
2484 size_t bytes_read;
2486 err = es_readn (stream, &c, 1, &bytes_read);
2488 return (err || (! bytes_read)) ? EOF : c;
2493 _es_putc_overflow (int c, estream_t stream)
2495 unsigned char d = c;
2496 int err;
2498 err = es_writen (stream, &d, 1, NULL);
2500 return err ? EOF : c;
2505 es_fgetc (estream_t stream)
2507 int ret;
2509 ESTREAM_LOCK (stream);
2510 ret = es_getc_unlocked (stream);
2511 ESTREAM_UNLOCK (stream);
2513 return ret;
2518 es_fputc (int c, estream_t stream)
2520 int ret;
2522 ESTREAM_LOCK (stream);
2523 ret = es_putc_unlocked (c, stream);
2524 ESTREAM_UNLOCK (stream);
2526 return ret;
2531 es_ungetc (int c, estream_t stream)
2533 unsigned char data = (unsigned char) c;
2534 size_t data_unread;
2536 ESTREAM_LOCK (stream);
2537 es_unreadn (stream, &data, 1, &data_unread);
2538 ESTREAM_UNLOCK (stream);
2540 return data_unread ? c : EOF;
2545 es_read (estream_t ES__RESTRICT stream,
2546 void *ES__RESTRICT buffer, size_t bytes_to_read,
2547 size_t *ES__RESTRICT bytes_read)
2549 int err;
2551 if (bytes_to_read)
2553 ESTREAM_LOCK (stream);
2554 err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2555 ESTREAM_UNLOCK (stream);
2557 else
2558 err = 0;
2560 return err;
2565 es_write (estream_t ES__RESTRICT stream,
2566 const void *ES__RESTRICT buffer, size_t bytes_to_write,
2567 size_t *ES__RESTRICT bytes_written)
2569 int err;
2571 if (bytes_to_write)
2573 ESTREAM_LOCK (stream);
2574 err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2575 ESTREAM_UNLOCK (stream);
2577 else
2578 err = 0;
2580 return err;
2584 size_t
2585 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2586 estream_t ES__RESTRICT stream)
2588 size_t ret, bytes;
2589 int err;
2591 if (size * nitems)
2593 ESTREAM_LOCK (stream);
2594 err = es_readn (stream, ptr, size * nitems, &bytes);
2595 ESTREAM_UNLOCK (stream);
2597 ret = bytes / size;
2599 else
2600 ret = 0;
2602 return ret;
2606 size_t
2607 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2608 estream_t ES__RESTRICT stream)
2610 size_t ret, bytes;
2611 int err;
2613 if (size * nitems)
2615 ESTREAM_LOCK (stream);
2616 err = es_writen (stream, ptr, size * nitems, &bytes);
2617 ESTREAM_UNLOCK (stream);
2619 ret = bytes / size;
2621 else
2622 ret = 0;
2624 return ret;
2628 char *
2629 es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
2631 unsigned char *s = (unsigned char*)buffer;
2632 int c;
2634 if (!length)
2635 return NULL;
2637 c = EOF;
2638 ESTREAM_LOCK (stream);
2639 while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n')
2641 *s++ = c;
2642 length--;
2644 ESTREAM_UNLOCK (stream);
2646 if (c == EOF && s == (unsigned char*)buffer)
2647 return NULL; /* Nothing read. */
2649 if (c != EOF && length > 1)
2650 *s++ = c;
2652 *s = 0;
2653 return buffer;
2658 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2660 size_t length;
2661 int err;
2663 length = strlen (s);
2664 ESTREAM_LOCK (stream);
2665 err = es_writen (stream, s, length, NULL);
2666 ESTREAM_UNLOCK (stream);
2668 return err ? EOF : 0;
2672 ssize_t
2673 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2674 estream_t ES__RESTRICT stream)
2676 char *line = NULL;
2677 size_t line_n = 0;
2678 int err;
2680 ESTREAM_LOCK (stream);
2681 err = doreadline (stream, 0, &line, &line_n);
2682 ESTREAM_UNLOCK (stream);
2683 if (err)
2684 goto out;
2686 if (*n)
2688 /* Caller wants us to use his buffer. */
2690 if (*n < (line_n + 1))
2692 /* Provided buffer is too small -> resize. */
2694 void *p;
2696 p = mem_realloc (*lineptr, line_n + 1);
2697 if (! p)
2698 err = -1;
2699 else
2701 if (*lineptr != p)
2702 *lineptr = p;
2706 if (! err)
2708 memcpy (*lineptr, line, line_n + 1);
2709 if (*n != line_n)
2710 *n = line_n;
2712 mem_free (line);
2714 else
2716 /* Caller wants new buffers. */
2717 *lineptr = line;
2718 *n = line_n;
2721 out:
2723 return err ? err : line_n;
2728 /* Same as fgets() but if the provided buffer is too short a larger
2729 one will be allocated. This is similar to getline. A line is
2730 considered a byte stream ending in a LF.
2732 If MAX_LENGTH is not NULL, it shall point to a value with the
2733 maximum allowed allocation.
2735 Returns the length of the line. EOF is indicated by a line of
2736 length zero. A truncated line is indicated my setting the value at
2737 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2738 memory was enable or another error occurred; ERRNO is then set
2739 accordingly.
2741 If a line has been truncated, the file pointer is moved forward to
2742 the end of the line so that the next read starts with the next
2743 line. Note that MAX_LENGTH must be re-initialzied in this case.
2745 The caller initially needs to provide the address of a variable,
2746 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2747 anymore with the following invocations. LENGTH_OF_BUFFER should be
2748 the address of a variable, initialized to 0, which is also
2749 maintained by this function. Thus, both paramaters should be
2750 considered the state of this function.
2752 Note: The returned buffer is allocated with enough extra space to
2753 allow the caller to append a CR,LF,Nul. The buffer should be
2754 released using es_free.
2756 ssize_t
2757 es_read_line (estream_t stream,
2758 char **addr_of_buffer, size_t *length_of_buffer,
2759 size_t *max_length)
2761 int c;
2762 char *buffer = *addr_of_buffer;
2763 size_t length = *length_of_buffer;
2764 size_t nbytes = 0;
2765 size_t maxlen = max_length? *max_length : 0;
2766 char *p;
2768 if (!buffer)
2770 /* No buffer given - allocate a new one. */
2771 length = 256;
2772 buffer = mem_alloc (length);
2773 *addr_of_buffer = buffer;
2774 if (!buffer)
2776 *length_of_buffer = 0;
2777 if (max_length)
2778 *max_length = 0;
2779 return -1;
2781 *length_of_buffer = length;
2784 if (length < 4)
2786 /* This should never happen. If it does, the function has been
2787 called with wrong arguments. */
2788 errno = EINVAL;
2789 return -1;
2791 length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2793 ESTREAM_LOCK (stream);
2794 p = buffer;
2795 while ((c = es_getc_unlocked (stream)) != EOF)
2797 if (nbytes == length)
2799 /* Enlarge the buffer. */
2800 if (maxlen && length > maxlen)
2802 /* We are beyond our limit: Skip the rest of the line. */
2803 while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
2805 *p++ = '\n'; /* Always append a LF (we reserved some space). */
2806 nbytes++;
2807 if (max_length)
2808 *max_length = 0; /* Indicate truncation. */
2809 break; /* the while loop. */
2811 length += 3; /* Adjust for the reserved bytes. */
2812 length += length < 1024? 256 : 1024;
2813 *addr_of_buffer = mem_realloc (buffer, length);
2814 if (!*addr_of_buffer)
2816 int save_errno = errno;
2817 mem_free (buffer);
2818 *length_of_buffer = *max_length = 0;
2819 ESTREAM_UNLOCK (stream);
2820 errno = save_errno;
2821 return -1;
2823 buffer = *addr_of_buffer;
2824 *length_of_buffer = length;
2825 length -= 3;
2826 p = buffer + nbytes;
2828 *p++ = c;
2829 nbytes++;
2830 if (c == '\n')
2831 break;
2833 *p = 0; /* Make sure the line is a string. */
2834 ESTREAM_UNLOCK (stream);
2836 return nbytes;
2839 /* Wrapper around free() to match the memory allocation system used
2840 by estream. Should be used for all buffers returned to the caller
2841 by libestream. */
2842 void
2843 es_free (void *a)
2845 mem_free (a);
2850 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2851 va_list ap)
2853 int ret;
2855 ESTREAM_LOCK (stream);
2856 ret = es_print (stream, format, ap);
2857 ESTREAM_UNLOCK (stream);
2859 return ret;
2863 static int
2864 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
2865 const char *ES__RESTRICT format, ...)
2867 int ret;
2869 va_list ap;
2870 va_start (ap, format);
2871 ret = es_print (stream, format, ap);
2872 va_end (ap);
2874 return ret;
2879 es_fprintf (estream_t ES__RESTRICT stream,
2880 const char *ES__RESTRICT format, ...)
2882 int ret;
2884 va_list ap;
2885 va_start (ap, format);
2886 ESTREAM_LOCK (stream);
2887 ret = es_print (stream, format, ap);
2888 ESTREAM_UNLOCK (stream);
2889 va_end (ap);
2891 return ret;
2895 static int
2896 tmpfd (void)
2898 #ifdef HAVE_W32_SYSTEM
2899 int attempts, n;
2900 char buffer[MAX_PATH+9+12+1];
2901 char *name, *p;
2902 HANDLE file;
2903 int pid = GetCurrentProcessId ();
2904 unsigned int value;
2905 int i;
2907 n = GetTempPath (MAX_PATH+1, buffer);
2908 if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
2910 errno = ENOENT;
2911 return -1;
2913 p = buffer + strlen (buffer);
2914 strcpy (p, "_estream");
2915 p += 8;
2916 /* We try to create the directory but don't care about an error as
2917 it may already exist and the CreateFile would throw an error
2918 anyway. */
2919 CreateDirectory (buffer, NULL);
2920 *p++ = '\\';
2921 name = p;
2922 for (attempts=0; attempts < 10; attempts++)
2924 p = name;
2925 value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
2926 for (i=0; i < 8; i++)
2928 *p++ = tohex (((value >> 28) & 0x0f));
2929 value <<= 4;
2931 strcpy (p, ".tmp");
2932 file = CreateFile (buffer,
2933 GENERIC_READ | GENERIC_WRITE,
2935 NULL,
2936 CREATE_NEW,
2937 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
2938 NULL);
2939 if (file != INVALID_HANDLE_VALUE)
2941 int fd = _open_osfhandle ((long)file, 0);
2942 if (fd == -1)
2944 CloseHandle (file);
2945 return -1;
2947 return fd;
2949 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
2951 errno = ENOENT;
2952 return -1;
2953 #else /*!HAVE_W32_SYSTEM*/
2954 FILE *fp;
2955 int fp_fd;
2956 int fd;
2958 fp = NULL;
2959 fd = -1;
2961 fp = tmpfile ();
2962 if (! fp)
2963 goto out;
2965 fp_fd = fileno (fp);
2966 fd = dup (fp_fd);
2968 out:
2970 if (fp)
2971 fclose (fp);
2973 return fd;
2974 #endif /*!HAVE_W32_SYSTEM*/
2977 estream_t
2978 es_tmpfile (void)
2980 unsigned int modeflags;
2981 int create_called;
2982 estream_t stream;
2983 void *cookie;
2984 int err;
2985 int fd;
2987 create_called = 0;
2988 stream = NULL;
2989 modeflags = O_RDWR | O_TRUNC | O_CREAT;
2990 cookie = NULL;
2992 fd = tmpfd ();
2993 if (fd == -1)
2995 err = -1;
2996 goto out;
2999 err = es_func_fd_create (&cookie, fd, modeflags, 0);
3000 if (err)
3001 goto out;
3003 create_called = 1;
3004 err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags);
3006 out:
3008 if (err)
3010 if (create_called)
3011 es_func_fd_destroy (cookie);
3012 else if (fd != -1)
3013 close (fd);
3014 stream = NULL;
3017 return stream;
3022 es_setvbuf (estream_t ES__RESTRICT stream,
3023 char *ES__RESTRICT buf, int type, size_t size)
3025 int err;
3027 if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
3028 && (! ((! size) && (type != _IONBF))))
3030 ESTREAM_LOCK (stream);
3031 err = es_set_buffering (stream, buf, type, size);
3032 ESTREAM_UNLOCK (stream);
3034 else
3036 errno = EINVAL;
3037 err = -1;
3040 return err;
3044 void
3045 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
3047 ESTREAM_LOCK (stream);
3048 es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3049 ESTREAM_UNLOCK (stream);
3052 void
3053 es_opaque_set (estream_t stream, void *opaque)
3055 ESTREAM_LOCK (stream);
3056 es_opaque_ctrl (stream, opaque, NULL);
3057 ESTREAM_UNLOCK (stream);
3061 void *
3062 es_opaque_get (estream_t stream)
3064 void *opaque;
3066 ESTREAM_LOCK (stream);
3067 es_opaque_ctrl (stream, NULL, &opaque);
3068 ESTREAM_UNLOCK (stream);
3070 return opaque;
3073 /* Print a BUFFER to STREAM while replacing all control characters and
3074 the characters in DELIMITERS by standard C escape sequences.
3075 Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
3076 the number of bytes actually written are stored at this
3077 address. */
3078 int
3079 es_write_sanitized (estream_t ES__RESTRICT stream,
3080 const void * ES__RESTRICT buffer, size_t length,
3081 const char * delimiters,
3082 size_t * ES__RESTRICT bytes_written)
3084 const unsigned char *p = buffer;
3085 size_t count = 0;
3086 int ret;
3088 ESTREAM_LOCK (stream);
3089 for (; length; length--, p++, count++)
3091 if (*p < 0x20
3092 || *p == 0x7f
3093 || (delimiters
3094 && (strchr (delimiters, *p) || *p == '\\')))
3096 es_putc_unlocked ('\\', stream);
3097 count++;
3098 if (*p == '\n')
3100 es_putc_unlocked ('n', stream);
3101 count++;
3103 else if (*p == '\r')
3105 es_putc_unlocked ('r', stream);
3106 count++;
3108 else if (*p == '\f')
3110 es_putc_unlocked ('f', stream);
3111 count++;
3113 else if (*p == '\v')
3115 es_putc_unlocked ('v', stream);
3116 count++;
3118 else if (*p == '\b')
3120 es_putc_unlocked ('b', stream);
3121 count++;
3123 else if (!*p)
3125 es_putc_unlocked('0', stream);
3126 count++;
3128 else
3130 es_fprintf_unlocked (stream, "x%02x", *p);
3131 count += 3;
3134 else
3136 es_putc_unlocked (*p, stream);
3137 count++;
3141 if (bytes_written)
3142 *bytes_written = count;
3143 ret = es_ferror_unlocked (stream)? -1 : 0;
3144 ESTREAM_UNLOCK (stream);
3146 return ret;
3150 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3151 RESERVED must be 0. Returns 0 on success or -1 on error. If
3152 BYTES_WRITTEN is not NULL the number of bytes actually written are
3153 stored at this address. */
3155 es_write_hexstring (estream_t ES__RESTRICT stream,
3156 const void *ES__RESTRICT buffer, size_t length,
3157 int reserved, size_t *ES__RESTRICT bytes_written )
3159 int ret;
3160 const unsigned char *s;
3161 size_t count = 0;
3163 (void)reserved;
3165 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3167 if (!length)
3168 return 0;
3170 ESTREAM_LOCK (stream);
3172 for (s = buffer; length; s++, length--)
3174 es_putc_unlocked ( tohex ((*s>>4)&15), stream);
3175 es_putc_unlocked ( tohex (*s&15), stream);
3176 count += 2;
3179 if (bytes_written)
3180 *bytes_written = count;
3181 ret = es_ferror_unlocked (stream)? -1 : 0;
3183 ESTREAM_UNLOCK (stream);
3185 return ret;
3187 #undef tohex
3192 #ifdef GNUPG_MAJOR_VERSION
3193 /* Special estream function to print an UTF8 string in the native
3194 encoding. The interface is the same as es_write_sanitized, however
3195 only one delimiter may be supported.
3197 THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3199 es_write_sanitized_utf8_buffer (estream_t stream,
3200 const void *buffer, size_t length,
3201 const char *delimiters, size_t *bytes_written)
3203 const char *p = buffer;
3204 size_t i;
3206 /* We can handle plain ascii simpler, so check for it first. */
3207 for (i=0; i < length; i++ )
3209 if ( (p[i] & 0x80) )
3210 break;
3212 if (i < length)
3214 int delim = delimiters? *delimiters : 0;
3215 char *buf;
3216 int ret;
3218 /*(utf8 conversion already does the control character quoting). */
3219 buf = utf8_to_native (p, length, delim);
3220 if (bytes_written)
3221 *bytes_written = strlen (buf);
3222 ret = es_fputs (buf, stream);
3223 xfree (buf);
3224 return i;
3226 else
3227 return es_write_sanitized (stream, p, length, delimiters, bytes_written);
3229 #endif /*GNUPG_MAJOR_VERSION*/