2008-02-01 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / estream.c
blobe712e85cd38c2c942a291b94caac0823024ad0de
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;
117 # define ESTREAM_MUTEX_INITIALIZER NULL
118 # define ESTREAM_MUTEX_LOCK(mutex) (void) 0
119 # define ESTREAM_MUTEX_UNLOCK(mutex) (void) 0
120 # define ESTREAM_MUTEX_TRYLOCK(mutex) 0
121 # define ESTREAM_MUTEX_INITIALIZE(mutex) (void) 0
122 #endif
124 /* Primitive system I/O. */
126 #ifdef HAVE_PTH
127 # define ESTREAM_SYS_READ pth_read
128 # define ESTREAM_SYS_WRITE pth_write
129 #else
130 # define ESTREAM_SYS_READ read
131 # define ESTREAM_SYS_WRITE write
132 #endif
134 /* Misc definitions. */
136 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
138 /* An internal stream object. */
140 struct estream_internal
142 unsigned char buffer[BUFFER_BLOCK_SIZE];
143 unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
144 estream_mutex_t lock; /* Lock. */
145 void *cookie; /* Cookie. */
146 void *opaque; /* Opaque data. */
147 unsigned int modeflags; /* Flags for the backend. */
148 off_t offset;
149 es_cookie_read_function_t func_read;
150 es_cookie_write_function_t func_write;
151 es_cookie_seek_function_t func_seek;
152 es_cookie_close_function_t func_close;
153 int strategy;
154 int fd;
155 struct
157 unsigned int err: 1;
158 unsigned int eof: 1;
159 } indicators;
160 unsigned int deallocate_buffer: 1;
161 unsigned int print_err: 1; /* Error in print_fun_writer. */
162 int print_errno; /* Errno from print_fun_writer. */
163 size_t print_ntotal; /* Bytes written from in print_fun_writer. */
164 FILE *print_fp; /* Stdio stream used by print_fun_writer. */
168 typedef struct estream_internal *estream_internal_t;
170 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
171 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
172 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
174 /* Stream list. */
176 typedef struct estream_list *estream_list_t;
178 struct estream_list
180 estream_t car;
181 estream_list_t cdr;
182 estream_list_t *prev_cdr;
185 static estream_list_t estream_list;
186 #ifdef HAVE_PTH
187 /* Note that we can't use a static initialization with W32Pth, thus we
188 do it in es_init. */
189 static estream_mutex_t estream_list_lock;
190 #endif
192 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
193 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
195 #ifndef EOPNOTSUPP
196 # define EOPNOTSUPP ENOSYS
197 #endif
202 /* Macros. */
204 /* Calculate array dimension. */
205 #ifndef DIM
206 #define DIM(array) (sizeof (array) / sizeof (*array))
207 #endif
209 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
212 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
213 VARIABLE is zero. */
214 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
215 do \
217 tmp_variable = expression; \
218 if ((! variable) && tmp_variable) \
219 variable = tmp_variable; \
221 while (0)
224 /* Malloc wrappers to overcvome problems on some older OSes. */
225 static void *
226 mem_alloc (size_t n)
228 if (!n)
229 n++;
230 return malloc (n);
233 static void *
234 mem_realloc (void *p, size_t n)
236 if (!p)
237 return mem_alloc (n);
238 return realloc (p, n);
241 static void
242 mem_free (void *p)
244 if (p)
245 free (p);
251 * List manipulation.
254 /* Add STREAM to the list of registered stream objects. */
255 static int
256 es_list_add (estream_t stream)
258 estream_list_t list_obj;
259 int ret;
261 list_obj = mem_alloc (sizeof (*list_obj));
262 if (! list_obj)
263 ret = -1;
264 else
266 ESTREAM_LIST_LOCK;
267 list_obj->car = stream;
268 list_obj->cdr = estream_list;
269 list_obj->prev_cdr = &estream_list;
270 if (estream_list)
271 estream_list->prev_cdr = &list_obj->cdr;
272 estream_list = list_obj;
273 ESTREAM_LIST_UNLOCK;
274 ret = 0;
277 return ret;
280 /* Remove STREAM from the list of registered stream objects. */
281 static void
282 es_list_remove (estream_t stream)
284 estream_list_t list_obj;
286 ESTREAM_LIST_LOCK;
287 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
288 if (list_obj->car == stream)
290 *list_obj->prev_cdr = list_obj->cdr;
291 if (list_obj->cdr)
292 list_obj->cdr->prev_cdr = list_obj->prev_cdr;
293 mem_free (list_obj);
294 break;
296 ESTREAM_LIST_UNLOCK;
299 /* Type of an stream-iterator-function. */
300 typedef int (*estream_iterator_t) (estream_t stream);
302 /* Iterate over list of registered streams, calling ITERATOR for each
303 of them. */
304 static int
305 es_list_iterate (estream_iterator_t iterator)
307 estream_list_t list_obj;
308 int ret = 0;
310 ESTREAM_LIST_LOCK;
311 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
312 ret |= (*iterator) (list_obj->car);
313 ESTREAM_LIST_UNLOCK;
315 return ret;
321 * Initialization.
324 static int
325 es_init_do (void)
327 #ifdef HAVE_PTH
328 static int initialized;
330 if (!initialized)
332 if (!pth_init () && errno != EPERM )
333 return -1;
334 if (pth_mutex_init (&estream_list_lock))
335 initialized = 1;
337 #endif
338 return 0;
344 * I/O methods.
347 /* Implementation of Memory I/O. */
349 /* Cookie for memory objects. */
350 typedef struct estream_cookie_mem
352 unsigned int modeflags; /* Open flags. */
353 unsigned char *memory; /* Allocated data buffer. */
354 size_t memory_size; /* Allocated size of memory. */
355 size_t memory_limit; /* Maximum allowed allocation size or
356 0 for no limit. */
357 size_t offset; /* Current offset in MEMORY. */
358 size_t data_len; /* Length of data in MEMORY. */
359 size_t block_size; /* Block size. */
360 struct {
361 unsigned int grow: 1; /* MEMORY is allowed to grow. */
362 } flags;
363 func_realloc_t func_realloc;
364 func_free_t func_free;
365 } *estream_cookie_mem_t;
368 /* Create function for memory objects. */
369 static int
370 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
371 unsigned char *ES__RESTRICT data, size_t data_n,
372 size_t data_len,
373 size_t block_size, unsigned int grow,
374 func_realloc_t func_realloc, func_free_t func_free,
375 unsigned int modeflags,
376 size_t memory_limit)
378 estream_cookie_mem_t mem_cookie;
379 int err;
381 mem_cookie = mem_alloc (sizeof (*mem_cookie));
382 if (!mem_cookie)
383 err = -1;
384 else
386 mem_cookie->modeflags = modeflags;
387 mem_cookie->memory = data;
388 mem_cookie->memory_size = data_n;
389 mem_cookie->memory_limit = memory_limit;
390 mem_cookie->offset = 0;
391 mem_cookie->data_len = data_len;
392 mem_cookie->block_size = block_size;
393 mem_cookie->flags.grow = !!grow;
394 mem_cookie->func_realloc = func_realloc ? func_realloc : mem_realloc;
395 mem_cookie->func_free = func_free ? func_free : mem_free;
396 *cookie = mem_cookie;
397 err = 0;
400 return err;
404 /* Read function for memory objects. */
405 static ssize_t
406 es_func_mem_read (void *cookie, void *buffer, size_t size)
408 estream_cookie_mem_t mem_cookie = cookie;
409 ssize_t ret;
411 if (size > mem_cookie->data_len - mem_cookie->offset)
412 size = mem_cookie->data_len - mem_cookie->offset;
414 if (size)
416 memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
417 mem_cookie->offset += size;
420 ret = size;
421 return ret;
425 /* Write function for memory objects. */
426 static ssize_t
427 es_func_mem_write (void *cookie, const void *buffer, size_t size)
429 estream_cookie_mem_t mem_cookie = cookie;
430 ssize_t ret;
432 if (!size)
433 return 0; /* A flush is a NOP for memory objects. */
435 if (mem_cookie->modeflags & O_APPEND)
437 /* Append to data. */
438 mem_cookie->offset = mem_cookie->data_len;
441 if (!mem_cookie->flags.grow)
443 /* We are not alloew to grow, thus limit the size to the left
444 space. FIXME: Does the grow flag an its semtics make sense
445 at all? */
446 if (size > mem_cookie->memory_size - mem_cookie->offset)
447 size = mem_cookie->memory_size - mem_cookie->offset;
450 if (size > (mem_cookie->memory_size - mem_cookie->offset))
452 unsigned char *newbuf;
453 size_t newsize;
455 newsize = mem_cookie->memory_size + mem_cookie->block_size;
457 newsize = mem_cookie->offset + size;
458 if (newsize < mem_cookie->offset)
460 errno = EINVAL;
461 return -1;
463 newsize += mem_cookie->block_size - 1;
464 if (newsize < mem_cookie->offset)
466 errno = EINVAL;
467 return -1;
469 newsize /= mem_cookie->block_size;
470 newsize *= mem_cookie->block_size;
472 if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
474 errno = ENOSPC;
475 return -1;
478 newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
479 if (!newbuf)
480 return -1;
482 mem_cookie->memory = newbuf;
483 mem_cookie->memory_size = newsize;
485 assert (!(size > (mem_cookie->memory_size - mem_cookie->offset)));
488 memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
489 if (mem_cookie->offset + size > mem_cookie->data_len)
490 mem_cookie->data_len = mem_cookie->offset + size;
491 mem_cookie->offset += size;
493 ret = size;
494 return ret;
498 /* Seek function for memory objects. */
499 static int
500 es_func_mem_seek (void *cookie, off_t *offset, int whence)
502 estream_cookie_mem_t mem_cookie = cookie;
503 off_t pos_new;
505 switch (whence)
507 case SEEK_SET:
508 pos_new = *offset;
509 break;
511 case SEEK_CUR:
512 pos_new = mem_cookie->offset += *offset;
513 break;
515 case SEEK_END:
516 pos_new = mem_cookie->data_len += *offset;
517 break;
519 default:
520 errno = EINVAL;
521 return -1;
524 if (pos_new > mem_cookie->memory_size)
526 size_t newsize;
527 void *newbuf;
529 if (!mem_cookie->flags.grow)
531 errno = ENOSPC;
532 return -1;
536 newsize = pos_new + mem_cookie->block_size - 1;
537 if (newsize < pos_new)
539 errno = EINVAL;
540 return -1;
542 newsize /= mem_cookie->block_size;
543 newsize *= mem_cookie->block_size;
544 if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
546 errno = ENOSPC;
547 return -1;
550 newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
551 if (!newbuf)
552 return -1;
554 mem_cookie->memory = newbuf;
555 mem_cookie->memory_size = newsize;
558 if (pos_new > mem_cookie->data_len)
560 /* Fill spare space with zeroes. */
561 memset (mem_cookie->memory + mem_cookie->data_len,
562 0, pos_new - mem_cookie->data_len);
563 mem_cookie->data_len = pos_new;
566 mem_cookie->offset = pos_new;
567 *offset = pos_new;
569 return 0;
573 /* Destroy function for memory objects. */
574 static int
575 es_func_mem_destroy (void *cookie)
577 estream_cookie_mem_t mem_cookie = cookie;
579 if (cookie)
581 mem_cookie->func_free (mem_cookie->memory);
582 mem_free (mem_cookie);
584 return 0;
588 static es_cookie_io_functions_t estream_functions_mem =
590 es_func_mem_read,
591 es_func_mem_write,
592 es_func_mem_seek,
593 es_func_mem_destroy
598 /* Implementation of fd I/O. */
600 /* Cookie for fd objects. */
601 typedef struct estream_cookie_fd
603 int fd; /* The file descriptor we are using for actual output. */
604 int no_close; /* If set we won't close the file descriptor. */
605 } *estream_cookie_fd_t;
607 /* Create function for fd objects. */
608 static int
609 es_func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
611 estream_cookie_fd_t fd_cookie;
612 int err;
614 fd_cookie = mem_alloc (sizeof (*fd_cookie));
615 if (! fd_cookie)
616 err = -1;
617 else
619 #ifdef HAVE_DOSISH_SYSTEM
620 /* Make sure it is in binary mode if requested. */
621 if ( (modeflags & O_BINARY) )
622 setmode (fd, O_BINARY);
623 #endif
624 fd_cookie->fd = fd;
625 fd_cookie->no_close = no_close;
626 *cookie = fd_cookie;
627 err = 0;
630 return err;
633 /* Read function for fd objects. */
634 static ssize_t
635 es_func_fd_read (void *cookie, void *buffer, size_t size)
638 estream_cookie_fd_t file_cookie = cookie;
639 ssize_t bytes_read;
642 bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
643 while (bytes_read == -1 && errno == EINTR);
645 return bytes_read;
648 /* Write function for fd objects. */
649 static ssize_t
650 es_func_fd_write (void *cookie, const void *buffer, size_t size)
653 estream_cookie_fd_t file_cookie = cookie;
654 ssize_t bytes_written;
657 bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
658 while (bytes_written == -1 && errno == EINTR);
660 return bytes_written;
663 /* Seek function for fd objects. */
664 static int
665 es_func_fd_seek (void *cookie, off_t *offset, int whence)
667 estream_cookie_fd_t file_cookie = cookie;
668 off_t offset_new;
669 int err;
671 offset_new = lseek (file_cookie->fd, *offset, whence);
672 if (offset_new == -1)
673 err = -1;
674 else
676 *offset = offset_new;
677 err = 0;
680 return err;
683 /* Destroy function for fd objects. */
684 static int
685 es_func_fd_destroy (void *cookie)
687 estream_cookie_fd_t fd_cookie = cookie;
688 int err;
690 if (fd_cookie)
692 err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
693 mem_free (fd_cookie);
695 else
696 err = 0;
698 return err;
702 static es_cookie_io_functions_t estream_functions_fd =
704 es_func_fd_read,
705 es_func_fd_write,
706 es_func_fd_seek,
707 es_func_fd_destroy
713 /* Implementation of FILE* I/O. */
715 /* Cookie for fp objects. */
716 typedef struct estream_cookie_fp
718 FILE *fp; /* The file pointer we are using for actual output. */
719 int no_close; /* If set we won't close the file pointer. */
720 } *estream_cookie_fp_t;
722 /* Create function for fd objects. */
723 static int
724 es_func_fp_create (void **cookie, FILE *fp, unsigned int modeflags, int no_close)
726 estream_cookie_fp_t fp_cookie;
727 int err;
729 fp_cookie = mem_alloc (sizeof *fp_cookie);
730 if (!fp_cookie)
731 err = -1;
732 else
734 #ifdef HAVE_DOSISH_SYSTEM
735 /* Make sure it is in binary mode if requested. */
736 if ( (modeflags & O_BINARY) )
737 setmode (fileno (fp), O_BINARY);
738 #endif
739 fp_cookie->fp = fp;
740 fp_cookie->no_close = no_close;
741 *cookie = fp_cookie;
742 err = 0;
745 return err;
748 /* Read function for FILE* objects. */
749 static ssize_t
750 es_func_fp_read (void *cookie, void *buffer, size_t size)
753 estream_cookie_fp_t file_cookie = cookie;
754 ssize_t bytes_read;
756 bytes_read = fread (buffer, 1, size, file_cookie->fp);
757 if (!bytes_read && ferror (file_cookie->fp))
758 return -1;
759 return bytes_read;
762 /* Write function for FILE* objects. */
763 static ssize_t
764 es_func_fp_write (void *cookie, const void *buffer, size_t size)
767 estream_cookie_fp_t file_cookie = cookie;
768 size_t bytes_written;
770 bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
771 if (bytes_written != size)
772 return -1;
773 return bytes_written;
776 /* Seek function for FILE* objects. */
777 static int
778 es_func_fp_seek (void *cookie, off_t *offset, int whence)
780 estream_cookie_fp_t file_cookie = cookie;
781 long int offset_new;
783 if ( fseek (file_cookie->fp, (long int)*offset, whence) )
785 fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", errno,strerror (errno));
786 return -1;
789 offset_new = ftell (file_cookie->fp);
790 if (offset_new == -1)
792 fprintf (stderr, "\nftell failed: errno=%d (%s)\n", errno,strerror (errno));
793 return -1;
795 *offset = offset_new;
796 return 0;
799 /* Destroy function for fd objects. */
800 static int
801 es_func_fp_destroy (void *cookie)
803 estream_cookie_fp_t fp_cookie = cookie;
804 int err;
806 if (fp_cookie)
808 fflush (fp_cookie->fp);
809 err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
810 mem_free (fp_cookie);
812 else
813 err = 0;
815 return err;
819 static es_cookie_io_functions_t estream_functions_fp =
821 es_func_fp_read,
822 es_func_fp_write,
823 es_func_fp_seek,
824 es_func_fp_destroy
830 /* Implementation of file I/O. */
832 /* Create function for file objects. */
833 static int
834 es_func_file_create (void **cookie, int *filedes,
835 const char *path, unsigned int modeflags)
837 estream_cookie_fd_t file_cookie;
838 int err;
839 int fd;
841 err = 0;
842 fd = -1;
844 file_cookie = mem_alloc (sizeof (*file_cookie));
845 if (! file_cookie)
847 err = -1;
848 goto out;
851 fd = open (path, modeflags, ES_DEFAULT_OPEN_MODE);
852 if (fd == -1)
854 err = -1;
855 goto out;
857 #ifdef HAVE_DOSISH_SYSTEM
858 /* Make sure it is in binary mode if requested. */
859 if ( (modeflags & O_BINARY) )
860 setmode (fd, O_BINARY);
861 #endif
863 file_cookie->fd = fd;
864 file_cookie->no_close = 0;
865 *cookie = file_cookie;
866 *filedes = fd;
868 out:
870 if (err)
871 mem_free (file_cookie);
873 return err;
876 static es_cookie_io_functions_t estream_functions_file =
878 es_func_fd_read,
879 es_func_fd_write,
880 es_func_fd_seek,
881 es_func_fd_destroy
886 /* Stream primitives. */
888 static int
889 es_convert_mode (const char *mode, unsigned int *modeflags)
892 /* FIXME: We need to allow all mode flags permutations. */
893 struct
895 const char *mode;
896 unsigned int flags;
897 } mode_flags[] = { { "r",
898 O_RDONLY },
899 { "rb",
900 O_RDONLY | O_BINARY },
901 { "w",
902 O_WRONLY | O_TRUNC | O_CREAT },
903 { "wb",
904 O_WRONLY | O_TRUNC | O_CREAT | O_BINARY },
905 { "a",
906 O_WRONLY | O_APPEND | O_CREAT },
907 { "ab",
908 O_WRONLY | O_APPEND | O_CREAT | O_BINARY },
909 { "r+",
910 O_RDWR },
911 { "rb+",
912 O_RDWR | O_BINARY },
913 { "r+b",
914 O_RDONLY | O_WRONLY | O_BINARY },
915 { "w+",
916 O_RDWR | O_TRUNC | O_CREAT },
917 { "wb+",
918 O_RDWR | O_TRUNC | O_CREAT | O_BINARY },
919 { "w+b",
920 O_RDWR | O_TRUNC | O_CREAT | O_BINARY },
921 { "a+",
922 O_RDWR | O_CREAT | O_APPEND },
923 { "ab+",
924 O_RDWR | O_CREAT | O_APPEND | O_BINARY },
925 { "a+b",
926 O_RDWR | O_CREAT | O_APPEND | O_BINARY }
928 unsigned int i;
929 int err;
931 for (i = 0; i < DIM (mode_flags); i++)
932 if (! strcmp (mode_flags[i].mode, mode))
933 break;
934 if (i == DIM (mode_flags))
936 errno = EINVAL;
937 err = -1;
939 else
941 err = 0;
942 *modeflags = mode_flags[i].flags;
945 return err;
951 * Low level stream functionality.
954 static int
955 es_fill (estream_t stream)
957 size_t bytes_read = 0;
958 int err;
960 if (!stream->intern->func_read)
962 errno = EOPNOTSUPP;
963 err = -1;
965 else
967 es_cookie_read_function_t func_read = stream->intern->func_read;
968 ssize_t ret;
970 ret = (*func_read) (stream->intern->cookie,
971 stream->buffer, stream->buffer_size);
972 if (ret == -1)
974 bytes_read = 0;
975 err = -1;
977 else
979 bytes_read = ret;
980 err = 0;
984 if (err)
985 stream->intern->indicators.err = 1;
986 else if (!bytes_read)
987 stream->intern->indicators.eof = 1;
989 stream->intern->offset += stream->data_len;
990 stream->data_len = bytes_read;
991 stream->data_offset = 0;
993 return err;
996 static int
997 es_flush (estream_t stream)
999 es_cookie_write_function_t func_write = stream->intern->func_write;
1000 int err;
1002 assert (stream->flags.writing);
1004 if (stream->data_offset)
1006 size_t bytes_written;
1007 size_t data_flushed;
1008 ssize_t ret;
1010 if (! func_write)
1012 err = EOPNOTSUPP;
1013 goto out;
1016 /* Note: to prevent an endless loop caused by user-provided
1017 write-functions that pretend to have written more bytes than
1018 they were asked to write, we have to check for
1019 "(stream->data_offset - data_flushed) > 0" instead of
1020 "stream->data_offset - data_flushed". */
1022 data_flushed = 0;
1023 err = 0;
1025 while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
1027 ret = (*func_write) (stream->intern->cookie,
1028 stream->buffer + data_flushed,
1029 stream->data_offset - data_flushed);
1030 if (ret == -1)
1032 bytes_written = 0;
1033 err = -1;
1035 else
1036 bytes_written = ret;
1038 data_flushed += bytes_written;
1039 if (err)
1040 break;
1043 stream->data_flushed += data_flushed;
1044 if (stream->data_offset == data_flushed)
1046 stream->intern->offset += stream->data_offset;
1047 stream->data_offset = 0;
1048 stream->data_flushed = 0;
1050 /* Propagate flush event. */
1051 (*func_write) (stream->intern->cookie, NULL, 0);
1054 else
1055 err = 0;
1057 out:
1059 if (err)
1060 stream->intern->indicators.err = 1;
1062 return err;
1065 /* Discard buffered data for STREAM. */
1066 static void
1067 es_empty (estream_t stream)
1069 assert (!stream->flags.writing);
1070 stream->data_len = 0;
1071 stream->data_offset = 0;
1072 stream->unread_data_len = 0;
1075 /* Initialize STREAM. */
1076 static void
1077 es_initialize (estream_t stream,
1078 void *cookie, int fd, es_cookie_io_functions_t functions,
1079 unsigned int modeflags)
1081 stream->intern->cookie = cookie;
1082 stream->intern->opaque = NULL;
1083 stream->intern->offset = 0;
1084 stream->intern->func_read = functions.func_read;
1085 stream->intern->func_write = functions.func_write;
1086 stream->intern->func_seek = functions.func_seek;
1087 stream->intern->func_close = functions.func_close;
1088 stream->intern->strategy = _IOFBF;
1089 stream->intern->fd = fd;
1090 stream->intern->print_err = 0;
1091 stream->intern->print_errno = 0;
1092 stream->intern->print_ntotal = 0;
1093 stream->intern->print_fp = NULL;
1094 stream->intern->indicators.err = 0;
1095 stream->intern->indicators.eof = 0;
1096 stream->intern->deallocate_buffer = 0;
1098 stream->data_len = 0;
1099 stream->data_offset = 0;
1100 stream->data_flushed = 0;
1101 stream->unread_data_len = 0;
1102 /* Depending on the modeflags we set whether we start in writing or
1103 reading mode. This is required in case we are working on a
1104 wronly stream which is not seeekable (like stdout). Without this
1105 pre-initialization we would do a seek at the first write call and
1106 as this will fail no utput will be delivered. */
1107 if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1108 stream->flags.writing = 1;
1109 else
1110 stream->flags.writing = 0;
1113 /* Deinitialize STREAM. */
1114 static int
1115 es_deinitialize (estream_t stream)
1117 es_cookie_close_function_t func_close;
1118 int err, tmp_err;
1120 if (stream->intern->print_fp)
1122 int save_errno = errno;
1123 fclose (stream->intern->print_fp);
1124 stream->intern->print_fp = NULL;
1125 errno = save_errno;
1128 func_close = stream->intern->func_close;
1130 err = 0;
1131 if (stream->flags.writing)
1132 SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1133 if (func_close)
1134 SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1137 return err;
1140 /* Create a new stream object, initialize it. */
1141 static int
1142 es_create (estream_t *stream, void *cookie, int fd,
1143 es_cookie_io_functions_t functions, unsigned int modeflags)
1145 estream_internal_t stream_internal_new;
1146 estream_t stream_new;
1147 int err;
1149 stream_new = NULL;
1150 stream_internal_new = NULL;
1152 stream_new = mem_alloc (sizeof (*stream_new));
1153 if (! stream_new)
1155 err = -1;
1156 goto out;
1159 stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
1160 if (! stream_internal_new)
1162 err = -1;
1163 goto out;
1166 stream_new->buffer = stream_internal_new->buffer;
1167 stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1168 stream_new->unread_buffer = stream_internal_new->unread_buffer;
1169 stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1170 stream_new->intern = stream_internal_new;
1172 ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
1173 es_initialize (stream_new, cookie, fd, functions, modeflags);
1175 err = es_list_add (stream_new);
1176 if (err)
1177 goto out;
1179 *stream = stream_new;
1181 out:
1183 if (err)
1185 if (stream_new)
1187 es_deinitialize (stream_new);
1188 mem_free (stream_new);
1192 return err;
1195 /* Deinitialize a stream object and destroy it. */
1196 static int
1197 es_destroy (estream_t stream)
1199 int err = 0;
1201 if (stream)
1203 es_list_remove (stream);
1204 err = es_deinitialize (stream);
1205 mem_free (stream->intern);
1206 mem_free (stream);
1209 return err;
1212 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1213 unbuffered-mode, storing the amount of bytes read in
1214 *BYTES_READ. */
1215 static int
1216 es_read_nbf (estream_t ES__RESTRICT stream,
1217 unsigned char *ES__RESTRICT buffer,
1218 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1220 es_cookie_read_function_t func_read = stream->intern->func_read;
1221 size_t data_read;
1222 ssize_t ret;
1223 int err;
1225 data_read = 0;
1226 err = 0;
1228 while (bytes_to_read - data_read)
1230 ret = (*func_read) (stream->intern->cookie,
1231 buffer + data_read, bytes_to_read - data_read);
1232 if (ret == -1)
1234 err = -1;
1235 break;
1237 else if (ret)
1238 data_read += ret;
1239 else
1240 break;
1243 stream->intern->offset += data_read;
1244 *bytes_read = data_read;
1246 return err;
1249 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1250 fully-buffered-mode, storing the amount of bytes read in
1251 *BYTES_READ. */
1252 static int
1253 es_read_fbf (estream_t ES__RESTRICT stream,
1254 unsigned char *ES__RESTRICT buffer,
1255 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1257 size_t data_available;
1258 size_t data_to_read;
1259 size_t data_read;
1260 int err;
1262 data_read = 0;
1263 err = 0;
1265 while ((bytes_to_read - data_read) && (! err))
1267 if (stream->data_offset == stream->data_len)
1269 /* Nothing more to read in current container, try to
1270 fill container with new data. */
1271 err = es_fill (stream);
1272 if (! err)
1273 if (! stream->data_len)
1274 /* Filling did not result in any data read. */
1275 break;
1278 if (! err)
1280 /* Filling resulted in some new data. */
1282 data_to_read = bytes_to_read - data_read;
1283 data_available = stream->data_len - stream->data_offset;
1284 if (data_to_read > data_available)
1285 data_to_read = data_available;
1287 memcpy (buffer + data_read,
1288 stream->buffer + stream->data_offset, data_to_read);
1289 stream->data_offset += data_to_read;
1290 data_read += data_to_read;
1294 *bytes_read = data_read;
1296 return err;
1299 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1300 line-buffered-mode, storing the amount of bytes read in
1301 *BYTES_READ. */
1302 static int
1303 es_read_lbf (estream_t ES__RESTRICT stream,
1304 unsigned char *ES__RESTRICT buffer,
1305 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1307 int err;
1309 err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1311 return err;
1314 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1315 *the amount of bytes read in BYTES_READ. */
1316 static int
1317 es_readn (estream_t ES__RESTRICT stream,
1318 void *ES__RESTRICT buffer_arg,
1319 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1321 unsigned char *buffer = (unsigned char *)buffer_arg;
1322 size_t data_read_unread, data_read;
1323 int err;
1325 data_read_unread = 0;
1326 data_read = 0;
1327 err = 0;
1329 if (stream->flags.writing)
1331 /* Switching to reading mode -> flush output. */
1332 err = es_flush (stream);
1333 if (err)
1334 goto out;
1335 stream->flags.writing = 0;
1338 /* Read unread data first. */
1339 while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1341 buffer[data_read_unread]
1342 = stream->unread_buffer[stream->unread_data_len - 1];
1343 stream->unread_data_len--;
1344 data_read_unread++;
1347 switch (stream->intern->strategy)
1349 case _IONBF:
1350 err = es_read_nbf (stream,
1351 buffer + data_read_unread,
1352 bytes_to_read - data_read_unread, &data_read);
1353 break;
1354 case _IOLBF:
1355 err = es_read_lbf (stream,
1356 buffer + data_read_unread,
1357 bytes_to_read - data_read_unread, &data_read);
1358 break;
1359 case _IOFBF:
1360 err = es_read_fbf (stream,
1361 buffer + data_read_unread,
1362 bytes_to_read - data_read_unread, &data_read);
1363 break;
1366 out:
1368 if (bytes_read)
1369 *bytes_read = data_read_unread + data_read;
1371 return err;
1374 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1375 amount of bytes succesfully unread in *BYTES_UNREAD. */
1376 static void
1377 es_unreadn (estream_t ES__RESTRICT stream,
1378 const unsigned char *ES__RESTRICT data, size_t data_n,
1379 size_t *ES__RESTRICT bytes_unread)
1381 size_t space_left;
1383 space_left = stream->unread_buffer_size - stream->unread_data_len;
1385 if (data_n > space_left)
1386 data_n = space_left;
1388 if (! data_n)
1389 goto out;
1391 memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1392 stream->unread_data_len += data_n;
1393 stream->intern->indicators.eof = 0;
1395 out:
1397 if (bytes_unread)
1398 *bytes_unread = data_n;
1401 /* Seek in STREAM. */
1402 static int
1403 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1404 off_t *ES__RESTRICT offset_new)
1406 es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1407 int err, ret;
1408 off_t off;
1410 if (! func_seek)
1412 errno = EOPNOTSUPP;
1413 err = -1;
1414 goto out;
1417 if (stream->flags.writing)
1419 /* Flush data first in order to prevent flushing it to the wrong
1420 offset. */
1421 err = es_flush (stream);
1422 if (err)
1423 goto out;
1424 stream->flags.writing = 0;
1427 off = offset;
1428 if (whence == SEEK_CUR)
1430 off = off - stream->data_len + stream->data_offset;
1431 off -= stream->unread_data_len;
1434 ret = (*func_seek) (stream->intern->cookie, &off, whence);
1435 if (ret == -1)
1437 err = -1;
1438 goto out;
1441 err = 0;
1442 es_empty (stream);
1444 if (offset_new)
1445 *offset_new = off;
1447 stream->intern->indicators.eof = 0;
1448 stream->intern->offset = off;
1450 out:
1452 if (err)
1453 stream->intern->indicators.err = 1;
1455 return err;
1458 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1459 unbuffered-mode, storing the amount of bytes written in
1460 *BYTES_WRITTEN. */
1461 static int
1462 es_write_nbf (estream_t ES__RESTRICT stream,
1463 const unsigned char *ES__RESTRICT buffer,
1464 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1466 es_cookie_write_function_t func_write = stream->intern->func_write;
1467 size_t data_written;
1468 ssize_t ret;
1469 int err;
1471 if (bytes_to_write && (! func_write))
1473 err = EOPNOTSUPP;
1474 goto out;
1477 data_written = 0;
1478 err = 0;
1480 while (bytes_to_write - data_written)
1482 ret = (*func_write) (stream->intern->cookie,
1483 buffer + data_written,
1484 bytes_to_write - data_written);
1485 if (ret == -1)
1487 err = -1;
1488 break;
1490 else
1491 data_written += ret;
1494 stream->intern->offset += data_written;
1495 *bytes_written = data_written;
1497 out:
1499 return err;
1502 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1503 fully-buffered-mode, storing the amount of bytes written in
1504 *BYTES_WRITTEN. */
1505 static int
1506 es_write_fbf (estream_t ES__RESTRICT stream,
1507 const unsigned char *ES__RESTRICT buffer,
1508 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1510 size_t space_available;
1511 size_t data_to_write;
1512 size_t data_written;
1513 int err;
1515 data_written = 0;
1516 err = 0;
1518 while ((bytes_to_write - data_written) && (! err))
1520 if (stream->data_offset == stream->buffer_size)
1521 /* Container full, flush buffer. */
1522 err = es_flush (stream);
1524 if (! err)
1526 /* Flushing resulted in empty container. */
1528 data_to_write = bytes_to_write - data_written;
1529 space_available = stream->buffer_size - stream->data_offset;
1530 if (data_to_write > space_available)
1531 data_to_write = space_available;
1533 memcpy (stream->buffer + stream->data_offset,
1534 buffer + data_written, data_to_write);
1535 stream->data_offset += data_to_write;
1536 data_written += data_to_write;
1540 *bytes_written = data_written;
1542 return err;
1546 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1547 line-buffered-mode, storing the amount of bytes written in
1548 *BYTES_WRITTEN. */
1549 static int
1550 es_write_lbf (estream_t ES__RESTRICT stream,
1551 const unsigned char *ES__RESTRICT buffer,
1552 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1554 size_t data_flushed = 0;
1555 size_t data_buffered = 0;
1556 unsigned char *nlp;
1557 int err = 0;
1559 nlp = memrchr (buffer, '\n', bytes_to_write);
1560 if (nlp)
1562 /* Found a newline, directly write up to (including) this
1563 character. */
1564 err = es_flush (stream);
1565 if (!err)
1566 err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1569 if (!err)
1571 /* Write remaining data fully buffered. */
1572 err = es_write_fbf (stream, buffer + data_flushed,
1573 bytes_to_write - data_flushed, &data_buffered);
1576 *bytes_written = data_flushed + data_buffered;
1577 return err;
1581 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1582 amount of bytes written in BYTES_WRITTEN. */
1583 static int
1584 es_writen (estream_t ES__RESTRICT stream,
1585 const void *ES__RESTRICT buffer,
1586 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1588 size_t data_written;
1589 int err;
1591 data_written = 0;
1592 err = 0;
1594 if (!stream->flags.writing)
1596 /* Switching to writing mode -> discard input data and seek to
1597 position at which reading has stopped. We can do this only
1598 if a seek function has been registered. */
1599 if (stream->intern->func_seek)
1601 err = es_seek (stream, 0, SEEK_CUR, NULL);
1602 if (err)
1604 if (errno == ESPIPE)
1605 err = 0;
1606 else
1607 goto out;
1612 switch (stream->intern->strategy)
1614 case _IONBF:
1615 err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1616 break;
1618 case _IOLBF:
1619 err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1620 break;
1622 case _IOFBF:
1623 err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1624 break;
1627 out:
1629 if (bytes_written)
1630 *bytes_written = data_written;
1631 if (data_written)
1632 if (!stream->flags.writing)
1633 stream->flags.writing = 1;
1635 return err;
1639 static int
1640 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1641 size_t *ES__RESTRICT data_len)
1643 int err;
1645 if (stream->flags.writing)
1647 /* Switching to reading mode -> flush output. */
1648 err = es_flush (stream);
1649 if (err)
1650 goto out;
1651 stream->flags.writing = 0;
1654 if (stream->data_offset == stream->data_len)
1656 /* Refill container. */
1657 err = es_fill (stream);
1658 if (err)
1659 goto out;
1662 if (data)
1663 *data = stream->buffer + stream->data_offset;
1664 if (data_len)
1665 *data_len = stream->data_len - stream->data_offset;
1666 err = 0;
1668 out:
1670 return err;
1674 /* Skip SIZE bytes of input data contained in buffer. */
1675 static int
1676 es_skip (estream_t stream, size_t size)
1678 int err;
1680 if (stream->data_offset + size > stream->data_len)
1682 errno = EINVAL;
1683 err = -1;
1685 else
1687 stream->data_offset += size;
1688 err = 0;
1691 return err;
1695 static int
1696 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
1697 char *ES__RESTRICT *ES__RESTRICT line,
1698 size_t *ES__RESTRICT line_length)
1700 size_t space_left;
1701 size_t line_size;
1702 estream_t line_stream;
1703 char *line_new;
1704 void *line_stream_cookie;
1705 char *newline;
1706 unsigned char *data;
1707 size_t data_len;
1708 int err;
1710 line_new = NULL;
1711 line_stream = NULL;
1712 line_stream_cookie = NULL;
1714 err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0,
1715 BUFFER_BLOCK_SIZE, 1,
1716 mem_realloc, mem_free,
1717 O_RDWR,
1719 if (err)
1720 goto out;
1722 err = es_create (&line_stream, line_stream_cookie, -1,
1723 estream_functions_mem, O_RDWR);
1724 if (err)
1725 goto out;
1727 space_left = max_length;
1728 line_size = 0;
1729 while (1)
1731 if (max_length && (space_left == 1))
1732 break;
1734 err = es_peek (stream, &data, &data_len);
1735 if (err || (! data_len))
1736 break;
1738 if (data_len > (space_left - 1))
1739 data_len = space_left - 1;
1741 newline = memchr (data, '\n', data_len);
1742 if (newline)
1744 data_len = (newline - (char *) data) + 1;
1745 err = es_write (line_stream, data, data_len, NULL);
1746 if (! err)
1748 space_left -= data_len;
1749 line_size += data_len;
1750 es_skip (stream, data_len);
1751 break;
1754 else
1756 err = es_write (line_stream, data, data_len, NULL);
1757 if (! err)
1759 space_left -= data_len;
1760 line_size += data_len;
1761 es_skip (stream, data_len);
1764 if (err)
1765 break;
1767 if (err)
1768 goto out;
1770 /* Complete line has been written to line_stream. */
1772 if ((max_length > 1) && (! line_size))
1774 stream->intern->indicators.eof = 1;
1775 goto out;
1778 err = es_seek (line_stream, 0, SEEK_SET, NULL);
1779 if (err)
1780 goto out;
1782 if (! *line)
1784 line_new = mem_alloc (line_size + 1);
1785 if (! line_new)
1787 err = -1;
1788 goto out;
1791 else
1792 line_new = *line;
1794 err = es_read (line_stream, line_new, line_size, NULL);
1795 if (err)
1796 goto out;
1798 line_new[line_size] = '\0';
1800 if (! *line)
1801 *line = line_new;
1802 if (line_length)
1803 *line_length = line_size;
1805 out:
1807 if (line_stream)
1808 es_destroy (line_stream);
1809 else if (line_stream_cookie)
1810 es_func_mem_destroy (line_stream_cookie);
1812 if (err)
1814 if (! *line)
1815 mem_free (line_new);
1816 stream->intern->indicators.err = 1;
1819 return err;
1823 /* Output fucntion used for estream_format. */
1824 static int
1825 print_writer (void *outfncarg, const char *buf, size_t buflen)
1827 estream_t stream = outfncarg;
1828 size_t nwritten;
1829 int rc;
1831 nwritten = 0;
1832 rc = es_writen (stream, buf, buflen, &nwritten);
1833 stream->intern->print_ntotal += nwritten;
1834 return rc;
1838 /* The core of our printf function. This is called in locked state. */
1839 static int
1840 es_print (estream_t ES__RESTRICT stream,
1841 const char *ES__RESTRICT format, va_list ap)
1843 int rc;
1845 stream->intern->print_ntotal = 0;
1846 rc = estream_format (print_writer, stream, format, ap);
1847 if (rc)
1848 return -1;
1849 return (int)stream->intern->print_ntotal;
1853 static void
1854 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1856 if (ind_err != -1)
1857 stream->intern->indicators.err = ind_err ? 1 : 0;
1858 if (ind_eof != -1)
1859 stream->intern->indicators.eof = ind_eof ? 1 : 0;
1863 static int
1864 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1866 int ret = 0;
1868 if (ind_err)
1869 ret = stream->intern->indicators.err;
1870 else if (ind_eof)
1871 ret = stream->intern->indicators.eof;
1873 return ret;
1877 static int
1878 es_set_buffering (estream_t ES__RESTRICT stream,
1879 char *ES__RESTRICT buffer, int mode, size_t size)
1881 int err;
1883 /* Flush or empty buffer depending on mode. */
1884 if (stream->flags.writing)
1886 err = es_flush (stream);
1887 if (err)
1888 goto out;
1890 else
1891 es_empty (stream);
1893 es_set_indicators (stream, -1, 0);
1895 /* Free old buffer in case that was allocated by this function. */
1896 if (stream->intern->deallocate_buffer)
1898 stream->intern->deallocate_buffer = 0;
1899 mem_free (stream->buffer);
1900 stream->buffer = NULL;
1903 if (mode == _IONBF)
1904 stream->buffer_size = 0;
1905 else
1907 void *buffer_new;
1909 if (buffer)
1910 buffer_new = buffer;
1911 else
1913 buffer_new = mem_alloc (size);
1914 if (! buffer_new)
1916 err = -1;
1917 goto out;
1921 stream->buffer = buffer_new;
1922 stream->buffer_size = size;
1923 if (! buffer)
1924 stream->intern->deallocate_buffer = 1;
1926 stream->intern->strategy = mode;
1927 err = 0;
1929 out:
1931 return err;
1935 static off_t
1936 es_offset_calculate (estream_t stream)
1938 off_t offset;
1940 offset = stream->intern->offset + stream->data_offset;
1941 if (offset < stream->unread_data_len)
1942 /* Offset undefined. */
1943 offset = 0;
1944 else
1945 offset -= stream->unread_data_len;
1947 return offset;
1951 static void
1952 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
1953 void **ES__RESTRICT opaque_old)
1955 if (opaque_old)
1956 *opaque_old = stream->intern->opaque;
1957 if (opaque_new)
1958 stream->intern->opaque = opaque_new;
1962 static int
1963 es_get_fd (estream_t stream)
1965 return stream->intern->fd;
1970 /* API. */
1973 es_init (void)
1975 int err;
1977 err = es_init_do ();
1979 return err;
1982 estream_t
1983 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
1985 unsigned int modeflags;
1986 int create_called;
1987 estream_t stream;
1988 void *cookie;
1989 int err;
1990 int fd;
1992 stream = NULL;
1993 cookie = NULL;
1994 create_called = 0;
1996 err = es_convert_mode (mode, &modeflags);
1997 if (err)
1998 goto out;
2000 err = es_func_file_create (&cookie, &fd, path, modeflags);
2001 if (err)
2002 goto out;
2004 create_called = 1;
2005 err = es_create (&stream, cookie, fd, estream_functions_file, modeflags);
2006 if (err)
2007 goto out;
2009 out:
2011 if (err && create_called)
2012 (*estream_functions_file.func_close) (cookie);
2014 return stream;
2018 estream_t
2019 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
2020 unsigned int grow,
2021 func_realloc_t func_realloc, func_free_t func_free,
2022 const char *ES__RESTRICT mode)
2024 unsigned int modeflags;
2025 int create_called;
2026 estream_t stream;
2027 void *cookie;
2028 int err;
2030 cookie = 0;
2031 stream = NULL;
2032 create_called = 0;
2034 err = es_convert_mode (mode, &modeflags);
2035 if (err)
2036 goto out;
2038 err = es_func_mem_create (&cookie, data, data_n, data_len,
2039 BUFFER_BLOCK_SIZE, grow,
2040 func_realloc, func_free, modeflags, 0);
2041 if (err)
2042 goto out;
2044 create_called = 1;
2045 err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags);
2047 out:
2049 if (err && create_called)
2050 (*estream_functions_mem.func_close) (cookie);
2052 return stream;
2056 estream_t
2057 es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
2059 unsigned int modeflags;
2060 estream_t stream = NULL;
2061 void *cookie = NULL;
2063 /* Memory streams are always read/write. We use MODE only to get
2064 the append flag. */
2065 if (es_convert_mode (mode, &modeflags))
2066 return NULL;
2067 modeflags |= O_RDWR;
2070 if (es_func_mem_create (&cookie, NULL, 0, 0,
2071 BUFFER_BLOCK_SIZE, 1,
2072 mem_realloc, mem_free, modeflags,
2073 memlimit))
2074 return NULL;
2076 if (es_create (&stream, cookie, -1, estream_functions_mem, modeflags))
2077 (*estream_functions_mem.func_close) (cookie);
2079 return stream;
2084 estream_t
2085 es_fopencookie (void *ES__RESTRICT cookie,
2086 const char *ES__RESTRICT mode,
2087 es_cookie_io_functions_t functions)
2089 unsigned int modeflags;
2090 estream_t stream;
2091 int err;
2093 stream = NULL;
2094 modeflags = 0;
2096 err = es_convert_mode (mode, &modeflags);
2097 if (err)
2098 goto out;
2100 err = es_create (&stream, cookie, -1, functions, modeflags);
2101 if (err)
2102 goto out;
2104 out:
2106 return stream;
2110 estream_t
2111 do_fdopen (int filedes, const char *mode, int no_close)
2113 unsigned int modeflags;
2114 int create_called;
2115 estream_t stream;
2116 void *cookie;
2117 int err;
2119 stream = NULL;
2120 cookie = NULL;
2121 create_called = 0;
2123 err = es_convert_mode (mode, &modeflags);
2124 if (err)
2125 goto out;
2127 err = es_func_fd_create (&cookie, filedes, modeflags, no_close);
2128 if (err)
2129 goto out;
2131 create_called = 1;
2132 err = es_create (&stream, cookie, filedes, estream_functions_fd, modeflags);
2134 out:
2136 if (err && create_called)
2137 (*estream_functions_fd.func_close) (cookie);
2139 return stream;
2142 estream_t
2143 es_fdopen (int filedes, const char *mode)
2145 return do_fdopen (filedes, mode, 0);
2148 /* A variant of es_fdopen which does not close FILEDES at the end. */
2149 estream_t
2150 es_fdopen_nc (int filedes, const char *mode)
2152 return do_fdopen (filedes, mode, 1);
2156 estream_t
2157 do_fpopen (FILE *fp, const char *mode, int no_close)
2159 unsigned int modeflags;
2160 int create_called;
2161 estream_t stream;
2162 void *cookie;
2163 int err;
2165 stream = NULL;
2166 cookie = NULL;
2167 create_called = 0;
2169 err = es_convert_mode (mode, &modeflags);
2170 if (err)
2171 goto out;
2173 fflush (fp);
2174 err = es_func_fp_create (&cookie, fp, modeflags, no_close);
2175 if (err)
2176 goto out;
2178 create_called = 1;
2179 err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
2180 modeflags);
2182 out:
2184 if (err && create_called)
2185 (*estream_functions_fp.func_close) (cookie);
2187 return stream;
2191 /* Create an estream from the stdio stream FP. This mechanism is
2192 useful in case the stdio streams have special properties and may
2193 not be mixed with fd based functions. This is for example the case
2194 under Windows where the 3 standard streams are associated with the
2195 console whereas a duped and fd-opened stream of one of this stream
2196 won't be associated with the console. As this messes things up it
2197 is easier to keep on using the standard I/O stream as a backend for
2198 estream. */
2199 estream_t
2200 es_fpopen (FILE *fp, const char *mode)
2202 return do_fpopen (fp, mode, 0);
2206 /* Same as es_fpopen but does not close FP at the end. */
2207 estream_t
2208 es_fpopen_nc (FILE *fp, const char *mode)
2210 return do_fpopen (fp, mode, 1);
2214 estream_t
2215 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
2216 estream_t ES__RESTRICT stream)
2218 int err;
2220 if (path)
2222 unsigned int modeflags;
2223 int create_called;
2224 void *cookie;
2225 int fd;
2227 cookie = NULL;
2228 create_called = 0;
2230 ESTREAM_LOCK (stream);
2232 es_deinitialize (stream);
2234 err = es_convert_mode (mode, &modeflags);
2235 if (err)
2236 goto leave;
2238 err = es_func_file_create (&cookie, &fd, path, modeflags);
2239 if (err)
2240 goto leave;
2242 create_called = 1;
2243 es_initialize (stream, cookie, fd, estream_functions_file, modeflags);
2245 leave:
2247 if (err)
2249 if (create_called)
2250 es_func_fd_destroy (cookie);
2252 es_destroy (stream);
2253 stream = NULL;
2255 else
2256 ESTREAM_UNLOCK (stream);
2258 else
2260 /* FIXME? We don't support re-opening at the moment. */
2261 errno = EINVAL;
2262 es_deinitialize (stream);
2263 es_destroy (stream);
2264 stream = NULL;
2267 return stream;
2272 es_fclose (estream_t stream)
2274 int err;
2276 err = es_destroy (stream);
2278 return err;
2282 es_fileno_unlocked (estream_t stream)
2284 return es_get_fd (stream);
2288 void
2289 es_flockfile (estream_t stream)
2291 ESTREAM_LOCK (stream);
2296 es_ftrylockfile (estream_t stream)
2298 return ESTREAM_TRYLOCK (stream);
2302 void
2303 es_funlockfile (estream_t stream)
2305 ESTREAM_UNLOCK (stream);
2310 es_fileno (estream_t stream)
2312 int ret;
2314 ESTREAM_LOCK (stream);
2315 ret = es_fileno_unlocked (stream);
2316 ESTREAM_UNLOCK (stream);
2318 return ret;
2323 es_feof_unlocked (estream_t stream)
2325 return es_get_indicator (stream, 0, 1);
2330 es_feof (estream_t stream)
2332 int ret;
2334 ESTREAM_LOCK (stream);
2335 ret = es_feof_unlocked (stream);
2336 ESTREAM_UNLOCK (stream);
2338 return ret;
2343 es_ferror_unlocked (estream_t stream)
2345 return es_get_indicator (stream, 1, 0);
2350 es_ferror (estream_t stream)
2352 int ret;
2354 ESTREAM_LOCK (stream);
2355 ret = es_ferror_unlocked (stream);
2356 ESTREAM_UNLOCK (stream);
2358 return ret;
2362 void
2363 es_clearerr_unlocked (estream_t stream)
2365 es_set_indicators (stream, 0, 0);
2369 void
2370 es_clearerr (estream_t stream)
2372 ESTREAM_LOCK (stream);
2373 es_clearerr_unlocked (stream);
2374 ESTREAM_UNLOCK (stream);
2379 es_fflush (estream_t stream)
2381 int err;
2383 if (stream)
2385 ESTREAM_LOCK (stream);
2386 if (stream->flags.writing)
2387 err = es_flush (stream);
2388 else
2390 es_empty (stream);
2391 err = 0;
2393 ESTREAM_UNLOCK (stream);
2395 else
2396 err = es_list_iterate (es_fflush);
2398 return err ? EOF : 0;
2403 es_fseek (estream_t stream, long int offset, int whence)
2405 int err;
2407 ESTREAM_LOCK (stream);
2408 err = es_seek (stream, offset, whence, NULL);
2409 ESTREAM_UNLOCK (stream);
2411 return err;
2416 es_fseeko (estream_t stream, off_t offset, int whence)
2418 int err;
2420 ESTREAM_LOCK (stream);
2421 err = es_seek (stream, offset, whence, NULL);
2422 ESTREAM_UNLOCK (stream);
2424 return err;
2428 long int
2429 es_ftell (estream_t stream)
2431 long int ret;
2433 ESTREAM_LOCK (stream);
2434 ret = es_offset_calculate (stream);
2435 ESTREAM_UNLOCK (stream);
2437 return ret;
2441 off_t
2442 es_ftello (estream_t stream)
2444 off_t ret = -1;
2446 ESTREAM_LOCK (stream);
2447 ret = es_offset_calculate (stream);
2448 ESTREAM_UNLOCK (stream);
2450 return ret;
2454 void
2455 es_rewind (estream_t stream)
2457 ESTREAM_LOCK (stream);
2458 es_seek (stream, 0L, SEEK_SET, NULL);
2459 es_set_indicators (stream, 0, -1);
2460 ESTREAM_UNLOCK (stream);
2465 _es_getc_underflow (estream_t stream)
2467 int err;
2468 unsigned char c;
2469 size_t bytes_read;
2471 err = es_readn (stream, &c, 1, &bytes_read);
2473 return (err || (! bytes_read)) ? EOF : c;
2478 _es_putc_overflow (int c, estream_t stream)
2480 unsigned char d = c;
2481 int err;
2483 err = es_writen (stream, &d, 1, NULL);
2485 return err ? EOF : c;
2490 es_fgetc (estream_t stream)
2492 int ret;
2494 ESTREAM_LOCK (stream);
2495 ret = es_getc_unlocked (stream);
2496 ESTREAM_UNLOCK (stream);
2498 return ret;
2503 es_fputc (int c, estream_t stream)
2505 int ret;
2507 ESTREAM_LOCK (stream);
2508 ret = es_putc_unlocked (c, stream);
2509 ESTREAM_UNLOCK (stream);
2511 return ret;
2516 es_ungetc (int c, estream_t stream)
2518 unsigned char data = (unsigned char) c;
2519 size_t data_unread;
2521 ESTREAM_LOCK (stream);
2522 es_unreadn (stream, &data, 1, &data_unread);
2523 ESTREAM_UNLOCK (stream);
2525 return data_unread ? c : EOF;
2530 es_read (estream_t ES__RESTRICT stream,
2531 void *ES__RESTRICT buffer, size_t bytes_to_read,
2532 size_t *ES__RESTRICT bytes_read)
2534 int err;
2536 if (bytes_to_read)
2538 ESTREAM_LOCK (stream);
2539 err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2540 ESTREAM_UNLOCK (stream);
2542 else
2543 err = 0;
2545 return err;
2550 es_write (estream_t ES__RESTRICT stream,
2551 const void *ES__RESTRICT buffer, size_t bytes_to_write,
2552 size_t *ES__RESTRICT bytes_written)
2554 int err;
2556 if (bytes_to_write)
2558 ESTREAM_LOCK (stream);
2559 err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2560 ESTREAM_UNLOCK (stream);
2562 else
2563 err = 0;
2565 return err;
2569 size_t
2570 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2571 estream_t ES__RESTRICT stream)
2573 size_t ret, bytes;
2574 int err;
2576 if (size * nitems)
2578 ESTREAM_LOCK (stream);
2579 err = es_readn (stream, ptr, size * nitems, &bytes);
2580 ESTREAM_UNLOCK (stream);
2582 ret = bytes / size;
2584 else
2585 ret = 0;
2587 return ret;
2591 size_t
2592 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2593 estream_t ES__RESTRICT stream)
2595 size_t ret, bytes;
2596 int err;
2598 if (size * nitems)
2600 ESTREAM_LOCK (stream);
2601 err = es_writen (stream, ptr, size * nitems, &bytes);
2602 ESTREAM_UNLOCK (stream);
2604 ret = bytes / size;
2606 else
2607 ret = 0;
2609 return ret;
2613 char *
2614 es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
2616 unsigned char *s = (unsigned char*)buffer;
2617 int c;
2619 if (!length)
2620 return NULL;
2622 c = EOF;
2623 ESTREAM_LOCK (stream);
2624 while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n')
2626 *s++ = c;
2627 length--;
2629 ESTREAM_UNLOCK (stream);
2631 if (c == EOF && s == (unsigned char*)buffer)
2632 return NULL; /* Nothing read. */
2634 if (c != EOF && length > 1)
2635 *s++ = c;
2637 *s = 0;
2638 return buffer;
2643 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2645 size_t length;
2646 int err;
2648 length = strlen (s);
2649 ESTREAM_LOCK (stream);
2650 err = es_writen (stream, s, length, NULL);
2651 ESTREAM_UNLOCK (stream);
2653 return err ? EOF : 0;
2657 ssize_t
2658 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2659 estream_t ES__RESTRICT stream)
2661 char *line = NULL;
2662 size_t line_n = 0;
2663 int err;
2665 ESTREAM_LOCK (stream);
2666 err = doreadline (stream, 0, &line, &line_n);
2667 ESTREAM_UNLOCK (stream);
2668 if (err)
2669 goto out;
2671 if (*n)
2673 /* Caller wants us to use his buffer. */
2675 if (*n < (line_n + 1))
2677 /* Provided buffer is too small -> resize. */
2679 void *p;
2681 p = mem_realloc (*lineptr, line_n + 1);
2682 if (! p)
2683 err = -1;
2684 else
2686 if (*lineptr != p)
2687 *lineptr = p;
2691 if (! err)
2693 memcpy (*lineptr, line, line_n + 1);
2694 if (*n != line_n)
2695 *n = line_n;
2697 mem_free (line);
2699 else
2701 /* Caller wants new buffers. */
2702 *lineptr = line;
2703 *n = line_n;
2706 out:
2708 return err ? err : line_n;
2713 /* Same as fgets() but if the provided buffer is too short a larger
2714 one will be allocated. This is similar to getline. A line is
2715 considered a byte stream ending in a LF.
2717 If MAX_LENGTH is not NULL, it shall point to a value with the
2718 maximum allowed allocation.
2720 Returns the length of the line. EOF is indicated by a line of
2721 length zero. A truncated line is indicated my setting the value at
2722 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2723 memory was enable or another error occurred; ERRNO is then set
2724 accordingly.
2726 If a line has been truncated, the file pointer is moved forward to
2727 the end of the line so that the next read starts with the next
2728 line. Note that MAX_LENGTH must be re-initialzied in this case.
2730 The caller initially needs to provide the address of a variable,
2731 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2732 anymore with the following invocations. LENGTH_OF_BUFFER should be
2733 the address of a variable, initialized to 0, which is also
2734 maintained by this function. Thus, both paramaters should be
2735 considered the state of this function.
2737 Note: The returned buffer is allocated with enough extra space to
2738 allow the caller to append a CR,LF,Nul. The buffer should be
2739 released using es_free.
2741 ssize_t
2742 es_read_line (estream_t stream,
2743 char **addr_of_buffer, size_t *length_of_buffer,
2744 size_t *max_length)
2746 int c;
2747 char *buffer = *addr_of_buffer;
2748 size_t length = *length_of_buffer;
2749 size_t nbytes = 0;
2750 size_t maxlen = max_length? *max_length : 0;
2751 char *p;
2753 if (!buffer)
2755 /* No buffer given - allocate a new one. */
2756 length = 256;
2757 buffer = mem_alloc (length);
2758 *addr_of_buffer = buffer;
2759 if (!buffer)
2761 *length_of_buffer = 0;
2762 if (max_length)
2763 *max_length = 0;
2764 return -1;
2766 *length_of_buffer = length;
2769 if (length < 4)
2771 /* This should never happen. If it does, the function has been
2772 called with wrong arguments. */
2773 errno = EINVAL;
2774 return -1;
2776 length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2778 ESTREAM_LOCK (stream);
2779 p = buffer;
2780 while ((c = es_getc_unlocked (stream)) != EOF)
2782 if (nbytes == length)
2784 /* Enlarge the buffer. */
2785 if (maxlen && length > maxlen)
2787 /* We are beyond our limit: Skip the rest of the line. */
2788 while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
2790 *p++ = '\n'; /* Always append a LF (we reserved some space). */
2791 nbytes++;
2792 if (max_length)
2793 *max_length = 0; /* Indicate truncation. */
2794 break; /* the while loop. */
2796 length += 3; /* Adjust for the reserved bytes. */
2797 length += length < 1024? 256 : 1024;
2798 *addr_of_buffer = mem_realloc (buffer, length);
2799 if (!*addr_of_buffer)
2801 int save_errno = errno;
2802 mem_free (buffer);
2803 *length_of_buffer = *max_length = 0;
2804 ESTREAM_UNLOCK (stream);
2805 errno = save_errno;
2806 return -1;
2808 buffer = *addr_of_buffer;
2809 *length_of_buffer = length;
2810 length -= 3;
2811 p = buffer + nbytes;
2813 *p++ = c;
2814 nbytes++;
2815 if (c == '\n')
2816 break;
2818 *p = 0; /* Make sure the line is a string. */
2819 ESTREAM_UNLOCK (stream);
2821 return nbytes;
2824 /* Wrapper around free() to match the memory allocation system used
2825 by estream. Should be used for all buffers returned to the caller
2826 by libestream. */
2827 void
2828 es_free (void *a)
2830 mem_free (a);
2835 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2836 va_list ap)
2838 int ret;
2840 ESTREAM_LOCK (stream);
2841 ret = es_print (stream, format, ap);
2842 ESTREAM_UNLOCK (stream);
2844 return ret;
2848 static int
2849 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
2850 const char *ES__RESTRICT format, ...)
2852 int ret;
2854 va_list ap;
2855 va_start (ap, format);
2856 ret = es_print (stream, format, ap);
2857 va_end (ap);
2859 return ret;
2864 es_fprintf (estream_t ES__RESTRICT stream,
2865 const char *ES__RESTRICT format, ...)
2867 int ret;
2869 va_list ap;
2870 va_start (ap, format);
2871 ESTREAM_LOCK (stream);
2872 ret = es_print (stream, format, ap);
2873 ESTREAM_UNLOCK (stream);
2874 va_end (ap);
2876 return ret;
2880 static int
2881 tmpfd (void)
2883 #ifdef HAVE_W32_SYSTEM
2884 int attempts, n;
2885 char buffer[MAX_PATH+9+12+1];
2886 char *name, *p;
2887 HANDLE file;
2888 int pid = GetCurrentProcessId ();
2889 unsigned int value;
2890 int i;
2892 n = GetTempPath (MAX_PATH+1, buffer);
2893 if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
2895 errno = ENOENT;
2896 return -1;
2898 p = buffer + strlen (buffer);
2899 strcpy (p, "_estream");
2900 p += 8;
2901 /* We try to create the directory but don't care about an error as
2902 it may already exist and the CreateFile would throw an error
2903 anyway. */
2904 CreateDirectory (buffer, NULL);
2905 *p++ = '\\';
2906 name = p;
2907 for (attempts=0; attempts < 10; attempts++)
2909 p = name;
2910 value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
2911 for (i=0; i < 8; i++)
2913 *p++ = tohex (((value >> 28) & 0x0f));
2914 value <<= 4;
2916 strcpy (p, ".tmp");
2917 file = CreateFile (buffer,
2918 GENERIC_READ | GENERIC_WRITE,
2920 NULL,
2921 CREATE_NEW,
2922 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
2923 NULL);
2924 if (file != INVALID_HANDLE_VALUE)
2926 int fd = _open_osfhandle ((long)file, 0);
2927 if (fd == -1)
2929 CloseHandle (file);
2930 return -1;
2932 return fd;
2934 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
2936 errno = ENOENT;
2937 return -1;
2938 #else /*!HAVE_W32_SYSTEM*/
2939 FILE *fp;
2940 int fp_fd;
2941 int fd;
2943 fp = NULL;
2944 fd = -1;
2946 fp = tmpfile ();
2947 if (! fp)
2948 goto out;
2950 fp_fd = fileno (fp);
2951 fd = dup (fp_fd);
2953 out:
2955 if (fp)
2956 fclose (fp);
2958 return fd;
2959 #endif /*!HAVE_W32_SYSTEM*/
2962 estream_t
2963 es_tmpfile (void)
2965 unsigned int modeflags;
2966 int create_called;
2967 estream_t stream;
2968 void *cookie;
2969 int err;
2970 int fd;
2972 create_called = 0;
2973 stream = NULL;
2974 modeflags = O_RDWR | O_TRUNC | O_CREAT;
2975 cookie = NULL;
2977 fd = tmpfd ();
2978 if (fd == -1)
2980 err = -1;
2981 goto out;
2984 err = es_func_fd_create (&cookie, fd, modeflags, 0);
2985 if (err)
2986 goto out;
2988 create_called = 1;
2989 err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags);
2991 out:
2993 if (err)
2995 if (create_called)
2996 es_func_fd_destroy (cookie);
2997 else if (fd != -1)
2998 close (fd);
2999 stream = NULL;
3002 return stream;
3007 es_setvbuf (estream_t ES__RESTRICT stream,
3008 char *ES__RESTRICT buf, int type, size_t size)
3010 int err;
3012 if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
3013 && (! ((! size) && (type != _IONBF))))
3015 ESTREAM_LOCK (stream);
3016 err = es_set_buffering (stream, buf, type, size);
3017 ESTREAM_UNLOCK (stream);
3019 else
3021 errno = EINVAL;
3022 err = -1;
3025 return err;
3029 void
3030 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
3032 ESTREAM_LOCK (stream);
3033 es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3034 ESTREAM_UNLOCK (stream);
3037 void
3038 es_opaque_set (estream_t stream, void *opaque)
3040 ESTREAM_LOCK (stream);
3041 es_opaque_ctrl (stream, opaque, NULL);
3042 ESTREAM_UNLOCK (stream);
3046 void *
3047 es_opaque_get (estream_t stream)
3049 void *opaque;
3051 ESTREAM_LOCK (stream);
3052 es_opaque_ctrl (stream, NULL, &opaque);
3053 ESTREAM_UNLOCK (stream);
3055 return opaque;
3058 /* Print a BUFFER to STREAM while replacing all control characters and
3059 the characters in DELIMITERS by standard C escape sequences.
3060 Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
3061 the number of bytes actually written are stored at this
3062 address. */
3063 int
3064 es_write_sanitized (estream_t ES__RESTRICT stream,
3065 const void * ES__RESTRICT buffer, size_t length,
3066 const char * delimiters,
3067 size_t * ES__RESTRICT bytes_written)
3069 const unsigned char *p = buffer;
3070 size_t count = 0;
3071 int ret;
3073 ESTREAM_LOCK (stream);
3074 for (; length; length--, p++, count++)
3076 if (*p < 0x20
3077 || (*p >= 0x7f && *p < 0xa0)
3078 || (delimiters
3079 && (strchr (delimiters, *p) || *p == '\\')))
3081 es_putc_unlocked ('\\', stream);
3082 count++;
3083 if (*p == '\n')
3085 es_putc_unlocked ('n', stream);
3086 count++;
3088 else if (*p == '\r')
3090 es_putc_unlocked ('r', stream);
3091 count++;
3093 else if (*p == '\f')
3095 es_putc_unlocked ('f', stream);
3096 count++;
3098 else if (*p == '\v')
3100 es_putc_unlocked ('v', stream);
3101 count++;
3103 else if (*p == '\b')
3105 es_putc_unlocked ('b', stream);
3106 count++;
3108 else if (!*p)
3110 es_putc_unlocked('0', stream);
3111 count++;
3113 else
3115 es_fprintf_unlocked (stream, "x%02x", *p);
3116 count += 3;
3119 else
3121 es_putc_unlocked (*p, stream);
3122 count++;
3126 if (bytes_written)
3127 *bytes_written = count;
3128 ret = es_ferror_unlocked (stream)? -1 : 0;
3129 ESTREAM_UNLOCK (stream);
3131 return ret;
3135 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3136 RESERVED must be 0. Returns 0 on success or -1 on error. If
3137 BYTES_WRITTEN is not NULL the number of bytes actually written are
3138 stored at this address. */
3140 es_write_hexstring (estream_t ES__RESTRICT stream,
3141 const void *ES__RESTRICT buffer, size_t length,
3142 int reserved, size_t *ES__RESTRICT bytes_written )
3144 int ret;
3145 const unsigned char *s;
3146 size_t count = 0;
3148 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3150 if (!length)
3151 return 0;
3153 ESTREAM_LOCK (stream);
3155 for (s = buffer; length; s++, length--)
3157 es_putc_unlocked ( tohex ((*s>>4)&15), stream);
3158 es_putc_unlocked ( tohex (*s&15), stream);
3159 count += 2;
3162 if (bytes_written)
3163 *bytes_written = count;
3164 ret = es_ferror_unlocked (stream)? -1 : 0;
3166 ESTREAM_UNLOCK (stream);
3168 return ret;
3170 #undef tohex
3175 #ifdef GNUPG_MAJOR_VERSION
3176 /* Special estream function to print an UTF8 string in the native
3177 encoding. The interface is the same as es_write_sanitized, however
3178 only one delimiter may be supported.
3180 THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3182 es_write_sanitized_utf8_buffer (estream_t stream,
3183 const void *buffer, size_t length,
3184 const char *delimiters, size_t *bytes_written)
3186 const char *p = buffer;
3187 size_t i;
3189 /* We can handle plain ascii simpler, so check for it first. */
3190 for (i=0; i < length; i++ )
3192 if ( (p[i] & 0x80) )
3193 break;
3195 if (i < length)
3197 int delim = delimiters? *delimiters : 0;
3198 char *buf;
3199 int ret;
3201 /*(utf8 conversion already does the control character quoting). */
3202 buf = utf8_to_native (p, length, delim);
3203 if (bytes_written)
3204 *bytes_written = strlen (buf);
3205 ret = es_fputs (buf, stream);
3206 xfree (buf);
3207 return i;
3209 else
3210 return es_write_sanitized (stream, p, length, delimiters, bytes_written);
3212 #endif /*GNUPG_MAJOR_VERSION*/